From 5646e19dc378dd6facf06f3feb3921e137a8fd4f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 10 Sep 2017 14:38:43 +0800 Subject: [PATCH 0001/2457] rtio/sed: add output network (untested) --- artiq/gateware/rtio/sed/__init__.py | 0 artiq/gateware/rtio/sed/output_network.py | 95 +++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 artiq/gateware/rtio/sed/__init__.py create mode 100644 artiq/gateware/rtio/sed/output_network.py diff --git a/artiq/gateware/rtio/sed/__init__.py b/artiq/gateware/rtio/sed/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/artiq/gateware/rtio/sed/output_network.py b/artiq/gateware/rtio/sed/output_network.py new file mode 100644 index 000000000..7c48caac3 --- /dev/null +++ b/artiq/gateware/rtio/sed/output_network.py @@ -0,0 +1,95 @@ +from migen import * + + +# Based on: https://github.com/Bekbolatov/SortingNetworks/blob/master/src/main/js/gr.js +def boms_get_partner(n, l, p): + if p == 1: + return n ^ (1 << (l - 1)) + scale = 1 << (l - p) + box = 1 << p + sn = n//scale - n//scale//box*box + if sn == 0 or sn == (box - 1): + return n + if (sn % 2) == 0: + return n - scale + return n + scale + + +def boms_steps_pairs(node_count): + d = log2_int(node_count) + steps = [] + for l in range(1, d+1): + for p in range(1, l+1): + pairs = [] + for n in range(2**d): + partner = boms_get_partner(n, l, p) + if partner != n: + if partner > n: + pair = (n, partner) + else: + pair = (partner, n) + if pair not in pairs: + pairs.append(pair) + steps.append(pairs) + return steps + + +layout_rtio_payload = [ + ("channel", 24), + ("timestamp", 64), + ("address", 16), + ("data", 512), +] + + +def layout_node_data(seqn_size): + return [ + ("valid", 1), + ("seqn", seqn_size), + ("replace_occured", 1), + ("payload", layout_rtio_payload) + ] + + +def cmp_wrap(a, b): + return Mux(a[-2:] == ~b[-2:], a[0], a[:-2] < b[:-2]) + + +class OutputNetwork(Module): + def __init__(self, node_count, seqn_size): + self.input = [Record(layout_node_data(seqn_size)) for _ in node_count] + self.output = None + + step_input = self.input + for step in boms_steps_pairs(node_count): + step_output = [Record(layout_node_data(seqn_size)) for _ in node_count] + + for node1, node2 in step: + self.sync += [ + If(step_input[node1].payload.channel == step_input[node2].payload.channel, + If(cmp_wrap(step_input[node1].seqn, step_input[node2].seqn), + step_output[node1].eq(step_output[node2]), + ).Else( + step_output[node1].eq(step_output[node1]), + ), + step_output[node1].replace_occured.eq(1), + step_output[node2].eq(step_input[node2]), + step_output[node2].valid.eq(0) + ).Elif(step_input[node1].payload.channel < step_input[node2].payload.channel, + step_output[node1].eq(step_input[node1]), + step_output[node2].eq(step_input[node2]) + ).Else( + step_output[node1].eq(step_input[node2]), + step_output[node2].eq(step_input[node1]) + ) + ] + + unchanged = list(range(node_count)) + for node1, node2 in step: + unchanged.remove(node1) + unchanged.remove(node2) + for node in unchanged: + self.sync += step_output[node].eq(step_input[node]) + + self.output = step_output + step_input = step_output From 96505a1cd941afded053bff9fe212c0283195aa7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 10 Sep 2017 23:23:10 +0800 Subject: [PATCH 0002/2457] rtio/sed: output network fixes --- artiq/gateware/rtio/sed/output_network.py | 48 +++++++++++++---------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/artiq/gateware/rtio/sed/output_network.py b/artiq/gateware/rtio/sed/output_network.py index 7c48caac3..94cd0d094 100644 --- a/artiq/gateware/rtio/sed/output_network.py +++ b/artiq/gateware/rtio/sed/output_network.py @@ -15,8 +15,8 @@ def boms_get_partner(n, l, p): return n + scale -def boms_steps_pairs(node_count): - d = log2_int(node_count) +def boms_steps_pairs(lane_count): + d = log2_int(lane_count) steps = [] for l in range(1, d+1): for p in range(1, l+1): @@ -34,20 +34,21 @@ def boms_steps_pairs(node_count): return steps -layout_rtio_payload = [ - ("channel", 24), - ("timestamp", 64), - ("address", 16), - ("data", 512), -] +def layout_rtio_payload(fine_ts_width): + return [ + ("channel", 24), + ("fine_ts", fine_ts_width), + ("address", 16), + ("data", 512), + ] -def layout_node_data(seqn_size): +def layout_node_data(seqn_width, fine_ts_width): return [ ("valid", 1), - ("seqn", seqn_size), + ("seqn", seqn_width), ("replace_occured", 1), - ("payload", layout_rtio_payload) + ("payload", layout_rtio_payload(fine_ts_width)) ] @@ -56,25 +57,30 @@ def cmp_wrap(a, b): class OutputNetwork(Module): - def __init__(self, node_count, seqn_size): - self.input = [Record(layout_node_data(seqn_size)) for _ in node_count] + def __init__(self, lane_count, seqn_width, fine_ts_width): + self.input = [Record(layout_node_data(seqn_width, fine_ts_width)) + for _ in range(lane_count)] self.output = None step_input = self.input - for step in boms_steps_pairs(node_count): - step_output = [Record(layout_node_data(seqn_size)) for _ in node_count] + for step in boms_steps_pairs(lane_count): + step_output = [Record(layout_node_data(seqn_width, fine_ts_width)) + for _ in range(lane_count)] for node1, node2 in step: self.sync += [ If(step_input[node1].payload.channel == step_input[node2].payload.channel, If(cmp_wrap(step_input[node1].seqn, step_input[node2].seqn), - step_output[node1].eq(step_output[node2]), + step_output[node1].eq(step_input[node2]), + step_output[node2].eq(step_input[node1]) ).Else( - step_output[node1].eq(step_output[node1]), + step_output[node1].eq(step_input[node1]), + step_output[node2].eq(step_input[node2]) ), - step_output[node1].replace_occured.eq(1), - step_output[node2].eq(step_input[node2]), - step_output[node2].valid.eq(0) + If(step_input[node1].valid & step_input[node2].valid, + step_output[node1].replace_occured.eq(1), + step_output[node2].valid.eq(0) + ) ).Elif(step_input[node1].payload.channel < step_input[node2].payload.channel, step_output[node1].eq(step_input[node1]), step_output[node2].eq(step_input[node2]) @@ -84,7 +90,7 @@ class OutputNetwork(Module): ) ] - unchanged = list(range(node_count)) + unchanged = list(range(lane_count)) for node1, node2 in step: unchanged.remove(node1) unchanged.remove(node2) From c5d6a2ba1a06bb01e71e03d278f65a263d646525 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 10 Sep 2017 23:41:04 +0800 Subject: [PATCH 0003/2457] rtio/sed: more output network fixes --- artiq/gateware/rtio/sed/output_network.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/rtio/sed/output_network.py b/artiq/gateware/rtio/sed/output_network.py index 94cd0d094..d993a58aa 100644 --- a/artiq/gateware/rtio/sed/output_network.py +++ b/artiq/gateware/rtio/sed/output_network.py @@ -68,8 +68,10 @@ class OutputNetwork(Module): for _ in range(lane_count)] for node1, node2 in step: + k1 = Cat(step_input[node1].payload.channel, ~step_input[node1].valid) + k2 = Cat(step_input[node2].payload.channel, ~step_input[node2].valid) self.sync += [ - If(step_input[node1].payload.channel == step_input[node2].payload.channel, + If(k1 == k2, If(cmp_wrap(step_input[node1].seqn, step_input[node2].seqn), step_output[node1].eq(step_input[node2]), step_output[node2].eq(step_input[node1]) @@ -77,11 +79,9 @@ class OutputNetwork(Module): step_output[node1].eq(step_input[node1]), step_output[node2].eq(step_input[node2]) ), - If(step_input[node1].valid & step_input[node2].valid, - step_output[node1].replace_occured.eq(1), - step_output[node2].valid.eq(0) - ) - ).Elif(step_input[node1].payload.channel < step_input[node2].payload.channel, + step_output[node1].replace_occured.eq(1), + step_output[node2].valid.eq(0), + ).Elif(k1 < k2, step_output[node1].eq(step_input[node1]), step_output[node2].eq(step_input[node2]) ).Else( From 527b403bb1b27810caf51aa90f0ae56296b2e8d1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 10 Sep 2017 23:41:20 +0800 Subject: [PATCH 0004/2457] rtio/sed: add output network simulation unittest --- .../test/rtio/test_sed_output_network.py | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 artiq/gateware/test/rtio/test_sed_output_network.py diff --git a/artiq/gateware/test/rtio/test_sed_output_network.py b/artiq/gateware/test/rtio/test_sed_output_network.py new file mode 100644 index 000000000..7650678e7 --- /dev/null +++ b/artiq/gateware/test/rtio/test_sed_output_network.py @@ -0,0 +1,56 @@ +import unittest + +from migen import * + +from artiq.gateware.rtio.sed import output_network + + +LANE_COUNT = 8 + + +def simulate(input_events): + dut = output_network.OutputNetwork(LANE_COUNT, LANE_COUNT*4, 3) + output = [] + def gen(): + yield + for n, input_event in enumerate(input_events): + yield dut.input[n].valid.eq(1) + yield dut.input[n].seqn.eq(n) + for k, v in input_event.items(): + yield getattr(dut.input[n].payload, k).eq(v) + yield + for n in range(len(input_events)): + yield dut.input[n].valid.eq(0) + for i in range(6): + yield + for x in range(LANE_COUNT): + if (yield dut.output[x].valid): + d = { + "replace_occured": (yield dut.output[x].replace_occured), + "channel": (yield dut.output[x].payload.channel), + "fine_ts": (yield dut.output[x].payload.fine_ts), + "address": (yield dut.output[x].payload.address), + "data": (yield dut.output[x].payload.data), + } + output.append(d) + run_simulation(dut, gen()) + return output + + +class TestOutputNetwork(unittest.TestCase): + def test_replace(self): + for n_events in range(2, LANE_COUNT+1): + with self.subTest(n_events=n_events): + input = [{"channel": 1, "address": i} for i in range(n_events)] + output = simulate(input) + expect = [{'replace_occured': 1, 'channel': 1, 'fine_ts': 0, 'address': n_events-1, 'data': 0}] + self.assertEqual(output, expect) + + def test_no_replace(self): + for n_events in range(1, LANE_COUNT+1): + with self.subTest(n_events=n_events): + input = [{"channel": i, "address": i} for i in range(n_events)] + output = simulate(input) + expect = [{'replace_occured': 0, 'channel': i, 'fine_ts': 0, 'address': i, 'data': 0} + for i in range(n_events)] + self.assertEqual(output, expect) From 1d2ebbe60f345bdffb941e947fda2b037bff1dab Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Sep 2017 09:06:40 +0800 Subject: [PATCH 0005/2457] rtio/sed: make ON payload layout configurable, add latency function --- artiq/gateware/rtio/sed/output_network.py | 23 +++++++++---------- .../test/rtio/test_sed_output_network.py | 10 ++++++-- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/artiq/gateware/rtio/sed/output_network.py b/artiq/gateware/rtio/sed/output_network.py index d993a58aa..edb875b1c 100644 --- a/artiq/gateware/rtio/sed/output_network.py +++ b/artiq/gateware/rtio/sed/output_network.py @@ -1,6 +1,9 @@ from migen import * +__all__ = ["latency", "OutputNetwork"] + + # Based on: https://github.com/Bekbolatov/SortingNetworks/blob/master/src/main/js/gr.js def boms_get_partner(n, l, p): if p == 1: @@ -34,21 +37,17 @@ def boms_steps_pairs(lane_count): return steps -def layout_rtio_payload(fine_ts_width): - return [ - ("channel", 24), - ("fine_ts", fine_ts_width), - ("address", 16), - ("data", 512), - ] +def latency(lane_count): + d = log2_int(lane_count) + return sum(l for l in range(1, d+1)) -def layout_node_data(seqn_width, fine_ts_width): +def layout_node_data(seqn_width, layout_payload): return [ ("valid", 1), ("seqn", seqn_width), ("replace_occured", 1), - ("payload", layout_rtio_payload(fine_ts_width)) + ("payload", layout_payload) ] @@ -57,14 +56,14 @@ def cmp_wrap(a, b): class OutputNetwork(Module): - def __init__(self, lane_count, seqn_width, fine_ts_width): - self.input = [Record(layout_node_data(seqn_width, fine_ts_width)) + def __init__(self, lane_count, seqn_width, layout_payload): + self.input = [Record(layout_node_data(seqn_width, layout_payload)) for _ in range(lane_count)] self.output = None step_input = self.input for step in boms_steps_pairs(lane_count): - step_output = [Record(layout_node_data(seqn_width, fine_ts_width)) + step_output = [Record(layout_node_data(seqn_width, layout_payload)) for _ in range(lane_count)] for node1, node2 in step: diff --git a/artiq/gateware/test/rtio/test_sed_output_network.py b/artiq/gateware/test/rtio/test_sed_output_network.py index 7650678e7..e876637af 100644 --- a/artiq/gateware/test/rtio/test_sed_output_network.py +++ b/artiq/gateware/test/rtio/test_sed_output_network.py @@ -9,7 +9,13 @@ LANE_COUNT = 8 def simulate(input_events): - dut = output_network.OutputNetwork(LANE_COUNT, LANE_COUNT*4, 3) + layout_payload = [ + ("channel", 8), + ("fine_ts", 3), + ("address", 16), + ("data", 512), + ] + dut = output_network.OutputNetwork(LANE_COUNT, LANE_COUNT*4, layout_payload) output = [] def gen(): yield @@ -21,7 +27,7 @@ def simulate(input_events): yield for n in range(len(input_events)): yield dut.input[n].valid.eq(0) - for i in range(6): + for i in range(output_network.latency(LANE_COUNT)): yield for x in range(LANE_COUNT): if (yield dut.output[x].valid): From 666bc600a28f3c31d1790f46c1eda55940402352 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Sep 2017 11:10:28 +0800 Subject: [PATCH 0006/2457] rtio/sed: add output driver (untested) --- artiq/gateware/rtio/sed/output_driver.py | 112 +++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 artiq/gateware/rtio/sed/output_driver.py diff --git a/artiq/gateware/rtio/sed/output_driver.py b/artiq/gateware/rtio/sed/output_driver.py new file mode 100644 index 000000000..be5e3a2c4 --- /dev/null +++ b/artiq/gateware/rtio/sed/output_driver.py @@ -0,0 +1,112 @@ +from functools import reduce +from operator import or_ + +from migen import * + +from artiq.gateware.rtio import rtlink +from artiq.gateware.rtio.sed.output_network import OutputNetwork + + +class OutputDriver(Module): + def __init__(self, channels, lane_count, seqn_width): + self.collision = Signal() + self.collision_channel = Signal(max=len(channels)) + self.busy = Signal() + self.busy_channel = Signal(max=len(channels)) + + fine_ts_width = max(rtlink.get_fine_ts_width(channel.interface) + for channel in channels) + address_width = max(rtlink.get_address_width(channel.interface) + for channel in channels) + data_width = max(rtlink.get_data_width(channel.interface) + for channel in channels) + + # output network + layout_on_payload = [("channel", bits_for(len(channels)-1))] + if fine_ts_width: + layout_on_payload.append(("fine_ts", fine_ts_width)) + if address_width: + layout_on_payload.append(("address", address_width)) + if data_width: + layout_on_payload.append(("data", data_width)) + output_network = OutputNetwork(lane_count, seqn_width, layout_on_payload) + self.submodules += output_network + self.input = output_network.input + + # detect collisions (adds one pipeline stage) + layout_lane_data = [ + ("valid", 1), + ("collision", 1), + ("payload", layout_on_payload) + ] + lane_datas = [Record(layout_lane_data) for _ in range(lane_count)] + en_replaces = [channel.interface.o.enable_replace for channel in channels] + for lane_data, on_output in zip(lane_datas, output_network.output): + replace_occured_r = Signal() + self.sync += [ + lane_data.valid.eq(on_output.valid), + lane_data.payload.eq(on_output.payload), + replace_occured_r.eq(on_output.replace_occured), + ] + + en_replaces_rom = Memory(1, len(en_replaces), init=en_replaces) + en_replaces_rom_port = en_replaces_rom.get_port() + self.specials += en_replaces_rom, en_replaces_rom_port + self.comb += [ + en_replaces_rom_port.adr.eq(on_output.payload.channel), + lane_data.collision.eq(replace_occured_r & ~en_replaces_rom_port.dat_r) + ] + + self.sync += [ + self.collision.eq(0), + self.collision_channel.eq(0) + ] + for lane_data in lane_datas: + self.sync += [ + If(lane_data.valid & lane_data.collision, + self.collision.eq(1), + self.collision_channel.eq(lane_data.payload.channel) + ) + ] + + # demultiplex channels (adds one pipeline stage) + for n, channel in enumerate(channels): + onehot_stb = [] + onehot_fine_ts = [] + onehot_address = [] + onehot_data = [] + for lane_data in lane_datas: + selected = Signal() + self.comb += selected.eq(lane_data.valid & ~lane_data.collision & (lane_data.payload.channel == n)) + onehot_stb.append(selected) + if hasattr(lane_data.payload, "fine_ts"): + onehot_fine_ts.append(Mux(selected, lane_data.payload.fine_ts, 0)) + if hasattr(lane_data.payload, "address"): + onehot_address.append(Mux(selected, lane_data.payload.address, 0)) + if hasattr(lane_data.payload, "data"): + onehot_data.append(Mux(selected, lane_data.payload.data, 0)) + + oif = channel.interface.o + self.sync += oif.stb.eq(reduce(or_, onehot_stb)) + if hasattr(oif, "fine_ts"): + self.sync += oif.fine_ts.eq(reduce(or_, onehot_fine_ts)) + if hasattr(oif, "address"): + self.sync += oif.address.eq(reduce(or_, onehot_address)) + if hasattr(oif, "data"): + self.sync += oif.data.eq(reduce(or_, onehot_data)) + + # detect busy errors, at lane level to reduce muxing + for lane_data in lane_datas: + stb_r = Signal() + channel_r = Signal(max=len(channels)) + self.sync += [ + stb_r.eq(lane_data.valid & ~lane_data.collision), + channel_r.eq(lane_data.payload.channel), + + self.busy.eq(0), + self.busy_channel.eq(0), + If(stb_r & Array(channel.interface.o.busy for channel in channels)[channel_r], + self.busy.eq(1), + self.busy_channel.eq(channel_r) + ) + ] From 64d9381c36535b90bae0c94108409c1e4c6b025d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Sep 2017 23:02:56 +0800 Subject: [PATCH 0007/2457] rtio/sed: remove uneeded yield in test_sed_output_network --- artiq/gateware/test/rtio/test_sed_output_network.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/gateware/test/rtio/test_sed_output_network.py b/artiq/gateware/test/rtio/test_sed_output_network.py index e876637af..b9c10526e 100644 --- a/artiq/gateware/test/rtio/test_sed_output_network.py +++ b/artiq/gateware/test/rtio/test_sed_output_network.py @@ -18,7 +18,6 @@ def simulate(input_events): dut = output_network.OutputNetwork(LANE_COUNT, LANE_COUNT*4, layout_payload) output = [] def gen(): - yield for n, input_event in enumerate(input_events): yield dut.input[n].valid.eq(1) yield dut.input[n].seqn.eq(n) From 00ff3f5b0d0d6e634c70f22f8865fb648a12b011 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Sep 2017 23:04:52 +0800 Subject: [PATCH 0008/2457] rtio/sed: fix output driver busy output --- artiq/gateware/rtio/sed/output_driver.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/sed/output_driver.py b/artiq/gateware/rtio/sed/output_driver.py index be5e3a2c4..ad9a6c2e9 100644 --- a/artiq/gateware/rtio/sed/output_driver.py +++ b/artiq/gateware/rtio/sed/output_driver.py @@ -96,6 +96,10 @@ class OutputDriver(Module): self.sync += oif.data.eq(reduce(or_, onehot_data)) # detect busy errors, at lane level to reduce muxing + self.sync += [ + self.busy.eq(0), + self.busy_channel.eq(0) + ] for lane_data in lane_datas: stb_r = Signal() channel_r = Signal(max=len(channels)) @@ -103,8 +107,6 @@ class OutputDriver(Module): stb_r.eq(lane_data.valid & ~lane_data.collision), channel_r.eq(lane_data.payload.channel), - self.busy.eq(0), - self.busy_channel.eq(0), If(stb_r & Array(channel.interface.o.busy for channel in channels)[channel_r], self.busy.eq(1), self.busy_channel.eq(channel_r) From a2b78941345ed8993ec5891b7a962ad2a1c75915 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Sep 2017 23:05:10 +0800 Subject: [PATCH 0009/2457] rtio/sed: add output driver simulation unittest --- .../test/rtio/test_sed_output_driver.py | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 artiq/gateware/test/rtio/test_sed_output_driver.py diff --git a/artiq/gateware/test/rtio/test_sed_output_driver.py b/artiq/gateware/test/rtio/test_sed_output_driver.py new file mode 100644 index 000000000..ef61b98ea --- /dev/null +++ b/artiq/gateware/test/rtio/test_sed_output_driver.py @@ -0,0 +1,125 @@ +import unittest + +from migen import * + +from artiq.gateware import rtio +from artiq.gateware.rtio.sed import output_network, output_driver +from artiq.gateware.rtio.phy import ttl_simple +from artiq.gateware.rtio import rtlink + + +LANE_COUNT = 8 + + +class BusyPHY(Module): + def __init__(self): + self.rtlink = rtlink.Interface(rtlink.OInterface(1)) + self.comb += self.rtlink.o.busy.eq(1) + + +class DUT(Module): + def __init__(self): + self.ttl0 = Signal() + self.ttl1 = Signal() + self.ttl2 = Signal() + + self.submodules.phy0 = ttl_simple.Output(self.ttl0) + self.submodules.phy1 = ttl_simple.Output(self.ttl1) + self.submodules.phy2 = ttl_simple.Output(self.ttl2) + self.phy2.rtlink.o.enable_replace = False + self.submodules.phy3 = BusyPHY() + + rtio_channels = [ + rtio.Channel.from_phy(self.phy0, ofifo_depth=4), + rtio.Channel.from_phy(self.phy1, ofifo_depth=4), + rtio.Channel.from_phy(self.phy2, ofifo_depth=4), + rtio.Channel.from_phy(self.phy3, ofifo_depth=4), + ] + + self.submodules.output_driver = output_driver.OutputDriver( + rtio_channels, LANE_COUNT, 4*LANE_COUNT) + + +def simulate(input_events): + dut = DUT() + + def gen(): + for n, input_event in enumerate(input_events): + yield dut.output_driver.input[n].valid.eq(1) + yield dut.output_driver.input[n].seqn.eq(n) + for k, v in input_event.items(): + yield getattr(dut.output_driver.input[n].payload, k).eq(v) + yield + for n in range(len(input_events)): + yield dut.output_driver.input[n].valid.eq(0) + for i in range(output_network.latency(LANE_COUNT) + 2): + yield + for i in range(3): + yield + + output = "" + + @passive + def monitor(): + nonlocal output + + ttls = [dut.ttl0, dut.ttl1, dut.ttl2] + prev_ttl_values = [0, 0, 0] + while True: + ttl_values = [] + for ttl in ttls: + ttl_values.append((yield ttl)) + for n, (old, new) in enumerate(zip(prev_ttl_values, ttl_values)): + if old != new: + output += "TTL{} {}->{}\n".format(n, old, new) + prev_ttl_values = ttl_values + + if (yield dut.output_driver.collision): + output += "collision ch{}\n".format((yield dut.output_driver.collision_channel)) + if (yield dut.output_driver.busy): + output += "busy ch{}\n".format((yield dut.output_driver.busy_channel)) + + yield + + run_simulation(dut, {"sys": [gen(), monitor()]}, + {"sys": 5, "rio": 5, "rio_phy": 5}, vcd_name="foo.vcd") + return output + + +class TestOutputNetwork(unittest.TestCase): + def test_one_ttl(self): + self.assertEqual( + simulate([{"data": 1}]), + "TTL0 0->1\n") + + def test_simultaneous_ttl(self): + self.assertEqual( + simulate([{"channel": 0, "data": 1}, + {"channel": 1, "data": 1}, + {"channel": 2, "data": 1}]), + "TTL0 0->1\n" + "TTL1 0->1\n" + "TTL2 0->1\n") + + def test_replace(self): + self.assertEqual( + simulate([{"data": 0}, + {"data": 1}, + {"data": 0}]), + "") + self.assertEqual( + simulate([{"data": 1}, + {"data": 0}, + {"data": 1}]), + "TTL0 0->1\n") + + def test_collision(self): + self.assertEqual( + simulate([{"channel": 2}, + {"channel": 2}]), + "collision ch2\n") + + def test_busy(self): + self.assertEqual( + simulate([{"channel": 3}]), + "busy ch3\n") From faf54127ac746fc6227fdd7042473596909e940b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Sep 2017 23:07:09 +0800 Subject: [PATCH 0010/2457] rtio/sed: remove VCD fine in unittest --- artiq/gateware/test/rtio/test_sed_output_driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/test/rtio/test_sed_output_driver.py b/artiq/gateware/test/rtio/test_sed_output_driver.py index ef61b98ea..f5f038426 100644 --- a/artiq/gateware/test/rtio/test_sed_output_driver.py +++ b/artiq/gateware/test/rtio/test_sed_output_driver.py @@ -82,7 +82,7 @@ def simulate(input_events): yield run_simulation(dut, {"sys": [gen(), monitor()]}, - {"sys": 5, "rio": 5, "rio_phy": 5}, vcd_name="foo.vcd") + {"sys": 5, "rio": 5, "rio_phy": 5}) return output From bdd96084c59b5f51daebc7137d40aa653aa41b18 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Sep 2017 00:07:26 +0800 Subject: [PATCH 0011/2457] rtio/sed: add lane distributor (untested) --- artiq/gateware/rtio/sed/lane_distributor.py | 118 ++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 artiq/gateware/rtio/sed/lane_distributor.py diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py new file mode 100644 index 000000000..2cdf025b8 --- /dev/null +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -0,0 +1,118 @@ +from migen import * + +from artiq.gateware.rtio import cri + + +def layout_lane_io(seqn_width, layout_payload): + return [ + ("we", 1, DIR_M_TO_S), + ("writable", 1, DIR_S_TO_M), + ("seqn", seqn_width, DIR_M_TO_S), + ("payload", layout_payload, DIR_M_TO_S) + ] + + +# CRI write happens in 3 cycles: +# 1. set timestamp +# 2. set other payload elements and issue write command +# 3. check status + +class LaneDistributor(Module): + def __init__(self, lane_count, fifo_size, layout_payload, fine_ts_width): + if lane_count & (lane_count - 1): + raise NotImplementedError("lane count must be a power of 2") + + seqn_width = 4*bits_for(fifo_size-1)*lane_count + + self.cri = cri.Interface() + self.minimum_coarse_timestamp = Signal(64-fine_ts_width) + self.lane_io = [Record(layout_lane_io(seqn_width, layout_payload)) + for _ in range(lane_count)] + + # # # + + o_status_wait = Signal() + o_status_underflow = Signal() + o_status_sequence_error = Signal() + self.comb += self.cri.o_status.eq(Cat(o_status_wait, o_status_underflow, + o_status_sequence_error)) + + # internal state + current_lane = Signal(max=lane_count) + last_coarse_timestamp = Signal(64-fine_ts_width) + last_lane_coarse_timestamps = Array(Signal(64-fine_ts_width) + for _ in range(lane_count)) + seqn = Signal(seqn_width) + + # distribute data to lanes + for lio in lane_io: + self.comb += [ + lio.seqn.eq(seqn), + lio.payload.channel.eq(self.cri.chan_sel[:16]), + lio.payload.timestamp.eq(self.cri.timestamp), + ] + if hasattr(lio.payload, "address"): + self.comb += lio.payload.address.eq(self.cri.address) + if hasattr(lio.payload, "data"): + self.comb += lio.payload.data.eq(self.cri.data) + + # when timestamp arrives in cycle #1, prepare computations + coarse_timestamp = self.cri.timestamp[fine_ts_width:] + timestamp_above_min = Signal() + timestamp_above_laneA_min = Signal() + timestamp_above_laneB_min = Signal() + use_laneB = Signal() + use_lanen = Signal(max=lane_count) + self.sync += [ + timestamp_above_min.eq(coarse_timestamp > self.minimum_coarse_timestamp), + timestamp_above_laneA_min.eq(coarse_timestamp > last_lane_coarse_timestamps[current_lane]), + timestamp_above_laneB_min.eq(coarse_timestamp > last_lane_coarse_timestamps[current_lane + 1]), + If(coarse_timestamp <= last_coarse_timestamp, + use_lanen.eq(current_lane + 1), + use_laneB.eq(1) + ).Else( + use_lanen.eq(current_lane), + use_laneB.eq(0) + ) + ] + + # cycle #2, write + timestamp_above_lane_min = Signal() + do_write = Signal() + do_underflow = Signal() + do_sequence_error = Signal() + self.comb += [ + timestamp_above_lane_min.eq(Mux(use_laneB, timestamp_above_laneB_min, timestamp_above_laneA_min)), + do_write.eq((self.cri.cmd == cri.commands["write"]) & timestamp_above_min & timestamp_above_lane_min), + do_underflow.eq((self.cri.cmd == cri.commands["write"]) & ~timestamp_above_min), + do_sequence_error((self.cri.cmd == cri.commands["write"]) & timestamp_above_min & ~timestamp_above_lane_min), + Array(lio.we for lio in lane_io)[use_lanen].eq(do_write) + ] + self.sync += [ + If(do_write, + current_lane.eq(current_lane + 1), + last_coarse_timestamp.eq(coarse_timestamp), + last_lane_coarse_timestamps[use_lanen].eq(coarse_timestamp), + seqn.eq(seqn + 1), + ) + ] + + # cycle #3, read status + current_lane_writable = Signal() + self.comb += [ + current_lane_writable.eq((lio.writable for lio in lane_io)[current_lane]), + o_status_wait.eq(~current_lane_writable) + ] + self.sync += [ + o_status_underflow.eq(do_underflow), + o_status_sequence_error(do_sequence_error) + ] + + # current lane has been full, spread events by switching to the next. + current_lane_writable_r = Signal() + self.sync += [ + current_lane_writable_r.eq(current_lane_writable), + If(~current_lane_writable_r & current_lane_writable, + current_lane.eq(current_lane + 1) + ) + ] From c74abccfd5d30fb7b1708d307d36695b1261ea1a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Sep 2017 17:50:06 +0800 Subject: [PATCH 0012/2457] rtio/sed: lane distributor fixes --- artiq/gateware/rtio/sed/lane_distributor.py | 40 +++++++++++---------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index 2cdf025b8..ddd19ee33 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -8,7 +8,7 @@ def layout_lane_io(seqn_width, layout_payload): ("we", 1, DIR_M_TO_S), ("writable", 1, DIR_S_TO_M), ("seqn", seqn_width, DIR_M_TO_S), - ("payload", layout_payload, DIR_M_TO_S) + ("payload", [(a, b, DIR_M_TO_S) for a, b in layout_payload]) ] @@ -18,11 +18,11 @@ def layout_lane_io(seqn_width, layout_payload): # 3. check status class LaneDistributor(Module): - def __init__(self, lane_count, fifo_size, layout_payload, fine_ts_width): + def __init__(self, lane_count, fifo_size, layout_payload, fine_ts_width, enable_spread=False): if lane_count & (lane_count - 1): raise NotImplementedError("lane count must be a power of 2") - seqn_width = 4*bits_for(fifo_size-1)*lane_count + seqn_width = 4*bits_for(lane_count*fifo_size-1) self.cri = cri.Interface() self.minimum_coarse_timestamp = Signal(64-fine_ts_width) @@ -45,7 +45,7 @@ class LaneDistributor(Module): seqn = Signal(seqn_width) # distribute data to lanes - for lio in lane_io: + for lio in self.lane_io: self.comb += [ lio.seqn.eq(seqn), lio.payload.channel.eq(self.cri.chan_sel[:16]), @@ -57,16 +57,19 @@ class LaneDistributor(Module): self.comb += lio.payload.data.eq(self.cri.data) # when timestamp arrives in cycle #1, prepare computations - coarse_timestamp = self.cri.timestamp[fine_ts_width:] + coarse_timestamp = Signal(64-fine_ts_width) + self.comb += coarse_timestamp.eq(self.cri.timestamp[fine_ts_width:]) timestamp_above_min = Signal() timestamp_above_laneA_min = Signal() timestamp_above_laneB_min = Signal() use_laneB = Signal() use_lanen = Signal(max=lane_count) + current_lane_plus_one = Signal(max=lane_count) + self.comb += current_lane_plus_one.eq(current_lane + 1) self.sync += [ timestamp_above_min.eq(coarse_timestamp > self.minimum_coarse_timestamp), timestamp_above_laneA_min.eq(coarse_timestamp > last_lane_coarse_timestamps[current_lane]), - timestamp_above_laneB_min.eq(coarse_timestamp > last_lane_coarse_timestamps[current_lane + 1]), + timestamp_above_laneB_min.eq(coarse_timestamp > last_lane_coarse_timestamps[current_lane_plus_one]), If(coarse_timestamp <= last_coarse_timestamp, use_lanen.eq(current_lane + 1), use_laneB.eq(1) @@ -85,12 +88,12 @@ class LaneDistributor(Module): timestamp_above_lane_min.eq(Mux(use_laneB, timestamp_above_laneB_min, timestamp_above_laneA_min)), do_write.eq((self.cri.cmd == cri.commands["write"]) & timestamp_above_min & timestamp_above_lane_min), do_underflow.eq((self.cri.cmd == cri.commands["write"]) & ~timestamp_above_min), - do_sequence_error((self.cri.cmd == cri.commands["write"]) & timestamp_above_min & ~timestamp_above_lane_min), - Array(lio.we for lio in lane_io)[use_lanen].eq(do_write) + do_sequence_error.eq((self.cri.cmd == cri.commands["write"]) & timestamp_above_min & ~timestamp_above_lane_min), + Array(lio.we for lio in self.lane_io)[use_lanen].eq(do_write) ] self.sync += [ If(do_write, - current_lane.eq(current_lane + 1), + If(use_laneB, current_lane.eq(current_lane + 1)), last_coarse_timestamp.eq(coarse_timestamp), last_lane_coarse_timestamps[use_lanen].eq(coarse_timestamp), seqn.eq(seqn + 1), @@ -100,19 +103,20 @@ class LaneDistributor(Module): # cycle #3, read status current_lane_writable = Signal() self.comb += [ - current_lane_writable.eq((lio.writable for lio in lane_io)[current_lane]), + current_lane_writable.eq(Array(lio.writable for lio in self.lane_io)[current_lane]), o_status_wait.eq(~current_lane_writable) ] self.sync += [ o_status_underflow.eq(do_underflow), - o_status_sequence_error(do_sequence_error) + o_status_sequence_error.eq(do_sequence_error) ] # current lane has been full, spread events by switching to the next. - current_lane_writable_r = Signal() - self.sync += [ - current_lane_writable_r.eq(current_lane_writable), - If(~current_lane_writable_r & current_lane_writable, - current_lane.eq(current_lane + 1) - ) - ] + if enable_spread: + current_lane_writable_r = Signal() + self.sync += [ + current_lane_writable_r.eq(current_lane_writable), + If(~current_lane_writable_r & current_lane_writable, + current_lane.eq(current_lane + 1) + ) + ] From feec6298a5e9d7cf0235c0c8e9f0b55292e4f879 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Sep 2017 18:00:16 +0800 Subject: [PATCH 0013/2457] rtio/sed: add lane distributor simulation unittest --- .../test/rtio/test_sed_lane_distributor.py | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 artiq/gateware/test/rtio/test_sed_lane_distributor.py diff --git a/artiq/gateware/test/rtio/test_sed_lane_distributor.py b/artiq/gateware/test/rtio/test_sed_lane_distributor.py new file mode 100644 index 000000000..76c719fb9 --- /dev/null +++ b/artiq/gateware/test/rtio/test_sed_lane_distributor.py @@ -0,0 +1,114 @@ +import unittest + +from migen import * + +from artiq.gateware.rtio import cri +from artiq.gateware.rtio.sed import lane_distributor + + +LANE_COUNT = 8 + + +def simulate(input_events): + dut = lane_distributor.LaneDistributor(LANE_COUNT, 16, [("channel", 8), ("timestamp", 32)], 3) + + output = [] + access_results = [] + + def gen(): + for channel, timestamp in input_events: + yield dut.cri.chan_sel.eq(channel) + yield dut.cri.timestamp.eq(timestamp) + yield + + yield dut.cri.cmd.eq(cri.commands["write"]) + yield + yield dut.cri.cmd.eq(cri.commands["nop"]) + + access_time = 0 + yield + while (yield dut.cri.o_status) & 0x01: + yield + access_time += 1 + + status = (yield dut.cri.o_status) + access_status = "ok" + if status & 0x02: + access_status = "underflow" + if status & 0x04: + access_status = "sequence_error" + + access_results.append((access_status, access_time)) + + @passive + def monitor_lane(n, lio, wait_time): + yield lio.writable.eq(1) + while True: + while not (yield lio.we): + yield + seqn = (yield lio.seqn) + channel = (yield lio.payload.channel) + timestamp = (yield lio.payload.timestamp) + output.append((n, seqn, channel, timestamp)) + + yield lio.writable.eq(0) + for i in range(wait_time): + yield + yield lio.writable.eq(1) + yield + + generators = [gen()] + for n, lio in enumerate(dut.lane_io): + if n == 6: + wait_time = 1 + elif n == 7: + wait_time = 4 + else: + wait_time = 0 + generators.append(monitor_lane(n, lio, wait_time)) + run_simulation(dut, generators) + + return output, access_results + + +class TestLaneDistributor(unittest.TestCase): + def test_regular(self): + # Assumes lane 0 does not have wait time. + N = 16 + output, access_results = simulate([(42+n, (n+1)*8) for n in range(N)]) + self.assertEqual(output, [(0, n, 42+n, (n+1)*8) for n in range(N)]) + self.assertEqual(access_results, [("ok", 0)]*N) + + def test_wait_time(self): + output, access_results = simulate([(42+n, 8) for n in range(LANE_COUNT)]) + self.assertEqual(output, [(n, n, 42+n, 8) for n in range(LANE_COUNT)]) + expected_access_results = [("ok", 0)]*LANE_COUNT + expected_access_results[6] = ("ok", 1) + expected_access_results[7] = ("ok", 4) + self.assertEqual(access_results, expected_access_results) + + def test_lane_switch(self): + N = 32 + output, access_results = simulate([(42+n, n+8) for n in range(N)]) + self.assertEqual(output, [((n-n//8) % LANE_COUNT, n, 42+n, n+8) for n in range(N)]) + self.assertEqual([ar[0] for ar in access_results], ["ok"]*N) + + def test_sequence_error(self): + input_events = [(42+n, 8) for n in range(LANE_COUNT+1)] + input_events.append((42+LANE_COUNT+1, 16)) + output, access_results = simulate(input_events) + self.assertEqual(len(output), len(input_events)-1) # event with sequence error must get discarded + self.assertEqual([ar[0] for ar in access_results[:LANE_COUNT]], ["ok"]*LANE_COUNT) + self.assertEqual(access_results[LANE_COUNT][0], "sequence_error") + + def test_underflow(self): + N = 16 + input_events = [(42+n, (n+1)*8) for n in range(N-2)] + input_events.append((0, 0)) # timestamp < 8 underflows + input_events.append((42+N-2, N*8)) + output, access_results = simulate(input_events) + self.assertEqual(len(output), len(input_events)-1) # event with underflow must get discarded + self.assertEqual([ar[0] for ar in access_results[:N-2]], ["ok"]*(N-2)) + self.assertEqual(access_results[N-2][0], "underflow") + self.assertEqual(output[N-2], (0, N-2, 42+N-2, N*8)) + self.assertEqual(access_results[N-1][0], "ok") From a92a955d1e6a98cd4d334c2a48a81c465455f3b9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Sep 2017 18:17:22 +0800 Subject: [PATCH 0014/2457] rtio/sed: use __all__ --- artiq/gateware/rtio/sed/lane_distributor.py | 3 +++ artiq/gateware/rtio/sed/output_driver.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index ddd19ee33..9b3a17e64 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -3,6 +3,9 @@ from migen import * from artiq.gateware.rtio import cri +__all__ = ["LaneDistributor"] + + def layout_lane_io(seqn_width, layout_payload): return [ ("we", 1, DIR_M_TO_S), diff --git a/artiq/gateware/rtio/sed/output_driver.py b/artiq/gateware/rtio/sed/output_driver.py index ad9a6c2e9..5ee24753e 100644 --- a/artiq/gateware/rtio/sed/output_driver.py +++ b/artiq/gateware/rtio/sed/output_driver.py @@ -7,6 +7,9 @@ from artiq.gateware.rtio import rtlink from artiq.gateware.rtio.sed.output_network import OutputNetwork +__all__ = ["OutputDriver"] + + class OutputDriver(Module): def __init__(self, channels, lane_count, seqn_width): self.collision = Signal() From 8cfe2ec53a00f916b9d6f7771d20c2bee6042003 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Sep 2017 22:11:41 +0800 Subject: [PATCH 0015/2457] rtio/sed: fix sequence number width computation --- artiq/gateware/rtio/sed/lane_distributor.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index 9b3a17e64..08c537994 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -25,7 +25,9 @@ class LaneDistributor(Module): if lane_count & (lane_count - 1): raise NotImplementedError("lane count must be a power of 2") - seqn_width = 4*bits_for(lane_count*fifo_size-1) + # There must be a unique sequence number for every possible event in every FIFO. + # Plus 2 bits to detect and handle wraparounds. + seqn_width = bits_for(lane_count*fifo_size-1) + 2 self.cri = cri.Interface() self.minimum_coarse_timestamp = Signal(64-fine_ts_width) From 1b61442bc33900b7aa58c196085791629a2d0a77 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Sep 2017 22:48:10 +0800 Subject: [PATCH 0016/2457] rtio/sed: fix lane spreading and enable by default --- artiq/gateware/rtio/sed/lane_distributor.py | 12 ++++++--- .../test/rtio/test_sed_lane_distributor.py | 26 +++++++++++++------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index 08c537994..f2524d012 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -21,7 +21,7 @@ def layout_lane_io(seqn_width, layout_payload): # 3. check status class LaneDistributor(Module): - def __init__(self, lane_count, fifo_size, layout_payload, fine_ts_width, enable_spread=False): + def __init__(self, lane_count, fifo_size, layout_payload, fine_ts_width, enable_spread=True): if lane_count & (lane_count - 1): raise NotImplementedError("lane count must be a power of 2") @@ -67,6 +67,7 @@ class LaneDistributor(Module): timestamp_above_min = Signal() timestamp_above_laneA_min = Signal() timestamp_above_laneB_min = Signal() + force_laneB = Signal() use_laneB = Signal() use_lanen = Signal(max=lane_count) current_lane_plus_one = Signal(max=lane_count) @@ -75,7 +76,7 @@ class LaneDistributor(Module): timestamp_above_min.eq(coarse_timestamp > self.minimum_coarse_timestamp), timestamp_above_laneA_min.eq(coarse_timestamp > last_lane_coarse_timestamps[current_lane]), timestamp_above_laneB_min.eq(coarse_timestamp > last_lane_coarse_timestamps[current_lane_plus_one]), - If(coarse_timestamp <= last_coarse_timestamp, + If(force_laneB | (coarse_timestamp <= last_coarse_timestamp), use_lanen.eq(current_lane + 1), use_laneB.eq(1) ).Else( @@ -118,10 +119,13 @@ class LaneDistributor(Module): # current lane has been full, spread events by switching to the next. if enable_spread: - current_lane_writable_r = Signal() + current_lane_writable_r = Signal(reset=1) self.sync += [ current_lane_writable_r.eq(current_lane_writable), If(~current_lane_writable_r & current_lane_writable, - current_lane.eq(current_lane + 1) + force_laneB.eq(1) + ), + If(do_write, + force_laneB.eq(0) ) ] diff --git a/artiq/gateware/test/rtio/test_sed_lane_distributor.py b/artiq/gateware/test/rtio/test_sed_lane_distributor.py index 76c719fb9..c9f883db4 100644 --- a/artiq/gateware/test/rtio/test_sed_lane_distributor.py +++ b/artiq/gateware/test/rtio/test_sed_lane_distributor.py @@ -9,7 +9,7 @@ from artiq.gateware.rtio.sed import lane_distributor LANE_COUNT = 8 -def simulate(input_events): +def simulate(input_events, wait=True): dut = lane_distributor.LaneDistributor(LANE_COUNT, 16, [("channel", 8), ("timestamp", 32)], 3) output = [] @@ -59,12 +59,13 @@ def simulate(input_events): generators = [gen()] for n, lio in enumerate(dut.lane_io): - if n == 6: - wait_time = 1 - elif n == 7: - wait_time = 4 - else: - wait_time = 0 + lio.writable.reset = 1 + wait_time = 0 + if wait: + if n == 6: + wait_time = 1 + elif n == 7: + wait_time = 4 generators.append(monitor_lane(n, lio, wait_time)) run_simulation(dut, generators) @@ -89,7 +90,7 @@ class TestLaneDistributor(unittest.TestCase): def test_lane_switch(self): N = 32 - output, access_results = simulate([(42+n, n+8) for n in range(N)]) + output, access_results = simulate([(42+n, n+8) for n in range(N)], wait=False) self.assertEqual(output, [((n-n//8) % LANE_COUNT, n, 42+n, n+8) for n in range(N)]) self.assertEqual([ar[0] for ar in access_results], ["ok"]*N) @@ -112,3 +113,12 @@ class TestLaneDistributor(unittest.TestCase): self.assertEqual(access_results[N-2][0], "underflow") self.assertEqual(output[N-2], (0, N-2, 42+N-2, N*8)) self.assertEqual(access_results[N-1][0], "ok") + + def test_spread(self): + # get to lane 6 + input_events = [(42+n, 8) for n in range(7)] + input_events.append((100, 16)) + input_events.append((100, 32)) + output, access_results = simulate(input_events) + self.assertEqual([o[0] for o in output], [x % LANE_COUNT for x in range(9)]) + self.assertEqual([ar[0] for ar in access_results], ["ok"]*9) From 181cb42ba8ce3be6f1a59d2c7923893daf853bfd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Sep 2017 19:52:31 +0800 Subject: [PATCH 0017/2457] rtio/sed: centralize all layouts in one file --- artiq/gateware/rtio/sed/lane_distributor.py | 11 +--- artiq/gateware/rtio/sed/layouts.py | 67 +++++++++++++++++++++ artiq/gateware/rtio/sed/output_driver.py | 17 +----- artiq/gateware/rtio/sed/output_network.py | 15 ++--- 4 files changed, 75 insertions(+), 35 deletions(-) create mode 100644 artiq/gateware/rtio/sed/layouts.py diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index f2524d012..d21d40484 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -1,19 +1,12 @@ from migen import * from artiq.gateware.rtio import cri +from artiq.gateware.rtio.sed import layouts __all__ = ["LaneDistributor"] -def layout_lane_io(seqn_width, layout_payload): - return [ - ("we", 1, DIR_M_TO_S), - ("writable", 1, DIR_S_TO_M), - ("seqn", seqn_width, DIR_M_TO_S), - ("payload", [(a, b, DIR_M_TO_S) for a, b in layout_payload]) - ] - # CRI write happens in 3 cycles: # 1. set timestamp @@ -31,7 +24,7 @@ class LaneDistributor(Module): self.cri = cri.Interface() self.minimum_coarse_timestamp = Signal(64-fine_ts_width) - self.lane_io = [Record(layout_lane_io(seqn_width, layout_payload)) + self.lane_io = [Record(layouts.fifo_ingress(seqn_width, layout_payload)) for _ in range(lane_count)] # # # diff --git a/artiq/gateware/rtio/sed/layouts.py b/artiq/gateware/rtio/sed/layouts.py new file mode 100644 index 000000000..4408a5d00 --- /dev/null +++ b/artiq/gateware/rtio/sed/layouts.py @@ -0,0 +1,67 @@ +from migen import * + +from artiq.gateware.rtio import rtlink + + +def fifo_payload(channels): + address_width = max(rtlink.get_address_width(channel.interface) + for channel in channels) + data_width = max(rtlink.get_data_width(channel.interface) + for channel in channels) + + layout = [ + ("channel", bits_for(len(channels)-1)), + ("timestamp", 64) + ] + if address_width: + layout.append(("address", address_width)) + if data_width: + layout.append(("data", data_width)) + + return layout + + +def fifo_ingress(seqn_width, layout_payload): + return [ + ("we", 1, DIR_M_TO_S), + ("writable", 1, DIR_S_TO_M), + ("seqn", seqn_width, DIR_M_TO_S), + ("payload", [(a, b, DIR_M_TO_S) for a, b in layout_payload]) + ] + + +def fifo_egress(seqn_width, layout_payload): + return [ + ("re", 1, DIR_S_TO_M), + ("readable", 1, DIR_M_TO_S), + ("seqn", seqn_width, DIR_M_TO_S), + ("payload", [(a, b, DIR_M_TO_S) for a, b in layout_payload]) + ] + + +def output_network_payload(channels): + fine_ts_width = max(rtlink.get_fine_ts_width(channel.interface) + for channel in channels) + address_width = max(rtlink.get_address_width(channel.interface) + for channel in channels) + data_width = max(rtlink.get_data_width(channel.interface) + for channel in channels) + + layout = [("channel", bits_for(len(channels)-1))] + if fine_ts_width: + layout.append(("fine_ts", fine_ts_width)) + if address_width: + layout.append(("address", address_width)) + if data_width: + layout.append(("data", data_width)) + + return layout + + +def output_network_node(seqn_width, layout_payload): + return [ + ("valid", 1), + ("seqn", seqn_width), + ("replace_occured", 1), + ("payload", layout_payload) + ] diff --git a/artiq/gateware/rtio/sed/output_driver.py b/artiq/gateware/rtio/sed/output_driver.py index 5ee24753e..4edf83d34 100644 --- a/artiq/gateware/rtio/sed/output_driver.py +++ b/artiq/gateware/rtio/sed/output_driver.py @@ -3,7 +3,7 @@ from operator import or_ from migen import * -from artiq.gateware.rtio import rtlink +from artiq.gateware.rtio.sed import layouts from artiq.gateware.rtio.sed.output_network import OutputNetwork @@ -17,21 +17,8 @@ class OutputDriver(Module): self.busy = Signal() self.busy_channel = Signal(max=len(channels)) - fine_ts_width = max(rtlink.get_fine_ts_width(channel.interface) - for channel in channels) - address_width = max(rtlink.get_address_width(channel.interface) - for channel in channels) - data_width = max(rtlink.get_data_width(channel.interface) - for channel in channels) - # output network - layout_on_payload = [("channel", bits_for(len(channels)-1))] - if fine_ts_width: - layout_on_payload.append(("fine_ts", fine_ts_width)) - if address_width: - layout_on_payload.append(("address", address_width)) - if data_width: - layout_on_payload.append(("data", data_width)) + layout_on_payload = layouts.output_network_payload(channels) output_network = OutputNetwork(lane_count, seqn_width, layout_on_payload) self.submodules += output_network self.input = output_network.input diff --git a/artiq/gateware/rtio/sed/output_network.py b/artiq/gateware/rtio/sed/output_network.py index edb875b1c..05797bdcb 100644 --- a/artiq/gateware/rtio/sed/output_network.py +++ b/artiq/gateware/rtio/sed/output_network.py @@ -1,5 +1,7 @@ from migen import * +from artiq.gateware.rtio.sed import layouts + __all__ = ["latency", "OutputNetwork"] @@ -42,28 +44,19 @@ def latency(lane_count): return sum(l for l in range(1, d+1)) -def layout_node_data(seqn_width, layout_payload): - return [ - ("valid", 1), - ("seqn", seqn_width), - ("replace_occured", 1), - ("payload", layout_payload) - ] - - def cmp_wrap(a, b): return Mux(a[-2:] == ~b[-2:], a[0], a[:-2] < b[:-2]) class OutputNetwork(Module): def __init__(self, lane_count, seqn_width, layout_payload): - self.input = [Record(layout_node_data(seqn_width, layout_payload)) + self.input = [Record(layouts.output_network_node(seqn_width, layout_payload)) for _ in range(lane_count)] self.output = None step_input = self.input for step in boms_steps_pairs(lane_count): - step_output = [Record(layout_node_data(seqn_width, layout_payload)) + step_output = [Record(layouts.output_network_node(seqn_width, layout_payload)) for _ in range(lane_count)] for node1, node2 in step: From 490c9815a295865b305c96c65c394336f68a396f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Sep 2017 19:53:21 +0800 Subject: [PATCH 0018/2457] rtio/sed: add TSC/gate (untested) --- artiq/gateware/rtio/sed/tsc_gate.py | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 artiq/gateware/rtio/sed/tsc_gate.py diff --git a/artiq/gateware/rtio/sed/tsc_gate.py b/artiq/gateware/rtio/sed/tsc_gate.py new file mode 100644 index 000000000..38e35081e --- /dev/null +++ b/artiq/gateware/rtio/sed/tsc_gate.py @@ -0,0 +1,38 @@ +from migen import * + +from artiq.gateware.rtio.sed import layouts + + +__all__ = ["TSCGate"] + + + +class TSCGate(Module): + def __init__(self, lane_count, seqn_width, layout_fifo_payload, layout_output_network_payload): + self.input = [Record(layouts.fifo_egress(seqn_width, layout_fifo_payload)) + for _ in range(lane_count)] + self.output = [Record(layouts.output_network_node(seqn_width, layout_output_network_payload)) + for _ in range(lane_count)] + + if hasattr(self.output[0], "fine_ts"): + fine_ts_width = len(self.output[0].fine_ts) + else: + fine_ts_width = 0 + self.tsc = Signal(64-fine_ts_width) + + # # # + + self.sync += self.tsc.eq(self.tsc + 1) + + for input, output in zip(self.input, self.output): + for field, _ in output.payload.layout: + if field == "fine_ts": + self.sync += output.payload.fine_ts.eq(input.payload.timestamp[:fine_ts_width]) + else: + self.sync += getattr(output.payload, field).eq(getattr(input.payload, field)) + self.sync += output.seqn.eq(input.seqn) + self.comb += output.replace_occured.eq(0) + + self.comb += input.re.eq(input.payload.timestamp[fine_ts_width:] == self.tsc) + self.sync += ouput.valid.eq(input.re & input.readable) + From 8e5ab90129fb3e69ae77bbff4e5349f98b4268cb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 15 Sep 2017 15:36:34 +0800 Subject: [PATCH 0019/2457] rtio/sed: add FIFO wrapper --- artiq/gateware/rtio/sed/fifo.py | 37 +++++++++++++++++++ artiq/gateware/rtio/sed/lane_distributor.py | 6 +-- artiq/gateware/rtio/sed/layouts.py | 6 +++ .../test/rtio/test_sed_lane_distributor.py | 2 +- 4 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 artiq/gateware/rtio/sed/fifo.py diff --git a/artiq/gateware/rtio/sed/fifo.py b/artiq/gateware/rtio/sed/fifo.py new file mode 100644 index 000000000..1f908a0c1 --- /dev/null +++ b/artiq/gateware/rtio/sed/fifo.py @@ -0,0 +1,37 @@ +from migen import * +from migen.genlib.fifo import * + +from artiq.gateware.rtio.sed import layouts + + +__all__ = ["FIFO"] + + +class FIFO(Module): + def __init__(self, lane_count, mode, fifo_depth, layout_payload): + seqn_width = layouts.seqn_width(lane_count, fifo_width) + self.input = [layouts.fifo_ingress(seqn_width, layout_payload) + for _ in range(lane_count)] + self.output = [layouts.fifo_egress(seqn_width, layout_payload) + for _ in range(lane_count)] + + if mode == "sync": + fifo_cls = fifo.SyncFIFOBuffered + elif mode == "async": + fifo_cls = fifo.AsyncFIFO + else: + raise ValueError + + for input, output in zip(self.input, self.output): + fifo = fifo_cls(layout_len(layout_payload), fifo_depth) + self.submodules += fifo + + self.comb += [ + fifo.din.eq(input.payload.raw_bits()), + fifo.we.eq(input.we), + input.writable.eq(fifo.writable), + + output.payload.raw_bits().eq(fifo.dout), + output.readable.eq(fifo.readable), + fifo.re.eq(output.re) + ] diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index d21d40484..c58dfeb6d 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -14,14 +14,10 @@ __all__ = ["LaneDistributor"] # 3. check status class LaneDistributor(Module): - def __init__(self, lane_count, fifo_size, layout_payload, fine_ts_width, enable_spread=True): + def __init__(self, lane_count, seqn_width, layout_payload, fine_ts_width, enable_spread=True): if lane_count & (lane_count - 1): raise NotImplementedError("lane count must be a power of 2") - # There must be a unique sequence number for every possible event in every FIFO. - # Plus 2 bits to detect and handle wraparounds. - seqn_width = bits_for(lane_count*fifo_size-1) + 2 - self.cri = cri.Interface() self.minimum_coarse_timestamp = Signal(64-fine_ts_width) self.lane_io = [Record(layouts.fifo_ingress(seqn_width, layout_payload)) diff --git a/artiq/gateware/rtio/sed/layouts.py b/artiq/gateware/rtio/sed/layouts.py index 4408a5d00..5feac13b2 100644 --- a/artiq/gateware/rtio/sed/layouts.py +++ b/artiq/gateware/rtio/sed/layouts.py @@ -21,6 +21,12 @@ def fifo_payload(channels): return layout +def seqn_width(lane_count, fifo_width): + # There must be a unique sequence number for every possible event in every FIFO. + # Plus 2 bits to detect and handle wraparounds. + return bits_for(lane_count*fifo_size-1) + 2 + + def fifo_ingress(seqn_width, layout_payload): return [ ("we", 1, DIR_M_TO_S), diff --git a/artiq/gateware/test/rtio/test_sed_lane_distributor.py b/artiq/gateware/test/rtio/test_sed_lane_distributor.py index c9f883db4..f7c4efa28 100644 --- a/artiq/gateware/test/rtio/test_sed_lane_distributor.py +++ b/artiq/gateware/test/rtio/test_sed_lane_distributor.py @@ -10,7 +10,7 @@ LANE_COUNT = 8 def simulate(input_events, wait=True): - dut = lane_distributor.LaneDistributor(LANE_COUNT, 16, [("channel", 8), ("timestamp", 32)], 3) + dut = lane_distributor.LaneDistributor(LANE_COUNT, 8, [("channel", 8), ("timestamp", 32)], 3) output = [] access_results = [] From 3c922463a0d49779c8120d581e1f1fbf417c0974 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 15 Sep 2017 15:36:46 +0800 Subject: [PATCH 0020/2457] style --- artiq/gateware/rtio/sed/tsc_gate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/gateware/rtio/sed/tsc_gate.py b/artiq/gateware/rtio/sed/tsc_gate.py index 38e35081e..4114a8f3c 100644 --- a/artiq/gateware/rtio/sed/tsc_gate.py +++ b/artiq/gateware/rtio/sed/tsc_gate.py @@ -6,7 +6,6 @@ from artiq.gateware.rtio.sed import layouts __all__ = ["TSCGate"] - class TSCGate(Module): def __init__(self, lane_count, seqn_width, layout_fifo_payload, layout_output_network_payload): self.input = [Record(layouts.fifo_egress(seqn_width, layout_fifo_payload)) From 1cb05f3ed50ed3c9cbc83a64f507db83187ad1d4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 10:51:44 +0800 Subject: [PATCH 0021/2457] rtio/sed/LaneDistributor: persist underflow/sequence error until next write --- artiq/gateware/rtio/sed/lane_distributor.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index c58dfeb6d..a65521028 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -102,8 +102,16 @@ class LaneDistributor(Module): o_status_wait.eq(~current_lane_writable) ] self.sync += [ - o_status_underflow.eq(do_underflow), - o_status_sequence_error.eq(do_sequence_error) + If(self.cri.cmd == cri.commands["write"], + o_status_underflow.eq(0), + o_status_sequence_error.eq(0) + ), + If(do_underflow, + o_status_underflow.eq(1) + ), + If(do_sequence_error, + o_status_sequence_error.eq(1) + ) ] # current lane has been full, spread events by switching to the next. From 064503f22422bc4e318de644f7e2b7cfcdff3209 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 10:52:13 +0800 Subject: [PATCH 0022/2457] rtio/sed/LaneDistributor: support specifying existing CRI --- artiq/gateware/rtio/sed/lane_distributor.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index a65521028..1c191ba6f 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -7,18 +7,19 @@ from artiq.gateware.rtio.sed import layouts __all__ = ["LaneDistributor"] - # CRI write happens in 3 cycles: # 1. set timestamp # 2. set other payload elements and issue write command # 3. check status class LaneDistributor(Module): - def __init__(self, lane_count, seqn_width, layout_payload, fine_ts_width, enable_spread=True): + def __init__(self, lane_count, seqn_width, layout_payload, fine_ts_width, enable_spread=True, interface=None): if lane_count & (lane_count - 1): raise NotImplementedError("lane count must be a power of 2") - self.cri = cri.Interface() + if interface is None: + interface = cri.Interface() + self.cri = interface self.minimum_coarse_timestamp = Signal(64-fine_ts_width) self.lane_io = [Record(layouts.fifo_ingress(seqn_width, layout_payload)) for _ in range(lane_count)] From f39ee7ad6216ddae86908303426b68f4612dcd28 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 10:52:37 +0800 Subject: [PATCH 0023/2457] rtio/sed: fix seqn_width --- artiq/gateware/rtio/sed/layouts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/sed/layouts.py b/artiq/gateware/rtio/sed/layouts.py index 5feac13b2..35dbbf460 100644 --- a/artiq/gateware/rtio/sed/layouts.py +++ b/artiq/gateware/rtio/sed/layouts.py @@ -21,10 +21,10 @@ def fifo_payload(channels): return layout -def seqn_width(lane_count, fifo_width): +def seqn_width(lane_count, fifo_depth): # There must be a unique sequence number for every possible event in every FIFO. # Plus 2 bits to detect and handle wraparounds. - return bits_for(lane_count*fifo_size-1) + 2 + return bits_for(lane_count*fifo_depth-1) + 2 def fifo_ingress(seqn_width, layout_payload): From 6b7a1893c783bd982ef3966a25a4443a8302f9eb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 10:53:30 +0800 Subject: [PATCH 0024/2457] rtio/sed/OutputDriver: support channels with different fine timestamp widths --- artiq/gateware/rtio/sed/output_driver.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/rtio/sed/output_driver.py b/artiq/gateware/rtio/sed/output_driver.py index 4edf83d34..ff7086031 100644 --- a/artiq/gateware/rtio/sed/output_driver.py +++ b/artiq/gateware/rtio/sed/output_driver.py @@ -61,6 +61,8 @@ class OutputDriver(Module): # demultiplex channels (adds one pipeline stage) for n, channel in enumerate(channels): + oif = channel.interface.o + onehot_stb = [] onehot_fine_ts = [] onehot_address = [] @@ -69,14 +71,14 @@ class OutputDriver(Module): selected = Signal() self.comb += selected.eq(lane_data.valid & ~lane_data.collision & (lane_data.payload.channel == n)) onehot_stb.append(selected) - if hasattr(lane_data.payload, "fine_ts"): - onehot_fine_ts.append(Mux(selected, lane_data.payload.fine_ts, 0)) + if hasattr(lane_data.payload, "fine_ts") and hasattr(oif, "fine_ts"): + ts_shift = len(lane_data.payload.fine_ts) - len(oif.fine_ts) + onehot_fine_ts.append(Mux(selected, lane_data.payload.fine_ts[ts_shift:], 0)) if hasattr(lane_data.payload, "address"): onehot_address.append(Mux(selected, lane_data.payload.address, 0)) if hasattr(lane_data.payload, "data"): onehot_data.append(Mux(selected, lane_data.payload.data, 0)) - oif = channel.interface.o self.sync += oif.stb.eq(reduce(or_, onehot_stb)) if hasattr(oif, "fine_ts"): self.sync += oif.fine_ts.eq(reduce(or_, onehot_fine_ts)) From 7b299ba58335eb7d9d1a705b5611b1fa8cfac6ef Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 14:01:19 +0800 Subject: [PATCH 0025/2457] rtio/sed: remove obsolete ofifo_depth from test_output_driver --- artiq/gateware/test/rtio/test_sed_output_driver.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/test/rtio/test_sed_output_driver.py b/artiq/gateware/test/rtio/test_sed_output_driver.py index f5f038426..44e478e42 100644 --- a/artiq/gateware/test/rtio/test_sed_output_driver.py +++ b/artiq/gateware/test/rtio/test_sed_output_driver.py @@ -30,10 +30,10 @@ class DUT(Module): self.submodules.phy3 = BusyPHY() rtio_channels = [ - rtio.Channel.from_phy(self.phy0, ofifo_depth=4), - rtio.Channel.from_phy(self.phy1, ofifo_depth=4), - rtio.Channel.from_phy(self.phy2, ofifo_depth=4), - rtio.Channel.from_phy(self.phy3, ofifo_depth=4), + rtio.Channel.from_phy(self.phy0), + rtio.Channel.from_phy(self.phy1), + rtio.Channel.from_phy(self.phy2), + rtio.Channel.from_phy(self.phy3), ] self.submodules.output_driver = output_driver.OutputDriver( From ac52c7c818a83526d9384366d4e21e7e53669a50 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 14:02:37 +0800 Subject: [PATCH 0026/2457] rtio/sed/LaneDistributor: style --- artiq/gateware/rtio/sed/lane_distributor.py | 15 ++++++++------- .../test/rtio/test_sed_lane_distributor.py | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index 1c191ba6f..6e877c3bf 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -13,7 +13,8 @@ __all__ = ["LaneDistributor"] # 3. check status class LaneDistributor(Module): - def __init__(self, lane_count, seqn_width, layout_payload, fine_ts_width, enable_spread=True, interface=None): + def __init__(self, lane_count, seqn_width, layout_payload, fine_ts_width, + enable_spread=True, interface=None): if lane_count & (lane_count - 1): raise NotImplementedError("lane count must be a power of 2") @@ -21,8 +22,8 @@ class LaneDistributor(Module): interface = cri.Interface() self.cri = interface self.minimum_coarse_timestamp = Signal(64-fine_ts_width) - self.lane_io = [Record(layouts.fifo_ingress(seqn_width, layout_payload)) - for _ in range(lane_count)] + self.output = [Record(layouts.fifo_ingress(seqn_width, layout_payload)) + for _ in range(lane_count)] # # # @@ -40,7 +41,7 @@ class LaneDistributor(Module): seqn = Signal(seqn_width) # distribute data to lanes - for lio in self.lane_io: + for lio in self.output: self.comb += [ lio.seqn.eq(seqn), lio.payload.channel.eq(self.cri.chan_sel[:16]), @@ -49,7 +50,7 @@ class LaneDistributor(Module): if hasattr(lio.payload, "address"): self.comb += lio.payload.address.eq(self.cri.address) if hasattr(lio.payload, "data"): - self.comb += lio.payload.data.eq(self.cri.data) + self.comb += lio.payload.data.eq(self.cri.o_data) # when timestamp arrives in cycle #1, prepare computations coarse_timestamp = Signal(64-fine_ts_width) @@ -85,7 +86,7 @@ class LaneDistributor(Module): do_write.eq((self.cri.cmd == cri.commands["write"]) & timestamp_above_min & timestamp_above_lane_min), do_underflow.eq((self.cri.cmd == cri.commands["write"]) & ~timestamp_above_min), do_sequence_error.eq((self.cri.cmd == cri.commands["write"]) & timestamp_above_min & ~timestamp_above_lane_min), - Array(lio.we for lio in self.lane_io)[use_lanen].eq(do_write) + Array(lio.we for lio in self.output)[use_lanen].eq(do_write) ] self.sync += [ If(do_write, @@ -99,7 +100,7 @@ class LaneDistributor(Module): # cycle #3, read status current_lane_writable = Signal() self.comb += [ - current_lane_writable.eq(Array(lio.writable for lio in self.lane_io)[current_lane]), + current_lane_writable.eq(Array(lio.writable for lio in self.output)[current_lane]), o_status_wait.eq(~current_lane_writable) ] self.sync += [ diff --git a/artiq/gateware/test/rtio/test_sed_lane_distributor.py b/artiq/gateware/test/rtio/test_sed_lane_distributor.py index f7c4efa28..4c57bc9c8 100644 --- a/artiq/gateware/test/rtio/test_sed_lane_distributor.py +++ b/artiq/gateware/test/rtio/test_sed_lane_distributor.py @@ -58,7 +58,7 @@ def simulate(input_events, wait=True): yield generators = [gen()] - for n, lio in enumerate(dut.lane_io): + for n, lio in enumerate(dut.output): lio.writable.reset = 1 wait_time = 0 if wait: From 92c63ce2e4b688e39d22f7bd368deffb0de79c14 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 14:03:48 +0800 Subject: [PATCH 0027/2457] rtio/sed: rename fifos/gates, refactor tsc --- artiq/gateware/rtio/sed/{fifo.py => fifos.py} | 16 ++++++++-------- .../gateware/rtio/sed/{tsc_gate.py => gates.py} | 14 ++++++-------- 2 files changed, 14 insertions(+), 16 deletions(-) rename artiq/gateware/rtio/sed/{fifo.py => fifos.py} (66%) rename artiq/gateware/rtio/sed/{tsc_gate.py => gates.py} (83%) diff --git a/artiq/gateware/rtio/sed/fifo.py b/artiq/gateware/rtio/sed/fifos.py similarity index 66% rename from artiq/gateware/rtio/sed/fifo.py rename to artiq/gateware/rtio/sed/fifos.py index 1f908a0c1..da0f4fcfe 100644 --- a/artiq/gateware/rtio/sed/fifo.py +++ b/artiq/gateware/rtio/sed/fifos.py @@ -4,21 +4,21 @@ from migen.genlib.fifo import * from artiq.gateware.rtio.sed import layouts -__all__ = ["FIFO"] +__all__ = ["FIFOs"] -class FIFO(Module): - def __init__(self, lane_count, mode, fifo_depth, layout_payload): - seqn_width = layouts.seqn_width(lane_count, fifo_width) - self.input = [layouts.fifo_ingress(seqn_width, layout_payload) +class FIFOs(Module): + def __init__(self, lane_count, fifo_depth, layout_payload, mode): + seqn_width = layouts.seqn_width(lane_count, fifo_depth) + self.input = [Record(layouts.fifo_ingress(seqn_width, layout_payload)) for _ in range(lane_count)] - self.output = [layouts.fifo_egress(seqn_width, layout_payload) + self.output = [Record(layouts.fifo_egress(seqn_width, layout_payload)) for _ in range(lane_count)] if mode == "sync": - fifo_cls = fifo.SyncFIFOBuffered + fifo_cls = SyncFIFOBuffered elif mode == "async": - fifo_cls = fifo.AsyncFIFO + fifo_cls = AsyncFIFO else: raise ValueError diff --git a/artiq/gateware/rtio/sed/tsc_gate.py b/artiq/gateware/rtio/sed/gates.py similarity index 83% rename from artiq/gateware/rtio/sed/tsc_gate.py rename to artiq/gateware/rtio/sed/gates.py index 4114a8f3c..3475c71a1 100644 --- a/artiq/gateware/rtio/sed/tsc_gate.py +++ b/artiq/gateware/rtio/sed/gates.py @@ -3,10 +3,10 @@ from migen import * from artiq.gateware.rtio.sed import layouts -__all__ = ["TSCGate"] +__all__ = ["Gates"] -class TSCGate(Module): +class Gates(Module): def __init__(self, lane_count, seqn_width, layout_fifo_payload, layout_output_network_payload): self.input = [Record(layouts.fifo_egress(seqn_width, layout_fifo_payload)) for _ in range(lane_count)] @@ -17,12 +17,11 @@ class TSCGate(Module): fine_ts_width = len(self.output[0].fine_ts) else: fine_ts_width = 0 - self.tsc = Signal(64-fine_ts_width) + + self.coarse_timestamp = Signal(64-fine_ts_width) # # # - self.sync += self.tsc.eq(self.tsc + 1) - for input, output in zip(self.input, self.output): for field, _ in output.payload.layout: if field == "fine_ts": @@ -32,6 +31,5 @@ class TSCGate(Module): self.sync += output.seqn.eq(input.seqn) self.comb += output.replace_occured.eq(0) - self.comb += input.re.eq(input.payload.timestamp[fine_ts_width:] == self.tsc) - self.sync += ouput.valid.eq(input.re & input.readable) - + self.comb += input.re.eq(input.payload.timestamp[fine_ts_width:] == self.coarse_timestamp) + self.sync += output.valid.eq(input.re & input.readable) From a155a481b1f31b0984a297e8d44dec135042a863 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 14:04:56 +0800 Subject: [PATCH 0028/2457] rtio/sed: add top-level core --- artiq/gateware/rtio/sed/core.py | 81 +++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 artiq/gateware/rtio/sed/core.py diff --git a/artiq/gateware/rtio/sed/core.py b/artiq/gateware/rtio/sed/core.py new file mode 100644 index 000000000..ba87191ad --- /dev/null +++ b/artiq/gateware/rtio/sed/core.py @@ -0,0 +1,81 @@ +from migen import * + +from artiq.gateware.rtio import rtlink +from artiq.gateware.rtio.sed import layouts +from artiq.gateware.rtio.sed.lane_distributor import * +from artiq.gateware.rtio.sed.fifos import * +from artiq.gateware.rtio.sed.gates import * +from artiq.gateware.rtio.sed.output_driver import * + + +__all__ = ["SED"] + + +class SED(Module): + def __init__(self, channels, mode, enable_spread=True, lane_count=8, fifo_depth=128, interface=None): + if mode == "sync": + lane_dist_cdr = lambda x: x + fifos_cdr = lambda x: x + gates_cdr = lambda x: x + output_driver_cdr = lambda x: x + elif mode == "async": + lane_dist_cdr = ClockDomainsRenamer("rsys") + fifos_cdr = ClockDomainsRenamer({"write": "rsys", "read": "rio"}) + gates_cdr = ClockDomainsRenamer("rio") + output_driver_cdr = ClockDomainsRenamer("rio") + else: + raise ValueError + + fine_ts_width = max(rtlink.get_fine_ts_width(c.interface) + for c in channels) + seqn_width = layouts.seqn_width(lane_count, fifo_depth) + + self.submodules.lane_dist = lane_dist_cdr( + LaneDistributor(lane_count, seqn_width, + layouts.fifo_payload(channels), fine_ts_width, + enable_spread=enable_spread, + interface=interface)) + self.submodules.fifos = fifos_cdr( + FIFOs(lane_count, fifo_depth, + layouts.fifo_payload(channels), mode)) + self.submodules.gates = gates_cdr( + Gates(lane_count, seqn_width, + layouts.fifo_payload(channels), + layouts.output_network_payload(channels))) + self.submodules.output_driver = output_driver_cdr( + OutputDriver(channels, lane_count, seqn_width)) + + for o, i in zip(self.lane_dist.output, self.fifos.input): + self.comb += o.connect(i) + for o, i in zip(self.fifos.output, self.gates.input): + self.comb += o.connect(i) + for o, i in zip(self.gates.output, self.output_driver.input): + self.comb += i.eq(o) + + @property + def cri(self): + return self.lane_dist.cri + + @property + def minimum_coarse_timestamp(self): + return self.lane_dist.minimum_coarse_timestamp + + @property + def coarse_timestamp(self): + return self.gates.coarse_timestamp + + @property + def collision(self): + return self.output_driver.collision + + @property + def collision_channel(self): + return self.output_driver.collision_channel + + @property + def busy(self): + return self.output_driver.busy + + @property + def busy_channel(self): + return self.output_driver.busy_channel From 25c644c663aea4e808d78b761245eeb9028fb47e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 14:05:08 +0800 Subject: [PATCH 0029/2457] rtio/sed: add top-level core unit test --- artiq/gateware/test/rtio/test_sed_top.py | 87 ++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 artiq/gateware/test/rtio/test_sed_top.py diff --git a/artiq/gateware/test/rtio/test_sed_top.py b/artiq/gateware/test/rtio/test_sed_top.py new file mode 100644 index 000000000..25a65ae2a --- /dev/null +++ b/artiq/gateware/test/rtio/test_sed_top.py @@ -0,0 +1,87 @@ +import unittest +import itertools + +from migen import * + +from artiq.gateware import rtio +from artiq.gateware.rtio import cri +from artiq.gateware.rtio.sed.core import * +from artiq.gateware.rtio.phy import ttl_simple + + +class DUT(Module): + def __init__(self): + self.ttl0 = Signal() + self.ttl1 = Signal() + + self.submodules.phy0 = ttl_simple.Output(self.ttl0) + self.submodules.phy1 = ttl_simple.Output(self.ttl1) + + rtio_channels = [ + rtio.Channel.from_phy(self.phy0), + rtio.Channel.from_phy(self.phy1) + ] + + self.submodules.sed = SED(rtio_channels, "sync") + self.sync += [ + self.sed.coarse_timestamp.eq(self.sed.coarse_timestamp + 1), + self.sed.minimum_coarse_timestamp.eq(self.sed.coarse_timestamp + 16) + ] + +def simulate(input_events): + dut = DUT() + + ttl_changes = [] + access_results = [] + + def gen(): + yield dut.sed.cri.chan_sel.eq(0) + for timestamp, data in input_events: + yield dut.sed.cri.timestamp.eq(timestamp) + yield dut.sed.cri.o_data.eq(data) + yield + + yield dut.sed.cri.cmd.eq(cri.commands["write"]) + yield + yield dut.sed.cri.cmd.eq(cri.commands["nop"]) + + access_time = 0 + yield + while (yield dut.sed.cri.o_status) & 0x01: + yield + access_time += 1 + + status = (yield dut.sed.cri.o_status) + access_status = "ok" + if status & 0x02: + access_status = "underflow" + if status & 0x04: + access_status = "sequence_error" + + access_results.append((access_status, access_time)) + + @passive + def monitor(): + old_ttl_state = 0 + for time in itertools.count(): + ttl_state = yield dut.ttl0 + if ttl_state != old_ttl_state: + ttl_changes.append(time) + old_ttl_state = ttl_state + yield + + run_simulation(dut, {"sys": [ + gen(), monitor(), + (None for _ in range(45)) + ]}, {"sys": 5, "rio": 5, "rio_phy": 5}) + + return ttl_changes, access_results + + +class TestSED(unittest.TestCase): + def test_sed(self): + input_events = [(18, 1), (20, 0), (25, 1), (30, 0)] + latency = 11 + ttl_changes, access_results = simulate(input_events) + self.assertEqual(ttl_changes, [e[0] + latency for e in input_events]) + self.assertEqual(access_results, [("ok", 0)]*len(input_events)) From 131f5e4a3b057abc56023472845a6dcfa5bf5946 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 14:13:01 +0800 Subject: [PATCH 0030/2457] rtio/sed/LaneDistributor: fix CRI address --- artiq/gateware/rtio/sed/lane_distributor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index 6e877c3bf..aee932157 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -48,7 +48,7 @@ class LaneDistributor(Module): lio.payload.timestamp.eq(self.cri.timestamp), ] if hasattr(lio.payload, "address"): - self.comb += lio.payload.address.eq(self.cri.address) + self.comb += lio.payload.address.eq(self.cri.o_address) if hasattr(lio.payload, "data"): self.comb += lio.payload.data.eq(self.cri.o_data) From a3bb6c167c6d7f2b337962b436df4970f38b6a8b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 14:13:42 +0800 Subject: [PATCH 0031/2457] rtio: use SED --- artiq/gateware/drtio/rt_controller_master.py | 19 +- artiq/gateware/rtio/__init__.py | 3 +- artiq/gateware/rtio/cdc.py | 20 +- artiq/gateware/rtio/channel.py | 36 ++ artiq/gateware/rtio/core.py | 433 +++++-------------- 5 files changed, 164 insertions(+), 347 deletions(-) create mode 100644 artiq/gateware/rtio/channel.py diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index d97f418c6..0522e68e2 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -7,7 +7,6 @@ from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.interconnect.csr import * -from artiq.gateware.rtio.cdc import RTIOCounter from artiq.gateware.rtio import cri @@ -33,6 +32,24 @@ class _CSRs(AutoCSR): self.o_wait = CSRStatus() +class RTIOCounter(Module): + def __init__(self, width): + self.width = width + # Timestamp counter in RTIO domain + self.value_rtio = Signal(width) + # Timestamp counter resynchronized to sys domain + # Lags behind value_rtio, monotonic and glitch-free + self.value_sys = Signal(width) + + # # # + + # note: counter is in rtio domain and never affected by the reset CSRs + self.sync.rtio += self.value_rtio.eq(self.value_rtio + 1) + gt = GrayCodeTransfer(width) + self.submodules += gt + self.comb += gt.i.eq(self.value_rtio), self.value_sys.eq(gt.o) + + class RTController(Module): def __init__(self, rt_packet, channel_count, fine_ts_width): self.csrs = _CSRs() diff --git a/artiq/gateware/rtio/__init__.py b/artiq/gateware/rtio/__init__.py index 18feec299..718f2bc7f 100644 --- a/artiq/gateware/rtio/__init__.py +++ b/artiq/gateware/rtio/__init__.py @@ -1,5 +1,6 @@ from artiq.gateware.rtio.cri import KernelInitiator, CRIInterconnectShared -from artiq.gateware.rtio.core import Channel, LogChannel, Core +from artiq.gateware.rtio.channel import Channel, LogChannel +from artiq.gateware.rtio.core import Core from artiq.gateware.rtio.analyzer import Analyzer from artiq.gateware.rtio.moninj import MonInj from artiq.gateware.rtio.dma import DMA diff --git a/artiq/gateware/rtio/cdc.py b/artiq/gateware/rtio/cdc.py index af93b4105..493b1e2e8 100644 --- a/artiq/gateware/rtio/cdc.py +++ b/artiq/gateware/rtio/cdc.py @@ -2,7 +2,7 @@ from migen import * from migen.genlib.cdc import * -__all__ = ["GrayCodeTransfer", "RTIOCounter", "BlindTransfer"] +__all__ = ["GrayCodeTransfer", "BlindTransfer"] # note: transfer is in rtio/sys domains and not affected by the reset CSRs @@ -28,24 +28,6 @@ class GrayCodeTransfer(Module): self.sync += self.o.eq(value_sys) -class RTIOCounter(Module): - def __init__(self, width): - self.width = width - # Timestamp counter in RTIO domain - self.value_rtio = Signal(width) - # Timestamp counter resynchronized to sys domain - # Lags behind value_rtio, monotonic and glitch-free - self.value_sys = Signal(width) - - # # # - - # note: counter is in rtio domain and never affected by the reset CSRs - self.sync.rtio += self.value_rtio.eq(self.value_rtio + 1) - gt = GrayCodeTransfer(width) - self.submodules += gt - self.comb += gt.i.eq(self.value_rtio), self.value_sys.eq(gt.o) - - class BlindTransfer(Module): def __init__(self, idomain="rio", odomain="rsys"): self.i = Signal() diff --git a/artiq/gateware/rtio/channel.py b/artiq/gateware/rtio/channel.py new file mode 100644 index 000000000..5e85a1add --- /dev/null +++ b/artiq/gateware/rtio/channel.py @@ -0,0 +1,36 @@ +import warnings + +from artiq.gateware.rtio import rtlink + + +class Channel: + def __init__(self, interface, probes=None, overrides=None, + ofifo_depth=None, ififo_depth=64): + if probes is None: + probes = [] + if overrides is None: + overrides = [] + + self.interface = interface + self.probes = probes + self.overrides = overrides + if ofifo_depth is None: + ofifo_depth = 64 + else: + warnings.warn("ofifo_depth is deprecated", DeprecationWarning) + self.ofifo_depth = ofifo_depth + self.ififo_depth = ififo_depth + + @classmethod + def from_phy(cls, phy, **kwargs): + probes = getattr(phy, "probes", []) + overrides = getattr(phy, "overrides", []) + return cls(phy.rtlink, probes, overrides, **kwargs) + + +class LogChannel: + """A degenerate channel used to log messages into the analyzer.""" + def __init__(self): + self.interface = rtlink.Interface(rtlink.OInterface(32)) + self.probes = [] + self.overrides = [] diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 76bcd09ee..87c5975ee 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -5,195 +5,18 @@ from migen import * from migen.genlib.record import Record from migen.genlib.fifo import AsyncFIFO from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.cdc import PulseSynchronizer from misoc.interconnect.csr import * -from artiq.gateware.rtio import cri, rtlink +from artiq.gateware.rtio import cri +from artiq.gateware.rtio import rtlink +from artiq.gateware.rtio.channel import * from artiq.gateware.rtio.cdc import * - - -# CHOOSING A GUARD TIME -# -# The buffer must be transferred to the FIFO soon enough to account for: -# * transfer of counter to sys domain: Tio + 2*Tsys + Tsys -# * FIFO latency: Tsys + 2*Tio -# * FIFO buffer latency: Tio -# Therefore we must choose: -# guard_io_cycles > (4*Tio + 4*Tsys)/Tio -# -# We are writing to the FIFO from the buffer when the guard time has been -# reached. This can fill the FIFO and deassert the writable flag. A race -# condition occurs that causes problems if the deassertion happens between -# the CPU checking the writable flag (and reading 1) and writing a new event. -# -# When the FIFO is about to be full, it contains fifo_depth-1 events of -# strictly increasing timestamps. -# -# Thus the FIFO-filling event's timestamp must satisfy: -# timestamp*Tio > (fifo_depth-1)*Tio + time -# We also have (guard time reached): -# timestamp*Tio < time + guard_io_cycles*Tio -# [NB: time > counter.value_sys*Tio] -# Thus we must have: -# guard_io_cycles > fifo_depth-1 -# -# We can prevent overflows by choosing instead: -# guard_io_cycles < fifo_depth-1 - -class _OutputManager(Module): - def __init__(self, interface, counter, fifo_depth, guard_io_cycles): - data_width = rtlink.get_data_width(interface) - address_width = rtlink.get_address_width(interface) - fine_ts_width = rtlink.get_fine_ts_width(interface) - - ev_layout = [] - if data_width: - ev_layout.append(("data", data_width)) - if address_width: - ev_layout.append(("address", address_width)) - ev_layout.append(("timestamp", counter.width + fine_ts_width)) - # ev must be valid 1 cycle before we to account for the latency in - # generating replace, sequence_error and collision - self.ev = Record(ev_layout) - - self.writable = Signal() - self.we = Signal() # maximum throughput 1/2 - - self.underflow = Signal() # valid 1 cycle after we, pulsed - self.sequence_error = Signal() - self.collision = Signal() - self.busy = Signal() # pulsed - - # # # - - # FIFO - fifo = ClockDomainsRenamer({"write": "rsys", "read": "rio"})( - AsyncFIFO(layout_len(ev_layout), fifo_depth)) - self.submodules += fifo - fifo_in = Record(ev_layout) - fifo_out = Record(ev_layout) - self.comb += [ - fifo.din.eq(fifo_in.raw_bits()), - fifo_out.raw_bits().eq(fifo.dout) - ] - - # Buffer - buf_pending = Signal() - buf = Record(ev_layout) - buf_just_written = Signal() - - # Special cases - replace = Signal(reset_less=True) - sequence_error = Signal(reset_less=True) - collision = Signal(reset_less=True) - any_error = Signal() - if interface.enable_replace: - # Note: replace may be asserted at the same time as collision - # when addresses are different. In that case, it is a collision. - self.sync.rsys += replace.eq(self.ev.timestamp == buf.timestamp) - # Detect sequence errors on coarse timestamps only - # so that they are mutually exclusive with collision errors. - self.sync.rsys += sequence_error.eq(self.ev.timestamp[fine_ts_width:] < - buf.timestamp[fine_ts_width:]) - if interface.enable_replace: - if address_width: - different_addresses = self.ev.address != buf.address - else: - different_addresses = 0 - if fine_ts_width: - self.sync.rsys += collision.eq( - (self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:]) - & ((self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width]) - |different_addresses)) - else: - self.sync.rsys += collision.eq( - (self.ev.timestamp == buf.timestamp) & different_addresses) - else: - self.sync.rsys += collision.eq( - self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:]) - self.comb += [ - any_error.eq(sequence_error | collision), - self.sequence_error.eq(self.we & sequence_error), - self.collision.eq(self.we & collision) - ] - - # Buffer read and FIFO write - self.comb += fifo_in.eq(buf) - in_guard_time = Signal() - self.comb += in_guard_time.eq( - buf.timestamp[fine_ts_width:] - < counter.value_sys + guard_io_cycles) - self.sync.rsys += If(in_guard_time, buf_pending.eq(0)) - self.comb += \ - If(buf_pending, - If(in_guard_time, - If(buf_just_written, - self.underflow.eq(1) - ).Else( - fifo.we.eq(1) - ) - ), - If(self.we & ~replace & ~any_error, - fifo.we.eq(1) - ) - ) - - # Buffer write - # Must come after read to handle concurrent read+write properly - self.sync.rsys += [ - buf_just_written.eq(0), - If(self.we & ~any_error, - buf_just_written.eq(1), - buf_pending.eq(1), - buf.eq(self.ev) - ) - ] - self.comb += self.writable.eq(fifo.writable) - - # Buffer output of FIFO to improve timing - dout_stb = Signal() - dout_ack = Signal() - dout = Record(ev_layout) - self.sync.rio += \ - If(fifo.re, - dout_stb.eq(1), - dout.eq(fifo_out) - ).Elif(dout_ack, - dout_stb.eq(0) - ) - self.comb += fifo.re.eq(fifo.readable & (~dout_stb | dout_ack)) - - # latency compensation - if interface.delay: - counter_rtio = Signal.like(counter.value_rtio, reset_less=True) - self.sync.rtio += counter_rtio.eq(counter.value_rtio - - (interface.delay + 1)) - else: - counter_rtio = counter.value_rtio - - # FIFO read through buffer - self.comb += [ - dout_ack.eq( - dout.timestamp[fine_ts_width:] == counter_rtio), - interface.stb.eq(dout_stb & dout_ack) - ] - - busy_transfer = BlindTransfer() - self.submodules += busy_transfer - self.comb += [ - busy_transfer.i.eq(interface.stb & interface.busy), - self.busy.eq(busy_transfer.o), - ] - - if data_width: - self.comb += interface.data.eq(dout.data) - if address_width: - self.comb += interface.address.eq(dout.address) - if fine_ts_width: - self.comb += interface.fine_ts.eq(dout.timestamp[:fine_ts_width]) +from artiq.gateware.rtio.sed.core import * class _InputManager(Module): - def __init__(self, interface, counter, fifo_depth): + def __init__(self, interface, coarse_ts, fifo_depth): data_width = rtlink.get_data_width(interface) fine_ts_width = rtlink.get_fine_ts_width(interface) @@ -201,7 +24,7 @@ class _InputManager(Module): if data_width: ev_layout.append(("data", data_width)) if interface.timestamped: - ev_layout.append(("timestamp", counter.width + fine_ts_width)) + ev_layout.append(("timestamp", len(coarse_ts) + fine_ts_width)) self.ev = Record(ev_layout) self.readable = Signal() @@ -223,11 +46,11 @@ class _InputManager(Module): # latency compensation if interface.delay: - counter_rtio = Signal.like(counter.value_rtio, reset_less=True) - self.sync.rtio += counter_rtio.eq(counter.value_rtio - + counter_rtio = Signal.like(coarse_ts, reset_less=True) + self.sync.rtio += counter_rtio.eq(coarse_ts - (interface.delay + 1)) else: - counter_rtio = counter.value_rtio + counter_rtio = coarse_ts # FIFO write if data_width: @@ -255,41 +78,80 @@ class _InputManager(Module): ] -class Channel: - def __init__(self, interface, probes=None, overrides=None, - ofifo_depth=64, ififo_depth=64): - if probes is None: - probes = [] - if overrides is None: - overrides = [] +class _Inputs(Module): + def __init__(self, interface, coarse_ts, channels): + self.cri = interface - self.interface = interface - self.probes = probes - self.overrides = overrides - self.ofifo_depth = ofifo_depth - self.ififo_depth = ififo_depth + # Inputs + i_statuses = [] + i_datas, i_timestamps = [], [] + i_ack = Signal() + sel = self.cri.chan_sel[:16] + for n, channel in enumerate(channels): + if isinstance(channel, LogChannel): + i_datas.append(0) + i_timestamps.append(0) + i_statuses.append(0) + continue - @classmethod - def from_phy(cls, phy, **kwargs): - probes = getattr(phy, "probes", []) - overrides = getattr(phy, "overrides", []) - return cls(phy.rtlink, probes, overrides, **kwargs) + if channel.interface.i is not None: + selected = Signal() + self.comb += selected.eq(sel == n) + i_manager = _InputManager(channel.interface.i, coarse_ts, + channel.ififo_depth) + self.submodules += i_manager -class LogChannel: - """A degenerate channel used to log messages into the analyzer.""" - def __init__(self): - self.interface = rtlink.Interface(rtlink.OInterface(32)) - self.probes = [] - self.overrides = [] + if hasattr(i_manager.ev, "data"): + i_datas.append(i_manager.ev.data) + else: + i_datas.append(0) + if channel.interface.i.timestamped: + ts_shift = (len(self.cri.i_timestamp) - len(i_manager.ev.timestamp)) + i_timestamps.append(i_manager.ev.timestamp << ts_shift) + else: + i_timestamps.append(0) + + overflow = Signal() + self.sync.rsys += [ + If(selected & i_ack, + overflow.eq(0)), + If(i_manager.overflow, + overflow.eq(1)) + ] + self.comb += i_manager.re.eq(selected & i_ack & ~overflow) + i_statuses.append(Cat(i_manager.readable & ~overflow, overflow)) + + else: + i_datas.append(0) + i_timestamps.append(0) + i_statuses.append(0) + + i_status_raw = Signal(2) + self.comb += i_status_raw.eq(Array(i_statuses)[sel]) + input_timeout = Signal.like(self.cri.timestamp) + input_pending = Signal() + self.sync.rsys += [ + i_ack.eq(0), + If(i_ack, + self.cri.i_status.eq(Cat(~i_status_raw[0], i_status_raw[1], 0)), + self.cri.i_data.eq(Array(i_datas)[sel]), + self.cri.i_timestamp.eq(Array(i_timestamps)[sel]), + ), + If((self.cri.counter >= input_timeout) | (i_status_raw != 0), + If(input_pending, i_ack.eq(1)), + input_pending.eq(0) + ), + If(self.cri.cmd == cri.commands["read"], + input_timeout.eq(self.cri.timestamp), + input_pending.eq(1), + self.cri.i_status.eq(0b100) + ) + ] class Core(Module, AutoCSR): - def __init__(self, channels, fine_ts_width=None, guard_io_cycles=20): - if fine_ts_width is None: - fine_ts_width = max(rtlink.get_fine_ts_width(c.interface) - for c in channels) - + def __init__(self, channels, lane_count=8, fifo_depth=128): self.cri = cri.Interface() self.reset = CSR() self.reset_phy = CSR() @@ -297,7 +159,7 @@ class Core(Module, AutoCSR): # Clocking/Reset # Create rsys, rio and rio_phy domains based on sys and rtio - # with reset controlled by CRI. + # with reset controlled by CSR. # # The `rio` CD contains logic that is reset with `core.reset()`. # That's state that could unduly affect subsequent experiments, @@ -327,125 +189,44 @@ class Core(Module, AutoCSR): self.specials += AsyncResetSynchronizer(self.cd_rio, cmd_reset) self.specials += AsyncResetSynchronizer(self.cd_rio_phy, cmd_reset_phy) - # Managers - self.submodules.counter = RTIOCounter(len(self.cri.timestamp) - fine_ts_width) + # TSC + fine_ts_width = max(rtlink.get_fine_ts_width(channel.interface) + for channel in channels) + coarse_ts = Signal(64-fine_ts_width) + self.sync.rtio += coarse_ts.eq(coarse_ts + 1) + coarse_ts_cdc = GrayCodeTransfer(len(coarse_ts)) + self.submodules += coarse_ts_cdc + self.comb += [ + coarse_ts_cdc.i.eq(coarse_ts), + self.cri.counter.eq(coarse_ts_cdc.o << fine_ts_width) + ] - # Collision is not an asynchronous error with local RTIO, but - # we treat it as such for consistency with DRTIO, where collisions - # are reported by the satellites. - o_underflow = Signal() - o_sequence_error = Signal() + # Asychronous output errors + o_collision_sync = PulseSynchronizer("rtio", "rsys") + o_busy_sync = PulseSynchronizer("rtio", "rsys") + self.submodules += o_collision_sync, o_busy_sync o_collision = Signal() o_busy = Signal() - self.sync.rsys += [ - If(self.cri.cmd == cri.commands["write"], - o_underflow.eq(0), - o_sequence_error.eq(0), - ) - ] self.sync += [ If(self.async_error.re, If(self.async_error.r[0], o_collision.eq(0)), If(self.async_error.r[1], o_busy.eq(0)), - ) + ), + If(o_collision_sync.o, o_collision.eq(1)), + If(o_busy_sync.o, o_busy.eq(1)) ] + self.comb += self.async_error.w.eq(Cat(o_collision, o_busy)) - o_statuses, i_statuses = [], [] - i_datas, i_timestamps = [], [] - i_ack = Signal() - sel = self.cri.chan_sel[:16] - for n, channel in enumerate(channels): - if isinstance(channel, LogChannel): - o_statuses.append(1) - i_datas.append(0) - i_timestamps.append(0) - i_statuses.append(0) - continue + # Inputs + inputs = _Inputs(self.cri, coarse_ts, channels) + self.submodules += inputs - selected = Signal() - self.comb += selected.eq(sel == n) - - o_manager = _OutputManager(channel.interface.o, self.counter, - channel.ofifo_depth, guard_io_cycles) - self.submodules += o_manager - - if hasattr(o_manager.ev, "data"): - self.comb += o_manager.ev.data.eq(self.cri.o_data) - if hasattr(o_manager.ev, "address"): - self.comb += o_manager.ev.address.eq(self.cri.o_address) - ts_shift = len(self.cri.timestamp) - len(o_manager.ev.timestamp) - self.comb += o_manager.ev.timestamp.eq(self.cri.timestamp[ts_shift:]) - - self.comb += o_manager.we.eq(selected & (self.cri.cmd == cri.commands["write"])) - - self.sync.rsys += [ - If(o_manager.underflow, o_underflow.eq(1)), - If(o_manager.sequence_error, o_sequence_error.eq(1)) - ] - self.sync += [ - If(o_manager.collision, o_collision.eq(1)), - If(o_manager.busy, o_busy.eq(1)) - ] - o_statuses.append(o_manager.writable) - - if channel.interface.i is not None: - i_manager = _InputManager(channel.interface.i, self.counter, - channel.ififo_depth) - self.submodules += i_manager - - if hasattr(i_manager.ev, "data"): - i_datas.append(i_manager.ev.data) - else: - i_datas.append(0) - if channel.interface.i.timestamped: - ts_shift = (len(self.cri.i_timestamp) - len(i_manager.ev.timestamp)) - i_timestamps.append(i_manager.ev.timestamp << ts_shift) - else: - i_timestamps.append(0) - - overflow = Signal() - self.sync.rsys += [ - If(selected & i_ack, - overflow.eq(0)), - If(i_manager.overflow, - overflow.eq(1)) - ] - self.comb += i_manager.re.eq(selected & i_ack & ~overflow) - i_statuses.append(Cat(i_manager.readable & ~overflow, overflow)) - - else: - i_datas.append(0) - i_timestamps.append(0) - i_statuses.append(0) - - o_status_raw = Signal() + # Outputs + outputs = SED(channels, "async", interface=self.cri) + self.submodules += outputs + self.comb += outputs.coarse_timestamp.eq(coarse_ts) + self.sync += outputs.minimum_coarse_timestamp.eq(coarse_ts + 16) self.comb += [ - o_status_raw.eq(Array(o_statuses)[sel]), - self.cri.o_status.eq(Cat( - ~o_status_raw, o_underflow, o_sequence_error)), - self.async_error.w.eq(Cat(o_collision, o_busy)) + o_collision_sync.i.eq(outputs.collision), + o_busy_sync.i.eq(outputs.busy) ] - - i_status_raw = Signal(2) - self.comb += i_status_raw.eq(Array(i_statuses)[sel]) - input_timeout = Signal.like(self.cri.timestamp) - input_pending = Signal() - self.sync.rsys += [ - i_ack.eq(0), - If(i_ack, - self.cri.i_status.eq(Cat(~i_status_raw[0], i_status_raw[1], 0)), - self.cri.i_data.eq(Array(i_datas)[sel]), - self.cri.i_timestamp.eq(Array(i_timestamps)[sel]), - ), - If((self.cri.counter >= input_timeout) | (i_status_raw != 0), - If(input_pending, i_ack.eq(1)), - input_pending.eq(0) - ), - If(self.cri.cmd == cri.commands["read"], - input_timeout.eq(self.cri.timestamp), - input_pending.eq(1), - self.cri.i_status.eq(0b100) - ) - ] - - self.comb += self.cri.counter.eq(self.counter.value_sys << fine_ts_width) From 30e7765a2ec194015757a800c53aa4c3ac7e4847 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 14:36:27 +0800 Subject: [PATCH 0032/2457] drtio: add missing import --- artiq/gateware/drtio/rt_controller_master.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 0522e68e2..b7ecfd5a3 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -7,6 +7,7 @@ from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.interconnect.csr import * +from artiq.gateware.rtio.cdc import GrayCodeTransfer from artiq.gateware.rtio import cri From 1cfe90b1d94e044d7ab1837f307ebe7a9ace5711 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 15:09:21 +0800 Subject: [PATCH 0033/2457] rtio/sed/Gates: fix fine_ts_width computation --- artiq/gateware/rtio/sed/gates.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/sed/gates.py b/artiq/gateware/rtio/sed/gates.py index 3475c71a1..7ed460d0c 100644 --- a/artiq/gateware/rtio/sed/gates.py +++ b/artiq/gateware/rtio/sed/gates.py @@ -13,8 +13,8 @@ class Gates(Module): self.output = [Record(layouts.output_network_node(seqn_width, layout_output_network_payload)) for _ in range(lane_count)] - if hasattr(self.output[0], "fine_ts"): - fine_ts_width = len(self.output[0].fine_ts) + if hasattr(self.output[0].payload, "fine_ts"): + fine_ts_width = len(self.output[0].payload.fine_ts) else: fine_ts_width = 0 From 0e25154e25ead77b402225bcd44531938833d02a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 15:19:30 +0800 Subject: [PATCH 0034/2457] rtio/sed: quash writes to LogChannel --- artiq/gateware/rtio/core.py | 4 +++- artiq/gateware/rtio/sed/core.py | 4 +++- artiq/gateware/rtio/sed/lane_distributor.py | 19 +++++++++++++------ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 87c5975ee..8492e31f4 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -222,7 +222,9 @@ class Core(Module, AutoCSR): self.submodules += inputs # Outputs - outputs = SED(channels, "async", interface=self.cri) + outputs = SED(channels, "async", + quash_channels=[n for n, c in enumerate(channels) if isinstance(c, LogChannel)], + interface=self.cri) self.submodules += outputs self.comb += outputs.coarse_timestamp.eq(coarse_ts) self.sync += outputs.minimum_coarse_timestamp.eq(coarse_ts + 16) diff --git a/artiq/gateware/rtio/sed/core.py b/artiq/gateware/rtio/sed/core.py index ba87191ad..30f16a863 100644 --- a/artiq/gateware/rtio/sed/core.py +++ b/artiq/gateware/rtio/sed/core.py @@ -12,7 +12,8 @@ __all__ = ["SED"] class SED(Module): - def __init__(self, channels, mode, enable_spread=True, lane_count=8, fifo_depth=128, interface=None): + def __init__(self, channels, mode, lane_count=8, fifo_depth=128, enable_spread=True, + quash_channels=[], interface=None): if mode == "sync": lane_dist_cdr = lambda x: x fifos_cdr = lambda x: x @@ -34,6 +35,7 @@ class SED(Module): LaneDistributor(lane_count, seqn_width, layouts.fifo_payload(channels), fine_ts_width, enable_spread=enable_spread, + quash_channels=quash_channels, interface=interface)) self.submodules.fifos = fifos_cdr( FIFOs(lane_count, fifo_depth, diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index aee932157..986d7a470 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -8,13 +8,13 @@ __all__ = ["LaneDistributor"] # CRI write happens in 3 cycles: -# 1. set timestamp +# 1. set timestamp and channel # 2. set other payload elements and issue write command # 3. check status class LaneDistributor(Module): def __init__(self, lane_count, seqn_width, layout_payload, fine_ts_width, - enable_spread=True, interface=None): + enable_spread=True, quash_channels=[], interface=None): if lane_count & (lane_count - 1): raise NotImplementedError("lane count must be a power of 2") @@ -52,7 +52,7 @@ class LaneDistributor(Module): if hasattr(lio.payload, "data"): self.comb += lio.payload.data.eq(self.cri.o_data) - # when timestamp arrives in cycle #1, prepare computations + # when timestamp and channel arrive in cycle #1, prepare computations coarse_timestamp = Signal(64-fine_ts_width) self.comb += coarse_timestamp.eq(self.cri.timestamp[fine_ts_width:]) timestamp_above_min = Signal() @@ -76,6 +76,11 @@ class LaneDistributor(Module): ) ] + quash = Signal() + self.sync += quash.eq(0) + for channel in quash_channels: + self.sync += If(self.cri.chan_sel[:16] == channel, quash.eq(1)) + # cycle #2, write timestamp_above_lane_min = Signal() do_write = Signal() @@ -83,9 +88,11 @@ class LaneDistributor(Module): do_sequence_error = Signal() self.comb += [ timestamp_above_lane_min.eq(Mux(use_laneB, timestamp_above_laneB_min, timestamp_above_laneA_min)), - do_write.eq((self.cri.cmd == cri.commands["write"]) & timestamp_above_min & timestamp_above_lane_min), - do_underflow.eq((self.cri.cmd == cri.commands["write"]) & ~timestamp_above_min), - do_sequence_error.eq((self.cri.cmd == cri.commands["write"]) & timestamp_above_min & ~timestamp_above_lane_min), + If(~quash, + do_write.eq((self.cri.cmd == cri.commands["write"]) & timestamp_above_min & timestamp_above_lane_min), + do_underflow.eq((self.cri.cmd == cri.commands["write"]) & ~timestamp_above_min), + do_sequence_error.eq((self.cri.cmd == cri.commands["write"]) & timestamp_above_min & ~timestamp_above_lane_min), + ), Array(lio.we for lio in self.output)[use_lanen].eq(do_write) ] self.sync += [ From 770ce2658fa88da46a55750086cf858ed4135571 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 16:28:57 +0800 Subject: [PATCH 0035/2457] test: adapt SequenceError test to SED --- artiq/test/coredevice/test_rtio.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 92a0d1abc..bc57ee19d 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -258,10 +258,10 @@ class SequenceError(EnvExperiment): @kernel def run(self): self.core.reset() - t = now_mu() - self.ttl_out.pulse(25*us) - at_mu(t) - self.ttl_out.pulse(25*us) + delay(55*256*us) + for _ in range(256): + self.ttl_out.pulse(25*us) + delay(-75*us) class Collision(EnvExperiment): From e2c1d4f3d590ee3742dd89e1148567665a78030c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 17:01:23 +0800 Subject: [PATCH 0036/2457] rtio/sed: trigger collision error on non-data replace --- artiq/gateware/rtio/sed/gates.py | 5 ++++- artiq/gateware/rtio/sed/layouts.py | 1 + artiq/gateware/rtio/sed/output_driver.py | 4 +++- artiq/gateware/rtio/sed/output_network.py | 8 ++++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/sed/gates.py b/artiq/gateware/rtio/sed/gates.py index 7ed460d0c..8d0f604e4 100644 --- a/artiq/gateware/rtio/sed/gates.py +++ b/artiq/gateware/rtio/sed/gates.py @@ -29,7 +29,10 @@ class Gates(Module): else: self.sync += getattr(output.payload, field).eq(getattr(input.payload, field)) self.sync += output.seqn.eq(input.seqn) - self.comb += output.replace_occured.eq(0) + self.comb += [ + output.replace_occured.eq(0), + output.nondata_replace_occured.eq(0) + ] self.comb += input.re.eq(input.payload.timestamp[fine_ts_width:] == self.coarse_timestamp) self.sync += output.valid.eq(input.re & input.readable) diff --git a/artiq/gateware/rtio/sed/layouts.py b/artiq/gateware/rtio/sed/layouts.py index 35dbbf460..b0a983911 100644 --- a/artiq/gateware/rtio/sed/layouts.py +++ b/artiq/gateware/rtio/sed/layouts.py @@ -69,5 +69,6 @@ def output_network_node(seqn_width, layout_payload): ("valid", 1), ("seqn", seqn_width), ("replace_occured", 1), + ("nondata_replace_occured", 1), ("payload", layout_payload) ] diff --git a/artiq/gateware/rtio/sed/output_driver.py b/artiq/gateware/rtio/sed/output_driver.py index ff7086031..7f26ec58a 100644 --- a/artiq/gateware/rtio/sed/output_driver.py +++ b/artiq/gateware/rtio/sed/output_driver.py @@ -33,10 +33,12 @@ class OutputDriver(Module): en_replaces = [channel.interface.o.enable_replace for channel in channels] for lane_data, on_output in zip(lane_datas, output_network.output): replace_occured_r = Signal() + nondata_replace_occured_r = Signal() self.sync += [ lane_data.valid.eq(on_output.valid), lane_data.payload.eq(on_output.payload), replace_occured_r.eq(on_output.replace_occured), + nondata_replace_occured_r.eq(on_output.nondata_replace_occured) ] en_replaces_rom = Memory(1, len(en_replaces), init=en_replaces) @@ -44,7 +46,7 @@ class OutputDriver(Module): self.specials += en_replaces_rom, en_replaces_rom_port self.comb += [ en_replaces_rom_port.adr.eq(on_output.payload.channel), - lane_data.collision.eq(replace_occured_r & ~en_replaces_rom_port.dat_r) + lane_data.collision.eq(replace_occured_r & (~en_replaces_rom_port.dat_r | nondata_replace_occured_r)) ] self.sync += [ diff --git a/artiq/gateware/rtio/sed/output_network.py b/artiq/gateware/rtio/sed/output_network.py index 05797bdcb..1b57baf9e 100644 --- a/artiq/gateware/rtio/sed/output_network.py +++ b/artiq/gateware/rtio/sed/output_network.py @@ -60,6 +60,13 @@ class OutputNetwork(Module): for _ in range(lane_count)] for node1, node2 in step: + nondata_difference = Signal() + for field, _ in layout_payload: + if field != "data": + f1 = getattr(step_input[node1].payload, field) + f2 = getattr(step_input[node2].payload, field) + self.comb += If(f1 != f2, nondata_difference.eq(1)) + k1 = Cat(step_input[node1].payload.channel, ~step_input[node1].valid) k2 = Cat(step_input[node2].payload.channel, ~step_input[node2].valid) self.sync += [ @@ -72,6 +79,7 @@ class OutputNetwork(Module): step_output[node2].eq(step_input[node2]) ), step_output[node1].replace_occured.eq(1), + step_output[node1].nondata_replace_occured.eq(nondata_difference), step_output[node2].valid.eq(0), ).Elif(k1 < k2, step_output[node1].eq(step_input[node1]), From 0824e0aeaedbebd6a266d1e92a0cb7bad9af76b0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 17:04:11 +0800 Subject: [PATCH 0037/2457] gateware/targets: remove deprecated ofifo_depth parameter --- artiq/gateware/targets/kc705_dds.py | 22 +++++++++------------- artiq/gateware/targets/kc705_sma_spi.py | 4 ++-- artiq/gateware/targets/phaser.py | 3 +-- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/artiq/gateware/targets/kc705_dds.py b/artiq/gateware/targets/kc705_dds.py index 7aad8930b..6c56fea26 100755 --- a/artiq/gateware/targets/kc705_dds.py +++ b/artiq/gateware/targets/kc705_dds.py @@ -224,24 +224,22 @@ class NIST_CLOCK(_NIST_Ions): phy = spi.SPIMaster(ams101_dac) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( - phy, ofifo_depth=4, ififo_depth=4)) + phy, ififo_depth=4)) for i in range(3): phy = spi.SPIMaster(self.platform.request("spi", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( - phy, ofifo_depth=128, ififo_depth=128)) - + phy, ififo_depth=128)) + phy = spi.SPIMaster(platform.request("sdcard_spi_33", 0)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( - phy, ofifo_depth=4, ififo_depth=4)) - + phy, ififo_depth=4)) + phy = dds.AD9914(platform.request("dds"), 11, onehot=True) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, - ofifo_depth=512, - ififo_depth=4)) + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) @@ -299,21 +297,19 @@ class NIST_QC2(_NIST_Ions): phy = spi.SPIMaster(ams101_dac) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( - phy, ofifo_depth=4, ififo_depth=4)) + phy, ififo_depth=4)) for i in range(4): phy = spi.SPIMaster(self.platform.request("spi", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( - phy, ofifo_depth=128, ififo_depth=128)) + phy, ififo_depth=128)) for backplane_offset in range(2): phy = dds.AD9914( platform.request("dds", backplane_offset), 12, onehot=True) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, - ofifo_depth=512, - ififo_depth=4)) + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) diff --git a/artiq/gateware/targets/kc705_sma_spi.py b/artiq/gateware/targets/kc705_sma_spi.py index cea74c574..63f91a3a5 100755 --- a/artiq/gateware/targets/kc705_sma_spi.py +++ b/artiq/gateware/targets/kc705_sma_spi.py @@ -101,12 +101,12 @@ class SMA_SPI(_NIST_Ions): phy = spi.SPIMaster(ams101_dac) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( - phy, ofifo_depth=4, ififo_depth=4)) + phy, ififo_depth=4)) phy = spi.SPIMaster(self.platform.request("sma_spi")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( - phy, ofifo_depth=128, ififo_depth=128)) + phy, ififo_depth=128)) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) diff --git a/artiq/gateware/targets/phaser.py b/artiq/gateware/targets/phaser.py index fe141837f..ba63b3819 100755 --- a/artiq/gateware/targets/phaser.py +++ b/artiq/gateware/targets/phaser.py @@ -213,8 +213,7 @@ class Phaser(MiniSoC, AMPSoC): sysref_pads = platform.request("ad9154_sysref") phy = ttl_serdes_7series.Input_8X(sysref_pads.p, sysref_pads.n) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32, - ofifo_depth=2)) + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=32)) self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels) rtio_channels.extend(rtio.Channel.from_phy(phy) From 53860868f49ea52afa1d733d072fd33fee15a11e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 16 Sep 2017 17:52:39 +0800 Subject: [PATCH 0038/2457] test/rtio: wait for counter >= now before checking for async errors --- artiq/test/coredevice/test_rtio.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index bc57ee19d..a120a94ec 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -276,6 +276,8 @@ class Collision(EnvExperiment): for i in range(16): self.ttl_out_serdes.pulse_mu(1) delay_mu(1) + while self.core.get_rtio_counter_mu() < now_mu(): + pass class AddressCollision(EnvExperiment): @@ -288,6 +290,8 @@ class AddressCollision(EnvExperiment): self.core.reset() self.loop_in.input() self.loop_in.pulse(10*us) + while self.core.get_rtio_counter_mu() < now_mu(): + pass class TimeKeepsRunning(EnvExperiment): From 65baca8c57a6933eb35f41aa1d6d5ef9c98d6fc9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 17 Sep 2017 16:11:36 +0800 Subject: [PATCH 0039/2457] rtio: clean up error-prone rtlink.get_or_zero() --- artiq/gateware/rtio/core.py | 6 ++++-- artiq/gateware/rtio/rtlink.py | 13 ++++++------- artiq/gateware/rtio/sed/core.py | 2 +- artiq/gateware/rtio/sed/layouts.py | 10 +++++----- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 8492e31f4..ea390bd2c 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -190,8 +190,10 @@ class Core(Module, AutoCSR): self.specials += AsyncResetSynchronizer(self.cd_rio_phy, cmd_reset_phy) # TSC - fine_ts_width = max(rtlink.get_fine_ts_width(channel.interface) - for channel in channels) + fine_ts_width = max(max(rtlink.get_fine_ts_width(channel.interface.o) + for channel in channels), + max(rtlink.get_fine_ts_width(channel.interface.i) + for channel in channels)) coarse_ts = Signal(64-fine_ts_width) self.sync.rtio += coarse_ts.eq(coarse_ts + 1) coarse_ts_cdc = GrayCodeTransfer(len(coarse_ts)) diff --git a/artiq/gateware/rtio/rtlink.py b/artiq/gateware/rtio/rtlink.py index a4fb3ebf9..06cc0ebf2 100644 --- a/artiq/gateware/rtio/rtlink.py +++ b/artiq/gateware/rtio/rtlink.py @@ -69,14 +69,13 @@ class Interface: def _get_or_zero(interface, attr): - if isinstance(interface, Interface): - return max(_get_or_zero(interface.i, attr), - _get_or_zero(interface.o, attr)) + if interface is None: + return 0 + assert isinstance(interface, (OInterface, IInterface)) + if hasattr(interface, attr): + return len(getattr(interface, attr)) else: - if hasattr(interface, attr): - return len(getattr(interface, attr)) - else: - return 0 + return 0 def get_data_width(interface): diff --git a/artiq/gateware/rtio/sed/core.py b/artiq/gateware/rtio/sed/core.py index 30f16a863..55a068c4b 100644 --- a/artiq/gateware/rtio/sed/core.py +++ b/artiq/gateware/rtio/sed/core.py @@ -27,7 +27,7 @@ class SED(Module): else: raise ValueError - fine_ts_width = max(rtlink.get_fine_ts_width(c.interface) + fine_ts_width = max(rtlink.get_fine_ts_width(c.interface.o) for c in channels) seqn_width = layouts.seqn_width(lane_count, fifo_depth) diff --git a/artiq/gateware/rtio/sed/layouts.py b/artiq/gateware/rtio/sed/layouts.py index b0a983911..b49e1139b 100644 --- a/artiq/gateware/rtio/sed/layouts.py +++ b/artiq/gateware/rtio/sed/layouts.py @@ -4,9 +4,9 @@ from artiq.gateware.rtio import rtlink def fifo_payload(channels): - address_width = max(rtlink.get_address_width(channel.interface) + address_width = max(rtlink.get_address_width(channel.interface.o) for channel in channels) - data_width = max(rtlink.get_data_width(channel.interface) + data_width = max(rtlink.get_data_width(channel.interface.o) for channel in channels) layout = [ @@ -46,11 +46,11 @@ def fifo_egress(seqn_width, layout_payload): def output_network_payload(channels): - fine_ts_width = max(rtlink.get_fine_ts_width(channel.interface) + fine_ts_width = max(rtlink.get_fine_ts_width(channel.interface.o) for channel in channels) - address_width = max(rtlink.get_address_width(channel.interface) + address_width = max(rtlink.get_address_width(channel.interface.o) for channel in channels) - data_width = max(rtlink.get_data_width(channel.interface) + data_width = max(rtlink.get_data_width(channel.interface.o) for channel in channels) layout = [("channel", bits_for(len(channels)-1))] From 81d6317053dcc97a8f219b8b9f8da3113b9468d9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 18 Sep 2017 10:26:06 +0800 Subject: [PATCH 0040/2457] rtio/sed: take global fine TS width --- artiq/gateware/rtio/sed/core.py | 12 +++++------- artiq/gateware/rtio/sed/gates.py | 10 +++++----- artiq/gateware/rtio/sed/lane_distributor.py | 12 ++++++------ artiq/gateware/rtio/sed/layouts.py | 13 ++++++++----- artiq/gateware/rtio/sed/output_driver.py | 4 ++-- artiq/gateware/test/rtio/test_sed_output_driver.py | 2 +- artiq/gateware/test/rtio/test_sed_top.py | 2 +- 7 files changed, 28 insertions(+), 27 deletions(-) diff --git a/artiq/gateware/rtio/sed/core.py b/artiq/gateware/rtio/sed/core.py index 55a068c4b..3cea2cf85 100644 --- a/artiq/gateware/rtio/sed/core.py +++ b/artiq/gateware/rtio/sed/core.py @@ -1,6 +1,5 @@ from migen import * -from artiq.gateware.rtio import rtlink from artiq.gateware.rtio.sed import layouts from artiq.gateware.rtio.sed.lane_distributor import * from artiq.gateware.rtio.sed.fifos import * @@ -12,7 +11,8 @@ __all__ = ["SED"] class SED(Module): - def __init__(self, channels, mode, lane_count=8, fifo_depth=128, enable_spread=True, + def __init__(self, channels, glbl_fine_ts_width, mode, + lane_count=8, fifo_depth=128, enable_spread=True, quash_channels=[], interface=None): if mode == "sync": lane_dist_cdr = lambda x: x @@ -27,13 +27,11 @@ class SED(Module): else: raise ValueError - fine_ts_width = max(rtlink.get_fine_ts_width(c.interface.o) - for c in channels) seqn_width = layouts.seqn_width(lane_count, fifo_depth) self.submodules.lane_dist = lane_dist_cdr( LaneDistributor(lane_count, seqn_width, - layouts.fifo_payload(channels), fine_ts_width, + layouts.fifo_payload(channels), glbl_fine_ts_width, enable_spread=enable_spread, quash_channels=quash_channels, interface=interface)) @@ -43,9 +41,9 @@ class SED(Module): self.submodules.gates = gates_cdr( Gates(lane_count, seqn_width, layouts.fifo_payload(channels), - layouts.output_network_payload(channels))) + layouts.output_network_payload(channels, glbl_fine_ts_width))) self.submodules.output_driver = output_driver_cdr( - OutputDriver(channels, lane_count, seqn_width)) + OutputDriver(channels, glbl_fine_ts_width, lane_count, seqn_width)) for o, i in zip(self.lane_dist.output, self.fifos.input): self.comb += o.connect(i) diff --git a/artiq/gateware/rtio/sed/gates.py b/artiq/gateware/rtio/sed/gates.py index 8d0f604e4..9b1c27d23 100644 --- a/artiq/gateware/rtio/sed/gates.py +++ b/artiq/gateware/rtio/sed/gates.py @@ -14,18 +14,18 @@ class Gates(Module): for _ in range(lane_count)] if hasattr(self.output[0].payload, "fine_ts"): - fine_ts_width = len(self.output[0].payload.fine_ts) + glbl_fine_ts_width = len(self.output[0].payload.fine_ts) else: - fine_ts_width = 0 + glbl_fine_ts_width = 0 - self.coarse_timestamp = Signal(64-fine_ts_width) + self.coarse_timestamp = Signal(64-glbl_fine_ts_width) # # # for input, output in zip(self.input, self.output): for field, _ in output.payload.layout: if field == "fine_ts": - self.sync += output.payload.fine_ts.eq(input.payload.timestamp[:fine_ts_width]) + self.sync += output.payload.fine_ts.eq(input.payload.timestamp[:glbl_fine_ts_width]) else: self.sync += getattr(output.payload, field).eq(getattr(input.payload, field)) self.sync += output.seqn.eq(input.seqn) @@ -34,5 +34,5 @@ class Gates(Module): output.nondata_replace_occured.eq(0) ] - self.comb += input.re.eq(input.payload.timestamp[fine_ts_width:] == self.coarse_timestamp) + self.comb += input.re.eq(input.payload.timestamp[glbl_fine_ts_width:] == self.coarse_timestamp) self.sync += output.valid.eq(input.re & input.readable) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index 986d7a470..436e59695 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -13,7 +13,7 @@ __all__ = ["LaneDistributor"] # 3. check status class LaneDistributor(Module): - def __init__(self, lane_count, seqn_width, layout_payload, fine_ts_width, + def __init__(self, lane_count, seqn_width, layout_payload, glbl_fine_ts_width, enable_spread=True, quash_channels=[], interface=None): if lane_count & (lane_count - 1): raise NotImplementedError("lane count must be a power of 2") @@ -21,7 +21,7 @@ class LaneDistributor(Module): if interface is None: interface = cri.Interface() self.cri = interface - self.minimum_coarse_timestamp = Signal(64-fine_ts_width) + self.minimum_coarse_timestamp = Signal(64-glbl_fine_ts_width) self.output = [Record(layouts.fifo_ingress(seqn_width, layout_payload)) for _ in range(lane_count)] @@ -35,8 +35,8 @@ class LaneDistributor(Module): # internal state current_lane = Signal(max=lane_count) - last_coarse_timestamp = Signal(64-fine_ts_width) - last_lane_coarse_timestamps = Array(Signal(64-fine_ts_width) + last_coarse_timestamp = Signal(64-glbl_fine_ts_width) + last_lane_coarse_timestamps = Array(Signal(64-glbl_fine_ts_width) for _ in range(lane_count)) seqn = Signal(seqn_width) @@ -53,8 +53,8 @@ class LaneDistributor(Module): self.comb += lio.payload.data.eq(self.cri.o_data) # when timestamp and channel arrive in cycle #1, prepare computations - coarse_timestamp = Signal(64-fine_ts_width) - self.comb += coarse_timestamp.eq(self.cri.timestamp[fine_ts_width:]) + coarse_timestamp = Signal(64-glbl_fine_ts_width) + self.comb += coarse_timestamp.eq(self.cri.timestamp[glbl_fine_ts_width:]) timestamp_above_min = Signal() timestamp_above_laneA_min = Signal() timestamp_above_laneB_min = Signal() diff --git a/artiq/gateware/rtio/sed/layouts.py b/artiq/gateware/rtio/sed/layouts.py index b49e1139b..1fbb8f6ec 100644 --- a/artiq/gateware/rtio/sed/layouts.py +++ b/artiq/gateware/rtio/sed/layouts.py @@ -45,17 +45,20 @@ def fifo_egress(seqn_width, layout_payload): ] -def output_network_payload(channels): - fine_ts_width = max(rtlink.get_fine_ts_width(channel.interface.o) - for channel in channels) +# We use glbl_fine_ts_width in the output network so that collisions due +# to insufficiently increasing timestamps are always reliably detected. +# We can still have undetected collisions on the address by making it wrap +# around, but those are more rare and easier to debug, and addresses are +# not normally exposed directly to the ARTIQ user. +def output_network_payload(channels, glbl_fine_ts_width): address_width = max(rtlink.get_address_width(channel.interface.o) for channel in channels) data_width = max(rtlink.get_data_width(channel.interface.o) for channel in channels) layout = [("channel", bits_for(len(channels)-1))] - if fine_ts_width: - layout.append(("fine_ts", fine_ts_width)) + if glbl_fine_ts_width: + layout.append(("fine_ts", glbl_fine_ts_width)) if address_width: layout.append(("address", address_width)) if data_width: diff --git a/artiq/gateware/rtio/sed/output_driver.py b/artiq/gateware/rtio/sed/output_driver.py index 7f26ec58a..3150e98b6 100644 --- a/artiq/gateware/rtio/sed/output_driver.py +++ b/artiq/gateware/rtio/sed/output_driver.py @@ -11,14 +11,14 @@ __all__ = ["OutputDriver"] class OutputDriver(Module): - def __init__(self, channels, lane_count, seqn_width): + def __init__(self, channels, glbl_fine_ts_width, lane_count, seqn_width): self.collision = Signal() self.collision_channel = Signal(max=len(channels)) self.busy = Signal() self.busy_channel = Signal(max=len(channels)) # output network - layout_on_payload = layouts.output_network_payload(channels) + layout_on_payload = layouts.output_network_payload(channels, glbl_fine_ts_width) output_network = OutputNetwork(lane_count, seqn_width, layout_on_payload) self.submodules += output_network self.input = output_network.input diff --git a/artiq/gateware/test/rtio/test_sed_output_driver.py b/artiq/gateware/test/rtio/test_sed_output_driver.py index 44e478e42..4da3bd463 100644 --- a/artiq/gateware/test/rtio/test_sed_output_driver.py +++ b/artiq/gateware/test/rtio/test_sed_output_driver.py @@ -37,7 +37,7 @@ class DUT(Module): ] self.submodules.output_driver = output_driver.OutputDriver( - rtio_channels, LANE_COUNT, 4*LANE_COUNT) + rtio_channels, 0, LANE_COUNT, 4*LANE_COUNT) def simulate(input_events): diff --git a/artiq/gateware/test/rtio/test_sed_top.py b/artiq/gateware/test/rtio/test_sed_top.py index 25a65ae2a..2ed1f91a2 100644 --- a/artiq/gateware/test/rtio/test_sed_top.py +++ b/artiq/gateware/test/rtio/test_sed_top.py @@ -22,7 +22,7 @@ class DUT(Module): rtio.Channel.from_phy(self.phy1) ] - self.submodules.sed = SED(rtio_channels, "sync") + self.submodules.sed = SED(rtio_channels, 0, "sync") self.sync += [ self.sed.coarse_timestamp.eq(self.sed.coarse_timestamp + 1), self.sed.minimum_coarse_timestamp.eq(self.sed.coarse_timestamp + 16) From 6dc9cad2c960f7a011a69b43aeba127678864994 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Sep 2017 12:05:12 +0800 Subject: [PATCH 0041/2457] rtio: add explanation about cri.counter --- artiq/gateware/rtio/cri.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index f282ae307..7a4359ba7 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -35,6 +35,9 @@ layout = [ # <0> and <1> are mutually exclusive. <1> has higher priority. ("i_status", 3, DIR_S_TO_M), + # value of the timestamp counter transferred into the CRI clock domain. + # monotonic, may lag behind the counter in the IO clock domain, but + # not be ahead of it. ("counter", 64, DIR_S_TO_M) ] From d37577a8a115fcda593f185d8f03222bd39ae6fd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Sep 2017 15:30:30 +0800 Subject: [PATCH 0042/2457] rtio: add input collector module --- artiq/gateware/rtio/input_collector.py | 139 +++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 artiq/gateware/rtio/input_collector.py diff --git a/artiq/gateware/rtio/input_collector.py b/artiq/gateware/rtio/input_collector.py new file mode 100644 index 000000000..b0962adb5 --- /dev/null +++ b/artiq/gateware/rtio/input_collector.py @@ -0,0 +1,139 @@ +from migen import * +from migen.genlib.record import Record +from migen.genlib.fifo import * + +from artiq.gateware.rtio import cri +from artiq.gateware.rtio import rtlink + + +__all__ = ["InputCollector"] + + +def get_channel_layout(coarse_ts_width, interface): + data_width = rtlink.get_data_width(interface) + fine_ts_width = rtlink.get_fine_ts_width(interface) + + layout = [] + if data_width: + layout.append(("data", data_width)) + if interface.timestamped: + layout.append(("timestamp", coarse_ts_width + fine_ts_width)) + + return layout + + +class InputCollector(Module): + def __init__(self, channels, glbl_fine_ts_width, mode, quash_channels=[], interface=None): + if interface is None: + interface = cri.Interface() + self.cri = interface + self.coarse_timestamp = Signal(64 - glbl_fine_ts_width) + + # # # + + if mode == "sync": + fifo_factory = SyncFIFOBuffered + sync_io = self.sync + sync_cri = self.sync + elif mode == "async": + fifo_factory = lambda *args: ClockDomainsRenamer({"write": "rio", "read": "rsys"})(AsyncFIFO(*args)) + sync_io = self.sync.rio + sync_cri = self.sync.rsys + else: + raise ValueError + + i_statuses, i_datas, i_timestamps = [], [], [] + i_ack = Signal() + sel = self.cri.chan_sel[:16] + for n, channel in enumerate(channels): + iif = channel.interface.i + if iif is None or n in quash_channels: + i_datas.append(0) + i_timestamps.append(0) + i_statuses.append(0) + continue + + # FIFO + layout = get_channel_layout(len(self.coarse_timestamp), iif) + fifo = fifo_factory(layout_len(layout), channel.ififo_depth) + self.submodules += fifo + fifo_in = Record(layout) + fifo_out = Record(layout) + self.comb += [ + fifo.din.eq(fifo_in.raw_bits()), + fifo_out.raw_bits().eq(fifo.dout) + ] + + # FIFO write + if iif.delay: + counter_rtio = Signal.like(self.coarse_timestamp, reset_less=True) + sync_io += counter_rtio.eq(self.coarse_timestamp - (iif.delay + 1)) + else: + counter_rtio = self.coarse_timestamp + if hasattr(fifo_in, "data"): + self.comb += fifo_in.data.eq(iif.data) + if hasattr(fifo_in, "timestamp"): + if hasattr(iif, "fine_ts"): + full_ts = Cat(iif.fine_ts, counter_rtio) + else: + full_ts = counter_rtio + self.comb += fifo_in.timestamp.eq(full_ts) + self.comb += fifo.we.eq(iif.stb) + + overflow_io = Signal() + self.comb += overflow_io.eq(fifo.we & ~fifo.writable) + if mode == "sync": + overflow_trigger = overflow_io + elif mode == "async": + overflow_transfer = BlindTransfer() + self.submodules += overflow_transfer + self.comb += overflow_transfer.i.eq(overflow_io) + overflow_trigger = overflow_transfer.o + else: + raise ValueError + + # FIFO read, CRI connection + if hasattr(fifo_out, "data"): + i_datas.append(fifo_out.data) + else: + i_datas.append(0) + if hasattr(fifo_out, "timestamp"): + ts_shift = 64 - len(fifo_out.timestamp) + i_timestamps.append(fifo_out.timestamp << ts_shift) + else: + i_timestamps.append(0) + + selected = Signal() + self.comb += selected.eq(sel == n) + + overflow = Signal() + sync_cri += [ + If(selected & i_ack, + overflow.eq(0)), + If(overflow_trigger, + overflow.eq(1)) + ] + self.comb += fifo.re.eq(selected & i_ack & ~overflow) + i_statuses.append(Cat(fifo.readable & ~overflow, overflow)) + + i_status_raw = Signal(2) + self.comb += i_status_raw.eq(Array(i_statuses)[sel]) + input_timeout = Signal.like(self.cri.timestamp) + input_pending = Signal() + sync_cri += [ + i_ack.eq(0), + If(i_ack, + self.cri.i_status.eq(Cat(~i_status_raw[0], i_status_raw[1], 0)), + self.cri.i_data.eq(Array(i_datas)[sel]), + self.cri.i_timestamp.eq(Array(i_timestamps)[sel]), + ), + If((self.cri.counter >= input_timeout) | (i_status_raw != 0), + If(input_pending, i_ack.eq(1)), + input_pending.eq(0) + ), + If(self.cri.cmd == cri.commands["read"], + input_timeout.eq(self.cri.timestamp), + input_pending.eq(1), + self.cri.i_status.eq(0b100) + ) + ] From 06a0707c00769f1837d3396198c7c723b1d83498 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Sep 2017 15:30:44 +0800 Subject: [PATCH 0043/2457] rtio: add simulation unit test for input collector --- .../test/rtio/test_input_collector.py | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 artiq/gateware/test/rtio/test_input_collector.py diff --git a/artiq/gateware/test/rtio/test_input_collector.py b/artiq/gateware/test/rtio/test_input_collector.py new file mode 100644 index 000000000..c67f2aa53 --- /dev/null +++ b/artiq/gateware/test/rtio/test_input_collector.py @@ -0,0 +1,90 @@ +import unittest + +from migen import * + +from artiq.gateware import rtio +from artiq.gateware.rtio import rtlink +from artiq.gateware.rtio import cri +from artiq.gateware.rtio.input_collector import * + + +class OscInput(Module): + def __init__(self): + self.rtlink = rtlink.Interface( + rtlink.OInterface(1), + rtlink.IInterface(1)) + self.overrides = [] + self.probes = [] + + # # # + + counter = Signal(2) + trigger = Signal() + self.sync += [ + Cat(counter, trigger).eq(counter + 1), + self.rtlink.i.stb.eq(0), + If(trigger, + self.rtlink.i.stb.eq(1), + self.rtlink.i.data.eq(~self.rtlink.i.data) + ) + ] + + +class DUT(Module): + def __init__(self): + self.submodules.phy0 = OscInput() + self.submodules.phy1 = OscInput() + rtio_channels = [ + rtio.Channel.from_phy(self.phy0, ififo_depth=4), + rtio.Channel.from_phy(self.phy1, ififo_depth=4) + ] + self.submodules.input_collector = InputCollector(rtio_channels, 0, "sync") + self.sync += self.input_collector.coarse_timestamp.eq(self.input_collector.coarse_timestamp + 1) + self.comb += self.input_collector.cri.counter.eq(self.input_collector.coarse_timestamp) + + @property + def cri(self): + return self.input_collector.cri + + +def simulate(wait_cycles, ts_timeouts): + result = [] + dut = DUT() + def gen(): + for _ in range(wait_cycles): + yield + + for ts_timeout in ts_timeouts: + yield dut.cri.timestamp.eq(ts_timeout) + yield dut.cri.cmd.eq(cri.commands["read"]) + yield + yield dut.cri.cmd.eq(cri.commands["nop"]) + yield + while (yield dut.cri.i_status) & 4: + yield + status = yield dut.cri.i_status + if status & 2: + result.append("overflow") + elif status & 1: + result.append("timeout") + else: + i_timestamp = yield dut.cri.i_timestamp + i_data = yield dut.cri.i_data + result.append((i_timestamp, i_data)) + + run_simulation(dut, gen()) + return result + + +class TestInput(unittest.TestCase): + def test_get_data(self): + result = simulate(0, [256]*8) + self.assertEqual(result, [(n*4+1, n % 2) for n in range(1, 9)]) + + def test_timeout(self): + result = simulate(0, [3, 16]) + self.assertEqual(result, ["timeout", (5, 1)]) + + def test_overflow(self): + result = simulate(32, [256]) + self.assertEqual(result, ["overflow"]) From 4dc80e3d05abf53c4d6a87abc9b016747ec7d6f5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Sep 2017 15:53:23 +0800 Subject: [PATCH 0044/2457] rtio: add missing import --- artiq/gateware/rtio/input_collector.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/rtio/input_collector.py b/artiq/gateware/rtio/input_collector.py index b0962adb5..d0cba4f50 100644 --- a/artiq/gateware/rtio/input_collector.py +++ b/artiq/gateware/rtio/input_collector.py @@ -4,6 +4,7 @@ from migen.genlib.fifo import * from artiq.gateware.rtio import cri from artiq.gateware.rtio import rtlink +from artiq.gateware.rtio.cdc import * __all__ = ["InputCollector"] From ff8e17ab890b29feb42815faf885052590a063c7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Sep 2017 15:53:35 +0800 Subject: [PATCH 0045/2457] rtio: use input collector module --- artiq/gateware/rtio/core.py | 166 ++++-------------------------------- 1 file changed, 17 insertions(+), 149 deletions(-) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index ea390bd2c..5ad5f6591 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -2,8 +2,6 @@ from functools import reduce from operator import and_ from migen import * -from migen.genlib.record import Record -from migen.genlib.fifo import AsyncFIFO from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.cdc import PulseSynchronizer from misoc.interconnect.csr import * @@ -13,141 +11,7 @@ from artiq.gateware.rtio import rtlink from artiq.gateware.rtio.channel import * from artiq.gateware.rtio.cdc import * from artiq.gateware.rtio.sed.core import * - - -class _InputManager(Module): - def __init__(self, interface, coarse_ts, fifo_depth): - data_width = rtlink.get_data_width(interface) - fine_ts_width = rtlink.get_fine_ts_width(interface) - - ev_layout = [] - if data_width: - ev_layout.append(("data", data_width)) - if interface.timestamped: - ev_layout.append(("timestamp", len(coarse_ts) + fine_ts_width)) - self.ev = Record(ev_layout) - - self.readable = Signal() - self.re = Signal() - - self.overflow = Signal() # pulsed - - # # # - - fifo = ClockDomainsRenamer({"read": "rsys", "write": "rio"})( - AsyncFIFO(layout_len(ev_layout), fifo_depth)) - self.submodules += fifo - fifo_in = Record(ev_layout) - fifo_out = Record(ev_layout) - self.comb += [ - fifo.din.eq(fifo_in.raw_bits()), - fifo_out.raw_bits().eq(fifo.dout) - ] - - # latency compensation - if interface.delay: - counter_rtio = Signal.like(coarse_ts, reset_less=True) - self.sync.rtio += counter_rtio.eq(coarse_ts - - (interface.delay + 1)) - else: - counter_rtio = coarse_ts - - # FIFO write - if data_width: - self.comb += fifo_in.data.eq(interface.data) - if interface.timestamped: - if fine_ts_width: - full_ts = Cat(interface.fine_ts, counter_rtio) - else: - full_ts = counter_rtio - self.comb += fifo_in.timestamp.eq(full_ts) - self.comb += fifo.we.eq(interface.stb) - - # FIFO read - self.comb += [ - self.ev.eq(fifo_out), - self.readable.eq(fifo.readable), - fifo.re.eq(self.re) - ] - - overflow_transfer = BlindTransfer() - self.submodules += overflow_transfer - self.comb += [ - overflow_transfer.i.eq(fifo.we & ~fifo.writable), - self.overflow.eq(overflow_transfer.o), - ] - - -class _Inputs(Module): - def __init__(self, interface, coarse_ts, channels): - self.cri = interface - - # Inputs - i_statuses = [] - i_datas, i_timestamps = [], [] - i_ack = Signal() - sel = self.cri.chan_sel[:16] - for n, channel in enumerate(channels): - if isinstance(channel, LogChannel): - i_datas.append(0) - i_timestamps.append(0) - i_statuses.append(0) - continue - - if channel.interface.i is not None: - selected = Signal() - self.comb += selected.eq(sel == n) - - i_manager = _InputManager(channel.interface.i, coarse_ts, - channel.ififo_depth) - self.submodules += i_manager - - if hasattr(i_manager.ev, "data"): - i_datas.append(i_manager.ev.data) - else: - i_datas.append(0) - if channel.interface.i.timestamped: - ts_shift = (len(self.cri.i_timestamp) - len(i_manager.ev.timestamp)) - i_timestamps.append(i_manager.ev.timestamp << ts_shift) - else: - i_timestamps.append(0) - - overflow = Signal() - self.sync.rsys += [ - If(selected & i_ack, - overflow.eq(0)), - If(i_manager.overflow, - overflow.eq(1)) - ] - self.comb += i_manager.re.eq(selected & i_ack & ~overflow) - i_statuses.append(Cat(i_manager.readable & ~overflow, overflow)) - - else: - i_datas.append(0) - i_timestamps.append(0) - i_statuses.append(0) - - i_status_raw = Signal(2) - self.comb += i_status_raw.eq(Array(i_statuses)[sel]) - input_timeout = Signal.like(self.cri.timestamp) - input_pending = Signal() - self.sync.rsys += [ - i_ack.eq(0), - If(i_ack, - self.cri.i_status.eq(Cat(~i_status_raw[0], i_status_raw[1], 0)), - self.cri.i_data.eq(Array(i_datas)[sel]), - self.cri.i_timestamp.eq(Array(i_timestamps)[sel]), - ), - If((self.cri.counter >= input_timeout) | (i_status_raw != 0), - If(input_pending, i_ack.eq(1)), - input_pending.eq(0) - ), - If(self.cri.cmd == cri.commands["read"], - input_timeout.eq(self.cri.timestamp), - input_pending.eq(1), - self.cri.i_status.eq(0b100) - ) - ] +from artiq.gateware.rtio.input_collector import * class Core(Module, AutoCSR): @@ -190,17 +54,17 @@ class Core(Module, AutoCSR): self.specials += AsyncResetSynchronizer(self.cd_rio_phy, cmd_reset_phy) # TSC - fine_ts_width = max(max(rtlink.get_fine_ts_width(channel.interface.o) - for channel in channels), - max(rtlink.get_fine_ts_width(channel.interface.i) - for channel in channels)) - coarse_ts = Signal(64-fine_ts_width) + glbl_fine_ts_width = max(max(rtlink.get_fine_ts_width(channel.interface.o) + for channel in channels), + max(rtlink.get_fine_ts_width(channel.interface.i) + for channel in channels)) + coarse_ts = Signal(64-glbl_fine_ts_width) self.sync.rtio += coarse_ts.eq(coarse_ts + 1) coarse_ts_cdc = GrayCodeTransfer(len(coarse_ts)) self.submodules += coarse_ts_cdc self.comb += [ coarse_ts_cdc.i.eq(coarse_ts), - self.cri.counter.eq(coarse_ts_cdc.o << fine_ts_width) + self.cri.counter.eq(coarse_ts_cdc.o << glbl_fine_ts_width) ] # Asychronous output errors @@ -219,13 +83,12 @@ class Core(Module, AutoCSR): ] self.comb += self.async_error.w.eq(Cat(o_collision, o_busy)) - # Inputs - inputs = _Inputs(self.cri, coarse_ts, channels) - self.submodules += inputs - # Outputs - outputs = SED(channels, "async", - quash_channels=[n for n, c in enumerate(channels) if isinstance(c, LogChannel)], + # Outputs/Inputs + quash_channels = [n for n, c in enumerate(channels) if isinstance(c, LogChannel)] + + outputs = SED(channels, glbl_fine_ts_width, "async", + quash_channels=quash_channels, interface=self.cri) self.submodules += outputs self.comb += outputs.coarse_timestamp.eq(coarse_ts) @@ -234,3 +97,8 @@ class Core(Module, AutoCSR): o_collision_sync.i.eq(outputs.collision), o_busy_sync.i.eq(outputs.busy) ] + + inputs = InputCollector(channels, glbl_fine_ts_width, "async", + quash_channels=quash_channels, + interface=self.cri) + self.submodules += inputs From ddcd6065e880fc3a99e49bbcf7d90fc582f28594 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Sep 2017 17:46:38 +0800 Subject: [PATCH 0046/2457] rtio: drive InputCollector.coarse_timestamp --- artiq/gateware/rtio/core.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 5ad5f6591..6b19c52dd 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -102,3 +102,4 @@ class Core(Module, AutoCSR): quash_channels=quash_channels, interface=self.cri) self.submodules += inputs + self.comb += inputs.coarse_timestamp.eq(coarse_ts) From 1ff10785dc2a2deed4a9638b3f78bee8331251e2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Sep 2017 20:46:16 +0800 Subject: [PATCH 0047/2457] targets/kc705_drtio_satellite: add missing shebang line --- artiq/gateware/targets/kc705_drtio_satellite.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/gateware/targets/kc705_drtio_satellite.py b/artiq/gateware/targets/kc705_drtio_satellite.py index b4579d50f..e81756491 100755 --- a/artiq/gateware/targets/kc705_drtio_satellite.py +++ b/artiq/gateware/targets/kc705_drtio_satellite.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + import argparse import os From 171a2d19a04ace0075e9f48c6467a60bef15bad0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Sep 2017 20:47:37 +0800 Subject: [PATCH 0048/2457] drtio: remove spurious signals --- artiq/gateware/drtio/rt_packet_satellite.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 13bc921bb..249f8ca27 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -29,8 +29,6 @@ class RTPacketSatellite(Module): self.write_channel = Signal(16) self.write_address = Signal(16) self.write_data = Signal(512) - self.write_overflow = Signal() - self.write_underflow = Signal() self.read_channel = Signal(16) self.read_readable = Signal() From 63e39dec949652478fe9639bdb7fb3529136f408 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Sep 2017 11:26:12 +0800 Subject: [PATCH 0049/2457] style --- artiq/gateware/test/rtio/test_sed_top.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/test/rtio/test_sed_top.py b/artiq/gateware/test/rtio/test_sed_top.py index 2ed1f91a2..eeb4c46a8 100644 --- a/artiq/gateware/test/rtio/test_sed_top.py +++ b/artiq/gateware/test/rtio/test_sed_top.py @@ -28,6 +28,7 @@ class DUT(Module): self.sed.minimum_coarse_timestamp.eq(self.sed.coarse_timestamp + 16) ] + def simulate(input_events): dut = DUT() From d8aa75b7420ada8d9f03798f9171d4c5cfc733aa Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Sep 2017 11:27:57 +0800 Subject: [PATCH 0050/2457] rtio/sed: add minimum buffer space reporting --- artiq/gateware/rtio/cri.py | 3 ++ artiq/gateware/rtio/sed/core.py | 7 +++-- artiq/gateware/rtio/sed/fifos.py | 49 +++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 7a4359ba7..5dad6b886 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -27,6 +27,9 @@ layout = [ # o_status bits: # <0:wait> <1:underflow> <2:sequence_error> ("o_status", 3, DIR_S_TO_M), + # targets may optionally report a pessimistic estimate of the number + # of outputs events that can be written without waiting. + ("o_buffer_space", 16, DIR_S_TO_M), ("i_data", 32, DIR_S_TO_M), ("i_timestamp", 64, DIR_S_TO_M), diff --git a/artiq/gateware/rtio/sed/core.py b/artiq/gateware/rtio/sed/core.py index 3cea2cf85..d31161efc 100644 --- a/artiq/gateware/rtio/sed/core.py +++ b/artiq/gateware/rtio/sed/core.py @@ -13,7 +13,7 @@ __all__ = ["SED"] class SED(Module): def __init__(self, channels, glbl_fine_ts_width, mode, lane_count=8, fifo_depth=128, enable_spread=True, - quash_channels=[], interface=None): + quash_channels=[], interface=None, report_min_space=False): if mode == "sync": lane_dist_cdr = lambda x: x fifos_cdr = lambda x: x @@ -37,7 +37,7 @@ class SED(Module): interface=interface)) self.submodules.fifos = fifos_cdr( FIFOs(lane_count, fifo_depth, - layouts.fifo_payload(channels), mode)) + layouts.fifo_payload(channels), mode, report_min_space)) self.submodules.gates = gates_cdr( Gates(lane_count, seqn_width, layouts.fifo_payload(channels), @@ -52,6 +52,9 @@ class SED(Module): for o, i in zip(self.gates.output, self.output_driver.input): self.comb += i.eq(o) + if report_min_space: + self.comb += self.cri.o_buffer_space.eq(self.fifos.min_space) + @property def cri(self): return self.lane_dist.cri diff --git a/artiq/gateware/rtio/sed/fifos.py b/artiq/gateware/rtio/sed/fifos.py index da0f4fcfe..43b0079e8 100644 --- a/artiq/gateware/rtio/sed/fifos.py +++ b/artiq/gateware/rtio/sed/fifos.py @@ -1,3 +1,6 @@ +from operator import or_ +from functools import reduce + from migen import * from migen.genlib.fifo import * @@ -8,13 +11,18 @@ __all__ = ["FIFOs"] class FIFOs(Module): - def __init__(self, lane_count, fifo_depth, layout_payload, mode): + def __init__(self, lane_count, fifo_depth, layout_payload, mode, report_min_space=False): seqn_width = layouts.seqn_width(lane_count, fifo_depth) self.input = [Record(layouts.fifo_ingress(seqn_width, layout_payload)) for _ in range(lane_count)] self.output = [Record(layouts.fifo_egress(seqn_width, layout_payload)) for _ in range(lane_count)] + if report_min_space: + self.min_space = Signal(max=fifo_depth+1) + + # # # + if mode == "sync": fifo_cls = SyncFIFOBuffered elif mode == "async": @@ -22,9 +30,11 @@ class FIFOs(Module): else: raise ValueError + fifos = [] for input, output in zip(self.input, self.output): fifo = fifo_cls(layout_len(layout_payload), fifo_depth) self.submodules += fifo + fifos.append(fifo) self.comb += [ fifo.din.eq(input.payload.raw_bits()), @@ -35,3 +45,40 @@ class FIFOs(Module): output.readable.eq(fifo.readable), fifo.re.eq(output.re) ] + + if report_min_space: + if mode != "sync": + raise NotImplementedError + + def compute_max(elts): + l = len(elts) + if l == 1: + return elts[0], 0 + else: + maximum1, latency1 = compute_max(elts[:l//2]) + maximum2, latency2 = compute_max(elts[l//2:]) + maximum = Signal(max(len(maximum1), len(maximum2))) + self.sync += [ + If(maximum1 > maximum2, + maximum.eq(maximum1) + ).Else( + maximum.eq(maximum2) + ) + ] + latency = max(latency1, latency2) + 1 + return maximum, latency + + max_level, latency = compute_max([fifo.level for fifo in fifos]) + max_level_valid = Signal() + max_level_valid_counter = Signal(max=latency) + self.sync += [ + If(reduce(or_, [fifo.we for fifo in fifos]), + max_level_valid.eq(0), + max_level_valid_counter.eq(latency - 1) + ).Elif(max_level_valid_counter == 0, + max_level_valid.eq(1) + ).Else( + max_level_valid_counter.eq(max_level_valid_counter - 1) + ) + ] + self.comb += If(max_level_valid, self.min_space.eq(fifo_depth - max_level)) From 07d3f87c5168e0b6441b102f5793f5d703fce17d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Sep 2017 14:36:13 +0800 Subject: [PATCH 0051/2457] =?UTF-8?q?rtio/sed:=20min=5Fspace=20=E2=86=92?= =?UTF-8?q?=20buffer=5Fspace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- artiq/gateware/rtio/sed/core.py | 8 ++++---- artiq/gateware/rtio/sed/fifos.py | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/rtio/sed/core.py b/artiq/gateware/rtio/sed/core.py index d31161efc..ffade986a 100644 --- a/artiq/gateware/rtio/sed/core.py +++ b/artiq/gateware/rtio/sed/core.py @@ -13,7 +13,7 @@ __all__ = ["SED"] class SED(Module): def __init__(self, channels, glbl_fine_ts_width, mode, lane_count=8, fifo_depth=128, enable_spread=True, - quash_channels=[], interface=None, report_min_space=False): + quash_channels=[], interface=None, report_buffer_space=False): if mode == "sync": lane_dist_cdr = lambda x: x fifos_cdr = lambda x: x @@ -37,7 +37,7 @@ class SED(Module): interface=interface)) self.submodules.fifos = fifos_cdr( FIFOs(lane_count, fifo_depth, - layouts.fifo_payload(channels), mode, report_min_space)) + layouts.fifo_payload(channels), mode, report_buffer_space)) self.submodules.gates = gates_cdr( Gates(lane_count, seqn_width, layouts.fifo_payload(channels), @@ -52,8 +52,8 @@ class SED(Module): for o, i in zip(self.gates.output, self.output_driver.input): self.comb += i.eq(o) - if report_min_space: - self.comb += self.cri.o_buffer_space.eq(self.fifos.min_space) + if report_buffer_space: + self.comb += self.cri.o_buffer_space.eq(self.fifos.buffer_space) @property def cri(self): diff --git a/artiq/gateware/rtio/sed/fifos.py b/artiq/gateware/rtio/sed/fifos.py index 43b0079e8..f056e1a69 100644 --- a/artiq/gateware/rtio/sed/fifos.py +++ b/artiq/gateware/rtio/sed/fifos.py @@ -11,15 +11,15 @@ __all__ = ["FIFOs"] class FIFOs(Module): - def __init__(self, lane_count, fifo_depth, layout_payload, mode, report_min_space=False): + def __init__(self, lane_count, fifo_depth, layout_payload, mode, report_buffer_space=False): seqn_width = layouts.seqn_width(lane_count, fifo_depth) self.input = [Record(layouts.fifo_ingress(seqn_width, layout_payload)) for _ in range(lane_count)] self.output = [Record(layouts.fifo_egress(seqn_width, layout_payload)) for _ in range(lane_count)] - if report_min_space: - self.min_space = Signal(max=fifo_depth+1) + if report_buffer_space: + self.buffer_space = Signal(max=fifo_depth+1) # # # @@ -46,7 +46,7 @@ class FIFOs(Module): fifo.re.eq(output.re) ] - if report_min_space: + if report_buffer_space: if mode != "sync": raise NotImplementedError @@ -81,4 +81,4 @@ class FIFOs(Module): max_level_valid_counter.eq(max_level_valid_counter - 1) ) ] - self.comb += If(max_level_valid, self.min_space.eq(fifo_depth - max_level)) + self.comb += If(max_level_valid, self.buffer_space.eq(fifo_depth - max_level)) From d74a7d272e6585f70df5f3cc13c9f9b442fd6a4d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Sep 2017 15:59:48 +0800 Subject: [PATCH 0052/2457] rtio: fix/cleanup parameters --- artiq/gateware/rtio/core.py | 1 + artiq/gateware/rtio/sed/core.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 6b19c52dd..4917a0371 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -89,6 +89,7 @@ class Core(Module, AutoCSR): outputs = SED(channels, glbl_fine_ts_width, "async", quash_channels=quash_channels, + lane_count=lane_count, fifo_depth=fifo_depth, interface=self.cri) self.submodules += outputs self.comb += outputs.coarse_timestamp.eq(coarse_ts) diff --git a/artiq/gateware/rtio/sed/core.py b/artiq/gateware/rtio/sed/core.py index ffade986a..df4e61b69 100644 --- a/artiq/gateware/rtio/sed/core.py +++ b/artiq/gateware/rtio/sed/core.py @@ -13,7 +13,7 @@ __all__ = ["SED"] class SED(Module): def __init__(self, channels, glbl_fine_ts_width, mode, lane_count=8, fifo_depth=128, enable_spread=True, - quash_channels=[], interface=None, report_buffer_space=False): + quash_channels=[], report_buffer_space=False, interface=None): if mode == "sync": lane_dist_cdr = lambda x: x fifos_cdr = lambda x: x From 5cf06937588e644099cede68405ffcc347d09241 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Sep 2017 22:31:56 +0800 Subject: [PATCH 0053/2457] rtio: use BlindTransfer to report collision and busy errors to sys domain --- artiq/gateware/rtio/core.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 4917a0371..7fea824ee 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -3,7 +3,6 @@ from operator import and_ from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer -from migen.genlib.cdc import PulseSynchronizer from misoc.interconnect.csr import * from artiq.gateware.rtio import cri @@ -68,8 +67,8 @@ class Core(Module, AutoCSR): ] # Asychronous output errors - o_collision_sync = PulseSynchronizer("rtio", "rsys") - o_busy_sync = PulseSynchronizer("rtio", "rsys") + o_collision_sync = BlindTransfer() + o_busy_sync = BlindTransfer() self.submodules += o_collision_sync, o_busy_sync o_collision = Signal() o_busy = Signal() From aa8fc81a87cfb56aa3d73ffd6c60236aab19659b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 23 Sep 2017 22:34:55 +0800 Subject: [PATCH 0054/2457] rtio: allow specifying glbl_fine_ts_width externally --- artiq/gateware/rtio/core.py | 9 +++++++-- artiq/gateware/targets/kc705_drtio_master.py | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 7fea824ee..8305db821 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -14,7 +14,8 @@ from artiq.gateware.rtio.input_collector import * class Core(Module, AutoCSR): - def __init__(self, channels, lane_count=8, fifo_depth=128): + def __init__(self, channels, lane_count=8, fifo_depth=128, + glbl_fine_ts_width=None): self.cri = cri.Interface() self.reset = CSR() self.reset_phy = CSR() @@ -53,10 +54,14 @@ class Core(Module, AutoCSR): self.specials += AsyncResetSynchronizer(self.cd_rio_phy, cmd_reset_phy) # TSC - glbl_fine_ts_width = max(max(rtlink.get_fine_ts_width(channel.interface.o) + chan_fine_ts_width = max(max(rtlink.get_fine_ts_width(channel.interface.o) for channel in channels), max(rtlink.get_fine_ts_width(channel.interface.i) for channel in channels)) + if glbl_fine_ts_width is None: + glbl_fine_ts_width = chan_fine_ts_width + assert glbl_fine_ts_width >= chan_fine_ts_width + coarse_ts = Signal(64-glbl_fine_ts_width) self.sync.rtio += coarse_ts.eq(coarse_ts + 1) coarse_ts_cdc = GrayCodeTransfer(len(coarse_ts)) diff --git a/artiq/gateware/targets/kc705_drtio_master.py b/artiq/gateware/targets/kc705_drtio_master.py index 889258965..9f49e3c6f 100755 --- a/artiq/gateware/targets/kc705_drtio_master.py +++ b/artiq/gateware/targets/kc705_drtio_master.py @@ -94,7 +94,7 @@ class Master(MiniSoC, AMPSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.submodules.rtio_core = rtio.Core(rtio_channels, 3) + self.submodules.rtio_core = rtio.Core(rtio_channels, glbl_fine_ts_width=3) self.csr_devices.append("rtio_core") self.submodules.rtio = rtio.KernelInitiator() From 20d79c930c4f5b1fecbaaf08fae94170a9d17555 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 24 Sep 2017 12:23:47 +0800 Subject: [PATCH 0055/2457] drtio: use SED and input collector --- artiq/firmware/ksupport/api.rs | 5 +- artiq/firmware/ksupport/rtio.rs | 24 +- artiq/firmware/libdrtioaux/lib.rs | 13 +- artiq/firmware/libproto/kernel_proto.rs | 8 +- artiq/firmware/runtime/kern_hwreq.rs | 19 +- artiq/firmware/runtime/rtio_mgt.rs | 70 +---- artiq/firmware/satman/lib.rs | 13 +- artiq/gateware/drtio/core.py | 33 ++- artiq/gateware/drtio/rt_controller_master.py | 118 +++------ artiq/gateware/drtio/rt_errors_satellite.py | 49 ++-- artiq/gateware/drtio/rt_ios_satellite.py | 246 ----------------- artiq/gateware/drtio/rt_packet_master.py | 34 +-- artiq/gateware/drtio/rt_packet_satellite.py | 123 ++++----- artiq/gateware/drtio/rt_serializer.py | 8 +- artiq/gateware/test/drtio/test_full_stack.py | 264 ++++++++++--------- 15 files changed, 342 insertions(+), 685 deletions(-) delete mode 100644 artiq/gateware/drtio/rt_ios_satellite.py diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 1cf3ce884..55e43edd1 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -112,11 +112,8 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(dma_retrieve = ::dma_retrieve), api!(dma_playback = ::dma_playback), - api!(drtio_get_channel_state = ::rtio::drtio_dbg::get_channel_state), - api!(drtio_reset_channel_state = ::rtio::drtio_dbg::reset_channel_state), - api!(drtio_get_fifo_space = ::rtio::drtio_dbg::get_fifo_space), api!(drtio_get_packet_counts = ::rtio::drtio_dbg::get_packet_counts), - api!(drtio_get_fifo_space_req_count = ::rtio::drtio_dbg::get_fifo_space_req_count), + api!(drtio_get_buffer_space_req_count = ::rtio::drtio_dbg::get_buffer_space_req_count), api!(i2c_start = ::nrt_bus::i2c::start), api!(i2c_restart = ::nrt_bus::i2c::restart), diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index ebc86b9f5..e03b2ea4c 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -161,24 +161,6 @@ pub mod drtio_dbg { use ::recv; use kernel_proto::*; - - #[repr(C)] - pub struct ChannelState(i32, i64); - - pub extern fn get_channel_state(channel: i32) -> ChannelState { - send(&DrtioChannelStateRequest { channel: channel as u32 }); - recv!(&DrtioChannelStateReply { fifo_space, last_timestamp } - => ChannelState(fifo_space as i32, last_timestamp as i64)) - } - - pub extern fn reset_channel_state(channel: i32) { - send(&DrtioResetChannelStateRequest { channel: channel as u32 }) - } - - pub extern fn get_fifo_space(channel: i32) { - send(&DrtioGetFifoSpaceRequest { channel: channel as u32 }) - } - #[repr(C)] pub struct PacketCounts(i32, i32); @@ -188,9 +170,9 @@ pub mod drtio_dbg { => PacketCounts(tx_cnt as i32, rx_cnt as i32)) } - pub extern fn get_fifo_space_req_count(linkno: i32) -> i32 { - send(&DrtioFifoSpaceReqCountRequest { linkno: linkno as u8 }); - recv!(&DrtioFifoSpaceReqCountReply { cnt } + pub extern fn get_buffer_space_req_count(linkno: i32) -> i32 { + send(&DrtioBufferSpaceReqCountRequest { linkno: linkno as u8 }); + recv!(&DrtioBufferSpaceReqCountReply { cnt } => cnt as i32) } } diff --git a/artiq/firmware/libdrtioaux/lib.rs b/artiq/firmware/libdrtioaux/lib.rs index ece63f37e..51ff8faa8 100644 --- a/artiq/firmware/libdrtioaux/lib.rs +++ b/artiq/firmware/libdrtioaux/lib.rs @@ -21,6 +21,7 @@ pub enum Packet { RtioErrorRequest, RtioNoErrorReply, + RtioErrorSequenceErrorReply, RtioErrorCollisionReply, RtioErrorBusyReply, @@ -55,8 +56,9 @@ impl Packet { 0x20 => Packet::RtioErrorRequest, 0x21 => Packet::RtioNoErrorReply, - 0x22 => Packet::RtioErrorCollisionReply, - 0x23 => Packet::RtioErrorBusyReply, + 0x22 => Packet::RtioErrorSequenceErrorReply, + 0x23 => Packet::RtioErrorCollisionReply, + 0x24 => Packet::RtioErrorBusyReply, 0x40 => Packet::MonitorRequest { channel: read_u16(reader)?, @@ -145,8 +147,9 @@ impl Packet { Packet::RtioErrorRequest => write_u8(writer, 0x20)?, Packet::RtioNoErrorReply => write_u8(writer, 0x21)?, - Packet::RtioErrorCollisionReply => write_u8(writer, 0x22)?, - Packet::RtioErrorBusyReply => write_u8(writer, 0x23)?, + Packet::RtioErrorSequenceErrorReply => write_u8(writer, 0x22)?, + Packet::RtioErrorCollisionReply => write_u8(writer, 0x23)?, + Packet::RtioErrorBusyReply => write_u8(writer, 0x24)?, Packet::MonitorRequest { channel, probe } => { write_u8(writer, 0x40)?; @@ -278,7 +281,7 @@ pub mod hw { unsafe { if (board::csr::DRTIO[linkidx].aux_rx_present_read)() == 1 { let length = (board::csr::DRTIO[linkidx].aux_rx_length_read)(); - let base = board::mem::DRTIO_AUX[linkidx].base + board::mem::DRTIO_AUX[linkidx].size/2; + let base = board::mem::DRTIO_AUX[linkidx].base + board::mem::DRTIO_AUX[linkidx].size/2; let sl = slice::from_raw_parts(base as *mut u8, length as usize); Some(RxBuffer(linkno, sl)) } else { diff --git a/artiq/firmware/libproto/kernel_proto.rs b/artiq/firmware/libproto/kernel_proto.rs index c59306cb8..06e5473d0 100644 --- a/artiq/firmware/libproto/kernel_proto.rs +++ b/artiq/firmware/libproto/kernel_proto.rs @@ -46,14 +46,10 @@ pub enum Message<'a> { duration: u64 }, - DrtioChannelStateRequest { channel: u32 }, - DrtioChannelStateReply { fifo_space: u16, last_timestamp: u64 }, - DrtioResetChannelStateRequest { channel: u32 }, - DrtioGetFifoSpaceRequest { channel: u32 }, DrtioPacketCountRequest { linkno: u8 }, DrtioPacketCountReply { tx_cnt: u32, rx_cnt: u32 }, - DrtioFifoSpaceReqCountRequest { linkno: u8 }, - DrtioFifoSpaceReqCountReply { cnt: u32 }, + DrtioBufferSpaceReqCountRequest { linkno: u8 }, + DrtioBufferSpaceReqCountReply { cnt: u32 }, RunFinished, RunException { diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index a9c67178b..402a8590c 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -323,26 +323,13 @@ pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> io::Result kern_acknowledge() } - &kern::DrtioChannelStateRequest { channel } => { - let (fifo_space, last_timestamp) = rtio_mgt::drtio_dbg::get_channel_state(channel); - kern_send(io, &kern::DrtioChannelStateReply { fifo_space: fifo_space, - last_timestamp: last_timestamp }) - } - &kern::DrtioResetChannelStateRequest { channel } => { - rtio_mgt::drtio_dbg::reset_channel_state(channel); - kern_acknowledge() - } - &kern::DrtioGetFifoSpaceRequest { channel } => { - rtio_mgt::drtio_dbg::get_fifo_space(channel); - kern_acknowledge() - } &kern::DrtioPacketCountRequest { linkno } => { let (tx_cnt, rx_cnt) = rtio_mgt::drtio_dbg::get_packet_counts(linkno); kern_send(io, &kern::DrtioPacketCountReply { tx_cnt: tx_cnt, rx_cnt: rx_cnt }) } - &kern::DrtioFifoSpaceReqCountRequest { linkno } => { - let cnt = rtio_mgt::drtio_dbg::get_fifo_space_req_count(linkno); - kern_send(io, &kern::DrtioFifoSpaceReqCountReply { cnt: cnt }) + &kern::DrtioBufferSpaceReqCountRequest { linkno } => { + let cnt = rtio_mgt::drtio_dbg::get_buffer_space_req_count(linkno); + kern_send(io, &kern::DrtioBufferSpaceReqCountReply { cnt: cnt }) } &kern::I2cStartRequest { busno } => { diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index e7578d92c..c411295f4 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -73,21 +73,11 @@ pub mod drtio { unsafe { (csr::DRTIO[linkidx].reset_write)(1); while (csr::DRTIO[linkidx].o_wait_read)() == 1 {} - } - // TODO: determine actual number of remote FIFOs - for channel in 0..16 { - unsafe { - (csr::DRTIO[linkidx].chan_sel_override_write)(channel); - (csr::DRTIO[linkidx].chan_sel_override_en_write)(1); - (csr::DRTIO[linkidx].o_reset_channel_status_write)(1); - (csr::DRTIO[linkidx].o_get_fifo_space_write)(1); - while (csr::DRTIO[linkidx].o_wait_read)() == 1 {} - info!("[LINK#{}] FIFO space on channel {} is {}", - linkno, channel, (csr::DRTIO[linkidx].o_dbg_fifo_space_read)()); - - (csr::DRTIO[linkidx].chan_sel_override_en_write)(0); - } + (csr::DRTIO[linkidx].o_get_buffer_space_write)(1); + while (csr::DRTIO[linkidx].o_wait_read)() == 1 {} + info!("[LINK#{}] buffer space is {}", + linkno, (csr::DRTIO[linkidx].o_dbg_buffer_space_read)()); } } @@ -130,7 +120,7 @@ pub mod drtio { error!("[LINK#{}] received truncated packet", linkno); } if errors & 4 != 0 { - error!("[LINK#{}] timeout attempting to get remote FIFO space", linkno); + error!("[LINK#{}] timeout attempting to get remote buffer space", linkno); } } } @@ -139,6 +129,8 @@ pub mod drtio { drtioaux::hw::send_link(linkno, &drtioaux::Packet::RtioErrorRequest).unwrap(); match drtioaux::hw::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::RtioNoErrorReply) => (), + Ok(drtioaux::Packet::RtioErrorSequenceErrorReply) => + error!("[LINK#{}] RTIO sequence error", linkno), Ok(drtioaux::Packet::RtioErrorCollisionReply) => error!("[LINK#{}] RTIO collision", linkno), Ok(drtioaux::Packet::RtioErrorBusyReply) => @@ -251,42 +243,6 @@ pub fn init_core() { pub mod drtio_dbg { use board::csr; - // TODO: routing - pub fn get_channel_state(channel: u32) -> (u16, u64) { - let linkno = ((channel >> 16) - 1) as usize; - let node_channel = channel as u16; - unsafe { - (csr::DRTIO[linkno].chan_sel_override_write)(node_channel as u16); - (csr::DRTIO[linkno].chan_sel_override_en_write)(1); - let fifo_space = (csr::DRTIO[linkno].o_dbg_fifo_space_read)(); - let last_timestamp = (csr::DRTIO[linkno].o_dbg_last_timestamp_read)(); - (csr::DRTIO[linkno].chan_sel_override_en_write)(0); - (fifo_space, last_timestamp) - } - } - - pub fn reset_channel_state(channel: u32) { - let linkno = ((channel >> 16) - 1) as usize; - let node_channel = channel as u16; - unsafe { - (csr::DRTIO[linkno].chan_sel_override_write)(node_channel); - (csr::DRTIO[linkno].chan_sel_override_en_write)(1); - (csr::DRTIO[linkno].o_reset_channel_status_write)(1); - (csr::DRTIO[linkno].chan_sel_override_en_write)(0); - } - } - - pub fn get_fifo_space(channel: u32) { - let linkno = ((channel >> 16) - 1) as usize; - let node_channel = channel as u16; - unsafe { - (csr::DRTIO[linkno].chan_sel_override_write)(node_channel); - (csr::DRTIO[linkno].chan_sel_override_en_write)(1); - (csr::DRTIO[linkno].o_get_fifo_space_write)(1); - (csr::DRTIO[linkno].chan_sel_override_en_write)(0); - } - } - pub fn get_packet_counts(linkno: u8) -> (u32, u32) { let linkno = linkno as usize; unsafe { @@ -296,23 +252,17 @@ pub mod drtio_dbg { } } - pub fn get_fifo_space_req_count(linkno: u8) -> u32 { + pub fn get_buffer_space_req_count(linkno: u8) -> u32 { let linkno = linkno as usize; unsafe { - (csr::DRTIO[linkno].o_dbg_fifo_space_req_cnt_read)() + (csr::DRTIO[linkno].o_dbg_buffer_space_req_cnt_read)() } } } #[cfg(not(has_drtio))] pub mod drtio_dbg { - pub fn get_channel_state(_channel: u32) -> (u16, u64) { (0, 0) } - - pub fn reset_channel_state(_channel: u32) {} - - pub fn get_fifo_space(_channel: u32) {} - pub fn get_packet_counts(_linkno: u8) -> (u32, u32) { (0, 0) } - pub fn get_fifo_space_req_count(_linkno: u8) -> u32 { 0 } + pub fn get_buffer_space_req_count(_linkno: u8) -> u32 { 0 } } diff --git a/artiq/firmware/satman/lib.rs b/artiq/firmware/satman/lib.rs index 5ffb0d6a2..4df701b4d 100644 --- a/artiq/firmware/satman/lib.rs +++ b/artiq/firmware/satman/lib.rs @@ -26,13 +26,19 @@ fn process_aux_packet(p: &drtioaux::Packet) { unsafe { (board::csr::DRTIO[0].rtio_error_write)(1); } - drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorCollisionReply).unwrap(); + drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorSequenceErrorReply).unwrap(); } else if errors & 2 != 0 { unsafe { (board::csr::DRTIO[0].rtio_error_write)(2); } + drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorCollisionReply).unwrap(); + } else if errors & 4 != 0 { + unsafe { + (board::csr::DRTIO[0].rtio_error_write)(4); + } drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorBusyReply).unwrap(); - } else { + } + else { drtioaux::hw::send_link(0, &drtioaux::Packet::RtioNoErrorReply).unwrap(); } } @@ -153,9 +159,6 @@ fn process_errors() { if errors & 8 != 0 { error!("write overflow"); } - if errors & 16 != 0 { - error!("write sequence error"); - } } diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index c3da1cb51..f2ecce9e4 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -3,10 +3,12 @@ from types import SimpleNamespace from migen import * from migen.genlib.cdc import ElasticBuffer +from artiq.gateware.rtio.sed.core import * +from artiq.gateware.rtio.input_collector import * from artiq.gateware.drtio import (link_layer, aux_controller, - rt_packet_satellite, rt_ios_satellite, + rt_packet_satellite, rt_iobuffer_satellite, rt_errors_satellite, - rt_packet_master, rt_controller_master) + rt_packet_master, rt_controller_master) class ChannelInterface: @@ -49,7 +51,8 @@ class GenericRXSynchronizer(Module): class DRTIOSatellite(Module): - def __init__(self, chanif, channels, rx_synchronizer=None, fine_ts_width=3, full_ts_width=63): + def __init__(self, chanif, channels, rx_synchronizer=None, fine_ts_width=3, + lane_count=8, fifo_depth=128): if rx_synchronizer is None: rx_synchronizer = GenericRXSynchronizer() self.submodules += rx_synchronizer @@ -77,11 +80,29 @@ class DRTIOSatellite(Module): self.submodules.rt_packet = ClockDomainsRenamer("rtio")( rt_packet_satellite.RTPacketSatellite(link_layer_sync)) - self.submodules.ios = rt_ios_satellite.IOS( - self.rt_packet, channels, fine_ts_width, full_ts_width) + coarse_ts = Signal(64 - fine_ts_width) + self.sync.rtio += \ + If(self.rt_packet.tsc_load, + coarse_ts.eq(self.rt_packet.tsc_load_value) + ).Else( + coarse_ts.eq(coarse_ts + 1) + ) + self.comb += self.rt_packet.cri.counter.eq(coarse_ts << fine_ts_width) + + self.submodules.outputs = ClockDomainsRenamer("rio")( + SED(channels, fine_ts_width, "sync", + lane_count=lane_count, fifo_depth=fifo_depth, + report_buffer_space=True, interface=self.rt_packet.cri)) + self.comb += self.outputs.coarse_timestamp.eq(coarse_ts) + self.sync += self.outputs.minimum_coarse_timestamp.eq(coarse_ts + 16) + + self.submodules.inputs = ClockDomainsRenamer("rio")( + InputCollector(channels, fine_ts_width, "sync", + interface=self.rt_packet.cri)) + self.comb += self.inputs.coarse_timestamp.eq(coarse_ts) self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite( - self.rt_packet, self.ios) + self.rt_packet, self.outputs) self.clock_domains.cd_rio = ClockDomain() self.clock_domains.cd_rio_phy = ClockDomain() diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index b7ecfd5a3..12683db01 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -15,9 +15,6 @@ class _CSRs(AutoCSR): def __init__(self): self.protocol_error = CSR(3) - self.chan_sel_override = CSRStorage(16) - self.chan_sel_override_en = CSRStorage() - self.tsc_correction = CSRStorage(64) self.set_time = CSR() self.underflow_margin = CSRStorage(16, reset=200) @@ -25,11 +22,9 @@ class _CSRs(AutoCSR): self.reset = CSR() self.reset_phy = CSR() - self.o_get_fifo_space = CSR() - self.o_dbg_fifo_space = CSRStatus(16) - self.o_dbg_last_timestamp = CSRStatus(64) - self.o_dbg_fifo_space_req_cnt = CSRStatus(32) - self.o_reset_channel_status = CSR() + self.o_get_buffer_space = CSR() + self.o_dbg_buffer_space = CSRStatus(16) + self.o_dbg_buffer_space_req_cnt = CSRStatus(32) self.o_wait = CSRStatus() @@ -59,27 +54,20 @@ class RTController(Module): # protocol errors err_unknown_packet_type = Signal() err_packet_truncated = Signal() - signal_fifo_space_timeout = Signal() - err_fifo_space_timeout = Signal() + signal_buffer_space_timeout = Signal() + err_buffer_space_timeout = Signal() self.sync.sys_with_rst += [ If(self.csrs.protocol_error.re, If(self.csrs.protocol_error.r[0], err_unknown_packet_type.eq(0)), If(self.csrs.protocol_error.r[1], err_packet_truncated.eq(0)), - If(self.csrs.protocol_error.r[2], err_fifo_space_timeout.eq(0)) + If(self.csrs.protocol_error.r[2], err_buffer_space_timeout.eq(0)) ), If(rt_packet.err_unknown_packet_type, err_unknown_packet_type.eq(1)), If(rt_packet.err_packet_truncated, err_packet_truncated.eq(1)), - If(signal_fifo_space_timeout, err_fifo_space_timeout.eq(1)) + If(signal_buffer_space_timeout, err_buffer_space_timeout.eq(1)) ] self.comb += self.csrs.protocol_error.w.eq( - Cat(err_unknown_packet_type, err_packet_truncated, err_fifo_space_timeout)) - - # channel selection - chan_sel = Signal(16) - self.comb += chan_sel.eq( - Mux(self.csrs.chan_sel_override_en.storage, - self.csrs.chan_sel_override.storage, - self.cri.chan_sel[:16])) + Cat(err_unknown_packet_type, err_packet_truncated, err_buffer_space_timeout)) # master RTIO counter and counter synchronization self.submodules.counter = RTIOCounter(64-fine_ts_width) @@ -122,26 +110,16 @@ class RTController(Module): self.comb += self.cd_rtio_with_rst.clk.eq(ClockSignal("rtio")) self.specials += AsyncResetSynchronizer(self.cd_rtio_with_rst, local_reset) - # remote channel status cache - fifo_spaces_mem = Memory(16, channel_count) - fifo_spaces = fifo_spaces_mem.get_port(write_capable=True) - self.specials += fifo_spaces_mem, fifo_spaces - last_timestamps_mem = Memory(64, channel_count) - last_timestamps = last_timestamps_mem.get_port(write_capable=True) - self.specials += last_timestamps_mem, last_timestamps - # common packet fields - rt_packet_fifo_request = Signal() + chan_sel = self.cri.chan_sel[:16] + rt_packet_buffer_request = Signal() rt_packet_read_request = Signal() self.comb += [ - fifo_spaces.adr.eq(chan_sel), - last_timestamps.adr.eq(chan_sel), - last_timestamps.dat_w.eq(self.cri.timestamp), rt_packet.sr_channel.eq(chan_sel), rt_packet.sr_address.eq(self.cri.o_address), rt_packet.sr_data.eq(self.cri.o_data), rt_packet.sr_timestamp.eq(self.cri.timestamp), - If(rt_packet_fifo_request, + If(rt_packet_buffer_request, rt_packet.sr_notwrite.eq(1), rt_packet.sr_address.eq(0) ), @@ -154,30 +132,28 @@ class RTController(Module): # output status o_status_wait = Signal() o_status_underflow = Signal() - o_status_sequence_error = Signal() self.comb += [ self.cri.o_status.eq(Cat( - o_status_wait, o_status_underflow, o_status_sequence_error)), + o_status_wait, o_status_underflow)), self.csrs.o_wait.status.eq(o_status_wait) ] - o_sequence_error_set = Signal() o_underflow_set = Signal() self.sync.sys_with_rst += [ If(self.cri.cmd == cri.commands["write"], - o_status_underflow.eq(0), - o_status_sequence_error.eq(0), + o_status_underflow.eq(0) ), - If(o_underflow_set, o_status_underflow.eq(1)), - If(o_sequence_error_set, o_status_sequence_error.eq(1)) + If(o_underflow_set, o_status_underflow.eq(1)) ] timeout_counter = WaitTimer(8191) self.submodules += timeout_counter - cond_sequence_error = self.cri.timestamp < last_timestamps.dat_r - cond_underflow = ((self.cri.timestamp[fine_ts_width:] + cond_underflow = Signal() + self.comb += cond_underflow.eq((self.cri.timestamp[fine_ts_width:] - self.csrs.underflow_margin.storage[fine_ts_width:]) < self.counter.value_sys) + buffer_space = Signal(16) + # input status i_status_wait_event = Signal() i_status_overflow = Signal() @@ -208,56 +184,51 @@ class RTController(Module): fsm.act("IDLE", If(self.cri.cmd == cri.commands["write"], - If(cond_sequence_error, - o_sequence_error_set.eq(1) - ).Elif(cond_underflow, + If(cond_underflow, o_underflow_set.eq(1) ).Else( NextState("WRITE") ) ), If(self.cri.cmd == cri.commands["read"], NextState("READ")), - If(self.csrs.o_get_fifo_space.re, NextState("GET_FIFO_SPACE")) + If(self.csrs.o_get_buffer_space.re, NextState("GET_BUFFER_SPACE")) ) fsm.act("WRITE", o_status_wait.eq(1), rt_packet.sr_stb.eq(1), If(rt_packet.sr_ack, - fifo_spaces.we.eq(1), - fifo_spaces.dat_w.eq(fifo_spaces.dat_r - 1), - last_timestamps.we.eq(1), - If(fifo_spaces.dat_r <= 1, - NextState("GET_FIFO_SPACE") + NextValue(buffer_space, buffer_space - 1), + If(buffer_space <= 1, + NextState("GET_BUFFER_SPACE") ).Else( NextState("IDLE") ) ) ) - fsm.act("GET_FIFO_SPACE", + fsm.act("GET_BUFFER_SPACE", o_status_wait.eq(1), - rt_packet.fifo_space_not_ack.eq(1), - rt_packet_fifo_request.eq(1), + rt_packet.buffer_space_not_ack.eq(1), + rt_packet_buffer_request.eq(1), rt_packet.sr_stb.eq(1), If(rt_packet.sr_ack, - NextState("GET_FIFO_SPACE_REPLY") + NextState("GET_BUFFER_SPACE_REPLY") ) ) - fsm.act("GET_FIFO_SPACE_REPLY", + fsm.act("GET_BUFFER_SPACE_REPLY", o_status_wait.eq(1), - fifo_spaces.dat_w.eq(rt_packet.fifo_space), - fifo_spaces.we.eq(1), - rt_packet.fifo_space_not_ack.eq(1), - If(rt_packet.fifo_space_not, - If(rt_packet.fifo_space != 0, + NextValue(buffer_space, rt_packet.buffer_space), + rt_packet.buffer_space_not_ack.eq(1), + If(rt_packet.buffer_space_not, + If(rt_packet.buffer_space != 0, NextState("IDLE") ).Else( - NextState("GET_FIFO_SPACE") + NextState("GET_BUFFER_SPACE") ) ), timeout_counter.wait.eq(1), If(timeout_counter.done, - signal_fifo_space_timeout.eq(1), - NextState("GET_FIFO_SPACE") + signal_buffer_space_timeout.eq(1), + NextState("GET_BUFFER_SPACE") ) ) fsm.act("READ", @@ -278,21 +249,12 @@ class RTController(Module): ) ) - # channel state access - self.comb += [ - self.csrs.o_dbg_fifo_space.status.eq(fifo_spaces.dat_r), - self.csrs.o_dbg_last_timestamp.status.eq(last_timestamps.dat_r), - If(self.csrs.o_reset_channel_status.re, - fifo_spaces.dat_w.eq(0), - fifo_spaces.we.eq(1), - last_timestamps.dat_w.eq(0), - last_timestamps.we.eq(1) - ) - ] + # debug CSRs + self.comb += self.csrs.o_dbg_buffer_space.status.eq(buffer_space), self.sync += \ - If((rt_packet.sr_stb & rt_packet.sr_ack & rt_packet_fifo_request), - self.csrs.o_dbg_fifo_space_req_cnt.status.eq( - self.csrs.o_dbg_fifo_space_req_cnt.status + 1) + If((rt_packet.sr_stb & rt_packet.sr_ack & rt_packet_buffer_request), + self.csrs.o_dbg_buffer_space_req_cnt.status.eq( + self.csrs.o_dbg_buffer_space_req_cnt.status + 1) ) def get_csrs(self): diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index e93a7bc9c..173dd7dcf 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -7,31 +7,48 @@ from artiq.gateware.rtio.cdc import BlindTransfer class RTErrorsSatellite(Module, AutoCSR): - def __init__(self, rt_packet, ios): - self.protocol_error = CSR(5) - self.rtio_error = CSR(2) + def __init__(self, rt_packet, outputs): + self.protocol_error = CSR(4) + self.rtio_error = CSR(3) def error_csr(csr, *sources): - for n, source in enumerate(sources): + for n, (source, detect_edges) in enumerate(sources): + assert isinstance(source, Signal) pending = Signal(related=source) xfer = BlindTransfer(odomain="sys") self.submodules += xfer - self.comb += xfer.i.eq(source) + if detect_edges: + source_r = Signal() + self.sync.rio += source_r.eq(source) + self.comb += xfer.i.eq(source & source_r) + else: + self.comb += xfer.i.eq(source) self.sync += [ If(csr.re & csr.r[n], pending.eq(0)), If(xfer.o, pending.eq(1)) ] self.comb += csr.w[n].eq(pending) - # The master is normally responsible for avoiding output overflows, - # output underflows, and sequence errors. - # Error reports here are only for diagnosing internal ARTIQ bugs. - error_csr(self.protocol_error, - rt_packet.unknown_packet_type, - rt_packet.packet_truncated, - ios.write_underflow, - ios.write_overflow, - ios.write_sequence_error) + + # The master is normally responsible for avoiding output overflows + # and output underflows. The error reports here are only for diagnosing + # internal ARTIQ bugs. + underflow = Signal() + overflow = Signal() + sequence_error = Signal() + self.comb += [ + underflow.eq(outputs.cri.o_status[1]), + overflow.eq(outputs.cri.o_status[0]), + sequence_error.eq(outputs.cri.o_status[2]) + ] + error_csr(self.protocol_error, + (rt_packet.unknown_packet_type, False), + (rt_packet.packet_truncated, False), + (underflow, True), + (overflow, True) + ) error_csr(self.rtio_error, - ios.collision, - ios.busy) + (sequence_error, True), + (outputs.collision, False), + (outputs.busy, False) + ) diff --git a/artiq/gateware/drtio/rt_ios_satellite.py b/artiq/gateware/drtio/rt_ios_satellite.py deleted file mode 100644 index f9fc9096e..000000000 --- a/artiq/gateware/drtio/rt_ios_satellite.py +++ /dev/null @@ -1,246 +0,0 @@ -"""Real-time I/O scheduler for satellites""" - -from migen import * -from migen.genlib.fifo import SyncFIFOBuffered -from migen.genlib.record import * - -from artiq.gateware.rtio import rtlink - - -class IOS(Module): - def __init__(self, rt_packet, channels, max_fine_ts_width, full_ts_width): - self.write_underflow = Signal() - self.write_overflow = Signal() - self.write_sequence_error = Signal() - self.collision = Signal() - self.busy = Signal() - - self.rt_packet = rt_packet - self.max_fine_ts_width = max_fine_ts_width - - self.tsc = Signal(full_ts_width - max_fine_ts_width) - self.sync.rtio += \ - If(rt_packet.tsc_load, - self.tsc.eq(rt_packet.tsc_load_value) - ).Else( - self.tsc.eq(self.tsc + 1) - ) - self.comb += rt_packet.tsc_input.eq(self.tsc) - - self.sync.rio += [ - self.write_underflow.eq(0), - self.write_overflow.eq(0), - self.collision.eq(0), - self.busy.eq(0) - ] - for n, channel in enumerate(channels): - self.add_output(n, channel) - self.add_input(n, channel) - - def add_output(self, n, channel): - rt_packet = self.rt_packet - max_fine_ts_width = self.max_fine_ts_width - - interface = channel.interface.o - data_width = rtlink.get_data_width(interface) - address_width = rtlink.get_address_width(interface) - fine_ts_width = rtlink.get_fine_ts_width(interface) - assert fine_ts_width <= max_fine_ts_width - - we = Signal() - self.comb += we.eq(rt_packet.write_stb - & (rt_packet.write_channel == n)) - write_timestamp = rt_packet.write_timestamp[max_fine_ts_width-fine_ts_width:] - write_timestamp_coarse = rt_packet.write_timestamp[max_fine_ts_width:] - write_timestamp_fine = rt_packet.write_timestamp[max_fine_ts_width-fine_ts_width:max_fine_ts_width] - - # latency compensation - if interface.delay: - tsc_comp = Signal.like(self.tsc) - self.sync.rtio += tsc_comp.eq(self.tsc - interface.delay + 1) - else: - tsc_comp = self.tsc - - # FIFO - ev_layout = [] - if data_width: - ev_layout.append(("data", data_width)) - if address_width: - ev_layout.append(("address", address_width)) - ev_layout.append(("timestamp", len(self.tsc) + fine_ts_width)) - - fifo = ClockDomainsRenamer("rio")( - SyncFIFOBuffered(layout_len(ev_layout), channel.ofifo_depth)) - self.submodules += fifo - fifo_in = Record(ev_layout) - fifo_out = Record(ev_layout) - self.comb += [ - fifo.din.eq(fifo_in.raw_bits()), - fifo_out.raw_bits().eq(fifo.dout) - ] - - # Buffer - buf_pending = Signal() - buf = Record(ev_layout) - buf_just_written = Signal() - - # Special cases - replace = Signal() - sequence_error = Signal() - collision = Signal() - any_error = Signal() - if interface.enable_replace: - # Note: replace may be asserted at the same time as collision - # when addresses are different. In that case, it is a collision. - self.sync.rio += replace.eq(write_timestamp == buf.timestamp) - # Detect sequence errors on coarse timestamps only - # so that they are mutually exclusive with collision errors. - self.sync.rio += sequence_error.eq(write_timestamp_coarse < buf.timestamp[fine_ts_width:]) - if interface.enable_replace: - if address_width: - different_addresses = rt_packet.write_address != buf.address - else: - different_addresses = 0 - if fine_ts_width: - self.sync.rio += collision.eq( - (write_timestamp_coarse == buf.timestamp[fine_ts_width:]) - & ((write_timestamp_fine != buf.timestamp[:fine_ts_width]) - |different_addresses)) - else: - self.sync.rio += collision.eq( - (write_timestamp == buf.timestamp) & different_addresses) - else: - self.sync.rio += collision.eq( - write_timestamp_coarse == buf.timestamp[fine_ts_width:]) - self.comb += any_error.eq(sequence_error | collision) - self.sync.rio += [ - If(we & sequence_error, self.write_sequence_error.eq(1)), - If(we & collision, self.collision.eq(1)) - ] - - # Buffer read and FIFO write - self.comb += fifo_in.eq(buf) - in_guard_time = Signal() - self.comb += in_guard_time.eq( - buf.timestamp[fine_ts_width:] < tsc_comp + 4) - self.sync.rio += If(in_guard_time, buf_pending.eq(0)) - report_underflow = Signal() - self.comb += \ - If(buf_pending, - If(in_guard_time, - If(buf_just_written, - report_underflow.eq(1) - ).Else( - fifo.we.eq(1) - ) - ), - If(we & ~replace & ~any_error, - fifo.we.eq(1) - ) - ) - self.sync.rio += If(report_underflow, self.write_underflow.eq(1)) - - # Buffer write - # Must come after read to handle concurrent read+write properly - self.sync.rio += [ - buf_just_written.eq(0), - If(we & ~any_error, - buf_just_written.eq(1), - buf_pending.eq(1), - buf.timestamp.eq(write_timestamp), - buf.data.eq(rt_packet.write_data) if data_width else [], - buf.address.eq(rt_packet.write_address) if address_width else [], - ), - If(we & ~fifo.writable, self.write_overflow.eq(1)) - ] - - # FIFO level - self.sync.rio += \ - If(rt_packet.fifo_space_update & - (rt_packet.fifo_space_channel == n), - rt_packet.fifo_space.eq(channel.ofifo_depth - fifo.level)) - - # FIFO read - self.sync.rio += [ - fifo.re.eq(0), - interface.stb.eq(0), - If(fifo.readable & - (fifo_out.timestamp[fine_ts_width:] == tsc_comp), - fifo.re.eq(1), - interface.stb.eq(1) - ) - ] - if data_width: - self.sync.rio += interface.data.eq(fifo_out.data) - if address_width: - self.sync.rio += interface.address.eq(fifo_out.address) - if fine_ts_width: - self.sync.rio += interface.fine_ts.eq(fifo_out.timestamp[:fine_ts_width]) - - self.sync.rio += If(interface.stb & interface.busy, self.busy.eq(1)) - - def add_input(self, n, channel): - rt_packet = self.rt_packet - - interface = channel.interface.i - if interface is None: - return - data_width = rtlink.get_data_width(interface) - fine_ts_width = rtlink.get_fine_ts_width(interface) - - selected = Signal() - self.comb += selected.eq(rt_packet.read_channel == n) - - # latency compensation - if interface.delay: - tsc_comp = Signal.like(self.tsc) - self.sync.rtio += tsc_comp.eq(self.tsc - interface.delay + 1) - else: - tsc_comp = self.tsc - - # FIFO - ev_layout = [] - if data_width: - ev_layout.append(("data", data_width)) - if interface.timestamped: - ev_layout.append(("timestamp", len(self.tsc) + fine_ts_width)) - - fifo = ClockDomainsRenamer("rio")( - SyncFIFOBuffered(layout_len(ev_layout), channel.ififo_depth)) - self.submodules += fifo - fifo_in = Record(ev_layout) - fifo_out = Record(ev_layout) - self.comb += [ - fifo.din.eq(fifo_in.raw_bits()), - fifo_out.raw_bits().eq(fifo.dout) - ] - - # FIFO write - if data_width: - self.comb += fifo_in.data.eq(interface.data) - if interface.timestamped: - if fine_ts_width: - full_ts = Cat(interface.fine_ts, tsc_comp) - else: - full_ts = tsc_comp - self.comb += fifo_in.timestamp.eq(full_ts) - self.comb += fifo.we.eq(interface.stb) - - overflow = Signal() - self.comb += If(selected, rt_packet.read_overflow.eq(overflow)) - self.sync.rio += [ - If(selected & rt_packet.read_overflow_ack, overflow.eq(0)), - If(fifo.we & ~fifo.writable, overflow.eq(1)) - ] - - # FIFO read - if data_width: - self.comb += If(selected, rt_packet.read_data.eq(fifo_out.data)) - if interface.timestamped: - self.comb += If(selected, rt_packet.read_timestamp.eq(fifo_out.timestamp)) - self.comb += [ - If(selected, - rt_packet.read_readable.eq(fifo.readable), - fifo.re.eq(rt_packet.read_consume) - ) - ] diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index a32004ebd..94dea3944 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -66,12 +66,12 @@ class RTPacketMaster(Module): # standard request interface # - # notwrite=1 address=0 FIFO space request + # notwrite=1 address=0 buffer space request # notwrite=1 address=1 read request # # optimized for write throughput # requests are performed on the DRTIO link preserving their order of issue - # this is important for FIFO space requests, which have to be ordered + # this is important for buffer space requests, which have to be ordered # wrt writes. self.sr_stb = Signal() self.sr_ack = Signal() @@ -81,10 +81,10 @@ class RTPacketMaster(Module): self.sr_address = Signal(16) self.sr_data = Signal(512) - # fifo space reply interface - self.fifo_space_not = Signal() - self.fifo_space_not_ack = Signal() - self.fifo_space = Signal(16) + # buffer space reply interface + self.buffer_space_not = Signal() + self.buffer_space_not_ack = Signal() + self.buffer_space = Signal(16) # read reply interface self.read_not = Signal() @@ -209,11 +209,11 @@ class RTPacketMaster(Module): ) # CDC - fifo_space_not = Signal() - fifo_space = Signal(16) + buffer_space_not = Signal() + buffer_space = Signal(16) self.submodules += _CrossDomainNotification("rtio_rx", - fifo_space_not, fifo_space, - self.fifo_space_not, self.fifo_space_not_ack, self.fifo_space) + buffer_space_not, buffer_space, + self.buffer_space_not, self.buffer_space_not_ack, self.buffer_space) set_time_stb = Signal() set_time_ack = Signal() @@ -274,7 +274,7 @@ class RTPacketMaster(Module): If(sr_buf_readable, If(sr_notwrite, Case(sr_address[0], { - 0: NextState("FIFO_SPACE"), + 0: NextState("BUFFER_SPACE"), 1: NextState("READ") }), ).Else( @@ -316,8 +316,8 @@ class RTPacketMaster(Module): NextState("IDLE") ) ) - tx_fsm.act("FIFO_SPACE", - tx_dp.send("fifo_space_request", channel=sr_channel), + tx_fsm.act("BUFFER_SPACE", + tx_dp.send("buffer_space_request"), If(tx_dp.packet_last, sr_buf_re.eq(1), NextState("IDLE") @@ -369,7 +369,7 @@ class RTPacketMaster(Module): If(rx_dp.packet_last, Case(rx_dp.packet_type, { rx_plm.types["echo_reply"]: echo_received_now.eq(1), - rx_plm.types["fifo_space_reply"]: NextState("FIFO_SPACE"), + rx_plm.types["buffer_space_reply"]: NextState("BUFFER_SPACE"), rx_plm.types["read_reply"]: NextState("READ_REPLY"), rx_plm.types["read_reply_noevent"]: NextState("READ_REPLY_NOEVENT"), "default": err_unknown_packet_type.i.eq(1) @@ -382,9 +382,9 @@ class RTPacketMaster(Module): err_packet_truncated.i.eq(1) ) ) - rx_fsm.act("FIFO_SPACE", - fifo_space_not.eq(1), - fifo_space.eq(rx_dp.packet_as["fifo_space_reply"].space), + rx_fsm.act("BUFFER_SPACE", + buffer_space_not.eq(1), + buffer_space.eq(rx_dp.packet_as["buffer_space_reply"].space), NextState("INPUT") ) rx_fsm.act("READ_REPLY", diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 249f8ca27..47b9a1d55 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -3,6 +3,7 @@ from migen import * from migen.genlib.fsm import * +from artiq.gateware.rtio import cri from artiq.gateware.drtio.rt_serializer import * @@ -13,30 +14,11 @@ class RTPacketSatellite(Module): self.tsc_load = Signal() self.tsc_load_value = Signal(64) - self.tsc_input = Signal(64) self.reset = Signal(reset=1) self.reset_phy = Signal(reset=1) - self.fifo_space_channel = Signal(16) - self.fifo_space_update = Signal() - self.fifo_space = Signal(16) - - # write parameters are stable one cycle before stb is asserted, - # and when stb is asserted. - self.write_stb = Signal() - self.write_timestamp = Signal(64) - self.write_channel = Signal(16) - self.write_address = Signal(16) - self.write_data = Signal(512) - - self.read_channel = Signal(16) - self.read_readable = Signal() - self.read_consume = Signal() - self.read_data = Signal(32) - self.read_timestamp = Signal(64) - self.read_overflow = Signal() - self.read_overflow_ack = Signal() + self.cri = cri.Interface() # # # @@ -69,27 +51,49 @@ class RTPacketSatellite(Module): # RX->TX echo_req = Signal() - fifo_space_set = Signal() - fifo_space_req = Signal() - fifo_space_ack = Signal() + buffer_space_set = Signal() + buffer_space_req = Signal() + buffer_space_ack = Signal() self.sync += [ - If(fifo_space_ack, fifo_space_req.eq(0)), - If(fifo_space_set, fifo_space_req.eq(1)), + If(buffer_space_ack, buffer_space_req.eq(0)), + If(buffer_space_set, buffer_space_req.eq(1)), + ] + + buffer_space_update = Signal() + buffer_space = Signal(16) + self.sync += If(buffer_space_update, buffer_space.eq(self.cri.o_buffer_space)) + + load_read_request = Signal() + clear_read_request = Signal() + read_request_pending = Signal() + self.sync += [ + If(clear_read_request | self.reset, + read_request_pending.eq(0) + ), + If(load_read_request, + read_request_pending.eq(1), + ) ] # RX FSM + read = Signal() self.comb += [ self.tsc_load_value.eq( rx_dp.packet_as["set_time"].timestamp), - self.fifo_space_channel.eq( - rx_dp.packet_as["fifo_space_request"].channel), - self.write_timestamp.eq( - rx_dp.packet_as["write"].timestamp), - self.write_channel.eq( - rx_dp.packet_as["write"].channel), - self.write_address.eq( + If(load_read_request | read_request_pending, + self.cri.chan_sel.eq( + rx_dp.packet_as["read_request"].channel), + self.cri.timestamp.eq( + rx_dp.packet_as["read_request"].timeout) + ).Else( + self.cri.chan_sel.eq( + rx_dp.packet_as["write"].channel), + self.cri.timestamp.eq( + rx_dp.packet_as["write"].timestamp) + ), + self.cri.o_address.eq( rx_dp.packet_as["write"].address), - self.write_data.eq( + self.cri.o_data.eq( Cat(rx_dp.packet_as["write"].short_data, write_data_buffer)), ] @@ -100,26 +104,6 @@ class RTPacketSatellite(Module): self.reset_phy.eq(reset_phy) ] - load_read_request = Signal() - clear_read_request = Signal() - read_request_pending = Signal() - read_request_time_limit = Signal(64) - read_request_timeout = Signal() - read_request_wait = Signal() # 1 cycle latency channel→(data,overflow) and time_limit→timeout - self.sync += [ - If(clear_read_request | self.reset, - read_request_pending.eq(0) - ), - read_request_wait.eq(0), - If(load_read_request, - read_request_pending.eq(1), - read_request_wait.eq(1), - self.read_channel.eq(rx_dp.packet_as["read_request"].channel), - read_request_time_limit.eq(rx_dp.packet_as["read_request"].timeout) - ), - read_request_timeout.eq(self.tsc_input >= read_request_time_limit), - ] - rx_fsm = FSM(reset_state="INPUT") self.submodules += rx_fsm @@ -138,7 +122,7 @@ class RTPacketSatellite(Module): rx_plm.types["set_time"]: NextState("SET_TIME"), rx_plm.types["reset"]: NextState("RESET"), rx_plm.types["write"]: NextState("WRITE"), - rx_plm.types["fifo_space_request"]: NextState("FIFO_SPACE"), + rx_plm.types["buffer_space_request"]: NextState("BUFFER_SPACE"), rx_plm.types["read_request"]: NextState("READ_REQUEST"), "default": self.unknown_packet_type.eq(1) }) @@ -165,7 +149,7 @@ class RTPacketSatellite(Module): rx_fsm.act("WRITE", If(write_data_buffer_cnt == rx_dp.packet_as["write"].extra_data_cnt, - self.write_stb.eq(1), + self.cri.cmd.eq(cri.commands["write"]), NextState("INPUT") ).Else( write_data_buffer_load.eq(1), @@ -175,14 +159,15 @@ class RTPacketSatellite(Module): ) ) ) - rx_fsm.act("FIFO_SPACE", - fifo_space_set.eq(1), - self.fifo_space_update.eq(1), + rx_fsm.act("BUFFER_SPACE", + buffer_space_set.eq(1), + buffer_space_update.eq(1), NextState("INPUT") ) rx_fsm.act("READ_REQUEST", load_read_request.eq(1), + self.cri.cmd.eq(cri.commands["read"]), NextState("INPUT") ) @@ -192,11 +177,11 @@ class RTPacketSatellite(Module): tx_fsm.act("IDLE", If(echo_req, NextState("ECHO")), - If(fifo_space_req, NextState("FIFO_SPACE")), - If(~read_request_wait & read_request_pending, - If(read_request_timeout, NextState("READ_TIMEOUT")), - If(self.read_overflow, NextState("READ_OVERFLOW")), - If(self.read_readable, NextState("READ")) + If(buffer_space_req, NextState("BUFFER_SPACE")), + If(read_request_pending, + If(~self.cri.i_status[2], NextState("READ")), + If(self.cri.i_status[0], NextState("READ_TIMEOUT")), + If(self.cri.i_status[1], NextState("READ_OVERFLOW")) ) ) @@ -205,9 +190,9 @@ class RTPacketSatellite(Module): If(tx_dp.packet_last, NextState("IDLE")) ) - tx_fsm.act("FIFO_SPACE", - fifo_space_ack.eq(1), - tx_dp.send("fifo_space_reply", space=self.fifo_space), + tx_fsm.act("BUFFER_SPACE", + buffer_space_ack.eq(1), + tx_dp.send("buffer_space_reply", space=buffer_space), If(tx_dp.packet_last, NextState("IDLE")) ) @@ -220,17 +205,15 @@ class RTPacketSatellite(Module): tx_dp.send("read_reply_noevent", overflow=1), clear_read_request.eq(1), If(tx_dp.packet_last, - self.read_overflow_ack.eq(1), NextState("IDLE") ) ) tx_fsm.act("READ", tx_dp.send("read_reply", - timestamp=self.read_timestamp, - data=self.read_data), + timestamp=self.cri.i_timestamp, + data=self.cri.i_data), clear_read_request.eq(1), If(tx_dp.packet_last, - self.read_consume.eq(1), NextState("IDLE") ) ) diff --git a/artiq/gateware/drtio/rt_serializer.py b/artiq/gateware/drtio/rt_serializer.py index df1e2e5c6..8ba5668fc 100644 --- a/artiq/gateware/drtio/rt_serializer.py +++ b/artiq/gateware/drtio/rt_serializer.py @@ -18,7 +18,7 @@ class PacketLayoutManager: self.layouts = dict() self.types = dict() self.type_names = dict() - + def add_type(self, name, *fields, pad=True): type_n = len(self.types) self.types[name] = type_n @@ -54,7 +54,7 @@ def get_m2s_layouts(alignment): ("address", 16), ("extra_data_cnt", 8), ("short_data", short_data_len)) - plm.add_type("fifo_space_request", ("channel", 16)) + plm.add_type("buffer_space_request") plm.add_type("read_request", ("channel", 16), ("timeout", 64)) @@ -66,7 +66,7 @@ def get_s2m_layouts(alignment): plm.add_type("echo_reply") - plm.add_type("fifo_space_reply", ("space", 16)) + plm.add_type("buffer_space_reply", ("space", 16)) plm.add_type("read_reply", ("timestamp", 64), ("data", 32)) plm.add_type("read_reply_noevent", ("overflow", 1)) # overflow=0→timeout @@ -110,7 +110,7 @@ class ReceiveDatapath(Module): packet_buffer_count = Signal(max=w_in_packet+1) self.sync += \ If(self.packet_buffer_load, - Case(packet_buffer_count, + Case(packet_buffer_count, {i: packet_buffer[i*ws:(i+1)*ws].eq(self.data_r) for i in range(w_in_packet)}), packet_buffer_count.eq(packet_buffer_count + 1) diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 59e5b2897..3b1281005 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -52,7 +52,8 @@ class DUT(Module): self.ttl1 = Signal() self.transceivers = DummyTransceiverPair(nwords) - self.submodules.master = DRTIOMaster(self.transceivers.alice) + self.submodules.master = DRTIOMaster(self.transceivers.alice, + fine_ts_width=0) self.submodules.master_ki = rtio.KernelInitiator(self.master.cri) rx_synchronizer = DummyRXSynchronizer() @@ -60,132 +61,166 @@ class DUT(Module): self.submodules.phy1 = ttl_simple.Output(self.ttl1) self.submodules.phy2 = SimpleIOPHY(512, 32) # test wide output data rtio_channels = [ - rtio.Channel.from_phy(self.phy0, ofifo_depth=4), - rtio.Channel.from_phy(self.phy1, ofifo_depth=4), - rtio.Channel.from_phy(self.phy2, ofifo_depth=4), + rtio.Channel.from_phy(self.phy0), + rtio.Channel.from_phy(self.phy1), + rtio.Channel.from_phy(self.phy2), ] self.submodules.satellite = DRTIOSatellite( - self.transceivers.bob, rtio_channels, rx_synchronizer) - + self.transceivers.bob, rtio_channels, rx_synchronizer, + lane_count=4, fifo_depth=8, fine_ts_width=0) + + +class OutputsTestbench: + def __init__(self): + self.dut = DUT(2) + self.now = 0 + + def init(self): + yield from self.dut.master.rt_controller.csrs.underflow_margin.write(100) + while not (yield from self.dut.master.link_layer.link_status.read()): + yield + yield from self.get_buffer_space() + + def get_buffer_space(self): + csrs = self.dut.master.rt_controller.csrs + yield from csrs.o_get_buffer_space.write(1) + yield + while (yield from csrs.o_wait.read()): + yield + r = (yield from csrs.o_dbg_buffer_space.read()) + return r + + def delay(self, dt): + self.now += dt + + def sync(self): + t = self.now + 15 + while (yield self.dut.master.cri.counter) < t: + yield + + def write(self, channel, data): + kcsrs = self.dut.master_ki + yield from kcsrs.chan_sel.write(channel) + yield from kcsrs.timestamp.write(self.now) + yield from kcsrs.o_data.write(data) + yield from kcsrs.o_we.write(1) + yield + status = 1 + wlen = 0 + while status: + status = yield from kcsrs.o_status.read() + if status & 2: + raise RTIOUnderflow + if status & 4: + raise RTIOSequenceError + yield + wlen += 1 + return wlen + + @passive + def check_ttls(self, ttl_changes): + cycle = 0 + old_ttls = [0, 0] + while True: + ttls = [(yield self.dut.ttl0), (yield self.dut.ttl1)] + for n, (old_ttl, ttl) in enumerate(zip(old_ttls, ttls)): + if ttl != old_ttl: + ttl_changes.append((cycle, n)) + old_ttls = ttls + yield + cycle += 1 + class TestFullStack(unittest.TestCase): clocks = {"sys": 8, "rtio": 5, "rtio_rx": 5, "rio": 5, "rio_phy": 5, "sys_with_rst": 8, "rtio_with_rst": 5} - def test_outputs(self): - dut = DUT(2) - kcsrs = dut.master_ki - csrs = dut.master.rt_controller.csrs - mgr = dut.master.rt_manager - saterr = dut.satellite.rt_errors - + def test_pulses(self): + tb = OutputsTestbench() ttl_changes = [] correct_ttl_changes = [ - # from test_pulses - (203, 0), (208, 0), - (208, 1), - (214, 1), - - # from test_fifo_space - (414, 0), - (454, 0), - (494, 0), - (534, 0), - (574, 0), - (614, 0) + (213, 0), + (213, 1), + (219, 1), ] - now = 0 - def delay(dt): - nonlocal now - now += dt + def test(): + yield from tb.init() + tb.delay(200) + yield from tb.write(0, 1) + tb.delay(5) + yield from tb.write(0, 0) + yield from tb.write(1, 1) + tb.delay(6) + yield from tb.write(1, 0) + yield from tb.sync() - def get_fifo_space(channel): - yield from csrs.chan_sel_override_en.write(1) - yield from csrs.chan_sel_override.write(channel) - yield from csrs.o_get_fifo_space.write(1) - yield - while (yield from csrs.o_wait.read()): - yield - r = (yield from csrs.o_dbg_fifo_space.read()) - yield from csrs.chan_sel_override_en.write(0) - return r + run_simulation(tb.dut, + {"sys": test(), "rtio": tb.check_ttls(ttl_changes)}, self.clocks) + self.assertEqual(ttl_changes, correct_ttl_changes) - def write(channel, data): - yield from kcsrs.chan_sel.write(channel) - yield from kcsrs.timestamp.write(now) - yield from kcsrs.o_data.write(data) - yield from kcsrs.o_we.write(1) - yield - status = 1 - wlen = 0 - while status: - status = yield from kcsrs.o_status.read() - if status & 2: - raise RTIOUnderflow - if status & 4: - raise RTIOSequenceError - yield - wlen += 1 - return wlen + def test_underflow(self): + tb = OutputsTestbench() - def test_init(): - yield from get_fifo_space(0) - yield from get_fifo_space(1) - - def test_underflow(): + def test(): + yield from tb.init() with self.assertRaises(RTIOUnderflow): - yield from write(0, 0) + yield from tb.write(0, 0) - def test_pulses(): - delay(200*8) - yield from write(0, 1) - delay(5*8) - yield from write(0, 1) - yield from write(0, 0) # replace - yield from write(1, 1) - delay(6*8) - yield from write(1, 0) + run_simulation(tb.dut, {"sys": test()}, self.clocks) - def test_sequence_error(): - delay(-200*8) - with self.assertRaises(RTIOSequenceError): - yield from write(0, 1) - delay(200*8) + def test_large_data(self): + tb = OutputsTestbench() - def test_large_data(): + def test(): + yield from tb.init() correct_large_data = random.Random(0).randrange(2**512-1) - self.assertNotEqual((yield dut.phy2.received_data), correct_large_data) - delay(10*8) - yield from write(2, correct_large_data) - for i in range(45): - yield - self.assertEqual((yield dut.phy2.received_data), correct_large_data) + self.assertNotEqual((yield tb.dut.phy2.received_data), correct_large_data) + tb.delay(200) + yield from tb.write(2, correct_large_data) + yield from tb.sync() + self.assertEqual((yield tb.dut.phy2.received_data), correct_large_data) - def test_fifo_space(): - delay(200*8) + run_simulation(tb.dut, {"sys": test()}, self.clocks) + + def test_buffer_space(self): + tb = OutputsTestbench() + ttl_changes = [] + correct_ttl_changes = [(258 + 40*i, 0) for i in range(10)] + + def test(): + yield from tb.init() + tb.delay(250) max_wlen = 0 - for _ in range(3): - wlen = yield from write(0, 1) + for i in range(10): + wlen = yield from tb.write(0, (i + 1) % 2) max_wlen = max(max_wlen, wlen) - delay(40*8) - wlen = yield from write(0, 0) - max_wlen = max(max_wlen, wlen) - delay(40*8) - # check that some writes caused FIFO space requests + tb.delay(40) + # check that some writes caused buffer space requests self.assertGreater(max_wlen, 5) + yield from tb.sync() - def test_tsc_error(): + run_simulation(tb.dut, + {"sys": test(), "rtio": tb.check_ttls(ttl_changes)}, self.clocks) + self.assertEqual(ttl_changes, correct_ttl_changes) + + def test_tsc_error(self): + tb = OutputsTestbench() + + def test(): + saterr = tb.dut.satellite.rt_errors + csrs = tb.dut.master.rt_controller.csrs + yield from tb.init() errors = yield from saterr.protocol_error.read() self.assertEqual(errors, 0) yield from csrs.tsc_correction.write(100000000) yield from csrs.set_time.write(1) for i in range(15): yield - delay(10000*8) - yield from write(0, 1) + tb.delay(10000) + yield from tb.write(0, 1) for i in range(12): yield errors = yield from saterr.protocol_error.read() @@ -195,39 +230,7 @@ class TestFullStack(unittest.TestCase): errors = yield from saterr.protocol_error.read() self.assertEqual(errors, 0) - def wait_ttl_events(): - while len(ttl_changes) < len(correct_ttl_changes): - yield - - def test(): - while not (yield from dut.master.link_layer.link_status.read()): - yield - - yield from test_init() - yield from test_underflow() - yield from test_pulses() - yield from test_sequence_error() - yield from test_fifo_space() - yield from test_large_data() - yield from test_tsc_error() - yield from wait_ttl_events() - - @passive - def check_ttls(): - cycle = 0 - old_ttls = [0, 0] - while True: - ttls = [(yield dut.ttl0), (yield dut.ttl1)] - for n, (old_ttl, ttl) in enumerate(zip(old_ttls, ttls)): - if ttl != old_ttl: - ttl_changes.append((cycle, n)) - old_ttls = ttls - yield - cycle += 1 - - run_simulation(dut, - {"sys": test(), "rtio": check_ttls()}, self.clocks) - self.assertEqual(ttl_changes, correct_ttl_changes) + run_simulation(tb.dut, {"sys": test()}, self.clocks) def test_inputs(self): dut = DUT(2) @@ -250,8 +253,7 @@ class TestFullStack(unittest.TestCase): (yield from kcsrs.i_timestamp.read())) def test(): - # wait for link layer ready - for i in range(5): + while not (yield from dut.master.link_layer.link_status.read()): yield i1 = yield from get_input(10) @@ -269,7 +271,7 @@ class TestFullStack(unittest.TestCase): yield dut.phy2.rtlink.i.stb.eq(0) run_simulation(dut, - {"sys": test(), "rtio": generate_input()}, self.clocks, vcd_name="foo.vcd") + {"sys": test(), "rtio": generate_input()}, self.clocks) def test_echo(self): dut = DUT(2) From e430d04d3ffbb7636018632b0a3a535e7ad4a994 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 24 Sep 2017 12:49:21 +0800 Subject: [PATCH 0056/2457] drtio: remove obsolete import --- artiq/gateware/drtio/core.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index f2ecce9e4..213fb7a8a 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -6,8 +6,7 @@ from migen.genlib.cdc import ElasticBuffer from artiq.gateware.rtio.sed.core import * from artiq.gateware.rtio.input_collector import * from artiq.gateware.drtio import (link_layer, aux_controller, - rt_packet_satellite, rt_iobuffer_satellite, - rt_errors_satellite, + rt_packet_satellite, rt_errors_satellite, rt_packet_master, rt_controller_master) From 4112e403de6350d67343475f0b367878c4ce5980 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 26 Sep 2017 15:09:07 +0800 Subject: [PATCH 0057/2457] rtio/sed: latency compensation --- artiq/gateware/rtio/sed/core.py | 4 +- artiq/gateware/rtio/sed/lane_distributor.py | 62 +++++++++++++------ .../test/rtio/test_sed_lane_distributor.py | 3 +- 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/artiq/gateware/rtio/sed/core.py b/artiq/gateware/rtio/sed/core.py index df4e61b69..472eda626 100644 --- a/artiq/gateware/rtio/sed/core.py +++ b/artiq/gateware/rtio/sed/core.py @@ -31,7 +31,9 @@ class SED(Module): self.submodules.lane_dist = lane_dist_cdr( LaneDistributor(lane_count, seqn_width, - layouts.fifo_payload(channels), glbl_fine_ts_width, + layouts.fifo_payload(channels), + [channel.interface.o.delay for channel in channels], + glbl_fine_ts_width, enable_spread=enable_spread, quash_channels=quash_channels, interface=interface)) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index 436e59695..c0a7e6857 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -13,7 +13,8 @@ __all__ = ["LaneDistributor"] # 3. check status class LaneDistributor(Module): - def __init__(self, lane_count, seqn_width, layout_payload, glbl_fine_ts_width, + def __init__(self, lane_count, seqn_width, layout_payload, + compensation, glbl_fine_ts_width, enable_spread=True, quash_channels=[], interface=None): if lane_count & (lane_count - 1): raise NotImplementedError("lane count must be a power of 2") @@ -53,27 +54,20 @@ class LaneDistributor(Module): self.comb += lio.payload.data.eq(self.cri.o_data) # when timestamp and channel arrive in cycle #1, prepare computations - coarse_timestamp = Signal(64-glbl_fine_ts_width) + us_timestamp_width = 64 - glbl_fine_ts_width + coarse_timestamp = Signal(us_timestamp_width) self.comb += coarse_timestamp.eq(self.cri.timestamp[glbl_fine_ts_width:]) - timestamp_above_min = Signal() - timestamp_above_laneA_min = Signal() - timestamp_above_laneB_min = Signal() - force_laneB = Signal() - use_laneB = Signal() - use_lanen = Signal(max=lane_count) + min_minus_timestamp = Signal((us_timestamp_width + 1, True)) + laneAmin_minus_timestamp = Signal((us_timestamp_width + 1, True)) + laneBmin_minus_timestamp = Signal((us_timestamp_width + 1, True)) + last_minus_timestamp = Signal((us_timestamp_width + 1, True)) current_lane_plus_one = Signal(max=lane_count) self.comb += current_lane_plus_one.eq(current_lane + 1) self.sync += [ - timestamp_above_min.eq(coarse_timestamp > self.minimum_coarse_timestamp), - timestamp_above_laneA_min.eq(coarse_timestamp > last_lane_coarse_timestamps[current_lane]), - timestamp_above_laneB_min.eq(coarse_timestamp > last_lane_coarse_timestamps[current_lane_plus_one]), - If(force_laneB | (coarse_timestamp <= last_coarse_timestamp), - use_lanen.eq(current_lane + 1), - use_laneB.eq(1) - ).Else( - use_lanen.eq(current_lane), - use_laneB.eq(0) - ) + min_minus_timestamp.eq(self.minimum_coarse_timestamp - coarse_timestamp), + laneAmin_minus_timestamp.eq(last_lane_coarse_timestamps[current_lane] - coarse_timestamp), + laneBmin_minus_timestamp.eq(last_lane_coarse_timestamps[current_lane_plus_one] - coarse_timestamp), + last_minus_timestamp.eq(last_coarse_timestamp - coarse_timestamp) ] quash = Signal() @@ -81,12 +75,36 @@ class LaneDistributor(Module): for channel in quash_channels: self.sync += If(self.cri.chan_sel[:16] == channel, quash.eq(1)) + latency_compensation = Memory(14, len(compensation), init=compensation) + latency_compensation_port = latency_compensation.get_port() + self.specials += latency_compensation, latency_compensation_port + self.comb += latency_compensation_port.adr.eq(self.cri.chan_sel[:16]) + # cycle #2, write + compensation = latency_compensation_port.dat_r + timestamp_above_min = Signal() + timestamp_above_laneA_min = Signal() + timestamp_above_laneB_min = Signal() timestamp_above_lane_min = Signal() + force_laneB = Signal() + use_laneB = Signal() + use_lanen = Signal(max=lane_count) + do_write = Signal() do_underflow = Signal() do_sequence_error = Signal() self.comb += [ + timestamp_above_min.eq(min_minus_timestamp - compensation < 0), + timestamp_above_laneA_min.eq(laneAmin_minus_timestamp - compensation < 0), + timestamp_above_laneB_min.eq(laneBmin_minus_timestamp - compensation < 0), + If(force_laneB | (last_minus_timestamp - compensation >= 0), + use_lanen.eq(current_lane + 1), + use_laneB.eq(1) + ).Else( + use_lanen.eq(current_lane), + use_laneB.eq(0) + ), + timestamp_above_lane_min.eq(Mux(use_laneB, timestamp_above_laneB_min, timestamp_above_laneA_min)), If(~quash, do_write.eq((self.cri.cmd == cri.commands["write"]) & timestamp_above_min & timestamp_above_lane_min), @@ -95,14 +113,18 @@ class LaneDistributor(Module): ), Array(lio.we for lio in self.output)[use_lanen].eq(do_write) ] + compensated_timestamp = Signal(64) + self.comb += compensated_timestamp.eq(self.cri.timestamp + (compensation << glbl_fine_ts_width)) self.sync += [ If(do_write, If(use_laneB, current_lane.eq(current_lane + 1)), - last_coarse_timestamp.eq(coarse_timestamp), - last_lane_coarse_timestamps[use_lanen].eq(coarse_timestamp), + last_coarse_timestamp.eq(compensated_timestamp[glbl_fine_ts_width:]), + last_lane_coarse_timestamps[use_lanen].eq(compensated_timestamp[glbl_fine_ts_width:]), seqn.eq(seqn + 1), ) ] + for lio in self.output: + self.comb += lio.payload.timestamp.eq(compensated_timestamp) # cycle #3, read status current_lane_writable = Signal() diff --git a/artiq/gateware/test/rtio/test_sed_lane_distributor.py b/artiq/gateware/test/rtio/test_sed_lane_distributor.py index 4c57bc9c8..db57ae6cd 100644 --- a/artiq/gateware/test/rtio/test_sed_lane_distributor.py +++ b/artiq/gateware/test/rtio/test_sed_lane_distributor.py @@ -10,7 +10,8 @@ LANE_COUNT = 8 def simulate(input_events, wait=True): - dut = lane_distributor.LaneDistributor(LANE_COUNT, 8, [("channel", 8), ("timestamp", 32)], 3) + dut = lane_distributor.LaneDistributor(LANE_COUNT, 8, [("channel", 8), ("timestamp", 32)], + [0]*256, 3) output = [] access_results = [] From f079ac6af6bf755c642f9477f4a398fb67d13853 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 26 Sep 2017 16:10:52 +0800 Subject: [PATCH 0058/2457] rtio/sed: disable wait in TestLaneDistributor.test_regular --- artiq/gateware/test/rtio/test_sed_lane_distributor.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/gateware/test/rtio/test_sed_lane_distributor.py b/artiq/gateware/test/rtio/test_sed_lane_distributor.py index db57ae6cd..b369d711b 100644 --- a/artiq/gateware/test/rtio/test_sed_lane_distributor.py +++ b/artiq/gateware/test/rtio/test_sed_lane_distributor.py @@ -75,9 +75,8 @@ def simulate(input_events, wait=True): class TestLaneDistributor(unittest.TestCase): def test_regular(self): - # Assumes lane 0 does not have wait time. N = 16 - output, access_results = simulate([(42+n, (n+1)*8) for n in range(N)]) + output, access_results = simulate([(42+n, (n+1)*8) for n in range(N)], wait=False) self.assertEqual(output, [(0, n, 42+n, (n+1)*8) for n in range(N)]) self.assertEqual(access_results, [("ok", 0)]*N) From 9905b8723b11dfdad305d9a8c4e03bd060252380 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 26 Sep 2017 16:11:08 +0800 Subject: [PATCH 0059/2457] rtio/sed: support negative latency compensation --- artiq/gateware/rtio/sed/lane_distributor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index c0a7e6857..232c37ac6 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -81,7 +81,8 @@ class LaneDistributor(Module): self.comb += latency_compensation_port.adr.eq(self.cri.chan_sel[:16]) # cycle #2, write - compensation = latency_compensation_port.dat_r + compensation = Signal((14, True)) + self.comb += compensation.eq(latency_compensation_port.dat_r) timestamp_above_min = Signal() timestamp_above_laneA_min = Signal() timestamp_above_laneB_min = Signal() From e6f0ce3abad0ce5b39a1c1fb3a8732973a86394f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 26 Sep 2017 16:11:21 +0800 Subject: [PATCH 0060/2457] rtio/sed: test latency compensation --- .../test/rtio/test_sed_lane_distributor.py | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/test/rtio/test_sed_lane_distributor.py b/artiq/gateware/test/rtio/test_sed_lane_distributor.py index b369d711b..488d914a9 100644 --- a/artiq/gateware/test/rtio/test_sed_lane_distributor.py +++ b/artiq/gateware/test/rtio/test_sed_lane_distributor.py @@ -9,9 +9,11 @@ from artiq.gateware.rtio.sed import lane_distributor LANE_COUNT = 8 -def simulate(input_events, wait=True): - dut = lane_distributor.LaneDistributor(LANE_COUNT, 8, [("channel", 8), ("timestamp", 32)], - [0]*256, 3) +def simulate(input_events, compensation=None, wait=True): + layout = [("channel", 8), ("timestamp", 32)] + if compensation is None: + compensation = [0]*256 + dut = lane_distributor.LaneDistributor(LANE_COUNT, 8, layout, compensation, 3) output = [] access_results = [] @@ -122,3 +124,30 @@ class TestLaneDistributor(unittest.TestCase): output, access_results = simulate(input_events) self.assertEqual([o[0] for o in output], [x % LANE_COUNT for x in range(9)]) self.assertEqual([ar[0] for ar in access_results], ["ok"]*9) + + def test_regular_lc(self): + N = 16 + output, access_results = simulate([(n, 8) for n in range(N)], + compensation=range(N), wait=False) + self.assertEqual(output, [(0, n, n, (n+1)*8) for n in range(N)]) + self.assertEqual(access_results, [("ok", 0)]*N) + + def test_lane_switch_lc(self): + N = 32 + compensation = [n//2 for n in range(N)] + output, access_results = simulate([(n, 8) for n in range(N)], + compensation=compensation, wait=False) + self.assertEqual(output, [((n-n//2) % LANE_COUNT, n, n, 8*(1+n//2)) for n in range(N)]) + self.assertEqual([ar[0] for ar in access_results], ["ok"]*N) + + def test_underflow_lc(self): + N = 16 + compensation = [0]*N + input_events = [(n, (n+1)*8) for n in range(N)] + compensation[N-2] = -input_events[N-2][1]//8 + output, access_results = simulate(input_events, compensation=compensation) + self.assertEqual(len(output), len(input_events)-1) # event with underflow must get discarded + self.assertEqual([ar[0] for ar in access_results[:N-2]], ["ok"]*(N-2)) + self.assertEqual(access_results[N-2][0], "underflow") + self.assertEqual(output[N-2], (0, N-2, N-1, N*8)) + self.assertEqual(access_results[N-1][0], "ok") From d7ef07a0c256f9aeb7d0fc43a5f3c20ed58117e1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 26 Sep 2017 16:44:23 +0800 Subject: [PATCH 0061/2457] rtio/sed: document architecture --- artiq/gateware/rtio/sed/__init__.py | 57 +++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/artiq/gateware/rtio/sed/__init__.py b/artiq/gateware/rtio/sed/__init__.py index e69de29bb..d0055b52a 100644 --- a/artiq/gateware/rtio/sed/__init__.py +++ b/artiq/gateware/rtio/sed/__init__.py @@ -0,0 +1,57 @@ +""" +The traditional RTIO system used one dedicated FIFO per output channel. While this architecture +is simple and appropriate for ARTIQ systems that were rather small and simple, it shows limitations +on more complex ones. By decreasing importance: +* with DRTIO, the master needed to keep track, for each FIFO in each satellite, a lower bound on +the number of available entries plus the last timestamp written. The timestamp is stored in order +to detect sequence errors rapidly (and allow precise exceptions without compromising performance). +When many satellites are involved, especially with DRTIO switches, the storage requirements become +prohibitive. +* with many channels in one device, the large muxes and the error detection logic that +can handle all the FIFOs make timing closure problematic. +* with many channels in one device, the FIFOs waste FPGA space, as they are never all filled at the +same time. + +The scalable event dispatcher (SED) addresses those issues: +* only one lower bound on the available entries needs to be stored per satellite device for flow +control purposes (called "buffer space"). Most sequence errors no longer exist (non-increasing +timestamps into one channel are permitted to an extent) so rapid detection of them is no longer +required. +* the events can be demultiplexed to the different channels using pipeline stages that ease timing. +* only a few FIFOs are required and they are shared between the channels. + +The SED core contains a configurable number of FIFOs that hold the usual information about RTIO +events (timestamp, address, data), the channel number, and a sequence number. The sequence number is +increased for each event submitted. + +When an event is submitted, it is written into the current FIFO if its timestamp is strictly +increasing. Otherwise, the current FIFO number is incremented by one (and wraps around, if the +current FIFO was the last) and the event is written there, unless that FIFO already contains an +event with a greater timestamp. In that case, an asynchronous error is reported. If the destination +FIFO is full, the submitter is blocked. + +In order to help spreading events among FIFOs and maximize buffering, the SED core may optionally +also switch to the next FIFO after the current FIFO has been full. + +At the output of the FIFOs, the events are distributed to the channels and simultaneous events on +the same channel are handled using a structure similar to a odd-even merge-sort network that sorts +by channel. When there are simultaneous events on the same channel, the event with the highest +sequence number is kept and a flag is raised to indicate that a replacement occured on that +channel. If a replacement was made on a channel that has replacements disabled, the final +event is dropped and a collision error is reported asynchronously. + +Underflow errors are detected as before by comparing the event timestamp with the current value of +the counter, and dropping events that do not have enough time to make it through the system. + +The sequence number is sized to be able to represent the combined capacity of all FIFOs, plus +2 bits that allow the detection of wrap-arounds. + +The maximum number of simultaneous events (on different channels), and the maximum number of active +timeline "rewinds", are equal to the number of FIFOs. + +The SED logic support both synchronous and asynchronous FIFOs, which are used respectively for local +RTIO and DRTIO. + +To implement flow control in DRTIO, the master queries the satellite for buffer space. The satellite +uses as buffer space the space available in its fullest FIFO. +""" From 73043c34641b2910cf802bc7aeaaccda19ea25f9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 26 Sep 2017 16:46:09 +0800 Subject: [PATCH 0062/2457] drtio: disable SED lane spread Doesn't improve things as the buffer space would still be determined by the full FIFO, and adds unnecessary logic. --- artiq/gateware/drtio/core.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 213fb7a8a..0bda7ad38 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -91,7 +91,8 @@ class DRTIOSatellite(Module): self.submodules.outputs = ClockDomainsRenamer("rio")( SED(channels, fine_ts_width, "sync", lane_count=lane_count, fifo_depth=fifo_depth, - report_buffer_space=True, interface=self.rt_packet.cri)) + enable_spread=False, report_buffer_space=True, + interface=self.rt_packet.cri)) self.comb += self.outputs.coarse_timestamp.eq(coarse_ts) self.sync += self.outputs.minimum_coarse_timestamp.eq(coarse_ts + 16) From 4e31e9a9ac3c26fee24238e388fc55c04622f69f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 26 Sep 2017 17:13:02 +0800 Subject: [PATCH 0063/2457] test: relax test_rtio.test_loopback With SED there are 8 additional FIFO output stages. --- artiq/test/coredevice/test_rtio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index a120a94ec..086b964d8 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -362,7 +362,7 @@ class CoredeviceTest(ExperimentCase): rtt = self.dataset_mgr.get("rtt") print(rtt) self.assertGreater(rtt, 0*ns) - self.assertLess(rtt, 60*ns) + self.assertLess(rtt, 124*ns) def test_clock_generator_loopback(self): self.execute(ClockGeneratorLoopback) From 5437f0e3e36cabce5757b343db7d3b2a5bb5fbde Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 29 Sep 2017 14:40:06 +0800 Subject: [PATCH 0064/2457] rtio: make sequence errors consistently asychronous --- artiq/coredevice/__init__.py | 4 +- artiq/coredevice/comm_analyzer.py | 2 +- artiq/coredevice/exceptions.py | 13 +++--- artiq/firmware/ksupport/lib.rs | 19 +++----- artiq/firmware/ksupport/rtio.rs | 6 --- artiq/firmware/runtime/rtio_mgt.rs | 3 ++ artiq/gateware/drtio/rt_errors_satellite.py | 6 +-- artiq/gateware/rtio/analyzer.py | 4 -- artiq/gateware/rtio/core.py | 14 +++--- artiq/gateware/rtio/cri.py | 6 +-- artiq/gateware/rtio/dma.py | 45 ++++++++----------- artiq/gateware/rtio/sed/core.py | 16 +++++++ artiq/gateware/rtio/sed/lane_distributor.py | 14 +++--- artiq/gateware/test/drtio/test_full_stack.py | 2 - .../test/rtio/test_sed_lane_distributor.py | 2 +- artiq/gateware/test/rtio/test_sed_top.py | 2 +- artiq/test/coredevice/test_rtio.py | 28 +++++------- doc/manual/rtio.rst | 16 +++++++ 18 files changed, 102 insertions(+), 100 deletions(-) diff --git a/artiq/coredevice/__init__.py b/artiq/coredevice/__init__.py index 70539315d..0a1a4de6c 100644 --- a/artiq/coredevice/__init__.py +++ b/artiq/coredevice/__init__.py @@ -1,9 +1,9 @@ from artiq.coredevice import exceptions, dds, spi -from artiq.coredevice.exceptions import (RTIOUnderflow, RTIOSequenceError, RTIOOverflow) +from artiq.coredevice.exceptions import (RTIOUnderflow, RTIOOverflow) from artiq.coredevice.dds import (PHASE_MODE_CONTINUOUS, PHASE_MODE_ABSOLUTE, PHASE_MODE_TRACKING) __all__ = [] -__all__ += ["RTIOUnderflow", "RTIOSequenceError", "RTIOOverflow"] +__all__ += ["RTIOUnderflow", "RTIOOverflow"] __all__ += ["PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE", "PHASE_MODE_TRACKING"] diff --git a/artiq/coredevice/comm_analyzer.py b/artiq/coredevice/comm_analyzer.py index d8b6e0434..f4b2d56f0 100644 --- a/artiq/coredevice/comm_analyzer.py +++ b/artiq/coredevice/comm_analyzer.py @@ -27,9 +27,9 @@ class ExceptionType(Enum): legacy_o_sequence_error_reset = 0b010001 legacy_o_collision_reset = 0b010010 legacy_i_overflow_reset = 0b100000 + legacy_o_sequence_error = 0b010101 o_underflow = 0b010100 - o_sequence_error = 0b010101 i_overflow = 0b100001 diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index 44d0af86e..de86baf25 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -78,13 +78,6 @@ class RTIOUnderflow(Exception): """ artiq_builtin = True -class RTIOSequenceError(Exception): - """Raised when an event is submitted on a given channel with a timestamp - not larger than the previous one. - - The offending event is discarded and the RTIO core keeps operating. - """ - artiq_builtin = True class RTIOOverflow(Exception): """Raised when at least one event could not be registered into the RTIO @@ -96,26 +89,32 @@ class RTIOOverflow(Exception): """ artiq_builtin = True + class DMAError(Exception): """Raised when performing an invalid DMA operation.""" artiq_builtin = True + class DDSError(Exception): """Raised when attempting to start a DDS batch while already in a batch, when too many commands are batched, and when DDS channel settings are incorrect. """ + class WatchdogExpired(Exception): """Raised when a watchdog expires.""" + class ClockFailure(Exception): """Raised when RTIO PLL has lost lock.""" + class I2CError(Exception): """Raised when a I2C transaction fails.""" pass + class SPIError(Exception): """Raised when a SPI transaction fails.""" pass diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 2f06b0118..8d3d8bf7c 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -380,22 +380,13 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { while csr::rtio_dma::enable_read() != 0 {} csr::cri_con::selected_write(0); - let status = csr::rtio_dma::error_status_read(); - if status != 0 { + if csr::rtio_dma::underflow_read() != 0 { let timestamp = csr::rtio_dma::error_timestamp_read(); let channel = csr::rtio_dma::error_channel_read(); - if status & rtio::RTIO_O_STATUS_UNDERFLOW != 0 { - csr::rtio_dma::error_underflow_reset_write(1); - raise!("RTIOUnderflow", - "RTIO underflow at {0} mu, channel {1}", - timestamp as i64, channel as i64, 0) - } - if status & rtio::RTIO_O_STATUS_SEQUENCE_ERROR != 0 { - csr::rtio_dma::error_sequence_error_reset_write(1); - raise!("RTIOSequenceError", - "RTIO sequence error at {0} mu, channel {1}", - timestamp as i64, channel as i64, 0) - } + csr::rtio_dma::underflow_write(1); + raise!("RTIOUnderflow", + "RTIO underflow at {0} mu, channel {1}", + timestamp as i64, channel as i64, 0) } } } diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index e03b2ea4c..feeb7890f 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -6,7 +6,6 @@ use kernel_proto::*; pub const RTIO_O_STATUS_WAIT: u8 = 1; pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2; -pub const RTIO_O_STATUS_SEQUENCE_ERROR: u8 = 4; pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1; pub const RTIO_I_STATUS_OVERFLOW: u8 = 2; pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4; @@ -45,11 +44,6 @@ unsafe fn process_exceptional_status(timestamp: i64, channel: i32, status: u8) { "RTIO underflow at {0} mu, channel {1}, slack {2} mu", timestamp, channel as i64, timestamp - get_counter()) } - if status & RTIO_O_STATUS_SEQUENCE_ERROR != 0 { - raise!("RTIOSequenceError", - "RTIO sequence error at {0} mu, channel {1}", - timestamp, channel as i64, 0) - } } pub extern fn output(timestamp: i64, channel: i32, addr: i32, data: i32) { diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index c411295f4..992a62bb3 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -195,6 +195,9 @@ fn async_error_thread(io: Io) { if errors & 2 != 0 { error!("RTIO busy"); } + if errors & 4 != 0 { + error!("RTIO sequence error"); + } csr::rtio_core::async_error_write(errors); } } diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index 173dd7dcf..9b3ab00a0 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -35,11 +35,9 @@ class RTErrorsSatellite(Module, AutoCSR): # internal ARTIQ bugs. underflow = Signal() overflow = Signal() - sequence_error = Signal() self.comb += [ underflow.eq(outputs.cri.o_status[1]), - overflow.eq(outputs.cri.o_status[0]), - sequence_error.eq(outputs.cri.o_status[2]) + overflow.eq(outputs.cri.o_status[0]) ] error_csr(self.protocol_error, (rt_packet.unknown_packet_type, False), @@ -48,7 +46,7 @@ class RTErrorsSatellite(Module, AutoCSR): (overflow, True) ) error_csr(self.rtio_error, - (sequence_error, True), + (outputs.sequence_error, False), (outputs.collision, False), (outputs.busy, False) ) diff --git a/artiq/gateware/rtio/analyzer.py b/artiq/gateware/rtio/analyzer.py index 2461f80c1..f958ca8d6 100644 --- a/artiq/gateware/rtio/analyzer.py +++ b/artiq/gateware/rtio/analyzer.py @@ -94,10 +94,6 @@ class MessageEncoder(Module, AutoCSR): exception_stb.eq(1), exception.exception_type.eq(ExceptionType.o_underflow.value) ), - If(just_written & cri.o_status[2], - exception_stb.eq(1), - exception.exception_type.eq(ExceptionType.o_sequence_error.value) - ), If(read_overflow, exception_stb.eq(1), exception.exception_type.eq(ExceptionType.i_overflow.value) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 8305db821..c77d5084d 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -19,7 +19,7 @@ class Core(Module, AutoCSR): self.cri = cri.Interface() self.reset = CSR() self.reset_phy = CSR() - self.async_error = CSR(2) + self.async_error = CSR(3) # Clocking/Reset # Create rsys, rio and rio_phy domains based on sys and rtio @@ -75,18 +75,21 @@ class Core(Module, AutoCSR): o_collision_sync = BlindTransfer() o_busy_sync = BlindTransfer() self.submodules += o_collision_sync, o_busy_sync + o_sequence_error_trig = Signal() o_collision = Signal() o_busy = Signal() + o_sequence_error = Signal() self.sync += [ If(self.async_error.re, If(self.async_error.r[0], o_collision.eq(0)), If(self.async_error.r[1], o_busy.eq(0)), + If(self.async_error.r[2], o_sequence_error.eq(0)), ), If(o_collision_sync.o, o_collision.eq(1)), - If(o_busy_sync.o, o_busy.eq(1)) + If(o_busy_sync.o, o_busy.eq(1)), + If(o_sequence_error_trig, o_sequence_error.eq(1)) ] - self.comb += self.async_error.w.eq(Cat(o_collision, o_busy)) - + self.comb += self.async_error.w.eq(Cat(o_collision, o_busy, o_sequence_error)) # Outputs/Inputs quash_channels = [n for n, c in enumerate(channels) if isinstance(c, LogChannel)] @@ -100,7 +103,8 @@ class Core(Module, AutoCSR): self.sync += outputs.minimum_coarse_timestamp.eq(coarse_ts + 16) self.comb += [ o_collision_sync.i.eq(outputs.collision), - o_busy_sync.i.eq(outputs.busy) + o_busy_sync.i.eq(outputs.busy), + o_sequence_error_trig.eq(outputs.sequence_error) ] inputs = InputCollector(channels, glbl_fine_ts_width, "async", diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 5dad6b886..4885c0219 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -25,8 +25,8 @@ layout = [ ("o_data", 512, DIR_M_TO_S), ("o_address", 16, DIR_M_TO_S), # o_status bits: - # <0:wait> <1:underflow> <2:sequence_error> - ("o_status", 3, DIR_S_TO_M), + # <0:wait> <1:underflow> + ("o_status", 2, DIR_S_TO_M), # targets may optionally report a pessimistic estimate of the number # of outputs events that can be written without waiting. ("o_buffer_space", 16, DIR_S_TO_M), @@ -61,7 +61,7 @@ class KernelInitiator(Module, AutoCSR): self.o_data = CSRStorage(512, write_from_dev=True) self.o_address = CSRStorage(16) self.o_we = CSR() - self.o_status = CSRStatus(3) + self.o_status = CSRStatus(2) self.i_data = CSRStatus(32) self.i_timestamp = CSRStatus(64) diff --git a/artiq/gateware/rtio/dma.py b/artiq/gateware/rtio/dma.py index ecfb3b5f5..0ea364ef8 100644 --- a/artiq/gateware/rtio/dma.py +++ b/artiq/gateware/rtio/dma.py @@ -242,9 +242,7 @@ class TimeOffset(Module, AutoCSR): class CRIMaster(Module, AutoCSR): def __init__(self): - self.error_status = CSRStatus(3) # same encoding as RTIO status - self.error_underflow_reset = CSR() - self.error_sequence_error_reset = CSR() + self.underflow = CSR() self.error_channel = CSRStatus(24) self.error_timestamp = CSRStatus(64) @@ -256,19 +254,16 @@ class CRIMaster(Module, AutoCSR): # # # - error_set = Signal(2) - for i, rcsr in enumerate([self.error_underflow_reset, self.error_sequence_error_reset]): - # bit 0 is RTIO wait and always 0 here - bit = i + 1 - self.sync += [ - If(error_set[i], - self.error_status.status[bit].eq(1), - self.error_channel.status.eq(self.sink.channel), - self.error_timestamp.status.eq(self.sink.timestamp), - self.error_address.status.eq(self.sink.address) - ), - If(rcsr.re, self.error_status.status[bit].eq(0)) - ] + underflow_trigger = Signal(2) + self.sync += [ + If(underflow_trigger, + self.underflow.w.eq(1), + self.error_channel.status.eq(self.sink.channel), + self.error_timestamp.status.eq(self.sink.timestamp), + self.error_address.status.eq(self.sink.address) + ), + If(self.underflow.re, self.underflow.w.eq(0)) + ] self.comb += [ self.cri.chan_sel.eq(self.sink.channel), @@ -281,7 +276,7 @@ class CRIMaster(Module, AutoCSR): self.submodules += fsm fsm.act("IDLE", - If(self.error_status.status == 0, + If(~self.underflow.w, If(self.sink.stb, If(self.sink.eop, # last packet contains dummy data, discard it @@ -306,16 +301,14 @@ class CRIMaster(Module, AutoCSR): self.sink.ack.eq(1), NextState("IDLE") ), - If(self.cri.o_status[1], NextState("UNDERFLOW")), - If(self.cri.o_status[2], NextState("SEQUENCE_ERROR")) + If(self.cri.o_status[1], NextState("UNDERFLOW")) + ) + fsm.act("UNDERFLOW", + self.busy.eq(1), + underflow_trigger.eq(1), + self.sink.ack.eq(1), + NextState("IDLE") ) - for n, name in enumerate(["UNDERFLOW", "SEQUENCE_ERROR"]): - fsm.act(name, - self.busy.eq(1), - error_set.eq(1 << n), - self.sink.ack.eq(1), - NextState("IDLE") - ) class DMA(Module): diff --git a/artiq/gateware/rtio/sed/core.py b/artiq/gateware/rtio/sed/core.py index 472eda626..ca757e976 100644 --- a/artiq/gateware/rtio/sed/core.py +++ b/artiq/gateware/rtio/sed/core.py @@ -61,26 +61,42 @@ class SED(Module): def cri(self): return self.lane_dist.cri + # in CRI clock domain @property def minimum_coarse_timestamp(self): return self.lane_dist.minimum_coarse_timestamp + # in I/O clock domain @property def coarse_timestamp(self): return self.gates.coarse_timestamp + # in CRI clock domain + @property + def sequence_error(self): + return self.lane_dist.sequence_error + + # in CRI clock domain + @property + def sequence_error_channel(self): + return self.lane_dist.sequence_error_channel + + # in I/O clock domain @property def collision(self): return self.output_driver.collision + # in I/O clock domain @property def collision_channel(self): return self.output_driver.collision_channel + # in I/O clock domain @property def busy(self): return self.output_driver.busy + # in I/O clock domain @property def busy_channel(self): return self.output_driver.busy_channel diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index 232c37ac6..d6e346c9a 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -22,6 +22,8 @@ class LaneDistributor(Module): if interface is None: interface = cri.Interface() self.cri = interface + self.sequence_error = Signal() + self.sequence_error_channel = Signal(16) self.minimum_coarse_timestamp = Signal(64-glbl_fine_ts_width) self.output = [Record(layouts.fifo_ingress(seqn_width, layout_payload)) for _ in range(lane_count)] @@ -30,9 +32,7 @@ class LaneDistributor(Module): o_status_wait = Signal() o_status_underflow = Signal() - o_status_sequence_error = Signal() - self.comb += self.cri.o_status.eq(Cat(o_status_wait, o_status_underflow, - o_status_sequence_error)) + self.comb += self.cri.o_status.eq(Cat(o_status_wait, o_status_underflow)) # internal state current_lane = Signal(max=lane_count) @@ -135,15 +135,13 @@ class LaneDistributor(Module): ] self.sync += [ If(self.cri.cmd == cri.commands["write"], - o_status_underflow.eq(0), - o_status_sequence_error.eq(0) + o_status_underflow.eq(0) ), If(do_underflow, o_status_underflow.eq(1) ), - If(do_sequence_error, - o_status_sequence_error.eq(1) - ) + self.sequence_error.eq(do_sequence_error), + self.sequence_error_channel.eq(self.cri.chan_sel[:16]) ] # current lane has been full, spread events by switching to the next. diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 3b1281005..23810321c 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -111,8 +111,6 @@ class OutputsTestbench: status = yield from kcsrs.o_status.read() if status & 2: raise RTIOUnderflow - if status & 4: - raise RTIOSequenceError yield wlen += 1 return wlen diff --git a/artiq/gateware/test/rtio/test_sed_lane_distributor.py b/artiq/gateware/test/rtio/test_sed_lane_distributor.py index 488d914a9..c02b6c4bb 100644 --- a/artiq/gateware/test/rtio/test_sed_lane_distributor.py +++ b/artiq/gateware/test/rtio/test_sed_lane_distributor.py @@ -38,7 +38,7 @@ def simulate(input_events, compensation=None, wait=True): access_status = "ok" if status & 0x02: access_status = "underflow" - if status & 0x04: + if (yield dut.sequence_error): access_status = "sequence_error" access_results.append((access_status, access_time)) diff --git a/artiq/gateware/test/rtio/test_sed_top.py b/artiq/gateware/test/rtio/test_sed_top.py index eeb4c46a8..d5de88979 100644 --- a/artiq/gateware/test/rtio/test_sed_top.py +++ b/artiq/gateware/test/rtio/test_sed_top.py @@ -56,7 +56,7 @@ def simulate(input_events): access_status = "ok" if status & 0x02: access_status = "underflow" - if status & 0x04: + if (yield dut.sed.sequence_error): access_status = "sequence_error" access_results.append((access_status, access_time)) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 086b964d8..79043c9b8 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -401,27 +401,23 @@ class CoredeviceTest(ExperimentCase): with self.assertRaises(RTIOUnderflow): self.execute(Underflow) + def execute_and_test_in_log(self, experiment, string): + core_addr = self.device_mgr.get_desc("core")["arguments"]["host"] + mgmt = CommMgmt(core_addr) + mgmt.clear_log() + self.execute(experiment) + log = mgmt.get_log() + self.assertIn(string, log) + mgmt.close() + def test_sequence_error(self): - with self.assertRaises(RTIOSequenceError): - self.execute(SequenceError) + self.execute_and_test_in_log(SequenceError, "RTIO sequence error") def test_collision(self): - core_addr = self.device_mgr.get_desc("core")["arguments"]["host"] - mgmt = CommMgmt(core_addr) - mgmt.clear_log() - self.execute(Collision) - log = mgmt.get_log() - self.assertIn("RTIO collision", log) - mgmt.close() + self.execute_and_test_in_log(Collision, "RTIO collision") def test_address_collision(self): - core_addr = self.device_mgr.get_desc("core")["arguments"]["host"] - mgmt = CommMgmt(core_addr) - mgmt.clear_log() - self.execute(AddressCollision) - log = mgmt.get_log() - self.assertIn("RTIO collision", log) - mgmt.close() + self.execute_and_test_in_log(AddressCollision, "RTIO collision") def test_watchdog(self): # watchdog only works on the device diff --git a/doc/manual/rtio.rst b/doc/manual/rtio.rst index a08edad32..f62c3b57d 100644 --- a/doc/manual/rtio.rst +++ b/doc/manual/rtio.rst @@ -117,6 +117,22 @@ To track down ``RTIOUnderflows`` in an experiment there are a few approaches: code. * The :any:`integrated logic analyzer ` shows the timeline context that lead to the exception. The analyzer is always active and supports plotting of RTIO slack. RTIO slack is the difference between timeline cursor and wall clock time (``now - rtio_counter``). +Sequence errors +--------------- +A sequence error happens when the sequence of coarse timestamps cannot be supported by the gateware. For example, there may have been too many timeline rewinds. + +Internally, the gateware stores output events in an array of FIFO buffers (the "lanes") and the timestamps in each lane much be strictly increasing. The gateware selects a different lane when an event with a decreasing or equal timestamp is submitted. A sequence error occurs when no appropriate lane can be found. + +Notes: + +* Strictly increasing timestamps never cause sequence errors. +* Configuring the gateware with more lanes for the RTIO core reduces the frequency of sequence errors. +* Whether a particular sequence of timestamps causes a sequence error or not is fully deterministic (starting from a known RTIO state, e.g. after a reset). Adding a constant offset to the whole sequence does not affect the result. + +The offending event is discarded and the RTIO core keeps operating. + +This error is reported asynchronously via the core device log: for performance reasons with DRTIO, the CPU does not wait for an error report from the satellite after writing an event. Therefore, it is not possible to raise an exception precisely. + Collisions ---------- A collision happens when more than one event is submitted on a given channel with the same coarse timestamp, and that channel does not implement replacement behavior or the fine timestamps are different. From 6c049ad40ccf172137a76a8b8ae843fc0ab282b7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 29 Sep 2017 16:32:57 +0800 Subject: [PATCH 0065/2457] rtio: report channel numbers in asynchronous errors --- artiq/firmware/libdrtioaux/lib.rs | 33 +++++++--- artiq/firmware/runtime/rtio_mgt.rs | 21 ++++--- artiq/firmware/satman/lib.rs | 12 +++- artiq/gateware/drtio/rt_errors_satellite.py | 37 ++++++++--- artiq/gateware/rtio/cdc.py | 14 ++++- artiq/gateware/rtio/core.py | 69 +++++++++++++-------- 6 files changed, 129 insertions(+), 57 deletions(-) diff --git a/artiq/firmware/libdrtioaux/lib.rs b/artiq/firmware/libdrtioaux/lib.rs index 51ff8faa8..46be40b34 100644 --- a/artiq/firmware/libdrtioaux/lib.rs +++ b/artiq/firmware/libdrtioaux/lib.rs @@ -21,9 +21,9 @@ pub enum Packet { RtioErrorRequest, RtioNoErrorReply, - RtioErrorSequenceErrorReply, - RtioErrorCollisionReply, - RtioErrorBusyReply, + RtioErrorSequenceErrorReply { channel: u16 }, + RtioErrorCollisionReply { channel: u16 }, + RtioErrorBusyReply { channel: u16 }, MonitorRequest { channel: u16, probe: u8 }, MonitorReply { value: u32 }, @@ -56,9 +56,15 @@ impl Packet { 0x20 => Packet::RtioErrorRequest, 0x21 => Packet::RtioNoErrorReply, - 0x22 => Packet::RtioErrorSequenceErrorReply, - 0x23 => Packet::RtioErrorCollisionReply, - 0x24 => Packet::RtioErrorBusyReply, + 0x22 => Packet::RtioErrorSequenceErrorReply { + channel: read_u16(reader)? + }, + 0x23 => Packet::RtioErrorCollisionReply { + channel: read_u16(reader)? + }, + 0x24 => Packet::RtioErrorBusyReply { + channel: read_u16(reader)? + }, 0x40 => Packet::MonitorRequest { channel: read_u16(reader)?, @@ -147,9 +153,18 @@ impl Packet { Packet::RtioErrorRequest => write_u8(writer, 0x20)?, Packet::RtioNoErrorReply => write_u8(writer, 0x21)?, - Packet::RtioErrorSequenceErrorReply => write_u8(writer, 0x22)?, - Packet::RtioErrorCollisionReply => write_u8(writer, 0x23)?, - Packet::RtioErrorBusyReply => write_u8(writer, 0x24)?, + Packet::RtioErrorSequenceErrorReply { channel } => { + write_u8(writer, 0x22)?; + write_u16(writer, channel)?; + }, + Packet::RtioErrorCollisionReply { channel } => { + write_u8(writer, 0x23)?; + write_u16(writer, channel)?; + }, + Packet::RtioErrorBusyReply { channel } => { + write_u8(writer, 0x24)?; + write_u16(writer, channel)?; + }, Packet::MonitorRequest { channel, probe } => { write_u8(writer, 0x40)?; diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 992a62bb3..fe3697e6f 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -129,12 +129,12 @@ pub mod drtio { drtioaux::hw::send_link(linkno, &drtioaux::Packet::RtioErrorRequest).unwrap(); match drtioaux::hw::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::RtioNoErrorReply) => (), - Ok(drtioaux::Packet::RtioErrorSequenceErrorReply) => - error!("[LINK#{}] RTIO sequence error", linkno), - Ok(drtioaux::Packet::RtioErrorCollisionReply) => - error!("[LINK#{}] RTIO collision", linkno), - Ok(drtioaux::Packet::RtioErrorBusyReply) => - error!("[LINK#{}] RTIO busy", linkno), + Ok(drtioaux::Packet::RtioErrorSequenceErrorReply { channel }) => + error!("[LINK#{}] RTIO sequence error involving channel {}", linkno, channel), + Ok(drtioaux::Packet::RtioErrorCollisionReply { channel }) => + error!("[LINK#{}] RTIO collision involving channel {}", linkno, channel), + Ok(drtioaux::Packet::RtioErrorBusyReply { channel }) => + error!("[LINK#{}] RTIO busy error involving channel {}", linkno, channel), Ok(_) => error!("[LINK#{}] received unexpected aux packet", linkno), Err(e) => error!("[LINK#{}] aux packet error ({})", linkno, e) } @@ -190,13 +190,16 @@ fn async_error_thread(io: Io) { io.until(|| csr::rtio_core::async_error_read() != 0).unwrap(); let errors = csr::rtio_core::async_error_read(); if errors & 1 != 0 { - error!("RTIO collision"); + error!("RTIO collision involving channel {}", + csr::rtio_core::collision_channel_read()); } if errors & 2 != 0 { - error!("RTIO busy"); + error!("RTIO busy error involving channel {}", + csr::rtio_core::busy_channel_read()); } if errors & 4 != 0 { - error!("RTIO sequence error"); + error!("RTIO sequence error involving channel {}", + csr::rtio_core::sequence_error_channel_read()); } csr::rtio_core::async_error_write(errors); } diff --git a/artiq/firmware/satman/lib.rs b/artiq/firmware/satman/lib.rs index 4df701b4d..7620c33c8 100644 --- a/artiq/firmware/satman/lib.rs +++ b/artiq/firmware/satman/lib.rs @@ -23,20 +23,26 @@ fn process_aux_packet(p: &drtioaux::Packet) { errors = (board::csr::DRTIO[0].rtio_error_read)(); } if errors & 1 != 0 { + let channel; unsafe { + channel = (board::csr::DRTIO[0].sequence_error_channel_read)(); (board::csr::DRTIO[0].rtio_error_write)(1); } - drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorSequenceErrorReply).unwrap(); + drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorSequenceErrorReply { channel: channel }).unwrap(); } else if errors & 2 != 0 { + let channel; unsafe { + channel = (board::csr::DRTIO[0].collision_channel_read)(); (board::csr::DRTIO[0].rtio_error_write)(2); } - drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorCollisionReply).unwrap(); + drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorCollisionReply { channel: channel }).unwrap(); } else if errors & 4 != 0 { + let channel; unsafe { + channel = (board::csr::DRTIO[0].busy_channel_read)(); (board::csr::DRTIO[0].rtio_error_write)(4); } - drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorBusyReply).unwrap(); + drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorBusyReply { channel: channel }).unwrap(); } else { drtioaux::hw::send_link(0, &drtioaux::Packet::RtioNoErrorReply).unwrap(); diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index 9b3ab00a0..bf6e9a3d9 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -10,25 +10,39 @@ class RTErrorsSatellite(Module, AutoCSR): def __init__(self, rt_packet, outputs): self.protocol_error = CSR(4) self.rtio_error = CSR(3) + self.sequence_error_channel = CSRStatus(16) + self.collision_channel = CSRStatus(16) + self.busy_channel = CSRStatus(16) def error_csr(csr, *sources): - for n, (source, detect_edges) in enumerate(sources): + for n, (source, detect_edges, din, dout) in enumerate(sources): assert isinstance(source, Signal) - pending = Signal(related=source) - xfer = BlindTransfer(odomain="sys") + + if din is not None: + data_width = len(din) + else: + data_width = 0 + xfer = BlindTransfer(odomain="sys", data_width=data_width) self.submodules += xfer + if detect_edges: source_r = Signal() self.sync.rio += source_r.eq(source) self.comb += xfer.i.eq(source & source_r) else: self.comb += xfer.i.eq(source) + + pending = Signal(related=source) self.sync += [ If(csr.re & csr.r[n], pending.eq(0)), If(xfer.o, pending.eq(1)) ] self.comb += csr.w[n].eq(pending) + if din is not None: + self.comb += xfer.data_i.eq(din) + self.sync += If(xfer.o & ~pending, dout.eq(xfer.data_o)) + # The master is normally responsible for avoiding output overflows # and output underflows. The error reports here are only for diagnosing @@ -40,13 +54,16 @@ class RTErrorsSatellite(Module, AutoCSR): overflow.eq(outputs.cri.o_status[0]) ] error_csr(self.protocol_error, - (rt_packet.unknown_packet_type, False), - (rt_packet.packet_truncated, False), - (underflow, True), - (overflow, True) + (rt_packet.unknown_packet_type, False, None, None), + (rt_packet.packet_truncated, False, None, None), + (underflow, True, None, None), + (overflow, True, None, None) ) error_csr(self.rtio_error, - (outputs.sequence_error, False), - (outputs.collision, False), - (outputs.busy, False) + (outputs.sequence_error, False, + outputs.sequence_error_channel, self.sequence_error_channel.status), + (outputs.collision, False, + outputs.collision_channel, self.collision_channel.status), + (outputs.busy, False, + outputs.busy_channel, self.busy_channel.status) ) diff --git a/artiq/gateware/rtio/cdc.py b/artiq/gateware/rtio/cdc.py index 493b1e2e8..e5f75fba3 100644 --- a/artiq/gateware/rtio/cdc.py +++ b/artiq/gateware/rtio/cdc.py @@ -29,9 +29,14 @@ class GrayCodeTransfer(Module): class BlindTransfer(Module): - def __init__(self, idomain="rio", odomain="rsys"): + def __init__(self, idomain="rio", odomain="rsys", data_width=0): self.i = Signal() self.o = Signal() + if data_width: + self.data_i = Signal(data_width) + self.data_o = Signal(data_width) + + # # # ps = PulseSynchronizer(idomain, odomain) ps_ack = PulseSynchronizer(odomain, idomain) @@ -47,3 +52,10 @@ class BlindTransfer(Module): ps_ack.i.eq(ps.o), self.o.eq(ps.o) ] + + if data_width: + bxfer_data = Signal(data_width) + isync += If(ps.i, bxfer_data.eq(self.data_i)) + bxfer_data.attr.add("no_retiming") + self.specials += MultiReg(bxfer_data, self.data_o, + odomain=odomain) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index c77d5084d..c2bee2947 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -20,6 +20,9 @@ class Core(Module, AutoCSR): self.reset = CSR() self.reset_phy = CSR() self.async_error = CSR(3) + self.collision_channel = CSRStatus(16) + self.busy_channel = CSRStatus(16) + self.sequence_error_channel = CSRStatus(16) # Clocking/Reset # Create rsys, rio and rio_phy domains based on sys and rtio @@ -71,26 +74,6 @@ class Core(Module, AutoCSR): self.cri.counter.eq(coarse_ts_cdc.o << glbl_fine_ts_width) ] - # Asychronous output errors - o_collision_sync = BlindTransfer() - o_busy_sync = BlindTransfer() - self.submodules += o_collision_sync, o_busy_sync - o_sequence_error_trig = Signal() - o_collision = Signal() - o_busy = Signal() - o_sequence_error = Signal() - self.sync += [ - If(self.async_error.re, - If(self.async_error.r[0], o_collision.eq(0)), - If(self.async_error.r[1], o_busy.eq(0)), - If(self.async_error.r[2], o_sequence_error.eq(0)), - ), - If(o_collision_sync.o, o_collision.eq(1)), - If(o_busy_sync.o, o_busy.eq(1)), - If(o_sequence_error_trig, o_sequence_error.eq(1)) - ] - self.comb += self.async_error.w.eq(Cat(o_collision, o_busy, o_sequence_error)) - # Outputs/Inputs quash_channels = [n for n, c in enumerate(channels) if isinstance(c, LogChannel)] @@ -101,14 +84,50 @@ class Core(Module, AutoCSR): self.submodules += outputs self.comb += outputs.coarse_timestamp.eq(coarse_ts) self.sync += outputs.minimum_coarse_timestamp.eq(coarse_ts + 16) - self.comb += [ - o_collision_sync.i.eq(outputs.collision), - o_busy_sync.i.eq(outputs.busy), - o_sequence_error_trig.eq(outputs.sequence_error) - ] inputs = InputCollector(channels, glbl_fine_ts_width, "async", quash_channels=quash_channels, interface=self.cri) self.submodules += inputs self.comb += inputs.coarse_timestamp.eq(coarse_ts) + + # Asychronous output errors + o_collision_sync = BlindTransfer(data_width=16) + o_busy_sync = BlindTransfer(data_width=16) + self.submodules += o_collision_sync, o_busy_sync + o_collision = Signal() + o_busy = Signal() + o_sequence_error = Signal() + self.sync += [ + If(self.async_error.re, + If(self.async_error.r[0], o_collision.eq(0)), + If(self.async_error.r[1], o_busy.eq(0)), + If(self.async_error.r[2], o_sequence_error.eq(0)), + ), + If(o_collision_sync.o, + o_collision.eq(1), + If(~o_collision, + self.collision_channel.status.eq(o_collision_sync.data_o) + ) + ), + If(o_busy_sync.o, + o_busy.eq(1), + If(~o_busy, + self.busy_channel.status.eq(o_busy_sync.data_o) + ) + ), + If(outputs.sequence_error, + o_sequence_error.eq(1), + If(~o_sequence_error, + self.sequence_error_channel.status.eq(outputs.sequence_error_channel) + ) + ) + ] + self.comb += self.async_error.w.eq(Cat(o_collision, o_busy, o_sequence_error)) + + self.comb += [ + o_collision_sync.i.eq(outputs.collision), + o_collision_sync.data_i.eq(outputs.collision_channel), + o_busy_sync.i.eq(outputs.busy), + o_busy_sync.data_i.eq(outputs.busy_channel) + ] From 5f083f21a4c1eb58726fe0ba2fbbb431645d743e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 8 Oct 2017 22:37:46 +0800 Subject: [PATCH 0066/2457] rtio/dma: fix signal width --- artiq/gateware/rtio/dma.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/dma.py b/artiq/gateware/rtio/dma.py index 0ea364ef8..a8b7c9195 100644 --- a/artiq/gateware/rtio/dma.py +++ b/artiq/gateware/rtio/dma.py @@ -254,7 +254,7 @@ class CRIMaster(Module, AutoCSR): # # # - underflow_trigger = Signal(2) + underflow_trigger = Signal() self.sync += [ If(underflow_trigger, self.underflow.w.eq(1), From a9c9d5779d08e15a8bc3b47f59d53c3ffb5dc697 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 8 Oct 2017 22:38:02 +0800 Subject: [PATCH 0067/2457] rtio/dma: add full-stack test with connection to RTIO core --- artiq/gateware/test/rtio/test_dma.py | 83 ++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 11 deletions(-) diff --git a/artiq/gateware/test/rtio/test_dma.py b/artiq/gateware/test/rtio/test_dma.py index 759fe60b0..8f84b37d9 100644 --- a/artiq/gateware/test/rtio/test_dma.py +++ b/artiq/gateware/test/rtio/test_dma.py @@ -1,10 +1,13 @@ import unittest import random +import itertools from migen import * from misoc.interconnect import wishbone +from artiq.gateware import rtio from artiq.gateware.rtio import dma, cri +from artiq.gateware.rtio.phy import ttl_simple def encode_n(n, min_length, max_length): @@ -47,6 +50,14 @@ def encode_sequence(writes, ws): return pack(sequence, ws) +def do_dma(dut, address): + yield from dut.dma.base_address.write(address) + yield from dut.enable.write(1) + yield + while ((yield from dut.enable.read())): + yield + + test_writes1 = [ (0x01, 0x23, 0x12, 0x33), (0x901, 0x902, 0x911, 0xeeeeeeeeeeeeeefffffffffffffffffffffffffffffff28888177772736646717738388488), @@ -83,21 +94,44 @@ class TB(Module): self.submodules.dut = dma.DMA(bus) +test_writes_full_stack = [ + (0, 32, 0, 1), + (1, 40, 0, 1), + (0, 48, 0, 0), + (1, 50, 0, 0), +] + + +class FullStackTB(Module): + def __init__(self, ws): + self.ttl0 = Signal() + self.ttl1 = Signal() + + self.submodules.phy0 = ttl_simple.Output(self.ttl0) + self.submodules.phy1 = ttl_simple.Output(self.ttl1) + + rtio_channels = [ + rtio.Channel.from_phy(self.phy0), + rtio.Channel.from_phy(self.phy1) + ] + + sequence = encode_sequence(test_writes_full_stack, ws) + + bus = wishbone.Interface(ws*8) + self.submodules.memory = wishbone.SRAM( + 256, init=sequence, bus=bus) + self.submodules.dut = dma.DMA(bus) + self.submodules.rtio = rtio.Core(rtio_channels) + self.comb += self.dut.cri.connect(self.rtio.cri) + + class TestDMA(unittest.TestCase): def test_dma_noerror(self): - ws = 64 - tb = TB(ws) - - def do_dma(address): - yield from tb.dut.dma.base_address.write(address) - yield from tb.dut.enable.write(1) - yield - while ((yield from tb.dut.enable.read())): - yield + tb = TB(64) def do_writes(): - yield from do_dma(0) - yield from do_dma(512) + yield from do_dma(tb.dut, 0) + yield from do_dma(tb.dut, 512) received = [] @passive @@ -124,3 +158,30 @@ class TestDMA(unittest.TestCase): run_simulation(tb, [do_writes(), rtio_sim()]) self.assertEqual(received, test_writes1 + test_writes2) + + def test_full_stack(self): + tb = FullStackTB(64) + + ttl_changes = [] + @passive + def monitor(): + old_ttl_states = [0, 0] + for time in itertools.count(): + ttl_states = [ + (yield tb.ttl0), + (yield tb.ttl1) + ] + for i, (old, new) in enumerate(zip(old_ttl_states, ttl_states)): + if new != old: + ttl_changes.append((time, i)) + old_ttl_states = ttl_states + yield + + run_simulation(tb, {"sys": [ + do_dma(tb.dut, 0), monitor(), + (None for _ in range(70)), + ]}, {"sys": 8, "rsys": 8, "rtio": 8, "rio": 8, "rio_phy": 8}) + + correct_changes = [(timestamp + 11, channel) + for channel, timestamp, _, _ in test_writes_full_stack] + self.assertEqual(ttl_changes, correct_changes) From 893be82ad167efd6a0a5924af1506d674ea1e2d6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Oct 2017 10:22:58 +0800 Subject: [PATCH 0068/2457] rtio/dma: raise underflow in test --- artiq/gateware/test/rtio/test_dma.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/gateware/test/rtio/test_dma.py b/artiq/gateware/test/rtio/test_dma.py index 8f84b37d9..d0e74b5ea 100644 --- a/artiq/gateware/test/rtio/test_dma.py +++ b/artiq/gateware/test/rtio/test_dma.py @@ -5,6 +5,7 @@ import itertools from migen import * from misoc.interconnect import wishbone +from artiq.coredevice.exceptions import RTIOUnderflow from artiq.gateware import rtio from artiq.gateware.rtio import dma, cri from artiq.gateware.rtio.phy import ttl_simple @@ -56,6 +57,8 @@ def do_dma(dut, address): yield while ((yield from dut.enable.read())): yield + if (yield from dut.cri_master.underflow.read()): + raise RTIOUnderflow test_writes1 = [ From b772c2c2378861fe19cc9298a34cb5ad2ddc3d92 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Oct 2017 11:42:06 +0800 Subject: [PATCH 0069/2457] conda: update misoc --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index e476cf990..83e6f01b0 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.5.dev py35_146+git1ccf140 - - misoc 0.6.dev py35_65+git6abc1b4c + - misoc 0.7.dev-py35_4+git622b8074 - jesd204b 0.3 - binutils-or1k-linux >=2.27 - llvm-or1k From acb25f549b2ebc6beb5f2251b83cabf389a8b414 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Oct 2017 12:57:24 +0800 Subject: [PATCH 0070/2457] conda: use new misoc version number --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 83e6f01b0..fb5ab0f31 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.5.dev py35_146+git1ccf140 - - misoc 0.7.dev-py35_4+git622b8074 + - misoc 0.7.dev py35_5+git362de1a9 - jesd204b 0.3 - binutils-or1k-linux >=2.27 - llvm-or1k From 9bf189ca10644161219bf8c2b9cc8197ebe8ad6e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 30 Oct 2017 22:57:12 +0800 Subject: [PATCH 0071/2457] test: relax timing requirements when not using DMA handle core_dma.playback() without handle incurs a round-trip with the comms CPU and should not be used in critical real-time sections. Closes #834. --- artiq/test/coredevice/test_rtio.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 79043c9b8..c82327e90 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -491,7 +491,7 @@ class RPCTest(ExperimentCase): class _DMA(EnvExperiment): - def build(self, trace_name="foobar"): + def build(self, trace_name="test_rtio"): self.setattr_device("core") self.setattr_device("core_dma") self.setattr_device("ttl1") @@ -499,8 +499,12 @@ class _DMA(EnvExperiment): self.delta = np.int64(0) @kernel - def record(self): + def record(self, for_handle=True): with self.core_dma.record(self.trace_name): + # When not using the handle, retrieving the DMA trace + # in dma.playback() can be slow. Allow some time. + if not for_handle: + delay(1*ms) delay(100*ns) self.ttl1.on() delay(100*ns) @@ -519,20 +523,22 @@ class _DMA(EnvExperiment): self.set_dataset("dma_record_time", self.core.mu_to_seconds(t2 - t1)) @kernel - def playback(self, use_handle=False): - self.core.break_realtime() - start = now_mu() + def playback(self, use_handle=True): if use_handle: handle = self.core_dma.get_handle(self.trace_name) + self.core.break_realtime() + start = now_mu() self.core_dma.playback_handle(handle) else: + self.core.break_realtime() + start = now_mu() self.core_dma.playback(self.trace_name) self.delta = now_mu() - start @kernel def playback_many(self, n): - self.core.break_realtime() handle = self.core_dma.get_handle(self.trace_name) + self.core.break_realtime() t1 = self.core.get_rtio_counter_mu() for i in range(n): self.core_dma.playback_handle(handle) @@ -579,9 +585,9 @@ class DMATest(ExperimentCase): core_host = self.device_mgr.get_desc("core")["arguments"]["host"] exp = self.create(_DMA) - exp.record() for use_handle in [False, True]: + exp.record(use_handle) get_analyzer_dump(core_host) # clear analyzer buffer exp.playback(use_handle) @@ -603,9 +609,13 @@ class DMATest(ExperimentCase): exp = self.create(_DMA) exp.record() - for use_handle in [False, True]: - exp.playback(use_handle) - self.assertEqual(exp.delta, 200) + exp.record(False) + exp.playback(False) + self.assertEqual(exp.delta, 1000200) + + exp.record(True) + exp.playback(True) + self.assertEqual(exp.delta, 200) def test_dma_record_time(self): exp = self.create(_DMA) From 20a5f095f8f33c40300011b1921b637aab1a3cfd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 30 Oct 2017 23:06:38 +0800 Subject: [PATCH 0072/2457] test: use longer DMA sequence when playing it back repeatedly The CPU has to keep up. --- artiq/test/coredevice/test_rtio.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index c82327e90..6e7e50365 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -628,11 +628,11 @@ class DMATest(ExperimentCase): def test_dma_playback_time(self): exp = self.create(_DMA) count = 20000 - exp.record() + exp.record_many(40) exp.playback_many(count) dt = self.dataset_mgr.get("dma_playback_time") print("dt={}, dt/count={}".format(dt, dt/count)) - self.assertLess(dt/count, 3*us) + self.assertLess(dt/count, 4.5*us) def test_handle_invalidation(self): exp = self.create(_DMA) From 415fa00846d33d46ed3b97f99e3946105f6f1042 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 30 Oct 2017 23:07:54 +0800 Subject: [PATCH 0073/2457] test: relax rtio test_loopback --- artiq/test/coredevice/test_rtio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 6e7e50365..c968bb37e 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -362,7 +362,7 @@ class CoredeviceTest(ExperimentCase): rtt = self.dataset_mgr.get("rtt") print(rtt) self.assertGreater(rtt, 0*ns) - self.assertLess(rtt, 124*ns) + self.assertLess(rtt, 140*ns) def test_clock_generator_loopback(self): self.execute(ClockGeneratorLoopback) From 0695afec37cbbe97e0fc4665452987a5e201247e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 31 Oct 2017 00:07:34 +0800 Subject: [PATCH 0074/2457] examples/dma_blink: use handle --- .../master/repository/coredevice_examples/simple/dma_blink.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/examples/master/repository/coredevice_examples/simple/dma_blink.py b/artiq/examples/master/repository/coredevice_examples/simple/dma_blink.py index e2866483f..92c96327c 100644 --- a/artiq/examples/master/repository/coredevice_examples/simple/dma_blink.py +++ b/artiq/examples/master/repository/coredevice_examples/simple/dma_blink.py @@ -21,6 +21,7 @@ class DMABlink(EnvExperiment): def run(self): self.core.reset() self.record() + handle = self.core_dma.get_handle("blink") self.core.break_realtime() for i in range(5): - self.core_dma.playback("blink") + self.core_dma.playback_handle(handle) From f3f83174b15e69e47e4167c1cc53066fe11dd5e4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 31 Oct 2017 00:10:13 +0800 Subject: [PATCH 0075/2457] test: check that DMA can underflow --- artiq/test/coredevice/test_rtio.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index c968bb37e..13517084a 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -634,6 +634,12 @@ class DMATest(ExperimentCase): print("dt={}, dt/count={}".format(dt, dt/count)) self.assertLess(dt/count, 4.5*us) + def test_dma_underflow(self): + exp = self.create(_DMA) + exp.record() + with self.assertRaises(RTIOUnderflow): + exp.playback_many(20000) + def test_handle_invalidation(self): exp = self.create(_DMA) for mode in [0, 1]: From 77897228cadf3984bc3f06c55dbcc0fc01915bba Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Dec 2017 18:01:28 +0800 Subject: [PATCH 0076/2457] drtio: add GTH transceiver code from Florent (197c79d47) --- .../drtio/transceiver/clock_aligner.py | 113 +++++ .../drtio/transceiver/gth_ultrascale.py | 453 ++++++++++++++++++ .../drtio/transceiver/gth_ultrascale_init.py | 137 ++++++ 3 files changed, 703 insertions(+) create mode 100644 artiq/gateware/drtio/transceiver/clock_aligner.py create mode 100644 artiq/gateware/drtio/transceiver/gth_ultrascale.py create mode 100644 artiq/gateware/drtio/transceiver/gth_ultrascale_init.py diff --git a/artiq/gateware/drtio/transceiver/clock_aligner.py b/artiq/gateware/drtio/transceiver/clock_aligner.py new file mode 100644 index 000000000..050720998 --- /dev/null +++ b/artiq/gateware/drtio/transceiver/clock_aligner.py @@ -0,0 +1,113 @@ +from math import ceil +from functools import reduce +from operator import add + +from litex.gen import * +from litex.gen.genlib.cdc import MultiReg, PulseSynchronizer + + +# Changes the phase of the transceiver RX clock to align the comma to +# the LSBs of RXDATA, fixing the latency. +# +# This is implemented by repeatedly resetting the transceiver until it +# gives out the correct phase. Each reset gives a random phase. +# +# If Xilinx had designed the GTX transceiver correctly, RXSLIDE_MODE=PMA +# would achieve this faster and in a cleaner way. But: +# * the phase jumps are of 2 UI at every second RXSLIDE pulse, instead +# of 1 UI at every pulse. It is unclear what the latency becomes. +# * RXSLIDE_MODE=PMA cannot be used with the RX buffer bypassed. +# Those design flaws make RXSLIDE_MODE=PMA yet another broken and useless +# transceiver "feature". +# +# Warning: Xilinx transceivers are LSB first, and comma needs to be flipped +# compared to the usual 8b10b binary representation. +class BruteforceClockAligner(Module): + def __init__(self, comma, tx_clk_freq, check_period=6e-3): + self.rxdata = Signal(20) + self.restart = Signal() + + self.ready = Signal() + + check_max_val = ceil(check_period*tx_clk_freq) + check_counter = Signal(max=check_max_val+1) + check = Signal() + reset_check_counter = Signal() + self.sync.rtio_tx += [ + check.eq(0), + If(reset_check_counter, + check_counter.eq(check_max_val) + ).Else( + If(check_counter == 0, + check.eq(1), + check_counter.eq(check_max_val) + ).Else( + check_counter.eq(check_counter-1) + ) + ) + ] + + checks_reset = PulseSynchronizer("rtio_tx", "rtio_rx") + self.submodules += checks_reset + + comma_n = ~comma & 0b1111111111 + comma_seen_rxclk = Signal() + comma_seen = Signal() + comma_seen_rxclk.attr.add("no_retiming") + self.specials += MultiReg(comma_seen_rxclk, comma_seen) + self.sync.rtio_rx += \ + If(checks_reset.o, + comma_seen_rxclk.eq(0) + ).Elif((self.rxdata[:10] == comma) | (self.rxdata[:10] == comma_n), + comma_seen_rxclk.eq(1) + ) + + error_seen_rxclk = Signal() + error_seen = Signal() + error_seen_rxclk.attr.add("no_retiming") + self.specials += MultiReg(error_seen_rxclk, error_seen) + rx1cnt = Signal(max=11) + self.sync.rtio_rx += [ + rx1cnt.eq(reduce(add, [self.rxdata[i] for i in range(10)])), + If(checks_reset.o, + error_seen_rxclk.eq(0) + ).Elif((rx1cnt != 4) & (rx1cnt != 5) & (rx1cnt != 6), + error_seen_rxclk.eq(1) + ) + ] + + fsm = ClockDomainsRenamer("rtio_tx")(FSM(reset_state="WAIT_COMMA")) + self.submodules += fsm + + fsm.act("WAIT_COMMA", + If(check, + # Errors are still OK at this stage, as the transceiver + # has just been reset and may output garbage data. + If(comma_seen, + NextState("WAIT_NOERROR") + ).Else( + self.restart.eq(1) + ), + checks_reset.i.eq(1) + ) + ) + fsm.act("WAIT_NOERROR", + If(check, + If(comma_seen & ~error_seen, + NextState("READY") + ).Else( + self.restart.eq(1), + NextState("WAIT_COMMA") + ), + checks_reset.i.eq(1) + ) + ) + fsm.act("READY", + reset_check_counter.eq(1), + self.ready.eq(1), + If(error_seen, + checks_reset.i.eq(1), + self.restart.eq(1), + NextState("WAIT_COMMA") + ) + ) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py new file mode 100644 index 000000000..616a30a72 --- /dev/null +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -0,0 +1,453 @@ +from litex.gen import * +from litex.gen.genlib.resetsync import AsyncResetSynchronizer +from litex.gen.genlib.cdc import MultiReg + +from litex.soc.interconnect.csr import * +from litex.soc.cores.code_8b10b import Encoder, Decoder + +from drtio.common import TransceiverInterface, ChannelInterface +from drtio.gth_ultrascale_init import GTHInit +from drtio.clock_aligner import BruteforceClockAligner + + +class GTHChannelPLL(Module): + def __init__(self, refclk, refclk_freq, linerate): + self.refclk = refclk + self.reset = Signal() + self.lock = Signal() + self.config = self.compute_config(refclk_freq, linerate) + + @staticmethod + def compute_config(refclk_freq, linerate): + for n1 in 4, 5: + for n2 in 1, 2, 3, 4, 5: + for m in 1, 2: + vco_freq = refclk_freq*(n1*n2)/m + if 2.0e9 <= vco_freq <= 6.25e9: + for d in 1, 2, 4, 8, 16: + current_linerate = vco_freq*2/d + if current_linerate == linerate: + return {"n1": n1, "n2": n2, "m": m, "d": d, + "vco_freq": vco_freq, + "clkin": refclk_freq, + "linerate": linerate} + msg = "No config found for {:3.2f} MHz refclk / {:3.2f} Gbps linerate." + raise ValueError(msg.format(refclk_freq/1e6, linerate/1e9)) + + def __repr__(self): + r = """ +GTHChannelPLL +============== + overview: + --------- + +--------------------------------------------------+ + | | + | +-----+ +---------------------------+ +-----+ | + | | | | Phase Frequency Detector | | | | +CLKIN +----> /M +--> Charge Pump +-> VCO +---> CLKOUT + | | | | Loop Filter | | | | + | +-----+ +---------------------------+ +--+--+ | + | ^ | | + | | +-------+ +-------+ | | + | +----+ /N2 <----+ /N1 <----+ | + | +-------+ +-------+ | + +--------------------------------------------------+ + +-------+ + CLKOUT +-> 2/D +-> LINERATE + +-------+ + config: + ------- + CLKIN = {clkin}MHz + CLKOUT = CLKIN x (N1 x N2) / M = {clkin}MHz x ({n1} x {n2}) / {m} + = {vco_freq}GHz + LINERATE = CLKOUT x 2 / D = {vco_freq}GHz x 2 / {d} + = {linerate}GHz +""".format(clkin=self.config["clkin"]/1e6, + n1=self.config["n1"], + n2=self.config["n2"], + m=self.config["m"], + vco_freq=self.config["vco_freq"]/1e9, + d=self.config["d"], + linerate=self.config["linerate"]/1e9) + return r + + +class GTHQuadPLL(Module): + def __init__(self, refclk, refclk_freq, linerate): + self.clk = Signal() + self.refclk = Signal() + self.reset = Signal() + self.lock = Signal() + self.config = self.compute_config(refclk_freq, linerate) + + # # # + + self.specials += \ + Instance("GTHE3_COMMON", + # common + i_GTREFCLK00=refclk, + i_GTREFCLK01=refclk, + i_QPLLRSVD1=0, + i_QPLLRSVD2=0, + i_QPLLRSVD3=0, + i_QPLLRSVD4=0, + i_BGBYPASSB=1, + i_BGMONITORENB=1, + i_BGPDB=1, + i_BGRCALOVRD=0b11111, + i_BGRCALOVRDENB=0b1, + i_RCALENB=1, + + # qpll0 + p_QPLL0_FBDIV=self.config["n"], + p_QPLL0_REFCLK_DIV=self.config["m"], + i_QPLL0CLKRSVD0=0, + i_QPLL0CLKRSVD1=0, + i_QPLL0LOCKDETCLK=ClockSignal(), + i_QPLL0LOCKEN=1, + o_QPLL0LOCK=self.lock if self.config["qpll"] == "qpll0" else + Signal(), + o_QPLL0OUTCLK=self.clk if self.config["qpll"] == "qpll0" else + Signal(), + o_QPLL0OUTREFCLK=self.refclk if self.config["qpll"] == "qpll0" else + Signal(), + i_QPLL0PD=0 if self.config["qpll"] == "qpll0" else 1, + i_QPLL0REFCLKSEL=0b001, + i_QPLL0RESET=self.reset, + + # qpll1 + p_QPLL1_FBDIV=self.config["n"], + p_QPLL1_REFCLK_DIV=self.config["m"], + i_QPLL1CLKRSVD0=0, + i_QPLL1CLKRSVD1=0, + i_QPLL1LOCKDETCLK=ClockSignal(), + i_QPLL1LOCKEN=1, + o_QPLL1LOCK=self.lock if self.config["qpll"] == "qpll1" else + Signal(), + o_QPLL1OUTCLK=self.clk if self.config["qpll"] == "qpll1" else + Signal(), + o_QPLL1OUTREFCLK=self.refclk if self.config["qpll"] == "qpll1" else + Signal(), + i_QPLL1PD=0 if self.config["qpll"] == "qpll1" else 1, + i_QPLL1REFCLKSEL=0b001, + i_QPLL1RESET=self.reset, + ) + + @staticmethod + def compute_config(refclk_freq, linerate): + for n in [16, 20, 32, 40, 60, 64, 66, 75, 80, 84, + 90, 96, 100, 112, 120, 125, 150, 160]: + for m in 1, 2, 3, 4: + vco_freq = refclk_freq*n/m + if 8e9 <= vco_freq <= 13e9: + qpll = "qpll1" + elif 9.8e9 <= vco_freq <= 16.375e9: + qpll = "qpll0" + else: + qpll = None + if qpll is not None: + for d in 1, 2, 4, 8, 16: + current_linerate = (vco_freq/2)*2/d + if current_linerate == linerate: + return {"n": n, "m": m, "d": d, + "vco_freq": vco_freq, + "qpll": qpll, + "clkin": refclk_freq, + "clkout": vco_freq/2, + "linerate": linerate} + msg = "No config found for {:3.2f} MHz refclk / {:3.2f} Gbps linerate." + raise ValueError(msg.format(refclk_freq/1e6, linerate/1e9)) + + def __repr__(self): + r = """ +GTXQuadPLL +=========== + overview: + --------- + +-------------------------------------------------------------++ + | +------------+ | + | +-----+ +---------------------------+ | QPLL0 | +--+ | + | | | | Phase Frequency Detector +-> VCO | | | | +CLKIN +----> /M +--> Charge Pump | +------------+->/2+--> CLKOUT + | | | | Loop Filter +-> QPLL1 | | | | + | +-----+ +---------------------------+ | VCO | +--+ | + | ^ +-----+------+ | + | | +-------+ | | + | +--------+ /N <----------------+ | + | +-------+ | + +--------------------------------------------------------------+ + +-------+ + CLKOUT +-> 2/D +-> LINERATE + +-------+ + config: + ------- + CLKIN = {clkin}MHz + CLKOUT = CLKIN x N / (2 x M) = {clkin}MHz x {n} / (2 x {m}) + = {clkout}GHz + VCO = {vco_freq}GHz ({qpll}) + LINERATE = CLKOUT x 2 / D = {clkout}GHz x 2 / {d} + = {linerate}GHz +""".format(clkin=self.config["clkin"]/1e6, + n=self.config["n"], + m=self.config["m"], + clkout=self.config["clkout"]/1e9, + vco_freq=self.config["vco_freq"]/1e9, + qpll=self.config["qpll"].upper(), + d=self.config["d"], + linerate=self.config["linerate"]/1e9) + return r + + +class GTHSingle(Module): + def __init__(self, pll, tx_pads, rx_pads, sys_clk_freq, dw=20, mode="master"): + assert (dw == 20) or (dw == 40) + assert mode in ["master", "slave"] + + # # # + + nwords = dw//10 + + use_cpll = isinstance(pll, GTHChannelPLL) + use_qpll0 = isinstance(pll, GTHQuadPLL) and pll.config["qpll"] == "qpll0" + use_qpll1 = isinstance(pll, GTHQuadPLL) and pll.config["qpll"] == "qpll1" + + self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( + Encoder(nwords, True)) + self.submodules.decoders = decoders = [ClockDomainsRenamer("rtio_rx")( + (Decoder(True))) for _ in range(nwords)] + self.rx_ready = Signal() + + self.rtio_clk_freq = pll.config["linerate"]/dw + + # transceiver direct clock outputs + # useful to specify clock constraints in a way palatable to Vivado + self.txoutclk = Signal() + self.rxoutclk = Signal() + + # # # + + # TX generates RTIO clock, init must be in system domain + tx_init = GTHInit(sys_clk_freq, False) + # RX receives restart commands from RTIO domain + rx_init = ClockDomainsRenamer("rtio_tx")( + GTHInit(self.rtio_clk_freq, True)) + self.submodules += tx_init, rx_init + self.comb += [ + tx_init.plllock.eq(pll.lock), + rx_init.plllock.eq(pll.lock) + ] + + txdata = Signal(dw) + rxdata = Signal(dw) + rxphaligndone = Signal() + self.specials += \ + Instance("GTHE3_CHANNEL", + # Reset modes + i_GTRESETSEL=0, + i_RESETOVRD=0, + + # PMA Attributes + p_PMA_RSV1=0xf800, + p_RX_BIAS_CFG0=0x0AB4, + p_RX_CM_TRIM=0b1010, + p_RX_CLK25_DIV=5, + p_TX_CLK25_DIV=5, + + # Power-Down Attributes + p_PD_TRANS_TIME_FROM_P2=0x3c, + p_PD_TRANS_TIME_NONE_P2=0x19, + p_PD_TRANS_TIME_TO_P2=0x64, + + # CPLL + p_CPLL_CFG0=0x67f8, + p_CPLL_CFG1=0xa4ac, + p_CPLL_CFG2=0xf007, + p_CPLL_CFG3=0x0000, + p_CPLL_FBDIV=1 if use_qpll0 or use_qpll1 else pll.config["n2"], + p_CPLL_FBDIV_45=4 if use_qpll0 or use_qpll1 else pll.config["n1"], + p_CPLL_REFCLK_DIV=1 if use_qpll0 or use_qpll1 else pll.config["m"], + p_RXOUT_DIV=pll.config["d"], + p_TXOUT_DIV=pll.config["d"], + i_CPLLRESET=0, + i_CPLLPD=0 if use_qpll0 or use_qpll1 else pll.reset, + o_CPLLLOCK=Signal() if use_qpll0 or use_qpll1 else pll.lock, + i_CPLLLOCKEN=1, + i_CPLLREFCLKSEL=0b001, + i_TSTIN=2**20-1, + i_GTREFCLK0=0 if use_qpll0 or use_qpll1 else pll.refclk, + + # QPLL + i_QPLL0CLK=0 if use_cpll or use_qpll1 else pll.clk, + i_QPLL0REFCLK=0 if use_cpll or use_qpll1 else pll.refclk, + i_QPLL1CLK=0 if use_cpll or use_qpll0 else pll.clk, + i_QPLL1REFCLK=0 if use_cpll or use_qpll0 else pll.refclk, + + # TX clock + p_TXBUF_EN="FALSE", + p_TX_XCLK_SEL="TXUSR", + o_TXOUTCLK=self.txoutclk, + i_TXSYSCLKSEL=0b00 if use_cpll else 0b10 if use_qpll0 else 0b11, + i_TXPLLCLKSEL=0b00 if use_cpll else 0b11 if use_qpll0 else 0b10, + i_TXOUTCLKSEL=0b11, + + # TX Startup/Reset + i_GTTXRESET=tx_init.gtXxreset, + o_TXRESETDONE=tx_init.Xxresetdone, + i_TXDLYSRESET=tx_init.Xxdlysreset, + o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone, + o_TXPHALIGNDONE=tx_init.Xxphaligndone, + i_TXUSERRDY=tx_init.Xxuserrdy, + i_TXSYNCMODE=1, + + # TX data + p_TX_DATA_WIDTH=dw, + p_TX_INT_DATAWIDTH=dw == 40, + i_TXCTRL0=Cat(*[txdata[10*i+8] for i in range(nwords)]), + i_TXCTRL1=Cat(*[txdata[10*i+9] for i in range(nwords)]), + i_TXDATA=Cat(*[txdata[10*i:10*i+8] for i in range(nwords)]), + i_TXUSRCLK=ClockSignal("rtio_tx"), + i_TXUSRCLK2=ClockSignal("rtio_tx"), + + # TX electrical + i_TXPD=0b00, + p_TX_CLKMUX_EN=1, + i_TXBUFDIFFCTRL=0b000, + i_TXDIFFCTRL=0b1100, + + # RX Startup/Reset + i_GTRXRESET=rx_init.gtXxreset, + o_RXRESETDONE=rx_init.Xxresetdone, + i_RXDLYSRESET=rx_init.Xxdlysreset, + o_RXPHALIGNDONE=rxphaligndone, + i_RXSYNCALLIN=rxphaligndone, + i_RXUSERRDY=rx_init.Xxuserrdy, + i_RXSYNCIN=0, + i_RXSYNCMODE=1, + o_RXSYNCDONE=rx_init.Xxsyncdone, + + # RX AFE + i_RXDFEAGCCTRL=1, + i_RXDFEXYDEN=1, + i_RXLPMEN=1, + i_RXOSINTCFG=0xd, + i_RXOSINTEN=1, + + # RX clock + i_RXRATE=0, + i_RXDLYBYPASS=0, + p_RXBUF_EN="FALSE", + p_RX_XCLK_SEL="RXUSR", + i_RXSYSCLKSEL=0b00, + i_RXOUTCLKSEL=0b010, + i_RXPLLCLKSEL=0b00, + o_RXOUTCLK=self.rxoutclk, + i_RXUSRCLK=ClockSignal("rtio_rx"), + i_RXUSRCLK2=ClockSignal("rtio_rx"), + + # RX Clock Correction Attributes + p_CLK_CORRECT_USE="FALSE", + p_CLK_COR_SEQ_1_1=0b0100000000, + p_CLK_COR_SEQ_2_1=0b0100000000, + p_CLK_COR_SEQ_1_ENABLE=0b1111, + p_CLK_COR_SEQ_2_ENABLE=0b1111, + + # RX data + p_RX_DATA_WIDTH=dw, + p_RX_INT_DATAWIDTH=dw == 40, + o_RXCTRL0=Cat(*[rxdata[10*i+8] for i in range(nwords)]), + o_RXCTRL1=Cat(*[rxdata[10*i+9] for i in range(nwords)]), + o_RXDATA=Cat(*[rxdata[10*i:10*i+8] for i in range(nwords)]), + + # RX electrical + i_RXPD=0b00, + p_RX_CLKMUX_EN=1, + i_RXELECIDLEMODE=0b11, + + # Pads + i_GTHRXP=rx_pads.p, + i_GTHRXN=rx_pads.n, + o_GTHTXP=tx_pads.p, + o_GTHTXN=tx_pads.n + ) + + # tx clocking + tx_reset_deglitched = Signal() + tx_reset_deglitched.attr.add("no_retiming") + self.sync += tx_reset_deglitched.eq(~tx_init.done) + self.clock_domains.cd_rtio_tx = ClockDomain() + if mode == "master": + tx_bufg_div = pll.config["clkin"]/self.rtio_clk_freq + assert tx_bufg_div == int(tx_bufg_div) + self.specials += \ + Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk, + i_DIV=int(tx_bufg_div)-1) + self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched) + + # rx clocking + rx_reset_deglitched = Signal() + rx_reset_deglitched.attr.add("no_retiming") + self.sync.rtio_tx += rx_reset_deglitched.eq(~rx_init.done) + self.clock_domains.cd_rtio_rx = ClockDomain() + self.specials += [ + Instance("BUFG_GT", i_I=self.rxoutclk, o_O=self.cd_rtio_rx.clk), + AsyncResetSynchronizer(self.cd_rtio_rx, rx_reset_deglitched) + ] + + # tx data + self.comb += txdata.eq(Cat(*[encoder.output[i] for i in range(nwords)])) + + # rx data + for i in range(nwords): + self.comb += decoders[i].input.eq(rxdata[10*i:10*(i+1)]) + + # clock alignment + clock_aligner = BruteforceClockAligner(0b0101111100, self.rtio_clk_freq) + self.submodules += clock_aligner + self.comb += [ + clock_aligner.rxdata.eq(rxdata), + rx_init.restart.eq(clock_aligner.restart), + self.rx_ready.eq(clock_aligner.ready) + ] + + +class GTH(Module, TransceiverInterface): + def __init__(self, plls, tx_pads, rx_pads, sys_clk_freq, dw, master=0): + self.nchannels = nchannels = len(tx_pads) + self.gths = [] + + # # # + + nwords = dw//10 + + rtio_tx_clk = Signal() + channel_interfaces = [] + for i in range(nchannels): + mode = "master" if i == master else "slave" + gth = GTHSingle(plls[i], tx_pads[i], rx_pads[i], sys_clk_freq, dw, mode) + if mode == "master": + self.comb += rtio_tx_clk.eq(gth.cd_rtio_tx.clk) + else: + self.comb += gth.cd_rtio_tx.clk.eq(rtio_tx_clk) + self.gths.append(gth) + setattr(self.submodules, "gth"+str(i), gth) + channel_interface = ChannelInterface(gth.encoder, gth.decoders) + self.comb += channel_interface.rx_ready.eq(gth.rx_ready) + channel_interfaces.append(channel_interface) + + TransceiverInterface.__init__(self, channel_interfaces) + + # rtio clock domain (clock from gth tx0, ored reset from all gth txs) + self.comb += self.cd_rtio.clk.eq(ClockSignal("gth0_rtio_tx")) + rtio_rst = Signal() + for i in range(nchannels): + rtio_rst.eq(rtio_rst | ResetSignal("gth" + str(i) + "rtio_tx")) + new_rtio_rst = Signal() + rtio_rst = new_rtio_rst + self.comb += self.cd_rtio.rst.eq(rtio_rst) + + # rtio_rx clock domains + for i in range(nchannels): + self.comb += [ + getattr(self, "cd_rtio_rx" + str(i)).clk.eq(self.gths[i].cd_rtio_rx.clk), + getattr(self, "cd_rtio_rx" + str(i)).rst.eq(self.gths[i].cd_rtio_rx.rst) + ] diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py b/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py new file mode 100644 index 000000000..070cb0bfb --- /dev/null +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py @@ -0,0 +1,137 @@ +from math import ceil + +from litex.gen import * +from litex.gen.genlib.cdc import MultiReg +from litex.gen.genlib.misc import WaitTimer + + +class GTHInit(Module): + def __init__(self, sys_clk_freq, rx): + self.done = Signal() + self.restart = Signal() + + # GTH signals + self.plllock = Signal() + self.pllreset = Signal() + self.gtXxreset = Signal() + self.Xxresetdone = Signal() + self.Xxdlysreset = Signal() + self.Xxdlysresetdone = Signal() + self.Xxphaligndone = Signal() + self.Xxsyncdone = Signal() + self.Xxuserrdy = Signal() + + # # # + + # Double-latch transceiver asynch outputs + plllock = Signal() + Xxresetdone = Signal() + Xxdlysresetdone = Signal() + Xxphaligndone = Signal() + Xxsyncdone = Signal() + self.specials += [ + MultiReg(self.plllock, plllock), + MultiReg(self.Xxresetdone, Xxresetdone), + MultiReg(self.Xxdlysresetdone, Xxdlysresetdone), + MultiReg(self.Xxphaligndone, Xxphaligndone), + MultiReg(self.Xxsyncdone, Xxsyncdone) + ] + + # Deglitch FSM outputs driving transceiver asynch inputs + gtXxreset = Signal() + Xxdlysreset = Signal() + Xxuserrdy = Signal() + self.sync += [ + self.gtXxreset.eq(gtXxreset), + self.Xxdlysreset.eq(Xxdlysreset), + self.Xxuserrdy.eq(Xxuserrdy) + ] + + # PLL reset must be at least 2us + pll_reset_cycles = ceil(2000*sys_clk_freq/1000000000) + pll_reset_timer = WaitTimer(pll_reset_cycles) + self.submodules += pll_reset_timer + + startup_fsm = ResetInserter()(FSM(reset_state="RESET_ALL")) + self.submodules += startup_fsm + + ready_timer = WaitTimer(int(sys_clk_freq/1000)) + self.submodules += ready_timer + self.comb += [ + ready_timer.wait.eq(~self.done & ~startup_fsm.reset), + startup_fsm.reset.eq(self.restart | ready_timer.done) + ] + + if rx: + cdr_stable_timer = WaitTimer(1024) + self.submodules += cdr_stable_timer + + Xxphaligndone_r = Signal(reset=1) + Xxphaligndone_rising = Signal() + self.sync += Xxphaligndone_r.eq(Xxphaligndone) + self.comb += Xxphaligndone_rising.eq(Xxphaligndone & ~Xxphaligndone_r) + + startup_fsm.act("RESET_ALL", + gtXxreset.eq(1), + self.pllreset.eq(1), + pll_reset_timer.wait.eq(1), + If(pll_reset_timer.done, + NextState("RELEASE_PLL_RESET") + ) + ) + startup_fsm.act("RELEASE_PLL_RESET", + gtXxreset.eq(1), + If(plllock, NextState("RELEASE_GTH_RESET")) + ) + # Release GTH reset and wait for GTH resetdone + # (from UG476, GTH is reset on falling edge + # of gtXxreset) + if rx: + startup_fsm.act("RELEASE_GTH_RESET", + Xxuserrdy.eq(1), + cdr_stable_timer.wait.eq(1), + If(Xxresetdone & cdr_stable_timer.done, NextState("ALIGN")) + ) + else: + startup_fsm.act("RELEASE_GTH_RESET", + Xxuserrdy.eq(1), + If(Xxresetdone, NextState("ALIGN")) + ) + # Start delay alignment (pulse) + startup_fsm.act("ALIGN", + Xxuserrdy.eq(1), + Xxdlysreset.eq(1), + NextState("WAIT_ALIGN") + ) + if rx: + # Wait for delay alignment + startup_fsm.act("WAIT_ALIGN", + Xxuserrdy.eq(1), + If(Xxsyncdone, + NextState("READY") + ) + ) + else: + # Wait for delay alignment + startup_fsm.act("WAIT_ALIGN", + Xxuserrdy.eq(1), + If(Xxdlysresetdone, + NextState("WAIT_FIRST_ALIGN_DONE") + ) + ) + + # Wait 2 rising edges of Xxphaligndone + # (from UG576 in TX Buffer Bypass in Single-Lane Auto Mode) + startup_fsm.act("WAIT_FIRST_ALIGN_DONE", + Xxuserrdy.eq(1), + If(Xxphaligndone_rising, NextState("WAIT_SECOND_ALIGN_DONE")) + ) + startup_fsm.act("WAIT_SECOND_ALIGN_DONE", + Xxuserrdy.eq(1), + If(Xxphaligndone_rising, NextState("READY")) + ) + startup_fsm.act("READY", + Xxuserrdy.eq(1), + self.done.eq(1), + If(self.restart, NextState("RESET_ALL")) + ) From c57b66497c7c090f9551123c7082c6244e04ca39 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 23 Dec 2017 01:19:44 +0800 Subject: [PATCH 0077/2457] drtio: refactor/simplify GTH, use migen --- .../drtio/transceiver/clock_aligner.py | 113 -------- .../drtio/transceiver/gth_ultrascale.py | 265 +++--------------- .../drtio/transceiver/gth_ultrascale_init.py | 119 +++++++- 3 files changed, 149 insertions(+), 348 deletions(-) delete mode 100644 artiq/gateware/drtio/transceiver/clock_aligner.py diff --git a/artiq/gateware/drtio/transceiver/clock_aligner.py b/artiq/gateware/drtio/transceiver/clock_aligner.py deleted file mode 100644 index 050720998..000000000 --- a/artiq/gateware/drtio/transceiver/clock_aligner.py +++ /dev/null @@ -1,113 +0,0 @@ -from math import ceil -from functools import reduce -from operator import add - -from litex.gen import * -from litex.gen.genlib.cdc import MultiReg, PulseSynchronizer - - -# Changes the phase of the transceiver RX clock to align the comma to -# the LSBs of RXDATA, fixing the latency. -# -# This is implemented by repeatedly resetting the transceiver until it -# gives out the correct phase. Each reset gives a random phase. -# -# If Xilinx had designed the GTX transceiver correctly, RXSLIDE_MODE=PMA -# would achieve this faster and in a cleaner way. But: -# * the phase jumps are of 2 UI at every second RXSLIDE pulse, instead -# of 1 UI at every pulse. It is unclear what the latency becomes. -# * RXSLIDE_MODE=PMA cannot be used with the RX buffer bypassed. -# Those design flaws make RXSLIDE_MODE=PMA yet another broken and useless -# transceiver "feature". -# -# Warning: Xilinx transceivers are LSB first, and comma needs to be flipped -# compared to the usual 8b10b binary representation. -class BruteforceClockAligner(Module): - def __init__(self, comma, tx_clk_freq, check_period=6e-3): - self.rxdata = Signal(20) - self.restart = Signal() - - self.ready = Signal() - - check_max_val = ceil(check_period*tx_clk_freq) - check_counter = Signal(max=check_max_val+1) - check = Signal() - reset_check_counter = Signal() - self.sync.rtio_tx += [ - check.eq(0), - If(reset_check_counter, - check_counter.eq(check_max_val) - ).Else( - If(check_counter == 0, - check.eq(1), - check_counter.eq(check_max_val) - ).Else( - check_counter.eq(check_counter-1) - ) - ) - ] - - checks_reset = PulseSynchronizer("rtio_tx", "rtio_rx") - self.submodules += checks_reset - - comma_n = ~comma & 0b1111111111 - comma_seen_rxclk = Signal() - comma_seen = Signal() - comma_seen_rxclk.attr.add("no_retiming") - self.specials += MultiReg(comma_seen_rxclk, comma_seen) - self.sync.rtio_rx += \ - If(checks_reset.o, - comma_seen_rxclk.eq(0) - ).Elif((self.rxdata[:10] == comma) | (self.rxdata[:10] == comma_n), - comma_seen_rxclk.eq(1) - ) - - error_seen_rxclk = Signal() - error_seen = Signal() - error_seen_rxclk.attr.add("no_retiming") - self.specials += MultiReg(error_seen_rxclk, error_seen) - rx1cnt = Signal(max=11) - self.sync.rtio_rx += [ - rx1cnt.eq(reduce(add, [self.rxdata[i] for i in range(10)])), - If(checks_reset.o, - error_seen_rxclk.eq(0) - ).Elif((rx1cnt != 4) & (rx1cnt != 5) & (rx1cnt != 6), - error_seen_rxclk.eq(1) - ) - ] - - fsm = ClockDomainsRenamer("rtio_tx")(FSM(reset_state="WAIT_COMMA")) - self.submodules += fsm - - fsm.act("WAIT_COMMA", - If(check, - # Errors are still OK at this stage, as the transceiver - # has just been reset and may output garbage data. - If(comma_seen, - NextState("WAIT_NOERROR") - ).Else( - self.restart.eq(1) - ), - checks_reset.i.eq(1) - ) - ) - fsm.act("WAIT_NOERROR", - If(check, - If(comma_seen & ~error_seen, - NextState("READY") - ).Else( - self.restart.eq(1), - NextState("WAIT_COMMA") - ), - checks_reset.i.eq(1) - ) - ) - fsm.act("READY", - reset_check_counter.eq(1), - self.ready.eq(1), - If(error_seen, - checks_reset.i.eq(1), - self.restart.eq(1), - NextState("WAIT_COMMA") - ) - ) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index 616a30a72..d847f928f 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -1,224 +1,26 @@ -from litex.gen import * -from litex.gen.genlib.resetsync import AsyncResetSynchronizer -from litex.gen.genlib.cdc import MultiReg +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.cdc import MultiReg -from litex.soc.interconnect.csr import * -from litex.soc.cores.code_8b10b import Encoder, Decoder +from misoc.interconnect.csr import * +from misoc.cores.code_8b10b import Encoder, Decoder -from drtio.common import TransceiverInterface, ChannelInterface -from drtio.gth_ultrascale_init import GTHInit -from drtio.clock_aligner import BruteforceClockAligner - - -class GTHChannelPLL(Module): - def __init__(self, refclk, refclk_freq, linerate): - self.refclk = refclk - self.reset = Signal() - self.lock = Signal() - self.config = self.compute_config(refclk_freq, linerate) - - @staticmethod - def compute_config(refclk_freq, linerate): - for n1 in 4, 5: - for n2 in 1, 2, 3, 4, 5: - for m in 1, 2: - vco_freq = refclk_freq*(n1*n2)/m - if 2.0e9 <= vco_freq <= 6.25e9: - for d in 1, 2, 4, 8, 16: - current_linerate = vco_freq*2/d - if current_linerate == linerate: - return {"n1": n1, "n2": n2, "m": m, "d": d, - "vco_freq": vco_freq, - "clkin": refclk_freq, - "linerate": linerate} - msg = "No config found for {:3.2f} MHz refclk / {:3.2f} Gbps linerate." - raise ValueError(msg.format(refclk_freq/1e6, linerate/1e9)) - - def __repr__(self): - r = """ -GTHChannelPLL -============== - overview: - --------- - +--------------------------------------------------+ - | | - | +-----+ +---------------------------+ +-----+ | - | | | | Phase Frequency Detector | | | | -CLKIN +----> /M +--> Charge Pump +-> VCO +---> CLKOUT - | | | | Loop Filter | | | | - | +-----+ +---------------------------+ +--+--+ | - | ^ | | - | | +-------+ +-------+ | | - | +----+ /N2 <----+ /N1 <----+ | - | +-------+ +-------+ | - +--------------------------------------------------+ - +-------+ - CLKOUT +-> 2/D +-> LINERATE - +-------+ - config: - ------- - CLKIN = {clkin}MHz - CLKOUT = CLKIN x (N1 x N2) / M = {clkin}MHz x ({n1} x {n2}) / {m} - = {vco_freq}GHz - LINERATE = CLKOUT x 2 / D = {vco_freq}GHz x 2 / {d} - = {linerate}GHz -""".format(clkin=self.config["clkin"]/1e6, - n1=self.config["n1"], - n2=self.config["n2"], - m=self.config["m"], - vco_freq=self.config["vco_freq"]/1e9, - d=self.config["d"], - linerate=self.config["linerate"]/1e9) - return r - - -class GTHQuadPLL(Module): - def __init__(self, refclk, refclk_freq, linerate): - self.clk = Signal() - self.refclk = Signal() - self.reset = Signal() - self.lock = Signal() - self.config = self.compute_config(refclk_freq, linerate) - - # # # - - self.specials += \ - Instance("GTHE3_COMMON", - # common - i_GTREFCLK00=refclk, - i_GTREFCLK01=refclk, - i_QPLLRSVD1=0, - i_QPLLRSVD2=0, - i_QPLLRSVD3=0, - i_QPLLRSVD4=0, - i_BGBYPASSB=1, - i_BGMONITORENB=1, - i_BGPDB=1, - i_BGRCALOVRD=0b11111, - i_BGRCALOVRDENB=0b1, - i_RCALENB=1, - - # qpll0 - p_QPLL0_FBDIV=self.config["n"], - p_QPLL0_REFCLK_DIV=self.config["m"], - i_QPLL0CLKRSVD0=0, - i_QPLL0CLKRSVD1=0, - i_QPLL0LOCKDETCLK=ClockSignal(), - i_QPLL0LOCKEN=1, - o_QPLL0LOCK=self.lock if self.config["qpll"] == "qpll0" else - Signal(), - o_QPLL0OUTCLK=self.clk if self.config["qpll"] == "qpll0" else - Signal(), - o_QPLL0OUTREFCLK=self.refclk if self.config["qpll"] == "qpll0" else - Signal(), - i_QPLL0PD=0 if self.config["qpll"] == "qpll0" else 1, - i_QPLL0REFCLKSEL=0b001, - i_QPLL0RESET=self.reset, - - # qpll1 - p_QPLL1_FBDIV=self.config["n"], - p_QPLL1_REFCLK_DIV=self.config["m"], - i_QPLL1CLKRSVD0=0, - i_QPLL1CLKRSVD1=0, - i_QPLL1LOCKDETCLK=ClockSignal(), - i_QPLL1LOCKEN=1, - o_QPLL1LOCK=self.lock if self.config["qpll"] == "qpll1" else - Signal(), - o_QPLL1OUTCLK=self.clk if self.config["qpll"] == "qpll1" else - Signal(), - o_QPLL1OUTREFCLK=self.refclk if self.config["qpll"] == "qpll1" else - Signal(), - i_QPLL1PD=0 if self.config["qpll"] == "qpll1" else 1, - i_QPLL1REFCLKSEL=0b001, - i_QPLL1RESET=self.reset, - ) - - @staticmethod - def compute_config(refclk_freq, linerate): - for n in [16, 20, 32, 40, 60, 64, 66, 75, 80, 84, - 90, 96, 100, 112, 120, 125, 150, 160]: - for m in 1, 2, 3, 4: - vco_freq = refclk_freq*n/m - if 8e9 <= vco_freq <= 13e9: - qpll = "qpll1" - elif 9.8e9 <= vco_freq <= 16.375e9: - qpll = "qpll0" - else: - qpll = None - if qpll is not None: - for d in 1, 2, 4, 8, 16: - current_linerate = (vco_freq/2)*2/d - if current_linerate == linerate: - return {"n": n, "m": m, "d": d, - "vco_freq": vco_freq, - "qpll": qpll, - "clkin": refclk_freq, - "clkout": vco_freq/2, - "linerate": linerate} - msg = "No config found for {:3.2f} MHz refclk / {:3.2f} Gbps linerate." - raise ValueError(msg.format(refclk_freq/1e6, linerate/1e9)) - - def __repr__(self): - r = """ -GTXQuadPLL -=========== - overview: - --------- - +-------------------------------------------------------------++ - | +------------+ | - | +-----+ +---------------------------+ | QPLL0 | +--+ | - | | | | Phase Frequency Detector +-> VCO | | | | -CLKIN +----> /M +--> Charge Pump | +------------+->/2+--> CLKOUT - | | | | Loop Filter +-> QPLL1 | | | | - | +-----+ +---------------------------+ | VCO | +--+ | - | ^ +-----+------+ | - | | +-------+ | | - | +--------+ /N <----------------+ | - | +-------+ | - +--------------------------------------------------------------+ - +-------+ - CLKOUT +-> 2/D +-> LINERATE - +-------+ - config: - ------- - CLKIN = {clkin}MHz - CLKOUT = CLKIN x N / (2 x M) = {clkin}MHz x {n} / (2 x {m}) - = {clkout}GHz - VCO = {vco_freq}GHz ({qpll}) - LINERATE = CLKOUT x 2 / D = {clkout}GHz x 2 / {d} - = {linerate}GHz -""".format(clkin=self.config["clkin"]/1e6, - n=self.config["n"], - m=self.config["m"], - clkout=self.config["clkout"]/1e9, - vco_freq=self.config["vco_freq"]/1e9, - qpll=self.config["qpll"].upper(), - d=self.config["d"], - linerate=self.config["linerate"]/1e9) - return r +from artiq.gateware.drtio.core import TransceiverInterface, ChannelInterface +from artiq.gateware.drtio.transceiver.gth_ultrascale_init import * class GTHSingle(Module): - def __init__(self, pll, tx_pads, rx_pads, sys_clk_freq, dw=20, mode="master"): + def __init__(self, refclk, tx_pads, rx_pads, sys_clk_freq, rtio_clk_freq, dw, mode): assert (dw == 20) or (dw == 40) assert mode in ["master", "slave"] - # # # - nwords = dw//10 - - use_cpll = isinstance(pll, GTHChannelPLL) - use_qpll0 = isinstance(pll, GTHQuadPLL) and pll.config["qpll"] == "qpll0" - use_qpll1 = isinstance(pll, GTHQuadPLL) and pll.config["qpll"] == "qpll1" - self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( Encoder(nwords, True)) self.submodules.decoders = decoders = [ClockDomainsRenamer("rtio_rx")( (Decoder(True))) for _ in range(nwords)] self.rx_ready = Signal() - self.rtio_clk_freq = pll.config["linerate"]/dw - # transceiver direct clock outputs # useful to specify clock constraints in a way palatable to Vivado self.txoutclk = Signal() @@ -230,11 +32,13 @@ class GTHSingle(Module): tx_init = GTHInit(sys_clk_freq, False) # RX receives restart commands from RTIO domain rx_init = ClockDomainsRenamer("rtio_tx")( - GTHInit(self.rtio_clk_freq, True)) + GTHInit(rtio_clk_freq, True)) self.submodules += tx_init, rx_init + + pll_lock = Signal() self.comb += [ - tx_init.plllock.eq(pll.lock), - rx_init.plllock.eq(pll.lock) + tx_init.plllock.eq(pll_lock), + rx_init.plllock.eq(pll_lock) ] txdata = Signal(dw) @@ -263,31 +67,25 @@ class GTHSingle(Module): p_CPLL_CFG1=0xa4ac, p_CPLL_CFG2=0xf007, p_CPLL_CFG3=0x0000, - p_CPLL_FBDIV=1 if use_qpll0 or use_qpll1 else pll.config["n2"], - p_CPLL_FBDIV_45=4 if use_qpll0 or use_qpll1 else pll.config["n1"], - p_CPLL_REFCLK_DIV=1 if use_qpll0 or use_qpll1 else pll.config["m"], - p_RXOUT_DIV=pll.config["d"], - p_TXOUT_DIV=pll.config["d"], + p_CPLL_FBDIV=5, + p_CPLL_FBDIV_45=4, + p_CPLL_REFCLK_DIV=1, + p_RXOUT_DIV=2, + p_TXOUT_DIV=2, i_CPLLRESET=0, - i_CPLLPD=0 if use_qpll0 or use_qpll1 else pll.reset, - o_CPLLLOCK=Signal() if use_qpll0 or use_qpll1 else pll.lock, + i_CPLLPD=0, + o_CPLLLOCK=pll_lock, i_CPLLLOCKEN=1, i_CPLLREFCLKSEL=0b001, i_TSTIN=2**20-1, - i_GTREFCLK0=0 if use_qpll0 or use_qpll1 else pll.refclk, - - # QPLL - i_QPLL0CLK=0 if use_cpll or use_qpll1 else pll.clk, - i_QPLL0REFCLK=0 if use_cpll or use_qpll1 else pll.refclk, - i_QPLL1CLK=0 if use_cpll or use_qpll0 else pll.clk, - i_QPLL1REFCLK=0 if use_cpll or use_qpll0 else pll.refclk, + i_GTREFCLK0=refclk, # TX clock p_TXBUF_EN="FALSE", p_TX_XCLK_SEL="TXUSR", o_TXOUTCLK=self.txoutclk, - i_TXSYSCLKSEL=0b00 if use_cpll else 0b10 if use_qpll0 else 0b11, - i_TXPLLCLKSEL=0b00 if use_cpll else 0b11 if use_qpll0 else 0b10, + i_TXSYSCLKSEL=0b00, + i_TXPLLCLKSEL=0b00, i_TXOUTCLKSEL=0b11, # TX Startup/Reset @@ -376,11 +174,9 @@ class GTHSingle(Module): self.sync += tx_reset_deglitched.eq(~tx_init.done) self.clock_domains.cd_rtio_tx = ClockDomain() if mode == "master": - tx_bufg_div = pll.config["clkin"]/self.rtio_clk_freq - assert tx_bufg_div == int(tx_bufg_div) self.specials += \ Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk, - i_DIV=int(tx_bufg_div)-1) + i_DIV=0) self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched) # rx clocking @@ -401,7 +197,7 @@ class GTHSingle(Module): self.comb += decoders[i].input.eq(rxdata[10*i:10*(i+1)]) # clock alignment - clock_aligner = BruteforceClockAligner(0b0101111100, self.rtio_clk_freq) + clock_aligner = BruteforceClockAligner(0b0101111100, rtio_clk_freq) self.submodules += clock_aligner self.comb += [ clock_aligner.rxdata.eq(rxdata), @@ -411,19 +207,24 @@ class GTHSingle(Module): class GTH(Module, TransceiverInterface): - def __init__(self, plls, tx_pads, rx_pads, sys_clk_freq, dw, master=0): + def __init__(self, clock_pads, tx_pads, rx_pads, sys_clk_freq, rtio_clk_freq, dw=20, master=0): self.nchannels = nchannels = len(tx_pads) self.gths = [] # # # - nwords = dw//10 + refclk = Signal() + self.specials += Instance("IBUFDS_GTE3", + i_CEB=0, + i_I=clock_pads.p, + i_IB=clock_pads.n, + o_O=refclk) rtio_tx_clk = Signal() channel_interfaces = [] for i in range(nchannels): mode = "master" if i == master else "slave" - gth = GTHSingle(plls[i], tx_pads[i], rx_pads[i], sys_clk_freq, dw, mode) + gth = GTHSingle(refclk, tx_pads[i], rx_pads[i], sys_clk_freq, rtio_clk_freq, dw, mode) if mode == "master": self.comb += rtio_tx_clk.eq(gth.cd_rtio_tx.clk) else: diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py b/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py index 070cb0bfb..0c2734051 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py @@ -1,8 +1,13 @@ from math import ceil +from functools import reduce +from operator import add -from litex.gen import * -from litex.gen.genlib.cdc import MultiReg -from litex.gen.genlib.misc import WaitTimer +from migen import * +from migen.genlib.cdc import MultiReg, PulseSynchronizer +from migen.genlib.misc import WaitTimer + + +__all__ = ["BruteforceClockAligner", "GTHInit"] class GTHInit(Module): @@ -135,3 +140,111 @@ class GTHInit(Module): self.done.eq(1), If(self.restart, NextState("RESET_ALL")) ) + + +# Changes the phase of the transceiver RX clock to align the comma to +# the LSBs of RXDATA, fixing the latency. +# +# This is implemented by repeatedly resetting the transceiver until it +# gives out the correct phase. Each reset gives a random phase. +# +# If Xilinx had designed the GTX transceiver correctly, RXSLIDE_MODE=PMA +# would achieve this faster and in a cleaner way. But: +# * the phase jumps are of 2 UI at every second RXSLIDE pulse, instead +# of 1 UI at every pulse. It is unclear what the latency becomes. +# * RXSLIDE_MODE=PMA cannot be used with the RX buffer bypassed. +# Those design flaws make RXSLIDE_MODE=PMA yet another broken and useless +# transceiver "feature". +# +# Warning: Xilinx transceivers are LSB first, and comma needs to be flipped +# compared to the usual 8b10b binary representation. +class BruteforceClockAligner(Module): + def __init__(self, comma, tx_clk_freq, check_period=6e-3): + self.rxdata = Signal(20) + self.restart = Signal() + + self.ready = Signal() + + check_max_val = ceil(check_period*tx_clk_freq) + check_counter = Signal(max=check_max_val+1) + check = Signal() + reset_check_counter = Signal() + self.sync.rtio_tx += [ + check.eq(0), + If(reset_check_counter, + check_counter.eq(check_max_val) + ).Else( + If(check_counter == 0, + check.eq(1), + check_counter.eq(check_max_val) + ).Else( + check_counter.eq(check_counter-1) + ) + ) + ] + + checks_reset = PulseSynchronizer("rtio_tx", "rtio_rx") + self.submodules += checks_reset + + comma_n = ~comma & 0b1111111111 + comma_seen_rxclk = Signal() + comma_seen = Signal() + comma_seen_rxclk.attr.add("no_retiming") + self.specials += MultiReg(comma_seen_rxclk, comma_seen) + self.sync.rtio_rx += \ + If(checks_reset.o, + comma_seen_rxclk.eq(0) + ).Elif((self.rxdata[:10] == comma) | (self.rxdata[:10] == comma_n), + comma_seen_rxclk.eq(1) + ) + + error_seen_rxclk = Signal() + error_seen = Signal() + error_seen_rxclk.attr.add("no_retiming") + self.specials += MultiReg(error_seen_rxclk, error_seen) + rx1cnt = Signal(max=11) + self.sync.rtio_rx += [ + rx1cnt.eq(reduce(add, [self.rxdata[i] for i in range(10)])), + If(checks_reset.o, + error_seen_rxclk.eq(0) + ).Elif((rx1cnt != 4) & (rx1cnt != 5) & (rx1cnt != 6), + error_seen_rxclk.eq(1) + ) + ] + + fsm = ClockDomainsRenamer("rtio_tx")(FSM(reset_state="WAIT_COMMA")) + self.submodules += fsm + + fsm.act("WAIT_COMMA", + If(check, + # Errors are still OK at this stage, as the transceiver + # has just been reset and may output garbage data. + If(comma_seen, + NextState("WAIT_NOERROR") + ).Else( + self.restart.eq(1) + ), + checks_reset.i.eq(1) + ) + ) + fsm.act("WAIT_NOERROR", + If(check, + If(comma_seen & ~error_seen, + NextState("READY") + ).Else( + self.restart.eq(1), + NextState("WAIT_COMMA") + ), + checks_reset.i.eq(1) + ) + ) + fsm.act("READY", + reset_check_counter.eq(1), + self.ready.eq(1), + If(error_seen, + checks_reset.i.eq(1), + self.restart.eq(1), + NextState("WAIT_COMMA") + ) + ) + From 1af21c0b29c5e441697782c778148f87981cb8d3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 23 Dec 2017 01:19:59 +0800 Subject: [PATCH 0078/2457] drtio: integrate GTH transceiver for Sayma --- .../targets/sayma_amc_drtio_master.py | 18 +++++++----- .../targets/sayma_amc_drtio_satellite.py | 28 +++++++++---------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc_drtio_master.py b/artiq/gateware/targets/sayma_amc_drtio_master.py index cd1bbc149..1d4d7ba09 100755 --- a/artiq/gateware/targets/sayma_amc_drtio_master.py +++ b/artiq/gateware/targets/sayma_amc_drtio_master.py @@ -6,6 +6,7 @@ from migen import * from migen.build.generic_platform import * from misoc.cores import spi as spi_csr +from misoc.cores import gpio from misoc.integration.soc_sdram import soc_sdram_args, soc_sdram_argdict from misoc.integration.builder import builder_args, builder_argdict from misoc.targets.sayma_amc import MiniSoC @@ -40,6 +41,7 @@ class Master(MiniSoC, AMPSoC): AMPSoC.__init__(self) platform = self.platform + rtio_clk_freq = 150e6 # Si5324 used as a free-running oscillator, to avoid dependency on RTM. self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) @@ -55,7 +57,8 @@ class Master(MiniSoC, AMPSoC): clock_pads=platform.request("si5324_clkout"), tx_pads=[platform.request("sfp_tx")], rx_pads=[platform.request("sfp_rx")], - sys_clk_freq=self.clk_freq) + sys_clk_freq=self.clk_freq, + rtio_clk_freq=rtio_clk_freq) self.submodules.drtio0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"})( DRTIOMaster(self.transceiver.channels[0])) @@ -67,12 +70,13 @@ class Master(MiniSoC, AMPSoC): self.add_csr_group("drtio", ["drtio0"]) self.add_memory_group("drtio_aux", ["drtio0_aux"]) - rtio_clk_period = 1e9/self.transceiver.rtio_clk_freq - platform.add_period_constraint(self.transceiver.txoutclk, rtio_clk_period) - platform.add_period_constraint(self.transceiver.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - self.transceiver.txoutclk, self.transceiver.rxoutclk) + rtio_clk_period = 1e9/rtio_clk_freq + for gth in self.transceiver.gths: + platform.add_period_constraint(gth.txoutclk, rtio_clk_period) + platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, + gth.txoutclk, gth.rxoutclk) rtio_channels = [] for i in range(4): diff --git a/artiq/gateware/targets/sayma_amc_drtio_satellite.py b/artiq/gateware/targets/sayma_amc_drtio_satellite.py index aecfca2c1..6d046862c 100755 --- a/artiq/gateware/targets/sayma_amc_drtio_satellite.py +++ b/artiq/gateware/targets/sayma_amc_drtio_satellite.py @@ -8,7 +8,7 @@ from migen.build.generic_platform import * from misoc.cores import spi as spi_csr from misoc.cores import gpio from misoc.integration.soc_sdram import soc_sdram_args, soc_sdram_argdict -from misoc.integration.builder import builder_args, builder_argdict +from misoc.integration.builder import * from misoc.targets.sayma_amc import BaseSoC from artiq.gateware import rtio @@ -34,6 +34,7 @@ class Satellite(BaseSoC): **kwargs) platform = self.platform + rtio_clk_freq = 150e6 rtio_channels = [] for i in range(4): @@ -54,17 +55,15 @@ class Satellite(BaseSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.submodules.transceiver = gth_7series.GTH( + self.submodules.transceiver = gth_ultrascale.GTH( clock_pads=platform.request("si5324_clkout"), - tx_pads=platform.request("sfp_tx"), - rx_pads=platform.request("sfp_rx"), - sys_clk_freq=self.clk_freq) + tx_pads=[platform.request("sfp_tx")], + rx_pads=[platform.request("sfp_rx")], + sys_clk_freq=self.clk_freq, + rtio_clk_freq=rtio_clk_freq) rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) - self.submodules.rx_synchronizer0 = rx0(gth_ultrascale.RXSynchronizer( - self.transceiver.rtio_clk_freq, initial_phase=180.0)) self.submodules.drtio0 = rx0(DRTIOSatellite( - self.transceiver.channels[0], rtio_channels, self.rx_synchronizer0)) - self.csr_devices.append("rx_synchronizer0") + self.transceiver.channels[0], rtio_channels)) self.csr_devices.append("drtio0") self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, self.drtio0.aux_controller.bus) @@ -73,7 +72,7 @@ class Satellite(BaseSoC): self.add_csr_group("drtio", ["drtio0"]) self.add_memory_group("drtio_aux", ["drtio0_aux"]) - self.config["RTIO_FREQUENCY"] = str(self.transceiver.rtio_clk_freq/1e6) + self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) si5324_clkin = platform.request("si5324_clkin") self.specials += \ Instance("OBUFDS", @@ -88,12 +87,13 @@ class Satellite(BaseSoC): self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None - rtio_clk_period = 1e9/self.transceiver.rtio_clk_freq - platform.add_period_constraint(self.transceiver.txoutclk, rtio_clk_period) - platform.add_period_constraint(self.transceiver.rxoutclk, rtio_clk_period) + rtio_clk_period = 1e9/rtio_clk_freq + gth = self.transceiver.gths[0] + platform.add_period_constraint(gth.txoutclk, rtio_clk_period) + platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( self.crg.cd_sys.clk, - self.transceiver.txoutclk, self.transceiver.rxoutclk) + gth.txoutclk, gth.rxoutclk) def main(): From f8c8f3fe26f214ddb1bc74359621248a24882729 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 23 Dec 2017 07:21:44 +0800 Subject: [PATCH 0079/2457] drtio: fix GTH clock domains --- .../drtio/transceiver/gth_ultrascale.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index d847f928f..5fef1f78f 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -1,3 +1,6 @@ +from functools import reduce +from operator import or_ + from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.cdc import MultiReg @@ -237,16 +240,10 @@ class GTH(Module, TransceiverInterface): TransceiverInterface.__init__(self, channel_interfaces) - # rtio clock domain (clock from gth tx0, ored reset from all gth txs) - self.comb += self.cd_rtio.clk.eq(ClockSignal("gth0_rtio_tx")) - rtio_rst = Signal() - for i in range(nchannels): - rtio_rst.eq(rtio_rst | ResetSignal("gth" + str(i) + "rtio_tx")) - new_rtio_rst = Signal() - rtio_rst = new_rtio_rst - self.comb += self.cd_rtio.rst.eq(rtio_rst) - - # rtio_rx clock domains + self.comb += [ + self.cd_rtio.clk.eq(self.gths[master].cd_rtio_tx.clk), + self.cd_rtio.rst.eq(reduce(or_, [gth.cd_rtio_tx.rst for gth in self.gths])) + ] for i in range(nchannels): self.comb += [ getattr(self, "cd_rtio_rx" + str(i)).clk.eq(self.gths[i].cd_rtio_rx.clk), From 00ed51f6f4941320c28318573e7d68bf075894ac Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 23 Dec 2017 22:15:39 +0800 Subject: [PATCH 0080/2457] satman: use new alloc_list (#880) --- artiq/firmware/satman/lib.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/satman/lib.rs b/artiq/firmware/satman/lib.rs index 6cf05a137..d9a72e273 100644 --- a/artiq/firmware/satman/lib.rs +++ b/artiq/firmware/satman/lib.rs @@ -1,8 +1,8 @@ -#![feature(compiler_builtins_lib, lang_items)] +#![feature(compiler_builtins_lib, lang_items, global_allocator)] #![no_std] extern crate compiler_builtins; -extern crate alloc_artiq; +extern crate alloc_list; extern crate std_artiq as std; #[macro_use] extern crate log; @@ -218,6 +218,9 @@ fn startup() { } } +#[global_allocator] +static mut ALLOC: alloc_list::ListAlloc = alloc_list::EMPTY; + #[no_mangle] pub extern fn main() -> i32 { unsafe { @@ -225,8 +228,7 @@ pub extern fn main() -> i32 { static mut _fheap: u8; static mut _eheap: u8; } - alloc_artiq::seed(&mut _fheap as *mut u8, - &_eheap as *const u8 as usize - &_fheap as *const u8 as usize); + ALLOC.add_range(&mut _fheap, &mut _eheap); static mut LOG_BUFFER: [u8; 65536] = [0; 65536]; logger_artiq::BufferLogger::new(&mut LOG_BUFFER[..]).register(startup); From 70b7f28ad35f58ccf83bc00542862c54f185e465 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 23 Dec 2017 22:58:51 +0800 Subject: [PATCH 0081/2457] drtio: drive SFP TX disable pins --- artiq/gateware/targets/sayma_amc_drtio_master.py | 5 +++-- artiq/gateware/targets/sayma_amc_drtio_satellite.py | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc_drtio_master.py b/artiq/gateware/targets/sayma_amc_drtio_master.py index 1d4d7ba09..ac47e00ab 100755 --- a/artiq/gateware/targets/sayma_amc_drtio_master.py +++ b/artiq/gateware/targets/sayma_amc_drtio_master.py @@ -53,10 +53,11 @@ class Master(MiniSoC, AMPSoC): self.config["HAS_SI5324"] = None self.config["SI5324_FREE_RUNNING"] = None + self.comb += platform.request("sfp_tx_disable_n", 0).eq(1) self.submodules.transceiver = gth_ultrascale.GTH( clock_pads=platform.request("si5324_clkout"), - tx_pads=[platform.request("sfp_tx")], - rx_pads=[platform.request("sfp_rx")], + tx_pads=[platform.request("sfp_tx", 0)], + rx_pads=[platform.request("sfp_rx", 0)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) diff --git a/artiq/gateware/targets/sayma_amc_drtio_satellite.py b/artiq/gateware/targets/sayma_amc_drtio_satellite.py index 6d046862c..82f9f52e5 100755 --- a/artiq/gateware/targets/sayma_amc_drtio_satellite.py +++ b/artiq/gateware/targets/sayma_amc_drtio_satellite.py @@ -55,10 +55,11 @@ class Satellite(BaseSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") + self.comb += platform.request("sfp_tx_disable_n", 0).eq(1) self.submodules.transceiver = gth_ultrascale.GTH( clock_pads=platform.request("si5324_clkout"), - tx_pads=[platform.request("sfp_tx")], - rx_pads=[platform.request("sfp_rx")], + tx_pads=[platform.request("sfp_tx", 0)], + rx_pads=[platform.request("sfp_rx", 0)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) From fa4dc1bf0e07a8392113d7cf819fa18dd4bfd789 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 24 Dec 2017 16:27:54 +0000 Subject: [PATCH 0082/2457] doc: developing: show how to make clang source builds faster. --- doc/manual/developing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index d6600d841..ecc3f6ffa 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -95,7 +95,7 @@ and the ARTIQ kernels. $ mkdir build $ cd build - $ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/llvm-or1k -DLLVM_TARGETS_TO_BUILD="OR1K;X86" -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INSTALL_UTILS=ON + $ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/llvm-or1k -DLLVM_TARGETS_TO_BUILD="OR1K;X86" -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INSTALL_UTILS=ON -DCLANG_ENABLE_ARCMT=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF $ make -j4 $ sudo make install From 1570a482c2675339a7af3c70532765e0044c48ab Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 25 Dec 2017 16:15:51 +0000 Subject: [PATCH 0083/2457] artiq_devtool: don't require lock for reset. reset is mainly useful as a part of reset+hotswap sequence, and that already needs lock via connect. --- artiq/frontend/artiq_devtool.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index e84b988f3..8c5b0ac01 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -44,7 +44,7 @@ def get_argparser(): parser.add_argument("actions", metavar="ACTION", type=str, default=[], nargs="+", help="actions to perform, sequence of: " - "build reset boot boot+log connect hotswap clean") + "build boot boot+log connect reset hotswap clean") return parser @@ -112,14 +112,6 @@ def main(): if os.path.isdir(target_dir): shutil.rmtree(target_dir) - elif action == "reset": - lock() - - logger.info("Resetting device") - client.run_command( - "{env} artiq_flash start", - **substs) - elif action == "boot" or action == "boot+log": lock() @@ -196,6 +188,12 @@ def main(): "{env} python3 flterm.py {serial} --output-only", **substs) + elif action == "reset": + logger.info("Resetting device") + client.run_command( + "{env} artiq_flash start", + **substs) + elif action == "hotswap": logger.info("Hotswapping firmware") try: From 3eec15c01d0b78e6f7bf862c69e6eae969bdd1df Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 25 Dec 2017 17:16:05 +0000 Subject: [PATCH 0084/2457] firmware: fix compatibility with newer rustc. NFC. --- artiq/firmware/ksupport/lib.rs | 6 +++--- artiq/firmware/runtime/config.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 1ce29e05b..29466daea 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -167,7 +167,7 @@ extern fn rpc_recv(slot: *mut ()) -> usize { }) } -fn terminate(exception: &eh::Exception, mut backtrace: &mut [usize]) -> ! { +fn terminate(exception: &eh::Exception, backtrace: &mut [usize]) -> ! { let mut cursor = 0; for index in 0..backtrace.len() { if backtrace[index] > kernel_proto::KERNELCPU_PAYLOAD_ADDRESS { @@ -333,8 +333,8 @@ extern fn dma_record_output_wide(timestamp: i64, channel: i32, address: i32, wor if DMA_RECORDER.buffer.len() - DMA_RECORDER.data_len < length { dma_record_flush() } - let mut dst = &mut DMA_RECORDER.buffer[DMA_RECORDER.data_len.. - DMA_RECORDER.data_len + length]; + let dst = &mut DMA_RECORDER.buffer[DMA_RECORDER.data_len.. + DMA_RECORDER.data_len + length]; dst[..header_length].copy_from_slice(&header[..]); dst[header_length..].copy_from_slice(&data[..]); DMA_RECORDER.data_len += length; diff --git a/artiq/firmware/runtime/config.rs b/artiq/firmware/runtime/config.rs index c4b45ee6c..4a1407a08 100644 --- a/artiq/firmware/runtime/config.rs +++ b/artiq/firmware/runtime/config.rs @@ -10,9 +10,9 @@ mod imp { mod lock { use core::slice; - use core::sync::atomic::{AtomicUsize, Ordering}; + use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; - static LOCKED: AtomicUsize = AtomicUsize::new(0); + static LOCKED: AtomicUsize = ATOMIC_USIZE_INIT; pub struct Lock; From 230f2e5e18726e8c4b3ed72a78d0fe4aa48fd701 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 25 Dec 2017 17:55:20 +0000 Subject: [PATCH 0085/2457] runtime: print (address-only) backtraces on core device panics. --- artiq/firmware/Cargo.lock | 5 +++ artiq/firmware/ksupport/Makefile | 2 +- artiq/firmware/libbacktrace_artiq/Cargo.toml | 8 +++++ artiq/firmware/libbacktrace_artiq/lib.rs | 38 ++++++++++++++++++++ artiq/firmware/runtime/Cargo.toml | 1 + artiq/firmware/runtime/Makefile | 16 +++++++-- artiq/firmware/runtime/lib.rs | 18 +++++----- artiq/firmware/runtime/runtime.ld | 21 +++++++---- conda/artiq-dev/meta.yaml | 2 +- 9 files changed, 91 insertions(+), 20 deletions(-) create mode 100644 artiq/firmware/libbacktrace_artiq/Cargo.toml create mode 100644 artiq/firmware/libbacktrace_artiq/lib.rs diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 0cb9aef5b..353118496 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -13,6 +13,10 @@ dependencies = [ "board 0.0.0", ] +[[package]] +name = "backtrace_artiq" +version = "0.0.0" + [[package]] name = "bitflags" version = "1.0.1" @@ -150,6 +154,7 @@ version = "0.0.0" dependencies = [ "alloc_list 0.0.0", "amp 0.0.0", + "backtrace_artiq 0.0.0", "board 0.0.0", "build_artiq 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/artiq/firmware/ksupport/Makefile b/artiq/firmware/ksupport/Makefile index c45aea7a4..718b2c639 100644 --- a/artiq/firmware/ksupport/Makefile +++ b/artiq/firmware/ksupport/Makefile @@ -23,7 +23,7 @@ $(RUSTOUT)/libksupport.a: ksupport.elf: $(RUSTOUT)/libksupport.a glue.o $(LD) $(LDFLAGS) -T $(KSUPPORT_DIRECTORY)/ksupport.ld -o $@ $^ \ - -lunwind -lcompiler-rt -lbase -lm + -lunwind-elf -lcompiler-rt -lbase -lm @chmod -x $@ %.o: $(KSUPPORT_DIRECTORY)/%.c diff --git a/artiq/firmware/libbacktrace_artiq/Cargo.toml b/artiq/firmware/libbacktrace_artiq/Cargo.toml new file mode 100644 index 000000000..afab53124 --- /dev/null +++ b/artiq/firmware/libbacktrace_artiq/Cargo.toml @@ -0,0 +1,8 @@ +[package] +authors = ["M-Labs"] +name = "backtrace_artiq" +version = "0.0.0" + +[lib] +name = "backtrace_artiq" +path = "lib.rs" diff --git a/artiq/firmware/libbacktrace_artiq/lib.rs b/artiq/firmware/libbacktrace_artiq/lib.rs new file mode 100644 index 000000000..cf06c8f5a --- /dev/null +++ b/artiq/firmware/libbacktrace_artiq/lib.rs @@ -0,0 +1,38 @@ +#![feature(libc, panic_unwind, never_type)] +#![allow(non_upper_case_globals, non_camel_case_types)] +#![no_std] + +extern crate unwind; +extern crate libc; + +use unwind as uw; +use libc::c_void; + +type _Unwind_Trace_Fn = extern "C" fn(*mut uw::_Unwind_Context, *mut c_void) + -> uw::_Unwind_Reason_Code; +extern { + fn _Unwind_Backtrace(trace_fn: _Unwind_Trace_Fn, arg: *mut c_void) + -> uw::_Unwind_Reason_Code; +} + +pub fn backtrace(mut f: F) -> Result<(), uw::_Unwind_Reason_Code> + where F: FnMut(usize) -> () +{ + extern fn trace(context: *mut uw::_Unwind_Context, arg: *mut c_void) + -> uw::_Unwind_Reason_Code + where F: FnMut(usize) -> () + { + unsafe { + let step_fn = &mut *(arg as *mut F); + step_fn(uw::_Unwind_GetIP(context)); + uw::_URC_NO_REASON + } + } + + unsafe { + match _Unwind_Backtrace(trace::, &mut f as *mut _ as *mut c_void) { + uw::_URC_NO_REASON => Ok(()), + err => Err(err) + } + } +} diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 4a820e33d..f9db55dee 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -19,6 +19,7 @@ log = { version = "0.3", default-features = false } alloc_list = { path = "../liballoc_list" } std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] } logger_artiq = { path = "../liblogger_artiq" } +backtrace_artiq = { path = "../libbacktrace_artiq" } board = { path = "../libboard", features = ["uart_console"] } proto = { path = "../libproto", features = ["log"] } amp = { path = "../libamp" } diff --git a/artiq/firmware/runtime/Makefile b/artiq/firmware/runtime/Makefile index 94cd87cbe..2ec0a033a 100644 --- a/artiq/firmware/runtime/Makefile +++ b/artiq/firmware/runtime/Makefile @@ -1,7 +1,13 @@ include ../include/generated/variables.mak include $(MISOC_DIRECTORY)/software/common.mak -LDFLAGS += -L../libbase +CFLAGS += \ + -I$(LIBUNWIND_DIRECTORY) \ + -I$(LIBUNWIND_DIRECTORY)/../unwinder/include \ + +LDFLAGS += -L../libbase \ + -L../libprintf \ + -L../libunwind RUSTFLAGS += -Cpanic=abort @@ -11,13 +17,17 @@ all: runtime.bin runtime.fbi $(RUSTOUT)/libruntime.a: $(cargo) --manifest-path $(RUNTIME_DIRECTORY)/Cargo.toml -runtime.elf: $(RUSTOUT)/libruntime.a ksupport_data.o - $(LD) $(LDFLAGS) -T $(RUNTIME_DIRECTORY)/runtime.ld -o $@ $^ +runtime.elf: $(RUSTOUT)/libruntime.a ksupport_data.o glue.o + $(LD) $(LDFLAGS) -T $(RUNTIME_DIRECTORY)/runtime.ld -o $@ $^ \ + -lunwind-bare -lprintf-nofloat --eh-frame-hdr @chmod -x $@ ksupport_data.o: ../ksupport/ksupport.elf $(LD) -r -b binary -o $@ $< +%.o: $(RUNTIME_DIRECTORY)/%.c + $(compile) + %.bin: %.elf $(OBJCOPY) -O binary $< $@ @chmod -x $@ diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index 61d0dba4f..784a42f45 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -14,6 +14,7 @@ extern crate alloc_list; #[macro_use] extern crate std_artiq as std; extern crate logger_artiq; +extern crate backtrace_artiq; #[macro_use] extern crate board; extern crate proto; @@ -231,7 +232,9 @@ pub extern fn exception_handler(vect: u32, _regs: *const u32, pc: u32, ea: u32) #[no_mangle] pub extern fn abort() { - panic!("aborted") + println!("aborted"); + + loop {} } #[no_mangle] @@ -239,6 +242,11 @@ pub extern fn abort() { pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! { println!("panic at {}:{}: {}", file, line, args); + println!("backtrace:"); + let _ = backtrace_artiq::backtrace(|ip| { + println!("{:#08x}", ip); + }); + if config::read_str("panic_reboot", |r| r == Ok("1")) { println!("rebooting..."); unsafe { board::boot::reboot() } @@ -248,11 +256,3 @@ pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u3 loop {} } } - -// Allow linking with crates that are built as -Cpanic=unwind even if we use -Cpanic=abort. -// This is never called. -#[allow(non_snake_case)] -#[no_mangle] -pub extern fn _Unwind_Resume() -> ! { - loop {} -} diff --git a/artiq/firmware/runtime/runtime.ld b/artiq/firmware/runtime/runtime.ld index 026ec9186..1d21c61fb 100644 --- a/artiq/firmware/runtime/runtime.ld +++ b/artiq/firmware/runtime/runtime.ld @@ -20,6 +20,21 @@ SECTIONS _etext = .; } > runtime + .eh_frame : + { + __eh_frame_start = .; + KEEP(*(.eh_frame)) + __eh_frame_end = .; + } > runtime + + .eh_frame_hdr : + { + KEEP(*(.eh_frame_hdr)) + } > runtime + + __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0; + __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0; + /* https://sourceware.org/bugzilla/show_bug.cgi?id=20475 */ .got : { @@ -79,10 +94,4 @@ SECTIONS . = ORIGIN(runtime) + LENGTH(runtime); _eheap = .; } > runtime - - /DISCARD/ : - { - *(.eh_frame) - *(.gcc_except_table) - } } diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 91fffb4bf..b93946398 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6.dev py35_50+git82b06ee - - misoc 0.8.dev py35_15+git5c201712 + - misoc 0.8.dev py35_30+gitd95f4edb - jesd204b 0.4 - binutils-or1k-linux >=2.27 - llvm-or1k From 061fb3dcd52df714b5f7c7ea51350ba776d2a44b Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 25 Dec 2017 20:30:13 +0000 Subject: [PATCH 0086/2457] runtime: remove accidentally committed parts of a Makefile. --- artiq/firmware/runtime/Makefile | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/artiq/firmware/runtime/Makefile b/artiq/firmware/runtime/Makefile index 2ec0a033a..aa2e43b6f 100644 --- a/artiq/firmware/runtime/Makefile +++ b/artiq/firmware/runtime/Makefile @@ -17,7 +17,7 @@ all: runtime.bin runtime.fbi $(RUSTOUT)/libruntime.a: $(cargo) --manifest-path $(RUNTIME_DIRECTORY)/Cargo.toml -runtime.elf: $(RUSTOUT)/libruntime.a ksupport_data.o glue.o +runtime.elf: $(RUSTOUT)/libruntime.a ksupport_data.o $(LD) $(LDFLAGS) -T $(RUNTIME_DIRECTORY)/runtime.ld -o $@ $^ \ -lunwind-bare -lprintf-nofloat --eh-frame-hdr @chmod -x $@ @@ -25,9 +25,6 @@ runtime.elf: $(RUSTOUT)/libruntime.a ksupport_data.o glue.o ksupport_data.o: ../ksupport/ksupport.elf $(LD) -r -b binary -o $@ $< -%.o: $(RUNTIME_DIRECTORY)/%.c - $(compile) - %.bin: %.elf $(OBJCOPY) -O binary $< $@ @chmod -x $@ From 6e341da3a1f21b0e19231f13e50767337bb08938 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 02:31:28 +0000 Subject: [PATCH 0087/2457] runtime: simplify. NFC. --- artiq/firmware/libbacktrace_artiq/lib.rs | 12 ++---------- artiq/firmware/runtime/Makefile | 3 +-- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/artiq/firmware/libbacktrace_artiq/lib.rs b/artiq/firmware/libbacktrace_artiq/lib.rs index cf06c8f5a..7e84e5e44 100644 --- a/artiq/firmware/libbacktrace_artiq/lib.rs +++ b/artiq/firmware/libbacktrace_artiq/lib.rs @@ -1,5 +1,4 @@ -#![feature(libc, panic_unwind, never_type)] -#![allow(non_upper_case_globals, non_camel_case_types)] +#![feature(libc, panic_unwind)] #![no_std] extern crate unwind; @@ -8,13 +7,6 @@ extern crate libc; use unwind as uw; use libc::c_void; -type _Unwind_Trace_Fn = extern "C" fn(*mut uw::_Unwind_Context, *mut c_void) - -> uw::_Unwind_Reason_Code; -extern { - fn _Unwind_Backtrace(trace_fn: _Unwind_Trace_Fn, arg: *mut c_void) - -> uw::_Unwind_Reason_Code; -} - pub fn backtrace(mut f: F) -> Result<(), uw::_Unwind_Reason_Code> where F: FnMut(usize) -> () { @@ -30,7 +22,7 @@ pub fn backtrace(mut f: F) -> Result<(), uw::_Unwind_Reason_Code> } unsafe { - match _Unwind_Backtrace(trace::, &mut f as *mut _ as *mut c_void) { + match uw::_Unwind_Backtrace(trace::, &mut f as *mut _ as *mut c_void) { uw::_URC_NO_REASON => Ok(()), err => Err(err) } diff --git a/artiq/firmware/runtime/Makefile b/artiq/firmware/runtime/Makefile index aa2e43b6f..187793ae4 100644 --- a/artiq/firmware/runtime/Makefile +++ b/artiq/firmware/runtime/Makefile @@ -6,7 +6,6 @@ CFLAGS += \ -I$(LIBUNWIND_DIRECTORY)/../unwinder/include \ LDFLAGS += -L../libbase \ - -L../libprintf \ -L../libunwind RUSTFLAGS += -Cpanic=abort @@ -19,7 +18,7 @@ $(RUSTOUT)/libruntime.a: runtime.elf: $(RUSTOUT)/libruntime.a ksupport_data.o $(LD) $(LDFLAGS) -T $(RUNTIME_DIRECTORY)/runtime.ld -o $@ $^ \ - -lunwind-bare -lprintf-nofloat --eh-frame-hdr + -lunwind-bare @chmod -x $@ ksupport_data.o: ../ksupport/ksupport.elf From e2513a24016dd4eb7814e952206120fbfe9b1abb Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 02:48:36 +0000 Subject: [PATCH 0088/2457] runtime: ensure flash storage never overlaps with runtime sections. --- artiq/firmware/runtime/config.rs | 68 +++++++++++++++++-------------- artiq/firmware/runtime/runtime.ld | 9 ++++ artiq/frontend/artiq_flash.py | 7 ++-- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/artiq/firmware/runtime/config.rs b/artiq/firmware/runtime/config.rs index 4a1407a08..cc0d2ab14 100644 --- a/artiq/firmware/runtime/config.rs +++ b/artiq/firmware/runtime/config.rs @@ -3,10 +3,7 @@ mod imp { use core::str; use std::btree_map::BTreeMap; use byteorder::{ByteOrder, BigEndian}; - use board::{mem, csr, cache, spiflash}; - - const ADDR: usize = mem::FLASH_BOOT_ADDRESS + 0x80000 /* max runtime size */; - const SIZE: usize = csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize; + use board::{cache, spiflash}; mod lock { use core::slice; @@ -26,7 +23,16 @@ mod imp { } pub fn data(&self) -> &'static [u8] { - unsafe { slice::from_raw_parts(super::ADDR as *const u8, super::SIZE) } + extern { + static _fstorage: u8; + static _estorage: u8; + } + + unsafe { + let begin = &_fstorage as *const u8; + let end = &_estorage as *const u8; + slice::from_raw_parts(begin, end as usize - begin as usize) + } } } @@ -62,12 +68,11 @@ mod imp { } let record_size = BigEndian::read_u32(data) as usize; - if record_size < 4 { - error!("offset {}: invalid record size", self.offset); - return Some(Err(())) - } if record_size == !0 /* all ones; erased flash */ { return None + } else if record_size < 4 || record_size > data.len() { + error!("offset {}: invalid record size", self.offset); + return Some(Err(())) } let record_body = &data[4..record_size]; @@ -107,29 +112,28 @@ mod imp { }) } - fn append_at(mut offset: usize, key: &[u8], value: &[u8]) -> Result { + unsafe fn append_at<'a>(mut data: &'a [u8], key: &[u8], value: &[u8]) -> Result<&'a [u8], ()> { let record_size = 4 + key.len() + 1 + value.len(); - if offset + record_size > SIZE { + if data.len() < record_size { return Err(()) } let mut record_size_bytes = [0u8; 4]; BigEndian::write_u32(&mut record_size_bytes[..], record_size as u32); - spiflash::write(ADDR + offset, &record_size_bytes[..]); - offset += record_size_bytes.len(); + spiflash::write(data.as_ptr() as usize, &record_size_bytes[..]); + data = &data[record_size_bytes.len()..]; - spiflash::write(ADDR + offset, key); - offset += key.len(); + spiflash::write(data.as_ptr() as usize, key); + data = &data[key.len()..]; - spiflash::write(ADDR + offset, &[0]); - offset += 1; + spiflash::write(data.as_ptr() as usize, &[0]); + data = &data[1..]; - spiflash::write(ADDR + offset, value); - offset += value.len(); + spiflash::write(data.as_ptr() as usize, value); + data = &data[value.len()..]; - cache::flush_l2_cache(); - Ok(offset) + Ok(data) } fn compact() -> Result<(), ()> { @@ -144,28 +148,30 @@ mod imp { } } - spiflash::erase_sector(ADDR); - cache::flush_l2_cache(); - - let mut offset = 0; + let mut data = lock.data(); + spiflash::erase_sector(data.as_ptr() as usize); for (key, value) in items { - offset = append_at(offset, key, value)?; + data = unsafe { append_at(data, key, value)? }; } + + cache::flush_l2_cache(); Ok(()) } fn append(key: &str, value: &[u8]) -> Result<(), ()> { let lock = Lock::take()?; - let free_offset = { + let free = { let mut iter = Iter::new(lock.data()); while let Some(result) = iter.next() { let _ = result?; } - iter.offset + &iter.data[iter.offset..] }; - append_at(free_offset, key.as_bytes(), value)?; + unsafe { append_at(free, key.as_bytes(), value)? }; + + cache::flush_l2_cache(); Ok(()) } @@ -185,9 +191,9 @@ mod imp { } pub fn erase() -> Result<(), ()> { - let _lock = Lock::take()?; + let lock = Lock::take()?; - spiflash::erase_sector(ADDR); + spiflash::erase_sector(lock.data().as_ptr() as usize); cache::flush_l2_cache(); Ok(()) diff --git a/artiq/firmware/runtime/runtime.ld b/artiq/firmware/runtime/runtime.ld index 1d21c61fb..54a964836 100644 --- a/artiq/firmware/runtime/runtime.ld +++ b/artiq/firmware/runtime/runtime.ld @@ -66,6 +66,15 @@ SECTIONS _edata = .; } > runtime + .storage : + { + /* Keep in sync with artiq_flash.py */ + _fstorage = .; + . = _ftext + 0x80000; + . += /*SPIFLASH_SECTOR_SIZE*/ 0x10000; + _estorage = .; + } > runtime + .bss : { . = ALIGN(4); diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index db1a98f31..beb408e0c 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -41,7 +41,7 @@ Prerequisites: help="board variant") parser.add_argument("--preinit-command", default=[], action="append", help="add a pre-initialization OpenOCD command. " - "Useful for selecting a development board " + "Useful for selecting a development board " "when several are connected.") parser.add_argument("-f", "--storage", help="write file to storage area") parser.add_argument("-d", "--dir", help="look for files in this directory") @@ -188,6 +188,7 @@ def main(): parser = get_argparser() opts = parser.parse_args() + storage_at = 0x80000 # Keep in sync with runtime.ld config = { "kc705": { "programmer_factory": partial(ProgrammerJtagSpi7, "kc705"), @@ -196,7 +197,7 @@ def main(): "gateware": (0, 0x000000), "bios": (0, 0xaf0000), "runtime": (0, 0xb00000), - "storage": (0, 0xb80000), + "storage": (0, 0xb00000 + storage_at), }, "sayma": { "programmer_factory": ProgrammerSayma, @@ -205,7 +206,7 @@ def main(): "gateware": (0, 0x000000), "bios": (1, 0x000000), "runtime": (1, 0x010000), - "storage": (1, 0x090000), + "storage": (1, 0x010000 + storage_at), }, }[opts.target] From 188764693e120c339ba1859034b61329e069b9a8 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 03:34:16 +0000 Subject: [PATCH 0089/2457] runtime: we're growing, put storage at 1M instead of 512K. --- artiq/firmware/runtime/runtime.ld | 2 +- artiq/frontend/artiq_flash.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/runtime.ld b/artiq/firmware/runtime/runtime.ld index 54a964836..7346d6188 100644 --- a/artiq/firmware/runtime/runtime.ld +++ b/artiq/firmware/runtime/runtime.ld @@ -70,7 +70,7 @@ SECTIONS { /* Keep in sync with artiq_flash.py */ _fstorage = .; - . = _ftext + 0x80000; + . = _ftext + 0x100000; . += /*SPIFLASH_SECTOR_SIZE*/ 0x10000; _estorage = .; } > runtime diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index beb408e0c..4e7e85eb3 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -188,7 +188,7 @@ def main(): parser = get_argparser() opts = parser.parse_args() - storage_at = 0x80000 # Keep in sync with runtime.ld + storage_at = 0x100000 # Keep in sync with runtime.ld config = { "kc705": { "programmer_factory": partial(ProgrammerJtagSpi7, "kc705"), From 71eca5ad61fb046da718aa58e00b92b4981e6fa5 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 14:09:09 +0000 Subject: [PATCH 0090/2457] runtime: fix some final flash storage issues. --- artiq/firmware/runtime/config.rs | 15 +++++++++++---- artiq/firmware/runtime/runtime.ld | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/runtime/config.rs b/artiq/firmware/runtime/config.rs index cc0d2ab14..fd3c14efe 100644 --- a/artiq/firmware/runtime/config.rs +++ b/artiq/firmware/runtime/config.rs @@ -8,6 +8,7 @@ mod imp { mod lock { use core::slice; use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; + use board; static LOCKED: AtomicUsize = ATOMIC_USIZE_INIT; @@ -24,14 +25,20 @@ mod imp { pub fn data(&self) -> &'static [u8] { extern { + static _ftext: u8; static _fstorage: u8; static _estorage: u8; } unsafe { - let begin = &_fstorage as *const u8; - let end = &_estorage as *const u8; - slice::from_raw_parts(begin, end as usize - begin as usize) + let base = &_ftext as *const _ as usize; + let begin = &_fstorage as *const _ as usize; + let end = &_estorage as *const _ as usize; + + let ptr = board::mem::FLASH_BOOT_ADDRESS + (begin - base); + let len = end - begin; + + slice::from_raw_parts(ptr as *const u8, len) } } } @@ -71,7 +78,7 @@ mod imp { if record_size == !0 /* all ones; erased flash */ { return None } else if record_size < 4 || record_size > data.len() { - error!("offset {}: invalid record size", self.offset); + error!("offset {}: invalid record size {}", self.offset, record_size); return Some(Err(())) } diff --git a/artiq/firmware/runtime/runtime.ld b/artiq/firmware/runtime/runtime.ld index 7346d6188..d629e4ff8 100644 --- a/artiq/firmware/runtime/runtime.ld +++ b/artiq/firmware/runtime/runtime.ld @@ -69,8 +69,8 @@ SECTIONS .storage : { /* Keep in sync with artiq_flash.py */ - _fstorage = .; . = _ftext + 0x100000; + _fstorage = .; . += /*SPIFLASH_SECTOR_SIZE*/ 0x10000; _estorage = .; } > runtime From c939c6183e59f56877a8ac9e8d0474672569f69f Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 13:47:27 +0000 Subject: [PATCH 0091/2457] Update to LLVM 4.0. --- .../compiler/transforms/llvm_ir_generator.py | 2 +- conda/artiq-dev/meta.yaml | 4 ++-- doc/manual/developing.rst | 20 ++++++++++--------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 1fdad4319..726528dee 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -22,7 +22,7 @@ llptr = ll.IntType(8).as_pointer() llptrptr = ll.IntType(8).as_pointer().as_pointer() llslice = ll.LiteralStructType([llptr, lli32]) llsliceptr = ll.LiteralStructType([llptr, lli32]).as_pointer() -llmetadata = ll.MetaData() +llmetadata = ll.MetaDataType() def memoize(generator): diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index b93946398..78de72bf7 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -18,9 +18,9 @@ requirements: - misoc 0.8.dev py35_30+gitd95f4edb - jesd204b 0.4 - binutils-or1k-linux >=2.27 - - llvm-or1k + - llvm-or1k 4.0.1 - llvmlite-artiq 0.12.0 - - rust-core-or1k 1.20.0 16 + - rust-core-or1k 1.22.1 17 - cargo 0.11.0 - openocd 0.10.0+git1 - lit diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index ecc3f6ffa..912c19dd2 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -89,20 +89,20 @@ and the ARTIQ kernels. * Install LLVM and Clang: :: $ cd ~/artiq-dev - $ git clone -b artiq-3.9 https://github.com/m-labs/llvm-or1k + $ git clone -b artiq-4.0 https://github.com/m-labs/llvm-or1k $ cd llvm-or1k - $ git clone -b artiq-3.9 https://github.com/m-labs/clang-or1k tools/clang + $ git clone -b artiq-4.0 https://github.com/m-labs/clang-or1k tools/clang $ mkdir build $ cd build - $ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/llvm-or1k -DLLVM_TARGETS_TO_BUILD="OR1K;X86" -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INSTALL_UTILS=ON -DCLANG_ENABLE_ARCMT=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF + $ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/llvm-or1k -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=OR1K -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INSTALL_UTILS=ON -DCLANG_ENABLE_ARCMT=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF $ make -j4 $ sudo make install * Install Rust: :: $ cd ~/artiq-dev - $ git clone -b artiq-1.20.0 https://github.com/m-labs/rust + $ git clone -b artiq-1.22.1 https://github.com/m-labs/rust $ cd rust $ git submodule update --init $ mkdir build @@ -112,14 +112,16 @@ and the ARTIQ kernels. $ sudo chown $USER.$USER /usr/local/rust-or1k $ make install - $ libs="libcore libstd_unicode liballoc liblibc_mini libunwind" - $ rustc="/usr/local/rust-or1k/bin/rustc --target or1k-unknown-none -g -C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s -L ." + $ libs="core std_unicode alloc" + $ rustc="/usr/local/rust-or1k/bin/rustc --target or1k-unknown-none -C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s -g --crate-type rlib -L ." $ destdir="/usr/local/rust-or1k/lib/rustlib/or1k-unknown-none/lib/" $ mkdir ../build-or1k $ cd ../build-or1k - $ for lib in ${libs}; do ${rustc} ../src/${lib}/lib.rs; done - $ ${rustc} -Cpanic=abort ../src/libpanic_abort/lib.rs - $ ${rustc} -Cpanic=unwind ../src/libpanic_unwind/lib.rs --cfg llvm_libunwind + $ for lib in ${libs}; do ${rustc} --crate-name ${lib} ../src/lib${lib}/lib.rs; done + $ ${rustc} --crate-name libc ../src/liblibc_mini/lib.rs + $ ${rustc} --crate-name unwind ../src/libunwind/lib.rs + $ ${rustc} -Cpanic=abort --crate-name panic_abort ../src/libpanic_abort/lib.rs + $ ${rustc} -Cpanic=unwind --crate-name panic_unwind ../src/libpanic_unwind/lib.rs --cfg llvm_libunwind $ mkdir -p ${destdir} $ cp *.rlib ${destdir} From 8b4a00685560919e261061b2ff6a26ec0323e89e Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 14:33:56 +0000 Subject: [PATCH 0092/2457] runtime: update smoltcp. --- artiq/firmware/Cargo.lock | 6 +++--- artiq/firmware/runtime/Cargo.toml | 4 ++-- artiq/firmware/runtime/lib.rs | 17 +++++++++++------ 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 353118496..0fcaac872 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -165,7 +165,7 @@ dependencies = [ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "logger_artiq 0.0.0", "proto 0.0.0", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=960b001)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)", "std_artiq 0.0.0", ] @@ -200,7 +200,7 @@ dependencies = [ [[package]] name = "smoltcp" version = "0.4.0" -source = "git+https://github.com/m-labs/smoltcp?rev=960b001#960b0012a09d37dde1d86b28bb5531316f606bfd" +source = "git+https://github.com/m-labs/smoltcp?rev=507d2fe#507d2fe0ea390ec309d2e900a9d0d4a70a3dfa3c" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -245,7 +245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)" = "" "checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" -"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=960b001)" = "" +"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)" = "" "checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index f9db55dee..00f1ca121 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -38,6 +38,6 @@ features = ["alloc"] [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "960b001" +rev = "507d2fe" default-features = false -features = ["alloc", "log", "socket-tcp"] +features = ["alloc", "log", "proto-ipv4", "socket-tcp"] diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index 784a42f45..fba23d853 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -141,7 +141,7 @@ fn startup_ethernet() { // where U: smoltcp::wire::pretty_print::PrettyPrint { // let seconds = timestamp / 1000; // let micros = timestamp % 1000 * 1000; - // print!("\x1b[37m[{:6}.{:06}s]\n{}\x1b[0m", seconds, micros, printer) + // print!("\x1b[37m[{:6}.{:06}s]\n{}\x1b[0m\n", seconds, micros, printer) // } let net_device = unsafe { ethmac::EthernetDevice::new() }; @@ -193,11 +193,16 @@ fn startup_ethernet() { loop { scheduler.run(); - match interface.poll(&mut *borrow_mut!(scheduler.sockets()), - board::clock::get_ms()) { - Ok(_poll_at) => (), - Err(smoltcp::Error::Unrecognized) => (), - Err(err) => warn!("network error: {}", err) + { + let sockets = &mut *borrow_mut!(scheduler.sockets()); + loop { + match interface.poll(sockets, board::clock::get_ms()) { + Ok(true) => (), + Ok(false) => break, + Err(smoltcp::Error::Unrecognized) => (), + Err(err) => warn!("network error: {}", err) + } + } } if let Some(_net_stats_diff) = net_stats.update() { From fd6d97f052d3574365dfe6699e660d38180345e2 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 15:41:03 +0000 Subject: [PATCH 0093/2457] artiq_devtool: set ServerAliveInterval. --- artiq/frontend/artiq_devtool.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 8c5b0ac01..a2c5bbfd1 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -136,6 +136,7 @@ def main(): lock() transport = client.get_transport() + transport.set_keepalive(30) def forwarder(local_stream, remote_stream): try: From a0a2650fca8dc9840ef0ab9d1d64c58b06e008dd Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 16:24:57 +0000 Subject: [PATCH 0094/2457] compiler: do not use invoke for calls to nounwind ffi functions. Otherwise, declarations such as: @syscall(flags={"nounwind", "nowrite"}) def foo(...): trip an LLVM assert because the invoke instruction and the !tbaa metadata are no longer compatible since LLVM 4.0. --- artiq/compiler/transforms/artiq_ir_generator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index a1bc76956..f2e9d5bd3 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1812,7 +1812,8 @@ class ARTIQIRGenerator(algorithm.Visitor): assert None not in args - if self.unwind_target is None: + if self.unwind_target is None or \ + types.is_function(callee.type) and "nounwind" in callee.type.flags: insn = self.append(ir.Call(func, args, arg_exprs)) else: after_invoke = self.add_block("invoke") From b31b59f7ca438511d6b8221e2afddb4e6fd71348 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 16:25:19 +0000 Subject: [PATCH 0095/2457] compiler: update for llvmlite 0.20.0. --- artiq/compiler/transforms/llvm_ir_generator.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 726528dee..db221f264 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -270,7 +270,7 @@ class LLVMIRGenerator: sanitized_str = re.sub(rb"[^a-zA-Z0-9_.]", b"", as_bytes[:20]).decode('ascii') name = self.llmodule.get_unique_name("S.{}".format(sanitized_str)) - llstr = self.llmodule.get_global(name) + llstr = self.llmodule.globals.get(name) if llstr is None: llstrty = ll.ArrayType(lli8, len(as_bytes)) llstr = ll.GlobalVariable(self.llmodule, llstrty, name) @@ -306,7 +306,7 @@ class LLVMIRGenerator: assert False def llbuiltin(self, name): - llglobal = self.llmodule.get_global(name) + llglobal = self.llmodule.globals.get(name) if llglobal is not None: return llglobal @@ -458,7 +458,7 @@ class LLVMIRGenerator: assert False def get_function(self, typ, name): - llfun = self.llmodule.get_global(name) + llfun = self.llmodule.globals.get(name) if llfun is None: llfunty = self.llty_of_type(typ, bare=True) llfun = ll.Function(self.llmodule, llfunty, name) @@ -499,7 +499,7 @@ class LLVMIRGenerator: llobjects = defaultdict(lambda: []) for obj_id, obj_ref, obj_typ in self.embedding_map.iter_objects(): - llobject = self.llmodule.get_global("O.{}".format(obj_id)) + llobject = self.llmodule.globals.get("O.{}".format(obj_id)) if llobject is not None: llobjects[obj_typ].append(llobject.bitcast(llptr)) @@ -1209,7 +1209,7 @@ class LLVMIRGenerator: llargs.append(llarg) llfunname = insn.target_function().type.name - llfun = self.llmodule.get_global(llfunname) + llfun = self.llmodule.globals.get(llfunname) if llfun is None: llretty = self.llty_of_type(insn.type, for_return=True) if self.needs_sret(llretty): @@ -1643,7 +1643,7 @@ class LLVMIRGenerator: llclauseexnname = self.llconst_of_const( ir.Constant(exnname, builtins.TStr())) - llclauseexnnameptr = self.llmodule.get_global("exn.{}".format(exnname)) + llclauseexnnameptr = self.llmodule.globals.get("exn.{}".format(exnname)) if llclauseexnnameptr is None: llclauseexnnameptr = ll.GlobalVariable(self.llmodule, llclauseexnname.type, name="exn.{}".format(exnname)) From a2bc12da685529112888743b734f41ea10d539ce Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 21:13:46 +0000 Subject: [PATCH 0096/2457] Only print gateware/software mismatch warning once per process. --- artiq/coredevice/comm_kernel.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 2731ffd4d..2a2a7f560 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -136,6 +136,8 @@ class CommKernelDummy: class CommKernel: + warned_of_mismatch = False + def __init__(self, host, port=1381): self._read_type = None self.host = host @@ -284,10 +286,11 @@ class CommKernel: .format(runtime_id)) gateware_version = self._read_string() - if gateware_version != software_version: + if gateware_version != software_version and not self.warned_of_mismatch: logger.warning("Mismatch between gateware (%s) " "and software (%s) versions", gateware_version, software_version) + CommKernel.warned_of_mismatch = True finished_cleanly = self._read_bool() if not finished_cleanly: From 9aec64093bfbcb480ecea5831d847ee6d1137619 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 21:35:08 +0000 Subject: [PATCH 0097/2457] compiler: do not ever emit !tbaa on invoke instructions. --- artiq/compiler/transforms/llvm_ir_generator.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index db221f264..57d60b429 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -1448,9 +1448,8 @@ class LLVMIRGenerator: llcall = self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock, name=insn.name) - # See the comment in process_Call. - if types.is_c_function(functiontyp) and 'nowrite' in functiontyp.flags: - llcall.set_metadata('tbaa', self.tbaa_nowrite_call) + # The !tbaa metadata is not legal to use with the invoke instruction, + # so unlike process_Call, we do not set it here. return llcall From 40ca0ac83f0b9a09a854f173423b9367d6c4e74d Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 21:46:20 +0000 Subject: [PATCH 0098/2457] conda: update llvmlite-artiq dependency. --- conda/artiq-dev/meta.yaml | 2 +- conda/artiq/meta.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 78de72bf7..5830885a4 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -19,7 +19,7 @@ requirements: - jesd204b 0.4 - binutils-or1k-linux >=2.27 - llvm-or1k 4.0.1 - - llvmlite-artiq 0.12.0 + - llvmlite-artiq 0.20.0 - rust-core-or1k 1.22.1 17 - cargo 0.11.0 - openocd 0.10.0+git1 diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index 00690d38d..3ba815985 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -26,7 +26,7 @@ requirements: - setuptools 33.1.1 run: - python >=3.5.3,<3.6 - - llvmlite-artiq 0.12.0 + - llvmlite-artiq 0.20.0 - binutils-or1k-linux - pythonparser >=1.1 - openocd 0.10.0+git1 From edfacbd0634228d2848943abf3bdc3bfa26acd54 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 21:50:31 +0000 Subject: [PATCH 0099/2457] conda: ship runtime.elf in board-specific packages. This is so that backtraces may be symbolized. --- artiq/firmware/runtime/lib.rs | 3 ++- conda/artiq-kc705-nist_clock/build.sh | 2 +- conda/artiq-kc705-nist_qc2/build.sh | 2 +- conda/artiq-sayma_amc-standalone/build.sh | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index fba23d853..a8991557e 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -247,7 +247,8 @@ pub extern fn abort() { pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! { println!("panic at {}:{}: {}", file, line, args); - println!("backtrace:"); + println!("backtrace for software version {}:", + include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); let _ = backtrace_artiq::backtrace(|ip| { println!("{:#08x}", ip); }); diff --git a/conda/artiq-kc705-nist_clock/build.sh b/conda/artiq-kc705-nist_clock/build.sh index f0275be02..880719a42 100644 --- a/conda/artiq-kc705-nist_clock/build.sh +++ b/conda/artiq-kc705-nist_clock/build.sh @@ -6,4 +6,4 @@ mkdir -p $SOC_PREFIX V=1 $PYTHON -m artiq.gateware.targets.kc705_dds -H nist_clock cp misoc_nist_clock_kc705/gateware/top.bit $SOC_PREFIX cp misoc_nist_clock_kc705/software/bios/bios.bin $SOC_PREFIX -cp misoc_nist_clock_kc705/software/runtime/runtime.fbi $SOC_PREFIX +cp misoc_nist_clock_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-kc705-nist_qc2/build.sh b/conda/artiq-kc705-nist_qc2/build.sh index b60f39b3e..403045dfa 100644 --- a/conda/artiq-kc705-nist_qc2/build.sh +++ b/conda/artiq-kc705-nist_qc2/build.sh @@ -6,4 +6,4 @@ mkdir -p $SOC_PREFIX V=1 $PYTHON -m artiq.gateware.targets.kc705_dds -H nist_qc2 cp misoc_nist_qc2_kc705/gateware/top.bit $SOC_PREFIX cp misoc_nist_qc2_kc705/software/bios/bios.bin $SOC_PREFIX -cp misoc_nist_qc2_kc705/software/runtime/runtime.fbi $SOC_PREFIX +cp misoc_nist_qc2_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-sayma_amc-standalone/build.sh b/conda/artiq-sayma_amc-standalone/build.sh index aa116befb..f256da963 100644 --- a/conda/artiq-sayma_amc-standalone/build.sh +++ b/conda/artiq-sayma_amc-standalone/build.sh @@ -6,4 +6,4 @@ mkdir -p $SOC_PREFIX V=1 $PYTHON -m artiq.gateware.targets.sayma_amc_standalone --rtm-csr-csv $SP_DIR/artiq/binaries/sayma_rtm/sayma_rtm_csr.csv cp misoc_standalone_sayma_amc/gateware/top.bit $SOC_PREFIX cp misoc_standalone_sayma_amc/software/bios/bios.bin $SOC_PREFIX -cp misoc_standalone_sayma_amc/software/runtime/runtime.fbi $SOC_PREFIX +cp misoc_standalone_sayma_amc/software/runtime/runtime.{elf,fbi} $SOC_PREFIX From 355acb5e132cfa727b52f07e6d9554b5e05d5f2c Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 21:55:22 +0000 Subject: [PATCH 0100/2457] compiler: fix typo in a0a2650f. --- artiq/compiler/transforms/artiq_ir_generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index f2e9d5bd3..a2f1971dc 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1813,7 +1813,7 @@ class ARTIQIRGenerator(algorithm.Visitor): assert None not in args if self.unwind_target is None or \ - types.is_function(callee.type) and "nounwind" in callee.type.flags: + types.is_c_function(callee.type) and "nounwind" in callee.type.flags: insn = self.append(ir.Call(func, args, arg_exprs)) else: after_invoke = self.add_block("invoke") From f46a58f5b23f8a591685f93e8aadc621f4790a81 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 27 Dec 2017 01:44:16 +0000 Subject: [PATCH 0101/2457] conda: bump rustc version requirement. --- conda/artiq-dev/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 5830885a4..a00d82173 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -20,8 +20,8 @@ requirements: - binutils-or1k-linux >=2.27 - llvm-or1k 4.0.1 - llvmlite-artiq 0.20.0 - - rust-core-or1k 1.22.1 17 - - cargo 0.11.0 + - rustc 1.22.1 17 + - rust-core-or1k 1.22.1 18 - openocd 0.10.0+git1 - lit - outputcheck From bd47a0371fecfe024a001be924711384c788329d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 27 Dec 2017 10:52:41 +0800 Subject: [PATCH 0102/2457] RELEASE_NOTES: add 3.2 entry --- RELEASE_NOTES.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 890552f1b..19f2e71b9 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -14,6 +14,14 @@ Release notes * ``artiq_flash --adapter`` has been changed to ``artiq_flash --variant``. +3.2 +--- + +* To accommodate larger runtimes, the flash layout as changed. As a result, the + contents of the flash storage will be lost when upgrading. Set the values back + (IP, MAC address, startup kernel, etc.) after the upgrade. + + 3.1 --- From 4d915ad15beddca5aa8ef6ff741379bbbb37c962 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 27 Dec 2017 01:52:27 +0000 Subject: [PATCH 0103/2457] compiler: do not permit str(...). (#878) --- artiq/compiler/transforms/inferencer.py | 5 +++++ artiq/test/lit/inferencer/error_builtin_calls.py | 3 +++ 2 files changed, 8 insertions(+) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index c4fb07b94..5c54f235c 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -682,6 +682,11 @@ class Inferencer(algorithm.Visitor): pass else: diagnose(valid_forms()) + elif types.is_builtin(typ, "str"): + diag = diagnostic.Diagnostic("error", + "strings currently cannot be constructed", {}, + node.loc) + self.engine.process(diag) elif types.is_builtin(typ, "list") or types.is_builtin(typ, "array"): if types.is_builtin(typ, "list"): valid_forms = lambda: [ diff --git a/artiq/test/lit/inferencer/error_builtin_calls.py b/artiq/test/lit/inferencer/error_builtin_calls.py index f3d8b7df8..bb1b8ca04 100644 --- a/artiq/test/lit/inferencer/error_builtin_calls.py +++ b/artiq/test/lit/inferencer/error_builtin_calls.py @@ -9,3 +9,6 @@ list(1) # CHECK-L: ${LINE:+1}: error: the arguments of min() must be of a numeric type min([1], [1]) + +# CHECK-L: ${LINE:+1}: error: strings currently cannot be constructed +str(1) From 5a2cbe708834e08c7f2d5935e04c7e0410bb0139 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 27 Dec 2017 04:25:46 +0000 Subject: [PATCH 0104/2457] runtime: remove borrow_mut!() in favor of backtraces. --- artiq/firmware/runtime/lib.rs | 11 +---------- artiq/firmware/runtime/sched.rs | 23 ++++++++++++----------- artiq/firmware/runtime/session.rs | 6 +++--- 3 files changed, 16 insertions(+), 24 deletions(-) diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index a8991557e..c30c6c8d5 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -26,15 +26,6 @@ use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; use proto::{mgmt_proto, analyzer_proto, moninj_proto, rpc_proto, session_proto, kernel_proto}; use amp::{mailbox, rpc_queue}; -macro_rules! borrow_mut { - ($x:expr) => ({ - match $x.try_borrow_mut() { - Ok(x) => x, - Err(_) => panic!("cannot borrow mutably at {}:{}", file!(), line!()) - } - }) -} - mod config; #[cfg(has_ethmac)] mod ethmac; @@ -194,7 +185,7 @@ fn startup_ethernet() { scheduler.run(); { - let sockets = &mut *borrow_mut!(scheduler.sockets()); + let sockets = &mut *scheduler.sockets().borrow_mut(); loop { match interface.poll(sockets, board::clock::get_ms()) { Ok(true) => (), diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index 1a6ce55b4..82738e9c4 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -124,7 +124,7 @@ impl Scheduler { pub fn run(&mut self) { self.sockets.borrow_mut().prune(); - self.threads.append(&mut *borrow_mut!(self.spawned)); + self.threads.append(&mut *self.spawned.borrow_mut()); if self.threads.len() == 0 { return } let now = board::clock::get_ms(); @@ -133,7 +133,7 @@ impl Scheduler { self.run_idx = (self.run_idx + 1) % self.threads.len(); let result = { - let mut thread = borrow_mut!(self.threads[self.run_idx].0); + let mut thread = self.threads[self.run_idx].0.borrow_mut(); match thread.waiting_for { _ if thread.interrupted => { thread.interrupted = false; @@ -164,7 +164,7 @@ impl Scheduler { }, Some(wait_request) => { // The thread has suspended itself. - let mut thread = borrow_mut!(self.threads[self.run_idx].0); + let mut thread = self.threads[self.run_idx].0.borrow_mut(); thread.waiting_for = wait_request } } @@ -189,7 +189,7 @@ impl<'a> Io<'a> { pub fn spawn(&self, stack_size: usize, f: F) -> ThreadHandle where F: 'static + FnOnce(Io) + Send { let handle = unsafe { Thread::new(self, stack_size, f) }; - borrow_mut!(self.spawned).push(handle.clone()); + self.spawned.borrow_mut().push(handle.clone()); handle } @@ -241,7 +241,7 @@ macro_rules! until { ($socket:expr, $ty:ty, |$var:ident| $cond:expr) => ({ let (sockets, handle) = ($socket.io.sockets.clone(), $socket.handle); $socket.io.until(move || { - let mut sockets = borrow_mut!(sockets); + let mut sockets = sockets.borrow_mut(); let $var = sockets.get::<$ty>(handle); $cond }) @@ -269,7 +269,8 @@ impl<'a> TcpListener<'a> { fn new_lower(io: &'a Io<'a>, buffer_size: usize) -> SocketHandle { let rx_buffer = vec![0; buffer_size]; let tx_buffer = vec![0; buffer_size]; - borrow_mut!(io.sockets) + io.sockets + .borrow_mut() .add(TcpSocketLower::new( TcpSocketBuffer::new(rx_buffer), TcpSocketBuffer::new(tx_buffer))) @@ -286,7 +287,7 @@ impl<'a> TcpListener<'a> { fn with_lower(&self, f: F) -> R where F: FnOnce(SocketRef) -> R { - let mut sockets = borrow_mut!(self.io.sockets); + let mut sockets = self.io.sockets.borrow_mut(); let result = f(sockets.get(self.handle.get())); result } @@ -327,7 +328,7 @@ impl<'a> TcpListener<'a> { // that still counts as accepting even though nothing may be sent. let (sockets, handle) = (self.io.sockets.clone(), self.handle.get()); self.io.until(move || { - let mut sockets = borrow_mut!(sockets); + let mut sockets = sockets.borrow_mut(); let socket = sockets.get::(handle); socket.may_send() || socket.may_recv() })?; @@ -352,7 +353,7 @@ impl<'a> TcpListener<'a> { impl<'a> Drop for TcpListener<'a> { fn drop(&mut self) { self.with_lower(|mut s| s.close()); - borrow_mut!(self.io.sockets).release(self.handle.get()) + self.io.sockets.borrow_mut().release(self.handle.get()) } } @@ -377,7 +378,7 @@ impl<'a> TcpStream<'a> { fn with_lower(&self, f: F) -> R where F: FnOnce(SocketRef) -> R { - let mut sockets = borrow_mut!(self.io.sockets); + let mut sockets = self.io.sockets.borrow_mut(); let result = f(sockets.get(self.handle)); result } @@ -496,6 +497,6 @@ impl<'a> Write for TcpStream<'a> { impl<'a> Drop for TcpStream<'a> { fn drop(&mut self) { self.with_lower(|mut s| s.close()); - borrow_mut!(self.io.sockets).release(self.handle) + self.io.sockets.borrow_mut().release(self.handle) } } diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 263933765..349ba782f 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -634,7 +634,7 @@ pub fn thread(io: Io) { { let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { - let mut congress = borrow_mut!(congress); + let mut congress = congress.borrow_mut(); info!("running startup kernel"); match flash_kernel_worker(&io, &mut congress, "startup_kernel") { Ok(()) => info!("startup kernel finished"), @@ -669,7 +669,7 @@ pub fn thread(io: Io) { let congress = congress.clone(); let stream = stream.into_handle(); respawn(&io, &mut kernel_thread, move |io| { - let mut congress = borrow_mut!(congress); + let mut congress = congress.borrow_mut(); let mut stream = TcpStream::from_handle(&io, stream); match host_kernel_worker(&io, &mut stream, &mut *congress) { Ok(()) => (), @@ -692,7 +692,7 @@ pub fn thread(io: Io) { let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { - let mut congress = borrow_mut!(congress); + let mut congress = congress.borrow_mut(); match flash_kernel_worker(&io, &mut *congress, "idle_kernel") { Ok(()) => info!("idle kernel finished, standing by"), From d7cb4963e16a78f756509fea8ee1f51da54c4fee Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 27 Dec 2017 19:14:41 +0000 Subject: [PATCH 0105/2457] firmware: prepare config block for access from BIOS/bootloader. * remove liballoc dependency from mod config, * move mod config to libboard, * move config sector immediately after BIOS sector. --- artiq/firmware/Cargo.lock | 1 + artiq/firmware/libboard/Cargo.toml | 3 +- .../firmware/{runtime => libboard}/config.rs | 63 ++++++------ artiq/firmware/libboard/lib.rs | 6 +- artiq/firmware/libboard/spiflash.rs | 99 +++++++++---------- artiq/firmware/runtime/lib.rs | 3 +- artiq/firmware/runtime/rtio_mgt.rs | 3 +- artiq/firmware/runtime/runtime.ld | 9 -- artiq/firmware/runtime/session.rs | 4 +- artiq/frontend/artiq_flash.py | 31 +++--- conda/artiq-dev/meta.yaml | 2 +- 11 files changed, 105 insertions(+), 119 deletions(-) rename artiq/firmware/{runtime => libboard}/config.rs (82%) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 0fcaac872..36a5db4e9 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -28,6 +28,7 @@ version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "build_artiq 0.0.0", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/artiq/firmware/libboard/Cargo.toml b/artiq/firmware/libboard/Cargo.toml index 825c9cf81..c9eb425fc 100644 --- a/artiq/firmware/libboard/Cargo.toml +++ b/artiq/firmware/libboard/Cargo.toml @@ -12,8 +12,9 @@ path = "lib.rs" build_artiq = { path = "../libbuild_artiq" } [dependencies] +bitflags = "1.0" +byteorder = { version = "1.0", default-features = false } log = { version = "0.3", default-features = false } -bitflags = { version = "1.0" } [features] uart_console = [] diff --git a/artiq/firmware/runtime/config.rs b/artiq/firmware/libboard/config.rs similarity index 82% rename from artiq/firmware/runtime/config.rs rename to artiq/firmware/libboard/config.rs index fd3c14efe..5c673da5b 100644 --- a/artiq/firmware/runtime/config.rs +++ b/artiq/firmware/libboard/config.rs @@ -1,14 +1,17 @@ #[cfg(has_spiflash)] mod imp { use core::str; - use std::btree_map::BTreeMap; use byteorder::{ByteOrder, BigEndian}; - use board::{cache, spiflash}; + use cache; + use spiflash; + + // One flash sector immediately after the bootloader. + const ADDR: usize = ::mem::FLASH_BOOT_ADDRESS - spiflash::PAGE_SIZE; + const SIZE: usize = spiflash::PAGE_SIZE; mod lock { use core::slice; use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; - use board; static LOCKED: AtomicUsize = ATOMIC_USIZE_INIT; @@ -24,22 +27,7 @@ mod imp { } pub fn data(&self) -> &'static [u8] { - extern { - static _ftext: u8; - static _fstorage: u8; - static _estorage: u8; - } - - unsafe { - let base = &_ftext as *const _ as usize; - let begin = &_fstorage as *const _ as usize; - let end = &_estorage as *const _ as usize; - - let ptr = board::mem::FLASH_BOOT_ADDRESS + (begin - base); - let len = end - begin; - - slice::from_raw_parts(ptr as *const u8, len) - } + unsafe { slice::from_raw_parts(super::ADDR as *const u8, super::SIZE) } } } @@ -52,6 +40,7 @@ mod imp { use self::lock::Lock; + #[derive(Clone)] struct Iter<'a> { data: &'a [u8], offset: usize @@ -140,28 +129,39 @@ mod imp { spiflash::write(data.as_ptr() as usize, value); data = &data[value.len()..]; + cache::flush_l2_cache(); + Ok(data) } fn compact() -> Result<(), ()> { let lock = Lock::take()?; - let mut items = BTreeMap::new(); - { - let mut iter = Iter::new(lock.data()); - while let Some(result) = iter.next() { - let (key, value) = result?; - items.insert(key, value); - } - } + static mut OLD_DATA: [u8; SIZE] = [0; SIZE]; + let old_data = unsafe { + OLD_DATA.copy_from_slice(lock.data()); + &OLD_DATA[..] + }; let mut data = lock.data(); - spiflash::erase_sector(data.as_ptr() as usize); - for (key, value) in items { + unsafe { spiflash::erase_sector(data.as_ptr() as usize) }; + + // This is worst-case quadratic, but we're limited by a small SPI flash sector size, + // so it does not really matter. + let mut iter = Iter::new(old_data); + while let Some(result) = iter.next() { + let (key, mut value) = result?; + + let mut next_iter = iter.clone(); + while let Some(next_result) = next_iter.next() { + let (next_key, next_value) = next_result?; + if key == next_key { + value = next_value + } + } data = unsafe { append_at(data, key, value)? }; } - cache::flush_l2_cache(); Ok(()) } @@ -178,7 +178,6 @@ mod imp { unsafe { append_at(free, key.as_bytes(), value)? }; - cache::flush_l2_cache(); Ok(()) } @@ -200,7 +199,7 @@ mod imp { pub fn erase() -> Result<(), ()> { let lock = Lock::take()?; - spiflash::erase_sector(lock.data().as_ptr() as usize); + unsafe { spiflash::erase_sector(lock.data().as_ptr() as usize) }; cache::flush_l2_cache(); Ok(()) diff --git a/artiq/firmware/libboard/lib.rs b/artiq/firmware/libboard/lib.rs index d25a54d80..b25e98837 100644 --- a/artiq/firmware/libboard/lib.rs +++ b/artiq/firmware/libboard/lib.rs @@ -1,10 +1,11 @@ #![feature(asm, lang_items)] #![no_std] -#[macro_use] -extern crate log; #[macro_use] extern crate bitflags; +extern crate byteorder; +#[macro_use] +extern crate log; use core::{cmp, ptr, str}; @@ -21,6 +22,7 @@ pub mod uart_console; #[cfg(has_spiflash)] pub mod spiflash; +pub mod config; pub mod i2c; pub mod spi; diff --git a/artiq/firmware/libboard/spiflash.rs b/artiq/firmware/libboard/spiflash.rs index 26c5cbbc6..643a2160c 100644 --- a/artiq/firmware/libboard/spiflash.rs +++ b/artiq/firmware/libboard/spiflash.rs @@ -3,6 +3,10 @@ use core::cmp; use csr; +pub const PAGE_SIZE: usize = csr::CONFIG_SPIFLASH_PAGE_SIZE as usize; + +const PAGE_MASK: usize = PAGE_SIZE - 1; + const CMD_PP: u8 = 0x02; const CMD_WRDI: u8 = 0x04; const CMD_RDSR: u8 = 0x05; @@ -15,28 +19,24 @@ const PIN_DQ_I: u8 = 1 << 3; const SR_WIP: u8 = 1; -fn write_byte(mut byte: u8) { - unsafe { - csr::spiflash::bitbang_write(0); - for _ in 0..8 { - csr::spiflash::bitbang_write((byte & 0x80) >> 7); - csr::spiflash::bitbang_write((byte & 0x80) >> 7 | PIN_CLK); - byte <<= 1; - } - csr::spiflash::bitbang_write(0); +unsafe fn write_byte(mut byte: u8) { + csr::spiflash::bitbang_write(0); + for _ in 0..8 { + csr::spiflash::bitbang_write((byte & 0x80) >> 7); + csr::spiflash::bitbang_write((byte & 0x80) >> 7 | PIN_CLK); + byte <<= 1; } + csr::spiflash::bitbang_write(0); } -fn write_addr(mut addr: usize) { - unsafe { - csr::spiflash::bitbang_write(0); - for _ in 0..24 { - csr::spiflash::bitbang_write(((addr & 0x800000) >> 23) as u8); - csr::spiflash::bitbang_write(((addr & 0x800000) >> 23) as u8 | PIN_CLK); - addr <<= 1; - } - csr::spiflash::bitbang_write(0); +unsafe fn write_addr(mut addr: usize) { + csr::spiflash::bitbang_write(0); + for _ in 0..24 { + csr::spiflash::bitbang_write(((addr & 0x800000) >> 23) as u8); + csr::spiflash::bitbang_write(((addr & 0x800000) >> 23) as u8 | PIN_CLK); + addr <<= 1; } + csr::spiflash::bitbang_write(0); } fn wait_until_ready() { @@ -59,54 +59,47 @@ fn wait_until_ready() { } } -pub fn erase_sector(addr: usize) { - unsafe { - let sector_addr = addr & !(csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize - 1); +pub unsafe fn erase_sector(addr: usize) { + let sector_addr = addr & !(csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize - 1); - csr::spiflash::bitbang_en_write(1); + csr::spiflash::bitbang_en_write(1); - wait_until_ready(); + wait_until_ready(); - write_byte(CMD_WREN); - csr::spiflash::bitbang_write(PIN_CS_N); + write_byte(CMD_WREN); + csr::spiflash::bitbang_write(PIN_CS_N); - write_byte(CMD_SE); - write_addr(sector_addr); - csr::spiflash::bitbang_write(PIN_CS_N); + write_byte(CMD_SE); + write_addr(sector_addr); + csr::spiflash::bitbang_write(PIN_CS_N); - wait_until_ready(); + wait_until_ready(); - csr::spiflash::bitbang_en_write(0); - } + csr::spiflash::bitbang_en_write(0); } -fn write_page(addr: usize, data: &[u8]) { - unsafe { - csr::spiflash::bitbang_en_write(1); +unsafe fn write_page(addr: usize, data: &[u8]) { + csr::spiflash::bitbang_en_write(1); - wait_until_ready(); + wait_until_ready(); - write_byte(CMD_WREN); - csr::spiflash::bitbang_write(PIN_CS_N); - write_byte(CMD_PP); - write_addr(addr); - for &byte in data { - write_byte(byte) - } - - csr::spiflash::bitbang_write(PIN_CS_N); - csr::spiflash::bitbang_write(0); - - wait_until_ready(); - - csr::spiflash::bitbang_en_write(0); + write_byte(CMD_WREN); + csr::spiflash::bitbang_write(PIN_CS_N); + write_byte(CMD_PP); + write_addr(addr); + for &byte in data { + write_byte(byte) } + + csr::spiflash::bitbang_write(PIN_CS_N); + csr::spiflash::bitbang_write(0); + + wait_until_ready(); + + csr::spiflash::bitbang_en_write(0); } -const PAGE_SIZE: usize = csr::CONFIG_SPIFLASH_PAGE_SIZE as usize; -const PAGE_MASK: usize = PAGE_SIZE - 1; - -pub fn write(mut addr: usize, mut data: &[u8]) { +pub unsafe fn write(mut addr: usize, mut data: &[u8]) { if addr & PAGE_MASK != 0 { let size = cmp::min((PAGE_SIZE - (addr & PAGE_MASK)) as usize, data.len()); write_page(addr, &data[..size]); diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index c30c6c8d5..2723ebb9c 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -23,10 +23,11 @@ extern crate amp; extern crate drtioaux; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; + +use board::config; use proto::{mgmt_proto, analyzer_proto, moninj_proto, rpc_proto, session_proto, kernel_proto}; use amp::{mailbox, rpc_queue}; -mod config; #[cfg(has_ethmac)] mod ethmac; #[cfg(has_rtio_core)] diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 9fd924936..35083315c 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -1,5 +1,4 @@ -use config; -use board::csr; +use board::{csr, config}; use sched::Io; #[cfg(has_rtio_crg)] diff --git a/artiq/firmware/runtime/runtime.ld b/artiq/firmware/runtime/runtime.ld index d629e4ff8..1d21c61fb 100644 --- a/artiq/firmware/runtime/runtime.ld +++ b/artiq/firmware/runtime/runtime.ld @@ -66,15 +66,6 @@ SECTIONS _edata = .; } > runtime - .storage : - { - /* Keep in sync with artiq_flash.py */ - . = _ftext + 0x100000; - _fstorage = .; - . += /*SPIFLASH_SECTOR_SIZE*/ 0x10000; - _estorage = .; - } > runtime - .bss : { . = ALIGN(4); diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 349ba782f..dd1fe3fde 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -8,8 +8,8 @@ use byteorder::{ByteOrder, NetworkEndian}; use urc::Urc; use sched::{ThreadHandle, Io}; use sched::{TcpListener, TcpStream}; -use board; -use {config, mailbox, rpc_queue, kernel}; +use board::{self, config}; +use {mailbox, rpc_queue, kernel}; #[cfg(has_rtio_core)] use rtio_mgt; use rtio_dma::Manager as DmaManager; diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 4e7e85eb3..112340428 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -20,9 +20,9 @@ Valid actions: * proxy: load the flash proxy gateware bitstream * gateware: write gateware bitstream to flash - * bios: write bios to flash - * runtime: write runtime to flash + * bootloader: write bootloader to flash * storage: write storage image to flash + * runtime: write runtime to flash * load: load gateware bitstream into device (volatile but fast) * start: trigger the target to (re)load its gateware bitstream from flash @@ -48,7 +48,7 @@ Prerequisites: parser.add_argument("--srcbuild", help="look for bitstream, BIOS and runtime in this " "ARTIQ source build tree") parser.add_argument("action", metavar="ACTION", nargs="*", - default="proxy gateware bios runtime start".split(), + default="proxy gateware bootloader runtime start".split(), help="actions to perform, default: %(default)s") return parser @@ -188,25 +188,24 @@ def main(): parser = get_argparser() opts = parser.parse_args() - storage_at = 0x100000 # Keep in sync with runtime.ld config = { "kc705": { "programmer_factory": partial(ProgrammerJtagSpi7, "kc705"), "proxy_bitfile": "bscan_spi_xc7k325t.bit", "variants": ["nist_clock", "nist_qc2"], - "gateware": (0, 0x000000), - "bios": (0, 0xaf0000), - "runtime": (0, 0xb00000), - "storage": (0, 0xb00000 + storage_at), + "gateware": (0, 0x000000), + "bootloader": (0, 0xaf0000), + "storage": (0, 0xb00000), + "runtime": (0, 0xb10000), }, "sayma": { "programmer_factory": ProgrammerSayma, "proxy_bitfile": "bscan_spi_xcku040-sayma.bit", "variants": ["standalone"], - "gateware": (0, 0x000000), - "bios": (1, 0x000000), - "runtime": (1, 0x010000), - "storage": (1, 0x010000 + storage_at), + "gateware": (0, 0x000000), + "bootloader": (1, 0x000000), + "storage": (1, 0x010000), + "runtime": (1, 0x020000), }, }[opts.target] @@ -256,20 +255,20 @@ def main(): bit2bin(f, g) conv = True programmer.flash_binary(*config["gateware"], bin) - elif action == "bios": + elif action == "bootloader": if opts.srcbuild is None: path = bin_dir else: path = os.path.join(opts.srcbuild, "software", "bios") - programmer.flash_binary(*config["bios"], os.path.join(path, "bios.bin")) + programmer.flash_binary(*config["bootloader"], os.path.join(path, "bios.bin")) + elif action == "storage": + programmer.flash_binary(*config["storage"], opts.storage) elif action == "runtime": if opts.srcbuild is None: path = bin_dir else: path = os.path.join(opts.srcbuild, "software", "runtime") programmer.flash_binary(*config["runtime"], os.path.join(path, "runtime.fbi")) - elif action == "storage": - programmer.flash_binary(*config["storage"], opts.storage) elif action == "load": if opts.srcbuild is None: path = bin_dir diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index a00d82173..23f86a710 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6.dev py35_50+git82b06ee - - misoc 0.8.dev py35_30+gitd95f4edb + - misoc 0.8.dev py35_35+git6845fc0a - jesd204b 0.4 - binutils-or1k-linux >=2.27 - llvm-or1k 4.0.1 From 68f128944a63cba79c533646432f913b1a96a94f Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 27 Dec 2017 23:04:40 +0000 Subject: [PATCH 0106/2457] firmware: clean up makefiles. --- artiq/firmware/ksupport/Makefile | 12 ++---------- artiq/firmware/runtime/Makefile | 18 +++++------------- artiq/firmware/satman/Makefile | 16 ++++------------ conda/artiq-dev/meta.yaml | 2 +- 4 files changed, 12 insertions(+), 36 deletions(-) diff --git a/artiq/firmware/ksupport/Makefile b/artiq/firmware/ksupport/Makefile index 718b2c639..ff93ec31f 100644 --- a/artiq/firmware/ksupport/Makefile +++ b/artiq/firmware/ksupport/Makefile @@ -5,7 +5,6 @@ CFLAGS += \ -I$(LIBUNWIND_DIRECTORY) \ -I$(LIBUNWIND_DIRECTORY)/../unwinder/include \ -I$(MISOC_DIRECTORY)/software/include/dyld -CFLAGS += -DNDEBUG LDFLAGS += --eh-frame-hdr \ -L../libcompiler-rt \ @@ -15,22 +14,15 @@ LDFLAGS += --eh-frame-hdr \ RUSTFLAGS += -Cpanic=unwind -all: ksupport.elf +all:: ksupport.elf .PHONY: $(RUSTOUT)/libksupport.a $(RUSTOUT)/libksupport.a: $(cargo) --manifest-path $(KSUPPORT_DIRECTORY)/Cargo.toml ksupport.elf: $(RUSTOUT)/libksupport.a glue.o - $(LD) $(LDFLAGS) -T $(KSUPPORT_DIRECTORY)/ksupport.ld -o $@ $^ \ + $(link) -T $(KSUPPORT_DIRECTORY)/ksupport.ld \ -lunwind-elf -lcompiler-rt -lbase -lm - @chmod -x $@ %.o: $(KSUPPORT_DIRECTORY)/%.c $(compile) - -clean: - $(RM) *.o ksupport.elf - $(RM) -rf cargo - -.PHONY: all clean diff --git a/artiq/firmware/runtime/Makefile b/artiq/firmware/runtime/Makefile index 187793ae4..8e33691d2 100644 --- a/artiq/firmware/runtime/Makefile +++ b/artiq/firmware/runtime/Makefile @@ -3,36 +3,28 @@ include $(MISOC_DIRECTORY)/software/common.mak CFLAGS += \ -I$(LIBUNWIND_DIRECTORY) \ - -I$(LIBUNWIND_DIRECTORY)/../unwinder/include \ + -I$(LIBUNWIND_DIRECTORY)/../unwinder/include LDFLAGS += -L../libbase \ -L../libunwind RUSTFLAGS += -Cpanic=abort -all: runtime.bin runtime.fbi +all:: runtime.bin runtime.fbi .PHONY: $(RUSTOUT)/libruntime.a $(RUSTOUT)/libruntime.a: $(cargo) --manifest-path $(RUNTIME_DIRECTORY)/Cargo.toml runtime.elf: $(RUSTOUT)/libruntime.a ksupport_data.o - $(LD) $(LDFLAGS) -T $(RUNTIME_DIRECTORY)/runtime.ld -o $@ $^ \ + $(link) -T $(RUNTIME_DIRECTORY)/runtime.ld \ -lunwind-bare - @chmod -x $@ ksupport_data.o: ../ksupport/ksupport.elf $(LD) -r -b binary -o $@ $< %.bin: %.elf - $(OBJCOPY) -O binary $< $@ - @chmod -x $@ + $(objcopy) -O binary %.fbi: %.bin - @echo " MSCIMG " $@ && $(PYTHON) -m misoc.tools.mkmscimg -f -o $@ $< - -clean: - $(RM) *.o runtime.elf runtime.bin runtime.fbi - $(RM) -rf cargo - -.PHONY: all clean + $(mscimg) -f diff --git a/artiq/firmware/satman/Makefile b/artiq/firmware/satman/Makefile index 703490663..b96938d1b 100644 --- a/artiq/firmware/satman/Makefile +++ b/artiq/firmware/satman/Makefile @@ -5,25 +5,17 @@ LDFLAGS += -L../libbase RUSTFLAGS += -Cpanic=abort -all: satman.bin satman.fbi +all:: satman.bin satman.fbi .PHONY: $(RUSTOUT)/libsatman.a $(RUSTOUT)/libsatman.a: $(cargo) --manifest-path $(SATMAN_DIRECTORY)/Cargo.toml satman.elf: $(RUSTOUT)/libsatman.a - $(LD) $(LDFLAGS) -T $(SATMAN_DIRECTORY)/satman.ld -o $@ $^ - @chmod -x $@ + $(link) -T $(SATMAN_DIRECTORY)/satman.ld %.bin: %.elf - $(OBJCOPY) -O binary $< $@ - @chmod -x $@ + $(objcopy) -O binary %.fbi: %.bin - @echo " MSCIMG " $@ && $(PYTHON) -m misoc.tools.mkmscimg -f -o $@ $< - -clean: - $(RM) satman.elf satman.bin satman.fbi - $(RM) -rf cargo - -.PHONY: all clean + $(mscimg) -f diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 23f86a710..63cc5b328 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6.dev py35_50+git82b06ee - - misoc 0.8.dev py35_35+git6845fc0a + - misoc 0.8.dev py35_39+git4126dedf - jesd204b 0.4 - binutils-or1k-linux >=2.27 - llvm-or1k 4.0.1 From 4dfe71676efd8e19cf113f51752732b6cf200d92 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 02:20:08 +0000 Subject: [PATCH 0107/2457] firmware: remove dependency on libbase. --- artiq/firmware/Cargo.lock | 14 ++ artiq/firmware/ksupport/Cargo.toml | 1 + artiq/firmware/ksupport/Makefile | 4 +- artiq/firmware/ksupport/glue.c | 2 + artiq/firmware/ksupport/ksupport.ld | 37 +-- artiq/firmware/ksupport/lib.rs | 10 +- artiq/firmware/libboard/Cargo.toml | 1 + artiq/firmware/libboard/boot.rs | 6 +- artiq/firmware/libboard/build.rs | 9 + artiq/firmware/libboard/lib.rs | 1 + artiq/firmware/libboard/vectors.S | 374 ++++++++++++++++++++++++++++ artiq/firmware/runtime/Makefile | 2 +- artiq/firmware/runtime/lib.rs | 2 +- artiq/firmware/runtime/runtime.ld | 41 +-- 14 files changed, 437 insertions(+), 67 deletions(-) create mode 100644 artiq/firmware/libboard/vectors.S diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 36a5db4e9..f6d660460 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -29,6 +29,7 @@ dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "build_artiq 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -44,6 +45,11 @@ name = "byteorder" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cc" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "compiler_builtins" version = "0.1.0" @@ -106,6 +112,7 @@ dependencies = [ "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dyld 0.0.0", "proto 0.0.0", + "rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "std_artiq 0.0.0", ] @@ -149,6 +156,11 @@ dependencies = [ "std_artiq 0.0.0", ] +[[package]] +name = "rlibc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "runtime" version = "0.0.0" @@ -235,6 +247,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" +"checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" "checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)" = "" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" "checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "" @@ -244,6 +257,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" "checksum managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)" = "" +"checksum rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" "checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)" = "" diff --git a/artiq/firmware/ksupport/Cargo.toml b/artiq/firmware/ksupport/Cargo.toml index c785d0aa3..d808e4af7 100644 --- a/artiq/firmware/ksupport/Cargo.toml +++ b/artiq/firmware/ksupport/Cargo.toml @@ -13,6 +13,7 @@ crate-type = ["staticlib"] build_artiq = { path = "../libbuild_artiq" } [dependencies] +rlibc = "1.0" byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } alloc_stub = { path = "../liballoc_stub" } diff --git a/artiq/firmware/ksupport/Makefile b/artiq/firmware/ksupport/Makefile index ff93ec31f..b2ad9410c 100644 --- a/artiq/firmware/ksupport/Makefile +++ b/artiq/firmware/ksupport/Makefile @@ -8,8 +8,8 @@ CFLAGS += \ LDFLAGS += --eh-frame-hdr \ -L../libcompiler-rt \ - -L../libbase \ -L../libm \ + -L../libprintf \ -L../libunwind RUSTFLAGS += -Cpanic=unwind @@ -22,7 +22,7 @@ $(RUSTOUT)/libksupport.a: ksupport.elf: $(RUSTOUT)/libksupport.a glue.o $(link) -T $(KSUPPORT_DIRECTORY)/ksupport.ld \ - -lunwind-elf -lcompiler-rt -lbase -lm + -lunwind-elf -lprintf-float -lm -lcompiler-rt %.o: $(KSUPPORT_DIRECTORY)/%.c $(compile) diff --git a/artiq/firmware/ksupport/glue.c b/artiq/firmware/ksupport/glue.c index 475e22a84..4e4ce318d 100644 --- a/artiq/firmware/ksupport/glue.c +++ b/artiq/firmware/ksupport/glue.c @@ -19,6 +19,8 @@ void send_to_rtio_log(long long int timestamp, struct slice data); #define KERNELCPU_LAST_ADDRESS 0x4fffffff #define KSUPPORT_HEADER_SIZE 0x80 +FILE *stderr; + /* called by libunwind */ int fprintf(FILE *stream, const char *fmt, ...) { diff --git a/artiq/firmware/ksupport/ksupport.ld b/artiq/firmware/ksupport/ksupport.ld index 333db0739..48b6978f2 100644 --- a/artiq/firmware/ksupport/ksupport.ld +++ b/artiq/firmware/ksupport/ksupport.ld @@ -1,8 +1,6 @@ INCLUDE generated/output_format.ld -STARTUP(crt0-or1k.o) -ENTRY(_start) - INCLUDE generated/regions.ld +ENTRY(_reset_handler) /* First 4M of main memory are reserved for runtime * code/data/heap, then comes kernel memory. @@ -17,7 +15,7 @@ MEMORY { } /* Kernel stack is at the end of main RAM. */ -PROVIDE(_fstack = ORIGIN(main_ram) + LENGTH(main_ram) - 4); +_fstack = ORIGIN(main_ram) + LENGTH(main_ram) - 4; /* Force ld to make the ELF header as loadable. */ PHDRS @@ -28,16 +26,18 @@ PHDRS SECTIONS { + .vectors : { + *(.vectors) + } :text + .text : { - _ftext = .; - *(.text .stub .text.* .gnu.linkonce.t.*) - _etext = .; + *(.text .text.*) } :text /* https://sourceware.org/bugzilla/show_bug.cgi?id=20475 */ .got : { - _GLOBAL_OFFSET_TABLE_ = .; + PROVIDE(_GLOBAL_OFFSET_TABLE_ = .); *(.got) } :text @@ -47,11 +47,7 @@ SECTIONS .rodata : { - . = ALIGN(4); - _frodata = .; - *(.rodata .rodata.* .gnu.linkonce.r.*) - *(.rodata1) - _erodata = .; + *(.rodata .rodata.*) } > ksupport .eh_frame : @@ -66,24 +62,13 @@ SECTIONS .data : { - . = ALIGN(4); - _fdata = .; - *(.data .data.* .gnu.linkonce.d.*) - *(.data1) - *(.sdata .sdata.* .gnu.linkonce.s.*) - _edata = .; + *(.data .data.*) } .bss : { - . = ALIGN(4); _fbss = .; - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) + *(.bss .bss.*) . = ALIGN(4); _ebss = .; } diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 29466daea..87b3cec4e 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -1,10 +1,11 @@ #![feature(lang_items, asm, libc, panic_unwind, unwind_attributes, global_allocator)] #![no_std] -extern crate unwind; -extern crate libc; +extern crate rlibc; extern crate byteorder; extern crate cslice; +extern crate unwind; +extern crate libc; extern crate alloc_stub; extern crate std_artiq as std; @@ -492,12 +493,11 @@ pub unsafe fn main() { } #[no_mangle] -pub extern fn exception_handler(vect: u32, _regs: *const u32, pc: u32, ea: u32) { +pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea) } -// We don't export this because libbase does. -// #[no_mangle] +#[no_mangle] pub extern fn abort() { panic!("aborted") } diff --git a/artiq/firmware/libboard/Cargo.toml b/artiq/firmware/libboard/Cargo.toml index c9eb425fc..f7dff2d1b 100644 --- a/artiq/firmware/libboard/Cargo.toml +++ b/artiq/firmware/libboard/Cargo.toml @@ -9,6 +9,7 @@ name = "board" path = "lib.rs" [build-dependencies] +cc = "1.0" build_artiq = { path = "../libbuild_artiq" } [dependencies] diff --git a/artiq/firmware/libboard/boot.rs b/artiq/firmware/libboard/boot.rs index bd54177a0..7e98257b0 100644 --- a/artiq/firmware/libboard/boot.rs +++ b/artiq/firmware/libboard/boot.rs @@ -4,7 +4,7 @@ pub unsafe fn reboot() -> ! { irq::set_ie(false); #[cfg(target_arch="or1k")] asm!(r#" - l.j _ftext + l.j _reset_handler l.nop "# : : : : "volatile"); loop {} @@ -16,8 +16,8 @@ pub unsafe fn hotswap(new_code: &[u8]) -> ! { asm!(r#" # This loop overwrites itself, but it's structured in such a way # that before that happens, it loads itself into I$$ fully. - l.movhi r4, hi(_ftext) - l.ori r4, r4, lo(_ftext) + l.movhi r4, hi(_reset_handler) + l.ori r4, r4, lo(_reset_handler) l.or r7, r4, r0 0: l.sfnei r5, 0 l.bf 1f diff --git a/artiq/firmware/libboard/build.rs b/artiq/firmware/libboard/build.rs index 03ad582f8..6090fad77 100644 --- a/artiq/firmware/libboard/build.rs +++ b/artiq/firmware/libboard/build.rs @@ -1,4 +1,5 @@ extern crate build_artiq; +extern crate cc; use std::env; use std::fs::File; @@ -6,6 +7,13 @@ use std::io::Write; use std::path::PathBuf; use std::process::Command; +fn build_vectors() { + println!("cargo:rerun-if-changed=vectors.S"); + cc::Build::new() + .file("vectors.S") + .compile("vectors"); +} + fn gen_hmc7043_writes() { println!("cargo:rerun-if-changed=hmc7043_gen_writes.py"); println!("cargo:rerun-if-changed=hmc7043_guiexport_6gbps.py"); @@ -25,5 +33,6 @@ fn gen_hmc7043_writes() { fn main() { build_artiq::misoc_cfg(); + build_vectors(); gen_hmc7043_writes(); } diff --git a/artiq/firmware/libboard/lib.rs b/artiq/firmware/libboard/lib.rs index b25e98837..8711cff3c 100644 --- a/artiq/firmware/libboard/lib.rs +++ b/artiq/firmware/libboard/lib.rs @@ -11,6 +11,7 @@ use core::{cmp, ptr, str}; include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/mem.rs")); include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/csr.rs")); +include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/sdram_phy.rs")); pub mod spr; pub mod irq; pub mod cache; diff --git a/artiq/firmware/libboard/vectors.S b/artiq/firmware/libboard/vectors.S new file mode 100644 index 000000000..a92f97a69 --- /dev/null +++ b/artiq/firmware/libboard/vectors.S @@ -0,0 +1,374 @@ +/* + * (C) Copyright 2012, Stefan Kristiansson + * + * This program 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 2 of + * the License, or (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +/* + * OR1K Architecture has a 128 byte "red zone" after the stack that can not be + * touched by exception handlers. GCC uses this red zone for locals and + * temps without needing to change the stack pointer. + */ +#define OR1K_RED_ZONE_SIZE 128 + +/* + * We need 4 bytes (32 bits) * 32 registers space on the stack to save all the + * registers. + */ +#define EXCEPTION_STACK_SIZE ((4*32) + OR1K_RED_ZONE_SIZE) + +#define HANDLE_EXCEPTION ; \ + l.addi r1, r1, -EXCEPTION_STACK_SIZE ; \ + l.sw 0x1c(r1), r9 ; \ + l.jal _exception_handler ; \ + l.nop ; \ + l.lwz r9, 0x1c(r1) ; \ + l.addi r1, r1, EXCEPTION_STACK_SIZE ; \ + l.rfe ; \ + l.nop + + +.section .vectors, "ax", @progbits +.global _reset_handler +_reset_handler: + l.movhi r0, 0 + l.movhi r1, 0 + l.movhi r2, 0 + l.movhi r3, 0 + l.movhi r4, 0 + l.movhi r5, 0 + l.movhi r6, 0 + l.movhi r7, 0 + l.movhi r8, 0 + l.movhi r9, 0 + l.movhi r10, 0 + l.movhi r11, 0 + l.movhi r12, 0 + l.movhi r13, 0 + l.movhi r14, 0 + l.movhi r15, 0 + l.movhi r16, 0 + l.movhi r17, 0 + l.movhi r18, 0 + l.movhi r19, 0 + l.movhi r20, 0 + l.movhi r21, 0 + l.movhi r22, 0 + l.movhi r23, 0 + l.movhi r24, 0 + l.movhi r25, 0 + l.movhi r26, 0 + l.movhi r27, 0 + l.movhi r28, 0 + l.movhi r29, 0 + l.movhi r30, 0 + l.movhi r31, 0 + + l.ori r21, r0, SPR_SR_SM + l.mtspr r0, r21, SPR_SR + l.movhi r21, hi(_reset_handler) + l.ori r21, r21, lo(_reset_handler) + l.mtspr r0, r21, SPR_EVBAR + /* enable caches */ + l.jal _cache_init + l.nop + l.j _crt0 + l.nop + + /* bus error */ + .org 0x200 + HANDLE_EXCEPTION + + /* data page fault */ + .org 0x300 + HANDLE_EXCEPTION + + /* instruction page fault */ + .org 0x400 + HANDLE_EXCEPTION + + /* tick timer */ + .org 0x500 + HANDLE_EXCEPTION + + /* alignment */ + .org 0x600 + HANDLE_EXCEPTION + + /* illegal instruction */ + .org 0x700 + HANDLE_EXCEPTION + + /* external interrupt */ + .org 0x800 + HANDLE_EXCEPTION + + /* D-TLB miss */ + .org 0x900 + HANDLE_EXCEPTION + + /* I-TLB miss */ + .org 0xa00 + HANDLE_EXCEPTION + + /* range */ + .org 0xb00 + HANDLE_EXCEPTION + + /* system call */ + .org 0xc00 + HANDLE_EXCEPTION + + /* floating point */ + .org 0xd00 + HANDLE_EXCEPTION + + /* trap */ + .org 0xe00 + HANDLE_EXCEPTION + + /* reserved */ + .org 0xf00 + HANDLE_EXCEPTION + + .org 0x1000 +_crt0: + /* Setup stack and global pointer */ + l.movhi r1, hi(_fstack) + l.ori r1, r1, lo(_fstack) + + /* Clear BSS */ + l.movhi r21, hi(_fbss) + l.ori r21, r21, lo(_fbss) + l.movhi r3, hi(_ebss) + l.ori r3, r3, lo(_ebss) +.clearBSS: + l.sfeq r21, r3 + l.bf .callMain + l.nop + l.sw 0(r21), r0 + l.addi r21, r21, 4 + l.j .clearBSS + l.nop + +.callMain: + l.j main + l.nop + +_exception_handler: + l.sw 0x00(r1), r2 + l.sw 0x04(r1), r3 + l.sw 0x08(r1), r4 + l.sw 0x0c(r1), r5 + l.sw 0x10(r1), r6 + l.sw 0x14(r1), r7 + l.sw 0x18(r1), r8 + l.sw 0x20(r1), r10 + l.sw 0x24(r1), r11 + l.sw 0x28(r1), r12 + l.sw 0x2c(r1), r13 + l.sw 0x30(r1), r14 + l.sw 0x34(r1), r15 + l.sw 0x38(r1), r16 + l.sw 0x3c(r1), r17 + l.sw 0x40(r1), r18 + l.sw 0x44(r1), r19 + l.sw 0x48(r1), r20 + l.sw 0x4c(r1), r21 + l.sw 0x50(r1), r22 + l.sw 0x54(r1), r23 + l.sw 0x58(r1), r24 + l.sw 0x5c(r1), r25 + l.sw 0x60(r1), r26 + l.sw 0x64(r1), r27 + l.sw 0x68(r1), r28 + l.sw 0x6c(r1), r29 + l.sw 0x70(r1), r30 + l.sw 0x74(r1), r31 + + /* Save return address */ + l.or r14, r0, r9 + /* Calculate exception vector from handler address */ + l.andi r3, r9, 0xf00 + l.srli r3, r3, 8 + /* Pass saved register state */ + l.or r4, r0, r1 + /* Extract exception PC */ + l.mfspr r5, r0, SPR_EPCR_BASE + /* Extract exception effective address */ + l.mfspr r6, r0, SPR_EEAR_BASE + /* Extract exception SR */ + l.mfspr r7, r0, SPR_ESR_BASE + /* Call exception handler with the link address as argument */ + l.jal exception + l.nop + + /* Load return address */ + l.or r9, r0, r14 + /* Restore state */ + l.lwz r2, 0x00(r1) + l.lwz r3, 0x04(r1) + l.lwz r4, 0x08(r1) + l.lwz r5, 0x0c(r1) + l.lwz r6, 0x10(r1) + l.lwz r7, 0x14(r1) + l.lwz r8, 0x18(r1) + l.lwz r10, 0x20(r1) + l.lwz r11, 0x24(r1) + l.lwz r12, 0x28(r1) + l.lwz r13, 0x2c(r1) + l.lwz r14, 0x30(r1) + l.lwz r15, 0x34(r1) + l.lwz r16, 0x38(r1) + l.lwz r17, 0x3c(r1) + l.lwz r18, 0x40(r1) + l.lwz r19, 0x44(r1) + l.lwz r20, 0x48(r1) + l.lwz r21, 0x4c(r1) + l.lwz r22, 0x50(r1) + l.lwz r23, 0x54(r1) + l.lwz r24, 0x58(r1) + l.lwz r25, 0x5c(r1) + l.lwz r26, 0x60(r1) + l.lwz r27, 0x64(r1) + l.lwz r28, 0x68(r1) + l.lwz r29, 0x6c(r1) + l.lwz r30, 0x70(r1) + l.lwz r31, 0x74(r1) + l.jr r9 + l.nop + +.global _cache_init +_cache_init: + /* + This function is to be used ONLY during reset, before main() is called. + TODO: Perhaps break into individual enable instruction/data cache + sections functions, and provide disable functions, also, all + callable from C + */ + + /* Instruction cache enable */ + /* Check if IC present and skip enabling otherwise */ +#if 1 +.L6: + l.mfspr r3,r0,SPR_UPR + l.andi r7,r3,SPR_UPR_ICP + l.sfeq r7,r0 + l.bf .L8 + l.nop + + /* Disable IC */ + l.mfspr r6,r0,SPR_SR + l.addi r5,r0,-1 + l.xori r5,r5,SPR_SR_ICE + l.and r5,r6,r5 + l.mtspr r0,r5,SPR_SR + + /* Establish cache block size + If BS=0, 16; + If BS=1, 32; + r14 contain block size + */ + l.mfspr r3,r0,SPR_ICCFGR + l.andi r7,r3,SPR_ICCFGR_CBS + l.srli r8,r7,7 + l.ori r4,r0,16 + l.sll r14,r4,r8 + + /* Establish number of cache sets + r10 contains number of cache sets + r8 contains log(# of cache sets) + */ + l.andi r7,r3,SPR_ICCFGR_NCS + l.srli r8,r7,3 + l.ori r4,r0,1 + l.sll r10,r4,r8 + + /* Invalidate IC */ + l.addi r6,r0,0 + l.sll r5,r14,r8 + +.L7: l.mtspr r0,r6,SPR_ICBIR + l.sfne r6,r5 + l.bf .L7 + l.add r6,r6,r14 + + /* Enable IC */ + l.mfspr r6,r0,SPR_SR + l.ori r6,r6,SPR_SR_ICE + l.mtspr r0,r6,SPR_SR + l.nop + l.nop + l.nop + l.nop + l.nop + l.nop + l.nop + l.nop + /* Data cache enable */ + /* Check if DC present and skip enabling otherwise */ +#endif +.L8: +#if 1 + l.mfspr r3,r0,SPR_UPR + l.andi r7,r3,SPR_UPR_DCP + l.sfeq r7,r0 + l.bf .L10 + l.nop + /* Disable DC */ + l.mfspr r6,r0,SPR_SR + l.addi r5,r0,-1 + l.xori r5,r5,SPR_SR_DCE + l.and r5,r6,r5 + l.mtspr r0,r5,SPR_SR + /* Establish cache block size + If BS=0, 16; + If BS=1, 32; + r14 contain block size + */ + l.mfspr r3,r0,SPR_DCCFGR + l.andi r7,r3,SPR_DCCFGR_CBS + l.srli r8,r7,7 + l.ori r4,r0,16 + l.sll r14,r4,r8 + /* Establish number of cache sets + r10 contains number of cache sets + r8 contains log(# of cache sets) + */ + l.andi r7,r3,SPR_DCCFGR_NCS + l.srli r8,r7,3 + l.ori r4,r0,1 + l.sll r10,r4,r8 + /* Invalidate DC */ + l.addi r6,r0,0 + l.sll r5,r14,r8 + +.L9: + l.mtspr r0,r6,SPR_DCBIR + l.sfne r6,r5 + l.bf .L9 + l.add r6,r6,r14 + /* Enable DC */ + l.mfspr r6,r0,SPR_SR + l.ori r6,r6,SPR_SR_DCE + l.mtspr r0,r6,SPR_SR +#endif +.L10: + /* Return */ + l.jr r9 + l.nop diff --git a/artiq/firmware/runtime/Makefile b/artiq/firmware/runtime/Makefile index 8e33691d2..a98ccc312 100644 --- a/artiq/firmware/runtime/Makefile +++ b/artiq/firmware/runtime/Makefile @@ -5,7 +5,7 @@ CFLAGS += \ -I$(LIBUNWIND_DIRECTORY) \ -I$(LIBUNWIND_DIRECTORY)/../unwinder/include -LDFLAGS += -L../libbase \ +LDFLAGS += \ -L../libunwind RUSTFLAGS += -Cpanic=abort diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index 2723ebb9c..049d8c12a 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -223,7 +223,7 @@ pub extern fn main() -> i32 { } #[no_mangle] -pub extern fn exception_handler(vect: u32, _regs: *const u32, pc: u32, ea: u32) { +pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea) } diff --git a/artiq/firmware/runtime/runtime.ld b/artiq/firmware/runtime/runtime.ld index 1d21c61fb..67841f91e 100644 --- a/artiq/firmware/runtime/runtime.ld +++ b/artiq/firmware/runtime/runtime.ld @@ -1,8 +1,6 @@ INCLUDE generated/output_format.ld -STARTUP(crt0-or1k.o) -ENTRY(_start) - INCLUDE generated/regions.ld +ENTRY(_reset_handler) /* Assume ORIGIN(main_ram) = 0x40000000. Unfortunately, * ld does not allow this expression here. @@ -13,11 +11,14 @@ MEMORY { SECTIONS { + .vectors : + { + *(.vectors) + } > runtime + .text : { - _ftext = .; - *(.text .stub .text.* .gnu.linkonce.t.*) - _etext = .; + *(.text .text.*) } > runtime .eh_frame : @@ -49,41 +50,23 @@ SECTIONS .rodata : { - . = ALIGN(4); - _frodata = .; - *(.rodata .rodata.* .gnu.linkonce.r.*) - *(.rodata1) - _erodata = .; + *(.rodata .rodata.*) } > runtime .data : { - . = ALIGN(4); - _fdata = .; - *(.data .data.* .gnu.linkonce.d.*) - *(.data1) - *(.sdata .sdata.* .gnu.linkonce.s.*) - _edata = .; + *(.data .data.*) } > runtime - .bss : + .bss ALIGN(4) : { - . = ALIGN(4); _fbss = .; - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - . = ALIGN(4); + *(.bss .bss.*) _ebss = .; } > runtime - .stack : + .stack ALIGN(0x1000) : { - . = ALIGN(0x1000); - _estack = .; . += 0x4000; _fstack = . - 4; } > runtime From 7687a34285e3206023fa5d8bfd298e205d5be7c0 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 03:57:23 +0000 Subject: [PATCH 0108/2457] firmware: remove dependency on compiler-rt. --- artiq/firmware/Cargo.lock | 16 ++++++++-------- artiq/firmware/ksupport/Cargo.toml | 6 +++++- artiq/firmware/ksupport/Makefile | 3 +-- artiq/firmware/ksupport/api.rs | 4 ---- artiq/firmware/ksupport/lib.rs | 5 +++-- artiq/firmware/runtime/Cargo.toml | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index f6d660460..700bc76ee 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -59,6 +59,11 @@ dependencies = [ "rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "compiler_builtins" +version = "0.1.0" +source = "git+https://github.com/m-labs/compiler-builtins?rev=97916b1#97916b17ca542eac0524b8570c7d05913891a0dc" + [[package]] name = "cslice" version = "0.3.0" @@ -109,10 +114,10 @@ dependencies = [ "board 0.0.0", "build_artiq 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dyld 0.0.0", "proto 0.0.0", - "rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "std_artiq 0.0.0", ] @@ -156,11 +161,6 @@ dependencies = [ "std_artiq 0.0.0", ] -[[package]] -name = "rlibc" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "runtime" version = "0.0.0" @@ -171,7 +171,7 @@ dependencies = [ "board 0.0.0", "build_artiq 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)", + "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "drtioaux 0.0.0", "fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)", @@ -248,6 +248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" +"checksum compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)" = "" "checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)" = "" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" "checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "" @@ -257,7 +258,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" "checksum managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)" = "" -"checksum rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" "checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)" = "" diff --git a/artiq/firmware/ksupport/Cargo.toml b/artiq/firmware/ksupport/Cargo.toml index d808e4af7..1162a848c 100644 --- a/artiq/firmware/ksupport/Cargo.toml +++ b/artiq/firmware/ksupport/Cargo.toml @@ -13,7 +13,6 @@ crate-type = ["staticlib"] build_artiq = { path = "../libbuild_artiq" } [dependencies] -rlibc = "1.0" byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } alloc_stub = { path = "../liballoc_stub" } @@ -22,3 +21,8 @@ dyld = { path = "../libdyld" } board = { path = "../libboard" } proto = { path = "../libproto" } amp = { path = "../libamp" } + +[dependencies.compiler_builtins] +git = "https://github.com/m-labs/compiler-builtins" +rev = "97916b1" +features = ["mem"] diff --git a/artiq/firmware/ksupport/Makefile b/artiq/firmware/ksupport/Makefile index b2ad9410c..297bad7bd 100644 --- a/artiq/firmware/ksupport/Makefile +++ b/artiq/firmware/ksupport/Makefile @@ -7,7 +7,6 @@ CFLAGS += \ -I$(MISOC_DIRECTORY)/software/include/dyld LDFLAGS += --eh-frame-hdr \ - -L../libcompiler-rt \ -L../libm \ -L../libprintf \ -L../libunwind @@ -22,7 +21,7 @@ $(RUSTOUT)/libksupport.a: ksupport.elf: $(RUSTOUT)/libksupport.a glue.o $(link) -T $(KSUPPORT_DIRECTORY)/ksupport.ld \ - -lunwind-elf -lprintf-float -lm -lcompiler-rt + -lunwind-elf -lprintf-float -lm %.o: $(KSUPPORT_DIRECTORY)/%.c $(compile) diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 1cf3ce884..d7c079243 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -31,8 +31,6 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(__ltdf2), api!(__nedf2), api!(__gtdf2), - api!(__negsf2), - api!(__negdf2), api!(__addsf3), api!(__subsf3), api!(__mulsf3), @@ -57,8 +55,6 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(__fixdfsi), api!(__fixdfdi), api!(__fixunsdfsi), - api!(__clzsi2), - api!(__ctzsi2), api!(__udivdi3), api!(__umoddi3), api!(__moddi3), diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 87b3cec4e..c6ec95fb2 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -1,7 +1,8 @@ -#![feature(lang_items, asm, libc, panic_unwind, unwind_attributes, global_allocator)] +#![feature(lang_items, asm, libc, panic_unwind, unwind_attributes, global_allocator, + compiler_builtins_lib)] #![no_std] -extern crate rlibc; +extern crate compiler_builtins; extern crate byteorder; extern crate cslice; extern crate unwind; diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 00f1ca121..468ca295d 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -26,8 +26,8 @@ amp = { path = "../libamp" } drtioaux = { path = "../libdrtioaux" } [dependencies.compiler_builtins] -git = "https://github.com/rust-lang-nursery/compiler-builtins" -rev = "631b568" +git = "https://github.com/m-labs/compiler-builtins" +rev = "97916b1" features = ["mem"] [dependencies.fringe] From b443fbd8f71cd5b229e860e74a1a5d1af89bc6a4 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 04:46:27 +0000 Subject: [PATCH 0109/2457] runtime: remove #[repr(simd)] hack. --- artiq/firmware/runtime/analyzer.rs | 12 ++---------- artiq/firmware/runtime/lib.rs | 2 +- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/artiq/firmware/runtime/analyzer.rs b/artiq/firmware/runtime/analyzer.rs index 1e2909a37..f3330fc11 100644 --- a/artiq/firmware/runtime/analyzer.rs +++ b/artiq/firmware/runtime/analyzer.rs @@ -5,18 +5,13 @@ use analyzer_proto::*; const BUFFER_SIZE: usize = 512 * 1024; -// hack until https://github.com/rust-lang/rust/issues/33626 is fixed -#[repr(simd)] -struct Align64(u64, u64, u64, u64, u64, u64, u64, u64); - +#[repr(align(64))] struct Buffer { data: [u8; BUFFER_SIZE], - __alignment: [Align64; 0] } static mut BUFFER: Buffer = Buffer { - data: [0; BUFFER_SIZE], - __alignment: [] + data: [0; BUFFER_SIZE] }; fn arm() { @@ -68,9 +63,6 @@ fn worker(stream: &mut TcpStream) -> io::Result<()> { } pub fn thread(io: Io) { - // verify that the hack above works - assert!(::core::mem::align_of::() == 64); - let listener = TcpListener::new(&io, 65535); listener.listen(1382).expect("analyzer: cannot listen"); diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index 049d8c12a..b167cd2a3 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(compiler_builtins_lib, alloc, repr_simd, lang_items, const_fn, global_allocator)] +#![feature(compiler_builtins_lib, alloc, lang_items, global_allocator, repr_align, attr_literals)] extern crate compiler_builtins; extern crate alloc; From c626456030a3cb092bdaacaa6395f518f125093c Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 05:21:30 +0000 Subject: [PATCH 0110/2457] conda: bump misoc dependency. --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 63cc5b328..e15e8dcd1 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6.dev py35_50+git82b06ee - - misoc 0.8.dev py35_39+git4126dedf + - misoc 0.8.dev py35_41+gitc69cb371 - jesd204b 0.4 - binutils-or1k-linux >=2.27 - llvm-or1k 4.0.1 From 6801921fc067147631efb28561f52d46f97b4752 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Dec 2017 15:03:14 +0800 Subject: [PATCH 0111/2457] drtio: instrument GTH transceiver --- .../drtio/transceiver/gth_ultrascale.py | 26 +++++++++++++------ .../targets/sayma_amc_drtio_master.py | 5 ++++ .../targets/sayma_amc_drtio_satellite.py | 5 ++++ conda/artiq-dev/meta.yaml | 1 + 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index 5fef1f78f..211c2ac7b 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -8,6 +8,8 @@ from migen.genlib.cdc import MultiReg from misoc.interconnect.csr import * from misoc.cores.code_8b10b import Encoder, Decoder +from microscope import * + from artiq.gateware.drtio.core import TransceiverInterface, ChannelInterface from artiq.gateware.drtio.transceiver.gth_ultrascale_init import * @@ -34,14 +36,13 @@ class GTHSingle(Module): # TX generates RTIO clock, init must be in system domain tx_init = GTHInit(sys_clk_freq, False) # RX receives restart commands from RTIO domain - rx_init = ClockDomainsRenamer("rtio_tx")( - GTHInit(rtio_clk_freq, True)) + rx_init = ClockDomainsRenamer("rtio_tx")(GTHInit(rtio_clk_freq, True)) self.submodules += tx_init, rx_init - pll_lock = Signal() + cpll_lock = Signal() self.comb += [ - tx_init.plllock.eq(pll_lock), - rx_init.plllock.eq(pll_lock) + tx_init.plllock.eq(cpll_lock), + rx_init.plllock.eq(cpll_lock) ] txdata = Signal(dw) @@ -77,7 +78,7 @@ class GTHSingle(Module): p_TXOUT_DIV=2, i_CPLLRESET=0, i_CPLLPD=0, - o_CPLLLOCK=pll_lock, + o_CPLLLOCK=cpll_lock, i_CPLLLOCKEN=1, i_CPLLREFCLKSEL=0b001, i_TSTIN=2**20-1, @@ -171,6 +172,14 @@ class GTHSingle(Module): o_GTHTXN=tx_pads.n ) + self.submodules += [ + add_probe_single("drtio_gth", "cpll_lock", cpll_lock), + add_probe_single("drtio_gth", "txuserrdy", tx_init.Xxuserrdy), + add_probe_single("drtio_gth", "rxuserrdy", rx_init.Xxuserrdy, clock_domain="rtio_tx"), + add_probe_buffer("drtio_gth", "txdata", txdata, clock_domain="rtio_tx"), + add_probe_buffer("drtio_gth", "rxdata", rxdata, clock_domain="rtio_rx") + ] + # tx clocking tx_reset_deglitched = Signal() tx_reset_deglitched.attr.add("no_retiming") @@ -178,8 +187,7 @@ class GTHSingle(Module): self.clock_domains.cd_rtio_tx = ClockDomain() if mode == "master": self.specials += \ - Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk, - i_DIV=0) + Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk, i_DIV=0) self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched) # rx clocking @@ -207,6 +215,8 @@ class GTHSingle(Module): rx_init.restart.eq(clock_aligner.restart), self.rx_ready.eq(clock_aligner.ready) ] + self.submodules += add_probe_single("drtio_gth", "clock_aligner_ready", clock_aligner.ready, + clock_domain="rtio_tx") class GTH(Module, TransceiverInterface): diff --git a/artiq/gateware/targets/sayma_amc_drtio_master.py b/artiq/gateware/targets/sayma_amc_drtio_master.py index ac47e00ab..a14c1446f 100755 --- a/artiq/gateware/targets/sayma_amc_drtio_master.py +++ b/artiq/gateware/targets/sayma_amc_drtio_master.py @@ -11,6 +11,8 @@ from misoc.integration.soc_sdram import soc_sdram_args, soc_sdram_argdict from misoc.integration.builder import builder_args, builder_argdict from misoc.targets.sayma_amc import MiniSoC +from microscope import * + from artiq.gateware.amp import AMPSoC, build_artiq_soc from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple @@ -43,6 +45,9 @@ class Master(MiniSoC, AMPSoC): platform = self.platform rtio_clk_freq = 150e6 + self.submodules += Microscope(platform.request("serial", 1), + self.clk_freq) + # Si5324 used as a free-running oscillator, to avoid dependency on RTM. self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) self.csr_devices.append("si5324_rst_n") diff --git a/artiq/gateware/targets/sayma_amc_drtio_satellite.py b/artiq/gateware/targets/sayma_amc_drtio_satellite.py index 82f9f52e5..dc6d35ef5 100755 --- a/artiq/gateware/targets/sayma_amc_drtio_satellite.py +++ b/artiq/gateware/targets/sayma_amc_drtio_satellite.py @@ -11,6 +11,8 @@ from misoc.integration.soc_sdram import soc_sdram_args, soc_sdram_argdict from misoc.integration.builder import * from misoc.targets.sayma_amc import BaseSoC +from microscope import * + from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple from artiq.gateware.drtio.transceiver import gth_ultrascale @@ -36,6 +38,9 @@ class Satellite(BaseSoC): platform = self.platform rtio_clk_freq = 150e6 + self.submodules += Microscope(platform.request("serial", 1), + self.clk_freq) + rtio_channels = [] for i in range(4): phy = ttl_simple.Output(platform.request("user_led", i)) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index e15e8dcd1..c1faa2656 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -17,6 +17,7 @@ requirements: - migen 0.6.dev py35_50+git82b06ee - misoc 0.8.dev py35_41+gitc69cb371 - jesd204b 0.4 + - microscope - binutils-or1k-linux >=2.27 - llvm-or1k 4.0.1 - llvmlite-artiq 0.20.0 From ca419aa3c23c1466811f8998a12b1d0f2c86f741 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 07:06:45 +0000 Subject: [PATCH 0112/2457] firmware: split out libboard_artiq from libboard. --- artiq/firmware/Cargo.lock | 18 ++- artiq/firmware/libboard/Cargo.toml | 4 +- artiq/firmware/libboard/build.rs | 44 ++---- artiq/firmware/libboard/clock.rs | 49 +------ artiq/firmware/libboard/config.rs | 135 +++++++++++------- artiq/firmware/libboard/ident.rs | 13 ++ artiq/firmware/libboard/lib.rs | 52 ++----- artiq/firmware/libboard/{ => or1k}/cache.rs | 22 +-- artiq/firmware/libboard/{ => or1k}/irq.rs | 0 artiq/firmware/libboard/or1k/mod.rs | 3 + artiq/firmware/libboard/{ => or1k}/spr.rs | 0 artiq/firmware/libboard/{ => or1k}/vectors.S | 0 artiq/firmware/libboard/spiflash.rs | 4 +- artiq/firmware/libboard_artiq/Cargo.toml | 19 +++ .../{libboard => libboard_artiq}/ad9154.rs | 0 .../ad9154_reg.rs | 2 + .../{libboard => libboard_artiq}/boot.rs | 2 +- artiq/firmware/libboard_artiq/build.rs | 28 ++++ .../hmc7043_gen_writes.py | 0 .../hmc7043_guiexport_6gbps.py | 0 .../hmc830_7043.rs | 0 .../{libboard => libboard_artiq}/i2c.rs | 0 artiq/firmware/libboard_artiq/lib.rs | 25 ++++ .../{libboard => libboard_artiq}/pcr.rs | 2 +- .../{libboard => libboard_artiq}/serwb.rs | 2 +- .../{libboard => libboard_artiq}/si5324.rs | 0 .../{libboard => libboard_artiq}/spi.rs | 0 artiq/firmware/libbuild_misoc/Cargo.toml | 8 ++ artiq/firmware/libbuild_misoc/lib.rs | 15 ++ artiq/firmware/liblogger_artiq/lib.rs | 8 +- artiq/firmware/runtime/Cargo.toml | 3 +- artiq/firmware/runtime/kern_hwreq.rs | 28 ++-- artiq/firmware/runtime/lib.rs | 46 +++--- artiq/firmware/runtime/mgmt.rs | 6 +- artiq/firmware/runtime/rtio_mgt.rs | 5 +- artiq/firmware/runtime/session.rs | 9 +- artiq/firmware/runtime/watchdog.rs | 47 ++++++ 37 files changed, 352 insertions(+), 247 deletions(-) create mode 100644 artiq/firmware/libboard/ident.rs rename artiq/firmware/libboard/{ => or1k}/cache.rs (50%) rename artiq/firmware/libboard/{ => or1k}/irq.rs (100%) create mode 100644 artiq/firmware/libboard/or1k/mod.rs rename artiq/firmware/libboard/{ => or1k}/spr.rs (100%) rename artiq/firmware/libboard/{ => or1k}/vectors.S (100%) create mode 100644 artiq/firmware/libboard_artiq/Cargo.toml rename artiq/firmware/{libboard => libboard_artiq}/ad9154.rs (100%) rename artiq/firmware/{libboard => libboard_artiq}/ad9154_reg.rs (99%) rename artiq/firmware/{libboard => libboard_artiq}/boot.rs (98%) create mode 100644 artiq/firmware/libboard_artiq/build.rs rename artiq/firmware/{libboard => libboard_artiq}/hmc7043_gen_writes.py (100%) rename artiq/firmware/{libboard => libboard_artiq}/hmc7043_guiexport_6gbps.py (100%) rename artiq/firmware/{libboard => libboard_artiq}/hmc830_7043.rs (100%) rename artiq/firmware/{libboard => libboard_artiq}/i2c.rs (100%) create mode 100644 artiq/firmware/libboard_artiq/lib.rs rename artiq/firmware/{libboard => libboard_artiq}/pcr.rs (98%) rename artiq/firmware/{libboard => libboard_artiq}/serwb.rs (99%) rename artiq/firmware/{libboard => libboard_artiq}/si5324.rs (100%) rename artiq/firmware/{libboard => libboard_artiq}/spi.rs (100%) create mode 100644 artiq/firmware/libbuild_misoc/Cargo.toml create mode 100644 artiq/firmware/libbuild_misoc/lib.rs create mode 100644 artiq/firmware/runtime/watchdog.rs diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 700bc76ee..3b6ed3581 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -26,11 +26,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "board" version = "0.0.0" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "build_artiq 0.0.0", + "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "board_artiq" +version = "0.0.0" +dependencies = [ + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "board 0.0.0", + "build_artiq 0.0.0", ] [[package]] @@ -40,6 +47,10 @@ dependencies = [ "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "build_misoc" +version = "0.0.0" + [[package]] name = "byteorder" version = "1.2.1" @@ -169,6 +180,7 @@ dependencies = [ "amp 0.0.0", "backtrace_artiq 0.0.0", "board 0.0.0", + "board_artiq 0.0.0", "build_artiq 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)", diff --git a/artiq/firmware/libboard/Cargo.toml b/artiq/firmware/libboard/Cargo.toml index f7dff2d1b..9604e9a6e 100644 --- a/artiq/firmware/libboard/Cargo.toml +++ b/artiq/firmware/libboard/Cargo.toml @@ -10,12 +10,10 @@ path = "lib.rs" [build-dependencies] cc = "1.0" -build_artiq = { path = "../libbuild_artiq" } +build_misoc = { path = "../libbuild_misoc" } [dependencies] -bitflags = "1.0" byteorder = { version = "1.0", default-features = false } -log = { version = "0.3", default-features = false } [features] uart_console = [] diff --git a/artiq/firmware/libboard/build.rs b/artiq/firmware/libboard/build.rs index 6090fad77..c0a5971eb 100644 --- a/artiq/firmware/libboard/build.rs +++ b/artiq/firmware/libboard/build.rs @@ -1,38 +1,18 @@ -extern crate build_artiq; +extern crate build_misoc; extern crate cc; use std::env; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; -use std::process::Command; - -fn build_vectors() { - println!("cargo:rerun-if-changed=vectors.S"); - cc::Build::new() - .file("vectors.S") - .compile("vectors"); -} - -fn gen_hmc7043_writes() { - println!("cargo:rerun-if-changed=hmc7043_gen_writes.py"); - println!("cargo:rerun-if-changed=hmc7043_guiexport_6gbps.py"); - - let hmc7043_writes = - Command::new("python3") - .arg("hmc7043_gen_writes.py") - .arg("hmc7043_guiexport_6gbps.py") - .output() - .ok() - .and_then(|o| String::from_utf8(o.stdout).ok()) - .unwrap(); - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let mut f = File::create(out_dir.join("hmc7043_writes.rs")).unwrap(); - write!(f, "{}", hmc7043_writes).unwrap(); -} +use std::path::Path; fn main() { - build_artiq::misoc_cfg(); - build_vectors(); - gen_hmc7043_writes(); + build_misoc::cfg(); + + let triple = env::var("TARGET").unwrap(); + let arch = triple.split("-").next().unwrap(); + let vectors_path = Path::new(arch).join("vectors.S"); + + println!("cargo:rerun-if-changed={}", vectors_path.to_str().unwrap()); + cc::Build::new() + .file(vectors_path) + .compile("vectors"); } diff --git a/artiq/firmware/libboard/clock.rs b/artiq/firmware/libboard/clock.rs index 31fe7bafc..deddd8c39 100644 --- a/artiq/firmware/libboard/clock.rs +++ b/artiq/firmware/libboard/clock.rs @@ -1,6 +1,7 @@ +use core::i64; use csr; -const INIT: u64 = ::core::i64::MAX as u64; +const INIT: u64 = i64::MAX as u64; const FREQ: u64 = csr::CONFIG_CLOCK_FREQUENCY as u64; pub fn init() { @@ -35,49 +36,3 @@ pub fn spin_us(interval: u64) { } } } - -#[derive(Debug, Clone, Copy)] -struct Watchdog { - active: bool, - threshold: u64 -} - -pub const MAX_WATCHDOGS: usize = 16; - -#[derive(Debug)] -pub struct WatchdogSet { - watchdogs: [Watchdog; MAX_WATCHDOGS] -} - -impl WatchdogSet { - pub fn new() -> WatchdogSet { - WatchdogSet { - watchdogs: [Watchdog { active: false, threshold: 0 }; MAX_WATCHDOGS] - } - } - - pub fn set_ms(&mut self, interval: u64) -> Result { - for (index, watchdog) in self.watchdogs.iter_mut().enumerate() { - if !watchdog.active { - watchdog.active = true; - watchdog.threshold = get_ms() + interval; - return Ok(index) - } - } - - Err(()) - } - - pub fn clear(&mut self, index: usize) { - if index < MAX_WATCHDOGS { - self.watchdogs[index].active = false - } - } - - pub fn expired(&self) -> bool { - self.watchdogs.iter() - .filter(|wd| wd.active) - .min_by_key(|wd| wd.threshold) - .map_or(false, |wd| get_ms() > wd.threshold) - } -} diff --git a/artiq/firmware/libboard/config.rs b/artiq/firmware/libboard/config.rs index 5c673da5b..aec58979b 100644 --- a/artiq/firmware/libboard/config.rs +++ b/artiq/firmware/libboard/config.rs @@ -1,9 +1,41 @@ +use core::{str, fmt}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Error { + AlreadyLocked, + SpaceExhausted, + Truncated { offset: usize }, + InvalidSize { offset: usize, size: usize }, + MissingSeparator { offset: usize }, + Utf8Error(str::Utf8Error) +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &Error::AlreadyLocked => + write!(f, "attempt at reentrant access"), + &Error::SpaceExhausted => + write!(f, "space exhausted"), + &Error::Truncated { offset }=> + write!(f, "truncated record at offset {}", offset), + &Error::InvalidSize { offset, size } => + write!(f, "invalid record size {} at offset {}", size, offset), + &Error::MissingSeparator { offset } => + write!(f, "missing separator at offset {}", offset), + &Error::Utf8Error(err) => + write!(f, "{}", err) + } + } +} + #[cfg(has_spiflash)] mod imp { use core::str; use byteorder::{ByteOrder, BigEndian}; use cache; use spiflash; + use super::Error; // One flash sector immediately after the bootloader. const ADDR: usize = ::mem::FLASH_BOOT_ADDRESS - spiflash::PAGE_SIZE; @@ -12,17 +44,18 @@ mod imp { mod lock { use core::slice; use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; + use super::Error; static LOCKED: AtomicUsize = ATOMIC_USIZE_INIT; pub struct Lock; impl Lock { - pub fn take() -> Result { + pub fn take() -> Result { if LOCKED.swap(1, Ordering::SeqCst) != 0 { - Err(()) // already locked + Err(Error::AlreadyLocked) } else { - Ok(Lock) // locked now + Ok(Lock) } } @@ -53,29 +86,27 @@ mod imp { } impl<'a> Iterator for Iter<'a> { - type Item = Result<(&'a [u8], &'a [u8]), ()>; + type Item = Result<(&'a [u8], &'a [u8]), Error>; fn next(&mut self) -> Option { let data = &self.data[self.offset..]; if data.len() < 4 { - error!("offset {}: truncated record", self.offset); - return Some(Err(())) + // error!("offset {}: truncated record", self.offset); + return Some(Err(Error::Truncated { offset: self.offset })) } let record_size = BigEndian::read_u32(data) as usize; if record_size == !0 /* all ones; erased flash */ { return None } else if record_size < 4 || record_size > data.len() { - error!("offset {}: invalid record size {}", self.offset, record_size); - return Some(Err(())) + return Some(Err(Error::InvalidSize { offset: self.offset, size: record_size })) } let record_body = &data[4..record_size]; match record_body.iter().position(|&x| x == 0) { None => { - error!("offset {}: missing separator", self.offset); - Some(Err(())) + return Some(Err(Error::MissingSeparator { offset: self.offset })) } Some(pos) => { self.offset += record_size; @@ -87,7 +118,7 @@ mod imp { } } - pub fn read) -> R, R>(key: &str, f: F) -> R { + pub fn read) -> R, R>(key: &str, f: F) -> R { f(Lock::take().and_then(|lock| { let mut iter = Iter::new(lock.data()); let mut value = &[][..]; @@ -102,52 +133,53 @@ mod imp { })) } - pub fn read_str) -> R, R>(key: &str, f: F) -> R { + pub fn read_str) -> R, R>(key: &str, f: F) -> R { read(key, |result| { - f(result.and_then(|value| str::from_utf8(value).map_err(|_| ()))) + f(result.and_then(|value| str::from_utf8(value).map_err(Error::Utf8Error))) }) } - unsafe fn append_at<'a>(mut data: &'a [u8], key: &[u8], value: &[u8]) -> Result<&'a [u8], ()> { + unsafe fn append_at(data: &[u8], mut offset: usize, + key: &[u8], value: &[u8]) -> Result { let record_size = 4 + key.len() + 1 + value.len(); - if data.len() < record_size { - return Err(()) + if offset + record_size > data.len() { + return Err(Error::SpaceExhausted) } let mut record_size_bytes = [0u8; 4]; BigEndian::write_u32(&mut record_size_bytes[..], record_size as u32); - spiflash::write(data.as_ptr() as usize, &record_size_bytes[..]); - data = &data[record_size_bytes.len()..]; + { + let mut write = |payload| { + spiflash::write(data.as_ptr().offset(offset as isize) as usize, payload); + offset += payload.len(); + }; - spiflash::write(data.as_ptr() as usize, key); - data = &data[key.len()..]; + write(&record_size_bytes[..]); + write(key); + write(&[0]); + write(value); + cache::flush_l2_cache(); + } - spiflash::write(data.as_ptr() as usize, &[0]); - data = &data[1..]; - - spiflash::write(data.as_ptr() as usize, value); - data = &data[value.len()..]; - - cache::flush_l2_cache(); - - Ok(data) + Ok(offset) } - fn compact() -> Result<(), ()> { + fn compact() -> Result<(), Error> { let lock = Lock::take()?; + let data = lock.data(); static mut OLD_DATA: [u8; SIZE] = [0; SIZE]; let old_data = unsafe { - OLD_DATA.copy_from_slice(lock.data()); + OLD_DATA.copy_from_slice(data); &OLD_DATA[..] }; - let mut data = lock.data(); unsafe { spiflash::erase_sector(data.as_ptr() as usize) }; // This is worst-case quadratic, but we're limited by a small SPI flash sector size, // so it does not really matter. + let mut offset = 0; let mut iter = Iter::new(old_data); while let Some(result) = iter.next() { let (key, mut value) = result?; @@ -159,47 +191,48 @@ mod imp { value = next_value } } - data = unsafe { append_at(data, key, value)? }; + offset = unsafe { append_at(data, offset, key, value)? }; } Ok(()) } - fn append(key: &str, value: &[u8]) -> Result<(), ()> { + fn append(key: &str, value: &[u8]) -> Result<(), Error> { let lock = Lock::take()?; + let data = lock.data(); - let free = { - let mut iter = Iter::new(lock.data()); + let free_offset = { + let mut iter = Iter::new(data); while let Some(result) = iter.next() { let _ = result?; } - &iter.data[iter.offset..] + iter.offset }; - unsafe { append_at(free, key.as_bytes(), value)? }; + unsafe { append_at(data, free_offset, key.as_bytes(), value)? }; Ok(()) } - pub fn write(key: &str, value: &[u8]) -> Result<(), ()> { + pub fn write(key: &str, value: &[u8]) -> Result<(), Error> { match append(key, value) { - Ok(()) => (), - Err(()) => { + Err(Error::SpaceExhausted) => { compact()?; - append(key, value)?; + append(key, value) } + res => res } - Ok(()) } - pub fn remove(key: &str) -> Result<(), ()> { + pub fn remove(key: &str) -> Result<(), Error> { write(key, &[]) } - pub fn erase() -> Result<(), ()> { + pub fn erase() -> Result<(), Error> { let lock = Lock::take()?; + let data = lock.data(); - unsafe { spiflash::erase_sector(lock.data().as_ptr() as usize) }; + unsafe { spiflash::erase_sector(data.as_ptr() as usize) }; cache::flush_l2_cache(); Ok(()) @@ -208,23 +241,23 @@ mod imp { #[cfg(not(has_spiflash))] mod imp { - pub fn read) -> R, R>(_key: &str, f: F) -> R { + pub fn read) -> R, R>(_key: &str, f: F) -> R { f(Err(())) } - pub fn read_str) -> R, R>(_key: &str, f: F) -> R { + pub fn read_str) -> R, R>(_key: &str, f: F) -> R { f(Err(())) } - pub fn write(_key: &str, _value: &[u8]) -> Result<(), ()> { + pub fn write(_key: &str, _value: &[u8]) -> Result<(), Error> { Err(()) } - pub fn remove(_key: &str) -> Result<(), ()> { + pub fn remove(_key: &str) -> Result<(), Error> { Err(()) } - pub fn erase() -> Result<(), ()> { + pub fn erase() -> Result<(), Error> { Err(()) } } diff --git a/artiq/firmware/libboard/ident.rs b/artiq/firmware/libboard/ident.rs new file mode 100644 index 000000000..26b5befdc --- /dev/null +++ b/artiq/firmware/libboard/ident.rs @@ -0,0 +1,13 @@ +use core::{ptr, cmp, str}; +use csr; + +pub fn read(buf: &mut [u8]) -> &str { + unsafe { + let len = ptr::read_volatile(csr::IDENTIFIER_MEM_BASE); + let len = cmp::min(len as usize, buf.len()); + for i in 0..len { + buf[i] = ptr::read_volatile(csr::IDENTIFIER_MEM_BASE.offset(1 + i as isize)) as u8 + } + str::from_utf8_unchecked(&buf[..len]) + } +} diff --git a/artiq/firmware/libboard/lib.rs b/artiq/firmware/libboard/lib.rs index 8711cff3c..9eb6bd31e 100644 --- a/artiq/firmware/libboard/lib.rs +++ b/artiq/firmware/libboard/lib.rs @@ -1,58 +1,22 @@ -#![feature(asm, lang_items)] #![no_std] +#![feature(asm)] -#[macro_use] -extern crate bitflags; extern crate byteorder; -#[macro_use] -extern crate log; -use core::{cmp, ptr, str}; +#[cfg(target_arch = "or1k")] +#[path = "or1k/mod.rs"] +mod arch; + +pub use arch::*; include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/mem.rs")); include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/csr.rs")); include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/sdram_phy.rs")); -pub mod spr; -pub mod irq; -pub mod cache; -pub mod pcr; +pub mod ident; pub mod clock; pub mod uart; -#[cfg(feature = "uart_console")] -pub mod uart_console; - #[cfg(has_spiflash)] pub mod spiflash; pub mod config; - -pub mod i2c; -pub mod spi; - -#[cfg(has_si5324)] -pub mod si5324; - -#[cfg(has_serwb_phy_amc)] -pub mod serwb; -#[cfg(has_hmc830_7043)] -pub mod hmc830_7043; -#[cfg(has_ad9154)] -#[allow(dead_code)] -mod ad9154_reg; -#[cfg(has_ad9154)] -pub mod ad9154; - -pub mod boot; - #[cfg(feature = "uart_console")] -pub use uart_console::Console; - -pub fn ident(buf: &mut [u8]) -> &str { - unsafe { - let len = ptr::read_volatile(csr::IDENTIFIER_MEM_BASE); - let len = cmp::min(len as usize, buf.len()); - for i in 0..len { - buf[i] = ptr::read_volatile(csr::IDENTIFIER_MEM_BASE.offset(1 + i as isize)) as u8 - } - str::from_utf8_unchecked(&buf[..len]) - } -} +pub mod uart_console; diff --git a/artiq/firmware/libboard/cache.rs b/artiq/firmware/libboard/or1k/cache.rs similarity index 50% rename from artiq/firmware/libboard/cache.rs rename to artiq/firmware/libboard/or1k/cache.rs index e90bb1061..8e79b11ec 100644 --- a/artiq/firmware/libboard/cache.rs +++ b/artiq/firmware/libboard/or1k/cache.rs @@ -1,19 +1,19 @@ use core::ptr; -use spr::{self, mfspr, mtspr}; +use super::spr::*; use csr; use mem; pub fn flush_cpu_icache() { unsafe { - let iccfgr = mfspr(spr::SPR_ICCFGR); - let ways = 1 << (iccfgr & spr::SPR_ICCFGR_NCW); - let set_size = 1 << ((iccfgr & spr::SPR_ICCFGR_NCS) >> 3); - let block_size = if iccfgr & spr::SPR_ICCFGR_CBS != 0 { 32 } else { 16 }; + let iccfgr = mfspr(SPR_ICCFGR); + let ways = 1 << (iccfgr & SPR_ICCFGR_NCW); + let set_size = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3); + let block_size = if iccfgr & SPR_ICCFGR_CBS != 0 { 32 } else { 16 }; let size = set_size * ways * block_size; let mut i = 0; while i < size { - mtspr(spr::SPR_ICBIR, i); + mtspr(SPR_ICBIR, i); i += block_size; } } @@ -21,15 +21,15 @@ pub fn flush_cpu_icache() { pub fn flush_cpu_dcache() { unsafe { - let dccfgr = mfspr(spr::SPR_DCCFGR); - let ways = 1 << (dccfgr & spr::SPR_ICCFGR_NCW); - let set_size = 1 << ((dccfgr & spr::SPR_DCCFGR_NCS) >> 3); - let block_size = if dccfgr & spr::SPR_DCCFGR_CBS != 0 { 32 } else { 16 }; + let dccfgr = mfspr(SPR_DCCFGR); + let ways = 1 << (dccfgr & SPR_ICCFGR_NCW); + let set_size = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3); + let block_size = if dccfgr & SPR_DCCFGR_CBS != 0 { 32 } else { 16 }; let size = set_size * ways * block_size; let mut i = 0; while i < size { - mtspr(spr::SPR_DCBIR, i); + mtspr(SPR_DCBIR, i); i += block_size; } } diff --git a/artiq/firmware/libboard/irq.rs b/artiq/firmware/libboard/or1k/irq.rs similarity index 100% rename from artiq/firmware/libboard/irq.rs rename to artiq/firmware/libboard/or1k/irq.rs diff --git a/artiq/firmware/libboard/or1k/mod.rs b/artiq/firmware/libboard/or1k/mod.rs new file mode 100644 index 000000000..01589ddc8 --- /dev/null +++ b/artiq/firmware/libboard/or1k/mod.rs @@ -0,0 +1,3 @@ +pub mod spr; +pub mod irq; +pub mod cache; diff --git a/artiq/firmware/libboard/spr.rs b/artiq/firmware/libboard/or1k/spr.rs similarity index 100% rename from artiq/firmware/libboard/spr.rs rename to artiq/firmware/libboard/or1k/spr.rs diff --git a/artiq/firmware/libboard/vectors.S b/artiq/firmware/libboard/or1k/vectors.S similarity index 100% rename from artiq/firmware/libboard/vectors.S rename to artiq/firmware/libboard/or1k/vectors.S diff --git a/artiq/firmware/libboard/spiflash.rs b/artiq/firmware/libboard/spiflash.rs index 643a2160c..2273185d5 100644 --- a/artiq/firmware/libboard/spiflash.rs +++ b/artiq/firmware/libboard/spiflash.rs @@ -1,5 +1,3 @@ -#![allow(dead_code)] - use core::cmp; use csr; @@ -8,7 +6,7 @@ pub const PAGE_SIZE: usize = csr::CONFIG_SPIFLASH_PAGE_SIZE as usize; const PAGE_MASK: usize = PAGE_SIZE - 1; const CMD_PP: u8 = 0x02; -const CMD_WRDI: u8 = 0x04; +// const CMD_WRDI: u8 = 0x04; const CMD_RDSR: u8 = 0x05; const CMD_WREN: u8 = 0x06; const CMD_SE: u8 = 0xd8; diff --git a/artiq/firmware/libboard_artiq/Cargo.toml b/artiq/firmware/libboard_artiq/Cargo.toml new file mode 100644 index 000000000..8ac55b6a2 --- /dev/null +++ b/artiq/firmware/libboard_artiq/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["M-Labs"] +name = "board_artiq" +version = "0.0.0" +build = "build.rs" + +[lib] +name = "board_artiq" +path = "lib.rs" + +[build-dependencies] +build_artiq = { path = "../libbuild_artiq" } + +[dependencies] +bitflags = "1.0" +board = { path = "../libboard" } + +[features] +uart_console = [] diff --git a/artiq/firmware/libboard/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs similarity index 100% rename from artiq/firmware/libboard/ad9154.rs rename to artiq/firmware/libboard_artiq/ad9154.rs diff --git a/artiq/firmware/libboard/ad9154_reg.rs b/artiq/firmware/libboard_artiq/ad9154_reg.rs similarity index 99% rename from artiq/firmware/libboard/ad9154_reg.rs rename to artiq/firmware/libboard_artiq/ad9154_reg.rs index 3830f89c8..3af180496 100644 --- a/artiq/firmware/libboard/ad9154_reg.rs +++ b/artiq/firmware/libboard_artiq/ad9154_reg.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + pub const SPI_INTFCONFA : u16 = 0x000; pub const SOFTRESET : u8 = 1 << 0; pub const LSBFIRST : u8 = 1 << 1; diff --git a/artiq/firmware/libboard/boot.rs b/artiq/firmware/libboard_artiq/boot.rs similarity index 98% rename from artiq/firmware/libboard/boot.rs rename to artiq/firmware/libboard_artiq/boot.rs index 7e98257b0..803a094a6 100644 --- a/artiq/firmware/libboard/boot.rs +++ b/artiq/firmware/libboard_artiq/boot.rs @@ -1,4 +1,4 @@ -use irq; +use board::irq; pub unsafe fn reboot() -> ! { irq::set_ie(false); diff --git a/artiq/firmware/libboard_artiq/build.rs b/artiq/firmware/libboard_artiq/build.rs new file mode 100644 index 000000000..b787e5007 --- /dev/null +++ b/artiq/firmware/libboard_artiq/build.rs @@ -0,0 +1,28 @@ +extern crate build_artiq; + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; +use std::process::Command; + +fn gen_hmc7043_writes() { + println!("cargo:rerun-if-changed=hmc7043_gen_writes.py"); + println!("cargo:rerun-if-changed=hmc7043_guiexport_6gbps.py"); + + let hmc7043_writes = + Command::new("python3") + .arg("hmc7043_gen_writes.py") + .arg("hmc7043_guiexport_6gbps.py") + .output() + .ok() + .and_then(|o| String::from_utf8(o.stdout).ok()) + .unwrap(); + let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let mut f = File::create(out_dir.join("hmc7043_writes.rs")).unwrap(); + write!(f, "{}", hmc7043_writes).unwrap(); +} + +fn main() { + gen_hmc7043_writes(); +} diff --git a/artiq/firmware/libboard/hmc7043_gen_writes.py b/artiq/firmware/libboard_artiq/hmc7043_gen_writes.py similarity index 100% rename from artiq/firmware/libboard/hmc7043_gen_writes.py rename to artiq/firmware/libboard_artiq/hmc7043_gen_writes.py diff --git a/artiq/firmware/libboard/hmc7043_guiexport_6gbps.py b/artiq/firmware/libboard_artiq/hmc7043_guiexport_6gbps.py similarity index 100% rename from artiq/firmware/libboard/hmc7043_guiexport_6gbps.py rename to artiq/firmware/libboard_artiq/hmc7043_guiexport_6gbps.py diff --git a/artiq/firmware/libboard/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs similarity index 100% rename from artiq/firmware/libboard/hmc830_7043.rs rename to artiq/firmware/libboard_artiq/hmc830_7043.rs diff --git a/artiq/firmware/libboard/i2c.rs b/artiq/firmware/libboard_artiq/i2c.rs similarity index 100% rename from artiq/firmware/libboard/i2c.rs rename to artiq/firmware/libboard_artiq/i2c.rs diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs new file mode 100644 index 000000000..894866980 --- /dev/null +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -0,0 +1,25 @@ +#![feature(asm, lang_items)] +#![no_std] + +#[macro_use] +extern crate bitflags; +extern crate board; + +pub mod pcr; + +pub mod i2c; +pub mod spi; + +#[cfg(has_si5324)] +pub mod si5324; + +#[cfg(has_serwb_phy_amc)] +pub mod serwb; +#[cfg(has_hmc830_7043)] +pub mod hmc830_7043; +#[cfg(has_ad9154)] +mod ad9154_reg; +#[cfg(has_ad9154)] +pub mod ad9154; + +pub mod boot; diff --git a/artiq/firmware/libboard/pcr.rs b/artiq/firmware/libboard_artiq/pcr.rs similarity index 98% rename from artiq/firmware/libboard/pcr.rs rename to artiq/firmware/libboard_artiq/pcr.rs index 59518e8bf..543ad4df6 100644 --- a/artiq/firmware/libboard/pcr.rs +++ b/artiq/firmware/libboard_artiq/pcr.rs @@ -1,4 +1,4 @@ -use spr::*; +use board::spr::*; bitflags! { pub struct Counters: u32 { diff --git a/artiq/firmware/libboard/serwb.rs b/artiq/firmware/libboard_artiq/serwb.rs similarity index 99% rename from artiq/firmware/libboard/serwb.rs rename to artiq/firmware/libboard_artiq/serwb.rs index 0d76ff5f7..687d5ea04 100644 --- a/artiq/firmware/libboard/serwb.rs +++ b/artiq/firmware/libboard_artiq/serwb.rs @@ -21,7 +21,7 @@ pub fn wait_init() { error!("incorrect RTM identifier: 0x{:08x}", rtm_identifier); // proceed anyway } - + unsafe { debug!("AMC serwb settings:"); debug!(" delay_min_found: {}", csr::serwb_phy_amc::control_delay_min_found_read()); diff --git a/artiq/firmware/libboard/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs similarity index 100% rename from artiq/firmware/libboard/si5324.rs rename to artiq/firmware/libboard_artiq/si5324.rs diff --git a/artiq/firmware/libboard/spi.rs b/artiq/firmware/libboard_artiq/spi.rs similarity index 100% rename from artiq/firmware/libboard/spi.rs rename to artiq/firmware/libboard_artiq/spi.rs diff --git a/artiq/firmware/libbuild_misoc/Cargo.toml b/artiq/firmware/libbuild_misoc/Cargo.toml new file mode 100644 index 000000000..400e5fbe1 --- /dev/null +++ b/artiq/firmware/libbuild_misoc/Cargo.toml @@ -0,0 +1,8 @@ +[package] +authors = ["M-Labs"] +name = "build_misoc" +version = "0.0.0" + +[lib] +name = "build_misoc" +path = "lib.rs" diff --git a/artiq/firmware/libbuild_misoc/lib.rs b/artiq/firmware/libbuild_misoc/lib.rs new file mode 100644 index 000000000..36f354fa1 --- /dev/null +++ b/artiq/firmware/libbuild_misoc/lib.rs @@ -0,0 +1,15 @@ +use std::env; +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::path::Path; + +pub fn cfg() { + let out_dir = env::var("BUILDINC_DIRECTORY").unwrap(); + let cfg_path = Path::new(&out_dir).join("generated").join("rust-cfg"); + println!("cargo:rerun-if-changed={}", cfg_path.to_str().unwrap()); + + let f = BufReader::new(File::open(&cfg_path).unwrap()); + for line in f.lines() { + println!("cargo:rustc-cfg={}", line.unwrap()); + } +} diff --git a/artiq/firmware/liblogger_artiq/lib.rs b/artiq/firmware/liblogger_artiq/lib.rs index 67b2c36f5..c51d45b7b 100644 --- a/artiq/firmware/liblogger_artiq/lib.rs +++ b/artiq/firmware/liblogger_artiq/lib.rs @@ -2,13 +2,14 @@ extern crate log; extern crate log_buffer; +#[macro_use] extern crate board; use core::cell::{Cell, RefCell}; use core::fmt::Write; use log::{Log, LogMetadata, LogRecord, LogLevelFilter, MaxLogLevelFilter}; use log_buffer::LogBuffer; -use board::{Console, clock}; +use board::clock; pub struct BufferLogger { buffer: RefCell>, @@ -110,9 +111,8 @@ impl Log for BufferLogger { record.level(), record.target(), record.args()).unwrap(); if record.level() <= self.uart_filter.get() { - writeln!(Console, - "[{:6}.{:06}s] {:>5}({}): {}", seconds, micros, - record.level(), record.target(), record.args()).unwrap(); + println!("[{:6}.{:06}s] {:>5}({}): {}", seconds, micros, + record.level(), record.target(), record.args()); } } } diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 468ca295d..e6c20ba4d 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -16,11 +16,12 @@ build_artiq = { path = "../libbuild_artiq" } byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } log = { version = "0.3", default-features = false } +board = { path = "../libboard", features = ["uart_console"] } alloc_list = { path = "../liballoc_list" } std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] } logger_artiq = { path = "../liblogger_artiq" } backtrace_artiq = { path = "../libbacktrace_artiq" } -board = { path = "../libboard", features = ["uart_console"] } +board_artiq = { path = "../libboard_artiq" } proto = { path = "../libproto", features = ["log"] } amp = { path = "../libamp" } drtioaux = { path = "../libdrtioaux" } diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index 245fdaeab..aae60c3c8 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -120,14 +120,14 @@ mod drtio_i2c { } mod i2c { - use board; + use board_artiq::i2c as local_i2c; use super::drtio_i2c; pub fn start(busno: u32) -> Result<(), ()> { let nodeno = (busno >> 16) as u8; let node_busno = busno as u8; if nodeno == 0 { - board::i2c::start(node_busno) + local_i2c::start(node_busno) } else { drtio_i2c::start(nodeno, node_busno) } @@ -137,7 +137,7 @@ mod i2c { let nodeno = (busno >> 16) as u8; let node_busno = busno as u8; if nodeno == 0 { - board::i2c::restart(node_busno) + local_i2c::restart(node_busno) } else { drtio_i2c::restart(nodeno, node_busno) } @@ -147,7 +147,7 @@ mod i2c { let nodeno = (busno >> 16) as u8; let node_busno = busno as u8; if nodeno == 0 { - board::i2c::stop(node_busno) + local_i2c::stop(node_busno) } else { drtio_i2c::stop(nodeno, node_busno) } @@ -157,7 +157,7 @@ mod i2c { let nodeno = (busno >> 16 )as u8; let node_busno = busno as u8; if nodeno == 0 { - board::i2c::write(node_busno, data) + local_i2c::write(node_busno, data) } else { drtio_i2c::write(nodeno, node_busno, data) } @@ -167,7 +167,7 @@ mod i2c { let nodeno = (busno >> 16) as u8; let node_busno = busno as u8; if nodeno == 0 { - board::i2c::read(node_busno, ack) + local_i2c::read(node_busno, ack) } else { drtio_i2c::read(nodeno, node_busno, ack) } @@ -254,11 +254,13 @@ mod drtio_spi { #[cfg(not(has_drtio))] mod drtio_spi { - pub fn set_config(_nodeno: u8, _busno: u8, _flags: u8, _write_div: u8, _read_div: u8) -> Result<(), ()> { + pub fn set_config(_nodeno: u8, _busno: u8, _flags: u8, + _write_div: u8, _read_div: u8) -> Result<(), ()> { Err(()) } - pub fn set_xfer(_nodeno: u8, _busno: u8, _chip_select: u16, _write_length: u8, _read_length: u8) -> Result<(), ()> { + pub fn set_xfer(_nodeno: u8, _busno: u8, _chip_select: u16, + _write_length: u8, _read_length: u8) -> Result<(), ()> { Err(()) } @@ -272,14 +274,14 @@ mod drtio_spi { } mod spi { - use board; + use board_artiq::spi as local_spi; use super::drtio_spi; pub fn set_config(busno: u32, flags: u8, write_div: u8, read_div: u8) -> Result<(), ()> { let nodeno = (busno >> 16) as u8; let node_busno = busno as u8; if nodeno == 0 { - board::spi::set_config(node_busno, flags, write_div, read_div) + local_spi::set_config(node_busno, flags, write_div, read_div) } else { drtio_spi::set_config(nodeno, node_busno, flags, write_div, read_div) } @@ -289,7 +291,7 @@ mod spi { let nodeno = (busno >> 16) as u8; let node_busno = busno as u8; if nodeno == 0 { - board::spi::set_xfer(node_busno, chip_select, write_length, read_length) + local_spi::set_xfer(node_busno, chip_select, write_length, read_length) } else { drtio_spi::set_xfer(nodeno, node_busno, chip_select, write_length, read_length) } @@ -299,7 +301,7 @@ mod spi { let nodeno = (busno >> 16) as u8; let node_busno = busno as u8; if nodeno == 0 { - board::spi::write(node_busno, data) + local_spi::write(node_busno, data) } else { drtio_spi::write(nodeno, node_busno, data) } @@ -309,7 +311,7 @@ mod spi { let nodeno = (busno >> 16) as u8; let node_busno = busno as u8; if nodeno == 0 { - board::spi::read(node_busno) + local_spi::read(node_busno) } else { drtio_spi::read(nodeno, node_busno) } diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index b167cd2a3..158abecb1 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -17,6 +17,7 @@ extern crate logger_artiq; extern crate backtrace_artiq; #[macro_use] extern crate board; +extern crate board_artiq; extern crate proto; extern crate amp; #[cfg(has_drtio)] @@ -41,6 +42,7 @@ mod rtio_dma; mod mgmt; mod kernel; mod kern_hwreq; +mod watchdog; mod session; #[cfg(any(has_rtio_moninj, has_drtio))] mod moninj; @@ -51,7 +53,7 @@ fn startup() { board::clock::init(); info!("ARTIQ runtime starting..."); info!("software version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); - info!("gateware version {}", board::ident(&mut [0; 64])); + info!("gateware version {}", board::ident::read(&mut [0; 64])); #[cfg(has_serwb_phy_amc)] board::serwb::wait_init(); @@ -69,7 +71,7 @@ fn startup() { info!("continuing boot"); #[cfg(has_i2c)] - board::i2c::init(); + board_artiq::i2c::init(); #[cfg(si5324_free_running)] setup_si5324_free_running(); #[cfg(has_hmc830_7043)] @@ -106,27 +108,27 @@ fn setup_si5324_free_running() #[cfg(has_ethmac)] fn startup_ethernet() { let hardware_addr; - match config::read_str("mac", |r| r?.parse()) { - Err(()) => { - hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); - warn!("using default MAC address {}; consider changing it", hardware_addr); - } - Ok(addr) => { + match config::read_str("mac", |r| r.map(|s| s.parse())) { + Ok(Ok(addr)) => { hardware_addr = addr; info!("using MAC address {}", hardware_addr); } + _ => { + hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); + warn!("using default MAC address {}; consider changing it", hardware_addr); + } } let protocol_addr; - match config::read_str("ip", |r| r?.parse()) { - Err(()) => { - protocol_addr = IpAddress::v4(192, 168, 1, 50); - info!("using default IP address {}", protocol_addr); - } - Ok(addr) => { + match config::read_str("ip", |r| r.map(|s| s.parse())) { + Ok(Ok(addr)) => { protocol_addr = addr; info!("using IP address {}", protocol_addr); } + _ => { + protocol_addr = IpAddress::v4(192, 168, 1, 50); + info!("using default IP address {}", protocol_addr); + } } // fn _net_trace_writer(timestamp: u64, printer: smoltcp::wire::PrettyPrinter) @@ -159,26 +161,24 @@ fn startup_ethernet() { #[cfg(has_rtio_analyzer)] io.spawn(4096, analyzer::thread); - match config::read_str("log_level", |r| r?.parse()) { - Err(()) => (), - Ok(log_level_filter) => { + match config::read_str("log_level", |r| r.map(|s| s.parse())) { + Ok(Ok(log_level_filter)) => { info!("log level set to {} by `log_level` config key", log_level_filter); logger_artiq::BufferLogger::with(|logger| logger.set_max_log_level(log_level_filter)); } + _ => info!("log level set to INFO by default") } - match config::read_str("uart_log_level", |r| r?.parse()) { - Err(()) => { - info!("UART log level set to INFO by default"); - }, - Ok(uart_log_level_filter) => { + match config::read_str("uart_log_level", |r| r.map(|s| s.parse())) { + Ok(Ok(uart_log_level_filter)) => { info!("UART log level set to {} by `uart_log_level` config key", uart_log_level_filter); logger_artiq::BufferLogger::with(|logger| logger.set_uart_log_level(uart_log_level_filter)); } + _ => info!("UART log level set to INFO by default") } let mut net_stats = ethmac::EthernetStatistics::new(); @@ -247,7 +247,7 @@ pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u3 if config::read_str("panic_reboot", |r| r == Ok("1")) { println!("rebooting..."); - unsafe { board::boot::reboot() } + unsafe { board_artiq::boot::reboot() } } else { println!("halting."); println!("use `artiq_coreconfig write -s panic_reboot 1` to reboot instead"); diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 0cdb7eef6..23898f0f3 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -1,9 +1,9 @@ +use board_artiq::boot; use std::io::{self, Read, Write}; use log::LogLevelFilter; use logger_artiq::BufferLogger; use sched::Io; use sched::{TcpListener, TcpStream}; -use board; use proto::WriteExt; use mgmt_proto::*; @@ -86,14 +86,14 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> { Reply::RebootImminent.write_to(stream)?; stream.close()?; stream.flush()?; - unsafe { board::boot::hotswap(&firmware) } + unsafe { boot::hotswap(&firmware) } }, Request::Reboot => { Reply::RebootImminent.write_to(stream)?; stream.close()?; warn!("rebooting"); - unsafe { board::boot::reboot() } + unsafe { boot::reboot() } } }; } diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 35083315c..6917dc771 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -226,12 +226,13 @@ pub fn startup(io: &Io) { info!("using external startup RTIO clock"); RtioClock::External }, - Err(()) => { + Err(_) => { info!("using internal startup RTIO clock (by default)"); RtioClock::Internal }, Ok(_) => { - error!("unrecognized startup_clock configuration entry, using internal RTIO clock"); + error!("unrecognized startup_clock configuration entry, \ + using internal RTIO clock"); RtioClock::Internal } } diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index dd1fe3fde..1cb26509e 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -15,6 +15,7 @@ use rtio_mgt; use rtio_dma::Manager as DmaManager; use cache::Cache; use kern_hwreq; +use watchdog::WatchdogSet; use rpc_proto as rpc; use session_proto as host; @@ -66,7 +67,7 @@ enum KernelState { struct Session<'a> { congress: &'a mut Congress, kernel_state: KernelState, - watchdog_set: board::clock::WatchdogSet, + watchdog_set: WatchdogSet, log_buffer: String } @@ -75,7 +76,7 @@ impl<'a> Session<'a> { Session { congress: congress, kernel_state: KernelState::Absent, - watchdog_set: board::clock::WatchdogSet::new(), + watchdog_set: WatchdogSet::new(), log_buffer: String::new() } } @@ -226,7 +227,7 @@ fn process_host_message(io: &Io, match host_read(stream)? { host::Request::SystemInfo => { host_write(stream, host::Reply::SystemInfo { - ident: board::ident(&mut [0; 64]), + ident: board::ident::read(&mut [0; 64]), finished_cleanly: session.congress.finished_cleanly.get() })?; session.congress.finished_cleanly.set(true); @@ -238,7 +239,7 @@ fn process_host_message(io: &Io, config::read(key, |result| { match result { Ok(value) => host_write(stream, host::Reply::FlashRead(&value)), - Err(()) => host_write(stream, host::Reply::FlashError) + Err(_) => host_write(stream, host::Reply::FlashError) } }) } diff --git a/artiq/firmware/runtime/watchdog.rs b/artiq/firmware/runtime/watchdog.rs new file mode 100644 index 000000000..921472dae --- /dev/null +++ b/artiq/firmware/runtime/watchdog.rs @@ -0,0 +1,47 @@ +use board::clock; + +#[derive(Debug, Clone, Copy)] +struct Watchdog { + active: bool, + threshold: u64 +} + +pub const MAX_WATCHDOGS: usize = 16; + +#[derive(Debug)] +pub struct WatchdogSet { + watchdogs: [Watchdog; MAX_WATCHDOGS] +} + +impl WatchdogSet { + pub fn new() -> WatchdogSet { + WatchdogSet { + watchdogs: [Watchdog { active: false, threshold: 0 }; MAX_WATCHDOGS] + } + } + + pub fn set_ms(&mut self, interval: u64) -> Result { + for (index, watchdog) in self.watchdogs.iter_mut().enumerate() { + if !watchdog.active { + watchdog.active = true; + watchdog.threshold = clock::get_ms() + interval; + return Ok(index) + } + } + + Err(()) + } + + pub fn clear(&mut self, index: usize) { + if index < MAX_WATCHDOGS { + self.watchdogs[index].active = false + } + } + + pub fn expired(&self) -> bool { + self.watchdogs.iter() + .filter(|wd| wd.active) + .min_by_key(|wd| wd.threshold) + .map_or(false, |wd| clock::get_ms() > wd.threshold) + } +} From d3066e50444bc49160944e365e3cfe57b1a630f1 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 07:34:17 +0000 Subject: [PATCH 0113/2457] firmware: oops, misoc #[cfg]s were missing from libboard_artiq. --- artiq/firmware/Cargo.lock | 2 + artiq/firmware/libboard_artiq/Cargo.toml | 2 + artiq/firmware/libboard_artiq/build.rs | 2 + artiq/firmware/libboard_artiq/i2c.rs | 263 +++++++++++------------ artiq/firmware/libboard_artiq/lib.rs | 2 + artiq/firmware/libboard_artiq/si5324.rs | 5 +- 6 files changed, 136 insertions(+), 140 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 3b6ed3581..2144f7367 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -38,6 +38,8 @@ dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "board 0.0.0", "build_artiq 0.0.0", + "build_misoc 0.0.0", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/artiq/firmware/libboard_artiq/Cargo.toml b/artiq/firmware/libboard_artiq/Cargo.toml index 8ac55b6a2..2c92b6050 100644 --- a/artiq/firmware/libboard_artiq/Cargo.toml +++ b/artiq/firmware/libboard_artiq/Cargo.toml @@ -9,10 +9,12 @@ name = "board_artiq" path = "lib.rs" [build-dependencies] +build_misoc = { path = "../libbuild_misoc" } build_artiq = { path = "../libbuild_artiq" } [dependencies] bitflags = "1.0" +log = { version = "0.3", default-features = false } board = { path = "../libboard" } [features] diff --git a/artiq/firmware/libboard_artiq/build.rs b/artiq/firmware/libboard_artiq/build.rs index b787e5007..225cf707a 100644 --- a/artiq/firmware/libboard_artiq/build.rs +++ b/artiq/firmware/libboard_artiq/build.rs @@ -1,3 +1,4 @@ +extern crate build_misoc; extern crate build_artiq; use std::env; @@ -24,5 +25,6 @@ fn gen_hmc7043_writes() { } fn main() { + build_misoc::cfg(); gen_hmc7043_writes(); } diff --git a/artiq/firmware/libboard_artiq/i2c.rs b/artiq/firmware/libboard_artiq/i2c.rs index 6f3880645..819c21c1b 100644 --- a/artiq/firmware/libboard_artiq/i2c.rs +++ b/artiq/firmware/libboard_artiq/i2c.rs @@ -1,22 +1,18 @@ #[cfg(has_i2c)] -use csr; +mod imp { + use board::{csr, clock}; -#[cfg(has_i2c)] -mod io { - use csr; - use clock; - - pub fn half_period() { clock::spin_us(100) } + fn half_period() { clock::spin_us(100) } fn sda_bit(busno: u8) -> u8 { 1 << (2 * busno + 1) } fn scl_bit(busno: u8) -> u8 { 1 << (2 * busno) } - pub fn sda_i(busno: u8) -> bool { + fn sda_i(busno: u8) -> bool { unsafe { csr::i2c::in_read() & sda_bit(busno) != 0 } } - pub fn sda_oe(busno: u8, oe: bool) { + fn sda_oe(busno: u8, oe: bool) { unsafe { let reg = csr::i2c::oe_read(); let reg = if oe { reg | sda_bit(busno) } else { reg & !sda_bit(busno) }; @@ -24,7 +20,7 @@ mod io { } } - pub fn sda_o(busno: u8, o: bool) { + fn sda_o(busno: u8, o: bool) { unsafe { let reg = csr::i2c::out_read(); let reg = if o { reg | sda_bit(busno) } else { reg & !sda_bit(busno) }; @@ -32,7 +28,7 @@ mod io { } } - pub fn scl_oe(busno: u8, oe: bool) { + fn scl_oe(busno: u8, oe: bool) { unsafe { let reg = csr::i2c::oe_read(); let reg = if oe { reg | scl_bit(busno) } else { reg & !scl_bit(busno) }; @@ -40,151 +36,144 @@ mod io { } } - pub fn scl_o(busno: u8, o: bool) { + fn scl_o(busno: u8, o: bool) { unsafe { let reg = csr::i2c::out_read(); let reg = if o { reg | scl_bit(busno) } else { reg & !scl_bit(busno) }; csr::i2c::out_write(reg) } } -} -#[cfg(has_i2c)] -pub fn init() { - for busno in 0..csr::CONFIG_I2C_BUS_COUNT { - let busno = busno as u8; - // Set SCL as output, and high level - io::scl_o(busno, true); - io::scl_oe(busno, true); - // Prepare a zero level on SDA so that sda_oe pulls it down - io::sda_o(busno, false); - // Release SDA - io::sda_oe(busno, false); + pub fn init() { + for busno in 0..csr::CONFIG_I2C_BUS_COUNT { + let busno = busno as u8; + // Set SCL as output, and high level + scl_o(busno, true); + scl_oe(busno, true); + // Prepare a zero level on SDA so that sda_oe pulls it down + sda_o(busno, false); + // Release SDA + sda_oe(busno, false); - // Check the I2C bus is ready - io::half_period(); - io::half_period(); - if !io::sda_i(busno) { - error!("SDA is stuck low on bus #{}", busno) + // Check the I2C bus is ready + half_period(); + half_period(); + if !sda_i(busno) { + error!("SDA is stuck low on bus #{}", busno) + } } } -} -#[cfg(has_i2c)] -pub fn start(busno: u8) -> Result<(), ()> { - if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { - return Err(()) + pub fn start(busno: u8) -> Result<(), ()> { + if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { + return Err(()) + } + // Set SCL high then SDA low + scl_o(busno, true); + half_period(); + sda_oe(busno, true); + half_period(); + Ok(()) } - // Set SCL high then SDA low - io::scl_o(busno, true); - io::half_period(); - io::sda_oe(busno, true); - io::half_period(); - Ok(()) -} -#[cfg(has_i2c)] -pub fn restart(busno: u8) -> Result<(), ()> { - if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { - return Err(()) + pub fn restart(busno: u8) -> Result<(), ()> { + if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { + return Err(()) + } + // Set SCL low then SDA high */ + scl_o(busno, false); + half_period(); + sda_oe(busno, false); + half_period(); + // Do a regular start + start(busno)?; + Ok(()) } - // Set SCL low then SDA high */ - io::scl_o(busno, false); - io::half_period(); - io::sda_oe(busno, false); - io::half_period(); - // Do a regular start - start(busno)?; - Ok(()) -} -#[cfg(has_i2c)] -pub fn stop(busno: u8) -> Result<(), ()> { - if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { - return Err(()) + pub fn stop(busno: u8) -> Result<(), ()> { + if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { + return Err(()) + } + // First, make sure SCL is low, so that the target releases the SDA line + scl_o(busno, false); + half_period(); + // Set SCL high then SDA high + sda_oe(busno, true); + scl_o(busno, true); + half_period(); + sda_oe(busno, false); + half_period(); + Ok(()) } - // First, make sure SCL is low, so that the target releases the SDA line - io::scl_o(busno, false); - io::half_period(); - // Set SCL high then SDA high - io::sda_oe(busno, true); - io::scl_o(busno, true); - io::half_period(); - io::sda_oe(busno, false); - io::half_period(); - Ok(()) -} -#[cfg(has_i2c)] -pub fn write(busno: u8, data: u8) -> Result { - if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { - return Err(()) + pub fn write(busno: u8, data: u8) -> Result { + if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { + return Err(()) + } + // MSB first + for bit in (0..8).rev() { + // Set SCL low and set our bit on SDA + scl_o(busno, false); + sda_oe(busno, data & (1 << bit) == 0); + half_period(); + // Set SCL high ; data is shifted on the rising edge of SCL + scl_o(busno, true); + half_period(); + } + // Check ack + // Set SCL low, then release SDA so that the I2C target can respond + scl_o(busno, false); + half_period(); + sda_oe(busno, false); + // Set SCL high and check for ack + scl_o(busno, true); + half_period(); + // returns true if acked (I2C target pulled SDA low) + Ok(!sda_i(busno)) } - // MSB first - for bit in (0..8).rev() { - // Set SCL low and set our bit on SDA - io::scl_o(busno, false); - io::sda_oe(busno, data & (1 << bit) == 0); - io::half_period(); - // Set SCL high ; data is shifted on the rising edge of SCL - io::scl_o(busno, true); - io::half_period(); + + pub fn read(busno: u8, ack: bool) -> Result { + if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { + return Err(()) + } + // Set SCL low first, otherwise setting SDA as input may cause a transition + // on SDA with SCL high which will be interpreted as START/STOP condition. + scl_o(busno, false); + half_period(); // make sure SCL has settled low + sda_oe(busno, false); + + let mut data: u8 = 0; + + // MSB first + for bit in (0..8).rev() { + scl_o(busno, false); + half_period(); + // Set SCL high and shift data + scl_o(busno, true); + half_period(); + if sda_i(busno) { data |= 1 << bit } + } + // Send ack + // Set SCL low and pull SDA low when acking + scl_o(busno, false); + if ack { sda_oe(busno, true) } + half_period(); + // then set SCL high + scl_o(busno, true); + half_period(); + + Ok(data) } - // Check ack - // Set SCL low, then release SDA so that the I2C target can respond - io::scl_o(busno, false); - io::half_period(); - io::sda_oe(busno, false); - // Set SCL high and check for ack - io::scl_o(busno, true); - io::half_period(); - // returns true if acked (I2C target pulled SDA low) - Ok(!io::sda_i(busno)) -} - -#[cfg(has_i2c)] -pub fn read(busno: u8, ack: bool) -> Result { - if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { - return Err(()) - } - // Set SCL low first, otherwise setting SDA as input may cause a transition - // on SDA with SCL high which will be interpreted as START/STOP condition. - io::scl_o(busno, false); - io::half_period(); // make sure SCL has settled low - io::sda_oe(busno, false); - - let mut data: u8 = 0; - - // MSB first - for bit in (0..8).rev() { - io::scl_o(busno, false); - io::half_period(); - // Set SCL high and shift data - io::scl_o(busno, true); - io::half_period(); - if io::sda_i(busno) { data |= 1 << bit } - } - // Send ack - // Set SCL low and pull SDA low when acking - io::scl_o(busno, false); - if ack { io::sda_oe(busno, true) } - io::half_period(); - // then set SCL high - io::scl_o(busno, true); - io::half_period(); - - Ok(data) } #[cfg(not(has_i2c))] -pub fn init() {} -#[cfg(not(has_i2c))] -pub fn start(_busno: u8) -> Result<(), ()> { Err(()) } -#[cfg(not(has_i2c))] -pub fn restart(_busno: u8) -> Result<(), ()> { Err(()) } -#[cfg(not(has_i2c))] -pub fn stop(_busno: u8) -> Result<(), ()> { Err(()) } -#[cfg(not(has_i2c))] -pub fn write(_busno: u8, _data: u8) -> Result { Err(()) } -#[cfg(not(has_i2c))] -pub fn read(_busno: u8, _ack: bool) -> Result { Err(()) } +mod imp { + pub fn init() {} + pub fn start(_busno: u8) -> Result<(), ()> { Err(()) } + pub fn restart(_busno: u8) -> Result<(), ()> { Err(()) } + pub fn stop(_busno: u8) -> Result<(), ()> { Err(()) } + pub fn write(_busno: u8, _data: u8) -> Result { Err(()) } + pub fn read(_busno: u8, _ack: bool) -> Result { Err(()) } +} + +pub use self::imp::*; diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 894866980..c40f899c3 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -3,6 +3,8 @@ #[macro_use] extern crate bitflags; +#[macro_use] +extern crate log; extern crate board; pub mod pcr; diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 5cea4f814..574e1ba53 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -1,7 +1,6 @@ use core::result; +use board::{csr, clock}; use i2c; -use clock; -use csr; type Result = result::Result; @@ -200,8 +199,8 @@ pub fn setup(settings: &FrequencySettings) -> Result<()> { if !has_clkin2()? { return Err("Si5324 misses CLKIN2 signal"); } - monitor_lock()?; + monitor_lock()?; Ok(()) } From 3b18ece3b788c71082bae3b4234cb7ec56d1717c Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 07:10:34 +0000 Subject: [PATCH 0114/2457] satman: update for changes in firmware elsewhere. --- artiq/firmware/Cargo.lock | 1 + artiq/firmware/runtime/lib.rs | 1 - artiq/firmware/satman/Cargo.toml | 5 +- artiq/firmware/satman/lib.rs | 85 ++++++++++++++++++-------------- artiq/firmware/satman/satman.ld | 45 +++++------------ artiq/frontend/artiq_devtool.py | 7 +-- 6 files changed, 68 insertions(+), 76 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 2144f7367..aa3483f37 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -216,6 +216,7 @@ version = "0.0.0" dependencies = [ "alloc_list 0.0.0", "board 0.0.0", + "board_artiq 0.0.0", "build_artiq 0.0.0", "compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)", "drtioaux 0.0.0", diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index 158abecb1..83081b0cc 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -230,7 +230,6 @@ pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { #[no_mangle] pub extern fn abort() { println!("aborted"); - loop {} } diff --git a/artiq/firmware/satman/Cargo.toml b/artiq/firmware/satman/Cargo.toml index b8c7106f5..f3aa3cc4a 100644 --- a/artiq/firmware/satman/Cargo.toml +++ b/artiq/firmware/satman/Cargo.toml @@ -13,12 +13,13 @@ path = "lib.rs" build_artiq = { path = "../libbuild_artiq" } [dependencies] +log = { version = "0.3", default-features = false } alloc_list = { path = "../liballoc_list" } +board = { path = "../libboard", features = ["uart_console"] } +board_artiq = { path = "../libboard_artiq" } std_artiq = { path = "../libstd_artiq", features = ["alloc"] } logger_artiq = { path = "../liblogger_artiq" } -board = { path = "../libboard", features = ["uart_console"] } drtioaux = { path = "../libdrtioaux" } -log = { version = "0.3", default-features = false } [dependencies.compiler_builtins] git = "https://github.com/rust-lang-nursery/compiler-builtins" diff --git a/artiq/firmware/satman/lib.rs b/artiq/firmware/satman/lib.rs index d9a72e273..2e9110e7a 100644 --- a/artiq/firmware/satman/lib.rs +++ b/artiq/firmware/satman/lib.rs @@ -9,8 +9,16 @@ extern crate log; extern crate logger_artiq; #[macro_use] extern crate board; +extern crate board_artiq; extern crate drtioaux; +use board::csr; +use board_artiq::{i2c, spi, si5324}; +#[cfg(has_serwb_phy_amc)] +use board_artiq::serwb; +#[cfg(has_hmc830_7043)] +use board_artiq::hmc830_7043; + fn process_aux_packet(p: &drtioaux::Packet) { // In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels, // and u16 otherwise; hence the `as _` conversion. @@ -20,16 +28,16 @@ fn process_aux_packet(p: &drtioaux::Packet) { drtioaux::Packet::RtioErrorRequest => { let errors; unsafe { - errors = (board::csr::DRTIO[0].rtio_error_read)(); + errors = (csr::DRTIO[0].rtio_error_read)(); } if errors & 1 != 0 { unsafe { - (board::csr::DRTIO[0].rtio_error_write)(1); + (csr::DRTIO[0].rtio_error_write)(1); } drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorCollisionReply).unwrap(); } else if errors & 2 != 0 { unsafe { - (board::csr::DRTIO[0].rtio_error_write)(2); + (csr::DRTIO[0].rtio_error_write)(2); } drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorBusyReply).unwrap(); } else { @@ -41,10 +49,10 @@ fn process_aux_packet(p: &drtioaux::Packet) { let value; #[cfg(has_rtio_moninj)] unsafe { - board::csr::rtio_moninj::mon_chan_sel_write(channel as _); - board::csr::rtio_moninj::mon_probe_sel_write(probe); - board::csr::rtio_moninj::mon_value_update_write(1); - value = board::csr::rtio_moninj::mon_value_read(); + csr::rtio_moninj::mon_chan_sel_write(channel as _); + csr::rtio_moninj::mon_probe_sel_write(probe); + csr::rtio_moninj::mon_value_update_write(1); + value = csr::rtio_moninj::mon_value_read(); } #[cfg(not(has_rtio_moninj))] { @@ -56,18 +64,18 @@ fn process_aux_packet(p: &drtioaux::Packet) { drtioaux::Packet::InjectionRequest { channel, overrd, value } => { #[cfg(has_rtio_moninj)] unsafe { - board::csr::rtio_moninj::inj_chan_sel_write(channel as _); - board::csr::rtio_moninj::inj_override_sel_write(overrd); - board::csr::rtio_moninj::inj_value_write(value); + csr::rtio_moninj::inj_chan_sel_write(channel as _); + csr::rtio_moninj::inj_override_sel_write(overrd); + csr::rtio_moninj::inj_value_write(value); } }, drtioaux::Packet::InjectionStatusRequest { channel, overrd } => { let value; #[cfg(has_rtio_moninj)] unsafe { - board::csr::rtio_moninj::inj_chan_sel_write(channel as _); - board::csr::rtio_moninj::inj_override_sel_write(overrd); - value = board::csr::rtio_moninj::inj_value_read(); + csr::rtio_moninj::inj_chan_sel_write(channel as _); + csr::rtio_moninj::inj_override_sel_write(overrd); + value = csr::rtio_moninj::inj_value_read(); } #[cfg(not(has_rtio_moninj))] { @@ -78,44 +86,44 @@ fn process_aux_packet(p: &drtioaux::Packet) { }, drtioaux::Packet::I2cStartRequest { busno } => { - let succeeded = board::i2c::start(busno).is_ok(); + let succeeded = i2c::start(busno).is_ok(); drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }).unwrap(); } drtioaux::Packet::I2cRestartRequest { busno } => { - let succeeded = board::i2c::restart(busno).is_ok(); + let succeeded = i2c::restart(busno).is_ok(); drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }).unwrap(); } drtioaux::Packet::I2cStopRequest { busno } => { - let succeeded = board::i2c::stop(busno).is_ok(); + let succeeded = i2c::stop(busno).is_ok(); drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }).unwrap(); } drtioaux::Packet::I2cWriteRequest { busno, data } => { - match board::i2c::write(busno, data) { + match i2c::write(busno, data) { Ok(ack) => drtioaux::hw::send_link(0, &drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }).unwrap(), Err(_) => drtioaux::hw::send_link(0, &drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false }).unwrap() }; } drtioaux::Packet::I2cReadRequest { busno, ack } => { - match board::i2c::read(busno, ack) { + match i2c::read(busno, ack) { Ok(data) => drtioaux::hw::send_link(0, &drtioaux::Packet::I2cReadReply { succeeded: true, data: data }).unwrap(), Err(_) => drtioaux::hw::send_link(0, &drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff }).unwrap() }; } drtioaux::Packet::SpiSetConfigRequest { busno, flags, write_div, read_div } => { - let succeeded = board::spi::set_config(busno, flags, write_div, read_div).is_ok(); + let succeeded = spi::set_config(busno, flags, write_div, read_div).is_ok(); drtioaux::hw::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }).unwrap(); }, drtioaux::Packet::SpiSetXferRequest { busno, chip_select, write_length, read_length } => { - let succeeded = board::spi::set_xfer(busno, chip_select, write_length, read_length).is_ok(); + let succeeded = spi::set_xfer(busno, chip_select, write_length, read_length).is_ok(); drtioaux::hw::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }).unwrap(); } drtioaux::Packet::SpiWriteRequest { busno, data } => { - let succeeded = board::spi::write(busno, data).is_ok(); + let succeeded = spi::write(busno, data).is_ok(); drtioaux::hw::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }).unwrap(); } drtioaux::Packet::SpiReadRequest { busno } => { - match board::spi::read(busno) { + match spi::read(busno) { Ok(data) => drtioaux::hw::send_link(0, &drtioaux::Packet::SpiReadReply { succeeded: true, data: data }).unwrap(), Err(_) => drtioaux::hw::send_link(0, &drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 }).unwrap() }; @@ -138,8 +146,8 @@ fn process_aux_packets() { fn process_errors() { let errors; unsafe { - errors = (board::csr::DRTIO[0].protocol_error_read)(); - (board::csr::DRTIO[0].protocol_error_write)(errors); + errors = (csr::DRTIO[0].protocol_error_read)(); + (csr::DRTIO[0].protocol_error_write)(errors); } if errors & 1 != 0 { error!("received packet of an unknown type"); @@ -160,8 +168,8 @@ fn process_errors() { #[cfg(rtio_frequency = "62.5")] -const SI5324_SETTINGS: board::si5324::FrequencySettings - = board::si5324::FrequencySettings { +const SI5324_SETTINGS: si5324::FrequencySettings + = si5324::FrequencySettings { n1_hs : 10, nc1_ls : 8, n2_hs : 10, @@ -172,8 +180,8 @@ const SI5324_SETTINGS: board::si5324::FrequencySettings }; #[cfg(rtio_frequency = "150.0")] -const SI5324_SETTINGS: board::si5324::FrequencySettings - = board::si5324::FrequencySettings { +const SI5324_SETTINGS: si5324::FrequencySettings + = si5324::FrequencySettings { n1_hs : 9, nc1_ls : 4, n2_hs : 10, @@ -185,7 +193,7 @@ const SI5324_SETTINGS: board::si5324::FrequencySettings fn drtio_link_is_up() -> bool { unsafe { - (board::csr::DRTIO[0].link_status_read)() == 1 + (csr::DRTIO[0].link_status_read)() == 1 } } @@ -193,28 +201,28 @@ fn startup() { board::clock::init(); info!("ARTIQ satellite manager starting..."); info!("software version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); - info!("gateware version {}", board::ident(&mut [0; 64])); + info!("gateware version {}", board::ident::read(&mut [0; 64])); #[cfg(has_serwb_phy_amc)] - board::serwb::wait_init(); + serwb::wait_init(); #[cfg(has_hmc830_7043)] - board::hmc830_7043::init().expect("cannot initialize HMC830/7043"); - board::i2c::init(); - board::si5324::setup(&SI5324_SETTINGS).expect("cannot initialize Si5324"); + hmc830_7043::init().expect("cannot initialize HMC830/7043"); + i2c::init(); + si5324::setup(&SI5324_SETTINGS).expect("cannot initialize Si5324"); loop { while !drtio_link_is_up() { process_errors(); } info!("link is up, switching to recovered clock"); - board::si5324::select_ext_input(true).expect("failed to switch clocks"); + si5324::select_ext_input(true).expect("failed to switch clocks"); while drtio_link_is_up() { process_errors(); process_aux_packets(); } info!("link is down, switching to local crystal clock"); - board::si5324::select_ext_input(false).expect("failed to switch clocks"); + si5324::select_ext_input(false).expect("failed to switch clocks"); } } @@ -237,13 +245,14 @@ pub extern fn main() -> i32 { } #[no_mangle] -pub extern fn exception_handler(vect: u32, _regs: *const u32, pc: u32, ea: u32) { +pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea) } #[no_mangle] pub extern fn abort() { - panic!("aborted") + println!("aborted"); + loop {} } #[no_mangle] diff --git a/artiq/firmware/satman/satman.ld b/artiq/firmware/satman/satman.ld index 89a1d6e7e..f6e4c6a6a 100644 --- a/artiq/firmware/satman/satman.ld +++ b/artiq/firmware/satman/satman.ld @@ -1,22 +1,23 @@ INCLUDE generated/output_format.ld -STARTUP(crt0-or1k.o) -ENTRY(_start) - INCLUDE generated/regions.ld +ENTRY(_reset_handler) SECTIONS { + .vectors : + { + *(.vectors) + } > main_ram + .text : { - _ftext = .; - *(.text .stub .text.* .gnu.linkonce.t.*) - _etext = .; + *(.text .text.*) } > main_ram /* https://sourceware.org/bugzilla/show_bug.cgi?id=20475 */ .got : { - _GLOBAL_OFFSET_TABLE_ = .; + PROVIDE(_GLOBAL_OFFSET_TABLE_ = .); *(.got) } > main_ram @@ -27,40 +28,26 @@ SECTIONS .rodata : { - . = ALIGN(4); _frodata = .; - *(.rodata .rodata.* .gnu.linkonce.r.*) - *(.rodata1) + *(.rodata .rodata.*) _erodata = .; } > main_ram .data : { - . = ALIGN(4); - _fdata = .; - *(.data .data.* .gnu.linkonce.d.*) - *(.data1) - *(.sdata .sdata.* .gnu.linkonce.s.*) - _edata = .; + *(.data .data.*) } > main_ram - .bss : + .bss ALIGN(4) : { - . = ALIGN(4); _fbss = .; - *(.dynsbss) - *(.sbss .sbss.* .gnu.linkonce.sb.*) - *(.scommon) - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) + *(.bss .bss.*) . = ALIGN(4); _ebss = .; } > main_ram - .stack : + .stack ALIGN(0x1000) : { - . = ALIGN(0x1000); _estack = .; . += 0x4000; _fstack = . - 4; @@ -72,10 +59,4 @@ SECTIONS . = ORIGIN(main_ram) + LENGTH(main_ram); _eheap = .; } > main_ram - - /DISCARD/ : - { - *(.eh_frame) - *(.gcc_except_table) - } } diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index a2c5bbfd1..951c04db7 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -39,7 +39,8 @@ def get_argparser(): parser.add_argument("-t", "--target", metavar="TARGET", type=str, default="kc705_dds", help="Target to build, one of: " - "kc705_dds kc705_drtio_master kc705_drtio_satellite") + "kc705_dds sayma_amc_standalone " + "sayma_amc_drtio_master sayma_amc_drtio_satellite") parser.add_argument("actions", metavar="ACTION", type=str, default=[], nargs="+", @@ -55,9 +56,9 @@ def main(): if args.verbose == args.quiet == 0: logging.getLogger().setLevel(logging.INFO) - if args.target == "kc705_dds" or args.target == "kc705_drtio_master": + if args.target in ["kc705_dds", "sayma_amc_standalone", "sayma_amc_drtio_master"]: firmware = "runtime" - elif args.target == "kc705_drtio_satellite": + elif args.target == "sayma_amc_drtio_satellite": firmware = "satman" else: raise NotImplementedError("unknown target {}".format(args.target)) From 4ea801b2ea4267f79d8839e79a67f6dc62eddb83 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Dec 2017 15:45:45 +0800 Subject: [PATCH 0115/2457] firmware: si5324 moved to board_artiq --- artiq/firmware/runtime/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index 83081b0cc..98f38aa92 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -92,8 +92,8 @@ fn startup() { fn setup_si5324_free_running() { // 150MHz output (hardcoded) - const SI5324_SETTINGS: board::si5324::FrequencySettings - = board::si5324::FrequencySettings { + const SI5324_SETTINGS: board_artiq::si5324::FrequencySettings + = board_artiq::si5324::FrequencySettings { n1_hs : 9, nc1_ls : 4, n2_hs : 10, @@ -102,7 +102,7 @@ fn setup_si5324_free_running() n32 : 7139, bwsel : 3 }; - board::si5324::setup(&SI5324_SETTINGS).expect("cannot initialize Si5324"); + board_artiq::si5324::setup(&SI5324_SETTINGS).expect("cannot initialize Si5324"); } #[cfg(has_ethmac)] From 8f33061a6d765e830603c3fb4c080db06719a973 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 08:15:51 +0000 Subject: [PATCH 0116/2457] firmware: fix sayma_amc_standalone build with sawg. --- artiq/firmware/libboard_artiq/ad9154.rs | 3 +- artiq/firmware/libboard_artiq/hmc830_7043.rs | 7 +- artiq/firmware/libboard_artiq/serwb.rs | 2 +- artiq/firmware/libboard_artiq/spi.rs | 109 ++++++++++--------- artiq/firmware/runtime/lib.rs | 6 +- 5 files changed, 63 insertions(+), 64 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 9da8ec748..5d2f4c057 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -1,5 +1,4 @@ -use csr; -use clock; +use board::{csr, clock}; use ad9154_reg; fn spi_setup(dacno: u8) { diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index ab106cd2c..56ea4792e 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -11,7 +11,7 @@ */ mod clock_mux { - use csr; + use board::csr; const CLK_SRC_EXT_SEL : u8 = 1 << 0; const REF_CLK_SRC_SEL : u8 = 1 << 1; @@ -28,8 +28,7 @@ mod clock_mux { } mod hmc830 { - use clock; - use csr; + use board::{csr, clock}; const HMC830_WRITES: [(u8, u32); 16] = [ (0x0, 0x20), @@ -117,7 +116,7 @@ mod hmc830 { } mod hmc7043 { - use csr; + use board::csr; include!(concat!(env!("OUT_DIR"), "/hmc7043_writes.rs")); diff --git a/artiq/firmware/libboard_artiq/serwb.rs b/artiq/firmware/libboard_artiq/serwb.rs index 687d5ea04..69b9f9676 100644 --- a/artiq/firmware/libboard_artiq/serwb.rs +++ b/artiq/firmware/libboard_artiq/serwb.rs @@ -1,4 +1,4 @@ -use csr; +use board::csr; pub fn wait_init() { info!("waiting for AMC/RTM serwb bridge to be ready..."); diff --git a/artiq/firmware/libboard_artiq/spi.rs b/artiq/firmware/libboard_artiq/spi.rs index 3c0611311..44aa0c729 100644 --- a/artiq/firmware/libboard_artiq/spi.rs +++ b/artiq/firmware/libboard_artiq/spi.rs @@ -1,66 +1,67 @@ #[cfg(has_converter_spi)] -use csr; +mod imp { + use board::csr; -#[cfg(has_converter_spi)] -pub fn set_config(busno: u8, flags: u8, write_div: u8, read_div: u8) -> Result<(), ()> { - if busno != 0 { - return Err(()) + pub fn set_config(busno: u8, flags: u8, write_div: u8, read_div: u8) -> Result<(), ()> { + if busno != 0 { + return Err(()) + } + unsafe { + csr::converter_spi::offline_write(1); + csr::converter_spi::cs_polarity_write(flags >> 3 & 1); + csr::converter_spi::clk_polarity_write(flags >> 4 & 1); + csr::converter_spi::clk_phase_write(flags >> 5 & 1); + csr::converter_spi::lsb_first_write(flags >> 6 & 1); + csr::converter_spi::half_duplex_write(flags >> 7 & 1); + csr::converter_spi::clk_div_write_write(write_div); + csr::converter_spi::clk_div_read_write(read_div); + csr::converter_spi::offline_write(0); + } + Ok(()) } - unsafe { - csr::converter_spi::offline_write(1); - csr::converter_spi::cs_polarity_write(flags >> 3 & 1); - csr::converter_spi::clk_polarity_write(flags >> 4 & 1); - csr::converter_spi::clk_phase_write(flags >> 5 & 1); - csr::converter_spi::lsb_first_write(flags >> 6 & 1); - csr::converter_spi::half_duplex_write(flags >> 7 & 1); - csr::converter_spi::clk_div_write_write(write_div); - csr::converter_spi::clk_div_read_write(read_div); - csr::converter_spi::offline_write(0); - } - Ok(()) -} -#[cfg(has_converter_spi)] -pub fn set_xfer(busno: u8, chip_select: u16, write_length: u8, read_length: u8) -> Result<(), ()> { - if busno != 0 { - return Err(()) + pub fn set_xfer(busno: u8, chip_select: u16, write_length: u8, read_length: u8) + -> Result<(), ()> { + if busno != 0 { + return Err(()) + } + unsafe { + csr::converter_spi::cs_write(chip_select as _); + csr::converter_spi::xfer_len_write_write(write_length); + csr::converter_spi::xfer_len_read_write(read_length); + } + Ok(()) } - unsafe { - csr::converter_spi::cs_write(chip_select as _); - csr::converter_spi::xfer_len_write_write(write_length); - csr::converter_spi::xfer_len_read_write(read_length); - } - Ok(()) -} -#[cfg(has_converter_spi)] -pub fn write(busno: u8, data: u32) -> Result<(), ()> { - if busno != 0 { - return Err(()) + pub fn write(busno: u8, data: u32) -> Result<(), ()> { + if busno != 0 { + return Err(()) + } + unsafe { + csr::converter_spi::data_write_write(data); + while csr::converter_spi::pending_read() != 0 {} + while csr::converter_spi::active_read() != 0 {} + } + Ok(()) } - unsafe { - csr::converter_spi::data_write_write(data); - while csr::converter_spi::pending_read() != 0 {} - while csr::converter_spi::active_read() != 0 {} - } - Ok(()) -} -#[cfg(has_converter_spi)] -pub fn read(busno: u8) -> Result { - if busno != 0 { - return Err(()) + pub fn read(busno: u8) -> Result { + if busno != 0 { + return Err(()) + } + Ok(unsafe { + csr::converter_spi::data_read_read() + }) } - Ok(unsafe { - csr::converter_spi::data_read_read() - }) } #[cfg(not(has_converter_spi))] -pub fn set_config(_busno: u8, _flags: u8, _write_div: u8, _read_div: u8) -> Result<(), ()> { Err(()) } -#[cfg(not(has_converter_spi))] -pub fn set_xfer(_busno: u8,_chip_select: u16, _write_length: u8, _read_length: u8) -> Result<(), ()> { Err(()) } -#[cfg(not(has_converter_spi))] -pub fn write(_busno: u8,_data: u32) -> Result<(), ()> { Err(()) } -#[cfg(not(has_converter_spi))] -pub fn read(_busno: u8,) -> Result { Err(()) } +mod imp { + pub fn set_config(_busno: u8, _flags: u8, _write_div: u8, _read_div: u8) -> Result<(), ()> { Err(()) } + pub fn set_xfer(_busno: u8,_chip_select: u16, _write_length: u8, _read_length: u8) + -> Result<(), ()> { Err(()) } + pub fn write(_busno: u8,_data: u32) -> Result<(), ()> { Err(()) } + pub fn read(_busno: u8,) -> Result { Err(()) } +} + +pub use self::imp::*; diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index 98f38aa92..0cb4e6a58 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -56,7 +56,7 @@ fn startup() { info!("gateware version {}", board::ident::read(&mut [0; 64])); #[cfg(has_serwb_phy_amc)] - board::serwb::wait_init(); + board_artiq::serwb::wait_init(); let t = board::clock::get_ms(); info!("press 'e' to erase startup and idle kernels..."); @@ -75,9 +75,9 @@ fn startup() { #[cfg(si5324_free_running)] setup_si5324_free_running(); #[cfg(has_hmc830_7043)] - board::hmc830_7043::init().expect("cannot initialize HMC830/7043"); + board_artiq::hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] - board::ad9154::init().expect("cannot initialize AD9154"); + board_artiq::ad9154::init().expect("cannot initialize AD9154"); #[cfg(has_ethmac)] startup_ethernet(); From 1b9b5602420a7dfde8c9433481cb10f070aca840 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 08:05:38 +0000 Subject: [PATCH 0117/2457] firmware: use libbuild_misoc in libdrtioaux. NFC. --- artiq/firmware/Cargo.lock | 32 +++++++++++ artiq/firmware/Cargo.toml | 2 +- artiq/firmware/bootloader/Cargo.toml | 18 ++++++ artiq/firmware/bootloader/Makefile | 18 ++++++ artiq/firmware/bootloader/bootloader.ld | 46 ++++++++++++++++ artiq/firmware/bootloader/build.rs | 6 ++ artiq/firmware/bootloader/main.rs | 73 +++++++++++++++++++++++++ artiq/firmware/libdrtioaux/Cargo.toml | 3 + artiq/firmware/libdrtioaux/build.rs | 14 +---- artiq/gateware/amp/soc.py | 1 + 10 files changed, 200 insertions(+), 13 deletions(-) create mode 100644 artiq/firmware/bootloader/Cargo.toml create mode 100644 artiq/firmware/bootloader/Makefile create mode 100644 artiq/firmware/bootloader/bootloader.ld create mode 100644 artiq/firmware/bootloader/build.rs create mode 100644 artiq/firmware/bootloader/main.rs diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index aa3483f37..dd4bf58f7 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -42,6 +42,16 @@ dependencies = [ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bootloader" +version = "0.0.0" +dependencies = [ + "board 0.0.0", + "build_artiq 0.0.0", + "crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)", + "rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "build_artiq" version = "0.0.0" @@ -49,6 +59,11 @@ dependencies = [ "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "build_const" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "build_misoc" version = "0.0.0" @@ -77,6 +92,14 @@ name = "compiler_builtins" version = "0.1.0" source = "git+https://github.com/m-labs/compiler-builtins?rev=97916b1#97916b17ca542eac0524b8570c7d05913891a0dc" +[[package]] +name = "crc" +version = "1.6.0" +source = "git+git://github.com/whitequark/crc-rs?rev=51cd356#51cd3560aa9d3823061f2bb46797d8c61f4cfa9e" +dependencies = [ + "build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cslice" version = "0.3.0" @@ -87,6 +110,7 @@ name = "drtioaux" version = "0.0.0" dependencies = [ "board 0.0.0", + "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "std_artiq 0.0.0", @@ -174,6 +198,11 @@ dependencies = [ "std_artiq 0.0.0", ] +[[package]] +name = "rlibc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "runtime" version = "0.0.0" @@ -261,10 +290,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" +"checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" "checksum compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)" = "" "checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)" = "" +"checksum crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)" = "" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" "checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" @@ -273,6 +304,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" "checksum managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)" = "" +"checksum rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" "checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)" = "" diff --git a/artiq/firmware/Cargo.toml b/artiq/firmware/Cargo.toml index af13ba5ff..0f2007873 100644 --- a/artiq/firmware/Cargo.toml +++ b/artiq/firmware/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["runtime", "ksupport", "satman"] +members = ["bootloader", "runtime", "ksupport", "satman"] diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml new file mode 100644 index 000000000..cbf8ccef7 --- /dev/null +++ b/artiq/firmware/bootloader/Cargo.toml @@ -0,0 +1,18 @@ +[package] +authors = ["M-Labs"] +name = "bootloader" +version = "0.0.0" +build = "build.rs" + +[lib] +name = "bootloader" +crate-type = ["staticlib"] +path = "main.rs" + +[build-dependencies] +build_artiq = { path = "../libbuild_artiq" } + +[dependencies] +rlibc = "1.0" +crc = { git = "git://github.com/whitequark/crc-rs", rev = "51cd356", default-features = false } +board = { path = "../libboard", features = ["uart_console"] } diff --git a/artiq/firmware/bootloader/Makefile b/artiq/firmware/bootloader/Makefile new file mode 100644 index 000000000..f247c0994 --- /dev/null +++ b/artiq/firmware/bootloader/Makefile @@ -0,0 +1,18 @@ +include ../include/generated/variables.mak +include $(MISOC_DIRECTORY)/software/common.mak + +RUSTFLAGS += -Cpanic=abort + +all:: bootloader.bin + +.PHONY: $(RUSTOUT)/libbootloader.a +$(RUSTOUT)/libbootloader.a: + $(cargo) --manifest-path $(BOOTLOADER_DIRECTORY)/Cargo.toml -- \ + -Clto + +bootloader.elf: $(RUSTOUT)/libbootloader.a + $(link) -T $(BOOTLOADER_DIRECTORY)/bootloader.ld + +%.bin: %.elf + $(objcopy) -O binary + $(MSCIMG) $@ diff --git a/artiq/firmware/bootloader/bootloader.ld b/artiq/firmware/bootloader/bootloader.ld new file mode 100644 index 000000000..8fe809a49 --- /dev/null +++ b/artiq/firmware/bootloader/bootloader.ld @@ -0,0 +1,46 @@ +INCLUDE generated/output_format.ld +INCLUDE generated/regions.ld +ENTRY(_reset_handler) + +SECTIONS +{ + .vectors : + { + _begin = .; + *(.vectors) + } > rom + + .text : + { + *(.text .text.*) + } > rom + + .rodata : + { + *(.rodata.*) + . = ALIGN(4); + _end = .; + } > rom + + .crc ALIGN(4) : + { + _crc = .; + . += 4; + } + + .bss ALIGN(4) : + { + _fbss = .; + *(.bss .bss.*) + . = ALIGN(4); + _ebss = .; + } > sram + + .stack : + { + /* Ensure we have a certain amount of space available for stack. */ + . = ORIGIN(sram) + LENGTH(sram) - 0x800; + . = ORIGIN(sram) + LENGTH(sram) - 4; + _fstack = .; + } > sram +} diff --git a/artiq/firmware/bootloader/build.rs b/artiq/firmware/bootloader/build.rs new file mode 100644 index 000000000..0a7d63df9 --- /dev/null +++ b/artiq/firmware/bootloader/build.rs @@ -0,0 +1,6 @@ +extern crate build_artiq; + +fn main() { + build_artiq::misoc_cfg(); + build_artiq::git_describe(); +} diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs new file mode 100644 index 000000000..ec9f54bbf --- /dev/null +++ b/artiq/firmware/bootloader/main.rs @@ -0,0 +1,73 @@ +#![no_std] +#![feature(lang_items)] + +extern crate rlibc; +extern crate crc; +#[macro_use] +extern crate board; + +use core::slice; + +fn check_integrity() -> bool { + extern { + static _begin: u8; + static _end: u8; + static _crc: u32; + } + + unsafe { + let length = &_end as *const u8 as usize - + &_begin as *const u8 as usize; + let bios = slice::from_raw_parts(&_begin as *const u8, length); + crc::crc32::checksum_ieee(bios) == _crc + } +} + +fn initialize_sdram() -> bool { + unsafe { + board::sdram_phy::initialize(); + + true + } +} + +#[no_mangle] +pub extern fn main() -> i32 { + println!(""); + println!(r" _ ____ _____ ___ ___ "); + println!(r" / \ | _ \_ _|_ _/ _ \ "); + println!(r" / _ \ | |_) || | | | | | |"); + println!(r" / ___ \| _ < | | | | |_| |"); + println!(r"/_/ \_\_| \_\|_| |___\__\_\"); + println!(""); + println!("ARTIQ Bootloader"); + println!("Copyright (c) 2017 M-Labs Limited"); + println!("Version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); + println!(""); + + if !check_integrity() { + panic!("Bootloader CRC failed"); + } else { + println!("Bootloader CRC passed"); + } + + if !initialize_sdram() { + panic!("SDRAM initialization failed") + } else { + println!("SDRAM initialized"); + } + + loop {} +} + +#[no_mangle] +pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { + panic!("exception {} at PC {:#08x}, EA {:#08x}", vect, pc, ea) +} + +#[no_mangle] +#[lang = "panic_fmt"] +pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! { + println!("panic at {}:{}: {}", file, line, args); + loop {} +} diff --git a/artiq/firmware/libdrtioaux/Cargo.toml b/artiq/firmware/libdrtioaux/Cargo.toml index 682d97316..def5c328b 100644 --- a/artiq/firmware/libdrtioaux/Cargo.toml +++ b/artiq/firmware/libdrtioaux/Cargo.toml @@ -8,6 +8,9 @@ build = "build.rs" name = "drtioaux" path = "lib.rs" +[build-dependencies] +build_misoc = { path = "../libbuild_misoc" } + [dependencies] log = { version = "0.3", default-features = false } std_artiq = { path = "../libstd_artiq", features = ["alloc"] } diff --git a/artiq/firmware/libdrtioaux/build.rs b/artiq/firmware/libdrtioaux/build.rs index a7b0335e5..3548ea5ff 100644 --- a/artiq/firmware/libdrtioaux/build.rs +++ b/artiq/firmware/libdrtioaux/build.rs @@ -1,15 +1,5 @@ -use std::env; -use std::path::Path; -use std::io::{BufRead, BufReader}; -use std::fs::File; +extern crate build_misoc; fn main() { - let out_dir = env::var("BUILDINC_DIRECTORY").unwrap(); - let cfg_path = Path::new(&out_dir).join("generated").join("rust-cfg"); - println!("cargo:rerun-if-changed={}", cfg_path.to_str().unwrap()); - - let f = BufReader::new(File::open(&cfg_path).unwrap()); - for line in f.lines() { - println!("cargo:rustc-cfg={}", line.unwrap()); - } + build_misoc::cfg(); } diff --git a/artiq/gateware/amp/soc.py b/artiq/gateware/amp/soc.py index d237822eb..16ab97396 100644 --- a/artiq/gateware/amp/soc.py +++ b/artiq/gateware/amp/soc.py @@ -48,6 +48,7 @@ def build_artiq_soc(soc, argdict): builder = Builder(soc, **argdict) builder.add_software_package("libm") builder.add_software_package("libunwind") + builder.add_software_package("bootloader", os.path.join(artiq_dir, "firmware", "bootloader")) builder.add_software_package("ksupport", os.path.join(artiq_dir, "firmware", "ksupport")) builder.add_software_package("runtime", os.path.join(artiq_dir, "firmware", "runtime")) try: From fcc438524c38d1ac336aa8d2b857e4c2338705f3 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 08:16:44 +0000 Subject: [PATCH 0118/2457] firmware: use main.rs as the root source for non-library crates. NFC. --- artiq/firmware/runtime/Cargo.toml | 2 +- artiq/firmware/runtime/{lib.rs => main.rs} | 0 artiq/firmware/satman/Cargo.toml | 2 +- artiq/firmware/satman/{lib.rs => main.rs} | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename artiq/firmware/runtime/{lib.rs => main.rs} (100%) rename artiq/firmware/satman/{lib.rs => main.rs} (100%) diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index e6c20ba4d..6753261cd 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -7,7 +7,7 @@ build = "build.rs" [lib] name = "runtime" crate-type = ["staticlib"] -path = "lib.rs" +path = "main.rs" [build-dependencies] build_artiq = { path = "../libbuild_artiq" } diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/main.rs similarity index 100% rename from artiq/firmware/runtime/lib.rs rename to artiq/firmware/runtime/main.rs diff --git a/artiq/firmware/satman/Cargo.toml b/artiq/firmware/satman/Cargo.toml index f3aa3cc4a..be6abc55f 100644 --- a/artiq/firmware/satman/Cargo.toml +++ b/artiq/firmware/satman/Cargo.toml @@ -7,7 +7,7 @@ build = "build.rs" [lib] name = "satman" crate-type = ["staticlib"] -path = "lib.rs" +path = "main.rs" [build-dependencies] build_artiq = { path = "../libbuild_artiq" } diff --git a/artiq/firmware/satman/lib.rs b/artiq/firmware/satman/main.rs similarity index 100% rename from artiq/firmware/satman/lib.rs rename to artiq/firmware/satman/main.rs From d94db1de5dbf8b183c57ef3cdb93daf7b1b8a57d Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 08:23:34 +0000 Subject: [PATCH 0119/2457] Revert accidentally committed parts of 1b9b5602. --- artiq/firmware/Cargo.lock | 31 ----------- artiq/firmware/Cargo.toml | 2 +- artiq/firmware/bootloader/Cargo.toml | 18 ------ artiq/firmware/bootloader/Makefile | 18 ------ artiq/firmware/bootloader/bootloader.ld | 46 ---------------- artiq/firmware/bootloader/build.rs | 6 -- artiq/firmware/bootloader/main.rs | 73 ------------------------- artiq/gateware/amp/soc.py | 1 - 8 files changed, 1 insertion(+), 194 deletions(-) delete mode 100644 artiq/firmware/bootloader/Cargo.toml delete mode 100644 artiq/firmware/bootloader/Makefile delete mode 100644 artiq/firmware/bootloader/bootloader.ld delete mode 100644 artiq/firmware/bootloader/build.rs delete mode 100644 artiq/firmware/bootloader/main.rs diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index dd4bf58f7..a60de7ea9 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -42,16 +42,6 @@ dependencies = [ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bootloader" -version = "0.0.0" -dependencies = [ - "board 0.0.0", - "build_artiq 0.0.0", - "crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)", - "rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "build_artiq" version = "0.0.0" @@ -59,11 +49,6 @@ dependencies = [ "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "build_const" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "build_misoc" version = "0.0.0" @@ -92,14 +77,6 @@ name = "compiler_builtins" version = "0.1.0" source = "git+https://github.com/m-labs/compiler-builtins?rev=97916b1#97916b17ca542eac0524b8570c7d05913891a0dc" -[[package]] -name = "crc" -version = "1.6.0" -source = "git+git://github.com/whitequark/crc-rs?rev=51cd356#51cd3560aa9d3823061f2bb46797d8c61f4cfa9e" -dependencies = [ - "build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cslice" version = "0.3.0" @@ -198,11 +175,6 @@ dependencies = [ "std_artiq 0.0.0", ] -[[package]] -name = "rlibc" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "runtime" version = "0.0.0" @@ -290,12 +262,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" -"checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" "checksum compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)" = "" "checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)" = "" -"checksum crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)" = "" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" "checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" @@ -304,7 +274,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" "checksum managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)" = "" -"checksum rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" "checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)" = "" diff --git a/artiq/firmware/Cargo.toml b/artiq/firmware/Cargo.toml index 0f2007873..af13ba5ff 100644 --- a/artiq/firmware/Cargo.toml +++ b/artiq/firmware/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["bootloader", "runtime", "ksupport", "satman"] +members = ["runtime", "ksupport", "satman"] diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml deleted file mode 100644 index cbf8ccef7..000000000 --- a/artiq/firmware/bootloader/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -authors = ["M-Labs"] -name = "bootloader" -version = "0.0.0" -build = "build.rs" - -[lib] -name = "bootloader" -crate-type = ["staticlib"] -path = "main.rs" - -[build-dependencies] -build_artiq = { path = "../libbuild_artiq" } - -[dependencies] -rlibc = "1.0" -crc = { git = "git://github.com/whitequark/crc-rs", rev = "51cd356", default-features = false } -board = { path = "../libboard", features = ["uart_console"] } diff --git a/artiq/firmware/bootloader/Makefile b/artiq/firmware/bootloader/Makefile deleted file mode 100644 index f247c0994..000000000 --- a/artiq/firmware/bootloader/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -include ../include/generated/variables.mak -include $(MISOC_DIRECTORY)/software/common.mak - -RUSTFLAGS += -Cpanic=abort - -all:: bootloader.bin - -.PHONY: $(RUSTOUT)/libbootloader.a -$(RUSTOUT)/libbootloader.a: - $(cargo) --manifest-path $(BOOTLOADER_DIRECTORY)/Cargo.toml -- \ - -Clto - -bootloader.elf: $(RUSTOUT)/libbootloader.a - $(link) -T $(BOOTLOADER_DIRECTORY)/bootloader.ld - -%.bin: %.elf - $(objcopy) -O binary - $(MSCIMG) $@ diff --git a/artiq/firmware/bootloader/bootloader.ld b/artiq/firmware/bootloader/bootloader.ld deleted file mode 100644 index 8fe809a49..000000000 --- a/artiq/firmware/bootloader/bootloader.ld +++ /dev/null @@ -1,46 +0,0 @@ -INCLUDE generated/output_format.ld -INCLUDE generated/regions.ld -ENTRY(_reset_handler) - -SECTIONS -{ - .vectors : - { - _begin = .; - *(.vectors) - } > rom - - .text : - { - *(.text .text.*) - } > rom - - .rodata : - { - *(.rodata.*) - . = ALIGN(4); - _end = .; - } > rom - - .crc ALIGN(4) : - { - _crc = .; - . += 4; - } - - .bss ALIGN(4) : - { - _fbss = .; - *(.bss .bss.*) - . = ALIGN(4); - _ebss = .; - } > sram - - .stack : - { - /* Ensure we have a certain amount of space available for stack. */ - . = ORIGIN(sram) + LENGTH(sram) - 0x800; - . = ORIGIN(sram) + LENGTH(sram) - 4; - _fstack = .; - } > sram -} diff --git a/artiq/firmware/bootloader/build.rs b/artiq/firmware/bootloader/build.rs deleted file mode 100644 index 0a7d63df9..000000000 --- a/artiq/firmware/bootloader/build.rs +++ /dev/null @@ -1,6 +0,0 @@ -extern crate build_artiq; - -fn main() { - build_artiq::misoc_cfg(); - build_artiq::git_describe(); -} diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs deleted file mode 100644 index ec9f54bbf..000000000 --- a/artiq/firmware/bootloader/main.rs +++ /dev/null @@ -1,73 +0,0 @@ -#![no_std] -#![feature(lang_items)] - -extern crate rlibc; -extern crate crc; -#[macro_use] -extern crate board; - -use core::slice; - -fn check_integrity() -> bool { - extern { - static _begin: u8; - static _end: u8; - static _crc: u32; - } - - unsafe { - let length = &_end as *const u8 as usize - - &_begin as *const u8 as usize; - let bios = slice::from_raw_parts(&_begin as *const u8, length); - crc::crc32::checksum_ieee(bios) == _crc - } -} - -fn initialize_sdram() -> bool { - unsafe { - board::sdram_phy::initialize(); - - true - } -} - -#[no_mangle] -pub extern fn main() -> i32 { - println!(""); - println!(r" _ ____ _____ ___ ___ "); - println!(r" / \ | _ \_ _|_ _/ _ \ "); - println!(r" / _ \ | |_) || | | | | | |"); - println!(r" / ___ \| _ < | | | | |_| |"); - println!(r"/_/ \_\_| \_\|_| |___\__\_\"); - println!(""); - println!("ARTIQ Bootloader"); - println!("Copyright (c) 2017 M-Labs Limited"); - println!("Version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); - println!(""); - - if !check_integrity() { - panic!("Bootloader CRC failed"); - } else { - println!("Bootloader CRC passed"); - } - - if !initialize_sdram() { - panic!("SDRAM initialization failed") - } else { - println!("SDRAM initialized"); - } - - loop {} -} - -#[no_mangle] -pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { - panic!("exception {} at PC {:#08x}, EA {:#08x}", vect, pc, ea) -} - -#[no_mangle] -#[lang = "panic_fmt"] -pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! { - println!("panic at {}:{}: {}", file, line, args); - loop {} -} diff --git a/artiq/gateware/amp/soc.py b/artiq/gateware/amp/soc.py index 16ab97396..d237822eb 100644 --- a/artiq/gateware/amp/soc.py +++ b/artiq/gateware/amp/soc.py @@ -48,7 +48,6 @@ def build_artiq_soc(soc, argdict): builder = Builder(soc, **argdict) builder.add_software_package("libm") builder.add_software_package("libunwind") - builder.add_software_package("bootloader", os.path.join(artiq_dir, "firmware", "bootloader")) builder.add_software_package("ksupport", os.path.join(artiq_dir, "firmware", "ksupport")) builder.add_software_package("runtime", os.path.join(artiq_dir, "firmware", "runtime")) try: From c0861497824a2fd458a5f8df0092ef1a06d72539 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Dec 2017 16:36:47 +0800 Subject: [PATCH 0120/2457] drtio/gth: use async microscope probes --- artiq/gateware/drtio/transceiver/gth_ultrascale.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index 211c2ac7b..9fc70a3b0 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -173,9 +173,9 @@ class GTHSingle(Module): ) self.submodules += [ - add_probe_single("drtio_gth", "cpll_lock", cpll_lock), - add_probe_single("drtio_gth", "txuserrdy", tx_init.Xxuserrdy), - add_probe_single("drtio_gth", "rxuserrdy", rx_init.Xxuserrdy, clock_domain="rtio_tx"), + add_probe_async("drtio_gth", "cpll_lock", cpll_lock), + add_probe_async("drtio_gth", "txuserrdy", tx_init.Xxuserrdy), + add_probe_async("drtio_gth", "rxuserrdy", rx_init.Xxuserrdy), add_probe_buffer("drtio_gth", "txdata", txdata, clock_domain="rtio_tx"), add_probe_buffer("drtio_gth", "rxdata", rxdata, clock_domain="rtio_rx") ] @@ -215,8 +215,7 @@ class GTHSingle(Module): rx_init.restart.eq(clock_aligner.restart), self.rx_ready.eq(clock_aligner.ready) ] - self.submodules += add_probe_single("drtio_gth", "clock_aligner_ready", clock_aligner.ready, - clock_domain="rtio_tx") + self.submodules += add_probe_async("drtio_gth", "clock_aligner_ready", clock_aligner.ready) class GTH(Module, TransceiverInterface): From 8153cfa88fccabbd3ed00e45398c9bebea86fab3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Dec 2017 16:49:08 +0800 Subject: [PATCH 0121/2457] drtio/gth: add probes on {tx,rx}_init.done --- artiq/gateware/drtio/transceiver/gth_ultrascale.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index 9fc70a3b0..7febc7a1d 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -175,7 +175,9 @@ class GTHSingle(Module): self.submodules += [ add_probe_async("drtio_gth", "cpll_lock", cpll_lock), add_probe_async("drtio_gth", "txuserrdy", tx_init.Xxuserrdy), + add_probe_async("drtio_gth", "tx_init_done", tx_init.done), add_probe_async("drtio_gth", "rxuserrdy", rx_init.Xxuserrdy), + add_probe_async("drtio_gth", "rx_init_done", rx_init.done), add_probe_buffer("drtio_gth", "txdata", txdata, clock_domain="rtio_tx"), add_probe_buffer("drtio_gth", "rxdata", rxdata, clock_domain="rtio_rx") ] From b9754e710871552b1144a6c59e137b63f73eebfa Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 12:57:40 +0000 Subject: [PATCH 0122/2457] firmware: deduplicate libbuild_misoc and libbuild_artiq. --- artiq/firmware/Cargo.lock | 3 ++- artiq/firmware/ksupport/Cargo.toml | 2 +- artiq/firmware/ksupport/build.rs | 4 ++-- artiq/firmware/libboard_artiq/build.rs | 7 +++---- artiq/firmware/libbuild_artiq/lib.rs | 19 ++++--------------- artiq/firmware/runtime/Cargo.toml | 1 + artiq/firmware/runtime/build.rs | 3 ++- artiq/firmware/satman/Cargo.toml | 1 + artiq/firmware/satman/build.rs | 3 ++- 9 files changed, 18 insertions(+), 25 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index a60de7ea9..794b0e2d3 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -126,7 +126,7 @@ dependencies = [ "alloc_stub 0.0.0", "amp 0.0.0", "board 0.0.0", - "build_artiq 0.0.0", + "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -185,6 +185,7 @@ dependencies = [ "board 0.0.0", "board_artiq 0.0.0", "build_artiq 0.0.0", + "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/artiq/firmware/ksupport/Cargo.toml b/artiq/firmware/ksupport/Cargo.toml index 1162a848c..b295c160c 100644 --- a/artiq/firmware/ksupport/Cargo.toml +++ b/artiq/firmware/ksupport/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" crate-type = ["staticlib"] [build-dependencies] -build_artiq = { path = "../libbuild_artiq" } +build_misoc = { path = "../libbuild_misoc" } [dependencies] byteorder = { version = "1.0", default-features = false } diff --git a/artiq/firmware/ksupport/build.rs b/artiq/firmware/ksupport/build.rs index 6f802af66..ab6acff39 100644 --- a/artiq/firmware/ksupport/build.rs +++ b/artiq/firmware/ksupport/build.rs @@ -1,6 +1,6 @@ -extern crate build_artiq; +extern crate build_misoc; fn main() { - build_artiq::misoc_cfg(); + build_misoc::cfg(); println!("cargo:rustc-cfg={}", "ksupport"); } diff --git a/artiq/firmware/libboard_artiq/build.rs b/artiq/firmware/libboard_artiq/build.rs index 225cf707a..508c9f935 100644 --- a/artiq/firmware/libboard_artiq/build.rs +++ b/artiq/firmware/libboard_artiq/build.rs @@ -1,10 +1,9 @@ extern crate build_misoc; -extern crate build_artiq; use std::env; use std::fs::File; use std::io::Write; -use std::path::PathBuf; +use std::path::Path; use std::process::Command; fn gen_hmc7043_writes() { @@ -19,8 +18,8 @@ fn gen_hmc7043_writes() { .ok() .and_then(|o| String::from_utf8(o.stdout).ok()) .unwrap(); - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let mut f = File::create(out_dir.join("hmc7043_writes.rs")).unwrap(); + let out_dir = env::var("OUT_DIR").unwrap(); + let mut f = File::create(Path::new(&out_dir).join("hmc7043_writes.rs")).unwrap(); write!(f, "{}", hmc7043_writes).unwrap(); } diff --git a/artiq/firmware/libbuild_artiq/lib.rs b/artiq/firmware/libbuild_artiq/lib.rs index 2eb27a040..cd35a30a8 100644 --- a/artiq/firmware/libbuild_artiq/lib.rs +++ b/artiq/firmware/libbuild_artiq/lib.rs @@ -2,8 +2,8 @@ extern crate walkdir; use std::env; use std::fs::File; -use std::io::{Write, BufRead, BufReader}; -use std::path::{Path, PathBuf}; +use std::io::Write; +use std::path::Path; use std::process::Command; use walkdir::WalkDir; @@ -42,18 +42,7 @@ pub fn git_describe() { version = "unknown".to_owned(); } - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); - let mut f = File::create(out_dir.join("git-describe")).unwrap(); + let out_dir = env::var("OUT_DIR").unwrap(); + let mut f = File::create(Path::new(&out_dir).join("git-describe")).unwrap(); write!(f, "{}", version).unwrap(); } - -pub fn misoc_cfg() { - let out_dir = env::var("BUILDINC_DIRECTORY").unwrap(); - let cfg_path = Path::new(&out_dir).join("generated").join("rust-cfg"); - println!("cargo:rerun-if-changed={}", cfg_path.to_str().unwrap()); - - let f = BufReader::new(File::open(&cfg_path).unwrap()); - for line in f.lines() { - println!("cargo:rustc-cfg={}", line.unwrap()); - } -} diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 6753261cd..5802b84b2 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["staticlib"] path = "main.rs" [build-dependencies] +build_misoc = { path = "../libbuild_misoc" } build_artiq = { path = "../libbuild_artiq" } [dependencies] diff --git a/artiq/firmware/runtime/build.rs b/artiq/firmware/runtime/build.rs index d9df648a6..64a84fcb8 100644 --- a/artiq/firmware/runtime/build.rs +++ b/artiq/firmware/runtime/build.rs @@ -1,6 +1,7 @@ +extern crate build_misoc; extern crate build_artiq; fn main() { + build_misoc::cfg(); build_artiq::git_describe(); - build_artiq::misoc_cfg(); } diff --git a/artiq/firmware/satman/Cargo.toml b/artiq/firmware/satman/Cargo.toml index be6abc55f..7cab6d4c1 100644 --- a/artiq/firmware/satman/Cargo.toml +++ b/artiq/firmware/satman/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["staticlib"] path = "main.rs" [build-dependencies] +build_misoc = { path = "../libbuild_misoc" } build_artiq = { path = "../libbuild_artiq" } [dependencies] diff --git a/artiq/firmware/satman/build.rs b/artiq/firmware/satman/build.rs index d9df648a6..64a84fcb8 100644 --- a/artiq/firmware/satman/build.rs +++ b/artiq/firmware/satman/build.rs @@ -1,6 +1,7 @@ +extern crate build_misoc; extern crate build_artiq; fn main() { + build_misoc::cfg(); build_artiq::git_describe(); - build_artiq::misoc_cfg(); } From acd13837ffdc72626be7b32310839e2d07aafd6e Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 13:17:49 +0000 Subject: [PATCH 0123/2457] firmware: implement the new bootloader. --- artiq/firmware/Cargo.lock | 33 +++ artiq/firmware/Cargo.toml | 2 +- artiq/firmware/bootloader/Cargo.toml | 19 ++ artiq/firmware/bootloader/Makefile | 18 ++ artiq/firmware/bootloader/bootloader.ld | 46 +++ artiq/firmware/bootloader/build.rs | 5 + artiq/firmware/bootloader/main.rs | 171 +++++++++++ artiq/firmware/libboard/lib.rs | 1 + .../{libboard_artiq => libboard/or1k}/boot.rs | 32 ++- artiq/firmware/libboard/or1k/mod.rs | 1 + artiq/firmware/libboard/sdram.rs | 271 ++++++++++++++++++ artiq/firmware/libboard_artiq/lib.rs | 2 - artiq/firmware/runtime/main.rs | 8 +- artiq/firmware/runtime/mgmt.rs | 6 +- artiq/frontend/artiq_flash.py | 4 +- artiq/gateware/amp/soc.py | 8 +- conda/artiq-kc705-nist_clock/build.sh | 2 +- conda/artiq-kc705-nist_qc2/build.sh | 2 +- conda/artiq-sayma_amc-standalone/build.sh | 2 +- 19 files changed, 604 insertions(+), 29 deletions(-) create mode 100644 artiq/firmware/bootloader/Cargo.toml create mode 100644 artiq/firmware/bootloader/Makefile create mode 100644 artiq/firmware/bootloader/bootloader.ld create mode 100644 artiq/firmware/bootloader/build.rs create mode 100644 artiq/firmware/bootloader/main.rs rename artiq/firmware/{libboard_artiq => libboard/or1k}/boot.rs (59%) create mode 100644 artiq/firmware/libboard/sdram.rs diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 794b0e2d3..a3a9dfd79 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -42,6 +42,17 @@ dependencies = [ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bootloader" +version = "0.0.0" +dependencies = [ + "board 0.0.0", + "build_misoc 0.0.0", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)", + "rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "build_artiq" version = "0.0.0" @@ -49,6 +60,11 @@ dependencies = [ "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "build_const" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "build_misoc" version = "0.0.0" @@ -77,6 +93,14 @@ name = "compiler_builtins" version = "0.1.0" source = "git+https://github.com/m-labs/compiler-builtins?rev=97916b1#97916b17ca542eac0524b8570c7d05913891a0dc" +[[package]] +name = "crc" +version = "1.6.0" +source = "git+git://github.com/whitequark/crc-rs?rev=51cd356#51cd3560aa9d3823061f2bb46797d8c61f4cfa9e" +dependencies = [ + "build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cslice" version = "0.3.0" @@ -175,6 +199,11 @@ dependencies = [ "std_artiq 0.0.0", ] +[[package]] +name = "rlibc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "runtime" version = "0.0.0" @@ -220,6 +249,7 @@ dependencies = [ "board 0.0.0", "board_artiq 0.0.0", "build_artiq 0.0.0", + "build_misoc 0.0.0", "compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)", "drtioaux 0.0.0", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -263,10 +293,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" +"checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" "checksum compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)" = "" "checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)" = "" +"checksum crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)" = "" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" "checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" @@ -275,6 +307,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" "checksum managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)" = "" +"checksum rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" "checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)" = "" diff --git a/artiq/firmware/Cargo.toml b/artiq/firmware/Cargo.toml index af13ba5ff..0f2007873 100644 --- a/artiq/firmware/Cargo.toml +++ b/artiq/firmware/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["runtime", "ksupport", "satman"] +members = ["bootloader", "runtime", "ksupport", "satman"] diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml new file mode 100644 index 000000000..26521a87e --- /dev/null +++ b/artiq/firmware/bootloader/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["M-Labs"] +name = "bootloader" +version = "0.0.0" +build = "build.rs" + +[lib] +name = "bootloader" +crate-type = ["staticlib"] +path = "main.rs" + +[build-dependencies] +build_misoc = { path = "../libbuild_misoc" } + +[dependencies] +rlibc = "1.0" +byteorder = { version = "1.0", default-features = false } +crc = { git = "git://github.com/whitequark/crc-rs", rev = "51cd356", default-features = false } +board = { path = "../libboard", features = ["uart_console"] } diff --git a/artiq/firmware/bootloader/Makefile b/artiq/firmware/bootloader/Makefile new file mode 100644 index 000000000..f247c0994 --- /dev/null +++ b/artiq/firmware/bootloader/Makefile @@ -0,0 +1,18 @@ +include ../include/generated/variables.mak +include $(MISOC_DIRECTORY)/software/common.mak + +RUSTFLAGS += -Cpanic=abort + +all:: bootloader.bin + +.PHONY: $(RUSTOUT)/libbootloader.a +$(RUSTOUT)/libbootloader.a: + $(cargo) --manifest-path $(BOOTLOADER_DIRECTORY)/Cargo.toml -- \ + -Clto + +bootloader.elf: $(RUSTOUT)/libbootloader.a + $(link) -T $(BOOTLOADER_DIRECTORY)/bootloader.ld + +%.bin: %.elf + $(objcopy) -O binary + $(MSCIMG) $@ diff --git a/artiq/firmware/bootloader/bootloader.ld b/artiq/firmware/bootloader/bootloader.ld new file mode 100644 index 000000000..8fe809a49 --- /dev/null +++ b/artiq/firmware/bootloader/bootloader.ld @@ -0,0 +1,46 @@ +INCLUDE generated/output_format.ld +INCLUDE generated/regions.ld +ENTRY(_reset_handler) + +SECTIONS +{ + .vectors : + { + _begin = .; + *(.vectors) + } > rom + + .text : + { + *(.text .text.*) + } > rom + + .rodata : + { + *(.rodata.*) + . = ALIGN(4); + _end = .; + } > rom + + .crc ALIGN(4) : + { + _crc = .; + . += 4; + } + + .bss ALIGN(4) : + { + _fbss = .; + *(.bss .bss.*) + . = ALIGN(4); + _ebss = .; + } > sram + + .stack : + { + /* Ensure we have a certain amount of space available for stack. */ + . = ORIGIN(sram) + LENGTH(sram) - 0x800; + . = ORIGIN(sram) + LENGTH(sram) - 4; + _fstack = .; + } > sram +} diff --git a/artiq/firmware/bootloader/build.rs b/artiq/firmware/bootloader/build.rs new file mode 100644 index 000000000..3548ea5ff --- /dev/null +++ b/artiq/firmware/bootloader/build.rs @@ -0,0 +1,5 @@ +extern crate build_misoc; + +fn main() { + build_misoc::cfg(); +} diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs new file mode 100644 index 000000000..61ae7a48d --- /dev/null +++ b/artiq/firmware/bootloader/main.rs @@ -0,0 +1,171 @@ +#![no_std] +#![feature(lang_items)] + +extern crate rlibc; +extern crate crc; +extern crate byteorder; +#[macro_use] +extern crate board; + +use core::{ptr, slice}; +use crc::crc32; +use byteorder::{ByteOrder, BigEndian}; +use board::{boot, cache}; +use board::uart_console::Console; + +fn check_integrity() -> bool { + extern { + static _begin: u8; + static _end: u8; + static _crc: u32; + } + + unsafe { + let length = &_end as *const u8 as usize - + &_begin as *const u8 as usize; + let bootloader = slice::from_raw_parts(&_begin as *const u8, length); + crc32::checksum_ieee(bootloader) == _crc + } +} + +unsafe fn memory_test(total: &mut usize, wrong: &mut usize) -> bool { + const MEMORY: *mut u32 = board::mem::MAIN_RAM_BASE as *mut u32; + + *total = 0; + *wrong = 0; + + macro_rules! test { + ( + $prepare:stmt; + for $i:ident in ($range:expr) { + MEMORY[$index:expr] = $data:expr + } + ) => ({ + $prepare; + for $i in $range { + ptr::write_volatile(MEMORY.offset($index as isize), $data); + *total += 1; + } + + cache::flush_cpu_dcache(); + cache::flush_l2_cache(); + + $prepare; + for $i in $range { + if ptr::read_volatile(MEMORY.offset($index as isize)) != $data { + *wrong += 1; + } + } + }) + } + + fn prng32(seed: &mut u32) -> u32 { *seed = 1664525 * *seed + 1013904223; *seed } + fn prng16(seed: &mut u16) -> u16 { *seed = 25173 * *seed + 13849; *seed } + + // Test data bus + test!((); for i in (0..0x100) { MEMORY[i] = 0xAAAAAAAA }); + test!((); for i in (0..0x100) { MEMORY[i] = 0x55555555 }); + + // Test counter addressing with random data + test!(let mut seed = 0; + for i in (0..0x100000) { MEMORY[i] = prng32(&mut seed) }); + + // Test random addressing with counter data + test!(let mut seed = 0; + for i in (0..0x10000) { MEMORY[prng16(&mut seed)] = i }); + + *wrong == 0 +} + +fn startup() -> bool { + if check_integrity() { + println!("Bootloader CRC passed"); + } else { + println!("Bootloader CRC failed"); + return false + } + + println!("Initializing SDRAM..."); + + if unsafe { board::sdram::init(Some(&mut Console)) } { + println!("SDRAM initialized"); + } else { + println!("SDRAM initialization failed"); + return false + } + + let (mut total, mut wrong) = (0, 0); + if unsafe { memory_test(&mut total, &mut wrong) } { + println!("Memory test passed"); + } else { + println!("Memory test failed ({}/{} words incorrect)", wrong, total); + return false + } + + true +} + +unsafe fn flash_boot() { + const FIRMWARE: *mut u8 = board::mem::FLASH_BOOT_ADDRESS as *mut u8; + const MAIN_RAM: *mut u8 = board::mem::MAIN_RAM_BASE as *mut u8; + + println!("Booting from flash..."); + + let header = slice::from_raw_parts(FIRMWARE, 8); + let length = BigEndian::read_u32(&header[0..]) as usize; + let expected_crc = BigEndian::read_u32(&header[4..]); + + if length == 0xffffffff { + println!("No firmware present"); + return + } + + let firmware_in_flash = slice::from_raw_parts(FIRMWARE.offset(8), length); + let actual_crc = crc32::checksum_ieee(firmware_in_flash); + + if actual_crc == expected_crc { + let firmware_in_sdram = slice::from_raw_parts_mut(MAIN_RAM, length); + firmware_in_sdram.copy_from_slice(firmware_in_flash); + + println!("Starting firmware."); + boot::jump(MAIN_RAM as usize); + } else { + println!("Firmware CRC failed (actual {:08x}, expected {:08x}", + actual_crc, expected_crc); + } +} + +#[no_mangle] +pub extern fn main() -> i32 { + println!(""); + println!(r" __ __ _ ____ ____ "); + println!(r"| \/ (_) ___| ___ / ___|"); + println!(r"| |\/| | \___ \ / _ \| | "); + println!(r"| | | | |___) | (_) | |___ "); + println!(r"|_| |_|_|____/ \___/ \____|"); + println!(""); + println!("MiSoC Bootloader"); + println!("Copyright (c) 2017 M-Labs Limited"); + println!(""); + + if startup() { + println!(""); + unsafe { flash_boot() }; + } else { + println!("Halting."); + } + + loop {} +} + +#[no_mangle] +pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { + panic!("exception {} at PC {:#08x}, EA {:#08x}", vect, pc, ea) +} + +#[no_mangle] +#[lang = "panic_fmt"] +pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! { + println!("panic at {}:{}: {}", file, line, args); + loop {} +} diff --git a/artiq/firmware/libboard/lib.rs b/artiq/firmware/libboard/lib.rs index 9eb6bd31e..27de0b9e1 100644 --- a/artiq/firmware/libboard/lib.rs +++ b/artiq/firmware/libboard/lib.rs @@ -12,6 +12,7 @@ pub use arch::*; include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/mem.rs")); include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/csr.rs")); include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/sdram_phy.rs")); +pub mod sdram; pub mod ident; pub mod clock; pub mod uart; diff --git a/artiq/firmware/libboard_artiq/boot.rs b/artiq/firmware/libboard/or1k/boot.rs similarity index 59% rename from artiq/firmware/libboard_artiq/boot.rs rename to artiq/firmware/libboard/or1k/boot.rs index 803a094a6..51a368e6e 100644 --- a/artiq/firmware/libboard_artiq/boot.rs +++ b/artiq/firmware/libboard/or1k/boot.rs @@ -1,18 +1,26 @@ -use board::irq; +use super::{irq, cache}; -pub unsafe fn reboot() -> ! { +pub unsafe fn reset() -> ! { irq::set_ie(false); - #[cfg(target_arch="or1k")] asm!(r#" - l.j _reset_handler - l.nop + l.j _reset_handler + l.nop "# : : : : "volatile"); loop {} } -pub unsafe fn hotswap(new_code: &[u8]) -> ! { +pub unsafe fn jump(addr: usize) -> ! { + irq::set_ie(false); + cache::flush_cpu_icache(); + asm!(r#" + l.jr $0 + l.nop + "# : : "r"(addr) : : "volatile"); + loop {} +} + +pub unsafe fn hotswap(firmware: &[u8]) -> ! { irq::set_ie(false); - #[cfg(target_arch="or1k")] asm!(r#" # This loop overwrites itself, but it's structured in such a way # that before that happens, it loads itself into I$$ fully. @@ -21,20 +29,20 @@ pub unsafe fn hotswap(new_code: &[u8]) -> ! { l.or r7, r4, r0 0: l.sfnei r5, 0 l.bf 1f - l.nop + l.nop l.jr r7 - l.nop + l.nop 1: l.lwz r6, 0(r3) l.sw 0(r4), r6 l.addi r3, r3, 4 l.addi r4, r4, 4 l.addi r5, r5, -4 l.bf 0b - l.nop + l.nop "# : - : "{r3}"(new_code.as_ptr() as usize), - "{r5}"(new_code.len()) + : "{r3}"(firmware.as_ptr() as usize), + "{r5}"(firmware.len()) : : "volatile"); loop {} diff --git a/artiq/firmware/libboard/or1k/mod.rs b/artiq/firmware/libboard/or1k/mod.rs index 01589ddc8..52a619d1b 100644 --- a/artiq/firmware/libboard/or1k/mod.rs +++ b/artiq/firmware/libboard/or1k/mod.rs @@ -1,3 +1,4 @@ pub mod spr; pub mod irq; pub mod cache; +pub mod boot; diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs new file mode 100644 index 000000000..fbedacff2 --- /dev/null +++ b/artiq/firmware/libboard/sdram.rs @@ -0,0 +1,271 @@ +#[cfg(has_ddrphy)] +mod ddr { + use core::{ptr, fmt}; + use core::cell::Cell; + use csr::{dfii, ddrphy}; + use sdram_phy::{self, spin_cycles}; + use sdram_phy::{DFII_COMMAND_CS, DFII_COMMAND_WE, DFII_COMMAND_CAS, DFII_COMMAND_RAS, + DFII_COMMAND_WRDATA, DFII_COMMAND_RDDATA}; + use sdram_phy::{DFII_NPHASES, DFII_PIX_DATA_SIZE, DFII_PIX_WRDATA_ADDR, DFII_PIX_RDDATA_ADDR}; + + unsafe fn enable_write_leveling(enabled: bool) { + dfii::pi0_address_write(sdram_phy::DDR3_MR1 as u16 | ((enabled as u16) << 7)); + dfii::pi0_baddress_write(1); + sdram_phy::command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); + ddrphy::wlevel_en_write(enabled as u8); + } + + #[cfg(kusddrphy)] + const DDRPHY_MAX_DELAY: u16 = 512; + #[cfg(not(kusddrphy))] + const DDRPHY_MAX_DELAY: u16 = 32; + + const DQS_SIGNAL_COUNT: usize = DFII_PIX_DATA_SIZE / 2; + + macro_rules! log { + ($logger:expr, $( $arg:expr ),+) => ( + if let &mut Some(ref mut f) = $logger { + let _ = write!(f, $( $arg ),+); + } + ) + } + + unsafe fn write_level(logger: &mut Option<&mut fmt::Write>, + delay: &mut [u16; DQS_SIGNAL_COUNT], + high_skew: &mut [bool; DQS_SIGNAL_COUNT]) -> bool { + log!(logger, "Write leveling: "); + + enable_write_leveling(true); + spin_cycles(100); + + let mut failed = false; + for n in 0..DQS_SIGNAL_COUNT { + let dq_addr = dfii::PI0_RDDATA_ADDR + .offset((DQS_SIGNAL_COUNT - 1 - n) as isize); + + delay[n] = 0; + high_skew[n] = false; + + ddrphy::dly_sel_write(1 << n); + + ddrphy::wdly_dq_rst_write(1); + ddrphy::wdly_dqs_rst_write(1); + ddrphy::wlevel_strobe_write(1); + spin_cycles(10); + + let mut incr_delay = || { + delay[n] += 1; + if delay[n] >= DDRPHY_MAX_DELAY { + failed = true; + return false + } + + ddrphy::wdly_dq_inc_write(1); + ddrphy::wdly_dqs_inc_write(1); + ddrphy::wlevel_strobe_write(1); + spin_cycles(10); + + true + }; + + let mut dq = ptr::read_volatile(dq_addr); + + if dq != 0 { + // Assume this DQ group has between 1 and 2 bit times of skew. + // Bring DQS into the CK=0 zone before continuing leveling. + high_skew[n] = true; + + while dq != 0 { + if !incr_delay() { break } + dq = ptr::read_volatile(dq_addr); + } + } + + while dq == 0 { + if !incr_delay() { break } + dq = ptr::read_volatile(dq_addr); + } + } + + enable_write_leveling(false); + + for n in (0..DQS_SIGNAL_COUNT).rev() { + log!(logger, "{}{} ", delay[n], if high_skew[n] { "*" } else { "" }); + } + + if !failed { + log!(logger, "done\n") + } else { + log!(logger, "failed\n") + } + + !failed + } + + unsafe fn read_bitslip(logger: &mut Option<&mut fmt::Write>, + delay: &[u16; DQS_SIGNAL_COUNT], + high_skew: &[bool; DQS_SIGNAL_COUNT]) { + let threshold_opt = delay.iter().zip(high_skew.iter()) + .filter_map(|(&delay, &high_skew)| + if high_skew { Some(delay) } else { None }) + .min() + .map(|threshold| threshold / 2); + + if let Some(threshold) = threshold_opt { + log!(logger, "Read bitslip: "); + + for n in (0..DQS_SIGNAL_COUNT).rev() { + if delay[n] > threshold { + ddrphy::dly_sel_write(1 << n); + + #[cfg(kusddrphy)] + ddrphy::rdly_dq_bitslip_write(1); + #[cfg(not(kusddrphy))] + for _ in 0..3 { + ddrphy::rdly_dq_bitslip_write(1); + } + + log!(logger, "{} ", n); + } + } + + log!(logger, "\n"); + } + } + + unsafe fn read_delays(logger: &mut Option<&mut fmt::Write>) { + log!(logger, "Read delays: "); + + // Generate pseudo-random sequence + let mut prs = [0; DFII_NPHASES * DFII_PIX_DATA_SIZE]; + let mut prv = 42; + for b in prs.iter_mut() { + prv = 1664525 * prv + 1013904223; + *b = prv as u8; + } + + // Activate + dfii::pi0_address_write(0); + dfii::pi0_baddress_write(0); + sdram_phy::command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CS); + spin_cycles(15); + + // Write test pattern + for p in 0..DFII_NPHASES { + for offset in 0..DFII_PIX_DATA_SIZE { + let addr = DFII_PIX_WRDATA_ADDR[p].offset(offset as isize); + let data = prs[DFII_PIX_DATA_SIZE * p + offset]; + ptr::write_volatile(addr, data as u32); + } + } + sdram_phy::dfii_piwr_address_write(0); + sdram_phy::dfii_piwr_baddress_write(0); + sdram_phy::command_pwr(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS| + DFII_COMMAND_WRDATA); + + // Calibrate each DQ in turn + sdram_phy::dfii_pird_address_write(0); + sdram_phy::dfii_pird_baddress_write(0); + for n in 0..DQS_SIGNAL_COUNT { + ddrphy::dly_sel_write(1 << (DQS_SIGNAL_COUNT - n - 1)); + + ddrphy::rdly_dq_rst_write(1); + + let delay = Cell::new(0); + let incr_delay_until = |expected| { + while delay.get() < DDRPHY_MAX_DELAY { + sdram_phy::command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS| + DFII_COMMAND_RDDATA); + spin_cycles(15); + + let mut working = true; + for p in 0..DFII_NPHASES { + for &offset in [n, n + DQS_SIGNAL_COUNT].iter() { + let addr = DFII_PIX_RDDATA_ADDR[p].offset(offset as isize); + let data = prs[DFII_PIX_DATA_SIZE * p + offset]; + if ptr::read_volatile(addr) as u8 != data { + working = false; + } + } + } + + if working == expected { + break + } + + delay.set(delay.get() + 1); + ddrphy::rdly_dq_inc_write(1); + } + }; + + // Find smallest working delay + incr_delay_until(true); + let min_delay = delay.get(); + + // Get a bit further into the working zone + #[cfg(kusddrphy)] + for _ in 0..8 { + delay.set(delay.get() + 1); + ddrphy::rdly_dq_inc_write(1); + } + #[cfg(not(kusddrphy))] + { + delay.set(delay.get() + 1); + ddrphy::rdly_dq_inc_write(1); + } + + // Find largest working delay + incr_delay_until(false); + let max_delay = delay.get(); + + log!(logger, "{}:{:02}-{:02} ", DQS_SIGNAL_COUNT - n - 1, + min_delay, max_delay); + + // Set delay to the middle + ddrphy::rdly_dq_rst_write(1); + for _ in 0..(min_delay + max_delay) / 2 { + ddrphy::rdly_dq_inc_write(1); + } + } + + // Precharge + dfii::pi0_address_write(0); + dfii::pi0_baddress_write(0); + sdram_phy::command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS); + spin_cycles(15); + + log!(logger, "done\n"); + } + + pub unsafe fn level(logger: &mut Option<&mut fmt::Write>) -> bool { + let mut delay = [0; DQS_SIGNAL_COUNT]; + let mut high_skew = [false; DQS_SIGNAL_COUNT]; + + if !write_level(logger, &mut delay, &mut high_skew) { + return false + } + read_bitslip(logger, &delay, &high_skew); + read_delays(logger); + + true + } +} + +use core::fmt; +use csr; +use sdram_phy; + +pub unsafe fn init(mut _logger: Option<&mut fmt::Write>) -> bool { + sdram_phy::initialize(); + + #[cfg(has_ddrphy)] + { + if !ddr::level(&mut _logger) { + return false + } + } + + csr::dfii::control_write(sdram_phy::DFII_CONTROL_SEL); + + true +} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index c40f899c3..3307681b3 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -23,5 +23,3 @@ pub mod hmc830_7043; mod ad9154_reg; #[cfg(has_ad9154)] pub mod ad9154; - -pub mod boot; diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 0cb4e6a58..d5e9462f5 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -244,12 +244,12 @@ pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u3 println!("{:#08x}", ip); }); - if config::read_str("panic_reboot", |r| r == Ok("1")) { - println!("rebooting..."); - unsafe { board_artiq::boot::reboot() } + if config::read_str("panic_reset", |r| r == Ok("1")) { + println!("restarting..."); + unsafe { board::boot::reset() } } else { println!("halting."); - println!("use `artiq_coreconfig write -s panic_reboot 1` to reboot instead"); + println!("use `artiq_coreconfig write -s panic_reset 1` to restart instead"); loop {} } } diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 23898f0f3..2933102f5 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -1,4 +1,4 @@ -use board_artiq::boot; +use board::boot; use std::io::{self, Read, Write}; use log::LogLevelFilter; use logger_artiq::BufferLogger; @@ -92,8 +92,8 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> { Request::Reboot => { Reply::RebootImminent.write_to(stream)?; stream.close()?; - warn!("rebooting"); - unsafe { boot::reboot() } + warn!("restarting"); + unsafe { boot::reset() } } }; } diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 112340428..72d5fd11e 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -259,8 +259,8 @@ def main(): if opts.srcbuild is None: path = bin_dir else: - path = os.path.join(opts.srcbuild, "software", "bios") - programmer.flash_binary(*config["bootloader"], os.path.join(path, "bios.bin")) + path = os.path.join(opts.srcbuild, "software", "bootloader") + programmer.flash_binary(*config["bootloader"], os.path.join(path, "bootloader.bin")) elif action == "storage": programmer.flash_binary(*config["storage"], opts.storage) elif action == "runtime": diff --git a/artiq/gateware/amp/soc.py b/artiq/gateware/amp/soc.py index d237822eb..1761fb72c 100644 --- a/artiq/gateware/amp/soc.py +++ b/artiq/gateware/amp/soc.py @@ -45,11 +45,15 @@ class AMPSoC: def build_artiq_soc(soc, argdict): + firmware_dir = os.path.join(artiq_dir, "firmware") builder = Builder(soc, **argdict) + builder.software_packages = [] builder.add_software_package("libm") + builder.add_software_package("libprintf") builder.add_software_package("libunwind") - builder.add_software_package("ksupport", os.path.join(artiq_dir, "firmware", "ksupport")) - builder.add_software_package("runtime", os.path.join(artiq_dir, "firmware", "runtime")) + builder.add_software_package("bootloader", os.path.join(firmware_dir, "bootloader")) + builder.add_software_package("ksupport", os.path.join(firmware_dir, "ksupport")) + builder.add_software_package("runtime", os.path.join(firmware_dir, "runtime")) try: builder.build() except subprocess.CalledProcessError as e: diff --git a/conda/artiq-kc705-nist_clock/build.sh b/conda/artiq-kc705-nist_clock/build.sh index 880719a42..e81da80f7 100644 --- a/conda/artiq-kc705-nist_clock/build.sh +++ b/conda/artiq-kc705-nist_clock/build.sh @@ -5,5 +5,5 @@ mkdir -p $SOC_PREFIX V=1 $PYTHON -m artiq.gateware.targets.kc705_dds -H nist_clock cp misoc_nist_clock_kc705/gateware/top.bit $SOC_PREFIX -cp misoc_nist_clock_kc705/software/bios/bios.bin $SOC_PREFIX +cp misoc_nist_clock_kc705/software/bootloader/bootloader.bin $SOC_PREFIX cp misoc_nist_clock_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-kc705-nist_qc2/build.sh b/conda/artiq-kc705-nist_qc2/build.sh index 403045dfa..a36df210d 100644 --- a/conda/artiq-kc705-nist_qc2/build.sh +++ b/conda/artiq-kc705-nist_qc2/build.sh @@ -5,5 +5,5 @@ mkdir -p $SOC_PREFIX V=1 $PYTHON -m artiq.gateware.targets.kc705_dds -H nist_qc2 cp misoc_nist_qc2_kc705/gateware/top.bit $SOC_PREFIX -cp misoc_nist_qc2_kc705/software/bios/bios.bin $SOC_PREFIX +cp misoc_nist_qc2_kc705/software/bootloader/bootloader.bin $SOC_PREFIX cp misoc_nist_qc2_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-sayma_amc-standalone/build.sh b/conda/artiq-sayma_amc-standalone/build.sh index f256da963..512e14ad0 100644 --- a/conda/artiq-sayma_amc-standalone/build.sh +++ b/conda/artiq-sayma_amc-standalone/build.sh @@ -5,5 +5,5 @@ mkdir -p $SOC_PREFIX V=1 $PYTHON -m artiq.gateware.targets.sayma_amc_standalone --rtm-csr-csv $SP_DIR/artiq/binaries/sayma_rtm/sayma_rtm_csr.csv cp misoc_standalone_sayma_amc/gateware/top.bit $SOC_PREFIX -cp misoc_standalone_sayma_amc/software/bios/bios.bin $SOC_PREFIX +cp misoc_standalone_sayma_amc/software/bootloader/bootloader.bin $SOC_PREFIX cp misoc_standalone_sayma_amc/software/runtime/runtime.{elf,fbi} $SOC_PREFIX From a9ad4f08e9b64cdb4ca0d42ccfb728b336019a5f Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 13:36:28 +0000 Subject: [PATCH 0124/2457] conda: bump misoc dependency. --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index c1faa2656..5a17de0d9 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6.dev py35_50+git82b06ee - - misoc 0.8.dev py35_41+gitc69cb371 + - misoc 0.8.dev py35_44+git9b3ccd9c - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From 55cfdec644d953ce31ef9a04ccbfeabfd2f6eb58 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 14:38:56 +0000 Subject: [PATCH 0125/2457] firmware: enlarge bootloader partition to 4 sectors. --- artiq/firmware/libboard/config.rs | 2 +- artiq/frontend/artiq_flash.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/libboard/config.rs b/artiq/firmware/libboard/config.rs index aec58979b..665ccc462 100644 --- a/artiq/firmware/libboard/config.rs +++ b/artiq/firmware/libboard/config.rs @@ -37,7 +37,7 @@ mod imp { use spiflash; use super::Error; - // One flash sector immediately after the bootloader. + // One flash sector immediately before the firmware. const ADDR: usize = ::mem::FLASH_BOOT_ADDRESS - spiflash::PAGE_SIZE; const SIZE: usize = spiflash::PAGE_SIZE; diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 72d5fd11e..5e1d15a12 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -195,8 +195,8 @@ def main(): "variants": ["nist_clock", "nist_qc2"], "gateware": (0, 0x000000), "bootloader": (0, 0xaf0000), - "storage": (0, 0xb00000), - "runtime": (0, 0xb10000), + "storage": (0, 0xb30000), + "runtime": (0, 0xb40000), }, "sayma": { "programmer_factory": ProgrammerSayma, @@ -204,8 +204,8 @@ def main(): "variants": ["standalone"], "gateware": (0, 0x000000), "bootloader": (1, 0x000000), - "storage": (1, 0x010000), - "runtime": (1, 0x020000), + "storage": (1, 0x040000), + "runtime": (1, 0x050000), }, }[opts.target] From 33e0393e4ad0f8bbaf93373a1994480f31af47bd Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 14:40:15 +0000 Subject: [PATCH 0126/2457] firmware: move mod ethmac to libboard. --- artiq/firmware/libboard/Cargo.toml | 6 ++++++ artiq/firmware/{runtime => libboard}/ethmac.rs | 7 ++++--- artiq/firmware/libboard/lib.rs | 4 ++++ artiq/firmware/runtime/Cargo.toml | 2 +- artiq/firmware/runtime/main.rs | 4 ++-- 5 files changed, 17 insertions(+), 6 deletions(-) rename artiq/firmware/{runtime => libboard}/ethmac.rs (97%) diff --git a/artiq/firmware/libboard/Cargo.toml b/artiq/firmware/libboard/Cargo.toml index 9604e9a6e..be1129200 100644 --- a/artiq/firmware/libboard/Cargo.toml +++ b/artiq/firmware/libboard/Cargo.toml @@ -15,5 +15,11 @@ build_misoc = { path = "../libbuild_misoc" } [dependencies] byteorder = { version = "1.0", default-features = false } +[dependencies.smoltcp] +git = "https://github.com/m-labs/smoltcp" +rev = "507d2fe" +default-features = false +optional = true + [features] uart_console = [] diff --git a/artiq/firmware/runtime/ethmac.rs b/artiq/firmware/libboard/ethmac.rs similarity index 97% rename from artiq/firmware/runtime/ethmac.rs rename to artiq/firmware/libboard/ethmac.rs index a19a13933..1a1f29272 100644 --- a/artiq/firmware/runtime/ethmac.rs +++ b/artiq/firmware/libboard/ethmac.rs @@ -2,7 +2,8 @@ use core::{slice, fmt}; use smoltcp::Result; use smoltcp::phy::{self, DeviceCapabilities, Device}; -use board::{csr, mem}; +use csr; +use mem::ETHMAC_BASE; const RX_SLOTS: usize = csr::ETHMAC_RX_SLOTS as usize; const TX_SLOTS: usize = csr::ETHMAC_TX_SLOTS as usize; @@ -30,12 +31,12 @@ fn next_tx_slot() -> Option { fn rx_buffer(slot: usize) -> *const u8 { debug_assert!(slot < RX_SLOTS); - (mem::ETHMAC_BASE + SLOT_SIZE * slot) as _ + (ETHMAC_BASE + SLOT_SIZE * slot) as _ } fn tx_buffer(slot: usize) -> *mut u8 { debug_assert!(slot < TX_SLOTS); - (mem::ETHMAC_BASE + SLOT_SIZE * (RX_SLOTS + slot)) as _ + (ETHMAC_BASE + SLOT_SIZE * (RX_SLOTS + slot)) as _ } pub struct EthernetDevice(()); diff --git a/artiq/firmware/libboard/lib.rs b/artiq/firmware/libboard/lib.rs index 27de0b9e1..06e08a417 100644 --- a/artiq/firmware/libboard/lib.rs +++ b/artiq/firmware/libboard/lib.rs @@ -2,6 +2,8 @@ #![feature(asm)] extern crate byteorder; +#[cfg(feature = "smoltcp")] +extern crate smoltcp; #[cfg(target_arch = "or1k")] #[path = "or1k/mod.rs"] @@ -21,3 +23,5 @@ pub mod spiflash; pub mod config; #[cfg(feature = "uart_console")] pub mod uart_console; +#[cfg(all(has_ethmac, feature = "smoltcp"))] +pub mod ethmac; diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 5802b84b2..f9d75b567 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -17,7 +17,7 @@ build_artiq = { path = "../libbuild_artiq" } byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } log = { version = "0.3", default-features = false } -board = { path = "../libboard", features = ["uart_console"] } +board = { path = "../libboard", features = ["uart_console", "smoltcp"] } alloc_list = { path = "../liballoc_list" } std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] } logger_artiq = { path = "../liblogger_artiq" } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index d5e9462f5..245acb8ba 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -26,11 +26,11 @@ extern crate drtioaux; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; use board::config; +#[cfg(has_ethmac)] +use board::ethmac; use proto::{mgmt_proto, analyzer_proto, moninj_proto, rpc_proto, session_proto, kernel_proto}; use amp::{mailbox, rpc_queue}; -#[cfg(has_ethmac)] -mod ethmac; #[cfg(has_rtio_core)] mod rtio_mgt; From 6d0168edb75d3f244d9d71356664fa4082faba96 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 15:25:56 +0000 Subject: [PATCH 0127/2457] conda: bump misoc dependency. --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 5a17de0d9..3bf80921e 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6.dev py35_50+git82b06ee - - misoc 0.8.dev py35_44+git9b3ccd9c + - misoc 0.8.dev py35_45+giteba459e9 - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From d2687ce3c467457f24a7a971392ee9b70ef063ed Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 15:25:40 +0000 Subject: [PATCH 0128/2457] firmware: fix a typo replacing spiflash::SECTOR_SIZE with PAGE_SIZE. --- artiq/firmware/libboard/config.rs | 4 ++-- artiq/firmware/libboard/spiflash.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard/config.rs b/artiq/firmware/libboard/config.rs index 665ccc462..443221d76 100644 --- a/artiq/firmware/libboard/config.rs +++ b/artiq/firmware/libboard/config.rs @@ -38,8 +38,8 @@ mod imp { use super::Error; // One flash sector immediately before the firmware. - const ADDR: usize = ::mem::FLASH_BOOT_ADDRESS - spiflash::PAGE_SIZE; - const SIZE: usize = spiflash::PAGE_SIZE; + const ADDR: usize = ::mem::FLASH_BOOT_ADDRESS - spiflash::SECTOR_SIZE; + const SIZE: usize = spiflash::SECTOR_SIZE; mod lock { use core::slice; diff --git a/artiq/firmware/libboard/spiflash.rs b/artiq/firmware/libboard/spiflash.rs index 2273185d5..3a4e7cb59 100644 --- a/artiq/firmware/libboard/spiflash.rs +++ b/artiq/firmware/libboard/spiflash.rs @@ -1,7 +1,8 @@ use core::cmp; use csr; -pub const PAGE_SIZE: usize = csr::CONFIG_SPIFLASH_PAGE_SIZE as usize; +pub const SECTOR_SIZE: usize = csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize; +pub const PAGE_SIZE: usize = csr::CONFIG_SPIFLASH_PAGE_SIZE as usize; const PAGE_MASK: usize = PAGE_SIZE - 1; From 35058781769d36fc6931b3ec56a90b7c037a39b0 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 28 Dec 2017 14:51:20 +0000 Subject: [PATCH 0129/2457] bootloader: add basic network support. --- artiq/firmware/Cargo.lock | 10 +-- artiq/firmware/bootloader/Cargo.toml | 14 ++++- artiq/firmware/bootloader/bootloader.ld | 2 +- artiq/firmware/bootloader/main.rs | 82 ++++++++++++++++++++----- 4 files changed, 84 insertions(+), 24 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index a3a9dfd79..60bc1d727 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -29,6 +29,7 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)", ] [[package]] @@ -49,8 +50,9 @@ dependencies = [ "board 0.0.0", "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)", "crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)", - "rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)", ] [[package]] @@ -199,11 +201,6 @@ dependencies = [ "std_artiq 0.0.0", ] -[[package]] -name = "rlibc" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "runtime" version = "0.0.0" @@ -307,7 +304,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" "checksum managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)" = "" -"checksum rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" "checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)" = "" diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml index 26521a87e..465905e7e 100644 --- a/artiq/firmware/bootloader/Cargo.toml +++ b/artiq/firmware/bootloader/Cargo.toml @@ -13,7 +13,17 @@ path = "main.rs" build_misoc = { path = "../libbuild_misoc" } [dependencies] -rlibc = "1.0" byteorder = { version = "1.0", default-features = false } crc = { git = "git://github.com/whitequark/crc-rs", rev = "51cd356", default-features = false } -board = { path = "../libboard", features = ["uart_console"] } +board = { path = "../libboard", features = ["uart_console", "smoltcp"] } + +[dependencies.compiler_builtins] +git = "https://github.com/m-labs/compiler-builtins" +rev = "97916b1" +features = ["mem"] + +[dependencies.smoltcp] +git = "https://github.com/m-labs/smoltcp" +rev = "507d2fe" +default-features = false +features = ["proto-ipv4", "socket-tcp"] diff --git a/artiq/firmware/bootloader/bootloader.ld b/artiq/firmware/bootloader/bootloader.ld index 8fe809a49..6331f920e 100644 --- a/artiq/firmware/bootloader/bootloader.ld +++ b/artiq/firmware/bootloader/bootloader.ld @@ -28,7 +28,7 @@ SECTIONS . += 4; } - .bss ALIGN(4) : + .bss : { _fbss = .; *(.bss .bss.*) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 61ae7a48d..2c06953a6 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -1,16 +1,18 @@ #![no_std] -#![feature(lang_items)] +#![feature(lang_items, compiler_builtins_lib)] -extern crate rlibc; +extern crate compiler_builtins; extern crate crc; extern crate byteorder; +extern crate smoltcp; #[macro_use] extern crate board; use core::{ptr, slice}; use crc::crc32; use byteorder::{ByteOrder, BigEndian}; -use board::{boot, cache}; +use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; +use board::{boot, cache, clock, config, ethmac}; use board::uart_console::Console; fn check_integrity() -> bool { @@ -28,7 +30,7 @@ fn check_integrity() -> bool { } } -unsafe fn memory_test(total: &mut usize, wrong: &mut usize) -> bool { +fn memory_test(total: &mut usize, wrong: &mut usize) -> bool { const MEMORY: *mut u32 = board::mem::MAIN_RAM_BASE as *mut u32; *total = 0; @@ -43,7 +45,7 @@ unsafe fn memory_test(total: &mut usize, wrong: &mut usize) -> bool { ) => ({ $prepare; for $i in $range { - ptr::write_volatile(MEMORY.offset($index as isize), $data); + unsafe { ptr::write_volatile(MEMORY.offset($index as isize), $data) }; *total += 1; } @@ -52,7 +54,7 @@ unsafe fn memory_test(total: &mut usize, wrong: &mut usize) -> bool { $prepare; for $i in $range { - if ptr::read_volatile(MEMORY.offset($index as isize)) != $data { + if unsafe { ptr::read_volatile(MEMORY.offset($index as isize)) } != $data { *wrong += 1; } } @@ -95,7 +97,7 @@ fn startup() -> bool { } let (mut total, mut wrong) = (0, 0); - if unsafe { memory_test(&mut total, &mut wrong) } { + if memory_test(&mut total, &mut wrong) { println!("Memory test passed"); } else { println!("Memory test failed ({}/{} words incorrect)", wrong, total); @@ -105,36 +107,81 @@ fn startup() -> bool { true } -unsafe fn flash_boot() { +fn flash_boot() { const FIRMWARE: *mut u8 = board::mem::FLASH_BOOT_ADDRESS as *mut u8; const MAIN_RAM: *mut u8 = board::mem::MAIN_RAM_BASE as *mut u8; println!("Booting from flash..."); - let header = slice::from_raw_parts(FIRMWARE, 8); + let header = unsafe { slice::from_raw_parts(FIRMWARE, 8) }; let length = BigEndian::read_u32(&header[0..]) as usize; let expected_crc = BigEndian::read_u32(&header[4..]); if length == 0xffffffff { println!("No firmware present"); return + } else if length > 4 * 1024 * 1024 { + println!("Firmware too large (is it corrupted?)"); + return } - let firmware_in_flash = slice::from_raw_parts(FIRMWARE.offset(8), length); + let firmware_in_flash = unsafe { slice::from_raw_parts(FIRMWARE.offset(8), length) }; let actual_crc = crc32::checksum_ieee(firmware_in_flash); if actual_crc == expected_crc { - let firmware_in_sdram = slice::from_raw_parts_mut(MAIN_RAM, length); + let firmware_in_sdram = unsafe { slice::from_raw_parts_mut(MAIN_RAM, length) }; firmware_in_sdram.copy_from_slice(firmware_in_flash); println!("Starting firmware."); - boot::jump(MAIN_RAM as usize); + unsafe { boot::jump(MAIN_RAM as usize) } } else { - println!("Firmware CRC failed (actual {:08x}, expected {:08x}", + println!("Firmware CRC failed (actual {:08x}, expected {:08x})", actual_crc, expected_crc); } } +fn network_boot() { + println!("Initializing network..."); + + let eth_addr = match config::read_str("mac", |r| r.map(|s| s.parse())) { + Ok(Ok(addr)) => addr, + _ => EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]) + }; + + let ip_addr = match config::read_str("ip", |r| r.map(|s| s.parse())) { + Ok(Ok(addr)) => addr, + _ => IpAddress::v4(192, 168, 1, 50) + }; + + println!("Using MAC address {} and IP address {}", eth_addr, ip_addr); + + let net_device = unsafe { ethmac::EthernetDevice::new() }; + let mut neighbor_cache_storage = [None; 2]; + let neighbor_cache = + smoltcp::iface::NeighborCache::new(&mut neighbor_cache_storage[..]); + let mut ip_addrs = [IpCidr::new(ip_addr, 0)]; + let mut interface = + smoltcp::iface::EthernetInterfaceBuilder::new(net_device) + .neighbor_cache(neighbor_cache) + .ethernet_addr(eth_addr) + .ip_addrs(&mut ip_addrs[..]) + .finalize(); + + let mut socket_set_storage = []; + let mut sockets = + smoltcp::socket::SocketSet::new(&mut socket_set_storage[..]); + + println!("Waiting for connections..."); + + loop { + match interface.poll(&mut sockets, clock::get_ms()) { + Ok(_) => (), + Err(smoltcp::Error::Unrecognized) => (), + Err(err) => println!("Network error: {}", err) + } + } +} + #[no_mangle] pub extern fn main() -> i32 { println!(""); @@ -150,7 +197,8 @@ pub extern fn main() -> i32 { if startup() { println!(""); - unsafe { flash_boot() }; + flash_boot(); + network_boot(); } else { println!("Halting."); } @@ -163,6 +211,12 @@ pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { panic!("exception {} at PC {:#08x}, EA {:#08x}", vect, pc, ea) } +#[no_mangle] +pub extern fn abort() { + println!("aborted"); + loop {} +} + #[no_mangle] #[lang = "panic_fmt"] pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! { From 37f9c0b10c47a826b88bd6ff6cb9551f80e49e34 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 28 Dec 2017 16:49:35 +0100 Subject: [PATCH 0130/2457] spi: register clk following m-labs/misoc#65 https://github.com/m-labs/misoc/commit/1dc68b0d0b19ecb35878d345034b2f0853a10bb8 --- artiq/gateware/spi.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/spi.py b/artiq/gateware/spi.py index 182a934f5..59cc64dbe 100644 --- a/artiq/gateware/spi.py +++ b/artiq/gateware/spi.py @@ -203,7 +203,11 @@ class SPIMaster(Module): mosi_oe.eq( ~config.offline & spi.cs & (spi.oe | ~config.half_duplex)), - clk.eq((spi.cg.clk & spi.cs) ^ config.clk_polarity) + ] + self.sync += [ + If(spi.cg.ce & spi.cg.edge, + clk.eq((~spi.cg.clk & spi.cs_next) ^ config.clk_polarity) + ) ] if pads_n is None: From 605da18684bd73a81a48f51c602f542451bfbfcf Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 28 Dec 2017 16:53:41 +0100 Subject: [PATCH 0131/2457] conda/artiq-dev: bump misoc (spi) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 3bf80921e..37c5f3fe7 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6.dev py35_50+git82b06ee - - misoc 0.8.dev py35_45+giteba459e9 + - misoc 0.8.dev py35_46+git1dc68b0d - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From f26d08fed3f0b63fde35997d8a1dabe2d918339e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 28 Dec 2017 22:47:25 +0100 Subject: [PATCH 0132/2457] conda/artiq-dev: bump migen (color vivado 2017.4) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 37c5f3fe7..252951803 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.6.dev py35_50+git82b06ee + - migen 0.6.dev py35_59+gite459800 - misoc 0.8.dev py35_46+git1dc68b0d - jesd204b 0.4 - microscope From 6f27ca81fb665c6dd060e762bb305c7a0b6d04d0 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 28 Dec 2017 23:37:28 +0100 Subject: [PATCH 0133/2457] conda/artiq-dev: bump migen (color xilinx, colorama) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 252951803..bbaddc4c3 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.6.dev py35_59+gite459800 + - migen 0.6.dev py35_60+git8d68a3d - misoc 0.8.dev py35_46+git1dc68b0d - jesd204b 0.4 - microscope From 37eb73bf5c8094b758ef442c567fc19d26f2027b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 29 Dec 2017 10:45:46 +0800 Subject: [PATCH 0134/2457] conda: bump migen --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index bbaddc4c3..d554e8c7c 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.6.dev py35_60+git8d68a3d + - migen 0.6.dev py35_61+git31c446b - misoc 0.8.dev py35_46+git1dc68b0d - jesd204b 0.4 - microscope From 379d29561bb327a6eccca9a43ddc4ad1d031262c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 29 Dec 2017 19:15:40 +0100 Subject: [PATCH 0135/2457] sayma: plausibility assertion on sawg data stream --- artiq/gateware/targets/sayma_amc_standalone.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/targets/sayma_amc_standalone.py b/artiq/gateware/targets/sayma_amc_standalone.py index c9361cee5..6a966e2b1 100755 --- a/artiq/gateware/targets/sayma_amc_standalone.py +++ b/artiq/gateware/targets/sayma_amc_standalone.py @@ -95,6 +95,7 @@ class AD9154(Module, AutoCSR): self.submodules += self.sawgs for conv, ch in zip(self.jesd.core.sink.flatten(), self.sawgs): + assert len(Cat(ch.o)) == len(conv) self.sync.jesd += conv.eq(Cat(ch.o)) From 6e0288e56807a494f1119de0132201f2cc3ea2ee Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 30 Dec 2017 12:13:43 +0800 Subject: [PATCH 0136/2457] drtio: fix GTH CPLL reset --- artiq/gateware/drtio/transceiver/gth_ultrascale.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index 7febc7a1d..d6a74bb04 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -39,8 +39,10 @@ class GTHSingle(Module): rx_init = ClockDomainsRenamer("rtio_tx")(GTHInit(rtio_clk_freq, True)) self.submodules += tx_init, rx_init + cpll_reset = Signal() cpll_lock = Signal() self.comb += [ + cpll_reset.eq(tx_init.pllreset), tx_init.plllock.eq(cpll_lock), rx_init.plllock.eq(cpll_lock) ] @@ -77,7 +79,7 @@ class GTHSingle(Module): p_RXOUT_DIV=2, p_TXOUT_DIV=2, i_CPLLRESET=0, - i_CPLLPD=0, + i_CPLLPD=cpll_reset, o_CPLLLOCK=cpll_lock, i_CPLLLOCKEN=1, i_CPLLREFCLKSEL=0b001, From a897d82324992cea1b2bbfb891f0b0486793d14b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 31 Dec 2017 11:27:43 +0800 Subject: [PATCH 0137/2457] ad9154: retry initialization (#727) --- artiq/firmware/libboard_artiq/ad9154.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 5d2f4c057..c06a2197d 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -473,6 +473,17 @@ fn dac_cfg(dacno: u8) -> Result<(), &'static str> { Ok(()) } +fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { + for i in 0..99 { + let outcome = dac_cfg(dacno); + match outcome { + Ok(_) => return outcome, + Err(e) => warn!("AD9154-{} config attempt #{} failed ({}), retrying", dacno, i, e) + } + } + dac_cfg(dacno) +} + pub fn init() -> Result<(), &'static str> { // Release the JESD clock domain reset late, as we need to // set up clock chips before. @@ -481,7 +492,7 @@ pub fn init() -> Result<(), &'static str> { for dacno in 0..csr::AD9154.len() { let dacno = dacno as u8; debug!("setting up AD9154-{} DAC...", dacno); - dac_cfg(dacno)?; + dac_cfg_retry(dacno)?; } Ok(()) } From 38ce1f1d5df54ca7ae461100ad06fce43520a20b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 31 Dec 2017 12:08:11 +0800 Subject: [PATCH 0138/2457] artiq_flash: support flashing satman A bit ugly and ad-hoc but I cannot think of an easy and better option right now. --- artiq/frontend/artiq_flash.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 5e1d15a12..eebbd9b8d 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -22,7 +22,7 @@ Valid actions: * gateware: write gateware bitstream to flash * bootloader: write bootloader to flash * storage: write storage image to flash - * runtime: write runtime to flash + * firmware: write firmware to flash * load: load gateware bitstream into device (volatile but fast) * start: trigger the target to (re)load its gateware bitstream from flash @@ -45,10 +45,10 @@ Prerequisites: "when several are connected.") parser.add_argument("-f", "--storage", help="write file to storage area") parser.add_argument("-d", "--dir", help="look for files in this directory") - parser.add_argument("--srcbuild", help="look for bitstream, BIOS and runtime in this " + parser.add_argument("--srcbuild", help="look for bitstream, bootloader and firmware in this " "ARTIQ source build tree") parser.add_argument("action", metavar="ACTION", nargs="*", - default="proxy gateware bootloader runtime start".split(), + default="proxy gateware bootloader firmware start".split(), help="actions to perform, default: %(default)s") return parser @@ -196,32 +196,28 @@ def main(): "gateware": (0, 0x000000), "bootloader": (0, 0xaf0000), "storage": (0, 0xb30000), - "runtime": (0, 0xb40000), + "firmware": (0, 0xb40000), }, "sayma": { "programmer_factory": ProgrammerSayma, "proxy_bitfile": "bscan_spi_xcku040-sayma.bit", - "variants": ["standalone"], + "variants": ["standalone", "master", "satellite"], "gateware": (0, 0x000000), "bootloader": (1, 0x000000), "storage": (1, 0x040000), - "runtime": (1, 0x050000), + "firmware": (1, 0x050000), }, }[opts.target] variant = opts.variant if variant is not None and variant not in config["variants"]: raise SystemExit("Invalid variant for this board") - if variant is None and config["variants"]: + if variant is None: variant = config["variants"][0] bin_dir = opts.dir if bin_dir is None: - if variant is None: - bin_dir = os.path.join(artiq_dir, "binaries", - "{}".format(opts.target)) - else: - bin_dir = os.path.join(artiq_dir, "binaries", - "{}-{}".format(opts.target, variant)) + bin_dir = os.path.join(artiq_dir, "binaries", + "{}-{}".format(opts.target, variant)) if opts.srcbuild is None and not os.path.exists(bin_dir) and opts.action != ["start"]: raise SystemExit("Binaries directory '{}' does not exist" .format(bin_dir)) @@ -263,12 +259,17 @@ def main(): programmer.flash_binary(*config["bootloader"], os.path.join(path, "bootloader.bin")) elif action == "storage": programmer.flash_binary(*config["storage"], opts.storage) - elif action == "runtime": + elif action == "firmware": + if variant == "satellite": + firmware_name = "satman" + else: + firmware_name = "runtime" if opts.srcbuild is None: path = bin_dir else: - path = os.path.join(opts.srcbuild, "software", "runtime") - programmer.flash_binary(*config["runtime"], os.path.join(path, "runtime.fbi")) + path = os.path.join(opts.srcbuild, "software", firmware_name) + programmer.flash_binary(*config["firmware"], + os.path.join(path, firmware_name + ".fbi")) elif action == "load": if opts.srcbuild is None: path = bin_dir From 100bda2582eb939ae08bb395144e1e2f655016ce Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 31 Dec 2017 12:10:16 +0800 Subject: [PATCH 0139/2457] artiq_flash: ignore RTM FPGA It has no flash connected, and attempting to detect it causes unnecessary program failure when the RTM is not present. --- artiq/frontend/artiq_flash.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index eebbd9b8d..5f9f2f0db 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -147,9 +147,8 @@ class ProgrammerSayma(Programmer): "adapter_khz 5000", "transport select jtag", - "source [find cpld/xilinx-xc7.cfg]", # tap 0, pld 0 "set CHIP XCKU040", - "source [find cpld/xilinx-xcu.cfg]", # tap 1, pld 1 + "source [find cpld/xilinx-xcu.cfg]", "target create xcu.proxy testee -chain-position xcu.tap", "set XILINX_USER1 0x02", @@ -159,11 +158,11 @@ class ProgrammerSayma(Programmer): ] self.init() - def load(self, bitfile, pld=1): - self.prog.append("pld load {} {{{}}}".format(pld, bitfile)) + def load(self, bitfile): + self.prog.append("pld load 0 {{{}}}".format(bitfile)) - def proxy(self, proxy_bitfile, pld=1): - self.load(proxy_bitfile, pld) + def proxy(self, proxy_bitfile): + self.load(proxy_bitfile) self.prog.append("reset halt") def flash_binary(self, flashno, address, filename): From a1b8bca1e691425b64cfec3c5973e14123ca4cef Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 31 Dec 2017 13:23:26 +0800 Subject: [PATCH 0140/2457] Revert "artiq_flash: ignore RTM FPGA" Naive optimism. This reverts commit 100bda2582eb939ae08bb395144e1e2f655016ce. --- artiq/frontend/artiq_flash.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 5f9f2f0db..eebbd9b8d 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -147,8 +147,9 @@ class ProgrammerSayma(Programmer): "adapter_khz 5000", "transport select jtag", + "source [find cpld/xilinx-xc7.cfg]", # tap 0, pld 0 "set CHIP XCKU040", - "source [find cpld/xilinx-xcu.cfg]", + "source [find cpld/xilinx-xcu.cfg]", # tap 1, pld 1 "target create xcu.proxy testee -chain-position xcu.tap", "set XILINX_USER1 0x02", @@ -158,11 +159,11 @@ class ProgrammerSayma(Programmer): ] self.init() - def load(self, bitfile): - self.prog.append("pld load 0 {{{}}}".format(bitfile)) + def load(self, bitfile, pld=1): + self.prog.append("pld load {} {{{}}}".format(pld, bitfile)) - def proxy(self, proxy_bitfile): - self.load(proxy_bitfile) + def proxy(self, proxy_bitfile, pld=1): + self.load(proxy_bitfile, pld) self.prog.append("reset halt") def flash_binary(self, flashno, address, filename): From b8f3d28bc049d21f2bd7314c446d93b864d419a8 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 31 Dec 2017 09:11:52 +0000 Subject: [PATCH 0141/2457] firmware: update compiler_builtins dependency and move it to libboard. This is so that we only specify it once. --- artiq/firmware/Cargo.lock | 31 +++------------------------- artiq/firmware/bootloader/Cargo.toml | 5 ----- artiq/firmware/bootloader/main.rs | 3 +-- artiq/firmware/ksupport/Cargo.toml | 5 ----- artiq/firmware/ksupport/lib.rs | 5 +---- artiq/firmware/libboard/Cargo.toml | 5 +++++ artiq/firmware/libboard/lib.rs | 3 ++- artiq/firmware/runtime/Cargo.toml | 5 ----- artiq/firmware/runtime/main.rs | 3 +-- artiq/firmware/satman/Cargo.toml | 5 ----- artiq/firmware/satman/main.rs | 2 +- 11 files changed, 14 insertions(+), 58 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 60bc1d727..19e46510e 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -29,6 +29,7 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=1c765ad)", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)", ] @@ -50,7 +51,6 @@ dependencies = [ "board 0.0.0", "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)", "crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)", ] @@ -84,16 +84,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "compiler_builtins" version = "0.1.0" -source = "git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568#631b5687b24af413fdbffa4c2644484e60660b00" -dependencies = [ - "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "compiler_builtins" -version = "0.1.0" -source = "git+https://github.com/m-labs/compiler-builtins?rev=97916b1#97916b17ca542eac0524b8570c7d05913891a0dc" +source = "git+https://github.com/m-labs/compiler-builtins?rev=1c765ad#1c765adbe8e246e01db39aba0a71a6b5721e2465" [[package]] name = "crc" @@ -131,11 +122,6 @@ dependencies = [ "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "gcc" -version = "0.3.54" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "kernel32-sys" version = "0.2.2" @@ -154,7 +140,6 @@ dependencies = [ "board 0.0.0", "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dyld 0.0.0", "proto 0.0.0", @@ -213,7 +198,6 @@ dependencies = [ "build_artiq 0.0.0", "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "drtioaux 0.0.0", "fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)", @@ -224,11 +208,6 @@ dependencies = [ "std_artiq 0.0.0", ] -[[package]] -name = "rustc-cfg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "same-file" version = "0.1.3" @@ -247,7 +226,6 @@ dependencies = [ "board_artiq 0.0.0", "build_artiq 0.0.0", "build_misoc 0.0.0", - "compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)", "drtioaux 0.0.0", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "logger_artiq 0.0.0", @@ -293,18 +271,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" -"checksum compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=97916b1)" = "" -"checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)" = "" +"checksum compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=1c765ad)" = "" "checksum crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)" = "" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" "checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "" -"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" "checksum managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)" = "" -"checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)" = "" "checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml index 465905e7e..987630d1c 100644 --- a/artiq/firmware/bootloader/Cargo.toml +++ b/artiq/firmware/bootloader/Cargo.toml @@ -17,11 +17,6 @@ byteorder = { version = "1.0", default-features = false } crc = { git = "git://github.com/whitequark/crc-rs", rev = "51cd356", default-features = false } board = { path = "../libboard", features = ["uart_console", "smoltcp"] } -[dependencies.compiler_builtins] -git = "https://github.com/m-labs/compiler-builtins" -rev = "97916b1" -features = ["mem"] - [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" rev = "507d2fe" diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 2c06953a6..454cfd8c1 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -1,7 +1,6 @@ #![no_std] -#![feature(lang_items, compiler_builtins_lib)] +#![feature(lang_items)] -extern crate compiler_builtins; extern crate crc; extern crate byteorder; extern crate smoltcp; diff --git a/artiq/firmware/ksupport/Cargo.toml b/artiq/firmware/ksupport/Cargo.toml index b295c160c..eafb7c7ae 100644 --- a/artiq/firmware/ksupport/Cargo.toml +++ b/artiq/firmware/ksupport/Cargo.toml @@ -21,8 +21,3 @@ dyld = { path = "../libdyld" } board = { path = "../libboard" } proto = { path = "../libproto" } amp = { path = "../libamp" } - -[dependencies.compiler_builtins] -git = "https://github.com/m-labs/compiler-builtins" -rev = "97916b1" -features = ["mem"] diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index c6ec95fb2..d1fb0029f 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -1,8 +1,6 @@ -#![feature(lang_items, asm, libc, panic_unwind, unwind_attributes, global_allocator, - compiler_builtins_lib)] +#![feature(lang_items, asm, libc, panic_unwind, unwind_attributes, global_allocator)] #![no_std] -extern crate compiler_builtins; extern crate byteorder; extern crate cslice; extern crate unwind; @@ -10,7 +8,6 @@ extern crate libc; extern crate alloc_stub; extern crate std_artiq as std; - extern crate board; extern crate dyld; extern crate proto; diff --git a/artiq/firmware/libboard/Cargo.toml b/artiq/firmware/libboard/Cargo.toml index be1129200..c0dfd8055 100644 --- a/artiq/firmware/libboard/Cargo.toml +++ b/artiq/firmware/libboard/Cargo.toml @@ -15,6 +15,11 @@ build_misoc = { path = "../libbuild_misoc" } [dependencies] byteorder = { version = "1.0", default-features = false } +[dependencies.compiler_builtins] +git = "https://github.com/m-labs/compiler-builtins" +rev = "1c765ad" +features = ["mem"] + [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" rev = "507d2fe" diff --git a/artiq/firmware/libboard/lib.rs b/artiq/firmware/libboard/lib.rs index 06e08a417..4d0311719 100644 --- a/artiq/firmware/libboard/lib.rs +++ b/artiq/firmware/libboard/lib.rs @@ -1,6 +1,7 @@ #![no_std] -#![feature(asm)] +#![feature(compiler_builtins_lib, asm)] +extern crate compiler_builtins; extern crate byteorder; #[cfg(feature = "smoltcp")] extern crate smoltcp; diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index f9d75b567..7057814c1 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -27,11 +27,6 @@ proto = { path = "../libproto", features = ["log"] } amp = { path = "../libamp" } drtioaux = { path = "../libdrtioaux" } -[dependencies.compiler_builtins] -git = "https://github.com/m-labs/compiler-builtins" -rev = "97916b1" -features = ["mem"] - [dependencies.fringe] git = "https://github.com/m-labs/libfringe" rev = "bd23494" diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 245acb8ba..f8f996601 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -1,7 +1,6 @@ #![no_std] -#![feature(compiler_builtins_lib, alloc, lang_items, global_allocator, repr_align, attr_literals)] +#![feature(alloc, lang_items, global_allocator, repr_align, attr_literals)] -extern crate compiler_builtins; extern crate alloc; extern crate cslice; #[macro_use] diff --git a/artiq/firmware/satman/Cargo.toml b/artiq/firmware/satman/Cargo.toml index 7cab6d4c1..8ca07b053 100644 --- a/artiq/firmware/satman/Cargo.toml +++ b/artiq/firmware/satman/Cargo.toml @@ -21,8 +21,3 @@ board_artiq = { path = "../libboard_artiq" } std_artiq = { path = "../libstd_artiq", features = ["alloc"] } logger_artiq = { path = "../liblogger_artiq" } drtioaux = { path = "../libdrtioaux" } - -[dependencies.compiler_builtins] -git = "https://github.com/rust-lang-nursery/compiler-builtins" -rev = "631b568" -features = ["mem"] diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 2e9110e7a..e942068fe 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -1,4 +1,4 @@ -#![feature(compiler_builtins_lib, lang_items, global_allocator)] +#![feature(lang_items, global_allocator)] #![no_std] extern crate compiler_builtins; From e1253db0e869266714227f20deb25909d77a71a2 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 31 Dec 2017 09:15:22 +0000 Subject: [PATCH 0142/2457] firmware: update crc dependency, use it in libdrtioaux. --- artiq/firmware/Cargo.lock | 9 ++--- artiq/firmware/bootloader/Cargo.toml | 2 +- artiq/firmware/libdrtioaux/Cargo.toml | 1 + artiq/firmware/libdrtioaux/crc32.rs | 49 --------------------------- artiq/firmware/libdrtioaux/lib.rs | 11 +++--- 5 files changed, 12 insertions(+), 60 deletions(-) delete mode 100644 artiq/firmware/libdrtioaux/crc32.rs diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 19e46510e..6a04d73c2 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -51,7 +51,7 @@ dependencies = [ "board 0.0.0", "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)", + "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)", ] @@ -88,8 +88,8 @@ source = "git+https://github.com/m-labs/compiler-builtins?rev=1c765ad#1c765adbe8 [[package]] name = "crc" -version = "1.6.0" -source = "git+git://github.com/whitequark/crc-rs?rev=51cd356#51cd3560aa9d3823061f2bb46797d8c61f4cfa9e" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -106,6 +106,7 @@ dependencies = [ "board 0.0.0", "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "std_artiq 0.0.0", ] @@ -272,7 +273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" "checksum compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=1c765ad)" = "" -"checksum crc 1.6.0 (git+git://github.com/whitequark/crc-rs?rev=51cd356)" = "" +"checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" "checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml index 987630d1c..a5975ade1 100644 --- a/artiq/firmware/bootloader/Cargo.toml +++ b/artiq/firmware/bootloader/Cargo.toml @@ -14,7 +14,7 @@ build_misoc = { path = "../libbuild_misoc" } [dependencies] byteorder = { version = "1.0", default-features = false } -crc = { git = "git://github.com/whitequark/crc-rs", rev = "51cd356", default-features = false } +crc = { version = "1.7", default-features = false } board = { path = "../libboard", features = ["uart_console", "smoltcp"] } [dependencies.smoltcp] diff --git a/artiq/firmware/libdrtioaux/Cargo.toml b/artiq/firmware/libdrtioaux/Cargo.toml index def5c328b..515c15e29 100644 --- a/artiq/firmware/libdrtioaux/Cargo.toml +++ b/artiq/firmware/libdrtioaux/Cargo.toml @@ -13,6 +13,7 @@ build_misoc = { path = "../libbuild_misoc" } [dependencies] log = { version = "0.3", default-features = false } +crc = { version = "1.7", default-features = false } std_artiq = { path = "../libstd_artiq", features = ["alloc"] } board = { path = "../libboard" } byteorder = { version = "1.0", default-features = false } diff --git a/artiq/firmware/libdrtioaux/crc32.rs b/artiq/firmware/libdrtioaux/crc32.rs deleted file mode 100644 index 9cbaa56de..000000000 --- a/artiq/firmware/libdrtioaux/crc32.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Based on crc 1.4.0 by mrhooray - -static IEEE_TABLE: [u32; 256] = [ - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, -]; - -pub fn update(mut value: u32, table: &[u32; 256], bytes: &[u8]) -> u32 { - value = !value; - for &i in bytes.iter() { - value = table[((value as u8) ^ i) as usize] ^ (value >> 8) - } - !value -} - -pub fn checksum_ieee(bytes: &[u8]) -> u32 { - return update(0, &IEEE_TABLE, bytes); -} - diff --git a/artiq/firmware/libdrtioaux/lib.rs b/artiq/firmware/libdrtioaux/lib.rs index ece63f37e..e1b4c282c 100644 --- a/artiq/firmware/libdrtioaux/lib.rs +++ b/artiq/firmware/libdrtioaux/lib.rs @@ -1,13 +1,12 @@ #![no_std] +extern crate byteorder; +extern crate crc; #[macro_use] extern crate std_artiq as std; extern crate board; -extern crate byteorder; mod proto; -#[cfg(has_drtio)] -mod crc32; use std::io::{self, Read, Write}; #[cfg(has_drtio)] @@ -278,7 +277,7 @@ pub mod hw { unsafe { if (board::csr::DRTIO[linkidx].aux_rx_present_read)() == 1 { let length = (board::csr::DRTIO[linkidx].aux_rx_length_read)(); - let base = board::mem::DRTIO_AUX[linkidx].base + board::mem::DRTIO_AUX[linkidx].size/2; + let base = board::mem::DRTIO_AUX[linkidx].base + board::mem::DRTIO_AUX[linkidx].size/2; let sl = slice::from_raw_parts(base as *mut u8, length as usize); Some(RxBuffer(linkno, sl)) } else { @@ -301,7 +300,7 @@ pub mod hw { if len < 8 { return Err(io::Error::new(io::ErrorKind::InvalidData, "packet too short")) } - let computed_crc = crc32::checksum_ieee(&reader.get_ref()[0..len-4]); + let computed_crc = crc::crc32::checksum_ieee(&reader.get_ref()[0..len-4]); reader.set_position((len-4) as u64); let crc = read_u32(&mut reader)?; if crc != computed_crc { @@ -365,7 +364,7 @@ pub mod hw { len += padding; } - let crc = crc32::checksum_ieee(&writer.get_ref()[0..len as usize]); + let crc = crc::crc32::checksum_ieee(&writer.get_ref()[0..len as usize]); write_u32(&mut writer, crc)?; len += 4; From 70ebe431fd3a518b4c20f94dfafc20eab7ca04a4 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 31 Dec 2017 09:21:02 +0000 Subject: [PATCH 0143/2457] satman: fix build after b8f3d28b. --- artiq/firmware/satman/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index e942068fe..66893a915 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -1,7 +1,6 @@ #![feature(lang_items, global_allocator)] #![no_std] -extern crate compiler_builtins; extern crate alloc_list; extern crate std_artiq as std; #[macro_use] From a371b2552516ece785a77342407b09f147a6d40c Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 31 Dec 2017 09:21:28 +0000 Subject: [PATCH 0144/2457] bootloader: allow using without Ethernet. --- artiq/firmware/bootloader/main.rs | 9 +++++++-- artiq/gateware/targets/sayma_amc_drtio_satellite.py | 5 ++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 454cfd8c1..87cdfb67d 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -10,8 +10,9 @@ extern crate board; use core::{ptr, slice}; use crc::crc32; use byteorder::{ByteOrder, BigEndian}; -use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; -use board::{boot, cache, clock, config, ethmac}; +use board::{boot, cache}; +#[cfg(has_ethmac)] +use board::{clock, config, ethmac}; use board::uart_console::Console; fn check_integrity() -> bool { @@ -139,7 +140,10 @@ fn flash_boot() { } } +#[cfg(has_ethmac)] fn network_boot() { + use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; + println!("Initializing network..."); let eth_addr = match config::read_str("mac", |r| r.map(|s| s.parse())) { @@ -197,6 +201,7 @@ pub extern fn main() -> i32 { if startup() { println!(""); flash_boot(); + #[cfg(has_ethmac)] network_boot(); } else { println!("Halting."); diff --git a/artiq/gateware/targets/sayma_amc_drtio_satellite.py b/artiq/gateware/targets/sayma_amc_drtio_satellite.py index dc6d35ef5..6b83ceb8a 100755 --- a/artiq/gateware/targets/sayma_amc_drtio_satellite.py +++ b/artiq/gateware/targets/sayma_amc_drtio_satellite.py @@ -110,8 +110,11 @@ def main(): args = parser.parse_args() soc = Satellite(**soc_sdram_argdict(args)) + firmware_dir = os.path.join(artiq_dir, "firmware") builder = Builder(soc, **builder_argdict(args)) - builder.add_software_package("satman", os.path.join(artiq_dir, "firmware", "satman")) + builder.software_packages = [] + builder.add_software_package("bootloader", os.path.join(firmware_dir, "bootloader")) + builder.add_software_package("satman", os.path.join(firmware_dir, "satman")) builder.build() From 745e695b0948a82cbb99ca8b3c348d8406feed85 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 31 Dec 2017 12:18:37 +0100 Subject: [PATCH 0145/2457] sayma: output a ramp in the absence of SAWG channels --- .../gateware/targets/sayma_amc_standalone.py | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc_standalone.py b/artiq/gateware/targets/sayma_amc_standalone.py index 6a966e2b1..1c732281d 100755 --- a/artiq/gateware/targets/sayma_amc_standalone.py +++ b/artiq/gateware/targets/sayma_amc_standalone.py @@ -99,6 +99,19 @@ class AD9154(Module, AutoCSR): self.sync.jesd += conv.eq(Cat(ch.o)) +class AD9154NoSAWG(Module, AutoCSR): + def __init__(self, platform, sys_crg, jesd_crg, dac): + self.submodules.jesd = AD9154JESD(platform, sys_crg, jesd_crg, dac) + + self.sawgs = [] + + for i, conv in enumerate(self.jesd.core.sink.flatten()): + ramp = Signal(16) + self.sync += ramp.eq(ramp + (1 << 9 + i)) + self.comb += conv.eq(Cat(ramp + for i in range(len(conv) // len(ramp)))) + + class Standalone(MiniSoC, AMPSoC): mem_map = { "cri_con": 0x10000000, @@ -177,19 +190,23 @@ class Standalone(MiniSoC, AMPSoC): rtio_channels.append(rtio.Channel.from_phy(phy)) if with_sawg: - self.submodules.ad9154_crg = AD9154CRG(platform) - self.submodules.ad9154_0 = AD9154(platform, self.crg, self.ad9154_crg, 0) - self.submodules.ad9154_1 = AD9154(platform, self.crg, self.ad9154_crg, 1) - self.csr_devices.append("ad9154_crg") - self.csr_devices.append("ad9154_0") - self.csr_devices.append("ad9154_1") - self.config["HAS_AD9154"] = None - self.add_csr_group("ad9154", ["ad9154_0", "ad9154_1"]) - self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels) - rtio_channels.extend(rtio.Channel.from_phy(phy) - for sawg in self.ad9154_0.sawgs + - self.ad9154_1.sawgs - for phy in sawg.phys) + cls = AD9154 + else: + cls = AD9154NoSAWG + + self.submodules.ad9154_crg = AD9154CRG(platform) + self.submodules.ad9154_0 = cls(platform, self.crg, self.ad9154_crg, 0) + self.submodules.ad9154_1 = cls(platform, self.crg, self.ad9154_crg, 1) + self.csr_devices.append("ad9154_crg") + self.csr_devices.append("ad9154_0") + self.csr_devices.append("ad9154_1") + self.config["HAS_AD9154"] = None + self.add_csr_group("ad9154", ["ad9154_0", "ad9154_1"]) + self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels) + rtio_channels.extend(rtio.Channel.from_phy(phy) + for sawg in self.ad9154_0.sawgs + + self.ad9154_1.sawgs + for phy in sawg.phys) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) From b7f38b123bfc76d0819f208c3748db136a62e00b Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 1 Jan 2018 11:45:55 +0000 Subject: [PATCH 0146/2457] frimware: update to log 0.4. --- artiq/firmware/Cargo.lock | 27 ++++++++--- artiq/firmware/libboard_artiq/Cargo.toml | 2 +- artiq/firmware/libdrtioaux/Cargo.toml | 2 +- artiq/firmware/liblogger_artiq/Cargo.toml | 2 +- artiq/firmware/liblogger_artiq/lib.rs | 56 +++++++---------------- artiq/firmware/libproto/Cargo.toml | 2 +- artiq/firmware/libproto/mgmt_proto.rs | 20 ++++---- artiq/firmware/runtime/Cargo.toml | 2 +- artiq/firmware/runtime/main.rs | 3 +- artiq/firmware/runtime/mgmt.rs | 9 ++-- artiq/firmware/satman/Cargo.toml | 2 +- 11 files changed, 58 insertions(+), 69 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 6a04d73c2..9f6e3a821 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -41,7 +41,7 @@ dependencies = [ "board 0.0.0", "build_artiq 0.0.0", "build_misoc 0.0.0", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -81,6 +81,11 @@ name = "cc" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cfg-if" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "compiler_builtins" version = "0.1.0" @@ -107,7 +112,7 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "std_artiq 0.0.0", ] @@ -157,6 +162,14 @@ name = "log" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "log" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log_buffer" version = "1.1.0" @@ -167,7 +180,7 @@ name = "logger_artiq" version = "0.0.0" dependencies = [ "board 0.0.0", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -183,7 +196,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dyld 0.0.0", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "std_artiq 0.0.0", ] @@ -202,7 +215,7 @@ dependencies = [ "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "drtioaux 0.0.0", "fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "logger_artiq 0.0.0", "proto 0.0.0", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)", @@ -228,7 +241,7 @@ dependencies = [ "build_artiq 0.0.0", "build_misoc 0.0.0", "drtioaux 0.0.0", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "logger_artiq 0.0.0", "std_artiq 0.0.0", ] @@ -272,6 +285,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" +"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=1c765ad)" = "" "checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" @@ -279,6 +293,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" +"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" "checksum managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)" = "" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" diff --git a/artiq/firmware/libboard_artiq/Cargo.toml b/artiq/firmware/libboard_artiq/Cargo.toml index 2c92b6050..d666b3ef0 100644 --- a/artiq/firmware/libboard_artiq/Cargo.toml +++ b/artiq/firmware/libboard_artiq/Cargo.toml @@ -14,7 +14,7 @@ build_artiq = { path = "../libbuild_artiq" } [dependencies] bitflags = "1.0" -log = { version = "0.3", default-features = false } +log = { version = "0.4", default-features = false } board = { path = "../libboard" } [features] diff --git a/artiq/firmware/libdrtioaux/Cargo.toml b/artiq/firmware/libdrtioaux/Cargo.toml index 515c15e29..6c4842148 100644 --- a/artiq/firmware/libdrtioaux/Cargo.toml +++ b/artiq/firmware/libdrtioaux/Cargo.toml @@ -12,7 +12,7 @@ path = "lib.rs" build_misoc = { path = "../libbuild_misoc" } [dependencies] -log = { version = "0.3", default-features = false } +log = { version = "0.4", default-features = false } crc = { version = "1.7", default-features = false } std_artiq = { path = "../libstd_artiq", features = ["alloc"] } board = { path = "../libboard" } diff --git a/artiq/firmware/liblogger_artiq/Cargo.toml b/artiq/firmware/liblogger_artiq/Cargo.toml index d9e6e2299..2cf792723 100644 --- a/artiq/firmware/liblogger_artiq/Cargo.toml +++ b/artiq/firmware/liblogger_artiq/Cargo.toml @@ -8,6 +8,6 @@ name = "logger_artiq" path = "lib.rs" [dependencies] -log = { version = "0.3", default-features = false, features = [] } +log = { version = "0.4", default-features = false } log_buffer = { version = "1.0" } board = { path = "../libboard" } diff --git a/artiq/firmware/liblogger_artiq/lib.rs b/artiq/firmware/liblogger_artiq/lib.rs index c51d45b7b..2d7dd531b 100644 --- a/artiq/firmware/liblogger_artiq/lib.rs +++ b/artiq/firmware/liblogger_artiq/lib.rs @@ -7,14 +7,13 @@ extern crate board; use core::cell::{Cell, RefCell}; use core::fmt::Write; -use log::{Log, LogMetadata, LogRecord, LogLevelFilter, MaxLogLevelFilter}; +use log::{Log, LevelFilter}; use log_buffer::LogBuffer; use board::clock; pub struct BufferLogger { buffer: RefCell>, - filter: RefCell>, - uart_filter: Cell + uart_filter: Cell } static mut LOGGER: *const BufferLogger = 0 as *const _; @@ -23,28 +22,18 @@ impl BufferLogger { pub fn new(buffer: &'static mut [u8]) -> BufferLogger { BufferLogger { buffer: RefCell::new(LogBuffer::new(buffer)), - filter: RefCell::new(None), - uart_filter: Cell::new(LogLevelFilter::Info), + uart_filter: Cell::new(LevelFilter::Info), } } pub fn register(&self, f: F) { - // log::set_logger_raw captures a pointer to ourselves, so we must prevent - // ourselves from being moved or dropped after that function is called (and - // before log::shutdown_logger_raw is called). unsafe { - log::set_logger_raw(|max_log_level| { - max_log_level.set(LogLevelFilter::Info); - *self.filter.borrow_mut() = Some(max_log_level); - self as *const Log - }).expect("global logger can only be initialized once"); LOGGER = self; + log::set_logger(&*LOGGER) + .expect("global logger can only be initialized once"); } + log::set_max_level(LevelFilter::Info); f(); - log::shutdown_logger_raw().unwrap(); - unsafe { - LOGGER = 0 as *const _; - } } pub fn with R>(f: F) -> R { @@ -60,34 +49,18 @@ impl BufferLogger { } pub fn extract R>(&self, f: F) -> R { - let old_log_level = self.max_log_level(); - self.set_max_log_level(LogLevelFilter::Off); + let old_log_level = log::max_level(); + log::set_max_level(LevelFilter::Off); let result = f(self.buffer.borrow_mut().extract()); - self.set_max_log_level(old_log_level); + log::set_max_level(old_log_level); result } - pub fn max_log_level(&self) -> LogLevelFilter { - self.filter - .borrow() - .as_ref() - .expect("register the logger before touching maximum log level") - .get() - } - - pub fn set_max_log_level(&self, max_level: LogLevelFilter) { - self.filter - .borrow() - .as_ref() - .expect("register the logger before touching maximum log level") - .set(max_level) - } - - pub fn uart_log_level(&self) -> LogLevelFilter { + pub fn uart_log_level(&self) -> LevelFilter { self.uart_filter.get() } - pub fn set_uart_log_level(&self, max_level: LogLevelFilter) { + pub fn set_uart_log_level(&self, max_level: LevelFilter) { self.uart_filter.set(max_level) } } @@ -96,11 +69,11 @@ impl BufferLogger { unsafe impl Sync for BufferLogger {} impl Log for BufferLogger { - fn enabled(&self, _metadata: &LogMetadata) -> bool { + fn enabled(&self, _metadata: &log::Metadata) -> bool { true } - fn log(&self, record: &LogRecord) { + fn log(&self, record: &log::Record) { if self.enabled(record.metadata()) { let timestamp = clock::get_us(); let seconds = timestamp / 1_000_000; @@ -116,4 +89,7 @@ impl Log for BufferLogger { } } } + + fn flush(&self) { + } } diff --git a/artiq/firmware/libproto/Cargo.toml b/artiq/firmware/libproto/Cargo.toml index 487ae483b..eb805f1eb 100644 --- a/artiq/firmware/libproto/Cargo.toml +++ b/artiq/firmware/libproto/Cargo.toml @@ -10,6 +10,6 @@ path = "lib.rs" [dependencies] byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } -log = { version = "0.3", default-features = false, optional = true } +log = { version = "0.4", default-features = false, optional = true } std_artiq = { path = "../libstd_artiq", features = ["alloc"] } dyld = { path = "../libdyld" } diff --git a/artiq/firmware/libproto/mgmt_proto.rs b/artiq/firmware/libproto/mgmt_proto.rs index 123af8915..cb5e08856 100644 --- a/artiq/firmware/libproto/mgmt_proto.rs +++ b/artiq/firmware/libproto/mgmt_proto.rs @@ -2,7 +2,7 @@ use std::vec::Vec; use std::io::{self, Read, Write}; use {ReadExt, WriteExt}; #[cfg(feature = "log")] -use log::LogLevelFilter; +use log; #[derive(Debug)] pub enum Request { @@ -10,9 +10,9 @@ pub enum Request { ClearLog, PullLog, #[cfg(feature = "log")] - SetLogFilter(LogLevelFilter), + SetLogFilter(log::LevelFilter), #[cfg(feature = "log")] - SetUartLogFilter(LogLevelFilter), + SetUartLogFilter(log::LevelFilter), Hotswap(Vec), Reboot, @@ -29,14 +29,14 @@ pub enum Reply<'a> { impl Request { pub fn read_from(reader: &mut Read) -> io::Result { #[cfg(feature = "log")] - fn read_log_level_filter(reader: &mut Read) -> io::Result { + fn read_log_level_filter(reader: &mut Read) -> io::Result { Ok(match reader.read_u8()? { - 0 => LogLevelFilter::Off, - 1 => LogLevelFilter::Error, - 2 => LogLevelFilter::Warn, - 3 => LogLevelFilter::Info, - 4 => LogLevelFilter::Debug, - 5 => LogLevelFilter::Trace, + 0 => log::LevelFilter::Off, + 1 => log::LevelFilter::Error, + 2 => log::LevelFilter::Warn, + 3 => log::LevelFilter::Info, + 4 => log::LevelFilter::Debug, + 5 => log::LevelFilter::Trace, _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid log level")) }) diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 7057814c1..59dd144c2 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -16,7 +16,7 @@ build_artiq = { path = "../libbuild_artiq" } [dependencies] byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } -log = { version = "0.3", default-features = false } +log = { version = "0.4", default-features = false } board = { path = "../libboard", features = ["uart_console", "smoltcp"] } alloc_list = { path = "../liballoc_list" } std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index f8f996601..1d6e631f5 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -164,8 +164,7 @@ fn startup_ethernet() { Ok(Ok(log_level_filter)) => { info!("log level set to {} by `log_level` config key", log_level_filter); - logger_artiq::BufferLogger::with(|logger| - logger.set_max_log_level(log_level_filter)); + log::set_max_level(log_level_filter); } _ => info!("log level set to INFO by default") } diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 2933102f5..ee3cbe5fb 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -1,6 +1,6 @@ use board::boot; use std::io::{self, Read, Write}; -use log::LogLevelFilter; +use log::{self, LevelFilter}; use logger_artiq::BufferLogger; use sched::Io; use sched::{TcpListener, TcpStream}; @@ -44,11 +44,11 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> { io.until(|| BufferLogger::with(|logger| !logger.is_empty()))?; BufferLogger::with(|logger| { - let log_level = logger.max_log_level(); + let log_level = log::max_level(); logger.extract(|log| { stream.write_string(log)?; - if log_level == LogLevelFilter::Trace { + if log_level == LevelFilter::Trace { // Hold exclusive access over the logger until we get positive // acknowledgement; otherwise we get an infinite loop of network // trace messages being transmitted and causing more network @@ -69,8 +69,7 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> { Request::SetLogFilter(level) => { info!("changing log level to {}", level); - BufferLogger::with(|logger| - logger.set_max_log_level(level)); + log::set_max_level(level); Reply::Success.write_to(stream)?; }, diff --git a/artiq/firmware/satman/Cargo.toml b/artiq/firmware/satman/Cargo.toml index 8ca07b053..82db164f9 100644 --- a/artiq/firmware/satman/Cargo.toml +++ b/artiq/firmware/satman/Cargo.toml @@ -14,7 +14,7 @@ build_misoc = { path = "../libbuild_misoc" } build_artiq = { path = "../libbuild_artiq" } [dependencies] -log = { version = "0.3", default-features = false } +log = { version = "0.4", default-features = false } alloc_list = { path = "../liballoc_list" } board = { path = "../libboard", features = ["uart_console"] } board_artiq = { path = "../libboard_artiq" } From 6d20b71ddeb0a7c203f7443b51a382faa8f5c530 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 2 Jan 2018 12:59:41 +0100 Subject: [PATCH 0147/2457] ttl_serdes_7series: refactor IOSERDES --- artiq/gateware/rtio/phy/ttl_serdes_7series.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_7series.py b/artiq/gateware/rtio/phy/ttl_serdes_7series.py index 266037e1e..8ef6be219 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_7series.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_7series.py @@ -67,19 +67,9 @@ class _IOSERDESE2_8X(Module): pad_i = Signal() pad_o = Signal() - i = self.i - self.specials += Instance("ISERDESE2", p_DATA_RATE="DDR", - p_DATA_WIDTH=8, - p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1, - o_Q1=i[7], o_Q2=i[6], o_Q3=i[5], o_Q4=i[4], - o_Q5=i[3], o_Q6=i[2], o_Q7=i[1], o_Q8=i[0], - i_D=pad_i, - i_CLK=ClockSignal("rtiox4"), - i_CLKB=~ClockSignal("rtiox4"), - i_CE1=1, i_RST=0, - i_CLKDIV=ClockSignal("rio_phy")) + iserdes = _ISERDESE2_8X(pad_i) oserdes = _OSERDESE2_8X(pad_o) - self.submodules += oserdes + self.submodules += iserdes, oserdes if pad_n is None: self.specials += Instance("IOBUF", i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, @@ -89,6 +79,7 @@ class _IOSERDESE2_8X(Module): i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, io_IO=pad, io_IOB=pad_n) self.comb += [ + self.i.eq(iserdes.i), oserdes.t_in.eq(~self.oe), oserdes.o.eq(self.o) ] From 2f8e6c74629da8b663b7cc0fa0cfa3d5bc69bc47 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 2 Jan 2018 11:32:55 +0100 Subject: [PATCH 0148/2457] spi: add diff_term, save power on outputs --- artiq/gateware/spi.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/spi.py b/artiq/gateware/spi.py index 59cc64dbe..3ed4a2159 100644 --- a/artiq/gateware/spi.py +++ b/artiq/gateware/spi.py @@ -238,22 +238,32 @@ class SPIMaster(Module): else: if hasattr(pads, "cs_n"): for i in range(len(pads.cs_n)): - self.specials += Instance("IOBUFDS", + self.specials += Instance("OBUFTDS", i_I=(cs[i] & spi.cs) ^ ~config.cs_polarity, i_T=config.offline, - io_IO=pads.cs_n[i], io_IOB=pads_n.cs_n[i]) + o_O=pads.cs_n[i], o_OB=pads_n.cs_n[i]) - self.specials += Instance("IOBUFDS", + self.specials += Instance("OBUFTDS", i_I=clk, i_T=config.offline, - io_IO=pads.clk, io_IOB=pads_n.clk) + o_O=pads.clk, o_OB=pads_n.clk) mosi = Signal() - self.specials += Instance("IOBUFDS", + self.specials += Instance("IOBUFDS_INTERMDISABLE", + p_DIFF_TERM="TRUE", + p_IBUF_LOW_PWR="FALSE", + p_USE_IBUFDISABLE="TRUE", + i_IBUFDISABLE=config.offline | mosi_oe, + i_INTERMDISABLE=config.offline | mosi_oe, o_O=mosi, i_I=spi.reg.o, i_T=~mosi_oe, io_IO=pads.mosi, io_IOB=pads_n.mosi) if hasattr(pads, "miso"): miso = Signal() - self.specials += Instance("IBUFDS", + self.specials += Instance("IBUFDS_INTERMDISABLE", + p_DIFF_TERM="TRUE", + p_IBUF_LOW_PWR="FALSE", + p_USE_IBUFDISABLE="TRUE", + i_IBUFDISABLE=config.offline, + i_INTERMDISABLE=config.offline, o_O=miso, i_I=pads.miso, i_IB=pads_n.miso) else: miso = mosi From 53969d3686270137cce5d8691fb7dc24817d7174 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 2 Jan 2018 12:01:24 +0100 Subject: [PATCH 0149/2457] kc705_dds: add urukul on vhdci extension definition --- artiq/gateware/targets/kc705_dds.py | 68 +++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/artiq/gateware/targets/kc705_dds.py b/artiq/gateware/targets/kc705_dds.py index 642c0ca44..ce0a4deed 100755 --- a/artiq/gateware/targets/kc705_dds.py +++ b/artiq/gateware/targets/kc705_dds.py @@ -135,6 +135,73 @@ _zotino = [ ) ] + +# FMC DIO 32ch LVDS a v1.2 on HPC to VHDCI-Carrier v1.1 +# uring the upper/right VHDCI connector: LVDS7 and LVDS8 +# using the lower/left VHDCI connector: LVDS3 and LVDS4 +_urukul = [ + ("urukul_spi_p", 0, + Subsignal("clk", Pins("HPC:LA17_CC_P")), + Subsignal("mosi", Pins("HPC:LA16_P")), + Subsignal("miso", Pins("HPC:LA24_P")), + Subsignal("cs_n", Pins("HPC:LA19_P HPC:LA20_P HPC:LA21_P")), + IOStandard("LVDS_25"), + ), + ("urukul_spi_n", 0, + Subsignal("clk", Pins("HPC:LA17_CC_N")), + Subsignal("mosi", Pins("HPC:LA16_N")), + Subsignal("miso", Pins("HPC:LA24_N")), + Subsignal("cs_n", Pins("HPC:LA19_N HPC:LA20_N HPC:LA21_N")), + IOStandard("LVDS_25"), + ), + ("urukul_io_update", 0, + Subsignal("p", Pins("HPC:LA22_P")), + Subsignal("n", Pins("HPC:LA22_N")), + IOStandard("LVDS_25"), + ), + ("urukul_dds_reset", 0, + Subsignal("p", Pins("HPC:LA23_P")), + Subsignal("n", Pins("HPC:LA23_N")), + IOStandard("LVDS_25"), + ), + ("urukul_sync_clk", 0, + Subsignal("p", Pins("HPC:LA18_CC_P")), + Subsignal("n", Pins("HPC:LA18_CC_N")), + IOStandard("LVDS_25"), + ), + ("urukul_sync_in", 0, + Subsignal("p", Pins("HPC:LA25_P")), + Subsignal("n", Pins("HPC:LA25_N")), + IOStandard("LVDS_25"), + ), + ("urukul_io_update_ret", 0, + Subsignal("p", Pins("HPC:LA26_P")), + Subsignal("n", Pins("HPC:LA26_N")), + IOStandard("LVDS_25"), + ), + ("urukul_sw0", 0, + Subsignal("p", Pins("HPC:LA28_P")), + Subsignal("n", Pins("HPC:LA28_N")), + IOStandard("LVDS_25"), + ), + ("urukul_sw1", 0, + Subsignal("p", Pins("HPC:LA29_P")), + Subsignal("n", Pins("HPC:LA29_N")), + IOStandard("LVDS_25"), + ), + ("urukul_sw2", 0, + Subsignal("p", Pins("HPC:LA30_P")), + Subsignal("n", Pins("HPC:LA30_N")), + IOStandard("LVDS_25"), + ), + ("urukul_sw3", 0, + Subsignal("p", Pins("HPC:LA31_P")), + Subsignal("n", Pins("HPC:LA31_N")), + IOStandard("LVDS_25"), + ) +] + + class _NIST_Ions(MiniSoC, AMPSoC): mem_map = { "cri_con": 0x10000000, @@ -170,6 +237,7 @@ class _NIST_Ions(MiniSoC, AMPSoC): self.platform.add_extension(_ams101_dac) self.platform.add_extension(_sdcard_spi_33) self.platform.add_extension(_zotino) + self.platform.add_extension(_urukul) i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) From 94b84ebe7cdb1d2d2f875d5bf8309397e191210c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 2 Jan 2018 12:12:52 +0100 Subject: [PATCH 0150/2457] kc705_dds: add urukul spi/ttl channels --- artiq/examples/master/device_db.py | 51 ++++++++++++++++++++++++++--- artiq/gateware/targets/kc705_dds.py | 11 +++++++ doc/manual/core_device.rst | 48 +++++++++++++++++---------- 3 files changed, 89 insertions(+), 21 deletions(-) diff --git a/artiq/examples/master/device_db.py b/artiq/examples/master/device_db.py index b4c9c70ce..8d0b8c693 100644 --- a/artiq/examples/master/device_db.py +++ b/artiq/examples/master/device_db.py @@ -34,7 +34,7 @@ device_db = { "class": "DDSGroupAD9914", "arguments": { "sysclk": 3e9, - "first_dds_bus_channel": 32, + "first_dds_bus_channel": 39, "dds_bus_count": 2, "dds_channel_count": 3 } @@ -191,25 +191,68 @@ device_db = { "arguments": {"spi_device": "spi_zotino", "ldac_device": "ttl_zotino_ldac"} }, + "spi_urukul": { + "type": "local", + "module": "artiq.coredevice.spi", + "class": "SPIMaster", + "arguments": {"channel": 32} + }, + "ttl_urukul_io_update": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 33} + }, + "ttl_urukul_dds_reset": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 34} + }, + "ttl_urukul_sw0": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 35} + }, + "ttl_urukul_sw1": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 36} + }, + "ttl_urukul_sw2": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 37} + }, + "ttl_urukul_sw3": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 38} + }, + # AD9914 DDS "dds0": { "type": "local", "module": "artiq.coredevice.dds", "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 32, "channel": 0}, + "arguments": {"bus_channel": 39, "channel": 0}, "comment": "Comments work in DDS panel as well" }, "dds1": { "type": "local", "module": "artiq.coredevice.dds", "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 32, "channel": 1} + "arguments": {"bus_channel": 39, "channel": 1} }, "dds2": { "type": "local", "module": "artiq.coredevice.dds", "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 32, "channel": 2} + "arguments": {"bus_channel": 39, "channel": 2} }, # Controllers diff --git a/artiq/gateware/targets/kc705_dds.py b/artiq/gateware/targets/kc705_dds.py index ce0a4deed..47b1fb6f5 100755 --- a/artiq/gateware/targets/kc705_dds.py +++ b/artiq/gateware/targets/kc705_dds.py @@ -353,6 +353,17 @@ class NIST_CLOCK(_NIST_Ions): self.submodules += dac_monitor sdac_phy.probes.extend(dac_monitor.probes) + phy = spi.SPIMaster(self.platform.request("urukul_spi_p"), + self.platform.request("urukul_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + for signal in "io_update dds_reset sw0 sw1 sw2 sw3".split(): + pads = platform.request("urukul_{}".format(signal)) + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + phy = dds.AD9914(platform.request("dds"), 11, onehot=True) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index ed5eaf448..43f787eeb 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -76,28 +76,42 @@ With the CLOCK hardware, the TTL lines are mapped as follows: +--------------------+-----------------------+--------------+ | 31 | ZOTINO_LDAC | Output | +--------------------+-----------------------+--------------+ +| 33 | URUKUL_IO_UPDATE | Output | ++--------------------+-----------------------+--------------+ +| 34 | URUKUL_DDS_RESET | Output | ++--------------------+-----------------------+--------------+ +| 35 | URUKUL_SW0 | Output | ++--------------------+-----------------------+--------------+ +| 36 | URUKUL_SW1 | Output | ++--------------------+-----------------------+--------------+ +| 37 | URUKUL_SW2 | Output | ++--------------------+-----------------------+--------------+ +| 38 | URUKUL_SW3 | Output | ++--------------------+-----------------------+--------------+ The board has RTIO SPI buses mapped as follows: -+--------------+--------------+--------------+--------------+------------+ -| RTIO channel | CS_N | MOSI | MISO | CLK | -+==============+==============+==============+==============+============+ -| 22 | AMS101_CS_N | AMS101_MOSI | | AMS101_CLK | -+--------------+--------------+--------------+--------------+------------+ -| 23 | SPI0_CS_N | SPI0_MOSI | SPI0_MISO | SPI0_CLK | -+--------------+--------------+--------------+--------------+------------+ -| 24 | SPI1_CS_N | SPI1_MOSI | SPI1_MISO | SPI1_CLK | -+--------------+--------------+--------------+--------------+------------+ -| 25 | SPI2_CS_N | SPI2_MOSI | SPI2_MISO | SPI2_CLK | -+--------------+--------------+--------------+--------------+------------+ -| 26 | MMC_SPI_CS_N | MMC_SPI_MOSI | MMC_SPI_MISO | MMC_SPI_CLK| -+--------------+--------------+--------------+--------------+------------+ -| 30 | ZOTINO_CS_N | ZOTINO_MOSI | ZOTINO_MISO | ZOTINO_CLK | -+--------------+--------------+--------------+--------------+------------+ ++--------------+------------------+--------------+--------------+------------+ +| RTIO channel | CS_N | MOSI | MISO | CLK | ++==============+==================+==============+==============+============+ +| 22 | AMS101_CS_N | AMS101_MOSI | | AMS101_CLK | ++--------------+------------------+--------------+--------------+------------+ +| 23 | SPI0_CS_N | SPI0_MOSI | SPI0_MISO | SPI0_CLK | ++--------------+------------------+--------------+--------------+------------+ +| 24 | SPI1_CS_N | SPI1_MOSI | SPI1_MISO | SPI1_CLK | ++--------------+------------------+--------------+--------------+------------+ +| 25 | SPI2_CS_N | SPI2_MOSI | SPI2_MISO | SPI2_CLK | ++--------------+------------------+--------------+--------------+------------+ +| 26 | MMC_SPI_CS_N | MMC_SPI_MOSI | MMC_SPI_MISO | MMC_SPI_CLK| ++--------------+------------------+--------------+--------------+------------+ +| 30 | ZOTINO_CS_N | ZOTINO_MOSI | ZOTINO_MISO | ZOTINO_CLK | ++--------------+------------------+--------------+--------------+------------+ +| 32 | URUKUL_CS_N[0:2] | URUKUL_MOSI | URUKUL_MISO | URUKUL_CLK | ++--------------+------------------+--------------+--------------+------------+ -The DDS bus is on channel 32. +The DDS bus is on channel 39. -This configuration supports a Zotino connected to the KC705 FMC HPC through a FMC DIO 32ch LVDS v1.2 and a VHDCI breakout board rev 1.0. On the VHDCI breakout board, the VHDCI cable to the KC705 should be plugged into to the bottom connector, and the EEM cable to the Zotino should be connected to J41. +This configuration supports a Zotino and/or an Urukul connected to the KC705 FMC HPC through a FMC DIO 32ch LVDS v1.2 and a VHDCI breakout board rev 1.0 or rev 1.1. On the VHDCI breakout board, the VHDCI cable to the KC705 should be plugged into to the bottom connector. The EEM cable to the Zotino should be connected to J41 and the EEM cables to Urukul to J42 and J43. The shift registers on the FMC card should be configured to set the directions of its LVDS buffers, using :mod:`artiq.coredevice.shiftreg`. From 43686f324be38c4458f79fd0ee8d485388955114 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 2 Jan 2018 12:42:52 +0100 Subject: [PATCH 0151/2457] kc705_dds: fix HPC voltages * VADJ is 3.3 V due to the DDS card on LPC * the LVDS standards need to be 2.5 V * the direction control register on HPC (FMC-DIO to VHDCI) was LVCMOS33 but while all the LVDS pairs are at VCCIO=VADJ=3.3 V they were instantiated as LVDS_25 (ignoring the wrongly powered bank) * we now use 2.5 V standards on HPC consistently despite VADJ=3.3 V and hope for the best. --- artiq/gateware/targets/kc705_dds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kc705_dds.py b/artiq/gateware/targets/kc705_dds.py index 47b1fb6f5..f990a39f6 100755 --- a/artiq/gateware/targets/kc705_dds.py +++ b/artiq/gateware/targets/kc705_dds.py @@ -112,7 +112,7 @@ _zotino = [ Subsignal("clk", Pins("HPC:LA32_N")), Subsignal("ser", Pins("HPC:LA33_P")), Subsignal("latch", Pins("HPC:LA32_P")), - IOStandard("LVCMOS33") + IOStandard("LVCMOS25") ), ("zotino_spi_p", 0, Subsignal("clk", Pins("HPC:LA08_P")), From c2be820e9a680820d357accc40f486afdbfba9a6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 2 Jan 2018 17:38:11 +0000 Subject: [PATCH 0152/2457] kc705_dds: make ext_clkout 100 MHz --- artiq/gateware/targets/kc705_dds.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/kc705_dds.py b/artiq/gateware/targets/kc705_dds.py index f990a39f6..62fab2427 100755 --- a/artiq/gateware/targets/kc705_dds.py +++ b/artiq/gateware/targets/kc705_dds.py @@ -29,12 +29,11 @@ class _RTIOCRG(Module, AutoCSR): self.clock_domains.cd_rtio = ClockDomain() self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) - # 10 MHz when using 125MHz input + # 100 MHz when using 125MHz input self.clock_domains.cd_ext_clkout = ClockDomain(reset_less=True) ext_clkout = platform.request("user_sma_gpio_p_33") self.sync.ext_clkout += ext_clkout.eq(~ext_clkout) - rtio_external_clk = Signal() user_sma_clock = platform.request("user_sma_clock") platform.add_period_constraint(user_sma_clock.p, 8.0) @@ -66,7 +65,7 @@ class _RTIOCRG(Module, AutoCSR): p_CLKOUT0_DIVIDE=2, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=rtiox4_clk, - p_CLKOUT1_DIVIDE=50, p_CLKOUT1_PHASE=0.0, + p_CLKOUT1_DIVIDE=5, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=ext_clkout_clk), Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk), Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), From a940550e4755f92c96408acfd560099e2e2ee3ed Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 2 Jan 2018 14:52:13 +0100 Subject: [PATCH 0153/2457] urukul: add CPLD and AD9912 driver [wip] --- artiq/coredevice/ad9912.py | 131 ++++++++++---- artiq/coredevice/urukul.py | 162 ++++++++++++++++++ artiq/examples/master/device_db.py | 55 ++++++ .../coredevice_examples/simple/urukul.py | 72 ++++++++ 4 files changed, 386 insertions(+), 34 deletions(-) create mode 100644 artiq/coredevice/urukul.py create mode 100644 artiq/examples/master/repository/coredevice_examples/simple/urukul.py diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 10b360806..4b522c54e 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -3,53 +3,116 @@ Driver for the AD9912 DDS. """ -from artiq.language.core import kernel, delay_mu -from artiq.language.units import ns, us -from artiq.coredevice import spi +from artiq.language.core import kernel, delay_mu, delay +from artiq.language.units import us, ns +from artiq.coredevice import spi, urukul +from artiq.coredevice.ad9912_reg import * - -_AD9912_SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_CS_POLARITY | - 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | - 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) +from numpy import int32, int64 class AD9912: """ Support for the Analog devices AD9912 DDS - :param spi_device: Name of the SPI bus this device is on. - :param chip_select: Value to drive on the chip select lines - during transactions. + :param chip_select: Chip select configuration. + :param cpld_device: Name of the Urukul CPLD this device is on. + :param sw_device: Name of the RF switch device. """ + kernel_invariants = {"chip_select", "cpld", "core", "bus", "sw", + "ftw_per_hz", "sysclk", "pll_n"} - def __init__(self, dmgr, spi_device, chip_select): - self.core = dmgr.get("core") - self.bus = dmgr.get(spi_device) + def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, + pll_n=10): + self.cpld = dmgr.get(cpld_device) + self.core = self.cpld.core + self.bus = self.cpld.bus + assert chip_select >= 4 self.chip_select = chip_select + if sw_device: + self.sw = dmgr.get(sw_device) + self.pll_n = pll_n + self.sysclk = self.cpld.refclk * pll_n + self.ftw_per_hz = 1/self.sysclk*(int64(1) << 48) @kernel - def setup_bus(self, write_div=5, read_div=20): - """Configure the SPI bus and the SPI transaction parameters - for this device. This method has to be called before any other method - if the bus has been used to access a different device in the meantime. - - This method advances the timeline by the duration of two - RTIO-to-Wishbone bus transactions. - - :param write_div: Write clock divider. - :param read_div: Read clock divider. - """ - # write: 5*8ns >= 40ns = t_clk (typ clk rate) - # read: 2*8*ns >= 25ns = t_dv (clk falling to miso valid) + RTT - self.bus.set_config_mu(_AD9912_SPI_CONFIG, write_div, read_div) - self.bus.set_xfer(self.chip_select, 24, 0) + def write(self, addr, data, length=1): + assert length > 0 + assert length <= 4 + self.bus.set_xfer(self.chip_select, 16, 0) + self.bus.write((addr | ((length - 1) << 13)) << 16) + delay_mu(-self.bus.xfer_period_mu) + self.bus.set_xfer(self.chip_select, length*8, 0) + if length < 4: + data <<= 32 - length*8 + self.bus.write(data) + delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu) @kernel - def write(self, data): - """Write 24 bits of data. + def read(self, addr, length=1): + assert length > 0 + assert length <= 4 + self.bus.set_xfer(self.chip_select, 16, 0) + self.bus.write((addr | ((length - 1) << 13) | 0x8000) << 16) + delay_mu(-self.bus.xfer_period_mu) + self.bus.set_xfer(self.chip_select, 0, length*8) + self.bus.write(0) + delay_mu(2*self.bus.xfer_period_mu) + data = self.bus.read_sync() + if length < 4: + data &= (1 << (length*8)) - 1 + return data - This method advances the timeline by the duration of the SPI transfer - and the required CS high time. + @kernel + def init(self): + t = now_mu() + self.write(AD9912_SER_CONF, 0x99) + prodid = self.read(AD9912_PRODIDH, length=2) + assert (prodid == 0x1982) or (prodid == 0x1902) + delay(10*us) + self.write(AD9912_PWRCNTRL1, 0x80) # HSTL, CMOS power down + delay(10*us) + self.write(AD9912_N_DIV, self.pll_n//2 - 2) + delay(10*us) + self.write(AD9912_PLLCFG, 0b00000101) # 375 µA, high range + at_mu(t) + delay(100*us) + + @kernel + def set_att_mu(self, att): + self.cpld.set_att_mu(self.chip_select - 4, att) + + @kernel + def set_att(self, att): + self.cpld.set_att(self.chip_select - 4, att) + + @kernel + def set_mu(self, ftw=int64(0), pow=int32(0)): + # do a streaming transfer of FTW and POW + self.bus.set_xfer(self.chip_select, 16, 0) + self.bus.write((AD9912_POW1 << 16) | (3 << 29)) + delay_mu(-self.bus.xfer_period_mu) + self.bus.set_xfer(self.chip_select, 32, 0) + self.bus.write((pow << 16) | int32(ftw >> 32)) + self.bus.write(int32(ftw)) + delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu) + self.cpld.io_update.pulse(10*ns) + + @portable(flags={"fast-math"}) + def frequency_to_ftw(self, frequency): + """Returns the frequency tuning word corresponding to the given + frequency. """ - self.bus.write(data << 8) - delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high + return int64(round(self.ftw_per_hz*frequency)) + + @portable(flags={"fast-math"}) + def turns_to_pow(self, phase): + """Returns the phase offset word corresponding to the given + phase. + """ + return int32(round((1 << 16)*phase)) + + @kernel + def set(self, frequency, phase=0.0): + self.set_mu(self.frequency_to_ftw(frequency), + self.turns_to_pow(phase)) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py new file mode 100644 index 000000000..750993eed --- /dev/null +++ b/artiq/coredevice/urukul.py @@ -0,0 +1,162 @@ +from artiq.language.core import kernel, delay_mu, delay, now_mu, at_mu +from artiq.language.units import us + +from numpy import int32, int64 + +from artiq.coredevice import spi + + +_SPI_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_CS_POLARITY | + 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | + 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) + +# SPI clock write and read dividers +_SPIT_CFG_WR = 2 +_SPIT_CFG_RD = 16 +_SPIT_ATT_WR = 2 +_SPIT_ATT_RD = 16 +_SPIT_DDS_WR = 16 +_SPIT_DDS_RD = 16 + +# CFG configuration register bit offsets +CFG_RF_SW = 0 +CFG_LED = 4 +CFG_PROFILE = 8 +CFG_ATT_LE = 11 +CFG_IO_UPDATE = 12 +CFG_MASK_NU = 16 +CFG_CLK_SEL = 17 +CFG_SYNC_SEL = 18 +CFG_RST = 19 +CFG_IO_RST = 20 + + +@kernel +def urukul_cfg(rf_sw, led, profile, att_le, io_update, mask_nu, + clk_sel, sync_sel, rst, io_rst): + return ((rf_sw << CFG_RF_SW) | (led << CFG_LED) | + (profile << CFG_PROFILE) | (att_le << CFG_ATT_LE) | + (io_update << CFG_IO_UPDATE) | (mask_nu << CFG_MASK_NU) | + (clk_sel << CFG_CLK_SEL) | (sync_sel << CFG_SYNC_SEL) | + (rst << CFG_RST) | (io_rst << CFG_IO_RST)) + + +# STA status register bit offsets +STA_RF_SW = 0 +STA_SMP_ERR = 4 +STA_PLL_LOCK = 8 +STA_IFC_MODE = 12 +STA_PROTO_REV = 16 + + +@kernel +def urukul_sta_rf_sw(sta): + return (sta >> STA_RF_SW) & 0xf + + +@kernel +def urukul_sta_smp_err(sta): + return (sta >> STA_SMP_ERR) & 0xf + + +@kernel +def urukul_sta_pll_lock(sta): + return (sta >> STA_PLL_LOCK) & 0xf + + +@kernel +def urukul_sta_ifc_mode(sta): + return (sta >> STA_IFC_MODE) & 0xf + + +@kernel +def urukul_sta_proto_rev(sta): + return (sta >> STA_PROTO_REV) & 0xff + + +# supported hardware and CPLD code version +STA_PROTO_REV_MATCH = 0x06 + +# chip select (decoded) +CS_CFG = 1 +CS_ATT = 2 +CS_DDS_MULTI = 3 +CS_DDS_CH0 = 4 +CS_DDS_CH1 = 5 +CS_DDS_CH2 = 6 +CS_DDS_CH3 = 7 + + +class CPLD: + def __init__(self, dmgr, spi_device, io_update_device, dds_reset_device, + refclk=100e6, core_device="core"): + + self.core = dmgr.get(core_device) + self.refclk = refclk + + self.bus = dmgr.get(spi_device) + self.io_update = dmgr.get(io_update_device) + if dds_reset_device is not None: + self.dds_reset = dmgr.get(dds_reset_device) + + self.cfg_reg = int32(0) + self.att_reg = int32(0) + + @kernel + def cfg_write(self, cfg_reg): + self.bus.set_config_mu(_SPI_CONFIG, _SPIT_CFG_WR, _SPIT_CFG_RD) + self.bus.set_xfer(CS_CFG, 24, 0) + self.bus.write(cfg_reg << 8) + self.bus.set_config_mu(_SPI_CONFIG, _SPIT_DDS_WR, _SPIT_DDS_RD) + self.cfg_reg = cfg_reg + + @kernel + def sta_read(self): + self.bus.set_config_mu(_SPI_CONFIG, _SPIT_CFG_WR, _SPIT_CFG_RD) + self.bus.set_xfer(CS_CFG, 0, 24) + self.bus.write(self.cfg_reg << 8) + self.bus.set_config_mu(_SPI_CONFIG, _SPIT_DDS_WR, _SPIT_DDS_RD) + return self.bus.read_sync() + + @kernel + def init(self, clk_sel=0, sync_sel=0): + t = now_mu() + cfg = urukul_cfg(rf_sw=0, led=0, profile=0, att_le=0, + io_update=0, mask_nu=0, clk_sel=clk_sel, + sync_sel=sync_sel, rst=0, io_rst=0) + self.cfg_write(cfg | (1 << CFG_RST)) + self.cfg_write(cfg) + proto_rev = urukul_sta_proto_rev(self.sta_read()) + if proto_rev != STA_PROTO_REV_MATCH: + raise ValueError("Urukul proto_rev mismatch") + at_mu(t) + delay(100*us) + + @kernel + def cfg_sw(self, sw, on): + c = self.cfg_reg + if on: + c |= 1 << sw + else: + c &= ~(1 << sw) + self.write_cfg(c) + + @kernel + def set_att_mu(self, channel, att): + """ + Parameters: + att (int): 0-255, 255 minimum attenuation, + 0 maximum attenuation (31.5 dB) + """ + a = self.att_reg & ~(0xff << (channel * 8)) + a |= att << (channel * 8) + self.att_reg = a + self.bus.set_config_mu(_SPI_CONFIG, _SPIT_ATT_WR, _SPIT_ATT_RD) + self.bus.set_xfer(CS_ATT, 32, 0) + self.bus.write(a) + self.cfg_write(self.cfg_reg | (1 << CFG_ATT_LE)) + self.cfg_write(self.cfg_reg & ~(1 << CFG_ATT_LE)) + + @kernel + def set_att(self, channel, att): + self.set_att_mu(channel, 255 - int32(round(att*8))) diff --git a/artiq/examples/master/device_db.py b/artiq/examples/master/device_db.py index 8d0b8c693..da3f55707 100644 --- a/artiq/examples/master/device_db.py +++ b/artiq/examples/master/device_db.py @@ -233,6 +233,61 @@ device_db = { "class": "TTLOut", "arguments": {"channel": 38} }, + "urukul_cpld": { + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul", + "io_update_device": "ttl_urukul_io_update", + "dds_reset_device": "ttl_urukul_dds_reset", + "refclk": 100e6 + } + }, + "urukul_ch0": { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 4, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw0" + } + }, + "urukul_ch1": { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 5, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw1" + } + }, + "urukul_ch2": { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 6, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw2" + } + }, + "urukul_ch3": { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 7, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw3" + } + }, # AD9914 DDS "dds0": { diff --git a/artiq/examples/master/repository/coredevice_examples/simple/urukul.py b/artiq/examples/master/repository/coredevice_examples/simple/urukul.py new file mode 100644 index 000000000..8b8958a6c --- /dev/null +++ b/artiq/examples/master/repository/coredevice_examples/simple/urukul.py @@ -0,0 +1,72 @@ +from artiq.experiment import * + + +class UrukulTest(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("fmcdio_dirctl") + self.setattr_device("urukul_cpld") + self.setattr_device("urukul_ch0") + self.setattr_device("urukul_ch1") + self.setattr_device("urukul_ch2") + self.setattr_device("urukul_ch3") + self.setattr_device("led") + + def p(self, f, *a): + print(f % a) + + @kernel + def run(self): + self.core.reset() + self.led.on() + delay(5*ms) + # Zotino plus Urukul (MISO, IO_UPDATE_RET) + self.fmcdio_dirctl.set(0x0A008800) + self.led.off() + + self.urukul_cpld.init(clk_sel=1) + self.urukul_ch0.init() + self.urukul_ch1.init() + self.urukul_ch2.init() + self.urukul_ch3.init() + delay(100*us) + + self.urukul_ch0.set(10*MHz) + self.urukul_ch0.sw.on() + self.urukul_ch0.set_att(10.) + + delay(100*us) + self.urukul_ch1.set(10*MHz, 0.5) + self.urukul_ch1.sw.on() + self.urukul_ch1.set_att(10.) + + delay(100*us) + self.urukul_ch2.set(400*MHz) + self.urukul_ch2.sw.on() + self.urukul_ch2.set_att(0.) + + delay(100*us) + self.urukul_ch3.set(1*MHz) + self.urukul_ch3.sw.on() + self.urukul_ch3.set_att(0.) + + while True: + self.urukul_ch0.set_mu(0x123456789abc, 0) + + while True: + self.urukul_ch0.sw.pulse(5*ms) + delay(5*ms) + + while False: + self.led.pulse(.5*s) + delay(.5*s) + + @kernel + def test_att_noise(self, n=1024): + bus = self.urukul_cpld.bus + bus.set_config_mu(_SPI_CONFIG, _SPIT_ATT_WR, _SPIT_ATT_RD) + bus.set_xfer(CS_ATT, 32, 0) + for i in range(n): + delay(5*us) + bus.write(self.att_reg) + bus.set_config_mu(_SPI_CONFIG, _SPIT_DDS_WR, _SPIT_DDS_RD) From 08dada9e16a1db01859a440ef5082a55936ed823 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 3 Jan 2018 09:14:35 +0100 Subject: [PATCH 0154/2457] artiq-dev: bump misoc (spi logic fold) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index d554e8c7c..d0aae5048 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6.dev py35_61+git31c446b - - misoc 0.8.dev py35_46+git1dc68b0d + - misoc 0.8.dev py35_52+gitddbf9cbd - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From 7f4756a8693ef965664a36bbd9544fad72e85ad9 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 3 Jan 2018 17:30:12 +0100 Subject: [PATCH 0155/2457] gateware/serwb: cleanup packet --- artiq/gateware/serwb/packet.py | 77 +++++++++++++++++----------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/artiq/gateware/serwb/packet.py b/artiq/gateware/serwb/packet.py index c7650087a..f22e2d944 100644 --- a/artiq/gateware/serwb/packet.py +++ b/artiq/gateware/serwb/packet.py @@ -89,34 +89,31 @@ class Packetizer(Module): # - length : 4 bytes # - payload - fsm = FSM(reset_state="IDLE") + fsm = FSM(reset_state="PREAMBLE") self.submodules += fsm - fsm.act("IDLE", + fsm.act("PREAMBLE", If(sink.stb, - NextState("INSERT_PREAMBLE") + source.stb.eq(1), + source.data.eq(0x5aa55aa5), + If(source.ack, + NextState("LENGTH") + ) ) ) - fsm.act("INSERT_PREAMBLE", - source.stb.eq(1), - source.data.eq(0x5aa55aa5), - If(source.ack, - NextState("INSERT_LENGTH") - ) - ) - fsm.act("INSERT_LENGTH", + fsm.act("LENGTH", source.stb.eq(1), source.data.eq(sink.length), If(source.ack, - NextState("COPY") + NextState("DATA") ) ) - fsm.act("COPY", + fsm.act("DATA", source.stb.eq(sink.stb), source.data.eq(sink.data), sink.ack.eq(source.ack), If(source.ack & sink.eop, - NextState("IDLE") + NextState("PREAMBLE") ) ) @@ -128,45 +125,49 @@ class Depacketizer(Module): # # # + count = Signal(len(source.length)) + length = Signal(len(source.length)) + # Packet description # - preamble : 4 bytes # - length : 4 bytes # - payload - fsm = FSM(reset_state="IDLE") + fsm = FSM(reset_state="PREAMBLE") self.submodules += fsm - self.submodules.timer = WaitTimer(clk_freq*timeout) - self.comb += self.timer.wait.eq(~fsm.ongoing("IDLE")) + timer = WaitTimer(clk_freq*timeout) + self.submodules += timer - fsm.act("IDLE", + fsm.act("PREAMBLE", sink.ack.eq(1), - If(sink.stb & (sink.data == 0x5aa55aa5), - NextState("RECEIVE_LENGTH") + If(sink.stb & + (sink.data == 0x5aa55aa5), + NextState("LENGTH") ) ) - fsm.act("RECEIVE_LENGTH", + fsm.act("LENGTH", sink.ack.eq(1), If(sink.stb, - NextValue(source.length, sink.data), - NextState("COPY") - ) + NextValue(count, 0), + NextValue(length, sink.data), + NextState("DATA") + ), + timer.wait.eq(1) ) - eop = Signal() - cnt = Signal(32) - fsm.act("COPY", + fsm.act("DATA", source.stb.eq(sink.stb), - source.eop.eq(eop), + source.eop.eq(count == (length[2:] - 1)), + source.length.eq(length), source.data.eq(sink.data), sink.ack.eq(source.ack), - If((source.stb & source.ack & eop) | self.timer.done, - NextState("IDLE") - ) - ) - self.sync += \ - If(fsm.ongoing("IDLE"), - cnt.eq(0) + If(timer.done, + NextState("PREAMBLE") ).Elif(source.stb & source.ack, - cnt.eq(cnt + 1) - ) - self.comb += eop.eq(cnt == source.length[2:] - 1) + NextValue(count, count + 1), + If(source.eop, + NextState("PREAMBLE") + ) + ), + timer.wait.eq(1) + ) From 907af25a697e9867b0253488ea2e7a5e7f4e89f0 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 3 Jan 2018 17:32:18 +0100 Subject: [PATCH 0156/2457] gateware/serwb: add scrambling, reduce cdc fifo depth --- artiq/gateware/serwb/core.py | 54 +++++++++++------ artiq/gateware/serwb/kusphy.py | 21 ++++--- artiq/gateware/serwb/phy.py | 1 + artiq/gateware/serwb/s7phy.py | 21 ++++--- artiq/gateware/serwb/scrambler.py | 99 +++++++++++++++++++++++++++++++ 5 files changed, 163 insertions(+), 33 deletions(-) create mode 100644 artiq/gateware/serwb/scrambler.py diff --git a/artiq/gateware/serwb/core.py b/artiq/gateware/serwb/core.py index 61c76a884..4e190e03b 100644 --- a/artiq/gateware/serwb/core.py +++ b/artiq/gateware/serwb/core.py @@ -2,38 +2,54 @@ from migen import * from misoc.interconnect import stream -from artiq.gateware.serwb.packet import Depacketizer, Packetizer +from artiq.gateware.serwb.scrambler import Scrambler, Descrambler +from artiq.gateware.serwb.packet import Packetizer, Depacketizer from artiq.gateware.serwb.etherbone import Etherbone class SERWBCore(Module): - def __init__(self, phy, clk_freq, mode): + def __init__(self, phy, clk_freq, mode, with_scrambling=False): + # etherbone self.submodules.etherbone = etherbone = Etherbone(mode) + + # packetizer / depacketizer depacketizer = Depacketizer(clk_freq) packetizer = Packetizer() self.submodules += depacketizer, packetizer - tx_cdc = stream.AsyncFIFO([("data", 32)], 32) - tx_cdc = ClockDomainsRenamer({"write": "sys", "read": "serwb_serdes"})(tx_cdc) - self.submodules += tx_cdc - rx_cdc = stream.AsyncFIFO([("data", 32)], 32) - rx_cdc = ClockDomainsRenamer({"write": "serwb_serdes", "read": "sys"})(rx_cdc) - self.submodules += rx_cdc - self.comb += [ - # core <--> etherbone - depacketizer.source.connect(etherbone.sink), - etherbone.source.connect(packetizer.sink), - # core --> serdes + # clock domain crossing + tx_cdc = stream.AsyncFIFO([("data", 32)], 16) + tx_cdc = ClockDomainsRenamer({"write": "sys", "read": phy.cd})(tx_cdc) + rx_cdc = stream.AsyncFIFO([("data", 32)], 16) + rx_cdc = ClockDomainsRenamer({"write": phy.cd, "read": "sys"})(rx_cdc) + self.submodules += tx_cdc, rx_cdc + + # scrambling + scrambler = ClockDomainsRenamer(phy.cd)(Scrambler(enable=with_scrambling)) + descrambler = ClockDomainsRenamer(phy.cd)(Descrambler(enable=with_scrambling)) + self.submodules += scrambler, descrambler + + # modules connection + self.comb += [ + # core --> phy packetizer.source.connect(tx_cdc.sink), + tx_cdc.source.connect(scrambler.sink), If(phy.init.ready, - If(tx_cdc.source.stb, - phy.serdes.tx_data.eq(tx_cdc.source.data) + If(scrambler.source.stb, + phy.serdes.tx_k.eq(scrambler.source.k), + phy.serdes.tx_d.eq(scrambler.source.d) ), - tx_cdc.source.ack.eq(1) + scrambler.source.ack.eq(1) ), - # serdes --> core - rx_cdc.sink.stb.eq(phy.init.ready), - rx_cdc.sink.data.eq(phy.serdes.rx_data), + # phy --> core + descrambler.sink.stb.eq(phy.init.ready), + descrambler.sink.k.eq(phy.serdes.rx_k), + descrambler.sink.d.eq(phy.serdes.rx_d), + descrambler.source.connect(rx_cdc.sink), rx_cdc.source.connect(depacketizer.sink), + + # etherbone <--> core + depacketizer.source.connect(etherbone.sink), + etherbone.source.connect(packetizer.sink) ] diff --git a/artiq/gateware/serwb/kusphy.py b/artiq/gateware/serwb/kusphy.py index f4fd6cd6c..51a08a6d8 100644 --- a/artiq/gateware/serwb/kusphy.py +++ b/artiq/gateware/serwb/kusphy.py @@ -8,8 +8,10 @@ from misoc.cores.code_8b10b import Encoder, Decoder class KUSSerdes(Module): def __init__(self, pll, pads, mode="master"): - self.tx_data = Signal(32) - self.rx_data = Signal(32) + self.tx_k = Signal(4) + self.tx_d = Signal(32) + self.rx_k = Signal(4) + self.rx_d = Signal(32) self.tx_idle = Signal() self.tx_comma = Signal() @@ -111,10 +113,14 @@ class KUSSerdes(Module): self.encoder.k[0].eq(1), self.encoder.d[0].eq(0xbc) ).Else( - self.encoder.d[0].eq(self.tx_data[0:8]), - self.encoder.d[1].eq(self.tx_data[8:16]), - self.encoder.d[2].eq(self.tx_data[16:24]), - self.encoder.d[3].eq(self.tx_data[24:32]) + self.encoder.k[0].eq(self.tx_k[0]), + self.encoder.k[1].eq(self.tx_k[1]), + self.encoder.k[2].eq(self.tx_k[2]), + self.encoder.k[3].eq(self.tx_k[3]), + self.encoder.d[0].eq(self.tx_d[0:8]), + self.encoder.d[1].eq(self.tx_d[8:16]), + self.encoder.d[2].eq(self.tx_d[16:24]), + self.encoder.d[3].eq(self.tx_d[24:32]) ) ] self.sync.serwb_serdes += \ @@ -217,7 +223,8 @@ class KUSSerdes(Module): self.decoders[1].input.eq(self.rx_bitslip.o[10:20]), self.decoders[2].input.eq(self.rx_bitslip.o[20:30]), self.decoders[3].input.eq(self.rx_bitslip.o[30:40]), - self.rx_data.eq(Cat(*[self.decoders[i].d for i in range(4)])), + self.rx_k.eq(Cat(*[self.decoders[i].k for i in range(4)])), + self.rx_d.eq(Cat(*[self.decoders[i].d for i in range(4)])), rx_idle.eq(self.rx_bitslip.o == 0), rx_comma.eq(((self.decoders[0].d == 0xbc) & (self.decoders[0].k == 1)) & ((self.decoders[1].d == 0x00) & (self.decoders[1].k == 0)) & diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index d48084116..556b53709 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -376,6 +376,7 @@ class SERWBPLL(Module): class SERWBPHY(Module, AutoCSR): + cd = "serwb_serdes" def __init__(self, device, pll, pads, mode="master"): assert mode in ["master", "slave"] if device[:4] == "xcku": diff --git a/artiq/gateware/serwb/s7phy.py b/artiq/gateware/serwb/s7phy.py index d64f5bbb5..f21d39a4b 100644 --- a/artiq/gateware/serwb/s7phy.py +++ b/artiq/gateware/serwb/s7phy.py @@ -8,8 +8,10 @@ from misoc.cores.code_8b10b import Encoder, Decoder class S7Serdes(Module): def __init__(self, pll, pads, mode="master"): - self.tx_data = Signal(32) - self.rx_data = Signal(32) + self.tx_k = Signal(4) + self.tx_d = Signal(32) + self.rx_k = Signal(4) + self.rx_d = Signal(32) self.tx_idle = Signal() self.tx_comma = Signal() @@ -99,10 +101,14 @@ class S7Serdes(Module): self.encoder.k[0].eq(1), self.encoder.d[0].eq(0xbc) ).Else( - self.encoder.d[0].eq(self.tx_data[0:8]), - self.encoder.d[1].eq(self.tx_data[8:16]), - self.encoder.d[2].eq(self.tx_data[16:24]), - self.encoder.d[3].eq(self.tx_data[24:32]) + self.encoder.k[0].eq(self.tx_k[0]), + self.encoder.k[1].eq(self.tx_k[1]), + self.encoder.k[2].eq(self.tx_k[2]), + self.encoder.k[3].eq(self.tx_k[3]), + self.encoder.d[0].eq(self.tx_d[0:8]), + self.encoder.d[1].eq(self.tx_d[8:16]), + self.encoder.d[2].eq(self.tx_d[16:24]), + self.encoder.d[3].eq(self.tx_d[24:32]) ) ] self.sync.serwb_serdes += \ @@ -213,7 +219,8 @@ class S7Serdes(Module): self.decoders[1].input.eq(self.rx_bitslip.o[10:20]), self.decoders[2].input.eq(self.rx_bitslip.o[20:30]), self.decoders[3].input.eq(self.rx_bitslip.o[30:40]), - self.rx_data.eq(Cat(*[self.decoders[i].d for i in range(4)])), + self.rx_k.eq(Cat(*[self.decoders[i].k for i in range(4)])), + self.rx_d.eq(Cat(*[self.decoders[i].d for i in range(4)])), rx_idle.eq(self.rx_bitslip.o == 0), rx_comma.eq(((self.decoders[0].d == 0xbc) & (self.decoders[0].k == 1)) & ((self.decoders[1].d == 0x00) & (self.decoders[1].k == 0)) & diff --git a/artiq/gateware/serwb/scrambler.py b/artiq/gateware/serwb/scrambler.py new file mode 100644 index 000000000..83f8b5a55 --- /dev/null +++ b/artiq/gateware/serwb/scrambler.py @@ -0,0 +1,99 @@ +from functools import reduce +from operator import xor + +from migen import * + +from misoc.interconnect import stream + + +def K(x, y): + return (y << 5) | x + + +@ResetInserter() +class _Scrambler(Module): + def __init__(self, n_io, n_state=23, taps=[17, 22]): + self.i = Signal(n_io) + self.o = Signal(n_io) + + # # # + + state = Signal(n_state, reset=1) + curval = [state[i] for i in range(n_state)] + for i in reversed(range(n_io)): + flip = reduce(xor, [curval[tap] for tap in taps]) + self.comb += self.o[i].eq(flip ^ self.i[i]) + curval.insert(0, flip) + curval.pop() + + self.sync += state.eq(Cat(*curval[:n_state])) + + +class Scrambler(Module): + def __init__(self, sync_interval=1024, enable=True): + self.sink = sink = stream.Endpoint([("data", 32)]) + self.source = source = stream.Endpoint([("d", 32), ("k", 4)]) + + # # # + + if enable: + # scrambler + scrambler = _Scrambler(32) + self.submodules += scrambler + self.comb += scrambler.i.eq(sink.data) + + # insert K.29.7 as sync character + # every sync_interval cycles + count = Signal(max=sync_interval) + self.sync += count.eq(count + 1) + self.comb += [ + If(count == 0, + scrambler.reset.eq(1), + source.stb.eq(1), + source.k[0].eq(1), + source.d[:8].eq(K(29, 7)) + ).Else( + sink.ack.eq(source.ack), + source.stb.eq(sink.stb), + source.d.eq(scrambler.o) + ) + ] + else: + self.comb += [ + sink.connect(source, omit={"data"}), + source.k.eq(0b0000), + source.d.eq(sink.data) + ] + + +class Descrambler(Module): + def __init__(self, enable=True): + self.sink = sink = stream.Endpoint([("d", 32), ("k", 4)]) + self.source = source = stream.Endpoint([("data", 32)]) + + # # # + + if enable: + # descrambler + descrambler = _Scrambler(32) + self.submodules += descrambler + self.comb += descrambler.i.eq(sink.d) + + # detect K29.7 and synchronize descrambler + self.comb += [ + descrambler.reset.eq(0), + If((sink.k[0] == 1) & + (sink.d[:8] == K(29,7)), + sink.ack.eq(1), + descrambler.reset.eq(1) + ).Else( + sink.ack.eq(source.ack), + source.stb.eq(sink.stb), + source.data.eq(descrambler.o) + ) + ] + else: + self.comb += [ + sink.connect(source, omit={"d", "k"}), + source.data.eq(sink.d) + ] From 1e972034e83357ad8f42b72e0cde40554cc654cd Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 3 Jan 2018 17:34:46 +0100 Subject: [PATCH 0157/2457] gateware/targets: enable serwb scrambling on sayma amc & rtm --- artiq/gateware/targets/sayma_amc_standalone.py | 2 +- artiq/gateware/targets/sayma_rtm.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc_standalone.py b/artiq/gateware/targets/sayma_amc_standalone.py index 1c732281d..7a4de3d3c 100755 --- a/artiq/gateware/targets/sayma_amc_standalone.py +++ b/artiq/gateware/targets/sayma_amc_standalone.py @@ -168,7 +168,7 @@ class Standalone(MiniSoC, AMPSoC): serwb_phy_amc.serdes.cd_serwb_serdes.clk, serwb_phy_amc.serdes.cd_serwb_serdes_5x.clk) - serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave") + serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave", with_scrambling=True) self.submodules += serwb_core self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index df9206dc5..0632592b1 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -159,7 +159,7 @@ class SaymaRTM(Module): serwb_phy_rtm.serdes.cd_serwb_serdes.clk, serwb_phy_rtm.serdes.cd_serwb_serdes_5x.clk) - serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master") + serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master", with_scrambling=True) self.submodules += serwb_core # process CSR devices and connect them to serwb From e8608d12f5b56634278442621f072d07d0be8194 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 3 Jan 2018 12:00:19 +0000 Subject: [PATCH 0158/2457] device_db.py: whitespace --- artiq/examples/master/device_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/master/device_db.py b/artiq/examples/master/device_db.py index da3f55707..95ec6a482 100644 --- a/artiq/examples/master/device_db.py +++ b/artiq/examples/master/device_db.py @@ -124,7 +124,7 @@ device_db = { "class": "SPIMaster", "arguments": {"channel": 23} }, - "spi_mmc": { + "spi_mmc": { "type": "local", "module": "artiq.coredevice.spi", "class": "SPIMaster", From d8dbab024dac7762471bf0b48ed672fc4c624a02 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 3 Jan 2018 15:49:56 +0000 Subject: [PATCH 0159/2457] urukul: don't deal with dds_reset for now --- artiq/coredevice/urukul.py | 3 ++- artiq/examples/master/device_db.py | 7 ------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 750993eed..9d8caed20 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -88,7 +88,8 @@ CS_DDS_CH3 = 7 class CPLD: - def __init__(self, dmgr, spi_device, io_update_device, dds_reset_device, + def __init__(self, dmgr, spi_device, io_update_device, + dds_reset_device=None, refclk=100e6, core_device="core"): self.core = dmgr.get(core_device) diff --git a/artiq/examples/master/device_db.py b/artiq/examples/master/device_db.py index 95ec6a482..b9b38188d 100644 --- a/artiq/examples/master/device_db.py +++ b/artiq/examples/master/device_db.py @@ -203,12 +203,6 @@ device_db = { "class": "TTLOut", "arguments": {"channel": 33} }, - "ttl_urukul_dds_reset": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 34} - }, "ttl_urukul_sw0": { "type": "local", "module": "artiq.coredevice.ttl", @@ -240,7 +234,6 @@ device_db = { "arguments": { "spi_device": "spi_urukul", "io_update_device": "ttl_urukul_io_update", - "dds_reset_device": "ttl_urukul_dds_reset", "refclk": 100e6 } }, From cef40eef432e7915df4a36f4619e96861b0cbdd7 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 3 Jan 2018 18:28:36 +0000 Subject: [PATCH 0160/2457] ad9912: clean up --- artiq/coredevice/ad9912.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 4b522c54e..77e78d568 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -1,11 +1,5 @@ -""" -Driver for the AD9912 DDS. -""" - - -from artiq.language.core import kernel, delay_mu, delay +from artiq.language.core import kernel, delay_mu, delay, portable from artiq.language.units import us, ns -from artiq.coredevice import spi, urukul from artiq.coredevice.ad9912_reg import * from numpy import int32, int64 @@ -13,7 +7,7 @@ from numpy import int32, int64 class AD9912: """ - Support for the Analog devices AD9912 DDS + Support for the AD9912 DDS on Urukul :param chip_select: Chip select configuration. :param cpld_device: Name of the Urukul CPLD this device is on. @@ -32,7 +26,7 @@ class AD9912: if sw_device: self.sw = dmgr.get(sw_device) self.pll_n = pll_n - self.sysclk = self.cpld.refclk * pll_n + self.sysclk = self.cpld.refclk*pll_n self.ftw_per_hz = 1/self.sysclk*(int64(1) << 48) @kernel @@ -43,9 +37,7 @@ class AD9912: self.bus.write((addr | ((length - 1) << 13)) << 16) delay_mu(-self.bus.xfer_period_mu) self.bus.set_xfer(self.chip_select, length*8, 0) - if length < 4: - data <<= 32 - length*8 - self.bus.write(data) + self.bus.write(data << (32 - length*8)) delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu) @kernel From 28a3ee7e6123cd7fe84f1b5d56eaa2acf1bcab39 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 3 Jan 2018 18:29:39 +0000 Subject: [PATCH 0161/2457] urukul: make STA reading robust, add io_rst(), clean up --- artiq/coredevice/urukul.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 9d8caed20..9eaa4a1e5 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -113,6 +113,7 @@ class CPLD: @kernel def sta_read(self): + self.cfg_write(self.cfg_reg) # to latch STA self.bus.set_config_mu(_SPI_CONFIG, _SPIT_CFG_WR, _SPIT_CFG_RD) self.bus.set_xfer(CS_CFG, 0, 24) self.bus.write(self.cfg_reg << 8) @@ -121,18 +122,25 @@ class CPLD: @kernel def init(self, clk_sel=0, sync_sel=0): - t = now_mu() cfg = urukul_cfg(rf_sw=0, led=0, profile=0, att_le=0, io_update=0, mask_nu=0, clk_sel=clk_sel, sync_sel=sync_sel, rst=0, io_rst=0) self.cfg_write(cfg | (1 << CFG_RST)) + delay(100*us) self.cfg_write(cfg) proto_rev = urukul_sta_proto_rev(self.sta_read()) if proto_rev != STA_PROTO_REV_MATCH: raise ValueError("Urukul proto_rev mismatch") - at_mu(t) delay(100*us) + @kernel + def io_rst(self): + delay(1*us) + self.cfg_write(self.cfg_reg | (1 << CFG_IO_RST)) + delay(1*us) + self.cfg_write(self.cfg_reg & ~(1 << CFG_IO_RST)) + delay(1*us) + @kernel def cfg_sw(self, sw, on): c = self.cfg_reg @@ -140,7 +148,7 @@ class CPLD: c |= 1 << sw else: c &= ~(1 << sw) - self.write_cfg(c) + self.cfg_write(c) @kernel def set_att_mu(self, channel, att): From 7ac809f8b3e981dc925829e5817013dceabbf594 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 3 Jan 2018 18:41:21 +0000 Subject: [PATCH 0162/2457] urukul: do io reset --- artiq/coredevice/urukul.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 9eaa4a1e5..28f31f7a5 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -125,7 +125,7 @@ class CPLD: cfg = urukul_cfg(rf_sw=0, led=0, profile=0, att_le=0, io_update=0, mask_nu=0, clk_sel=clk_sel, sync_sel=sync_sel, rst=0, io_rst=0) - self.cfg_write(cfg | (1 << CFG_RST)) + self.cfg_write(cfg | (1 << CFG_RST) | (1 << CFG_IO_RST)) delay(100*us) self.cfg_write(cfg) proto_rev = urukul_sta_proto_rev(self.sta_read()) From eae758443287e443b8a833505a92b6008d561b15 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 3 Jan 2018 18:42:22 +0000 Subject: [PATCH 0163/2457] ad9910: add [wip] --- artiq/coredevice/ad9910.py | 159 +++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 artiq/coredevice/ad9910.py diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py new file mode 100644 index 000000000..4d4399b82 --- /dev/null +++ b/artiq/coredevice/ad9910.py @@ -0,0 +1,159 @@ +from artiq.language.core import kernel, delay_mu, delay, portable +from artiq.language.units import us, ns, ms +from artiq.coredevice.urukul import urukul_sta_pll_lock + +from numpy import int32, int64 + + +_AD9910_REG_CFR1 = 0x00 +_AD9910_REG_CFR2 = 0x01 +_AD9910_REG_CFR3 = 0x02 +_AD9910_REG_AUX_DAC = 0x03 +_AD9910_REG_IO_UPD = 0x04 +_AD9910_REG_FTW = 0x07 +_AD9910_REG_POW = 0x08 +_AD9910_REG_ASF = 0x09 +_AD9910_REG_MSYNC = 0x0A +_AD9910_REG_DRAMPL = 0x0B +_AD9910_REG_DRAMPS = 0x0C +_AD9910_REG_DRAMPR = 0x0D +_AD9910_REG_PR0 = 0x0E +_AD9910_REG_PR1 = 0x0F +_AD9910_REG_PR2 = 0x10 +_AD9910_REG_PR3 = 0x11 +_AD9910_REG_PR4 = 0x12 +_AD9910_REG_PR5 = 0x13 +_AD9910_REG_PR6 = 0x14 +_AD9910_REG_PR7 = 0x15 +_AD9910_REG_RAM = 0x16 + + +class AD9910: + """ + Support for the AD9910 DDS on Urukul + + :param chip_select: Chip select configuration. + :param cpld_device: Name of the Urukul CPLD this device is on. + :param sw_device: Name of the RF switch device. + """ + kernel_invariants = {"chip_select", "cpld", "core", "bus", "sw", + "ftw_per_hz", "sysclk", "pll_n", "pll_cp", "pll_vco"} + + def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, + pll_n=40, pll_cp=7, pll_vco=5): + self.cpld = dmgr.get(cpld_device) + self.core = self.cpld.core + self.bus = self.cpld.bus + assert chip_select >= 4 + self.chip_select = chip_select + if sw_device: + self.sw = dmgr.get(sw_device) + assert 12 <= pll_n <= 127 + self.pll_n = pll_n + self.sysclk = self.cpld.refclk*pll_n/4 # Urukul clock fanout divider + self.ftw_per_hz = 1./self.sysclk*(int64(1) << 32) + assert 0 <= pll_vco <= 5 + vco_min, vco_max = [(370, 510), (420, 590), (500, 700), + (600, 880), (700, 950), (820, 1150)][pll_vco] + assert vco_min <= self.sysclk/1e6 <= vco_max + self.pll_vco = pll_vco + assert 0 <= pll_cp <= 7 + self.pll_cp = pll_cp + + @kernel + def write(self, addr, data, length=4): + assert (length == 2) or (length == 4) + self.bus.set_xfer(self.chip_select, 8, 0) + self.bus.write(addr << 24) + delay_mu(-self.bus.xfer_period_mu) + self.bus.set_xfer(self.chip_select, length*8, 0) + self.bus.write(data << (32 - length*8)) + delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu) + + @kernel + def write64(self, addr, data_high, data_low): + self.bus.set_xfer(self.chip_select, 8, 0) + self.bus.write(addr << 24) + t = self.bus.xfer_period_mu + delay_mu(-t) + self.bus.set_xfer(self.chip_select, 32, 0) + self.bus.write(data_high) + self.bus.write(data_low) + delay_mu(t - 2*self.bus.write_period_mu) + + @kernel + def read(self, addr, length=4): + assert length >= 2 + assert length <= 4 + self.bus.set_xfer(self.chip_select, 8, 0) + self.bus.write((addr | 0x80) << 24) + delay_mu(-self.bus.xfer_period_mu) + self.bus.set_xfer(self.chip_select, 0, length*8) + self.bus.write(0) + delay_mu(2*self.bus.xfer_period_mu) + data = self.bus.read_sync() + if length < 4: + data &= (1 << (length*8)) - 1 + return data + + @kernel + def init(self): + # self.cpld.io_rst() + self.write(_AD9910_REG_CFR1, 0x00000002) + delay(100*ns) + self.cpld.io_update.pulse(100*ns) + aux_dac = self.read(_AD9910_REG_AUX_DAC) + assert aux_dac & 0xff == 0x7f + delay(10*us) + self.write(_AD9910_REG_CFR2, 0x01400020) + cfr3 = (0x0807c100 | (self.pll_vco << 24) | + (self.pll_cp << 19) | (self.pll_n << 1)) + self.write(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset + delay(10*us) + self.cpld.io_update.pulse(100*ns) + self.write(_AD9910_REG_CFR3, cfr3) + delay(10*us) + self.cpld.io_update.pulse(100*ns) + for i in range(100): + lock = urukul_sta_pll_lock(self.cpld.sta_read()) + delay(1*ms) + if lock & (1 << self.chip_select - 4) != 0: + return + raise ValueError("PLL failed to lock") + + @kernel + def set_mu(self, ftw, pow=0, asf=0x3fff): + self.write64(_AD9910_REG_PR0, (asf << 16) | pow, ftw) + self.cpld.io_update.pulse(10*ns) + + @portable(flags={"fast-math"}) + def frequency_to_ftw(self, frequency): + """Returns the frequency tuning word corresponding to the given + frequency. + """ + return int32(round(self.ftw_per_hz*frequency)) + + @portable(flags={"fast-math"}) + def turns_to_pow(self, turns): + """Returns the phase offset word corresponding to the given phase + in turns.""" + return int32(round(turns*0x10000)) + + @portable(flags={"fast-math"}) + def amplitude_to_asf(self, amplitude): + """Returns amplitude scale factor corresponding to given amplitude.""" + return int32(round(amplitude*0x3ffe)) + + @kernel + def set(self, frequency, phase=0.0, amplitude=1.0): + self.set_mu(self.frequency_to_ftw(frequency), + self.turns_to_pow(phase), + self.amplitude_to_asf(amplitude)) + + @kernel + def set_att_mu(self, att): + self.cpld.set_att_mu(self.chip_select - 4, att) + + @kernel + def set_att(self, att): + self.cpld.set_att(self.chip_select - 4, att) From e3d66d286d7bafb50d4c3b308cbef02d6d89f171 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 3 Jan 2018 18:42:58 +0000 Subject: [PATCH 0164/2457] urukul: ad9910 examples --- artiq/examples/master/device_db.py | 52 ++++++++++++++++-- .../coredevice_examples/simple/urukul.py | 53 ++++++++++--------- 2 files changed, 77 insertions(+), 28 deletions(-) diff --git a/artiq/examples/master/device_db.py b/artiq/examples/master/device_db.py index b9b38188d..87351ffa7 100644 --- a/artiq/examples/master/device_db.py +++ b/artiq/examples/master/device_db.py @@ -237,7 +237,7 @@ device_db = { "refclk": 100e6 } }, - "urukul_ch0": { + "urukul_ch0a": { "type": "local", "module": "artiq.coredevice.ad9912", "class": "AD9912", @@ -248,7 +248,7 @@ device_db = { "sw_device": "ttl_urukul_sw0" } }, - "urukul_ch1": { + "urukul_ch1a": { "type": "local", "module": "artiq.coredevice.ad9912", "class": "AD9912", @@ -259,7 +259,7 @@ device_db = { "sw_device": "ttl_urukul_sw1" } }, - "urukul_ch2": { + "urukul_ch2a": { "type": "local", "module": "artiq.coredevice.ad9912", "class": "AD9912", @@ -270,7 +270,7 @@ device_db = { "sw_device": "ttl_urukul_sw2" } }, - "urukul_ch3": { + "urukul_ch3a": { "type": "local", "module": "artiq.coredevice.ad9912", "class": "AD9912", @@ -281,6 +281,50 @@ device_db = { "sw_device": "ttl_urukul_sw3" } }, + "urukul_ch0b": { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 4, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw0" + } + }, + "urukul_ch1b": { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 5, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw1" + } + }, + "urukul_ch2b": { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 6, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw2" + } + }, + "urukul_ch3b": { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 7, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw3" + } + }, # AD9914 DDS "dds0": { diff --git a/artiq/examples/master/repository/coredevice_examples/simple/urukul.py b/artiq/examples/master/repository/coredevice_examples/simple/urukul.py index 8b8958a6c..b89deb2bb 100644 --- a/artiq/examples/master/repository/coredevice_examples/simple/urukul.py +++ b/artiq/examples/master/repository/coredevice_examples/simple/urukul.py @@ -6,10 +6,14 @@ class UrukulTest(EnvExperiment): self.setattr_device("core") self.setattr_device("fmcdio_dirctl") self.setattr_device("urukul_cpld") - self.setattr_device("urukul_ch0") - self.setattr_device("urukul_ch1") - self.setattr_device("urukul_ch2") - self.setattr_device("urukul_ch3") + self.setattr_device("urukul_ch0a") + self.setattr_device("urukul_ch1a") + self.setattr_device("urukul_ch2a") + self.setattr_device("urukul_ch3a") + self.setattr_device("urukul_ch0b") + self.setattr_device("urukul_ch1b") + self.setattr_device("urukul_ch2b") + self.setattr_device("urukul_ch3b") self.setattr_device("led") def p(self, f, *a): @@ -25,36 +29,37 @@ class UrukulTest(EnvExperiment): self.led.off() self.urukul_cpld.init(clk_sel=1) - self.urukul_ch0.init() - self.urukul_ch1.init() - self.urukul_ch2.init() - self.urukul_ch3.init() - delay(100*us) - - self.urukul_ch0.set(10*MHz) - self.urukul_ch0.sw.on() - self.urukul_ch0.set_att(10.) + delay(1*ms) # DDS wake up + self.urukul_ch0b.init() + self.urukul_ch1b.init() + self.urukul_ch2b.init() + self.urukul_ch3b.init() delay(100*us) - self.urukul_ch1.set(10*MHz, 0.5) - self.urukul_ch1.sw.on() - self.urukul_ch1.set_att(10.) + self.urukul_ch0b.set(100*MHz) + self.urukul_ch0b.sw.on() + self.urukul_ch0b.set_att(10.) delay(100*us) - self.urukul_ch2.set(400*MHz) - self.urukul_ch2.sw.on() - self.urukul_ch2.set_att(0.) + self.urukul_ch1b.set(10*MHz, 0.5) + self.urukul_ch1b.sw.on() + self.urukul_ch1b.set_att(0.) delay(100*us) - self.urukul_ch3.set(1*MHz) - self.urukul_ch3.sw.on() - self.urukul_ch3.set_att(0.) + self.urukul_ch2b.set(400*MHz) + self.urukul_ch2b.sw.on() + self.urukul_ch2b.set_att(0.) + + delay(100*us) + self.urukul_ch3b.set(1*MHz) + self.urukul_ch3b.sw.on() + self.urukul_ch3b.set_att(20.) while True: - self.urukul_ch0.set_mu(0x123456789abc, 0) + self.urukul_ch0b.set_mu(0x12345678, 0, 0x3fff) while True: - self.urukul_ch0.sw.pulse(5*ms) + self.urukul_ch0b.sw.pulse(5*ms) delay(5*ms) while False: From 67746cc7a01a3cd461e6b811ed8ef35a559027df Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 3 Jan 2018 19:22:36 +0000 Subject: [PATCH 0165/2457] urukul: raise instead of assert, clean up --- artiq/coredevice/ad9910.py | 31 ++++++++----------- artiq/coredevice/ad9912.py | 5 +-- artiq/coredevice/urukul.py | 5 +-- .../coredevice_examples/simple/urukul.py | 1 - 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 4d4399b82..c3263acce 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -44,7 +44,7 @@ class AD9910: self.cpld = dmgr.get(cpld_device) self.core = self.cpld.core self.bus = self.cpld.bus - assert chip_select >= 4 + assert 4 <= chip_select <= 7 self.chip_select = chip_select if sw_device: self.sw = dmgr.get(sw_device) @@ -61,13 +61,12 @@ class AD9910: self.pll_cp = pll_cp @kernel - def write(self, addr, data, length=4): - assert (length == 2) or (length == 4) + def write32(self, addr, data): self.bus.set_xfer(self.chip_select, 8, 0) self.bus.write(addr << 24) delay_mu(-self.bus.xfer_period_mu) - self.bus.set_xfer(self.chip_select, length*8, 0) - self.bus.write(data << (32 - length*8)) + self.bus.set_xfer(self.chip_select, 32, 0) + self.bus.write(data) delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu) @kernel @@ -82,36 +81,32 @@ class AD9910: delay_mu(t - 2*self.bus.write_period_mu) @kernel - def read(self, addr, length=4): - assert length >= 2 - assert length <= 4 + def read32(self, addr): self.bus.set_xfer(self.chip_select, 8, 0) self.bus.write((addr | 0x80) << 24) delay_mu(-self.bus.xfer_period_mu) - self.bus.set_xfer(self.chip_select, 0, length*8) + self.bus.set_xfer(self.chip_select, 0, 32) self.bus.write(0) delay_mu(2*self.bus.xfer_period_mu) data = self.bus.read_sync() - if length < 4: - data &= (1 << (length*8)) - 1 return data @kernel def init(self): - # self.cpld.io_rst() - self.write(_AD9910_REG_CFR1, 0x00000002) + self.write32(_AD9910_REG_CFR1, 0x00000002) delay(100*ns) self.cpld.io_update.pulse(100*ns) - aux_dac = self.read(_AD9910_REG_AUX_DAC) - assert aux_dac & 0xff == 0x7f + aux_dac = self.read32(_AD9910_REG_AUX_DAC) + if aux_dac & 0xff != 0x7f: + raise ValueError("Urukul AD9910 AUX_DAC mismatch") delay(10*us) - self.write(_AD9910_REG_CFR2, 0x01400020) + self.write32(_AD9910_REG_CFR2, 0x01400020) cfr3 = (0x0807c100 | (self.pll_vco << 24) | (self.pll_cp << 19) | (self.pll_n << 1)) - self.write(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset + self.write32(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset delay(10*us) self.cpld.io_update.pulse(100*ns) - self.write(_AD9910_REG_CFR3, cfr3) + self.write32(_AD9910_REG_CFR3, cfr3) delay(10*us) self.cpld.io_update.pulse(100*ns) for i in range(100): diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 77e78d568..a5da146ed 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -21,7 +21,7 @@ class AD9912: self.cpld = dmgr.get(cpld_device) self.core = self.cpld.core self.bus = self.cpld.bus - assert chip_select >= 4 + assert 4 <= chip_select <= 7 self.chip_select = chip_select if sw_device: self.sw = dmgr.get(sw_device) @@ -60,7 +60,8 @@ class AD9912: t = now_mu() self.write(AD9912_SER_CONF, 0x99) prodid = self.read(AD9912_PRODIDH, length=2) - assert (prodid == 0x1982) or (prodid == 0x1902) + if (prodid != 0x1982) and (prodid != 0x1902): + raise ValueError("Urukul AD9912 product id mismatch") delay(10*us) self.write(AD9912_PWRCNTRL1, 0x80) # HSTL, CMOS power down delay(10*us) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 28f31f7a5..c905d7441 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -1,5 +1,5 @@ from artiq.language.core import kernel, delay_mu, delay, now_mu, at_mu -from artiq.language.units import us +from artiq.language.units import us, ms from numpy import int32, int64 @@ -126,8 +126,9 @@ class CPLD: io_update=0, mask_nu=0, clk_sel=clk_sel, sync_sel=sync_sel, rst=0, io_rst=0) self.cfg_write(cfg | (1 << CFG_RST) | (1 << CFG_IO_RST)) - delay(100*us) + delay(1*ms) self.cfg_write(cfg) + delay(10*ms) # DDS wake up proto_rev = urukul_sta_proto_rev(self.sta_read()) if proto_rev != STA_PROTO_REV_MATCH: raise ValueError("Urukul proto_rev mismatch") diff --git a/artiq/examples/master/repository/coredevice_examples/simple/urukul.py b/artiq/examples/master/repository/coredevice_examples/simple/urukul.py index b89deb2bb..42454b36b 100644 --- a/artiq/examples/master/repository/coredevice_examples/simple/urukul.py +++ b/artiq/examples/master/repository/coredevice_examples/simple/urukul.py @@ -29,7 +29,6 @@ class UrukulTest(EnvExperiment): self.led.off() self.urukul_cpld.init(clk_sel=1) - delay(1*ms) # DDS wake up self.urukul_ch0b.init() self.urukul_ch1b.init() self.urukul_ch2b.init() From fc9766d2fa4b694a183330d8a403035f4419b143 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 4 Jan 2018 11:37:52 +0000 Subject: [PATCH 0166/2457] firmware: reset ethphy before initializing smoltcp (fixes #884). --- artiq/firmware/bootloader/main.rs | 8 +++++--- artiq/firmware/libboard/ethmac.rs | 10 ++++++++++ artiq/firmware/runtime/main.rs | 10 ++++++---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 87cdfb67d..2a9325fac 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -158,10 +158,12 @@ fn network_boot() { println!("Using MAC address {} and IP address {}", eth_addr, ip_addr); - let net_device = unsafe { ethmac::EthernetDevice::new() }; - let mut neighbor_cache_storage = [None; 2]; + let mut net_device = unsafe { ethmac::EthernetDevice::new() }; + net_device.reset(); + + let mut neighbor_map = [None; 2]; let neighbor_cache = - smoltcp::iface::NeighborCache::new(&mut neighbor_cache_storage[..]); + smoltcp::iface::NeighborCache::new(&mut neighbor_map[..]); let mut ip_addrs = [IpCidr::new(ip_addr, 0)]; let mut interface = smoltcp::iface::EthernetInterfaceBuilder::new(net_device) diff --git a/artiq/firmware/libboard/ethmac.rs b/artiq/firmware/libboard/ethmac.rs index 1a1f29272..ff9c1149e 100644 --- a/artiq/firmware/libboard/ethmac.rs +++ b/artiq/firmware/libboard/ethmac.rs @@ -4,6 +4,7 @@ use smoltcp::phy::{self, DeviceCapabilities, Device}; use csr; use mem::ETHMAC_BASE; +use clock; const RX_SLOTS: usize = csr::ETHMAC_RX_SLOTS as usize; const TX_SLOTS: usize = csr::ETHMAC_TX_SLOTS as usize; @@ -45,6 +46,15 @@ impl EthernetDevice { pub unsafe fn new() -> EthernetDevice { EthernetDevice(()) } + + pub fn reset(&mut self) { + unsafe { + csr::ethphy::crg_reset_write(1); + clock::spin_us(2_000); + csr::ethphy::crg_reset_write(0); + clock::spin_us(2_000); + } + } } impl<'a> Device<'a> for EthernetDevice { diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 1d6e631f5..ad4863c03 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -130,18 +130,20 @@ fn startup_ethernet() { } } + let mut net_device = unsafe { ethmac::EthernetDevice::new() }; + net_device.reset(); + // fn _net_trace_writer(timestamp: u64, printer: smoltcp::wire::PrettyPrinter) // where U: smoltcp::wire::pretty_print::PrettyPrint { // let seconds = timestamp / 1000; // let micros = timestamp % 1000 * 1000; // print!("\x1b[37m[{:6}.{:06}s]\n{}\x1b[0m\n", seconds, micros, printer) // } - - let net_device = unsafe { ethmac::EthernetDevice::new() }; // let net_device = smoltcp::phy::EthernetTracer::new(net_device, _net_trace_writer); - let mut neighbor_cache_storage = [None; 8]; + + let mut neighbor_map = [None; 8]; let neighbor_cache = - smoltcp::iface::NeighborCache::new(&mut neighbor_cache_storage[..]); + smoltcp::iface::NeighborCache::new(&mut neighbor_map[..]); let mut interface = smoltcp::iface::EthernetInterfaceBuilder::new(net_device) .neighbor_cache(neighbor_cache) From e1a75ac1c14cdd7c85a12be907437b331b4e430e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 4 Jan 2018 22:19:46 +0800 Subject: [PATCH 0167/2457] runtime: set log level early We want to debug startup. --- artiq/firmware/runtime/main.rs | 37 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index ad4863c03..a2645c028 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -54,6 +54,24 @@ fn startup() { info!("software version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); info!("gateware version {}", board::ident::read(&mut [0; 64])); + match config::read_str("log_level", |r| r.map(|s| s.parse())) { + Ok(Ok(log_level_filter)) => { + info!("log level set to {} by `log_level` config key", + log_level_filter); + log::set_max_level(log_level_filter); + } + _ => info!("log level set to INFO by default") + } + match config::read_str("uart_log_level", |r| r.map(|s| s.parse())) { + Ok(Ok(uart_log_level_filter)) => { + info!("UART log level set to {} by `uart_log_level` config key", + uart_log_level_filter); + logger_artiq::BufferLogger::with(|logger| + logger.set_uart_log_level(uart_log_level_filter)); + } + _ => info!("UART log level set to INFO by default") + } + #[cfg(has_serwb_phy_amc)] board_artiq::serwb::wait_init(); @@ -162,25 +180,6 @@ fn startup_ethernet() { #[cfg(has_rtio_analyzer)] io.spawn(4096, analyzer::thread); - match config::read_str("log_level", |r| r.map(|s| s.parse())) { - Ok(Ok(log_level_filter)) => { - info!("log level set to {} by `log_level` config key", - log_level_filter); - log::set_max_level(log_level_filter); - } - _ => info!("log level set to INFO by default") - } - - match config::read_str("uart_log_level", |r| r.map(|s| s.parse())) { - Ok(Ok(uart_log_level_filter)) => { - info!("UART log level set to {} by `uart_log_level` config key", - uart_log_level_filter); - logger_artiq::BufferLogger::with(|logger| - logger.set_uart_log_level(uart_log_level_filter)); - } - _ => info!("UART log level set to INFO by default") - } - let mut net_stats = ethmac::EthernetStatistics::new(); loop { scheduler.run(); From 161a4145673845e67a39ed6cb6b337d1df1e8f55 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 4 Jan 2018 22:23:59 +0800 Subject: [PATCH 0168/2457] serwb: debug print on error --- artiq/firmware/libboard_artiq/serwb.rs | 45 +++++++++++++++----------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/artiq/firmware/libboard_artiq/serwb.rs b/artiq/firmware/libboard_artiq/serwb.rs index 69b9f9676..c31fa8eeb 100644 --- a/artiq/firmware/libboard_artiq/serwb.rs +++ b/artiq/firmware/libboard_artiq/serwb.rs @@ -1,11 +1,36 @@ use board::csr; +unsafe fn debug_print(rtm: bool) { + debug!("AMC serwb settings:"); + debug!(" delay_min_found: {}", csr::serwb_phy_amc::control_delay_min_found_read()); + debug!(" delay_min: {}", csr::serwb_phy_amc::control_delay_min_read()); + debug!(" delay_max_found: {}", csr::serwb_phy_amc::control_delay_max_found_read()); + debug!(" delay_max: {}", csr::serwb_phy_amc::control_delay_max_read()); + debug!(" delay: {}", csr::serwb_phy_amc::control_delay_read()); + debug!(" bitslip: {}", csr::serwb_phy_amc::control_bitslip_read()); + debug!(" ready: {}", csr::serwb_phy_amc::control_ready_read()); + debug!(" error: {}", csr::serwb_phy_amc::control_error_read()); + + if rtm { + debug!("RTM serwb settings:"); + debug!(" delay_min_found: {}", csr::serwb_phy_rtm::control_delay_min_found_read()); + debug!(" delay_min: {}", csr::serwb_phy_rtm::control_delay_min_read()); + debug!(" delay_max_found: {}", csr::serwb_phy_rtm::control_delay_max_found_read()); + debug!(" delay_max: {}", csr::serwb_phy_rtm::control_delay_max_read()); + debug!(" delay: {}", csr::serwb_phy_rtm::control_delay_read()); + debug!(" bitslip: {}", csr::serwb_phy_rtm::control_bitslip_read()); + debug!(" ready: {}", csr::serwb_phy_rtm::control_ready_read()); + debug!(" error: {}", csr::serwb_phy_rtm::control_error_read()); + } +} + pub fn wait_init() { info!("waiting for AMC/RTM serwb bridge to be ready..."); unsafe { csr::serwb_phy_amc::control_reset_write(1); while csr::serwb_phy_amc::control_ready_read() == 0 { if csr::serwb_phy_amc::control_error_read() == 1 { + debug_print(false); warn!("AMC/RTM serwb bridge initialization failed, retrying."); csr::serwb_phy_amc::control_reset_write(1); } @@ -23,24 +48,6 @@ pub fn wait_init() { } unsafe { - debug!("AMC serwb settings:"); - debug!(" delay_min_found: {}", csr::serwb_phy_amc::control_delay_min_found_read()); - debug!(" delay_min: {}", csr::serwb_phy_amc::control_delay_min_read()); - debug!(" delay_max_found: {}", csr::serwb_phy_amc::control_delay_max_found_read()); - debug!(" delay_max: {}", csr::serwb_phy_amc::control_delay_max_read()); - debug!(" delay: {}", csr::serwb_phy_amc::control_delay_read()); - debug!(" bitslip: {}", csr::serwb_phy_amc::control_bitslip_read()); - debug!(" ready: {}", csr::serwb_phy_amc::control_ready_read()); - debug!(" error: {}", csr::serwb_phy_amc::control_error_read()); - - debug!("RTM serwb settings:"); - debug!(" delay_min_found: {}", csr::serwb_phy_rtm::control_delay_min_found_read()); - debug!(" delay_min: {}", csr::serwb_phy_rtm::control_delay_min_read()); - debug!(" delay_max_found: {}", csr::serwb_phy_rtm::control_delay_max_found_read()); - debug!(" delay_max: {}", csr::serwb_phy_rtm::control_delay_max_read()); - debug!(" delay: {}", csr::serwb_phy_rtm::control_delay_read()); - debug!(" bitslip: {}", csr::serwb_phy_rtm::control_bitslip_read()); - debug!(" ready: {}", csr::serwb_phy_rtm::control_ready_read()); - debug!(" error: {}", csr::serwb_phy_rtm::control_error_read()); + debug_print(true); } } From 8813aee6b1514cd649f5c5c34a05a8be27141c58 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 4 Jan 2018 15:12:00 +0000 Subject: [PATCH 0169/2457] targets: add kasli [wip, untested] --- artiq/gateware/targets/kasli.py | 202 ++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 artiq/gateware/targets/kasli.py diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py new file mode 100644 index 000000000..c4c90561d --- /dev/null +++ b/artiq/gateware/targets/kasli.py @@ -0,0 +1,202 @@ +#!/usr/bin/env python3 + +import argparse + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.cdc import MultiReg +from migen.build.generic_platform import * +from migen.build.xilinx.vivado import XilinxVivadoToolchain +from migen.build.xilinx.ise import XilinxISEToolchain + +from misoc.interconnect.csr import * +from misoc.cores import gpio +from misoc.targets.kasli import (MiniSoC, soc_kasli_args, + soc_kasli_argdict) +from misoc.integration.builder import builder_args, builder_argdict + +from artiq.gateware.amp import AMPSoC, build_artiq_soc +from artiq.gateware import rtio +from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi +from artiq import __version__ as artiq_version + + +class _RTIOCRG(Module, AutoCSR): + def __init__(self, platform, rtio_internal_clk): + self._clock_sel = CSRStorage() + self._pll_reset = CSRStorage(reset=1) + self._pll_locked = CSRStatus() + self.clock_domains.cd_rtio = ClockDomain() + self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) + + rtio_external_clk = Signal() + clk_fpgaio_se = Signal() + clk_fpgaio = platform.request("clk_fpgaio") # from Si5324 + platform.add_period_constraint(clk_fpgaio.p, 8.0) + self.specials += [ + Instance("IBUFGDS", + p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE", + i_I=clk_fpgaio.p, i_IB=clk_fpgaio.n, o_O=clk_fpgaio_se), + Instance("BUFG", i_I=clk_fpgaio_se, o_O=rtio_external_clk), + ] + + pll_locked = Signal() + rtio_clk = Signal() + rtiox4_clk = Signal() + ext_clkout_clk = Signal() + self.specials += [ + Instance("PLLE2_ADV", + p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, + + p_REF_JITTER1=0.01, + p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0, + i_CLKIN1=rtio_internal_clk, i_CLKIN2=rtio_external_clk, + # Warning: CLKINSEL=0 means CLKIN2 is selected + i_CLKINSEL=~self._clock_sel.storage, + + # VCO @ 1GHz when using 125MHz input + p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, + i_CLKFBIN=self.cd_rtio.clk, + i_RST=self._pll_reset.storage, + + o_CLKFBOUT=rtio_clk, + + p_CLKOUT0_DIVIDE=2, p_CLKOUT0_PHASE=0.0, + o_CLKOUT0=rtiox4_clk), + Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk), + Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), + + AsyncResetSynchronizer(self.cd_rtio, ~pll_locked), + MultiReg(pll_locked, self._pll_locked.status) + ] + + +class _KasliBase(MiniSoC, AMPSoC): + mem_map = { + "cri_con": 0x10000000, + "rtio": 0x20000000, + "rtio_dma": 0x30000000, + "mailbox": 0x70000000 + } + mem_map.update(MiniSoC.mem_map) + + def __init__(self, cpu_type="or1k", **kwargs): + MiniSoC.__init__(self, + cpu_type=cpu_type, + sdram_controller_type="minicon", + l2_size=128*1024, + ident=artiq_version, + ethmac_nrxslots=4, + ethmac_ntxslots=4, + **kwargs) + AMPSoC.__init__(self) + + self.submodules.leds = gpio.GPIOOut(Cat( + self.platform.request("user_led", 0))) + self.csr_devices.append("leds") + + i2c = self.platform.request("i2c") + self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) + self.csr_devices.append("i2c") + self.config["I2C_BUS_COUNT"] = 1 + + def add_rtio(self, rtio_channels): + self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) + self.csr_devices.append("rtio_crg") + self.submodules.rtio_core = rtio.Core(rtio_channels) + self.csr_devices.append("rtio_core") + self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( + rtio.DMA(self.get_native_sdram_if())) + self.register_kernel_cpu_csrdevice("rtio") + self.register_kernel_cpu_csrdevice("rtio_dma") + self.submodules.cri_con = rtio.CRIInterconnectShared( + [self.rtio.cri, self.rtio_dma.cri], + [self.rtio_core.cri]) + self.register_kernel_cpu_csrdevice("cri_con") + self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) + self.csr_devices.append("rtio_moninj") + + self.rtio_crg.cd_rtio.clk.attr.add("keep") + self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.) + self.platform.add_false_path_constraints( + self.crg.cd_sys.clk, + self.rtio_crg.cd_rtio.clk) + + self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri, + self.get_native_sdram_if()) + self.csr_devices.append("rtio_analyzer") + + +def _eem_signal(i): + n = "d{}".format(i) + if i == 0: + n += "_cc" + return n + + +def _dio(eem): + return [(eem, i, + Subsignal("p", Pins("{}:{}_p".format(eem, _eem_signal(i)))), + Subsignal("n", Pins("{}:{}_n".format(eem, _eem_signal(i)))), + IOStandard("LVDS_25")) + for i in range(8)] + + +class Opticlock(_KasliBase): + """ + Opticlock extension configuration + """ + def __init__(self, cpu_type="or1k", **kwargs): + _KasliBase.__init__(self, cpu_type, **kwargs) + + platform = self.platform + platform.add_extension(_dio("eem0")) + platform.add_extension(_dio("eem1")) + platform.add_extension(_dio("eem2")) + # platform.add_extension(_urukul("eem3", "eem4")) + # platform.add_extension(_novogorny("eem5")) + + rtio_channels = [] + for eem in "eem0 eem1 eem2".split(): + for i in range(8): + phy = ttl_serdes_7series.Output_8X( + platform.request(eem, i)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + for i in (1, 2): + sfp = platform.request("sfp", i) + phy = ttl_simple.Output(sfp.led) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) + rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(rtio_channels) + + +def main(): + parser = argparse.ArgumentParser( + description="ARTIQ device binary builder for Kasli systems") + builder_args(parser) + soc_kasli_args(parser) + parser.add_argument("-E", "--extensions", default="opticlock", + help="extension setup: opticlock " + "(default: %(default)s)") + args = parser.parse_args() + + extensions = args.extensions.lower() + if extensions == "opticlock": + cls = Opticlock + else: + raise SystemExit("Invalid hardware adapter string (-E/--extensions)") + + soc = cls(**soc_kasli_argdict(args)) + build_artiq_soc(soc, builder_argdict(args)) + + +if __name__ == "__main__": + main() From 987a9c83085169f4d4603577a09e1b877715ab43 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 8 Jan 2018 21:39:15 +0000 Subject: [PATCH 0170/2457] conda: update rustc to 1.23.0. --- artiq/firmware/Cargo.toml | 3 +++ conda/artiq-dev/meta.yaml | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/Cargo.toml b/artiq/firmware/Cargo.toml index 0f2007873..ec99844a5 100644 --- a/artiq/firmware/Cargo.toml +++ b/artiq/firmware/Cargo.toml @@ -1,2 +1,5 @@ [workspace] members = ["bootloader", "runtime", "ksupport", "satman"] + +[profile.dev] +debug = 1 # either 0 or 2 cause an LLVM ICE diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index d0aae5048..36be45c37 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -21,8 +21,7 @@ requirements: - binutils-or1k-linux >=2.27 - llvm-or1k 4.0.1 - llvmlite-artiq 0.20.0 - - rustc 1.22.1 17 - - rust-core-or1k 1.22.1 18 + - rust-core-or1k 1.23.0 19 - openocd 0.10.0+git1 - lit - outputcheck From 3a3f44af53282f12869e52659620685e8bf6cba6 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 8 Jan 2018 21:41:53 +0000 Subject: [PATCH 0171/2457] firmware: update smoltcp. --- artiq/firmware/Cargo.lock | 18 +++++++++--------- artiq/firmware/bootloader/Cargo.toml | 2 +- artiq/firmware/libboard/Cargo.toml | 2 +- artiq/firmware/runtime/Cargo.toml | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 9f6e3a821..863b990a0 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -30,7 +30,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=1c765ad)", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=888b1d2)", ] [[package]] @@ -52,7 +52,7 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=888b1d2)", ] [[package]] @@ -186,8 +186,8 @@ dependencies = [ [[package]] name = "managed" -version = "0.4.0" -source = "git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1#629a6786a1cf1692015f464ed16c04eafa5cb8d1" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proto" @@ -218,7 +218,7 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "logger_artiq 0.0.0", "proto 0.0.0", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=888b1d2)", "std_artiq 0.0.0", ] @@ -249,11 +249,11 @@ dependencies = [ [[package]] name = "smoltcp" version = "0.4.0" -source = "git+https://github.com/m-labs/smoltcp?rev=507d2fe#507d2fe0ea390ec309d2e900a9d0d4a70a3dfa3c" +source = "git+https://github.com/m-labs/smoltcp?rev=888b1d2#888b1d2403de79083ad9840ea8c6d93039555db3" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)", + "managed 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -295,9 +295,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" -"checksum managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)" = "" +"checksum managed 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "786bd3519bdfb0e1a57146a74b7584555dd6c4f1b6e1137c70e177d60dde8186" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" -"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=507d2fe)" = "" +"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=888b1d2)" = "" "checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml index a5975ade1..5d479ddd9 100644 --- a/artiq/firmware/bootloader/Cargo.toml +++ b/artiq/firmware/bootloader/Cargo.toml @@ -19,6 +19,6 @@ board = { path = "../libboard", features = ["uart_console", "smoltcp"] } [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "507d2fe" +rev = "888b1d2" default-features = false features = ["proto-ipv4", "socket-tcp"] diff --git a/artiq/firmware/libboard/Cargo.toml b/artiq/firmware/libboard/Cargo.toml index c0dfd8055..111d66738 100644 --- a/artiq/firmware/libboard/Cargo.toml +++ b/artiq/firmware/libboard/Cargo.toml @@ -22,7 +22,7 @@ features = ["mem"] [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "507d2fe" +rev = "888b1d2" default-features = false optional = true diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 59dd144c2..0d3514c12 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -35,6 +35,6 @@ features = ["alloc"] [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "507d2fe" +rev = "888b1d2" default-features = false features = ["alloc", "log", "proto-ipv4", "socket-tcp"] From 34a5445802f140ada8023c50f95db5cbd8eb22ab Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 8 Jan 2018 21:53:04 +0000 Subject: [PATCH 0172/2457] compiler: don't die if addr2line cannot extract line from backtrace. Fixes #885. --- artiq/compiler/targets.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index b3cfdec8d..db626da85 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -216,8 +216,12 @@ class Target: filename, line = location.rsplit(":", 1) if filename == "??" or filename == "": continue + if line == "?": + line = -1 + else: + line = int(line) # can't get column out of addr2line D: - backtrace.append((filename, int(line), -1, function, address)) + backtrace.append((filename, line, -1, function, address)) return backtrace def demangle(self, names): From 07ccb9eebdf81e394644e17e7080233b37b9b702 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 8 Jan 2018 22:15:52 +0000 Subject: [PATCH 0173/2457] firmware: support configuration without ethphy (#886). Currently, this is kasli. --- artiq/firmware/bootloader/main.rs | 4 +++- artiq/firmware/libboard/ethmac.rs | 6 ++++-- artiq/firmware/runtime/main.rs | 1 - artiq/frontend/artiq_devtool.py | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 2a9325fac..91e101f08 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -159,7 +159,9 @@ fn network_boot() { println!("Using MAC address {} and IP address {}", eth_addr, ip_addr); let mut net_device = unsafe { ethmac::EthernetDevice::new() }; - net_device.reset(); + + #[cfg(has_ethphy)] + net_device.reset_phy(); let mut neighbor_map = [None; 2]; let neighbor_cache = diff --git a/artiq/firmware/libboard/ethmac.rs b/artiq/firmware/libboard/ethmac.rs index ff9c1149e..90cd1faa4 100644 --- a/artiq/firmware/libboard/ethmac.rs +++ b/artiq/firmware/libboard/ethmac.rs @@ -4,7 +4,6 @@ use smoltcp::phy::{self, DeviceCapabilities, Device}; use csr; use mem::ETHMAC_BASE; -use clock; const RX_SLOTS: usize = csr::ETHMAC_RX_SLOTS as usize; const TX_SLOTS: usize = csr::ETHMAC_TX_SLOTS as usize; @@ -47,7 +46,10 @@ impl EthernetDevice { EthernetDevice(()) } - pub fn reset(&mut self) { + #[cfg(has_ethphy)] + pub fn reset_phy(&mut self) { + use clock; + unsafe { csr::ethphy::crg_reset_write(1); clock::spin_us(2_000); diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index a2645c028..37c455b78 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -149,7 +149,6 @@ fn startup_ethernet() { } let mut net_device = unsafe { ethmac::EthernetDevice::new() }; - net_device.reset(); // fn _net_trace_writer(timestamp: u64, printer: smoltcp::wire::PrettyPrinter) // where U: smoltcp::wire::pretty_print::PrettyPrint { diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 951c04db7..fa3236fd7 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -39,7 +39,7 @@ def get_argparser(): parser.add_argument("-t", "--target", metavar="TARGET", type=str, default="kc705_dds", help="Target to build, one of: " - "kc705_dds sayma_amc_standalone " + "kc705_dds kasli sayma_amc_standalone " "sayma_amc_drtio_master sayma_amc_drtio_satellite") parser.add_argument("actions", metavar="ACTION", @@ -56,7 +56,7 @@ def main(): if args.verbose == args.quiet == 0: logging.getLogger().setLevel(logging.INFO) - if args.target in ["kc705_dds", "sayma_amc_standalone", "sayma_amc_drtio_master"]: + if args.target in ["kc705_dds", "kasli", "sayma_amc_standalone", "sayma_amc_drtio_master"]: firmware = "runtime" elif args.target == "sayma_amc_drtio_satellite": firmware = "satman" From 267c6998351097b887ea572c6db9d5c304572a17 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 9 Jan 2018 02:41:02 +0000 Subject: [PATCH 0174/2457] firmware: support DDRPHY without write leveling (fixes #886). Currently, this is kasli. --- artiq/firmware/bootloader/main.rs | 1 + artiq/firmware/libboard/sdram.rs | 32 ++++++++++++++++++------------- artiq/firmware/runtime/main.rs | 2 +- conda/artiq-dev/meta.yaml | 2 +- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 91e101f08..2507cf14f 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -158,6 +158,7 @@ fn network_boot() { println!("Using MAC address {} and IP address {}", eth_addr, ip_addr); + #[allow(unused_mut)] let mut net_device = unsafe { ethmac::EthernetDevice::new() }; #[cfg(has_ethphy)] diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index fbedacff2..f924f2df1 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -8,13 +8,6 @@ mod ddr { DFII_COMMAND_WRDATA, DFII_COMMAND_RDDATA}; use sdram_phy::{DFII_NPHASES, DFII_PIX_DATA_SIZE, DFII_PIX_WRDATA_ADDR, DFII_PIX_RDDATA_ADDR}; - unsafe fn enable_write_leveling(enabled: bool) { - dfii::pi0_address_write(sdram_phy::DDR3_MR1 as u16 | ((enabled as u16) << 7)); - dfii::pi0_baddress_write(1); - sdram_phy::command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - ddrphy::wlevel_en_write(enabled as u8); - } - #[cfg(kusddrphy)] const DDRPHY_MAX_DELAY: u16 = 512; #[cfg(not(kusddrphy))] @@ -30,6 +23,15 @@ mod ddr { ) } + #[cfg(ddrphy_wlevel)] + unsafe fn enable_write_leveling(enabled: bool) { + dfii::pi0_address_write(sdram_phy::DDR3_MR1 as u16 | ((enabled as u16) << 7)); + dfii::pi0_baddress_write(1); + sdram_phy::command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); + ddrphy::wlevel_en_write(enabled as u8); + } + + #[cfg(ddrphy_wlevel)] unsafe fn write_level(logger: &mut Option<&mut fmt::Write>, delay: &mut [u16; DQS_SIGNAL_COUNT], high_skew: &mut [bool; DQS_SIGNAL_COUNT]) -> bool { @@ -102,6 +104,7 @@ mod ddr { !failed } + #[cfg(ddrphy_wlevel)] unsafe fn read_bitslip(logger: &mut Option<&mut fmt::Write>, delay: &[u16; DQS_SIGNAL_COUNT], high_skew: &[bool; DQS_SIGNAL_COUNT]) { @@ -238,13 +241,16 @@ mod ddr { } pub unsafe fn level(logger: &mut Option<&mut fmt::Write>) -> bool { - let mut delay = [0; DQS_SIGNAL_COUNT]; - let mut high_skew = [false; DQS_SIGNAL_COUNT]; - - if !write_level(logger, &mut delay, &mut high_skew) { - return false + #[cfg(ddrphy_wlevel)] + { + let mut delay = [0; DQS_SIGNAL_COUNT]; + let mut high_skew = [false; DQS_SIGNAL_COUNT]; + if !write_level(logger, &mut delay, &mut high_skew) { + return false + } + read_bitslip(logger, &delay, &high_skew); } - read_bitslip(logger, &delay, &high_skew); + read_delays(logger); true diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 37c455b78..378d44f07 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -148,7 +148,7 @@ fn startup_ethernet() { } } - let mut net_device = unsafe { ethmac::EthernetDevice::new() }; + let net_device = unsafe { ethmac::EthernetDevice::new() }; // fn _net_trace_writer(timestamp: u64, printer: smoltcp::wire::PrettyPrinter) // where U: smoltcp::wire::pretty_print::PrettyPrint { diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 36be45c37..f0fa8bc93 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6.dev py35_61+git31c446b - - misoc 0.8.dev py35_52+gitddbf9cbd + - misoc 0.8.dev py35_57+git3bfb128a - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From 9c6a7f7509026e47daf9dda5f5c553f3986f05fc Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 9 Jan 2018 18:54:05 +0100 Subject: [PATCH 0175/2457] serwb/kusphy: use same serwb_serdes_5x reset than s7phy --- artiq/gateware/serwb/kusphy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/serwb/kusphy.py b/artiq/gateware/serwb/kusphy.py index 51a08a6d8..054971612 100644 --- a/artiq/gateware/serwb/kusphy.py +++ b/artiq/gateware/serwb/kusphy.py @@ -48,7 +48,7 @@ class KUSSerdes(Module): self.cd_serwb_serdes_20x.clk.eq(pll.serwb_serdes_20x_clk) ] self.specials += AsyncResetSynchronizer(self.cd_serwb_serdes, ~pll.lock) - self.specials += AsyncResetSynchronizer(self.cd_serwb_serdes_5x, ~pll.lock) + self.comb += self.cd_serwb_serdes_5x.rst.eq(self.cd_serwb_serdes.rst) # control/status cdc tx_idle = Signal() From 2009734b3c61f7dab760ab5bc4a75ab66771a7fe Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 9 Jan 2018 18:54:52 +0100 Subject: [PATCH 0176/2457] serwb/phy: get 625Mbps linerate working, increase timeout --- artiq/gateware/serwb/phy.py | 38 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index 556b53709..b6436cdca 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -17,7 +17,7 @@ from artiq.gateware.serwb.s7phy import S7Serdes # 6) Link is ready. class _SerdesMasterInit(Module): - def __init__(self, serdes, taps, timeout=1024): + def __init__(self, serdes, taps, timeout=4096): self.reset = Signal() self.ready = Signal() self.error = Signal() @@ -153,7 +153,7 @@ class _SerdesMasterInit(Module): class _SerdesSlaveInit(Module, AutoCSR): - def __init__(self, serdes, taps, timeout=1024): + def __init__(self, serdes, taps, timeout=4096): self.reset = Signal() self.ready = Signal() self.error = Signal() @@ -174,7 +174,7 @@ class _SerdesSlaveInit(Module, AutoCSR): self.comb += serdes.rx_delay_inc.eq(1) - self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) + self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", NextValue(delay, 0), NextValue(delay_min, 0), @@ -313,8 +313,8 @@ class _SerdesControl(Module, AutoCSR): class SERWBPLL(Module): def __init__(self, refclk_freq, linerate, vco_div=1): - assert refclk_freq == 125e6 - assert linerate == 1.25e9 + assert refclk_freq in [62.5e6, 125e6] + assert linerate in [625e6, 1.25e9] self.lock = Signal() self.refclk = Signal() @@ -324,16 +324,11 @@ class SERWBPLL(Module): # # # - #---------------------------- - # refclk: 125MHz - # vco: 1250MHz - #---------------------------- - # serwb_serdes: 31.25MHz - # serwb_serdes_20x: 625MHz - # serwb_serdes_5x: 156.25MHz - #---------------------------- self.linerate = linerate + refclk_mult = 125e6//refclk_freq + linerate_div = 1.25e9//linerate + pll_locked = Signal() pll_fb = Signal() pll_serwb_serdes_clk = Signal() @@ -344,21 +339,21 @@ class SERWBPLL(Module): p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, # VCO @ 1.25GHz / vco_div - p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=8.0, - p_CLKFBOUT_MULT=10, p_DIVCLK_DIVIDE=vco_div, + p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=8.0*refclk_mult, + p_CLKFBOUT_MULT=10*refclk_mult, p_DIVCLK_DIVIDE=vco_div, i_CLKIN1=self.refclk, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, - # 31.25MHz: serwb_serdes - p_CLKOUT0_DIVIDE=40//vco_div, p_CLKOUT0_PHASE=0.0, + # serwb_serdes + p_CLKOUT0_DIVIDE=linerate_div*40//vco_div, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_serwb_serdes_clk, - # 625MHz: serwb_serdes_20x - p_CLKOUT1_DIVIDE=2//vco_div, p_CLKOUT1_PHASE=0.0, + # serwb_serdes_20x + p_CLKOUT1_DIVIDE=linerate_div*2//vco_div, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=pll_serwb_serdes_20x_clk, - # 156.25MHz: serwb_serdes_5x - p_CLKOUT2_DIVIDE=8//vco_div, p_CLKOUT2_PHASE=0.0, + # serwb_serdes_5x + p_CLKOUT2_DIVIDE=linerate_div*8//vco_div, p_CLKOUT2_PHASE=0.0, o_CLKOUT2=pll_serwb_serdes_5x_clk ), Instance("BUFG", @@ -374,7 +369,6 @@ class SERWBPLL(Module): self.specials += MultiReg(pll_locked, self.lock) - class SERWBPHY(Module, AutoCSR): cd = "serwb_serdes" def __init__(self, device, pll, pads, mode="master"): From 16832291eb11d5f8b7a2e88a38b1bf1aec65ca21 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 10 Jan 2018 01:25:53 +0000 Subject: [PATCH 0177/2457] doc: update Rust version. [ci skip] --- doc/manual/developing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index 912c19dd2..931795a15 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -102,7 +102,7 @@ and the ARTIQ kernels. * Install Rust: :: $ cd ~/artiq-dev - $ git clone -b artiq-1.22.1 https://github.com/m-labs/rust + $ git clone -b artiq-1.23.0 https://github.com/m-labs/rust $ cd rust $ git submodule update --init $ mkdir build From 0ce63e7f4ae5632bd1cf6c37b058de58a9b85895 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 10 Jan 2018 01:27:10 +0000 Subject: [PATCH 0178/2457] doc: Rust uses recursive submodules (brrr). [ci skip] --- doc/manual/developing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index 931795a15..8b2f20e96 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -104,7 +104,7 @@ and the ARTIQ kernels. $ cd ~/artiq-dev $ git clone -b artiq-1.23.0 https://github.com/m-labs/rust $ cd rust - $ git submodule update --init + $ git submodule update --init --recursive $ mkdir build $ cd build $ ../configure --prefix=/usr/local/rust-or1k --llvm-root=/usr/local/llvm-or1k --disable-manage-submodules --disable-docs From 04b2fd3e13ef70e26900b702b1084fb20af15c3b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Jan 2018 12:11:33 +0800 Subject: [PATCH 0179/2457] sayma: fix AD9154NoSAWG ramp clock domain --- artiq/gateware/targets/sayma_amc_standalone.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc_standalone.py b/artiq/gateware/targets/sayma_amc_standalone.py index 7a4de3d3c..82fcfdc51 100755 --- a/artiq/gateware/targets/sayma_amc_standalone.py +++ b/artiq/gateware/targets/sayma_amc_standalone.py @@ -107,7 +107,7 @@ class AD9154NoSAWG(Module, AutoCSR): for i, conv in enumerate(self.jesd.core.sink.flatten()): ramp = Signal(16) - self.sync += ramp.eq(ramp + (1 << 9 + i)) + self.sync.rtio += ramp.eq(ramp + (1 << 9 + i)) self.comb += conv.eq(Cat(ramp for i in range(len(conv) // len(ramp)))) From 94d51d1364ee4e0b3cf42004231c45c812814a47 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Jan 2018 12:15:23 +0800 Subject: [PATCH 0180/2457] firmware: fix drtio_dbg module syntax --- artiq/firmware/ksupport/rtio.rs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index be9106348..f53243b46 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -193,23 +193,22 @@ mod imp { pub use self::imp::*; pub mod drtio_dbg { - use ::send; - use ::recv; - use kernel_proto::*; + use ::send; + use ::recv; + use kernel_proto::*; - #[repr(C)] - pub struct PacketCounts(i32, i32); + #[repr(C)] + pub struct PacketCounts(i32, i32); - pub extern fn get_packet_counts(linkno: i32) -> PacketCounts { - send(&DrtioPacketCountRequest { linkno: linkno as u8 }); - recv!(&DrtioPacketCountReply { tx_cnt, rx_cnt } - => PacketCounts(tx_cnt as i32, rx_cnt as i32)) - } + pub extern fn get_packet_counts(linkno: i32) -> PacketCounts { + send(&DrtioPacketCountRequest { linkno: linkno as u8 }); + recv!(&DrtioPacketCountReply { tx_cnt, rx_cnt } + => PacketCounts(tx_cnt as i32, rx_cnt as i32)) + } - pub extern fn get_buffer_space_req_count(linkno: i32) -> i32 { - send(&DrtioBufferSpaceReqCountRequest { linkno: linkno as u8 }); - recv!(&DrtioBufferSpaceReqCountReply { cnt } - => cnt as i32) - } + pub extern fn get_buffer_space_req_count(linkno: i32) -> i32 { + send(&DrtioBufferSpaceReqCountRequest { linkno: linkno as u8 }); + recv!(&DrtioBufferSpaceReqCountReply { cnt } + => cnt as i32) } } From 7c82fcf41af10c32eecd88412e6f196ef0af34ab Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 11 Jan 2018 11:21:55 +0800 Subject: [PATCH 0181/2457] targets: avoid passing cpu_type around unnecessarily --- artiq/gateware/targets/kasli.py | 8 ++++---- artiq/gateware/targets/kc705_dds.py | 12 ++++++------ artiq/gateware/targets/kc705_sma_spi.py | 4 ++-- artiq/gateware/targets/sayma_amc_standalone.py | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index c4c90561d..0e0346c12 100644 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -80,9 +80,9 @@ class _KasliBase(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, cpu_type="or1k", **kwargs): + def __init__(self, **kwargs): MiniSoC.__init__(self, - cpu_type=cpu_type, + cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, ident=artiq_version, @@ -147,8 +147,8 @@ class Opticlock(_KasliBase): """ Opticlock extension configuration """ - def __init__(self, cpu_type="or1k", **kwargs): - _KasliBase.__init__(self, cpu_type, **kwargs) + def __init__(self, **kwargs): + _KasliBase.__init__(self, **kwargs) platform = self.platform platform.add_extension(_dio("eem0")) diff --git a/artiq/gateware/targets/kc705_dds.py b/artiq/gateware/targets/kc705_dds.py index bb6a662eb..31baed85e 100755 --- a/artiq/gateware/targets/kc705_dds.py +++ b/artiq/gateware/targets/kc705_dds.py @@ -210,9 +210,9 @@ class _NIST_Ions(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, cpu_type="or1k", **kwargs): + def __init__(self, **kwargs): MiniSoC.__init__(self, - cpu_type=cpu_type, + cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, ident=artiq_version, @@ -277,8 +277,8 @@ class NIST_CLOCK(_NIST_Ions): """ NIST clock hardware, with old backplane and 11 DDS channels """ - def __init__(self, cpu_type="or1k", **kwargs): - _NIST_Ions.__init__(self, cpu_type, **kwargs) + def __init__(self, **kwargs): + _NIST_Ions.__init__(self, **kwargs) platform = self.platform platform.add_extension(nist_clock.fmc_adapter_io) @@ -379,8 +379,8 @@ class NIST_QC2(_NIST_Ions): NIST QC2 hardware, as used in Quantum I and Quantum II, with new backplane and 24 DDS channels. Two backplanes are used. """ - def __init__(self, cpu_type="or1k", **kwargs): - _NIST_Ions.__init__(self, cpu_type, **kwargs) + def __init__(self, **kwargs): + _NIST_Ions.__init__(self, **kwargs) platform = self.platform platform.add_extension(nist_qc2.fmc_adapter_io) diff --git a/artiq/gateware/targets/kc705_sma_spi.py b/artiq/gateware/targets/kc705_sma_spi.py index 63f91a3a5..cd1a705e5 100755 --- a/artiq/gateware/targets/kc705_sma_spi.py +++ b/artiq/gateware/targets/kc705_sma_spi.py @@ -81,8 +81,8 @@ class SMA_SPI(_NIST_Ions): """ SPI on 4 SMA for PDQ2 test/demo. """ - def __init__(self, cpu_type="or1k", **kwargs): - _NIST_Ions.__init__(self, cpu_type, **kwargs) + def __init__(self, **kwargs): + _NIST_Ions.__init__(self, **kwargs) platform = self.platform self.platform.add_extension(_sma_spi) diff --git a/artiq/gateware/targets/sayma_amc_standalone.py b/artiq/gateware/targets/sayma_amc_standalone.py index 82fcfdc51..7c8429175 100755 --- a/artiq/gateware/targets/sayma_amc_standalone.py +++ b/artiq/gateware/targets/sayma_amc_standalone.py @@ -122,9 +122,9 @@ class Standalone(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, cpu_type="or1k", with_sawg=False, **kwargs): + def __init__(self, with_sawg=False, **kwargs): MiniSoC.__init__(self, - cpu_type=cpu_type, + cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, ident=artiq_version, From 5a79c9bc09cfff496875c5b54a1f62348e4f6190 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 11 Jan 2018 11:38:06 +0800 Subject: [PATCH 0182/2457] RELEASE_NOTES: add SED --- RELEASE_NOTES.rst | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 19f2e71b9..525455f53 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -3,9 +3,16 @@ Release notes ============= -4.0 (unreleased) ----------------- +4.0 +--- +* RTIO outputs use a new architecture called Scalable Event Dispatcher (SED), + which allows building systems with large number of RTIO channels more + efficiently. + From the user perspective, collision errors become asynchronous, and non- + monotonic timestamps on any combination of channels are generally allowed + (instead of producing sequence errors). + RTIO inputs are not affected. * The DDS channel number for the NIST CLOCK target has changed. * The dashboard configuration files are now stored one-per-master, keyed by the server address argument and the notify port. From 7429ee4fb63316b05da07407d6802670ebdb80fd Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Thu, 11 Jan 2018 23:34:59 +0000 Subject: [PATCH 0183/2457] firmware: make read leveling robust for KUS SDRAM Increases the initial delay step into the valid read window as with the original delay I was not getting out of the noisy transition window, as evidenced by seeing read delay windows of only 8 LSB ~10% of the time, leading to failing memory tests --- artiq/firmware/libboard/sdram.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index f924f2df1..f2b320c93 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -207,7 +207,7 @@ mod ddr { // Get a bit further into the working zone #[cfg(kusddrphy)] - for _ in 0..8 { + for _ in 0..16 { delay.set(delay.get() + 1); ddrphy::rdly_dq_inc_write(1); } From ac3c3871d07118a84b4ce9982f3c9f10b64b1721 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 12 Jan 2018 12:29:42 +0100 Subject: [PATCH 0184/2457] kasli: s/extensions/variant/g --- artiq/gateware/targets/kasli.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 0e0346c12..e17445987 100644 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -145,7 +145,7 @@ def _dio(eem): class Opticlock(_KasliBase): """ - Opticlock extension configuration + Opticlock extension variant configuration """ def __init__(self, **kwargs): _KasliBase.__init__(self, **kwargs) @@ -183,16 +183,16 @@ def main(): description="ARTIQ device binary builder for Kasli systems") builder_args(parser) soc_kasli_args(parser) - parser.add_argument("-E", "--extensions", default="opticlock", - help="extension setup: opticlock " + parser.add_argument("--variant", default="opticlock", + help="extension variant setup: opticlock " "(default: %(default)s)") args = parser.parse_args() - extensions = args.extensions.lower() - if extensions == "opticlock": + variant = args.variant.lower() + if variant == "opticlock": cls = Opticlock else: - raise SystemExit("Invalid hardware adapter string (-E/--extensions)") + raise SystemExit("Invalid hardware adapter string (--variant)") soc = cls(**soc_kasli_argdict(args)) build_artiq_soc(soc, builder_argdict(args)) From 529033e016fffc69c20895348e037370faf78d20 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 12 Jan 2018 12:03:50 +0000 Subject: [PATCH 0185/2457] kernel_cpu: disable PCU * contributes to long timing paths on artix 7 (kasli) * currently only used for testing and debugging --- artiq/gateware/amp/kernel_cpu.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/artiq/gateware/amp/kernel_cpu.py b/artiq/gateware/amp/kernel_cpu.py index 62a1f6f16..b1c06517e 100644 --- a/artiq/gateware/amp/kernel_cpu.py +++ b/artiq/gateware/amp/kernel_cpu.py @@ -25,9 +25,7 @@ class KernelCPU(Module): self.submodules.cpu = ClockDomainsRenamer("sys_kernel")( mor1kx.MOR1KX( platform, - OPTION_RESET_PC=exec_address, - FEATURE_PERFCOUNTERS="ENABLED", - OPTION_PERFCOUNTERS_NUM=7)) + OPTION_RESET_PC=exec_address)) # DRAM access self.wb_sdram = wishbone.Interface() From 6891141fa6e19b030c75ae200c51eacb39612f09 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 15 Jan 2018 11:43:29 +0000 Subject: [PATCH 0186/2457] artiq_flash: add sayma support. --- DEVELOPER_NOTES.rst | 7 +- artiq/frontend/artiq_devtool.py | 146 ++++++++++++++++++---------- artiq/gateware/targets/sayma_rtm.py | 24 ++++- 3 files changed, 120 insertions(+), 57 deletions(-) diff --git a/DEVELOPER_NOTES.rst b/DEVELOPER_NOTES.rst index 460a16d05..3c6724f9a 100644 --- a/DEVELOPER_NOTES.rst +++ b/DEVELOPER_NOTES.rst @@ -34,7 +34,8 @@ To avoid conflicts for development boards on the server, while using a board you To lock the KC705 for 30 minutes or until Ctrl-C is pressed: :: - flock --verbose /run/boards/kc705 sleep 1800 + flock --verbose /run/boards/kc705_1 sleep 1800 + Check that the command acquires the lock, i.e. prints something such as: :: flock: getting lock took 0.000003 seconds @@ -42,7 +43,7 @@ Check that the command acquires the lock, i.e. prints something such as: To lock the KC705 for the duration of the execution of a shell: :: - flock /run/boards/kc705 bash + flock /run/boards/kc705_1 bash You may also use this script: :: @@ -53,7 +54,7 @@ If the board is already locked by another user, the ``flock`` commands above wil To determine which user is locking a board, use: :: - fuser -v /run/boards/kc705 + fuser -v /run/boards/kc705_1 Selecting a development board with artiq_flash diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index fa3236fd7..021b51f9c 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -22,30 +22,33 @@ def get_argparser(): verbosity_args(parser) - parser.add_argument("-H", "--host", metavar="HOSTNAME", - type=str, default="lab.m-labs.hk", - help="SSH host where the development board is located") - parser.add_argument("-D", "--device", metavar="HOSTNAME", - type=str, default="kc705.lab.m-labs.hk", - help="address or domain corresponding to the development board") - parser.add_argument("-s", "--serial", metavar="PATH", - type=str, default="/dev/ttyUSB_kc705", - help="TTY device corresponding to the development board") - parser.add_argument("-l", "--lockfile", metavar="PATH", - type=str, default="/run/boards/kc705", - help="The lockfile to be acquired for the duration of the actions") - parser.add_argument("-w", "--wait", action="store_true", - help="Wait for the board to unlock instead of aborting the actions") parser.add_argument("-t", "--target", metavar="TARGET", type=str, default="kc705_dds", help="Target to build, one of: " - "kc705_dds kasli sayma_amc_standalone " + "kc705_dds kasli sayma_rtm sayma_amc_standalone " "sayma_amc_drtio_master sayma_amc_drtio_satellite") + parser.add_argument("-H", "--host", metavar="HOSTNAME", + type=str, default="lab.m-labs.hk", + help="SSH host where the development board is located") + parser.add_argument('-b', "--board", metavar="BOARD", + type=str, default=None, + help="Board to connect to on the development SSH host") + parser.add_argument("-d", "--device", metavar="DEVICENAME", + type=str, default="{board}.{hostname}", + help="Address or domain corresponding to the development board") + parser.add_argument("-s", "--serial", metavar="SERIAL", + type=str, default="/dev/ttyUSB_{board}", + help="TTY device corresponding to the development board") + parser.add_argument("-l", "--lockfile", metavar="LOCKFILE", + type=str, default="/run/boards/{board}", + help="The lockfile to be acquired for the duration of the actions") + parser.add_argument("-w", "--wait", action="store_true", + help="Wait for the board to unlock instead of aborting the actions") parser.add_argument("actions", metavar="ACTION", type=str, default=[], nargs="+", help="actions to perform, sequence of: " - "build boot boot+log connect reset hotswap clean") + "build clean reset flash flash+log hotswap") return parser @@ -56,19 +59,47 @@ def main(): if args.verbose == args.quiet == 0: logging.getLogger().setLevel(logging.INFO) - if args.target in ["kc705_dds", "kasli", "sayma_amc_standalone", "sayma_amc_drtio_master"]: - firmware = "runtime" + build_args = [] + if args.target == "kc705_dds": + boardtype, firmware = "kc705", "runtime" + elif args.target == "sayma_amc_standalone": + boardtype, firmware = "sayma", "runtime" + build_args += ["--rtm-csr-csv", "/tmp/sayma_rtm/sayma_rtm_csr.csv"] + elif args.target == "sayma_amc_drtio_master": + boardtype, firmware = "sayma", "runtime" elif args.target == "sayma_amc_drtio_satellite": - firmware = "satman" + boardtype, firmware = "sayma", "satman" + elif args.target == "sayma_rtm": + boardtype, firmware = "sayma_rtm", None else: raise NotImplementedError("unknown target {}".format(args.target)) + flash_args = ["-t", boardtype] + if boardtype == "sayma": + if args.board is None: + args.board = "sayma_1" + if args.board == "sayma_1": + flash_args += ["--preinit-command", "ftdi_location 5:2"] + elif args.board == "sayma_2": + flash_args += ["--preinit-command", "ftdi_location 3:10"] + elif args.board == "sayma_3": + flash_args += ["--preinit-command", "ftdi_location 5:1"] + else: + raise NotImplementedError("unknown --preinit-command for {}".format(boardtype)) + client = SSHClient(args.host) substs = { - "env": "bash -c 'export PATH=$HOME/miniconda/bin:$PATH; exec $0 $*' ", - "serial": args.serial, - "firmware": firmware, + "target": args.target, + "hostname": args.host, + "boardtype": boardtype, + "board": args.board if args.board else boardtype + "_1", + "firmware": firmware, } + substs.update({ + "devicename": args.device.format(**substs), + "lockfile": args.lockfile.format(**substs), + "serial": args.serial.format(**substs), + }) flock_acquired = False flock_file = None # GC root @@ -80,7 +111,7 @@ def main(): logger.info("Acquiring device lock") flock = client.spawn_command("flock --verbose {block} {lockfile} sleep 86400" .format(block="" if args.wait else "--nonblock", - lockfile=args.lockfile), + **substs), get_pty=True) flock_file = flock.makefile('r') while not flock_acquired: @@ -94,44 +125,65 @@ def main(): logger.error("Failed to get lock") sys.exit(1) + def artiq_flash(args, synchronous=True): + args = flash_args + args + args = ["'{}'".format(arg) if " " in arg else arg for arg in args] + cmd = client.spawn_command( + "artiq_flash " + " ".join(args), + **substs) + if synchronous: + client.drain(cmd) + else: + return cmd + for action in args.actions: if action == "build": - logger.info("Building firmware") + logger.info("Building target") try: subprocess.check_call(["python3", "-m", "artiq.gateware.targets." + args.target, "--no-compile-gateware", + *build_args, "--output-dir", - "/tmp/{target}".format(target=args.target)]) + "/tmp/{target}".format(**substs)]) except subprocess.CalledProcessError: logger.error("Build failed") sys.exit(1) elif action == "clean": logger.info("Cleaning build directory") - target_dir = "/tmp/{target}".format(target=args.target) + target_dir = "/tmp/{target}".format(**substs) if os.path.isdir(target_dir): shutil.rmtree(target_dir) - elif action == "boot" or action == "boot+log": - lock() + elif action == "reset": + logger.info("Resetting device") + artiq_flash(["reset"]) - logger.info("Uploading firmware") - client.get_sftp().put("/tmp/{target}/software/{firmware}/{firmware}.bin" - .format(target=args.target, firmware=firmware), - "{tmp}/{firmware}.bin" - .format(tmp=client.tmp, firmware=firmware)) + elif action == "flash" or action == "flash+log": + def upload_product(product, ext): + logger.info("Uploading {}".format(product)) + client.get_sftp().put("/tmp/{target}/software/{product}/{product}.{ext}" + .format(target=args.target, product=product, ext=ext), + "{tmp}/{product}.{ext}" + .format(tmp=client.tmp, product=product, ext=ext)) - logger.info("Booting firmware") - flterm = client.spawn_command( - "{env} python3 flterm.py {serial} " + - "--kernel {tmp}/{firmware}.bin " + - ("--upload-only" if action == "boot" else "--output-only"), - **substs) - artiq_flash = client.spawn_command( - "{env} artiq_flash start", - **substs) - client.drain(flterm) + upload_product("bootloader", "bin") + upload_product(firmware, "fbi") + + logger.info("Flashing firmware") + artiq_flash(["-d", "{tmp}", "proxy", "bootloader", "firmware", + "start" if action == "flash" else ""]) + + if action == "flash+log": + logger.info("Booting firmware") + flterm = client.spawn_command( + "flterm {serial} " + + "--kernel {tmp}/{firmware}.bin " + + ("--upload-only" if action == "boot" else "--output-only"), + **substs) + artiq_flash(["start"], synchronous=False) + client.drain(flterm) elif action == "connect": lock() @@ -187,13 +239,7 @@ def main(): logger.info("Forwarding ports {} to core device and logs from core device" .format(", ".join(map(str, ports)))) client.run_command( - "{env} python3 flterm.py {serial} --output-only", - **substs) - - elif action == "reset": - logger.info("Resetting device") - client.run_command( - "{env} artiq_flash start", + "flterm {serial} --output-only", **substs) elif action == "hotswap": diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 0632592b1..c438d469d 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import os +import argparse from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer @@ -182,13 +183,28 @@ class SaymaRTM(Module): def main(): - build_dir = "artiq_sayma_rtm" + parser = argparse.ArgumentParser( + description="ARTIQ device binary builder for Kasli systems") + parser.add_argument("--output-dir", default="artiq_sayma_rtm", + help="output directory for generated " + "source files and binaries") + parser.add_argument("--no-compile-gateware", action="store_true", + help="do not compile the gateware, only generate " + "the CSR map") + parser.add_argument("--csr-csv", default=None, + help="store CSR map in CSV format into the " + "specified file") + args = parser.parse_args() + platform = sayma_rtm.Platform() top = SaymaRTM(platform) - os.makedirs(build_dir, exist_ok=True) - with open(os.path.join(build_dir, "sayma_rtm_csr.csv"), "w") as f: + + os.makedirs(args.output_dir, exist_ok=True) + with open(os.path.join(args.output_dir, "sayma_rtm_csr.csv"), "w") as f: f.write(get_csr_csv(top.csr_regions)) - platform.build(top, build_dir=build_dir) + + if not args.no_compile_gateware: + platform.build(top, build_dir=args.output_dir) if __name__ == "__main__": From fe44b6651a646fbadfaa268c4e458d21ea68e253 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 15 Jan 2018 10:29:48 +0000 Subject: [PATCH 0187/2457] conda: bump misoc (1000basex) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index f0fa8bc93..2d0096e90 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6.dev py35_61+git31c446b - - misoc 0.8.dev py35_57+git3bfb128a + - misoc 0.8 py35_9+git45dcca87 - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From 8a960c1b316c61722786c6e230efa858a816baab Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 15 Jan 2018 11:13:01 +0000 Subject: [PATCH 0188/2457] conda: bump openocd (kasli) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 2d0096e90..e24f987a9 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -22,7 +22,7 @@ requirements: - llvm-or1k 4.0.1 - llvmlite-artiq 0.20.0 - rust-core-or1k 1.23.0 19 - - openocd 0.10.0+git1 + - openocd 0.10.0+git2 - lit - outputcheck - coverage From 1c15124c5e28d5afed5523facc59fef7839ad09c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 15 Jan 2018 12:59:11 +0000 Subject: [PATCH 0189/2457] artiq_flash: add kasli --- artiq/frontend/artiq_flash.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index eebbd9b8d..a2b41451c 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -198,6 +198,15 @@ def main(): "storage": (0, 0xb30000), "firmware": (0, 0xb40000), }, + "kasli": { + "programmer_factory": partial(ProgrammerJtagSpi7, "kasli"), + "proxy_bitfile": "bscan_spi_xc7a100t.bit", + "variants": ["opticlock"], + "gateware": (0, 0x000000), + "bootloader": (0, 0x400000), + "storage": (0, 0x440000), + "firmware": (0, 0x450000), + }, "sayma": { "programmer_factory": ProgrammerSayma, "proxy_bitfile": "bscan_spi_xcku040-sayma.bit", From 344ce7e294530c24b254b3b223fe1f315b1f9ac2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 15 Jan 2018 13:17:12 +0000 Subject: [PATCH 0190/2457] conda: bump misoc (kasli sfp) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index e24f987a9..4af518058 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6.dev py35_61+git31c446b - - misoc 0.8 py35_9+git45dcca87 + - misoc 0.8 py35_12+git172a6c87 - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From ef40fb93c2d7b16348065f6b5237c887d1801bc2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 15 Jan 2018 15:04:46 +0100 Subject: [PATCH 0191/2457] conda: add artiq-kasli-opticlock --- conda/artiq-kasli-opticlock/build.sh | 9 +++++++++ conda/artiq-kasli-opticlock/meta.yaml | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 conda/artiq-kasli-opticlock/build.sh create mode 100644 conda/artiq-kasli-opticlock/meta.yaml diff --git a/conda/artiq-kasli-opticlock/build.sh b/conda/artiq-kasli-opticlock/build.sh new file mode 100644 index 000000000..fcf6dc5ee --- /dev/null +++ b/conda/artiq-kasli-opticlock/build.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/kasli-opticlock +mkdir -p $SOC_PREFIX + +V=1 $PYTHON -m artiq.gateware.targets.kasli --variant opticlock +cp misoc_opticlock_kasli/gateware/top.bit $SOC_PREFIX +cp misoc_opticlock_kasli/software/bootloader/bootloader.bin $SOC_PREFIX +cp misoc_opticlock_kasli/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-kasli-opticlock/meta.yaml b/conda/artiq-kasli-opticlock/meta.yaml new file mode 100644 index 000000000..57acc34f7 --- /dev/null +++ b/conda/artiq-kasli-opticlock/meta.yaml @@ -0,0 +1,23 @@ +package: + name: artiq-kasli-opticlock + version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} + +source: + git_url: ../.. + +build: + noarch: generic + ignore_prefix_files: True + number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} + string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} + +requirements: + build: + - artiq-dev {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} + run: + - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} + +about: + home: https://m-labs.hk/artiq + license: LGPL + summary: 'Bitstream, BIOS and runtime for the opticlock variant of Kasli' From 21cd24fe80a22015466bb92e49a012b3413f1e1b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 15 Jan 2018 15:13:24 +0100 Subject: [PATCH 0192/2457] manual: add section on Kasli/opticlock --- doc/manual/core_device.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index 43f787eeb..72def13d5 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -158,3 +158,22 @@ The QC2 hardware uses TCA6424A I2C I/O expanders to define the directions of its To avoid I/O contention, the startup kernel should first program the TCA6424A expanders and then call ``output()`` on all ``TTLInOut`` channels that should be configured as outputs. See :mod:`artiq.coredevice.i2c` for more details. + +Kasli +----- + +`Kasli `_ is a versatile coredevice designed for ARTIQ as part of the `Sinara `_ family of boards. + +Opticlock ++++++++++ + +In the opticlock variant, Kasli is the coredevice controlling three `DIO_BNC `_ boards, one `Urukul-AD9912 `_, one `Urukul-AD9910 `_, and one Sampler ``_. + +Kasli is connected to the network using a 1000Base-X SFP module. `No-name +`_ BiDi (1000Base-BX) modules have been used successfully. + +Kasli is supplied with 100 MHz reference at its SMA input. +Both Urukul boards are supplied with a 100 MHz reference clock on their external +SMA inputs. + +The first four TTL channels are used as inputs. The rest are outputs. From fd82a1a9af301f2f3679389c1c56a916268feebb Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 15 Jan 2018 16:14:58 +0100 Subject: [PATCH 0193/2457] conda: bump migen (kasli) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 4af518058..4c31746dc 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.6.dev py35_61+git31c446b + - migen 0.6.dev py35_64+gitc6ffa44 - misoc 0.8 py35_12+git172a6c87 - jesd204b 0.4 - microscope From d52568e254ddeb5e29efb4d2f15f8b538a025d0f Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 15 Jan 2018 16:41:24 +0100 Subject: [PATCH 0194/2457] conda: bump migen (kasli link_up) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 4c31746dc..76031427b 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6.dev py35_64+gitc6ffa44 - - misoc 0.8 py35_12+git172a6c87 + - misoc 0.8 py35_14+git97f1b8a6 - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From 5b03cc2fae256595bcf5fb5cb8d4d02dcc2ad671 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 15 Jan 2018 21:53:40 +0100 Subject: [PATCH 0195/2457] gateware/test/serwb: update and cleanup tests --- artiq/gateware/test/serwb/test_etherbone.py | 70 ---------- artiq/gateware/test/serwb/test_serwb_core.py | 128 ++++++++++++++++++ ...t_serwb_phy_init.py => test_serwb_init.py} | 3 +- 3 files changed, 129 insertions(+), 72 deletions(-) delete mode 100644 artiq/gateware/test/serwb/test_etherbone.py create mode 100644 artiq/gateware/test/serwb/test_serwb_core.py rename artiq/gateware/test/serwb/{test_serwb_phy_init.py => test_serwb_init.py} (98%) diff --git a/artiq/gateware/test/serwb/test_etherbone.py b/artiq/gateware/test/serwb/test_etherbone.py deleted file mode 100644 index 963769a1f..000000000 --- a/artiq/gateware/test/serwb/test_etherbone.py +++ /dev/null @@ -1,70 +0,0 @@ -import unittest -import random - -from migen import * - -from misoc.interconnect.wishbone import SRAM -from misoc.interconnect.stream import Converter - -from artiq.gateware.serwb import packet -from artiq.gateware.serwb import etherbone - - -class DUT(Module): - def __init__(self): - # wishbone slave - slave_depacketizer = packet.Depacketizer(int(100e6)) - slave_packetizer = packet.Packetizer() - self.submodules += slave_depacketizer, slave_packetizer - slave_etherbone = etherbone.Etherbone(mode="slave") - self.submodules += slave_etherbone - self.comb += [ - slave_depacketizer.source.connect(slave_etherbone.sink), - slave_etherbone.source.connect(slave_packetizer.sink) - ] - - # wishbone master - master_depacketizer = packet.Depacketizer(int(100e6)) - master_packetizer = packet.Packetizer() - self.submodules += master_depacketizer, master_packetizer - master_etherbone = etherbone.Etherbone(mode="master") - master_sram = SRAM(64, bus=master_etherbone.wishbone.bus) - self.submodules += master_etherbone, master_sram - self.comb += [ - master_depacketizer.source.connect(master_etherbone.sink), - master_etherbone.source.connect(master_packetizer.sink) - ] - - # connect core directly with converters in the loop - s2m_downconverter = Converter(32, 16) - s2m_upconverter = Converter(16, 32) - self.submodules += s2m_downconverter, s2m_upconverter - m2s_downconverter = Converter(32, 16) - m2s_upconverter = Converter(16, 32) - self.submodules += m2s_upconverter, m2s_downconverter - self.comb += [ - slave_packetizer.source.connect(s2m_downconverter.sink), - s2m_downconverter.source.connect(s2m_upconverter.sink), - s2m_upconverter.source.connect(master_depacketizer.sink), - - master_packetizer.source.connect(m2s_downconverter.sink), - m2s_downconverter.source.connect(m2s_upconverter.sink), - m2s_upconverter.source.connect(slave_depacketizer.sink) - ] - - # expose wishbone slave - self.wishbone = slave_etherbone.wishbone.bus - - -class TestEtherbone(unittest.TestCase): - def test_write_read_sram(self): - dut = DUT() - prng = random.Random(1) - def generator(dut): - datas = [prng.randrange(0, 2**32-1) for i in range(16)] - for i in range(16): - yield from dut.wishbone.write(i, datas[i]) - for i in range(16): - data = (yield from dut.wishbone.read(i)) - self.assertEqual(data, datas[i]) - run_simulation(dut, generator(dut)) diff --git a/artiq/gateware/test/serwb/test_serwb_core.py b/artiq/gateware/test/serwb/test_serwb_core.py new file mode 100644 index 000000000..c0355d97f --- /dev/null +++ b/artiq/gateware/test/serwb/test_serwb_core.py @@ -0,0 +1,128 @@ +import unittest +import random + +from migen import * + +from artiq.gateware.serwb import scrambler +from artiq.gateware.serwb import SERWBCore + +from misoc.interconnect.wishbone import SRAM + + +class FakeInit(Module): + def __init__(self): + self.ready = 1 + + +class FakeSerdes(Module): + def __init__(self): + self.tx_k = Signal(4) + self.tx_d = Signal(32) + self.rx_k = Signal(4) + self.rx_d = Signal(32) + + +class FakePHY(Module): + cd = "sys" + def __init__(self): + self.init = FakeInit() + self.serdes = FakeSerdes() + + +class DUTScrambler(Module): + def __init__(self): + self.submodules.scrambler = scrambler.Scrambler(sync_interval=16) + self.submodules.descrambler = scrambler.Descrambler() + self.comb += [ + self.scrambler.source.connect(self.descrambler.sink), + self.descrambler.source.ready.eq(1) + ] + + +class DUTCore(Module): + def __init__(self, **kwargs): + # wishbone slave + phy_slave = FakePHY() + serwb_slave = SERWBCore(phy_slave, int(1e6), "slave", **kwargs) + self.submodules += phy_slave, serwb_slave + + # wishbone master + phy_master = FakePHY() + serwb_master = SERWBCore(phy_master, int(1e6), "master", **kwargs) + self.submodules += phy_master, serwb_master + + # connect phy + self.comb += [ + phy_master.serdes.rx_k.eq(phy_slave.serdes.tx_k), + phy_master.serdes.rx_d.eq(phy_slave.serdes.tx_d), + phy_slave.serdes.rx_k.eq(phy_master.serdes.tx_k), + phy_slave.serdes.rx_d.eq(phy_master.serdes.tx_d) + ] + + # add wishbone sram to wishbone master + sram = SRAM(1024, bus=serwb_master.etherbone.wishbone.bus) + self.submodules += sram + + # expose wishbone slave + self.wishbone = serwb_slave.etherbone.wishbone.bus + + +class TestSERWBCore(unittest.TestCase): + def test_scrambler(self): + def generator(dut): + i = 0 + last_data = -1 + while i != 256: + # stim + if (yield dut.scrambler.sink.ready): + i += 1 + yield dut.scrambler.sink.data.eq(i) + + # check + if (yield dut.descrambler.source.valid): + current_data = (yield dut.descrambler.source.data) + if (current_data != (last_data + 1)): + dut.errors += 1 + last_data = current_data + + # cycle + yield + + dut = DUTScrambler() + dut.errors = 0 + run_simulation(dut, generator(dut)) + self.assertEqual(dut.errors, 0) + + def test_serwb(self): + def generator(dut): + # prepare test + prng = random.Random(42) + data_base = 0x100 + data_length = 4 + datas_w = [prng.randrange(2**32) for i in range(data_length)] + datas_r = [] + + # write + for i in range(data_length): + yield from dut.wishbone.write(data_base + i, datas_w[i]) + + # read + for i in range(data_length): + datas_r.append((yield from dut.wishbone.read(data_base + i))) + + # check + for i in range(data_length): + if datas_r[i] != datas_w[i]: + dut.errors += 1 + + # scrambling off + dut = DUTCore(with_scrambling=False) + dut.errors = 0 + run_simulation(dut, generator(dut)) + self.assertEqual(dut.errors, 0) + + # scrambling on + dut = DUTCore(with_scrambling=True) + dut.errors = 0 + run_simulation(dut, generator(dut)) + self.assertEqual(dut.errors, 0) diff --git a/artiq/gateware/test/serwb/test_serwb_phy_init.py b/artiq/gateware/test/serwb/test_serwb_init.py similarity index 98% rename from artiq/gateware/test/serwb/test_serwb_phy_init.py rename to artiq/gateware/test/serwb/test_serwb_init.py index ea807f97d..2e488165f 100644 --- a/artiq/gateware/test/serwb/test_serwb_phy_init.py +++ b/artiq/gateware/test/serwb/test_serwb_init.py @@ -4,7 +4,6 @@ import unittest from migen import * from artiq.gateware.serwb import packet -from artiq.gateware.serwb import etherbone from artiq.gateware.serwb.phy import _SerdesMasterInit, _SerdesSlaveInit @@ -116,7 +115,7 @@ def generator(test, dut, valid_bitslip, valid_delays, check_success): test.assertEqual(error, 1) -class TestPHYInit(unittest.TestCase): +class TestSERWBInit(unittest.TestCase): def test_master_init_success(self): dut = DUTMaster() valid_bitslip = 2 From 702c35821b3e83027aa7e58475e168e89f5ba3cb Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 15 Jan 2018 22:15:35 +0100 Subject: [PATCH 0196/2457] libboard_artiq/ad9154: add dac_status and dac_prbs (untested) --- artiq/firmware/libboard_artiq/ad9154.rs | 108 +++++++++++++++++++++++- 1 file changed, 107 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index c06a2197d..0f38ee321 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -54,7 +54,7 @@ fn jesd_ready(dacno: u8) -> bool { fn jesd_prbs(dacno: u8, en: bool) { unsafe { - (csr::AD9154[dacno as usize].jesd_control_prbs_config_write)(if en {1} else {0}) + (csr::AD9154[dacno as usize].jesd_control_prbs_config_write)(if en {0b01} else {0b00}) } } @@ -392,6 +392,58 @@ fn dac_setup(linerate: u64) -> Result<(), &'static str> { Ok(()) } +fn dac_status() { + info!("SERDES_PLL_LOCK: {}", + (read(ad9154_reg::PLL_STATUS) & ad9154_reg::SERDES_PLL_LOCK_RB)); + info!(""); + info!("CODEGRPSYNC: 0x{:02x}", read(ad9154_reg::CODEGRPSYNCFLG)); + info!("FRAMESYNC: 0x{:02x}", read(ad9154_reg::FRAMESYNCFLG)); + info!("GOODCHECKSUM: 0x{:02x}", read(ad9154_reg::GOODCHKSUMFLG)); + info!("INITLANESYNC: 0x{:02x}", read(ad9154_reg::INITLANESYNCFLG)); + info!(""); + info!("DID_REG: 0x{:02x}", read(ad9154_reg::DID_REG)); + info!("BID_REG: 0x{:02x}", read(ad9154_reg::BID_REG)); + info!("SCR_L_REG: 0x{:02x}", read(ad9154_reg::SCR_L_REG)); + info!("F_REG: 0x{:02x}", read(ad9154_reg::F_REG)); + info!("K_REG: 0x{:02x}", read(ad9154_reg::K_REG)); + info!("M_REG: 0x{:02x}", read(ad9154_reg::M_REG)); + info!("CS_N_REG: 0x{:02x}", read(ad9154_reg::CS_N_REG)); + info!("NP_REG: 0x{:02x}", read(ad9154_reg::NP_REG)); + info!("S_REG: 0x{:02x}", read(ad9154_reg::S_REG)); + info!("HD_CF_REG: 0x{:02x}", read(ad9154_reg::HD_CF_REG)); + info!("RES1_REG: 0x{:02x}", read(ad9154_reg::RES1_REG)); + info!("RES2_REG: 0x{:02x}", read(ad9154_reg::RES2_REG)); + info!("LIDx_REG: 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x}", + read(ad9154_reg::LID0_REG), + read(ad9154_reg::LID1_REG), + read(ad9154_reg::LID2_REG), + read(ad9154_reg::LID3_REG), + read(ad9154_reg::LID4_REG), + read(ad9154_reg::LID5_REG), + read(ad9154_reg::LID6_REG), + read(ad9154_reg::LID7_REG)); + info!("CHECKSUMx_REG: 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x}", + read(ad9154_reg::CHECKSUM0_REG), + read(ad9154_reg::CHECKSUM1_REG), + read(ad9154_reg::CHECKSUM2_REG), + read(ad9154_reg::CHECKSUM3_REG), + read(ad9154_reg::CHECKSUM4_REG), + read(ad9154_reg::CHECKSUM5_REG), + read(ad9154_reg::CHECKSUM6_REG), + read(ad9154_reg::CHECKSUM7_REG)); + info!("COMPSUMx_REG: 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x} 0x{:02x}", + read(ad9154_reg::COMPSUM0_REG), + read(ad9154_reg::COMPSUM1_REG), + read(ad9154_reg::COMPSUM2_REG), + read(ad9154_reg::COMPSUM3_REG), + read(ad9154_reg::COMPSUM4_REG), + read(ad9154_reg::COMPSUM5_REG), + read(ad9154_reg::COMPSUM6_REG), + read(ad9154_reg::COMPSUM7_REG)); + info!("BADDISPARITY: 0x{:02x}", read(ad9154_reg::BADDISPARITY)); + info!("NITDISPARITY: 0x{:02x}", read(ad9154_reg::NIT_W)); +} + fn dac_monitor() { write(ad9154_reg::IRQ_STATUS0, 0x00); write(ad9154_reg::IRQ_STATUS1, 0x00); @@ -435,6 +487,60 @@ fn dac_monitor() { write(ad9154_reg::IRQ_STATUS3, 0x00); } +fn dac_prbs(dacno: u8, p: u8, t: u32) { + /* follow phy prbs testing (p58 of ad9154 datasheet) */ + + /* step 1: start sending prbs pattern from the transmitter */ + jesd_prbs(dacno, true); + + /* step 2: select prbs mode */ + write(ad9154_reg::PHY_PRBS_TEST_CTRL, + p*ad9154_reg::PHY_PRBS_PAT_SEL); + + /* step 3: enable test for all lanes */ + write(ad9154_reg::PHY_PRBS_TEST_EN, 0xff); + + /* step 4: reset */ + write(ad9154_reg::PHY_PRBS_TEST_CTRL, + p*ad9154_reg::PHY_PRBS_PAT_SEL | + 1*ad9154_reg::PHY_TEST_RESET); + write(ad9154_reg::PHY_PRBS_TEST_CTRL, + p*ad9154_reg::PHY_PRBS_PAT_SEL); + + /* step 5: prbs threshold */ + write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_LOBITS, t as u8); + write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_MIDBITS, (t >> 8) as u8); + write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_HIBITS, (t >> 16) as u8); + + /* step 6: start */ + write(ad9154_reg::PHY_PRBS_TEST_CTRL, + p*ad9154_reg::PHY_PRBS_PAT_SEL); + write(ad9154_reg::PHY_PRBS_TEST_CTRL, + p*ad9154_reg::PHY_PRBS_PAT_SEL | + 1*ad9154_reg::PHY_TEST_START); + + /* step 7: wait 500 ms */ + clock::spin_us(500000); + + /* step 8 : stop */ + write(ad9154_reg::PHY_PRBS_TEST_CTRL, + p*ad9154_reg::PHY_PRBS_PAT_SEL); + + info!("prbs_status: {:02x}", read(ad9154_reg::PHY_PRBS_TEST_STATUS)); + for i in 0..8 { + /* step 9.a: select src err */ + write(ad9154_reg::PHY_PRBS_TEST_CTRL, + i*ad9154_reg::PHY_SRC_ERR_CNT); + /* step 9.b: retrieve number of errors */ + info!("prbs errors[{}]: {:06x}", i, + (read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_LOBITS) as u32) | + ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_MIDBITS) as u32) << 8) | + ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_HIBITS) as u32) << 16)); + } + + jesd_prbs(dacno, false); +} + fn dac_cfg(dacno: u8) -> Result<(), &'static str> { spi_setup(dacno); jesd_enable(dacno, false); From 444b901dbec5c9ef50b712043344666a76a30159 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 16 Jan 2018 07:28:00 +0000 Subject: [PATCH 0197/2457] sayma: add RTM configuration port. --- artiq/gateware/targets/sayma_amc_standalone.py | 6 ++++++ conda/artiq-dev/meta.yaml | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc_standalone.py b/artiq/gateware/targets/sayma_amc_standalone.py index 7c8429175..b84ff4d26 100755 --- a/artiq/gateware/targets/sayma_amc_standalone.py +++ b/artiq/gateware/targets/sayma_amc_standalone.py @@ -7,6 +7,7 @@ from collections import namedtuple from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer +from misoc.cores.slave_fpga import SlaveFPGA from misoc.integration.soc_sdram import soc_sdram_args, soc_sdram_argdict from misoc.integration.builder import builder_args, builder_argdict from misoc.interconnect import stream @@ -147,6 +148,11 @@ class Standalone(MiniSoC, AMPSoC): serial_rtm.tx.eq(serial_1.rx) ] + # RTM bitstream upload + rtm_fpga_cfg = platform.request("rtm_fpga_cfg") + self.submodules.rtm_fpga_cfg = SlaveFPGA(rtm_fpga_cfg) + self.csr_devices.append("rtm_fpga_cfg") + # AMC/RTM serwb serwb_pll = serwb.phy.SERWBPLL(125e6, 1.25e9, vco_div=2) self.comb += serwb_pll.refclk.eq(self.crg.cd_sys.clk) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 76031427b..bdb83b29e 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,8 +14,8 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.6.dev py35_64+gitc6ffa44 - - misoc 0.8 py35_14+git97f1b8a6 + - migen 0.6 py35_2+git61a055f + - misoc 0.8 py35_15+gitc5082e52 - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From 44cd7dfa230379ab22dd101bfab17be3b2ce86b5 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 16 Jan 2018 08:09:25 +0000 Subject: [PATCH 0198/2457] conda: update misoc. --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index bdb83b29e..290070c5e 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6 py35_2+git61a055f - - misoc 0.8 py35_15+gitc5082e52 + - misoc 0.8 py35_17+gitb1c66d03 - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From 247167d34aa017e47c97e54823e2ea9e0f1bf977 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 16 Jan 2018 08:21:26 +0000 Subject: [PATCH 0199/2457] Revert "gateware/test/serwb: update and cleanup tests" This reverts commit 5b03cc2fae256595bcf5fb5cb8d4d02dcc2ad671. --- artiq/gateware/test/serwb/test_etherbone.py | 70 ++++++++++ artiq/gateware/test/serwb/test_serwb_core.py | 128 ------------------ ...t_serwb_init.py => test_serwb_phy_init.py} | 3 +- 3 files changed, 72 insertions(+), 129 deletions(-) create mode 100644 artiq/gateware/test/serwb/test_etherbone.py delete mode 100644 artiq/gateware/test/serwb/test_serwb_core.py rename artiq/gateware/test/serwb/{test_serwb_init.py => test_serwb_phy_init.py} (98%) diff --git a/artiq/gateware/test/serwb/test_etherbone.py b/artiq/gateware/test/serwb/test_etherbone.py new file mode 100644 index 000000000..963769a1f --- /dev/null +++ b/artiq/gateware/test/serwb/test_etherbone.py @@ -0,0 +1,70 @@ +import unittest +import random + +from migen import * + +from misoc.interconnect.wishbone import SRAM +from misoc.interconnect.stream import Converter + +from artiq.gateware.serwb import packet +from artiq.gateware.serwb import etherbone + + +class DUT(Module): + def __init__(self): + # wishbone slave + slave_depacketizer = packet.Depacketizer(int(100e6)) + slave_packetizer = packet.Packetizer() + self.submodules += slave_depacketizer, slave_packetizer + slave_etherbone = etherbone.Etherbone(mode="slave") + self.submodules += slave_etherbone + self.comb += [ + slave_depacketizer.source.connect(slave_etherbone.sink), + slave_etherbone.source.connect(slave_packetizer.sink) + ] + + # wishbone master + master_depacketizer = packet.Depacketizer(int(100e6)) + master_packetizer = packet.Packetizer() + self.submodules += master_depacketizer, master_packetizer + master_etherbone = etherbone.Etherbone(mode="master") + master_sram = SRAM(64, bus=master_etherbone.wishbone.bus) + self.submodules += master_etherbone, master_sram + self.comb += [ + master_depacketizer.source.connect(master_etherbone.sink), + master_etherbone.source.connect(master_packetizer.sink) + ] + + # connect core directly with converters in the loop + s2m_downconverter = Converter(32, 16) + s2m_upconverter = Converter(16, 32) + self.submodules += s2m_downconverter, s2m_upconverter + m2s_downconverter = Converter(32, 16) + m2s_upconverter = Converter(16, 32) + self.submodules += m2s_upconverter, m2s_downconverter + self.comb += [ + slave_packetizer.source.connect(s2m_downconverter.sink), + s2m_downconverter.source.connect(s2m_upconverter.sink), + s2m_upconverter.source.connect(master_depacketizer.sink), + + master_packetizer.source.connect(m2s_downconverter.sink), + m2s_downconverter.source.connect(m2s_upconverter.sink), + m2s_upconverter.source.connect(slave_depacketizer.sink) + ] + + # expose wishbone slave + self.wishbone = slave_etherbone.wishbone.bus + + +class TestEtherbone(unittest.TestCase): + def test_write_read_sram(self): + dut = DUT() + prng = random.Random(1) + def generator(dut): + datas = [prng.randrange(0, 2**32-1) for i in range(16)] + for i in range(16): + yield from dut.wishbone.write(i, datas[i]) + for i in range(16): + data = (yield from dut.wishbone.read(i)) + self.assertEqual(data, datas[i]) + run_simulation(dut, generator(dut)) diff --git a/artiq/gateware/test/serwb/test_serwb_core.py b/artiq/gateware/test/serwb/test_serwb_core.py deleted file mode 100644 index c0355d97f..000000000 --- a/artiq/gateware/test/serwb/test_serwb_core.py +++ /dev/null @@ -1,128 +0,0 @@ -import unittest -import random - -from migen import * - -from artiq.gateware.serwb import scrambler -from artiq.gateware.serwb import SERWBCore - -from misoc.interconnect.wishbone import SRAM - - -class FakeInit(Module): - def __init__(self): - self.ready = 1 - - -class FakeSerdes(Module): - def __init__(self): - self.tx_k = Signal(4) - self.tx_d = Signal(32) - self.rx_k = Signal(4) - self.rx_d = Signal(32) - - -class FakePHY(Module): - cd = "sys" - def __init__(self): - self.init = FakeInit() - self.serdes = FakeSerdes() - - -class DUTScrambler(Module): - def __init__(self): - self.submodules.scrambler = scrambler.Scrambler(sync_interval=16) - self.submodules.descrambler = scrambler.Descrambler() - self.comb += [ - self.scrambler.source.connect(self.descrambler.sink), - self.descrambler.source.ready.eq(1) - ] - - -class DUTCore(Module): - def __init__(self, **kwargs): - # wishbone slave - phy_slave = FakePHY() - serwb_slave = SERWBCore(phy_slave, int(1e6), "slave", **kwargs) - self.submodules += phy_slave, serwb_slave - - # wishbone master - phy_master = FakePHY() - serwb_master = SERWBCore(phy_master, int(1e6), "master", **kwargs) - self.submodules += phy_master, serwb_master - - # connect phy - self.comb += [ - phy_master.serdes.rx_k.eq(phy_slave.serdes.tx_k), - phy_master.serdes.rx_d.eq(phy_slave.serdes.tx_d), - phy_slave.serdes.rx_k.eq(phy_master.serdes.tx_k), - phy_slave.serdes.rx_d.eq(phy_master.serdes.tx_d) - ] - - # add wishbone sram to wishbone master - sram = SRAM(1024, bus=serwb_master.etherbone.wishbone.bus) - self.submodules += sram - - # expose wishbone slave - self.wishbone = serwb_slave.etherbone.wishbone.bus - - -class TestSERWBCore(unittest.TestCase): - def test_scrambler(self): - def generator(dut): - i = 0 - last_data = -1 - while i != 256: - # stim - if (yield dut.scrambler.sink.ready): - i += 1 - yield dut.scrambler.sink.data.eq(i) - - # check - if (yield dut.descrambler.source.valid): - current_data = (yield dut.descrambler.source.data) - if (current_data != (last_data + 1)): - dut.errors += 1 - last_data = current_data - - # cycle - yield - - dut = DUTScrambler() - dut.errors = 0 - run_simulation(dut, generator(dut)) - self.assertEqual(dut.errors, 0) - - def test_serwb(self): - def generator(dut): - # prepare test - prng = random.Random(42) - data_base = 0x100 - data_length = 4 - datas_w = [prng.randrange(2**32) for i in range(data_length)] - datas_r = [] - - # write - for i in range(data_length): - yield from dut.wishbone.write(data_base + i, datas_w[i]) - - # read - for i in range(data_length): - datas_r.append((yield from dut.wishbone.read(data_base + i))) - - # check - for i in range(data_length): - if datas_r[i] != datas_w[i]: - dut.errors += 1 - - # scrambling off - dut = DUTCore(with_scrambling=False) - dut.errors = 0 - run_simulation(dut, generator(dut)) - self.assertEqual(dut.errors, 0) - - # scrambling on - dut = DUTCore(with_scrambling=True) - dut.errors = 0 - run_simulation(dut, generator(dut)) - self.assertEqual(dut.errors, 0) diff --git a/artiq/gateware/test/serwb/test_serwb_init.py b/artiq/gateware/test/serwb/test_serwb_phy_init.py similarity index 98% rename from artiq/gateware/test/serwb/test_serwb_init.py rename to artiq/gateware/test/serwb/test_serwb_phy_init.py index 2e488165f..ea807f97d 100644 --- a/artiq/gateware/test/serwb/test_serwb_init.py +++ b/artiq/gateware/test/serwb/test_serwb_phy_init.py @@ -4,6 +4,7 @@ import unittest from migen import * from artiq.gateware.serwb import packet +from artiq.gateware.serwb import etherbone from artiq.gateware.serwb.phy import _SerdesMasterInit, _SerdesSlaveInit @@ -115,7 +116,7 @@ def generator(test, dut, valid_bitslip, valid_delays, check_success): test.assertEqual(error, 1) -class TestSERWBInit(unittest.TestCase): +class TestPHYInit(unittest.TestCase): def test_master_init_success(self): dut = DUTMaster() valid_bitslip = 2 From 3eb882b6b75c65a28d180374f20ad6f7995a988e Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 16 Jan 2018 08:51:45 +0000 Subject: [PATCH 0200/2457] conda: remove openocd version constraint. Conda chokes on it and I don't care enough to fix it. --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 290070c5e..2c5d97334 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -22,7 +22,7 @@ requirements: - llvm-or1k 4.0.1 - llvmlite-artiq 0.20.0 - rust-core-or1k 1.23.0 19 - - openocd 0.10.0+git2 + - openocd - lit - outputcheck - coverage From 7405006668cf4dffd87b9cc9bba8af8f772c465c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 16 Jan 2018 18:19:04 +0100 Subject: [PATCH 0201/2457] sayma: rtio clock is jesd fabric clock --- artiq/gateware/targets/sayma_amc_standalone.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc_standalone.py b/artiq/gateware/targets/sayma_amc_standalone.py index b84ff4d26..25ec0e506 100755 --- a/artiq/gateware/targets/sayma_amc_standalone.py +++ b/artiq/gateware/targets/sayma_amc_standalone.py @@ -220,8 +220,8 @@ class Standalone(MiniSoC, AMPSoC): self.clock_domains.cd_rtio = ClockDomain() self.comb += [ - self.cd_rtio.clk.eq(ClockSignal()), - self.cd_rtio.rst.eq(ResetSignal()) + self.cd_rtio.clk.eq(ClockSignal("jesd")), + self.cd_rtio.rst.eq(ResetSignal("jesd")) ] self.submodules.rtio_core = rtio.Core(rtio_channels) self.csr_devices.append("rtio_core") From f73c3e59441d8c809d1f807a9aae6fd5865393f9 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 16 Jan 2018 20:06:43 +0100 Subject: [PATCH 0202/2457] gateware/test/serwb: update and cleanup test (v2...) --- artiq/gateware/test/serwb/test_etherbone.py | 70 ---------- artiq/gateware/test/serwb/test_serwb_core.py | 128 ++++++++++++++++++ ...t_serwb_phy_init.py => test_serwb_init.py} | 3 +- 3 files changed, 129 insertions(+), 72 deletions(-) delete mode 100644 artiq/gateware/test/serwb/test_etherbone.py create mode 100644 artiq/gateware/test/serwb/test_serwb_core.py rename artiq/gateware/test/serwb/{test_serwb_phy_init.py => test_serwb_init.py} (98%) diff --git a/artiq/gateware/test/serwb/test_etherbone.py b/artiq/gateware/test/serwb/test_etherbone.py deleted file mode 100644 index 963769a1f..000000000 --- a/artiq/gateware/test/serwb/test_etherbone.py +++ /dev/null @@ -1,70 +0,0 @@ -import unittest -import random - -from migen import * - -from misoc.interconnect.wishbone import SRAM -from misoc.interconnect.stream import Converter - -from artiq.gateware.serwb import packet -from artiq.gateware.serwb import etherbone - - -class DUT(Module): - def __init__(self): - # wishbone slave - slave_depacketizer = packet.Depacketizer(int(100e6)) - slave_packetizer = packet.Packetizer() - self.submodules += slave_depacketizer, slave_packetizer - slave_etherbone = etherbone.Etherbone(mode="slave") - self.submodules += slave_etherbone - self.comb += [ - slave_depacketizer.source.connect(slave_etherbone.sink), - slave_etherbone.source.connect(slave_packetizer.sink) - ] - - # wishbone master - master_depacketizer = packet.Depacketizer(int(100e6)) - master_packetizer = packet.Packetizer() - self.submodules += master_depacketizer, master_packetizer - master_etherbone = etherbone.Etherbone(mode="master") - master_sram = SRAM(64, bus=master_etherbone.wishbone.bus) - self.submodules += master_etherbone, master_sram - self.comb += [ - master_depacketizer.source.connect(master_etherbone.sink), - master_etherbone.source.connect(master_packetizer.sink) - ] - - # connect core directly with converters in the loop - s2m_downconverter = Converter(32, 16) - s2m_upconverter = Converter(16, 32) - self.submodules += s2m_downconverter, s2m_upconverter - m2s_downconverter = Converter(32, 16) - m2s_upconverter = Converter(16, 32) - self.submodules += m2s_upconverter, m2s_downconverter - self.comb += [ - slave_packetizer.source.connect(s2m_downconverter.sink), - s2m_downconverter.source.connect(s2m_upconverter.sink), - s2m_upconverter.source.connect(master_depacketizer.sink), - - master_packetizer.source.connect(m2s_downconverter.sink), - m2s_downconverter.source.connect(m2s_upconverter.sink), - m2s_upconverter.source.connect(slave_depacketizer.sink) - ] - - # expose wishbone slave - self.wishbone = slave_etherbone.wishbone.bus - - -class TestEtherbone(unittest.TestCase): - def test_write_read_sram(self): - dut = DUT() - prng = random.Random(1) - def generator(dut): - datas = [prng.randrange(0, 2**32-1) for i in range(16)] - for i in range(16): - yield from dut.wishbone.write(i, datas[i]) - for i in range(16): - data = (yield from dut.wishbone.read(i)) - self.assertEqual(data, datas[i]) - run_simulation(dut, generator(dut)) diff --git a/artiq/gateware/test/serwb/test_serwb_core.py b/artiq/gateware/test/serwb/test_serwb_core.py new file mode 100644 index 000000000..96260399c --- /dev/null +++ b/artiq/gateware/test/serwb/test_serwb_core.py @@ -0,0 +1,128 @@ +import unittest +import random + +from migen import * + +from artiq.gateware.serwb import scrambler +from artiq.gateware.serwb import core + +from misoc.interconnect.wishbone import SRAM + + +class FakeInit(Module): + def __init__(self): + self.ready = 1 + + +class FakeSerdes(Module): + def __init__(self): + self.tx_k = Signal(4) + self.tx_d = Signal(32) + self.rx_k = Signal(4) + self.rx_d = Signal(32) + + +class FakePHY(Module): + cd = "sys" + def __init__(self): + self.init = FakeInit() + self.serdes = FakeSerdes() + + +class DUTScrambler(Module): + def __init__(self): + self.submodules.scrambler = scrambler.Scrambler(sync_interval=16) + self.submodules.descrambler = scrambler.Descrambler() + self.comb += [ + self.scrambler.source.connect(self.descrambler.sink), + self.descrambler.source.ack.eq(1) + ] + + +class DUTCore(Module): + def __init__(self, **kwargs): + # wishbone slave + phy_slave = FakePHY() + serwb_slave = core.SERWBCore(phy_slave, int(1e6), "slave", **kwargs) + self.submodules += phy_slave, serwb_slave + + # wishbone master + phy_master = FakePHY() + serwb_master = core.SERWBCore(phy_master, int(1e6), "master", **kwargs) + self.submodules += phy_master, serwb_master + + # connect phy + self.comb += [ + phy_master.serdes.rx_k.eq(phy_slave.serdes.tx_k), + phy_master.serdes.rx_d.eq(phy_slave.serdes.tx_d), + phy_slave.serdes.rx_k.eq(phy_master.serdes.tx_k), + phy_slave.serdes.rx_d.eq(phy_master.serdes.tx_d) + ] + + # add wishbone sram to wishbone master + sram = SRAM(1024, bus=serwb_master.etherbone.wishbone.bus) + self.submodules += sram + + # expose wishbone slave + self.wishbone = serwb_slave.etherbone.wishbone.bus + + +class TestSERWBCore(unittest.TestCase): + def test_scrambler(self): + def generator(dut): + i = 0 + last_data = -1 + while i != 256: + # stim + if (yield dut.scrambler.sink.ack): + i += 1 + yield dut.scrambler.sink.data.eq(i) + + # check + if (yield dut.descrambler.source.stb): + current_data = (yield dut.descrambler.source.data) + if (current_data != (last_data + 1)): + dut.errors += 1 + last_data = current_data + + # cycle + yield + + dut = DUTScrambler() + dut.errors = 0 + run_simulation(dut, generator(dut)) + self.assertEqual(dut.errors, 0) + + def test_serwb(self): + def generator(dut): + # prepare test + prng = random.Random(42) + data_base = 0x100 + data_length = 4 + datas_w = [prng.randrange(2**32) for i in range(data_length)] + datas_r = [] + + # write + for i in range(data_length): + yield from dut.wishbone.write(data_base + i, datas_w[i]) + + # read + for i in range(data_length): + datas_r.append((yield from dut.wishbone.read(data_base + i))) + + # check + for i in range(data_length): + if datas_r[i] != datas_w[i]: + dut.errors += 1 + + # scrambling off + dut = DUTCore(with_scrambling=False) + dut.errors = 0 + run_simulation(dut, generator(dut)) + self.assertEqual(dut.errors, 0) + + # scrambling on + dut = DUTCore(with_scrambling=True) + dut.errors = 0 + run_simulation(dut, generator(dut)) + self.assertEqual(dut.errors, 0) diff --git a/artiq/gateware/test/serwb/test_serwb_phy_init.py b/artiq/gateware/test/serwb/test_serwb_init.py similarity index 98% rename from artiq/gateware/test/serwb/test_serwb_phy_init.py rename to artiq/gateware/test/serwb/test_serwb_init.py index ea807f97d..2e488165f 100644 --- a/artiq/gateware/test/serwb/test_serwb_phy_init.py +++ b/artiq/gateware/test/serwb/test_serwb_init.py @@ -4,7 +4,6 @@ import unittest from migen import * from artiq.gateware.serwb import packet -from artiq.gateware.serwb import etherbone from artiq.gateware.serwb.phy import _SerdesMasterInit, _SerdesSlaveInit @@ -116,7 +115,7 @@ def generator(test, dut, valid_bitslip, valid_delays, check_success): test.assertEqual(error, 1) -class TestPHYInit(unittest.TestCase): +class TestSERWBInit(unittest.TestCase): def test_master_init_success(self): dut = DUTMaster() valid_bitslip = 2 From f317d1a2c64593e979c44748509bc6c3f69b1d51 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 17 Jan 2018 00:42:46 +0000 Subject: [PATCH 0203/2457] Update board naming (again) to match DNS. --- DEVELOPER_NOTES.rst | 6 +++--- artiq/frontend/artiq_devtool.py | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/DEVELOPER_NOTES.rst b/DEVELOPER_NOTES.rst index 3c6724f9a..527322ef9 100644 --- a/DEVELOPER_NOTES.rst +++ b/DEVELOPER_NOTES.rst @@ -34,7 +34,7 @@ To avoid conflicts for development boards on the server, while using a board you To lock the KC705 for 30 minutes or until Ctrl-C is pressed: :: - flock --verbose /run/boards/kc705_1 sleep 1800 + flock --verbose /run/boards/kc705-1 sleep 1800 Check that the command acquires the lock, i.e. prints something such as: :: @@ -43,7 +43,7 @@ Check that the command acquires the lock, i.e. prints something such as: To lock the KC705 for the duration of the execution of a shell: :: - flock /run/boards/kc705_1 bash + flock /run/boards/kc705-1 bash You may also use this script: :: @@ -54,7 +54,7 @@ If the board is already locked by another user, the ``flock`` commands above wil To determine which user is locking a board, use: :: - fuser -v /run/boards/kc705_1 + fuser -v /run/boards/kc705-1 Selecting a development board with artiq_flash diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 021b51f9c..b1a9313b5 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -48,7 +48,7 @@ def get_argparser(): parser.add_argument("actions", metavar="ACTION", type=str, default=[], nargs="+", help="actions to perform, sequence of: " - "build clean reset flash flash+log hotswap") + "build clean reset flash flash+log connect hotswap") return parser @@ -77,12 +77,12 @@ def main(): flash_args = ["-t", boardtype] if boardtype == "sayma": if args.board is None: - args.board = "sayma_1" - if args.board == "sayma_1": + args.board = "sayma-1" + if args.board == "sayma-1": flash_args += ["--preinit-command", "ftdi_location 5:2"] - elif args.board == "sayma_2": + elif args.board == "sayma-2": flash_args += ["--preinit-command", "ftdi_location 3:10"] - elif args.board == "sayma_3": + elif args.board == "sayma-3": flash_args += ["--preinit-command", "ftdi_location 5:1"] else: raise NotImplementedError("unknown --preinit-command for {}".format(boardtype)) @@ -92,7 +92,7 @@ def main(): "target": args.target, "hostname": args.host, "boardtype": boardtype, - "board": args.board if args.board else boardtype + "_1", + "board": args.board if args.board else boardtype + "-1", "firmware": firmware, } substs.update({ From 1e896d4ba8e0c30fa4a2d2e52d1fa97c1587ab41 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 17 Jan 2018 00:46:51 +0000 Subject: [PATCH 0204/2457] firmware: fix warnings. --- artiq/firmware/libboard_artiq/ad9154.rs | 2 ++ artiq/firmware/libdyld/lib.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 0f38ee321..21149c8b2 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -392,6 +392,7 @@ fn dac_setup(linerate: u64) -> Result<(), &'static str> { Ok(()) } +#[allow(dead_code)] fn dac_status() { info!("SERDES_PLL_LOCK: {}", (read(ad9154_reg::PLL_STATUS) & ad9154_reg::SERDES_PLL_LOCK_RB)); @@ -487,6 +488,7 @@ fn dac_monitor() { write(ad9154_reg::IRQ_STATUS3, 0x00); } +#[allow(dead_code)] fn dac_prbs(dacno: u8, p: u8, t: u32) { /* follow phy prbs testing (p58 of ad9154 datasheet) */ diff --git a/artiq/firmware/libdyld/lib.rs b/artiq/firmware/libdyld/lib.rs index c5d028226..1eeff2bf4 100644 --- a/artiq/firmware/libdyld/lib.rs +++ b/artiq/firmware/libdyld/lib.rs @@ -198,6 +198,8 @@ impl<'a> Library<'a> { pub fn load(data: &[u8], image: &'a mut [u8], resolve: &Fn(&[u8]) -> Option) -> Result, Error<'a>> { + #![allow(unused_assignments)] + let ehdr = read_unaligned::(data, 0) .map_err(|()| "cannot read ELF header")?; From bfceef439f00a003c19907a8d2c05e809d280899 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 17 Jan 2018 01:14:12 +0000 Subject: [PATCH 0205/2457] Add missing parts of f317d1a2. --- artiq/examples/master/device_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/master/device_db.py b/artiq/examples/master/device_db.py index 87351ffa7..6c2a45347 100644 --- a/artiq/examples/master/device_db.py +++ b/artiq/examples/master/device_db.py @@ -2,7 +2,7 @@ # The RTIO channel numbers here are for NIST CLOCK on KC705. # The list of devices here is not exhaustive. -core_addr = "kc705.lab.m-labs.hk" +core_addr = "kc705-1.lab.m-labs.hk" device_db = { # Core device From a536d6df12fde8479eb079a4203942a2b8172fc7 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 17 Jan 2018 01:21:19 +0000 Subject: [PATCH 0206/2457] artiq_flash: add sayma_rtm support. --- artiq/frontend/artiq_flash.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index a2b41451c..3259c8c5d 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -36,7 +36,8 @@ Prerequisites: plugdev group: 'sudo adduser $USER plugdev' and re-login. """) parser.add_argument("-t", "--target", default="kc705", - help="target board, default: %(default)s") + help="target board, default: %(default)s, one of: " + "kc705 kasli sayma sayma_rtm") parser.add_argument("-m", "--variant", default=None, help="board variant") parser.add_argument("--preinit-command", default=[], action="append", @@ -216,17 +217,26 @@ def main(): "storage": (1, 0x040000), "firmware": (1, 0x050000), }, + "sayma_rtm": { + "programmer_factory": ProgrammerSayma, + "proxy_bitfile": "bscan_spi_xcku040-sayma.bit", + "gateware": (1, 0x150000), + }, }[opts.target] variant = opts.variant - if variant is not None and variant not in config["variants"]: - raise SystemExit("Invalid variant for this board") - if variant is None: - variant = config["variants"][0] + if "variants" in config: + if variant is not None and variant not in config["variants"]: + raise SystemExit("Invalid variant for this board") + if variant is None: + variant = config["variants"][0] bin_dir = opts.dir if bin_dir is None: - bin_dir = os.path.join(artiq_dir, "binaries", - "{}-{}".format(opts.target, variant)) + if variant: + bin_name = "{}-{}".format(opts.target, variant) + else: + bin_name = opts.target + bin_dir = os.path.join(artiq_dir, "binaries", bin_name) if opts.srcbuild is None and not os.path.exists(bin_dir) and opts.action != ["start"]: raise SystemExit("Binaries directory '{}' does not exist" .format(bin_dir)) From f77aa9b78ff7d1a61417650cfd65dbc4635cca0f Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 17 Jan 2018 01:45:47 +0000 Subject: [PATCH 0207/2457] artiq_flash: rename sayma to sayma_amc to fix bitstream discovery. Fixes #895. --- artiq/frontend/artiq_flash.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 3259c8c5d..4e0bb2f99 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -37,7 +37,7 @@ Prerequisites: """) parser.add_argument("-t", "--target", default="kc705", help="target board, default: %(default)s, one of: " - "kc705 kasli sayma sayma_rtm") + "kc705 kasli sayma_amc sayma_rtm") parser.add_argument("-m", "--variant", default=None, help="board variant") parser.add_argument("--preinit-command", default=[], action="append", @@ -208,7 +208,7 @@ def main(): "storage": (0, 0x440000), "firmware": (0, 0x450000), }, - "sayma": { + "sayma_amc": { "programmer_factory": ProgrammerSayma, "proxy_bitfile": "bscan_spi_xcku040-sayma.bit", "variants": ["standalone", "master", "satellite"], From 5c6276c78f0527bfcd9c51e2ebfb0c8dde1c9b89 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 17 Jan 2018 02:09:53 +0000 Subject: [PATCH 0208/2457] conda: build artiq-$BOARD as noarch: python, like artiq itself. Fixes #894. --- conda/artiq-kasli-opticlock/meta.yaml | 2 +- conda/artiq-kc705-nist_clock/meta.yaml | 2 +- conda/artiq-kc705-nist_qc2/meta.yaml | 2 +- conda/artiq-sayma_amc-standalone/meta.yaml | 2 +- conda/artiq-sayma_rtm/meta.yaml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/conda/artiq-kasli-opticlock/meta.yaml b/conda/artiq-kasli-opticlock/meta.yaml index 57acc34f7..9d1367546 100644 --- a/conda/artiq-kasli-opticlock/meta.yaml +++ b/conda/artiq-kasli-opticlock/meta.yaml @@ -6,7 +6,7 @@ source: git_url: ../.. build: - noarch: generic + noarch: python ignore_prefix_files: True number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} diff --git a/conda/artiq-kc705-nist_clock/meta.yaml b/conda/artiq-kc705-nist_clock/meta.yaml index f6aebd686..1db897a6d 100644 --- a/conda/artiq-kc705-nist_clock/meta.yaml +++ b/conda/artiq-kc705-nist_clock/meta.yaml @@ -6,7 +6,7 @@ source: git_url: ../.. build: - noarch: generic + noarch: python ignore_prefix_files: True number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} diff --git a/conda/artiq-kc705-nist_qc2/meta.yaml b/conda/artiq-kc705-nist_qc2/meta.yaml index 7caf0169a..009f0b630 100644 --- a/conda/artiq-kc705-nist_qc2/meta.yaml +++ b/conda/artiq-kc705-nist_qc2/meta.yaml @@ -6,7 +6,7 @@ source: git_url: ../.. build: - noarch: generic + noarch: python ignore_prefix_files: True number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} diff --git a/conda/artiq-sayma_amc-standalone/meta.yaml b/conda/artiq-sayma_amc-standalone/meta.yaml index 543c04bed..832f7326a 100644 --- a/conda/artiq-sayma_amc-standalone/meta.yaml +++ b/conda/artiq-sayma_amc-standalone/meta.yaml @@ -6,7 +6,7 @@ source: git_url: ../.. build: - noarch: generic + noarch: python ignore_prefix_files: True number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} diff --git a/conda/artiq-sayma_rtm/meta.yaml b/conda/artiq-sayma_rtm/meta.yaml index a792ba439..0aed97148 100644 --- a/conda/artiq-sayma_rtm/meta.yaml +++ b/conda/artiq-sayma_rtm/meta.yaml @@ -6,7 +6,7 @@ source: git_url: ../.. build: - noarch: generic + noarch: python ignore_prefix_files: True number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} From f54b27b79c2ee8cdc7cbeae5ff8f03515aa9aed3 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 17 Jan 2018 11:49:36 +0100 Subject: [PATCH 0209/2457] sayma_amc: prepare for jesd subclass 1 --- artiq/gateware/targets/sayma_amc_standalone.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/artiq/gateware/targets/sayma_amc_standalone.py b/artiq/gateware/targets/sayma_amc_standalone.py index 25ec0e506..63abc19b6 100755 --- a/artiq/gateware/targets/sayma_amc_standalone.py +++ b/artiq/gateware/targets/sayma_amc_standalone.py @@ -6,6 +6,7 @@ from collections import namedtuple from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.io import DifferentialInput from misoc.cores.slave_fpga import SlaveFPGA from misoc.integration.soc_sdram import soc_sdram_args, soc_sdram_argdict @@ -40,6 +41,7 @@ class AD9154CRG(Module, AutoCSR): fabric_freq = int(125e6) def __init__(self, platform): self.jreset = CSRStorage(reset=1) + self.jref = Signal() self.refclk = Signal() refclk2 = Signal() @@ -56,6 +58,9 @@ class AD9154CRG(Module, AutoCSR): self.cd_jesd.clk.attr.add("keep") platform.add_period_constraint(self.cd_jesd.clk, 1e9/self.refclk_freq) + jref = platform.request("dac_sysref") + self.specials += DifferentialInput(jref.p, jref.n, self.jref) + class AD9154JESD(Module, AutoCSR): def __init__(self, platform, sys_crg, jesd_crg, dac): @@ -86,6 +91,7 @@ class AD9154JESD(Module, AutoCSR): phys, settings, converter_data_width=64)) self.submodules.control = control = to_jesd(JESD204BCoreTXControl(core)) core.register_jsync(platform.request("dac_sync", dac)) + #core.register_jref(jesd_crg.jref) # FIXME: uncomment on next jesd204b update class AD9154(Module, AutoCSR): From ed3e3b2791db54f196d4757b634c0e429d7b9c84 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 17 Jan 2018 12:10:30 +0100 Subject: [PATCH 0210/2457] sayma_amc: clarify --with-sawg help --- artiq/gateware/targets/sayma_amc_standalone.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc_standalone.py b/artiq/gateware/targets/sayma_amc_standalone.py index 63abc19b6..73124afe7 100755 --- a/artiq/gateware/targets/sayma_amc_standalone.py +++ b/artiq/gateware/targets/sayma_amc_standalone.py @@ -258,7 +258,9 @@ def main(): help="CSV file listing remote CSRs on RTM (default: %(default)s)") parser.add_argument("--with-sawg", default=False, action="store_true", - help="add JESD204B and SAWG channels (default: %(default)s)") + help="Add SAWG RTIO channels feeding the JESD links. If not " + "specified, fixed sawtooth generators are used. " + "(default: %(default)s)") args = parser.parse_args() soc = Standalone(with_sawg=args.with_sawg, **soc_sdram_argdict(args)) From 3313e997df71a2882c4bc4fe4258d8f1bf3724c1 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 17 Jan 2018 11:27:44 +0000 Subject: [PATCH 0211/2457] test: fix test_worker to work when deprecation warnings are emitted. --- artiq/test/test_worker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/test_worker.py b/artiq/test/test_worker.py index 73c09b352..ccf39a84f 100644 --- a/artiq/test/test_worker.py +++ b/artiq/test/test_worker.py @@ -90,7 +90,7 @@ class WorkerCase(unittest.TestCase): with self.assertLogs() as logs: with self.assertRaises(WorkerInternalException): _run_experiment("ExceptionTermination") - self.assertEqual(len(logs.records), 1) + self.assertGreater(len(logs.records), 0) self.assertIn("Terminating with exception (TypeError)", logs.output[0]) From dbe48d3cad77ee245578c235f0804602ae7e6660 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 17 Jan 2018 11:31:32 +0000 Subject: [PATCH 0212/2457] Fix 3313e997. --- artiq/test/test_worker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/test_worker.py b/artiq/test/test_worker.py index ccf39a84f..88e3ead82 100644 --- a/artiq/test/test_worker.py +++ b/artiq/test/test_worker.py @@ -92,7 +92,7 @@ class WorkerCase(unittest.TestCase): _run_experiment("ExceptionTermination") self.assertGreater(len(logs.records), 0) self.assertIn("Terminating with exception (TypeError)", - logs.output[0]) + logs.output[-1]) def test_watchdog_no_timeout(self): _run_experiment("WatchdogNoTimeout") From 8ec33ae7bd6224f744d12fad80e5604d86f0536e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 17 Jan 2018 14:22:20 +0000 Subject: [PATCH 0213/2457] kasli: feed EEM clock fan-out from SI5324 --- artiq/gateware/targets/kasli.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index e17445987..49f5ad13f 100644 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -157,6 +157,9 @@ class Opticlock(_KasliBase): # platform.add_extension(_urukul("eem3", "eem4")) # platform.add_extension(_novogorny("eem5")) + # EEM clock fan-out from Si5324, not MMCX + self.comb += platform.request("clk_sel").eq(1) + rtio_channels = [] for eem in "eem0 eem1 eem2".split(): for i in range(8): From 07f4e2e35a4f7e007383a230ea4356989f1c9c96 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 18 Jan 2018 08:19:37 +0100 Subject: [PATCH 0214/2457] libboard_artiq/ad9154: fix prbs test (only keep prbs7) and always do it after ad9154 initialization --- artiq/firmware/libboard_artiq/ad9154.rs | 58 +++++++++++++++---------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 21149c8b2..d30cb6adf 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -131,7 +131,7 @@ const JESD_SETTINGS: JESDSettings = JESDSettings { jesdv: 1 }; -fn dac_setup(linerate: u64) -> Result<(), &'static str> { +fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { // reset write(ad9154_reg::SPI_INTFCONFA, 1*ad9154_reg::SOFTRESET_M | 1*ad9154_reg::SOFTRESET | @@ -148,10 +148,10 @@ fn dac_setup(linerate: u64) -> Result<(), &'static str> { if (read(ad9154_reg::PRODIDH) as u16) << 8 | (read(ad9154_reg::PRODIDL) as u16) != 0x9154 { return Err("AD9154 not found"); } else { - info!("AD9154 found"); + info!("AD9154-{} found", dacno); } - info!("AD9154 configuration..."); + info!("AD9154-{} configuration...", dacno); write(ad9154_reg::PWRCNTRL0, 0*ad9154_reg::PD_DAC0 | 0*ad9154_reg::PD_DAC1 | 0*ad9154_reg::PD_DAC2 | 0*ad9154_reg::PD_DAC3 | @@ -488,37 +488,40 @@ fn dac_monitor() { write(ad9154_reg::IRQ_STATUS3, 0x00); } -#[allow(dead_code)] -fn dac_prbs(dacno: u8, p: u8, t: u32) { - /* follow phy prbs testing (p58 of ad9154 datasheet) */ +fn dac_prbs(dacno: u8) -> Result<(), &'static str> { + let mut prbs_errors: u32 = 0; - /* step 1: start sending prbs pattern from the transmitter */ + /* follow phy prbs testing (p58 of ad9154 datasheet) */ + info!("AD9154-{} PRBS test", dacno); + + /* step 1: start sending prbs7 pattern from the transmitter */ jesd_prbs(dacno, true); + clock::spin_us(500000); /* step 2: select prbs mode */ write(ad9154_reg::PHY_PRBS_TEST_CTRL, - p*ad9154_reg::PHY_PRBS_PAT_SEL); + 0b00*ad9154_reg::PHY_PRBS_PAT_SEL); /* step 3: enable test for all lanes */ write(ad9154_reg::PHY_PRBS_TEST_EN, 0xff); /* step 4: reset */ write(ad9154_reg::PHY_PRBS_TEST_CTRL, - p*ad9154_reg::PHY_PRBS_PAT_SEL | + 0b00*ad9154_reg::PHY_PRBS_PAT_SEL | 1*ad9154_reg::PHY_TEST_RESET); write(ad9154_reg::PHY_PRBS_TEST_CTRL, - p*ad9154_reg::PHY_PRBS_PAT_SEL); + 0b00*ad9154_reg::PHY_PRBS_PAT_SEL); /* step 5: prbs threshold */ - write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_LOBITS, t as u8); - write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_MIDBITS, (t >> 8) as u8); - write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_HIBITS, (t >> 16) as u8); + write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_LOBITS, 0); + write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_MIDBITS, 0); + write(ad9154_reg::PHY_PRBS_TEST_THRESHOLD_HIBITS, 0); /* step 6: start */ write(ad9154_reg::PHY_PRBS_TEST_CTRL, - p*ad9154_reg::PHY_PRBS_PAT_SEL); + 0b00*ad9154_reg::PHY_PRBS_PAT_SEL); write(ad9154_reg::PHY_PRBS_TEST_CTRL, - p*ad9154_reg::PHY_PRBS_PAT_SEL | + 0b00*ad9154_reg::PHY_PRBS_PAT_SEL | 1*ad9154_reg::PHY_TEST_START); /* step 7: wait 500 ms */ @@ -526,21 +529,29 @@ fn dac_prbs(dacno: u8, p: u8, t: u32) { /* step 8 : stop */ write(ad9154_reg::PHY_PRBS_TEST_CTRL, - p*ad9154_reg::PHY_PRBS_PAT_SEL); + 0b00*ad9154_reg::PHY_PRBS_PAT_SEL); - info!("prbs_status: {:02x}", read(ad9154_reg::PHY_PRBS_TEST_STATUS)); for i in 0..8 { + let mut lane_errors: u32 = 0; /* step 9.a: select src err */ write(ad9154_reg::PHY_PRBS_TEST_CTRL, i*ad9154_reg::PHY_SRC_ERR_CNT); /* step 9.b: retrieve number of errors */ - info!("prbs errors[{}]: {:06x}", i, - (read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_LOBITS) as u32) | - ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_MIDBITS) as u32) << 8) | - ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_HIBITS) as u32) << 16)); + lane_errors = (read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_LOBITS) as u32) | + ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_MIDBITS) as u32) << 8) | + ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_HIBITS) as u32) << 16); + if lane_errors > 0 { + warn!("AD9154-{} PRBS errors on lane{}: {:06x}", dacno, i, lane_errors); + } + prbs_errors += lane_errors } jesd_prbs(dacno, false); + + if prbs_errors > 0 { + return Err("AD9154 PRBS failed") + } + Ok(()) } fn dac_cfg(dacno: u8) -> Result<(), &'static str> { @@ -550,7 +561,7 @@ fn dac_cfg(dacno: u8) -> Result<(), &'static str> { jesd_stpl(dacno, false); clock::spin_us(10000); jesd_enable(dacno, true); - dac_setup(6_000_000_000)?; + dac_setup(dacno, 6_000_000_000)?; jesd_enable(dacno, false); clock::spin_us(10000); jesd_enable(dacno, true); @@ -601,6 +612,9 @@ pub fn init() -> Result<(), &'static str> { let dacno = dacno as u8; debug!("setting up AD9154-{} DAC...", dacno); dac_cfg_retry(dacno)?; + dac_prbs(dacno)?; + dac_cfg_retry(dacno)?; } + Ok(()) } From bdf41cd5740600b3ac3c2f3a0814a3a0eab4e20f Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 18 Jan 2018 20:29:24 +0000 Subject: [PATCH 0215/2457] doc: mention that ARTIQ can only be developed on Linux. (fixes #896). --- doc/manual/developing.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index 8b2f20e96..90b6f0849 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -1,6 +1,9 @@ Developing ARTIQ ^^^^^^^^^^^^^^^^ +.. note:: + Developing ARTIQ is currently only possible on Linux. + We describe two different approaches to creating a development environment for ARTIQ. The first method uses existing pre-compiled Anaconda packages and the ``artiq-dev`` meta-package for the development environment. From 1f82ceaa85c9c65a2013e914bc45794d875d1311 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 19 Jan 2018 04:39:16 +0000 Subject: [PATCH 0216/2457] firmware: add HMC542 (Allaki) support. --- artiq/firmware/libboard_artiq/hmc542.rs | 54 +++++++++++++++++++++++++ artiq/firmware/libboard_artiq/lib.rs | 2 + artiq/firmware/runtime/main.rs | 2 + 3 files changed, 58 insertions(+) create mode 100644 artiq/firmware/libboard_artiq/hmc542.rs diff --git a/artiq/firmware/libboard_artiq/hmc542.rs b/artiq/firmware/libboard_artiq/hmc542.rs new file mode 100644 index 000000000..70cd8af54 --- /dev/null +++ b/artiq/firmware/libboard_artiq/hmc542.rs @@ -0,0 +1,54 @@ +use board::{csr, clock}; + +const PIN_LE: u32 = 1 << 0; +const PIN_SIN: u32 = 1 << 1; +const PIN_CLK: u32 = 1 << 2; +const PIN_RST_N: u32 = 1 << 3; +const PIN_RST: u32 = PIN_RST_N; + +const CARDS: usize = 4; +const CHANNELS: usize = 2; + +fn set_pins(card_index: usize, chan_index: usize, pins: u32) { + let pins = pins ^ PIN_RST_N; + let shift = card_index * 2 + chan_index; + unsafe { + let state = csr::allaki_atts::out_read(); + let state = state & !(0xf << shift); + let state = state | (pins << shift); + csr::allaki_atts::out_write(state); + } + clock::spin_us(100); +} + +/// Attenuation is in units of 0.5dB, from 0dB (0) to 31.5dB (63). +pub fn program(card_index: usize, chan_index: usize, atten: u8) { + assert!(card_index < 4 && chan_index < 2); + + // 0b111111 = 1dB + // 0b111110 = 0.5dB + // 0b111101 = 1dB + // ... + // 0b011111 = 16dB + // 0b000000 = 31.5dB + let atten = !(atten << 2); + + let set_pins = |pins| set_pins(card_index, chan_index, pins); + set_pins(PIN_RST); + set_pins(0); + for n in 0..8 { + let sin = if atten & 1 << n != 0 { PIN_SIN } else { 0 }; + set_pins(sin); + set_pins(sin | PIN_CLK); + } + set_pins(PIN_LE); +} + +/// See `program`. +pub fn program_all(atten: u8) { + for card in 0..CARDS { + for chan in 0..CHANNELS { + program(card, chan, atten) + } + } +} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 3307681b3..127a55db8 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -23,3 +23,5 @@ pub mod hmc830_7043; mod ad9154_reg; #[cfg(has_ad9154)] pub mod ad9154; +#[cfg(has_allaki_atts)] +pub mod hmc542; diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 378d44f07..6ce66595c 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -95,6 +95,8 @@ fn startup() { board_artiq::hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] board_artiq::ad9154::init().expect("cannot initialize AD9154"); + #[cfg(has_allaki_atts)] + board_artiq::hmc542::program_all(8/*=4dB*/); #[cfg(has_ethmac)] startup_ethernet(); From 80cbef0031db4e874ed8688e06cf23c064ab5d68 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 19 Jan 2018 04:56:11 +0000 Subject: [PATCH 0217/2457] firmware: always reset PHY when initializing Ethernet. Fixes #897. --- artiq/firmware/bootloader/main.rs | 5 +---- artiq/firmware/libboard/ethmac.rs | 5 +++++ artiq/firmware/runtime/main.rs | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 2507cf14f..34bc58094 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -158,11 +158,8 @@ fn network_boot() { println!("Using MAC address {} and IP address {}", eth_addr, ip_addr); - #[allow(unused_mut)] let mut net_device = unsafe { ethmac::EthernetDevice::new() }; - - #[cfg(has_ethphy)] - net_device.reset_phy(); + net_device.reset_phy_if_any(); let mut neighbor_map = [None; 2]; let neighbor_cache = diff --git a/artiq/firmware/libboard/ethmac.rs b/artiq/firmware/libboard/ethmac.rs index 90cd1faa4..ce8af0e42 100644 --- a/artiq/firmware/libboard/ethmac.rs +++ b/artiq/firmware/libboard/ethmac.rs @@ -57,6 +57,11 @@ impl EthernetDevice { clock::spin_us(2_000); } } + + pub fn reset_phy_if_any(&mut self) { + #[cfg(has_ethphy)] + self.reset_phy(); + } } impl<'a> Device<'a> for EthernetDevice { diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 6ce66595c..95916a8dc 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -150,7 +150,8 @@ fn startup_ethernet() { } } - let net_device = unsafe { ethmac::EthernetDevice::new() }; + let mut net_device = unsafe { ethmac::EthernetDevice::new() }; + net_device.reset_phy_if_any(); // fn _net_trace_writer(timestamp: u64, printer: smoltcp::wire::PrettyPrinter) // where U: smoltcp::wire::pretty_print::PrettyPrint { From b553804e5ad9157badb91ba53d27da930ae6f496 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 19 Jan 2018 07:39:55 +0000 Subject: [PATCH 0218/2457] artiq_flash: implement network transparency. --- artiq/frontend/artiq_devtool.py | 145 +++++++++++++------------------- artiq/frontend/artiq_flash.py | 138 ++++++++++++++++++------------ artiq/tools.py | 59 +++++++++++-- 3 files changed, 198 insertions(+), 144 deletions(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index b1a9313b5..02ac2c211 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -18,7 +18,9 @@ from artiq.tools import verbosity_args, init_logger, logger, SSHClient def get_argparser(): - parser = argparse.ArgumentParser(description="ARTIQ core device development tool") + parser = argparse.ArgumentParser( + description="ARTIQ core device development tool", + formatter_class=argparse.ArgumentDefaultsHelpFormatter) verbosity_args(parser) @@ -27,19 +29,19 @@ def get_argparser(): help="Target to build, one of: " "kc705_dds kasli sayma_rtm sayma_amc_standalone " "sayma_amc_drtio_master sayma_amc_drtio_satellite") - parser.add_argument("-H", "--host", metavar="HOSTNAME", + parser.add_argument("-H", "--host", type=str, default="lab.m-labs.hk", help="SSH host where the development board is located") - parser.add_argument('-b', "--board", metavar="BOARD", - type=str, default=None, + parser.add_argument('-b', "--board", + type=str, default="{boardtype}-1", help="Board to connect to on the development SSH host") - parser.add_argument("-d", "--device", metavar="DEVICENAME", - type=str, default="{board}.{hostname}", + parser.add_argument("-d", "--device", + type=str, default="{board}.{host}", help="Address or domain corresponding to the development board") - parser.add_argument("-s", "--serial", metavar="SERIAL", + parser.add_argument("-s", "--serial", type=str, default="/dev/ttyUSB_{board}", help="TTY device corresponding to the development board") - parser.add_argument("-l", "--lockfile", metavar="LOCKFILE", + parser.add_argument("-l", "--lockfile", type=str, default="/run/boards/{board}", help="The lockfile to be acquired for the duration of the actions") parser.add_argument("-w", "--wait", action="store_true", @@ -59,47 +61,30 @@ def main(): if args.verbose == args.quiet == 0: logging.getLogger().setLevel(logging.INFO) + def build_dir(*path, target=args.target): + return os.path.join("/tmp", target, *path) + build_args = [] if args.target == "kc705_dds": boardtype, firmware = "kc705", "runtime" elif args.target == "sayma_amc_standalone": - boardtype, firmware = "sayma", "runtime" - build_args += ["--rtm-csr-csv", "/tmp/sayma_rtm/sayma_rtm_csr.csv"] + boardtype, firmware = "sayma_amc", "runtime" + build_args += ["--rtm-csr-csv", build_dir("sayma_rtm_csr.csv", target="sayma_rtm")] elif args.target == "sayma_amc_drtio_master": - boardtype, firmware = "sayma", "runtime" + boardtype, firmware = "sayma_amc", "runtime" elif args.target == "sayma_amc_drtio_satellite": - boardtype, firmware = "sayma", "satman" + boardtype, firmware = "sayma_amc", "satman" elif args.target == "sayma_rtm": boardtype, firmware = "sayma_rtm", None else: raise NotImplementedError("unknown target {}".format(args.target)) - flash_args = ["-t", boardtype] - if boardtype == "sayma": - if args.board is None: - args.board = "sayma-1" - if args.board == "sayma-1": - flash_args += ["--preinit-command", "ftdi_location 5:2"] - elif args.board == "sayma-2": - flash_args += ["--preinit-command", "ftdi_location 3:10"] - elif args.board == "sayma-3": - flash_args += ["--preinit-command", "ftdi_location 5:1"] - else: - raise NotImplementedError("unknown --preinit-command for {}".format(boardtype)) + board = args.board.format(boardtype=boardtype) + device = args.device.format(board=board, host=args.host) + lockfile = args.lockfile.format(board=board) + serial = args.serial.format(board=board) client = SSHClient(args.host) - substs = { - "target": args.target, - "hostname": args.host, - "boardtype": boardtype, - "board": args.board if args.board else boardtype + "-1", - "firmware": firmware, - } - substs.update({ - "devicename": args.device.format(**substs), - "lockfile": args.lockfile.format(**substs), - "serial": args.serial.format(**substs), - }) flock_acquired = False flock_file = None # GC root @@ -109,10 +94,13 @@ def main(): if not flock_acquired: logger.info("Acquiring device lock") - flock = client.spawn_command("flock --verbose {block} {lockfile} sleep 86400" - .format(block="" if args.wait else "--nonblock", - **substs), - get_pty=True) + flock_args = ["flock"] + if not args.wait: + flock_args.append("--nonblock") + flock_args += ["--verbose", lockfile] + flock_args += ["sleep", "86400"] + + flock = client.spawn_command(flock_args, get_pty=True) flock_file = flock.makefile('r') while not flock_acquired: line = flock_file.readline() @@ -125,65 +113,52 @@ def main(): logger.error("Failed to get lock") sys.exit(1) - def artiq_flash(args, synchronous=True): - args = flash_args + args - args = ["'{}'".format(arg) if " " in arg else arg for arg in args] - cmd = client.spawn_command( - "artiq_flash " + " ".join(args), - **substs) - if synchronous: - client.drain(cmd) - else: - return cmd + def flash(*steps): + flash_args = ["artiq_flash"] + for _ in range(args.verbose): + flash_args.append("-v") + flash_args += ["-H", args.host, "-t", boardtype] + flash_args += ["--srcbuild", build_dir()] + flash_args += ["--preinit-command", "source /var/boards/{}".format(board)] + flash_args += steps + subprocess.check_call(flash_args) for action in args.actions: if action == "build": logger.info("Building target") try: - subprocess.check_call(["python3", - "-m", "artiq.gateware.targets." + args.target, - "--no-compile-gateware", - *build_args, - "--output-dir", - "/tmp/{target}".format(**substs)]) + subprocess.check_call([ + "python3", "-m", "artiq.gateware.targets." + args.target, + "--no-compile-gateware", + *build_args, + "--output-dir", build_dir()]) except subprocess.CalledProcessError: logger.error("Build failed") sys.exit(1) elif action == "clean": logger.info("Cleaning build directory") - target_dir = "/tmp/{target}".format(**substs) - if os.path.isdir(target_dir): - shutil.rmtree(target_dir) + shutil.rmtree(build_dir, ignore_errors=True) elif action == "reset": + lock() + logger.info("Resetting device") - artiq_flash(["reset"]) + flash("start") elif action == "flash" or action == "flash+log": - def upload_product(product, ext): - logger.info("Uploading {}".format(product)) - client.get_sftp().put("/tmp/{target}/software/{product}/{product}.{ext}" - .format(target=args.target, product=product, ext=ext), - "{tmp}/{product}.{ext}" - .format(tmp=client.tmp, product=product, ext=ext)) - - upload_product("bootloader", "bin") - upload_product(firmware, "fbi") + lock() logger.info("Flashing firmware") - artiq_flash(["-d", "{tmp}", "proxy", "bootloader", "firmware", - "start" if action == "flash" else ""]) + flash("proxy", "bootloader", "firmware") + logger.info("Booting firmware") if action == "flash+log": - logger.info("Booting firmware") - flterm = client.spawn_command( - "flterm {serial} " + - "--kernel {tmp}/{firmware}.bin " + - ("--upload-only" if action == "boot" else "--output-only"), - **substs) - artiq_flash(["start"], synchronous=False) + flterm = client.spawn_command(["flterm", serial, "--output-only"]) + flash("start") client.drain(flterm) + else: + flash("start") elif action == "connect": lock() @@ -218,10 +193,10 @@ def main(): while True: local_stream, peer_addr = listener.accept() logger.info("Accepting %s:%s and opening SSH channel to %s:%s", - *peer_addr, args.device, port) + *peer_addr, device, port) try: remote_stream = \ - transport.open_channel('direct-tcpip', (args.device, port), peer_addr) + transport.open_channel('direct-tcpip', (device, port), peer_addr) except Exception: logger.exception("Cannot open channel on port %s", port) continue @@ -238,17 +213,13 @@ def main(): logger.info("Forwarding ports {} to core device and logs from core device" .format(", ".join(map(str, ports)))) - client.run_command( - "flterm {serial} --output-only", - **substs) + client.run_command(["flterm", serial, "--output-only"]) elif action == "hotswap": logger.info("Hotswapping firmware") try: - subprocess.check_call(["python3", - "-m", "artiq.frontend.artiq_coreboot", "hotswap", - "/tmp/{target}/software/{firmware}/{firmware}.bin" - .format(target=args.target, firmware=firmware)]) + subprocess.check_call(["artiq_coreboot", "hotswap", + build_dir("software", firmware, firmware + ".bin")]) except subprocess.CalledProcessError: logger.error("Build failed") sys.exit(1) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 4e0bb2f99..fbba5c5ee 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -5,12 +5,13 @@ import os import subprocess import tempfile import shutil +import re from functools import partial from artiq import __artiq_dir__ as artiq_dir +from artiq.tools import verbosity_args, init_logger, logger, SSHClient, LocalClient from artiq.frontend.bit2bin import bit2bin - def get_argparser(): parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, @@ -35,6 +36,12 @@ Prerequisites: and replug the device. Ensure you are member of the plugdev group: 'sudo adduser $USER plugdev' and re-login. """) + + verbosity_args(parser) + + parser.add_argument("-H", "--host", metavar="HOSTNAME", + type=str, default=None, + help="SSH host where the development board is located") parser.add_argument("-t", "--target", default="kc705", help="target board, default: %(default)s, one of: " "kc705 kasli sayma_amc sayma_rtm") @@ -73,14 +80,34 @@ def proxy_path(): class Programmer: - def __init__(self, target_file, preinit_commands): - self.target_file = target_file + def __init__(self, client, target_file, preinit_commands): + self.client = client + if target_file: + self.target_file = self._transfer_script(target_file) + else: + self.target_file = None self.preinit_commands = preinit_commands self.prog = [] + def _transfer_script(self, script): + if isinstance(self.client, LocalClient): + return script + + def rewriter(content): + def repl(match): + return "[find {}]".format(self._transfer_script(match.group(1))) + return re.sub(r"\[find (.+?)\]", repl, content, re.DOTALL) + + script = os.path.join(scripts_path(), script) + return self.client.transfer_file(script, rewriter) + + def _command(self, cmd): + self.prog.append(cmd.replace("{", "{{").replace("}", "}}")) + def init(self): - self.prog.extend(self.preinit_commands) - self.prog.append("init") + for command in self.preinit_commands: + self._command(command) + self._command("init") def load(self, bitfile): raise NotImplementedError @@ -95,46 +122,49 @@ class Programmer: raise NotImplementedError def do(self): - self.prog.append("exit") - cmdline = [ - "openocd", - "-s", scripts_path() - ] + self._command("exit") + + cmdline = ["openocd"] + if isinstance(self.client, LocalClient): + cmdline += ["-s", scripts_path()] if self.target_file is not None: cmdline += ["-f", self.target_file] cmdline += ["-c", "; ".join(self.prog)] - subprocess.check_call(cmdline) + + self.client.run_command(cmdline) class ProgrammerJtagSpi7(Programmer): - def __init__(self, target, preinit_commands): - Programmer.__init__(self, os.path.join("board", target + ".cfg"), + def __init__(self, client, target, preinit_commands): + Programmer.__init__(self, client, os.path.join("board", target + ".cfg"), preinit_commands) self.init() def load(self, bitfile, pld=0): - self.prog.append("pld load {} {{{}}}".format(pld, bitfile)) + bitfile = self.client.transfer_file(bitfile) + self._command("pld load {} {{{}}}".format(pld, bitfile)) def proxy(self, proxy_bitfile, pld=0): - self.prog.append("jtagspi_init {} {{{}}}".format(pld, proxy_bitfile)) + proxy_bitfile = self.client.transfer_file(proxy_bitfile) + self._command("jtagspi_init {} {{{}}}".format(pld, proxy_bitfile)) def flash_binary(self, flashno, address, filename): # jtagspi_program supports only one flash assert flashno == 0 - self.prog.append("jtagspi_program {{{}}} 0x{:x}".format( + filename = self.client.transfer_file(filename) + self._command("jtagspi_program {{{}}} 0x{:x}".format( filename, address)) def start(self): - self.prog.append("xc7_program xc7.tap") + self._command("xc7_program xc7.tap") class ProgrammerSayma(Programmer): sector_size = 0x10000 - def __init__(self, preinit_commands): - # TODO: support Sayma RTM - Programmer.__init__(self, None, preinit_commands) - self.proxy_loaded = False + def __init__(self, client, preinit_commands): + Programmer.__init__(self, client, None, preinit_commands) + self.prog += [ "interface ftdi", "ftdi_device_desc \"Quad RS232-HS\"", @@ -161,11 +191,12 @@ class ProgrammerSayma(Programmer): self.init() def load(self, bitfile, pld=1): - self.prog.append("pld load {} {{{}}}".format(pld, bitfile)) + bitfile = self.client.transfer_file(bitfile) + self._command("pld load {} {{{}}}".format(pld, bitfile)) def proxy(self, proxy_bitfile, pld=1): self.load(proxy_bitfile, pld) - self.prog.append("reset halt") + self._command("reset halt") def flash_binary(self, flashno, address, filename): sector_first = address // self.sector_size @@ -173,25 +204,23 @@ class ProgrammerSayma(Programmer): assert size sector_last = sector_first + (size - 1) // self.sector_size assert sector_last >= sector_first - self.prog += [ - "flash probe xcu.spi{}".format(flashno), - "flash erase_sector {} {} {}".format(flashno, sector_first, sector_last), - "flash write_bank {} {{{}}} 0x{:x}".format(flashno, filename, address), - "flash verify_bank {} {{{}}} 0x{:x}".format(flashno, filename, address), - ] + filename = self.client.transfer_file(filename) + self._command("flash probe xcu.spi{}".format(flashno)) + self._command("flash erase_sector {} {} {}".format(flashno, sector_first, sector_last)) + self._command("flash write_bank {} {{{}}} 0x{:x}".format(flashno, filename, address)) + self._command("flash verify_bank {} {{{}}} 0x{:x}".format(flashno, filename, address)) def start(self): - self.proxy_loaded = False - self.prog.append("xcu_program xcu.tap") + self._command("xcu_program xcu.tap") def main(): - parser = get_argparser() - opts = parser.parse_args() + args = get_argparser().parse_args() + init_logger(args) config = { "kc705": { - "programmer_factory": partial(ProgrammerJtagSpi7, "kc705"), + "programmer_factory": partial(ProgrammerJtagSpi7, target="kc705"), "proxy_bitfile": "bscan_spi_xc7k325t.bit", "variants": ["nist_clock", "nist_qc2"], "gateware": (0, 0x000000), @@ -200,7 +229,7 @@ def main(): "firmware": (0, 0xb40000), }, "kasli": { - "programmer_factory": partial(ProgrammerJtagSpi7, "kasli"), + "programmer_factory": partial(ProgrammerJtagSpi7, target="kasli"), "proxy_bitfile": "bscan_spi_xc7a100t.bit", "variants": ["opticlock"], "gateware": (0, 0x000000), @@ -222,29 +251,34 @@ def main(): "proxy_bitfile": "bscan_spi_xcku040-sayma.bit", "gateware": (1, 0x150000), }, - }[opts.target] + }[args.target] - variant = opts.variant + variant = args.variant if "variants" in config: if variant is not None and variant not in config["variants"]: raise SystemExit("Invalid variant for this board") if variant is None: variant = config["variants"][0] - bin_dir = opts.dir + bin_dir = args.dir if bin_dir is None: if variant: - bin_name = "{}-{}".format(opts.target, variant) + bin_name = "{}-{}".format(args.target, variant) else: - bin_name = opts.target + bin_name = args.target bin_dir = os.path.join(artiq_dir, "binaries", bin_name) - if opts.srcbuild is None and not os.path.exists(bin_dir) and opts.action != ["start"]: + if args.srcbuild is None and not os.path.exists(bin_dir) and args.action != ["start"]: raise SystemExit("Binaries directory '{}' does not exist" .format(bin_dir)) - programmer = config["programmer_factory"](opts.preinit_command) + if args.host is None: + client = LocalClient() + else: + client = SSHClient(args.host) + + programmer = config["programmer_factory"](client, preinit_commands=args.preinit_command) conv = False - for action in opts.action: + for action in args.action: if action == "proxy": proxy_found = False for p in [bin_dir, proxy_path(), os.path.expanduser("~/.migen"), @@ -258,10 +292,10 @@ def main(): raise SystemExit( "proxy gateware bitstream {} not found".format(config["proxy_bitfile"])) elif action == "gateware": - if opts.srcbuild is None: + if args.srcbuild is None: path = bin_dir else: - path = os.path.join(opts.srcbuild, "gateware") + path = os.path.join(args.srcbuild, "gateware") bin = os.path.join(path, "top.bin") if not os.access(bin, os.R_OK): bin_handle, bin = tempfile.mkstemp() @@ -271,29 +305,29 @@ def main(): conv = True programmer.flash_binary(*config["gateware"], bin) elif action == "bootloader": - if opts.srcbuild is None: + if args.srcbuild is None: path = bin_dir else: - path = os.path.join(opts.srcbuild, "software", "bootloader") + path = os.path.join(args.srcbuild, "software", "bootloader") programmer.flash_binary(*config["bootloader"], os.path.join(path, "bootloader.bin")) elif action == "storage": - programmer.flash_binary(*config["storage"], opts.storage) + programmer.flash_binary(*config["storage"], args.storage) elif action == "firmware": if variant == "satellite": firmware_name = "satman" else: firmware_name = "runtime" - if opts.srcbuild is None: + if args.srcbuild is None: path = bin_dir else: - path = os.path.join(opts.srcbuild, "software", firmware_name) + path = os.path.join(args.srcbuild, "software", firmware_name) programmer.flash_binary(*config["firmware"], os.path.join(path, firmware_name + ".fbi")) elif action == "load": - if opts.srcbuild is None: + if args.srcbuild is None: path = bin_dir else: - path = os.path.join(opts.srcbuild, "gateware") + path = os.path.join(args.srcbuild, "gateware") programmer.load(os.path.join(path, "top.bit")) elif action == "start": programmer.start() diff --git a/artiq/tools.py b/artiq/tools.py index 95685100f..9f2cf97c5 100644 --- a/artiq/tools.py +++ b/artiq/tools.py @@ -3,10 +3,9 @@ import logging import sys import asyncio import collections -import os import atexit import string -import random +import os, random, tempfile, shutil, shlex, subprocess import numpy as np @@ -256,7 +255,45 @@ def get_user_config_dir(): return dir -class SSHClient: +class Client: + def transfer_file(self, filename, rewriter=None): + raise NotImplementedError + + def run_command(self, cmd, **kws): + raise NotImplementedError + + +class LocalClient(Client): + def __init__(self): + tmpname = "".join([random.Random().choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ") + for _ in range(6)]) + self.tmp = os.path.join(tempfile.gettempdir(), "artiq" + tmpname) + self._has_tmp = False + + def _prepare_tmp(self): + if not self._has_tmp: + os.mkdir(self.tmp) + atexit.register(lambda: shutil.rmtree(self.tmp, ignore_errors=True)) + self._has_tmp = True + + def transfer_file(self, filename, rewriter=None): + logger.debug("Transferring {}".format(filename)) + if rewriter is None: + return filename + else: + tmp_filename = os.path.join(self.tmp, filename.replace(os.sep, "_")) + with open(filename) as local: + self._prepare_tmp() + with open(tmp_filename, 'w') as tmp: + tmp.write(rewriter(local.read())) + return tmp_filename + + def run_command(self, cmd, **kws): + logger.debug("Executing {}".format(cmd)) + subprocess.check_call([arg.format(tmp=self.tmp, **kws) for arg in cmd]) + + +class SSHClient(Client): def __init__(self, host): self.host = host self.ssh = None @@ -284,16 +321,28 @@ class SSHClient: if self.sftp is None: self.sftp = self.get_ssh().open_sftp() self.sftp.mkdir(self.tmp) - atexit.register(lambda: self.run_command("rm -rf {tmp}")) + atexit.register(lambda: self.run_command(["rm", "-rf", "{tmp}"])) return self.sftp + def transfer_file(self, filename, rewriter=None): + remote_filename = "{}/{}".format(self.tmp, filename.replace("/", "_")) + logger.debug("Transferring {}".format(filename)) + if rewriter is None: + self.get_sftp().put(filename, remote_filename) + else: + with open(filename) as local: + with self.get_sftp().open(remote_filename, 'w') as remote: + remote.write(rewriter(local.read())) + return remote_filename + def spawn_command(self, cmd, get_pty=False, **kws): chan = self.get_transport().open_session() chan.set_combine_stderr(True) if get_pty: chan.get_pty() + cmd = " ".join([shlex.quote(arg.format(tmp=self.tmp, **kws)) for arg in cmd]) logger.debug("Executing {}".format(cmd)) - chan.exec_command(cmd.format(tmp=self.tmp, **kws)) + chan.exec_command(cmd) return chan def drain(self, chan): From 3922a7c64b97e24b1fe3a293f720ea27c1406862 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 19 Jan 2018 07:58:58 +0000 Subject: [PATCH 0219/2457] artiq_devtool: make locking reentrant. --- artiq/frontend/artiq_devtool.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 02ac2c211..c4c230ff4 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -13,6 +13,7 @@ import select import threading import os import shutil +import re from artiq.tools import verbosity_args, init_logger, logger, SSHClient @@ -93,6 +94,15 @@ def main(): nonlocal flock_file if not flock_acquired: + fuser_args = ["fuser", "-u", lockfile] + fuser = client.spawn_command(fuser_args) + fuser_file = fuser.makefile('r') + fuser_match = re.search(r"\((.+?)\)", fuser_file.readline()) + if fuser_match.group(1) == os.getenv("USER"): + logger.info("Lock already acquired by {}".format(os.getenv("USER"))) + flock_acquired = True + return + logger.info("Acquiring device lock") flock_args = ["flock"] if not args.wait: From 06388e21b7cb180ec5f5ce20d5804d8e5cd7a6ec Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 19 Jan 2018 07:59:23 +0000 Subject: [PATCH 0220/2457] doc: update DEVELOPER_NOTES. --- DEVELOPER_NOTES.rst | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/DEVELOPER_NOTES.rst b/DEVELOPER_NOTES.rst index 527322ef9..e119e541e 100644 --- a/DEVELOPER_NOTES.rst +++ b/DEVELOPER_NOTES.rst @@ -30,11 +30,11 @@ Minor (bugfix) releases Sharing development boards ========================== -To avoid conflicts for development boards on the server, while using a board you must hold the corresponding lock file present in ``/run/board``. Holding the lock file grants you exclusive access to the board. +To avoid conflicts for development boards on the server, while using a board you must hold the corresponding lock file present in ``/var/boards``. Holding the lock file grants you exclusive access to the board. To lock the KC705 for 30 minutes or until Ctrl-C is pressed: :: - flock --verbose /run/boards/kc705-1 sleep 1800 + flock --verbose /var/boards/kc705-1 sleep 1800 Check that the command acquires the lock, i.e. prints something such as: :: @@ -43,28 +43,52 @@ Check that the command acquires the lock, i.e. prints something such as: To lock the KC705 for the duration of the execution of a shell: :: - flock /run/boards/kc705-1 bash + flock /var/boards/kc705-1 bash You may also use this script: :: #!/bin/bash - exec flock /run/boards/$1 bash --rcfile <(cat ~/.bashrc; echo PS1=\"[$1\ lock]\ \$PS1\") + exec flock /var/boards/$1 bash --rcfile <(cat ~/.bashrc; echo PS1=\"[$1\ lock]\ \$PS1\") If the board is already locked by another user, the ``flock`` commands above will wait for the lock to be released. To determine which user is locking a board, use: :: - fuser -v /run/boards/kc705-1 + fuser -v /var/boards/kc705-1 Selecting a development board with artiq_flash ============================================== -Use the ``bus:port`` notation:: +The board lock file also contains the openocd commands for selecting the corresponding developer board: +:: + artiq_flash --preinit-command "$(cat /var/boards/sayma-1)" - artiq_flash --preinit-command "ftdi_location 5:2" # Sayma 1 - artiq_flash --preinit-command "ftdi_location 3:10" # Sayma 2 - artiq_flash --preinit-command "ftdi_location 5:1" # Sayma 3 + +Using developer tools +===================== + +ARTIQ ships with an ``artiq_devtool`` binary, which automates common actions arising when developing the board gateware and firmware on a machine other than the one to which the board is connected. + +.. argparse:: + :ref: artiq.frontend.artiq_compile.get_argparser + :prog: artiq_compile + +To build and flash the firmware for ``sayma_amc_standalone`` target: +:: + artiq_devtool -t sayma_amc_standalone build flash+log + +To build the same target, flash it to the 3rd connected board, and forward the core device ports (1380, 1381, ...) as well as logs on the serial port: +:: + artiq_devtool -t sayma_amc_standalone -b sayma-3 build flash connect + +While the previous command is running, to build a new firmware and hotswap it, i.e. run without reflashing the board: +:: + artiq_devtool -t sayma_amc_standalone build hotswap + +While the previous command is running, to reset a board, e.g. if it became unresponsive: +:: + artiq_devtool -t sayma_amc_standalone reset Deleting git branches From 4fd236d234e20b04e90a504ebccfe771a079694c Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 19 Jan 2018 08:28:04 +0000 Subject: [PATCH 0221/2457] artiq_flash: cache transferred artifacts. --- artiq/frontend/artiq_devtool.py | 24 ++++--- artiq/frontend/artiq_flash.py | 14 +++-- artiq/remoting.py | 108 ++++++++++++++++++++++++++++++++ artiq/tools.py | 104 +----------------------------- 4 files changed, 133 insertions(+), 117 deletions(-) create mode 100644 artiq/remoting.py diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index c4c230ff4..527ef0bce 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -15,7 +15,10 @@ import os import shutil import re -from artiq.tools import verbosity_args, init_logger, logger, SSHClient +from artiq.tools import verbosity_args, init_logger +from artiq.remoting import SSHClient + +logger = logging.getLogger(__name__) def get_argparser(): @@ -98,7 +101,7 @@ def main(): fuser = client.spawn_command(fuser_args) fuser_file = fuser.makefile('r') fuser_match = re.search(r"\((.+?)\)", fuser_file.readline()) - if fuser_match.group(1) == os.getenv("USER"): + if fuser_match and fuser_match.group(1) == os.getenv("USER"): logger.info("Lock already acquired by {}".format(os.getenv("USER"))) flock_acquired = True return @@ -156,19 +159,22 @@ def main(): logger.info("Resetting device") flash("start") - elif action == "flash" or action == "flash+log": + elif action == "flash": + lock() + + logger.info("Flashing and booting firmware") + flash("proxy", "bootloader", "firmware", "start") + + elif action == "flash+log": lock() logger.info("Flashing firmware") flash("proxy", "bootloader", "firmware") + flterm = client.spawn_command(["flterm", serial, "--output-only"]) logger.info("Booting firmware") - if action == "flash+log": - flterm = client.spawn_command(["flterm", serial, "--output-only"]) - flash("start") - client.drain(flterm) - else: - flash("start") + flash("start") + client.drain(flterm) elif action == "connect": lock() diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index fbba5c5ee..e5c68b5f7 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -9,9 +9,11 @@ import re from functools import partial from artiq import __artiq_dir__ as artiq_dir -from artiq.tools import verbosity_args, init_logger, logger, SSHClient, LocalClient +from artiq.tools import verbosity_args, init_logger +from artiq.remoting import SSHClient, LocalClient from artiq.frontend.bit2bin import bit2bin + def get_argparser(): parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, @@ -95,8 +97,8 @@ class Programmer: def rewriter(content): def repl(match): - return "[find {}]".format(self._transfer_script(match.group(1))) - return re.sub(r"\[find (.+?)\]", repl, content, re.DOTALL) + return self._transfer_script(match.group(1).decode()).encode() + return re.sub(rb"\[find (.+?)\]", repl, content, re.DOTALL) script = os.path.join(scripts_path(), script) return self.client.transfer_file(script, rewriter) @@ -178,9 +180,11 @@ class ProgrammerSayma(Programmer): "adapter_khz 5000", "transport select jtag", - "source [find cpld/xilinx-xc7.cfg]", # tap 0, pld 0 + # tap 0, pld 0 + "source {}".format(self._transfer_script("cpld/xilinx-xc7.cfg")), + # tap 1, pld 1 "set CHIP XCKU040", - "source [find cpld/xilinx-xcu.cfg]", # tap 1, pld 1 + "source {}".format(self._transfer_script("cpld/xilinx-xcu.cfg")), "target create xcu.proxy testee -chain-position xcu.tap", "set XILINX_USER1 0x02", diff --git a/artiq/remoting.py b/artiq/remoting.py new file mode 100644 index 000000000..0c6a99899 --- /dev/null +++ b/artiq/remoting.py @@ -0,0 +1,108 @@ +import os +import sys +import logging +import tempfile +import shutil +import shlex +import subprocess +import hashlib + +__all__ = ["LocalClient", "SSHClient"] + +logger = logging.getLogger(__name__) + + +class Client: + def transfer_file(self, filename, rewriter=None): + raise NotImplementedError + + def run_command(self, cmd, **kws): + raise NotImplementedError + + +class LocalClient(Client): + def __init__(self): + self._tmp = os.path.join(tempfile.gettempdir(), "artiq") + + def transfer_file(self, filename, rewriter=None): + logger.debug("Transferring {}".format(filename)) + if rewriter is None: + return filename + else: + os.makedirs(self._tmp, exist_ok=True) + with open(filename, 'rb') as local: + rewritten = rewriter(local.read()) + tmp_filename = os.path.join(self._tmp, hashlib.sha1(rewritten).hexdigest()) + with open(tmp_filename, 'wb') as tmp: + tmp.write(rewritten) + return tmp_filename + + def run_command(self, cmd, **kws): + logger.debug("Executing {}".format(cmd)) + subprocess.check_call([arg.format(tmp=self._tmp, **kws) for arg in cmd]) + + +class SSHClient(Client): + def __init__(self, host): + self.host = host + self.ssh = None + self.sftp = None + self._tmp = "/tmp/artiq" + self._cached = [] + + def get_ssh(self): + if self.ssh is None: + import paramiko + logging.getLogger("paramiko").setLevel(logging.WARNING) + self.ssh = paramiko.SSHClient() + self.ssh.load_system_host_keys() + self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + self.ssh.connect(self.host) + logger.debug("Connecting to {}".format(self.host)) + return self.ssh + + def get_transport(self): + return self.get_ssh().get_transport() + + def get_sftp(self): + if self.sftp is None: + self.sftp = self.get_ssh().open_sftp() + try: + self._cached = self.sftp.listdir(self._tmp) + except OSError: + self.sftp.mkdir(self._tmp) + return self.sftp + + def transfer_file(self, filename, rewriter=lambda x: x): + sftp = self.get_sftp() + with open(filename, 'rb') as local: + rewritten = rewriter(local.read()) + digest = hashlib.sha1(rewritten).hexdigest() + remote_filename = os.path.join(self._tmp, digest) + if digest in self._cached: + logger.debug("Using cached {}".format(filename)) + else: + logger.debug("Transferring {}".format(filename)) + with sftp.open(remote_filename, 'wb') as remote: + remote.write(rewritten) + return remote_filename + + def spawn_command(self, cmd, get_pty=False, **kws): + chan = self.get_transport().open_session() + chan.set_combine_stderr(True) + if get_pty: + chan.get_pty() + cmd = " ".join([shlex.quote(arg.format(tmp=self._tmp, **kws)) for arg in cmd]) + logger.debug("Executing {}".format(cmd)) + chan.exec_command(cmd) + return chan + + def drain(self, chan): + while True: + char = chan.recv(1) + if char == b"": + break + sys.stderr.write(char.decode("utf-8", errors='replace')) + + def run_command(self, cmd, **kws): + self.drain(self.spawn_command(cmd, **kws)) diff --git a/artiq/tools.py b/artiq/tools.py index 9f2cf97c5..f8f4314bf 100644 --- a/artiq/tools.py +++ b/artiq/tools.py @@ -3,9 +3,8 @@ import logging import sys import asyncio import collections -import atexit import string -import os, random, tempfile, shutil, shlex, subprocess +import os import numpy as np @@ -253,104 +252,3 @@ def get_user_config_dir(): dir = user_config_dir("artiq", "m-labs", major) os.makedirs(dir, exist_ok=True) return dir - - -class Client: - def transfer_file(self, filename, rewriter=None): - raise NotImplementedError - - def run_command(self, cmd, **kws): - raise NotImplementedError - - -class LocalClient(Client): - def __init__(self): - tmpname = "".join([random.Random().choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ") - for _ in range(6)]) - self.tmp = os.path.join(tempfile.gettempdir(), "artiq" + tmpname) - self._has_tmp = False - - def _prepare_tmp(self): - if not self._has_tmp: - os.mkdir(self.tmp) - atexit.register(lambda: shutil.rmtree(self.tmp, ignore_errors=True)) - self._has_tmp = True - - def transfer_file(self, filename, rewriter=None): - logger.debug("Transferring {}".format(filename)) - if rewriter is None: - return filename - else: - tmp_filename = os.path.join(self.tmp, filename.replace(os.sep, "_")) - with open(filename) as local: - self._prepare_tmp() - with open(tmp_filename, 'w') as tmp: - tmp.write(rewriter(local.read())) - return tmp_filename - - def run_command(self, cmd, **kws): - logger.debug("Executing {}".format(cmd)) - subprocess.check_call([arg.format(tmp=self.tmp, **kws) for arg in cmd]) - - -class SSHClient(Client): - def __init__(self, host): - self.host = host - self.ssh = None - self.sftp = None - - tmpname = "".join([random.Random().choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ") - for _ in range(6)]) - self.tmp = "/tmp/artiq" + tmpname - - def get_ssh(self): - if self.ssh is None: - import paramiko - logging.getLogger("paramiko").setLevel(logging.WARNING) - self.ssh = paramiko.SSHClient() - self.ssh.load_system_host_keys() - self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - self.ssh.connect(self.host) - logger.debug("Connecting to {}".format(self.host)) - return self.ssh - - def get_transport(self): - return self.get_ssh().get_transport() - - def get_sftp(self): - if self.sftp is None: - self.sftp = self.get_ssh().open_sftp() - self.sftp.mkdir(self.tmp) - atexit.register(lambda: self.run_command(["rm", "-rf", "{tmp}"])) - return self.sftp - - def transfer_file(self, filename, rewriter=None): - remote_filename = "{}/{}".format(self.tmp, filename.replace("/", "_")) - logger.debug("Transferring {}".format(filename)) - if rewriter is None: - self.get_sftp().put(filename, remote_filename) - else: - with open(filename) as local: - with self.get_sftp().open(remote_filename, 'w') as remote: - remote.write(rewriter(local.read())) - return remote_filename - - def spawn_command(self, cmd, get_pty=False, **kws): - chan = self.get_transport().open_session() - chan.set_combine_stderr(True) - if get_pty: - chan.get_pty() - cmd = " ".join([shlex.quote(arg.format(tmp=self.tmp, **kws)) for arg in cmd]) - logger.debug("Executing {}".format(cmd)) - chan.exec_command(cmd) - return chan - - def drain(self, chan): - while True: - char = chan.recv(1) - if char == b"": - break - sys.stderr.write(char.decode("utf-8", errors='replace')) - - def run_command(self, cmd, **kws): - self.drain(self.spawn_command(cmd, **kws)) From b1453eb85602031f3460789cb187f93475338e94 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 19 Jan 2018 08:28:36 +0000 Subject: [PATCH 0222/2457] Revert "conda: remove openocd version constraint." This reverts commit 3eb882b6b75c65a28d180374f20ad6f7995a988e. Fixes #892. --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 2c5d97334..290070c5e 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -22,7 +22,7 @@ requirements: - llvm-or1k 4.0.1 - llvmlite-artiq 0.20.0 - rust-core-or1k 1.23.0 19 - - openocd + - openocd 0.10.0+git2 - lit - outputcheck - coverage From 0cdbc5544a4f05fdcd6a5c3a7e56470f9869c3c6 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 19 Jan 2018 09:38:06 +0000 Subject: [PATCH 0223/2457] doc: update DEVELOPER_NOTES. --- DEVELOPER_NOTES.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/DEVELOPER_NOTES.rst b/DEVELOPER_NOTES.rst index e119e541e..e3b80f249 100644 --- a/DEVELOPER_NOTES.rst +++ b/DEVELOPER_NOTES.rst @@ -30,11 +30,11 @@ Minor (bugfix) releases Sharing development boards ========================== -To avoid conflicts for development boards on the server, while using a board you must hold the corresponding lock file present in ``/var/boards``. Holding the lock file grants you exclusive access to the board. +To avoid conflicts for development boards on the server, while using a board you must hold the corresponding lock file present in ``/var/artiq/boards``. Holding the lock file grants you exclusive access to the board. To lock the KC705 for 30 minutes or until Ctrl-C is pressed: :: - flock --verbose /var/boards/kc705-1 sleep 1800 + flock --verbose /var/artiq/boards/kc705-1 sleep 1800 Check that the command acquires the lock, i.e. prints something such as: :: @@ -43,18 +43,18 @@ Check that the command acquires the lock, i.e. prints something such as: To lock the KC705 for the duration of the execution of a shell: :: - flock /var/boards/kc705-1 bash + flock /var/artiq/boards/kc705-1 bash You may also use this script: :: #!/bin/bash - exec flock /var/boards/$1 bash --rcfile <(cat ~/.bashrc; echo PS1=\"[$1\ lock]\ \$PS1\") + exec flock /var/artiq/boards/$1 bash --rcfile <(cat ~/.bashrc; echo PS1=\"[$1\ lock]\ \$PS1\") If the board is already locked by another user, the ``flock`` commands above will wait for the lock to be released. To determine which user is locking a board, use: :: - fuser -v /var/boards/kc705-1 + fuser -v /var/artiq/boards/kc705-1 Selecting a development board with artiq_flash @@ -62,7 +62,7 @@ Selecting a development board with artiq_flash The board lock file also contains the openocd commands for selecting the corresponding developer board: :: - artiq_flash --preinit-command "$(cat /var/boards/sayma-1)" + artiq_flash --preinit-command "$(cat /var/artiq/boards/sayma-1)" Using developer tools From 3c0b164e4da509acfd79e730763e6d35789e695a Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 19 Jan 2018 09:43:03 +0000 Subject: [PATCH 0224/2457] artiq_devtool: update for new board file convention. Also fix a typo in documentation. --- DEVELOPER_NOTES.rst | 12 +++++----- artiq/frontend/artiq_devtool.py | 41 +++++++++++++++++---------------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/DEVELOPER_NOTES.rst b/DEVELOPER_NOTES.rst index e3b80f249..687ceaca4 100644 --- a/DEVELOPER_NOTES.rst +++ b/DEVELOPER_NOTES.rst @@ -30,11 +30,11 @@ Minor (bugfix) releases Sharing development boards ========================== -To avoid conflicts for development boards on the server, while using a board you must hold the corresponding lock file present in ``/var/artiq/boards``. Holding the lock file grants you exclusive access to the board. +To avoid conflicts for development boards on the server, while using a board you must hold the corresponding lock file present in ``/var/lib/artiq/boards``. Holding the lock file grants you exclusive access to the board. To lock the KC705 for 30 minutes or until Ctrl-C is pressed: :: - flock --verbose /var/artiq/boards/kc705-1 sleep 1800 + flock --verbose /var/lib/artiq/boards/kc705-1 sleep 1800 Check that the command acquires the lock, i.e. prints something such as: :: @@ -43,18 +43,18 @@ Check that the command acquires the lock, i.e. prints something such as: To lock the KC705 for the duration of the execution of a shell: :: - flock /var/artiq/boards/kc705-1 bash + flock /var/lib/artiq/boards/kc705-1 bash You may also use this script: :: #!/bin/bash - exec flock /var/artiq/boards/$1 bash --rcfile <(cat ~/.bashrc; echo PS1=\"[$1\ lock]\ \$PS1\") + exec flock /var/lib/artiq/boards/$1 bash --rcfile <(cat ~/.bashrc; echo PS1=\"[$1\ lock]\ \$PS1\") If the board is already locked by another user, the ``flock`` commands above will wait for the lock to be released. To determine which user is locking a board, use: :: - fuser -v /var/artiq/boards/kc705-1 + fuser -v /var/lib/artiq/boards/kc705-1 Selecting a development board with artiq_flash @@ -62,7 +62,7 @@ Selecting a development board with artiq_flash The board lock file also contains the openocd commands for selecting the corresponding developer board: :: - artiq_flash --preinit-command "$(cat /var/artiq/boards/sayma-1)" + artiq_flash --preinit-command "$(cat /var/lib/artiq/boards/sayma-1)" Using developer tools diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 527ef0bce..8afd5a1aa 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -37,17 +37,18 @@ def get_argparser(): type=str, default="lab.m-labs.hk", help="SSH host where the development board is located") parser.add_argument('-b', "--board", - type=str, default="{boardtype}-1", + type=str, default="{board_type}-1", help="Board to connect to on the development SSH host") - parser.add_argument("-d", "--device", - type=str, default="{board}.{host}", - help="Address or domain corresponding to the development board") + parser.add_argument("-B", "--board-file", + type=str, default="/var/lib/artiq/boards/{board}", + help="The board file containing the openocd initialization commands; " + "it is also used as the lock file") parser.add_argument("-s", "--serial", type=str, default="/dev/ttyUSB_{board}", help="TTY device corresponding to the development board") - parser.add_argument("-l", "--lockfile", - type=str, default="/run/boards/{board}", - help="The lockfile to be acquired for the duration of the actions") + parser.add_argument("-d", "--device", + type=str, default="{board}.{host}", + help="Address or domain corresponding to the development board") parser.add_argument("-w", "--wait", action="store_true", help="Wait for the board to unlock instead of aborting the actions") @@ -70,23 +71,23 @@ def main(): build_args = [] if args.target == "kc705_dds": - boardtype, firmware = "kc705", "runtime" + board_type, firmware = "kc705", "runtime" elif args.target == "sayma_amc_standalone": - boardtype, firmware = "sayma_amc", "runtime" + board_type, firmware = "sayma_amc", "runtime" build_args += ["--rtm-csr-csv", build_dir("sayma_rtm_csr.csv", target="sayma_rtm")] elif args.target == "sayma_amc_drtio_master": - boardtype, firmware = "sayma_amc", "runtime" + board_type, firmware = "sayma_amc", "runtime" elif args.target == "sayma_amc_drtio_satellite": - boardtype, firmware = "sayma_amc", "satman" + board_type, firmware = "sayma_amc", "satman" elif args.target == "sayma_rtm": - boardtype, firmware = "sayma_rtm", None + board_type, firmware = "sayma_rtm", None else: raise NotImplementedError("unknown target {}".format(args.target)) - board = args.board.format(boardtype=boardtype) - device = args.device.format(board=board, host=args.host) - lockfile = args.lockfile.format(board=board) - serial = args.serial.format(board=board) + board = args.board.format(board_type=board_type) + board_file = args.board_file.format(board=board) + device = args.device.format(board=board, host=args.host) + serial = args.serial.format(board=board) client = SSHClient(args.host) @@ -97,7 +98,7 @@ def main(): nonlocal flock_file if not flock_acquired: - fuser_args = ["fuser", "-u", lockfile] + fuser_args = ["fuser", "-u", board_file] fuser = client.spawn_command(fuser_args) fuser_file = fuser.makefile('r') fuser_match = re.search(r"\((.+?)\)", fuser_file.readline()) @@ -110,7 +111,7 @@ def main(): flock_args = ["flock"] if not args.wait: flock_args.append("--nonblock") - flock_args += ["--verbose", lockfile] + flock_args += ["--verbose", board_file] flock_args += ["sleep", "86400"] flock = client.spawn_command(flock_args, get_pty=True) @@ -130,9 +131,9 @@ def main(): flash_args = ["artiq_flash"] for _ in range(args.verbose): flash_args.append("-v") - flash_args += ["-H", args.host, "-t", boardtype] + flash_args += ["-H", args.host, "-t", board_type] flash_args += ["--srcbuild", build_dir()] - flash_args += ["--preinit-command", "source /var/boards/{}".format(board)] + flash_args += ["--preinit-command", "source {}".format(board_file)] flash_args += steps subprocess.check_call(flash_args) From cdbf95d46aaac36c453d9c41c7a193f1ce451aee Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 19 Jan 2018 18:31:20 +0800 Subject: [PATCH 0225/2457] kasli: fix permissions --- artiq/gateware/targets/kasli.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 artiq/gateware/targets/kasli.py diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py old mode 100644 new mode 100755 From d27727968cd1bdb9bf0e9d7d92e180aa208c76b5 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 19 Jan 2018 12:17:54 +0100 Subject: [PATCH 0226/2457] add artix7 gtp (3gbps), share clock aligner with gth_ultrascale --- .../drtio/transceiver/clock_aligner.py | 114 +++++++ .../drtio/transceiver/gth_ultrascale.py | 3 +- .../drtio/transceiver/gth_ultrascale_init.py | 112 +------ .../gateware/drtio/transceiver/gtp_7series.py | 251 ++++++++++++++ .../drtio/transceiver/gtp_7series_init.py | 305 ++++++++++++++++++ 5 files changed, 672 insertions(+), 113 deletions(-) create mode 100644 artiq/gateware/drtio/transceiver/clock_aligner.py create mode 100644 artiq/gateware/drtio/transceiver/gtp_7series.py create mode 100644 artiq/gateware/drtio/transceiver/gtp_7series_init.py diff --git a/artiq/gateware/drtio/transceiver/clock_aligner.py b/artiq/gateware/drtio/transceiver/clock_aligner.py new file mode 100644 index 000000000..9d17d2b77 --- /dev/null +++ b/artiq/gateware/drtio/transceiver/clock_aligner.py @@ -0,0 +1,114 @@ +from math import ceil +from functools import reduce +from operator import add + +from migen import * +from migen.genlib.cdc import MultiReg, PulseSynchronizer + + +# Changes the phase of the transceiver RX clock to align the comma to +# the LSBs of RXDATA, fixing the latency. +# +# This is implemented by repeatedly resetting the transceiver until it +# gives out the correct phase. Each reset gives a random phase. +# +# If Xilinx had designed the GTX transceiver correctly, RXSLIDE_MODE=PMA +# would achieve this faster and in a cleaner way. But: +# * the phase jumps are of 2 UI at every second RXSLIDE pulse, instead +# of 1 UI at every pulse. It is unclear what the latency becomes. +# * RXSLIDE_MODE=PMA cannot be used with the RX buffer bypassed. +# Those design flaws make RXSLIDE_MODE=PMA yet another broken and useless +# transceiver "feature". +# +# Warning: Xilinx transceivers are LSB first, and comma needs to be flipped +# compared to the usual 8b10b binary representation. +class BruteforceClockAligner(Module): + def __init__(self, comma, tx_clk_freq, check_period=6e-3): + self.rxdata = Signal(20) + self.restart = Signal() + + self.ready = Signal() + + check_max_val = ceil(check_period*tx_clk_freq) + check_counter = Signal(max=check_max_val+1) + check = Signal() + reset_check_counter = Signal() + self.sync.rtio_tx += [ + check.eq(0), + If(reset_check_counter, + check_counter.eq(check_max_val) + ).Else( + If(check_counter == 0, + check.eq(1), + check_counter.eq(check_max_val) + ).Else( + check_counter.eq(check_counter-1) + ) + ) + ] + + checks_reset = PulseSynchronizer("rtio_tx", "rtio_rx") + self.submodules += checks_reset + + comma_n = ~comma & 0b1111111111 + comma_seen_rxclk = Signal() + comma_seen = Signal() + comma_seen_rxclk.attr.add("no_retiming") + self.specials += MultiReg(comma_seen_rxclk, comma_seen) + self.sync.rtio_rx += \ + If(checks_reset.o, + comma_seen_rxclk.eq(0) + ).Elif((self.rxdata[:10] == comma) | (self.rxdata[:10] == comma_n), + comma_seen_rxclk.eq(1) + ) + + error_seen_rxclk = Signal() + error_seen = Signal() + error_seen_rxclk.attr.add("no_retiming") + self.specials += MultiReg(error_seen_rxclk, error_seen) + rx1cnt = Signal(max=11) + self.sync.rtio_rx += [ + rx1cnt.eq(reduce(add, [self.rxdata[i] for i in range(10)])), + If(checks_reset.o, + error_seen_rxclk.eq(0) + ).Elif((rx1cnt != 4) & (rx1cnt != 5) & (rx1cnt != 6), + error_seen_rxclk.eq(1) + ) + ] + + fsm = ClockDomainsRenamer("rtio_tx")(FSM(reset_state="WAIT_COMMA")) + self.submodules += fsm + + fsm.act("WAIT_COMMA", + If(check, + # Errors are still OK at this stage, as the transceiver + # has just been reset and may output garbage data. + If(comma_seen, + NextState("WAIT_NOERROR") + ).Else( + self.restart.eq(1) + ), + checks_reset.i.eq(1) + ) + ) + fsm.act("WAIT_NOERROR", + If(check, + If(comma_seen & ~error_seen, + NextState("READY") + ).Else( + self.restart.eq(1), + NextState("WAIT_COMMA") + ), + checks_reset.i.eq(1) + ) + ) + fsm.act("READY", + reset_check_counter.eq(1), + self.ready.eq(1), + If(error_seen, + checks_reset.i.eq(1), + self.restart.eq(1), + NextState("WAIT_COMMA") + ) + ) + diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index d6a74bb04..5d5cf2575 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -3,14 +3,13 @@ from operator import or_ from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer -from migen.genlib.cdc import MultiReg -from misoc.interconnect.csr import * from misoc.cores.code_8b10b import Encoder, Decoder from microscope import * from artiq.gateware.drtio.core import TransceiverInterface, ChannelInterface +from artiq.gateware.drtio.transceiver.clock_aligner import BruteforceClockAligner from artiq.gateware.drtio.transceiver.gth_ultrascale_init import * diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py b/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py index 0c2734051..8d188f6c0 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py @@ -1,13 +1,11 @@ from math import ceil -from functools import reduce -from operator import add from migen import * from migen.genlib.cdc import MultiReg, PulseSynchronizer from migen.genlib.misc import WaitTimer -__all__ = ["BruteforceClockAligner", "GTHInit"] +__all__ = ["GTHInit"] class GTHInit(Module): @@ -140,111 +138,3 @@ class GTHInit(Module): self.done.eq(1), If(self.restart, NextState("RESET_ALL")) ) - - -# Changes the phase of the transceiver RX clock to align the comma to -# the LSBs of RXDATA, fixing the latency. -# -# This is implemented by repeatedly resetting the transceiver until it -# gives out the correct phase. Each reset gives a random phase. -# -# If Xilinx had designed the GTX transceiver correctly, RXSLIDE_MODE=PMA -# would achieve this faster and in a cleaner way. But: -# * the phase jumps are of 2 UI at every second RXSLIDE pulse, instead -# of 1 UI at every pulse. It is unclear what the latency becomes. -# * RXSLIDE_MODE=PMA cannot be used with the RX buffer bypassed. -# Those design flaws make RXSLIDE_MODE=PMA yet another broken and useless -# transceiver "feature". -# -# Warning: Xilinx transceivers are LSB first, and comma needs to be flipped -# compared to the usual 8b10b binary representation. -class BruteforceClockAligner(Module): - def __init__(self, comma, tx_clk_freq, check_period=6e-3): - self.rxdata = Signal(20) - self.restart = Signal() - - self.ready = Signal() - - check_max_val = ceil(check_period*tx_clk_freq) - check_counter = Signal(max=check_max_val+1) - check = Signal() - reset_check_counter = Signal() - self.sync.rtio_tx += [ - check.eq(0), - If(reset_check_counter, - check_counter.eq(check_max_val) - ).Else( - If(check_counter == 0, - check.eq(1), - check_counter.eq(check_max_val) - ).Else( - check_counter.eq(check_counter-1) - ) - ) - ] - - checks_reset = PulseSynchronizer("rtio_tx", "rtio_rx") - self.submodules += checks_reset - - comma_n = ~comma & 0b1111111111 - comma_seen_rxclk = Signal() - comma_seen = Signal() - comma_seen_rxclk.attr.add("no_retiming") - self.specials += MultiReg(comma_seen_rxclk, comma_seen) - self.sync.rtio_rx += \ - If(checks_reset.o, - comma_seen_rxclk.eq(0) - ).Elif((self.rxdata[:10] == comma) | (self.rxdata[:10] == comma_n), - comma_seen_rxclk.eq(1) - ) - - error_seen_rxclk = Signal() - error_seen = Signal() - error_seen_rxclk.attr.add("no_retiming") - self.specials += MultiReg(error_seen_rxclk, error_seen) - rx1cnt = Signal(max=11) - self.sync.rtio_rx += [ - rx1cnt.eq(reduce(add, [self.rxdata[i] for i in range(10)])), - If(checks_reset.o, - error_seen_rxclk.eq(0) - ).Elif((rx1cnt != 4) & (rx1cnt != 5) & (rx1cnt != 6), - error_seen_rxclk.eq(1) - ) - ] - - fsm = ClockDomainsRenamer("rtio_tx")(FSM(reset_state="WAIT_COMMA")) - self.submodules += fsm - - fsm.act("WAIT_COMMA", - If(check, - # Errors are still OK at this stage, as the transceiver - # has just been reset and may output garbage data. - If(comma_seen, - NextState("WAIT_NOERROR") - ).Else( - self.restart.eq(1) - ), - checks_reset.i.eq(1) - ) - ) - fsm.act("WAIT_NOERROR", - If(check, - If(comma_seen & ~error_seen, - NextState("READY") - ).Else( - self.restart.eq(1), - NextState("WAIT_COMMA") - ), - checks_reset.i.eq(1) - ) - ) - fsm.act("READY", - reset_check_counter.eq(1), - self.ready.eq(1), - If(error_seen, - checks_reset.i.eq(1), - self.restart.eq(1), - NextState("WAIT_COMMA") - ) - ) - diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py new file mode 100644 index 000000000..4c6fed24b --- /dev/null +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -0,0 +1,251 @@ +from functools import reduce +from operator import or_ + +from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +from misoc.cores.code_8b10b import Encoder, Decoder + +from artiq.gateware.drtio.core import TransceiverInterface, ChannelInterface +from artiq.gateware.drtio.transceiver.clock_aligner import BruteforceClockAligner +from artiq.gateware.drtio.transceiver.gtp_7series_init import * + + +class GTPSingle(Module): + def __init__(self, qpll_channel, tx_pads, rx_pads, sys_clk_freq, rtio_clk_freq, mode): + if mode != "master": + raise NotImplementedError + self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( + Encoder(2, True)) + self.submodules.decoders = decoders = [ClockDomainsRenamer("rtio_rx")( + (Decoder(True))) for _ in range(2)] + self.rx_ready = Signal() + + # transceiver direct clock outputs + # useful to specify clock constraints in a way palatable to Vivado + self.txoutclk = Signal() + self.rxoutclk = Signal() + + # # # + + # TX generates RTIO clock, init must be in system domain + tx_init = GTPTXInit(sys_clk_freq) + # RX receives restart commands from RTIO domain + rx_init = ClockDomainsRenamer("rtio_tx")(GTPRXInit(rtio_clk_freq)) + self.submodules += tx_init, rx_init + + self.comb += [ + qpll_channel.reset.eq(tx_init.pllreset), + tx_init.plllock.eq(qpll_channel.lock), + rx_init.plllock.eq(qpll_channel.lock), + ] + + txdata = Signal(20) + rxdata = Signal(20) + rxphaligndone = Signal() + self.specials += \ + Instance("GTPE2_CHANNEL", + # Reset modes + i_GTRESETSEL=0, + i_RESETOVRD=0, + + # DRP + i_DRPADDR=rx_init.drpaddr, + i_DRPCLK=ClockSignal("rtio_tx"), + i_DRPDI=rx_init.drpdi, + o_DRPDO=rx_init.drpdo, + i_DRPEN=rx_init.drpen, + o_DRPRDY=rx_init.drprdy, + i_DRPWE=rx_init.drpwe, + + # PMA Attributes + p_PMA_RSV=0x333, + p_PMA_RSV2=0x2040, + p_PMA_RSV3=0, + p_PMA_RSV4=0, + p_RX_BIAS_CFG=0b0000111100110011, + p_RX_CM_SEL=0b01, + p_RX_CM_TRIM=0b1010, + p_RX_OS_CFG=0b10000000, + p_RXLPM_IPCM_CFG=1, + i_RXELECIDLEMODE=0b11, + i_RXOSINTCFG=0b0010, + i_RXOSINTEN=1, + + # Power-Down Attributes + p_PD_TRANS_TIME_FROM_P2=0x3c, + p_PD_TRANS_TIME_NONE_P2=0x3c, + p_PD_TRANS_TIME_TO_P2=0x64, + + # QPLL + i_PLL0CLK=qpll_channel.clk, + i_PLL0REFCLK=qpll_channel.refclk, + + # TX clock + p_TXBUF_EN="FALSE", + p_TX_XCLK_SEL="TXUSR", + o_TXOUTCLK=self.txoutclk, + p_TXOUT_DIV=2, + i_TXSYSCLKSEL=0b00, + i_TXOUTCLKSEL=0b11, + + # TX Startup/Reset + i_GTTXRESET=tx_init.gttxreset, + o_TXRESETDONE=tx_init.txresetdone, + p_TXSYNC_OVRD=1, + i_TXDLYSRESET=tx_init.txdlysreset, + o_TXDLYSRESETDONE=tx_init.txdlysresetdone, + i_TXPHINIT=tx_init.txphinit, + o_TXPHINITDONE=tx_init.txphinitdone, + i_TXPHALIGNEN=1, + i_TXPHALIGN=tx_init.txphalign, + o_TXPHALIGNDONE=tx_init.txphaligndone, + i_TXDLYEN=tx_init.txdlyen, + i_TXUSERRDY=tx_init.txuserrdy, + + # TX data + p_TX_DATA_WIDTH=20, + i_TXCHARDISPMODE=Cat(txdata[9], txdata[19]), + i_TXCHARDISPVAL=Cat(txdata[8], txdata[18]), + i_TXDATA=Cat(txdata[:8], txdata[10:18]), + i_TXUSRCLK=ClockSignal("rtio_tx"), + i_TXUSRCLK2=ClockSignal("rtio_tx"), + + # TX electrical + i_TXBUFDIFFCTRL=0b100, + i_TXDIFFCTRL=0b1000, + + # RX Startup/Reset + i_GTRXRESET=rx_init.gtrxreset, + o_RXRESETDONE=rx_init.rxresetdone, + i_RXDLYSRESET=rx_init.rxdlysreset, + o_RXDLYSRESETDONE=rx_init.rxdlysresetdone, + o_RXPHALIGNDONE=rxphaligndone, + i_RXSYNCALLIN=rxphaligndone, + i_RXUSERRDY=rx_init.rxuserrdy, + i_RXSYNCIN=0, + i_RXSYNCMODE=1, + p_RXSYNC_MULTILANE=0, + p_RXSYNC_OVRD=0, + o_RXSYNCDONE=rx_init.rxsyncdone, + p_RXPMARESET_TIME=0b11, + o_RXPMARESETDONE=rx_init.rxpmaresetdone, + + # RX clock + p_RX_CLK25_DIV=5, + p_TX_CLK25_DIV=5, + p_RX_XCLK_SEL="RXUSR", + p_RXOUT_DIV=2, + i_RXSYSCLKSEL=0b00, + i_RXOUTCLKSEL=0b010, + o_RXOUTCLK=self.rxoutclk, + i_RXUSRCLK=ClockSignal("rtio_rx"), + i_RXUSRCLK2=ClockSignal("rtio_rx"), + p_RXCDR_CFG=0x0000107FE206001041010, + p_RXPI_CFG1=1, + p_RXPI_CFG2=1, + + # RX Clock Correction Attributes + p_CLK_CORRECT_USE="FALSE", + + # RX data + p_RXBUF_EN="FALSE", + p_RXDLY_CFG=0x001f, + p_RXDLY_LCFG=0x030, + p_RXPHDLY_CFG=0x084020, + p_RXPH_CFG=0xc00002, + p_RX_DATA_WIDTH=20, + i_RXCOMMADETEN=1, + i_RXDLYBYPASS=0, + i_RXDDIEN=1, + o_RXDISPERR=Cat(rxdata[9], rxdata[19]), + o_RXCHARISK=Cat(rxdata[8], rxdata[18]), + o_RXDATA=Cat(rxdata[:8], rxdata[10:18]), + + # Pads + i_GTPRXP=rx_pads.p, + i_GTPRXN=rx_pads.n, + o_GTPTXP=tx_pads.p, + o_GTPTXN=tx_pads.n + ) + + # tx clocking + tx_reset_deglitched = Signal() + tx_reset_deglitched.attr.add("no_retiming") + self.sync += tx_reset_deglitched.eq(~tx_init.done) + self.clock_domains.cd_rtio_tx = ClockDomain() + if mode == "master": + txoutclk_bufg = Signal() + txoutclk_bufr = Signal() + tx_bufr_div = 150.e6/rtio_clk_freq + assert tx_bufr_div == int(tx_bufr_div) + self.specials += [ + Instance("BUFG", i_I=self.txoutclk, o_O=txoutclk_bufg), + Instance("BUFR", i_I=txoutclk_bufg, o_O=txoutclk_bufr, + i_CE=1, p_BUFR_DIVIDE=str(int(tx_bufr_div))), + Instance("BUFG", i_I=txoutclk_bufr, o_O=self.cd_rtio_tx.clk) + ] + self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched) + + # rx clocking + rx_reset_deglitched = Signal() + rx_reset_deglitched.attr.add("no_retiming") + self.sync.rtio_tx += rx_reset_deglitched.eq(~rx_init.done) + self.clock_domains.cd_rtio_rx = ClockDomain() + self.specials += [ + Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rtio_rx.clk), + AsyncResetSynchronizer(self.cd_rtio_rx, rx_reset_deglitched) + ] + + # tx data + self.comb += txdata.eq(Cat(*[encoder.output[i] for i in range(2)])) + + # rx data + for i in range(2): + self.comb += decoders[i].input.eq(rxdata[10*i:10*(i+1)]) + + # clock alignment + clock_aligner = BruteforceClockAligner(0b0101111100, rtio_clk_freq, check_period=10e-3) + self.submodules += clock_aligner + self.comb += [ + clock_aligner.rxdata.eq(rxdata), + rx_init.restart.eq(clock_aligner.restart), + self.rx_ready.eq(clock_aligner.ready) + ] + + +class GTP(Module, TransceiverInterface): + def __init__(self, qpll_channel, tx_pads, rx_pads, sys_clk_freq, rtio_clk_freq, master=0): + self.nchannels = nchannels = len(tx_pads) + self.gtps = [] + if nchannels >= 1: + raise NotImplementedError + + # # # + + rtio_tx_clk = Signal() + channel_interfaces = [] + for i in range(nchannels): + mode = "master" if i == master else "slave" + gtp = GTPSingle(qpll_channel, tx_pads[i], rx_pads[i], sys_clk_freq, rtio_clk_freq, mode) + if mode == "master": + self.comb += rtio_tx_clk.eq(gtp.cd_rtio_tx.clk) + else: + self.comb += gtp.cd_rtio_tx.clk.eq(rtio_tx_clk) + self.gtps.append(gtp) + setattr(self.submodules, "gtp"+str(i), gtp) + channel_interface = ChannelInterface(gtp.encoder, gtp.decoders) + self.comb += channel_interface.rx_ready.eq(gtp.rx_ready) + channel_interfaces.append(channel_interface) + + TransceiverInterface.__init__(self, channel_interfaces) + + self.comb += [ + self.cd_rtio.clk.eq(self.gtps[master].cd_rtio_tx.clk), + self.cd_rtio.rst.eq(reduce(or_, [gtp.cd_rtio_tx.rst for gtp in self.gtps])) + ] + for i in range(nchannels): + self.comb += [ + getattr(self, "cd_rtio_rx" + str(i)).clk.eq(self.gtps[i].cd_rtio_rx.clk), + getattr(self, "cd_rtio_rx" + str(i)).rst.eq(self.gtps[i].cd_rtio_rx.rst) + ] diff --git a/artiq/gateware/drtio/transceiver/gtp_7series_init.py b/artiq/gateware/drtio/transceiver/gtp_7series_init.py new file mode 100644 index 000000000..e3f2d9316 --- /dev/null +++ b/artiq/gateware/drtio/transceiver/gtp_7series_init.py @@ -0,0 +1,305 @@ +from math import ceil + +from migen import * +from migen.genlib.cdc import MultiReg, PulseSynchronizer +from migen.genlib.misc import WaitTimer + + +__all__ = ["GTPTXInit", "GTPRXInit"] + + +class GTPTXInit(Module): + def __init__(self, sys_clk_freq): + self.done = Signal() + self.restart = Signal() + + # GTP signals + self.plllock = Signal() + self.pllreset = Signal() + self.gttxreset = Signal() + self.txresetdone = Signal() + self.txdlysreset = Signal() + self.txdlysresetdone = Signal() + self.txphinit = Signal() + self.txphinitdone = Signal() + self.txphalign = Signal() + self.txphaligndone = Signal() + self.txdlyen = Signal() + self.txuserrdy = Signal() + + # # # + + # Double-latch transceiver asynch outputs + plllock = Signal() + txresetdone = Signal() + txdlysresetdone = Signal() + txphinitdone = Signal() + txphaligndone = Signal() + self.specials += [ + MultiReg(self.plllock, plllock), + MultiReg(self.txresetdone, txresetdone), + MultiReg(self.txdlysresetdone, txdlysresetdone), + MultiReg(self.txphinitdone, txphinitdone), + MultiReg(self.txphaligndone, txphaligndone) + ] + + # Deglitch FSM outputs driving transceiver asynch inputs + gttxreset = Signal() + txdlysreset = Signal() + txphinit = Signal() + txphalign = Signal() + txdlyen = Signal() + txuserrdy = Signal() + self.sync += [ + self.gttxreset.eq(gttxreset), + self.txdlysreset.eq(txdlysreset), + self.txphinit.eq(txphinit), + self.txphalign.eq(txphalign), + self.txdlyen.eq(txdlyen), + self.txuserrdy.eq(txuserrdy) + ] + + # PLL reset must be at least 500us + pll_reset_cycles = ceil(500e-9*sys_clk_freq) + pll_reset_timer = WaitTimer(pll_reset_cycles) + self.submodules += pll_reset_timer + + startup_fsm = ResetInserter()(FSM(reset_state="PLL_RESET")) + self.submodules += startup_fsm + + ready_timer = WaitTimer(int(1e-3*sys_clk_freq)) + self.submodules += ready_timer + self.comb += [ + ready_timer.wait.eq(~self.done & ~startup_fsm.reset), + startup_fsm.reset.eq(self.restart | ready_timer.done) + ] + + txphaligndone_r = Signal(reset=1) + txphaligndone_rising = Signal() + self.sync += txphaligndone_r.eq(txphaligndone) + self.comb += txphaligndone_rising.eq(txphaligndone & ~txphaligndone_r) + + startup_fsm.act("PLL_RESET", + self.pllreset.eq(1), + pll_reset_timer.wait.eq(1), + If(pll_reset_timer.done, + NextState("GTP_RESET") + ) + ) + startup_fsm.act("GTP_RESET", + gttxreset.eq(1), + If(plllock, + NextState("WAIT_GTP_RESET_DONE") + ) + ) + # Release GTP reset and wait for GTP resetdone + # (from UG482, GTP is reset on falling edge + # of gttxreset) + startup_fsm.act("WAIT_GTP_RESET_DONE", + txuserrdy.eq(1), + If(txresetdone, NextState("ALIGN")) + ) + # Start delay alignment + startup_fsm.act("ALIGN", + txuserrdy.eq(1), + txdlysreset.eq(1), + If(txdlysresetdone, + NextState("PHALIGN") + ) + ) + # Start phase alignment + startup_fsm.act("PHALIGN", + txuserrdy.eq(1), + txphinit.eq(1), + If(txphinitdone, + NextState("WAIT_FIRST_ALIGN_DONE") + ) + ) + # Wait 2 rising edges of Xxphaligndone + # (from UG482 in TX Buffer Bypass in Single-Lane Auto Mode) + startup_fsm.act("WAIT_FIRST_ALIGN_DONE", + txuserrdy.eq(1), + txphalign.eq(1), + If(txphaligndone_rising, + NextState("WAIT_SECOND_ALIGN_DONE") + ) + ) + startup_fsm.act("WAIT_SECOND_ALIGN_DONE", + txuserrdy.eq(1), + txdlyen.eq(1), + If(txphaligndone_rising, + NextState("READY") + ) + ) + startup_fsm.act("READY", + txuserrdy.eq(1), + self.done.eq(1), + If(self.restart, NextState("PLL_RESET")) + ) + + +class GTPRXInit(Module): + def __init__(self, sys_clk_freq): + self.done = Signal() + self.restart = Signal() + + # GTP signals + self.plllock = Signal() + self.gtrxreset = Signal() + self.rxresetdone = Signal() + self.rxdlysreset = Signal() + self.rxdlysresetdone = Signal() + self.rxphalign = Signal() + self.rxdlyen = Signal() + self.rxuserrdy = Signal() + self.rxsyncdone = Signal() + self.rxpmaresetdone = Signal() + + self.drpaddr = Signal(9) + self.drpen = Signal() + self.drpdi = Signal(16) + self.drprdy = Signal() + self.drpdo = Signal(16) + self.drpwe = Signal() + + # # # + + drpvalue = Signal(16) + drpmask = Signal() + self.comb += [ + self.drpaddr.eq(0x011), + If(drpmask, + self.drpdi.eq(drpvalue & 0xf7ff) + ).Else( + self.drpdi.eq(drpvalue) + ) + ] + + rxpmaresetdone = Signal() + self.specials += MultiReg(self.rxpmaresetdone, rxpmaresetdone) + rxpmaresetdone_r = Signal() + self.sync += rxpmaresetdone_r.eq(rxpmaresetdone) + + # Double-latch transceiver asynch outputs + plllock = Signal() + rxresetdone = Signal() + rxdlysresetdone = Signal() + rxsyncdone = Signal() + self.specials += [ + MultiReg(self.plllock, plllock), + MultiReg(self.rxresetdone, rxresetdone), + MultiReg(self.rxdlysresetdone, rxdlysresetdone), + MultiReg(self.rxsyncdone, rxsyncdone) + ] + + # Deglitch FSM outputs driving transceiver asynch inputs + gtrxreset = Signal() + rxdlysreset = Signal() + rxphalign = Signal() + rxdlyen = Signal() + rxuserrdy = Signal() + self.sync += [ + self.gtrxreset.eq(gtrxreset), + self.rxdlysreset.eq(rxdlysreset), + self.rxphalign.eq(rxphalign), + self.rxdlyen.eq(rxdlyen), + self.rxuserrdy.eq(rxuserrdy) + ] + + # After configuration, transceiver resets have to stay low for + # at least 500ns (see AR43482) + pll_reset_cycles = ceil(500e-9*sys_clk_freq) + pll_reset_timer = WaitTimer(pll_reset_cycles) + self.submodules += pll_reset_timer + + startup_fsm = ResetInserter()(FSM(reset_state="GTP_RESET")) + self.submodules += startup_fsm + + ready_timer = WaitTimer(int(4e-3*sys_clk_freq)) + self.submodules += ready_timer + self.comb += [ + ready_timer.wait.eq(~self.done & ~startup_fsm.reset), + startup_fsm.reset.eq(self.restart | ready_timer.done) + ] + + cdr_stable_timer = WaitTimer(1024) + self.submodules += cdr_stable_timer + + startup_fsm.act("GTP_RESET", + gtrxreset.eq(1), + NextState("DRP_READ_ISSUE") + ) + startup_fsm.act("DRP_READ_ISSUE", + gtrxreset.eq(1), + self.drpen.eq(1), + NextState("DRP_READ_WAIT") + ) + startup_fsm.act("DRP_READ_WAIT", + gtrxreset.eq(1), + If(self.drprdy, + NextValue(drpvalue, self.drpdo), + NextState("DRP_MOD_ISSUE") + ) + ) + startup_fsm.act("DRP_MOD_ISSUE", + gtrxreset.eq(1), + drpmask.eq(1), + self.drpen.eq(1), + self.drpwe.eq(1), + NextState("DRP_MOD_WAIT") + ) + startup_fsm.act("DRP_MOD_WAIT", + gtrxreset.eq(1), + If(self.drprdy, + NextState("WAIT_PMARST_FALL") + ) + ) + startup_fsm.act("WAIT_PMARST_FALL", + rxuserrdy.eq(1), + If(rxpmaresetdone_r & ~rxpmaresetdone, + NextState("DRP_RESTORE_ISSUE") + ) + ) + startup_fsm.act("DRP_RESTORE_ISSUE", + rxuserrdy.eq(1), + self.drpen.eq(1), + self.drpwe.eq(1), + NextState("DRP_RESTORE_WAIT") + ) + startup_fsm.act("DRP_RESTORE_WAIT", + rxuserrdy.eq(1), + If(self.drprdy, + NextState("WAIT_GTP_RESET_DONE") + ) + ) + # Release GTP reset and wait for GTP resetdone + # (from UG482, GTP is reset on falling edge + # of gtrxreset) + startup_fsm.act("WAIT_GTP_RESET_DONE", + rxuserrdy.eq(1), + cdr_stable_timer.wait.eq(1), + If(rxresetdone & cdr_stable_timer.done, + NextState("ALIGN") + ) + ) + # Start delay alignment + startup_fsm.act("ALIGN", + rxuserrdy.eq(1), + rxdlysreset.eq(1), + If(rxdlysresetdone, + NextState("WAIT_ALIGN_DONE") + ) + ) + # Wait for delay alignment + startup_fsm.act("WAIT_ALIGN_DONE", + rxuserrdy.eq(1), + If(rxsyncdone, + NextState("READY") + ) + ) + startup_fsm.act("READY", + rxuserrdy.eq(1), + self.done.eq(1), + If(self.restart, NextState("GTP_RESET") + ) + ) From 9eb13aba3c8602fe1d6fa5600b5f32d381e2c7e7 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 19 Jan 2018 17:17:58 +0100 Subject: [PATCH 0227/2457] liboard_artiq/hmc830_7043: allow sysref digital/analog delay configuration (will need to be adjusted for jesd subclass1) --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 56ea4792e..4747f7557 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -170,9 +170,15 @@ mod hmc7043 { info!("HMC7043 found"); } info!("HMC7043 configuration..."); + /* global configuration */ for &(addr, data) in HMC7043_WRITES.iter() { write(addr, data); } + /* sysref digital coarse delay configuration (18 steps, 1/2VCO cycle/step)*/ + write(0x112, 0x0); + /* sysref analog fine delay configuration (24 steps, 25ps/step)*/ + write(0x111, 0x0); + Ok(()) } } From 323c7e66cf8f457ab841454589e98b4099d11cf9 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 19 Jan 2018 17:27:57 +0000 Subject: [PATCH 0228/2457] artiq_devtool: fix help message. --- artiq/frontend/artiq_devtool.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 8afd5a1aa..710b80273 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -30,7 +30,7 @@ def get_argparser(): parser.add_argument("-t", "--target", metavar="TARGET", type=str, default="kc705_dds", - help="Target to build, one of: " + help="target to build, one of: " "kc705_dds kasli sayma_rtm sayma_amc_standalone " "sayma_amc_drtio_master sayma_amc_drtio_satellite") parser.add_argument("-H", "--host", @@ -38,19 +38,19 @@ def get_argparser(): help="SSH host where the development board is located") parser.add_argument('-b', "--board", type=str, default="{board_type}-1", - help="Board to connect to on the development SSH host") + help="board to connect to on the development SSH host") parser.add_argument("-B", "--board-file", type=str, default="/var/lib/artiq/boards/{board}", - help="The board file containing the openocd initialization commands; " + help="the board file containing the openocd initialization commands; " "it is also used as the lock file") parser.add_argument("-s", "--serial", type=str, default="/dev/ttyUSB_{board}", help="TTY device corresponding to the development board") parser.add_argument("-d", "--device", type=str, default="{board}.{host}", - help="Address or domain corresponding to the development board") + help="address or domain corresponding to the development board") parser.add_argument("-w", "--wait", action="store_true", - help="Wait for the board to unlock instead of aborting the actions") + help="wait for the board to unlock instead of aborting the actions") parser.add_argument("actions", metavar="ACTION", type=str, default=[], nargs="+", From bcc39a8c9daba1476262f0f7b7232295f5ca3b9e Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 19 Jan 2018 16:24:59 +0000 Subject: [PATCH 0229/2457] artiq_flash: add --dry-run option. --- artiq/frontend/artiq_flash.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index e5c68b5f7..f1903aded 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -41,6 +41,9 @@ Prerequisites: verbosity_args(parser) + parser.add_argument("-n", "--dry-run", + default=False, action="store_true", + help="Only show the openocd script that would be run") parser.add_argument("-H", "--host", metavar="HOSTNAME", type=str, default=None, help="SSH host where the development board is located") @@ -123,6 +126,9 @@ class Programmer: def start(self): raise NotImplementedError + def script(self): + return "\n".join(self.prog) + def do(self): self._command("exit") @@ -338,11 +344,14 @@ def main(): else: raise ValueError("invalid action", action) - try: - programmer.do() - finally: - if conv: - os.unlink(bin) + if args.dry_run: + print(programmer.script()) + else: + try: + programmer.do() + finally: + if conv: + os.unlink(bin) if __name__ == "__main__": From 1c7cb737cac9bcf0a4adf15a2fe7d06e95b787a9 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 19 Jan 2018 17:44:23 +0000 Subject: [PATCH 0230/2457] artiq_flash: refactor. --- DEVELOPER_NOTES.rst | 2 +- artiq/frontend/artiq_flash.py | 124 ++++++++++++++++------------------ 2 files changed, 58 insertions(+), 68 deletions(-) diff --git a/DEVELOPER_NOTES.rst b/DEVELOPER_NOTES.rst index 687ceaca4..a8a078424 100644 --- a/DEVELOPER_NOTES.rst +++ b/DEVELOPER_NOTES.rst @@ -62,7 +62,7 @@ Selecting a development board with artiq_flash The board lock file also contains the openocd commands for selecting the corresponding developer board: :: - artiq_flash --preinit-command "$(cat /var/lib/artiq/boards/sayma-1)" + artiq_flash -I "$(cat /var/lib/artiq/boards/sayma-1)" Using developer tools diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index f1903aded..5605ddcbc 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -43,7 +43,7 @@ Prerequisites: parser.add_argument("-n", "--dry-run", default=False, action="store_true", - help="Only show the openocd script that would be run") + help="only show the openocd script that would be run") parser.add_argument("-H", "--host", metavar="HOSTNAME", type=str, default=None, help="SSH host where the development board is located") @@ -52,7 +52,7 @@ Prerequisites: "kc705 kasli sayma_amc sayma_rtm") parser.add_argument("-m", "--variant", default=None, help="board variant") - parser.add_argument("--preinit-command", default=[], action="append", + parser.add_argument("-I", "--preinit-command", default=[], action="append", help="add a pre-initialization OpenOCD command. " "Useful for selecting a development board " "when several are connected.") @@ -85,18 +85,14 @@ def proxy_path(): class Programmer: - def __init__(self, client, target_file, preinit_commands): - self.client = client - if target_file: - self.target_file = self._transfer_script(target_file) - else: - self.target_file = None - self.preinit_commands = preinit_commands - self.prog = [] + def __init__(self, client, preinit_script): + self._client = client + self._preinit_script = preinit_script + self._script = [] def _transfer_script(self, script): - if isinstance(self.client, LocalClient): - return script + if isinstance(self._client, LocalClient): + return "[find {}]".format(script) def rewriter(content): def repl(match): @@ -104,20 +100,29 @@ class Programmer: return re.sub(rb"\[find (.+?)\]", repl, content, re.DOTALL) script = os.path.join(scripts_path(), script) - return self.client.transfer_file(script, rewriter) + return self._client.transfer_file(script, rewriter) - def _command(self, cmd): - self.prog.append(cmd.replace("{", "{{").replace("}", "}}")) + def script(self): + return [ + *self._preinit_script, + "init", + *self._script, + "exit" + ] - def init(self): - for command in self.preinit_commands: - self._command(command) - self._command("init") + def run(self): + cmdline = ["openocd"] + if isinstance(self._client, LocalClient): + cmdline += ["-s", scripts_path()] + cmdline += ["-c", "; ".join(script)] - def load(self, bitfile): + cmdline = [arg.replace("{", "{{").replace("}", "}}") for arg in self.script()] + self._client.run_command(cmdline) + + def load(self, bitfile, pld): raise NotImplementedError - def proxy(self, proxy_bitfile): + def proxy(self, proxy_bitfile, pld): raise NotImplementedError def flash_binary(self, flashno, address, filename): @@ -126,54 +131,40 @@ class Programmer: def start(self): raise NotImplementedError - def script(self): - return "\n".join(self.prog) - - def do(self): - self._command("exit") - - cmdline = ["openocd"] - if isinstance(self.client, LocalClient): - cmdline += ["-s", scripts_path()] - if self.target_file is not None: - cmdline += ["-f", self.target_file] - cmdline += ["-c", "; ".join(self.prog)] - - self.client.run_command(cmdline) - class ProgrammerJtagSpi7(Programmer): - def __init__(self, client, target, preinit_commands): - Programmer.__init__(self, client, os.path.join("board", target + ".cfg"), - preinit_commands) - self.init() + def __init__(self, client, target, preinit_script): + Programmer.__init__(self, client, preinit_script) + + target_file = self._transfer_script(os.path.join("board", target + ".cfg")) + self._preinit_script.append("source {}".format(target_file)) def load(self, bitfile, pld=0): - bitfile = self.client.transfer_file(bitfile) - self._command("pld load {} {{{}}}".format(pld, bitfile)) + bitfile = self._client.transfer_file(bitfile) + self._script.append("pld load {} {{{}}}".format(pld, bitfile)) def proxy(self, proxy_bitfile, pld=0): - proxy_bitfile = self.client.transfer_file(proxy_bitfile) - self._command("jtagspi_init {} {{{}}}".format(pld, proxy_bitfile)) + proxy_bitfile = self._client.transfer_file(proxy_bitfile) + self._script.append("jtagspi_init {} {{{}}}".format(pld, proxy_bitfile)) def flash_binary(self, flashno, address, filename): - # jtagspi_program supports only one flash - assert flashno == 0 - filename = self.client.transfer_file(filename) - self._command("jtagspi_program {{{}}} 0x{:x}".format( + assert flashno == 0 # jtagspi_program supports only one flash + + filename = self._client.transfer_file(filename) + self._script.append("jtagspi_program {{{}}} 0x{:x}".format( filename, address)) def start(self): - self._command("xc7_program xc7.tap") + self._script.append("xc7_program xc7.tap") class ProgrammerSayma(Programmer): sector_size = 0x10000 - def __init__(self, client, preinit_commands): - Programmer.__init__(self, client, None, preinit_commands) + def __init__(self, client, preinit_script): + Programmer.__init__(self, client, preinit_script) - self.prog += [ + self._preinit_script += [ "interface ftdi", "ftdi_device_desc \"Quad RS232-HS\"", "ftdi_vid_pid 0x0403 0x6011", @@ -198,30 +189,29 @@ class ProgrammerSayma(Programmer): "flash bank xcu.spi0 jtagspi 0 0 0 0 xcu.proxy $XILINX_USER1", "flash bank xcu.spi1 jtagspi 0 0 0 0 xcu.proxy $XILINX_USER2" ] - self.init() def load(self, bitfile, pld=1): - bitfile = self.client.transfer_file(bitfile) - self._command("pld load {} {{{}}}".format(pld, bitfile)) + bitfile = self._client.transfer_file(bitfile) + self._script.append("pld load {} {{{}}}".format(pld, bitfile)) def proxy(self, proxy_bitfile, pld=1): self.load(proxy_bitfile, pld) - self._command("reset halt") + self._script.append("reset halt") def flash_binary(self, flashno, address, filename): sector_first = address // self.sector_size size = os.path.getsize(filename) - assert size sector_last = sector_first + (size - 1) // self.sector_size - assert sector_last >= sector_first - filename = self.client.transfer_file(filename) - self._command("flash probe xcu.spi{}".format(flashno)) - self._command("flash erase_sector {} {} {}".format(flashno, sector_first, sector_last)) - self._command("flash write_bank {} {{{}}} 0x{:x}".format(flashno, filename, address)) - self._command("flash verify_bank {} {{{}}} 0x{:x}".format(flashno, filename, address)) + filename = self._client.transfer_file(filename) + self._script += [ + "flash probe xcu.spi{}".format(flashno), + "flash erase_sector {} {} {}".format(flashno, sector_first, sector_last), + "flash write_bank {} {{{}}} 0x{:x}".format(flashno, filename, address), + "flash verify_bank {} {{{}}} 0x{:x}".format(flashno, filename, address), + ] def start(self): - self._command("xcu_program xcu.tap") + self._script.append("xcu_program xcu.tap") def main(): @@ -285,7 +275,7 @@ def main(): else: client = SSHClient(args.host) - programmer = config["programmer_factory"](client, preinit_commands=args.preinit_command) + programmer = config["programmer_factory"](client, preinit_script=args.preinit_command) conv = False for action in args.action: @@ -345,10 +335,10 @@ def main(): raise ValueError("invalid action", action) if args.dry_run: - print(programmer.script()) + print("\n".join(programmer.script())) else: try: - programmer.do() + programmer.run() finally: if conv: os.unlink(bin) From ebd02c4f43eac84ba1b14c6be991419f7f508d70 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 19 Jan 2018 18:53:49 +0000 Subject: [PATCH 0231/2457] artiq_flash: fix typo. --- artiq/frontend/artiq_flash.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 5605ddcbc..f2d73610e 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -114,9 +114,9 @@ class Programmer: cmdline = ["openocd"] if isinstance(self._client, LocalClient): cmdline += ["-s", scripts_path()] - cmdline += ["-c", "; ".join(script)] + cmdline += ["-c", "; ".join(self.script())] - cmdline = [arg.replace("{", "{{").replace("}", "}}") for arg in self.script()] + cmdline = [arg.replace("{", "{{").replace("}", "}}") for arg in cmdline] self._client.run_command(cmdline) def load(self, bitfile, pld): From 934bc53cb5a6b06b9453e840dedfc815aca24226 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 19 Jan 2018 20:34:31 +0000 Subject: [PATCH 0232/2457] artiq_devtool: refactor. --- artiq/frontend/artiq_devtool.py | 49 +++++++++++++++++---------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 710b80273..6fbf6dceb 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -33,6 +33,9 @@ def get_argparser(): help="target to build, one of: " "kc705_dds kasli sayma_rtm sayma_amc_standalone " "sayma_amc_drtio_master sayma_amc_drtio_satellite") + parser.add_argument("-g", "--build-gateware", + default=False, action="store_true", + help="build gateware, not just software") parser.add_argument("-H", "--host", type=str, default="lab.m-labs.hk", help="SSH host where the development board is located") @@ -69,12 +72,12 @@ def main(): def build_dir(*path, target=args.target): return os.path.join("/tmp", target, *path) - build_args = [] + extra_build_args = [] if args.target == "kc705_dds": board_type, firmware = "kc705", "runtime" elif args.target == "sayma_amc_standalone": board_type, firmware = "sayma_amc", "runtime" - build_args += ["--rtm-csr-csv", build_dir("sayma_rtm_csr.csv", target="sayma_rtm")] + extra_build_args += ["--rtm-csr-csv", build_dir("sayma_rtm_csr.csv", target="sayma_rtm")] elif args.target == "sayma_amc_drtio_master": board_type, firmware = "sayma_amc", "runtime" elif args.target == "sayma_amc_drtio_satellite": @@ -127,7 +130,16 @@ def main(): logger.error("Failed to get lock") sys.exit(1) + def command(*args, on_failure="Command failed"): + try: + subprocess.check_call(args) + except subprocess.CalledProcessError: + logger.error(on_failure) + sys.exit(1) + def flash(*steps): + lock() + flash_args = ["artiq_flash"] for _ in range(args.verbose): flash_args.append("-v") @@ -135,40 +147,32 @@ def main(): flash_args += ["--srcbuild", build_dir()] flash_args += ["--preinit-command", "source {}".format(board_file)] flash_args += steps - subprocess.check_call(flash_args) + command(*flash_args, on_failure="Flashing failed") for action in args.actions: if action == "build": logger.info("Building target") - try: - subprocess.check_call([ - "python3", "-m", "artiq.gateware.targets." + args.target, - "--no-compile-gateware", - *build_args, - "--output-dir", build_dir()]) - except subprocess.CalledProcessError: - logger.error("Build failed") - sys.exit(1) + + build_args = ["python3", "-m", "artiq.gateware.targets." + args.target] + if not args.build_gateware: + build_args.append("--no-compile-gateware") + build_args += ["--output-dir", build_dir()] + build_args += extra_build_args + command(*build_args, on_failure="Build failed") elif action == "clean": logger.info("Cleaning build directory") shutil.rmtree(build_dir, ignore_errors=True) elif action == "reset": - lock() - logger.info("Resetting device") flash("start") elif action == "flash": - lock() - logger.info("Flashing and booting firmware") flash("proxy", "bootloader", "firmware", "start") elif action == "flash+log": - lock() - logger.info("Flashing firmware") flash("proxy", "bootloader", "firmware") @@ -234,12 +238,9 @@ def main(): elif action == "hotswap": logger.info("Hotswapping firmware") - try: - subprocess.check_call(["artiq_coreboot", "hotswap", - build_dir("software", firmware, firmware + ".bin")]) - except subprocess.CalledProcessError: - logger.error("Build failed") - sys.exit(1) + firmware = build_dir("software", firmware, firmware + ".bin") + command("artiq_coreboot", "hotswap", firmware, + on_failure="Hotswapping failed") else: logger.error("Unknown action {}".format(action)) From 37fa3b29da81f74885cad04f90a3055beaf47fdd Mon Sep 17 00:00:00 2001 From: hartytp Date: Sat, 20 Jan 2018 00:19:31 +0000 Subject: [PATCH 0233/2457] firmware: add register dump on HMC830 lock timeout. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 4747f7557..a567d27ec 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -107,6 +107,13 @@ mod hmc830 { info!("waiting for lock..."); while read(0x12) & 0x02 == 0 { if clock::get_ms() > t + 2000 { + error!("lock timeout"); + info!("register dump:"); + for addr in 0x00..0x14 { + // These registers don't exist (in the data sheet at least) + if addr == 0x0d || addr == 0x0e { continue; } + info!("[0x{:02x}] = 0x{:04x}", addr, read(addr)); + } return Err("HMC830 lock timeout"); } } From 83278a6edb799d8e0e03c5f323834ced1b51e6a1 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 20 Jan 2018 01:19:09 +0000 Subject: [PATCH 0234/2457] artiq_flash: fix a refactoring bug. --- artiq/frontend/artiq_flash.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index f2d73610e..67b72d5b7 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -162,7 +162,7 @@ class ProgrammerSayma(Programmer): sector_size = 0x10000 def __init__(self, client, preinit_script): - Programmer.__init__(self, client, preinit_script) + Programmer.__init__(self, client, []) self._preinit_script += [ "interface ftdi", @@ -177,6 +177,8 @@ class ProgrammerSayma(Programmer): "adapter_khz 5000", "transport select jtag", + *preinit_script, + # tap 0, pld 0 "source {}".format(self._transfer_script("cpld/xilinx-xc7.cfg")), # tap 1, pld 1 From f4022ba872346278c9327c064b67c5308062767d Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 20 Jan 2018 01:28:07 +0000 Subject: [PATCH 0235/2457] remoting: avoid a race condition. --- artiq/remoting.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/artiq/remoting.py b/artiq/remoting.py index 0c6a99899..aa3c27f3f 100644 --- a/artiq/remoting.py +++ b/artiq/remoting.py @@ -83,8 +83,16 @@ class SSHClient(Client): logger.debug("Using cached {}".format(filename)) else: logger.debug("Transferring {}".format(filename)) - with sftp.open(remote_filename, 'wb') as remote: + # Avoid a race condition by writing into a temporary file + # and atomically replacing + with sftp.open(remote_filename + ".~", "wb") as remote: remote.write(rewritten) + try: + sftp.rename(remote_filename + ".~", remote_filename) + except IOError: + # Either it already exists (this is OK) or something else + # happened (this isn't) and we need to re-raise + sftp.stat(remote_filename) return remote_filename def spawn_command(self, cmd, get_pty=False, **kws): From 74ce7319d3006ece39c9ebb1b08c51ca2e63bc51 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 20 Jan 2018 05:48:13 +0100 Subject: [PATCH 0236/2457] sayma: reduce serwb linerate to 625Mbps (make it work on saymas with 1.8v issue, related?) --- artiq/gateware/targets/sayma_amc_standalone.py | 2 +- artiq/gateware/targets/sayma_rtm.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc_standalone.py b/artiq/gateware/targets/sayma_amc_standalone.py index 73124afe7..5ef866d0a 100755 --- a/artiq/gateware/targets/sayma_amc_standalone.py +++ b/artiq/gateware/targets/sayma_amc_standalone.py @@ -160,7 +160,7 @@ class Standalone(MiniSoC, AMPSoC): self.csr_devices.append("rtm_fpga_cfg") # AMC/RTM serwb - serwb_pll = serwb.phy.SERWBPLL(125e6, 1.25e9, vco_div=2) + serwb_pll = serwb.phy.SERWBPLL(125e6, 625e6, vco_div=2) self.comb += serwb_pll.refclk.eq(self.crg.cd_sys.clk) self.submodules += serwb_pll diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index c438d469d..5861be3e8 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -140,7 +140,7 @@ class SaymaRTM(Module): self.comb += platform.request("hmc7043_reset").eq(0) # AMC/RTM serwb - serwb_pll = serwb.phy.SERWBPLL(125e6, 1.25e9, vco_div=1) + serwb_pll = serwb.phy.SERWBPLL(62.5e6, 625e6, vco_div=1) self.submodules += serwb_pll serwb_pads = platform.request("amc_rtm_serwb") From 8fe463d4a0b73f3badfcc2b7264788fd7088336b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 20 Jan 2018 06:02:05 +0100 Subject: [PATCH 0237/2457] sayma_rtm: add UART loopback to easily know if rtm fpga is alive --- artiq/gateware/targets/sayma_rtm.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 5861be3e8..338019044 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -93,6 +93,10 @@ class SaymaRTM(Module): platform.request("dac_clk_src_sel"))) csr_devices.append("clock_mux") + # UART loopback + serial = platform.request(serial) + self.comb += serial.tx.eq(serial.rx) + # Allaki: enable RF output, GPIO access to attenuator self.comb += [ platform.request("allaki0_rfsw0").eq(1), From ab9eb56ceb638732b4b746daeb97ea100e27a11e Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 20 Jan 2018 04:50:26 +0000 Subject: [PATCH 0238/2457] setup.py: migen now works on Python 3.6, relax version check. --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index ae3c59cdc..2cb40bb5c 100755 --- a/setup.py +++ b/setup.py @@ -6,8 +6,8 @@ import sys import versioneer -if not (3, 5, 3) <= sys.version_info[:3] < (3, 6, 0): - raise Exception("You need Python 3.5.3+ (but not 3.6+)") +if sys.version_info[:3] < (3, 5, 3): + raise Exception("You need Python 3.5.3+") # Depends on PyQt5, but setuptools cannot check for it. From 1ffabac06f0e84d3253b0d9cc360d47c28216c03 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 20 Jan 2018 06:21:32 +0000 Subject: [PATCH 0239/2457] artiq_flash: use atexit for tempfile cleanup. --- artiq/frontend/artiq_flash.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 67b72d5b7..08c2d8110 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -6,6 +6,7 @@ import subprocess import tempfile import shutil import re +import atexit from functools import partial from artiq import __artiq_dir__ as artiq_dir @@ -279,7 +280,6 @@ def main(): programmer = config["programmer_factory"](client, preinit_script=args.preinit_command) - conv = False for action in args.action: if action == "proxy": proxy_found = False @@ -298,14 +298,14 @@ def main(): path = bin_dir else: path = os.path.join(args.srcbuild, "gateware") - bin = os.path.join(path, "top.bin") - if not os.access(bin, os.R_OK): - bin_handle, bin = tempfile.mkstemp() - bit = os.path.join(path, "top.bit") - with open(bit, "rb") as f, open(bin_handle, "wb") as g: - bit2bin(f, g) - conv = True - programmer.flash_binary(*config["gateware"], bin) + bin_filename = os.path.join(path, "top.bin") + if not os.access(bin_filename, os.R_OK): + bin_handle, bin_filename = tempfile.mkstemp() + bit_filename = os.path.join(path, "top.bit") + with open(bit_filename, "rb") as bit_handle: + bit2bin(bit_handle, bin_handle) + atexit.register(lambda: os.unlink(bin_filename)) + programmer.flash_binary(*config["gateware"], bin_filename) elif action == "bootloader": if args.srcbuild is None: path = bin_dir @@ -339,11 +339,7 @@ def main(): if args.dry_run: print("\n".join(programmer.script())) else: - try: - programmer.run() - finally: - if conv: - os.unlink(bin) + programmer.run() if __name__ == "__main__": From 94592c7a4c40a6d75a717867777ccdfd17bdfae3 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 20 Jan 2018 06:40:35 +0000 Subject: [PATCH 0240/2457] artiq_flash: unify flash handling in XC7 and Sayma programmers. --- artiq/frontend/artiq_flash.py | 201 ++++++++++++++++------------------ 1 file changed, 97 insertions(+), 104 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 08c2d8110..6ba52270c 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -85,9 +85,24 @@ def proxy_path(): return p +def find_proxy_bitfile(filename): + for p in [proxy_path(), os.path.expanduser("~/.migen"), + "/usr/local/share/migen", "/usr/share/migen"]: + full_path = os.path.join(p, filename) + if os.access(full_path, os.R_OK): + return full_path + raise FileNotFoundError("proxy bitstream {} not found" + .format(filename)) + + +def add_commands(script, *commands, **substs): + script += [command.format(**substs) for command in commands] + + class Programmer: def __init__(self, client, preinit_script): self._client = client + self._board_script = [] self._preinit_script = preinit_script self._script = [] @@ -103,8 +118,39 @@ class Programmer: script = os.path.join(scripts_path(), script) return self._client.transfer_file(script, rewriter) + def add_flash_bank(self, name, tap, index): + add_commands(self._board_script, + "target create {tap}.{name}.proxy testee -chain-position {tap}.tap", + "flash bank {name} jtagspi 0 0 0 0 {tap}.{name}.proxy {ir:#x}", + tap=tap, name=name, ir=0x02 + index) + + def load(self, bitfile, pld): + bitfile = self._client.transfer_file(bitfile) + add_commands(self._script, + "pld load {pld} {filename}", + pld=pld, filename=bitfile) + + def load_proxy(self): + raise NotImplementedError + + def flash_binary(self, bankname, address, filename): + size = os.path.getsize(filename) + filename = self._client.transfer_file(filename) + add_commands(self._script, + "flash probe {bankname}", + "flash erase_sector {bankname} {firstsector} {lastsector}", + "flash write_bank {bankname} {filename} {address:#x}", + "flash verify_bank {bankname} {filename} {address:#x}", + bankname=bankname, address=address, filename=filename, + firstsector=address // self._sector_size, + lastsector=(address + size - 1) // self._sector_size) + + def start(self): + raise NotImplementedError + def script(self): return [ + *self._board_script, *self._preinit_script, "init", *self._script, @@ -120,52 +166,34 @@ class Programmer: cmdline = [arg.replace("{", "{{").replace("}", "}}") for arg in cmdline] self._client.run_command(cmdline) - def load(self, bitfile, pld): - raise NotImplementedError - def proxy(self, proxy_bitfile, pld): - raise NotImplementedError +class ProgrammerXC7(Programmer): + _sector_size = 0x10000 - def flash_binary(self, flashno, address, filename): - raise NotImplementedError - - def start(self): - raise NotImplementedError - - -class ProgrammerJtagSpi7(Programmer): - def __init__(self, client, target, preinit_script): + def __init__(self, client, preinit_script, board, proxy): Programmer.__init__(self, client, preinit_script) + self._proxy = proxy - target_file = self._transfer_script(os.path.join("board", target + ".cfg")) - self._preinit_script.append("source {}".format(target_file)) + add_commands(self._board_script, + "source {boardfile}", + boardfile=self._transfer_script("board/{}.cfg".format(board))) + self.add_flash_bank("spi0", "xc7", index=0) - def load(self, bitfile, pld=0): - bitfile = self._client.transfer_file(bitfile) - self._script.append("pld load {} {{{}}}".format(pld, bitfile)) - - def proxy(self, proxy_bitfile, pld=0): - proxy_bitfile = self._client.transfer_file(proxy_bitfile) - self._script.append("jtagspi_init {} {{{}}}".format(pld, proxy_bitfile)) - - def flash_binary(self, flashno, address, filename): - assert flashno == 0 # jtagspi_program supports only one flash - - filename = self._client.transfer_file(filename) - self._script.append("jtagspi_program {{{}}} 0x{:x}".format( - filename, address)) + def load_proxy(self): + self.load(find_proxy_bitfile(self._proxy), pld=0) def start(self): - self._script.append("xc7_program xc7.tap") + add_commands(self._script, + "xc7_program xc7.tap") class ProgrammerSayma(Programmer): - sector_size = 0x10000 + _sector_size = 0x10000 def __init__(self, client, preinit_script): - Programmer.__init__(self, client, []) + Programmer.__init__(self, client, preinit_script) - self._preinit_script += [ + add_commands(self._board_script, "interface ftdi", "ftdi_device_desc \"Quad RS232-HS\"", "ftdi_vid_pid 0x0403 0x6011", @@ -174,47 +202,22 @@ class ProgrammerSayma(Programmer): # nTRST on ADBUS4: out, high, but R46 is DNP "ftdi_layout_init 0x0098 0x008b", "reset_config none", - "adapter_khz 5000", "transport select jtag", - - *preinit_script, - # tap 0, pld 0 "source {}".format(self._transfer_script("cpld/xilinx-xc7.cfg")), # tap 1, pld 1 "set CHIP XCKU040", - "source {}".format(self._transfer_script("cpld/xilinx-xcu.cfg")), + "source {}".format(self._transfer_script("cpld/xilinx-xcu.cfg"))) + self.add_flash_bank("spi0", "xcu", index=0) + self.add_flash_bank("spi1", "xcu", index=1) - "target create xcu.proxy testee -chain-position xcu.tap", - "set XILINX_USER1 0x02", - "set XILINX_USER2 0x03", - "flash bank xcu.spi0 jtagspi 0 0 0 0 xcu.proxy $XILINX_USER1", - "flash bank xcu.spi1 jtagspi 0 0 0 0 xcu.proxy $XILINX_USER2" - ] - - def load(self, bitfile, pld=1): - bitfile = self._client.transfer_file(bitfile) - self._script.append("pld load {} {{{}}}".format(pld, bitfile)) - - def proxy(self, proxy_bitfile, pld=1): - self.load(proxy_bitfile, pld) - self._script.append("reset halt") - - def flash_binary(self, flashno, address, filename): - sector_first = address // self.sector_size - size = os.path.getsize(filename) - sector_last = sector_first + (size - 1) // self.sector_size - filename = self._client.transfer_file(filename) - self._script += [ - "flash probe xcu.spi{}".format(flashno), - "flash erase_sector {} {} {}".format(flashno, sector_first, sector_last), - "flash write_bank {} {{{}}} 0x{:x}".format(flashno, filename, address), - "flash verify_bank {} {{{}}} 0x{:x}".format(flashno, filename, address), - ] + def load_proxy(self): + self.load(find_proxy_bitfile("bscan_spi_xcku040-sayma.bit"), pld=1) def start(self): - self._script.append("xcu_program xcu.tap") + add_commands(self._script, + "xcu_program xcu.tap") def main(): @@ -223,36 +226,32 @@ def main(): config = { "kc705": { - "programmer_factory": partial(ProgrammerJtagSpi7, target="kc705"), - "proxy_bitfile": "bscan_spi_xc7k325t.bit", - "variants": ["nist_clock", "nist_qc2"], - "gateware": (0, 0x000000), - "bootloader": (0, 0xaf0000), - "storage": (0, 0xb30000), - "firmware": (0, 0xb40000), + "programmer": partial(ProgrammerXC7, board="kc705", proxy="bscan_spi_xc7k325t.bit"), + "variants": ["nist_clock", "nist_qc2"], + "gateware": ("spi0", 0x000000), + "bootloader": ("spi0", 0xaf0000), + "storage": ("spi0", 0xb30000), + "firmware": ("spi0", 0xb40000), }, "kasli": { - "programmer_factory": partial(ProgrammerJtagSpi7, target="kasli"), - "proxy_bitfile": "bscan_spi_xc7a100t.bit", - "variants": ["opticlock"], - "gateware": (0, 0x000000), - "bootloader": (0, 0x400000), - "storage": (0, 0x440000), - "firmware": (0, 0x450000), + "programmer": partial(ProgrammerXC7, board="kasli", proxy="bscan_spi_xc7a100t.bit"), + "variants": ["opticlock"], + "gateware": ("spi0", 0x000000), + "bootloader": ("spi0", 0x400000), + "storage": ("spi0", 0x440000), + "firmware": ("spi0", 0x450000), }, "sayma_amc": { - "programmer_factory": ProgrammerSayma, - "proxy_bitfile": "bscan_spi_xcku040-sayma.bit", - "variants": ["standalone", "master", "satellite"], - "gateware": (0, 0x000000), - "bootloader": (1, 0x000000), - "storage": (1, 0x040000), - "firmware": (1, 0x050000), + "programmer": ProgrammerSayma, + "variants": ["standalone", "master", "satellite"], + "gateware": ("spi0", 0x000000), + "bootloader": ("spi1", 0x000000), + "storage": ("spi1", 0x040000), + "firmware": ("spi1", 0x050000), }, "sayma_rtm": { - "programmer_factory": ProgrammerSayma, - "proxy_bitfile": "bscan_spi_xcku040-sayma.bit", - "gateware": (1, 0x150000), + "programmer": ProgrammerSayma, + "gateware": ("spi1", 0x150000), }, }[args.target] @@ -262,13 +261,14 @@ def main(): raise SystemExit("Invalid variant for this board") if variant is None: variant = config["variants"][0] + bin_dir = args.dir if bin_dir is None: + bin_name = args.target if variant: - bin_name = "{}-{}".format(args.target, variant) - else: - bin_name = args.target + bin_name += "-" + variant bin_dir = os.path.join(artiq_dir, "binaries", bin_name) + if args.srcbuild is None and not os.path.exists(bin_dir) and args.action != ["start"]: raise SystemExit("Binaries directory '{}' does not exist" .format(bin_dir)) @@ -278,21 +278,14 @@ def main(): else: client = SSHClient(args.host) - programmer = config["programmer_factory"](client, preinit_script=args.preinit_command) + programmer = config["programmer"](client, preinit_script=args.preinit_command) for action in args.action: if action == "proxy": - proxy_found = False - for p in [bin_dir, proxy_path(), os.path.expanduser("~/.migen"), - "/usr/local/share/migen", "/usr/share/migen"]: - proxy_bitfile = os.path.join(p, config["proxy_bitfile"]) - if os.access(proxy_bitfile, os.R_OK): - programmer.proxy(proxy_bitfile) - proxy_found = True - break - if not proxy_found: - raise SystemExit( - "proxy gateware bitstream {} not found".format(config["proxy_bitfile"])) + try: + programmer.load_proxy() + except FileNotFoundError as e: + raise SystemExit(e) elif action == "gateware": if args.srcbuild is None: path = bin_dir From 115aa0d0d6629906e23e47b178fad81696c82c9c Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 20 Jan 2018 07:22:27 +0000 Subject: [PATCH 0241/2457] artiq_flash: support load action for Sayma RTM FPGA. --- artiq/frontend/artiq_flash.py | 63 ++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 6ba52270c..7019a7a0e 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -91,7 +91,7 @@ def find_proxy_bitfile(filename): full_path = os.path.join(p, filename) if os.access(full_path, os.R_OK): return full_path - raise FileNotFoundError("proxy bitstream {} not found" + raise FileNotFoundError("Cannot find proxy bitstream {}" .format(filename)) @@ -280,6 +280,13 @@ def main(): programmer = config["programmer"](client, preinit_script=args.preinit_command) + def artifact_path(*path_filename): + if args.srcbuild is None: + *path, filename = path_filename + return os.path.join(bin_dir, filename) + else: + return os.path.join(args.srcbuild, *path_filename) + for action in args.action: if action == "proxy": try: @@ -287,43 +294,39 @@ def main(): except FileNotFoundError as e: raise SystemExit(e) elif action == "gateware": - if args.srcbuild is None: - path = bin_dir - else: - path = os.path.join(args.srcbuild, "gateware") - bin_filename = os.path.join(path, "top.bin") - if not os.access(bin_filename, os.R_OK): - bin_handle, bin_filename = tempfile.mkstemp() - bit_filename = os.path.join(path, "top.bit") - with open(bit_filename, "rb") as bit_handle: + gateware_bin = artifact_path("gateware", "top.bin") + if not os.access(gateware_bin, os.R_OK): + bin_handle, gateware_bin = tempfile.mkstemp() + gateware_bit = artifact_path("gateware", "top.bit") + with open(gateware_bit, "rb") as bit_handle: bit2bin(bit_handle, bin_handle) - atexit.register(lambda: os.unlink(bin_filename)) - programmer.flash_binary(*config["gateware"], bin_filename) + atexit.register(lambda: os.unlink(gateware_bin)) + + programmer.flash_binary(*config["gateware"], gateware_bin) elif action == "bootloader": - if args.srcbuild is None: - path = bin_dir - else: - path = os.path.join(args.srcbuild, "software", "bootloader") - programmer.flash_binary(*config["bootloader"], os.path.join(path, "bootloader.bin")) + bootloader_bin = artifact_path("software", "bootloader", "bootloader.bin") + programmer.flash_binary(*config["bootloader"], bootloader_bin) elif action == "storage": - programmer.flash_binary(*config["storage"], args.storage) + storage_img = args.storage + programmer.flash_binary(*config["storage"], storage_img) elif action == "firmware": if variant == "satellite": - firmware_name = "satman" + firmware = "satman" else: - firmware_name = "runtime" - if args.srcbuild is None: - path = bin_dir - else: - path = os.path.join(args.srcbuild, "software", firmware_name) - programmer.flash_binary(*config["firmware"], - os.path.join(path, firmware_name + ".fbi")) + firmware = "runtime" + + firmware_fbi = artifact_path("software", firmware, firmware + ".fbi") + programmer.flash_binary(*config["firmware"], firmware_fbi) elif action == "load": - if args.srcbuild is None: - path = bin_dir + if args.target == "sayma_rtm": + gateware_bit = artifact_path("top.bit") + programmer.load(gateware_bit, 0) + elif args.target == "sayma_amc": + gateware_bit = artifact_path("gateware", "top.bit") + programmer.load(gateware_bit, 1) else: - path = os.path.join(args.srcbuild, "gateware") - programmer.load(os.path.join(path, "top.bit")) + gateware_bit = artifact_path("gateware", "top.bit") + programmer.load(gateware_bit, 0) elif action == "start": programmer.start() else: From c3323f0d5771f01ef27e93e9882f7740d957070c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 20 Jan 2018 15:42:53 +0800 Subject: [PATCH 0242/2457] hmc830: improve lock failure error report --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index a567d27ec..ee456beb9 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -107,12 +107,11 @@ mod hmc830 { info!("waiting for lock..."); while read(0x12) & 0x02 == 0 { if clock::get_ms() > t + 2000 { - error!("lock timeout"); - info!("register dump:"); + error!("HMC830 lock timeout. Register dump:"); for addr in 0x00..0x14 { // These registers don't exist (in the data sheet at least) if addr == 0x0d || addr == 0x0e { continue; } - info!("[0x{:02x}] = 0x{:04x}", addr, read(addr)); + error!("[0x{:02x}] = 0x{:04x}", addr, read(addr)); } return Err("HMC830 lock timeout"); } From 8598e475e92ab72347d1fa20e1296745d245e217 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 20 Jan 2018 08:00:13 +0000 Subject: [PATCH 0243/2457] artiq_flash: fix a refactoring mistake. --- artiq/frontend/artiq_flash.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 7019a7a0e..3520357e6 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -298,8 +298,8 @@ def main(): if not os.access(gateware_bin, os.R_OK): bin_handle, gateware_bin = tempfile.mkstemp() gateware_bit = artifact_path("gateware", "top.bit") - with open(gateware_bit, "rb") as bit_handle: - bit2bin(bit_handle, bin_handle) + with open(gateware_bit, "rb") as bit_file, open(bin_handle, "wb") as bin_file: + bit2bin(bit_file, bin_file) atexit.register(lambda: os.unlink(gateware_bin)) programmer.flash_binary(*config["gateware"], gateware_bin) From 5198c224a2fb9e86096100e4173093253724d783 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 22 Jan 2018 11:51:07 +0800 Subject: [PATCH 0244/2457] sayma,kasli: use new pin names --- .../drtio/transceiver/gth_ultrascale.py | 16 ++++++++-------- .../gateware/drtio/transceiver/gtp_7series.py | 16 ++++++++-------- artiq/gateware/targets/kasli.py | 18 +++++++++--------- .../gateware/targets/sayma_amc_drtio_master.py | 3 +-- .../targets/sayma_amc_drtio_satellite.py | 3 +-- 5 files changed, 27 insertions(+), 29 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index 5d5cf2575..a6a098b19 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -14,7 +14,7 @@ from artiq.gateware.drtio.transceiver.gth_ultrascale_init import * class GTHSingle(Module): - def __init__(self, refclk, tx_pads, rx_pads, sys_clk_freq, rtio_clk_freq, dw, mode): + def __init__(self, refclk, pads, sys_clk_freq, rtio_clk_freq, dw, mode): assert (dw == 20) or (dw == 40) assert mode in ["master", "slave"] @@ -167,10 +167,10 @@ class GTHSingle(Module): i_RXELECIDLEMODE=0b11, # Pads - i_GTHRXP=rx_pads.p, - i_GTHRXN=rx_pads.n, - o_GTHTXP=tx_pads.p, - o_GTHTXN=tx_pads.n + i_GTHRXP=pads.rxp, + i_GTHRXN=pads.rxn, + o_GTHTXP=pads.txp, + o_GTHTXN=pads.txn ) self.submodules += [ @@ -222,8 +222,8 @@ class GTHSingle(Module): class GTH(Module, TransceiverInterface): - def __init__(self, clock_pads, tx_pads, rx_pads, sys_clk_freq, rtio_clk_freq, dw=20, master=0): - self.nchannels = nchannels = len(tx_pads) + def __init__(self, clock_pads, data_pads, sys_clk_freq, rtio_clk_freq, dw=20, master=0): + self.nchannels = nchannels = len(data_pads) self.gths = [] # # # @@ -239,7 +239,7 @@ class GTH(Module, TransceiverInterface): channel_interfaces = [] for i in range(nchannels): mode = "master" if i == master else "slave" - gth = GTHSingle(refclk, tx_pads[i], rx_pads[i], sys_clk_freq, rtio_clk_freq, dw, mode) + gth = GTHSingle(refclk, data_pads[i], sys_clk_freq, rtio_clk_freq, dw, mode) if mode == "master": self.comb += rtio_tx_clk.eq(gth.cd_rtio_tx.clk) else: diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py index 4c6fed24b..92db40162 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -12,7 +12,7 @@ from artiq.gateware.drtio.transceiver.gtp_7series_init import * class GTPSingle(Module): - def __init__(self, qpll_channel, tx_pads, rx_pads, sys_clk_freq, rtio_clk_freq, mode): + def __init__(self, qpll_channel, pads, sys_clk_freq, rtio_clk_freq, mode): if mode != "master": raise NotImplementedError self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( @@ -163,10 +163,10 @@ class GTPSingle(Module): o_RXDATA=Cat(rxdata[:8], rxdata[10:18]), # Pads - i_GTPRXP=rx_pads.p, - i_GTPRXN=rx_pads.n, - o_GTPTXP=tx_pads.p, - o_GTPTXN=tx_pads.n + i_GTPRXP=pads.rxp, + i_GTPRXN=pads.rxn, + o_GTPTXP=pads.txp, + o_GTPTXN=pads.txn ) # tx clocking @@ -215,8 +215,8 @@ class GTPSingle(Module): class GTP(Module, TransceiverInterface): - def __init__(self, qpll_channel, tx_pads, rx_pads, sys_clk_freq, rtio_clk_freq, master=0): - self.nchannels = nchannels = len(tx_pads) + def __init__(self, qpll_channel, data_pads, sys_clk_freq, rtio_clk_freq, master=0): + self.nchannels = nchannels = len(data_pads) self.gtps = [] if nchannels >= 1: raise NotImplementedError @@ -227,7 +227,7 @@ class GTP(Module, TransceiverInterface): channel_interfaces = [] for i in range(nchannels): mode = "master" if i == master else "slave" - gtp = GTPSingle(qpll_channel, tx_pads[i], rx_pads[i], sys_clk_freq, rtio_clk_freq, mode) + gtp = GTPSingle(qpll_channel, data_pads[i], sys_clk_freq, rtio_clk_freq, mode) if mode == "master": self.comb += rtio_tx_clk.eq(gtp.cd_rtio_tx.clk) else: diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 49f5ad13f..5495bb582 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -30,14 +30,14 @@ class _RTIOCRG(Module, AutoCSR): self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) rtio_external_clk = Signal() - clk_fpgaio_se = Signal() - clk_fpgaio = platform.request("clk_fpgaio") # from Si5324 - platform.add_period_constraint(clk_fpgaio.p, 8.0) + clk_synth_se = Signal() + clk_synth = platform.request("si5324_clkout_fabric") + platform.add_period_constraint(clk_synth.p, 8.0) self.specials += [ - Instance("IBUFGDS", - p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE", - i_I=clk_fpgaio.p, i_IB=clk_fpgaio.n, o_O=clk_fpgaio_se), - Instance("BUFG", i_I=clk_fpgaio_se, o_O=rtio_external_clk), + Instance("IBUFGDS", + p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE", + i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se), + Instance("BUFG", i_I=clk_synth_se, o_O=rtio_external_clk), ] pll_locked = Signal() @@ -169,8 +169,8 @@ class Opticlock(_KasliBase): rtio_channels.append(rtio.Channel.from_phy(phy)) for i in (1, 2): - sfp = platform.request("sfp", i) - phy = ttl_simple.Output(sfp.led) + sfp_ctl = platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) diff --git a/artiq/gateware/targets/sayma_amc_drtio_master.py b/artiq/gateware/targets/sayma_amc_drtio_master.py index 28a70303e..9bbb8db31 100755 --- a/artiq/gateware/targets/sayma_amc_drtio_master.py +++ b/artiq/gateware/targets/sayma_amc_drtio_master.py @@ -61,8 +61,7 @@ class Master(MiniSoC, AMPSoC): self.comb += platform.request("sfp_tx_disable_n", 0).eq(1) self.submodules.transceiver = gth_ultrascale.GTH( clock_pads=platform.request("si5324_clkout"), - tx_pads=[platform.request("sfp_tx", 0)], - rx_pads=[platform.request("sfp_rx", 0)], + data_pads=[platform.request("sfp", 0)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) diff --git a/artiq/gateware/targets/sayma_amc_drtio_satellite.py b/artiq/gateware/targets/sayma_amc_drtio_satellite.py index 6b83ceb8a..20526e54b 100755 --- a/artiq/gateware/targets/sayma_amc_drtio_satellite.py +++ b/artiq/gateware/targets/sayma_amc_drtio_satellite.py @@ -63,8 +63,7 @@ class Satellite(BaseSoC): self.comb += platform.request("sfp_tx_disable_n", 0).eq(1) self.submodules.transceiver = gth_ultrascale.GTH( clock_pads=platform.request("si5324_clkout"), - tx_pads=[platform.request("sfp_tx", 0)], - rx_pads=[platform.request("sfp_rx", 0)], + data_pads=[platform.request("sfp", 0)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) From 25f3feeda8ac2e8b77df25f738f1ba9d1e2b3fb1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 22 Jan 2018 18:25:10 +0800 Subject: [PATCH 0245/2457] refactor targets --- RELEASE_NOTES.rst | 2 + artiq/build_soc.py | 27 ++ artiq/frontend/artiq_devtool.py | 15 +- artiq/frontend/artiq_flash.py | 2 +- artiq/gateware/amp/__init__.py | 2 +- artiq/gateware/amp/soc.py | 21 -- artiq/gateware/targets/kasli.py | 7 +- .../targets/{kc705_dds.py => kc705.py} | 125 ++++++++-- artiq/gateware/targets/kc705_sma_spi.py | 157 ------------ .../{sayma_amc_standalone.py => sayma_amc.py} | 230 ++++++++++++++++-- .../targets/sayma_amc_drtio_master.py | 131 ---------- .../targets/sayma_amc_drtio_satellite.py | 121 --------- conda/artiq-kasli-opticlock/build.sh | 2 +- conda/artiq-kc705-nist_clock/build.sh | 2 +- conda/artiq-kc705-nist_qc2/build.sh | 2 +- conda/artiq-sayma_amc-standalone/build.sh | 2 +- doc/manual/developing.rst | 2 +- 17 files changed, 359 insertions(+), 491 deletions(-) create mode 100644 artiq/build_soc.py rename artiq/gateware/targets/{kc705_dds.py => kc705.py} (79%) delete mode 100755 artiq/gateware/targets/kc705_sma_spi.py rename artiq/gateware/targets/{sayma_amc_standalone.py => sayma_amc.py} (54%) delete mode 100755 artiq/gateware/targets/sayma_amc_drtio_master.py delete mode 100755 artiq/gateware/targets/sayma_amc_drtio_satellite.py diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 525455f53..f0291cf45 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -19,6 +19,8 @@ Release notes * The master now has a ``--name`` argument. If given, the dashboard is labelled with this name rather than the server address. * ``artiq_flash --adapter`` has been changed to ``artiq_flash --variant``. +* ``kc705_dds`` has been renamed ``kc705``. +* the ``-H/--hw-adapter`` option of ``kc705`` has ben renamed ``-V/--variant``. 3.2 diff --git a/artiq/build_soc.py b/artiq/build_soc.py new file mode 100644 index 000000000..ab2caf9ce --- /dev/null +++ b/artiq/build_soc.py @@ -0,0 +1,27 @@ +import os +import subprocess + +from misoc.integration.builder import * + +from artiq.gateware.amp import AMPSoC +from artiq import __artiq_dir__ as artiq_dir + + +def build_artiq_soc(soc, argdict): + firmware_dir = os.path.join(artiq_dir, "firmware") + builder = Builder(soc, **argdict) + builder.software_packages = [] + builder.add_software_package("bootloader", os.path.join(firmware_dir, "bootloader")) + if isinstance(soc, AMPSoC): + builder.add_software_package("libm") + builder.add_software_package("libprintf") + builder.add_software_package("libunwind") + builder.add_software_package("ksupport", os.path.join(firmware_dir, "ksupport")) + builder.add_software_package("runtime", os.path.join(firmware_dir, "runtime")) + else: + # Assume DRTIO satellite. + builder.add_software_package("satman", os.path.join(firmware_dir, "satman")) + try: + builder.build() + except subprocess.CalledProcessError as e: + raise SystemExit("Command {} failed".format(" ".join(e.cmd))) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 6fbf6dceb..d0283f61e 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -29,17 +29,16 @@ def get_argparser(): verbosity_args(parser) parser.add_argument("-t", "--target", metavar="TARGET", - type=str, default="kc705_dds", + type=str, default="kc705", help="target to build, one of: " - "kc705_dds kasli sayma_rtm sayma_amc_standalone " - "sayma_amc_drtio_master sayma_amc_drtio_satellite") + "kc705 kasli sayma_rtm sayma_amc") parser.add_argument("-g", "--build-gateware", default=False, action="store_true", help="build gateware, not just software") parser.add_argument("-H", "--host", type=str, default="lab.m-labs.hk", help="SSH host where the development board is located") - parser.add_argument('-b', "--board", + parser.add_argument("-b", "--board", type=str, default="{board_type}-1", help="board to connect to on the development SSH host") parser.add_argument("-B", "--board-file", @@ -73,15 +72,11 @@ def main(): return os.path.join("/tmp", target, *path) extra_build_args = [] - if args.target == "kc705_dds": + if args.target == "kc705": board_type, firmware = "kc705", "runtime" - elif args.target == "sayma_amc_standalone": + elif args.target == "sayma_amc": board_type, firmware = "sayma_amc", "runtime" extra_build_args += ["--rtm-csr-csv", build_dir("sayma_rtm_csr.csv", target="sayma_rtm")] - elif args.target == "sayma_amc_drtio_master": - board_type, firmware = "sayma_amc", "runtime" - elif args.target == "sayma_amc_drtio_satellite": - board_type, firmware = "sayma_amc", "satman" elif args.target == "sayma_rtm": board_type, firmware = "sayma_rtm", None else: diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 3520357e6..7e1477af5 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -51,7 +51,7 @@ Prerequisites: parser.add_argument("-t", "--target", default="kc705", help="target board, default: %(default)s, one of: " "kc705 kasli sayma_amc sayma_rtm") - parser.add_argument("-m", "--variant", default=None, + parser.add_argument("-V", "--variant", default=None, help="board variant") parser.add_argument("-I", "--preinit-command", default=[], action="append", help="add a pre-initialization OpenOCD command. " diff --git a/artiq/gateware/amp/__init__.py b/artiq/gateware/amp/__init__.py index df70e9f90..6abb5b594 100644 --- a/artiq/gateware/amp/__init__.py +++ b/artiq/gateware/amp/__init__.py @@ -1 +1 @@ -from artiq.gateware.amp.soc import AMPSoC, build_artiq_soc +from artiq.gateware.amp.soc import AMPSoC diff --git a/artiq/gateware/amp/soc.py b/artiq/gateware/amp/soc.py index 1761fb72c..76d79807c 100644 --- a/artiq/gateware/amp/soc.py +++ b/artiq/gateware/amp/soc.py @@ -1,13 +1,8 @@ -import os -import subprocess - from misoc.cores import timer from misoc.interconnect import wishbone -from misoc.integration.builder import * from artiq.gateware.amp.kernel_cpu import KernelCPU from artiq.gateware.amp.mailbox import Mailbox -from artiq import __artiq_dir__ as artiq_dir class AMPSoC: @@ -42,19 +37,3 @@ class AMPSoC: self.add_csr_region(name, self.mem_map[name] | 0x80000000, 32, csrs) - - -def build_artiq_soc(soc, argdict): - firmware_dir = os.path.join(artiq_dir, "firmware") - builder = Builder(soc, **argdict) - builder.software_packages = [] - builder.add_software_package("libm") - builder.add_software_package("libprintf") - builder.add_software_package("libunwind") - builder.add_software_package("bootloader", os.path.join(firmware_dir, "bootloader")) - builder.add_software_package("ksupport", os.path.join(firmware_dir, "ksupport")) - builder.add_software_package("runtime", os.path.join(firmware_dir, "runtime")) - try: - builder.build() - except subprocess.CalledProcessError as e: - raise SystemExit("Command {} failed".format(" ".join(e.cmd))) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 5495bb582..79a718ed4 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -15,9 +15,10 @@ from misoc.targets.kasli import (MiniSoC, soc_kasli_args, soc_kasli_argdict) from misoc.integration.builder import builder_args, builder_argdict -from artiq.gateware.amp import AMPSoC, build_artiq_soc +from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi +from artiq.build_soc import build_artiq_soc from artiq import __version__ as artiq_version @@ -186,8 +187,8 @@ def main(): description="ARTIQ device binary builder for Kasli systems") builder_args(parser) soc_kasli_args(parser) - parser.add_argument("--variant", default="opticlock", - help="extension variant setup: opticlock " + parser.add_argument("-V", "--variant", default="opticlock", + help="variant: opticlock " "(default: %(default)s)") args = parser.parse_args() diff --git a/artiq/gateware/targets/kc705_dds.py b/artiq/gateware/targets/kc705.py similarity index 79% rename from artiq/gateware/targets/kc705_dds.py rename to artiq/gateware/targets/kc705.py index 31baed85e..180a88245 100755 --- a/artiq/gateware/targets/kc705_dds.py +++ b/artiq/gateware/targets/kc705.py @@ -14,15 +14,16 @@ from misoc.cores import gpio from misoc.targets.kc705 import MiniSoC, soc_kc705_args, soc_kc705_argdict from misoc.integration.builder import builder_args, builder_argdict -from artiq.gateware.amp import AMPSoC, build_artiq_soc +from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio, nist_clock, nist_qc2 from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series, dds, spi, ad5360_monitor) +from artiq.build_soc import build_artiq_soc from artiq import __version__ as artiq_version class _RTIOCRG(Module, AutoCSR): - def __init__(self, platform, rtio_internal_clk): + def __init__(self, platform, rtio_internal_clk, use_sma=True): self._clock_sel = CSRStorage() self._pll_reset = CSRStorage(reset=1) self._pll_locked = CSRStatus() @@ -31,15 +32,17 @@ class _RTIOCRG(Module, AutoCSR): # 100 MHz when using 125MHz input self.clock_domains.cd_ext_clkout = ClockDomain(reset_less=True) - ext_clkout = platform.request("user_sma_gpio_p_33") - self.sync.ext_clkout += ext_clkout.eq(~ext_clkout) + if use_sma: + ext_clkout = platform.request("user_sma_gpio_p_33") + self.sync.ext_clkout += ext_clkout.eq(~ext_clkout) rtio_external_clk = Signal() - user_sma_clock = platform.request("user_sma_clock") - platform.add_period_constraint(user_sma_clock.p, 8.0) - self.specials += Instance("IBUFDS", - i_I=user_sma_clock.p, i_IB=user_sma_clock.n, - o_O=rtio_external_clk) + if use_sma: + user_sma_clock = platform.request("user_sma_clock") + platform.add_period_constraint(user_sma_clock.p, 8.0) + self.specials += Instance("IBUFDS", + i_I=user_sma_clock.p, i_IB=user_sma_clock.n, + o_O=rtio_external_clk) pll_locked = Signal() rtio_clk = Signal() @@ -201,7 +204,7 @@ _urukul = [ ] -class _NIST_Ions(MiniSoC, AMPSoC): +class _Standalone_Base(MiniSoC, AMPSoC): mem_map = { "cri_con": 0x10000000, "rtio": 0x20000000, @@ -273,12 +276,12 @@ class _NIST_Ions(MiniSoC, AMPSoC): self.csr_devices.append("rtio_analyzer") -class NIST_CLOCK(_NIST_Ions): +class NIST_CLOCK(_Standalone_Base): """ NIST clock hardware, with old backplane and 11 DDS channels """ def __init__(self, **kwargs): - _NIST_Ions.__init__(self, **kwargs) + _Standalone_Base.__init__(self, **kwargs) platform = self.platform platform.add_extension(nist_clock.fmc_adapter_io) @@ -374,13 +377,13 @@ class NIST_CLOCK(_NIST_Ions): self.add_rtio(rtio_channels) -class NIST_QC2(_NIST_Ions): +class NIST_QC2(_Standalone_Base): """ NIST QC2 hardware, as used in Quantum I and Quantum II, with new backplane and 24 DDS channels. Two backplanes are used. """ def __init__(self, **kwargs): - _NIST_Ions.__init__(self, **kwargs) + _Standalone_Base.__init__(self, **kwargs) platform = self.platform platform.add_extension(nist_qc2.fmc_adapter_io) @@ -444,25 +447,101 @@ class NIST_QC2(_NIST_Ions): self.add_rtio(rtio_channels) +_sma_spi = [ + ("sma_spi", 0, + Subsignal("clk", Pins("Y23")), # user_sma_gpio_p + Subsignal("cs_n", Pins("Y24")), # user_sma_gpio_n + Subsignal("mosi", Pins("L25")), # user_sma_clk_p + Subsignal("miso", Pins("K25")), # user_sma_clk_n + IOStandard("LVCMOS25")), +] + + +class SMA_SPI(_Standalone_Base): + """ + SPI on 4 SMA for PDQ2 test/demo. + """ + def __init__(self, **kwargs): + _Standalone_Base.__init__(self, **kwargs) + + platform = self.platform + self.platform.add_extension(_sma_spi) + + rtio_channels = [] + + phy = ttl_simple.Output(platform.request("user_led", 2)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + ams101_dac = self.platform.request("ams101_dac", 0) + phy = ttl_simple.Output(ams101_dac.ldac) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + phy = spi.SPIMaster(ams101_dac) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy( + phy, ififo_depth=4)) + + phy = spi.SPIMaster(self.platform.request("sma_spi")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy( + phy, ififo_depth=128)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) + rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(rtio_channels) + + def add_rtio(self, rtio_channels): + self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk, + use_sma=False) + self.csr_devices.append("rtio_crg") + self.submodules.rtio_core = rtio.Core(rtio_channels) + self.csr_devices.append("rtio_core") + self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( + rtio.DMA(self.get_native_sdram_if())) + self.register_kernel_cpu_csrdevice("rtio") + self.register_kernel_cpu_csrdevice("rtio_dma") + self.submodules.cri_con = rtio.CRIInterconnectShared( + [self.rtio.cri, self.rtio_dma.cri], + [self.rtio_core.cri]) + self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) + self.csr_devices.append("rtio_moninj") + + self.rtio_crg.cd_rtio.clk.attr.add("keep") + self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.) + self.platform.add_false_path_constraints( + self.crg.cd_sys.clk, + self.rtio_crg.cd_rtio.clk) + + self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri, + self.get_native_sdram_if()) + self.csr_devices.append("rtio_analyzer") + + def main(): parser = argparse.ArgumentParser( - description="ARTIQ device binary builder / single-FPGA KC705-based " - "systems with AD9 DDS (NIST Ions hardware)") + description="KC705 gateware and firmware builder") builder_args(parser) soc_kc705_args(parser) - parser.add_argument("-H", "--hw-adapter", default="nist_clock", - help="hardware adapter type: " - "nist_clock/nist_qc2 " + parser.add_argument("-V", "--variant", default="nist_clock", + help="variant: " + "nist_clock/nist_qc2/sma_spi " "(default: %(default)s)") args = parser.parse_args() - hw_adapter = args.hw_adapter.lower() - if hw_adapter == "nist_clock": + variant = args.variant.lower() + if variant == "nist_clock": cls = NIST_CLOCK - elif hw_adapter == "nist_qc2": + elif variant == "nist_qc2": cls = NIST_QC2 + elif variant == "sma_spi": + cls = SMA_SPI else: - raise SystemExit("Invalid hardware adapter string (-H/--hw-adapter)") + raise SystemExit("Invalid variant (-V/--variant)") soc = cls(**soc_kc705_argdict(args)) build_artiq_soc(soc, builder_argdict(args)) diff --git a/artiq/gateware/targets/kc705_sma_spi.py b/artiq/gateware/targets/kc705_sma_spi.py deleted file mode 100755 index cd1a705e5..000000000 --- a/artiq/gateware/targets/kc705_sma_spi.py +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/env python3 - -import argparse - -from migen import * - -from migen.build.generic_platform import * -from migen.genlib.resetsync import AsyncResetSynchronizer -from migen.genlib.cdc import MultiReg -from misoc.targets.kc705 import soc_kc705_args, soc_kc705_argdict -from misoc.integration.builder import builder_args, builder_argdict -from misoc.interconnect.csr import * - -from artiq.gateware.amp import build_artiq_soc -from artiq.gateware import rtio -from artiq.gateware.rtio.phy import ttl_simple, spi - - -from .kc705_dds import _NIST_Ions - - -class _RTIOCRG(Module, AutoCSR): - def __init__(self, platform, rtio_internal_clk): - self._clock_sel = CSRStorage() - self._pll_reset = CSRStorage(reset=1) - self._pll_locked = CSRStatus() - self.clock_domains.cd_rtio = ClockDomain() - self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) - - # 10 MHz when using 125MHz input - self.clock_domains.cd_ext_clkout = ClockDomain(reset_less=True) - - rtio_external_clk = Signal() - - pll_locked = Signal() - rtio_clk = Signal() - rtiox4_clk = Signal() - ext_clkout_clk = Signal() - self.specials += [ - Instance("PLLE2_ADV", - p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, - - p_REF_JITTER1=0.01, - p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0, - i_CLKIN1=rtio_internal_clk, i_CLKIN2=rtio_external_clk, - # Warning: CLKINSEL=0 means CLKIN2 is selected - i_CLKINSEL=~self._clock_sel.storage, - - # VCO @ 1GHz when using 125MHz input - p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, - i_CLKFBIN=self.cd_rtio.clk, - i_RST=self._pll_reset.storage, - - o_CLKFBOUT=rtio_clk, - - p_CLKOUT0_DIVIDE=2, p_CLKOUT0_PHASE=0.0, - o_CLKOUT0=rtiox4_clk, - - p_CLKOUT1_DIVIDE=50, p_CLKOUT1_PHASE=0.0, - o_CLKOUT1=ext_clkout_clk), - Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk), - Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), - Instance("BUFG", i_I=ext_clkout_clk, o_O=self.cd_ext_clkout.clk), - - AsyncResetSynchronizer(self.cd_rtio, ~pll_locked), - MultiReg(pll_locked, self._pll_locked.status) - ] - - -_sma_spi = [ - ("sma_spi", 0, - Subsignal("clk", Pins("Y23")), # user_sma_gpio_p - Subsignal("cs_n", Pins("Y24")), # user_sma_gpio_n - Subsignal("mosi", Pins("L25")), # user_sma_clk_p - Subsignal("miso", Pins("K25")), # user_sma_clk_n - IOStandard("LVCMOS25")), -] - - -class SMA_SPI(_NIST_Ions): - """ - SPI on 4 SMA for PDQ2 test/demo. - """ - def __init__(self, **kwargs): - _NIST_Ions.__init__(self, **kwargs) - - platform = self.platform - self.platform.add_extension(_sma_spi) - - rtio_channels = [] - - phy = ttl_simple.Output(platform.request("user_led", 2)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - ams101_dac = self.platform.request("ams101_dac", 0) - phy = ttl_simple.Output(ams101_dac.ldac) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - phy = spi.SPIMaster(ams101_dac) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy( - phy, ififo_depth=4)) - - phy = spi.SPIMaster(self.platform.request("sma_spi")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy( - phy, ififo_depth=128)) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) - - self.add_rtio(rtio_channels) - - def add_rtio(self, rtio_channels): - self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) - self.csr_devices.append("rtio_crg") - self.submodules.rtio_core = rtio.Core(rtio_channels) - self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() - self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( - rtio.DMA(self.get_native_sdram_if())) - self.register_kernel_cpu_csrdevice("rtio") - self.register_kernel_cpu_csrdevice("rtio_dma") - self.submodules.cri_con = rtio.CRIInterconnectShared( - [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri]) - self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) - self.csr_devices.append("rtio_moninj") - - self.rtio_crg.cd_rtio.clk.attr.add("keep") - self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.) - self.platform.add_false_path_constraints( - self.crg.cd_sys.clk, - self.rtio_crg.cd_rtio.clk) - - self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri, - self.get_native_sdram_if()) - self.csr_devices.append("rtio_analyzer") - - -def main(): - parser = argparse.ArgumentParser( - description="ARTIQ device binary builder / " - "KC705 SMA SPI demo/test for PDQ2") - builder_args(parser) - soc_kc705_args(parser) - args = parser.parse_args() - - soc = SMA_SPI(**soc_kc705_argdict(args)) - build_artiq_soc(soc, builder_argdict(args)) - - -if __name__ == "__main__": - main() diff --git a/artiq/gateware/targets/sayma_amc_standalone.py b/artiq/gateware/targets/sayma_amc.py similarity index 54% rename from artiq/gateware/targets/sayma_amc_standalone.py rename to artiq/gateware/targets/sayma_amc.py index 5ef866d0a..27692219a 100755 --- a/artiq/gateware/targets/sayma_amc_standalone.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -3,6 +3,7 @@ import argparse import os from collections import namedtuple +import warnings from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer @@ -23,11 +24,14 @@ from jesd204b.phy import JESD204BPhyTX from jesd204b.core import JESD204BCoreTX from jesd204b.core import JESD204BCoreTXControl -from artiq.gateware.amp import AMPSoC, build_artiq_soc +from artiq.gateware.amp import AMPSoC from artiq.gateware import serwb from artiq.gateware import remote_csr from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple, sawg +from artiq.gateware.drtio.transceiver import gth_ultrascale +from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite +from artiq.build_soc import build_artiq_soc from artiq import __version__ as artiq_version @@ -129,7 +133,7 @@ class Standalone(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, with_sawg=False, **kwargs): + def __init__(self, with_sawg, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -248,33 +252,223 @@ class Standalone(MiniSoC, AMPSoC): self.csr_devices.append("rtio_analyzer") +class Master(MiniSoC, AMPSoC): + mem_map = { + "cri_con": 0x10000000, + "rtio": 0x20000000, + "rtio_dma": 0x30000000, + "drtio_aux": 0x50000000, + "mailbox": 0x70000000 + } + mem_map.update(MiniSoC.mem_map) + + def __init__(self, **kwargs): + MiniSoC.__init__(self, + cpu_type="or1k", + sdram_controller_type="minicon", + l2_size=128*1024, + ident=artiq_version, + ethmac_nrxslots=4, + ethmac_ntxslots=4, + **kwargs) + AMPSoC.__init__(self) + + platform = self.platform + rtio_clk_freq = 150e6 + + self.submodules += Microscope(platform.request("serial", 1), + self.clk_freq) + + # Si5324 used as a free-running oscillator, to avoid dependency on RTM. + self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) + self.csr_devices.append("si5324_rst_n") + i2c = self.platform.request("i2c") + self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) + self.csr_devices.append("i2c") + self.config["I2C_BUS_COUNT"] = 1 + self.config["HAS_SI5324"] = None + self.config["SI5324_FREE_RUNNING"] = None + + self.comb += platform.request("sfp_tx_disable_n", 0).eq(1) + self.submodules.transceiver = gth_ultrascale.GTH( + clock_pads=platform.request("si5324_clkout"), + data_pads=[platform.request("sfp", 0)], + sys_clk_freq=self.clk_freq, + rtio_clk_freq=rtio_clk_freq) + + self.submodules.drtio0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"})( + DRTIOMaster(self.transceiver.channels[0])) + self.csr_devices.append("drtio0") + self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, + self.drtio0.aux_controller.bus) + self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) + self.config["HAS_DRTIO"] = None + self.add_csr_group("drtio", ["drtio0"]) + self.add_memory_group("drtio_aux", ["drtio0_aux"]) + + rtio_clk_period = 1e9/rtio_clk_freq + for gth in self.transceiver.gths: + platform.add_period_constraint(gth.txoutclk, rtio_clk_period) + platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, + gth.txoutclk, gth.rxoutclk) + + rtio_channels = [] + for i in range(4): + phy = ttl_simple.Output(platform.request("user_led", i)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + sma_io = platform.request("sma_io", 0) + self.comb += sma_io.direction.eq(1) + phy = ttl_simple.Output(sma_io.level) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + sma_io = platform.request("sma_io", 1) + self.comb += sma_io.direction.eq(0) + phy = ttl_simple.InOut(sma_io.level) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) + self.csr_devices.append("rtio_moninj") + + self.submodules.rtio_core = rtio.Core(rtio_channels, glbl_fine_ts_width=3) + self.csr_devices.append("rtio_core") + + self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( + rtio.DMA(self.get_native_sdram_if())) + self.register_kernel_cpu_csrdevice("rtio") + self.register_kernel_cpu_csrdevice("rtio_dma") + self.submodules.cri_con = rtio.CRIInterconnectShared( + [self.rtio.cri, self.rtio_dma.cri], + [self.rtio_core.cri, self.drtio0.cri]) + self.register_kernel_cpu_csrdevice("cri_con") + + +class Satellite(BaseSoC): + mem_map = { + "drtio_aux": 0x50000000, + } + mem_map.update(BaseSoC.mem_map) + + def __init__(self, with_sawg, **kwargs): + BaseSoC.__init__(self, + cpu_type="or1k", + sdram_controller_type="minicon", + l2_size=128*1024, + ident=artiq_version, + **kwargs) + + if with_sawg: + warnings.warn("SAWG is not implemented yet with DRTIO, ignoring.") + + platform = self.platform + rtio_clk_freq = 150e6 + + self.submodules += Microscope(platform.request("serial", 1), + self.clk_freq) + + rtio_channels = [] + for i in range(4): + phy = ttl_simple.Output(platform.request("user_led", i)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + sma_io = platform.request("sma_io", 0) + self.comb += sma_io.direction.eq(1) + phy = ttl_simple.Output(sma_io.level) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + sma_io = platform.request("sma_io", 1) + self.comb += sma_io.direction.eq(0) + phy = ttl_simple.InOut(sma_io.level) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) + self.csr_devices.append("rtio_moninj") + + self.comb += platform.request("sfp_tx_disable_n", 0).eq(1) + self.submodules.transceiver = gth_ultrascale.GTH( + clock_pads=platform.request("si5324_clkout"), + data_pads=[platform.request("sfp", 0)], + sys_clk_freq=self.clk_freq, + rtio_clk_freq=rtio_clk_freq) + rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) + self.submodules.drtio0 = rx0(DRTIOSatellite( + self.transceiver.channels[0], rtio_channels)) + self.csr_devices.append("drtio0") + self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, + self.drtio0.aux_controller.bus) + self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) + self.config["HAS_DRTIO"] = None + self.add_csr_group("drtio", ["drtio0"]) + self.add_memory_group("drtio_aux", ["drtio0_aux"]) + + self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) + si5324_clkin = platform.request("si5324_clkin") + self.specials += \ + Instance("OBUFDS", + i_I=ClockSignal("rtio_rx0"), + o_O=si5324_clkin.p, o_OB=si5324_clkin.n + ) + self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) + self.csr_devices.append("si5324_rst_n") + i2c = self.platform.request("i2c") + self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) + self.csr_devices.append("i2c") + self.config["I2C_BUS_COUNT"] = 1 + self.config["HAS_SI5324"] = None + + rtio_clk_period = 1e9/rtio_clk_freq + gth = self.transceiver.gths[0] + platform.add_period_constraint(gth.txoutclk, rtio_clk_period) + platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, + gth.txoutclk, gth.rxoutclk) + + def main(): parser = argparse.ArgumentParser( - description="ARTIQ device binary builder / Sayma AMC stand-alone") + description="Sayma AMC gateware and firmware builder") builder_args(parser) soc_sdram_args(parser) + parser.add_argument("-V", "--variant", default="standalone", + help="variant: " + "standalone/master/satellite " + "(default: %(default)s)") parser.add_argument("--rtm-csr-csv", default=os.path.join("artiq_sayma_rtm", "sayma_rtm_csr.csv"), help="CSV file listing remote CSRs on RTM (default: %(default)s)") - parser.add_argument("--with-sawg", + parser.add_argument("--without-sawg", default=False, action="store_true", - help="Add SAWG RTIO channels feeding the JESD links. If not " - "specified, fixed sawtooth generators are used. " - "(default: %(default)s)") + help="Remove SAWG RTIO channels feeding the JESD links (speeds up " + "compilation time). Replaces them with fixed sawtooth generators.") args = parser.parse_args() - soc = Standalone(with_sawg=args.with_sawg, **soc_sdram_argdict(args)) + variant = args.variant.lower() + if variant == "standalone": + cls = Standalone + elif variant == "master": + cls = Master + elif variant == "satellite": + cls = Satellite + soc = cls(with_sawg=not args.without_sawg, **soc_sdram_argdict(args)) - remote_csr_regions = remote_csr.get_remote_csr_regions( - soc.mem_map["serwb"] | soc.shadow_base, - args.rtm_csr_csv) - for name, origin, busword, csrs in remote_csr_regions: - soc.add_csr_region(name, origin, busword, csrs) - # Configuration for RTM peripherals. Keep in sync with sayma_rtm.py! - soc.config["HAS_HMC830_7043"] = None - soc.config["CONVERTER_SPI_HMC830_CS"] = 0 - soc.config["CONVERTER_SPI_HMC7043_CS"] = 1 - soc.config["CONVERTER_SPI_FIRST_AD9154_CS"] = 2 + # DRTIO variants do not use the RTM yet. + if variant not in {"master", "satellite"}: + remote_csr_regions = remote_csr.get_remote_csr_regions( + soc.mem_map["serwb"] | soc.shadow_base, + args.rtm_csr_csv) + for name, origin, busword, csrs in remote_csr_regions: + soc.add_csr_region(name, origin, busword, csrs) + # Configuration for RTM peripherals. Keep in sync with sayma_rtm.py! + soc.config["HAS_HMC830_7043"] = None + soc.config["CONVERTER_SPI_HMC830_CS"] = 0 + soc.config["CONVERTER_SPI_HMC7043_CS"] = 1 + soc.config["CONVERTER_SPI_FIRST_AD9154_CS"] = 2 build_artiq_soc(soc, builder_argdict(args)) diff --git a/artiq/gateware/targets/sayma_amc_drtio_master.py b/artiq/gateware/targets/sayma_amc_drtio_master.py deleted file mode 100755 index 9bbb8db31..000000000 --- a/artiq/gateware/targets/sayma_amc_drtio_master.py +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env python3 - -import argparse - -from migen import * -from migen.build.generic_platform import * - -from misoc.cores import spi as spi_csr -from misoc.cores import gpio -from misoc.integration.soc_sdram import soc_sdram_args, soc_sdram_argdict -from misoc.integration.builder import builder_args, builder_argdict -from misoc.targets.sayma_amc import MiniSoC - -from microscope import * - -from artiq.gateware.amp import AMPSoC, build_artiq_soc -from artiq.gateware import rtio -from artiq.gateware.rtio.phy import ttl_simple -from artiq.gateware.drtio.transceiver import gth_ultrascale -from artiq.gateware.drtio import DRTIOMaster -from artiq import __version__ as artiq_version - - -class Master(MiniSoC, AMPSoC): - mem_map = { - "cri_con": 0x10000000, - "rtio": 0x20000000, - "rtio_dma": 0x30000000, - "drtio_aux": 0x50000000, - "mailbox": 0x70000000 - } - mem_map.update(MiniSoC.mem_map) - - def __init__(self, **kwargs): - MiniSoC.__init__(self, - cpu_type="or1k", - sdram_controller_type="minicon", - l2_size=128*1024, - ident=artiq_version, - ethmac_nrxslots=4, - ethmac_ntxslots=4, - **kwargs) - AMPSoC.__init__(self) - - platform = self.platform - rtio_clk_freq = 150e6 - - self.submodules += Microscope(platform.request("serial", 1), - self.clk_freq) - - # Si5324 used as a free-running oscillator, to avoid dependency on RTM. - self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) - self.csr_devices.append("si5324_rst_n") - i2c = self.platform.request("i2c") - self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) - self.csr_devices.append("i2c") - self.config["I2C_BUS_COUNT"] = 1 - self.config["HAS_SI5324"] = None - self.config["SI5324_FREE_RUNNING"] = None - - self.comb += platform.request("sfp_tx_disable_n", 0).eq(1) - self.submodules.transceiver = gth_ultrascale.GTH( - clock_pads=platform.request("si5324_clkout"), - data_pads=[platform.request("sfp", 0)], - sys_clk_freq=self.clk_freq, - rtio_clk_freq=rtio_clk_freq) - - self.submodules.drtio0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"})( - DRTIOMaster(self.transceiver.channels[0])) - self.csr_devices.append("drtio0") - self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, - self.drtio0.aux_controller.bus) - self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) - self.config["HAS_DRTIO"] = None - self.add_csr_group("drtio", ["drtio0"]) - self.add_memory_group("drtio_aux", ["drtio0_aux"]) - - rtio_clk_period = 1e9/rtio_clk_freq - for gth in self.transceiver.gths: - platform.add_period_constraint(gth.txoutclk, rtio_clk_period) - platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - gth.txoutclk, gth.rxoutclk) - - rtio_channels = [] - for i in range(4): - phy = ttl_simple.Output(platform.request("user_led", i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - sma_io = platform.request("sma_io", 0) - self.comb += sma_io.direction.eq(1) - phy = ttl_simple.Output(sma_io.level) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - sma_io = platform.request("sma_io", 1) - self.comb += sma_io.direction.eq(0) - phy = ttl_simple.InOut(sma_io.level) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) - self.csr_devices.append("rtio_moninj") - - self.submodules.rtio_core = rtio.Core(rtio_channels, glbl_fine_ts_width=3) - self.csr_devices.append("rtio_core") - - self.submodules.rtio = rtio.KernelInitiator() - self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( - rtio.DMA(self.get_native_sdram_if())) - self.register_kernel_cpu_csrdevice("rtio") - self.register_kernel_cpu_csrdevice("rtio_dma") - self.submodules.cri_con = rtio.CRIInterconnectShared( - [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri, self.drtio0.cri]) - self.register_kernel_cpu_csrdevice("cri_con") - - -def main(): - parser = argparse.ArgumentParser( - description="ARTIQ device binary builder / Sayma DRTIO master") - builder_args(parser) - soc_sdram_args(parser) - args = parser.parse_args() - - soc = Master(**soc_sdram_argdict(args)) - build_artiq_soc(soc, builder_argdict(args)) - - -if __name__ == "__main__": - main() diff --git a/artiq/gateware/targets/sayma_amc_drtio_satellite.py b/artiq/gateware/targets/sayma_amc_drtio_satellite.py deleted file mode 100755 index 20526e54b..000000000 --- a/artiq/gateware/targets/sayma_amc_drtio_satellite.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import os - -from migen import * -from migen.build.generic_platform import * -from misoc.cores import spi as spi_csr -from misoc.cores import gpio -from misoc.integration.soc_sdram import soc_sdram_args, soc_sdram_argdict -from misoc.integration.builder import * -from misoc.targets.sayma_amc import BaseSoC - -from microscope import * - -from artiq.gateware import rtio -from artiq.gateware.rtio.phy import ttl_simple -from artiq.gateware.drtio.transceiver import gth_ultrascale -from artiq.gateware.drtio import DRTIOSatellite -from artiq import __version__ as artiq_version -from artiq import __artiq_dir__ as artiq_dir - - -class Satellite(BaseSoC): - mem_map = { - "drtio_aux": 0x50000000, - } - mem_map.update(BaseSoC.mem_map) - - def __init__(self, **kwargs): - BaseSoC.__init__(self, - cpu_type="or1k", - sdram_controller_type="minicon", - l2_size=128*1024, - ident=artiq_version, - **kwargs) - - platform = self.platform - rtio_clk_freq = 150e6 - - self.submodules += Microscope(platform.request("serial", 1), - self.clk_freq) - - rtio_channels = [] - for i in range(4): - phy = ttl_simple.Output(platform.request("user_led", i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - sma_io = platform.request("sma_io", 0) - self.comb += sma_io.direction.eq(1) - phy = ttl_simple.Output(sma_io.level) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - sma_io = platform.request("sma_io", 1) - self.comb += sma_io.direction.eq(0) - phy = ttl_simple.InOut(sma_io.level) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) - self.csr_devices.append("rtio_moninj") - - self.comb += platform.request("sfp_tx_disable_n", 0).eq(1) - self.submodules.transceiver = gth_ultrascale.GTH( - clock_pads=platform.request("si5324_clkout"), - data_pads=[platform.request("sfp", 0)], - sys_clk_freq=self.clk_freq, - rtio_clk_freq=rtio_clk_freq) - rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) - self.submodules.drtio0 = rx0(DRTIOSatellite( - self.transceiver.channels[0], rtio_channels)) - self.csr_devices.append("drtio0") - self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, - self.drtio0.aux_controller.bus) - self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) - self.config["HAS_DRTIO"] = None - self.add_csr_group("drtio", ["drtio0"]) - self.add_memory_group("drtio_aux", ["drtio0_aux"]) - - self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - si5324_clkin = platform.request("si5324_clkin") - self.specials += \ - Instance("OBUFDS", - i_I=ClockSignal("rtio_rx0"), - o_O=si5324_clkin.p, o_OB=si5324_clkin.n - ) - self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) - self.csr_devices.append("si5324_rst_n") - i2c = self.platform.request("i2c") - self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) - self.csr_devices.append("i2c") - self.config["I2C_BUS_COUNT"] = 1 - self.config["HAS_SI5324"] = None - - rtio_clk_period = 1e9/rtio_clk_freq - gth = self.transceiver.gths[0] - platform.add_period_constraint(gth.txoutclk, rtio_clk_period) - platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - gth.txoutclk, gth.rxoutclk) - - -def main(): - parser = argparse.ArgumentParser( - description="ARTIQ device binary builder / Sayma DRTIO satellite") - builder_args(parser) - soc_sdram_args(parser) - args = parser.parse_args() - - soc = Satellite(**soc_sdram_argdict(args)) - firmware_dir = os.path.join(artiq_dir, "firmware") - builder = Builder(soc, **builder_argdict(args)) - builder.software_packages = [] - builder.add_software_package("bootloader", os.path.join(firmware_dir, "bootloader")) - builder.add_software_package("satman", os.path.join(firmware_dir, "satman")) - builder.build() - - -if __name__ == "__main__": - main() diff --git a/conda/artiq-kasli-opticlock/build.sh b/conda/artiq-kasli-opticlock/build.sh index fcf6dc5ee..c69d49191 100644 --- a/conda/artiq-kasli-opticlock/build.sh +++ b/conda/artiq-kasli-opticlock/build.sh @@ -3,7 +3,7 @@ SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/kasli-opticlock mkdir -p $SOC_PREFIX -V=1 $PYTHON -m artiq.gateware.targets.kasli --variant opticlock +V=1 $PYTHON -m artiq.gateware.targets.kasli -V opticlock cp misoc_opticlock_kasli/gateware/top.bit $SOC_PREFIX cp misoc_opticlock_kasli/software/bootloader/bootloader.bin $SOC_PREFIX cp misoc_opticlock_kasli/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-kc705-nist_clock/build.sh b/conda/artiq-kc705-nist_clock/build.sh index e81da80f7..dcad86304 100644 --- a/conda/artiq-kc705-nist_clock/build.sh +++ b/conda/artiq-kc705-nist_clock/build.sh @@ -3,7 +3,7 @@ SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/kc705-nist_clock mkdir -p $SOC_PREFIX -V=1 $PYTHON -m artiq.gateware.targets.kc705_dds -H nist_clock +V=1 $PYTHON -m artiq.gateware.targets.kc705 -V nist_clock cp misoc_nist_clock_kc705/gateware/top.bit $SOC_PREFIX cp misoc_nist_clock_kc705/software/bootloader/bootloader.bin $SOC_PREFIX cp misoc_nist_clock_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-kc705-nist_qc2/build.sh b/conda/artiq-kc705-nist_qc2/build.sh index a36df210d..4610d14f6 100644 --- a/conda/artiq-kc705-nist_qc2/build.sh +++ b/conda/artiq-kc705-nist_qc2/build.sh @@ -3,7 +3,7 @@ SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/kc705-nist_qc2 mkdir -p $SOC_PREFIX -V=1 $PYTHON -m artiq.gateware.targets.kc705_dds -H nist_qc2 +V=1 $PYTHON -m artiq.gateware.targets.kc705 -V nist_qc2 cp misoc_nist_qc2_kc705/gateware/top.bit $SOC_PREFIX cp misoc_nist_qc2_kc705/software/bootloader/bootloader.bin $SOC_PREFIX cp misoc_nist_qc2_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-sayma_amc-standalone/build.sh b/conda/artiq-sayma_amc-standalone/build.sh index 512e14ad0..918638a50 100644 --- a/conda/artiq-sayma_amc-standalone/build.sh +++ b/conda/artiq-sayma_amc-standalone/build.sh @@ -3,7 +3,7 @@ SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/sayma_amc-standalone mkdir -p $SOC_PREFIX -V=1 $PYTHON -m artiq.gateware.targets.sayma_amc_standalone --rtm-csr-csv $SP_DIR/artiq/binaries/sayma_rtm/sayma_rtm_csr.csv +V=1 $PYTHON -m artiq.gateware.targets.sayma_amc -V standalone --rtm-csr-csv $SP_DIR/artiq/binaries/sayma_rtm/sayma_rtm_csr.csv cp misoc_standalone_sayma_amc/gateware/top.bit $SOC_PREFIX cp misoc_standalone_sayma_amc/software/bootloader/bootloader.bin $SOC_PREFIX cp misoc_standalone_sayma_amc/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index 90b6f0849..1f60335d1 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -217,7 +217,7 @@ These steps are required to generate gateware bitstream (``.bit``) files, build * For KC705:: - $ python3 -m artiq.gateware.targets.kc705_dds -H nist_clock # or nist_qc2 + $ python3 -m artiq.gateware.targets.kc705 -V nist_clock # or nist_qc2 .. note:: Add ``--toolchain ise`` if you wish to use ISE instead of Vivado. ISE needs a separate installation step. From 53facfef133d841661cdb163e000e8ff23ecbe4c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 22 Jan 2018 18:33:22 +0800 Subject: [PATCH 0246/2457] sayma: build fixes --- artiq/gateware/targets/sayma_amc.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 27692219a..f7a22873d 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -9,12 +9,15 @@ from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.io import DifferentialInput +from microscope import * + +from misoc.cores import gpio from misoc.cores.slave_fpga import SlaveFPGA from misoc.integration.soc_sdram import soc_sdram_args, soc_sdram_argdict from misoc.integration.builder import builder_args, builder_argdict from misoc.interconnect import stream from misoc.interconnect.csr import * -from misoc.targets.sayma_amc import MiniSoC +from misoc.targets.sayma_amc import BaseSoC, MiniSoC from jesd204b.common import (JESD204BTransportSettings, JESD204BPhysicalSettings, @@ -262,7 +265,7 @@ class Master(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, **kwargs): + def __init__(self, with_sawg, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -273,6 +276,9 @@ class Master(MiniSoC, AMPSoC): **kwargs) AMPSoC.__init__(self) + if with_sawg: + warnings.warn("SAWG is not implemented yet with DRTIO, ignoring.") + platform = self.platform rtio_clk_freq = 150e6 From c1ac3b66b13e9811130789b5f91a83d6a3102995 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 00:01:45 +0800 Subject: [PATCH 0247/2457] sayma_rtm: fix 8fe463d4a --- artiq/gateware/targets/sayma_rtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 338019044..979decaa3 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -94,7 +94,7 @@ class SaymaRTM(Module): csr_devices.append("clock_mux") # UART loopback - serial = platform.request(serial) + serial = platform.request("serial") self.comb += serial.tx.eq(serial.rx) # Allaki: enable RF output, GPIO access to attenuator From ab7c49d6d0d24ed6e5f20e74296f7059f8c9f870 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 00:02:16 +0800 Subject: [PATCH 0248/2457] sayma_amc: raise error on invalid variant --- artiq/gateware/targets/sayma_amc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index f7a22873d..88af9bd3a 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -461,6 +461,8 @@ def main(): cls = Master elif variant == "satellite": cls = Satellite + else: + raise SystemExit("Invalid variant (-V/--variant)") soc = cls(with_sawg=not args.without_sawg, **soc_sdram_argdict(args)) # DRTIO variants do not use the RTM yet. From 77192256ea55056551ad74e1cb7d644c6a483426 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 00:02:35 +0800 Subject: [PATCH 0249/2457] kc705: style --- artiq/gateware/targets/kc705.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 180a88245..a74facd4b 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -204,7 +204,7 @@ _urukul = [ ] -class _Standalone_Base(MiniSoC, AMPSoC): +class _StandaloneBase(MiniSoC, AMPSoC): mem_map = { "cri_con": 0x10000000, "rtio": 0x20000000, @@ -276,12 +276,12 @@ class _Standalone_Base(MiniSoC, AMPSoC): self.csr_devices.append("rtio_analyzer") -class NIST_CLOCK(_Standalone_Base): +class NIST_CLOCK(_StandaloneBase): """ NIST clock hardware, with old backplane and 11 DDS channels """ def __init__(self, **kwargs): - _Standalone_Base.__init__(self, **kwargs) + _StandaloneBase.__init__(self, **kwargs) platform = self.platform platform.add_extension(nist_clock.fmc_adapter_io) @@ -377,13 +377,13 @@ class NIST_CLOCK(_Standalone_Base): self.add_rtio(rtio_channels) -class NIST_QC2(_Standalone_Base): +class NIST_QC2(_StandaloneBase): """ NIST QC2 hardware, as used in Quantum I and Quantum II, with new backplane and 24 DDS channels. Two backplanes are used. """ def __init__(self, **kwargs): - _Standalone_Base.__init__(self, **kwargs) + _StandaloneBase.__init__(self, **kwargs) platform = self.platform platform.add_extension(nist_qc2.fmc_adapter_io) @@ -457,12 +457,12 @@ _sma_spi = [ ] -class SMA_SPI(_Standalone_Base): +class SMA_SPI(_StandaloneBase): """ SPI on 4 SMA for PDQ2 test/demo. """ def __init__(self, **kwargs): - _Standalone_Base.__init__(self, **kwargs) + _StandaloneBase.__init__(self, **kwargs) platform = self.platform self.platform.add_extension(_sma_spi) From 296ac35f5d106d4fa39284a0302938f3e6927471 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 00:32:09 +0800 Subject: [PATCH 0250/2457] sayma_amc: SFP TX disable is active-high --- artiq/gateware/targets/sayma_amc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 88af9bd3a..e4cbef55c 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -295,7 +295,7 @@ class Master(MiniSoC, AMPSoC): self.config["HAS_SI5324"] = None self.config["SI5324_FREE_RUNNING"] = None - self.comb += platform.request("sfp_tx_disable_n", 0).eq(1) + self.comb += platform.request("sfp_tx_disable", 0).eq(0) self.submodules.transceiver = gth_ultrascale.GTH( clock_pads=platform.request("si5324_clkout"), data_pads=[platform.request("sfp", 0)], @@ -395,7 +395,7 @@ class Satellite(BaseSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.comb += platform.request("sfp_tx_disable_n", 0).eq(1) + self.comb += platform.request("sfp_tx_disable", 0).eq(0) self.submodules.transceiver = gth_ultrascale.GTH( clock_pads=platform.request("si5324_clkout"), data_pads=[platform.request("sfp", 0)], From aa62e91487b584ab35146378e54624c42b313cf6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 01:27:40 +0800 Subject: [PATCH 0251/2457] kasli: add DRTIO targets (no firmware) --- artiq/gateware/targets/kasli.py | 207 ++++++++++++++++++++++++++++++-- 1 file changed, 200 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 79a718ed4..65e3c3dd6 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -11,13 +11,16 @@ from migen.build.xilinx.ise import XilinxISEToolchain from misoc.interconnect.csr import * from misoc.cores import gpio -from misoc.targets.kasli import (MiniSoC, soc_kasli_args, - soc_kasli_argdict) +from misoc.cores.a7_gtp import * +from misoc.targets.kasli import (BaseSoC, MiniSoC, + soc_kasli_args, soc_kasli_argdict) from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi +from artiq.gateware.drtio.transceiver import gtp_7series +from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite from artiq.build_soc import build_artiq_soc from artiq import __version__ as artiq_version @@ -72,7 +75,7 @@ class _RTIOCRG(Module, AutoCSR): ] -class _KasliBase(MiniSoC, AMPSoC): +class _StandaloneBase(MiniSoC, AMPSoC): mem_map = { "cri_con": 0x10000000, "rtio": 0x20000000, @@ -144,12 +147,12 @@ def _dio(eem): for i in range(8)] -class Opticlock(_KasliBase): +class Opticlock(_StandaloneBase): """ Opticlock extension variant configuration """ def __init__(self, **kwargs): - _KasliBase.__init__(self, **kwargs) + _StandaloneBase.__init__(self, **kwargs) platform = self.platform platform.add_extension(_dio("eem0")) @@ -182,21 +185,211 @@ class Opticlock(_KasliBase): self.add_rtio(rtio_channels) +class Master(MiniSoC, AMPSoC): + mem_map = { + "cri_con": 0x10000000, + "rtio": 0x20000000, + "rtio_dma": 0x30000000, + "drtio_aux": 0x50000000, + "mailbox": 0x70000000 + } + mem_map.update(MiniSoC.mem_map) + + def __init__(self, **kwargs): + MiniSoC.__init__(self, + cpu_type="or1k", + sdram_controller_type="minicon", + l2_size=128*1024, + ident=artiq_version, + ethmac_nrxslots=4, + ethmac_ntxslots=4, + **kwargs) + AMPSoC.__init__(self) + + platform = self.platform + rtio_clk_freq = 150e6 + + i2c = self.platform.request("i2c") + self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) + self.csr_devices.append("i2c") + self.config["I2C_BUS_COUNT"] = 1 + self.config["HAS_SI5324"] = None + self.config["SI5324_SOFT_RESET"] = None + self.config["SI5324_FREE_RUNNING"] = None + + self.comb += platform.request("sfp_ctl", 1).tx_disable.eq(0) + self.submodules.transceiver = gtp_7series.GTP( + qpll_channel=self.drtio_qpll_channel, + data_pads=[platform.request("sfp", 1)], + sys_clk_freq=self.clk_freq, + rtio_clk_freq=rtio_clk_freq) + + self.submodules.drtio0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"})( + DRTIOMaster(self.transceiver.channels[0])) + self.csr_devices.append("drtio0") + self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, + self.drtio0.aux_controller.bus) + self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) + self.config["HAS_DRTIO"] = None + self.add_csr_group("drtio", ["drtio0"]) + self.add_memory_group("drtio_aux", ["drtio0_aux"]) + + rtio_clk_period = 1e9/rtio_clk_freq + for gtp in self.transceiver.gtps: + platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) + platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, + gtp.txoutclk, gtp.rxoutclk) + + rtio_channels = [] + phy = ttl_simple.Output(platform.request("user_led", 0)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + phy = ttl_simple.Output(platform.request("sfp_ctl", 2).led) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) + self.csr_devices.append("rtio_moninj") + + self.submodules.rtio_core = rtio.Core(rtio_channels, glbl_fine_ts_width=3) + self.csr_devices.append("rtio_core") + + self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( + rtio.DMA(self.get_native_sdram_if())) + self.register_kernel_cpu_csrdevice("rtio") + self.register_kernel_cpu_csrdevice("rtio_dma") + self.submodules.cri_con = rtio.CRIInterconnectShared( + [self.rtio.cri, self.rtio_dma.cri], + [self.rtio_core.cri, self.drtio0.cri]) + self.register_kernel_cpu_csrdevice("cri_con") + + # Never running out of stupid features, GTs on A7 make you pack + # unrelated transceiver PLLs into one GTPE2_COMMON yourself. + def create_qpll(self): + si5324_clkout = self.platform.request("si5324_clkout") + si5324_clkout_buf = Signal() + self.specials += Instance("IBUFDS_GTE2", + i_CEB=0, + i_I=si5324_clkout.p, i_IB=si5324_clkout.n, + o_O=si5324_clkout_buf) + qpll_eth_settings = QPLLSettings( + refclksel=0b001, + fbdiv=4, + fbdiv_45=5, + refclk_div=1) + qpll_drtio_settings = QPLLSettings( + refclksel=0b010, + fbdiv=4, + fbdiv_45=5, + refclk_div=1) + qpll = QPLL(self.crg.clk125_buf, qpll_eth_settings, + si5324_clkout_buf, qpll_drtio_settings) + self.ethphy_qpll_channel, self.drtio_qpll_channel = qpll.channels + + +class Satellite(BaseSoC): + mem_map = { + "drtio_aux": 0x50000000, + } + mem_map.update(BaseSoC.mem_map) + + def __init__(self, **kwargs): + BaseSoC.__init__(self, + cpu_type="or1k", + sdram_controller_type="minicon", + l2_size=128*1024, + ident=artiq_version, + **kwargs) + + platform = self.platform + rtio_clk_freq = 150e6 + + rtio_channels = [] + phy = ttl_simple.Output(platform.request("user_led", 0)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + phy = ttl_simple.Output(platform.request("sfp_ctl", 2).led) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) + self.csr_devices.append("rtio_moninj") + + si5324_clkout = platform.request("si5324_clkout") + si5324_clkout_buf = Signal() + self.specials += Instance("IBUFDS_GTE2", + i_CEB=0, + i_I=si5324_clkout.p, i_IB=si5324_clkout.n, + o_O=si5324_clkout_buf) + qpll_drtio_settings = QPLLSettings( + refclksel=0b010, + fbdiv=4, + fbdiv_45=5, + refclk_div=1) + qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings) + + self.comb += platform.request("sfp_ctl", 0).tx_disable.eq(0) + self.submodules.transceiver = gtp_7series.GTP( + qpll_channel=qpll.channels[0], + data_pads=[platform.request("sfp", 0)], + sys_clk_freq=self.clk_freq, + rtio_clk_freq=rtio_clk_freq) + rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) + self.submodules.drtio0 = rx0(DRTIOSatellite( + self.transceiver.channels[0], rtio_channels)) + self.csr_devices.append("drtio0") + self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, + self.drtio0.aux_controller.bus) + self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) + self.config["HAS_DRTIO"] = None + self.add_csr_group("drtio", ["drtio0"]) + self.add_memory_group("drtio_aux", ["drtio0_aux"]) + + self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) + si5324_clkin = platform.request("si5324_clkin") + self.specials += \ + Instance("OBUFDS", + i_I=ClockSignal("rtio_rx0"), + o_O=si5324_clkin.p, o_OB=si5324_clkin.n + ) + i2c = self.platform.request("i2c") + self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) + self.csr_devices.append("i2c") + self.config["I2C_BUS_COUNT"] = 1 + self.config["HAS_SI5324"] = None + self.config["SI5324_SOFT_RESET"] = None + + rtio_clk_period = 1e9/rtio_clk_freq + gtp = self.transceiver.gtps[0] + platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) + platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, + gtp.txoutclk, gtp.rxoutclk) + + def main(): parser = argparse.ArgumentParser( description="ARTIQ device binary builder for Kasli systems") builder_args(parser) soc_kasli_args(parser) parser.add_argument("-V", "--variant", default="opticlock", - help="variant: opticlock " + help="variant: opticlock/master/satellite " "(default: %(default)s)") args = parser.parse_args() variant = args.variant.lower() if variant == "opticlock": cls = Opticlock + elif variant == "master": + cls = Master + elif variant == "satellite": + cls = Satellite else: - raise SystemExit("Invalid hardware adapter string (--variant)") + raise SystemExit("Invalid variant (-V/--variant)") soc = cls(**soc_kasli_argdict(args)) build_artiq_soc(soc, builder_argdict(args)) From 401e57d41ce99a7dbed42b755e80c6a50cb5abc0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 01:28:01 +0800 Subject: [PATCH 0252/2457] gtp_7series: fix nchannels assert --- artiq/gateware/drtio/transceiver/gtp_7series.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py index 92db40162..797c256bb 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -218,7 +218,7 @@ class GTP(Module, TransceiverInterface): def __init__(self, qpll_channel, data_pads, sys_clk_freq, rtio_clk_freq, master=0): self.nchannels = nchannels = len(data_pads) self.gtps = [] - if nchannels >= 1: + if nchannels > 1: raise NotImplementedError # # # From 0d734013653985d4d5213694135214d30d490f0a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 01:28:10 +0800 Subject: [PATCH 0253/2457] conda: bump migen+misoc --- conda/artiq-dev/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 290070c5e..1a2dfb240 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,8 +14,8 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.6 py35_2+git61a055f - - misoc 0.8 py35_17+gitb1c66d03 + - migen 0.6 py35_6+gita4df9c7 + - misoc 0.8 py35_48+git45f957ab - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From ca1fdaa190f2670743134cdef9c762848c3552a1 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 22 Jan 2018 08:12:59 +0000 Subject: [PATCH 0254/2457] ad9910: relax timing for faster spi clock --- artiq/coredevice/ad9910.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index c3263acce..30628af4c 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -99,15 +99,15 @@ class AD9910: aux_dac = self.read32(_AD9910_REG_AUX_DAC) if aux_dac & 0xff != 0x7f: raise ValueError("Urukul AD9910 AUX_DAC mismatch") - delay(10*us) + delay(100*us) self.write32(_AD9910_REG_CFR2, 0x01400020) cfr3 = (0x0807c100 | (self.pll_vco << 24) | (self.pll_cp << 19) | (self.pll_n << 1)) self.write32(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset - delay(10*us) + delay(100*us) self.cpld.io_update.pulse(100*ns) self.write32(_AD9910_REG_CFR3, cfr3) - delay(10*us) + delay(100*us) self.cpld.io_update.pulse(100*ns) for i in range(100): lock = urukul_sta_pll_lock(self.cpld.sta_read()) From 5a9035b122a01c378c266ee244f5fde5ea132fb3 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 22 Jan 2018 08:13:27 +0000 Subject: [PATCH 0255/2457] urukul: faster spi clock --- artiq/coredevice/urukul.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index c905d7441..e4b29be21 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -15,7 +15,7 @@ _SPIT_CFG_WR = 2 _SPIT_CFG_RD = 16 _SPIT_ATT_WR = 2 _SPIT_ATT_RD = 16 -_SPIT_DDS_WR = 16 +_SPIT_DDS_WR = 3 _SPIT_DDS_RD = 16 # CFG configuration register bit offsets From a86b28def2cc0339d497dbb63ff7086017938c29 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 22 Jan 2018 08:25:12 +0000 Subject: [PATCH 0256/2457] urukul: example additions * relax timings for faster spi xfers * continuous readback test to explore spi speed limit --- .../coredevice_examples/simple/urukul.py | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/artiq/examples/master/repository/coredevice_examples/simple/urukul.py b/artiq/examples/master/repository/coredevice_examples/simple/urukul.py index 42454b36b..f56da2123 100644 --- a/artiq/examples/master/repository/coredevice_examples/simple/urukul.py +++ b/artiq/examples/master/repository/coredevice_examples/simple/urukul.py @@ -34,28 +34,42 @@ class UrukulTest(EnvExperiment): self.urukul_ch2b.init() self.urukul_ch3b.init() - delay(100*us) + delay(1000*us) self.urukul_ch0b.set(100*MHz) self.urukul_ch0b.sw.on() self.urukul_ch0b.set_att(10.) - delay(100*us) + delay(1000*us) self.urukul_ch1b.set(10*MHz, 0.5) self.urukul_ch1b.sw.on() self.urukul_ch1b.set_att(0.) - delay(100*us) + delay(1000*us) self.urukul_ch2b.set(400*MHz) self.urukul_ch2b.sw.on() self.urukul_ch2b.set_att(0.) - delay(100*us) + delay(1000*us) self.urukul_ch3b.set(1*MHz) self.urukul_ch3b.sw.on() self.urukul_ch3b.set_att(20.) + i = 0 + j = 0 while True: - self.urukul_ch0b.set_mu(0x12345678, 0, 0x3fff) + delay(13*us) + self.urukul_ch0b.write32(0x07, i) + self.urukul_cpld.io_update.pulse(10*ns) + k = self.urukul_ch0b.read32(0x07) + delay(100*us) + if k != i: + #print(i) + #print(k) + #if j > 20: + # return + j += 1 + #delay(20*ms) + i += 1 while True: self.urukul_ch0b.sw.pulse(5*ms) From 74b7baa8c5080193b4035defbf09d70b40187f91 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 22 Jan 2018 18:27:37 +0000 Subject: [PATCH 0257/2457] urukul example: mmcx clock input --- .../master/repository/coredevice_examples/simple/urukul.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/master/repository/coredevice_examples/simple/urukul.py b/artiq/examples/master/repository/coredevice_examples/simple/urukul.py index f56da2123..ea85597f9 100644 --- a/artiq/examples/master/repository/coredevice_examples/simple/urukul.py +++ b/artiq/examples/master/repository/coredevice_examples/simple/urukul.py @@ -28,7 +28,7 @@ class UrukulTest(EnvExperiment): self.fmcdio_dirctl.set(0x0A008800) self.led.off() - self.urukul_cpld.init(clk_sel=1) + self.urukul_cpld.init(clk_sel=0) self.urukul_ch0b.init() self.urukul_ch1b.init() self.urukul_ch2b.init() From 472840f16bb1275a96f495800646a0d3e6bbf6c6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 22 Jan 2018 20:32:18 +0100 Subject: [PATCH 0258/2457] conda: bump migen/misoc * kasli clock constraint * vivado false paths --- conda/artiq-dev/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 1a2dfb240..9a6eb79cb 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,8 +14,8 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.6 py35_6+gita4df9c7 - - misoc 0.8 py35_48+git45f957ab + - migen 0.6 py35_9+git4246d18 + - misoc 0.8 py35_49+git9c343e1c - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From 626075cbc1dbf8d24ee451404955ebce93d1f8b9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 09:49:23 +0800 Subject: [PATCH 0259/2457] gtp_7series: simplify TX clocking --- artiq/gateware/drtio/transceiver/gtp_7series.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py index 797c256bb..7493343be 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -175,16 +175,7 @@ class GTPSingle(Module): self.sync += tx_reset_deglitched.eq(~tx_init.done) self.clock_domains.cd_rtio_tx = ClockDomain() if mode == "master": - txoutclk_bufg = Signal() - txoutclk_bufr = Signal() - tx_bufr_div = 150.e6/rtio_clk_freq - assert tx_bufr_div == int(tx_bufr_div) - self.specials += [ - Instance("BUFG", i_I=self.txoutclk, o_O=txoutclk_bufg), - Instance("BUFR", i_I=txoutclk_bufg, o_O=txoutclk_bufr, - i_CE=1, p_BUFR_DIVIDE=str(int(tx_bufr_div))), - Instance("BUFG", i_I=txoutclk_bufr, o_O=self.cd_rtio_tx.clk) - ] + self.specials += Instance("BUFG", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk) self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched) # rx clocking From 031d7ff02009908da03611cfabd551f577ab92f1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 10:13:10 +0800 Subject: [PATCH 0260/2457] kasli: keep using second QPLL channel for DRTIO satellite --- artiq/gateware/targets/kasli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 65e3c3dd6..4aef7e1a7 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -329,11 +329,11 @@ class Satellite(BaseSoC): fbdiv=4, fbdiv_45=5, refclk_div=1) - qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings) + qpll = QPLL(0, None, si5324_clkout_buf, qpll_drtio_settings) self.comb += platform.request("sfp_ctl", 0).tx_disable.eq(0) self.submodules.transceiver = gtp_7series.GTP( - qpll_channel=qpll.channels[0], + qpll_channel=qpll.channels[1], data_pads=[platform.request("sfp", 0)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) From 25fee1a0bb909faec1c123645de5cc7e8e32491a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 10:15:49 +0800 Subject: [PATCH 0261/2457] gtp_7series: use QPLL second channel --- artiq/gateware/drtio/transceiver/gtp_7series.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py index 7493343be..f0fa8ed80 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -77,9 +77,9 @@ class GTPSingle(Module): p_PD_TRANS_TIME_NONE_P2=0x3c, p_PD_TRANS_TIME_TO_P2=0x64, - # QPLL - i_PLL0CLK=qpll_channel.clk, - i_PLL0REFCLK=qpll_channel.refclk, + # QPLL - must use channel 1! + i_PLL1CLK=qpll_channel.clk, + i_PLL1REFCLK=qpll_channel.refclk, # TX clock p_TXBUF_EN="FALSE", From 98a5607634735f19763db4ff31ae252de93d1c94 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 10:39:20 +0800 Subject: [PATCH 0262/2457] gtp_7series: set clock muxes correctly for second QPLL channel --- artiq/gateware/drtio/transceiver/gtp_7series.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py index f0fa8ed80..796fa77b0 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -86,7 +86,7 @@ class GTPSingle(Module): p_TX_XCLK_SEL="TXUSR", o_TXOUTCLK=self.txoutclk, p_TXOUT_DIV=2, - i_TXSYSCLKSEL=0b00, + i_TXSYSCLKSEL=0b11, i_TXOUTCLKSEL=0b11, # TX Startup/Reset @@ -136,7 +136,7 @@ class GTPSingle(Module): p_TX_CLK25_DIV=5, p_RX_XCLK_SEL="RXUSR", p_RXOUT_DIV=2, - i_RXSYSCLKSEL=0b00, + i_RXSYSCLKSEL=0b11, i_RXOUTCLKSEL=0b010, o_RXOUTCLK=self.rxoutclk, i_RXUSRCLK=ClockSignal("rtio_rx"), From 9f87c34a9434415e8a59004ff00ba5d0ecba6a9a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 10:39:31 +0800 Subject: [PATCH 0263/2457] kasli: fix QPLL instantiation --- artiq/gateware/targets/kasli.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 4aef7e1a7..df0c9fd0b 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -287,6 +287,7 @@ class Master(MiniSoC, AMPSoC): refclk_div=1) qpll = QPLL(self.crg.clk125_buf, qpll_eth_settings, si5324_clkout_buf, qpll_drtio_settings) + self.submodules += qpll self.ethphy_qpll_channel, self.drtio_qpll_channel = qpll.channels @@ -330,6 +331,7 @@ class Satellite(BaseSoC): fbdiv_45=5, refclk_div=1) qpll = QPLL(0, None, si5324_clkout_buf, qpll_drtio_settings) + self.submodules += qpll self.comb += platform.request("sfp_ctl", 0).tx_disable.eq(0) self.submodules.transceiver = gtp_7series.GTP( From d6157514c7f81db0663520f16b7fb0b427db7164 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 12:03:09 +0800 Subject: [PATCH 0264/2457] gtp_7series: flexible QPLL channel selection --- .../gateware/drtio/transceiver/gtp_7series.py | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py index 796fa77b0..470c3e7ba 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -43,8 +43,7 @@ class GTPSingle(Module): txdata = Signal(20) rxdata = Signal(20) rxphaligndone = Signal() - self.specials += \ - Instance("GTPE2_CHANNEL", + gtp_params = dict( # Reset modes i_GTRESETSEL=0, i_RESETOVRD=0, @@ -77,16 +76,11 @@ class GTPSingle(Module): p_PD_TRANS_TIME_NONE_P2=0x3c, p_PD_TRANS_TIME_TO_P2=0x64, - # QPLL - must use channel 1! - i_PLL1CLK=qpll_channel.clk, - i_PLL1REFCLK=qpll_channel.refclk, - # TX clock p_TXBUF_EN="FALSE", p_TX_XCLK_SEL="TXUSR", o_TXOUTCLK=self.txoutclk, p_TXOUT_DIV=2, - i_TXSYSCLKSEL=0b11, i_TXOUTCLKSEL=0b11, # TX Startup/Reset @@ -136,7 +130,6 @@ class GTPSingle(Module): p_TX_CLK25_DIV=5, p_RX_XCLK_SEL="RXUSR", p_RXOUT_DIV=2, - i_RXSYSCLKSEL=0b11, i_RXOUTCLKSEL=0b010, o_RXOUTCLK=self.rxoutclk, i_RXUSRCLK=ClockSignal("rtio_rx"), @@ -168,6 +161,27 @@ class GTPSingle(Module): o_GTPTXP=pads.txp, o_GTPTXN=pads.txn ) + if qpll_channel.index == 0: + gtp_params.update( + i_RXSYSCLKSEL=0b00, + i_TXSYSCLKSEL=0b00, + i_PLL0CLK=qpll_channel.clk, + i_PLL0REFCLK=qpll_channel.refclk, + i_PLL1CLK=0, + i_PLL1REFCLK=0, + ) + elif qpll_channel.index == 1: + gtp_params.update( + i_RXSYSCLKSEL=0b11, + i_TXSYSCLKSEL=0b11, + i_PLL0CLK=0, + i_PLL0REFCLK=0, + i_PLL1CLK=qpll_channel.clk, + i_PLL1REFCLK=qpll_channel.refclk, + ) + else: + raise ValueError + self.specials += Instance("GTPE2_CHANNEL", **gtp_params) # tx clocking tx_reset_deglitched = Signal() From c7b148a7046b05c0f1e4f93f1483a20131df6de2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 12:04:11 +0800 Subject: [PATCH 0265/2457] kasli: when using both GTP clocks, send REFCLK0 to PLL0 and REFCLK1 to PLL1 --- artiq/gateware/targets/kasli.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index df0c9fd0b..fac734017 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -275,20 +275,24 @@ class Master(MiniSoC, AMPSoC): i_CEB=0, i_I=si5324_clkout.p, i_IB=si5324_clkout.n, o_O=si5324_clkout_buf) - qpll_eth_settings = QPLLSettings( + # Note precisely the rules Xilinx made up: + # refclksel=0b001 GTREFCLK0 selected + # refclksel=0b010 GTREFCLK1 selected + # but if only one clock used, then it must be 001. + qpll_drtio_settings = QPLLSettings( refclksel=0b001, fbdiv=4, fbdiv_45=5, refclk_div=1) - qpll_drtio_settings = QPLLSettings( + qpll_eth_settings = QPLLSettings( refclksel=0b010, fbdiv=4, fbdiv_45=5, refclk_div=1) - qpll = QPLL(self.crg.clk125_buf, qpll_eth_settings, - si5324_clkout_buf, qpll_drtio_settings) + qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings + self.crg.clk125_buf, qpll_eth_settings) self.submodules += qpll - self.ethphy_qpll_channel, self.drtio_qpll_channel = qpll.channels + self.drtio_qpll_channel, self.ethphy_qpll_channel = qpll.channels class Satellite(BaseSoC): @@ -330,12 +334,12 @@ class Satellite(BaseSoC): fbdiv=4, fbdiv_45=5, refclk_div=1) - qpll = QPLL(0, None, si5324_clkout_buf, qpll_drtio_settings) + qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings) self.submodules += qpll self.comb += platform.request("sfp_ctl", 0).tx_disable.eq(0) self.submodules.transceiver = gtp_7series.GTP( - qpll_channel=qpll.channels[1], + qpll_channel=qpll.channels[0], data_pads=[platform.request("sfp", 0)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) From 763aefacff94e33e7e3be4c3fd8238c018a71c7e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 12:10:54 +0800 Subject: [PATCH 0266/2457] kasli: fix typo --- artiq/gateware/targets/kasli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index fac734017..f9164bba1 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -289,7 +289,7 @@ class Master(MiniSoC, AMPSoC): fbdiv=4, fbdiv_45=5, refclk_div=1) - qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings + qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings, self.crg.clk125_buf, qpll_eth_settings) self.submodules += qpll self.drtio_qpll_channel, self.ethphy_qpll_channel = qpll.channels From 4b4374f76a77cb8d90ca52e7c8cdafc139f559a0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 12:19:15 +0800 Subject: [PATCH 0267/2457] sayma: register_jref for JESD204. Closes #904 --- artiq/gateware/targets/sayma_amc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index e4cbef55c..dbffbdf16 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -98,7 +98,7 @@ class AD9154JESD(Module, AutoCSR): phys, settings, converter_data_width=64)) self.submodules.control = control = to_jesd(JESD204BCoreTXControl(core)) core.register_jsync(platform.request("dac_sync", dac)) - #core.register_jref(jesd_crg.jref) # FIXME: uncomment on next jesd204b update + core.register_jref(jesd_crg.jref) class AD9154(Module, AutoCSR): From 649deccd9b0531d3e217b8540632e16aba3c163b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 12:27:19 +0800 Subject: [PATCH 0268/2457] kasli: fix DRTIO satellite QPLL refclksel --- artiq/gateware/targets/kasli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index f9164bba1..46707ef12 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -330,7 +330,7 @@ class Satellite(BaseSoC): i_I=si5324_clkout.p, i_IB=si5324_clkout.n, o_O=si5324_clkout_buf) qpll_drtio_settings = QPLLSettings( - refclksel=0b010, + refclksel=0b001, fbdiv=4, fbdiv_45=5, refclk_div=1) From cfffd9e13d7d9a33817edfbb4a6274da9d6b139f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 13:16:34 +0800 Subject: [PATCH 0269/2457] si5324: kasli support --- artiq/firmware/libboard_artiq/si5324.rs | 49 +++++++++++++++++-------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 574e1ba53..147cb2302 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -1,5 +1,7 @@ use core::result; -use board::{csr, clock}; +use board::clock; +#[cfg(not(si5324_soft_reset))] +use board::csr; use i2c; type Result = result::Result; @@ -7,23 +9,27 @@ type Result = result::Result; const BUSNO: u8 = 0; const ADDRESS: u8 = 0x68; -#[cfg(any(soc_platform = "sayma_amc", soc_platform = "kc705"))] -fn pca9548_select(address: u8, channel: u8) -> Result<()> { +#[cfg(any(soc_platform = "kasli", + soc_platform = "sayma_amc", + soc_platform = "kc705"))] +fn pca9548_select(address: u8, channels: u8) -> Result<()> { i2c::start(BUSNO).unwrap(); if !i2c::write(BUSNO, (address << 1)).unwrap() { return Err("PCA9548 failed to ack write address") } - if !i2c::write(BUSNO, 1 << channel).unwrap() { + if !i2c::write(BUSNO, channels).unwrap() { return Err("PCA9548 failed to ack control word") } i2c::stop(BUSNO).unwrap(); Ok(()) } -fn reset(en: bool) { - unsafe { - csr::si5324_rst_n::out_write(if en { 0 } else { 1 }) - } +#[cfg(not(si5324_soft_reset))] +fn hard_reset() { + unsafe { csr::si5324_rst_n::out_write(0); } + clock::spin_us(1_000); + unsafe { csr::si5324_rst_n::out_write(1); } + clock::spin_us(10_000); } // NOTE: the logical parameters DO NOT MAP to physical values written @@ -127,6 +133,13 @@ fn ident() -> Result { Ok(((read(134)? as u16) << 8) | (read(135)? as u16)) } +#[cfg(si5324_soft_reset)] +fn soft_reset() -> Result<()> { + write(136, read(136)? | 0x80)?; + clock::spin_us(10_000); + Ok(()) +} + fn has_xtal() -> Result { Ok((read(129)? & 0x01) == 0) // LOSX_INT=0 } @@ -154,20 +167,26 @@ fn monitor_lock() -> Result<()> { pub fn setup(settings: &FrequencySettings) -> Result<()> { let s = map_frequency_settings(settings)?; - reset(true); - clock::spin_us(1_000); - reset(false); - clock::spin_us(10_000); + #[cfg(not(si5324_soft_reset))] + hard_reset(); - #[cfg(soc_platform = "kc705")] - pca9548_select(0x74, 7)?; + #[cfg(soc_platform = "kasli")] + { + pca9548_select(0x70, 0)?; + pca9548_select(0x71, 1 << 3)?; + } #[cfg(soc_platform = "sayma_amc")] - pca9548_select(0x70, 4)?; + pca9548_select(0x70, 1 << 4)?; + #[cfg(soc_platform = "kc705")] + pca9548_select(0x74, 1 << 7)?; if ident()? != 0x0182 { return Err("Si5324 does not have expected product number"); } + #[cfg(si5324_soft_reset)] + soft_reset()?; + write(0, read(0)? | 0x40)?; // FREE_RUN=1 write(2, (read(2)? & 0x0f) | (s.bwsel << 4))?; write(21, read(21)? & 0xfe)?; // CKSEL_PIN=0 From cb0016ceeeaa0e376a9b13ab5d2ea7ba7495100b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 23 Jan 2018 15:26:01 +0800 Subject: [PATCH 0270/2457] examples/sayma: fix ref_multiplier SAWG is working, whoohoo! --- artiq/examples/sayma/device_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/sayma/device_db.py b/artiq/examples/sayma/device_db.py index 01ef43913..f603f6e13 100644 --- a/artiq/examples/sayma/device_db.py +++ b/artiq/examples/sayma/device_db.py @@ -5,7 +5,7 @@ device_db = { "type": "local", "module": "artiq.coredevice.core", "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1/(150e6)} + "arguments": {"host": core_addr, "ref_period": 1/150e6, "ref_multiplier": 1} }, "core_log": { "type": "controller", From 7d1b3f37c92e69e2007d0292f58bca723c5ca317 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 23 Jan 2018 10:56:42 +0000 Subject: [PATCH 0271/2457] sayma_rtm: set CFGBVS/CONFIG_VOLTAGE, compress --- artiq/gateware/targets/sayma_rtm.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 979decaa3..3dbaf51c4 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -72,6 +72,12 @@ CSR_RANGE_SIZE = 0x800 class SaymaRTM(Module): def __init__(self, platform): + platform.toolchain.bitstream_commands.extend([ + "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]", + "set_property CFGBVS VCCO [current_design]", + "set_property CONFIG_VOLTAGE 3.3 [current_design]", + ]) + csr_devices = [] self.submodules.crg = CRG(platform) From 85102e191e582803e0f29aed60a4685694be1414 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 23 Jan 2018 11:00:55 +0000 Subject: [PATCH 0272/2457] sayma_rtm: derive clocks automatically * also don't add false paths unless necessary --- artiq/gateware/targets/sayma_rtm.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 3dbaf51c4..bbd8fb589 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -81,13 +81,7 @@ class SaymaRTM(Module): csr_devices = [] self.submodules.crg = CRG(platform) - self.crg.cd_sys.clk.attr.add("keep") clk_freq = 125e6 - platform.add_period_constraint(self.crg.cd_sys.clk, 8.0) - platform.add_period_constraint(self.crg.cd_clk200.clk, 5.0) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - self.crg.cd_clk200.clk) self.submodules.rtm_identifier = RTMIdentifier() csr_devices.append("rtm_identifier") From aada38f508059b33a1cebb35e3910339c5716ef7 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 23 Jan 2018 13:15:26 +0000 Subject: [PATCH 0273/2457] kasli, kc705: remove vivado "keep", cleanup a constraint --- artiq/gateware/targets/kasli.py | 1 - artiq/gateware/targets/kc705.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 46707ef12..37ded5d66 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -121,7 +121,6 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.rtio_crg.cd_rtio.clk.attr.add("keep") self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.) self.platform.add_false_path_constraints( self.crg.cd_sys.clk, diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index a74facd4b..771bdb4bf 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -32,6 +32,7 @@ class _RTIOCRG(Module, AutoCSR): # 100 MHz when using 125MHz input self.clock_domains.cd_ext_clkout = ClockDomain(reset_less=True) + platform.add_period_constraint(self.cd_ext_clkout.clk, 5.0) if use_sma: ext_clkout = platform.request("user_sma_gpio_p_33") self.sync.ext_clkout += ext_clkout.eq(~ext_clkout) @@ -265,7 +266,6 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.rtio_crg.cd_rtio.clk.attr.add("keep") self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.) self.platform.add_false_path_constraints( self.crg.cd_sys.clk, @@ -511,7 +511,6 @@ class SMA_SPI(_StandaloneBase): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.rtio_crg.cd_rtio.clk.attr.add("keep") self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.) self.platform.add_false_path_constraints( self.crg.cd_sys.clk, From b5c035bb5207affae54d4e24168790933ab0e9ce Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 23 Jan 2018 13:54:53 +0000 Subject: [PATCH 0274/2457] sayma_rtm: constrain serwb clock input --- artiq/gateware/targets/sayma_rtm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index bbd8fb589..6f7c9ee1c 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -148,6 +148,7 @@ class SaymaRTM(Module): self.submodules += serwb_pll serwb_pads = platform.request("amc_rtm_serwb") + platform.add_period_constraint(serwb_pads.clk_p, 16.) serwb_phy_rtm = serwb.phy.SERWBPHY(platform.device, serwb_pll, serwb_pads, mode="slave") self.submodules.serwb_phy_rtm = serwb_phy_rtm self.comb += self.crg.reset.eq(serwb_phy_rtm.init.reset) From ee14912042f55af781d74520f3f311c761f24363 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 23 Jan 2018 16:23:12 +0100 Subject: [PATCH 0275/2457] conda: bump migen/misoc (vivado constraints) --- conda/artiq-dev/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 9a6eb79cb..7f469378f 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,8 +14,8 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.6 py35_9+git4246d18 - - misoc 0.8 py35_49+git9c343e1c + - migen 0.6 py35_11+git78a671d + - misoc 0.8 py35_53+gite01cf4ce - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From e0e795f11ca1448cd60684b1c612547585df5201 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 23 Jan 2018 15:42:14 +0000 Subject: [PATCH 0276/2457] sayma_amc: constrain pin, remove keep --- artiq/gateware/targets/sayma_amc.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index dbffbdf16..43307c2f9 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -55,6 +55,7 @@ class AD9154CRG(Module, AutoCSR): self.clock_domains.cd_jesd = ClockDomain() refclk_pads = platform.request("dac_refclk", 0) + platform.add_period_constraint(refclk_pads.p, 1e9/self.refclk_freq) self.specials += [ Instance("IBUFDS_GTE3", i_CEB=0, p_REFCLK_HROW_CK_SEL=0b00, i_I=refclk_pads.p, i_IB=refclk_pads.n, @@ -62,8 +63,6 @@ class AD9154CRG(Module, AutoCSR): Instance("BUFG_GT", i_I=refclk2, o_O=self.cd_jesd.clk), AsyncResetSynchronizer(self.cd_jesd, self.jreset.storage), ] - self.cd_jesd.clk.attr.add("keep") - platform.add_period_constraint(self.cd_jesd.clk, 1e9/self.refclk_freq) jref = platform.request("dac_sysref") self.specials += DifferentialInput(jref.p, jref.n, self.jref) @@ -85,7 +84,6 @@ class AD9154JESD(Module, AutoCSR): phy = JESD204BPhyTX( cpll, PhyPads(jesd_pads.txp[i], jesd_pads.txn[i]), jesd_crg.fabric_freq, transceiver="gth") - phy.transmitter.cd_tx.clk.attr.add("keep") platform.add_period_constraint(phy.transmitter.cd_tx.clk, 40*1e9/jesd_crg.linerate) platform.add_false_path_constraints( From ed0fbd566219b7c17b0573ed2ce10ca728a424c9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 24 Jan 2018 00:28:39 +0800 Subject: [PATCH 0277/2457] test: add test for RTIO counter (#883) --- artiq/test/coredevice/test_rtio.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 13517084a..6393d1840 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -18,6 +18,17 @@ artiq_low_latency = os.getenv("ARTIQ_LOW_LATENCY") artiq_in_devel = os.getenv("ARTIQ_IN_DEVEL") +class RTIOCounter(EnvExperiment): + def build(self): + self.setattr_device("core") + + @kernel + def run(self): + t0 = self.core.get_rtio_counter_mu() + t1 = self.core.get_rtio_counter_mu() + self.set_dataset("dt", self.core.mu_to_seconds(t1 - t0)) + + class PulseNotReceived(Exception): pass @@ -357,6 +368,12 @@ class HandoverException(EnvExperiment): class CoredeviceTest(ExperimentCase): + def test_rtio_counter(self): + self.execute(RTIOCounter) + dt = self.dataset_mgr.get("dt") + self.assertGreater(dt, 50*ns) + self.assertLess(dt, 200*ns) + def test_loopback(self): self.execute(Loopback) rtt = self.dataset_mgr.get("rtt") From 77f90cf93bef711c37fad9c3e46c5ab81d1742a9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 24 Jan 2018 10:07:22 +0800 Subject: [PATCH 0278/2457] test: relax RTIO counter test and print result --- artiq/test/coredevice/test_rtio.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 6393d1840..371c5eb18 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -371,8 +371,9 @@ class CoredeviceTest(ExperimentCase): def test_rtio_counter(self): self.execute(RTIOCounter) dt = self.dataset_mgr.get("dt") + print(dt) self.assertGreater(dt, 50*ns) - self.assertLess(dt, 200*ns) + self.assertLess(dt, 1*us) def test_loopback(self): self.execute(Loopback) From ca4d5ae73e6082b8e3778a9c6437315c2d15e0dc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 25 Jan 2018 00:00:07 +0800 Subject: [PATCH 0279/2457] artiq_flash: add kasli drtio variants --- artiq/frontend/artiq_flash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 7e1477af5..328f3ac7f 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -235,7 +235,7 @@ def main(): }, "kasli": { "programmer": partial(ProgrammerXC7, board="kasli", proxy="bscan_spi_xc7a100t.bit"), - "variants": ["opticlock"], + "variants": ["opticlock", "master", "satellite"], "gateware": ("spi0", 0x000000), "bootloader": ("spi0", 0x400000), "storage": ("spi0", 0x440000), From 0d2f89db5366ff52f618d9fe1789a6242359a99c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 25 Jan 2018 11:06:19 +0800 Subject: [PATCH 0280/2457] si5324: chip does not ack RST_REG write --- artiq/firmware/libboard_artiq/si5324.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 147cb2302..69ed734db 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -112,6 +112,20 @@ fn write(reg: u8, val: u8) -> Result<()> { Ok(()) } +#[cfg(si5324_soft_reset)] +fn write_no_ack_value(reg: u8, val: u8) -> Result<()> { + i2c::start(BUSNO).unwrap(); + if !i2c::write(BUSNO, (ADDRESS << 1)).unwrap() { + return Err("Si5324 failed to ack write address") + } + if !i2c::write(BUSNO, reg).unwrap() { + return Err("Si5324 failed to ack register") + } + i2c::write(BUSNO, val).unwrap(); + i2c::stop(BUSNO).unwrap(); + Ok(()) +} + fn read(reg: u8) -> Result { i2c::start(BUSNO).unwrap(); if !i2c::write(BUSNO, (ADDRESS << 1)).unwrap() { @@ -135,7 +149,7 @@ fn ident() -> Result { #[cfg(si5324_soft_reset)] fn soft_reset() -> Result<()> { - write(136, read(136)? | 0x80)?; + write_no_ack_value(136, read(136)? | 0x80)?; clock::spin_us(10_000); Ok(()) } From c9b36e355997fe3b0ce294e6c4d77f14a00a9394 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 25 Jan 2018 19:31:26 +0100 Subject: [PATCH 0281/2457] conda: bump misoc, close #905 --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 7f469378f..aea27db84 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6 py35_11+git78a671d - - misoc 0.8 py35_53+gite01cf4ce + - misoc 0.8 py35_54+gitcb8e314c - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From 440e19b8f9c8ebfce80402a519796cee7fdd6b06 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 26 Jan 2018 19:02:54 +0800 Subject: [PATCH 0282/2457] kasli: use SFP2 for DRTIO mastering SFP1 PCB routing has some issues. Also use SFP1 LED for DRTIO in both master and satellite. --- artiq/gateware/targets/kasli.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 37ded5d66..3326ebd1d 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -216,10 +216,10 @@ class Master(MiniSoC, AMPSoC): self.config["SI5324_SOFT_RESET"] = None self.config["SI5324_FREE_RUNNING"] = None - self.comb += platform.request("sfp_ctl", 1).tx_disable.eq(0) + self.comb += platform.request("sfp_ctl", 2).tx_disable.eq(0) self.submodules.transceiver = gtp_7series.GTP( qpll_channel=self.drtio_qpll_channel, - data_pads=[platform.request("sfp", 1)], + data_pads=[platform.request("sfp", 2)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) @@ -245,7 +245,7 @@ class Master(MiniSoC, AMPSoC): phy = ttl_simple.Output(platform.request("user_led", 0)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - phy = ttl_simple.Output(platform.request("sfp_ctl", 2).led) + phy = ttl_simple.Output(platform.request("sfp_ctl", 1).led) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) @@ -315,7 +315,7 @@ class Satellite(BaseSoC): phy = ttl_simple.Output(platform.request("user_led", 0)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - phy = ttl_simple.Output(platform.request("sfp_ctl", 2).led) + phy = ttl_simple.Output(platform.request("sfp_ctl", 1).led) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From 08101b631dad11cfb9eded6163cbba1ec4464e46 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 26 Jan 2018 13:55:31 +0000 Subject: [PATCH 0283/2457] artiq_devtool: fix typo. --- artiq/frontend/artiq_devtool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index d0283f61e..04b112728 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -157,7 +157,7 @@ def main(): elif action == "clean": logger.info("Cleaning build directory") - shutil.rmtree(build_dir, ignore_errors=True) + shutil.rmtree(build_dir(), ignore_errors=True) elif action == "reset": logger.info("Resetting device") From d58393a1e590d147714cf03c87f7a024b1d124da Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 26 Jan 2018 23:01:24 +0000 Subject: [PATCH 0284/2457] runtime: build with -Cpanic=unwind. This is required for backtraces to function. I'm not sure how it turned out that master had -Cpanic=abort. --- artiq/firmware/runtime/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/Makefile b/artiq/firmware/runtime/Makefile index a98ccc312..5fa6dbdf8 100644 --- a/artiq/firmware/runtime/Makefile +++ b/artiq/firmware/runtime/Makefile @@ -8,7 +8,7 @@ CFLAGS += \ LDFLAGS += \ -L../libunwind -RUSTFLAGS += -Cpanic=abort +RUSTFLAGS += -Cpanic=unwind all:: runtime.bin runtime.fbi From eed2db3a9834a65dee7d2b12c614453888205d3f Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 27 Jan 2018 15:43:27 +0000 Subject: [PATCH 0285/2457] artiq_flash: make the proxy action unnecessary. --- artiq/frontend/artiq_flash.py | 96 ++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 328f3ac7f..4c14d9ef9 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -8,6 +8,7 @@ import shutil import re import atexit from functools import partial +from collections import defaultdict from artiq import __artiq_dir__ as artiq_dir from artiq.tools import verbosity_args, init_logger @@ -62,7 +63,7 @@ Prerequisites: parser.add_argument("--srcbuild", help="look for bitstream, bootloader and firmware in this " "ARTIQ source build tree") parser.add_argument("action", metavar="ACTION", nargs="*", - default="proxy gateware bootloader firmware start".split(), + default="gateware bootloader firmware start".split(), help="actions to perform, default: %(default)s") return parser @@ -104,6 +105,7 @@ class Programmer: self._client = client self._board_script = [] self._preinit_script = preinit_script + self._loaded = defaultdict(lambda: None) self._script = [] def _transfer_script(self, script): @@ -125,6 +127,12 @@ class Programmer: tap=tap, name=name, ir=0x02 + index) def load(self, bitfile, pld): + os.stat(bitfile) # check for existence + + if self._loaded[pld] == bitfile: + return + self._loaded[pld] = bitfile + bitfile = self._client.transfer_file(bitfile) add_commands(self._script, "pld load {pld} {filename}", @@ -134,6 +142,8 @@ class Programmer: raise NotImplementedError def flash_binary(self, bankname, address, filename): + self.load_proxy() + size = os.path.getsize(filename) filename = self._client.transfer_file(filename) add_commands(self._script, @@ -269,10 +279,6 @@ def main(): bin_name += "-" + variant bin_dir = os.path.join(artiq_dir, "binaries", bin_name) - if args.srcbuild is None and not os.path.exists(bin_dir) and args.action != ["start"]: - raise SystemExit("Binaries directory '{}' does not exist" - .format(bin_dir)) - if args.host is None: client = LocalClient() else: @@ -287,50 +293,48 @@ def main(): else: return os.path.join(args.srcbuild, *path_filename) - for action in args.action: - if action == "proxy": - try: - programmer.load_proxy() - except FileNotFoundError as e: - raise SystemExit(e) - elif action == "gateware": - gateware_bin = artifact_path("gateware", "top.bin") - if not os.access(gateware_bin, os.R_OK): - bin_handle, gateware_bin = tempfile.mkstemp() - gateware_bit = artifact_path("gateware", "top.bit") - with open(gateware_bit, "rb") as bit_file, open(bin_handle, "wb") as bin_file: - bit2bin(bit_file, bin_file) - atexit.register(lambda: os.unlink(gateware_bin)) + try: + for action in args.action: + if action == "gateware": + gateware_bin = artifact_path("gateware", "top.bin") + if not os.access(gateware_bin, os.R_OK): + bin_handle, gateware_bin = tempfile.mkstemp() + gateware_bit = artifact_path("gateware", "top.bit") + with open(gateware_bit, "rb") as bit_file, open(bin_handle, "wb") as bin_file: + bit2bin(bit_file, bin_file) + atexit.register(lambda: os.unlink(gateware_bin)) - programmer.flash_binary(*config["gateware"], gateware_bin) - elif action == "bootloader": - bootloader_bin = artifact_path("software", "bootloader", "bootloader.bin") - programmer.flash_binary(*config["bootloader"], bootloader_bin) - elif action == "storage": - storage_img = args.storage - programmer.flash_binary(*config["storage"], storage_img) - elif action == "firmware": - if variant == "satellite": - firmware = "satman" - else: - firmware = "runtime" + programmer.flash_binary(*config["gateware"], gateware_bin) + elif action == "bootloader": + bootloader_bin = artifact_path("software", "bootloader", "bootloader.bin") + programmer.flash_binary(*config["bootloader"], bootloader_bin) + elif action == "storage": + storage_img = args.storage + programmer.flash_binary(*config["storage"], storage_img) + elif action == "firmware": + if variant == "satellite": + firmware = "satman" + else: + firmware = "runtime" - firmware_fbi = artifact_path("software", firmware, firmware + ".fbi") - programmer.flash_binary(*config["firmware"], firmware_fbi) - elif action == "load": - if args.target == "sayma_rtm": - gateware_bit = artifact_path("top.bit") - programmer.load(gateware_bit, 0) - elif args.target == "sayma_amc": - gateware_bit = artifact_path("gateware", "top.bit") - programmer.load(gateware_bit, 1) + firmware_fbi = artifact_path("software", firmware, firmware + ".fbi") + programmer.flash_binary(*config["firmware"], firmware_fbi) + elif action == "load": + if args.target == "sayma_rtm": + gateware_bit = artifact_path("top.bit") + programmer.load(gateware_bit, 0) + elif args.target == "sayma_amc": + gateware_bit = artifact_path("gateware", "top.bit") + programmer.load(gateware_bit, 1) + else: + gateware_bit = artifact_path("gateware", "top.bit") + programmer.load(gateware_bit, 0) + elif action == "start": + programmer.start() else: - gateware_bit = artifact_path("gateware", "top.bit") - programmer.load(gateware_bit, 0) - elif action == "start": - programmer.start() - else: - raise ValueError("invalid action", action) + raise ValueError("invalid action", action) + except FileNotFoundError as e: + raise SystemExit(e) if args.dry_run: print("\n".join(programmer.script())) From 3231d8b235bec3c8c2c8da73cfff8740f61c462a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 28 Jan 2018 00:17:43 +0800 Subject: [PATCH 0286/2457] RELEASE_NOTES: 3.3 --- RELEASE_NOTES.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index f0291cf45..be06ffa75 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -23,6 +23,12 @@ Release notes * the ``-H/--hw-adapter`` option of ``kc705`` has ben renamed ``-V/--variant``. +3.3 +--- + +No further notes. + + 3.2 --- From e8ed3475ea3d3fd38bc093672c56af57b3cdb5f9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 28 Jan 2018 01:00:59 +0800 Subject: [PATCH 0287/2457] test: add kernel overhead test (#407) --- artiq/test/coredevice/test_performance.py | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index 71101d508..6a5e6d647 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -1,4 +1,5 @@ import os +import time import unittest from artiq.experiment import * @@ -52,3 +53,30 @@ class TransferTest(ExperimentCase): device_to_host_rate = exp.device_to_host() print(device_to_host_rate, "B/s") self.assertGreater(device_to_host_rate, 2e6) + + +class _KernelOverhead(EnvExperiment): + def build(self): + self.setattr_device("core") + + def kernel_overhead(self): + n = 100 + t0 = time.monotonic() + for _ in range(n): + self.dummy_kernel() + t1 = time.monotonic() + return (t1-t0)/n + + @kernel + def dummy_kernel(self): + pass + + +class KernelOverheadTest(ExperimentCase): + @unittest.skipUnless(artiq_low_latency, + "timings are dependent on CPU load and network conditions") + def test_kernel_overhead(self): + exp = self.create(_KernelOverhead) + kernel_overhead = exp.kernel_overhead() + print(kernel_overhead, "s") + self.assertLess(kernel_overhead, 0.5) From 67625fe9120b1952f691b3d4e5b632ecf265bf5d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 28 Jan 2018 01:02:03 +0800 Subject: [PATCH 0288/2457] test: check kernel overhead credibility --- artiq/test/coredevice/test_performance.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index 6a5e6d647..e6f70336b 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -79,4 +79,5 @@ class KernelOverheadTest(ExperimentCase): exp = self.create(_KernelOverhead) kernel_overhead = exp.kernel_overhead() print(kernel_overhead, "s") + self.assertGreater(kernel_overhead, 0.001) self.assertLess(kernel_overhead, 0.5) From 6f90a43df28bf439adcf0298fcd008082869384b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 28 Jan 2018 02:11:45 +0800 Subject: [PATCH 0289/2457] examples: reorganize for new hardware --- artiq/examples/kc705/device_db.py | 364 ++++++++++++++++++ .../examples/{master => kc705}/idle_kernel.py | 0 .../simple => kc705/repository}/ad5360.py | 0 .../repository}/blink_forever.py | 0 .../repository/core_pause.py | 0 .../repository}/dds_setter.py | 0 .../simple => kc705/repository}/dds_test.py | 0 .../simple => kc705/repository}/dma_blink.py | 0 .../simple => kc705/repository}/handover.py | 0 .../simple => kc705/repository}/mandelbrot.py | 0 .../repository}/photon_histogram.py | 0 .../repository/speed_benchmark.py | 0 .../repository}/tdr.py | 0 .../simple => kc705/repository}/urukul.py | 0 artiq/examples/master/device_db.py | 28 +- .../{sim => no_hardware}/device_db.py | 23 ++ .../repository}/al_spectroscopy.py | 0 .../repository/arguments_demo.py | 0 .../repository/code_applet.py | 0 .../repository/custom_applet.py | 0 .../repository/flopping_f_simulation.py | 0 .../repository/histograms.py | 0 .../repository/multi_scan.py | 0 .../repository/remote_exec_demo.py | 0 .../repository/remote_exec_processing.py | 0 .../repository/run_forever.py | 0 .../repository}/simple_simulation.py | 0 .../repository}/terminate_all.py | 0 .../repository/thumbnail.py | 0 .../{drtio => sayma_drtio}/device_db.py | 0 .../repository/ad9154_spi.py | 0 .../repository/blink_forever.py | 0 .../repository/pulse_rate.py | 0 .../{sayma => sayma_standalone}/device_db.py | 0 .../repository/blink_led.py | 0 .../repository/demo.py | 0 .../repository/demo_2tone.py | 0 .../repository/test_ad9154_status.py | 0 38 files changed, 390 insertions(+), 25 deletions(-) create mode 100644 artiq/examples/kc705/device_db.py rename artiq/examples/{master => kc705}/idle_kernel.py (100%) rename artiq/examples/{master/repository/coredevice_examples/simple => kc705/repository}/ad5360.py (100%) rename artiq/examples/{master/repository/coredevice_examples/simple => kc705/repository}/blink_forever.py (100%) rename artiq/examples/{master => kc705}/repository/core_pause.py (100%) rename artiq/examples/{master/repository/utilities => kc705/repository}/dds_setter.py (100%) rename artiq/examples/{master/repository/coredevice_examples/simple => kc705/repository}/dds_test.py (100%) rename artiq/examples/{master/repository/coredevice_examples/simple => kc705/repository}/dma_blink.py (100%) rename artiq/examples/{master/repository/coredevice_examples/simple => kc705/repository}/handover.py (100%) rename artiq/examples/{master/repository/coredevice_examples/simple => kc705/repository}/mandelbrot.py (100%) rename artiq/examples/{master/repository/coredevice_examples => kc705/repository}/photon_histogram.py (100%) rename artiq/examples/{master => kc705}/repository/speed_benchmark.py (100%) rename artiq/examples/{master/repository/coredevice_examples => kc705/repository}/tdr.py (100%) rename artiq/examples/{master/repository/coredevice_examples/simple => kc705/repository}/urukul.py (100%) rename artiq/examples/{sim => no_hardware}/device_db.py (66%) rename artiq/examples/{sim => no_hardware/repository}/al_spectroscopy.py (100%) rename artiq/examples/{master => no_hardware}/repository/arguments_demo.py (100%) rename artiq/examples/{master => no_hardware}/repository/code_applet.py (100%) rename artiq/examples/{master => no_hardware}/repository/custom_applet.py (100%) rename artiq/examples/{master => no_hardware}/repository/flopping_f_simulation.py (100%) rename artiq/examples/{master => no_hardware}/repository/histograms.py (100%) rename artiq/examples/{master => no_hardware}/repository/multi_scan.py (100%) rename artiq/examples/{master => no_hardware}/repository/remote_exec_demo.py (100%) rename artiq/examples/{master => no_hardware}/repository/remote_exec_processing.py (100%) rename artiq/examples/{master => no_hardware}/repository/run_forever.py (100%) rename artiq/examples/{sim => no_hardware/repository}/simple_simulation.py (100%) rename artiq/examples/{master/repository/utilities => no_hardware/repository}/terminate_all.py (100%) rename artiq/examples/{master => no_hardware}/repository/thumbnail.py (100%) rename artiq/examples/{drtio => sayma_drtio}/device_db.py (100%) rename artiq/examples/{drtio => sayma_drtio}/repository/ad9154_spi.py (100%) rename artiq/examples/{drtio => sayma_drtio}/repository/blink_forever.py (100%) rename artiq/examples/{drtio => sayma_drtio}/repository/pulse_rate.py (100%) rename artiq/examples/{sayma => sayma_standalone}/device_db.py (100%) rename artiq/examples/{sayma => sayma_standalone}/repository/blink_led.py (100%) rename artiq/examples/{sayma => sayma_standalone}/repository/demo.py (100%) rename artiq/examples/{sayma => sayma_standalone}/repository/demo_2tone.py (100%) rename artiq/examples/{sayma => sayma_standalone}/repository/test_ad9154_status.py (100%) diff --git a/artiq/examples/kc705/device_db.py b/artiq/examples/kc705/device_db.py new file mode 100644 index 000000000..28117fca0 --- /dev/null +++ b/artiq/examples/kc705/device_db.py @@ -0,0 +1,364 @@ +# This is an example device database that needs to be adapted to your setup. +# The RTIO channel numbers here are for NIST CLOCK on KC705. +# The list of devices here is not exhaustive. + +core_addr = "kc705-1.lab.m-labs.hk" + +device_db = { + # Core device + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + "core_dds": { + "type": "local", + "module": "artiq.coredevice.dds", + "class": "DDSGroupAD9914", + "arguments": { + "sysclk": 3e9, + "first_dds_bus_channel": 39, + "dds_bus_count": 2, + "dds_channel_count": 3 + } + }, + + "i2c_switch": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548" + }, + + # Generic TTL + "ttl0": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 0}, + "comment": "This is a fairly long comment, shown as tooltip." + }, + "ttl1": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 1}, + "comment": "Hello World" + }, + "ttl2": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 2} + }, + "ttl3": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 3} + }, + + "ttl4": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 4} + }, + "ttl5": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 5} + }, + "ttl6": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 6} + }, + "ttl7": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 7} + }, + "ttl_sma": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 18} + }, + "led": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 19} + }, + "ttl_clock_la32_p": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLClockGen", + "arguments": {"channel": 21} + }, + + # Generic SPI + "spi0": { + "type": "local", + "module": "artiq.coredevice.spi", + "class": "SPIMaster", + "arguments": {"channel": 23} + }, + "spi_mmc": { + "type": "local", + "module": "artiq.coredevice.spi", + "class": "SPIMaster", + "arguments": {"channel": 26} + }, + + # FMC DIO used to connect to Zotino + "fmcdio_dirctl_clk": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 27} + }, + "fmcdio_dirctl_ser": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 28} + }, + "fmcdio_dirctl_latch": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 29} + }, + "fmcdio_dirctl": { + "type": "local", + "module": "artiq.coredevice.shiftreg", + "class": "ShiftReg", + "arguments": {"clk": "fmcdio_dirctl_clk", + "ser": "fmcdio_dirctl_ser", + "latch": "fmcdio_dirctl_latch"} + }, + + # DAC + "spi_ams101": { + "type": "local", + "module": "artiq.coredevice.spi", + "class": "SPIMaster", + "arguments": {"channel": 22} + }, + "ttl_ams101_ldac": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 20} + }, + "spi_zotino": { + "type": "local", + "module": "artiq.coredevice.spi", + "class": "SPIMaster", + "arguments": {"channel": 30} + }, + "ttl_zotino_ldac": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 31} + }, + "dac_zotino": { + "type": "local", + "module": "artiq.coredevice.ad5360", + "class": "AD5360", + "arguments": {"spi_device": "spi_zotino", "ldac_device": "ttl_zotino_ldac"} + }, + + "spi_urukul": { + "type": "local", + "module": "artiq.coredevice.spi", + "class": "SPIMaster", + "arguments": {"channel": 32} + }, + "ttl_urukul_io_update": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 33} + }, + "ttl_urukul_sw0": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 35} + }, + "ttl_urukul_sw1": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 36} + }, + "ttl_urukul_sw2": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 37} + }, + "ttl_urukul_sw3": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 38} + }, + "urukul_cpld": { + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul", + "io_update_device": "ttl_urukul_io_update", + "refclk": 100e6 + } + }, + "urukul_ch0a": { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 4, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw0" + } + }, + "urukul_ch1a": { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 5, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw1" + } + }, + "urukul_ch2a": { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 6, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw2" + } + }, + "urukul_ch3a": { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 7, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw3" + } + }, + "urukul_ch0b": { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 4, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw0" + } + }, + "urukul_ch1b": { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 5, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw1" + } + }, + "urukul_ch2b": { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 6, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw2" + } + }, + "urukul_ch3b": { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 7, + "cpld_device": "urukul_cpld", + "sw_device": "ttl_urukul_sw3" + } + }, + + # AD9914 DDS + "dds0": { + "type": "local", + "module": "artiq.coredevice.dds", + "class": "DDSChannelAD9914", + "arguments": {"bus_channel": 39, "channel": 0}, + "comment": "Comments work in DDS panel as well" + }, + "dds1": { + "type": "local", + "module": "artiq.coredevice.dds", + "class": "DDSChannelAD9914", + "arguments": {"bus_channel": 39, "channel": 1} + }, + "dds2": { + "type": "local", + "module": "artiq.coredevice.dds", + "class": "DDSChannelAD9914", + "arguments": {"bus_channel": 39, "channel": 2} + }, + + # Aliases + "ttl_out": "ttl0", + "ttl_out_serdes": "ttl0", + + "loop_out": "ttl0", + "loop_in": "ttl3", + "loop_clock_out": "ttl_clock_la32_p", + "loop_clock_in": "ttl7", + + "pmt": "ttl3", + "bd_dds": "dds0", + "bd_sw": "ttl0", + "bdd_dds": "dds1", + "bdd_sw": "ttl1" +} diff --git a/artiq/examples/master/idle_kernel.py b/artiq/examples/kc705/idle_kernel.py similarity index 100% rename from artiq/examples/master/idle_kernel.py rename to artiq/examples/kc705/idle_kernel.py diff --git a/artiq/examples/master/repository/coredevice_examples/simple/ad5360.py b/artiq/examples/kc705/repository/ad5360.py similarity index 100% rename from artiq/examples/master/repository/coredevice_examples/simple/ad5360.py rename to artiq/examples/kc705/repository/ad5360.py diff --git a/artiq/examples/master/repository/coredevice_examples/simple/blink_forever.py b/artiq/examples/kc705/repository/blink_forever.py similarity index 100% rename from artiq/examples/master/repository/coredevice_examples/simple/blink_forever.py rename to artiq/examples/kc705/repository/blink_forever.py diff --git a/artiq/examples/master/repository/core_pause.py b/artiq/examples/kc705/repository/core_pause.py similarity index 100% rename from artiq/examples/master/repository/core_pause.py rename to artiq/examples/kc705/repository/core_pause.py diff --git a/artiq/examples/master/repository/utilities/dds_setter.py b/artiq/examples/kc705/repository/dds_setter.py similarity index 100% rename from artiq/examples/master/repository/utilities/dds_setter.py rename to artiq/examples/kc705/repository/dds_setter.py diff --git a/artiq/examples/master/repository/coredevice_examples/simple/dds_test.py b/artiq/examples/kc705/repository/dds_test.py similarity index 100% rename from artiq/examples/master/repository/coredevice_examples/simple/dds_test.py rename to artiq/examples/kc705/repository/dds_test.py diff --git a/artiq/examples/master/repository/coredevice_examples/simple/dma_blink.py b/artiq/examples/kc705/repository/dma_blink.py similarity index 100% rename from artiq/examples/master/repository/coredevice_examples/simple/dma_blink.py rename to artiq/examples/kc705/repository/dma_blink.py diff --git a/artiq/examples/master/repository/coredevice_examples/simple/handover.py b/artiq/examples/kc705/repository/handover.py similarity index 100% rename from artiq/examples/master/repository/coredevice_examples/simple/handover.py rename to artiq/examples/kc705/repository/handover.py diff --git a/artiq/examples/master/repository/coredevice_examples/simple/mandelbrot.py b/artiq/examples/kc705/repository/mandelbrot.py similarity index 100% rename from artiq/examples/master/repository/coredevice_examples/simple/mandelbrot.py rename to artiq/examples/kc705/repository/mandelbrot.py diff --git a/artiq/examples/master/repository/coredevice_examples/photon_histogram.py b/artiq/examples/kc705/repository/photon_histogram.py similarity index 100% rename from artiq/examples/master/repository/coredevice_examples/photon_histogram.py rename to artiq/examples/kc705/repository/photon_histogram.py diff --git a/artiq/examples/master/repository/speed_benchmark.py b/artiq/examples/kc705/repository/speed_benchmark.py similarity index 100% rename from artiq/examples/master/repository/speed_benchmark.py rename to artiq/examples/kc705/repository/speed_benchmark.py diff --git a/artiq/examples/master/repository/coredevice_examples/tdr.py b/artiq/examples/kc705/repository/tdr.py similarity index 100% rename from artiq/examples/master/repository/coredevice_examples/tdr.py rename to artiq/examples/kc705/repository/tdr.py diff --git a/artiq/examples/master/repository/coredevice_examples/simple/urukul.py b/artiq/examples/kc705/repository/urukul.py similarity index 100% rename from artiq/examples/master/repository/coredevice_examples/simple/urukul.py rename to artiq/examples/kc705/repository/urukul.py diff --git a/artiq/examples/master/device_db.py b/artiq/examples/master/device_db.py index 6c2a45347..44cf3d72f 100644 --- a/artiq/examples/master/device_db.py +++ b/artiq/examples/master/device_db.py @@ -1,6 +1,6 @@ -# This is an example device database that needs to be adapted to your setup. -# The RTIO channel numbers here are for NIST CLOCK on KC705. -# The list of devices here is not exhaustive. +# Copy of the KC705 device database, for compatibility of the buildbot and +# unit tests with release-3. +# Remove and update buildbot when release-3 is no longer maintained. core_addr = "kc705-1.lab.m-labs.hk" @@ -347,28 +347,6 @@ device_db = { "arguments": {"bus_channel": 39, "channel": 2} }, - # Controllers - "lda": { - "type": "controller", - "best_effort": True, - "host": "::1", - "port": 3253, - "command": "aqctl_lda -p {port} --bind {bind} --simulation" - }, - - "camera_sim": { - "type": "controller", - "host": "::1", - "port": 6283, - "target_name": "camera_sim", - "command": "python3 -m artiq.examples.remote_exec_controller" - }, - "camera_sim_rexec": { - "type": "controller_aux_target", - "controller": "camera_sim", - "target_name": "camera_sim_rexec" - }, - # Aliases "ttl_out": "ttl0", "ttl_out_serdes": "ttl0", diff --git a/artiq/examples/sim/device_db.py b/artiq/examples/no_hardware/device_db.py similarity index 66% rename from artiq/examples/sim/device_db.py rename to artiq/examples/no_hardware/device_db.py index 2fe351a5b..6e3c29af4 100644 --- a/artiq/examples/sim/device_db.py +++ b/artiq/examples/no_hardware/device_db.py @@ -41,4 +41,27 @@ device_db = { "class": "WaveOutput", "arguments": {"name": "state_detection"} }, + + # Controllers + "lda": { + "type": "controller", + "best_effort": True, + "host": "::1", + "port": 3253, + "command": "aqctl_lda -p {port} --bind {bind} --simulation" + }, + + "camera_sim": { + "type": "controller", + "host": "::1", + "port": 6283, + "target_name": "camera_sim", + "command": "python3 -m artiq.examples.remote_exec_controller" + }, + "camera_sim_rexec": { + "type": "controller_aux_target", + "controller": "camera_sim", + "target_name": "camera_sim_rexec" + }, + } diff --git a/artiq/examples/sim/al_spectroscopy.py b/artiq/examples/no_hardware/repository/al_spectroscopy.py similarity index 100% rename from artiq/examples/sim/al_spectroscopy.py rename to artiq/examples/no_hardware/repository/al_spectroscopy.py diff --git a/artiq/examples/master/repository/arguments_demo.py b/artiq/examples/no_hardware/repository/arguments_demo.py similarity index 100% rename from artiq/examples/master/repository/arguments_demo.py rename to artiq/examples/no_hardware/repository/arguments_demo.py diff --git a/artiq/examples/master/repository/code_applet.py b/artiq/examples/no_hardware/repository/code_applet.py similarity index 100% rename from artiq/examples/master/repository/code_applet.py rename to artiq/examples/no_hardware/repository/code_applet.py diff --git a/artiq/examples/master/repository/custom_applet.py b/artiq/examples/no_hardware/repository/custom_applet.py similarity index 100% rename from artiq/examples/master/repository/custom_applet.py rename to artiq/examples/no_hardware/repository/custom_applet.py diff --git a/artiq/examples/master/repository/flopping_f_simulation.py b/artiq/examples/no_hardware/repository/flopping_f_simulation.py similarity index 100% rename from artiq/examples/master/repository/flopping_f_simulation.py rename to artiq/examples/no_hardware/repository/flopping_f_simulation.py diff --git a/artiq/examples/master/repository/histograms.py b/artiq/examples/no_hardware/repository/histograms.py similarity index 100% rename from artiq/examples/master/repository/histograms.py rename to artiq/examples/no_hardware/repository/histograms.py diff --git a/artiq/examples/master/repository/multi_scan.py b/artiq/examples/no_hardware/repository/multi_scan.py similarity index 100% rename from artiq/examples/master/repository/multi_scan.py rename to artiq/examples/no_hardware/repository/multi_scan.py diff --git a/artiq/examples/master/repository/remote_exec_demo.py b/artiq/examples/no_hardware/repository/remote_exec_demo.py similarity index 100% rename from artiq/examples/master/repository/remote_exec_demo.py rename to artiq/examples/no_hardware/repository/remote_exec_demo.py diff --git a/artiq/examples/master/repository/remote_exec_processing.py b/artiq/examples/no_hardware/repository/remote_exec_processing.py similarity index 100% rename from artiq/examples/master/repository/remote_exec_processing.py rename to artiq/examples/no_hardware/repository/remote_exec_processing.py diff --git a/artiq/examples/master/repository/run_forever.py b/artiq/examples/no_hardware/repository/run_forever.py similarity index 100% rename from artiq/examples/master/repository/run_forever.py rename to artiq/examples/no_hardware/repository/run_forever.py diff --git a/artiq/examples/sim/simple_simulation.py b/artiq/examples/no_hardware/repository/simple_simulation.py similarity index 100% rename from artiq/examples/sim/simple_simulation.py rename to artiq/examples/no_hardware/repository/simple_simulation.py diff --git a/artiq/examples/master/repository/utilities/terminate_all.py b/artiq/examples/no_hardware/repository/terminate_all.py similarity index 100% rename from artiq/examples/master/repository/utilities/terminate_all.py rename to artiq/examples/no_hardware/repository/terminate_all.py diff --git a/artiq/examples/master/repository/thumbnail.py b/artiq/examples/no_hardware/repository/thumbnail.py similarity index 100% rename from artiq/examples/master/repository/thumbnail.py rename to artiq/examples/no_hardware/repository/thumbnail.py diff --git a/artiq/examples/drtio/device_db.py b/artiq/examples/sayma_drtio/device_db.py similarity index 100% rename from artiq/examples/drtio/device_db.py rename to artiq/examples/sayma_drtio/device_db.py diff --git a/artiq/examples/drtio/repository/ad9154_spi.py b/artiq/examples/sayma_drtio/repository/ad9154_spi.py similarity index 100% rename from artiq/examples/drtio/repository/ad9154_spi.py rename to artiq/examples/sayma_drtio/repository/ad9154_spi.py diff --git a/artiq/examples/drtio/repository/blink_forever.py b/artiq/examples/sayma_drtio/repository/blink_forever.py similarity index 100% rename from artiq/examples/drtio/repository/blink_forever.py rename to artiq/examples/sayma_drtio/repository/blink_forever.py diff --git a/artiq/examples/drtio/repository/pulse_rate.py b/artiq/examples/sayma_drtio/repository/pulse_rate.py similarity index 100% rename from artiq/examples/drtio/repository/pulse_rate.py rename to artiq/examples/sayma_drtio/repository/pulse_rate.py diff --git a/artiq/examples/sayma/device_db.py b/artiq/examples/sayma_standalone/device_db.py similarity index 100% rename from artiq/examples/sayma/device_db.py rename to artiq/examples/sayma_standalone/device_db.py diff --git a/artiq/examples/sayma/repository/blink_led.py b/artiq/examples/sayma_standalone/repository/blink_led.py similarity index 100% rename from artiq/examples/sayma/repository/blink_led.py rename to artiq/examples/sayma_standalone/repository/blink_led.py diff --git a/artiq/examples/sayma/repository/demo.py b/artiq/examples/sayma_standalone/repository/demo.py similarity index 100% rename from artiq/examples/sayma/repository/demo.py rename to artiq/examples/sayma_standalone/repository/demo.py diff --git a/artiq/examples/sayma/repository/demo_2tone.py b/artiq/examples/sayma_standalone/repository/demo_2tone.py similarity index 100% rename from artiq/examples/sayma/repository/demo_2tone.py rename to artiq/examples/sayma_standalone/repository/demo_2tone.py diff --git a/artiq/examples/sayma/repository/test_ad9154_status.py b/artiq/examples/sayma_standalone/repository/test_ad9154_status.py similarity index 100% rename from artiq/examples/sayma/repository/test_ad9154_status.py rename to artiq/examples/sayma_standalone/repository/test_ad9154_status.py From 0aacdb045867f4accba5c990176850455a9bc188 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 28 Jan 2018 02:12:46 +0800 Subject: [PATCH 0290/2457] tools: add missing import --- artiq/tools.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/tools.py b/artiq/tools.py index f8f4314bf..f7a399db7 100644 --- a/artiq/tools.py +++ b/artiq/tools.py @@ -3,6 +3,7 @@ import logging import sys import asyncio import collections +import atexit import string import os From 0b9c5519623fcecb8167b4c9c8bb0b1b24c15f04 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 27 Jan 2018 16:26:02 +0000 Subject: [PATCH 0291/2457] artiq_flash: implement flash read functionality. --- artiq/frontend/artiq_flash.py | 28 ++++++++---- artiq/remoting.py | 84 +++++++++++++++++++++++++---------- 2 files changed, 80 insertions(+), 32 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 4c14d9ef9..e1ced8702 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -118,7 +118,7 @@ class Programmer: return re.sub(rb"\[find (.+?)\]", repl, content, re.DOTALL) script = os.path.join(scripts_path(), script) - return self._client.transfer_file(script, rewriter) + return self._client.upload(script, rewriter) def add_flash_bank(self, name, tap, index): add_commands(self._board_script, @@ -133,7 +133,7 @@ class Programmer: return self._loaded[pld] = bitfile - bitfile = self._client.transfer_file(bitfile) + bitfile = self._client.upload(bitfile) add_commands(self._script, "pld load {pld} {filename}", pld=pld, filename=bitfile) @@ -141,11 +141,11 @@ class Programmer: def load_proxy(self): raise NotImplementedError - def flash_binary(self, bankname, address, filename): + def write_binary(self, bankname, address, filename): self.load_proxy() size = os.path.getsize(filename) - filename = self._client.transfer_file(filename) + filename = self._client.upload(filename) add_commands(self._script, "flash probe {bankname}", "flash erase_sector {bankname} {firstsector} {lastsector}", @@ -155,6 +155,15 @@ class Programmer: firstsector=address // self._sector_size, lastsector=(address + size - 1) // self._sector_size) + def read_binary(self, bankname, address, length, filename): + self.load_proxy() + + filename = self._client.prepare_download(filename) + add_commands(self._script, + "flash probe {bankname}", + "flash read_bank {bankname} {filename} {address:#x} {length}", + bankname=bankname, filename=filename, address=address, length=length) + def start(self): raise NotImplementedError @@ -175,6 +184,9 @@ class Programmer: cmdline = [arg.replace("{", "{{").replace("}", "}}") for arg in cmdline] self._client.run_command(cmdline) + self._client.download() + + self._script = [] class ProgrammerXC7(Programmer): @@ -304,13 +316,13 @@ def main(): bit2bin(bit_file, bin_file) atexit.register(lambda: os.unlink(gateware_bin)) - programmer.flash_binary(*config["gateware"], gateware_bin) + programmer.write_binary(*config["gateware"], gateware_bin) elif action == "bootloader": bootloader_bin = artifact_path("software", "bootloader", "bootloader.bin") - programmer.flash_binary(*config["bootloader"], bootloader_bin) + programmer.write_binary(*config["bootloader"], bootloader_bin) elif action == "storage": storage_img = args.storage - programmer.flash_binary(*config["storage"], storage_img) + programmer.write_binary(*config["storage"], storage_img) elif action == "firmware": if variant == "satellite": firmware = "satman" @@ -318,7 +330,7 @@ def main(): firmware = "runtime" firmware_fbi = artifact_path("software", firmware, firmware + ".fbi") - programmer.flash_binary(*config["firmware"], firmware_fbi) + programmer.write_binary(*config["firmware"], firmware_fbi) elif action == "load": if args.target == "sayma_rtm": gateware_bit = artifact_path("top.bit") diff --git a/artiq/remoting.py b/artiq/remoting.py index aa3c27f3f..8400b35e8 100644 --- a/artiq/remoting.py +++ b/artiq/remoting.py @@ -6,6 +6,7 @@ import shutil import shlex import subprocess import hashlib +import random __all__ = ["LocalClient", "SSHClient"] @@ -13,7 +14,13 @@ logger = logging.getLogger(__name__) class Client: - def transfer_file(self, filename, rewriter=None): + def upload(self, filename, rewriter=None): + raise NotImplementedError + + def prepare_download(self, filename): + raise NotImplementedError + + def download(self): raise NotImplementedError def run_command(self, cmd, **kws): @@ -24,8 +31,8 @@ class LocalClient(Client): def __init__(self): self._tmp = os.path.join(tempfile.gettempdir(), "artiq") - def transfer_file(self, filename, rewriter=None): - logger.debug("Transferring {}".format(filename)) + def upload(self, filename, rewriter=None): + logger.debug("Uploading {}".format(filename)) if rewriter is None: return filename else: @@ -37,6 +44,13 @@ class LocalClient(Client): tmp.write(rewritten) return tmp_filename + def prepare_download(self, filename): + logger.debug("Downloading {}".format(filename)) + return filename + + def download(self): + pass + def run_command(self, cmd, **kws): logger.debug("Executing {}".format(cmd)) subprocess.check_call([arg.format(tmp=self._tmp, **kws) for arg in cmd]) @@ -47,8 +61,10 @@ class SSHClient(Client): self.host = host self.ssh = None self.sftp = None - self._tmp = "/tmp/artiq" + self._tmpr = "/tmp/artiq" + self._tmpl = tempfile.TemporaryDirectory(prefix="artiq") self._cached = [] + self._downloads = {} def get_ssh(self): if self.ssh is None: @@ -68,39 +84,59 @@ class SSHClient(Client): if self.sftp is None: self.sftp = self.get_ssh().open_sftp() try: - self._cached = self.sftp.listdir(self._tmp) + self._cached = self.sftp.listdir(self._tmpr) except OSError: - self.sftp.mkdir(self._tmp) + self.sftp.mkdir(self._tmpr) return self.sftp - def transfer_file(self, filename, rewriter=lambda x: x): - sftp = self.get_sftp() + def upload(self, filename, rewriter=lambda x: x): with open(filename, 'rb') as local: rewritten = rewriter(local.read()) digest = hashlib.sha1(rewritten).hexdigest() - remote_filename = os.path.join(self._tmp, digest) - if digest in self._cached: - logger.debug("Using cached {}".format(filename)) - else: - logger.debug("Transferring {}".format(filename)) - # Avoid a race condition by writing into a temporary file - # and atomically replacing - with sftp.open(remote_filename + ".~", "wb") as remote: - remote.write(rewritten) - try: - sftp.rename(remote_filename + ".~", remote_filename) - except IOError: - # Either it already exists (this is OK) or something else - # happened (this isn't) and we need to re-raise - sftp.stat(remote_filename) + remote_filename = "{}/{}".format(self._tmpr, digest) + + sftp = self.get_sftp() + if digest in self._cached: + logger.debug("Using cached {}".format(filename)) + else: + logger.debug("Uploading {}".format(filename)) + # Avoid a race condition by writing into a temporary file + # and atomically replacing + with sftp.open(remote_filename + ".~", "wb") as remote: + remote.write(rewritten) + try: + sftp.rename(remote_filename + ".~", remote_filename) + except IOError: + # Either it already exists (this is OK) or something else + # happened (this isn't) and we need to re-raise + sftp.stat(remote_filename) + return remote_filename + def prepare_download(self, filename): + tmpname = "".join([random.Random().choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ") + for _ in range(6)]) + remote_filename = "{}/{}_{}".format(self._tmpr, tmpname, filename) + + _sftp = self.get_sftp() + logger.debug("Downloading {}".format(filename)) + self._downloads[filename] = remote_filename + + return remote_filename + + def download(self): + sftp = self.get_sftp() + for filename, remote_filename in self._downloads.items(): + sftp.get(remote_filename, filename) + + self._downloads = {} + def spawn_command(self, cmd, get_pty=False, **kws): chan = self.get_transport().open_session() chan.set_combine_stderr(True) if get_pty: chan.get_pty() - cmd = " ".join([shlex.quote(arg.format(tmp=self._tmp, **kws)) for arg in cmd]) + cmd = " ".join([shlex.quote(arg.format(tmp=self._tmpr, **kws)) for arg in cmd]) logger.debug("Executing {}".format(cmd)) chan.exec_command(cmd) return chan From 11a8b84355d7a73e9b6ae72f20617e0a23fb30e7 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 27 Jan 2018 19:53:43 +0000 Subject: [PATCH 0292/2457] Merge the build trees of sayma_amc and sayma_rtm targets. This also makes them a single artiq_flash target, and a single conda package. --- .gitignore | 1 + artiq/frontend/artiq_devtool.py | 29 ++++++++++--------- artiq/frontend/artiq_flash.py | 15 ++++------ artiq/gateware/targets/sayma_amc.py | 3 +- artiq/gateware/targets/sayma_rtm.py | 6 ++-- conda/artiq-sayma-standalone/build.sh | 13 +++++++++ .../meta.yaml | 4 +-- conda/artiq-sayma_amc-standalone/build.sh | 9 ------ conda/artiq-sayma_amc-standalone/meta.yaml | 24 --------------- conda/artiq-sayma_rtm/build.sh | 11 ------- 10 files changed, 41 insertions(+), 74 deletions(-) create mode 100644 conda/artiq-sayma-standalone/build.sh rename conda/{artiq-sayma_rtm => artiq-sayma-standalone}/meta.yaml (88%) delete mode 100644 conda/artiq-sayma_amc-standalone/build.sh delete mode 100644 conda/artiq-sayma_amc-standalone/meta.yaml delete mode 100644 conda/artiq-sayma_rtm/build.sh diff --git a/.gitignore b/.gitignore index 91ffc1c07..0fc39b517 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ __pycache__/ /artiq/binaries /artiq/firmware/target/ /misoc_*/ +/artiq_*/ /artiq/test/results /artiq/examples/*/results diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 04b112728..9d76f65a0 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -31,7 +31,7 @@ def get_argparser(): parser.add_argument("-t", "--target", metavar="TARGET", type=str, default="kc705", help="target to build, one of: " - "kc705 kasli sayma_rtm sayma_amc") + "kc705 kasli sayma") parser.add_argument("-g", "--build-gateware", default=False, action="store_true", help="build gateware, not just software") @@ -71,14 +71,10 @@ def main(): def build_dir(*path, target=args.target): return os.path.join("/tmp", target, *path) - extra_build_args = [] if args.target == "kc705": board_type, firmware = "kc705", "runtime" - elif args.target == "sayma_amc": - board_type, firmware = "sayma_amc", "runtime" - extra_build_args += ["--rtm-csr-csv", build_dir("sayma_rtm_csr.csv", target="sayma_rtm")] - elif args.target == "sayma_rtm": - board_type, firmware = "sayma_rtm", None + elif args.target == "sayma": + board_type, firmware = "sayma", "runtime" else: raise NotImplementedError("unknown target {}".format(args.target)) @@ -132,6 +128,13 @@ def main(): logger.error(on_failure) sys.exit(1) + def build(target, *extra_args, output_dir=build_dir()): + build_args = ["python3", "-m", "artiq.gateware.targets." + target, *extra_args] + if not args.build_gateware: + build_args.append("--no-compile-gateware") + build_args += ["--output-dir", output_dir] + command(*build_args, on_failure="Build failed") + def flash(*steps): lock() @@ -147,13 +150,11 @@ def main(): for action in args.actions: if action == "build": logger.info("Building target") - - build_args = ["python3", "-m", "artiq.gateware.targets." + args.target] - if not args.build_gateware: - build_args.append("--no-compile-gateware") - build_args += ["--output-dir", build_dir()] - build_args += extra_build_args - command(*build_args, on_failure="Build failed") + if args.target == "sayma": + build("sayma_rtm", output_dir=build_dir("rtm")) + build("sayma_amc", "--rtm-csr-csv", build_dir("rtm", "rtm_csr.csv")) + else: + build(args.target) elif action == "clean": logger.info("Cleaning build directory") diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index e1ced8702..6f6ebc8ce 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -51,7 +51,7 @@ Prerequisites: help="SSH host where the development board is located") parser.add_argument("-t", "--target", default="kc705", help="target board, default: %(default)s, one of: " - "kc705 kasli sayma_amc sayma_rtm") + "kc705 kasli sayma") parser.add_argument("-V", "--variant", default=None, help="board variant") parser.add_argument("-I", "--preinit-command", default=[], action="append", @@ -263,7 +263,7 @@ def main(): "storage": ("spi0", 0x440000), "firmware": ("spi0", 0x450000), }, - "sayma_amc": { + "sayma": { "programmer": ProgrammerSayma, "variants": ["standalone", "master", "satellite"], "gateware": ("spi0", 0x000000), @@ -271,10 +271,6 @@ def main(): "storage": ("spi1", 0x040000), "firmware": ("spi1", 0x050000), }, - "sayma_rtm": { - "programmer": ProgrammerSayma, - "gateware": ("spi1", 0x150000), - }, }[args.target] variant = args.variant @@ -332,10 +328,9 @@ def main(): firmware_fbi = artifact_path("software", firmware, firmware + ".fbi") programmer.write_binary(*config["firmware"], firmware_fbi) elif action == "load": - if args.target == "sayma_rtm": - gateware_bit = artifact_path("top.bit") - programmer.load(gateware_bit, 0) - elif args.target == "sayma_amc": + if args.target == "sayma": + rtm_gateware_bit = artifact_path("rtm", "rtm.bit") + programmer.load(rtm_gateware_bit, 0) gateware_bit = artifact_path("gateware", "top.bit") programmer.load(gateware_bit, 1) else: diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 43307c2f9..938d054a2 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -439,12 +439,13 @@ def main(): description="Sayma AMC gateware and firmware builder") builder_args(parser) soc_sdram_args(parser) + parser.set_defaults(output_dir="artiq_sayma") parser.add_argument("-V", "--variant", default="standalone", help="variant: " "standalone/master/satellite " "(default: %(default)s)") parser.add_argument("--rtm-csr-csv", - default=os.path.join("artiq_sayma_rtm", "sayma_rtm_csr.csv"), + default=os.path.join("artiq_sayma", "rtm", "rtm_csr.csv"), help="CSV file listing remote CSRs on RTM (default: %(default)s)") parser.add_argument("--without-sawg", default=False, action="store_true", diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 6f7c9ee1c..cf4ad3fdf 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -190,7 +190,7 @@ class SaymaRTM(Module): def main(): parser = argparse.ArgumentParser( description="ARTIQ device binary builder for Kasli systems") - parser.add_argument("--output-dir", default="artiq_sayma_rtm", + parser.add_argument("--output-dir", default="artiq_sayma/rtm", help="output directory for generated " "source files and binaries") parser.add_argument("--no-compile-gateware", action="store_true", @@ -205,11 +205,11 @@ def main(): top = SaymaRTM(platform) os.makedirs(args.output_dir, exist_ok=True) - with open(os.path.join(args.output_dir, "sayma_rtm_csr.csv"), "w") as f: + with open(os.path.join(args.output_dir, "rtm_csr.csv"), "w") as f: f.write(get_csr_csv(top.csr_regions)) if not args.no_compile_gateware: - platform.build(top, build_dir=args.output_dir) + platform.build(top, build_dir=args.output_dir, build_name="rtm") if __name__ == "__main__": diff --git a/conda/artiq-sayma-standalone/build.sh b/conda/artiq-sayma-standalone/build.sh new file mode 100644 index 000000000..a333452d1 --- /dev/null +++ b/conda/artiq-sayma-standalone/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/sayma-standalone +mkdir -p $SOC_PREFIX + +$PYTHON -m artiq.gateware.targets.sayma_rtm +cp artiq_sayma/rtm_gateware/rtm.bit $SOC_PREFIX + +$PYTHON -m artiq.gateware.targets.sayma_amc -V standalone \ + --rtm-csr-csv artiq_sayma/rtm/sayma_rtm_csr.csv +cp artiq_sayma/gateware/top.bit $SOC_PREFIX +cp artiq_sayma/software/bootloader/bootloader.bin $SOC_PREFIX +cp artiq_sayma/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-sayma_rtm/meta.yaml b/conda/artiq-sayma-standalone/meta.yaml similarity index 88% rename from conda/artiq-sayma_rtm/meta.yaml rename to conda/artiq-sayma-standalone/meta.yaml index 0aed97148..cb717d376 100644 --- a/conda/artiq-sayma_rtm/meta.yaml +++ b/conda/artiq-sayma-standalone/meta.yaml @@ -1,5 +1,5 @@ package: - name: artiq-sayma_rtm + name: artiq-sayma-standalone version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} source: @@ -20,4 +20,4 @@ requirements: about: home: https://m-labs.hk/artiq license: LGPL - summary: 'Bitstream and CSR map for Sayma RTM' + summary: 'AMC and RTM bitstream, BIOS and runtime for stand-alone Sayma AMC' diff --git a/conda/artiq-sayma_amc-standalone/build.sh b/conda/artiq-sayma_amc-standalone/build.sh deleted file mode 100644 index 918638a50..000000000 --- a/conda/artiq-sayma_amc-standalone/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/sayma_amc-standalone -mkdir -p $SOC_PREFIX - -V=1 $PYTHON -m artiq.gateware.targets.sayma_amc -V standalone --rtm-csr-csv $SP_DIR/artiq/binaries/sayma_rtm/sayma_rtm_csr.csv -cp misoc_standalone_sayma_amc/gateware/top.bit $SOC_PREFIX -cp misoc_standalone_sayma_amc/software/bootloader/bootloader.bin $SOC_PREFIX -cp misoc_standalone_sayma_amc/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-sayma_amc-standalone/meta.yaml b/conda/artiq-sayma_amc-standalone/meta.yaml deleted file mode 100644 index 832f7326a..000000000 --- a/conda/artiq-sayma_amc-standalone/meta.yaml +++ /dev/null @@ -1,24 +0,0 @@ -package: - name: artiq-sayma_amc-standalone - version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} - -source: - git_url: ../.. - -build: - noarch: python - ignore_prefix_files: True - number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} - string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} - -requirements: - build: - - artiq-dev {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} - - artiq-sayma_rtm {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} - run: - - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} - -about: - home: https://m-labs.hk/artiq - license: LGPL - summary: 'Bitstream, BIOS and runtime for stand-alone Sayma AMC' diff --git a/conda/artiq-sayma_rtm/build.sh b/conda/artiq-sayma_rtm/build.sh deleted file mode 100644 index 5b9476ac7..000000000 --- a/conda/artiq-sayma_rtm/build.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -BUILD_SETTINGS_FILE=$HOME/.m-labs/build_settings.sh -[ -f $BUILD_SETTINGS_FILE ] && . $BUILD_SETTINGS_FILE - -SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/sayma_rtm -mkdir -p $SOC_PREFIX - -$PYTHON -m artiq.gateware.targets.sayma_rtm -cp artiq_sayma_rtm/top.bit $SOC_PREFIX -cp artiq_sayma_rtm/sayma_rtm_csr.csv $SOC_PREFIX From 885ab40946c96fa95be165e9a2854bcb1fd6b850 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 28 Jan 2018 14:27:08 +0000 Subject: [PATCH 0293/2457] conda: split RTM and AMC packages back. This avoids multiplying the RTM compilation time by the number of AMC packages. --- artiq/frontend/artiq_devtool.py | 4 ++-- artiq/frontend/artiq_flash.py | 2 +- artiq/gateware/targets/sayma_amc.py | 2 +- artiq/gateware/targets/sayma_rtm.py | 2 +- conda/artiq-sayma-standalone/build.sh | 8 ++++---- conda/artiq-sayma-standalone/meta.yaml | 3 ++- conda/artiq-sayma_rtm/build.sh | 8 ++++++++ conda/artiq-sayma_rtm/meta.yaml | 23 +++++++++++++++++++++++ 8 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 conda/artiq-sayma_rtm/build.sh create mode 100644 conda/artiq-sayma_rtm/meta.yaml diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 9d76f65a0..ae54960a0 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -151,8 +151,8 @@ def main(): if action == "build": logger.info("Building target") if args.target == "sayma": - build("sayma_rtm", output_dir=build_dir("rtm")) - build("sayma_amc", "--rtm-csr-csv", build_dir("rtm", "rtm_csr.csv")) + build("sayma_rtm", output_dir=build_dir("rtm_gateware")) + build("sayma_amc", "--rtm-csr-csv", build_dir("rtm_gateware", "rtm_csr.csv")) else: build(args.target) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 6f6ebc8ce..12d1855e9 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -329,7 +329,7 @@ def main(): programmer.write_binary(*config["firmware"], firmware_fbi) elif action == "load": if args.target == "sayma": - rtm_gateware_bit = artifact_path("rtm", "rtm.bit") + rtm_gateware_bit = artifact_path("rtm_gateware", "rtm.bit") programmer.load(rtm_gateware_bit, 0) gateware_bit = artifact_path("gateware", "top.bit") programmer.load(gateware_bit, 1) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 938d054a2..c45f8d37a 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -445,7 +445,7 @@ def main(): "standalone/master/satellite " "(default: %(default)s)") parser.add_argument("--rtm-csr-csv", - default=os.path.join("artiq_sayma", "rtm", "rtm_csr.csv"), + default=os.path.join("artiq_sayma", "rtm_gateware", "rtm_csr.csv"), help="CSV file listing remote CSRs on RTM (default: %(default)s)") parser.add_argument("--without-sawg", default=False, action="store_true", diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index cf4ad3fdf..718a9d4ed 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -190,7 +190,7 @@ class SaymaRTM(Module): def main(): parser = argparse.ArgumentParser( description="ARTIQ device binary builder for Kasli systems") - parser.add_argument("--output-dir", default="artiq_sayma/rtm", + parser.add_argument("--output-dir", default="artiq_sayma/rtm_gateware", help="output directory for generated " "source files and binaries") parser.add_argument("--no-compile-gateware", action="store_true", diff --git a/conda/artiq-sayma-standalone/build.sh b/conda/artiq-sayma-standalone/build.sh index a333452d1..824329f3e 100644 --- a/conda/artiq-sayma-standalone/build.sh +++ b/conda/artiq-sayma-standalone/build.sh @@ -1,13 +1,13 @@ #!/bin/bash +RTM_PREFIX=$SP_DIR/artiq/binaries/sayma_rtm + SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/sayma-standalone mkdir -p $SOC_PREFIX -$PYTHON -m artiq.gateware.targets.sayma_rtm -cp artiq_sayma/rtm_gateware/rtm.bit $SOC_PREFIX - $PYTHON -m artiq.gateware.targets.sayma_amc -V standalone \ - --rtm-csr-csv artiq_sayma/rtm/sayma_rtm_csr.csv + --rtm-csr-csv $RTM_PREFIX/rtm_csr.csv cp artiq_sayma/gateware/top.bit $SOC_PREFIX cp artiq_sayma/software/bootloader/bootloader.bin $SOC_PREFIX cp artiq_sayma/software/runtime/runtime.{elf,fbi} $SOC_PREFIX +cp $RTM_PREFIX/rtm.bit $SOC_PREFIX diff --git a/conda/artiq-sayma-standalone/meta.yaml b/conda/artiq-sayma-standalone/meta.yaml index cb717d376..8450d3319 100644 --- a/conda/artiq-sayma-standalone/meta.yaml +++ b/conda/artiq-sayma-standalone/meta.yaml @@ -14,10 +14,11 @@ build: requirements: build: - artiq-dev {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} + - artiq-sayma_rtm {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} run: - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} about: home: https://m-labs.hk/artiq license: LGPL - summary: 'AMC and RTM bitstream, BIOS and runtime for stand-alone Sayma AMC' + summary: 'Bitstream, BIOS and runtime for stand-alone Sayma AMC' diff --git a/conda/artiq-sayma_rtm/build.sh b/conda/artiq-sayma_rtm/build.sh new file mode 100644 index 000000000..282ad44d2 --- /dev/null +++ b/conda/artiq-sayma_rtm/build.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/sayma_rtm +mkdir -p $SOC_PREFIX + +$PYTHON -m artiq.gateware.targets.sayma_rtm +cp artiq_sayma/rtm/rtm.bit $SOC_PREFIX +cp artiq_sayma/rtm/rtm_csr.csv $SOC_PREFIX diff --git a/conda/artiq-sayma_rtm/meta.yaml b/conda/artiq-sayma_rtm/meta.yaml new file mode 100644 index 000000000..0aed97148 --- /dev/null +++ b/conda/artiq-sayma_rtm/meta.yaml @@ -0,0 +1,23 @@ +package: + name: artiq-sayma_rtm + version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} + +source: + git_url: ../.. + +build: + noarch: python + ignore_prefix_files: True + number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} + string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} + +requirements: + build: + - artiq-dev {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} + run: + - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} + +about: + home: https://m-labs.hk/artiq + license: LGPL + summary: 'Bitstream and CSR map for Sayma RTM' From 79ea454ec13b24d295d2df75f8939c5775ada6ad Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 28 Jan 2018 14:28:55 +0000 Subject: [PATCH 0294/2457] conda: use $SP_DIR instead of $PREFIX/lib/python3.5/site-packages. (#652) This removes the last hardcoded python3.5 reference. --- conda/artiq-kasli-opticlock/build.sh | 2 +- conda/artiq-kc705-nist_clock/build.sh | 2 +- conda/artiq-kc705-nist_qc2/build.sh | 2 +- conda/artiq-sayma-standalone/build.sh | 2 +- conda/artiq-sayma_rtm/build.sh | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/conda/artiq-kasli-opticlock/build.sh b/conda/artiq-kasli-opticlock/build.sh index c69d49191..eb20aa328 100644 --- a/conda/artiq-kasli-opticlock/build.sh +++ b/conda/artiq-kasli-opticlock/build.sh @@ -1,6 +1,6 @@ #!/bin/bash -SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/kasli-opticlock +SOC_PREFIX=$SP_DIR/artiq/binaries/kasli-opticlock mkdir -p $SOC_PREFIX V=1 $PYTHON -m artiq.gateware.targets.kasli -V opticlock diff --git a/conda/artiq-kc705-nist_clock/build.sh b/conda/artiq-kc705-nist_clock/build.sh index dcad86304..7a7ff66a2 100644 --- a/conda/artiq-kc705-nist_clock/build.sh +++ b/conda/artiq-kc705-nist_clock/build.sh @@ -1,6 +1,6 @@ #!/bin/bash -SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/kc705-nist_clock +SOC_PREFIX=$SP_DIR/artiq/binaries/kc705-nist_clock mkdir -p $SOC_PREFIX V=1 $PYTHON -m artiq.gateware.targets.kc705 -V nist_clock diff --git a/conda/artiq-kc705-nist_qc2/build.sh b/conda/artiq-kc705-nist_qc2/build.sh index 4610d14f6..5e8d7cbdc 100644 --- a/conda/artiq-kc705-nist_qc2/build.sh +++ b/conda/artiq-kc705-nist_qc2/build.sh @@ -1,6 +1,6 @@ #!/bin/bash -SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/kc705-nist_qc2 +SOC_PREFIX=$SP_DIR/artiq/binaries/kc705-nist_qc2 mkdir -p $SOC_PREFIX V=1 $PYTHON -m artiq.gateware.targets.kc705 -V nist_qc2 diff --git a/conda/artiq-sayma-standalone/build.sh b/conda/artiq-sayma-standalone/build.sh index 824329f3e..db7a45f7f 100644 --- a/conda/artiq-sayma-standalone/build.sh +++ b/conda/artiq-sayma-standalone/build.sh @@ -2,7 +2,7 @@ RTM_PREFIX=$SP_DIR/artiq/binaries/sayma_rtm -SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/sayma-standalone +SOC_PREFIX=$SP_DIR/artiq/binaries/sayma-standalone mkdir -p $SOC_PREFIX $PYTHON -m artiq.gateware.targets.sayma_amc -V standalone \ diff --git a/conda/artiq-sayma_rtm/build.sh b/conda/artiq-sayma_rtm/build.sh index 282ad44d2..28389ece4 100644 --- a/conda/artiq-sayma_rtm/build.sh +++ b/conda/artiq-sayma_rtm/build.sh @@ -1,6 +1,6 @@ #!/bin/bash -SOC_PREFIX=$PREFIX/lib/python3.5/site-packages/artiq/binaries/sayma_rtm +SOC_PREFIX=$SP_DIR/artiq/binaries/sayma_rtm mkdir -p $SOC_PREFIX $PYTHON -m artiq.gateware.targets.sayma_rtm From 9a94482c6ea712865314f6683cbff515e2b7b3cb Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 28 Jan 2018 15:18:52 +0000 Subject: [PATCH 0295/2457] conda: fix typo in 885ab409. --- conda/artiq-sayma_rtm/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-sayma_rtm/build.sh b/conda/artiq-sayma_rtm/build.sh index 28389ece4..83e505221 100644 --- a/conda/artiq-sayma_rtm/build.sh +++ b/conda/artiq-sayma_rtm/build.sh @@ -4,5 +4,5 @@ SOC_PREFIX=$SP_DIR/artiq/binaries/sayma_rtm mkdir -p $SOC_PREFIX $PYTHON -m artiq.gateware.targets.sayma_rtm -cp artiq_sayma/rtm/rtm.bit $SOC_PREFIX -cp artiq_sayma/rtm/rtm_csr.csv $SOC_PREFIX +cp artiq_sayma/rtm_gateware/rtm.bit $SOC_PREFIX +cp artiq_sayma/rtm_gateware/rtm_csr.csv $SOC_PREFIX From 0edc34a9e5d3790a6692af33e16dff45924e2c5b Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 28 Jan 2018 14:57:43 +0000 Subject: [PATCH 0296/2457] artiq_devtool: the proxy artiq_flash action doesn't exist anymore. --- artiq/frontend/artiq_devtool.py | 4 ++-- artiq/frontend/artiq_flash.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index ae54960a0..e13752f97 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -166,11 +166,11 @@ def main(): elif action == "flash": logger.info("Flashing and booting firmware") - flash("proxy", "bootloader", "firmware", "start") + flash("bootloader", "firmware", "start") elif action == "flash+log": logger.info("Flashing firmware") - flash("proxy", "bootloader", "firmware") + flash("bootloader", "firmware") flterm = client.spawn_command(["flterm", serial, "--output-only"]) logger.info("Booting firmware") diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 12d1855e9..0da7fb945 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -23,7 +23,6 @@ def get_argparser(): epilog="""\ Valid actions: - * proxy: load the flash proxy gateware bitstream * gateware: write gateware bitstream to flash * bootloader: write bootloader to flash * storage: write storage image to flash From a669652854e8978ee8c7fbc6b49183183455c7f0 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 30 Jan 2018 03:12:06 +0000 Subject: [PATCH 0297/2457] artiq_flash: tell openocd to not listen on any network ports. --- artiq/frontend/artiq_flash.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 0da7fb945..eff7c8aa5 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -103,7 +103,11 @@ class Programmer: def __init__(self, client, preinit_script): self._client = client self._board_script = [] - self._preinit_script = preinit_script + self._preinit_script = [ + "gdb_port disabled", + "tcl_port disabled", + "telnet_port disabled" + ] + preinit_script self._loaded = defaultdict(lambda: None) self._script = [] From 807eb1155b1489aba58de92d45739684ee3033f1 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 30 Jan 2018 03:29:08 +0000 Subject: [PATCH 0298/2457] Update smoltcp. Fixes #902. --- artiq/firmware/Cargo.lock | 10 +++++----- artiq/firmware/bootloader/Cargo.toml | 2 +- artiq/firmware/libboard/Cargo.toml | 2 +- artiq/firmware/runtime/Cargo.toml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 863b990a0..044d1ff8f 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -30,7 +30,7 @@ dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=1c765ad)", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=888b1d2)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", ] [[package]] @@ -52,7 +52,7 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=888b1d2)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", ] [[package]] @@ -218,7 +218,7 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "logger_artiq 0.0.0", "proto 0.0.0", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=888b1d2)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", "std_artiq 0.0.0", ] @@ -249,7 +249,7 @@ dependencies = [ [[package]] name = "smoltcp" version = "0.4.0" -source = "git+https://github.com/m-labs/smoltcp?rev=888b1d2#888b1d2403de79083ad9840ea8c6d93039555db3" +source = "git+https://github.com/m-labs/smoltcp?rev=181083f#181083f18c977b8a0463a67e360e4db20594fa21" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -297,7 +297,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" "checksum managed 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "786bd3519bdfb0e1a57146a74b7584555dd6c4f1b6e1137c70e177d60dde8186" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" -"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=888b1d2)" = "" +"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)" = "" "checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml index 5d479ddd9..506a56a9b 100644 --- a/artiq/firmware/bootloader/Cargo.toml +++ b/artiq/firmware/bootloader/Cargo.toml @@ -19,6 +19,6 @@ board = { path = "../libboard", features = ["uart_console", "smoltcp"] } [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "888b1d2" +rev = "181083f" default-features = false features = ["proto-ipv4", "socket-tcp"] diff --git a/artiq/firmware/libboard/Cargo.toml b/artiq/firmware/libboard/Cargo.toml index 111d66738..f00a23abc 100644 --- a/artiq/firmware/libboard/Cargo.toml +++ b/artiq/firmware/libboard/Cargo.toml @@ -22,7 +22,7 @@ features = ["mem"] [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "888b1d2" +rev = "181083f" default-features = false optional = true diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 0d3514c12..e76add67b 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -35,6 +35,6 @@ features = ["alloc"] [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "888b1d2" +rev = "181083f" default-features = false features = ["alloc", "log", "proto-ipv4", "socket-tcp"] From fb8c779b4f138f6fcb0d33d061a777dc089bb5ac Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 30 Jan 2018 14:56:50 +0800 Subject: [PATCH 0299/2457] artiq_flash: report XADC data * bump openocd * only kasli, kc705, sayma rtm so far --- artiq/frontend/artiq_flash.py | 12 ++++++++---- conda/artiq-dev/meta.yaml | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index eff7c8aa5..c3f5ec7cf 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -109,7 +109,7 @@ class Programmer: "telnet_port disabled" ] + preinit_script self._loaded = defaultdict(lambda: None) - self._script = [] + self._script = ["init"] def _transfer_script(self, script): if isinstance(self._client, LocalClient): @@ -174,7 +174,6 @@ class Programmer: return [ *self._board_script, *self._preinit_script, - "init", *self._script, "exit" ] @@ -204,6 +203,8 @@ class ProgrammerXC7(Programmer): boardfile=self._transfer_script("board/{}.cfg".format(board))) self.add_flash_bank("spi0", "xc7", index=0) + add_commands(self._script, "xadc_report xc7.tap") + def load_proxy(self): self.load(find_proxy_bitfile(self._proxy), pld=0) @@ -219,6 +220,8 @@ class ProgrammerSayma(Programmer): Programmer.__init__(self, client, preinit_script) add_commands(self._board_script, + "source {}".format(self._transfer_script("fpga/xilinx-xadc.cfg")), + "interface ftdi", "ftdi_device_desc \"Quad RS232-HS\"", "ftdi_vid_pid 0x0403 0x6011", @@ -237,12 +240,13 @@ class ProgrammerSayma(Programmer): self.add_flash_bank("spi0", "xcu", index=0) self.add_flash_bank("spi1", "xcu", index=1) + add_commands(self._script, "echo \"RTM FPGA XADC:\"", "xadc_report xc7.tap") + def load_proxy(self): self.load(find_proxy_bitfile("bscan_spi_xcku040-sayma.bit"), pld=1) def start(self): - add_commands(self._script, - "xcu_program xcu.tap") + add_commands(self._script, "xcu_program xcu.tap") def main(): diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index aea27db84..86797ac9d 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -22,7 +22,7 @@ requirements: - llvm-or1k 4.0.1 - llvmlite-artiq 0.20.0 - rust-core-or1k 1.23.0 19 - - openocd 0.10.0+git2 + - openocd 0.10.0 4 - lit - outputcheck - coverage From 9fca7b8faa5fe43a1de83c6f709676ef7d1293da Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 30 Jan 2018 15:17:11 +0800 Subject: [PATCH 0300/2457] artiq_flash: also report sayma AMC SYSMONE1 data requires hardware patch (https://github.com/m-labs/sinara/issues/495) --- artiq/frontend/artiq_flash.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index c3f5ec7cf..16bcdef37 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -241,6 +241,7 @@ class ProgrammerSayma(Programmer): self.add_flash_bank("spi1", "xcu", index=1) add_commands(self._script, "echo \"RTM FPGA XADC:\"", "xadc_report xc7.tap") + add_commands(self._script, "echo \"AMC FPGA XADC:\"", "xadc_report xcu.tap") def load_proxy(self): self.load(find_proxy_bitfile("bscan_spi_xcku040-sayma.bit"), pld=1) From 4c22d64ee438d8b65ba728829794698191719181 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 30 Jan 2018 08:36:55 +0100 Subject: [PATCH 0301/2457] conda: sync artiq/artiq-dev dependencies --- conda/artiq-dev/meta.yaml | 2 +- conda/artiq/meta.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 86797ac9d..4b5abf404 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -38,7 +38,7 @@ requirements: - python-dateutil - pyqt >=5.5 - quamash - - pyqtgraph + - pyqtgraph 0.10.0 - pygit2 - aiohttp - pythonparser >=1.1 diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index 3ba815985..065c4150b 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -27,9 +27,9 @@ requirements: run: - python >=3.5.3,<3.6 - llvmlite-artiq 0.20.0 - - binutils-or1k-linux + - binutils-or1k-linux >=2.27 - pythonparser >=1.1 - - openocd 0.10.0+git1 + - openocd 0.10.0 4 - lit - outputcheck - scipy From e50bebb63db94c72bfc7fe8b8b802cc9b820c1e5 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 5 Feb 2018 13:39:30 +0100 Subject: [PATCH 0302/2457] firmware/liboard_artiq/ad9154.rs: add checks for jesd subclass 1 (verify that we receive the sysref and that phase error is within the specified window error threshold). --- artiq/firmware/libboard_artiq/ad9154.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index d30cb6adf..c683ccc47 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -374,9 +374,15 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { 1*ad9154_reg::SYNCARM | 0*ad9154_reg::SYNCCLRSTKY | 0*ad9154_reg::SYNCCLRLAST); clock::spin_us(1000); // ensure at least one sysref edge + if read(ad9154_reg::SYNC_CONTROL) & ad9154_reg::SYNCARM != 0 { + return Err("AD9154 no sysref edge"); + } if read(ad9154_reg::SYNC_STATUS) & ad9154_reg::SYNC_LOCK == 0 { return Err("AD9154 no sync lock"); } + if read(ad9154_reg::SYNC_STATUS) & ad9154_reg::SYNC_WLIM != 0 { + return Err("AD9154 sysref phase error"); + } write(ad9154_reg::XBAR_LN_0_1, 0*ad9154_reg::LOGICAL_LANE0_SRC | 1*ad9154_reg::LOGICAL_LANE1_SRC); write(ad9154_reg::XBAR_LN_2_3, From e80b4810322e8883bb946c0ee2accecfabb063be Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 5 Feb 2018 13:40:17 +0100 Subject: [PATCH 0303/2457] firmware/libboard_artiq/hmc830_7043.rs: add template for sys_ref phase configuration for dac1/dac2 and fpga --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index ee456beb9..7e5cf3971 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -180,10 +180,21 @@ mod hmc7043 { for &(addr, data) in HMC7043_WRITES.iter() { write(addr, data); } - /* sysref digital coarse delay configuration (18 steps, 1/2VCO cycle/step)*/ - write(0x112, 0x0); - /* sysref analog fine delay configuration (24 steps, 25ps/step)*/ - write(0x111, 0x0); + + /* dac1 sysref digital coarse delay configuration (17 steps, 1/2VCO cycle/step)*/ + write(0x0d6, 0); + /* dac1 sysref analog fine delay configuration (24 steps, 25ps/step)*/ + write(0x0d5, 0); + + /* dac2 sysref digital coarse delay configuration (17 steps, 1/2VCO cycle/step)*/ + write(0x0ea, 0); + /* dac2 sysref analog fine delay configuration (24 steps, 25ps/step)*/ + write(0x0e9, 0); + + /* fpga sysref digital coarse delay configuration (17 steps, 1/2VCO cycle/step)*/ + write(0x112, 0); + /* fpga sysref analog fine delay configuration (24 steps, 25ps/step)*/ + write(0x111, 0); Ok(()) } From 61c64a76bea0aece490daa89f43b93f07e820c9a Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 6 Feb 2018 08:18:56 +0000 Subject: [PATCH 0304/2457] gateware: use a per-variant subfolder in --output-dir. (fixes #912) This commit also adds support for --variant and --args to artiq-devtool. --- artiq/frontend/artiq_devtool.py | 24 +++++++++++++++++++----- artiq/frontend/artiq_flash.py | 12 ++++++------ artiq/gateware/targets/kasli.py | 3 ++- artiq/gateware/targets/kc705.py | 3 ++- conda/artiq-dev/meta.yaml | 2 +- conda/artiq-kasli-opticlock/build.sh | 6 +++--- conda/artiq-kc705-nist_clock/build.sh | 6 +++--- conda/artiq-kc705-nist_qc2/build.sh | 6 +++--- conda/artiq-sayma-standalone/build.sh | 6 +++--- 9 files changed, 42 insertions(+), 26 deletions(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index e13752f97..2e9f4ae84 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -14,6 +14,7 @@ import threading import os import shutil import re +import shlex from artiq.tools import verbosity_args, init_logger from artiq.remoting import SSHClient @@ -32,9 +33,16 @@ def get_argparser(): type=str, default="kc705", help="target to build, one of: " "kc705 kasli sayma") + parser.add_argument("-V", "--variant", metavar="VARIANT", + type=str, default=None, + help="variant to build, dependent on the target") parser.add_argument("-g", "--build-gateware", default=False, action="store_true", help="build gateware, not just software") + parser.add_argument("--args", metavar="ARGS", + type=shlex.split, default=[], + help="extra arguments for gateware/firmware build") + parser.add_argument("-H", "--host", type=str, default="lab.m-labs.hk", help="SSH host where the development board is located") @@ -69,7 +77,7 @@ def main(): logging.getLogger().setLevel(logging.INFO) def build_dir(*path, target=args.target): - return os.path.join("/tmp", target, *path) + return os.path.join("/tmp/", "artiq_" + target, *path) if args.target == "kc705": board_type, firmware = "kc705", "runtime" @@ -122,16 +130,19 @@ def main(): sys.exit(1) def command(*args, on_failure="Command failed"): + logger.debug("Running {}".format(" ".join([shlex.quote(arg) for arg in args]))) try: subprocess.check_call(args) except subprocess.CalledProcessError: logger.error(on_failure) sys.exit(1) - def build(target, *extra_args, output_dir=build_dir()): + def build(target, *extra_args, output_dir=build_dir(), variant=args.variant): build_args = ["python3", "-m", "artiq.gateware.targets." + target, *extra_args] if not args.build_gateware: build_args.append("--no-compile-gateware") + if variant: + build_args += ["--variant", args.variant] build_args += ["--output-dir", output_dir] command(*build_args, on_failure="Build failed") @@ -141,9 +152,12 @@ def main(): flash_args = ["artiq_flash"] for _ in range(args.verbose): flash_args.append("-v") - flash_args += ["-H", args.host, "-t", board_type] + flash_args += ["-H", args.host] + flash_args += ["-t", board_type] + if args.variant: + flash_args += ["-V", args.variant] + flash_args += ["-I", "source {}".format(board_file)] flash_args += ["--srcbuild", build_dir()] - flash_args += ["--preinit-command", "source {}".format(board_file)] flash_args += steps command(*flash_args, on_failure="Flashing failed") @@ -151,7 +165,7 @@ def main(): if action == "build": logger.info("Building target") if args.target == "sayma": - build("sayma_rtm", output_dir=build_dir("rtm_gateware")) + build("sayma_rtm", output_dir=build_dir("rtm_gateware"), variant=None) build("sayma_amc", "--rtm-csr-csv", build_dir("rtm_gateware", "rtm_csr.csv")) else: build(args.target) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 16bcdef37..ee5c93994 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -312,17 +312,17 @@ def main(): try: for action in args.action: if action == "gateware": - gateware_bin = artifact_path("gateware", "top.bin") + gateware_bin = artifact_path(variant, "gateware", "top.bin") if not os.access(gateware_bin, os.R_OK): bin_handle, gateware_bin = tempfile.mkstemp() - gateware_bit = artifact_path("gateware", "top.bit") + gateware_bit = artifact_path(variant, "gateware", "top.bit") with open(gateware_bit, "rb") as bit_file, open(bin_handle, "wb") as bin_file: bit2bin(bit_file, bin_file) atexit.register(lambda: os.unlink(gateware_bin)) programmer.write_binary(*config["gateware"], gateware_bin) elif action == "bootloader": - bootloader_bin = artifact_path("software", "bootloader", "bootloader.bin") + bootloader_bin = artifact_path(variant, "software", "bootloader", "bootloader.bin") programmer.write_binary(*config["bootloader"], bootloader_bin) elif action == "storage": storage_img = args.storage @@ -333,16 +333,16 @@ def main(): else: firmware = "runtime" - firmware_fbi = artifact_path("software", firmware, firmware + ".fbi") + firmware_fbi = artifact_path(variant, "software", firmware, firmware + ".fbi") programmer.write_binary(*config["firmware"], firmware_fbi) elif action == "load": if args.target == "sayma": rtm_gateware_bit = artifact_path("rtm_gateware", "rtm.bit") programmer.load(rtm_gateware_bit, 0) - gateware_bit = artifact_path("gateware", "top.bit") + gateware_bit = artifact_path(variant, "gateware", "top.bit") programmer.load(gateware_bit, 1) else: - gateware_bit = artifact_path("gateware", "top.bit") + gateware_bit = artifact_path(variant, "gateware", "top.bit") programmer.load(gateware_bit, 0) elif action == "start": programmer.start() diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 3326ebd1d..033fdcd54 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -248,7 +248,7 @@ class Master(MiniSoC, AMPSoC): phy = ttl_simple.Output(platform.request("sfp_ctl", 1).led) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - + self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") @@ -381,6 +381,7 @@ def main(): description="ARTIQ device binary builder for Kasli systems") builder_args(parser) soc_kasli_args(parser) + parser.set_defaults(output_dir="artiq_kasli") parser.add_argument("-V", "--variant", default="opticlock", help="variant: opticlock/master/satellite " "(default: %(default)s)") diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 771bdb4bf..7b868910d 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -329,7 +329,7 @@ class NIST_CLOCK(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=128)) - + phy = spi.SPIMaster(platform.request("sdcard_spi_33")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( @@ -526,6 +526,7 @@ def main(): description="KC705 gateware and firmware builder") builder_args(parser) soc_kc705_args(parser) + parser.set_defaults(output_dir="artiq_kc705") parser.add_argument("-V", "--variant", default="nist_clock", help="variant: " "nist_clock/nist_qc2/sma_spi " diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 4b5abf404..7e2a3d049 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.6 py35_11+git78a671d - - misoc 0.8 py35_54+gitcb8e314c + - misoc 0.9 py35_1+git2e2b7838 - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 diff --git a/conda/artiq-kasli-opticlock/build.sh b/conda/artiq-kasli-opticlock/build.sh index eb20aa328..cceb4f7ff 100644 --- a/conda/artiq-kasli-opticlock/build.sh +++ b/conda/artiq-kasli-opticlock/build.sh @@ -4,6 +4,6 @@ SOC_PREFIX=$SP_DIR/artiq/binaries/kasli-opticlock mkdir -p $SOC_PREFIX V=1 $PYTHON -m artiq.gateware.targets.kasli -V opticlock -cp misoc_opticlock_kasli/gateware/top.bit $SOC_PREFIX -cp misoc_opticlock_kasli/software/bootloader/bootloader.bin $SOC_PREFIX -cp misoc_opticlock_kasli/software/runtime/runtime.{elf,fbi} $SOC_PREFIX +cp artiq_kasli/opticlock/gateware/top.bit $SOC_PREFIX +cp artiq_kasli/opticlock/software/bootloader/bootloader.bin $SOC_PREFIX +cp artiq_kasli/opticlock/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-kc705-nist_clock/build.sh b/conda/artiq-kc705-nist_clock/build.sh index 7a7ff66a2..402b0b18f 100644 --- a/conda/artiq-kc705-nist_clock/build.sh +++ b/conda/artiq-kc705-nist_clock/build.sh @@ -4,6 +4,6 @@ SOC_PREFIX=$SP_DIR/artiq/binaries/kc705-nist_clock mkdir -p $SOC_PREFIX V=1 $PYTHON -m artiq.gateware.targets.kc705 -V nist_clock -cp misoc_nist_clock_kc705/gateware/top.bit $SOC_PREFIX -cp misoc_nist_clock_kc705/software/bootloader/bootloader.bin $SOC_PREFIX -cp misoc_nist_clock_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX +cp artiq_kc705/nist_clock/gateware/top.bit $SOC_PREFIX +cp artiq_kc705/nist_clock/software/bootloader/bootloader.bin $SOC_PREFIX +cp artiq_kc705/nist_clock/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-kc705-nist_qc2/build.sh b/conda/artiq-kc705-nist_qc2/build.sh index 5e8d7cbdc..03479e29f 100644 --- a/conda/artiq-kc705-nist_qc2/build.sh +++ b/conda/artiq-kc705-nist_qc2/build.sh @@ -4,6 +4,6 @@ SOC_PREFIX=$SP_DIR/artiq/binaries/kc705-nist_qc2 mkdir -p $SOC_PREFIX V=1 $PYTHON -m artiq.gateware.targets.kc705 -V nist_qc2 -cp misoc_nist_qc2_kc705/gateware/top.bit $SOC_PREFIX -cp misoc_nist_qc2_kc705/software/bootloader/bootloader.bin $SOC_PREFIX -cp misoc_nist_qc2_kc705/software/runtime/runtime.{elf,fbi} $SOC_PREFIX +cp artiq_kc705/nist_qc2/gateware/top.bit $SOC_PREFIX +cp artiq_kc705/nist_qc2/software/bootloader/bootloader.bin $SOC_PREFIX +cp artiq_kc705/nist_qc2/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-sayma-standalone/build.sh b/conda/artiq-sayma-standalone/build.sh index db7a45f7f..065201ba1 100644 --- a/conda/artiq-sayma-standalone/build.sh +++ b/conda/artiq-sayma-standalone/build.sh @@ -7,7 +7,7 @@ mkdir -p $SOC_PREFIX $PYTHON -m artiq.gateware.targets.sayma_amc -V standalone \ --rtm-csr-csv $RTM_PREFIX/rtm_csr.csv -cp artiq_sayma/gateware/top.bit $SOC_PREFIX -cp artiq_sayma/software/bootloader/bootloader.bin $SOC_PREFIX -cp artiq_sayma/software/runtime/runtime.{elf,fbi} $SOC_PREFIX +cp artiq_sayma/standalone/gateware/top.bit $SOC_PREFIX +cp artiq_sayma/standalone/software/bootloader/bootloader.bin $SOC_PREFIX +cp artiq_sayma/standalone/software/runtime/runtime.{elf,fbi} $SOC_PREFIX cp $RTM_PREFIX/rtm.bit $SOC_PREFIX From 2d4a1340ea3a25dbaaa2200b7e86d2f42e7a19b5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Feb 2018 12:27:35 +0800 Subject: [PATCH 0305/2457] sayma_amc: remove RTM bitstream upload core. Closes #908 --- artiq/gateware/targets/sayma_amc.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index c45f8d37a..b25a924cb 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -160,9 +160,10 @@ class Standalone(MiniSoC, AMPSoC): ] # RTM bitstream upload - rtm_fpga_cfg = platform.request("rtm_fpga_cfg") - self.submodules.rtm_fpga_cfg = SlaveFPGA(rtm_fpga_cfg) - self.csr_devices.append("rtm_fpga_cfg") + # https://github.com/m-labs/artiq/issues/908#issuecomment-363650534 + #rtm_fpga_cfg = platform.request("rtm_fpga_cfg") + #self.submodules.rtm_fpga_cfg = SlaveFPGA(rtm_fpga_cfg) + #self.csr_devices.append("rtm_fpga_cfg") # AMC/RTM serwb serwb_pll = serwb.phy.SERWBPLL(125e6, 625e6, vco_div=2) From 180c28551d62a7980b8d2fc5157221fa77c78e0d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 9 Feb 2018 20:17:02 +0100 Subject: [PATCH 0306/2457] drtio/gateware/transceiver/gtp_7series: add power down state before reset on rx (seems to make restart reliable) --- artiq/gateware/drtio/transceiver/gtp_7series.py | 1 + artiq/gateware/drtio/transceiver/gtp_7series_init.py | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py index 470c3e7ba..4c9e94e2b 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -111,6 +111,7 @@ class GTPSingle(Module): # RX Startup/Reset i_GTRXRESET=rx_init.gtrxreset, + i_RXPD=Cat(rx_init.gtrxpd, rx_init.gtrxpd), o_RXRESETDONE=rx_init.rxresetdone, i_RXDLYSRESET=rx_init.rxdlysreset, o_RXDLYSRESETDONE=rx_init.rxdlysresetdone, diff --git a/artiq/gateware/drtio/transceiver/gtp_7series_init.py b/artiq/gateware/drtio/transceiver/gtp_7series_init.py index e3f2d9316..e544a90b2 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series_init.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series_init.py @@ -146,6 +146,7 @@ class GTPRXInit(Module): # GTP signals self.plllock = Signal() self.gtrxreset = Signal() + self.gtrxpd = Signal() self.rxresetdone = Signal() self.rxdlysreset = Signal() self.rxdlysresetdone = Signal() @@ -194,12 +195,14 @@ class GTPRXInit(Module): # Deglitch FSM outputs driving transceiver asynch inputs gtrxreset = Signal() + gtrxpd = Signal() rxdlysreset = Signal() rxphalign = Signal() rxdlyen = Signal() rxuserrdy = Signal() self.sync += [ self.gtrxreset.eq(gtrxreset), + self.gtrxpd.eq(gtrxpd), self.rxdlysreset.eq(rxdlysreset), self.rxphalign.eq(rxphalign), self.rxdlyen.eq(rxdlyen), @@ -212,7 +215,7 @@ class GTPRXInit(Module): pll_reset_timer = WaitTimer(pll_reset_cycles) self.submodules += pll_reset_timer - startup_fsm = ResetInserter()(FSM(reset_state="GTP_RESET")) + startup_fsm = ResetInserter()(FSM(reset_state="GTP_PD")) self.submodules += startup_fsm ready_timer = WaitTimer(int(4e-3*sys_clk_freq)) @@ -225,6 +228,11 @@ class GTPRXInit(Module): cdr_stable_timer = WaitTimer(1024) self.submodules += cdr_stable_timer + startup_fsm.act("GTP_PD", + gtrxreset.eq(1), + gtrxpd.eq(1), + NextState("GTP_RESET") + ) startup_fsm.act("GTP_RESET", gtrxreset.eq(1), NextState("DRP_READ_ISSUE") @@ -300,6 +308,6 @@ class GTPRXInit(Module): startup_fsm.act("READY", rxuserrdy.eq(1), self.done.eq(1), - If(self.restart, NextState("GTP_RESET") + If(self.restart, NextState("GTP_PD") ) ) From bfdda340fdc678cfcc4d349c5dcaf058ec570534 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 13 Feb 2018 00:23:59 +0100 Subject: [PATCH 0307/2457] drtio/transceiver/gtp_7series: use parameters from xilinx wizard --- .../gateware/drtio/transceiver/gtp_7series.py | 688 +++++++++++++++--- 1 file changed, 582 insertions(+), 106 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py index 4c9e94e2b..6ea82de9c 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -44,124 +44,600 @@ class GTPSingle(Module): rxdata = Signal(20) rxphaligndone = Signal() gtp_params = dict( - # Reset modes - i_GTRESETSEL=0, - i_RESETOVRD=0, + # Simulation-Only Attributes + p_SIM_RECEIVER_DETECT_PASS ="TRUE", + p_SIM_TX_EIDLE_DRIVE_LEVEL ="X", + p_SIM_RESET_SPEEDUP ="FALSE", + p_SIM_VERSION ="2.0", - # DRP - i_DRPADDR=rx_init.drpaddr, - i_DRPCLK=ClockSignal("rtio_tx"), - i_DRPDI=rx_init.drpdi, - o_DRPDO=rx_init.drpdo, - i_DRPEN=rx_init.drpen, - o_DRPRDY=rx_init.drprdy, - i_DRPWE=rx_init.drpwe, + # RX Byte and Word Alignment Attributes + p_ALIGN_COMMA_DOUBLE ="FALSE", + p_ALIGN_COMMA_ENABLE =0b1111111111, + p_ALIGN_COMMA_WORD =1, + p_ALIGN_MCOMMA_DET ="TRUE", + p_ALIGN_MCOMMA_VALUE =0b1010000011, + p_ALIGN_PCOMMA_DET ="TRUE", + p_ALIGN_PCOMMA_VALUE =0b0101111100, + p_SHOW_REALIGN_COMMA ="FALSE", + p_RXSLIDE_AUTO_WAIT =7, + p_RXSLIDE_MODE ="PCS", + p_RX_SIG_VALID_DLY =10, - # PMA Attributes - p_PMA_RSV=0x333, - p_PMA_RSV2=0x2040, - p_PMA_RSV3=0, - p_PMA_RSV4=0, - p_RX_BIAS_CFG=0b0000111100110011, - p_RX_CM_SEL=0b01, - p_RX_CM_TRIM=0b1010, - p_RX_OS_CFG=0b10000000, - p_RXLPM_IPCM_CFG=1, - i_RXELECIDLEMODE=0b11, - i_RXOSINTCFG=0b0010, - i_RXOSINTEN=1, + # RX 8B/10B Decoder Attributes + p_RX_DISPERR_SEQ_MATCH ="FALSE", + p_DEC_MCOMMA_DETECT ="TRUE", + p_DEC_PCOMMA_DETECT ="TRUE", + p_DEC_VALID_COMMA_ONLY ="FALSE", - # Power-Down Attributes - p_PD_TRANS_TIME_FROM_P2=0x3c, - p_PD_TRANS_TIME_NONE_P2=0x3c, - p_PD_TRANS_TIME_TO_P2=0x64, + # RX Clock Correction Attributes + p_CBCC_DATA_SOURCE_SEL ="ENCODED", + p_CLK_COR_SEQ_2_USE ="FALSE", + p_CLK_COR_KEEP_IDLE ="FALSE", + p_CLK_COR_MAX_LAT =9, + p_CLK_COR_MIN_LAT =7, + p_CLK_COR_PRECEDENCE ="TRUE", + p_CLK_COR_REPEAT_WAIT =0, + p_CLK_COR_SEQ_LEN =1, + p_CLK_COR_SEQ_1_ENABLE =0b1111, + p_CLK_COR_SEQ_1_1 =0b0100000000, + p_CLK_COR_SEQ_1_2 =0b0000000000, + p_CLK_COR_SEQ_1_3 =0b0000000000, + p_CLK_COR_SEQ_1_4 =0b0000000000, + p_CLK_CORRECT_USE ="FALSE", + p_CLK_COR_SEQ_2_ENABLE =0b1111, + p_CLK_COR_SEQ_2_1 =0b0100000000, + p_CLK_COR_SEQ_2_2 =0b0000000000, + p_CLK_COR_SEQ_2_3 =0b0000000000, + p_CLK_COR_SEQ_2_4 =0b0000000000, - # TX clock - p_TXBUF_EN="FALSE", - p_TX_XCLK_SEL="TXUSR", - o_TXOUTCLK=self.txoutclk, - p_TXOUT_DIV=2, - i_TXOUTCLKSEL=0b11, + # RX Channel Bonding Attributes + p_CHAN_BOND_KEEP_ALIGN ="FALSE", + p_CHAN_BOND_MAX_SKEW =1, + p_CHAN_BOND_SEQ_LEN =1, + p_CHAN_BOND_SEQ_1_1 =0b0000000000, + p_CHAN_BOND_SEQ_1_2 =0b0000000000, + p_CHAN_BOND_SEQ_1_3 =0b0000000000, + p_CHAN_BOND_SEQ_1_4 =0b0000000000, + p_CHAN_BOND_SEQ_1_ENABLE =0b1111, + p_CHAN_BOND_SEQ_2_1 =0b0000000000, + p_CHAN_BOND_SEQ_2_2 =0b0000000000, + p_CHAN_BOND_SEQ_2_3 =0b0000000000, + p_CHAN_BOND_SEQ_2_4 =0b0000000000, + p_CHAN_BOND_SEQ_2_ENABLE =0b1111, + p_CHAN_BOND_SEQ_2_USE ="FALSE", + p_FTS_DESKEW_SEQ_ENABLE =0b1111, + p_FTS_LANE_DESKEW_CFG =0b1111, + p_FTS_LANE_DESKEW_EN ="FALSE", - # TX Startup/Reset - i_GTTXRESET=tx_init.gttxreset, - o_TXRESETDONE=tx_init.txresetdone, - p_TXSYNC_OVRD=1, - i_TXDLYSRESET=tx_init.txdlysreset, - o_TXDLYSRESETDONE=tx_init.txdlysresetdone, - i_TXPHINIT=tx_init.txphinit, - o_TXPHINITDONE=tx_init.txphinitdone, - i_TXPHALIGNEN=1, - i_TXPHALIGN=tx_init.txphalign, - o_TXPHALIGNDONE=tx_init.txphaligndone, - i_TXDLYEN=tx_init.txdlyen, - i_TXUSERRDY=tx_init.txuserrdy, + # RX Margin Analysis Attributes + p_ES_CONTROL =0b000000, + p_ES_ERRDET_EN ="FALSE", + p_ES_EYE_SCAN_EN ="FALSE", + p_ES_HORZ_OFFSET =0x010, + p_ES_PMA_CFG =0b0000000000, + p_ES_PRESCALE =0b00000, + p_ES_QUALIFIER =0x00000000000000000000, + p_ES_QUAL_MASK =0x00000000000000000000, + p_ES_SDATA_MASK =0x00000000000000000000, + p_ES_VERT_OFFSET =0b000000000, - # TX data - p_TX_DATA_WIDTH=20, - i_TXCHARDISPMODE=Cat(txdata[9], txdata[19]), - i_TXCHARDISPVAL=Cat(txdata[8], txdata[18]), - i_TXDATA=Cat(txdata[:8], txdata[10:18]), - i_TXUSRCLK=ClockSignal("rtio_tx"), - i_TXUSRCLK2=ClockSignal("rtio_tx"), + # FPGA RX Interface Attributes + p_RX_DATA_WIDTH =20, - # TX electrical - i_TXBUFDIFFCTRL=0b100, - i_TXDIFFCTRL=0b1000, + # PMA Attributes + p_OUTREFCLK_SEL_INV =0b11, + p_PMA_RSV =0x00000333, + p_PMA_RSV2 =0x00002040, + p_PMA_RSV3 =0b00, + p_PMA_RSV4 =0b0000, + p_RX_BIAS_CFG =0b0000111100110011, + p_DMONITOR_CFG =0x000A00, + p_RX_CM_SEL =0b01, + p_RX_CM_TRIM =0b0000, + p_RX_DEBUG_CFG =0b00000000000000, + p_RX_OS_CFG =0b0000010000000, + p_TERM_RCAL_CFG =0b100001000010000, + p_TERM_RCAL_OVRD =0b000, + p_TST_RSV =0x00000000, + p_RX_CLK25_DIV =5, + p_TX_CLK25_DIV =5, + p_UCODEER_CLR =0b0, - # RX Startup/Reset - i_GTRXRESET=rx_init.gtrxreset, - i_RXPD=Cat(rx_init.gtrxpd, rx_init.gtrxpd), - o_RXRESETDONE=rx_init.rxresetdone, - i_RXDLYSRESET=rx_init.rxdlysreset, - o_RXDLYSRESETDONE=rx_init.rxdlysresetdone, - o_RXPHALIGNDONE=rxphaligndone, - i_RXSYNCALLIN=rxphaligndone, - i_RXUSERRDY=rx_init.rxuserrdy, - i_RXSYNCIN=0, - i_RXSYNCMODE=1, - p_RXSYNC_MULTILANE=0, - p_RXSYNC_OVRD=0, - o_RXSYNCDONE=rx_init.rxsyncdone, - p_RXPMARESET_TIME=0b11, - o_RXPMARESETDONE=rx_init.rxpmaresetdone, + # PCI Express Attributes + p_PCS_PCIE_EN ="FALSE", - # RX clock - p_RX_CLK25_DIV=5, - p_TX_CLK25_DIV=5, - p_RX_XCLK_SEL="RXUSR", - p_RXOUT_DIV=2, - i_RXOUTCLKSEL=0b010, - o_RXOUTCLK=self.rxoutclk, - i_RXUSRCLK=ClockSignal("rtio_rx"), - i_RXUSRCLK2=ClockSignal("rtio_rx"), - p_RXCDR_CFG=0x0000107FE206001041010, - p_RXPI_CFG1=1, - p_RXPI_CFG2=1, + # PCS Attributes + p_PCS_RSVD_ATTR =0x000000000000, - # RX Clock Correction Attributes - p_CLK_CORRECT_USE="FALSE", + # RX Buffer Attributes + p_RXBUF_ADDR_MODE ="FAST", + p_RXBUF_EIDLE_HI_CNT =0b1000, + p_RXBUF_EIDLE_LO_CNT =0b0000, + p_RXBUF_EN ="FALSE", + p_RX_BUFFER_CFG =0b000000, + p_RXBUF_RESET_ON_CB_CHANGE ="TRUE", + p_RXBUF_RESET_ON_COMMAALIGN ="FALSE", + p_RXBUF_RESET_ON_EIDLE ="FALSE", + p_RXBUF_RESET_ON_RATE_CHANGE ="TRUE", + p_RXBUFRESET_TIME =0b00001, + p_RXBUF_THRESH_OVFLW =61, + p_RXBUF_THRESH_OVRD ="FALSE", + p_RXBUF_THRESH_UNDFLW =4, + p_RXDLY_CFG =0x001F, + p_RXDLY_LCFG =0x030, + p_RXDLY_TAP_CFG =0x0000, + p_RXPH_CFG =0xC00002, + p_RXPHDLY_CFG =0x084020, + p_RXPH_MONITOR_SEL =0b00000, + p_RX_XCLK_SEL ="RXUSR", + p_RX_DDI_SEL =0b000000, + p_RX_DEFER_RESET_BUF_EN ="TRUE", - # RX data - p_RXBUF_EN="FALSE", - p_RXDLY_CFG=0x001f, - p_RXDLY_LCFG=0x030, - p_RXPHDLY_CFG=0x084020, - p_RXPH_CFG=0xc00002, - p_RX_DATA_WIDTH=20, - i_RXCOMMADETEN=1, - i_RXDLYBYPASS=0, - i_RXDDIEN=1, - o_RXDISPERR=Cat(rxdata[9], rxdata[19]), - o_RXCHARISK=Cat(rxdata[8], rxdata[18]), - o_RXDATA=Cat(rxdata[:8], rxdata[10:18]), + # CDR Attributes + p_RXCDR_CFG =0x0001107FE206021081010, + p_RXCDR_FR_RESET_ON_EIDLE =0b0, + p_RXCDR_HOLD_DURING_EIDLE =0b0, + p_RXCDR_PH_RESET_ON_EIDLE =0b0, + p_RXCDR_LOCK_CFG =0b001001, - # Pads - i_GTPRXP=pads.rxp, - i_GTPRXN=pads.rxn, - o_GTPTXP=pads.txp, - o_GTPTXN=pads.txn - ) + # RX Initialization and Reset Attributes + p_RXCDRFREQRESET_TIME =0b00001, + p_RXCDRPHRESET_TIME =0b00001, + p_RXISCANRESET_TIME =0b00001, + p_RXPCSRESET_TIME =0b00001, + p_RXPMARESET_TIME =0b00011, + + # RX OOB Signaling Attributes + p_RXOOB_CFG =0b0000110, + + # RX Gearbox Attributes + p_RXGEARBOX_EN ="FALSE", + p_GEARBOX_MODE =0b000, + + # PRBS Detection Attribute + p_RXPRBS_ERR_LOOPBACK =0b0, + + # Power-Down Attributes + p_PD_TRANS_TIME_FROM_P2 =0x03c, + p_PD_TRANS_TIME_NONE_P2 =0x3c, + p_PD_TRANS_TIME_TO_P2 =0x64, + + # RX OOB Signaling Attributes + p_SAS_MAX_COM =64, + p_SAS_MIN_COM =36, + p_SATA_BURST_SEQ_LEN =0b0101, + p_SATA_BURST_VAL =0b100, + p_SATA_EIDLE_VAL =0b100, + p_SATA_MAX_BURST =8, + p_SATA_MAX_INIT =21, + p_SATA_MAX_WAKE =7, + p_SATA_MIN_BURST =4, + p_SATA_MIN_INIT =12, + p_SATA_MIN_WAKE =4, + + # RX Fabric Clock Output Control Attributes + p_TRANS_TIME_RATE =0x0E, + + # TX Buffer Attributes + p_TXBUF_EN ="FALSE", + p_TXBUF_RESET_ON_RATE_CHANGE ="TRUE", + p_TXDLY_CFG =0x001F, + p_TXDLY_LCFG =0x030, + p_TXDLY_TAP_CFG =0x0000, + p_TXPH_CFG =0x0780, + p_TXPHDLY_CFG =0x084020, + p_TXPH_MONITOR_SEL =0b00000, + p_TX_XCLK_SEL ="TXUSR", + + # FPGA TX Interface Attributes + p_TX_DATA_WIDTH =20, + + # TX Configurable Driver Attributes + p_TX_DEEMPH0 =0b000000, + p_TX_DEEMPH1 =0b000000, + p_TX_EIDLE_ASSERT_DELAY =0b110, + p_TX_EIDLE_DEASSERT_DELAY =0b100, + p_TX_LOOPBACK_DRIVE_HIZ ="FALSE", + p_TX_MAINCURSOR_SEL =0b0, + p_TX_DRIVE_MODE ="DIRECT", + p_TX_MARGIN_FULL_0 =0b1001110, + p_TX_MARGIN_FULL_1 =0b1001001, + p_TX_MARGIN_FULL_2 =0b1000101, + p_TX_MARGIN_FULL_3 =0b1000010, + p_TX_MARGIN_FULL_4 =0b1000000, + p_TX_MARGIN_LOW_0 =0b1000110, + p_TX_MARGIN_LOW_1 =0b1000100, + p_TX_MARGIN_LOW_2 =0b1000010, + p_TX_MARGIN_LOW_3 =0b1000000, + p_TX_MARGIN_LOW_4 =0b1000000, + + # TX Gearbox Attributes + p_TXGEARBOX_EN ="FALSE", + + # TX Initialization and Reset Attributes + p_TXPCSRESET_TIME =0b00001, + p_TXPMARESET_TIME =0b00001, + + # TX Receiver Detection Attributes + p_TX_RXDETECT_CFG =0x1832, + p_TX_RXDETECT_REF =0b100, + + # JTAG Attributes + p_ACJTAG_DEBUG_MODE =0b0, + p_ACJTAG_MODE =0b0, + p_ACJTAG_RESET =0b0, + + # CDR Attributes + p_CFOK_CFG =0x49000040E80, + p_CFOK_CFG2 =0b0100000, + p_CFOK_CFG3 =0b0100000, + p_CFOK_CFG4 =0b0, + p_CFOK_CFG5 =0x0, + p_CFOK_CFG6 =0b0000, + p_RXOSCALRESET_TIME =0b00011, + p_RXOSCALRESET_TIMEOUT =0b00000, + + # PMA Attributes + p_CLK_COMMON_SWING =0b0, + p_RX_CLKMUX_EN =0b1, + p_TX_CLKMUX_EN =0b1, + p_ES_CLK_PHASE_SEL =0b0, + p_USE_PCS_CLK_PHASE_SEL =0b0, + p_PMA_RSV6 =0b0, + p_PMA_RSV7 =0b0, + + # TX Configuration Driver Attributes + p_TX_PREDRIVER_MODE =0b0, + p_PMA_RSV5 =0b0, + p_SATA_PLL_CFG ="VCO_3000MHZ", + + # RX Fabric Clock Output Control Attributes + p_RXOUT_DIV =2, + + # TX Fabric Clock Output Control Attributes + p_TXOUT_DIV =2, + + # RX Phase Interpolator Attributes + p_RXPI_CFG0 =0b000, + p_RXPI_CFG1 =0b1, + p_RXPI_CFG2 =0b1, + + # RX Equalizer Attributes + p_ADAPT_CFG0 =0x00000, + p_RXLPMRESET_TIME =0b0001111, + p_RXLPM_BIAS_STARTUP_DISABLE =0b0, + p_RXLPM_CFG =0b0110, + p_RXLPM_CFG1 =0b0, + p_RXLPM_CM_CFG =0b0, + p_RXLPM_GC_CFG =0b111100010, + p_RXLPM_GC_CFG2 =0b001, + p_RXLPM_HF_CFG =0b00001111110000, + p_RXLPM_HF_CFG2 =0b01010, + p_RXLPM_HF_CFG3 =0b0000, + p_RXLPM_HOLD_DURING_EIDLE =0b0, + p_RXLPM_INCM_CFG =0b0, + p_RXLPM_IPCM_CFG =0b1, + p_RXLPM_LF_CFG =0b000000001111110000, + p_RXLPM_LF_CFG2 =0b01010, + p_RXLPM_OSINT_CFG =0b100, + + # TX Phase Interpolator PPM Controller Attributes + p_TXPI_CFG0 =0b00, + p_TXPI_CFG1 =0b00, + p_TXPI_CFG2 =0b00, + p_TXPI_CFG3 =0b0, + p_TXPI_CFG4 =0b0, + p_TXPI_CFG5 =0b000, + p_TXPI_GREY_SEL =0b0, + p_TXPI_INVSTROBE_SEL =0b0, + p_TXPI_PPMCLK_SEL ="TXUSRCLK2", + p_TXPI_PPM_CFG =0x00, + p_TXPI_SYNFREQ_PPM =0b001, + + # LOOPBACK Attributes + p_LOOPBACK_CFG =0b0, + p_PMA_LOOPBACK_CFG =0b0, + + # RX OOB Signalling Attributes + p_RXOOB_CLK_CFG ="PMA", + + # TX OOB Signalling Attributes + p_TXOOB_CFG =0b0, + + # RX Buffer Attributes + p_RXSYNC_MULTILANE =0b0, + p_RXSYNC_OVRD =0b0, + p_RXSYNC_SKIP_DA =0b0, + + # TX Buffer Attributes + p_TXSYNC_MULTILANE =0b0, + p_TXSYNC_OVRD =0b0, + p_TXSYNC_SKIP_DA =0b0 + ) + gtp_params.update( + # CPLL Ports + i_GTRSVD =0b0000000000000000, + i_PCSRSVDIN =0b0000000000000000, + i_TSTIN =0b11111111111111111111, + + # Channel - DRP Ports + i_DRPADDR=rx_init.drpaddr, + i_DRPCLK=ClockSignal("rtio_tx"), + i_DRPDI=rx_init.drpdi, + o_DRPDO=rx_init.drpdo, + i_DRPEN=rx_init.drpen, + o_DRPRDY=rx_init.drprdy, + i_DRPWE=rx_init.drpwe, + # FPGA TX Interface Datapath Configuration + i_TX8B10BEN =0, + # Loopback Ports + i_LOOPBACK =0, + # PCI Express Ports + #o_PHYSTATUS =, + i_RXRATE =0, + #o_RXVALID =, + # PMA Reserved Ports + i_PMARSVDIN3 =0b0, + i_PMARSVDIN4 =0b0, + # Power-Down Ports + i_RXPD =Cat(rx_init.gtrxpd, rx_init.gtrxpd), + i_TXPD =0b00, + # RX 8B/10B Decoder Ports + i_SETERRSTATUS =0, + # RX Initialization and Reset Ports + i_EYESCANRESET =0, + i_RXUSERRDY =rx_init.rxuserrdy, + # RX Margin Analysis Ports + #o_EYESCANDATAERROR =, + i_EYESCANMODE =0, + i_EYESCANTRIGGER =0, + # Receive Ports + i_CLKRSVD0 =0, + i_CLKRSVD1 =0, + i_DMONFIFORESET =0, + i_DMONITORCLK =0, + o_RXPMARESETDONE =rx_init.rxpmaresetdone, + i_SIGVALIDCLK =0, + # Receive Ports - CDR Ports + i_RXCDRFREQRESET =0, + i_RXCDRHOLD =0, + #o_RXCDRLOCK =, + i_RXCDROVRDEN =0, + i_RXCDRRESET =0, + i_RXCDRRESETRSV =0, + i_RXOSCALRESET =0, + i_RXOSINTCFG =0b0010, + #o_RXOSINTDONE =, + i_RXOSINTHOLD =0, + i_RXOSINTOVRDEN =0, + i_RXOSINTPD =0, + #o_RXOSINTSTARTED =, + i_RXOSINTSTROBE =0, + #o_RXOSINTSTROBESTARTED =, + i_RXOSINTTESTOVRDEN =0, + # Receive Ports - Clock Correction Ports + #o_RXCLKCORCNT =, + # Receive Ports - FPGA RX Interface Datapath Configuration + i_RX8B10BEN =0, + # Receive Ports - FPGA RX Interface Ports + o_RXDATA =Cat(rxdata[:8], rxdata[10:18]), + i_RXUSRCLK =ClockSignal("rtio_rx"), + i_RXUSRCLK2 =ClockSignal("rtio_rx"), + # Receive Ports - Pattern Checker Ports + #o_RXPRBSERR =, + i_RXPRBSSEL =0, + # Receive Ports - Pattern Checker ports + i_RXPRBSCNTRESET =0, + # Receive Ports - RX 8B/10B Decoder Ports + #o_RXCHARISCOMMA =, + o_RXCHARISK =Cat(rxdata[8], rxdata[18]), + o_RXDISPERR =Cat(rxdata[9], rxdata[19]), + + #o_RXNOTINTABLE =, + # Receive Ports - RX AFE Ports + i_GTPRXN =pads.rxn, + i_GTPRXP =pads.rxp, + i_PMARSVDIN2 =0b0, + #o_PMARSVDOUT0 =, + #o_PMARSVDOUT1 =, + # Receive Ports - RX Buffer Bypass Ports + i_RXBUFRESET =0, + #o_RXBUFSTATUS =, + i_RXDDIEN =1, + i_RXDLYBYPASS =0, + i_RXDLYEN =1, + i_RXDLYOVRDEN =0, + i_RXDLYSRESET =rx_init.rxdlysreset, + o_RXDLYSRESETDONE =rx_init.rxdlysresetdone, + i_RXPHALIGN =0, + o_RXPHALIGNDONE =rxphaligndone, + i_RXPHALIGNEN =0, + i_RXPHDLYPD =0, + i_RXPHDLYRESET =0, + #o_RXPHMONITOR =, + i_RXPHOVRDEN =0, + #o_RXPHSLIPMONITOR =, + #o_RXSTATUS =, + i_RXSYNCALLIN =rxphaligndone, + o_RXSYNCDONE =rx_init.rxsyncdone, + i_RXSYNCIN =0, + i_RXSYNCMODE =1, + #o_RXSYNCOUT =, + # Receive Ports - RX Byte and Word Alignment Ports + #o_RXBYTEISALIGNED =, + #o_RXBYTEREALIGN =, + #o_RXCOMMADET =, + i_RXCOMMADETEN =1, + i_RXMCOMMAALIGNEN =0, + i_RXPCOMMAALIGNEN =0, + i_RXSLIDE =0, + # Receive Ports - RX Channel Bonding Ports + #o_RXCHANBONDSEQ =, + i_RXCHBONDEN =0, + i_RXCHBONDI =0b0000, + i_RXCHBONDLEVEL =0, + i_RXCHBONDMASTER =0, + #o_RXCHBONDO =, + i_RXCHBONDSLAVE =0, + # Receive Ports - RX Channel Bonding Ports + #o_RXCHANISALIGNED =, + #o_RXCHANREALIGN =, + # Receive Ports - RX Decision Feedback Equalizer + #o_DMONITOROUT =, + i_RXADAPTSELTEST =0, + i_RXDFEXYDEN =0, + i_RXOSINTEN =0b1, + i_RXOSINTID0 =0, + i_RXOSINTNTRLEN =0, + #o_RXOSINTSTROBEDONE =, + # Receive Ports - RX Driver,OOB signalling,Coupling and Eq.,CDR + i_RXLPMLFOVRDEN =0, + i_RXLPMOSINTNTRLEN =0, + # Receive Ports - RX Equalizer Ports + i_RXLPMHFHOLD =0, + i_RXLPMHFOVRDEN =0, + i_RXLPMLFHOLD =0, + i_RXOSHOLD =0, + i_RXOSOVRDEN =0, + # Receive Ports - RX Fabric ClocK Output Control Ports + #o_RXRATEDONE =, + # Receive Ports - RX Fabric Clock Output Control Ports + i_RXRATEMODE =0b0, + # Receive Ports - RX Fabric Output Control Ports + o_RXOUTCLK =self.rxoutclk, + #o_RXOUTCLKFABRIC =, + #o_RXOUTCLKPCS =, + i_RXOUTCLKSEL =0b010, + # Receive Ports - RX Gearbox Ports + #o_RXDATAVALID =, + #o_RXHEADER =, + #o_RXHEADERVALID =, + #o_RXSTARTOFSEQ =, + i_RXGEARBOXSLIP =0, + # Receive Ports - RX Initialization and Reset Ports + i_GTRXRESET =rx_init.gtrxreset, + i_RXLPMRESET =0, + i_RXOOBRESET =0, + i_RXPCSRESET =0, + i_RXPMARESET =0, + # Receive Ports - RX OOB Signaling ports + #o_RXCOMSASDET =, + #o_RXCOMWAKEDET =, + #o_RXCOMINITDET =, + #o_RXELECIDLE =, + i_RXELECIDLEMODE =0b11, + + # Receive Ports - RX Polarity Control Ports + i_RXPOLARITY =0, + # Receive Ports -RX Initialization and Reset Ports + o_RXRESETDONE =rx_init.rxresetdone, + # TX Buffer Bypass Ports + i_TXPHDLYTSTCLK =0, + # TX Configurable Driver Ports + i_TXPOSTCURSOR =0b00000, + i_TXPOSTCURSORINV =0, + i_TXPRECURSOR =0, + i_TXPRECURSORINV =0, + # TX Fabric Clock Output Control Ports + i_TXRATEMODE =0, + # TX Initialization and Reset Ports + i_CFGRESET =0, + i_GTTXRESET =tx_init.gttxreset, + #o_PCSRSVDOUT =, + i_TXUSERRDY =tx_init.txuserrdy, + # TX Phase Interpolator PPM Controller Ports + i_TXPIPPMEN =0, + i_TXPIPPMOVRDEN =0, + i_TXPIPPMPD =0, + i_TXPIPPMSEL =0, + i_TXPIPPMSTEPSIZE =0, + # Transceiver Reset Mode Operation + i_GTRESETSEL =0, + i_RESETOVRD =0, + # Transmit Ports + #o_TXPMARESETDONE =, + # Transmit Ports - Configurable Driver Ports + i_PMARSVDIN0 =0b0, + i_PMARSVDIN1 =0b0, + # Transmit Ports - FPGA TX Interface Ports + i_TXDATA =Cat(txdata[:8], txdata[10:18]), + i_TXUSRCLK =ClockSignal("rtio_tx"), + i_TXUSRCLK2 =ClockSignal("rtio_tx"), + + # Transmit Ports - PCI Express Ports + i_TXELECIDLE =0, + i_TXMARGIN =0, + i_TXRATE =0, + i_TXSWING =0, + # Transmit Ports - Pattern Generator Ports + i_TXPRBSFORCEERR =0, + # Transmit Ports - TX 8B/10B Encoder Ports + i_TX8B10BBYPASS =0, + i_TXCHARDISPMODE =Cat(txdata[9], txdata[19]), + i_TXCHARDISPVAL =Cat(txdata[8], txdata[18]), + i_TXCHARISK =0, + # Transmit Ports - TX Buffer Bypass Ports + i_TXDLYBYPASS =0, + i_TXDLYEN =tx_init.txdlyen, + i_TXDLYHOLD =0, + i_TXDLYOVRDEN =0, + i_TXDLYSRESET =tx_init.txdlysreset, + o_TXDLYSRESETDONE =tx_init.txdlysresetdone, + i_TXDLYUPDOWN =0, + i_TXPHALIGN =tx_init.txphalign, + o_TXPHALIGNDONE =tx_init.txphaligndone, + i_TXPHALIGNEN =1, + i_TXPHDLYPD =0, + i_TXPHDLYRESET =0, + i_TXPHINIT =tx_init.txphinit, + o_TXPHINITDONE =tx_init.txphinitdone, + i_TXPHOVRDEN =0, + # Transmit Ports - TX Buffer Ports + #o_TXBUFSTATUS =, + # Transmit Ports - TX Buffer and Phase Alignment Ports + i_TXSYNCALLIN =0, + #o_TXSYNCDONE =, + #i_TXSYNCIN =0, + #i_TXSYNCMODE =0, + #o_TXSYNCOUT =, + # Transmit Ports - TX Configurable Driver Ports + o_GTPTXN =pads.txn, + o_GTPTXP =pads.txp, + i_TXBUFDIFFCTRL =0b100, + i_TXDEEMPH =0, + i_TXDIFFCTRL =0b1000, + i_TXDIFFPD =0, + i_TXINHIBIT =0, + i_TXMAINCURSOR =0b0000000, + i_TXPISOPD =0, + # Transmit Ports - TX Fabric Clock Output Control Ports + o_TXOUTCLK =self.txoutclk, + #o_TXOUTCLKFABRIC =, + #o_TXOUTCLKPCS =, + i_TXOUTCLKSEL =0b011, + #o_TXRATEDONE =, + # Transmit Ports - TX Gearbox Ports + #o_TXGEARBOXREADY =, + i_TXHEADER =0, + i_TXSEQUENCE =0, + i_TXSTARTSEQ =0, + # Transmit Ports - TX Initialization and Reset Ports + i_TXPCSRESET =0, + i_TXPMARESET =0, + o_TXRESETDONE =tx_init.txresetdone, + # Transmit Ports - TX OOB signalling Ports + #o_TXCOMFINISH =, + i_TXCOMINIT =0, + i_TXCOMSAS =0, + i_TXCOMWAKE =0, + i_TXPDELECIDLEMODE =0, + # Transmit Ports - TX Polarity Control Ports + i_TXPOLARITY =0, + # Transmit Ports - TX Receiver Detection Ports + i_TXDETECTRX =0, + # Transmit Ports - pattern Generator Ports + i_TXPRBSSEL =0 + ) if qpll_channel.index == 0: gtp_params.update( i_RXSYSCLKSEL=0b00, From e67a289e2b83342933ae1c3912498dce117eb8ed Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 9 Feb 2018 16:52:48 +0800 Subject: [PATCH 0308/2457] examples: add SAWG sines (DAC synchronization test) --- .../sayma_standalone/repository/sines.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 artiq/examples/sayma_standalone/repository/sines.py diff --git a/artiq/examples/sayma_standalone/repository/sines.py b/artiq/examples/sayma_standalone/repository/sines.py new file mode 100644 index 000000000..803164b3d --- /dev/null +++ b/artiq/examples/sayma_standalone/repository/sines.py @@ -0,0 +1,22 @@ +from artiq.experiment import * + + +class SAWGTest(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("ttl_sma_out") + self.sawgs = [self.get_device("sawg"+str(i)) for i in range(8)] + + @kernel + def run(self): + self.core.reset() + + for sawg in self.sawgs: + delay(1*ms) + sawg.amplitude1.set(.4) + # Do not use a sub-multiple of oscilloscope sample rates. + sawg.frequency0.set(49*MHz) + + while True: + delay(0.5*ms) + self.ttl_sma_out.pulse(0.5*ms) From 96b948f57f38b0a6ef5a22c39f1a882c62f62eb2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 13 Feb 2018 19:54:51 +0800 Subject: [PATCH 0309/2457] remote_csr: add sanity check of CSR CSV type column --- artiq/gateware/remote_csr.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/remote_csr.py b/artiq/gateware/remote_csr.py index 7acbba798..ae028a9b2 100644 --- a/artiq/gateware/remote_csr.py +++ b/artiq/gateware/remote_csr.py @@ -13,7 +13,12 @@ def _get_csr_data(csv_file): region_name, csr_name = name.split(".") address = int(address, 0) length = int(length, 0) - ro = ro == "ro" + if ro == "ro": + ro = True + elif ro == "rw": + ro = False + else: + raise ValueError if region_name not in csr_data: csr_data[region_name] = [] csr_data[region_name].append((csr_name, address, length, ro)) From 00f42f912bb852c31e8399c1e5fa0c07a714f1de Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 13 Feb 2018 19:58:51 +0800 Subject: [PATCH 0310/2457] rename 'RTM identifier' to 'RTM magic number' Avoids confusion with the MiSoC identifier (containing the ARTIQ version). --- artiq/firmware/libboard_artiq/serwb.rs | 10 +++++----- artiq/gateware/targets/sayma_rtm.py | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/artiq/firmware/libboard_artiq/serwb.rs b/artiq/firmware/libboard_artiq/serwb.rs index c31fa8eeb..39dff6fd4 100644 --- a/artiq/firmware/libboard_artiq/serwb.rs +++ b/artiq/firmware/libboard_artiq/serwb.rs @@ -38,12 +38,12 @@ pub fn wait_init() { } info!("done."); - // Try reading the identifier register on the other side of the bridge. - let rtm_identifier = unsafe { - csr::rtm_identifier::identifier_read() + // Try reading the magic number register on the other side of the bridge. + let rtm_magic = unsafe { + csr::rtm_magic::magic_read() }; - if rtm_identifier != 0x5352544d { - error!("incorrect RTM identifier: 0x{:08x}", rtm_identifier); + if rtm_magic != 0x5352544d { + error!("incorrect RTM magic number: 0x{:08x}", rtm_magic); // proceed anyway } diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 718a9d4ed..c6575c2d1 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -61,10 +61,10 @@ class CRG(Module): self.specials += Instance("IDELAYCTRL", i_REFCLK=ClockSignal("clk200"), i_RST=ic_reset) -class RTMIdentifier(Module, AutoCSR): +class RTMMagic(Module, AutoCSR): def __init__(self): - self.identifier = CSRStatus(32) - self.comb += self.identifier.status.eq(0x5352544d) # "SRTM" + self.magic = CSRStatus(32) + self.comb += self.magic.status.eq(0x5352544d) # "SRTM" CSR_RANGE_SIZE = 0x800 @@ -83,8 +83,8 @@ class SaymaRTM(Module): self.submodules.crg = CRG(platform) clk_freq = 125e6 - self.submodules.rtm_identifier = RTMIdentifier() - csr_devices.append("rtm_identifier") + self.submodules.rtm_magic = RTMMagic() + csr_devices.append("rtm_magic") # clock mux: 100MHz ext SMA clock to HMC830 input self.submodules.clock_mux = gpio.GPIOOut(Cat( From ab5f397fea26cdcf2b3d585c6b5baa8ccfc57c22 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 13 Feb 2018 20:02:26 +0800 Subject: [PATCH 0311/2457] sed/fifos: use AsyncFIFOBuffered (D)RTIO now passes timing at 150MHz on Kasli. --- artiq/gateware/rtio/sed/fifos.py | 2 +- conda/artiq-dev/meta.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/rtio/sed/fifos.py b/artiq/gateware/rtio/sed/fifos.py index f056e1a69..0452721f4 100644 --- a/artiq/gateware/rtio/sed/fifos.py +++ b/artiq/gateware/rtio/sed/fifos.py @@ -26,7 +26,7 @@ class FIFOs(Module): if mode == "sync": fifo_cls = SyncFIFOBuffered elif mode == "async": - fifo_cls = AsyncFIFO + fifo_cls = AsyncFIFOBuffered else: raise ValueError diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 7e2a3d049..08930c06e 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,8 +14,8 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.6 py35_11+git78a671d - - misoc 0.9 py35_1+git2e2b7838 + - migen 0.7 py35_2+git40721b2 + - misoc 0.9 py35_2+git8435d832 - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From df177bfd5be2264946f060ea625c9f03b6906d76 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 13 Feb 2018 20:38:48 +0800 Subject: [PATCH 0312/2457] use new misoc identifier --- artiq/firmware/libboard/ident.rs | 12 +++++++----- conda/artiq-dev/meta.yaml | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/libboard/ident.rs b/artiq/firmware/libboard/ident.rs index 26b5befdc..76ce2382d 100644 --- a/artiq/firmware/libboard/ident.rs +++ b/artiq/firmware/libboard/ident.rs @@ -1,13 +1,15 @@ -use core::{ptr, cmp, str}; +use core::{cmp, str}; use csr; pub fn read(buf: &mut [u8]) -> &str { unsafe { - let len = ptr::read_volatile(csr::IDENTIFIER_MEM_BASE); - let len = cmp::min(len as usize, buf.len()); + csr::identifier::address_write(0); + let len = csr::identifier::data_read(); + let len = cmp::min(len, buf.len() as u8); for i in 0..len { - buf[i] = ptr::read_volatile(csr::IDENTIFIER_MEM_BASE.offset(1 + i as isize)) as u8 + csr::identifier::address_write(1 + i); + buf[i as usize] = csr::identifier::data_read(); } - str::from_utf8_unchecked(&buf[..len]) + str::from_utf8_unchecked(&buf[..len as usize]) } } diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 08930c06e..a1b715eb2 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_2+git40721b2 - - misoc 0.9 py35_2+git8435d832 + - misoc 0.9 py35_3+git684b519a - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From bc6af03a61b930dc585b2269b4991592d37f7840 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 12 Feb 2018 13:57:33 +0000 Subject: [PATCH 0313/2457] urukul: (proto 7) drop att_le --- artiq/coredevice/urukul.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index e4b29be21..3fb2527f3 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -22,7 +22,6 @@ _SPIT_DDS_RD = 16 CFG_RF_SW = 0 CFG_LED = 4 CFG_PROFILE = 8 -CFG_ATT_LE = 11 CFG_IO_UPDATE = 12 CFG_MASK_NU = 16 CFG_CLK_SEL = 17 @@ -32,10 +31,10 @@ CFG_IO_RST = 20 @kernel -def urukul_cfg(rf_sw, led, profile, att_le, io_update, mask_nu, +def urukul_cfg(rf_sw, led, profile, io_update, mask_nu, clk_sel, sync_sel, rst, io_rst): return ((rf_sw << CFG_RF_SW) | (led << CFG_LED) | - (profile << CFG_PROFILE) | (att_le << CFG_ATT_LE) | + (profile << CFG_PROFILE) | (io_update << CFG_IO_UPDATE) | (mask_nu << CFG_MASK_NU) | (clk_sel << CFG_CLK_SEL) | (sync_sel << CFG_SYNC_SEL) | (rst << CFG_RST) | (io_rst << CFG_IO_RST)) @@ -75,7 +74,7 @@ def urukul_sta_proto_rev(sta): # supported hardware and CPLD code version -STA_PROTO_REV_MATCH = 0x06 +STA_PROTO_REV_MATCH = 0x07 # chip select (decoded) CS_CFG = 1 @@ -122,7 +121,7 @@ class CPLD: @kernel def init(self, clk_sel=0, sync_sel=0): - cfg = urukul_cfg(rf_sw=0, led=0, profile=0, att_le=0, + cfg = urukul_cfg(rf_sw=0, led=0, profile=0, io_update=0, mask_nu=0, clk_sel=clk_sel, sync_sel=sync_sel, rst=0, io_rst=0) self.cfg_write(cfg | (1 << CFG_RST) | (1 << CFG_IO_RST)) @@ -164,8 +163,6 @@ class CPLD: self.bus.set_config_mu(_SPI_CONFIG, _SPIT_ATT_WR, _SPIT_ATT_RD) self.bus.set_xfer(CS_ATT, 32, 0) self.bus.write(a) - self.cfg_write(self.cfg_reg | (1 << CFG_ATT_LE)) - self.cfg_write(self.cfg_reg & ~(1 << CFG_ATT_LE)) @kernel def set_att(self, channel, att): From 6a6695924fb4dc4814f303774e1bad0db5bdc0e9 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 12 Feb 2018 17:40:33 +0000 Subject: [PATCH 0314/2457] urukul: proto 8 --- artiq/coredevice/urukul.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 3fb2527f3..8532ab8b6 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -70,11 +70,11 @@ def urukul_sta_ifc_mode(sta): @kernel def urukul_sta_proto_rev(sta): - return (sta >> STA_PROTO_REV) & 0xff + return (sta >> STA_PROTO_REV) & 0x7f # supported hardware and CPLD code version -STA_PROTO_REV_MATCH = 0x07 +STA_PROTO_REV_MATCH = 0x08 # chip select (decoded) CS_CFG = 1 @@ -112,7 +112,6 @@ class CPLD: @kernel def sta_read(self): - self.cfg_write(self.cfg_reg) # to latch STA self.bus.set_config_mu(_SPI_CONFIG, _SPIT_CFG_WR, _SPIT_CFG_RD) self.bus.set_xfer(CS_CFG, 0, 24) self.bus.write(self.cfg_reg << 8) From 7f1bfddeda8c821a88c9fc928020e6f134a35304 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 12 Feb 2018 17:41:42 +0000 Subject: [PATCH 0315/2457] ad9910: tweak spi timing for higher speed --- artiq/coredevice/ad9910.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 30628af4c..4b958b97e 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -64,7 +64,7 @@ class AD9910: def write32(self, addr, data): self.bus.set_xfer(self.chip_select, 8, 0) self.bus.write(addr << 24) - delay_mu(-self.bus.xfer_period_mu) + delay_mu(-self.bus.xfer_period_mu + 8) self.bus.set_xfer(self.chip_select, 32, 0) self.bus.write(data) delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu) @@ -74,7 +74,7 @@ class AD9910: self.bus.set_xfer(self.chip_select, 8, 0) self.bus.write(addr << 24) t = self.bus.xfer_period_mu - delay_mu(-t) + delay_mu(-t + 8) self.bus.set_xfer(self.chip_select, 32, 0) self.bus.write(data_high) self.bus.write(data_low) @@ -84,7 +84,7 @@ class AD9910: def read32(self, addr): self.bus.set_xfer(self.chip_select, 8, 0) self.bus.write((addr | 0x80) << 24) - delay_mu(-self.bus.xfer_period_mu) + delay_mu(-self.bus.xfer_period_mu + 8) self.bus.set_xfer(self.chip_select, 0, 32) self.bus.write(0) delay_mu(2*self.bus.xfer_period_mu) From a3d136d30d2185d84bd0f26d56a2aeb2f4e1c3b6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 13 Feb 2018 06:21:56 +0000 Subject: [PATCH 0316/2457] opticlock: wire urukul and novogorny --- artiq/gateware/targets/kasli.py | 115 +++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 033fdcd54..c38fd3355 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -146,6 +146,79 @@ def _dio(eem): for i in range(8)] +def _novogorny(eem): + return [ + ("{}_spi_p".format(eem), 0, + Subsignal("clk", Pins("{}:{}_p".format(eem, _eem_signal(0)))), + Subsignal("mosi", Pins("{}:{}_p".format(eem, _eem_signal(1)))), + Subsignal("miso", Pins("{}:{}_p".format(eem, _eem_signal(2)))), + Subsignal("cs_n", Pins( + "{0}:{1[0]}_p {0}:{1[1]}_p".format( + eem, [_eem_signal(i + 3) for i in range(2)]))), + IOStandard("LVDS_25"), + ), + ("{}_spi_n".format(eem), 0, + Subsignal("clk", Pins("{}:{}_n".format(eem, _eem_signal(0)))), + Subsignal("mosi", Pins("{}:{}_n".format(eem, _eem_signal(1)))), + Subsignal("miso", Pins("{}:{}_n".format(eem, _eem_signal(2)))), + Subsignal("cs_n", Pins( + "{0}:{1[0]}_n {0}:{1[1]}_n".format( + eem, [_eem_signal(i + 3) for i in range(2)]))), + IOStandard("LVDS_25"), + ), + ] + [ + ("{}_{}".format(eem, sig), 0, + Subsignal("p", Pins("{}:{}_p".format(j, _eem_signal(i)))), + Subsignal("n", Pins("{}:{}_n".format(j, _eem_signal(i)))), + IOStandard("LVDS_25") + ) for i, j, sig in [ + (5, eem, "conv"), + (6, eem, "bosy"), + (7, eem, "scko"), + ] + ] + + +def _urukul(eem, eem_aux): + return [ + ("{}_spi_p".format(eem), 0, + Subsignal("clk", Pins("{}:{}_p".format(eem, _eem_signal(0)))), + Subsignal("mosi", Pins("{}:{}_p".format(eem, _eem_signal(1)))), + Subsignal("miso", Pins("{}:{}_p".format(eem, _eem_signal(2)))), + Subsignal("cs_n", Pins( + "{0}:{1[0]}_p {0}:{1[1]}_p {0}:{1[2]}_p".format( + eem, [_eem_signal(i + 3) for i in range(3)]))), + IOStandard("LVDS_25"), + ), + ("{}_spi_n".format(eem), 0, + Subsignal("clk", Pins("{}:{}_n".format(eem, _eem_signal(0)))), + Subsignal("mosi", Pins("{}:{}_n".format(eem, _eem_signal(1)))), + Subsignal("miso", Pins("{}:{}_n".format(eem, _eem_signal(2)))), + Subsignal("cs_n", Pins( + "{0}:{1[0]}_n {0}:{1[1]}_n {0}:{1[2]}_n".format( + eem, [_eem_signal(i + 3) for i in range(3)]))), + IOStandard("LVDS_25"), + ), + ] + [ + ("{}_{}".format(eem, sig), 0, + Subsignal("p", Pins("{}:{}_p".format(j, _eem_signal(i)))), + Subsignal("n", Pins("{}:{}_n".format(j, _eem_signal(i)))), + IOStandard("LVDS_25") + ) for i, j, sig in [ + (6, eem, "io_update"), + (7, eem, "dds_reset"), + (0, eem_aux, "sync_clk"), + (1, eem_aux, "sync_in"), + (2, eem_aux, "io_update_ret"), + (3, eem_aux, "nu_mosi3"), + (4, eem_aux, "sw0"), + (5, eem_aux, "sw1"), + (6, eem_aux, "sw2"), + (7, eem_aux, "sw3") + ] + ] + + class Opticlock(_StandaloneBase): """ Opticlock extension variant configuration @@ -157,19 +230,45 @@ class Opticlock(_StandaloneBase): platform.add_extension(_dio("eem0")) platform.add_extension(_dio("eem1")) platform.add_extension(_dio("eem2")) - # platform.add_extension(_urukul("eem3", "eem4")) - # platform.add_extension(_novogorny("eem5")) + platform.add_extension(_novogorny("eem3")) + platform.add_extension(_urukul("eem4", "eem5")) # EEM clock fan-out from Si5324, not MMCX self.comb += platform.request("clk_sel").eq(1) rtio_channels = [] - for eem in "eem0 eem1 eem2".split(): - for i in range(8): - phy = ttl_serdes_7series.Output_8X( - platform.request(eem, i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + for i in range(24): + eem, port = divmod(i, 8) + pads = platform.request("eem{}".format(eem), port) + if i < 4: + cls = ttl_serdes_7series.InOut_8X + else: + cls = ttl_serdes_7series.Output_8X + phy = cls(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + phy = spi.SPIMaster(self.platform.request("eem3_spi_p"), + self.platform.request("eem3_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + for signal in "conv".split(): + pads = platform.request("eem3_{}".format(signal)) + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + phy = spi.SPIMaster(self.platform.request("eem4_spi_p"), + self.platform.request("eem4_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + for signal in "io_update dds_reset sw0 sw1 sw2 sw3".split(): + pads = platform.request("eem4_{}".format(signal)) + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) for i in (1, 2): sfp_ctl = platform.request("sfp_ctl", i) From be693bc8a95a7311e8bab5780248afb5fbf404c5 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 13 Feb 2018 14:21:05 +0100 Subject: [PATCH 0317/2457] opticlock: examples --- artiq/examples/kasli/device_db.py | 306 ++++++++++++++++++++++ artiq/examples/kasli/idle_kernel.py | 21 ++ artiq/examples/kasli/repository/urukul.py | 83 ++++++ artiq/gateware/targets/kasli.py | 14 +- 4 files changed, 419 insertions(+), 5 deletions(-) create mode 100644 artiq/examples/kasli/device_db.py create mode 100644 artiq/examples/kasli/idle_kernel.py create mode 100644 artiq/examples/kasli/repository/urukul.py diff --git a/artiq/examples/kasli/device_db.py b/artiq/examples/kasli/device_db.py new file mode 100644 index 000000000..418a4119a --- /dev/null +++ b/artiq/examples/kasli/device_db.py @@ -0,0 +1,306 @@ +# This is an example device database that needs to be adapted to your setup. +# The RTIO channel numbers here are for OPTICLOCK on KASLI. +# The list of devices here is not exhaustive. + +core_addr = "vettel.ber.quartiq.de" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0x70} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0x71} + }, + + "ttl0": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 0}, + }, + "ttl1": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 1}, + }, + "ttl2": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 2}, + }, + "ttl3": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 3}, + }, + + "ttl4": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 4}, + }, + "ttl5": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 5}, + }, + "ttl6": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 6}, + }, + "ttl7": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 7}, + }, + "ttl8": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 8}, + }, + "ttl9": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 9}, + }, + "ttl10": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 10}, + }, + "ttl11": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 11}, + }, + "ttl12": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 12}, + }, + "ttl13": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 13}, + }, + "ttl14": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 14}, + }, + "ttl15": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 15}, + }, + "ttl16": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 16}, + }, + "ttl17": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 17}, + }, + "ttl18": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 18}, + }, + "ttl19": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 19}, + }, + "ttl20": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 20}, + }, + "ttl21": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 21}, + }, + "ttl22": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 22}, + }, + "ttl23": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 23}, + }, + + "spi_novogorny0": { + "type": "local", + "module": "artiq.coredevice.spi", + "class": "SPIMaster", + "arguments": {"channel": 24} + }, + "ttl_novogorny0_conv": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 25} + }, + + "spi_urukul0": { + "type": "local", + "module": "artiq.coredevice.spi", + "class": "SPIMaster", + "arguments": {"channel": 26} + }, + "ttl_urukul0_io_update": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 27} + }, + "ttl_urukul0_sw0": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 28} + }, + "ttl_urukul0_sw1": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 29} + }, + "ttl_urukul0_sw2": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 30} + }, + "ttl_urukul0_sw3": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 31} + }, + "urukul0_cpld": { + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 100e6 + } + }, + "urukul0_ch0": { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 4, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw0" + } + }, + "urukul0_ch1": { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 5, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw1" + } + }, + "urukul0_ch2": { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 6, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw2" + } + }, + "urukul0_ch3": { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 7, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw3" + } + }, + + "led0": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 32} + }, + "led1": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 33} + } +} diff --git a/artiq/examples/kasli/idle_kernel.py b/artiq/examples/kasli/idle_kernel.py new file mode 100644 index 000000000..05184f731 --- /dev/null +++ b/artiq/examples/kasli/idle_kernel.py @@ -0,0 +1,21 @@ +from artiq.experiment import * + + +class IdleKernel(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("led0") + + @kernel + def run(self): + start_time = now_mu() + self.core.seconds_to_mu(500*ms) + while self.core.get_rtio_counter_mu() < start_time: + pass + self.core.reset() + while True: + self.led0.pulse(250*ms) + delay(125*ms) + self.led0.pulse(125*ms) + delay(125*ms) + self.led0.pulse(125*ms) + delay(250*ms) diff --git a/artiq/examples/kasli/repository/urukul.py b/artiq/examples/kasli/repository/urukul.py new file mode 100644 index 000000000..3fc40a5fc --- /dev/null +++ b/artiq/examples/kasli/repository/urukul.py @@ -0,0 +1,83 @@ +from artiq.experiment import * + + +class UrukulTest(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("urukul0_cpld") + self.setattr_device("urukul0_ch0") + self.setattr_device("urukul0_ch1") + self.setattr_device("urukul0_ch2") + self.setattr_device("urukul0_ch3") + self.setattr_device("led0") + + def p(self, f, *a): + print(f % a) + + @kernel + def run(self): + self.core.reset() + self.led0.on() + delay(5*ms) + self.led0.off() + + self.urukul0_cpld.init(clk_sel=0) + self.urukul0_ch0.init() + self.urukul0_ch1.init() + self.urukul0_ch2.init() + self.urukul0_ch3.init() + + delay(1000*us) + self.urukul0_ch0.set(100*MHz) + self.urukul0_ch0.sw.on() + self.urukul0_ch0.set_att(10.) + + delay(1000*us) + self.urukul0_ch1.set(10*MHz, 0.5) + self.urukul0_ch1.sw.on() + self.urukul0_ch1.set_att(0.) + + delay(1000*us) + self.urukul0_ch2.set(400*MHz) + self.urukul0_ch2.sw.on() + self.urukul0_ch2.set_att(0.) + + delay(1000*us) + self.urukul0_ch3.set(1*MHz) + self.urukul0_ch3.sw.on() + self.urukul0_ch3.set_att(20.) + + i = 0 + j = 0 + while True: + delay(13*us) + self.urukul0_ch0.write32(0x07, i) + self.urukul0_cpld.io_update.pulse(10*ns) + k = self.urukul0_ch0.read32(0x07) + delay(100*us) + if k != i: + #print(i) + #print(k) + #if j > 20: + # return + j += 1 + #delay(20*ms) + i += 1 + + while True: + self.urukul0_ch0.sw.pulse(5*ms) + delay(5*ms) + + while False: + self.led0.pulse(.5*s) + delay(.5*s) + + @kernel + def test_att_noise(self, n=1024): + bus = self.urukul0_cpld.bus + bus.set_config_mu(_SPI_CONFIG, _SPIT_ATT_WR, _SPIT_ATT_RD) + bus.set_xfer(CS_ATT, 32, 0) + for i in range(n): + delay(5*us) + bus.write(self.att_reg) + bus.set_config_mu(_SPI_CONFIG, _SPIT_DDS_WR, _SPIT_DDS_RD) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index c38fd3355..7684a8f1b 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -8,6 +8,7 @@ from migen.genlib.cdc import MultiReg from migen.build.generic_platform import * from migen.build.xilinx.vivado import XilinxVivadoToolchain from migen.build.xilinx.ise import XilinxISEToolchain +from migen.genlib.io import DifferentialOutput from misoc.interconnect.csr import * from misoc.cores import gpio @@ -231,7 +232,7 @@ class Opticlock(_StandaloneBase): platform.add_extension(_dio("eem1")) platform.add_extension(_dio("eem2")) platform.add_extension(_novogorny("eem3")) - platform.add_extension(_urukul("eem4", "eem5")) + platform.add_extension(_urukul("eem5", "eem4")) # EEM clock fan-out from Si5324, not MMCX self.comb += platform.request("clk_sel").eq(1) @@ -259,13 +260,16 @@ class Opticlock(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - phy = spi.SPIMaster(self.platform.request("eem4_spi_p"), - self.platform.request("eem4_spi_n")) + phy = spi.SPIMaster(self.platform.request("eem5_spi_p"), + self.platform.request("eem5_spi_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - for signal in "io_update dds_reset sw0 sw1 sw2 sw3".split(): - pads = platform.request("eem4_{}".format(signal)) + pads = platform.request("eem5_dds_reset") + self.specials += DifferentialOutput(0, pads.p, pads.n) + + for signal in "io_update sw0 sw1 sw2 sw3".split(): + pads = platform.request("eem5_{}".format(signal)) phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From b6395a809b609a0a2a7c6c57ada7065a6178adf7 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 13 Feb 2018 20:54:31 +0000 Subject: [PATCH 0318/2457] kasli: remove old urukul test code --- artiq/examples/kasli/repository/urukul.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/artiq/examples/kasli/repository/urukul.py b/artiq/examples/kasli/repository/urukul.py index 3fc40a5fc..654d4f880 100644 --- a/artiq/examples/kasli/repository/urukul.py +++ b/artiq/examples/kasli/repository/urukul.py @@ -49,20 +49,6 @@ class UrukulTest(EnvExperiment): i = 0 j = 0 - while True: - delay(13*us) - self.urukul0_ch0.write32(0x07, i) - self.urukul0_cpld.io_update.pulse(10*ns) - k = self.urukul0_ch0.read32(0x07) - delay(100*us) - if k != i: - #print(i) - #print(k) - #if j > 20: - # return - j += 1 - #delay(20*ms) - i += 1 while True: self.urukul0_ch0.sw.pulse(5*ms) From ede98679fc4a21c760b2da5d7238c83f9f37a31b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 14 Feb 2018 09:05:03 +0100 Subject: [PATCH 0319/2457] ad9910: add documentation --- artiq/coredevice/ad9910.py | 65 +++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 4b958b97e..285ec8816 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -30,11 +30,21 @@ _AD9910_REG_RAM = 0x16 class AD9910: """ - Support for the AD9910 DDS on Urukul + AD9910 DDS channel on Urukul. - :param chip_select: Chip select configuration. + This class supports a single DDS channel and exposes the DDS, + the digital step attenuator, and the RF switch. + + :param chip_select: Chip select configuration. On Urukul this is an + encoded chip select and not "one-hot". :param cpld_device: Name of the Urukul CPLD this device is on. - :param sw_device: Name of the RF switch device. + :param sw_device: Name of the RF switch device. The RF switch is a + TTLOut channel available as the :attr:`sw` attribute of this instance. + :param pll_n: DDS PLL multiplier. The DDS sample clock is + f_ref/4*pll_n where f_ref is the reference frequency (set in the parent + Urukul CPLD instance). + :param pll_cp: DDS PLL charge pump setting. + :param pll_vco: DDS PLL VCO range selection. """ kernel_invariants = {"chip_select", "cpld", "core", "bus", "sw", "ftw_per_hz", "sysclk", "pll_n", "pll_cp", "pll_vco"} @@ -50,7 +60,9 @@ class AD9910: self.sw = dmgr.get(sw_device) assert 12 <= pll_n <= 127 self.pll_n = pll_n + assert self.cpld.refclk < 60e6 self.sysclk = self.cpld.refclk*pll_n/4 # Urukul clock fanout divider + assert self.sysclk < 1e9 self.ftw_per_hz = 1./self.sysclk*(int64(1) << 32) assert 0 <= pll_vco <= 5 vco_min, vco_max = [(370, 510), (420, 590), (500, 700), @@ -62,6 +74,11 @@ class AD9910: @kernel def write32(self, addr, data): + """Write to 32 bit register. + + :param addr: Register address + :param data: Data to be written + """ self.bus.set_xfer(self.chip_select, 8, 0) self.bus.write(addr << 24) delay_mu(-self.bus.xfer_period_mu + 8) @@ -71,6 +88,12 @@ class AD9910: @kernel def write64(self, addr, data_high, data_low): + """Write to 64 bit register. + + :param addr: Register address + :param data_high: High (MSB) 32 bits of the data + :param data_low: Low (LSB) 32 data bits + """ self.bus.set_xfer(self.chip_select, 8, 0) self.bus.write(addr << 24) t = self.bus.xfer_period_mu @@ -82,6 +105,10 @@ class AD9910: @kernel def read32(self, addr): + """Read from 32 bit register. + + :param addr: Register address + """ self.bus.set_xfer(self.chip_select, 8, 0) self.bus.write((addr | 0x80) << 24) delay_mu(-self.bus.xfer_period_mu + 8) @@ -93,13 +120,17 @@ class AD9910: @kernel def init(self): + """Initialize and configure the DDS.""" + # Set SPI mode self.write32(_AD9910_REG_CFR1, 0x00000002) - delay(100*ns) + delay(100*us) self.cpld.io_update.pulse(100*ns) + # Use the AUX DAC setting to identify and confirm presence aux_dac = self.read32(_AD9910_REG_AUX_DAC) if aux_dac & 0xff != 0x7f: raise ValueError("Urukul AD9910 AUX_DAC mismatch") delay(100*us) + # Configure PLL settings and bring up PLL self.write32(_AD9910_REG_CFR2, 0x01400020) cfr3 = (0x0807c100 | (self.pll_vco << 24) | (self.pll_cp << 19) | (self.pll_n << 1)) @@ -109,6 +140,7 @@ class AD9910: self.write32(_AD9910_REG_CFR3, cfr3) delay(100*us) self.cpld.io_update.pulse(100*ns) + # Wait for PLL lock, up to 100 ms for i in range(100): lock = urukul_sta_pll_lock(self.cpld.sta_read()) delay(1*ms) @@ -118,6 +150,15 @@ class AD9910: @kernel def set_mu(self, ftw, pow=0, asf=0x3fff): + """Set profile 0 data in machine units. + + After the SPI transfer, the shared IO update pin is pulsed to + activate the data. + + :param ftw: Frequency tuning word: 32 bit unsigned. + :param pow: Phase tuning word: 16 bit unsigned. + :param asf: Amplitude scale factor: 14 bit unsigned. + """ self.write64(_AD9910_REG_PR0, (asf << 16) | pow, ftw) self.cpld.io_update.pulse(10*ns) @@ -141,14 +182,30 @@ class AD9910: @kernel def set(self, frequency, phase=0.0, amplitude=1.0): + """Set profile 0 data in SI units. + + .. seealso:: :meth:`set_mu` + + :param ftw: Frequency in Hz + :param pow: Phase tuning word in turns + :param asf: Amplitude in units of full scale + """ self.set_mu(self.frequency_to_ftw(frequency), self.turns_to_pow(phase), self.amplitude_to_asf(amplitude)) @kernel def set_att_mu(self, att): + """Set digital step attenuator in machine units. + + :param att: Attenuation setting, 8 bit digital. + """ self.cpld.set_att_mu(self.chip_select - 4, att) @kernel def set_att(self, att): + """Set digital step attenuator in SI units. + + :param att: Attenuation in dB. + """ self.cpld.set_att(self.chip_select - 4, att) From 2adba3ed33ad9fb8c1f694389dc2618b0ab6b742 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 14 Feb 2018 09:45:17 +0100 Subject: [PATCH 0320/2457] urukul: document ad9912, and cpld, fix api --- artiq/coredevice/ad9910.py | 8 +++- artiq/coredevice/ad9912.py | 64 ++++++++++++++++++++++++--- artiq/coredevice/urukul.py | 36 +++++++++++---- doc/manual/core_drivers_reference.rst | 18 ++++++++ 4 files changed, 109 insertions(+), 17 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 285ec8816..22d490583 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -149,7 +149,7 @@ class AD9910: raise ValueError("PLL failed to lock") @kernel - def set_mu(self, ftw, pow=0, asf=0x3fff): + def set_mu(self, ftw=int32(0), pow=int32(0), asf=int32(0x3fff)): """Set profile 0 data in machine units. After the SPI transfer, the shared IO update pin is pulsed to @@ -195,9 +195,11 @@ class AD9910: self.amplitude_to_asf(amplitude)) @kernel - def set_att_mu(self, att): + def set_att_mu(self, att=int32(0)): """Set digital step attenuator in machine units. + .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att_mu` + :param att: Attenuation setting, 8 bit digital. """ self.cpld.set_att_mu(self.chip_select - 4, att) @@ -206,6 +208,8 @@ class AD9910: def set_att(self, att): """Set digital step attenuator in SI units. + .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att` + :param att: Attenuation in dB. """ self.cpld.set_att(self.chip_select - 4, att) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index a5da146ed..931b6551e 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -7,11 +7,19 @@ from numpy import int32, int64 class AD9912: """ - Support for the AD9912 DDS on Urukul + AD9912 DDS channel on Urukul - :param chip_select: Chip select configuration. + This class supports a single DDS channel and exposes the DDS, + the digital step attenuator, and the RF switch. + + :param chip_select: Chip select configuration. On Urukul this is an + encoded chip select and not "one-hot". :param cpld_device: Name of the Urukul CPLD this device is on. - :param sw_device: Name of the RF switch device. + :param sw_device: Name of the RF switch device. The RF switch is a + TTLOut channel available as the :attr:`sw` attribute of this instance. + :param pll_n: DDS PLL multiplier. The DDS sample clock is + f_ref*pll_n where f_ref is the reference frequency (set in the parent + Urukul CPLD instance). """ kernel_invariants = {"chip_select", "cpld", "core", "bus", "sw", "ftw_per_hz", "sysclk", "pll_n"} @@ -27,10 +35,17 @@ class AD9912: self.sw = dmgr.get(sw_device) self.pll_n = pll_n self.sysclk = self.cpld.refclk*pll_n + assert self.sysclk < 1e9 self.ftw_per_hz = 1/self.sysclk*(int64(1) << 48) @kernel - def write(self, addr, data, length=1): + def write(self, addr=int32(0), data=int32(0), length=int32(1)): + """Variable length write to a register. Up to 32 bits. + + :param addr: Register address + :param data: Data to be written: int32 + :param length: Length in bytes (1-4) + """ assert length > 0 assert length <= 4 self.bus.set_xfer(self.chip_select, 16, 0) @@ -41,7 +56,12 @@ class AD9912: delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu) @kernel - def read(self, addr, length=1): + def read(self, addr=int32(0), length=int32(1)): + """Variable length read from a register. Up to 32 bits. + + :param addr: Register address + :param length: Length in bytes (1-4) + """ assert length > 0 assert length <= 4 self.bus.set_xfer(self.chip_select, 16, 0) @@ -57,8 +77,11 @@ class AD9912: @kernel def init(self): + """Initialize and configure the DDS.""" t = now_mu() + # SPI mode self.write(AD9912_SER_CONF, 0x99) + # Verify chip ID and presence prodid = self.read(AD9912_PRODIDH, length=2) if (prodid != 0x1982) and (prodid != 0x1902): raise ValueError("Urukul AD9912 product id mismatch") @@ -69,19 +92,39 @@ class AD9912: delay(10*us) self.write(AD9912_PLLCFG, 0b00000101) # 375 µA, high range at_mu(t) - delay(100*us) + delay(100*us) # constant duration of 100 µs @kernel def set_att_mu(self, att): + """Set digital step attenuator in machine units. + + .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att_mu` + + :param att: Attenuation setting, 8 bit digital. + """ self.cpld.set_att_mu(self.chip_select - 4, att) @kernel def set_att(self, att): + """Set digital step attenuator in SI units. + + .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att` + + :param att: Attenuation in dB. + """ self.cpld.set_att(self.chip_select - 4, att) @kernel def set_mu(self, ftw=int64(0), pow=int32(0)): - # do a streaming transfer of FTW and POW + """Set profile 0 data in machine units. + + After the SPI transfer, the shared IO update pin is pulsed to + activate the data. + + :param ftw: Frequency tuning word: 32 bit unsigned. + :param pow: Phase tuning word: 16 bit unsigned. + """ + # streaming transfer of FTW and POW self.bus.set_xfer(self.chip_select, 16, 0) self.bus.write((AD9912_POW1 << 16) | (3 << 29)) delay_mu(-self.bus.xfer_period_mu) @@ -107,5 +150,12 @@ class AD9912: @kernel def set(self, frequency, phase=0.0): + """Set profile 0 data in SI units. + + .. seealso:: :meth:`set_mu` + + :param ftw: Frequency in Hz + :param pow: Phase tuning word in turns + """ self.set_mu(self.frequency_to_ftw(frequency), self.turns_to_pow(phase)) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 8532ab8b6..6648205c6 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -87,6 +87,15 @@ CS_DDS_CH3 = 7 class CPLD: + """Urukul CPLD SPI router and configuration interface. + + :param spi_device: SPI bus device name + :param io_update_device: IO update RTIO TTLOut channel name + :param dds_reset_device: DDS reset RTIO TTLOut channel name + :param refclk: Reference clock (SMA, MMCX or on-board 100 MHz oscillator) + frequency in Hz + :param core_device: Core device name + """ def __init__(self, dmgr, spi_device, io_update_device, dds_reset_device=None, refclk=100e6, core_device="core"): @@ -103,12 +112,17 @@ class CPLD: self.att_reg = int32(0) @kernel - def cfg_write(self, cfg_reg): + def cfg_write(self, data=int32(0)): + """Write to the configuration register. + + :param data: 24 bit data to be written. Will be stored at + :attr:`cfg_reg`. + """ self.bus.set_config_mu(_SPI_CONFIG, _SPIT_CFG_WR, _SPIT_CFG_RD) self.bus.set_xfer(CS_CFG, 24, 0) - self.bus.write(cfg_reg << 8) + self.bus.write(data << 8) self.bus.set_config_mu(_SPI_CONFIG, _SPIT_DDS_WR, _SPIT_DDS_RD) - self.cfg_reg = cfg_reg + self.cfg_reg = data @kernel def sta_read(self): @@ -150,11 +164,12 @@ class CPLD: self.cfg_write(c) @kernel - def set_att_mu(self, channel, att): - """ - Parameters: - att (int): 0-255, 255 minimum attenuation, - 0 maximum attenuation (31.5 dB) + def set_att_mu(self, channel=int32(0), att=int32(0)): + """Set digital step attenuator in machine units. + + :param channel: Attenuator channel (0-3). + :param att: Digital attenuation setting: + 255 minimum attenuation, 0 maximum attenuation (31.5 dB) """ a = self.att_reg & ~(0xff << (channel * 8)) a |= att << (channel * 8) @@ -165,4 +180,9 @@ class CPLD: @kernel def set_att(self, channel, att): + """Set digital step attenuator in SI units. + + :param channel: Attenuator channel (0-3). + :param att: Attenuation in dB. + """ self.set_att_mu(channel, 255 - int32(round(att*8))) diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 6def86ae8..d099c8ff3 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -68,3 +68,21 @@ These drivers are for the core device and the peripherals closely integrated int .. automodule:: artiq.coredevice.sawg :members: + +:mod:`artiq.coredevice.urukul` module +------------------------------------- + +.. automodule:: artiq.coredevice.urukul + :members: + +:mod:`artiq.coredevice.ad9912` module +------------------------------------- + +.. automodule:: artiq.coredevice.ad9912 + :members: + +:mod:`artiq.coredevice.ad9910` module +------------------------------------- + +.. automodule:: artiq.coredevice.ad9910 + :members: From fe50018037de509a0210af89cdd0f0d72a5dfd55 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 14 Feb 2018 23:03:09 +0000 Subject: [PATCH 0321/2457] firmware: make network tracing runtime switchable. --- artiq/firmware/runtime/main.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 95916a8dc..bb18e7dbf 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -153,13 +153,25 @@ fn startup_ethernet() { let mut net_device = unsafe { ethmac::EthernetDevice::new() }; net_device.reset_phy_if_any(); - // fn _net_trace_writer(timestamp: u64, printer: smoltcp::wire::PrettyPrinter) - // where U: smoltcp::wire::pretty_print::PrettyPrint { - // let seconds = timestamp / 1000; - // let micros = timestamp % 1000 * 1000; - // print!("\x1b[37m[{:6}.{:06}s]\n{}\x1b[0m\n", seconds, micros, printer) - // } - // let net_device = smoltcp::phy::EthernetTracer::new(net_device, _net_trace_writer); + let net_device = { + use smoltcp::wire::PrettyPrinter; + use smoltcp::wire::EthernetFrame; + + fn net_trace_writer(timestamp: u64, printer: PrettyPrinter>) { + let seconds = timestamp / 1000; + let micros = timestamp % 1000 * 1000; + print!("\x1b[37m[{:6}.{:06}s]\n{}\x1b[0m\n", seconds, micros, printer) + } + + fn net_trace_silent(_timestamp: u64, _printer: PrettyPrinter>) {} + + let net_trace_fn: fn(u64, PrettyPrinter>); + match config::read_str("net_trace", |r| r.map(|s| s == "1")) { + Ok(true) => net_trace_fn = net_trace_writer, + _ => net_trace_fn = net_trace_silent + } + smoltcp::phy::EthernetTracer::new(net_device, net_trace_fn) + }; let mut neighbor_map = [None; 8]; let neighbor_cache = From d572c0c34d1d7fdb16127f6cdc4508fd6b25a0d8 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 14 Feb 2018 23:10:27 +0000 Subject: [PATCH 0322/2457] artiq_devtool: fix the hotswap action. --- artiq/frontend/artiq_devtool.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 2e9f4ae84..289047b90 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -81,8 +81,10 @@ def main(): if args.target == "kc705": board_type, firmware = "kc705", "runtime" + variant = "nist_clock" if args.variant is None else args.variant elif args.target == "sayma": board_type, firmware = "sayma", "runtime" + variant = "standalone" if args.variant is None else args.variant else: raise NotImplementedError("unknown target {}".format(args.target)) @@ -137,12 +139,12 @@ def main(): logger.error(on_failure) sys.exit(1) - def build(target, *extra_args, output_dir=build_dir(), variant=args.variant): + def build(target, *extra_args, output_dir=build_dir(), variant=variant): build_args = ["python3", "-m", "artiq.gateware.targets." + target, *extra_args] if not args.build_gateware: build_args.append("--no-compile-gateware") if variant: - build_args += ["--variant", args.variant] + build_args += ["--variant", variant] build_args += ["--output-dir", output_dir] command(*build_args, on_failure="Build failed") @@ -154,8 +156,7 @@ def main(): flash_args.append("-v") flash_args += ["-H", args.host] flash_args += ["-t", board_type] - if args.variant: - flash_args += ["-V", args.variant] + flash_args += ["-V", variant] flash_args += ["-I", "source {}".format(board_file)] flash_args += ["--srcbuild", build_dir()] flash_args += steps @@ -248,7 +249,7 @@ def main(): elif action == "hotswap": logger.info("Hotswapping firmware") - firmware = build_dir("software", firmware, firmware + ".bin") + firmware = build_dir(variant, "software", firmware, firmware + ".bin") command("artiq_coreboot", "hotswap", firmware, on_failure="Hotswapping failed") From d7387611c0b7c9439ae03e059f4ac0ca188d852e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Feb 2018 19:31:58 +0800 Subject: [PATCH 0323/2457] sayma: print RTM gateware version --- artiq/firmware/libboard_artiq/serwb.rs | 16 ++++++++++++++++ artiq/gateware/targets/sayma_rtm.py | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/artiq/firmware/libboard_artiq/serwb.rs b/artiq/firmware/libboard_artiq/serwb.rs index 39dff6fd4..fea567172 100644 --- a/artiq/firmware/libboard_artiq/serwb.rs +++ b/artiq/firmware/libboard_artiq/serwb.rs @@ -1,5 +1,19 @@ +use core::{cmp, str}; use board::csr; +fn read_rtm_ident(buf: &mut [u8]) -> &str { + unsafe { + csr::rtm_identifier::address_write(0); + let len = csr::rtm_identifier::data_read(); + let len = cmp::min(len, buf.len() as u8); + for i in 0..len { + csr::rtm_identifier::address_write(1 + i); + buf[i as usize] = csr::rtm_identifier::data_read(); + } + str::from_utf8_unchecked(&buf[..len as usize]) + } +} + unsafe fn debug_print(rtm: bool) { debug!("AMC serwb settings:"); debug!(" delay_min_found: {}", csr::serwb_phy_amc::control_delay_min_found_read()); @@ -50,4 +64,6 @@ pub fn wait_init() { unsafe { debug_print(true); } + + info!("RTM gateware version {}", read_rtm_ident(&mut [0; 64])); } diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index c6575c2d1..9a77a4694 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -9,12 +9,14 @@ from migen.build.platforms.sinara import sayma_rtm from misoc.interconnect import wishbone, stream from misoc.interconnect.csr import * +from misoc.cores import identifier from misoc.cores import spi from misoc.cores import gpio from misoc.integration.wb_slaves import WishboneSlaveManager from misoc.integration.cpu_interface import get_csr_csv from artiq.gateware import serwb +from artiq import __version__ as artiq_version class CRG(Module): @@ -85,6 +87,8 @@ class SaymaRTM(Module): self.submodules.rtm_magic = RTMMagic() csr_devices.append("rtm_magic") + self.submodules.rtm_identifier = identifier.Identifier(artiq_version) + csr_devices.append("rtm_identifier") # clock mux: 100MHz ext SMA clock to HMC830 input self.submodules.clock_mux = gpio.GPIOOut(Cat( From c5ae81f452ffb8d727b9525c1afa6baa747d2147 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Feb 2018 20:29:51 +0800 Subject: [PATCH 0324/2457] satman: remove unused 62.5MHz Si5324 settings --- artiq/firmware/satman/main.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 1ff73542a..99de319cf 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -174,19 +174,6 @@ fn process_errors() { } } - -#[cfg(rtio_frequency = "62.5")] -const SI5324_SETTINGS: si5324::FrequencySettings - = si5324::FrequencySettings { - n1_hs : 10, - nc1_ls : 8, - n2_hs : 10, - n2_ls : 20112, - n31 : 2514, - n32 : 4597, - bwsel : 4 -}; - #[cfg(rtio_frequency = "150.0")] const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings { From 4d42df2a7c831c94ca16d8587ba86792d3dc4198 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Feb 2018 20:32:58 +0800 Subject: [PATCH 0325/2457] kasli: set up Si5324 in standalone operation --- artiq/firmware/runtime/main.rs | 15 ++++++++++++++- artiq/gateware/targets/kasli.py | 7 +++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index bb18e7dbf..4e4011e40 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -110,7 +110,20 @@ fn startup() { #[cfg(si5324_free_running)] fn setup_si5324_free_running() { - // 150MHz output (hardcoded) + // 125MHz output, from 10MHz CLKIN2 reference + #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref))] + const SI5324_SETTINGS: board_artiq::si5324::FrequencySettings + = board_artiq::si5324::FrequencySettings { + n1_hs : 10, + nc1_ls : 4, + n2_hs : 10, + n2_ls : 300, + n31 : 75, + n32 : 6, + bwsel : 10 + }; + // 150MHz output, from crystal + #[cfg(all(rtio_frequency = "150.0", not(si5324_ext_ref)))] const SI5324_SETTINGS: board_artiq::si5324::FrequencySettings = board_artiq::si5324::FrequencySettings { n1_hs : 9, diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 7684a8f1b..72b147064 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -104,6 +104,8 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) self.csr_devices.append("i2c") self.config["I2C_BUS_COUNT"] = 1 + self.config["HAS_SI5324"] = None + self.config["SI5324_SOFT_RESET"] = None def add_rtio(self, rtio_channels): self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) @@ -227,6 +229,10 @@ class Opticlock(_StandaloneBase): def __init__(self, **kwargs): _StandaloneBase.__init__(self, **kwargs) + self.config["SI5324_FREE_RUNNING"] = None + self.config["SI5324_EXT_REF"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + platform = self.platform platform.add_extension(_dio("eem0")) platform.add_extension(_dio("eem1")) @@ -318,6 +324,7 @@ class Master(MiniSoC, AMPSoC): self.config["HAS_SI5324"] = None self.config["SI5324_SOFT_RESET"] = None self.config["SI5324_FREE_RUNNING"] = None + self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.comb += platform.request("sfp_ctl", 2).tx_disable.eq(0) self.submodules.transceiver = gtp_7series.GTP( From 7002bea0ab49e91e491843416d4e508d973bdf55 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 14 Feb 2018 09:02:54 +0000 Subject: [PATCH 0326/2457] kasli: clean up urukul example more --- artiq/examples/kasli/repository/urukul.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/artiq/examples/kasli/repository/urukul.py b/artiq/examples/kasli/repository/urukul.py index 654d4f880..2f6a28d9f 100644 --- a/artiq/examples/kasli/repository/urukul.py +++ b/artiq/examples/kasli/repository/urukul.py @@ -47,23 +47,6 @@ class UrukulTest(EnvExperiment): self.urukul0_ch3.sw.on() self.urukul0_ch3.set_att(20.) - i = 0 - j = 0 - while True: self.urukul0_ch0.sw.pulse(5*ms) delay(5*ms) - - while False: - self.led0.pulse(.5*s) - delay(.5*s) - - @kernel - def test_att_noise(self, n=1024): - bus = self.urukul0_cpld.bus - bus.set_config_mu(_SPI_CONFIG, _SPIT_ATT_WR, _SPIT_ATT_RD) - bus.set_xfer(CS_ATT, 32, 0) - for i in range(n): - delay(5*us) - bus.write(self.att_reg) - bus.set_config_mu(_SPI_CONFIG, _SPIT_DDS_WR, _SPIT_DDS_RD) From 0ef33dd0d842eb1d18b03f486a66d41175772ab9 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 15 Feb 2018 14:20:43 +0100 Subject: [PATCH 0327/2457] manual: add note about the "correct" vivado version close #910 --- doc/manual/developing.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index 1f60335d1..7c237d670 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -142,6 +142,13 @@ These steps are required to generate gateware bitstream (``.bit``) files, build * Get Vivado from http://www.xilinx.com/support/download/index.htm. + * The "appropriate" Vivado version to use for building the bitstream can + vary. Some versions contain bugs that lead to hidden or visible failures, + others work fine. + Refer to the `M-Labs buildbot logs `_ to + determine which version is currently used to when building the binary + packages. + * During the Vivado installation, uncheck ``Install cable drivers`` (they are not required as we use better and open source alternatives). * Install Migen: :: From 7a5161d34838025a0473ddc93026402d59264835 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 17 Feb 2018 00:11:42 +0800 Subject: [PATCH 0328/2457] conda: bump misoc (#902) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index a1b715eb2..477bdf569 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_2+git40721b2 - - misoc 0.9 py35_3+git684b519a + - misoc 0.9 py35_6+git5c3ca413 - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From e4db84e214ba6c98260b56e5e5bb022ef5c1c64a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 17 Feb 2018 00:11:48 +0800 Subject: [PATCH 0329/2457] doc: fix typo --- doc/manual/developing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index 7c237d670..b1bf15336 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -146,7 +146,7 @@ These steps are required to generate gateware bitstream (``.bit``) files, build vary. Some versions contain bugs that lead to hidden or visible failures, others work fine. Refer to the `M-Labs buildbot logs `_ to - determine which version is currently used to when building the binary + determine which version is currently used when building the binary packages. * During the Vivado installation, uncheck ``Install cable drivers`` (they are not required as we use better and open source alternatives). From e41f49cc75c4267ef244603237ce5b95b53c9a50 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 16 Feb 2018 17:23:15 +0000 Subject: [PATCH 0330/2457] kasli: opticlock 125 MHz, mark external reference case broken --- artiq/firmware/runtime/main.rs | 21 +++++++++++++++++---- artiq/gateware/targets/kasli.py | 2 +- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 4e4011e40..364f801e9 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -110,18 +110,31 @@ fn startup() { #[cfg(si5324_free_running)] fn setup_si5324_free_running() { - // 125MHz output, from 10MHz CLKIN2 reference + // 125MHz output, from 100MHz CLKIN2 reference, 9 Hz + // FIXME: needs !FREE_RUN at address 0x00 #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref))] const SI5324_SETTINGS: board_artiq::si5324::FrequencySettings = board_artiq::si5324::FrequencySettings { n1_hs : 10, nc1_ls : 4, n2_hs : 10, - n2_ls : 300, - n31 : 75, - n32 : 6, + n2_ls : 260, + n31 : 65, + n32 : 52, bwsel : 10 }; + // 125MHz output, from crystal, 7 Hz + #[cfg(all(rtio_frequency = "125.0", not(si5324_ext_ref)))] + const SI5324_SETTINGS: board_artiq::si5324::FrequencySettings + = board_artiq::si5324::FrequencySettings { + n1_hs : 10, + nc1_ls : 4, + n2_hs : 10, + n2_ls : 19972, + n31 : 4993, + n32 : 4565, + bwsel : 4 + }; // 150MHz output, from crystal #[cfg(all(rtio_frequency = "150.0", not(si5324_ext_ref)))] const SI5324_SETTINGS: board_artiq::si5324::FrequencySettings diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 72b147064..2fd9058ae 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -230,7 +230,7 @@ class Opticlock(_StandaloneBase): _StandaloneBase.__init__(self, **kwargs) self.config["SI5324_FREE_RUNNING"] = None - self.config["SI5324_EXT_REF"] = None + # self.config["SI5324_EXT_REF"] = None self.config["RTIO_FREQUENCY"] = "125.0" platform = self.platform From ccc279b8da8b2c3a80cf6f70105125ce05a4977d Mon Sep 17 00:00:00 2001 From: hartytp Date: Sat, 17 Feb 2018 04:07:11 +0000 Subject: [PATCH 0331/2457] rewrite HMC7043 init code without using ADI GUI outputs, working analog/digital delay --- .../libboard_artiq/hmc7043_gen_writes.py | 30 - .../libboard_artiq/hmc7043_guiexport_6gbps.py | 696 ------------------ artiq/firmware/libboard_artiq/hmc830_7043.rs | 84 ++- 3 files changed, 64 insertions(+), 746 deletions(-) delete mode 100755 artiq/firmware/libboard_artiq/hmc7043_gen_writes.py delete mode 100644 artiq/firmware/libboard_artiq/hmc7043_guiexport_6gbps.py diff --git a/artiq/firmware/libboard_artiq/hmc7043_gen_writes.py b/artiq/firmware/libboard_artiq/hmc7043_gen_writes.py deleted file mode 100755 index 3f0a8cb47..000000000 --- a/artiq/firmware/libboard_artiq/hmc7043_gen_writes.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 - -# The HMC7043 GUI exports register write lists into Python files. -# This script converts them into Rust arrays. - -import sys -import runpy - - -class DUT: - def __init__(self): - self.writes = [] - - def write(self, address, value): - self.writes.append((address, value)) - - -def main(): - dut = DUT() - runpy.run_path(sys.argv[1], {"dut": dut}) - - print("// This file was autogenerated by hmc7043_gen_writes.py") - print("const HMC7043_WRITES: [(u16, u8); {}] = [".format(len(dut.writes))) - for address, value in dut.writes: - print(" (0x{:04x}, 0x{:02x}),".format(address, value)) - print("];") - - -if __name__ == "__main__": - main() diff --git a/artiq/firmware/libboard_artiq/hmc7043_guiexport_6gbps.py b/artiq/firmware/libboard_artiq/hmc7043_guiexport_6gbps.py deleted file mode 100644 index 77841ea03..000000000 --- a/artiq/firmware/libboard_artiq/hmc7043_guiexport_6gbps.py +++ /dev/null @@ -1,696 +0,0 @@ -# glbl_cfg1_swrst[0:0] = 0x0 -dut.write(0x0, 0x0) - -# glbl_cfg1_sleep[0:0] = 0x0 -# glbl_cfg1_restart[1:1] = 0x0 -# sysr_cfg1_pulsor_req[2:2] = 0x0 -# grpx_cfg1_mute[3:3] = 0x0 -# dist_cfg1_perf_floor[6:6] = 0x0 -# sysr_cfg1_reseed_req[7:7] = 0x0 -dut.write(0x1, 0x0) - -# sysr_cfg1_rev[0:0] = 0x0 -# sysr_cfg1_slipN_req[1:1] = 0x0 -dut.write(0x2, 0x0) - -# glbl_cfg1_ena_sysr[2:2] = 0x1 -# glbl_cfg2_ena_vcos[4:3] = 0x0 -# glbl_cfg1_ena_sysri[5:5] = 0x1 -dut.write(0x3, 0x24) - -# glbl_cfg7_ena_clkgr[6:0] = 0x3B -dut.write(0x4, 0x3B) - -# glbl_cfg1_clear_alarms[0:0] = 0x0 -dut.write(0x6, 0x0) - -# glbl_reserved[0:0] = 0x0 -dut.write(0x7, 0x0) - -# glbl_cfg5_ibuf0_en[0:0] = 0x0 -# glbl_cfg5_ibuf0_mode[4:1] = 0x7 -dut.write(0xA, 0xE) - -# glbl_cfg5_ibuf1_en[0:0] = 0x1 -# glbl_cfg5_ibuf1_mode[4:1] = 0x7 -dut.write(0xB, 0xF) - -# glbl_cfg5_gpi1_en[0:0] = 0x0 -# glbl_cfg5_gpi1_sel[4:1] = 0x0 -dut.write(0x46, 0x0) - -# glbl_cfg8_gpo1_en[0:0] = 0x1 -# glbl_cfg8_gpo1_mode[1:1] = 0x1 -# glbl_cfg8_gpo1_sel[7:2] = 0x7 -dut.write(0x50, 0x1F) - -# glbl_cfg2_sdio_en[0:0] = 0x1 -# glbl_cfg2_sdio_mode[1:1] = 0x1 -dut.write(0x54, 0x3) - -# sysr_cfg3_pulsor_mode[2:0] = 0x1 -dut.write(0x5A, 0x1) - -# sysr_cfg1_synci_invpol[0:0] = 0x0 -# sysr_cfg1_ext_sync_retimemode[2:2] = 0x1 -dut.write(0x5B, 0x4) - -# sysr_cfg16_divrat_lsb[7:0] = 0x0 -dut.write(0x5C, 0x0) - -# sysr_cfg16_divrat_msb[3:0] = 0x6 -dut.write(0x5D, 0x6) - -# dist_cfg1_extvco_islowfreq_sel[0:0] = 0x0 -# dist_cfg1_extvco_div2_sel[1:1] = 0x1 -dut.write(0x64, 0x2) - -# clkgrpx_cfg1_alg_dly_lowpwr_sel[0:0] = 0x0 -dut.write(0x65, 0x0) - -# alrm_cfg1_sysr_unsyncd_allow[1:1] = 0x0 -# alrm_cfg1_clkgrpx_validph_allow[2:2] = 0x0 -# alrm_cfg1_sync_req_allow[4:4] = 0x1 -dut.write(0x71, 0x10) - -# glbl_ro8_chipid_lob[7:0] = 0x1 -dut.write(0x78, 0x1) - -# glbl_ro8_chipid_mid[7:0] = 0x52 -dut.write(0x79, 0x52) - -# glbl_ro8_chipid_hib[7:0] = 0x4 -dut.write(0x7A, 0x4) - -# alrm_ro1_sysr_unsyncd_now[1:1] = 0x1 -# alrm_ro1_clkgrpx_validph_now[2:2] = 0x0 -# alrm_ro1_sync_req_now[4:4] = 0x1 -dut.write(0x7D, 0x12) - -# sysr_ro4_fsmstate[3:0] = 0x2 -# grpx_ro1_outdivfsm_busy[4:4] = 0x0 -dut.write(0x91, 0x2) - -# reg_98[7:0] = 0x0 -dut.write(0x98, 0x0) - -# reg_99[7:0] = 0x0 -dut.write(0x99, 0x0) - -# reg_9A[7:0] = 0x0 -dut.write(0x9A, 0x0) - -# reg_9B[7:0] = 0xAA -dut.write(0x9B, 0xAA) - -# reg_9C[7:0] = 0xAA -dut.write(0x9C, 0xAA) - -# reg_9D[7:0] = 0xAA -dut.write(0x9D, 0xAA) - -# reg_9E[7:0] = 0xAA -dut.write(0x9E, 0xAA) - -# reg_9F[7:0] = 0x4D -dut.write(0x9F, 0x4D) - -# reg_A0[7:0] = 0xDF -dut.write(0xA0, 0xDF) - -# reg_A1[7:0] = 0x97 -dut.write(0xA1, 0x97) - -# reg_A2[7:0] = 0x3 -dut.write(0xA2, 0x3) - -# reg_A3[7:0] = 0x0 -dut.write(0xA3, 0x0) - -# reg_A4[7:0] = 0x0 -dut.write(0xA4, 0x0) - -# reg_AD[7:0] = 0x0 -dut.write(0xAD, 0x0) - -# reg_AE[7:0] = 0x8 -dut.write(0xAE, 0x8) - -# reg_AF[7:0] = 0x50 -dut.write(0xAF, 0x50) - -# reg_B0[7:0] = 0x4 -dut.write(0xB0, 0x4) - -# reg_B1[7:0] = 0xD -dut.write(0xB1, 0xD) - -# reg_B2[7:0] = 0x0 -dut.write(0xB2, 0x0) - -# reg_B3[7:0] = 0x0 -dut.write(0xB3, 0x0) - -# reg_B5[7:0] = 0x0 -dut.write(0xB5, 0x0) - -# reg_B6[7:0] = 0x0 -dut.write(0xB6, 0x0) - -# reg_B7[7:0] = 0x0 -dut.write(0xB7, 0x0) - -# reg_B8[7:0] = 0x0 -dut.write(0xB8, 0x0) - -# clkgrp1_div1_cfg1_en[0:0] = 0x1 -# clkgrp1_div1_cfg1_phdelta_mslip[1:1] = 0x1 -# clkgrp1_div1_cfg2_startmode[3:2] = 0x0 -# clkgrp1_div1_cfg1_rev[4:4] = 0x1 -# clkgrp1_div1_cfg1_slipmask[5:5] = 0x1 -# clkgrp1_div1_cfg1_reseedmask[6:6] = 0x1 -# clkgrp1_div1_cfg1_hi_perf[7:7] = 0x0 -dut.write(0xC8, 0x73) - -# clkgrp1_div1_cfg12_divrat_lsb[7:0] = 0x1 -dut.write(0xC9, 0x1) - -# clkgrp1_div1_cfg12_divrat_msb[3:0] = 0x0 -dut.write(0xCA, 0x0) - -# clkgrp1_div1_cfg5_fine_delay[4:0] = 0x0 -dut.write(0xCB, 0x0) - -# clkgrp1_div1_cfg5_sel_coarse_delay[4:0] = 0x0 -dut.write(0xCC, 0x0) - -# clkgrp1_div1_cfg12_mslip_lsb[7:0] = 0x0 -dut.write(0xCD, 0x0) - -# clkgrp1_div1_cfg12_mslip_msb[3:0] = 0x0 -dut.write(0xCE, 0x0) - -# clkgrp1_div1_cfg2_sel_outmux[1:0] = 0x3 -# clkgrp1_div1_cfg1_drvr_sel_testclk[2:2] = 0x0 -dut.write(0xCF, 0x3) - -# clkgrp1_div1_cfg5_drvr_res[1:0] = 0x0 -# clkgrp1_div1_cfg5_drvr_spare[2:2] = 0x0 -# clkgrp1_div1_cfg5_drvr_mode[4:3] = 0x1 -# clkgrp1_div1_cfg_outbuf_dyn[5:5] = 0x0 -# clkgrp1_div1_cfg2_mutesel[7:6] = 0x0 -dut.write(0xD0, 0x8) - -# clkgrp1_div2_cfg1_en[0:0] = 0x1 -# clkgrp1_div2_cfg1_phdelta_mslip[1:1] = 0x0 -# clkgrp1_div2_cfg2_startmode[3:2] = 0x0 -# clkgrp1_div2_cfg1_rev[4:4] = 0x1 -# clkgrp1_div2_cfg1_slipmask[5:5] = 0x1 -# clkgrp1_div2_cfg1_reseedmask[6:6] = 0x1 -# clkgrp1_div2_cfg1_hi_perf[7:7] = 0x0 -dut.write(0xD2, 0x71) - -# clkgrp1_div2_cfg12_divrat_lsb[7:0] = 0x40 -dut.write(0xD3, 0x40) - -# clkgrp1_div2_cfg12_divrat_msb[3:0] = 0x0 -dut.write(0xD4, 0x0) - -# clkgrp1_div2_cfg5_fine_delay[4:0] = 0x0 -dut.write(0xD5, 0x0) - -# clkgrp1_div2_cfg5_sel_coarse_delay[4:0] = 0x0 -dut.write(0xD6, 0x0) - -# clkgrp1_div2_cfg12_mslip_lsb[7:0] = 0x0 -dut.write(0xD7, 0x0) - -# clkgrp1_div2_cfg12_mslip_msb[3:0] = 0x0 -dut.write(0xD8, 0x0) - -# clkgrp1_div2_cfg2_sel_outmux[1:0] = 0x0 -# clkgrp1_div2_cfg1_drvr_sel_testclk[2:2] = 0x0 -dut.write(0xD9, 0x0) - -# clkgrp1_div2_cfg5_drvr_res[1:0] = 0x1 -# clkgrp1_div2_cfg5_drvr_spare[2:2] = 0x0 -# clkgrp1_div2_cfg5_drvr_mode[4:3] = 0x1 -# clkgrp1_div2_cfg_outbuf_dyn[5:5] = 0x0 -# clkgrp1_div2_cfg2_mutesel[7:6] = 0x0 -dut.write(0xDA, 0x9) - -# clkgrp2_div1_cfg1_en[0:0] = 0x1 -# clkgrp2_div1_cfg1_phdelta_mslip[1:1] = 0x1 -# clkgrp2_div1_cfg2_startmode[3:2] = 0x0 -# clkgrp2_div1_cfg1_rev[4:4] = 0x1 -# clkgrp2_div1_cfg1_slipmask[5:5] = 0x1 -# clkgrp2_div1_cfg1_reseedmask[6:6] = 0x1 -# clkgrp2_div1_cfg1_hi_perf[7:7] = 0x0 -dut.write(0xDC, 0x73) - -# clkgrp2_div1_cfg12_divrat_lsb[7:0] = 0x1 -dut.write(0xDD, 0x1) - -# clkgrp2_div1_cfg12_divrat_msb[3:0] = 0x0 -dut.write(0xDE, 0x0) - -# clkgrp2_div1_cfg5_fine_delay[4:0] = 0x0 -dut.write(0xDF, 0x0) - -# clkgrp2_div1_cfg5_sel_coarse_delay[4:0] = 0x0 -dut.write(0xE0, 0x0) - -# clkgrp2_div1_cfg12_mslip_lsb[7:0] = 0x0 -dut.write(0xE1, 0x0) - -# clkgrp2_div1_cfg12_mslip_msb[3:0] = 0x0 -dut.write(0xE2, 0x0) - -# clkgrp2_div1_cfg2_sel_outmux[1:0] = 0x0 -# clkgrp2_div1_cfg1_drvr_sel_testclk[2:2] = 0x0 -dut.write(0xE3, 0x0) - -# clkgrp2_div1_cfg5_drvr_res[1:0] = 0x0 -# clkgrp2_div1_cfg5_drvr_spare[2:2] = 0x0 -# clkgrp2_div1_cfg5_drvr_mode[4:3] = 0x1 -# clkgrp2_div1_cfg_outbuf_dyn[5:5] = 0x0 -# clkgrp2_div1_cfg2_mutesel[7:6] = 0x0 -dut.write(0xE4, 0x8) - -# clkgrp2_div2_cfg1_en[0:0] = 0x1 -# clkgrp2_div2_cfg1_phdelta_mslip[1:1] = 0x0 -# clkgrp2_div2_cfg2_startmode[3:2] = 0x0 -# clkgrp2_div2_cfg1_rev[4:4] = 0x1 -# clkgrp2_div2_cfg1_slipmask[5:5] = 0x1 -# clkgrp2_div2_cfg1_reseedmask[6:6] = 0x1 -# clkgrp2_div2_cfg1_hi_perf[7:7] = 0x0 -dut.write(0xE6, 0x71) - -# clkgrp2_div2_cfg12_divrat_lsb[7:0] = 0x40 -dut.write(0xE7, 0x40) - -# clkgrp2_div2_cfg12_divrat_msb[3:0] = 0x0 -dut.write(0xE8, 0x0) - -# clkgrp2_div2_cfg5_fine_delay[4:0] = 0x0 -dut.write(0xE9, 0x0) - -# clkgrp2_div2_cfg5_sel_coarse_delay[4:0] = 0x0 -dut.write(0xEA, 0x0) - -# clkgrp2_div2_cfg12_mslip_lsb[7:0] = 0x0 -dut.write(0xEB, 0x0) - -# clkgrp2_div2_cfg12_mslip_msb[3:0] = 0x0 -dut.write(0xEC, 0x0) - -# clkgrp2_div2_cfg2_sel_outmux[1:0] = 0x0 -# clkgrp2_div2_cfg1_drvr_sel_testclk[2:2] = 0x0 -dut.write(0xED, 0x0) - -# clkgrp2_div2_cfg5_drvr_res[1:0] = 0x1 -# clkgrp2_div2_cfg5_drvr_spare[2:2] = 0x0 -# clkgrp2_div2_cfg5_drvr_mode[4:3] = 0x1 -# clkgrp2_div2_cfg_outbuf_dyn[5:5] = 0x0 -# clkgrp2_div2_cfg2_mutesel[7:6] = 0x0 -dut.write(0xEE, 0x9) - -# clkgrp3_div1_cfg1_en[0:0] = 0x1 -# clkgrp3_div1_cfg1_phdelta_mslip[1:1] = 0x1 -# clkgrp3_div1_cfg2_startmode[3:2] = 0x0 -# clkgrp3_div1_cfg1_rev[4:4] = 0x1 -# clkgrp3_div1_cfg1_slipmask[5:5] = 0x1 -# clkgrp3_div1_cfg1_reseedmask[6:6] = 0x1 -# clkgrp3_div1_cfg1_hi_perf[7:7] = 0x0 -dut.write(0xF0, 0x73) - -# clkgrp3_div1_cfg12_divrat_lsb[7:0] = 0x2 -dut.write(0xF1, 0x2) - -# clkgrp3_div1_cfg12_divrat_msb[3:0] = 0x0 -dut.write(0xF2, 0x0) - -# clkgrp3_div1_cfg5_fine_delay[4:0] = 0x0 -dut.write(0xF3, 0x0) - -# clkgrp3_div1_cfg5_sel_coarse_delay[4:0] = 0x0 -dut.write(0xF4, 0x0) - -# clkgrp3_div1_cfg12_mslip_lsb[7:0] = 0x0 -dut.write(0xF5, 0x0) - -# clkgrp3_div1_cfg12_mslip_msb[3:0] = 0x0 -dut.write(0xF6, 0x0) - -# clkgrp3_div1_cfg2_sel_outmux[1:0] = 0x0 -# clkgrp3_div1_cfg1_drvr_sel_testclk[2:2] = 0x0 -dut.write(0xF7, 0x0) - -# clkgrp3_div1_cfg5_drvr_res[1:0] = 0x0 -# clkgrp3_div1_cfg5_drvr_spare[2:2] = 0x0 -# clkgrp3_div1_cfg5_drvr_mode[4:3] = 0x1 -# clkgrp3_div1_cfg_outbuf_dyn[5:5] = 0x0 -# clkgrp3_div1_cfg2_mutesel[7:6] = 0x0 -dut.write(0xF8, 0x8) - -# clkgrp3_div2_cfg1_en[0:0] = 0x0 -# clkgrp3_div2_cfg1_phdelta_mslip[1:1] = 0x0 -# clkgrp3_div2_cfg2_startmode[3:2] = 0x0 -# clkgrp3_div2_cfg1_rev[4:4] = 0x1 -# clkgrp3_div2_cfg1_slipmask[5:5] = 0x1 -# clkgrp3_div2_cfg1_reseedmask[6:6] = 0x1 -# clkgrp3_div2_cfg1_hi_perf[7:7] = 0x0 -dut.write(0xFA, 0x70) - -# clkgrp3_div2_cfg12_divrat_lsb[7:0] = 0x80 -dut.write(0xFB, 0x80) - -# clkgrp3_div2_cfg12_divrat_msb[3:0] = 0x0 -dut.write(0xFC, 0x0) - -# clkgrp3_div2_cfg5_fine_delay[4:0] = 0x0 -dut.write(0xFD, 0x0) - -# clkgrp3_div2_cfg5_sel_coarse_delay[4:0] = 0x0 -dut.write(0xFE, 0x0) - -# clkgrp3_div2_cfg12_mslip_lsb[7:0] = 0x0 -dut.write(0xFF, 0x0) - -# clkgrp3_div2_cfg12_mslip_msb[3:0] = 0x0 -dut.write(0x100, 0x0) - -# clkgrp3_div2_cfg2_sel_outmux[1:0] = 0x0 -# clkgrp3_div2_cfg1_drvr_sel_testclk[2:2] = 0x0 -dut.write(0x101, 0x0) - -# clkgrp3_div2_cfg5_drvr_res[1:0] = 0x3 -# clkgrp3_div2_cfg5_drvr_spare[2:2] = 0x0 -# clkgrp3_div2_cfg5_drvr_mode[4:3] = 0x1 -# clkgrp3_div2_cfg_outbuf_dyn[5:5] = 0x0 -# clkgrp3_div2_cfg2_mutesel[7:6] = 0x0 -dut.write(0x102, 0xB) - -# clkgrp4_div1_cfg1_en[0:0] = 0x1 -# clkgrp4_div1_cfg1_phdelta_mslip[1:1] = 0x1 -# clkgrp4_div1_cfg2_startmode[3:2] = 0x0 -# clkgrp4_div1_cfg1_rev[4:4] = 0x1 -# clkgrp4_div1_cfg1_slipmask[5:5] = 0x1 -# clkgrp4_div1_cfg1_reseedmask[6:6] = 0x1 -# clkgrp4_div1_cfg1_hi_perf[7:7] = 0x0 -dut.write(0x104, 0x73) - -# clkgrp4_div1_cfg12_divrat_lsb[7:0] = 0x4 -dut.write(0x105, 0x4) - -# clkgrp4_div1_cfg12_divrat_msb[3:0] = 0x0 -dut.write(0x106, 0x0) - -# clkgrp4_div1_cfg5_fine_delay[4:0] = 0x0 -dut.write(0x107, 0x0) - -# clkgrp4_div1_cfg5_sel_coarse_delay[4:0] = 0x0 -dut.write(0x108, 0x0) - -# clkgrp4_div1_cfg12_mslip_lsb[7:0] = 0x0 -dut.write(0x109, 0x0) - -# clkgrp4_div1_cfg12_mslip_msb[3:0] = 0x0 -dut.write(0x10A, 0x0) - -# clkgrp4_div1_cfg2_sel_outmux[1:0] = 0x0 -# clkgrp4_div1_cfg1_drvr_sel_testclk[2:2] = 0x0 -dut.write(0x10B, 0x0) - -# clkgrp4_div1_cfg5_drvr_res[1:0] = 0x0 -# clkgrp4_div1_cfg5_drvr_spare[2:2] = 0x0 -# clkgrp4_div1_cfg5_drvr_mode[4:3] = 0x1 -# clkgrp4_div1_cfg_outbuf_dyn[5:5] = 0x0 -# clkgrp4_div1_cfg2_mutesel[7:6] = 0x0 -dut.write(0x10C, 0x8) - -# clkgrp4_div2_cfg1_en[0:0] = 0x1 -# clkgrp4_div2_cfg1_phdelta_mslip[1:1] = 0x0 -# clkgrp4_div2_cfg2_startmode[3:2] = 0x0 -# clkgrp4_div2_cfg1_rev[4:4] = 0x1 -# clkgrp4_div2_cfg1_slipmask[5:5] = 0x1 -# clkgrp4_div2_cfg1_reseedmask[6:6] = 0x1 -# clkgrp4_div2_cfg1_hi_perf[7:7] = 0x0 -dut.write(0x10E, 0x71) - -# clkgrp4_div2_cfg12_divrat_lsb[7:0] = 0x40 -dut.write(0x10F, 0x40) - -# clkgrp4_div2_cfg12_divrat_msb[3:0] = 0x0 -dut.write(0x110, 0x0) - -# clkgrp4_div2_cfg5_fine_delay[4:0] = 0x0 -dut.write(0x111, 0x0) - -# clkgrp4_div2_cfg5_sel_coarse_delay[4:0] = 0x0 -dut.write(0x112, 0x0) - -# clkgrp4_div2_cfg12_mslip_lsb[7:0] = 0x0 -dut.write(0x113, 0x0) - -# clkgrp4_div2_cfg12_mslip_msb[3:0] = 0x0 -dut.write(0x114, 0x0) - -# clkgrp4_div2_cfg2_sel_outmux[1:0] = 0x0 -# clkgrp4_div2_cfg1_drvr_sel_testclk[2:2] = 0x0 -dut.write(0x115, 0x0) - -# clkgrp4_div2_cfg5_drvr_res[1:0] = 0x3 -# clkgrp4_div2_cfg5_drvr_spare[2:2] = 0x0 -# clkgrp4_div2_cfg5_drvr_mode[4:3] = 0x2 -# clkgrp4_div2_cfg_outbuf_dyn[5:5] = 0x0 -# clkgrp4_div2_cfg2_mutesel[7:6] = 0x0 -dut.write(0x116, 0x13) - -# clkgrp5_div1_cfg1_en[0:0] = 0x1 -# clkgrp5_div1_cfg1_phdelta_mslip[1:1] = 0x1 -# clkgrp5_div1_cfg2_startmode[3:2] = 0x0 -# clkgrp5_div1_cfg1_rev[4:4] = 0x1 -# clkgrp5_div1_cfg1_slipmask[5:5] = 0x1 -# clkgrp5_div1_cfg1_reseedmask[6:6] = 0x1 -# clkgrp5_div1_cfg1_hi_perf[7:7] = 0x0 -dut.write(0x118, 0x73) - -# clkgrp5_div1_cfg12_divrat_lsb[7:0] = 0x4 -dut.write(0x119, 0x4) - -# clkgrp5_div1_cfg12_divrat_msb[3:0] = 0x0 -dut.write(0x11A, 0x0) - -# clkgrp5_div1_cfg5_fine_delay[4:0] = 0x0 -dut.write(0x11B, 0x0) - -# clkgrp5_div1_cfg5_sel_coarse_delay[4:0] = 0x0 -dut.write(0x11C, 0x0) - -# clkgrp5_div1_cfg12_mslip_lsb[7:0] = 0x0 -dut.write(0x11D, 0x0) - -# clkgrp5_div1_cfg12_mslip_msb[3:0] = 0x0 -dut.write(0x11E, 0x0) - -# clkgrp5_div1_cfg2_sel_outmux[1:0] = 0x0 -# clkgrp5_div1_cfg1_drvr_sel_testclk[2:2] = 0x0 -dut.write(0x11F, 0x0) - -# clkgrp5_div1_cfg5_drvr_res[1:0] = 0x0 -# clkgrp5_div1_cfg5_drvr_spare[2:2] = 0x0 -# clkgrp5_div1_cfg5_drvr_mode[4:3] = 0x1 -# clkgrp5_div1_cfg_outbuf_dyn[5:5] = 0x0 -# clkgrp5_div1_cfg2_mutesel[7:6] = 0x0 -dut.write(0x120, 0x8) - -# clkgrp5_div2_cfg1_en[0:0] = 0x1 -# clkgrp5_div2_cfg1_phdelta_mslip[1:1] = 0x1 -# clkgrp5_div2_cfg2_startmode[3:2] = 0x0 -# clkgrp5_div2_cfg1_rev[4:4] = 0x1 -# clkgrp5_div2_cfg1_slipmask[5:5] = 0x1 -# clkgrp5_div2_cfg1_reseedmask[6:6] = 0x1 -# clkgrp5_div2_cfg1_hi_perf[7:7] = 0x0 -dut.write(0x122, 0x73) - -# clkgrp5_div2_cfg12_divrat_lsb[7:0] = 0x4 -dut.write(0x123, 0x4) - -# clkgrp5_div2_cfg12_divrat_msb[3:0] = 0x0 -dut.write(0x124, 0x0) - -# clkgrp5_div2_cfg5_fine_delay[4:0] = 0x0 -dut.write(0x125, 0x0) - -# clkgrp5_div2_cfg5_sel_coarse_delay[4:0] = 0x0 -dut.write(0x126, 0x0) - -# clkgrp5_div2_cfg12_mslip_lsb[7:0] = 0x0 -dut.write(0x127, 0x0) - -# clkgrp5_div2_cfg12_mslip_msb[3:0] = 0x0 -dut.write(0x128, 0x0) - -# clkgrp5_div2_cfg2_sel_outmux[1:0] = 0x0 -# clkgrp5_div2_cfg1_drvr_sel_testclk[2:2] = 0x0 -dut.write(0x129, 0x0) - -# clkgrp5_div2_cfg5_drvr_res[1:0] = 0x3 -# clkgrp5_div2_cfg5_drvr_spare[2:2] = 0x0 -# clkgrp5_div2_cfg5_drvr_mode[4:3] = 0x1 -# clkgrp5_div2_cfg_outbuf_dyn[5:5] = 0x0 -# clkgrp5_div2_cfg2_mutesel[7:6] = 0x0 -dut.write(0x12A, 0xB) - -# clkgrp6_div1_cfg1_en[0:0] = 0x1 -# clkgrp6_div1_cfg1_phdelta_mslip[1:1] = 0x1 -# clkgrp6_div1_cfg2_startmode[3:2] = 0x0 -# clkgrp6_div1_cfg1_rev[4:4] = 0x1 -# clkgrp6_div1_cfg1_slipmask[5:5] = 0x1 -# clkgrp6_div1_cfg1_reseedmask[6:6] = 0x1 -# clkgrp6_div1_cfg1_hi_perf[7:7] = 0x0 -dut.write(0x12C, 0x73) - -# clkgrp6_div1_cfg12_divrat_lsb[7:0] = 0x4 -dut.write(0x12D, 0x4) - -# clkgrp6_div1_cfg12_divrat_msb[3:0] = 0x0 -dut.write(0x12E, 0x0) - -# clkgrp6_div1_cfg5_fine_delay[4:0] = 0x0 -dut.write(0x12F, 0x0) - -# clkgrp6_div1_cfg5_sel_coarse_delay[4:0] = 0x0 -dut.write(0x130, 0x0) - -# clkgrp6_div1_cfg12_mslip_lsb[7:0] = 0x0 -dut.write(0x131, 0x0) - -# clkgrp6_div1_cfg12_mslip_msb[3:0] = 0x0 -dut.write(0x132, 0x0) - -# clkgrp6_div1_cfg2_sel_outmux[1:0] = 0x0 -# clkgrp6_div1_cfg1_drvr_sel_testclk[2:2] = 0x0 -dut.write(0x133, 0x0) - -# clkgrp6_div1_cfg5_drvr_res[1:0] = 0x0 -# clkgrp6_div1_cfg5_drvr_spare[2:2] = 0x0 -# clkgrp6_div1_cfg5_drvr_mode[4:3] = 0x1 -# clkgrp6_div1_cfg_outbuf_dyn[5:5] = 0x0 -# clkgrp6_div1_cfg2_mutesel[7:6] = 0x0 -dut.write(0x134, 0x8) - -# clkgrp6_div2_cfg1_en[0:0] = 0x1 -# clkgrp6_div2_cfg1_phdelta_mslip[1:1] = 0x0 -# clkgrp6_div2_cfg2_startmode[3:2] = 0x0 -# clkgrp6_div2_cfg1_rev[4:4] = 0x1 -# clkgrp6_div2_cfg1_slipmask[5:5] = 0x1 -# clkgrp6_div2_cfg1_reseedmask[6:6] = 0x1 -# clkgrp6_div2_cfg1_hi_perf[7:7] = 0x0 -dut.write(0x136, 0x71) - -# clkgrp6_div2_cfg12_divrat_lsb[7:0] = 0x80 -dut.write(0x137, 0x80) - -# clkgrp6_div2_cfg12_divrat_msb[3:0] = 0x0 -dut.write(0x138, 0x0) - -# clkgrp6_div2_cfg5_fine_delay[4:0] = 0x0 -dut.write(0x139, 0x0) - -# clkgrp6_div2_cfg5_sel_coarse_delay[4:0] = 0x0 -dut.write(0x13A, 0x0) - -# clkgrp6_div2_cfg12_mslip_lsb[7:0] = 0x0 -dut.write(0x13B, 0x0) - -# clkgrp6_div2_cfg12_mslip_msb[3:0] = 0x0 -dut.write(0x13C, 0x0) - -# clkgrp6_div2_cfg2_sel_outmux[1:0] = 0x0 -# clkgrp6_div2_cfg1_drvr_sel_testclk[2:2] = 0x0 -dut.write(0x13D, 0x0) - -# clkgrp6_div2_cfg5_drvr_res[1:0] = 0x1 -# clkgrp6_div2_cfg5_drvr_spare[2:2] = 0x0 -# clkgrp6_div2_cfg5_drvr_mode[4:3] = 0x2 -# clkgrp6_div2_cfg_outbuf_dyn[5:5] = 0x0 -# clkgrp6_div2_cfg2_mutesel[7:6] = 0x0 -dut.write(0x13E, 0x11) - -# clkgrp7_div1_cfg1_en[0:0] = 0x0 -# clkgrp7_div1_cfg1_phdelta_mslip[1:1] = 0x1 -# clkgrp7_div1_cfg2_startmode[3:2] = 0x0 -# clkgrp7_div1_cfg1_rev[4:4] = 0x1 -# clkgrp7_div1_cfg1_slipmask[5:5] = 0x1 -# clkgrp7_div1_cfg1_reseedmask[6:6] = 0x1 -# clkgrp7_div1_cfg1_hi_perf[7:7] = 0x0 -dut.write(0x140, 0x72) - -# clkgrp7_div1_cfg12_divrat_lsb[7:0] = 0x2 -dut.write(0x141, 0x2) - -# clkgrp7_div1_cfg12_divrat_msb[3:0] = 0x0 -dut.write(0x142, 0x0) - -# clkgrp7_div1_cfg5_fine_delay[4:0] = 0x0 -dut.write(0x143, 0x0) - -# clkgrp7_div1_cfg5_sel_coarse_delay[4:0] = 0x0 -dut.write(0x144, 0x0) - -# clkgrp7_div1_cfg12_mslip_lsb[7:0] = 0x0 -dut.write(0x145, 0x0) - -# clkgrp7_div1_cfg12_mslip_msb[3:0] = 0x0 -dut.write(0x146, 0x0) - -# clkgrp7_div1_cfg2_sel_outmux[1:0] = 0x0 -# clkgrp7_div1_cfg1_drvr_sel_testclk[2:2] = 0x0 -dut.write(0x147, 0x0) - -# clkgrp7_div1_cfg5_drvr_res[1:0] = 0x0 -# clkgrp7_div1_cfg5_drvr_spare[2:2] = 0x0 -# clkgrp7_div1_cfg5_drvr_mode[4:3] = 0x1 -# clkgrp7_div1_cfg_outbuf_dyn[5:5] = 0x0 -# clkgrp7_div1_cfg2_mutesel[7:6] = 0x0 -dut.write(0x148, 0x8) - -# clkgrp7_div2_cfg1_en[0:0] = 0x0 -# clkgrp7_div2_cfg1_phdelta_mslip[1:1] = 0x0 -# clkgrp7_div2_cfg2_startmode[3:2] = 0x0 -# clkgrp7_div2_cfg1_rev[4:4] = 0x1 -# clkgrp7_div2_cfg1_slipmask[5:5] = 0x1 -# clkgrp7_div2_cfg1_reseedmask[6:6] = 0x1 -# clkgrp7_div2_cfg1_hi_perf[7:7] = 0x0 -dut.write(0x14A, 0x70) - -# clkgrp7_div2_cfg12_divrat_lsb[7:0] = 0x80 -dut.write(0x14B, 0x80) - -# clkgrp7_div2_cfg12_divrat_msb[3:0] = 0x0 -dut.write(0x14C, 0x0) - -# clkgrp7_div2_cfg5_fine_delay[4:0] = 0x0 -dut.write(0x14D, 0x0) - -# clkgrp7_div2_cfg5_sel_coarse_delay[4:0] = 0x0 -dut.write(0x14E, 0x0) - -# clkgrp7_div2_cfg12_mslip_lsb[7:0] = 0x0 -dut.write(0x14F, 0x0) - -# clkgrp7_div2_cfg12_mslip_msb[3:0] = 0x0 -dut.write(0x150, 0x0) - -# clkgrp7_div2_cfg2_sel_outmux[1:0] = 0x0 -# clkgrp7_div2_cfg1_drvr_sel_testclk[2:2] = 0x0 -dut.write(0x151, 0x0) - -# clkgrp7_div2_cfg5_drvr_res[1:0] = 0x3 -# clkgrp7_div2_cfg5_drvr_spare[2:2] = 0x0 -# clkgrp7_div2_cfg5_drvr_mode[4:3] = 0x1 -# clkgrp7_div2_cfg_outbuf_dyn[5:5] = 0x0 -# clkgrp7_div2_cfg2_mutesel[7:6] = 0x0 -dut.write(0x152, 0xB) \ No newline at end of file diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 7e5cf3971..96688d661 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -113,7 +113,8 @@ mod hmc830 { if addr == 0x0d || addr == 0x0e { continue; } error!("[0x{:02x}] = 0x{:04x}", addr, read(addr)); } - return Err("HMC830 lock timeout"); + // return Err("HMC830 lock timeout"); + break; } } @@ -123,8 +124,30 @@ mod hmc830 { mod hmc7043 { use board::csr; + + // To do: check which output channels we actually need + const DAC_CLK_DIV: u32 = 2; + const FPGA_CLK_DIV: u32 = 8; + const SYSREF_DIV: u32 = 128; + + // enabled, divider, analog phase shift, digital phase shift + const OUTPUT_CONFIG: [(bool, u32, u8, u8); 14] = [ + (true, DAC_CLK_DIV, 0x0, 0x0), // 0: DAC2_CLK + (true, SYSREF_DIV, 0x0, 0x0), // 1: DAC2_SYSREF + (true, DAC_CLK_DIV, 0x0, 0x0), // 2: DAC1_CLK + (true, SYSREF_DIV, 0x0, 0x0), // 3: DAC1_SYSREF + (false, 0, 0x0, 0x0), // 4: ADC2_CLK + (false, 0, 0x0, 0x0), // 5: ADC2_SYSREF + (true, FPGA_CLK_DIV, 0x0, 0x0), // 6: GTP_CLK2 + (true, SYSREF_DIV, 0x0, 0x0), // 7: FPGA_DAC_SYSREF + (true, FPGA_CLK_DIV, 0x0, 0x0), // 8: GTP_CLK1 + (true, FPGA_CLK_DIV, 0x0, 0x0), // 9: AMC_MASTER_AUX_CLK + (true, FPGA_CLK_DIV, 0x0, 0x0), // 10: RTM_MASTER_AUX_CLK + (false, 0, 0x0, 0x0), // 11: FPGA_ADC_SYSREF + (false, 0, 0x0, 0x0), // 12: ADC1_CLK + (false, 0, 0x0, 0x0), // 13: ADC1_SYSREF + ]; - include!(concat!(env!("OUT_DIR"), "/hmc7043_writes.rs")); fn spi_setup() { unsafe { @@ -176,26 +199,47 @@ mod hmc7043 { info!("HMC7043 found"); } info!("HMC7043 configuration..."); - /* global configuration */ - for &(addr, data) in HMC7043_WRITES.iter() { - write(addr, data); + + write(0x0, 0x1); // Software reset + write(0x0, 0x0); + + write(0x1, 0x40); // Enable high-performace/low-noise mode + write(0x3, 0x10); // Disable SYSREF timer + write(0xA, 0x06); // Disable the REFSYNCIN input + write(0xB, 0x07); // Enable the CLKIN input as LVPECL + write(0x50, 0x1f); // Disable GPO pin + write(0x9F, 0x4d); // Unexplained high-performance mode + write(0xA0, 0xdf); // Unexplained high-performance mode + + // Enable required output groups + write(0x4, (1 << 0) | + (1 << 1) | + (1 << 3) | + (1 << 4) | + (1 << 5)); + + for channel in 0..14 { + let channel_base = 0xc8 + 0x0a*(channel as u16); + let (enabled, divider, aphase, dphase) = OUTPUT_CONFIG[channel]; + + if enabled { + // Only clock channels need to be high-performance + if (channel % 2) == 0 { write(channel_base, 0x91); } + else { write(channel_base, 0x11); } + } + else { write(channel_base, 0x10); } + write(channel_base + 0x1, (divider & 0x0ff) as u8); + write(channel_base + 0x2, ((divider & 0x700) >> 8) as u8); + write(channel_base + 0x3, aphase & 0x1f); + write(channel_base + 0x4, dphase & 0x1f); + + // No analog phase shift on clock channels + if (channel % 2) == 0 { write(channel_base + 0x7, 0x00); } + else { write(channel_base + 0x7, 0x01); } + + write(channel_base + 0x8, 0x08) } - /* dac1 sysref digital coarse delay configuration (17 steps, 1/2VCO cycle/step)*/ - write(0x0d6, 0); - /* dac1 sysref analog fine delay configuration (24 steps, 25ps/step)*/ - write(0x0d5, 0); - - /* dac2 sysref digital coarse delay configuration (17 steps, 1/2VCO cycle/step)*/ - write(0x0ea, 0); - /* dac2 sysref analog fine delay configuration (24 steps, 25ps/step)*/ - write(0x0e9, 0); - - /* fpga sysref digital coarse delay configuration (17 steps, 1/2VCO cycle/step)*/ - write(0x112, 0); - /* fpga sysref analog fine delay configuration (24 steps, 25ps/step)*/ - write(0x111, 0); - Ok(()) } } From fb8b36cd41e35afec15e48152fc39bb469d3db86 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 17 Feb 2018 12:10:46 +0800 Subject: [PATCH 0332/2457] clean up ccc279b8 --- artiq/firmware/libboard_artiq/build.rs | 24 -------------------- artiq/firmware/libboard_artiq/hmc830_7043.rs | 3 +-- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/artiq/firmware/libboard_artiq/build.rs b/artiq/firmware/libboard_artiq/build.rs index 508c9f935..3548ea5ff 100644 --- a/artiq/firmware/libboard_artiq/build.rs +++ b/artiq/firmware/libboard_artiq/build.rs @@ -1,29 +1,5 @@ extern crate build_misoc; -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::Path; -use std::process::Command; - -fn gen_hmc7043_writes() { - println!("cargo:rerun-if-changed=hmc7043_gen_writes.py"); - println!("cargo:rerun-if-changed=hmc7043_guiexport_6gbps.py"); - - let hmc7043_writes = - Command::new("python3") - .arg("hmc7043_gen_writes.py") - .arg("hmc7043_guiexport_6gbps.py") - .output() - .ok() - .and_then(|o| String::from_utf8(o.stdout).ok()) - .unwrap(); - let out_dir = env::var("OUT_DIR").unwrap(); - let mut f = File::create(Path::new(&out_dir).join("hmc7043_writes.rs")).unwrap(); - write!(f, "{}", hmc7043_writes).unwrap(); -} - fn main() { build_misoc::cfg(); - gen_hmc7043_writes(); } diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 96688d661..80406251c 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -113,8 +113,7 @@ mod hmc830 { if addr == 0x0d || addr == 0x0e { continue; } error!("[0x{:02x}] = 0x{:04x}", addr, read(addr)); } - // return Err("HMC830 lock timeout"); - break; + return Err("HMC830 lock timeout"); } } From 07a31f8d867d24d3c31a2e6241a2f7e159e153e7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 17 Feb 2018 13:21:10 +0800 Subject: [PATCH 0333/2457] conda: bump openocd --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 477bdf569..e6318d0c5 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -22,7 +22,7 @@ requirements: - llvm-or1k 4.0.1 - llvmlite-artiq 0.20.0 - rust-core-or1k 1.23.0 19 - - openocd 0.10.0 4 + - openocd 0.10.0 6 - lit - outputcheck - coverage From cfb21ca126fcd3d44b777939ee959e23e4ab11df Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 17 Feb 2018 13:52:01 +0800 Subject: [PATCH 0334/2457] si5324: fix usage of external CLKIN2 reference --- artiq/firmware/libboard_artiq/si5324.rs | 7 +++++-- artiq/firmware/runtime/main.rs | 10 ++++++---- artiq/firmware/satman/main.rs | 3 ++- artiq/gateware/targets/kasli.py | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 69ed734db..acf6a2678 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -43,7 +43,8 @@ pub struct FrequencySettings { pub n2_ls: u32, pub n31: u32, pub n32: u32, - pub bwsel: u8 + pub bwsel: u8, + pub crystal_ref: bool } fn map_frequency_settings(settings: &FrequencySettings) -> Result { @@ -201,7 +202,9 @@ pub fn setup(settings: &FrequencySettings) -> Result<()> { #[cfg(si5324_soft_reset)] soft_reset()?; - write(0, read(0)? | 0x40)?; // FREE_RUN=1 + if settings.crystal_ref { + write(0, read(0)? | 0x40)?; // FREE_RUN=1 + } write(2, (read(2)? & 0x0f) | (s.bwsel << 4))?; write(21, read(21)? & 0xfe)?; // CKSEL_PIN=0 write(3, (read(3)? & 0x3f) | (0b01 << 6) | 0x10)?; // CKSEL_REG=b01 SQ_ICAL=1 diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 364f801e9..45e856526 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -111,7 +111,6 @@ fn startup() { fn setup_si5324_free_running() { // 125MHz output, from 100MHz CLKIN2 reference, 9 Hz - // FIXME: needs !FREE_RUN at address 0x00 #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref))] const SI5324_SETTINGS: board_artiq::si5324::FrequencySettings = board_artiq::si5324::FrequencySettings { @@ -121,7 +120,8 @@ fn setup_si5324_free_running() n2_ls : 260, n31 : 65, n32 : 52, - bwsel : 10 + bwsel : 10, + crystal_ref: false }; // 125MHz output, from crystal, 7 Hz #[cfg(all(rtio_frequency = "125.0", not(si5324_ext_ref)))] @@ -133,7 +133,8 @@ fn setup_si5324_free_running() n2_ls : 19972, n31 : 4993, n32 : 4565, - bwsel : 4 + bwsel : 4, + crystal_ref: true }; // 150MHz output, from crystal #[cfg(all(rtio_frequency = "150.0", not(si5324_ext_ref)))] @@ -145,7 +146,8 @@ fn setup_si5324_free_running() n2_ls : 33732, n31 : 9370, n32 : 7139, - bwsel : 3 + bwsel : 3, + crystal_ref: true }; board_artiq::si5324::setup(&SI5324_SETTINGS).expect("cannot initialize Si5324"); } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 99de319cf..cdaebff47 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -183,7 +183,8 @@ const SI5324_SETTINGS: si5324::FrequencySettings n2_ls : 33732, n31 : 9370, n32 : 7139, - bwsel : 3 + bwsel : 3, + crystal_ref: true }; fn drtio_link_is_up() -> bool { diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 2fd9058ae..72b147064 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -230,7 +230,7 @@ class Opticlock(_StandaloneBase): _StandaloneBase.__init__(self, **kwargs) self.config["SI5324_FREE_RUNNING"] = None - # self.config["SI5324_EXT_REF"] = None + self.config["SI5324_EXT_REF"] = None self.config["RTIO_FREQUENCY"] = "125.0" platform = self.platform From 039dee4c8e339ace99ec73991674584e8530cbac Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 17 Feb 2018 13:54:50 +0800 Subject: [PATCH 0335/2457] si5324: rename SI5324_FREE_RUNNING to SI5324_AS_SYNTHESIZER The previous name was causing confusion with the FREE_RUN bit that connects the crystal to CLKIN2. --- artiq/firmware/runtime/main.rs | 8 ++++---- artiq/gateware/targets/kasli.py | 4 ++-- artiq/gateware/targets/sayma_amc.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 45e856526..21d0edf85 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -89,8 +89,8 @@ fn startup() { #[cfg(has_i2c)] board_artiq::i2c::init(); - #[cfg(si5324_free_running)] - setup_si5324_free_running(); + #[cfg(si5324_as_synthesizer)] + setup_si5324_as_synthesizer(); #[cfg(has_hmc830_7043)] board_artiq::hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] @@ -107,8 +107,8 @@ fn startup() { } } -#[cfg(si5324_free_running)] -fn setup_si5324_free_running() +#[cfg(si5324_as_synthesizer)] +fn setup_si5324_as_synthesizer() { // 125MHz output, from 100MHz CLKIN2 reference, 9 Hz #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref))] diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 72b147064..6ef5c610e 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -229,7 +229,7 @@ class Opticlock(_StandaloneBase): def __init__(self, **kwargs): _StandaloneBase.__init__(self, **kwargs) - self.config["SI5324_FREE_RUNNING"] = None + self.config["SI5324_AS_SYNTHESIZER"] = None self.config["SI5324_EXT_REF"] = None self.config["RTIO_FREQUENCY"] = "125.0" @@ -323,7 +323,7 @@ class Master(MiniSoC, AMPSoC): self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None self.config["SI5324_SOFT_RESET"] = None - self.config["SI5324_FREE_RUNNING"] = None + self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.comb += platform.request("sfp_ctl", 2).tx_disable.eq(0) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index b25a924cb..eaa1232ac 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -292,7 +292,7 @@ class Master(MiniSoC, AMPSoC): self.csr_devices.append("i2c") self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None - self.config["SI5324_FREE_RUNNING"] = None + self.config["SI5324_AS_SYNTHESIZER"] = None self.comb += platform.request("sfp_tx_disable", 0).eq(0) self.submodules.transceiver = gth_ultrascale.GTH( From 73985a9215be5b411c37fc6a228b80d45556fe5e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 17 Feb 2018 17:38:17 +0800 Subject: [PATCH 0336/2457] sayma: remove constraints at outputs of serwb PLL (see misoc d1489ed) --- artiq/gateware/targets/sayma_amc.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index eaa1232ac..ab76f9fa5 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -176,11 +176,7 @@ class Standalone(MiniSoC, AMPSoC): self.csr_devices.append("serwb_phy_amc") serwb_phy_amc.serdes.cd_serwb_serdes.clk.attr.add("keep") - serwb_phy_amc.serdes.cd_serwb_serdes_20x.clk.attr.add("keep") serwb_phy_amc.serdes.cd_serwb_serdes_5x.clk.attr.add("keep") - platform.add_period_constraint(serwb_phy_amc.serdes.cd_serwb_serdes.clk, 40*1e9/serwb_pll.linerate), - platform.add_period_constraint(serwb_phy_amc.serdes.cd_serwb_serdes_20x.clk, 2*1e9/serwb_pll.linerate), - platform.add_period_constraint(serwb_phy_amc.serdes.cd_serwb_serdes_5x.clk, 8*1e9/serwb_pll.linerate) platform.add_false_path_constraints( self.crg.cd_sys.clk, serwb_phy_amc.serdes.cd_serwb_serdes.clk, From 287d5334373795b6d5a01efbfd7f74e53811155d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 17 Feb 2018 17:38:48 +0800 Subject: [PATCH 0337/2457] Revert "sayma_amc: remove RTM bitstream upload core. Closes #908" This reverts commit 2d4a1340ea3a25dbaaa2200b7e86d2f42e7a19b5. --- artiq/gateware/targets/sayma_amc.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index ab76f9fa5..b83f08cfb 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -160,10 +160,9 @@ class Standalone(MiniSoC, AMPSoC): ] # RTM bitstream upload - # https://github.com/m-labs/artiq/issues/908#issuecomment-363650534 - #rtm_fpga_cfg = platform.request("rtm_fpga_cfg") - #self.submodules.rtm_fpga_cfg = SlaveFPGA(rtm_fpga_cfg) - #self.csr_devices.append("rtm_fpga_cfg") + rtm_fpga_cfg = platform.request("rtm_fpga_cfg") + self.submodules.rtm_fpga_cfg = SlaveFPGA(rtm_fpga_cfg) + self.csr_devices.append("rtm_fpga_cfg") # AMC/RTM serwb serwb_pll = serwb.phy.SERWBPLL(125e6, 625e6, vco_div=2) From 41adbef9a9d81e274133b0c58beebbae2add883b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 17 Feb 2018 17:41:16 +0800 Subject: [PATCH 0338/2457] conda: bump misoc --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index e6318d0c5..e3c14ca7d 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_2+git40721b2 - - misoc 0.9 py35_6+git5c3ca413 + - misoc 0.9 py35_9+gitd1489edf - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From 6ae1cc20aac57abb9fbfdb9e32f06a2a8fb1b92f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 18 Feb 2018 12:35:49 +0800 Subject: [PATCH 0339/2457] conda: bump misoc (#908) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index e3c14ca7d..c9acb8403 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_2+git40721b2 - - misoc 0.9 py35_9+gitd1489edf + - misoc 0.9 py35_10+git3072d794 - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From 75c89422c95c226b1d45470b341002f607dcebd7 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 16 Feb 2018 17:51:57 +0000 Subject: [PATCH 0340/2457] ad991[02]: sysclk can be 1 GHz --- artiq/coredevice/ad9910.py | 2 +- artiq/coredevice/ad9912.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 22d490583..3f44a7625 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -62,7 +62,7 @@ class AD9910: self.pll_n = pll_n assert self.cpld.refclk < 60e6 self.sysclk = self.cpld.refclk*pll_n/4 # Urukul clock fanout divider - assert self.sysclk < 1e9 + assert self.sysclk <= 1e9 self.ftw_per_hz = 1./self.sysclk*(int64(1) << 32) assert 0 <= pll_vco <= 5 vco_min, vco_max = [(370, 510), (420, 590), (500, 700), diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 931b6551e..484f531e0 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -35,7 +35,7 @@ class AD9912: self.sw = dmgr.get(sw_device) self.pll_n = pll_n self.sysclk = self.cpld.refclk*pll_n - assert self.sysclk < 1e9 + assert self.sysclk <= 1e9 self.ftw_per_hz = 1/self.sysclk*(int64(1) << 48) @kernel From caedcd5a155dffaeba7f7deb7d12d43750f9288c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 16 Feb 2018 18:47:28 +0000 Subject: [PATCH 0341/2457] ad9912: cleanup, document init() --- artiq/coredevice/ad9912.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 484f531e0..f09e91695 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -86,13 +86,13 @@ class AD9912: if (prodid != 0x1982) and (prodid != 0x1902): raise ValueError("Urukul AD9912 product id mismatch") delay(10*us) - self.write(AD9912_PWRCNTRL1, 0x80) # HSTL, CMOS power down + # HSTL power down, CMOS power down + self.write(AD9912_PWRCNTRL1, 0x80) delay(10*us) self.write(AD9912_N_DIV, self.pll_n//2 - 2) delay(10*us) - self.write(AD9912_PLLCFG, 0b00000101) # 375 µA, high range - at_mu(t) - delay(100*us) # constant duration of 100 µs + # I_cp = 375 µA, VCO high range + self.write(AD9912_PLLCFG, 0b00000101) @kernel def set_att_mu(self, att): From c87636ed2bbf82b19f0cb84131005e4ba034bb53 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 18 Feb 2018 10:35:30 +0000 Subject: [PATCH 0342/2457] si5324: fix cfb21ca --- artiq/firmware/libboard_artiq/si5324.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index acf6a2678..db96c7acc 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -93,7 +93,8 @@ fn map_frequency_settings(settings: &FrequencySettings) -> Result Date: Sun, 18 Feb 2018 22:29:30 +0800 Subject: [PATCH 0343/2457] drtio: signal stable clock input to transceiver --- artiq/firmware/runtime/rtio_mgt.rs | 3 +++ artiq/firmware/satman/main.rs | 3 +++ artiq/gateware/drtio/core.py | 4 +++- artiq/gateware/drtio/transceiver/gth_ultrascale.py | 2 ++ artiq/gateware/drtio/transceiver/gtp_7series.py | 5 +++++ .../gateware/drtio/transceiver/gtp_7series_init.py | 3 ++- artiq/gateware/targets/kasli.py | 14 ++++++++------ 7 files changed, 26 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index cc63b86e2..f481b04ad 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -41,6 +41,9 @@ pub mod drtio { use drtioaux; pub fn startup(io: &Io) { + unsafe { + csr::drtio_transceiver::stable_clkin_write(1); + } io.spawn(4096, link_thread); } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index cdaebff47..a2c155085 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -206,6 +206,9 @@ fn startup() { hmc830_7043::init().expect("cannot initialize HMC830/7043"); i2c::init(); si5324::setup(&SI5324_SETTINGS).expect("cannot initialize Si5324"); + unsafe { + csr::drtio_transceiver::stable_clkin_write(1); + } loop { while !drtio_link_is_up() { diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 0bda7ad38..12b12b1ab 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -2,6 +2,7 @@ from types import SimpleNamespace from migen import * from migen.genlib.cdc import ElasticBuffer +from misoc.interconnect.csr import * from artiq.gateware.rtio.sed.core import * from artiq.gateware.rtio.input_collector import * @@ -17,8 +18,9 @@ class ChannelInterface: self.decoders = decoders -class TransceiverInterface: +class TransceiverInterface(AutoCSR): def __init__(self, channel_interfaces): + self.stable_clkin = CSRStorage() self.clock_domains.cd_rtio = ClockDomain() for i in range(len(channel_interfaces)): name = "rtio_rx" + str(i) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index a6a098b19..1e1a5a9e6 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -251,6 +251,8 @@ class GTH(Module, TransceiverInterface): channel_interfaces.append(channel_interface) TransceiverInterface.__init__(self, channel_interfaces) + # GTH PLLs recover on their own from an interrupted clock input. + # stable_clkin can be ignored. self.comb += [ self.cd_rtio.clk.eq(self.gths[master].cd_rtio_tx.clk), diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py index 6ea82de9c..4ed906391 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -15,6 +15,8 @@ class GTPSingle(Module): def __init__(self, qpll_channel, pads, sys_clk_freq, rtio_clk_freq, mode): if mode != "master": raise NotImplementedError + + self.stable_clkin = Signal() self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( Encoder(2, True)) self.submodules.decoders = decoders = [ClockDomainsRenamer("rtio_rx")( @@ -35,6 +37,7 @@ class GTPSingle(Module): self.submodules += tx_init, rx_init self.comb += [ + tx_init.stable_clkin.eq(self.stable_clkin), qpll_channel.reset.eq(tx_init.pllreset), tx_init.plllock.eq(qpll_channel.lock), rx_init.plllock.eq(qpll_channel.lock), @@ -721,6 +724,8 @@ class GTP(Module, TransceiverInterface): channel_interfaces.append(channel_interface) TransceiverInterface.__init__(self, channel_interfaces) + for gtp in self.gtps: + self.comb += gtp.stable_clkin.eq(self.stable_clkin.storage) self.comb += [ self.cd_rtio.clk.eq(self.gtps[master].cd_rtio_tx.clk), diff --git a/artiq/gateware/drtio/transceiver/gtp_7series_init.py b/artiq/gateware/drtio/transceiver/gtp_7series_init.py index e544a90b2..8e742d342 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series_init.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series_init.py @@ -10,6 +10,7 @@ __all__ = ["GTPTXInit", "GTPRXInit"] class GTPTXInit(Module): def __init__(self, sys_clk_freq): + self.stable_clkin = Signal() self.done = Signal() self.restart = Signal() @@ -82,7 +83,7 @@ class GTPTXInit(Module): startup_fsm.act("PLL_RESET", self.pllreset.eq(1), pll_reset_timer.wait.eq(1), - If(pll_reset_timer.done, + If(pll_reset_timer.done & self.stable_clkin, NextState("GTP_RESET") ) ) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 6ef5c610e..43d8b6031 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -327,14 +327,15 @@ class Master(MiniSoC, AMPSoC): self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.comb += platform.request("sfp_ctl", 2).tx_disable.eq(0) - self.submodules.transceiver = gtp_7series.GTP( + self.submodules.drtio_transceiver = gtp_7series.GTP( qpll_channel=self.drtio_qpll_channel, data_pads=[platform.request("sfp", 2)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) + self.csr_devices.append("drtio_transceiver") self.submodules.drtio0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"})( - DRTIOMaster(self.transceiver.channels[0])) + DRTIOMaster(self.drtio_transceiver.channels[0])) self.csr_devices.append("drtio0") self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, self.drtio0.aux_controller.bus) @@ -344,7 +345,7 @@ class Master(MiniSoC, AMPSoC): self.add_memory_group("drtio_aux", ["drtio0_aux"]) rtio_clk_period = 1e9/rtio_clk_freq - for gtp in self.transceiver.gtps: + for gtp in self.drtio_transceiver.gtps: platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( @@ -447,14 +448,15 @@ class Satellite(BaseSoC): self.submodules += qpll self.comb += platform.request("sfp_ctl", 0).tx_disable.eq(0) - self.submodules.transceiver = gtp_7series.GTP( + self.submodules.drtio_transceiver = gtp_7series.GTP( qpll_channel=qpll.channels[0], data_pads=[platform.request("sfp", 0)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) + self.csr_devices.append("drtio_transceiver") rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) self.submodules.drtio0 = rx0(DRTIOSatellite( - self.transceiver.channels[0], rtio_channels)) + self.drtio_transceiver.channels[0], rtio_channels)) self.csr_devices.append("drtio0") self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, self.drtio0.aux_controller.bus) @@ -478,7 +480,7 @@ class Satellite(BaseSoC): self.config["SI5324_SOFT_RESET"] = None rtio_clk_period = 1e9/rtio_clk_freq - gtp = self.transceiver.gtps[0] + gtp = self.drtio_transceiver.gtps[0] platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( From 94c20dfd4d8fdce9af676d0295cfc641a9c550d0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 19 Feb 2018 00:47:54 +0800 Subject: [PATCH 0344/2457] drtio: fix misleading GenericRXSynchronizer comment --- artiq/gateware/drtio/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 12b12b1ab..06ced73d6 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -31,8 +31,8 @@ class TransceiverInterface(AutoCSR): class GenericRXSynchronizer(Module): """Simple RX synchronizer based on the portable Migen elastic buffer. - Introduces timing non-determinism in the satellite -> master path, - (and in the echo_request/echo_reply RTT) but useful for testing. + Introduces timing non-determinism in the satellite RX path, e.g. + echo_request/echo_reply RTT and TSC sync, but useful for testing. """ def __init__(self): self.signals = [] From a93decdef2ea266a1e84505ad4034749cdead3fe Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 19 Feb 2018 00:48:37 +0800 Subject: [PATCH 0345/2457] kasli: disable DRTIO IBUFDS_GTE2 until Si5324 is initialized --- artiq/gateware/targets/kasli.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 43d8b6031..39a675b4f 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -333,6 +333,8 @@ class Master(MiniSoC, AMPSoC): sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") + self.sync += self.disable_si5324_ibuf.eq( + ~self.drtio_transceiver.stable_clkin.storage) self.submodules.drtio0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"})( DRTIOMaster(self.drtio_transceiver.channels[0])) @@ -379,16 +381,20 @@ class Master(MiniSoC, AMPSoC): # Never running out of stupid features, GTs on A7 make you pack # unrelated transceiver PLLs into one GTPE2_COMMON yourself. def create_qpll(self): + # The GTP acts up if you send any glitch to its + # clock input, even while the PLL is held in reset. + self.disable_si5324_ibuf = Signal(reset=1) + self.disable_si5324_ibuf.attr.add("keep") si5324_clkout = self.platform.request("si5324_clkout") si5324_clkout_buf = Signal() self.specials += Instance("IBUFDS_GTE2", - i_CEB=0, + i_CEB=self.disable_si5324_ibuf, i_I=si5324_clkout.p, i_IB=si5324_clkout.n, o_O=si5324_clkout_buf) # Note precisely the rules Xilinx made up: # refclksel=0b001 GTREFCLK0 selected # refclksel=0b010 GTREFCLK1 selected - # but if only one clock used, then it must be 001. + # but if only one clock is used, then it must be 001. qpll_drtio_settings = QPLLSettings( refclksel=0b001, fbdiv=4, @@ -433,10 +439,12 @@ class Satellite(BaseSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") + disable_si5324_ibuf = Signal(reset=1) + disable_si5324_ibuf.attr.add("keep") si5324_clkout = platform.request("si5324_clkout") si5324_clkout_buf = Signal() self.specials += Instance("IBUFDS_GTE2", - i_CEB=0, + i_CEB=disable_si5324_ibuf, i_I=si5324_clkout.p, i_IB=si5324_clkout.n, o_O=si5324_clkout_buf) qpll_drtio_settings = QPLLSettings( @@ -454,6 +462,9 @@ class Satellite(BaseSoC): sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") + self.sync += disable_si5324_ibuf.eq( + ~self.drtio_transceiver.stable_clkin.storage) + rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) self.submodules.drtio0 = rx0(DRTIOSatellite( self.drtio_transceiver.channels[0], rtio_channels)) From c329c83676fb4e9adac5978f18876001f1b99901 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 19 Feb 2018 12:18:59 +0800 Subject: [PATCH 0346/2457] kasli: fix disable_si5324_ibuf no_retiming --- artiq/gateware/targets/kasli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 39a675b4f..48ed7ab0b 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -384,7 +384,7 @@ class Master(MiniSoC, AMPSoC): # The GTP acts up if you send any glitch to its # clock input, even while the PLL is held in reset. self.disable_si5324_ibuf = Signal(reset=1) - self.disable_si5324_ibuf.attr.add("keep") + self.disable_si5324_ibuf.attr.add("no_retiming") si5324_clkout = self.platform.request("si5324_clkout") si5324_clkout_buf = Signal() self.specials += Instance("IBUFDS_GTE2", @@ -440,7 +440,7 @@ class Satellite(BaseSoC): self.csr_devices.append("rtio_moninj") disable_si5324_ibuf = Signal(reset=1) - disable_si5324_ibuf.attr.add("keep") + disable_si5324_ibuf.attr.add("no_retiming") si5324_clkout = platform.request("si5324_clkout") si5324_clkout_buf = Signal() self.specials += Instance("IBUFDS_GTE2", From 4b4090518b3975f6c52300a0b57167479287eb60 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 19 Feb 2018 15:14:06 +0800 Subject: [PATCH 0347/2457] drtio: clean up remnants of removed debug functions --- artiq/coredevice/drtio_dbg.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/artiq/coredevice/drtio_dbg.py b/artiq/coredevice/drtio_dbg.py index 4c92f0926..56482c6dc 100644 --- a/artiq/coredevice/drtio_dbg.py +++ b/artiq/coredevice/drtio_dbg.py @@ -8,21 +8,6 @@ from artiq.language.core import syscall from artiq.language.types import TTuple, TInt32, TInt64, TNone -@syscall(flags={"nounwind", "nowrite"}) -def drtio_get_channel_state(channel: TInt32) -> TTuple([TInt32, TInt64]): - raise NotImplementedError("syscall not simulated") - - -@syscall(flags={"nounwind", "nowrite"}) -def drtio_reset_channel_state(channel: TInt32) -> TNone: - raise NotImplementedError("syscall not simulated") - - -@syscall(flags={"nounwind", "nowrite"}) -def drtio_get_fifo_space(channel: TInt32) -> TNone: - raise NotImplementedError("syscall not simulated") - - @syscall(flags={"nounwind", "nowrite"}) def drtio_get_packet_counts(linkno: TInt32) -> TTuple([TInt32, TInt32]): raise NotImplementedError("syscall not simulated") From 01fa6c1c2ea75b0747dcc6f84c583b489292ed0e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 19 Feb 2018 15:46:08 +0800 Subject: [PATCH 0348/2457] reorganize examples --- artiq/examples/{kasli => kasli_opticlock}/device_db.py | 1 - artiq/examples/{kasli => kasli_opticlock}/idle_kernel.py | 0 artiq/examples/{kasli => kasli_opticlock}/repository/urukul.py | 0 artiq/examples/{kc705 => kc705_nist_clock}/device_db.py | 1 - artiq/examples/{kc705 => kc705_nist_clock}/idle_kernel.py | 0 artiq/examples/{kc705 => kc705_nist_clock}/repository/ad5360.py | 0 .../{kc705 => kc705_nist_clock}/repository/blink_forever.py | 0 .../{kc705 => kc705_nist_clock}/repository/core_pause.py | 0 .../{kc705 => kc705_nist_clock}/repository/dds_setter.py | 0 .../examples/{kc705 => kc705_nist_clock}/repository/dds_test.py | 0 .../{kc705 => kc705_nist_clock}/repository/dma_blink.py | 0 .../examples/{kc705 => kc705_nist_clock}/repository/handover.py | 0 .../{kc705 => kc705_nist_clock}/repository/mandelbrot.py | 0 .../{kc705 => kc705_nist_clock}/repository/photon_histogram.py | 0 .../{kc705 => kc705_nist_clock}/repository/speed_benchmark.py | 0 artiq/examples/{kc705 => kc705_nist_clock}/repository/tdr.py | 0 artiq/examples/{kc705 => kc705_nist_clock}/repository/urukul.py | 0 artiq/examples/sayma_drtio/device_db.py | 2 +- artiq/examples/sayma_standalone/device_db.py | 2 +- 19 files changed, 2 insertions(+), 4 deletions(-) rename artiq/examples/{kasli => kasli_opticlock}/device_db.py (99%) rename artiq/examples/{kasli => kasli_opticlock}/idle_kernel.py (100%) rename artiq/examples/{kasli => kasli_opticlock}/repository/urukul.py (100%) rename artiq/examples/{kc705 => kc705_nist_clock}/device_db.py (99%) rename artiq/examples/{kc705 => kc705_nist_clock}/idle_kernel.py (100%) rename artiq/examples/{kc705 => kc705_nist_clock}/repository/ad5360.py (100%) rename artiq/examples/{kc705 => kc705_nist_clock}/repository/blink_forever.py (100%) rename artiq/examples/{kc705 => kc705_nist_clock}/repository/core_pause.py (100%) rename artiq/examples/{kc705 => kc705_nist_clock}/repository/dds_setter.py (100%) rename artiq/examples/{kc705 => kc705_nist_clock}/repository/dds_test.py (100%) rename artiq/examples/{kc705 => kc705_nist_clock}/repository/dma_blink.py (100%) rename artiq/examples/{kc705 => kc705_nist_clock}/repository/handover.py (100%) rename artiq/examples/{kc705 => kc705_nist_clock}/repository/mandelbrot.py (100%) rename artiq/examples/{kc705 => kc705_nist_clock}/repository/photon_histogram.py (100%) rename artiq/examples/{kc705 => kc705_nist_clock}/repository/speed_benchmark.py (100%) rename artiq/examples/{kc705 => kc705_nist_clock}/repository/tdr.py (100%) rename artiq/examples/{kc705 => kc705_nist_clock}/repository/urukul.py (100%) diff --git a/artiq/examples/kasli/device_db.py b/artiq/examples/kasli_opticlock/device_db.py similarity index 99% rename from artiq/examples/kasli/device_db.py rename to artiq/examples/kasli_opticlock/device_db.py index 418a4119a..1600797ec 100644 --- a/artiq/examples/kasli/device_db.py +++ b/artiq/examples/kasli_opticlock/device_db.py @@ -1,5 +1,4 @@ # This is an example device database that needs to be adapted to your setup. -# The RTIO channel numbers here are for OPTICLOCK on KASLI. # The list of devices here is not exhaustive. core_addr = "vettel.ber.quartiq.de" diff --git a/artiq/examples/kasli/idle_kernel.py b/artiq/examples/kasli_opticlock/idle_kernel.py similarity index 100% rename from artiq/examples/kasli/idle_kernel.py rename to artiq/examples/kasli_opticlock/idle_kernel.py diff --git a/artiq/examples/kasli/repository/urukul.py b/artiq/examples/kasli_opticlock/repository/urukul.py similarity index 100% rename from artiq/examples/kasli/repository/urukul.py rename to artiq/examples/kasli_opticlock/repository/urukul.py diff --git a/artiq/examples/kc705/device_db.py b/artiq/examples/kc705_nist_clock/device_db.py similarity index 99% rename from artiq/examples/kc705/device_db.py rename to artiq/examples/kc705_nist_clock/device_db.py index 28117fca0..1beebf7c1 100644 --- a/artiq/examples/kc705/device_db.py +++ b/artiq/examples/kc705_nist_clock/device_db.py @@ -1,5 +1,4 @@ # This is an example device database that needs to be adapted to your setup. -# The RTIO channel numbers here are for NIST CLOCK on KC705. # The list of devices here is not exhaustive. core_addr = "kc705-1.lab.m-labs.hk" diff --git a/artiq/examples/kc705/idle_kernel.py b/artiq/examples/kc705_nist_clock/idle_kernel.py similarity index 100% rename from artiq/examples/kc705/idle_kernel.py rename to artiq/examples/kc705_nist_clock/idle_kernel.py diff --git a/artiq/examples/kc705/repository/ad5360.py b/artiq/examples/kc705_nist_clock/repository/ad5360.py similarity index 100% rename from artiq/examples/kc705/repository/ad5360.py rename to artiq/examples/kc705_nist_clock/repository/ad5360.py diff --git a/artiq/examples/kc705/repository/blink_forever.py b/artiq/examples/kc705_nist_clock/repository/blink_forever.py similarity index 100% rename from artiq/examples/kc705/repository/blink_forever.py rename to artiq/examples/kc705_nist_clock/repository/blink_forever.py diff --git a/artiq/examples/kc705/repository/core_pause.py b/artiq/examples/kc705_nist_clock/repository/core_pause.py similarity index 100% rename from artiq/examples/kc705/repository/core_pause.py rename to artiq/examples/kc705_nist_clock/repository/core_pause.py diff --git a/artiq/examples/kc705/repository/dds_setter.py b/artiq/examples/kc705_nist_clock/repository/dds_setter.py similarity index 100% rename from artiq/examples/kc705/repository/dds_setter.py rename to artiq/examples/kc705_nist_clock/repository/dds_setter.py diff --git a/artiq/examples/kc705/repository/dds_test.py b/artiq/examples/kc705_nist_clock/repository/dds_test.py similarity index 100% rename from artiq/examples/kc705/repository/dds_test.py rename to artiq/examples/kc705_nist_clock/repository/dds_test.py diff --git a/artiq/examples/kc705/repository/dma_blink.py b/artiq/examples/kc705_nist_clock/repository/dma_blink.py similarity index 100% rename from artiq/examples/kc705/repository/dma_blink.py rename to artiq/examples/kc705_nist_clock/repository/dma_blink.py diff --git a/artiq/examples/kc705/repository/handover.py b/artiq/examples/kc705_nist_clock/repository/handover.py similarity index 100% rename from artiq/examples/kc705/repository/handover.py rename to artiq/examples/kc705_nist_clock/repository/handover.py diff --git a/artiq/examples/kc705/repository/mandelbrot.py b/artiq/examples/kc705_nist_clock/repository/mandelbrot.py similarity index 100% rename from artiq/examples/kc705/repository/mandelbrot.py rename to artiq/examples/kc705_nist_clock/repository/mandelbrot.py diff --git a/artiq/examples/kc705/repository/photon_histogram.py b/artiq/examples/kc705_nist_clock/repository/photon_histogram.py similarity index 100% rename from artiq/examples/kc705/repository/photon_histogram.py rename to artiq/examples/kc705_nist_clock/repository/photon_histogram.py diff --git a/artiq/examples/kc705/repository/speed_benchmark.py b/artiq/examples/kc705_nist_clock/repository/speed_benchmark.py similarity index 100% rename from artiq/examples/kc705/repository/speed_benchmark.py rename to artiq/examples/kc705_nist_clock/repository/speed_benchmark.py diff --git a/artiq/examples/kc705/repository/tdr.py b/artiq/examples/kc705_nist_clock/repository/tdr.py similarity index 100% rename from artiq/examples/kc705/repository/tdr.py rename to artiq/examples/kc705_nist_clock/repository/tdr.py diff --git a/artiq/examples/kc705/repository/urukul.py b/artiq/examples/kc705_nist_clock/repository/urukul.py similarity index 100% rename from artiq/examples/kc705/repository/urukul.py rename to artiq/examples/kc705_nist_clock/repository/urukul.py diff --git a/artiq/examples/sayma_drtio/device_db.py b/artiq/examples/sayma_drtio/device_db.py index 09f70c544..039efb6bd 100644 --- a/artiq/examples/sayma_drtio/device_db.py +++ b/artiq/examples/sayma_drtio/device_db.py @@ -1,4 +1,4 @@ -core_addr = "sayma1.lab.m-labs.hk" +core_addr = "sayma-1.lab.m-labs.hk" device_db = { "core": { diff --git a/artiq/examples/sayma_standalone/device_db.py b/artiq/examples/sayma_standalone/device_db.py index f603f6e13..370b3f0a6 100644 --- a/artiq/examples/sayma_standalone/device_db.py +++ b/artiq/examples/sayma_standalone/device_db.py @@ -1,4 +1,4 @@ -core_addr = "sayma1.lab.m-labs.hk" +core_addr = "sayma-1.lab.m-labs.hk" device_db = { "core": { From 782051f4740a3bc0b05e8622e9d2f40193dcfcbe Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 19 Feb 2018 09:59:50 +0100 Subject: [PATCH 0349/2457] drtio/transceiver/gtp_7series_init: add no retiming on gtp resets --- artiq/gateware/drtio/transceiver/gtp_7series_init.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series_init.py b/artiq/gateware/drtio/transceiver/gtp_7series_init.py index 8e742d342..6c3f6ba99 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series_init.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series_init.py @@ -18,6 +18,7 @@ class GTPTXInit(Module): self.plllock = Signal() self.pllreset = Signal() self.gttxreset = Signal() + self.gttxreset.attr.add("no_retiming") self.txresetdone = Signal() self.txdlysreset = Signal() self.txdlysresetdone = Signal() @@ -147,6 +148,7 @@ class GTPRXInit(Module): # GTP signals self.plllock = Signal() self.gtrxreset = Signal() + self.gtrxreset.attr.add("no_retiming") self.gtrxpd = Signal() self.rxresetdone = Signal() self.rxdlysreset = Signal() From 89a158c0c91a98a8de698af2f0ff83ef242aa9a3 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 19 Feb 2018 10:02:23 +0100 Subject: [PATCH 0350/2457] drtio/transceiver/gtp_7series_init: remove dead code --- artiq/gateware/drtio/transceiver/gtp_7series.py | 3 +-- artiq/gateware/drtio/transceiver/gtp_7series_init.py | 9 --------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py index 4ed906391..397235e28 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -39,8 +39,7 @@ class GTPSingle(Module): self.comb += [ tx_init.stable_clkin.eq(self.stable_clkin), qpll_channel.reset.eq(tx_init.pllreset), - tx_init.plllock.eq(qpll_channel.lock), - rx_init.plllock.eq(qpll_channel.lock), + tx_init.plllock.eq(qpll_channel.lock) ] txdata = Signal(20) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series_init.py b/artiq/gateware/drtio/transceiver/gtp_7series_init.py index 6c3f6ba99..ad4b0a456 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series_init.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series_init.py @@ -146,7 +146,6 @@ class GTPRXInit(Module): self.restart = Signal() # GTP signals - self.plllock = Signal() self.gtrxreset = Signal() self.gtrxreset.attr.add("no_retiming") self.gtrxpd = Signal() @@ -185,12 +184,10 @@ class GTPRXInit(Module): self.sync += rxpmaresetdone_r.eq(rxpmaresetdone) # Double-latch transceiver asynch outputs - plllock = Signal() rxresetdone = Signal() rxdlysresetdone = Signal() rxsyncdone = Signal() self.specials += [ - MultiReg(self.plllock, plllock), MultiReg(self.rxresetdone, rxresetdone), MultiReg(self.rxdlysresetdone, rxdlysresetdone), MultiReg(self.rxsyncdone, rxsyncdone) @@ -212,12 +209,6 @@ class GTPRXInit(Module): self.rxuserrdy.eq(rxuserrdy) ] - # After configuration, transceiver resets have to stay low for - # at least 500ns (see AR43482) - pll_reset_cycles = ceil(500e-9*sys_clk_freq) - pll_reset_timer = WaitTimer(pll_reset_cycles) - self.submodules += pll_reset_timer - startup_fsm = ResetInserter()(FSM(reset_state="GTP_PD")) self.submodules += startup_fsm From f5831af535119e6e0524349724fd51d9f13657d0 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 19 Feb 2018 10:03:19 +0100 Subject: [PATCH 0351/2457] drtio/transceiver/gtp_7series_init: don't reset gtp rx on power down --- artiq/gateware/drtio/transceiver/gtp_7series_init.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series_init.py b/artiq/gateware/drtio/transceiver/gtp_7series_init.py index ad4b0a456..0414c00a3 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series_init.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series_init.py @@ -223,7 +223,6 @@ class GTPRXInit(Module): self.submodules += cdr_stable_timer startup_fsm.act("GTP_PD", - gtrxreset.eq(1), gtrxpd.eq(1), NextState("GTP_RESET") ) From 7376ab0ff8e3ca90d6cf83b9827fcfb3e86ddac4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 19 Feb 2018 16:54:43 +0800 Subject: [PATCH 0352/2457] drtio: fix Sayma after 83abdd28 --- artiq/gateware/targets/sayma_amc.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index b83f08cfb..501a4ff88 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -290,14 +290,15 @@ class Master(MiniSoC, AMPSoC): self.config["SI5324_AS_SYNTHESIZER"] = None self.comb += platform.request("sfp_tx_disable", 0).eq(0) - self.submodules.transceiver = gth_ultrascale.GTH( + self.submodules.drtio_transceiver = gth_ultrascale.GTH( clock_pads=platform.request("si5324_clkout"), data_pads=[platform.request("sfp", 0)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) + self.csr_devices.append("drtio_transceiver") self.submodules.drtio0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"})( - DRTIOMaster(self.transceiver.channels[0])) + DRTIOMaster(self.drtio_transceiver.channels[0])) self.csr_devices.append("drtio0") self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, self.drtio0.aux_controller.bus) @@ -307,7 +308,7 @@ class Master(MiniSoC, AMPSoC): self.add_memory_group("drtio_aux", ["drtio0_aux"]) rtio_clk_period = 1e9/rtio_clk_freq - for gth in self.transceiver.gths: + for gth in self.drtio_transceiver.gths: platform.add_period_constraint(gth.txoutclk, rtio_clk_period) platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( @@ -390,14 +391,15 @@ class Satellite(BaseSoC): self.csr_devices.append("rtio_moninj") self.comb += platform.request("sfp_tx_disable", 0).eq(0) - self.submodules.transceiver = gth_ultrascale.GTH( + self.submodules.drtio_transceiver = gth_ultrascale.GTH( clock_pads=platform.request("si5324_clkout"), data_pads=[platform.request("sfp", 0)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) + self.csr_devices.append("drtio_transceiver") rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) self.submodules.drtio0 = rx0(DRTIOSatellite( - self.transceiver.channels[0], rtio_channels)) + self.drtio_transceiver.channels[0], rtio_channels)) self.csr_devices.append("drtio0") self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, self.drtio0.aux_controller.bus) @@ -422,7 +424,7 @@ class Satellite(BaseSoC): self.config["HAS_SI5324"] = None rtio_clk_period = 1e9/rtio_clk_freq - gth = self.transceiver.gths[0] + gth = self.drtio_transceiver.gths[0] platform.add_period_constraint(gth.txoutclk, rtio_clk_period) platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( From 3bc575bee77f81ed8ba08e6938781c8a945f4d26 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 19 Feb 2018 17:11:21 +0800 Subject: [PATCH 0353/2457] drtio: add missing define for Sayma master --- artiq/gateware/targets/sayma_amc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 501a4ff88..86fec7f2c 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -288,6 +288,7 @@ class Master(MiniSoC, AMPSoC): self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None self.config["SI5324_AS_SYNTHESIZER"] = None + self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.comb += platform.request("sfp_tx_disable", 0).eq(0) self.submodules.drtio_transceiver = gth_ultrascale.GTH( From 52049cf36a738acb829128c44eda0c676dd937bc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 19 Feb 2018 17:49:43 +0800 Subject: [PATCH 0354/2457] drtio: add Xilinx RX synchronizer --- .../gateware/drtio/xilinx_rx_synchronizer.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 artiq/gateware/drtio/xilinx_rx_synchronizer.py diff --git a/artiq/gateware/drtio/xilinx_rx_synchronizer.py b/artiq/gateware/drtio/xilinx_rx_synchronizer.py new file mode 100644 index 000000000..d6bdfa0aa --- /dev/null +++ b/artiq/gateware/drtio/xilinx_rx_synchronizer.py @@ -0,0 +1,38 @@ +from migen import * + + +class XilinxRXSynchronizer(Module): + """Deterministic RX synchronizer using a relatively placed macro + to put the clock-domain-crossing FFs right next to each other. + + To meet setup/hold constraints receiving FFs, adjust the phase shift + of the Si5324. + + We assume that FPGA routing variations are small enough to be negligible. + """ + def __init__(self): + self.signals = [] + + def resync(self, signal): + synchronized = Signal.like(signal, related=signal) + self.signals.append((signal, synchronized)) + return synchronized + + def do_finalize(self): + l = sum(len(s[0]) for s in self.signals) + din = Signal(l) + inter = Signal(l) + dout = Signal(l) + self.comb += [ + din.eq(Cat(*[s[0] for s in self.signals])), + Cat(*[s[1] for s in self.signals]).eq(dout) + ] + + for i in range(l): + hu_set = ("HU_SET", "drtio_rx_synchronizer") + self.specials += [ + Instance("FD", i_C=ClockSignal("rtio_rx"), i_D=din[i], o_Q=inter[i], + attr={hu_set, ("RLOC", "X0Y{}".format(i))}), + Instance("FD", i_C=ClockSignal("rtio"), i_D=inter[i], o_Q=dout[i], + attr={hu_set, ("RLOC", "X1Y{}".format(i))}) + ] From 0f4549655bacc6d157911a82afd631d5afd759c4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 19 Feb 2018 17:49:53 +0800 Subject: [PATCH 0355/2457] sayma: use Xilinx RX synchronizer Cannot be used on Kasli, this breaks the bitstream entirely (nothing on UART). --- artiq/gateware/targets/sayma_amc.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 86fec7f2c..c7871c08a 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -33,6 +33,7 @@ from artiq.gateware import remote_csr from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale +from artiq.gateware.drtio.xilinx_rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite from artiq.build_soc import build_artiq_soc from artiq import __version__ as artiq_version @@ -399,8 +400,10 @@ class Satellite(BaseSoC): rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) + self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) self.submodules.drtio0 = rx0(DRTIOSatellite( - self.drtio_transceiver.channels[0], rtio_channels)) + self.drtio_transceiver.channels[0], rtio_channels, + self.rx_synchronizer)) self.csr_devices.append("drtio0") self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, self.drtio0.aux_controller.bus) From 7e02d8245cc12b6a5fe880d5d2e5e975e1d75b1a Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 19 Feb 2018 13:05:11 +0000 Subject: [PATCH 0356/2457] kasli: false paths * don't bother with the round trip OSERDESE2 -> ... -> pad -> ... -> ISERDESE2 * clock groups with derived clocks c.f. migen 9c3a301 --- artiq/gateware/targets/kasli.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 48ed7ab0b..77c1460e1 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -44,6 +44,8 @@ class _RTIOCRG(Module, AutoCSR): i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se), Instance("BUFG", i_I=clk_synth_se, o_O=rtio_external_clk), ] + platform.add_false_path_constraints( + rtio_external_clk, rtio_internal_clk) pll_locked = Signal() rtio_clk = Signal() @@ -124,7 +126,6 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.platform.add_period_constraint(self.rtio_crg.cd_rtio.clk, 8.) self.platform.add_false_path_constraints( self.crg.cd_sys.clk, self.rtio_crg.cd_rtio.clk) @@ -133,6 +134,15 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") + # ignore timing of path from OSERDESE2 through the pad to ISERDESE2 + self.platform.add_platform_command( + "set_false_path -quiet " + "-through [get_pins -filter {{REF_PIN_NAME == OQ || REF_PIN_NAME == TQ}} " + "-of [get_cells -filter {{REF_NAME == OSERDESE2}}]] " + "-to [get_pins -filter {{REF_PIN_NAME == D}} " + "-of [get_cells -filter {{REF_NAME == ISERDESE2}}]]" + ) + def _eem_signal(i): n = "d{}".format(i) From bfabf3c9068ebaf9daf4592bc8179d9dcbaa3be3 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 19 Feb 2018 13:07:17 +0000 Subject: [PATCH 0357/2457] conda: bump migen (9c3a301) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index c9acb8403..dc7687b8a 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_2+git40721b2 + - migen 0.7 py35_4+git9c3a301 - misoc 0.9 py35_10+git3072d794 - jesd204b 0.4 - microscope From ad2c9590d0dedc3da6bccd4d55ede00a291dd6b9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 20 Feb 2018 17:26:01 +0800 Subject: [PATCH 0358/2457] drtio: rewrite/fix reset and link bringup/teardown --- artiq/firmware/runtime/rtio_mgt.rs | 46 +++++++++----------- artiq/firmware/satman/main.rs | 10 +++++ artiq/gateware/drtio/core.py | 42 ++++++++++++------ artiq/gateware/drtio/rt_controller_master.py | 42 +++++++----------- artiq/gateware/drtio/rt_packet_master.py | 21 --------- artiq/gateware/drtio/rt_packet_satellite.py | 21 +-------- artiq/gateware/drtio/rt_serializer.py | 1 - 7 files changed, 77 insertions(+), 106 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index f481b04ad..bc03eac5d 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -54,11 +54,10 @@ pub mod drtio { } } - fn reset_phy(linkno: u8) { + fn link_reset(linkno: u8) { let linkno = linkno as usize; unsafe { - (csr::DRTIO[linkno].reset_phy_write)(1); - while (csr::DRTIO[linkno].o_wait_read)() == 1 {} + (csr::DRTIO[linkno].reset_write)(1); } } @@ -70,12 +69,9 @@ pub mod drtio { } } - fn init_link(linkno: u8) { + fn init_buffer_space(linkno: u8) { let linkidx = linkno as usize; unsafe { - (csr::DRTIO[linkidx].reset_write)(1); - while (csr::DRTIO[linkidx].o_wait_read)() == 1 {} - (csr::DRTIO[linkidx].o_get_buffer_space_write)(1); while (csr::DRTIO[linkidx].o_wait_read)() == 1 {} info!("[LINK#{}] buffer space is {}", @@ -83,12 +79,6 @@ pub mod drtio { } } - pub fn init() { - for linkno in 0..csr::DRTIO.len() { - init_link(linkno as u8); - } - } - fn ping_remote(linkno: u8, io: &Io) -> u32 { let mut count = 0; loop { @@ -114,7 +104,7 @@ pub mod drtio { (csr::DRTIO[linkidx].protocol_error_write)(errors); } if errors != 0 { - error!("[LINK#{}] found error(s)", linkno); + error!("[LINK#{}] error(s) found (0x{:02x}):", linkno, errors); if errors & 1 != 0 { error!("[LINK#{}] received packet of an unknown type", linkno); } @@ -148,34 +138,40 @@ pub mod drtio { loop { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; - if !link_up[linkno as usize] { + if link_up[linkno as usize] { + /* link was previously up */ + if link_rx_up(linkno) { + process_local_errors(linkno); + process_aux_errors(linkno); + } else { + info!("[LINK#{}] link is down", linkno); + link_up[linkno as usize] = false; + } + } else { + /* link was previously down */ if link_rx_up(linkno) { info!("[LINK#{}] link RX became up, pinging", linkno); + link_reset(linkno); let ping_count = ping_remote(linkno, &io); if ping_count > 0 { info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); - init_link(linkno); // clear all FIFOs first - reset_phy(linkno); + init_buffer_space(linkno); sync_tsc(linkno); info!("[LINK#{}] link initialization completed", linkno); link_up[linkno as usize] = true; } else { info!("[LINK#{}] ping failed", linkno); } - } else { - if link_rx_up(linkno) { - process_local_errors(linkno); - process_aux_errors(linkno); - } else { - info!("[LINK#{}] link is down", linkno); - link_up[linkno as usize] = false; - } } } } io.sleep(200).unwrap(); } } + + pub fn init() { + // TODO: send reset commands (over aux) to every link that is up + } } #[cfg(not(has_drtio))] diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index a2c155085..77c63f0ef 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -193,6 +193,14 @@ fn drtio_link_is_up() -> bool { } } +fn drtio_reset(reset: bool) { + let reset = if reset { 1 } else { 0 }; + unsafe { + (csr::DRTIO[0].reset_write)(reset); + (csr::DRTIO[0].reset_phy_write)(reset); + } +} + fn startup() { board::clock::init(); info!("ARTIQ satellite manager starting..."); @@ -216,10 +224,12 @@ fn startup() { } info!("link is up, switching to recovered clock"); si5324::select_ext_input(true).expect("failed to switch clocks"); + drtio_reset(false); while drtio_link_is_up() { process_errors(); process_aux_packets(); } + drtio_reset(true); info!("link is down, switching to local crystal clock"); si5324::select_ext_input(false).expect("failed to switch clocks"); } diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 06ced73d6..507b93a7e 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -2,6 +2,7 @@ from types import SimpleNamespace from migen import * from migen.genlib.cdc import ElasticBuffer +from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.interconnect.csr import * from artiq.gateware.rtio.sed.core import * @@ -54,14 +55,36 @@ class GenericRXSynchronizer(Module): class DRTIOSatellite(Module): def __init__(self, chanif, channels, rx_synchronizer=None, fine_ts_width=3, lane_count=8, fifo_depth=128): - if rx_synchronizer is None: - rx_synchronizer = GenericRXSynchronizer() - self.submodules += rx_synchronizer + self.reset = CSRStorage(reset=1) + self.reset_phy = CSRStorage(reset=1) + + self.clock_domains.cd_rio = ClockDomain() + self.clock_domains.cd_rio_phy = ClockDomain() + self.comb += [ + self.cd_rio.clk.eq(ClockSignal("rtio")), + self.cd_rio_phy.clk.eq(ClockSignal("rtio")) + ] + reset = Signal() + reset_phy = Signal() + reset.attr.add("no_retiming") + reset_phy.attr.add("no_retiming") + self.sync += [ + reset.eq(self.reset.storage), + reset_phy.eq(self.reset_phy.storage) + ] + self.specials += [ + AsyncResetSynchronizer(self.cd_rio, reset), + AsyncResetSynchronizer(self.cd_rio_phy, reset_phy) + ] self.submodules.link_layer = link_layer.LinkLayer( chanif.encoder, chanif.decoders) self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready) + if rx_synchronizer is None: + rx_synchronizer = GenericRXSynchronizer() + self.submodules += rx_synchronizer + link_layer_sync = SimpleNamespace( tx_aux_frame=self.link_layer.tx_aux_frame, tx_aux_data=self.link_layer.tx_aux_data, @@ -80,6 +103,7 @@ class DRTIOSatellite(Module): self.submodules.link_stats = link_layer.LinkLayerStats(link_layer_sync, "rtio") self.submodules.rt_packet = ClockDomainsRenamer("rtio")( rt_packet_satellite.RTPacketSatellite(link_layer_sync)) + self.comb += self.rt_packet.reset.eq(self.cd_rio.rst) coarse_ts = Signal(64 - fine_ts_width) self.sync.rtio += \ @@ -106,20 +130,12 @@ class DRTIOSatellite(Module): self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite( self.rt_packet, self.outputs) - self.clock_domains.cd_rio = ClockDomain() - self.clock_domains.cd_rio_phy = ClockDomain() - self.comb += [ - self.cd_rio.clk.eq(ClockSignal("rtio")), - self.cd_rio.rst.eq(self.rt_packet.reset), - self.cd_rio_phy.clk.eq(ClockSignal("rtio")), - self.cd_rio_phy.rst.eq(self.rt_packet.reset_phy), - ] - self.submodules.aux_controller = aux_controller.AuxController( self.link_layer) def get_csrs(self): - return (self.link_layer.get_csrs() + self.link_stats.get_csrs() + + return ([self.reset, self.reset_phy] + + self.link_layer.get_csrs() + self.link_stats.get_csrs() + self.rt_errors.get_csrs() + self.aux_controller.get_csrs()) diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 12683db01..cb2fcdab6 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -13,14 +13,14 @@ from artiq.gateware.rtio import cri class _CSRs(AutoCSR): def __init__(self): + self.reset = CSR() + self.protocol_error = CSR(3) self.tsc_correction = CSRStorage(64) self.set_time = CSR() self.underflow_margin = CSRStorage(16, reset=200) - self.reset = CSR() - self.reset_phy = CSR() self.o_get_buffer_space = CSR() self.o_dbg_buffer_space = CSRStatus(16) @@ -51,6 +51,19 @@ class RTController(Module): self.csrs = _CSRs() self.cri = cri.Interface() + # reset + local_reset = Signal(reset=1) + self.sync += local_reset.eq(self.csrs.reset.re) + local_reset.attr.add("no_retiming") + self.clock_domains.cd_sys_with_rst = ClockDomain() + self.clock_domains.cd_rtio_with_rst = ClockDomain() + self.comb += [ + self.cd_sys_with_rst.clk.eq(ClockSignal()), + self.cd_sys_with_rst.rst.eq(local_reset) + ] + self.comb += self.cd_rtio_with_rst.clk.eq(ClockSignal("rtio")) + self.specials += AsyncResetSynchronizer(self.cd_rtio_with_rst, local_reset) + # protocol errors err_unknown_packet_type = Signal() err_packet_truncated = Signal() @@ -85,31 +98,6 @@ class RTController(Module): If(self.csrs.set_time.re, rt_packet.set_time_stb.eq(1)) ] - # reset - self.sync += [ - If(rt_packet.reset_ack, rt_packet.reset_stb.eq(0)), - If(self.csrs.reset.re, - rt_packet.reset_stb.eq(1), - rt_packet.reset_phy.eq(0) - ), - If(self.csrs.reset_phy.re, - rt_packet.reset_stb.eq(1), - rt_packet.reset_phy.eq(1) - ), - ] - - local_reset = Signal(reset=1) - self.sync += local_reset.eq(self.csrs.reset.re) - local_reset.attr.add("no_retiming") - self.clock_domains.cd_sys_with_rst = ClockDomain() - self.clock_domains.cd_rtio_with_rst = ClockDomain() - self.comb += [ - self.cd_sys_with_rst.clk.eq(ClockSignal()), - self.cd_sys_with_rst.rst.eq(local_reset) - ] - self.comb += self.cd_rtio_with_rst.clk.eq(ClockSignal("rtio")) - self.specials += AsyncResetSynchronizer(self.cd_rtio_with_rst, local_reset) - # common packet fields chan_sel = self.cri.chan_sel[:16] rt_packet_buffer_request = Signal() diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index 94dea3944..2e07dcbc7 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -111,11 +111,6 @@ class RTPacketMaster(Module): # a set_time request pending self.tsc_value = Signal(64) - # reset interface - self.reset_stb = Signal() - self.reset_ack = Signal() - self.reset_phy = Signal() - # rx errors self.err_unknown_packet_type = Signal() self.err_packet_truncated = Signal() @@ -221,13 +216,6 @@ class RTPacketMaster(Module): self.set_time_stb, self.set_time_ack, None, set_time_stb, set_time_ack, None) - reset_stb = Signal() - reset_ack = Signal() - reset_phy = Signal() - self.submodules += _CrossDomainRequest("rtio", - self.reset_stb, self.reset_ack, self.reset_phy, - reset_stb, reset_ack, reset_phy) - echo_stb = Signal() echo_ack = Signal() self.submodules += _CrossDomainRequest("rtio", @@ -287,8 +275,6 @@ class RTPacketMaster(Module): ).Elif(set_time_stb, tsc_value_load.eq(1), NextState("SET_TIME") - ).Elif(reset_stb, - NextState("RESET") ) ) ) @@ -344,13 +330,6 @@ class RTPacketMaster(Module): NextState("IDLE") ) ) - tx_fsm.act("RESET", - tx_dp.send("reset", phy=reset_phy), - If(tx_dp.packet_last, - reset_ack.eq(1), - NextState("IDLE") - ) - ) # RX FSM rx_fsm = ClockDomainsRenamer("rtio_rx")(FSM(reset_state="INPUT")) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 47b9a1d55..02a5a98b1 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -9,15 +9,14 @@ from artiq.gateware.drtio.rt_serializer import * class RTPacketSatellite(Module): def __init__(self, link_layer): + self.reset = Signal() + self.unknown_packet_type = Signal() self.packet_truncated = Signal() self.tsc_load = Signal() self.tsc_load_value = Signal(64) - self.reset = Signal(reset=1) - self.reset_phy = Signal(reset=1) - self.cri = cri.Interface() # # # @@ -97,13 +96,6 @@ class RTPacketSatellite(Module): Cat(rx_dp.packet_as["write"].short_data, write_data_buffer)), ] - reset = Signal() - reset_phy = Signal() - self.sync += [ - self.reset.eq(reset), - self.reset_phy.eq(reset_phy) - ] - rx_fsm = FSM(reset_state="INPUT") self.submodules += rx_fsm @@ -120,7 +112,6 @@ class RTPacketSatellite(Module): # mechanism rx_plm.types["echo_request"]: echo_req.eq(1), rx_plm.types["set_time"]: NextState("SET_TIME"), - rx_plm.types["reset"]: NextState("RESET"), rx_plm.types["write"]: NextState("WRITE"), rx_plm.types["buffer_space_request"]: NextState("BUFFER_SPACE"), rx_plm.types["read_request"]: NextState("READ_REQUEST"), @@ -138,14 +129,6 @@ class RTPacketSatellite(Module): self.tsc_load.eq(1), NextState("INPUT") ) - rx_fsm.act("RESET", - If(rx_dp.packet_as["reset"].phy, - reset_phy.eq(1) - ).Else( - reset.eq(1) - ), - NextState("INPUT") - ) rx_fsm.act("WRITE", If(write_data_buffer_cnt == rx_dp.packet_as["write"].extra_data_cnt, diff --git a/artiq/gateware/drtio/rt_serializer.py b/artiq/gateware/drtio/rt_serializer.py index 8ba5668fc..00a46299f 100644 --- a/artiq/gateware/drtio/rt_serializer.py +++ b/artiq/gateware/drtio/rt_serializer.py @@ -47,7 +47,6 @@ def get_m2s_layouts(alignment): plm.add_type("echo_request") plm.add_type("set_time", ("timestamp", 64)) - plm.add_type("reset", ("phy", 1)) plm.add_type("write", ("timestamp", 64), ("channel", 16), From 7d9c7ada713bbf60cce8665b4892dcd7532f0bd6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 20 Feb 2018 17:42:00 +0800 Subject: [PATCH 0359/2457] drtio: fix test infinite loop --- artiq/gateware/test/drtio/test_full_stack.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 23810321c..905d188d5 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -68,6 +68,10 @@ class DUT(Module): self.submodules.satellite = DRTIOSatellite( self.transceivers.bob, rtio_channels, rx_synchronizer, lane_count=4, fifo_depth=8, fine_ts_width=0) + self.satellite.reset.storage.reset = 0 + self.satellite.reset.storage_full.reset = 0 + self.satellite.reset_phy.storage.reset = 0 + self.satellite.reset_phy.storage_full.reset = 0 class OutputsTestbench: From f15b4bdde71d7c11c628282ef215c195a8195a9e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 20 Feb 2018 18:47:59 +0800 Subject: [PATCH 0360/2457] style --- artiq/gateware/drtio/transceiver/gtp_7series_init.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series_init.py b/artiq/gateware/drtio/transceiver/gtp_7series_init.py index 0414c00a3..18b7a08a4 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series_init.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series_init.py @@ -301,6 +301,7 @@ class GTPRXInit(Module): startup_fsm.act("READY", rxuserrdy.eq(1), self.done.eq(1), - If(self.restart, NextState("GTP_PD") + If(self.restart, + NextState("GTP_PD") ) ) From 738654c783fec3d5940291f00f98ca7c5b40e229 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 20 Feb 2018 18:48:54 +0800 Subject: [PATCH 0361/2457] drtio: support remote RTIO resets --- artiq/firmware/libdrtioaux/lib.rs | 11 +++++++++ artiq/firmware/runtime/rtio_mgt.rs | 36 +++++++++++++++++++++++++----- artiq/firmware/satman/main.rs | 32 +++++++++++++++++++------- 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/artiq/firmware/libdrtioaux/lib.rs b/artiq/firmware/libdrtioaux/lib.rs index 7074d3a09..927825630 100644 --- a/artiq/firmware/libdrtioaux/lib.rs +++ b/artiq/firmware/libdrtioaux/lib.rs @@ -17,6 +17,8 @@ use proto::*; pub enum Packet { EchoRequest, EchoReply, + ResetRequest { phy: bool }, + ResetAck, RtioErrorRequest, RtioNoErrorReply, @@ -52,6 +54,10 @@ impl Packet { Ok(match read_u8(reader)? { 0x00 => Packet::EchoRequest, 0x01 => Packet::EchoReply, + 0x02 => Packet::ResetRequest { + phy: read_bool(reader)? + }, + 0x03 => Packet::ResetAck, 0x20 => Packet::RtioErrorRequest, 0x21 => Packet::RtioNoErrorReply, @@ -149,6 +155,11 @@ impl Packet { match *self { Packet::EchoRequest => write_u8(writer, 0x00)?, Packet::EchoReply => write_u8(writer, 0x01)?, + Packet::ResetRequest { phy } => { + write_u8(writer, 0x02)?; + write_bool(writer, phy)?; + }, + Packet::ResetAck => write_u8(writer, 0x03)?, Packet::RtioErrorRequest => write_u8(writer, 0x20)?, Packet::RtioNoErrorReply => write_u8(writer, 0x21)?, diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index bc03eac5d..f05c99d09 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -131,21 +131,34 @@ pub mod drtio { Err(e) => error!("[LINK#{}] aux packet error ({})", linkno, e) } } + + // FIXME: use csr::DRTIO.len(), maybe get rid of static mut as well. + static mut LINK_UP: [bool; 16] = [false; 16]; + + fn link_up(linkno: u8) -> bool { + unsafe { + LINK_UP[linkno as usize] + } + } + + fn set_link_up(linkno: u8, up: bool) { + unsafe { + LINK_UP[linkno as usize] = up + } + } pub fn link_thread(io: Io) { - let mut link_up = vec![false; csr::DRTIO.len()]; - loop { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; - if link_up[linkno as usize] { + if link_up(linkno) { /* link was previously up */ if link_rx_up(linkno) { process_local_errors(linkno); process_aux_errors(linkno); } else { info!("[LINK#{}] link is down", linkno); - link_up[linkno as usize] = false; + set_link_up(linkno, false); } } else { /* link was previously down */ @@ -158,7 +171,7 @@ pub mod drtio { init_buffer_space(linkno); sync_tsc(linkno); info!("[LINK#{}] link initialization completed", linkno); - link_up[linkno as usize] = true; + set_link_up(linkno, true); } else { info!("[LINK#{}] ping failed", linkno); } @@ -170,7 +183,18 @@ pub mod drtio { } pub fn init() { - // TODO: send reset commands (over aux) to every link that is up + for linkno in 0..csr::DRTIO.len() { + let linkno = linkno as u8; + if link_up(linkno) { + drtioaux::hw::send_link(linkno, + &drtioaux::Packet::ResetRequest { phy: false }).unwrap(); + match drtioaux::hw::recv_timeout_link(linkno, None) { + Ok(drtioaux::Packet::ResetAck) => (), + Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno), + Err(e) => error!("[LINK#{}] reset failed, aux packet error ({})", linkno, e) + } + } + } } } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 77c63f0ef..2e11ad869 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -18,11 +18,33 @@ use board_artiq::serwb; #[cfg(has_hmc830_7043)] use board_artiq::hmc830_7043; + +fn drtio_reset(reset: bool) { + unsafe { + (csr::DRTIO[0].reset_write)(if reset { 1 } else { 0 }); + } +} + +fn drtio_reset_phy(reset: bool) { + unsafe { + (csr::DRTIO[0].reset_phy_write)(if reset { 1 } else { 0 }); + } +} + fn process_aux_packet(p: &drtioaux::Packet) { // In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels, // and u16 otherwise; hence the `as _` conversion. match *p { drtioaux::Packet::EchoRequest => drtioaux::hw::send_link(0, &drtioaux::Packet::EchoReply).unwrap(), + drtioaux::Packet::ResetRequest { phy } => { + if phy { + drtio_reset_phy(true); + drtio_reset_phy(false); + } else { + drtio_reset(true); + drtio_reset(false); + } + }, drtioaux::Packet::RtioErrorRequest => { let errors; @@ -193,14 +215,6 @@ fn drtio_link_is_up() -> bool { } } -fn drtio_reset(reset: bool) { - let reset = if reset { 1 } else { 0 }; - unsafe { - (csr::DRTIO[0].reset_write)(reset); - (csr::DRTIO[0].reset_phy_write)(reset); - } -} - fn startup() { board::clock::init(); info!("ARTIQ satellite manager starting..."); @@ -225,10 +239,12 @@ fn startup() { info!("link is up, switching to recovered clock"); si5324::select_ext_input(true).expect("failed to switch clocks"); drtio_reset(false); + drtio_reset_phy(false); while drtio_link_is_up() { process_errors(); process_aux_packets(); } + drtio_reset_phy(true); drtio_reset(true); info!("link is down, switching to local crystal clock"); si5324::select_ext_input(false).expect("failed to switch clocks"); From f060d6e1b337b75f65590337063f1a7d00109a23 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 20 Feb 2018 18:50:35 +0800 Subject: [PATCH 0362/2457] drtio: increase A7 clock aligner check period --- artiq/gateware/drtio/transceiver/gtp_7series.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py index 397235e28..62d2728ef 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -689,7 +689,7 @@ class GTPSingle(Module): self.comb += decoders[i].input.eq(rxdata[10*i:10*(i+1)]) # clock alignment - clock_aligner = BruteforceClockAligner(0b0101111100, rtio_clk_freq, check_period=10e-3) + clock_aligner = BruteforceClockAligner(0b0101111100, rtio_clk_freq, check_period=12e-3) self.submodules += clock_aligner self.comb += [ clock_aligner.rxdata.eq(rxdata), From eed64a6d6ba3d800238fb4cffc94825a2d2a3e2f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 21 Feb 2018 10:35:31 +0800 Subject: [PATCH 0363/2457] conda: fix openocd dependency --- conda/artiq/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index 065c4150b..727c07130 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -29,7 +29,7 @@ requirements: - llvmlite-artiq 0.20.0 - binutils-or1k-linux >=2.27 - pythonparser >=1.1 - - openocd 0.10.0 4 + - openocd 0.10.0 6 - lit - outputcheck - scipy From 932fa884cca966b6034ce750ef50dbdca8f16de1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 21 Feb 2018 11:15:01 +0800 Subject: [PATCH 0364/2457] conda: add recipes for Kasli DRTIO --- conda/artiq-kasli-master/build.sh | 9 +++++++++ conda/artiq-kasli-master/meta.yaml | 23 +++++++++++++++++++++++ conda/artiq-kasli-satellite/build.sh | 9 +++++++++ conda/artiq-kasli-satellite/meta.yaml | 23 +++++++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 conda/artiq-kasli-master/build.sh create mode 100644 conda/artiq-kasli-master/meta.yaml create mode 100644 conda/artiq-kasli-satellite/build.sh create mode 100644 conda/artiq-kasli-satellite/meta.yaml diff --git a/conda/artiq-kasli-master/build.sh b/conda/artiq-kasli-master/build.sh new file mode 100644 index 000000000..2189002d9 --- /dev/null +++ b/conda/artiq-kasli-master/build.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +SOC_PREFIX=$SP_DIR/artiq/binaries/kasli-master +mkdir -p $SOC_PREFIX + +V=1 $PYTHON -m artiq.gateware.targets.kasli -V master +cp artiq_kasli/master/gateware/top.bit $SOC_PREFIX +cp artiq_kasli/master/software/bootloader/bootloader.bin $SOC_PREFIX +cp artiq_kasli/master/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-kasli-master/meta.yaml b/conda/artiq-kasli-master/meta.yaml new file mode 100644 index 000000000..a25621b55 --- /dev/null +++ b/conda/artiq-kasli-master/meta.yaml @@ -0,0 +1,23 @@ +package: + name: artiq-kasli-master + version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} + +source: + git_url: ../.. + +build: + noarch: python + ignore_prefix_files: True + number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} + string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} + +requirements: + build: + - artiq-dev {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} + run: + - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} + +about: + home: https://m-labs.hk/artiq + license: LGPL + summary: 'Bitstream, BIOS and runtime for the Kasli DRTIO master' diff --git a/conda/artiq-kasli-satellite/build.sh b/conda/artiq-kasli-satellite/build.sh new file mode 100644 index 000000000..bae8ecedf --- /dev/null +++ b/conda/artiq-kasli-satellite/build.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +SOC_PREFIX=$SP_DIR/artiq/binaries/kasli-satellite +mkdir -p $SOC_PREFIX + +V=1 $PYTHON -m artiq.gateware.targets.kasli -V satellite +cp artiq_kasli/satellite/gateware/top.bit $SOC_PREFIX +cp artiq_kasli/satellite/software/bootloader/bootloader.bin $SOC_PREFIX +cp artiq_kasli/satellite/software/satman/satman.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-kasli-satellite/meta.yaml b/conda/artiq-kasli-satellite/meta.yaml new file mode 100644 index 000000000..2a23d1bc4 --- /dev/null +++ b/conda/artiq-kasli-satellite/meta.yaml @@ -0,0 +1,23 @@ +package: + name: artiq-kasli-satellite + version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} + +source: + git_url: ../.. + +build: + noarch: python + ignore_prefix_files: True + number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} + string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} + +requirements: + build: + - artiq-dev {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} + run: + - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} + +about: + home: https://m-labs.hk/artiq + license: LGPL + summary: 'Bitstream, BIOS and satellite manager for the Kasli DRTIO satellite' From 6c4681e7d2cce6b184a705a1d98b7b5382501505 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 21 Feb 2018 11:57:57 +0800 Subject: [PATCH 0365/2457] manual: fix minor errors --- doc/manual/core_device.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index 72def13d5..41e3087fd 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -35,7 +35,7 @@ Common problems +++++++++++++++ * The SW13 switches on the board need to be set to 00001. -* When connected, CLOCK adapter breaks the JTAG chain due to TDI not being connect to TDO on the FMC mezzanine. +* When connected, the CLOCK adapter breaks the JTAG chain due to TDI not being connected to TDO on the FMC mezzanine. * On some boards, the JTAG USB connector is not correctly soldered. VADJ @@ -162,12 +162,12 @@ See :mod:`artiq.coredevice.i2c` for more details. Kasli ----- -`Kasli `_ is a versatile coredevice designed for ARTIQ as part of the `Sinara `_ family of boards. +`Kasli `_ is a versatile core device designed for ARTIQ as part of the `Sinara `_ family of boards. Opticlock +++++++++ -In the opticlock variant, Kasli is the coredevice controlling three `DIO_BNC `_ boards, one `Urukul-AD9912 `_, one `Urukul-AD9910 `_, and one Sampler ``_. +In the opticlock variant, Kasli is the core device controlling three `DIO_BNC `_ boards, one `Urukul-AD9912 `_, one `Urukul-AD9910 `_, and one Sampler ``_. Kasli is connected to the network using a 1000Base-X SFP module. `No-name `_ BiDi (1000Base-BX) modules have been used successfully. From 7986391422d69bd0dff543079b4b7f6ad5bb2211 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 21 Feb 2018 12:04:14 +0800 Subject: [PATCH 0366/2457] manual: update Kasli section --- doc/manual/core_device.rst | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index 41e3087fd..ef269277f 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -170,10 +170,29 @@ Opticlock In the opticlock variant, Kasli is the core device controlling three `DIO_BNC `_ boards, one `Urukul-AD9912 `_, one `Urukul-AD9910 `_, and one Sampler ``_. Kasli is connected to the network using a 1000Base-X SFP module. `No-name -`_ BiDi (1000Base-BX) modules have been used successfully. +`_ BiDi (1000Base-BX) modules have been used successfully. The SFP module for the network +should be installed into the SFP0 cage. Kasli is supplied with 100 MHz reference at its SMA input. Both Urukul boards are supplied with a 100 MHz reference clock on their external SMA inputs. +The RTIO clock frequency is 125 MHz, which is synthesized from the 100 MHz reference using the Si5324. + The first four TTL channels are used as inputs. The rest are outputs. + +DRTIO master +++++++++++++ + +Kasli can be used as a DRTIO master that provides local RTIO channels and can additionally control one DRTIO satellite. + +The RTIO clock frequency is 150 MHz, which is synthesized from the Si5324 crystal. The DRTIO line rate is 3 Gbps. + +The SFP module for the Ethernet network should be installed into the SFP0 cage, and the DRTIO connection is on SFP2. + +DRTIO satellite ++++++++++++++++ + +Kasli can be used as a DRTIO satellite with a 150 MHz RTIO clock and a 3 Gbps DRTIO line rate. + +The DRTIO connection is on SFP0. From 86ceee570ff5850ac4df7761bcdc1356550474ed Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 21 Feb 2018 11:37:12 +0000 Subject: [PATCH 0367/2457] compiler: reject calls with unexpected keyword arguments. Fixes #924. --- artiq/compiler/transforms/inferencer.py | 11 +++++++++++ artiq/test/lit/inferencer/error_call.py | 3 +++ 2 files changed, 14 insertions(+) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 5c54f235c..7880a6390 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -1004,6 +1004,17 @@ class Inferencer(algorithm.Visitor): elif keyword.arg in typ_optargs: self._unify(keyword.value.type, typ_optargs[keyword.arg], keyword.value.loc, None) + else: + note = diagnostic.Diagnostic("note", + "extraneous argument", {}, + keyword.loc) + diag = diagnostic.Diagnostic("error", + "this function of type {type} does not accept argument '{name}'", + {"type": types.TypePrinter().name(node.func.type), + "name": keyword.arg}, + node.func.loc, [], [note]) + self.engine.process(diag) + return passed_args[keyword.arg] = keyword.arg_loc for formalname in typ_args: diff --git a/artiq/test/lit/inferencer/error_call.py b/artiq/test/lit/inferencer/error_call.py index 1c3df3a6a..1497c7821 100644 --- a/artiq/test/lit/inferencer/error_call.py +++ b/artiq/test/lit/inferencer/error_call.py @@ -18,3 +18,6 @@ f(1, x=1) # CHECK-L: ${LINE:+1}: error: mandatory argument 'x' is not passed f() + +# CHECK: ${LINE:+1}: error: this function of type .* does not accept argument 'q' +f(1, q=1) From afc16a67b6d7d729fe315d1fb4c3216549f2004c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 21 Feb 2018 14:15:35 +0100 Subject: [PATCH 0368/2457] firmware/liboard/sdram.rs: iterate read multiple times in read_delays to avoid false positives --- artiq/firmware/libboard/sdram.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index f2b320c93..f987ab79c 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -177,17 +177,19 @@ mod ddr { let delay = Cell::new(0); let incr_delay_until = |expected| { while delay.get() < DDRPHY_MAX_DELAY { - sdram_phy::command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS| - DFII_COMMAND_RDDATA); - spin_cycles(15); - let mut working = true; - for p in 0..DFII_NPHASES { - for &offset in [n, n + DQS_SIGNAL_COUNT].iter() { - let addr = DFII_PIX_RDDATA_ADDR[p].offset(offset as isize); - let data = prs[DFII_PIX_DATA_SIZE * p + offset]; - if ptr::read_volatile(addr) as u8 != data { - working = false; + for _ in 0..64 { + sdram_phy::command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS| + DFII_COMMAND_RDDATA); + spin_cycles(15); + + for p in 0..DFII_NPHASES { + for &offset in [n, n + DQS_SIGNAL_COUNT].iter() { + let addr = DFII_PIX_RDDATA_ADDR[p].offset(offset as isize); + let data = prs[DFII_PIX_DATA_SIZE * p + offset]; + if ptr::read_volatile(addr) as u8 != data { + working = false; + } } } } From 476e4fdd56891546630c7d8f0e7635d076587c84 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Feb 2018 15:33:37 +0000 Subject: [PATCH 0369/2457] ttl_serdes_7series: disable IBUF and INTERM when output --- artiq/gateware/rtio/phy/ttl_serdes_7series.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_7series.py b/artiq/gateware/rtio/phy/ttl_serdes_7series.py index 8ef6be219..d04095e93 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_7series.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_7series.py @@ -75,7 +75,12 @@ class _IOSERDESE2_8X(Module): i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, io_IO=pad) else: - self.specials += Instance("IOBUFDS", + self.specials += Instance("IOBUFDS_INTERMDISABLE", + p_DIFF_TERM="TRUE", + p_IBUF_LOW_PWR="TRUE", + p_USE_IBUFDISABLE="TRUE", + i_IBUFDISABLE=self.oe, + i_INTERMDISABLE=self.oe, i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, io_IO=pad, io_IOB=pad_n) self.comb += [ From 7a1d71502a070d642ba185bc2347395b69f2dfb0 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Feb 2018 15:47:06 +0000 Subject: [PATCH 0370/2457] ttl_serdes_7series: drive IBUF and INTERM disables from serdes --- artiq/gateware/rtio/phy/ttl_serdes_7series.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_7series.py b/artiq/gateware/rtio/phy/ttl_serdes_7series.py index d04095e93..f91e7584c 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_7series.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_7series.py @@ -79,8 +79,8 @@ class _IOSERDESE2_8X(Module): p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE", p_USE_IBUFDISABLE="TRUE", - i_IBUFDISABLE=self.oe, - i_INTERMDISABLE=self.oe, + i_IBUFDISABLE=~oserdes.t_out, + i_INTERMDISABLE=~oserdes.t_out, i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, io_IO=pad, io_IOB=pad_n) self.comb += [ From 91a4a7b0eedd051b48fb41d7b1ec39ac989a5cad Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Feb 2018 16:33:59 +0000 Subject: [PATCH 0371/2457] kasli: free run si5324 on opticlock for now --- artiq/gateware/targets/kasli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 77c1460e1..e45c57ff1 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -240,7 +240,7 @@ class Opticlock(_StandaloneBase): _StandaloneBase.__init__(self, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None - self.config["SI5324_EXT_REF"] = None + # self.config["SI5324_EXT_REF"] = None self.config["RTIO_FREQUENCY"] = "125.0" platform = self.platform From 37a0d6580bb545c88ce10713152f699adb6ea556 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 21 Feb 2018 13:34:45 +0000 Subject: [PATCH 0372/2457] spi2: add RTIO gateware and coredevice driver https://github.com/m-labs/misoc/commit/1006218997c40d570686196cb8a25d01add8fab7 --- artiq/coredevice/spi2.py | 211 ++++++++++++++++++++++++++ artiq/gateware/rtio/phy/spi2.py | 116 ++++++++++++++ conda/artiq-dev/meta.yaml | 2 +- doc/manual/core_drivers_reference.rst | 6 + 4 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 artiq/coredevice/spi2.py create mode 100644 artiq/gateware/rtio/phy/spi2.py diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py new file mode 100644 index 000000000..8e5604703 --- /dev/null +++ b/artiq/coredevice/spi2.py @@ -0,0 +1,211 @@ +""" +Driver for generic SPI on RTIO. + +This ARTIQ coredevice driver corresponds to the "new" MiSoC SPI core (v2). + +Output event replacement is not supported and issuing commands at the same +time is an error. +""" + +from numpy import int64 +from artiq.language.core import syscall, kernel, portable, now_mu, delay_mu +from artiq.language.types import TInt32, TNone +from artiq.coredevice.rtio import rtio_output, rtio_input_data + + +__all__ = [ + "SPI_DATA_ADDR", "SPI_CONFIG_ADDR", + "SPI_OFFLINE", "SPI_END", "SPI_INPUT", + "SPI_CS_POLARITY", "SPI_CLK_POLARITY", "SPI_CLK_PHASE", + "SPI_LSB_FIRST", "SPI_HALF_DUPLEX", + "SPIMaster", "NRTSPIMaster" +] + +SPI_DATA_ADDR = 0 +SPI_CONFIG_ADDR = 1 + +SPI_OFFLINE = 0x01 +SPI_END = 0x02 +SPI_INPUT = 0x04 +SPI_CS_POLARITY = 0x08 +SPI_CLK_POLARITY = 0x10 +SPI_CLK_PHASE = 0x20 +SPI_LSB_FIRST = 0x40 +SPI_HALF_DUPLEX = 0x80 + + +class SPIMaster: + """Core device Serial Peripheral Interface (SPI) bus master. + + Owns one SPI bus. + + This ARTIQ coredevice driver corresponds to the "new" MiSoC SPI core (v2). + + **Transfer Sequence**: + + * If necessary, set the ``config`` register (:meth:`set_config` and + :meth:`set_config_mu`) to activate and configure the core and to set + various transfer parameters like transfer length, clock divider, + and chip selects. + * :meth:`write` to the ``data`` register. Writing starts the transfer. + * If the transfer included submitting the SPI input data as an RTIO input + event (``SPI_INPUT`` set), then :meth:`read` the ``data``. + * If ``SPI_END`` was not set, repeat the transfer sequence. + + A **transaction** consists of one or more **transfers**. The chip select + pattern is asserted for the entire length of the transaction. All but the + last transfer are submitted with ``SPI_END`` cleared in the configuration + register. + + :param channel: RTIO channel number of the SPI bus to control. + """ + kernel_invariants = {"core", "ref_period_mu", "channel"} + + def __init__(self, dmgr, channel, core_device="core"): + self.core = dmgr.get(core_device) + self.ref_period_mu = self.core.seconds_to_mu( + self.core.coarse_ref_period) + assert self.ref_period_mu == self.core.ref_multiplier + self.channel = channel + self.xfer_duration_mu = 2*self.ref_period_mu + + @portable + def frequency_to_div(self, f): + """Convert a SPI clock frequency to the closest SPI clock divider.""" + return int64(round( + 1/(f*self.core.mu_to_seconds(self.ref_period_mu)))) + + @kernel + def set_config(self, flags, length, freq, c): + """Set the configuration register. + + * If ``SPI_CS_POLARITY`` is cleared (``cs`` active low, the default), + "``cs`` all deasserted" means "all ``cs_n`` bits high". + * ``cs_n`` is not mandatory in the pads supplied to the gateware core. + Framing and chip selection can also be handled independently + through other means, e.g. ``TTLOut``. + * If there is a ``miso`` wire in the pads supplied in the gateware, + input and output may be two signals ("4-wire SPI"), + otherwise ``mosi`` must be used for both output and input + ("3-wire SPI") and ``SPI_HALF_DUPLEX`` must to be set + when reading data or when the slave drives the + ``mosi`` signal at any point. + * The first bit output on ``mosi`` is always the MSB/LSB (depending + on ``SPI_LSB_FIRST``) of the ``data`` written, independent of + the ``length`` of the transfer. The last bit input from ``miso`` + always ends up in the LSB/MSB (respectively) of the ``data`` read, + independent of the ``length`` of the transfer. + * ``cs`` is asserted at the beginning and deasserted at the end + of the transaction. + * ``cs`` handling is agnostic to whether it is one-hot or decoded + somewhere downstream. If it is decoded, "``cs`` all deasserted" + should be handled accordingly (no slave selected). + If it is one-hot, asserting multiple slaves should only be attempted + if ``miso`` is either not connected between slaves, or open + collector, or correctly multiplexed externally. + * Changes to the configuration register take effect on the start of the + next transfer with the exception of ``SPI_OFFLINE`` which takes + effect immediately. + * The SPI core can only be written to when it is idle or waiting + for the next transfer data. Writing (:meth:`set_config`, + :meth:`set_config_mu` or :meth:`write`) + when the core is busy will result in an RTIO busy error being logged. + + This method advances the timeline by one coarse RTIO clock cycle. + + **Configuration flags**: + + * :const:`SPI_OFFLINE`: all pins high-z (reset=1) + * :const:`SPI_END`: transfer in progress (reset=1) + * :const:`SPI_INPUT`: submit SPI read data as RTIO input event when + transfer is complete (reset=0) + * :const:`SPI_CS_POLARITY`: active level of ``cs_n`` (reset=0) + * :const:`SPI_CLK_POLARITY`: idle level of ``clk`` (reset=0) + * :const:`SPI_CLK_PHASE`: first edge after ``cs`` assertion to sample + data on (reset=0). In Motorola/Freescale SPI language + (:const:`SPI_CLK_POLARITY`, :const:`SPI_CLK_PHASE`) == (CPOL, CPHA): + + - (0, 0): idle low, output on falling, input on rising + - (0, 1): idle low, output on rising, input on falling + - (1, 0): idle high, output on rising, input on falling + - (1, 1): idle high, output on falling, input on rising + * :const:`SPI_LSB_FIRST`: LSB is the first bit on the wire (reset=0) + * :const:`SPI_HALF_DUPLEX`: 3-wire SPI, in/out on ``mosi`` (reset=0) + + :param flags: A bit map of `SPI_*` flags. + :param length: Number of bits to write during the next transfer. + (reset=1) + :param freq: Desired SPI clock frequency. (reset=f_rtio/2) + :param cs: Bit pattern of chip selects to assert. + Or number of the chip select to assert if ``cs`` is decoded + downstream. (reset=0) + """ + self.set_config_mu( + flags, length, self.frequency_to_div(write_freq), cs) + + @kernel + def set_config_mu(self, flags, length, div, cs): + """Set the ``config`` register (in SPI bus machine units). + + .. seealso:: :meth:`set_config` + + :param flags: A bit map of `SPI_*` flags. + :param length: Number of bits to write during the next transfer. + (reset=1) + :param div: Counter load value to divide the RTIO + clock by to generate the SPI clock. (minimum=2, reset=2) + ``f_rtio_clk/f_spi == div``. If ``div`` is odd, + the setup phase of the SPI clock is one coarse RTIO clock cycle + longer than the hold phase. + :param cs: Bit pattern of chip selects to assert. + Or number of the chip select to assert if ``cs`` is decoded + downstream. (reset=0) + """ + if length > 32 or length < 1: + raise ValueError("Invalid SPI transfer length") + if div > 257 or div < 2: + raise ValueError("Invalid SPI clock divider") + self.xfer_duration_mu = (length + 1)*div*self.ref_period_mu + rtio_output(now_mu(), self.channel, SPI_CONFIG_ADDR, flags | + ((length - 1) << 8) | ((div - 2) << 16) | (cs << 24)) + delay_mu(self.ref_period_mu) + + @kernel + def write(self, data): + """Write SPI data to shift register register and start transfer. + + * The ``data`` register and the shift register are 32 bits wide. + * Data writes take one ``ref_period`` cycle. + * A transaction consisting of a single transfer (``SPI_END``) takes + :attr:`xfer_duration_mu` ``=(n + 1)*div`` cycles RTIO time where + ``n`` is the number of bits and ``div`` is the SPI clock divider. + * Transfers in a multi-transfer transaction take up to one SPI clock + cycle less time depending on multiple parameters. Advanced users may + rewind the timeline appropriately to achieve faster multi-transfer + transactions. + * The SPI core will be busy for the duration of the SPI transfer. + * For bit alignment and bit ordering see :meth:`set_config`. + * The SPI core can only be written to when it is idle or waiting + for the next transfer data. Writing (:meth:`set_config`, + :meth:`set_config_mu` or :meth:`write`) + when the core is busy will result in an RTIO busy error being logged. + + This method advances the timeline by the duration of one + single-transfer SPI transaction (:attr:`xfer_duration_mu`). + + :param data: SPI output data to be written. + """ + rtio_output(now_mu(), self.channel, SPI_DATA_ADDR, data) + delay_mu(self.xfer_duration_mu) + + @kernel + def read(self): + """Read SPI data submitted by the SPI core. + + For bit alignment and bit ordering see :meth:`set_config`. + + This method does not alter the timeline. + + :return: SPI input data. + """ + return rtio_input_data(self.channel) diff --git a/artiq/gateware/rtio/phy/spi2.py b/artiq/gateware/rtio/phy/spi2.py new file mode 100644 index 000000000..cc4c06da6 --- /dev/null +++ b/artiq/gateware/rtio/phy/spi2.py @@ -0,0 +1,116 @@ +from migen import * + +from misoc.cores.spi2 import SPIMachine, SPIInterfaceXC7Diff, SPIInterface +from artiq.gateware.rtio import rtlink + + +class SPIMaster(Module): + """ + RTIO SPI Master version 2. + + Register address and bit map: + + data (address 0): + 32 write/read data + + config (address 1): + 1 offline: all pins high-z (reset=1) + 1 end: end transaction with next transfer (reset=1) + 1 input: submit read data on RTIO input when readable (reset=0) + 1 cs_polarity: active level of chip select (reset=0) + 1 clk_polarity: idle level of clk (reset=0) + 1 clk_phase: first edge after cs assertion to sample data on (reset=0) + (clk_polarity, clk_phase) == (CPOL, CPHA) in Freescale language. + (0, 0): idle low, output on falling, input on rising + (0, 1): idle low, output on rising, input on falling + (1, 0): idle high, output on rising, input on falling + (1, 1): idle high, output on falling, input on rising + There is never a clk edge during a cs edge. + 1 lsb_first: LSB is the first bit on the wire (reset=0) + 1 half_duplex: 3-wire SPI, in/out on mosi (reset=0) + 5 length: 1-32 bits = length + 1 (reset=0) + 3 padding + 8 div: counter load value to divide this module's clock + to generate the SPI write clk (reset=0) + f_clk/f_spi == div + 2 + 8 cs: active high bit pattern of chip selects (reset=0) + """ + def __init__(self, pads, pads_n=None): + to_rio_phy = ClockDomainsRenamer("rio_phy") + if pads_n is None: + interface = SPIInterface(pads) + else: + interface = SPIInterfaceXC7Diff(pads, pads_n) + interface = to_rio_phy(interface) + spi = to_rio_phy(SPIMachine(data_width=32, div_width=8)) + self.submodules += interface, spi + + self.rtlink = rtlink.Interface( + rtlink.OInterface(len(spi.reg.pdo), address_width=1, + enable_replace=False), + rtlink.IInterface(len(spi.reg.pdi), timestamped=False) + ) + + ### + + config = Record([ + ("offline", 1), + ("end", 1), + ("input", 1), + ("cs_polarity", 1), + ("clk_polarity", 1), + ("clk_phase", 1), + ("lsb_first", 1), + ("half_duplex", 1), + ("length", 5), + ("padding", 3), + ("div", 8), + ("cs", 8), + ]) + assert len(config) == len(spi.reg.pdo) == len(spi.reg.pdi) == 32 + + config.offline.reset = 1 + config.end.reset = 1 + read = Signal() + + self.sync.rio += [ + If(self.rtlink.i.stb, + read.eq(0) + ), + If(self.rtlink.o.stb & spi.writable, + If(self.rtlink.o.address, + config.raw_bits().eq(self.rtlink.o.data) + ).Else( + read.eq(config.input) + ) + ), + ] + + self.comb += [ + spi.length.eq(config.length), + spi.end.eq(config.end), + spi.cg.div.eq(config.div), + spi.clk_phase.eq(config.clk_phase), + spi.reg.lsb_first.eq(config.lsb_first), + + interface.half_duplex.eq(config.half_duplex), + interface.cs.eq(config.cs), + interface.cs_polarity.eq(Replicate( + config.cs_polarity, len(interface.cs_polarity))), + interface.clk_polarity.eq(config.clk_polarity), + interface.offline.eq(config.offline), + interface.cs_next.eq(spi.cs_next), + interface.clk_next.eq(spi.clk_next), + interface.ce.eq(spi.ce), + interface.sample.eq(spi.reg.sample), + spi.reg.sdi.eq(interface.sdi), + interface.sdo.eq(spi.reg.sdo), + + spi.load.eq(self.rtlink.o.stb & spi.writable & + ~self.rtlink.o.address), + spi.reg.pdo.eq(self.rtlink.o.data), + self.rtlink.o.busy.eq(~spi.writable), + self.rtlink.i.stb.eq(spi.readable & read), + self.rtlink.i.data.eq(spi.reg.pdi) + ] + self.probes = [] diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index dc7687b8a..47e4deae4 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_4+git9c3a301 - - misoc 0.9 py35_10+git3072d794 + - misoc 0.9 py35_11+git10062189 - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index d099c8ff3..003b8322d 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -33,6 +33,12 @@ These drivers are for the core device and the peripherals closely integrated int .. automodule:: artiq.coredevice.spi :members: +:mod:`artiq.coredevice.spi2` module +----------------------------------- + +.. automodule:: artiq.coredevice.spi2 + :members: + :mod:`artiq.coredevice.ad5360` module ------------------------------------- From a63fd306af3e4cce0419aee812f9d5a37d5b4eb5 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 21 Feb 2018 15:00:28 +0000 Subject: [PATCH 0373/2457] urukul: use spi2 * switch kc705 and kasli targets to spi2 gateware on urukul * rewrite urukul, ad9912, ad9910 * update example experiments, device_dbs --- artiq/coredevice/ad9910.py | 104 +++++---- artiq/coredevice/ad9912.py | 77 ++++--- artiq/coredevice/spi.py | 2 + artiq/coredevice/urukul.py | 206 +++++++++++------- artiq/examples/kasli_opticlock/device_db.py | 7 +- .../kasli_opticlock/repository/urukul.py | 5 +- artiq/examples/kc705_nist_clock/device_db.py | 2 +- .../kc705_nist_clock/repository/urukul.py | 34 ++- artiq/gateware/targets/kasli.py | 6 +- artiq/gateware/targets/kc705.py | 6 +- 10 files changed, 256 insertions(+), 193 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 3f44a7625..ff2c35070 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -1,9 +1,12 @@ -from artiq.language.core import kernel, delay_mu, delay, portable -from artiq.language.units import us, ns, ms -from artiq.coredevice.urukul import urukul_sta_pll_lock - from numpy import int32, int64 +from artiq.language.core import kernel, delay, portable +from artiq.language.units import us, ns, ms + +from artiq.coredevice import spi2 as spi +from artiq.coredevice import urukul +urukul_sta_pll_lock = urukul.urukul_sta_pll_lock + _AD9910_REG_CFR1 = 0x00 _AD9910_REG_CFR2 = 0x01 @@ -47,7 +50,7 @@ class AD9910: :param pll_vco: DDS PLL VCO range selection. """ kernel_invariants = {"chip_select", "cpld", "core", "bus", "sw", - "ftw_per_hz", "sysclk", "pll_n", "pll_cp", "pll_vco"} + "ftw_per_hz", "pll_n", "pll_cp", "pll_vco"} def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, pll_n=40, pll_cp=7, pll_vco=5): @@ -60,14 +63,14 @@ class AD9910: self.sw = dmgr.get(sw_device) assert 12 <= pll_n <= 127 self.pll_n = pll_n - assert self.cpld.refclk < 60e6 - self.sysclk = self.cpld.refclk*pll_n/4 # Urukul clock fanout divider - assert self.sysclk <= 1e9 - self.ftw_per_hz = 1./self.sysclk*(int64(1) << 32) + assert self.cpld.refclk/4 <= 60e6 + sysclk = self.cpld.refclk*pll_n/4 # Urukul clock fanout divider + assert sysclk <= 1e9 + self.ftw_per_hz = 1./sysclk*(int64(1) << 32) assert 0 <= pll_vco <= 5 vco_min, vco_max = [(370, 510), (420, 590), (500, 700), (600, 880), (700, 950), (820, 1150)][pll_vco] - assert vco_min <= self.sysclk/1e6 <= vco_max + assert vco_min <= sysclk/1e6 <= vco_max self.pll_vco = pll_vco assert 0 <= pll_cp <= 7 self.pll_cp = pll_cp @@ -79,12 +82,27 @@ class AD9910: :param addr: Register address :param data: Data to be written """ - self.bus.set_xfer(self.chip_select, 8, 0) + self.bus.set_config_mu(urukul.SPI_CONFIG, 8, + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write(addr << 24) - delay_mu(-self.bus.xfer_period_mu + 8) - self.bus.set_xfer(self.chip_select, 32, 0) + self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32, + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write(data) - delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu) + + @kernel + def read32(self, addr): + """Read from 32 bit register. + + :param addr: Register address + """ + self.bus.set_config_mu(urukul.SPI_CONFIG, 8, + urukul.SPIT_DDS_WR, self.chip_select) + self.bus.write((addr | 0x80) << 24) + self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END + | spi.SPI_INPUT, 32, + urukul.SPIT_DDS_RD, self.chip_select) + self.bus.write(0) + return self.bus.read() @kernel def write64(self, addr, data_high, data_low): @@ -94,68 +112,58 @@ class AD9910: :param data_high: High (MSB) 32 bits of the data :param data_low: Low (LSB) 32 data bits """ - self.bus.set_xfer(self.chip_select, 8, 0) + self.bus.set_config_mu(urukul.SPI_CONFIG, 8, + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write(addr << 24) - t = self.bus.xfer_period_mu - delay_mu(-t + 8) - self.bus.set_xfer(self.chip_select, 32, 0) + self.bus.set_config_mu(urukul.SPI_CONFIG, 32, + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write(data_high) + self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32, + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write(data_low) - delay_mu(t - 2*self.bus.write_period_mu) - - @kernel - def read32(self, addr): - """Read from 32 bit register. - - :param addr: Register address - """ - self.bus.set_xfer(self.chip_select, 8, 0) - self.bus.write((addr | 0x80) << 24) - delay_mu(-self.bus.xfer_period_mu + 8) - self.bus.set_xfer(self.chip_select, 0, 32) - self.bus.write(0) - delay_mu(2*self.bus.xfer_period_mu) - data = self.bus.read_sync() - return data @kernel def init(self): - """Initialize and configure the DDS.""" + """Initialize and configure the DDS. + + Sets up SPI mode, confirms chip presence, powers down unused blocks, + configures the PLL, waits for PLL lock. Uses the + IO_UPDATE signal multiple times. + """ # Set SPI mode self.write32(_AD9910_REG_CFR1, 0x00000002) - delay(100*us) - self.cpld.io_update.pulse(100*ns) + self.cpld.io_update.pulse(1*us) # Use the AUX DAC setting to identify and confirm presence aux_dac = self.read32(_AD9910_REG_AUX_DAC) if aux_dac & 0xff != 0x7f: raise ValueError("Urukul AD9910 AUX_DAC mismatch") - delay(100*us) + delay(20*us) # slack # Configure PLL settings and bring up PLL self.write32(_AD9910_REG_CFR2, 0x01400020) + self.cpld.io_update.pulse(1*us) cfr3 = (0x0807c100 | (self.pll_vco << 24) | (self.pll_cp << 19) | (self.pll_n << 1)) self.write32(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset - delay(100*us) - self.cpld.io_update.pulse(100*ns) + self.cpld.io_update.pulse(100*us) self.write32(_AD9910_REG_CFR3, cfr3) - delay(100*us) - self.cpld.io_update.pulse(100*ns) + self.cpld.io_update.pulse(100*us) # Wait for PLL lock, up to 100 ms for i in range(100): - lock = urukul_sta_pll_lock(self.cpld.sta_read()) + sta = self.cpld.sta_read() + lock = urukul_sta_pll_lock(sta) delay(1*ms) - if lock & (1 << self.chip_select - 4) != 0: + if lock & (1 << self.chip_select - 4): return - raise ValueError("PLL failed to lock") + raise ValueError("PLL lock timeout") @kernel - def set_mu(self, ftw=int32(0), pow=int32(0), asf=int32(0x3fff)): + def set_mu(self, ftw, pow=0, asf=0x3fff): """Set profile 0 data in machine units. After the SPI transfer, the shared IO update pin is pulsed to activate the data. - :param ftw: Frequency tuning word: 32 bit unsigned. + :param ftw: Frequency tuning word: 32 bit. :param pow: Phase tuning word: 16 bit unsigned. :param asf: Amplitude scale factor: 14 bit unsigned. """ @@ -195,7 +203,7 @@ class AD9910: self.amplitude_to_asf(amplitude)) @kernel - def set_att_mu(self, att=int32(0)): + def set_att_mu(self, att): """Set digital step attenuator in machine units. .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att_mu` diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index f09e91695..67549a74d 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -1,8 +1,11 @@ -from artiq.language.core import kernel, delay_mu, delay, portable +from numpy import int32, int64 + +from artiq.language.core import kernel, delay, portable from artiq.language.units import us, ns from artiq.coredevice.ad9912_reg import * -from numpy import int32, int64 +from artiq.coredevice import spi2 as spi +from artiq.coredevice import urukul class AD9912: @@ -39,8 +42,9 @@ class AD9912: self.ftw_per_hz = 1/self.sysclk*(int64(1) << 48) @kernel - def write(self, addr=int32(0), data=int32(0), length=int32(1)): - """Variable length write to a register. Up to 32 bits. + def write(self, addr, data, length): + """Variable length write to a register. + Up to 4 bytes. :param addr: Register address :param data: Data to be written: int32 @@ -48,51 +52,60 @@ class AD9912: """ assert length > 0 assert length <= 4 - self.bus.set_xfer(self.chip_select, 16, 0) + self.bus.set_config_mu(urukul.SPI_CONFIG, 16, + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write((addr | ((length - 1) << 13)) << 16) - delay_mu(-self.bus.xfer_period_mu) - self.bus.set_xfer(self.chip_select, length*8, 0) + self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, length*8, + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write(data << (32 - length*8)) - delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu) @kernel - def read(self, addr=int32(0), length=int32(1)): - """Variable length read from a register. Up to 32 bits. + def read(self, addr, length): + """Variable length read from a register. + Up to 4 bytes. :param addr: Register address :param length: Length in bytes (1-4) + :return: Data read """ assert length > 0 assert length <= 4 - self.bus.set_xfer(self.chip_select, 16, 0) + self.bus.set_config_mu(urukul.SPI_CONFIG, 16, + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write((addr | ((length - 1) << 13) | 0x8000) << 16) - delay_mu(-self.bus.xfer_period_mu) - self.bus.set_xfer(self.chip_select, 0, length*8) + self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END + | spi.SPI_INPUT, length*8, + urukul.SPIT_DDS_RD, self.chip_select) self.bus.write(0) - delay_mu(2*self.bus.xfer_period_mu) - data = self.bus.read_sync() + data = self.bus.read() if length < 4: data &= (1 << (length*8)) - 1 return data @kernel def init(self): - """Initialize and configure the DDS.""" - t = now_mu() + """Initialize and configure the DDS. + + Sets up SPI mode, confirms chip presence, powers down unused blocks, + and configures the PLL. Does not wait for PLL lock. Uses the + IO_UPDATE signal multiple times. + """ # SPI mode - self.write(AD9912_SER_CONF, 0x99) + self.write(AD9912_SER_CONF, 0x99, length=1) + self.cpld.io_update.pulse(1*us) # Verify chip ID and presence prodid = self.read(AD9912_PRODIDH, length=2) if (prodid != 0x1982) and (prodid != 0x1902): raise ValueError("Urukul AD9912 product id mismatch") - delay(10*us) + delay(20*us) # HSTL power down, CMOS power down - self.write(AD9912_PWRCNTRL1, 0x80) - delay(10*us) - self.write(AD9912_N_DIV, self.pll_n//2 - 2) - delay(10*us) + self.write(AD9912_PWRCNTRL1, 0x80, length=1) + self.cpld.io_update.pulse(1*us) + self.write(AD9912_N_DIV, self.pll_n//2 - 2, length=1) + self.cpld.io_update.pulse(1*us) # I_cp = 375 µA, VCO high range - self.write(AD9912_PLLCFG, 0b00000101) + self.write(AD9912_PLLCFG, 0b00000101, length=1) + self.cpld.io_update.pulse(1*us) @kernel def set_att_mu(self, att): @@ -110,12 +123,12 @@ class AD9912: .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att` - :param att: Attenuation in dB. + :param att: Attenuation in dB. Higher values mean more attenuation. """ self.cpld.set_att(self.chip_select - 4, att) @kernel - def set_mu(self, ftw=int64(0), pow=int32(0)): + def set_mu(self, ftw, pow): """Set profile 0 data in machine units. After the SPI transfer, the shared IO update pin is pulsed to @@ -125,13 +138,15 @@ class AD9912: :param pow: Phase tuning word: 16 bit unsigned. """ # streaming transfer of FTW and POW - self.bus.set_xfer(self.chip_select, 16, 0) + self.bus.set_config_mu(urukul.SPI_CONFIG, 16, + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write((AD9912_POW1 << 16) | (3 << 29)) - delay_mu(-self.bus.xfer_period_mu) - self.bus.set_xfer(self.chip_select, 32, 0) - self.bus.write((pow << 16) | int32(ftw >> 32)) + self.bus.set_config_mu(urukul.SPI_CONFIG, 32, + urukul.SPIT_DDS_WR, self.chip_select) + self.bus.write((pow << 16) | (int32(ftw >> 32) & 0xffff)) + self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32, + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write(int32(ftw)) - delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu) self.cpld.io_update.pulse(10*ns) @portable(flags={"fast-math"}) diff --git a/artiq/coredevice/spi.py b/artiq/coredevice/spi.py index 22859a962..1d60722d5 100644 --- a/artiq/coredevice/spi.py +++ b/artiq/coredevice/spi.py @@ -1,6 +1,8 @@ """ Driver for generic SPI on RTIO. +This ARTIQ coredevice driver corresponds to the legacy MiSoC SPI core (v1). + Output event replacement is not supported and issuing commands at the same time is an error. """ diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 6648205c6..2cc0b80ba 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -1,22 +1,23 @@ -from artiq.language.core import kernel, delay_mu, delay, now_mu, at_mu +from artiq.language.core import kernel, delay, portable from artiq.language.units import us, ms from numpy import int32, int64 -from artiq.coredevice import spi +from artiq.coredevice import spi2 as spi -_SPI_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_CS_POLARITY | +SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | + 0*spi.SPI_INPUT | 1*spi.SPI_CS_POLARITY | 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) # SPI clock write and read dividers -_SPIT_CFG_WR = 2 -_SPIT_CFG_RD = 16 -_SPIT_ATT_WR = 2 -_SPIT_ATT_RD = 16 -_SPIT_DDS_WR = 3 -_SPIT_DDS_RD = 16 +SPIT_CFG_WR = 2 +SPIT_CFG_RD = 16 +SPIT_ATT_WR = 2 +SPIT_ATT_RD = 16 +SPIT_DDS_WR = 2 +SPIT_DDS_RD = 16 # CFG configuration register bit offsets CFG_RF_SW = 0 @@ -29,17 +30,6 @@ CFG_SYNC_SEL = 18 CFG_RST = 19 CFG_IO_RST = 20 - -@kernel -def urukul_cfg(rf_sw, led, profile, io_update, mask_nu, - clk_sel, sync_sel, rst, io_rst): - return ((rf_sw << CFG_RF_SW) | (led << CFG_LED) | - (profile << CFG_PROFILE) | - (io_update << CFG_IO_UPDATE) | (mask_nu << CFG_MASK_NU) | - (clk_sel << CFG_CLK_SEL) | (sync_sel << CFG_SYNC_SEL) | - (rst << CFG_RST) | (io_rst << CFG_IO_RST)) - - # STA status register bit offsets STA_RF_SW = 0 STA_SMP_ERR = 4 @@ -47,32 +37,6 @@ STA_PLL_LOCK = 8 STA_IFC_MODE = 12 STA_PROTO_REV = 16 - -@kernel -def urukul_sta_rf_sw(sta): - return (sta >> STA_RF_SW) & 0xf - - -@kernel -def urukul_sta_smp_err(sta): - return (sta >> STA_SMP_ERR) & 0xf - - -@kernel -def urukul_sta_pll_lock(sta): - return (sta >> STA_PLL_LOCK) & 0xf - - -@kernel -def urukul_sta_ifc_mode(sta): - return (sta >> STA_IFC_MODE) & 0xf - - -@kernel -def urukul_sta_proto_rev(sta): - return (sta >> STA_PROTO_REV) & 0x7f - - # supported hardware and CPLD code version STA_PROTO_REV_MATCH = 0x08 @@ -86,6 +50,51 @@ CS_DDS_CH2 = 6 CS_DDS_CH3 = 7 +@portable +def urukul_cfg(rf_sw, led, profile, io_update, mask_nu, + clk_sel, sync_sel, rst, io_rst): + """Build Urukul CPLD configuration register""" + return ((rf_sw << CFG_RF_SW) | + (led << CFG_LED) | + (profile << CFG_PROFILE) | + (io_update << CFG_IO_UPDATE) | + (mask_nu << CFG_MASK_NU) | + (clk_sel << CFG_CLK_SEL) | + (sync_sel << CFG_SYNC_SEL) | + (rst << CFG_RST) | + (io_rst << CFG_IO_RST)) + + +@portable +def urukul_sta_rf_sw(sta): + """Return the RF switch status from Urukul status register value.""" + return (sta >> STA_RF_SW) & 0xf + + +@portable +def urukul_sta_smp_err(sta): + """Return the SMP_ERR status from Urukul status register value.""" + return (sta >> STA_SMP_ERR) & 0xf + + +@portable +def urukul_sta_pll_lock(sta): + """Return the PLL_LOCK status from Urukul status register value.""" + return (sta >> STA_PLL_LOCK) & 0xf + + +@portable +def urukul_sta_ifc_mode(sta): + """Return the IFC_MODE status from Urukul status register value.""" + return (sta >> STA_IFC_MODE) & 0xf + + +@portable +def urukul_sta_proto_rev(sta): + """Return the PROTO_REV value from Urukul status register value.""" + return (sta >> STA_PROTO_REV) & 0x7f + + class CPLD: """Urukul CPLD SPI router and configuration interface. @@ -94,11 +103,18 @@ class CPLD: :param dds_reset_device: DDS reset RTIO TTLOut channel name :param refclk: Reference clock (SMA, MMCX or on-board 100 MHz oscillator) frequency in Hz + :param clk_sel: Reference clock selection. 0 corresponds to the internal + MMCX or ob-board XO clock. 1 corresponds to the front panel SMA. + :param sync_sel: SYNC clock selection. 0 corresponds to SYNC clock over EEM + from FPGA. 1 corresponds to SYNC clock from DDS0. :param core_device: Core device name """ + kernel_invariants = {"refclk", "bus", "core", "io_update"} + def __init__(self, dmgr, spi_device, io_update_device, dds_reset_device=None, - refclk=100e6, core_device="core"): + sync_sel=0, clk_sel=0, + refclk=125e6, core_device="core"): self.core = dmgr.get(core_device) self.refclk = refclk @@ -108,63 +124,83 @@ class CPLD: if dds_reset_device is not None: self.dds_reset = dmgr.get(dds_reset_device) - self.cfg_reg = int32(0) - self.att_reg = int32(0) + self.cfg_reg = urukul_cfg(rf_sw=0, led=0, profile=0, + io_update=0, mask_nu=0, clk_sel=clk_sel, + sync_sel=sync_sel, rst=0, io_rst=0) + self.att_reg = 0 @kernel - def cfg_write(self, data=int32(0)): + def cfg_write(self, cfg): """Write to the configuration register. + See :func:`urukul_cfg` for possible flags. + :param data: 24 bit data to be written. Will be stored at :attr:`cfg_reg`. """ - self.bus.set_config_mu(_SPI_CONFIG, _SPIT_CFG_WR, _SPIT_CFG_RD) - self.bus.set_xfer(CS_CFG, 24, 0) - self.bus.write(data << 8) - self.bus.set_config_mu(_SPI_CONFIG, _SPIT_DDS_WR, _SPIT_DDS_RD) - self.cfg_reg = data + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 24, + SPIT_CFG_WR, CS_CFG) + self.bus.write(cfg << 8) + self.cfg_reg = cfg @kernel def sta_read(self): - self.bus.set_config_mu(_SPI_CONFIG, _SPIT_CFG_WR, _SPIT_CFG_RD) - self.bus.set_xfer(CS_CFG, 0, 24) + """Read the status register. + + Use any of the following functions to extract values: + + * :func:`urukul_sta_rf_sw` + * :func:`urukul_sta_smp_err` + * :func:`urukul_sta_pll_lock` + * :func:`urukul_sta_ifc_mode` + * :func:`urukul_sta_proto_rev` + + :return: The status register value. + """ + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 24, + SPIT_CFG_RD, CS_CFG) self.bus.write(self.cfg_reg << 8) - self.bus.set_config_mu(_SPI_CONFIG, _SPIT_DDS_WR, _SPIT_DDS_RD) - return self.bus.read_sync() + return self.bus.read() @kernel - def init(self, clk_sel=0, sync_sel=0): - cfg = urukul_cfg(rf_sw=0, led=0, profile=0, - io_update=0, mask_nu=0, clk_sel=clk_sel, - sync_sel=sync_sel, rst=0, io_rst=0) - self.cfg_write(cfg | (1 << CFG_RST) | (1 << CFG_IO_RST)) - delay(1*ms) - self.cfg_write(cfg) - delay(10*ms) # DDS wake up + def init(self): + """Initialize and detect Urukul. + + Resets the DDS and verifies correct CPLD gateware version. + """ + cfg = self.cfg_reg + self.cfg_reg = cfg | (1 << CFG_RST) | (1 << CFG_IO_RST) proto_rev = urukul_sta_proto_rev(self.sta_read()) if proto_rev != STA_PROTO_REV_MATCH: raise ValueError("Urukul proto_rev mismatch") - delay(100*us) + delay(20*us) # slack, reset + self.cfg_write(cfg) + delay(1*ms) # DDS wake up @kernel def io_rst(self): - delay(1*us) + """Pulse IO_RST""" self.cfg_write(self.cfg_reg | (1 << CFG_IO_RST)) - delay(1*us) self.cfg_write(self.cfg_reg & ~(1 << CFG_IO_RST)) - delay(1*us) @kernel - def cfg_sw(self, sw, on): + def cfg_sw(self, channel, on): + """Configure the RF switches through the configuration register. + + These values are logically OR-ed with the LVDS lines on EEM1. + + :param channel: Channel index (0-3) + :param on: Switch value + """ c = self.cfg_reg if on: - c |= 1 << sw + c |= 1 << channel else: - c &= ~(1 << sw) + c &= ~(1 << channel) self.cfg_write(c) @kernel - def set_att_mu(self, channel=int32(0), att=int32(0)): + def set_att_mu(self, channel, att): """Set digital step attenuator in machine units. :param channel: Attenuator channel (0-3). @@ -173,16 +209,28 @@ class CPLD: """ a = self.att_reg & ~(0xff << (channel * 8)) a |= att << (channel * 8) - self.att_reg = a - self.bus.set_config_mu(_SPI_CONFIG, _SPIT_ATT_WR, _SPIT_ATT_RD) - self.bus.set_xfer(CS_ATT, 32, 0) + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32, + SPIT_ATT_WR, CS_ATT) self.bus.write(a) + self.att_reg = a @kernel def set_att(self, channel, att): """Set digital step attenuator in SI units. :param channel: Attenuator channel (0-3). - :param att: Attenuation in dB. + :param att: Attenuation setting in dB. Higher value is more + attenuation. """ self.set_att_mu(channel, 255 - int32(round(att*8))) + + @kernel + def get_att_mu(self): + """Return the digital step attenuator settings in machine units. + + :return: 32 bit attenuator settings + """ + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 32, + SPIT_ATT_RD, CS_ATT) + self.bus.write(self.att_reg) + return self.bus.read() diff --git a/artiq/examples/kasli_opticlock/device_db.py b/artiq/examples/kasli_opticlock/device_db.py index 1600797ec..773962d73 100644 --- a/artiq/examples/kasli_opticlock/device_db.py +++ b/artiq/examples/kasli_opticlock/device_db.py @@ -188,7 +188,7 @@ device_db = { "spi_novogorny0": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "SPIMaster", "arguments": {"channel": 24} }, @@ -201,7 +201,7 @@ device_db = { "spi_urukul0": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "SPIMaster", "arguments": {"channel": 26} }, @@ -242,7 +242,8 @@ device_db = { "arguments": { "spi_device": "spi_urukul0", "io_update_device": "ttl_urukul0_io_update", - "refclk": 100e6 + "refclk": 100e6, + "clk_sel": 1 } }, "urukul0_ch0": { diff --git a/artiq/examples/kasli_opticlock/repository/urukul.py b/artiq/examples/kasli_opticlock/repository/urukul.py index 2f6a28d9f..39b8ea3c2 100644 --- a/artiq/examples/kasli_opticlock/repository/urukul.py +++ b/artiq/examples/kasli_opticlock/repository/urukul.py @@ -11,9 +11,6 @@ class UrukulTest(EnvExperiment): self.setattr_device("urukul0_ch3") self.setattr_device("led0") - def p(self, f, *a): - print(f % a) - @kernel def run(self): self.core.reset() @@ -21,7 +18,7 @@ class UrukulTest(EnvExperiment): delay(5*ms) self.led0.off() - self.urukul0_cpld.init(clk_sel=0) + self.urukul0_cpld.init() self.urukul0_ch0.init() self.urukul0_ch1.init() self.urukul0_ch2.init() diff --git a/artiq/examples/kc705_nist_clock/device_db.py b/artiq/examples/kc705_nist_clock/device_db.py index 1beebf7c1..deef2723a 100644 --- a/artiq/examples/kc705_nist_clock/device_db.py +++ b/artiq/examples/kc705_nist_clock/device_db.py @@ -192,7 +192,7 @@ device_db = { "spi_urukul": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "SPIMaster", "arguments": {"channel": 32} }, diff --git a/artiq/examples/kc705_nist_clock/repository/urukul.py b/artiq/examples/kc705_nist_clock/repository/urukul.py index ea85597f9..129daf0b7 100644 --- a/artiq/examples/kc705_nist_clock/repository/urukul.py +++ b/artiq/examples/kc705_nist_clock/repository/urukul.py @@ -16,9 +16,6 @@ class UrukulTest(EnvExperiment): self.setattr_device("urukul_ch3b") self.setattr_device("led") - def p(self, f, *a): - print(f % a) - @kernel def run(self): self.core.reset() @@ -28,7 +25,7 @@ class UrukulTest(EnvExperiment): self.fmcdio_dirctl.set(0x0A008800) self.led.off() - self.urukul_cpld.init(clk_sel=0) + self.urukul_cpld.init() self.urukul_ch0b.init() self.urukul_ch1b.init() self.urukul_ch2b.init() @@ -54,24 +51,19 @@ class UrukulTest(EnvExperiment): self.urukul_ch3b.sw.on() self.urukul_ch3b.set_att(20.) - i = 0 - j = 0 - while True: - delay(13*us) - self.urukul_ch0b.write32(0x07, i) - self.urukul_cpld.io_update.pulse(10*ns) - k = self.urukul_ch0b.read32(0x07) - delay(100*us) - if k != i: - #print(i) - #print(k) - #if j > 20: - # return - j += 1 - #delay(20*ms) - i += 1 + data = 0 + errors = 0 + delay(100*us) + while data != -1: + self.urukul_ch0b.write32(0x07, data) + read = self.urukul_ch0b.read32(0x07) + if read != data: + errors += 1 + if errors > 20: + return + data += 1 - while True: + while False: self.urukul_ch0b.sw.pulse(5*ms) delay(5*ms) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index e45c57ff1..d5affe656 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -19,7 +19,7 @@ from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio -from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi +from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi2 from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite from artiq.build_soc import build_artiq_soc @@ -265,7 +265,7 @@ class Opticlock(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - phy = spi.SPIMaster(self.platform.request("eem3_spi_p"), + phy = spi2.SPIMaster(self.platform.request("eem3_spi_p"), self.platform.request("eem3_spi_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) @@ -276,7 +276,7 @@ class Opticlock(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - phy = spi.SPIMaster(self.platform.request("eem5_spi_p"), + phy = spi2.SPIMaster(self.platform.request("eem5_spi_p"), self.platform.request("eem5_spi_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 7b868910d..1479c8e6c 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -17,7 +17,7 @@ from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio, nist_clock, nist_qc2 from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series, - dds, spi, ad5360_monitor) + dds, spi, spi2, ad5360_monitor) from artiq.build_soc import build_artiq_soc from artiq import __version__ as artiq_version @@ -355,8 +355,8 @@ class NIST_CLOCK(_StandaloneBase): self.submodules += dac_monitor sdac_phy.probes.extend(dac_monitor.probes) - phy = spi.SPIMaster(self.platform.request("urukul_spi_p"), - self.platform.request("urukul_spi_n")) + phy = spi2.SPIMaster(self.platform.request("urukul_spi_p"), + self.platform.request("urukul_spi_n")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) From 96f697ec96af06d5830800721d3647a3643292c8 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 21 Feb 2018 15:20:11 +0000 Subject: [PATCH 0374/2457] firmware: update compiler_builtins to unbreak __gtdf2. Fixes #883. --- artiq/firmware/Cargo.lock | 6 +++--- artiq/firmware/libboard/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 044d1ff8f..ed834b273 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -29,7 +29,7 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=1c765ad)", + "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=ca06a5e)", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", ] @@ -89,7 +89,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "compiler_builtins" version = "0.1.0" -source = "git+https://github.com/m-labs/compiler-builtins?rev=1c765ad#1c765adbe8e246e01db39aba0a71a6b5721e2465" +source = "git+https://github.com/m-labs/compiler-builtins?rev=ca06a5e#ca06a5e3d5ff9a17210f22401fdf6325f632c59e" [[package]] name = "crc" @@ -286,7 +286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"checksum compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=1c765ad)" = "" +"checksum compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=ca06a5e)" = "" "checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" "checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "" diff --git a/artiq/firmware/libboard/Cargo.toml b/artiq/firmware/libboard/Cargo.toml index f00a23abc..c47f8eecb 100644 --- a/artiq/firmware/libboard/Cargo.toml +++ b/artiq/firmware/libboard/Cargo.toml @@ -17,7 +17,7 @@ byteorder = { version = "1.0", default-features = false } [dependencies.compiler_builtins] git = "https://github.com/m-labs/compiler-builtins" -rev = "1c765ad" +rev = "ca06a5e" features = ["mem"] [dependencies.smoltcp] From be704b15331cca5bc1ad84581ef6a25330ce4533 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Feb 2018 01:32:12 +0800 Subject: [PATCH 0375/2457] RELEASE_NOTES: mention short options for artiq_flash --- RELEASE_NOTES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index be06ffa75..c87cb4877 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -18,7 +18,7 @@ Release notes server address argument and the notify port. * The master now has a ``--name`` argument. If given, the dashboard is labelled with this name rather than the server address. -* ``artiq_flash --adapter`` has been changed to ``artiq_flash --variant``. +* ``artiq_flash -m/--adapter`` has been changed to ``artiq_flash -V/--variant``. * ``kc705_dds`` has been renamed ``kc705``. * the ``-H/--hw-adapter`` option of ``kc705`` has ben renamed ``-V/--variant``. From 5eda894db41daacd906c57edfca163be98407069 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 21 Feb 2018 19:36:37 +0100 Subject: [PATCH 0376/2457] firmware/libboard/sdram: increase read_delays dead zone to 32 on KU --- artiq/firmware/libboard/sdram.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index f987ab79c..a753bc453 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -209,7 +209,7 @@ mod ddr { // Get a bit further into the working zone #[cfg(kusddrphy)] - for _ in 0..16 { + for _ in 0..32 { delay.set(delay.get() + 1); ddrphy::rdly_dq_inc_write(1); } From 898bad5abceb68af80b85664878aaa3106b26290 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 21 Feb 2018 18:26:51 +0000 Subject: [PATCH 0377/2457] spi2: fixes --- artiq/coredevice/spi2.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index 8e5604703..3bfdd5a20 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -7,9 +7,7 @@ Output event replacement is not supported and issuing commands at the same time is an error. """ -from numpy import int64 from artiq.language.core import syscall, kernel, portable, now_mu, delay_mu -from artiq.language.types import TInt32, TNone from artiq.coredevice.rtio import rtio_output, rtio_input_data @@ -72,11 +70,10 @@ class SPIMaster: @portable def frequency_to_div(self, f): """Convert a SPI clock frequency to the closest SPI clock divider.""" - return int64(round( - 1/(f*self.core.mu_to_seconds(self.ref_period_mu)))) + return int(round(1/(f*self.core.mu_to_seconds(self.ref_period_mu)))) @kernel - def set_config(self, flags, length, freq, c): + def set_config(self, flags, length, freq, cs): """Set the configuration register. * If ``SPI_CS_POLARITY`` is cleared (``cs`` active low, the default), @@ -140,8 +137,7 @@ class SPIMaster: Or number of the chip select to assert if ``cs`` is decoded downstream. (reset=0) """ - self.set_config_mu( - flags, length, self.frequency_to_div(write_freq), cs) + self.set_config_mu(flags, length, self.frequency_to_div(freq), cs) @kernel def set_config_mu(self, flags, length, div, cs): From 0d8145084ddc04784b6d3474564b87fc90f8c850 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 21 Feb 2018 18:27:07 +0000 Subject: [PATCH 0378/2457] test_spi: move to new spi2 core --- artiq/examples/kc705_nist_clock/device_db.py | 2 +- artiq/gateware/targets/kc705.py | 2 +- artiq/test/coredevice/test_spi.py | 63 ++++++++++---------- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/artiq/examples/kc705_nist_clock/device_db.py b/artiq/examples/kc705_nist_clock/device_db.py index deef2723a..a0a2fa679 100644 --- a/artiq/examples/kc705_nist_clock/device_db.py +++ b/artiq/examples/kc705_nist_clock/device_db.py @@ -125,7 +125,7 @@ device_db = { }, "spi_mmc": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "SPIMaster", "arguments": {"channel": 26} }, diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 1479c8e6c..5f008def0 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -330,7 +330,7 @@ class NIST_CLOCK(_StandaloneBase): rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=128)) - phy = spi.SPIMaster(platform.request("sdcard_spi_33")) + phy = spi2.SPIMaster(platform.request("sdcard_spi_33")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=4)) diff --git a/artiq/test/coredevice/test_spi.py b/artiq/test/coredevice/test_spi.py index 076185c0a..17bf6eeb6 100644 --- a/artiq/test/coredevice/test_spi.py +++ b/artiq/test/coredevice/test_spi.py @@ -3,13 +3,15 @@ from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase from artiq.language.core import (kernel, delay_mu, delay) from artiq.language.units import us -from artiq.coredevice import spi +from artiq.coredevice import spi2 as spi -_SDCARD_SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_CS_POLARITY | +_SDCARD_SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | + 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) + class CardTest(EnvExperiment): def build(self): self.setattr_device("core") @@ -18,44 +20,41 @@ class CardTest(EnvExperiment): @kernel def run(self): self.core.reset() - self.core.break_realtime() - response = 0xff - self.spi_mmc.set_config(_SDCARD_SPI_CONFIG, 500*kHz, 500*kHz) - self.spi_mmc.set_xfer(0, 8, 0) + + freq = 1*MHz + cs = 1 + # run a couple of clock cycles with miso high to wake up the card + self.spi_mmc.set_config(_SDCARD_SPI_CONFIG, 32, freq, 0) for i in range(10): self.spi_mmc.write(0xffffffff) - delay(-5*us) - - delay(100*us) - - self.spi_mmc.set_xfer(1, 8, 0) - self.spi_mmc.write(0x40000000) - delay(-5*us) - self.spi_mmc.write(0x00000000) - delay(-5*us) - self.spi_mmc.write(0x00000000) - delay(-5*us) - self.spi_mmc.write(0x00000000) - delay(-5*us) - self.spi_mmc.write(0x00000000) - delay(-5*us) - self.spi_mmc.write(0x95000000) - delay(-5*us) - - self.spi_mmc.set_xfer(1, 0, 24) + self.spi_mmc.set_config(_SDCARD_SPI_CONFIG | spi.SPI_END, 32, freq, 0) self.spi_mmc.write(0xffffffff) - response = self.spi_mmc.read_sync() + delay(200*us) - sd_response = False - for i in range(3): - if ((response >> 8*i) & 0x0000ff) == 0x01: - sd_response = True + self.spi_mmc.set_config(_SDCARD_SPI_CONFIG, 8, freq, cs) + self.spi_mmc.write(0x40 << 24) # CMD + self.spi_mmc.set_config(_SDCARD_SPI_CONFIG, 32, freq, cs) + self.spi_mmc.write(0x00000000) # ARG + self.spi_mmc.set_config(_SDCARD_SPI_CONFIG, 8, freq, cs) + self.spi_mmc.write(0x95 << 24) # CRC + self.spi_mmc.set_config(_SDCARD_SPI_CONFIG | spi.SPI_INPUT, 8, freq, cs) + idle = False + response = 0 + for i in range(8): + self.spi_mmc.write(0xff << 24) # NCR + response = self.spi_mmc.read() + delay(100*us) + if response == 0x01: + idle = True break - self.set_dataset("sd_response", sd_response) + self.spi_mmc.set_config(_SDCARD_SPI_CONFIG | spi.SPI_END, 8, freq, cs) + self.spi_mmc.write(0xff << 24) + if not idle: + print(response) + raise ValueError("SD Card did not reply with IDLE") class SDTest(ExperimentCase): def test(self): self.execute(CardTest) - self.assertTrue(self.dataset_mgr.get("sd_response")) From a5ad1dc266ee185407d951f477e5c327bdf27481 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 21 Feb 2018 19:40:12 +0100 Subject: [PATCH 0379/2457] kc705: fix sdcard miso pullup --- artiq/gateware/targets/kc705.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 5f008def0..c73b73ca5 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -102,7 +102,7 @@ _ams101_dac = [ _sdcard_spi_33 = [ ("sdcard_spi_33", 0, - Subsignal("miso", Pins("AC20"), Misc("PULLUP")), + Subsignal("miso", Pins("AC20"), Misc("PULLUP=TRUE")), Subsignal("clk", Pins("AB23")), Subsignal("mosi", Pins("AB22")), Subsignal("cs_n", Pins("AC21")), From 4d6619f3bc26f4d4931bc0f8d3df19d0ed2a61ac Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Feb 2018 15:17:44 +0800 Subject: [PATCH 0380/2457] satman: send ResetAck --- artiq/firmware/satman/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 2e11ad869..8feb65a1f 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -43,7 +43,8 @@ fn process_aux_packet(p: &drtioaux::Packet) { } else { drtio_reset(true); drtio_reset(false); - } + }, + drtioaux::hw::send_link(0, &drtioaux::Packet::ResetAck).unwrap(); }, drtioaux::Packet::RtioErrorRequest => { From e5de5ef4736138284a11339427d12ed7160d492f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Feb 2018 15:18:06 +0800 Subject: [PATCH 0381/2457] kasli: use deterministic RX synchronizer Could not reproduce the "fully broken bitstream" bug. --- artiq/gateware/targets/kasli.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index d5affe656..12e6cb20d 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -21,6 +21,7 @@ from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi2 from artiq.gateware.drtio.transceiver import gtp_7series +from artiq.gateware.drtio.xilinx_rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite from artiq.build_soc import build_artiq_soc from artiq import __version__ as artiq_version @@ -476,8 +477,10 @@ class Satellite(BaseSoC): ~self.drtio_transceiver.stable_clkin.storage) rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) + self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) self.submodules.drtio0 = rx0(DRTIOSatellite( - self.drtio_transceiver.channels[0], rtio_channels)) + self.drtio_transceiver.channels[0], rtio_channels, + self.rx_synchronizer)) self.csr_devices.append("drtio0") self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, self.drtio0.aux_controller.bus) From fa0d929b4db563418f071752f445fe6eba3c69c6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Feb 2018 15:21:23 +0800 Subject: [PATCH 0382/2457] drtio: reorganize RX synchronizers --- artiq/gateware/drtio/core.py | 25 +------------------ ..._rx_synchronizer.py => rx_synchronizer.py} | 24 ++++++++++++++++++ artiq/gateware/targets/kasli.py | 2 +- artiq/gateware/targets/sayma_amc.py | 2 +- 4 files changed, 27 insertions(+), 26 deletions(-) rename artiq/gateware/drtio/{xilinx_rx_synchronizer.py => rx_synchronizer.py} (61%) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 507b93a7e..36f262c4f 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -1,7 +1,6 @@ from types import SimpleNamespace from migen import * -from migen.genlib.cdc import ElasticBuffer from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.interconnect.csr import * @@ -10,6 +9,7 @@ from artiq.gateware.rtio.input_collector import * from artiq.gateware.drtio import (link_layer, aux_controller, rt_packet_satellite, rt_errors_satellite, rt_packet_master, rt_controller_master) +from artiq.gateware.drtio.rx_synchronizer import GenericRXSynchronizer class ChannelInterface: @@ -29,29 +29,6 @@ class TransceiverInterface(AutoCSR): self.channels = channel_interfaces -class GenericRXSynchronizer(Module): - """Simple RX synchronizer based on the portable Migen elastic buffer. - - Introduces timing non-determinism in the satellite RX path, e.g. - echo_request/echo_reply RTT and TSC sync, but useful for testing. - """ - def __init__(self): - self.signals = [] - - def resync(self, signal): - synchronized = Signal.like(signal, related=signal) - self.signals.append((signal, synchronized)) - return synchronized - - def do_finalize(self): - eb = ElasticBuffer(sum(len(s[0]) for s in self.signals), 4, "rtio_rx", "rtio") - self.submodules += eb - self.comb += [ - eb.din.eq(Cat(*[s[0] for s in self.signals])), - Cat(*[s[1] for s in self.signals]).eq(eb.dout) - ] - - class DRTIOSatellite(Module): def __init__(self, chanif, channels, rx_synchronizer=None, fine_ts_width=3, lane_count=8, fifo_depth=128): diff --git a/artiq/gateware/drtio/xilinx_rx_synchronizer.py b/artiq/gateware/drtio/rx_synchronizer.py similarity index 61% rename from artiq/gateware/drtio/xilinx_rx_synchronizer.py rename to artiq/gateware/drtio/rx_synchronizer.py index d6bdfa0aa..904e3cf17 100644 --- a/artiq/gateware/drtio/xilinx_rx_synchronizer.py +++ b/artiq/gateware/drtio/rx_synchronizer.py @@ -1,4 +1,28 @@ from migen import * +from migen.genlib.cdc import ElasticBuffer + + +class GenericRXSynchronizer(Module): + """Simple RX synchronizer based on the portable Migen elastic buffer. + + Introduces timing non-determinism in the satellite RX path, e.g. + echo_request/echo_reply RTT and TSC sync, but useful for testing. + """ + def __init__(self): + self.signals = [] + + def resync(self, signal): + synchronized = Signal.like(signal, related=signal) + self.signals.append((signal, synchronized)) + return synchronized + + def do_finalize(self): + eb = ElasticBuffer(sum(len(s[0]) for s in self.signals), 4, "rtio_rx", "rtio") + self.submodules += eb + self.comb += [ + eb.din.eq(Cat(*[s[0] for s in self.signals])), + Cat(*[s[1] for s in self.signals]).eq(eb.dout) + ] class XilinxRXSynchronizer(Module): diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 12e6cb20d..f04032c8f 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -21,7 +21,7 @@ from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi2 from artiq.gateware.drtio.transceiver import gtp_7series -from artiq.gateware.drtio.xilinx_rx_synchronizer import XilinxRXSynchronizer +from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite from artiq.build_soc import build_artiq_soc from artiq import __version__ as artiq_version diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index c7871c08a..30060fe6a 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -33,7 +33,7 @@ from artiq.gateware import remote_csr from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale -from artiq.gateware.drtio.xilinx_rx_synchronizer import XilinxRXSynchronizer +from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite from artiq.build_soc import build_artiq_soc from artiq import __version__ as artiq_version From 10c02afd9c5392d4673a96615bb65cd177e17a84 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 22 Feb 2018 07:22:22 +0000 Subject: [PATCH 0383/2457] conda: merge all board packages except sayma_rtm into one. Fixes #923. --- conda/artiq-board/build.sh | 9 +++++++ .../meta.yaml | 4 ++-- conda/artiq-kasli-master/build.sh | 9 ------- conda/artiq-kasli-master/meta.yaml | 23 ------------------ conda/artiq-kasli-opticlock/build.sh | 9 ------- conda/artiq-kasli-opticlock/meta.yaml | 23 ------------------ conda/artiq-kasli-satellite/build.sh | 9 ------- conda/artiq-kc705-nist_clock/build.sh | 9 ------- conda/artiq-kc705-nist_clock/meta.yaml | 23 ------------------ conda/artiq-kc705-nist_qc2/build.sh | 9 ------- conda/artiq-kc705-nist_qc2/meta.yaml | 23 ------------------ conda/artiq-sayma-standalone/build.sh | 13 ---------- conda/artiq-sayma-standalone/meta.yaml | 24 ------------------- 13 files changed, 11 insertions(+), 176 deletions(-) create mode 100644 conda/artiq-board/build.sh rename conda/{artiq-kasli-satellite => artiq-board}/meta.yaml (79%) delete mode 100644 conda/artiq-kasli-master/build.sh delete mode 100644 conda/artiq-kasli-master/meta.yaml delete mode 100644 conda/artiq-kasli-opticlock/build.sh delete mode 100644 conda/artiq-kasli-opticlock/meta.yaml delete mode 100644 conda/artiq-kasli-satellite/build.sh delete mode 100644 conda/artiq-kc705-nist_clock/build.sh delete mode 100644 conda/artiq-kc705-nist_clock/meta.yaml delete mode 100644 conda/artiq-kc705-nist_qc2/build.sh delete mode 100644 conda/artiq-kc705-nist_qc2/meta.yaml delete mode 100644 conda/artiq-sayma-standalone/build.sh delete mode 100644 conda/artiq-sayma-standalone/meta.yaml diff --git a/conda/artiq-board/build.sh b/conda/artiq-board/build.sh new file mode 100644 index 000000000..3b61b285e --- /dev/null +++ b/conda/artiq-board/build.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +SOC_PREFIX=$SP_DIR/artiq/binaries/${ARTIQ_TARGET}-${ARTIQ_VARIANT} +mkdir -p ${SOC_PREFIX} + +V=1 $PYTHON -m artiq.gateware.targets.${ARTIQ_TARGET} -V ${ARTIQ_VARIANT} +cp artiq_${ARTIQ_TARGET}/${ARTIQ_VARIANT}/gateware/top.bit ${SOC_PREFIX} +cp artiq_${ARTIQ_TARGET}/${ARTIQ_VARIANT}/software/bootloader/bootloader.bin ${SOC_PREFIX} +cp artiq_${ARTIQ_TARGET}/${ARTIQ_VARIANT}/software/runtime/runtime.{elf,fbi} ${SOC_PREFIX} diff --git a/conda/artiq-kasli-satellite/meta.yaml b/conda/artiq-board/meta.yaml similarity index 79% rename from conda/artiq-kasli-satellite/meta.yaml rename to conda/artiq-board/meta.yaml index 2a23d1bc4..eb13cb0cd 100644 --- a/conda/artiq-kasli-satellite/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -1,5 +1,5 @@ package: - name: artiq-kasli-satellite + name: artiq-{{ environ.get("ARTIQ_TARGET") }}-{{ environ.get("ARTIQ_VARIANT") }} version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} source: @@ -20,4 +20,4 @@ requirements: about: home: https://m-labs.hk/artiq license: LGPL - summary: 'Bitstream, BIOS and satellite manager for the Kasli DRTIO satellite' + summary: 'Bitstream, BIOS and runtime for the {{ environ.get("ARTIQ_TARGET") }}-{{ environ.get("ARTIQ_VARIANT") }} board variant' diff --git a/conda/artiq-kasli-master/build.sh b/conda/artiq-kasli-master/build.sh deleted file mode 100644 index 2189002d9..000000000 --- a/conda/artiq-kasli-master/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -SOC_PREFIX=$SP_DIR/artiq/binaries/kasli-master -mkdir -p $SOC_PREFIX - -V=1 $PYTHON -m artiq.gateware.targets.kasli -V master -cp artiq_kasli/master/gateware/top.bit $SOC_PREFIX -cp artiq_kasli/master/software/bootloader/bootloader.bin $SOC_PREFIX -cp artiq_kasli/master/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-kasli-master/meta.yaml b/conda/artiq-kasli-master/meta.yaml deleted file mode 100644 index a25621b55..000000000 --- a/conda/artiq-kasli-master/meta.yaml +++ /dev/null @@ -1,23 +0,0 @@ -package: - name: artiq-kasli-master - version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} - -source: - git_url: ../.. - -build: - noarch: python - ignore_prefix_files: True - number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} - string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} - -requirements: - build: - - artiq-dev {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} - run: - - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} - -about: - home: https://m-labs.hk/artiq - license: LGPL - summary: 'Bitstream, BIOS and runtime for the Kasli DRTIO master' diff --git a/conda/artiq-kasli-opticlock/build.sh b/conda/artiq-kasli-opticlock/build.sh deleted file mode 100644 index cceb4f7ff..000000000 --- a/conda/artiq-kasli-opticlock/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -SOC_PREFIX=$SP_DIR/artiq/binaries/kasli-opticlock -mkdir -p $SOC_PREFIX - -V=1 $PYTHON -m artiq.gateware.targets.kasli -V opticlock -cp artiq_kasli/opticlock/gateware/top.bit $SOC_PREFIX -cp artiq_kasli/opticlock/software/bootloader/bootloader.bin $SOC_PREFIX -cp artiq_kasli/opticlock/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-kasli-opticlock/meta.yaml b/conda/artiq-kasli-opticlock/meta.yaml deleted file mode 100644 index 9d1367546..000000000 --- a/conda/artiq-kasli-opticlock/meta.yaml +++ /dev/null @@ -1,23 +0,0 @@ -package: - name: artiq-kasli-opticlock - version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} - -source: - git_url: ../.. - -build: - noarch: python - ignore_prefix_files: True - number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} - string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} - -requirements: - build: - - artiq-dev {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} - run: - - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} - -about: - home: https://m-labs.hk/artiq - license: LGPL - summary: 'Bitstream, BIOS and runtime for the opticlock variant of Kasli' diff --git a/conda/artiq-kasli-satellite/build.sh b/conda/artiq-kasli-satellite/build.sh deleted file mode 100644 index bae8ecedf..000000000 --- a/conda/artiq-kasli-satellite/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -SOC_PREFIX=$SP_DIR/artiq/binaries/kasli-satellite -mkdir -p $SOC_PREFIX - -V=1 $PYTHON -m artiq.gateware.targets.kasli -V satellite -cp artiq_kasli/satellite/gateware/top.bit $SOC_PREFIX -cp artiq_kasli/satellite/software/bootloader/bootloader.bin $SOC_PREFIX -cp artiq_kasli/satellite/software/satman/satman.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-kc705-nist_clock/build.sh b/conda/artiq-kc705-nist_clock/build.sh deleted file mode 100644 index 402b0b18f..000000000 --- a/conda/artiq-kc705-nist_clock/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -SOC_PREFIX=$SP_DIR/artiq/binaries/kc705-nist_clock -mkdir -p $SOC_PREFIX - -V=1 $PYTHON -m artiq.gateware.targets.kc705 -V nist_clock -cp artiq_kc705/nist_clock/gateware/top.bit $SOC_PREFIX -cp artiq_kc705/nist_clock/software/bootloader/bootloader.bin $SOC_PREFIX -cp artiq_kc705/nist_clock/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-kc705-nist_clock/meta.yaml b/conda/artiq-kc705-nist_clock/meta.yaml deleted file mode 100644 index 1db897a6d..000000000 --- a/conda/artiq-kc705-nist_clock/meta.yaml +++ /dev/null @@ -1,23 +0,0 @@ -package: - name: artiq-kc705-nist_clock - version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} - -source: - git_url: ../.. - -build: - noarch: python - ignore_prefix_files: True - number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} - string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} - -requirements: - build: - - artiq-dev {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} - run: - - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} - -about: - home: https://m-labs.hk/artiq - license: LGPL - summary: 'Bitstream, BIOS and runtime for NIST_CLOCK on the KC705 board' diff --git a/conda/artiq-kc705-nist_qc2/build.sh b/conda/artiq-kc705-nist_qc2/build.sh deleted file mode 100644 index 03479e29f..000000000 --- a/conda/artiq-kc705-nist_qc2/build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -SOC_PREFIX=$SP_DIR/artiq/binaries/kc705-nist_qc2 -mkdir -p $SOC_PREFIX - -V=1 $PYTHON -m artiq.gateware.targets.kc705 -V nist_qc2 -cp artiq_kc705/nist_qc2/gateware/top.bit $SOC_PREFIX -cp artiq_kc705/nist_qc2/software/bootloader/bootloader.bin $SOC_PREFIX -cp artiq_kc705/nist_qc2/software/runtime/runtime.{elf,fbi} $SOC_PREFIX diff --git a/conda/artiq-kc705-nist_qc2/meta.yaml b/conda/artiq-kc705-nist_qc2/meta.yaml deleted file mode 100644 index 009f0b630..000000000 --- a/conda/artiq-kc705-nist_qc2/meta.yaml +++ /dev/null @@ -1,23 +0,0 @@ -package: - name: artiq-kc705-nist_qc2 - version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} - -source: - git_url: ../.. - -build: - noarch: python - ignore_prefix_files: True - number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} - string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} - -requirements: - build: - - artiq-dev {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} - run: - - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} - -about: - home: https://m-labs.hk/artiq - license: LGPL - summary: 'Bitstream, BIOS and runtime for NIST_QC2 on the KC705 board' diff --git a/conda/artiq-sayma-standalone/build.sh b/conda/artiq-sayma-standalone/build.sh deleted file mode 100644 index 065201ba1..000000000 --- a/conda/artiq-sayma-standalone/build.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -RTM_PREFIX=$SP_DIR/artiq/binaries/sayma_rtm - -SOC_PREFIX=$SP_DIR/artiq/binaries/sayma-standalone -mkdir -p $SOC_PREFIX - -$PYTHON -m artiq.gateware.targets.sayma_amc -V standalone \ - --rtm-csr-csv $RTM_PREFIX/rtm_csr.csv -cp artiq_sayma/standalone/gateware/top.bit $SOC_PREFIX -cp artiq_sayma/standalone/software/bootloader/bootloader.bin $SOC_PREFIX -cp artiq_sayma/standalone/software/runtime/runtime.{elf,fbi} $SOC_PREFIX -cp $RTM_PREFIX/rtm.bit $SOC_PREFIX diff --git a/conda/artiq-sayma-standalone/meta.yaml b/conda/artiq-sayma-standalone/meta.yaml deleted file mode 100644 index 8450d3319..000000000 --- a/conda/artiq-sayma-standalone/meta.yaml +++ /dev/null @@ -1,24 +0,0 @@ -package: - name: artiq-sayma-standalone - version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} - -source: - git_url: ../.. - -build: - noarch: python - ignore_prefix_files: True - number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} - string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} - -requirements: - build: - - artiq-dev {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} - - artiq-sayma_rtm {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} - run: - - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} - -about: - home: https://m-labs.hk/artiq - license: LGPL - summary: 'Bitstream, BIOS and runtime for stand-alone Sayma AMC' From 96423882f2fdf22bd79d8473e625313064df577b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Feb 2018 15:27:54 +0800 Subject: [PATCH 0384/2457] fix 4d6619f3b --- artiq/firmware/satman/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 8feb65a1f..7744c65c0 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -43,7 +43,7 @@ fn process_aux_packet(p: &drtioaux::Packet) { } else { drtio_reset(true); drtio_reset(false); - }, + } drtioaux::hw::send_link(0, &drtioaux::Packet::ResetAck).unwrap(); }, From c3b8fe06eb412b23f1c929c431b423eae46526e7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Feb 2018 15:30:26 +0800 Subject: [PATCH 0385/2457] conda/artiq-board: use 'firmware' to encompass runtime and satman --- conda/artiq-board/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index eb13cb0cd..f4900837e 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -20,4 +20,4 @@ requirements: about: home: https://m-labs.hk/artiq license: LGPL - summary: 'Bitstream, BIOS and runtime for the {{ environ.get("ARTIQ_TARGET") }}-{{ environ.get("ARTIQ_VARIANT") }} board variant' + summary: 'Bitstream, BIOS and firmware for the {{ environ.get("ARTIQ_TARGET") }}-{{ environ.get("ARTIQ_VARIANT") }} board variant' From d83ae0bc6a8369511322c3f313fd4868dbdefa1a Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 22 Feb 2018 09:25:18 +0000 Subject: [PATCH 0386/2457] conda: use the outputs section to dynamically name packages. --- conda/artiq-board/meta.yaml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index f4900837e..8662e90f5 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -1,5 +1,5 @@ package: - name: artiq-{{ environ.get("ARTIQ_TARGET") }}-{{ environ.get("ARTIQ_VARIANT") }} + name: artiq-build version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} source: @@ -10,6 +10,12 @@ build: ignore_prefix_files: True number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} + script_env: + - ARTIQ_TARGET + - ARTIQ_VARIANT + +outputs: + - name: artiq-{{ environ.get("ARTIQ_TARGET") }}-{{ environ.get("ARTIQ_VARIANT") }} requirements: build: From f8e6b4f4e3d96dfca4464f009e588825efcf8a6a Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 22 Feb 2018 08:38:56 +0000 Subject: [PATCH 0387/2457] ad5360: port to spi2 * kc705 nist_clock target gateware * coredevice driver * moninj code * test/example/device_db This is untested as we don't have a AD5360 board right now. Will be tested with Zotino v1.1 m-labs/artiq#926 --- artiq/coredevice/ad5360.py | 63 ++++++++++--------- artiq/examples/kc705_nist_clock/device_db.py | 9 ++- .../kc705_nist_clock/repository/ad5360.py | 2 +- artiq/gateware/rtio/phy/ad5360_monitor.py | 12 ++-- artiq/gateware/targets/kc705.py | 4 +- 5 files changed, 51 insertions(+), 39 deletions(-) diff --git a/artiq/coredevice/ad5360.py b/artiq/coredevice/ad5360.py index c470fbec2..65e67aa07 100644 --- a/artiq/coredevice/ad5360.py +++ b/artiq/coredevice/ad5360.py @@ -6,14 +6,16 @@ time is an error. """ -from artiq.language.core import (kernel, portable, delay_mu, delay) +from artiq.language.core import (kernel, portable, delay_mu, delay, now_mu, + at_mu) from artiq.language.units import ns, us -from artiq.coredevice import spi +from artiq.coredevice import spi2 as spi # Designed from the data sheets and somewhat after the linux kernel # iio driver. -_AD5360_SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_CS_POLARITY | +_AD5360_SPI_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_END | + 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | 0*spi.SPI_CLK_POLARITY | 1*spi.SPI_CLK_PHASE | 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) @@ -27,6 +29,7 @@ _AD5360_CMD_SPECIAL = 0 << 22 def _AD5360_WRITE_CHANNEL(c): return (c + 8) << 16 + _AD5360_SPECIAL_NOP = 0 << 16 _AD5360_SPECIAL_CONTROL = 1 << 16 _AD5360_SPECIAL_OFS0 = 2 << 16 @@ -38,6 +41,7 @@ _AD5360_SPECIAL_READ = 5 << 16 def _AD5360_READ_CHANNEL(ch): return (ch + 8) << 7 + _AD5360_READ_X1A = 0x000 << 7 _AD5360_READ_X1B = 0x040 << 7 _AD5360_READ_OFFSET = 0x080 << 7 @@ -57,31 +61,34 @@ class AD5360: (optional). Needs to be explicitly initialized to high. :param chip_select: Value to drive on the chip select lines during transactions. + :param div_write: SPI clock divider during writes + :param div_read: SPI clock divider during reads """ + kernel_invariants = {"bus", "core", "chip_select", "div_read", "div_write"} - def __init__(self, dmgr, spi_device, ldac_device=None, chip_select=1): + def __init__(self, dmgr, spi_device, ldac_device=None, chip_select=1, + div_write=4, div_read=7): self.core = dmgr.get("core") self.bus = dmgr.get(spi_device) if ldac_device is not None: self.ldac = dmgr.get(ldac_device) self.chip_select = chip_select + # write: 2*8ns >= 10ns = t_6 (clk falling to cs_n rising) + # 4*8ns >= 20ns = t_1 (clk cycle time) + self.div_write = div_write + # read: 4*8*ns >= 25ns = t_22 (clk falling to miso valid) + self.div_read = div_read @kernel - def setup_bus(self, write_div=4, read_div=7): + def setup_bus(self): """Configure the SPI bus and the SPI transaction parameters for this device. This method has to be called before any other method if the bus has been used to access a different device in the meantime. - This method advances the timeline by the duration of two - RTIO-to-Wishbone bus transactions. - - :param write_div: Write clock divider. - :param read_div: Read clock divider. + This method advances the timeline by one coarse RTIO cycle. """ - # write: 2*8ns >= 10ns = t_6 (clk falling to cs_n rising) - # read: 4*8*ns >= 25ns = t_22 (clk falling to miso valid) - self.bus.set_config_mu(_AD5360_SPI_CONFIG, write_div, read_div) - self.bus.set_xfer(self.chip_select, 24, 0) + self.bus.set_config_mu(_AD5360_SPI_CONFIG, 24, self.div_write, + self.chip_select) @kernel def write(self, data): @@ -126,8 +133,8 @@ class AD5360: def read_channel_sync(self, channel=0, op=_AD5360_READ_X1A): """Read a channel register. - This method advances the timeline by the duration of :meth:`write` plus - three RTIO-to-Wishbone transactions. + This method advances the timeline by the duration of two :meth:`write` + plus two coarse RTIO cycles. :param channel: Channel number to read from. :param op: Operation to perform, one of :const:`_AD5360_READ_X1A`, @@ -138,11 +145,13 @@ class AD5360: channel &= 0x3f self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_READ | op | _AD5360_READ_CHANNEL(channel)) - self.bus.set_xfer(self.chip_select, 0, 24) + self.bus.set_config_mu(_AD5360_SPI_CONFIG | spi.SPI_INPUT, 24, + self.div_read, self.chip_select) + delay(270*ns) # t_21 min sync high in readback self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_NOP) - self.bus.read_async() - self.bus.set_xfer(self.chip_select, 24, 0) - return self.bus.input_async() & 0xffff + self.bus.set_config_mu(_AD5360_SPI_CONFIG, 24, + self.div_write, self.chip_select) + return self.bus.read() & 0xffff @kernel def load(self): @@ -168,15 +177,13 @@ class AD5360: :const:`_AD5360_CMD_OFFSET`, :const:`_AD5360_CMD_GAIN` (default: :const:`_AD5360_CMD_DATA`). """ + t0 = now_mu() + # t10 max busy low for one channel + t_10 = self.core.seconds_to_mu(1.5*us) # compensate all delays that will be applied - delay_mu(-len(values)*(self.bus.xfer_period_mu + - self.bus.write_period_mu + - self.bus.ref_period_mu) - - 3*self.bus.ref_period_mu - - self.core.seconds_to_mu(1.5*us)) + delay_mu(-len(values)*self.bus.xfer_period_mu-t_10) for i in range(len(values)): self.write_channel(i, values[i], op) - delay_mu(3*self.bus.ref_period_mu + # latency alignment ttl to spi - self.core.seconds_to_mu(1.5*us)) # t10 max busy low for one channel + delay_mu(t_10) self.load() - delay_mu(-2*self.bus.ref_period_mu) # load(), t13 + at_mu(t0) diff --git a/artiq/examples/kc705_nist_clock/device_db.py b/artiq/examples/kc705_nist_clock/device_db.py index a0a2fa679..e8e0901f1 100644 --- a/artiq/examples/kc705_nist_clock/device_db.py +++ b/artiq/examples/kc705_nist_clock/device_db.py @@ -173,7 +173,7 @@ device_db = { }, "spi_zotino": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "SPIMaster", "arguments": {"channel": 30} }, @@ -187,7 +187,12 @@ device_db = { "type": "local", "module": "artiq.coredevice.ad5360", "class": "AD5360", - "arguments": {"spi_device": "spi_zotino", "ldac_device": "ttl_zotino_ldac"} + "arguments": { + "spi_device": "spi_zotino", + "ldac_device": "ttl_zotino_ldac", + "div_write": 30, + "div_read": 40 + } }, "spi_urukul": { diff --git a/artiq/examples/kc705_nist_clock/repository/ad5360.py b/artiq/examples/kc705_nist_clock/repository/ad5360.py index 79d1f01c6..88ba87631 100644 --- a/artiq/examples/kc705_nist_clock/repository/ad5360.py +++ b/artiq/examples/kc705_nist_clock/repository/ad5360.py @@ -13,7 +13,7 @@ class AD5360Test(EnvExperiment): self.core.reset() delay(5*ms) # build slack for shift register set self.fmcdio_dirctl.set(self, 0x00008800) - self.dac.setup_bus(write_div=30, read_div=40) + self.dac.setup_bus() self.dac.write_offsets() self.led.on() delay(400*us) diff --git a/artiq/gateware/rtio/phy/ad5360_monitor.py b/artiq/gateware/rtio/phy/ad5360_monitor.py index fad34ecc6..c112d6649 100644 --- a/artiq/gateware/rtio/phy/ad5360_monitor.py +++ b/artiq/gateware/rtio/phy/ad5360_monitor.py @@ -1,6 +1,6 @@ from migen import * -from artiq.coredevice.spi import SPI_XFER_ADDR, SPI_DATA_ADDR +from artiq.coredevice.spi2 import SPI_CONFIG_ADDR, SPI_DATA_ADDR from artiq.coredevice.ad5360 import _AD5360_CMD_DATA, _AD5360_WRITE_CHANNEL @@ -22,20 +22,20 @@ class AD5360Monitor(Module): If(ldac_oif.stb & ttl_level_adr & ~ldac_oif.data[0], [probe.eq(write_target) for probe, write_target in zip(self.probes, write_targets)] ) - + spi_oif = spi_rtlink.o selected = Signal() if cs_onehot: self.sync.rio_phy += [ - If(spi_oif.stb & (spi_oif.address == SPI_XFER_ADDR), - selected.eq(spi_oif.data[cs_no]) + If(spi_oif.stb & (spi_oif.address == SPI_CONFIG_ADDR), + selected.eq(spi_oif.data[24 + cs_no]) ) ] else: self.sync.rio_phy += [ - If(spi_oif.stb & (spi_oif.address == SPI_XFER_ADDR), - selected.eq(spi_oif.data[:16] == cs_no) + If(spi_oif.stb & (spi_oif.address == SPI_CONFIG_ADDR), + selected.eq(spi_oif.data[24:] == cs_no) ) ] diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index c73b73ca5..e19ce222b 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -341,8 +341,8 @@ class NIST_CLOCK(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - sdac_phy = spi.SPIMaster(self.platform.request("zotino_spi_p"), - self.platform.request("zotino_spi_n")) + sdac_phy = spi2.SPIMaster(self.platform.request("zotino_spi_p"), + self.platform.request("zotino_spi_n")) self.submodules += sdac_phy rtio_channels.append(rtio.Channel.from_phy(sdac_phy, ififo_depth=4)) From e8d4db1ccf4a8c5bf4684a97cfcaa32d080bb510 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 22 Feb 2018 10:39:18 +0100 Subject: [PATCH 0388/2457] coreanalyzer: add spi2 support m-labs/artiq#926 --- artiq/coredevice/comm_analyzer.py | 54 +++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/artiq/coredevice/comm_analyzer.py b/artiq/coredevice/comm_analyzer.py index f4b2d56f0..d5be1fde2 100644 --- a/artiq/coredevice/comm_analyzer.py +++ b/artiq/coredevice/comm_analyzer.py @@ -344,6 +344,55 @@ class SPIMasterHandler(WishboneHandler): raise ValueError("bad address %d", address) +class SPIMaster2Handler(WishboneHandler): + def __init__(self, vcd_manager, name): + self._reads = [] + self.channels = {} + with vcd_manager.scope("spi2/{}".format(name)): + self.stb = vcd_manager.get_channel("{}/{}".format(name, "stb"), 1) + for reg_name, reg_width in [ + ("flags", 8), + ("length", 5), + ("div", 8), + ("chip_select", 8), + ("write", 32), + ("read", 32)]: + self.channels[reg_name] = vcd_manager.get_channel( + "{}/{}".format(name, reg_name), reg_width) + + def process_message(self, message): + self.stb.set_value("1") + self.stb.set_value("0") + data = message.data + if isinstance(message, OutputMessage): + address = message.address + if address == 1: + logger.debug("SPI config @%d data=0x%08x", + message.timestamp, data) + self.channels["chip_select"].set_value( + "{:08b}".format(data >> 24)) + self.channels["div"].set_value( + "{:08b}".format(data >> 16 & 0xff)) + self.channels["length"].set_value( + "{:08b}".format(data >> 8 & 0x1f)) + self.channels["flags"].set_value( + "{:08b}".format(data & 0xff)) + elif address == 0: + logger.debug("SPI write @%d data=0x%08x", + message.timestamp, data) + self.channels["write"].set_value("{:032b}".format(data)) + else: + raise ValueError("bad address", address) + # process untimed reads and insert them here + while self._reads[0].rtio_counter < message.timestamp: + read = self._reads.pop(0) + logger.debug("SPI read @%d data=0x%08x", + read.rtio_counter, read.data) + self.channels["read"].set_value("{:032b}".format(read.data)) + elif isinstance(message, InputMessage): + self._reads.append(message) + + def _extract_log_chars(data): r = "" for i in range(4): @@ -448,6 +497,11 @@ def create_channel_handlers(vcd_manager, devices, ref_period, channel = desc["arguments"]["channel"] channel_handlers[channel] = SPIMasterHandler( vcd_manager, name) + if (desc["module"] == "artiq.coredevice.spi2" and + desc["class"] == "SPIMaster"): + channel = desc["arguments"]["channel"] + channel_handlers[channel] = SPIMaster2Handler( + vcd_manager, name) return channel_handlers From d4a10dcbd4418491aa30cd8b57bfb2331c9c3fea Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 22 Feb 2018 10:27:19 +0000 Subject: [PATCH 0389/2457] urukul: fix example --- artiq/examples/kc705_nist_clock/repository/urukul.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/examples/kc705_nist_clock/repository/urukul.py b/artiq/examples/kc705_nist_clock/repository/urukul.py index 129daf0b7..86f432eb0 100644 --- a/artiq/examples/kc705_nist_clock/repository/urukul.py +++ b/artiq/examples/kc705_nist_clock/repository/urukul.py @@ -55,7 +55,9 @@ class UrukulTest(EnvExperiment): errors = 0 delay(100*us) while data != -1: + delay(20*us) self.urukul_ch0b.write32(0x07, data) + self.urukul_cpld.io_update.pulse(1*us) read = self.urukul_ch0b.read32(0x07) if read != data: errors += 1 From 8938b6955921a70906bb217dbca8ac23e95bf612 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 22 Feb 2018 12:45:22 +0000 Subject: [PATCH 0390/2457] conda: simplify recipes. conda-build appears to no longer require the workaround with environ.get("GIT_*", "") to work. --- conda/artiq-board/meta.yaml | 14 +++++++------- conda/artiq-dev/meta.yaml | 6 +++--- conda/artiq-sayma_rtm/meta.yaml | 10 +++++----- conda/artiq/meta.yaml | 6 +++--- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index 8662e90f5..d2ce3bdcf 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -1,6 +1,6 @@ package: - name: artiq-build - version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} + name: artiq-board + version: {{ environ["GIT_DESCRIBE_TAG"] }} source: git_url: ../.. @@ -8,20 +8,20 @@ source: build: noarch: python ignore_prefix_files: True - number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} - string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} + number: {{ environ["GIT_DESCRIBE_NUMBER"] }} + string: {{ environ["GIT_DESCRIBE_NUMBER"] }}+git{{ environ["GIT_FULL_HASH"][:8] }} script_env: - ARTIQ_TARGET - ARTIQ_VARIANT outputs: - - name: artiq-{{ environ.get("ARTIQ_TARGET") }}-{{ environ.get("ARTIQ_VARIANT") }} + - name: artiq-{{ environ["ARTIQ_TARGET"] }}-{{ environ["ARTIQ_VARIANT"] }} requirements: build: - - artiq-dev {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} + - artiq-dev {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} run: - - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} + - artiq {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} about: home: https://m-labs.hk/artiq diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 47e4deae4..a3eebabac 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -1,14 +1,14 @@ package: name: artiq-dev - version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} + version: {{ environ["GIT_DESCRIBE_TAG"] }} source: git_url: ../.. build: noarch: python - number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} - string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} + number: {{ environ["GIT_DESCRIBE_NUMBER"] }} + string: {{ environ["GIT_DESCRIBE_NUMBER"] }}+git{{ environ["GIT_FULL_HASH"][:8] }} requirements: run: diff --git a/conda/artiq-sayma_rtm/meta.yaml b/conda/artiq-sayma_rtm/meta.yaml index 0aed97148..0ef011026 100644 --- a/conda/artiq-sayma_rtm/meta.yaml +++ b/conda/artiq-sayma_rtm/meta.yaml @@ -1,6 +1,6 @@ package: name: artiq-sayma_rtm - version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} + version: {{ environ["GIT_DESCRIBE_TAG"] }} source: git_url: ../.. @@ -8,14 +8,14 @@ source: build: noarch: python ignore_prefix_files: True - number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} - string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} + number: {{ environ["GIT_DESCRIBE_NUMBER"] }} + string: {{ environ["GIT_DESCRIBE_NUMBER"] }}+git{{ environ["GIT_FULL_HASH"][:8] }} requirements: build: - - artiq-dev {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} + - artiq-dev {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} run: - - artiq {{ "{tag} py_{number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG"), number=environ.get("GIT_DESCRIBE_NUMBER"), hash=environ.get("GIT_FULL_HASH", "")[:8]) if "GIT_DESCRIBE_TAG" in environ else "" }} + - artiq {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} about: home: https://m-labs.hk/artiq diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index 727c07130..bbbaba571 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -1,6 +1,6 @@ package: name: artiq - version: {{ environ.get("GIT_DESCRIBE_TAG", "") }} + version: {{ environ["GIT_DESCRIBE_TAG"] }} source: git_url: ../.. @@ -9,8 +9,8 @@ source: build: noarch: python - number: {{ environ.get("GIT_DESCRIBE_NUMBER", 0) }} - string: py_{{ environ.get("GIT_DESCRIBE_NUMBER", 0) }}+git{{ environ.get("GIT_FULL_HASH", "")[:8] }} + number: {{ environ["GIT_DESCRIBE_NUMBER"] }} + string: {{ environ["GIT_DESCRIBE_NUMBER"] }}+git{{ environ["GIT_FULL_HASH"][:8] }} entry_points: # NOTE: conda-build cannot distinguish between console and gui scripts {% for entry_point_type, entry_points in data.get("entry_points", dict()).items() -%} From e8d21adf303f9b82feddf60ae20f306e2940a0fe Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 22 Feb 2018 12:55:47 +0000 Subject: [PATCH 0391/2457] conda: turn off binary prefix detection everywhere. This just adds garbage to logs and serves no useful purpose. --- conda/artiq-board/meta.yaml | 2 +- conda/artiq-sayma_rtm/meta.yaml | 2 +- conda/artiq/meta.yaml | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index d2ce3bdcf..93aeb6ec6 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -7,12 +7,12 @@ source: build: noarch: python - ignore_prefix_files: True number: {{ environ["GIT_DESCRIBE_NUMBER"] }} string: {{ environ["GIT_DESCRIBE_NUMBER"] }}+git{{ environ["GIT_FULL_HASH"][:8] }} script_env: - ARTIQ_TARGET - ARTIQ_VARIANT + detect_binary_files_with_prefix: False outputs: - name: artiq-{{ environ["ARTIQ_TARGET"] }}-{{ environ["ARTIQ_VARIANT"] }} diff --git a/conda/artiq-sayma_rtm/meta.yaml b/conda/artiq-sayma_rtm/meta.yaml index 0ef011026..89d0c371d 100644 --- a/conda/artiq-sayma_rtm/meta.yaml +++ b/conda/artiq-sayma_rtm/meta.yaml @@ -7,9 +7,9 @@ source: build: noarch: python - ignore_prefix_files: True number: {{ environ["GIT_DESCRIBE_NUMBER"] }} string: {{ environ["GIT_DESCRIBE_NUMBER"] }}+git{{ environ["GIT_FULL_HASH"][:8] }} + detect_binary_files_with_prefix: False requirements: build: diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index bbbaba571..f538f4b45 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -19,6 +19,7 @@ build: {% endfor %} {% endfor %} script: $PYTHON setup.py install --no-compile --single-version-externally-managed --record=record.txt + detect_binary_files_with_prefix: False requirements: build: From 21b1757bfd6848f920ae364f3887ade12b61896d Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 22 Feb 2018 13:26:42 +0000 Subject: [PATCH 0392/2457] Fix e8d21adf3. As usual, conda documentation does not provide a clear explanation of what the options do... --- conda/artiq-board/meta.yaml | 2 +- conda/artiq-sayma_rtm/meta.yaml | 2 +- conda/artiq/meta.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index 93aeb6ec6..e182bd0d0 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -12,7 +12,7 @@ build: script_env: - ARTIQ_TARGET - ARTIQ_VARIANT - detect_binary_files_with_prefix: False + ignore_prefix_files: True outputs: - name: artiq-{{ environ["ARTIQ_TARGET"] }}-{{ environ["ARTIQ_VARIANT"] }} diff --git a/conda/artiq-sayma_rtm/meta.yaml b/conda/artiq-sayma_rtm/meta.yaml index 89d0c371d..76e381ff5 100644 --- a/conda/artiq-sayma_rtm/meta.yaml +++ b/conda/artiq-sayma_rtm/meta.yaml @@ -9,7 +9,7 @@ build: noarch: python number: {{ environ["GIT_DESCRIBE_NUMBER"] }} string: {{ environ["GIT_DESCRIBE_NUMBER"] }}+git{{ environ["GIT_FULL_HASH"][:8] }} - detect_binary_files_with_prefix: False + ignore_prefix_files: True requirements: build: diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index f538f4b45..2e47dd909 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -19,7 +19,7 @@ build: {% endfor %} {% endfor %} script: $PYTHON setup.py install --no-compile --single-version-externally-managed --record=record.txt - detect_binary_files_with_prefix: False + ignore_prefix_files: True requirements: build: From 771bf87b562823ed06362137ba23f654cfa2f927 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 22 Feb 2018 10:55:50 +0000 Subject: [PATCH 0393/2457] kc705: port amc101_dac/spi0 and sma_spi to spi2 --- artiq/examples/kc705_nist_clock/device_db.py | 4 ++-- artiq/gateware/targets/kc705.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/examples/kc705_nist_clock/device_db.py b/artiq/examples/kc705_nist_clock/device_db.py index e8e0901f1..24958a56d 100644 --- a/artiq/examples/kc705_nist_clock/device_db.py +++ b/artiq/examples/kc705_nist_clock/device_db.py @@ -119,7 +119,7 @@ device_db = { # Generic SPI "spi0": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "SPIMaster", "arguments": {"channel": 23} }, @@ -161,7 +161,7 @@ device_db = { # DAC "spi_ams101": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "SPIMaster", "arguments": {"channel": 22} }, diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index e19ce222b..5d171f053 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -319,7 +319,7 @@ class NIST_CLOCK(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - phy = spi.SPIMaster(ams101_dac) + phy = spi2.SPIMaster(ams101_dac) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=4)) @@ -423,7 +423,7 @@ class NIST_QC2(_StandaloneBase): # add clock generators after TTLs rtio_channels += clock_generators - phy = spi.SPIMaster(ams101_dac) + phy = spi2.SPIMaster(ams101_dac) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=4)) @@ -478,12 +478,12 @@ class SMA_SPI(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - phy = spi.SPIMaster(ams101_dac) + phy = spi2.SPIMaster(ams101_dac) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=4)) - phy = spi.SPIMaster(self.platform.request("sma_spi")) + phy = spi2.SPIMaster(self.platform.request("sma_spi")) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=128)) From 3b7971d15d13eca71d4bc8cdf85f286fedf7e6f6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 22 Feb 2018 11:49:23 +0000 Subject: [PATCH 0394/2457] kasli: spelling --- artiq/gateware/targets/kasli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index f04032c8f..0af06ab38 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -187,7 +187,7 @@ def _novogorny(eem): IOStandard("LVDS_25") ) for i, j, sig in [ (5, eem, "conv"), - (6, eem, "bosy"), + (6, eem, "busy"), (7, eem, "scko"), ] ] From 74517107f07e7cb6653dcf7d67b6f7e94a067738 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 22 Feb 2018 11:49:37 +0000 Subject: [PATCH 0395/2457] ad9912: add slack after prodid read --- artiq/coredevice/ad9912.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 67549a74d..bc12192d6 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -97,7 +97,7 @@ class AD9912: prodid = self.read(AD9912_PRODIDH, length=2) if (prodid != 0x1982) and (prodid != 0x1902): raise ValueError("Urukul AD9912 product id mismatch") - delay(20*us) + delay(30*us) # HSTL power down, CMOS power down self.write(AD9912_PWRCNTRL1, 0x80, length=1) self.cpld.io_update.pulse(1*us) From 1452cd7447f234d808f004a6f79b9694ed407a32 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 22 Feb 2018 15:41:30 +0000 Subject: [PATCH 0396/2457] novogorny: add coredevice driver and test with Kasli m-labs/artiq#687 --- artiq/coredevice/novogorny.py | 174 ++++++++++++++++++++++++++ artiq/coredevice/spi2.py | 2 +- artiq/gateware/targets/kasli.py | 2 +- doc/manual/core_drivers_reference.rst | 6 + 4 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 artiq/coredevice/novogorny.py diff --git a/artiq/coredevice/novogorny.py b/artiq/coredevice/novogorny.py new file mode 100644 index 000000000..94e119973 --- /dev/null +++ b/artiq/coredevice/novogorny.py @@ -0,0 +1,174 @@ +from numpy import int32, int64 + +from artiq.language.core import kernel, delay, portable +from artiq.language.units import us, ns +from artiq.coredevice.ad9912_reg import * + +from artiq.coredevice import spi2 as spi +from artiq.coredevice import urukul + + +SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | + 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | + 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | + 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) + + +SPI_CS_ADC = 1 +SPI_CS_SR = 2 + + +@portable +def adc_ctrl(channel=1, softspan=0b111, valid=1): + """Build a LTC2335-16 control word""" + return (valid << 7) | (channel << 3) | softspan + + +@portable +def adc_softspan(data): + """Return the softspan configuration index from a result packet""" + return data & 0x7 + + +@portable +def adc_channel(data): + """Return the channel index from a result packet""" + return (data >> 3) & 0x7 + + +@portable +def adc_data(data): + """Return the ADC value from a result packet""" + return (data >> 8) & 0xffff + + +@portable +def adc_value(data, v_ref=5.): + """Convert a ADC result packet to SI units (Volt)""" + softspan = adc_softspan(data) + data = adc_data(data) + if softspan & 4: + g3 = 2 + else: + g3 = 1 + if softspan & 2: + g2 = 1 << 15 + else: + g2 = 1 << 16 + if softspan & 1: + g1 = 1000 + else: + g1 = 1023 + data = -(data & g2) + (data & ~g2) + v_per_lsb = v_ref*(1250*g3)/(g1*g2) + return data*v_per_lsb + + +class Novogorny: + """Novogorny ADC. + + Controls the LTC2335-16 8 channel ADC with SPI interface and + the switchable gain instrumentation amplifiers using a shift + register. + + :param spi_device: SPI bus device name + :param conv_device: CONV RTIO TTLOut channel name + :param div: SPI clock divider (default: 8) + :param core_device: Core device name + """ + kernel_invariants = {"bus", "core", "conv", "div", "v_ref"} + + def __init__(self, dmgr, spi_device, conv_device, div=8, + core_device="core"): + self.bus = dmgr.get(spi_device) + self.core = dmgr.get(core_device) + self.conv = dmgr.get(conv_device) + self.div = div + self.gains = 0x0000 + self.v_ref = 5. # 5 Volt reference + + @kernel + def set_gain_mu(self, channel, gain): + """Set instrumentation amplifier gain of a channel. + + The four gain settings (0, 1, 2, 3) corresponds to gains of + (1, 10, 100, 1000) respectively. + + :param channel: Channel index + :param gain: Gain setting + """ + self.gains &= ~(0b11 << (channel*2)) + self.gains |= gain << (channel*2) + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, + 2, self.div, SPI_CS_SR) + self.bus.write(self.gains << 16) + + @kernel + def configure(self, data): + """Set up the ADC sequencer. + + :param data: List of 8 bit control words to write into the sequencer + table. + """ + if len(data) > 1: + self.bus.set_config_mu(SPI_CONFIG, + 8, self.div, SPI_CS_ADC) + for i in range(len(data) - 1): + self.bus.write(data[i] << 24) + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, + 8, self.div, SPI_CS_ADC) + self.bus.write(data[len(data) - 1] << 24) + + @kernel + def sample_mu(self, next_ctrl=0): + """Acquire a sample: + + Perform a conversion and transfer the sample. + + :param next_ctrl: ADC control word for the next sample + :return: The ADC result packet (machine units) + """ + self.conv.pulse(40*ns) # t_CNVH + delay(560*ns) # t_CONV max + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, + 24, self.div, SPI_CS_ADC) + self.bus.write(next_ctrl << 24) + return self.bus.read() + + @kernel + def sample(self, next_ctrl=0): + """Acquire a sample + + .. seealso:: :meth:`sample_mu` + + :param next_ctrl: ADC control word for the next sample + :return: The ADC result packet (Volt) + """ + return adc_value(self.sample_mu(), self.v_ref) + + @kernel + def burst_mu(self, data, dt_mu, ctrl=0): + """Acquire a burst of samples. + + If the burst is too long and the sample rate too high, there will be + RTIO input overflows. + + High sample rates lead to gain errors since the impedance between the + instrumentation amplifier and the ADC is high. + + :param data: List of data values to write result packets into. + In machine units. + :param dt: Sample interval in machine units. + :param ctrl: ADC control word to write during each result packet + transfer. + """ + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, + 24, self.div, SPI_CS_ADC) + for i in range(len(data)): + t0 = now_mu() + self.conv.pulse(40*ns) # t_CNVH + delay(560*ns) # t_CONV max + self.bus.write(ctrl << 24) + at_mu(t0 + dt_mu) + for i in range(len(data)): + data[i] = self.bus.read() diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index 3bfdd5a20..ddf81d477 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -16,7 +16,7 @@ __all__ = [ "SPI_OFFLINE", "SPI_END", "SPI_INPUT", "SPI_CS_POLARITY", "SPI_CLK_POLARITY", "SPI_CLK_PHASE", "SPI_LSB_FIRST", "SPI_HALF_DUPLEX", - "SPIMaster", "NRTSPIMaster" + "SPIMaster" ] SPI_DATA_ADDR = 0 diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 0af06ab38..2ae020e03 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -269,7 +269,7 @@ class Opticlock(_StandaloneBase): phy = spi2.SPIMaster(self.platform.request("eem3_spi_p"), self.platform.request("eem3_spi_n")) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=16)) for signal in "conv".split(): pads = platform.request("eem3_{}".format(signal)) diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 003b8322d..a77244da2 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -75,6 +75,12 @@ These drivers are for the core device and the peripherals closely integrated int .. automodule:: artiq.coredevice.sawg :members: +:mod:`artiq.coredevice.novogorny` module +---------------------------------------- + +.. automodule:: artiq.coredevice.novogorny + :members: + :mod:`artiq.coredevice.urukul` module ------------------------------------- From bc5e949bb47daa0c9422b49e26ecd0490f1424f1 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 22 Feb 2018 18:45:55 +0000 Subject: [PATCH 0397/2457] novogorny: fix gain register length --- artiq/coredevice/novogorny.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/novogorny.py b/artiq/coredevice/novogorny.py index 94e119973..f5d3911fd 100644 --- a/artiq/coredevice/novogorny.py +++ b/artiq/coredevice/novogorny.py @@ -100,7 +100,7 @@ class Novogorny: self.gains &= ~(0b11 << (channel*2)) self.gains |= gain << (channel*2) self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, - 2, self.div, SPI_CS_SR) + 16, self.div, SPI_CS_SR) self.bus.write(self.gains << 16) @kernel From 820c834251e75c7f08f19d8aafb9a4ee41b09cd6 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 22 Feb 2018 22:13:29 +0100 Subject: [PATCH 0398/2457] drtio/transceiver/gth: implement tx multi lane phase alignment sequence --- .../drtio/transceiver/gth_ultrascale.py | 76 +++++++++++++++++-- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index 1e1a5a9e6..cde2b6705 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -1,5 +1,5 @@ from functools import reduce -from operator import or_ +from operator import or_, and_ from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer @@ -16,7 +16,18 @@ from artiq.gateware.drtio.transceiver.gth_ultrascale_init import * class GTHSingle(Module): def __init__(self, refclk, pads, sys_clk_freq, rtio_clk_freq, dw, mode): assert (dw == 20) or (dw == 40) - assert mode in ["master", "slave"] + assert mode in ["single", "master", "slave"] + self.mode = mode + + # phase alignment + self.txsyncallin = Signal() + self.txphaligndone = Signal() + self.txsyncallin = Signal() + self.txsyncin = Signal() + self.txsyncout = Signal() + self.txdlysreset = Signal() + + # # # nwords = dw//10 self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( @@ -96,11 +107,16 @@ class GTHSingle(Module): # TX Startup/Reset i_GTTXRESET=tx_init.gtXxreset, o_TXRESETDONE=tx_init.Xxresetdone, - i_TXDLYSRESET=tx_init.Xxdlysreset, + i_TXDLYSRESET=tx_init.Xxdlysreset if mode != "slave" else self.txdlysreset, o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone, o_TXPHALIGNDONE=tx_init.Xxphaligndone, i_TXUSERRDY=tx_init.Xxuserrdy, - i_TXSYNCMODE=1, + i_TXSYNCMODE=mode != "slave", + p_TXSYNC_MULTILANE=0 if mode == "single" else 1, + p_TXSYNC_OVRD=0, + i_TXSYNCALLIN=self.txsyncallin, + i_TXSYNCIN=self.txsyncin, + o_TXSYNCOUT=self.txsyncout, # TX data p_TX_DATA_WIDTH=dw, @@ -172,6 +188,7 @@ class GTHSingle(Module): o_GTHTXP=pads.txp, o_GTHTXN=pads.txn ) + self.comb += self.txphaligndone.eq(tx_init.Xxphaligndone) self.submodules += [ add_probe_async("drtio_gth", "cpll_lock", cpll_lock), @@ -221,6 +238,44 @@ class GTHSingle(Module): self.submodules += add_probe_async("drtio_gth", "clock_aligner_ready", clock_aligner.ready) +class GTHTXPhaseAlignement(Module): + # TX Buffer Bypass in Single-Lane/Multi-Lane Auto Mode (ug576) + def __init__(self, gths): + txsyncallin = Signal() + txsync = Signal() + txphaligndone = Signal(len(gths)) + txdlysreset = Signal() + ready_for_align = Signal(len(gths)) + all_ready_for_align = Signal() + + for i, gth in enumerate(gths): + # Common to all transceivers + self.comb += [ + ready_for_align[i].eq(1), + gth.txsyncin.eq(txsync), + gth.txsyncallin.eq(txsyncallin), + txphaligndone[i].eq(gth.txphaligndone) + ] + # Specific to Master or Single transceivers + if gth.mode == "master" or gth.mode == "single": + self.comb += [ + gth.tx_init.all_ready_for_align.eq(all_ready_for_align), + txsync.eq(gth.txsyncout), + txdlysreset.eq(gth.tx_init.Xxdlysreset) + ] + # Specific to Slave transceivers + else: + self.comb += [ + ready_for_align[i].eq(gth.tx_init.ready_for_align), + gth.txdlysreset.eq(txdlysreset), + ] + + self.comb += [ + txsyncallin.eq(reduce(and_, [txphaligndone[i] for i in range(len(gths))])), + all_ready_for_align.eq(reduce(and_, [ready_for_align[i] for i in range(len(gths))])) + ] + + class GTH(Module, TransceiverInterface): def __init__(self, clock_pads, data_pads, sys_clk_freq, rtio_clk_freq, dw=20, master=0): self.nchannels = nchannels = len(data_pads) @@ -238,18 +293,23 @@ class GTH(Module, TransceiverInterface): rtio_tx_clk = Signal() channel_interfaces = [] for i in range(nchannels): - mode = "master" if i == master else "slave" - gth = GTHSingle(refclk, data_pads[i], sys_clk_freq, rtio_clk_freq, dw, mode) - if mode == "master": - self.comb += rtio_tx_clk.eq(gth.cd_rtio_tx.clk) + if nchannels == 1: + mode = "single" else: + mode = "master" if i == master else "slave" + gth = GTHSingle(plls[i], tx_pads[i], rx_pads[i], sys_clk_freq, dw, mode) + if mode == "slave": self.comb += gth.cd_rtio_tx.clk.eq(rtio_tx_clk) + else: + self.comb += rtio_tx_clk.eq(gth.cd_rtio_tx.clk) self.gths.append(gth) setattr(self.submodules, "gth"+str(i), gth) channel_interface = ChannelInterface(gth.encoder, gth.decoders) self.comb += channel_interface.rx_ready.eq(gth.rx_ready) channel_interfaces.append(channel_interface) + self.submodules.tx_phase_alignment = GTHTXPhaseAlignement(self.gths) + TransceiverInterface.__init__(self, channel_interfaces) # GTH PLLs recover on their own from an interrupted clock input. # stable_clkin can be ignored. From b4ba71c7a4a05908ecc0f862accf036034cd8365 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 23 Feb 2018 08:37:05 +0100 Subject: [PATCH 0399/2457] drtio/transceiver/gth: implement tx multi lane phase alignment sequence (fix merge issue...) --- .../drtio/transceiver/gth_ultrascale.py | 6 ++-- .../drtio/transceiver/gth_ultrascale_init.py | 30 ++++++++++++++----- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index cde2b6705..735bfa970 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -44,10 +44,10 @@ class GTHSingle(Module): # # # # TX generates RTIO clock, init must be in system domain - tx_init = GTHInit(sys_clk_freq, False) + self.submodules.tx_init = tx_init = GTHInit(sys_clk_freq, False) # RX receives restart commands from RTIO domain rx_init = ClockDomainsRenamer("rtio_tx")(GTHInit(rtio_clk_freq, True)) - self.submodules += tx_init, rx_init + self.submodules += rx_init cpll_reset = Signal() cpll_lock = Signal() @@ -297,7 +297,7 @@ class GTH(Module, TransceiverInterface): mode = "single" else: mode = "master" if i == master else "slave" - gth = GTHSingle(plls[i], tx_pads[i], rx_pads[i], sys_clk_freq, dw, mode) + gth = GTHSingle(refclk, data_pads[i], sys_clk_freq, rtio_clk_freq, dw, mode) if mode == "slave": self.comb += gth.cd_rtio_tx.clk.eq(rtio_tx_clk) else: diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py b/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py index 8d188f6c0..2a5799ded 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py @@ -9,7 +9,8 @@ __all__ = ["GTHInit"] class GTHInit(Module): - def __init__(self, sys_clk_freq, rx): + def __init__(self, sys_clk_freq, rx, mode="master"): + assert not (rx and mode != "master") self.done = Signal() self.restart = Signal() @@ -24,6 +25,9 @@ class GTHInit(Module): self.Xxsyncdone = Signal() self.Xxuserrdy = Signal() + self.all_ready_for_align = Signal(reset=1) + self.ready_for_align = Signal() + # # # # Double-latch transceiver asynch outputs @@ -98,13 +102,21 @@ class GTHInit(Module): else: startup_fsm.act("RELEASE_GTH_RESET", Xxuserrdy.eq(1), - If(Xxresetdone, NextState("ALIGN")) + If(Xxresetdone, + If(mode == "slave", + NextState("WAIT_ALIGN") + ).Else( + NextState("ALIGN") + ) + ) ) # Start delay alignment (pulse) startup_fsm.act("ALIGN", Xxuserrdy.eq(1), - Xxdlysreset.eq(1), - NextState("WAIT_ALIGN") + If(self.all_ready_for_align, + Xxdlysreset.eq(1), + NextState("WAIT_ALIGN") + ) ) if rx: # Wait for delay alignment @@ -119,7 +131,11 @@ class GTHInit(Module): startup_fsm.act("WAIT_ALIGN", Xxuserrdy.eq(1), If(Xxdlysresetdone, - NextState("WAIT_FIRST_ALIGN_DONE") + If(mode == "slave", + NextState("WAIT_LAST_ALIGN_DONE") + ).Else( + NextState("WAIT_FIRST_ALIGN_DONE") + ) ) ) @@ -127,9 +143,9 @@ class GTHInit(Module): # (from UG576 in TX Buffer Bypass in Single-Lane Auto Mode) startup_fsm.act("WAIT_FIRST_ALIGN_DONE", Xxuserrdy.eq(1), - If(Xxphaligndone_rising, NextState("WAIT_SECOND_ALIGN_DONE")) + If(Xxphaligndone_rising, NextState("WAIT_LAST_ALIGN_DONE")) ) - startup_fsm.act("WAIT_SECOND_ALIGN_DONE", + startup_fsm.act("WAIT_LAST_ALIGN_DONE", Xxuserrdy.eq(1), If(Xxphaligndone_rising, NextState("READY")) ) From cff85ee13b0f144d420745921b8accaa80efcb0f Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 22 Feb 2018 23:08:50 +0100 Subject: [PATCH 0400/2457] novogorny: simplify and fix coefficient --- artiq/coredevice/novogorny.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/artiq/coredevice/novogorny.py b/artiq/coredevice/novogorny.py index f5d3911fd..8892073af 100644 --- a/artiq/coredevice/novogorny.py +++ b/artiq/coredevice/novogorny.py @@ -47,20 +47,19 @@ def adc_value(data, v_ref=5.): """Convert a ADC result packet to SI units (Volt)""" softspan = adc_softspan(data) data = adc_data(data) + g = 625 if softspan & 4: - g3 = 2 - else: - g3 = 1 + g *= 2 if softspan & 2: - g2 = 1 << 15 + h = 1 << 15 else: - g2 = 1 << 16 + h = 1 << 16 + data = -(data & h) + (data & ~h) if softspan & 1: - g1 = 1000 + h *= 500 else: - g1 = 1023 - data = -(data & g2) + (data & ~g2) - v_per_lsb = v_ref*(1250*g3)/(g1*g2) + h *= 512 + v_per_lsb = v_ref*g/h return data*v_per_lsb From 5b0f9cc6fd3aa91cd4b2eb70f3c97a38960cbf6a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 23 Feb 2018 12:15:47 +0100 Subject: [PATCH 0401/2457] drtio/transceiver/gth: fix single transceiver case --- artiq/gateware/drtio/transceiver/gth_ultrascale.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index 735bfa970..55e81ab47 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -205,7 +205,7 @@ class GTHSingle(Module): tx_reset_deglitched.attr.add("no_retiming") self.sync += tx_reset_deglitched.eq(~tx_init.done) self.clock_domains.cd_rtio_tx = ClockDomain() - if mode == "master": + if mode == "master" or mode == "single": self.specials += \ Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk, i_DIV=0) self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched) From 98489d97399f2eee16b271113b910be4ce6850c7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 23 Feb 2018 21:46:51 +0800 Subject: [PATCH 0402/2457] conda: bump migen/misoc (#854) --- conda/artiq-dev/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index a3eebabac..274d3e0d1 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,8 +14,8 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_4+git9c3a301 - - misoc 0.9 py35_11+git10062189 + - migen 0.7 py35_8+giteeccd1a + - misoc 0.9 py35_14+gitd26c07ae - jesd204b 0.4 - microscope - binutils-or1k-linux >=2.27 From ddb3d2fe14e4bf4d60de00c4f3f8ca1aaeaa1ba0 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 23 Feb 2018 15:16:14 +0100 Subject: [PATCH 0403/2457] DEVELOPER_NOTES: fix devtool autodoc --- DEVELOPER_NOTES.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEVELOPER_NOTES.rst b/DEVELOPER_NOTES.rst index a8a078424..9ea07f4bd 100644 --- a/DEVELOPER_NOTES.rst +++ b/DEVELOPER_NOTES.rst @@ -71,8 +71,8 @@ Using developer tools ARTIQ ships with an ``artiq_devtool`` binary, which automates common actions arising when developing the board gateware and firmware on a machine other than the one to which the board is connected. .. argparse:: - :ref: artiq.frontend.artiq_compile.get_argparser - :prog: artiq_compile + :ref: artiq.frontend.artiq_devtool.get_argparser + :prog: artiq_devtool To build and flash the firmware for ``sayma_amc_standalone`` target: :: From b466a569bf49e50559234209f9f42032df50e89b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 24 Feb 2018 09:49:31 +0100 Subject: [PATCH 0404/2457] coredevice: export spi2 --- artiq/coredevice/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/__init__.py b/artiq/coredevice/__init__.py index 0a1a4de6c..2d0e7d27a 100644 --- a/artiq/coredevice/__init__.py +++ b/artiq/coredevice/__init__.py @@ -1,4 +1,4 @@ -from artiq.coredevice import exceptions, dds, spi +from artiq.coredevice import exceptions, dds, spi, spi2 from artiq.coredevice.exceptions import (RTIOUnderflow, RTIOOverflow) from artiq.coredevice.dds import (PHASE_MODE_CONTINUOUS, PHASE_MODE_ABSOLUTE, PHASE_MODE_TRACKING) From 760724c500db67a39eda21c2402b8f8043bbc99c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 26 Feb 2018 11:37:12 +0100 Subject: [PATCH 0405/2457] kasli/device_db: fix i2c switch addr --- artiq/examples/kasli_opticlock/device_db.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/examples/kasli_opticlock/device_db.py b/artiq/examples/kasli_opticlock/device_db.py index 773962d73..7f8478bbe 100644 --- a/artiq/examples/kasli_opticlock/device_db.py +++ b/artiq/examples/kasli_opticlock/device_db.py @@ -31,13 +31,13 @@ device_db = { "type": "local", "module": "artiq.coredevice.i2c", "class": "PCA9548", - "arguments": {"address": 0x70} + "arguments": {"address": 0xe0} }, "i2c_switch1": { "type": "local", "module": "artiq.coredevice.i2c", "class": "PCA9548", - "arguments": {"address": 0x71} + "arguments": {"address": 0xe2} }, "ttl0": { From a35e4fe0554fd0367bf2c47470ed5f3351d3c9e7 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 26 Feb 2018 12:48:48 +0100 Subject: [PATCH 0406/2457] conda: bump jesd204b-0.5 --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 274d3e0d1..bbde80b94 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -16,7 +16,7 @@ requirements: - setuptools 33.1.1 - migen 0.7 py35_8+giteeccd1a - misoc 0.9 py35_14+gitd26c07ae - - jesd204b 0.4 + - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27 - llvm-or1k 4.0.1 From 1de2da5644359e81574bd6f64a6b34eb2f440324 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 26 Feb 2018 14:16:05 +0100 Subject: [PATCH 0407/2457] conda: bump migen/misoc --- conda/artiq-dev/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index bbde80b94..7d50b6684 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,8 +14,8 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_8+giteeccd1a - - misoc 0.9 py35_14+gitd26c07ae + - migen 0.7 py35_10+git0996e0b + - misoc 0.9 py35_20+git5fed1095 - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27 From e565d3fa59a1f5e206186c6ad400c55be48dad0f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 27 Feb 2018 18:09:07 +0800 Subject: [PATCH 0408/2457] kasli: add analyzer and RTIO log to DRTIO master target --- artiq/gateware/targets/kasli.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 2ae020e03..9fc71ccde 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -372,6 +372,9 @@ class Master(MiniSoC, AMPSoC): phy = ttl_simple.Output(platform.request("sfp_ctl", 1).led) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) + rtio_channels.append(rtio.LogChannel()) self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") @@ -389,6 +392,10 @@ class Master(MiniSoC, AMPSoC): [self.rtio_core.cri, self.drtio0.cri]) self.register_kernel_cpu_csrdevice("cri_con") + self.submodules.rtio_analyzer = rtio.Analyzer(self.cri_con.switch.slave, + self.get_native_sdram_if()) + self.csr_devices.append("rtio_analyzer") + # Never running out of stupid features, GTs on A7 make you pack # unrelated transceiver PLLs into one GTPE2_COMMON yourself. def create_qpll(self): From 1f0d955ce4a6aa1f21e7d33a93c1d300bced04e2 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 27 Feb 2018 12:32:25 +0100 Subject: [PATCH 0409/2457] drtio/transceiver/gtp: implement tx multi lane phase alignment sequence --- .../gateware/drtio/transceiver/gtp_7series.py | 50 ++++++++++++++----- .../drtio/transceiver/gtp_7series_init.py | 44 ++++++++++++++-- 2 files changed, 77 insertions(+), 17 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py index 62d2728ef..98360ca2d 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -13,8 +13,10 @@ from artiq.gateware.drtio.transceiver.gtp_7series_init import * class GTPSingle(Module): def __init__(self, qpll_channel, pads, sys_clk_freq, rtio_clk_freq, mode): - if mode != "master": - raise NotImplementedError + assert mode in ["single", "master", "slave"] + self.mode = mode + + # # # self.stable_clkin = Signal() self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( @@ -31,10 +33,10 @@ class GTPSingle(Module): # # # # TX generates RTIO clock, init must be in system domain - tx_init = GTPTXInit(sys_clk_freq) + self.submodules.tx_init = tx_init = GTPTXInit(sys_clk_freq, mode) # RX receives restart commands from RTIO domain rx_init = ClockDomainsRenamer("rtio_tx")(GTPRXInit(rtio_clk_freq)) - self.submodules += tx_init, rx_init + self.submodules += rx_init self.comb += [ tx_init.stable_clkin.eq(self.stable_clkin), @@ -353,7 +355,7 @@ class GTPSingle(Module): # TX Buffer Attributes p_TXSYNC_MULTILANE =0b0, - p_TXSYNC_OVRD =0b0, + p_TXSYNC_OVRD =0b1, p_TXSYNC_SKIP_DA =0b0 ) gtp_params.update( @@ -438,7 +440,7 @@ class GTPSingle(Module): #o_RXNOTINTABLE =, # Receive Ports - RX AFE Ports i_GTPRXN =pads.rxn, - i_GTPRXP =pads.rxp, + i_GTPRXP =pads.rxp, i_PMARSVDIN2 =0b0, #o_PMARSVDOUT0 =, #o_PMARSVDOUT1 =, @@ -667,7 +669,7 @@ class GTPSingle(Module): tx_reset_deglitched.attr.add("no_retiming") self.sync += tx_reset_deglitched.eq(~tx_init.done) self.clock_domains.cd_rtio_tx = ClockDomain() - if mode == "master": + if mode == "master" or mode == "single": self.specials += Instance("BUFG", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk) self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched) @@ -698,30 +700,52 @@ class GTPSingle(Module): ] +class GTPTXPhaseAlignement(Module): + # TX Buffer Bypass in Single-Lane/Multi-Lane Auto Mode (ug482) + def __init__(self, gtps): + master_phaligndone = Signal() + slaves_phaligndone = Signal(reset=1) + # Specific to Slave transceivers + for gtp in gtps: + if gtp.mode == "slave": + self.comb += gtp.tx_init.master_phaligndone.eq(master_phaligndone) + slaves_phaligndone = slaves_phaligndone & gtp.tx_init.done + # Specific to Master transceivers + for gtp in gtps: + if gtp.mode == "master": + self.comb += [ + master_phaligndone.eq(gtp.tx_init.master_phaligndone), + gtp.tx_init.slaves_phaligndone.eq(slaves_phaligndone) + ] + + class GTP(Module, TransceiverInterface): def __init__(self, qpll_channel, data_pads, sys_clk_freq, rtio_clk_freq, master=0): self.nchannels = nchannels = len(data_pads) self.gtps = [] - if nchannels > 1: - raise NotImplementedError # # # rtio_tx_clk = Signal() channel_interfaces = [] for i in range(nchannels): - mode = "master" if i == master else "slave" - gtp = GTPSingle(qpll_channel, data_pads[i], sys_clk_freq, rtio_clk_freq, mode) - if mode == "master": - self.comb += rtio_tx_clk.eq(gtp.cd_rtio_tx.clk) + if nchannels == 1: + mode = "single" else: + mode = "master" if i == master else "slave" + gtp = GTPSingle(qpll_channel, data_pads[i], sys_clk_freq, rtio_clk_freq, mode) + if mode == "slave": self.comb += gtp.cd_rtio_tx.clk.eq(rtio_tx_clk) + else: + self.comb += rtio_tx_clk.eq(gtp.cd_rtio_tx.clk) self.gtps.append(gtp) setattr(self.submodules, "gtp"+str(i), gtp) channel_interface = ChannelInterface(gtp.encoder, gtp.decoders) self.comb += channel_interface.rx_ready.eq(gtp.rx_ready) channel_interfaces.append(channel_interface) + self.submodules.tx_phase_alignment = GTPTXPhaseAlignement(self.gtps) + TransceiverInterface.__init__(self, channel_interfaces) for gtp in self.gtps: self.comb += gtp.stable_clkin.eq(self.stable_clkin.storage) diff --git a/artiq/gateware/drtio/transceiver/gtp_7series_init.py b/artiq/gateware/drtio/transceiver/gtp_7series_init.py index 18b7a08a4..8916c2c36 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series_init.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series_init.py @@ -9,7 +9,7 @@ __all__ = ["GTPTXInit", "GTPRXInit"] class GTPTXInit(Module): - def __init__(self, sys_clk_freq): + def __init__(self, sys_clk_freq, mode="single"): self.stable_clkin = Signal() self.done = Signal() self.restart = Signal() @@ -29,6 +29,9 @@ class GTPTXInit(Module): self.txdlyen = Signal() self.txuserrdy = Signal() + self.master_phaligndone = Signal() + self.slaves_phaligndone = Signal() + # # # # Double-latch transceiver asynch outputs @@ -106,6 +109,16 @@ class GTPTXInit(Module): txuserrdy.eq(1), txdlysreset.eq(1), If(txdlysresetdone, + If(mode == "slave", + NextState("WAIT_MASTER") + ).Else( + NextState("PHALIGN") + ) + ) + ) + startup_fsm.act("WAIT_MASTER", + txuserrdy.eq(1), + If(self.master_phaligndone, NextState("PHALIGN") ) ) @@ -117,16 +130,39 @@ class GTPTXInit(Module): NextState("WAIT_FIRST_ALIGN_DONE") ) ) - # Wait 2 rising edges of Xxphaligndone - # (from UG482 in TX Buffer Bypass in Single-Lane Auto Mode) + # Wait N rising edges of Xxphaligndone + # N=2 for Single, 3 for Master, 1 for Slave + # (from UGB482 in TX Buffer Bypass in Multi/Single-Lane Auto Mode) startup_fsm.act("WAIT_FIRST_ALIGN_DONE", txuserrdy.eq(1), txphalign.eq(1), If(txphaligndone_rising, - NextState("WAIT_SECOND_ALIGN_DONE") + If(mode == "slave", + NextState("READY") + ).Else( + NextState("WAIT_SECOND_ALIGN_DONE") + ) ) ) startup_fsm.act("WAIT_SECOND_ALIGN_DONE", + txuserrdy.eq(1), + txdlyen.eq(1), + If(txphaligndone_rising, + If(mode == "master", + NextState("WAIT_SLAVES") + ).Else( + NextState("READY") + ) + ) + ) + startup_fsm.act("WAIT_SLAVES", + txuserrdy.eq(1), + self.master_phaligndone.eq(1), + If(self.slaves_phaligndone, + NextState("WAIT_THIRD_ALIGN_DONE") + ) + ) + startup_fsm.act("WAIT_THIRD_ALIGN_DONE", txuserrdy.eq(1), txdlyen.eq(1), If(txphaligndone_rising, From 771ba66055ddd3a01b24f7371a3cc3db1c983f83 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 27 Feb 2018 13:39:48 +0000 Subject: [PATCH 0410/2457] conda: include all files in output package. --- conda/artiq-board/meta.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index e182bd0d0..181d84842 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -16,6 +16,7 @@ build: outputs: - name: artiq-{{ environ["ARTIQ_TARGET"] }}-{{ environ["ARTIQ_VARIANT"] }} + files: * requirements: build: From 2f9d01295c23877430b4b2490ec74230f1491d4c Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 27 Feb 2018 14:03:50 +0000 Subject: [PATCH 0411/2457] conda: fix YAML syntax. --- conda/artiq-board/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index 181d84842..8e8454bb7 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -16,7 +16,7 @@ build: outputs: - name: artiq-{{ environ["ARTIQ_TARGET"] }}-{{ environ["ARTIQ_VARIANT"] }} - files: * + files: '*' requirements: build: From 5d81877b34f443ac4aa234785a5bc81b178d8c36 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 27 Feb 2018 23:15:20 +0800 Subject: [PATCH 0412/2457] kasli: implement multi-link DRTIO on SFP1 and SFP2 of master --- artiq/gateware/targets/kasli.py | 43 ++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 9fc71ccde..9e5aa0281 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -337,25 +337,39 @@ class Master(MiniSoC, AMPSoC): self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - self.comb += platform.request("sfp_ctl", 2).tx_disable.eq(0) + sfp_ctl = [platform.request("sfp_ctl", i) for i in range(1, 3)] + self.comb += [sc.tx_disable.eq(0) for sc in sfp_ctl] self.submodules.drtio_transceiver = gtp_7series.GTP( qpll_channel=self.drtio_qpll_channel, - data_pads=[platform.request("sfp", 2)], + data_pads=[platform.request("sfp", i) for i in range(1, 3)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") self.sync += self.disable_si5324_ibuf.eq( ~self.drtio_transceiver.stable_clkin.storage) - self.submodules.drtio0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"})( - DRTIOMaster(self.drtio_transceiver.channels[0])) - self.csr_devices.append("drtio0") - self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, - self.drtio0.aux_controller.bus) - self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) + drtio_csr_group = [] + drtio_memory_group = [] + drtio_cri = [] + for i in range(2): + core_name = "drtio" + str(i) + memory_name = "drtio" + str(i) + "_aux" + drtio_csr_group.append(core_name) + drtio_memory_group.append(memory_name) + + core = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)})( + DRTIOMaster(self.drtio_transceiver.channels[i])) + setattr(self.submodules, core_name, core) + drtio_cri.append(core.cri) + self.csr_devices.append(core_name) + + memory_address = self.mem_map["drtio_aux"] + 0x800*i + self.add_wb_slave(memory_address, 0x800, + core.aux_controller.bus) + self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None - self.add_csr_group("drtio", ["drtio0"]) - self.add_memory_group("drtio_aux", ["drtio0_aux"]) + self.add_csr_group("drtio", drtio_csr_group) + self.add_memory_group("drtio_aux", drtio_memory_group) rtio_clk_period = 1e9/rtio_clk_freq for gtp in self.drtio_transceiver.gtps: @@ -369,9 +383,10 @@ class Master(MiniSoC, AMPSoC): phy = ttl_simple.Output(platform.request("user_led", 0)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - phy = ttl_simple.Output(platform.request("sfp_ctl", 1).led) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + for sc in sfp_ctl: + phy = ttl_simple.Output(sc.led) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) @@ -389,7 +404,7 @@ class Master(MiniSoC, AMPSoC): self.register_kernel_cpu_csrdevice("rtio_dma") self.submodules.cri_con = rtio.CRIInterconnectShared( [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri, self.drtio0.cri]) + [self.rtio_core.cri] + drtio_cri) self.register_kernel_cpu_csrdevice("cri_con") self.submodules.rtio_analyzer = rtio.Analyzer(self.cri_con.switch.slave, From 386aa75aaaa1d7813fb3ba688420f5e7eb1b9a74 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 27 Feb 2018 23:18:18 +0800 Subject: [PATCH 0413/2457] kasli: control SFP1 and SFP2 LEDs in DRTIO satellite to match master --- artiq/gateware/targets/kasli.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 9e5aa0281..5855664d3 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -465,9 +465,10 @@ class Satellite(BaseSoC): phy = ttl_simple.Output(platform.request("user_led", 0)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - phy = ttl_simple.Output(platform.request("sfp_ctl", 1).led) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + for i in range(1, 3): + phy = ttl_simple.Output(platform.request("sfp_ctl", i).led) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") From b81855cce7b4e93af228d8589463611282c27205 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 27 Feb 2018 16:06:34 +0000 Subject: [PATCH 0414/2457] conda: don't use globs in file list. --- conda/artiq-board/meta.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index 8e8454bb7..4ed3bc3a1 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -16,7 +16,8 @@ build: outputs: - name: artiq-{{ environ["ARTIQ_TARGET"] }}-{{ environ["ARTIQ_VARIANT"] }} - files: '*' + files: + - lib requirements: build: From 916b10ca943a55de68118106029cb9431a2718b2 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 27 Feb 2018 18:36:45 +0000 Subject: [PATCH 0415/2457] =?UTF-8?q?examples:=20spi=20=E2=86=92=20spi2.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- artiq/examples/master/device_db.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/examples/master/device_db.py b/artiq/examples/master/device_db.py index 44cf3d72f..2ea42eac6 100644 --- a/artiq/examples/master/device_db.py +++ b/artiq/examples/master/device_db.py @@ -120,13 +120,13 @@ device_db = { # Generic SPI "spi0": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "SPIMaster", "arguments": {"channel": 23} }, "spi_mmc": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "SPIMaster", "arguments": {"channel": 26} }, From f97163cdeef384b2810871f78b0dc2b35f0e4857 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 27 Feb 2018 19:37:42 +0100 Subject: [PATCH 0416/2457] examples/master: sync device_db with kc705_nist_clock --- artiq/examples/master/device_db.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/artiq/examples/master/device_db.py b/artiq/examples/master/device_db.py index 2ea42eac6..268a84159 100644 --- a/artiq/examples/master/device_db.py +++ b/artiq/examples/master/device_db.py @@ -162,7 +162,7 @@ device_db = { # DAC "spi_ams101": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "SPIMaster", "arguments": {"channel": 22} }, @@ -174,7 +174,7 @@ device_db = { }, "spi_zotino": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "SPIMaster", "arguments": {"channel": 30} }, @@ -188,12 +188,17 @@ device_db = { "type": "local", "module": "artiq.coredevice.ad5360", "class": "AD5360", - "arguments": {"spi_device": "spi_zotino", "ldac_device": "ttl_zotino_ldac"} + "arguments": { + "spi_device": "spi_zotino", + "ldac_device": "ttl_zotino_ldac", + "div_write": 30, + "div_read": 40 + } }, "spi_urukul": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "SPIMaster", "arguments": {"channel": 32} }, From 5046d6a529cbd432ffa58afa6db462f9e68d58d1 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 26 Feb 2018 18:53:39 +0000 Subject: [PATCH 0417/2457] ad9912/10: add a bit more slack to init() --- artiq/coredevice/ad9910.py | 6 +++--- artiq/coredevice/ad9912.py | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index ff2c35070..06ddfee67 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -132,15 +132,15 @@ class AD9910: """ # Set SPI mode self.write32(_AD9910_REG_CFR1, 0x00000002) - self.cpld.io_update.pulse(1*us) + self.cpld.io_update.pulse(2*us) # Use the AUX DAC setting to identify and confirm presence aux_dac = self.read32(_AD9910_REG_AUX_DAC) if aux_dac & 0xff != 0x7f: raise ValueError("Urukul AD9910 AUX_DAC mismatch") - delay(20*us) # slack + delay(50*us) # slack # Configure PLL settings and bring up PLL self.write32(_AD9910_REG_CFR2, 0x01400020) - self.cpld.io_update.pulse(1*us) + self.cpld.io_update.pulse(2*us) cfr3 = (0x0807c100 | (self.pll_vco << 24) | (self.pll_cp << 19) | (self.pll_n << 1)) self.write32(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index bc12192d6..fbf116e05 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -92,20 +92,20 @@ class AD9912: """ # SPI mode self.write(AD9912_SER_CONF, 0x99, length=1) - self.cpld.io_update.pulse(1*us) + self.cpld.io_update.pulse(2*us) # Verify chip ID and presence prodid = self.read(AD9912_PRODIDH, length=2) if (prodid != 0x1982) and (prodid != 0x1902): raise ValueError("Urukul AD9912 product id mismatch") - delay(30*us) + delay(50*us) # HSTL power down, CMOS power down self.write(AD9912_PWRCNTRL1, 0x80, length=1) - self.cpld.io_update.pulse(1*us) + self.cpld.io_update.pulse(2*us) self.write(AD9912_N_DIV, self.pll_n//2 - 2, length=1) - self.cpld.io_update.pulse(1*us) + self.cpld.io_update.pulse(2*us) # I_cp = 375 µA, VCO high range self.write(AD9912_PLLCFG, 0b00000101, length=1) - self.cpld.io_update.pulse(1*us) + self.cpld.io_update.pulse(2*us) @kernel def set_att_mu(self, att): From 2896dc619bf3aa350595d04f3e1841c47349fbb8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 28 Feb 2018 14:15:40 +0100 Subject: [PATCH 0418/2457] drtio/transceiver/gth: fix multilane --- artiq/gateware/drtio/transceiver/gth_ultrascale.py | 8 ++++---- artiq/gateware/drtio/transceiver/gth_ultrascale_init.py | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index 55e81ab47..f05f1d626 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -44,7 +44,7 @@ class GTHSingle(Module): # # # # TX generates RTIO clock, init must be in system domain - self.submodules.tx_init = tx_init = GTHInit(sys_clk_freq, False) + self.submodules.tx_init = tx_init = GTHInit(sys_clk_freq, False, mode) # RX receives restart commands from RTIO domain rx_init = ClockDomainsRenamer("rtio_tx")(GTHInit(rtio_clk_freq, True)) self.submodules += rx_init @@ -298,10 +298,10 @@ class GTH(Module, TransceiverInterface): else: mode = "master" if i == master else "slave" gth = GTHSingle(refclk, data_pads[i], sys_clk_freq, rtio_clk_freq, dw, mode) - if mode == "slave": - self.comb += gth.cd_rtio_tx.clk.eq(rtio_tx_clk) - else: + if mode == "master": self.comb += rtio_tx_clk.eq(gth.cd_rtio_tx.clk) + elif mode == "slave": + self.comb += gth.cd_rtio_tx.clk.eq(rtio_tx_clk) self.gths.append(gth) setattr(self.submodules, "gth"+str(i), gth) channel_interface = ChannelInterface(gth.encoder, gth.decoders) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py b/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py index 2a5799ded..1edd76f34 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py @@ -130,6 +130,7 @@ class GTHInit(Module): # Wait for delay alignment startup_fsm.act("WAIT_ALIGN", Xxuserrdy.eq(1), + self.ready_for_align.eq(1), If(Xxdlysresetdone, If(mode == "slave", NextState("WAIT_LAST_ALIGN_DONE") From f95fb273f145a42d5e7d4ec3008a4f1fdb8f1901 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 28 Feb 2018 16:46:23 +0000 Subject: [PATCH 0419/2457] firmware: Sayma RTM FPGA bitstream loading prototype (#813). --- artiq/firmware/libboard_artiq/lib.rs | 3 +- artiq/firmware/libboard_artiq/rtm_fpga.rs | 46 +++++++++++++++++++++++ artiq/firmware/runtime/main.rs | 12 ++++-- artiq/frontend/artiq_flash.py | 30 +++++++++++---- 4 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 artiq/firmware/libboard_artiq/rtm_fpga.rs diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 127a55db8..a0f1a5c8a 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -1,4 +1,3 @@ -#![feature(asm, lang_items)] #![no_std] #[macro_use] @@ -25,3 +24,5 @@ mod ad9154_reg; pub mod ad9154; #[cfg(has_allaki_atts)] pub mod hmc542; +#[cfg(has_rtm_fpga_cfg)] +pub mod rtm_fpga; diff --git a/artiq/firmware/libboard_artiq/rtm_fpga.rs b/artiq/firmware/libboard_artiq/rtm_fpga.rs new file mode 100644 index 000000000..88fc6730e --- /dev/null +++ b/artiq/firmware/libboard_artiq/rtm_fpga.rs @@ -0,0 +1,46 @@ +use core::slice; +use board::csr::rtm_fpga_cfg; +use board::clock; + +const ADDR: *const u8 = 0x150000 as *const u8; + +pub fn program_bitstream() -> Result<(), ()> { + unsafe { + let length = *(ADDR as *const usize); + let bitstream = slice::from_raw_parts(ADDR.offset(4) as *const u32, length / 4); + + debug!("resetting"); + + rtm_fpga_cfg::divisor_write(15); + rtm_fpga_cfg::program_write(1); + clock::spin_us(1000); + rtm_fpga_cfg::program_write(0); + clock::spin_us(1000); + + while rtm_fpga_cfg::error_read() != 0 {} + + debug!("programming"); + + for word in bitstream { + rtm_fpga_cfg::data_write(*word); + rtm_fpga_cfg::start_write(1); + while rtm_fpga_cfg::busy_read() == 1 {} + } + + debug!("finishing"); + + loop { + if rtm_fpga_cfg::error_read() != 0 { + error!("programming error"); + + return Err(()) + } + + if rtm_fpga_cfg::done_read() != 0 { + debug!("done"); + + return Ok(()) + } + } + } +} diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 21d0edf85..6b6765195 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -49,11 +49,20 @@ mod moninj; mod analyzer; fn startup() { + log::set_max_level(log::LevelFilter::TRACE); + logger_artiq::BufferLogger::with(|logger| + logger.set_uart_log_level(log::LevelFilter::TRACE)); + board::clock::init(); info!("ARTIQ runtime starting..."); info!("software version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); info!("gateware version {}", board::ident::read(&mut [0; 64])); + #[cfg(has_rtm_fpga_cfg)] + board_artiq::rtm_fpga::program_bitstream().expect("cannot program RTM FPGA"); + #[cfg(has_serwb_phy_amc)] + board_artiq::serwb::wait_init(); + match config::read_str("log_level", |r| r.map(|s| s.parse())) { Ok(Ok(log_level_filter)) => { info!("log level set to {} by `log_level` config key", @@ -72,9 +81,6 @@ fn startup() { _ => info!("UART log level set to INFO by default") } - #[cfg(has_serwb_phy_amc)] - board_artiq::serwb::wait_init(); - let t = board::clock::get_ms(); info!("press 'e' to erase startup and idle kernels..."); while board::clock::get_ms() < t + 1000 { diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index ee5c93994..33b627236 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -6,6 +6,7 @@ import subprocess import tempfile import shutil import re +import io import atexit from functools import partial from collections import defaultdict @@ -278,6 +279,7 @@ def main(): "bootloader": ("spi1", 0x000000), "storage": ("spi1", 0x040000), "firmware": ("spi1", 0x050000), + "rtm_gateware": ("spi1", 0x150000), }, }[args.target] @@ -309,18 +311,30 @@ def main(): else: return os.path.join(args.srcbuild, *path_filename) + def convert_gateware(bit_filename, prefix_size=False): + bin_io = io.BytesIO() + with open(bit_filename, "rb") as bit_file: + bit2bin(bit_file, bin_io) + bin_data = bin_io.getvalue() + + bin_handle, bin_filename = tempfile.mkstemp( + prefix="artiq_", suffix="_" + os.path.basename(bit_filename)) + with open(bin_handle, "wb") as bin_file: + if prefix_size: + bin_file.write(len(bin_data).to_bytes(4, byteorder="big")) + bin_file.write(bin_data) + atexit.register(lambda: os.unlink(bin_filename)) + return bin_filename + try: for action in args.action: if action == "gateware": - gateware_bin = artifact_path(variant, "gateware", "top.bin") - if not os.access(gateware_bin, os.R_OK): - bin_handle, gateware_bin = tempfile.mkstemp() - gateware_bit = artifact_path(variant, "gateware", "top.bit") - with open(gateware_bit, "rb") as bit_file, open(bin_handle, "wb") as bin_file: - bit2bin(bit_file, bin_file) - atexit.register(lambda: os.unlink(gateware_bin)) - + gateware_bin = convert_gateware(artifact_path(variant, "gateware", "top.bit")) programmer.write_binary(*config["gateware"], gateware_bin) + + if args.target == "sayma": + rtm_gateware_bin = convert_gateware(artifact_path("rtm_gateware", "top.bit")) + programmer.write_binary(*config["rtm_gateware"], rtm_gateware_bin) elif action == "bootloader": bootloader_bin = artifact_path(variant, "software", "bootloader", "bootloader.bin") programmer.write_binary(*config["bootloader"], bootloader_bin) From cedecc3030c7a58b508069b7f1bdc3e28c142880 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 28 Feb 2018 18:43:56 +0100 Subject: [PATCH 0420/2457] Revert "firmware: Sayma RTM FPGA bitstream loading prototype (#813)." This reverts commit f95fb273f145a42d5e7d4ec3008a4f1fdb8f1901. Will be replaced with a bitbang/GPIO based version. --- artiq/firmware/libboard_artiq/lib.rs | 3 +- artiq/firmware/libboard_artiq/rtm_fpga.rs | 46 ----------------------- artiq/firmware/runtime/main.rs | 12 ++---- artiq/frontend/artiq_flash.py | 30 ++++----------- 4 files changed, 12 insertions(+), 79 deletions(-) delete mode 100644 artiq/firmware/libboard_artiq/rtm_fpga.rs diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index a0f1a5c8a..127a55db8 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -1,3 +1,4 @@ +#![feature(asm, lang_items)] #![no_std] #[macro_use] @@ -24,5 +25,3 @@ mod ad9154_reg; pub mod ad9154; #[cfg(has_allaki_atts)] pub mod hmc542; -#[cfg(has_rtm_fpga_cfg)] -pub mod rtm_fpga; diff --git a/artiq/firmware/libboard_artiq/rtm_fpga.rs b/artiq/firmware/libboard_artiq/rtm_fpga.rs deleted file mode 100644 index 88fc6730e..000000000 --- a/artiq/firmware/libboard_artiq/rtm_fpga.rs +++ /dev/null @@ -1,46 +0,0 @@ -use core::slice; -use board::csr::rtm_fpga_cfg; -use board::clock; - -const ADDR: *const u8 = 0x150000 as *const u8; - -pub fn program_bitstream() -> Result<(), ()> { - unsafe { - let length = *(ADDR as *const usize); - let bitstream = slice::from_raw_parts(ADDR.offset(4) as *const u32, length / 4); - - debug!("resetting"); - - rtm_fpga_cfg::divisor_write(15); - rtm_fpga_cfg::program_write(1); - clock::spin_us(1000); - rtm_fpga_cfg::program_write(0); - clock::spin_us(1000); - - while rtm_fpga_cfg::error_read() != 0 {} - - debug!("programming"); - - for word in bitstream { - rtm_fpga_cfg::data_write(*word); - rtm_fpga_cfg::start_write(1); - while rtm_fpga_cfg::busy_read() == 1 {} - } - - debug!("finishing"); - - loop { - if rtm_fpga_cfg::error_read() != 0 { - error!("programming error"); - - return Err(()) - } - - if rtm_fpga_cfg::done_read() != 0 { - debug!("done"); - - return Ok(()) - } - } - } -} diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 6b6765195..21d0edf85 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -49,20 +49,11 @@ mod moninj; mod analyzer; fn startup() { - log::set_max_level(log::LevelFilter::TRACE); - logger_artiq::BufferLogger::with(|logger| - logger.set_uart_log_level(log::LevelFilter::TRACE)); - board::clock::init(); info!("ARTIQ runtime starting..."); info!("software version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); info!("gateware version {}", board::ident::read(&mut [0; 64])); - #[cfg(has_rtm_fpga_cfg)] - board_artiq::rtm_fpga::program_bitstream().expect("cannot program RTM FPGA"); - #[cfg(has_serwb_phy_amc)] - board_artiq::serwb::wait_init(); - match config::read_str("log_level", |r| r.map(|s| s.parse())) { Ok(Ok(log_level_filter)) => { info!("log level set to {} by `log_level` config key", @@ -81,6 +72,9 @@ fn startup() { _ => info!("UART log level set to INFO by default") } + #[cfg(has_serwb_phy_amc)] + board_artiq::serwb::wait_init(); + let t = board::clock::get_ms(); info!("press 'e' to erase startup and idle kernels..."); while board::clock::get_ms() < t + 1000 { diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 33b627236..ee5c93994 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -6,7 +6,6 @@ import subprocess import tempfile import shutil import re -import io import atexit from functools import partial from collections import defaultdict @@ -279,7 +278,6 @@ def main(): "bootloader": ("spi1", 0x000000), "storage": ("spi1", 0x040000), "firmware": ("spi1", 0x050000), - "rtm_gateware": ("spi1", 0x150000), }, }[args.target] @@ -311,30 +309,18 @@ def main(): else: return os.path.join(args.srcbuild, *path_filename) - def convert_gateware(bit_filename, prefix_size=False): - bin_io = io.BytesIO() - with open(bit_filename, "rb") as bit_file: - bit2bin(bit_file, bin_io) - bin_data = bin_io.getvalue() - - bin_handle, bin_filename = tempfile.mkstemp( - prefix="artiq_", suffix="_" + os.path.basename(bit_filename)) - with open(bin_handle, "wb") as bin_file: - if prefix_size: - bin_file.write(len(bin_data).to_bytes(4, byteorder="big")) - bin_file.write(bin_data) - atexit.register(lambda: os.unlink(bin_filename)) - return bin_filename - try: for action in args.action: if action == "gateware": - gateware_bin = convert_gateware(artifact_path(variant, "gateware", "top.bit")) - programmer.write_binary(*config["gateware"], gateware_bin) + gateware_bin = artifact_path(variant, "gateware", "top.bin") + if not os.access(gateware_bin, os.R_OK): + bin_handle, gateware_bin = tempfile.mkstemp() + gateware_bit = artifact_path(variant, "gateware", "top.bit") + with open(gateware_bit, "rb") as bit_file, open(bin_handle, "wb") as bin_file: + bit2bin(bit_file, bin_file) + atexit.register(lambda: os.unlink(gateware_bin)) - if args.target == "sayma": - rtm_gateware_bin = convert_gateware(artifact_path("rtm_gateware", "top.bit")) - programmer.write_binary(*config["rtm_gateware"], rtm_gateware_bin) + programmer.write_binary(*config["gateware"], gateware_bin) elif action == "bootloader": bootloader_bin = artifact_path(variant, "software", "bootloader", "bootloader.bin") programmer.write_binary(*config["bootloader"], bootloader_bin) From 1f999c7f5f872b2b4f6f5489db1f9a911d145f36 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 28 Feb 2018 16:45:55 +0000 Subject: [PATCH 0421/2457] sayma_amc: expose RTM fpga load pins as GPIOs --- artiq/gateware/targets/sayma_amc.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 30060fe6a..54d49735d 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -161,9 +161,17 @@ class Standalone(MiniSoC, AMPSoC): ] # RTM bitstream upload - rtm_fpga_cfg = platform.request("rtm_fpga_cfg") - self.submodules.rtm_fpga_cfg = SlaveFPGA(rtm_fpga_cfg) - self.csr_devices.append("rtm_fpga_cfg") + slave_fpga_cfg = self.platform.request("rtm_fpga_cfg") + self.submodules.slave_fpga_cfg = gpio.GPIOTristate([ + slave_fpga_cfg.cclk, + slave_fpga_cfg.din, + slave_fpga_cfg.done, + slave_fpga_cfg.init_b, + slave_fpga_cfg.program_b, + ]) + self.csr_devices.append("slave_fpga_cfg") + self.config["HAS_SLAVE_FPGA"] = None + self.config["SLAVE_FPGA_GATEWARE"] = 0xde0000 # AMC/RTM serwb serwb_pll = serwb.phy.SERWBPLL(125e6, 625e6, vco_div=2) From 0c49201be7fe21456fac1e17a74b902a912ead95 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 28 Feb 2018 16:46:16 +0000 Subject: [PATCH 0422/2457] firmware: add slave fpga serial load support based on whitequark's work in f95fb27 m-labs/artiq#813 --- artiq/firmware/Cargo.lock | 1 + artiq/firmware/libboard_artiq/Cargo.toml | 1 + artiq/firmware/libboard_artiq/lib.rs | 3 + artiq/firmware/libboard_artiq/slave_fpga.rs | 79 +++++++++++++++++++++ artiq/firmware/runtime/main.rs | 2 + 5 files changed, 86 insertions(+) create mode 100644 artiq/firmware/libboard_artiq/slave_fpga.rs diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index ed834b273..5a3624209 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -41,6 +41,7 @@ dependencies = [ "board 0.0.0", "build_artiq 0.0.0", "build_misoc 0.0.0", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/artiq/firmware/libboard_artiq/Cargo.toml b/artiq/firmware/libboard_artiq/Cargo.toml index d666b3ef0..149fe4efc 100644 --- a/artiq/firmware/libboard_artiq/Cargo.toml +++ b/artiq/firmware/libboard_artiq/Cargo.toml @@ -14,6 +14,7 @@ build_artiq = { path = "../libbuild_artiq" } [dependencies] bitflags = "1.0" +byteorder = { version = "1.0", default-features = false } log = { version = "0.4", default-features = false } board = { path = "../libboard" } diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 127a55db8..f7066a653 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -3,6 +3,7 @@ #[macro_use] extern crate bitflags; +extern crate byteorder; #[macro_use] extern crate log; extern crate board; @@ -15,6 +16,8 @@ pub mod spi; #[cfg(has_si5324)] pub mod si5324; +#[cfg(has_slave_fpga)] +pub mod slave_fpga; #[cfg(has_serwb_phy_amc)] pub mod serwb; #[cfg(has_hmc830_7043)] diff --git a/artiq/firmware/libboard_artiq/slave_fpga.rs b/artiq/firmware/libboard_artiq/slave_fpga.rs new file mode 100644 index 000000000..907f01043 --- /dev/null +++ b/artiq/firmware/libboard_artiq/slave_fpga.rs @@ -0,0 +1,79 @@ +mod slave_fpga { + use board::{csr, clock}; + use core::slice; + use byteorder::{ByteOrder, BigEndian}; + + const CCLK_BIT: u8 = 1 << 0; + const DIN_BIT: u8 = 1 << 1; + const DONE_BIT: u8 = 1 << 2; + const INIT_B_BIT: u8 = 1 << 3; + const PROGRAM_B_BIT: u8 = 1 << 4; + + const GATEWARE: *mut u8 = csr::CONFIG_SLAVE_FPGA_GATEWARE as *mut u8; + + unsafe fn shift_u8(data: u8) { + for i in 0..8 { + let mut bits: u8 = PROGRAM_B_BIT; + if data & (0x80 >> i) != 0 { + bits |= DIN_BIT; + } + // Without delays, this is about 6 MHz CCLK which is fine. + csr::slave_fpga_cfg::out_write(bits); + // clock::spin_us(1); + csr::slave_fpga_cfg::out_write(bits | CCLK_BIT); + // clock::spin_us(1); + } + } + + pub fn load() -> Result<(), &'static str> { + info!("Loading slave FPGA gateware..."); + + let header = unsafe { slice::from_raw_parts(GATEWARE, 8) }; + let magic = BigEndian::read_u32(&header[0..]); + let length = BigEndian::read_u32(&header[4..]) as usize; + + if magic != 0x53415231 { // "SAR1" + return Err("Slave FPGA gateware magic not found"); + } else if length > 0x220000 { + return Err("Slave FPGA gateware too large (corrupted?)"); + } + info!("Slave FPGA gateware length: 0x{:06x}", length); + + unsafe { + csr::slave_fpga_cfg::oe_write(CCLK_BIT | DIN_BIT | PROGRAM_B_BIT); + + csr::slave_fpga_cfg::out_write(0); + clock::spin_us(1); // TPROGRAM=250ns min + csr::slave_fpga_cfg::out_write(PROGRAM_B_BIT); + clock::spin_us(5_000); // TPL=5ms max + if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { + return Err("Slave FPGA did not initialize."); + } + + for i in slice::from_raw_parts(GATEWARE.offset(8), length) { + shift_u8(*i); + if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { + return Err("Slave FPGA error: INIT_B went low."); + } + } + + let t = clock::get_ms(); + while csr::slave_fpga_cfg::in_read() & DONE_BIT == 0 { + if clock::get_ms() > t + 100 { + error!("Slave FPGA not DONE after loading"); + error!("Corrupt gateware? Slave FPGA in slave serial mode?"); + return Err("Slave FPGA not DONE"); + } + shift_u8(0xff); + } + shift_u8(0xff); // "Compensate for Special Startup Conditions" + csr::slave_fpga_cfg::out_write(PROGRAM_B_BIT); + } + + Ok(()) + } +} + +pub fn load() -> Result<(), &'static str> { + slave_fpga::load() +} diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 21d0edf85..9cf3c11f3 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -72,6 +72,8 @@ fn startup() { _ => info!("UART log level set to INFO by default") } + #[cfg(has_slave_fpga)] + board_artiq::slave_fpga::load().expect("cannot load RTM FPGA gateware"); #[cfg(has_serwb_phy_amc)] board_artiq::serwb::wait_init(); From 54984f080b33856ad452e9db7b454a8f2e14c601 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 28 Feb 2018 16:47:02 +0000 Subject: [PATCH 0423/2457] artiq_flash: flash RTM firmware based on whitequark's work in f95fb27 m-labs/artiq#813 --- artiq/frontend/artiq_flash.py | 69 ++++++++++++++++++----------- artiq/gateware/targets/sayma_amc.py | 2 +- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index ee5c93994..bfa71d8f5 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -256,28 +256,29 @@ def main(): config = { "kc705": { - "programmer": partial(ProgrammerXC7, board="kc705", proxy="bscan_spi_xc7k325t.bit"), - "variants": ["nist_clock", "nist_qc2"], - "gateware": ("spi0", 0x000000), - "bootloader": ("spi0", 0xaf0000), - "storage": ("spi0", 0xb30000), - "firmware": ("spi0", 0xb40000), + "programmer": partial(ProgrammerXC7, board="kc705", proxy="bscan_spi_xc7k325t.bit"), + "variants": ["nist_clock", "nist_qc2"], + "gateware": ("spi0", 0x000000), + "bootloader": ("spi0", 0xaf0000), + "storage": ("spi0", 0xb30000), + "firmware": ("spi0", 0xb40000), }, "kasli": { - "programmer": partial(ProgrammerXC7, board="kasli", proxy="bscan_spi_xc7a100t.bit"), - "variants": ["opticlock", "master", "satellite"], - "gateware": ("spi0", 0x000000), - "bootloader": ("spi0", 0x400000), - "storage": ("spi0", 0x440000), - "firmware": ("spi0", 0x450000), + "programmer": partial(ProgrammerXC7, board="kasli", proxy="bscan_spi_xc7a100t.bit"), + "variants": ["opticlock", "master", "satellite"], + "gateware": ("spi0", 0x000000), + "bootloader": ("spi0", 0x400000), + "storage": ("spi0", 0x440000), + "firmware": ("spi0", 0x450000), }, "sayma": { - "programmer": ProgrammerSayma, - "variants": ["standalone", "master", "satellite"], - "gateware": ("spi0", 0x000000), - "bootloader": ("spi1", 0x000000), - "storage": ("spi1", 0x040000), - "firmware": ("spi1", 0x050000), + "programmer": ProgrammerSayma, + "variants": ["standalone", "master", "satellite"], + "gateware": ("spi0", 0x000000), + "bootloader": ("spi1", 0x000000), + "storage": ("spi1", 0x040000), + "firmware": ("spi1", 0x050000), + "rtm_gateware": ("spi1", 0x150000), }, }[args.target] @@ -309,18 +310,34 @@ def main(): else: return os.path.join(args.srcbuild, *path_filename) + def convert_gateware(bit_filename, header=False): + bin_handle, bin_filename = tempfile.mkstemp( + prefix="artiq_", suffix="_" + os.path.basename(bit_filename)) + with open(bit_filename, "rb") as bit_file, \ + open(bin_handle, "wb") as bin_file: + if header: + bin_file.write(b"\x00"*8) + bit2bin(bit_file, bin_file) + if header: + magic = 0x53415231 # "SAR1" + length = bin_file.tell() - 8 + bin_file.seek(0) + bin_file.write(magic.to_bytes(4, byteorder="big")) + bin_file.write(length.to_bytes(4, byteorder="big")) + atexit.register(lambda: os.unlink(bin_filename)) + return bin_filename + try: for action in args.action: if action == "gateware": - gateware_bin = artifact_path(variant, "gateware", "top.bin") - if not os.access(gateware_bin, os.R_OK): - bin_handle, gateware_bin = tempfile.mkstemp() - gateware_bit = artifact_path(variant, "gateware", "top.bit") - with open(gateware_bit, "rb") as bit_file, open(bin_handle, "wb") as bin_file: - bit2bin(bit_file, bin_file) - atexit.register(lambda: os.unlink(gateware_bin)) - + gateware_bin = convert_gateware( + artifact_path(variant, "gateware", "top.bit")) programmer.write_binary(*config["gateware"], gateware_bin) + if args.target == "sayma": + rtm_gateware_bin = convert_gateware( + artifact_path("rtm_gateware", "rtm.bit"), header=True) + programmer.write_binary(*config["rtm_gateware"], + rtm_gateware_bin) elif action == "bootloader": bootloader_bin = artifact_path(variant, "software", "bootloader", "bootloader.bin") programmer.write_binary(*config["bootloader"], bootloader_bin) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 54d49735d..c19b4a653 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -171,7 +171,7 @@ class Standalone(MiniSoC, AMPSoC): ]) self.csr_devices.append("slave_fpga_cfg") self.config["HAS_SLAVE_FPGA"] = None - self.config["SLAVE_FPGA_GATEWARE"] = 0xde0000 + self.config["SLAVE_FPGA_GATEWARE"] = 0x150000 # AMC/RTM serwb serwb_pll = serwb.phy.SERWBPLL(125e6, 625e6, vco_div=2) From d051cec0dd5b9737743508db77ba7b8e4ce70cb6 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 1 Mar 2018 01:22:52 +0000 Subject: [PATCH 0424/2457] firmware: remove useless module. --- artiq/firmware/libboard_artiq/slave_fpga.rs | 134 ++++++++++---------- 1 file changed, 64 insertions(+), 70 deletions(-) diff --git a/artiq/firmware/libboard_artiq/slave_fpga.rs b/artiq/firmware/libboard_artiq/slave_fpga.rs index 907f01043..cd15b87ad 100644 --- a/artiq/firmware/libboard_artiq/slave_fpga.rs +++ b/artiq/firmware/libboard_artiq/slave_fpga.rs @@ -1,79 +1,73 @@ -mod slave_fpga { - use board::{csr, clock}; - use core::slice; - use byteorder::{ByteOrder, BigEndian}; +use board::{csr, clock}; +use core::slice; +use byteorder::{ByteOrder, BigEndian}; - const CCLK_BIT: u8 = 1 << 0; - const DIN_BIT: u8 = 1 << 1; - const DONE_BIT: u8 = 1 << 2; - const INIT_B_BIT: u8 = 1 << 3; - const PROGRAM_B_BIT: u8 = 1 << 4; +const CCLK_BIT: u8 = 1 << 0; +const DIN_BIT: u8 = 1 << 1; +const DONE_BIT: u8 = 1 << 2; +const INIT_B_BIT: u8 = 1 << 3; +const PROGRAM_B_BIT: u8 = 1 << 4; - const GATEWARE: *mut u8 = csr::CONFIG_SLAVE_FPGA_GATEWARE as *mut u8; +const GATEWARE: *mut u8 = csr::CONFIG_SLAVE_FPGA_GATEWARE as *mut u8; - unsafe fn shift_u8(data: u8) { - for i in 0..8 { - let mut bits: u8 = PROGRAM_B_BIT; - if data & (0x80 >> i) != 0 { - bits |= DIN_BIT; - } - // Without delays, this is about 6 MHz CCLK which is fine. - csr::slave_fpga_cfg::out_write(bits); - // clock::spin_us(1); - csr::slave_fpga_cfg::out_write(bits | CCLK_BIT); - // clock::spin_us(1); +unsafe fn shift_u8(data: u8) { + for i in 0..8 { + let mut bits: u8 = PROGRAM_B_BIT; + if data & (0x80 >> i) != 0 { + bits |= DIN_BIT; } - } - - pub fn load() -> Result<(), &'static str> { - info!("Loading slave FPGA gateware..."); - - let header = unsafe { slice::from_raw_parts(GATEWARE, 8) }; - let magic = BigEndian::read_u32(&header[0..]); - let length = BigEndian::read_u32(&header[4..]) as usize; - - if magic != 0x53415231 { // "SAR1" - return Err("Slave FPGA gateware magic not found"); - } else if length > 0x220000 { - return Err("Slave FPGA gateware too large (corrupted?)"); - } - info!("Slave FPGA gateware length: 0x{:06x}", length); - - unsafe { - csr::slave_fpga_cfg::oe_write(CCLK_BIT | DIN_BIT | PROGRAM_B_BIT); - - csr::slave_fpga_cfg::out_write(0); - clock::spin_us(1); // TPROGRAM=250ns min - csr::slave_fpga_cfg::out_write(PROGRAM_B_BIT); - clock::spin_us(5_000); // TPL=5ms max - if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { - return Err("Slave FPGA did not initialize."); - } - - for i in slice::from_raw_parts(GATEWARE.offset(8), length) { - shift_u8(*i); - if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { - return Err("Slave FPGA error: INIT_B went low."); - } - } - - let t = clock::get_ms(); - while csr::slave_fpga_cfg::in_read() & DONE_BIT == 0 { - if clock::get_ms() > t + 100 { - error!("Slave FPGA not DONE after loading"); - error!("Corrupt gateware? Slave FPGA in slave serial mode?"); - return Err("Slave FPGA not DONE"); - } - shift_u8(0xff); - } - shift_u8(0xff); // "Compensate for Special Startup Conditions" - csr::slave_fpga_cfg::out_write(PROGRAM_B_BIT); - } - - Ok(()) + // Without delays, this is about 6 MHz CCLK which is fine. + csr::slave_fpga_cfg::out_write(bits); + // clock::spin_us(1); + csr::slave_fpga_cfg::out_write(bits | CCLK_BIT); + // clock::spin_us(1); } } pub fn load() -> Result<(), &'static str> { - slave_fpga::load() + info!("Loading slave FPGA gateware..."); + + let header = unsafe { slice::from_raw_parts(GATEWARE, 8) }; + let magic = BigEndian::read_u32(&header[0..]); + let length = BigEndian::read_u32(&header[4..]) as usize; + + if magic != 0x53415231 { // "SAR1" + return Err("Slave FPGA gateware magic not found"); + } else if length > 0x220000 { + return Err("Slave FPGA gateware too large (corrupted?)"); + } + info!("Slave FPGA gateware length: 0x{:06x}", length); + + unsafe { + csr::slave_fpga_cfg::oe_write(CCLK_BIT | DIN_BIT | PROGRAM_B_BIT); + + csr::slave_fpga_cfg::out_write(0); + clock::spin_us(1); // TPROGRAM=250ns min + csr::slave_fpga_cfg::out_write(PROGRAM_B_BIT); + clock::spin_us(5_000); // TPL=5ms max + if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { + return Err("Slave FPGA did not initialize."); + } + + for i in slice::from_raw_parts(GATEWARE.offset(8), length) { + shift_u8(*i); + if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { + return Err("Slave FPGA error: INIT_B went low."); + } + } + + let t = clock::get_ms(); + while csr::slave_fpga_cfg::in_read() & DONE_BIT == 0 { + if clock::get_ms() > t + 100 { + error!("Slave FPGA not DONE after loading"); + error!("Corrupt gateware? Slave FPGA in slave serial mode?"); + return Err("Slave FPGA not DONE"); + } + shift_u8(0xff); + } + shift_u8(0xff); // "Compensate for Special Startup Conditions" + csr::slave_fpga_cfg::out_write(PROGRAM_B_BIT); + } + + Ok(()) } From 14f6fa6699560500e0eb04607c89ffc519e4a3ee Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 1 Mar 2018 01:25:55 +0000 Subject: [PATCH 0425/2457] firmware: fix a warning. --- artiq/firmware/libboard_artiq/ad9154.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index c683ccc47..d00f2fc40 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -538,14 +538,13 @@ fn dac_prbs(dacno: u8) -> Result<(), &'static str> { 0b00*ad9154_reg::PHY_PRBS_PAT_SEL); for i in 0..8 { - let mut lane_errors: u32 = 0; /* step 9.a: select src err */ write(ad9154_reg::PHY_PRBS_TEST_CTRL, i*ad9154_reg::PHY_SRC_ERR_CNT); /* step 9.b: retrieve number of errors */ - lane_errors = (read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_LOBITS) as u32) | - ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_MIDBITS) as u32) << 8) | - ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_HIBITS) as u32) << 16); + let lane_errors = (read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_LOBITS) as u32) | + ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_MIDBITS) as u32) << 8) | + ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_HIBITS) as u32) << 16); if lane_errors > 0 { warn!("AD9154-{} PRBS errors on lane{}: {:06x}", dacno, i, lane_errors); } From 68278e225dd97990a418028296f6487eb063c732 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 1 Mar 2018 17:28:01 +0800 Subject: [PATCH 0426/2457] slave_fpga: check for INIT low --- artiq/firmware/libboard_artiq/slave_fpga.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/slave_fpga.rs b/artiq/firmware/libboard_artiq/slave_fpga.rs index cd15b87ad..9f97039b3 100644 --- a/artiq/firmware/libboard_artiq/slave_fpga.rs +++ b/artiq/firmware/libboard_artiq/slave_fpga.rs @@ -42,11 +42,14 @@ pub fn load() -> Result<(), &'static str> { csr::slave_fpga_cfg::oe_write(CCLK_BIT | DIN_BIT | PROGRAM_B_BIT); csr::slave_fpga_cfg::out_write(0); - clock::spin_us(1); // TPROGRAM=250ns min + clock::spin_us(1_000); // TPROGRAM=250ns min, be_generous + if csr::slave_fpga_cfg::in_read() & INIT_B_BIT != 0 { + return Err("Slave FPGA did not react to PROGRAM."); + } csr::slave_fpga_cfg::out_write(PROGRAM_B_BIT); clock::spin_us(5_000); // TPL=5ms max if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { - return Err("Slave FPGA did not initialize."); + return Err("Slave FPGA did finish INITialization."); } for i in slice::from_raw_parts(GATEWARE.offset(8), length) { From a7720d05cdb507ea687b5e9316bdc6bd8fbba1dc Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 23 Feb 2018 09:50:49 +0000 Subject: [PATCH 0427/2457] firmware, sayma: port converter_spi to spi2 * ksupport/nrt_bus * port ad9154, hmc830, hmc7043 * port local_spi and drtio_spi * port kernel_proto libdrtioaux, satman * change sayma_rtm gateware over * add spi2 NRTSPIMaster * remove spi NRTSPIMaster * change sayma device_db * change HMC830 to open mode and explicitly sequence open mode --- artiq/coredevice/ad9154_spi.py | 5 +- artiq/coredevice/spi.py | 64 +--------------- artiq/coredevice/spi2.py | 53 ++++++++++++- artiq/examples/sayma_drtio/device_db.py | 4 +- artiq/examples/sayma_standalone/device_db.py | 2 +- artiq/firmware/ksupport/api.rs | 1 - artiq/firmware/ksupport/nrt_bus.rs | 12 +-- artiq/firmware/libboard_artiq/ad9154.rs | 19 +++-- artiq/firmware/libboard_artiq/hmc830_7043.rs | 80 +++++++++++--------- artiq/firmware/libboard_artiq/spi.rs | 41 ++++------ artiq/firmware/libdrtioaux/lib.rs | 29 +++---- artiq/firmware/libproto/kernel_proto.rs | 3 +- artiq/firmware/runtime/kern_hwreq.rs | 51 +++---------- artiq/firmware/runtime/main.rs | 1 + artiq/firmware/satman/main.rs | 9 +-- artiq/gateware/targets/sayma_rtm.py | 6 +- 16 files changed, 155 insertions(+), 225 deletions(-) diff --git a/artiq/coredevice/ad9154_spi.py b/artiq/coredevice/ad9154_spi.py index 0ebb77034..d83a85ff6 100644 --- a/artiq/coredevice/ad9154_spi.py +++ b/artiq/coredevice/ad9154_spi.py @@ -10,9 +10,8 @@ class AD9154: self.chip_select = chip_select @kernel - def setup_bus(self, write_div=16, read_div=16): - self.bus.set_config_mu(0, write_div, read_div) - self.bus.set_xfer(self.chip_select, 24, 0) + def setup_bus(self, div=16): + self.bus.set_config_mu(0, 24, div, self.chip_select) @kernel def write(self, addr, data): diff --git a/artiq/coredevice/spi.py b/artiq/coredevice/spi.py index 1d60722d5..b10d9dd0d 100644 --- a/artiq/coredevice/spi.py +++ b/artiq/coredevice/spi.py @@ -21,7 +21,7 @@ __all__ = [ "SPI_OFFLINE", "SPI_ACTIVE", "SPI_PENDING", "SPI_CS_POLARITY", "SPI_CLK_POLARITY", "SPI_CLK_PHASE", "SPI_LSB_FIRST", "SPI_HALF_DUPLEX", - "SPIMaster", "NRTSPIMaster" + "SPIMaster" ] @@ -284,65 +284,3 @@ class SPIMaster: rtio_output(now_mu(), self.channel, SPI_CONFIG_ADDR | SPI_RT2WB_READ, 0) return rtio_input_data(self.channel) - - -@syscall(flags={"nounwind", "nowrite"}) -def spi_set_config(busno: TInt32, flags: TInt32, write_div: TInt32, read_div: TInt32) -> TNone: - raise NotImplementedError("syscall not simulated") - - -@syscall(flags={"nounwind", "nowrite"}) -def spi_set_xfer(busno: TInt32, chip_select: TInt32, write_length: TInt32, read_length: TInt32) -> TNone: - raise NotImplementedError("syscall not simulated") - - -@syscall(flags={"nounwind", "nowrite"}) -def spi_write(busno: TInt32, data: TInt32) -> TNone: - raise NotImplementedError("syscall not simulated") - - -@syscall(flags={"nounwind", "nowrite"}) -def spi_read(busno: TInt32) -> TInt32: - raise NotImplementedError("syscall not simulated") - - -class NRTSPIMaster: - """Core device non-realtime Serial Peripheral Interface (SPI) bus master. - Owns one non-realtime SPI bus. - - With this driver, SPI transactions and are performed by the CPU without - involving RTIO. - - Realtime and non-realtime buses are separate and defined at bitstream - compilation time. - - See :class:`SPIMaster` for a description of the methods. - """ - def __init__(self, dmgr, busno=0, core_device="core"): - self.core = dmgr.get(core_device) - self.busno = busno - - @kernel - def set_config_mu(self, flags=0, write_div=6, read_div=6): - """Set the ``config`` register. - - Note that the non-realtime SPI cores are usually clocked by the system - clock and not the RTIO clock. In many cases, the SPI configuration is - already set by the firmware and you do not need to call this method. - - The offline bit cannot be set using this method. - The SPI bus is briefly taken offline when this method is called. - """ - spi_set_config(self.busno, flags, write_div, read_div) - - @kernel - def set_xfer(self, chip_select=0, write_length=0, read_length=0): - spi_set_xfer(self.busno, chip_select, write_length, read_length) - - @kernel - def write(self, data=0): - spi_write(self.busno, data) - - @kernel - def read(self): - return spi_read(self.busno) diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index ddf81d477..31e1effa2 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -8,6 +8,7 @@ time is an error. """ from artiq.language.core import syscall, kernel, portable, now_mu, delay_mu +from artiq.language.types import TInt32, TNone from artiq.coredevice.rtio import rtio_output, rtio_input_data @@ -16,7 +17,7 @@ __all__ = [ "SPI_OFFLINE", "SPI_END", "SPI_INPUT", "SPI_CS_POLARITY", "SPI_CLK_POLARITY", "SPI_CLK_PHASE", "SPI_LSB_FIRST", "SPI_HALF_DUPLEX", - "SPIMaster" + "SPIMaster", "NRTSPIMaster" ] SPI_DATA_ADDR = 0 @@ -205,3 +206,53 @@ class SPIMaster: :return: SPI input data. """ return rtio_input_data(self.channel) + + +@syscall(flags={"nounwind", "nowrite"}) +def spi_set_config(busno: TInt32, flags: TInt32, length: TInt32, div: TInt32, cs: TInt32) -> TNone: + raise NotImplementedError("syscall not simulated") + + +@syscall(flags={"nounwind", "nowrite"}) +def spi_write(busno: TInt32, data: TInt32) -> TNone: + raise NotImplementedError("syscall not simulated") + + +@syscall(flags={"nounwind", "nowrite"}) +def spi_read(busno: TInt32) -> TInt32: + raise NotImplementedError("syscall not simulated") + + +class NRTSPIMaster: + """Core device non-realtime Serial Peripheral Interface (SPI) bus master. + Owns one non-realtime SPI bus. + + With this driver, SPI transactions and are performed by the CPU without + involving RTIO. + + Realtime and non-realtime buses are separate and defined at bitstream + compilation time. + + See :class:`SPIMaster` for a description of the methods. + """ + def __init__(self, dmgr, busno=0, core_device="core"): + self.core = dmgr.get(core_device) + self.busno = busno + + @kernel + def set_config_mu(self, flags=0, length=8, div=6, cs=1): + """Set the ``config`` register. + + Note that the non-realtime SPI cores are usually clocked by the system + clock and not the RTIO clock. In many cases, the SPI configuration is + already set by the firmware and you do not need to call this method. + """ + spi_set_config(self.busno, flags, length, div, cs) + + @kernel + def write(self, data=0): + spi_write(self.busno, data) + + @kernel + def read(self): + return spi_read(self.busno) diff --git a/artiq/examples/sayma_drtio/device_db.py b/artiq/examples/sayma_drtio/device_db.py index 039efb6bd..92b7dd13d 100644 --- a/artiq/examples/sayma_drtio/device_db.py +++ b/artiq/examples/sayma_drtio/device_db.py @@ -95,7 +95,7 @@ device_db = { "converter_spi": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "NRTSPIMaster", }, "ad9154_spi0": { @@ -112,7 +112,7 @@ device_db = { }, "rconverter_spi": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "NRTSPIMaster", "arguments": {"busno": 0x010000} }, diff --git a/artiq/examples/sayma_standalone/device_db.py b/artiq/examples/sayma_standalone/device_db.py index 370b3f0a6..303fdce7e 100644 --- a/artiq/examples/sayma_standalone/device_db.py +++ b/artiq/examples/sayma_standalone/device_db.py @@ -21,7 +21,7 @@ device_db = { "converter_spi": { "type": "local", - "module": "artiq.coredevice.spi", + "module": "artiq.coredevice.spi2", "class": "NRTSPIMaster", }, "ad9154_spi0": { diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 53736a0fa..b2d608b1f 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -118,7 +118,6 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(i2c_read = ::nrt_bus::i2c::read), api!(spi_set_config = ::nrt_bus::spi::set_config), - api!(spi_set_xfer = ::nrt_bus::spi::set_xfer), api!(spi_write = ::nrt_bus::spi::write), api!(spi_read = ::nrt_bus::spi::read), ]; diff --git a/artiq/firmware/ksupport/nrt_bus.rs b/artiq/firmware/ksupport/nrt_bus.rs index c847bcf82..9e226dd96 100644 --- a/artiq/firmware/ksupport/nrt_bus.rs +++ b/artiq/firmware/ksupport/nrt_bus.rs @@ -50,17 +50,9 @@ pub mod spi { use ::recv; use kernel_proto::*; - pub extern fn set_config(busno: i32, flags: i32, write_div: i32, read_div: i32) { + pub extern fn set_config(busno: i32, flags: i32, length: i32, div: i32, cs: i32) { send(&SpiSetConfigRequest { busno: busno as u32, flags: flags as u8, - write_div: write_div as u8, read_div: read_div as u8 }); - recv!(&SpiBasicReply { succeeded } => if !succeeded { - raise!("SPIError", "SPI bus could not be accessed"); - }); - } - - pub extern fn set_xfer(busno: i32, chip_select: i32, write_length: i32, read_length: i32) { - send(&SpiSetXferRequest { busno: busno as u32, chip_select: chip_select as u16, - write_length: write_length as u8, read_length: read_length as u8 }); + length: length as u8, div: div as u8, cs: cs as u8 }); recv!(&SpiBasicReply { succeeded } => if !succeeded { raise!("SPIError", "SPI bus could not be accessed"); }); diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index d00f2fc40..a50d55ab8 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -3,34 +3,33 @@ use ad9154_reg; fn spi_setup(dacno: u8) { unsafe { - csr::converter_spi::offline_write(1); + while csr::converter_spi::idle_read() == 0 {} + csr::converter_spi::offline_write(0); + csr::converter_spi::end_write(1); csr::converter_spi::cs_polarity_write(0b0001); csr::converter_spi::clk_polarity_write(0); csr::converter_spi::clk_phase_write(0); csr::converter_spi::lsb_first_write(0); csr::converter_spi::half_duplex_write(0); - csr::converter_spi::clk_div_write_write(16); - csr::converter_spi::clk_div_read_write(16); - csr::converter_spi::xfer_len_write_write(24); - csr::converter_spi::xfer_len_read_write(0); + csr::converter_spi::length_write(24 - 1); + csr::converter_spi::div_write(16 - 2); csr::converter_spi::cs_write(1 << (csr::CONFIG_CONVERTER_SPI_FIRST_AD9154_CS + dacno as u32)); - csr::converter_spi::offline_write(0); } } fn write(addr: u16, data: u8) { unsafe { - csr::converter_spi::data_write_write( + while csr::converter_spi::writable_read() == 0 {} + csr::converter_spi::data_write( ((addr as u32) << 16) | ((data as u32) << 8)); - while csr::converter_spi::pending_read() != 0 {} - while csr::converter_spi::active_read() != 0 {} + while csr::converter_spi::writable_read() == 0 {} } } fn read(addr: u16) -> u8 { unsafe { write((1 << 15) | addr, 0); - csr::converter_spi::data_read_read() as u8 + csr::converter_spi::data_read() as u8 } } diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 80406251c..dc899ce15 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -51,16 +51,24 @@ mod hmc830 { fn spi_setup() { unsafe { - csr::converter_spi::offline_write(1); + while csr::converter_spi::idle_read() == 0 {} + csr::converter_spi::offline_write(0); + csr::converter_spi::end_write(1); csr::converter_spi::cs_polarity_write(0b0001); csr::converter_spi::clk_polarity_write(0); csr::converter_spi::clk_phase_write(0); csr::converter_spi::lsb_first_write(0); csr::converter_spi::half_duplex_write(0); - csr::converter_spi::clk_div_write_write(8); - csr::converter_spi::clk_div_read_write(8); + csr::converter_spi::div_write(16 - 2); csr::converter_spi::cs_write(1 << csr::CONFIG_CONVERTER_SPI_HMC830_CS); - csr::converter_spi::offline_write(0); + + // do a dummy cycle with cs still high to ensure Open mode + // (rising CLK before rising CS) + csr::converter_spi::length_write(0); + csr::converter_spi::data_write(0); + while csr::converter_spi::writable_read() == 0 {} + + csr::converter_spi::length_write(31 - 1); } } @@ -68,24 +76,17 @@ mod hmc830 { let cmd = (0 << 6) | addr; let val = ((cmd as u32) << 24) | data; unsafe { - csr::converter_spi::xfer_len_write_write(32); - csr::converter_spi::xfer_len_read_write(0); - csr::converter_spi::data_write_write(val << (32-31)); - while csr::converter_spi::pending_read() != 0 {} - while csr::converter_spi::active_read() != 0 {} + while csr::converter_spi::writable_read() == 0 {} + csr::converter_spi::data_write(val << 1); + while csr::converter_spi::writable_read() == 0 {} } } fn read(addr: u8) -> u32 { - let cmd = (1 << 6) | addr; - let val = (cmd as u32) << 24; + write(addr, 0); unsafe { - csr::converter_spi::xfer_len_write_write(7); - csr::converter_spi::xfer_len_read_write(25); - csr::converter_spi::data_write_write(val << (32-31)); - while csr::converter_spi::pending_read() != 0 {} - while csr::converter_spi::active_read() != 0 {} - csr::converter_spi::data_read_read() & 0xffffff + while csr::converter_spi::writable_read() == 0 {} + csr::converter_spi::data_read() & 0xffffff } } @@ -123,7 +124,7 @@ mod hmc830 { mod hmc7043 { use board::csr; - + // To do: check which output channels we actually need const DAC_CLK_DIV: u32 = 2; const FPGA_CLK_DIV: u32 = 8; @@ -150,16 +151,17 @@ mod hmc7043 { fn spi_setup() { unsafe { - csr::converter_spi::offline_write(1); + while csr::converter_spi::idle_read() == 0 {} + csr::converter_spi::offline_write(0); + csr::converter_spi::end_write(1); csr::converter_spi::cs_polarity_write(0b0001); csr::converter_spi::clk_polarity_write(0); csr::converter_spi::clk_phase_write(0); csr::converter_spi::lsb_first_write(0); - csr::converter_spi::half_duplex_write(1); - csr::converter_spi::clk_div_write_write(8); - csr::converter_spi::clk_div_read_write(8); + csr::converter_spi::half_duplex_write(0); // change mid-transaction for reads + csr::converter_spi::length_write(24 - 1); + csr::converter_spi::div_write(16 - 2); csr::converter_spi::cs_write(1 << csr::CONFIG_CONVERTER_SPI_HMC7043_CS); - csr::converter_spi::offline_write(0); } } @@ -167,24 +169,29 @@ mod hmc7043 { let cmd = (0 << 15) | addr; let val = ((cmd as u32) << 8) | data as u32; unsafe { - csr::converter_spi::xfer_len_write_write(24); - csr::converter_spi::xfer_len_read_write(0); - csr::converter_spi::data_write_write(val << (32-24)); - while csr::converter_spi::pending_read() != 0 {} - while csr::converter_spi::active_read() != 0 {} + while csr::converter_spi::writable_read() == 0 {} + csr::converter_spi::data_write(val << 8); + while csr::converter_spi::writable_read() == 0 {} } } fn read(addr: u16) -> u8 { let cmd = (1 << 15) | addr; - let val = (cmd as u32) << 8; + let val = cmd as u32; unsafe { - csr::converter_spi::xfer_len_write_write(16); - csr::converter_spi::xfer_len_read_write(8); - csr::converter_spi::data_write_write(val << (32-24)); - while csr::converter_spi::pending_read() != 0 {} - while csr::converter_spi::active_read() != 0 {} - csr::converter_spi::data_read_read() as u8 + while csr::converter_spi::writable_read() == 0 {} + csr::converter_spi::end_write(0); + csr::converter_spi::length_write(16 - 1); + csr::converter_spi::data_write(val << 16); + while csr::converter_spi::writable_read() == 0 {} + csr::converter_spi::end_write(1); + csr::converter_spi::half_duplex_write(1); + csr::converter_spi::length_write(8 - 1); + csr::converter_spi::data_write(0); + while csr::converter_spi::writable_read() == 0 {} + csr::converter_spi::half_duplex_write(0); + csr::converter_spi::length_write(24 - 1); + csr::converter_spi::data_read() as u8 } } @@ -233,7 +240,7 @@ mod hmc7043 { write(channel_base + 0x4, dphase & 0x1f); // No analog phase shift on clock channels - if (channel % 2) == 0 { write(channel_base + 0x7, 0x00); } + if (channel % 2) == 0 { write(channel_base + 0x7, 0x00); } else { write(channel_base + 0x7, 0x01); } write(channel_base + 0x8, 0x08) @@ -245,6 +252,7 @@ mod hmc7043 { pub fn init() -> Result<(), &'static str> { clock_mux::init(); + /* must be the first SPI init because of HMC830 SPI mode selection */ hmc830::init()?; hmc7043::init() } diff --git a/artiq/firmware/libboard_artiq/spi.rs b/artiq/firmware/libboard_artiq/spi.rs index 44aa0c729..94773b690 100644 --- a/artiq/firmware/libboard_artiq/spi.rs +++ b/artiq/firmware/libboard_artiq/spi.rs @@ -2,33 +2,24 @@ mod imp { use board::csr; - pub fn set_config(busno: u8, flags: u8, write_div: u8, read_div: u8) -> Result<(), ()> { + pub fn set_config(busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { if busno != 0 { return Err(()) } unsafe { - csr::converter_spi::offline_write(1); - csr::converter_spi::cs_polarity_write(flags >> 3 & 1); + while csr::converter_spi::idle_read() == 0 {} + csr::converter_spi::offline_write(flags >> 0 & 1); + csr::converter_spi::end_write(flags >> 1 & 1); + /* input (in RTIO): flags >> 2 & 1 */ + /* cs_polarity is a mask in the CSR interface */ + csr::converter_spi::cs_polarity_write(0xff & (flags >> 3 & 1)); csr::converter_spi::clk_polarity_write(flags >> 4 & 1); csr::converter_spi::clk_phase_write(flags >> 5 & 1); csr::converter_spi::lsb_first_write(flags >> 6 & 1); csr::converter_spi::half_duplex_write(flags >> 7 & 1); - csr::converter_spi::clk_div_write_write(write_div); - csr::converter_spi::clk_div_read_write(read_div); - csr::converter_spi::offline_write(0); - } - Ok(()) - } - - pub fn set_xfer(busno: u8, chip_select: u16, write_length: u8, read_length: u8) - -> Result<(), ()> { - if busno != 0 { - return Err(()) - } - unsafe { - csr::converter_spi::cs_write(chip_select as _); - csr::converter_spi::xfer_len_write_write(write_length); - csr::converter_spi::xfer_len_read_write(read_length); + csr::converter_spi::length_write(length - 1); + csr::converter_spi::div_write(div - 2); + csr::converter_spi::cs_write(cs); } Ok(()) } @@ -38,9 +29,9 @@ mod imp { return Err(()) } unsafe { - csr::converter_spi::data_write_write(data); - while csr::converter_spi::pending_read() != 0 {} - while csr::converter_spi::active_read() != 0 {} + while csr::converter_spi::writable_read() == 0 {} + csr::converter_spi::data_write(data); + while csr::converter_spi::writable_read() == 0 {} } Ok(()) } @@ -50,16 +41,14 @@ mod imp { return Err(()) } Ok(unsafe { - csr::converter_spi::data_read_read() + csr::converter_spi::data_read() }) } } #[cfg(not(has_converter_spi))] mod imp { - pub fn set_config(_busno: u8, _flags: u8, _write_div: u8, _read_div: u8) -> Result<(), ()> { Err(()) } - pub fn set_xfer(_busno: u8,_chip_select: u16, _write_length: u8, _read_length: u8) - -> Result<(), ()> { Err(()) } + pub fn set_config(_busno: u8, _flags: u8, _length: u8, _div: u8, _cs: u8) -> Result<(), ()> { Err(()) } pub fn write(_busno: u8,_data: u32) -> Result<(), ()> { Err(()) } pub fn read(_busno: u8,) -> Result { Err(()) } } diff --git a/artiq/firmware/libdrtioaux/lib.rs b/artiq/firmware/libdrtioaux/lib.rs index 927825630..bb4aa6dcc 100644 --- a/artiq/firmware/libdrtioaux/lib.rs +++ b/artiq/firmware/libdrtioaux/lib.rs @@ -41,8 +41,7 @@ pub enum Packet { I2cReadReply { succeeded: bool, data: u8 }, I2cBasicReply { succeeded: bool }, - SpiSetConfigRequest { busno: u8, flags: u8, write_div: u8, read_div: u8 }, - SpiSetXferRequest { busno: u8, chip_select: u16, write_length: u8, read_length: u8 }, + SpiSetConfigRequest { busno: u8, flags: u8, length: u8, div: u8, cs: u8 }, SpiWriteRequest { busno: u8, data: u32 }, SpiReadRequest { busno: u8 }, SpiReadReply { succeeded: bool, data: u32 }, @@ -123,15 +122,11 @@ impl Packet { 0x90 => Packet::SpiSetConfigRequest { busno: read_u8(reader)?, flags: read_u8(reader)?, - write_div: read_u8(reader)?, - read_div: read_u8(reader)? - }, - 0x91 => Packet::SpiSetXferRequest { - busno: read_u8(reader)?, - chip_select: read_u16(reader)?, - write_length: read_u8(reader)?, - read_length: read_u8(reader)? + length: read_u8(reader)?, + div: read_u8(reader)?, + cs: read_u8(reader)? }, + /* 0x91: was Packet::SpiSetXferRequest */ 0x92 => Packet::SpiWriteRequest { busno: read_u8(reader)?, data: read_u32(reader)? @@ -238,19 +233,13 @@ impl Packet { write_bool(writer, succeeded)?; }, - Packet::SpiSetConfigRequest { busno, flags, write_div, read_div } => { + Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => { write_u8(writer, 0x90)?; write_u8(writer, busno)?; write_u8(writer, flags)?; - write_u8(writer, write_div)?; - write_u8(writer, read_div)?; - }, - Packet::SpiSetXferRequest { busno, chip_select, write_length, read_length } => { - write_u8(writer, 0x91)?; - write_u8(writer, busno)?; - write_u16(writer, chip_select)?; - write_u8(writer, write_length)?; - write_u8(writer, read_length)?; + write_u8(writer, length)?; + write_u8(writer, div)?; + write_u8(writer, cs)?; }, Packet::SpiWriteRequest { busno, data } => { write_u8(writer, 0x92)?; diff --git a/artiq/firmware/libproto/kernel_proto.rs b/artiq/firmware/libproto/kernel_proto.rs index 06e5473d0..babd9fbcf 100644 --- a/artiq/firmware/libproto/kernel_proto.rs +++ b/artiq/firmware/libproto/kernel_proto.rs @@ -85,8 +85,7 @@ pub enum Message<'a> { I2cReadReply { succeeded: bool, data: u8 }, I2cBasicReply { succeeded: bool }, - SpiSetConfigRequest { busno: u32, flags: u8, write_div: u8, read_div: u8 }, - SpiSetXferRequest { busno: u32, chip_select: u16, write_length: u8, read_length: u8 }, + SpiSetConfigRequest { busno: u32, flags: u8, length: u8, div: u8, cs: u8 }, SpiWriteRequest { busno: u32, data: u32 }, SpiReadRequest { busno: u32 }, SpiReadReply { succeeded: bool, data: u32 }, diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index 8eea9cd17..be1a380e8 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -194,25 +194,13 @@ mod drtio_spi { } } - pub fn set_config(nodeno: u8, busno: u8, flags: u8, write_div: u8, read_div: u8) -> Result<(), ()> { + pub fn set_config(nodeno: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { let request = drtioaux::Packet::SpiSetConfigRequest { busno: busno, flags: flags, - write_div: write_div, - read_div: read_div - }; - if drtioaux::hw::send(nodeno, &request).is_err() { - return Err(()) - } - basic_reply(nodeno) - } - - pub fn set_xfer(nodeno: u8, busno: u8, chip_select: u16, write_length: u8, read_length: u8) -> Result<(), ()> { - let request = drtioaux::Packet::SpiSetXferRequest { - busno: busno, - chip_select: chip_select, - write_length: write_length, - read_length: read_length + length: length, + div: div, + cs: cs }; if drtioaux::hw::send(nodeno, &request).is_err() { return Err(()) @@ -255,12 +243,7 @@ mod drtio_spi { #[cfg(not(has_drtio))] mod drtio_spi { pub fn set_config(_nodeno: u8, _busno: u8, _flags: u8, - _write_div: u8, _read_div: u8) -> Result<(), ()> { - Err(()) - } - - pub fn set_xfer(_nodeno: u8, _busno: u8, _chip_select: u16, - _write_length: u8, _read_length: u8) -> Result<(), ()> { + _length: u8, _div: u8, _cs: u8) -> Result<(), ()> { Err(()) } @@ -277,23 +260,13 @@ mod spi { use board_artiq::spi as local_spi; use super::drtio_spi; - pub fn set_config(busno: u32, flags: u8, write_div: u8, read_div: u8) -> Result<(), ()> { + pub fn set_config(busno: u32, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { let nodeno = (busno >> 16) as u8; let node_busno = busno as u8; if nodeno == 0 { - local_spi::set_config(node_busno, flags, write_div, read_div) + local_spi::set_config(node_busno, flags, length, div, cs) } else { - drtio_spi::set_config(nodeno, node_busno, flags, write_div, read_div) - } - } - - pub fn set_xfer(busno: u32, chip_select: u16, write_length: u8, read_length: u8) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_spi::set_xfer(node_busno, chip_select, write_length, read_length) - } else { - drtio_spi::set_xfer(nodeno, node_busno, chip_select, write_length, read_length) + drtio_spi::set_config(nodeno, node_busno, flags, length, div, cs) } } @@ -364,14 +337,10 @@ pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> io::Result } } - &kern::SpiSetConfigRequest { busno, flags, write_div, read_div } => { - let succeeded = spi::set_config(busno, flags, write_div, read_div).is_ok(); + &kern::SpiSetConfigRequest { busno, flags, length, div, cs } => { + let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) }, - &kern::SpiSetXferRequest { busno, chip_select, write_length, read_length } => { - let succeeded = spi::set_xfer(busno, chip_select, write_length, read_length).is_ok(); - kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) - } &kern::SpiWriteRequest { busno, data } => { let succeeded = spi::write(busno, data).is_ok(); kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 9cf3c11f3..3066ea9b3 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -94,6 +94,7 @@ fn startup() { #[cfg(si5324_as_synthesizer)] setup_si5324_as_synthesizer(); #[cfg(has_hmc830_7043)] + /* must be the first SPI init because of HMC830 SPI mode selection */ board_artiq::hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] board_artiq::ad9154::init().expect("cannot initialize AD9154"); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 7744c65c0..195471457 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -144,14 +144,10 @@ fn process_aux_packet(p: &drtioaux::Packet) { }; } - drtioaux::Packet::SpiSetConfigRequest { busno, flags, write_div, read_div } => { - let succeeded = spi::set_config(busno, flags, write_div, read_div).is_ok(); + drtioaux::Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => { + let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); drtioaux::hw::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }).unwrap(); }, - drtioaux::Packet::SpiSetXferRequest { busno, chip_select, write_length, read_length } => { - let succeeded = spi::set_xfer(busno, chip_select, write_length, read_length).is_ok(); - drtioaux::hw::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }).unwrap(); - } drtioaux::Packet::SpiWriteRequest { busno, data } => { let succeeded = spi::write(busno, data).is_ok(); drtioaux::hw::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }).unwrap(); @@ -226,6 +222,7 @@ fn startup() { serwb::wait_init(); #[cfg(has_hmc830_7043)] + /* must be the first SPI init because of HMC830 SPI mode selection */ hmc830_7043::init().expect("cannot initialize HMC830/7043"); i2c::init(); si5324::setup(&SI5324_SETTINGS).expect("cannot initialize Si5324"); diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 9a77a4694..4061320ed 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -10,7 +10,7 @@ from migen.build.platforms.sinara import sayma_rtm from misoc.interconnect import wishbone, stream from misoc.interconnect.csr import * from misoc.cores import identifier -from misoc.cores import spi +from misoc.cores import spi2 from misoc.cores import gpio from misoc.integration.wb_slaves import WishboneSlaveManager from misoc.integration.cpu_interface import get_csr_csv @@ -140,10 +140,10 @@ class SaymaRTM(Module): platform.request("ad9154_txen", 1).eq(0b11) ] - self.submodules.converter_spi = spi.SPIMaster([ + self.submodules.converter_spi = spi2.SPIMaster(spi2.SPIInterface( platform.request("hmc_spi"), platform.request("ad9154_spi", 0), - platform.request("ad9154_spi", 1)]) + platform.request("ad9154_spi", 1))) csr_devices.append("converter_spi") self.comb += platform.request("hmc7043_reset").eq(0) From 6fbe0d8ed8c0ce7557a16bf73284d22dd46b1b27 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 23 Feb 2018 13:22:47 +0000 Subject: [PATCH 0428/2457] hmc830: be explicit about SPI mode selection --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index dc899ce15..16e9c3e7d 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -52,6 +52,8 @@ mod hmc830 { fn spi_setup() { unsafe { while csr::converter_spi::idle_read() == 0 {} + // rising egde on CS since cs_polarity still 0 + // selects "HMC Mode" csr::converter_spi::offline_write(0); csr::converter_spi::end_write(1); csr::converter_spi::cs_polarity_write(0b0001); @@ -62,30 +64,30 @@ mod hmc830 { csr::converter_spi::div_write(16 - 2); csr::converter_spi::cs_write(1 << csr::CONFIG_CONVERTER_SPI_HMC830_CS); - // do a dummy cycle with cs still high to ensure Open mode - // (rising CLK before rising CS) + // do a dummy cycle with cs still high to clear CS csr::converter_spi::length_write(0); csr::converter_spi::data_write(0); while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::length_write(31 - 1); + csr::converter_spi::length_write(32 - 1); } } fn write(addr: u8, data: u32) { - let cmd = (0 << 6) | addr; - let val = ((cmd as u32) << 24) | data; + let val = ((addr as u32) << 24) | data; unsafe { while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::data_write(val << 1); + csr::converter_spi::data_write(val << 1); // last clk cycle loads data while csr::converter_spi::writable_read() == 0 {} } } fn read(addr: u8) -> u32 { - write(addr, 0); + // SDO (miso/read bits) is technically CPHA=1, while SDI is CPHA=0 + // trust that the 8.2ns+0.2ns/pF provide enough hold time on top of + // the SPI round trip delay and stick with CPHA=0 + write((1 << 6) | addr, 0); unsafe { - while csr::converter_spi::writable_read() == 0 {} csr::converter_spi::data_read() & 0xffffff } } From ec5b81da5545f9766ef88524de2fc3fc1cca918b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 23 Feb 2018 17:26:51 +0100 Subject: [PATCH 0429/2457] kc705: switch backplane spi to spi2 --- artiq/gateware/targets/kc705.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 5d171f053..fcf52d055 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -17,7 +17,7 @@ from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio, nist_clock, nist_qc2 from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series, - dds, spi, spi2, ad5360_monitor) + dds, spi2, ad5360_monitor) from artiq.build_soc import build_artiq_soc from artiq import __version__ as artiq_version @@ -325,7 +325,7 @@ class NIST_CLOCK(_StandaloneBase): phy, ififo_depth=4)) for i in range(3): - phy = spi.SPIMaster(self.platform.request("spi", i)) + phy = spi2.SPIMaster(self.platform.request("spi", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=128)) @@ -429,7 +429,7 @@ class NIST_QC2(_StandaloneBase): phy, ififo_depth=4)) for i in range(4): - phy = spi.SPIMaster(self.platform.request("spi", i)) + phy = spi2.SPIMaster(self.platform.request("spi", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=128)) From 1329e1a23e01d309067b8c149e5c6736e3695a9b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 23 Feb 2018 17:26:59 +0100 Subject: [PATCH 0430/2457] RELEASE_NOTES: add note about spi2 port --- RELEASE_NOTES.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index c87cb4877..2befe32ca 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -21,7 +21,10 @@ Release notes * ``artiq_flash -m/--adapter`` has been changed to ``artiq_flash -V/--variant``. * ``kc705_dds`` has been renamed ``kc705``. * the ``-H/--hw-adapter`` option of ``kc705`` has ben renamed ``-V/--variant``. - +* SPI masters have been switched from misoc-spi to misoc-spi2. This affects + all out-of-tree RTIO core device drivers using those buses. See the various + commits on e.g. the ``ad5360`` driver for an example how to port from the old + to the new bus. 3.3 --- From cc70578f1fdc2f222c3c814fb3e03be85af640e4 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 23 Feb 2018 17:31:19 +0100 Subject: [PATCH 0431/2457] remove old spi RTIO Phy --- artiq/coredevice/__init__.py | 2 +- artiq/coredevice/comm_analyzer.py | 5 - artiq/coredevice/spi.py | 286 ------------------- artiq/gateware/rtio/phy/spi.py | 13 - artiq/gateware/spi.py | 385 -------------------------- doc/manual/core_drivers_reference.rst | 6 - doc/manual/rtio.rst | 2 +- 7 files changed, 2 insertions(+), 697 deletions(-) delete mode 100644 artiq/coredevice/spi.py delete mode 100644 artiq/gateware/rtio/phy/spi.py delete mode 100644 artiq/gateware/spi.py diff --git a/artiq/coredevice/__init__.py b/artiq/coredevice/__init__.py index 2d0e7d27a..fbec3d901 100644 --- a/artiq/coredevice/__init__.py +++ b/artiq/coredevice/__init__.py @@ -1,4 +1,4 @@ -from artiq.coredevice import exceptions, dds, spi, spi2 +from artiq.coredevice import exceptions, dds, spi2 from artiq.coredevice.exceptions import (RTIOUnderflow, RTIOOverflow) from artiq.coredevice.dds import (PHASE_MODE_CONTINUOUS, PHASE_MODE_ABSOLUTE, PHASE_MODE_TRACKING) diff --git a/artiq/coredevice/comm_analyzer.py b/artiq/coredevice/comm_analyzer.py index d5be1fde2..1da425730 100644 --- a/artiq/coredevice/comm_analyzer.py +++ b/artiq/coredevice/comm_analyzer.py @@ -492,11 +492,6 @@ def create_channel_handlers(vcd_manager, devices, ref_period, dds_onehot_sel, dds_sysclk) channel_handlers[dds_bus_channel] = dds_handler dds_handler.add_dds_channel(name, dds_channel) - if (desc["module"] == "artiq.coredevice.spi" and - desc["class"] == "SPIMaster"): - channel = desc["arguments"]["channel"] - channel_handlers[channel] = SPIMasterHandler( - vcd_manager, name) if (desc["module"] == "artiq.coredevice.spi2" and desc["class"] == "SPIMaster"): channel = desc["arguments"]["channel"] diff --git a/artiq/coredevice/spi.py b/artiq/coredevice/spi.py deleted file mode 100644 index b10d9dd0d..000000000 --- a/artiq/coredevice/spi.py +++ /dev/null @@ -1,286 +0,0 @@ -""" -Driver for generic SPI on RTIO. - -This ARTIQ coredevice driver corresponds to the legacy MiSoC SPI core (v1). - -Output event replacement is not supported and issuing commands at the same -time is an error. -""" - - -import numpy - -from artiq.language.core import syscall, kernel, portable, now_mu, delay_mu -from artiq.language.types import TInt32, TNone -from artiq.language.units import MHz -from artiq.coredevice.rtio import rtio_output, rtio_input_data - - -__all__ = [ - "SPI_DATA_ADDR", "SPI_XFER_ADDR", "SPI_CONFIG_ADDR", - "SPI_OFFLINE", "SPI_ACTIVE", "SPI_PENDING", - "SPI_CS_POLARITY", "SPI_CLK_POLARITY", "SPI_CLK_PHASE", - "SPI_LSB_FIRST", "SPI_HALF_DUPLEX", - "SPIMaster" -] - - -SPI_DATA_ADDR, SPI_XFER_ADDR, SPI_CONFIG_ADDR = range(3) -( - SPI_OFFLINE, - SPI_ACTIVE, - SPI_PENDING, - SPI_CS_POLARITY, - SPI_CLK_POLARITY, - SPI_CLK_PHASE, - SPI_LSB_FIRST, - SPI_HALF_DUPLEX, -) = (1 << i for i in range(8)) - -SPI_RT2WB_READ = 1 << 2 - - -class SPIMaster: - """Core device Serial Peripheral Interface (SPI) bus master. - Owns one SPI bus. - - **Transfer Sequence**: - - * If desired, write the ``config`` register (:meth:`set_config`) - to configure and activate the core. - * If desired, write the ``xfer`` register (:meth:`set_xfer`) - to set ``cs_n``, ``write_length``, and ``read_length``. - * :meth:`write` to the ``data`` register (also for transfers with - zero bits to be written). Writing starts the transfer. - * If desired, :meth:`read_sync` (or :meth:`read_async` followed by a - :meth:`input_async` later) the ``data`` register corresponding to - the last completed transfer. - * If desired, :meth:`set_xfer` for the next transfer. - * If desired, :meth:`write` ``data`` queuing the next - (possibly chained) transfer. - - **Notes**: - - * In order to chain a transfer onto an in-flight transfer without - deasserting ``cs`` in between, the second :meth:`write` needs to - happen strictly later than ``2*ref_period_mu`` (two coarse RTIO - cycles) but strictly earlier than ``xfer_period_mu + write_period_mu`` - after the first. Note that :meth:`write` already applies a delay of - ``xfer_period_mu + write_period_mu``. - * A full transfer takes ``write_period_mu + xfer_period_mu``. - * Chained transfers can happen every ``xfer_period_mu``. - * Read data is available every ``xfer_period_mu`` starting - a bit after xfer_period_mu (depending on ``clk_phase``). - * As a consequence, in order to chain transfers together, new data must - be written before the pending transfer's read data becomes available. - - :param channel: RTIO channel number of the SPI bus to control. - """ - - kernel_invariants = {"core", "ref_period_mu", "channel"} - - def __init__(self, dmgr, channel, core_device="core"): - self.core = dmgr.get(core_device) - self.ref_period_mu = self.core.seconds_to_mu( - self.core.coarse_ref_period) - assert self.ref_period_mu == self.core.ref_multiplier - self.channel = channel - self.write_period_mu = numpy.int64(0) - self.read_period_mu = numpy.int64(0) - self.xfer_period_mu = numpy.int64(0) - - @portable - def frequency_to_div(self, f): - return int(1/(f*self.core.mu_to_seconds(self.ref_period_mu))) + 1 - - @kernel - def set_config(self, flags=0, write_freq=20*MHz, read_freq=20*MHz): - """Set the configuration register. - - * If ``config.cs_polarity`` == 0 (``cs`` active low, the default), - "``cs_n`` all deasserted" means "all ``cs_n`` bits high". - * ``cs_n`` is not mandatory in the pads supplied to the gateware core. - Framing and chip selection can also be handled independently - through other means, e.g. ``TTLOut``. - * If there is a ``miso`` wire in the pads supplied in the gateware, - input and output may be two signals ("4-wire SPI"), - otherwise ``mosi`` must be used for both output and input - ("3-wire SPI") and ``config.half_duplex`` must to be set - when reading data is desired or when the slave drives the - ``mosi`` signal at any point. - * The first bit output on ``mosi`` is always the MSB/LSB (depending - on ``config.lsb_first``) of the ``data`` register, independent of - ``xfer.write_length``. The last bit input from ``miso`` always ends - up in the LSB/MSB (respectively) of the ``data`` register, - independent of ``xfer.read_length``. - * Writes to the ``config`` register take effect immediately. - - **Configuration flags**: - - * :const:`SPI_OFFLINE`: all pins high-z (reset=1) - * :const:`SPI_ACTIVE`: transfer in progress (read-only) - * :const:`SPI_PENDING`: transfer pending in intermediate buffer - (read-only) - * :const:`SPI_CS_POLARITY`: active level of ``cs_n`` (reset=0) - * :const:`SPI_CLK_POLARITY`: idle level of ``clk`` (reset=0) - * :const:`SPI_CLK_PHASE`: first edge after ``cs`` assertion to sample - data on (reset=0). In Motorola/Freescale SPI language - (:const:`SPI_CLK_POLARITY`, :const:`SPI_CLK_PHASE`) == (CPOL, CPHA): - - - (0, 0): idle low, output on falling, input on rising - - (0, 1): idle low, output on rising, input on falling - - (1, 0): idle high, output on rising, input on falling - - (1, 1): idle high, output on falling, input on rising - * :const:`SPI_LSB_FIRST`: LSB is the first bit on the wire (reset=0) - * :const:`SPI_HALF_DUPLEX`: 3-wire SPI, in/out on ``mosi`` (reset=0) - - This method advances the timeline by the duration of the - RTIO-to-Wishbone bus transaction (three RTIO clock cycles). - - :param flags: A bit map of `SPI_*` flags. - :param write_freq: Desired SPI clock frequency during write bits. - :param read_freq: Desired SPI clock frequency during read bits. - """ - self.set_config_mu(flags, self.frequency_to_div(write_freq), - self.frequency_to_div(read_freq)) - - @kernel - def set_config_mu(self, flags=0, write_div=6, read_div=6): - """Set the ``config`` register (in SPI bus machine units). - - .. seealso:: :meth:`set_config` - - :param write_div: Counter load value to divide the RTIO - clock by to generate the SPI write clk. (minimum=2, reset=2) - ``f_rtio_clk/f_spi_write == write_div``. If ``write_div`` is odd, - the setup phase of the SPI clock is biased to longer lengths - by one RTIO clock cycle. - :param read_div: Ditto for the read clock. - """ - if write_div > 257 or write_div < 2 or read_div > 257 or read_div < 2: - raise ValueError('Divider values out of range') - rtio_output(now_mu(), self.channel, SPI_CONFIG_ADDR, flags | - ((write_div - 2) << 16) | ((read_div - 2) << 24)) - self.write_period_mu = int(write_div*self.ref_period_mu) - self.read_period_mu = int(read_div*self.ref_period_mu) - delay_mu(3*self.ref_period_mu) - - @kernel - def set_xfer(self, chip_select=0, write_length=0, read_length=0): - """Set the ``xfer`` register. - - * Every transfer consists of a write of ``write_length`` bits - immediately followed by a read of ``read_length`` bits. - * ``cs_n`` is asserted at the beginning and deasserted at the end - of the transfer if there is no other transfer pending. - * ``cs_n`` handling is agnostic to whether it is one-hot or decoded - somewhere downstream. If it is decoded, "``cs_n`` all deasserted" - should be handled accordingly (no slave selected). - If it is one-hot, asserting multiple slaves should only be attempted - if ``miso`` is either not connected between slaves, or open - collector, or correctly multiplexed externally. - * For 4-wire SPI only the sum of ``read_length`` and ``write_length`` - matters. The behavior is the same (except for clock speeds) no matter - how the total transfer length is divided between the two. For - 3-wire SPI, the direction of ``mosi`` is switched from output to - input after ``write_length`` bits. - * Data output on ``mosi`` in 4-wire SPI during the read cycles is what - is found in the data register at the time. - Data in the ``data`` register outside the least/most (depending - on ``config.lsb_first``) significant ``read_length`` bits is what is - seen on ``miso`` (or ``mosi`` if ``config.half_duplex``) - during the write cycles. - * Writes to ``xfer`` are synchronized to the start of the next - (possibly chained) transfer. - - This method advances the timeline by the duration of the - RTIO-to-Wishbone bus transaction (three RTIO clock cycles). - - :param chip_select: Bit mask of chip selects to assert. Or number of - the chip select to assert if ``cs`` is decoded downstream. - (reset=0) - :param write_length: Number of bits to write during the next transfer. - (reset=0) - :param read_length: Number of bits to read during the next transfer. - (reset=0) - """ - rtio_output(now_mu(), self.channel, SPI_XFER_ADDR, - chip_select | (write_length << 16) | (read_length << 24)) - self.xfer_period_mu = int(write_length*self.write_period_mu + - read_length*self.read_period_mu) - delay_mu(3*self.ref_period_mu) - - @kernel - def write(self, data=0): - """Write data to data register. - - * The ``data`` register and the shift register are 32 bits wide. - If there are no writes to the register, ``miso`` data reappears on - ``mosi`` after 32 cycles. - * A wishbone data register write is acknowledged when the - transfer has been written to the intermediate buffer. - It will be started when there are no other transactions being - executed, either beginning a new SPI transfer of chained - to an in-flight transfer. - * Writes take three ``ref_period`` cycles unless another - chained transfer is pending and the transfer being - executed is not complete. - * The SPI ``data`` register is double-buffered: Once a transfer has - started, new write data can be written, queuing a new transfer. - Transfers submitted this way are chained and executed without - deasserting ``cs`` in between. Once a transfer completes, - the previous transfer's read data is available in the - ``data`` register. - * For bit alignment and bit ordering see :meth:`set_config`. - - This method advances the timeline by the duration of the SPI transfer. - If a transfer is to be chained, the timeline needs to be rewound. - """ - rtio_output(now_mu(), self.channel, SPI_DATA_ADDR, data) - delay_mu(self.xfer_period_mu + self.write_period_mu) - - @kernel - def read_async(self): - """Trigger an asynchronous read from the ``data`` register. - - For bit alignment and bit ordering see :meth:`set_config`. - - Reads always finish in two cycles. - - Every data register read triggered by a :meth:`read_async` - must be matched by a :meth:`input_async` to retrieve the data. - - This method advances the timeline by the duration of the - RTIO-to-Wishbone bus transaction (three RTIO clock cycles). - """ - rtio_output(now_mu(), self.channel, SPI_DATA_ADDR | SPI_RT2WB_READ, 0) - delay_mu(3*self.ref_period_mu) - - @kernel - def input_async(self): - """Retrieves data read asynchronously from the ``data`` register. - - :meth:`input_async` must match a preeeding :meth:`read_async`. - """ - return rtio_input_data(self.channel) - - @kernel - def read_sync(self): - """Read the ``data`` register synchronously. - - This is a shortcut for :meth:`read_async` followed by - :meth:`input_async`. - """ - self.read_async() - return self.input_async() - - @kernel - def _get_xfer_sync(self): - rtio_output(now_mu(), self.channel, SPI_XFER_ADDR | SPI_RT2WB_READ, 0) - return rtio_input_data(self.channel) - - @kernel - def _get_config_sync(self): - rtio_output(now_mu(), self.channel, SPI_CONFIG_ADDR | SPI_RT2WB_READ, - 0) - return rtio_input_data(self.channel) diff --git a/artiq/gateware/rtio/phy/spi.py b/artiq/gateware/rtio/phy/spi.py deleted file mode 100644 index 25d0d7703..000000000 --- a/artiq/gateware/rtio/phy/spi.py +++ /dev/null @@ -1,13 +0,0 @@ -from migen import * - -from artiq.gateware.spi import SPIMaster as SPIMasterWB -from artiq.gateware.rtio.phy.wishbone import RT2WB - - -class SPIMaster(Module): - def __init__(self, pads, pads_n=None, **kwargs): - self.submodules._ll = ClockDomainsRenamer("rio_phy")( - SPIMasterWB(pads, pads_n, **kwargs)) - self.submodules._rt2wb = RT2WB(2, self._ll.bus) - self.rtlink = self._rt2wb.rtlink - self.probes = [] diff --git a/artiq/gateware/spi.py b/artiq/gateware/spi.py deleted file mode 100644 index 3ed4a2159..000000000 --- a/artiq/gateware/spi.py +++ /dev/null @@ -1,385 +0,0 @@ -from itertools import product - -from migen import * -from misoc.interconnect import wishbone -from misoc.cores.spi import SPIMachine - - -class SPIMaster(Module): - """SPI Master. - - Notes: - * M = 32 is the data width (width of the data register, - maximum write bits, maximum read bits) - * Every transfer consists of a write_length 0-M bit write followed - by a read_length 0-M bit read. - * cs_n is asserted at the beginning and deasserted at the end of the - transfer if there is no other transfer pending. - * cs_n handling is agnostic to whether it is one-hot or decoded - somewhere downstream. If it is decoded, "cs_n all deasserted" - should be handled accordingly (no slave selected). - If it is one-hot, asserting multiple slaves should only be attempted - if miso is either not connected between slaves, or open collector, - or correctly multiplexed externally. - * If config.cs_polarity == 0 (cs active low, the default), - "cs_n all deasserted" means "all cs_n bits high". - * cs is not mandatory in pads. Framing and chip selection can also - be handled independently through other means. - * If there is a miso wire in pads, the input and output can be done - with two signals (a.k.a. 4-wire SPI), else mosi must be used for - both output and input (a.k.a. 3-wire SPI) and config.half_duplex - must to be set when reading data is desired. - * For 4-wire SPI only the sum of read_length and write_length matters. - The behavior is the same no matter how the total transfer length is - divided between the two. For 3-wire SPI, the direction of mosi/miso - is switched from output to input after write_len cycles, at the - "shift_out" clk edge corresponding to bit write_length + 1 of the - transfer. - * The first bit output on mosi is always the MSB/LSB (depending on - config.lsb_first) of the data register, independent of - xfer.write_len. The last bit input from miso always ends up in - the LSB/MSB (respectively) of the data register, independent of - read_len. - * Data output on mosi in 4-wire SPI during the read cycles is what - is found in the data register at the time. - Data in the data register outside the least/most (depending - on config.lsb_first) significant read_length bits is what is - seen on miso during the write cycles. - * The SPI data register is double-buffered: Once a transfer has - started, new write data can be written, queuing a new transfer. - Transfers submitted this way are chained and executed without - deasserting cs. Once a transfer completes, the previous transfer's - read data is available in the data register. - * Writes to the config register take effect immediately. Writes to xfer - and data are synchronized to the start of a transfer. - * A wishbone data register write is ack-ed when the transfer has - been written to the intermediate buffer. It will be started when - there are no other transactions being executed, either starting - a new SPI transfer of chained to an in-flight transfer. - Writes take two cycles unless the write is to the data register - and another chained transfer is pending and the transfer being - executed is not complete. Reads always finish in two cycles. - - Transaction Sequence: - * If desired, write the config register to set up the core. - * If desired, write the xfer register to change lengths and cs_n. - * Write the data register (also for zero-length writes), - writing triggers the transfer and when the transfer is accepted to - the inermediate buffer, the write is ack-ed. - * If desired, read the data register corresponding to the last - completed transfer. - * If desired, change xfer register for the next transfer. - * If desired, write data queuing the next (possibly chained) transfer. - - Register address and bit map: - - config (address 2): - 1 offline: all pins high-z (reset=1) - 1 active: cs/transfer active (read-only) - 1 pending: transfer pending in intermediate buffer (read-only) - 1 cs_polarity: active level of chip select (reset=0) - 1 clk_polarity: idle level of clk (reset=0) - 1 clk_phase: first edge after cs assertion to sample data on (reset=0) - (clk_polarity, clk_phase) == (CPOL, CPHA) in Freescale language. - (0, 0): idle low, output on falling, input on rising - (0, 1): idle low, output on rising, input on falling - (1, 0): idle high, output on rising, input on falling - (1, 1): idle high, output on falling, input on rising - There is never a clk edge during a cs edge. - 1 lsb_first: LSB is the first bit on the wire (reset=0) - 1 half_duplex: 3-wire SPI, in/out on mosi (reset=0) - 8 undefined - 8 div_write: counter load value to divide this module's clock - to generate the SPI write clk (reset=0) - f_clk/f_spi_write == div_write + 2 - 8 div_read: ditto for the read clock - - xfer (address 1): - 16 cs: active high bit mask of chip selects to assert (reset=0) - 6 write_len: 0-M bits (reset=0) - 2 undefined - 6 read_len: 0-M bits (reset=0) - 2 undefined - - data (address 0): - M write/read data (reset=0) - """ - def __init__(self, pads, pads_n=None, bus=None): - if bus is None: - bus = wishbone.Interface(data_width=32) - self.bus = bus - - ### - - # Wishbone - config = Record([ - ("offline", 1), - ("active", 1), - ("pending", 1), - ("cs_polarity", 1), - ("clk_polarity", 1), - ("clk_phase", 1), - ("lsb_first", 1), - ("half_duplex", 1), - ("padding", 8), - ("div_write", 8), - ("div_read", 8), - ]) - config.offline.reset = 1 - assert len(config) <= len(bus.dat_w) - - xfer = Record([ - ("cs", 16), - ("write_length", 6), - ("padding0", 2), - ("read_length", 6), - ("padding1", 2), - ]) - assert len(xfer) <= len(bus.dat_w) - - self.submodules.spi = spi = SPIMachine( - data_width=len(bus.dat_w) + 1, - clock_width=len(config.div_read), - bits_width=len(xfer.read_length)) - - pending = Signal() - cs = Signal.like(xfer.cs) - data_read = Signal.like(spi.reg.data) - data_write = Signal.like(spi.reg.data) - - self.comb += [ - spi.start.eq(pending & (~spi.cs | spi.done)), - spi.clk_phase.eq(config.clk_phase), - spi.reg.lsb.eq(config.lsb_first), - spi.div_write.eq(config.div_write), - spi.div_read.eq(config.div_read), - ] - self.sync += [ - If(spi.done, - data_read.eq( - Mux(spi.reg.lsb, spi.reg.data[1:], spi.reg.data[:-1])), - ), - If(spi.start, - cs.eq(xfer.cs), - spi.bits.n_write.eq(xfer.write_length), - spi.bits.n_read.eq(xfer.read_length), - If(spi.reg.lsb, - spi.reg.data[:-1].eq(data_write), - ).Else( - spi.reg.data[1:].eq(data_write), - ), - pending.eq(0), - ), - # wb.ack a transaction if any of the following: - # a) reading, - # b) writing to non-data register - # c) writing to data register and no pending transfer - # d) writing to data register and pending and swapping buffers - bus.ack.eq(bus.cyc & bus.stb & - (~bus.we | (bus.adr != 0) | ~pending | spi.done)), - If(bus.cyc & bus.stb, - bus.dat_r.eq( - Array([data_read, xfer.raw_bits(), config.raw_bits() - ])[bus.adr]), - ), - If(bus.ack, - bus.ack.eq(0), - If(bus.we, - Array([data_write, xfer.raw_bits(), config.raw_bits() - ])[bus.adr].eq(bus.dat_w), - If(bus.adr == 0, # data register - pending.eq(1), - ), - ), - ), - config.active.eq(spi.cs), - config.pending.eq(pending), - ] - - # I/O - mosi_oe = Signal() - clk = Signal() - self.comb += [ - mosi_oe.eq( - ~config.offline & spi.cs & - (spi.oe | ~config.half_duplex)), - ] - self.sync += [ - If(spi.cg.ce & spi.cg.edge, - clk.eq((~spi.cg.clk & spi.cs_next) ^ config.clk_polarity) - ) - ] - - if pads_n is None: - if hasattr(pads, "cs_n"): - cs_n_t = TSTriple(len(pads.cs_n)) - self.specials += cs_n_t.get_tristate(pads.cs_n) - self.comb += [ - cs_n_t.oe.eq(~config.offline), - cs_n_t.o.eq((cs & Replicate(spi.cs, len(cs))) ^ - Replicate(~config.cs_polarity, len(cs))), - ] - - clk_t = TSTriple() - self.specials += clk_t.get_tristate(pads.clk) - self.comb += [ - clk_t.oe.eq(~config.offline), - clk_t.o.eq(clk), - ] - - mosi_t = TSTriple() - self.specials += mosi_t.get_tristate(pads.mosi) - self.comb += [ - mosi_t.oe.eq(mosi_oe), - mosi_t.o.eq(spi.reg.o), - spi.reg.i.eq(Mux(config.half_duplex, mosi_t.i, - getattr(pads, "miso", mosi_t.i))), - ] - else: - if hasattr(pads, "cs_n"): - for i in range(len(pads.cs_n)): - self.specials += Instance("OBUFTDS", - i_I=(cs[i] & spi.cs) ^ ~config.cs_polarity, - i_T=config.offline, - o_O=pads.cs_n[i], o_OB=pads_n.cs_n[i]) - - self.specials += Instance("OBUFTDS", - i_I=clk, i_T=config.offline, - o_O=pads.clk, o_OB=pads_n.clk) - - mosi = Signal() - self.specials += Instance("IOBUFDS_INTERMDISABLE", - p_DIFF_TERM="TRUE", - p_IBUF_LOW_PWR="FALSE", - p_USE_IBUFDISABLE="TRUE", - i_IBUFDISABLE=config.offline | mosi_oe, - i_INTERMDISABLE=config.offline | mosi_oe, - o_O=mosi, i_I=spi.reg.o, i_T=~mosi_oe, - io_IO=pads.mosi, io_IOB=pads_n.mosi) - if hasattr(pads, "miso"): - miso = Signal() - self.specials += Instance("IBUFDS_INTERMDISABLE", - p_DIFF_TERM="TRUE", - p_IBUF_LOW_PWR="FALSE", - p_USE_IBUFDISABLE="TRUE", - i_IBUFDISABLE=config.offline, - i_INTERMDISABLE=config.offline, - o_O=miso, i_I=pads.miso, i_IB=pads_n.miso) - else: - miso = mosi - self.comb += spi.reg.i.eq(Mux(config.half_duplex, mosi, miso)) - - -SPI_DATA_ADDR, SPI_XFER_ADDR, SPI_CONFIG_ADDR = range(3) -( - SPI_OFFLINE, - SPI_ACTIVE, - SPI_PENDING, - SPI_CS_POLARITY, - SPI_CLK_POLARITY, - SPI_CLK_PHASE, - SPI_LSB_FIRST, - SPI_HALF_DUPLEX, -) = (1 << i for i in range(8)) - - -def SPI_DIV_WRITE(i): - return i << 16 - - -def SPI_DIV_READ(i): - return i << 24 - - -def SPI_CS(i): - return i << 0 - - -def SPI_WRITE_LENGTH(i): - return i << 16 - - -def SPI_READ_LENGTH(i): - return i << 24 - - -def _test_xfer(bus, cs, wlen, rlen, wdata): - yield from bus.write(SPI_XFER_ADDR, SPI_CS(cs) | - SPI_WRITE_LENGTH(wlen) | SPI_READ_LENGTH(rlen)) - yield from bus.write(SPI_DATA_ADDR, wdata) - yield - - -def _test_read(bus, sync=SPI_ACTIVE | SPI_PENDING): - while (yield from bus.read(SPI_CONFIG_ADDR)) & sync: - pass - return (yield from bus.read(SPI_DATA_ADDR)) - - -def _test_gen(bus): - yield from bus.write(SPI_CONFIG_ADDR, - 0*SPI_CLK_PHASE | 0*SPI_LSB_FIRST | - 1*SPI_HALF_DUPLEX | - SPI_DIV_WRITE(3) | SPI_DIV_READ(5)) - yield from _test_xfer(bus, 0b01, 4, 0, 0x90000000) - print(hex((yield from _test_read(bus)))) - yield from _test_xfer(bus, 0b10, 0, 4, 0x90000000) - print(hex((yield from _test_read(bus)))) - yield from _test_xfer(bus, 0b11, 4, 4, 0x81000000) - print(hex((yield from _test_read(bus)))) - yield from _test_xfer(bus, 0b01, 8, 32, 0x87654321) - yield from _test_xfer(bus, 0b01, 0, 32, 0x12345678) - print(hex((yield from _test_read(bus, SPI_PENDING)))) - print(hex((yield from _test_read(bus, SPI_ACTIVE)))) - return - for cpol, cpha, lsb, clk in product( - (0, 1), (0, 1), (0, 1), (0, 1)): - yield from bus.write(SPI_CONFIG_ADDR, - cpol*SPI_CLK_POLARITY | cpha*SPI_CLK_PHASE | - lsb*SPI_LSB_FIRST | SPI_DIV_WRITE(clk) | - SPI_DIV_READ(clk)) - for wlen, rlen, wdata in product((0, 8, 32), (0, 8, 32), - (0, 0xffffffff, 0xdeadbeef)): - rdata = (yield from _test_xfer(bus, 0b1, wlen, rlen, wdata, True)) - len = (wlen + rlen) % 32 - mask = (1 << len) - 1 - if lsb: - shift = (wlen + rlen) % 32 - else: - shift = 0 - a = (wdata >> wshift) & wmask - b = (rdata >> rshift) & rmask - if a != b: - print("ERROR", end=" ") - print(cpol, cpha, lsb, clk, wlen, rlen, - hex(wdata), hex(rdata), hex(a), hex(b)) - - -class _TestPads: - def __init__(self): - self.cs_n = Signal(2) - self.clk = Signal() - self.mosi = Signal() - self.miso = Signal() - - -class _TestTristate(Module): - def __init__(self, t): - oe = Signal() - self.comb += [ - t.target.eq(t.o), - oe.eq(t.oe), - t.i.eq(t.o), - ] - -if __name__ == "__main__": - from migen.fhdl.specials import Tristate - - pads = _TestPads() - dut = SPIMaster(pads) - dut.comb += pads.miso.eq(pads.mosi) - # from migen.fhdl.verilog import convert - # print(convert(dut)) - - Tristate.lower = _TestTristate - run_simulation(dut, _test_gen(dut.bus), vcd_name="spi_master.vcd") diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index a77244da2..e55d6a79f 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -27,12 +27,6 @@ These drivers are for the core device and the peripherals closely integrated int .. automodule:: artiq.coredevice.dma :members: -:mod:`artiq.coredevice.spi` module ----------------------------------- - -.. automodule:: artiq.coredevice.spi - :members: - :mod:`artiq.coredevice.spi2` module ----------------------------------- diff --git a/doc/manual/rtio.rst b/doc/manual/rtio.rst index f62c3b57d..33c03c10f 100644 --- a/doc/manual/rtio.rst +++ b/doc/manual/rtio.rst @@ -76,7 +76,7 @@ The sequence is exactly equivalent to:: ttl.pulse(2*us) -The :meth:`artiq.coredevice.ttl.TTLOut.pulse` method advances the timeline cursor (using ``delay()``) while other methods such as :meth:`artiq.coredevice.ttl.TTLOut.on`, :meth:`artiq.coredevice.ttl.TTLOut.off`, :meth:`artiq.coredevice.dds._DDSGeneric.set`, or the ``set_*()`` methods of :class:`artiq.coredevice.spi.SPIMaster` do not. The latter are called *zero-duration* methods. +The :meth:`artiq.coredevice.ttl.TTLOut.pulse` method advances the timeline cursor (using ``delay()``) while other methods such as :meth:`artiq.coredevice.ttl.TTLOut.on`, :meth:`artiq.coredevice.ttl.TTLOut.off`, :meth:`artiq.coredevice.dds._DDSGeneric.set`. The latter are called *zero-duration* methods. Underflow exceptions -------------------- From a6ae08d8b899a0f8fe93f1f0e3b0466205b0d5ba Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 28 Feb 2018 21:00:01 +0100 Subject: [PATCH 0432/2457] firmware/spi: work around cs_polarity semantics The semantics differ between the RTIO and CSR interface. --- artiq/firmware/libboard_artiq/spi.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/spi.rs b/artiq/firmware/libboard_artiq/spi.rs index 94773b690..c18daffc7 100644 --- a/artiq/firmware/libboard_artiq/spi.rs +++ b/artiq/firmware/libboard_artiq/spi.rs @@ -10,9 +10,16 @@ mod imp { while csr::converter_spi::idle_read() == 0 {} csr::converter_spi::offline_write(flags >> 0 & 1); csr::converter_spi::end_write(flags >> 1 & 1); - /* input (in RTIO): flags >> 2 & 1 */ - /* cs_polarity is a mask in the CSR interface */ - csr::converter_spi::cs_polarity_write(0xff & (flags >> 3 & 1)); + // input (in RTIO): flags >> 2 & 1 + // cs_polarity is a mask in the CSR interface + // only affect the bits that are selected + let mut cs_polarity = csr::converter_spi::cs_polarity_read(); + if flags >> 3 & 1 != 0 { + cs_polarity |= cs; + } else { + cs_polarity &= !cs; + } + csr::converter_spi::cs_polarity_write(cs_polarity); csr::converter_spi::clk_polarity_write(flags >> 4 & 1); csr::converter_spi::clk_phase_write(flags >> 5 & 1); csr::converter_spi::lsb_first_write(flags >> 6 & 1); From a04a36ee369906b4cc0330571653acd31328819e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 1 Mar 2018 11:37:33 +0100 Subject: [PATCH 0433/2457] firmware: move wait for write completion to read() --- artiq/firmware/libboard_artiq/ad9154.rs | 2 +- artiq/firmware/libboard_artiq/hmc830_7043.rs | 3 +-- artiq/firmware/libboard_artiq/spi.rs | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index a50d55ab8..9cd40b169 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -22,13 +22,13 @@ fn write(addr: u16, data: u8) { while csr::converter_spi::writable_read() == 0 {} csr::converter_spi::data_write( ((addr as u32) << 16) | ((data as u32) << 8)); - while csr::converter_spi::writable_read() == 0 {} } } fn read(addr: u16) -> u8 { unsafe { write((1 << 15) | addr, 0); + while csr::converter_spi::writable_read() == 0 {} csr::converter_spi::data_read() as u8 } } diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 16e9c3e7d..44bf0f967 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -78,7 +78,6 @@ mod hmc830 { unsafe { while csr::converter_spi::writable_read() == 0 {} csr::converter_spi::data_write(val << 1); // last clk cycle loads data - while csr::converter_spi::writable_read() == 0 {} } } @@ -88,6 +87,7 @@ mod hmc830 { // the SPI round trip delay and stick with CPHA=0 write((1 << 6) | addr, 0); unsafe { + while csr::converter_spi::writable_read() == 0 {} csr::converter_spi::data_read() & 0xffffff } } @@ -173,7 +173,6 @@ mod hmc7043 { unsafe { while csr::converter_spi::writable_read() == 0 {} csr::converter_spi::data_write(val << 8); - while csr::converter_spi::writable_read() == 0 {} } } diff --git a/artiq/firmware/libboard_artiq/spi.rs b/artiq/firmware/libboard_artiq/spi.rs index c18daffc7..a48f77239 100644 --- a/artiq/firmware/libboard_artiq/spi.rs +++ b/artiq/firmware/libboard_artiq/spi.rs @@ -7,7 +7,7 @@ mod imp { return Err(()) } unsafe { - while csr::converter_spi::idle_read() == 0 {} + while csr::converter_spi::writable_read() == 0 {} csr::converter_spi::offline_write(flags >> 0 & 1); csr::converter_spi::end_write(flags >> 1 & 1); // input (in RTIO): flags >> 2 & 1 @@ -38,7 +38,6 @@ mod imp { unsafe { while csr::converter_spi::writable_read() == 0 {} csr::converter_spi::data_write(data); - while csr::converter_spi::writable_read() == 0 {} } Ok(()) } @@ -48,6 +47,7 @@ mod imp { return Err(()) } Ok(unsafe { + while csr::converter_spi::writable_read() == 0 {} csr::converter_spi::data_read() }) } From abd160d143233b7170e3403a8c5f7355402c7e02 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 1 Mar 2018 19:52:27 +0800 Subject: [PATCH 0434/2457] slave_fpga: check DONE before loading --- artiq/firmware/libboard_artiq/slave_fpga.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/slave_fpga.rs b/artiq/firmware/libboard_artiq/slave_fpga.rs index 9f97039b3..1de245ce0 100644 --- a/artiq/firmware/libboard_artiq/slave_fpga.rs +++ b/artiq/firmware/libboard_artiq/slave_fpga.rs @@ -39,17 +39,20 @@ pub fn load() -> Result<(), &'static str> { info!("Slave FPGA gateware length: 0x{:06x}", length); unsafe { - csr::slave_fpga_cfg::oe_write(CCLK_BIT | DIN_BIT | PROGRAM_B_BIT); + if csr::slave_fpga_cfg::in_read() & DONE_BIT != 0 { + info!("Slave FPGA is DONE before loading"); + } csr::slave_fpga_cfg::out_write(0); + csr::slave_fpga_cfg::oe_write(CCLK_BIT | DIN_BIT | PROGRAM_B_BIT); clock::spin_us(1_000); // TPROGRAM=250ns min, be_generous if csr::slave_fpga_cfg::in_read() & INIT_B_BIT != 0 { return Err("Slave FPGA did not react to PROGRAM."); } csr::slave_fpga_cfg::out_write(PROGRAM_B_BIT); - clock::spin_us(5_000); // TPL=5ms max + clock::spin_us(10_000); // TPL=5ms max if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { - return Err("Slave FPGA did finish INITialization."); + return Err("Slave FPGA did not finish INITialization."); } for i in slice::from_raw_parts(GATEWARE.offset(8), length) { From de63e657b8f39c215a62d26322f19ac8aa499d78 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 1 Mar 2018 14:49:48 +0100 Subject: [PATCH 0435/2457] kasli/si5324: lock to 100 MHz with highest available bandwidth --- artiq/firmware/runtime/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 3066ea9b3..b2756ff31 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -113,7 +113,7 @@ fn startup() { #[cfg(si5324_as_synthesizer)] fn setup_si5324_as_synthesizer() { - // 125MHz output, from 100MHz CLKIN2 reference, 9 Hz + // 125MHz output, from 100MHz CLKIN2 reference, 586 Hz #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref))] const SI5324_SETTINGS: board_artiq::si5324::FrequencySettings = board_artiq::si5324::FrequencySettings { @@ -123,7 +123,7 @@ fn setup_si5324_as_synthesizer() n2_ls : 260, n31 : 65, n32 : 52, - bwsel : 10, + bwsel : 4, crystal_ref: false }; // 125MHz output, from crystal, 7 Hz From 1c57d27ae23366b9542d8dc3db04519a20861320 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 1 Mar 2018 18:32:19 +0100 Subject: [PATCH 0436/2457] slave_fpga: use sayma_rtm magic --- artiq/firmware/libboard_artiq/slave_fpga.rs | 31 +++++++++++---------- artiq/frontend/artiq_flash.py | 2 +- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/artiq/firmware/libboard_artiq/slave_fpga.rs b/artiq/firmware/libboard_artiq/slave_fpga.rs index 1de245ce0..3046fec31 100644 --- a/artiq/firmware/libboard_artiq/slave_fpga.rs +++ b/artiq/firmware/libboard_artiq/slave_fpga.rs @@ -28,46 +28,49 @@ pub fn load() -> Result<(), &'static str> { info!("Loading slave FPGA gateware..."); let header = unsafe { slice::from_raw_parts(GATEWARE, 8) }; - let magic = BigEndian::read_u32(&header[0..]); - let length = BigEndian::read_u32(&header[4..]) as usize; - if magic != 0x53415231 { // "SAR1" - return Err("Slave FPGA gateware magic not found"); - } else if length > 0x220000 { - return Err("Slave FPGA gateware too large (corrupted?)"); + let magic = BigEndian::read_u32(&header[0..]); + info!("Magic: 0x{:08x}", magic); + if magic != 0x5352544d { // "SRTM", see sayma_rtm target as well + return Err("Bad magic"); + } + + let length = BigEndian::read_u32(&header[4..]) as usize; + info!("Length: 0x{:08x}", length); + if length > 0x220000 { + return Err("Too large (corrupted?)"); } - info!("Slave FPGA gateware length: 0x{:06x}", length); unsafe { if csr::slave_fpga_cfg::in_read() & DONE_BIT != 0 { - info!("Slave FPGA is DONE before loading"); + info!("DONE before loading"); } csr::slave_fpga_cfg::out_write(0); csr::slave_fpga_cfg::oe_write(CCLK_BIT | DIN_BIT | PROGRAM_B_BIT); clock::spin_us(1_000); // TPROGRAM=250ns min, be_generous if csr::slave_fpga_cfg::in_read() & INIT_B_BIT != 0 { - return Err("Slave FPGA did not react to PROGRAM."); + return Err("Did not react to PROGRAM"); } csr::slave_fpga_cfg::out_write(PROGRAM_B_BIT); clock::spin_us(10_000); // TPL=5ms max if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { - return Err("Slave FPGA did not finish INITialization."); + return Err("Did not exit INIT"); } for i in slice::from_raw_parts(GATEWARE.offset(8), length) { shift_u8(*i); if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { - return Err("Slave FPGA error: INIT_B went low."); + return Err("INIT asserted during load"); } } let t = clock::get_ms(); while csr::slave_fpga_cfg::in_read() & DONE_BIT == 0 { if clock::get_ms() > t + 100 { - error!("Slave FPGA not DONE after loading"); - error!("Corrupt gateware? Slave FPGA in slave serial mode?"); - return Err("Slave FPGA not DONE"); + error!("Timeout wating for DONE after loading"); + error!("Boards not populated correctly?"); + return Err("Not DONE"); } shift_u8(0xff); } diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index bfa71d8f5..2cd673896 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -319,7 +319,7 @@ def main(): bin_file.write(b"\x00"*8) bit2bin(bit_file, bin_file) if header: - magic = 0x53415231 # "SAR1" + magic = 0x5352544d # "SRTM", see sayma_rtm target length = bin_file.tell() - 8 bin_file.seek(0) bin_file.write(magic.to_bytes(4, byteorder="big")) From a9daaad77bcfc5afe7be61687daaf472b2872c7c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 2 Mar 2018 14:44:31 +0800 Subject: [PATCH 0437/2457] kasli: add SYSU variant and device_db --- artiq/examples/kasli_sysu/device_db.py | 125 ++++++++++++++++++ artiq/examples/kasli_sysu/idle_kernel.py | 21 +++ .../examples/kasli_sysu/repository/urukul.py | 49 +++++++ artiq/gateware/targets/kasli.py | 57 +++++++- 4 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 artiq/examples/kasli_sysu/device_db.py create mode 100644 artiq/examples/kasli_sysu/idle_kernel.py create mode 100644 artiq/examples/kasli_sysu/repository/urukul.py diff --git a/artiq/examples/kasli_sysu/device_db.py b/artiq/examples/kasli_sysu/device_db.py new file mode 100644 index 000000000..1539994a9 --- /dev/null +++ b/artiq/examples/kasli_sysu/device_db.py @@ -0,0 +1,125 @@ +core_addr = "kasli-1.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + +for i in range(40): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": i}, + } + +device_db.update( + spi_urukul0={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 40} + }, + ttl_urukul0_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 41} + }, + ttl_urukul0_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 42} + }, + ttl_urukul0_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 43} + }, + ttl_urukul0_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 44} + }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 45} + }, + urukul0_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul0_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } + +device_db.update( + led0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 46} + }, + led1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 47} + } +) diff --git a/artiq/examples/kasli_sysu/idle_kernel.py b/artiq/examples/kasli_sysu/idle_kernel.py new file mode 100644 index 000000000..05184f731 --- /dev/null +++ b/artiq/examples/kasli_sysu/idle_kernel.py @@ -0,0 +1,21 @@ +from artiq.experiment import * + + +class IdleKernel(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("led0") + + @kernel + def run(self): + start_time = now_mu() + self.core.seconds_to_mu(500*ms) + while self.core.get_rtio_counter_mu() < start_time: + pass + self.core.reset() + while True: + self.led0.pulse(250*ms) + delay(125*ms) + self.led0.pulse(125*ms) + delay(125*ms) + self.led0.pulse(125*ms) + delay(250*ms) diff --git a/artiq/examples/kasli_sysu/repository/urukul.py b/artiq/examples/kasli_sysu/repository/urukul.py new file mode 100644 index 000000000..39b8ea3c2 --- /dev/null +++ b/artiq/examples/kasli_sysu/repository/urukul.py @@ -0,0 +1,49 @@ +from artiq.experiment import * + + +class UrukulTest(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("urukul0_cpld") + self.setattr_device("urukul0_ch0") + self.setattr_device("urukul0_ch1") + self.setattr_device("urukul0_ch2") + self.setattr_device("urukul0_ch3") + self.setattr_device("led0") + + @kernel + def run(self): + self.core.reset() + self.led0.on() + delay(5*ms) + self.led0.off() + + self.urukul0_cpld.init() + self.urukul0_ch0.init() + self.urukul0_ch1.init() + self.urukul0_ch2.init() + self.urukul0_ch3.init() + + delay(1000*us) + self.urukul0_ch0.set(100*MHz) + self.urukul0_ch0.sw.on() + self.urukul0_ch0.set_att(10.) + + delay(1000*us) + self.urukul0_ch1.set(10*MHz, 0.5) + self.urukul0_ch1.sw.on() + self.urukul0_ch1.set_att(0.) + + delay(1000*us) + self.urukul0_ch2.set(400*MHz) + self.urukul0_ch2.sw.on() + self.urukul0_ch2.set_att(0.) + + delay(1000*us) + self.urukul0_ch3.set(1*MHz) + self.urukul0_ch3.sw.on() + self.urukul0_ch3.set_att(20.) + + while True: + self.urukul0_ch0.sw.pulse(5*ms) + delay(5*ms) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 5855664d3..bd97fe36f 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -304,6 +304,59 @@ class Opticlock(_StandaloneBase): self.add_rtio(rtio_channels) +class SYSU(_StandaloneBase): + def __init__(self, **kwargs): + _StandaloneBase.__init__(self, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + + platform = self.platform + platform.add_extension(_urukul("eem1", "eem0")) + platform.add_extension(_dio("eem2")) + platform.add_extension(_dio("eem3")) + platform.add_extension(_dio("eem4")) + platform.add_extension(_dio("eem5")) + platform.add_extension(_dio("eem6")) + + # EEM clock fan-out from Si5324, not MMCX + self.comb += platform.request("clk_sel").eq(1) + + rtio_channels = [] + for i in range(40): + eem_offset, port = divmod(i, 8) + pads = platform.request("eem{}".format(2 + eem_offset), port) + phy = ttl_serdes_7series.InOut_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + phy = spi2.SPIMaster(self.platform.request("eem1_spi_p"), + self.platform.request("eem1_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + pads = platform.request("eem1_dds_reset") + self.specials += DifferentialOutput(0, pads.p, pads.n) + + for signal in "io_update sw0 sw1 sw2 sw3".split(): + pads = platform.request("eem1_{}".format(signal)) + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + for i in (1, 2): + sfp_ctl = platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) + rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(rtio_channels) + + class Master(MiniSoC, AMPSoC): mem_map = { "cri_con": 0x10000000, @@ -542,13 +595,15 @@ def main(): soc_kasli_args(parser) parser.set_defaults(output_dir="artiq_kasli") parser.add_argument("-V", "--variant", default="opticlock", - help="variant: opticlock/master/satellite " + help="variant: opticlock/sysu/master/satellite " "(default: %(default)s)") args = parser.parse_args() variant = args.variant.lower() if variant == "opticlock": cls = Opticlock + elif variant == "sysu": + cls = SYSU elif variant == "master": cls = Master elif variant == "satellite": From 29d42f4648fb1b28a851319688ff20fba0ad1744 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 2 Mar 2018 15:49:41 +0800 Subject: [PATCH 0438/2457] artiq_flash: add kasli sysu --- artiq/frontend/artiq_flash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 2cd673896..0a1e9e10a 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -265,7 +265,7 @@ def main(): }, "kasli": { "programmer": partial(ProgrammerXC7, board="kasli", proxy="bscan_spi_xc7a100t.bit"), - "variants": ["opticlock", "master", "satellite"], + "variants": ["opticlock", "sysu", "master", "satellite"], "gateware": ("spi0", 0x000000), "bootloader": ("spi0", 0x400000), "storage": ("spi0", 0x440000), From 5e074f83ac333922f4b5eb16195b559085e1cef5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 2 Mar 2018 16:05:12 +0800 Subject: [PATCH 0439/2457] examples: update kasli sysu --- artiq/examples/kasli_sysu/idle_kernel.py | 21 --------------- .../repository/{urukul.py => demo.py} | 27 ++++++++++--------- 2 files changed, 15 insertions(+), 33 deletions(-) delete mode 100644 artiq/examples/kasli_sysu/idle_kernel.py rename artiq/examples/kasli_sysu/repository/{urukul.py => demo.py} (62%) diff --git a/artiq/examples/kasli_sysu/idle_kernel.py b/artiq/examples/kasli_sysu/idle_kernel.py deleted file mode 100644 index 05184f731..000000000 --- a/artiq/examples/kasli_sysu/idle_kernel.py +++ /dev/null @@ -1,21 +0,0 @@ -from artiq.experiment import * - - -class IdleKernel(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("led0") - - @kernel - def run(self): - start_time = now_mu() + self.core.seconds_to_mu(500*ms) - while self.core.get_rtio_counter_mu() < start_time: - pass - self.core.reset() - while True: - self.led0.pulse(250*ms) - delay(125*ms) - self.led0.pulse(125*ms) - delay(125*ms) - self.led0.pulse(125*ms) - delay(250*ms) diff --git a/artiq/examples/kasli_sysu/repository/urukul.py b/artiq/examples/kasli_sysu/repository/demo.py similarity index 62% rename from artiq/examples/kasli_sysu/repository/urukul.py rename to artiq/examples/kasli_sysu/repository/demo.py index 39b8ea3c2..bdb3b9361 100644 --- a/artiq/examples/kasli_sysu/repository/urukul.py +++ b/artiq/examples/kasli_sysu/repository/demo.py @@ -10,13 +10,13 @@ class UrukulTest(EnvExperiment): self.setattr_device("urukul0_ch2") self.setattr_device("urukul0_ch3") self.setattr_device("led0") + self.ttl = self.get_device("ttl16") @kernel def run(self): self.core.reset() - self.led0.on() - delay(5*ms) - self.led0.off() + self.ttl.output() + delay(1*us) self.urukul0_cpld.init() self.urukul0_ch0.init() @@ -25,25 +25,28 @@ class UrukulTest(EnvExperiment): self.urukul0_ch3.init() delay(1000*us) - self.urukul0_ch0.set(100*MHz) + self.urukul0_ch0.set(10*MHz) self.urukul0_ch0.sw.on() self.urukul0_ch0.set_att(10.) delay(1000*us) - self.urukul0_ch1.set(10*MHz, 0.5) + self.urukul0_ch1.set(20*MHz, 0.5) self.urukul0_ch1.sw.on() - self.urukul0_ch1.set_att(0.) + self.urukul0_ch1.set_att(8.) delay(1000*us) - self.urukul0_ch2.set(400*MHz) + self.urukul0_ch2.set(30*MHz) self.urukul0_ch2.sw.on() - self.urukul0_ch2.set_att(0.) + self.urukul0_ch2.set_att(6.) delay(1000*us) - self.urukul0_ch3.set(1*MHz) + self.urukul0_ch3.set(40*MHz) self.urukul0_ch3.sw.on() - self.urukul0_ch3.set_att(20.) + self.urukul0_ch3.set_att(4.) while True: - self.urukul0_ch0.sw.pulse(5*ms) - delay(5*ms) + with parallel: + self.ttl.pulse(100*ms) + self.urukul0_ch0.sw.pulse(100*ms) + delay(100*ms) + self.led0.pulse(100*ms) From ddcc68cff9f52224150f00e42e46fdb107d24e49 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 2 Mar 2018 18:10:57 +0800 Subject: [PATCH 0440/2457] sayma_amc: move bitstream options to migen close #930 --- artiq/gateware/targets/sayma_amc.py | 5 ----- conda/artiq-dev/meta.yaml | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index c19b4a653..22038b355 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -146,11 +146,6 @@ class Standalone(MiniSoC, AMPSoC): **kwargs) AMPSoC.__init__(self) platform = self.platform - platform.toolchain.bitstream_commands.extend([ - "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]", - "set_property CFGBVS VCCO [current_design]", - "set_property CONFIG_VOLTAGE 3.3 [current_design]", - ]) # forward RTM UART to second FTDI UART channel serial_1 = platform.request("serial", 1) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 7d50b6684..c3a5342be 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_10+git0996e0b + - migen 0.7 py35_14+git8fcd67a - misoc 0.9 py35_20+git5fed1095 - jesd204b 0.5 - microscope From abfbadebb50513388c8da16a4bbe7dfc7b5c548e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 3 Mar 2018 13:14:34 +0800 Subject: [PATCH 0441/2457] doc: DMA can also raise RTIOUnderflow --- artiq/coredevice/exceptions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index de86baf25..440be95f3 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -71,8 +71,8 @@ class CacheError(Exception): class RTIOUnderflow(Exception): - """Raised when the CPU fails to submit a RTIO event early enough - (with respect to the event's timestamp). + """Raised when the CPU or DMA core fails to submit a RTIO event early + enough (with respect to the event's timestamp). The offending event is discarded and the RTIO core keeps operating. """ From ba74013e3e82d4c75dfba34b9e5d0d7bd9030672 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 3 Mar 2018 13:16:18 +0800 Subject: [PATCH 0442/2457] runtime: add a missing overflow flag reset --- artiq/firmware/ksupport/rtio.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index f53243b46..4d8b251a0 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -93,6 +93,7 @@ mod imp { } if status & RTIO_I_STATUS_OVERFLOW != 0 { + csr::rtio::i_overflow_reset_write(1); raise!("RTIOOverflow", "RTIO input overflow on channel {0}", channel as i64, 0, 0); From 928d5dc9b30e9db1329db76cd2b8b60f79d36dcc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 4 Mar 2018 01:02:53 +0800 Subject: [PATCH 0443/2457] drtio: raise RTIOLinkError if operation fails due to link lost (#942) --- artiq/coredevice/exceptions.py | 7 +++++ artiq/firmware/ksupport/lib.rs | 18 ++++++++---- artiq/firmware/ksupport/rtio.rs | 19 +++++++++++- artiq/firmware/runtime/rtio_mgt.rs | 31 +++++++------------- artiq/firmware/satman/main.rs | 8 ++--- artiq/gateware/drtio/link_layer.py | 26 ++++++++-------- artiq/gateware/drtio/rt_controller_master.py | 10 +++++-- artiq/gateware/rtio/cri.py | 11 +++---- artiq/gateware/rtio/dma.py | 24 +++++++++++---- artiq/gateware/test/drtio/test_full_stack.py | 13 +++++--- artiq/gateware/test/rtio/test_dma.py | 7 +++-- 11 files changed, 112 insertions(+), 62 deletions(-) diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index 440be95f3..f0ce65291 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -90,6 +90,13 @@ class RTIOOverflow(Exception): artiq_builtin = True +class RTIOLinkError(Exception): + """Raised with a RTIO operation could not be completed due to a DRTIO link + being down. + """ + artiq_builtin = True + + class DMAError(Exception): """Raised when performing an invalid DMA operation.""" artiq_builtin = True diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 517dac0e9..068f83761 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -384,13 +384,21 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { while csr::rtio_dma::enable_read() != 0 {} csr::cri_con::selected_write(0); - if csr::rtio_dma::underflow_read() != 0 { + let error = csr::rtio_dma::error_read(); + if error != 0 { let timestamp = csr::rtio_dma::error_timestamp_read(); let channel = csr::rtio_dma::error_channel_read(); - csr::rtio_dma::underflow_write(1); - raise!("RTIOUnderflow", - "RTIO underflow at {0} mu, channel {1}", - timestamp as i64, channel as i64, 0) + csr::rtio_dma::error_write(1); + if error & 1 != 0 { + raise!("RTIOUnderflow", + "RTIO underflow at {0} mu, channel {1}", + timestamp as i64, channel as i64, 0); + } + if error & 2 != 0 { + raise!("RTIOLinkError", + "RTIO output link error at {0} mu, channel {1}", + timestamp as i64, channel as i64, 0); + } } } } diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index 4d8b251a0..7af22169c 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -9,9 +9,11 @@ mod imp { pub const RTIO_O_STATUS_WAIT: u8 = 1; pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2; + pub const RTIO_O_STATUS_LINK_ERROR: u8 = 4; pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1; pub const RTIO_I_STATUS_OVERFLOW: u8 = 2; pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4; + pub const RTIO_I_STATUS_LINK_ERROR: u8 = 8; pub extern fn init() { send(&RtioInitRequest); @@ -45,7 +47,12 @@ mod imp { if status & RTIO_O_STATUS_UNDERFLOW != 0 { raise!("RTIOUnderflow", "RTIO underflow at {0} mu, channel {1}, slack {2} mu", - timestamp, channel as i64, timestamp - get_counter()) + timestamp, channel as i64, timestamp - get_counter()); + } + if status & RTIO_O_STATUS_LINK_ERROR != 0 { + raise!("RTIOLinkError", + "RTIO output link error at {0} mu, channel {1}", + timestamp, channel as i64, 0); } } @@ -101,6 +108,11 @@ mod imp { if status & RTIO_I_STATUS_WAIT_EVENT != 0 { return !0 } + if status & RTIO_I_STATUS_LINK_ERROR != 0 { + raise!("RTIOLinkError", + "RTIO input link error on channel {0}", + channel as i64, 0, 0); + } csr::rtio::i_timestamp_read() } @@ -123,6 +135,11 @@ mod imp { "RTIO input overflow on channel {0}", channel as i64, 0, 0); } + if status & RTIO_I_STATUS_LINK_ERROR != 0 { + raise!("RTIOLinkError", + "RTIO input link error on channel {0}", + channel as i64, 0, 0); + } rtio_i_data_read(0) as i32 } diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index f05c99d09..490535fee 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -50,14 +50,21 @@ pub mod drtio { fn link_rx_up(linkno: u8) -> bool { let linkno = linkno as usize; unsafe { - (csr::DRTIO[linkno].link_status_read)() == 1 + (csr::DRTIO[linkno].rx_up_read)() == 1 } } - fn link_reset(linkno: u8) { + fn link_up(linkno: u8) -> bool { let linkno = linkno as usize; unsafe { - (csr::DRTIO[linkno].reset_write)(1); + (csr::DRTIO[linkno].link_up_read)() == 1 + } + } + + fn set_link_up(linkno: u8, up: bool) { + let linkno = linkno as usize; + unsafe { + (csr::DRTIO[linkno].link_up_write)(if up { 1 } else { 0 }); } } @@ -132,21 +139,6 @@ pub mod drtio { } } - // FIXME: use csr::DRTIO.len(), maybe get rid of static mut as well. - static mut LINK_UP: [bool; 16] = [false; 16]; - - fn link_up(linkno: u8) -> bool { - unsafe { - LINK_UP[linkno as usize] - } - } - - fn set_link_up(linkno: u8, up: bool) { - unsafe { - LINK_UP[linkno as usize] = up - } - } - pub fn link_thread(io: Io) { loop { for linkno in 0..csr::DRTIO.len() { @@ -164,14 +156,13 @@ pub mod drtio { /* link was previously down */ if link_rx_up(linkno) { info!("[LINK#{}] link RX became up, pinging", linkno); - link_reset(linkno); let ping_count = ping_remote(linkno, &io); if ping_count > 0 { info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); + set_link_up(linkno, true); init_buffer_space(linkno); sync_tsc(linkno); info!("[LINK#{}] link initialization completed", linkno); - set_link_up(linkno, true); } else { info!("[LINK#{}] ping failed", linkno); } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 195471457..7e069b752 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -206,9 +206,9 @@ const SI5324_SETTINGS: si5324::FrequencySettings crystal_ref: true }; -fn drtio_link_is_up() -> bool { +fn drtio_link_rx_up() -> bool { unsafe { - (csr::DRTIO[0].link_status_read)() == 1 + (csr::DRTIO[0].rx_up_read)() == 1 } } @@ -231,14 +231,14 @@ fn startup() { } loop { - while !drtio_link_is_up() { + while !drtio_link_rx_up() { process_errors(); } info!("link is up, switching to recovered clock"); si5324::select_ext_input(true).expect("failed to switch clocks"); drtio_reset(false); drtio_reset_phy(false); - while drtio_link_is_up() { + while drtio_link_rx_up() { process_errors(); process_aux_packets(); } diff --git a/artiq/gateware/drtio/link_layer.py b/artiq/gateware/drtio/link_layer.py index 50f2ca6a3..a4779e912 100644 --- a/artiq/gateware/drtio/link_layer.py +++ b/artiq/gateware/drtio/link_layer.py @@ -224,7 +224,7 @@ class LinkLayerRX(Module): class LinkLayer(Module, AutoCSR): def __init__(self, encoder, decoders): - self.link_status = CSRStatus() + self.rx_up = CSRStatus() self.rx_disable = CSRStorage() self.tx_force_aux_zero = CSRStorage() self.tx_force_rt_zero = CSRStorage() @@ -254,14 +254,14 @@ class LinkLayer(Module, AutoCSR): # # # - ready = Signal() - ready_r = Signal() - self.sync.rtio += ready_r.eq(ready) - ready_rx = Signal() - ready_r.attr.add("no_retiming") + rx_up = Signal() + rx_up_r = Signal() + self.sync.rtio += rx_up_r.eq(rx_up) + rx_up_rx = Signal() + rx_up_r.attr.add("no_retiming") self.specials += [ - MultiReg(ready_r, ready_rx, "rtio_rx"), - MultiReg(ready_r, self.link_status.status)] + MultiReg(rx_up_r, rx_up_rx, "rtio_rx"), + MultiReg(rx_up_r, self.rx_up.status)] tx_force_aux_zero_rtio = Signal() tx_force_rt_zero_rtio = Signal() @@ -286,11 +286,11 @@ class LinkLayer(Module, AutoCSR): # to be recaptured by RXSynchronizer. self.sync.rtio_rx += [ self.rx_aux_stb.eq(rx.aux_stb), - self.rx_aux_frame.eq(rx.aux_frame & ready_rx & ~rx_disable_rx), - self.rx_aux_frame_perm.eq(rx.aux_frame & ready_rx), + self.rx_aux_frame.eq(rx.aux_frame & rx_up_rx & ~rx_disable_rx), + self.rx_aux_frame_perm.eq(rx.aux_frame & rx_up_rx), self.rx_aux_data.eq(rx.aux_data), - self.rx_rt_frame.eq(rx.rt_frame & ready_rx & ~rx_disable_rx), - self.rx_rt_frame_perm.eq(rx.rt_frame & ready_rx), + self.rx_rt_frame.eq(rx.rt_frame & rx_up_rx & ~rx_disable_rx), + self.rx_rt_frame_perm.eq(rx.rt_frame & rx_up_rx), self.rx_rt_data.eq(rx.rt_data) ] @@ -308,7 +308,7 @@ class LinkLayer(Module, AutoCSR): If(wait_scrambler.done, NextState("READY")) ) fsm.act("READY", - ready.eq(1), + rx_up.eq(1), If(~self.rx_ready, NextState("WAIT_RX_READY")) ) diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index cb2fcdab6..0cfaaeafc 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -13,7 +13,7 @@ from artiq.gateware.rtio import cri class _CSRs(AutoCSR): def __init__(self): - self.reset = CSR() + self.link_up = CSRStorage() self.protocol_error = CSR(3) @@ -21,7 +21,6 @@ class _CSRs(AutoCSR): self.set_time = CSR() self.underflow_margin = CSRStorage(16, reset=200) - self.o_get_buffer_space = CSR() self.o_dbg_buffer_space = CSRStatus(16) self.o_dbg_buffer_space_req_cnt = CSRStatus(32) @@ -53,7 +52,7 @@ class RTController(Module): # reset local_reset = Signal(reset=1) - self.sync += local_reset.eq(self.csrs.reset.re) + self.sync += local_reset.eq(~self.csrs.link_up.storage) local_reset.attr.add("no_retiming") self.clock_domains.cd_sys_with_rst = ClockDomain() self.clock_domains.cd_rtio_with_rst = ClockDomain() @@ -64,6 +63,11 @@ class RTController(Module): self.comb += self.cd_rtio_with_rst.clk.eq(ClockSignal("rtio")) self.specials += AsyncResetSynchronizer(self.cd_rtio_with_rst, local_reset) + self.comb += [ + self.cri.o_status[2].eq(~self.csrs.link_up.storage), + self.cri.i_status[3].eq(~self.csrs.link_up.storage) + ] + # protocol errors err_unknown_packet_type = Signal() err_packet_truncated = Signal() diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 4885c0219..c85958baa 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -25,8 +25,8 @@ layout = [ ("o_data", 512, DIR_M_TO_S), ("o_address", 16, DIR_M_TO_S), # o_status bits: - # <0:wait> <1:underflow> - ("o_status", 2, DIR_S_TO_M), + # <0:wait> <1:underflow> <2:link error> + ("o_status", 3, DIR_S_TO_M), # targets may optionally report a pessimistic estimate of the number # of outputs events that can be written without waiting. ("o_buffer_space", 16, DIR_S_TO_M), @@ -35,8 +35,9 @@ layout = [ ("i_timestamp", 64, DIR_S_TO_M), # i_status bits: # <0:wait for event (command timeout)> <1:overflow> <2:wait for status> + # <3:link error> # <0> and <1> are mutually exclusive. <1> has higher priority. - ("i_status", 3, DIR_S_TO_M), + ("i_status", 4, DIR_S_TO_M), # value of the timestamp counter transferred into the CRI clock domain. # monotonic, may lag behind the counter in the IO clock domain, but @@ -61,12 +62,12 @@ class KernelInitiator(Module, AutoCSR): self.o_data = CSRStorage(512, write_from_dev=True) self.o_address = CSRStorage(16) self.o_we = CSR() - self.o_status = CSRStatus(2) + self.o_status = CSRStatus(3) self.i_data = CSRStatus(32) self.i_timestamp = CSRStatus(64) self.i_request = CSR() - self.i_status = CSRStatus(3) + self.i_status = CSRStatus(4) self.i_overflow_reset = CSR() self.counter = CSRStatus(64) diff --git a/artiq/gateware/rtio/dma.py b/artiq/gateware/rtio/dma.py index a8b7c9195..735d52f54 100644 --- a/artiq/gateware/rtio/dma.py +++ b/artiq/gateware/rtio/dma.py @@ -242,7 +242,7 @@ class TimeOffset(Module, AutoCSR): class CRIMaster(Module, AutoCSR): def __init__(self): - self.underflow = CSR() + self.error = CSR(2) self.error_channel = CSRStatus(24) self.error_timestamp = CSRStatus(64) @@ -255,14 +255,21 @@ class CRIMaster(Module, AutoCSR): # # # underflow_trigger = Signal() + link_error_trigger = Signal() self.sync += [ If(underflow_trigger, - self.underflow.w.eq(1), + self.error.w.eq(1), self.error_channel.status.eq(self.sink.channel), self.error_timestamp.status.eq(self.sink.timestamp), self.error_address.status.eq(self.sink.address) ), - If(self.underflow.re, self.underflow.w.eq(0)) + If(link_error_trigger, + self.error.w.eq(2), + self.error_channel.status.eq(self.sink.channel), + self.error_timestamp.status.eq(self.sink.timestamp), + self.error_address.status.eq(self.sink.address) + ), + If(self.error.re, self.error.w.eq(0)) ] self.comb += [ @@ -276,7 +283,7 @@ class CRIMaster(Module, AutoCSR): self.submodules += fsm fsm.act("IDLE", - If(~self.underflow.w, + If(self.error.w == 0, If(self.sink.stb, If(self.sink.eop, # last packet contains dummy data, discard it @@ -301,7 +308,8 @@ class CRIMaster(Module, AutoCSR): self.sink.ack.eq(1), NextState("IDLE") ), - If(self.cri.o_status[1], NextState("UNDERFLOW")) + If(self.cri.o_status[1], NextState("UNDERFLOW")), + If(self.cri.o_status[2], NextState("LINK_ERROR")) ) fsm.act("UNDERFLOW", self.busy.eq(1), @@ -309,6 +317,12 @@ class CRIMaster(Module, AutoCSR): self.sink.ack.eq(1), NextState("IDLE") ) + fsm.act("LINK_ERROR", + self.busy.eq(1), + link_error_trigger.eq(1), + self.sink.ack.eq(1), + NextState("IDLE") + ) class DMA(Module): diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 905d188d5..45d6a4441 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -55,6 +55,7 @@ class DUT(Module): self.submodules.master = DRTIOMaster(self.transceivers.alice, fine_ts_width=0) self.submodules.master_ki = rtio.KernelInitiator(self.master.cri) + self.master.rt_controller.csrs.link_up.storage.reset = 1 rx_synchronizer = DummyRXSynchronizer() self.submodules.phy0 = ttl_simple.Output(self.ttl0) @@ -81,7 +82,7 @@ class OutputsTestbench: def init(self): yield from self.dut.master.rt_controller.csrs.underflow_margin.write(100) - while not (yield from self.dut.master.link_layer.link_status.read()): + while not (yield from self.dut.master.link_layer.rx_up.read()): yield yield from self.get_buffer_space() @@ -113,8 +114,10 @@ class OutputsTestbench: wlen = 0 while status: status = yield from kcsrs.o_status.read() - if status & 2: + if status & 0x2: raise RTIOUnderflow + if status & 0x4: + raise RTIOLinkError yield wlen += 1 return wlen @@ -251,11 +254,13 @@ class TestFullStack(unittest.TestCase): return "timeout" if status & 0x2: return "overflow" + if status & 0x8: + return "link error" return ((yield from kcsrs.i_data.read()), (yield from kcsrs.i_timestamp.read())) def test(): - while not (yield from dut.master.link_layer.link_status.read()): + while not (yield from dut.master.link_layer.rx_up.read()): yield i1 = yield from get_input(10) @@ -281,7 +286,7 @@ class TestFullStack(unittest.TestCase): mgr = dut.master.rt_manager def test(): - while not (yield from dut.master.link_layer.link_status.read()): + while not (yield from dut.master.link_layer.rx_up.read()): yield yield from mgr.update_packet_cnt.write(1) diff --git a/artiq/gateware/test/rtio/test_dma.py b/artiq/gateware/test/rtio/test_dma.py index d0e74b5ea..9ad6fd6d9 100644 --- a/artiq/gateware/test/rtio/test_dma.py +++ b/artiq/gateware/test/rtio/test_dma.py @@ -5,7 +5,7 @@ import itertools from migen import * from misoc.interconnect import wishbone -from artiq.coredevice.exceptions import RTIOUnderflow +from artiq.coredevice.exceptions import RTIOUnderflow, RTIOLinkError from artiq.gateware import rtio from artiq.gateware.rtio import dma, cri from artiq.gateware.rtio.phy import ttl_simple @@ -57,8 +57,11 @@ def do_dma(dut, address): yield while ((yield from dut.enable.read())): yield - if (yield from dut.cri_master.underflow.read()): + error = yield from dut.cri_master.underflow.read() + if error & 1: raise RTIOUnderflow + if error & 2: + raise RTIOLinkError test_writes1 = [ From d747d74cb386ca0c54046906a1c326576714f171 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 4 Mar 2018 23:19:06 +0800 Subject: [PATCH 0444/2457] test: fix test_dma --- artiq/gateware/test/rtio/test_dma.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/test/rtio/test_dma.py b/artiq/gateware/test/rtio/test_dma.py index 9ad6fd6d9..536575b32 100644 --- a/artiq/gateware/test/rtio/test_dma.py +++ b/artiq/gateware/test/rtio/test_dma.py @@ -57,7 +57,7 @@ def do_dma(dut, address): yield while ((yield from dut.enable.read())): yield - error = yield from dut.cri_master.underflow.read() + error = yield from dut.cri_master.error.read() if error & 1: raise RTIOUnderflow if error & 2: From 6aaa8bf9d95d0a337a000c14b0465ee41913bb9e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 4 Mar 2018 23:20:13 +0800 Subject: [PATCH 0445/2457] drtio: fix link error generation --- artiq/gateware/drtio/rt_controller_master.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 0cfaaeafc..ea325a1b8 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -63,11 +63,6 @@ class RTController(Module): self.comb += self.cd_rtio_with_rst.clk.eq(ClockSignal("rtio")) self.specials += AsyncResetSynchronizer(self.cd_rtio_with_rst, local_reset) - self.comb += [ - self.cri.o_status[2].eq(~self.csrs.link_up.storage), - self.cri.i_status[3].eq(~self.csrs.link_up.storage) - ] - # protocol errors err_unknown_packet_type = Signal() err_packet_truncated = Signal() @@ -126,7 +121,7 @@ class RTController(Module): o_status_underflow = Signal() self.comb += [ self.cri.o_status.eq(Cat( - o_status_wait, o_status_underflow)), + o_status_wait, o_status_underflow, ~self.csrs.link_up.storage)), self.csrs.o_wait.status.eq(o_status_wait) ] o_underflow_set = Signal() @@ -151,7 +146,8 @@ class RTController(Module): i_status_overflow = Signal() i_status_wait_status = Signal() self.comb += self.cri.i_status.eq(Cat( - i_status_wait_event, i_status_overflow, i_status_wait_status)) + i_status_wait_event, i_status_overflow, i_status_wait_status, + ~self.csrs.link_up.storage)) load_read_reply = Signal() self.sync.sys_with_rst += [ From 432e61bbb450185fb64d15ce6c078e3425a3f861 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 5 Mar 2018 00:23:55 +0800 Subject: [PATCH 0446/2457] drtio: add kernel API to check for link status. Closes #941 --- artiq/coredevice/core.py | 12 ++++++++++++ artiq/firmware/ksupport/api.rs | 5 +++-- artiq/firmware/ksupport/rtio.rs | 7 ++++++- artiq/firmware/libproto/kernel_proto.rs | 3 +++ artiq/firmware/runtime/kern_hwreq.rs | 5 +++++ artiq/firmware/runtime/rtio_mgt.rs | 9 ++++++++- doc/manual/installing.rst | 2 ++ 7 files changed, 39 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 8f96bb7c9..300085882 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -47,6 +47,10 @@ def rtio_init() -> TNone: def rtio_get_counter() -> TInt64: raise NotImplementedError("syscall not simulated") +@syscall(flags={"nounwind", "nowrite"}) +def drtio_get_link_status(linkno: TInt32) -> TBool: + raise NotImplementedError("syscall not simulated") + class Core: """Core device driver. @@ -155,6 +159,14 @@ class Core: def get_rtio_counter_mu(self): return rtio_get_counter() + @kernel + def get_drtio_link_status(self, linkno): + """Returns whether the specified DRTIO link is up. + + This is particularly useful in startup kernels to delay + startup until certain DRTIO links are up.""" + return drtio_get_link_status(linkno) + @kernel def reset(self): """Clear RTIO FIFOs, release RTIO PHY reset, and set the time cursor diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index b2d608b1f..75b8b928b 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -108,8 +108,9 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(dma_retrieve = ::dma_retrieve), api!(dma_playback = ::dma_playback), - api!(drtio_get_packet_counts = ::rtio::drtio_dbg::get_packet_counts), - api!(drtio_get_buffer_space_req_count = ::rtio::drtio_dbg::get_buffer_space_req_count), + api!(drtio_get_link_status = ::rtio::drtio::get_link_status), + api!(drtio_get_packet_counts = ::rtio::drtio::get_packet_counts), + api!(drtio_get_buffer_space_req_count = ::rtio::drtio::get_buffer_space_req_count), api!(i2c_start = ::nrt_bus::i2c::start), api!(i2c_restart = ::nrt_bus::i2c::restart), diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index 7af22169c..a3afb6d79 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -210,11 +210,16 @@ mod imp { pub use self::imp::*; -pub mod drtio_dbg { +pub mod drtio { use ::send; use ::recv; use kernel_proto::*; + pub extern fn get_link_status(linkno: i32) -> bool { + send(&DrtioLinkStatusRequest { linkno: linkno as u8 }); + recv!(&DrtioLinkStatusReply { up } => up) + } + #[repr(C)] pub struct PacketCounts(i32, i32); diff --git a/artiq/firmware/libproto/kernel_proto.rs b/artiq/firmware/libproto/kernel_proto.rs index babd9fbcf..ae794ec34 100644 --- a/artiq/firmware/libproto/kernel_proto.rs +++ b/artiq/firmware/libproto/kernel_proto.rs @@ -46,6 +46,9 @@ pub enum Message<'a> { duration: u64 }, + DrtioLinkStatusRequest { linkno: u8 }, + DrtioLinkStatusReply { up: bool }, + DrtioPacketCountRequest { linkno: u8 }, DrtioPacketCountReply { tx_cnt: u32, rx_cnt: u32 }, DrtioBufferSpaceReqCountRequest { linkno: u8 }, diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index be1a380e8..b3f77f567 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -300,6 +300,11 @@ pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> io::Result kern_acknowledge() } + #[cfg(has_rtio_core)] + &kern::DrtioLinkStatusRequest { linkno } => { + let up = rtio_mgt::drtio::link_up(linkno); + kern_send(io, &kern::DrtioLinkStatusReply { up: up }) + } #[cfg(has_rtio_core)] &kern::DrtioPacketCountRequest { linkno } => { diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 490535fee..279c9c865 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -54,8 +54,14 @@ pub mod drtio { } } - fn link_up(linkno: u8) -> bool { + pub fn link_up(linkno: u8) -> bool { let linkno = linkno as usize; + /* This function may be called by kernels with arbitrary + * linkno values. + */ + if linkno >= csr::DRTIO.len() { + return false; + } unsafe { (csr::DRTIO[linkno].link_up_read)() == 1 } @@ -195,6 +201,7 @@ mod drtio { pub fn startup(_io: &Io) {} pub fn init() {} + pub fn link_up(_linkno: u8) -> bool { false } } fn async_error_thread(io: Io) { diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index e9a82226c..574af6ac8 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -187,6 +187,8 @@ To flash the idle kernel: The startup kernel is executed once when the core device powers up. It should initialize DDSes, set up TTL directions, etc. Proceed as with the idle kernel, but using the ``startup_kernel`` key in ``artiq_coreconfig``. +For DRTIO systems, the startup kernel should wait until the desired links are up, using :method:`artiq.coredevice.Core.get_drtio_link_status`. + * (optional) Select the startup clock The core device may use either an external clock signal or its internal clock. This clock can be switched dynamically after the PC is connected using the ``external_clock`` parameter of the core device driver; however, one may want to select the clock at power-up so that it is used for the startup and idle kernels. Use one of these commands: :: From a274af77d5d215dd86ee73753b367d3f18a56417 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 5 Mar 2018 00:43:42 +0800 Subject: [PATCH 0447/2457] runtime: fix compilation without DRTIO --- artiq/firmware/runtime/rtio_mgt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 279c9c865..a5778bd59 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -196,7 +196,7 @@ pub mod drtio { } #[cfg(not(has_drtio))] -mod drtio { +pub mod drtio { use super::*; pub fn startup(_io: &Io) {} From 45f1e5a70e591cb757b77139e02174ef446a537d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 6 Mar 2018 10:56:07 +0100 Subject: [PATCH 0448/2457] drtio/gth: cleanup import --- artiq/gateware/drtio/transceiver/gth_ultrascale_init.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py b/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py index 1edd76f34..30645b876 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale_init.py @@ -1,7 +1,7 @@ from math import ceil from migen import * -from migen.genlib.cdc import MultiReg, PulseSynchronizer +from migen.genlib.cdc import MultiReg from migen.genlib.misc import WaitTimer From 64b05f07bbe855852c43a8738f95ac66a14ee204 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 6 Mar 2018 11:00:07 +0100 Subject: [PATCH 0449/2457] drtio/gth: use parameters from Xilinx transceiver wizard --- .../drtio/transceiver/gth_ultrascale.py | 587 ++++++++++++++---- 1 file changed, 470 insertions(+), 117 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index f05f1d626..5c4fcbc25 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -60,134 +60,487 @@ class GTHSingle(Module): txdata = Signal(dw) rxdata = Signal(dw) rxphaligndone = Signal() - self.specials += \ - Instance("GTHE3_CHANNEL", - # Reset modes - i_GTRESETSEL=0, - i_RESETOVRD=0, + gth_params = dict( + p_ACJTAG_DEBUG_MODE =0b0, + p_ACJTAG_MODE =0b0, + p_ACJTAG_RESET =0b0, + p_ADAPT_CFG0 =0b1111100000000000, + p_ADAPT_CFG1 =0b0000000000000000, + p_ALIGN_COMMA_DOUBLE ="FALSE", + p_ALIGN_COMMA_ENABLE =0b0000000000, + p_ALIGN_COMMA_WORD =1, + p_ALIGN_MCOMMA_DET ="FALSE", + p_ALIGN_MCOMMA_VALUE =0b1010000011, + p_ALIGN_PCOMMA_DET ="FALSE", + p_ALIGN_PCOMMA_VALUE =0b0101111100, + p_A_RXOSCALRESET =0b0, + p_A_RXPROGDIVRESET =0b0, + p_A_TXPROGDIVRESET =0b0, + p_CBCC_DATA_SOURCE_SEL ="ENCODED", + p_CDR_SWAP_MODE_EN =0b0, + p_CHAN_BOND_KEEP_ALIGN ="FALSE", + p_CHAN_BOND_MAX_SKEW =1, + p_CHAN_BOND_SEQ_1_1 =0b0000000000, + p_CHAN_BOND_SEQ_1_2 =0b0000000000, + p_CHAN_BOND_SEQ_1_3 =0b0000000000, + p_CHAN_BOND_SEQ_1_4 =0b0000000000, + p_CHAN_BOND_SEQ_1_ENABLE =0b1111, + p_CHAN_BOND_SEQ_2_1 =0b0000000000, + p_CHAN_BOND_SEQ_2_2 =0b0000000000, + p_CHAN_BOND_SEQ_2_3 =0b0000000000, + p_CHAN_BOND_SEQ_2_4 =0b0000000000, + p_CHAN_BOND_SEQ_2_ENABLE =0b1111, + p_CHAN_BOND_SEQ_2_USE ="FALSE", + p_CHAN_BOND_SEQ_LEN =1, + p_CLK_CORRECT_USE ="FALSE", + p_CLK_COR_KEEP_IDLE ="FALSE", + p_CLK_COR_MAX_LAT =20, + p_CLK_COR_MIN_LAT =18, + p_CLK_COR_PRECEDENCE ="TRUE", + p_CLK_COR_REPEAT_WAIT =0, + p_CLK_COR_SEQ_1_1 =0b0000000000, + p_CLK_COR_SEQ_1_2 =0b0000000000, + p_CLK_COR_SEQ_1_3 =0b0000000000, + p_CLK_COR_SEQ_1_4 =0b0000000000, + p_CLK_COR_SEQ_1_ENABLE =0b1111, + p_CLK_COR_SEQ_2_1 =0b0000000000, + p_CLK_COR_SEQ_2_2 =0b0000000000, + p_CLK_COR_SEQ_2_3 =0b0000000000, + p_CLK_COR_SEQ_2_4 =0b0000000000, + p_CLK_COR_SEQ_2_ENABLE =0b1111, + p_CLK_COR_SEQ_2_USE ="FALSE", + p_CLK_COR_SEQ_LEN =1, + p_CPLL_CFG0 =0b0110011111111000, + p_CPLL_CFG1 =0b1010010010101100, + p_CPLL_CFG2 =0b0000000000000111, + p_CPLL_CFG3 =0b000000, + p_CPLL_FBDIV =5, + p_CPLL_FBDIV_45 =4, + p_CPLL_INIT_CFG0 =0b0000001010110010, + p_CPLL_INIT_CFG1 =0b00000000, + p_CPLL_LOCK_CFG =0b0000000111101000, + p_CPLL_REFCLK_DIV =1, + p_DDI_CTRL =0b00, + p_DDI_REALIGN_WAIT =15, + p_DEC_MCOMMA_DETECT ="FALSE", + p_DEC_PCOMMA_DETECT ="FALSE", + p_DEC_VALID_COMMA_ONLY ="FALSE", + p_DFE_D_X_REL_POS =0b0, + p_DFE_VCM_COMP_EN =0b0, + p_DMONITOR_CFG0 =0b0000000000, + p_DMONITOR_CFG1 =0b00000000, + p_ES_CLK_PHASE_SEL =0b0, + p_ES_CONTROL =0b000000, + p_ES_ERRDET_EN ="FALSE", + p_ES_EYE_SCAN_EN ="FALSE", + p_ES_HORZ_OFFSET =0b000000000000, + p_ES_PMA_CFG =0b0000000000, + p_ES_PRESCALE =0b00000, + p_ES_QUALIFIER0 =0b0000000000000000, + p_ES_QUALIFIER1 =0b0000000000000000, + p_ES_QUALIFIER2 =0b0000000000000000, + p_ES_QUALIFIER3 =0b0000000000000000, + p_ES_QUALIFIER4 =0b0000000000000000, + p_ES_QUAL_MASK0 =0b0000000000000000, + p_ES_QUAL_MASK1 =0b0000000000000000, + p_ES_QUAL_MASK2 =0b0000000000000000, + p_ES_QUAL_MASK3 =0b0000000000000000, + p_ES_QUAL_MASK4 =0b0000000000000000, + p_ES_SDATA_MASK0 =0b0000000000000000, + p_ES_SDATA_MASK1 =0b0000000000000000, + p_ES_SDATA_MASK2 =0b0000000000000000, + p_ES_SDATA_MASK3 =0b0000000000000000, + p_ES_SDATA_MASK4 =0b0000000000000000, + p_EVODD_PHI_CFG =0b00000000000, + p_EYE_SCAN_SWAP_EN =0b0, + p_FTS_DESKEW_SEQ_ENABLE =0b1111, + p_FTS_LANE_DESKEW_CFG =0b1111, + p_FTS_LANE_DESKEW_EN ="FALSE", + p_GEARBOX_MODE =0b00000, + p_GM_BIAS_SELECT =0b0, + p_LOCAL_MASTER =0b1, + p_OOBDIVCTL =0b00, + p_OOB_PWRUP =0b0, + p_PCI3_AUTO_REALIGN ="OVR_1K_BLK", + p_PCI3_PIPE_RX_ELECIDLE =0b0, + p_PCI3_RX_ASYNC_EBUF_BYPASS =0b00, + p_PCI3_RX_ELECIDLE_EI2_ENABLE =0b0, + p_PCI3_RX_ELECIDLE_H2L_COUNT =0b000000, + p_PCI3_RX_ELECIDLE_H2L_DISABLE =0b000, + p_PCI3_RX_ELECIDLE_HI_COUNT =0b000000, + p_PCI3_RX_ELECIDLE_LP4_DISABLE =0b0, + p_PCI3_RX_FIFO_DISABLE =0b0, + p_PCIE_BUFG_DIV_CTRL =0b0001000000000000, + p_PCIE_RXPCS_CFG_GEN3 =0b0000001010100100, + p_PCIE_RXPMA_CFG =0b0000000000001010, + p_PCIE_TXPCS_CFG_GEN3 =0b0010010010100100, + p_PCIE_TXPMA_CFG =0b0000000000001010, + p_PCS_PCIE_EN ="FALSE", + p_PCS_RSVD0 =0b0000000000000000, + p_PCS_RSVD1 =0b000, + p_PD_TRANS_TIME_FROM_P2 =0b000000111100, + p_PD_TRANS_TIME_NONE_P2 =0b00011001, + p_PD_TRANS_TIME_TO_P2 =0b01100100, + p_PLL_SEL_MODE_GEN12 =0b00, + p_PLL_SEL_MODE_GEN3 =0b11, + p_PMA_RSV1 =0b1111000000000000, + p_PROCESS_PAR =0b010, + p_RATE_SW_USE_DRP =0b1, + p_RESET_POWERSAVE_DISABLE =0b0, + ) + gth_params.update( + p_RXBUFRESET_TIME =0b00011, + p_RXBUF_ADDR_MODE ="FAST", + p_RXBUF_EIDLE_HI_CNT =0b1000, + p_RXBUF_EIDLE_LO_CNT =0b0000, + p_RXBUF_EN ="FALSE", + p_RXBUF_RESET_ON_CB_CHANGE ="TRUE", + p_RXBUF_RESET_ON_COMMAALIGN ="FALSE", + p_RXBUF_RESET_ON_EIDLE ="FALSE", + p_RXBUF_RESET_ON_RATE_CHANGE ="TRUE", + p_RXBUF_THRESH_OVFLW =0, + p_RXBUF_THRESH_OVRD ="FALSE", + p_RXBUF_THRESH_UNDFLW =0, + p_RXCDRFREQRESET_TIME =0b00001, + p_RXCDRPHRESET_TIME =0b00001, + p_RXCDR_CFG0 =0b0000000000000000, + p_RXCDR_CFG0_GEN3 =0b0000000000000000, + p_RXCDR_CFG1 =0b0000000000000000, + p_RXCDR_CFG1_GEN3 =0b0000000000000000, + p_RXCDR_CFG2 =0b0000011111010110, + p_RXCDR_CFG2_GEN3 =0b0000011111100110, + p_RXCDR_CFG3 =0b0000000000000000, + p_RXCDR_CFG3_GEN3 =0b0000000000000000, + p_RXCDR_CFG4 =0b0000000000000000, + p_RXCDR_CFG4_GEN3 =0b0000000000000000, + p_RXCDR_CFG5 =0b0000000000000000, + p_RXCDR_CFG5_GEN3 =0b0000000000000000, + p_RXCDR_FR_RESET_ON_EIDLE =0b0, + p_RXCDR_HOLD_DURING_EIDLE =0b0, + p_RXCDR_LOCK_CFG0 =0b0100010010000000, + p_RXCDR_LOCK_CFG1 =0b0101111111111111, + p_RXCDR_LOCK_CFG2 =0b0111011111000011, + p_RXCDR_PH_RESET_ON_EIDLE =0b0, + p_RXCFOK_CFG0 =0b0100000000000000, + p_RXCFOK_CFG1 =0b0000000001100101, + p_RXCFOK_CFG2 =0b0000000000101110, + p_RXDFELPMRESET_TIME =0b0001111, + p_RXDFELPM_KL_CFG0 =0b0000000000000000, + p_RXDFELPM_KL_CFG1 =0b0000000000000010, + p_RXDFELPM_KL_CFG2 =0b0000000000000000, + p_RXDFE_CFG0 =0b0000101000000000, + p_RXDFE_CFG1 =0b0000000000000000, + p_RXDFE_GC_CFG0 =0b0000000000000000, + p_RXDFE_GC_CFG1 =0b0111100001110000, + p_RXDFE_GC_CFG2 =0b0000000000000000, + p_RXDFE_H2_CFG0 =0b0000000000000000, + p_RXDFE_H2_CFG1 =0b0000000000000000, + p_RXDFE_H3_CFG0 =0b0100000000000000, + p_RXDFE_H3_CFG1 =0b0000000000000000, + p_RXDFE_H4_CFG0 =0b0010000000000000, + p_RXDFE_H4_CFG1 =0b0000000000000011, + p_RXDFE_H5_CFG0 =0b0010000000000000, + p_RXDFE_H5_CFG1 =0b0000000000000011, + p_RXDFE_H6_CFG0 =0b0010000000000000, + p_RXDFE_H6_CFG1 =0b0000000000000000, + p_RXDFE_H7_CFG0 =0b0010000000000000, + p_RXDFE_H7_CFG1 =0b0000000000000000, + p_RXDFE_H8_CFG0 =0b0010000000000000, + p_RXDFE_H8_CFG1 =0b0000000000000000, + p_RXDFE_H9_CFG0 =0b0010000000000000, + p_RXDFE_H9_CFG1 =0b0000000000000000, + p_RXDFE_HA_CFG0 =0b0010000000000000, + p_RXDFE_HA_CFG1 =0b0000000000000000, + p_RXDFE_HB_CFG0 =0b0010000000000000, + p_RXDFE_HB_CFG1 =0b0000000000000000, + p_RXDFE_HC_CFG0 =0b0000000000000000, + p_RXDFE_HC_CFG1 =0b0000000000000000, + p_RXDFE_HD_CFG0 =0b0000000000000000, + p_RXDFE_HD_CFG1 =0b0000000000000000, + p_RXDFE_HE_CFG0 =0b0000000000000000, + p_RXDFE_HE_CFG1 =0b0000000000000000, + p_RXDFE_HF_CFG0 =0b0000000000000000, + p_RXDFE_HF_CFG1 =0b0000000000000000, + p_RXDFE_OS_CFG0 =0b1000000000000000, + p_RXDFE_OS_CFG1 =0b0000000000000000, + p_RXDFE_UT_CFG0 =0b1000000000000000, + p_RXDFE_UT_CFG1 =0b0000000000000011, + p_RXDFE_VP_CFG0 =0b1010101000000000, + p_RXDFE_VP_CFG1 =0b0000000000110011, + p_RXDLY_CFG =0b0000000000011111, + p_RXDLY_LCFG =0b0000000000110000, + p_RXELECIDLE_CFG ="SIGCFG_4", + p_RXGBOX_FIFO_INIT_RD_ADDR =4, + p_RXGEARBOX_EN ="FALSE", + p_RXISCANRESET_TIME =0b00001, + p_RXLPM_CFG =0b0000000000000000, + p_RXLPM_GC_CFG =0b0001000000000000, + p_RXLPM_KH_CFG0 =0b0000000000000000, + p_RXLPM_KH_CFG1 =0b0000000000000010, + p_RXLPM_OS_CFG0 =0b1000000000000000, + p_RXLPM_OS_CFG1 =0b0000000000000010, + p_RXOOB_CFG =0b000000110, + p_RXOOB_CLK_CFG ="PMA", + p_RXOSCALRESET_TIME =0b00011, + p_RXOUT_DIV =2, + p_RXPCSRESET_TIME =0b00011, + p_RXPHBEACON_CFG =0b0000000000000000, + p_RXPHDLY_CFG =0b0010000000100000, + p_RXPHSAMP_CFG =0b0010000100000000, + p_RXPHSLIP_CFG =0b0110011000100010, + p_RXPH_MONITOR_SEL =0b00000, + p_RXPI_CFG0 =0b00, + p_RXPI_CFG1 =0b00, + p_RXPI_CFG2 =0b00, + p_RXPI_CFG3 =0b00, + p_RXPI_CFG4 =0b1, + p_RXPI_CFG5 =0b1, + p_RXPI_CFG6 =0b000, + p_RXPI_LPM =0b0, + p_RXPI_VREFSEL =0b0, + p_RXPMACLK_SEL ="DATA", + p_RXPMARESET_TIME =0b00011, + p_RXPRBS_ERR_LOOPBACK =0b0, + p_RXPRBS_LINKACQ_CNT =15, + p_RXSLIDE_AUTO_WAIT =7, + p_RXSLIDE_MODE ="OFF", + p_RXSYNC_MULTILANE =0b0, + p_RXSYNC_OVRD =0b0, + p_RXSYNC_SKIP_DA =0b0, + p_RX_AFE_CM_EN =0b0, + p_RX_BIAS_CFG0 =0b0000101010110100, + p_RX_BUFFER_CFG =0b000000, + p_RX_CAPFF_SARC_ENB =0b0, + p_RX_CLK25_DIV =6, + p_RX_CLKMUX_EN =0b1, + p_RX_CLK_SLIP_OVRD =0b00000, + p_RX_CM_BUF_CFG =0b1010, + p_RX_CM_BUF_PD =0b0, + p_RX_CM_SEL =0b11, + p_RX_CM_TRIM =0b1010, + p_RX_CTLE3_LPF =0b00000001, + p_RX_DATA_WIDTH =dw, + p_RX_DDI_SEL =0b000000, + p_RX_DEFER_RESET_BUF_EN ="TRUE", + p_RX_DFELPM_CFG0 =0b0110, + p_RX_DFELPM_CFG1 =0b1, + p_RX_DFELPM_KLKH_AGC_STUP_EN =0b1, + p_RX_DFE_AGC_CFG0 =0b10, + p_RX_DFE_AGC_CFG1 =0b100, + p_RX_DFE_KL_LPM_KH_CFG0 =0b01, + p_RX_DFE_KL_LPM_KH_CFG1 =0b100, + p_RX_DFE_KL_LPM_KL_CFG0 =0b01, + p_RX_DFE_KL_LPM_KL_CFG1 =0b100, + p_RX_DFE_LPM_HOLD_DURING_EIDLE =0b0, + p_RX_DISPERR_SEQ_MATCH ="TRUE", + p_RX_DIVRESET_TIME =0b00001, + p_RX_EN_HI_LR =0b0, + p_RX_EYESCAN_VS_CODE =0b0000000, + p_RX_EYESCAN_VS_NEG_DIR =0b0, + p_RX_EYESCAN_VS_RANGE =0b00, + p_RX_EYESCAN_VS_UT_SIGN =0b0, + p_RX_FABINT_USRCLK_FLOP =0b0, + p_RX_INT_DATAWIDTH =dw==40, + p_RX_PMA_POWER_SAVE =0b0, + p_RX_PROGDIV_CFG =0.0, + p_RX_SAMPLE_PERIOD =0b111, + p_RX_SIG_VALID_DLY =11, + p_RX_SUM_DFETAPREP_EN =0b0, + p_RX_SUM_IREF_TUNE =0b0000, + p_RX_SUM_RES_CTRL =0b00, + p_RX_SUM_VCMTUNE =0b0000, + p_RX_SUM_VCM_OVWR =0b0, + p_RX_SUM_VREF_TUNE =0b000, + p_RX_TUNE_AFE_OS =0b10, + p_RX_WIDEMODE_CDR =0b0, + p_RX_XCLK_SEL ="RXUSR", + p_SAS_MAX_COM =64, + p_SAS_MIN_COM =36, + p_SATA_BURST_SEQ_LEN =0b1110, + p_SATA_CPLL_CFG ="VCO_3000MHZ", + p_SATA_MAX_BURST =8, + p_SATA_MAX_INIT =21, + p_SATA_MAX_WAKE =7, + p_SATA_MIN_BURST =4, + p_SATA_MIN_INIT =12, + p_SATA_MIN_WAKE =4, + p_SHOW_REALIGN_COMMA ="TRUE", + p_SIM_RECEIVER_DETECT_PASS ="TRUE", + p_SIM_RESET_SPEEDUP ="TRUE", + p_SIM_TX_EIDLE_DRIVE_LEVEL =0b0, + p_SIM_VERSION =2, + p_TAPDLY_SET_TX =0b00, + p_TEMPERATUR_PAR =0b0010, + p_TERM_RCAL_CFG =0b100001000010000, + p_TERM_RCAL_OVRD =0b000, + p_TRANS_TIME_RATE =0b00001110, + p_TST_RSV0 =0b00000000, + p_TST_RSV1 =0b00000000, + ) + gth_params.update( + p_TXBUF_EN ="FALSE", + p_TXBUF_RESET_ON_RATE_CHANGE ="TRUE", + p_TXDLY_CFG =0b0000000000001001, + p_TXDLY_LCFG =0b0000000001010000, + p_TXDRVBIAS_N =0b1010, + p_TXDRVBIAS_P =0b1010, + p_TXFIFO_ADDR_CFG ="LOW", + p_TXGBOX_FIFO_INIT_RD_ADDR =4, + p_TXGEARBOX_EN ="FALSE", + p_TXOUT_DIV =2, + p_TXPCSRESET_TIME =0b00011, + p_TXPHDLY_CFG0 =0b0010000000100000, + p_TXPHDLY_CFG1 =0b0000000001110101, + p_TXPH_CFG =0b0000100110000000, + p_TXPH_MONITOR_SEL =0b00000, + p_TXPI_CFG0 =0b00, + p_TXPI_CFG1 =0b00, + p_TXPI_CFG2 =0b00, + p_TXPI_CFG3 =0b1, + p_TXPI_CFG4 =0b1, + p_TXPI_CFG5 =0b000, + p_TXPI_GRAY_SEL =0b0, + p_TXPI_INVSTROBE_SEL =0b0, + p_TXPI_LPM =0b0, + p_TXPI_PPMCLK_SEL ="TXUSRCLK2", + p_TXPI_PPM_CFG =0b00000000, + p_TXPI_SYNFREQ_PPM =0b001, + p_TXPI_VREFSEL =0b0, + p_TXPMARESET_TIME =0b00011, + p_TXSYNC_MULTILANE =0 if mode == "single" else 1, + p_TXSYNC_OVRD =0b0, + p_TXSYNC_SKIP_DA =0b0, + p_TX_CLK25_DIV =6, + p_TX_CLKMUX_EN =0b1, + p_TX_DATA_WIDTH =dw, + p_TX_DCD_CFG =0b000010, + p_TX_DCD_EN =0b0, + p_TX_DEEMPH0 =0b000000, + p_TX_DEEMPH1 =0b000000, + p_TX_DIVRESET_TIME =0b00001, + p_TX_DRIVE_MODE ="DIRECT", + p_TX_EIDLE_ASSERT_DELAY =0b100, + p_TX_EIDLE_DEASSERT_DELAY =0b011, + p_TX_EML_PHI_TUNE =0b0, + p_TX_FABINT_USRCLK_FLOP =0b0, + p_TX_IDLE_DATA_ZERO =0b0, + p_TX_INT_DATAWIDTH =dw==40, + p_TX_LOOPBACK_DRIVE_HIZ ="FALSE", + p_TX_MAINCURSOR_SEL =0b0, + p_TX_MARGIN_FULL_0 =0b1001111, + p_TX_MARGIN_FULL_1 =0b1001110, + p_TX_MARGIN_FULL_2 =0b1001100, + p_TX_MARGIN_FULL_3 =0b1001010, + p_TX_MARGIN_FULL_4 =0b1001000, + p_TX_MARGIN_LOW_0 =0b1000110, + p_TX_MARGIN_LOW_1 =0b1000101, + p_TX_MARGIN_LOW_2 =0b1000011, + p_TX_MARGIN_LOW_3 =0b1000010, + p_TX_MARGIN_LOW_4 =0b1000000, + p_TX_MODE_SEL =0b000, + p_TX_PMADATA_OPT =0b0, + p_TX_PMA_POWER_SAVE =0b0, + p_TX_PROGCLK_SEL ="PREPI", + p_TX_PROGDIV_CFG =0.0, + p_TX_QPI_STATUS_EN =0b0, + p_TX_RXDETECT_CFG =0b00000000110010, + p_TX_RXDETECT_REF =0b100, + p_TX_SAMPLE_PERIOD =0b111, + p_TX_SARC_LPBK_ENB =0b0, + p_TX_XCLK_SEL ="TXUSR", + p_USE_PCS_CLK_PHASE_SEL =0b0, + p_WB_MODE =0b00, + ) + gth_params.update( + # Reset modes + i_GTRESETSEL=0, + i_RESETOVRD=0, + + i_CPLLRESET=0, + i_CPLLPD=cpll_reset, + o_CPLLLOCK=cpll_lock, + i_CPLLLOCKEN=1, + i_CPLLREFCLKSEL=0b001, + i_TSTIN=2**20-1, + i_GTREFCLK0=refclk, - # PMA Attributes - p_PMA_RSV1=0xf800, - p_RX_BIAS_CFG0=0x0AB4, - p_RX_CM_TRIM=0b1010, - p_RX_CLK25_DIV=5, - p_TX_CLK25_DIV=5, + # TX clock + + o_TXOUTCLK=self.txoutclk, + i_TXSYSCLKSEL=0b00, + i_TXPLLCLKSEL=0b00, + i_TXOUTCLKSEL=0b11, - # Power-Down Attributes - p_PD_TRANS_TIME_FROM_P2=0x3c, - p_PD_TRANS_TIME_NONE_P2=0x19, - p_PD_TRANS_TIME_TO_P2=0x64, + # TX Startup/Reset + i_GTTXRESET=tx_init.gtXxreset, + o_TXRESETDONE=tx_init.Xxresetdone, + i_TXDLYSRESET=tx_init.Xxdlysreset if mode != "slave" else self.txdlysreset, + o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone, + o_TXPHALIGNDONE=tx_init.Xxphaligndone, + i_TXUSERRDY=tx_init.Xxuserrdy, + i_TXSYNCMODE=mode != "slave", + + i_TXSYNCALLIN=self.txsyncallin, + i_TXSYNCIN=self.txsyncin, + o_TXSYNCOUT=self.txsyncout, - # CPLL - p_CPLL_CFG0=0x67f8, - p_CPLL_CFG1=0xa4ac, - p_CPLL_CFG2=0xf007, - p_CPLL_CFG3=0x0000, - p_CPLL_FBDIV=5, - p_CPLL_FBDIV_45=4, - p_CPLL_REFCLK_DIV=1, - p_RXOUT_DIV=2, - p_TXOUT_DIV=2, - i_CPLLRESET=0, - i_CPLLPD=cpll_reset, - o_CPLLLOCK=cpll_lock, - i_CPLLLOCKEN=1, - i_CPLLREFCLKSEL=0b001, - i_TSTIN=2**20-1, - i_GTREFCLK0=refclk, + # TX data - # TX clock - p_TXBUF_EN="FALSE", - p_TX_XCLK_SEL="TXUSR", - o_TXOUTCLK=self.txoutclk, - i_TXSYSCLKSEL=0b00, - i_TXPLLCLKSEL=0b00, - i_TXOUTCLKSEL=0b11, + i_TXCTRL0=Cat(*[txdata[10*i+8] for i in range(nwords)]), + i_TXCTRL1=Cat(*[txdata[10*i+9] for i in range(nwords)]), + i_TXDATA=Cat(*[txdata[10*i:10*i+8] for i in range(nwords)]), + i_TXUSRCLK=ClockSignal("rtio_tx"), + i_TXUSRCLK2=ClockSignal("rtio_tx"), - # TX Startup/Reset - i_GTTXRESET=tx_init.gtXxreset, - o_TXRESETDONE=tx_init.Xxresetdone, - i_TXDLYSRESET=tx_init.Xxdlysreset if mode != "slave" else self.txdlysreset, - o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone, - o_TXPHALIGNDONE=tx_init.Xxphaligndone, - i_TXUSERRDY=tx_init.Xxuserrdy, - i_TXSYNCMODE=mode != "slave", - p_TXSYNC_MULTILANE=0 if mode == "single" else 1, - p_TXSYNC_OVRD=0, - i_TXSYNCALLIN=self.txsyncallin, - i_TXSYNCIN=self.txsyncin, - o_TXSYNCOUT=self.txsyncout, + # TX electrical + i_TXPD=0b00, + i_TXBUFDIFFCTRL=0b000, + i_TXDIFFCTRL=0b1100, - # TX data - p_TX_DATA_WIDTH=dw, - p_TX_INT_DATAWIDTH=dw == 40, - i_TXCTRL0=Cat(*[txdata[10*i+8] for i in range(nwords)]), - i_TXCTRL1=Cat(*[txdata[10*i+9] for i in range(nwords)]), - i_TXDATA=Cat(*[txdata[10*i:10*i+8] for i in range(nwords)]), - i_TXUSRCLK=ClockSignal("rtio_tx"), - i_TXUSRCLK2=ClockSignal("rtio_tx"), + # RX Startup/Reset + i_GTRXRESET=rx_init.gtXxreset, + o_RXRESETDONE=rx_init.Xxresetdone, + i_RXDLYSRESET=rx_init.Xxdlysreset, + o_RXPHALIGNDONE=rxphaligndone, + i_RXSYNCALLIN=rxphaligndone, + i_RXUSERRDY=rx_init.Xxuserrdy, + i_RXSYNCIN=0, + i_RXSYNCMODE=1, + o_RXSYNCDONE=rx_init.Xxsyncdone, - # TX electrical - i_TXPD=0b00, - p_TX_CLKMUX_EN=1, - i_TXBUFDIFFCTRL=0b000, - i_TXDIFFCTRL=0b1100, + # RX AFE + i_RXDFEAGCCTRL=1, + i_RXDFEXYDEN=1, + i_RXLPMEN=1, + i_RXOSINTCFG=0xd, + i_RXOSINTEN=1, - # RX Startup/Reset - i_GTRXRESET=rx_init.gtXxreset, - o_RXRESETDONE=rx_init.Xxresetdone, - i_RXDLYSRESET=rx_init.Xxdlysreset, - o_RXPHALIGNDONE=rxphaligndone, - i_RXSYNCALLIN=rxphaligndone, - i_RXUSERRDY=rx_init.Xxuserrdy, - i_RXSYNCIN=0, - i_RXSYNCMODE=1, - o_RXSYNCDONE=rx_init.Xxsyncdone, + # RX clock + i_RXRATE=0, + i_RXDLYBYPASS=0, + i_RXSYSCLKSEL=0b00, + i_RXOUTCLKSEL=0b010, + i_RXPLLCLKSEL=0b00, + o_RXOUTCLK=self.rxoutclk, + i_RXUSRCLK=ClockSignal("rtio_rx"), + i_RXUSRCLK2=ClockSignal("rtio_rx"), - # RX AFE - i_RXDFEAGCCTRL=1, - i_RXDFEXYDEN=1, - i_RXLPMEN=1, - i_RXOSINTCFG=0xd, - i_RXOSINTEN=1, + # RX data + o_RXCTRL0=Cat(*[rxdata[10*i+8] for i in range(nwords)]), + o_RXCTRL1=Cat(*[rxdata[10*i+9] for i in range(nwords)]), + o_RXDATA=Cat(*[rxdata[10*i:10*i+8] for i in range(nwords)]), - # RX clock - i_RXRATE=0, - i_RXDLYBYPASS=0, - p_RXBUF_EN="FALSE", - p_RX_XCLK_SEL="RXUSR", - i_RXSYSCLKSEL=0b00, - i_RXOUTCLKSEL=0b010, - i_RXPLLCLKSEL=0b00, - o_RXOUTCLK=self.rxoutclk, - i_RXUSRCLK=ClockSignal("rtio_rx"), - i_RXUSRCLK2=ClockSignal("rtio_rx"), + # RX electrical + i_RXPD=0b00, + i_RXELECIDLEMODE=0b11, - # RX Clock Correction Attributes - p_CLK_CORRECT_USE="FALSE", - p_CLK_COR_SEQ_1_1=0b0100000000, - p_CLK_COR_SEQ_2_1=0b0100000000, - p_CLK_COR_SEQ_1_ENABLE=0b1111, - p_CLK_COR_SEQ_2_ENABLE=0b1111, - - # RX data - p_RX_DATA_WIDTH=dw, - p_RX_INT_DATAWIDTH=dw == 40, - o_RXCTRL0=Cat(*[rxdata[10*i+8] for i in range(nwords)]), - o_RXCTRL1=Cat(*[rxdata[10*i+9] for i in range(nwords)]), - o_RXDATA=Cat(*[rxdata[10*i:10*i+8] for i in range(nwords)]), - - # RX electrical - i_RXPD=0b00, - p_RX_CLKMUX_EN=1, - i_RXELECIDLEMODE=0b11, - - # Pads - i_GTHRXP=pads.rxp, - i_GTHRXN=pads.rxn, - o_GTHTXP=pads.txp, - o_GTHTXN=pads.txn - ) + # Pads + i_GTHRXP=pads.rxp, + i_GTHRXN=pads.rxn, + o_GTHTXP=pads.txp, + o_GTHTXN=pads.txn + ) + self.specials += Instance("GTHE3_CHANNEL", **gth_params) self.comb += self.txphaligndone.eq(tx_init.Xxphaligndone) self.submodules += [ From 5b3d6d57e2dacbcc48b2725760cdb0753a39244d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 6 Mar 2018 11:49:28 +0100 Subject: [PATCH 0450/2457] drtio/gth: power down rx on restart (seems to make link initialization reliable) --- artiq/gateware/drtio/transceiver/gth_ultrascale.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index 5c4fcbc25..baad1d557 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -531,8 +531,8 @@ class GTHSingle(Module): o_RXDATA=Cat(*[rxdata[10*i:10*i+8] for i in range(nwords)]), # RX electrical - i_RXPD=0b00, - i_RXELECIDLEMODE=0b11, + i_RXPD=Replicate(rx_init.restart, 2), + i_RXELECIDLEMODE=0b11, # Pads i_GTHRXP=pads.rxp, From f40255c968de41d60bca3256e3849f75dd620619 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 6 Mar 2018 20:51:09 +0800 Subject: [PATCH 0451/2457] sed: add comments about key points in LaneDistributor --- artiq/gateware/rtio/sed/lane_distributor.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index d6e346c9a..fe9066299 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -24,6 +24,10 @@ class LaneDistributor(Module): self.cri = interface self.sequence_error = Signal() self.sequence_error_channel = Signal(16) + # The minimum timestamp that an event must have to avoid triggering + # an underflow, at the time when the CRI write happens, and to a channel + # with zero latency compensation. This is synchronous to the system clock + # domain. self.minimum_coarse_timestamp = Signal(64-glbl_fine_ts_width) self.output = [Record(layouts.fifo_ingress(seqn_width, layout_payload)) for _ in range(lane_count)] @@ -41,6 +45,15 @@ class LaneDistributor(Module): for _ in range(lane_count)) seqn = Signal(seqn_width) + # The core keeps writing events into the current lane as long as timestamps + # (after compensation) are strictly increasing, otherwise it switches to + # the next lane. + # If spread is enabled, it also switches to the next lane after the current + # lane has been full, in order to maximize lane utilization. + # The current lane is called lane "A". The next lane (which may be chosen + # a later stage by the core) is called lane "B". + # Computations for both lanes are prepared in advance to increase performance. + # distribute data to lanes for lio in self.output: self.comb += [ @@ -70,6 +83,9 @@ class LaneDistributor(Module): last_minus_timestamp.eq(last_coarse_timestamp - coarse_timestamp) ] + # Quash channels are "dummy" channels to which writes are completely ignored. + # This is used by the RTIO log channel, which is taken into account + # by the analyzer but does not enter the lanes. quash = Signal() self.sync += quash.eq(0) for channel in quash_channels: From c25560baeccaf06fec5915dfd92ae84e82469232 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 6 Mar 2018 20:56:35 +0800 Subject: [PATCH 0452/2457] sed: more LaneDistributor comments --- artiq/gateware/rtio/sed/lane_distributor.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index fe9066299..8fe7af477 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -38,22 +38,27 @@ class LaneDistributor(Module): o_status_underflow = Signal() self.comb += self.cri.o_status.eq(Cat(o_status_wait, o_status_underflow)) - # internal state - current_lane = Signal(max=lane_count) - last_coarse_timestamp = Signal(64-glbl_fine_ts_width) - last_lane_coarse_timestamps = Array(Signal(64-glbl_fine_ts_width) - for _ in range(lane_count)) - seqn = Signal(seqn_width) - # The core keeps writing events into the current lane as long as timestamps # (after compensation) are strictly increasing, otherwise it switches to # the next lane. # If spread is enabled, it also switches to the next lane after the current # lane has been full, in order to maximize lane utilization. # The current lane is called lane "A". The next lane (which may be chosen - # a later stage by the core) is called lane "B". + # at a later stage by the core) is called lane "B". # Computations for both lanes are prepared in advance to increase performance. + current_lane = Signal(max=lane_count) + # The last coarse timestamp received from the CRI, after compensation. + # Used to determine when to switch lanes. + last_coarse_timestamp = Signal(64-glbl_fine_ts_width) + # The last coarse timestamp written to each lane. Used to detect + # sequence errors. + last_lane_coarse_timestamps = Array(Signal(64-glbl_fine_ts_width) + for _ in range(lane_count)) + # Sequence number counter. The sequence number is used to determine which + # event wins during a replace. + seqn = Signal(seqn_width) + # distribute data to lanes for lio in self.output: self.comb += [ From 257bef0d212834fad2a48f0bcc28696720dd8957 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 5 Mar 2018 15:35:21 +0100 Subject: [PATCH 0453/2457] slave_fpga: print more info --- artiq/firmware/libboard_artiq/slave_fpga.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/slave_fpga.rs b/artiq/firmware/libboard_artiq/slave_fpga.rs index 3046fec31..2a7377ff4 100644 --- a/artiq/firmware/libboard_artiq/slave_fpga.rs +++ b/artiq/firmware/libboard_artiq/slave_fpga.rs @@ -45,17 +45,20 @@ pub fn load() -> Result<(), &'static str> { if csr::slave_fpga_cfg::in_read() & DONE_BIT != 0 { info!("DONE before loading"); } + if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { + info!("INIT asserted before loading"); + } csr::slave_fpga_cfg::out_write(0); csr::slave_fpga_cfg::oe_write(CCLK_BIT | DIN_BIT | PROGRAM_B_BIT); clock::spin_us(1_000); // TPROGRAM=250ns min, be_generous if csr::slave_fpga_cfg::in_read() & INIT_B_BIT != 0 { - return Err("Did not react to PROGRAM"); + return Err("Did not assert INIT in reaction to PROGRAM"); } csr::slave_fpga_cfg::out_write(PROGRAM_B_BIT); clock::spin_us(10_000); // TPL=5ms max if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { - return Err("Did not exit INIT"); + return Err("Did not exit INIT after releasing PROGRAM"); } for i in slice::from_raw_parts(GATEWARE.offset(8), length) { From 07de7af86a6018f7633212b767ae8b28b4bb9442 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 5 Mar 2018 18:06:17 +0100 Subject: [PATCH 0454/2457] kasli: make second eem optional in urukul --- artiq/gateware/targets/kasli.py | 34 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index bd97fe36f..e2ce13963 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -193,8 +193,8 @@ def _novogorny(eem): ] -def _urukul(eem, eem_aux): - return [ +def _urukul(eem, eem_aux=None): + ios = [ ("{}_spi_p".format(eem), 0, Subsignal("clk", Pins("{}:{}_p".format(eem, _eem_signal(0)))), Subsignal("mosi", Pins("{}:{}_p".format(eem, _eem_signal(1)))), @@ -213,24 +213,26 @@ def _urukul(eem, eem_aux): eem, [_eem_signal(i + 3) for i in range(3)]))), IOStandard("LVDS_25"), ), - ] + [ + ] + ttls = [(6, eem, "io_update"), + (7, eem, "dds_reset")] + if eem_aux is not None: + ttls += [(0, eem_aux, "sync_clk"), + (1, eem_aux, "sync_in"), + (2, eem_aux, "io_update_ret"), + (3, eem_aux, "nu_mosi3"), + (4, eem_aux, "sw0"), + (5, eem_aux, "sw1"), + (6, eem_aux, "sw2"), + (7, eem_aux, "sw3")] + for i, j, sig in ttls: + ios.append( ("{}_{}".format(eem, sig), 0, Subsignal("p", Pins("{}:{}_p".format(j, _eem_signal(i)))), Subsignal("n", Pins("{}:{}_n".format(j, _eem_signal(i)))), IOStandard("LVDS_25") - ) for i, j, sig in [ - (6, eem, "io_update"), - (7, eem, "dds_reset"), - (0, eem_aux, "sync_clk"), - (1, eem_aux, "sync_in"), - (2, eem_aux, "io_update_ret"), - (3, eem_aux, "nu_mosi3"), - (4, eem_aux, "sw0"), - (5, eem_aux, "sw1"), - (6, eem_aux, "sw2"), - (7, eem_aux, "sw3") - ] - ] + )) + return ios class Opticlock(_StandaloneBase): From 956098c2137e21c2809757ed4d28eccf39746e49 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 5 Mar 2018 18:07:04 +0100 Subject: [PATCH 0455/2457] kasli: add second urukul, make clk_sel drive optional --- artiq/gateware/targets/kasli.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index e2ce13963..9a3b31a74 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -252,9 +252,14 @@ class Opticlock(_StandaloneBase): platform.add_extension(_dio("eem2")) platform.add_extension(_novogorny("eem3")) platform.add_extension(_urukul("eem5", "eem4")) + platform.add_extension(_urukul("eem6")) + # platform.add_extension(_zotino("eem7")) # EEM clock fan-out from Si5324, not MMCX - self.comb += platform.request("clk_sel").eq(1) + try: + self.comb += platform.request("clk_sel").eq(1) + except ConstraintError: + pass rtio_channels = [] for i in range(24): From e356150ac479096d1dd139810d54c5273c7bc560 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 5 Mar 2018 19:12:49 +0000 Subject: [PATCH 0456/2457] ttl_simple: support differential io --- artiq/gateware/rtio/phy/ttl_simple.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_simple.py b/artiq/gateware/rtio/phy/ttl_simple.py index d5129606a..fc83065f3 100644 --- a/artiq/gateware/rtio/phy/ttl_simple.py +++ b/artiq/gateware/rtio/phy/ttl_simple.py @@ -1,13 +1,15 @@ from migen import * from migen.genlib.cdc import MultiReg +from migen.genlib.io import DifferentialInput, DifferentialOutput from artiq.gateware.rtio import rtlink class Output(Module): - def __init__(self, pad): + def __init__(self, pad, pad_n=None): self.rtlink = rtlink.Interface(rtlink.OInterface(1)) - self.probes = [pad] + pad_o = Signal(reset_less=True) + self.probes = [pad_o] override_en = Signal() override_o = Signal() self.overrides = [override_en, override_o] @@ -20,15 +22,19 @@ class Output(Module): pad_k.eq(self.rtlink.o.data) ), If(override_en, - pad.eq(override_o) + pad_o.eq(override_o) ).Else( - pad.eq(pad_k) + pad_o.eq(pad_k) ) ] + if pad_n is None: + self.comb += pad.eq(pad_o) + else: + self.specials += DifferentialOutput(pad_o, pad, pad_n) class Input(Module): - def __init__(self, pad): + def __init__(self, pad, pad_n=None): self.rtlink = rtlink.Interface( rtlink.OInterface(2, 2), rtlink.IInterface(1)) @@ -49,8 +55,13 @@ class Input(Module): ] i = Signal() - i_d = Signal() - self.specials += MultiReg(pad, i, "rio_phy") + i_d = Signal(reset_less=True) + pad_i = Signal() + if pad_n is None: + self.comb += pad_i.eq(pad) + else: + self.specials += DifferentialInput(pad, pad_n, pad_i) + self.specials += MultiReg(pad_i, i, "rio_phy") self.sync.rio_phy += i_d.eq(i) self.comb += [ self.rtlink.i.stb.eq( From 50298a6104ab01e8b22ac88c8db22ffb0c9be754 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 5 Mar 2018 19:14:06 +0000 Subject: [PATCH 0457/2457] ttl_serdes_7series: suppress diff_term in outputs --- artiq/gateware/rtio/phy/ttl_serdes_7series.py | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_7series.py b/artiq/gateware/rtio/phy/ttl_serdes_7series.py index f91e7584c..0c5b89c9b 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_7series.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_7series.py @@ -26,10 +26,15 @@ class _OSERDESE2_8X(Module): if pad_n is None: self.comb += pad.eq(pad_o) else: - self.specials += Instance("OBUFDS", + self.specials += Instance("IOBUFDS_INTERMDISABLE", + p_DIFF_TERM="FALSE", + p_IBUF_LOW_PWR="TRUE", + p_USE_IBUFDISABLE="TRUE", + i_IBUFDISABLE=1, + i_INTERMDISABLE=1, i_I=pad_o, - o_O=pad, o_OB=pad_n) - + i_T=self.t_out, + io_IO=pad, io_IOB=pad_n) class _ISERDESE2_8X(Module): def __init__(self, pad, pad_n=None): @@ -54,7 +59,14 @@ class _ISERDESE2_8X(Module): if pad_n is None: self.comb += pad_i.eq(pad) else: - self.specials += Instance("IBUFDS", o_O=pad_i, i_I=pad, i_IB=pad_n) + self.specials += Instance("IBUFDS_INTERMDISABLE", + p_DIFF_TERM="TRUE", + p_IBUF_LOW_PWR="TRUE", + p_USE_IBUFDISABLE="TRUE", + i_IBUFDISABLE=0, + i_INTERMDISABLE=0, + o_O=pad_i, + io_IO=pad, io_IOB=pad_n) class _IOSERDESE2_8X(Module): From fd3cdce59a23138baf9aaec432b785fe669c337d Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 5 Mar 2018 19:14:27 +0000 Subject: [PATCH 0458/2457] kasli/opticlock: use plain ttls for channels 8-23 --- artiq/gateware/targets/kasli.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 9a3b31a74..b0fe23778 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -267,8 +267,10 @@ class Opticlock(_StandaloneBase): pads = platform.request("eem{}".format(eem), port) if i < 4: cls = ttl_serdes_7series.InOut_8X - else: + elif i < 8: cls = ttl_serdes_7series.Output_8X + else: + cls = ttl_simple.Output phy = cls(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From 62af7fe2ac1b40dbc46582bdfcc9640af673983c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 6 Mar 2018 10:28:34 +0000 Subject: [PATCH 0459/2457] Revert "kasli/opticlock: use plain ttls for channels 8-23" This reverts commit bd5c222569eb68d624a5ac1e9f2542f6ee553f83. No decrease in power consumption or improvement in timing. --- artiq/gateware/targets/kasli.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b0fe23778..9a3b31a74 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -267,10 +267,8 @@ class Opticlock(_StandaloneBase): pads = platform.request("eem{}".format(eem), port) if i < 4: cls = ttl_serdes_7series.InOut_8X - elif i < 8: - cls = ttl_serdes_7series.Output_8X else: - cls = ttl_simple.Output + cls = ttl_serdes_7series.Output_8X phy = cls(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From f4dad87fd9cfd0b33454e9843f81290bb6ff81cb Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 6 Mar 2018 11:09:45 +0000 Subject: [PATCH 0460/2457] coredevice: add pcf8574a driver I2C IO expander with 8 quasi-bidirectional pins --- artiq/coredevice/pcf8574a.py | 47 +++++++++++++++++++++++++++ doc/manual/core_drivers_reference.rst | 6 ++++ 2 files changed, 53 insertions(+) create mode 100644 artiq/coredevice/pcf8574a.py diff --git a/artiq/coredevice/pcf8574a.py b/artiq/coredevice/pcf8574a.py new file mode 100644 index 000000000..ed11cc311 --- /dev/null +++ b/artiq/coredevice/pcf8574a.py @@ -0,0 +1,47 @@ +from artiq.experiment import kernel +from artiq.coredevice.i2c import ( + i2c_start, i2c_write, i2c_read, i2c_stop, I2CError) + + +class PCF8574A: + """Driver for the PCF8574 I2C remote 8-bit I/O expander. + + I2C transactions not real-time, and are performed by the CPU without + involving RTIO. + """ + def __init__(self, dmgr, busno=0, address=0x7c, core_device="core"): + self.core = dmgr.get(core_device) + self.busno = busno + self.address = address + + @kernel + def set(self, data): + """Drive data on the quasi-bidirectional pins. + + :param data: Pin data. High bits are weakly driven high + (and thus inputs), low bits are strongly driven low. + """ + i2c_start(self.busno) + try: + if not i2c_write(self.busno, self.address): + raise I2CError("PCF8574A failed to ack address") + if not i2c_write(self.busno, data): + raise I2CError("PCF8574A failed to ack data") + finally: + i2c_stop(self.busno) + + @kernel + def get(self): + """Retrieve quasi-bidirectional pin input data. + + :return: Pin data + """ + i2c_start(self.busno) + ret = 0 + try: + if not i2c_write(self.busno, self.address | 1): + raise I2CError("PCF8574A failed to ack address") + ret = i2c_read(self.busno, False) + finally: + i2c_stop(self.busno) + return ret diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index e55d6a79f..4185ddc47 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -45,6 +45,12 @@ These drivers are for the core device and the peripherals closely integrated int .. automodule:: artiq.coredevice.i2c :members: +:mod:`artiq.coredevice.pcf8574a` module +--------------------------------------- + +.. automodule:: artiq.coredevice.pcf8574a + :members: + :mod:`artiq.coredevice.cache` module ------------------------------------ From 994ceca9ffb4d45312e4425b49d346acc672f4ce Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 6 Mar 2018 17:27:43 +0100 Subject: [PATCH 0461/2457] sayma_amc: disable slave fpga gateware loading --- artiq/gateware/targets/sayma_amc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 22038b355..e89fa6e35 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -165,7 +165,7 @@ class Standalone(MiniSoC, AMPSoC): slave_fpga_cfg.program_b, ]) self.csr_devices.append("slave_fpga_cfg") - self.config["HAS_SLAVE_FPGA"] = None + # self.config["HAS_SLAVE_FPGA"] = None self.config["SLAVE_FPGA_GATEWARE"] = 0x150000 # AMC/RTM serwb From c34d00cbc97123954713a90061b2b180f7478b0f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Mar 2018 00:06:39 +0800 Subject: [PATCH 0462/2457] drtio: implement Si5324 phaser gateware and partial firmware support --- artiq/firmware/libboard_artiq/si5324.rs | 56 ++++++++++++---- artiq/firmware/runtime/main.rs | 2 +- artiq/firmware/satman/main.rs | 21 +++--- artiq/gateware/drtio/si_phaser.py | 85 +++++++++++++++++++++++++ artiq/gateware/targets/kasli.py | 12 ++-- 5 files changed, 147 insertions(+), 29 deletions(-) create mode 100644 artiq/gateware/drtio/si_phaser.py diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index db96c7acc..9aeeb36be 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -1,6 +1,6 @@ use core::result; use board::clock; -#[cfg(not(si5324_soft_reset))] +#[cfg(any(not(si5324_soft_reset), has_si_phaser))] use board::csr; use i2c; @@ -47,6 +47,11 @@ pub struct FrequencySettings { pub crystal_ref: bool } +pub enum Input { + Ckin1, + Ckin2, +} + fn map_frequency_settings(settings: &FrequencySettings) -> Result { if settings.nc1_ls != 0 && (settings.nc1_ls % 2) == 1 { return Err("NC1_LS must be 0 or even") @@ -160,8 +165,11 @@ fn has_xtal() -> Result { Ok((read(129)? & 0x01) == 0) // LOSX_INT=0 } -fn has_clkin2() -> Result { - Ok((read(129)? & 0x04) == 0) // LOS2_INT=0 +fn has_ckin(input: Input) -> Result { + match input { + Input::Ckin1 => Ok((read(129)? & 0x02) == 0), // LOS1_INT=0 + Input::Ckin2 => Ok((read(129)? & 0x04) == 0), // LOS2_INT=0 + } } fn locked() -> Result { @@ -180,7 +188,7 @@ fn monitor_lock() -> Result<()> { Ok(()) } -pub fn setup(settings: &FrequencySettings) -> Result<()> { +pub fn setup(settings: &FrequencySettings, input: Input) -> Result<()> { let s = map_frequency_settings(settings)?; #[cfg(not(si5324_soft_reset))] @@ -203,12 +211,16 @@ pub fn setup(settings: &FrequencySettings) -> Result<()> { #[cfg(si5324_soft_reset)] soft_reset()?; + let cksel_reg = match input { + Input::Ckin1 => 0b00, + Input::Ckin2 => 0b01, + }; if settings.crystal_ref { write(0, read(0)? | 0x40)?; // FREE_RUN=1 } write(2, (read(2)? & 0x0f) | (s.bwsel << 4))?; write(21, read(21)? & 0xfe)?; // CKSEL_PIN=0 - write(3, (read(3)? & 0x3f) | (0b01 << 6) | 0x10)?; // CKSEL_REG=b01 SQ_ICAL=1 + write(3, (read(3)? & 0x3f) | (cksel_reg << 6) | 0x10)?; // CKSEL_REG, SQ_ICAL=1 write(4, (read(4)? & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00 write(6, (read(6)? & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111 write(25, (s.n1_hs << 5 ) as u8)?; @@ -233,20 +245,40 @@ pub fn setup(settings: &FrequencySettings) -> Result<()> { if !has_xtal()? { return Err("Si5324 misses XA/XB signal"); } - if !has_clkin2()? { - return Err("Si5324 misses CLKIN2 signal"); + if !has_ckin(input)? { + return Err("Si5324 misses clock input signal"); } monitor_lock()?; Ok(()) } -pub fn select_ext_input(external: bool) -> Result<()> { - if external { - write(3, (read(3)? & 0x3f) | (0b00 << 6))?; // CKSEL_REG=b00 - } else { - write(3, (read(3)? & 0x3f) | (0b01 << 6))?; // CKSEL_REG=b01 +pub fn select_input(input: Input) -> Result<()> { + let cksel_reg = match input { + Input::Ckin1 => 0b00, + Input::Ckin2 => 0b01, + }; + write(3, (read(3)? & 0x3f) | (cksel_reg << 6))?; + if !has_ckin(input)? { + return Err("Si5324 misses clock input signal"); } monitor_lock()?; Ok(()) } + +#[cfg(has_si_phaser)] +pub fn select_recovered_clock(rc: bool) -> Result<()> { + write(3, (read(3)? & 0xdf) | (1 << 5))?; // DHOLD=1 + unsafe { + csr::si_phaser::switch_clocks_write(if rc { 1 } else { 0 }); + } + write(3, (read(3)? & 0xdf) | (1 << 5))?; // DHOLD=0 + monitor_lock()?; + Ok(()) +} + +#[cfg(has_si_phaser)] +pub fn calibrate_skew() -> Result<()> { + // TODO: implement + Ok(()) +} diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index b2756ff31..181981df6 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -152,7 +152,7 @@ fn setup_si5324_as_synthesizer() bwsel : 3, crystal_ref: true }; - board_artiq::si5324::setup(&SI5324_SETTINGS).expect("cannot initialize Si5324"); + board_artiq::si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin2).expect("cannot initialize Si5324"); } #[cfg(has_ethmac)] diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 7e069b752..e1b60179d 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -195,14 +195,14 @@ fn process_errors() { #[cfg(rtio_frequency = "150.0")] const SI5324_SETTINGS: si5324::FrequencySettings - = si5324::FrequencySettings { - n1_hs : 9, - nc1_ls : 4, + = si5324::FrequencySettings { + n1_hs : 6, + nc1_ls : 6, n2_hs : 10, - n2_ls : 33732, - n31 : 9370, - n32 : 7139, - bwsel : 3, + n2_ls : 270, + n31 : 75, + n32 : 75, + bwsel : 4, crystal_ref: true }; @@ -225,7 +225,7 @@ fn startup() { /* must be the first SPI init because of HMC830 SPI mode selection */ hmc830_7043::init().expect("cannot initialize HMC830/7043"); i2c::init(); - si5324::setup(&SI5324_SETTINGS).expect("cannot initialize Si5324"); + si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324"); unsafe { csr::drtio_transceiver::stable_clkin_write(1); } @@ -235,7 +235,8 @@ fn startup() { process_errors(); } info!("link is up, switching to recovered clock"); - si5324::select_ext_input(true).expect("failed to switch clocks"); + si5324::select_recovered_clock(true).expect("failed to switch clocks"); + si5324::calibrate_skew().expect("failed to calibrate skew"); drtio_reset(false); drtio_reset_phy(false); while drtio_link_rx_up() { @@ -245,7 +246,7 @@ fn startup() { drtio_reset_phy(true); drtio_reset(true); info!("link is down, switching to local crystal clock"); - si5324::select_ext_input(false).expect("failed to switch clocks"); + si5324::select_recovered_clock(false).expect("failed to switch clocks"); } } diff --git a/artiq/gateware/drtio/si_phaser.py b/artiq/gateware/drtio/si_phaser.py new file mode 100644 index 000000000..292dd3a9f --- /dev/null +++ b/artiq/gateware/drtio/si_phaser.py @@ -0,0 +1,85 @@ +from migen import * +from migen.genlib.cdc import MultiReg + +from misoc.interconnect.csr import * + + +# This code assumes 125MHz system clock and 150MHz RTIO frequency. + +class SiPhaser7Series(Module, AutoCSR): + def __init__(self, si5324_clkin, si5324_clkout_fabric): + self.switch_clocks = CSRStorage() + self.phase_shift = CSR() + self.phase_shift_done = CSRStatus() + self.sample_result = CSRStatus() + + # 125MHz system clock to 150MHz. VCO @ 625MHz. + # Used to provide a startup clock to the transceiver through the Si, + # we do not use the crystal reference so that the PFD (f3) frequency + # can be high. + mmcm_freerun_fb = Signal() + mmcm_freerun_output = Signal() + self.specials += \ + Instance("MMCME2_BASE", + p_CLKIN1_PERIOD=1e9/125e6, + i_CLKIN1=ClockSignal("sys"), + i_RST=ResetSignal("sys"), + + p_CLKFBOUT_MULT_F=6.0, p_DIVCLK_DIVIDE=1, + + o_CLKFBOUT=mmcm_freerun_fb, i_CLKFBIN=mmcm_freerun_fb, + + p_CLKOUT0_DIVIDE_F=5.0, o_CLKOUT0=mmcm_freerun_output, + ) + + # 150MHz to 150MHz with controllable phase shift, VCO @ 1200MHz. + # Inserted between CDR and output to Si, used to correct + # non-determinstic skew of Si5324. + mmcm_ps_fb = Signal() + mmcm_ps_output = Signal() + self.specials += \ + Instance("MMCME2_ADV", + p_CLKIN1_PERIOD=1e9/150e6, + i_CLKIN1=ClockSignal("rtio_rx0"), + i_RST=ResetSignal("rtio_rx0"), + i_CLKINSEL=1, # yes, 1=CLKIN1 0=CLKIN2 + + p_CLKFBOUT_MULT_F=8.0, + p_CLKOUT0_DIVIDE_F=8.0, + p_DIVCLK_DIVIDE=1, + + o_CLKFBOUT=mmcm_ps_fb, i_CLKFBIN=mmcm_ps_fb, + + p_CLKOUT0_USE_FINE_PS="TRUE", + o_CLKOUT0=mmcm_ps_output, + + i_PSCLK=ClockSignal(), + i_PSEN=self.phase_shift.re, + i_PSINCDEC=self.phase_shift.r, + o_PSDONE=self.phase_shift_done.status, + ) + + si5324_clkin_se = Signal() + self.specials += [ + Instance("BUFGMUX", + i_I0=mmcm_freerun_output, + i_I1=mmcm_ps_output, + i_S=self.switch_clocks.storage, + o_O=si5324_clkin_se + ), + Instance("OBUFDS", + i_I=si5324_clkin_se, + o_O=si5324_clkin.p, o_OB=si5324_clkin.n + ) + ] + + si5324_clkout_se = Signal() + self.specials += \ + Instance("IBUFDS", + p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE", + i_I=si5324_clkout_fabric.p, i_IB=si5324_clkout_fabric.n, + o_O=si5324_clkout_se), + + clkout_sample1 = Signal() # IOB register + self.sync.rtio_rx0 += clkout_sample1.eq(si5324_clkout_se) + self.specials += MultiReg(clkout_sample1, self.sample_result.status) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 9a3b31a74..77791cfed 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -21,6 +21,7 @@ from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi2 from artiq.gateware.drtio.transceiver import gtp_7series +from artiq.gateware.drtio.si_phaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite from artiq.build_soc import build_artiq_soc @@ -573,12 +574,11 @@ class Satellite(BaseSoC): self.add_memory_group("drtio_aux", ["drtio0_aux"]) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - si5324_clkin = platform.request("si5324_clkin") - self.specials += \ - Instance("OBUFDS", - i_I=ClockSignal("rtio_rx0"), - o_O=si5324_clkin.p, o_OB=si5324_clkin.n - ) + self.submodules.si_phaser = SiPhaser7Series( + si5324_clkin=platform.request("si5324_clkin"), + si5324_clkout_fabric=platform.request("si5324_clkout_fabric") + ) + self.csr_devices.append("si_phaser") i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) self.csr_devices.append("i2c") From a6e29462a83a8a40f08c6bb8f469dbef33c0cb8e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Mar 2018 09:42:26 +0800 Subject: [PATCH 0463/2457] sayma: enable multilink DRTIO --- artiq/gateware/targets/sayma_amc.py | 38 ++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index e89fa6e35..8283f6844 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -294,23 +294,39 @@ class Master(MiniSoC, AMPSoC): self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - self.comb += platform.request("sfp_tx_disable", 0).eq(0) + self.comb += [ + platform.request("sfp_tx_disable", i).eq(0) + for i in range(2) + ] self.submodules.drtio_transceiver = gth_ultrascale.GTH( clock_pads=platform.request("si5324_clkout"), - data_pads=[platform.request("sfp", 0)], + data_pads=[platform.request("sfp", i) for i in range(2)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") - self.submodules.drtio0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"})( - DRTIOMaster(self.drtio_transceiver.channels[0])) - self.csr_devices.append("drtio0") - self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, - self.drtio0.aux_controller.bus) - self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) + drtio_csr_group = [] + drtio_memory_group = [] + drtio_cri = [] + for i in range(2): + core_name = "drtio" + str(i) + memory_name = "drtio" + str(i) + "_aux" + drtio_csr_group.append(core_name) + drtio_memory_group.append(memory_name) + + core = ClockDomainsRenamer({"rtio_rx": "rtio_rx"+str(i)})( + DRTIOMaster(self.drtio_transceiver.channels[i])) + setattr(self.submodules, core_name, core) + drtio_cri.append(core.cri) + self.csr_devices.append(core_name) + + memory_address = self.mem_map["drtio_aux"] + 0x800*i + self.add_wb_slave(memory_address, 0x800, + core.aux_controller.bus) + self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None - self.add_csr_group("drtio", ["drtio0"]) - self.add_memory_group("drtio_aux", ["drtio0_aux"]) + self.add_csr_group("drtio", drtio_csr_group) + self.add_memory_group("drtio_aux", drtio_memory_group) rtio_clk_period = 1e9/rtio_clk_freq for gth in self.drtio_transceiver.gths: @@ -349,7 +365,7 @@ class Master(MiniSoC, AMPSoC): self.register_kernel_cpu_csrdevice("rtio_dma") self.submodules.cri_con = rtio.CRIInterconnectShared( [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri, self.drtio0.cri]) + [self.rtio_core.cri] + drtio_cri) self.register_kernel_cpu_csrdevice("cri_con") From c2d2cc2d72d12a846763ffff8d532a74938fba3f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Mar 2018 09:42:54 +0800 Subject: [PATCH 0464/2457] runtime: fix setup_si5324_as_synthesizer --- artiq/firmware/runtime/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 181981df6..0be6550b3 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -152,7 +152,8 @@ fn setup_si5324_as_synthesizer() bwsel : 3, crystal_ref: true }; - board_artiq::si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin2).expect("cannot initialize Si5324"); + board_artiq::si5324::setup(&SI5324_SETTINGS, + board_artiq::si5324::Input::Ckin2).expect("cannot initialize Si5324"); } #[cfg(has_ethmac)] From 7d98864b318afb1f420964e46918c0a4cf347349 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Mar 2018 09:43:09 +0800 Subject: [PATCH 0465/2457] sayma: enable siphaser --- artiq/gateware/drtio/si_phaser.py | 12 ++++++------ artiq/gateware/targets/sayma_amc.py | 14 ++++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/artiq/gateware/drtio/si_phaser.py b/artiq/gateware/drtio/si_phaser.py index 292dd3a9f..54c9af2fb 100644 --- a/artiq/gateware/drtio/si_phaser.py +++ b/artiq/gateware/drtio/si_phaser.py @@ -18,7 +18,7 @@ class SiPhaser7Series(Module, AutoCSR): # we do not use the crystal reference so that the PFD (f3) frequency # can be high. mmcm_freerun_fb = Signal() - mmcm_freerun_output = Signal() + self.mmcm_freerun_output = Signal() self.specials += \ Instance("MMCME2_BASE", p_CLKIN1_PERIOD=1e9/125e6, @@ -29,14 +29,14 @@ class SiPhaser7Series(Module, AutoCSR): o_CLKFBOUT=mmcm_freerun_fb, i_CLKFBIN=mmcm_freerun_fb, - p_CLKOUT0_DIVIDE_F=5.0, o_CLKOUT0=mmcm_freerun_output, + p_CLKOUT0_DIVIDE_F=5.0, o_CLKOUT0=self.mmcm_freerun_output, ) # 150MHz to 150MHz with controllable phase shift, VCO @ 1200MHz. # Inserted between CDR and output to Si, used to correct # non-determinstic skew of Si5324. mmcm_ps_fb = Signal() - mmcm_ps_output = Signal() + self.mmcm_ps_output = Signal() self.specials += \ Instance("MMCME2_ADV", p_CLKIN1_PERIOD=1e9/150e6, @@ -51,7 +51,7 @@ class SiPhaser7Series(Module, AutoCSR): o_CLKFBOUT=mmcm_ps_fb, i_CLKFBIN=mmcm_ps_fb, p_CLKOUT0_USE_FINE_PS="TRUE", - o_CLKOUT0=mmcm_ps_output, + o_CLKOUT0=self.mmcm_ps_output, i_PSCLK=ClockSignal(), i_PSEN=self.phase_shift.re, @@ -62,8 +62,8 @@ class SiPhaser7Series(Module, AutoCSR): si5324_clkin_se = Signal() self.specials += [ Instance("BUFGMUX", - i_I0=mmcm_freerun_output, - i_I1=mmcm_ps_output, + i_I0=self.mmcm_freerun_output, + i_I1=self.mmcm_ps_output, i_S=self.switch_clocks.storage, o_O=si5324_clkin_se ), diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 8283f6844..ae650216f 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -33,6 +33,7 @@ from artiq.gateware import remote_csr from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale +from artiq.gateware.drtio.si_phaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite from artiq.build_soc import build_artiq_soc @@ -432,12 +433,13 @@ class Satellite(BaseSoC): self.add_memory_group("drtio_aux", ["drtio0_aux"]) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - si5324_clkin = platform.request("si5324_clkin") - self.specials += \ - Instance("OBUFDS", - i_I=ClockSignal("rtio_rx0"), - o_O=si5324_clkin.p, o_OB=si5324_clkin.n - ) + self.submodules.si_phaser = SiPhaser7Series( + si5324_clkin=platform.request("si5324_clkin"), + si5324_clkout_fabric=platform.request("si5324_clkout_fabric") + ) + platform.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets {mmcm_ps}]", + mmcm_ps=self.si_phaser.mmcm_ps_output) + self.csr_devices.append("si_phaser") self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) self.csr_devices.append("si5324_rst_n") i2c = self.platform.request("i2c") From e6e5236ce224502b077606b6ff5914804776b10b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Mar 2018 09:45:27 +0800 Subject: [PATCH 0466/2457] firmware: fix si5324 select_recovered_clock --- artiq/firmware/libboard_artiq/si5324.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 9aeeb36be..2738bec71 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -272,7 +272,7 @@ pub fn select_recovered_clock(rc: bool) -> Result<()> { unsafe { csr::si_phaser::switch_clocks_write(if rc { 1 } else { 0 }); } - write(3, (read(3)? & 0xdf) | (1 << 5))?; // DHOLD=0 + write(3, (read(3)? & 0xdf) | (0 << 5))?; // DHOLD=0 monitor_lock()?; Ok(()) } From acfd9db185aa29238f282aee61ac357857a208e8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Mar 2018 10:04:18 +0800 Subject: [PATCH 0467/2457] siphaser: minor cleanup --- artiq/gateware/drtio/si_phaser.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/drtio/si_phaser.py b/artiq/gateware/drtio/si_phaser.py index 54c9af2fb..b4681615b 100644 --- a/artiq/gateware/drtio/si_phaser.py +++ b/artiq/gateware/drtio/si_phaser.py @@ -18,7 +18,7 @@ class SiPhaser7Series(Module, AutoCSR): # we do not use the crystal reference so that the PFD (f3) frequency # can be high. mmcm_freerun_fb = Signal() - self.mmcm_freerun_output = Signal() + mmcm_freerun_output = Signal() self.specials += \ Instance("MMCME2_BASE", p_CLKIN1_PERIOD=1e9/125e6, @@ -29,14 +29,14 @@ class SiPhaser7Series(Module, AutoCSR): o_CLKFBOUT=mmcm_freerun_fb, i_CLKFBIN=mmcm_freerun_fb, - p_CLKOUT0_DIVIDE_F=5.0, o_CLKOUT0=self.mmcm_freerun_output, + p_CLKOUT0_DIVIDE_F=5.0, o_CLKOUT0=mmcm_freerun_output, ) # 150MHz to 150MHz with controllable phase shift, VCO @ 1200MHz. # Inserted between CDR and output to Si, used to correct # non-determinstic skew of Si5324. mmcm_ps_fb = Signal() - self.mmcm_ps_output = Signal() + mmcm_ps_output = Signal() self.specials += \ Instance("MMCME2_ADV", p_CLKIN1_PERIOD=1e9/150e6, @@ -51,7 +51,7 @@ class SiPhaser7Series(Module, AutoCSR): o_CLKFBOUT=mmcm_ps_fb, i_CLKFBIN=mmcm_ps_fb, p_CLKOUT0_USE_FINE_PS="TRUE", - o_CLKOUT0=self.mmcm_ps_output, + o_CLKOUT0=mmcm_ps_output, i_PSCLK=ClockSignal(), i_PSEN=self.phase_shift.re, @@ -62,8 +62,8 @@ class SiPhaser7Series(Module, AutoCSR): si5324_clkin_se = Signal() self.specials += [ Instance("BUFGMUX", - i_I0=self.mmcm_freerun_output, - i_I1=self.mmcm_ps_output, + i_I0=mmcm_freerun_output, + i_I1=mmcm_ps_output, i_S=self.switch_clocks.storage, o_O=si5324_clkin_se ), @@ -83,3 +83,7 @@ class SiPhaser7Series(Module, AutoCSR): clkout_sample1 = Signal() # IOB register self.sync.rtio_rx0 += clkout_sample1.eq(si5324_clkout_se) self.specials += MultiReg(clkout_sample1, self.sample_result.status) + + # expose MMCM outputs - used for clock constraints + self.mmcm_freerun_output = mmcm_freerun_output + self.mmcm_ps_output = mmcm_ps_output From f7aba6b570858b0c2c8f3fcc2bab17a02b2da6fe Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Mar 2018 10:05:05 +0800 Subject: [PATCH 0468/2457] siphaser: fix phase_shift_done CSR --- artiq/gateware/drtio/si_phaser.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/si_phaser.py b/artiq/gateware/drtio/si_phaser.py index b4681615b..13c61d81e 100644 --- a/artiq/gateware/drtio/si_phaser.py +++ b/artiq/gateware/drtio/si_phaser.py @@ -10,7 +10,7 @@ class SiPhaser7Series(Module, AutoCSR): def __init__(self, si5324_clkin, si5324_clkout_fabric): self.switch_clocks = CSRStorage() self.phase_shift = CSR() - self.phase_shift_done = CSRStatus() + self.phase_shift_done = CSRStatus(reset=1) self.sample_result = CSRStatus() # 125MHz system clock to 150MHz. VCO @ 625MHz. @@ -37,6 +37,7 @@ class SiPhaser7Series(Module, AutoCSR): # non-determinstic skew of Si5324. mmcm_ps_fb = Signal() mmcm_ps_output = Signal() + mmcm_ps_psdone = Signal() self.specials += \ Instance("MMCME2_ADV", p_CLKIN1_PERIOD=1e9/150e6, @@ -56,8 +57,12 @@ class SiPhaser7Series(Module, AutoCSR): i_PSCLK=ClockSignal(), i_PSEN=self.phase_shift.re, i_PSINCDEC=self.phase_shift.r, - o_PSDONE=self.phase_shift_done.status, + o_PSDONE=mmcm_ps_psdone, ) + self.sync += [ + If(self.phase_shift.re, self.phase_shift_done.status.eq(0)), + If(mmcm_ps_psdone, self.phase_shift_done.status.eq(1)) + ] si5324_clkin_se = Signal() self.specials += [ From 74d1df3ff0541a91ec0af296d8ab70b4085f2381 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Mar 2018 10:56:12 +0800 Subject: [PATCH 0469/2457] firmware: implement si5324 skew calibration --- artiq/firmware/libboard_artiq/si5324.rs | 75 ++++++++++++++++++++++++- artiq/firmware/satman/main.rs | 2 +- 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 2738bec71..9b93eae96 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -278,7 +278,78 @@ pub fn select_recovered_clock(rc: bool) -> Result<()> { } #[cfg(has_si_phaser)] -pub fn calibrate_skew() -> Result<()> { - // TODO: implement +fn phase_shift(direction: u8) { + unsafe { + csr::si_phaser::phase_shift_write(direction); + while csr::si_phaser::phase_shift_done_read() == 0 {} + } + // wait for the Si5324 loop to stabilize + clock::spin_us(500); +} + +#[cfg(has_si_phaser)] +fn get_phaser_sample() -> bool { + let mut sample = true; + for _ in 0..32 { + if unsafe { csr::si_phaser::sample_result_read() } == 0 { + sample = false; + } + } + sample +} + +#[cfg(has_si_phaser)] +const PS_MARGIN: u32 = 28; + +#[cfg(has_si_phaser)] +fn get_stable_phaser_sample() -> (bool, u32) { + let mut nshifts: u32 = 0; + loop { + let s1 = get_phaser_sample(); + for _ in 0..PS_MARGIN { + phase_shift(1); + } + let s2 = get_phaser_sample(); + for _ in 0..PS_MARGIN { + phase_shift(1); + } + let s3 = get_phaser_sample(); + nshifts += 2*PS_MARGIN; + if s1 == s2 && s2 == s3 { + for _ in 0..PS_MARGIN { + phase_shift(0); + } + nshifts -= PS_MARGIN; + return (s2, nshifts); + } + } +} + +#[cfg(has_si_phaser)] +pub fn calibrate_skew(skew: u16) -> Result<()> { + // Get into a 0 region + let (s1, mut nshifts) = get_stable_phaser_sample(); + if s1 { + while get_phaser_sample() { + phase_shift(1); + nshifts += 1; + } + for _ in 0..PS_MARGIN { + phase_shift(1); + } + nshifts += PS_MARGIN; + } + + // Get to the 0->1 transition + while !get_phaser_sample() { + phase_shift(1); + nshifts += 1; + } + info!("nshifts to 0->1 siphaser transition: {} ({}deg)", nshifts, nshifts*360/(56*8)); + + // Apply specified skew referenced to that transition + for _ in 0..skew { + phase_shift(1); + } Ok(()) } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index e1b60179d..19f0d2517 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -236,7 +236,7 @@ fn startup() { } info!("link is up, switching to recovered clock"); si5324::select_recovered_clock(true).expect("failed to switch clocks"); - si5324::calibrate_skew().expect("failed to calibrate skew"); + si5324::calibrate_skew(32).expect("failed to calibrate skew"); drtio_reset(false); drtio_reset_phy(false); while drtio_link_rx_up() { From 916197c4d78ac1ebd58d7ffe2c16e0b1d7647797 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Mar 2018 11:15:44 +0800 Subject: [PATCH 0470/2457] siphaser: cleanup --- artiq/firmware/libboard_artiq/si5324.rs | 145 +++++++++--------- artiq/firmware/satman/main.rs | 6 +- .../drtio/{si_phaser.py => siphaser.py} | 0 artiq/gateware/targets/kasli.py | 6 +- artiq/gateware/targets/sayma_amc.py | 8 +- 5 files changed, 83 insertions(+), 82 deletions(-) rename artiq/gateware/drtio/{si_phaser.py => siphaser.py} (100%) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 9b93eae96..8cd8d94d8 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -1,6 +1,6 @@ use core::result; use board::clock; -#[cfg(any(not(si5324_soft_reset), has_si_phaser))] +#[cfg(not(si5324_soft_reset))] use board::csr; use i2c; @@ -266,90 +266,91 @@ pub fn select_input(input: Input) -> Result<()> { Ok(()) } -#[cfg(has_si_phaser)] -pub fn select_recovered_clock(rc: bool) -> Result<()> { - write(3, (read(3)? & 0xdf) | (1 << 5))?; // DHOLD=1 - unsafe { - csr::si_phaser::switch_clocks_write(if rc { 1 } else { 0 }); - } - write(3, (read(3)? & 0xdf) | (0 << 5))?; // DHOLD=0 - monitor_lock()?; - Ok(()) -} +#[cfg(has_siphaser)] +pub mod siphaser { + use super::*; + use board::csr; + use board::clock; -#[cfg(has_si_phaser)] -fn phase_shift(direction: u8) { - unsafe { - csr::si_phaser::phase_shift_write(direction); - while csr::si_phaser::phase_shift_done_read() == 0 {} - } - // wait for the Si5324 loop to stabilize - clock::spin_us(500); -} - -#[cfg(has_si_phaser)] -fn get_phaser_sample() -> bool { - let mut sample = true; - for _ in 0..32 { - if unsafe { csr::si_phaser::sample_result_read() } == 0 { - sample = false; + pub fn select_recovered_clock(rc: bool) -> Result<()> { + write(3, (read(3)? & 0xdf) | (1 << 5))?; // DHOLD=1 + unsafe { + csr::siphaser::switch_clocks_write(if rc { 1 } else { 0 }); } + write(3, (read(3)? & 0xdf) | (0 << 5))?; // DHOLD=0 + monitor_lock()?; + Ok(()) } - sample -} -#[cfg(has_si_phaser)] -const PS_MARGIN: u32 = 28; + fn phase_shift(direction: u8) { + unsafe { + csr::siphaser::phase_shift_write(direction); + while csr::siphaser::phase_shift_done_read() == 0 {} + } + // wait for the Si5324 loop to stabilize + clock::spin_us(500); + } -#[cfg(has_si_phaser)] -fn get_stable_phaser_sample() -> (bool, u32) { - let mut nshifts: u32 = 0; - loop { - let s1 = get_phaser_sample(); - for _ in 0..PS_MARGIN { - phase_shift(1); - } - let s2 = get_phaser_sample(); - for _ in 0..PS_MARGIN { - phase_shift(1); - } - let s3 = get_phaser_sample(); - nshifts += 2*PS_MARGIN; - if s1 == s2 && s2 == s3 { - for _ in 0..PS_MARGIN { - phase_shift(0); + fn get_phaser_sample() -> bool { + let mut sample = true; + for _ in 0..32 { + if unsafe { csr::siphaser::sample_result_read() } == 0 { + sample = false; + } + } + sample + } + + const PS_MARGIN: u32 = 28; + + fn get_stable_phaser_sample() -> (bool, u32) { + let mut nshifts: u32 = 0; + loop { + let s1 = get_phaser_sample(); + for _ in 0..PS_MARGIN { + phase_shift(1); + } + let s2 = get_phaser_sample(); + for _ in 0..PS_MARGIN { + phase_shift(1); + } + let s3 = get_phaser_sample(); + nshifts += 2*PS_MARGIN; + if s1 == s2 && s2 == s3 { + for _ in 0..PS_MARGIN { + phase_shift(0); + } + nshifts -= PS_MARGIN; + return (s2, nshifts); } - nshifts -= PS_MARGIN; - return (s2, nshifts); } } -} -#[cfg(has_si_phaser)] -pub fn calibrate_skew(skew: u16) -> Result<()> { - // Get into a 0 region - let (s1, mut nshifts) = get_stable_phaser_sample(); - if s1 { - while get_phaser_sample() { + pub fn calibrate_skew(skew: u16) -> Result<()> { + // Get into a 0 region + let (s1, mut nshifts) = get_stable_phaser_sample(); + if s1 { + while get_phaser_sample() { + phase_shift(1); + nshifts += 1; + } + for _ in 0..PS_MARGIN { + phase_shift(1); + } + nshifts += PS_MARGIN; + } + + // Get to the 0->1 transition + while !get_phaser_sample() { phase_shift(1); nshifts += 1; } - for _ in 0..PS_MARGIN { + info!("nshifts to 0->1 siphaser transition: {} ({}deg)", nshifts, nshifts*360/(56*8)); + + // Apply specified skew referenced to that transition + for _ in 0..skew { phase_shift(1); } - nshifts += PS_MARGIN; + Ok(()) } - - // Get to the 0->1 transition - while !get_phaser_sample() { - phase_shift(1); - nshifts += 1; - } - info!("nshifts to 0->1 siphaser transition: {} ({}deg)", nshifts, nshifts*360/(56*8)); - - // Apply specified skew referenced to that transition - for _ in 0..skew { - phase_shift(1); - } - Ok(()) } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 19f0d2517..c00c5b484 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -235,8 +235,8 @@ fn startup() { process_errors(); } info!("link is up, switching to recovered clock"); - si5324::select_recovered_clock(true).expect("failed to switch clocks"); - si5324::calibrate_skew(32).expect("failed to calibrate skew"); + si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); + si5324::siphaser::calibrate_skew(32).expect("failed to calibrate skew"); drtio_reset(false); drtio_reset_phy(false); while drtio_link_rx_up() { @@ -246,7 +246,7 @@ fn startup() { drtio_reset_phy(true); drtio_reset(true); info!("link is down, switching to local crystal clock"); - si5324::select_recovered_clock(false).expect("failed to switch clocks"); + si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks"); } } diff --git a/artiq/gateware/drtio/si_phaser.py b/artiq/gateware/drtio/siphaser.py similarity index 100% rename from artiq/gateware/drtio/si_phaser.py rename to artiq/gateware/drtio/siphaser.py diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 77791cfed..05542e817 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -21,7 +21,7 @@ from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi2 from artiq.gateware.drtio.transceiver import gtp_7series -from artiq.gateware.drtio.si_phaser import SiPhaser7Series +from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite from artiq.build_soc import build_artiq_soc @@ -574,11 +574,11 @@ class Satellite(BaseSoC): self.add_memory_group("drtio_aux", ["drtio0_aux"]) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - self.submodules.si_phaser = SiPhaser7Series( + self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), si5324_clkout_fabric=platform.request("si5324_clkout_fabric") ) - self.csr_devices.append("si_phaser") + self.csr_devices.append("siphaser") i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) self.csr_devices.append("i2c") diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index ae650216f..6e909f2db 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -33,7 +33,7 @@ from artiq.gateware import remote_csr from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_simple, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale -from artiq.gateware.drtio.si_phaser import SiPhaser7Series +from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite from artiq.build_soc import build_artiq_soc @@ -433,13 +433,13 @@ class Satellite(BaseSoC): self.add_memory_group("drtio_aux", ["drtio0_aux"]) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - self.submodules.si_phaser = SiPhaser7Series( + self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), si5324_clkout_fabric=platform.request("si5324_clkout_fabric") ) platform.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets {mmcm_ps}]", - mmcm_ps=self.si_phaser.mmcm_ps_output) - self.csr_devices.append("si_phaser") + mmcm_ps=self.siphaser.mmcm_ps_output) + self.csr_devices.append("siphaser") self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) self.csr_devices.append("si5324_rst_n") i2c = self.platform.request("i2c") From 2cbd597416368268dd2adb275f89164d325badbb Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 6 Mar 2018 16:50:21 +0000 Subject: [PATCH 0471/2457] LaneDistributor: style and signal consolidation [NFC] --- artiq/gateware/rtio/sed/lane_distributor.py | 35 ++++++++++++------- .../test/rtio/test_sed_lane_distributor.py | 20 ++++++++--- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index 8fe7af477..a34e98519 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -28,7 +28,8 @@ class LaneDistributor(Module): # an underflow, at the time when the CRI write happens, and to a channel # with zero latency compensation. This is synchronous to the system clock # domain. - self.minimum_coarse_timestamp = Signal(64-glbl_fine_ts_width) + us_timestamp_width = 64 - glbl_fine_ts_width + self.minimum_coarse_timestamp = Signal(us_timestamp_width) self.output = [Record(layouts.fifo_ingress(seqn_width, layout_payload)) for _ in range(lane_count)] @@ -50,10 +51,10 @@ class LaneDistributor(Module): current_lane = Signal(max=lane_count) # The last coarse timestamp received from the CRI, after compensation. # Used to determine when to switch lanes. - last_coarse_timestamp = Signal(64-glbl_fine_ts_width) + last_coarse_timestamp = Signal(us_timestamp_width) # The last coarse timestamp written to each lane. Used to detect # sequence errors. - last_lane_coarse_timestamps = Array(Signal(64-glbl_fine_ts_width) + last_lane_coarse_timestamps = Array(Signal(us_timestamp_width) for _ in range(lane_count)) # Sequence number counter. The sequence number is used to determine which # event wins during a replace. @@ -72,7 +73,6 @@ class LaneDistributor(Module): self.comb += lio.payload.data.eq(self.cri.o_data) # when timestamp and channel arrive in cycle #1, prepare computations - us_timestamp_width = 64 - glbl_fine_ts_width coarse_timestamp = Signal(us_timestamp_width) self.comb += coarse_timestamp.eq(self.cri.timestamp[glbl_fine_ts_width:]) min_minus_timestamp = Signal((us_timestamp_width + 1, True)) @@ -96,15 +96,17 @@ class LaneDistributor(Module): for channel in quash_channels: self.sync += If(self.cri.chan_sel[:16] == channel, quash.eq(1)) + assert all(abs(c) < 1 << 14 - 1 for c in compensation) latency_compensation = Memory(14, len(compensation), init=compensation) latency_compensation_port = latency_compensation.get_port() - self.specials += latency_compensation, latency_compensation_port - self.comb += latency_compensation_port.adr.eq(self.cri.chan_sel[:16]) + self.specials += latency_compensation, latency_compensation_port + self.comb += latency_compensation_port.adr.eq(self.cri.chan_sel[:16]) # cycle #2, write compensation = Signal((14, True)) self.comb += compensation.eq(latency_compensation_port.dat_r) timestamp_above_min = Signal() + timestamp_above_last = Signal() timestamp_above_laneA_min = Signal() timestamp_above_laneB_min = Signal() timestamp_above_lane_min = Signal() @@ -119,8 +121,9 @@ class LaneDistributor(Module): timestamp_above_min.eq(min_minus_timestamp - compensation < 0), timestamp_above_laneA_min.eq(laneAmin_minus_timestamp - compensation < 0), timestamp_above_laneB_min.eq(laneBmin_minus_timestamp - compensation < 0), - If(force_laneB | (last_minus_timestamp - compensation >= 0), - use_lanen.eq(current_lane + 1), + timestamp_above_last.eq(last_minus_timestamp - compensation < 0), + If(force_laneB | ~timestamp_above_last, + use_lanen.eq(current_lane_plus_one), use_laneB.eq(1) ).Else( use_lanen.eq(current_lane), @@ -128,10 +131,16 @@ class LaneDistributor(Module): ), timestamp_above_lane_min.eq(Mux(use_laneB, timestamp_above_laneB_min, timestamp_above_laneA_min)), - If(~quash, - do_write.eq((self.cri.cmd == cri.commands["write"]) & timestamp_above_min & timestamp_above_lane_min), - do_underflow.eq((self.cri.cmd == cri.commands["write"]) & ~timestamp_above_min), - do_sequence_error.eq((self.cri.cmd == cri.commands["write"]) & timestamp_above_min & ~timestamp_above_lane_min), + If(~quash & (self.cri.cmd == cri.commands["write"]), + If(timestamp_above_min, + If(timestamp_above_lane_min, + do_write.eq(1) + ).Else( + do_sequence_error.eq(1) + ) + ).Else( + do_underflow.eq(1) + ) ), Array(lio.we for lio in self.output)[use_lanen].eq(do_write) ] @@ -139,7 +148,7 @@ class LaneDistributor(Module): self.comb += compensated_timestamp.eq(self.cri.timestamp + (compensation << glbl_fine_ts_width)) self.sync += [ If(do_write, - If(use_laneB, current_lane.eq(current_lane + 1)), + current_lane.eq(use_lanen), last_coarse_timestamp.eq(compensated_timestamp[glbl_fine_ts_width:]), last_lane_coarse_timestamps[use_lanen].eq(compensated_timestamp[glbl_fine_ts_width:]), seqn.eq(seqn + 1), diff --git a/artiq/gateware/test/rtio/test_sed_lane_distributor.py b/artiq/gateware/test/rtio/test_sed_lane_distributor.py index c02b6c4bb..609877643 100644 --- a/artiq/gateware/test/rtio/test_sed_lane_distributor.py +++ b/artiq/gateware/test/rtio/test_sed_lane_distributor.py @@ -77,12 +77,15 @@ def simulate(input_events, compensation=None, wait=True): class TestLaneDistributor(unittest.TestCase): def test_regular(self): + # N sequential events, all on lane 0 N = 16 output, access_results = simulate([(42+n, (n+1)*8) for n in range(N)], wait=False) self.assertEqual(output, [(0, n, 42+n, (n+1)*8) for n in range(N)]) self.assertEqual(access_results, [("ok", 0)]*N) def test_wait_time(self): + # LANE_COUNT simultaneous events should be distributed and written to + # the lanes when the latter are writable output, access_results = simulate([(42+n, 8) for n in range(LANE_COUNT)]) self.assertEqual(output, [(n, n, 42+n, 8) for n in range(LANE_COUNT)]) expected_access_results = [("ok", 0)]*LANE_COUNT @@ -91,33 +94,40 @@ class TestLaneDistributor(unittest.TestCase): self.assertEqual(access_results, expected_access_results) def test_lane_switch(self): + # N events separated by one fine timestamp distributed onto lanes + # LANE_COUNT == 1 << fine_ts_width N = 32 output, access_results = simulate([(42+n, n+8) for n in range(N)], wait=False) self.assertEqual(output, [((n-n//8) % LANE_COUNT, n, 42+n, n+8) for n in range(N)]) self.assertEqual([ar[0] for ar in access_results], ["ok"]*N) def test_sequence_error(self): + # LANE_COUNT + 1 simultaneous events, the last one being discarded due + # to sequence error, followed by a valid event input_events = [(42+n, 8) for n in range(LANE_COUNT+1)] input_events.append((42+LANE_COUNT+1, 16)) output, access_results = simulate(input_events) self.assertEqual(len(output), len(input_events)-1) # event with sequence error must get discarded + self.assertEqual(output[-1], (0, LANE_COUNT, 42+LANE_COUNT+1, 16)) self.assertEqual([ar[0] for ar in access_results[:LANE_COUNT]], ["ok"]*LANE_COUNT) self.assertEqual(access_results[LANE_COUNT][0], "sequence_error") + self.assertEqual(access_results[LANE_COUNT + 1][0], "ok") def test_underflow(self): + # N sequential events except the penultimate which underflows N = 16 - input_events = [(42+n, (n+1)*8) for n in range(N-2)] - input_events.append((0, 0)) # timestamp < 8 underflows - input_events.append((42+N-2, N*8)) + input_events = [(42+n, (n+1)*8) for n in range(N)] + input_events[-2] = (0, 0) # timestamp < 8 underflows output, access_results = simulate(input_events) self.assertEqual(len(output), len(input_events)-1) # event with underflow must get discarded self.assertEqual([ar[0] for ar in access_results[:N-2]], ["ok"]*(N-2)) self.assertEqual(access_results[N-2][0], "underflow") - self.assertEqual(output[N-2], (0, N-2, 42+N-2, N*8)) + self.assertEqual(output[N-2], (0, N-2, 42+N-1, N*8)) self.assertEqual(access_results[N-1][0], "ok") def test_spread(self): - # get to lane 6 + # 6 simultaneous events to reach lane 6 and 7 which are not writable + # for 1 and 4 cycles respectively causing a forced lane switch input_events = [(42+n, 8) for n in range(7)] input_events.append((100, 16)) input_events.append((100, 32)) From 8b70db5f17f46f7d5ab66a5fafe63af6a4a5c842 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 7 Mar 2018 10:28:34 +0000 Subject: [PATCH 0472/2457] LaneDistributor: try equivalent spread logic --- artiq/gateware/rtio/sed/lane_distributor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index a34e98519..9e727393d 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -176,10 +176,10 @@ class LaneDistributor(Module): # current lane has been full, spread events by switching to the next. if enable_spread: - current_lane_writable_r = Signal(reset=1) + do_write_r = Signal() self.sync += [ - current_lane_writable_r.eq(current_lane_writable), - If(~current_lane_writable_r & current_lane_writable, + do_write_r.eq(do_write), + If(do_write_r & ~current_lane_writable, force_laneB.eq(1) ), If(do_write, From a6d1b030c1f1697755a081f671c571d734a96187 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 7 Mar 2018 11:26:01 +0000 Subject: [PATCH 0473/2457] RTIO: use TS counter in the correct CD artiq/m-labs#938 --- artiq/gateware/rtio/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index c2bee2947..484c64bbe 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -67,7 +67,7 @@ class Core(Module, AutoCSR): coarse_ts = Signal(64-glbl_fine_ts_width) self.sync.rtio += coarse_ts.eq(coarse_ts + 1) - coarse_ts_cdc = GrayCodeTransfer(len(coarse_ts)) + coarse_ts_cdc = GrayCodeTransfer(len(coarse_ts)) # from rtio to sys self.submodules += coarse_ts_cdc self.comb += [ coarse_ts_cdc.i.eq(coarse_ts), @@ -83,7 +83,7 @@ class Core(Module, AutoCSR): interface=self.cri) self.submodules += outputs self.comb += outputs.coarse_timestamp.eq(coarse_ts) - self.sync += outputs.minimum_coarse_timestamp.eq(coarse_ts + 16) + self.sync += outputs.minimum_coarse_timestamp.eq(coarse_ts_cdc.o + 16) inputs = InputCollector(channels, glbl_fine_ts_width, "async", quash_channels=quash_channels, From 4af7600b2de785457fda4ac3cf3dfe88fe720966 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 7 Mar 2018 11:34:51 +0000 Subject: [PATCH 0474/2457] Revert "LaneDistributor: try equivalent spread logic" This reverts commit 8b70db5f17f46f7d5ab66a5fafe63af6a4a5c842. Just a shot into the dark. --- artiq/gateware/rtio/sed/lane_distributor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index 9e727393d..a34e98519 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -176,10 +176,10 @@ class LaneDistributor(Module): # current lane has been full, spread events by switching to the next. if enable_spread: - do_write_r = Signal() + current_lane_writable_r = Signal(reset=1) self.sync += [ - do_write_r.eq(do_write), - If(do_write_r & ~current_lane_writable, + current_lane_writable_r.eq(current_lane_writable), + If(~current_lane_writable_r & current_lane_writable, force_laneB.eq(1) ), If(do_write, From 7afb23e8be261686330586c739bc858669d5c47d Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 7 Mar 2018 14:28:21 +0100 Subject: [PATCH 0475/2457] runtime: demote dropped and malformed packets msgs to debug --- artiq/firmware/runtime/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 0be6550b3..20261c025 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -237,13 +237,13 @@ fn startup_ethernet() { Ok(true) => (), Ok(false) => break, Err(smoltcp::Error::Unrecognized) => (), - Err(err) => warn!("network error: {}", err) + Err(err) => debug!("network error: {}", err) } } } if let Some(_net_stats_diff) = net_stats.update() { - warn!("ethernet mac:{}", ethmac::EthernetStatistics::new()); + debug!("ethernet mac:{}", ethmac::EthernetStatistics::new()); } } } From b0282fa855a32e42de2e897db7abd98370269d08 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 7 Mar 2018 14:23:28 +0000 Subject: [PATCH 0476/2457] spi2: reset configuration in rio_phy --- artiq/gateware/rtio/phy/spi2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/phy/spi2.py b/artiq/gateware/rtio/phy/spi2.py index cc4c06da6..c304d5b93 100644 --- a/artiq/gateware/rtio/phy/spi2.py +++ b/artiq/gateware/rtio/phy/spi2.py @@ -73,7 +73,7 @@ class SPIMaster(Module): config.end.reset = 1 read = Signal() - self.sync.rio += [ + self.sync.rio_phy += [ If(self.rtlink.i.stb, read.eq(0) ), From 3a6566f9492f9c7eae2188079e293491a7a73c4e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 7 Mar 2018 15:11:32 +0100 Subject: [PATCH 0477/2457] rtio: judicious spray with reset_less=True Hoping to reduce rst routing difficulty and easier RTIO timing closure. --- artiq/gateware/rtio/cdc.py | 8 ++++---- artiq/gateware/rtio/cri.py | 6 +++--- artiq/gateware/rtio/input_collector.py | 4 +++- artiq/gateware/rtio/rtlink.py | 10 +++++----- artiq/gateware/rtio/sed/gates.py | 4 +++- artiq/gateware/rtio/sed/lane_distributor.py | 11 ++++++----- artiq/gateware/rtio/sed/output_driver.py | 10 ++++++---- artiq/gateware/rtio/sed/output_network.py | 3 ++- 8 files changed, 32 insertions(+), 24 deletions(-) diff --git a/artiq/gateware/rtio/cdc.py b/artiq/gateware/rtio/cdc.py index e5f75fba3..9feb0d8c6 100644 --- a/artiq/gateware/rtio/cdc.py +++ b/artiq/gateware/rtio/cdc.py @@ -9,12 +9,12 @@ __all__ = ["GrayCodeTransfer", "BlindTransfer"] class GrayCodeTransfer(Module): def __init__(self, width): self.i = Signal(width) # in rtio domain - self.o = Signal(width) # in sys domain + self.o = Signal(width, reset_less=True) # in sys domain # # # # convert to Gray code - value_gray_rtio = Signal(width) + value_gray_rtio = Signal(width, reset_less=True) self.sync.rtio += value_gray_rtio.eq(self.i ^ self.i[1:]) # transfer to system clock domain value_gray_sys = Signal(width) @@ -34,7 +34,7 @@ class BlindTransfer(Module): self.o = Signal() if data_width: self.data_i = Signal(data_width) - self.data_o = Signal(data_width) + self.data_o = Signal(data_width, reset_less=True) # # # @@ -54,7 +54,7 @@ class BlindTransfer(Module): ] if data_width: - bxfer_data = Signal(data_width) + bxfer_data = Signal(data_width, reset_less=True) isync += If(ps.i, bxfer_data.eq(self.data_i)) bxfer_data.attr.add("no_retiming") self.specials += MultiReg(bxfer_data, self.data_o, diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index c85958baa..1d2b89435 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -47,8 +47,8 @@ layout = [ class Interface(Record): - def __init__(self): - Record.__init__(self, layout) + def __init__(self, **kwargs): + Record.__init__(self, layout, **kwargs) class KernelInitiator(Module, AutoCSR): @@ -112,7 +112,7 @@ class CRIDecoder(Module): # # # - selected = Signal(8) + selected = Signal(8, reset_less=True) self.sync += selected.eq(self.master.chan_sel[16:]) # master -> slave diff --git a/artiq/gateware/rtio/input_collector.py b/artiq/gateware/rtio/input_collector.py index d0cba4f50..cff5aeaf8 100644 --- a/artiq/gateware/rtio/input_collector.py +++ b/artiq/gateware/rtio/input_collector.py @@ -119,8 +119,10 @@ class InputCollector(Module): i_status_raw = Signal(2) self.comb += i_status_raw.eq(Array(i_statuses)[sel]) - input_timeout = Signal.like(self.cri.timestamp) + input_timeout = Signal.like(self.cri.timestamp, reset_less=True) input_pending = Signal() + self.cri.i_data.reset_less = True + self.cri.i_timestamp.reset_less = True sync_cri += [ i_ack.eq(0), If(i_ack, diff --git a/artiq/gateware/rtio/rtlink.py b/artiq/gateware/rtio/rtlink.py index 06cc0ebf2..66e678412 100644 --- a/artiq/gateware/rtio/rtlink.py +++ b/artiq/gateware/rtio/rtlink.py @@ -9,11 +9,11 @@ class OInterface: self.busy = Signal() if data_width: - self.data = Signal(data_width) + self.data = Signal(data_width, reset_less=True) if address_width: - self.address = Signal(address_width) + self.address = Signal(address_width, reset_less=True) if fine_ts_width: - self.fine_ts = Signal(fine_ts_width) + self.fine_ts = Signal(fine_ts_width, reset_less=True) self.enable_replace = enable_replace @@ -36,9 +36,9 @@ class IInterface: self.stb = Signal() if data_width: - self.data = Signal(data_width) + self.data = Signal(data_width, reset_less=True) if fine_ts_width: - self.fine_ts = Signal(fine_ts_width) + self.fine_ts = Signal(fine_ts_width, reset_less=True) assert(not fine_ts_width or timestamped) self.timestamped = timestamped diff --git a/artiq/gateware/rtio/sed/gates.py b/artiq/gateware/rtio/sed/gates.py index 9b1c27d23..bf4a99d25 100644 --- a/artiq/gateware/rtio/sed/gates.py +++ b/artiq/gateware/rtio/sed/gates.py @@ -10,7 +10,8 @@ class Gates(Module): def __init__(self, lane_count, seqn_width, layout_fifo_payload, layout_output_network_payload): self.input = [Record(layouts.fifo_egress(seqn_width, layout_fifo_payload)) for _ in range(lane_count)] - self.output = [Record(layouts.output_network_node(seqn_width, layout_output_network_payload)) + self.output = [Record(layouts.output_network_node(seqn_width, layout_output_network_payload), + reset_less=True) for _ in range(lane_count)] if hasattr(self.output[0].payload, "fine_ts"): @@ -35,4 +36,5 @@ class Gates(Module): ] self.comb += input.re.eq(input.payload.timestamp[glbl_fine_ts_width:] == self.coarse_timestamp) + output.valid.reset_less = False self.sync += output.valid.eq(input.re & input.readable) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index a34e98519..a2834f13b 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -23,7 +23,7 @@ class LaneDistributor(Module): interface = cri.Interface() self.cri = interface self.sequence_error = Signal() - self.sequence_error_channel = Signal(16) + self.sequence_error_channel = Signal(16, reset_less=True) # The minimum timestamp that an event must have to avoid triggering # an underflow, at the time when the CRI write happens, and to a channel # with zero latency compensation. This is synchronous to the system clock @@ -75,10 +75,11 @@ class LaneDistributor(Module): # when timestamp and channel arrive in cycle #1, prepare computations coarse_timestamp = Signal(us_timestamp_width) self.comb += coarse_timestamp.eq(self.cri.timestamp[glbl_fine_ts_width:]) - min_minus_timestamp = Signal((us_timestamp_width + 1, True)) - laneAmin_minus_timestamp = Signal((us_timestamp_width + 1, True)) - laneBmin_minus_timestamp = Signal((us_timestamp_width + 1, True)) - last_minus_timestamp = Signal((us_timestamp_width + 1, True)) + min_minus_timestamp = Signal((us_timestamp_width + 1, True), + reset_less=True) + laneAmin_minus_timestamp = Signal.like(min_minus_timestamp) + laneBmin_minus_timestamp = Signal.like(min_minus_timestamp) + last_minus_timestamp = Signal.like(min_minus_timestamp) current_lane_plus_one = Signal(max=lane_count) self.comb += current_lane_plus_one.eq(current_lane + 1) self.sync += [ diff --git a/artiq/gateware/rtio/sed/output_driver.py b/artiq/gateware/rtio/sed/output_driver.py index 3150e98b6..e98c87227 100644 --- a/artiq/gateware/rtio/sed/output_driver.py +++ b/artiq/gateware/rtio/sed/output_driver.py @@ -13,9 +13,9 @@ __all__ = ["OutputDriver"] class OutputDriver(Module): def __init__(self, channels, glbl_fine_ts_width, lane_count, seqn_width): self.collision = Signal() - self.collision_channel = Signal(max=len(channels)) + self.collision_channel = Signal(max=len(channels), reset_less=True) self.busy = Signal() - self.busy_channel = Signal(max=len(channels)) + self.busy_channel = Signal(max=len(channels), reset_less=True) # output network layout_on_payload = layouts.output_network_payload(channels, glbl_fine_ts_width) @@ -29,9 +29,11 @@ class OutputDriver(Module): ("collision", 1), ("payload", layout_on_payload) ] - lane_datas = [Record(layout_lane_data) for _ in range(lane_count)] + lane_datas = [Record(layout_lane_data, reset_less=True) for _ in range(lane_count)] en_replaces = [channel.interface.o.enable_replace for channel in channels] for lane_data, on_output in zip(lane_datas, output_network.output): + lane_data.valid.reset_less = False + lane_data.collision.reset_less = False replace_occured_r = Signal() nondata_replace_occured_r = Signal() self.sync += [ @@ -96,7 +98,7 @@ class OutputDriver(Module): ] for lane_data in lane_datas: stb_r = Signal() - channel_r = Signal(max=len(channels)) + channel_r = Signal(max=len(channels), reset_less=True) self.sync += [ stb_r.eq(lane_data.valid & ~lane_data.collision), channel_r.eq(lane_data.payload.channel), diff --git a/artiq/gateware/rtio/sed/output_network.py b/artiq/gateware/rtio/sed/output_network.py index 1b57baf9e..8be0ef0ef 100644 --- a/artiq/gateware/rtio/sed/output_network.py +++ b/artiq/gateware/rtio/sed/output_network.py @@ -56,7 +56,8 @@ class OutputNetwork(Module): step_input = self.input for step in boms_steps_pairs(lane_count): - step_output = [Record(layouts.output_network_node(seqn_width, layout_payload)) + step_output = [Record(layouts.output_network_node(seqn_width, layout_payload), + reset_less=True) for _ in range(lane_count)] for node1, node2 in step: From 5cc1d2a1d3f05d65aedb372f49f6ec25509101eb Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 7 Mar 2018 17:17:30 +0100 Subject: [PATCH 0478/2457] conda: bump migen, misoc * flterm leak * kasli version * sayma ddram * ethernet clocking * fifo dout reset_less --- conda/artiq-dev/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index c3a5342be..11c332b64 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,8 +14,8 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_14+git8fcd67a - - misoc 0.9 py35_20+git5fed1095 + - migen 0.7 py35_18+git90e4101 + - misoc 0.9 py35_29+gitbf82a812 - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27 From 82831a85b6a4a27983f19ff73bf60fbf66f9b247 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 7 Mar 2018 18:50:39 +0000 Subject: [PATCH 0479/2457] kasli/opticlock: add eem6 phys --- artiq/gateware/targets/kasli.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 05542e817..920af19fb 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -305,6 +305,20 @@ class Opticlock(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) + phy = spi2.SPIMaster(self.platform.request("eem6_spi_p"), + self.platform.request("eem6_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + for signal in "io_update".split(): + pads = platform.request("eem6_{}".format(signal)) + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + pads = platform.request("eem6_dds_reset") + self.specials += DifferentialOutput(0, pads.p, pads.n) + self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) From 37ec97eb28e6212ee4d8808e008b49069d4b0916 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 7 Mar 2018 19:00:50 +0000 Subject: [PATCH 0480/2457] ad9910/2: add sw invariant only when passed --- artiq/coredevice/ad9910.py | 3 ++- artiq/coredevice/ad9912.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 06ddfee67..4be5d8ff7 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -49,7 +49,7 @@ class AD9910: :param pll_cp: DDS PLL charge pump setting. :param pll_vco: DDS PLL VCO range selection. """ - kernel_invariants = {"chip_select", "cpld", "core", "bus", "sw", + kernel_invariants = {"chip_select", "cpld", "core", "bus", "ftw_per_hz", "pll_n", "pll_cp", "pll_vco"} def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, @@ -61,6 +61,7 @@ class AD9910: self.chip_select = chip_select if sw_device: self.sw = dmgr.get(sw_device) + self.kernel_invariants.add("sw") assert 12 <= pll_n <= 127 self.pll_n = pll_n assert self.cpld.refclk/4 <= 60e6 diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index fbf116e05..f8b139be8 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -24,7 +24,7 @@ class AD9912: f_ref*pll_n where f_ref is the reference frequency (set in the parent Urukul CPLD instance). """ - kernel_invariants = {"chip_select", "cpld", "core", "bus", "sw", + kernel_invariants = {"chip_select", "cpld", "core", "bus", "ftw_per_hz", "sysclk", "pll_n"} def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, @@ -36,6 +36,7 @@ class AD9912: self.chip_select = chip_select if sw_device: self.sw = dmgr.get(sw_device) + self.kernel_invariants.add("sw") self.pll_n = pll_n self.sysclk = self.cpld.refclk*pll_n assert self.sysclk <= 1e9 From 8bd85caafb257d05016906f4b9e7d4cd3bf1bb86 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Mar 2018 15:09:33 +0800 Subject: [PATCH 0481/2457] examples: fix Sayma DRTIO ref_period --- artiq/examples/sayma_drtio/device_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/sayma_drtio/device_db.py b/artiq/examples/sayma_drtio/device_db.py index 92b7dd13d..7808734ac 100644 --- a/artiq/examples/sayma_drtio/device_db.py +++ b/artiq/examples/sayma_drtio/device_db.py @@ -5,7 +5,7 @@ device_db = { "type": "local", "module": "artiq.coredevice.core", "class": "Core", - "arguments": {"host": core_addr, "ref_period": 2e-9} + "arguments": {"host": core_addr, "ref_period": 1/(8*150e6)} }, "core_log": { "type": "controller", From 0adbbd8ede0ccc119ae35c32b5689934d33776de Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Mar 2018 15:41:05 +0800 Subject: [PATCH 0482/2457] drtio: reset aux packet gateware after locking to recovered clock Closes #949 --- artiq/firmware/libdrtioaux/lib.rs | 11 +++++++++++ artiq/firmware/satman/main.rs | 1 + 2 files changed, 12 insertions(+) diff --git a/artiq/firmware/libdrtioaux/lib.rs b/artiq/firmware/libdrtioaux/lib.rs index bb4aa6dcc..e818ab22e 100644 --- a/artiq/firmware/libdrtioaux/lib.rs +++ b/artiq/firmware/libdrtioaux/lib.rs @@ -269,6 +269,17 @@ pub mod hw { use super::*; use std::io::Cursor; + pub fn reset(linkno: u8) { + let linkno = linkno as usize; + unsafe { + // clear buffer first to limit race window with buffer overflow + // error. We assume the CPU is fast enough so that no two packets + // will be received between the buffer and the error flag are cleared. + (board::csr::DRTIO[linkno].aux_rx_present_write)(1); + (board::csr::DRTIO[linkno].aux_rx_error_write)(1); + } + } + fn rx_has_error(linkno: u8) -> bool { let linkno = linkno as usize; unsafe { diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index c00c5b484..19ab75bcc 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -237,6 +237,7 @@ fn startup() { info!("link is up, switching to recovered clock"); si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); si5324::siphaser::calibrate_skew(32).expect("failed to calibrate skew"); + drtioaux::hw::reset(0); drtio_reset(false); drtio_reset_phy(false); while drtio_link_rx_up() { From 8bd15d36c4f3e206c5f128a8dc462a7adb671dbe Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Mar 2018 16:28:25 +0800 Subject: [PATCH 0483/2457] drtio: fix error CSR edge detection (#947) --- artiq/gateware/drtio/rt_errors_satellite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index bf6e9a3d9..743b5e031 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -28,7 +28,7 @@ class RTErrorsSatellite(Module, AutoCSR): if detect_edges: source_r = Signal() self.sync.rio += source_r.eq(source) - self.comb += xfer.i.eq(source & source_r) + self.comb += xfer.i.eq(source & ~source_r) else: self.comb += xfer.i.eq(source) From 8475c21c461a9aefca4849ee69ba3e2d589e9a62 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 8 Mar 2018 09:56:45 +0100 Subject: [PATCH 0484/2457] firmware/libboard/sdram: kusddrphy now use time mode for odelaye3/idelaye3, now reloading dqs delay_value (500ps) with software --- artiq/firmware/libboard/sdram.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index a753bc453..4a88bd528 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -35,6 +35,8 @@ mod ddr { unsafe fn write_level(logger: &mut Option<&mut fmt::Write>, delay: &mut [u16; DQS_SIGNAL_COUNT], high_skew: &mut [bool; DQS_SIGNAL_COUNT]) -> bool { + #[cfg(kusddrphy)] + log!(logger, "DQS initial delay: {} taps\n", ddrphy::wdly_dqs_taps_read()); log!(logger, "Write leveling: "); enable_write_leveling(true); @@ -52,6 +54,10 @@ mod ddr { ddrphy::wdly_dq_rst_write(1); ddrphy::wdly_dqs_rst_write(1); + #[cfg(kusddrphy)] + for _ in 0..ddrphy::wdly_dqs_taps_read() { + ddrphy::wdly_dqs_inc_write(1); + } ddrphy::wlevel_strobe_write(1); spin_cycles(10); @@ -268,9 +274,13 @@ pub unsafe fn init(mut _logger: Option<&mut fmt::Write>) -> bool { #[cfg(has_ddrphy)] { + #[cfg(kusddrphy)] + csr::ddrphy::en_vtc_write(0); if !ddr::level(&mut _logger) { return false } + #[cfg(kusddrphy)] + csr::ddrphy::en_vtc_write(1); } csr::dfii::control_write(sdram_phy::DFII_CONTROL_SEL); From 37f5f0d38d9322011f94a49a3d89a827d263f751 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 9 Mar 2018 00:48:32 +0800 Subject: [PATCH 0485/2457] examples: add DMA to Sayma DRTIO --- artiq/examples/sayma_drtio/device_db.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/artiq/examples/sayma_drtio/device_db.py b/artiq/examples/sayma_drtio/device_db.py index 7808734ac..dc0ef7aff 100644 --- a/artiq/examples/sayma_drtio/device_db.py +++ b/artiq/examples/sayma_drtio/device_db.py @@ -18,6 +18,11 @@ device_db = { "module": "artiq.coredevice.cache", "class": "CoreCache" }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, "led0": { "type": "local", From e38187c760bda318a35c72269916d06ba3831fea Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 9 Mar 2018 00:49:07 +0800 Subject: [PATCH 0486/2457] drtio: increase default underflow margin. Closes #947 --- artiq/gateware/drtio/rt_controller_master.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index ea325a1b8..24387bda2 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -19,7 +19,7 @@ class _CSRs(AutoCSR): self.tsc_correction = CSRStorage(64) self.set_time = CSR() - self.underflow_margin = CSRStorage(16, reset=200) + self.underflow_margin = CSRStorage(16, reset=300) self.o_get_buffer_space = CSR() self.o_dbg_buffer_space = CSRStatus(16) From 3fbcf5f303e01ee0903fad0307aa637dc3494f57 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 9 Mar 2018 10:36:17 +0800 Subject: [PATCH 0487/2457] drtio: remove TSC correction (#40) --- artiq/gateware/drtio/rt_controller_master.py | 9 ++------- artiq/gateware/test/drtio/test_full_stack.py | 9 +++------ 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 24387bda2..786e2aa97 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -17,7 +17,6 @@ class _CSRs(AutoCSR): self.protocol_error = CSR(3) - self.tsc_correction = CSRStorage(64) self.set_time = CSR() self.underflow_margin = CSRStorage(16, reset=300) @@ -83,13 +82,9 @@ class RTController(Module): # master RTIO counter and counter synchronization self.submodules.counter = RTIOCounter(64-fine_ts_width) - self.comb += self.cri.counter.eq(self.counter.value_sys << fine_ts_width) - tsc_correction = Signal(64) - self.csrs.tsc_correction.storage.attr.add("no_retiming") - self.specials += MultiReg(self.csrs.tsc_correction.storage, tsc_correction) self.comb += [ - rt_packet.tsc_value.eq( - self.counter.value_rtio + tsc_correction), + self.cri.counter.eq(self.counter.value_sys << fine_ts_width), + rt_packet.tsc_value.eq(self.counter.value_rtio), self.csrs.set_time.w.eq(rt_packet.set_time_stb) ] self.sync += [ diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 45d6a4441..82b0d1c79 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -211,7 +211,7 @@ class TestFullStack(unittest.TestCase): {"sys": test(), "rtio": tb.check_ttls(ttl_changes)}, self.clocks) self.assertEqual(ttl_changes, correct_ttl_changes) - def test_tsc_error(self): + def test_write_underflow(self): tb = OutputsTestbench() def test(): @@ -220,11 +220,8 @@ class TestFullStack(unittest.TestCase): yield from tb.init() errors = yield from saterr.protocol_error.read() self.assertEqual(errors, 0) - yield from csrs.tsc_correction.write(100000000) - yield from csrs.set_time.write(1) - for i in range(15): - yield - tb.delay(10000) + yield from csrs.underflow_margin.write(0) + tb.delay(100) yield from tb.write(0, 1) for i in range(12): yield From b0b13be23b886a3ea4d77755f5477fe1bfa61f85 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 9 Mar 2018 09:23:20 +0100 Subject: [PATCH 0488/2457] libboard/sdram: rename read_delays to read_leveling --- artiq/firmware/libboard/sdram.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index 4a88bd528..2f16fc8ee 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -142,8 +142,8 @@ mod ddr { } } - unsafe fn read_delays(logger: &mut Option<&mut fmt::Write>) { - log!(logger, "Read delays: "); + unsafe fn read_leveling(logger: &mut Option<&mut fmt::Write>) { + log!(logger, "Read leveling: "); // Generate pseudo-random sequence let mut prs = [0; DFII_NPHASES * DFII_PIX_DATA_SIZE]; @@ -259,7 +259,7 @@ mod ddr { read_bitslip(logger, &delay, &high_skew); } - read_delays(logger); + read_leveling(logger); true } From 8f6f83029cd376d33f707d61d08763c5689433c2 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 9 Mar 2018 10:45:45 +0100 Subject: [PATCH 0489/2457] libboard/sdram: add write/read leveling scan --- artiq/firmware/libboard/sdram.rs | 131 ++++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index 2f16fc8ee..246b51fff 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -31,6 +31,51 @@ mod ddr { ddrphy::wlevel_en_write(enabled as u8); } + #[cfg(kusddrphy)] + unsafe fn write_level_scan(logger: &mut Option<&mut fmt::Write>) { + log!(logger, "DQS initial delay: {} taps\n", ddrphy::wdly_dqs_taps_read()); + log!(logger, "Write leveling scan:\n"); + + enable_write_leveling(true); + spin_cycles(100); + + for n in 0..DQS_SIGNAL_COUNT { + let dq_addr = dfii::PI0_RDDATA_ADDR + .offset((DQS_SIGNAL_COUNT - 1 - n) as isize); + + log!(logger, "Module {}:\n", DQS_SIGNAL_COUNT - 1 - n); + + ddrphy::dly_sel_write(1 << n); + + ddrphy::wdly_dq_rst_write(1); + ddrphy::wdly_dqs_rst_write(1); + #[cfg(kusddrphy)] + for _ in 0..ddrphy::wdly_dqs_taps_read() { + ddrphy::wdly_dqs_inc_write(1); + } + + let mut dq; + for _ in 0..DDRPHY_MAX_DELAY { + ddrphy::wlevel_strobe_write(1); + spin_cycles(10); + dq = ptr::read_volatile(dq_addr); + if dq != 0 { + log!(logger, "1"); + } + else { + log!(logger, "0"); + } + + ddrphy::wdly_dq_inc_write(1); + ddrphy::wdly_dqs_inc_write(1); + } + + log!(logger, "\n"); + } + + enable_write_leveling(false); + } + #[cfg(ddrphy_wlevel)] unsafe fn write_level(logger: &mut Option<&mut fmt::Write>, delay: &mut [u16; DQS_SIGNAL_COUNT], @@ -142,7 +187,85 @@ mod ddr { } } - unsafe fn read_leveling(logger: &mut Option<&mut fmt::Write>) { + #[cfg(kusddrphy)] + unsafe fn read_level_scan(logger: &mut Option<&mut fmt::Write>) { + log!(logger, "Read leveling scan:\n"); + + // Generate pseudo-random sequence + let mut prs = [0; DFII_NPHASES * DFII_PIX_DATA_SIZE]; + let mut prv = 42; + for b in prs.iter_mut() { + prv = 1664525 * prv + 1013904223; + *b = prv as u8; + } + + // Activate + dfii::pi0_address_write(0); + dfii::pi0_baddress_write(0); + sdram_phy::command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CS); + spin_cycles(15); + + // Write test pattern + for p in 0..DFII_NPHASES { + for offset in 0..DFII_PIX_DATA_SIZE { + let addr = DFII_PIX_WRDATA_ADDR[p].offset(offset as isize); + let data = prs[DFII_PIX_DATA_SIZE * p + offset]; + ptr::write_volatile(addr, data as u32); + } + } + sdram_phy::dfii_piwr_address_write(0); + sdram_phy::dfii_piwr_baddress_write(0); + sdram_phy::command_pwr(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS| + DFII_COMMAND_WRDATA); + + // Calibrate each DQ in turn + sdram_phy::dfii_pird_address_write(0); + sdram_phy::dfii_pird_baddress_write(0); + for n in 0..DQS_SIGNAL_COUNT { + log!(logger, "Module {}:\n", DQS_SIGNAL_COUNT - n - 1); + + ddrphy::dly_sel_write(1 << (DQS_SIGNAL_COUNT - n - 1)); + + ddrphy::rdly_dq_rst_write(1); + + for _ in 0..DDRPHY_MAX_DELAY { + sdram_phy::command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS| + DFII_COMMAND_RDDATA); + spin_cycles(15); + + let mut working = true; + for p in 0..DFII_NPHASES { + for _ in 0..64 { + for &offset in [n, n + DQS_SIGNAL_COUNT].iter() { + let addr = DFII_PIX_RDDATA_ADDR[p].offset(offset as isize); + let data = prs[DFII_PIX_DATA_SIZE * p + offset]; + if ptr::read_volatile(addr) as u8 != data { + working = false; + } + } + } + } + if working { + log!(logger, "1"); + } + else { + log!(logger, "0"); + } + ddrphy::rdly_dq_inc_write(1); + } + + log!(logger, "\n"); + + } + + // Precharge + dfii::pi0_address_write(0); + dfii::pi0_baddress_write(0); + sdram_phy::command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS); + spin_cycles(15); + } + + unsafe fn read_level(logger: &mut Option<&mut fmt::Write>) { log!(logger, "Read leveling: "); // Generate pseudo-random sequence @@ -253,13 +376,17 @@ mod ddr { { let mut delay = [0; DQS_SIGNAL_COUNT]; let mut high_skew = [false; DQS_SIGNAL_COUNT]; + #[cfg(kusddrphy)] + write_level_scan(logger); if !write_level(logger, &mut delay, &mut high_skew) { return false } read_bitslip(logger, &delay, &high_skew); } - read_leveling(logger); + #[cfg(kusddrphy)] + read_level_scan(logger); + read_level(logger); true } From e65e2421a33bda988fd046c6450ab8bee112ff05 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 9 Mar 2018 21:32:18 +0800 Subject: [PATCH 0490/2457] conda: bump migen/misoc --- conda/artiq-dev/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 11c332b64..12b6e1f84 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,8 +14,8 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_18+git90e4101 - - misoc 0.9 py35_29+gitbf82a812 + - migen 0.7 py35_19+git96f2fa6 + - misoc 0.9 py35_37+gitf051a1f2 - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27 From caf7b14b55f2a92c8dba03d650864d575eb93e66 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 9 Mar 2018 22:36:16 +0800 Subject: [PATCH 0491/2457] kasli: generate fine RTIO clock in DRTIO targets, separate RTIO channel code --- artiq/gateware/targets/kasli.py | 151 +++++++++++++++++++++++--------- 1 file changed, 108 insertions(+), 43 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 920af19fb..2d6a1b5cb 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -379,7 +379,32 @@ class SYSU(_StandaloneBase): self.add_rtio(rtio_channels) -class Master(MiniSoC, AMPSoC): +class _RTIOClockMultiplier(Module): + def __init__(self, rtio_clk_freq): + self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) + + # See "Global Clock Network Deskew Using Two BUFGs" in ug472. + clkfbout = Signal() + clkfbin = Signal() + rtiox4_clk = Signal() + self.specials += [ + Instance("MMCME2_BASE", + p_CLKIN1_PERIOD=1e9/rtio_clk_freq, + i_CLKIN1=ClockSignal("rtio"), + i_RST=ResetSignal("rtio"), + + p_CLKFBOUT_MULT_F=8.0, p_DIVCLK_DIVIDE=1, + + o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbin, + + p_CLKOUT0_DIVIDE_F=2.0, o_CLKOUT0=rtiox4_clk, + ), + Instance("BUFG", i_I=clkfbout, o_O=clkfbin), + Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk) + ] + + +class _MasterBase(MiniSoC, AMPSoC): mem_map = { "cri_con": 0x10000000, "rtio": 0x20000000, @@ -412,8 +437,8 @@ class Master(MiniSoC, AMPSoC): self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - sfp_ctl = [platform.request("sfp_ctl", i) for i in range(1, 3)] - self.comb += [sc.tx_disable.eq(0) for sc in sfp_ctl] + self.sfp_ctl = [platform.request("sfp_ctl", i) for i in range(1, 3)] + self.comb += [sc.tx_disable.eq(0) for sc in self.sfp_ctl] self.submodules.drtio_transceiver = gtp_7series.GTP( qpll_channel=self.drtio_qpll_channel, data_pads=[platform.request("sfp", i) for i in range(1, 3)], @@ -425,7 +450,7 @@ class Master(MiniSoC, AMPSoC): drtio_csr_group = [] drtio_memory_group = [] - drtio_cri = [] + self.drtio_cri = [] for i in range(2): core_name = "drtio" + str(i) memory_name = "drtio" + str(i) + "_aux" @@ -435,7 +460,7 @@ class Master(MiniSoC, AMPSoC): core = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)})( DRTIOMaster(self.drtio_transceiver.channels[i])) setattr(self.submodules, core_name, core) - drtio_cri.append(core.cri) + self.drtio_cri.append(core.cri) self.csr_devices.append(core_name) memory_address = self.mem_map["drtio_aux"] + 0x800*i @@ -454,18 +479,9 @@ class Master(MiniSoC, AMPSoC): self.crg.cd_sys.clk, gtp.txoutclk, gtp.rxoutclk) - rtio_channels = [] - phy = ttl_simple.Output(platform.request("user_led", 0)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - for sc in sfp_ctl: - phy = ttl_simple.Output(sc.led) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) + self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) + def add_rtio(self, rtio_channels): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") @@ -479,7 +495,7 @@ class Master(MiniSoC, AMPSoC): self.register_kernel_cpu_csrdevice("rtio_dma") self.submodules.cri_con = rtio.CRIInterconnectShared( [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri] + drtio_cri) + [self.rtio_core.cri] + self.drtio_cri) self.register_kernel_cpu_csrdevice("cri_con") self.submodules.rtio_analyzer = rtio.Analyzer(self.cri_con.switch.slave, @@ -519,7 +535,7 @@ class Master(MiniSoC, AMPSoC): self.drtio_qpll_channel, self.ethphy_qpll_channel = qpll.channels -class Satellite(BaseSoC): +class _SatelliteBase(BaseSoC): mem_map = { "drtio_aux": 0x50000000, } @@ -536,18 +552,6 @@ class Satellite(BaseSoC): platform = self.platform rtio_clk_freq = 150e6 - rtio_channels = [] - phy = ttl_simple.Output(platform.request("user_led", 0)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - for i in range(1, 3): - phy = ttl_simple.Output(platform.request("sfp_ctl", i).led) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) - self.csr_devices.append("rtio_moninj") - disable_si5324_ibuf = Signal(reset=1) disable_si5324_ibuf.attr.add("no_retiming") si5324_clkout = platform.request("si5324_clkout") @@ -574,19 +578,6 @@ class Satellite(BaseSoC): self.sync += disable_si5324_ibuf.eq( ~self.drtio_transceiver.stable_clkin.storage) - rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) - self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) - self.submodules.drtio0 = rx0(DRTIOSatellite( - self.drtio_transceiver.channels[0], rtio_channels, - self.rx_synchronizer)) - self.csr_devices.append("drtio0") - self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, - self.drtio0.aux_controller.bus) - self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) - self.config["HAS_DRTIO"] = None - self.add_csr_group("drtio", ["drtio0"]) - self.add_memory_group("drtio_aux", ["drtio0_aux"]) - self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), @@ -608,6 +599,80 @@ class Satellite(BaseSoC): self.crg.cd_sys.clk, gtp.txoutclk, gtp.rxoutclk) + self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) + + def add_rtio(self, rtio_channels): + self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) + self.csr_devices.append("rtio_moninj") + + rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) + self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) + self.submodules.drtio0 = rx0(DRTIOSatellite( + self.drtio_transceiver.channels[0], rtio_channels, + self.rx_synchronizer)) + self.csr_devices.append("drtio0") + self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, + self.drtio0.aux_controller.bus) + self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) + self.config["HAS_DRTIO"] = None + self.add_csr_group("drtio", ["drtio0"]) + self.add_memory_group("drtio_aux", ["drtio0_aux"]) + + +class Master(_MasterBase): + def __init__(self, *args, **kwargs): + _MasterBase.__init__(self, *args, **kwargs) + + platform = self.platform + platform.add_extension(_dio("eem0")) + + rtio_channels = [] + + phy = ttl_simple.Output(platform.request("user_led", 0)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + for sc in self.sfp_ctl: + phy = ttl_simple.Output(sc.led) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + for i in range(8): + pads = platform.request("eem0", i) + phy = ttl_serdes_7series.InOut_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) + rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(rtio_channels) + + +class Satellite(_SatelliteBase): + def __init__(self, *args, **kwargs): + _SatelliteBase.__init__(self, *args, **kwargs) + + platform = self.platform + platform.add_extension(_dio("eem0")) + + rtio_channels = [] + phy = ttl_simple.Output(platform.request("user_led", 0)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + for i in range(1, 3): + phy = ttl_simple.Output(platform.request("sfp_ctl", i).led) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + for i in range(8): + pads = platform.request("eem0", i) + phy = ttl_serdes_7series.InOut_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.add_rtio(rtio_channels) + def main(): parser = argparse.ArgumentParser( From fc3d97f1f76121e4cbc5b734a7c0129c353547b1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 9 Mar 2018 22:46:20 +0800 Subject: [PATCH 0492/2457] drtio: remove spurious multichannel transceiver clock constraints They used to cause (otherwise harmless) Vivado critical warnings. --- artiq/gateware/targets/kasli.py | 12 ++++++++---- artiq/gateware/targets/sayma_amc.py | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 2d6a1b5cb..824699780 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -472,12 +472,16 @@ class _MasterBase(MiniSoC, AMPSoC): self.add_memory_group("drtio_aux", drtio_memory_group) rtio_clk_period = 1e9/rtio_clk_freq - for gtp in self.drtio_transceiver.gtps: + gtp = self.drtio_transceiver.gtps[0] + platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) + platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, + gtp.txoutclk, gtp.rxoutclk) + for gtp in self.drtio_transceiver.gtps[1:]: platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) - platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( - self.crg.cd_sys.clk, - gtp.txoutclk, gtp.rxoutclk) + self.crg.cd_sys.clk, gtp.rxoutclk) self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 6e909f2db..0b25886ba 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -330,12 +330,16 @@ class Master(MiniSoC, AMPSoC): self.add_memory_group("drtio_aux", drtio_memory_group) rtio_clk_period = 1e9/rtio_clk_freq - for gth in self.drtio_transceiver.gths: - platform.add_period_constraint(gth.txoutclk, rtio_clk_period) + gth = self.drtio_transceiver.gths[0] + platform.add_period_constraint(gth.txoutclk, rtio_clk_period) + platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, + gth.txoutclk, gth.rxoutclk) + for gth in self.drtio_transceiver.gths[1:]: platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( - self.crg.cd_sys.clk, - gth.txoutclk, gth.rxoutclk) + self.crg.cd_sys.clk, gth.rxoutclk) rtio_channels = [] for i in range(4): From a95cd423cc1320968a678ab0c01fd7471e133940 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 9 Mar 2018 18:53:57 +0100 Subject: [PATCH 0493/2457] libboard/sdram: add gap for write leveling --- artiq/firmware/libboard/sdram.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index 246b51fff..a42e5c668 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -132,6 +132,12 @@ mod ddr { if !incr_delay() { break } dq = ptr::read_volatile(dq_addr); } + + // Get a bit further into the 0 zone + #[cfg(kusddrphy)] + for _ in 0..32 { + incr_delay(); + } } while dq == 0 { From 5af4609053d210f81ee09ae798f94153aa8d1978 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 9 Mar 2018 19:06:47 +0100 Subject: [PATCH 0494/2457] libboard/sdram: limit write leveling scan to "512 - initial dqs taps delay" on ultrascale --- artiq/firmware/libboard/sdram.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index a42e5c668..aa8b0330b 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -39,6 +39,11 @@ mod ddr { enable_write_leveling(true); spin_cycles(100); + let mut ddrphy_max_delay : u16 = DDRPHY_MAX_DELAY; + #[cfg(kusddrphy)] { + ddrphy_max_delay -= ddrphy::wdly_dqs_taps_read(); + } + for n in 0..DQS_SIGNAL_COUNT { let dq_addr = dfii::PI0_RDDATA_ADDR .offset((DQS_SIGNAL_COUNT - 1 - n) as isize); @@ -55,7 +60,7 @@ mod ddr { } let mut dq; - for _ in 0..DDRPHY_MAX_DELAY { + for _ in 0..ddrphy_max_delay { ddrphy::wlevel_strobe_write(1); spin_cycles(10); dq = ptr::read_volatile(dq_addr); @@ -87,6 +92,11 @@ mod ddr { enable_write_leveling(true); spin_cycles(100); + let mut ddrphy_max_delay : u16 = DDRPHY_MAX_DELAY; + #[cfg(kusddrphy)] { + ddrphy_max_delay -= ddrphy::wdly_dqs_taps_read(); + } + let mut failed = false; for n in 0..DQS_SIGNAL_COUNT { let dq_addr = dfii::PI0_RDDATA_ADDR @@ -108,7 +118,7 @@ mod ddr { let mut incr_delay = || { delay[n] += 1; - if delay[n] >= DDRPHY_MAX_DELAY { + if delay[n] >= ddrphy_max_delay { failed = true; return false } From a04bd5a4fd2bf9328c33ab2ec72f37ae65d07f25 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 8 Mar 2018 15:22:07 +0000 Subject: [PATCH 0495/2457] spi2: xfers take one more cycle until ~busy --- artiq/coredevice/spi2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index 31e1effa2..d64f1ad17 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -162,7 +162,7 @@ class SPIMaster: raise ValueError("Invalid SPI transfer length") if div > 257 or div < 2: raise ValueError("Invalid SPI clock divider") - self.xfer_duration_mu = (length + 1)*div*self.ref_period_mu + self.xfer_duration_mu = ((length + 1)*div + 1)*self.ref_period_mu rtio_output(now_mu(), self.channel, SPI_CONFIG_ADDR, flags | ((length - 1) << 8) | ((div - 2) << 16) | (cs << 24)) delay_mu(self.ref_period_mu) From 44277c5b7e6e1082ed97d9e88e75fd77253b88ce Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 11 Mar 2018 10:11:42 +0800 Subject: [PATCH 0496/2457] conda: bump migen/misoc --- conda/artiq-dev/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 12b6e1f84..c1143ee16 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,8 +14,8 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_19+git96f2fa6 - - misoc 0.9 py35_37+gitf051a1f2 + - migen 0.7 py35_20+git1f82faa + - misoc 0.10 py35_0+gitd167deff - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27 From 6dfebd54ddf777f0b6641f57a9acba7f1618cc94 Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Sun, 11 Mar 2018 22:55:39 +0000 Subject: [PATCH 0497/2457] ttl_serdes_7series: use correct IBUFDS_INTERMDISABLE port names --- artiq/gateware/rtio/phy/ttl_serdes_7series.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_7series.py b/artiq/gateware/rtio/phy/ttl_serdes_7series.py index 0c5b89c9b..ed6faf566 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_7series.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_7series.py @@ -66,7 +66,7 @@ class _ISERDESE2_8X(Module): i_IBUFDISABLE=0, i_INTERMDISABLE=0, o_O=pad_i, - io_IO=pad, io_IOB=pad_n) + io_I=pad, io_IB=pad_n) class _IOSERDESE2_8X(Module): From eb6e59b44c30f0d544aafbffbbb368731fbe3d02 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 12 Mar 2018 11:25:29 +0100 Subject: [PATCH 0498/2457] sayma_rtm: fix serwb timing constraints (was causing the gated clock warning) --- artiq/gateware/targets/sayma_rtm.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 4061320ed..9052477a5 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -159,11 +159,7 @@ class SaymaRTM(Module): csr_devices.append("serwb_phy_rtm") serwb_phy_rtm.serdes.cd_serwb_serdes.clk.attr.add("keep") - serwb_phy_rtm.serdes.cd_serwb_serdes_20x.clk.attr.add("keep") serwb_phy_rtm.serdes.cd_serwb_serdes_5x.clk.attr.add("keep") - platform.add_period_constraint(serwb_phy_rtm.serdes.cd_serwb_serdes.clk, 40*1e9/serwb_pll.linerate), - platform.add_period_constraint(serwb_phy_rtm.serdes.cd_serwb_serdes_20x.clk, 2*1e9/serwb_pll.linerate), - platform.add_period_constraint(serwb_phy_rtm.serdes.cd_serwb_serdes_5x.clk, 8*1e9/serwb_pll.linerate) platform.add_false_path_constraints( self.crg.cd_sys.clk, serwb_phy_rtm.serdes.cd_serwb_serdes.clk, From 1d081ed6c26b8866df7cddebfce888a91aa48662 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 12 Mar 2018 23:41:19 +0800 Subject: [PATCH 0499/2457] drtio: print diagnostic info on satellite write underflow (#947) --- artiq/firmware/satman/main.rs | 15 +++++++++++++-- artiq/gateware/drtio/rt_errors_satellite.py | 17 +++++++++++++++-- artiq/gateware/test/drtio/test_full_stack.py | 6 +++++- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 19ab75bcc..bb20c5450 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -177,7 +177,6 @@ fn process_errors() { let errors; unsafe { errors = (csr::DRTIO[0].protocol_error_read)(); - (csr::DRTIO[0].protocol_error_write)(errors); } if errors & 1 != 0 { error!("received packet of an unknown type"); @@ -186,11 +185,23 @@ fn process_errors() { error!("received truncated packet"); } if errors & 4 != 0 { - error!("write underflow"); + let channel; + let timestamp_event; + let timestamp_counter; + unsafe { + channel = (csr::DRTIO[0].underflow_channel_read)(); + timestamp_event = (csr::DRTIO[0].underflow_timestamp_event_read)() as i64; + timestamp_counter = (csr::DRTIO[0].underflow_timestamp_counter_read)() as i64; + } + error!("write underflow, channel={}, timestamp={}, counter={}, slack={}", + channel, timestamp_event, timestamp_counter, timestamp_event-timestamp_counter); } if errors & 8 != 0 { error!("write overflow"); } + unsafe { + (csr::DRTIO[0].protocol_error_write)(errors); + } } #[cfg(rtio_frequency = "150.0")] diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index 743b5e031..8d563a3dc 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -9,6 +9,10 @@ from artiq.gateware.rtio.cdc import BlindTransfer class RTErrorsSatellite(Module, AutoCSR): def __init__(self, rt_packet, outputs): self.protocol_error = CSR(4) + self.underflow_channel = CSRStatus(16) + self.underflow_timestamp_event = CSRStatus(64) + self.underflow_timestamp_counter = CSRStatus(64) + self.rtio_error = CSR(3) self.sequence_error_channel = CSRStatus(16) self.collision_channel = CSRStatus(16) @@ -49,16 +53,25 @@ class RTErrorsSatellite(Module, AutoCSR): # internal ARTIQ bugs. underflow = Signal() overflow = Signal() + underflow_error_cri = Signal(16+64+64) + underflow_error_csr = Signal(16+64+64) self.comb += [ underflow.eq(outputs.cri.o_status[1]), - overflow.eq(outputs.cri.o_status[0]) + overflow.eq(outputs.cri.o_status[0]), + underflow_error_cri.eq(Cat(outputs.cri.chan_sel[:16], + outputs.cri.timestamp, + outputs.cri.counter)), + Cat(self.underflow_channel.status, + self.underflow_timestamp_event.status, + self.underflow_timestamp_counter.status).eq(underflow_error_csr) ] error_csr(self.protocol_error, (rt_packet.unknown_packet_type, False, None, None), (rt_packet.packet_truncated, False, None, None), - (underflow, True, None, None), + (underflow, True, underflow_error_cri, underflow_error_csr), (overflow, True, None, None) ) + error_csr(self.rtio_error, (outputs.sequence_error, False, outputs.sequence_error_channel, self.sequence_error_channel.status), diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 82b0d1c79..feade41d4 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -222,11 +222,15 @@ class TestFullStack(unittest.TestCase): self.assertEqual(errors, 0) yield from csrs.underflow_margin.write(0) tb.delay(100) - yield from tb.write(0, 1) + yield from tb.write(42, 1) for i in range(12): yield errors = yield from saterr.protocol_error.read() + underflow_channel = yield from saterr.underflow_channel.read() + underflow_timestamp_event = yield from saterr.underflow_timestamp_event.read() self.assertEqual(errors, 4) # write underflow + self.assertEqual(underflow_channel, 42) + self.assertEqual(underflow_timestamp_event, 100) yield from saterr.protocol_error.write(errors) yield errors = yield from saterr.protocol_error.read() From 2caeea6f251c9e3427ed08abb2dc045c18c4eade Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 13 Mar 2018 00:09:13 +0800 Subject: [PATCH 0500/2457] update copyright year --- README.rst | 2 +- artiq/firmware/bootloader/main.rs | 2 +- doc/manual/conf.py | 2 +- doc/manual/introduction.rst | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 3b380833a..dd54d3dd6 100644 --- a/README.rst +++ b/README.rst @@ -31,7 +31,7 @@ Website: https://m-labs.hk/artiq License ======= -Copyright (C) 2014-2017 M-Labs Limited. +Copyright (C) 2014-2018 M-Labs Limited. ARTIQ is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 34bc58094..c1ae1d8bc 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -197,7 +197,7 @@ pub extern fn main() -> i32 { println!(r"|_| |_|_|____/ \___/ \____|"); println!(""); println!("MiSoC Bootloader"); - println!("Copyright (c) 2017 M-Labs Limited"); + println!("Copyright (c) 2017-2018 M-Labs Limited"); println!(""); if startup() { diff --git a/doc/manual/conf.py b/doc/manual/conf.py index 9605e9015..e32cf6a5a 100644 --- a/doc/manual/conf.py +++ b/doc/manual/conf.py @@ -84,7 +84,7 @@ master_doc = 'index' # General information about the project. project = 'ARTIQ' -copyright = '2014-2017, M-Labs Limited' +copyright = '2014-2018, M-Labs Limited' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/doc/manual/introduction.rst b/doc/manual/introduction.rst index c5513f070..821f8ef8f 100644 --- a/doc/manual/introduction.rst +++ b/doc/manual/introduction.rst @@ -29,4 +29,4 @@ Website: https://m-labs.hk/artiq `Cite ARTIQ `_ as ``Bourdeauducq, Sébastien et al. (2016). ARTIQ 1.0. Zenodo. 10.5281/zenodo.51303``. -Copyright (C) 2014-2017 M-Labs Limited. Licensed under GNU LGPL version 3+. +Copyright (C) 2014-2018 M-Labs Limited. Licensed under GNU LGPL version 3+. From 999ec40e793f13eaba97a1d6ce84e623fe875c87 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 13 Mar 2018 00:11:25 +0800 Subject: [PATCH 0501/2457] bootloader: print gateware ident --- artiq/firmware/bootloader/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index c1ae1d8bc..7173ef86d 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -87,6 +87,8 @@ fn startup() -> bool { return false } + println!("Gateware ident {}", board::ident::read(&mut [0; 64])); + println!("Initializing SDRAM..."); if unsafe { board::sdram::init(Some(&mut Console)) } { From 2edf65f57b86fa9797d5f9cb300191cec31e50ba Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 13 Mar 2018 00:20:57 +0800 Subject: [PATCH 0502/2457] drtio: fix satellite minimum_coarse_timestamp clock domain (#947) --- artiq/gateware/drtio/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 36f262c4f..ff64bf5f0 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -97,7 +97,7 @@ class DRTIOSatellite(Module): enable_spread=False, report_buffer_space=True, interface=self.rt_packet.cri)) self.comb += self.outputs.coarse_timestamp.eq(coarse_ts) - self.sync += self.outputs.minimum_coarse_timestamp.eq(coarse_ts + 16) + self.sync.rtio += self.outputs.minimum_coarse_timestamp.eq(coarse_ts + 16) self.submodules.inputs = ClockDomainsRenamer("rio")( InputCollector(channels, fine_ts_width, "sync", From 2fdc18060148f3f372a0c6db756d913a0a0ebd6b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 13 Mar 2018 17:11:50 +0000 Subject: [PATCH 0503/2457] dsp/fir: outputs reset_less (pipelined) --- artiq/gateware/dsp/fir.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/dsp/fir.py b/artiq/gateware/dsp/fir.py index 516ca5c7f..002487e32 100644 --- a/artiq/gateware/dsp/fir.py +++ b/artiq/gateware/dsp/fir.py @@ -69,7 +69,7 @@ class ParallelFIR(Module): n = len(coefficients) # input and output: old to new, decreasing delay self.i = [Signal((width, True)) for i in range(p)] - self.o = [Signal((width, True)) for i in range(p)] + self.o = [Signal((width, True), reset_less=True) for i in range(p)] self.latency = (n + 1)//2//p + 2 w = _widths[arch] From a315ecd10bb08969c81ceb2d07f29d03f404a64d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 14 Mar 2018 09:01:29 +0800 Subject: [PATCH 0504/2457] rtio/ttl_serdes_7series: reset IOSERDES (#958) --- artiq/gateware/rtio/phy/ttl_serdes_7series.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_7series.py b/artiq/gateware/rtio/phy/ttl_serdes_7series.py index ed6faf566..6049d38f8 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_7series.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_7series.py @@ -17,11 +17,12 @@ class _OSERDESE2_8X(Module): p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, o_OQ=pad_o, o_TQ=self.t_out, + i_RST=ResetSignal("rio_phy"), i_CLK=ClockSignal("rtiox4"), i_CLKDIV=ClockSignal("rio_phy"), i_D1=o[0], i_D2=o[1], i_D3=o[2], i_D4=o[3], i_D5=o[4], i_D6=o[5], i_D7=o[6], i_D8=o[7], - i_TCE=1, i_OCE=1, i_RST=0, + i_TCE=1, i_OCE=1, i_T1=self.t_in) if pad_n is None: self.comb += pad.eq(pad_o) @@ -54,7 +55,8 @@ class _ISERDESE2_8X(Module): i_D=pad_i, i_CLK=ClockSignal("rtiox4"), i_CLKB=~ClockSignal("rtiox4"), - i_CE1=1, i_RST=0, + i_CE1=1, + i_RST=ResetSignal("rio_phy"), i_CLKDIV=ClockSignal("rio_phy")) if pad_n is None: self.comb += pad_i.eq(pad) From 158ceb08813fe609f9bf8ece7b8a8303ac48f716 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 14 Mar 2018 18:13:13 +0000 Subject: [PATCH 0505/2457] artiq_devtool: add kasli target. --- artiq/frontend/artiq_devtool.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 289047b90..7e60a7b2c 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -85,6 +85,9 @@ def main(): elif args.target == "sayma": board_type, firmware = "sayma", "runtime" variant = "standalone" if args.variant is None else args.variant + elif args.target == "kasli": + board_type, firmware = "kasli", "runtime" + variant = "opticlock" if args.variant is None else args.variant else: raise NotImplementedError("unknown target {}".format(args.target)) From 9ea7d7a8044641e5d6307c5794b698e853de725b Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 14 Mar 2018 18:34:31 +0000 Subject: [PATCH 0506/2457] firmware: allow building without system UART. --- artiq/firmware/libboard/lib.rs | 1 + artiq/firmware/libboard/uart_console.rs | 10 +++++++++- artiq/firmware/runtime/main.rs | 20 +++++++++++--------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/artiq/firmware/libboard/lib.rs b/artiq/firmware/libboard/lib.rs index 4d0311719..a685f5252 100644 --- a/artiq/firmware/libboard/lib.rs +++ b/artiq/firmware/libboard/lib.rs @@ -18,6 +18,7 @@ include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/sdram_phy.rs")); pub mod sdram; pub mod ident; pub mod clock; +#[cfg(has_uart)] pub mod uart; #[cfg(has_spiflash)] pub mod spiflash; diff --git a/artiq/firmware/libboard/uart_console.rs b/artiq/firmware/libboard/uart_console.rs index 5a1c82f7c..a63adeea1 100644 --- a/artiq/firmware/libboard/uart_console.rs +++ b/artiq/firmware/libboard/uart_console.rs @@ -1,16 +1,24 @@ use core::fmt; -use csr; pub struct Console; impl fmt::Write for Console { + #[cfg(has_uart)] fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { + use csr; + for c in s.bytes() { unsafe { while csr::uart::txfull_read() != 0 {} csr::uart::rxtx_write(c) } } + + Ok(()) + } + + #[cfg(not(has_uart))] + fn write_str(&mut self, _s: &str) -> Result<(), fmt::Error> { Ok(()) } } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 20261c025..6fce27df4 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -77,17 +77,19 @@ fn startup() { #[cfg(has_serwb_phy_amc)] board_artiq::serwb::wait_init(); - let t = board::clock::get_ms(); - info!("press 'e' to erase startup and idle kernels..."); - while board::clock::get_ms() < t + 1000 { - if unsafe { board::csr::uart::rxtx_read() == b'e' } { - config::remove("startup_kernel").unwrap(); - config::remove("idle_kernel").unwrap(); - info!("startup and idle kernels erased"); - break + #[cfg(has_uart)] { + let t = board::clock::get_ms(); + info!("press 'e' to erase startup and idle kernels..."); + while board::clock::get_ms() < t + 1000 { + if unsafe { board::csr::uart::rxtx_read() == b'e' } { + config::remove("startup_kernel").unwrap(); + config::remove("idle_kernel").unwrap(); + info!("startup and idle kernels erased"); + break + } } + info!("continuing boot"); } - info!("continuing boot"); #[cfg(has_i2c)] board_artiq::i2c::init(); From 5cb2602021fd29db21f1e7998829b012387ca907 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 15 Mar 2018 08:33:53 +0000 Subject: [PATCH 0507/2457] artiq_devtool: flash gateware if -g is passed. --- artiq/frontend/artiq_devtool.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 7e60a7b2c..3bc6d5047 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -36,9 +36,9 @@ def get_argparser(): parser.add_argument("-V", "--variant", metavar="VARIANT", type=str, default=None, help="variant to build, dependent on the target") - parser.add_argument("-g", "--build-gateware", + parser.add_argument("-g", "--gateware", default=False, action="store_true", - help="build gateware, not just software") + help="build/flash gateware, not just software") parser.add_argument("--args", metavar="ARGS", type=shlex.split, default=[], help="extra arguments for gateware/firmware build") @@ -144,7 +144,7 @@ def main(): def build(target, *extra_args, output_dir=build_dir(), variant=variant): build_args = ["python3", "-m", "artiq.gateware.targets." + target, *extra_args] - if not args.build_gateware: + if not args.gateware: build_args.append("--no-compile-gateware") if variant: build_args += ["--variant", variant] @@ -183,15 +183,19 @@ def main(): flash("start") elif action == "flash": - logger.info("Flashing and booting firmware") - flash("bootloader", "firmware", "start") + gateware = ["gateware"] if args.gateware else [] + + logger.info("Flashing and booting") + flash(*gateware, "bootloader", "firmware", "start") elif action == "flash+log": - logger.info("Flashing firmware") - flash("bootloader", "firmware") + gateware = ["gateware"] if args.gateware else [] + + logger.info("Flashing") + flash(*gateware, "bootloader", "firmware") flterm = client.spawn_command(["flterm", serial, "--output-only"]) - logger.info("Booting firmware") + logger.info("Booting") flash("start") client.drain(flterm) From 4b5a78e231d823111360cdb8b99c6ef6de7c1ab8 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 15 Mar 2018 22:21:29 +0000 Subject: [PATCH 0508/2457] compiler: do not pass files to external tools while they are opened. This fixes access violations on Windows that are present both with input and output files. For some reason, Cygwin-compiled binutils did not exhibit this problem, but MSYS-compiled binutils do. Fixes #961. --- artiq/compiler/targets.py | 55 +++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index db626da85..f2c7c408b 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -1,4 +1,4 @@ -import os, sys, tempfile, subprocess +import os, sys, tempfile, subprocess, io from artiq.compiler import types from llvmlite_artiq import ir as ll, binding as llvm @@ -8,27 +8,25 @@ llvm.initialize_all_asmprinters() class RunTool: def __init__(self, pattern, **tempdata): - self.files = [] - self.pattern = pattern - self.tempdata = tempdata - - def maketemp(self, data): - f = tempfile.NamedTemporaryFile() - f.write(data) - f.flush() - self.files.append(f) - return f + self._pattern = pattern + self._tempdata = tempdata + self._tempnames = {} + self._tempfiles = {} def __enter__(self): - tempfiles = {} - tempnames = {} - for key in self.tempdata: - tempfiles[key] = self.maketemp(self.tempdata[key]) - tempnames[key] = tempfiles[key].name + for key, data in self._tempdata.items(): + if data is None: + fd, filename = tempfile.mkstemp() + os.close(fd) + self._tempnames[key] = filename + else: + with tempfile.NamedTemporaryFile(delete=False) as f: + f.write(data) + self._tempnames[key] = f.name cmdline = [] - for argument in self.pattern: - cmdline.append(argument.format(**tempnames)) + for argument in self._pattern: + cmdline.append(argument.format(**self._tempnames)) process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = process.communicate() @@ -36,12 +34,17 @@ class RunTool: raise Exception("{} invocation failed: {}". format(cmdline[0], stderr.decode('utf-8'))) - tempfiles["__stdout__"] = stdout.decode('utf-8') - return tempfiles + self._tempfiles["__stdout__"] = io.StringIO(stdout.decode('utf-8')) + for key in self._tempdata: + if self._tempdata[key] is None: + self._tempfiles[key] = open(self._tempnames[key], "rb") + return self._tempfiles def __exit__(self, exc_typ, exc_value, exc_trace): - for f in self.files: - f.close() + for file in self._tempfiles.values(): + file.close() + for filename in self._tempnames.values(): + os.unlink(filename) def _dump(target, kind, suffix, content): if target is not None: @@ -166,7 +169,7 @@ class Target: with RunTool([self.triple + "-ld", "-shared", "--eh-frame-hdr"] + ["{{obj{}}}".format(index) for index in range(len(objects))] + ["-o", "{output}"], - output=b"", + output=None, **{"obj{}".format(index): obj for index, obj in enumerate(objects)}) \ as results: library = results["output"].read() @@ -181,7 +184,7 @@ class Target: def strip(self, library): with RunTool([self.triple + "-strip", "--strip-debug", "{library}", "-o", "{output}"], - library=library, output=b"") \ + library=library, output=None) \ as results: return results["output"].read() @@ -198,7 +201,7 @@ class Target: "--demangle", "--exe={library}"] + offset_addresses, library=library) \ as results: - lines = iter(results["__stdout__"].rstrip().split("\n")) + lines = iter(results["__stdout__"].read().rstrip().split("\n")) backtrace = [] while True: try: @@ -226,7 +229,7 @@ class Target: def demangle(self, names): with RunTool([self.triple + "-c++filt"] + names) as results: - return results["__stdout__"].rstrip().split("\n") + return results["__stdout__"].read().rstrip().split("\n") class NativeTarget(Target): def __init__(self): From c4bfc83b3831a90e9eeca3410a5e407ec2a783eb Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 15 Mar 2018 23:16:51 +0000 Subject: [PATCH 0509/2457] conda: mark the artiq-build output package as noarch, not toplevel. This also changes `noarch: python` to `noarch: generic` since this is semantically correct; the bitstream/firmware packages contain no Python code. Fixes #960. --- conda/artiq-board/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index 4ed3bc3a1..a25dac139 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -6,7 +6,6 @@ source: git_url: ../.. build: - noarch: python number: {{ environ["GIT_DESCRIBE_NUMBER"] }} string: {{ environ["GIT_DESCRIBE_NUMBER"] }}+git{{ environ["GIT_FULL_HASH"][:8] }} script_env: @@ -16,6 +15,7 @@ build: outputs: - name: artiq-{{ environ["ARTIQ_TARGET"] }}-{{ environ["ARTIQ_VARIANT"] }} + noarch: generic files: - lib From c1439bfd3b817ad4c6d4e2b6fde158a5701baecb Mon Sep 17 00:00:00 2001 From: ion Date: Sat, 17 Mar 2018 11:37:11 +0000 Subject: [PATCH 0510/2457] Fix AD5360 after migration to SPI2 --- artiq/coredevice/ad5360.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/ad5360.py b/artiq/coredevice/ad5360.py index 65e67aa07..4cfd43c18 100644 --- a/artiq/coredevice/ad5360.py +++ b/artiq/coredevice/ad5360.py @@ -181,7 +181,8 @@ class AD5360: # t10 max busy low for one channel t_10 = self.core.seconds_to_mu(1.5*us) # compensate all delays that will be applied - delay_mu(-len(values)*self.bus.xfer_period_mu-t_10) + delay_mu(-t_10-len(values)*( + self.bus.ref_period_mu+self.bus.xfer_duration_mu)) for i in range(len(values)): self.write_channel(i, values[i], op) delay_mu(t_10) From f39b7b33e8d0e5fb67dd768556341f868042d8e7 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 17 Mar 2018 18:51:17 +0100 Subject: [PATCH 0511/2457] ad5360: whitespace [nfc] --- artiq/coredevice/ad5360.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad5360.py b/artiq/coredevice/ad5360.py index 4cfd43c18..3cff52d6c 100644 --- a/artiq/coredevice/ad5360.py +++ b/artiq/coredevice/ad5360.py @@ -182,7 +182,7 @@ class AD5360: t_10 = self.core.seconds_to_mu(1.5*us) # compensate all delays that will be applied delay_mu(-t_10-len(values)*( - self.bus.ref_period_mu+self.bus.xfer_duration_mu)) + self.bus.ref_period_mu + self.bus.xfer_duration_mu)) for i in range(len(values)): self.write_channel(i, values[i], op) delay_mu(t_10) From c4fa44bc62bfe246f5a2270cf9840f547713d9b0 Mon Sep 17 00:00:00 2001 From: Thomas Harty Date: Sun, 18 Mar 2018 00:25:43 +0000 Subject: [PATCH 0512/2457] Add Zotino and Sampler functions to Kasli. Add Zotino to Kasli EEM 7 on OptiClock. --- artiq/gateware/targets/kasli.py | 98 +++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 824699780..34f0d2992 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -161,6 +161,44 @@ def _dio(eem): for i in range(8)] +def _sampler(eem): + return [ + ("{}_adc_spi_p".format(eem), 0, + Subsignal("clk", Pins("{}:{}_p".format(eem, _eem_signal(0)))), + Subsignal("miso", Pins("{}:{}_p".format(eem, _eem_signal(1)))), + IOStandard("LVDS_25"), + ), + ("{}_adc_spi_n".format(eem), 0, + Subsignal("clk", Pins("{}:{}_n".format(eem, _eem_signal(0)))), + Subsignal("miso", Pins("{}:{}_n".format(eem, _eem_signal(1)))), + IOStandard("LVDS_25"), + ), + ("{}_pgia_spi_p".format(eem), 0, + Subsignal("clk", Pins("{}:{}_p".format(eem, _eem_signal(4)))), + Subsignal("mosi", Pins("{}:{}_p".format(eem, _eem_signal(5)))), + Subsignal("miso", Pins("{}:{}_p".format(eem, _eem_signal(6)))), + Subsignal("cs_n", Pins("{}:{}_p".format(eem, _eem_signal(7)))), + IOStandard("LVDS_25"), + ), + ("{}_pgia_spi_n".format(eem), 0, + Subsignal("clk", Pins("{}:{}_n".format(eem, _eem_signal(4)))), + Subsignal("mosi", Pins("{}:{}_n".format(eem, _eem_signal(5)))), + Subsignal("miso", Pins("{}:{}_n".format(eem, _eem_signal(6)))), + Subsignal("cs_n", Pins("{}:{}_n".format(eem, _eem_signal(7)))), + IOStandard("LVDS_25"), + ), + ] + [ + ("{}_{}".format(eem, sig), 0, + Subsignal("p", Pins("{}:{}_p".format(j, _eem_signal(i)))), + Subsignal("n", Pins("{}:{}_n".format(j, _eem_signal(i)))), + IOStandard("LVDS_25") + ) for i, j, sig in [ + (2, eem, "cnv"), + (3, eem, "sdr") + ] + ] + + def _novogorny(eem): return [ ("{}_spi_p".format(eem), 0, @@ -182,14 +220,47 @@ def _novogorny(eem): IOStandard("LVDS_25"), ), ] + [ - ("{}_{}".format(eem, sig), 0, + ("{}_{}".format(eem, sig), 0, + Subsignal("p", Pins("{}:{}_p".format(j, _eem_signal(i)))), + Subsignal("n", Pins("{}:{}_n".format(j, _eem_signal(i)))), + IOStandard("LVDS_25") + ) for i, j, sig in [ + (5, eem, "conv"), + (6, eem, "busy"), + (7, eem, "scko"), + ] + ] + + +def _zotino(eem): + return [ + ("{}_spi_p".format(eem), 0, + Subsignal("clk", Pins("{}:{}_p".format(eem, _eem_signal(0)))), + Subsignal("mosi", Pins("{}:{}_p".format(eem, _eem_signal(1)))), + Subsignal("miso", Pins("{}:{}_p".format(eem, _eem_signal(2)))), + Subsignal("cs_n", Pins( + "{0}:{1[0]}_p {0}:{1[1]}_p".format( + eem, [_eem_signal(i + 3) for i in range(2)]))), + IOStandard("LVDS_25"), + ), + ("{}_spi_n".format(eem), 0, + Subsignal("clk", Pins("{}:{}_n".format(eem, _eem_signal(0)))), + Subsignal("mosi", Pins("{}:{}_n".format(eem, _eem_signal(1)))), + Subsignal("miso", Pins("{}:{}_n".format(eem, _eem_signal(2)))), + Subsignal("cs_n", Pins( + "{0}:{1[0]}_n {0}:{1[1]}_n".format( + eem, [_eem_signal(i + 3) for i in range(2)]))), + IOStandard("LVDS_25"), + ), + ] + [ + ("{}_{}".format(eem, sig), 0, Subsignal("p", Pins("{}:{}_p".format(j, _eem_signal(i)))), Subsignal("n", Pins("{}:{}_n".format(j, _eem_signal(i)))), IOStandard("LVDS_25") - ) for i, j, sig in [ - (5, eem, "conv"), - (6, eem, "busy"), - (7, eem, "scko"), + ) for i, j, sig in [ + (5, eem, "ldac_n"), + (6, eem, "busy"), + (7, eem, "clr_n"), ] ] @@ -254,7 +325,7 @@ class Opticlock(_StandaloneBase): platform.add_extension(_novogorny("eem3")) platform.add_extension(_urukul("eem5", "eem4")) platform.add_extension(_urukul("eem6")) - # platform.add_extension(_zotino("eem7")) + platform.add_extension(_zotino("eem7")) # EEM clock fan-out from Si5324, not MMCX try: @@ -274,6 +345,7 @@ class Opticlock(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) + # EEM3: Novogorny phy = spi2.SPIMaster(self.platform.request("eem3_spi_p"), self.platform.request("eem3_spi_n")) self.submodules += phy @@ -285,6 +357,7 @@ class Opticlock(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) + # EEM3 + EEM5: Urukul phy = spi2.SPIMaster(self.platform.request("eem5_spi_p"), self.platform.request("eem5_spi_n")) self.submodules += phy @@ -305,6 +378,7 @@ class Opticlock(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) + # EEM6: Urukul phy = spi2.SPIMaster(self.platform.request("eem6_spi_p"), self.platform.request("eem6_spi_n")) self.submodules += phy @@ -319,6 +393,18 @@ class Opticlock(_StandaloneBase): pads = platform.request("eem6_dds_reset") self.specials += DifferentialOutput(0, pads.p, pads.n) + # EEM7: Zotino + phy = spi2.SPIMaster(self.platform.request("eem7_spi_p"), + self.platform.request("eem7_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=16)) + + for signal in "ldac_n clr_n".split(): + pads = platform.request("eem7_{}".format(signal)) + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) From c86df8e13eb52aea817c14221d0223fdb08bf8d1 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 19 Mar 2018 06:23:12 +0000 Subject: [PATCH 0513/2457] firmware: try to unstuck the I2C bus if it gets stuck. Fixes #957. --- artiq/firmware/libboard_artiq/i2c.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/i2c.rs b/artiq/firmware/libboard_artiq/i2c.rs index 819c21c1b..e46b3d0fd 100644 --- a/artiq/firmware/libboard_artiq/i2c.rs +++ b/artiq/firmware/libboard_artiq/i2c.rs @@ -59,7 +59,19 @@ mod imp { half_period(); half_period(); if !sda_i(busno) { - error!("SDA is stuck low on bus #{}", busno) + warn!("SDA is stuck low on bus #{}, trying to unstuck", busno); + + // Try toggling SCL a few times + for bit in 0..8 { + scl_o(busno, false); + half_period(); + scl_o(busno, true); + half_period(); + } + } + + if !sda_i(busno) { + error!("SDA is stuck low on bus #{} and doesn't get unstuck", busno); } } } From 37d431039d7e6b0ef97e00ed3242c18897360a58 Mon Sep 17 00:00:00 2001 From: Thomas Harty Date: Mon, 19 Mar 2018 09:42:18 +0000 Subject: [PATCH 0514/2457] Fix typos. Reduce ififo depth to 4 for Zotino. --- artiq/gateware/targets/kasli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 34f0d2992..7ddf54245 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -229,7 +229,7 @@ def _novogorny(eem): (6, eem, "busy"), (7, eem, "scko"), ] - ] + ] def _zotino(eem): @@ -357,7 +357,7 @@ class Opticlock(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - # EEM3 + EEM5: Urukul + # EEM5 + EEM4: Urukul phy = spi2.SPIMaster(self.platform.request("eem5_spi_p"), self.platform.request("eem5_spi_n")) self.submodules += phy @@ -397,7 +397,7 @@ class Opticlock(_StandaloneBase): phy = spi2.SPIMaster(self.platform.request("eem7_spi_p"), self.platform.request("eem7_spi_n")) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=16)) + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) for signal in "ldac_n clr_n".split(): pads = platform.request("eem7_{}".format(signal)) From a27b5d88c2b482dd7c6c0d8eca88501d4e8d4b6d Mon Sep 17 00:00:00 2001 From: hartytp Date: Mon, 19 Mar 2018 10:58:14 +0000 Subject: [PATCH 0515/2457] Novogorny driver, remove unused imports (#964) * Novogorny driver, remove unused imports * more unused imports * oops, one final one! --- artiq/coredevice/novogorny.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/artiq/coredevice/novogorny.py b/artiq/coredevice/novogorny.py index 8892073af..ae8b59d21 100644 --- a/artiq/coredevice/novogorny.py +++ b/artiq/coredevice/novogorny.py @@ -1,11 +1,8 @@ -from numpy import int32, int64 from artiq.language.core import kernel, delay, portable -from artiq.language.units import us, ns -from artiq.coredevice.ad9912_reg import * +from artiq.language.units import ns from artiq.coredevice import spi2 as spi -from artiq.coredevice import urukul SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | From ed2e0c8b346b4cbb285e116fffc7e0b337a7e3ee Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Mar 2018 00:59:31 +0800 Subject: [PATCH 0516/2457] sayma/sdram/scan: test each tap 1024 times --- artiq/firmware/libboard/sdram.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index aa8b0330b..75c092e7e 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -251,7 +251,7 @@ mod ddr { let mut working = true; for p in 0..DFII_NPHASES { - for _ in 0..64 { + for _ in 0..1024 { for &offset in [n, n + DQS_SIGNAL_COUNT].iter() { let addr = DFII_PIX_RDDATA_ADDR[p].offset(offset as isize); let data = prs[DFII_PIX_DATA_SIZE * p + offset]; @@ -323,7 +323,7 @@ mod ddr { let incr_delay_until = |expected| { while delay.get() < DDRPHY_MAX_DELAY { let mut working = true; - for _ in 0..64 { + for _ in 0..1024 { sdram_phy::command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS| DFII_COMMAND_RDDATA); spin_cycles(15); From 845784c180f86a52963782b309b2fda624b6259a Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 19 Mar 2018 17:54:26 +0000 Subject: [PATCH 0517/2457] kusddrphy: use first and last tap that yield many valid reads --- artiq/firmware/libboard/sdram.rs | 48 +++++++++++--------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index 75c092e7e..e4d9d306d 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -1,7 +1,6 @@ #[cfg(has_ddrphy)] mod ddr { use core::{ptr, fmt}; - use core::cell::Cell; use csr::{dfii, ddrphy}; use sdram_phy::{self, spin_cycles}; use sdram_phy::{DFII_COMMAND_CS, DFII_COMMAND_WE, DFII_COMMAND_CAS, DFII_COMMAND_RAS, @@ -317,13 +316,14 @@ mod ddr { for n in 0..DQS_SIGNAL_COUNT { ddrphy::dly_sel_write(1 << (DQS_SIGNAL_COUNT - n - 1)); - ddrphy::rdly_dq_rst_write(1); - - let delay = Cell::new(0); - let incr_delay_until = |expected| { - while delay.get() < DDRPHY_MAX_DELAY { - let mut working = true; - for _ in 0..1024 { + let find_edge = |which| { + // Find the first (which=true) or last (which=false) tap that leads to a + // sufficiently high number of correct reads. + let mut last_valid = 0; + ddrphy::rdly_dq_rst_write(1); + for delay in 0..DDRPHY_MAX_DELAY { + let mut valid = true; + for _ in 0..256 { sdram_phy::command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS| DFII_COMMAND_RDDATA); spin_cycles(15); @@ -333,40 +333,26 @@ mod ddr { let addr = DFII_PIX_RDDATA_ADDR[p].offset(offset as isize); let data = prs[DFII_PIX_DATA_SIZE * p + offset]; if ptr::read_volatile(addr) as u8 != data { - working = false; + valid = false; } } } } - if working == expected { - break + if valid { + last_valid = delay; + if which { + break; + } } - - delay.set(delay.get() + 1); ddrphy::rdly_dq_inc_write(1); } + last_valid }; // Find smallest working delay - incr_delay_until(true); - let min_delay = delay.get(); - - // Get a bit further into the working zone - #[cfg(kusddrphy)] - for _ in 0..32 { - delay.set(delay.get() + 1); - ddrphy::rdly_dq_inc_write(1); - } - #[cfg(not(kusddrphy))] - { - delay.set(delay.get() + 1); - ddrphy::rdly_dq_inc_write(1); - } - - // Find largest working delay - incr_delay_until(false); - let max_delay = delay.get(); + let min_delay = find_edge(true); + let max_delay = find_edge(false); log!(logger, "{}:{:02}-{:02} ", DQS_SIGNAL_COUNT - n - 1, min_delay, max_delay); From 4b3f4081439d21134a1bf45fa768d229186b0c97 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 19 Mar 2018 18:41:56 +0000 Subject: [PATCH 0518/2457] sdram: simplify read level scan --- artiq/firmware/libboard/sdram.rs | 70 ++++++++++++++++---------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index e4d9d306d..9e7133095 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -95,7 +95,7 @@ mod ddr { #[cfg(kusddrphy)] { ddrphy_max_delay -= ddrphy::wdly_dqs_taps_read(); } - + let mut failed = false; for n in 0..DQS_SIGNAL_COUNT { let dq_addr = dfii::PI0_RDDATA_ADDR @@ -316,50 +316,50 @@ mod ddr { for n in 0..DQS_SIGNAL_COUNT { ddrphy::dly_sel_write(1 << (DQS_SIGNAL_COUNT - n - 1)); - let find_edge = |which| { - // Find the first (which=true) or last (which=false) tap that leads to a - // sufficiently high number of correct reads. - let mut last_valid = 0; - ddrphy::rdly_dq_rst_write(1); - for delay in 0..DDRPHY_MAX_DELAY { - let mut valid = true; - for _ in 0..256 { - sdram_phy::command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS| - DFII_COMMAND_RDDATA); - spin_cycles(15); + // Find the first (which=true) or last (which=false) tap that leads to a + // sufficiently high number of correct reads. + let mut min_delay = 0; + let mut have_min_delay = false; + let mut max_delay = 0; - for p in 0..DFII_NPHASES { - for &offset in [n, n + DQS_SIGNAL_COUNT].iter() { - let addr = DFII_PIX_RDDATA_ADDR[p].offset(offset as isize); - let data = prs[DFII_PIX_DATA_SIZE * p + offset]; - if ptr::read_volatile(addr) as u8 != data { - valid = false; - } + ddrphy::rdly_dq_rst_write(1); + + for delay in 0..DDRPHY_MAX_DELAY { + let mut valid = true; + for _ in 0..256 { + sdram_phy::command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS| + DFII_COMMAND_RDDATA); + spin_cycles(15); + + for p in 0..DFII_NPHASES { + for &offset in [n, n + DQS_SIGNAL_COUNT].iter() { + let addr = DFII_PIX_RDDATA_ADDR[p].offset(offset as isize); + let data = prs[DFII_PIX_DATA_SIZE * p + offset]; + if ptr::read_volatile(addr) as u8 != data { + valid = false; } } } - - if valid { - last_valid = delay; - if which { - break; - } - } - ddrphy::rdly_dq_inc_write(1); } - last_valid - }; - // Find smallest working delay - let min_delay = find_edge(true); - let max_delay = find_edge(false); + if valid { + if !have_min_delay { + min_delay = delay; + have_min_delay = true; + } + max_delay = delay; + } + ddrphy::rdly_dq_inc_write(1); + } - log!(logger, "{}:{:02}-{:02} ", DQS_SIGNAL_COUNT - n - 1, - min_delay, max_delay); + let mean_delay = (min_delay + max_delay) / 2; + log!(logger, "{}: {} ({} wide), ", + DQS_SIGNAL_COUNT - n - 1, mean_delay, + max_delay - min_delay); // Set delay to the middle ddrphy::rdly_dq_rst_write(1); - for _ in 0..(min_delay + max_delay) / 2 { + for _ in 0..mean_delay { ddrphy::rdly_dq_inc_write(1); } } From 65379b1f7a4913ee2202a5dbb6d6ce52853aa9c2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 19 Mar 2018 19:57:00 +0100 Subject: [PATCH 0519/2457] conda: bump migen, misoc * xilinx ODDR2 SRTYPE * flterm leak * I/ODELAY VTC/reset sequencing * sayma SDRAM clock buffer LOC --- conda/artiq-dev/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index c1143ee16..08aed670c 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,8 +14,8 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_20+git1f82faa - - misoc 0.10 py35_0+gitd167deff + - migen 0.7 py35_21+git881741b + - misoc 0.10 py35_9+git103bb3a8 - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27 From 276b0c7f06d32655f6a5debd8573273cf2a580bf Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Mar 2018 07:27:51 +0800 Subject: [PATCH 0520/2457] sdram: reject read delay wrap arounds --- artiq/firmware/libboard/sdram.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index 9e7133095..15f17af8e 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -321,6 +321,8 @@ mod ddr { let mut min_delay = 0; let mut have_min_delay = false; let mut max_delay = 0; + let mut have_max_delay = false; + let mut have_invalid = 0; ddrphy::rdly_dq_rst_write(1); @@ -328,7 +330,7 @@ mod ddr { let mut valid = true; for _ in 0..256 { sdram_phy::command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS| - DFII_COMMAND_RDDATA); + DFII_COMMAND_RDDATA); spin_cycles(15); for p in 0..DFII_NPHASES { @@ -347,7 +349,14 @@ mod ddr { min_delay = delay; have_min_delay = true; } - max_delay = delay; + if !have_max_delay { + max_delay = delay; + } + } else if have_min_delay { + have_invalid += 1; + if have_invalid >= 10 { + have_max_delay = true; + } } ddrphy::rdly_dq_inc_write(1); } From fad066f1aace6621905875debe6794ac9357320f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 20 Mar 2018 15:49:59 +0800 Subject: [PATCH 0521/2457] ttl_serdes_7series: cleanup indentation Inconsistent with other code and confuses text editors. --- artiq/gateware/rtio/phy/ttl_serdes_7series.py | 89 ++++++++++--------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_7series.py b/artiq/gateware/rtio/phy/ttl_serdes_7series.py index 6049d38f8..730aea35b 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_7series.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_7series.py @@ -14,28 +14,29 @@ class _OSERDESE2_8X(Module): o = self.o pad_o = Signal() self.specials += Instance("OSERDESE2", - p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", - p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - o_OQ=pad_o, o_TQ=self.t_out, - i_RST=ResetSignal("rio_phy"), - i_CLK=ClockSignal("rtiox4"), - i_CLKDIV=ClockSignal("rio_phy"), - i_D1=o[0], i_D2=o[1], i_D3=o[2], i_D4=o[3], - i_D5=o[4], i_D6=o[5], i_D7=o[6], i_D8=o[7], - i_TCE=1, i_OCE=1, - i_T1=self.t_in) + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + o_OQ=pad_o, o_TQ=self.t_out, + i_RST=ResetSignal("rio_phy"), + i_CLK=ClockSignal("rtiox4"), + i_CLKDIV=ClockSignal("rio_phy"), + i_D1=o[0], i_D2=o[1], i_D3=o[2], i_D4=o[3], + i_D5=o[4], i_D6=o[5], i_D7=o[6], i_D8=o[7], + i_TCE=1, i_OCE=1, + i_T1=self.t_in) if pad_n is None: self.comb += pad.eq(pad_o) else: self.specials += Instance("IOBUFDS_INTERMDISABLE", - p_DIFF_TERM="FALSE", - p_IBUF_LOW_PWR="TRUE", - p_USE_IBUFDISABLE="TRUE", - i_IBUFDISABLE=1, - i_INTERMDISABLE=1, - i_I=pad_o, - i_T=self.t_out, - io_IO=pad, io_IOB=pad_n) + p_DIFF_TERM="FALSE", + p_IBUF_LOW_PWR="TRUE", + p_USE_IBUFDISABLE="TRUE", + i_IBUFDISABLE=1, + i_INTERMDISABLE=1, + i_I=pad_o, + i_T=self.t_out, + io_IO=pad, io_IOB=pad_n) + class _ISERDESE2_8X(Module): def __init__(self, pad, pad_n=None): @@ -48,27 +49,27 @@ class _ISERDESE2_8X(Module): pad_i = Signal() i = self.i self.specials += Instance("ISERDESE2", p_DATA_RATE="DDR", - p_DATA_WIDTH=8, - p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1, - o_Q1=i[7], o_Q2=i[6], o_Q3=i[5], o_Q4=i[4], - o_Q5=i[3], o_Q6=i[2], o_Q7=i[1], o_Q8=i[0], - i_D=pad_i, - i_CLK=ClockSignal("rtiox4"), - i_CLKB=~ClockSignal("rtiox4"), - i_CE1=1, - i_RST=ResetSignal("rio_phy"), - i_CLKDIV=ClockSignal("rio_phy")) + p_DATA_WIDTH=8, + p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1, + o_Q1=i[7], o_Q2=i[6], o_Q3=i[5], o_Q4=i[4], + o_Q5=i[3], o_Q6=i[2], o_Q7=i[1], o_Q8=i[0], + i_D=pad_i, + i_CLK=ClockSignal("rtiox4"), + i_CLKB=~ClockSignal("rtiox4"), + i_CE1=1, + i_RST=ResetSignal("rio_phy"), + i_CLKDIV=ClockSignal("rio_phy")) if pad_n is None: self.comb += pad_i.eq(pad) else: self.specials += Instance("IBUFDS_INTERMDISABLE", - p_DIFF_TERM="TRUE", - p_IBUF_LOW_PWR="TRUE", - p_USE_IBUFDISABLE="TRUE", - i_IBUFDISABLE=0, - i_INTERMDISABLE=0, - o_O=pad_i, - io_I=pad, io_IB=pad_n) + p_DIFF_TERM="TRUE", + p_IBUF_LOW_PWR="TRUE", + p_USE_IBUFDISABLE="TRUE", + i_IBUFDISABLE=0, + i_INTERMDISABLE=0, + o_O=pad_i, + io_I=pad, io_IB=pad_n) class _IOSERDESE2_8X(Module): @@ -86,17 +87,17 @@ class _IOSERDESE2_8X(Module): self.submodules += iserdes, oserdes if pad_n is None: self.specials += Instance("IOBUF", - i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, - io_IO=pad) + i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, + io_IO=pad) else: self.specials += Instance("IOBUFDS_INTERMDISABLE", - p_DIFF_TERM="TRUE", - p_IBUF_LOW_PWR="TRUE", - p_USE_IBUFDISABLE="TRUE", - i_IBUFDISABLE=~oserdes.t_out, - i_INTERMDISABLE=~oserdes.t_out, - i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, - io_IO=pad, io_IOB=pad_n) + p_DIFF_TERM="TRUE", + p_IBUF_LOW_PWR="TRUE", + p_USE_IBUFDISABLE="TRUE", + i_IBUFDISABLE=~oserdes.t_out, + i_INTERMDISABLE=~oserdes.t_out, + i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, + io_IO=pad, io_IOB=pad_n) self.comb += [ self.i.eq(iserdes.i), oserdes.t_in.eq(~self.oe), From a5825184b73ce935af5a7e39051024360d3f79b8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 20 Mar 2018 16:07:23 +0800 Subject: [PATCH 0522/2457] add ttl_serdes_ultrascale (untested) --- .../rtio/phy/ttl_serdes_ultrascale.py | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py diff --git a/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py b/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py new file mode 100644 index 000000000..33afb9afd --- /dev/null +++ b/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py @@ -0,0 +1,117 @@ +from migen import * + +from artiq.gateware.rtio.phy import ttl_serdes_generic + + +# SERDES clocks are in dedicated domains to make the implementation +# of the convoluted clocking schemes from AR#67885 less tedious. + + +class _OSERDESE2_8X(Module): + def __init__(self, pad, pad_n=None): + self.o = Signal(8) + self.t_in = Signal() + self.t_out = Signal() + + # # # + + pad_o = Signal() + self.specials += Instance("OSERDESE3", + p_DATA_WIDTH=8, p_INIT=0, + p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, + + o_OQ=pad_o, o_T_OUT=self.t_out, + i_RST=ResetSignal("rtio_serdes"), + i_CLK=ClockSignal("rtiox4_serdes"), i_CLKDIV=ClockSignal("rtio_serdes"), + i_D=self.o, i_T=self.t_in) + if pad_n is None: + self.comb += pad.eq(pad_o) + else: + self.specials += Instance("IOBUFDS_INTERMDISABLE", + i_IBUFDISABLE=1, + i_INTERMDISABLE=1, + i_I=pad_o, + i_T=self.t_out, + io_IO=pad, io_IOB=pad_n) + + +class _ISERDESE2_8X(Module): + def __init__(self, pad, pad_n=None): + self.o = Signal(8) + self.i = Signal(8) + self.oe = Signal() + + # # # + + pad_i = Signal() + self.specials += Instance("ISERDESE3", + p_IS_CLK_INVERTED=0, + p_IS_CLK_B_INVERTED=1, + p_DATA_WIDTH=8, + + i_D=pad_i, + i_RST=ResetSignal("rtio_serdes"), + i_FIFO_RD_EN=0, + i_CLK=ClockSignal("rtiox4_serdes"), + i_CLK_B=ClockSignal("rtiox4_serdes"), # locally inverted + i_CLKDIV=ClockSignal("rtio_serdes"), + o_Q=Cat(*self.i[::-1])) + if pad_n is None: + self.comb += pad_i.eq(pad) + else: + self.specials += Instance("IBUFDS_INTERMDISABLE", + i_IBUFDISABLE=0, + i_INTERMDISABLE=0, + o_O=pad_i, + io_I=pad, io_IB=pad_n) + + +class _IOSERDESE2_8X(Module): + def __init__(self, pad, pad_n=None): + self.o = Signal(8) + self.i = Signal(8) + self.oe = Signal() + + # # # + + pad_i = Signal() + pad_o = Signal() + iserdes = _ISERDESE2_8X(pad_i) + oserdes = _OSERDESE2_8X(pad_o) + self.submodules += iserdes, oserdes + if pad_n is None: + self.specials += Instance("IOBUF", + i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, + io_IO=pad) + else: + self.specials += Instance("IOBUFDS_INTERMDISABLE", + i_IBUFDISABLE=~oserdes.t_out, + i_INTERMDISABLE=~oserdes.t_out, + i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, + io_IO=pad, io_IOB=pad_n) + self.comb += [ + self.i.eq(iserdes.i), + oserdes.t_in.eq(~self.oe), + oserdes.o.eq(self.o) + ] + + +class Output_8X(ttl_serdes_generic.Output): + def __init__(self, pad, pad_n=None): + serdes = _OSERDESE2_8X(pad, pad_n) + self.submodules += serdes + ttl_serdes_generic.Output.__init__(self, serdes) + + +class InOut_8X(ttl_serdes_generic.InOut): + def __init__(self, pad, pad_n=None): + serdes = _IOSERDESE2_8X(pad, pad_n) + self.submodules += serdes + ttl_serdes_generic.InOut.__init__(self, serdes) + + +class Input_8X(ttl_serdes_generic.InOut): + def __init__(self, pad, pad_n=None): + serdes = _ISERDESE2_8X(pad, pad_n) + self.submodules += serdes + ttl_serdes_generic.InOut.__init__(self, serdes) From c8020f6bbd24267087863124a496b3f9c550d9f1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 20 Mar 2018 16:46:57 +0800 Subject: [PATCH 0523/2457] ttl_serdes_generic: fix/upgrade test --- artiq/gateware/rtio/phy/ttl_serdes_generic.py | 163 ------------------ artiq/gateware/test/rtio/test_ttl_serdes.py | 125 ++++++++++++++ 2 files changed, 125 insertions(+), 163 deletions(-) create mode 100644 artiq/gateware/test/rtio/test_ttl_serdes.py diff --git a/artiq/gateware/rtio/phy/ttl_serdes_generic.py b/artiq/gateware/rtio/phy/ttl_serdes_generic.py index 0d88c4284..1fc79673d 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_generic.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_generic.py @@ -115,166 +115,3 @@ class InOut(Module): self.submodules += pe self.comb += pe.i.eq(serdes.i ^ Replicate(i_d, serdes_width)) self.sync.rio_phy += self.rtlink.i.fine_ts.eq(pe.o) - - -class _FakeSerdes(Module): - def __init__(self): - self.o = Signal(8) - self.i = Signal(8) - self.oe = Signal() - - -class _OutputTB(Module): - def __init__(self): - serdes = _FakeSerdes() - self.submodules.dut = RenameClockDomains(Output(serdes), - {"rio_phy": "sys"}) - - def gen_simulation(self, selfp): - selfp.dut.rtlink.o.data = 1 - selfp.dut.rtlink.o.fine_ts = 1 - selfp.dut.rtlink.o.stb = 1 - yield - selfp.dut.rtlink.o.stb = 0 - yield - selfp.dut.rtlink.o.data = 0 - selfp.dut.rtlink.o.fine_ts = 2 - selfp.dut.rtlink.o.stb = 1 - yield - yield - selfp.dut.rtlink.o.data = 1 - selfp.dut.rtlink.o.fine_ts = 7 - selfp.dut.rtlink.o.stb = 1 - for _ in range(6): - # note that stb stays active; output should not change - yield - - -class _InOutTB(Module): - def __init__(self): - self.serdes = _FakeSerdes() - self.submodules.dut = RenameClockDomains(InOut(self.serdes), - {"rio_phy": "sys", - "rio": "sys"}) - - def check_input(self, selfp, stb, fine_ts=None): - if stb != selfp.dut.rtlink.i.stb: - print("KO rtlink.i.stb should be {} but is {}" - .format(stb, selfp.dut.rtlink.i.stb)) - elif fine_ts is not None and fine_ts != selfp.dut.rtlink.i.fine_ts: - print("KO rtlink.i.fine_ts should be {} but is {}" - .format(fine_ts, selfp.dut.rtlink.i.fine_ts)) - else: - print("OK") - - def check_output(self, selfp, data): - if selfp.serdes.o != data: - print("KO io.o should be {} but is {}".format(data, selfp.serdes.o)) - else: - print("OK") - - def check_output_enable(self, selfp, oe): - if selfp.serdes.oe != oe: - print("KO io.oe should be {} but is {}".format(oe, selfp.serdes.oe)) - else: - print("OK") - - def gen_simulation(self, selfp): - selfp.dut.rtlink.o.address = 2 - selfp.dut.rtlink.o.data = 0b11 - selfp.dut.rtlink.o.stb = 1 # set sensitivity to rising + falling - yield - selfp.dut.rtlink.o.stb = 0 - - self.check_output_enable(selfp, 0) - yield - - selfp.serdes.i = 0b11111110 # rising edge at fine_ts = 1 - yield - selfp.serdes.i = 0b11111111 - yield - self.check_input(selfp, stb=1, fine_ts=1) - - selfp.serdes.i = 0b01111111 # falling edge at fine_ts = 7 - yield - selfp.serdes.i = 0b00000000 - yield - self.check_input(selfp, stb=1, fine_ts=7) - - selfp.serdes.i = 0b11000000 # rising edge at fine_ts = 6 - yield - selfp.serdes.i = 0b11111111 - yield - self.check_input(selfp, stb=1, fine_ts=6) - - selfp.dut.rtlink.o.address = 2 - selfp.dut.rtlink.o.data = 0b11 - selfp.dut.rtlink.o.stb = 1 # set sensitivity to rising only - yield - selfp.dut.rtlink.o.stb = 0 - yield - - selfp.serdes.i = 0b00001111 # falling edge at fine_ts = 4 - yield - self.check_input(selfp, stb=0) # no strobe, sensitivity is rising edge - - selfp.serdes.i = 0b11110000 # rising edge at fine_ts = 4 - yield - self.check_input(selfp, stb=1, fine_ts=4) - - selfp.dut.rtlink.o.address = 1 - selfp.dut.rtlink.o.data = 1 - selfp.dut.rtlink.o.stb = 1 # set Output Enable to 1 - yield - selfp.dut.rtlink.o.stb = 0 - yield - yield - self.check_output_enable(selfp, 1) - - selfp.dut.rtlink.o.address = 0 - selfp.dut.rtlink.o.data = 1 - selfp.dut.rtlink.o.fine_ts = 3 - selfp.dut.rtlink.o.stb = 1 # rising edge at fine_ts = 3 - yield - selfp.dut.rtlink.o.stb = 0 - yield - self.check_output(selfp, data=0b11111000) - - yield - self.check_output(selfp, data=0xFF) # stays at 1 - - selfp.dut.rtlink.o.data = 0 - selfp.dut.rtlink.o.fine_ts = 0 - selfp.dut.rtlink.o.stb = 1 # falling edge at fine_ts = 0 - yield - selfp.dut.rtlink.o.stb = 0 - yield - self.check_output(selfp, data=0) - - yield - self.check_output(selfp, data=0) - - selfp.dut.rtlink.o.data = 1 - selfp.dut.rtlink.o.fine_ts = 7 - selfp.dut.rtlink.o.stb = 1 # rising edge at fine_ts = 7 - yield - selfp.dut.rtlink.o.stb = 0 - yield - self.check_output(selfp, data=0b10000000) - - -if __name__ == "__main__": - import sys - from migen.sim.generic import Simulator, TopLevel - - if len(sys.argv) != 2: - print("Incorrect command line") - sys.exit(1) - - cls = { - "output": _OutputTB, - "inout": _InOutTB - }[sys.argv[1]] - - with Simulator(cls(), TopLevel("top.vcd", clk_period=int(1/0.125))) as s: - s.run() diff --git a/artiq/gateware/test/rtio/test_ttl_serdes.py b/artiq/gateware/test/rtio/test_ttl_serdes.py new file mode 100644 index 000000000..7b4976cac --- /dev/null +++ b/artiq/gateware/test/rtio/test_ttl_serdes.py @@ -0,0 +1,125 @@ +import unittest + +from migen import * + +from artiq.gateware.rtio.phy.ttl_serdes_generic import * + + +class _FakeSerdes: + def __init__(self): + self.o = Signal(8) + self.i = Signal(8) + self.oe = Signal() + + +class _TB(Module): + def __init__(self): + self.serdes = _FakeSerdes() + self.submodules.dut = ClockDomainsRenamer({"rio_phy": "sys", "rio": "sys"})( + InOut(self.serdes)) + + +class TestTTLSerdes(unittest.TestCase): + def test_input(self): + tb = _TB() + + def gen(): + yield tb.dut.rtlink.o.address.eq(2) + yield tb.dut.rtlink.o.data.eq(0b11) + yield tb.dut.rtlink.o.stb.eq(1) # set sensitivity to rising + falling + yield + yield tb.dut.rtlink.o.stb.eq(0) + yield + + self.assertEqual((yield tb.serdes.oe), 0) + self.assertEqual((yield tb.dut.rtlink.i.stb), 0) + + yield tb.serdes.i.eq(0b11111110) # rising edge at fine_ts = 1 + yield + yield tb.serdes.i.eq(0b11111111) + yield + self.assertEqual((yield tb.dut.rtlink.i.stb), 1) + self.assertEqual((yield tb.dut.rtlink.i.fine_ts), 1) + + yield tb.serdes.i.eq(0b01111111) # falling edge at fine_ts = 7 + yield + yield tb.serdes.i.eq(0b00000000) + yield + self.assertEqual((yield tb.dut.rtlink.i.stb), 1) + self.assertEqual((yield tb.dut.rtlink.i.fine_ts), 7) + + yield tb.serdes.i.eq(0b11000000) # rising edge at fine_ts = 6 + yield + yield tb.serdes.i.eq(0b11111111) + yield + self.assertEqual((yield tb.dut.rtlink.i.stb), 1) + self.assertEqual((yield tb.dut.rtlink.i.fine_ts), 6) + + yield tb.dut.rtlink.o.address.eq(2) + yield tb.dut.rtlink.o.data.eq(0b01) + yield tb.dut.rtlink.o.stb.eq(1) # set sensitivity to rising only + yield + yield tb.dut.rtlink.o.stb.eq(0) + yield + + yield tb.serdes.i.eq(0b00001111) # falling edge at fine_ts = 4 + yield + yield tb.serdes.i.eq(0b00000000) + yield + # no strobe, sensitivity is rising edge + self.assertEqual((yield tb.dut.rtlink.i.stb), 0) + + yield tb.serdes.i.eq(0b11110000) # rising edge at fine_ts = 4 + yield + yield tb.serdes.i.eq(0b11111111) + yield + self.assertEqual((yield tb.dut.rtlink.i.stb), 1) + self.assertEqual((yield tb.dut.rtlink.i.fine_ts), 4) + + run_simulation(tb, gen()) + + def test_output(self): + tb = _TB() + + def gen(): + yield tb.dut.rtlink.o.address.eq(1) + yield tb.dut.rtlink.o.data.eq(1) + yield tb.dut.rtlink.o.stb.eq(1) # set Output Enable to 1 + yield + yield tb.dut.rtlink.o.stb.eq(0) + yield + yield + self.assertEqual((yield tb.serdes.oe), 1) + + yield tb.dut.rtlink.o.address.eq(0) + yield tb.dut.rtlink.o.data.eq(1) + yield tb.dut.rtlink.o.fine_ts.eq(3) + yield tb.dut.rtlink.o.stb.eq(1) # rising edge at fine_ts = 3 + yield + yield tb.dut.rtlink.o.stb.eq(0) + yield + self.assertEqual((yield tb.serdes.o), 0b11111000) + + yield + self.assertEqual((yield tb.serdes.o), 0b11111111) # stays at 1 + + yield tb.dut.rtlink.o.data.eq(0) + yield tb.dut.rtlink.o.fine_ts.eq(0) + yield tb.dut.rtlink.o.stb.eq(1) # falling edge at fine_ts = 0 + yield + yield tb.dut.rtlink.o.stb.eq(0) + yield + self.assertEqual((yield tb.serdes.o), 0b00000000) + + yield + self.assertEqual((yield tb.serdes.o), 0b00000000) + + yield tb.dut.rtlink.o.data.eq(1) + yield tb.dut.rtlink.o.fine_ts.eq(7) + yield tb.dut.rtlink.o.stb.eq(1) # rising edge at fine_ts = 7 + yield + yield tb.dut.rtlink.o.stb.eq(0) + yield + self.assertEqual((yield tb.serdes.o), 0b10000000) + + run_simulation(tb, gen()) From 3abb378fbe10d9876246752f61a4e7e9367af952 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Mar 2018 09:23:38 +0000 Subject: [PATCH 0524/2457] i2c: unused variable --- artiq/firmware/libboard_artiq/i2c.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/i2c.rs b/artiq/firmware/libboard_artiq/i2c.rs index e46b3d0fd..ddb70a129 100644 --- a/artiq/firmware/libboard_artiq/i2c.rs +++ b/artiq/firmware/libboard_artiq/i2c.rs @@ -62,7 +62,7 @@ mod imp { warn!("SDA is stuck low on bus #{}, trying to unstuck", busno); // Try toggling SCL a few times - for bit in 0..8 { + for _bit in 0..8 { scl_o(busno, false); half_period(); scl_o(busno, true); From 6fb0cbfcd3dde90fdf525751e730dd43f756160e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Mar 2018 09:48:16 +0000 Subject: [PATCH 0525/2457] sdram: clean up, make read_level robust to wrap around * fix a few rust warnings * also do eye scans on kintex --- artiq/firmware/libboard/sdram.rs | 72 ++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index 15f17af8e..d49addd72 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -30,18 +30,19 @@ mod ddr { ddrphy::wlevel_en_write(enabled as u8); } - #[cfg(kusddrphy)] + #[cfg(ddrphy_wlevel)] unsafe fn write_level_scan(logger: &mut Option<&mut fmt::Write>) { + #[cfg(kusddrphy)] log!(logger, "DQS initial delay: {} taps\n", ddrphy::wdly_dqs_taps_read()); log!(logger, "Write leveling scan:\n"); enable_write_leveling(true); spin_cycles(100); - let mut ddrphy_max_delay : u16 = DDRPHY_MAX_DELAY; - #[cfg(kusddrphy)] { - ddrphy_max_delay -= ddrphy::wdly_dqs_taps_read(); - } + #[cfg(not(kusddrphy))] + let ddrphy_max_delay : u16 = DDRPHY_MAX_DELAY; + #[cfg(kusddrphy)] + let ddrphy_max_delay : u16 = DDRPHY_MAX_DELAY - ddrphy::wdly_dqs_taps_read(); for n in 0..DQS_SIGNAL_COUNT { let dq_addr = dfii::PI0_RDDATA_ADDR @@ -91,10 +92,10 @@ mod ddr { enable_write_leveling(true); spin_cycles(100); - let mut ddrphy_max_delay : u16 = DDRPHY_MAX_DELAY; - #[cfg(kusddrphy)] { - ddrphy_max_delay -= ddrphy::wdly_dqs_taps_read(); - } + #[cfg(not(kusddrphy))] + let ddrphy_max_delay : u16 = DDRPHY_MAX_DELAY; + #[cfg(kusddrphy)] + let ddrphy_max_delay : u16 = DDRPHY_MAX_DELAY - ddrphy::wdly_dqs_taps_read(); let mut failed = false; for n in 0..DQS_SIGNAL_COUNT { @@ -202,7 +203,6 @@ mod ddr { } } - #[cfg(kusddrphy)] unsafe fn read_level_scan(logger: &mut Option<&mut fmt::Write>) { log!(logger, "Read leveling scan:\n"); @@ -280,7 +280,7 @@ mod ddr { spin_cycles(15); } - unsafe fn read_level(logger: &mut Option<&mut fmt::Write>) { + unsafe fn read_level(logger: &mut Option<&mut fmt::Write>) -> bool { log!(logger, "Read leveling: "); // Generate pseudo-random sequence @@ -316,13 +316,15 @@ mod ddr { for n in 0..DQS_SIGNAL_COUNT { ddrphy::dly_sel_write(1 << (DQS_SIGNAL_COUNT - n - 1)); - // Find the first (which=true) or last (which=false) tap that leads to a - // sufficiently high number of correct reads. + // Find the first (min_delay) and last (max_delay) tap that bracket + // the largest tap interval of correct reads. let mut min_delay = 0; - let mut have_min_delay = false; let mut max_delay = 0; - let mut have_max_delay = false; - let mut have_invalid = 0; + + let mut first_valid = 0; + let mut seen_valid = 0; + let mut seen_invalid = 0; + let mut max_seen_valid = 0; ddrphy::rdly_dq_rst_write(1); @@ -345,22 +347,37 @@ mod ddr { } if valid { - if !have_min_delay { - min_delay = delay; - have_min_delay = true; + if seen_valid == 0 { + first_valid = delay; } - if !have_max_delay { + seen_valid += 1; + seen_invalid = 0; + if seen_valid > max_seen_valid { + min_delay = first_valid; max_delay = delay; + max_seen_valid = seen_valid; } - } else if have_min_delay { - have_invalid += 1; - if have_invalid >= 10 { - have_max_delay = true; + } else { + seen_invalid += 1; + if seen_invalid >= DDRPHY_MAX_DELAY / 8 { + seen_valid = 0; } } ddrphy::rdly_dq_inc_write(1); } + if max_delay <= min_delay { + log!(logger, "Zero window: {}: {}-{}\n", + DQS_SIGNAL_COUNT - n - 1, min_delay, max_delay); + return false + } + if max_seen_valid <= 5 { + log!(logger, "Small window: {}: {}-{} ({})\n", + DQS_SIGNAL_COUNT - n - 1, min_delay, max_delay, + max_seen_valid); + return false + } + let mean_delay = (min_delay + max_delay) / 2; log!(logger, "{}: {} ({} wide), ", DQS_SIGNAL_COUNT - n - 1, mean_delay, @@ -380,6 +397,7 @@ mod ddr { spin_cycles(15); log!(logger, "done\n"); + true } pub unsafe fn level(logger: &mut Option<&mut fmt::Write>) -> bool { @@ -387,7 +405,6 @@ mod ddr { { let mut delay = [0; DQS_SIGNAL_COUNT]; let mut high_skew = [false; DQS_SIGNAL_COUNT]; - #[cfg(kusddrphy)] write_level_scan(logger); if !write_level(logger, &mut delay, &mut high_skew) { return false @@ -395,9 +412,10 @@ mod ddr { read_bitslip(logger, &delay, &high_skew); } - #[cfg(kusddrphy)] read_level_scan(logger); - read_level(logger); + if !read_level(logger) { + return false + } true } From 495625b99d45bfa7fdc300b01bcf748fd79c3e14 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Mar 2018 09:56:02 +0000 Subject: [PATCH 0526/2457] bootloader: repeat memory test 4 times --- artiq/firmware/bootloader/main.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 7173ef86d..8f65e3a66 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -64,18 +64,19 @@ fn memory_test(total: &mut usize, wrong: &mut usize) -> bool { fn prng32(seed: &mut u32) -> u32 { *seed = 1664525 * *seed + 1013904223; *seed } fn prng16(seed: &mut u16) -> u16 { *seed = 25173 * *seed + 13849; *seed } - // Test data bus - test!((); for i in (0..0x100) { MEMORY[i] = 0xAAAAAAAA }); - test!((); for i in (0..0x100) { MEMORY[i] = 0x55555555 }); + for _ in 0..4 { + // Test data bus + test!((); for i in (0..0x100) { MEMORY[i] = 0xAAAAAAAA }); + test!((); for i in (0..0x100) { MEMORY[i] = 0x55555555 }); - // Test counter addressing with random data - test!(let mut seed = 0; - for i in (0..0x100000) { MEMORY[i] = prng32(&mut seed) }); - - // Test random addressing with counter data - test!(let mut seed = 0; - for i in (0..0x10000) { MEMORY[prng16(&mut seed)] = i }); + // Test counter addressing with random data + test!(let mut seed = 0; + for i in (0..0x100000) { MEMORY[i] = prng32(&mut seed) }); + // Test random addressing with counter data + test!(let mut seed = 0; + for i in (0..0x10000) { MEMORY[prng16(&mut seed)] = i }); + } *wrong == 0 } From 206664afd9c746ee97ec868617e3eb82ed887e63 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Mar 2018 10:16:05 +0000 Subject: [PATCH 0527/2457] sdram: compact read_level output --- artiq/firmware/libboard/sdram.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index d49addd72..dcc55e55d 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -379,9 +379,9 @@ mod ddr { } let mean_delay = (min_delay + max_delay) / 2; - log!(logger, "{}: {} ({} wide), ", + log!(logger, "{}: {}+-{}, ", DQS_SIGNAL_COUNT - n - 1, mean_delay, - max_delay - min_delay); + max_seen_valid / 2); // Set delay to the middle ddrphy::rdly_dq_rst_write(1); From f4719ae24bf90de81cb93f45082f8800452e8ec9 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Mar 2018 15:42:49 +0100 Subject: [PATCH 0528/2457] sdram: clean up console output --- artiq/firmware/libboard/sdram.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard/sdram.rs index dcc55e55d..a4de6fcb8 100644 --- a/artiq/firmware/libboard/sdram.rs +++ b/artiq/firmware/libboard/sdram.rs @@ -367,8 +367,9 @@ mod ddr { } if max_delay <= min_delay { - log!(logger, "Zero window: {}: {}-{}\n", - DQS_SIGNAL_COUNT - n - 1, min_delay, max_delay); + log!(logger, "Zero window: {}: {}-{} ({})\n", + DQS_SIGNAL_COUNT - n - 1, min_delay, max_delay, + max_seen_valid); return false } if max_seen_valid <= 5 { @@ -379,9 +380,7 @@ mod ddr { } let mean_delay = (min_delay + max_delay) / 2; - log!(logger, "{}: {}+-{}, ", - DQS_SIGNAL_COUNT - n - 1, mean_delay, - max_seen_valid / 2); + log!(logger, "{}+-{} ", mean_delay, max_seen_valid / 2); // Set delay to the middle ddrphy::rdly_dq_rst_write(1); From a185e8dc524d92e92731f602def0d8d78826a57b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Mar 2018 16:10:11 +0000 Subject: [PATCH 0529/2457] urukul: fix MASK_NU offset --- artiq/coredevice/urukul.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 2cc0b80ba..d8dc058db 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -24,7 +24,7 @@ CFG_RF_SW = 0 CFG_LED = 4 CFG_PROFILE = 8 CFG_IO_UPDATE = 12 -CFG_MASK_NU = 16 +CFG_MASK_NU = 13 CFG_CLK_SEL = 17 CFG_SYNC_SEL = 18 CFG_RST = 19 From f17c0abfe431158eed1671f5d4cdcb430638367f Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Mar 2018 16:10:26 +0000 Subject: [PATCH 0530/2457] urukul: don't pulse DDS_RST on init closes m-labs/artiq#940 Apparently, if the DDS are reset, every other time they don't work properly. --- artiq/coredevice/urukul.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index d8dc058db..c9c3edf4e 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -169,7 +169,7 @@ class CPLD: Resets the DDS and verifies correct CPLD gateware version. """ cfg = self.cfg_reg - self.cfg_reg = cfg | (1 << CFG_RST) | (1 << CFG_IO_RST) + self.cfg_reg = cfg | (0 << CFG_RST) | (1 << CFG_IO_RST) proto_rev = urukul_sta_proto_rev(self.sta_read()) if proto_rev != STA_PROTO_REV_MATCH: raise ValueError("Urukul proto_rev mismatch") From 9ad1fd8f25328c35a92e67ceac95c93d6d3dddab Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Mar 2018 17:40:03 +0100 Subject: [PATCH 0531/2457] urukul: add comment and doc about the AD9910 MASTER_RESET --- artiq/coredevice/urukul.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index c9c3edf4e..d2739a6d3 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -166,9 +166,12 @@ class CPLD: def init(self): """Initialize and detect Urukul. - Resets the DDS and verifies correct CPLD gateware version. + Resets the DDS I/O interface and verifies correct CPLD gateware + version. + Does not pulse the DDS MASTER_RESET as that confuses the AD9910. """ cfg = self.cfg_reg + # Don't pulse MASTER_RESET (m-labs/artiq#940) self.cfg_reg = cfg | (0 << CFG_RST) | (1 << CFG_IO_RST) proto_rev = urukul_sta_proto_rev(self.sta_read()) if proto_rev != STA_PROTO_REV_MATCH: From 9c2d343052d7e65f76f55dcda8b2f3ec5528de11 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 21 Mar 2018 10:52:14 +0800 Subject: [PATCH 0532/2457] sayma: use SERDES RTIO TTL This is not enabled on the standalone design as it breaks timing. --- artiq/gateware/targets/sayma_amc.py | 59 ++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 0b25886ba..2abd9786c 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -31,7 +31,7 @@ from artiq.gateware.amp import AMPSoC from artiq.gateware import serwb from artiq.gateware import remote_csr from artiq.gateware import rtio -from artiq.gateware.rtio.phy import ttl_simple, sawg +from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_ultrascale, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer @@ -126,6 +126,53 @@ class AD9154NoSAWG(Module, AutoCSR): for i in range(len(conv) // len(ramp)))) +class _RTIOClockMultiplier(Module): + def __init__(self, platform, rtio_clk_freq): + self.clock_domains.cd_rtio_serdes = ClockDomain() + self.clock_domains.cd_rtiox4_serdes = ClockDomain(reset_less=True) + + # See "Global Clock Network Deskew Using Two BUFGs" in ug572. + # See also AR#67885. + clkfbout = Signal() + clkfbin = Signal() + rtio_clk = Signal() + rtiox4_clk = Signal() + self.specials += [ + Instance("MMCME2_BASE", + p_CLKIN1_PERIOD=1e9/rtio_clk_freq, + i_CLKIN1=ClockSignal("rtio"), + i_RST=ResetSignal("rtio"), + + p_CLKFBOUT_MULT_F=8.0, p_DIVCLK_DIVIDE=1, + + o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbin, + + p_CLKOUT1_DIVIDE=8, o_CLKOUT1=rtio_clk, + p_CLKOUT2_DIVIDE=2, o_CLKOUT2=rtiox4_clk, + ), + Instance("BUFG", name="rtioserdes_bufg_fb", + i_I=clkfbout, o_O=clkfbin), + Instance("BUFG", name="rtioserdes_bufg_div", + i_I=rtio_clk, o_O=self.cd_rtio_serdes.clk), + Instance("BUFG", name="rtioserdes_bufg", + i_I=rtiox4_clk, o_O=self.cd_rtiox4_serdes.clk) + ] + self.comb += self.cd_rtio_serdes.rst.eq(ResetSignal("rio_phy")) + + platform.add_platform_command( + "set_property CLOCK_DELAY_GROUP RTIOSERDES_BALANCE [get_nets -of [get_pins rtioserdes_bufg_fb/O]]") + platform.add_platform_command( + "set_property CLOCK_DELAY_GROUP RTIOSERDES_BALANCE [get_nets -of [get_pins rtioserdes_bufg_div/O]]") + platform.add_platform_command( + "set_property CLOCK_DELAY_GROUP RTIOSERDES_BALANCE [get_nets -of [get_pins rtioserdes_bufg/O]]") + platform.add_platform_command( + "set_property USER_CLOCK_ROOT X2Y1 [get_nets -of [get_pins rtioserdes_bufg_fb/O]]") + platform.add_platform_command( + "set_property USER_CLOCK_ROOT X2Y1 [get_nets -of [get_pins rtioserdes_bufg_div/O]]") + platform.add_platform_command( + "set_property USER_CLOCK_ROOT X2Y1 [get_nets -of [get_pins rtioserdes_bufg/O]]") + + class Standalone(MiniSoC, AMPSoC): mem_map = { "cri_con": 0x10000000, @@ -341,6 +388,7 @@ class Master(MiniSoC, AMPSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gth.rxoutclk) + self.submodules.rtio_clkmul = _RTIOClockMultiplier(platform, rtio_clk_freq) rtio_channels = [] for i in range(4): phy = ttl_simple.Output(platform.request("user_led", i)) @@ -348,12 +396,12 @@ class Master(MiniSoC, AMPSoC): rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 0) self.comb += sma_io.direction.eq(1) - phy = ttl_simple.Output(sma_io.level) + phy = ttl_serdes_ultrascale.Output_8X(sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 1) self.comb += sma_io.direction.eq(0) - phy = ttl_simple.InOut(sma_io.level) + phy = ttl_serdes_ultrascale.InOut_8X(sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) @@ -397,6 +445,7 @@ class Satellite(BaseSoC): self.submodules += Microscope(platform.request("serial", 1), self.clk_freq) + self.submodules.rtio_clkmul = _RTIOClockMultiplier(platform, rtio_clk_freq) rtio_channels = [] for i in range(4): phy = ttl_simple.Output(platform.request("user_led", i)) @@ -404,12 +453,12 @@ class Satellite(BaseSoC): rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 0) self.comb += sma_io.direction.eq(1) - phy = ttl_simple.Output(sma_io.level) + phy = ttl_serdes_ultrascale.Output_8X(sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 1) self.comb += sma_io.direction.eq(0) - phy = ttl_simple.InOut(sma_io.level) + phy = ttl_serdes_ultrascale.InOut_8X(sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From f8c2d54e75bb28f1c0f1ab885aaf3a9d2ee02617 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 21 Mar 2018 13:01:38 +0800 Subject: [PATCH 0533/2457] ttl_serdes_ultrascale: configurable SERDES ratio. Also try X4 on Sayma --- .../rtio/phy/ttl_serdes_ultrascale.py | 55 +++++++++---------- artiq/gateware/targets/sayma_amc.py | 22 ++++---- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py b/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py index 33afb9afd..c9e47fcf8 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py @@ -6,10 +6,9 @@ from artiq.gateware.rtio.phy import ttl_serdes_generic # SERDES clocks are in dedicated domains to make the implementation # of the convoluted clocking schemes from AR#67885 less tedious. - -class _OSERDESE2_8X(Module): - def __init__(self, pad, pad_n=None): - self.o = Signal(8) +class _OSERDESE3(Module): + def __init__(self, dw, pad, pad_n=None): + self.o = Signal(dw) self.t_in = Signal() self.t_out = Signal() @@ -17,12 +16,12 @@ class _OSERDESE2_8X(Module): pad_o = Signal() self.specials += Instance("OSERDESE3", - p_DATA_WIDTH=8, p_INIT=0, + p_DATA_WIDTH=dw, p_INIT=0, p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, o_OQ=pad_o, o_T_OUT=self.t_out, i_RST=ResetSignal("rtio_serdes"), - i_CLK=ClockSignal("rtiox4_serdes"), i_CLKDIV=ClockSignal("rtio_serdes"), + i_CLK=ClockSignal("rtiox_serdes"), i_CLKDIV=ClockSignal("rtio_serdes"), i_D=self.o, i_T=self.t_in) if pad_n is None: self.comb += pad.eq(pad_o) @@ -35,10 +34,10 @@ class _OSERDESE2_8X(Module): io_IO=pad, io_IOB=pad_n) -class _ISERDESE2_8X(Module): - def __init__(self, pad, pad_n=None): - self.o = Signal(8) - self.i = Signal(8) +class _ISERDESE3(Module): + def __init__(self, dw, pad, pad_n=None): + self.o = Signal(dw) + self.i = Signal(dw) self.oe = Signal() # # # @@ -47,15 +46,15 @@ class _ISERDESE2_8X(Module): self.specials += Instance("ISERDESE3", p_IS_CLK_INVERTED=0, p_IS_CLK_B_INVERTED=1, - p_DATA_WIDTH=8, + p_DATA_WIDTH=dw, i_D=pad_i, i_RST=ResetSignal("rtio_serdes"), i_FIFO_RD_EN=0, - i_CLK=ClockSignal("rtiox4_serdes"), - i_CLK_B=ClockSignal("rtiox4_serdes"), # locally inverted + i_CLK=ClockSignal("rtiox_serdes"), + i_CLK_B=ClockSignal("rtiox_serdes"), # locally inverted i_CLKDIV=ClockSignal("rtio_serdes"), - o_Q=Cat(*self.i[::-1])) + o_Q=Cat(*[self.i[i] for i in reversed(range(dw))])) if pad_n is None: self.comb += pad_i.eq(pad) else: @@ -66,18 +65,18 @@ class _ISERDESE2_8X(Module): io_I=pad, io_IB=pad_n) -class _IOSERDESE2_8X(Module): - def __init__(self, pad, pad_n=None): - self.o = Signal(8) - self.i = Signal(8) +class _IOSERDESE3(Module): + def __init__(self, dw, pad, pad_n=None): + self.o = Signal(dw) + self.i = Signal(dw) self.oe = Signal() # # # pad_i = Signal() pad_o = Signal() - iserdes = _ISERDESE2_8X(pad_i) - oserdes = _OSERDESE2_8X(pad_o) + iserdes = _ISERDESE3(dw, pad_i) + oserdes = _OSERDESE3(dw, pad_o) self.submodules += iserdes, oserdes if pad_n is None: self.specials += Instance("IOBUF", @@ -96,22 +95,22 @@ class _IOSERDESE2_8X(Module): ] -class Output_8X(ttl_serdes_generic.Output): - def __init__(self, pad, pad_n=None): - serdes = _OSERDESE2_8X(pad, pad_n) +class Output(ttl_serdes_generic.Output): + def __init__(self, dw, pad, pad_n=None): + serdes = _OSERDESE3(dw, pad, pad_n) self.submodules += serdes ttl_serdes_generic.Output.__init__(self, serdes) -class InOut_8X(ttl_serdes_generic.InOut): - def __init__(self, pad, pad_n=None): - serdes = _IOSERDESE2_8X(pad, pad_n) +class InOut(ttl_serdes_generic.InOut): + def __init__(self, dw, pad, pad_n=None): + serdes = _IOSERDESE3(dw, pad, pad_n) self.submodules += serdes ttl_serdes_generic.InOut.__init__(self, serdes) -class Input_8X(ttl_serdes_generic.InOut): +class Input(ttl_serdes_generic.InOut): def __init__(self, pad, pad_n=None): - serdes = _ISERDESE2_8X(pad, pad_n) + serdes = _ISERDESE3(dw, pad, pad_n) self.submodules += serdes ttl_serdes_generic.InOut.__init__(self, serdes) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 2abd9786c..b5ca73c06 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -126,17 +126,18 @@ class AD9154NoSAWG(Module, AutoCSR): for i in range(len(conv) // len(ramp)))) +# Generates a X2 clock that can be used for 4:1 SERDES ratio. class _RTIOClockMultiplier(Module): def __init__(self, platform, rtio_clk_freq): self.clock_domains.cd_rtio_serdes = ClockDomain() - self.clock_domains.cd_rtiox4_serdes = ClockDomain(reset_less=True) + self.clock_domains.cd_rtiox_serdes = ClockDomain(reset_less=True) # See "Global Clock Network Deskew Using Two BUFGs" in ug572. # See also AR#67885. clkfbout = Signal() clkfbin = Signal() rtio_clk = Signal() - rtiox4_clk = Signal() + rtiox_clk = Signal() self.specials += [ Instance("MMCME2_BASE", p_CLKIN1_PERIOD=1e9/rtio_clk_freq, @@ -148,14 +149,14 @@ class _RTIOClockMultiplier(Module): o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbin, p_CLKOUT1_DIVIDE=8, o_CLKOUT1=rtio_clk, - p_CLKOUT2_DIVIDE=2, o_CLKOUT2=rtiox4_clk, + p_CLKOUT2_DIVIDE=4, o_CLKOUT2=rtiox_clk, ), Instance("BUFG", name="rtioserdes_bufg_fb", i_I=clkfbout, o_O=clkfbin), Instance("BUFG", name="rtioserdes_bufg_div", i_I=rtio_clk, o_O=self.cd_rtio_serdes.clk), Instance("BUFG", name="rtioserdes_bufg", - i_I=rtiox4_clk, o_O=self.cd_rtiox4_serdes.clk) + i_I=rtiox_clk, o_O=self.cd_rtiox_serdes.clk) ] self.comb += self.cd_rtio_serdes.rst.eq(ResetSignal("rio_phy")) @@ -238,6 +239,7 @@ class Standalone(MiniSoC, AMPSoC): self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) # RTIO + self.submodules.rtio_clkmul = _RTIOClockMultiplier(platform, 150e6) rtio_channels = [] for i in range(4): phy = ttl_simple.Output(platform.request("user_led", i)) @@ -245,12 +247,12 @@ class Standalone(MiniSoC, AMPSoC): rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 0) self.comb += sma_io.direction.eq(1) - phy = ttl_simple.Output(sma_io.level) + phy = ttl_serdes_ultrascale.Output(4, sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 1) self.comb += sma_io.direction.eq(0) - phy = ttl_simple.InOut(sma_io.level) + phy = ttl_serdes_ultrascale.InOut(4, sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) @@ -396,12 +398,12 @@ class Master(MiniSoC, AMPSoC): rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 0) self.comb += sma_io.direction.eq(1) - phy = ttl_serdes_ultrascale.Output_8X(sma_io.level) + phy = ttl_serdes_ultrascale.Output(4, sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 1) self.comb += sma_io.direction.eq(0) - phy = ttl_serdes_ultrascale.InOut_8X(sma_io.level) + phy = ttl_serdes_ultrascale.InOut(4, sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) @@ -453,12 +455,12 @@ class Satellite(BaseSoC): rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 0) self.comb += sma_io.direction.eq(1) - phy = ttl_serdes_ultrascale.Output_8X(sma_io.level) + phy = ttl_serdes_ultrascale.Output(4, sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 1) self.comb += sma_io.direction.eq(0) - phy = ttl_serdes_ultrascale.InOut_8X(sma_io.level) + phy = ttl_serdes_ultrascale.InOut(4, sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From 32f22f4c9cb41f1446a0380e5be100b21edaf755 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 21 Mar 2018 13:03:46 +0800 Subject: [PATCH 0534/2457] sayma: disable SERDES TTL entirely Timing closure becomes very random, even at 4X. --- artiq/gateware/targets/sayma_amc.py | 64 ++++------------------------- 1 file changed, 7 insertions(+), 57 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index b5ca73c06..f25039c5a 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -31,7 +31,7 @@ from artiq.gateware.amp import AMPSoC from artiq.gateware import serwb from artiq.gateware import remote_csr from artiq.gateware import rtio -from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_ultrascale, sawg +from artiq.gateware.rtio.phy import ttl_simple, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer @@ -126,54 +126,6 @@ class AD9154NoSAWG(Module, AutoCSR): for i in range(len(conv) // len(ramp)))) -# Generates a X2 clock that can be used for 4:1 SERDES ratio. -class _RTIOClockMultiplier(Module): - def __init__(self, platform, rtio_clk_freq): - self.clock_domains.cd_rtio_serdes = ClockDomain() - self.clock_domains.cd_rtiox_serdes = ClockDomain(reset_less=True) - - # See "Global Clock Network Deskew Using Two BUFGs" in ug572. - # See also AR#67885. - clkfbout = Signal() - clkfbin = Signal() - rtio_clk = Signal() - rtiox_clk = Signal() - self.specials += [ - Instance("MMCME2_BASE", - p_CLKIN1_PERIOD=1e9/rtio_clk_freq, - i_CLKIN1=ClockSignal("rtio"), - i_RST=ResetSignal("rtio"), - - p_CLKFBOUT_MULT_F=8.0, p_DIVCLK_DIVIDE=1, - - o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbin, - - p_CLKOUT1_DIVIDE=8, o_CLKOUT1=rtio_clk, - p_CLKOUT2_DIVIDE=4, o_CLKOUT2=rtiox_clk, - ), - Instance("BUFG", name="rtioserdes_bufg_fb", - i_I=clkfbout, o_O=clkfbin), - Instance("BUFG", name="rtioserdes_bufg_div", - i_I=rtio_clk, o_O=self.cd_rtio_serdes.clk), - Instance("BUFG", name="rtioserdes_bufg", - i_I=rtiox_clk, o_O=self.cd_rtiox_serdes.clk) - ] - self.comb += self.cd_rtio_serdes.rst.eq(ResetSignal("rio_phy")) - - platform.add_platform_command( - "set_property CLOCK_DELAY_GROUP RTIOSERDES_BALANCE [get_nets -of [get_pins rtioserdes_bufg_fb/O]]") - platform.add_platform_command( - "set_property CLOCK_DELAY_GROUP RTIOSERDES_BALANCE [get_nets -of [get_pins rtioserdes_bufg_div/O]]") - platform.add_platform_command( - "set_property CLOCK_DELAY_GROUP RTIOSERDES_BALANCE [get_nets -of [get_pins rtioserdes_bufg/O]]") - platform.add_platform_command( - "set_property USER_CLOCK_ROOT X2Y1 [get_nets -of [get_pins rtioserdes_bufg_fb/O]]") - platform.add_platform_command( - "set_property USER_CLOCK_ROOT X2Y1 [get_nets -of [get_pins rtioserdes_bufg_div/O]]") - platform.add_platform_command( - "set_property USER_CLOCK_ROOT X2Y1 [get_nets -of [get_pins rtioserdes_bufg/O]]") - - class Standalone(MiniSoC, AMPSoC): mem_map = { "cri_con": 0x10000000, @@ -239,7 +191,6 @@ class Standalone(MiniSoC, AMPSoC): self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) # RTIO - self.submodules.rtio_clkmul = _RTIOClockMultiplier(platform, 150e6) rtio_channels = [] for i in range(4): phy = ttl_simple.Output(platform.request("user_led", i)) @@ -247,12 +198,12 @@ class Standalone(MiniSoC, AMPSoC): rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 0) self.comb += sma_io.direction.eq(1) - phy = ttl_serdes_ultrascale.Output(4, sma_io.level) + phy = ttl_simple.Output(sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 1) self.comb += sma_io.direction.eq(0) - phy = ttl_serdes_ultrascale.InOut(4, sma_io.level) + phy = ttl_simple.InOut(sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) @@ -390,7 +341,6 @@ class Master(MiniSoC, AMPSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gth.rxoutclk) - self.submodules.rtio_clkmul = _RTIOClockMultiplier(platform, rtio_clk_freq) rtio_channels = [] for i in range(4): phy = ttl_simple.Output(platform.request("user_led", i)) @@ -398,12 +348,12 @@ class Master(MiniSoC, AMPSoC): rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 0) self.comb += sma_io.direction.eq(1) - phy = ttl_serdes_ultrascale.Output(4, sma_io.level) + phy = ttl_simple.Output(sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 1) self.comb += sma_io.direction.eq(0) - phy = ttl_serdes_ultrascale.InOut(4, sma_io.level) + phy = ttl_simple.InOut(sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) @@ -455,12 +405,12 @@ class Satellite(BaseSoC): rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 0) self.comb += sma_io.direction.eq(1) - phy = ttl_serdes_ultrascale.Output(4, sma_io.level) + phy = ttl_simple.Output(sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 1) self.comb += sma_io.direction.eq(0) - phy = ttl_serdes_ultrascale.InOut(4, sma_io.level) + phy = ttl_simple.InOut(sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From f74d5772f4b882f4e55eb014188997acc4903593 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Mar 2018 18:11:22 +0000 Subject: [PATCH 0535/2457] sampler: add wide eem definition --- artiq/gateware/targets/kasli.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 7ddf54245..14cadd1c6 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -161,8 +161,8 @@ def _dio(eem): for i in range(8)] -def _sampler(eem): - return [ +def _sampler(eem, eem_aux=None): + ios = [ ("{}_adc_spi_p".format(eem), 0, Subsignal("clk", Pins("{}:{}_p".format(eem, _eem_signal(0)))), Subsignal("miso", Pins("{}:{}_p".format(eem, _eem_signal(1)))), @@ -197,6 +197,26 @@ def _sampler(eem): (3, eem, "sdr") ] ] + if eem_aux is not None: + ios += [ + ("{}_adc_data_p".format(eem), 0, + Subsignal("clkout", Pins("{}:{}_p".format(eem_aux, _eem_signal(0)))), + Subsignal("sdoa", Pins("{}:{}_p".format(eem_aux, _eem_signal(1)))), + Subsignal("sdob", Pins("{}:{}_p".format(eem_aux, _eem_signal(2)))), + Subsignal("sdoc", Pins("{}:{}_p".format(eem_aux, _eem_signal(3)))), + Subsignal("sdod", Pins("{}:{}_p".format(eem_aux, _eem_signal(4)))), + IOStandard("LVDS_25"), + ), + ("{}_adc_data_n".format(eem), 0, + Subsignal("clkout", Pins("{}:{}_n".format(eem_aux, _eem_signal(0)))), + Subsignal("sdoa", Pins("{}:{}_n".format(eem_aux, _eem_signal(1)))), + Subsignal("sdob", Pins("{}:{}_n".format(eem_aux, _eem_signal(2)))), + Subsignal("sdoc", Pins("{}:{}_n".format(eem_aux, _eem_signal(3)))), + Subsignal("sdod", Pins("{}:{}_n".format(eem_aux, _eem_signal(4)))), + IOStandard("LVDS_25"), + ), + ] + return ios def _novogorny(eem): From 1fb59073629fff988893d4dec43be16b1858933d Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 20 Mar 2018 18:12:45 +0000 Subject: [PATCH 0536/2457] kasli: add SUServo variant (Sampler-Urukul Servo) --- artiq/gateware/targets/kasli.py | 104 +++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 14cadd1c6..00c19cc24 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -347,8 +347,8 @@ class Opticlock(_StandaloneBase): platform.add_extension(_urukul("eem6")) platform.add_extension(_zotino("eem7")) - # EEM clock fan-out from Si5324, not MMCX try: + # EEM clock fan-out from Si5324, not MMCX, only Kasli/v1.0 self.comb += platform.request("clk_sel").eq(1) except ConstraintError: pass @@ -432,6 +432,104 @@ class Opticlock(_StandaloneBase): self.add_rtio(rtio_channels) +class SUServo(_StandaloneBase): + """ + SUServo (Sampler-Urukul-Servo) extension variant configuration + """ + def __init__(self, **kwargs): + _StandaloneBase.__init__(self, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + # self.config["SI5324_EXT_REF"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + + platform = self.platform + platform.add_extension(_dio("eem0")) + platform.add_extension(_dio("eem1")) + platform.add_extension(_sampler("eem3", "eem2")) + platform.add_extension(_urukul("eem5", "eem4")) + platform.add_extension(_urukul("eem7", "eem6")) + + try: + # EEM clock fan-out from Si5324, not MMCX, only Kasli/v1.0 + self.comb += platform.request("clk_sel").eq(1) + except ConstraintError: + pass + + rtio_channels = [] + for i in range(16): + eem, port = divmod(i, 8) + pads = platform.request("eem{}".format(eem), port) + if i < 4: + cls = ttl_serdes_7series.InOut_8X + else: + cls = ttl_serdes_7series.Output_8X + phy = cls(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + # EEM3, EEM2: Sampler + phy = spi2.SPIMaster(self.platform.request("eem3_adc_spi_p"), + self.platform.request("eem3_adc_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=16)) + phy = spi2.SPIMaster(self.platform.request("eem3_pgia_spi_p"), + self.platform.request("eem3_pgia_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=2)) + + for signal in "cnv".split(): + pads = platform.request("eem3_{}".format(signal)) + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + pads = platform.request("eem3_sdr") + self.specials += DifferentialOutput(1, pads.p, pads.n) + + # EEM5 + EEM4: Urukul + phy = spi2.SPIMaster(self.platform.request("eem5_spi_p"), + self.platform.request("eem5_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + pads = platform.request("eem5_dds_reset") + self.specials += DifferentialOutput(0, pads.p, pads.n) + + for signal in "io_update sw0 sw1 sw2 sw3".split(): + pads = platform.request("eem5_{}".format(signal)) + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + # EEM7 + EEM6: Urukul + phy = spi2.SPIMaster(self.platform.request("eem7_spi_p"), + self.platform.request("eem7_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + pads = platform.request("eem7_dds_reset") + self.specials += DifferentialOutput(0, pads.p, pads.n) + + for signal in "io_update sw0 sw1 sw2 sw3".split(): + pads = platform.request("eem7_{}".format(signal)) + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + for i in (1, 2): + sfp_ctl = platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) + rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(rtio_channels) + + class SYSU(_StandaloneBase): def __init__(self, **kwargs): _StandaloneBase.__init__(self, **kwargs) @@ -791,13 +889,15 @@ def main(): soc_kasli_args(parser) parser.set_defaults(output_dir="artiq_kasli") parser.add_argument("-V", "--variant", default="opticlock", - help="variant: opticlock/sysu/master/satellite " + help="variant: opticlock/suservo/sysu/master/satellite " "(default: %(default)s)") args = parser.parse_args() variant = args.variant.lower() if variant == "opticlock": cls = Opticlock + elif variant == "suservo": + cls = SUServo elif variant == "sysu": cls = SYSU elif variant == "master": From f5a100111411f189eeaaa31fe6a60a090a0c0982 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 21 Mar 2018 08:22:12 +0000 Subject: [PATCH 0537/2457] suservo: add device database and artiq_flash variant --- artiq/examples/kasli_suservo/device_db.py | 155 ++++++++++++++++++++++ artiq/frontend/artiq_flash.py | 2 +- 2 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 artiq/examples/kasli_suservo/device_db.py diff --git a/artiq/examples/kasli_suservo/device_db.py b/artiq/examples/kasli_suservo/device_db.py new file mode 100644 index 000000000..b34536fa6 --- /dev/null +++ b/artiq/examples/kasli_suservo/device_db.py @@ -0,0 +1,155 @@ +core_addr = "lauda.ber.quartiq.de" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + +for i in range(16): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": i}, + } + + +device_db.update( + spi_sampler0_adc={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 16} + }, + spi_sampler0_pgia={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 17} + }, + ttl_sampler0_cnv={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 18} + }, + sampler0={ + "type": "local", + "module": "artiq.coredevice.sampler", + "class": "Sampler", + "arguments": { + "spi_adc_device": "spi_sampler0_adc", + "spi_pgia_device": "spi_sampler0_pgia", + "cnv_device": "ttl_sampler0_cnv", + } + }, + + spi_urukul0={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 19} + }, + ttl_urukul0_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 20} + }, + ttl_urukul0_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 21} + }, + ttl_urukul0_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 22} + }, + ttl_urukul0_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 23} + }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 24} + }, + urukul0_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul0_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } + +device_db.update( + led0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 31} + }, + led1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 32} + } +) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 0a1e9e10a..a03cad20d 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -265,7 +265,7 @@ def main(): }, "kasli": { "programmer": partial(ProgrammerXC7, board="kasli", proxy="bscan_spi_xc7a100t.bit"), - "variants": ["opticlock", "sysu", "master", "satellite"], + "variants": ["opticlock", "suservo", "sysu", "master", "satellite"], "gateware": ("spi0", 0x000000), "bootloader": ("spi0", 0x400000), "storage": ("spi0", 0x440000), From 80903cead78f29a91826ba568d4bb7a452434b7f Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 21 Mar 2018 08:22:48 +0000 Subject: [PATCH 0538/2457] novogorny: streamline gain setting method, style [nfc] --- artiq/coredevice/novogorny.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/artiq/coredevice/novogorny.py b/artiq/coredevice/novogorny.py index ae8b59d21..6fa879eb1 100644 --- a/artiq/coredevice/novogorny.py +++ b/artiq/coredevice/novogorny.py @@ -1,4 +1,3 @@ - from artiq.language.core import kernel, delay, portable from artiq.language.units import ns @@ -6,9 +5,9 @@ from artiq.coredevice import spi2 as spi SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | - 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | - 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | - 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) + 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | + 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | + 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) SPI_CS_ADC = 1 @@ -75,7 +74,7 @@ class Novogorny: kernel_invariants = {"bus", "core", "conv", "div", "v_ref"} def __init__(self, dmgr, spi_device, conv_device, div=8, - core_device="core"): + core_device="core"): self.bus = dmgr.get(spi_device) self.core = dmgr.get(core_device) self.conv = dmgr.get(conv_device) @@ -93,11 +92,13 @@ class Novogorny: :param channel: Channel index :param gain: Gain setting """ - self.gains &= ~(0b11 << (channel*2)) - self.gains |= gain << (channel*2) + gains = self.gains + gains &= ~(0b11 << (channel*2)) + gains |= gain << (channel*2) self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 16, self.div, SPI_CS_SR) - self.bus.write(self.gains << 16) + self.bus.write(gains << 16) + self.gains = gains @kernel def configure(self, data): From d48b8f308624b2511afff5a9fa073a766d751cf7 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 21 Mar 2018 09:17:48 +0000 Subject: [PATCH 0539/2457] kasli: fix sampler sdr/cnv pins --- artiq/gateware/targets/kasli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 00c19cc24..35de3f006 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -193,8 +193,8 @@ def _sampler(eem, eem_aux=None): Subsignal("n", Pins("{}:{}_n".format(j, _eem_signal(i)))), IOStandard("LVDS_25") ) for i, j, sig in [ - (2, eem, "cnv"), - (3, eem, "sdr") + (2, eem, "sdr"), + (3, eem, "cnv") ] ] if eem_aux is not None: From 1afce8c6138e40305ff46cd559c79336a5b18ad6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 21 Mar 2018 11:47:07 +0000 Subject: [PATCH 0540/2457] kasli: simplify single eem pin formatting --- artiq/gateware/targets/kasli.py | 122 ++++++++++++++++---------------- 1 file changed, 60 insertions(+), 62 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 35de3f006..9736191c4 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -153,10 +153,14 @@ def _eem_signal(i): return n +def _eem_pin(eem, i, pol): + return "{}:{}_{}".format(eem, _eem_signal(i), pol) + + def _dio(eem): return [(eem, i, - Subsignal("p", Pins("{}:{}_p".format(eem, _eem_signal(i)))), - Subsignal("n", Pins("{}:{}_n".format(eem, _eem_signal(i)))), + Subsignal("p", Pins(_eem_pin(eem, i, "p"))), + Subsignal("n", Pins(_eem_pin(eem, i, "n"))), IOStandard("LVDS_25")) for i in range(8)] @@ -164,33 +168,33 @@ def _dio(eem): def _sampler(eem, eem_aux=None): ios = [ ("{}_adc_spi_p".format(eem), 0, - Subsignal("clk", Pins("{}:{}_p".format(eem, _eem_signal(0)))), - Subsignal("miso", Pins("{}:{}_p".format(eem, _eem_signal(1)))), + Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), + Subsignal("miso", Pins(_eem_pin(eem, 1, "p"))), IOStandard("LVDS_25"), ), ("{}_adc_spi_n".format(eem), 0, - Subsignal("clk", Pins("{}:{}_n".format(eem, _eem_signal(0)))), - Subsignal("miso", Pins("{}:{}_n".format(eem, _eem_signal(1)))), + Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), + Subsignal("miso", Pins(_eem_pin(eem, 1, "n"))), IOStandard("LVDS_25"), ), ("{}_pgia_spi_p".format(eem), 0, - Subsignal("clk", Pins("{}:{}_p".format(eem, _eem_signal(4)))), - Subsignal("mosi", Pins("{}:{}_p".format(eem, _eem_signal(5)))), - Subsignal("miso", Pins("{}:{}_p".format(eem, _eem_signal(6)))), - Subsignal("cs_n", Pins("{}:{}_p".format(eem, _eem_signal(7)))), + Subsignal("clk", Pins(_eem_pin(eem, 4, "p"))), + Subsignal("mosi", Pins(_eem_pin(eem, 5, "p"))), + Subsignal("miso", Pins(_eem_pin(eem, 6, "p"))), + Subsignal("cs_n", Pins(_eem_pin(eem, 7, "p"))), IOStandard("LVDS_25"), ), ("{}_pgia_spi_n".format(eem), 0, - Subsignal("clk", Pins("{}:{}_n".format(eem, _eem_signal(4)))), - Subsignal("mosi", Pins("{}:{}_n".format(eem, _eem_signal(5)))), - Subsignal("miso", Pins("{}:{}_n".format(eem, _eem_signal(6)))), - Subsignal("cs_n", Pins("{}:{}_n".format(eem, _eem_signal(7)))), + Subsignal("clk", Pins(_eem_pin(eem, 4, "n"))), + Subsignal("mosi", Pins(_eem_pin(eem, 5, "n"))), + Subsignal("miso", Pins(_eem_pin(eem, 6, "n"))), + Subsignal("cs_n", Pins(_eem_pin(eem, 7, "n"))), IOStandard("LVDS_25"), ), ] + [ ("{}_{}".format(eem, sig), 0, - Subsignal("p", Pins("{}:{}_p".format(j, _eem_signal(i)))), - Subsignal("n", Pins("{}:{}_n".format(j, _eem_signal(i)))), + Subsignal("p", Pins(_eem_pin(j, i, "p"))), + Subsignal("n", Pins(_eem_pin(j, i, "n"))), IOStandard("LVDS_25") ) for i, j, sig in [ (2, eem, "sdr"), @@ -200,19 +204,19 @@ def _sampler(eem, eem_aux=None): if eem_aux is not None: ios += [ ("{}_adc_data_p".format(eem), 0, - Subsignal("clkout", Pins("{}:{}_p".format(eem_aux, _eem_signal(0)))), - Subsignal("sdoa", Pins("{}:{}_p".format(eem_aux, _eem_signal(1)))), - Subsignal("sdob", Pins("{}:{}_p".format(eem_aux, _eem_signal(2)))), - Subsignal("sdoc", Pins("{}:{}_p".format(eem_aux, _eem_signal(3)))), - Subsignal("sdod", Pins("{}:{}_p".format(eem_aux, _eem_signal(4)))), + Subsignal("clkout", Pins(_eem_pin(eem_aux, 0, "p"))), + Subsignal("sdoa", Pins(_eem_pin(eem_aux, 1, "p"))), + Subsignal("sdob", Pins(_eem_pin(eem_aux, 2, "p"))), + Subsignal("sdoc", Pins(_eem_pin(eem_aux, 3, "p"))), + Subsignal("sdod", Pins(_eem_pin(eem_aux, 4, "p"))), IOStandard("LVDS_25"), ), ("{}_adc_data_n".format(eem), 0, - Subsignal("clkout", Pins("{}:{}_n".format(eem_aux, _eem_signal(0)))), - Subsignal("sdoa", Pins("{}:{}_n".format(eem_aux, _eem_signal(1)))), - Subsignal("sdob", Pins("{}:{}_n".format(eem_aux, _eem_signal(2)))), - Subsignal("sdoc", Pins("{}:{}_n".format(eem_aux, _eem_signal(3)))), - Subsignal("sdod", Pins("{}:{}_n".format(eem_aux, _eem_signal(4)))), + Subsignal("clkout", Pins(_eem_pin(eem_aux, 0, "n"))), + Subsignal("sdoa", Pins(_eem_pin(eem_aux, 1, "n"))), + Subsignal("sdob", Pins(_eem_pin(eem_aux, 2, "n"))), + Subsignal("sdoc", Pins(_eem_pin(eem_aux, 3, "n"))), + Subsignal("sdod", Pins(_eem_pin(eem_aux, 4, "n"))), IOStandard("LVDS_25"), ), ] @@ -222,27 +226,25 @@ def _sampler(eem, eem_aux=None): def _novogorny(eem): return [ ("{}_spi_p".format(eem), 0, - Subsignal("clk", Pins("{}:{}_p".format(eem, _eem_signal(0)))), - Subsignal("mosi", Pins("{}:{}_p".format(eem, _eem_signal(1)))), - Subsignal("miso", Pins("{}:{}_p".format(eem, _eem_signal(2)))), + Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), + Subsignal("mosi", Pins(_eem_pin(eem, 1, "p"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))), Subsignal("cs_n", Pins( - "{0}:{1[0]}_p {0}:{1[1]}_p".format( - eem, [_eem_signal(i + 3) for i in range(2)]))), + _eem_pin(eem, 3, "p"), _eem_pin(eem, 4, "p"))), IOStandard("LVDS_25"), ), ("{}_spi_n".format(eem), 0, - Subsignal("clk", Pins("{}:{}_n".format(eem, _eem_signal(0)))), - Subsignal("mosi", Pins("{}:{}_n".format(eem, _eem_signal(1)))), - Subsignal("miso", Pins("{}:{}_n".format(eem, _eem_signal(2)))), + Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), + Subsignal("mosi", Pins(_eem_pin(eem, 1, "n"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))), Subsignal("cs_n", Pins( - "{0}:{1[0]}_n {0}:{1[1]}_n".format( - eem, [_eem_signal(i + 3) for i in range(2)]))), + _eem_pin(eem, 3, "n"), _eem_pin(eem, 4, "n"))), IOStandard("LVDS_25"), ), ] + [ ("{}_{}".format(eem, sig), 0, - Subsignal("p", Pins("{}:{}_p".format(j, _eem_signal(i)))), - Subsignal("n", Pins("{}:{}_n".format(j, _eem_signal(i)))), + Subsignal("p", Pins(_eem_pin(j, i, "p"))), + Subsignal("n", Pins(_eem_pin(j, i, "n"))), IOStandard("LVDS_25") ) for i, j, sig in [ (5, eem, "conv"), @@ -255,27 +257,25 @@ def _novogorny(eem): def _zotino(eem): return [ ("{}_spi_p".format(eem), 0, - Subsignal("clk", Pins("{}:{}_p".format(eem, _eem_signal(0)))), - Subsignal("mosi", Pins("{}:{}_p".format(eem, _eem_signal(1)))), - Subsignal("miso", Pins("{}:{}_p".format(eem, _eem_signal(2)))), + Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), + Subsignal("mosi", Pins(_eem_pin(eem, 1, "p"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))), Subsignal("cs_n", Pins( - "{0}:{1[0]}_p {0}:{1[1]}_p".format( - eem, [_eem_signal(i + 3) for i in range(2)]))), + _eem_pin(eem, 3, "p"), _eem_pin(eem, 4, "p"))), IOStandard("LVDS_25"), ), ("{}_spi_n".format(eem), 0, - Subsignal("clk", Pins("{}:{}_n".format(eem, _eem_signal(0)))), - Subsignal("mosi", Pins("{}:{}_n".format(eem, _eem_signal(1)))), - Subsignal("miso", Pins("{}:{}_n".format(eem, _eem_signal(2)))), + Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), + Subsignal("mosi", Pins(_eem_pin(eem, 1, "n"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))), Subsignal("cs_n", Pins( - "{0}:{1[0]}_n {0}:{1[1]}_n".format( - eem, [_eem_signal(i + 3) for i in range(2)]))), + _eem_pin(eem, 3, "n"), _eem_pin(eem, 4, "n"))), IOStandard("LVDS_25"), ), ] + [ ("{}_{}".format(eem, sig), 0, - Subsignal("p", Pins("{}:{}_p".format(j, _eem_signal(i)))), - Subsignal("n", Pins("{}:{}_n".format(j, _eem_signal(i)))), + Subsignal("p", Pins(_eem_pin(j, i, "p"))), + Subsignal("n", Pins(_eem_pin(j, i, "n"))), IOStandard("LVDS_25") ) for i, j, sig in [ (5, eem, "ldac_n"), @@ -288,21 +288,19 @@ def _zotino(eem): def _urukul(eem, eem_aux=None): ios = [ ("{}_spi_p".format(eem), 0, - Subsignal("clk", Pins("{}:{}_p".format(eem, _eem_signal(0)))), - Subsignal("mosi", Pins("{}:{}_p".format(eem, _eem_signal(1)))), - Subsignal("miso", Pins("{}:{}_p".format(eem, _eem_signal(2)))), + Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), + Subsignal("mosi", Pins(_eem_pin(eem, 1, "p"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))), Subsignal("cs_n", Pins( - "{0}:{1[0]}_p {0}:{1[1]}_p {0}:{1[2]}_p".format( - eem, [_eem_signal(i + 3) for i in range(3)]))), + *(_eem_pin(eem, i + 3, "p") for i in range(3)))), IOStandard("LVDS_25"), ), ("{}_spi_n".format(eem), 0, - Subsignal("clk", Pins("{}:{}_n".format(eem, _eem_signal(0)))), - Subsignal("mosi", Pins("{}:{}_n".format(eem, _eem_signal(1)))), - Subsignal("miso", Pins("{}:{}_n".format(eem, _eem_signal(2)))), + Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), + Subsignal("mosi", Pins(_eem_pin(eem, 1, "n"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))), Subsignal("cs_n", Pins( - "{0}:{1[0]}_n {0}:{1[1]}_n {0}:{1[2]}_n".format( - eem, [_eem_signal(i + 3) for i in range(3)]))), + *(_eem_pin(eem, i + 3, "n") for i in range(3)))), IOStandard("LVDS_25"), ), ] @@ -320,8 +318,8 @@ def _urukul(eem, eem_aux=None): for i, j, sig in ttls: ios.append( ("{}_{}".format(eem, sig), 0, - Subsignal("p", Pins("{}:{}_p".format(j, _eem_signal(i)))), - Subsignal("n", Pins("{}:{}_n".format(j, _eem_signal(i)))), + Subsignal("p", Pins(_eem_pin(j, i, "p"))), + Subsignal("n", Pins(_eem_pin(j, i, "n"))), IOStandard("LVDS_25") )) return ios From 97918447a3426c39f23d3766049c7fb644c0a33e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 21 Mar 2018 10:06:31 +0000 Subject: [PATCH 0541/2457] sampler: add coredevice driver --- artiq/coredevice/sampler.py | 138 ++++++++++++++++++++++++++ doc/manual/core_drivers_reference.rst | 6 ++ 2 files changed, 144 insertions(+) create mode 100644 artiq/coredevice/sampler.py diff --git a/artiq/coredevice/sampler.py b/artiq/coredevice/sampler.py new file mode 100644 index 000000000..3bb94f555 --- /dev/null +++ b/artiq/coredevice/sampler.py @@ -0,0 +1,138 @@ + +from artiq.language.core import kernel, delay, portable +from artiq.language.units import ns + +from artiq.coredevice import spi2 as spi + + +SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | + 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | + 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | + 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) + + +SPI_CS_ADC = 0 # no CS, SPI_END does not matter, framing is done with CNV +SPI_CS_PGIA = 1 # separate SPI bus, CS used as RCLK + + +@portable +def adc_mu_to_volt(data, gain=0, v_ref=5.): + """Convert ADC data in machine units to Volts. + + :param data: 16 bit signed ADC word + :param gain: PGIA gain setting (0: 1, ..., 3: 1000) + :param v_ref: Reference voltage in Volts + :return: Voltage in Volts + """ + for i in range(gain): + v_ref /= 10. + volt_per_lsb = v_ref/(1 << 15) + return data*volt_per_lsb + + +class Sampler: + """Sampler ADC. + + Controls the LTC2320-16 8 channel 16 bit ADC with SPI interface and + the switchable gain instrumentation amplifiers. + + :param spi_adc_device: ADC SPI bus device name + :param spi_pgia_device: PGIA SPI bus device name + :param cnv_device: CNV RTIO TTLOut channel name + :param div: SPI clock divider (default: 8) + :param core_device: Core device name + """ + kernel_invariants = {"bus_adc", "bus_pgia", "core", "cnv", "div", "v_ref"} + + def __init__(self, dmgr, spi_adc_device, spi_pgia_device, cnv_device, + div=8, core_device="core"): + self.bus_adc = dmgr.get(spi_adc_device) + self.bus_pgia = dmgr.get(spi_pgia_device) + self.core = dmgr.get(core_device) + self.cnv = dmgr.get(cnv_device) + self.div = div + self.gains = 0x0000 + self.v_ref = 10. # 5 Volt reference, 0.5 AFE diff gain + + @kernel + def init(self): + """Initialize the device. + + Sets up SPI channels. + """ + self.bus_adc.set_config_mu(SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, + 32, self.div, SPI_CS_ADC) + self.bus_pgia.set_config_mu(SPI_CONFIG | spi.SPI_END, + 16, self.div, SPI_CS_PGIA) + + @kernel + def set_gain_mu(self, channel, gain): + """Set instrumentation amplifier gain of a channel. + + The four gain settings (0, 1, 2, 3) corresponds to gains of + (1, 10, 100, 1000) respectively. + + :param channel: Channel index + :param gain: Gain setting + """ + gains = self.gains + gains &= ~(0b11 << (channel*2)) + gains |= gain << (channel*2) + self.bus_pgia.write(gains << 16) + self.gains = gains + + @kernel + def get_gains_mu(self): + """Read the PGIA gain settings of all channels. + + :return: The PGIA gain settings in machine units. + """ + self.bus_pgia.set_config_mu(SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, + 16, self.div, SPI_CS_PGIA) + self.bus_pgia.write(self.gains << 16) + self.bus_pgia.set_config_mu(SPI_CONFIG | spi.SPI_END, + 16, self.div, SPI_CS_PGIA) + self.gains = self.bus_pgia.read() & 0xffff + return self.gains + + @kernel + def sample_mu(self, data): + """Acquire a set of samples. + + Perform a conversion and transfer the samples. + + This assumes that the input FIFO of the ADC SPI RTIO channel is deep + enough to buffer the samples (half the length of `data` deep). + If it is not, there will be RTIO input overflows. + + :param data: List of data samples to fill. Must have even length. + Samples are always read from the last channel (channel 7) down. + The `data` list will always be filled with the last item + holding to the sample from channel 7. + """ + self.cnv.pulse(30*ns) # t_CNVH + delay(450*ns) # t_CONV + mask = 1 << 15 + for i in range(len(data)//2): + self.bus_adc.write(0) + for i in range(len(data) - 1, -1, -2): + val = self.bus_adc.read() + data[i] = val >> 16 + val &= 0xffff + data[i - 1] = -(val & mask) + (val & ~mask) + + @kernel + def sample(self, data): + """Acquire a set of samples. + + .. seealso:: :meth:`sample_mu` + + :param data: List of floating point data samples to fill. + """ + n = len(data) + adc_data = [0]*n + self.sample_mu(adc_data) + for i in range(n): + channel = 8 - len(data) + gain = (self.gains >> (channel*2)) & 0b11 + data[i] = adc_mu_to_volt(adc_data[i], gain, self.v_ref) diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 4185ddc47..8655fbcea 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -81,6 +81,12 @@ These drivers are for the core device and the peripherals closely integrated int .. automodule:: artiq.coredevice.novogorny :members: +:mod:`artiq.coredevice.sampler` module +-------------------------------------- + +.. automodule:: artiq.coredevice.sampler + :members: + :mod:`artiq.coredevice.urukul` module ------------------------------------- From 12d699f2a849d65e9f8d56079d1ca93a917f2a35 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 21 Mar 2018 10:11:23 +0000 Subject: [PATCH 0542/2457] suservo: add sampler example --- .../kasli_suservo/repository/sampler.py | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 artiq/examples/kasli_suservo/repository/sampler.py diff --git a/artiq/examples/kasli_suservo/repository/sampler.py b/artiq/examples/kasli_suservo/repository/sampler.py new file mode 100644 index 000000000..fc4e425ee --- /dev/null +++ b/artiq/examples/kasli_suservo/repository/sampler.py @@ -0,0 +1,35 @@ +from artiq.experiment import * + + +class Sampler(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("sampler0") + + def run(self): + self.data = [] + self.sample() + for d in self.data: + print(d) + + @kernel + def sample(self): + self.core.break_realtime() + self.sampler0.init() + for g in range(4): + for ch in range(8): + self.sampler0.set_gain_mu(ch, g) + self.ret([self.sampler0.get_gains_mu()]) + delay(10*ms) + raw = [0] * 8 + self.sampler0.sample_mu(raw) + self.ret(raw) + delay(10*ms) + data = [0.] * 8 + self.sampler0.sample(data) + self.ret(data) + delay(10*ms) + + @rpc(flags={"async"}) + def ret(self, data): + self.data.append(data) From 82c4f0eed42ee31653dd2fda109571e35573b3b0 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 21 Mar 2018 14:22:13 +0100 Subject: [PATCH 0543/2457] sampler: fix channel gain retrieval --- artiq/coredevice/sampler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/sampler.py b/artiq/coredevice/sampler.py index 3bb94f555..66c8d45ad 100644 --- a/artiq/coredevice/sampler.py +++ b/artiq/coredevice/sampler.py @@ -133,6 +133,6 @@ class Sampler: adc_data = [0]*n self.sample_mu(adc_data) for i in range(n): - channel = 8 - len(data) + channel = i + 8 - len(data) gain = (self.gains >> (channel*2)) & 0b11 data[i] = adc_mu_to_volt(adc_data[i], gain, self.v_ref) From 770b0a7b79a89f1ea0da6cfd8d1c647dc71c85a2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 21 Mar 2018 18:38:39 +0000 Subject: [PATCH 0544/2457] novogorny: conv -> cnv * parity with sampler * also add novogorny device to opticlock --- artiq/coredevice/novogorny.py | 12 ++++++------ artiq/examples/kasli_opticlock/device_db.py | 11 ++++++++++- artiq/gateware/targets/kasli.py | 4 ++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/artiq/coredevice/novogorny.py b/artiq/coredevice/novogorny.py index 6fa879eb1..f92b00e25 100644 --- a/artiq/coredevice/novogorny.py +++ b/artiq/coredevice/novogorny.py @@ -67,17 +67,17 @@ class Novogorny: register. :param spi_device: SPI bus device name - :param conv_device: CONV RTIO TTLOut channel name + :param cnv_device: CNV RTIO TTLOut channel name :param div: SPI clock divider (default: 8) :param core_device: Core device name """ - kernel_invariants = {"bus", "core", "conv", "div", "v_ref"} + kernel_invariants = {"bus", "core", "cnv", "div", "v_ref"} - def __init__(self, dmgr, spi_device, conv_device, div=8, + def __init__(self, dmgr, spi_device, cnv_device, div=8, core_device="core"): self.bus = dmgr.get(spi_device) self.core = dmgr.get(core_device) - self.conv = dmgr.get(conv_device) + self.cnv = dmgr.get(cnv_device) self.div = div self.gains = 0x0000 self.v_ref = 5. # 5 Volt reference @@ -125,7 +125,7 @@ class Novogorny: :param next_ctrl: ADC control word for the next sample :return: The ADC result packet (machine units) """ - self.conv.pulse(40*ns) # t_CNVH + self.cnv.pulse(40*ns) # t_CNVH delay(560*ns) # t_CONV max self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, 24, self.div, SPI_CS_ADC) @@ -163,7 +163,7 @@ class Novogorny: 24, self.div, SPI_CS_ADC) for i in range(len(data)): t0 = now_mu() - self.conv.pulse(40*ns) # t_CNVH + self.cnv.pulse(40*ns) # t_CNVH delay(560*ns) # t_CONV max self.bus.write(ctrl << 24) at_mu(t0 + dt_mu) diff --git a/artiq/examples/kasli_opticlock/device_db.py b/artiq/examples/kasli_opticlock/device_db.py index 7f8478bbe..3ee94fb2e 100644 --- a/artiq/examples/kasli_opticlock/device_db.py +++ b/artiq/examples/kasli_opticlock/device_db.py @@ -192,12 +192,21 @@ device_db = { "class": "SPIMaster", "arguments": {"channel": 24} }, - "ttl_novogorny0_conv": { + "ttl_novogorny0_cnv": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 25} }, + "novogorny0" : { + "type": "local", + "module": "artiq.coredevice.novogorny", + "class": "Novogorny", + "arguments": { + "spi_device": "spi_novogorny0", + "cnv_device": "ttl_novogorny0_cnv", + } + }, "spi_urukul0": { "type": "local", diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 9736191c4..5923db950 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -247,7 +247,7 @@ def _novogorny(eem): Subsignal("n", Pins(_eem_pin(j, i, "n"))), IOStandard("LVDS_25") ) for i, j, sig in [ - (5, eem, "conv"), + (5, eem, "cnv"), (6, eem, "busy"), (7, eem, "scko"), ] @@ -369,7 +369,7 @@ class Opticlock(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=16)) - for signal in "conv".split(): + for signal in "cnv".split(): pads = platform.request("eem3_{}".format(signal)) phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) self.submodules += phy From 06f24c6aa2b9932db8bf354b8cc7c84c5e37a460 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Mar 2018 11:46:41 +0800 Subject: [PATCH 0545/2457] RELEASE_NOTES: update --- RELEASE_NOTES.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 2befe32ca..237ac9caa 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -26,6 +26,25 @@ Release notes commits on e.g. the ``ad5360`` driver for an example how to port from the old to the new bus. + +3.6 +--- + +No further notes. + + +3.5 +--- + +No further notes. + + +3.4 +--- + +No further notes. + + 3.3 --- From 1b913398659eaacd38a9f173c0bed0ae5dd22469 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Mar 2018 12:05:47 +0800 Subject: [PATCH 0546/2457] manual: fix text role --- doc/manual/installing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 574af6ac8..5cd152771 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -187,7 +187,7 @@ To flash the idle kernel: The startup kernel is executed once when the core device powers up. It should initialize DDSes, set up TTL directions, etc. Proceed as with the idle kernel, but using the ``startup_kernel`` key in ``artiq_coreconfig``. -For DRTIO systems, the startup kernel should wait until the desired links are up, using :method:`artiq.coredevice.Core.get_drtio_link_status`. +For DRTIO systems, the startup kernel should wait until the desired links are up, using :meth:`artiq.coredevice.Core.get_drtio_link_status`. * (optional) Select the startup clock From 102e3983b5cd34147552f03c693ee12b1bee485b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Mar 2018 12:06:01 +0800 Subject: [PATCH 0547/2457] manual: reorganize core drivers --- doc/manual/core_drivers_reference.rst | 136 +++++++++++++++----------- 1 file changed, 79 insertions(+), 57 deletions(-) diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 8655fbcea..66e3cfea6 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -3,104 +3,126 @@ Core drivers reference These drivers are for the core device and the peripherals closely integrated into it, which do not use the controller mechanism. + +System drivers +-------------- + :mod:`artiq.coredevice.core` module ------------------------------------ ++++++++++++++++++++++++++++++++++++ .. automodule:: artiq.coredevice.core :members: -:mod:`artiq.coredevice.ttl` module ----------------------------------- +:mod:`artiq.coredevice.exceptions` module ++++++++++++++++++++++++++++++++++++++++++ -.. automodule:: artiq.coredevice.ttl - :members: - -:mod:`artiq.coredevice.dds` module ----------------------------------- - -.. automodule:: artiq.coredevice.dds +.. automodule:: artiq.coredevice.exceptions :members: :mod:`artiq.coredevice.dma` module ----------------------------------- +++++++++++++++++++++++++++++++++++ .. automodule:: artiq.coredevice.dma :members: +:mod:`artiq.coredevice.cache` module +++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.cache + :members: + + +Digital I/O drivers ++++++++++++++++++++ + +:mod:`artiq.coredevice.ttl` module +++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.ttl + :members: + +:mod:`artiq.coredevice.shiftreg` module +++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.shiftreg + :members: + :mod:`artiq.coredevice.spi2` module ------------------------------------ ++++++++++++++++++++++++++++++++++++ .. automodule:: artiq.coredevice.spi2 :members: -:mod:`artiq.coredevice.ad5360` module -------------------------------------- - -.. automodule:: artiq.coredevice.ad5360 - :members: - :mod:`artiq.coredevice.i2c` module ----------------------------------- +++++++++++++++++++++++++++++++++++ .. automodule:: artiq.coredevice.i2c :members: :mod:`artiq.coredevice.pcf8574a` module ---------------------------------------- ++++++++++++++++++++++++++++++++++++++++ .. automodule:: artiq.coredevice.pcf8574a :members: -:mod:`artiq.coredevice.cache` module ------------------------------------- -.. automodule:: artiq.coredevice.cache - :members: - -:mod:`artiq.coredevice.exceptions` module ------------------------------------------ - -.. automodule:: artiq.coredevice.exceptions - :members: - -:mod:`artiq.coredevice.spline` module -------------------------------------- - -.. automodule:: artiq.coredevice.spline - :members: - -:mod:`artiq.coredevice.sawg` module ------------------------------------ - -.. automodule:: artiq.coredevice.sawg - :members: - -:mod:`artiq.coredevice.novogorny` module ----------------------------------------- - -.. automodule:: artiq.coredevice.novogorny - :members: - -:mod:`artiq.coredevice.sampler` module --------------------------------------- - -.. automodule:: artiq.coredevice.sampler - :members: +RF generation drivers +--------------------- :mod:`artiq.coredevice.urukul` module -------------------------------------- ++++++++++++++++++++++++++++++++++++++ .. automodule:: artiq.coredevice.urukul :members: :mod:`artiq.coredevice.ad9912` module -------------------------------------- ++++++++++++++++++++++++++++++++++++++ .. automodule:: artiq.coredevice.ad9912 :members: :mod:`artiq.coredevice.ad9910` module -------------------------------------- ++++++++++++++++++++++++++++++++++++++ .. automodule:: artiq.coredevice.ad9910 :members: + +:mod:`artiq.coredevice.spline` module ++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.spline + :members: + +:mod:`artiq.coredevice.sawg` module ++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.sawg + :members: + +:mod:`artiq.coredevice.dds` module +++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.dds + :members: + + +DAC/ADC drivers +--------------- + +:mod:`artiq.coredevice.ad5360` module ++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.ad5360 + :members: + +:mod:`artiq.coredevice.sampler` module +++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.sampler + :members: + +:mod:`artiq.coredevice.novogorny` module +++++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.novogorny + :members: From 9eb02183896be911e819af3d512269ea9cc2fe94 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Mar 2018 13:26:28 +0800 Subject: [PATCH 0548/2457] RELEASE_NOTES: add sections for major releases --- RELEASE_NOTES.rst | 60 ++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 237ac9caa..89a507a52 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -3,8 +3,11 @@ Release notes ============= +ARTIQ-4 +------- + 4.0 ---- +*** * RTIO outputs use a new architecture called Scalable Event Dispatcher (SED), which allows building systems with large number of RTIO channels more @@ -27,32 +30,35 @@ Release notes to the new bus. +ARTIQ-3 +------- + 3.6 ---- +*** No further notes. 3.5 ---- +*** No further notes. 3.4 ---- +*** No further notes. 3.3 ---- +*** No further notes. 3.2 ---- +*** * To accommodate larger runtimes, the flash layout as changed. As a result, the contents of the flash storage will be lost when upgrading. Set the values back @@ -60,13 +66,13 @@ No further notes. 3.1 ---- +*** No further notes. 3.0 ---- +*** * The ``--embed`` option of applets is replaced with the environment variable ``ARTIQ_APPLET_EMBED``. The GUI sets this enviroment variable itself and the @@ -119,50 +125,53 @@ No further notes. * Packages are no longer available for 32-bit Windows. +ARTIQ-2 +------- + 2.5 ---- +*** No further notes. 2.4 ---- +*** No further notes. 2.3 ---- +*** * When using conda, add the conda-forge channel before installing ARTIQ. 2.2 ---- +*** No further notes. 2.1 ---- +*** No further notes. 2.0 ---- +*** No further notes. 2.0rc2 ------- +****** No further notes. 2.0rc1 ------- +****** * The format of the influxdb pattern file is simplified. The procedure to edit patterns is also changed to modifying the pattern file and calling: @@ -211,39 +220,42 @@ No further notes. receives a numpy type. +ARTIQ-1 +------- + 1.3 ---- +*** No further notes. 1.2 ---- +*** No further notes. 1.1 ---- +*** * TCA6424A.set converts the "outputs" value to little-endian before programming it into the registers. 1.0 ---- +*** No further notes. 1.0rc4 ------- +****** * setattr_argument and setattr_device add their key to kernel_invariants. 1.0rc3 ------- +****** * The HDF5 format has changed. @@ -257,7 +269,7 @@ No further notes. 1.0rc2 ------- +****** * The CPU speed in the pipistrello gateware has been reduced from 83 1/3 MHz to 75 MHz. This will reduce the achievable sustained pulse rate and latency @@ -267,7 +279,7 @@ No further notes. 1.0rc1 ------- +****** * Experiments (your code) should use ``from artiq.experiment import *`` (and not ``from artiq import *`` as previously) From 40e2ced85e9f7869be25b254eed429b08352b981 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Mar 2018 13:26:45 +0800 Subject: [PATCH 0549/2457] manual: fix core_drivers_reference --- doc/manual/core_drivers_reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 66e3cfea6..08633b7c6 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -33,7 +33,7 @@ System drivers Digital I/O drivers -+++++++++++++++++++ +------------------- :mod:`artiq.coredevice.ttl` module ++++++++++++++++++++++++++++++++++ From f2cc2a5ff298009af324365e3287da23a9199d52 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Mar 2018 16:29:31 +0800 Subject: [PATCH 0550/2457] firmware: reset local RTIO PHYs on startup (#958) --- artiq/firmware/runtime/rtio_mgt.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index a5778bd59..675d91a1a 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -271,6 +271,7 @@ pub fn startup(io: &Io) { pub fn init_core() { unsafe { csr::rtio_core::reset_write(1); + csr::rtio_core::reset_phy_write(1); } drtio::init() } From eeedcfbdd7dc3946652575fb6bf6477438911754 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Mar 2018 17:11:21 +0800 Subject: [PATCH 0551/2457] artiq_flash: do not suppress useful backtrace information --- artiq/frontend/artiq_flash.py | 75 +++++++++++++++++------------------ 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index a03cad20d..27d527579 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -327,46 +327,43 @@ def main(): atexit.register(lambda: os.unlink(bin_filename)) return bin_filename - try: - for action in args.action: - if action == "gateware": - gateware_bin = convert_gateware( - artifact_path(variant, "gateware", "top.bit")) - programmer.write_binary(*config["gateware"], gateware_bin) - if args.target == "sayma": - rtm_gateware_bin = convert_gateware( - artifact_path("rtm_gateware", "rtm.bit"), header=True) - programmer.write_binary(*config["rtm_gateware"], - rtm_gateware_bin) - elif action == "bootloader": - bootloader_bin = artifact_path(variant, "software", "bootloader", "bootloader.bin") - programmer.write_binary(*config["bootloader"], bootloader_bin) - elif action == "storage": - storage_img = args.storage - programmer.write_binary(*config["storage"], storage_img) - elif action == "firmware": - if variant == "satellite": - firmware = "satman" - else: - firmware = "runtime" - - firmware_fbi = artifact_path(variant, "software", firmware, firmware + ".fbi") - programmer.write_binary(*config["firmware"], firmware_fbi) - elif action == "load": - if args.target == "sayma": - rtm_gateware_bit = artifact_path("rtm_gateware", "rtm.bit") - programmer.load(rtm_gateware_bit, 0) - gateware_bit = artifact_path(variant, "gateware", "top.bit") - programmer.load(gateware_bit, 1) - else: - gateware_bit = artifact_path(variant, "gateware", "top.bit") - programmer.load(gateware_bit, 0) - elif action == "start": - programmer.start() + for action in args.action: + if action == "gateware": + gateware_bin = convert_gateware( + artifact_path(variant, "gateware", "top.bit")) + programmer.write_binary(*config["gateware"], gateware_bin) + if args.target == "sayma": + rtm_gateware_bin = convert_gateware( + artifact_path("rtm_gateware", "rtm.bit"), header=True) + programmer.write_binary(*config["rtm_gateware"], + rtm_gateware_bin) + elif action == "bootloader": + bootloader_bin = artifact_path(variant, "software", "bootloader", "bootloader.bin") + programmer.write_binary(*config["bootloader"], bootloader_bin) + elif action == "storage": + storage_img = args.storage + programmer.write_binary(*config["storage"], storage_img) + elif action == "firmware": + if variant == "satellite": + firmware = "satman" else: - raise ValueError("invalid action", action) - except FileNotFoundError as e: - raise SystemExit(e) + firmware = "runtime" + + firmware_fbi = artifact_path(variant, "software", firmware, firmware + ".fbi") + programmer.write_binary(*config["firmware"], firmware_fbi) + elif action == "load": + if args.target == "sayma": + rtm_gateware_bit = artifact_path("rtm_gateware", "rtm.bit") + programmer.load(rtm_gateware_bit, 0) + gateware_bit = artifact_path(variant, "gateware", "top.bit") + programmer.load(gateware_bit, 1) + else: + gateware_bit = artifact_path(variant, "gateware", "top.bit") + programmer.load(gateware_bit, 0) + elif action == "start": + programmer.start() + else: + raise ValueError("invalid action", action) if args.dry_run: print("\n".join(programmer.script())) From 46d5af31a1a3304a4e0a4cb8af7cf2cb2ba36e8a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Mar 2018 17:20:45 +0800 Subject: [PATCH 0552/2457] artiq_flash: enclose filename in curly braces before passing to OpenOCD Closes #927 --- artiq/frontend/artiq_flash.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 27d527579..b11548a03 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -138,7 +138,7 @@ class Programmer: bitfile = self._client.upload(bitfile) add_commands(self._script, - "pld load {pld} {filename}", + "pld load {pld} {{{filename}}}", pld=pld, filename=bitfile) def load_proxy(self): @@ -152,8 +152,8 @@ class Programmer: add_commands(self._script, "flash probe {bankname}", "flash erase_sector {bankname} {firstsector} {lastsector}", - "flash write_bank {bankname} {filename} {address:#x}", - "flash verify_bank {bankname} {filename} {address:#x}", + "flash write_bank {bankname} {{{filename}}} {address:#x}", + "flash verify_bank {bankname} {{{filename}}} {address:#x}", bankname=bankname, address=address, filename=filename, firstsector=address // self._sector_size, lastsector=(address + size - 1) // self._sector_size) @@ -164,7 +164,7 @@ class Programmer: filename = self._client.prepare_download(filename) add_commands(self._script, "flash probe {bankname}", - "flash read_bank {bankname} {filename} {address:#x} {length}", + "flash read_bank {bankname} {{{filename}}} {address:#x} {length}", bankname=bankname, filename=filename, address=address, length=length) def start(self): @@ -184,7 +184,6 @@ class Programmer: cmdline += ["-s", scripts_path()] cmdline += ["-c", "; ".join(self.script())] - cmdline = [arg.replace("{", "{{").replace("}", "}}") for arg in cmdline] self._client.run_command(cmdline) self._client.download() From 0635907699ea75527b27eb7e2a5572dd0d094f2e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 22 Mar 2018 19:10:29 +0800 Subject: [PATCH 0553/2457] artiq_flash: fix cmdline formatting --- artiq/frontend/artiq_flash.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index b11548a03..4b614aa98 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -184,6 +184,7 @@ class Programmer: cmdline += ["-s", scripts_path()] cmdline += ["-c", "; ".join(self.script())] + cmdline = [arg.replace("{", "{{").replace("}", "}}") for arg in cmdline] self._client.run_command(cmdline) self._client.download() From 1553fc8c7df7150c00ce853dea71fc6840606f7e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 23 Mar 2018 11:10:41 +0000 Subject: [PATCH 0554/2457] sed: reset `valid` in output sorter --- artiq/gateware/rtio/sed/output_network.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/rtio/sed/output_network.py b/artiq/gateware/rtio/sed/output_network.py index 8be0ef0ef..58e566a29 100644 --- a/artiq/gateware/rtio/sed/output_network.py +++ b/artiq/gateware/rtio/sed/output_network.py @@ -56,9 +56,12 @@ class OutputNetwork(Module): step_input = self.input for step in boms_steps_pairs(lane_count): - step_output = [Record(layouts.output_network_node(seqn_width, layout_payload), - reset_less=True) - for _ in range(lane_count)] + step_output = [] + for i in range(lane_count): + rec = Record(layouts.output_network_node(seqn_width, layout_payload), + reset_less=True) + rec.valid.reset_less = False + step_output.append(rec) for node1, node2 in step: nondata_difference = Signal() From a992a672d9a2ae3a5e3f99d8fb1abde0b237b114 Mon Sep 17 00:00:00 2001 From: hartytp Date: Sat, 24 Mar 2018 12:41:18 +0000 Subject: [PATCH 0555/2457] coredevice/zotino: add (#969) * Replace ad5360 driver with a ad53xx driver, designed to have a nicer interface Add Zotino driver and add to opticlock target for Kasli Test Zotino on hw: - Verify all timings on the hardware with a scope - Verify that we can correctly set and read back all registers in a loop (checks for SI and driver issues) - check we can set LEDs correctly - check calibration routine + all si unit functions with a good DVM - look at DAC transitions on a scope (while triggering of a TTL) on persist to check there are no LDAC glitches etc To do: update examples and e.g. KC705 device db. --- artiq/coredevice/ad5360.py | 190 ------------ artiq/coredevice/ad53xx.py | 328 ++++++++++++++++++++ artiq/coredevice/zotino.py | 53 ++++ artiq/examples/kasli_opticlock/device_db.py | 38 ++- 4 files changed, 410 insertions(+), 199 deletions(-) delete mode 100644 artiq/coredevice/ad5360.py create mode 100644 artiq/coredevice/ad53xx.py create mode 100644 artiq/coredevice/zotino.py diff --git a/artiq/coredevice/ad5360.py b/artiq/coredevice/ad5360.py deleted file mode 100644 index 3cff52d6c..000000000 --- a/artiq/coredevice/ad5360.py +++ /dev/null @@ -1,190 +0,0 @@ -""" -Driver for the AD5360 DAC on RTIO. - -Output event replacement is not supported and issuing commands at the same -time is an error. -""" - - -from artiq.language.core import (kernel, portable, delay_mu, delay, now_mu, - at_mu) -from artiq.language.units import ns, us -from artiq.coredevice import spi2 as spi - -# Designed from the data sheets and somewhat after the linux kernel -# iio driver. - -_AD5360_SPI_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_END | - 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | - 0*spi.SPI_CLK_POLARITY | 1*spi.SPI_CLK_PHASE | - 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) - -_AD5360_CMD_DATA = 3 << 22 -_AD5360_CMD_OFFSET = 2 << 22 -_AD5360_CMD_GAIN = 1 << 22 -_AD5360_CMD_SPECIAL = 0 << 22 - - -@portable -def _AD5360_WRITE_CHANNEL(c): - return (c + 8) << 16 - - -_AD5360_SPECIAL_NOP = 0 << 16 -_AD5360_SPECIAL_CONTROL = 1 << 16 -_AD5360_SPECIAL_OFS0 = 2 << 16 -_AD5360_SPECIAL_OFS1 = 3 << 16 -_AD5360_SPECIAL_READ = 5 << 16 - - -@portable -def _AD5360_READ_CHANNEL(ch): - return (ch + 8) << 7 - - -_AD5360_READ_X1A = 0x000 << 7 -_AD5360_READ_X1B = 0x040 << 7 -_AD5360_READ_OFFSET = 0x080 << 7 -_AD5360_READ_GAIN = 0x0c0 << 7 -_AD5360_READ_CONTROL = 0x101 << 7 -_AD5360_READ_OFS0 = 0x102 << 7 -_AD5360_READ_OFS1 = 0x103 << 7 - - -class AD5360: - """ - Support for the Analog devices AD53[67][0123] - multi-channel Digital to Analog Converters - - :param spi_device: Name of the SPI bus this device is on. - :param ldac_device: Name of the TTL device that LDAC is connected to - (optional). Needs to be explicitly initialized to high. - :param chip_select: Value to drive on the chip select lines - during transactions. - :param div_write: SPI clock divider during writes - :param div_read: SPI clock divider during reads - """ - kernel_invariants = {"bus", "core", "chip_select", "div_read", "div_write"} - - def __init__(self, dmgr, spi_device, ldac_device=None, chip_select=1, - div_write=4, div_read=7): - self.core = dmgr.get("core") - self.bus = dmgr.get(spi_device) - if ldac_device is not None: - self.ldac = dmgr.get(ldac_device) - self.chip_select = chip_select - # write: 2*8ns >= 10ns = t_6 (clk falling to cs_n rising) - # 4*8ns >= 20ns = t_1 (clk cycle time) - self.div_write = div_write - # read: 4*8*ns >= 25ns = t_22 (clk falling to miso valid) - self.div_read = div_read - - @kernel - def setup_bus(self): - """Configure the SPI bus and the SPI transaction parameters - for this device. This method has to be called before any other method - if the bus has been used to access a different device in the meantime. - - This method advances the timeline by one coarse RTIO cycle. - """ - self.bus.set_config_mu(_AD5360_SPI_CONFIG, 24, self.div_write, - self.chip_select) - - @kernel - def write(self, data): - """Write 24 bits of data. - - This method advances the timeline by the duration of the SPI transfer - and the required CS high time. - """ - self.bus.write(data << 8) - delay_mu(self.bus.ref_period_mu) # get to 20ns min cs high - - @kernel - def write_offsets(self, value=0x1fff): - """Write the OFS0 and OFS1 offset DACs. - - This method advances the timeline by twice the duration of - :meth:`write`. - - :param value: Value to set both offset registers to. - """ - value &= 0x3fff - self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_OFS0 | value) - self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_OFS1 | value) - - @kernel - def write_channel(self, channel=0, value=0, op=_AD5360_CMD_DATA): - """Write to a channel register. - - This method advances the timeline by the duration of :meth:`write`. - - :param channel: Channel number to write to. - :param value: 16 bit value to write to the register. - :param op: Operation to perform, one of :const:`_AD5360_CMD_DATA`, - :const:`_AD5360_CMD_OFFSET`, :const:`_AD5360_CMD_GAIN` - (default: :const:`_AD5360_CMD_DATA`). - """ - channel &= 0x3f - value &= 0xffff - self.write(op | _AD5360_WRITE_CHANNEL(channel) | value) - - @kernel - def read_channel_sync(self, channel=0, op=_AD5360_READ_X1A): - """Read a channel register. - - This method advances the timeline by the duration of two :meth:`write` - plus two coarse RTIO cycles. - - :param channel: Channel number to read from. - :param op: Operation to perform, one of :const:`_AD5360_READ_X1A`, - :const:`_AD5360_READ_X1B`, :const:`_AD5360_READ_OFFSET`, - :const:`_AD5360_READ_GAIN` (default: :const:`_AD5360_READ_X1A`). - :return: The 16 bit register value. - """ - channel &= 0x3f - self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_READ | op | - _AD5360_READ_CHANNEL(channel)) - self.bus.set_config_mu(_AD5360_SPI_CONFIG | spi.SPI_INPUT, 24, - self.div_read, self.chip_select) - delay(270*ns) # t_21 min sync high in readback - self.write(_AD5360_CMD_SPECIAL | _AD5360_SPECIAL_NOP) - self.bus.set_config_mu(_AD5360_SPI_CONFIG, 24, - self.div_write, self.chip_select) - return self.bus.read() & 0xffff - - @kernel - def load(self): - """Pulse the LDAC line. - - This method advances the timeline by two RTIO clock periods (16 ns). - """ - self.ldac.off() - # t13 = 10ns ldac pulse width low - delay_mu(2*self.bus.ref_period_mu) - self.ldac.on() - - @kernel - def set(self, values, op=_AD5360_CMD_DATA): - """Write to several channels and pulse LDAC to update the channels. - - This method does not advance the timeline. Write events are scheduled - in the past. The DACs will synchronously start changing their output - levels `now`. - - :param values: List of 16 bit values to write to the channels. - :param op: Operation to perform, one of :const:`_AD5360_CMD_DATA`, - :const:`_AD5360_CMD_OFFSET`, :const:`_AD5360_CMD_GAIN` - (default: :const:`_AD5360_CMD_DATA`). - """ - t0 = now_mu() - # t10 max busy low for one channel - t_10 = self.core.seconds_to_mu(1.5*us) - # compensate all delays that will be applied - delay_mu(-t_10-len(values)*( - self.bus.ref_period_mu + self.bus.xfer_duration_mu)) - for i in range(len(values)): - self.write_channel(i, values[i], op) - delay_mu(t_10) - self.load() - at_mu(t0) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py new file mode 100644 index 000000000..65443754d --- /dev/null +++ b/artiq/coredevice/ad53xx.py @@ -0,0 +1,328 @@ +""""RTIO driver for the Analog Devices AD53[67][0123] family of multi-channel +Digital to Analog Converters. + +Output event replacement is not supported and issuing commands at the same +time is an error. +""" + +# Designed from the data sheets and somewhat after the linux kernel +# iio driver. + +from artiq.language.core import (kernel, portable, delay_mu, delay, now_mu, + at_mu) +from artiq.language.units import ns +from artiq.coredevice import spi2 as spi + +SPI_AD53XX_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_END | + 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | + 0*spi.SPI_CLK_POLARITY | 1*spi.SPI_CLK_PHASE | + 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) + +AD53XX_CMD_DATA = 3 << 22 +AD53XX_CMD_OFFSET = 2 << 22 +AD53XX_CMD_GAIN = 1 << 22 +AD53XX_CMD_SPECIAL = 0 << 22 + +AD53XX_SPECIAL_NOP = 0 << 16 +AD53XX_SPECIAL_CONTROL = 1 << 16 +AD53XX_SPECIAL_OFS0 = 2 << 16 +AD53XX_SPECIAL_OFS1 = 3 << 16 +AD53XX_SPECIAL_READ = 5 << 16 + +AD53XX_READ_X1A = 0X000 << 7 +AD53XX_READ_X1B = 0X040 << 7 +AD53XX_READ_OFFSET = 0X080 << 7 +AD53XX_READ_GAIN = 0X0C0 << 7 +AD53XX_READ_CONTROL = 0X101 << 7 +AD53XX_READ_OFS0 = 0X102 << 7 +AD53XX_READ_OFS1 = 0X103 << 7 + + +@portable +def ad53xx_cmd_write_ch(channel, value, op): + """Returns the word that must be written to the DAC to set a DAC + channel register to a given value. + + :param channel: DAC channel to write to (8 bits) + :param value: 16-bit value to write to the register + :param op: The channel register to write to, one of + :const:`AD53XX_CMD_DATA`, :const:`AD53XX_CMD_OFFSET` or + :const:`AD53XX_CMD_GAIN`. + :return: The 24-bit word to be written to the DAC, aligned as the 24 MSB of + a 32-bit integer, ready to be transferred directly by the SPI core. + """ + return (op | ((channel & 0x3f) + 8) << 16 | (value & 0xffff)) << 8 + + +@portable +def ad53xx_cmd_read_ch(channel, op): + """Returns the word that must be written to the DAC to read a given + DAC channel register. + + :param channel: DAC channel to read (8 bits) + :param op: The channel register to read, one of + :const:`AD53XX_CMD_DATA`, :const:`AD53XX_CMD_OFFSET` or + :const:`AD53XX_CMD_GAIN` + :return: The 24-bit word to be written to the DAC, aligned as the 24 MSB of + a 32-bit integer, ready to be transferred directly by the SPI core. + """ + return (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_READ | op | + (((channel & 0x3f) + 8) << 7)) << 8 + + +@portable +def voltage_to_mu(voltage, offset_dacs=8192, vref=5.): + """Returns the DAC register value required to produce a given output + voltage, assuming offset and gain errors have been trimmed out. + + :param voltage: Voltage + :param offset_dacs: Register value for the two offset DACs (default + :0x1555) + :param vref: DAC reference voltage (default: 5.) + """ + return int(round(0x10000*(voltage/(4.*vref)) + offset_dacs*0x4)) + +@portable +def offset_to_mu(voltage, offset_dacs=8192, vref=5.): + """Returns the offset register value required to produce a given voltage + when the DAC register is set to mid-scale. + + An offset of V can be used to trim out a DAC offset error of -V. + + :param voltage: Offset voltage + :param offset_dacs: Register value for the two offset DACs (default + :0x1555) + :param vref: DAC reference voltage (default: 5.) + """ + return int(round(0x10000*(voltage/(4.*vref)) + offset_dacs*0x4)) + +class AD53xx: + """Analog devices AD53[67][0123] family of multi-channel Digital to Analog + Converters. + + :param spi_device: SPI bus device name + :param ldac_device: LDAC RTIO TTLOut channel name + :param clr_device: CLR RTIO TTLOut channel name + :param chip_select: Value to drive on SPI chip select lines during + transactions (default: 1) + :param div_write: SPI clock divider for write operations (default: 4, + 50MHz max SPI clock with {t_high, t_low} >=8ns) + :param div_read: SPI clock divider for read operations (default: 8, not + optimized for speed, but cf data sheet t22: 25ns min SCLK edge to SDO + valid) + :param vref: DAC reference voltage (default: 5.) + :param offset_dacs: Initial register value for the two offset DACs, device + dependent and must be set correctly for correct voltage to mu conversions + (default: 8192) + :param core_device: Core device name (default: "core") + """ + kernel_invariants = {"bus", "ldac", "clr", "chip_select", "div_write", + "div_read", "vref", "core"} + + def __init__(self, dmgr, spi_device, ldac_device, clr_device, + chip_select=1, div_write=4, div_read=8, vref=5., + offset_dacs=8192, core="core"): + self.bus = dmgr.get(spi_device) + self.ldac = dmgr.get(ldac_device) + self.clr = dmgr.get(clr_device) + self.chip_select = chip_select + self.div_write = div_write + self.div_read = div_read + self.vref = vref + self.offset_dacs = offset_dacs + self.core = dmgr.get(core) + + @kernel + def init(self): + """Configures the SPI bus, drives LDAC and CLR high and programmes + the offset DACss. + + This method must be called before any other method at start-up or if + the SPI bus has been accessed by another device. + This method advances the timeline by one coarse RTIO cycle. + """ + self.ldac.on() + self.clr.on() + self.bus.set_config_mu(SPI_AD53XX_CONFIG, 24, self.div_write, + self.chip_select) + self.write_offset_dacs_mu(self.offset_dacs) + + @kernel + def read_reg(self, channel=0, op=AD53XX_READ_X1A): + """Read a DAC register. + + This method advances the timeline by the duration of two SPI transfers + plus two RTIO coarse cycles. + + :param channel: Channel number to read from (default :0) + :param op: Operation to perform, one of :const:`AD53XX_READ_X1A`, + :const:`AD53XX_READ_X1B`, :const:`AD53XX_READ_OFFSET`, + :const:`AD53XX_READ_GAIN` (default: :const:`AD53XX_READ_X1A`). + :return: The 16 bit register value + """ + self.bus.write(ad53xx_cmd_read_ch(channel, op)) + self.bus.set_config_mu(SPI_AD53XX_CONFIG | spi.SPI_INPUT, 24, + self.div_read, self.chip_select) + delay(270*ns) # t_21 min sync high in readback + self.bus.write((AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_NOP) << 8) + + self.bus.set_config_mu(SPI_AD53XX_CONFIG, 24, self.div_write, + self.chip_select) + return self.bus.read() + + @kernel + def write_offset_dacs_mu(self, value): + """Program the OFS0 and OFS1 offset DAC registers. + + Writes to the offset DACs take effect immediately without requiring + a LDAC. This method advances the timeline by the duration of two SPI + transfers. + + :param value: Value to set both offset DAC registers to + """ + value &= 0x3fff + self.offset_dacs = value + self.bus.write((AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_OFS0 | value) << 8) + self.bus.write((AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_OFS1 | value) << 8) + + @kernel + def write_gain_mu(self, channel, gain=0xffff): + """Program the gain register for a DAC channel. + + The DAC output is not updated until LDAC is pulsed (see :meth load:). + This method advances the timeline by the duration of one SPI transfer. + + :param gain: 16-bit gain register value (default: 0xffff) + """ + self.bus.write(ad53xx_cmd_write_ch(channel, gain, AD53XX_CMD_GAIN)) + + @kernel + def write_offset_mu(self, channel, offset=0x8000): + """Program the offset register for a DAC channel. + + The DAC output is not updated until LDAC is pulsed (see :meth load:). + This method advances the timeline by the duration of one SPI transfer. + + :param offset: 16-bit offset register value (default: 0x8000) + """ + self.bus.write(ad53xx_cmd_write_ch(channel, offset, AD53XX_CMD_OFFSET)) + + @kernel + def write_offset(self, channel, voltage): + """Program the DAC offset voltage for a channel. + + An offset of +V can be used to trim out a DAC offset error of -V. + The DAC output is not updated until LDAC is pulsed (see :meth load:). + This method advances the timeline by the duration of one SPI transfer. + + :param voltage: the offset voltage + """ + self.write_offset_mu(channel, offset_to_mu(voltage, self.offset_dacs, + self.vref)) + + @kernel + def write_dac_mu(self, channel, value): + """Program the DAC input register for a channel. + + The DAC output is not updated until LDAC is pulsed (see :meth load:). + This method advances the timeline by the duration of one SPI transfer. + """ + self.bus.write(ad53xx_cmd_write_ch(channel, value, AD53XX_CMD_DATA)) + + @kernel + def write_dac(self, channel, voltage): + """Program the DAC output voltage for a channel. + + The DAC output is not updated until LDAC is pulsed (see :meth load:). + This method advances the timeline by the duration of one SPI transfer. + """ + self.write_dac_mu(channel, voltage_to_mu(voltage, self.offset_dacs, + self.vref)) + + @kernel + def load(self): + """Pulse the LDAC line. + + Note that there is a <= 1.5us "BUSY" period (t10) after writing to a + DAC input/gain/offset register. All DAC registers may be programmed + normally during the busy period, however LDACs during the busy period + cause the DAC output to change *after* the BUSY period has completed, + instead of the usual immediate update on LDAC behaviour. + + This method advances the timeline by two RTIO clock periods. + """ + self.ldac.off() + delay_mu(2*self.bus.ref_period_mu) # t13 = 10ns ldac pulse width low + self.ldac.on() + + @kernel + def set_dac_mu(self, values, channels=list(range(40))): + """Program multiple DAC channels and pulse LDAC to update the DAC + outputs. + + This method does not advance the timeline; write events are scheduled + in the past. The DACs will synchronously start changing their output + levels `now`. + + See :meth load:. + + :param values: list of DAC values to program + :param channels: list of DAC channels to program. If not specified, + we program the DAC channels sequentially, starting at 0. + """ + t0 = now_mu() + + # t10: max busy period after writing to DAC registers + t_10 = self.core.seconds_to_mu(1500*ns) + # compensate all delays that will be applied + delay_mu(-t_10-len(values)*self.bus.xfer_duration_mu) + for i in range(len(values)): + self.write_dac_mu(channels[i], values[i]) + delay_mu(t_10) + self.load() + at_mu(t0) + + @kernel + def set_dac(self, voltages, channels=list(range(40))): + """Program multiple DAC channels and pulse LDAC to update the DAC + outputs. + + This method does not advance the timeline; write events are scheduled + in the past. The DACs will synchronously start changing their output + levels `now`. + + :param voltages: list of voltages to program the DAC channels to + :param channels: list of DAC channels to program. If not specified, + we program the DAC channels sequentially, starting at 0. + """ + values = [voltage_to_mu(voltage, self.offset_dacs, self.vref) + for voltage in voltages] + self.set_dac_mu(values, channels) + + @kernel + def calibrate(self, channel, vzs, vfs): + """ Two-point calibration of a DAC channel. + + Programs the offset and gain register to trim out DAC errors. Does not + take effect until LDAC is pulsed (see :meth load:). + + Calibration consists of measuring the DAC output voltage for a channel + with the DAC set to zero-scale (0x0000) and full-scale (0xffff). + + Note that only negative offsets and full-scale errors (DAC gain too + high) can be calibrated in this fashion. + + :param channel: The number of the calibrated channel + :params vzs: Measured voltage with the DAC set to zero-scale (0x0000) + :params vfs: Measured voltage with the DAC set to full-scale (0xffff) + """ + offset_err = voltage_to_mu(vzs, self.offset_dacs, self.vref) + gain_err = voltage_to_mu(vfs, self.offset_dacs, self.vref) - ( + offset_err + 0xffff) + + assert offset_err <= 0 + assert gain_err >= 0 + + self.core.break_realtime() + self.write_offset_mu(channel, 0x8000-offset_err) + self.write_gain_mu(channel, 0xffff-gain_err) diff --git a/artiq/coredevice/zotino.py b/artiq/coredevice/zotino.py new file mode 100644 index 000000000..dfb5096e1 --- /dev/null +++ b/artiq/coredevice/zotino.py @@ -0,0 +1,53 @@ +"""RTIO driver for the Zotino 32-channel, 16-bit 1MSPS DAC. + +Output event replacement is not supported and issuing commands at the same +time is an error. +""" + +from artiq.language.core import kernel +from artiq.coredevice import spi2 as spi +from artiq.coredevice.ad53xx import SPI_AD53XX_CONFIG, AD53xx + +_SPI_DAC_CONFIG = SPI_AD53XX_CONFIG +_SPI_SR_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_END | + 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | + 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | + 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) + +_SPI_CS_DAC = 1 +_SPI_CS_SR = 2 + +class Zotino(AD53xx): + """ Zotino 32-channel, 16-bit 1MSPS DAC. + + Controls the AD5372 DAC and the 8 user LEDs via a shared SPI interface. + + :param spi_device: SPI bus device name + :param ldac_device: LDAC RTIO TTLOut channel name. + :param clr_device: CLR RTIO TTLOut channel name. + :param div_write: SPI clock divider for write operations (default: 4, + 50MHz max SPI clock) + :param div_read: SPI clock divider for read operations (default: 8, not + optimized for speed, but cf data sheet t22: 25ns min SCLK edge to SDO + valid) + :param vref: DAC reference voltage (default: 5.) + :param core_device: Core device name (default: "core") + """ + + def __init__(self, dmgr, spi_device, ldac_device, clr_device, + div_write=4, div_read=8, vref=5., core="core"): + AD53xx.__init__(self, dmgr=dmgr, spi_device=spi_device, + ldac_device=ldac_device, clr_device=clr_device, + chip_select=_SPI_CS_DAC, div_write=div_write, + div_read=div_read, core=core) + + @ kernel + def set_leds(self, leds): + """ Sets the states of the 8 user LEDs. + + :param leds: 8-bit word with LED state + """ + self.bus.set_config_mu(_SPI_SR_CONFIG, 8, self.div_write, _SPI_CS_SR) + self.bus.write(leds << 24) + self.bus.set_config_mu(_SPI_DAC_CONFIG, 24, self.div_write, + _SPI_CS_DAC) diff --git a/artiq/examples/kasli_opticlock/device_db.py b/artiq/examples/kasli_opticlock/device_db.py index 3ee94fb2e..a64c28a36 100644 --- a/artiq/examples/kasli_opticlock/device_db.py +++ b/artiq/examples/kasli_opticlock/device_db.py @@ -198,15 +198,6 @@ device_db = { "class": "TTLOut", "arguments": {"channel": 25} }, - "novogorny0" : { - "type": "local", - "module": "artiq.coredevice.novogorny", - "class": "Novogorny", - "arguments": { - "spi_device": "spi_novogorny0", - "cnv_device": "ttl_novogorny0_cnv", - } - }, "spi_urukul0": { "type": "local", @@ -311,5 +302,34 @@ device_db = { "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 33} + }, + + "spi_zotino0": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 36} + }, + "ttl_zotino0_ldac": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 37} + }, + "ttl_zotino0_clr": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 38} + }, + "zotino0": { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino0", + "ldac_device": "ttl_zotino0_ldac", + "clr_device": "ttl_zotino0_clr" + } } } From 68e433a3a8c7424233b7c1e19309f266d0537097 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 24 Mar 2018 13:46:45 +0100 Subject: [PATCH 0556/2457] opticlock/device_db: resurrect novogorny deleted in a992a67 --- artiq/examples/kasli_opticlock/device_db.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/artiq/examples/kasli_opticlock/device_db.py b/artiq/examples/kasli_opticlock/device_db.py index a64c28a36..0da3c204d 100644 --- a/artiq/examples/kasli_opticlock/device_db.py +++ b/artiq/examples/kasli_opticlock/device_db.py @@ -198,6 +198,15 @@ device_db = { "class": "TTLOut", "arguments": {"channel": 25} }, + "novogorny0" : { + "type": "local", + "module": "artiq.coredevice.novogorny", + "class": "Novogorny", + "arguments": { + "spi_device": "spi_novogorny0", + "cnv_device": "ttl_novogorny0_cnv", + } + }, "spi_urukul0": { "type": "local", From 08326c5727f66fbdbabe971d25be593323dd931f Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 24 Mar 2018 14:10:20 +0100 Subject: [PATCH 0557/2457] ad53xx: style [nfc] --- artiq/coredevice/ad53xx.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 65443754d..05ea36109 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -13,6 +13,7 @@ from artiq.language.core import (kernel, portable, delay_mu, delay, now_mu, from artiq.language.units import ns from artiq.coredevice import spi2 as spi + SPI_AD53XX_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_END | 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | 0*spi.SPI_CLK_POLARITY | 1*spi.SPI_CLK_PHASE | @@ -67,7 +68,7 @@ def ad53xx_cmd_read_ch(channel, op): a 32-bit integer, ready to be transferred directly by the SPI core. """ return (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_READ | op | - (((channel & 0x3f) + 8) << 7)) << 8 + (((channel & 0x3f) + 8) << 7)) << 8 @portable @@ -82,6 +83,7 @@ def voltage_to_mu(voltage, offset_dacs=8192, vref=5.): """ return int(round(0x10000*(voltage/(4.*vref)) + offset_dacs*0x4)) + @portable def offset_to_mu(voltage, offset_dacs=8192, vref=5.): """Returns the offset register value required to produce a given voltage @@ -96,6 +98,7 @@ def offset_to_mu(voltage, offset_dacs=8192, vref=5.): """ return int(round(0x10000*(voltage/(4.*vref)) + offset_dacs*0x4)) + class AD53xx: """Analog devices AD53[67][0123] family of multi-channel Digital to Analog Converters. @@ -252,7 +255,7 @@ class AD53xx: This method advances the timeline by two RTIO clock periods. """ self.ldac.off() - delay_mu(2*self.bus.ref_period_mu) # t13 = 10ns ldac pulse width low + delay_mu(2*self.bus.ref_period_mu) # t13 = 10ns ldac pulse width low self.ldac.on() @kernel From 2cf414a4803d4559e78f939829fa5ade4985933d Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 24 Mar 2018 15:15:56 +0100 Subject: [PATCH 0558/2457] ad53xx: move 8 bit shift out of ad53xx protocol funcs That's specific to the SPI bus, not to the ad53xx. --- artiq/coredevice/ad53xx.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 05ea36109..063a149c9 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -49,10 +49,9 @@ def ad53xx_cmd_write_ch(channel, value, op): :param op: The channel register to write to, one of :const:`AD53XX_CMD_DATA`, :const:`AD53XX_CMD_OFFSET` or :const:`AD53XX_CMD_GAIN`. - :return: The 24-bit word to be written to the DAC, aligned as the 24 MSB of - a 32-bit integer, ready to be transferred directly by the SPI core. + :return: The 24-bit word to be written to the DAC """ - return (op | ((channel & 0x3f) + 8) << 16 | (value & 0xffff)) << 8 + return op | ((channel & 0x3f) + 8) << 16 | (value & 0xffff) @portable @@ -64,11 +63,10 @@ def ad53xx_cmd_read_ch(channel, op): :param op: The channel register to read, one of :const:`AD53XX_CMD_DATA`, :const:`AD53XX_CMD_OFFSET` or :const:`AD53XX_CMD_GAIN` - :return: The 24-bit word to be written to the DAC, aligned as the 24 MSB of - a 32-bit integer, ready to be transferred directly by the SPI core. + :return: The 24-bit word to be written to the DAC """ return (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_READ | op | - (((channel & 0x3f) + 8) << 7)) << 8 + (((channel & 0x3f) + 8) << 7)) @portable @@ -163,7 +161,7 @@ class AD53xx: :const:`AD53XX_READ_GAIN` (default: :const:`AD53XX_READ_X1A`). :return: The 16 bit register value """ - self.bus.write(ad53xx_cmd_read_ch(channel, op)) + self.bus.write(ad53xx_cmd_read_ch(channel, op) << 8) self.bus.set_config_mu(SPI_AD53XX_CONFIG | spi.SPI_INPUT, 24, self.div_read, self.chip_select) delay(270*ns) # t_21 min sync high in readback @@ -197,7 +195,8 @@ class AD53xx: :param gain: 16-bit gain register value (default: 0xffff) """ - self.bus.write(ad53xx_cmd_write_ch(channel, gain, AD53XX_CMD_GAIN)) + self.bus.write( + ad53xx_cmd_write_ch(channel, gain, AD53XX_CMD_GAIN) << 8) @kernel def write_offset_mu(self, channel, offset=0x8000): @@ -208,7 +207,8 @@ class AD53xx: :param offset: 16-bit offset register value (default: 0x8000) """ - self.bus.write(ad53xx_cmd_write_ch(channel, offset, AD53XX_CMD_OFFSET)) + self.bus.write( + ad53xx_cmd_write_ch(channel, offset, AD53XX_CMD_OFFSET) << 8) @kernel def write_offset(self, channel, voltage): @@ -230,7 +230,8 @@ class AD53xx: The DAC output is not updated until LDAC is pulsed (see :meth load:). This method advances the timeline by the duration of one SPI transfer. """ - self.bus.write(ad53xx_cmd_write_ch(channel, value, AD53XX_CMD_DATA)) + self.bus.write( + ad53xx_cmd_write_ch(channel, value, AD53XX_CMD_DATA) << 8) @kernel def write_dac(self, channel, voltage): From 9bc2ce84fc8b9bc3daae0ed164765ee3cd2e75e5 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 24 Mar 2018 15:18:08 +0100 Subject: [PATCH 0559/2457] doc: ad5360 -> ad53xx, add zotino --- doc/manual/core_drivers_reference.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 08633b7c6..8732d94f6 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -109,10 +109,16 @@ RF generation drivers DAC/ADC drivers --------------- -:mod:`artiq.coredevice.ad5360` module +:mod:`artiq.coredevice.ad53xx` module +++++++++++++++++++++++++++++++++++++ -.. automodule:: artiq.coredevice.ad5360 +.. automodule:: artiq.coredevice.ad53xx + :members: + +:mod:`artiq.coredevice.zotino` module ++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.zotino :members: :mod:`artiq.coredevice.sampler` module From 22557294ac956f40b78dd34f86f60a486574d4bb Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 24 Mar 2018 15:20:04 +0100 Subject: [PATCH 0560/2457] RELEASE_NOTES: ad53xx, zotino --- RELEASE_NOTES.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 89a507a52..26b611e27 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -26,9 +26,10 @@ ARTIQ-4 * the ``-H/--hw-adapter`` option of ``kc705`` has ben renamed ``-V/--variant``. * SPI masters have been switched from misoc-spi to misoc-spi2. This affects all out-of-tree RTIO core device drivers using those buses. See the various - commits on e.g. the ``ad5360`` driver for an example how to port from the old + commits on e.g. the ``ad53xx`` driver for an example how to port from the old to the new bus. - +* The ``ad5360`` coredevice driver has been renamed to ``ad53xx`` and the API + has changed to better support Zotino. ARTIQ-3 ------- From 77bcc2c78f41bf481ca0acfe763e4579f5e618bf Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 24 Mar 2018 15:37:34 +0100 Subject: [PATCH 0561/2457] zotino: style, use attributes to set SPI config --- artiq/coredevice/ad53xx.py | 1 - artiq/coredevice/zotino.py | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 063a149c9..90d62c6d1 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -13,7 +13,6 @@ from artiq.language.core import (kernel, portable, delay_mu, delay, now_mu, from artiq.language.units import ns from artiq.coredevice import spi2 as spi - SPI_AD53XX_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_END | 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | 0*spi.SPI_CLK_POLARITY | 1*spi.SPI_CLK_PHASE | diff --git a/artiq/coredevice/zotino.py b/artiq/coredevice/zotino.py index dfb5096e1..19eeca6c2 100644 --- a/artiq/coredevice/zotino.py +++ b/artiq/coredevice/zotino.py @@ -8,7 +8,6 @@ from artiq.language.core import kernel from artiq.coredevice import spi2 as spi from artiq.coredevice.ad53xx import SPI_AD53XX_CONFIG, AD53xx -_SPI_DAC_CONFIG = SPI_AD53XX_CONFIG _SPI_SR_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_END | 0*spi.SPI_INPUT | 0*spi.SPI_CS_POLARITY | 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | @@ -17,6 +16,7 @@ _SPI_SR_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_END | _SPI_CS_DAC = 1 _SPI_CS_SR = 2 + class Zotino(AD53xx): """ Zotino 32-channel, 16-bit 1MSPS DAC. @@ -41,7 +41,7 @@ class Zotino(AD53xx): chip_select=_SPI_CS_DAC, div_write=div_write, div_read=div_read, core=core) - @ kernel + @kernel def set_leds(self, leds): """ Sets the states of the 8 user LEDs. @@ -49,5 +49,5 @@ class Zotino(AD53xx): """ self.bus.set_config_mu(_SPI_SR_CONFIG, 8, self.div_write, _SPI_CS_SR) self.bus.write(leds << 24) - self.bus.set_config_mu(_SPI_DAC_CONFIG, 24, self.div_write, - _SPI_CS_DAC) + self.bus.set_config_mu(SPI_AD53XX_CONFIG, 24, self.div_write, + self.chip_select) From b0c80970257911ea65f0776ba22dd9f82d98fe7a Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 24 Mar 2018 15:39:06 +0100 Subject: [PATCH 0562/2457] ad53xx: remove channel index AND It's incorrect since it doesn't respect the number of channels of any of those chips (none has 64 channels). --- artiq/coredevice/ad53xx.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 90d62c6d1..a07c28794 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -50,7 +50,7 @@ def ad53xx_cmd_write_ch(channel, value, op): :const:`AD53XX_CMD_GAIN`. :return: The 24-bit word to be written to the DAC """ - return op | ((channel & 0x3f) + 8) << 16 | (value & 0xffff) + return op | (channel + 8) << 16 | (value & 0xffff) @portable @@ -65,7 +65,7 @@ def ad53xx_cmd_read_ch(channel, op): :return: The 24-bit word to be written to the DAC """ return (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_READ | op | - (((channel & 0x3f) + 8) << 7)) + ((channel + 8) << 7)) @portable From a8f0ee1c86534839e32c6cbc72bdf4f580e752d0 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 24 Mar 2018 15:45:42 +0100 Subject: [PATCH 0563/2457] ad53xx: refactor offset_to_mu(), fix docs --- artiq/coredevice/ad53xx.py | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index a07c28794..b3393c0eb 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -69,28 +69,17 @@ def ad53xx_cmd_read_ch(channel, op): @portable -def voltage_to_mu(voltage, offset_dacs=8192, vref=5.): +def voltage_to_mu(voltage, offset_dacs=0x2000, vref=5.): """Returns the DAC register value required to produce a given output voltage, assuming offset and gain errors have been trimmed out. - :param voltage: Voltage - :param offset_dacs: Register value for the two offset DACs (default - :0x1555) - :param vref: DAC reference voltage (default: 5.) - """ - return int(round(0x10000*(voltage/(4.*vref)) + offset_dacs*0x4)) - - -@portable -def offset_to_mu(voltage, offset_dacs=8192, vref=5.): - """Returns the offset register value required to produce a given voltage - when the DAC register is set to mid-scale. - + Also used to return offset register value required to produce a given + voltage when the DAC register is set to mid-scale. An offset of V can be used to trim out a DAC offset error of -V. - :param voltage: Offset voltage - :param offset_dacs: Register value for the two offset DACs (default - :0x1555) + :param voltage: Voltage + :param offset_dacs: Register value for the two offset DACs + (default: 0x2000) :param vref: DAC reference voltage (default: 5.) """ return int(round(0x10000*(voltage/(4.*vref)) + offset_dacs*0x4)) @@ -219,8 +208,8 @@ class AD53xx: :param voltage: the offset voltage """ - self.write_offset_mu(channel, offset_to_mu(voltage, self.offset_dacs, - self.vref)) + self.write_offset_mu(channel, voltage_to_mu(voltage, self.offset_dacs, + self.vref)) @kernel def write_dac_mu(self, channel, value): From 3a0dfb7fdcf415e32950c4ef2bf3b6e6080ee12e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 24 Mar 2018 16:04:02 +0100 Subject: [PATCH 0564/2457] ad53xx: port monitor, moninj dashboard, kc705 target --- artiq/dashboard/moninj.py | 4 ++-- .../rtio/phy/{ad5360_monitor.py => ad53xx_monitor.py} | 10 ++++++---- artiq/gateware/targets/kc705.py | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) rename artiq/gateware/rtio/phy/{ad5360_monitor.py => ad53xx_monitor.py} (83%) diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py index e34679c34..0225690ed 100644 --- a/artiq/dashboard/moninj.py +++ b/artiq/dashboard/moninj.py @@ -224,8 +224,8 @@ def setup_from_ddb(ddb): channel = v["arguments"]["channel"] widget = _WidgetDesc(k, comment, _DDSWidget, (bus_channel, channel, k)) description.add(widget) - elif (v["module"] == "artiq.coredevice.ad5360" - and v["class"] == "AD5360"): + elif (v["module"] == "artiq.coredevice.ad53xx" + and v["class"] == "AD53XX"): spi_device = v["arguments"]["spi_device"] spi_device = ddb[spi_device] while isinstance(spi_device, str): diff --git a/artiq/gateware/rtio/phy/ad5360_monitor.py b/artiq/gateware/rtio/phy/ad53xx_monitor.py similarity index 83% rename from artiq/gateware/rtio/phy/ad5360_monitor.py rename to artiq/gateware/rtio/phy/ad53xx_monitor.py index c112d6649..267649734 100644 --- a/artiq/gateware/rtio/phy/ad5360_monitor.py +++ b/artiq/gateware/rtio/phy/ad53xx_monitor.py @@ -1,10 +1,10 @@ from migen import * from artiq.coredevice.spi2 import SPI_CONFIG_ADDR, SPI_DATA_ADDR -from artiq.coredevice.ad5360 import _AD5360_CMD_DATA, _AD5360_WRITE_CHANNEL +from artiq.coredevice.ad53xx import AD53XX_CMD_DATA, ad53xx_cmd_write_ch -class AD5360Monitor(Module): +class AD53XXMonitor(Module): def __init__(self, spi_rtlink, ldac_rtlink=None, cs_no=0, cs_onehot=False, nchannels=32): self.probes = [Signal(16) for i in range(nchannels)] @@ -39,8 +39,10 @@ class AD5360Monitor(Module): ) ] - writes = {(_AD5360_CMD_DATA | _AD5360_WRITE_CHANNEL(i)) >> 16: t.eq(spi_oif.data[8:24]) - for i, t in enumerate(write_targets)} + writes = { + ad53xx_cmd_write_ch(channel=i, value=0, op=AD53XX_CMD_DATA) >> 16: + t.eq(spi_oif.data[8:24]) + for i, t in enumerate(write_targets)} self.sync.rio_phy += [ If(spi_oif.stb & (spi_oif.address == SPI_DATA_ADDR), Case(spi_oif.data[24:], writes) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index fcf52d055..f29828415 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -17,7 +17,7 @@ from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio, nist_clock, nist_qc2 from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series, - dds, spi2, ad5360_monitor) + dds, spi2, ad53xx_monitor) from artiq.build_soc import build_artiq_soc from artiq import __version__ as artiq_version @@ -351,7 +351,7 @@ class NIST_CLOCK(_StandaloneBase): self.submodules += ldac_phy rtio_channels.append(rtio.Channel.from_phy(ldac_phy)) - dac_monitor = ad5360_monitor.AD5360Monitor(sdac_phy.rtlink, ldac_phy.rtlink) + dac_monitor = ad53xx_monitor.AD53XXMonitor(sdac_phy.rtlink, ldac_phy.rtlink) self.submodules += dac_monitor sdac_phy.probes.extend(dac_monitor.probes) From 0505e9124f622e5d3e66dcfdecfc3d6a92b7f647 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 24 Mar 2018 16:05:26 +0100 Subject: [PATCH 0565/2457] kc705: port device_db, ad53xx/zotino example --- artiq/examples/kc705_nist_clock/device_db.py | 4 ++-- .../kc705_nist_clock/repository/{ad5360.py => ad53xx.py} | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) rename artiq/examples/kc705_nist_clock/repository/{ad5360.py => ad53xx.py} (80%) diff --git a/artiq/examples/kc705_nist_clock/device_db.py b/artiq/examples/kc705_nist_clock/device_db.py index 24958a56d..b51a330c9 100644 --- a/artiq/examples/kc705_nist_clock/device_db.py +++ b/artiq/examples/kc705_nist_clock/device_db.py @@ -185,8 +185,8 @@ device_db = { }, "dac_zotino": { "type": "local", - "module": "artiq.coredevice.ad5360", - "class": "AD5360", + "module": "artiq.coredevice.zotino", + "class": "Zotino", "arguments": { "spi_device": "spi_zotino", "ldac_device": "ttl_zotino_ldac", diff --git a/artiq/examples/kc705_nist_clock/repository/ad5360.py b/artiq/examples/kc705_nist_clock/repository/ad53xx.py similarity index 80% rename from artiq/examples/kc705_nist_clock/repository/ad5360.py rename to artiq/examples/kc705_nist_clock/repository/ad53xx.py index 88ba87631..f10bde057 100644 --- a/artiq/examples/kc705_nist_clock/repository/ad5360.py +++ b/artiq/examples/kc705_nist_clock/repository/ad53xx.py @@ -1,7 +1,7 @@ from artiq.experiment import * -class AD5360Test(EnvExperiment): +class AD53XXTest(EnvExperiment): def build(self): self.setattr_device("core") self.setattr_device("fmcdio_dirctl") @@ -14,8 +14,7 @@ class AD5360Test(EnvExperiment): delay(5*ms) # build slack for shift register set self.fmcdio_dirctl.set(self, 0x00008800) self.dac.setup_bus() - self.dac.write_offsets() self.led.on() delay(400*us) self.led.off() - self.dac.set([i << 10 for i in range(32)]) + self.dac.set_dac_mu([i << 10 for i in range(32)]) From 774030698e0e65ee269e735f51005af24b1f3c6d Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 24 Mar 2018 16:07:53 +0100 Subject: [PATCH 0566/2457] doc: title underline --- doc/manual/core_drivers_reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 8732d94f6..bdfd93519 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -42,7 +42,7 @@ Digital I/O drivers :members: :mod:`artiq.coredevice.shiftreg` module -++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++ .. automodule:: artiq.coredevice.shiftreg :members: From a20dfd9c001c97ebd2add65b766ed3f1aa62350f Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 24 Mar 2018 16:46:59 +0100 Subject: [PATCH 0567/2457] examples/master: ad5360 -> zotino --- artiq/examples/master/device_db.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/examples/master/device_db.py b/artiq/examples/master/device_db.py index 268a84159..9150e2b0a 100644 --- a/artiq/examples/master/device_db.py +++ b/artiq/examples/master/device_db.py @@ -186,8 +186,8 @@ device_db = { }, "dac_zotino": { "type": "local", - "module": "artiq.coredevice.ad5360", - "class": "AD5360", + "module": "artiq.coredevice.zotino", + "class": "Zotino", "arguments": { "spi_device": "spi_zotino", "ldac_device": "ttl_zotino_ldac", From d6a63ad165fe9d70bc5232a13b6c85d9788f513b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 25 Mar 2018 11:19:25 +0800 Subject: [PATCH 0568/2457] RELEASE_NOTES: formatting --- RELEASE_NOTES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 26b611e27..536840335 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -31,6 +31,7 @@ ARTIQ-4 * The ``ad5360`` coredevice driver has been renamed to ``ad53xx`` and the API has changed to better support Zotino. + ARTIQ-3 ------- From c3f763e217293600532bcce73a323ca926643aec Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 25 Mar 2018 11:19:40 +0800 Subject: [PATCH 0569/2457] dashboard: also create monitoring widgets for the Zotino class --- artiq/dashboard/moninj.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py index 0225690ed..476be6b6a 100644 --- a/artiq/dashboard/moninj.py +++ b/artiq/dashboard/moninj.py @@ -224,8 +224,8 @@ def setup_from_ddb(ddb): channel = v["arguments"]["channel"] widget = _WidgetDesc(k, comment, _DDSWidget, (bus_channel, channel, k)) description.add(widget) - elif (v["module"] == "artiq.coredevice.ad53xx" - and v["class"] == "AD53XX"): + elif ( (v["module"] == "artiq.coredevice.ad53xx" and v["class"] == "AD53XX") + or (v["module"] == "artiq.coredevice.zotino" and v["class"] == "Zotino")): spi_device = v["arguments"]["spi_device"] spi_device = ddb[spi_device] while isinstance(spi_device, str): From 8d62ea228856f283580323276bd5e30dca53fd01 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 25 Mar 2018 11:19:54 +0800 Subject: [PATCH 0570/2457] examples: fix KC705 ad53xx --- artiq/examples/kc705_nist_clock/repository/ad53xx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/kc705_nist_clock/repository/ad53xx.py b/artiq/examples/kc705_nist_clock/repository/ad53xx.py index f10bde057..87da4cd3f 100644 --- a/artiq/examples/kc705_nist_clock/repository/ad53xx.py +++ b/artiq/examples/kc705_nist_clock/repository/ad53xx.py @@ -12,7 +12,7 @@ class AD53XXTest(EnvExperiment): def run(self): self.core.reset() delay(5*ms) # build slack for shift register set - self.fmcdio_dirctl.set(self, 0x00008800) + self.fmcdio_dirctl.set(0x00008800) self.dac.setup_bus() self.led.on() delay(400*us) From 87c2f119a5d7307118137d1d8205426e8c89b872 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 25 Mar 2018 20:28:48 +0000 Subject: [PATCH 0571/2457] artiq_devtool: add load action. --- artiq/frontend/artiq_devtool.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 3bc6d5047..a17c29b26 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -65,7 +65,7 @@ def get_argparser(): parser.add_argument("actions", metavar="ACTION", type=str, default=[], nargs="+", help="actions to perform, sequence of: " - "build clean reset flash flash+log connect hotswap") + "build clean reset flash flash+log load connect hotswap") return parser @@ -199,6 +199,10 @@ def main(): flash("start") client.drain(flterm) + elif action == "load": + logger.info("Loading gateware") + flash("load") + elif action == "connect": lock() From 4804cfef9b39e60948aec94ff70d43332de7006d Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 26 Mar 2018 03:26:25 +0000 Subject: [PATCH 0572/2457] gateware: don't run tests if there is no migen. This allows us to skip testing gateware on Windows. --- artiq/gateware/test/__init__.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/artiq/gateware/test/__init__.py b/artiq/gateware/test/__init__.py index e69de29bb..a3ab498e1 100644 --- a/artiq/gateware/test/__init__.py +++ b/artiq/gateware/test/__init__.py @@ -0,0 +1,7 @@ +import unittest + +try: + import migen +except ImportError: + def load_tests(*args, **kwargs): + raise unittest.SkipTest("migen unavailable") From bab6723ff21c1455c23fbf84aa1a2538d1eb3b86 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 26 Mar 2018 03:33:52 +0000 Subject: [PATCH 0573/2457] Revert "gateware: don't run tests if there is no migen." This reverts commit 4804cfef9b39e60948aec94ff70d43332de7006d. --- artiq/gateware/test/__init__.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/artiq/gateware/test/__init__.py b/artiq/gateware/test/__init__.py index a3ab498e1..e69de29bb 100644 --- a/artiq/gateware/test/__init__.py +++ b/artiq/gateware/test/__init__.py @@ -1,7 +0,0 @@ -import unittest - -try: - import migen -except ImportError: - def load_tests(*args, **kwargs): - raise unittest.SkipTest("migen unavailable") From 5ca59467fdfca01e3b0754b1cc6a1d7fbf6ec036 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 26 Mar 2018 22:45:01 +0800 Subject: [PATCH 0574/2457] ad53xx: make LDAC and CLR optional --- artiq/coredevice/ad53xx.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index b3393c0eb..fa41f7d9d 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -85,13 +85,23 @@ def voltage_to_mu(voltage, offset_dacs=0x2000, vref=5.): return int(round(0x10000*(voltage/(4.*vref)) + offset_dacs*0x4)) +class _DummyTTL: + @portable + def on(self): + pass + + @portable + def off(self): + pass + + class AD53xx: """Analog devices AD53[67][0123] family of multi-channel Digital to Analog Converters. :param spi_device: SPI bus device name - :param ldac_device: LDAC RTIO TTLOut channel name - :param clr_device: CLR RTIO TTLOut channel name + :param ldac_device: LDAC RTIO TTLOut channel name (optional) + :param clr_device: CLR RTIO TTLOut channel name (optional) :param chip_select: Value to drive on SPI chip select lines during transactions (default: 1) :param div_write: SPI clock divider for write operations (default: 4, @@ -108,12 +118,18 @@ class AD53xx: kernel_invariants = {"bus", "ldac", "clr", "chip_select", "div_write", "div_read", "vref", "core"} - def __init__(self, dmgr, spi_device, ldac_device, clr_device, + def __init__(self, dmgr, spi_device, ldac_device=None, clr_device=None, chip_select=1, div_write=4, div_read=8, vref=5., offset_dacs=8192, core="core"): self.bus = dmgr.get(spi_device) - self.ldac = dmgr.get(ldac_device) - self.clr = dmgr.get(clr_device) + if ldac_device is None: + self.ldac = _DummyTTL() + else: + self.ldac = dmgr.get(ldac_device) + if clr_device is None: + self.clr = _DummyTTL() + else: + self.clr = dmgr.get(clr_device) self.chip_select = chip_select self.div_write = div_write self.div_read = div_read @@ -256,6 +272,8 @@ class AD53xx: in the past. The DACs will synchronously start changing their output levels `now`. + If no LDAC device was defined, the LDAC pulse is skipped. + See :meth load:. :param values: list of DAC values to program @@ -283,6 +301,8 @@ class AD53xx: in the past. The DACs will synchronously start changing their output levels `now`. + If no LDAC device was defined, the LDAC pulse is skipped. + :param voltages: list of voltages to program the DAC channels to :param channels: list of DAC channels to program. If not specified, we program the DAC channels sequentially, starting at 0. From 416232cb6407905d8e02d847c1796c8f6f252b1b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 28 Mar 2018 10:51:07 +0800 Subject: [PATCH 0575/2457] runtime: do not reset RTIO PHY on core.reset(). Closes #971 --- artiq/firmware/runtime/kern_hwreq.rs | 2 +- artiq/firmware/runtime/rtio_mgt.rs | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index b3f77f567..87ebd665e 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -296,7 +296,7 @@ pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> io::Result #[cfg(has_rtio_core)] &kern::RtioInitRequest => { info!("resetting RTIO"); - rtio_mgt::init_core(); + rtio_mgt::init_core(false); kern_acknowledge() } diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 675d91a1a..d2c926b5d 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -264,14 +264,16 @@ pub fn startup(io: &Io) { } drtio::startup(io); - init_core(); + init_core(true); io.spawn(4096, async_error_thread); } -pub fn init_core() { +pub fn init_core(phy: bool) { unsafe { csr::rtio_core::reset_write(1); - csr::rtio_core::reset_phy_write(1); + if phy { + csr::rtio_core::reset_phy_write(1); + } } drtio::init() } From 605292535c5cc108b1d0a5de375da6a1c7797366 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 29 Mar 2018 10:12:02 +0800 Subject: [PATCH 0576/2457] kasli: ignore OSERDESE2->ISERDESE2 timing path on DRTIO targets as well --- artiq/gateware/targets/kasli.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 5923db950..22b6a3fbf 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -80,6 +80,17 @@ class _RTIOCRG(Module, AutoCSR): ] +def fix_serdes_timing_path(platform): + # ignore timing of path from OSERDESE2 through the pad to ISERDESE2 + platform.add_platform_command( + "set_false_path -quiet " + "-through [get_pins -filter {{REF_PIN_NAME == OQ || REF_PIN_NAME == TQ}} " + "-of [get_cells -filter {{REF_NAME == OSERDESE2}}]] " + "-to [get_pins -filter {{REF_PIN_NAME == D}} " + "-of [get_cells -filter {{REF_NAME == ISERDESE2}}]]" + ) + + class _StandaloneBase(MiniSoC, AMPSoC): mem_map = { "cri_con": 0x10000000, @@ -114,6 +125,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): def add_rtio(self, rtio_channels): self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) self.csr_devices.append("rtio_crg") + fix_serdes_timing_path(self.platform) self.submodules.rtio_core = rtio.Core(rtio_channels) self.csr_devices.append("rtio_core") self.submodules.rtio = rtio.KernelInitiator() @@ -136,15 +148,6 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") - # ignore timing of path from OSERDESE2 through the pad to ISERDESE2 - self.platform.add_platform_command( - "set_false_path -quiet " - "-through [get_pins -filter {{REF_PIN_NAME == OQ || REF_PIN_NAME == TQ}} " - "-of [get_cells -filter {{REF_NAME == OSERDESE2}}]] " - "-to [get_pins -filter {{REF_PIN_NAME == D}} " - "-of [get_cells -filter {{REF_NAME == ISERDESE2}}]]" - ) - def _eem_signal(i): n = "d{}".format(i) @@ -686,6 +689,7 @@ class _MasterBase(MiniSoC, AMPSoC): self.crg.cd_sys.clk, gtp.rxoutclk) self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) + fix_serdes_timing_path(platform) def add_rtio(self, rtio_channels): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) @@ -806,6 +810,7 @@ class _SatelliteBase(BaseSoC): gtp.txoutclk, gtp.rxoutclk) self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) + fix_serdes_timing_path(platform) def add_rtio(self, rtio_channels): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) From 3d89ba2e11c3059fcaf32ffe7f60cd557b8b6132 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 29 Mar 2018 10:20:17 +0800 Subject: [PATCH 0577/2457] sayma: remove debug leftover --- artiq/gateware/targets/sayma_amc.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index f25039c5a..116ce75c6 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -82,7 +82,6 @@ class AD9154JESD(Module, AutoCSR): cpll = JESD204BGTHChannelPLL( jesd_crg.refclk, jesd_crg.refclk_freq, jesd_crg.linerate) self.submodules += cpll - #print(cpll) phy = JESD204BPhyTX( cpll, PhyPads(jesd_pads.txp[i], jesd_pads.txn[i]), jesd_crg.fabric_freq, transceiver="gth") From 4229c045f4907436e21f1146450f033ac6010ac7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 29 Mar 2018 10:20:31 +0800 Subject: [PATCH 0578/2457] kasli: fix DRTIO master clock constraint --- artiq/gateware/targets/kasli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 22b6a3fbf..c35dabce7 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -684,7 +684,7 @@ class _MasterBase(MiniSoC, AMPSoC): self.crg.cd_sys.clk, gtp.txoutclk, gtp.rxoutclk) for gtp in self.drtio_transceiver.gtps[1:]: - platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) + platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.rxoutclk) From 493d2a653f01abcee5db8c9d9897655f29c11a0e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 29 Mar 2018 10:55:41 +0800 Subject: [PATCH 0579/2457] siphaser: add false path between sys_clk and mmcm_freerun_output --- artiq/gateware/targets/kasli.py | 5 +++-- artiq/gateware/targets/sayma_amc.py | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index c35dabce7..b9f8320bb 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -791,8 +791,9 @@ class _SatelliteBase(BaseSoC): self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), - si5324_clkout_fabric=platform.request("si5324_clkout_fabric") - ) + si5324_clkout_fabric=platform.request("si5324_clkout_fabric")) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) self.csr_devices.append("siphaser") i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 116ce75c6..a27c59fac 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -439,10 +439,11 @@ class Satellite(BaseSoC): self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), - si5324_clkout_fabric=platform.request("si5324_clkout_fabric") - ) + si5324_clkout_fabric=platform.request("si5324_clkout_fabric")) platform.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets {mmcm_ps}]", mmcm_ps=self.siphaser.mmcm_ps_output) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) self.csr_devices.append("siphaser") self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) self.csr_devices.append("si5324_rst_n") From e83863a8da04e456a0f94090005480443dd52ff9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 29 Mar 2018 12:35:41 +0800 Subject: [PATCH 0580/2457] conda: bump migen --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 08aed670c..e58cd0b52 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_21+git881741b + - migen 0.7 py35_23+gitf4180e9 - misoc 0.10 py35_9+git103bb3a8 - jesd204b 0.5 - microscope From f0771765c17c53ded102d7d06ed09b609b316528 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 29 Mar 2018 23:55:00 +0800 Subject: [PATCH 0581/2457] rtio: move CRI write comment to more appropriate location --- artiq/gateware/rtio/cri.py | 5 +++++ artiq/gateware/rtio/sed/lane_distributor.py | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 1d2b89435..2a871f736 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -6,6 +6,11 @@ from migen.genlib.record import * from misoc.interconnect.csr import * +# CRI write happens in 3 cycles: +# 1. set timestamp and channel +# 2. set other payload elements and issue write command +# 3. check status + commands = { "nop": 0, diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index a2834f13b..4f8b7e146 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -7,11 +7,6 @@ from artiq.gateware.rtio.sed import layouts __all__ = ["LaneDistributor"] -# CRI write happens in 3 cycles: -# 1. set timestamp and channel -# 2. set other payload elements and issue write command -# 3. check status - class LaneDistributor(Module): def __init__(self, lane_count, seqn_width, layout_payload, compensation, glbl_fine_ts_width, From 2ca3fda898cb924c78b28ff179185a49b2553e71 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 3 Apr 2018 14:29:29 +0800 Subject: [PATCH 0582/2457] conda: bump misoc. Closes #891 --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index e58cd0b52..7aff7b4de 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_23+gitf4180e9 - - misoc 0.10 py35_9+git103bb3a8 + - misoc 0.11 py35_2+gita6848044 - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27 From d0f6123f5c47eb74f5dd906041c103e0d967b188 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 3 Apr 2018 15:55:53 +0800 Subject: [PATCH 0583/2457] conda: bump misoc again --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 7aff7b4de..8b30e7925 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_23+gitf4180e9 - - misoc 0.11 py35_2+gita6848044 + - misoc 0.11 py35_3+git4c010df2 - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27 From dd1c5c61d0bdbd2f4796fb9feb0ecffe78ee070f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 3 Apr 2018 19:36:31 +0800 Subject: [PATCH 0584/2457] conda: error out if command in build.sh fails --- conda/artiq-board/build.sh | 2 ++ conda/artiq-sayma_rtm/build.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/conda/artiq-board/build.sh b/conda/artiq-board/build.sh index 3b61b285e..44c067c00 100644 --- a/conda/artiq-board/build.sh +++ b/conda/artiq-board/build.sh @@ -1,5 +1,7 @@ #!/bin/bash +set -e + SOC_PREFIX=$SP_DIR/artiq/binaries/${ARTIQ_TARGET}-${ARTIQ_VARIANT} mkdir -p ${SOC_PREFIX} diff --git a/conda/artiq-sayma_rtm/build.sh b/conda/artiq-sayma_rtm/build.sh index 83e505221..eceae8698 100644 --- a/conda/artiq-sayma_rtm/build.sh +++ b/conda/artiq-sayma_rtm/build.sh @@ -1,5 +1,7 @@ #!/bin/bash +set -e + SOC_PREFIX=$SP_DIR/artiq/binaries/sayma_rtm mkdir -p $SOC_PREFIX From efbe915b2417e6975f0f9c8f6325e7a5ebd6376d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 3 Apr 2018 19:36:40 +0800 Subject: [PATCH 0585/2457] conda: support satellite in board package --- conda/artiq-board/build.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/conda/artiq-board/build.sh b/conda/artiq-board/build.sh index 44c067c00..bac341b51 100644 --- a/conda/artiq-board/build.sh +++ b/conda/artiq-board/build.sh @@ -8,4 +8,7 @@ mkdir -p ${SOC_PREFIX} V=1 $PYTHON -m artiq.gateware.targets.${ARTIQ_TARGET} -V ${ARTIQ_VARIANT} cp artiq_${ARTIQ_TARGET}/${ARTIQ_VARIANT}/gateware/top.bit ${SOC_PREFIX} cp artiq_${ARTIQ_TARGET}/${ARTIQ_VARIANT}/software/bootloader/bootloader.bin ${SOC_PREFIX} -cp artiq_${ARTIQ_TARGET}/${ARTIQ_VARIANT}/software/runtime/runtime.{elf,fbi} ${SOC_PREFIX} +if [ -e artiq_${ARTIQ_TARGET}/${ARTIQ_VARIANT}/software/runtime ] +then cp artiq_${ARTIQ_TARGET}/${ARTIQ_VARIANT}/software/runtime/runtime.{elf,fbi} ${SOC_PREFIX} +else cp artiq_${ARTIQ_TARGET}/${ARTIQ_VARIANT}/software/satman/satman.{elf,fbi} ${SOC_PREFIX} +fi From 3248caa1843b4bbd09ab8d54472639739004e643 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 3 Apr 2018 18:48:08 +0200 Subject: [PATCH 0586/2457] gateware/serwb: move all clocking outside of serwb, use existing sys/sys4x clocks --- artiq/gateware/serwb/kusphy.py | 68 ++++++++++++++------------------ artiq/gateware/serwb/phy.py | 72 +++------------------------------- artiq/gateware/serwb/s7phy.py | 54 +++++++++++-------------- 3 files changed, 59 insertions(+), 135 deletions(-) diff --git a/artiq/gateware/serwb/kusphy.py b/artiq/gateware/serwb/kusphy.py index 054971612..e0b9baa1f 100644 --- a/artiq/gateware/serwb/kusphy.py +++ b/artiq/gateware/serwb/kusphy.py @@ -7,7 +7,10 @@ from misoc.cores.code_8b10b import Encoder, Decoder class KUSSerdes(Module): - def __init__(self, pll, pads, mode="master"): + def __init__(self, pads, mode="master"): + if mode == "slave": + self.refclk = Signal() + self.tx_k = Signal(4) self.tx_d = Signal(32) self.rx_k = Signal(4) @@ -26,29 +29,18 @@ class KUSSerdes(Module): # # # - self.submodules.encoder = ClockDomainsRenamer("serwb_serdes")( + self.submodules.encoder = ClockDomainsRenamer("sys0p2x")( Encoder(4, True)) - self.decoders = [ClockDomainsRenamer("serwb_serdes")( + self.decoders = [ClockDomainsRenamer("sys0p2x")( Decoder(True)) for _ in range(4)] self.submodules += self.decoders # clocking: # In master mode: - # - linerate/10 pll refclk provided by user - # - linerate/10 slave refclk generated on clk_pads + # - linerate/10 refclk generated on clk_pads # In Slave mode: - # - linerate/10 pll refclk provided by clk_pads - self.clock_domains.cd_serwb_serdes = ClockDomain() - self.clock_domains.cd_serwb_serdes_5x = ClockDomain() - self.clock_domains.cd_serwb_serdes_20x = ClockDomain(reset_less=True) - self.comb += [ - self.cd_serwb_serdes.clk.eq(pll.serwb_serdes_clk), - self.cd_serwb_serdes_5x.clk.eq(pll.serwb_serdes_5x_clk), - self.cd_serwb_serdes_20x.clk.eq(pll.serwb_serdes_20x_clk) - ] - self.specials += AsyncResetSynchronizer(self.cd_serwb_serdes, ~pll.lock) - self.comb += self.cd_serwb_serdes_5x.rst.eq(self.cd_serwb_serdes.rst) + # - linerate/10 refclk provided by clk_pads # control/status cdc tx_idle = Signal() @@ -61,20 +53,20 @@ class KUSSerdes(Module): rx_delay_en_vtc = Signal() rx_delay_ce = Signal() self.specials += [ - MultiReg(self.tx_idle, tx_idle, "serwb_serdes"), - MultiReg(self.tx_comma, tx_comma, "serwb_serdes"), + MultiReg(self.tx_idle, tx_idle, "sys0p2x"), + MultiReg(self.tx_comma, tx_comma, "sys0p2x"), MultiReg(rx_idle, self.rx_idle, "sys"), MultiReg(rx_comma, self.rx_comma, "sys"), - MultiReg(self.rx_bitslip_value, rx_bitslip_value, "serwb_serdes"), - MultiReg(self.rx_delay_inc, rx_delay_inc, "serwb_serdes_5x"), - MultiReg(self.rx_delay_en_vtc, rx_delay_en_vtc, "serwb_serdes_5x") + MultiReg(self.rx_bitslip_value, rx_bitslip_value, "sys0p2x"), + MultiReg(self.rx_delay_inc, rx_delay_inc, "sys"), + MultiReg(self.rx_delay_en_vtc, rx_delay_en_vtc, "sys") ] - self.submodules.do_rx_delay_rst = PulseSynchronizer("sys", "serwb_serdes_5x") + self.submodules.do_rx_delay_rst = PulseSynchronizer("sys", "sys") self.comb += [ rx_delay_rst.eq(self.do_rx_delay_rst.o), self.do_rx_delay_rst.i.eq(self.rx_delay_rst) ] - self.submodules.do_rx_delay_ce = PulseSynchronizer("sys", "serwb_serdes_5x") + self.submodules.do_rx_delay_ce = PulseSynchronizer("sys", "sys") self.comb += [ rx_delay_ce.eq(self.do_rx_delay_ce.o), self.do_rx_delay_ce.i.eq(self.rx_delay_ce) @@ -82,7 +74,7 @@ class KUSSerdes(Module): # tx clock (linerate/10) if mode == "master": - self.submodules.tx_clk_gearbox = Gearbox(40, "serwb_serdes", 8, "serwb_serdes_5x") + self.submodules.tx_clk_gearbox = Gearbox(40, "sys0p2x", 8, "sys") self.comb += self.tx_clk_gearbox.i.eq((0b1111100000 << 30) | (0b1111100000 << 20) | (0b1111100000 << 10) | @@ -94,8 +86,8 @@ class KUSSerdes(Module): p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, o_OQ=clk_o, - i_RST=ResetSignal("serwb_serdes"), - i_CLK=ClockSignal("serwb_serdes_20x"), i_CLKDIV=ClockSignal("serwb_serdes_5x"), + i_RST=ResetSignal("sys"), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D=self.tx_clk_gearbox.o ), Instance("OBUFDS", @@ -107,7 +99,7 @@ class KUSSerdes(Module): # tx datapath # tx_data -> encoders -> gearbox -> serdes - self.submodules.tx_gearbox = Gearbox(40, "serwb_serdes", 8, "serwb_serdes_5x") + self.submodules.tx_gearbox = Gearbox(40, "sys0p2x", 8, "sys") self.comb += [ If(tx_comma, self.encoder.k[0].eq(1), @@ -123,7 +115,7 @@ class KUSSerdes(Module): self.encoder.d[3].eq(self.tx_d[24:32]) ) ] - self.sync.serwb_serdes += \ + self.sync.sys0p2x += \ If(tx_idle, self.tx_gearbox.i.eq(0) ).Else( @@ -137,8 +129,8 @@ class KUSSerdes(Module): p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, o_OQ=serdes_o, - i_RST=ResetSignal("serwb_serdes"), - i_CLK=ClockSignal("serwb_serdes_20x"), i_CLKDIV=ClockSignal("serwb_serdes_5x"), + i_RST=ResetSignal("sys"), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D=self.tx_gearbox.o ), Instance("OBUFDS", @@ -168,12 +160,12 @@ class KUSSerdes(Module): ] else: self.specials += Instance("BUFG", i_I=clk_i, o_O=clk_i_bufg) - self.comb += pll.refclk.eq(clk_i_bufg) + self.comb += self.refclk.eq(clk_i_bufg) # rx datapath # serdes -> gearbox -> bitslip -> decoders -> rx_data - self.submodules.rx_gearbox = Gearbox(8, "serwb_serdes_5x", 40, "serwb_serdes") - self.submodules.rx_bitslip = ClockDomainsRenamer("serwb_serdes")(BitSlip(40)) + self.submodules.rx_gearbox = Gearbox(8, "sys", 40, "sys0p2x") + self.submodules.rx_bitslip = ClockDomainsRenamer("sys0p2x")(BitSlip(40)) serdes_i_nodelay = Signal() self.specials += [ @@ -193,7 +185,7 @@ class KUSSerdes(Module): p_DELAY_FORMAT="COUNT", p_DELAY_SRC="IDATAIN", p_DELAY_TYPE="VARIABLE", p_DELAY_VALUE=0, - i_CLK=ClockSignal("serwb_serdes_5x"), + i_CLK=ClockSignal("sys"), i_RST=rx_delay_rst, i_LOAD=0, i_INC=rx_delay_inc, i_EN_VTC=rx_delay_en_vtc, i_CE=rx_delay_ce, @@ -206,11 +198,11 @@ class KUSSerdes(Module): p_DATA_WIDTH=8, i_D=serdes_i_delayed, - i_RST=ResetSignal("serwb_serdes"), + i_RST=ResetSignal("sys"), i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0, - i_CLK=ClockSignal("serwb_serdes_20x"), - i_CLK_B=ClockSignal("serwb_serdes_20x"), # locally inverted - i_CLKDIV=ClockSignal("serwb_serdes_5x"), + i_CLK=ClockSignal("sys4x"), + i_CLK_B=ClockSignal("sys4x"), # locally inverted + i_CLKDIV=ClockSignal("sys"), o_Q=serdes_q ) ] diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index b6436cdca..e22e436fe 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -154,7 +154,6 @@ class _SerdesMasterInit(Module): class _SerdesSlaveInit(Module, AutoCSR): def __init__(self, serdes, taps, timeout=4096): - self.reset = Signal() self.ready = Signal() self.error = Signal() @@ -170,11 +169,10 @@ class _SerdesSlaveInit(Module, AutoCSR): timer = WaitTimer(timeout) self.submodules += timer - self.comb += self.reset.eq(serdes.rx_idle) - self.comb += serdes.rx_delay_inc.eq(1) - self.submodules.fsm = fsm = FSM(reset_state="IDLE") + self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) + self.comb += fsm.reset.eq(serdes.rx_idle) fsm.act("IDLE", NextValue(delay, 0), NextValue(delay_min, 0), @@ -311,74 +309,16 @@ class _SerdesControl(Module, AutoCSR): ] -class SERWBPLL(Module): - def __init__(self, refclk_freq, linerate, vco_div=1): - assert refclk_freq in [62.5e6, 125e6] - assert linerate in [625e6, 1.25e9] - - self.lock = Signal() - self.refclk = Signal() - self.serwb_serdes_clk = Signal() - self.serwb_serdes_20x_clk = Signal() - self.serwb_serdes_5x_clk = Signal() - - # # # - - self.linerate = linerate - - refclk_mult = 125e6//refclk_freq - linerate_div = 1.25e9//linerate - - pll_locked = Signal() - pll_fb = Signal() - pll_serwb_serdes_clk = Signal() - pll_serwb_serdes_20x_clk = Signal() - pll_serwb_serdes_5x_clk = Signal() - self.specials += [ - Instance("PLLE2_BASE", - p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, - - # VCO @ 1.25GHz / vco_div - p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=8.0*refclk_mult, - p_CLKFBOUT_MULT=10*refclk_mult, p_DIVCLK_DIVIDE=vco_div, - i_CLKIN1=self.refclk, i_CLKFBIN=pll_fb, - o_CLKFBOUT=pll_fb, - - # serwb_serdes - p_CLKOUT0_DIVIDE=linerate_div*40//vco_div, p_CLKOUT0_PHASE=0.0, - o_CLKOUT0=pll_serwb_serdes_clk, - - # serwb_serdes_20x - p_CLKOUT1_DIVIDE=linerate_div*2//vco_div, p_CLKOUT1_PHASE=0.0, - o_CLKOUT1=pll_serwb_serdes_20x_clk, - - # serwb_serdes_5x - p_CLKOUT2_DIVIDE=linerate_div*8//vco_div, p_CLKOUT2_PHASE=0.0, - o_CLKOUT2=pll_serwb_serdes_5x_clk - ), - Instance("BUFG", - i_I=pll_serwb_serdes_clk, - o_O=self.serwb_serdes_clk), - Instance("BUFG", - i_I=pll_serwb_serdes_20x_clk, - o_O=self.serwb_serdes_20x_clk), - Instance("BUFG", - i_I=pll_serwb_serdes_5x_clk, - o_O=self.serwb_serdes_5x_clk) - ] - self.specials += MultiReg(pll_locked, self.lock) - - class SERWBPHY(Module, AutoCSR): - cd = "serwb_serdes" - def __init__(self, device, pll, pads, mode="master"): + cd = "sys0p2x" + def __init__(self, device, pads, mode="master"): assert mode in ["master", "slave"] if device[:4] == "xcku": taps = 512 - self.submodules.serdes = KUSSerdes(pll, pads, mode) + self.submodules.serdes = KUSSerdes(pads, mode) elif device[:4] == "xc7a": taps = 32 - self.submodules.serdes = S7Serdes(pll, pads, mode) + self.submodules.serdes = S7Serdes(pads, mode) else: raise NotImplementedError if mode == "master": diff --git a/artiq/gateware/serwb/s7phy.py b/artiq/gateware/serwb/s7phy.py index f21d39a4b..a345d6823 100644 --- a/artiq/gateware/serwb/s7phy.py +++ b/artiq/gateware/serwb/s7phy.py @@ -7,7 +7,10 @@ from misoc.cores.code_8b10b import Encoder, Decoder class S7Serdes(Module): - def __init__(self, pll, pads, mode="master"): + def __init__(self, pads, mode="master"): + if mode == "slave": + self.refclk = Signal() + self.tx_k = Signal(4) self.tx_d = Signal(32) self.rx_k = Signal(4) @@ -25,29 +28,18 @@ class S7Serdes(Module): # # # - self.submodules.encoder = ClockDomainsRenamer("serwb_serdes")( + self.submodules.encoder = ClockDomainsRenamer("sys0p2x")( Encoder(4, True)) - self.decoders = [ClockDomainsRenamer("serwb_serdes")( + self.decoders = [ClockDomainsRenamer("sys0p2x")( Decoder(True)) for _ in range(4)] self.submodules += self.decoders # clocking: # In master mode: - # - linerate/10 pll refclk provided by user # - linerate/10 slave refclk generated on clk_pads # In Slave mode: - # - linerate/10 pll refclk provided by clk_pads - self.clock_domains.cd_serwb_serdes = ClockDomain() - self.clock_domains.cd_serwb_serdes_5x = ClockDomain() - self.clock_domains.cd_serwb_serdes_20x = ClockDomain(reset_less=True) - self.comb += [ - self.cd_serwb_serdes.clk.eq(pll.serwb_serdes_clk), - self.cd_serwb_serdes_5x.clk.eq(pll.serwb_serdes_5x_clk), - self.cd_serwb_serdes_20x.clk.eq(pll.serwb_serdes_20x_clk) - ] - self.specials += AsyncResetSynchronizer(self.cd_serwb_serdes, ~pll.lock) - self.comb += self.cd_serwb_serdes_5x.rst.eq(self.cd_serwb_serdes.rst) + # - linerate/10 refclk provided by clk_pads # control/status cdc tx_idle = Signal() @@ -56,16 +48,16 @@ class S7Serdes(Module): rx_comma = Signal() rx_bitslip_value = Signal(6) self.specials += [ - MultiReg(self.tx_idle, tx_idle, "serwb_serdes"), - MultiReg(self.tx_comma, tx_comma, "serwb_serdes"), + MultiReg(self.tx_idle, tx_idle, "sys0p2x"), + MultiReg(self.tx_comma, tx_comma, "sys0p2x"), MultiReg(rx_idle, self.rx_idle, "sys"), MultiReg(rx_comma, self.rx_comma, "sys") ] - self.specials += MultiReg(self.rx_bitslip_value, rx_bitslip_value, "serwb_serdes"), + self.specials += MultiReg(self.rx_bitslip_value, rx_bitslip_value, "sys0p2x"), # tx clock (linerate/10) if mode == "master": - self.submodules.tx_clk_gearbox = Gearbox(40, "serwb_serdes", 8, "serwb_serdes_5x") + self.submodules.tx_clk_gearbox = Gearbox(40, "sys0p2x", 8, "sys") self.comb += self.tx_clk_gearbox.i.eq((0b1111100000 << 30) | (0b1111100000 << 20) | (0b1111100000 << 10) | @@ -79,8 +71,8 @@ class S7Serdes(Module): o_OQ=clk_o, i_OCE=1, - i_RST=ResetSignal("serwb_serdes"), - i_CLK=ClockSignal("serwb_serdes_20x"), i_CLKDIV=ClockSignal("serwb_serdes_5x"), + i_RST=ResetSignal("sys"), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D1=self.tx_clk_gearbox.o[0], i_D2=self.tx_clk_gearbox.o[1], i_D3=self.tx_clk_gearbox.o[2], i_D4=self.tx_clk_gearbox.o[3], i_D5=self.tx_clk_gearbox.o[4], i_D6=self.tx_clk_gearbox.o[5], @@ -95,7 +87,7 @@ class S7Serdes(Module): # tx datapath # tx_data -> encoders -> gearbox -> serdes - self.submodules.tx_gearbox = Gearbox(40, "serwb_serdes", 8, "serwb_serdes_5x") + self.submodules.tx_gearbox = Gearbox(40, "sys0p2x", 8, "sys") self.comb += [ If(tx_comma, self.encoder.k[0].eq(1), @@ -111,7 +103,7 @@ class S7Serdes(Module): self.encoder.d[3].eq(self.tx_d[24:32]) ) ] - self.sync.serwb_serdes += \ + self.sync.sys0p2x += \ If(tx_idle, self.tx_gearbox.i.eq(0) ).Else( @@ -127,8 +119,8 @@ class S7Serdes(Module): o_OQ=serdes_o, i_OCE=1, - i_RST=ResetSignal("serwb_serdes"), - i_CLK=ClockSignal("serwb_serdes_20x"), i_CLKDIV=ClockSignal("serwb_serdes_5x"), + i_RST=ResetSignal("sys"), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D1=self.tx_gearbox.o[0], i_D2=self.tx_gearbox.o[1], i_D3=self.tx_gearbox.o[2], i_D4=self.tx_gearbox.o[3], i_D5=self.tx_gearbox.o[4], i_D6=self.tx_gearbox.o[5], @@ -161,12 +153,12 @@ class S7Serdes(Module): ] else: self.specials += Instance("BUFG", i_I=clk_i, o_O=clk_i_bufg) - self.comb += pll.refclk.eq(clk_i_bufg) + self.comb += self.refclk.eq(clk_i_bufg) # rx datapath # serdes -> gearbox -> bitslip -> decoders -> rx_data - self.submodules.rx_gearbox = Gearbox(8, "serwb_serdes_5x", 40, "serwb_serdes") - self.submodules.rx_bitslip = ClockDomainsRenamer("serwb_serdes")(BitSlip(40)) + self.submodules.rx_gearbox = Gearbox(8, "sys", 40, "sys0p2x") + self.submodules.rx_bitslip = ClockDomainsRenamer("sys0p2x")(BitSlip(40)) serdes_i_nodelay = Signal() self.specials += [ @@ -200,9 +192,9 @@ class S7Serdes(Module): i_DDLY=serdes_i_delayed, i_CE1=1, - i_RST=ResetSignal("serwb_serdes"), - i_CLK=ClockSignal("serwb_serdes_20x"), i_CLKB=~ClockSignal("serwb_serdes_20x"), - i_CLKDIV=ClockSignal("serwb_serdes_5x"), + i_RST=ResetSignal("sys"), + i_CLK=ClockSignal("sys4x"), i_CLKB=~ClockSignal("sys4x"), + i_CLKDIV=ClockSignal("sys"), i_BITSLIP=0, o_Q8=serdes_q[0], o_Q7=serdes_q[1], o_Q6=serdes_q[2], o_Q5=serdes_q[3], From aef0153a8fbe7a3b5a6e195186d8d7c8d1c51e9d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 3 Apr 2018 18:53:39 +0200 Subject: [PATCH 0587/2457] targets/sayma: adapt to new serwb clocking --- artiq/gateware/targets/sayma_amc.py | 13 +-------- artiq/gateware/targets/sayma_rtm.py | 43 +++++++++++++++-------------- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index a27c59fac..6ff2f73ed 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -169,22 +169,11 @@ class Standalone(MiniSoC, AMPSoC): self.config["SLAVE_FPGA_GATEWARE"] = 0x150000 # AMC/RTM serwb - serwb_pll = serwb.phy.SERWBPLL(125e6, 625e6, vco_div=2) - self.comb += serwb_pll.refclk.eq(self.crg.cd_sys.clk) - self.submodules += serwb_pll - serwb_pads = platform.request("amc_rtm_serwb") - serwb_phy_amc = serwb.phy.SERWBPHY(platform.device, serwb_pll, serwb_pads, mode="master") + serwb_phy_amc = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="master") self.submodules.serwb_phy_amc = serwb_phy_amc self.csr_devices.append("serwb_phy_amc") - serwb_phy_amc.serdes.cd_serwb_serdes.clk.attr.add("keep") - serwb_phy_amc.serdes.cd_serwb_serdes_5x.clk.attr.add("keep") - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - serwb_phy_amc.serdes.cd_serwb_serdes.clk, - serwb_phy_amc.serdes.cd_serwb_serdes_5x.clk) - serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave", with_scrambling=True) self.submodules += serwb_core self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 9052477a5..7795a2382 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -21,35 +21,48 @@ from artiq import __version__ as artiq_version class CRG(Module): def __init__(self, platform): + self.clock_domains.cd_sys0p2x = ClockDomain() self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys4x = ClockDomain() self.clock_domains.cd_clk200 = ClockDomain() - clk50 = platform.request("clk50") - self.reset = Signal() + self.serwb_refclk = Signal() pll_locked = Signal() pll_fb = Signal() + pll_sys0p2x = Signal() pll_sys = Signal() + pll_sys4x = Signal() pll_clk200 = Signal() self.specials += [ Instance("PLLE2_BASE", p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, # VCO @ 1GHz - p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=20.0, - p_CLKFBOUT_MULT=20, p_DIVCLK_DIVIDE=1, - i_CLKIN1=clk50, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, + p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=10.0, + p_CLKFBOUT_MULT=10, p_DIVCLK_DIVIDE=1, + i_CLKIN1=self.serwb_refclk, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, + + # 25MHz + p_CLKOUT0_DIVIDE=40, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_sys0p2x, # 125MHz - p_CLKOUT0_DIVIDE=8, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_sys, + p_CLKOUT1_DIVIDE=8, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=pll_sys, + + # 500MHz + p_CLKOUT2_DIVIDE=2, p_CLKOUT2_PHASE=0.0, o_CLKOUT2=pll_sys4x, # 200MHz p_CLKOUT3_DIVIDE=5, p_CLKOUT3_PHASE=0.0, o_CLKOUT3=pll_clk200 ), + Instance("BUFG", i_I=pll_sys0p2x, o_O=self.cd_sys0p2x.clk), Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk), + Instance("BUFG", i_I=pll_sys4x, o_O=self.cd_sys4x.clk), Instance("BUFG", i_I=pll_clk200, o_O=self.cd_clk200.clk), - AsyncResetSynchronizer(self.cd_sys, ~pll_locked | self.reset), - AsyncResetSynchronizer(self.cd_clk200, ~pll_locked | self.reset) + AsyncResetSynchronizer(self.cd_sys0p2x, ~pll_locked), + AsyncResetSynchronizer(self.cd_sys, ~pll_locked), + AsyncResetSynchronizer(self.cd_sys4x, ~pll_locked), + AsyncResetSynchronizer(self.cd_clk200, ~pll_locked) ] reset_counter = Signal(4, reset=15) @@ -148,23 +161,13 @@ class SaymaRTM(Module): self.comb += platform.request("hmc7043_reset").eq(0) # AMC/RTM serwb - serwb_pll = serwb.phy.SERWBPLL(62.5e6, 625e6, vco_div=1) - self.submodules += serwb_pll - serwb_pads = platform.request("amc_rtm_serwb") - platform.add_period_constraint(serwb_pads.clk_p, 16.) + platform.add_period_constraint(serwb_pads.clk_p, 10.) serwb_phy_rtm = serwb.phy.SERWBPHY(platform.device, serwb_pll, serwb_pads, mode="slave") self.submodules.serwb_phy_rtm = serwb_phy_rtm - self.comb += self.crg.reset.eq(serwb_phy_rtm.init.reset) + self.comb += self.crg.serwb_refclk.eq(serwb_phy.serdes.refclk) csr_devices.append("serwb_phy_rtm") - serwb_phy_rtm.serdes.cd_serwb_serdes.clk.attr.add("keep") - serwb_phy_rtm.serdes.cd_serwb_serdes_5x.clk.attr.add("keep") - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - serwb_phy_rtm.serdes.cd_serwb_serdes.clk, - serwb_phy_rtm.serdes.cd_serwb_serdes_5x.clk) - serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master", with_scrambling=True) self.submodules += serwb_core From 7488703f233acc9514a9e654b95a5a0fbc35ec59 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 3 Apr 2018 18:57:00 +0200 Subject: [PATCH 0588/2457] targets/sayma_rtm: fix serwb --- artiq/gateware/targets/sayma_rtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 7795a2382..4c41b811c 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -163,7 +163,7 @@ class SaymaRTM(Module): # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") platform.add_period_constraint(serwb_pads.clk_p, 10.) - serwb_phy_rtm = serwb.phy.SERWBPHY(platform.device, serwb_pll, serwb_pads, mode="slave") + serwb_phy_rtm = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="slave") self.submodules.serwb_phy_rtm = serwb_phy_rtm self.comb += self.crg.serwb_refclk.eq(serwb_phy.serdes.refclk) csr_devices.append("serwb_phy_rtm") From dd21c07b85c1067913d521b09fda80acf561df7d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 3 Apr 2018 18:59:05 +0200 Subject: [PATCH 0589/2457] targets/sayma_rtm: fix serwb 2 ... --- artiq/gateware/targets/sayma_rtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 4c41b811c..08ed4245c 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -165,7 +165,7 @@ class SaymaRTM(Module): platform.add_period_constraint(serwb_pads.clk_p, 10.) serwb_phy_rtm = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="slave") self.submodules.serwb_phy_rtm = serwb_phy_rtm - self.comb += self.crg.serwb_refclk.eq(serwb_phy.serdes.refclk) + self.comb += self.crg.serwb_refclk.eq(serwb_phy_rtm.serdes.refclk) csr_devices.append("serwb_phy_rtm") serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master", with_scrambling=True) From 73b727cade00da5f3b9bc87fa3d2b96e2cf1496f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 7 Apr 2018 02:59:14 +0200 Subject: [PATCH 0590/2457] serwb: new version using only sys/sys4x clocks domains, scrambling deactivated. --- artiq/gateware/serwb/core.py | 34 +++--- artiq/gateware/serwb/kusphy.py | 160 +++++++++++++--------------- artiq/gateware/serwb/phy.py | 68 ++++++------ artiq/gateware/serwb/s7phy.py | 157 ++++++++++++++------------- artiq/gateware/targets/sayma_amc.py | 2 +- artiq/gateware/targets/sayma_rtm.py | 2 +- 6 files changed, 210 insertions(+), 213 deletions(-) diff --git a/artiq/gateware/serwb/core.py b/artiq/gateware/serwb/core.py index 4e190e03b..a49d7231c 100644 --- a/artiq/gateware/serwb/core.py +++ b/artiq/gateware/serwb/core.py @@ -17,37 +17,37 @@ class SERWBCore(Module): packetizer = Packetizer() self.submodules += depacketizer, packetizer - # clock domain crossing - tx_cdc = stream.AsyncFIFO([("data", 32)], 16) - tx_cdc = ClockDomainsRenamer({"write": "sys", "read": phy.cd})(tx_cdc) - rx_cdc = stream.AsyncFIFO([("data", 32)], 16) - rx_cdc = ClockDomainsRenamer({"write": phy.cd, "read": "sys"})(rx_cdc) - self.submodules += tx_cdc, rx_cdc + # fifos + tx_fifo = stream.SyncFIFO([("data", 32)], 16) + rx_fifo = stream.SyncFIFO([("data", 32)], 16) + self.submodules += tx_fifo, rx_fifo # scrambling - scrambler = ClockDomainsRenamer(phy.cd)(Scrambler(enable=with_scrambling)) - descrambler = ClockDomainsRenamer(phy.cd)(Descrambler(enable=with_scrambling)) + scrambler = Scrambler(enable=with_scrambling) + descrambler = Descrambler(enable=with_scrambling) self.submodules += scrambler, descrambler # modules connection self.comb += [ # core --> phy - packetizer.source.connect(tx_cdc.sink), - tx_cdc.source.connect(scrambler.sink), + packetizer.source.connect(tx_fifo.sink), + tx_fifo.source.connect(scrambler.sink), If(phy.init.ready, - If(scrambler.source.stb, + If(scrambler.source.valid, phy.serdes.tx_k.eq(scrambler.source.k), phy.serdes.tx_d.eq(scrambler.source.d) ), - scrambler.source.ack.eq(1) + scrambler.source.ready.eq(phy.serdes.tx_ce) ), # phy --> core - descrambler.sink.stb.eq(phy.init.ready), - descrambler.sink.k.eq(phy.serdes.rx_k), - descrambler.sink.d.eq(phy.serdes.rx_d), - descrambler.source.connect(rx_cdc.sink), - rx_cdc.source.connect(depacketizer.sink), + If(phy.init.ready, + descrambler.sink.valid.eq(phy.serdes.rx_ce), + descrambler.sink.k.eq(phy.serdes.rx_k), + descrambler.sink.d.eq(phy.serdes.rx_d) + ), + descrambler.source.connect(rx_fifo.sink), + rx_fifo.source.connect(depacketizer.sink), # etherbone <--> core depacketizer.source.connect(etherbone.sink), diff --git a/artiq/gateware/serwb/kusphy.py b/artiq/gateware/serwb/kusphy.py index e0b9baa1f..cfd10d94b 100644 --- a/artiq/gateware/serwb/kusphy.py +++ b/artiq/gateware/serwb/kusphy.py @@ -1,18 +1,26 @@ from migen import * -from migen.genlib.resetsync import AsyncResetSynchronizer -from migen.genlib.cdc import MultiReg, PulseSynchronizer, Gearbox from migen.genlib.misc import BitSlip +from migen.genlib.misc import WaitTimer +from misoc.interconnect import stream from misoc.cores.code_8b10b import Encoder, Decoder +def K(x, y): + return (y << 5) | x + + +@ResetInserter() class KUSSerdes(Module): def __init__(self, pads, mode="master"): if mode == "slave": self.refclk = Signal() + self.tx_ce = Signal() self.tx_k = Signal(4) self.tx_d = Signal(32) + + self.rx_ce = Signal() self.rx_k = Signal(4) self.rx_d = Signal(32) @@ -24,16 +32,14 @@ class KUSSerdes(Module): self.rx_bitslip_value = Signal(6) self.rx_delay_rst = Signal() self.rx_delay_inc = Signal() - self.rx_delay_ce = Signal() self.rx_delay_en_vtc = Signal() # # # - self.submodules.encoder = ClockDomainsRenamer("sys0p2x")( - Encoder(4, True)) - self.decoders = [ClockDomainsRenamer("sys0p2x")( - Decoder(True)) for _ in range(4)] - self.submodules += self.decoders + self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) + self.comb += encoder.ce.eq(self.tx_ce) + self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] + self.comb += [decoders[i].ce.eq(self.rx_ce) for i in range(4)] # clocking: @@ -42,53 +48,26 @@ class KUSSerdes(Module): # In Slave mode: # - linerate/10 refclk provided by clk_pads - # control/status cdc - tx_idle = Signal() - tx_comma = Signal() - rx_idle = Signal() - rx_comma = Signal() - rx_bitslip_value = Signal(6) - rx_delay_rst = Signal() - rx_delay_inc = Signal() - rx_delay_en_vtc = Signal() - rx_delay_ce = Signal() - self.specials += [ - MultiReg(self.tx_idle, tx_idle, "sys0p2x"), - MultiReg(self.tx_comma, tx_comma, "sys0p2x"), - MultiReg(rx_idle, self.rx_idle, "sys"), - MultiReg(rx_comma, self.rx_comma, "sys"), - MultiReg(self.rx_bitslip_value, rx_bitslip_value, "sys0p2x"), - MultiReg(self.rx_delay_inc, rx_delay_inc, "sys"), - MultiReg(self.rx_delay_en_vtc, rx_delay_en_vtc, "sys") - ] - self.submodules.do_rx_delay_rst = PulseSynchronizer("sys", "sys") - self.comb += [ - rx_delay_rst.eq(self.do_rx_delay_rst.o), - self.do_rx_delay_rst.i.eq(self.rx_delay_rst) - ] - self.submodules.do_rx_delay_ce = PulseSynchronizer("sys", "sys") - self.comb += [ - rx_delay_ce.eq(self.do_rx_delay_ce.o), - self.do_rx_delay_ce.i.eq(self.rx_delay_ce) - ] - # tx clock (linerate/10) if mode == "master": - self.submodules.tx_clk_gearbox = Gearbox(40, "sys0p2x", 8, "sys") - self.comb += self.tx_clk_gearbox.i.eq((0b1111100000 << 30) | - (0b1111100000 << 20) | - (0b1111100000 << 10) | - (0b1111100000 << 0)) + clk_converter = stream.Converter(40, 8) + self.submodules += clk_converter + self.comb += [ + clk_converter.sink.valid.eq(1), + clk_converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), + clk_converter.source.ready.eq(1) + ] clk_o = Signal() self.specials += [ Instance("OSERDESE3", p_DATA_WIDTH=8, p_INIT=0, - p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, + p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, + p_IS_RST_INVERTED=0, o_OQ=clk_o, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D=self.tx_clk_gearbox.o + i_D=clk_converter.source.data ), Instance("OBUFDS", i_I=clk_o, @@ -98,29 +77,32 @@ class KUSSerdes(Module): ] # tx datapath - # tx_data -> encoders -> gearbox -> serdes - self.submodules.tx_gearbox = Gearbox(40, "sys0p2x", 8, "sys") + # tx_data -> encoders -> converter -> serdes + self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) self.comb += [ - If(tx_comma, - self.encoder.k[0].eq(1), - self.encoder.d[0].eq(0xbc) + tx_converter.sink.valid.eq(1), + self.tx_ce.eq(tx_converter.sink.ready), + tx_converter.source.ready.eq(1), + If(self.tx_idle, + tx_converter.sink.data.eq(0) ).Else( - self.encoder.k[0].eq(self.tx_k[0]), - self.encoder.k[1].eq(self.tx_k[1]), - self.encoder.k[2].eq(self.tx_k[2]), - self.encoder.k[3].eq(self.tx_k[3]), - self.encoder.d[0].eq(self.tx_d[0:8]), - self.encoder.d[1].eq(self.tx_d[8:16]), - self.encoder.d[2].eq(self.tx_d[16:24]), - self.encoder.d[3].eq(self.tx_d[24:32]) + tx_converter.sink.data.eq( + Cat(*[encoder.output[i] for i in range(4)])) + ), + If(self.tx_comma, + encoder.k[0].eq(1), + encoder.d[0].eq(K(28,5)), + ).Else( + encoder.k[0].eq(self.tx_k[0]), + encoder.k[1].eq(self.tx_k[1]), + encoder.k[2].eq(self.tx_k[2]), + encoder.k[3].eq(self.tx_k[3]), + encoder.d[0].eq(self.tx_d[0:8]), + encoder.d[1].eq(self.tx_d[8:16]), + encoder.d[2].eq(self.tx_d[16:24]), + encoder.d[3].eq(self.tx_d[24:32]) ) ] - self.sync.sys0p2x += \ - If(tx_idle, - self.tx_gearbox.i.eq(0) - ).Else( - self.tx_gearbox.i.eq(Cat(*[self.encoder.output[i] for i in range(4)])) - ) serdes_o = Signal() self.specials += [ @@ -131,7 +113,7 @@ class KUSSerdes(Module): o_OQ=serdes_o, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D=self.tx_gearbox.o + i_D=tx_converter.source.data ), Instance("OBUFDS", i_I=serdes_o, @@ -163,9 +145,14 @@ class KUSSerdes(Module): self.comb += self.refclk.eq(clk_i_bufg) # rx datapath - # serdes -> gearbox -> bitslip -> decoders -> rx_data - self.submodules.rx_gearbox = Gearbox(8, "sys", 40, "sys0p2x") - self.submodules.rx_bitslip = ClockDomainsRenamer("sys0p2x")(BitSlip(40)) + # serdes -> converter -> bitslip -> decoders -> rx_data + self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) + self.comb += [ + self.rx_ce.eq(rx_converter.source.valid), + rx_converter.source.ready.eq(1) + ] + self.submodules.rx_bitslip = rx_bitslip = CEInserter()(BitSlip(40)) + self.comb += rx_bitslip.ce.eq(self.rx_ce) serdes_i_nodelay = Signal() self.specials += [ @@ -186,9 +173,9 @@ class KUSSerdes(Module): p_DELAY_TYPE="VARIABLE", p_DELAY_VALUE=0, i_CLK=ClockSignal("sys"), - i_RST=rx_delay_rst, i_LOAD=0, - i_INC=rx_delay_inc, i_EN_VTC=rx_delay_en_vtc, - i_CE=rx_delay_ce, + i_RST=self.rx_delay_rst, i_LOAD=0, + i_INC=1, i_EN_VTC=self.rx_delay_en_vtc, + i_CE=self.rx_delay_inc, i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed ), @@ -208,19 +195,20 @@ class KUSSerdes(Module): ] self.comb += [ - self.rx_gearbox.i.eq(serdes_q), - self.rx_bitslip.value.eq(rx_bitslip_value), - self.rx_bitslip.i.eq(self.rx_gearbox.o), - self.decoders[0].input.eq(self.rx_bitslip.o[0:10]), - self.decoders[1].input.eq(self.rx_bitslip.o[10:20]), - self.decoders[2].input.eq(self.rx_bitslip.o[20:30]), - self.decoders[3].input.eq(self.rx_bitslip.o[30:40]), - self.rx_k.eq(Cat(*[self.decoders[i].k for i in range(4)])), - self.rx_d.eq(Cat(*[self.decoders[i].d for i in range(4)])), - rx_idle.eq(self.rx_bitslip.o == 0), - rx_comma.eq(((self.decoders[0].d == 0xbc) & (self.decoders[0].k == 1)) & - ((self.decoders[1].d == 0x00) & (self.decoders[1].k == 0)) & - ((self.decoders[2].d == 0x00) & (self.decoders[2].k == 0)) & - ((self.decoders[3].d == 0x00) & (self.decoders[3].k == 0))) + rx_converter.sink.valid.eq(1), + rx_converter.sink.data.eq(serdes_q), + rx_bitslip.value.eq(self.rx_bitslip_value), + rx_bitslip.i.eq(rx_converter.source.data), + decoders[0].input.eq(rx_bitslip.o[0:10]), + decoders[1].input.eq(rx_bitslip.o[10:20]), + decoders[2].input.eq(rx_bitslip.o[20:30]), + decoders[3].input.eq(rx_bitslip.o[30:40]), + self.rx_k.eq(Cat(*[decoders[i].k for i in range(4)])), + self.rx_d.eq(Cat(*[decoders[i].d for i in range(4)])), + self.rx_comma.eq((decoders[0].k == 1) & (decoders[0].d == K(28,5))) + ] - ] + idle_timer = WaitTimer(32) + self.submodules += idle_timer + self.comb += idle_timer.wait.eq(1) + self.sync += self.rx_idle.eq(idle_timer.done & (rx_bitslip.o == 0)) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index e22e436fe..46083f0fa 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -14,11 +14,12 @@ from artiq.gateware.serwb.s7phy import S7Serdes # 3) Slave sends K28.5 commas to allow Master to calibrate, Master sends K28.5 commas. # 4) Master stops sending K28.5 commas. # 5) Slave stops sending K28.5 commas. -# 6) Link is ready. +# 6) Physical link is ready. + +@ResetInserter() class _SerdesMasterInit(Module): - def __init__(self, serdes, taps, timeout=4096): - self.reset = Signal() + def __init__(self, serdes, taps, timeout=2**14): self.ready = Signal() self.error = Signal() @@ -31,14 +32,9 @@ class _SerdesMasterInit(Module): self.delay_max_found = delay_max_found = Signal() self.bitslip = bitslip = Signal(max=40) - timer = WaitTimer(timeout) - self.submodules += timer - - self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) - self.comb += self.fsm.reset.eq(self.reset) - - self.comb += serdes.rx_delay_inc.eq(1) + self.submodules.timer = timer = WaitTimer(timeout) + self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", NextValue(delay, 0), NextValue(delay_min, 0), @@ -109,14 +105,12 @@ class _SerdesMasterInit(Module): serdes.rx_delay_rst.eq(1) ).Else( NextValue(delay, delay + 1), - serdes.rx_delay_ce.eq(1) + serdes.rx_delay_inc.eq(1) ), serdes.tx_comma.eq(1) ) fsm.act("CHECK_SAMPLING_WINDOW", - If((delay_min == 0) | - (delay_max == (taps - 1)) | - ((delay_max - delay_min) < taps//16), + If((delay_max - delay_min) < taps//16, NextValue(delay_min_found, 0), NextValue(delay_max_found, 0), NextState("WAIT_STABLE") @@ -131,7 +125,6 @@ class _SerdesMasterInit(Module): ).Else( NextValue(delay, delay + 1), serdes.rx_delay_inc.eq(1), - serdes.rx_delay_ce.eq(1), NextState("WAIT_SAMPLING_WINDOW") ), serdes.tx_comma.eq(1) @@ -147,13 +140,16 @@ class _SerdesMasterInit(Module): fsm.act("READY", self.ready.eq(1) ) + if hasattr(serdes, "rx_delay_en_vtc"): + self.comb += serdes.rx_delay_en_vtc.eq(self.ready) fsm.act("ERROR", self.error.eq(1) ) +@ResetInserter() class _SerdesSlaveInit(Module, AutoCSR): - def __init__(self, serdes, taps, timeout=4096): + def __init__(self, serdes, taps, timeout=2**14): self.ready = Signal() self.error = Signal() @@ -166,13 +162,10 @@ class _SerdesSlaveInit(Module, AutoCSR): self.delay_max_found = delay_max_found = Signal() self.bitslip = bitslip = Signal(max=40) - timer = WaitTimer(timeout) - self.submodules += timer + self.submodules.timer = timer = WaitTimer(timeout) - self.comb += serdes.rx_delay_inc.eq(1) - - self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) - self.comb += fsm.reset.eq(serdes.rx_idle) + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + # reset fsm.act("IDLE", NextValue(delay, 0), NextValue(delay_min, 0), @@ -181,7 +174,11 @@ class _SerdesSlaveInit(Module, AutoCSR): NextValue(delay_max_found, 0), serdes.rx_delay_rst.eq(1), NextValue(bitslip, 0), - NextState("WAIT_STABLE"), + timer.wait.eq(1), + If(timer.done, + timer.wait.eq(0), + NextState("WAIT_STABLE"), + ), serdes.tx_idle.eq(1) ) fsm.act("WAIT_STABLE", @@ -229,14 +226,12 @@ class _SerdesSlaveInit(Module, AutoCSR): serdes.rx_delay_rst.eq(1) ).Else( NextValue(delay, delay + 1), - serdes.rx_delay_ce.eq(1) + serdes.rx_delay_inc.eq(1) ), serdes.tx_idle.eq(1) ) fsm.act("CHECK_SAMPLING_WINDOW", - If((delay_min == 0) | - (delay_max == (taps - 1)) | - ((delay_max - delay_min) < taps//16), + If((delay_max - delay_min) < taps//16, NextValue(delay_min_found, 0), NextValue(delay_max_found, 0), NextState("WAIT_STABLE") @@ -251,7 +246,6 @@ class _SerdesSlaveInit(Module, AutoCSR): ).Else( NextValue(delay, delay + 1), serdes.rx_delay_inc.eq(1), - serdes.rx_delay_ce.eq(1), NextState("WAIT_SAMPLING_WINDOW") ) ) @@ -274,13 +268,15 @@ class _SerdesSlaveInit(Module, AutoCSR): fsm.act("READY", self.ready.eq(1) ) + if hasattr(serdes, "rx_delay_en_vtc"): + self.comb += serdes.rx_delay_en_vtc.eq(self.ready) fsm.act("ERROR", self.error.eq(1) ) class _SerdesControl(Module, AutoCSR): - def __init__(self, init, mode="master"): + def __init__(self, serdes, init, mode="master"): if mode == "master": self.reset = CSR() self.ready = CSRStatus() @@ -296,7 +292,18 @@ class _SerdesControl(Module, AutoCSR): # # # if mode == "master": + # In Master mode, reset is coming from CSR, + # it resets the Master that will also reset + # the Slave by putting the link in idle. self.comb += init.reset.eq(self.reset.re) + else: + # In Slave mode, reset is coming from link, + # Master reset the Slave by putting the link + # in idle. + self.comb += [ + init.reset.eq(serdes.rx_idle), + serdes.reset.eq(serdes.rx_idle) + ] self.comb += [ self.ready.status.eq(init.ready), self.error.status.eq(init.error), @@ -310,7 +317,6 @@ class _SerdesControl(Module, AutoCSR): class SERWBPHY(Module, AutoCSR): - cd = "sys0p2x" def __init__(self, device, pads, mode="master"): assert mode in ["master", "slave"] if device[:4] == "xcku": @@ -325,4 +331,4 @@ class SERWBPHY(Module, AutoCSR): self.submodules.init = _SerdesMasterInit(self.serdes, taps) else: self.submodules.init = _SerdesSlaveInit(self.serdes, taps) - self.submodules.control = _SerdesControl(self.init, mode) + self.submodules.control = _SerdesControl(self.serdes, self.init, mode) diff --git a/artiq/gateware/serwb/s7phy.py b/artiq/gateware/serwb/s7phy.py index a345d6823..fcd77da48 100644 --- a/artiq/gateware/serwb/s7phy.py +++ b/artiq/gateware/serwb/s7phy.py @@ -1,18 +1,26 @@ from migen import * -from migen.genlib.resetsync import AsyncResetSynchronizer -from migen.genlib.cdc import MultiReg, Gearbox from migen.genlib.misc import BitSlip +from migen.genlib.misc import WaitTimer +from misoc.interconnect import stream from misoc.cores.code_8b10b import Encoder, Decoder +def K(x, y): + return (y << 5) | x + + +@ResetInserter() class S7Serdes(Module): def __init__(self, pads, mode="master"): if mode == "slave": self.refclk = Signal() + self.tx_ce = Signal() self.tx_k = Signal(4) self.tx_d = Signal(32) + + self.rx_ce = Signal() self.rx_k = Signal(4) self.rx_d = Signal(32) @@ -24,44 +32,30 @@ class S7Serdes(Module): self.rx_bitslip_value = Signal(6) self.rx_delay_rst = Signal() self.rx_delay_inc = Signal() - self.rx_delay_ce = Signal() # # # - self.submodules.encoder = ClockDomainsRenamer("sys0p2x")( - Encoder(4, True)) - self.decoders = [ClockDomainsRenamer("sys0p2x")( - Decoder(True)) for _ in range(4)] - self.submodules += self.decoders + self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) + self.comb += encoder.ce.eq(self.tx_ce) + self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] + self.comb += [decoders[i].ce.eq(self.rx_ce) for i in range(4)] # clocking: - # In master mode: - # - linerate/10 slave refclk generated on clk_pads + # In Master mode: + # - linerate/10 refclk is generated on clk_pads # In Slave mode: - # - linerate/10 refclk provided by clk_pads - - # control/status cdc - tx_idle = Signal() - tx_comma = Signal() - rx_idle = Signal() - rx_comma = Signal() - rx_bitslip_value = Signal(6) - self.specials += [ - MultiReg(self.tx_idle, tx_idle, "sys0p2x"), - MultiReg(self.tx_comma, tx_comma, "sys0p2x"), - MultiReg(rx_idle, self.rx_idle, "sys"), - MultiReg(rx_comma, self.rx_comma, "sys") - ] - self.specials += MultiReg(self.rx_bitslip_value, rx_bitslip_value, "sys0p2x"), + # - linerate/10 refclk is provided by clk_pads # tx clock (linerate/10) if mode == "master": - self.submodules.tx_clk_gearbox = Gearbox(40, "sys0p2x", 8, "sys") - self.comb += self.tx_clk_gearbox.i.eq((0b1111100000 << 30) | - (0b1111100000 << 20) | - (0b1111100000 << 10) | - (0b1111100000 << 0)) + clk_converter = stream.Converter(40, 8) + self.submodules += clk_converter + self.comb += [ + clk_converter.sink.valid.eq(1), + clk_converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), + clk_converter.source.ready.eq(1) + ] clk_o = Signal() self.specials += [ Instance("OSERDESE2", @@ -73,10 +67,10 @@ class S7Serdes(Module): i_OCE=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D1=self.tx_clk_gearbox.o[0], i_D2=self.tx_clk_gearbox.o[1], - i_D3=self.tx_clk_gearbox.o[2], i_D4=self.tx_clk_gearbox.o[3], - i_D5=self.tx_clk_gearbox.o[4], i_D6=self.tx_clk_gearbox.o[5], - i_D7=self.tx_clk_gearbox.o[6], i_D8=self.tx_clk_gearbox.o[7] + i_D1=clk_converter.source.data[0], i_D2=clk_converter.source.data[1], + i_D3=clk_converter.source.data[2], i_D4=clk_converter.source.data[3], + i_D5=clk_converter.source.data[4], i_D6=clk_converter.source.data[5], + i_D7=clk_converter.source.data[6], i_D8=clk_converter.source.data[7] ), Instance("OBUFDS", i_I=clk_o, @@ -86,29 +80,32 @@ class S7Serdes(Module): ] # tx datapath - # tx_data -> encoders -> gearbox -> serdes - self.submodules.tx_gearbox = Gearbox(40, "sys0p2x", 8, "sys") + # tx_data -> encoders -> converter -> serdes + self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) self.comb += [ - If(tx_comma, - self.encoder.k[0].eq(1), - self.encoder.d[0].eq(0xbc) + tx_converter.sink.valid.eq(1), + self.tx_ce.eq(tx_converter.sink.ready), + tx_converter.source.ready.eq(1), + If(self.tx_idle, + tx_converter.sink.data.eq(0) ).Else( - self.encoder.k[0].eq(self.tx_k[0]), - self.encoder.k[1].eq(self.tx_k[1]), - self.encoder.k[2].eq(self.tx_k[2]), - self.encoder.k[3].eq(self.tx_k[3]), - self.encoder.d[0].eq(self.tx_d[0:8]), - self.encoder.d[1].eq(self.tx_d[8:16]), - self.encoder.d[2].eq(self.tx_d[16:24]), - self.encoder.d[3].eq(self.tx_d[24:32]) + tx_converter.sink.data.eq( + Cat(*[encoder.output[i] for i in range(4)])) + ), + If(self.tx_comma, + encoder.k[0].eq(1), + encoder.d[0].eq(K(28,5)), + ).Else( + encoder.k[0].eq(self.tx_k[0]), + encoder.k[1].eq(self.tx_k[1]), + encoder.k[2].eq(self.tx_k[2]), + encoder.k[3].eq(self.tx_k[3]), + encoder.d[0].eq(self.tx_d[0:8]), + encoder.d[1].eq(self.tx_d[8:16]), + encoder.d[2].eq(self.tx_d[16:24]), + encoder.d[3].eq(self.tx_d[24:32]) ) ] - self.sync.sys0p2x += \ - If(tx_idle, - self.tx_gearbox.i.eq(0) - ).Else( - self.tx_gearbox.i.eq(Cat(*[self.encoder.output[i] for i in range(4)])) - ) serdes_o = Signal() self.specials += [ @@ -121,10 +118,10 @@ class S7Serdes(Module): i_OCE=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D1=self.tx_gearbox.o[0], i_D2=self.tx_gearbox.o[1], - i_D3=self.tx_gearbox.o[2], i_D4=self.tx_gearbox.o[3], - i_D5=self.tx_gearbox.o[4], i_D6=self.tx_gearbox.o[5], - i_D7=self.tx_gearbox.o[6], i_D8=self.tx_gearbox.o[7] + i_D1=tx_converter.source.data[0], i_D2=tx_converter.source.data[1], + i_D3=tx_converter.source.data[2], i_D4=tx_converter.source.data[3], + i_D5=tx_converter.source.data[4], i_D6=tx_converter.source.data[5], + i_D7=tx_converter.source.data[6], i_D8=tx_converter.source.data[7] ), Instance("OBUFDS", i_I=serdes_o, @@ -156,9 +153,14 @@ class S7Serdes(Module): self.comb += self.refclk.eq(clk_i_bufg) # rx datapath - # serdes -> gearbox -> bitslip -> decoders -> rx_data - self.submodules.rx_gearbox = Gearbox(8, "sys", 40, "sys0p2x") - self.submodules.rx_bitslip = ClockDomainsRenamer("sys0p2x")(BitSlip(40)) + # serdes -> converter -> bitslip -> decoders -> rx_data + self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) + self.comb += [ + self.rx_ce.eq(rx_converter.source.valid), + rx_converter.source.ready.eq(1) + ] + self.submodules.rx_bitslip = rx_bitslip = CEInserter()(BitSlip(40)) + self.comb += rx_bitslip.ce.eq(self.rx_ce) serdes_i_nodelay = Signal() self.specials += [ @@ -180,8 +182,8 @@ class S7Serdes(Module): i_C=ClockSignal(), i_LD=self.rx_delay_rst, - i_CE=self.rx_delay_ce, - i_LDPIPEEN=0, i_INC=self.rx_delay_inc, + i_CE=self.rx_delay_inc, + i_LDPIPEEN=0, i_INC=1, i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed ), @@ -204,19 +206,20 @@ class S7Serdes(Module): ] self.comb += [ - self.rx_gearbox.i.eq(serdes_q), - self.rx_bitslip.value.eq(rx_bitslip_value), - self.rx_bitslip.i.eq(self.rx_gearbox.o), - self.decoders[0].input.eq(self.rx_bitslip.o[0:10]), - self.decoders[1].input.eq(self.rx_bitslip.o[10:20]), - self.decoders[2].input.eq(self.rx_bitslip.o[20:30]), - self.decoders[3].input.eq(self.rx_bitslip.o[30:40]), - self.rx_k.eq(Cat(*[self.decoders[i].k for i in range(4)])), - self.rx_d.eq(Cat(*[self.decoders[i].d for i in range(4)])), - rx_idle.eq(self.rx_bitslip.o == 0), - rx_comma.eq(((self.decoders[0].d == 0xbc) & (self.decoders[0].k == 1)) & - ((self.decoders[1].d == 0x00) & (self.decoders[1].k == 0)) & - ((self.decoders[2].d == 0x00) & (self.decoders[2].k == 0)) & - ((self.decoders[3].d == 0x00) & (self.decoders[3].k == 0))) + rx_converter.sink.valid.eq(1), + rx_converter.sink.data.eq(serdes_q), + rx_bitslip.value.eq(self.rx_bitslip_value), + rx_bitslip.i.eq(rx_converter.source.data), + decoders[0].input.eq(rx_bitslip.o[0:10]), + decoders[1].input.eq(rx_bitslip.o[10:20]), + decoders[2].input.eq(rx_bitslip.o[20:30]), + decoders[3].input.eq(rx_bitslip.o[30:40]), + self.rx_k.eq(Cat(*[decoders[i].k for i in range(4)])), + self.rx_d.eq(Cat(*[decoders[i].d for i in range(4)])), + self.rx_comma.eq((decoders[0].k == 1) & (decoders[0].d == K(28,5))) + ] - ] + idle_timer = WaitTimer(32) + self.submodules += idle_timer + self.comb += idle_timer.wait.eq(1) + self.sync += self.rx_idle.eq(idle_timer.done & (rx_bitslip.o == 0)) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 6ff2f73ed..0dd27d30a 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -174,7 +174,7 @@ class Standalone(MiniSoC, AMPSoC): self.submodules.serwb_phy_amc = serwb_phy_amc self.csr_devices.append("serwb_phy_amc") - serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave", with_scrambling=True) + serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave", with_scrambling=False) self.submodules += serwb_core self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 08ed4245c..49b95a92c 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -168,7 +168,7 @@ class SaymaRTM(Module): self.comb += self.crg.serwb_refclk.eq(serwb_phy_rtm.serdes.refclk) csr_devices.append("serwb_phy_rtm") - serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master", with_scrambling=True) + serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master", with_scrambling=False) self.submodules += serwb_core # process CSR devices and connect them to serwb From c8a08375f86859dc3cbcdd32168c11355c976c80 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 7 Apr 2018 03:03:44 +0200 Subject: [PATCH 0591/2457] serwb: replace valid/ready with stb/ack --- artiq/gateware/serwb/kusphy.py | 16 ++++++++-------- artiq/gateware/serwb/s7phy.py | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/artiq/gateware/serwb/kusphy.py b/artiq/gateware/serwb/kusphy.py index cfd10d94b..8abcb08d3 100644 --- a/artiq/gateware/serwb/kusphy.py +++ b/artiq/gateware/serwb/kusphy.py @@ -53,9 +53,9 @@ class KUSSerdes(Module): clk_converter = stream.Converter(40, 8) self.submodules += clk_converter self.comb += [ - clk_converter.sink.valid.eq(1), + clk_converter.sink.stb.eq(1), clk_converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), - clk_converter.source.ready.eq(1) + clk_converter.source.ack.eq(1) ] clk_o = Signal() self.specials += [ @@ -80,9 +80,9 @@ class KUSSerdes(Module): # tx_data -> encoders -> converter -> serdes self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) self.comb += [ - tx_converter.sink.valid.eq(1), - self.tx_ce.eq(tx_converter.sink.ready), - tx_converter.source.ready.eq(1), + tx_converter.sink.stb.eq(1), + self.tx_ce.eq(tx_converter.sink.ack), + tx_converter.source.ack.eq(1), If(self.tx_idle, tx_converter.sink.data.eq(0) ).Else( @@ -148,8 +148,8 @@ class KUSSerdes(Module): # serdes -> converter -> bitslip -> decoders -> rx_data self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) self.comb += [ - self.rx_ce.eq(rx_converter.source.valid), - rx_converter.source.ready.eq(1) + self.rx_ce.eq(rx_converter.source.stb), + rx_converter.source.ack.eq(1) ] self.submodules.rx_bitslip = rx_bitslip = CEInserter()(BitSlip(40)) self.comb += rx_bitslip.ce.eq(self.rx_ce) @@ -195,7 +195,7 @@ class KUSSerdes(Module): ] self.comb += [ - rx_converter.sink.valid.eq(1), + rx_converter.sink.stb.eq(1), rx_converter.sink.data.eq(serdes_q), rx_bitslip.value.eq(self.rx_bitslip_value), rx_bitslip.i.eq(rx_converter.source.data), diff --git a/artiq/gateware/serwb/s7phy.py b/artiq/gateware/serwb/s7phy.py index fcd77da48..df4930572 100644 --- a/artiq/gateware/serwb/s7phy.py +++ b/artiq/gateware/serwb/s7phy.py @@ -52,9 +52,9 @@ class S7Serdes(Module): clk_converter = stream.Converter(40, 8) self.submodules += clk_converter self.comb += [ - clk_converter.sink.valid.eq(1), + clk_converter.sink.stb.eq(1), clk_converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), - clk_converter.source.ready.eq(1) + clk_converter.source.ack.eq(1) ] clk_o = Signal() self.specials += [ @@ -83,9 +83,9 @@ class S7Serdes(Module): # tx_data -> encoders -> converter -> serdes self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) self.comb += [ - tx_converter.sink.valid.eq(1), - self.tx_ce.eq(tx_converter.sink.ready), - tx_converter.source.ready.eq(1), + tx_converter.sink.stb.eq(1), + self.tx_ce.eq(tx_converter.sink.ack), + tx_converter.source.ack.eq(1), If(self.tx_idle, tx_converter.sink.data.eq(0) ).Else( @@ -156,8 +156,8 @@ class S7Serdes(Module): # serdes -> converter -> bitslip -> decoders -> rx_data self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) self.comb += [ - self.rx_ce.eq(rx_converter.source.valid), - rx_converter.source.ready.eq(1) + self.rx_ce.eq(rx_converter.source.stb), + rx_converter.source.ack.eq(1) ] self.submodules.rx_bitslip = rx_bitslip = CEInserter()(BitSlip(40)) self.comb += rx_bitslip.ce.eq(self.rx_ce) @@ -206,7 +206,7 @@ class S7Serdes(Module): ] self.comb += [ - rx_converter.sink.valid.eq(1), + rx_converter.sink.stb.eq(1), rx_converter.sink.data.eq(serdes_q), rx_bitslip.value.eq(self.rx_bitslip_value), rx_bitslip.i.eq(rx_converter.source.data), From 1fd96eb0fdfe11a3fa0d74291cfbac4f3862fe28 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 7 Apr 2018 03:06:19 +0200 Subject: [PATCH 0592/2457] serwb: replace valid/ready with stb/ack --- artiq/gateware/serwb/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/serwb/core.py b/artiq/gateware/serwb/core.py index a49d7231c..f7e13acd5 100644 --- a/artiq/gateware/serwb/core.py +++ b/artiq/gateware/serwb/core.py @@ -33,16 +33,16 @@ class SERWBCore(Module): packetizer.source.connect(tx_fifo.sink), tx_fifo.source.connect(scrambler.sink), If(phy.init.ready, - If(scrambler.source.valid, + If(scrambler.source.stb, phy.serdes.tx_k.eq(scrambler.source.k), phy.serdes.tx_d.eq(scrambler.source.d) ), - scrambler.source.ready.eq(phy.serdes.tx_ce) + scrambler.source.ack.eq(phy.serdes.tx_ce) ), # phy --> core If(phy.init.ready, - descrambler.sink.valid.eq(phy.serdes.rx_ce), + descrambler.sink.stb.eq(phy.serdes.rx_ce), descrambler.sink.k.eq(phy.serdes.rx_k), descrambler.sink.d.eq(phy.serdes.rx_d) ), From 2f8bd022f778be1f8f0d45cbf10a78d869ce7e20 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 7 Apr 2018 03:10:34 +0200 Subject: [PATCH 0593/2457] sayma_rtm: remove sys0p2x clock --- artiq/gateware/targets/sayma_rtm.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 49b95a92c..30981ed54 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -21,7 +21,6 @@ from artiq import __version__ as artiq_version class CRG(Module): def __init__(self, platform): - self.clock_domains.cd_sys0p2x = ClockDomain() self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_sys4x = ClockDomain() self.clock_domains.cd_clk200 = ClockDomain() @@ -30,7 +29,6 @@ class CRG(Module): pll_locked = Signal() pll_fb = Signal() - pll_sys0p2x = Signal() pll_sys = Signal() pll_sys4x = Signal() pll_clk200 = Signal() @@ -43,23 +41,18 @@ class CRG(Module): p_CLKFBOUT_MULT=10, p_DIVCLK_DIVIDE=1, i_CLKIN1=self.serwb_refclk, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, - # 25MHz - p_CLKOUT0_DIVIDE=40, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_sys0p2x, - # 125MHz - p_CLKOUT1_DIVIDE=8, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=pll_sys, + p_CLKOUT0_DIVIDE=8, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_sys, # 500MHz - p_CLKOUT2_DIVIDE=2, p_CLKOUT2_PHASE=0.0, o_CLKOUT2=pll_sys4x, + p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=pll_sys4x, # 200MHz - p_CLKOUT3_DIVIDE=5, p_CLKOUT3_PHASE=0.0, o_CLKOUT3=pll_clk200 + p_CLKOUT2_DIVIDE=5, p_CLKOUT2_PHASE=0.0, o_CLKOUT2=pll_clk200 ), - Instance("BUFG", i_I=pll_sys0p2x, o_O=self.cd_sys0p2x.clk), Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk), Instance("BUFG", i_I=pll_sys4x, o_O=self.cd_sys4x.clk), Instance("BUFG", i_I=pll_clk200, o_O=self.cd_clk200.clk), - AsyncResetSynchronizer(self.cd_sys0p2x, ~pll_locked), AsyncResetSynchronizer(self.cd_sys, ~pll_locked), AsyncResetSynchronizer(self.cd_sys4x, ~pll_locked), AsyncResetSynchronizer(self.cd_clk200, ~pll_locked) From 9d0e8c27ffe48e751dfb696d5a27bd1af3c4262f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 7 Apr 2018 14:51:17 +0200 Subject: [PATCH 0594/2457] serwb/scrambler: add flow control --- artiq/gateware/serwb/scrambler.py | 48 +++++++++++++++++++------------ 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/artiq/gateware/serwb/scrambler.py b/artiq/gateware/serwb/scrambler.py index 83f8b5a55..79b98e15a 100644 --- a/artiq/gateware/serwb/scrambler.py +++ b/artiq/gateware/serwb/scrambler.py @@ -11,6 +11,7 @@ def K(x, y): @ResetInserter() +@CEInserter() class _Scrambler(Module): def __init__(self, n_io, n_state=23, taps=[17, 22]): self.i = Signal(n_io) @@ -38,26 +39,35 @@ class Scrambler(Module): if enable: # scrambler - scrambler = _Scrambler(32) - self.submodules += scrambler - self.comb += scrambler.i.eq(sink.data) + self.submodules.scrambler = scrambler = _Scrambler(32) # insert K.29.7 as sync character # every sync_interval cycles count = Signal(max=sync_interval) - self.sync += count.eq(count + 1) - self.comb += [ - If(count == 0, - scrambler.reset.eq(1), - source.stb.eq(1), - source.k[0].eq(1), - source.d[:8].eq(K(29, 7)) - ).Else( - sink.ack.eq(source.ack), - source.stb.eq(sink.stb), - source.d.eq(scrambler.o) + self.submodules.fsm = fsm = FSM(reset_state="SYNC") + fsm.act("SYNC", + scrambler.reset.eq(1), + source.stb.eq(1), + source.k[0].eq(1), + source.d[:8].eq(K(29, 7)), + NextValue(count, 0), + If(source.ack, + NextState("DATA") ) - ] + ) + fsm.act("DATA", + scrambler.i.eq(sink.data), + sink.ack.eq(source.ack), + source.stb.eq(1), + source.d.eq(scrambler.o), + If(source.stb & source.ack, + scrambler.ce.eq(1), + NextValue(count, count + 1), + If(count == (sync_interval - 1), + NextState("SYNC") + ) + ) + ) else: self.comb += [ sink.connect(source, omit={"data"}), @@ -75,8 +85,7 @@ class Descrambler(Module): if enable: # descrambler - descrambler = _Scrambler(32) - self.submodules += descrambler + self.submodules.descrambler = descrambler = _Scrambler(32) self.comb += descrambler.i.eq(sink.d) # detect K29.7 and synchronize descrambler @@ -89,7 +98,10 @@ class Descrambler(Module): ).Else( sink.ack.eq(source.ack), source.stb.eq(sink.stb), - source.data.eq(descrambler.o) + source.data.eq(descrambler.o), + If(source.stb & source.ack, + descrambler.ce.eq(1) + ) ) ] else: From e15f8aa903d30144ee73e38fe447f747ac04a0d9 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 7 Apr 2018 14:52:37 +0200 Subject: [PATCH 0595/2457] sayma/serwb: enable scrambling --- artiq/gateware/targets/sayma_amc.py | 2 +- artiq/gateware/targets/sayma_rtm.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 0dd27d30a..6ff2f73ed 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -174,7 +174,7 @@ class Standalone(MiniSoC, AMPSoC): self.submodules.serwb_phy_amc = serwb_phy_amc self.csr_devices.append("serwb_phy_amc") - serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave", with_scrambling=False) + serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave", with_scrambling=True) self.submodules += serwb_core self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 30981ed54..f93f154e8 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -161,7 +161,7 @@ class SaymaRTM(Module): self.comb += self.crg.serwb_refclk.eq(serwb_phy_rtm.serdes.refclk) csr_devices.append("serwb_phy_rtm") - serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master", with_scrambling=False) + serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master", with_scrambling=True) self.submodules += serwb_core # process CSR devices and connect them to serwb From 73dbc0b6b64a94f00de4553d8ebcb16cccd83913 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 7 Apr 2018 15:09:29 +0200 Subject: [PATCH 0596/2457] serwb/test: adapt to new version --- artiq/gateware/test/serwb/test_serwb_core.py | 35 ++++++++++++++------ artiq/gateware/test/serwb/test_serwb_init.py | 23 +------------ 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/artiq/gateware/test/serwb/test_serwb_core.py b/artiq/gateware/test/serwb/test_serwb_core.py index 96260399c..90900f1d3 100644 --- a/artiq/gateware/test/serwb/test_serwb_core.py +++ b/artiq/gateware/test/serwb/test_serwb_core.py @@ -11,32 +11,39 @@ from misoc.interconnect.wishbone import SRAM class FakeInit(Module): def __init__(self): - self.ready = 1 + self.ready = Signal(reset=1) class FakeSerdes(Module): def __init__(self): + self.tx_ce = Signal() self.tx_k = Signal(4) self.tx_d = Signal(32) + self.rx_ce = Signal() self.rx_k = Signal(4) self.rx_d = Signal(32) + # # # + + data_ce = Signal(5, reset=0b00001) + self.sync += data_ce.eq(Cat(data_ce[1:], data_ce[0])) + + self.comb += [ + self.tx_ce.eq(data_ce[0]), + self.rx_ce.eq(data_ce[0]) + ] class FakePHY(Module): - cd = "sys" def __init__(self): - self.init = FakeInit() - self.serdes = FakeSerdes() + self.submodules.init = FakeInit() + self.submodules.serdes = FakeSerdes() class DUTScrambler(Module): def __init__(self): self.submodules.scrambler = scrambler.Scrambler(sync_interval=16) self.submodules.descrambler = scrambler.Descrambler() - self.comb += [ - self.scrambler.source.connect(self.descrambler.sink), - self.descrambler.source.ack.eq(1) - ] + self.comb += self.scrambler.source.connect(self.descrambler.sink) class DUTCore(Module): @@ -53,8 +60,11 @@ class DUTCore(Module): # connect phy self.comb += [ + phy_master.serdes.rx_ce.eq(phy_slave.serdes.tx_ce), phy_master.serdes.rx_k.eq(phy_slave.serdes.tx_k), phy_master.serdes.rx_d.eq(phy_slave.serdes.tx_d), + + phy_slave.serdes.rx_ce.eq(phy_master.serdes.tx_ce), phy_slave.serdes.rx_k.eq(phy_master.serdes.tx_k), phy_slave.serdes.rx_d.eq(phy_master.serdes.tx_d) ] @@ -70,16 +80,21 @@ class DUTCore(Module): class TestSERWBCore(unittest.TestCase): def test_scrambler(self): def generator(dut): + # prepare test + prng = random.Random(42) i = 0 last_data = -1 + # test loop while i != 256: # stim - if (yield dut.scrambler.sink.ack): + yield dut.scrambler.sink.valid.eq(1) + if (yield dut.scrambler.sink.valid) & (yield dut.scrambler.sink.ready): i += 1 yield dut.scrambler.sink.data.eq(i) # check - if (yield dut.descrambler.source.stb): + yield dut.descrambler.source.ready.eq(prng.randrange(2)) + if (yield dut.descrambler.source.valid) & (yield dut.descrambler.source.ready): current_data = (yield dut.descrambler.source.data) if (current_data != (last_data + 1)): dut.errors += 1 diff --git a/artiq/gateware/test/serwb/test_serwb_init.py b/artiq/gateware/test/serwb/test_serwb_init.py index 2e488165f..c64d59e45 100644 --- a/artiq/gateware/test/serwb/test_serwb_init.py +++ b/artiq/gateware/test/serwb/test_serwb_init.py @@ -17,7 +17,6 @@ class SerdesModel(Module): self.rx_bitslip_value = Signal(6) self.rx_delay_rst = Signal() self.rx_delay_inc = Signal() - self.rx_delay_ce = Signal() self.valid_bitslip = Signal(6) self.valid_delays = Signal(taps) @@ -35,7 +34,7 @@ class SerdesModel(Module): bitslip.eq(self.rx_bitslip_value), If(self.rx_delay_rst, delay.eq(0) - ).Elif(self.rx_delay_inc & self.rx_delay_ce, + ).Elif(self.rx_delay_inc, delay.eq(delay + 1) ) ] @@ -123,16 +122,6 @@ class TestSERWBInit(unittest.TestCase): run_simulation(dut, generator(self, dut, valid_bitslip, valid_delays, True)) def test_master_init_failure(self): - # partial window at the beginning - dut = DUTMaster() - valid_bitslip = 2 - valid_delays = 0b11000000000000000000000000000000 - run_simulation(dut, generator(self, dut, valid_bitslip, valid_delays, False)) - # partial window at the end - dut = DUTMaster() - valid_bitslip = 2 - valid_delays = 0b00000000000000000000000000000011 - run_simulation(dut, generator(self, dut, valid_bitslip, valid_delays, False)) # too small window dut = DUTMaster() valid_bitslip = 2 @@ -146,16 +135,6 @@ class TestSERWBInit(unittest.TestCase): run_simulation(dut, generator(self, dut, valid_bitslip, valid_delays, True)) def test_slave_init_failure(self): - # partial window at the beginning - dut = DUTSlave() - valid_bitslip = 2 - valid_delays = 0b11000000000000000000000000000000 - run_simulation(dut, generator(self, dut, valid_bitslip, valid_delays, False)) - # partial window at the end - dut = DUTSlave() - valid_bitslip = 2 - valid_delays = 0b00000000000000000000000000000011 - run_simulation(dut, generator(self, dut, valid_bitslip, valid_delays, False)) # too small window dut = DUTSlave() valid_bitslip = 2 From 6aa8e2c433d31ca0f514ef10c8bd94936eeadcd9 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 7 Apr 2018 15:55:57 +0200 Subject: [PATCH 0597/2457] serwb/test: replace valid/ready with stb/ack --- artiq/gateware/test/serwb/test_serwb_core.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/test/serwb/test_serwb_core.py b/artiq/gateware/test/serwb/test_serwb_core.py index 90900f1d3..be7539125 100644 --- a/artiq/gateware/test/serwb/test_serwb_core.py +++ b/artiq/gateware/test/serwb/test_serwb_core.py @@ -63,7 +63,7 @@ class DUTCore(Module): phy_master.serdes.rx_ce.eq(phy_slave.serdes.tx_ce), phy_master.serdes.rx_k.eq(phy_slave.serdes.tx_k), phy_master.serdes.rx_d.eq(phy_slave.serdes.tx_d), - + phy_slave.serdes.rx_ce.eq(phy_master.serdes.tx_ce), phy_slave.serdes.rx_k.eq(phy_master.serdes.tx_k), phy_slave.serdes.rx_d.eq(phy_master.serdes.tx_d) @@ -87,14 +87,14 @@ class TestSERWBCore(unittest.TestCase): # test loop while i != 256: # stim - yield dut.scrambler.sink.valid.eq(1) - if (yield dut.scrambler.sink.valid) & (yield dut.scrambler.sink.ready): + yield dut.scrambler.sink.stb.eq(1) + if (yield dut.scrambler.sink.stb) & (yield dut.scrambler.sink.ack): i += 1 yield dut.scrambler.sink.data.eq(i) # check - yield dut.descrambler.source.ready.eq(prng.randrange(2)) - if (yield dut.descrambler.source.valid) & (yield dut.descrambler.source.ready): + yield dut.descrambler.source.ack.eq(prng.randrange(2)) + if (yield dut.descrambler.source.stb) & (yield dut.descrambler.source.ack): current_data = (yield dut.descrambler.source.data) if (current_data != (last_data + 1)): dut.errors += 1 From bb90fb7d59070b423fd4ada21bb5d40eaaa137da Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 7 Apr 2018 15:57:57 +0200 Subject: [PATCH 0598/2457] sayma/serwb: remove scrambling (does not seems to work on sayma for now...) --- artiq/gateware/targets/sayma_amc.py | 2 +- artiq/gateware/targets/sayma_rtm.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 6ff2f73ed..0dd27d30a 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -174,7 +174,7 @@ class Standalone(MiniSoC, AMPSoC): self.submodules.serwb_phy_amc = serwb_phy_amc self.csr_devices.append("serwb_phy_amc") - serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave", with_scrambling=True) + serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave", with_scrambling=False) self.submodules += serwb_core self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index f93f154e8..30981ed54 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -161,7 +161,7 @@ class SaymaRTM(Module): self.comb += self.crg.serwb_refclk.eq(serwb_phy_rtm.serdes.refclk) csr_devices.append("serwb_phy_rtm") - serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master", with_scrambling=True) + serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master", with_scrambling=False) self.submodules += serwb_core # process CSR devices and connect them to serwb From 4e21a13be0c1e9d468eafff0fc48bf48aee97a01 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 7 Apr 2018 23:32:31 +0000 Subject: [PATCH 0599/2457] conda: put requirements on correct artiq-board package. Fixes #975. --- conda/artiq-board/meta.yaml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index a25dac139..465f4ab93 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -18,12 +18,11 @@ outputs: noarch: generic files: - lib - -requirements: - build: - - artiq-dev {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} - run: - - artiq {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} + requirements: + build: + - artiq-dev {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} + run: + - artiq {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} about: home: https://m-labs.hk/artiq From 1ef673c2d43c3c13a2e4bffbc6209b75035a5503 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 8 Apr 2018 02:34:34 +0000 Subject: [PATCH 0600/2457] conda: split build/run requirements for artiq-board. Build requirements for packages in the outputs section seem to be ignored. --- conda/artiq-board/meta.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index 465f4ab93..3174bce65 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -19,11 +19,13 @@ outputs: files: - lib requirements: - build: - - artiq-dev {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} run: - artiq {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} +requirements: + build: + - artiq-dev {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} + about: home: https://m-labs.hk/artiq license: LGPL From f96f597ecbffd6ca66f11a94ae705db0ebf90e2c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Apr 2018 15:15:07 +0800 Subject: [PATCH 0601/2457] doc: update Sinara information --- README.rst | 8 +++----- doc/manual/introduction.rst | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index dd54d3dd6..5f6397c8b 100644 --- a/README.rst +++ b/README.rst @@ -9,11 +9,9 @@ It is maintained and developed by `M-Labs `_ and the initial The system features a high-level programming language that helps describing complex experiments, which is compiled and executed on dedicated hardware with nanosecond timing resolution and sub-microsecond latency. It includes graphical user interfaces to parametrize and schedule experiments and to visualize and explore the results. -ARTIQ uses FPGA hardware to perform its time-critical tasks. -It is designed to be portable to hardware platforms from different vendors and FPGA manufacturers. -Currently, several different configurations of a `high-end FPGA evaluation kit `_ are used and supported. This FPGA platform can be combined with any number of additional peripherals, either already accessible from ARTIQ or made accessible with little effort. - -Custom hardware components with widely extended capabilities and advanced support for scalable and fully distributed real-time control of experiments `are being designed `_. +ARTIQ uses FPGA hardware to perform its time-critical tasks. The `Sinara hardware `_, and in particular the Kasli FPGA carrier, is designed to work with ARTIQ. +ARTIQ is designed to be portable to hardware platforms from different vendors and FPGA manufacturers. +Several different configurations of a `high-end FPGA evaluation kit `_ are also used and supported. FPGA platforms can be combined with any number of additional peripherals, either already accessible from ARTIQ or made accessible with little effort. ARTIQ and its dependencies are available in the form of `conda packages `_ for both Linux and Windows. Packages containing pre-compiled binary images to be loaded onto the hardware platforms are supplied for each configuration. diff --git a/doc/manual/introduction.rst b/doc/manual/introduction.rst index 821f8ef8f..d628d2554 100644 --- a/doc/manual/introduction.rst +++ b/doc/manual/introduction.rst @@ -10,11 +10,9 @@ It is maintained and developed by `M-Labs `_ and the initial The system features a high-level programming language that helps describing complex experiments, which is compiled and executed on dedicated hardware with nanosecond timing resolution and sub-microsecond latency. It includes graphical user interfaces to parametrize and schedule experiments and to visualize and explore the results. -ARTIQ uses FPGA hardware to perform its time-critical tasks. -It is designed to be portable to hardware platforms from different vendors and FPGA manufacturers. -Currently, several different configurations of a `high-end FPGA evaluation kit `_ are used and supported. This FPGA platform can be combined with any number of additional peripherals, either already accessible from ARTIQ or made accessible with little effort. - -Custom hardware components with widely extended capabilities and advanced support for scalable and fully distributed real-time control of experiments `are being designed `_. +ARTIQ uses FPGA hardware to perform its time-critical tasks. The `Sinara hardware `_, and in particular the Kasli FPGA carrier, is designed to work with ARTIQ. +ARTIQ is designed to be portable to hardware platforms from different vendors and FPGA manufacturers. +Several different configurations of a `high-end FPGA evaluation kit `_ are also used and supported. FPGA platforms can be combined with any number of additional peripherals, either already accessible from ARTIQ or made accessible with little effort. ARTIQ and its dependencies are available in the form of `conda packages `_ for both Linux and Windows. Packages containing pre-compiled binary images to be loaded onto the hardware platforms are supplied for each configuration. From 825a2158ba8333ff5d32f999af3de8bf346df64b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 16 Apr 2018 22:44:03 +0200 Subject: [PATCH 0602/2457] serwb: add phy_width parameter to allow reducing linerate to 500Mbps or 250Mbps --- artiq/gateware/serwb/kusphy.py | 43 ++++++++++++++++++++++++----- artiq/gateware/serwb/phy.py | 6 ++--- artiq/gateware/serwb/s7phy.py | 49 +++++++++++++++++++++++++++------- 3 files changed, 80 insertions(+), 18 deletions(-) diff --git a/artiq/gateware/serwb/kusphy.py b/artiq/gateware/serwb/kusphy.py index 8abcb08d3..9917a1c77 100644 --- a/artiq/gateware/serwb/kusphy.py +++ b/artiq/gateware/serwb/kusphy.py @@ -12,7 +12,8 @@ def K(x, y): @ResetInserter() class KUSSerdes(Module): - def __init__(self, pads, mode="master"): + def __init__(self, pads, mode="master", phy_width=8): + assert phy_width in [2, 4, 8] if mode == "slave": self.refclk = Signal() @@ -78,7 +79,7 @@ class KUSSerdes(Module): # tx datapath # tx_data -> encoders -> converter -> serdes - self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) + self.submodules.tx_converter = tx_converter = stream.Converter(40, phy_width) self.comb += [ tx_converter.sink.stb.eq(1), self.tx_ce.eq(tx_converter.sink.ack), @@ -105,6 +106,22 @@ class KUSSerdes(Module): ] serdes_o = Signal() + serdes_d = Signal(8) + if phy_width == 2: + self.comb += [ + serdes_d[0:4].eq(Replicate(tx_converter.source.data[0], 4)), + serdes_d[4:8].eq(Replicate(tx_converter.source.data[1], 4)) + ] + elif phy_width == 4: + self.comb += [ + serdes_d[0:2].eq(Replicate(tx_converter.source.data[0], 2)), + serdes_d[2:4].eq(Replicate(tx_converter.source.data[1], 2)), + serdes_d[4:6].eq(Replicate(tx_converter.source.data[2], 2)), + serdes_d[6:8].eq(Replicate(tx_converter.source.data[3], 2)) + ] + else: + self.comb += serdes_d.eq(tx_converter.source.data) + self.specials += [ Instance("OSERDESE3", p_DATA_WIDTH=8, p_INIT=0, @@ -113,7 +130,7 @@ class KUSSerdes(Module): o_OQ=serdes_o, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D=tx_converter.source.data + i_D=serdes_d ), Instance("OBUFDS", i_I=serdes_o, @@ -146,7 +163,7 @@ class KUSSerdes(Module): # rx datapath # serdes -> converter -> bitslip -> decoders -> rx_data - self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) + self.submodules.rx_converter = rx_converter = stream.Converter(phy_width, 40) self.comb += [ self.rx_ce.eq(rx_converter.source.stb), rx_converter.source.ack.eq(1) @@ -194,9 +211,23 @@ class KUSSerdes(Module): ) ] + self.comb += rx_converter.sink.stb.eq(1) + if phy_width == 2: + self.comb += [ + rx_converter.sink.data[0].eq(serdes_q[0]), + rx_converter.sink.data[1].eq(serdes_q[4]) + ] + elif phy_width == 4: + self.comb += [ + rx_converter.sink.data[0].eq(serdes_q[0]), + rx_converter.sink.data[1].eq(serdes_q[2]), + rx_converter.sink.data[2].eq(serdes_q[4]), + rx_converter.sink.data[3].eq(serdes_q[6]), + ] + else: + self.comb += rx_converter.sink.data.eq(serdes_q) + self.comb += [ - rx_converter.sink.stb.eq(1), - rx_converter.sink.data.eq(serdes_q), rx_bitslip.value.eq(self.rx_bitslip_value), rx_bitslip.i.eq(rx_converter.source.data), decoders[0].input.eq(rx_bitslip.o[0:10]), diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index 46083f0fa..0ce3aa8ca 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -317,14 +317,14 @@ class _SerdesControl(Module, AutoCSR): class SERWBPHY(Module, AutoCSR): - def __init__(self, device, pads, mode="master"): + def __init__(self, device, pads, mode="master", phy_width=8): assert mode in ["master", "slave"] if device[:4] == "xcku": taps = 512 - self.submodules.serdes = KUSSerdes(pads, mode) + self.submodules.serdes = KUSSerdes(pads, mode, phy_width) elif device[:4] == "xc7a": taps = 32 - self.submodules.serdes = S7Serdes(pads, mode) + self.submodules.serdes = S7Serdes(pads, mode, phy_width) else: raise NotImplementedError if mode == "master": diff --git a/artiq/gateware/serwb/s7phy.py b/artiq/gateware/serwb/s7phy.py index df4930572..d7947be1c 100644 --- a/artiq/gateware/serwb/s7phy.py +++ b/artiq/gateware/serwb/s7phy.py @@ -12,7 +12,8 @@ def K(x, y): @ResetInserter() class S7Serdes(Module): - def __init__(self, pads, mode="master"): + def __init__(self, pads, mode="master", phy_width=8): + assert phy_width in [2, 4, 8] if mode == "slave": self.refclk = Signal() @@ -81,7 +82,7 @@ class S7Serdes(Module): # tx datapath # tx_data -> encoders -> converter -> serdes - self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) + self.submodules.tx_converter = tx_converter = stream.Converter(40, phy_width) self.comb += [ tx_converter.sink.stb.eq(1), self.tx_ce.eq(tx_converter.sink.ack), @@ -108,6 +109,22 @@ class S7Serdes(Module): ] serdes_o = Signal() + serdes_d = Signal(8) + if phy_width == 2: + self.comb += [ + serdes_d[0:4].eq(Replicate(tx_converter.source.data[0], 4)), + serdes_d[4:8].eq(Replicate(tx_converter.source.data[1], 4)) + ] + elif phy_width == 4: + self.comb += [ + serdes_d[0:2].eq(Replicate(tx_converter.source.data[0], 2)), + serdes_d[2:4].eq(Replicate(tx_converter.source.data[1], 2)), + serdes_d[4:6].eq(Replicate(tx_converter.source.data[2], 2)), + serdes_d[6:8].eq(Replicate(tx_converter.source.data[3], 2)) + ] + else: + self.comb += serdes_d.eq(tx_converter.source.data) + self.specials += [ Instance("OSERDESE2", p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, @@ -118,10 +135,10 @@ class S7Serdes(Module): i_OCE=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D1=tx_converter.source.data[0], i_D2=tx_converter.source.data[1], - i_D3=tx_converter.source.data[2], i_D4=tx_converter.source.data[3], - i_D5=tx_converter.source.data[4], i_D6=tx_converter.source.data[5], - i_D7=tx_converter.source.data[6], i_D8=tx_converter.source.data[7] + i_D1=serdes_d[0], i_D2=serdes_d[1], + i_D3=serdes_d[2], i_D4=serdes_d[3], + i_D5=serdes_d[4], i_D6=serdes_d[5], + i_D7=serdes_d[6], i_D8=serdes_d[7] ), Instance("OBUFDS", i_I=serdes_o, @@ -154,7 +171,7 @@ class S7Serdes(Module): # rx datapath # serdes -> converter -> bitslip -> decoders -> rx_data - self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) + self.submodules.rx_converter = rx_converter = stream.Converter(phy_width, 40) self.comb += [ self.rx_ce.eq(rx_converter.source.stb), rx_converter.source.ack.eq(1) @@ -205,9 +222,23 @@ class S7Serdes(Module): ) ] + self.comb += rx_converter.sink.stb.eq(1) + if phy_width == 2: + self.comb += [ + rx_converter.sink.data[0].eq(serdes_q[3]), + rx_converter.sink.data[1].eq(serdes_q[7]) + ] + elif phy_width == 4: + self.comb += [ + rx_converter.sink.data[0].eq(serdes_q[1]), + rx_converter.sink.data[1].eq(serdes_q[3]), + rx_converter.sink.data[2].eq(serdes_q[5]), + rx_converter.sink.data[3].eq(serdes_q[7]), + ] + else: + self.comb += rx_converter.sink.data.eq(serdes_q) + self.comb += [ - rx_converter.sink.stb.eq(1), - rx_converter.sink.data.eq(serdes_q), rx_bitslip.value.eq(self.rx_bitslip_value), rx_bitslip.i.eq(rx_converter.source.data), decoders[0].input.eq(rx_bitslip.o[0:10]), From ca01c8f1cbcf921872cae2403bee12633b0b2fad Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 16 Apr 2018 22:45:33 +0200 Subject: [PATCH 0603/2457] sayma: reduce serwb linerate to 500Mbps --- artiq/gateware/targets/sayma_amc.py | 2 +- artiq/gateware/targets/sayma_rtm.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 0dd27d30a..7a175f8fd 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -170,7 +170,7 @@ class Standalone(MiniSoC, AMPSoC): # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") - serwb_phy_amc = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="master") + serwb_phy_amc = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="master", phy_width=4) self.submodules.serwb_phy_amc = serwb_phy_amc self.csr_devices.append("serwb_phy_amc") diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 30981ed54..efd491b5d 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -156,7 +156,7 @@ class SaymaRTM(Module): # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") platform.add_period_constraint(serwb_pads.clk_p, 10.) - serwb_phy_rtm = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="slave") + serwb_phy_rtm = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="slave", phy_width=4) self.submodules.serwb_phy_rtm = serwb_phy_rtm self.comb += self.crg.serwb_refclk.eq(serwb_phy_rtm.serdes.refclk) csr_devices.append("serwb_phy_rtm") From 1acd7ea1db1cbc8fe714adeb76e090bda2f671ad Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 17 Apr 2018 00:49:36 +0200 Subject: [PATCH 0604/2457] sayma/serwb: re-enable scrambling --- artiq/gateware/targets/sayma_amc.py | 2 +- artiq/gateware/targets/sayma_rtm.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 7a175f8fd..896a00ae7 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -174,7 +174,7 @@ class Standalone(MiniSoC, AMPSoC): self.submodules.serwb_phy_amc = serwb_phy_amc self.csr_devices.append("serwb_phy_amc") - serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave", with_scrambling=False) + serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave", with_scrambling=True) self.submodules += serwb_core self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index efd491b5d..22e2580fb 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -161,7 +161,7 @@ class SaymaRTM(Module): self.comb += self.crg.serwb_refclk.eq(serwb_phy_rtm.serdes.refclk) csr_devices.append("serwb_phy_rtm") - serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master", with_scrambling=False) + serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master", with_scrambling=True) self.submodules += serwb_core # process CSR devices and connect them to serwb From 142561c4bd12d2df2b850f56983e61fd49733c18 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Apr 2018 18:46:35 +0800 Subject: [PATCH 0605/2457] conda: bump misoc --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 8b30e7925..979032302 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_23+gitf4180e9 - - misoc 0.11 py35_3+git4c010df2 + - misoc 0.11 py35_6+gitea742b67 - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27 From 756e120c270b038db9fecd3490381ed0931ce230 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Apr 2018 18:46:55 +0800 Subject: [PATCH 0606/2457] kasli/sysu: add comments --- artiq/gateware/targets/kasli.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b9f8320bb..b90680470 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -549,6 +549,7 @@ class SYSU(_StandaloneBase): # EEM clock fan-out from Si5324, not MMCX self.comb += platform.request("clk_sel").eq(1) + # EEM2-6: TTL rtio_channels = [] for i in range(40): eem_offset, port = divmod(i, 8) @@ -557,6 +558,7 @@ class SYSU(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) + # EEM0, EEM1: Urukul phy = spi2.SPIMaster(self.platform.request("eem1_spi_p"), self.platform.request("eem1_spi_n")) self.submodules += phy From eac447278fd788ec2b0462c97292c4fd0580c5d4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Apr 2018 18:48:22 +0800 Subject: [PATCH 0607/2457] kasli: add MITLL variant --- artiq/examples/kasli_mitll/device_db.py | 155 ++++++++++++++++++ artiq/examples/kasli_mitll/repository/demo.py | 52 ++++++ artiq/frontend/artiq_flash.py | 2 +- artiq/gateware/targets/kasli.py | 69 +++++++- 4 files changed, 276 insertions(+), 2 deletions(-) create mode 100644 artiq/examples/kasli_mitll/device_db.py create mode 100644 artiq/examples/kasli_mitll/repository/demo.py diff --git a/artiq/examples/kasli_mitll/device_db.py b/artiq/examples/kasli_mitll/device_db.py new file mode 100644 index 000000000..f828fe8f1 --- /dev/null +++ b/artiq/examples/kasli_mitll/device_db.py @@ -0,0 +1,155 @@ +core_addr = "kasli-2.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + +for i in range(8): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": i}, + } + +device_db.update( + spi_urukul0={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 9} + }, + ttl_urukul0_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 10} + }, + ttl_urukul0_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 11} + }, + ttl_urukul0_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 12} + }, + ttl_urukul0_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 13} + }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 14} + }, + urukul0_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul0_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } + +for i in range(2): + device_db["spi_zotino{}".format(i)] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 15+3*i+0} + }, + device_db["ttl_zotino{}_ldac".format(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 15+3*i+1} + }, + device_db["ttl_zotino{}_clr".format(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 15+3*i+2} + }, + device_db["zotino{}".format(i)] = { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino{}".format(i), + "ldac_device": "ttl_zotino{}_ldac".format(i), + "clr_device": "ttl_zotino{}_clr".format(i) + } + } + +device_db.update( + led0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 18} + }, + led1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 19} + } +) diff --git a/artiq/examples/kasli_mitll/repository/demo.py b/artiq/examples/kasli_mitll/repository/demo.py new file mode 100644 index 000000000..bdb3b9361 --- /dev/null +++ b/artiq/examples/kasli_mitll/repository/demo.py @@ -0,0 +1,52 @@ +from artiq.experiment import * + + +class UrukulTest(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("urukul0_cpld") + self.setattr_device("urukul0_ch0") + self.setattr_device("urukul0_ch1") + self.setattr_device("urukul0_ch2") + self.setattr_device("urukul0_ch3") + self.setattr_device("led0") + self.ttl = self.get_device("ttl16") + + @kernel + def run(self): + self.core.reset() + self.ttl.output() + delay(1*us) + + self.urukul0_cpld.init() + self.urukul0_ch0.init() + self.urukul0_ch1.init() + self.urukul0_ch2.init() + self.urukul0_ch3.init() + + delay(1000*us) + self.urukul0_ch0.set(10*MHz) + self.urukul0_ch0.sw.on() + self.urukul0_ch0.set_att(10.) + + delay(1000*us) + self.urukul0_ch1.set(20*MHz, 0.5) + self.urukul0_ch1.sw.on() + self.urukul0_ch1.set_att(8.) + + delay(1000*us) + self.urukul0_ch2.set(30*MHz) + self.urukul0_ch2.sw.on() + self.urukul0_ch2.set_att(6.) + + delay(1000*us) + self.urukul0_ch3.set(40*MHz) + self.urukul0_ch3.sw.on() + self.urukul0_ch3.set_att(4.) + + while True: + with parallel: + self.ttl.pulse(100*ms) + self.urukul0_ch0.sw.pulse(100*ms) + delay(100*ms) + self.led0.pulse(100*ms) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 4b614aa98..8023dac56 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -265,7 +265,7 @@ def main(): }, "kasli": { "programmer": partial(ProgrammerXC7, board="kasli", proxy="bscan_spi_xc7a100t.bit"), - "variants": ["opticlock", "suservo", "sysu", "master", "satellite"], + "variants": ["opticlock", "suservo", "sysu", "mitll", "master", "satellite"], "gateware": ("spi0", 0x000000), "bootloader": ("spi0", 0x400000), "storage": ("spi0", 0x440000), diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b90680470..a6cd054c3 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -586,6 +586,71 @@ class SYSU(_StandaloneBase): self.add_rtio(rtio_channels) +class MITLL(_StandaloneBase): + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + + platform = self.platform + # TODO: grabber on eem0->eemB eem1->eemA + platform.add_extension(_urukul("eem3", "eem2")) + platform.add_extension(_dio("eem4")) + platform.add_extension(_zotino("eem5")) + platform.add_extension(_zotino("eem6")) + + # EEM4: TTL + rtio_channels = [] + for i in range(8): + pads = platform.request("eem4", i) + phy = ttl_serdes_7series.InOut_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + # EEM2, EEM3: Urukul + phy = spi2.SPIMaster(self.platform.request("eem3_spi_p"), + self.platform.request("eem3_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + pads = platform.request("eem3_dds_reset") + self.specials += DifferentialOutput(0, pads.p, pads.n) + + for signal in "io_update sw0 sw1 sw2 sw3".split(): + pads = platform.request("eem3_{}".format(signal)) + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + # EEM5, EEM6: Zotino + for i in (5, 6): + phy = spi2.SPIMaster(self.platform.request("eem{}_spi_p".format(i)), + self.platform.request("eem{}_spi_n".format(i))) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + for signal in "ldac_n clr_n".split(): + pads = platform.request("eem{}_{}".format(i, signal)) + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + for i in (1, 2): + sfp_ctl = platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) + rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(rtio_channels) + + class _RTIOClockMultiplier(Module): def __init__(self, rtio_clk_freq): self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) @@ -895,7 +960,7 @@ def main(): soc_kasli_args(parser) parser.set_defaults(output_dir="artiq_kasli") parser.add_argument("-V", "--variant", default="opticlock", - help="variant: opticlock/suservo/sysu/master/satellite " + help="variant: opticlock/suservo/sysu/mitll/master/satellite " "(default: %(default)s)") args = parser.parse_args() @@ -906,6 +971,8 @@ def main(): cls = SUServo elif variant == "sysu": cls = SYSU + elif variant == "mitll": + cls = MITLL elif variant == "master": cls = Master elif variant == "satellite": From 79f4892e227e814da4d6d799221a0e17890d111e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Apr 2018 20:15:17 +0800 Subject: [PATCH 0608/2457] kasli/mitll: fix RTIO channel numbers --- artiq/examples/kasli_mitll/device_db.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/artiq/examples/kasli_mitll/device_db.py b/artiq/examples/kasli_mitll/device_db.py index f828fe8f1..45f13457b 100644 --- a/artiq/examples/kasli_mitll/device_db.py +++ b/artiq/examples/kasli_mitll/device_db.py @@ -51,37 +51,37 @@ device_db.update( "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 9} + "arguments": {"channel": 8} }, ttl_urukul0_io_update={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 10} + "arguments": {"channel": 9} }, ttl_urukul0_sw0={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 11} + "arguments": {"channel": 10} }, ttl_urukul0_sw1={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 12} + "arguments": {"channel": 11} }, ttl_urukul0_sw2={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 13} + "arguments": {"channel": 12} }, ttl_urukul0_sw3={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 14} + "arguments": {"channel": 13} }, urukul0_cpld={ "type": "local", @@ -114,19 +114,19 @@ for i in range(2): "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 15+3*i+0} + "arguments": {"channel": 14+3*i+0} }, device_db["ttl_zotino{}_ldac".format(i)] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 15+3*i+1} + "arguments": {"channel": 14+3*i+1} }, device_db["ttl_zotino{}_clr".format(i)] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 15+3*i+2} + "arguments": {"channel": 14+3*i+2} }, device_db["zotino{}".format(i)] = { "type": "local", @@ -144,12 +144,12 @@ device_db.update( "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 18} + "arguments": {"channel": 20} }, led1={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 19} - } + "arguments": {"channel": 21} + }, ) From 48b48e44ddc22919e04f4d30c29a882afbefc2cd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Apr 2018 20:15:38 +0800 Subject: [PATCH 0609/2457] kasli/mitll: fix demo --- artiq/examples/kasli_mitll/repository/demo.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/examples/kasli_mitll/repository/demo.py b/artiq/examples/kasli_mitll/repository/demo.py index bdb3b9361..eafb6d4ea 100644 --- a/artiq/examples/kasli_mitll/repository/demo.py +++ b/artiq/examples/kasli_mitll/repository/demo.py @@ -10,7 +10,8 @@ class UrukulTest(EnvExperiment): self.setattr_device("urukul0_ch2") self.setattr_device("urukul0_ch3") self.setattr_device("led0") - self.ttl = self.get_device("ttl16") + self.setattr_device("led1") + self.ttl = self.get_device("ttl0") @kernel def run(self): @@ -50,3 +51,4 @@ class UrukulTest(EnvExperiment): self.urukul0_ch0.sw.pulse(100*ms) delay(100*ms) self.led0.pulse(100*ms) + self.led1.pulse(100*ms) From c86d41edc6ab7c299963ec3df7cc42be50c705fc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 18 Apr 2018 00:58:34 +0800 Subject: [PATCH 0610/2457] conda: update migen+misoc --- conda/artiq-dev/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 979032302..1fb1c112a 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,8 +14,8 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_23+gitf4180e9 - - misoc 0.11 py35_6+gitea742b67 + - migen 0.7 py35_26+git4039322 + - misoc 0.11 py35_7+git269b6502 - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27 From 816a6f2ec7f24a554d6666421bb23f66590eaae5 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 17 Apr 2018 19:19:18 +0200 Subject: [PATCH 0611/2457] serwb/phys: remove phy_width (revert linerate to 1Gbps) --- artiq/gateware/serwb/kusphy.py | 43 +++++------------------------ artiq/gateware/serwb/s7phy.py | 49 +++++++--------------------------- 2 files changed, 15 insertions(+), 77 deletions(-) diff --git a/artiq/gateware/serwb/kusphy.py b/artiq/gateware/serwb/kusphy.py index 9917a1c77..8abcb08d3 100644 --- a/artiq/gateware/serwb/kusphy.py +++ b/artiq/gateware/serwb/kusphy.py @@ -12,8 +12,7 @@ def K(x, y): @ResetInserter() class KUSSerdes(Module): - def __init__(self, pads, mode="master", phy_width=8): - assert phy_width in [2, 4, 8] + def __init__(self, pads, mode="master"): if mode == "slave": self.refclk = Signal() @@ -79,7 +78,7 @@ class KUSSerdes(Module): # tx datapath # tx_data -> encoders -> converter -> serdes - self.submodules.tx_converter = tx_converter = stream.Converter(40, phy_width) + self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) self.comb += [ tx_converter.sink.stb.eq(1), self.tx_ce.eq(tx_converter.sink.ack), @@ -106,22 +105,6 @@ class KUSSerdes(Module): ] serdes_o = Signal() - serdes_d = Signal(8) - if phy_width == 2: - self.comb += [ - serdes_d[0:4].eq(Replicate(tx_converter.source.data[0], 4)), - serdes_d[4:8].eq(Replicate(tx_converter.source.data[1], 4)) - ] - elif phy_width == 4: - self.comb += [ - serdes_d[0:2].eq(Replicate(tx_converter.source.data[0], 2)), - serdes_d[2:4].eq(Replicate(tx_converter.source.data[1], 2)), - serdes_d[4:6].eq(Replicate(tx_converter.source.data[2], 2)), - serdes_d[6:8].eq(Replicate(tx_converter.source.data[3], 2)) - ] - else: - self.comb += serdes_d.eq(tx_converter.source.data) - self.specials += [ Instance("OSERDESE3", p_DATA_WIDTH=8, p_INIT=0, @@ -130,7 +113,7 @@ class KUSSerdes(Module): o_OQ=serdes_o, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D=serdes_d + i_D=tx_converter.source.data ), Instance("OBUFDS", i_I=serdes_o, @@ -163,7 +146,7 @@ class KUSSerdes(Module): # rx datapath # serdes -> converter -> bitslip -> decoders -> rx_data - self.submodules.rx_converter = rx_converter = stream.Converter(phy_width, 40) + self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) self.comb += [ self.rx_ce.eq(rx_converter.source.stb), rx_converter.source.ack.eq(1) @@ -211,23 +194,9 @@ class KUSSerdes(Module): ) ] - self.comb += rx_converter.sink.stb.eq(1) - if phy_width == 2: - self.comb += [ - rx_converter.sink.data[0].eq(serdes_q[0]), - rx_converter.sink.data[1].eq(serdes_q[4]) - ] - elif phy_width == 4: - self.comb += [ - rx_converter.sink.data[0].eq(serdes_q[0]), - rx_converter.sink.data[1].eq(serdes_q[2]), - rx_converter.sink.data[2].eq(serdes_q[4]), - rx_converter.sink.data[3].eq(serdes_q[6]), - ] - else: - self.comb += rx_converter.sink.data.eq(serdes_q) - self.comb += [ + rx_converter.sink.stb.eq(1), + rx_converter.sink.data.eq(serdes_q), rx_bitslip.value.eq(self.rx_bitslip_value), rx_bitslip.i.eq(rx_converter.source.data), decoders[0].input.eq(rx_bitslip.o[0:10]), diff --git a/artiq/gateware/serwb/s7phy.py b/artiq/gateware/serwb/s7phy.py index d7947be1c..df4930572 100644 --- a/artiq/gateware/serwb/s7phy.py +++ b/artiq/gateware/serwb/s7phy.py @@ -12,8 +12,7 @@ def K(x, y): @ResetInserter() class S7Serdes(Module): - def __init__(self, pads, mode="master", phy_width=8): - assert phy_width in [2, 4, 8] + def __init__(self, pads, mode="master"): if mode == "slave": self.refclk = Signal() @@ -82,7 +81,7 @@ class S7Serdes(Module): # tx datapath # tx_data -> encoders -> converter -> serdes - self.submodules.tx_converter = tx_converter = stream.Converter(40, phy_width) + self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) self.comb += [ tx_converter.sink.stb.eq(1), self.tx_ce.eq(tx_converter.sink.ack), @@ -109,22 +108,6 @@ class S7Serdes(Module): ] serdes_o = Signal() - serdes_d = Signal(8) - if phy_width == 2: - self.comb += [ - serdes_d[0:4].eq(Replicate(tx_converter.source.data[0], 4)), - serdes_d[4:8].eq(Replicate(tx_converter.source.data[1], 4)) - ] - elif phy_width == 4: - self.comb += [ - serdes_d[0:2].eq(Replicate(tx_converter.source.data[0], 2)), - serdes_d[2:4].eq(Replicate(tx_converter.source.data[1], 2)), - serdes_d[4:6].eq(Replicate(tx_converter.source.data[2], 2)), - serdes_d[6:8].eq(Replicate(tx_converter.source.data[3], 2)) - ] - else: - self.comb += serdes_d.eq(tx_converter.source.data) - self.specials += [ Instance("OSERDESE2", p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, @@ -135,10 +118,10 @@ class S7Serdes(Module): i_OCE=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D1=serdes_d[0], i_D2=serdes_d[1], - i_D3=serdes_d[2], i_D4=serdes_d[3], - i_D5=serdes_d[4], i_D6=serdes_d[5], - i_D7=serdes_d[6], i_D8=serdes_d[7] + i_D1=tx_converter.source.data[0], i_D2=tx_converter.source.data[1], + i_D3=tx_converter.source.data[2], i_D4=tx_converter.source.data[3], + i_D5=tx_converter.source.data[4], i_D6=tx_converter.source.data[5], + i_D7=tx_converter.source.data[6], i_D8=tx_converter.source.data[7] ), Instance("OBUFDS", i_I=serdes_o, @@ -171,7 +154,7 @@ class S7Serdes(Module): # rx datapath # serdes -> converter -> bitslip -> decoders -> rx_data - self.submodules.rx_converter = rx_converter = stream.Converter(phy_width, 40) + self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) self.comb += [ self.rx_ce.eq(rx_converter.source.stb), rx_converter.source.ack.eq(1) @@ -222,23 +205,9 @@ class S7Serdes(Module): ) ] - self.comb += rx_converter.sink.stb.eq(1) - if phy_width == 2: - self.comb += [ - rx_converter.sink.data[0].eq(serdes_q[3]), - rx_converter.sink.data[1].eq(serdes_q[7]) - ] - elif phy_width == 4: - self.comb += [ - rx_converter.sink.data[0].eq(serdes_q[1]), - rx_converter.sink.data[1].eq(serdes_q[3]), - rx_converter.sink.data[2].eq(serdes_q[5]), - rx_converter.sink.data[3].eq(serdes_q[7]), - ] - else: - self.comb += rx_converter.sink.data.eq(serdes_q) - self.comb += [ + rx_converter.sink.stb.eq(1), + rx_converter.sink.data.eq(serdes_q), rx_bitslip.value.eq(self.rx_bitslip_value), rx_bitslip.i.eq(rx_converter.source.data), decoders[0].input.eq(rx_bitslip.o[0:10]), From ebfac36223951998060c5f7b89b123003b84092f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 17 Apr 2018 19:20:06 +0200 Subject: [PATCH 0612/2457] serwb/scrambler: dynamic enable/disable --- artiq/gateware/serwb/scrambler.py | 122 +++++++++++++++--------------- 1 file changed, 62 insertions(+), 60 deletions(-) diff --git a/artiq/gateware/serwb/scrambler.py b/artiq/gateware/serwb/scrambler.py index 79b98e15a..e1e8ac17e 100644 --- a/artiq/gateware/serwb/scrambler.py +++ b/artiq/gateware/serwb/scrambler.py @@ -31,81 +31,83 @@ class _Scrambler(Module): class Scrambler(Module): - def __init__(self, sync_interval=1024, enable=True): + def __init__(self, sync_interval=1024): + self.enable = Signal() self.sink = sink = stream.Endpoint([("data", 32)]) self.source = source = stream.Endpoint([("d", 32), ("k", 4)]) # # # - if enable: - # scrambler - self.submodules.scrambler = scrambler = _Scrambler(32) + # scrambler + self.submodules.scrambler = scrambler = _Scrambler(32) - # insert K.29.7 as sync character - # every sync_interval cycles - count = Signal(max=sync_interval) - self.submodules.fsm = fsm = FSM(reset_state="SYNC") - fsm.act("SYNC", - scrambler.reset.eq(1), - source.stb.eq(1), - source.k[0].eq(1), - source.d[:8].eq(K(29, 7)), - NextValue(count, 0), - If(source.ack, - NextState("DATA") + # insert K.29.7 as sync character + # every sync_interval cycles + count = Signal(max=sync_interval) + self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="DISABLE")) + self.comb += fsm.reset.eq(~self.enable) + fsm.act("DISABLE", + sink.connect(source, omit={"data"}), + source.k.eq(0b0000), + source.d.eq(sink.data), + NextState("SYNC") + ) + fsm.act("SYNC", + scrambler.reset.eq(1), + source.stb.eq(1), + source.k[0].eq(1), + source.d[:8].eq(K(29, 7)), + NextValue(count, 0), + If(source.ack, + NextState("DATA") + ) + ) + fsm.act("DATA", + scrambler.i.eq(sink.data), + sink.ack.eq(source.ack), + source.stb.eq(1), + source.d.eq(scrambler.o), + If(source.stb & source.ack, + scrambler.ce.eq(1), + NextValue(count, count + 1), + If(count == (sync_interval - 1), + NextState("SYNC") ) ) - fsm.act("DATA", - scrambler.i.eq(sink.data), - sink.ack.eq(source.ack), - source.stb.eq(1), - source.d.eq(scrambler.o), - If(source.stb & source.ack, - scrambler.ce.eq(1), - NextValue(count, count + 1), - If(count == (sync_interval - 1), - NextState("SYNC") - ) - ) - ) - else: - self.comb += [ - sink.connect(source, omit={"data"}), - source.k.eq(0b0000), - source.d.eq(sink.data) - ] + ) class Descrambler(Module): - def __init__(self, enable=True): + def __init__(self): + self.enable = Signal() self.sink = sink = stream.Endpoint([("d", 32), ("k", 4)]) self.source = source = stream.Endpoint([("data", 32)]) # # # - if enable: - # descrambler - self.submodules.descrambler = descrambler = _Scrambler(32) - self.comb += descrambler.i.eq(sink.d) + # descrambler + self.submodules.descrambler = descrambler = _Scrambler(32) + self.comb += descrambler.i.eq(sink.d) - # detect K29.7 and synchronize descrambler - self.comb += [ - descrambler.reset.eq(0), - If((sink.k[0] == 1) & - (sink.d[:8] == K(29,7)), - sink.ack.eq(1), - descrambler.reset.eq(1) - ).Else( - sink.ack.eq(source.ack), - source.stb.eq(sink.stb), - source.data.eq(descrambler.o), - If(source.stb & source.ack, - descrambler.ce.eq(1) - ) + # detect K29.7 and synchronize descrambler + self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="DISABLE")) + self.comb += fsm.reset.eq(~self.enable) + fsm.act("DISABLE", + sink.connect(source, omit={"d", "k"}), + source.data.eq(sink.d), + NextState("SYNC_DATA") + ) + fsm.act("SYNC_DATA", + If((sink.k[0] == 1) & + (sink.d[:8] == K(29,7)), + sink.ack.eq(1), + descrambler.reset.eq(1) + ).Else( + sink.ack.eq(source.ack), + source.stb.eq(sink.stb), + source.data.eq(descrambler.o), + If(source.stb & source.ack, + descrambler.ce.eq(1) ) - ] - else: - self.comb += [ - sink.connect(source, omit={"d", "k"}), - source.data.eq(sink.d) - ] + ) + ) From 20ccc9d82fcc609c804253a618d5f510e9402508 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 17 Apr 2018 19:21:21 +0200 Subject: [PATCH 0613/2457] serwb/core/phy: move scrambler in phy, add link test, revert delay min/max checks --- artiq/gateware/serwb/core.py | 24 ++-------- artiq/gateware/serwb/phy.py | 92 ++++++++++++++++++++++++++++++++---- 2 files changed, 86 insertions(+), 30 deletions(-) diff --git a/artiq/gateware/serwb/core.py b/artiq/gateware/serwb/core.py index f7e13acd5..a3109e4fd 100644 --- a/artiq/gateware/serwb/core.py +++ b/artiq/gateware/serwb/core.py @@ -2,13 +2,12 @@ from migen import * from misoc.interconnect import stream -from artiq.gateware.serwb.scrambler import Scrambler, Descrambler from artiq.gateware.serwb.packet import Packetizer, Depacketizer from artiq.gateware.serwb.etherbone import Etherbone class SERWBCore(Module): - def __init__(self, phy, clk_freq, mode, with_scrambling=False): + def __init__(self, phy, clk_freq, mode): # etherbone self.submodules.etherbone = etherbone = Etherbone(mode) @@ -22,31 +21,14 @@ class SERWBCore(Module): rx_fifo = stream.SyncFIFO([("data", 32)], 16) self.submodules += tx_fifo, rx_fifo - # scrambling - scrambler = Scrambler(enable=with_scrambling) - descrambler = Descrambler(enable=with_scrambling) - self.submodules += scrambler, descrambler - # modules connection self.comb += [ # core --> phy packetizer.source.connect(tx_fifo.sink), - tx_fifo.source.connect(scrambler.sink), - If(phy.init.ready, - If(scrambler.source.stb, - phy.serdes.tx_k.eq(scrambler.source.k), - phy.serdes.tx_d.eq(scrambler.source.d) - ), - scrambler.source.ack.eq(phy.serdes.tx_ce) - ), + tx_fifo.source.connect(phy.sink), # phy --> core - If(phy.init.ready, - descrambler.sink.stb.eq(phy.serdes.rx_ce), - descrambler.sink.k.eq(phy.serdes.rx_k), - descrambler.sink.d.eq(phy.serdes.rx_d) - ), - descrambler.source.connect(rx_fifo.sink), + phy.source.connect(rx_fifo.sink), rx_fifo.source.connect(depacketizer.sink), # etherbone <--> core diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index 0ce3aa8ca..fe6885ab9 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -2,8 +2,10 @@ from migen import * from migen.genlib.cdc import MultiReg, PulseSynchronizer from migen.genlib.misc import WaitTimer +from misoc.interconnect import stream from misoc.interconnect.csr import * +from artiq.gateware.serwb.scrambler import Scrambler, Descrambler from artiq.gateware.serwb.kusphy import KUSSerdes from artiq.gateware.serwb.s7phy import S7Serdes @@ -110,7 +112,9 @@ class _SerdesMasterInit(Module): serdes.tx_comma.eq(1) ) fsm.act("CHECK_SAMPLING_WINDOW", - If((delay_max - delay_min) < taps//16, + If((delay_min == 0) | + (delay_max == (taps - 1)) | + ((delay_max - delay_min) < taps//16), NextValue(delay_min_found, 0), NextValue(delay_max_found, 0), NextState("WAIT_STABLE") @@ -231,7 +235,9 @@ class _SerdesSlaveInit(Module, AutoCSR): serdes.tx_idle.eq(1) ) fsm.act("CHECK_SAMPLING_WINDOW", - If((delay_max - delay_min) < taps//16, + If((delay_min == 0) | + (delay_max == (taps - 1)) | + ((delay_max - delay_min) < taps//16), NextValue(delay_min_found, 0), NextValue(delay_max_found, 0), NextState("WAIT_STABLE") @@ -289,18 +295,25 @@ class _SerdesControl(Module, AutoCSR): self.delay_max = CSRStatus(9) self.bitslip = CSRStatus(6) + self.scrambling_enable = CSRStorage() + + self.prbs_error = Signal() + self.prbs_start = CSR() + self.prbs_cycles = CSRStorage(32) + self.prbs_errors = CSRStatus(32) + # # # if mode == "master": # In Master mode, reset is coming from CSR, # it resets the Master that will also reset # the Slave by putting the link in idle. - self.comb += init.reset.eq(self.reset.re) + self.sync += init.reset.eq(self.reset.re) else: # In Slave mode, reset is coming from link, # Master reset the Slave by putting the link # in idle. - self.comb += [ + self.sync += [ init.reset.eq(serdes.rx_idle), serdes.reset.eq(serdes.rx_idle) ] @@ -315,20 +328,81 @@ class _SerdesControl(Module, AutoCSR): self.bitslip.status.eq(init.bitslip) ] + # prbs + prbs_cycles = Signal(32) + prbs_errors = self.prbs_errors.status + prbs_fsm = FSM(reset_state="IDLE") + self.submodules += prbs_fsm + prbs_fsm.act("IDLE", + NextValue(prbs_cycles, 0), + If(self.prbs_start.re, + NextValue(prbs_errors, 0), + NextState("CHECK") + ) + ) + prbs_fsm.act("CHECK", + NextValue(prbs_cycles, prbs_cycles + 1), + If(self.prbs_error, + NextValue(prbs_errors, prbs_errors + 1), + ), + If(prbs_cycles == self.prbs_cycles.storage, + NextState("IDLE") + ) + ) + class SERWBPHY(Module, AutoCSR): - def __init__(self, device, pads, mode="master", phy_width=8): + def __init__(self, device, pads, mode="master", init_timeout=2**14): + self.sink = sink = stream.Endpoint([("data", 32)]) + self.source = source = stream.Endpoint([("data", 32)]) assert mode in ["master", "slave"] if device[:4] == "xcku": taps = 512 - self.submodules.serdes = KUSSerdes(pads, mode, phy_width) + self.submodules.serdes = KUSSerdes(pads, mode) elif device[:4] == "xc7a": taps = 32 - self.submodules.serdes = S7Serdes(pads, mode, phy_width) + self.submodules.serdes = S7Serdes(pads, mode) else: raise NotImplementedError if mode == "master": - self.submodules.init = _SerdesMasterInit(self.serdes, taps) + self.submodules.init = _SerdesMasterInit(self.serdes, taps, init_timeout) else: - self.submodules.init = _SerdesSlaveInit(self.serdes, taps) + self.submodules.init = _SerdesSlaveInit(self.serdes, taps, init_timeout) self.submodules.control = _SerdesControl(self.serdes, self.init, mode) + + # scrambling + scrambler = Scrambler() + descrambler = Descrambler() + self.submodules += scrambler, descrambler + self.comb += [ + scrambler.enable.eq(self.control.scrambling_enable.storage), + descrambler.enable.eq(self.control.scrambling_enable.storage) + ] + + # tx dataflow + self.comb += \ + If(self.init.ready, + sink.connect(scrambler.sink), + scrambler.source.ack.eq(self.serdes.tx_ce), + If(scrambler.source.stb, + self.serdes.tx_d.eq(scrambler.source.d), + self.serdes.tx_k.eq(scrambler.source.k) + ) + ) + + # rx dataflow + self.comb += [ + If(self.init.ready, + descrambler.sink.stb.eq(self.serdes.rx_ce), + descrambler.sink.d.eq(self.serdes.rx_d), + descrambler.sink.k.eq(self.serdes.rx_k), + descrambler.source.connect(source) + ), + # For PRBS test we are using the scrambler/descrambler as PRBS, + # sending 0 to the scrambler and checking that descrambler + # output is always 0. + self.control.prbs_error.eq( + descrambler.source.stb & + descrambler.source.ack & + (descrambler.source.data != 0)) + ] From 8edf4541d6d8efd71f45b7313e7415103c28c83a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 17 Apr 2018 19:21:53 +0200 Subject: [PATCH 0614/2457] serwb: adapt test --- artiq/gateware/test/serwb/test_serwb_core.py | 37 ++++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/artiq/gateware/test/serwb/test_serwb_core.py b/artiq/gateware/test/serwb/test_serwb_core.py index be7539125..d0aeeaa25 100644 --- a/artiq/gateware/test/serwb/test_serwb_core.py +++ b/artiq/gateware/test/serwb/test_serwb_core.py @@ -6,6 +6,7 @@ from migen import * from artiq.gateware.serwb import scrambler from artiq.gateware.serwb import core +from misoc.interconnect import stream from misoc.interconnect.wishbone import SRAM @@ -35,9 +36,30 @@ class FakeSerdes(Module): class FakePHY(Module): def __init__(self): + self.sink = sink = stream.Endpoint([("data", 32)]) + self.source = source = stream.Endpoint([("data", 32)]) + + # # # + self.submodules.init = FakeInit() self.submodules.serdes = FakeSerdes() + # tx dataflow + self.comb += \ + If(self.init.ready, + sink.ack.eq(self.serdes.tx_ce), + If(sink.stb, + self.serdes.tx_d.eq(sink.data) + ) + ) + + # rx dataflow + self.comb += \ + If(self.init.ready, + source.stb.eq(self.serdes.rx_ce), + source.data.eq(self.serdes.rx_d) + ) + class DUTScrambler(Module): def __init__(self): @@ -47,15 +69,15 @@ class DUTScrambler(Module): class DUTCore(Module): - def __init__(self, **kwargs): + def __init__(self): # wishbone slave phy_slave = FakePHY() - serwb_slave = core.SERWBCore(phy_slave, int(1e6), "slave", **kwargs) + serwb_slave = core.SERWBCore(phy_slave, int(1e6), "slave") self.submodules += phy_slave, serwb_slave # wishbone master phy_master = FakePHY() - serwb_master = core.SERWBCore(phy_master, int(1e6), "master", **kwargs) + serwb_master = core.SERWBCore(phy_master, int(1e6), "master") self.submodules += phy_master, serwb_master # connect phy @@ -130,14 +152,7 @@ class TestSERWBCore(unittest.TestCase): if datas_r[i] != datas_w[i]: dut.errors += 1 - # scrambling off - dut = DUTCore(with_scrambling=False) - dut.errors = 0 - run_simulation(dut, generator(dut)) - self.assertEqual(dut.errors, 0) - - # scrambling on - dut = DUTCore(with_scrambling=True) + dut = DUTCore() dut.errors = 0 run_simulation(dut, generator(dut)) self.assertEqual(dut.errors, 0) From 439d2bf2bc3b236193a05e471f4d2c8863f30d6a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 17 Apr 2018 19:22:09 +0200 Subject: [PATCH 0615/2457] sayma/serwb: adapt, full reset of rtm on link reset --- artiq/gateware/targets/sayma_amc.py | 4 ++-- artiq/gateware/targets/sayma_rtm.py | 16 ++++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 896a00ae7..db2387f73 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -170,11 +170,11 @@ class Standalone(MiniSoC, AMPSoC): # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") - serwb_phy_amc = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="master", phy_width=4) + serwb_phy_amc = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="master") self.submodules.serwb_phy_amc = serwb_phy_amc self.csr_devices.append("serwb_phy_amc") - serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave", with_scrambling=True) + serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave") self.submodules += serwb_core self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 22e2580fb..07199320b 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -26,6 +26,7 @@ class CRG(Module): self.clock_domains.cd_clk200 = ClockDomain() self.serwb_refclk = Signal() + self.serwb_reset = Signal() pll_locked = Signal() pll_fb = Signal() @@ -53,9 +54,9 @@ class CRG(Module): Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk), Instance("BUFG", i_I=pll_sys4x, o_O=self.cd_sys4x.clk), Instance("BUFG", i_I=pll_clk200, o_O=self.cd_clk200.clk), - AsyncResetSynchronizer(self.cd_sys, ~pll_locked), - AsyncResetSynchronizer(self.cd_sys4x, ~pll_locked), - AsyncResetSynchronizer(self.cd_clk200, ~pll_locked) + AsyncResetSynchronizer(self.cd_sys, ~pll_locked | self.serwb_reset), + AsyncResetSynchronizer(self.cd_sys4x, ~pll_locked | self.serwb_reset), + AsyncResetSynchronizer(self.cd_clk200, ~pll_locked | self.serwb_reset) ] reset_counter = Signal(4, reset=15) @@ -156,12 +157,15 @@ class SaymaRTM(Module): # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") platform.add_period_constraint(serwb_pads.clk_p, 10.) - serwb_phy_rtm = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="slave", phy_width=4) + serwb_phy_rtm = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="slave") self.submodules.serwb_phy_rtm = serwb_phy_rtm - self.comb += self.crg.serwb_refclk.eq(serwb_phy_rtm.serdes.refclk) + self.comb += [ + self.crg.serwb_refclk.eq(serwb_phy_rtm.serdes.refclk), + self.crg.serwb_reset.eq(serwb_phy_rtm.serdes.reset) + ] csr_devices.append("serwb_phy_rtm") - serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master", with_scrambling=True) + serwb_core = serwb.core.SERWBCore(serwb_phy_rtm, int(clk_freq), mode="master") self.submodules += serwb_core # process CSR devices and connect them to serwb From fe689ab4f2c24a06d45e02ed5604c7bdf19e2f0b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 17 Apr 2018 19:24:22 +0200 Subject: [PATCH 0616/2457] firmware/serwb: add link test, use info! instead of debug! for link settings (useful to analyze logs from others boards) --- artiq/firmware/libboard_artiq/serwb.rs | 52 ++++++++++++++++---------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/artiq/firmware/libboard_artiq/serwb.rs b/artiq/firmware/libboard_artiq/serwb.rs index fea567172..20ed083e8 100644 --- a/artiq/firmware/libboard_artiq/serwb.rs +++ b/artiq/firmware/libboard_artiq/serwb.rs @@ -1,5 +1,5 @@ use core::{cmp, str}; -use board::csr; +use board::{csr, clock}; fn read_rtm_ident(buf: &mut [u8]) -> &str { unsafe { @@ -15,26 +15,26 @@ fn read_rtm_ident(buf: &mut [u8]) -> &str { } unsafe fn debug_print(rtm: bool) { - debug!("AMC serwb settings:"); - debug!(" delay_min_found: {}", csr::serwb_phy_amc::control_delay_min_found_read()); - debug!(" delay_min: {}", csr::serwb_phy_amc::control_delay_min_read()); - debug!(" delay_max_found: {}", csr::serwb_phy_amc::control_delay_max_found_read()); - debug!(" delay_max: {}", csr::serwb_phy_amc::control_delay_max_read()); - debug!(" delay: {}", csr::serwb_phy_amc::control_delay_read()); - debug!(" bitslip: {}", csr::serwb_phy_amc::control_bitslip_read()); - debug!(" ready: {}", csr::serwb_phy_amc::control_ready_read()); - debug!(" error: {}", csr::serwb_phy_amc::control_error_read()); + info!("AMC serwb settings:"); + info!(" delay_min_found: {}", csr::serwb_phy_amc::control_delay_min_found_read()); + info!(" delay_min: {}", csr::serwb_phy_amc::control_delay_min_read()); + info!(" delay_max_found: {}", csr::serwb_phy_amc::control_delay_max_found_read()); + info!(" delay_max: {}", csr::serwb_phy_amc::control_delay_max_read()); + info!(" delay: {}", csr::serwb_phy_amc::control_delay_read()); + info!(" bitslip: {}", csr::serwb_phy_amc::control_bitslip_read()); + info!(" ready: {}", csr::serwb_phy_amc::control_ready_read()); + info!(" error: {}", csr::serwb_phy_amc::control_error_read()); if rtm { - debug!("RTM serwb settings:"); - debug!(" delay_min_found: {}", csr::serwb_phy_rtm::control_delay_min_found_read()); - debug!(" delay_min: {}", csr::serwb_phy_rtm::control_delay_min_read()); - debug!(" delay_max_found: {}", csr::serwb_phy_rtm::control_delay_max_found_read()); - debug!(" delay_max: {}", csr::serwb_phy_rtm::control_delay_max_read()); - debug!(" delay: {}", csr::serwb_phy_rtm::control_delay_read()); - debug!(" bitslip: {}", csr::serwb_phy_rtm::control_bitslip_read()); - debug!(" ready: {}", csr::serwb_phy_rtm::control_ready_read()); - debug!(" error: {}", csr::serwb_phy_rtm::control_error_read()); + info!("RTM serwb settings:"); + info!(" delay_min_found: {}", csr::serwb_phy_rtm::control_delay_min_found_read()); + info!(" delay_min: {}", csr::serwb_phy_rtm::control_delay_min_read()); + info!(" delay_max_found: {}", csr::serwb_phy_rtm::control_delay_max_found_read()); + info!(" delay_max: {}", csr::serwb_phy_rtm::control_delay_max_read()); + info!(" delay: {}", csr::serwb_phy_rtm::control_delay_read()); + info!(" bitslip: {}", csr::serwb_phy_rtm::control_bitslip_read()); + info!(" ready: {}", csr::serwb_phy_rtm::control_ready_read()); + info!(" error: {}", csr::serwb_phy_rtm::control_error_read()); } } @@ -52,6 +52,20 @@ pub fn wait_init() { } info!("done."); + unsafe { + info!("RTM to AMC Link test"); + csr::serwb_phy_amc::control_prbs_cycles_write(1<<20); + csr::serwb_phy_amc::control_prbs_start_write(1); + clock::spin_us(1000000); + info!("{} errors", csr::serwb_phy_amc::control_prbs_errors_read()); + + info!("AMC to RTM Link test"); + csr::serwb_phy_rtm::control_prbs_cycles_write(1<<20); + csr::serwb_phy_rtm::control_prbs_start_write(1); + clock::spin_us(1000000); + info!("{} errors", csr::serwb_phy_rtm::control_prbs_errors_read()); + } + // Try reading the magic number register on the other side of the bridge. let rtm_magic = unsafe { csr::rtm_magic::magic_read() From 1b2a4bcbab0dd5ec58c5a456198d3bc29df60d61 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 17 Apr 2018 12:03:56 +0200 Subject: [PATCH 0617/2457] doc: add out-of-tree controller ports * newfocus8742 (https://github.com/quartiq/newfocus8742) * ptb-drivers (https://github.com/quartiq/ptb-drivers) * picam (https://github.com/quartiq/picam) --- doc/manual/default_network_ports.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/manual/default_network_ports.rst b/doc/manual/default_network_ports.rst index fb3da836d..5c2652cd6 100644 --- a/doc/manual/default_network_ports.rst +++ b/doc/manual/default_network_ports.rst @@ -36,3 +36,9 @@ Default network ports +--------------------------------+--------------+ | Korad KA3005P | 3256 | +--------------------------------+--------------+ +| Newfocus 8742 (out-of-tree) | 3257 | ++--------------------------------+--------------+ +| PICam (out-of-tree) | 3258 | ++--------------------------------+--------------+ +| PTB Drivers (out-of-tree) | 3259-3270 | ++--------------------------------+--------------+ From a4f1877085cdaf5e63a00d1ab07d3fbb8909ba58 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 17 Apr 2018 12:12:40 +0200 Subject: [PATCH 0618/2457] CONTRIBUTING: add checklist for code contributions --- CONTRIBUTING.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 14cdaa256..65fe5d11f 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -47,6 +47,30 @@ that the testsuite passes. Then prepare a pull request or send patches to the discussed. Expect your contribution to be held up to coding standards (e.g. use ``flake8`` to check yourself). +Checklist for Code Contributions +-------------------------------- + +- Test your changes or have someone test them. Mention what was tested and how. +- Use correct spelling and grammar. Use your code editor to help you with + syntax, spelling, and style +- Style: PEP-8 (``flake8``) +- Add, check docstrings and comments +- Split your contribution into logically separate changes (``git rebase + --interactive``). Merge (squash, fixup) commits that just fix previous commits + or amend them. Remove unintended changes. Clean up your commits. +- Check the copyright situation of your changes and sign off your patches + (``git commit --signoff``, see also below) +- Write meaningful commit messages containing the area of the change + and a concise description (50 characters or less) in the first line. + Describe everything else in the long explanation. +- Review each of your commits for the above items (``git show``) +- Update ``RELEASE_NOTES.md`` if there are noteworthy changes, especially if + there are changes to existing APIs +- Check, test, and update the documentation in `doc/` +- Check, test, and update the conda recipes in `conda/` +- Check, test, and update the unittests +- Close and/or update issues + Copyright and Sign-Off ---------------------- From b4e3c30d8c264f50cf8bab1f50d8f443238be841 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 20 Apr 2018 12:18:58 +0000 Subject: [PATCH 0619/2457] compiler: desugar x != y into not x == y (fixes #974). --- .../compiler/transforms/artiq_ir_generator.py | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index a2f1971dc..df274b794 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1478,7 +1478,7 @@ class ARTIQIRGenerator(algorithm.Visitor): else: assert False - def polymorphic_compare_pair_inclusion(self, op, needle, haystack): + def polymorphic_compare_pair_inclusion(self, needle, haystack): if builtins.is_range(haystack.type): # Optimized range `in` operator start = self.append(ir.GetAttr(haystack, "start")) @@ -1522,21 +1522,29 @@ class ARTIQIRGenerator(algorithm.Visitor): else: assert False - if isinstance(op, ast.NotIn): - result = self.append(ir.Select(result, - ir.Constant(False, builtins.TBool()), - ir.Constant(True, builtins.TBool()))) - return result + def invert(self, value): + return self.append(ir.Select(value, + ir.Constant(False, builtins.TBool()), + ir.Constant(True, builtins.TBool()))) + def polymorphic_compare_pair(self, op, lhs, rhs): if isinstance(op, (ast.Is, ast.IsNot)): # The backend will handle equality of aggregates. return self.append(ir.Compare(op, lhs, rhs)) - elif isinstance(op, (ast.In, ast.NotIn)): - return self.polymorphic_compare_pair_inclusion(op, lhs, rhs) - else: # Eq, NotEq, Lt, LtE, Gt, GtE + elif isinstance(op, ast.In): + return self.polymorphic_compare_pair_inclusion(lhs, rhs) + elif isinstance(op, ast.NotIn): + result = self.polymorphic_compare_pair_inclusion(lhs, rhs) + return self.invert(result) + elif isinstance(op, (ast.Eq, ast.Lt, ast.LtE, ast.Gt, ast.GtE)): return self.polymorphic_compare_pair_order(op, lhs, rhs) + elif isinstance(op, ast.NotEq): + result = self.polymorphic_compare_pair_order(ast.Eq(loc=op.loc), lhs, rhs) + return self.invert(result) + else: + assert False def visit_CompareT(self, node): # Essentially a sequence of `and`s performed over results From 0d5fd1e83d78cb88ddd33fe55e1170269d10dd7a Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 20 Apr 2018 15:26:00 +0000 Subject: [PATCH 0620/2457] runtime: fix race condition in log extraction code paths (#979). The core device used to panic if certain combinations of borrows of the log buffer happened. Now they all use .try_borrow_mut(). --- artiq/firmware/liblogger_artiq/lib.rs | 59 +++++++++++++++++++-------- artiq/firmware/runtime/mgmt.rs | 58 ++++++++++++++------------ artiq/firmware/runtime/sched.rs | 57 +++++++++++++++----------- 3 files changed, 105 insertions(+), 69 deletions(-) diff --git a/artiq/firmware/liblogger_artiq/lib.rs b/artiq/firmware/liblogger_artiq/lib.rs index 2d7dd531b..8ccfdc6fb 100644 --- a/artiq/firmware/liblogger_artiq/lib.rs +++ b/artiq/firmware/liblogger_artiq/lib.rs @@ -5,12 +5,43 @@ extern crate log_buffer; #[macro_use] extern crate board; -use core::cell::{Cell, RefCell}; +use core::cell::{Cell, RefCell, RefMut}; use core::fmt::Write; use log::{Log, LevelFilter}; use log_buffer::LogBuffer; use board::clock; +pub struct LogBufferRef<'a> { + buffer: RefMut<'a, LogBuffer<&'static mut [u8]>>, + old_log_level: LevelFilter +} + +impl<'a> LogBufferRef<'a> { + fn new(buffer: RefMut<'a, LogBuffer<&'static mut [u8]>>) -> LogBufferRef<'a> { + let old_log_level = log::max_level(); + log::set_max_level(LevelFilter::Off); + LogBufferRef { buffer, old_log_level } + } + + pub fn is_empty(&mut self) -> bool { + self.buffer.extract().len() == 0 + } + + pub fn clear(&mut self) { + self.buffer.clear() + } + + pub fn extract(&mut self) -> &str { + self.buffer.extract() + } +} + +impl<'a> Drop for LogBufferRef<'a> { + fn drop(&mut self) { + log::set_max_level(self.old_log_level) + } +} + pub struct BufferLogger { buffer: RefCell>, uart_filter: Cell @@ -40,20 +71,11 @@ impl BufferLogger { f(unsafe { &*LOGGER }) } - pub fn clear(&self) { - self.buffer.borrow_mut().clear() - } - - pub fn is_empty(&self) -> bool { - self.buffer.borrow_mut().extract().len() == 0 - } - - pub fn extract R>(&self, f: F) -> R { - let old_log_level = log::max_level(); - log::set_max_level(LevelFilter::Off); - let result = f(self.buffer.borrow_mut().extract()); - log::set_max_level(old_log_level); - result + pub fn buffer<'a>(&'a self) -> Result, ()> { + self.buffer + .try_borrow_mut() + .map(LogBufferRef::new) + .map_err(|_| ()) } pub fn uart_log_level(&self) -> LevelFilter { @@ -79,9 +101,10 @@ impl Log for BufferLogger { let seconds = timestamp / 1_000_000; let micros = timestamp % 1_000_000; - writeln!(self.buffer.borrow_mut(), - "[{:6}.{:06}s] {:>5}({}): {}", seconds, micros, - record.level(), record.target(), record.args()).unwrap(); + if let Ok(mut buffer) = self.buffer.try_borrow_mut() { + writeln!(buffer, "[{:6}.{:06}s] {:>5}({}): {}", seconds, micros, + record.level(), record.target(), record.args()).unwrap(); + } if record.level() <= self.uart_filter.get() { println!("[{:6}.{:06}s] {:>5}({}): {}", seconds, micros, diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index ee3cbe5fb..8877f6221 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -27,44 +27,48 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> { match Request::read_from(stream)? { Request::GetLog => { BufferLogger::with(|logger| { - logger.extract(|log| { - Reply::LogContent(log).write_to(stream) - }) + let mut buffer = io.until_ok(|| logger.buffer())?; + Reply::LogContent(buffer.extract()).write_to(stream) })?; }, Request::ClearLog => { - BufferLogger::with(|logger| - logger.clear()); + BufferLogger::with(|logger| -> io::Result<()> { + let mut buffer = io.until_ok(|| logger.buffer())?; + Ok(buffer.clear()) + })?; + Reply::Success.write_to(stream)?; }, Request::PullLog => { - loop { - io.until(|| BufferLogger::with(|logger| !logger.is_empty()))?; - - BufferLogger::with(|logger| { + BufferLogger::with(|logger| -> io::Result<()> { + loop { + // Do this *before* acquiring the buffer, since that sets the log level + // to OFF. let log_level = log::max_level(); - logger.extract(|log| { - stream.write_string(log)?; - if log_level == LevelFilter::Trace { - // Hold exclusive access over the logger until we get positive - // acknowledgement; otherwise we get an infinite loop of network - // trace messages being transmitted and causing more network - // trace messages to be emitted. - // - // Any messages unrelated to this management socket that arrive - // while it is flushed are lost, but such is life. - stream.flush() - } else { - Ok(()) - } - })?; + let mut buffer = io.until_ok(|| logger.buffer())?; + if buffer.is_empty() { continue } - Ok(logger.clear()) as io::Result<()> - })?; - } + stream.write_string(buffer.extract())?; + + if log_level == LevelFilter::Trace { + // Hold exclusive access over the logger until we get positive + // acknowledgement; otherwise we get an infinite loop of network + // trace messages being transmitted and causing more network + // trace messages to be emitted. + // + // Any messages unrelated to this management socket that arrive + // while it is flushed are lost, but such is life. + stream.flush()?; + } + + // Clear the log *after* flushing the network buffers, or we're just + // going to resend all the trace messages on the next iteration. + buffer.clear(); + } + })?; }, Request::SetLogFilter(level) => { diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index 82738e9c4..eeb31ceca 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -1,6 +1,7 @@ #![allow(dead_code)] use std::mem; +use std::result; use std::cell::{Cell, RefCell}; use std::vec::Vec; use std::io::{Read, Write, Result, Error, ErrorKind}; @@ -17,7 +18,7 @@ type SocketSet = ::smoltcp::socket::SocketSet<'static, 'static, 'static>; #[derive(Debug)] struct WaitRequest { - event: Option<*const (Fn() -> bool + 'static)>, + event: Option<*mut FnMut() -> bool>, timeout: Option } @@ -133,26 +134,22 @@ impl Scheduler { self.run_idx = (self.run_idx + 1) % self.threads.len(); let result = { - let mut thread = self.threads[self.run_idx].0.borrow_mut(); - match thread.waiting_for { - _ if thread.interrupted => { - thread.interrupted = false; - thread.generator.resume(WaitResult::Interrupted) - } - WaitRequest { event: None, timeout: None } => - thread.generator.resume(WaitResult::Completed), - WaitRequest { timeout: Some(instant), .. } if now >= instant => - thread.generator.resume(WaitResult::TimedOut), - WaitRequest { event: Some(event), .. } if unsafe { (*event)() } => - thread.generator.resume(WaitResult::Completed), - _ => { - if self.run_idx == start_idx { - // We've checked every thread and none of them are runnable. - break - } else { - continue - } - } + let &mut Thread { ref mut generator, ref mut interrupted, ref waiting_for } = + &mut *self.threads[self.run_idx].0.borrow_mut(); + if *interrupted { + *interrupted = false; + generator.resume(WaitResult::Interrupted) + } else if waiting_for.event.is_none() && waiting_for.timeout.is_none() { + generator.resume(WaitResult::Completed) + } else if waiting_for.timeout.map(|instant| now >= instant).unwrap_or(false) { + generator.resume(WaitResult::TimedOut) + } else if waiting_for.event.map(|event| unsafe { (*event)() }).unwrap_or(false) { + generator.resume(WaitResult::Completed) + } else if self.run_idx == start_idx { + // We've checked every thread and none of them are runnable. + break + } else { + continue } }; @@ -225,13 +222,25 @@ impl<'a> Io<'a> { }) } - pub fn until bool + 'static>(&self, f: F) -> Result<()> { + pub fn until bool>(&self, mut f: F) -> Result<()> { + let f = unsafe { mem::transmute::<&mut FnMut() -> bool, *mut FnMut() -> bool>(&mut f) }; self.suspend(WaitRequest { timeout: None, - event: Some(&f as *const _) + event: Some(f) }) } + pub fn until_ok result::Result>(&self, mut f: F) -> Result { + let mut value = None; + self.until(|| { + if let Ok(result) = f() { + value = Some(result) + } + value.is_some() + })?; + Ok(value.unwrap()) + } + pub fn join(&self, handle: ThreadHandle) -> Result<()> { self.until(move || handle.terminated()) } @@ -250,7 +259,7 @@ macro_rules! until { use ::smoltcp::Error as ErrorLower; -// https://github.com/rust-lang/rust/issues/44057 +// https://github.com/rust-lang/rust/issues/26264 // type ErrorLower = ::smoltcp::Error; type TcpSocketBuffer = ::smoltcp::socket::TcpSocketBuffer<'static>; From 742e27344119e1bc2c2fde89e44d7b211ad5f8e8 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 20 Apr 2018 15:27:27 +0000 Subject: [PATCH 0621/2457] Commit missing part of b4e3c30d. --- artiq/test/lit/integration/str.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/artiq/test/lit/integration/str.py b/artiq/test/lit/integration/str.py index 45b430d2a..9d75399e9 100644 --- a/artiq/test/lit/integration/str.py +++ b/artiq/test/lit/integration/str.py @@ -2,4 +2,9 @@ # RUN: %python %s assert "xy" == "xy" +assert not ("xy" == "xz") + +assert "xy" != "xz" +assert not ("xy" != "xy") + assert ("x" + "y") == "xy" From 58967f14fd9cf74ad915976981185f2de821366a Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 21 Apr 2018 18:24:00 +0000 Subject: [PATCH 0622/2457] compiler: do not try to re-coerce fully coerced numerics. --- artiq/compiler/transforms/inferencer.py | 10 +++++++++- artiq/test/lit/inferencer/coerce_explicit.py | 12 ++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 artiq/test/lit/inferencer/coerce_explicit.py diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 7880a6390..9142658b3 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -310,7 +310,15 @@ class Inferencer(algorithm.Visitor): node_types = [] for node in nodes: if isinstance(node, asttyped.CoerceT): - node_types.append(node.value.type) + # If we already know exactly what we coerce this value to, use that type, + # or we'll get an unification error in case the coerced type is not the same + # as the type of the coerced value. + # Otherwise, use the potentially more specific subtype when considering possible + # coercions, or we may get stuck. + if node.type.fold(False, lambda acc, ty: acc or types.is_var(ty)): + node_types.append(node.value.type) + else: + node_types.append(node.type) else: node_types.append(node.type) if any(map(types.is_var, node_types)): # not enough info yet diff --git a/artiq/test/lit/inferencer/coerce_explicit.py b/artiq/test/lit/inferencer/coerce_explicit.py new file mode 100644 index 000000000..4455c596c --- /dev/null +++ b/artiq/test/lit/inferencer/coerce_explicit.py @@ -0,0 +1,12 @@ +# RUN: %python -m artiq.compiler.testbench.inferencer +mono %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +# CHECK-L: n:numpy.int32 = +n = 0 +# CHECK-L: a:numpy.int32 = +a = n // 1 +# CHECK-L: b:numpy.int32 = +b = n // 10 +# CHECK-L: q:numpy.int64 = +q = (a << 0) + (b << 8) +core_log(int64(q)) From 873324d52b3b22e5abd4990a0659e78caaaa6c35 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 21 Apr 2018 19:38:40 +0000 Subject: [PATCH 0623/2457] firmware: don't truncate queued RPCs (fixes #985). --- artiq/firmware/runtime/session.rs | 2 +- artiq/test/coredevice/test_stress.py | 29 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 artiq/test/coredevice/test_stress.py diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 1cb26509e..8b42329ee 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -522,7 +522,7 @@ fn process_kern_queued_rpc(stream: &mut TcpStream, let length = NetworkEndian::read_u32(slice) as usize; host_write(stream, host::Reply::RpcRequest { async: true })?; debug!("{:?}", &slice[4..][..length]); - stream.write(&slice[4..][..length])?; + stream.write_all(&slice[4..][..length])?; Ok(()) }) } diff --git a/artiq/test/coredevice/test_stress.py b/artiq/test/coredevice/test_stress.py new file mode 100644 index 000000000..a7037f156 --- /dev/null +++ b/artiq/test/coredevice/test_stress.py @@ -0,0 +1,29 @@ +import os +import time +import unittest + +from artiq.experiment import * +from artiq.test.hardware_testbench import ExperimentCase + + +artiq_low_latency = os.getenv("ARTIQ_LOW_LATENCY") + + +class _Stress(EnvExperiment): + def build(self): + self.setattr_device("core") + + @rpc(flags={"async"}) + def sink(self, data): + pass + + @kernel + def async_rpc(self, n): + for _ in range(n): + self.sink(b"") + + +class StressTest(ExperimentCase): + def test_async_rpc(self): + exp = self.create(_Stress) + exp.async_rpc(16000) From 3b054855ecb758e6a5697fe4811d38e12cde68f8 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 21 Apr 2018 18:27:14 +0000 Subject: [PATCH 0624/2457] firmware: add allocator debug feature, invoked by artiq_coredebug frontend. --- artiq/coredevice/comm_mgmt.py | 5 ++++ artiq/firmware/libproto/mgmt_proto.rs | 3 ++ artiq/firmware/runtime/mgmt.rs | 5 +++- artiq/frontend/artiq_coredebug.py | 43 +++++++++++++++++++++++++++ setup.py | 1 + 5 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 artiq/frontend/artiq_coredebug.py diff --git a/artiq/coredevice/comm_mgmt.py b/artiq/coredevice/comm_mgmt.py index 9a551a378..f0b7d009a 100644 --- a/artiq/coredevice/comm_mgmt.py +++ b/artiq/coredevice/comm_mgmt.py @@ -17,6 +17,8 @@ class Request(Enum): Hotswap = 4 Reboot = 5 + DebugAllocator = 8 + class Reply(Enum): Success = 1 @@ -151,3 +153,6 @@ class CommMgmt: def reboot(self): self._write_header(Request.Reboot) self._read_expect(Reply.RebootImminent) + + def debug_allocator(self): + self._write_header(Request.DebugAllocator) diff --git a/artiq/firmware/libproto/mgmt_proto.rs b/artiq/firmware/libproto/mgmt_proto.rs index cb5e08856..c96ad27c5 100644 --- a/artiq/firmware/libproto/mgmt_proto.rs +++ b/artiq/firmware/libproto/mgmt_proto.rs @@ -16,6 +16,8 @@ pub enum Request { Hotswap(Vec), Reboot, + + DebugAllocator, } pub enum Reply<'a> { @@ -52,6 +54,7 @@ impl Request { 6 => Request::SetUartLogFilter(read_log_level_filter(reader)?), 4 => Request::Hotswap(reader.read_bytes()?), 5 => Request::Reboot, + 8 => Request::DebugAllocator, _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown request type")) }) } diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 8877f6221..4db85de70 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -97,7 +97,10 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> { stream.close()?; warn!("restarting"); unsafe { boot::reset() } - } + }, + + Request::DebugAllocator => + unsafe { println!("{}", ::ALLOC) }, }; } } diff --git a/artiq/frontend/artiq_coredebug.py b/artiq/frontend/artiq_coredebug.py new file mode 100644 index 000000000..55631e037 --- /dev/null +++ b/artiq/frontend/artiq_coredebug.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +import argparse +import sys +import struct + +from artiq.tools import verbosity_args, init_logger +from artiq.master.databases import DeviceDB +from artiq.coredevice.comm_mgmt import CommMgmt + + +def get_argparser(): + parser = argparse.ArgumentParser(description="ARTIQ core device debug tool") + + verbosity_args(parser) + parser.add_argument("--device-db", default="device_db.py", + help="device database file (default: '%(default)s')") + + subparsers = parser.add_subparsers(dest="action") + + p_allocator = subparsers.add_parser("allocator", + help="show heap layout") + + return parser + + +def main(): + args = get_argparser().parse_args() + init_logger(args) + + core_addr = DeviceDB(args.device_db).get("core")["arguments"]["host"] + mgmt = CommMgmt(core_addr) + try: + if args.action == "allocator": + mgmt.debug_allocator() + else: + print("An action needs to be specified.", file=sys.stderr) + sys.exit(1) + finally: + mgmt.close() + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index 2cb40bb5c..ac7e9d7e9 100755 --- a/setup.py +++ b/setup.py @@ -25,6 +25,7 @@ console_scripts = [ "artiq_coreconfig = artiq.frontend.artiq_coreconfig:main", "artiq_corelog = artiq.frontend.artiq_corelog:main", "artiq_coreboot = artiq.frontend.artiq_coreboot:main", + "artiq_coredebug = artiq.frontend.artiq_coredebug:main", "artiq_ctlmgr = artiq.frontend.artiq_ctlmgr:main", "artiq_devtool = artiq.frontend.artiq_devtool:main", "artiq_pcap = artiq.frontend.artiq_pcap:main", From d2d02ae353e7e1cf2deab7e347a78550f92f34bd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 22 Apr 2018 15:02:17 +0800 Subject: [PATCH 0625/2457] artiq_coredebug: fix permissions --- artiq/frontend/artiq_coredebug.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 artiq/frontend/artiq_coredebug.py diff --git a/artiq/frontend/artiq_coredebug.py b/artiq/frontend/artiq_coredebug.py old mode 100644 new mode 100755 From c47d3ec8c844158f8fce3c8f993e77c5276d7196 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 22 Apr 2018 15:02:50 +0800 Subject: [PATCH 0626/2457] zotino: use None as default for ldac and clr This is also what AD53xx does. --- artiq/coredevice/zotino.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/zotino.py b/artiq/coredevice/zotino.py index 19eeca6c2..e56842be5 100644 --- a/artiq/coredevice/zotino.py +++ b/artiq/coredevice/zotino.py @@ -34,7 +34,7 @@ class Zotino(AD53xx): :param core_device: Core device name (default: "core") """ - def __init__(self, dmgr, spi_device, ldac_device, clr_device, + def __init__(self, dmgr, spi_device, ldac_device=None, clr_device=None, div_write=4, div_read=8, vref=5., core="core"): AD53xx.__init__(self, dmgr=dmgr, spi_device=spi_device, ldac_device=ldac_device, clr_device=clr_device, From 4fe09fddd5013880b75cef0c117990316278575f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 22 Apr 2018 15:03:30 +0800 Subject: [PATCH 0627/2457] examples/kc705_nist_clock: update to new ad53xx driver --- artiq/examples/kc705_nist_clock/repository/ad53xx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/kc705_nist_clock/repository/ad53xx.py b/artiq/examples/kc705_nist_clock/repository/ad53xx.py index 87da4cd3f..943923227 100644 --- a/artiq/examples/kc705_nist_clock/repository/ad53xx.py +++ b/artiq/examples/kc705_nist_clock/repository/ad53xx.py @@ -13,7 +13,7 @@ class AD53XXTest(EnvExperiment): self.core.reset() delay(5*ms) # build slack for shift register set self.fmcdio_dirctl.set(0x00008800) - self.dac.setup_bus() + self.dac.init() self.led.on() delay(400*us) self.led.off() From 934c41b90a21258d1b1b3f3190c6c5bad0bb514e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 23 Apr 2018 10:35:42 +0000 Subject: [PATCH 0628/2457] gateware: add suservo from https://github.com/m-labs/nu-servo/commit/fe4b60b9027fc93d9a7c91aec5f62aafb04b847a m-labs/artiq#788 --- artiq/gateware/rtio/phy/servo.py | 85 ++++ artiq/gateware/suservo/adc_ser.py | 139 ++++++ artiq/gateware/suservo/dds_ser.py | 48 +++ artiq/gateware/suservo/iir.py | 677 ++++++++++++++++++++++++++++++ artiq/gateware/suservo/servo.py | 60 +++ artiq/gateware/suservo/spi.py | 104 +++++ artiq/gateware/suservo/tools.py | 19 + 7 files changed, 1132 insertions(+) create mode 100644 artiq/gateware/rtio/phy/servo.py create mode 100644 artiq/gateware/suservo/adc_ser.py create mode 100644 artiq/gateware/suservo/dds_ser.py create mode 100644 artiq/gateware/suservo/iir.py create mode 100644 artiq/gateware/suservo/servo.py create mode 100644 artiq/gateware/suservo/spi.py create mode 100644 artiq/gateware/suservo/tools.py diff --git a/artiq/gateware/rtio/phy/servo.py b/artiq/gateware/rtio/phy/servo.py new file mode 100644 index 000000000..ff7695d0a --- /dev/null +++ b/artiq/gateware/rtio/phy/servo.py @@ -0,0 +1,85 @@ +from migen import * + +from artiq.gateware.rtio import rtlink + + +class RTServoCtrl(Module): + """Per channel RTIO control interface""" + def __init__(self, ctrl): + self.rtlink = rtlink.Interface( + rtlink.OInterface(len(ctrl))) + + # # # + + self.sync.rio += [ + If(self.rtlink.o.stb, + Cat(ctrl.profile, ctrl.en_out, ctrl.en_iir).eq( + self.rtlink.o.data), + ) + ] + self.comb += [ + ctrl.stb.eq(self.rtlink.o.stb) + ] + + +class RTServoMem(Module): + """All-channel all-profile coefficient and state RTIO control + interface.""" + def __init__(self, w, servo): + m_coeff = servo.m_coeff.get_port(write_capable=True, + we_granularity=w.coeff) + assert len(m_coeff.we) == 2 + m_state = servo.m_state.get_port(write_capable=True) + self.specials += m_state, m_coeff + + assert w.coeff >= w.state + assert w.coeff >= w.word + + self.rtlink = rtlink.Interface( + rtlink.OInterface( + w.coeff, + # coeff, profile, channel, 2 mems, rw + 3 + w.profile + w.channel + 1 + 1, + enable_replace=False), + rtlink.IInterface( + w.coeff, + timestamped=False) + ) + + # # # + + we = self.rtlink.o.address[-1] + state_sel = self.rtlink.o.address[-2] + high_coeff = self.rtlink.o.address[0] + self.comb += [ + self.rtlink.o.busy.eq(active), + m_coeff.adr.eq(self.rtlink.o.address[1:]), + m_coeff.dat_w.eq(Cat(self.rtlink.o.data, self.rtlink.o.data)), + m_coeff.we[0].eq(self.rtlink.o.stb & ~high_coeff & + we & ~state_sel), + m_coeff.we[1].eq(self.rtlink.o.stb & high_coeff & + we & ~state_sel), + m_state.adr.eq(self.rtlink.o.address), + m_state.dat_w.eq(self.rtlink.o.data << w.state - w.coeff), + m_state.we.eq(self.rtlink.o.stb & we & state_sel), + ] + read = Signal() + read_sel = Signal() + read_high = Signal() + self.sync.rio += [ + If(read, + read.eq(0) + ), + If(self.rtlink.o.stb & ~we, + read.eq(1), + read_sel.eq(state_sel), + read_high.eq(high_coeff), + ) + ] + self.comb += [ + self.rtlink.i.stb.eq(read), + self.rtlink.i.data.eq(Mux(state_sel, + m_state.dat_r >> w.state - w.coeff, + Mux(read_high, m_coeff.dat_r[w.coeff:], + m_coeff.dat_r))) + ] diff --git a/artiq/gateware/suservo/adc_ser.py b/artiq/gateware/suservo/adc_ser.py new file mode 100644 index 000000000..8534e6f61 --- /dev/null +++ b/artiq/gateware/suservo/adc_ser.py @@ -0,0 +1,139 @@ +import logging +import string +from collections import namedtuple + +from migen import * +from migen.genlib import io + +from .tools import DiffMixin + + +logger = logging.getLogger(__name__) + + +# all times in cycles +ADCParams = namedtuple("ADCParams", [ + "channels", # number of channels + "lanes", # number of SDO? data lanes + # lanes need to be named alphabetically and contiguous + # (e.g. [sdoa, sdob, sdoc, sdoc] or [sdoa, sdob]) + "width", # bits to transfer per channel + "t_cnvh", # CNVH duration (minimum) + "t_conv", # CONV duration (minimum) + "t_rtt", # upper estimate for clock round trip time from + # sck at the FPGA to clkout at the FPGA. + # this avoids having synchronizers and another counter + # to signal end-of transfer (CLKOUT cycles) + # and it ensures fixed latency early in the pipeline +]) + + +class ADC(Module, DiffMixin): + """Multi-lane, multi-channel, triggered, source-synchronous, serial + ADC interface. + + * Supports ADCs like the LTC2320-16. + * Hardcoded timings. + """ + def __init__(self, pads, params): + self.params = p = params # ADCParams + self.data = [Signal((p.width, True), reset_less=True) + for i in range(p.channels)] # retrieved ADC data + self.start = Signal() # start conversion and reading + self.reading = Signal() # data is being read (outputs are invalid) + self.done = Signal() # data is valid and a new conversion can + # be started + + ### + + # collect sdo lines + sdo = [] + for i in string.ascii_lowercase[:p.lanes]: + sdo.append(self._diff(pads, "sdo" + i)) + assert p.lanes == len(sdo) + + # set up counters for the four states CNVH, CONV, READ, RTT + t_read = p.width*p.channels//p.lanes//2 # DDR + assert 2*p.lanes*t_read == p.width*p.channels + assert all(_ > 0 for _ in (p.t_cnvh, p.t_conv, p.t_rtt)) + assert p.t_conv > 1 + count = Signal(max=max(p.t_cnvh, p.t_conv, t_read, p.t_rtt) - 1, + reset_less=True) + count_load = Signal.like(count) + count_done = Signal() + self.comb += [ + count_done.eq(count == 0), + ] + self.sync += [ + count.eq(count - 1), + If(count_done, + count.eq(count_load), + ) + ] + + sck_en = Signal() + if hasattr(pads, "sck_en"): + self.sync += pads.sck_en.eq(sck_en) # ODDR delay + self.specials += io.DDROutput(0, sck_en, + self._diff(pads, "sck", output=True)) + self.submodules.fsm = fsm = FSM("IDLE") + fsm.act("IDLE", + self.done.eq(1), + If(self.start, + count_load.eq(p.t_cnvh - 1), + NextState("CNVH") + ) + ) + fsm.act("CNVH", + count_load.eq(p.t_conv - 2), # account for sck ODDR delay + pads.cnv_b.eq(1), + If(count_done, + NextState("CONV") + ) + ) + fsm.act("CONV", + count_load.eq(t_read - 1), + If(count_done, + NextState("READ") + ) + ) + fsm.act("READ", + self.reading.eq(1), + count_load.eq(p.t_rtt), # account for sck ODDR delay + sck_en.eq(1), + If(count_done, + NextState("RTT") + ) + ) + fsm.act("RTT", # account for sck->clkout round trip time + self.reading.eq(1), + If(count_done, + NextState("IDLE") + ) + ) + + try: + sck_en_ret = pads.sck_en_ret + except AttributeError: + sck_en_ret = 1 + self.clock_domains.cd_ret = ClockDomain("ret", reset_less=True) + self.comb += [ + # falling clkout makes two bits available + self.cd_ret.clk.eq(~self._diff(pads, "clkout")), + ] + k = p.channels//p.lanes + assert 2*t_read == k*p.width + for i, sdo in enumerate(sdo): + sdo_sr = Signal(2*t_read - 2) + sdo_ddr = Signal(2) + self.specials += io.DDRInput(sdo, sdo_ddr[1], sdo_ddr[0], + self.cd_ret.clk) + self.sync.ret += [ + If(self.reading & sck_en_ret, + sdo_sr.eq(Cat(sdo_ddr, sdo_sr)) + ) + ] + self.comb += [ + Cat(reversed([self.data[i*k + j] for j in range(k)])).eq( + Cat(sdo_ddr, sdo_sr)) + ] diff --git a/artiq/gateware/suservo/dds_ser.py b/artiq/gateware/suservo/dds_ser.py new file mode 100644 index 000000000..4f6d1f1f2 --- /dev/null +++ b/artiq/gateware/suservo/dds_ser.py @@ -0,0 +1,48 @@ +import logging + +from migen import * + +from . import spi + + +logger = logging.getLogger(__name__) + + +DDSParams = spi.SPIParams + + +class DDS(spi.SPISimple): + """Multi-DDS SPI interface. + + * Supports SPI DDS chips like the AD9910. + * Shifts data out to multiple DDS in parallel with a shared CLK and shared + CS_N line. + * Supports a single hardcoded command. + * Configuration and setup must be done over a different channel. + * Asserts IO_UPDATE for one clock cycle immediately after the SPI transfer. + """ + def __init__(self, pads, params): + super().__init__(pads, params) + + self.profile = [Signal(32 + 16 + 16, reset_less=True) + for i in range(params.channels)] + cmd = Signal(8, reset=0x0e) # write to single tone profile 0 + assert params.width == len(cmd) + len(self.profile[0]) + + self.sync += [ + If(self.start, + [d.eq(Cat(p, cmd)) + for d, p in zip(self.data, self.profile)] + ) + ] + + io_update = self._diff(pads, "io_update", output=True) + # this assumes that the cycle time (1/125 MHz = 8 ns) is >1 SYNC_CLK + # cycle (1/250 MHz = 4ns) + done = Signal() + self.sync += [ + done.eq(self.done) + ] + self.comb += [ + io_update.eq(self.done & ~done) + ] diff --git a/artiq/gateware/suservo/iir.py b/artiq/gateware/suservo/iir.py new file mode 100644 index 000000000..c7cfc3c77 --- /dev/null +++ b/artiq/gateware/suservo/iir.py @@ -0,0 +1,677 @@ +from collections import namedtuple +import logging + +from migen import * + + +logger = logging.getLogger(__name__) + + +# all these are number of bits! +IIRWidths = namedtuple("IIRWidths", [ + "state", # the signed x and y states of the IIR filter + # DSP A input, x state is one bit smaller + # due to AD pre-adder, y has full width (25) + "coeff", # signed IIR filter coefficients a1, b0, b1 (18) + "accu", # IIR accumulator width (48) + "adc", # signed ADC data (16) + "word", # "word" size to break up DDS profile data (16) + "asf", # unsigned amplitude scale factor for DDS (14) + "shift", # fixed point scaling coefficient for a1, b0, b1 (log2!) (11) + "channel", # channels (log2!) (3) + "profile", # profiles per channel (log2!) (5) +]) + + +def signed(v, w): + """Convert an unsigned integer ``v`` to it's signed value assuming ``w`` + bits""" + assert 0 <= v < (1 << w) + if v & (1 << w - 1): + v -= 1 << w + return v + + +class DSP(Module): + """Thin abstraction of DSP functionality used here, commonly present, + and inferrable in FPGAs: multiplier with pre-adder and post-accumulator + and pipeline registers at every stage.""" + def __init__(self, w, signed_output=False): + self.state = Signal((w.state, True)) + # NOTE: + # If offset is non-zero, care must be taken to ensure that the + # offset-state difference does not overflow the width of the ad factor + # which is also w.state. + self.offset = Signal((w.state, True)) + self.coeff = Signal((w.coeff, True)) + self.output = Signal((w.state, True)) + self.accu_clr = Signal() + self.offset_load = Signal() + self.clip = Signal() + + a = Signal((w.state, True), reset_less=True) + d = Signal((w.state, True), reset_less=True) + ad = Signal((w.state, True), reset_less=True) + b = Signal((w.coeff, True), reset_less=True) + m = Signal((w.accu, True), reset_less=True) + p = Signal((w.accu, True), reset_less=True) + + self.sync += [ + a.eq(self.state), + If(self.offset_load, + d.eq(self.offset) + ), + ad.eq(d - a), + b.eq(self.coeff), + m.eq(ad*b), + p.eq(p + m), + If(self.accu_clr, + # inject symmetric rouding constant + # p.eq(1 << (w.shift - 1)) + # but that won't infer P reg, so we just clear + # and round down + p.eq(0), + ) + ] + # Bit layout (LSB-MSB): w.shift | w.state - 1 | n_sign - 1 | 1 (sign) + n_sign = w.accu - w.state - w.shift + 1 + assert n_sign > 1 + + # clipping + if signed_output: + self.comb += [ + self.clip.eq(p[-n_sign:] != Replicate(p[-1], n_sign)), + self.output.eq(Mux(self.clip, + Cat(Replicate(~p[-1], w.state - 1), p[-1]), + p[w.shift:])) + ] + else: + self.comb += [ + self.clip.eq(p[-n_sign:] != 0), + self.output.eq(Mux(self.clip, + Replicate(~p[-1], w.state - 1), + p[w.shift:])) + ] + + +class IIR(Module): + """Pipelined IIR processor. + + This module implements a multi-channel IIR (infinite impulse response) + filter processor optimized for synthesis on FPGAs. + + The module is parametrized by passing a ``IIRWidths()`` object which + will be abbreviated W here. + + It reads 1 << W.channels input channels (typically from an ADC) + and on each iteration processes the data on using a first-order IIR filter. + At the end of the cycle each the output of the filter together with + additional data (typically frequency tunning word and phase offset word + for a DDS) are presented at the 1 << W.channels outputs of the module. + + Profile memory + ============== + + Each channel can operate using any of its 1 << W.profile profiles. + The profile data consists of the input ADC channel index (SEL), a delay + (DLY) for delayed activation of the IIR updates, the three IIR + coefficients (A1, B0, B1), the input offset (OFFSET), and additional data + (FTW0, FTW1, and POW). Profile data is stored in a dual-port block RAM that + can be accessed externally. + + Memory Layout + ------------- + + The profile data is stored sequentially for each channel. + Each channel has 1 << W.profile profiles available. + Each profile stores 8 values, each up to W.coeff bits wide, arranged as: + [FTW1, B1, POW, CFG, OFFSET, A1, FTW0, B0] + The lower 8 bits of CFG hold the ADC input channel index SEL. + The bits from bit 8 up hold the IIR activation delay DLY. + The back memory is 2*W.coeff bits wide and each value pair + (even and odd address) + are stored in a single location with the odd address value occupying the + high bits. + + State memory + ============ + + The filter state consists of the previous ADC input values X1, + the current ADC input values X0 and the previous output values + of the IIR filter (Y1). The filter + state is stored in a dual-port block RAM that can be accessed + externally. + + Memory Layout + ------------- + + The state memory holds all Y1 values (IIR processor outputs) for all + profiles of all channels in the lower half (1 << W.profile + W.channel + addresses) and the pairs of old and new ADC input values X1, and X0, + in the upper half (1 << W.channel addresses). Each memory location is + W.state bits wide. + + Real-time control + ================= + + Signals are exposed for each channel: + + * The active profile, PROFILE + * Whether to perform IIR filter iterations, EN_IIR + * The RF switch state enabling output from the channel, EN_OUT + + Delayed IIR processing + ====================== + + The IIR filter iterations on a given channel are only performed all of the + following are true: + + * PROFILE, EN_IIR, EN_OUT have not been updated in the within the + last DLY cycles + * EN_IIR is asserted + * EN_OUT is asserted + + DSP design + ========== + + Typical design at the DSP level. This does not include the description of + the pipelining or the overall latency involved. + + IIRWidths(state=25, coeff=18, adc=16, + asf=14, word=16, accu=48, shift=11, + channel=3, profile=5) + + X0 = ADC * 2^(25 - 1 - 16) + X1 = X0 delayed by one cycle + A0 = 2^11 + A0*Y0 = A1*Y1 - B0*(X0 - OFFSET) - B1*(X1 - OFFSET) + Y1 = Y0 delayed by one cycle + ASF = Y0 / 2^(25 - 14 - 1) + + ADC: input value from the ADC + ASF: output amplitude scale factor to DDS + OFFSET: setpoint + A0: fixed factor + A1/B0/B1: coefficients + + B0 --/- A0: 2^11 + 18 | | + ADC -/-[<<]-/-(-)-/---(x)-(+)-/-[>>]-/-[_/^]-/---[>>]-/- ASF + 16 8 24 | 25 | | 48 11 37 25 | 10 15 + OFFSET --/- [z^-1] ^ [z^-1] + 24 | | | + -(x)-(+)-<-(x)-----<------ + | | + B1 --/- A1 --/- + 18 18 + + [<<]: left shift, multiply by 2^n + [>>]: right shift, divide by 2^n + (x): multiplication + (+), (-): addition, subtraction + [_/^]: clip + [z^-1]: register, delay by one processing cycle (~1.1 µs) + --/--: signal with a given bit width always includes a sign bit + -->--: flow is to the right and down unless otherwise indicated + """ + def __init__(self, w): + self.widths = w + for i, j in enumerate(w): + assert j > 0, (i, j, w) + assert w.word <= w.coeff # same memory + assert w.state + w.coeff + 3 <= w.accu + + # m_coeff of active profiles should only be accessed during + # ~processing + self.specials.m_coeff = Memory( + width=2*w.coeff, # Cat(pow/ftw/offset, cfg/a/b) + depth=4 << w.profile + w.channel) + # m_state[x] should only be read during ~(shifting | + # loading) + # m_state[y] of active profiles should only be read during + # ~processing + self.specials.m_state = Memory( + width=w.state, # y1,x0,x1 + depth=(1 << w.profile + w.channel) + (2 << w.channel)) + # ctrl should only be updated synchronously + self.ctrl = [Record([ + ("profile", w.profile), + ("en_out", 1), + ("en_iir", 1), + ("stb", 1)]) + for i in range(1 << w.channel)] + # only update during ~loading + self.adc = [Signal((w.adc, True), reset_less=True) + for i in range(1 << w.channel)] + # Cat(ftw0, ftw1, pow, asf) + # only read during ~processing + self.dds = [Signal(4*w.word, reset_less=True) + for i in range(1 << w.channel)] + # perform one IIR iteration, start with loading, + # then processing, then shifting, end with done + self.start = Signal() + # adc inputs being loaded into RAM (becoming x0) + self.loading = Signal() + # processing state data (extracting ftw0/ftw1/pow, + # computing asf/y0, and storing as y1) + self.processing = Signal() + # shifting input state values around (x0 becomes x1) + self.shifting = Signal() + # iteration done, the next iteration can be started + self.done = Signal() + + ### + + # pivot arrays for muxing + profiles = Array([ch.profile for ch in self.ctrl]) + en_outs = Array([ch.en_out for ch in self.ctrl]) + en_iirs = Array([ch.en_iir for ch in self.ctrl]) + + # state counter + state = Signal(w.channel + 2) + # pipeline group activity flags (SR) + stage = Signal(3) + self.submodules.fsm = fsm = FSM("IDLE") + state_clr = Signal() + stage_en = Signal() + fsm.act("IDLE", + self.done.eq(1), + state_clr.eq(1), + If(self.start, + NextState("LOAD") + ) + ) + fsm.act("LOAD", + self.loading.eq(1), + If(state == (1 << w.channel) - 1, + state_clr.eq(1), + stage_en.eq(1), + NextState("PROCESS") + ) + ) + fsm.act("PROCESS", + self.processing.eq(1), + # this is technically wasting three cycles + # (one for setting stage, and phase=2,3 with stage[2]) + If(stage == 0, + state_clr.eq(1), + NextState("SHIFT") + ) + ) + fsm.act("SHIFT", + self.shifting.eq(1), + If(state == (2 << w.channel) - 1, + NextState("IDLE") + ) + ) + + self.sync += [ + state.eq(state + 1), + If(state_clr, + state.eq(0), + ), + If(stage_en, + stage[0].eq(1) + ) + ] + + # pipeline group channel pointer + # for each pipeline stage, this is the channel currently being + # processed + channel = [Signal(w.channel, reset_less=True) for i in range(3)] + # pipeline group profile pointer (SR) + # for each pipeline stage, this is the profile currently being + # processed + profile = [Signal(w.profile, reset_less=True) for i in range(2)] + # pipeline phase (lower two bits of state) + phase = Signal(2, reset_less=True) + + self.comb += Cat(phase, channel[0]).eq(state) + self.sync += [ + Case(phase, { + 0: [ + profile[0].eq(profiles[channel[0]]), + profile[1].eq(profile[0]) + ], + 3: [ + Cat(channel[1:]).eq(Cat(channel[:-1])), + stage[1:].eq(stage[:-1]), + If(channel[0] == (1 << w.channel) - 1, + stage[0].eq(0) + ) + ] + }) + ] + + m_coeff = self.m_coeff.get_port() + m_state = self.m_state.get_port(write_capable=True) + self.specials += m_state, m_coeff + + dsp = DSP(w) + self.submodules += dsp + + offset_clr = Signal() + + self.comb += [ + m_coeff.adr.eq(Cat(phase, profile[0], + Mux(phase==0, channel[1], channel[0]))), + dsp.offset[-w.coeff - 1:].eq(Mux(offset_clr, 0, + Cat(m_coeff.dat_r[:w.coeff], m_coeff.dat_r[w.coeff - 1]) + )), + dsp.coeff.eq(m_coeff.dat_r[w.coeff:]), + dsp.state.eq(m_state.dat_r), + Case(phase, { + 0: dsp.accu_clr.eq(1), + 2: [ + offset_clr.eq(1), + dsp.offset_load.eq(1) + ], + 3: dsp.offset_load.eq(1) + }) + ] + + # selected adc (combinatorial from dat_r) + sel_profile = Signal(w.channel) + # profile delay (combinatorial from dat_r) + dly_profile = Signal(8) + + # latched adc selection + sel = Signal(w.channel, reset_less=True) + # iir enable SR + en = Signal(2, reset_less=True) + + assert w.channel <= 8 + assert w.profile <= len(dly_profile) + assert w.profile + 8 <= len(m_coeff.dat_r) + + self.comb += [ + sel_profile.eq(m_coeff.dat_r[w.coeff:]), + dly_profile.eq(m_coeff.dat_r[w.coeff + 8:]), + If(self.shifting, + m_state.adr.eq(state | (1 << w.profile + w.channel)), + m_state.dat_w.eq(m_state.dat_r), + m_state.we.eq(state[0]) + ), + If(self.loading, + m_state.adr.eq((state << 1) | (1 << w.profile + w.channel)), + m_state.dat_w[-w.adc - 1:-1].eq(Array(self.adc)[state]), + m_state.dat_w[-1].eq(m_state.dat_w[-2]), + m_state.we.eq(1) + ), + If(self.processing, + m_state.adr.eq(Array([ + # write back new y + Cat(profile[1], channel[2]), + # read old y + Cat(profile[0], channel[0]), + # x0 (recent) + 0 | (sel_profile << 1) | (1 << w.profile + w.channel), + # x1 (old) + 1 | (sel << 1) | (1 << w.profile + w.channel), + ])[phase]), + m_state.dat_w.eq(dsp.output), + m_state.we.eq((phase == 0) & stage[2] & en[1]), + ) + ] + + # internal channel delay counters + dlys = Array([Signal(len(dly_profile)) + for i in range(1 << w.channel)]) + self._dlys = dlys # expose for debugging only + + for i in range(1 << w.channel): + self.sync += [ + # (profile != profile_old) | ~en_out + If(self.ctrl[i].stb, + dlys[i].eq(0), + ) + ] + + # latched channel delay + dly = Signal(len(dly_profile), reset_less=True) + # latched channel en_out + en_out = Signal(reset_less=True) + # latched channel en_iir + en_iir = Signal(reset_less=True) + # muxing + ddss = Array(self.dds) + + self.sync += [ + Case(phase, { + 0: [ + dly.eq(dlys[channel[0]]), + en_out.eq(en_outs[channel[0]]), + en_iir.eq(en_iirs[channel[0]]), + If(stage[1], + ddss[channel[1]][:w.word].eq( + m_coeff.dat_r), + ) + ], + 1: [ + If(stage[1], + ddss[channel[1]][w.word:2*w.word].eq( + m_coeff.dat_r), + ), + If(stage[2], + ddss[channel[2]][3*w.word:].eq( + m_state.dat_r[w.state - w.asf - 1:w.state - 1]) + ) + ], + 2: [ + en[0].eq(0), + en[1].eq(en[0]), + sel.eq(sel_profile), + If(stage[0], + ddss[channel[0]][2*w.word:3*w.word].eq( + m_coeff.dat_r), + If(en_out, + If(dly != dly_profile, + dlys[channel[0]].eq(dly + 1) + ).Elif(en_iir, + en[0].eq(1) + ) + ) + ) + ], + 3: [ + ], + }), + ] + + def _coeff(self, channel, profile, coeff): + """Return ``high_word``, ``address`` and bit ``mask`` for the + storage of coefficient name ``coeff`` in profile ``profile`` + of channel ``channel``. + + ``high_word`` determines whether the coefficient is stored in the high + or low part of the memory location. + """ + w = self.widths + addr = "ftw1 b1 pow cfg offset a1 ftw0 b0".split().index(coeff) + coeff_addr = ((channel << w.profile + 2) | (profile << 2) | + (addr >> 1)) + mask = (1 << w.coeff) - 1 + return addr & 1, coeff_addr, mask + + def set_coeff(self, channel, profile, coeff, value): + """Set the coefficient value. + + Note that due to two coefficiddents sharing a single memory + location, only one coefficient update can be effected to a given memory + location per simulation clock cycle. + """ + w = self.widths + word, addr, mask = self._coeff(channel, profile, coeff) + val = yield self.m_coeff[addr] + if word: + val = (val & mask) | ((value & mask) << w.coeff) + else: + val = (value & mask) | (val & (mask << w.coeff)) + yield self.m_coeff[addr].eq(val) + + def get_coeff(self, channel, profile, coeff): + """Get a coefficient value.""" + w = self.widths + word, addr, mask = self._coeff(channel, profile, coeff) + val = yield self.m_coeff[addr] + if word: + return val >> w.coeff + else: + return val & mask + if val in "offset a1 b0 b1".split(): + val = signed(val, w.coeff) + return val + + def set_state(self, channel, val, profile=None, coeff="y1"): + """Set a state value.""" + w = self.widths + if coeff == "y1": + assert profile is not None + yield self.m_state[profile | (channel << w.profile)].eq(val) + elif coeff == "x0": + assert profile is None + yield self.m_state[(channel << 1) | + (1 << w.profile + w.channel)].eq(val) + elif coeff == "x1": + assert profile is None + yield self.m_state[1 | (channel << 1) | + (1 << w.profile + w.channel)].eq(val) + else: + raise ValueError("no such state", coeff) + + def get_state(self, channel, profile=None, coeff="y1"): + """Get a state value.""" + w = self.widths + if coeff == "y1": + val = yield self.m_state[profile | (channel << w.profile)] + elif coeff == "x0": + val = yield self.m_state[(channel << 1) | + (1 << w.profile + w.channel)] + elif coeff == "x1": + val = yield self.m_state[1 | (channel << 1) | + (1 << w.profile + w.channel)] + else: + raise ValueError("no such state", coeff) + return signed(val, w.state) + + def fast_iter(self): + """Perform a single processing iteration.""" + assert (yield self.done) + yield self.start.eq(1) + yield + yield self.start.eq(0) + yield + while not (yield self.done): + yield + + def check_iter(self): + """Perform a single processing iteration while verifying + the behavior.""" + w = self.widths + + while not (yield self.done): + yield + + yield self.start.eq(1) + yield + yield self.start.eq(0) + yield + assert not (yield self.done) + assert (yield self.loading) + while (yield self.loading): + yield + + x0s = [] + # check adc loading + for i in range(1 << w.channel): + v_adc = signed((yield self.adc[i]), w.adc) + x0 = yield from self.get_state(i, coeff="x0") + x0s.append(x0) + assert v_adc << (w.state - w.adc - 1) == x0, (hex(v_adc), hex(x0)) + logger.debug("adc[%d] adc=%x x0=%x", i, v_adc, x0) + + data = [] + # predict output + for i in range(1 << w.channel): + j = yield self.ctrl[i].profile + en_iir = yield self.ctrl[i].en_iir + en_out = yield self.ctrl[i].en_out + dly_i = yield self._dlys[i] + logger.debug("ctrl[%d] profile=%d en_iir=%d en_out=%d dly=%d", + i, j, en_iir, en_out, dly_i) + + cfg = yield from self.get_coeff(i, j, "cfg") + k_j = cfg & ((1 << w.channel) - 1) + dly_j = (cfg >> 8) & 0xff + logger.debug("cfg[%d,%d] sel=%d dly=%d", i, j, k_j, dly_j) + + en = en_iir & en_out & (dly_i >= dly_j) + logger.debug("en[%d,%d] %d", i, j, en) + + offset = yield from self.get_coeff(i, j, "offset") + offset <<= w.state - w.coeff - 1 + a1 = yield from self.get_coeff(i, j, "a1") + b0 = yield from self.get_coeff(i, j, "b0") + b1 = yield from self.get_coeff(i, j, "b1") + logger.debug("coeff[%d,%d] offset=%#x a1=%#x b0=%#x b1=%#x", + i, j, offset, a1, b0, b1) + + ftw0 = yield from self.get_coeff(i, j, "ftw0") + ftw1 = yield from self.get_coeff(i, j, "ftw1") + pow = yield from self.get_coeff(i, j, "pow") + logger.debug("dds[%d,%d] ftw0=%#x ftw1=%#x pow=%#x", + i, j, ftw0, ftw1, pow) + + y1 = yield from self.get_state(i, j, "y1") + x1 = yield from self.get_state(k_j, coeff="x1") + x0 = yield from self.get_state(k_j, coeff="x0") + logger.debug("state y1[%d,%d]=%#x x0[%d]=%#x x1[%d]=%#x", + i, j, y1, k_j, x0, k_j, x1) + + p = (0*(1 << w.shift - 1) + a1*(0 - y1) + + b0*(offset - x0) + b1*(offset - x1)) + out = p >> w.shift + y0 = min(max(0, out), (1 << w.state - 1) - 1) + logger.debug("dsp[%d,%d] p=%#x out=%#x y0=%#x", + i, j, p, out, y0) + + if not en: + y0 = y1 + data.append((ftw0, ftw1, pow, y0, x1, x0)) + + # wait for output + assert (yield self.processing) + while (yield self.processing): + yield + + assert (yield self.shifting) + while (yield self.shifting): + yield + + # check x shifting + for i, x0 in enumerate(x0s): + x1 = yield from self.get_state(i, coeff="x1") + assert x1 == x0, (hex(x1), hex(x0)) + logger.debug("adc[%d] x0=%x x1=%x", i, x0, x1) + + # check new state + for i in range(1 << w.channel): + j = yield self.ctrl[i].profile + logger.debug("ch[%d] profile=%d", i, j) + y1 = yield from self.get_state(i, j, "y1") + ftw0, ftw1, pow, y0, x1, x0 = data[i] + assert y1 == y0, (hex(y1), hex(y0)) + + # check dds output + for i in range(1 << w.channel): + ftw0, ftw1, pow, y0, x1, x0 = data[i] + asf = y0 >> (w.state - w.asf - 1) + dds = (ftw0 | (ftw1 << w.word) | + (pow << 2*w.word) | (asf << 3*w.word)) + dds_state = yield self.dds[i] + logger.debug("ch[%d] dds_state=%#x dds=%#x", i, dds_state, dds) + assert dds_state == dds, [hex(_) for _ in + (dds_state, asf, pow, ftw1, ftw0)] + + assert (yield self.done) + return data diff --git a/artiq/gateware/suservo/servo.py b/artiq/gateware/suservo/servo.py new file mode 100644 index 000000000..31491429a --- /dev/null +++ b/artiq/gateware/suservo/servo.py @@ -0,0 +1,60 @@ +from migen import * + +from .adc_ser import ADC, ADCParams +from .iir import IIR, IIRWidths +from .dds_ser import DDS, DDSParams + + +class Servo(Module): + def __init__(self, adc_pads, dds_pads, adc_p, iir_p, dds_p): + self.submodules.adc = ADC(adc_pads, adc_p) + self.submodules.iir = IIR(iir_p) + self.submodules.dds = DDS(dds_pads, dds_p) + + for i, j, k, l in zip(self.adc.data, self.iir.adc, + self.iir.dds, self.dds.profile): + self.comb += j.eq(i), l.eq(k) + + t_adc = (adc_p.t_cnvh + adc_p.t_conv + adc_p.t_rtt + + adc_p.channels*adc_p.width//2//adc_p.lanes) + 1 + t_iir = ((1 + 4 + 1) << iir_p.channel) + 1 + t_dds = (dds_p.width*2 + 1)*dds_p.clk + 1 + t_cycle = max(t_adc, t_iir, t_dds) + assert t_iir + (2 << iir_p.channel) < t_cycle, "need shifting time" + + self.start = Signal() + t_restart = t_cycle - t_iir - t_adc + assert t_restart > 0 + cnt = Signal(max=t_restart) + cnt_done = Signal() + token = Signal(2) + self.done = Signal() + iir_done = Signal() + self.comb += [ + cnt_done.eq(cnt == 0), + iir_done.eq(self.iir.shifting | self.iir.done), + self.adc.start.eq(self.start & cnt_done), + self.iir.start.eq(token[0] & self.adc.done), + self.dds.start.eq(token[1] & iir_done), + self.done.eq(self.dds.done), + ] + self.sync += [ + If(iir_done & ~cnt_done & ~token[0], + cnt.eq(cnt - 1), + ), + If(self.adc.start, + cnt.eq(t_restart - 1), + ), + If(self.adc.done, + token[0].eq(0) + ), + If(self.adc.start, + token[0].eq(1) + ), + If(iir_done, + token[1].eq(0) + ), + If(self.iir.start, + token[1].eq(1) + ) + ] diff --git a/artiq/gateware/suservo/spi.py b/artiq/gateware/suservo/spi.py new file mode 100644 index 000000000..791486589 --- /dev/null +++ b/artiq/gateware/suservo/spi.py @@ -0,0 +1,104 @@ +import logging +from collections import namedtuple + +from migen import * +from migen.genlib.fsm import FSM, NextState +from migen.genlib import io + +from .tools import DiffMixin + + +logger = logging.getLogger(__name__) + + +# all times in cycles +SPIParams = namedtuple("SPIParams", [ + "channels", # number of MOSI? data lanes + "width", # transfer width + "clk", # CLK half cycle width (in cycles) +]) + + +class SPISimple(Module, DiffMixin): + """Simple reduced SPI interface. + + * Multiple MOSI lines + * Supports differential CLK/CS_N/MOSI + * Fixed CLK timing + * SPI MODE 0 (CPHA=0, CPOL=0) + """ + def __init__(self, pads, params): + self.params = p = params + self.data = [Signal(p.width, reset_less=True) + for i in range(p.channels)] # data to be output, MSB first + self.start = Signal() # start transfer + self.done = Signal() # transfer complete, next transfer can be + # started + + ### + + assert p.clk >= 1 + + cs_n = self._diff(pads, "cs_n", output=True) + + clk = self._diff(pads, "clk", output=True) + cnt = Signal(max=max(2, p.clk), reset_less=True) + cnt_done = Signal() + cnt_next = Signal() + self.comb += cnt_done.eq(cnt == 0) + self.sync += [ + If(cnt_done, + If(cnt_next, + cnt.eq(p.clk - 1) + ) + ).Else( + cnt.eq(cnt - 1) + ) + ] + + for i, d in enumerate(self.data): + self.comb += [ + self._diff(pads, "mosi{}".format(i), output=True).eq(d[-1]) + ] + + bits = Signal(max=p.width + 1, reset_less=True) + + self.submodules.fsm = fsm = CEInserter()(FSM("IDLE")) + + self.comb += [ + fsm.ce.eq(cnt_done) + ] + + fsm.act("IDLE", + self.done.eq(1), + cs_n.eq(1), + If(self.start, + cnt_next.eq(1), + NextState("SETUP") + ) + ) + fsm.act("SETUP", + cnt_next.eq(1), + If(bits == 0, + NextState("IDLE") + ).Else( + NextState("HOLD") + ) + ) + fsm.act("HOLD", + cnt_next.eq(1), + clk.eq(1), + NextState("SETUP") + ) + + self.sync += [ + If(fsm.ce, + If(fsm.before_leaving("HOLD"), + bits.eq(bits - 1), + [d[1:].eq(d) for d in self.data] + ), + If(fsm.ongoing("IDLE"), + bits.eq(p.width) + ) + ) + ] diff --git a/artiq/gateware/suservo/tools.py b/artiq/gateware/suservo/tools.py new file mode 100644 index 000000000..7a4feac1f --- /dev/null +++ b/artiq/gateware/suservo/tools.py @@ -0,0 +1,19 @@ +from migen import * +from migen.genlib import io + + +class DiffMixin: + def _diff(self, pads, name, output=False): + """Retrieve the single-ended ``Signal()`` ``name`` from + ``pads`` and in its absence retrieve the differential signal with the + pin pairs ``name_p`` and ``name_n``. Do so as an output if ``output``, + otherwise make a differential input.""" + if hasattr(pads, name): + return getattr(pads, name) + sig = Signal() + p, n = (getattr(pads, name + "_" + s) for s in "pn") + if output: + self.specials += io.DifferentialOutput(sig, p, n) + else: + self.specials += io.DifferentialInput(p, n, sig) + return sig From c8fd63754ac8a90cd1e09a2a46aceef6add0bc8e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 23 Apr 2018 16:08:57 +0000 Subject: [PATCH 0629/2457] suservo: add unittests m-labs/artiq#788 --- artiq/gateware/test/suservo/__init__.py | 0 artiq/gateware/test/suservo/test_adc.py | 165 ++++++++++++++++++++++ artiq/gateware/test/suservo/test_dds.py | 93 ++++++++++++ artiq/gateware/test/suservo/test_iir.py | 56 ++++++++ artiq/gateware/test/suservo/test_servo.py | 109 ++++++++++++++ 5 files changed, 423 insertions(+) create mode 100644 artiq/gateware/test/suservo/__init__.py create mode 100644 artiq/gateware/test/suservo/test_adc.py create mode 100644 artiq/gateware/test/suservo/test_dds.py create mode 100644 artiq/gateware/test/suservo/test_iir.py create mode 100644 artiq/gateware/test/suservo/test_servo.py diff --git a/artiq/gateware/test/suservo/__init__.py b/artiq/gateware/test/suservo/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/artiq/gateware/test/suservo/test_adc.py b/artiq/gateware/test/suservo/test_adc.py new file mode 100644 index 000000000..2dbcd6342 --- /dev/null +++ b/artiq/gateware/test/suservo/test_adc.py @@ -0,0 +1,165 @@ +import logging +import string +import unittest + +from migen import * +from migen.genlib import io + +from artiq.gateware.suservo.adc_ser import ADC, ADCParams + + +class DDROutputImpl(Module): + def __init__(self, i1, i2, o, clk): + do_clk0 = Signal(reset_less=True) + do_j1 = Signal(reset_less=True) + do_j2 = Signal(reset_less=True) + do_j3 = Signal(reset_less=True) + self.sync.async += [ + do_clk0.eq(clk), + do_j1.eq(i1), + do_j2.eq(i2), + If(Cat(do_clk0, clk) == 0b10, + o.eq(do_j1), + do_j3.eq(do_j2), + ).Elif(Cat(do_clk0, clk) == 0b01, + o.eq(do_j3), + ) + ] + + +class DDROutput: + @staticmethod + def lower(dr): + return DDROutputImpl(dr.i1, dr.i2, dr.o, dr.clk) + + +class DDRInputImpl(Module): + def __init__(self, i, o1, o2, clk): + di_clk0 = Signal(reset_less=True) + # SAME_EDGE_PIPELINED is effectively one register for o1 + # (during rising clock) + di_j1 = Signal(reset_less=True) + di_j2 = Signal(reset_less=True) + di_j3 = Signal(reset_less=True) + self.sync.async += [ + di_clk0.eq(clk), + di_j1.eq(i), + If(Cat(di_clk0, clk) == 0b10, + di_j3.eq(di_j1), + o1.eq(di_j3), + o2.eq(di_j2) + ).Elif(Cat(di_clk0, clk) == 0b01, + di_j2.eq(di_j1) + ) + ] + + +class DDRInput: + @staticmethod + def lower(dr): + return DDRInputImpl(dr.i, dr.o1, dr.o2, dr.clk) + + +class TB(Module): + def __init__(self, params): + self.params = p = params + + self.sck = Signal() + self.clkout = Signal(reset_less=True) + self.cnv_b = Signal() + + self.sck_en = Signal() + self.sck_en_ret = Signal() + + adc_sck_en = Signal() + cd_adc = ClockDomain("adc", reset_less=True) + self.clock_domains += cd_adc + + self.sdo = [] + self.data = [Signal((p.width, True), reset_less=True) + for i in range(p.channels)] + + srs = [] + for i in range(p.lanes): + name = "sdo" + string.ascii_lowercase[i] + sdo = Signal(name=name, reset_less=True) + self.sdo.append(sdo) + setattr(self, name, sdo) + sr = Signal(p.width*p.channels//p.lanes, reset_less=True) + srs.append(sr) + self.specials += io.DDROutput( + # one for async + self._dly(sr[-1], -1), self._dly(sr[-2], -1), sdo) + self.sync.adc += [ + If(adc_sck_en, + sr[2:].eq(sr) + ) + ] + cnv_b_old = Signal(reset_less=True) + self.sync.async += [ + cnv_b_old.eq(self.cnv_b), + If(Cat(cnv_b_old, self.cnv_b) == 0b10, + sr.eq(Cat(reversed(self.data[2*i:2*i + 2]))), + ) + ] + + adc_clk_rec = Signal() + self.comb += [ + adc_sck_en.eq(self._dly(self.sck_en, 1)), + self.sck_en_ret.eq(self._dly(adc_sck_en)), + adc_clk_rec.eq(self._dly(self.sck, 1)), + self.clkout.eq(self._dly(adc_clk_rec)), + ] + + def _dly(self, sig, n=0): + n += self.params.t_rtt*4//2 # t_{sys,adc,ret}/t_async half rtt + dly = Signal(n, reset_less=True) + self.sync.async += dly.eq(Cat(sig, dly)) + return dly[-1] + + +def main(): + params = ADCParams(width=8, channels=4, lanes=2, + t_cnvh=3, t_conv=5, t_rtt=4) + tb = TB(params) + adc = ADC(tb, params) + tb.submodules += adc + + def run(tb): + dut = adc + for i, ch in enumerate(tb.data): + yield ch.eq(i) + assert (yield dut.done) + yield dut.start.eq(1) + yield + yield dut.start.eq(0) + yield + assert not (yield dut.done) + while not (yield dut.done): + yield + x = (yield from [(yield d) for d in dut.data]) + for i, ch in enumerate(x): + assert ch == i, (hex(ch), hex(i)) + + run_simulation(tb, [run(tb)], + vcd_name="adc.vcd", + clocks={ + "sys": (8, 0), + "adc": (8, 0), + "ret": (8, 0), + "async": (2, 0), + }, + special_overrides={ + io.DDROutput: DDROutput, + io.DDRInput: DDRInput + }) + + +class ADCTest(unittest.TestCase): + def test_run(self): + main() + + +if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG) + main() diff --git a/artiq/gateware/test/suservo/test_dds.py b/artiq/gateware/test/suservo/test_dds.py new file mode 100644 index 000000000..e8c221f51 --- /dev/null +++ b/artiq/gateware/test/suservo/test_dds.py @@ -0,0 +1,93 @@ +import logging +import unittest + +from migen import * + +from artiq.gateware.suservo.dds_ser import DDSParams, DDS + + +class TB(Module): + def __init__(self, p): + self.cs_n = Signal() + self.clk = Signal() + self.mosi = [Signal() for i in range(p.channels)] + for i, m in enumerate(self.mosi): + setattr(self, "mosi{}".format(i), m) + self.miso = Signal() + self.io_update = Signal() + + clk0 = Signal() + self.sync += clk0.eq(self.clk) + sample = Signal() + self.comb += sample.eq(Cat(self.clk, clk0) == 0b01) + + self.ddss = [] + for i in range(p.channels): + dds = Record([("ftw", 32), ("pow", 16), ("asf", 16), ("cmd", 8)]) + sr = Signal(len(dds)) + self.sync += [ + If(~self.cs_n & sample, + sr.eq(Cat(self.mosi[i], sr)) + ), + If(self.io_update, + dds.raw_bits().eq(sr) + ) + ] + self.ddss.append(dds) + + @passive + def log(self, data): + i = 0 + while True: + i += 1 + if (yield self.io_update): + yield + dat = [] + for dds in self.ddss: + v = yield from [(yield getattr(dds, k)) + for k in "cmd ftw pow asf".split()] + dat.append(v) + data.append((i, dat)) + else: + yield + + +def main(): + p = DDSParams(channels=4, width=8 + 32 + 16 + 16, clk=1) + tb = TB(p) + dds = DDS(tb, p) + tb.submodules += dds + + def run(tb): + dut = dds + for i, ch in enumerate(dut.profile): + yield ch.eq((((0 + << 16 | i | 0x20) + << 16 | i | 0x30) + << 32 | i | 0x40)) + # assert (yield dut.done) + yield dut.start.eq(1) + yield + yield dut.start.eq(0) + yield + yield + assert not (yield dut.done) + while not (yield dut.done): + yield + yield + + data = [] + run_simulation(tb, [tb.log(data), run(tb)], vcd_name="dds.vcd") + + assert data[-1][1] == [[0xe, 0x40 | i, 0x30 | i, 0x20 | i] for i in + range(4)] + + +class DDSTest(unittest.TestCase): + def test_run(self): + main() + + +if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG) + main() diff --git a/artiq/gateware/test/suservo/test_iir.py b/artiq/gateware/test/suservo/test_iir.py new file mode 100644 index 000000000..c3d66de52 --- /dev/null +++ b/artiq/gateware/test/suservo/test_iir.py @@ -0,0 +1,56 @@ +import logging +import unittest + +from migen import * +from artiq.gateware.suservo import iir + + +def main(): + w_kasli = iir.IIRWidths(state=25, coeff=18, adc=16, + asf=14, word=16, accu=48, shift=11, + channel=3, profile=5) + w = iir.IIRWidths(state=17, coeff=16, adc=16, + asf=14, word=16, accu=48, shift=11, + channel=2, profile=1) + + def run(dut): + for i, ch in enumerate(dut.adc): + yield ch.eq(i) + for i, ch in enumerate(dut.ctrl): + yield ch.en_iir.eq(1) + yield ch.en_out.eq(1) + yield ch.profile.eq(i) + for i in range(1 << w.channel): + yield from dut.set_state(i, i << 8, coeff="x1") + yield from dut.set_state(i, i << 8, coeff="x0") + for j in range(1 << w.profile): + yield from dut.set_state(i, + (j << 1) | (i << 8), profile=j, coeff="y1") + for k, l in enumerate("pow offset ftw0 ftw1".split()): + yield from dut.set_coeff(i, profile=j, coeff=l, + value=(i << 12) | (j << 8) | (k << 4)) + yield + for i in range(1 << w.channel): + for j in range(1 << w.profile): + for k, l in enumerate("cfg a1 b0 b1".split()): + yield from dut.set_coeff(i, profile=j, coeff=l, + value=(i << 12) | (j << 8) | (k << 4)) + yield from dut.set_coeff(i, profile=j, coeff="cfg", + value=(i << 0) | (j << 8)) # sel, dly + yield + for i in range(10): + yield from dut.check_iter() + yield + + dut = iir.IIR(w) + run_simulation(dut, [run(dut)], vcd_name="iir.vcd") + + +class IIRTest(unittest.TestCase): + def test_run(self): + main() + + +if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG) + main() diff --git a/artiq/gateware/test/suservo/test_servo.py b/artiq/gateware/test/suservo/test_servo.py new file mode 100644 index 000000000..c8b43349e --- /dev/null +++ b/artiq/gateware/test/suservo/test_servo.py @@ -0,0 +1,109 @@ +import logging +import unittest + +from migen import * +from migen.genlib import io + +from artiq.gateware.test.suservo import test_adc, test_dds +from artiq.gateware.suservo import servo + + +class ServoSim(servo.Servo): + def __init__(self): + adc_p = servo.ADCParams(width=16, channels=8, lanes=4, + t_cnvh=4, t_conv=57, t_rtt=4) + iir_p = servo.IIRWidths(state=25, coeff=18, adc=16, + asf=14, word=16, accu=48, shift=11, + channel=3, profile=5) + dds_p = servo.DDSParams(width=8 + 32 + 16 + 16, + channels=adc_p.channels, clk=1) + + self.submodules.adc_tb = test_adc.TB(adc_p) + self.submodules.dds_tb = test_dds.TB(dds_p) + + servo.Servo.__init__(self, self.adc_tb, self.dds_tb, + adc_p, iir_p, dds_p) + + def test(self): + assert (yield self.done) + + adc = 1 + x0 = 0x0141 + yield self.adc_tb.data[adc].eq(x0) + channel = 3 + yield self.iir.adc[channel].eq(adc) + yield self.iir.ctrl[channel].en_iir.eq(1) + yield self.iir.ctrl[channel].en_out.eq(1) + profile = 5 + yield self.iir.ctrl[channel].profile.eq(profile) + x1 = 0x0743 + yield from self.iir.set_state(adc, x1, coeff="x1") + y1 = 0x1145 + yield from self.iir.set_state(channel, y1, + profile=profile, coeff="y1") + coeff = dict(pow=0x1333, offset=0x1531, ftw0=0x1727, ftw1=0x1929, + a1=0x0135, b0=0x0337, b1=0x0539, cfg=adc | (0 << 3)) + for ks in "pow offset ftw0 ftw1", "a1 b0 b1 cfg": + for k in ks.split(): + yield from self.iir.set_coeff(channel, value=coeff[k], + profile=profile, coeff=k) + yield + + yield self.start.eq(1) + yield + yield self.start.eq(0) + while not (yield self.dds_tb.io_update): + yield + yield # io_update + + w = self.iir.widths + + x0 = x0 << (w.state - w.adc - 1) + _ = yield from self.iir.get_state(adc, coeff="x1") + assert _ == x0, (hex(_), hex(x0)) + + offset = coeff["offset"] << (w.state - w.coeff - 1) + a1, b0, b1 = coeff["a1"], coeff["b0"], coeff["b1"] + out = ( + 0*(1 << w.shift - 1) + # rounding + a1*(0 - y1) + b0*(offset - x0) + b1*(offset - x1) + ) >> w.shift + y1 = min(max(0, out), (1 << w.state - 1) - 1) + + _ = yield from self.iir.get_state(channel, profile, coeff="y1") + assert _ == y1, (hex(_), hex(y1)) + + _ = yield self.dds_tb.ddss[channel].ftw + ftw = (coeff["ftw1"] << 16) | coeff["ftw0"] + assert _ == ftw, (hex(_), hex(ftw)) + + _ = yield self.dds_tb.ddss[channel].pow + assert _ == coeff["pow"], (hex(_), hex(coeff["pow"])) + + _ = yield self.dds_tb.ddss[channel].asf + asf = y1 >> (w.state - w.asf - 1) + assert _ == asf, (hex(_), hex(asf)) + + +def main(): + servo = ServoSim() + run_simulation(servo, servo.test(), vcd_name="servo.vcd", + clocks={ + "sys": (8, 0), + "adc": (8, 0), + "ret": (8, 0), + "async": (2, 0), + }, + special_overrides={ + io.DDROutput: test_adc.DDROutput, + io.DDRInput: test_adc.DDRInput + }) + + +class ServoTest(unittest.TestCase): + def test_run(self): + main() + + +if __name__ == "__main__": + main() From d5eea962ec13d1c803682d216b0e5fb1c67bb273 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 23 Apr 2018 15:15:38 +0000 Subject: [PATCH 0630/2457] suservo: fix cnv_b diff --- artiq/gateware/suservo/adc_ser.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/suservo/adc_ser.py b/artiq/gateware/suservo/adc_ser.py index 8534e6f61..f8ac09cf3 100644 --- a/artiq/gateware/suservo/adc_ser.py +++ b/artiq/gateware/suservo/adc_ser.py @@ -76,6 +76,8 @@ class ADC(Module, DiffMixin): self.sync += pads.sck_en.eq(sck_en) # ODDR delay self.specials += io.DDROutput(0, sck_en, self._diff(pads, "sck", output=True)) + cnv_b = Signal() + self.comb += self._diff(pads, "cnv_b", output=True).eq(cnv_b) self.submodules.fsm = fsm = FSM("IDLE") fsm.act("IDLE", self.done.eq(1), @@ -86,7 +88,7 @@ class ADC(Module, DiffMixin): ) fsm.act("CNVH", count_load.eq(p.t_conv - 2), # account for sck ODDR delay - pads.cnv_b.eq(1), + cnv_b.eq(1), If(count_done, NextState("CONV") ) From 99dd9c7a2ae552c5fe6a85a09bfa235def46cc83 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 23 Apr 2018 15:15:52 +0000 Subject: [PATCH 0631/2457] suservo: fix rtio interface width --- artiq/gateware/rtio/phy/servo.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/rtio/phy/servo.py b/artiq/gateware/rtio/phy/servo.py index ff7695d0a..6070fad81 100644 --- a/artiq/gateware/rtio/phy/servo.py +++ b/artiq/gateware/rtio/phy/servo.py @@ -32,17 +32,18 @@ class RTServoMem(Module): m_state = servo.m_state.get_port(write_capable=True) self.specials += m_state, m_coeff - assert w.coeff >= w.state + assert w.state >= w.coeff + assert len(m_coeff.dat_w) == 2*w.coeff assert w.coeff >= w.word self.rtlink = rtlink.Interface( rtlink.OInterface( - w.coeff, + w.state, # coeff, profile, channel, 2 mems, rw 3 + w.profile + w.channel + 1 + 1, enable_replace=False), rtlink.IInterface( - w.coeff, + w.state, timestamped=False) ) @@ -52,7 +53,6 @@ class RTServoMem(Module): state_sel = self.rtlink.o.address[-2] high_coeff = self.rtlink.o.address[0] self.comb += [ - self.rtlink.o.busy.eq(active), m_coeff.adr.eq(self.rtlink.o.address[1:]), m_coeff.dat_w.eq(Cat(self.rtlink.o.data, self.rtlink.o.data)), m_coeff.we[0].eq(self.rtlink.o.stb & ~high_coeff & @@ -77,6 +77,7 @@ class RTServoMem(Module): ) ] self.comb += [ + self.rtlink.o.busy.eq(read), self.rtlink.i.stb.eq(read), self.rtlink.i.data.eq(Mux(state_sel, m_state.dat_r >> w.state - w.coeff, From 4c1e356f6794721c0116d7996815f1762712c928 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 23 Apr 2018 16:09:39 +0000 Subject: [PATCH 0632/2457] suservo: add pads rewiring layer for eems --- artiq/gateware/suservo/__init__.py | 0 artiq/gateware/suservo/pads.py | 43 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 artiq/gateware/suservo/__init__.py create mode 100644 artiq/gateware/suservo/pads.py diff --git a/artiq/gateware/suservo/__init__.py b/artiq/gateware/suservo/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/artiq/gateware/suservo/pads.py b/artiq/gateware/suservo/pads.py new file mode 100644 index 000000000..34e9924be --- /dev/null +++ b/artiq/gateware/suservo/pads.py @@ -0,0 +1,43 @@ +from migen import * +from migen.genlib.io import DifferentialOutput + + +class SamplerPads(Module): + def __init__(self, platform, eem0, eem1): + self.sck_p, self.sck_n = [ + platform.request("{}_adc_spi_{}".format(eem0, pol), 0).clk + for pol in "pn"] + pads = platform.request("{}_cnv".format(eem0), 0) + self.cnv_b_p, self.cnv_b_n = pads.p, pads.n + pads = platform.request("{}_sdr".format(eem0), 0) + self.specials += DifferentialOutput(0, pads.p, pads.n) + dp, dn = [ + platform.request("{}_adc_data_{}".format(eem0, pol), 0) + for pol in "pn"] + self.clkout_p, self.clkout_n = dp.clkout, dn.clkout + self.sdoa_p, self.sdoa_n = dp.sdoa, dn.sdoa + self.sdob_p, self.sdob_n = dp.sdob, dn.sdob + self.sdoc_p, self.sdoc_n = dp.sdoc, dn.sdoc + self.sdod_p, self.sdod_n = dp.sdod, dn.sdod + + +class UrukulPads(Module): + def __init__(self, platform, eem00, eem01, eem10, eem11): + spip, spin = [[ + platform.request("{}_qspi_{}".format(eem, pol), 0) + for eem in (eem00, eem10)] for pol in "pn"] + ioup = [platform.request("{}_io_update".format(eem), 0) + for eem in (eem00, eem10)] + self.cs_n = Signal() + self.clk = Signal() + self.io_update = Signal() + self.specials += [( + DifferentialOutput(self.cs_n, spip[i].cs_n, spin[i].cs_n), + DifferentialOutput(self.clk, spip[i].clk, spin[i].clk), + DifferentialOutput(self.io_update, ioup[i].p, ioup[i].n)) + for i in range(2)] + for i in range(8): + setattr(self, "mosi{}_p".format(i), + getattr(spip[i // 4], "mosi{}".format(i % 4))) + setattr(self, "mosi{}_n".format(i), + getattr(spin[i // 4], "mosi{}".format(i % 4))) From 929ed4471b1f472de81a42ef5b16dd7d5d93f2cc Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 23 Apr 2018 15:16:30 +0000 Subject: [PATCH 0633/2457] kasli/SUServo: use suservo, implement urukul_qspi m-labs/artiq#788 --- artiq/gateware/targets/kasli.py | 121 +++++++++++++++++++++++++------- 1 file changed, 94 insertions(+), 27 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index a6cd054c3..a7b996512 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -19,7 +19,9 @@ from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio -from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, spi2 +from artiq.gateware.rtio.phy import ( + ttl_simple, ttl_serdes_7series, spi2, servo as rtservo) +from artiq.gateware.suservo import servo, pads as servo_pads from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer @@ -328,6 +330,59 @@ def _urukul(eem, eem_aux=None): return ios +def _urukul_qspi(eem0, eem1): + ios = [ + ("{}_spi_p".format(eem0), 0, + Subsignal("clk", Pins(_eem_pin(eem0, 0, "p"))), + Subsignal("mosi", Pins(_eem_pin(eem0, 1, "p"))), + Subsignal("cs_n", Pins( + _eem_pin(eem0, 3, "p"), _eem_pin(eem0, 4, "p"))), + IOStandard("LVDS_25"), + ), + ("{}_spi_n".format(eem0), 0, + Subsignal("clk", Pins(_eem_pin(eem0, 0, "n"))), + Subsignal("mosi", Pins(_eem_pin(eem0, 1, "n"))), + Subsignal("cs_n", Pins( + _eem_pin(eem0, 3, "n"), _eem_pin(eem0, 4, "n"))), + IOStandard("LVDS_25"), + ), + ] + ttls = [(6, eem0, "io_update"), + (7, eem0, "dds_reset"), + (4, eem1, "sw0"), + (5, eem1, "sw1"), + (6, eem1, "sw2"), + (7, eem1, "sw3")] + for i, j, sig in ttls: + ios.append( + ("{}_{}".format(eem0, sig), 0, + Subsignal("p", Pins(_eem_pin(j, i, "p"))), + Subsignal("n", Pins(_eem_pin(j, i, "n"))), + IOStandard("LVDS_25") + )) + ios += [ + ("{}_qspi_p".format(eem0), 0, + Subsignal("cs_n", Pins(_eem_pin(eem0, 5, "p"))), + Subsignal("clk", Pins(_eem_pin(eem0, 2, "p"))), + Subsignal("mosi0", Pins(_eem_pin(eem1, 0, "p"))), + Subsignal("mosi1", Pins(_eem_pin(eem1, 1, "p"))), + Subsignal("mosi2", Pins(_eem_pin(eem1, 2, "p"))), + Subsignal("mosi3", Pins(_eem_pin(eem1, 3, "p"))), + IOStandard("LVDS_25"), + ), + ("{}_qspi_n".format(eem0), 0, + Subsignal("cs_n", Pins(_eem_pin(eem0, 5, "n"))), + Subsignal("clk", Pins(_eem_pin(eem0, 2, "n"))), + Subsignal("mosi0", Pins(_eem_pin(eem1, 0, "n"))), + Subsignal("mosi1", Pins(_eem_pin(eem1, 1, "n"))), + Subsignal("mosi2", Pins(_eem_pin(eem1, 2, "n"))), + Subsignal("mosi3", Pins(_eem_pin(eem1, 3, "n"))), + IOStandard("LVDS_25"), + ), + ] + return ios + + class Opticlock(_StandaloneBase): """ Opticlock extension variant configuration @@ -448,8 +503,8 @@ class SUServo(_StandaloneBase): platform.add_extension(_dio("eem0")) platform.add_extension(_dio("eem1")) platform.add_extension(_sampler("eem3", "eem2")) - platform.add_extension(_urukul("eem5", "eem4")) - platform.add_extension(_urukul("eem7", "eem6")) + platform.add_extension(_urukul_qspi("eem5", "eem4")) + platform.add_extension(_urukul_qspi("eem7", "eem6")) try: # EEM clock fan-out from Si5324, not MMCX, only Kasli/v1.0 @@ -470,23 +525,27 @@ class SUServo(_StandaloneBase): rtio_channels.append(rtio.Channel.from_phy(phy)) # EEM3, EEM2: Sampler - phy = spi2.SPIMaster(self.platform.request("eem3_adc_spi_p"), - self.platform.request("eem3_adc_spi_n")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=16)) - phy = spi2.SPIMaster(self.platform.request("eem3_pgia_spi_p"), - self.platform.request("eem3_pgia_spi_n")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=2)) + sampler_pads = servo_pads.SamplerPads(self.platform, "eem3", "eem2") + # EEM5, EEM4 and EEM7, EEM6: Urukul + urukul_pads = servo_pads.UrukulPads(self.platform, + "eem5", "eem4", "eem7", "eem6") + adc_p = servo.ADCParams(width=16, channels=8, lanes=4, + t_cnvh=4, t_conv=57, t_rtt=4) + iir_p = servo.IIRWidths(state=25, coeff=18, adc=16, + asf=14, word=16, accu=48, shift=11, + channel=3, profile=5) + dds_p = servo.DDSParams(width=8 + 32 + 16 + 16, + channels=adc_p.channels, clk=1) + su = servo.Servo(sampler_pads, urukul_pads, adc_p, iir_p, dds_p) + su = ClockDomainsRenamer({"sys": "rio_phy"})(su) + self.submodules += sampler_pads, urukul_pads, su - for signal in "cnv".split(): - pads = platform.request("eem3_{}".format(signal)) - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - pads = platform.request("eem3_sdr") - self.specials += DifferentialOutput(1, pads.p, pads.n) + ctrls = [rtservo.RTServoCtrl(ctrl) for ctrl in su.iir.ctrl] + self.submodules += ctrls + rtio_channels.extend(rtio.Channel.from_phy(ctrl) for ctrl in ctrls) + mem = rtservo.RTServoMem(iir_p, su.iir) + self.submodules += mem + rtio_channels.append(rtio.Channel.from_phy(mem, ififo_depth=4)) # EEM5 + EEM4: Urukul phy = spi2.SPIMaster(self.platform.request("eem5_spi_p"), @@ -497,11 +556,11 @@ class SUServo(_StandaloneBase): pads = platform.request("eem5_dds_reset") self.specials += DifferentialOutput(0, pads.p, pads.n) - for signal in "io_update sw0 sw1 sw2 sw3".split(): + for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): pads = platform.request("eem5_{}".format(signal)) - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + self.specials += DifferentialOutput( + su.iir.ctrl[i].en_out, + pads.p, pads.n) # EEM7 + EEM6: Urukul phy = spi2.SPIMaster(self.platform.request("eem7_spi_p"), @@ -512,11 +571,11 @@ class SUServo(_StandaloneBase): pads = platform.request("eem7_dds_reset") self.specials += DifferentialOutput(0, pads.p, pads.n) - for signal in "io_update sw0 sw1 sw2 sw3".split(): + for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): pads = platform.request("eem7_{}".format(signal)) - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + self.specials += DifferentialOutput( + su.iir.ctrl[i + 4].en_out, + pads.p, pads.n) for i in (1, 2): sfp_ctl = platform.request("sfp_ctl", i) @@ -530,6 +589,14 @@ class SUServo(_StandaloneBase): self.add_rtio(rtio_channels) + platform.add_period_constraint(su.adc.cd_ret.clk, 8.) + platform.add_false_path_constraints( + su.adc.cd_ret.clk, + self.rtio_crg.cd_rtio.clk) + platform.add_false_path_constraints( + su.adc.cd_ret.clk, + self.crg.cd_sys.clk) + class SYSU(_StandaloneBase): def __init__(self, **kwargs): From e36deab0a8977fc4723686c713f255c8fb92fc1e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 23 Apr 2018 18:21:03 +0000 Subject: [PATCH 0634/2457] suservo/adc: try to help vivado extract srls --- artiq/gateware/suservo/adc_ser.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/suservo/adc_ser.py b/artiq/gateware/suservo/adc_ser.py index f8ac09cf3..0bf4a4b85 100644 --- a/artiq/gateware/suservo/adc_ser.py +++ b/artiq/gateware/suservo/adc_ser.py @@ -126,16 +126,18 @@ class ADC(Module, DiffMixin): k = p.channels//p.lanes assert 2*t_read == k*p.width for i, sdo in enumerate(sdo): - sdo_sr = Signal(2*t_read - 2) + sdo_sr0 = Signal(t_read - 1) + sdo_sr1 = Signal(t_read - 1) sdo_ddr = Signal(2) self.specials += io.DDRInput(sdo, sdo_ddr[1], sdo_ddr[0], self.cd_ret.clk) self.sync.ret += [ If(self.reading & sck_en_ret, - sdo_sr.eq(Cat(sdo_ddr, sdo_sr)) + sdo_sr0.eq(Cat(sdo_ddr[0], sdo_sr0)), + sdo_sr1.eq(Cat(sdo_ddr[1], sdo_sr1)) ) ] self.comb += [ Cat(reversed([self.data[i*k + j] for j in range(k)])).eq( - Cat(sdo_ddr, sdo_sr)) + Cat(sdo_ddr, zip(sdo_sr0, sdo_sr1))) ] From 4903eb074c025e1b437fcfa3b39ea54c47d7e977 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 23 Apr 2018 18:24:22 +0000 Subject: [PATCH 0635/2457] suservo: use BUFIO/BUFH for ADC --- artiq/gateware/suservo/adc_ser.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/suservo/adc_ser.py b/artiq/gateware/suservo/adc_ser.py index 0bf4a4b85..c010cd3b9 100644 --- a/artiq/gateware/suservo/adc_ser.py +++ b/artiq/gateware/suservo/adc_ser.py @@ -119,9 +119,16 @@ class ADC(Module, DiffMixin): except AttributeError: sck_en_ret = 1 self.clock_domains.cd_ret = ClockDomain("ret", reset_less=True) + clkout = self._diff(pads, "clkout") + clkout_fabric = Signal() + clkout_io = Signal() + self.specials += [ + Instance("BUFH", i_I=clkout, o_O=clkout_fabric), + Instance("BUFIO", i_I=clkout, o_O=clkout_io) + ] self.comb += [ # falling clkout makes two bits available - self.cd_ret.clk.eq(~self._diff(pads, "clkout")), + self.cd_ret.clk.eq(~clkout_fabric) ] k = p.channels//p.lanes assert 2*t_read == k*p.width @@ -130,7 +137,7 @@ class ADC(Module, DiffMixin): sdo_sr1 = Signal(t_read - 1) sdo_ddr = Signal(2) self.specials += io.DDRInput(sdo, sdo_ddr[1], sdo_ddr[0], - self.cd_ret.clk) + ~clkout_io) self.sync.ret += [ If(self.reading & sck_en_ret, sdo_sr0.eq(Cat(sdo_ddr[0], sdo_sr0)), From f74998a5e043ac9efb26989c44068627c24528cd Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 23 Apr 2018 21:11:26 +0000 Subject: [PATCH 0636/2457] suservo: move arch logic to top, fix tests --- artiq/gateware/suservo/adc_ser.py | 15 ++------------- artiq/gateware/targets/kasli.py | 15 ++++++++++++++- artiq/gateware/test/suservo/test_adc.py | 7 +++++++ artiq/gateware/test/suservo/test_servo.py | 1 + 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/artiq/gateware/suservo/adc_ser.py b/artiq/gateware/suservo/adc_ser.py index c010cd3b9..f0006d927 100644 --- a/artiq/gateware/suservo/adc_ser.py +++ b/artiq/gateware/suservo/adc_ser.py @@ -118,18 +118,7 @@ class ADC(Module, DiffMixin): sck_en_ret = pads.sck_en_ret except AttributeError: sck_en_ret = 1 - self.clock_domains.cd_ret = ClockDomain("ret", reset_less=True) - clkout = self._diff(pads, "clkout") - clkout_fabric = Signal() - clkout_io = Signal() - self.specials += [ - Instance("BUFH", i_I=clkout, o_O=clkout_fabric), - Instance("BUFIO", i_I=clkout, o_O=clkout_io) - ] - self.comb += [ - # falling clkout makes two bits available - self.cd_ret.clk.eq(~clkout_fabric) - ] + self.clkout_io = Signal() k = p.channels//p.lanes assert 2*t_read == k*p.width for i, sdo in enumerate(sdo): @@ -137,7 +126,7 @@ class ADC(Module, DiffMixin): sdo_sr1 = Signal(t_read - 1) sdo_ddr = Signal(2) self.specials += io.DDRInput(sdo, sdo_ddr[1], sdo_ddr[0], - ~clkout_io) + ~self.clkout_io) self.sync.ret += [ If(self.reading & sck_en_ret, sdo_sr0.eq(Cat(sdo_ddr[0], sdo_sr0)), diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index a7b996512..de3aad6c8 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -8,7 +8,7 @@ from migen.genlib.cdc import MultiReg from migen.build.generic_platform import * from migen.build.xilinx.vivado import XilinxVivadoToolchain from migen.build.xilinx.ise import XilinxISEToolchain -from migen.genlib.io import DifferentialOutput +from migen.genlib.io import DifferentialOutput, DifferentialInput from misoc.interconnect.csr import * from misoc.cores import gpio @@ -540,6 +540,19 @@ class SUServo(_StandaloneBase): su = ClockDomainsRenamer({"sys": "rio_phy"})(su) self.submodules += sampler_pads, urukul_pads, su + self.clock_domains.cd_ret = ClockDomain("ret", reset_less=True) + clkout = Signal() + clkout_fabric = Signal() + self.specials += [ + DifferentialInput(pads.clkout_p, pads.clkout_n, clkout), + Instance("BUFH", i_I=clkout, o_O=clkout_fabric), + Instance("BUFIO", i_I=clkout, o_O=su.adc.clkout_io) + ] + self.comb += [ + # falling clkout makes two bits available + self.cd_ret.clk.eq(~clkout_fabric) + ] + ctrls = [rtservo.RTServoCtrl(ctrl) for ctrl in su.iir.ctrl] self.submodules += ctrls rtio_channels.extend(rtio.Channel.from_phy(ctrl) for ctrl in ctrls) diff --git a/artiq/gateware/test/suservo/test_adc.py b/artiq/gateware/test/suservo/test_adc.py index 2dbcd6342..3fc11352f 100644 --- a/artiq/gateware/test/suservo/test_adc.py +++ b/artiq/gateware/test/suservo/test_adc.py @@ -75,6 +75,12 @@ class TB(Module): cd_adc = ClockDomain("adc", reset_less=True) self.clock_domains += cd_adc + self.clock_domains.cd_ret = ClockDomain("ret", reset_less=True) + self.comb += [ + # falling clkout makes two bits available + self.cd_ret.clk.eq(~self.clkout) + ] + self.sdo = [] self.data = [Signal((p.width, True), reset_less=True) for i in range(p.channels)] @@ -124,6 +130,7 @@ def main(): tb = TB(params) adc = ADC(tb, params) tb.submodules += adc + tb.comb += adc.clkout_io.eq(tb.clkout) def run(tb): dut = adc diff --git a/artiq/gateware/test/suservo/test_servo.py b/artiq/gateware/test/suservo/test_servo.py index c8b43349e..a33c379a7 100644 --- a/artiq/gateware/test/suservo/test_servo.py +++ b/artiq/gateware/test/suservo/test_servo.py @@ -23,6 +23,7 @@ class ServoSim(servo.Servo): servo.Servo.__init__(self, self.adc_tb, self.dds_tb, adc_p, iir_p, dds_p) + self.adc_tb.comb += self.adc.clkout_io.eq(self.adc_tb.clkout) def test(self): assert (yield self.done) From 3942c2d274565cf1328ae2c498777f9d6826d8da Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 24 Apr 2018 10:18:32 +0000 Subject: [PATCH 0637/2457] suservo: fix clkout cd drive --- artiq/gateware/targets/kasli.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index de3aad6c8..bbad616dd 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -544,7 +544,8 @@ class SUServo(_StandaloneBase): clkout = Signal() clkout_fabric = Signal() self.specials += [ - DifferentialInput(pads.clkout_p, pads.clkout_n, clkout), + DifferentialInput( + sampler_pads.clkout_p, sampler_pads.clkout_n, clkout), Instance("BUFH", i_I=clkout, o_O=clkout_fabric), Instance("BUFIO", i_I=clkout, o_O=su.adc.clkout_io) ] @@ -602,12 +603,12 @@ class SUServo(_StandaloneBase): self.add_rtio(rtio_channels) - platform.add_period_constraint(su.adc.cd_ret.clk, 8.) + platform.add_period_constraint(self.cd_ret.clk, 8.) platform.add_false_path_constraints( - su.adc.cd_ret.clk, + self.cd_ret.clk, self.rtio_crg.cd_rtio.clk) platform.add_false_path_constraints( - su.adc.cd_ret.clk, + self.cd_ret.clk, self.crg.cd_sys.clk) From fe75064c1e22290c6c16635fbe3927b9a3bcc7c6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 24 Apr 2018 13:08:40 +0000 Subject: [PATCH 0638/2457] suservo: cleanup rtio interface --- artiq/gateware/rtio/phy/servo.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/artiq/gateware/rtio/phy/servo.py b/artiq/gateware/rtio/phy/servo.py index 6070fad81..24d1ef5b4 100644 --- a/artiq/gateware/rtio/phy/servo.py +++ b/artiq/gateware/rtio/phy/servo.py @@ -32,18 +32,19 @@ class RTServoMem(Module): m_state = servo.m_state.get_port(write_capable=True) self.specials += m_state, m_coeff + # just expose the w.coeff (18) MSBs of state assert w.state >= w.coeff assert len(m_coeff.dat_w) == 2*w.coeff assert w.coeff >= w.word self.rtlink = rtlink.Interface( rtlink.OInterface( - w.state, + data_width=w.coeff, # coeff, profile, channel, 2 mems, rw - 3 + w.profile + w.channel + 1 + 1, + address_width=3 + w.profile + w.channel + 1 + 1, enable_replace=False), rtlink.IInterface( - w.state, + data_width=w.coeff, timestamped=False) ) @@ -53,6 +54,7 @@ class RTServoMem(Module): state_sel = self.rtlink.o.address[-2] high_coeff = self.rtlink.o.address[0] self.comb += [ + self.rtlink.o.busy.eq(0), m_coeff.adr.eq(self.rtlink.o.address[1:]), m_coeff.dat_w.eq(Cat(self.rtlink.o.data, self.rtlink.o.data)), m_coeff.we[0].eq(self.rtlink.o.stb & ~high_coeff & @@ -60,7 +62,7 @@ class RTServoMem(Module): m_coeff.we[1].eq(self.rtlink.o.stb & high_coeff & we & ~state_sel), m_state.adr.eq(self.rtlink.o.address), - m_state.dat_w.eq(self.rtlink.o.data << w.state - w.coeff), + m_state.dat_w[w.state - w.coeff:].eq(self.rtlink.o.data), m_state.we.eq(self.rtlink.o.stb & we & state_sel), ] read = Signal() @@ -70,17 +72,20 @@ class RTServoMem(Module): If(read, read.eq(0) ), - If(self.rtlink.o.stb & ~we, - read.eq(1), + If(self.rtlink.o.stb, + read.eq(~we), read_sel.eq(state_sel), read_high.eq(high_coeff), ) ] self.comb += [ - self.rtlink.o.busy.eq(read), self.rtlink.i.stb.eq(read), - self.rtlink.i.data.eq(Mux(state_sel, - m_state.dat_r >> w.state - w.coeff, - Mux(read_high, m_coeff.dat_r[w.coeff:], - m_coeff.dat_r))) + self.rtlink.i.data.eq( + Mux( + state_sel, + m_state.dat_r[w.state - w.coeff:], + Mux( + read_high, + m_coeff.dat_r[w.coeff:], + m_coeff.dat_r[:w.coeff]))) ] From d0258b9b2d60f2f09d6af065240bded3100a39bb Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 24 Apr 2018 14:40:37 +0000 Subject: [PATCH 0639/2457] suservo: set input delays --- artiq/gateware/targets/kasli.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index bbad616dd..2619a8656 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -603,13 +603,29 @@ class SUServo(_StandaloneBase): self.add_rtio(rtio_channels) - platform.add_period_constraint(self.cd_ret.clk, 8.) + platform.add_period_constraint(sampler_pads.clkout_p, 8.) platform.add_false_path_constraints( - self.cd_ret.clk, + sampler_pads.clkout_p, self.rtio_crg.cd_rtio.clk) platform.add_false_path_constraints( - self.cd_ret.clk, + sampler_pads.clkout_p, self.crg.cd_sys.clk) + for i in "abcd": + port = getattr(sampler_pads, "sdo{}_p".format(i)) + platform.add_platform_command( + "set_input_delay -clock [get_clocks " + "-include_generated_clocks -of [get_nets {clk}]] " + "-max 6 [get_ports {port}]\n" + "set_input_delay -clock [get_clocks " + "-include_generated_clocks -of [get_nets {clk}]] " + "-min 3.5 [get_ports {port}]\n" + "set_input_delay -clock [get_clocks " + "-include_generated_clocks -of [get_nets {clk}]] " + "-max 6 [get_ports {port}] -clock_fall -add_delay\n" + "set_input_delay -clock [get_clocks " + "-include_generated_clocks -of [get_nets {clk}]] " + "-min 3.5 [get_ports {port}] -clock_fall -add_delay", + clk=sampler_pads.clkout_p, port=port) class SYSU(_StandaloneBase): From 37c186a0fcd93ff50074dcd978ca851ecf1dc3b4 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 25 Apr 2018 13:44:52 +0000 Subject: [PATCH 0640/2457] suservo: refactor, constrain * remove DiffMixin, move pad layout handling to pads * add input delay constraints, IDELAYs --- artiq/gateware/suservo/adc_ser.py | 34 ++++---- artiq/gateware/suservo/dds_ser.py | 2 +- artiq/gateware/suservo/pads.py | 94 ++++++++++++++++++----- artiq/gateware/suservo/spi.py | 11 +-- artiq/gateware/suservo/tools.py | 19 ----- artiq/gateware/targets/kasli.py | 31 -------- artiq/gateware/test/suservo/test_adc.py | 77 ++----------------- artiq/gateware/test/suservo/test_servo.py | 1 - 8 files changed, 101 insertions(+), 168 deletions(-) delete mode 100644 artiq/gateware/suservo/tools.py diff --git a/artiq/gateware/suservo/adc_ser.py b/artiq/gateware/suservo/adc_ser.py index f0006d927..865017e18 100644 --- a/artiq/gateware/suservo/adc_ser.py +++ b/artiq/gateware/suservo/adc_ser.py @@ -5,8 +5,6 @@ from collections import namedtuple from migen import * from migen.genlib import io -from .tools import DiffMixin - logger = logging.getLogger(__name__) @@ -28,7 +26,7 @@ ADCParams = namedtuple("ADCParams", [ ]) -class ADC(Module, DiffMixin): +class ADC(Module): """Multi-lane, multi-channel, triggered, source-synchronous, serial ADC interface. @@ -49,7 +47,7 @@ class ADC(Module, DiffMixin): # collect sdo lines sdo = [] for i in string.ascii_lowercase[:p.lanes]: - sdo.append(self._diff(pads, "sdo" + i)) + sdo.append(getattr(pads, "sdo" + i)) assert p.lanes == len(sdo) # set up counters for the four states CNVH, CONV, READ, RTT @@ -71,13 +69,6 @@ class ADC(Module, DiffMixin): ) ] - sck_en = Signal() - if hasattr(pads, "sck_en"): - self.sync += pads.sck_en.eq(sck_en) # ODDR delay - self.specials += io.DDROutput(0, sck_en, - self._diff(pads, "sck", output=True)) - cnv_b = Signal() - self.comb += self._diff(pads, "cnv_b", output=True).eq(cnv_b) self.submodules.fsm = fsm = FSM("IDLE") fsm.act("IDLE", self.done.eq(1), @@ -88,7 +79,7 @@ class ADC(Module, DiffMixin): ) fsm.act("CNVH", count_load.eq(p.t_conv - 2), # account for sck ODDR delay - cnv_b.eq(1), + pads.cnv.eq(1), If(count_done, NextState("CONV") ) @@ -102,7 +93,7 @@ class ADC(Module, DiffMixin): fsm.act("READ", self.reading.eq(1), count_load.eq(p.t_rtt), # account for sck ODDR delay - sck_en.eq(1), + pads.sck_en.eq(1), If(count_done, NextState("RTT") ) @@ -118,22 +109,25 @@ class ADC(Module, DiffMixin): sck_en_ret = pads.sck_en_ret except AttributeError: sck_en_ret = 1 - self.clkout_io = Signal() + + self.clock_domains.cd_ret = ClockDomain("ret", reset_less=True) + self.comb += [ + # falling clkout makes two bits available + self.cd_ret.clk.eq(~pads.clkout) + ] + k = p.channels//p.lanes assert 2*t_read == k*p.width for i, sdo in enumerate(sdo): sdo_sr0 = Signal(t_read - 1) sdo_sr1 = Signal(t_read - 1) - sdo_ddr = Signal(2) - self.specials += io.DDRInput(sdo, sdo_ddr[1], sdo_ddr[0], - ~self.clkout_io) self.sync.ret += [ If(self.reading & sck_en_ret, - sdo_sr0.eq(Cat(sdo_ddr[0], sdo_sr0)), - sdo_sr1.eq(Cat(sdo_ddr[1], sdo_sr1)) + sdo_sr0.eq(Cat(sdo[0], sdo_sr0)), + sdo_sr1.eq(Cat(sdo[1], sdo_sr1)) ) ] self.comb += [ Cat(reversed([self.data[i*k + j] for j in range(k)])).eq( - Cat(sdo_ddr, zip(sdo_sr0, sdo_sr1))) + Cat(sdo, zip(sdo_sr0, sdo_sr1))) ] diff --git a/artiq/gateware/suservo/dds_ser.py b/artiq/gateware/suservo/dds_ser.py index 4f6d1f1f2..7ce0021fb 100644 --- a/artiq/gateware/suservo/dds_ser.py +++ b/artiq/gateware/suservo/dds_ser.py @@ -36,7 +36,7 @@ class DDS(spi.SPISimple): ) ] - io_update = self._diff(pads, "io_update", output=True) + io_update = pads.io_update # this assumes that the cycle time (1/125 MHz = 8 ns) is >1 SYNC_CLK # cycle (1/250 MHz = 4ns) done = Signal() diff --git a/artiq/gateware/suservo/pads.py b/artiq/gateware/suservo/pads.py index 34e9924be..91dfb3783 100644 --- a/artiq/gateware/suservo/pads.py +++ b/artiq/gateware/suservo/pads.py @@ -1,24 +1,77 @@ from migen import * -from migen.genlib.io import DifferentialOutput +from migen.genlib.io import DifferentialOutput, DifferentialInput, DDROutput class SamplerPads(Module): def __init__(self, platform, eem0, eem1): - self.sck_p, self.sck_n = [ - platform.request("{}_adc_spi_{}".format(eem0, pol), 0).clk - for pol in "pn"] - pads = platform.request("{}_cnv".format(eem0), 0) - self.cnv_b_p, self.cnv_b_n = pads.p, pads.n - pads = platform.request("{}_sdr".format(eem0), 0) - self.specials += DifferentialOutput(0, pads.p, pads.n) - dp, dn = [ - platform.request("{}_adc_data_{}".format(eem0, pol), 0) - for pol in "pn"] - self.clkout_p, self.clkout_n = dp.clkout, dn.clkout - self.sdoa_p, self.sdoa_n = dp.sdoa, dn.sdoa - self.sdob_p, self.sdob_n = dp.sdob, dn.sdob - self.sdoc_p, self.sdoc_n = dp.sdoc, dn.sdoc - self.sdod_p, self.sdod_n = dp.sdod, dn.sdod + self.sck_en = Signal() + self.cnv = Signal() + self.clkout = Signal() + + spip = platform.request("{}_adc_spi_p".format(eem0)) + spin = platform.request("{}_adc_spi_n".format(eem0)) + cnv = platform.request("{}_cnv".format(eem0)) + sdr = platform.request("{}_sdr".format(eem0)) + dp = platform.request("{}_adc_data_p".format(eem0)) + dn = platform.request("{}_adc_data_n".format(eem0)) + + clkout_se = Signal() + clkout_d = Signal() + sck = Signal() + + self.specials += [ + DifferentialOutput(self.cnv, cnv.p, cnv.n), + DifferentialOutput(1, sdr.p, sdr.n), + DDROutput(0, self.sck_en, sck), + DifferentialOutput(sck, spip.clk, spin.clk), + DifferentialInput(dp.clkout, dn.clkout, clkout_se), + Instance( + "IDELAYE2", + p_HIGH_PERFORMANCE_MODE="TRUE", p_IDELAY_TYPE="FIXED", + p_SIGNAL_PATTERN="CLOCK", p_IDELAY_VALUE=0, + p_REFCLK_FREQUENCY=200., + i_IDATAIN=clkout_se, o_DATAOUT=clkout_d), + Instance("BUFR", i_I=clkout_d, o_O=self.clkout) + ] + + # here to be early before the input delays below to have the clock + # available + self.clkout_p = dp.clkout # availabel for false paths + platform.add_platform_command( + "create_clock -name {clk} -period 8 [get_nets {clk}]", + clk=dp.clkout) + # platform.add_period_constraint(sampler_pads.clkout_p, 8.) + for i in "abcd": + sdo_se = Signal() + sdo_d = Signal() + sdo = Signal(2) + setattr(self, "sdo{}".format(i), sdo) + sdop = getattr(dp, "sdo{}".format(i)) + sdon = getattr(dn, "sdo{}".format(i)) + self.specials += [ + DifferentialInput(sdop, sdon, sdo_se), + Instance( + "IDELAYE2", + p_HIGH_PERFORMANCE_MODE="TRUE", p_IDELAY_TYPE="FIXED", + p_SIGNAL_PATTERN="DATA", p_IDELAY_VALUE=31, + p_REFCLK_FREQUENCY=200., + i_IDATAIN=sdo_se, o_DATAOUT=sdo_d), + Instance("IDDR", + p_DDR_CLK_EDGE="SAME_EDGE", + i_C=~self.clkout, i_CE=1, i_S=0, i_R=0, + i_D=sdo_d, o_Q1=sdo[0], o_Q2=sdo[1]) # sdo[1] older + ] + # 4, -0+1.5 hold (t_HSDO_DDR), -0.2+0.2 skew + platform.add_platform_command( + "set_input_delay -clock {clk} " + "-max 1.6 [get_ports {port}]\n" + "set_input_delay -clock {clk} " + "-min -0.1 [get_ports {port}]\n" + "set_input_delay -clock {clk} " + "-max 1.6 [get_ports {port}] -clock_fall -add_delay\n" + "set_input_delay -clock {clk} " + "-min -0.1 [get_ports {port}] -clock_fall -add_delay", + clk=dp.clkout, port=sdop) class UrukulPads(Module): @@ -37,7 +90,10 @@ class UrukulPads(Module): DifferentialOutput(self.io_update, ioup[i].p, ioup[i].n)) for i in range(2)] for i in range(8): - setattr(self, "mosi{}_p".format(i), - getattr(spip[i // 4], "mosi{}".format(i % 4))) - setattr(self, "mosi{}_n".format(i), + mosi = Signal() + setattr(self, "mosi{}".format(i), mosi) + self.specials += [ + DifferentialOutput(mosi, + getattr(spip[i // 4], "mosi{}".format(i % 4)), getattr(spin[i // 4], "mosi{}".format(i % 4))) + ] diff --git a/artiq/gateware/suservo/spi.py b/artiq/gateware/suservo/spi.py index 791486589..d1d129aa9 100644 --- a/artiq/gateware/suservo/spi.py +++ b/artiq/gateware/suservo/spi.py @@ -5,8 +5,6 @@ from migen import * from migen.genlib.fsm import FSM, NextState from migen.genlib import io -from .tools import DiffMixin - logger = logging.getLogger(__name__) @@ -19,7 +17,7 @@ SPIParams = namedtuple("SPIParams", [ ]) -class SPISimple(Module, DiffMixin): +class SPISimple(Module): """Simple reduced SPI interface. * Multiple MOSI lines @@ -39,9 +37,8 @@ class SPISimple(Module, DiffMixin): assert p.clk >= 1 - cs_n = self._diff(pads, "cs_n", output=True) - - clk = self._diff(pads, "clk", output=True) + cs_n = pads.cs_n + clk = pads.clk cnt = Signal(max=max(2, p.clk), reset_less=True) cnt_done = Signal() cnt_next = Signal() @@ -58,7 +55,7 @@ class SPISimple(Module, DiffMixin): for i, d in enumerate(self.data): self.comb += [ - self._diff(pads, "mosi{}".format(i), output=True).eq(d[-1]) + getattr(pads, "mosi{}".format(i)).eq(d[-1]) ] bits = Signal(max=p.width + 1, reset_less=True) diff --git a/artiq/gateware/suservo/tools.py b/artiq/gateware/suservo/tools.py deleted file mode 100644 index 7a4feac1f..000000000 --- a/artiq/gateware/suservo/tools.py +++ /dev/null @@ -1,19 +0,0 @@ -from migen import * -from migen.genlib import io - - -class DiffMixin: - def _diff(self, pads, name, output=False): - """Retrieve the single-ended ``Signal()`` ``name`` from - ``pads`` and in its absence retrieve the differential signal with the - pin pairs ``name_p`` and ``name_n``. Do so as an output if ``output``, - otherwise make a differential input.""" - if hasattr(pads, name): - return getattr(pads, name) - sig = Signal() - p, n = (getattr(pads, name + "_" + s) for s in "pn") - if output: - self.specials += io.DifferentialOutput(sig, p, n) - else: - self.specials += io.DifferentialInput(p, n, sig) - return sig diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 2619a8656..6bd39081f 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -540,20 +540,6 @@ class SUServo(_StandaloneBase): su = ClockDomainsRenamer({"sys": "rio_phy"})(su) self.submodules += sampler_pads, urukul_pads, su - self.clock_domains.cd_ret = ClockDomain("ret", reset_less=True) - clkout = Signal() - clkout_fabric = Signal() - self.specials += [ - DifferentialInput( - sampler_pads.clkout_p, sampler_pads.clkout_n, clkout), - Instance("BUFH", i_I=clkout, o_O=clkout_fabric), - Instance("BUFIO", i_I=clkout, o_O=su.adc.clkout_io) - ] - self.comb += [ - # falling clkout makes two bits available - self.cd_ret.clk.eq(~clkout_fabric) - ] - ctrls = [rtservo.RTServoCtrl(ctrl) for ctrl in su.iir.ctrl] self.submodules += ctrls rtio_channels.extend(rtio.Channel.from_phy(ctrl) for ctrl in ctrls) @@ -603,29 +589,12 @@ class SUServo(_StandaloneBase): self.add_rtio(rtio_channels) - platform.add_period_constraint(sampler_pads.clkout_p, 8.) platform.add_false_path_constraints( sampler_pads.clkout_p, self.rtio_crg.cd_rtio.clk) platform.add_false_path_constraints( sampler_pads.clkout_p, self.crg.cd_sys.clk) - for i in "abcd": - port = getattr(sampler_pads, "sdo{}_p".format(i)) - platform.add_platform_command( - "set_input_delay -clock [get_clocks " - "-include_generated_clocks -of [get_nets {clk}]] " - "-max 6 [get_ports {port}]\n" - "set_input_delay -clock [get_clocks " - "-include_generated_clocks -of [get_nets {clk}]] " - "-min 3.5 [get_ports {port}]\n" - "set_input_delay -clock [get_clocks " - "-include_generated_clocks -of [get_nets {clk}]] " - "-max 6 [get_ports {port}] -clock_fall -add_delay\n" - "set_input_delay -clock [get_clocks " - "-include_generated_clocks -of [get_nets {clk}]] " - "-min 3.5 [get_ports {port}] -clock_fall -add_delay", - clk=sampler_pads.clkout_p, port=port) class SYSU(_StandaloneBase): diff --git a/artiq/gateware/test/suservo/test_adc.py b/artiq/gateware/test/suservo/test_adc.py index 3fc11352f..6f74c19ea 100644 --- a/artiq/gateware/test/suservo/test_adc.py +++ b/artiq/gateware/test/suservo/test_adc.py @@ -8,57 +8,6 @@ from migen.genlib import io from artiq.gateware.suservo.adc_ser import ADC, ADCParams -class DDROutputImpl(Module): - def __init__(self, i1, i2, o, clk): - do_clk0 = Signal(reset_less=True) - do_j1 = Signal(reset_less=True) - do_j2 = Signal(reset_less=True) - do_j3 = Signal(reset_less=True) - self.sync.async += [ - do_clk0.eq(clk), - do_j1.eq(i1), - do_j2.eq(i2), - If(Cat(do_clk0, clk) == 0b10, - o.eq(do_j1), - do_j3.eq(do_j2), - ).Elif(Cat(do_clk0, clk) == 0b01, - o.eq(do_j3), - ) - ] - - -class DDROutput: - @staticmethod - def lower(dr): - return DDROutputImpl(dr.i1, dr.i2, dr.o, dr.clk) - - -class DDRInputImpl(Module): - def __init__(self, i, o1, o2, clk): - di_clk0 = Signal(reset_less=True) - # SAME_EDGE_PIPELINED is effectively one register for o1 - # (during rising clock) - di_j1 = Signal(reset_less=True) - di_j2 = Signal(reset_less=True) - di_j3 = Signal(reset_less=True) - self.sync.async += [ - di_clk0.eq(clk), - di_j1.eq(i), - If(Cat(di_clk0, clk) == 0b10, - di_j3.eq(di_j1), - o1.eq(di_j3), - o2.eq(di_j2) - ).Elif(Cat(di_clk0, clk) == 0b01, - di_j2.eq(di_j1) - ) - ] - - -class DDRInput: - @staticmethod - def lower(dr): - return DDRInputImpl(dr.i, dr.o1, dr.o2, dr.clk) - class TB(Module): def __init__(self, params): @@ -66,7 +15,7 @@ class TB(Module): self.sck = Signal() self.clkout = Signal(reset_less=True) - self.cnv_b = Signal() + self.cnv = Signal() self.sck_en = Signal() self.sck_en_ret = Signal() @@ -75,12 +24,6 @@ class TB(Module): cd_adc = ClockDomain("adc", reset_less=True) self.clock_domains += cd_adc - self.clock_domains.cd_ret = ClockDomain("ret", reset_less=True) - self.comb += [ - # falling clkout makes two bits available - self.cd_ret.clk.eq(~self.clkout) - ] - self.sdo = [] self.data = [Signal((p.width, True), reset_less=True) for i in range(p.channels)] @@ -88,23 +31,21 @@ class TB(Module): srs = [] for i in range(p.lanes): name = "sdo" + string.ascii_lowercase[i] - sdo = Signal(name=name, reset_less=True) + sdo = Signal(2, name=name, reset_less=True) self.sdo.append(sdo) setattr(self, name, sdo) sr = Signal(p.width*p.channels//p.lanes, reset_less=True) srs.append(sr) - self.specials += io.DDROutput( - # one for async - self._dly(sr[-1], -1), self._dly(sr[-2], -1), sdo) self.sync.adc += [ + sdo.eq(Cat(self._dly(sr[-1], 3), self._dly(sr[-2], 3))), If(adc_sck_en, sr[2:].eq(sr) ) ] - cnv_b_old = Signal(reset_less=True) + cnv_old = Signal(reset_less=True) self.sync.async += [ - cnv_b_old.eq(self.cnv_b), - If(Cat(cnv_b_old, self.cnv_b) == 0b10, + cnv_old.eq(self.cnv), + If(Cat(cnv_old, self.cnv) == 0b10, sr.eq(Cat(reversed(self.data[2*i:2*i + 2]))), ) ] @@ -130,7 +71,6 @@ def main(): tb = TB(params) adc = ADC(tb, params) tb.submodules += adc - tb.comb += adc.clkout_io.eq(tb.clkout) def run(tb): dut = adc @@ -156,10 +96,7 @@ def main(): "ret": (8, 0), "async": (2, 0), }, - special_overrides={ - io.DDROutput: DDROutput, - io.DDRInput: DDRInput - }) + ) class ADCTest(unittest.TestCase): diff --git a/artiq/gateware/test/suservo/test_servo.py b/artiq/gateware/test/suservo/test_servo.py index a33c379a7..c8b43349e 100644 --- a/artiq/gateware/test/suservo/test_servo.py +++ b/artiq/gateware/test/suservo/test_servo.py @@ -23,7 +23,6 @@ class ServoSim(servo.Servo): servo.Servo.__init__(self, self.adc_tb, self.dds_tb, adc_p, iir_p, dds_p) - self.adc_tb.comb += self.adc.clkout_io.eq(self.adc_tb.clkout) def test(self): assert (yield self.done) From b44d6517d1cbf960804c0c5c3c9f8bdf2a20d484 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 25 Apr 2018 14:23:22 +0000 Subject: [PATCH 0641/2457] suservo: use 125 MHz SDR ADC * easier timing * natural sampling on rising edge * timing, signal robustness * adjust the servo iteration timing --- artiq/gateware/suservo/adc_ser.py | 27 +++++++++++------------ artiq/gateware/suservo/pads.py | 23 ++++++------------- artiq/gateware/suservo/servo.py | 7 +++--- artiq/gateware/test/suservo/test_adc.py | 7 +++--- artiq/gateware/test/suservo/test_servo.py | 4 ---- 5 files changed, 28 insertions(+), 40 deletions(-) diff --git a/artiq/gateware/suservo/adc_ser.py b/artiq/gateware/suservo/adc_ser.py index 865017e18..7fd33c304 100644 --- a/artiq/gateware/suservo/adc_ser.py +++ b/artiq/gateware/suservo/adc_ser.py @@ -19,9 +19,9 @@ ADCParams = namedtuple("ADCParams", [ "t_cnvh", # CNVH duration (minimum) "t_conv", # CONV duration (minimum) "t_rtt", # upper estimate for clock round trip time from - # sck at the FPGA to clkout at the FPGA. + # sck at the FPGA to clkout at the FPGA (cycles) # this avoids having synchronizers and another counter - # to signal end-of transfer (CLKOUT cycles) + # to signal end-of transfer # and it ensures fixed latency early in the pipeline ]) @@ -51,11 +51,11 @@ class ADC(Module): assert p.lanes == len(sdo) # set up counters for the four states CNVH, CONV, READ, RTT - t_read = p.width*p.channels//p.lanes//2 # DDR - assert 2*p.lanes*t_read == p.width*p.channels + t_read = p.width*p.channels//p.lanes # SDR + assert p.lanes*t_read == p.width*p.channels assert all(_ > 0 for _ in (p.t_cnvh, p.t_conv, p.t_rtt)) assert p.t_conv > 1 - count = Signal(max=max(p.t_cnvh, p.t_conv, t_read, p.t_rtt) - 1, + count = Signal(max=max(p.t_cnvh, p.t_conv - 1, t_read, p.t_rtt + 1) - 1, reset_less=True) count_load = Signal.like(count) count_done = Signal() @@ -92,7 +92,7 @@ class ADC(Module): ) fsm.act("READ", self.reading.eq(1), - count_load.eq(p.t_rtt), # account for sck ODDR delay + count_load.eq(p.t_rtt), # again account for sck ODDR delay pads.sck_en.eq(1), If(count_done, NextState("RTT") @@ -113,21 +113,20 @@ class ADC(Module): self.clock_domains.cd_ret = ClockDomain("ret", reset_less=True) self.comb += [ # falling clkout makes two bits available - self.cd_ret.clk.eq(~pads.clkout) + self.cd_ret.clk.eq(pads.clkout) ] k = p.channels//p.lanes - assert 2*t_read == k*p.width + assert t_read == k*p.width for i, sdo in enumerate(sdo): - sdo_sr0 = Signal(t_read - 1) - sdo_sr1 = Signal(t_read - 1) + sdo_sr = Signal(2*t_read) self.sync.ret += [ If(self.reading & sck_en_ret, - sdo_sr0.eq(Cat(sdo[0], sdo_sr0)), - sdo_sr1.eq(Cat(sdo[1], sdo_sr1)) + sdo_sr[1:].eq(sdo_sr), + sdo_sr[0].eq(sdo), ) ] self.comb += [ - Cat(reversed([self.data[i*k + j] for j in range(k)])).eq( - Cat(sdo, zip(sdo_sr0, sdo_sr1))) + Cat(reversed([self.data[i*k + j] for j in range(k)]) + ).eq(sdo_sr) ] diff --git a/artiq/gateware/suservo/pads.py b/artiq/gateware/suservo/pads.py index 91dfb3783..a57655c2f 100644 --- a/artiq/gateware/suservo/pads.py +++ b/artiq/gateware/suservo/pads.py @@ -22,7 +22,7 @@ class SamplerPads(Module): self.specials += [ DifferentialOutput(self.cnv, cnv.p, cnv.n), DifferentialOutput(1, sdr.p, sdr.n), - DDROutput(0, self.sck_en, sck), + DDROutput(self.sck_en, 0, sck), DifferentialOutput(sck, spip.clk, spin.clk), DifferentialInput(dp.clkout, dn.clkout, clkout_se), Instance( @@ -43,8 +43,7 @@ class SamplerPads(Module): # platform.add_period_constraint(sampler_pads.clkout_p, 8.) for i in "abcd": sdo_se = Signal() - sdo_d = Signal() - sdo = Signal(2) + sdo = Signal() setattr(self, "sdo{}".format(i), sdo) sdop = getattr(dp, "sdo{}".format(i)) sdon = getattr(dn, "sdo{}".format(i)) @@ -53,24 +52,16 @@ class SamplerPads(Module): Instance( "IDELAYE2", p_HIGH_PERFORMANCE_MODE="TRUE", p_IDELAY_TYPE="FIXED", - p_SIGNAL_PATTERN="DATA", p_IDELAY_VALUE=31, + p_SIGNAL_PATTERN="DATA", p_IDELAY_VALUE=15, p_REFCLK_FREQUENCY=200., - i_IDATAIN=sdo_se, o_DATAOUT=sdo_d), - Instance("IDDR", - p_DDR_CLK_EDGE="SAME_EDGE", - i_C=~self.clkout, i_CE=1, i_S=0, i_R=0, - i_D=sdo_d, o_Q1=sdo[0], o_Q2=sdo[1]) # sdo[1] older + i_IDATAIN=sdo_se, o_DATAOUT=sdo), ] - # 4, -0+1.5 hold (t_HSDO_DDR), -0.2+0.2 skew + # 8, -0+1.5 hold (t_HSDO_DDR), -0.5+0.5 skew platform.add_platform_command( "set_input_delay -clock {clk} " - "-max 1.6 [get_ports {port}]\n" + "-max 2 [get_ports {port}] -clock_fall\n" "set_input_delay -clock {clk} " - "-min -0.1 [get_ports {port}]\n" - "set_input_delay -clock {clk} " - "-max 1.6 [get_ports {port}] -clock_fall -add_delay\n" - "set_input_delay -clock {clk} " - "-min -0.1 [get_ports {port}] -clock_fall -add_delay", + "-min -0.5 [get_ports {port}] -clock_fall", clk=dp.clkout, port=sdop) diff --git a/artiq/gateware/suservo/servo.py b/artiq/gateware/suservo/servo.py index 31491429a..c40e7c318 100644 --- a/artiq/gateware/suservo/servo.py +++ b/artiq/gateware/suservo/servo.py @@ -16,14 +16,15 @@ class Servo(Module): self.comb += j.eq(i), l.eq(k) t_adc = (adc_p.t_cnvh + adc_p.t_conv + adc_p.t_rtt + - adc_p.channels*adc_p.width//2//adc_p.lanes) + 1 + adc_p.channels*adc_p.width//adc_p.lanes) + 1 t_iir = ((1 + 4 + 1) << iir_p.channel) + 1 t_dds = (dds_p.width*2 + 1)*dds_p.clk + 1 + t_cycle = max(t_adc, t_iir, t_dds) assert t_iir + (2 << iir_p.channel) < t_cycle, "need shifting time" self.start = Signal() - t_restart = t_cycle - t_iir - t_adc + t_restart = t_cycle - t_adc assert t_restart > 0 cnt = Signal(max=t_restart) cnt_done = Signal() @@ -39,7 +40,7 @@ class Servo(Module): self.done.eq(self.dds.done), ] self.sync += [ - If(iir_done & ~cnt_done & ~token[0], + If(self.adc.done & ~cnt_done, cnt.eq(cnt - 1), ), If(self.adc.start, diff --git a/artiq/gateware/test/suservo/test_adc.py b/artiq/gateware/test/suservo/test_adc.py index 6f74c19ea..c561dbd51 100644 --- a/artiq/gateware/test/suservo/test_adc.py +++ b/artiq/gateware/test/suservo/test_adc.py @@ -31,15 +31,15 @@ class TB(Module): srs = [] for i in range(p.lanes): name = "sdo" + string.ascii_lowercase[i] - sdo = Signal(2, name=name, reset_less=True) + sdo = Signal(name=name, reset_less=True) self.sdo.append(sdo) setattr(self, name, sdo) sr = Signal(p.width*p.channels//p.lanes, reset_less=True) srs.append(sr) self.sync.adc += [ - sdo.eq(Cat(self._dly(sr[-1], 3), self._dly(sr[-2], 3))), + sdo.eq(self._dly(sr[-1], -1)), If(adc_sck_en, - sr[2:].eq(sr) + sr[1:].eq(sr) ) ] cnv_old = Signal(reset_less=True) @@ -54,6 +54,7 @@ class TB(Module): self.comb += [ adc_sck_en.eq(self._dly(self.sck_en, 1)), self.sck_en_ret.eq(self._dly(adc_sck_en)), + adc_clk_rec.eq(self._dly(self.sck, 1)), self.clkout.eq(self._dly(adc_clk_rec)), ] diff --git a/artiq/gateware/test/suservo/test_servo.py b/artiq/gateware/test/suservo/test_servo.py index c8b43349e..8d0443ef8 100644 --- a/artiq/gateware/test/suservo/test_servo.py +++ b/artiq/gateware/test/suservo/test_servo.py @@ -93,10 +93,6 @@ def main(): "adc": (8, 0), "ret": (8, 0), "async": (2, 0), - }, - special_overrides={ - io.DDROutput: test_adc.DDROutput, - io.DDRInput: test_adc.DDRInput }) From c304b6207ab28ab43ddcc032ef279a92b8194fd5 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 25 Apr 2018 14:59:50 +0000 Subject: [PATCH 0642/2457] suservo: drop adc idelays --- artiq/gateware/suservo/pads.py | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/artiq/gateware/suservo/pads.py b/artiq/gateware/suservo/pads.py index a57655c2f..93c54e207 100644 --- a/artiq/gateware/suservo/pads.py +++ b/artiq/gateware/suservo/pads.py @@ -16,7 +16,6 @@ class SamplerPads(Module): dn = platform.request("{}_adc_data_n".format(eem0)) clkout_se = Signal() - clkout_d = Signal() sck = Signal() self.specials += [ @@ -25,13 +24,7 @@ class SamplerPads(Module): DDROutput(self.sck_en, 0, sck), DifferentialOutput(sck, spip.clk, spin.clk), DifferentialInput(dp.clkout, dn.clkout, clkout_se), - Instance( - "IDELAYE2", - p_HIGH_PERFORMANCE_MODE="TRUE", p_IDELAY_TYPE="FIXED", - p_SIGNAL_PATTERN="CLOCK", p_IDELAY_VALUE=0, - p_REFCLK_FREQUENCY=200., - i_IDATAIN=clkout_se, o_DATAOUT=clkout_d), - Instance("BUFR", i_I=clkout_d, o_O=self.clkout) + Instance("BUFR", i_I=clkout_se, o_O=self.clkout) ] # here to be early before the input delays below to have the clock @@ -42,19 +35,12 @@ class SamplerPads(Module): clk=dp.clkout) # platform.add_period_constraint(sampler_pads.clkout_p, 8.) for i in "abcd": - sdo_se = Signal() sdo = Signal() setattr(self, "sdo{}".format(i), sdo) sdop = getattr(dp, "sdo{}".format(i)) sdon = getattr(dn, "sdo{}".format(i)) self.specials += [ - DifferentialInput(sdop, sdon, sdo_se), - Instance( - "IDELAYE2", - p_HIGH_PERFORMANCE_MODE="TRUE", p_IDELAY_TYPE="FIXED", - p_SIGNAL_PATTERN="DATA", p_IDELAY_VALUE=15, - p_REFCLK_FREQUENCY=200., - i_IDATAIN=sdo_se, o_DATAOUT=sdo), + DifferentialInput(sdop, sdon, sdo), ] # 8, -0+1.5 hold (t_HSDO_DDR), -0.5+0.5 skew platform.add_platform_command( From 105068ad90df0a0e09a8cea47257b6190a257d4d Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 25 Apr 2018 15:19:49 +0000 Subject: [PATCH 0643/2457] suservo: fix restart timing --- artiq/gateware/suservo/servo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/suservo/servo.py b/artiq/gateware/suservo/servo.py index c40e7c318..10599b5a6 100644 --- a/artiq/gateware/suservo/servo.py +++ b/artiq/gateware/suservo/servo.py @@ -26,7 +26,7 @@ class Servo(Module): self.start = Signal() t_restart = t_cycle - t_adc assert t_restart > 0 - cnt = Signal(max=t_restart) + cnt = Signal(max=t_restart + 1) cnt_done = Signal() token = Signal(2) self.done = Signal() @@ -44,7 +44,7 @@ class Servo(Module): cnt.eq(cnt - 1), ), If(self.adc.start, - cnt.eq(t_restart - 1), + cnt.eq(t_restart), ), If(self.adc.done, token[0].eq(0) From c83305065a5b035228ad7c47c2cb0a08c695c4a6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 25 Apr 2018 15:58:46 +0000 Subject: [PATCH 0644/2457] suservo: add servo/config/status register --- artiq/gateware/rtio/phy/servo.py | 38 +++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/rtio/phy/servo.py b/artiq/gateware/rtio/phy/servo.py index 24d1ef5b4..46375cd8d 100644 --- a/artiq/gateware/rtio/phy/servo.py +++ b/artiq/gateware/rtio/phy/servo.py @@ -34,7 +34,9 @@ class RTServoMem(Module): # just expose the w.coeff (18) MSBs of state assert w.state >= w.coeff + # ensure that we can split the coefficient storage correctly assert len(m_coeff.dat_w) == 2*w.coeff + # ensure that the DDS word data fits into the coefficient mem assert w.coeff >= w.word self.rtlink = rtlink.Interface( @@ -50,8 +52,27 @@ class RTServoMem(Module): # # # + config = Signal(1, reset=0) + status = Signal(2) + self.comb += [ + Cat(servo.start).eq(config), + status.eq(Cat(servo.start, servo.done)) + ] + + assert len(self.rtlink.o.address) == ( + 1 + # we + 1 + # state_sel + 1 + # high_coeff + len(m_coeff.adr)) + # ensure that we can fit config/status into the state address space + assert len(self.rtlink.o.address) >= ( + 1 + # we + 1 + # state_sel + 1 + # config_sel + len(m_state.adr)) we = self.rtlink.o.address[-1] state_sel = self.rtlink.o.address[-2] + config_sel = self.rtlink.o.address[-3] high_coeff = self.rtlink.o.address[0] self.comb += [ self.rtlink.o.busy.eq(0), @@ -63,7 +84,7 @@ class RTServoMem(Module): we & ~state_sel), m_state.adr.eq(self.rtlink.o.address), m_state.dat_w[w.state - w.coeff:].eq(self.rtlink.o.data), - m_state.we.eq(self.rtlink.o.stb & we & state_sel), + m_state.we.eq(self.rtlink.o.stb & we & state_sel & ~config_sel), ] read = Signal() read_sel = Signal() @@ -78,14 +99,19 @@ class RTServoMem(Module): read_high.eq(high_coeff), ) ] + self.sync.rio_phy += [ + If(self.rtlink.o.stb & we & state_sel & config_sel, + config.eq(self.rtlink.o.data) + ) + ] self.comb += [ self.rtlink.i.stb.eq(read), self.rtlink.i.data.eq( - Mux( - state_sel, - m_state.dat_r[w.state - w.coeff:], - Mux( - read_high, + Mux(state_sel, + Mux(config_sel, + status, + m_state.dat_r[w.state - w.coeff:]), + Mux(read_high, m_coeff.dat_r[w.coeff:], m_coeff.dat_r[:w.coeff]))) ] From f9b2c3273993bfb677cc30284046fa008e42c77d Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 25 Apr 2018 16:23:30 +0000 Subject: [PATCH 0645/2457] suservo: add pgia spi channel --- artiq/gateware/targets/kasli.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 6bd39081f..c27035746 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -547,6 +547,12 @@ class SUServo(_StandaloneBase): self.submodules += mem rtio_channels.append(rtio.Channel.from_phy(mem, ififo_depth=4)) + # EEM3: Sampler + phy = spi2.SPIMaster(self.platform.request("eem3_pgia_spi_p"), + self.platform.request("eem3_pgia_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + # EEM5 + EEM4: Urukul phy = spi2.SPIMaster(self.platform.request("eem5_spi_p"), self.platform.request("eem5_spi_n")) From 8a1151b54f4b6bf8dc823c3edc2b1bc9a5fd1483 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 25 Apr 2018 16:23:47 +0000 Subject: [PATCH 0646/2457] suservo: example device db --- artiq/examples/kasli_suservo/device_db.py | 261 +++++++++++++++------- 1 file changed, 179 insertions(+), 82 deletions(-) diff --git a/artiq/examples/kasli_suservo/device_db.py b/artiq/examples/kasli_suservo/device_db.py index b34536fa6..a869bffa4 100644 --- a/artiq/examples/kasli_suservo/device_db.py +++ b/artiq/examples/kasli_suservo/device_db.py @@ -36,120 +36,217 @@ device_db = { "class": "PCA9548", "arguments": {"address": 0xe2} }, -} -for i in range(16): - device_db["ttl" + str(i)] = { + "ttl0": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLInOut", - "arguments": {"channel": i}, - } - - -device_db.update( - spi_sampler0_adc={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 16} + "arguments": {"channel": 0}, }, - spi_sampler0_pgia={ + "ttl1": { "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 17} + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 1}, }, - ttl_sampler0_cnv={ + "ttl2": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 2}, + }, + "ttl3": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 3}, + }, + + "ttl4": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 18} + "arguments": {"channel": 4}, }, - sampler0={ + "ttl5": { "type": "local", - "module": "artiq.coredevice.sampler", - "class": "Sampler", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 5}, + }, + "ttl6": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 6}, + }, + "ttl7": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 7}, + }, + "ttl8": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 8}, + }, + "ttl9": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 9}, + }, + "ttl10": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 10}, + }, + "ttl11": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 11}, + }, + "ttl12": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 12}, + }, + "ttl13": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 13}, + }, + "ttl14": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 14}, + }, + "ttl15": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 15}, + }, + + "suservo0": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "SUServo", "arguments": { - "spi_adc_device": "spi_sampler0_adc", - "spi_pgia_device": "spi_sampler0_pgia", - "cnv_device": "ttl_sampler0_cnv", + "channel": 24, + "sampler_pgia_device": "spi_sampler0_pgia", + "urukul0_device": "urukul0_cpld", + "urukul1_device": "urukul1_cpld" } }, - spi_urukul0={ + "suservo0_ch0": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", + "arguments": {"channel": 16, "servo_device": "suservo0"} + }, + "suservo0_ch1": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", + "arguments": {"channel": 17, "servo_device": "suservo0"} + }, + "suservo0_ch2": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", + "arguments": {"channel": 18, "servo_device": "suservo0"} + }, + "suservo0_ch3": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", + "arguments": {"channel": 19, "servo_device": "suservo0"} + }, + "suservo0_ch4": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", + "arguments": {"channel": 20, "servo_device": "suservo0"} + }, + "suservo0_ch5": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", + "arguments": {"channel": 21, "servo_device": "suservo0"} + }, + "suservo0_ch6": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", + "arguments": {"channel": 22, "servo_device": "suservo0"} + }, + "suservo0_ch7": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "Channel", + "arguments": {"channel": 23, "servo_device": "suservo0"} + }, + + "spi_sampler0_pgia": { "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 19} + "arguments": {"channel": 25} }, - ttl_urukul0_io_update={ + + "spi_urukul0": { "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 20} + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 26} }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 21} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 22} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 23} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 24} - }, - urukul0_cpld={ + "urukul0_cpld": { "type": "local", "module": "artiq.coredevice.urukul", "class": "CPLD", "arguments": { "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", "refclk": 125e6, "clk_sel": 0 } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - -device_db.update( - led0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 31} }, - led1={ + + "spi_urukul1": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 27} + }, + "urukul1_cpld": { + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul1", + "refclk": 125e6, + "clk_sel": 0 + } + }, + + "led0": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 32} + "arguments": {"channel": 28} + }, + "led1": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 29} } -) +} From edbc7763e075badb235003d6143bc6f32f96fc27 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 25 Apr 2018 17:32:36 +0000 Subject: [PATCH 0647/2457] urukul: allow no io_update_device --- artiq/coredevice/urukul.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index d2739a6d3..76782f706 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -111,7 +111,7 @@ class CPLD: """ kernel_invariants = {"refclk", "bus", "core", "io_update"} - def __init__(self, dmgr, spi_device, io_update_device, + def __init__(self, dmgr, spi_device, io_update_device=None, dds_reset_device=None, sync_sel=0, clk_sel=0, refclk=125e6, core_device="core"): @@ -120,7 +120,8 @@ class CPLD: self.refclk = refclk self.bus = dmgr.get(spi_device) - self.io_update = dmgr.get(io_update_device) + if io_update_device is not None: + self.io_update = dmgr.get(io_update_device) if dds_reset_device is not None: self.dds_reset = dmgr.get(dds_reset_device) From 28ccca412abac7489cfbacdd9eb74f7f529a5f73 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 26 Apr 2018 10:49:41 +0800 Subject: [PATCH 0648/2457] doc: automatic artiq_flash proxy --- RELEASE_NOTES.rst | 2 ++ doc/manual/installing.rst | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 536840335..0008a825a 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -22,6 +22,8 @@ ARTIQ-4 * The master now has a ``--name`` argument. If given, the dashboard is labelled with this name rather than the server address. * ``artiq_flash -m/--adapter`` has been changed to ``artiq_flash -V/--variant``. +* The ``proxy`` action of ``artiq_flash`` is determined automatically and should + not be specified manually anymore. * ``kc705_dds`` has been renamed ``kc705``. * the ``-H/--hw-adapter`` option of ``kc705`` has ben renamed ``-V/--variant``. * SPI masters have been switched from misoc-spi to misoc-spi2. This affects diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 5cd152771..da9affe38 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -161,7 +161,7 @@ This should be done after either installation method (conda or source). * Set the MAC and IP address in the :ref:`core device configuration flash storage ` (see above for the ``-t`` and ``-m`` options to ``artiq_flash`` that may be required): :: $ artiq_mkfs flash_storage.img -s mac xx:xx:xx:xx:xx:xx -s ip xx.xx.xx.xx - $ artiq_flash -t [board] -m [adapter] -f flash_storage.img proxy storage start + $ artiq_flash -t [board] -m [adapter] -f flash_storage.img storage start * (optional) Flash the idle kernel From 8212e46f5ed97154b2f03010c17ac7a7fa98c4a2 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 27 Apr 2018 13:04:37 +0200 Subject: [PATCH 0649/2457] sayma_amc: filter jesd refclk/sysref with jreset (hmc7043 can generate noise when unconfigured see sinara issue #541) --- artiq/gateware/targets/sayma_amc.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index db2387f73..6e2415d57 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -59,7 +59,7 @@ class AD9154CRG(Module, AutoCSR): platform.add_period_constraint(refclk_pads.p, 1e9/self.refclk_freq) self.specials += [ - Instance("IBUFDS_GTE3", i_CEB=0, p_REFCLK_HROW_CK_SEL=0b00, + Instance("IBUFDS_GTE3", i_CEB=self.jreset.storage, p_REFCLK_HROW_CK_SEL=0b00, i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=self.refclk, o_ODIV2=refclk2), Instance("BUFG_GT", i_I=refclk2, o_O=self.cd_jesd.clk), @@ -67,7 +67,11 @@ class AD9154CRG(Module, AutoCSR): ] jref = platform.request("dac_sysref") - self.specials += DifferentialInput(jref.p, jref.n, self.jref) + self.specials += Instance("IBUFDS_IBUFDISABLE", + p_USE_IBUFDISABLE="TRUE", p_SIM_DEVICE="ULTRASCALE", + i_IBUFDISABLE=self.jreset.storage, + i_I=jref.p, i_IB=jref.n, + o_O=self.jref) class AD9154JESD(Module, AutoCSR): From 3802c7badb08417843e4a9786a665f6d9720e12f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 27 Apr 2018 13:20:20 +0200 Subject: [PATCH 0650/2457] firmware/ad9154: add sysref scan/conf for jesd sc1 --- artiq/firmware/libboard_artiq/ad9154.rs | 40 ++++++++++++++++++++ artiq/firmware/libboard_artiq/hmc830_7043.rs | 16 +++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 9cd40b169..2f9bbd86c 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -1,5 +1,6 @@ use board::{csr, clock}; use ad9154_reg; +use hmc830_7043::{hmc7043}; fn spi_setup(dacno: u8) { unsafe { @@ -607,6 +608,44 @@ fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { dac_cfg(dacno) } +fn dac_sysref_cfg(dacno: u8) { + let mut sync_error: u16 = 0; + let mut sync_error_last: u16 = 0; + let mut cphase_min_found: bool = false; + let mut cphase_min: u8 = 0; + let mut cphase_max_found: bool = false; + let mut cphase_max: u8 = 0; + let mut cphase_opt: u8 = 0; + + info!("AD9154-{} SYSREF scan/conf...", dacno); + for cphase in 0..32 { + hmc7043::cfg_dac_sysref(dacno, 0, cphase); + clock::spin_us(10000); + spi_setup(dacno); + sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) | + ((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8)) + & 0x1ff; + info!(" cphase: {}, sync error: {}", cphase, sync_error); + if sync_error != 0 { + if cphase_min_found { + if sync_error != sync_error_last { + cphase_max_found = true; + cphase_max = cphase - 1; + break; + } + } else { + cphase_min_found = true; + cphase_min = cphase; + } + } + sync_error_last = sync_error; + } + + cphase_opt = cphase_min + (cphase_max-cphase_min)/2; + info!(" cphase min: {}, cphase max: {}, cphase opt: {}", cphase_min, cphase_max, cphase_opt); + hmc7043::cfg_dac_sysref(dacno, 0, cphase_opt); +} + pub fn init() -> Result<(), &'static str> { // Release the JESD clock domain reset late, as we need to // set up clock chips before. @@ -617,6 +656,7 @@ pub fn init() -> Result<(), &'static str> { debug!("setting up AD9154-{} DAC...", dacno); dac_cfg_retry(dacno)?; dac_prbs(dacno)?; + dac_sysref_cfg(dacno); dac_cfg_retry(dacno)?; } diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 44bf0f967..b1e5d9201 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -124,7 +124,7 @@ mod hmc830 { } } -mod hmc7043 { +pub mod hmc7043 { use board::csr; // To do: check which output channels we actually need @@ -249,6 +249,20 @@ mod hmc7043 { Ok(()) } + + pub fn cfg_dac_sysref(dacno: u8, aphase: u8, cphase: u8) { + spi_setup(); + if dacno == 0 { + write(0x00D5, aphase); + write(0x00D6, cphase); + } else if dacno == 1 { + write(0x00E9, aphase); + write(0x00EA, cphase); + } else { + unimplemented!(); + } + } + } pub fn init() -> Result<(), &'static str> { From 01f762a8f50dc7ec416117c6b1562413fa44b823 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 26 Apr 2018 07:59:08 +0000 Subject: [PATCH 0651/2457] urukul/ad9910: support blind init urukul: always set io_update attribute to silence compiler warning w.r.t. kernel_invariants --- artiq/coredevice/ad9910.py | 21 ++++++++++++++------- artiq/coredevice/urukul.py | 27 ++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 4be5d8ff7..6ef26a405 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -57,7 +57,7 @@ class AD9910: self.cpld = dmgr.get(cpld_device) self.core = self.cpld.core self.bus = self.cpld.bus - assert 4 <= chip_select <= 7 + assert 3 <= chip_select <= 7 self.chip_select = chip_select if sw_device: self.sw = dmgr.get(sw_device) @@ -124,21 +124,25 @@ class AD9910: self.bus.write(data_low) @kernel - def init(self): + def init(self, blind=False): """Initialize and configure the DDS. Sets up SPI mode, confirms chip presence, powers down unused blocks, configures the PLL, waits for PLL lock. Uses the IO_UPDATE signal multiple times. + + :param blind: Do not read back DDS identity and do not wait for lock. """ # Set SPI mode self.write32(_AD9910_REG_CFR1, 0x00000002) self.cpld.io_update.pulse(2*us) - # Use the AUX DAC setting to identify and confirm presence - aux_dac = self.read32(_AD9910_REG_AUX_DAC) - if aux_dac & 0xff != 0x7f: - raise ValueError("Urukul AD9910 AUX_DAC mismatch") - delay(50*us) # slack + delay(1*ms) + if not blind: + # Use the AUX DAC setting to identify and confirm presence + aux_dac = self.read32(_AD9910_REG_AUX_DAC) + if aux_dac & 0xff != 0x7f: + raise ValueError("Urukul AD9910 AUX_DAC mismatch") + delay(50*us) # slack # Configure PLL settings and bring up PLL self.write32(_AD9910_REG_CFR2, 0x01400020) self.cpld.io_update.pulse(2*us) @@ -148,6 +152,9 @@ class AD9910: self.cpld.io_update.pulse(100*us) self.write32(_AD9910_REG_CFR3, cfr3) self.cpld.io_update.pulse(100*us) + if blind: + delay(100*ms) + return # Wait for PLL lock, up to 100 ms for i in range(100): sta = self.cpld.sta_read() diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 76782f706..a2ce2365f 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -95,6 +95,18 @@ def urukul_sta_proto_rev(sta): return (sta >> STA_PROTO_REV) & 0x7f +class _RegIOUpdate: + def __init__(self, cpld): + self.cpld = cpld + + @portable + def pulse(self, t): + cfg = self.cpld.cfg_reg + self.cpld.cfg_write(cfg | (1 << CFG_IO_UPDATE)) + delay(t) + self.cpld.cfg_write(cfg) + + class CPLD: """Urukul CPLD SPI router and configuration interface. @@ -122,6 +134,8 @@ class CPLD: self.bus = dmgr.get(spi_device) if io_update_device is not None: self.io_update = dmgr.get(io_update_device) + else: + self.io_update = _RegIOUpdate(self) if dds_reset_device is not None: self.dds_reset = dmgr.get(dds_reset_device) @@ -164,20 +178,23 @@ class CPLD: return self.bus.read() @kernel - def init(self): + def init(self, blind=False): """Initialize and detect Urukul. Resets the DDS I/O interface and verifies correct CPLD gateware version. Does not pulse the DDS MASTER_RESET as that confuses the AD9910. + + :param blind: Do not attempt to verify presence and compatibility. """ cfg = self.cfg_reg # Don't pulse MASTER_RESET (m-labs/artiq#940) self.cfg_reg = cfg | (0 << CFG_RST) | (1 << CFG_IO_RST) - proto_rev = urukul_sta_proto_rev(self.sta_read()) - if proto_rev != STA_PROTO_REV_MATCH: - raise ValueError("Urukul proto_rev mismatch") - delay(20*us) # slack, reset + if not blind: + proto_rev = urukul_sta_proto_rev(self.sta_read()) + if proto_rev != STA_PROTO_REV_MATCH: + raise ValueError("Urukul proto_rev mismatch") + delay(100*us) # reset, slack self.cfg_write(cfg) delay(1*ms) # DDS wake up From 307cd07b9d6caf09b3f37477aa2287c4a14a9a92 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 25 Apr 2018 21:26:07 +0000 Subject: [PATCH 0652/2457] suservo: lots of gateware/ runtime changes tested/validated: * servo enable/disable * dds interface, timing, io_update, mask_nu * channel control (en_out, en_iir, profile) * profile configuration (coefficients, delays, offsets, channel) * adc timings and waveforms measured * asf state readback * adc readback individual changes below: suservo: correct rtio readback suservo: example, device_db [wip] suservo: change rtio channel layout suservo: mem ports in rio domain suservo: sck clocked from rio_phy suservo: cleanup, straighten out timing suservo: dds cs polarity suservo: simplify pipeline suservo: drop unused eem names suservo: decouple adc SR from IIR suservo: expand coredevice layer suservo: start the correct stage suservo: actually load ctrl suservo: refactor/tweak adc timing suservo: implement cpld and dds init --- artiq/coredevice/suservo.py | 132 ++++++++++++++++++ artiq/examples/kasli_suservo/device_db.py | 34 ++++- .../kasli_suservo/repository/sampler.py | 35 ----- .../kasli_suservo/repository/suservo.py | 33 +++++ artiq/gateware/rtio/phy/servo.py | 38 ++--- artiq/gateware/suservo/adc_ser.py | 26 ++-- artiq/gateware/suservo/dds_ser.py | 11 +- artiq/gateware/suservo/pads.py | 24 ++-- artiq/gateware/suservo/servo.py | 49 ++++--- artiq/gateware/suservo/spi.py | 14 +- artiq/gateware/targets/kasli.py | 24 ++-- artiq/gateware/test/suservo/test_adc.py | 6 +- artiq/gateware/test/suservo/test_servo.py | 7 +- 13 files changed, 288 insertions(+), 145 deletions(-) create mode 100644 artiq/coredevice/suservo.py delete mode 100644 artiq/examples/kasli_suservo/repository/sampler.py create mode 100644 artiq/examples/kasli_suservo/repository/suservo.py diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py new file mode 100644 index 000000000..653f0b683 --- /dev/null +++ b/artiq/coredevice/suservo.py @@ -0,0 +1,132 @@ +from artiq.language.core import kernel, delay, portable, now_mu +from artiq.language.units import us, ms +from artiq.coredevice.rtio import rtio_output, rtio_input_data + +from numpy import int32, int64 + +from artiq.coredevice import spi2 as spi +from artiq.coredevice import urukul, sampler + + +COEFF_WIDTH = 18 +COEFF_DEPTH = 10 + 1 +WE = 1 << COEFF_DEPTH + 1 +STATE_SEL = 1 << COEFF_DEPTH +CONFIG_SEL = 1 << COEFF_DEPTH - 1 +CONFIG_ADDR = CONFIG_SEL | STATE_SEL + + +class SUServo: + kernel_invariants = {"channel", "core", "pgia", "cpld0", "cpld1", + "dds0", "dds1", "ref_period_mu"} + + def __init__(self, dmgr, channel, pgia_device, + cpld0_device, cpld1_device, + dds0_device, dds1_device, + core_device="core"): + + self.core = dmgr.get(core_device) + self.pgia = dmgr.get(pgia_device) + self.dds0 = dmgr.get(dds0_device) + self.dds1 = dmgr.get(dds1_device) + self.cpld0 = dmgr.get(cpld0_device) + self.cpld1 = dmgr.get(cpld1_device) + self.channel = channel + self.gains = 0x0000 + self.ref_period_mu = self.core.seconds_to_mu( + self.core.coarse_ref_period) + assert self.ref_period_mu == self.core.ref_multiplier + + @kernel + def init(self): + self.set_config(0) + delay(2*us) # pipeline flush + + self.pgia.set_config_mu( + sampler.SPI_CONFIG | spi.SPI_END, + 16, 4, sampler.SPI_CS_PGIA) + + self.cpld0.init(blind=True) + cfg0 = self.cpld0.cfg_reg + self.cpld0.cfg_write(cfg0 | (0xf << urukul.CFG_MASK_NU)) + self.dds0.init(blind=True) + self.cpld0.cfg_write(cfg0) + + self.cpld1.init(blind=True) + cfg1 = self.cpld1.cfg_reg + self.cpld1.cfg_write(cfg1 | (0xf << urukul.CFG_MASK_NU)) + self.dds1.init(blind=True) + self.cpld1.cfg_write(cfg1) + + @kernel + def write(self, addr, value): + rtio_output(now_mu(), self.channel, addr | WE, value) + delay_mu(self.ref_period_mu) + + @kernel + def read(self, addr): + rtio_output(now_mu(), self.channel, addr, 0) + return rtio_input_data(self.channel) + + @kernel + def set_config(self, start): + self.write(CONFIG_ADDR, start) + + @kernel + def get_status(self): + return self.read(CONFIG_ADDR) + + @kernel + def get_adc_mu(self, adc): + return self.read(STATE_SEL | (adc << 1) | (1 << 8)) + + @kernel + def set_gain_mu(self, channel, gain): + """Set instrumentation amplifier gain of a channel. + + The four gain settings (0, 1, 2, 3) corresponds to gains of + (1, 10, 100, 1000) respectively. + + :param channel: Channel index + :param gain: Gain setting + """ + gains = self.gains + gains &= ~(0b11 << (channel*2)) + gains |= gain << (channel*2) + self.pgia.write(gains << 16) + self.gains = gains + + +class Channel: + kernel_invariants = {"channel", "core", "servo", "servo_channel"} + + def __init__(self, dmgr, channel, servo_device, + core_device="core"): + self.core = dmgr.get(core_device) + self.servo = dmgr.get(servo_device) + self.channel = channel + self.servo_channel = self.channel + 8 - self.servo.channel # FIXME + + @kernel + def set(self, en_out, en_iir=0, profile=0): + rtio_output(now_mu(), self.channel, 0, + en_out | (en_iir << 1) | (profile << 2)) + + @kernel + def set_profile_mu(self, profile, ftw, adc, offset, + a1, b0, b1, delay, pow=0): + base = (self.servo_channel << 8) | (profile << 3) + data = [ftw >> 16, b1, pow, adc | (delay << 8), offset, a1, ftw, b0] + for i in range(8): + self.servo.write(base + i, data[i]) + + @kernel + def get_profile_mu(self, profile, data): + base = (self.servo_channel << 8) | (profile << 3) + for i in range(8): + data[i] = self.servo.read(base + i) + delay(2*us) + + @kernel + def get_asf_mu(self, profile): + return self.servo.read(STATE_SEL | (self.servo_channel << 5) | profile) diff --git a/artiq/examples/kasli_suservo/device_db.py b/artiq/examples/kasli_suservo/device_db.py index a869bffa4..2da2df0cf 100644 --- a/artiq/examples/kasli_suservo/device_db.py +++ b/artiq/examples/kasli_suservo/device_db.py @@ -1,4 +1,4 @@ -core_addr = "lauda.ber.quartiq.de" +core_addr = "10.0.16.119" device_db = { "core": { @@ -141,9 +141,11 @@ device_db = { "class": "SUServo", "arguments": { "channel": 24, - "sampler_pgia_device": "spi_sampler0_pgia", - "urukul0_device": "urukul0_cpld", - "urukul1_device": "urukul1_cpld" + "pgia_device": "spi_sampler0_pgia", + "cpld0_device": "urukul0_cpld", + "cpld1_device": "urukul1_cpld", + "dds0_device": "urukul0_dds", + "dds1_device": "urukul1_dds" } }, @@ -215,10 +217,20 @@ device_db = { "class": "CPLD", "arguments": { "spi_device": "spi_urukul0", - "refclk": 125e6, + "refclk": 100e6, "clk_sel": 0 } }, + "urukul0_dds": { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 3, + "cpld_device": "urukul0_cpld", + } + }, "spi_urukul1": { "type": "local", @@ -232,10 +244,20 @@ device_db = { "class": "CPLD", "arguments": { "spi_device": "spi_urukul1", - "refclk": 125e6, + "refclk": 100e6, "clk_sel": 0 } }, + "urukul1_dds": { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 3, + "cpld_device": "urukul1_cpld", + } + }, "led0": { "type": "local", diff --git a/artiq/examples/kasli_suservo/repository/sampler.py b/artiq/examples/kasli_suservo/repository/sampler.py deleted file mode 100644 index fc4e425ee..000000000 --- a/artiq/examples/kasli_suservo/repository/sampler.py +++ /dev/null @@ -1,35 +0,0 @@ -from artiq.experiment import * - - -class Sampler(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("sampler0") - - def run(self): - self.data = [] - self.sample() - for d in self.data: - print(d) - - @kernel - def sample(self): - self.core.break_realtime() - self.sampler0.init() - for g in range(4): - for ch in range(8): - self.sampler0.set_gain_mu(ch, g) - self.ret([self.sampler0.get_gains_mu()]) - delay(10*ms) - raw = [0] * 8 - self.sampler0.sample_mu(raw) - self.ret(raw) - delay(10*ms) - data = [0.] * 8 - self.sampler0.sample(data) - self.ret(data) - delay(10*ms) - - @rpc(flags={"async"}) - def ret(self, data): - self.data.append(data) diff --git a/artiq/examples/kasli_suservo/repository/suservo.py b/artiq/examples/kasli_suservo/repository/suservo.py new file mode 100644 index 000000000..aa7853c0a --- /dev/null +++ b/artiq/examples/kasli_suservo/repository/suservo.py @@ -0,0 +1,33 @@ +from artiq.experiment import * + + +class SUServo(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("led0") + self.setattr_device("suservo0") + self.setattr_device("suservo0_ch0") + + def run(self): + # self.led() + self.init() + + @kernel + def init(self): + self.core.break_realtime() + self.core.reset() + + self.suservo0.init() + self.suservo0.set_config(1) + print(self.suservo0.get_status()) + delay(3*ms) + self.suservo0.set_config(0) + delay(3*ms) + print(self.suservo0.get_status()) + + @kernel + def led(self): + self.core.break_realtime() + for i in range(10): + self.led0.pulse(.1*s) + delay(.1*s) diff --git a/artiq/gateware/rtio/phy/servo.py b/artiq/gateware/rtio/phy/servo.py index 46375cd8d..34a5e58fe 100644 --- a/artiq/gateware/rtio/phy/servo.py +++ b/artiq/gateware/rtio/phy/servo.py @@ -7,18 +7,19 @@ class RTServoCtrl(Module): """Per channel RTIO control interface""" def __init__(self, ctrl): self.rtlink = rtlink.Interface( - rtlink.OInterface(len(ctrl))) + rtlink.OInterface(len(ctrl.profile) + 2)) # # # - self.sync.rio += [ - If(self.rtlink.o.stb, - Cat(ctrl.profile, ctrl.en_out, ctrl.en_iir).eq( - self.rtlink.o.data), - ) - ] self.comb += [ - ctrl.stb.eq(self.rtlink.o.stb) + ctrl.stb.eq(self.rtlink.o.stb), + self.rtlink.o.busy.eq(0) + ] + self.sync.rio_phy += [ + If(self.rtlink.o.stb, + Cat(ctrl.en_out, ctrl.en_iir, ctrl.profile).eq( + self.rtlink.o.data) + ) ] @@ -26,10 +27,11 @@ class RTServoMem(Module): """All-channel all-profile coefficient and state RTIO control interface.""" def __init__(self, w, servo): - m_coeff = servo.m_coeff.get_port(write_capable=True, - we_granularity=w.coeff) + m_coeff = servo.iir.m_coeff.get_port(write_capable=True, + we_granularity=w.coeff, clock_domain="rio") assert len(m_coeff.we) == 2 - m_state = servo.m_state.get_port(write_capable=True) + m_state = servo.iir.m_state.get_port(write_capable=True, + clock_domain="rio") self.specials += m_state, m_coeff # just expose the w.coeff (18) MSBs of state @@ -52,8 +54,8 @@ class RTServoMem(Module): # # # - config = Signal(1, reset=0) - status = Signal(2) + config = Signal(w.coeff, reset=0) + status = Signal(w.coeff) self.comb += [ Cat(servo.start).eq(config), status.eq(Cat(servo.start, servo.done)) @@ -87,16 +89,18 @@ class RTServoMem(Module): m_state.we.eq(self.rtlink.o.stb & we & state_sel & ~config_sel), ] read = Signal() - read_sel = Signal() + read_state = Signal() read_high = Signal() + read_config = Signal() self.sync.rio += [ If(read, read.eq(0) ), If(self.rtlink.o.stb, read.eq(~we), - read_sel.eq(state_sel), + read_state.eq(state_sel), read_high.eq(high_coeff), + read_config.eq(config_sel), ) ] self.sync.rio_phy += [ @@ -107,8 +111,8 @@ class RTServoMem(Module): self.comb += [ self.rtlink.i.stb.eq(read), self.rtlink.i.data.eq( - Mux(state_sel, - Mux(config_sel, + Mux(read_state, + Mux(read_config, status, m_state.dat_r[w.state - w.coeff:]), Mux(read_high, diff --git a/artiq/gateware/suservo/adc_ser.py b/artiq/gateware/suservo/adc_ser.py index 7fd33c304..93d471fcb 100644 --- a/artiq/gateware/suservo/adc_ser.py +++ b/artiq/gateware/suservo/adc_ser.py @@ -55,13 +55,13 @@ class ADC(Module): assert p.lanes*t_read == p.width*p.channels assert all(_ > 0 for _ in (p.t_cnvh, p.t_conv, p.t_rtt)) assert p.t_conv > 1 - count = Signal(max=max(p.t_cnvh, p.t_conv - 1, t_read, p.t_rtt + 1) - 1, + count = Signal(max=max(p.t_cnvh, p.t_conv, t_read, p.t_rtt), reset_less=True) count_load = Signal.like(count) count_done = Signal() - self.comb += [ - count_done.eq(count == 0), - ] + update = Signal() + + self.comb += count_done.eq(count == 0) self.sync += [ count.eq(count - 1), If(count_done, @@ -78,7 +78,7 @@ class ADC(Module): ) ) fsm.act("CNVH", - count_load.eq(p.t_conv - 2), # account for sck ODDR delay + count_load.eq(p.t_conv - 1), pads.cnv.eq(1), If(count_done, NextState("CONV") @@ -92,7 +92,7 @@ class ADC(Module): ) fsm.act("READ", self.reading.eq(1), - count_load.eq(p.t_rtt), # again account for sck ODDR delay + count_load.eq(p.t_rtt - 1), pads.sck_en.eq(1), If(count_done, NextState("RTT") @@ -101,6 +101,7 @@ class ADC(Module): fsm.act("RTT", # account for sck->clkout round trip time self.reading.eq(1), If(count_done, + update.eq(1), NextState("IDLE") ) ) @@ -111,10 +112,7 @@ class ADC(Module): sck_en_ret = 1 self.clock_domains.cd_ret = ClockDomain("ret", reset_less=True) - self.comb += [ - # falling clkout makes two bits available - self.cd_ret.clk.eq(pads.clkout) - ] + self.comb += self.cd_ret.clk.eq(pads.clkout) k = p.channels//p.lanes assert t_read == k*p.width @@ -126,7 +124,9 @@ class ADC(Module): sdo_sr[0].eq(sdo), ) ] - self.comb += [ - Cat(reversed([self.data[i*k + j] for j in range(k)]) - ).eq(sdo_sr) + self.sync += [ + If(update, + Cat(reversed([self.data[i*k + j] for j in range(k)]) + ).eq(sdo_sr) + ) ] diff --git a/artiq/gateware/suservo/dds_ser.py b/artiq/gateware/suservo/dds_ser.py index 7ce0021fb..8df30e9fe 100644 --- a/artiq/gateware/suservo/dds_ser.py +++ b/artiq/gateware/suservo/dds_ser.py @@ -36,13 +36,8 @@ class DDS(spi.SPISimple): ) ] - io_update = pads.io_update # this assumes that the cycle time (1/125 MHz = 8 ns) is >1 SYNC_CLK # cycle (1/250 MHz = 4ns) - done = Signal() - self.sync += [ - done.eq(self.done) - ] - self.comb += [ - io_update.eq(self.done & ~done) - ] + done_old = Signal() + self.sync += done_old.eq(self.done) + self.comb += pads.io_update.eq(self.done & ~done_old) diff --git a/artiq/gateware/suservo/pads.py b/artiq/gateware/suservo/pads.py index 93c54e207..a26d02901 100644 --- a/artiq/gateware/suservo/pads.py +++ b/artiq/gateware/suservo/pads.py @@ -3,17 +3,17 @@ from migen.genlib.io import DifferentialOutput, DifferentialInput, DDROutput class SamplerPads(Module): - def __init__(self, platform, eem0, eem1): + def __init__(self, platform, eem): self.sck_en = Signal() self.cnv = Signal() self.clkout = Signal() - spip = platform.request("{}_adc_spi_p".format(eem0)) - spin = platform.request("{}_adc_spi_n".format(eem0)) - cnv = platform.request("{}_cnv".format(eem0)) - sdr = platform.request("{}_sdr".format(eem0)) - dp = platform.request("{}_adc_data_p".format(eem0)) - dn = platform.request("{}_adc_data_n".format(eem0)) + spip = platform.request("{}_adc_spi_p".format(eem)) + spin = platform.request("{}_adc_spi_n".format(eem)) + cnv = platform.request("{}_cnv".format(eem)) + sdr = platform.request("{}_sdr".format(eem)) + dp = platform.request("{}_adc_data_p".format(eem)) + dn = platform.request("{}_adc_data_n".format(eem)) clkout_se = Signal() sck = Signal() @@ -21,7 +21,7 @@ class SamplerPads(Module): self.specials += [ DifferentialOutput(self.cnv, cnv.p, cnv.n), DifferentialOutput(1, sdr.p, sdr.n), - DDROutput(self.sck_en, 0, sck), + DDROutput(0, self.sck_en, sck, ClockSignal("rio_phy")), DifferentialOutput(sck, spip.clk, spin.clk), DifferentialInput(dp.clkout, dn.clkout, clkout_se), Instance("BUFR", i_I=clkout_se, o_O=self.clkout) @@ -52,17 +52,17 @@ class SamplerPads(Module): class UrukulPads(Module): - def __init__(self, platform, eem00, eem01, eem10, eem11): + def __init__(self, platform, eem0, eem1): spip, spin = [[ platform.request("{}_qspi_{}".format(eem, pol), 0) - for eem in (eem00, eem10)] for pol in "pn"] + for eem in (eem0, eem1)] for pol in "pn"] ioup = [platform.request("{}_io_update".format(eem), 0) - for eem in (eem00, eem10)] + for eem in (eem0, eem1)] self.cs_n = Signal() self.clk = Signal() self.io_update = Signal() self.specials += [( - DifferentialOutput(self.cs_n, spip[i].cs_n, spin[i].cs_n), + DifferentialOutput(~self.cs_n, spip[i].cs, spin[i].cs), DifferentialOutput(self.clk, spip[i].clk, spin[i].clk), DifferentialOutput(self.io_update, ioup[i].p, ioup[i].n)) for i in range(2)] diff --git a/artiq/gateware/suservo/servo.py b/artiq/gateware/suservo/servo.py index 10599b5a6..b2df44bc4 100644 --- a/artiq/gateware/suservo/servo.py +++ b/artiq/gateware/suservo/servo.py @@ -24,38 +24,37 @@ class Servo(Module): assert t_iir + (2 << iir_p.channel) < t_cycle, "need shifting time" self.start = Signal() - t_restart = t_cycle - t_adc + t_restart = t_cycle - t_adc + 1 assert t_restart > 0 - cnt = Signal(max=t_restart + 1) + cnt = Signal(max=t_restart) cnt_done = Signal() - token = Signal(2) + active = Signal(3) self.done = Signal() - iir_done = Signal() - self.comb += [ - cnt_done.eq(cnt == 0), - iir_done.eq(self.iir.shifting | self.iir.done), - self.adc.start.eq(self.start & cnt_done), - self.iir.start.eq(token[0] & self.adc.done), - self.dds.start.eq(token[1] & iir_done), - self.done.eq(self.dds.done), - ] self.sync += [ - If(self.adc.done & ~cnt_done, - cnt.eq(cnt - 1), + If(self.dds.done, + active[2].eq(0) ), - If(self.adc.start, - cnt.eq(t_restart), + If(self.dds.start & self.dds.done, + active[2].eq(1), + active[1].eq(0) ), - If(self.adc.done, - token[0].eq(0) + If(self.iir.start & self.iir.done, + active[1].eq(1), + active[0].eq(0) ), - If(self.adc.start, - token[0].eq(1) + If(~cnt_done & self.adc.done, + cnt.eq(cnt - 1) ), - If(iir_done, - token[1].eq(0) - ), - If(self.iir.start, - token[1].eq(1) + If(self.adc.start & self.adc.done, + active[0].eq(1), + cnt.eq(t_restart - 1) ) ] + self.comb += [ + cnt_done.eq(cnt == 0), + self.adc.start.eq(self.start & cnt_done), + self.iir.start.eq(active[0] & self.adc.done), + self.dds.start.eq(active[1] & + (self.iir.shifting | self.iir.done)), + self.done.eq(self.dds.done), + ] diff --git a/artiq/gateware/suservo/spi.py b/artiq/gateware/suservo/spi.py index d1d129aa9..94f28c9a1 100644 --- a/artiq/gateware/suservo/spi.py +++ b/artiq/gateware/suservo/spi.py @@ -37,8 +37,6 @@ class SPISimple(Module): assert p.clk >= 1 - cs_n = pads.cs_n - clk = pads.clk cnt = Signal(max=max(2, p.clk), reset_less=True) cnt_done = Signal() cnt_next = Signal() @@ -54,21 +52,17 @@ class SPISimple(Module): ] for i, d in enumerate(self.data): - self.comb += [ - getattr(pads, "mosi{}".format(i)).eq(d[-1]) - ] + self.comb += getattr(pads, "mosi{}".format(i)).eq(d[-1]) bits = Signal(max=p.width + 1, reset_less=True) self.submodules.fsm = fsm = CEInserter()(FSM("IDLE")) - self.comb += [ - fsm.ce.eq(cnt_done) - ] + self.comb += fsm.ce.eq(cnt_done) fsm.act("IDLE", self.done.eq(1), - cs_n.eq(1), + pads.cs_n.eq(1), If(self.start, cnt_next.eq(1), NextState("SETUP") @@ -84,7 +78,7 @@ class SPISimple(Module): ) fsm.act("HOLD", cnt_next.eq(1), - clk.eq(1), + pads.clk.eq(1), NextState("SETUP") ) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index c27035746..ab7541858 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -224,7 +224,7 @@ def _sampler(eem, eem_aux=None): Subsignal("sdod", Pins(_eem_pin(eem_aux, 4, "n"))), IOStandard("LVDS_25"), ), - ] + ] return ios @@ -362,7 +362,7 @@ def _urukul_qspi(eem0, eem1): )) ios += [ ("{}_qspi_p".format(eem0), 0, - Subsignal("cs_n", Pins(_eem_pin(eem0, 5, "p"))), + Subsignal("cs", Pins(_eem_pin(eem0, 5, "p"))), Subsignal("clk", Pins(_eem_pin(eem0, 2, "p"))), Subsignal("mosi0", Pins(_eem_pin(eem1, 0, "p"))), Subsignal("mosi1", Pins(_eem_pin(eem1, 1, "p"))), @@ -371,7 +371,7 @@ def _urukul_qspi(eem0, eem1): IOStandard("LVDS_25"), ), ("{}_qspi_n".format(eem0), 0, - Subsignal("cs_n", Pins(_eem_pin(eem0, 5, "n"))), + Subsignal("cs", Pins(_eem_pin(eem0, 5, "n"))), Subsignal("clk", Pins(_eem_pin(eem0, 2, "n"))), Subsignal("mosi0", Pins(_eem_pin(eem1, 0, "n"))), Subsignal("mosi1", Pins(_eem_pin(eem1, 1, "n"))), @@ -525,25 +525,25 @@ class SUServo(_StandaloneBase): rtio_channels.append(rtio.Channel.from_phy(phy)) # EEM3, EEM2: Sampler - sampler_pads = servo_pads.SamplerPads(self.platform, "eem3", "eem2") + sampler_pads = servo_pads.SamplerPads(self.platform, "eem3") # EEM5, EEM4 and EEM7, EEM6: Urukul urukul_pads = servo_pads.UrukulPads(self.platform, - "eem5", "eem4", "eem7", "eem6") - adc_p = servo.ADCParams(width=16, channels=8, lanes=4, - t_cnvh=4, t_conv=57, t_rtt=4) - iir_p = servo.IIRWidths(state=25, coeff=18, adc=16, - asf=14, word=16, accu=48, shift=11, - channel=3, profile=5) + "eem5", "eem7") + adc_p = servo.ADCParams(width=16, channels=8, lanes=4, t_cnvh=4, + # account for SCK pipeline latency + t_conv=57 - 4, t_rtt=4 + 4) + iir_p = servo.IIRWidths(state=25, coeff=18, adc=16, asf=14, word=16, + accu=48, shift=11, channel=3, profile=5) dds_p = servo.DDSParams(width=8 + 32 + 16 + 16, channels=adc_p.channels, clk=1) su = servo.Servo(sampler_pads, urukul_pads, adc_p, iir_p, dds_p) - su = ClockDomainsRenamer({"sys": "rio_phy"})(su) + su = ClockDomainsRenamer("rio_phy")(su) self.submodules += sampler_pads, urukul_pads, su ctrls = [rtservo.RTServoCtrl(ctrl) for ctrl in su.iir.ctrl] self.submodules += ctrls rtio_channels.extend(rtio.Channel.from_phy(ctrl) for ctrl in ctrls) - mem = rtservo.RTServoMem(iir_p, su.iir) + mem = rtservo.RTServoMem(iir_p, su) self.submodules += mem rtio_channels.append(rtio.Channel.from_phy(mem, ififo_depth=4)) diff --git a/artiq/gateware/test/suservo/test_adc.py b/artiq/gateware/test/suservo/test_adc.py index c561dbd51..3b31b0708 100644 --- a/artiq/gateware/test/suservo/test_adc.py +++ b/artiq/gateware/test/suservo/test_adc.py @@ -37,7 +37,7 @@ class TB(Module): sr = Signal(p.width*p.channels//p.lanes, reset_less=True) srs.append(sr) self.sync.adc += [ - sdo.eq(self._dly(sr[-1], -1)), + sdo.eq(self._dly(sr[-1], 0)), If(adc_sck_en, sr[1:].eq(sr) ) @@ -52,10 +52,10 @@ class TB(Module): adc_clk_rec = Signal() self.comb += [ - adc_sck_en.eq(self._dly(self.sck_en, 1)), + adc_sck_en.eq(self._dly(self.sck_en, 0)), self.sck_en_ret.eq(self._dly(adc_sck_en)), - adc_clk_rec.eq(self._dly(self.sck, 1)), + adc_clk_rec.eq(self._dly(self.sck, 0)), self.clkout.eq(self._dly(adc_clk_rec)), ] diff --git a/artiq/gateware/test/suservo/test_servo.py b/artiq/gateware/test/suservo/test_servo.py index 8d0443ef8..efa706cd0 100644 --- a/artiq/gateware/test/suservo/test_servo.py +++ b/artiq/gateware/test/suservo/test_servo.py @@ -11,10 +11,9 @@ from artiq.gateware.suservo import servo class ServoSim(servo.Servo): def __init__(self): adc_p = servo.ADCParams(width=16, channels=8, lanes=4, - t_cnvh=4, t_conv=57, t_rtt=4) - iir_p = servo.IIRWidths(state=25, coeff=18, adc=16, - asf=14, word=16, accu=48, shift=11, - channel=3, profile=5) + t_cnvh=4, t_conv=57 - 4, t_rtt=4 + 4) + iir_p = servo.IIRWidths(state=25, coeff=18, adc=16, asf=14, word=16, + accu=48, shift=11, channel=3, profile=5) dds_p = servo.DDSParams(width=8 + 32 + 16 + 16, channels=adc_p.channels, clk=1) From fe9834bac4c87a8f857d0dd1f4967ad9f552cb4e Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 27 Apr 2018 12:04:17 +0000 Subject: [PATCH 0653/2457] suservo: update 'technology preview' example [wip] Still with mostly undocumented and unstable API. --- .../kasli_suservo/repository/suservo.py | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/artiq/examples/kasli_suservo/repository/suservo.py b/artiq/examples/kasli_suservo/repository/suservo.py index aa7853c0a..ace00485c 100644 --- a/artiq/examples/kasli_suservo/repository/suservo.py +++ b/artiq/examples/kasli_suservo/repository/suservo.py @@ -6,23 +6,50 @@ class SUServo(EnvExperiment): self.setattr_device("core") self.setattr_device("led0") self.setattr_device("suservo0") - self.setattr_device("suservo0_ch0") + for i in range(8): + self.setattr_device("suservo0_ch{}".format(i)) def run(self): # self.led() self.init() + def p(self, d): + for name, value in zip("ftw1 b1 pow cfg offset a1 ftw0 b0".split(), d): + print(name, hex(value)) + @kernel def init(self): self.core.break_realtime() self.core.reset() self.suservo0.init() - self.suservo0.set_config(1) + delay(1*us) + self.suservo0.cpld0.set_att_mu(0, 255) + delay(1*us) + print(self.suservo0.get_status()) delay(3*ms) - self.suservo0.set_config(0) - delay(3*ms) + + self.suservo0_ch0.set_profile_mu( + profile=0, ftw=0x12345667, adc=0, offset=0x10, + a1=-0x2000, b0=0x1ffff, b1=0, delay=0, pow=0xaa55) + self.suservo0_ch0.set(en_out=1, en_iir=1, profile=0) + + delay(10*ms) + self.suservo0.set_config(1) + delay(10*ms) + data = [0] * 8 + self.suservo0_ch0.get_profile_mu(0, data) + self.p(data) + delay(10*ms) + print(self.suservo0.get_adc_mu(0)) + delay(10*ms) + print(self.suservo0.get_adc_mu(1)) + delay(10*ms) + print(self.suservo0_ch0.get_asf_mu(0)) + delay(10*ms) + print(self.suservo0_ch0.get_asf_mu(0)) + delay(10*ms) print(self.suservo0.get_status()) @kernel From 4e2d9abaf7f0500a877c6fbee86a56cf553137d5 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 27 Apr 2018 14:32:03 +0200 Subject: [PATCH 0654/2457] firmware/ad9154: combine analog and digital delay of hmc7043 for sysref scan --- artiq/firmware/libboard_artiq/ad9154.rs | 34 ++++++++++---------- artiq/firmware/libboard_artiq/hmc830_7043.rs | 14 +++++--- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 2f9bbd86c..48f4cdcc1 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -1,6 +1,6 @@ use board::{csr, clock}; use ad9154_reg; -use hmc830_7043::{hmc7043}; +use hmc830_7043::hmc7043; fn spi_setup(dacno: u8) { unsafe { @@ -611,39 +611,39 @@ fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { fn dac_sysref_cfg(dacno: u8) { let mut sync_error: u16 = 0; let mut sync_error_last: u16 = 0; - let mut cphase_min_found: bool = false; - let mut cphase_min: u8 = 0; - let mut cphase_max_found: bool = false; - let mut cphase_max: u8 = 0; - let mut cphase_opt: u8 = 0; + let mut phase_min_found: bool = false; + let mut phase_min: u16 = 0; + let mut phase_max_found: bool = false; + let mut phase_max: u16 = 0; + let mut phase_opt: u16 = 0; info!("AD9154-{} SYSREF scan/conf...", dacno); - for cphase in 0..32 { - hmc7043::cfg_dac_sysref(dacno, 0, cphase); + for phase in 0..512 { + hmc7043::cfg_dac_sysref(dacno, phase); clock::spin_us(10000); spi_setup(dacno); sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) | ((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8)) & 0x1ff; - info!(" cphase: {}, sync error: {}", cphase, sync_error); + info!(" phase: {}, sync error: {}", phase, sync_error); if sync_error != 0 { - if cphase_min_found { + if phase_min_found { if sync_error != sync_error_last { - cphase_max_found = true; - cphase_max = cphase - 1; + phase_max_found = true; + phase_max = phase - 1; break; } } else { - cphase_min_found = true; - cphase_min = cphase; + phase_min_found = true; + phase_min = phase; } } sync_error_last = sync_error; } - cphase_opt = cphase_min + (cphase_max-cphase_min)/2; - info!(" cphase min: {}, cphase max: {}, cphase opt: {}", cphase_min, cphase_max, cphase_opt); - hmc7043::cfg_dac_sysref(dacno, 0, cphase_opt); + phase_opt = phase_min + (phase_max-phase_min)/2; + info!(" phase min: {}, phase max: {}, phase opt: {}", phase_min, phase_max, phase_opt); + hmc7043::cfg_dac_sysref(dacno, phase_opt); } pub fn init() -> Result<(), &'static str> { diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index b1e5d9201..fef3c8236 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -250,14 +250,18 @@ pub mod hmc7043 { Ok(()) } - pub fn cfg_dac_sysref(dacno: u8, aphase: u8, cphase: u8) { + pub fn cfg_dac_sysref(dacno: u8, phase: u16) { spi_setup(); + /* Analog delay resolution: 25ps + * Digital delay resolution: 1/2 input clock cycle = 416ps for 1.2GHz + * 16*25ps = 400ps: limit analog delay to 16 steps instead of 32. + */ if dacno == 0 { - write(0x00D5, aphase); - write(0x00D6, cphase); + write(0x00d5, (phase & 0xf) as u8); + write(0x00d6, ((phase >> 4) & 0x1f) as u8); } else if dacno == 1 { - write(0x00E9, aphase); - write(0x00EA, cphase); + write(0x00e9, (phase & 0xf) as u8); + write(0x00ea, ((phase >> 4) & 0x1f) as u8); } else { unimplemented!(); } From 73fa5722754d6e2c7e34be92887b5aa050cca8e0 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 27 Apr 2018 14:53:11 +0000 Subject: [PATCH 0655/2457] suservo: documentation, small API changes --- artiq/coredevice/suservo.py | 172 ++++++++++++++++-- .../kasli_suservo/repository/suservo.py | 47 +++-- doc/manual/core_drivers_reference.rst | 10 + 3 files changed, 198 insertions(+), 31 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 653f0b683..e642afcec 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -1,4 +1,4 @@ -from artiq.language.core import kernel, delay, portable, now_mu +from artiq.language.core import kernel, delay, portable, now_mu, delay_mu from artiq.language.units import us, ms from artiq.coredevice.rtio import rtio_output, rtio_input_data @@ -39,8 +39,18 @@ class SUServo: @kernel def init(self): + """Initialize the Servo, Sampler and both Urukuls. + + Leaves the Servo disabled (see :meth:`set_config`), resets all DDS. + + Urukul initialization is performed blindly as there is no readback from + the DDS or the CPLDs. + + This method does not alter the profile configuration memory + or the channel controls. + """ self.set_config(0) - delay(2*us) # pipeline flush + delay(3*us) # pipeline flush self.pgia.set_config_mu( sampler.SPI_CONFIG | spi.SPI_END, @@ -60,29 +70,62 @@ class SUServo: @kernel def write(self, addr, value): + """Write to Servo memory. + + This method advances the timeline by one coarse RTIO cycle. + + :param addr: Memory location address. + :param value: Data to be written. + """ rtio_output(now_mu(), self.channel, addr | WE, value) delay_mu(self.ref_period_mu) @kernel def read(self, addr): + """Read from Servo memory. + + This method does not advance the timeline but consumes all slack. + + :param addr: Memory location address. + """ rtio_output(now_mu(), self.channel, addr, 0) return rtio_input_data(self.channel) @kernel - def set_config(self, start): - self.write(CONFIG_ADDR, start) + def set_config(self, enable): + """Set SU Servo configuration. + + This method advances the timeline by one Servo memory access. + + :param enable: Enable Servo operation. Disabling takes up to 2 Servo + cycles (~2.2 µs). + """ + self.write(CONFIG_ADDR, enable) @kernel def get_status(self): + """Get current SU Servo status. + + This method does not advance the timeline but consumes all slack. + + :return: Status. Bit 0: enabled, bit 1: done + """ return self.read(CONFIG_ADDR) @kernel def get_adc_mu(self, adc): + """Get an ADC reading (IIR filter input X0). + + This method does not advance the timeline but consumes all slack. + + :param adc: ADC channel number (0-7) + :return: 16 bit signed Y0 + """ return self.read(STATE_SEL | (adc << 1) | (1 << 8)) @kernel - def set_gain_mu(self, channel, gain): - """Set instrumentation amplifier gain of a channel. + def set_pgia_mu(self, channel, gain): + """Set instrumentation amplifier gain of a ADC channel. The four gain settings (0, 1, 2, 3) corresponds to gains of (1, 10, 100, 1000) respectively. @@ -96,6 +139,10 @@ class SUServo: self.pgia.write(gains << 16) self.gains = gains + @kernel + def get_adc(self, adc): + raise NotImplementedError # FIXME + class Channel: kernel_invariants = {"channel", "core", "servo", "servo_channel"} @@ -105,28 +152,123 @@ class Channel: self.core = dmgr.get(core_device) self.servo = dmgr.get(servo_device) self.channel = channel - self.servo_channel = self.channel + 8 - self.servo.channel # FIXME + # FIXME: this assumes the mem channel is right after the control + # channels + self.servo_channel = self.channel + 8 - self.servo.channel @kernel def set(self, en_out, en_iir=0, profile=0): + """Operate channel. + + This method does not advance the timeline. + + :param en_out: RF switch enable + :param en_iir: IIR updates enable + :param profile: Active profile (0-31) + """ rtio_output(now_mu(), self.channel, 0, en_out | (en_iir << 1) | (profile << 2)) @kernel - def set_profile_mu(self, profile, ftw, adc, offset, - a1, b0, b1, delay, pow=0): + def set_dds_mu(self, profile, ftw, offset, pow=0): + """Set profile DDS coefficients. + + This method advances the timeline by four Servo memory accesses. + + :param profile: Profile number (0-31) + :param ftw: Frequency tuning word (32 bit unsigned) + :param offset: IIR offset (setpoint) + :param pow: Phase offset word (16 bit unsigned) + """ base = (self.servo_channel << 8) | (profile << 3) - data = [ftw >> 16, b1, pow, adc | (delay << 8), offset, a1, ftw, b0] - for i in range(8): - self.servo.write(base + i, data[i]) + self.servo.write(base + 0, ftw >> 16) + self.servo.write(base + 6, ftw) + self.servo.write(base + 4, offset) + self.servo.write(base + 2, pow) + + @kernel + def set_dds(self, profile, frequency, offset, phase=0.): + raise NotImplementedError # FIXME + + @kernel + def set_iir_mu(self, profile, adc, a1, b0, b1, delay=0): + """Set profile IIR coefficients. + + This method advances the timeline by four Servo memory accesses. + + :param profile: Profile number (0-31) + :param adc: ADC channel to use (0-7) + :param a1: 18 bit signed A1 coefficient (Y1 coefficient, + feedback, integrator gain) + :param b0: 18 bit signed B0 coefficient (recent, + X0 coefficient, feed forward, proportional gain) + :param b1: 18 bit signed B1 coefficient (old, + X1 coefficient, feed forward, proportional gain) + :param delay: Number of Servo cycles (~1.1 µs each) to suppress + IIR updates for after either (1) enabling or disabling RF output, + (2) enabling or disabling IIR updates, or (3) setting the active + profile number: i.e. after invoking :meth:`set`. + """ + base = (self.servo_channel << 8) | (profile << 3) + self.servo.write(base + 1, b1) + self.servo.write(base + 3, adc | (delay << 8)) + self.servo.write(base + 5, a1) + self.servo.write(base + 7, b0) + + @kernel + def set_iir(self, profile, adc, i_gain, p_gain, delay=0.): + raise NotImplementedError # FIXME @kernel def get_profile_mu(self, profile, data): + """Retrieve profile data. + + The data is returned in the `data` argument as: + `[ftw >> 16, b1, pow, adc | (delay << 8), offset, a1, ftw, b0]`. + + This method advances the timeline by 32 µs and consumes all slack. + + :param profile: Profile number (0-31) + :param data: List of 8 integers to write the profile data into + """ base = (self.servo_channel << 8) | (profile << 3) - for i in range(8): + for i in range(len(data)): data[i] = self.servo.read(base + i) - delay(2*us) + delay(4*us) @kernel - def get_asf_mu(self, profile): + def get_y_mu(self, profile): + """Get a profile's IIR state (filter output, Y0). + + The IIR state is also know as the "integrator", or the DDS amplitude + scale factor. It is 18 bits wide and unsigned. + + This method does not advance the timeline but consumes all slack. + + :param profile: Profile number (0-31) + :return: 18 bit unsigned Y0 + """ return self.servo.read(STATE_SEL | (self.servo_channel << 5) | profile) + + @kernel + def get_y(self, profile): + raise NotImplementedError # FIXME + + @kernel + def set_y_mu(self, profile, y): + """Set a profile's IIR state (filter output, Y0). + + The IIR state is also know as the "integrator", or the DDS amplitude + scale factor. It is 18 bits wide and unsigned. + + This method advances the timeline by one Servo memory access. + + :param profile: Profile number (0-31) + :param y: 18 bit unsigned Y0 + """ + return self.servo.write( + STATE_SEL | (self.servo_channel << 5) | profile, y) + + @kernel + def set_y(self, profile, y): + raise NotImplementedError # FIXME diff --git a/artiq/examples/kasli_suservo/repository/suservo.py b/artiq/examples/kasli_suservo/repository/suservo.py index ace00485c..09e3f7653 100644 --- a/artiq/examples/kasli_suservo/repository/suservo.py +++ b/artiq/examples/kasli_suservo/repository/suservo.py @@ -24,33 +24,48 @@ class SUServo(EnvExperiment): self.suservo0.init() delay(1*us) - self.suservo0.cpld0.set_att_mu(0, 255) + # ADC PGIA gain + self.suservo0.set_pgia_mu(0, 0) + # DDS attenuator + self.suservo0.cpld0.set_att_mu(0, 64) delay(1*us) + assert self.suservo0.get_status() == 2 - print(self.suservo0.get_status()) - delay(3*ms) - - self.suservo0_ch0.set_profile_mu( - profile=0, ftw=0x12345667, adc=0, offset=0x10, - a1=-0x2000, b0=0x1ffff, b1=0, delay=0, pow=0xaa55) + # set up profile 0 on channel 0 + self.suservo0_ch0.set_y_mu(0, 0) + self.suservo0_ch0.set_iir_mu( + profile=0, adc=0, a1=-0x800, b0=0x1000, b1=0, delay=0) + self.suservo0_ch0.set_dds_mu( + profile=0, ftw=0x12345667, offset=0x1, pow=0xaa55) + # enable channel self.suservo0_ch0.set(en_out=1, en_iir=1, profile=0) - - delay(10*ms) + # enable servo iterations self.suservo0.set_config(1) - delay(10*ms) + + # read back profile data data = [0] * 8 self.suservo0_ch0.get_profile_mu(0, data) self.p(data) delay(10*ms) + + # check servo status + assert self.suservo0.get_status() == 1 + + # reach back ADC data print(self.suservo0.get_adc_mu(0)) delay(10*ms) - print(self.suservo0.get_adc_mu(1)) + + # read out IIR data + print(self.suservo0_ch0.get_y_mu(0)) delay(10*ms) - print(self.suservo0_ch0.get_asf_mu(0)) - delay(10*ms) - print(self.suservo0_ch0.get_asf_mu(0)) - delay(10*ms) - print(self.suservo0.get_status()) + + # repeatedly clear the IIR state/integrator + # with the ADC yielding 0's and given the profile configuration, + # this will lead to a slow ram up of the amplitude over about 200ms + # followed by saturation and repetition. + while True: + self.suservo0_ch0.set_y_mu(0, 0) + delay(.2*s) @kernel def led(self): diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index bdfd93519..c54a44c0d 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -132,3 +132,13 @@ DAC/ADC drivers .. automodule:: artiq.coredevice.novogorny :members: + + +Compound drivers +---------------- + +:mod:`artiq.coredevice.suservo` module +++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.suservo + :members: From 5f00326c654275875528ab62df2cfb1996a53174 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 27 Apr 2018 15:34:48 +0000 Subject: [PATCH 0656/2457] suservo: coeff mem write port READ_FIRST --- artiq/coredevice/suservo.py | 10 ++++++++-- artiq/examples/kasli_suservo/repository/suservo.py | 3 +++ artiq/gateware/rtio/phy/servo.py | 2 ++ artiq/gateware/suservo/iir.py | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index e642afcec..8dfff8af1 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -95,10 +95,12 @@ class SUServo: def set_config(self, enable): """Set SU Servo configuration. + Disabling takes up to 2 Servo cycles (~2.2 µs) to clear + the processing pipeline. + This method advances the timeline by one Servo memory access. - :param enable: Enable Servo operation. Disabling takes up to 2 Servo - cycles (~2.2 µs). + :param enable: Enable Servo operation. """ self.write(CONFIG_ADDR, enable) @@ -261,6 +263,10 @@ class Channel: The IIR state is also know as the "integrator", or the DDS amplitude scale factor. It is 18 bits wide and unsigned. + This method must not be used when the Servo + could be writing to the same location. Either deactivate the profile, + or deactivate IIR updates, or disable Servo iterations. + This method advances the timeline by one Servo memory access. :param profile: Profile number (0-31) diff --git a/artiq/examples/kasli_suservo/repository/suservo.py b/artiq/examples/kasli_suservo/repository/suservo.py index 09e3f7653..7e7b4e711 100644 --- a/artiq/examples/kasli_suservo/repository/suservo.py +++ b/artiq/examples/kasli_suservo/repository/suservo.py @@ -30,11 +30,13 @@ class SUServo(EnvExperiment): self.suservo0.cpld0.set_att_mu(0, 64) delay(1*us) assert self.suservo0.get_status() == 2 + delay(10*us) # set up profile 0 on channel 0 self.suservo0_ch0.set_y_mu(0, 0) self.suservo0_ch0.set_iir_mu( profile=0, adc=0, a1=-0x800, b0=0x1000, b1=0, delay=0) + delay(10*us) self.suservo0_ch0.set_dds_mu( profile=0, ftw=0x12345667, offset=0x1, pow=0xaa55) # enable channel @@ -50,6 +52,7 @@ class SUServo(EnvExperiment): # check servo status assert self.suservo0.get_status() == 1 + delay(10*us) # reach back ADC data print(self.suservo0.get_adc_mu(0)) diff --git a/artiq/gateware/rtio/phy/servo.py b/artiq/gateware/rtio/phy/servo.py index 34a5e58fe..eb1f8495f 100644 --- a/artiq/gateware/rtio/phy/servo.py +++ b/artiq/gateware/rtio/phy/servo.py @@ -28,9 +28,11 @@ class RTServoMem(Module): interface.""" def __init__(self, w, servo): m_coeff = servo.iir.m_coeff.get_port(write_capable=True, + mode=READ_FIRST, we_granularity=w.coeff, clock_domain="rio") assert len(m_coeff.we) == 2 m_state = servo.iir.m_state.get_port(write_capable=True, + # mode=READ_FIRST, clock_domain="rio") self.specials += m_state, m_coeff diff --git a/artiq/gateware/suservo/iir.py b/artiq/gateware/suservo/iir.py index c7cfc3c77..bd4c7dda2 100644 --- a/artiq/gateware/suservo/iir.py +++ b/artiq/gateware/suservo/iir.py @@ -344,7 +344,7 @@ class IIR(Module): ] m_coeff = self.m_coeff.get_port() - m_state = self.m_state.get_port(write_capable=True) + m_state = self.m_state.get_port(write_capable=True) # mode=READ_FIRST self.specials += m_state, m_coeff dsp = DSP(w) From 5d3c76fd50611a9c084ba9370128249bbf83dfec Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 27 Apr 2018 15:38:57 +0000 Subject: [PATCH 0657/2457] sayma_rtm: use bitstream opts in migen --- artiq/gateware/targets/sayma_rtm.py | 6 ------ conda/artiq-dev/meta.yaml | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 07199320b..9bb6bef55 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -81,12 +81,6 @@ CSR_RANGE_SIZE = 0x800 class SaymaRTM(Module): def __init__(self, platform): - platform.toolchain.bitstream_commands.extend([ - "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]", - "set_property CFGBVS VCCO [current_design]", - "set_property CONFIG_VOLTAGE 3.3 [current_design]", - ]) - csr_devices = [] self.submodules.crg = CRG(platform) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 1fb1c112a..4f29e7777 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_26+git4039322 + - migen 0.7 py35_30+git5c2c144 - misoc 0.11 py35_7+git269b6502 - jesd204b 0.5 - microscope From ae80bab180905f64030c9f4194a40d8759a51666 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 27 Apr 2018 16:42:09 +0000 Subject: [PATCH 0658/2457] urukul: reg based io-update is a kernel --- artiq/coredevice/urukul.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index a2ce2365f..295281364 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -99,7 +99,7 @@ class _RegIOUpdate: def __init__(self, cpld): self.cpld = cpld - @portable + @kernel def pulse(self, t): cfg = self.cpld.cfg_reg self.cpld.cfg_write(cfg | (1 << CFG_IO_UPDATE)) From 8812824fb25e789725c720b5807e43df13b5d629 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 27 Apr 2018 17:17:17 +0000 Subject: [PATCH 0659/2457] suservo: speed up example, interlock mem --- artiq/examples/kasli_suservo/repository/suservo.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/artiq/examples/kasli_suservo/repository/suservo.py b/artiq/examples/kasli_suservo/repository/suservo.py index 7e7b4e711..61ad9f47f 100644 --- a/artiq/examples/kasli_suservo/repository/suservo.py +++ b/artiq/examples/kasli_suservo/repository/suservo.py @@ -38,7 +38,7 @@ class SUServo(EnvExperiment): profile=0, adc=0, a1=-0x800, b0=0x1000, b1=0, delay=0) delay(10*us) self.suservo0_ch0.set_dds_mu( - profile=0, ftw=0x12345667, offset=0x1, pow=0xaa55) + profile=0, ftw=0x12345667, offset=0x1000, pow=0xaa55) # enable channel self.suservo0_ch0.set(en_out=1, en_iir=1, profile=0) # enable servo iterations @@ -64,11 +64,15 @@ class SUServo(EnvExperiment): # repeatedly clear the IIR state/integrator # with the ADC yielding 0's and given the profile configuration, - # this will lead to a slow ram up of the amplitude over about 200ms + # this will lead to a slow ram up of the amplitude over about 40µs # followed by saturation and repetition. while True: + self.suservo0_ch0.set(1, 0, 0) + delay(1*us) self.suservo0_ch0.set_y_mu(0, 0) - delay(.2*s) + delay(1*us) + self.suservo0_ch0.set(1, 1, 0) + delay(60*us) @kernel def led(self): From f35f10011091ccffe7d2cc02c7681367b49ff1e6 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 28 Apr 2018 00:49:25 +0000 Subject: [PATCH 0660/2457] compiler: don't crash printing locations of specialized functions. Fixes #987. --- artiq/compiler/embedding.py | 5 +++++ .../lit/embedding/error_specialized_annot.py | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 artiq/test/lit/embedding/error_specialized_annot.py diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index 6cee76bf9..e72adeee2 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -749,6 +749,11 @@ class Stitcher: quote_function=self._quote_function) def _function_loc(self, function): + if isinstance(function, SpecializedFunction): + function = function.host_function + if hasattr(function, 'artiq_embedded'): + function = function.artiq_embedded.function + filename = function.__code__.co_filename line = function.__code__.co_firstlineno name = function.__code__.co_name diff --git a/artiq/test/lit/embedding/error_specialized_annot.py b/artiq/test/lit/embedding/error_specialized_annot.py new file mode 100644 index 000000000..c474f235b --- /dev/null +++ b/artiq/test/lit/embedding/error_specialized_annot.py @@ -0,0 +1,19 @@ +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t +# RUN: OutputCheck %s --file-to-check=%t + +from artiq.experiment import * + +class c(): +# CHECK-L: ${LINE:+2}: error: type annotation for argument 'x', 'None', is not an ARTIQ type + @kernel + def hello(self, x: None): + pass + + @kernel + def run(self): + self.hello(2) + +i = c() +@kernel +def entrypoint(): + i.run() From 5170848cd61a09cfdb40e7afdfccc6372d0edca0 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 28 Apr 2018 00:56:01 +0000 Subject: [PATCH 0661/2457] conda: artiq-board should be noarch, like artiq itself. Fixes #989. --- conda/artiq-board/meta.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index 3174bce65..db5a37cf9 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -6,6 +6,7 @@ source: git_url: ../.. build: + noarch: python number: {{ environ["GIT_DESCRIBE_NUMBER"] }} string: {{ environ["GIT_DESCRIBE_NUMBER"] }}+git{{ environ["GIT_FULL_HASH"][:8] }} script_env: From f7e08ec46b5f4ce8d2767aae9c568b5c27cfe1d0 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 28 Apr 2018 01:03:08 +0000 Subject: [PATCH 0662/2457] Unbreak f35f1001. --- artiq/compiler/embedding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index e72adeee2..539e4ddad 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -751,7 +751,7 @@ class Stitcher: def _function_loc(self, function): if isinstance(function, SpecializedFunction): function = function.host_function - if hasattr(function, 'artiq_embedded'): + if hasattr(function, 'artiq_embedded') and function.artiq_embedded.function: function = function.artiq_embedded.function filename = function.__code__.co_filename From 17d7d7856a833f3c07dbff88a67143bc0f3a3d19 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 28 Apr 2018 21:30:29 +0200 Subject: [PATCH 0663/2457] kasli: force hw_rev for the different targets --- artiq/gateware/targets/kasli.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index ab7541858..faba6e128 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -388,7 +388,7 @@ class Opticlock(_StandaloneBase): Opticlock extension variant configuration """ def __init__(self, **kwargs): - _StandaloneBase.__init__(self, **kwargs) + _StandaloneBase.__init__(self, hw_rev="v1.0", **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None @@ -493,7 +493,7 @@ class SUServo(_StandaloneBase): SUServo (Sampler-Urukul-Servo) extension variant configuration """ def __init__(self, **kwargs): - _StandaloneBase.__init__(self, **kwargs) + _StandaloneBase.__init__(self, hw_rev="v1.1", **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None @@ -605,7 +605,7 @@ class SUServo(_StandaloneBase): class SYSU(_StandaloneBase): def __init__(self, **kwargs): - _StandaloneBase.__init__(self, **kwargs) + _StandaloneBase.__init__(self, hw_rev="v1.1", **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" @@ -659,10 +659,8 @@ class SYSU(_StandaloneBase): class MITLL(_StandaloneBase): - def __init__(self, hw_rev=None, **kwargs): - if hw_rev is None: - hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + def __init__(self, **kwargs): + _StandaloneBase.__init__(self, hw_rev="v1.1", **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" From 5a683ddd1f1e9604c3ea06cb9a6bb0bacaab0794 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 28 Apr 2018 23:24:41 +0200 Subject: [PATCH 0664/2457] Revert "kasli: force hw_rev for the different targets" This reverts commit 17d7d7856a833f3c07dbff88a67143bc0f3a3d19. Would require filtering it in misoc or better removing the argparse option. --- artiq/gateware/targets/kasli.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index faba6e128..ab7541858 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -388,7 +388,7 @@ class Opticlock(_StandaloneBase): Opticlock extension variant configuration """ def __init__(self, **kwargs): - _StandaloneBase.__init__(self, hw_rev="v1.0", **kwargs) + _StandaloneBase.__init__(self, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None @@ -493,7 +493,7 @@ class SUServo(_StandaloneBase): SUServo (Sampler-Urukul-Servo) extension variant configuration """ def __init__(self, **kwargs): - _StandaloneBase.__init__(self, hw_rev="v1.1", **kwargs) + _StandaloneBase.__init__(self, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None @@ -605,7 +605,7 @@ class SUServo(_StandaloneBase): class SYSU(_StandaloneBase): def __init__(self, **kwargs): - _StandaloneBase.__init__(self, hw_rev="v1.1", **kwargs) + _StandaloneBase.__init__(self, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" @@ -659,8 +659,10 @@ class SYSU(_StandaloneBase): class MITLL(_StandaloneBase): - def __init__(self, **kwargs): - _StandaloneBase.__init__(self, hw_rev="v1.1", **kwargs) + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" From 64c8eee28d6eec7db071842c8a67d21880998142 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 30 Apr 2018 23:59:56 +0200 Subject: [PATCH 0665/2457] serwb/phy/master: fix slave ready detection by filtering possible glitches on rx data (seems to happen when RTM fpga is not loaded) --- artiq/gateware/serwb/phy.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index fe6885ab9..8a921dbe6 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -58,7 +58,10 @@ class _SerdesMasterInit(Module): ) fsm.act("SEND_PATTERN", If(~serdes.rx_idle, - NextState("WAIT_STABLE") + timer.wait.eq(1), + If(timer.done, + NextState("CHECK_PATTERN") + ) ), serdes.tx_comma.eq(1) ) From 623614f8351917276d977689b6604a76db45ccb9 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 1 May 2018 08:57:26 +0000 Subject: [PATCH 0666/2457] Update LLVM to 6.0.0 and Rust to 1.25.0. --- artiq/firmware/Cargo.lock | 47 ++++++++++++++++++---------------- artiq/firmware/Cargo.toml | 3 ++- artiq/firmware/ksupport/lib.rs | 3 --- artiq/firmware/runtime/main.rs | 2 +- conda/artiq-dev/meta.yaml | 6 ++--- conda/artiq/meta.yaml | 2 +- 6 files changed, 32 insertions(+), 31 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 5a3624209..7543617be 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -27,8 +27,8 @@ name = "board" version = "0.0.0" dependencies = [ "build_misoc 0.0.0", - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=ca06a5e)", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", ] @@ -41,7 +41,7 @@ dependencies = [ "board 0.0.0", "build_artiq 0.0.0", "build_misoc 0.0.0", - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -51,7 +51,7 @@ version = "0.0.0" dependencies = [ "board 0.0.0", "build_misoc 0.0.0", - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", ] @@ -74,12 +74,12 @@ version = "0.0.0" [[package]] name = "byteorder" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cc" -version = "1.0.3" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -111,7 +111,7 @@ version = "0.0.0" dependencies = [ "board 0.0.0", "build_misoc 0.0.0", - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "std_artiq 0.0.0", @@ -126,7 +126,7 @@ name = "fringe" version = "1.1.0" source = "git+https://github.com/m-labs/libfringe?rev=bd23494#bd2349467157969324ca7da5d2ae033c7ffac0c0" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -146,7 +146,7 @@ dependencies = [ "amp 0.0.0", "board 0.0.0", "build_misoc 0.0.0", - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dyld 0.0.0", "proto 0.0.0", @@ -155,13 +155,16 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.34" +version = "0.2.40" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "log" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "log" @@ -187,14 +190,14 @@ dependencies = [ [[package]] name = "managed" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proto" version = "0.0.0" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dyld 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -212,7 +215,7 @@ dependencies = [ "board_artiq 0.0.0", "build_artiq 0.0.0", "build_misoc 0.0.0", - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "drtioaux 0.0.0", "fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)", @@ -252,9 +255,9 @@ name = "smoltcp" version = "0.4.0" source = "git+https://github.com/m-labs/smoltcp?rev=181083f#181083f18c977b8a0463a67e360e4db20594fa21" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "managed 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "managed 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -284,19 +287,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9" -"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" -"checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719" +"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" +"checksum cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2b4911e4bdcb4100c7680e7e854ff38e23f1b34d4d9e079efae3da2801341ffc" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=ca06a5e)" = "" "checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" "checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0" -"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" +"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" +"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" -"checksum managed 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "786bd3519bdfb0e1a57146a74b7584555dd6c4f1b6e1137c70e177d60dde8186" +"checksum managed 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43e2737ecabe4ae36a68061398bf27d2bfd0763f4c3c837a398478459494c4b7" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)" = "" "checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" diff --git a/artiq/firmware/Cargo.toml b/artiq/firmware/Cargo.toml index ec99844a5..8ab755b00 100644 --- a/artiq/firmware/Cargo.toml +++ b/artiq/firmware/Cargo.toml @@ -2,4 +2,5 @@ members = ["bootloader", "runtime", "ksupport", "satman"] [profile.dev] -debug = 1 # either 0 or 2 cause an LLVM ICE +incremental = false # incompatible with LTO +debug = 2 diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 068f83761..f4f7c8afb 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -228,15 +228,12 @@ const DMA_BUFFER_SIZE: usize = 64 * 1024; struct DmaRecorder { active: bool, - #[allow(dead_code)] - padding: [u8; 3], //https://github.com/rust-lang/rust/issues/41315 data_len: usize, buffer: [u8; DMA_BUFFER_SIZE], } static mut DMA_RECORDER: DmaRecorder = DmaRecorder { active: false, - padding: [0; 3], data_len: 0, buffer: [0; DMA_BUFFER_SIZE], }; diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 6fce27df4..4aa9a5cf1 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(alloc, lang_items, global_allocator, repr_align, attr_literals)] +#![feature(lang_items, alloc, global_allocator)] extern crate alloc; extern crate cslice; diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 4f29e7777..75a3647b1 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -19,9 +19,9 @@ requirements: - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27 - - llvm-or1k 4.0.1 - - llvmlite-artiq 0.20.0 - - rust-core-or1k 1.23.0 19 + - llvm-or1k 6.0.0 + - llvmlite-artiq 0.23.0.dev 2 + - rust-core-or1k 1.25.0 20 - openocd 0.10.0 6 - lit - outputcheck diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index 2e47dd909..f40fde944 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -27,7 +27,7 @@ requirements: - setuptools 33.1.1 run: - python >=3.5.3,<3.6 - - llvmlite-artiq 0.20.0 + - llvmlite-artiq 0.23.0.dev 2 - binutils-or1k-linux >=2.27 - pythonparser >=1.1 - openocd 0.10.0 6 From 6cb9c8a9c1258d80053f2073e2d8c7658c759d02 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 1 May 2018 09:04:15 +0000 Subject: [PATCH 0667/2457] conda: fix build number for llvmlite-artiq. --- conda/artiq-dev/meta.yaml | 2 +- conda/artiq/meta.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 75a3647b1..0f51761e9 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -20,7 +20,7 @@ requirements: - microscope - binutils-or1k-linux >=2.27 - llvm-or1k 6.0.0 - - llvmlite-artiq 0.23.0.dev 2 + - llvmlite-artiq 0.23.0.dev py_2 - rust-core-or1k 1.25.0 20 - openocd 0.10.0 6 - lit diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index f40fde944..99a7e2ebf 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -27,7 +27,7 @@ requirements: - setuptools 33.1.1 run: - python >=3.5.3,<3.6 - - llvmlite-artiq 0.23.0.dev 2 + - llvmlite-artiq 0.23.0.dev py_2 - binutils-or1k-linux >=2.27 - pythonparser >=1.1 - openocd 0.10.0 6 From 84e598de69325b00fdfe7eb6625a15c88b602c42 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 1 May 2018 09:08:17 +0000 Subject: [PATCH 0668/2457] conda: fix build number for llvmlite-artiq (again). --- conda/artiq-dev/meta.yaml | 2 +- conda/artiq/meta.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 0f51761e9..0887bc237 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -20,7 +20,7 @@ requirements: - microscope - binutils-or1k-linux >=2.27 - llvm-or1k 6.0.0 - - llvmlite-artiq 0.23.0.dev py_2 + - llvmlite-artiq 0.23.0.dev py35_2 - rust-core-or1k 1.25.0 20 - openocd 0.10.0 6 - lit diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index 99a7e2ebf..482341845 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -27,7 +27,7 @@ requirements: - setuptools 33.1.1 run: - python >=3.5.3,<3.6 - - llvmlite-artiq 0.23.0.dev py_2 + - llvmlite-artiq 0.23.0.dev py35_2 - binutils-or1k-linux >=2.27 - pythonparser >=1.1 - openocd 0.10.0 6 From 84e1f05559bdf4d95408aea051509b4646a6b8c9 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 1 May 2018 16:11:26 +0200 Subject: [PATCH 0669/2457] sayma_rtm: make cd_sys4x clock domain reset_less --- artiq/gateware/targets/sayma_rtm.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 9bb6bef55..8cffd12ad 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -22,7 +22,7 @@ from artiq import __version__ as artiq_version class CRG(Module): def __init__(self, platform): self.clock_domains.cd_sys = ClockDomain() - self.clock_domains.cd_sys4x = ClockDomain() + self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) self.clock_domains.cd_clk200 = ClockDomain() self.serwb_refclk = Signal() @@ -55,7 +55,6 @@ class CRG(Module): Instance("BUFG", i_I=pll_sys4x, o_O=self.cd_sys4x.clk), Instance("BUFG", i_I=pll_clk200, o_O=self.cd_clk200.clk), AsyncResetSynchronizer(self.cd_sys, ~pll_locked | self.serwb_reset), - AsyncResetSynchronizer(self.cd_sys4x, ~pll_locked | self.serwb_reset), AsyncResetSynchronizer(self.cd_clk200, ~pll_locked | self.serwb_reset) ] From b48e782dd67282127a6bab96de5166a143e57f29 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 May 2018 22:15:19 +0800 Subject: [PATCH 0670/2457] tools/file_import: restore sys.modules. Closes #976 --- artiq/tools.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/artiq/tools.py b/artiq/tools.py index f7a399db7..679293143 100644 --- a/artiq/tools.py +++ b/artiq/tools.py @@ -6,6 +6,7 @@ import collections import atexit import string import os +from copy import copy import numpy as np @@ -84,8 +85,12 @@ def file_import(filename, prefix="file_import_"): path = os.path.dirname(os.path.realpath(filename)) sys.path.insert(0, path) try: - loader = importlib.machinery.SourceFileLoader(modname, filename) - module = loader.load_module() + previous_modules = copy(sys.modules) + try: + loader = importlib.machinery.SourceFileLoader(modname, filename) + module = loader.load_module() + finally: + sys.modules = previous_modules finally: sys.path.remove(path) From 05955bfd79daa925f86a812ae382145e70e8c5ca Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 1 May 2018 22:16:35 +0200 Subject: [PATCH 0671/2457] sayma_rtm: use bufio for sys4x (needed since we are using a -1 speedgrade) --- artiq/gateware/targets/sayma_rtm.py | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 8cffd12ad..8aecc65ff 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -30,29 +30,25 @@ class CRG(Module): pll_locked = Signal() pll_fb = Signal() - pll_sys = Signal() pll_sys4x = Signal() pll_clk200 = Signal() self.specials += [ - Instance("PLLE2_BASE", - p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, + Instance("MMCME2_BASE", + p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, - # VCO @ 1GHz - p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=10.0, - p_CLKFBOUT_MULT=10, p_DIVCLK_DIVIDE=1, - i_CLKIN1=self.serwb_refclk, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, + # VCO @ 1GHz + p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=10.0, + p_CLKFBOUT_MULT_F=10, p_DIVCLK_DIVIDE=1, + i_CLKIN1=self.serwb_refclk, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, - # 125MHz - p_CLKOUT0_DIVIDE=8, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_sys, + # 500MHz + p_CLKOUT0_DIVIDE_F=2, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_sys4x, - # 500MHz - p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=pll_sys4x, - - # 200MHz - p_CLKOUT2_DIVIDE=5, p_CLKOUT2_PHASE=0.0, o_CLKOUT2=pll_clk200 + # 200MHz + p_CLKOUT1_DIVIDE=5, p_CLKOUT1_PHASE=0.0, o_CLKOUT1=pll_clk200 ), - Instance("BUFG", i_I=pll_sys, o_O=self.cd_sys.clk), - Instance("BUFG", i_I=pll_sys4x, o_O=self.cd_sys4x.clk), + Instance("BUFR", p_BUFR_DIVIDE="4", i_I=pll_sys4x, o_O=self.cd_sys.clk), + Instance("BUFIO", i_I=pll_sys4x, o_O=self.cd_sys4x.clk), Instance("BUFG", i_I=pll_clk200, o_O=self.cd_clk200.clk), AsyncResetSynchronizer(self.cd_sys, ~pll_locked | self.serwb_reset), AsyncResetSynchronizer(self.cd_clk200, ~pll_locked | self.serwb_reset) From 83fb431cd0e23b8e040d8dafa9d009659da6f679 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 May 2018 10:57:57 +0800 Subject: [PATCH 0672/2457] rtio/sed: pass sequence numbers through the FIFOs. Closes #978 --- artiq/gateware/rtio/sed/fifos.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/rtio/sed/fifos.py b/artiq/gateware/rtio/sed/fifos.py index 0452721f4..cbecccf07 100644 --- a/artiq/gateware/rtio/sed/fifos.py +++ b/artiq/gateware/rtio/sed/fifos.py @@ -32,16 +32,16 @@ class FIFOs(Module): fifos = [] for input, output in zip(self.input, self.output): - fifo = fifo_cls(layout_len(layout_payload), fifo_depth) + fifo = fifo_cls(seqn_width + layout_len(layout_payload), fifo_depth) self.submodules += fifo fifos.append(fifo) self.comb += [ - fifo.din.eq(input.payload.raw_bits()), + fifo.din.eq(Cat(input.seqn, input.payload.raw_bits())), fifo.we.eq(input.we), input.writable.eq(fifo.writable), - output.payload.raw_bits().eq(fifo.dout), + Cat(output.seqn, output.payload.raw_bits()).eq(fifo.dout), output.readable.eq(fifo.readable), fifo.re.eq(output.re) ] From bce8fa3ec50edee238d7ac03a2a8221bf502f915 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 May 2018 10:58:18 +0800 Subject: [PATCH 0673/2457] rtio/sed: add replace unittest at the top level (#978) --- artiq/gateware/test/rtio/test_sed_top.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/test/rtio/test_sed_top.py b/artiq/gateware/test/rtio/test_sed_top.py index d5de88979..d0f14b32e 100644 --- a/artiq/gateware/test/rtio/test_sed_top.py +++ b/artiq/gateware/test/rtio/test_sed_top.py @@ -73,7 +73,7 @@ def simulate(input_events): run_simulation(dut, {"sys": [ gen(), monitor(), - (None for _ in range(45)) + (None for _ in range(max(ts for ts, _ in input_events) + 15)) ]}, {"sys": 5, "rio": 5, "rio_phy": 5}) return ttl_changes, access_results @@ -86,3 +86,16 @@ class TestSED(unittest.TestCase): ttl_changes, access_results = simulate(input_events) self.assertEqual(ttl_changes, [e[0] + latency for e in input_events]) self.assertEqual(access_results, [("ok", 0)]*len(input_events)) + + def test_replace(self): + input_events = [] + now = 19 + for i in range(5): + now += 10 + input_events += [(now, 1)] + now += 10 + input_events += [(now, 1), (now, 0)] + + ttl_changes, access_results = simulate(input_events) + self.assertEqual(ttl_changes, list(range(40, 140, 10))) + self.assertEqual(access_results, [("ok", 0)]*len(input_events)) From 4120105e3a1574a16d5d44009e52a4bd8b6797ef Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 May 2018 12:03:50 +0800 Subject: [PATCH 0674/2457] rtio/sed: fix output network cmp_wrap --- artiq/gateware/rtio/sed/output_network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/sed/output_network.py b/artiq/gateware/rtio/sed/output_network.py index 58e566a29..e37f7f29c 100644 --- a/artiq/gateware/rtio/sed/output_network.py +++ b/artiq/gateware/rtio/sed/output_network.py @@ -45,7 +45,7 @@ def latency(lane_count): def cmp_wrap(a, b): - return Mux(a[-2:] == ~b[-2:], a[0], a[:-2] < b[:-2]) + return Mux((a[-2] == a[-1]) & (b[-2] == b[-1]) & (a[-1] != b[-1]), a[-1], a < b) class OutputNetwork(Module): From 5f0cfadb3089fdb51847ce8e814995de2be4ea37 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 May 2018 12:04:30 +0800 Subject: [PATCH 0675/2457] rtio/sed: add unittest for sequence number rollover --- artiq/gateware/test/rtio/test_sed_top.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/test/rtio/test_sed_top.py b/artiq/gateware/test/rtio/test_sed_top.py index d0f14b32e..fb97caac6 100644 --- a/artiq/gateware/test/rtio/test_sed_top.py +++ b/artiq/gateware/test/rtio/test_sed_top.py @@ -10,7 +10,7 @@ from artiq.gateware.rtio.phy import ttl_simple class DUT(Module): - def __init__(self): + def __init__(self, **kwargs): self.ttl0 = Signal() self.ttl1 = Signal() @@ -22,15 +22,15 @@ class DUT(Module): rtio.Channel.from_phy(self.phy1) ] - self.submodules.sed = SED(rtio_channels, 0, "sync") + self.submodules.sed = SED(rtio_channels, 0, "sync", **kwargs) self.sync += [ self.sed.coarse_timestamp.eq(self.sed.coarse_timestamp + 1), self.sed.minimum_coarse_timestamp.eq(self.sed.coarse_timestamp + 16) ] -def simulate(input_events): - dut = DUT() +def simulate(input_events, **kwargs): + dut = DUT(**kwargs) ttl_changes = [] access_results = [] @@ -97,5 +97,19 @@ class TestSED(unittest.TestCase): input_events += [(now, 1), (now, 0)] ttl_changes, access_results = simulate(input_events) - self.assertEqual(ttl_changes, list(range(40, 140, 10))) self.assertEqual(access_results, [("ok", 0)]*len(input_events)) + self.assertEqual(ttl_changes, list(range(40, 40+5*20, 10))) + + def test_replace_rollover(self): + input_events = [] + now = 24 + for i in range(40): + now += 10 + input_events += [(now, 1)] + now += 10 + input_events += [(now, 1), (now, 0)] + + ttl_changes, access_results = simulate(input_events, + lane_count=2, fifo_depth=2, enable_spread=False) + self.assertEqual([r[0] for r in access_results], ["ok"]*len(input_events)) + self.assertEqual(ttl_changes, list(range(40, 40+40*20, 10))) From 8d66d53e06a70f331b404da928d64d525e0efef0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 May 2018 12:14:56 +0800 Subject: [PATCH 0676/2457] Revert "tools/file_import: restore sys.modules. Closes #976" This reverts commit b48e782dd67282127a6bab96de5166a143e57f29. --- artiq/tools.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/artiq/tools.py b/artiq/tools.py index 679293143..f7a399db7 100644 --- a/artiq/tools.py +++ b/artiq/tools.py @@ -6,7 +6,6 @@ import collections import atexit import string import os -from copy import copy import numpy as np @@ -85,12 +84,8 @@ def file_import(filename, prefix="file_import_"): path = os.path.dirname(os.path.realpath(filename)) sys.path.insert(0, path) try: - previous_modules = copy(sys.modules) - try: - loader = importlib.machinery.SourceFileLoader(modname, filename) - module = loader.load_module() - finally: - sys.modules = previous_modules + loader = importlib.machinery.SourceFileLoader(modname, filename) + module = loader.load_module() finally: sys.path.remove(path) From 8c69d939fb5b4df15546dced9faa128931bf2736 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 May 2018 12:32:35 +0800 Subject: [PATCH 0677/2457] worker: restore sys.modules in examine() (#976) --- artiq/master/worker_impl.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index 3d6153603..4aec04afb 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -4,6 +4,7 @@ import os import logging import traceback from collections import OrderedDict +from copy import copy import h5py @@ -152,7 +153,11 @@ class ExamineDatasetMgr: def examine(device_mgr, dataset_mgr, file): - module = file_import(file) + previous_modules = copy(sys.modules) + try: + module = file_import(file) + finally: + sys.modules = previous_modules for class_name, exp_class in module.__dict__.items(): if class_name[0] == "_": continue From 8079aa6d208c5115823c9c95cebaa1e05b71bede Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 May 2018 12:48:50 +0800 Subject: [PATCH 0678/2457] worker: python docs recommend not replacing sys.modules --- artiq/master/worker_impl.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index 4aec04afb..836ff6050 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -4,7 +4,6 @@ import os import logging import traceback from collections import OrderedDict -from copy import copy import h5py @@ -153,11 +152,13 @@ class ExamineDatasetMgr: def examine(device_mgr, dataset_mgr, file): - previous_modules = copy(sys.modules) + previous_keys = set(sys.modules.keys()) try: module = file_import(file) finally: - sys.modules = previous_modules + new_keys = set(sys.modules.keys()) + for key in new_keys - previous_keys: + del sys.modules[key] for class_name, exp_class in module.__dict__.items(): if class_name[0] == "_": continue From 0b4d06c7a9d749a333c9b5d1e8ce102ce5da3050 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 May 2018 12:50:37 +0800 Subject: [PATCH 0679/2457] worker: keep sys.modules untouched until the end of examine() --- artiq/master/worker_impl.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index 836ff6050..a3db42d1a 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -155,26 +155,26 @@ def examine(device_mgr, dataset_mgr, file): previous_keys = set(sys.modules.keys()) try: module = file_import(file) + for class_name, exp_class in module.__dict__.items(): + if class_name[0] == "_": + continue + if is_experiment(exp_class): + if exp_class.__doc__ is None: + name = class_name + else: + name = exp_class.__doc__.splitlines()[0].strip() + if name[-1] == ".": + name = name[:-1] + argument_mgr = TraceArgumentManager() + exp_class((device_mgr, dataset_mgr, argument_mgr)) + arginfo = OrderedDict( + (k, (proc.describe(), group, tooltip)) + for k, (proc, group, tooltip) in argument_mgr.requested_args.items()) + register_experiment(class_name, name, arginfo) finally: new_keys = set(sys.modules.keys()) for key in new_keys - previous_keys: del sys.modules[key] - for class_name, exp_class in module.__dict__.items(): - if class_name[0] == "_": - continue - if is_experiment(exp_class): - if exp_class.__doc__ is None: - name = class_name - else: - name = exp_class.__doc__.splitlines()[0].strip() - if name[-1] == ".": - name = name[:-1] - argument_mgr = TraceArgumentManager() - exp_class((device_mgr, dataset_mgr, argument_mgr)) - arginfo = OrderedDict( - (k, (proc.describe(), group, tooltip)) - for k, (proc, group, tooltip) in argument_mgr.requested_args.items()) - register_experiment(class_name, name, arginfo) def setup_diagnostics(experiment_file, repository_path): From 9857dfcd7dbe93901c38f5c517d5e561ea98cae4 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 4 May 2018 18:26:12 +0000 Subject: [PATCH 0680/2457] firmware: add irq::Exception to libboard. --- artiq/firmware/libboard/lib.rs | 2 +- artiq/firmware/libboard/or1k/irq.rs | 84 ++++++++++++++++++++++++++++- artiq/firmware/libboard/or1k/spr.rs | 2 + 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard/lib.rs b/artiq/firmware/libboard/lib.rs index a685f5252..369a38d8c 100644 --- a/artiq/firmware/libboard/lib.rs +++ b/artiq/firmware/libboard/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(compiler_builtins_lib, asm)] +#![feature(compiler_builtins_lib, asm, try_from)] extern crate compiler_builtins; extern crate byteorder; diff --git a/artiq/firmware/libboard/or1k/irq.rs b/artiq/firmware/libboard/or1k/irq.rs index ad9c917b9..bc745ae02 100644 --- a/artiq/firmware/libboard/or1k/irq.rs +++ b/artiq/firmware/libboard/or1k/irq.rs @@ -1,9 +1,76 @@ +use core::{fmt, convert}; + use super::spr::*; +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub enum Exception { + Reset = 0x1, + BusError = 0x2, + DataPageFault = 0x3, + InsnPageFault = 0x4, + Tick = 0x5, + Alignment = 0x6, + IllegalInsn = 0x7, + Interrupt = 0x8, + DtlbMiss = 0x9, + ItlbMiss = 0xa, + Range = 0xb, + Syscall = 0xc, + FloatingPoint = 0xd, + Trap = 0xe, +} + +impl fmt::Display for Exception { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Exception::Reset => write!(f, "reset"), + Exception::BusError => write!(f, "bus error"), + Exception::DataPageFault => write!(f, "data page fault"), + Exception::InsnPageFault => write!(f, "instruction page fault"), + Exception::Tick => write!(f, "tick"), + Exception::Alignment => write!(f, "alignment"), + Exception::IllegalInsn => write!(f, "illegal instruction"), + Exception::Interrupt => write!(f, "interrupt"), + Exception::DtlbMiss => write!(f, "D-TLB miss"), + Exception::ItlbMiss => write!(f, "I-TLB miss"), + Exception::Range => write!(f, "range"), + Exception::Syscall => write!(f, "system call"), + Exception::FloatingPoint => write!(f, "floating point"), + Exception::Trap => write!(f, "trap"), + } + } +} + +impl convert::TryFrom for Exception { + type Error = (); + + fn try_from(num: u32) -> Result { + match num { + 0x1 => Ok(Exception::Reset), + 0x2 => Ok(Exception::BusError), + 0x3 => Ok(Exception::DataPageFault), + 0x4 => Ok(Exception::InsnPageFault), + 0x5 => Ok(Exception::Tick), + 0x6 => Ok(Exception::Alignment), + 0x7 => Ok(Exception::IllegalInsn), + 0x8 => Ok(Exception::Interrupt), + 0x9 => Ok(Exception::DtlbMiss), + 0xa => Ok(Exception::ItlbMiss), + 0xb => Ok(Exception::Range), + 0xc => Ok(Exception::Syscall), + 0xd => Ok(Exception::FloatingPoint), + 0xe => Ok(Exception::Trap), + _ => Err(()) + } + } +} + +#[inline] pub fn get_ie() -> bool { unsafe { mfspr(SPR_SR) & SPR_SR_IEE != 0 } } +#[inline] pub fn set_ie(ie: bool) { if ie { unsafe { mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_IEE) } @@ -12,14 +79,29 @@ pub fn set_ie(ie: bool) { } } +#[inline] pub fn get_mask() -> u32 { unsafe { mfspr(SPR_PICMR) } } +#[inline] pub fn set_mask(mask: u32) { unsafe { mtspr(SPR_PICMR, mask) } } -pub fn pending() -> u32 { +#[inline] +pub fn pending_mask() -> u32 { unsafe { mfspr(SPR_PICSR) } } + +pub fn enable(irq: u32) { + set_mask(get_mask() | (1 << irq)) +} + +pub fn disable(irq: u32) { + set_mask(get_mask() & !(1 << irq)) +} + +pub fn is_pending(irq: u32) -> bool { + get_mask() & (1 << irq) != 0 +} diff --git a/artiq/firmware/libboard/or1k/spr.rs b/artiq/firmware/libboard/or1k/spr.rs index 8f011a564..14bb5ae3d 100644 --- a/artiq/firmware/libboard/or1k/spr.rs +++ b/artiq/firmware/libboard/or1k/spr.rs @@ -1,9 +1,11 @@ +#[inline(always)] pub unsafe fn mfspr(reg: u32) -> u32 { let value: u32; asm!("l.mfspr $0, $1, 0" : "=r"(value) : "r"(reg) : : "volatile"); value } +#[inline(always)] pub unsafe fn mtspr(reg: u32, value: u32) { asm!("l.mtspr $0, $1, 0" : : "r"(reg), "r"(value) : : "volatile") } From b1d349cc1ba5bb2875ed54576dee3b2656b94e5f Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 4 May 2018 23:44:51 +0000 Subject: [PATCH 0681/2457] firmware: implement a sampling profiler. Does not yet support constructing call graphs. --- .gitignore | 1 + artiq/coredevice/comm_mgmt.py | 41 +++++ artiq/firmware/Cargo.lock | 7 + artiq/firmware/libproto/mgmt_proto.rs | 33 +++- artiq/firmware/runtime/Cargo.toml | 1 + artiq/firmware/runtime/main.rs | 21 ++- artiq/firmware/runtime/mgmt.rs | 59 ++++++- artiq/firmware/runtime/profiler.rs | 242 ++++++++++++++++++++++++++ artiq/frontend/artiq_coreprofile.py | 155 +++++++++++++++++ artiq/gateware/targets/kc705.py | 6 +- setup.py | 1 + 11 files changed, 554 insertions(+), 13 deletions(-) create mode 100644 artiq/firmware/runtime/profiler.rs create mode 100755 artiq/frontend/artiq_coreprofile.py diff --git a/.gitignore b/.gitignore index 0fc39b517..77178c15e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ __pycache__/ *.elf *.fbi *.pcap +*.prof .ipynb_checkpoints /doc/manual/_build /build diff --git a/artiq/coredevice/comm_mgmt.py b/artiq/coredevice/comm_mgmt.py index f0b7d009a..98ad07e2b 100644 --- a/artiq/coredevice/comm_mgmt.py +++ b/artiq/coredevice/comm_mgmt.py @@ -14,6 +14,10 @@ class Request(Enum): SetLogFilter = 3 SetUartLogFilter = 6 + StartProfiler = 9 + StopProfiler = 10 + GetProfile = 11 + Hotswap = 4 Reboot = 5 @@ -22,9 +26,12 @@ class Request(Enum): class Reply(Enum): Success = 1 + Unavailable = 4 LogContent = 2 + Profile = 5 + RebootImminent = 3 @@ -145,6 +152,40 @@ class CommMgmt: self._write_int8(getattr(LogLevel, level).value) self._read_expect(Reply.Success) + def start_profiler(self, interval, edges_size, hits_size): + self._write_header(Request.StartProfiler) + self._write_int32(interval) + self._write_int32(edges_size) + self._write_int32(hits_size) + self._read_expect(Reply.Success) + + def stop_profiler(self): + self._write_header(Request.StopProfiler) + self._read_expect(Reply.Success) + + def stop_profiler(self): + self._write_header(Request.StopProfiler) + self._read_expect(Reply.Success) + + def get_profile(self): + self._write_header(Request.GetProfile) + self._read_expect(Reply.Profile) + + hits = {} + for _ in range(self._read_int32()): + addr = self._read_int32() + count = self._read_int32() + hits[addr] = count + + edges = {} + for _ in range(self._read_int32()): + caller = self._read_int32() + callee = self._read_int32() + count = self._read_int32() + edges[(caller, callee)] = count + + return hits, edges + def hotswap(self, firmware): self._write_header(Request.Hotswap) self._write_bytes(firmware) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 7543617be..b2413039e 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -193,6 +193,11 @@ name = "managed" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "managed" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "proto" version = "0.0.0" @@ -221,6 +226,7 @@ dependencies = [ "fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "logger_artiq 0.0.0", + "managed 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "proto 0.0.0", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", "std_artiq 0.0.0", @@ -300,6 +306,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" "checksum managed 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43e2737ecabe4ae36a68061398bf27d2bfd0763f4c3c837a398478459494c4b7" +"checksum managed 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5a31885241e61ba264d780d2e6686e7e59561c947b4581470364eb3e10102d86" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)" = "" "checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" diff --git a/artiq/firmware/libproto/mgmt_proto.rs b/artiq/firmware/libproto/mgmt_proto.rs index c96ad27c5..8ac1a95ec 100644 --- a/artiq/firmware/libproto/mgmt_proto.rs +++ b/artiq/firmware/libproto/mgmt_proto.rs @@ -14,6 +14,14 @@ pub enum Request { #[cfg(feature = "log")] SetUartLogFilter(log::LevelFilter), + StartProfiler { + interval_us: u32, + hits_size: u32, + edges_size: u32, + }, + StopProfiler, + GetProfile, + Hotswap(Vec), Reboot, @@ -22,9 +30,12 @@ pub enum Request { pub enum Reply<'a> { Success, + Unavailable, LogContent(&'a str), + Profile, + RebootImminent, } @@ -52,6 +63,13 @@ impl Request { 3 => Request::SetLogFilter(read_log_level_filter(reader)?), #[cfg(feature = "log")] 6 => Request::SetUartLogFilter(read_log_level_filter(reader)?), + 9 => Request::StartProfiler { + interval_us: reader.read_u32()?, + hits_size: reader.read_u32()?, + edges_size: reader.read_u32()?, + }, + 10 => Request::StopProfiler, + 11 => Request::GetProfile, 4 => Request::Hotswap(reader.read_bytes()?), 5 => Request::Reboot, 8 => Request::DebugAllocator, @@ -65,16 +83,25 @@ impl<'a> Reply<'a> { match *self { Reply::Success => { writer.write_u8(1)?; - }, + } + + Reply::Unavailable => { + writer.write_u8(4)?; + } Reply::LogContent(ref log) => { writer.write_u8(2)?; writer.write_string(log)?; - }, + } + + Reply::Profile => { + writer.write_u8(5)?; + // profile data follows + } Reply::RebootImminent => { writer.write_u8(3)?; - }, + } } Ok(()) } diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index e76add67b..899bb424b 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -17,6 +17,7 @@ build_artiq = { path = "../libbuild_artiq" } byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } log = { version = "0.4", default-features = false } +managed = { version = "0.6", default-features = false, features = ["alloc", "map"] } board = { path = "../libboard", features = ["uart_console", "smoltcp"] } alloc_list = { path = "../liballoc_list" } std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 4aa9a5cf1..865cd76a2 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(lang_items, alloc, global_allocator)] +#![feature(lang_items, alloc, global_allocator, try_from, nonzero, nll)] extern crate alloc; extern crate cslice; @@ -7,6 +7,7 @@ extern crate cslice; extern crate log; extern crate byteorder; extern crate fringe; +extern crate managed; extern crate smoltcp; extern crate alloc_list; @@ -22,8 +23,10 @@ extern crate amp; #[cfg(has_drtio)] extern crate drtioaux; +use core::convert::TryFrom; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; +use board::irq; use board::config; #[cfg(has_ethmac)] use board::ethmac; @@ -39,6 +42,7 @@ mod cache; mod rtio_dma; mod mgmt; +mod profiler; mod kernel; mod kern_hwreq; mod watchdog; @@ -49,6 +53,7 @@ mod moninj; mod analyzer; fn startup() { + irq::set_ie(true); board::clock::init(); info!("ARTIQ runtime starting..."); info!("software version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); @@ -271,7 +276,19 @@ pub extern fn main() -> i32 { #[no_mangle] pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { - panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea) + let vect = irq::Exception::try_from(vect).expect("unknown exception"); + match vect { + irq::Exception::Interrupt => + while irq::pending_mask() != 0 { + match () { + #[cfg(has_timer1)] + () if irq::is_pending(::board::csr::TIMER1_INTERRUPT) => + profiler::sample(pc as usize), + _ => panic!("spurious irq {}", irq::pending_mask().trailing_zeros()) + } + }, + _ => panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea) + } } #[no_mangle] diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 4db85de70..70c64be70 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -6,6 +6,7 @@ use sched::Io; use sched::{TcpListener, TcpStream}; use proto::WriteExt; use mgmt_proto::*; +use profiler; fn check_magic(stream: &mut TcpStream) -> io::Result<()> { const MAGIC: &'static [u8] = b"ARTIQ management\n"; @@ -30,7 +31,7 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> { let mut buffer = io.until_ok(|| logger.buffer())?; Reply::LogContent(buffer.extract()).write_to(stream) })?; - }, + } Request::ClearLog => { BufferLogger::with(|logger| -> io::Result<()> { @@ -39,7 +40,7 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> { })?; Reply::Success.write_to(stream)?; - }, + } Request::PullLog => { BufferLogger::with(|logger| -> io::Result<()> { @@ -69,35 +70,79 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> { buffer.clear(); } })?; - }, + } Request::SetLogFilter(level) => { info!("changing log level to {}", level); log::set_max_level(level); Reply::Success.write_to(stream)?; - }, + } Request::SetUartLogFilter(level) => { info!("changing UART log level to {}", level); BufferLogger::with(|logger| logger.set_uart_log_level(level)); Reply::Success.write_to(stream)?; - }, + } + + Request::StartProfiler { interval_us, hits_size, edges_size } => { + match profiler::start(interval_us as u64, + hits_size as usize, edges_size as usize) { + Ok(()) => Reply::Success.write_to(stream)?, + Err(()) => Reply::Unavailable.write_to(stream)? + } + } + + Request::StopProfiler => { + profiler::stop(); + Reply::Success.write_to(stream)?; + } + + Request::GetProfile => { + profiler::pause(|profile| { + let profile = match profile { + None => return Reply::Unavailable.write_to(stream), + Some(profile) => profile + }; + + Reply::Profile.write_to(stream)?; + { + let hits = profile.hits(); + stream.write_u32(hits.len() as u32)?; + for (&addr, &count) in hits.iter() { + stream.write_u32(addr.as_raw() as u32)?; + stream.write_u32(count)?; + } + } + { + let edges = profile.edges(); + stream.write_u32(edges.len() as u32)?; + for (&(caller, callee), &count) in edges.iter() { + stream.write_u32(caller.as_raw() as u32)?; + stream.write_u32(callee.as_raw() as u32)?; + stream.write_u32(count)?; + } + } + + Ok(()) + })?; + } Request::Hotswap(firmware) => { + profiler::stop(); warn!("hotswapping firmware"); Reply::RebootImminent.write_to(stream)?; stream.close()?; stream.flush()?; unsafe { boot::hotswap(&firmware) } - }, + } Request::Reboot => { Reply::RebootImminent.write_to(stream)?; stream.close()?; warn!("restarting"); unsafe { boot::reset() } - }, + } Request::DebugAllocator => unsafe { println!("{}", ::ALLOC) }, diff --git a/artiq/firmware/runtime/profiler.rs b/artiq/firmware/runtime/profiler.rs new file mode 100644 index 000000000..db830198c --- /dev/null +++ b/artiq/firmware/runtime/profiler.rs @@ -0,0 +1,242 @@ +#![cfg_attr(not(has_timer1), allow(dead_code))] + +use core::mem; +use core::fmt; +use core::nonzero::NonZero; +use alloc::Vec; +use managed::ManagedMap; + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Address(NonZero); + +impl Address { + pub fn new(raw: usize) -> Option
{ + NonZero::new(raw).map(Address) + } + + pub fn as_raw(&self) -> usize { + self.0.get() + } +} + +pub struct Profile { + hits: Vec>, + edges: Vec>, +} + +impl fmt::Debug for Profile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Profile {{ hits: vec![...; {}], edges: vec![...; {}] }}", + self.hits.len(), self.edges.len()) + } +} + +impl Profile { + pub fn new(hits_size: usize, edges_size: usize) -> Profile { + let mut hits = vec![None; hits_size]; + hits.shrink_to_fit(); + let mut edges = vec![None; edges_size]; + edges.shrink_to_fit(); + Profile { + hits: hits.into(), + edges: edges.into(), + } + } + + pub fn overhead(&self) -> usize { + let hit_size = mem::size_of::>(); + let edge_size = mem::size_of::>(); + self.hits.capacity() * hit_size + + self.edges.capacity() * edge_size + } + + pub fn hits<'a>(&'a mut self) -> ManagedMap<'a, Address, u32> { + ManagedMap::Borrowed(&mut self.hits[..]) + } + + pub fn edges<'a>(&'a mut self) -> ManagedMap<'a, (Address, Address), u32> { + ManagedMap::Borrowed(&mut self.edges[..]) + } + + pub fn record_hit(&mut self, addr: Address) -> Result<(), ()> { + let mut hits = self.hits(); + match hits.get_mut(&addr) { + Some(count) => *count = count.saturating_add(1), + None => { + if let Err(_) = hits.insert(addr, 1) { + return Err(()) + } + } + } + Ok(()) + } + + #[allow(dead_code)] + pub fn record_edge(&mut self, caller: Address, callee: Address) -> Result<(), ()> { + let mut edges = self.edges(); + match edges.get_mut(&(caller, callee)) { + Some(count) => *count = count.saturating_add(1), + None => { + if let Err(_) = edges.insert((caller, callee), 1) { + return Err(()) + } + } + } + Ok(()) + } +} + +#[cfg(has_timer1)] +mod imp { + use board::{csr, irq}; + use super::{Address, Profile}; + + static mut PROFILE: Option = None; + + mod lock { + use core::ops::{Deref, DerefMut}; + use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; + + static LOCKED: AtomicUsize = ATOMIC_USIZE_INIT; + + pub struct Lock; + + impl Lock { + pub fn take() -> Result { + if LOCKED.swap(1, Ordering::SeqCst) != 0 { + Err(()) + } else { + Ok(Lock) + } + } + } + + impl Deref for Lock { + type Target = Option; + + fn deref(&self) -> &Option { + unsafe { &super::PROFILE } + } + } + + impl DerefMut for Lock { + fn deref_mut(&mut self) -> &mut Option { + unsafe { &mut super::PROFILE } + } + } + + impl Drop for Lock { + fn drop(&mut self) { + LOCKED.store(0, Ordering::SeqCst) + } + } + } + + use self::lock::Lock; + + pub fn start(interval_us: u64, hits_size: usize, edges_size: usize) -> Result<(), ()> { + stop(); + + let profile = Profile::new(hits_size, edges_size); + info!("starting at {}us interval using {} heap bytes", + interval_us, profile.overhead()); + + *Lock::take().expect("cannot lock") = Some(profile); + + unsafe { + let reload = csr::CONFIG_CLOCK_FREQUENCY as u64 * interval_us / 1_000_000; + csr::timer1::load_write(reload); + csr::timer1::reload_write(reload); + csr::timer1::ev_pending_write(1); + csr::timer1::ev_enable_write(1); + irq::enable(csr::TIMER1_INTERRUPT); + csr::timer1::en_write(1); + } + + Ok(()) + } + + pub fn stop() { + unsafe { + if csr::timer1::en_read() == 0 || csr::timer1::ev_enable_read() == 0 { + return + } + + irq::disable(csr::TIMER1_INTERRUPT); + csr::timer1::en_write(0); + + *Lock::take().expect("cannot lock") = None; + + info!("stopped"); + } + } + + pub fn pause) -> R, R>(f: F) -> R { + unsafe { + if csr::timer1::en_read() == 0 { + return f(None) + } + + irq::disable(csr::TIMER1_INTERRUPT); + csr::timer1::en_write(0); + + let result = { + let mut profile = Lock::take().expect("cannot lock"); + f(profile.as_mut()) + }; + + irq::enable(csr::TIMER1_INTERRUPT); + csr::timer1::en_write(1); + + result + } + } + + #[inline(always)] // make the top of backtrace predictable + fn record(profile: &mut Profile, pc: usize) -> Result<(), ()> { + let callee = Address::new(pc).expect("null code address"); + profile.record_hit(callee)?; + + // TODO: record edges + + Ok(()) + } + + #[inline(never)] // see above + pub fn sample(pc: usize) { + unsafe { + csr::timer1::ev_pending_write(1); + } + + let result = { + let mut profile = Lock::take().expect("cannot lock"); + record(profile.as_mut().expect("profiler not running"), pc) + }; + + if result.is_err() { + warn!("out of space"); + stop(); + } + } +} + +#[cfg(not(has_timer1))] +mod imp { + #![allow(dead_code)] + + pub fn start(_interval_us: u64, _hits_size: usize, _edges_size: usize) -> Result<(), ()> { + error!("timer not available"); + + Err(()) + } + + pub fn stop() {} + + pub fn pause) -> R, R>(f: F) -> R { + f(None) + } + + pub fn sample(_pc: usize) {} +} + +pub use self::imp::*; diff --git a/artiq/frontend/artiq_coreprofile.py b/artiq/frontend/artiq_coreprofile.py new file mode 100755 index 000000000..a5873c1ec --- /dev/null +++ b/artiq/frontend/artiq_coreprofile.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 + +import argparse +import sys +import struct +from collections import defaultdict +import subprocess + +from artiq.tools import verbosity_args, init_logger +from artiq.master.databases import DeviceDB +from artiq.coredevice.comm_mgmt import CommMgmt + + +class Symbolizer: + def __init__(self, binary): + self._addr2line = subprocess.Popen([ + "or1k-linux-addr2line", "--exe=" + binary, + "--addresses", "--demangle=rust", "--functions", "--inlines" + ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True) + + def symbolize(self, addr): + self._addr2line.stdin.write("0x{:08x}\n0\n".format(addr)) + self._addr2line.stdin.flush() + self._addr2line.stdout.readline() # 0x[addr] + + result = [] + while True: + function = self._addr2line.stdout.readline().rstrip() + + # check for end marker + if function == "0x00000000": # 0x00000000 + self._addr2line.stdout.readline() # ?? + self._addr2line.stdout.readline() # ??:0 + return result + + file, line = self._addr2line.stdout.readline().rstrip().split(":") + + result.append((function, file, line)) + + +class CallgrindWriter: + def __init__(self, output, binary, compression=True): + self._output = output + self._binary = binary + self._current = defaultdict(lambda: None) + self._ids = defaultdict(lambda: {}) + self._compression = compression + self._symbolizer = Symbolizer(binary) + + def _write(self, fmt, *args, **kwargs): + self._output.write(fmt.format(*args, **kwargs)) + self._output.write("\n") + + def _spec(self, spec, value): + if self._current[spec] == value: + return + self._current[spec] = value + + if not self._compression or value == "??": + self._write("{}={}", spec, value) + return + + spec_ids = self._ids[spec] + if value in spec_ids: + self._write("{}=({})", spec, spec_ids[value]) + else: + spec_ids[value] = len(spec_ids) + 1 + self._write("{}=({}) {}", spec, spec_ids[value], value) + + def header(self): + self._write("# callgrind format") + self._write("version: 1") + self._write("creator: ARTIQ") + self._write("positions: instr line") + self._write("events: Hits") + self._write("") + self._spec("ob", self._binary) + self._spec("cob", self._binary) + + def hit(self, addr, count): + for function, file, line in self._symbolizer.symbolize(addr): + self._spec("fn", function) + self._spec("fl", file) + self._write("0x{:08x} {} {}", addr, line, count) + + def edge(self, caller, callee, count): + function, file, line = next(self._symbolizer.symbolize(callee)) + self._spec("cfn", function) + self._spec("cfl", file) + self._write("calls={} 0x{:08x} {}", count, callee, line) + + function, file, line = next(self._symbolizer.symbolize(caller)) + self._spec("fn", function) + self._spec("fl", file) + self._write("0x{:08x} {} {}", caller, line, count) + + +def get_argparser(): + parser = argparse.ArgumentParser(description="ARTIQ core device profiling tool") + + verbosity_args(parser) + parser.add_argument("--device-db", default="device_db.py", + help="device database file (default: '%(default)s')") + + subparsers = parser.add_subparsers(dest="action") + subparsers.required = True + + p_start = subparsers.add_parser("start", + help="start profiling") + p_start.add_argument("--interval", metavar="MICROS", type=int, default=2000, + help="sampling interval, in microseconds") + p_start.add_argument("--hits-size", metavar="ENTRIES", type=int, default=8192, + help="hit buffer size") + p_start.add_argument("--edges-size", metavar="ENTRIES", type=int, default=0, + help="edge buffer size (edge profiling not implemented)") + + p_stop = subparsers.add_parser("stop", + help="stop profiling") + + p_save = subparsers.add_parser("save", + help="save profile") + p_save.add_argument("output", metavar="OUTPUT", type=argparse.FileType("w"), + help="file to save profile to, in Callgrind format") + p_save.add_argument("firmware", metavar="FIRMWARE", type=str, + help="path to firmware ELF file") + p_save.add_argument("--no-compression", default=True, action='store_false', + help="disable profile compression") + + return parser + + +def main(): + args = get_argparser().parse_args() + init_logger(args) + + core_addr = DeviceDB(args.device_db).get("core")["arguments"]["host"] + mgmt = CommMgmt(core_addr) + try: + if args.action == "start": + mgmt.start_profiler(args.interval, args.hits_size, args.edges_size) + elif args.action == "stop": + mgmt.stop_profiler() + elif args.action == "save": + hits, edges = mgmt.get_profile() + writer = CallgrindWriter(args.output, args.firmware, not args.no_compression) + writer.header() + for addr, count in hits.items(): + writer.hit(addr, count) + for (caller, callee), count in edges.items(): + writer.edge(caller, callee, count) + finally: + mgmt.close() + +if __name__ == "__main__": + main() diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index f29828415..a3eea1949 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -10,7 +10,7 @@ from migen.build.xilinx.vivado import XilinxVivadoToolchain from migen.build.xilinx.ise import XilinxISEToolchain from misoc.interconnect.csr import * -from misoc.cores import gpio +from misoc.cores import gpio, timer from misoc.targets.kc705 import MiniSoC, soc_kc705_args, soc_kc705_argdict from misoc.integration.builder import builder_args, builder_argdict @@ -231,6 +231,10 @@ class _StandaloneBase(MiniSoC, AMPSoC): if isinstance(self.platform.toolchain, XilinxISEToolchain): self.platform.toolchain.bitgen_opt += " -g compress" + self.submodules.timer1 = timer.Timer() + self.csr_devices.append("timer1") + self.interrupt_devices.append("timer1") + self.submodules.leds = gpio.GPIOOut(Cat( self.platform.request("user_led", 0), self.platform.request("user_led", 1))) diff --git a/setup.py b/setup.py index ac7e9d7e9..8806a4f65 100755 --- a/setup.py +++ b/setup.py @@ -26,6 +26,7 @@ console_scripts = [ "artiq_corelog = artiq.frontend.artiq_corelog:main", "artiq_coreboot = artiq.frontend.artiq_coreboot:main", "artiq_coredebug = artiq.frontend.artiq_coredebug:main", + "artiq_coreprofile = artiq.frontend.artiq_coreprofile:main", "artiq_ctlmgr = artiq.frontend.artiq_ctlmgr:main", "artiq_devtool = artiq.frontend.artiq_devtool:main", "artiq_pcap = artiq.frontend.artiq_pcap:main", From 5ebc626cf4be2d17bc1ca55f752ef93dfef689f0 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 5 May 2018 00:49:42 +0000 Subject: [PATCH 0682/2457] artiq_coreprofile: fix an inverted option. --- artiq/frontend/artiq_coreprofile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_coreprofile.py b/artiq/frontend/artiq_coreprofile.py index a5873c1ec..5b300e911 100755 --- a/artiq/frontend/artiq_coreprofile.py +++ b/artiq/frontend/artiq_coreprofile.py @@ -123,7 +123,7 @@ def get_argparser(): help="file to save profile to, in Callgrind format") p_save.add_argument("firmware", metavar="FIRMWARE", type=str, help="path to firmware ELF file") - p_save.add_argument("--no-compression", default=True, action='store_false', + p_save.add_argument("--no-compression", default=False, action='store_true', help="disable profile compression") return parser From 4f29d9134fe1c66769799ed2da4e5014d6b9c759 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 5 May 2018 01:18:59 +0000 Subject: [PATCH 0683/2457] firmware: update log_buffer. Fixes #986. --- artiq/firmware/Cargo.lock | 8 ++++---- artiq/firmware/liblogger_artiq/Cargo.toml | 2 +- artiq/firmware/liblogger_artiq/lib.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index b2413039e..0d9aedad3 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -176,8 +176,8 @@ dependencies = [ [[package]] name = "log_buffer" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "1.2.0" +source = "git+https://github.com/whitequark/rust-log_buffer?rev=rust-1.25#ff84e565d9954d5864d60aec12b9e1381505d72a" [[package]] name = "logger_artiq" @@ -185,7 +185,7 @@ version = "0.0.0" dependencies = [ "board 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log_buffer 1.2.0 (git+https://github.com/whitequark/rust-log_buffer?rev=rust-1.25)", ] [[package]] @@ -304,7 +304,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" -"checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" +"checksum log_buffer 1.2.0 (git+https://github.com/whitequark/rust-log_buffer?rev=rust-1.25)" = "" "checksum managed 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43e2737ecabe4ae36a68061398bf27d2bfd0763f4c3c837a398478459494c4b7" "checksum managed 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5a31885241e61ba264d780d2e6686e7e59561c947b4581470364eb3e10102d86" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" diff --git a/artiq/firmware/liblogger_artiq/Cargo.toml b/artiq/firmware/liblogger_artiq/Cargo.toml index 2cf792723..822cae637 100644 --- a/artiq/firmware/liblogger_artiq/Cargo.toml +++ b/artiq/firmware/liblogger_artiq/Cargo.toml @@ -9,5 +9,5 @@ path = "lib.rs" [dependencies] log = { version = "0.4", default-features = false } -log_buffer = { version = "1.0" } +log_buffer = { version = "1.2", git = "https://github.com/whitequark/rust-log_buffer", rev = "rust-1.25" } board = { path = "../libboard" } diff --git a/artiq/firmware/liblogger_artiq/lib.rs b/artiq/firmware/liblogger_artiq/lib.rs index 8ccfdc6fb..fd6228978 100644 --- a/artiq/firmware/liblogger_artiq/lib.rs +++ b/artiq/firmware/liblogger_artiq/lib.rs @@ -23,8 +23,8 @@ impl<'a> LogBufferRef<'a> { LogBufferRef { buffer, old_log_level } } - pub fn is_empty(&mut self) -> bool { - self.buffer.extract().len() == 0 + pub fn is_empty(&self) -> bool { + self.buffer.is_empty() } pub fn clear(&mut self) { From 9dc7efefe4e8cb7690fc9f1ad9b1c82d088d7f19 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 5 May 2018 01:43:00 +0000 Subject: [PATCH 0684/2457] compiler: transparently handle Windows newlines in RunTool. --- artiq/compiler/targets.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index f2c7c408b..22c1e9a2b 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -28,7 +28,8 @@ class RunTool: for argument in self._pattern: cmdline.append(argument.format(**self._tempnames)) - process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + universal_newlines=True) stdout, stderr = process.communicate() if process.returncode != 0: raise Exception("{} invocation failed: {}". From 68ef09ed73aa9bea058178d5488b5ffdc48bcd74 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 5 May 2018 01:52:44 +0000 Subject: [PATCH 0685/2457] firmware: stop profiler before rebooting too. --- artiq/firmware/runtime/mgmt.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 70c64be70..3c14e776e 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -129,17 +129,21 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> { } Request::Hotswap(firmware) => { - profiler::stop(); - warn!("hotswapping firmware"); Reply::RebootImminent.write_to(stream)?; stream.close()?; stream.flush()?; + + profiler::stop(); + warn!("hotswapping firmware"); unsafe { boot::hotswap(&firmware) } } Request::Reboot => { Reply::RebootImminent.write_to(stream)?; stream.close()?; + stream.flush()?; + + profiler::stop(); warn!("restarting"); unsafe { boot::reset() } } From 8a70c18d1e1444c509710aacfc4dfceb371d3c6a Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 5 May 2018 01:53:30 +0000 Subject: [PATCH 0686/2457] firmware: add debug output to hmc542 driver. --- artiq/firmware/libboard_artiq/hmc542.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/hmc542.rs b/artiq/firmware/libboard_artiq/hmc542.rs index 70cd8af54..52490cdd3 100644 --- a/artiq/firmware/libboard_artiq/hmc542.rs +++ b/artiq/firmware/libboard_artiq/hmc542.rs @@ -21,7 +21,7 @@ fn set_pins(card_index: usize, chan_index: usize, pins: u32) { clock::spin_us(100); } -/// Attenuation is in units of 0.5dB, from 0dB (0) to 31.5dB (63). +/// Attenuation is in units of 0.5 dB, from 0 dB (0) to 31.5 dB (63). pub fn program(card_index: usize, chan_index: usize, atten: u8) { assert!(card_index < 4 && chan_index < 2); @@ -42,6 +42,10 @@ pub fn program(card_index: usize, chan_index: usize, atten: u8) { set_pins(sin | PIN_CLK); } set_pins(PIN_LE); + + debug!("card {} channel {} set to {}{} dB", + card_index, chan_index, + atten / 2, if atten % 2 != 0 { ".5" } else { "" }); } /// See `program`. From 9704fb837fec236d70c8fda752d60962d0ee24fe Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 5 May 2018 01:55:42 +0000 Subject: [PATCH 0687/2457] firmware: fix warnings in ad9154 driver. --- artiq/firmware/libboard_artiq/ad9154.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 48f4cdcc1..ee8c7f80c 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -609,27 +609,25 @@ fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { } fn dac_sysref_cfg(dacno: u8) { - let mut sync_error: u16 = 0; - let mut sync_error_last: u16 = 0; - let mut phase_min_found: bool = false; - let mut phase_min: u16 = 0; - let mut phase_max_found: bool = false; - let mut phase_max: u16 = 0; - let mut phase_opt: u16 = 0; + let mut sync_error_last = 0u16; + let mut phase_min_found = false; + let mut phase_min = 0u16; + let mut _phase_max_found = false; + let mut phase_max = 0u16; info!("AD9154-{} SYSREF scan/conf...", dacno); for phase in 0..512 { hmc7043::cfg_dac_sysref(dacno, phase); clock::spin_us(10000); spi_setup(dacno); - sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) | - ((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8)) - & 0x1ff; + let sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) | + ((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8)) + & 0x1ff; info!(" phase: {}, sync error: {}", phase, sync_error); if sync_error != 0 { if phase_min_found { if sync_error != sync_error_last { - phase_max_found = true; + _phase_max_found = true; phase_max = phase - 1; break; } @@ -641,7 +639,7 @@ fn dac_sysref_cfg(dacno: u8) { sync_error_last = sync_error; } - phase_opt = phase_min + (phase_max-phase_min)/2; + let phase_opt = phase_min + (phase_max-phase_min)/2; info!(" phase min: {}, phase max: {}, phase opt: {}", phase_min, phase_max, phase_opt); hmc7043::cfg_dac_sysref(dacno, phase_opt); } From a148729bf87b0ab62af9392137cd45b77e78af80 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 5 May 2018 02:50:01 +0000 Subject: [PATCH 0688/2457] artiq_flash, artiq_devtool: add support for ssh -J option. --- artiq/frontend/artiq_devtool.py | 9 +++++++-- artiq/frontend/artiq_flash.py | 5 ++++- artiq/remoting.py | 14 ++++++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index a17c29b26..3ab31e776 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -46,6 +46,9 @@ def get_argparser(): parser.add_argument("-H", "--host", type=str, default="lab.m-labs.hk", help="SSH host where the development board is located") + parser.add_argument("-J", "--jump", + type=str, default=None, + help="SSH host to jump through") parser.add_argument("-b", "--board", type=str, default="{board_type}-1", help="board to connect to on the development SSH host") @@ -57,7 +60,7 @@ def get_argparser(): type=str, default="/dev/ttyUSB_{board}", help="TTY device corresponding to the development board") parser.add_argument("-d", "--device", - type=str, default="{board}.{host}", + type=str, default="{board}", help="address or domain corresponding to the development board") parser.add_argument("-w", "--wait", action="store_true", help="wait for the board to unlock instead of aborting the actions") @@ -96,7 +99,7 @@ def main(): device = args.device.format(board=board, host=args.host) serial = args.serial.format(board=board) - client = SSHClient(args.host) + client = SSHClient(args.host, args.jump) flock_acquired = False flock_file = None # GC root @@ -158,6 +161,8 @@ def main(): for _ in range(args.verbose): flash_args.append("-v") flash_args += ["-H", args.host] + if args.jump: + flash_args += ["-J", args.jump] flash_args += ["-t", board_type] flash_args += ["-V", variant] flash_args += ["-I", "source {}".format(board_file)] diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 8023dac56..0ed2a5fde 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -48,6 +48,9 @@ Prerequisites: parser.add_argument("-H", "--host", metavar="HOSTNAME", type=str, default=None, help="SSH host where the development board is located") + parser.add_argument("-J", "--jump", + type=str, default=None, + help="SSH host to jump through") parser.add_argument("-t", "--target", default="kc705", help="target board, default: %(default)s, one of: " "kc705 kasli sayma") @@ -299,7 +302,7 @@ def main(): if args.host is None: client = LocalClient() else: - client = SSHClient(args.host) + client = SSHClient(args.host, args.jump) programmer = config["programmer"](client, preinit_script=args.preinit_command) diff --git a/artiq/remoting.py b/artiq/remoting.py index 8400b35e8..2c5f8af31 100644 --- a/artiq/remoting.py +++ b/artiq/remoting.py @@ -57,8 +57,9 @@ class LocalClient(Client): class SSHClient(Client): - def __init__(self, host): + def __init__(self, host, jump_host=None): self.host = host + self.jump_host = jump_host self.ssh = None self.sftp = None self._tmpr = "/tmp/artiq" @@ -70,10 +71,19 @@ class SSHClient(Client): if self.ssh is None: import paramiko logging.getLogger("paramiko").setLevel(logging.WARNING) + + if self.jump_host: + proxy_cmd = "ssh -W {}:22 {}".format(self.host, self.jump_host) + logger.debug("Using proxy command '{}'".format(proxy_cmd)) + proxy = paramiko.proxy.ProxyCommand(proxy_cmd) + else: + proxy = None + self.ssh = paramiko.SSHClient() self.ssh.load_system_host_keys() self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - self.ssh.connect(self.host) + self.ssh.connect(self.host, sock=proxy) + logger.debug("Connecting to {}".format(self.host)) return self.ssh From fd2b8d5f8f583b68de40d0d2aa9240035954e339 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 5 May 2018 02:59:49 +0000 Subject: [PATCH 0689/2457] firmware: raise hmc542 log level to INFO. --- artiq/firmware/libboard_artiq/hmc542.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc542.rs b/artiq/firmware/libboard_artiq/hmc542.rs index 52490cdd3..d7a0c48b7 100644 --- a/artiq/firmware/libboard_artiq/hmc542.rs +++ b/artiq/firmware/libboard_artiq/hmc542.rs @@ -43,9 +43,9 @@ pub fn program(card_index: usize, chan_index: usize, atten: u8) { } set_pins(PIN_LE); - debug!("card {} channel {} set to {}{} dB", - card_index, chan_index, - atten / 2, if atten % 2 != 0 { ".5" } else { "" }); + info!("card {} channel {} set to {}{} dB", + card_index, chan_index, + atten / 2, if atten % 2 != 0 { ".5" } else { "" }); } /// See `program`. From 917a4185ebeaebb84cb1bc59196b287ff2cd6919 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 5 May 2018 03:00:30 +0000 Subject: [PATCH 0690/2457] Unbreak 9dc7efef. --- artiq/compiler/targets.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index 22c1e9a2b..ffdb7d994 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -33,9 +33,9 @@ class RunTool: stdout, stderr = process.communicate() if process.returncode != 0: raise Exception("{} invocation failed: {}". - format(cmdline[0], stderr.decode('utf-8'))) + format(cmdline[0], stderr)) - self._tempfiles["__stdout__"] = io.StringIO(stdout.decode('utf-8')) + self._tempfiles["__stdout__"] = io.StringIO(stdout) for key in self._tempdata: if self._tempdata[key] is None: self._tempfiles[key] = open(self._tempnames[key], "rb") From c646409dbe5e8e5f995f309d01dcbcd4d00c524d Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 5 May 2018 03:12:13 +0000 Subject: [PATCH 0691/2457] firmware: fix order of bits clocked into hmc542. Fixes #993. --- artiq/firmware/libboard_artiq/hmc542.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc542.rs b/artiq/firmware/libboard_artiq/hmc542.rs index d7a0c48b7..f395e0ede 100644 --- a/artiq/firmware/libboard_artiq/hmc542.rs +++ b/artiq/firmware/libboard_artiq/hmc542.rs @@ -25,27 +25,29 @@ fn set_pins(card_index: usize, chan_index: usize, pins: u32) { pub fn program(card_index: usize, chan_index: usize, atten: u8) { assert!(card_index < 4 && chan_index < 2); - // 0b111111 = 1dB + info!("card {} channel {} set to {}{} dB", + card_index, chan_index, + atten / 2, if atten % 2 != 0 { ".5" } else { "" }); + + // 0b111111 = 0dB // 0b111110 = 0.5dB // 0b111101 = 1dB + // 0b111100 = 1.5dB // ... // 0b011111 = 16dB + // ... // 0b000000 = 31.5dB - let atten = !(atten << 2); + let atten = !atten << 2; let set_pins = |pins| set_pins(card_index, chan_index, pins); set_pins(PIN_RST); set_pins(0); - for n in 0..8 { + for n in (0..8).rev() { let sin = if atten & 1 << n != 0 { PIN_SIN } else { 0 }; set_pins(sin); set_pins(sin | PIN_CLK); } set_pins(PIN_LE); - - info!("card {} channel {} set to {}{} dB", - card_index, chan_index, - atten / 2, if atten % 2 != 0 { ".5" } else { "" }); } /// See `program`. From 7d4a103a43a2cc4c1787eaa7aff2f37de8738050 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 7 May 2018 09:07:18 +0200 Subject: [PATCH 0692/2457] opticlock, suservo: set default kasli hw_rev --- artiq/gateware/targets/kasli.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index ab7541858..a1cb3dda2 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -387,8 +387,10 @@ class Opticlock(_StandaloneBase): """ Opticlock extension variant configuration """ - def __init__(self, **kwargs): - _StandaloneBase.__init__(self, **kwargs) + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.0" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None @@ -492,8 +494,10 @@ class SUServo(_StandaloneBase): """ SUServo (Sampler-Urukul-Servo) extension variant configuration """ - def __init__(self, **kwargs): - _StandaloneBase.__init__(self, **kwargs) + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None From bfa7637760a343c12a1fbe34fa33a75528044f28 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 7 May 2018 07:44:15 +0000 Subject: [PATCH 0693/2457] conda: bump llvmlite-artiq dependency (ncurses) --- conda/artiq-dev/meta.yaml | 2 +- conda/artiq/meta.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 0887bc237..5d9a838ba 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -20,7 +20,7 @@ requirements: - microscope - binutils-or1k-linux >=2.27 - llvm-or1k 6.0.0 - - llvmlite-artiq 0.23.0.dev py35_2 + - llvmlite-artiq 0.23.0.dev py35_4 - rust-core-or1k 1.25.0 20 - openocd 0.10.0 6 - lit diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index 482341845..192f79e40 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -27,7 +27,7 @@ requirements: - setuptools 33.1.1 run: - python >=3.5.3,<3.6 - - llvmlite-artiq 0.23.0.dev py35_2 + - llvmlite-artiq 0.23.0.dev py35_4 - binutils-or1k-linux >=2.27 - pythonparser >=1.1 - openocd 0.10.0 6 From 60fd362d57348fe424410e7e95323fac867ce0e5 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 7 May 2018 23:54:35 +0200 Subject: [PATCH 0694/2457] serwb: fix rx_comma detection --- artiq/gateware/serwb/kusphy.py | 8 ++++++-- artiq/gateware/serwb/s7phy.py | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/serwb/kusphy.py b/artiq/gateware/serwb/kusphy.py index 8abcb08d3..e0a0bd58b 100644 --- a/artiq/gateware/serwb/kusphy.py +++ b/artiq/gateware/serwb/kusphy.py @@ -205,8 +205,12 @@ class KUSSerdes(Module): decoders[3].input.eq(rx_bitslip.o[30:40]), self.rx_k.eq(Cat(*[decoders[i].k for i in range(4)])), self.rx_d.eq(Cat(*[decoders[i].d for i in range(4)])), - self.rx_comma.eq((decoders[0].k == 1) & (decoders[0].d == K(28,5))) - ] + self.rx_comma.eq( + (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & + (decoders[1].k == 0) & (decoders[1].d == 0) & + (decoders[2].k == 0) & (decoders[2].d == 0) & + (decoders[3].k == 0) & (decoders[3].d == 0)) + ] idle_timer = WaitTimer(32) self.submodules += idle_timer diff --git a/artiq/gateware/serwb/s7phy.py b/artiq/gateware/serwb/s7phy.py index df4930572..967991aea 100644 --- a/artiq/gateware/serwb/s7phy.py +++ b/artiq/gateware/serwb/s7phy.py @@ -216,8 +216,12 @@ class S7Serdes(Module): decoders[3].input.eq(rx_bitslip.o[30:40]), self.rx_k.eq(Cat(*[decoders[i].k for i in range(4)])), self.rx_d.eq(Cat(*[decoders[i].d for i in range(4)])), - self.rx_comma.eq((decoders[0].k == 1) & (decoders[0].d == K(28,5))) - ] + self.rx_comma.eq( + (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & + (decoders[1].k == 0) & (decoders[1].d == 0) & + (decoders[2].k == 0) & (decoders[2].d == 0) & + (decoders[3].k == 0) & (decoders[3].d == 0)) + ] idle_timer = WaitTimer(32) self.submodules += idle_timer From f055bf88f6b5137f1caca22b81a0af65e8d64559 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 9 May 2018 07:16:15 +0000 Subject: [PATCH 0695/2457] suservo: add clip flags (#992) --- artiq/coredevice/suservo.py | 4 +++- .../kasli_suservo/repository/suservo.py | 20 +++++++++++++------ artiq/gateware/rtio/phy/servo.py | 7 ++++++- artiq/gateware/suservo/iir.py | 8 ++++++-- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 8dfff8af1..c5aa6f2d1 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -109,8 +109,10 @@ class SUServo: """Get current SU Servo status. This method does not advance the timeline but consumes all slack. + This method returns and clears the clip indicator for all channels. - :return: Status. Bit 0: enabled, bit 1: done + :return: Status. Bit 0: enabled, bit 1: done, + bits 8-15: channel clip indicators. """ return self.read(CONFIG_ADDR) diff --git a/artiq/examples/kasli_suservo/repository/suservo.py b/artiq/examples/kasli_suservo/repository/suservo.py index 61ad9f47f..cf49a77fb 100644 --- a/artiq/examples/kasli_suservo/repository/suservo.py +++ b/artiq/examples/kasli_suservo/repository/suservo.py @@ -29,7 +29,8 @@ class SUServo(EnvExperiment): # DDS attenuator self.suservo0.cpld0.set_att_mu(0, 64) delay(1*us) - assert self.suservo0.get_status() == 2 + # Servo is done + assert self.suservo0.get_status() & 0xff == 2 delay(10*us) # set up profile 0 on channel 0 @@ -51,16 +52,19 @@ class SUServo(EnvExperiment): delay(10*ms) # check servo status - assert self.suservo0.get_status() == 1 + assert self.suservo0.get_status() & 0xff == 1 delay(10*us) # reach back ADC data - print(self.suservo0.get_adc_mu(0)) - delay(10*ms) + assert self.suservo0.get_adc_mu(0) == 0 + delay(10*us) # read out IIR data - print(self.suservo0_ch0.get_y_mu(0)) - delay(10*ms) + assert self.suservo0_ch0.get_y_mu(0) == 0x1ffff + delay(10*us) + + assert self.suservo0.get_status() & 0xff00 == 0x0100 + delay(10*us) # repeatedly clear the IIR state/integrator # with the ADC yielding 0's and given the profile configuration, @@ -69,6 +73,10 @@ class SUServo(EnvExperiment): while True: self.suservo0_ch0.set(1, 0, 0) delay(1*us) + assert self.suservo0.get_status() & 0xff00 == 0x0100 + delay(10*us) + assert self.suservo0.get_status() & 0xff00 == 0x0000 + delay(10*us) self.suservo0_ch0.set_y_mu(0, 0) delay(1*us) self.suservo0_ch0.set(1, 1, 0) diff --git a/artiq/gateware/rtio/phy/servo.py b/artiq/gateware/rtio/phy/servo.py index eb1f8495f..a4ef729a4 100644 --- a/artiq/gateware/rtio/phy/servo.py +++ b/artiq/gateware/rtio/phy/servo.py @@ -58,9 +58,11 @@ class RTServoMem(Module): config = Signal(w.coeff, reset=0) status = Signal(w.coeff) + pad = Signal(6) self.comb += [ Cat(servo.start).eq(config), - status.eq(Cat(servo.start, servo.done)) + status.eq(Cat(servo.start, servo.done, pad, + [_.clip for _ in servo.iir.ctrl])) ] assert len(self.rtlink.o.address) == ( @@ -108,6 +110,9 @@ class RTServoMem(Module): self.sync.rio_phy += [ If(self.rtlink.o.stb & we & state_sel & config_sel, config.eq(self.rtlink.o.data) + ), + If(read & read_config & read_state, + [_.clip.eq(0) for _ in servo.iir.ctrl] ) ] self.comb += [ diff --git a/artiq/gateware/suservo/iir.py b/artiq/gateware/suservo/iir.py index bd4c7dda2..c8b31da6e 100644 --- a/artiq/gateware/suservo/iir.py +++ b/artiq/gateware/suservo/iir.py @@ -238,6 +238,7 @@ class IIR(Module): ("profile", w.profile), ("en_out", 1), ("en_iir", 1), + ("clip", 1), ("stb", 1)]) for i in range(1 << w.channel)] # only update during ~loading @@ -266,6 +267,7 @@ class IIR(Module): profiles = Array([ch.profile for ch in self.ctrl]) en_outs = Array([ch.en_out for ch in self.ctrl]) en_iirs = Array([ch.en_iir for ch in self.ctrl]) + clips = Array([ch.clip for ch in self.ctrl]) # state counter state = Signal(w.channel + 2) @@ -443,8 +445,10 @@ class IIR(Module): en_out.eq(en_outs[channel[0]]), en_iir.eq(en_iirs[channel[0]]), If(stage[1], - ddss[channel[1]][:w.word].eq( - m_coeff.dat_r), + ddss[channel[1]][:w.word].eq(m_coeff.dat_r) + ), + If(stage[2] & en[1] & dsp.clip, + clips[channel[2]].eq(1) ) ], 1: [ From 9de08f85c67f93bae6938a8b2c8ef1015ab989c1 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 9 May 2018 10:57:00 +0200 Subject: [PATCH 0696/2457] firmware/ad9154: reduce verbosity of dac_sysref_cfg --- artiq/firmware/libboard_artiq/ad9154.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index ee8c7f80c..7366d9ce5 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -623,7 +623,9 @@ fn dac_sysref_cfg(dacno: u8) { let sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) | ((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8)) & 0x1ff; - info!(" phase: {}, sync error: {}", phase, sync_error); + if sync_error != sync_error_last { + info!(" phase: {}, sync error: {}", phase, sync_error); + } if sync_error != 0 { if phase_min_found { if sync_error != sync_error_last { From 6b811c1a8b978efa4347862169e6dc2fcc8bdae0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 9 May 2018 19:47:29 +0800 Subject: [PATCH 0697/2457] sayma: fix runtime/rtm gateware address conflict --- artiq/frontend/artiq_flash.py | 2 +- artiq/gateware/targets/sayma_amc.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 0ed2a5fde..fb6610297 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -281,7 +281,7 @@ def main(): "bootloader": ("spi1", 0x000000), "storage": ("spi1", 0x040000), "firmware": ("spi1", 0x050000), - "rtm_gateware": ("spi1", 0x150000), + "rtm_gateware": ("spi1", 0x200000), }, }[args.target] diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 6e2415d57..d0262a00b 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -170,7 +170,7 @@ class Standalone(MiniSoC, AMPSoC): ]) self.csr_devices.append("slave_fpga_cfg") # self.config["HAS_SLAVE_FPGA"] = None - self.config["SLAVE_FPGA_GATEWARE"] = 0x150000 + self.config["SLAVE_FPGA_GATEWARE"] = 0x200000 # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") From 2cece47b106af0246b1dec5aec15706af5f7533b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 9 May 2018 20:00:08 +0800 Subject: [PATCH 0698/2457] firmware/si5324: fix compilation warning --- artiq/firmware/libboard_artiq/si5324.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 8cd8d94d8..0633186b7 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -14,7 +14,7 @@ const ADDRESS: u8 = 0x68; soc_platform = "kc705"))] fn pca9548_select(address: u8, channels: u8) -> Result<()> { i2c::start(BUSNO).unwrap(); - if !i2c::write(BUSNO, (address << 1)).unwrap() { + if !i2c::write(BUSNO, address << 1).unwrap() { return Err("PCA9548 failed to ack write address") } if !i2c::write(BUSNO, channels).unwrap() { @@ -106,7 +106,7 @@ fn map_frequency_settings(settings: &FrequencySettings) -> Result Result<()> { i2c::start(BUSNO).unwrap(); - if !i2c::write(BUSNO, (ADDRESS << 1)).unwrap() { + if !i2c::write(BUSNO, ADDRESS << 1).unwrap() { return Err("Si5324 failed to ack write address") } if !i2c::write(BUSNO, reg).unwrap() { @@ -122,7 +122,7 @@ fn write(reg: u8, val: u8) -> Result<()> { #[cfg(si5324_soft_reset)] fn write_no_ack_value(reg: u8, val: u8) -> Result<()> { i2c::start(BUSNO).unwrap(); - if !i2c::write(BUSNO, (ADDRESS << 1)).unwrap() { + if !i2c::write(BUSNO, ADDRESS << 1).unwrap() { return Err("Si5324 failed to ack write address") } if !i2c::write(BUSNO, reg).unwrap() { @@ -135,7 +135,7 @@ fn write_no_ack_value(reg: u8, val: u8) -> Result<()> { fn read(reg: u8) -> Result { i2c::start(BUSNO).unwrap(); - if !i2c::write(BUSNO, (ADDRESS << 1)).unwrap() { + if !i2c::write(BUSNO, ADDRESS << 1).unwrap() { return Err("Si5324 failed to ack write address") } if !i2c::write(BUSNO, reg).unwrap() { From 13618c7d6e1a725c76fe5a6a774ee67bc8b316da Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 9 May 2018 21:03:58 +0800 Subject: [PATCH 0699/2457] conda: bump migen --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 5d9a838ba..b1807008e 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_30+git5c2c144 + - migen 0.7 py35_35+git9bc084a - misoc 0.11 py35_7+git269b6502 - jesd204b 0.5 - microscope From da1a61b8cf998875706a4284263ea5dbee699cf4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 9 May 2018 21:27:28 +0800 Subject: [PATCH 0700/2457] conda: bump misoc. Closes #995 --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index b1807008e..2d48949b0 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_35+git9bc084a - - misoc 0.11 py35_7+git269b6502 + - misoc 0.11 py35_10+git6d5bacf1 - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27 From 2e3bf8602f2b60489d78a60f720ddf4ab3c15fac Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 11 May 2018 14:13:41 +0800 Subject: [PATCH 0701/2457] serwb: reduce buffering. Closes #997 --- artiq/gateware/serwb/etherbone.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/serwb/etherbone.py b/artiq/gateware/serwb/etherbone.py index d69baf923..3d869d889 100644 --- a/artiq/gateware/serwb/etherbone.py +++ b/artiq/gateware/serwb/etherbone.py @@ -414,7 +414,7 @@ class _EtherboneRecordDepacketizer(_Depacketizer): class _EtherboneRecordReceiver(Module): - def __init__(self, buffer_depth=256): + def __init__(self, buffer_depth=16): self.sink = sink = stream.Endpoint(etherbone_record_description(32)) self.source = source = stream.Endpoint(etherbone_mmap_description(32)) @@ -497,7 +497,7 @@ class _EtherboneRecordReceiver(Module): class _EtherboneRecordSender(Module): - def __init__(self, buffer_depth=256): + def __init__(self, buffer_depth=16): self.sink = sink = stream.Endpoint(etherbone_mmap_description(32)) self.source = source = stream.Endpoint(etherbone_record_description(32)) From cd4477864ae9f47d6535ef8d59ab817c151f9abc Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 11 May 2018 23:31:25 +0200 Subject: [PATCH 0702/2457] serwb: fix case when rtm fpga is not loaded, lvds input can be 0 or 1 --- artiq/gateware/serwb/kusphy.py | 3 ++- artiq/gateware/serwb/s7phy.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/serwb/kusphy.py b/artiq/gateware/serwb/kusphy.py index e0a0bd58b..395c4c0b7 100644 --- a/artiq/gateware/serwb/kusphy.py +++ b/artiq/gateware/serwb/kusphy.py @@ -215,4 +215,5 @@ class KUSSerdes(Module): idle_timer = WaitTimer(32) self.submodules += idle_timer self.comb += idle_timer.wait.eq(1) - self.sync += self.rx_idle.eq(idle_timer.done & (rx_bitslip.o == 0)) + self.sync += self.rx_idle.eq(idle_timer.done & + ((rx_bitslip.o == 0) | (rx_bitslip.o == (2**40-1)))) diff --git a/artiq/gateware/serwb/s7phy.py b/artiq/gateware/serwb/s7phy.py index 967991aea..cc7cc4e30 100644 --- a/artiq/gateware/serwb/s7phy.py +++ b/artiq/gateware/serwb/s7phy.py @@ -226,4 +226,5 @@ class S7Serdes(Module): idle_timer = WaitTimer(32) self.submodules += idle_timer self.comb += idle_timer.wait.eq(1) - self.sync += self.rx_idle.eq(idle_timer.done & (rx_bitslip.o == 0)) + self.sync += self.rx_idle.eq(idle_timer.done & + ((rx_bitslip.o == 0) | (rx_bitslip.o == (2**40-1)))) From 3c49eba0a0e3ff684da91ce5bb00c9ad126b8157 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 12 May 2018 00:06:49 +0200 Subject: [PATCH 0703/2457] firmware/hmc830_7043: put hmc7043 in sleep mode before hmc830 initialization hmc7043 seems to generate broadband noise when not initialized. This allows isolating issues. If hmc830 still does not always lock correctly, then this is not related to hmc7043 broadband noise. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 27 ++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index fef3c8236..710bdeb03 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -92,7 +92,7 @@ mod hmc830 { } } - pub fn init() -> Result<(), &'static str> { + pub fn detect() -> Result<(), &'static str> { spi_setup(); let id = read(0x00); if id != 0xa7975 { @@ -101,6 +101,12 @@ mod hmc830 { } else { info!("HMC830 found"); } + + Ok(()) + } + + pub fn init() -> Result<(), &'static str> { + spi_setup(); info!("HMC830 configuration..."); for &(addr, data) in HMC830_WRITES.iter() { write(addr, data); @@ -196,7 +202,7 @@ pub mod hmc7043 { } } - pub fn init() -> Result<(), &'static str> { + pub fn detect() -> Result<(), &'static str> { spi_setup(); let id = (read(0x78) as u32) << 16 | (read(0x79) as u32) << 8 | read(0x7a) as u32; if id != 0xf17904 { @@ -205,6 +211,20 @@ pub mod hmc7043 { } else { info!("HMC7043 found"); } + + Ok(()) + } + + pub fn shutdown() -> Result<(), &'static str> { + spi_setup(); + info!("HMC7043 shutdown..."); + write(0x1, 0x1); // Sleep mode + + Ok(()) + } + + pub fn init() -> Result<(), &'static str> { + spi_setup(); info!("HMC7043 configuration..."); write(0x0, 0x1); // Software reset @@ -272,6 +292,9 @@ pub mod hmc7043 { pub fn init() -> Result<(), &'static str> { clock_mux::init(); /* must be the first SPI init because of HMC830 SPI mode selection */ + hmc830::detect()?; + hmc7043::detect()?; + hmc7043::shutdown()?; hmc830::init()?; hmc7043::init() } From 6b4bbe31f73ed57a31506d6a3af6217283291621 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 12 May 2018 00:12:59 +0200 Subject: [PATCH 0704/2457] firmware/ad9154: use fixed hmc7043 sysref phase (found with scan) --- artiq/firmware/libboard_artiq/ad9154.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 7366d9ce5..746a702cc 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -608,7 +608,8 @@ fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { dac_cfg(dacno) } -fn dac_sysref_cfg(dacno: u8) { +#[allow(dead_code)] +fn dac_sysref_scan(dacno: u8) { let mut sync_error_last = 0u16; let mut phase_min_found = false; let mut phase_min = 0u16; @@ -646,6 +647,11 @@ fn dac_sysref_cfg(dacno: u8) { hmc7043::cfg_dac_sysref(dacno, phase_opt); } +fn dac_sysref_cfg(dacno: u8, phase: u16) { + info!("AD9154-{} setting SYSREF phase to {}", dacno, phase); + hmc7043::cfg_dac_sysref(dacno, phase); +} + pub fn init() -> Result<(), &'static str> { // Release the JESD clock domain reset late, as we need to // set up clock chips before. @@ -654,9 +660,9 @@ pub fn init() -> Result<(), &'static str> { for dacno in 0..csr::AD9154.len() { let dacno = dacno as u8; debug!("setting up AD9154-{} DAC...", dacno); + dac_sysref_cfg(dacno, 88); dac_cfg_retry(dacno)?; dac_prbs(dacno)?; - dac_sysref_cfg(dacno); dac_cfg_retry(dacno)?; } From e09dbc89bcae10f8dfcf8b8b10564d3c8e4de964 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 12 May 2018 01:32:16 +0200 Subject: [PATCH 0705/2457] serwb: remove idelaye3 en_vtc (was not done correctly, we'll add direct software control) --- artiq/gateware/serwb/kusphy.py | 3 +-- artiq/gateware/serwb/phy.py | 4 ---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/artiq/gateware/serwb/kusphy.py b/artiq/gateware/serwb/kusphy.py index 395c4c0b7..dd7cf6760 100644 --- a/artiq/gateware/serwb/kusphy.py +++ b/artiq/gateware/serwb/kusphy.py @@ -32,7 +32,6 @@ class KUSSerdes(Module): self.rx_bitslip_value = Signal(6) self.rx_delay_rst = Signal() self.rx_delay_inc = Signal() - self.rx_delay_en_vtc = Signal() # # # @@ -174,7 +173,7 @@ class KUSSerdes(Module): i_CLK=ClockSignal("sys"), i_RST=self.rx_delay_rst, i_LOAD=0, - i_INC=1, i_EN_VTC=self.rx_delay_en_vtc, + i_INC=1, i_EN_VTC=0, i_CE=self.rx_delay_inc, i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index 8a921dbe6..de7c4144e 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -147,8 +147,6 @@ class _SerdesMasterInit(Module): fsm.act("READY", self.ready.eq(1) ) - if hasattr(serdes, "rx_delay_en_vtc"): - self.comb += serdes.rx_delay_en_vtc.eq(self.ready) fsm.act("ERROR", self.error.eq(1) ) @@ -277,8 +275,6 @@ class _SerdesSlaveInit(Module, AutoCSR): fsm.act("READY", self.ready.eq(1) ) - if hasattr(serdes, "rx_delay_en_vtc"): - self.comb += serdes.rx_delay_en_vtc.eq(self.ready) fsm.act("ERROR", self.error.eq(1) ) From b6ab59fb80f45a230b486208acae0c0d885c3b51 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 12 May 2018 01:32:55 +0200 Subject: [PATCH 0706/2457] serwb/phy: increase timeout --- artiq/gateware/serwb/phy.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index de7c4144e..d683444b1 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -21,7 +21,7 @@ from artiq.gateware.serwb.s7phy import S7Serdes @ResetInserter() class _SerdesMasterInit(Module): - def __init__(self, serdes, taps, timeout=2**14): + def __init__(self, serdes, taps, timeout=2**15): self.ready = Signal() self.error = Signal() @@ -154,7 +154,7 @@ class _SerdesMasterInit(Module): @ResetInserter() class _SerdesSlaveInit(Module, AutoCSR): - def __init__(self, serdes, taps, timeout=2**14): + def __init__(self, serdes, taps, timeout=2**15): self.ready = Signal() self.error = Signal() @@ -351,7 +351,7 @@ class _SerdesControl(Module, AutoCSR): class SERWBPHY(Module, AutoCSR): - def __init__(self, device, pads, mode="master", init_timeout=2**14): + def __init__(self, device, pads, mode="master", init_timeout=2**15): self.sink = sink = stream.Endpoint([("data", 32)]) self.source = source = stream.Endpoint([("data", 32)]) assert mode in ["master", "slave"] From 0a6d4ccd85d0332de8d8ab26c1507aec7f6996fe Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 12 May 2018 01:35:34 +0200 Subject: [PATCH 0707/2457] serwb/phy: improve/cleanup init --- artiq/gateware/serwb/phy.py | 50 ++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index d683444b1..0ba064372 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -104,6 +104,9 @@ class _SerdesMasterInit(Module): NextState("ERROR") ).Else( NextValue(delay_min_found, 0), + NextValue(delay_min, 0), + NextValue(delay_max_found, 0), + NextValue(delay_max, 0), NextValue(bitslip, bitslip + 1) ), NextValue(delay, 0), @@ -118,10 +121,12 @@ class _SerdesMasterInit(Module): If((delay_min == 0) | (delay_max == (taps - 1)) | ((delay_max - delay_min) < taps//16), - NextValue(delay_min_found, 0), - NextValue(delay_max_found, 0), - NextState("WAIT_STABLE") + # switch to next bitslip + NextValue(delay, taps - 1), + NextState("INC_DELAY_BITSLIP") ).Else( + NextValue(delay, 0), + serdes.rx_delay_rst.eq(1), NextState("CONFIGURE_SAMPLING_WINDOW") ), serdes.tx_comma.eq(1) @@ -131,16 +136,7 @@ class _SerdesMasterInit(Module): NextState("READY") ).Else( NextValue(delay, delay + 1), - serdes.rx_delay_inc.eq(1), - NextState("WAIT_SAMPLING_WINDOW") - ), - serdes.tx_comma.eq(1) - ) - fsm.act("WAIT_SAMPLING_WINDOW", - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("CONFIGURE_SAMPLING_WINDOW") + serdes.rx_delay_inc.eq(1) ), serdes.tx_comma.eq(1) ) @@ -225,6 +221,9 @@ class _SerdesSlaveInit(Module, AutoCSR): NextState("ERROR") ).Else( NextValue(delay_min_found, 0), + NextValue(delay_min, 0), + NextValue(delay_max_found, 0), + NextValue(delay_max, 0), NextValue(bitslip, bitslip + 1) ), NextValue(delay, 0), @@ -239,10 +238,12 @@ class _SerdesSlaveInit(Module, AutoCSR): If((delay_min == 0) | (delay_max == (taps - 1)) | ((delay_max - delay_min) < taps//16), - NextValue(delay_min_found, 0), - NextValue(delay_max_found, 0), - NextState("WAIT_STABLE") + # switch to next bitslip + NextValue(delay, taps - 1), + NextState("INC_DELAY_BITSLIP") ).Else( + NextValue(delay, 0), + serdes.rx_delay_rst.eq(1), NextState("CONFIGURE_SAMPLING_WINDOW") ), serdes.tx_idle.eq(1) @@ -253,20 +254,13 @@ class _SerdesSlaveInit(Module, AutoCSR): ).Else( NextValue(delay, delay + 1), serdes.rx_delay_inc.eq(1), - NextState("WAIT_SAMPLING_WINDOW") - ) - ) - fsm.act("WAIT_SAMPLING_WINDOW", - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("CONFIGURE_SAMPLING_WINDOW") - ) + ), + serdes.tx_idle.eq(1) ) fsm.act("SEND_PATTERN", - timer.wait.eq(1), - If(timer.done, - If(~serdes.rx_comma, + If(~serdes.rx_comma, + timer.wait.eq(1), + If(timer.done, NextState("READY") ) ), From 6e67e6d0b12743873176acf7c19377fdcb3b744a Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 12 May 2018 11:59:46 +0200 Subject: [PATCH 0708/2457] serwb: revert some changes (was breaking simulation) --- artiq/gateware/serwb/phy.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index 0ba064372..ecd6f527c 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -121,9 +121,9 @@ class _SerdesMasterInit(Module): If((delay_min == 0) | (delay_max == (taps - 1)) | ((delay_max - delay_min) < taps//16), - # switch to next bitslip - NextValue(delay, taps - 1), - NextState("INC_DELAY_BITSLIP") + NextValue(delay_min_found, 0), + NextValue(delay_max_found, 0), + NextState("WAIT_STABLE") ).Else( NextValue(delay, 0), serdes.rx_delay_rst.eq(1), @@ -238,9 +238,9 @@ class _SerdesSlaveInit(Module, AutoCSR): If((delay_min == 0) | (delay_max == (taps - 1)) | ((delay_max - delay_min) < taps//16), - # switch to next bitslip - NextValue(delay, taps - 1), - NextState("INC_DELAY_BITSLIP") + NextValue(delay_min_found, 0), + NextValue(delay_max_found, 0), + NextState("WAIT_STABLE") ).Else( NextValue(delay, 0), serdes.rx_delay_rst.eq(1), @@ -258,9 +258,9 @@ class _SerdesSlaveInit(Module, AutoCSR): serdes.tx_idle.eq(1) ) fsm.act("SEND_PATTERN", - If(~serdes.rx_comma, - timer.wait.eq(1), - If(timer.done, + timer.wait.eq(1), + If(timer.done, + If(~serdes.rx_comma, NextState("READY") ) ), From fdc953e5694b8f460d680bbe2ad5fb5fd77b8d26 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 12 May 2018 12:03:11 +0200 Subject: [PATCH 0709/2457] serwb/etherbone: recuce buffering --- artiq/gateware/serwb/etherbone.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/serwb/etherbone.py b/artiq/gateware/serwb/etherbone.py index 3d869d889..f0fcf2632 100644 --- a/artiq/gateware/serwb/etherbone.py +++ b/artiq/gateware/serwb/etherbone.py @@ -414,7 +414,7 @@ class _EtherboneRecordDepacketizer(_Depacketizer): class _EtherboneRecordReceiver(Module): - def __init__(self, buffer_depth=16): + def __init__(self, buffer_depth=4): self.sink = sink = stream.Endpoint(etherbone_record_description(32)) self.source = source = stream.Endpoint(etherbone_mmap_description(32)) @@ -497,7 +497,7 @@ class _EtherboneRecordReceiver(Module): class _EtherboneRecordSender(Module): - def __init__(self, buffer_depth=16): + def __init__(self, buffer_depth=4): self.sink = sink = stream.Endpoint(etherbone_mmap_description(32)) self.source = source = stream.Endpoint(etherbone_record_description(32)) From f5208ff2f39f166ad2c443cc4d0d2d00bf185ba4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 12 May 2018 12:03:58 +0200 Subject: [PATCH 0710/2457] serwb/core: reduce buffering, use buffered=True --- artiq/gateware/serwb/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/serwb/core.py b/artiq/gateware/serwb/core.py index a3109e4fd..72b4b8119 100644 --- a/artiq/gateware/serwb/core.py +++ b/artiq/gateware/serwb/core.py @@ -17,8 +17,8 @@ class SERWBCore(Module): self.submodules += depacketizer, packetizer # fifos - tx_fifo = stream.SyncFIFO([("data", 32)], 16) - rx_fifo = stream.SyncFIFO([("data", 32)], 16) + tx_fifo = stream.SyncFIFO([("data", 32)], 8, buffered=True) + rx_fifo = stream.SyncFIFO([("data", 32)], 8, buffered=True) self.submodules += tx_fifo, rx_fifo # modules connection From 6796413a53f7a37bf8848325b5ec116169be6e04 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 12 May 2018 22:49:44 +0800 Subject: [PATCH 0711/2457] serwb: remove unnecessary shebang line --- artiq/gateware/test/serwb/test_serwb_init.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/gateware/test/serwb/test_serwb_init.py b/artiq/gateware/test/serwb/test_serwb_init.py index c64d59e45..1651489fa 100644 --- a/artiq/gateware/test/serwb/test_serwb_init.py +++ b/artiq/gateware/test/serwb/test_serwb_init.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import unittest from migen import * From 2426fea3f2b20f3c8205b158088ca59db25b2d95 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 12 May 2018 22:57:11 +0800 Subject: [PATCH 0712/2457] siphaser: support external reference for the freerunning 150MHz --- artiq/gateware/drtio/siphaser.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/drtio/siphaser.py b/artiq/gateware/drtio/siphaser.py index 13c61d81e..893b9e91d 100644 --- a/artiq/gateware/drtio/siphaser.py +++ b/artiq/gateware/drtio/siphaser.py @@ -4,16 +4,17 @@ from migen.genlib.cdc import MultiReg from misoc.interconnect.csr import * -# This code assumes 125MHz system clock and 150MHz RTIO frequency. +# This code assumes 125/62.5MHz reference clock and 150MHz RTIO frequency. class SiPhaser7Series(Module, AutoCSR): - def __init__(self, si5324_clkin, si5324_clkout_fabric): + def __init__(self, si5324_clkin, si5324_clkout_fabric, + ref_clk=None, ref_div2=False): self.switch_clocks = CSRStorage() self.phase_shift = CSR() self.phase_shift_done = CSRStatus(reset=1) self.sample_result = CSRStatus() - # 125MHz system clock to 150MHz. VCO @ 625MHz. + # 125MHz/62.5MHz reference clock to 150MHz. VCO @ 625MHz. # Used to provide a startup clock to the transceiver through the Si, # we do not use the crystal reference so that the PFD (f3) frequency # can be high. @@ -21,11 +22,12 @@ class SiPhaser7Series(Module, AutoCSR): mmcm_freerun_output = Signal() self.specials += \ Instance("MMCME2_BASE", - p_CLKIN1_PERIOD=1e9/125e6, - i_CLKIN1=ClockSignal("sys"), - i_RST=ResetSignal("sys"), + p_CLKIN1_PERIOD=16.0 if ref_div2 else 8.0, + i_CLKIN1=ClockSignal("sys") if ref_clk is None else ref_clk, + i_RST=ResetSignal("sys") if ref_clk is None else 0, - p_CLKFBOUT_MULT_F=6.0, p_DIVCLK_DIVIDE=1, + p_CLKFBOUT_MULT_F=12.0 if ref_div2 else 6.0, + p_DIVCLK_DIVIDE=1, o_CLKFBOUT=mmcm_freerun_fb, i_CLKFBIN=mmcm_freerun_fb, From 8c1390e5570422ece2d37d41bc7c47671533d8c6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 12 May 2018 22:57:34 +0800 Subject: [PATCH 0713/2457] kasli: use 62.5MHz clock for siphaser reference (#999) --- artiq/gateware/targets/kasli.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index a1cb3dda2..14c1b9448 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -934,7 +934,8 @@ class _SatelliteBase(BaseSoC): self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), - si5324_clkout_fabric=platform.request("si5324_clkout_fabric")) + si5324_clkout_fabric=platform.request("si5324_clkout_fabric"), + ref_clk=self.crg.clk125_div2, ref_div2=True) platform.add_false_path_constraints( self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) self.csr_devices.append("siphaser") From 4ed9fdbf2701902ebdac7c69bbca43e3ff3d87a0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 12 May 2018 22:58:48 +0800 Subject: [PATCH 0714/2457] conda: bump misoc --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 2d48949b0..62d283af0 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_35+git9bc084a - - misoc 0.11 py35_10+git6d5bacf1 + - misoc 0.11 py35_14+gitc60ccfb2 - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27 From ee4c475cf3c5954041a3e6d8e689c13f77ab5fdd Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 13 May 2018 13:10:39 +0000 Subject: [PATCH 0715/2457] gateware: fix Sayma satellite build. RTIO clock multiplier was removed from Sayma in 32f22f4c. --- artiq/gateware/targets/sayma_amc.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index d0262a00b..856adb965 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -389,7 +389,6 @@ class Satellite(BaseSoC): self.submodules += Microscope(platform.request("serial", 1), self.clk_freq) - self.submodules.rtio_clkmul = _RTIOClockMultiplier(platform, rtio_clk_freq) rtio_channels = [] for i in range(4): phy = ttl_simple.Output(platform.request("user_led", i)) From 32522be413b720089c8af63370759926984338ea Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 13 May 2018 13:28:00 +0000 Subject: [PATCH 0716/2457] satman: use 1K log buffer and 4K stack. This reduces memory requirements in half. --- artiq/firmware/satman/main.rs | 2 +- artiq/firmware/satman/satman.ld | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index bb20c5450..f2f616bc4 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -274,7 +274,7 @@ pub extern fn main() -> i32 { } ALLOC.add_range(&mut _fheap, &mut _eheap); - static mut LOG_BUFFER: [u8; 65536] = [0; 65536]; + static mut LOG_BUFFER: [u8; 1024] = [0; 1024]; logger_artiq::BufferLogger::new(&mut LOG_BUFFER[..]).register(startup); 0 } diff --git a/artiq/firmware/satman/satman.ld b/artiq/firmware/satman/satman.ld index f6e4c6a6a..3766b38d6 100644 --- a/artiq/firmware/satman/satman.ld +++ b/artiq/firmware/satman/satman.ld @@ -46,10 +46,10 @@ SECTIONS _ebss = .; } > main_ram - .stack ALIGN(0x1000) : + .stack : { _estack = .; - . += 0x4000; + . += 0x1000; _fstack = . - 4; } > main_ram From aa42a69849588c3abdcc6934cec1d1c11a895c0d Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 13 May 2018 13:39:14 +0000 Subject: [PATCH 0717/2457] libdrtioaux: always inline read/write helpers. This shrinks Packet::{read_from,write_to} by 1K. --- artiq/firmware/libdrtioaux/proto.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/artiq/firmware/libdrtioaux/proto.rs b/artiq/firmware/libdrtioaux/proto.rs index ca3101ba6..9a89796e0 100644 --- a/artiq/firmware/libdrtioaux/proto.rs +++ b/artiq/firmware/libdrtioaux/proto.rs @@ -6,17 +6,20 @@ use std::string::String; use byteorder::{ByteOrder, NetworkEndian}; // FIXME: replace these with byteorder core io traits once those are in +#[inline(always)] pub fn read_u8(reader: &mut Read) -> io::Result { let mut bytes = [0; 1]; reader.read_exact(&mut bytes)?; Ok(bytes[0]) } +#[inline(always)] pub fn write_u8(writer: &mut Write, value: u8) -> io::Result<()> { let bytes = [value; 1]; writer.write_all(&bytes) } +#[inline(always)] pub fn read_bool(reader: &mut Read) -> io::Result { if read_u8(reader)? == 0 { Ok(false) @@ -25,6 +28,7 @@ pub fn read_bool(reader: &mut Read) -> io::Result { } } +#[inline(always)] pub fn write_bool(writer: &mut Write, value: bool) -> io::Result<()> { if value { write_u8(writer, 1) @@ -33,42 +37,49 @@ pub fn write_bool(writer: &mut Write, value: bool) -> io::Result<()> { } } +#[inline(always)] pub fn read_u16(reader: &mut Read) -> io::Result { let mut bytes = [0; 2]; reader.read_exact(&mut bytes)?; Ok(NetworkEndian::read_u16(&bytes)) } +#[inline(always)] pub fn write_u16(writer: &mut Write, value: u16) -> io::Result<()> { let mut bytes = [0; 2]; NetworkEndian::write_u16(&mut bytes, value); writer.write_all(&bytes) } +#[inline(always)] pub fn read_u32(reader: &mut Read) -> io::Result { let mut bytes = [0; 4]; reader.read_exact(&mut bytes)?; Ok(NetworkEndian::read_u32(&bytes)) } +#[inline(always)] pub fn write_u32(writer: &mut Write, value: u32) -> io::Result<()> { let mut bytes = [0; 4]; NetworkEndian::write_u32(&mut bytes, value); writer.write_all(&bytes) } +#[inline(always)] pub fn read_u64(reader: &mut Read) -> io::Result { let mut bytes = [0; 8]; reader.read_exact(&mut bytes)?; Ok(NetworkEndian::read_u64(&bytes)) } +#[inline(always)] pub fn write_u64(writer: &mut Write, value: u64) -> io::Result<()> { let mut bytes = [0; 8]; NetworkEndian::write_u64(&mut bytes, value); writer.write_all(&bytes) } +#[inline(always)] pub fn read_bytes(reader: &mut Read) -> io::Result> { let length = read_u32(reader)?; let mut value = vec![0; length as usize]; @@ -76,17 +87,20 @@ pub fn read_bytes(reader: &mut Read) -> io::Result> { Ok(value) } +#[inline(always)] pub fn write_bytes(writer: &mut Write, value: &[u8]) -> io::Result<()> { write_u32(writer, value.len() as u32)?; writer.write_all(value) } +#[inline(always)] pub fn read_string(reader: &mut Read) -> io::Result { let bytes = read_bytes(reader)?; String::from_utf8(bytes) .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid UTF-8")) } +#[inline(always)] pub fn write_string(writer: &mut Write, value: &str) -> io::Result<()> { write_bytes(writer, value.as_bytes()) } From f383a470fe690f4d22b59650a162ca3b89558789 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 13 May 2018 13:43:39 +0000 Subject: [PATCH 0718/2457] satman: do not debug print unexpected aux packets. This shrinks firmware by 2.8K. --- artiq/firmware/satman/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index f2f616bc4..8bcdc0819 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -159,7 +159,7 @@ fn process_aux_packet(p: &drtioaux::Packet) { }; } - _ => warn!("received unexpected aux packet {:?}", p) + _ => warn!("received unexpected aux packet") } } From c8d91b297d44cf4ad4cf73e594c322b026de845b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 May 2018 22:30:33 +0800 Subject: [PATCH 0719/2457] coredevice: add new ad9914 driver --- artiq/coredevice/ad9914.py | 307 +++++++++++++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 artiq/coredevice/ad9914.py diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py new file mode 100644 index 000000000..a291cf6d6 --- /dev/null +++ b/artiq/coredevice/ad9914.py @@ -0,0 +1,307 @@ +""" +Driver for the AD9914 DDS (with parallel bus) on RTIO. +""" + + +from artiq.language.core import * +from artiq.language.types import * +from artiq.language.units import * +from artiq.coredevice.rtio import rtio_output + +from numpy import int32, int64 + + +_PHASE_MODE_DEFAULT = -1 +PHASE_MODE_CONTINUOUS = 0 +PHASE_MODE_ABSOLUTE = 1 +PHASE_MODE_TRACKING = 2 + +AD9914_REG_CFR1L = 0x01 +AD9914_REG_CFR1H = 0x03 +AD9914_REG_CFR2L = 0x05 +AD9914_REG_CFR2H = 0x07 +AD9914_REG_CFR3L = 0x09 +AD9914_REG_CFR3H = 0x0b +AD9914_REG_CFR4L = 0x0d +AD9914_REG_CFR4H = 0x0f +AD9914_REG_DRGFL = 0x11 +AD9914_REG_DRGFH = 0x13 +AD9914_REG_DRGBL = 0x15 +AD9914_REG_DRGBH = 0x17 +AD9914_REG_DRGAL = 0x19 +AD9914_REG_DRGAH = 0x1b +AD9914_REG_FTWL = 0x2d +AD9914_REG_FTWH = 0x2f +AD9914_REG_POW = 0x31 +AD9914_REG_ASF = 0x33 +AD9914_REG_USR0 = 0x6d +AD9914_FUD = 0x80 +AD9914_GPIO = 0x81 + + +class AD9914: + """Driver for one AD9914 DDS channel. + + The time cursor is not modified by any function in this class. + + Output event replacement is not supported and issuing commands at the same + time is an error. + + :param sysclk: DDS system frequency. The DDS system clock must be a + phase-locked multiple of the RTIO clock. + :param bus_channel: RTIO channel number of the DDS bus. + :param channel: channel number (on the bus) of the DDS device to control. + """ + + kernel_invariants = {"core", "sysclk", "bus_channel", "channel", + "rtio_period_mu", "sysclk_per_mu", "write_duration_mu", + "dac_cal_duration_mu", "init_duration_mu", "init_sync_duration_mu", + "set_duration_mu", "set_x_duration_mu" + "continuous_phase_comp"} + + def __init__(self, dmgr, sysclk, bus_channel, channel, core_device="core"): + self.core = dmgr.get(core_device) + self.sysclk = sysclk + self.bus_channel = bus_channel + self.channel = channel + self.phase_mode = PHASE_MODE_CONTINUOUS + + self.rtio_period_mu = int64(8) + self.sysclk_per_mu = int32(self.sysclk * self.core.ref_period) + + self.write_duration_mu = 5 * self.rtio_period_mu + self.dac_cal_duration_mu = 147000 * self.rtio_period_mu + self.init_duration_mu = 10 * self.write_duration_mu + self.dac_cal_duration_mu + self.init_sync_duration_mu = 18 * self.write_duration_mu + 2 * self.dac_cal_duration_mu + self.set_duration_mu = 6 * self.write_duration_mu + self.set_x_duration_mu = 7 * self.write_duration_mu + + self.continuous_phase_comp = 0 + + @kernel + def write(self, addr, data): + rtio_output(now_mu(), self.bus_channel, addr, data) + delay_mu(self.write_duration_mu) + + @kernel + def init(self): + """Resets and initializes the DDS channel. + + This needs to be done for each DDS channel before it can be used, and + it is recommended to use the startup kernel for this purpose. + """ + delay_mu(-self.init_duration_mu) + self.write(AD9914_GPIO, (1 << self.channel) << 1); + + self.write(AD9914_REG_CFR1H, 0x0000) # Enable cosine output + self.write(AD9914_REG_CFR2L, 0x8900) # Enable matched latency + self.write(AD9914_REG_CFR2H, 0x0080) # Enable profile mode + self.write(AD9914_REG_DRGBH, 0x8000) # Programmable modulus B == 2**31 + self.write(AD9914_REG_DRGBL, 0x0000) + self.write(AD9914_REG_ASF, 0x0fff) # Set amplitude to maximum + self.write(AD9914_REG_CFR4H, 0x0105) # Enable DAC calibration + self.write(AD9914_FUD, 0) + delay_mu(self.dac_cal_duration_mu) + self.write(AD9914_REG_CFR4H, 0x0005) # Disable DAC calibration + self.write(AD9914_FUD, 0) + + @kernel + def init_sync(self, sync_delay): + """Resets and initializes the DDS channel as well as configures + the AD9914 DDS for synchronisation. The synchronisation procedure + follows the steps outlined in the AN-1254 application note. + + This needs to be done for each DDS channel before it can be used, and + it is recommended to use the startup kernel for this. + + This function cannot be used in a batch; the correct way of + initializing multiple DDS channels is to call this function + sequentially with a delay between the calls. 10ms provides a good + timing margin. + + :param sync_delay: integer from 0 to 0x3f that sets the value of + SYNC_OUT (bits 3-5) and SYNC_IN (bits 0-2) delay ADJ bits. + """ + delay_mu(-self.init_sync_duration_mu) + self.write(AD9914_GPIO, (1 << self.channel) << 1) + + self.write(AD9914_REG_CFR4H, 0x0105) # Enable DAC calibration + self.write(AD9914_FUD, 0) + delay_mu(self.dac_cal_duration_mu) + self.write(AD9914_REG_CFR4H, 0x0005) # Disable DAC calibration + self.write(AD9914_FUD, 0) + self.write(AD9914_REG_CFR2L, 0x8b00) # Enable matched latency and sync_out + self.write(AD9914_FUD, 0) + # Set cal with sync and set sync_out and sync_in delay + self.write(AD9914_REG_USR0, 0x0840 | (sync_delay & 0x3f)) + self.write(AD9914_FUD, 0) + self.write(AD9914_REG_CFR4H, 0x0105) # Enable DAC calibration + self.write(AD9914_FUD, 0) + delay_mu(self.dac_cal_duration_mu) + self.write(AD9914_REG_CFR4H, 0x0005) # Disable DAC calibration + self.write(AD9914_FUD, 0) + self.write(AD9914_REG_CFR1H, 0x0000) # Enable cosine output + self.write(AD9914_REG_CFR2H, 0x0080) # Enable profile mode + self.write(AD9914_REG_DRGBH, 0x8000) # Programmable modulus B == 2**31 + self.write(AD9914_REG_DRGBL, 0x0000) + self.write(AD9914_REG_ASF, 0x0fff) # Set amplitude to maximum + self.write(AD9914_FUD, 0) + + @kernel + def set_phase_mode(self, phase_mode): + """Sets the phase mode of the DDS channel. Supported phase modes are: + + * ``PHASE_MODE_CONTINUOUS``: the phase accumulator is unchanged when + switching frequencies. The DDS phase is the sum of the phase + accumulator and the phase offset. The only discrete jumps in the + DDS output phase come from changes to the phase offset. + + * ``PHASE_MODE_ABSOLUTE``: the phase accumulator is reset when + switching frequencies. Thus, the phase of the DDS at the time of + the frequency change is equal to the phase offset. + + * ``PHASE_MODE_TRACKING``: when switching frequencies, the phase + accumulator is set to the value it would have if the DDS had been + running at the specified frequency since the start of the + experiment. + """ + self.phase_mode = phase_mode + + @kernel + def set_mu(self, frequency, phase=0, phase_mode=_PHASE_MODE_DEFAULT, + amplitude=0x0fff, ref_time=-1): + """Sets the DDS channel to the specified frequency and phase. + + This uses machine units (FTW and POW). The frequency tuning word width + is 32, whereas the phase offset word width depends on the type of DDS + chip and can be retrieved via the ``pow_width`` attribute. The amplitude + width is 12. + + The "frequency update" pulse is sent to the DDS with a fixed latency + with respect to the current position of the time cursor. + + :param frequency: frequency to generate. + :param phase: adds an offset, in turns, to the phase. + :param phase_mode: if specified, overrides the default phase mode set + by ``set_phase_mode`` for this call. + :param ref_time: reference time used to compute phase. Specifying this + makes it easier to have a well-defined phase relationship between + DDSes on the same bus that are updated at a similar time. + """ + if phase_mode == _PHASE_MODE_DEFAULT: + phase_mode = self.phase_mode + if ref_time < 0: + ref_time = now_mu() + delay_mu(-self.set_duration_mu) + + self.write(AD9914_GPIO, (1 << self.channel) << 1) + + self.write(AD9914_REG_FTWL, ftw & 0xffff) + self.write(AD9914_REG_FTWH, (ftw >> 16) & 0xffff) + + # We need the RTIO fine timestamp clock to be phase-locked + # to DDS SYSCLK, and divided by an integer self.sysclk_per_mu. + if phase_mode == PHASE_MODE_CONTINUOUS: + # Do not clear phase accumulator on FUD + # Disable autoclear phase accumulator and enables OSK. + self.write(AD9914_REG_CFR1L, 0x0108) + pow += self.continuous_phase_comp + else: + # Clear phase accumulator on FUD + # Enable autoclear phase accumulator and enables OSK. + self.write(AD9914_REG_CFR1L, 0x2108) + fud_time = now_mu() + 2 * self.write_duration_mu + pow -= int32((ref_time - fud_time) * self.sysclk_per_mu * ftw >> (32 - 16)) + if phase_mode == PHASE_MODE_TRACKING: + pow += int32(ref_time * self.sysclk_per_mu * ftw >> (32 - 16)) + self.continuous_phase_comp = pow + + self.write(AD9914_REG_POW, pow) + self.write(AD9914_REG_ASF, amplitude) + self.write(AD9914_FUD, 0) + + @portable(flags={"fast-math"}) + def frequency_to_ftw(self, frequency): + """Returns the frequency tuning word corresponding to the given + frequency. + """ + return round(float(int64(2)**32*frequency/self.sysclk)) + + @portable(flags={"fast-math"}) + def ftw_to_frequency(self, ftw): + """Returns the frequency corresponding to the given frequency tuning + word. + """ + return ftw*self.sysclk/int64(2)**32 + + @portable(flags={"fast-math"}) + def turns_to_pow(self, turns): + """Returns the phase offset word corresponding to the given phase + in turns.""" + return round(float(turns*2**16)) + + @portable(flags={"fast-math"}) + def pow_to_turns(self, pow): + """Returns the phase in turns corresponding to the given phase offset + word.""" + return pow/2**16 + + @portable(flags={"fast-math"}) + def amplitude_to_asf(self, amplitude): + """Returns amplitude scale factor corresponding to given amplitude.""" + return round(float(amplitude*0x0fff)) + + @portable(flags={"fast-math"}) + def asf_to_amplitude(self, asf): + """Returns the amplitude corresponding to the given amplitude scale + factor.""" + return asf/0x0fff + + @kernel + def set(self, frequency, phase=0.0, phase_mode=_PHASE_MODE_DEFAULT, + amplitude=1.0): + """Like ``set_mu``, but uses Hz and turns.""" + self.set_mu(self.frequency_to_ftw(frequency), + self.turns_to_pow(phase), phase_mode, + self.amplitude_to_asf(amplitude)) + + # Extended resolution functions + @kernel + def set_mu_x(self, xftw, amplitude=0x0fff): + delay_mu(-self.set_x_duration_mu) + + self.write(AD9914_GPIO, (1 << self.channel) << 1) + + # Enable programmable modulus. + # Note another undocumented "feature" of the AD9914: + # Programmable modulus breaks if the digital ramp enable bit is + # not set at the same time. + self.write(AD9914_REG_CFR2H, 0x0089) + self.write(AD9914_REG_DRGAL, xftw & 0xffff) + self.write(AD9914_REG_DRGAH, (xftw >> 16) & 0x7fff) + self.write(AD9914_REG_DRGFL, (xftw >> 31) & 0xffff) + self.write(AD9914_REG_DRGFH, (xftw >> 47) & 0xffff) + self.write(AD9914_REG_ASF, amplitude) + + self.write(AD9914_FUD, 0) + + @portable(flags={"fast-math"}) + def frequency_to_xftw(self, frequency): + """Returns the frequency tuning word corresponding to the given + frequency (extended resolution mode). + """ + return round(float(int64(2)**63*frequency/self.sysclk)) + + @portable(flags={"fast-math"}) + def xftw_to_frequency(self, xftw): + """Returns the frequency corresponding to the given frequency tuning + word (extended resolution mode). + """ + return xftw*self.sysclk/int64(2)**63 + + @kernel + def set_x(self, frequency, amplitude=1.0): + """Like ``set_mu_x``, but uses Hz and turns.""" + self.set_mu_x(self.frequency_to_xftw(frequency), + self.amplitude_to_asf(amplitude)) + From 663d8e66badc0aff33af55a4fc50468ebfc733a4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 May 2018 23:01:06 +0800 Subject: [PATCH 0720/2457] ad9914: optimize extended-resolution mode --- artiq/coredevice/ad9914.py | 55 ++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index a291cf6d6..ee5f5c45c 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -30,8 +30,6 @@ AD9914_REG_DRGBL = 0x15 AD9914_REG_DRGBH = 0x17 AD9914_REG_DRGAL = 0x19 AD9914_REG_DRGAH = 0x1b -AD9914_REG_FTWL = 0x2d -AD9914_REG_FTWH = 0x2f AD9914_REG_POW = 0x31 AD9914_REG_ASF = 0x33 AD9914_REG_USR0 = 0x6d @@ -71,10 +69,11 @@ class AD9914: self.write_duration_mu = 5 * self.rtio_period_mu self.dac_cal_duration_mu = 147000 * self.rtio_period_mu - self.init_duration_mu = 10 * self.write_duration_mu + self.dac_cal_duration_mu - self.init_sync_duration_mu = 18 * self.write_duration_mu + 2 * self.dac_cal_duration_mu - self.set_duration_mu = 6 * self.write_duration_mu + self.init_duration_mu = 13 * self.write_duration_mu + self.dac_cal_duration_mu + self.init_sync_duration_mu = 21 * self.write_duration_mu + 2 * self.dac_cal_duration_mu + self.set_duration_mu = 7 * self.write_duration_mu self.set_x_duration_mu = 7 * self.write_duration_mu + self.exit_x_duration_mu = 3 * self.write_duration_mu self.continuous_phase_comp = 0 @@ -93,9 +92,14 @@ class AD9914: delay_mu(-self.init_duration_mu) self.write(AD9914_GPIO, (1 << self.channel) << 1); + # Note another undocumented "feature" of the AD9914: + # Programmable modulus breaks if the digital ramp enable bit is + # not set at the same time. self.write(AD9914_REG_CFR1H, 0x0000) # Enable cosine output self.write(AD9914_REG_CFR2L, 0x8900) # Enable matched latency - self.write(AD9914_REG_CFR2H, 0x0080) # Enable profile mode + self.write(AD9914_REG_CFR2H, 0x0089) # Enable profile mode + programmable modulus + DRG + self.write(AD9914_REG_DRGAL, 0) # Programmable modulus A = 0 + self.write(AD9914_REG_DRGAH, 0) self.write(AD9914_REG_DRGBH, 0x8000) # Programmable modulus B == 2**31 self.write(AD9914_REG_DRGBL, 0x0000) self.write(AD9914_REG_ASF, 0x0fff) # Set amplitude to maximum @@ -141,7 +145,9 @@ class AD9914: self.write(AD9914_REG_CFR4H, 0x0005) # Disable DAC calibration self.write(AD9914_FUD, 0) self.write(AD9914_REG_CFR1H, 0x0000) # Enable cosine output - self.write(AD9914_REG_CFR2H, 0x0080) # Enable profile mode + self.write(AD9914_REG_CFR2H, 0x0089) # Enable profile mode + programmable modulus + DRG + self.write(AD9914_REG_DRGAL, 0) # Programmable modulus A = 0 + self.write(AD9914_REG_DRGAH, 0) self.write(AD9914_REG_DRGBH, 0x8000) # Programmable modulus B == 2**31 self.write(AD9914_REG_DRGBL, 0x0000) self.write(AD9914_REG_ASF, 0x0fff) # Set amplitude to maximum @@ -196,8 +202,8 @@ class AD9914: self.write(AD9914_GPIO, (1 << self.channel) << 1) - self.write(AD9914_REG_FTWL, ftw & 0xffff) - self.write(AD9914_REG_FTWH, (ftw >> 16) & 0xffff) + self.write(AD9914_REG_DRGFL, ftw & 0xffff) + self.write(AD9914_REG_DRGFL, (ftw >> 16) & 0xffff) # We need the RTIO fine timestamp clock to be phase-locked # to DDS SYSCLK, and divided by an integer self.sysclk_per_mu. @@ -265,18 +271,22 @@ class AD9914: self.turns_to_pow(phase), phase_mode, self.amplitude_to_asf(amplitude)) - # Extended resolution functions + # Extended-resolution functions @kernel def set_mu_x(self, xftw, amplitude=0x0fff): + """Set the DDS frequency and amplitude with an extended-resolution + (63-bit) frequency tuning word. + + Phase control is not implemented in this mode; the phase offset + can assume any value. + + After this function has been called, exit extended-resolution mode + before calling functions that use standard-resolution mode. + """ delay_mu(-self.set_x_duration_mu) self.write(AD9914_GPIO, (1 << self.channel) << 1) - # Enable programmable modulus. - # Note another undocumented "feature" of the AD9914: - # Programmable modulus breaks if the digital ramp enable bit is - # not set at the same time. - self.write(AD9914_REG_CFR2H, 0x0089) self.write(AD9914_REG_DRGAL, xftw & 0xffff) self.write(AD9914_REG_DRGAH, (xftw >> 16) & 0x7fff) self.write(AD9914_REG_DRGFL, (xftw >> 31) & 0xffff) @@ -285,6 +295,14 @@ class AD9914: self.write(AD9914_FUD, 0) + @kernel + def exit_x(self): + """Exits extended-resolution mode.""" + delay_mu(-self.exit_x_duration_mu) + self.write(AD9914_GPIO, (1 << self.channel) << 1) + self.write(AD9914_REG_DRGAL, 0) + self.write(AD9914_REG_DRGAH, 0) + @portable(flags={"fast-math"}) def frequency_to_xftw(self, frequency): """Returns the frequency tuning word corresponding to the given @@ -301,7 +319,10 @@ class AD9914: @kernel def set_x(self, frequency, amplitude=1.0): - """Like ``set_mu_x``, but uses Hz and turns.""" + """Like ``set_mu_x``, but uses Hz and turns. + + Note that the precision of ``float`` is less than the precision + of the extended frequency tuning word. + """ self.set_mu_x(self.frequency_to_xftw(frequency), self.amplitude_to_asf(amplitude)) - From 3027951dd85d642b235dec57b1309ea65a79c502 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 May 2018 23:29:35 +0800 Subject: [PATCH 0721/2457] integrate new AD9914 driver moninj, analyzer, docs, examples, tests. --- RELEASE_NOTES.rst | 3 + artiq/coredevice/__init__.py | 8 +- artiq/coredevice/comm_analyzer.py | 38 +- artiq/coredevice/dds.py | 401 ------------------ artiq/coredevice/exceptions.py | 7 - artiq/dashboard/moninj.py | 8 +- artiq/examples/kc705_nist_clock/device_db.py | 29 +- .../kc705_nist_clock/repository/dds_setter.py | 4 +- .../kc705_nist_clock/repository/dds_test.py | 7 +- .../repository/photon_histogram.py | 8 +- artiq/examples/master/device_db.py | 29 +- artiq/gateware/rtio/phy/dds.py | 13 +- artiq/test/coredevice/test_rtio.py | 10 +- doc/manual/core_drivers_reference.rst | 18 +- doc/manual/rtio.rst | 2 +- 15 files changed, 70 insertions(+), 515 deletions(-) delete mode 100644 artiq/coredevice/dds.py diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 0008a825a..f329d0c8d 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -32,6 +32,9 @@ ARTIQ-4 to the new bus. * The ``ad5360`` coredevice driver has been renamed to ``ad53xx`` and the API has changed to better support Zotino. +* ``artiq.coredevice.dds`` has been renamed to ``artiq.coredevice.ad9914`` and + simplified. DDS batch mode is no longer supported. The ``core_dds`` device + is no longer necessary. ARTIQ-3 diff --git a/artiq/coredevice/__init__.py b/artiq/coredevice/__init__.py index fbec3d901..dced6ef0a 100644 --- a/artiq/coredevice/__init__.py +++ b/artiq/coredevice/__init__.py @@ -1,9 +1,3 @@ -from artiq.coredevice import exceptions, dds, spi2 from artiq.coredevice.exceptions import (RTIOUnderflow, RTIOOverflow) -from artiq.coredevice.dds import (PHASE_MODE_CONTINUOUS, PHASE_MODE_ABSOLUTE, - PHASE_MODE_TRACKING) -__all__ = [] -__all__ += ["RTIOUnderflow", "RTIOOverflow"] -__all__ += ["PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE", - "PHASE_MODE_TRACKING"] +__all__ = ["RTIOUnderflow", "RTIOOverflow"] diff --git a/artiq/coredevice/comm_analyzer.py b/artiq/coredevice/comm_analyzer.py index 1da425730..6f432ea77 100644 --- a/artiq/coredevice/comm_analyzer.py +++ b/artiq/coredevice/comm_analyzer.py @@ -211,9 +211,8 @@ class TTLClockGenHandler: class DDSHandler: - def __init__(self, vcd_manager, dds_type, onehot_sel, sysclk): + def __init__(self, vcd_manager, onehot_sel, sysclk): self.vcd_manager = vcd_manager - self.dds_type = dds_type self.onehot_sel = onehot_sel self.sysclk = sysclk @@ -227,9 +226,8 @@ class DDSHandler: self.vcd_manager.get_channel(name + "/frequency", 64) dds_channel["vcd_phase"] = \ self.vcd_manager.get_channel(name + "/phase", 64) - if self.dds_type == "DDSChannelAD9914": - dds_channel["ftw"] = [None, None] - dds_channel["pow"] = None + dds_channel["ftw"] = [None, None] + dds_channel["pow"] = None self.dds_channels[dds_channel_nr] = dds_channel def _gpio_to_channels(self, gpio): @@ -252,9 +250,9 @@ class DDSHandler: self.selected_dds_channels = self._gpio_to_channels(message.data) for dds_channel_nr in self.selected_dds_channels: dds_channel = self.dds_channels[dds_channel_nr] - if message.address == 0x2d: + if message.address == 0x11: dds_channel["ftw"][0] = message.data - elif message.address == 0x2f: + elif message.address == 0x13: dds_channel["ftw"][1] = message.data elif message.address == 0x31: dds_channel["pow"] = message.data @@ -273,8 +271,7 @@ class DDSHandler: logger.debug("DDS write @%d 0x%04x to 0x%02x, selected channels: %s", message.timestamp, message.data, message.address, self.selected_dds_channels) - if self.dds_type == "DDSChannelAD9914": - self._decode_ad9914_write(message) + self._decode_ad9914_write(message) class WishboneHandler: @@ -444,16 +441,17 @@ def get_vcd_log_channels(log_channel, messages): def get_single_device_argument(devices, module, cls, argument): - ref_period = None + found = None for desc in devices.values(): if isinstance(desc, dict) and desc["type"] == "local": if (desc["module"] == module and desc["class"] in cls): - if ref_period is None: - ref_period = desc["arguments"][argument] - else: - return None # more than one device found - return ref_period + value = desc["arguments"][argument] + if found is None: + found = value + elif value != found: + return None # more than one value/device found + return found def get_ref_period(devices): @@ -462,8 +460,8 @@ def get_ref_period(devices): def get_dds_sysclk(devices): - return get_single_device_argument(devices, "artiq.coredevice.dds", - ("DDSGroupAD9914",), "sysclk") + return get_single_device_argument(devices, "artiq.coredevice.ad9914", + ("ad9914",), "sysclk") def create_channel_handlers(vcd_manager, devices, ref_period, @@ -479,14 +477,12 @@ def create_channel_handlers(vcd_manager, devices, ref_period, and desc["class"] == "TTLClockGen"): channel = desc["arguments"]["channel"] channel_handlers[channel] = TTLClockGenHandler(vcd_manager, name, ref_period) - if (desc["module"] == "artiq.coredevice.dds" - and desc["class"] in {"DDSChannelAD9914"}): + if (desc["module"] == "artiq.coredevice.ad9914" + and desc["class"] == "AD9914"): dds_bus_channel = desc["arguments"]["bus_channel"] dds_channel = desc["arguments"]["channel"] if dds_bus_channel in channel_handlers: dds_handler = channel_handlers[dds_bus_channel] - if dds_handler.dds_type != desc["class"]: - raise ValueError("All DDS channels must have the same type") else: dds_handler = DDSHandler(vcd_manager, desc["class"], dds_onehot_sel, dds_sysclk) diff --git a/artiq/coredevice/dds.py b/artiq/coredevice/dds.py deleted file mode 100644 index 5c7293edf..000000000 --- a/artiq/coredevice/dds.py +++ /dev/null @@ -1,401 +0,0 @@ -""" -Drivers for direct digital synthesis (DDS) chips on RTIO. - -Output event replacement is not supported and issuing commands at the same -time is an error. -""" - - -from artiq.language.core import * -from artiq.language.types import * -from artiq.language.units import * -from artiq.coredevice.rtio import rtio_output -from artiq.coredevice.exceptions import DDSError - -from numpy import int32, int64 - - -_PHASE_MODE_DEFAULT = -1 -PHASE_MODE_CONTINUOUS = 0 -PHASE_MODE_ABSOLUTE = 1 -PHASE_MODE_TRACKING = 2 - - -class DDSParams: - def __init__(self): - self.bus_channel = 0 - self.channel = 0 - self.ftw = 0 - self.pow = 0 - self.phase_mode = 0 - self.amplitude = 0 - - -class BatchContextManager: - kernel_invariants = {"core", "core_dds", "params"} - - def __init__(self, core_dds): - self.core_dds = core_dds - self.core = self.core_dds.core - self.active = False - self.params = [DDSParams() for _ in range(16)] - self.count = 0 - self.ref_time = int64(0) - - @kernel - def __enter__(self): - """Starts a DDS command batch. All DDS commands are buffered - after this call, until ``batch_exit`` is called. - - The time of execution of the DDS commands is the time cursor position - when the batch is entered.""" - if self.active: - raise DDSError("DDS batch entered twice") - - self.active = True - self.count = 0 - self.ref_time = now_mu() - - @kernel - def append(self, bus_channel, channel, ftw, pow, phase_mode, amplitude): - if self.count == len(self.params): - raise DDSError("Too many commands in DDS batch") - - params = self.params[self.count] - params.bus_channel = bus_channel - params.channel = channel - params.ftw = ftw - params.pow = pow - params.phase_mode = phase_mode - params.amplitude = amplitude - self.count += 1 - - @kernel - def __exit__(self, type, value, traceback): - """Ends a DDS command batch. All buffered DDS commands are issued - on the bus.""" - if not self.active: - raise DDSError("DDS batch exited twice") - - self.active = False - at_mu(self.ref_time - self.core_dds.batch_duration_mu()) - for i in range(self.count): - param = self.params[i] - self.core_dds.program(self.ref_time, - param.bus_channel, param.channel, param.ftw, - param.pow, param.phase_mode, param.amplitude) - - -class DDSGroup: - """Core device Direct Digital Synthesis (DDS) driver. - - Gives access to the DDS functionality of the core device. - - :param sysclk: DDS system frequency. The DDS system clock must be a - phase-locked multiple of the RTIO clock. - """ - - kernel_invariants = {"core", "sysclk", "batch"} - - def __init__(self, dmgr, sysclk, core_device="core"): - self.core = dmgr.get(core_device) - self.sysclk = sysclk - self.batch = BatchContextManager(self) - - @kernel - def batch_duration_mu(self): - raise NotImplementedError - - @kernel - def init(self, bus_channel, channel): - raise NotImplementedError - - @kernel - def program(self, ref_time, bus_channel, channel, ftw, pow, phase_mode, amplitude): - raise NotImplementedError - - @kernel - def set(self, bus_channel, channel, ftw, pow, phase_mode, amplitude): - if self.batch.active: - self.batch.append(bus_channel, channel, ftw, pow, phase_mode, amplitude) - else: - ref_time = now_mu() - at_mu(ref_time - self.program_duration_mu) - self.program(ref_time, - bus_channel, channel, ftw, pow, phase_mode, amplitude) - - @portable(flags={"fast-math"}) - def frequency_to_ftw(self, frequency): - """Returns the frequency tuning word corresponding to the given - frequency. - """ - return round(float(int64(2)**32*frequency/self.sysclk)) - - @portable(flags={"fast-math"}) - def ftw_to_frequency(self, ftw): - """Returns the frequency corresponding to the given frequency tuning - word. - """ - return ftw*self.sysclk/int64(2)**32 - - @portable(flags={"fast-math"}) - def turns_to_pow(self, turns): - """Returns the phase offset word corresponding to the given phase - in turns.""" - return round(float(turns*2**self.pow_width)) - - @portable(flags={"fast-math"}) - def pow_to_turns(self, pow): - """Returns the phase in turns corresponding to the given phase offset - word.""" - return pow/2**self.pow_width - - @portable(flags={"fast-math"}) - def amplitude_to_asf(self, amplitude): - """Returns amplitude scale factor corresponding to given amplitude.""" - return round(float(amplitude*0x0fff)) - - @portable(flags={"fast-math"}) - def asf_to_amplitude(self, asf): - """Returns the amplitude corresponding to the given amplitude scale - factor.""" - return asf/0x0fff - - -class DDSChannel: - """Core device Direct Digital Synthesis (DDS) channel driver. - - Controls one DDS channel managed directly by the core device's runtime. - - This class should not be used directly, instead, use the chip-specific - drivers such as ``DDSChannelAD9914``. - - The time cursor is not modified by any function in this class. - - :param bus: name of the DDS bus device that this DDS is connected to. - :param channel: channel number of the DDS device to control. - """ - - kernel_invariants = { - "core", "core_dds", "bus_channel", "channel", - } - - def __init__(self, dmgr, bus_channel, channel, core_dds_device="core_dds"): - self.core_dds = dmgr.get(core_dds_device) - self.core = self.core_dds.core - self.bus_channel = bus_channel - self.channel = channel - self.phase_mode = PHASE_MODE_CONTINUOUS - - @kernel - def init(self): - """Resets and initializes the DDS channel. - - This needs to be done for each DDS channel before it can be used, and - it is recommended to use the startup kernel for this. - - This function cannot be used in a batch; the correct way of - initializing multiple DDS channels is to call this function - sequentially with a delay between the calls. 2ms provides a good - timing margin.""" - self.core_dds.init(self.bus_channel, self.channel) - - @kernel - def set_phase_mode(self, phase_mode): - """Sets the phase mode of the DDS channel. Supported phase modes are: - - * ``PHASE_MODE_CONTINUOUS``: the phase accumulator is unchanged when - switching frequencies. The DDS phase is the sum of the phase - accumulator and the phase offset. The only discrete jumps in the - DDS output phase come from changes to the phase offset. - - * ``PHASE_MODE_ABSOLUTE``: the phase accumulator is reset when - switching frequencies. Thus, the phase of the DDS at the time of - the frequency change is equal to the phase offset. - - * ``PHASE_MODE_TRACKING``: when switching frequencies, the phase - accumulator is set to the value it would have if the DDS had been - running at the specified frequency since the start of the - experiment. - """ - self.phase_mode = phase_mode - - @kernel - def set_mu(self, frequency, phase=0, phase_mode=_PHASE_MODE_DEFAULT, - amplitude=0x0fff): - """Sets the DDS channel to the specified frequency and phase. - - This uses machine units (FTW and POW). The frequency tuning word width - is 32, whereas the phase offset word width depends on the type of DDS - chip and can be retrieved via the ``pow_width`` attribute. The amplitude - width is 12. - - The "frequency update" pulse is sent to the DDS with a fixed latency - with respect to the current position of the time cursor. - - :param frequency: frequency to generate. - :param phase: adds an offset, in turns, to the phase. - :param phase_mode: if specified, overrides the default phase mode set - by ``set_phase_mode`` for this call. - """ - if phase_mode == _PHASE_MODE_DEFAULT: - phase_mode = self.phase_mode - self.core_dds.set(self.bus_channel, self.channel, frequency, phase, phase_mode, amplitude) - - @kernel - def set(self, frequency, phase=0.0, phase_mode=_PHASE_MODE_DEFAULT, - amplitude=1.0): - """Like ``set_mu``, but uses Hz and turns.""" - self.set_mu(self.core_dds.frequency_to_ftw(frequency), - self.core_dds.turns_to_pow(phase), phase_mode, - self.core_dds.amplitude_to_asf(amplitude)) - - -AD9914_REG_CFR1L = 0x01 -AD9914_REG_CFR1H = 0x03 -AD9914_REG_CFR2L = 0x05 -AD9914_REG_CFR2H = 0x07 -AD9914_REG_CFR3L = 0x09 -AD9914_REG_CFR3H = 0x0b -AD9914_REG_CFR4L = 0x0d -AD9914_REG_CFR4H = 0x0f -AD9914_REG_FTWL = 0x2d -AD9914_REG_FTWH = 0x2f -AD9914_REG_POW = 0x31 -AD9914_REG_ASF = 0x33 -AD9914_REG_USR0 = 0x6d -AD9914_FUD = 0x80 -AD9914_GPIO = 0x81 - - -class DDSGroupAD9914(DDSGroup): - """Driver for AD9914 DDS chips. See ``DDSGroup`` for a description - of the functionality.""" - kernel_invariants = DDSGroup.kernel_invariants.union({ - "pow_width", "rtio_period_mu", "sysclk_per_mu", "write_duration_mu", "dac_cal_duration_mu", - "init_duration_mu", "init_sync_duration_mu", "program_duration_mu", - "first_dds_bus_channel", "dds_channel_count", "continuous_phase_comp" - }) - - pow_width = 16 - - def __init__(self, *args, first_dds_bus_channel, dds_bus_count, dds_channel_count, **kwargs): - super().__init__(*args, **kwargs) - - self.first_dds_bus_channel = first_dds_bus_channel - self.dds_bus_count = dds_bus_count - self.dds_channel_count = dds_channel_count - - self.rtio_period_mu = int64(8) - self.sysclk_per_mu = int32(self.sysclk * self.core.ref_period) - - self.write_duration_mu = 5 * self.rtio_period_mu - self.dac_cal_duration_mu = 147000 * self.rtio_period_mu - self.init_duration_mu = 8 * self.write_duration_mu + self.dac_cal_duration_mu - self.init_sync_duration_mu = 16 * self.write_duration_mu + 2 * self.dac_cal_duration_mu - self.program_duration_mu = 6 * self.write_duration_mu - - self.continuous_phase_comp = [0] * (self.dds_bus_count * self.dds_channel_count) - - @kernel - def batch_duration_mu(self): - return self.batch.count * (self.program_duration_mu + - self.write_duration_mu) # + FUD time - - @kernel - def write(self, bus_channel, addr, data): - rtio_output(now_mu(), bus_channel, addr, data) - delay_mu(self.write_duration_mu) - - @kernel - def init(self, bus_channel, channel): - delay_mu(-self.init_duration_mu) - self.write(bus_channel, AD9914_GPIO, (1 << channel) << 1); - - self.write(bus_channel, AD9914_REG_CFR1H, 0x0000) # Enable cosine output - self.write(bus_channel, AD9914_REG_CFR2L, 0x8900) # Enable matched latency - self.write(bus_channel, AD9914_REG_CFR2H, 0x0080) # Enable profile mode - self.write(bus_channel, AD9914_REG_ASF, 0x0fff) # Set amplitude to maximum - self.write(bus_channel, AD9914_REG_CFR4H, 0x0105) # Enable DAC calibration - self.write(bus_channel, AD9914_FUD, 0) - delay_mu(self.dac_cal_duration_mu) - self.write(bus_channel, AD9914_REG_CFR4H, 0x0005) # Disable DAC calibration - self.write(bus_channel, AD9914_FUD, 0) - - @kernel - def init_sync(self, bus_channel, channel, sync_delay): - delay_mu(-self.init_sync_duration_mu) - self.write(bus_channel, AD9914_GPIO, (1 << channel) << 1) - - self.write(bus_channel, AD9914_REG_CFR4H, 0x0105) # Enable DAC calibration - self.write(bus_channel, AD9914_FUD, 0) - delay_mu(self.dac_cal_duration_mu) - self.write(bus_channel, AD9914_REG_CFR4H, 0x0005) # Disable DAC calibration - self.write(bus_channel, AD9914_FUD, 0) - self.write(bus_channel, AD9914_REG_CFR2L, 0x8b00) # Enable matched latency and sync_out - self.write(bus_channel, AD9914_FUD, 0) - # Set cal with sync and set sync_out and sync_in delay - self.write(bus_channel, AD9914_REG_USR0, 0x0840 | (sync_delay & 0x3f)) - self.write(bus_channel, AD9914_FUD, 0) - self.write(bus_channel, AD9914_REG_CFR4H, 0x0105) # Enable DAC calibration - self.write(bus_channel, AD9914_FUD, 0) - delay_mu(self.dac_cal_duration_mu) - self.write(bus_channel, AD9914_REG_CFR4H, 0x0005) # Disable DAC calibration - self.write(bus_channel, AD9914_FUD, 0) - self.write(bus_channel, AD9914_REG_CFR1H, 0x0000) # Enable cosine output - self.write(bus_channel, AD9914_REG_CFR2H, 0x0080) # Enable profile mode - self.write(bus_channel, AD9914_REG_ASF, 0x0fff) # Set amplitude to maximum - self.write(bus_channel, AD9914_FUD, 0) - - @kernel - def program(self, ref_time, bus_channel, channel, ftw, pow, phase_mode, amplitude): - self.write(bus_channel, AD9914_GPIO, (1 << channel) << 1) - - self.write(bus_channel, AD9914_REG_FTWL, ftw & 0xffff) - self.write(bus_channel, AD9914_REG_FTWH, (ftw >> 16) & 0xffff) - - # We need the RTIO fine timestamp clock to be phase-locked - # to DDS SYSCLK, and divided by an integer self.sysclk_per_mu. - dds_bus_index = bus_channel - self.first_dds_bus_channel - phase_comp_index = dds_bus_index * self.dds_channel_count + channel - if phase_mode == PHASE_MODE_CONTINUOUS: - # Do not clear phase accumulator on FUD - # Disable autoclear phase accumulator and enables OSK. - self.write(bus_channel, AD9914_REG_CFR1L, 0x0108) - pow += self.continuous_phase_comp[phase_comp_index] - else: - # Clear phase accumulator on FUD - # Enable autoclear phase accumulator and enables OSK. - self.write(bus_channel, AD9914_REG_CFR1L, 0x2108) - fud_time = now_mu() + 2 * self.write_duration_mu - pow -= int32((ref_time - fud_time) * self.sysclk_per_mu * ftw >> (32 - self.pow_width)) - if phase_mode == PHASE_MODE_TRACKING: - pow += int32(ref_time * self.sysclk_per_mu * ftw >> (32 - self.pow_width)) - self.continuous_phase_comp[phase_comp_index] = pow - - self.write(bus_channel, AD9914_REG_POW, pow) - self.write(bus_channel, AD9914_REG_ASF, amplitude) - self.write(bus_channel, AD9914_FUD, 0) - - -class DDSChannelAD9914(DDSChannel): - """Driver for AD9914 DDS chips. See ``DDSChannel`` for a description - of the functionality.""" - @kernel - def init_sync(self, sync_delay=0): - """Resets and initializes the DDS channel as well as configures - the AD9914 DDS for synchronisation. The synchronisation procedure - follows the steps outlined in the AN-1254 application note. - - This needs to be done for each DDS channel before it can be used, and - it is recommended to use the startup kernel for this. - - This function cannot be used in a batch; the correct way of - initializing multiple DDS channels is to call this function - sequentially with a delay between the calls. 10ms provides a good - timing margin. - - :param sync_delay: integer from 0 to 0x3f that sets the value of - SYNC_OUT (bits 3-5) and SYNC_IN (bits 0-2) delay ADJ bits. - """ - self.core_dds.init_sync(self.bus_channel, self.channel, sync_delay) diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index f0ce65291..8264c7a55 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -102,13 +102,6 @@ class DMAError(Exception): artiq_builtin = True -class DDSError(Exception): - """Raised when attempting to start a DDS batch while already in a batch, - when too many commands are batched, and when DDS channel settings are - incorrect. - """ - - class WatchdogExpired(Exception): """Raised when a watchdog expires.""" diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py index 476be6b6a..d36807da3 100644 --- a/artiq/dashboard/moninj.py +++ b/artiq/dashboard/moninj.py @@ -215,13 +215,11 @@ def setup_from_ddb(ddb): force_out = v["class"] == "TTLOut" widget = _WidgetDesc(k, comment, _TTLWidget, (channel, force_out, k)) description.add(widget) - elif (v["module"] == "artiq.coredevice.dds" - and v["class"] == "DDSGroupAD9914"): - dds_sysclk = v["arguments"]["sysclk"] - elif (v["module"] == "artiq.coredevice.dds" - and v["class"] == "DDSChannelAD9914"): + elif (v["module"] == "artiq.coredevice.ad9914" + and v["class"] == "AD9914"): bus_channel = v["arguments"]["bus_channel"] channel = v["arguments"]["channel"] + dds_sysclk = v["arguments"]["sysclk"] widget = _WidgetDesc(k, comment, _DDSWidget, (bus_channel, channel, k)) description.add(widget) elif ( (v["module"] == "artiq.coredevice.ad53xx" and v["class"] == "AD53XX") diff --git a/artiq/examples/kc705_nist_clock/device_db.py b/artiq/examples/kc705_nist_clock/device_db.py index b51a330c9..78b21e82d 100644 --- a/artiq/examples/kc705_nist_clock/device_db.py +++ b/artiq/examples/kc705_nist_clock/device_db.py @@ -27,17 +27,6 @@ device_db = { "module": "artiq.coredevice.dma", "class": "CoreDMA" }, - "core_dds": { - "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSGroupAD9914", - "arguments": { - "sysclk": 3e9, - "first_dds_bus_channel": 39, - "dds_bus_count": 2, - "dds_channel_count": 3 - } - }, "i2c_switch": { "type": "local", @@ -333,22 +322,22 @@ device_db = { # AD9914 DDS "dds0": { "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 39, "channel": 0}, + "module": "artiq.coredevice.ad9914", + "class": "AD9914", + "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 0}, "comment": "Comments work in DDS panel as well" }, "dds1": { "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 39, "channel": 1} + "module": "artiq.coredevice.ad9914", + "class": "AD9914", + "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 1} }, "dds2": { "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 39, "channel": 2} + "module": "artiq.coredevice.ad9914", + "class": "AD9914", + "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 2} }, # Aliases diff --git a/artiq/examples/kc705_nist_clock/repository/dds_setter.py b/artiq/examples/kc705_nist_clock/repository/dds_setter.py index ef13b1bd3..c5490d6b2 100644 --- a/artiq/examples/kc705_nist_clock/repository/dds_setter.py +++ b/artiq/examples/kc705_nist_clock/repository/dds_setter.py @@ -14,8 +14,8 @@ class DDSSetter(EnvExperiment): for k, v in sorted(device_db.items(), key=itemgetter(0)): if (isinstance(v, dict) and v["type"] == "local" - and v["module"] == "artiq.coredevice.dds" - and v["class"] in {"DDSChannelAD9914"}): + and v["module"] == "artiq.coredevice.ad9914" + and v["class"] == "AD9914"): self.dds[k] = { "driver": self.get_device(k), "frequency": self.get_argument( diff --git a/artiq/examples/kc705_nist_clock/repository/dds_test.py b/artiq/examples/kc705_nist_clock/repository/dds_test.py index ec57f9e52..5f93b2bc1 100644 --- a/artiq/examples/kc705_nist_clock/repository/dds_test.py +++ b/artiq/examples/kc705_nist_clock/repository/dds_test.py @@ -6,7 +6,6 @@ class DDSTest(EnvExperiment): def build(self): self.setattr_device("core") - self.setattr_device("core_dds") self.setattr_device("dds0") self.setattr_device("dds1") self.setattr_device("dds2") @@ -19,9 +18,9 @@ class DDSTest(EnvExperiment): def run(self): self.core.reset() delay(200*us) - with self.core_dds.batch: - self.dds1.set(120*MHz) - self.dds2.set(200*MHz) + self.dds1.set(120*MHz) + delay(10*us) + self.dds2.set(200*MHz) delay(1*us) for i in range(10000): diff --git a/artiq/examples/kc705_nist_clock/repository/photon_histogram.py b/artiq/examples/kc705_nist_clock/repository/photon_histogram.py index f58a59a10..6d860db0e 100644 --- a/artiq/examples/kc705_nist_clock/repository/photon_histogram.py +++ b/artiq/examples/kc705_nist_clock/repository/photon_histogram.py @@ -6,7 +6,6 @@ class PhotonHistogram(EnvExperiment): def build(self): self.setattr_device("core") - self.setattr_device("core_dds") self.setattr_device("bd_dds") self.setattr_device("bd_sw") self.setattr_device("bdd_dds") @@ -22,9 +21,10 @@ class PhotonHistogram(EnvExperiment): @kernel def program_cooling(self): - with self.core_dds.batch: - self.bd_dds.set(200*MHz) - self.bdd_dds.set(300*MHz) + delay_mu(-self.bd_dds.set_duration_mu) + self.bd_dds.set(200*MHz) + delay_mu(self.bd_dds.set_duration_mu) + self.bdd_dds.set(300*MHz) @kernel def cool_detect(self): diff --git a/artiq/examples/master/device_db.py b/artiq/examples/master/device_db.py index 9150e2b0a..69ed74c8f 100644 --- a/artiq/examples/master/device_db.py +++ b/artiq/examples/master/device_db.py @@ -28,17 +28,6 @@ device_db = { "module": "artiq.coredevice.dma", "class": "CoreDMA" }, - "core_dds": { - "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSGroupAD9914", - "arguments": { - "sysclk": 3e9, - "first_dds_bus_channel": 39, - "dds_bus_count": 2, - "dds_channel_count": 3 - } - }, "i2c_switch": { "type": "local", @@ -334,22 +323,22 @@ device_db = { # AD9914 DDS "dds0": { "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 39, "channel": 0}, + "module": "artiq.coredevice.ad9914", + "class": "AD9914", + "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 0}, "comment": "Comments work in DDS panel as well" }, "dds1": { "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 39, "channel": 1} + "module": "artiq.coredevice.ad9914", + "class": "AD9914", + "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 1} }, "dds2": { "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 39, "channel": 2} + "module": "artiq.coredevice.ad9914", + "class": "AD9914", + "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 2} }, # Aliases diff --git a/artiq/gateware/rtio/phy/dds.py b/artiq/gateware/rtio/phy/dds.py index d0c58ccfa..7e5011bd4 100644 --- a/artiq/gateware/rtio/phy/dds.py +++ b/artiq/gateware/rtio/phy/dds.py @@ -4,8 +4,8 @@ from artiq.gateware import ad9_dds from artiq.gateware.rtio.phy.wishbone import RT2WB -class _AD9_DDS(Module): - def __init__(self, ftw_base, pads, nchannels, onehot=False, **kwargs): +class AD9914(Module): + def __init__(self, pads, nchannels, onehot=False, **kwargs): self.submodules._ll = ClockDomainsRenamer("rio_phy")( ad9_dds.AD9_DDS(pads, **kwargs)) self.submodules._rt2wb = RT2WB(len(pads.a)+1, self._ll.bus) @@ -38,13 +38,13 @@ class _AD9_DDS(Module): if len(pads.d) == 8: self.sync.rio_phy += \ If(selected(c), [ - If(current_address == ftw_base+i, + If(current_address == 0x11+i, ftw[i*8:(i+1)*8].eq(current_data)) for i in range(4)]) elif len(pads.d) == 16: self.sync.rio_phy += \ If(selected(c), [ - If(current_address == ftw_base+2*i, + If(current_address == 0x11+2*i, ftw[i*16:(i+1)*16].eq(current_data)) for i in range(2)]) else: @@ -54,8 +54,3 @@ class _AD9_DDS(Module): self.sync.rio_phy += If(current_address == 2**len(pads.a), [ If(selected(c), probe.eq(ftw)) for c, (probe, ftw) in enumerate(zip(self.probes, ftws))]) - - -class AD9914(_AD9_DDS): - def __init__(self, *args, **kwargs): - _AD9_DDS.__init__(self, 0x2d, *args, **kwargs) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 371c5eb18..4069e046a 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -127,7 +127,6 @@ class PulseRate(EnvExperiment): class PulseRateDDS(EnvExperiment): def build(self): self.setattr_device("core") - self.setattr_device("core_dds") self.setattr_device("dds0") self.setattr_device("dds1") @@ -135,14 +134,15 @@ class PulseRateDDS(EnvExperiment): def run(self): self.core.reset() dt = self.core.seconds_to_mu(5*us) - freq = self.core_dds.frequency_to_ftw(100*MHz) + freq = self.dds0.frequency_to_ftw(100*MHz) while True: delay(10*ms) for i in range(1250): try: - with self.core_dds.batch: - self.dds0.set_mu(freq) - self.dds1.set_mu(freq) + delay_mu(-self.dds0.set_duration_mu) + self.dds0.set_mu(freq) + delay_mu(self.dds0.set_duration_mu) + self.dds1.set_mu(freq) delay_mu(dt) except RTIOUnderflow: dt += 100 diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index c54a44c0d..6bce75560 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -75,16 +75,22 @@ RF generation drivers .. automodule:: artiq.coredevice.urukul :members: +:mod:`artiq.coredevice.ad9910` module ++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.ad9910 + :members: + :mod:`artiq.coredevice.ad9912` module +++++++++++++++++++++++++++++++++++++ .. automodule:: artiq.coredevice.ad9912 :members: -:mod:`artiq.coredevice.ad9910` module -+++++++++++++++++++++++++++++++++++++ +:mod:`artiq.coredevice.ad9914` module +++++++++++++++++++++++++++++++++++ -.. automodule:: artiq.coredevice.ad9910 +.. automodule:: artiq.coredevice.ad9914 :members: :mod:`artiq.coredevice.spline` module @@ -99,12 +105,6 @@ RF generation drivers .. automodule:: artiq.coredevice.sawg :members: -:mod:`artiq.coredevice.dds` module -++++++++++++++++++++++++++++++++++ - -.. automodule:: artiq.coredevice.dds - :members: - DAC/ADC drivers --------------- diff --git a/doc/manual/rtio.rst b/doc/manual/rtio.rst index 33c03c10f..1abdd25a3 100644 --- a/doc/manual/rtio.rst +++ b/doc/manual/rtio.rst @@ -76,7 +76,7 @@ The sequence is exactly equivalent to:: ttl.pulse(2*us) -The :meth:`artiq.coredevice.ttl.TTLOut.pulse` method advances the timeline cursor (using ``delay()``) while other methods such as :meth:`artiq.coredevice.ttl.TTLOut.on`, :meth:`artiq.coredevice.ttl.TTLOut.off`, :meth:`artiq.coredevice.dds._DDSGeneric.set`. The latter are called *zero-duration* methods. +The :meth:`artiq.coredevice.ttl.TTLOut.pulse` method advances the timeline cursor (using ``delay()``) while other methods such as :meth:`artiq.coredevice.ttl.TTLOut.on`, :meth:`artiq.coredevice.ttl.TTLOut.off`, :meth:`artiq.coredevice.ad9914.set`. The latter are called *zero-duration* methods. Underflow exceptions -------------------- From 00cb31b80440432b40cc32863321680153894ed3 Mon Sep 17 00:00:00 2001 From: hartytp Date: Sun, 13 May 2018 17:00:57 +0100 Subject: [PATCH 0722/2457] sampler: remove v_ref parameter (#988) --- artiq/coredevice/sampler.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/artiq/coredevice/sampler.py b/artiq/coredevice/sampler.py index 66c8d45ad..ce8817a4c 100644 --- a/artiq/coredevice/sampler.py +++ b/artiq/coredevice/sampler.py @@ -16,17 +16,17 @@ SPI_CS_PGIA = 1 # separate SPI bus, CS used as RCLK @portable -def adc_mu_to_volt(data, gain=0, v_ref=5.): +def adc_mu_to_volt(data, gain=0): """Convert ADC data in machine units to Volts. :param data: 16 bit signed ADC word :param gain: PGIA gain setting (0: 1, ..., 3: 1000) - :param v_ref: Reference voltage in Volts :return: Voltage in Volts """ + input_span = 20. for i in range(gain): - v_ref /= 10. - volt_per_lsb = v_ref/(1 << 15) + input_span /= 10. + volt_per_lsb = input_span/(1 << 16) return data*volt_per_lsb @@ -42,7 +42,7 @@ class Sampler: :param div: SPI clock divider (default: 8) :param core_device: Core device name """ - kernel_invariants = {"bus_adc", "bus_pgia", "core", "cnv", "div", "v_ref"} + kernel_invariants = {"bus_adc", "bus_pgia", "core", "cnv", "div"} def __init__(self, dmgr, spi_adc_device, spi_pgia_device, cnv_device, div=8, core_device="core"): @@ -52,7 +52,6 @@ class Sampler: self.cnv = dmgr.get(cnv_device) self.div = div self.gains = 0x0000 - self.v_ref = 10. # 5 Volt reference, 0.5 AFE diff gain @kernel def init(self): @@ -135,4 +134,4 @@ class Sampler: for i in range(n): channel = i + 8 - len(data) gain = (self.gains >> (channel*2)) & 0b11 - data[i] = adc_mu_to_volt(adc_data[i], gain, self.v_ref) + data[i] = adc_mu_to_volt(adc_data[i], gain) From 194d6462eec5483c31e90e86642b0bfa8e14a884 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 14 May 2018 00:18:54 +0800 Subject: [PATCH 0723/2457] ad9914: fix set_mu --- artiq/coredevice/ad9914.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index ee5f5c45c..5496ca8d3 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -174,20 +174,18 @@ class AD9914: self.phase_mode = phase_mode @kernel - def set_mu(self, frequency, phase=0, phase_mode=_PHASE_MODE_DEFAULT, - amplitude=0x0fff, ref_time=-1): + def set_mu(self, ftw, pow=0, phase_mode=_PHASE_MODE_DEFAULT, + asf=0x0fff, ref_time=-1): """Sets the DDS channel to the specified frequency and phase. This uses machine units (FTW and POW). The frequency tuning word width - is 32, whereas the phase offset word width depends on the type of DDS - chip and can be retrieved via the ``pow_width`` attribute. The amplitude - width is 12. + is 32, and the phase offset word width is 16. The "frequency update" pulse is sent to the DDS with a fixed latency with respect to the current position of the time cursor. - :param frequency: frequency to generate. - :param phase: adds an offset, in turns, to the phase. + :param ftw: frequency to generate. + :param pow: adds an offset to the phase. :param phase_mode: if specified, overrides the default phase mode set by ``set_phase_mode`` for this call. :param ref_time: reference time used to compute phase. Specifying this @@ -223,7 +221,7 @@ class AD9914: self.continuous_phase_comp = pow self.write(AD9914_REG_POW, pow) - self.write(AD9914_REG_ASF, amplitude) + self.write(AD9914_REG_ASF, asf) self.write(AD9914_FUD, 0) @portable(flags={"fast-math"}) From 56a18682a7fc11addb5f34c291defc0842264d95 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 14 May 2018 10:37:50 +0800 Subject: [PATCH 0724/2457] ad9914: minor fixes --- artiq/coredevice/ad9914.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index 5496ca8d3..4287e1d29 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -11,6 +11,12 @@ from artiq.coredevice.rtio import rtio_output from numpy import int32, int64 +__all__ = [ + "AD9914", + "PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE", "PHASE_MODE_TRACKING" +] + + _PHASE_MODE_DEFAULT = -1 PHASE_MODE_CONTINUOUS = 0 PHASE_MODE_ABSOLUTE = 1 @@ -54,7 +60,7 @@ class AD9914: kernel_invariants = {"core", "sysclk", "bus_channel", "channel", "rtio_period_mu", "sysclk_per_mu", "write_duration_mu", "dac_cal_duration_mu", "init_duration_mu", "init_sync_duration_mu", - "set_duration_mu", "set_x_duration_mu" + "set_duration_mu", "set_x_duration_mu", "exit_x_duration_mu", "continuous_phase_comp"} def __init__(self, dmgr, sysclk, bus_channel, channel, core_device="core"): @@ -179,7 +185,8 @@ class AD9914: """Sets the DDS channel to the specified frequency and phase. This uses machine units (FTW and POW). The frequency tuning word width - is 32, and the phase offset word width is 16. + is 32, the phase offset word width is 16, and the amplitude scale factor + width is 12. The "frequency update" pulse is sent to the DDS with a fixed latency with respect to the current position of the time cursor. From b04c7abde88597264931d26924e771521690926b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 14 May 2018 14:02:11 +0800 Subject: [PATCH 0725/2457] ad9914: fix kernel_invariants --- artiq/coredevice/ad9914.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index 4287e1d29..af2c2d558 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -60,8 +60,7 @@ class AD9914: kernel_invariants = {"core", "sysclk", "bus_channel", "channel", "rtio_period_mu", "sysclk_per_mu", "write_duration_mu", "dac_cal_duration_mu", "init_duration_mu", "init_sync_duration_mu", - "set_duration_mu", "set_x_duration_mu", "exit_x_duration_mu", - "continuous_phase_comp"} + "set_duration_mu", "set_x_duration_mu", "exit_x_duration_mu"} def __init__(self, dmgr, sysclk, bus_channel, channel, core_device="core"): self.core = dmgr.get(core_device) From d543c9aa6303373a6b660b93557a2d89256b0dd4 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 07:32:55 +0000 Subject: [PATCH 0726/2457] =?UTF-8?q?firmware:=20backtrace=5Fartiq=20?= =?UTF-8?q?=E2=86=92=20unwind=5Fbacktrace.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This crate isn't ARTIQ-specific. --- artiq/firmware/Cargo.lock | 10 +++++----- .../Cargo.toml | 4 ++-- .../{libbacktrace_artiq => libunwind_backtrace}/lib.rs | 0 artiq/firmware/runtime/Cargo.toml | 2 +- artiq/firmware/runtime/main.rs | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) rename artiq/firmware/{libbacktrace_artiq => libunwind_backtrace}/Cargo.toml (58%) rename artiq/firmware/{libbacktrace_artiq => libunwind_backtrace}/lib.rs (100%) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 0d9aedad3..b1b82a1b9 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -13,10 +13,6 @@ dependencies = [ "board 0.0.0", ] -[[package]] -name = "backtrace_artiq" -version = "0.0.0" - [[package]] name = "bitflags" version = "1.0.1" @@ -215,7 +211,6 @@ version = "0.0.0" dependencies = [ "alloc_list 0.0.0", "amp 0.0.0", - "backtrace_artiq 0.0.0", "board 0.0.0", "board_artiq 0.0.0", "build_artiq 0.0.0", @@ -230,6 +225,7 @@ dependencies = [ "proto 0.0.0", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", "std_artiq 0.0.0", + "unwind_backtrace 0.0.0", ] [[package]] @@ -270,6 +266,10 @@ dependencies = [ name = "std_artiq" version = "0.0.0" +[[package]] +name = "unwind_backtrace" +version = "0.0.0" + [[package]] name = "walkdir" version = "1.0.7" diff --git a/artiq/firmware/libbacktrace_artiq/Cargo.toml b/artiq/firmware/libunwind_backtrace/Cargo.toml similarity index 58% rename from artiq/firmware/libbacktrace_artiq/Cargo.toml rename to artiq/firmware/libunwind_backtrace/Cargo.toml index afab53124..637e55bc6 100644 --- a/artiq/firmware/libbacktrace_artiq/Cargo.toml +++ b/artiq/firmware/libunwind_backtrace/Cargo.toml @@ -1,8 +1,8 @@ [package] authors = ["M-Labs"] -name = "backtrace_artiq" +name = "unwind_backtrace" version = "0.0.0" [lib] -name = "backtrace_artiq" +name = "unwind_backtrace" path = "lib.rs" diff --git a/artiq/firmware/libbacktrace_artiq/lib.rs b/artiq/firmware/libunwind_backtrace/lib.rs similarity index 100% rename from artiq/firmware/libbacktrace_artiq/lib.rs rename to artiq/firmware/libunwind_backtrace/lib.rs diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 899bb424b..b7a19a423 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -18,11 +18,11 @@ byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } log = { version = "0.4", default-features = false } managed = { version = "0.6", default-features = false, features = ["alloc", "map"] } +unwind_backtrace = { path = "../libunwind_backtrace" } board = { path = "../libboard", features = ["uart_console", "smoltcp"] } alloc_list = { path = "../liballoc_list" } std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] } logger_artiq = { path = "../liblogger_artiq" } -backtrace_artiq = { path = "../libbacktrace_artiq" } board_artiq = { path = "../libboard_artiq" } proto = { path = "../libproto", features = ["log"] } amp = { path = "../libamp" } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 865cd76a2..7472acc51 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -11,10 +11,10 @@ extern crate managed; extern crate smoltcp; extern crate alloc_list; +extern crate unwind_backtrace; #[macro_use] extern crate std_artiq as std; extern crate logger_artiq; -extern crate backtrace_artiq; #[macro_use] extern crate board; extern crate board_artiq; @@ -304,7 +304,7 @@ pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u3 println!("backtrace for software version {}:", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); - let _ = backtrace_artiq::backtrace(|ip| { + let _ = unwind_backtrace::backtrace(|ip| { println!("{:#08x}", ip); }); From 46c8afc56cdbcfafc735e93e1e81fab419cf7a5b Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 10:02:39 +0000 Subject: [PATCH 0727/2457] firmware: implement libio and use in in drtioaux. --- artiq/firmware/Cargo.lock | 10 +- artiq/firmware/libdrtioaux/Cargo.toml | 3 +- artiq/firmware/libdrtioaux/hw.rs | 139 +++++++++ artiq/firmware/libdrtioaux/lib.rs | 434 ++++++++++---------------- artiq/firmware/libdrtioaux/proto.rs | 106 ------- artiq/firmware/libio/Cargo.toml | 14 + artiq/firmware/libio/lib.rs | 176 +++++++++++ artiq/firmware/libio/proto.rs | 132 ++++++++ 8 files changed, 633 insertions(+), 381 deletions(-) create mode 100644 artiq/firmware/libdrtioaux/hw.rs delete mode 100644 artiq/firmware/libdrtioaux/proto.rs create mode 100644 artiq/firmware/libio/Cargo.toml create mode 100644 artiq/firmware/libio/lib.rs create mode 100644 artiq/firmware/libio/proto.rs diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index b1b82a1b9..95338bef4 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -107,10 +107,9 @@ version = "0.0.0" dependencies = [ "board 0.0.0", "build_misoc 0.0.0", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "io 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "std_artiq 0.0.0", ] [[package]] @@ -125,6 +124,13 @@ dependencies = [ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "io" +version = "0.0.0" +dependencies = [ + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" diff --git a/artiq/firmware/libdrtioaux/Cargo.toml b/artiq/firmware/libdrtioaux/Cargo.toml index 6c4842148..5959b56a8 100644 --- a/artiq/firmware/libdrtioaux/Cargo.toml +++ b/artiq/firmware/libdrtioaux/Cargo.toml @@ -14,6 +14,5 @@ build_misoc = { path = "../libbuild_misoc" } [dependencies] log = { version = "0.4", default-features = false } crc = { version = "1.7", default-features = false } -std_artiq = { path = "../libstd_artiq", features = ["alloc"] } +io = { path = "../libio", features = ["byteorder"] } board = { path = "../libboard" } -byteorder = { version = "1.0", default-features = false } diff --git a/artiq/firmware/libdrtioaux/hw.rs b/artiq/firmware/libdrtioaux/hw.rs new file mode 100644 index 000000000..ea68c24e1 --- /dev/null +++ b/artiq/firmware/libdrtioaux/hw.rs @@ -0,0 +1,139 @@ +use super::*; + +use {Error, Result}; +use io::Cursor; +use io::proto::ProtoRead; + +pub fn reset(linkno: u8) { + let linkno = linkno as usize; + unsafe { + // clear buffer first to limit race window with buffer overflow + // error. We assume the CPU is fast enough so that no two packets + // will be received between the buffer and the error flag are cleared. + (board::csr::DRTIO[linkno].aux_rx_present_write)(1); + (board::csr::DRTIO[linkno].aux_rx_error_write)(1); + } +} + +fn has_rx_error(linkno: u8) -> bool { + let linkno = linkno as usize; + unsafe { + let error = (board::csr::DRTIO[linkno].aux_rx_error_read)() != 0; + if error { + (board::csr::DRTIO[linkno].aux_rx_error_write)(1) + } + error + } +} + +fn receive(linkno: u8, f: F) -> Result, !> + where F: FnOnce(&[u8]) -> Result +{ + let linkidx = linkno as usize; + unsafe { + if (board::csr::DRTIO[linkidx].aux_rx_present_read)() == 1 { + let ptr = board::mem::DRTIO_AUX[linkidx].base + + board::mem::DRTIO_AUX[linkidx].size / 2; + let len = (board::csr::DRTIO[linkidx].aux_rx_length_read)(); + let result = f(slice::from_raw_parts(ptr as *mut u8, len as usize)); + (board::csr::DRTIO[linkidx].aux_rx_present_write)(1); + Ok(Some(result?)) + } else { + Ok(None) + } + } +} + +pub fn recv_link(linkno: u8) -> Result, !> { + if has_rx_error(linkno) { + return Err(Error::GatewareError) + } + + receive(linkno, |buffer| { + if buffer.len() < 8 { + return Err(Error::Io(IoError::UnexpectedEof)) + } + + let mut reader = Cursor::new(buffer); + + let checksum_at = buffer.len() - 4; + let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]); + reader.set_position(checksum_at); + if reader.read_u32()? != checksum { + return Err(Error::CorruptedPacket) + } + reader.set_position(0); + + Packet::read_from(&mut reader) + }) +} + +pub fn recv_timeout_link(linkno: u8, timeout_ms: Option) -> Result { + let timeout_ms = timeout_ms.unwrap_or(10); + let limit = board::clock::get_ms() + timeout_ms; + while board::clock::get_ms() < limit { + match recv_link(linkno)? { + None => (), + Some(packet) => return Ok(packet), + } + } + Err(Error::TimedOut) +} + +fn transmit(linkno: u8, f: F) -> Result<(), !> + where F: FnOnce(&mut [u8]) -> Result +{ + let linkno = linkno as usize; + unsafe { + while (board::csr::DRTIO[linkno].aux_tx_read)() != 0 {} + let ptr = board::mem::DRTIO_AUX[linkno].base; + let len = board::mem::DRTIO_AUX[linkno].size / 2; + let len = f(slice::from_raw_parts_mut(ptr as *mut u8, len))?; + (board::csr::DRTIO[linkno].aux_tx_length_write)(len as u16); + (board::csr::DRTIO[linkno].aux_tx_write)(1); + Ok(()) + } +} + +pub fn send_link(linkno: u8, packet: &Packet) -> Result<(), !> { + transmit(linkno, |buffer| { + let mut writer = Cursor::new(buffer); + + packet.write_to(&mut writer)?; + + let padding = 4 - (writer.position() % 4); + if padding != 4 { + for _ in 0..padding { + writer.write_u8(0)?; + } + } + + let checksum = crc::crc32::checksum_ieee(&writer.get_ref()[0..writer.position()]); + writer.write_u32(checksum)?; + + Ok(writer.position()) + }) +} + +// TODO: routing +fn get_linkno(nodeno: u8) -> Result { + if nodeno == 0 || nodeno as usize > board::csr::DRTIO.len() { + return Err(Error::NoRoute) + } + Ok(nodeno - 1) +} + +pub fn recv(nodeno: u8) -> Result, !> { + let linkno = get_linkno(nodeno)?; + recv_link(linkno) +} + +pub fn recv_timeout(nodeno: u8, timeout_ms: Option) -> Result { + let linkno = get_linkno(nodeno)?; + recv_timeout_link(linkno, timeout_ms) +} + +pub fn send(nodeno: u8, packet: &Packet) -> Result<(), !> { + let linkno = get_linkno(nodeno)?; + send_link(linkno, packet) +} diff --git a/artiq/firmware/libdrtioaux/lib.rs b/artiq/firmware/libdrtioaux/lib.rs index e818ab22e..97b7f46af 100644 --- a/artiq/firmware/libdrtioaux/lib.rs +++ b/artiq/firmware/libdrtioaux/lib.rs @@ -1,17 +1,63 @@ #![no_std] +#![feature(never_type)] -extern crate byteorder; extern crate crc; -#[macro_use] -extern crate std_artiq as std; + +extern crate io; extern crate board; -mod proto; - -use std::io::{self, Read, Write}; -#[cfg(has_drtio)] use core::slice; -use proto::*; +use core::result; +use core::fmt; + +use io::{Read, Write, Error as IoError}; +use io::proto::{ProtoRead, ProtoWrite}; + +pub type Result = result::Result>; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Error { + UnknownPacket(u8), + CorruptedPacket, + TimedOut, + NoRoute, + GatewareError, + Io(IoError), + Other(T) +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &Error::UnknownPacket(ty) => + write!(f, "unknown packet type {:#02x}", ty), + &Error::CorruptedPacket => + write!(f, "packet CRC failed"), + &Error::TimedOut => + write!(f, "timed out waiting for data"), + &Error::NoRoute => + write!(f, "invalid node number"), + &Error::GatewareError => + write!(f, "gateware reported error"), + &Error::Io(ref io) => + write!(f, "I/O error ({})", io), + &Error::Other(ref err) => + write!(f, "{}", err) + } + } +} + +impl From for Error { + fn from(value: T) -> Error { + Error::Other(value) + } +} + +impl From> for Error { + fn from(value: IoError) -> Error { + Error::Io(value) + } +} #[derive(Debug)] pub enum Packet { @@ -49,215 +95,220 @@ pub enum Packet { } impl Packet { - pub fn read_from(reader: &mut Read) -> io::Result { - Ok(match read_u8(reader)? { + pub fn read_from(reader: &mut T) -> Result { + Ok(match reader.read_u8()? { 0x00 => Packet::EchoRequest, 0x01 => Packet::EchoReply, 0x02 => Packet::ResetRequest { - phy: read_bool(reader)? + phy: reader.read_bool()? }, 0x03 => Packet::ResetAck, 0x20 => Packet::RtioErrorRequest, 0x21 => Packet::RtioNoErrorReply, 0x22 => Packet::RtioErrorSequenceErrorReply { - channel: read_u16(reader)? + channel: reader.read_u16()? }, 0x23 => Packet::RtioErrorCollisionReply { - channel: read_u16(reader)? + channel: reader.read_u16()? }, 0x24 => Packet::RtioErrorBusyReply { - channel: read_u16(reader)? + channel: reader.read_u16()? }, 0x40 => Packet::MonitorRequest { - channel: read_u16(reader)?, - probe: read_u8(reader)? + channel: reader.read_u16()?, + probe: reader.read_u8()? }, 0x41 => Packet::MonitorReply { - value: read_u32(reader)? + value: reader.read_u32()? }, 0x50 => Packet::InjectionRequest { - channel: read_u16(reader)?, - overrd: read_u8(reader)?, - value: read_u8(reader)? + channel: reader.read_u16()?, + overrd: reader.read_u8()?, + value: reader.read_u8()? }, 0x51 => Packet::InjectionStatusRequest { - channel: read_u16(reader)?, - overrd: read_u8(reader)? + channel: reader.read_u16()?, + overrd: reader.read_u8()? }, 0x52 => Packet::InjectionStatusReply { - value: read_u8(reader)? + value: reader.read_u8()? }, 0x80 => Packet::I2cStartRequest { - busno: read_u8(reader)? + busno: reader.read_u8()? }, 0x81 => Packet::I2cRestartRequest { - busno: read_u8(reader)? + busno: reader.read_u8()? }, 0x82 => Packet::I2cStopRequest { - busno: read_u8(reader)? + busno: reader.read_u8()? }, 0x83 => Packet::I2cWriteRequest { - busno: read_u8(reader)?, - data: read_u8(reader)? + busno: reader.read_u8()?, + data: reader.read_u8()? }, 0x84 => Packet::I2cWriteReply { - succeeded: read_bool(reader)?, - ack: read_bool(reader)? + succeeded: reader.read_bool()?, + ack: reader.read_bool()? }, 0x85 => Packet::I2cReadRequest { - busno: read_u8(reader)?, - ack: read_bool(reader)? + busno: reader.read_u8()?, + ack: reader.read_bool()? }, 0x86 => Packet::I2cReadReply { - succeeded: read_bool(reader)?, - data: read_u8(reader)? + succeeded: reader.read_bool()?, + data: reader.read_u8()? }, 0x87 => Packet::I2cBasicReply { - succeeded: read_bool(reader)? + succeeded: reader.read_bool()? }, 0x90 => Packet::SpiSetConfigRequest { - busno: read_u8(reader)?, - flags: read_u8(reader)?, - length: read_u8(reader)?, - div: read_u8(reader)?, - cs: read_u8(reader)? + busno: reader.read_u8()?, + flags: reader.read_u8()?, + length: reader.read_u8()?, + div: reader.read_u8()?, + cs: reader.read_u8()? }, /* 0x91: was Packet::SpiSetXferRequest */ 0x92 => Packet::SpiWriteRequest { - busno: read_u8(reader)?, - data: read_u32(reader)? + busno: reader.read_u8()?, + data: reader.read_u32()? }, 0x93 => Packet::SpiReadRequest { - busno: read_u8(reader)? + busno: reader.read_u8()? }, 0x94 => Packet::SpiReadReply { - succeeded: read_bool(reader)?, - data: read_u32(reader)? + succeeded: reader.read_bool()?, + data: reader.read_u32()? }, 0x95 => Packet::SpiBasicReply { - succeeded: read_bool(reader)? + succeeded: reader.read_bool()? }, - _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown packet type")) + ty => return Err(Error::UnknownPacket(ty)) }) } - pub fn write_to(&self, writer: &mut Write) -> io::Result<()> { + pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { match *self { - Packet::EchoRequest => write_u8(writer, 0x00)?, - Packet::EchoReply => write_u8(writer, 0x01)?, + Packet::EchoRequest => + writer.write_u8(0x00)?, + Packet::EchoReply => + writer.write_u8(0x01)?, Packet::ResetRequest { phy } => { - write_u8(writer, 0x02)?; - write_bool(writer, phy)?; + writer.write_u8(0x02)?; + writer.write_bool(phy)?; }, - Packet::ResetAck => write_u8(writer, 0x03)?, + Packet::ResetAck => + writer.write_u8(0x03)?, - Packet::RtioErrorRequest => write_u8(writer, 0x20)?, - Packet::RtioNoErrorReply => write_u8(writer, 0x21)?, + Packet::RtioErrorRequest => + writer.write_u8(0x20)?, + Packet::RtioNoErrorReply => + writer.write_u8(0x21)?, Packet::RtioErrorSequenceErrorReply { channel } => { - write_u8(writer, 0x22)?; - write_u16(writer, channel)?; + writer.write_u8(0x22)?; + writer.write_u16(channel)?; }, Packet::RtioErrorCollisionReply { channel } => { - write_u8(writer, 0x23)?; - write_u16(writer, channel)?; + writer.write_u8(0x23)?; + writer.write_u16(channel)?; }, Packet::RtioErrorBusyReply { channel } => { - write_u8(writer, 0x24)?; - write_u16(writer, channel)?; + writer.write_u8(0x24)?; + writer.write_u16(channel)?; }, Packet::MonitorRequest { channel, probe } => { - write_u8(writer, 0x40)?; - write_u16(writer, channel)?; - write_u8(writer, probe)?; + writer.write_u8(0x40)?; + writer.write_u16(channel)?; + writer.write_u8(probe)?; }, Packet::MonitorReply { value } => { - write_u8(writer, 0x41)?; - write_u32(writer, value)?; + writer.write_u8(0x41)?; + writer.write_u32(value)?; }, Packet::InjectionRequest { channel, overrd, value } => { - write_u8(writer, 0x50)?; - write_u16(writer, channel)?; - write_u8(writer, overrd)?; - write_u8(writer, value)?; + writer.write_u8(0x50)?; + writer.write_u16(channel)?; + writer.write_u8(overrd)?; + writer.write_u8(value)?; }, Packet::InjectionStatusRequest { channel, overrd } => { - write_u8(writer, 0x51)?; - write_u16(writer, channel)?; - write_u8(writer, overrd)?; + writer.write_u8(0x51)?; + writer.write_u16(channel)?; + writer.write_u8(overrd)?; }, Packet::InjectionStatusReply { value } => { - write_u8(writer, 0x52)?; - write_u8(writer, value)?; + writer.write_u8(0x52)?; + writer.write_u8(value)?; }, Packet::I2cStartRequest { busno } => { - write_u8(writer, 0x80)?; - write_u8(writer, busno)?; + writer.write_u8(0x80)?; + writer.write_u8(busno)?; }, Packet::I2cRestartRequest { busno } => { - write_u8(writer, 0x81)?; - write_u8(writer, busno)?; + writer.write_u8(0x81)?; + writer.write_u8(busno)?; }, Packet::I2cStopRequest { busno } => { - write_u8(writer, 0x82)?; - write_u8(writer, busno)?; + writer.write_u8(0x82)?; + writer.write_u8(busno)?; }, Packet::I2cWriteRequest { busno, data } => { - write_u8(writer, 0x83)?; - write_u8(writer, busno)?; - write_u8(writer, data)?; + writer.write_u8(0x83)?; + writer.write_u8(busno)?; + writer.write_u8(data)?; }, Packet::I2cWriteReply { succeeded, ack } => { - write_u8(writer, 0x84)?; - write_bool(writer, succeeded)?; - write_bool(writer, ack)?; + writer.write_u8(0x84)?; + writer.write_bool(succeeded)?; + writer.write_bool(ack)?; }, Packet::I2cReadRequest { busno, ack } => { - write_u8(writer, 0x85)?; - write_u8(writer, busno)?; - write_bool(writer, ack)?; + writer.write_u8(0x85)?; + writer.write_u8(busno)?; + writer.write_bool(ack)?; }, Packet::I2cReadReply { succeeded, data } => { - write_u8(writer, 0x86)?; - write_bool(writer, succeeded)?; - write_u8(writer, data)?; + writer.write_u8(0x86)?; + writer.write_bool(succeeded)?; + writer.write_u8(data)?; }, Packet::I2cBasicReply { succeeded } => { - write_u8(writer, 0x87)?; - write_bool(writer, succeeded)?; + writer.write_u8(0x87)?; + writer.write_bool(succeeded)?; }, Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => { - write_u8(writer, 0x90)?; - write_u8(writer, busno)?; - write_u8(writer, flags)?; - write_u8(writer, length)?; - write_u8(writer, div)?; - write_u8(writer, cs)?; + writer.write_u8(0x90)?; + writer.write_u8(busno)?; + writer.write_u8(flags)?; + writer.write_u8(length)?; + writer.write_u8(div)?; + writer.write_u8(cs)?; }, Packet::SpiWriteRequest { busno, data } => { - write_u8(writer, 0x92)?; - write_u8(writer, busno)?; - write_u32(writer, data)?; + writer.write_u8(0x92)?; + writer.write_u8(busno)?; + writer.write_u32(data)?; }, Packet::SpiReadRequest { busno } => { - write_u8(writer, 0x93)?; - write_u8(writer, busno)?; + writer.write_u8(0x93)?; + writer.write_u8(busno)?; }, Packet::SpiReadReply { succeeded, data } => { - write_u8(writer, 0x94)?; - write_bool(writer, succeeded)?; - write_u32(writer, data)?; + writer.write_u8(0x94)?; + writer.write_bool(succeeded)?; + writer.write_u32(data)?; }, Packet::SpiBasicReply { succeeded } => { - write_u8(writer, 0x95)?; - write_bool(writer, succeeded)?; + writer.write_u8(0x95)?; + writer.write_bool(succeeded)?; }, } Ok(()) @@ -265,163 +316,4 @@ impl Packet { } #[cfg(has_drtio)] -pub mod hw { - use super::*; - use std::io::Cursor; - - pub fn reset(linkno: u8) { - let linkno = linkno as usize; - unsafe { - // clear buffer first to limit race window with buffer overflow - // error. We assume the CPU is fast enough so that no two packets - // will be received between the buffer and the error flag are cleared. - (board::csr::DRTIO[linkno].aux_rx_present_write)(1); - (board::csr::DRTIO[linkno].aux_rx_error_write)(1); - } - } - - fn rx_has_error(linkno: u8) -> bool { - let linkno = linkno as usize; - unsafe { - let error = (board::csr::DRTIO[linkno].aux_rx_error_read)() != 0; - if error { - (board::csr::DRTIO[linkno].aux_rx_error_write)(1) - } - error - } - } - - struct RxBuffer(u8, &'static [u8]); - - impl Drop for RxBuffer { - fn drop(&mut self) { - unsafe { - (board::csr::DRTIO[self.0 as usize].aux_rx_present_write)(1); - } - } - } - - fn rx_get_buffer(linkno: u8) -> Option { - let linkidx = linkno as usize; - unsafe { - if (board::csr::DRTIO[linkidx].aux_rx_present_read)() == 1 { - let length = (board::csr::DRTIO[linkidx].aux_rx_length_read)(); - let base = board::mem::DRTIO_AUX[linkidx].base + board::mem::DRTIO_AUX[linkidx].size/2; - let sl = slice::from_raw_parts(base as *mut u8, length as usize); - Some(RxBuffer(linkno, sl)) - } else { - None - } - } - } - - pub fn recv_link(linkno: u8) -> io::Result> { - if rx_has_error(linkno) { - return Err(io::Error::new(io::ErrorKind::Other, "gateware reported error")) - } - let buffer = rx_get_buffer(linkno); - match buffer { - Some(rxb) => { - let slice = rxb.1; - let mut reader = Cursor::new(slice); - - let len = slice.len(); - if len < 8 { - return Err(io::Error::new(io::ErrorKind::InvalidData, "packet too short")) - } - let computed_crc = crc::crc32::checksum_ieee(&reader.get_ref()[0..len-4]); - reader.set_position((len-4) as u64); - let crc = read_u32(&mut reader)?; - if crc != computed_crc { - return Err(io::Error::new(io::ErrorKind::InvalidData, "packet CRC failed")) - } - reader.set_position(0); - - let packet_r = Packet::read_from(&mut reader); - match packet_r { - Ok(packet) => Ok(Some(packet)), - Err(e) => Err(e) - } - } - None => Ok(None) - } - } - - pub fn recv_timeout_link(linkno: u8, timeout_ms: Option) -> io::Result { - let timeout_ms = timeout_ms.unwrap_or(10); - let limit = board::clock::get_ms() + timeout_ms; - while board::clock::get_ms() < limit { - match recv_link(linkno) { - Ok(None) => (), - Ok(Some(packet)) => return Ok(packet), - Err(e) => return Err(e) - } - } - return Err(io::Error::new(io::ErrorKind::TimedOut, "timed out waiting for data")) - } - - fn tx_get_buffer(linkno: u8) -> &'static mut [u8] { - let linkno = linkno as usize; - unsafe { - while (board::csr::DRTIO[linkno].aux_tx_read)() != 0 {} - let base = board::mem::DRTIO_AUX[linkno].base; - let size = board::mem::DRTIO_AUX[linkno].size/2; - slice::from_raw_parts_mut(base as *mut u8, size) - } - } - - fn tx_ack_buffer(linkno: u8, length: u16) { - let linkno = linkno as usize; - unsafe { - (board::csr::DRTIO[linkno].aux_tx_length_write)(length); - (board::csr::DRTIO[linkno].aux_tx_write)(1) - } - } - - pub fn send_link(linkno: u8, packet: &Packet) -> io::Result<()> { - let sl = tx_get_buffer(linkno); - - let mut writer = Cursor::new(sl); - packet.write_to(&mut writer)?; - let mut len = writer.position(); - - let padding = 4 - (len % 4); - if padding != 4 { - for _ in 0..padding { - write_u8(&mut writer, 0)?; - } - len += padding; - } - - let crc = crc::crc32::checksum_ieee(&writer.get_ref()[0..len as usize]); - write_u32(&mut writer, crc)?; - len += 4; - - tx_ack_buffer(linkno, len as u16); - - Ok(()) - } - - // TODO: routing - fn get_linkno(nodeno: u8) -> io::Result { - if nodeno == 0 || nodeno as usize > board::csr::DRTIO.len() { - return Err(io::Error::new(io::ErrorKind::NotFound, "invalid node number")) - } - Ok(nodeno - 1) - } - - pub fn recv(nodeno: u8) -> io::Result> { - let linkno = get_linkno(nodeno)?; - recv_link(linkno) - } - - pub fn recv_timeout(nodeno: u8, timeout_ms: Option) -> io::Result { - let linkno = get_linkno(nodeno)?; - recv_timeout_link(linkno, timeout_ms) - } - - pub fn send(nodeno: u8, packet: &Packet) -> io::Result<()> { - let linkno = get_linkno(nodeno)?; - send_link(linkno, packet) - } -} +pub mod hw; diff --git a/artiq/firmware/libdrtioaux/proto.rs b/artiq/firmware/libdrtioaux/proto.rs deleted file mode 100644 index 9a89796e0..000000000 --- a/artiq/firmware/libdrtioaux/proto.rs +++ /dev/null @@ -1,106 +0,0 @@ -#![allow(dead_code)] - -use std::io::{self, Read, Write}; -use std::vec::Vec; -use std::string::String; -use byteorder::{ByteOrder, NetworkEndian}; - -// FIXME: replace these with byteorder core io traits once those are in -#[inline(always)] -pub fn read_u8(reader: &mut Read) -> io::Result { - let mut bytes = [0; 1]; - reader.read_exact(&mut bytes)?; - Ok(bytes[0]) -} - -#[inline(always)] -pub fn write_u8(writer: &mut Write, value: u8) -> io::Result<()> { - let bytes = [value; 1]; - writer.write_all(&bytes) -} - -#[inline(always)] -pub fn read_bool(reader: &mut Read) -> io::Result { - if read_u8(reader)? == 0 { - Ok(false) - } else { - Ok(true) - } -} - -#[inline(always)] -pub fn write_bool(writer: &mut Write, value: bool) -> io::Result<()> { - if value { - write_u8(writer, 1) - } else { - write_u8(writer, 0) - } -} - -#[inline(always)] -pub fn read_u16(reader: &mut Read) -> io::Result { - let mut bytes = [0; 2]; - reader.read_exact(&mut bytes)?; - Ok(NetworkEndian::read_u16(&bytes)) -} - -#[inline(always)] -pub fn write_u16(writer: &mut Write, value: u16) -> io::Result<()> { - let mut bytes = [0; 2]; - NetworkEndian::write_u16(&mut bytes, value); - writer.write_all(&bytes) -} - -#[inline(always)] -pub fn read_u32(reader: &mut Read) -> io::Result { - let mut bytes = [0; 4]; - reader.read_exact(&mut bytes)?; - Ok(NetworkEndian::read_u32(&bytes)) -} - -#[inline(always)] -pub fn write_u32(writer: &mut Write, value: u32) -> io::Result<()> { - let mut bytes = [0; 4]; - NetworkEndian::write_u32(&mut bytes, value); - writer.write_all(&bytes) -} - -#[inline(always)] -pub fn read_u64(reader: &mut Read) -> io::Result { - let mut bytes = [0; 8]; - reader.read_exact(&mut bytes)?; - Ok(NetworkEndian::read_u64(&bytes)) -} - -#[inline(always)] -pub fn write_u64(writer: &mut Write, value: u64) -> io::Result<()> { - let mut bytes = [0; 8]; - NetworkEndian::write_u64(&mut bytes, value); - writer.write_all(&bytes) -} - -#[inline(always)] -pub fn read_bytes(reader: &mut Read) -> io::Result> { - let length = read_u32(reader)?; - let mut value = vec![0; length as usize]; - reader.read_exact(&mut value)?; - Ok(value) -} - -#[inline(always)] -pub fn write_bytes(writer: &mut Write, value: &[u8]) -> io::Result<()> { - write_u32(writer, value.len() as u32)?; - writer.write_all(value) -} - -#[inline(always)] -pub fn read_string(reader: &mut Read) -> io::Result { - let bytes = read_bytes(reader)?; - String::from_utf8(bytes) - .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid UTF-8")) -} - -#[inline(always)] -pub fn write_string(writer: &mut Write, value: &str) -> io::Result<()> { - write_bytes(writer, value.as_bytes()) -} diff --git a/artiq/firmware/libio/Cargo.toml b/artiq/firmware/libio/Cargo.toml new file mode 100644 index 000000000..9729aca32 --- /dev/null +++ b/artiq/firmware/libio/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["M-Labs"] +name = "io" +version = "0.0.0" + +[lib] +name = "io" +path = "lib.rs" + +[dependencies] +byteorder = { version = "1.0", default-features = false, optional = true } + +[features] +alloc = [] diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs new file mode 100644 index 000000000..631269ddb --- /dev/null +++ b/artiq/firmware/libio/lib.rs @@ -0,0 +1,176 @@ +#![no_std] +#![feature(never_type)] +#![cfg_attr(feature = "alloc", feature(alloc))] + +#[cfg(feature = "alloc")] +#[macro_use] +extern crate alloc; +#[cfg(feature = "byteorder")] +extern crate byteorder; + +use core::result; +use core::fmt; + +#[cfg(feature = "byteorder")] +pub mod proto; + +pub type Result = result::Result>; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Error { + UnexpectedEof, + Other(T) +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &Error::UnexpectedEof => + write!(f, "unexpected end of stream"), + &Error::Other(ref err) => + write!(f, "{}", err) + } + } +} + +impl From for Error { + fn from(value: T) -> Error { + Error::Other(value) + } +} + +pub trait Read { + type ReadError; + + /// Pull some bytes from this source into the specified buffer, returning + /// how many bytes were read. + fn read(&mut self, buf: &mut [u8]) -> result::Result; + + /// Read the exact number of bytes required to fill `buf`. + fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), Self::ReadError> { + while !buf.is_empty() { + let read_bytes = self.read(buf)?; + if read_bytes == 0 { + return Err(Error::UnexpectedEof) + } + + buf = &mut { buf }[read_bytes..]; + } + + Ok(()) + } +} + +pub trait Write { + type WriteError; + type FlushError; + + /// Write a buffer into this object, returning how many bytes were written. + fn write(&mut self, buf: &[u8]) -> result::Result; + + /// Flush this output stream, ensuring that all intermediately buffered contents + /// reach their destination. + fn flush(&mut self) -> result::Result<(), Self::FlushError>; + + /// Attempts to write an entire buffer into `self`. + fn write_all(&mut self, mut buf: &[u8]) -> Result<(), Self::WriteError> { + while buf.len() > 0 { + let written_bytes = self.write(buf)?; + if written_bytes == 0 { + return Err(Error::UnexpectedEof) + } + + buf = &buf[written_bytes..]; + } + + Ok(()) + } + + /// Hints the writer how much bytes will be written after call to this function. + /// + /// At least `min` bytes should be written after the call to this function and + /// if `max` is `Some(x)` than at most `x` bytes should be written. + fn size_hint(&mut self, _min: usize, _max: Option) {} +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CursorError { + EndOfBuffer +} + +#[derive(Debug, Clone)] +pub struct Cursor { + inner: T, + pos: usize +} + +impl Cursor { + pub fn new(inner: T) -> Cursor { + Cursor { inner, pos: 0 } + } + + pub fn into_inner(self) -> T { + self.inner + } + + pub fn get_ref(&self) -> &T { + &self.inner + } + + pub fn get_mut(&mut self) -> &mut T { + &mut self.inner + } + + pub fn position(&self) -> usize { + self.pos + + } + + pub fn set_position(&mut self, pos: usize) { + self.pos = pos + } +} + +impl> Read for Cursor { + type ReadError = !; + + fn read(&mut self, buf: &mut [u8]) -> result::Result { + let data = &self.inner.as_ref()[self.pos..]; + let len = buf.len().min(data.len()); + buf[..len].copy_from_slice(&data[..len]); + self.pos += len; + Ok(len) + } +} + +impl> Write for Cursor { + type WriteError = !; + type FlushError = !; + + fn write(&mut self, buf: &[u8]) -> result::Result { + let data = &mut self.inner.as_mut()[self.pos..]; + let len = buf.len().min(data.len()); + data[..len].copy_from_slice(&buf[..len]); + self.pos += len; + Ok(len) + } + + fn flush(&mut self) -> result::Result<(), Self::FlushError> { + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl> Write for Cursor { + type WriteError = !; + type FlushError = !; + + fn write(&mut self, buf: &[u8]) -> result::Result { + self.inner.extend(buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> result::Result<(), Self::FlushError> { + Ok(()) + } +} diff --git a/artiq/firmware/libio/proto.rs b/artiq/firmware/libio/proto.rs new file mode 100644 index 000000000..eaf0c3042 --- /dev/null +++ b/artiq/firmware/libio/proto.rs @@ -0,0 +1,132 @@ +use byteorder::{ByteOrder, NetworkEndian}; + +use ::{Read, Write, Error as IoError}; + +pub trait ProtoRead { + type ReadError; + + fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError>; + + fn read_u8(&mut self) -> Result { + let mut bytes = [0; 1]; + self.read_exact(&mut bytes)?; + Ok(bytes[0]) + } + + fn read_u16(&mut self) -> Result { + let mut bytes = [0; 2]; + self.read_exact(&mut bytes)?; + Ok(NetworkEndian::read_u16(&bytes)) + } + + fn read_u32(&mut self) -> Result { + let mut bytes = [0; 4]; + self.read_exact(&mut bytes)?; + Ok(NetworkEndian::read_u32(&bytes)) + } + + fn read_u64(&mut self) -> Result { + let mut bytes = [0; 8]; + self.read_exact(&mut bytes)?; + Ok(NetworkEndian::read_u64(&bytes)) + } + + fn read_bool(&mut self) -> Result { + Ok(self.read_u8()? != 0) + } + + #[cfg(feature = "alloc")] + fn read_bytes(&mut self) -> Result<::alloc::Vec, Self::ReadError> { + let length = self.read_u32()?; + let mut value = vec![0; length as usize]; + self.read_exact(&mut value)?; + Ok(value) + } + +// fn read_string(&mut self) -> Result { +// let bytes = self.read_bytes()?; +// String::from_utf8(bytes) +// .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid UTF-8")) +// } +} + +pub trait ProtoWrite { + type WriteError; + + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError>; + + fn write_u8(&mut self, value: u8) -> Result<(), Self::WriteError> { + let bytes = [value; 1]; + self.write_all(&bytes) + } + + fn write_i8(&mut self, value: i8) -> Result<(), Self::WriteError> { + let bytes = [value as u8; 1]; + self.write_all(&bytes) + } + + fn write_u16(&mut self, value: u16) -> Result<(), Self::WriteError> { + let mut bytes = [0; 2]; + NetworkEndian::write_u16(&mut bytes, value); + self.write_all(&bytes) + } + + fn write_i16(&mut self, value: i16) -> Result<(), Self::WriteError> { + let mut bytes = [0; 2]; + NetworkEndian::write_i16(&mut bytes, value); + self.write_all(&bytes) + } + + fn write_u32(&mut self, value: u32) -> Result<(), Self::WriteError> { + let mut bytes = [0; 4]; + NetworkEndian::write_u32(&mut bytes, value); + self.write_all(&bytes) + } + + fn write_i32(&mut self, value: i32) -> Result<(), Self::WriteError> { + let mut bytes = [0; 4]; + NetworkEndian::write_i32(&mut bytes, value); + self.write_all(&bytes) + } + + fn write_u64(&mut self, value: u64) -> Result<(), Self::WriteError> { + let mut bytes = [0; 8]; + NetworkEndian::write_u64(&mut bytes, value); + self.write_all(&bytes) + } + + fn write_i64(&mut self, value: i64) -> Result<(), Self::WriteError> { + let mut bytes = [0; 8]; + NetworkEndian::write_i64(&mut bytes, value); + self.write_all(&bytes) + } + + fn write_bool(&mut self, value: bool) -> Result<(), Self::WriteError> { + self.write_u8(value as u8) + } + + fn write_bytes(&mut self, value: &[u8]) -> Result<(), Self::WriteError> { + self.write_u32(value.len() as u32)?; + self.write_all(value) + } + + fn write_string(&mut self, value: &str) -> Result<(), Self::WriteError> { + self.write_bytes(value.as_bytes()) + } +} + +impl ProtoRead for T where T: Read { + type ReadError = IoError; + + fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError> { + T::read_exact(self, buf) + } +} + +impl ProtoWrite for T where T: Write { + type WriteError = IoError; + + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError> { + T::write_all(self, buf) + } +} From 5d43d457d293b4a6981dfb48fb5f531ec3f8f59a Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 10:05:02 +0000 Subject: [PATCH 0728/2457] satman: eliminate heap. --- artiq/firmware/Cargo.lock | 2 -- artiq/firmware/satman/Cargo.toml | 4 +--- artiq/firmware/satman/main.rs | 11 ----------- artiq/firmware/satman/satman.ld | 7 ------- 4 files changed, 1 insertion(+), 23 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 95338bef4..ff4780279 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -247,7 +247,6 @@ dependencies = [ name = "satman" version = "0.0.0" dependencies = [ - "alloc_list 0.0.0", "board 0.0.0", "board_artiq 0.0.0", "build_artiq 0.0.0", @@ -255,7 +254,6 @@ dependencies = [ "drtioaux 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "logger_artiq 0.0.0", - "std_artiq 0.0.0", ] [[package]] diff --git a/artiq/firmware/satman/Cargo.toml b/artiq/firmware/satman/Cargo.toml index 82db164f9..65f6127b0 100644 --- a/artiq/firmware/satman/Cargo.toml +++ b/artiq/firmware/satman/Cargo.toml @@ -15,9 +15,7 @@ build_artiq = { path = "../libbuild_artiq" } [dependencies] log = { version = "0.4", default-features = false } -alloc_list = { path = "../liballoc_list" } +drtioaux = { path = "../libdrtioaux" } board = { path = "../libboard", features = ["uart_console"] } board_artiq = { path = "../libboard_artiq" } -std_artiq = { path = "../libstd_artiq", features = ["alloc"] } logger_artiq = { path = "../liblogger_artiq" } -drtioaux = { path = "../libdrtioaux" } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 8bcdc0819..5434edc01 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -1,8 +1,6 @@ #![feature(lang_items, global_allocator)] #![no_std] -extern crate alloc_list; -extern crate std_artiq as std; #[macro_use] extern crate log; extern crate logger_artiq; @@ -262,18 +260,9 @@ fn startup() { } } -#[global_allocator] -static mut ALLOC: alloc_list::ListAlloc = alloc_list::EMPTY; - #[no_mangle] pub extern fn main() -> i32 { unsafe { - extern { - static mut _fheap: u8; - static mut _eheap: u8; - } - ALLOC.add_range(&mut _fheap, &mut _eheap); - static mut LOG_BUFFER: [u8; 1024] = [0; 1024]; logger_artiq::BufferLogger::new(&mut LOG_BUFFER[..]).register(startup); 0 diff --git a/artiq/firmware/satman/satman.ld b/artiq/firmware/satman/satman.ld index 3766b38d6..efae5d319 100644 --- a/artiq/firmware/satman/satman.ld +++ b/artiq/firmware/satman/satman.ld @@ -52,11 +52,4 @@ SECTIONS . += 0x1000; _fstack = . - 4; } > main_ram - - .heap : - { - _fheap = .; - . = ORIGIN(main_ram) + LENGTH(main_ram); - _eheap = .; - } > main_ram } From 56a29b91fc806fd2604942513b9bca48517791e0 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 10:45:11 +0000 Subject: [PATCH 0729/2457] firmware: implement ConsoleLogger, use it in satman. --- artiq/firmware/Cargo.lock | 2 +- artiq/firmware/libboard/Cargo.toml | 1 + artiq/firmware/libboard/lib.rs | 4 +++ artiq/firmware/libboard/uart_logger.rs | 35 ++++++++++++++++++++++++++ artiq/firmware/satman/Cargo.toml | 5 ++-- artiq/firmware/satman/main.rs | 18 ++++--------- 6 files changed, 48 insertions(+), 17 deletions(-) create mode 100644 artiq/firmware/libboard/uart_logger.rs diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index ff4780279..4d6a5a473 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -26,6 +26,7 @@ dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=ca06a5e)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", ] @@ -253,7 +254,6 @@ dependencies = [ "build_misoc 0.0.0", "drtioaux 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "logger_artiq 0.0.0", ] [[package]] diff --git a/artiq/firmware/libboard/Cargo.toml b/artiq/firmware/libboard/Cargo.toml index c47f8eecb..abd97a682 100644 --- a/artiq/firmware/libboard/Cargo.toml +++ b/artiq/firmware/libboard/Cargo.toml @@ -14,6 +14,7 @@ build_misoc = { path = "../libbuild_misoc" } [dependencies] byteorder = { version = "1.0", default-features = false } +log = { version = "0.4", default-features = false, optional = true } [dependencies.compiler_builtins] git = "https://github.com/m-labs/compiler-builtins" diff --git a/artiq/firmware/libboard/lib.rs b/artiq/firmware/libboard/lib.rs index 369a38d8c..690f29e99 100644 --- a/artiq/firmware/libboard/lib.rs +++ b/artiq/firmware/libboard/lib.rs @@ -3,6 +3,8 @@ extern crate compiler_builtins; extern crate byteorder; +#[cfg(feature = "log")] +extern crate log; #[cfg(feature = "smoltcp")] extern crate smoltcp; @@ -25,5 +27,7 @@ pub mod spiflash; pub mod config; #[cfg(feature = "uart_console")] pub mod uart_console; +#[cfg(all(feature = "uart_console", feature = "log"))] +pub mod uart_logger; #[cfg(all(has_ethmac, feature = "smoltcp"))] pub mod ethmac; diff --git a/artiq/firmware/libboard/uart_logger.rs b/artiq/firmware/libboard/uart_logger.rs new file mode 100644 index 000000000..c9308f34f --- /dev/null +++ b/artiq/firmware/libboard/uart_logger.rs @@ -0,0 +1,35 @@ +use core::fmt::Write; +use log::{Log, Metadata, Record, set_logger}; + +use clock; +use uart_console::Console; + +pub struct ConsoleLogger; + +impl ConsoleLogger { + pub fn register() { + static LOGGER: ConsoleLogger = ConsoleLogger; + set_logger(&LOGGER).expect("global logger can only be initialized once") + } +} + +impl Log for ConsoleLogger { + fn enabled(&self, _metadata: &Metadata) -> bool { + true + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + let timestamp = clock::get_us(); + let seconds = timestamp / 1_000_000; + let micros = timestamp % 1_000_000; + + let _ = write!(Console, "[{:6}.{:06}s] {:>5}({}): {}", + seconds, micros, record.level(), record.target(), record.args()); + } + } + + fn flush(&self) { + } +} + diff --git a/artiq/firmware/satman/Cargo.toml b/artiq/firmware/satman/Cargo.toml index 65f6127b0..a227e58e2 100644 --- a/artiq/firmware/satman/Cargo.toml +++ b/artiq/firmware/satman/Cargo.toml @@ -15,7 +15,6 @@ build_artiq = { path = "../libbuild_artiq" } [dependencies] log = { version = "0.4", default-features = false } -drtioaux = { path = "../libdrtioaux" } -board = { path = "../libboard", features = ["uart_console"] } +board = { path = "../libboard", features = ["uart_console", "log"] } board_artiq = { path = "../libboard_artiq" } -logger_artiq = { path = "../liblogger_artiq" } +drtioaux = { path = "../libdrtioaux" } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 5434edc01..da20bba29 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -1,9 +1,8 @@ -#![feature(lang_items, global_allocator)] +#![feature(lang_items)] #![no_std] #[macro_use] extern crate log; -extern crate logger_artiq; #[macro_use] extern crate board; extern crate board_artiq; @@ -170,7 +169,6 @@ fn process_aux_packets() { } } - fn process_errors() { let errors; unsafe { @@ -221,8 +219,11 @@ fn drtio_link_rx_up() -> bool { } } -fn startup() { +#[no_mangle] +pub extern fn main() -> i32 { board::clock::init(); + board::uart_logger::ConsoleLogger::register(); + info!("ARTIQ satellite manager starting..."); info!("software version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); info!("gateware version {}", board::ident::read(&mut [0; 64])); @@ -260,15 +261,6 @@ fn startup() { } } -#[no_mangle] -pub extern fn main() -> i32 { - unsafe { - static mut LOG_BUFFER: [u8; 1024] = [0; 1024]; - logger_artiq::BufferLogger::new(&mut LOG_BUFFER[..]).register(startup); - 0 - } -} - #[no_mangle] pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea) From ba1d137d199cfc53ce9e4976076a258e6d6c9498 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 14 May 2018 18:47:23 +0800 Subject: [PATCH 0730/2457] ad9914: fix FTW write in regular resolution mode --- artiq/coredevice/ad9914.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index af2c2d558..dee917d8c 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -207,7 +207,7 @@ class AD9914: self.write(AD9914_GPIO, (1 << self.channel) << 1) self.write(AD9914_REG_DRGFL, ftw & 0xffff) - self.write(AD9914_REG_DRGFL, (ftw >> 16) & 0xffff) + self.write(AD9914_REG_DRGFH, (ftw >> 16) & 0xffff) # We need the RTIO fine timestamp clock to be phase-locked # to DDS SYSCLK, and divided by an integer self.sysclk_per_mu. From 42420e094a0237a4bd30d52b36ae80f165e67ff4 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 11:18:09 +0000 Subject: [PATCH 0731/2457] satman: don't unwrap so much in process_aux_packet. This shrinks the code by almost 4K. --- artiq/firmware/satman/main.rs | 84 ++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index da20bba29..c6a0d7fca 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -1,4 +1,4 @@ -#![feature(lang_items)] +#![feature(lang_items, never_type)] #![no_std] #[macro_use] @@ -15,7 +15,6 @@ use board_artiq::serwb; #[cfg(has_hmc830_7043)] use board_artiq::hmc830_7043; - fn drtio_reset(reset: bool) { unsafe { (csr::DRTIO[0].reset_write)(if reset { 1 } else { 0 }); @@ -28,11 +27,12 @@ fn drtio_reset_phy(reset: bool) { } } -fn process_aux_packet(p: &drtioaux::Packet) { +fn process_aux_packet(packet: drtioaux::Packet) -> drtioaux::Result<(), !> { // In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels, // and u16 otherwise; hence the `as _` conversion. - match *p { - drtioaux::Packet::EchoRequest => drtioaux::hw::send_link(0, &drtioaux::Packet::EchoReply).unwrap(), + match packet { + drtioaux::Packet::EchoRequest => + drtioaux::hw::send_link(0, &drtioaux::Packet::EchoReply), drtioaux::Packet::ResetRequest { phy } => { if phy { drtio_reset_phy(true); @@ -41,7 +41,7 @@ fn process_aux_packet(p: &drtioaux::Packet) { drtio_reset(true); drtio_reset(false); } - drtioaux::hw::send_link(0, &drtioaux::Packet::ResetAck).unwrap(); + drtioaux::hw::send_link(0, &drtioaux::Packet::ResetAck) }, drtioaux::Packet::RtioErrorRequest => { @@ -55,24 +55,27 @@ fn process_aux_packet(p: &drtioaux::Packet) { channel = (csr::DRTIO[0].sequence_error_channel_read)(); (csr::DRTIO[0].rtio_error_write)(1); } - drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorSequenceErrorReply { channel: channel }).unwrap(); + drtioaux::hw::send_link(0, + &drtioaux::Packet::RtioErrorSequenceErrorReply { channel }) } else if errors & 2 != 0 { let channel; unsafe { channel = (csr::DRTIO[0].collision_channel_read)(); (csr::DRTIO[0].rtio_error_write)(2); } - drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorCollisionReply { channel: channel }).unwrap(); + drtioaux::hw::send_link(0, + &drtioaux::Packet::RtioErrorCollisionReply { channel }) } else if errors & 4 != 0 { let channel; unsafe { channel = (board::csr::DRTIO[0].busy_channel_read)(); (board::csr::DRTIO[0].rtio_error_write)(4); } - drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorBusyReply { channel: channel }).unwrap(); + drtioaux::hw::send_link(0, + &drtioaux::Packet::RtioErrorBusyReply { channel }) } else { - drtioaux::hw::send_link(0, &drtioaux::Packet::RtioNoErrorReply).unwrap(); + drtioaux::hw::send_link(0, &drtioaux::Packet::RtioNoErrorReply) } } @@ -90,7 +93,7 @@ fn process_aux_packet(p: &drtioaux::Packet) { value = 0; } let reply = drtioaux::Packet::MonitorReply { value: value as u32 }; - drtioaux::hw::send_link(0, &reply).unwrap(); + drtioaux::hw::send_link(0, &reply) }, drtioaux::Packet::InjectionRequest { channel, overrd, value } => { #[cfg(has_rtio_moninj)] @@ -99,6 +102,7 @@ fn process_aux_packet(p: &drtioaux::Packet) { csr::rtio_moninj::inj_override_sel_write(overrd); csr::rtio_moninj::inj_value_write(value); } + Ok(()) }, drtioaux::Packet::InjectionStatusRequest { channel, overrd } => { let value; @@ -112,59 +116,75 @@ fn process_aux_packet(p: &drtioaux::Packet) { { value = 0; } - let reply = drtioaux::Packet::InjectionStatusReply { value: value }; - drtioaux::hw::send_link(0, &reply).unwrap(); + drtioaux::hw::send_link(0, &drtioaux::Packet::InjectionStatusReply { value: value }) }, drtioaux::Packet::I2cStartRequest { busno } => { let succeeded = i2c::start(busno).is_ok(); - drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }).unwrap(); + drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } drtioaux::Packet::I2cRestartRequest { busno } => { let succeeded = i2c::restart(busno).is_ok(); - drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }).unwrap(); + drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } drtioaux::Packet::I2cStopRequest { busno } => { let succeeded = i2c::stop(busno).is_ok(); - drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }).unwrap(); + drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } drtioaux::Packet::I2cWriteRequest { busno, data } => { match i2c::write(busno, data) { - Ok(ack) => drtioaux::hw::send_link(0, &drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }).unwrap(), - Err(_) => drtioaux::hw::send_link(0, &drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false }).unwrap() - }; + Ok(ack) => drtioaux::hw::send_link(0, + &drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }), + Err(_) => drtioaux::hw::send_link(0, + &drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false }) + } } drtioaux::Packet::I2cReadRequest { busno, ack } => { match i2c::read(busno, ack) { - Ok(data) => drtioaux::hw::send_link(0, &drtioaux::Packet::I2cReadReply { succeeded: true, data: data }).unwrap(), - Err(_) => drtioaux::hw::send_link(0, &drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff }).unwrap() - }; + Ok(data) => drtioaux::hw::send_link(0, + &drtioaux::Packet::I2cReadReply { succeeded: true, data: data }), + Err(_) => drtioaux::hw::send_link(0, + &drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff }) + } } drtioaux::Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => { let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); - drtioaux::hw::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }).unwrap(); + drtioaux::hw::send_link(0, + &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) }, drtioaux::Packet::SpiWriteRequest { busno, data } => { let succeeded = spi::write(busno, data).is_ok(); - drtioaux::hw::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }).unwrap(); + drtioaux::hw::send_link(0, + &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) } drtioaux::Packet::SpiReadRequest { busno } => { match spi::read(busno) { - Ok(data) => drtioaux::hw::send_link(0, &drtioaux::Packet::SpiReadReply { succeeded: true, data: data }).unwrap(), - Err(_) => drtioaux::hw::send_link(0, &drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 }).unwrap() - }; + Ok(data) => drtioaux::hw::send_link(0, + &drtioaux::Packet::SpiReadReply { succeeded: true, data: data }), + Err(_) => drtioaux::hw::send_link(0, + &drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 }) + } } - _ => warn!("received unexpected aux packet") + _ => { + warn!("received unexpected aux packet"); + Ok(()) + } } } fn process_aux_packets() { - let pr = drtioaux::hw::recv_link(0); - match pr { - Ok(None) => (), - Ok(Some(p)) => process_aux_packet(&p), + let result = + drtioaux::hw::recv_link(0).and_then(|packet| { + if let Some(packet) = packet { + process_aux_packet(packet) + } else { + Ok(()) + } + }); + match result { + Ok(()) => (), Err(e) => warn!("aux packet error ({})", e) } } From 368d6f9bfbf51129b07d5624cdecfaa124070459 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 11:18:19 +0000 Subject: [PATCH 0732/2457] satman: remove useless _Unwind_Resume. --- artiq/firmware/satman/main.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index c6a0d7fca..3c064d266 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -298,11 +298,3 @@ pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u3 println!("panic at {}:{}: {}", file, line, args); loop {} } - -// Allow linking with crates that are built as -Cpanic=unwind even if we use -Cpanic=abort. -// This is never called. -#[allow(non_snake_case)] -#[no_mangle] -pub extern "C" fn _Unwind_Resume() -> ! { - loop {} -} From 7e299563dfeb65fa7707fd37aadc4d6c55c1c5b2 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 11:22:10 +0000 Subject: [PATCH 0733/2457] firmware: mark many functions in libio as #[inline]. --- artiq/firmware/libio/lib.rs | 10 +++++++++- artiq/firmware/libio/proto.rs | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs index 631269ddb..ecfe51341 100644 --- a/artiq/firmware/libio/lib.rs +++ b/artiq/firmware/libio/lib.rs @@ -105,27 +105,32 @@ pub struct Cursor { } impl Cursor { + #[inline] pub fn new(inner: T) -> Cursor { Cursor { inner, pos: 0 } } + #[inline] pub fn into_inner(self) -> T { self.inner } + #[inline] pub fn get_ref(&self) -> &T { &self.inner } + #[inline] pub fn get_mut(&mut self) -> &mut T { &mut self.inner } + #[inline] pub fn position(&self) -> usize { self.pos - } + #[inline] pub fn set_position(&mut self, pos: usize) { self.pos = pos } @@ -155,6 +160,7 @@ impl> Write for Cursor { Ok(len) } + #[inline] fn flush(&mut self) -> result::Result<(), Self::FlushError> { Ok(()) } @@ -165,11 +171,13 @@ impl> Write for Cursor { type WriteError = !; type FlushError = !; + #[inline] fn write(&mut self, buf: &[u8]) -> result::Result { self.inner.extend(buf); Ok(buf.len()) } + #[inline] fn flush(&mut self) -> result::Result<(), Self::FlushError> { Ok(()) } diff --git a/artiq/firmware/libio/proto.rs b/artiq/firmware/libio/proto.rs index eaf0c3042..f8c52e1e7 100644 --- a/artiq/firmware/libio/proto.rs +++ b/artiq/firmware/libio/proto.rs @@ -7,35 +7,41 @@ pub trait ProtoRead { fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError>; + #[inline] fn read_u8(&mut self) -> Result { let mut bytes = [0; 1]; self.read_exact(&mut bytes)?; Ok(bytes[0]) } + #[inline] fn read_u16(&mut self) -> Result { let mut bytes = [0; 2]; self.read_exact(&mut bytes)?; Ok(NetworkEndian::read_u16(&bytes)) } + #[inline] fn read_u32(&mut self) -> Result { let mut bytes = [0; 4]; self.read_exact(&mut bytes)?; Ok(NetworkEndian::read_u32(&bytes)) } + #[inline] fn read_u64(&mut self) -> Result { let mut bytes = [0; 8]; self.read_exact(&mut bytes)?; Ok(NetworkEndian::read_u64(&bytes)) } + #[inline] fn read_bool(&mut self) -> Result { Ok(self.read_u8()? != 0) } #[cfg(feature = "alloc")] + #[inline] fn read_bytes(&mut self) -> Result<::alloc::Vec, Self::ReadError> { let length = self.read_u32()?; let mut value = vec![0; length as usize]; @@ -55,61 +61,72 @@ pub trait ProtoWrite { fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError>; + #[inline] fn write_u8(&mut self, value: u8) -> Result<(), Self::WriteError> { let bytes = [value; 1]; self.write_all(&bytes) } + #[inline] fn write_i8(&mut self, value: i8) -> Result<(), Self::WriteError> { let bytes = [value as u8; 1]; self.write_all(&bytes) } + #[inline] fn write_u16(&mut self, value: u16) -> Result<(), Self::WriteError> { let mut bytes = [0; 2]; NetworkEndian::write_u16(&mut bytes, value); self.write_all(&bytes) } + #[inline] fn write_i16(&mut self, value: i16) -> Result<(), Self::WriteError> { let mut bytes = [0; 2]; NetworkEndian::write_i16(&mut bytes, value); self.write_all(&bytes) } + #[inline] fn write_u32(&mut self, value: u32) -> Result<(), Self::WriteError> { let mut bytes = [0; 4]; NetworkEndian::write_u32(&mut bytes, value); self.write_all(&bytes) } + #[inline] fn write_i32(&mut self, value: i32) -> Result<(), Self::WriteError> { let mut bytes = [0; 4]; NetworkEndian::write_i32(&mut bytes, value); self.write_all(&bytes) } + #[inline] fn write_u64(&mut self, value: u64) -> Result<(), Self::WriteError> { let mut bytes = [0; 8]; NetworkEndian::write_u64(&mut bytes, value); self.write_all(&bytes) } + #[inline] fn write_i64(&mut self, value: i64) -> Result<(), Self::WriteError> { let mut bytes = [0; 8]; NetworkEndian::write_i64(&mut bytes, value); self.write_all(&bytes) } + #[inline] fn write_bool(&mut self, value: bool) -> Result<(), Self::WriteError> { self.write_u8(value as u8) } + #[inline] fn write_bytes(&mut self, value: &[u8]) -> Result<(), Self::WriteError> { self.write_u32(value.len() as u32)?; self.write_all(value) } + #[inline] fn write_string(&mut self, value: &str) -> Result<(), Self::WriteError> { self.write_bytes(value.as_bytes()) } From 04240cdc08222a22f20d160a42a958655d8cbf4b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 11 May 2018 12:46:12 +0000 Subject: [PATCH 0734/2457] suservo: sampler channels are reversed --- artiq/gateware/suservo/servo.py | 2 +- artiq/gateware/test/suservo/test_servo.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/suservo/servo.py b/artiq/gateware/suservo/servo.py index b2df44bc4..34b485d06 100644 --- a/artiq/gateware/suservo/servo.py +++ b/artiq/gateware/suservo/servo.py @@ -11,7 +11,7 @@ class Servo(Module): self.submodules.iir = IIR(iir_p) self.submodules.dds = DDS(dds_pads, dds_p) - for i, j, k, l in zip(self.adc.data, self.iir.adc, + for i, j, k, l in zip(reversed(self.adc.data), self.iir.adc, self.iir.dds, self.dds.profile): self.comb += j.eq(i), l.eq(k) diff --git a/artiq/gateware/test/suservo/test_servo.py b/artiq/gateware/test/suservo/test_servo.py index efa706cd0..67fcdeb71 100644 --- a/artiq/gateware/test/suservo/test_servo.py +++ b/artiq/gateware/test/suservo/test_servo.py @@ -28,7 +28,7 @@ class ServoSim(servo.Servo): adc = 1 x0 = 0x0141 - yield self.adc_tb.data[adc].eq(x0) + yield self.adc_tb.data[-adc-1].eq(x0) channel = 3 yield self.iir.adc[channel].eq(adc) yield self.iir.ctrl[channel].en_iir.eq(1) From 74c0b4452b7dc5ef305cb32aeb9a22293103c452 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 11 May 2018 16:15:18 +0000 Subject: [PATCH 0735/2457] suservo: clkout and sdo[b-d] are inverted --- artiq/gateware/suservo/pads.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/artiq/gateware/suservo/pads.py b/artiq/gateware/suservo/pads.py index a26d02901..5a9fdba75 100644 --- a/artiq/gateware/suservo/pads.py +++ b/artiq/gateware/suservo/pads.py @@ -16,20 +16,23 @@ class SamplerPads(Module): dn = platform.request("{}_adc_data_n".format(eem)) clkout_se = Signal() + clkout_inv = Signal() sck = Signal() self.specials += [ DifferentialOutput(self.cnv, cnv.p, cnv.n), DifferentialOutput(1, sdr.p, sdr.n), - DDROutput(0, self.sck_en, sck, ClockSignal("rio_phy")), + DDROutput(self.sck_en, 0, sck, ClockSignal("rio_phy")), DifferentialOutput(sck, spip.clk, spin.clk), DifferentialInput(dp.clkout, dn.clkout, clkout_se), - Instance("BUFR", i_I=clkout_se, o_O=self.clkout) + # FIXME (hardware): CLKOUT is inverted + # (Sampler v2.0, v2.1) out on rising, in on falling + Instance("BUFR", i_I=clkout_se, o_O=clkout_inv) ] + self.comb += self.clkout.eq(~clkout_inv) - # here to be early before the input delays below to have the clock - # available - self.clkout_p = dp.clkout # availabel for false paths + # define clock here before the input delays below + self.clkout_p = dp.clkout # available for false paths platform.add_platform_command( "create_clock -name {clk} -period 8 [get_nets {clk}]", clk=dp.clkout) @@ -37,17 +40,20 @@ class SamplerPads(Module): for i in "abcd": sdo = Signal() setattr(self, "sdo{}".format(i), sdo) + if i != "a": + # FIXME (hardware): sdob, sdoc, sdod are inverted + # (Sampler v2.0, v2.1) + sdo, sdo_inv = Signal(), sdo + self.comb += sdo_inv.eq(~sdo) sdop = getattr(dp, "sdo{}".format(i)) sdon = getattr(dn, "sdo{}".format(i)) self.specials += [ DifferentialInput(sdop, sdon, sdo), ] - # 8, -0+1.5 hold (t_HSDO_DDR), -0.5+0.5 skew + # -0+1.5 hold (t_HSDO_SDR), -0.5+0.5 skew platform.add_platform_command( - "set_input_delay -clock {clk} " - "-max 2 [get_ports {port}] -clock_fall\n" - "set_input_delay -clock {clk} " - "-min -0.5 [get_ports {port}] -clock_fall", + "set_input_delay -clock {clk} -max 2 [get_ports {port}]\n" + "set_input_delay -clock {clk} -min -0.5 [get_ports {port}]", clk=dp.clkout, port=sdop) From 2a47b934eafd8654c18751fce074bd33cd4b17e3 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 12 May 2018 22:10:40 +0000 Subject: [PATCH 0736/2457] suservo: remove adc return clock gating --- artiq/gateware/suservo/adc_ser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/suservo/adc_ser.py b/artiq/gateware/suservo/adc_ser.py index 93d471fcb..9e2bf48b9 100644 --- a/artiq/gateware/suservo/adc_ser.py +++ b/artiq/gateware/suservo/adc_ser.py @@ -107,7 +107,7 @@ class ADC(Module): ) try: - sck_en_ret = pads.sck_en_ret + sck_en_ret = pads.sck_en_ret # simulation except AttributeError: sck_en_ret = 1 @@ -119,7 +119,7 @@ class ADC(Module): for i, sdo in enumerate(sdo): sdo_sr = Signal(2*t_read) self.sync.ret += [ - If(self.reading & sck_en_ret, + If(sck_en_ret, sdo_sr[1:].eq(sdo_sr), sdo_sr[0].eq(sdo), ) From 27f975e7bb145d9b233690636e408e6bd859a496 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 12 May 2018 22:12:39 +0000 Subject: [PATCH 0737/2457] kasli: eem DifferentialInputs need DIFF_TERM cleanup some formatting on the way --- artiq/gateware/targets/kasli.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 14c1b9448..b3bce96fe 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -6,21 +6,19 @@ from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.cdc import MultiReg from migen.build.generic_platform import * -from migen.build.xilinx.vivado import XilinxVivadoToolchain -from migen.build.xilinx.ise import XilinxISEToolchain -from migen.genlib.io import DifferentialOutput, DifferentialInput +from migen.genlib.io import DifferentialOutput from misoc.interconnect.csr import * from misoc.cores import gpio from misoc.cores.a7_gtp import * -from misoc.targets.kasli import (BaseSoC, MiniSoC, - soc_kasli_args, soc_kasli_argdict) +from misoc.targets.kasli import ( + BaseSoC, MiniSoC, soc_kasli_args, soc_kasli_argdict) from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio from artiq.gateware.rtio.phy import ( - ttl_simple, ttl_serdes_7series, spi2, servo as rtservo) + ttl_simple, ttl_serdes_7series, spi2, servo as rtservo) from artiq.gateware.suservo import servo, pads as servo_pads from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series @@ -214,6 +212,7 @@ def _sampler(eem, eem_aux=None): Subsignal("sdob", Pins(_eem_pin(eem_aux, 2, "p"))), Subsignal("sdoc", Pins(_eem_pin(eem_aux, 3, "p"))), Subsignal("sdod", Pins(_eem_pin(eem_aux, 4, "p"))), + Misc("DIFF_TERM=TRUE"), IOStandard("LVDS_25"), ), ("{}_adc_data_n".format(eem), 0, @@ -222,6 +221,7 @@ def _sampler(eem, eem_aux=None): Subsignal("sdob", Pins(_eem_pin(eem_aux, 2, "n"))), Subsignal("sdoc", Pins(_eem_pin(eem_aux, 3, "n"))), Subsignal("sdod", Pins(_eem_pin(eem_aux, 4, "n"))), + Misc("DIFF_TERM=TRUE"), IOStandard("LVDS_25"), ), ] From d71e4e60a9a334930831b67b6513e41c71458e21 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sun, 13 May 2018 11:16:31 +0000 Subject: [PATCH 0738/2457] suservo: use addition for offset --- artiq/gateware/suservo/iir.py | 10 +++++----- artiq/gateware/test/suservo/test_servo.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/suservo/iir.py b/artiq/gateware/suservo/iir.py index c8b31da6e..33ec96c99 100644 --- a/artiq/gateware/suservo/iir.py +++ b/artiq/gateware/suservo/iir.py @@ -61,7 +61,7 @@ class DSP(Module): If(self.offset_load, d.eq(self.offset) ), - ad.eq(d - a), + ad.eq(d + a), b.eq(self.coeff), m.eq(ad*b), p.eq(p + m), @@ -184,7 +184,7 @@ class IIR(Module): X0 = ADC * 2^(25 - 1 - 16) X1 = X0 delayed by one cycle A0 = 2^11 - A0*Y0 = A1*Y1 - B0*(X0 - OFFSET) - B1*(X1 - OFFSET) + A0*Y0 = A1*Y1 + B0*(X0 + OFFSET) + B1*(X1 + OFFSET) Y1 = Y0 delayed by one cycle ASF = Y0 / 2^(25 - 14 - 1) @@ -196,7 +196,7 @@ class IIR(Module): B0 --/- A0: 2^11 18 | | - ADC -/-[<<]-/-(-)-/---(x)-(+)-/-[>>]-/-[_/^]-/---[>>]-/- ASF + ADC -/-[<<]-/-(+)-/---(x)-(+)-/-[>>]-/-[_/^]-/---[>>]-/- ASF 16 8 24 | 25 | | 48 11 37 25 | 10 15 OFFSET --/- [z^-1] ^ [z^-1] 24 | | | @@ -632,8 +632,8 @@ class IIR(Module): logger.debug("state y1[%d,%d]=%#x x0[%d]=%#x x1[%d]=%#x", i, j, y1, k_j, x0, k_j, x1) - p = (0*(1 << w.shift - 1) + a1*(0 - y1) + - b0*(offset - x0) + b1*(offset - x1)) + p = (0*(1 << w.shift - 1) + a1*(y1 + 0) + + b0*(x0 + offset) + b1*(x1 + offset)) out = p >> w.shift y0 = min(max(0, out), (1 << w.state - 1) - 1) logger.debug("dsp[%d,%d] p=%#x out=%#x y0=%#x", diff --git a/artiq/gateware/test/suservo/test_servo.py b/artiq/gateware/test/suservo/test_servo.py index 67fcdeb71..616561f12 100644 --- a/artiq/gateware/test/suservo/test_servo.py +++ b/artiq/gateware/test/suservo/test_servo.py @@ -65,7 +65,7 @@ class ServoSim(servo.Servo): a1, b0, b1 = coeff["a1"], coeff["b0"], coeff["b1"] out = ( 0*(1 << w.shift - 1) + # rounding - a1*(0 - y1) + b0*(offset - x0) + b1*(offset - x1) + a1*(y1 + 0) + b0*(x0 + offset) + b1*(x1 + offset) ) >> w.shift y1 = min(max(0, out), (1 << w.state - 1) - 1) From 4993ceec35b662a70e27556db62d823dfeff0d57 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 14 May 2018 08:41:19 +0000 Subject: [PATCH 0739/2457] sampler: unroll conversion for speed --- artiq/coredevice/sampler.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/sampler.py b/artiq/coredevice/sampler.py index ce8817a4c..7ede3a21f 100644 --- a/artiq/coredevice/sampler.py +++ b/artiq/coredevice/sampler.py @@ -23,10 +23,16 @@ def adc_mu_to_volt(data, gain=0): :param gain: PGIA gain setting (0: 1, ..., 3: 1000) :return: Voltage in Volts """ - input_span = 20. - for i in range(gain): - input_span /= 10. - volt_per_lsb = input_span/(1 << 16) + if gain == 0: + volt_per_lsb = 20./(1 << 16) + elif gain == 1: + volt_per_lsb = 2./(1 << 16) + elif gain == 2: + volt_per_lsb = .2/(1 << 16) + elif gain == 3: + volt_per_lsb = .02/(1 << 16) + else: + raise ValueError("invalid gain") return data*volt_per_lsb From 504d37b66bca1e7858cd7e4fc077f170e4868127 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 14 May 2018 12:24:06 +0000 Subject: [PATCH 0740/2457] suservo: add SI units functions and document m-labs/artiq#788 --- artiq/coredevice/suservo.py | 222 +++++++++++++++--- .../kasli_suservo/repository/suservo.py | 73 +++--- artiq/gateware/suservo/iir.py | 4 +- artiq/gateware/suservo/servo.py | 1 + 4 files changed, 219 insertions(+), 81 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index c5aa6f2d1..ef7698313 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -1,9 +1,6 @@ -from artiq.language.core import kernel, delay, portable, now_mu, delay_mu -from artiq.language.units import us, ms +from artiq.language.core import kernel, delay, now_mu, delay_mu +from artiq.language.units import us, ns from artiq.coredevice.rtio import rtio_output, rtio_input_data - -from numpy import int32, int64 - from artiq.coredevice import spi2 as spi from artiq.coredevice import urukul, sampler @@ -14,6 +11,8 @@ WE = 1 << COEFF_DEPTH + 1 STATE_SEL = 1 << COEFF_DEPTH CONFIG_SEL = 1 << COEFF_DEPTH - 1 CONFIG_ADDR = CONFIG_SEL | STATE_SEL +F_CYCLE = 1/((2*(8 + 64) + 2 + 1)*8*ns) +COEFF_SHIFT = 11 class SUServo: @@ -49,7 +48,7 @@ class SUServo: This method does not alter the profile configuration memory or the channel controls. """ - self.set_config(0) + self.set_config(enable=0) delay(3*us) # pipeline flush self.pgia.set_config_mu( @@ -118,13 +117,16 @@ class SUServo: @kernel def get_adc_mu(self, adc): - """Get an ADC reading (IIR filter input X0). + """Get an ADC reading (IIR filter input X0) in machine units. This method does not advance the timeline but consumes all slack. :param adc: ADC channel number (0-7) - :return: 16 bit signed Y0 + :return: 17 bit signed X0 """ + # State memory entries are 25 bits. Due to the pre-adder dynamic + # range, X0/X1/OFFSET are only 24 bits. Finally, the RTIO interface + # only returns the 18 MSBs (the width of the coefficient memory). return self.read(STATE_SEL | (adc << 1) | (1 << 8)) @kernel @@ -144,11 +146,24 @@ class SUServo: self.gains = gains @kernel - def get_adc(self, adc): - raise NotImplementedError # FIXME + def get_adc(self, channel): + """Get an ADC reading (IIR filter input X0). + + This method does not advance the timeline but consumes all slack. + + :param adc: ADC channel number (0-7) + :return: ADC voltage + """ + val = (self.get_adc_mu(channel) >> 1) & 0xffff + mask = 1 << 15 + val = -(val & mask) + (val & ~mask) + gain = (self.gains >> (channel*2)) & 0b11 + return sampler.adc_mu_to_volt(val, gain) class Channel: + """SU-Servo channel""" + kernel_invariants = {"channel", "core", "servo", "servo_channel"} def __init__(self, dmgr, channel, servo_device, @@ -165,6 +180,9 @@ class Channel: """Operate channel. This method does not advance the timeline. + Output RF switch setting takes effect immediately. + IIR updates take place once the RF switch has been enabled for the + configured delay and the profile setting has been stable. :param en_out: RF switch enable :param en_iir: IIR updates enable @@ -174,54 +192,154 @@ class Channel: en_out | (en_iir << 1) | (profile << 2)) @kernel - def set_dds_mu(self, profile, ftw, offset, pow=0): - """Set profile DDS coefficients. + def set_dds_mu(self, profile, ftw, offs, pow_=0): + """Set profile DDS coefficients in machine units. - This method advances the timeline by four Servo memory accesses. + .. seealso:: :meth:`set_amplitude` :param profile: Profile number (0-31) :param ftw: Frequency tuning word (32 bit unsigned) - :param offset: IIR offset (setpoint) - :param pow: Phase offset word (16 bit unsigned) + :param offs: IIR offset (17 bit signed) + :param pow_: Phase offset word (16 bit) """ base = (self.servo_channel << 8) | (profile << 3) self.servo.write(base + 0, ftw >> 16) self.servo.write(base + 6, ftw) - self.servo.write(base + 4, offset) - self.servo.write(base + 2, pow) + self.servo.write(base + 4, offs) + self.servo.write(base + 2, pow_) @kernel def set_dds(self, profile, frequency, offset, phase=0.): - raise NotImplementedError # FIXME - - @kernel - def set_iir_mu(self, profile, adc, a1, b0, b1, delay=0): - """Set profile IIR coefficients. + """Set profile DDS coefficients. This method advances the timeline by four Servo memory accesses. + Profile parameter changes are not synchronized. Activate a different + profile or stop the servo to ensure synchronous changes. :param profile: Profile number (0-31) - :param adc: ADC channel to use (0-7) + :param frequency: DDS frequency in Hz + :param offset: IIR offset (negative setpoint) in units of full scale. + For positive ADC voltages as setpoints, this should be negative. + :param phase: DDS phase in turns + """ + if self.servo_channel < 4: + dds = self.servo.dds0 + else: + dds = self.servo.dds1 + ftw = dds.frequency_to_ftw(frequency) + pow_ = dds.turns_to_pow(phase) + offs = int(round(offset*(1 << COEFF_WIDTH - 1))) + self.set_dds_mu(profile, ftw, offs, pow_) + + @kernel + def set_iir_mu(self, profile, adc, a1, b0, b1, dly=0): + """Set profile IIR coefficients in machine units. + + The recurrence relation is (all data signed and MSB aligned): + + .. math:: + a_0 y_n = a_1 y_{n - 1} + b_0 (x_n + o)/2 + b_1 (x_{n - 1} + o)/2 + + Where: + + * :math:`y_n` and :math:`y_{n-1}` are the current and previous + filter outputs, clipped to :math:`[0, 1]`. + * :math:`x_n` and :math:`x_{n-1}` are the current and previous + filter inputs + * :math:`o` is the offset + * :math:`a_0` is the normalization factor :math:`2^{11}` + * :math:`a_1` is the feedback gain + * :math:`b_0` and :math:`b_1` are the feedforward gains for the two + delays + + .. seealso:: :meth:`set_iir` + + :param profile: Profile number (0-31) + :param adc: ADC channel to take IIR input from (0-7) :param a1: 18 bit signed A1 coefficient (Y1 coefficient, feedback, integrator gain) :param b0: 18 bit signed B0 coefficient (recent, X0 coefficient, feed forward, proportional gain) :param b1: 18 bit signed B1 coefficient (old, X1 coefficient, feed forward, proportional gain) - :param delay: Number of Servo cycles (~1.1 µs each) to suppress - IIR updates for after either (1) enabling or disabling RF output, - (2) enabling or disabling IIR updates, or (3) setting the active - profile number: i.e. after invoking :meth:`set`. + :param dly: IIR update suppression time. In units of IIR cycles + (~1.1 µs) """ base = (self.servo_channel << 8) | (profile << 3) + self.servo.write(base + 3, adc | (dly << 8)) self.servo.write(base + 1, b1) - self.servo.write(base + 3, adc | (delay << 8)) self.servo.write(base + 5, a1) self.servo.write(base + 7, b0) @kernel - def set_iir(self, profile, adc, i_gain, p_gain, delay=0.): - raise NotImplementedError # FIXME + def set_iir(self, profile, adc, gain, corner=0., limit=0., delay=0.): + """Set profile IIR coefficients. + + This method advances the timeline by four Servo memory accesses. + Profile parameter changes are not synchronized. Activate a different + profile or stop the servo to ensure synchronous changes. + + Gains are given in units of output full per scale per input full scale. + + The transfer function is (up to time discretization and + coefficient quantization errors): + + .. math:: + H(s) = K \\frac{1 + \\frac{s}{\\omega_0}} + {\\frac{1}{g} + \\frac{s}{\\omega_0}} + + Where: + * :math:`s = \\sigma + i\\omega` is the complex frequency + * :math:`K` is the proportional gain + * :math:`\\omega_0` is the integrator corner frequency + * :math:`g` is the integrator gain limit + + :param profile: Profile number (0-31) + :param adc: ADC channel to take IIR input from (0-7) + :param gain: Proportional gain (1). This is usually negative (closed + loop, positive ADC voltage, positive setpoint). + :param corner: Integrator corner frequency (Hz). When 0 (the default) + this implements a pure P controller. + :param limit: Integrator gain limit (1). When 0 (the default) the + integrator gain limit is infinite. + :param delay: Delay (in seconds) before allowing IIR updates after + invoking :meth:`set`. + """ + B_NORM = 1 << COEFF_SHIFT + 1 + A_NORM = 1 << COEFF_SHIFT + PI_TS = 3.1415927/F_CYCLE + COEFF_MAX = 1 << COEFF_WIDTH - 1 + + k = B_NORM*gain + if corner == 0.: + a1_ = 0 + b0_ = int(round(k)) + b1_ = 0 + else: + q = PI_TS*corner + kq = k*q + + a1_ = A_NORM + b0 = kq + k + b1 = kq - k + if limit != 0.: + ql = q/limit + qlr = 1./(1. + ql) + a1_ = int(round(a1_*(1. - ql)*qlr)) + b0 *= qlr + b0 *= qlr + b0_ = int(round(b0)) + b1_ = int(round(b1)) + + if b1_ == -b0_: + raise ValueError("low corner, gain, limit") + + if (b0_ >= COEFF_MAX or b0_ < -COEFF_MAX or + b1_ >= COEFF_MAX or b1_ < -COEFF_MAX): + raise ValueError("high corner, gain, limit") + + dly = int(round(delay*F_CYCLE)) + self.set_iir_mu(profile, adc, a1_, b0_, b1_, dly) @kernel def get_profile_mu(self, profile, data): @@ -231,6 +349,7 @@ class Channel: `[ftw >> 16, b1, pow, adc | (delay << 8), offset, a1, ftw, b0]`. This method advances the timeline by 32 µs and consumes all slack. + Profile data is returned :param profile: Profile number (0-31) :param data: List of 8 integers to write the profile data into @@ -242,7 +361,7 @@ class Channel: @kernel def get_y_mu(self, profile): - """Get a profile's IIR state (filter output, Y0). + """Get a profile's IIR state (filter output, Y0) in machine units. The IIR state is also know as the "integrator", or the DDS amplitude scale factor. It is 18 bits wide and unsigned. @@ -256,10 +375,40 @@ class Channel: @kernel def get_y(self, profile): - raise NotImplementedError # FIXME + """Get a profile's IIR state (filter output, Y0). + + The IIR state is also know as the "integrator", or the DDS amplitude + scale factor. It is 18 bits wide and unsigned. + + This method does not advance the timeline but consumes all slack. + + :param profile: Profile number (0-31) + :return: IIR filter output in Y0 units of full scale + """ + return self.get_y_mu(profile)*(1./(1 << COEFF_WIDTH - 1)) @kernel def set_y_mu(self, profile, y): + """Set a profile's IIR state (filter output, Y0) in machine units. + + The IIR state is also know as the "integrator", or the DDS amplitude + scale factor. It is 18 bits wide and unsigned. + + This method must not be used when the Servo + could be writing to the same location. Either deactivate the profile, + or deactivate IIR updates, or disable Servo iterations. + + This method advances the timeline by one Servo memory access. + + :param profile: Profile number (0-31) + :param y: 17 bit unsigned Y0 + """ + # State memory is 25 bits wide and signed. + # Reads interact with the 18 MSBs (coefficient memory width) + self.servo.write(STATE_SEL | (self.servo_channel << 5) | profile, y) + + @kernel + def set_y(self, profile, y): """Set a profile's IIR state (filter output, Y0). The IIR state is also know as the "integrator", or the DDS amplitude @@ -272,11 +421,6 @@ class Channel: This method advances the timeline by one Servo memory access. :param profile: Profile number (0-31) - :param y: 18 bit unsigned Y0 + :param y: IIR state in units of full scale """ - return self.servo.write( - STATE_SEL | (self.servo_channel << 5) | profile, y) - - @kernel - def set_y(self, profile, y): - raise NotImplementedError # FIXME + self.set_y_mu(profile, int(round((1 << COEFF_WIDTH - 1)*y))) diff --git a/artiq/examples/kasli_suservo/repository/suservo.py b/artiq/examples/kasli_suservo/repository/suservo.py index cf49a77fb..9074bdfbe 100644 --- a/artiq/examples/kasli_suservo/repository/suservo.py +++ b/artiq/examples/kasli_suservo/repository/suservo.py @@ -10,40 +10,47 @@ class SUServo(EnvExperiment): self.setattr_device("suservo0_ch{}".format(i)) def run(self): - # self.led() self.init() def p(self, d): - for name, value in zip("ftw1 b1 pow cfg offset a1 ftw0 b0".split(), d): - print(name, hex(value)) + mask = 1 << 18 - 1 + for name, val in zip("ftw1 b1 pow cfg offset a1 ftw0 b0".split(), d): + val = -(val & mask) + (val & ~mask) + print(name, hex(val), val) + + @rpc(flags={"async"}) + def p1(self, adc, asf, st): + print("{:10s}".format("#"*int(adc*10))) @kernel def init(self): self.core.break_realtime() self.core.reset() + self.led() self.suservo0.init() delay(1*us) # ADC PGIA gain - self.suservo0.set_pgia_mu(0, 0) + for i in range(8): + self.suservo0.set_pgia_mu(i, 0) + delay(10*us) # DDS attenuator - self.suservo0.cpld0.set_att_mu(0, 64) + self.suservo0.cpld0.set_att(0, 10.) delay(1*us) - # Servo is done + # Servo is done and disabled assert self.suservo0.get_status() & 0xff == 2 - delay(10*us) # set up profile 0 on channel 0 - self.suservo0_ch0.set_y_mu(0, 0) - self.suservo0_ch0.set_iir_mu( - profile=0, adc=0, a1=-0x800, b0=0x1000, b1=0, delay=0) - delay(10*us) - self.suservo0_ch0.set_dds_mu( - profile=0, ftw=0x12345667, offset=0x1000, pow=0xaa55) + delay(100*us) + self.suservo0_ch0.set_y(0, 0.) + self.suservo0_ch0.set_iir( + profile=0, adc=7, gain=-.1, corner=7000*Hz, limit=0., delay=0.) + self.suservo0_ch0.set_dds( + profile=0, offset=-.5, frequency=71*MHz, phase=0.) # enable channel self.suservo0_ch0.set(en_out=1, en_iir=1, profile=0) # enable servo iterations - self.suservo0.set_config(1) + self.suservo0.set_config(enable=1) # read back profile data data = [0] * 8 @@ -51,40 +58,26 @@ class SUServo(EnvExperiment): self.p(data) delay(10*ms) - # check servo status - assert self.suservo0.get_status() & 0xff == 1 + # check servo enabled + assert self.suservo0.get_status() & 0x01 == 1 delay(10*us) - # reach back ADC data - assert self.suservo0.get_adc_mu(0) == 0 - delay(10*us) - - # read out IIR data - assert self.suservo0_ch0.get_y_mu(0) == 0x1ffff - delay(10*us) - - assert self.suservo0.get_status() & 0xff00 == 0x0100 - delay(10*us) - - # repeatedly clear the IIR state/integrator - # with the ADC yielding 0's and given the profile configuration, - # this will lead to a slow ram up of the amplitude over about 40µs - # followed by saturation and repetition. while True: - self.suservo0_ch0.set(1, 0, 0) - delay(1*us) - assert self.suservo0.get_status() & 0xff00 == 0x0100 + self.suservo0.set_config(0) delay(10*us) - assert self.suservo0.get_status() & 0xff00 == 0x0000 + v = self.suservo0.get_adc(7) + delay(30*us) + w = self.suservo0_ch0.get_y(0) + delay(20*us) + x = self.suservo0.get_status() delay(10*us) - self.suservo0_ch0.set_y_mu(0, 0) - delay(1*us) - self.suservo0_ch0.set(1, 1, 0) - delay(60*us) + self.suservo0.set_config(1) + self.p1(v, w, x) + delay(200*ms) @kernel def led(self): self.core.break_realtime() - for i in range(10): + for i in range(3): self.led0.pulse(.1*s) delay(.1*s) diff --git a/artiq/gateware/suservo/iir.py b/artiq/gateware/suservo/iir.py index 33ec96c99..72501afae 100644 --- a/artiq/gateware/suservo/iir.py +++ b/artiq/gateware/suservo/iir.py @@ -191,8 +191,8 @@ class IIR(Module): ADC: input value from the ADC ASF: output amplitude scale factor to DDS OFFSET: setpoint - A0: fixed factor - A1/B0/B1: coefficients + A0: fixed factor (normalization) + A1/B0/B1: coefficients (integers) B0 --/- A0: 2^11 18 | | diff --git a/artiq/gateware/suservo/servo.py b/artiq/gateware/suservo/servo.py index 34b485d06..b19a6e73d 100644 --- a/artiq/gateware/suservo/servo.py +++ b/artiq/gateware/suservo/servo.py @@ -11,6 +11,7 @@ class Servo(Module): self.submodules.iir = IIR(iir_p) self.submodules.dds = DDS(dds_pads, dds_p) + # adc channels are reversed on Sampler for i, j, k, l in zip(reversed(self.adc.data), self.iir.adc, self.iir.dds, self.dds.profile): self.comb += j.eq(i), l.eq(k) From bfc8fd0807f25c7abf5f0e41e9b0f958ef66303d Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 12:06:33 +0000 Subject: [PATCH 0741/2457] firmware: add io::Error::Unrecognized variant and use it in drtioaux. --- artiq/firmware/libdrtioaux/hw.rs | 64 +++++++++++++++++++++++-------- artiq/firmware/libdrtioaux/lib.rs | 54 +------------------------- artiq/firmware/libio/lib.rs | 3 ++ artiq/firmware/satman/main.rs | 2 +- 4 files changed, 55 insertions(+), 68 deletions(-) diff --git a/artiq/firmware/libdrtioaux/hw.rs b/artiq/firmware/libdrtioaux/hw.rs index ea68c24e1..bd4f609b5 100644 --- a/artiq/firmware/libdrtioaux/hw.rs +++ b/artiq/firmware/libdrtioaux/hw.rs @@ -1,8 +1,42 @@ +use core::fmt; +use io::{Cursor, Error as IoError}; +use io::proto::ProtoRead; + use super::*; -use {Error, Result}; -use io::Cursor; -use io::proto::ProtoRead; +pub type Result = result::Result; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Error { + CorruptedPacket, + TimedOut, + NoRoute, + GatewareError, + Io(IoError) +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &Error::CorruptedPacket => + write!(f, "packet CRC failed"), + &Error::TimedOut => + write!(f, "timed out waiting for data"), + &Error::NoRoute => + write!(f, "invalid node number"), + &Error::GatewareError => + write!(f, "gateware reported error"), + &Error::Io(ref io) => + write!(f, "I/O error ({})", io) + } + } +} + +impl From> for Error { + fn from(value: IoError) -> Error { + Error::Io(value) + } +} pub fn reset(linkno: u8) { let linkno = linkno as usize; @@ -26,8 +60,8 @@ fn has_rx_error(linkno: u8) -> bool { } } -fn receive(linkno: u8, f: F) -> Result, !> - where F: FnOnce(&[u8]) -> Result +fn receive(linkno: u8, f: F) -> Result> + where F: FnOnce(&[u8]) -> Result { let linkidx = linkno as usize; unsafe { @@ -44,7 +78,7 @@ fn receive(linkno: u8, f: F) -> Result, !> } } -pub fn recv_link(linkno: u8) -> Result, !> { +pub fn recv_link(linkno: u8) -> Result> { if has_rx_error(linkno) { return Err(Error::GatewareError) } @@ -64,11 +98,11 @@ pub fn recv_link(linkno: u8) -> Result, !> { } reader.set_position(0); - Packet::read_from(&mut reader) + Ok(Packet::read_from(&mut reader)?) }) } -pub fn recv_timeout_link(linkno: u8, timeout_ms: Option) -> Result { +pub fn recv_timeout_link(linkno: u8, timeout_ms: Option) -> Result { let timeout_ms = timeout_ms.unwrap_or(10); let limit = board::clock::get_ms() + timeout_ms; while board::clock::get_ms() < limit { @@ -80,8 +114,8 @@ pub fn recv_timeout_link(linkno: u8, timeout_ms: Option) -> Result(linkno: u8, f: F) -> Result<(), !> - where F: FnOnce(&mut [u8]) -> Result +fn transmit(linkno: u8, f: F) -> Result<()> + where F: FnOnce(&mut [u8]) -> Result { let linkno = linkno as usize; unsafe { @@ -95,7 +129,7 @@ fn transmit(linkno: u8, f: F) -> Result<(), !> } } -pub fn send_link(linkno: u8, packet: &Packet) -> Result<(), !> { +pub fn send_link(linkno: u8, packet: &Packet) -> Result<()> { transmit(linkno, |buffer| { let mut writer = Cursor::new(buffer); @@ -116,24 +150,24 @@ pub fn send_link(linkno: u8, packet: &Packet) -> Result<(), !> { } // TODO: routing -fn get_linkno(nodeno: u8) -> Result { +fn get_linkno(nodeno: u8) -> Result { if nodeno == 0 || nodeno as usize > board::csr::DRTIO.len() { return Err(Error::NoRoute) } Ok(nodeno - 1) } -pub fn recv(nodeno: u8) -> Result, !> { +pub fn recv(nodeno: u8) -> Result> { let linkno = get_linkno(nodeno)?; recv_link(linkno) } -pub fn recv_timeout(nodeno: u8, timeout_ms: Option) -> Result { +pub fn recv_timeout(nodeno: u8, timeout_ms: Option) -> Result { let linkno = get_linkno(nodeno)?; recv_timeout_link(linkno, timeout_ms) } -pub fn send(nodeno: u8, packet: &Packet) -> Result<(), !> { +pub fn send(nodeno: u8, packet: &Packet) -> Result<()> { let linkno = get_linkno(nodeno)?; send_link(linkno, packet) } diff --git a/artiq/firmware/libdrtioaux/lib.rs b/artiq/firmware/libdrtioaux/lib.rs index 97b7f46af..9c26144ef 100644 --- a/artiq/firmware/libdrtioaux/lib.rs +++ b/artiq/firmware/libdrtioaux/lib.rs @@ -6,59 +6,9 @@ extern crate crc; extern crate io; extern crate board; -use core::slice; -use core::result; -use core::fmt; - -use io::{Read, Write, Error as IoError}; +use io::{Read, Write, Error, Result}; use io::proto::{ProtoRead, ProtoWrite}; -pub type Result = result::Result>; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Error { - UnknownPacket(u8), - CorruptedPacket, - TimedOut, - NoRoute, - GatewareError, - Io(IoError), - Other(T) -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &Error::UnknownPacket(ty) => - write!(f, "unknown packet type {:#02x}", ty), - &Error::CorruptedPacket => - write!(f, "packet CRC failed"), - &Error::TimedOut => - write!(f, "timed out waiting for data"), - &Error::NoRoute => - write!(f, "invalid node number"), - &Error::GatewareError => - write!(f, "gateware reported error"), - &Error::Io(ref io) => - write!(f, "I/O error ({})", io), - &Error::Other(ref err) => - write!(f, "{}", err) - } - } -} - -impl From for Error { - fn from(value: T) -> Error { - Error::Other(value) - } -} - -impl From> for Error { - fn from(value: IoError) -> Error { - Error::Io(value) - } -} - #[derive(Debug)] pub enum Packet { EchoRequest, @@ -188,7 +138,7 @@ impl Packet { succeeded: reader.read_bool()? }, - ty => return Err(Error::UnknownPacket(ty)) + _ => return Err(Error::Unrecognized) }) } diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs index ecfe51341..5050c8934 100644 --- a/artiq/firmware/libio/lib.rs +++ b/artiq/firmware/libio/lib.rs @@ -19,6 +19,7 @@ pub type Result = result::Result>; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Error { UnexpectedEof, + Unrecognized, Other(T) } @@ -27,6 +28,8 @@ impl fmt::Display for Error { match self { &Error::UnexpectedEof => write!(f, "unexpected end of stream"), + &Error::Unrecognized => + write!(f, "unrecognized input"), &Error::Other(ref err) => write!(f, "{}", err) } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 3c064d266..9afe0ff4c 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -27,7 +27,7 @@ fn drtio_reset_phy(reset: bool) { } } -fn process_aux_packet(packet: drtioaux::Packet) -> drtioaux::Result<(), !> { +fn process_aux_packet(packet: drtioaux::Packet) -> drtioaux::hw::Result<()> { // In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels, // and u16 otherwise; hence the `as _` conversion. match packet { From 29997564936115db19bd401df531b319c04842ab Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 12:49:36 +0000 Subject: [PATCH 0742/2457] firmware: impl std_artiq::io::{Read,Write} for io::{Read,Write}. --- artiq/firmware/Cargo.lock | 3 +++ artiq/firmware/libio/Cargo.toml | 1 + artiq/firmware/libio/lib.rs | 44 +++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 4d6a5a473..ef7c33ae5 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -130,6 +130,7 @@ name = "io" version = "0.0.0" dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "std_artiq 0.0.0", ] [[package]] @@ -208,6 +209,7 @@ dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dyld 0.0.0", + "io 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "std_artiq 0.0.0", ] @@ -226,6 +228,7 @@ dependencies = [ "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "drtioaux 0.0.0", "fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)", + "io 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "logger_artiq 0.0.0", "managed 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/artiq/firmware/libio/Cargo.toml b/artiq/firmware/libio/Cargo.toml index 9729aca32..4f6ffd678 100644 --- a/artiq/firmware/libio/Cargo.toml +++ b/artiq/firmware/libio/Cargo.toml @@ -9,6 +9,7 @@ path = "lib.rs" [dependencies] byteorder = { version = "1.0", default-features = false, optional = true } +std_artiq = { path = "../libstd_artiq", optional = true } [features] alloc = [] diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs index 5050c8934..f4a289cee 100644 --- a/artiq/firmware/libio/lib.rs +++ b/artiq/firmware/libio/lib.rs @@ -8,6 +8,9 @@ extern crate alloc; #[cfg(feature = "byteorder")] extern crate byteorder; +#[cfg(feature = "std_artiq")] +extern crate std_artiq; + use core::result; use core::fmt; @@ -185,3 +188,44 @@ impl> Write for Cursor { Ok(()) } } + +#[cfg(feature = "std_artiq")] +impl Read for T where T: std_artiq::io::Read { + type ReadError = std_artiq::io::Error; + + fn read(&mut self, buf: &mut [u8]) -> result::Result { + std_artiq::io::Read::read(self, buf) + } +} + +#[cfg(feature = "std_artiq")] +impl Write for T where T: std_artiq::io::Write { + type WriteError = std_artiq::io::Error; + type FlushError = std_artiq::io::Error; + + fn write(&mut self, buf: &[u8]) -> result::Result { + std_artiq::io::Write::write(self, buf) + } + + fn flush(&mut self) -> result::Result<(), Self::WriteError> { + std_artiq::io::Write::flush(self) + } +} + +#[cfg(feature = "std_artiq")] +impl From> for std_artiq::io::Error + where T: Into +{ + fn from(value: Error) -> std_artiq::io::Error { + match value { + Error::UnexpectedEof => + std_artiq::io::Error::new(std_artiq::io::ErrorKind::UnexpectedEof, + "unexpected end of stream"), + Error::Unrecognized => + std_artiq::io::Error::new(std_artiq::io::ErrorKind::InvalidData, + "unrecognized data"), + Error::Other(err) => + err.into() + } + } +} From 976bb5e935fa24a9be102f6b2e04299f8238435f Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 12:51:44 +0000 Subject: [PATCH 0743/2457] firmware: migrate analyzer_proto to new libio. --- artiq/firmware/libproto/Cargo.toml | 1 + artiq/firmware/libproto/analyzer_proto.rs | 6 +++--- artiq/firmware/libproto/lib.rs | 1 + artiq/firmware/runtime/Cargo.toml | 1 + 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libproto/Cargo.toml b/artiq/firmware/libproto/Cargo.toml index eb805f1eb..5efb9ce81 100644 --- a/artiq/firmware/libproto/Cargo.toml +++ b/artiq/firmware/libproto/Cargo.toml @@ -11,5 +11,6 @@ path = "lib.rs" byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } log = { version = "0.4", default-features = false, optional = true } +io = { path = "../libio", features = ["byteorder"] } std_artiq = { path = "../libstd_artiq", features = ["alloc"] } dyld = { path = "../libdyld" } diff --git a/artiq/firmware/libproto/analyzer_proto.rs b/artiq/firmware/libproto/analyzer_proto.rs index 45153fdd4..66c54c753 100644 --- a/artiq/firmware/libproto/analyzer_proto.rs +++ b/artiq/firmware/libproto/analyzer_proto.rs @@ -1,5 +1,5 @@ -use std::io::{self, Write}; -use WriteExt; +use io::{Write, Result}; +use io::proto::{ProtoWrite}; #[derive(Debug)] pub struct Header { @@ -11,7 +11,7 @@ pub struct Header { } impl Header { - pub fn write_to(&self, writer: &mut Write) -> io::Result<()> { + pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { writer.write_u32(self.sent_bytes)?; writer.write_u64(self.total_byte_count)?; writer.write_u8(self.overflow_occurred as u8)?; diff --git a/artiq/firmware/libproto/lib.rs b/artiq/firmware/libproto/lib.rs index d3422b5ee..31b8c5d1b 100644 --- a/artiq/firmware/libproto/lib.rs +++ b/artiq/firmware/libproto/lib.rs @@ -6,6 +6,7 @@ extern crate cslice; #[macro_use] extern crate log; +extern crate io; extern crate dyld; extern crate std_artiq as std; diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index b7a19a423..ddca4d8a6 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -19,6 +19,7 @@ cslice = { version = "0.3" } log = { version = "0.4", default-features = false } managed = { version = "0.6", default-features = false, features = ["alloc", "map"] } unwind_backtrace = { path = "../libunwind_backtrace" } +io = { path = "../libio", features = ["std_artiq"] } board = { path = "../libboard", features = ["uart_console", "smoltcp"] } alloc_list = { path = "../liballoc_list" } std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] } From 4ddb29fa02fe3e109f3489fde28d41079c9d0dd4 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 14 May 2018 14:59:55 +0200 Subject: [PATCH 0744/2457] suservo: document class arguments --- artiq/coredevice/suservo.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index ef7698313..1bb4cf938 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -16,6 +16,18 @@ COEFF_SHIFT = 11 class SUServo: + """Sampler-Urukul Servo configuration device. + + :param channel: RTIO channel number + :param pgia_device: Name of the Sampler PGIA gain setting SPI bus + :param cpld0_device: Name of the first Urukul CPLD SPI bus + :param cpld1_device: Name of the second Urukul CPLD SPI bus + :param dds0_device: Name of the AD9910 device for the DDS on the first + Urukul + :param dds1_device: Name of the AD9910 device for the DDS on the second + Urukul + :param core_device: Core device name + """ kernel_invariants = {"channel", "core", "pgia", "cpld0", "cpld1", "dds0", "dds1", "ref_period_mu"} @@ -162,14 +174,16 @@ class SUServo: class Channel: - """SU-Servo channel""" + """Sampler-Urukul Servo channel + :param channel: RTIO channel number + :param servo_device: Name of the parent SUServo device + """ kernel_invariants = {"channel", "core", "servo", "servo_channel"} - def __init__(self, dmgr, channel, servo_device, - core_device="core"): - self.core = dmgr.get(core_device) + def __init__(self, dmgr, channel, servo_device): self.servo = dmgr.get(servo_device) + self.core = self.servo.core self.channel = channel # FIXME: this assumes the mem channel is right after the control # channels @@ -243,14 +257,14 @@ class Channel: Where: * :math:`y_n` and :math:`y_{n-1}` are the current and previous - filter outputs, clipped to :math:`[0, 1]`. + filter outputs, clipped to :math:`[0, 1]`. * :math:`x_n` and :math:`x_{n-1}` are the current and previous - filter inputs + filter inputs * :math:`o` is the offset * :math:`a_0` is the normalization factor :math:`2^{11}` * :math:`a_1` is the feedback gain * :math:`b_0` and :math:`b_1` are the feedforward gains for the two - delays + delays .. seealso:: :meth:`set_iir` From 0c1caf074401bfc1707eac74d15e28b7f0a8aad2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 14 May 2018 13:22:34 +0000 Subject: [PATCH 0745/2457] suservo: clean up and beautify example --- .../kasli_suservo/repository/suservo.py | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/artiq/examples/kasli_suservo/repository/suservo.py b/artiq/examples/kasli_suservo/repository/suservo.py index 9074bdfbe..93c9faf5e 100644 --- a/artiq/examples/kasli_suservo/repository/suservo.py +++ b/artiq/examples/kasli_suservo/repository/suservo.py @@ -16,11 +16,12 @@ class SUServo(EnvExperiment): mask = 1 << 18 - 1 for name, val in zip("ftw1 b1 pow cfg offset a1 ftw0 b0".split(), d): val = -(val & mask) + (val & ~mask) - print(name, hex(val), val) + print("{}: {:x} = {}".format(name, val, val)) @rpc(flags={"async"}) def p1(self, adc, asf, st): - print("{:10s}".format("#"*int(adc*10))) + print("ADC: {:10s}, ASF: {:10s}, clipped: {}".format( + "#"*int(adc), "#"*int(asf*10), (st >> 8) & 1), end="\r") @kernel def init(self): @@ -40,28 +41,43 @@ class SUServo(EnvExperiment): # Servo is done and disabled assert self.suservo0.get_status() & 0xff == 2 - # set up profile 0 on channel 0 + # set up profile 0 on channel 0: delay(100*us) - self.suservo0_ch0.set_y(0, 0.) + self.suservo0_ch0.set_y( + profile=0, + y=0. # clear integrator + ) self.suservo0_ch0.set_iir( - profile=0, adc=7, gain=-.1, corner=7000*Hz, limit=0., delay=0.) + profile=0, + adc=7, # take data from Sampler channel 7 + gain=-.1, # -0.1 P gain + corner=70*Hz, # very low corner frequency + limit=0., # unlimited integrator gain + delay=0. # no IIR update delay after enabling + ) + # setpoint 0.5 (5 V with above PGIA gain setting) + # 71 MHz + # 0 phase self.suservo0_ch0.set_dds( - profile=0, offset=-.5, frequency=71*MHz, phase=0.) - # enable channel + profile=0, + offset=-.5, # 5 V with above PGIA settings + frequency=71*MHz, + phase=0.) + # enable RF, IIR updates and profile 0 self.suservo0_ch0.set(en_out=1, en_iir=1, profile=0) - # enable servo iterations + # enable global servo iterations self.suservo0.set_config(enable=1) + # check servo enabled + assert self.suservo0.get_status() & 0x01 == 1 + delay(10*us) + # read back profile data data = [0] * 8 self.suservo0_ch0.get_profile_mu(0, data) self.p(data) delay(10*ms) - # check servo enabled - assert self.suservo0.get_status() & 0x01 == 1 - delay(10*us) - while True: self.suservo0.set_config(0) delay(10*us) @@ -73,7 +89,7 @@ class SUServo(EnvExperiment): delay(10*us) self.suservo0.set_config(1) self.p1(v, w, x) - delay(200*ms) + delay(20*ms) @kernel def led(self): From e292c8ab651f780611caea32a3f1c41aa99843cf Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 13:03:57 +0000 Subject: [PATCH 0746/2457] firmware: migrate mgmt_proto to new libio. --- artiq/firmware/libio/lib.rs | 6 +++--- artiq/firmware/libproto/Cargo.toml | 2 +- artiq/firmware/libproto/lib.rs | 2 ++ artiq/firmware/libproto/mgmt_proto.rs | 19 ++++++++++--------- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs index f4a289cee..4fb1cef91 100644 --- a/artiq/firmware/libio/lib.rs +++ b/artiq/firmware/libio/lib.rs @@ -154,12 +154,12 @@ impl> Read for Cursor { } } -impl> Write for Cursor { +impl<'a> Write for Cursor<&'a mut [u8]> { type WriteError = !; type FlushError = !; fn write(&mut self, buf: &[u8]) -> result::Result { - let data = &mut self.inner.as_mut()[self.pos..]; + let data = &mut self.inner[self.pos..]; let len = buf.len().min(data.len()); data[..len].copy_from_slice(&buf[..len]); self.pos += len; @@ -173,7 +173,7 @@ impl> Write for Cursor { } #[cfg(feature = "alloc")] -impl> Write for Cursor { +impl Write for Cursor<::alloc::Vec> { type WriteError = !; type FlushError = !; diff --git a/artiq/firmware/libproto/Cargo.toml b/artiq/firmware/libproto/Cargo.toml index 5efb9ce81..c1ff3a4c3 100644 --- a/artiq/firmware/libproto/Cargo.toml +++ b/artiq/firmware/libproto/Cargo.toml @@ -11,6 +11,6 @@ path = "lib.rs" byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } log = { version = "0.4", default-features = false, optional = true } -io = { path = "../libio", features = ["byteorder"] } +io = { path = "../libio", features = ["byteorder", "alloc"] } std_artiq = { path = "../libstd_artiq", features = ["alloc"] } dyld = { path = "../libdyld" } diff --git a/artiq/firmware/libproto/lib.rs b/artiq/firmware/libproto/lib.rs index 31b8c5d1b..4f4e27018 100644 --- a/artiq/firmware/libproto/lib.rs +++ b/artiq/firmware/libproto/lib.rs @@ -1,5 +1,7 @@ #![no_std] +#![feature(alloc)] +extern crate alloc; extern crate byteorder; extern crate cslice; #[cfg(feature = "log")] diff --git a/artiq/firmware/libproto/mgmt_proto.rs b/artiq/firmware/libproto/mgmt_proto.rs index 8ac1a95ec..44e6b09dc 100644 --- a/artiq/firmware/libproto/mgmt_proto.rs +++ b/artiq/firmware/libproto/mgmt_proto.rs @@ -1,9 +1,10 @@ -use std::vec::Vec; -use std::io::{self, Read, Write}; -use {ReadExt, WriteExt}; +use alloc::vec::Vec; #[cfg(feature = "log")] use log; +use io::{Read, Write, Error, Result}; +use io::proto::{ProtoRead, ProtoWrite}; + #[derive(Debug)] pub enum Request { GetLog, @@ -40,9 +41,10 @@ pub enum Reply<'a> { } impl Request { - pub fn read_from(reader: &mut Read) -> io::Result { + pub fn read_from(reader: &mut T) -> Result { #[cfg(feature = "log")] - fn read_log_level_filter(reader: &mut Read) -> io::Result { + fn read_log_level_filter(reader: &mut T) -> + Result { Ok(match reader.read_u8()? { 0 => log::LevelFilter::Off, 1 => log::LevelFilter::Error, @@ -50,8 +52,7 @@ impl Request { 3 => log::LevelFilter::Info, 4 => log::LevelFilter::Debug, 5 => log::LevelFilter::Trace, - _ => return Err(io::Error::new(io::ErrorKind::InvalidData, - "invalid log level")) + _ => return Err(Error::Unrecognized) }) } @@ -73,13 +74,13 @@ impl Request { 4 => Request::Hotswap(reader.read_bytes()?), 5 => Request::Reboot, 8 => Request::DebugAllocator, - _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown request type")) + _ => return Err(Error::Unrecognized) }) } } impl<'a> Reply<'a> { - pub fn write_to(&self, writer: &mut Write) -> io::Result<()> { + pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { match *self { Reply::Success => { writer.write_u8(1)?; From e9c88e32e6ba9f7684ad2bbe4a6eeed10d075eb5 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 13:06:28 +0000 Subject: [PATCH 0747/2457] firmware: migrate moninj_proto to new libio. --- artiq/firmware/libdrtioaux/lib.rs | 2 +- artiq/firmware/libproto/mgmt_proto.rs | 2 +- artiq/firmware/libproto/moninj_proto.rs | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/artiq/firmware/libdrtioaux/lib.rs b/artiq/firmware/libdrtioaux/lib.rs index 9c26144ef..bed9bddf7 100644 --- a/artiq/firmware/libdrtioaux/lib.rs +++ b/artiq/firmware/libdrtioaux/lib.rs @@ -45,7 +45,7 @@ pub enum Packet { } impl Packet { - pub fn read_from(reader: &mut T) -> Result { + pub fn read_from(reader: &mut T) -> Result { Ok(match reader.read_u8()? { 0x00 => Packet::EchoRequest, 0x01 => Packet::EchoReply, diff --git a/artiq/firmware/libproto/mgmt_proto.rs b/artiq/firmware/libproto/mgmt_proto.rs index 44e6b09dc..569a24104 100644 --- a/artiq/firmware/libproto/mgmt_proto.rs +++ b/artiq/firmware/libproto/mgmt_proto.rs @@ -41,7 +41,7 @@ pub enum Reply<'a> { } impl Request { - pub fn read_from(reader: &mut T) -> Result { + pub fn read_from(reader: &mut T) -> Result { #[cfg(feature = "log")] fn read_log_level_filter(reader: &mut T) -> Result { diff --git a/artiq/firmware/libproto/moninj_proto.rs b/artiq/firmware/libproto/moninj_proto.rs index de233d3c0..32a833a97 100644 --- a/artiq/firmware/libproto/moninj_proto.rs +++ b/artiq/firmware/libproto/moninj_proto.rs @@ -1,5 +1,5 @@ -use std::io::{self, Read, Write}; -use {ReadExt, WriteExt}; +use io::{Read, Write, Error, Result}; +use io::proto::{ProtoRead, ProtoWrite}; #[derive(Debug)] pub enum HostMessage { @@ -15,7 +15,7 @@ pub enum DeviceMessage { } impl HostMessage { - pub fn read_from(reader: &mut Read) -> io::Result { + pub fn read_from(reader: &mut T) -> Result { Ok(match reader.read_u8()? { 0 => HostMessage::Monitor { enable: if reader.read_u8()? == 0 { false } else { true }, @@ -31,13 +31,13 @@ impl HostMessage { channel: reader.read_u32()?, overrd: reader.read_u8()? }, - _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown packet type")) + _ => return Err(Error::Unrecognized) }) } } impl DeviceMessage { - pub fn write_to(&self, writer: &mut Write) -> io::Result<()> { + pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { match *self { DeviceMessage::MonitorStatus { channel, probe, value } => { writer.write_u8(0)?; From 09617c9f5ef9f2a52c61a02872844452551c36c1 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 13:33:38 +0000 Subject: [PATCH 0748/2457] firmware: migrate session_proto to new libio. --- artiq/firmware/libio/lib.rs | 4 +- artiq/firmware/libio/proto.rs | 64 +++++++++++++++++++++--- artiq/firmware/libproto/mgmt_proto.rs | 6 +-- artiq/firmware/libproto/moninj_proto.rs | 4 +- artiq/firmware/libproto/session_proto.rs | 19 +++---- artiq/firmware/runtime/session.rs | 2 +- 6 files changed, 75 insertions(+), 24 deletions(-) diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs index 4fb1cef91..0524e1c6f 100644 --- a/artiq/firmware/libio/lib.rs +++ b/artiq/firmware/libio/lib.rs @@ -190,7 +190,7 @@ impl Write for Cursor<::alloc::Vec> { } #[cfg(feature = "std_artiq")] -impl Read for T where T: std_artiq::io::Read { +impl Read for T where T: std_artiq::io::Read + ?Sized { type ReadError = std_artiq::io::Error; fn read(&mut self, buf: &mut [u8]) -> result::Result { @@ -199,7 +199,7 @@ impl Read for T where T: std_artiq::io::Read { } #[cfg(feature = "std_artiq")] -impl Write for T where T: std_artiq::io::Write { +impl Write for T where T: std_artiq::io::Write + ?Sized { type WriteError = std_artiq::io::Error; type FlushError = std_artiq::io::Error; diff --git a/artiq/firmware/libio/proto.rs b/artiq/firmware/libio/proto.rs index f8c52e1e7..143e8fd8f 100644 --- a/artiq/firmware/libio/proto.rs +++ b/artiq/firmware/libio/proto.rs @@ -1,7 +1,50 @@ +use core::fmt; +use alloc::string; use byteorder::{ByteOrder, NetworkEndian}; use ::{Read, Write, Error as IoError}; +#[derive(Debug)] +pub enum ReadStringError { + Utf8Error(string::FromUtf8Error), + Other(T) +} + +impl fmt::Display for ReadStringError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &ReadStringError::Utf8Error(ref err) => + write!(f, "invalid UTF-8 ({})", err), + &ReadStringError::Other(ref err) => + write!(f, "{}", err) + } + } +} + +impl From>> for IoError +{ + fn from(value: ReadStringError>) -> IoError { + match value { + ReadStringError::Utf8Error(_) => IoError::Unrecognized, + ReadStringError::Other(err) => err + } + } +} + +#[cfg(feature = "std_artiq")] +impl From> for ::std_artiq::io::Error + where T: Into<::std_artiq::io::Error> +{ + fn from(value: ReadStringError) -> ::std_artiq::io::Error { + match value { + ReadStringError::Utf8Error(_) => + ::std_artiq::io::Error::new(::std_artiq::io::ErrorKind::InvalidData, + "invalid UTF-8"), + ReadStringError::Other(err) => err.into() + } + } +} + pub trait ProtoRead { type ReadError; @@ -49,11 +92,18 @@ pub trait ProtoRead { Ok(value) } -// fn read_string(&mut self) -> Result { -// let bytes = self.read_bytes()?; -// String::from_utf8(bytes) -// .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid UTF-8")) -// } + #[cfg(feature = "alloc")] + #[inline] + fn read_string(&mut self) -> Result<::alloc::String, ReadStringError> { + match self.read_bytes() { + Ok(bytes) => + match ::alloc::String::from_utf8(bytes) { + Ok(string) => Ok(string), + Err(err) => Err(ReadStringError::Utf8Error(err)) + }, + Err(err) => Err(ReadStringError::Other(err)) + } + } } pub trait ProtoWrite { @@ -132,7 +182,7 @@ pub trait ProtoWrite { } } -impl ProtoRead for T where T: Read { +impl ProtoRead for T where T: Read + ?Sized { type ReadError = IoError; fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError> { @@ -140,7 +190,7 @@ impl ProtoRead for T where T: Read { } } -impl ProtoWrite for T where T: Write { +impl ProtoWrite for T where T: Write + ?Sized { type WriteError = IoError; fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError> { diff --git a/artiq/firmware/libproto/mgmt_proto.rs b/artiq/firmware/libproto/mgmt_proto.rs index 569a24104..6e343c083 100644 --- a/artiq/firmware/libproto/mgmt_proto.rs +++ b/artiq/firmware/libproto/mgmt_proto.rs @@ -41,9 +41,9 @@ pub enum Reply<'a> { } impl Request { - pub fn read_from(reader: &mut T) -> Result { + pub fn read_from(reader: &mut T) -> Result { #[cfg(feature = "log")] - fn read_log_level_filter(reader: &mut T) -> + fn read_log_level_filter(reader: &mut T) -> Result { Ok(match reader.read_u8()? { 0 => log::LevelFilter::Off, @@ -80,7 +80,7 @@ impl Request { } impl<'a> Reply<'a> { - pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { + pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { match *self { Reply::Success => { writer.write_u8(1)?; diff --git a/artiq/firmware/libproto/moninj_proto.rs b/artiq/firmware/libproto/moninj_proto.rs index 32a833a97..b440fab14 100644 --- a/artiq/firmware/libproto/moninj_proto.rs +++ b/artiq/firmware/libproto/moninj_proto.rs @@ -15,7 +15,7 @@ pub enum DeviceMessage { } impl HostMessage { - pub fn read_from(reader: &mut T) -> Result { + pub fn read_from(reader: &mut T) -> Result { Ok(match reader.read_u8()? { 0 => HostMessage::Monitor { enable: if reader.read_u8()? == 0 { false } else { true }, @@ -37,7 +37,7 @@ impl HostMessage { } impl DeviceMessage { - pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { + pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { match *self { DeviceMessage::MonitorStatus { channel, probe, value } => { writer.write_u8(0)?; diff --git a/artiq/firmware/libproto/session_proto.rs b/artiq/firmware/libproto/session_proto.rs index c852f3918..8dd5dec9f 100644 --- a/artiq/firmware/libproto/session_proto.rs +++ b/artiq/firmware/libproto/session_proto.rs @@ -1,9 +1,10 @@ -use std::io::{self, Read, Write}; -use std::vec::Vec; -use std::string::String; -use {ReadExt, WriteExt}; +use alloc::vec::Vec; +use alloc::string::String; -fn read_sync(reader: &mut Read) -> io::Result<()> { +use io::{Read, Write, Error, Result}; +use io::proto::{ProtoRead, ProtoWrite}; + +fn read_sync(reader: &mut T) -> Result<(), T::ReadError> { let mut sync = [0; 4]; for i in 0.. { sync[i % 4] = reader.read_u8()?; @@ -12,7 +13,7 @@ fn read_sync(reader: &mut Read) -> io::Result<()> { Ok(()) } -fn write_sync(writer: &mut Write) -> io::Result<()> { +fn write_sync(writer: &mut T) -> Result<(), T::WriteError> { writer.write_all(&[0x5a; 4]) } @@ -42,7 +43,7 @@ pub enum Request { } impl Request { - pub fn read_from(reader: &mut Read) -> io::Result { + pub fn read_from(reader: &mut T) -> Result { read_sync(reader)?; Ok(match reader.read_u8()? { 3 => Request::SystemInfo, @@ -74,7 +75,7 @@ impl Request { 12 => Request::FlashRemove { key: reader.read_string()? }, - _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown request type")) + _ => return Err(Error::Unrecognized) }) } } @@ -115,7 +116,7 @@ pub enum Reply<'a> { } impl<'a> Reply<'a> { - pub fn write_to(&self, writer: &mut Write) -> io::Result<()> { + pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { write_sync(writer)?; match *self { Reply::SystemInfo { ident, finished_cleanly } => { diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 8b42329ee..2d617ef78 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -127,7 +127,7 @@ fn host_read(stream: &mut TcpStream) -> io::Result { fn host_write(stream: &mut Write, reply: host::Reply) -> io::Result<()> { debug!("comm->host {:?}", reply); - reply.write_to(stream) + Ok(reply.write_to(stream)?) } pub fn kern_send(io: &Io, request: &kern::Message) -> io::Result<()> { From 80df86f700d34fe46f221c40914667fdcb7f3e4c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 14 May 2018 23:28:14 +0800 Subject: [PATCH 0749/2457] ad9914: set_mu_x -> set_x_mu --- artiq/coredevice/ad9914.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index dee917d8c..55882d4bd 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -277,7 +277,7 @@ class AD9914: # Extended-resolution functions @kernel - def set_mu_x(self, xftw, amplitude=0x0fff): + def set_x_mu(self, xftw, amplitude=0x0fff): """Set the DDS frequency and amplitude with an extended-resolution (63-bit) frequency tuning word. @@ -323,10 +323,10 @@ class AD9914: @kernel def set_x(self, frequency, amplitude=1.0): - """Like ``set_mu_x``, but uses Hz and turns. + """Like ``set_x_mu``, but uses Hz and turns. Note that the precision of ``float`` is less than the precision of the extended frequency tuning word. """ - self.set_mu_x(self.frequency_to_xftw(frequency), + self.set_x_mu(self.frequency_to_xftw(frequency), self.amplitude_to_asf(amplitude)) From e121a81f2175c941e05f1e7401b69300bc9acb6e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 14 May 2018 23:30:08 +0800 Subject: [PATCH 0750/2457] ad9914: fix frequency_to_xftw and xftw_to_frequency --- artiq/coredevice/ad9914.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index 55882d4bd..e892ba65d 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -312,14 +312,14 @@ class AD9914: """Returns the frequency tuning word corresponding to the given frequency (extended resolution mode). """ - return round(float(int64(2)**63*frequency/self.sysclk)) + return int64(round(2.0*float(int64(2)**62)*frequency/self.sysclk)) @portable(flags={"fast-math"}) def xftw_to_frequency(self, xftw): """Returns the frequency corresponding to the given frequency tuning word (extended resolution mode). """ - return xftw*self.sysclk/int64(2)**63 + return xftw*self.sysclk/(2.0*float(int64(2)**62)) @kernel def set_x(self, frequency, amplitude=1.0): From 019c92aa0239ee441a85eddb8c7a120eb151ac17 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 14 May 2018 23:47:59 +0800 Subject: [PATCH 0751/2457] manual: fix title underline warning --- doc/manual/core_drivers_reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 6bce75560..06f1fd4ce 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -88,7 +88,7 @@ RF generation drivers :members: :mod:`artiq.coredevice.ad9914` module -++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++ .. automodule:: artiq.coredevice.ad9914 :members: From 9a1bd66d2cb47d90ba1c220be8d49351689cec3a Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 15:56:19 +0000 Subject: [PATCH 0752/2457] compiler: add test for int64(round(1.0)). --- artiq/test/lit/inferencer/cast.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/test/lit/inferencer/cast.py b/artiq/test/lit/inferencer/cast.py index 0f9c4c8d9..be2ddbf4a 100644 --- a/artiq/test/lit/inferencer/cast.py +++ b/artiq/test/lit/inferencer/cast.py @@ -1,5 +1,8 @@ # RUN: %python -m artiq.compiler.testbench.inferencer +mono %s >%t # RUN: OutputCheck %s --file-to-check=%t -# CHECK-L: numpy.int64 +# CHECK-L: 2:numpy.int64 int64(2)**32 + +# CHECK-L: round:(1.0:float):numpy.int64 +int64(round(1.0)) From 6a10d544326b089503bc48956ed25a7a8ad4e5a3 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 16:52:14 +0000 Subject: [PATCH 0753/2457] firmware: migrate rpc_proto to new libio. This closes an old and horrible issue in that some code in ksupport may implicitly try to allocate and we'll never know until it crashes at runtime inside liballoc_stub. This also removes liballoc_stub. This also removes ReadExt and WriteExt from libproto. Hooray! --- artiq/firmware/Cargo.lock | 9 +-- artiq/firmware/ksupport/Cargo.toml | 4 +- artiq/firmware/ksupport/lib.rs | 18 ++--- artiq/firmware/liballoc_stub/Cargo.toml | 8 --- artiq/firmware/liballoc_stub/lib.rs | 18 ----- artiq/firmware/libio/lib.rs | 17 +++++ artiq/firmware/libio/proto.rs | 6 ++ artiq/firmware/libproto/Cargo.toml | 6 +- artiq/firmware/libproto/lib.rs | 92 ++----------------------- artiq/firmware/libproto/rpc_proto.rs | 33 ++++++--- artiq/firmware/runtime/Cargo.toml | 4 +- artiq/firmware/runtime/main.rs | 1 + artiq/firmware/runtime/mgmt.rs | 5 +- artiq/firmware/runtime/session.rs | 4 +- 14 files changed, 73 insertions(+), 152 deletions(-) delete mode 100644 artiq/firmware/liballoc_stub/Cargo.toml delete mode 100644 artiq/firmware/liballoc_stub/lib.rs diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index ef7c33ae5..5686e6124 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -2,10 +2,6 @@ name = "alloc_list" version = "0.0.0" -[[package]] -name = "alloc_stub" -version = "0.0.0" - [[package]] name = "amp" version = "0.0.0" @@ -146,15 +142,13 @@ dependencies = [ name = "ksupport" version = "0.0.0" dependencies = [ - "alloc_stub 0.0.0", "amp 0.0.0", "board 0.0.0", "build_misoc 0.0.0", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dyld 0.0.0", + "io 0.0.0", "proto 0.0.0", - "std_artiq 0.0.0", ] [[package]] @@ -211,7 +205,6 @@ dependencies = [ "dyld 0.0.0", "io 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "std_artiq 0.0.0", ] [[package]] diff --git a/artiq/firmware/ksupport/Cargo.toml b/artiq/firmware/ksupport/Cargo.toml index eafb7c7ae..53995f3e4 100644 --- a/artiq/firmware/ksupport/Cargo.toml +++ b/artiq/firmware/ksupport/Cargo.toml @@ -13,10 +13,8 @@ crate-type = ["staticlib"] build_misoc = { path = "../libbuild_misoc" } [dependencies] -byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } -alloc_stub = { path = "../liballoc_stub" } -std_artiq = { path = "../libstd_artiq" } +io = { path = "../libio", features = ["byteorder"] } dyld = { path = "../libdyld" } board = { path = "../libboard" } proto = { path = "../libproto" } diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index f4f7c8afb..e46d4e244 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -1,31 +1,27 @@ -#![feature(lang_items, asm, libc, panic_unwind, unwind_attributes, global_allocator)] +#![feature(lang_items, asm, libc, panic_unwind, unwind_attributes, global_allocator, + needs_panic_runtime)] #![no_std] +#![needs_panic_runtime] -extern crate byteorder; extern crate cslice; extern crate unwind; extern crate libc; -extern crate alloc_stub; -extern crate std_artiq as std; +extern crate io; extern crate board; extern crate dyld; extern crate proto; extern crate amp; use core::{mem, ptr, slice, str}; -use std::io::Cursor; use cslice::{CSlice, AsCSlice}; -use alloc_stub::StubAlloc; +use io::Cursor; use board::csr; use dyld::Library; use proto::{kernel_proto, rpc_proto}; use proto::kernel_proto::*; use amp::{mailbox, rpc_queue}; -#[global_allocator] -static mut ALLOC: StubAlloc = StubAlloc; - fn send(request: &Message) { unsafe { mailbox::send(request as *const _ as usize) } while !mailbox::acknowledged() {} @@ -131,9 +127,9 @@ extern fn rpc_send_async(service: u32, tag: CSlice, data: *const *const ()) rpc_proto::send_args(&mut writer, service, tag.as_ref(), data)?; writer.position() }; - proto::WriteExt::write_u32(&mut slice, length as u32) + io::proto::ProtoWrite::write_u32(&mut slice, length as u32) }).unwrap_or_else(|err| { - assert!(err.kind() == std::io::ErrorKind::WriteZero); + assert!(err == io::Error::UnexpectedEof); while !rpc_queue::empty() {} send(&RpcSend { diff --git a/artiq/firmware/liballoc_stub/Cargo.toml b/artiq/firmware/liballoc_stub/Cargo.toml deleted file mode 100644 index 1503c9005..000000000 --- a/artiq/firmware/liballoc_stub/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -authors = ["M-Labs"] -name = "alloc_stub" -version = "0.0.0" - -[lib] -name = "alloc_stub" -path = "lib.rs" diff --git a/artiq/firmware/liballoc_stub/lib.rs b/artiq/firmware/liballoc_stub/lib.rs deleted file mode 100644 index 941b5e16f..000000000 --- a/artiq/firmware/liballoc_stub/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![feature(alloc, allocator_api)] -#![no_std] - -extern crate alloc; - -use alloc::allocator::{Layout, AllocErr, Alloc}; - -pub struct StubAlloc; - -unsafe impl<'a> Alloc for &'a StubAlloc { - unsafe fn alloc(&mut self, _layout: Layout) -> Result<*mut u8, AllocErr> { - unimplemented!() - } - - unsafe fn dealloc(&mut self, _ptr: *mut u8, _layout: Layout) { - unimplemented!() - } -} diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs index 0524e1c6f..8c0b501af 100644 --- a/artiq/firmware/libio/lib.rs +++ b/artiq/firmware/libio/lib.rs @@ -99,6 +99,23 @@ pub trait Write { fn size_hint(&mut self, _min: usize, _max: Option) {} } +#[cfg(not(feature = "std_artiq"))] +impl<'a> Write for &'a mut [u8] { + type WriteError = !; + type FlushError = !; + + fn write(&mut self, buf: &[u8]) -> result::Result { + let len = buf.len().min(self.len()); + self[..len].copy_from_slice(&buf[..len]); + Ok(len) + } + + #[inline] + fn flush(&mut self) -> result::Result<(), Self::FlushError> { + Ok(()) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CursorError { EndOfBuffer diff --git a/artiq/firmware/libio/proto.rs b/artiq/firmware/libio/proto.rs index 143e8fd8f..bb36ffa40 100644 --- a/artiq/firmware/libio/proto.rs +++ b/artiq/firmware/libio/proto.rs @@ -1,15 +1,19 @@ +#[cfg(feature = "alloc")] use core::fmt; +#[cfg(feature = "alloc")] use alloc::string; use byteorder::{ByteOrder, NetworkEndian}; use ::{Read, Write, Error as IoError}; +#[cfg(feature = "alloc")] #[derive(Debug)] pub enum ReadStringError { Utf8Error(string::FromUtf8Error), Other(T) } +#[cfg(feature = "alloc")] impl fmt::Display for ReadStringError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -21,6 +25,7 @@ impl fmt::Display for ReadStringError { } } +#[cfg(feature = "alloc")] impl From>> for IoError { fn from(value: ReadStringError>) -> IoError { @@ -31,6 +36,7 @@ impl From>> for IoError } } +#[cfg(feature = "alloc")] #[cfg(feature = "std_artiq")] impl From> for ::std_artiq::io::Error where T: Into<::std_artiq::io::Error> diff --git a/artiq/firmware/libproto/Cargo.toml b/artiq/firmware/libproto/Cargo.toml index c1ff3a4c3..c1e980915 100644 --- a/artiq/firmware/libproto/Cargo.toml +++ b/artiq/firmware/libproto/Cargo.toml @@ -11,6 +11,8 @@ path = "lib.rs" byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } log = { version = "0.4", default-features = false, optional = true } -io = { path = "../libio", features = ["byteorder", "alloc"] } -std_artiq = { path = "../libstd_artiq", features = ["alloc"] } +io = { path = "../libio", features = ["byteorder"] } dyld = { path = "../libdyld" } + +[features] +alloc = ["io/alloc"] diff --git a/artiq/firmware/libproto/lib.rs b/artiq/firmware/libproto/lib.rs index 4f4e27018..949fabb35 100644 --- a/artiq/firmware/libproto/lib.rs +++ b/artiq/firmware/libproto/lib.rs @@ -1,8 +1,8 @@ #![no_std] -#![feature(alloc)] +#![cfg_attr(feature = "alloc", feature(alloc))] +#[cfg(feature = "alloc")] extern crate alloc; -extern crate byteorder; extern crate cslice; #[cfg(feature = "log")] #[macro_use] @@ -10,97 +10,17 @@ extern crate log; extern crate io; extern crate dyld; -extern crate std_artiq as std; // Internal protocols. pub mod kernel_proto; // External protocols. +#[cfg(feature = "alloc")] pub mod mgmt_proto; +#[cfg(feature = "alloc")] pub mod analyzer_proto; +#[cfg(feature = "alloc")] pub mod moninj_proto; +#[cfg(feature = "alloc")] pub mod session_proto; pub mod rpc_proto; - -use std::io::{Read, Write, Result, Error, ErrorKind}; -use std::vec::Vec; -use std::string::String; -use byteorder::{ByteOrder, NetworkEndian}; - -pub trait ReadExt: Read { - fn read_u8(&mut self) -> Result { - let mut bytes = [0; 1]; - self.read_exact(&mut bytes)?; - Ok(bytes[0]) - } - - fn read_u16(&mut self) -> Result { - let mut bytes = [0; 2]; - self.read_exact(&mut bytes)?; - Ok(NetworkEndian::read_u16(&bytes)) - } - - fn read_u32(&mut self) -> Result { - let mut bytes = [0; 4]; - self.read_exact(&mut bytes)?; - Ok(NetworkEndian::read_u32(&bytes)) - } - - fn read_u64(&mut self) -> Result { - let mut bytes = [0; 8]; - self.read_exact(&mut bytes)?; - Ok(NetworkEndian::read_u64(&bytes)) - } - - fn read_bytes(&mut self) -> Result> { - let length = self.read_u32()?; - let mut value = Vec::new(); - value.resize(length as usize, 0); - self.read_exact(&mut value)?; - Ok(value) - } - - fn read_string(&mut self) -> Result { - let bytes = self.read_bytes()?; - String::from_utf8(bytes) - .map_err(|_| Error::new(ErrorKind::InvalidData, "invalid UTF-8")) - } -} - -impl ReadExt for R {} - -pub trait WriteExt: Write { - fn write_u8(&mut self, value: u8) -> Result<()> { - let bytes = [value; 1]; - self.write_all(&bytes) - } - - fn write_u16(&mut self, value: u16) -> Result<()> { - let mut bytes = [0; 2]; - NetworkEndian::write_u16(&mut bytes, value); - self.write_all(&bytes) - } - - fn write_u32(&mut self, value: u32) -> Result<()> { - let mut bytes = [0; 4]; - NetworkEndian::write_u32(&mut bytes, value); - self.write_all(&bytes) - } - - fn write_u64(&mut self, value: u64) -> Result<()> { - let mut bytes = [0; 8]; - NetworkEndian::write_u64(&mut bytes, value); - self.write_all(&bytes) - } - - fn write_bytes(&mut self, value: &[u8]) -> Result<()> { - self.write_u32(value.len() as u32)?; - self.write_all(value) - } - - fn write_string(&mut self, value: &str) -> Result<()> { - self.write_bytes(value.as_bytes()) - } -} - -impl WriteExt for W {} diff --git a/artiq/firmware/libproto/rpc_proto.rs b/artiq/firmware/libproto/rpc_proto.rs index 8ff7693a9..226cb47b6 100644 --- a/artiq/firmware/libproto/rpc_proto.rs +++ b/artiq/firmware/libproto/rpc_proto.rs @@ -1,11 +1,16 @@ -use std::io::{self, Read, Write}; -use std::str; +use core::str; use cslice::{CSlice, CMutSlice}; -use {ReadExt, WriteExt}; + +use io::{Read, Write, Result}; +use io::proto::{ProtoRead, ProtoWrite}; + use self::tag::{Tag, TagIterator, split_tag}; -unsafe fn recv_value(reader: &mut Read, tag: Tag, data: &mut *mut (), - alloc: &Fn(usize) -> io::Result<*mut ()>) -> io::Result<()> { +unsafe fn recv_value(reader: &mut T, tag: Tag, data: &mut *mut (), + alloc: &Fn(usize) -> Result<*mut (), T::ReadError>) + -> Result<(), T::ReadError> + where T: Read + ?Sized +{ macro_rules! consume_value { ($ty:ty, |$ptr:ident| $map:expr) => ({ let $ptr = (*data) as *mut $ty; @@ -71,8 +76,11 @@ unsafe fn recv_value(reader: &mut Read, tag: Tag, data: &mut *mut (), } } -pub fn recv_return(reader: &mut Read, tag_bytes: &[u8], data: *mut (), - alloc: &Fn(usize) -> io::Result<*mut ()>) -> io::Result<()> { +pub fn recv_return(reader: &mut T, tag_bytes: &[u8], data: *mut (), + alloc: &Fn(usize) -> Result<*mut (), T::ReadError>) + -> Result<(), T::ReadError> + where T: Read + ?Sized +{ let mut it = TagIterator::new(tag_bytes); #[cfg(feature = "log")] debug!("recv ...->{}", it); @@ -84,7 +92,10 @@ pub fn recv_return(reader: &mut Read, tag_bytes: &[u8], data: *mut (), Ok(()) } -unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io::Result<()> { +unsafe fn send_value(writer: &mut T, tag: Tag, data: &mut *const ()) + -> Result<(), T::WriteError> + where T: Write + ?Sized +{ macro_rules! consume_value { ($ty:ty, |$ptr:ident| $map:expr) => ({ let $ptr = (*data) as *const $ty; @@ -158,8 +169,10 @@ unsafe fn send_value(writer: &mut Write, tag: Tag, data: &mut *const ()) -> io:: } } -pub fn send_args(writer: &mut Write, service: u32, tag_bytes: &[u8], - data: *const *const ()) -> io::Result<()> { +pub fn send_args(writer: &mut T, service: u32, tag_bytes: &[u8], data: *const *const ()) + -> Result<(), T::WriteError> + where T: Write + ?Sized +{ let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes); let mut args_it = TagIterator::new(arg_tags_bytes); diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index ddca4d8a6..a264157f4 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -19,13 +19,13 @@ cslice = { version = "0.3" } log = { version = "0.4", default-features = false } managed = { version = "0.6", default-features = false, features = ["alloc", "map"] } unwind_backtrace = { path = "../libunwind_backtrace" } -io = { path = "../libio", features = ["std_artiq"] } +io = { path = "../libio", features = ["byteorder", "std_artiq"] } board = { path = "../libboard", features = ["uart_console", "smoltcp"] } alloc_list = { path = "../liballoc_list" } std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] } logger_artiq = { path = "../liblogger_artiq" } board_artiq = { path = "../libboard_artiq" } -proto = { path = "../libproto", features = ["log"] } +proto = { path = "../libproto", features = ["log", "alloc"] } amp = { path = "../libamp" } drtioaux = { path = "../libdrtioaux" } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 7472acc51..212e7f7de 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -12,6 +12,7 @@ extern crate smoltcp; extern crate alloc_list; extern crate unwind_backtrace; +extern crate io; #[macro_use] extern crate std_artiq as std; extern crate logger_artiq; diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 3c14e776e..70fb2ea07 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -1,10 +1,11 @@ -use board::boot; use std::io::{self, Read, Write}; use log::{self, LevelFilter}; + +use io::proto::ProtoWrite; +use board::boot; use logger_artiq::BufferLogger; use sched::Io; use sched::{TcpListener, TcpStream}; -use proto::WriteExt; use mgmt_proto::*; use profiler; diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 2d617ef78..d60a48430 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -313,12 +313,12 @@ fn process_host_message(io: &Io, })?; rpc::recv_return(stream, &tag, slot, &|size| { kern_send(io, &kern::RpcRecvReply(Ok(size)))?; - kern_recv(io, |reply| { + Ok(kern_recv(io, |reply| { match reply { &kern::RpcRecvRequest(slot) => Ok(slot), other => unexpected!("unexpected reply from kernel CPU: {:?}", other) } - }) + })?) })?; kern_send(io, &kern::RpcRecvReply(Ok(0)))?; From 764386c9e39d4237dd1b563a93387a50ad22c63d Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 17:26:36 +0000 Subject: [PATCH 0754/2457] firmware: split libdrtioaux into libproto and libboard_artiq modules. All other protocol code lives in libproto, and all other gateware interfaces live in libboard_artiq. --- artiq/firmware/Cargo.lock | 16 ++----- artiq/firmware/libboard_artiq/Cargo.toml | 3 ++ .../hw.rs => libboard_artiq/drtioaux.rs} | 11 +++-- artiq/firmware/libboard_artiq/lib.rs | 8 +++- artiq/firmware/libdrtioaux/Cargo.toml | 18 ------- artiq/firmware/libdrtioaux/build.rs | 5 -- .../lib.rs => libproto/drtioaux_proto.rs} | 11 ----- artiq/firmware/libproto/lib.rs | 1 + artiq/firmware/runtime/Cargo.toml | 1 - artiq/firmware/runtime/kern_hwreq.rs | 26 +++++----- artiq/firmware/runtime/main.rs | 8 ++-- artiq/firmware/runtime/moninj.rs | 10 ++-- artiq/firmware/runtime/rtio_mgt.rs | 14 +++--- artiq/firmware/satman/Cargo.toml | 1 - artiq/firmware/satman/main.rs | 47 +++++++++---------- 15 files changed, 74 insertions(+), 106 deletions(-) rename artiq/firmware/{libdrtioaux/hw.rs => libboard_artiq/drtioaux.rs} (97%) delete mode 100644 artiq/firmware/libdrtioaux/Cargo.toml delete mode 100644 artiq/firmware/libdrtioaux/build.rs rename artiq/firmware/{libdrtioaux/lib.rs => libproto/drtioaux_proto.rs} (98%) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 5686e6124..d4c556ebb 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -35,7 +35,10 @@ dependencies = [ "build_artiq 0.0.0", "build_misoc 0.0.0", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "io 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proto 0.0.0", ] [[package]] @@ -98,17 +101,6 @@ name = "cslice" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "drtioaux" -version = "0.0.0" -dependencies = [ - "board 0.0.0", - "build_misoc 0.0.0", - "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "io 0.0.0", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "dyld" version = "0.0.0" @@ -219,7 +211,6 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "drtioaux 0.0.0", "fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)", "io 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -248,7 +239,6 @@ dependencies = [ "board_artiq 0.0.0", "build_artiq 0.0.0", "build_misoc 0.0.0", - "drtioaux 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/artiq/firmware/libboard_artiq/Cargo.toml b/artiq/firmware/libboard_artiq/Cargo.toml index 149fe4efc..573440a77 100644 --- a/artiq/firmware/libboard_artiq/Cargo.toml +++ b/artiq/firmware/libboard_artiq/Cargo.toml @@ -15,7 +15,10 @@ build_artiq = { path = "../libbuild_artiq" } [dependencies] bitflags = "1.0" byteorder = { version = "1.0", default-features = false } +crc = { version = "1.7", default-features = false } log = { version = "0.4", default-features = false } +io = { path = "../libio", features = ["byteorder"] } +proto = { path = "../libproto" } board = { path = "../libboard" } [features] diff --git a/artiq/firmware/libdrtioaux/hw.rs b/artiq/firmware/libboard_artiq/drtioaux.rs similarity index 97% rename from artiq/firmware/libdrtioaux/hw.rs rename to artiq/firmware/libboard_artiq/drtioaux.rs index bd4f609b5..149f608d6 100644 --- a/artiq/firmware/libdrtioaux/hw.rs +++ b/artiq/firmware/libboard_artiq/drtioaux.rs @@ -1,8 +1,11 @@ -use core::fmt; -use io::{Cursor, Error as IoError}; -use io::proto::ProtoRead; +use core::{slice, fmt, result}; +use crc; -use super::*; +use io::{Cursor, Error as IoError}; +use io::proto::{ProtoRead, ProtoWrite}; +use board; + +pub use proto::drtioaux_proto::Packet; pub type Result = result::Result; diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index f7066a653..bf4c491a2 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -1,12 +1,15 @@ -#![feature(asm, lang_items)] +#![feature(asm, lang_items, never_type)] #![no_std] #[macro_use] extern crate bitflags; extern crate byteorder; +extern crate crc; #[macro_use] extern crate log; extern crate board; +extern crate io; +extern crate proto; pub mod pcr; @@ -28,3 +31,6 @@ mod ad9154_reg; pub mod ad9154; #[cfg(has_allaki_atts)] pub mod hmc542; + +#[cfg(has_drtio)] +pub mod drtioaux; diff --git a/artiq/firmware/libdrtioaux/Cargo.toml b/artiq/firmware/libdrtioaux/Cargo.toml deleted file mode 100644 index 5959b56a8..000000000 --- a/artiq/firmware/libdrtioaux/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -authors = ["M-Labs"] -name = "drtioaux" -version = "0.0.0" -build = "build.rs" - -[lib] -name = "drtioaux" -path = "lib.rs" - -[build-dependencies] -build_misoc = { path = "../libbuild_misoc" } - -[dependencies] -log = { version = "0.4", default-features = false } -crc = { version = "1.7", default-features = false } -io = { path = "../libio", features = ["byteorder"] } -board = { path = "../libboard" } diff --git a/artiq/firmware/libdrtioaux/build.rs b/artiq/firmware/libdrtioaux/build.rs deleted file mode 100644 index 3548ea5ff..000000000 --- a/artiq/firmware/libdrtioaux/build.rs +++ /dev/null @@ -1,5 +0,0 @@ -extern crate build_misoc; - -fn main() { - build_misoc::cfg(); -} diff --git a/artiq/firmware/libdrtioaux/lib.rs b/artiq/firmware/libproto/drtioaux_proto.rs similarity index 98% rename from artiq/firmware/libdrtioaux/lib.rs rename to artiq/firmware/libproto/drtioaux_proto.rs index bed9bddf7..1899f0787 100644 --- a/artiq/firmware/libdrtioaux/lib.rs +++ b/artiq/firmware/libproto/drtioaux_proto.rs @@ -1,11 +1,3 @@ -#![no_std] -#![feature(never_type)] - -extern crate crc; - -extern crate io; -extern crate board; - use io::{Read, Write, Error, Result}; use io::proto::{ProtoRead, ProtoWrite}; @@ -264,6 +256,3 @@ impl Packet { Ok(()) } } - -#[cfg(has_drtio)] -pub mod hw; diff --git a/artiq/firmware/libproto/lib.rs b/artiq/firmware/libproto/lib.rs index 949fabb35..36e776d0f 100644 --- a/artiq/firmware/libproto/lib.rs +++ b/artiq/firmware/libproto/lib.rs @@ -13,6 +13,7 @@ extern crate dyld; // Internal protocols. pub mod kernel_proto; +pub mod drtioaux_proto; // External protocols. #[cfg(feature = "alloc")] diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index a264157f4..fc8cb35ad 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -27,7 +27,6 @@ logger_artiq = { path = "../liblogger_artiq" } board_artiq = { path = "../libboard_artiq" } proto = { path = "../libproto", features = ["log", "alloc"] } amp = { path = "../libamp" } -drtioaux = { path = "../libdrtioaux" } [dependencies.fringe] git = "https://github.com/m-labs/libfringe" diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index 87ebd665e..fec653e9c 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -10,7 +10,7 @@ mod drtio_i2c { use drtioaux; fn basic_reply(nodeno: u8) -> Result<(), ()> { - match drtioaux::hw::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout(nodeno, None) { Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } @@ -27,7 +27,7 @@ mod drtio_i2c { pub fn start(nodeno: u8, busno: u8) -> Result<(), ()> { let request = drtioaux::Packet::I2cStartRequest { busno: busno }; - if drtioaux::hw::send(nodeno, &request).is_err() { + if drtioaux::send(nodeno, &request).is_err() { return Err(()) } basic_reply(nodeno) @@ -35,7 +35,7 @@ mod drtio_i2c { pub fn restart(nodeno: u8, busno: u8) -> Result<(), ()> { let request = drtioaux::Packet::I2cRestartRequest { busno: busno }; - if drtioaux::hw::send(nodeno, &request).is_err() { + if drtioaux::send(nodeno, &request).is_err() { return Err(()) } basic_reply(nodeno) @@ -43,7 +43,7 @@ mod drtio_i2c { pub fn stop(nodeno: u8, busno: u8) -> Result<(), ()> { let request = drtioaux::Packet::I2cStopRequest { busno: busno }; - if drtioaux::hw::send(nodeno, &request).is_err() { + if drtioaux::send(nodeno, &request).is_err() { return Err(()) } basic_reply(nodeno) @@ -54,10 +54,10 @@ mod drtio_i2c { busno: busno, data: data }; - if drtioaux::hw::send(nodeno, &request).is_err() { + if drtioaux::send(nodeno, &request).is_err() { return Err(()) } - match drtioaux::hw::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout(nodeno, None) { Ok(drtioaux::Packet::I2cWriteReply { succeeded, ack }) => { if succeeded { Ok(ack) } else { Err(()) } } @@ -77,10 +77,10 @@ mod drtio_i2c { busno: busno, ack: ack }; - if drtioaux::hw::send(nodeno, &request).is_err() { + if drtioaux::send(nodeno, &request).is_err() { return Err(()) } - match drtioaux::hw::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout(nodeno, None) { Ok(drtioaux::Packet::I2cReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } @@ -179,7 +179,7 @@ mod drtio_spi { use drtioaux; fn basic_reply(nodeno: u8) -> Result<(), ()> { - match drtioaux::hw::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout(nodeno, None) { Ok(drtioaux::Packet::SpiBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } @@ -202,7 +202,7 @@ mod drtio_spi { div: div, cs: cs }; - if drtioaux::hw::send(nodeno, &request).is_err() { + if drtioaux::send(nodeno, &request).is_err() { return Err(()) } basic_reply(nodeno) @@ -213,7 +213,7 @@ mod drtio_spi { busno: busno, data: data }; - if drtioaux::hw::send(nodeno, &request).is_err() { + if drtioaux::send(nodeno, &request).is_err() { return Err(()) } basic_reply(nodeno) @@ -221,10 +221,10 @@ mod drtio_spi { pub fn read(nodeno: u8, busno: u8) -> Result { let request = drtioaux::Packet::SpiReadRequest { busno: busno }; - if drtioaux::hw::send(nodeno, &request).is_err() { + if drtioaux::send(nodeno, &request).is_err() { return Err(()) } - match drtioaux::hw::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout(nodeno, None) { Ok(drtioaux::Packet::SpiReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 212e7f7de..0aed7b4f8 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -21,8 +21,6 @@ extern crate board; extern crate board_artiq; extern crate proto; extern crate amp; -#[cfg(has_drtio)] -extern crate drtioaux; use core::convert::TryFrom; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; @@ -31,7 +29,11 @@ use board::irq; use board::config; #[cfg(has_ethmac)] use board::ethmac; -use proto::{mgmt_proto, analyzer_proto, moninj_proto, rpc_proto, session_proto, kernel_proto}; +#[cfg(has_drtio)] +use board_artiq::drtioaux; +use proto::{mgmt_proto, moninj_proto, rpc_proto, session_proto,kernel_proto}; +#[cfg(has_rtio_analyzer)] +use proto::analyzer_proto; use amp::{mailbox, rpc_queue}; #[cfg(has_rtio_core)] diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index 76de9cfbb..429d8d938 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -35,14 +35,14 @@ fn read_probe_local(channel: u16, probe: u8) -> u32 { #[cfg(has_drtio)] fn read_probe_drtio(nodeno: u8, channel: u16, probe: u8) -> u32 { let request = drtioaux::Packet::MonitorRequest { channel: channel, probe: probe }; - match drtioaux::hw::send(nodeno, &request) { + match drtioaux::send(nodeno, &request) { Ok(_) => (), Err(e) => { error!("aux packet error ({})", e); return 0; } } - match drtioaux::hw::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout(nodeno, None) { Ok(drtioaux::Packet::MonitorReply { value }) => return value, Ok(_) => error!("received unexpected aux packet"), Err(e) => error!("aux packet error ({})", e) @@ -85,7 +85,7 @@ fn inject_drtio(nodeno: u8, channel: u16, overrd: u8, value: u8) { overrd: overrd, value: value }; - match drtioaux::hw::send(nodeno, &request) { + match drtioaux::send(nodeno, &request) { Ok(_) => (), Err(e) => error!("aux packet error ({})", e) } @@ -126,14 +126,14 @@ fn read_injection_status_drtio(nodeno: u8, channel: u16, overrd: u8) -> u8 { channel: channel, overrd: overrd }; - match drtioaux::hw::send(nodeno, &request) { + match drtioaux::send(nodeno, &request) { Ok(_) => (), Err(e) => { error!("aux packet error ({})", e); return 0; } } - match drtioaux::hw::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout(nodeno, None) { Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value, Ok(_) => error!("received unexpected aux packet"), Err(e) => error!("aux packet error ({})", e) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index d2c926b5d..41dc4a18e 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -99,9 +99,9 @@ pub mod drtio { return 0 } count += 1; - drtioaux::hw::send_link(linkno, &drtioaux::Packet::EchoRequest).unwrap(); + drtioaux::send_link(linkno, &drtioaux::Packet::EchoRequest).unwrap(); io.sleep(100).unwrap(); - let pr = drtioaux::hw::recv_link(linkno); + let pr = drtioaux::recv_link(linkno); match pr { Ok(Some(drtioaux::Packet::EchoReply)) => return count, _ => {} @@ -131,8 +131,8 @@ pub mod drtio { } fn process_aux_errors(linkno: u8) { - drtioaux::hw::send_link(linkno, &drtioaux::Packet::RtioErrorRequest).unwrap(); - match drtioaux::hw::recv_timeout_link(linkno, None) { + drtioaux::send_link(linkno, &drtioaux::Packet::RtioErrorRequest).unwrap(); + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::RtioNoErrorReply) => (), Ok(drtioaux::Packet::RtioErrorSequenceErrorReply { channel }) => error!("[LINK#{}] RTIO sequence error involving channel {}", linkno, channel), @@ -144,7 +144,7 @@ pub mod drtio { Err(e) => error!("[LINK#{}] aux packet error ({})", linkno, e) } } - + pub fn link_thread(io: Io) { loop { for linkno in 0..csr::DRTIO.len() { @@ -183,9 +183,9 @@ pub mod drtio { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; if link_up(linkno) { - drtioaux::hw::send_link(linkno, + drtioaux::send_link(linkno, &drtioaux::Packet::ResetRequest { phy: false }).unwrap(); - match drtioaux::hw::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::ResetAck) => (), Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno), Err(e) => error!("[LINK#{}] reset failed, aux packet error ({})", linkno, e) diff --git a/artiq/firmware/satman/Cargo.toml b/artiq/firmware/satman/Cargo.toml index a227e58e2..3dffc9652 100644 --- a/artiq/firmware/satman/Cargo.toml +++ b/artiq/firmware/satman/Cargo.toml @@ -17,4 +17,3 @@ build_artiq = { path = "../libbuild_artiq" } log = { version = "0.4", default-features = false } board = { path = "../libboard", features = ["uart_console", "log"] } board_artiq = { path = "../libboard_artiq" } -drtioaux = { path = "../libdrtioaux" } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 9afe0ff4c..a0e857f4f 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -6,10 +6,9 @@ extern crate log; #[macro_use] extern crate board; extern crate board_artiq; -extern crate drtioaux; use board::csr; -use board_artiq::{i2c, spi, si5324}; +use board_artiq::{i2c, spi, si5324, drtioaux}; #[cfg(has_serwb_phy_amc)] use board_artiq::serwb; #[cfg(has_hmc830_7043)] @@ -27,12 +26,12 @@ fn drtio_reset_phy(reset: bool) { } } -fn process_aux_packet(packet: drtioaux::Packet) -> drtioaux::hw::Result<()> { +fn process_aux_packet(packet: drtioaux::Packet) -> drtioaux::Result<()> { // In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels, // and u16 otherwise; hence the `as _` conversion. match packet { drtioaux::Packet::EchoRequest => - drtioaux::hw::send_link(0, &drtioaux::Packet::EchoReply), + drtioaux::send_link(0, &drtioaux::Packet::EchoReply), drtioaux::Packet::ResetRequest { phy } => { if phy { drtio_reset_phy(true); @@ -41,7 +40,7 @@ fn process_aux_packet(packet: drtioaux::Packet) -> drtioaux::hw::Result<()> { drtio_reset(true); drtio_reset(false); } - drtioaux::hw::send_link(0, &drtioaux::Packet::ResetAck) + drtioaux::send_link(0, &drtioaux::Packet::ResetAck) }, drtioaux::Packet::RtioErrorRequest => { @@ -55,7 +54,7 @@ fn process_aux_packet(packet: drtioaux::Packet) -> drtioaux::hw::Result<()> { channel = (csr::DRTIO[0].sequence_error_channel_read)(); (csr::DRTIO[0].rtio_error_write)(1); } - drtioaux::hw::send_link(0, + drtioaux::send_link(0, &drtioaux::Packet::RtioErrorSequenceErrorReply { channel }) } else if errors & 2 != 0 { let channel; @@ -63,7 +62,7 @@ fn process_aux_packet(packet: drtioaux::Packet) -> drtioaux::hw::Result<()> { channel = (csr::DRTIO[0].collision_channel_read)(); (csr::DRTIO[0].rtio_error_write)(2); } - drtioaux::hw::send_link(0, + drtioaux::send_link(0, &drtioaux::Packet::RtioErrorCollisionReply { channel }) } else if errors & 4 != 0 { let channel; @@ -71,11 +70,11 @@ fn process_aux_packet(packet: drtioaux::Packet) -> drtioaux::hw::Result<()> { channel = (board::csr::DRTIO[0].busy_channel_read)(); (board::csr::DRTIO[0].rtio_error_write)(4); } - drtioaux::hw::send_link(0, + drtioaux::send_link(0, &drtioaux::Packet::RtioErrorBusyReply { channel }) } else { - drtioaux::hw::send_link(0, &drtioaux::Packet::RtioNoErrorReply) + drtioaux::send_link(0, &drtioaux::Packet::RtioNoErrorReply) } } @@ -93,7 +92,7 @@ fn process_aux_packet(packet: drtioaux::Packet) -> drtioaux::hw::Result<()> { value = 0; } let reply = drtioaux::Packet::MonitorReply { value: value as u32 }; - drtioaux::hw::send_link(0, &reply) + drtioaux::send_link(0, &reply) }, drtioaux::Packet::InjectionRequest { channel, overrd, value } => { #[cfg(has_rtio_moninj)] @@ -116,53 +115,53 @@ fn process_aux_packet(packet: drtioaux::Packet) -> drtioaux::hw::Result<()> { { value = 0; } - drtioaux::hw::send_link(0, &drtioaux::Packet::InjectionStatusReply { value: value }) + drtioaux::send_link(0, &drtioaux::Packet::InjectionStatusReply { value: value }) }, drtioaux::Packet::I2cStartRequest { busno } => { let succeeded = i2c::start(busno).is_ok(); - drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) + drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } drtioaux::Packet::I2cRestartRequest { busno } => { let succeeded = i2c::restart(busno).is_ok(); - drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) + drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } drtioaux::Packet::I2cStopRequest { busno } => { let succeeded = i2c::stop(busno).is_ok(); - drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) + drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } drtioaux::Packet::I2cWriteRequest { busno, data } => { match i2c::write(busno, data) { - Ok(ack) => drtioaux::hw::send_link(0, + Ok(ack) => drtioaux::send_link(0, &drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }), - Err(_) => drtioaux::hw::send_link(0, + Err(_) => drtioaux::send_link(0, &drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false }) } } drtioaux::Packet::I2cReadRequest { busno, ack } => { match i2c::read(busno, ack) { - Ok(data) => drtioaux::hw::send_link(0, + Ok(data) => drtioaux::send_link(0, &drtioaux::Packet::I2cReadReply { succeeded: true, data: data }), - Err(_) => drtioaux::hw::send_link(0, + Err(_) => drtioaux::send_link(0, &drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff }) } } drtioaux::Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => { let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); - drtioaux::hw::send_link(0, + drtioaux::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) }, drtioaux::Packet::SpiWriteRequest { busno, data } => { let succeeded = spi::write(busno, data).is_ok(); - drtioaux::hw::send_link(0, + drtioaux::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) } drtioaux::Packet::SpiReadRequest { busno } => { match spi::read(busno) { - Ok(data) => drtioaux::hw::send_link(0, + Ok(data) => drtioaux::send_link(0, &drtioaux::Packet::SpiReadReply { succeeded: true, data: data }), - Err(_) => drtioaux::hw::send_link(0, + Err(_) => drtioaux::send_link(0, &drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 }) } } @@ -176,7 +175,7 @@ fn process_aux_packet(packet: drtioaux::Packet) -> drtioaux::hw::Result<()> { fn process_aux_packets() { let result = - drtioaux::hw::recv_link(0).and_then(|packet| { + drtioaux::recv_link(0).and_then(|packet| { if let Some(packet) = packet { process_aux_packet(packet) } else { @@ -267,7 +266,7 @@ pub extern fn main() -> i32 { info!("link is up, switching to recovered clock"); si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); si5324::siphaser::calibrate_skew(32).expect("failed to calibrate skew"); - drtioaux::hw::reset(0); + drtioaux::reset(0); drtio_reset(false); drtio_reset_phy(false); while drtio_link_rx_up() { From 1ff42683d943b730e38462645624a84d087bc557 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 17:33:25 +0000 Subject: [PATCH 0755/2457] firmware: merge libamp into libboard_artiq. All gateware interfaces live in libboard_artiq, but libamp predates libboard_artiq. --- artiq/firmware/Cargo.lock | 10 +--------- artiq/firmware/ksupport/Cargo.toml | 2 +- artiq/firmware/ksupport/lib.rs | 10 +++++----- artiq/firmware/libamp/Cargo.toml | 11 ----------- artiq/firmware/libamp/lib.rs | 6 ------ artiq/firmware/libboard_artiq/lib.rs | 3 +++ artiq/firmware/{libamp => libboard_artiq}/mailbox.rs | 0 .../firmware/{libamp => libboard_artiq}/rpc_queue.rs | 0 artiq/firmware/runtime/Cargo.toml | 1 - artiq/firmware/runtime/main.rs | 3 +-- 10 files changed, 11 insertions(+), 35 deletions(-) delete mode 100644 artiq/firmware/libamp/Cargo.toml delete mode 100644 artiq/firmware/libamp/lib.rs rename artiq/firmware/{libamp => libboard_artiq}/mailbox.rs (100%) rename artiq/firmware/{libamp => libboard_artiq}/rpc_queue.rs (100%) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index d4c556ebb..9ce01cd31 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -2,13 +2,6 @@ name = "alloc_list" version = "0.0.0" -[[package]] -name = "amp" -version = "0.0.0" -dependencies = [ - "board 0.0.0", -] - [[package]] name = "bitflags" version = "1.0.1" @@ -134,8 +127,8 @@ dependencies = [ name = "ksupport" version = "0.0.0" dependencies = [ - "amp 0.0.0", "board 0.0.0", + "board_artiq 0.0.0", "build_misoc 0.0.0", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dyld 0.0.0", @@ -204,7 +197,6 @@ name = "runtime" version = "0.0.0" dependencies = [ "alloc_list 0.0.0", - "amp 0.0.0", "board 0.0.0", "board_artiq 0.0.0", "build_artiq 0.0.0", diff --git a/artiq/firmware/ksupport/Cargo.toml b/artiq/firmware/ksupport/Cargo.toml index 53995f3e4..ef5513344 100644 --- a/artiq/firmware/ksupport/Cargo.toml +++ b/artiq/firmware/ksupport/Cargo.toml @@ -17,5 +17,5 @@ cslice = { version = "0.3" } io = { path = "../libio", features = ["byteorder"] } dyld = { path = "../libdyld" } board = { path = "../libboard" } +board_artiq = { path = "../libboard_artiq" } proto = { path = "../libproto" } -amp = { path = "../libamp" } diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index e46d4e244..1975ca12b 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -8,19 +8,19 @@ extern crate unwind; extern crate libc; extern crate io; -extern crate board; extern crate dyld; +extern crate board; +extern crate board_artiq; extern crate proto; -extern crate amp; use core::{mem, ptr, slice, str}; use cslice::{CSlice, AsCSlice}; use io::Cursor; -use board::csr; use dyld::Library; +use board::csr; +use board_artiq::{mailbox, rpc_queue}; use proto::{kernel_proto, rpc_proto}; -use proto::kernel_proto::*; -use amp::{mailbox, rpc_queue}; +use kernel_proto::*; fn send(request: &Message) { unsafe { mailbox::send(request as *const _ as usize) } diff --git a/artiq/firmware/libamp/Cargo.toml b/artiq/firmware/libamp/Cargo.toml deleted file mode 100644 index 2607f80c2..000000000 --- a/artiq/firmware/libamp/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -authors = ["M-Labs"] -name = "amp" -version = "0.0.0" - -[lib] -name = "amp" -path = "lib.rs" - -[dependencies] -board = { path = "../libboard" } diff --git a/artiq/firmware/libamp/lib.rs b/artiq/firmware/libamp/lib.rs deleted file mode 100644 index df46ef0c0..000000000 --- a/artiq/firmware/libamp/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![no_std] - -extern crate board; - -pub mod mailbox; -pub mod rpc_queue; diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index bf4c491a2..a94c20a62 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -16,6 +16,9 @@ pub mod pcr; pub mod i2c; pub mod spi; +pub mod mailbox; +pub mod rpc_queue; + #[cfg(has_si5324)] pub mod si5324; diff --git a/artiq/firmware/libamp/mailbox.rs b/artiq/firmware/libboard_artiq/mailbox.rs similarity index 100% rename from artiq/firmware/libamp/mailbox.rs rename to artiq/firmware/libboard_artiq/mailbox.rs diff --git a/artiq/firmware/libamp/rpc_queue.rs b/artiq/firmware/libboard_artiq/rpc_queue.rs similarity index 100% rename from artiq/firmware/libamp/rpc_queue.rs rename to artiq/firmware/libboard_artiq/rpc_queue.rs diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index fc8cb35ad..7eff26c33 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -26,7 +26,6 @@ std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] } logger_artiq = { path = "../liblogger_artiq" } board_artiq = { path = "../libboard_artiq" } proto = { path = "../libproto", features = ["log", "alloc"] } -amp = { path = "../libamp" } [dependencies.fringe] git = "https://github.com/m-labs/libfringe" diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 0aed7b4f8..2f14a4b4a 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -20,7 +20,6 @@ extern crate logger_artiq; extern crate board; extern crate board_artiq; extern crate proto; -extern crate amp; use core::convert::TryFrom; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; @@ -34,7 +33,7 @@ use board_artiq::drtioaux; use proto::{mgmt_proto, moninj_proto, rpc_proto, session_proto,kernel_proto}; #[cfg(has_rtio_analyzer)] use proto::analyzer_proto; -use amp::{mailbox, rpc_queue}; +use board_artiq::{mailbox, rpc_queue}; #[cfg(has_rtio_core)] mod rtio_mgt; From 02b8426f607e44a1cca69fc3f21015da8cdded54 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 17:54:29 +0000 Subject: [PATCH 0756/2457] firmware: rename libboard to libboard_misoc. By analogy with libbuild_misoc. Hopefully one day it actually gets moved to misoc... --- artiq/firmware/Cargo.lock | 42 +++++++++---------- artiq/firmware/bootloader/Cargo.toml | 2 +- artiq/firmware/bootloader/main.rs | 18 ++++---- artiq/firmware/ksupport/Cargo.toml | 2 +- artiq/firmware/ksupport/api.rs | 4 +- artiq/firmware/ksupport/lib.rs | 4 +- artiq/firmware/ksupport/rtio.rs | 2 +- artiq/firmware/libboard_artiq/Cargo.toml | 2 +- artiq/firmware/libboard_artiq/ad9154.rs | 2 +- artiq/firmware/libboard_artiq/drtioaux.rs | 35 ++++++++-------- artiq/firmware/libboard_artiq/hmc542.rs | 2 +- artiq/firmware/libboard_artiq/hmc830_7043.rs | 6 +-- artiq/firmware/libboard_artiq/i2c.rs | 2 +- artiq/firmware/libboard_artiq/lib.rs | 4 +- artiq/firmware/libboard_artiq/mailbox.rs | 2 +- artiq/firmware/libboard_artiq/pcr.rs | 2 +- artiq/firmware/libboard_artiq/rpc_queue.rs | 2 +- artiq/firmware/libboard_artiq/serwb.rs | 2 +- artiq/firmware/libboard_artiq/si5324.rs | 7 ++-- artiq/firmware/libboard_artiq/spi.rs | 2 +- .../{libboard => libboard_misoc}/Cargo.toml | 4 +- .../{libboard => libboard_misoc}/build.rs | 0 .../{libboard => libboard_misoc}/clock.rs | 0 .../{libboard => libboard_misoc}/config.rs | 0 .../{libboard => libboard_misoc}/ethmac.rs | 0 .../{libboard => libboard_misoc}/ident.rs | 0 .../{libboard => libboard_misoc}/lib.rs | 0 .../{libboard => libboard_misoc}/or1k/boot.rs | 0 .../or1k/cache.rs | 0 .../{libboard => libboard_misoc}/or1k/irq.rs | 0 .../{libboard => libboard_misoc}/or1k/mod.rs | 0 .../{libboard => libboard_misoc}/or1k/spr.rs | 0 .../or1k/vectors.S | 0 .../{libboard => libboard_misoc}/sdram.rs | 0 .../{libboard => libboard_misoc}/spiflash.rs | 0 .../{libboard => libboard_misoc}/uart.rs | 0 .../uart_console.rs | 0 .../uart_logger.rs | 0 artiq/firmware/liblogger_artiq/Cargo.toml | 2 +- artiq/firmware/liblogger_artiq/lib.rs | 4 +- artiq/firmware/runtime/Cargo.toml | 2 +- artiq/firmware/runtime/analyzer.rs | 2 +- artiq/firmware/runtime/kernel.rs | 2 +- artiq/firmware/runtime/main.rs | 29 +++++++------ artiq/firmware/runtime/mgmt.rs | 2 +- artiq/firmware/runtime/moninj.rs | 3 +- artiq/firmware/runtime/profiler.rs | 2 +- artiq/firmware/runtime/rtio_mgt.rs | 6 +-- artiq/firmware/runtime/sched.rs | 17 ++++---- artiq/firmware/runtime/session.rs | 8 ++-- artiq/firmware/runtime/watchdog.rs | 2 +- artiq/firmware/satman/Cargo.toml | 2 +- artiq/firmware/satman/main.rs | 14 +++---- 53 files changed, 121 insertions(+), 124 deletions(-) rename artiq/firmware/{libboard => libboard_misoc}/Cargo.toml (93%) rename artiq/firmware/{libboard => libboard_misoc}/build.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/clock.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/config.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/ethmac.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/ident.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/lib.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/or1k/boot.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/or1k/cache.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/or1k/irq.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/or1k/mod.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/or1k/spr.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/or1k/vectors.S (100%) rename artiq/firmware/{libboard => libboard_misoc}/sdram.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/spiflash.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/uart.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/uart_console.rs (100%) rename artiq/firmware/{libboard => libboard_misoc}/uart_logger.rs (100%) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 9ce01cd31..06347899b 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -8,7 +8,22 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "board" +name = "board_artiq" +version = "0.0.0" +dependencies = [ + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "board_misoc 0.0.0", + "build_artiq 0.0.0", + "build_misoc 0.0.0", + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "io 0.0.0", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proto 0.0.0", +] + +[[package]] +name = "board_misoc" version = "0.0.0" dependencies = [ "build_misoc 0.0.0", @@ -19,26 +34,11 @@ dependencies = [ "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", ] -[[package]] -name = "board_artiq" -version = "0.0.0" -dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "board 0.0.0", - "build_artiq 0.0.0", - "build_misoc 0.0.0", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "io 0.0.0", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proto 0.0.0", -] - [[package]] name = "bootloader" version = "0.0.0" dependencies = [ - "board 0.0.0", + "board_misoc 0.0.0", "build_misoc 0.0.0", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -127,8 +127,8 @@ dependencies = [ name = "ksupport" version = "0.0.0" dependencies = [ - "board 0.0.0", "board_artiq 0.0.0", + "board_misoc 0.0.0", "build_misoc 0.0.0", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dyld 0.0.0", @@ -166,7 +166,7 @@ source = "git+https://github.com/whitequark/rust-log_buffer?rev=rust-1.25#ff84e5 name = "logger_artiq" version = "0.0.0" dependencies = [ - "board 0.0.0", + "board_misoc 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "log_buffer 1.2.0 (git+https://github.com/whitequark/rust-log_buffer?rev=rust-1.25)", ] @@ -197,8 +197,8 @@ name = "runtime" version = "0.0.0" dependencies = [ "alloc_list 0.0.0", - "board 0.0.0", "board_artiq 0.0.0", + "board_misoc 0.0.0", "build_artiq 0.0.0", "build_misoc 0.0.0", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -227,8 +227,8 @@ dependencies = [ name = "satman" version = "0.0.0" dependencies = [ - "board 0.0.0", "board_artiq 0.0.0", + "board_misoc 0.0.0", "build_artiq 0.0.0", "build_misoc 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml index 506a56a9b..519e587ba 100644 --- a/artiq/firmware/bootloader/Cargo.toml +++ b/artiq/firmware/bootloader/Cargo.toml @@ -15,7 +15,7 @@ build_misoc = { path = "../libbuild_misoc" } [dependencies] byteorder = { version = "1.0", default-features = false } crc = { version = "1.7", default-features = false } -board = { path = "../libboard", features = ["uart_console", "smoltcp"] } +board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp"] } [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 8f65e3a66..398731e99 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -5,15 +5,15 @@ extern crate crc; extern crate byteorder; extern crate smoltcp; #[macro_use] -extern crate board; +extern crate board_misoc; use core::{ptr, slice}; use crc::crc32; use byteorder::{ByteOrder, BigEndian}; -use board::{boot, cache}; +use board_misoc::{ident, cache, sdram, boot, mem as board_mem}; #[cfg(has_ethmac)] -use board::{clock, config, ethmac}; -use board::uart_console::Console; +use board_misoc::{clock, config, ethmac}; +use board_misoc::uart_console::Console; fn check_integrity() -> bool { extern { @@ -31,7 +31,7 @@ fn check_integrity() -> bool { } fn memory_test(total: &mut usize, wrong: &mut usize) -> bool { - const MEMORY: *mut u32 = board::mem::MAIN_RAM_BASE as *mut u32; + const MEMORY: *mut u32 = board_mem::MAIN_RAM_BASE as *mut u32; *total = 0; *wrong = 0; @@ -88,11 +88,11 @@ fn startup() -> bool { return false } - println!("Gateware ident {}", board::ident::read(&mut [0; 64])); + println!("Gateware ident {}", ident::read(&mut [0; 64])); println!("Initializing SDRAM..."); - if unsafe { board::sdram::init(Some(&mut Console)) } { + if unsafe { sdram::init(Some(&mut Console)) } { println!("SDRAM initialized"); } else { println!("SDRAM initialization failed"); @@ -111,8 +111,8 @@ fn startup() -> bool { } fn flash_boot() { - const FIRMWARE: *mut u8 = board::mem::FLASH_BOOT_ADDRESS as *mut u8; - const MAIN_RAM: *mut u8 = board::mem::MAIN_RAM_BASE as *mut u8; + const FIRMWARE: *mut u8 = board_mem::FLASH_BOOT_ADDRESS as *mut u8; + const MAIN_RAM: *mut u8 = board_mem::MAIN_RAM_BASE as *mut u8; println!("Booting from flash..."); diff --git a/artiq/firmware/ksupport/Cargo.toml b/artiq/firmware/ksupport/Cargo.toml index ef5513344..1ce4d6325 100644 --- a/artiq/firmware/ksupport/Cargo.toml +++ b/artiq/firmware/ksupport/Cargo.toml @@ -16,6 +16,6 @@ build_misoc = { path = "../libbuild_misoc" } cslice = { version = "0.3" } io = { path = "../libio", features = ["byteorder"] } dyld = { path = "../libdyld" } -board = { path = "../libboard" } +board_misoc = { path = "../libboard_misoc" } board_artiq = { path = "../libboard_artiq" } proto = { path = "../libproto" } diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 75b8b928b..20efa1411 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -90,8 +90,8 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(cache_get = ::cache_get), api!(cache_put = ::cache_put), - api!(mfspr = ::board::spr::mfspr), - api!(mtspr = ::board::spr::mtspr), + api!(mfspr = ::board_misoc::spr::mfspr), + api!(mtspr = ::board_misoc::spr::mtspr), /* direct syscalls */ api!(rtio_init = ::rtio::init), diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 1975ca12b..9c5030da1 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -9,7 +9,7 @@ extern crate libc; extern crate io; extern crate dyld; -extern crate board; +extern crate board_misoc; extern crate board_artiq; extern crate proto; @@ -17,7 +17,7 @@ use core::{mem, ptr, slice, str}; use cslice::{CSlice, AsCSlice}; use io::Cursor; use dyld::Library; -use board::csr; +use board_misoc::csr; use board_artiq::{mailbox, rpc_queue}; use proto::{kernel_proto, rpc_proto}; use kernel_proto::*; diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index a3afb6d79..123d15d07 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -3,7 +3,7 @@ mod imp { use core::ptr::{read_volatile, write_volatile}; use cslice::CSlice; - use board::csr; + use board_misoc::csr; use ::send; use kernel_proto::*; diff --git a/artiq/firmware/libboard_artiq/Cargo.toml b/artiq/firmware/libboard_artiq/Cargo.toml index 573440a77..0668d0e6c 100644 --- a/artiq/firmware/libboard_artiq/Cargo.toml +++ b/artiq/firmware/libboard_artiq/Cargo.toml @@ -18,8 +18,8 @@ byteorder = { version = "1.0", default-features = false } crc = { version = "1.7", default-features = false } log = { version = "0.4", default-features = false } io = { path = "../libio", features = ["byteorder"] } +board_misoc = { path = "../libboard_misoc" } proto = { path = "../libproto" } -board = { path = "../libboard" } [features] uart_console = [] diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 746a702cc..528b4c6cb 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -1,4 +1,4 @@ -use board::{csr, clock}; +use board_misoc::{csr, clock}; use ad9154_reg; use hmc830_7043::hmc7043; diff --git a/artiq/firmware/libboard_artiq/drtioaux.rs b/artiq/firmware/libboard_artiq/drtioaux.rs index 149f608d6..5253d8dd2 100644 --- a/artiq/firmware/libboard_artiq/drtioaux.rs +++ b/artiq/firmware/libboard_artiq/drtioaux.rs @@ -3,7 +3,7 @@ use crc; use io::{Cursor, Error as IoError}; use io::proto::{ProtoRead, ProtoWrite}; -use board; +use board_misoc::{csr::DRTIO, mem::DRTIO_AUX, clock}; pub use proto::drtioaux_proto::Packet; @@ -47,17 +47,17 @@ pub fn reset(linkno: u8) { // clear buffer first to limit race window with buffer overflow // error. We assume the CPU is fast enough so that no two packets // will be received between the buffer and the error flag are cleared. - (board::csr::DRTIO[linkno].aux_rx_present_write)(1); - (board::csr::DRTIO[linkno].aux_rx_error_write)(1); + (DRTIO[linkno].aux_rx_present_write)(1); + (DRTIO[linkno].aux_rx_error_write)(1); } } fn has_rx_error(linkno: u8) -> bool { let linkno = linkno as usize; unsafe { - let error = (board::csr::DRTIO[linkno].aux_rx_error_read)() != 0; + let error = (DRTIO[linkno].aux_rx_error_read)() != 0; if error { - (board::csr::DRTIO[linkno].aux_rx_error_write)(1) + (DRTIO[linkno].aux_rx_error_write)(1) } error } @@ -68,12 +68,11 @@ fn receive(linkno: u8, f: F) -> Result> { let linkidx = linkno as usize; unsafe { - if (board::csr::DRTIO[linkidx].aux_rx_present_read)() == 1 { - let ptr = board::mem::DRTIO_AUX[linkidx].base + - board::mem::DRTIO_AUX[linkidx].size / 2; - let len = (board::csr::DRTIO[linkidx].aux_rx_length_read)(); + if (DRTIO[linkidx].aux_rx_present_read)() == 1 { + let ptr = DRTIO_AUX[linkidx].base + DRTIO_AUX[linkidx].size / 2; + let len = (DRTIO[linkidx].aux_rx_length_read)(); let result = f(slice::from_raw_parts(ptr as *mut u8, len as usize)); - (board::csr::DRTIO[linkidx].aux_rx_present_write)(1); + (DRTIO[linkidx].aux_rx_present_write)(1); Ok(Some(result?)) } else { Ok(None) @@ -107,8 +106,8 @@ pub fn recv_link(linkno: u8) -> Result> { pub fn recv_timeout_link(linkno: u8, timeout_ms: Option) -> Result { let timeout_ms = timeout_ms.unwrap_or(10); - let limit = board::clock::get_ms() + timeout_ms; - while board::clock::get_ms() < limit { + let limit = clock::get_ms() + timeout_ms; + while clock::get_ms() < limit { match recv_link(linkno)? { None => (), Some(packet) => return Ok(packet), @@ -122,12 +121,12 @@ fn transmit(linkno: u8, f: F) -> Result<()> { let linkno = linkno as usize; unsafe { - while (board::csr::DRTIO[linkno].aux_tx_read)() != 0 {} - let ptr = board::mem::DRTIO_AUX[linkno].base; - let len = board::mem::DRTIO_AUX[linkno].size / 2; + while (DRTIO[linkno].aux_tx_read)() != 0 {} + let ptr = DRTIO_AUX[linkno].base; + let len = DRTIO_AUX[linkno].size / 2; let len = f(slice::from_raw_parts_mut(ptr as *mut u8, len))?; - (board::csr::DRTIO[linkno].aux_tx_length_write)(len as u16); - (board::csr::DRTIO[linkno].aux_tx_write)(1); + (DRTIO[linkno].aux_tx_length_write)(len as u16); + (DRTIO[linkno].aux_tx_write)(1); Ok(()) } } @@ -154,7 +153,7 @@ pub fn send_link(linkno: u8, packet: &Packet) -> Result<()> { // TODO: routing fn get_linkno(nodeno: u8) -> Result { - if nodeno == 0 || nodeno as usize > board::csr::DRTIO.len() { + if nodeno == 0 || nodeno as usize > DRTIO.len() { return Err(Error::NoRoute) } Ok(nodeno - 1) diff --git a/artiq/firmware/libboard_artiq/hmc542.rs b/artiq/firmware/libboard_artiq/hmc542.rs index f395e0ede..509bc148c 100644 --- a/artiq/firmware/libboard_artiq/hmc542.rs +++ b/artiq/firmware/libboard_artiq/hmc542.rs @@ -1,4 +1,4 @@ -use board::{csr, clock}; +use board_misoc::{csr, clock}; const PIN_LE: u32 = 1 << 0; const PIN_SIN: u32 = 1 << 1; diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 710bdeb03..0e6e78703 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -11,7 +11,7 @@ */ mod clock_mux { - use board::csr; + use board_misoc::csr; const CLK_SRC_EXT_SEL : u8 = 1 << 0; const REF_CLK_SRC_SEL : u8 = 1 << 1; @@ -28,7 +28,7 @@ mod clock_mux { } mod hmc830 { - use board::{csr, clock}; + use board_misoc::{csr, clock}; const HMC830_WRITES: [(u8, u32); 16] = [ (0x0, 0x20), @@ -131,7 +131,7 @@ mod hmc830 { } pub mod hmc7043 { - use board::csr; + use board_misoc::csr; // To do: check which output channels we actually need const DAC_CLK_DIV: u32 = 2; diff --git a/artiq/firmware/libboard_artiq/i2c.rs b/artiq/firmware/libboard_artiq/i2c.rs index ddb70a129..ca40fbc5b 100644 --- a/artiq/firmware/libboard_artiq/i2c.rs +++ b/artiq/firmware/libboard_artiq/i2c.rs @@ -1,6 +1,6 @@ #[cfg(has_i2c)] mod imp { - use board::{csr, clock}; + use board_misoc::{csr, clock}; fn half_period() { clock::spin_us(100) } fn sda_bit(busno: u8) -> u8 { 1 << (2 * busno + 1) } diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index a94c20a62..6ee367598 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -7,8 +7,8 @@ extern crate byteorder; extern crate crc; #[macro_use] extern crate log; -extern crate board; extern crate io; +extern crate board_misoc; extern crate proto; pub mod pcr; @@ -16,7 +16,9 @@ pub mod pcr; pub mod i2c; pub mod spi; +#[cfg(has_kernel_cpu)] pub mod mailbox; +#[cfg(has_kernel_cpu)] pub mod rpc_queue; #[cfg(has_si5324)] diff --git a/artiq/firmware/libboard_artiq/mailbox.rs b/artiq/firmware/libboard_artiq/mailbox.rs index db1f5af47..9c1f374f6 100644 --- a/artiq/firmware/libboard_artiq/mailbox.rs +++ b/artiq/firmware/libboard_artiq/mailbox.rs @@ -1,5 +1,5 @@ use core::ptr::{read_volatile, write_volatile}; -use board::{mem, cache}; +use board_misoc::{mem, cache}; const MAILBOX: *mut usize = mem::MAILBOX_BASE as *mut usize; static mut LAST: usize = 0; diff --git a/artiq/firmware/libboard_artiq/pcr.rs b/artiq/firmware/libboard_artiq/pcr.rs index 543ad4df6..d16575398 100644 --- a/artiq/firmware/libboard_artiq/pcr.rs +++ b/artiq/firmware/libboard_artiq/pcr.rs @@ -1,4 +1,4 @@ -use board::spr::*; +use board_misoc::spr::*; bitflags! { pub struct Counters: u32 { diff --git a/artiq/firmware/libboard_artiq/rpc_queue.rs b/artiq/firmware/libboard_artiq/rpc_queue.rs index 8f9f40f96..8b25372e5 100644 --- a/artiq/firmware/libboard_artiq/rpc_queue.rs +++ b/artiq/firmware/libboard_artiq/rpc_queue.rs @@ -1,6 +1,6 @@ use core::ptr::{read_volatile, write_volatile}; use core::slice; -use board::{mem, cache}; +use board_misoc::{mem, cache}; const SEND_MAILBOX: *mut usize = (mem::MAILBOX_BASE + 4) as *mut usize; const RECV_MAILBOX: *mut usize = (mem::MAILBOX_BASE + 8) as *mut usize; diff --git a/artiq/firmware/libboard_artiq/serwb.rs b/artiq/firmware/libboard_artiq/serwb.rs index 20ed083e8..23a2db391 100644 --- a/artiq/firmware/libboard_artiq/serwb.rs +++ b/artiq/firmware/libboard_artiq/serwb.rs @@ -1,5 +1,5 @@ use core::{cmp, str}; -use board::{csr, clock}; +use board_misoc::{csr, clock}; fn read_rtm_ident(buf: &mut [u8]) -> &str { unsafe { diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 0633186b7..a03aaccb2 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -1,7 +1,7 @@ use core::result; -use board::clock; +use board_misoc::clock; #[cfg(not(si5324_soft_reset))] -use board::csr; +use board_misoc::csr; use i2c; type Result = result::Result; @@ -269,8 +269,7 @@ pub fn select_input(input: Input) -> Result<()> { #[cfg(has_siphaser)] pub mod siphaser { use super::*; - use board::csr; - use board::clock; + use board_misoc::{csr, clock}; pub fn select_recovered_clock(rc: bool) -> Result<()> { write(3, (read(3)? & 0xdf) | (1 << 5))?; // DHOLD=1 diff --git a/artiq/firmware/libboard_artiq/spi.rs b/artiq/firmware/libboard_artiq/spi.rs index a48f77239..78556b24b 100644 --- a/artiq/firmware/libboard_artiq/spi.rs +++ b/artiq/firmware/libboard_artiq/spi.rs @@ -1,6 +1,6 @@ #[cfg(has_converter_spi)] mod imp { - use board::csr; + use board_misoc::csr; pub fn set_config(busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { if busno != 0 { diff --git a/artiq/firmware/libboard/Cargo.toml b/artiq/firmware/libboard_misoc/Cargo.toml similarity index 93% rename from artiq/firmware/libboard/Cargo.toml rename to artiq/firmware/libboard_misoc/Cargo.toml index abd97a682..5fa31a7dc 100644 --- a/artiq/firmware/libboard/Cargo.toml +++ b/artiq/firmware/libboard_misoc/Cargo.toml @@ -1,11 +1,11 @@ [package] authors = ["M-Labs"] -name = "board" +name = "board_misoc" version = "0.0.0" build = "build.rs" [lib] -name = "board" +name = "board_misoc" path = "lib.rs" [build-dependencies] diff --git a/artiq/firmware/libboard/build.rs b/artiq/firmware/libboard_misoc/build.rs similarity index 100% rename from artiq/firmware/libboard/build.rs rename to artiq/firmware/libboard_misoc/build.rs diff --git a/artiq/firmware/libboard/clock.rs b/artiq/firmware/libboard_misoc/clock.rs similarity index 100% rename from artiq/firmware/libboard/clock.rs rename to artiq/firmware/libboard_misoc/clock.rs diff --git a/artiq/firmware/libboard/config.rs b/artiq/firmware/libboard_misoc/config.rs similarity index 100% rename from artiq/firmware/libboard/config.rs rename to artiq/firmware/libboard_misoc/config.rs diff --git a/artiq/firmware/libboard/ethmac.rs b/artiq/firmware/libboard_misoc/ethmac.rs similarity index 100% rename from artiq/firmware/libboard/ethmac.rs rename to artiq/firmware/libboard_misoc/ethmac.rs diff --git a/artiq/firmware/libboard/ident.rs b/artiq/firmware/libboard_misoc/ident.rs similarity index 100% rename from artiq/firmware/libboard/ident.rs rename to artiq/firmware/libboard_misoc/ident.rs diff --git a/artiq/firmware/libboard/lib.rs b/artiq/firmware/libboard_misoc/lib.rs similarity index 100% rename from artiq/firmware/libboard/lib.rs rename to artiq/firmware/libboard_misoc/lib.rs diff --git a/artiq/firmware/libboard/or1k/boot.rs b/artiq/firmware/libboard_misoc/or1k/boot.rs similarity index 100% rename from artiq/firmware/libboard/or1k/boot.rs rename to artiq/firmware/libboard_misoc/or1k/boot.rs diff --git a/artiq/firmware/libboard/or1k/cache.rs b/artiq/firmware/libboard_misoc/or1k/cache.rs similarity index 100% rename from artiq/firmware/libboard/or1k/cache.rs rename to artiq/firmware/libboard_misoc/or1k/cache.rs diff --git a/artiq/firmware/libboard/or1k/irq.rs b/artiq/firmware/libboard_misoc/or1k/irq.rs similarity index 100% rename from artiq/firmware/libboard/or1k/irq.rs rename to artiq/firmware/libboard_misoc/or1k/irq.rs diff --git a/artiq/firmware/libboard/or1k/mod.rs b/artiq/firmware/libboard_misoc/or1k/mod.rs similarity index 100% rename from artiq/firmware/libboard/or1k/mod.rs rename to artiq/firmware/libboard_misoc/or1k/mod.rs diff --git a/artiq/firmware/libboard/or1k/spr.rs b/artiq/firmware/libboard_misoc/or1k/spr.rs similarity index 100% rename from artiq/firmware/libboard/or1k/spr.rs rename to artiq/firmware/libboard_misoc/or1k/spr.rs diff --git a/artiq/firmware/libboard/or1k/vectors.S b/artiq/firmware/libboard_misoc/or1k/vectors.S similarity index 100% rename from artiq/firmware/libboard/or1k/vectors.S rename to artiq/firmware/libboard_misoc/or1k/vectors.S diff --git a/artiq/firmware/libboard/sdram.rs b/artiq/firmware/libboard_misoc/sdram.rs similarity index 100% rename from artiq/firmware/libboard/sdram.rs rename to artiq/firmware/libboard_misoc/sdram.rs diff --git a/artiq/firmware/libboard/spiflash.rs b/artiq/firmware/libboard_misoc/spiflash.rs similarity index 100% rename from artiq/firmware/libboard/spiflash.rs rename to artiq/firmware/libboard_misoc/spiflash.rs diff --git a/artiq/firmware/libboard/uart.rs b/artiq/firmware/libboard_misoc/uart.rs similarity index 100% rename from artiq/firmware/libboard/uart.rs rename to artiq/firmware/libboard_misoc/uart.rs diff --git a/artiq/firmware/libboard/uart_console.rs b/artiq/firmware/libboard_misoc/uart_console.rs similarity index 100% rename from artiq/firmware/libboard/uart_console.rs rename to artiq/firmware/libboard_misoc/uart_console.rs diff --git a/artiq/firmware/libboard/uart_logger.rs b/artiq/firmware/libboard_misoc/uart_logger.rs similarity index 100% rename from artiq/firmware/libboard/uart_logger.rs rename to artiq/firmware/libboard_misoc/uart_logger.rs diff --git a/artiq/firmware/liblogger_artiq/Cargo.toml b/artiq/firmware/liblogger_artiq/Cargo.toml index 822cae637..c33acd01f 100644 --- a/artiq/firmware/liblogger_artiq/Cargo.toml +++ b/artiq/firmware/liblogger_artiq/Cargo.toml @@ -10,4 +10,4 @@ path = "lib.rs" [dependencies] log = { version = "0.4", default-features = false } log_buffer = { version = "1.2", git = "https://github.com/whitequark/rust-log_buffer", rev = "rust-1.25" } -board = { path = "../libboard" } +board_misoc = { path = "../libboard_misoc" } diff --git a/artiq/firmware/liblogger_artiq/lib.rs b/artiq/firmware/liblogger_artiq/lib.rs index fd6228978..d0b72c6cd 100644 --- a/artiq/firmware/liblogger_artiq/lib.rs +++ b/artiq/firmware/liblogger_artiq/lib.rs @@ -3,13 +3,13 @@ extern crate log; extern crate log_buffer; #[macro_use] -extern crate board; +extern crate board_misoc; use core::cell::{Cell, RefCell, RefMut}; use core::fmt::Write; use log::{Log, LevelFilter}; use log_buffer::LogBuffer; -use board::clock; +use board_misoc::clock; pub struct LogBufferRef<'a> { buffer: RefMut<'a, LogBuffer<&'static mut [u8]>>, diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 7eff26c33..a6f6e7c0f 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -20,8 +20,8 @@ log = { version = "0.4", default-features = false } managed = { version = "0.6", default-features = false, features = ["alloc", "map"] } unwind_backtrace = { path = "../libunwind_backtrace" } io = { path = "../libio", features = ["byteorder", "std_artiq"] } -board = { path = "../libboard", features = ["uart_console", "smoltcp"] } alloc_list = { path = "../liballoc_list" } +board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp"] } std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] } logger_artiq = { path = "../liblogger_artiq" } board_artiq = { path = "../libboard_artiq" } diff --git a/artiq/firmware/runtime/analyzer.rs b/artiq/firmware/runtime/analyzer.rs index f3330fc11..2ff4d6cd4 100644 --- a/artiq/firmware/runtime/analyzer.rs +++ b/artiq/firmware/runtime/analyzer.rs @@ -1,5 +1,5 @@ use std::io::{self, Write}; -use board::{csr, cache}; +use board_misoc::{csr, cache}; use sched::{Io, TcpListener, TcpStream}; use analyzer_proto::*; diff --git a/artiq/firmware/runtime/kernel.rs b/artiq/firmware/runtime/kernel.rs index 9e02ce82c..1a67af556 100644 --- a/artiq/firmware/runtime/kernel.rs +++ b/artiq/firmware/runtime/kernel.rs @@ -1,5 +1,5 @@ use core::ptr; -use board::csr; +use board_misoc::csr; use mailbox; use rpc_queue; diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 2f14a4b4a..3e888f266 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -14,26 +14,25 @@ extern crate alloc_list; extern crate unwind_backtrace; extern crate io; #[macro_use] +extern crate board_misoc; +extern crate board_artiq; +#[macro_use] extern crate std_artiq as std; extern crate logger_artiq; -#[macro_use] -extern crate board; -extern crate board_artiq; extern crate proto; use core::convert::TryFrom; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; -use board::irq; -use board::config; +use board_misoc::{csr, irq, ident, clock, boot, config}; #[cfg(has_ethmac)] -use board::ethmac; +use board_misoc::ethmac; #[cfg(has_drtio)] use board_artiq::drtioaux; +use board_artiq::{mailbox, rpc_queue}; use proto::{mgmt_proto, moninj_proto, rpc_proto, session_proto,kernel_proto}; #[cfg(has_rtio_analyzer)] use proto::analyzer_proto; -use board_artiq::{mailbox, rpc_queue}; #[cfg(has_rtio_core)] mod rtio_mgt; @@ -56,10 +55,10 @@ mod analyzer; fn startup() { irq::set_ie(true); - board::clock::init(); + clock::init(); info!("ARTIQ runtime starting..."); info!("software version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); - info!("gateware version {}", board::ident::read(&mut [0; 64])); + info!("gateware version {}", ident::read(&mut [0; 64])); match config::read_str("log_level", |r| r.map(|s| s.parse())) { Ok(Ok(log_level_filter)) => { @@ -85,10 +84,10 @@ fn startup() { board_artiq::serwb::wait_init(); #[cfg(has_uart)] { - let t = board::clock::get_ms(); + let t = clock::get_ms(); info!("press 'e' to erase startup and idle kernels..."); - while board::clock::get_ms() < t + 1000 { - if unsafe { board::csr::uart::rxtx_read() == b'e' } { + while clock::get_ms() < t + 1000 { + if unsafe { csr::uart::rxtx_read() == b'e' } { config::remove("startup_kernel").unwrap(); config::remove("idle_kernel").unwrap(); info!("startup and idle kernels erased"); @@ -242,7 +241,7 @@ fn startup_ethernet() { { let sockets = &mut *scheduler.sockets().borrow_mut(); loop { - match interface.poll(sockets, board::clock::get_ms()) { + match interface.poll(sockets, clock::get_ms()) { Ok(true) => (), Ok(false) => break, Err(smoltcp::Error::Unrecognized) => (), @@ -284,7 +283,7 @@ pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { while irq::pending_mask() != 0 { match () { #[cfg(has_timer1)] - () if irq::is_pending(::board::csr::TIMER1_INTERRUPT) => + () if irq::is_pending(csr::TIMER1_INTERRUPT) => profiler::sample(pc as usize), _ => panic!("spurious irq {}", irq::pending_mask().trailing_zeros()) } @@ -312,7 +311,7 @@ pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u3 if config::read_str("panic_reset", |r| r == Ok("1")) { println!("restarting..."); - unsafe { board::boot::reset() } + unsafe { boot::reset() } } else { println!("halting."); println!("use `artiq_coreconfig write -s panic_reset 1` to restart instead"); diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 70fb2ea07..2e30c5cfd 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -1,8 +1,8 @@ use std::io::{self, Read, Write}; use log::{self, LevelFilter}; +use board_misoc::boot; use io::proto::ProtoWrite; -use board::boot; use logger_artiq::BufferLogger; use sched::Io; use sched::{TcpListener, TcpStream}; diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index 429d8d938..dc8cccf0b 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -3,13 +3,12 @@ use std::btree_map::BTreeMap; use sched::Io; use sched::{TcpListener, TcpStream}; -use board::{clock, csr}; +use board_misoc::{clock, csr}; #[cfg(has_drtio)] use drtioaux; use moninj_proto::*; - fn check_magic(stream: &mut TcpStream) -> io::Result<()> { const MAGIC: &'static [u8] = b"ARTIQ moninj\n"; diff --git a/artiq/firmware/runtime/profiler.rs b/artiq/firmware/runtime/profiler.rs index db830198c..0e4380f96 100644 --- a/artiq/firmware/runtime/profiler.rs +++ b/artiq/firmware/runtime/profiler.rs @@ -88,7 +88,7 @@ impl Profile { #[cfg(has_timer1)] mod imp { - use board::{csr, irq}; + use board_misoc::{csr, irq}; use super::{Address, Profile}; static mut PROFILE: Option = None; diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 41dc4a18e..01ba1a4b9 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -1,9 +1,9 @@ -use board::{csr, config}; +use board_misoc::{csr, config}; use sched::Io; #[cfg(has_rtio_crg)] pub mod crg { - use board::{clock, csr}; + use board_misoc::{clock, csr}; pub fn init() { unsafe { csr::rtio_crg::pll_reset_write(0) } @@ -280,7 +280,7 @@ pub fn init_core(phy: bool) { #[cfg(has_drtio)] pub mod drtio_dbg { - use board::csr; + use board_misoc::csr; pub fn get_packet_counts(linkno: u8) -> (u32, u32) { let linkno = linkno as usize; diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index eeb31ceca..8622b56e8 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -1,17 +1,16 @@ #![allow(dead_code)] -use std::mem; -use std::result; -use std::cell::{Cell, RefCell}; -use std::vec::Vec; -use std::io::{Read, Write, Result, Error, ErrorKind}; +use core::mem; +use core::result; +use core::cell::{Cell, RefCell}; use fringe::OwnedStack; use fringe::generator::{Generator, Yielder, State as GeneratorState}; - use smoltcp::wire::IpEndpoint; use smoltcp::socket::{SocketHandle, SocketRef}; -use board; +use std::vec::Vec; +use std::io::{Read, Write, Result, Error, ErrorKind}; +use board_misoc::clock; use urc::Urc; type SocketSet = ::smoltcp::socket::SocketSet<'static, 'static, 'static>; @@ -128,7 +127,7 @@ impl Scheduler { self.threads.append(&mut *self.spawned.borrow_mut()); if self.threads.len() == 0 { return } - let now = board::clock::get_ms(); + let now = clock::get_ms(); let start_idx = self.run_idx; loop { self.run_idx = (self.run_idx + 1) % self.threads.len(); @@ -196,7 +195,7 @@ impl<'a> Io<'a> { pub fn sleep(&self, duration_ms: u64) -> Result<()> { let request = WaitRequest { - timeout: Some(board::clock::get_ms() + duration_ms), + timeout: Some(clock::get_ms() + duration_ms), event: None }; diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index d60a48430..5579cde5a 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -5,11 +5,11 @@ use std::io::{self, Read, Write}; use std::error::Error; use byteorder::{ByteOrder, NetworkEndian}; +use board_misoc::{ident, cache, config}; +use {mailbox, rpc_queue, kernel}; use urc::Urc; use sched::{ThreadHandle, Io}; use sched::{TcpListener, TcpStream}; -use board::{self, config}; -use {mailbox, rpc_queue, kernel}; #[cfg(has_rtio_core)] use rtio_mgt; use rtio_dma::Manager as DmaManager; @@ -227,7 +227,7 @@ fn process_host_message(io: &Io, match host_read(stream)? { host::Request::SystemInfo => { host_write(stream, host::Reply::SystemInfo { - ident: board::ident::read(&mut [0; 64]), + ident: ident::read(&mut [0; 64]), finished_cleanly: session.congress.finished_cleanly.get() })?; session.congress.finished_cleanly.set(true); @@ -413,7 +413,7 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, } &kern::DmaRecordStop { duration } => { session.congress.dma_manager.record_stop(duration); - board::cache::flush_l2_cache(); + cache::flush_l2_cache(); kern_acknowledge() } &kern::DmaEraseRequest { name } => { diff --git a/artiq/firmware/runtime/watchdog.rs b/artiq/firmware/runtime/watchdog.rs index 921472dae..fa0adc97f 100644 --- a/artiq/firmware/runtime/watchdog.rs +++ b/artiq/firmware/runtime/watchdog.rs @@ -1,4 +1,4 @@ -use board::clock; +use board_misoc::clock; #[derive(Debug, Clone, Copy)] struct Watchdog { diff --git a/artiq/firmware/satman/Cargo.toml b/artiq/firmware/satman/Cargo.toml index 3dffc9652..78c84ab87 100644 --- a/artiq/firmware/satman/Cargo.toml +++ b/artiq/firmware/satman/Cargo.toml @@ -15,5 +15,5 @@ build_artiq = { path = "../libbuild_artiq" } [dependencies] log = { version = "0.4", default-features = false } -board = { path = "../libboard", features = ["uart_console", "log"] } +board_misoc = { path = "../libboard_misoc", features = ["uart_console", "log"] } board_artiq = { path = "../libboard_artiq" } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index a0e857f4f..faa343678 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -4,10 +4,10 @@ #[macro_use] extern crate log; #[macro_use] -extern crate board; +extern crate board_misoc; extern crate board_artiq; -use board::csr; +use board_misoc::{csr, ident, clock, uart_logger}; use board_artiq::{i2c, spi, si5324, drtioaux}; #[cfg(has_serwb_phy_amc)] use board_artiq::serwb; @@ -67,8 +67,8 @@ fn process_aux_packet(packet: drtioaux::Packet) -> drtioaux::Result<()> { } else if errors & 4 != 0 { let channel; unsafe { - channel = (board::csr::DRTIO[0].busy_channel_read)(); - (board::csr::DRTIO[0].rtio_error_write)(4); + channel = (csr::DRTIO[0].busy_channel_read)(); + (csr::DRTIO[0].rtio_error_write)(4); } drtioaux::send_link(0, &drtioaux::Packet::RtioErrorBusyReply { channel }) @@ -240,12 +240,12 @@ fn drtio_link_rx_up() -> bool { #[no_mangle] pub extern fn main() -> i32 { - board::clock::init(); - board::uart_logger::ConsoleLogger::register(); + clock::init(); + uart_logger::ConsoleLogger::register(); info!("ARTIQ satellite manager starting..."); info!("software version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); - info!("gateware version {}", board::ident::read(&mut [0; 64])); + info!("gateware version {}", ident::read(&mut [0; 64])); #[cfg(has_serwb_phy_amc)] serwb::wait_init(); From ae50196186721372bbac91b5f3ffd10f8c7d019e Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 17:58:34 +0000 Subject: [PATCH 0757/2457] firmware: rename libproto to libproto_artiq. libproto_artiq only has ARTIQ-specific protocols. --- artiq/firmware/Cargo.lock | 8 ++++---- artiq/firmware/ksupport/Cargo.toml | 2 +- artiq/firmware/ksupport/lib.rs | 4 ++-- artiq/firmware/libboard_artiq/Cargo.toml | 2 +- artiq/firmware/libboard_artiq/drtioaux.rs | 2 +- artiq/firmware/libboard_artiq/lib.rs | 2 +- artiq/firmware/{libproto => libproto_artiq}/Cargo.toml | 4 ++-- .../{libproto => libproto_artiq}/analyzer_proto.rs | 0 .../{libproto => libproto_artiq}/drtioaux_proto.rs | 0 .../firmware/{libproto => libproto_artiq}/kernel_proto.rs | 0 artiq/firmware/{libproto => libproto_artiq}/lib.rs | 0 artiq/firmware/{libproto => libproto_artiq}/mgmt_proto.rs | 0 .../firmware/{libproto => libproto_artiq}/moninj_proto.rs | 0 artiq/firmware/{libproto => libproto_artiq}/rpc_proto.rs | 0 .../{libproto => libproto_artiq}/session_proto.rs | 0 artiq/firmware/runtime/Cargo.toml | 2 +- artiq/firmware/runtime/main.rs | 6 +++--- 17 files changed, 16 insertions(+), 16 deletions(-) rename artiq/firmware/{libproto => libproto_artiq}/Cargo.toml (89%) rename artiq/firmware/{libproto => libproto_artiq}/analyzer_proto.rs (100%) rename artiq/firmware/{libproto => libproto_artiq}/drtioaux_proto.rs (100%) rename artiq/firmware/{libproto => libproto_artiq}/kernel_proto.rs (100%) rename artiq/firmware/{libproto => libproto_artiq}/lib.rs (100%) rename artiq/firmware/{libproto => libproto_artiq}/mgmt_proto.rs (100%) rename artiq/firmware/{libproto => libproto_artiq}/moninj_proto.rs (100%) rename artiq/firmware/{libproto => libproto_artiq}/rpc_proto.rs (100%) rename artiq/firmware/{libproto => libproto_artiq}/session_proto.rs (100%) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 06347899b..b14a8b490 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -19,7 +19,7 @@ dependencies = [ "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "io 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proto 0.0.0", + "proto_artiq 0.0.0", ] [[package]] @@ -133,7 +133,7 @@ dependencies = [ "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dyld 0.0.0", "io 0.0.0", - "proto 0.0.0", + "proto_artiq 0.0.0", ] [[package]] @@ -182,7 +182,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "proto" +name = "proto_artiq" version = "0.0.0" dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -208,7 +208,7 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "logger_artiq 0.0.0", "managed 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proto 0.0.0", + "proto_artiq 0.0.0", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", "std_artiq 0.0.0", "unwind_backtrace 0.0.0", diff --git a/artiq/firmware/ksupport/Cargo.toml b/artiq/firmware/ksupport/Cargo.toml index 1ce4d6325..3318dc44d 100644 --- a/artiq/firmware/ksupport/Cargo.toml +++ b/artiq/firmware/ksupport/Cargo.toml @@ -18,4 +18,4 @@ io = { path = "../libio", features = ["byteorder"] } dyld = { path = "../libdyld" } board_misoc = { path = "../libboard_misoc" } board_artiq = { path = "../libboard_artiq" } -proto = { path = "../libproto" } +proto_artiq = { path = "../libproto_artiq" } diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 9c5030da1..4122e75c7 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -11,7 +11,7 @@ extern crate io; extern crate dyld; extern crate board_misoc; extern crate board_artiq; -extern crate proto; +extern crate proto_artiq; use core::{mem, ptr, slice, str}; use cslice::{CSlice, AsCSlice}; @@ -19,7 +19,7 @@ use io::Cursor; use dyld::Library; use board_misoc::csr; use board_artiq::{mailbox, rpc_queue}; -use proto::{kernel_proto, rpc_proto}; +use proto_artiq::{kernel_proto, rpc_proto}; use kernel_proto::*; fn send(request: &Message) { diff --git a/artiq/firmware/libboard_artiq/Cargo.toml b/artiq/firmware/libboard_artiq/Cargo.toml index 0668d0e6c..776392d42 100644 --- a/artiq/firmware/libboard_artiq/Cargo.toml +++ b/artiq/firmware/libboard_artiq/Cargo.toml @@ -19,7 +19,7 @@ crc = { version = "1.7", default-features = false } log = { version = "0.4", default-features = false } io = { path = "../libio", features = ["byteorder"] } board_misoc = { path = "../libboard_misoc" } -proto = { path = "../libproto" } +proto_artiq = { path = "../libproto_artiq" } [features] uart_console = [] diff --git a/artiq/firmware/libboard_artiq/drtioaux.rs b/artiq/firmware/libboard_artiq/drtioaux.rs index 5253d8dd2..207f7baf1 100644 --- a/artiq/firmware/libboard_artiq/drtioaux.rs +++ b/artiq/firmware/libboard_artiq/drtioaux.rs @@ -5,7 +5,7 @@ use io::{Cursor, Error as IoError}; use io::proto::{ProtoRead, ProtoWrite}; use board_misoc::{csr::DRTIO, mem::DRTIO_AUX, clock}; -pub use proto::drtioaux_proto::Packet; +pub use proto_artiq::drtioaux_proto::Packet; pub type Result = result::Result; diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 6ee367598..6f22153c7 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -9,7 +9,7 @@ extern crate crc; extern crate log; extern crate io; extern crate board_misoc; -extern crate proto; +extern crate proto_artiq; pub mod pcr; diff --git a/artiq/firmware/libproto/Cargo.toml b/artiq/firmware/libproto_artiq/Cargo.toml similarity index 89% rename from artiq/firmware/libproto/Cargo.toml rename to artiq/firmware/libproto_artiq/Cargo.toml index c1e980915..19b1884dd 100644 --- a/artiq/firmware/libproto/Cargo.toml +++ b/artiq/firmware/libproto_artiq/Cargo.toml @@ -1,10 +1,10 @@ [package] authors = ["M-Labs"] -name = "proto" +name = "proto_artiq" version = "0.0.0" [lib] -name = "proto" +name = "proto_artiq" path = "lib.rs" [dependencies] diff --git a/artiq/firmware/libproto/analyzer_proto.rs b/artiq/firmware/libproto_artiq/analyzer_proto.rs similarity index 100% rename from artiq/firmware/libproto/analyzer_proto.rs rename to artiq/firmware/libproto_artiq/analyzer_proto.rs diff --git a/artiq/firmware/libproto/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs similarity index 100% rename from artiq/firmware/libproto/drtioaux_proto.rs rename to artiq/firmware/libproto_artiq/drtioaux_proto.rs diff --git a/artiq/firmware/libproto/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs similarity index 100% rename from artiq/firmware/libproto/kernel_proto.rs rename to artiq/firmware/libproto_artiq/kernel_proto.rs diff --git a/artiq/firmware/libproto/lib.rs b/artiq/firmware/libproto_artiq/lib.rs similarity index 100% rename from artiq/firmware/libproto/lib.rs rename to artiq/firmware/libproto_artiq/lib.rs diff --git a/artiq/firmware/libproto/mgmt_proto.rs b/artiq/firmware/libproto_artiq/mgmt_proto.rs similarity index 100% rename from artiq/firmware/libproto/mgmt_proto.rs rename to artiq/firmware/libproto_artiq/mgmt_proto.rs diff --git a/artiq/firmware/libproto/moninj_proto.rs b/artiq/firmware/libproto_artiq/moninj_proto.rs similarity index 100% rename from artiq/firmware/libproto/moninj_proto.rs rename to artiq/firmware/libproto_artiq/moninj_proto.rs diff --git a/artiq/firmware/libproto/rpc_proto.rs b/artiq/firmware/libproto_artiq/rpc_proto.rs similarity index 100% rename from artiq/firmware/libproto/rpc_proto.rs rename to artiq/firmware/libproto_artiq/rpc_proto.rs diff --git a/artiq/firmware/libproto/session_proto.rs b/artiq/firmware/libproto_artiq/session_proto.rs similarity index 100% rename from artiq/firmware/libproto/session_proto.rs rename to artiq/firmware/libproto_artiq/session_proto.rs diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index a6f6e7c0f..2057502df 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -25,7 +25,7 @@ board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] } logger_artiq = { path = "../liblogger_artiq" } board_artiq = { path = "../libboard_artiq" } -proto = { path = "../libproto", features = ["log", "alloc"] } +proto_artiq = { path = "../libproto_artiq", features = ["log", "alloc"] } [dependencies.fringe] git = "https://github.com/m-labs/libfringe" diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 3e888f266..7a7fe3c98 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -19,7 +19,7 @@ extern crate board_artiq; #[macro_use] extern crate std_artiq as std; extern crate logger_artiq; -extern crate proto; +extern crate proto_artiq; use core::convert::TryFrom; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; @@ -30,9 +30,9 @@ use board_misoc::ethmac; #[cfg(has_drtio)] use board_artiq::drtioaux; use board_artiq::{mailbox, rpc_queue}; -use proto::{mgmt_proto, moninj_proto, rpc_proto, session_proto,kernel_proto}; +use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto,kernel_proto}; #[cfg(has_rtio_analyzer)] -use proto::analyzer_proto; +use proto_artiq::analyzer_proto; #[cfg(has_rtio_core)] mod rtio_mgt; From a100c73dfeecdb1fc253263e0088c33a375b9e05 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 14 May 2018 20:15:30 +0200 Subject: [PATCH 0758/2457] suservo: support pure-I --- artiq/coredevice/suservo.py | 62 +++++++++++-------- .../kasli_suservo/repository/suservo.py | 2 +- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 1bb4cf938..5bd4860c1 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -11,7 +11,7 @@ WE = 1 << COEFF_DEPTH + 1 STATE_SEL = 1 << COEFF_DEPTH CONFIG_SEL = 1 << COEFF_DEPTH - 1 CONFIG_ADDR = CONFIG_SEL | STATE_SEL -F_CYCLE = 1/((2*(8 + 64) + 2 + 1)*8*ns) +T_CYCLE = (2*(8 + 64) + 2 + 1)*8*ns COEFF_SHIFT = 11 @@ -277,7 +277,7 @@ class Channel: :param b1: 18 bit signed B1 coefficient (old, X1 coefficient, feed forward, proportional gain) :param dly: IIR update suppression time. In units of IIR cycles - (~1.1 µs) + (~1.2 µs, 0-255) """ base = (self.servo_channel << 8) | (profile << 3) self.servo.write(base + 3, adc | (dly << 8)) @@ -305,45 +305,55 @@ class Channel: Where: * :math:`s = \\sigma + i\\omega` is the complex frequency * :math:`K` is the proportional gain - * :math:`\\omega_0` is the integrator corner frequency + * :math:`\\omega_0 = 2\\pi f_0` is the integrator corner frequency * :math:`g` is the integrator gain limit :param profile: Profile number (0-31) :param adc: ADC channel to take IIR input from (0-7) :param gain: Proportional gain (1). This is usually negative (closed - loop, positive ADC voltage, positive setpoint). + loop, positive ADC voltage, positive setpoint). When 0, this + implements a pure I controller with unit gain frequency at + `corner` (use the sign of `corner` for overall gain sign). :param corner: Integrator corner frequency (Hz). When 0 (the default) this implements a pure P controller. :param limit: Integrator gain limit (1). When 0 (the default) the - integrator gain limit is infinite. - :param delay: Delay (in seconds) before allowing IIR updates after - invoking :meth:`set`. + integrator gain limit is infinite. Positive. + :param delay: Delay (in seconds, 0-300 µs) before allowing IIR updates + after invoking :meth:`set`. """ B_NORM = 1 << COEFF_SHIFT + 1 A_NORM = 1 << COEFF_SHIFT - PI_TS = 3.1415927/F_CYCLE + PI_TS = 3.1415927*T_CYCLE COEFF_MAX = 1 << COEFF_WIDTH - 1 - k = B_NORM*gain - if corner == 0.: - a1_ = 0 - b0_ = int(round(k)) - b1_ = 0 - else: - q = PI_TS*corner - kq = k*q + gain *= B_NORM + corner *= PI_TS + if corner == 0.: + # pure P + a1_ = 0 + b1_ = 0 + b0_ = int(round(gain)) + else: a1_ = A_NORM - b0 = kq + k - b1 = kq - k - if limit != 0.: - ql = q/limit - qlr = 1./(1. + ql) - a1_ = int(round(a1_*(1. - ql)*qlr)) - b0 *= qlr - b0 *= qlr + if gain == 0.: + # pure I + b0 = (2*B_NORM)*corner + b1_ = 0 + else: + # PI + k = gain*corner + b1 = k - gain + b0 = k + gain + if limit != 0.: + # PI with limit + q = corner/limit + qr = 1./(1. + q) + a1_ = int(round(a1_*(1. - q)*qr)) + b0 *= qr + b1 *= qr + b1_ = int(round(b1)) b0_ = int(round(b0)) - b1_ = int(round(b1)) if b1_ == -b0_: raise ValueError("low corner, gain, limit") @@ -352,7 +362,7 @@ class Channel: b1_ >= COEFF_MAX or b1_ < -COEFF_MAX): raise ValueError("high corner, gain, limit") - dly = int(round(delay*F_CYCLE)) + dly = int(round(delay/T_CYCLE)) self.set_iir_mu(profile, adc, a1_, b0_, b1_, dly) @kernel diff --git a/artiq/examples/kasli_suservo/repository/suservo.py b/artiq/examples/kasli_suservo/repository/suservo.py index 93c9faf5e..900e4e9ea 100644 --- a/artiq/examples/kasli_suservo/repository/suservo.py +++ b/artiq/examples/kasli_suservo/repository/suservo.py @@ -16,7 +16,7 @@ class SUServo(EnvExperiment): mask = 1 << 18 - 1 for name, val in zip("ftw1 b1 pow cfg offset a1 ftw0 b0".split(), d): val = -(val & mask) + (val & ~mask) - print("{}: {:x} = {}".format(name, val, val)) + print("{}: {:#x} = {}".format(name, val, val)) @rpc(flags={"async"}) def p1(self, adc, asf, st): From cf33ba748d225961b13c8806a29814e0dc28d803 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 18:27:17 +0000 Subject: [PATCH 0759/2457] firmware: eliminate non-io uses of std_artiq from runtime. Just replace these with references to alloc. --- artiq/firmware/runtime/cache.rs | 4 +--- artiq/firmware/runtime/moninj.rs | 4 ++-- artiq/firmware/runtime/rtio_dma.rs | 7 +++---- artiq/firmware/runtime/sched.rs | 4 ++-- artiq/firmware/runtime/session.rs | 12 ++++++------ artiq/firmware/runtime/urc.rs | 6 +++--- 6 files changed, 17 insertions(+), 20 deletions(-) diff --git a/artiq/firmware/runtime/cache.rs b/artiq/firmware/runtime/cache.rs index 082dda287..2f1948924 100644 --- a/artiq/firmware/runtime/cache.rs +++ b/artiq/firmware/runtime/cache.rs @@ -1,6 +1,4 @@ -use std::vec::Vec; -use std::string::String; -use std::btree_map::BTreeMap; +use alloc::{Vec, String, BTreeMap}; #[derive(Debug)] struct Entry { diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index dc8cccf0b..ecb862b38 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -1,6 +1,6 @@ -use std::io::{self, Read}; -use std::btree_map::BTreeMap; +use alloc::btree_map::BTreeMap; +use std::io::{self, Read}; use sched::Io; use sched::{TcpListener, TcpStream}; use board_misoc::{clock, csr}; diff --git a/artiq/firmware/runtime/rtio_dma.rs b/artiq/firmware/runtime/rtio_dma.rs index 4a024e929..b0f964d86 100644 --- a/artiq/firmware/runtime/rtio_dma.rs +++ b/artiq/firmware/runtime/rtio_dma.rs @@ -1,7 +1,6 @@ -use std::mem; -use std::vec::Vec; -use std::string::String; -use std::btree_map::BTreeMap; +use core::mem; +use alloc::{Vec, String, BTreeMap}; + use std::io::Write; const ALIGNMENT: usize = 64; diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index 8622b56e8..e9ca34cc3 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -3,14 +3,14 @@ use core::mem; use core::result; use core::cell::{Cell, RefCell}; +use alloc::Vec; use fringe::OwnedStack; use fringe::generator::{Generator, Yielder, State as GeneratorState}; use smoltcp::wire::IpEndpoint; use smoltcp::socket::{SocketHandle, SocketRef}; -use std::vec::Vec; -use std::io::{Read, Write, Result, Error, ErrorKind}; use board_misoc::clock; +use std::io::{Read, Write, Result, Error, ErrorKind}; use urc::Urc; type SocketSet = ::smoltcp::socket::SocketSet<'static, 'static, 'static>; diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 5579cde5a..82cf8c89c 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -1,11 +1,9 @@ -use std::prelude::v1::*; -use std::{mem, str}; -use std::cell::{Cell, RefCell}; -use std::io::{self, Read, Write}; -use std::error::Error; +use core::{mem, str, cell::{Cell, RefCell}, fmt::Write as FmtWrite}; +use alloc::{Vec, String}; use byteorder::{ByteOrder, NetworkEndian}; use board_misoc::{ident, cache, config}; +use std::io::{self, Read, Write}; use {mailbox, rpc_queue, kernel}; use urc::Urc; use sched::{ThreadHandle, Io}; @@ -289,7 +287,9 @@ fn process_host_message(io: &Io, match unsafe { kern_load(io, session, &kernel) } { Ok(()) => host_write(stream, host::Reply::LoadCompleted), Err(error) => { - host_write(stream, host::Reply::LoadFailed(error.description()))?; + let mut description = String::new(); + write!(&mut description, "{}", error).unwrap(); + host_write(stream, host::Reply::LoadFailed(&description))?; kern_acknowledge() } }, diff --git a/artiq/firmware/runtime/urc.rs b/artiq/firmware/runtime/urc.rs index cec7751ea..1117269b6 100644 --- a/artiq/firmware/runtime/urc.rs +++ b/artiq/firmware/runtime/urc.rs @@ -1,6 +1,6 @@ -use std::rc::Rc; -use std::ops::Deref; -use std::fmt; +use core::ops::Deref; +use core::fmt; +use alloc::rc::Rc; pub struct Urc(Rc); From 5ead27f2e164358ab0f8e2851935a1b43527cbeb Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 19:06:54 +0000 Subject: [PATCH 0760/2457] firmware: eliminate uses of std_artiq::io::{Read,Write} from runtime. --- artiq/firmware/Cargo.lock | 1 - artiq/firmware/libio/Cargo.toml | 1 - artiq/firmware/libio/lib.rs | 88 +++++++++++------------ artiq/firmware/libio/proto.rs | 15 ---- artiq/firmware/runtime/Cargo.toml | 2 +- artiq/firmware/runtime/analyzer.rs | 4 +- artiq/firmware/runtime/kern_hwreq.rs | 4 +- artiq/firmware/runtime/mgmt.rs | 16 ++--- artiq/firmware/runtime/moninj.rs | 8 +-- artiq/firmware/runtime/rtio_dma.rs | 2 +- artiq/firmware/runtime/sched.rs | 8 ++- artiq/firmware/runtime/session.rs | 101 ++++++++++++++------------- 12 files changed, 118 insertions(+), 132 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index b14a8b490..13bcb05ed 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -111,7 +111,6 @@ name = "io" version = "0.0.0" dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "std_artiq 0.0.0", ] [[package]] diff --git a/artiq/firmware/libio/Cargo.toml b/artiq/firmware/libio/Cargo.toml index 4f6ffd678..9729aca32 100644 --- a/artiq/firmware/libio/Cargo.toml +++ b/artiq/firmware/libio/Cargo.toml @@ -9,7 +9,6 @@ path = "lib.rs" [dependencies] byteorder = { version = "1.0", default-features = false, optional = true } -std_artiq = { path = "../libstd_artiq", optional = true } [features] alloc = [] diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs index 8c0b501af..c536e5383 100644 --- a/artiq/firmware/libio/lib.rs +++ b/artiq/firmware/libio/lib.rs @@ -8,9 +8,6 @@ extern crate alloc; #[cfg(feature = "byteorder")] extern crate byteorder; -#[cfg(feature = "std_artiq")] -extern crate std_artiq; - use core::result; use core::fmt; @@ -67,6 +64,14 @@ pub trait Read { } } +impl<'a, T: Read> Read for &'a mut T { + type ReadError = T::ReadError; + + fn read(&mut self, buf: &mut [u8]) -> result::Result { + T::read(self, buf) + } +} + pub trait Write { type WriteError; type FlushError; @@ -99,7 +104,23 @@ pub trait Write { fn size_hint(&mut self, _min: usize, _max: Option) {} } -#[cfg(not(feature = "std_artiq"))] +impl<'a, T: Write> Write for &'a mut T { + type WriteError = T::WriteError; + type FlushError = T::FlushError; + + fn write(&mut self, buf: &[u8]) -> result::Result { + T::write(self, buf) + } + + fn flush(&mut self) -> result::Result<(), Self::FlushError> { + T::flush(self) + } + + fn size_hint(&mut self, min: usize, max: Option) { + T::size_hint(self, min, max) + } +} + impl<'a> Write for &'a mut [u8] { type WriteError = !; type FlushError = !; @@ -116,6 +137,22 @@ impl<'a> Write for &'a mut [u8] { } } +#[cfg(feature = "alloc")] +impl<'a> Write for alloc::Vec { + type WriteError = !; + type FlushError = !; + + fn write(&mut self, buf: &[u8]) -> result::Result { + self.extend_from_slice(buf); + Ok(buf.len()) + } + + #[inline] + fn flush(&mut self) -> result::Result<(), Self::FlushError> { + Ok(()) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CursorError { EndOfBuffer @@ -196,7 +233,7 @@ impl Write for Cursor<::alloc::Vec> { #[inline] fn write(&mut self, buf: &[u8]) -> result::Result { - self.inner.extend(buf); + self.inner.extend_from_slice(buf); Ok(buf.len()) } @@ -205,44 +242,3 @@ impl Write for Cursor<::alloc::Vec> { Ok(()) } } - -#[cfg(feature = "std_artiq")] -impl Read for T where T: std_artiq::io::Read + ?Sized { - type ReadError = std_artiq::io::Error; - - fn read(&mut self, buf: &mut [u8]) -> result::Result { - std_artiq::io::Read::read(self, buf) - } -} - -#[cfg(feature = "std_artiq")] -impl Write for T where T: std_artiq::io::Write + ?Sized { - type WriteError = std_artiq::io::Error; - type FlushError = std_artiq::io::Error; - - fn write(&mut self, buf: &[u8]) -> result::Result { - std_artiq::io::Write::write(self, buf) - } - - fn flush(&mut self) -> result::Result<(), Self::WriteError> { - std_artiq::io::Write::flush(self) - } -} - -#[cfg(feature = "std_artiq")] -impl From> for std_artiq::io::Error - where T: Into -{ - fn from(value: Error) -> std_artiq::io::Error { - match value { - Error::UnexpectedEof => - std_artiq::io::Error::new(std_artiq::io::ErrorKind::UnexpectedEof, - "unexpected end of stream"), - Error::Unrecognized => - std_artiq::io::Error::new(std_artiq::io::ErrorKind::InvalidData, - "unrecognized data"), - Error::Other(err) => - err.into() - } - } -} diff --git a/artiq/firmware/libio/proto.rs b/artiq/firmware/libio/proto.rs index bb36ffa40..0722f6926 100644 --- a/artiq/firmware/libio/proto.rs +++ b/artiq/firmware/libio/proto.rs @@ -36,21 +36,6 @@ impl From>> for IoError } } -#[cfg(feature = "alloc")] -#[cfg(feature = "std_artiq")] -impl From> for ::std_artiq::io::Error - where T: Into<::std_artiq::io::Error> -{ - fn from(value: ReadStringError) -> ::std_artiq::io::Error { - match value { - ReadStringError::Utf8Error(_) => - ::std_artiq::io::Error::new(::std_artiq::io::ErrorKind::InvalidData, - "invalid UTF-8"), - ReadStringError::Other(err) => err.into() - } - } -} - pub trait ProtoRead { type ReadError; diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 2057502df..3f05a2cb2 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -19,7 +19,7 @@ cslice = { version = "0.3" } log = { version = "0.4", default-features = false } managed = { version = "0.6", default-features = false, features = ["alloc", "map"] } unwind_backtrace = { path = "../libunwind_backtrace" } -io = { path = "../libio", features = ["byteorder", "std_artiq"] } +io = { path = "../libio", features = ["byteorder"] } alloc_list = { path = "../liballoc_list" } board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp"] } std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] } diff --git a/artiq/firmware/runtime/analyzer.rs b/artiq/firmware/runtime/analyzer.rs index 2ff4d6cd4..8bebf851b 100644 --- a/artiq/firmware/runtime/analyzer.rs +++ b/artiq/firmware/runtime/analyzer.rs @@ -1,4 +1,4 @@ -use std::io::{self, Write}; +use io::{self, Write}; use board_misoc::{csr, cache}; use sched::{Io, TcpListener, TcpStream}; use analyzer_proto::*; @@ -35,7 +35,7 @@ fn disarm() { } } -fn worker(stream: &mut TcpStream) -> io::Result<()> { +fn worker(stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { let data = unsafe { &BUFFER.data[..] }; let overflow_occurred = unsafe { csr::rtio_analyzer::message_encoder_overflow_read() != 0 }; let total_byte_count = unsafe { csr::rtio_analyzer::dma_byte_count_read() }; diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index fec653e9c..610e5be96 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -1,4 +1,4 @@ -use std::io; +use io; use kernel_proto as kern; use sched::Io; use session::{kern_acknowledge, kern_send}; @@ -291,7 +291,7 @@ mod spi { } } -pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> io::Result { +pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> io::Result { match request { #[cfg(has_rtio_core)] &kern::RtioInitRequest => { diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 2e30c5cfd..d1ae97260 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -1,27 +1,26 @@ -use std::io::{self, Read, Write}; use log::{self, LevelFilter}; +use io::{self, Read, Write, proto::ProtoWrite}; use board_misoc::boot; -use io::proto::ProtoWrite; use logger_artiq::BufferLogger; use sched::Io; use sched::{TcpListener, TcpStream}; use mgmt_proto::*; use profiler; -fn check_magic(stream: &mut TcpStream) -> io::Result<()> { +fn check_magic(stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { const MAGIC: &'static [u8] = b"ARTIQ management\n"; let mut magic: [u8; 17] = [0; 17]; stream.read_exact(&mut magic)?; if magic != MAGIC { - Err(io::Error::new(io::ErrorKind::InvalidData, "unrecognized magic")) + Err(io::Error::Unrecognized) } else { Ok(()) } } -fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> { +fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { check_magic(stream)?; info!("new connection from {}", stream.remote_endpoint()); @@ -35,7 +34,7 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> { } Request::ClearLog => { - BufferLogger::with(|logger| -> io::Result<()> { + BufferLogger::with(|logger| -> io::Result<(), ::std::io::Error> { let mut buffer = io.until_ok(|| logger.buffer())?; Ok(buffer.clear()) })?; @@ -44,7 +43,7 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<()> { } Request::PullLog => { - BufferLogger::with(|logger| -> io::Result<()> { + BufferLogger::with(|logger| -> io::Result<(), ::std::io::Error> { loop { // Do this *before* acquiring the buffer, since that sets the log level // to OFF. @@ -166,8 +165,7 @@ pub fn thread(io: Io) { let mut stream = TcpStream::from_handle(&io, stream); match worker(&io, &mut stream) { Ok(()) => (), - Err(ref err) if err.kind() == io::ErrorKind::UnexpectedEof => (), - Err(ref err) if err.kind() == io::ErrorKind::WriteZero => (), + Err(io::Error::UnexpectedEof) => (), Err(err) => error!("aborted: {}", err) } }); diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index ecb862b38..36fae9430 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -1,6 +1,6 @@ use alloc::btree_map::BTreeMap; -use std::io::{self, Read}; +use io::{self, Read}; use sched::Io; use sched::{TcpListener, TcpStream}; use board_misoc::{clock, csr}; @@ -9,13 +9,13 @@ use drtioaux; use moninj_proto::*; -fn check_magic(stream: &mut TcpStream) -> io::Result<()> { +fn check_magic(stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { const MAGIC: &'static [u8] = b"ARTIQ moninj\n"; let mut magic: [u8; 13] = [0; 13]; stream.read_exact(&mut magic)?; if magic != MAGIC { - Err(io::Error::new(io::ErrorKind::InvalidData, "unrecognized magic")) + Err(io::Error::Unrecognized) } else { Ok(()) } @@ -159,7 +159,7 @@ fn read_injection_status(channel: u32, probe: u8) -> u8 { 0 } -fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> io::Result<()> { +fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { let mut watch_list = BTreeMap::new(); let mut next_check = 0; diff --git a/artiq/firmware/runtime/rtio_dma.rs b/artiq/firmware/runtime/rtio_dma.rs index b0f964d86..6c135e72a 100644 --- a/artiq/firmware/runtime/rtio_dma.rs +++ b/artiq/firmware/runtime/rtio_dma.rs @@ -1,7 +1,7 @@ use core::mem; use alloc::{Vec, String, BTreeMap}; -use std::io::Write; +use io::Write; const ALIGNMENT: usize = 64; diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index e9ca34cc3..d6f2efcb7 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -9,8 +9,9 @@ use fringe::generator::{Generator, Yielder, State as GeneratorState}; use smoltcp::wire::IpEndpoint; use smoltcp::socket::{SocketHandle, SocketRef}; +use io::{Read, Write}; use board_misoc::clock; -use std::io::{Read, Write, Result, Error, ErrorKind}; +use std::io::{Result, Error, ErrorKind}; use urc::Urc; type SocketSet = ::smoltcp::socket::SocketSet<'static, 'static, 'static>; @@ -446,6 +447,8 @@ impl<'a> TcpStream<'a> { } impl<'a> Read for TcpStream<'a> { + type ReadError = Error; + fn read(&mut self, buf: &mut [u8]) -> Result { // Only borrow the underlying socket for the span of the next statement. let result = self.with_lower(|mut s| s.recv_slice(buf)); @@ -470,6 +473,9 @@ impl<'a> Read for TcpStream<'a> { } impl<'a> Write for TcpStream<'a> { + type WriteError = Error; + type FlushError = Error; + fn write(&mut self, buf: &[u8]) -> Result { // Only borrow the underlying socket for the span of the next statement. let result = self.with_lower(|mut s| s.send_slice(buf)); diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 82cf8c89c..63e397776 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -2,8 +2,8 @@ use core::{mem, str, cell::{Cell, RefCell}, fmt::Write as FmtWrite}; use alloc::{Vec, String}; use byteorder::{ByteOrder, NetworkEndian}; +use io::{self, Read, Write}; use board_misoc::{ident, cache, config}; -use std::io::{self, Read, Write}; use {mailbox, rpc_queue, kernel}; use urc::Urc; use sched::{ThreadHandle, Io}; @@ -23,13 +23,13 @@ macro_rules! unexpected { ($($arg:tt)*) => { { error!($($arg)*); - return Err(io::Error::new(io::ErrorKind::InvalidData, "protocol error")) + return Err(io::Error::Unrecognized) } }; } -fn io_error(msg: &str) -> io::Error { - io::Error::new(io::ErrorKind::Other, msg) +fn io_error(msg: &str) -> io::Error<::std::io::Error> { + io::Error::Other(::std::io::Error::new(::std::io::ErrorKind::Other, msg)) } // Persistent state @@ -102,19 +102,19 @@ impl<'a> Drop for Session<'a> { } } -fn check_magic(stream: &mut TcpStream) -> io::Result<()> { +fn check_magic(stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { const MAGIC: &'static [u8] = b"ARTIQ coredev\n"; let mut magic: [u8; 14] = [0; 14]; stream.read_exact(&mut magic)?; if magic != MAGIC { - Err(io::Error::new(io::ErrorKind::InvalidData, "unrecognized magic")) + Err(io::Error::Unrecognized) } else { Ok(()) } } -fn host_read(stream: &mut TcpStream) -> io::Result { +fn host_read(stream: &mut TcpStream) -> io::Result { let request = host::Request::read_from(stream)?; match &request { &host::Request::LoadKernel(_) => debug!("comm<-host LoadLibrary(...)"), @@ -123,12 +123,12 @@ fn host_read(stream: &mut TcpStream) -> io::Result { Ok(request) } -fn host_write(stream: &mut Write, reply: host::Reply) -> io::Result<()> { +fn host_write(stream: &mut TcpStream, reply: host::Reply) -> io::Result<(), ::std::io::Error> { debug!("comm->host {:?}", reply); - Ok(reply.write_to(stream)?) + reply.write_to(stream) } -pub fn kern_send(io: &Io, request: &kern::Message) -> io::Result<()> { +pub fn kern_send(io: &Io, request: &kern::Message) -> io::Result<(), ::std::io::Error> { match request { &kern::LoadRequest(_) => debug!("comm->kern LoadRequest(...)"), &kern::DmaRetrieveReply { trace, duration } => { @@ -141,15 +141,15 @@ pub fn kern_send(io: &Io, request: &kern::Message) -> io::Result<()> { _ => debug!("comm->kern {:?}", request) } unsafe { mailbox::send(request as *const _ as usize) } - io.until(mailbox::acknowledged) + Ok(io.until(mailbox::acknowledged)?) } -fn kern_recv_notrace(io: &Io, f: F) -> io::Result - where F: FnOnce(&kern::Message) -> io::Result { +fn kern_recv_notrace(io: &Io, f: F) -> io::Result + where F: FnOnce(&kern::Message) -> io::Result { io.until(|| mailbox::receive() != 0)?; if !kernel::validate(mailbox::receive()) { let message = format!("invalid kernel CPU pointer 0x{:x}", mailbox::receive()); - return Err(io::Error::new(io::ErrorKind::InvalidData, message)) + return Err(io::Error::Other(::std::io::Error::new(::std::io::ErrorKind::InvalidData, message))) } f(unsafe { &*(mailbox::receive() as *const kern::Message) }) @@ -171,20 +171,20 @@ fn kern_recv_dotrace(reply: &kern::Message) { } #[inline(always)] -fn kern_recv(io: &Io, f: F) -> io::Result - where F: FnOnce(&kern::Message) -> io::Result { +fn kern_recv(io: &Io, f: F) -> io::Result + where F: FnOnce(&kern::Message) -> io::Result { kern_recv_notrace(io, |reply| { kern_recv_dotrace(reply); f(reply) }) } -pub fn kern_acknowledge() -> io::Result<()> { +pub fn kern_acknowledge() -> io::Result<(), ::std::io::Error> { mailbox::acknowledge(); Ok(()) } -unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) -> io::Result<()> { +unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) -> io::Result<(), ::std::io::Error> { if session.running() { unexpected!("attempted to load a new kernel while a kernel was running") } @@ -200,8 +200,8 @@ unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) -> io::Resul } &kern::LoadReply(Err(ref error)) => { kernel::stop(); - Err(io::Error::new(io::ErrorKind::Other, - format!("cannot load kernel: {}", error))) + Err(io::Error::Other(::std::io::Error::new(::std::io::ErrorKind::Other, + format!("cannot load kernel: {}", error)))) } other => unexpected!("unexpected reply from kernel CPU: {:?}", other) @@ -209,7 +209,7 @@ unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) -> io::Resul }) } -fn kern_run(session: &mut Session) -> io::Result<()> { +fn kern_run(session: &mut Session) -> io::Result<(), ::std::io::Error> { if session.kernel_state != KernelState::Loaded { unexpected!("attempted to run a kernel while not in Loaded state") } @@ -221,7 +221,7 @@ fn kern_run(session: &mut Session) -> io::Result<()> { fn process_host_message(io: &Io, stream: &mut TcpStream, - session: &mut Session) -> io::Result<()> { + session: &mut Session) -> io::Result<(), ::std::io::Error> { match host_read(stream)? { host::Request::SystemInfo => { host_write(stream, host::Reply::SystemInfo { @@ -359,7 +359,7 @@ fn process_host_message(io: &Io, } fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, - session: &mut Session) -> io::Result { + session: &mut Session) -> io::Result { kern_recv_notrace(io, |request| { match (request, session.kernel_state) { (&kern::LoadReply(_), KernelState::Loaded) | @@ -516,7 +516,7 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, } fn process_kern_queued_rpc(stream: &mut TcpStream, - _session: &mut Session) -> io::Result<()> { + _session: &mut Session) -> io::Result<(), ::std::io::Error> { rpc_queue::dequeue(|slice| { debug!("comm<-kern (async RPC)"); let length = NetworkEndian::read_u32(slice) as usize; @@ -529,7 +529,7 @@ fn process_kern_queued_rpc(stream: &mut TcpStream, fn host_kernel_worker(io: &Io, stream: &mut TcpStream, - congress: &mut Congress) -> io::Result<()> { + congress: &mut Congress) -> io::Result<(), ::std::io::Error> { let mut session = Session::new(congress); loop { @@ -568,7 +568,7 @@ fn host_kernel_worker(io: &Io, fn flash_kernel_worker(io: &Io, congress: &mut Congress, - config_key: &str) -> io::Result<()> { + config_key: &str) -> io::Result<(), ::std::io::Error> { let mut session = Session::new(congress); config::read(config_key, |result| { @@ -578,7 +578,8 @@ fn flash_kernel_worker(io: &Io, // so make a copy. kern_load(io, &mut session, Vec::from(kernel).as_ref()) }, - _ => Err(io::Error::new(io::ErrorKind::NotFound, "kernel not found")), + _ => Err(io::Error::Other(::std::io::Error::new(::std::io::ErrorKind::NotFound, + "kernel not found"))), } })?; kern_run(&mut session)?; @@ -639,13 +640,12 @@ pub fn thread(io: Io) { info!("running startup kernel"); match flash_kernel_worker(&io, &mut congress, "startup_kernel") { Ok(()) => info!("startup kernel finished"), + Err(io::Error::Other(ref err)) if err.kind() == ::std::io::ErrorKind::NotFound => { + info!("no startup kernel found") + } Err(err) => { - if err.kind() == io::ErrorKind::NotFound { - info!("no startup kernel found") - } else { - congress.finished_cleanly.set(false); - error!("startup kernel aborted: {}", err); - } + congress.finished_cleanly.set(false); + error!("startup kernel aborted: {}", err); } } }) @@ -674,15 +674,16 @@ pub fn thread(io: Io) { let mut stream = TcpStream::from_handle(&io, stream); match host_kernel_worker(&io, &mut stream, &mut *congress) { Ok(()) => (), + Err(io::Error::UnexpectedEof) => { + info!("connection closed"); + } + Err(io::Error::Other(ref err)) + if err.kind() == ::std::io::ErrorKind::Interrupted => { + info!("kernel interrupted"); + } Err(err) => { - if err.kind() == io::ErrorKind::UnexpectedEof { - info!("connection closed"); - } else if err.kind() == io::ErrorKind::Interrupted { - info!("kernel interrupted"); - } else { - congress.finished_cleanly.set(false); - error!("session aborted: {}", err); - } + congress.finished_cleanly.set(false); + error!("session aborted: {}", err); } } }); @@ -697,15 +698,17 @@ pub fn thread(io: Io) { match flash_kernel_worker(&io, &mut *congress, "idle_kernel") { Ok(()) => info!("idle kernel finished, standing by"), + Err(io::Error::Other(ref err)) + if err.kind() == ::std::io::ErrorKind::Interrupted => { + info!("idle kernel interrupted"); + } + Err(io::Error::Other(ref err)) + if err.kind() == ::std::io::ErrorKind::NotFound => { + info!("no idle kernel found"); + while io.relinquish().is_ok() {} + } Err(err) => { - if err.kind() == io::ErrorKind::Interrupted { - info!("idle kernel interrupted"); - } else if err.kind() == io::ErrorKind::NotFound { - info!("no idle kernel found"); - while io.relinquish().is_ok() {} - } else { - error!("idle kernel aborted: {}", err); - } + error!("idle kernel aborted: {}", err); } } }) From d93aa13fd63d9f45ce0745a296d4d9e0c8c479bd Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 19:11:16 +0000 Subject: [PATCH 0761/2457] firmware: use upstream compiler_builtins again. I've fixed i128 in LLVM, so there is no need in our fork anymore. --- artiq/firmware/Cargo.lock | 6 +++--- artiq/firmware/libboard_misoc/Cargo.toml | 6 +----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 13bcb05ed..cb0201e69 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -29,7 +29,7 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=ca06a5e)", + "compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", ] @@ -79,7 +79,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "compiler_builtins" version = "0.1.0" -source = "git+https://github.com/m-labs/compiler-builtins?rev=ca06a5e#ca06a5e3d5ff9a17210f22401fdf6325f632c59e" +source = "git+https://github.com/rust-lang-nursery/compiler-builtins#28daccd9159d33fac5e36394e4f9618db8870dc0" [[package]] name = "crc" @@ -277,7 +277,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" "checksum cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2b4911e4bdcb4100c7680e7e854ff38e23f1b34d4d9e079efae3da2801341ffc" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"checksum compiler_builtins 0.1.0 (git+https://github.com/m-labs/compiler-builtins?rev=ca06a5e)" = "" +"checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins)" = "" "checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" "checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "" diff --git a/artiq/firmware/libboard_misoc/Cargo.toml b/artiq/firmware/libboard_misoc/Cargo.toml index 5fa31a7dc..35851cfb5 100644 --- a/artiq/firmware/libboard_misoc/Cargo.toml +++ b/artiq/firmware/libboard_misoc/Cargo.toml @@ -13,14 +13,10 @@ cc = "1.0" build_misoc = { path = "../libbuild_misoc" } [dependencies] +compiler_builtins = { git = "https://github.com/rust-lang-nursery/compiler-builtins", features = ["mem"] } byteorder = { version = "1.0", default-features = false } log = { version = "0.4", default-features = false, optional = true } -[dependencies.compiler_builtins] -git = "https://github.com/m-labs/compiler-builtins" -rev = "ca06a5e" -features = ["mem"] - [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" rev = "181083f" From a4ab236af33297b7cd67437a788b599fd801a2a4 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 14 May 2018 19:24:14 +0000 Subject: [PATCH 0762/2457] firmware: simplify some `use`s. --- artiq/firmware/libproto_artiq/mgmt_proto.rs | 2 +- artiq/firmware/libproto_artiq/session_proto.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libproto_artiq/mgmt_proto.rs b/artiq/firmware/libproto_artiq/mgmt_proto.rs index 6e343c083..490be2e5d 100644 --- a/artiq/firmware/libproto_artiq/mgmt_proto.rs +++ b/artiq/firmware/libproto_artiq/mgmt_proto.rs @@ -1,4 +1,4 @@ -use alloc::vec::Vec; +use alloc::Vec; #[cfg(feature = "log")] use log; diff --git a/artiq/firmware/libproto_artiq/session_proto.rs b/artiq/firmware/libproto_artiq/session_proto.rs index 8dd5dec9f..6e4e91cd4 100644 --- a/artiq/firmware/libproto_artiq/session_proto.rs +++ b/artiq/firmware/libproto_artiq/session_proto.rs @@ -1,5 +1,4 @@ -use alloc::vec::Vec; -use alloc::string::String; +use alloc::{Vec, String}; use io::{Read, Write, Error, Result}; use io::proto::{ProtoRead, ProtoWrite}; From 9e8f8bb669e501065e6bedbbccdc9a9c4be7ecdf Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 15 May 2018 06:24:04 +0000 Subject: [PATCH 0763/2457] firmware: extract io::Cursor into its own file. Also remove unused io::CursorError. --- artiq/firmware/libio/cursor.rs | 86 +++++++++++++++++++++++++++++++ artiq/firmware/libio/lib.rs | 93 ++-------------------------------- 2 files changed, 89 insertions(+), 90 deletions(-) create mode 100644 artiq/firmware/libio/cursor.rs diff --git a/artiq/firmware/libio/cursor.rs b/artiq/firmware/libio/cursor.rs new file mode 100644 index 000000000..b820bdddc --- /dev/null +++ b/artiq/firmware/libio/cursor.rs @@ -0,0 +1,86 @@ +use {Read, Write}; + +#[derive(Debug, Clone)] +pub struct Cursor { + inner: T, + pos: usize +} + +impl Cursor { + #[inline] + pub fn new(inner: T) -> Cursor { + Cursor { inner, pos: 0 } + } + + #[inline] + pub fn into_inner(self) -> T { + self.inner + } + + #[inline] + pub fn get_ref(&self) -> &T { + &self.inner + } + + #[inline] + pub fn get_mut(&mut self) -> &mut T { + &mut self.inner + } + + #[inline] + pub fn position(&self) -> usize { + self.pos + } + + #[inline] + pub fn set_position(&mut self, pos: usize) { + self.pos = pos + } +} + +impl> Read for Cursor { + type ReadError = !; + + fn read(&mut self, buf: &mut [u8]) -> Result { + let data = &self.inner.as_ref()[self.pos..]; + let len = buf.len().min(data.len()); + buf[..len].copy_from_slice(&data[..len]); + self.pos += len; + Ok(len) + } +} + +impl<'a> Write for Cursor<&'a mut [u8]> { + type WriteError = !; + type FlushError = !; + + fn write(&mut self, buf: &[u8]) -> Result { + let data = &mut self.inner[self.pos..]; + let len = buf.len().min(data.len()); + data[..len].copy_from_slice(&buf[..len]); + self.pos += len; + Ok(len) + } + + #[inline] + fn flush(&mut self) -> Result<(), Self::FlushError> { + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl Write for Cursor<::alloc::Vec> { + type WriteError = !; + type FlushError = !; + + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + self.inner.extend_from_slice(buf); + Ok(buf.len()) + } + + #[inline] + fn flush(&mut self) -> Result<(), Self::FlushError> { + Ok(()) + } +} diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs index c536e5383..884f57f27 100644 --- a/artiq/firmware/libio/lib.rs +++ b/artiq/firmware/libio/lib.rs @@ -11,9 +11,12 @@ extern crate byteorder; use core::result; use core::fmt; +mod cursor; #[cfg(feature = "byteorder")] pub mod proto; +pub use cursor::Cursor; + pub type Result = result::Result>; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -152,93 +155,3 @@ impl<'a> Write for alloc::Vec { Ok(()) } } - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum CursorError { - EndOfBuffer -} - -#[derive(Debug, Clone)] -pub struct Cursor { - inner: T, - pos: usize -} - -impl Cursor { - #[inline] - pub fn new(inner: T) -> Cursor { - Cursor { inner, pos: 0 } - } - - #[inline] - pub fn into_inner(self) -> T { - self.inner - } - - #[inline] - pub fn get_ref(&self) -> &T { - &self.inner - } - - #[inline] - pub fn get_mut(&mut self) -> &mut T { - &mut self.inner - } - - #[inline] - pub fn position(&self) -> usize { - self.pos - } - - #[inline] - pub fn set_position(&mut self, pos: usize) { - self.pos = pos - } -} - -impl> Read for Cursor { - type ReadError = !; - - fn read(&mut self, buf: &mut [u8]) -> result::Result { - let data = &self.inner.as_ref()[self.pos..]; - let len = buf.len().min(data.len()); - buf[..len].copy_from_slice(&data[..len]); - self.pos += len; - Ok(len) - } -} - -impl<'a> Write for Cursor<&'a mut [u8]> { - type WriteError = !; - type FlushError = !; - - fn write(&mut self, buf: &[u8]) -> result::Result { - let data = &mut self.inner[self.pos..]; - let len = buf.len().min(data.len()); - data[..len].copy_from_slice(&buf[..len]); - self.pos += len; - Ok(len) - } - - #[inline] - fn flush(&mut self) -> result::Result<(), Self::FlushError> { - Ok(()) - } -} - -#[cfg(feature = "alloc")] -impl Write for Cursor<::alloc::Vec> { - type WriteError = !; - type FlushError = !; - - #[inline] - fn write(&mut self, buf: &[u8]) -> result::Result { - self.inner.extend_from_slice(buf); - Ok(buf.len()) - } - - #[inline] - fn flush(&mut self) -> result::Result<(), Self::FlushError> { - Ok(()) - } -} From 4416c04ae17c723402bac6cd5b89d81d054ce4b2 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 15 May 2018 07:33:12 +0000 Subject: [PATCH 0764/2457] firmware: use the failure crate in libio. --- artiq/firmware/Cargo.lock | 61 +++++++++++++++++++++++++++++++++ artiq/firmware/libio/Cargo.toml | 2 ++ artiq/firmware/libio/lib.rs | 24 +++++-------- artiq/firmware/libio/proto.rs | 32 ++++------------- 4 files changed, 78 insertions(+), 41 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index cb0201e69..3370bc073 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -98,6 +98,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "dyld" version = "0.0.0" +[[package]] +name = "failure" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "failure_derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fringe" version = "1.1.0" @@ -111,6 +126,8 @@ name = "io" version = "0.0.0" dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -191,6 +208,11 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quote" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "runtime" version = "0.0.0" @@ -247,6 +269,38 @@ dependencies = [ name = "std_artiq" version = "0.0.0" +[[package]] +name = "syn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synom" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-xid" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unwind_backtrace" version = "0.0.0" @@ -280,6 +334,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins)" = "" "checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" +"checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" +"checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" "checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" @@ -288,8 +344,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log_buffer 1.2.0 (git+https://github.com/whitequark/rust-log_buffer?rev=rust-1.25)" = "" "checksum managed 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43e2737ecabe4ae36a68061398bf27d2bfd0763f4c3c837a398478459494c4b7" "checksum managed 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5a31885241e61ba264d780d2e6686e7e59561c947b4581470364eb3e10102d86" +"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)" = "" +"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" +"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +"checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" +"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/artiq/firmware/libio/Cargo.toml b/artiq/firmware/libio/Cargo.toml index 9729aca32..6aacf0c47 100644 --- a/artiq/firmware/libio/Cargo.toml +++ b/artiq/firmware/libio/Cargo.toml @@ -8,6 +8,8 @@ name = "io" path = "lib.rs" [dependencies] +failure = { version = "0.1", default-features = false } +failure_derive = { version = "0.1", default-features = false } byteorder = { version = "1.0", default-features = false, optional = true } [features] diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs index 884f57f27..48f07394d 100644 --- a/artiq/firmware/libio/lib.rs +++ b/artiq/firmware/libio/lib.rs @@ -2,6 +2,9 @@ #![feature(never_type)] #![cfg_attr(feature = "alloc", feature(alloc))] +extern crate failure; +#[macro_use] +extern crate failure_derive; #[cfg(feature = "alloc")] #[macro_use] extern crate alloc; @@ -9,7 +12,6 @@ extern crate alloc; extern crate byteorder; use core::result; -use core::fmt; mod cursor; #[cfg(feature = "byteorder")] @@ -19,24 +21,14 @@ pub use cursor::Cursor; pub type Result = result::Result>; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Fail, Debug, Clone, PartialEq)] pub enum Error { + #[fail(display = "unexpected end of stream")] UnexpectedEof, + #[fail(display = "unrecognized input")] Unrecognized, - Other(T) -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &Error::UnexpectedEof => - write!(f, "unexpected end of stream"), - &Error::Unrecognized => - write!(f, "unrecognized input"), - &Error::Other(ref err) => - write!(f, "{}", err) - } - } + #[fail(display = "{}", _0)] + Other(#[cause] T) } impl From for Error { diff --git a/artiq/firmware/libio/proto.rs b/artiq/firmware/libio/proto.rs index 0722f6926..22a8deb3e 100644 --- a/artiq/firmware/libio/proto.rs +++ b/artiq/firmware/libio/proto.rs @@ -1,30 +1,18 @@ #[cfg(feature = "alloc")] -use core::fmt; -#[cfg(feature = "alloc")] -use alloc::string; +use {core::str::Utf8Error, alloc::String}; use byteorder::{ByteOrder, NetworkEndian}; use ::{Read, Write, Error as IoError}; #[cfg(feature = "alloc")] -#[derive(Debug)] +#[derive(Fail, Debug, Clone, PartialEq)] pub enum ReadStringError { - Utf8Error(string::FromUtf8Error), + #[fail(display = "invalid UTF-8: {}", _0)] + Utf8Error(Utf8Error), + #[fail(display = "{}", _0)] Other(T) } -#[cfg(feature = "alloc")] -impl fmt::Display for ReadStringError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &ReadStringError::Utf8Error(ref err) => - write!(f, "invalid UTF-8 ({})", err), - &ReadStringError::Other(ref err) => - write!(f, "{}", err) - } - } -} - #[cfg(feature = "alloc")] impl From>> for IoError { @@ -86,14 +74,8 @@ pub trait ProtoRead { #[cfg(feature = "alloc")] #[inline] fn read_string(&mut self) -> Result<::alloc::String, ReadStringError> { - match self.read_bytes() { - Ok(bytes) => - match ::alloc::String::from_utf8(bytes) { - Ok(string) => Ok(string), - Err(err) => Err(ReadStringError::Utf8Error(err)) - }, - Err(err) => Err(ReadStringError::Other(err)) - } + let bytes = self.read_bytes().map_err(ReadStringError::Other)?; + String::from_utf8(bytes).map_err(|err| ReadStringError::Utf8Error(err.utf8_error())) } } From ce0593315b30198a3c2fd84152b22f5869afc776 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 15 May 2018 08:16:09 +0000 Subject: [PATCH 0765/2457] firmware: move {ProtoRead,ProtoWrite} to the root of libio. --- artiq/firmware/Cargo.lock | 2 ++ artiq/firmware/ksupport/lib.rs | 2 +- artiq/firmware/libio/lib.rs | 4 +++- artiq/firmware/libproto_artiq/Cargo.toml | 2 ++ artiq/firmware/libproto_artiq/analyzer_proto.rs | 3 +-- artiq/firmware/libproto_artiq/drtioaux_proto.rs | 3 +-- artiq/firmware/libproto_artiq/mgmt_proto.rs | 3 +-- artiq/firmware/libproto_artiq/moninj_proto.rs | 3 +-- artiq/firmware/libproto_artiq/rpc_proto.rs | 4 +--- artiq/firmware/libproto_artiq/session_proto.rs | 3 +-- artiq/firmware/runtime/mgmt.rs | 2 +- 11 files changed, 15 insertions(+), 16 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 3370bc073..673c6e9e0 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -204,6 +204,8 @@ dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dyld 0.0.0", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "io 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 4122e75c7..229e616c2 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -127,7 +127,7 @@ extern fn rpc_send_async(service: u32, tag: CSlice, data: *const *const ()) rpc_proto::send_args(&mut writer, service, tag.as_ref(), data)?; writer.position() }; - io::proto::ProtoWrite::write_u32(&mut slice, length as u32) + io::ProtoWrite::write_u32(&mut slice, length as u32) }).unwrap_or_else(|err| { assert!(err == io::Error::UnexpectedEof); diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs index 48f07394d..486e4ae7b 100644 --- a/artiq/firmware/libio/lib.rs +++ b/artiq/firmware/libio/lib.rs @@ -15,9 +15,11 @@ use core::result; mod cursor; #[cfg(feature = "byteorder")] -pub mod proto; +mod proto; pub use cursor::Cursor; +#[cfg(feature = "byteorder")] +pub use proto::{ProtoRead, ProtoWrite}; pub type Result = result::Result>; diff --git a/artiq/firmware/libproto_artiq/Cargo.toml b/artiq/firmware/libproto_artiq/Cargo.toml index 19b1884dd..92d5e0d0f 100644 --- a/artiq/firmware/libproto_artiq/Cargo.toml +++ b/artiq/firmware/libproto_artiq/Cargo.toml @@ -8,6 +8,8 @@ name = "proto_artiq" path = "lib.rs" [dependencies] +failure = { version = "0.1", default-features = false } +failure_derive = { version = "0.1", default-features = false } byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } log = { version = "0.4", default-features = false, optional = true } diff --git a/artiq/firmware/libproto_artiq/analyzer_proto.rs b/artiq/firmware/libproto_artiq/analyzer_proto.rs index 66c54c753..02f81fce2 100644 --- a/artiq/firmware/libproto_artiq/analyzer_proto.rs +++ b/artiq/firmware/libproto_artiq/analyzer_proto.rs @@ -1,5 +1,4 @@ -use io::{Write, Result}; -use io::proto::{ProtoWrite}; +use io::{Write, ProtoWrite, Result}; #[derive(Debug)] pub struct Header { diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 1899f0787..1bd4eabb7 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -1,5 +1,4 @@ -use io::{Read, Write, Error, Result}; -use io::proto::{ProtoRead, ProtoWrite}; +use io::{Read, ProtoRead, Write, ProtoWrite, Error, Result}; #[derive(Debug)] pub enum Packet { diff --git a/artiq/firmware/libproto_artiq/mgmt_proto.rs b/artiq/firmware/libproto_artiq/mgmt_proto.rs index 490be2e5d..d7c2cb8be 100644 --- a/artiq/firmware/libproto_artiq/mgmt_proto.rs +++ b/artiq/firmware/libproto_artiq/mgmt_proto.rs @@ -2,8 +2,7 @@ use alloc::Vec; #[cfg(feature = "log")] use log; -use io::{Read, Write, Error, Result}; -use io::proto::{ProtoRead, ProtoWrite}; +use io::{Read, ProtoRead, Write, ProtoWrite, Error, Result}; #[derive(Debug)] pub enum Request { diff --git a/artiq/firmware/libproto_artiq/moninj_proto.rs b/artiq/firmware/libproto_artiq/moninj_proto.rs index b440fab14..d40dc40dc 100644 --- a/artiq/firmware/libproto_artiq/moninj_proto.rs +++ b/artiq/firmware/libproto_artiq/moninj_proto.rs @@ -1,5 +1,4 @@ -use io::{Read, Write, Error, Result}; -use io::proto::{ProtoRead, ProtoWrite}; +use io::{Read, ProtoRead, Write, ProtoWrite, Error, Result}; #[derive(Debug)] pub enum HostMessage { diff --git a/artiq/firmware/libproto_artiq/rpc_proto.rs b/artiq/firmware/libproto_artiq/rpc_proto.rs index 226cb47b6..3e0b6594d 100644 --- a/artiq/firmware/libproto_artiq/rpc_proto.rs +++ b/artiq/firmware/libproto_artiq/rpc_proto.rs @@ -1,9 +1,7 @@ use core::str; use cslice::{CSlice, CMutSlice}; -use io::{Read, Write, Result}; -use io::proto::{ProtoRead, ProtoWrite}; - +use io::{ProtoRead, Read, Write, ProtoWrite, Result}; use self::tag::{Tag, TagIterator, split_tag}; unsafe fn recv_value(reader: &mut T, tag: Tag, data: &mut *mut (), diff --git a/artiq/firmware/libproto_artiq/session_proto.rs b/artiq/firmware/libproto_artiq/session_proto.rs index 6e4e91cd4..0253c8e8c 100644 --- a/artiq/firmware/libproto_artiq/session_proto.rs +++ b/artiq/firmware/libproto_artiq/session_proto.rs @@ -1,7 +1,6 @@ use alloc::{Vec, String}; -use io::{Read, Write, Error, Result}; -use io::proto::{ProtoRead, ProtoWrite}; +use io::{Read, ProtoRead, Write, ProtoWrite, Error, Result}; fn read_sync(reader: &mut T) -> Result<(), T::ReadError> { let mut sync = [0; 4]; diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index d1ae97260..574f55df8 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -1,6 +1,6 @@ use log::{self, LevelFilter}; -use io::{self, Read, Write, proto::ProtoWrite}; +use io::{self, Read, Write, ProtoWrite}; use board_misoc::boot; use logger_artiq::BufferLogger; use sched::Io; From 140ca729aa3bf4b24e40c46534dbc9bf907e0a21 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 15 May 2018 08:27:45 +0000 Subject: [PATCH 0766/2457] =?UTF-8?q?firmware:=20rename=20io::Error::{Unex?= =?UTF-8?q?pectedEof=E2=86=92UnexpectedEnd}.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't even have files. --- artiq/firmware/ksupport/lib.rs | 2 +- artiq/firmware/libio/lib.rs | 6 +++--- artiq/firmware/runtime/mgmt.rs | 2 +- artiq/firmware/runtime/session.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 229e616c2..e2f7696a2 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -129,7 +129,7 @@ extern fn rpc_send_async(service: u32, tag: CSlice, data: *const *const ()) }; io::ProtoWrite::write_u32(&mut slice, length as u32) }).unwrap_or_else(|err| { - assert!(err == io::Error::UnexpectedEof); + assert!(err == io::Error::UnexpectedEnd); while !rpc_queue::empty() {} send(&RpcSend { diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs index 486e4ae7b..654f68c36 100644 --- a/artiq/firmware/libio/lib.rs +++ b/artiq/firmware/libio/lib.rs @@ -26,7 +26,7 @@ pub type Result = result::Result>; #[derive(Fail, Debug, Clone, PartialEq)] pub enum Error { #[fail(display = "unexpected end of stream")] - UnexpectedEof, + UnexpectedEnd, #[fail(display = "unrecognized input")] Unrecognized, #[fail(display = "{}", _0)] @@ -51,7 +51,7 @@ pub trait Read { while !buf.is_empty() { let read_bytes = self.read(buf)?; if read_bytes == 0 { - return Err(Error::UnexpectedEof) + return Err(Error::UnexpectedEnd) } buf = &mut { buf }[read_bytes..]; @@ -85,7 +85,7 @@ pub trait Write { while buf.len() > 0 { let written_bytes = self.write(buf)?; if written_bytes == 0 { - return Err(Error::UnexpectedEof) + return Err(Error::UnexpectedEnd) } buf = &buf[written_bytes..]; diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 574f55df8..b23b6bbcc 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -165,7 +165,7 @@ pub fn thread(io: Io) { let mut stream = TcpStream::from_handle(&io, stream); match worker(&io, &mut stream) { Ok(()) => (), - Err(io::Error::UnexpectedEof) => (), + Err(io::Error::UnexpectedEnd) => (), Err(err) => error!("aborted: {}", err) } }); diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 63e397776..dced8025c 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -674,7 +674,7 @@ pub fn thread(io: Io) { let mut stream = TcpStream::from_handle(&io, stream); match host_kernel_worker(&io, &mut stream, &mut *congress) { Ok(()) => (), - Err(io::Error::UnexpectedEof) => { + Err(io::Error::UnexpectedEnd) => { info!("connection closed"); } Err(io::Error::Other(ref err)) From 26faaad2b775b7bd7180988f0380674553552140 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 15 May 2018 08:29:03 +0000 Subject: [PATCH 0767/2457] firmware: remove io::Result in favor of Result. This doesn't yet use impl Fail since std_artiq::io::Error doesn't impl it. --- artiq/firmware/libio/lib.rs | 28 +++++++--------- .../firmware/libproto_artiq/analyzer_proto.rs | 4 +-- .../firmware/libproto_artiq/drtioaux_proto.rs | 6 ++-- artiq/firmware/libproto_artiq/mgmt_proto.rs | 8 ++--- artiq/firmware/libproto_artiq/moninj_proto.rs | 6 ++-- artiq/firmware/libproto_artiq/rpc_proto.rs | 14 ++++---- .../firmware/libproto_artiq/session_proto.rs | 10 +++--- artiq/firmware/runtime/analyzer.rs | 2 +- artiq/firmware/runtime/kern_hwreq.rs | 2 +- artiq/firmware/runtime/mgmt.rs | 8 ++--- artiq/firmware/runtime/moninj.rs | 4 +-- artiq/firmware/runtime/session.rs | 32 +++++++++---------- 12 files changed, 60 insertions(+), 64 deletions(-) diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs index 654f68c36..b8bc09d7b 100644 --- a/artiq/firmware/libio/lib.rs +++ b/artiq/firmware/libio/lib.rs @@ -11,8 +11,6 @@ extern crate alloc; #[cfg(feature = "byteorder")] extern crate byteorder; -use core::result; - mod cursor; #[cfg(feature = "byteorder")] mod proto; @@ -21,8 +19,6 @@ pub use cursor::Cursor; #[cfg(feature = "byteorder")] pub use proto::{ProtoRead, ProtoWrite}; -pub type Result = result::Result>; - #[derive(Fail, Debug, Clone, PartialEq)] pub enum Error { #[fail(display = "unexpected end of stream")] @@ -44,10 +40,10 @@ pub trait Read { /// Pull some bytes from this source into the specified buffer, returning /// how many bytes were read. - fn read(&mut self, buf: &mut [u8]) -> result::Result; + fn read(&mut self, buf: &mut [u8]) -> Result; /// Read the exact number of bytes required to fill `buf`. - fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), Self::ReadError> { + fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), Error> { while !buf.is_empty() { let read_bytes = self.read(buf)?; if read_bytes == 0 { @@ -64,7 +60,7 @@ pub trait Read { impl<'a, T: Read> Read for &'a mut T { type ReadError = T::ReadError; - fn read(&mut self, buf: &mut [u8]) -> result::Result { + fn read(&mut self, buf: &mut [u8]) -> Result { T::read(self, buf) } } @@ -74,14 +70,14 @@ pub trait Write { type FlushError; /// Write a buffer into this object, returning how many bytes were written. - fn write(&mut self, buf: &[u8]) -> result::Result; + fn write(&mut self, buf: &[u8]) -> Result; /// Flush this output stream, ensuring that all intermediately buffered contents /// reach their destination. - fn flush(&mut self) -> result::Result<(), Self::FlushError>; + fn flush(&mut self) -> Result<(), Self::FlushError>; /// Attempts to write an entire buffer into `self`. - fn write_all(&mut self, mut buf: &[u8]) -> Result<(), Self::WriteError> { + fn write_all(&mut self, mut buf: &[u8]) -> Result<(), Error> { while buf.len() > 0 { let written_bytes = self.write(buf)?; if written_bytes == 0 { @@ -105,11 +101,11 @@ impl<'a, T: Write> Write for &'a mut T { type WriteError = T::WriteError; type FlushError = T::FlushError; - fn write(&mut self, buf: &[u8]) -> result::Result { + fn write(&mut self, buf: &[u8]) -> Result { T::write(self, buf) } - fn flush(&mut self) -> result::Result<(), Self::FlushError> { + fn flush(&mut self) -> Result<(), Self::FlushError> { T::flush(self) } @@ -122,14 +118,14 @@ impl<'a> Write for &'a mut [u8] { type WriteError = !; type FlushError = !; - fn write(&mut self, buf: &[u8]) -> result::Result { + fn write(&mut self, buf: &[u8]) -> Result { let len = buf.len().min(self.len()); self[..len].copy_from_slice(&buf[..len]); Ok(len) } #[inline] - fn flush(&mut self) -> result::Result<(), Self::FlushError> { + fn flush(&mut self) -> Result<(), Self::FlushError> { Ok(()) } } @@ -139,13 +135,13 @@ impl<'a> Write for alloc::Vec { type WriteError = !; type FlushError = !; - fn write(&mut self, buf: &[u8]) -> result::Result { + fn write(&mut self, buf: &[u8]) -> Result { self.extend_from_slice(buf); Ok(buf.len()) } #[inline] - fn flush(&mut self) -> result::Result<(), Self::FlushError> { + fn flush(&mut self) -> Result<(), Self::FlushError> { Ok(()) } } diff --git a/artiq/firmware/libproto_artiq/analyzer_proto.rs b/artiq/firmware/libproto_artiq/analyzer_proto.rs index 02f81fce2..c74632ec2 100644 --- a/artiq/firmware/libproto_artiq/analyzer_proto.rs +++ b/artiq/firmware/libproto_artiq/analyzer_proto.rs @@ -1,4 +1,4 @@ -use io::{Write, ProtoWrite, Result}; +use io::{Write, ProtoWrite, Error}; #[derive(Debug)] pub struct Header { @@ -10,7 +10,7 @@ pub struct Header { } impl Header { - pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { + pub fn write_to(&self, writer: &mut T) -> Result<(), Error> { writer.write_u32(self.sent_bytes)?; writer.write_u64(self.total_byte_count)?; writer.write_u8(self.overflow_occurred as u8)?; diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 1bd4eabb7..0aae19617 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -1,4 +1,4 @@ -use io::{Read, ProtoRead, Write, ProtoWrite, Error, Result}; +use io::{Read, ProtoRead, Write, ProtoWrite, Error}; #[derive(Debug)] pub enum Packet { @@ -36,7 +36,7 @@ pub enum Packet { } impl Packet { - pub fn read_from(reader: &mut T) -> Result { + pub fn read_from(reader: &mut T) -> Result> { Ok(match reader.read_u8()? { 0x00 => Packet::EchoRequest, 0x01 => Packet::EchoReply, @@ -133,7 +133,7 @@ impl Packet { }) } - pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { + pub fn write_to(&self, writer: &mut T) -> Result<(), Error> { match *self { Packet::EchoRequest => writer.write_u8(0x00)?, diff --git a/artiq/firmware/libproto_artiq/mgmt_proto.rs b/artiq/firmware/libproto_artiq/mgmt_proto.rs index d7c2cb8be..3bb33e65d 100644 --- a/artiq/firmware/libproto_artiq/mgmt_proto.rs +++ b/artiq/firmware/libproto_artiq/mgmt_proto.rs @@ -2,7 +2,7 @@ use alloc::Vec; #[cfg(feature = "log")] use log; -use io::{Read, ProtoRead, Write, ProtoWrite, Error, Result}; +use io::{Read, ProtoRead, Write, ProtoWrite, Error}; #[derive(Debug)] pub enum Request { @@ -40,10 +40,10 @@ pub enum Reply<'a> { } impl Request { - pub fn read_from(reader: &mut T) -> Result { + pub fn read_from(reader: &mut T) -> Result> { #[cfg(feature = "log")] fn read_log_level_filter(reader: &mut T) -> - Result { + Result> { Ok(match reader.read_u8()? { 0 => log::LevelFilter::Off, 1 => log::LevelFilter::Error, @@ -79,7 +79,7 @@ impl Request { } impl<'a> Reply<'a> { - pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { + pub fn write_to(&self, writer: &mut T) -> Result<(), Error> { match *self { Reply::Success => { writer.write_u8(1)?; diff --git a/artiq/firmware/libproto_artiq/moninj_proto.rs b/artiq/firmware/libproto_artiq/moninj_proto.rs index d40dc40dc..285ce9f09 100644 --- a/artiq/firmware/libproto_artiq/moninj_proto.rs +++ b/artiq/firmware/libproto_artiq/moninj_proto.rs @@ -1,4 +1,4 @@ -use io::{Read, ProtoRead, Write, ProtoWrite, Error, Result}; +use io::{Read, ProtoRead, Write, ProtoWrite, Error}; #[derive(Debug)] pub enum HostMessage { @@ -14,7 +14,7 @@ pub enum DeviceMessage { } impl HostMessage { - pub fn read_from(reader: &mut T) -> Result { + pub fn read_from(reader: &mut T) -> Result> { Ok(match reader.read_u8()? { 0 => HostMessage::Monitor { enable: if reader.read_u8()? == 0 { false } else { true }, @@ -36,7 +36,7 @@ impl HostMessage { } impl DeviceMessage { - pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { + pub fn write_to(&self, writer: &mut T) -> Result<(), Error> { match *self { DeviceMessage::MonitorStatus { channel, probe, value } => { writer.write_u8(0)?; diff --git a/artiq/firmware/libproto_artiq/rpc_proto.rs b/artiq/firmware/libproto_artiq/rpc_proto.rs index 3e0b6594d..f5f8581c1 100644 --- a/artiq/firmware/libproto_artiq/rpc_proto.rs +++ b/artiq/firmware/libproto_artiq/rpc_proto.rs @@ -1,12 +1,12 @@ use core::str; use cslice::{CSlice, CMutSlice}; -use io::{ProtoRead, Read, Write, ProtoWrite, Result}; +use io::{ProtoRead, Read, Write, ProtoWrite, Error}; use self::tag::{Tag, TagIterator, split_tag}; unsafe fn recv_value(reader: &mut T, tag: Tag, data: &mut *mut (), - alloc: &Fn(usize) -> Result<*mut (), T::ReadError>) - -> Result<(), T::ReadError> + alloc: &Fn(usize) -> Result<*mut (), Error>) + -> Result<(), Error> where T: Read + ?Sized { macro_rules! consume_value { @@ -75,8 +75,8 @@ unsafe fn recv_value(reader: &mut T, tag: Tag, data: &mut *mut (), } pub fn recv_return(reader: &mut T, tag_bytes: &[u8], data: *mut (), - alloc: &Fn(usize) -> Result<*mut (), T::ReadError>) - -> Result<(), T::ReadError> + alloc: &Fn(usize) -> Result<*mut (), Error>) + -> Result<(), Error> where T: Read + ?Sized { let mut it = TagIterator::new(tag_bytes); @@ -91,7 +91,7 @@ pub fn recv_return(reader: &mut T, tag_bytes: &[u8], data: *mut (), } unsafe fn send_value(writer: &mut T, tag: Tag, data: &mut *const ()) - -> Result<(), T::WriteError> + -> Result<(), Error> where T: Write + ?Sized { macro_rules! consume_value { @@ -168,7 +168,7 @@ unsafe fn send_value(writer: &mut T, tag: Tag, data: &mut *const ()) } pub fn send_args(writer: &mut T, service: u32, tag_bytes: &[u8], data: *const *const ()) - -> Result<(), T::WriteError> + -> Result<(), Error> where T: Write + ?Sized { let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes); diff --git a/artiq/firmware/libproto_artiq/session_proto.rs b/artiq/firmware/libproto_artiq/session_proto.rs index 0253c8e8c..5ef1fee20 100644 --- a/artiq/firmware/libproto_artiq/session_proto.rs +++ b/artiq/firmware/libproto_artiq/session_proto.rs @@ -1,8 +1,8 @@ use alloc::{Vec, String}; -use io::{Read, ProtoRead, Write, ProtoWrite, Error, Result}; +use io::{Read, ProtoRead, Write, ProtoWrite, Error}; -fn read_sync(reader: &mut T) -> Result<(), T::ReadError> { +fn read_sync(reader: &mut T) -> Result<(), Error> { let mut sync = [0; 4]; for i in 0.. { sync[i % 4] = reader.read_u8()?; @@ -11,7 +11,7 @@ fn read_sync(reader: &mut T) -> Result<(), T::ReadError> { Ok(()) } -fn write_sync(writer: &mut T) -> Result<(), T::WriteError> { +fn write_sync(writer: &mut T) -> Result<(), Error> { writer.write_all(&[0x5a; 4]) } @@ -41,7 +41,7 @@ pub enum Request { } impl Request { - pub fn read_from(reader: &mut T) -> Result { + pub fn read_from(reader: &mut T) -> Result> { read_sync(reader)?; Ok(match reader.read_u8()? { 3 => Request::SystemInfo, @@ -114,7 +114,7 @@ pub enum Reply<'a> { } impl<'a> Reply<'a> { - pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { + pub fn write_to(&self, writer: &mut T) -> Result<(), Error> { write_sync(writer)?; match *self { Reply::SystemInfo { ident, finished_cleanly } => { diff --git a/artiq/firmware/runtime/analyzer.rs b/artiq/firmware/runtime/analyzer.rs index 8bebf851b..f6842e433 100644 --- a/artiq/firmware/runtime/analyzer.rs +++ b/artiq/firmware/runtime/analyzer.rs @@ -35,7 +35,7 @@ fn disarm() { } } -fn worker(stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { +fn worker(stream: &mut TcpStream) -> Result<(), io::Error<::std::io::Error>> { let data = unsafe { &BUFFER.data[..] }; let overflow_occurred = unsafe { csr::rtio_analyzer::message_encoder_overflow_read() != 0 }; let total_byte_count = unsafe { csr::rtio_analyzer::dma_byte_count_read() }; diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index 610e5be96..ae684511a 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -291,7 +291,7 @@ mod spi { } } -pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> io::Result { +pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result> { match request { #[cfg(has_rtio_core)] &kern::RtioInitRequest => { diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index b23b6bbcc..c6b744982 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -8,7 +8,7 @@ use sched::{TcpListener, TcpStream}; use mgmt_proto::*; use profiler; -fn check_magic(stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { +fn check_magic(stream: &mut TcpStream) -> Result<(), io::Error<::std::io::Error>> { const MAGIC: &'static [u8] = b"ARTIQ management\n"; let mut magic: [u8; 17] = [0; 17]; @@ -20,7 +20,7 @@ fn check_magic(stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { } } -fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { +fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), io::Error<::std::io::Error>> { check_magic(stream)?; info!("new connection from {}", stream.remote_endpoint()); @@ -34,7 +34,7 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { } Request::ClearLog => { - BufferLogger::with(|logger| -> io::Result<(), ::std::io::Error> { + BufferLogger::with(|logger| -> Result<(), io::Error<::std::io::Error>> { let mut buffer = io.until_ok(|| logger.buffer())?; Ok(buffer.clear()) })?; @@ -43,7 +43,7 @@ fn worker(io: &Io, stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { } Request::PullLog => { - BufferLogger::with(|logger| -> io::Result<(), ::std::io::Error> { + BufferLogger::with(|logger| -> Result<(), io::Error<::std::io::Error>> { loop { // Do this *before* acquiring the buffer, since that sets the log level // to OFF. diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index 36fae9430..e19c6b3d2 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -9,7 +9,7 @@ use drtioaux; use moninj_proto::*; -fn check_magic(stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { +fn check_magic(stream: &mut TcpStream) -> Result<(), io::Error<::std::io::Error>> { const MAGIC: &'static [u8] = b"ARTIQ moninj\n"; let mut magic: [u8; 13] = [0; 13]; @@ -159,7 +159,7 @@ fn read_injection_status(channel: u32, probe: u8) -> u8 { 0 } -fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { +fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), io::Error<::std::io::Error>> { let mut watch_list = BTreeMap::new(); let mut next_check = 0; diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index dced8025c..8d987ced9 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -102,7 +102,7 @@ impl<'a> Drop for Session<'a> { } } -fn check_magic(stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { +fn check_magic(stream: &mut TcpStream) -> Result<(), io::Error<::std::io::Error>> { const MAGIC: &'static [u8] = b"ARTIQ coredev\n"; let mut magic: [u8; 14] = [0; 14]; @@ -114,7 +114,7 @@ fn check_magic(stream: &mut TcpStream) -> io::Result<(), ::std::io::Error> { } } -fn host_read(stream: &mut TcpStream) -> io::Result { +fn host_read(stream: &mut TcpStream) -> Result> { let request = host::Request::read_from(stream)?; match &request { &host::Request::LoadKernel(_) => debug!("comm<-host LoadLibrary(...)"), @@ -123,12 +123,12 @@ fn host_read(stream: &mut TcpStream) -> io::Result io::Result<(), ::std::io::Error> { +fn host_write(stream: &mut TcpStream, reply: host::Reply) -> Result<(), io::Error<::std::io::Error>> { debug!("comm->host {:?}", reply); reply.write_to(stream) } -pub fn kern_send(io: &Io, request: &kern::Message) -> io::Result<(), ::std::io::Error> { +pub fn kern_send(io: &Io, request: &kern::Message) -> Result<(), io::Error<::std::io::Error>> { match request { &kern::LoadRequest(_) => debug!("comm->kern LoadRequest(...)"), &kern::DmaRetrieveReply { trace, duration } => { @@ -144,8 +144,8 @@ pub fn kern_send(io: &Io, request: &kern::Message) -> io::Result<(), ::std::io:: Ok(io.until(mailbox::acknowledged)?) } -fn kern_recv_notrace(io: &Io, f: F) -> io::Result - where F: FnOnce(&kern::Message) -> io::Result { +fn kern_recv_notrace(io: &Io, f: F) -> Result> + where F: FnOnce(&kern::Message) -> Result> { io.until(|| mailbox::receive() != 0)?; if !kernel::validate(mailbox::receive()) { let message = format!("invalid kernel CPU pointer 0x{:x}", mailbox::receive()); @@ -171,20 +171,20 @@ fn kern_recv_dotrace(reply: &kern::Message) { } #[inline(always)] -fn kern_recv(io: &Io, f: F) -> io::Result - where F: FnOnce(&kern::Message) -> io::Result { +fn kern_recv(io: &Io, f: F) -> Result> + where F: FnOnce(&kern::Message) -> Result> { kern_recv_notrace(io, |reply| { kern_recv_dotrace(reply); f(reply) }) } -pub fn kern_acknowledge() -> io::Result<(), ::std::io::Error> { +pub fn kern_acknowledge() -> Result<(), io::Error<::std::io::Error>> { mailbox::acknowledge(); Ok(()) } -unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) -> io::Result<(), ::std::io::Error> { +unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) -> Result<(), io::Error<::std::io::Error>> { if session.running() { unexpected!("attempted to load a new kernel while a kernel was running") } @@ -209,7 +209,7 @@ unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) -> io::Resul }) } -fn kern_run(session: &mut Session) -> io::Result<(), ::std::io::Error> { +fn kern_run(session: &mut Session) -> Result<(), io::Error<::std::io::Error>> { if session.kernel_state != KernelState::Loaded { unexpected!("attempted to run a kernel while not in Loaded state") } @@ -221,7 +221,7 @@ fn kern_run(session: &mut Session) -> io::Result<(), ::std::io::Error> { fn process_host_message(io: &Io, stream: &mut TcpStream, - session: &mut Session) -> io::Result<(), ::std::io::Error> { + session: &mut Session) -> Result<(), io::Error<::std::io::Error>> { match host_read(stream)? { host::Request::SystemInfo => { host_write(stream, host::Reply::SystemInfo { @@ -359,7 +359,7 @@ fn process_host_message(io: &Io, } fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, - session: &mut Session) -> io::Result { + session: &mut Session) -> Result> { kern_recv_notrace(io, |request| { match (request, session.kernel_state) { (&kern::LoadReply(_), KernelState::Loaded) | @@ -516,7 +516,7 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, } fn process_kern_queued_rpc(stream: &mut TcpStream, - _session: &mut Session) -> io::Result<(), ::std::io::Error> { + _session: &mut Session) -> Result<(), io::Error<::std::io::Error>> { rpc_queue::dequeue(|slice| { debug!("comm<-kern (async RPC)"); let length = NetworkEndian::read_u32(slice) as usize; @@ -529,7 +529,7 @@ fn process_kern_queued_rpc(stream: &mut TcpStream, fn host_kernel_worker(io: &Io, stream: &mut TcpStream, - congress: &mut Congress) -> io::Result<(), ::std::io::Error> { + congress: &mut Congress) -> Result<(), io::Error<::std::io::Error>> { let mut session = Session::new(congress); loop { @@ -568,7 +568,7 @@ fn host_kernel_worker(io: &Io, fn flash_kernel_worker(io: &Io, congress: &mut Congress, - config_key: &str) -> io::Result<(), ::std::io::Error> { + config_key: &str) -> Result<(), io::Error<::std::io::Error>> { let mut session = Session::new(congress); config::read(config_key, |result| { From 514eab3d399fbedf312806688dae9e4f6507350f Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 15 May 2018 12:47:51 +0000 Subject: [PATCH 0768/2457] Update Rust to 1.26.0. --- artiq/firmware/ksupport/eh.rs | 4 ++-- artiq/firmware/runtime/profiler.rs | 6 +++--- conda/artiq-dev/meta.yaml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/ksupport/eh.rs b/artiq/firmware/ksupport/eh.rs index 6138969a4..5cd220bbc 100644 --- a/artiq/firmware/ksupport/eh.rs +++ b/artiq/firmware/ksupport/eh.rs @@ -398,7 +398,7 @@ static mut INFLIGHT: ExceptionInfo = ExceptionInfo { }; #[export_name="__artiq_raise"] -#[unwind] +#[unwind(allowed)] pub unsafe extern fn raise(exception: *const Exception) -> ! { // Zing! The Exception<'a> to Exception<'static> transmute is not really sound in case // the exception is ever captured. Fortunately, they currently aren't, and we save @@ -416,7 +416,7 @@ pub unsafe extern fn raise(exception: *const Exception) -> ! { } #[export_name="__artiq_reraise"] -#[unwind] +#[unwind(allowed)] pub unsafe extern fn reraise() -> ! { if INFLIGHT.handled { raise(&INFLIGHT.exception.unwrap()) diff --git a/artiq/firmware/runtime/profiler.rs b/artiq/firmware/runtime/profiler.rs index 0e4380f96..e3c47e1a0 100644 --- a/artiq/firmware/runtime/profiler.rs +++ b/artiq/firmware/runtime/profiler.rs @@ -2,16 +2,16 @@ use core::mem; use core::fmt; -use core::nonzero::NonZero; +use core::num::NonZeroUsize; use alloc::Vec; use managed::ManagedMap; #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct Address(NonZero); +pub struct Address(NonZeroUsize); impl Address { pub fn new(raw: usize) -> Option
{ - NonZero::new(raw).map(Address) + NonZeroUsize::new(raw).map(Address) } pub fn as_raw(&self) -> usize { diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 62d283af0..62629e2a2 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -21,7 +21,7 @@ requirements: - binutils-or1k-linux >=2.27 - llvm-or1k 6.0.0 - llvmlite-artiq 0.23.0.dev py35_4 - - rust-core-or1k 1.25.0 20 + - rust-core-or1k 1.26.0 21 - openocd 0.10.0 6 - lit - outputcheck From 479cb9a857987d6daff74dbc7391dc3f19ae91b2 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 15 May 2018 13:27:23 +0000 Subject: [PATCH 0769/2457] firmware: use dedicated error types for every protocol and thread. Good riddance to io::Error::Unrecognized. --- artiq/firmware/Cargo.lock | 6 + artiq/firmware/libio/lib.rs | 4 +- artiq/firmware/libio/proto.rs | 15 +- artiq/firmware/libproto_artiq/Cargo.toml | 4 +- .../firmware/libproto_artiq/analyzer_proto.rs | 6 +- .../firmware/libproto_artiq/drtioaux_proto.rs | 26 ++- artiq/firmware/libproto_artiq/lib.rs | 5 + artiq/firmware/libproto_artiq/mgmt_proto.rs | 53 ++++- artiq/firmware/libproto_artiq/moninj_proto.rs | 49 +++- artiq/firmware/libproto_artiq/rpc_proto.rs | 30 +-- .../firmware/libproto_artiq/session_proto.rs | 69 +++++- artiq/firmware/libstd_artiq/Cargo.toml | 3 + artiq/firmware/libstd_artiq/lib.rs | 3 + artiq/firmware/runtime/Cargo.toml | 2 + artiq/firmware/runtime/kern_hwreq.rs | 5 +- artiq/firmware/runtime/main.rs | 3 + artiq/firmware/runtime/mgmt.rs | 26 +-- artiq/firmware/runtime/moninj.rs | 20 +- artiq/firmware/runtime/session.rs | 210 +++++++++--------- artiq/firmware/runtime/watchdog.rs | 12 +- 20 files changed, 355 insertions(+), 196 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 673c6e9e0..7cdd463c4 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -208,6 +208,7 @@ dependencies = [ "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "io 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "std_artiq 0.0.0", ] [[package]] @@ -226,6 +227,8 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)", "io 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -270,6 +273,9 @@ dependencies = [ [[package]] name = "std_artiq" version = "0.0.0" +dependencies = [ + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "syn" diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs index b8bc09d7b..b10c41345 100644 --- a/artiq/firmware/libio/lib.rs +++ b/artiq/firmware/libio/lib.rs @@ -18,13 +18,13 @@ mod proto; pub use cursor::Cursor; #[cfg(feature = "byteorder")] pub use proto::{ProtoRead, ProtoWrite}; +#[cfg(all(feature = "byteorder", feature = "alloc"))] +pub use proto::ReadStringError; #[derive(Fail, Debug, Clone, PartialEq)] pub enum Error { #[fail(display = "unexpected end of stream")] UnexpectedEnd, - #[fail(display = "unrecognized input")] - Unrecognized, #[fail(display = "{}", _0)] Other(#[cause] T) } diff --git a/artiq/firmware/libio/proto.rs b/artiq/firmware/libio/proto.rs index 22a8deb3e..3df4a04aa 100644 --- a/artiq/firmware/libio/proto.rs +++ b/artiq/firmware/libio/proto.rs @@ -8,22 +8,11 @@ use ::{Read, Write, Error as IoError}; #[derive(Fail, Debug, Clone, PartialEq)] pub enum ReadStringError { #[fail(display = "invalid UTF-8: {}", _0)] - Utf8Error(Utf8Error), + Utf8(Utf8Error), #[fail(display = "{}", _0)] Other(T) } -#[cfg(feature = "alloc")] -impl From>> for IoError -{ - fn from(value: ReadStringError>) -> IoError { - match value { - ReadStringError::Utf8Error(_) => IoError::Unrecognized, - ReadStringError::Other(err) => err - } - } -} - pub trait ProtoRead { type ReadError; @@ -75,7 +64,7 @@ pub trait ProtoRead { #[inline] fn read_string(&mut self) -> Result<::alloc::String, ReadStringError> { let bytes = self.read_bytes().map_err(ReadStringError::Other)?; - String::from_utf8(bytes).map_err(|err| ReadStringError::Utf8Error(err.utf8_error())) + String::from_utf8(bytes).map_err(|err| ReadStringError::Utf8(err.utf8_error())) } } diff --git a/artiq/firmware/libproto_artiq/Cargo.toml b/artiq/firmware/libproto_artiq/Cargo.toml index 92d5e0d0f..829d7f693 100644 --- a/artiq/firmware/libproto_artiq/Cargo.toml +++ b/artiq/firmware/libproto_artiq/Cargo.toml @@ -15,6 +15,8 @@ cslice = { version = "0.3" } log = { version = "0.4", default-features = false, optional = true } io = { path = "../libio", features = ["byteorder"] } dyld = { path = "../libdyld" } +# TODO: remove +std_artiq = { path = "../libstd_artiq", optional = true } [features] -alloc = ["io/alloc"] +alloc = ["io/alloc", "std_artiq"] diff --git a/artiq/firmware/libproto_artiq/analyzer_proto.rs b/artiq/firmware/libproto_artiq/analyzer_proto.rs index c74632ec2..a35f8de39 100644 --- a/artiq/firmware/libproto_artiq/analyzer_proto.rs +++ b/artiq/firmware/libproto_artiq/analyzer_proto.rs @@ -1,4 +1,4 @@ -use io::{Write, ProtoWrite, Error}; +use io::{Write, ProtoWrite, Error as IoError}; #[derive(Debug)] pub struct Header { @@ -10,7 +10,9 @@ pub struct Header { } impl Header { - pub fn write_to(&self, writer: &mut T) -> Result<(), Error> { + pub fn write_to(&self, writer: &mut W) -> Result<(), IoError> + where W: Write + ?Sized + { writer.write_u32(self.sent_bytes)?; writer.write_u64(self.total_byte_count)?; writer.write_u8(self.overflow_occurred as u8)?; diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 0aae19617..ae103f44b 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -1,4 +1,18 @@ -use io::{Read, ProtoRead, Write, ProtoWrite, Error}; +use io::{Read, ProtoRead, Write, ProtoWrite, Error as IoError}; + +#[derive(Fail, Debug)] +pub enum Error { + #[fail(display = "unknown packet {:#02x}", _0)] + UnknownPacket(u8), + #[fail(display = "{}", _0)] + Io(#[cause] IoError) +} + +impl From> for Error { + fn from(value: IoError) -> Error { + Error::Io(value) + } +} #[derive(Debug)] pub enum Packet { @@ -36,7 +50,9 @@ pub enum Packet { } impl Packet { - pub fn read_from(reader: &mut T) -> Result> { + pub fn read_from(reader: &mut R) -> Result> + where R: Read + ?Sized + { Ok(match reader.read_u8()? { 0x00 => Packet::EchoRequest, 0x01 => Packet::EchoReply, @@ -129,11 +145,13 @@ impl Packet { succeeded: reader.read_bool()? }, - _ => return Err(Error::Unrecognized) + ty => return Err(Error::UnknownPacket(ty)) }) } - pub fn write_to(&self, writer: &mut T) -> Result<(), Error> { + pub fn write_to(&self, writer: &mut W) -> Result<(), IoError> + where W: Write + ?Sized + { match *self { Packet::EchoRequest => writer.write_u8(0x00)?, diff --git a/artiq/firmware/libproto_artiq/lib.rs b/artiq/firmware/libproto_artiq/lib.rs index 36e776d0f..1290f559e 100644 --- a/artiq/firmware/libproto_artiq/lib.rs +++ b/artiq/firmware/libproto_artiq/lib.rs @@ -1,6 +1,9 @@ #![no_std] #![cfg_attr(feature = "alloc", feature(alloc))] +extern crate failure; +#[macro_use] +extern crate failure_derive; #[cfg(feature = "alloc")] extern crate alloc; extern crate cslice; @@ -8,6 +11,8 @@ extern crate cslice; #[macro_use] extern crate log; +#[cfg(feature = "std_artiq")] +extern crate std_artiq; extern crate io; extern crate dyld; diff --git a/artiq/firmware/libproto_artiq/mgmt_proto.rs b/artiq/firmware/libproto_artiq/mgmt_proto.rs index 3bb33e65d..c137623d0 100644 --- a/artiq/firmware/libproto_artiq/mgmt_proto.rs +++ b/artiq/firmware/libproto_artiq/mgmt_proto.rs @@ -2,7 +2,46 @@ use alloc::Vec; #[cfg(feature = "log")] use log; -use io::{Read, ProtoRead, Write, ProtoWrite, Error}; +use io::{Read, ProtoRead, Write, ProtoWrite, Error as IoError}; + +#[derive(Fail, Debug)] +pub enum Error { + #[fail(display = "incorrect magic")] + WrongMagic, + #[fail(display = "unknown packet {:#02x}", _0)] + UnknownPacket(u8), + #[fail(display = "unknown log level {}", _0)] + UnknownLogLevel(u8), + #[fail(display = "{}", _0)] + Io(#[cause] IoError) +} + +impl From> for Error { + fn from(value: IoError) -> Error { + Error::Io(value) + } +} + +#[cfg(feature = "std_artiq")] +impl From<::std_artiq::io::Error> for Error<::std_artiq::io::Error> { + fn from(value: ::std_artiq::io::Error) -> Error<::std_artiq::io::Error> { + Error::Io(IoError::Other(value)) + } +} + +pub fn read_magic(reader: &mut R) -> Result<(), Error> + where R: Read + ?Sized +{ + const MAGIC: &'static [u8] = b"ARTIQ management\n"; + + let mut magic: [u8; 17] = [0; 17]; + reader.read_exact(&mut magic)?; + if magic != MAGIC { + Err(Error::WrongMagic) + } else { + Ok(()) + } +} #[derive(Debug)] pub enum Request { @@ -40,7 +79,9 @@ pub enum Reply<'a> { } impl Request { - pub fn read_from(reader: &mut T) -> Result> { + pub fn read_from(reader: &mut R) -> Result> + where R: Read + ?Sized + { #[cfg(feature = "log")] fn read_log_level_filter(reader: &mut T) -> Result> { @@ -51,7 +92,7 @@ impl Request { 3 => log::LevelFilter::Info, 4 => log::LevelFilter::Debug, 5 => log::LevelFilter::Trace, - _ => return Err(Error::Unrecognized) + lv => return Err(Error::UnknownLogLevel(lv)) }) } @@ -73,13 +114,15 @@ impl Request { 4 => Request::Hotswap(reader.read_bytes()?), 5 => Request::Reboot, 8 => Request::DebugAllocator, - _ => return Err(Error::Unrecognized) + ty => return Err(Error::UnknownPacket(ty)) }) } } impl<'a> Reply<'a> { - pub fn write_to(&self, writer: &mut T) -> Result<(), Error> { + pub fn write_to(&self, writer: &mut W) -> Result<(), IoError> + where W: Write + ?Sized + { match *self { Reply::Success => { writer.write_u8(1)?; diff --git a/artiq/firmware/libproto_artiq/moninj_proto.rs b/artiq/firmware/libproto_artiq/moninj_proto.rs index 285ce9f09..ee60d2eb5 100644 --- a/artiq/firmware/libproto_artiq/moninj_proto.rs +++ b/artiq/firmware/libproto_artiq/moninj_proto.rs @@ -1,4 +1,41 @@ -use io::{Read, ProtoRead, Write, ProtoWrite, Error}; +use io::{Read, ProtoRead, Write, ProtoWrite, Error as IoError}; + +#[derive(Fail, Debug)] +pub enum Error { + #[fail(display = "incorrect magic")] + WrongMagic, + #[fail(display = "unknown packet {:#02x}", _0)] + UnknownPacket(u8), + #[fail(display = "{}", _0)] + Io(#[cause] IoError) +} + +impl From> for Error { + fn from(value: IoError) -> Error { + Error::Io(value) + } +} + +#[cfg(feature = "std_artiq")] +impl From<::std_artiq::io::Error> for Error<::std_artiq::io::Error> { + fn from(value: ::std_artiq::io::Error) -> Error<::std_artiq::io::Error> { + Error::Io(IoError::Other(value)) + } +} + +pub fn read_magic(reader: &mut R) -> Result<(), Error> + where R: Read + ?Sized +{ + const MAGIC: &'static [u8] = b"ARTIQ moninj\n"; + + let mut magic: [u8; 13] = [0; 13]; + reader.read_exact(&mut magic)?; + if magic != MAGIC { + Err(Error::WrongMagic) + } else { + Ok(()) + } +} #[derive(Debug)] pub enum HostMessage { @@ -14,7 +51,9 @@ pub enum DeviceMessage { } impl HostMessage { - pub fn read_from(reader: &mut T) -> Result> { + pub fn read_from(reader: &mut R) -> Result> + where R: Read + ?Sized + { Ok(match reader.read_u8()? { 0 => HostMessage::Monitor { enable: if reader.read_u8()? == 0 { false } else { true }, @@ -30,13 +69,15 @@ impl HostMessage { channel: reader.read_u32()?, overrd: reader.read_u8()? }, - _ => return Err(Error::Unrecognized) + ty => return Err(Error::UnknownPacket(ty)) }) } } impl DeviceMessage { - pub fn write_to(&self, writer: &mut T) -> Result<(), Error> { + pub fn write_to(&self, writer: &mut W) -> Result<(), IoError> + where W: Write + ?Sized + { match *self { DeviceMessage::MonitorStatus { channel, probe, value } => { writer.write_u8(0)?; diff --git a/artiq/firmware/libproto_artiq/rpc_proto.rs b/artiq/firmware/libproto_artiq/rpc_proto.rs index f5f8581c1..6f9fc2042 100644 --- a/artiq/firmware/libproto_artiq/rpc_proto.rs +++ b/artiq/firmware/libproto_artiq/rpc_proto.rs @@ -4,10 +4,11 @@ use cslice::{CSlice, CMutSlice}; use io::{ProtoRead, Read, Write, ProtoWrite, Error}; use self::tag::{Tag, TagIterator, split_tag}; -unsafe fn recv_value(reader: &mut T, tag: Tag, data: &mut *mut (), - alloc: &Fn(usize) -> Result<*mut (), Error>) - -> Result<(), Error> - where T: Read + ?Sized +unsafe fn recv_value(reader: &mut R, tag: Tag, data: &mut *mut (), + alloc: &Fn(usize) -> Result<*mut (), E>) + -> Result<(), E> + where R: Read + ?Sized, + E: From> { macro_rules! consume_value { ($ty:ty, |$ptr:ident| $map:expr) => ({ @@ -74,10 +75,11 @@ unsafe fn recv_value(reader: &mut T, tag: Tag, data: &mut *mut (), } } -pub fn recv_return(reader: &mut T, tag_bytes: &[u8], data: *mut (), - alloc: &Fn(usize) -> Result<*mut (), Error>) - -> Result<(), Error> - where T: Read + ?Sized +pub fn recv_return(reader: &mut R, tag_bytes: &[u8], data: *mut (), + alloc: &Fn(usize) -> Result<*mut (), E>) + -> Result<(), E> + where R: Read + ?Sized, + E: From> { let mut it = TagIterator::new(tag_bytes); #[cfg(feature = "log")] @@ -90,9 +92,9 @@ pub fn recv_return(reader: &mut T, tag_bytes: &[u8], data: *mut (), Ok(()) } -unsafe fn send_value(writer: &mut T, tag: Tag, data: &mut *const ()) - -> Result<(), Error> - where T: Write + ?Sized +unsafe fn send_value(writer: &mut W, tag: Tag, data: &mut *const ()) + -> Result<(), Error> + where W: Write + ?Sized { macro_rules! consume_value { ($ty:ty, |$ptr:ident| $map:expr) => ({ @@ -167,9 +169,9 @@ unsafe fn send_value(writer: &mut T, tag: Tag, data: &mut *const ()) } } -pub fn send_args(writer: &mut T, service: u32, tag_bytes: &[u8], data: *const *const ()) - -> Result<(), Error> - where T: Write + ?Sized +pub fn send_args(writer: &mut W, service: u32, tag_bytes: &[u8], data: *const *const ()) + -> Result<(), Error> + where W: Write + ?Sized { let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes); diff --git a/artiq/firmware/libproto_artiq/session_proto.rs b/artiq/firmware/libproto_artiq/session_proto.rs index 5ef1fee20..d5816a174 100644 --- a/artiq/firmware/libproto_artiq/session_proto.rs +++ b/artiq/firmware/libproto_artiq/session_proto.rs @@ -1,8 +1,59 @@ +use core::str::Utf8Error; use alloc::{Vec, String}; -use io::{Read, ProtoRead, Write, ProtoWrite, Error}; +use io::{Read, ProtoRead, Write, ProtoWrite, Error as IoError, ReadStringError}; -fn read_sync(reader: &mut T) -> Result<(), Error> { +#[derive(Fail, Debug)] +pub enum Error { + #[fail(display = "incorrect magic")] + WrongMagic, + #[fail(display = "unknown packet {:#02x}", _0)] + UnknownPacket(u8), + #[fail(display = "invalid UTF-8: {}", _0)] + Utf8(Utf8Error), + #[fail(display = "{}", _0)] + Io(#[cause] IoError) +} + +impl From> for Error { + fn from(value: IoError) -> Error { + Error::Io(value) + } +} + +impl From>> for Error { + fn from(value: ReadStringError>) -> Error { + match value { + ReadStringError::Utf8(err) => Error::Utf8(err), + ReadStringError::Other(err) => Error::Io(err) + } + } +} + +#[cfg(feature = "std_artiq")] +impl From<::std_artiq::io::Error> for Error<::std_artiq::io::Error> { + fn from(value: ::std_artiq::io::Error) -> Error<::std_artiq::io::Error> { + Error::Io(IoError::Other(value)) + } +} + +pub fn read_magic(reader: &mut R) -> Result<(), Error> + where R: Read + ?Sized +{ + const MAGIC: &'static [u8] = b"ARTIQ coredev\n"; + + let mut magic: [u8; 14] = [0; 14]; + reader.read_exact(&mut magic)?; + if magic != MAGIC { + Err(Error::WrongMagic) + } else { + Ok(()) + } +} + +fn read_sync(reader: &mut R) -> Result<(), IoError> + where R: Read + ?Sized +{ let mut sync = [0; 4]; for i in 0.. { sync[i % 4] = reader.read_u8()?; @@ -11,7 +62,9 @@ fn read_sync(reader: &mut T) -> Result<(), Error Ok(()) } -fn write_sync(writer: &mut T) -> Result<(), Error> { +fn write_sync(writer: &mut W) -> Result<(), IoError> + where W: Write + ?Sized +{ writer.write_all(&[0x5a; 4]) } @@ -41,7 +94,9 @@ pub enum Request { } impl Request { - pub fn read_from(reader: &mut T) -> Result> { + pub fn read_from(reader: &mut R) -> Result> + where R: Read + ?Sized + { read_sync(reader)?; Ok(match reader.read_u8()? { 3 => Request::SystemInfo, @@ -73,7 +128,7 @@ impl Request { 12 => Request::FlashRemove { key: reader.read_string()? }, - _ => return Err(Error::Unrecognized) + ty => return Err(Error::UnknownPacket(ty)) }) } } @@ -114,7 +169,9 @@ pub enum Reply<'a> { } impl<'a> Reply<'a> { - pub fn write_to(&self, writer: &mut T) -> Result<(), Error> { + pub fn write_to(&self, writer: &mut W) -> Result<(), IoError> + where W: Write + ?Sized + { write_sync(writer)?; match *self { Reply::SystemInfo { ident, finished_cleanly } => { diff --git a/artiq/firmware/libstd_artiq/Cargo.toml b/artiq/firmware/libstd_artiq/Cargo.toml index bc7034f51..52ab62954 100644 --- a/artiq/firmware/libstd_artiq/Cargo.toml +++ b/artiq/firmware/libstd_artiq/Cargo.toml @@ -10,3 +10,6 @@ path = "lib.rs" [features] alloc = [] io_error_alloc = [] + +[dependencies] +failure = { version = "0.1", default-features = false } diff --git a/artiq/firmware/libstd_artiq/lib.rs b/artiq/firmware/libstd_artiq/lib.rs index f0c7b8c5a..285d985e5 100644 --- a/artiq/firmware/libstd_artiq/lib.rs +++ b/artiq/firmware/libstd_artiq/lib.rs @@ -8,6 +8,7 @@ extern crate std_unicode; #[macro_use] #[macro_reexport(vec, format)] extern crate alloc; +extern crate failure; pub use core::{any, cell, clone, cmp, convert, default, hash, iter, marker, mem, num, ops, option, ptr, result, sync, @@ -38,3 +39,5 @@ impl FakeBox { val } } + +impl failure::Fail for error::Error + Send + Sync {} diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 3f05a2cb2..70875e37a 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -14,6 +14,8 @@ build_misoc = { path = "../libbuild_misoc" } build_artiq = { path = "../libbuild_artiq" } [dependencies] +failure = { version = "0.1", default-features = false } +failure_derive = { version = "0.1", default-features = false } byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } log = { version = "0.4", default-features = false } diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index ae684511a..c2bc6a651 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -1,7 +1,6 @@ -use io; use kernel_proto as kern; use sched::Io; -use session::{kern_acknowledge, kern_send}; +use session::{kern_acknowledge, kern_send, Error}; #[cfg(has_rtio_core)] use rtio_mgt; @@ -291,7 +290,7 @@ mod spi { } } -pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result> { +pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result> { match request { #[cfg(has_rtio_core)] &kern::RtioInitRequest => { diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 7a7fe3c98..e43d11be1 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -2,6 +2,9 @@ #![feature(lang_items, alloc, global_allocator, try_from, nonzero, nll)] extern crate alloc; +extern crate failure; +#[macro_use] +extern crate failure_derive; extern crate cslice; #[macro_use] extern crate log; diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index c6b744982..6cfe48017 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -1,27 +1,15 @@ use log::{self, LevelFilter}; -use io::{self, Read, Write, ProtoWrite}; +use io::{Write, ProtoWrite, Error as IoError}; use board_misoc::boot; use logger_artiq::BufferLogger; +use mgmt_proto::*; use sched::Io; use sched::{TcpListener, TcpStream}; -use mgmt_proto::*; use profiler; -fn check_magic(stream: &mut TcpStream) -> Result<(), io::Error<::std::io::Error>> { - const MAGIC: &'static [u8] = b"ARTIQ management\n"; - - let mut magic: [u8; 17] = [0; 17]; - stream.read_exact(&mut magic)?; - if magic != MAGIC { - Err(io::Error::Unrecognized) - } else { - Ok(()) - } -} - -fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), io::Error<::std::io::Error>> { - check_magic(stream)?; +fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error<::std::io::Error>> { + read_magic(stream)?; info!("new connection from {}", stream.remote_endpoint()); loop { @@ -34,7 +22,7 @@ fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), io::Error<::std::io::Er } Request::ClearLog => { - BufferLogger::with(|logger| -> Result<(), io::Error<::std::io::Error>> { + BufferLogger::with(|logger| -> Result<(), Error<::std::io::Error>> { let mut buffer = io.until_ok(|| logger.buffer())?; Ok(buffer.clear()) })?; @@ -43,7 +31,7 @@ fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), io::Error<::std::io::Er } Request::PullLog => { - BufferLogger::with(|logger| -> Result<(), io::Error<::std::io::Error>> { + BufferLogger::with(|logger| -> Result<(), Error<::std::io::Error>> { loop { // Do this *before* acquiring the buffer, since that sets the log level // to OFF. @@ -165,7 +153,7 @@ pub fn thread(io: Io) { let mut stream = TcpStream::from_handle(&io, stream); match worker(&io, &mut stream) { Ok(()) => (), - Err(io::Error::UnexpectedEnd) => (), + Err(Error::Io(IoError::UnexpectedEnd)) => (), Err(err) => error!("aborted: {}", err) } }); diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index e19c6b3d2..9297bd11b 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -1,26 +1,12 @@ use alloc::btree_map::BTreeMap; -use io::{self, Read}; +use moninj_proto::*; use sched::Io; use sched::{TcpListener, TcpStream}; use board_misoc::{clock, csr}; #[cfg(has_drtio)] use drtioaux; -use moninj_proto::*; - -fn check_magic(stream: &mut TcpStream) -> Result<(), io::Error<::std::io::Error>> { - const MAGIC: &'static [u8] = b"ARTIQ moninj\n"; - - let mut magic: [u8; 13] = [0; 13]; - stream.read_exact(&mut magic)?; - if magic != MAGIC { - Err(io::Error::Unrecognized) - } else { - Ok(()) - } -} - #[cfg(has_rtio_moninj)] fn read_probe_local(channel: u16, probe: u8) -> u32 { unsafe { @@ -159,11 +145,11 @@ fn read_injection_status(channel: u32, probe: u8) -> u8 { 0 } -fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), io::Error<::std::io::Error>> { +fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error<::std::io::Error>> { let mut watch_list = BTreeMap::new(); let mut next_check = 0; - check_magic(&mut stream)?; + read_magic(&mut stream)?; info!("new connection from {}", stream.remote_endpoint()); loop { diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 8d987ced9..445b0ea5d 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -2,7 +2,7 @@ use core::{mem, str, cell::{Cell, RefCell}, fmt::Write as FmtWrite}; use alloc::{Vec, String}; use byteorder::{ByteOrder, NetworkEndian}; -use io::{self, Read, Write}; +use io::{self, Read, Write, Error as IoError}; use board_misoc::{ident, cache, config}; use {mailbox, rpc_queue, kernel}; use urc::Urc; @@ -19,17 +19,46 @@ use rpc_proto as rpc; use session_proto as host; use kernel_proto as kern; -macro_rules! unexpected { - ($($arg:tt)*) => { - { - error!($($arg)*); - return Err(io::Error::Unrecognized) - } - }; +#[derive(Fail, Debug)] +pub enum Error { + #[fail(display = "cannot load kernel: {}", _0)] + Load(String), + #[fail(display = "kernel not found")] + KernelNotFound, + #[fail(display = "invalid kernel CPU pointer: {:#08x}", _0)] + InvalidPointer(usize), + #[fail(display = "RTIO clock failure")] + ClockFailure, + #[fail(display = "watchdog {} expired", _0)] + WatchdogExpired(usize), + #[fail(display = "out of watchdogs")] + OutOfWatchdogs, + #[fail(display = "protocol error: {}", _0)] + Protocol(#[cause] host::Error), + #[fail(display = "{}", _0)] + Unexpected(String), } -fn io_error(msg: &str) -> io::Error<::std::io::Error> { - io::Error::Other(::std::io::Error::new(::std::io::ErrorKind::Other, msg)) +impl From> for Error { + fn from(value: host::Error) -> Error { + Error::Protocol(value) + } +} + +impl From<::std::io::Error> for Error<::std::io::Error> { + fn from(value: ::std::io::Error) -> Error<::std::io::Error> { + Error::Protocol(host::Error::Io(io::Error::Other(value))) + } +} + +impl From> for Error<::std::io::Error> { + fn from(value: io::Error<::std::io::Error>) -> Error<::std::io::Error> { + Error::Protocol(host::Error::Io(value)) + } +} + +macro_rules! unexpected { + ($($arg:tt)*) => (return Err(Error::Unexpected(format!($($arg)*)))); } // Persistent state @@ -102,20 +131,10 @@ impl<'a> Drop for Session<'a> { } } -fn check_magic(stream: &mut TcpStream) -> Result<(), io::Error<::std::io::Error>> { - const MAGIC: &'static [u8] = b"ARTIQ coredev\n"; - - let mut magic: [u8; 14] = [0; 14]; - stream.read_exact(&mut magic)?; - if magic != MAGIC { - Err(io::Error::Unrecognized) - } else { - Ok(()) - } -} - -fn host_read(stream: &mut TcpStream) -> Result> { - let request = host::Request::read_from(stream)?; +fn host_read(reader: &mut R) -> Result> + where R: Read + ?Sized +{ + let request = host::Request::read_from(reader)?; match &request { &host::Request::LoadKernel(_) => debug!("comm<-host LoadLibrary(...)"), _ => debug!("comm<-host {:?}", request) @@ -123,12 +142,14 @@ fn host_read(stream: &mut TcpStream) -> Result Result<(), io::Error<::std::io::Error>> { +fn host_write(writer: &mut W, reply: host::Reply) -> Result<(), IoError> + where W: Write + ?Sized +{ debug!("comm->host {:?}", reply); - reply.write_to(stream) + reply.write_to(writer) } -pub fn kern_send(io: &Io, request: &kern::Message) -> Result<(), io::Error<::std::io::Error>> { +pub fn kern_send(io: &Io, request: &kern::Message) -> Result<(), Error<::std::io::Error>> { match request { &kern::LoadRequest(_) => debug!("comm->kern LoadRequest(...)"), &kern::DmaRetrieveReply { trace, duration } => { @@ -144,12 +165,11 @@ pub fn kern_send(io: &Io, request: &kern::Message) -> Result<(), io::Error<::std Ok(io.until(mailbox::acknowledged)?) } -fn kern_recv_notrace(io: &Io, f: F) -> Result> - where F: FnOnce(&kern::Message) -> Result> { +fn kern_recv_notrace(io: &Io, f: F) -> Result> + where F: FnOnce(&kern::Message) -> Result> { io.until(|| mailbox::receive() != 0)?; if !kernel::validate(mailbox::receive()) { - let message = format!("invalid kernel CPU pointer 0x{:x}", mailbox::receive()); - return Err(io::Error::Other(::std::io::Error::new(::std::io::ErrorKind::InvalidData, message))) + return Err(Error::InvalidPointer(mailbox::receive())) } f(unsafe { &*(mailbox::receive() as *const kern::Message) }) @@ -171,20 +191,21 @@ fn kern_recv_dotrace(reply: &kern::Message) { } #[inline(always)] -fn kern_recv(io: &Io, f: F) -> Result> - where F: FnOnce(&kern::Message) -> Result> { +fn kern_recv(io: &Io, f: F) -> Result> + where F: FnOnce(&kern::Message) -> Result> { kern_recv_notrace(io, |reply| { kern_recv_dotrace(reply); f(reply) }) } -pub fn kern_acknowledge() -> Result<(), io::Error<::std::io::Error>> { +pub fn kern_acknowledge() -> Result<(), Error<::std::io::Error>> { mailbox::acknowledge(); Ok(()) } -unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) -> Result<(), io::Error<::std::io::Error>> { +unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) + -> Result<(), Error<::std::io::Error>> { if session.running() { unexpected!("attempted to load a new kernel while a kernel was running") } @@ -194,14 +215,13 @@ unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) -> Result<() kern_send(io, &kern::LoadRequest(&library))?; kern_recv(io, |reply| { match reply { - &kern::LoadReply(Ok(())) => { + kern::LoadReply(Ok(())) => { session.kernel_state = KernelState::Loaded; Ok(()) } - &kern::LoadReply(Err(ref error)) => { + kern::LoadReply(Err(error)) => { kernel::stop(); - Err(io::Error::Other(::std::io::Error::new(::std::io::ErrorKind::Other, - format!("cannot load kernel: {}", error)))) + Err(Error::Load(format!("{}", error))) } other => unexpected!("unexpected reply from kernel CPU: {:?}", other) @@ -209,7 +229,7 @@ unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) -> Result<() }) } -fn kern_run(session: &mut Session) -> Result<(), io::Error<::std::io::Error>> { +fn kern_run(session: &mut Session) -> Result<(), Error<::std::io::Error>> { if session.kernel_state != KernelState::Loaded { unexpected!("attempted to run a kernel while not in Loaded state") } @@ -221,15 +241,14 @@ fn kern_run(session: &mut Session) -> Result<(), io::Error<::std::io::Error>> { fn process_host_message(io: &Io, stream: &mut TcpStream, - session: &mut Session) -> Result<(), io::Error<::std::io::Error>> { + session: &mut Session) -> Result<(), Error<::std::io::Error>> { match host_read(stream)? { host::Request::SystemInfo => { host_write(stream, host::Reply::SystemInfo { ident: ident::read(&mut [0; 64]), finished_cleanly: session.congress.finished_cleanly.get() })?; - session.congress.finished_cleanly.set(true); - Ok(()) + session.congress.finished_cleanly.set(true) } // artiq_coreconfig @@ -239,29 +258,26 @@ fn process_host_message(io: &Io, Ok(value) => host_write(stream, host::Reply::FlashRead(&value)), Err(_) => host_write(stream, host::Reply::FlashError) } - }) + })?; } - host::Request::FlashWrite { ref key, ref value } => { match config::write(key, value) { Ok(_) => host_write(stream, host::Reply::FlashOk), Err(_) => host_write(stream, host::Reply::FlashError) - } + }?; } - host::Request::FlashRemove { ref key } => { match config::remove(key) { Ok(()) => host_write(stream, host::Reply::FlashOk), Err(_) => host_write(stream, host::Reply::FlashError), - } + }?; } - host::Request::FlashErase => { match config::erase() { Ok(()) => host_write(stream, host::Reply::FlashOk), Err(_) => host_write(stream, host::Reply::FlashError), - } + }?; } // artiq_run/artiq_master @@ -273,9 +289,9 @@ fn process_host_message(io: &Io, #[cfg(has_rtio_core)] { if rtio_mgt::crg::switch_clock(clk) { - host_write(stream, host::Reply::ClockSwitchCompleted) + host_write(stream, host::Reply::ClockSwitchCompleted)?; } else { - host_write(stream, host::Reply::ClockSwitchFailed) + host_write(stream, host::Reply::ClockSwitchFailed)?; } } @@ -285,19 +301,18 @@ fn process_host_message(io: &Io, host::Request::LoadKernel(kernel) => match unsafe { kern_load(io, session, &kernel) } { - Ok(()) => host_write(stream, host::Reply::LoadCompleted), + Ok(()) => host_write(stream, host::Reply::LoadCompleted)?, Err(error) => { let mut description = String::new(); write!(&mut description, "{}", error).unwrap(); host_write(stream, host::Reply::LoadFailed(&description))?; - kern_acknowledge() + kern_acknowledge()?; } }, - host::Request::RunKernel => match kern_run(session) { - Ok(()) => Ok(()), - Err(_) => host_write(stream, host::Reply::KernelStartupFailed) + Ok(()) => (), + Err(_) => host_write(stream, host::Reply::KernelStartupFailed)? }, host::Request::RpcReply { tag } => { @@ -311,7 +326,7 @@ fn process_host_message(io: &Io, other => unexpected!("unexpected reply from kernel CPU: {:?}", other) } })?; - rpc::recv_return(stream, &tag, slot, &|size| { + rpc::recv_return(stream, &tag, slot, &|size| -> Result<_, Error<::std::io::Error>> { kern_send(io, &kern::RpcRecvReply(Ok(size)))?; Ok(kern_recv(io, |reply| { match reply { @@ -322,8 +337,7 @@ fn process_host_message(io: &Io, })?; kern_send(io, &kern::RpcRecvReply(Ok(0)))?; - session.kernel_state = KernelState::Running; - Ok(()) + session.kernel_state = KernelState::Running } host::Request::RpcException { @@ -352,14 +366,15 @@ fn process_host_message(io: &Io, }; kern_send(io, &kern::RpcRecvReply(Err(exn)))?; - session.kernel_state = KernelState::Running; - Ok(()) + session.kernel_state = KernelState::Running } } + + Ok(()) } fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, - session: &mut Session) -> Result> { + session: &mut Session) -> Result> { kern_recv_notrace(io, |request| { match (request, session.kernel_state) { (&kern::LoadReply(_), KernelState::Loaded) | @@ -383,8 +398,9 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, match request { &kern::Log(args) => { use std::fmt::Write; - session.log_buffer.write_fmt(args) - .map_err(|_| io_error("cannot append to session log buffer"))?; + session.log_buffer + .write_fmt(args) + .unwrap_or_else(|_| warn!("cannot append to session log buffer")); session.flush_log_buffer(); kern_acknowledge() } @@ -430,11 +446,9 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, } &kern::WatchdogSetRequest { ms } => { - let id = session.watchdog_set.set_ms(ms) - .map_err(|()| io_error("out of watchdogs"))?; + let id = session.watchdog_set.set_ms(ms).map_err(|()| Error::OutOfWatchdogs)?; kern_send(io, &kern::WatchdogSetReply { id: id }) } - &kern::WatchdogClear { id } => { session.watchdog_set.clear(id); kern_acknowledge() @@ -476,10 +490,9 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, match stream { None => return Ok(true), Some(ref mut stream) => - host_write(stream, host::Reply::KernelFinished) + host_write(stream, host::Reply::KernelFinished).map_err(|e| e.into()) } } - &kern::RunException { exception: kern::Exception { name, message, param, file, line, column, function }, backtrace @@ -505,7 +518,7 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, column: column, function: function, backtrace: backtrace - }) + }).map_err(|e| e.into()) } } } @@ -516,7 +529,7 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, } fn process_kern_queued_rpc(stream: &mut TcpStream, - _session: &mut Session) -> Result<(), io::Error<::std::io::Error>> { + _session: &mut Session) -> Result<(), Error<::std::io::Error>> { rpc_queue::dequeue(|slice| { debug!("comm<-kern (async RPC)"); let length = NetworkEndian::read_u32(slice) as usize; @@ -529,7 +542,7 @@ fn process_kern_queued_rpc(stream: &mut TcpStream, fn host_kernel_worker(io: &Io, stream: &mut TcpStream, - congress: &mut Congress) -> Result<(), io::Error<::std::io::Error>> { + congress: &mut Congress) -> Result<(), Error<::std::io::Error>> { let mut session = Session::new(congress); loop { @@ -548,16 +561,16 @@ fn host_kernel_worker(io: &Io, } if session.kernel_state == KernelState::Running { - if session.watchdog_set.expired() { + if let Some(idx) = session.watchdog_set.expired() { host_write(stream, host::Reply::WatchdogExpired)?; - return Err(io_error("watchdog expired")) + return Err(Error::WatchdogExpired(idx)) } #[cfg(has_rtio_core)] { if !rtio_mgt::crg::check() { host_write(stream, host::Reply::ClockFailure)?; - return Err(io_error("RTIO clock failure")) + return Err(Error::ClockFailure) } } } @@ -568,7 +581,7 @@ fn host_kernel_worker(io: &Io, fn flash_kernel_worker(io: &Io, congress: &mut Congress, - config_key: &str) -> Result<(), io::Error<::std::io::Error>> { + config_key: &str) -> Result<(), Error<::std::io::Error>> { let mut session = Session::new(congress); config::read(config_key, |result| { @@ -578,15 +591,14 @@ fn flash_kernel_worker(io: &Io, // so make a copy. kern_load(io, &mut session, Vec::from(kernel).as_ref()) }, - _ => Err(io::Error::Other(::std::io::Error::new(::std::io::ErrorKind::NotFound, - "kernel not found"))), + _ => Err(Error::KernelNotFound) } })?; kern_run(&mut session)?; loop { if !rpc_queue::empty() { - return Err(io_error("unexpected background RPC in flash kernel")) + unexpected!("unexpected background RPC in flash kernel") } if mailbox::receive() != 0 { @@ -595,14 +607,14 @@ fn flash_kernel_worker(io: &Io, } } - if session.watchdog_set.expired() { - return Err(io_error("watchdog expired")) + if let Some(idx) = session.watchdog_set.expired() { + return Err(Error::WatchdogExpired(idx)) } #[cfg(has_rtio_core)] { if !rtio_mgt::crg::check() { - return Err(io_error("RTIO clock failure")) + return Err(Error::ClockFailure) } } @@ -639,10 +651,10 @@ pub fn thread(io: Io) { let mut congress = congress.borrow_mut(); info!("running startup kernel"); match flash_kernel_worker(&io, &mut congress, "startup_kernel") { - Ok(()) => info!("startup kernel finished"), - Err(io::Error::Other(ref err)) if err.kind() == ::std::io::ErrorKind::NotFound => { - info!("no startup kernel found") - } + Ok(()) => + info!("startup kernel finished"), + Err(Error::KernelNotFound) => + info!("no startup kernel found"), Err(err) => { congress.finished_cleanly.set(false); error!("startup kernel aborted: {}", err); @@ -657,7 +669,7 @@ pub fn thread(io: Io) { stream.set_timeout(Some(1000)); stream.set_keep_alive(Some(500)); - match check_magic(&mut stream) { + match host::read_magic(&mut stream) { Ok(()) => (), Err(_) => { warn!("wrong magic from {}", stream.remote_endpoint()); @@ -674,13 +686,11 @@ pub fn thread(io: Io) { let mut stream = TcpStream::from_handle(&io, stream); match host_kernel_worker(&io, &mut stream, &mut *congress) { Ok(()) => (), - Err(io::Error::UnexpectedEnd) => { - info!("connection closed"); - } - Err(io::Error::Other(ref err)) - if err.kind() == ::std::io::ErrorKind::Interrupted => { - info!("kernel interrupted"); - } + Err(Error::Protocol(host::Error::Io(io::Error::UnexpectedEnd))) => + info!("connection closed"), + Err(Error::Protocol(host::Error::Io(io::Error::Other(ref err)))) + if err.kind() == ::std::io::ErrorKind::Interrupted => + info!("kernel interrupted"), Err(err) => { congress.finished_cleanly.set(false); error!("session aborted: {}", err); @@ -698,18 +708,16 @@ pub fn thread(io: Io) { match flash_kernel_worker(&io, &mut *congress, "idle_kernel") { Ok(()) => info!("idle kernel finished, standing by"), - Err(io::Error::Other(ref err)) + Err(Error::Protocol(host::Error::Io(io::Error::Other(ref err)))) if err.kind() == ::std::io::ErrorKind::Interrupted => { info!("idle kernel interrupted"); } - Err(io::Error::Other(ref err)) - if err.kind() == ::std::io::ErrorKind::NotFound => { + Err(Error::KernelNotFound) => { info!("no idle kernel found"); while io.relinquish().is_ok() {} } - Err(err) => { - error!("idle kernel aborted: {}", err); - } + Err(err) => + error!("idle kernel aborted: {}", err) } }) } diff --git a/artiq/firmware/runtime/watchdog.rs b/artiq/firmware/runtime/watchdog.rs index fa0adc97f..202a1d1a0 100644 --- a/artiq/firmware/runtime/watchdog.rs +++ b/artiq/firmware/runtime/watchdog.rs @@ -38,10 +38,12 @@ impl WatchdogSet { } } - pub fn expired(&self) -> bool { - self.watchdogs.iter() - .filter(|wd| wd.active) - .min_by_key(|wd| wd.threshold) - .map_or(false, |wd| clock::get_ms() > wd.threshold) + pub fn expired(&self) -> Option { + self.watchdogs + .iter() + .enumerate() + .filter(|(_, wd)| wd.active && clock::get_ms() > wd.threshold) + .min_by_key(|(_, wd)| wd.threshold) + .map_or(None, |(i, _)| Some(i)) } } From 9347f6e00c24a6faf94edaa6d79d6fede54d50d8 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 15 May 2018 14:14:27 +0000 Subject: [PATCH 0770/2457] firmware: use a dedicated error type in the scheduler. After this commit, error handling does not normally allocate (session::Error::{Load,Unexpected} still allocate, but those two are very rare). Good riddance to libstd_artiq. --- artiq/firmware/Cargo.lock | 9 - artiq/firmware/libproto_artiq/Cargo.toml | 4 +- artiq/firmware/libproto_artiq/lib.rs | 2 - artiq/firmware/libproto_artiq/mgmt_proto.rs | 7 - artiq/firmware/libproto_artiq/moninj_proto.rs | 7 - .../firmware/libproto_artiq/session_proto.rs | 7 - artiq/firmware/libstd_artiq/Cargo.toml | 15 - artiq/firmware/libstd_artiq/error.rs | 453 ---- artiq/firmware/libstd_artiq/io/buffered.rs | 1108 ---------- artiq/firmware/libstd_artiq/io/cursor.rs | 574 ----- artiq/firmware/libstd_artiq/io/error.rs | 384 ---- artiq/firmware/libstd_artiq/io/impls.rs | 289 --- artiq/firmware/libstd_artiq/io/memchr.rs | 297 --- artiq/firmware/libstd_artiq/io/mod.rs | 1844 ----------------- artiq/firmware/libstd_artiq/io/prelude.rs | 22 - artiq/firmware/libstd_artiq/io/util.rs | 208 -- artiq/firmware/libstd_artiq/lib.rs | 43 - artiq/firmware/runtime/Cargo.toml | 1 - artiq/firmware/runtime/analyzer.rs | 6 +- artiq/firmware/runtime/kern_hwreq.rs | 4 +- artiq/firmware/runtime/main.rs | 6 +- artiq/firmware/runtime/mgmt.rs | 15 +- artiq/firmware/runtime/moninj.rs | 5 +- artiq/firmware/runtime/sched.rs | 75 +- artiq/firmware/runtime/session.rs | 58 +- 25 files changed, 89 insertions(+), 5354 deletions(-) delete mode 100644 artiq/firmware/libstd_artiq/Cargo.toml delete mode 100644 artiq/firmware/libstd_artiq/error.rs delete mode 100644 artiq/firmware/libstd_artiq/io/buffered.rs delete mode 100644 artiq/firmware/libstd_artiq/io/cursor.rs delete mode 100644 artiq/firmware/libstd_artiq/io/error.rs delete mode 100644 artiq/firmware/libstd_artiq/io/impls.rs delete mode 100644 artiq/firmware/libstd_artiq/io/memchr.rs delete mode 100644 artiq/firmware/libstd_artiq/io/mod.rs delete mode 100644 artiq/firmware/libstd_artiq/io/prelude.rs delete mode 100644 artiq/firmware/libstd_artiq/io/util.rs delete mode 100644 artiq/firmware/libstd_artiq/lib.rs diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 7cdd463c4..12568fcff 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -208,7 +208,6 @@ dependencies = [ "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "io 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "std_artiq 0.0.0", ] [[package]] @@ -236,7 +235,6 @@ dependencies = [ "managed 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "proto_artiq 0.0.0", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", - "std_artiq 0.0.0", "unwind_backtrace 0.0.0", ] @@ -270,13 +268,6 @@ dependencies = [ "managed 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "std_artiq" -version = "0.0.0" -dependencies = [ - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syn" version = "0.11.11" diff --git a/artiq/firmware/libproto_artiq/Cargo.toml b/artiq/firmware/libproto_artiq/Cargo.toml index 829d7f693..92d5e0d0f 100644 --- a/artiq/firmware/libproto_artiq/Cargo.toml +++ b/artiq/firmware/libproto_artiq/Cargo.toml @@ -15,8 +15,6 @@ cslice = { version = "0.3" } log = { version = "0.4", default-features = false, optional = true } io = { path = "../libio", features = ["byteorder"] } dyld = { path = "../libdyld" } -# TODO: remove -std_artiq = { path = "../libstd_artiq", optional = true } [features] -alloc = ["io/alloc", "std_artiq"] +alloc = ["io/alloc"] diff --git a/artiq/firmware/libproto_artiq/lib.rs b/artiq/firmware/libproto_artiq/lib.rs index 1290f559e..d8cbfe607 100644 --- a/artiq/firmware/libproto_artiq/lib.rs +++ b/artiq/firmware/libproto_artiq/lib.rs @@ -11,8 +11,6 @@ extern crate cslice; #[macro_use] extern crate log; -#[cfg(feature = "std_artiq")] -extern crate std_artiq; extern crate io; extern crate dyld; diff --git a/artiq/firmware/libproto_artiq/mgmt_proto.rs b/artiq/firmware/libproto_artiq/mgmt_proto.rs index c137623d0..9c44397e8 100644 --- a/artiq/firmware/libproto_artiq/mgmt_proto.rs +++ b/artiq/firmware/libproto_artiq/mgmt_proto.rs @@ -22,13 +22,6 @@ impl From> for Error { } } -#[cfg(feature = "std_artiq")] -impl From<::std_artiq::io::Error> for Error<::std_artiq::io::Error> { - fn from(value: ::std_artiq::io::Error) -> Error<::std_artiq::io::Error> { - Error::Io(IoError::Other(value)) - } -} - pub fn read_magic(reader: &mut R) -> Result<(), Error> where R: Read + ?Sized { diff --git a/artiq/firmware/libproto_artiq/moninj_proto.rs b/artiq/firmware/libproto_artiq/moninj_proto.rs index ee60d2eb5..d6f9a699b 100644 --- a/artiq/firmware/libproto_artiq/moninj_proto.rs +++ b/artiq/firmware/libproto_artiq/moninj_proto.rs @@ -16,13 +16,6 @@ impl From> for Error { } } -#[cfg(feature = "std_artiq")] -impl From<::std_artiq::io::Error> for Error<::std_artiq::io::Error> { - fn from(value: ::std_artiq::io::Error) -> Error<::std_artiq::io::Error> { - Error::Io(IoError::Other(value)) - } -} - pub fn read_magic(reader: &mut R) -> Result<(), Error> where R: Read + ?Sized { diff --git a/artiq/firmware/libproto_artiq/session_proto.rs b/artiq/firmware/libproto_artiq/session_proto.rs index d5816a174..7540ba513 100644 --- a/artiq/firmware/libproto_artiq/session_proto.rs +++ b/artiq/firmware/libproto_artiq/session_proto.rs @@ -30,13 +30,6 @@ impl From>> for Error { } } -#[cfg(feature = "std_artiq")] -impl From<::std_artiq::io::Error> for Error<::std_artiq::io::Error> { - fn from(value: ::std_artiq::io::Error) -> Error<::std_artiq::io::Error> { - Error::Io(IoError::Other(value)) - } -} - pub fn read_magic(reader: &mut R) -> Result<(), Error> where R: Read + ?Sized { diff --git a/artiq/firmware/libstd_artiq/Cargo.toml b/artiq/firmware/libstd_artiq/Cargo.toml deleted file mode 100644 index 52ab62954..000000000 --- a/artiq/firmware/libstd_artiq/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -authors = ["M-Labs"] -name = "std_artiq" -version = "0.0.0" - -[lib] -name = "std_artiq" -path = "lib.rs" - -[features] -alloc = [] -io_error_alloc = [] - -[dependencies] -failure = { version = "0.1", default-features = false } diff --git a/artiq/firmware/libstd_artiq/error.rs b/artiq/firmware/libstd_artiq/error.rs deleted file mode 100644 index 5e4e0ead1..000000000 --- a/artiq/firmware/libstd_artiq/error.rs +++ /dev/null @@ -1,453 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Traits for working with Errors. -//! -//! # The `Error` trait -//! -//! `Error` is a trait representing the basic expectations for error values, -//! i.e. values of type `E` in `Result`. At a minimum, errors must provide -//! a description, but they may optionally provide additional detail (via -//! `Display`) and cause chain information: -//! -//! ``` -//! use std::fmt::Display; -//! -//! trait Error: Display { -//! fn description(&self) -> &str; -//! -//! fn cause(&self) -> Option<&Error> { None } -//! } -//! ``` -//! -//! The `cause` method is generally used when errors cross "abstraction -//! boundaries", i.e. when a one module must report an error that is "caused" -//! by an error from a lower-level module. This setup makes it possible for the -//! high-level module to provide its own errors that do not commit to any -//! particular implementation, but also reveal some of its implementation for -//! debugging via `cause` chains. - -// A note about crates and the facade: -// -// Originally, the `Error` trait was defined in libcore, and the impls -// were scattered about. However, coherence objected to this -// arrangement, because to create the blanket impls for `Box` required -// knowing that `&str: !Error`, and we have no means to deal with that -// sort of conflict just now. Therefore, for the time being, we have -// moved the `Error` trait into libstd. As we evolve a sol'n to the -// coherence challenge (e.g., specialization, neg impls, etc) we can -// reconsider what crate these items belong in. - -use any::TypeId; -use boxed::Box; -use cell; -use fmt::{self, Debug, Display}; -use marker::{Send, Sync}; -use mem::transmute; -use num; -use core::raw::TraitObject; -use str; -use string::{self, String}; - -/// Base functionality for all errors in Rust. -pub trait Error: Debug + Display { - /// A short description of the error. - /// - /// The description should not contain newlines or sentence-ending - /// punctuation, to facilitate embedding in larger user-facing - /// strings. - /// - /// # Examples - /// - /// ``` - /// use std::error::Error; - /// - /// match "xc".parse::() { - /// Err(e) => { - /// println!("Error: {}", e.description()); - /// } - /// _ => println!("No error"), - /// } - /// ``` - fn description(&self) -> &str; - - /// The lower-level cause of this error, if any. - /// - /// # Examples - /// - /// ``` - /// use std::error::Error; - /// use std::fmt; - /// - /// #[derive(Debug)] - /// struct SuperError { - /// side: SuperErrorSideKick, - /// } - /// - /// impl fmt::Display for SuperError { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - /// write!(f, "SuperError is here!") - /// } - /// } - /// - /// impl Error for SuperError { - /// fn description(&self) -> &str { - /// "I'm the superhero of errors!" - /// } - /// - /// fn cause(&self) -> Option<&Error> { - /// Some(&self.side) - /// } - /// } - /// - /// #[derive(Debug)] - /// struct SuperErrorSideKick; - /// - /// impl fmt::Display for SuperErrorSideKick { - /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - /// write!(f, "SuperErrorSideKick is here!") - /// } - /// } - /// - /// impl Error for SuperErrorSideKick { - /// fn description(&self) -> &str { - /// "I'm SuperError side kick!" - /// } - /// } - /// - /// fn get_super_error() -> Result<(), SuperError> { - /// Err(SuperError { side: SuperErrorSideKick }) - /// } - /// - /// fn main() { - /// match get_super_error() { - /// Err(e) => { - /// println!("Error: {}", e.description()); - /// println!("Caused by: {}", e.cause().unwrap()); - /// } - /// _ => println!("No error"), - /// } - /// } - /// ``` - fn cause(&self) -> Option<&Error> { None } - - /// Get the `TypeId` of `self` - #[doc(hidden)] - fn type_id(&self) -> TypeId where Self: 'static { - TypeId::of::() - } -} - -impl<'a, E: Error + 'a> From for Box { - fn from(err: E) -> Box { - Box::new(err) - } -} - -impl<'a, E: Error + Send + Sync + 'a> From for Box { - fn from(err: E) -> Box { - Box::new(err) - } -} - -impl From for Box { - fn from(err: String) -> Box { - #[derive(Debug)] - struct StringError(String); - - impl Error for StringError { - fn description(&self) -> &str { &self.0 } - } - - impl Display for StringError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - Display::fmt(&self.0, f) - } - } - - Box::new(StringError(err)) - } -} - -impl From for Box { - fn from(str_err: String) -> Box { - let err1: Box = From::from(str_err); - let err2: Box = err1; - err2 - } -} - -impl<'a, 'b> From<&'b str> for Box { - fn from(err: &'b str) -> Box { - From::from(String::from(err)) - } -} - -impl<'a> From<&'a str> for Box { - fn from(err: &'a str) -> Box { - From::from(String::from(err)) - } -} - -impl Error for str::ParseBoolError { - fn description(&self) -> &str { "failed to parse bool" } -} - -impl Error for str::Utf8Error { - fn description(&self) -> &str { - "invalid utf-8: corrupt contents" - } -} - -impl Error for num::ParseIntError { - fn description(&self) -> &str { - self.__description() - } -} - -impl Error for num::TryFromIntError { - fn description(&self) -> &str { - self.__description() - } -} - -impl Error for num::ParseFloatError { - fn description(&self) -> &str { - self.__description() - } -} - -impl Error for string::FromUtf8Error { - fn description(&self) -> &str { - "invalid utf-8" - } -} - -impl Error for string::FromUtf16Error { - fn description(&self) -> &str { - "invalid utf-16" - } -} - -impl Error for string::ParseError { - fn description(&self) -> &str { - match *self {} - } -} - -impl Error for Box { - fn description(&self) -> &str { - Error::description(&**self) - } - - fn cause(&self) -> Option<&Error> { - Error::cause(&**self) - } -} - -impl Error for fmt::Error { - fn description(&self) -> &str { - "an error occurred when formatting an argument" - } -} - -impl Error for cell::BorrowError { - fn description(&self) -> &str { - "already mutably borrowed" - } -} - -impl Error for cell::BorrowMutError { - fn description(&self) -> &str { - "already borrowed" - } -} - -// copied from any.rs -impl Error + 'static { - /// Returns true if the boxed type is the same as `T` - #[inline] - pub fn is(&self) -> bool { - // Get TypeId of the type this function is instantiated with - let t = TypeId::of::(); - - // Get TypeId of the type in the trait object - let boxed = self.type_id(); - - // Compare both TypeIds on equality - t == boxed - } - - /// Returns some reference to the boxed value if it is of type `T`, or - /// `None` if it isn't. - #[inline] - pub fn downcast_ref(&self) -> Option<&T> { - if self.is::() { - unsafe { - // Get the raw representation of the trait object - let to: TraitObject = transmute(self); - - // Extract the data pointer - Some(&*(to.data as *const T)) - } - } else { - None - } - } - - /// Returns some mutable reference to the boxed value if it is of type `T`, or - /// `None` if it isn't. - #[inline] - pub fn downcast_mut(&mut self) -> Option<&mut T> { - if self.is::() { - unsafe { - // Get the raw representation of the trait object - let to: TraitObject = transmute(self); - - // Extract the data pointer - Some(&mut *(to.data as *const T as *mut T)) - } - } else { - None - } - } -} - -impl Error + 'static + Send { - /// Forwards to the method defined on the type `Any`. - #[inline] - pub fn is(&self) -> bool { - ::is::(self) - } - - /// Forwards to the method defined on the type `Any`. - #[inline] - pub fn downcast_ref(&self) -> Option<&T> { - ::downcast_ref::(self) - } - - /// Forwards to the method defined on the type `Any`. - #[inline] - pub fn downcast_mut(&mut self) -> Option<&mut T> { - ::downcast_mut::(self) - } -} - -impl Error + 'static + Send + Sync { - /// Forwards to the method defined on the type `Any`. - #[inline] - pub fn is(&self) -> bool { - ::is::(self) - } - - /// Forwards to the method defined on the type `Any`. - #[inline] - pub fn downcast_ref(&self) -> Option<&T> { - ::downcast_ref::(self) - } - - /// Forwards to the method defined on the type `Any`. - #[inline] - pub fn downcast_mut(&mut self) -> Option<&mut T> { - ::downcast_mut::(self) - } -} - -impl Error { - #[inline] - /// Attempt to downcast the box to a concrete type. - pub fn downcast(self: Box) -> Result, Box> { - if self.is::() { - unsafe { - // Get the raw representation of the trait object - let raw = Box::into_raw(self); - let to: TraitObject = - transmute::<*mut Error, TraitObject>(raw); - - // Extract the data pointer - Ok(Box::from_raw(to.data as *mut T)) - } - } else { - Err(self) - } - } -} - -impl Error + Send { - #[inline] - /// Attempt to downcast the box to a concrete type. - pub fn downcast(self: Box) - -> Result, Box> { - let err: Box = self; - ::downcast(err).map_err(|s| unsafe { - // reapply the Send marker - transmute::, Box>(s) - }) - } -} - -impl Error + Send + Sync { - #[inline] - /// Attempt to downcast the box to a concrete type. - pub fn downcast(self: Box) - -> Result, Box> { - let err: Box = self; - ::downcast(err).map_err(|s| unsafe { - // reapply the Send+Sync marker - transmute::, Box>(s) - }) - } -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use super::Error; - use fmt; - - #[derive(Debug, PartialEq)] - struct A; - #[derive(Debug, PartialEq)] - struct B; - - impl fmt::Display for A { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "A") - } - } - impl fmt::Display for B { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "B") - } - } - - impl Error for A { - fn description(&self) -> &str { "A-desc" } - } - impl Error for B { - fn description(&self) -> &str { "A-desc" } - } - - #[test] - fn downcasting() { - let mut a = A; - let mut a = &mut a as &mut (Error + 'static); - assert_eq!(a.downcast_ref::(), Some(&A)); - assert_eq!(a.downcast_ref::(), None); - assert_eq!(a.downcast_mut::(), Some(&mut A)); - assert_eq!(a.downcast_mut::(), None); - - let a: Box = Box::new(A); - match a.downcast::() { - Ok(..) => panic!("expected error"), - Err(e) => assert_eq!(*e.downcast::().unwrap(), A), - } - } -} diff --git a/artiq/firmware/libstd_artiq/io/buffered.rs b/artiq/firmware/libstd_artiq/io/buffered.rs deleted file mode 100644 index d0e7dbf72..000000000 --- a/artiq/firmware/libstd_artiq/io/buffered.rs +++ /dev/null @@ -1,1108 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Buffering wrappers for I/O traits - -use core::prelude::v1::*; -use io::prelude::*; - -use core::cmp; -use core::fmt; -use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom}; -use io::memchr; -use alloc::boxed::Box; -use alloc::vec::Vec; - -/// The `BufReader` struct adds buffering to any reader. -/// -/// It can be excessively inefficient to work directly with a `Read` instance. -/// For example, every call to `read` on `TcpStream` results in a system call. -/// A `BufReader` performs large, infrequent reads on the underlying `Read` -/// and maintains an in-memory buffer of the results. -/// -/// # Examples -/// -/// ``` -/// use std::io::prelude::*; -/// use std::io::BufReader; -/// use std::fs::File; -/// -/// # fn foo() -> std::io::Result<()> { -/// let mut f = try!(File::open("log.txt")); -/// let mut reader = BufReader::new(f); -/// -/// let mut line = String::new(); -/// let len = try!(reader.read_line(&mut line)); -/// println!("First line is {} bytes long", len); -/// # Ok(()) -/// # } -/// ``` -pub struct BufReader { - inner: R, - buf: Box<[u8]>, - pos: usize, - cap: usize, -} - -impl BufReader { - /// Creates a new `BufReader` with a default buffer capacity. - /// - /// # Examples - /// - /// ``` - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = try!(File::open("log.txt")); - /// let mut reader = BufReader::new(f); - /// # Ok(()) - /// # } - /// ``` - pub fn new(inner: R) -> BufReader { - BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) - } - - /// Creates a new `BufReader` with the specified buffer capacity. - /// - /// # Examples - /// - /// Creating a buffer with ten bytes of capacity: - /// - /// ``` - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f = try!(File::open("log.txt")); - /// let mut reader = BufReader::with_capacity(10, f); - /// # Ok(()) - /// # } - /// ``` - pub fn with_capacity(cap: usize, inner: R) -> BufReader { - BufReader { - inner: inner, - buf: vec![0; cap].into_boxed_slice(), - pos: 0, - cap: 0, - } - } - - /// Gets a reference to the underlying reader. - /// - /// It is inadvisable to directly read from the underlying reader. - /// - /// # Examples - /// - /// ``` - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f1 = try!(File::open("log.txt")); - /// let mut reader = BufReader::new(f1); - /// - /// let f2 = reader.get_ref(); - /// # Ok(()) - /// # } - /// ``` - pub fn get_ref(&self) -> &R { &self.inner } - - /// Gets a mutable reference to the underlying reader. - /// - /// It is inadvisable to directly read from the underlying reader. - /// - /// # Examples - /// - /// ``` - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f1 = try!(File::open("log.txt")); - /// let mut reader = BufReader::new(f1); - /// - /// let f2 = reader.get_mut(); - /// # Ok(()) - /// # } - /// ``` - pub fn get_mut(&mut self) -> &mut R { &mut self.inner } - - /// Unwraps this `BufReader`, returning the underlying reader. - /// - /// Note that any leftover data in the internal buffer is lost. - /// - /// # Examples - /// - /// ``` - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut f1 = try!(File::open("log.txt")); - /// let mut reader = BufReader::new(f1); - /// - /// let f2 = reader.into_inner(); - /// # Ok(()) - /// # } - /// ``` - pub fn into_inner(self) -> R { self.inner } -} - -impl Read for BufReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - // If we don't have any buffered data and we're doing a massive read - // (larger than our internal buffer), bypass our internal buffer - // entirely. - if self.pos == self.cap && buf.len() >= self.buf.len() { - return self.inner.read(buf); - } - let nread = { - let mut rem = self.fill_buf()?; - rem.read(buf)? - }; - self.consume(nread); - Ok(nread) - } -} - -impl BufRead for BufReader { - fn fill_buf(&mut self) -> io::Result<&[u8]> { - // If we've reached the end of our internal buffer then we need to fetch - // some more data from the underlying reader. - if self.pos == self.cap { - self.cap = self.inner.read(&mut self.buf)?; - self.pos = 0; - } - Ok(&self.buf[self.pos..self.cap]) - } - - fn consume(&mut self, amt: usize) { - self.pos = cmp::min(self.pos + amt, self.cap); - } -} - -impl fmt::Debug for BufReader where R: fmt::Debug { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("BufReader") - .field("reader", &self.inner) - .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len())) - .finish() - } -} - -impl Seek for BufReader { - /// Seek to an offset, in bytes, in the underlying reader. - /// - /// The position used for seeking with `SeekFrom::Current(_)` is the - /// position the underlying reader would be at if the `BufReader` had no - /// internal buffer. - /// - /// Seeking always discards the internal buffer, even if the seek position - /// would otherwise fall within it. This guarantees that calling - /// `.unwrap()` immediately after a seek yields the underlying reader at - /// the same position. - /// - /// See `std::io::Seek` for more details. - /// - /// Note: In the edge case where you're seeking with `SeekFrom::Current(n)` - /// where `n` minus the internal buffer length underflows an `i64`, two - /// seeks will be performed instead of one. If the second seek returns - /// `Err`, the underlying reader will be left at the same position it would - /// have if you seeked to `SeekFrom::Current(0)`. - fn seek(&mut self, pos: SeekFrom) -> io::Result { - let result: u64; - if let SeekFrom::Current(n) = pos { - let remainder = (self.cap - self.pos) as i64; - // it should be safe to assume that remainder fits within an i64 as the alternative - // means we managed to allocate 8 ebibytes and that's absurd. - // But it's not out of the realm of possibility for some weird underlying reader to - // support seeking by i64::min_value() so we need to handle underflow when subtracting - // remainder. - if let Some(offset) = n.checked_sub(remainder) { - result = self.inner.seek(SeekFrom::Current(offset))?; - } else { - // seek backwards by our remainder, and then by the offset - self.inner.seek(SeekFrom::Current(-remainder))?; - self.pos = self.cap; // empty the buffer - result = self.inner.seek(SeekFrom::Current(n))?; - } - } else { - // Seeking with Start/End doesn't care about our buffer length. - result = self.inner.seek(pos)?; - } - self.pos = self.cap; // empty the buffer - Ok(result) - } -} - -/// Wraps a writer and buffers its output. -/// -/// It can be excessively inefficient to work directly with something that -/// implements `Write`. For example, every call to `write` on `TcpStream` -/// results in a system call. A `BufWriter` keeps an in-memory buffer of data -/// and writes it to an underlying writer in large, infrequent batches. -/// -/// The buffer will be written out when the writer is dropped. -/// -/// # Examples -/// -/// Let's write the numbers one through ten to a `TcpStream`: -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::net::TcpStream; -/// -/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); -/// -/// for i in 1..10 { -/// stream.write(&[i]).unwrap(); -/// } -/// ``` -/// -/// Because we're not buffering, we write each one in turn, incurring the -/// overhead of a system call per byte written. We can fix this with a -/// `BufWriter`: -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::io::BufWriter; -/// use std::net::TcpStream; -/// -/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); -/// -/// for i in 1..10 { -/// stream.write(&[i]).unwrap(); -/// } -/// ``` -/// -/// By wrapping the stream with a `BufWriter`, these ten writes are all grouped -/// together by the buffer, and will all be written out in one system call when -/// the `stream` is dropped. -pub struct BufWriter { - inner: Option, - buf: Vec, - // #30888: If the inner writer panics in a call to write, we don't want to - // write the buffered data a second time in BufWriter's destructor. This - // flag tells the Drop impl if it should skip the flush. - panicked: bool, -} - -/// An error returned by `into_inner` which combines an error that -/// happened while writing out the buffer, and the buffered writer object -/// which may be used to recover from the condition. -/// -/// # Examples -/// -/// ```no_run -/// use std::io::BufWriter; -/// use std::net::TcpStream; -/// -/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); -/// -/// // do stuff with the stream -/// -/// // we want to get our `TcpStream` back, so let's try: -/// -/// let stream = match stream.into_inner() { -/// Ok(s) => s, -/// Err(e) => { -/// // Here, e is an IntoInnerError -/// panic!("An error occurred"); -/// } -/// }; -/// ``` -#[derive(Debug)] -pub struct IntoInnerError(W, Error); - -impl BufWriter { - /// Creates a new `BufWriter` with a default buffer capacity. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// ``` - pub fn new(inner: W) -> BufWriter { - BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) - } - - /// Creates a new `BufWriter` with the specified buffer capacity. - /// - /// # Examples - /// - /// Creating a buffer with a buffer of a hundred bytes. - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap(); - /// let mut buffer = BufWriter::with_capacity(100, stream); - /// ``` - pub fn with_capacity(cap: usize, inner: W) -> BufWriter { - BufWriter { - inner: Some(inner), - buf: Vec::with_capacity(cap), - panicked: false, - } - } - - fn flush_buf(&mut self) -> io::Result<()> { - let mut written = 0; - let len = self.buf.len(); - let mut ret = Ok(()); - while written < len { - self.panicked = true; - let r = self.inner.as_mut().unwrap().write(&self.buf[written..]); - self.panicked = false; - - match r { - Ok(0) => { - ret = Err(Error::new(ErrorKind::WriteZero, - "failed to write the buffered data")); - break; - } - Ok(n) => written += n, - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => { ret = Err(e); break } - - } - } - if written > 0 { - self.buf.drain(..written); - } - ret - } - - /// Gets a reference to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // we can use reference just like buffer - /// let reference = buffer.get_ref(); - /// ``` - pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() } - - /// Gets a mutable reference to the underlying writer. - /// - /// It is inadvisable to directly write to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // we can use reference just like buffer - /// let reference = buffer.get_mut(); - /// ``` - pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() } - - /// Unwraps this `BufWriter`, returning the underlying writer. - /// - /// The buffer is written out before returning the writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // unwrap the TcpStream and flush the buffer - /// let stream = buffer.into_inner().unwrap(); - /// ``` - pub fn into_inner(mut self) -> Result>> { - match self.flush_buf() { - Err(e) => Err(IntoInnerError(self, e)), - Ok(()) => Ok(self.inner.take().unwrap()) - } - } -} - -impl Write for BufWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - if self.buf.len() + buf.len() > self.buf.capacity() { - self.flush_buf()?; - } - if buf.len() >= self.buf.capacity() { - self.panicked = true; - let r = self.inner.as_mut().unwrap().write(buf); - self.panicked = false; - r - } else { - let amt = cmp::min(buf.len(), self.buf.capacity()); - Write::write(&mut self.buf, &buf[..amt]) - } - } - fn flush(&mut self) -> io::Result<()> { - self.flush_buf().and_then(|()| self.get_mut().flush()) - } -} - -impl fmt::Debug for BufWriter where W: fmt::Debug { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("BufWriter") - .field("writer", &self.inner.as_ref().unwrap()) - .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity())) - .finish() - } -} - -impl Seek for BufWriter { - /// Seek to the offset, in bytes, in the underlying writer. - /// - /// Seeking always writes out the internal buffer before seeking. - fn seek(&mut self, pos: SeekFrom) -> io::Result { - self.flush_buf().and_then(|_| self.get_mut().seek(pos)) - } -} - -impl Drop for BufWriter { - fn drop(&mut self) { - if self.inner.is_some() && !self.panicked { - // dtors should not panic, so we ignore a failed flush - let _r = self.flush_buf(); - } - } -} - -impl IntoInnerError { - /// Returns the error which caused the call to `into_inner()` to fail. - /// - /// This error was returned when attempting to write the internal buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // do stuff with the stream - /// - /// // we want to get our `TcpStream` back, so let's try: - /// - /// let stream = match stream.into_inner() { - /// Ok(s) => s, - /// Err(e) => { - /// // Here, e is an IntoInnerError, let's log the inner error. - /// // - /// // We'll just 'log' to stdout for this example. - /// println!("{}", e.error()); - /// - /// panic!("An unexpected error occurred."); - /// } - /// }; - /// ``` - pub fn error(&self) -> &Error { &self.1 } - - /// Returns the buffered writer instance which generated the error. - /// - /// The returned object can be used for error recovery, such as - /// re-inspecting the buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // do stuff with the stream - /// - /// // we want to get our `TcpStream` back, so let's try: - /// - /// let stream = match stream.into_inner() { - /// Ok(s) => s, - /// Err(e) => { - /// // Here, e is an IntoInnerError, let's re-examine the buffer: - /// let buffer = e.into_inner(); - /// - /// // do stuff to try to recover - /// - /// // afterwards, let's just return the stream - /// buffer.into_inner().unwrap() - /// } - /// }; - /// ``` - pub fn into_inner(self) -> W { self.0 } -} - -impl From> for Error { - fn from(iie: IntoInnerError) -> Error { iie.1 } -} - -impl fmt::Display for IntoInnerError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.error().fmt(f) - } -} - -/// Wraps a writer and buffers output to it, flushing whenever a newline -/// (`0x0a`, `'\n'`) is detected. -/// -/// The [`BufWriter`][bufwriter] struct wraps a writer and buffers its output. -/// But it only does this batched write when it goes out of scope, or when the -/// internal buffer is full. Sometimes, you'd prefer to write each line as it's -/// completed, rather than the entire buffer at once. Enter `LineWriter`. It -/// does exactly that. -/// -/// [bufwriter]: struct.BufWriter.html -/// -/// If there's still a partial line in the buffer when the `LineWriter` is -/// dropped, it will flush those contents. -/// -/// # Examples -/// -/// We can use `LineWriter` to write one line at a time, significantly -/// reducing the number of actual writes to the file. -/// -/// ``` -/// use std::fs::File; -/// use std::io::prelude::*; -/// use std::io::LineWriter; -/// -/// # fn foo() -> std::io::Result<()> { -/// let road_not_taken = b"I shall be telling this with a sigh -/// Somewhere ages and ages hence: -/// Two roads diverged in a wood, and I - -/// I took the one less traveled by, -/// And that has made all the difference."; -/// -/// let file = try!(File::create("poem.txt")); -/// let mut file = LineWriter::new(file); -/// -/// for &byte in road_not_taken.iter() { -/// file.write(&[byte]).unwrap(); -/// } -/// -/// // let's check we did the right thing. -/// let mut file = try!(File::open("poem.txt")); -/// let mut contents = String::new(); -/// -/// try!(file.read_to_string(&mut contents)); -/// -/// assert_eq!(contents.as_bytes(), &road_not_taken[..]); -/// # Ok(()) -/// # } -/// ``` -pub struct LineWriter { - inner: BufWriter, -} - -impl LineWriter { - /// Creates a new `LineWriter`. - /// - /// # Examples - /// - /// ``` - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// # fn foo() -> std::io::Result<()> { - /// let file = try!(File::create("poem.txt")); - /// let file = LineWriter::new(file); - /// # Ok(()) - /// # } - /// ``` - pub fn new(inner: W) -> LineWriter { - // Lines typically aren't that long, don't use a giant buffer - LineWriter::with_capacity(1024, inner) - } - - /// Creates a new `LineWriter` with a specified capacity for the internal - /// buffer. - /// - /// # Examples - /// - /// ``` - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// # fn foo() -> std::io::Result<()> { - /// let file = try!(File::create("poem.txt")); - /// let file = LineWriter::with_capacity(100, file); - /// # Ok(()) - /// # } - /// ``` - pub fn with_capacity(cap: usize, inner: W) -> LineWriter { - LineWriter { inner: BufWriter::with_capacity(cap, inner) } - } - - /// Gets a reference to the underlying writer. - /// - /// # Examples - /// - /// ``` - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// # fn foo() -> std::io::Result<()> { - /// let file = try!(File::create("poem.txt")); - /// let file = LineWriter::new(file); - /// - /// let reference = file.get_ref(); - /// # Ok(()) - /// # } - /// ``` - pub fn get_ref(&self) -> &W { self.inner.get_ref() } - - /// Gets a mutable reference to the underlying writer. - /// - /// Caution must be taken when calling methods on the mutable reference - /// returned as extra writes could corrupt the output stream. - /// - /// # Examples - /// - /// ``` - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// # fn foo() -> std::io::Result<()> { - /// let file = try!(File::create("poem.txt")); - /// let mut file = LineWriter::new(file); - /// - /// // we can use reference just like file - /// let reference = file.get_mut(); - /// # Ok(()) - /// # } - /// ``` - pub fn get_mut(&mut self) -> &mut W { self.inner.get_mut() } - - /// Unwraps this `LineWriter`, returning the underlying writer. - /// - /// The internal buffer is written out before returning the writer. - /// - /// # Examples - /// - /// ``` - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// # fn foo() -> std::io::Result<()> { - /// let file = try!(File::create("poem.txt")); - /// - /// let writer: LineWriter = LineWriter::new(file); - /// - /// let file: File = try!(writer.into_inner()); - /// # Ok(()) - /// # } - /// ``` - pub fn into_inner(self) -> Result>> { - self.inner.into_inner().map_err(|IntoInnerError(buf, e)| { - IntoInnerError(LineWriter { inner: buf }, e) - }) - } -} - -impl Write for LineWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - match memchr::memrchr(b'\n', buf) { - Some(i) => { - let n = self.inner.write(&buf[..i + 1])?; - if n != i + 1 || self.inner.flush().is_err() { - // Do not return errors on partial writes. - return Ok(n); - } - self.inner.write(&buf[i + 1..]).map(|i| n + i) - } - None => self.inner.write(buf), - } - } - - fn flush(&mut self) -> io::Result<()> { self.inner.flush() } -} - -impl fmt::Debug for LineWriter where W: fmt::Debug { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("LineWriter") - .field("writer", &self.inner.inner) - .field("buffer", - &format_args!("{}/{}", self.inner.buf.len(), self.inner.buf.capacity())) - .finish() - } -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use io::prelude::*; - use io::{self, BufReader, BufWriter, LineWriter, SeekFrom}; - use sync::atomic::{AtomicUsize, Ordering}; - use thread; - use test; - - /// A dummy reader intended at testing short-reads propagation. - pub struct ShortReader { - lengths: Vec, - } - - impl Read for ShortReader { - fn read(&mut self, _: &mut [u8]) -> io::Result { - if self.lengths.is_empty() { - Ok(0) - } else { - Ok(self.lengths.remove(0)) - } - } - } - - #[test] - fn test_buffered_reader() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(2, inner); - - let mut buf = [0, 0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(buf, b); - - let mut buf = [0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 2); - let b: &[_] = &[0, 1]; - assert_eq!(buf, b); - - let mut buf = [0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 1); - let b: &[_] = &[2]; - assert_eq!(buf, b); - - let mut buf = [0, 0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 1); - let b: &[_] = &[3, 0, 0]; - assert_eq!(buf, b); - - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 1); - let b: &[_] = &[4, 0, 0]; - assert_eq!(buf, b); - - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_buffered_reader_seek() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); - - assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3)); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4)); - assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..])); - reader.consume(1); - assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3)); - } - - #[test] - fn test_buffered_reader_seek_underflow() { - // gimmick reader that yields its position modulo 256 for each byte - struct PositionReader { - pos: u64 - } - impl Read for PositionReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let len = buf.len(); - for x in buf { - *x = self.pos as u8; - self.pos = self.pos.wrapping_add(1); - } - Ok(len) - } - } - impl Seek for PositionReader { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - match pos { - SeekFrom::Start(n) => { - self.pos = n; - } - SeekFrom::Current(n) => { - self.pos = self.pos.wrapping_add(n as u64); - } - SeekFrom::End(n) => { - self.pos = u64::max_value().wrapping_add(n as u64); - } - } - Ok(self.pos) - } - } - - let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 }); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..])); - assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::max_value()-5)); - assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); - // the following seek will require two underlying seeks - let expected = 9223372036854775802; - assert_eq!(reader.seek(SeekFrom::Current(i64::min_value())).ok(), Some(expected)); - assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); - // seeking to 0 should empty the buffer. - assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected)); - assert_eq!(reader.get_ref().pos, expected); - } - - #[test] - fn test_buffered_writer() { - let inner = Vec::new(); - let mut writer = BufWriter::with_capacity(2, inner); - - writer.write(&[0, 1]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1]); - - writer.write(&[2]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1]); - - writer.write(&[3]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1]); - - writer.flush().unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); - - writer.write(&[4]).unwrap(); - writer.write(&[5]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); - - writer.write(&[6]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); - - writer.write(&[7, 8]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); - - writer.write(&[9, 10, 11]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); - - writer.flush().unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); - } - - #[test] - fn test_buffered_writer_inner_flushes() { - let mut w = BufWriter::with_capacity(3, Vec::new()); - w.write(&[0, 1]).unwrap(); - assert_eq!(*w.get_ref(), []); - let w = w.into_inner().unwrap(); - assert_eq!(w, [0, 1]); - } - - #[test] - fn test_buffered_writer_seek() { - let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new())); - w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap(); - w.write_all(&[6, 7]).unwrap(); - assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8)); - assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]); - assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2)); - w.write_all(&[8, 9]).unwrap(); - assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]); - } - - #[test] - fn test_read_until() { - let inner: &[u8] = &[0, 1, 2, 1, 0]; - let mut reader = BufReader::with_capacity(2, inner); - let mut v = Vec::new(); - reader.read_until(0, &mut v).unwrap(); - assert_eq!(v, [0]); - v.truncate(0); - reader.read_until(2, &mut v).unwrap(); - assert_eq!(v, [1, 2]); - v.truncate(0); - reader.read_until(1, &mut v).unwrap(); - assert_eq!(v, [1]); - v.truncate(0); - reader.read_until(8, &mut v).unwrap(); - assert_eq!(v, [0]); - v.truncate(0); - reader.read_until(9, &mut v).unwrap(); - assert_eq!(v, []); - } - - #[test] - fn test_line_buffer_fail_flush() { - // Issue #32085 - struct FailFlushWriter<'a>(&'a mut Vec); - - impl<'a> Write for FailFlushWriter<'a> { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.extend_from_slice(buf); - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Err(io::Error::new(io::ErrorKind::Other, "flush failed")) - } - } - - let mut buf = Vec::new(); - { - let mut writer = LineWriter::new(FailFlushWriter(&mut buf)); - let to_write = b"abc\ndef"; - if let Ok(written) = writer.write(to_write) { - assert!(written < to_write.len(), "didn't flush on new line"); - // PASS - return; - } - } - assert!(buf.is_empty(), "write returned an error but wrote data"); - } - - #[test] - fn test_line_buffer() { - let mut writer = LineWriter::new(Vec::new()); - writer.write(&[0]).unwrap(); - assert_eq!(*writer.get_ref(), []); - writer.write(&[1]).unwrap(); - assert_eq!(*writer.get_ref(), []); - writer.flush().unwrap(); - assert_eq!(*writer.get_ref(), [0, 1]); - writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']); - writer.flush().unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]); - writer.write(&[3, b'\n']).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']); - } - - #[test] - fn test_read_line() { - let in_buf: &[u8] = b"a\nb\nc"; - let mut reader = BufReader::with_capacity(2, in_buf); - let mut s = String::new(); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, "a\n"); - s.truncate(0); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, "b\n"); - s.truncate(0); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, "c"); - s.truncate(0); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, ""); - } - - #[test] - fn test_lines() { - let in_buf: &[u8] = b"a\nb\nc"; - let reader = BufReader::with_capacity(2, in_buf); - let mut it = reader.lines(); - assert_eq!(it.next().unwrap().unwrap(), "a".to_string()); - assert_eq!(it.next().unwrap().unwrap(), "b".to_string()); - assert_eq!(it.next().unwrap().unwrap(), "c".to_string()); - assert!(it.next().is_none()); - } - - #[test] - fn test_short_reads() { - let inner = ShortReader{lengths: vec![0, 1, 2, 0, 1, 0]}; - let mut reader = BufReader::new(inner); - let mut buf = [0, 0]; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.read(&mut buf).unwrap(), 2); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn read_char_buffered() { - let buf = [195, 159]; - let reader = BufReader::with_capacity(1, &buf[..]); - assert_eq!(reader.chars().next().unwrap().unwrap(), 'ß'); - } - - #[test] - fn test_chars() { - let buf = [195, 159, b'a']; - let reader = BufReader::with_capacity(1, &buf[..]); - let mut it = reader.chars(); - assert_eq!(it.next().unwrap().unwrap(), 'ß'); - assert_eq!(it.next().unwrap().unwrap(), 'a'); - assert!(it.next().is_none()); - } - - #[test] - #[should_panic] - fn dont_panic_in_drop_on_panicked_flush() { - struct FailFlushWriter; - - impl Write for FailFlushWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { Ok(buf.len()) } - fn flush(&mut self) -> io::Result<()> { - Err(io::Error::last_os_error()) - } - } - - let writer = FailFlushWriter; - let _writer = BufWriter::new(writer); - - // If writer panics *again* due to the flush error then the process will - // abort. - panic!(); - } - - #[test] - fn panic_in_write_doesnt_flush_in_drop() { - static WRITES: AtomicUsize = AtomicUsize::new(0); - - struct PanicWriter; - - impl Write for PanicWriter { - fn write(&mut self, _: &[u8]) -> io::Result { - WRITES.fetch_add(1, Ordering::SeqCst); - panic!(); - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } - } - - thread::spawn(|| { - let mut writer = BufWriter::new(PanicWriter); - let _ = writer.write(b"hello world"); - let _ = writer.flush(); - }).join().unwrap_err(); - - assert_eq!(WRITES.load(Ordering::SeqCst), 1); - } - - #[bench] - fn bench_buffered_reader(b: &mut test::Bencher) { - b.iter(|| { - BufReader::new(io::empty()) - }); - } - - #[bench] - fn bench_buffered_writer(b: &mut test::Bencher) { - b.iter(|| { - BufWriter::new(io::sink()) - }); - } -} diff --git a/artiq/firmware/libstd_artiq/io/cursor.rs b/artiq/firmware/libstd_artiq/io/cursor.rs deleted file mode 100644 index 8b4783ae7..000000000 --- a/artiq/firmware/libstd_artiq/io/cursor.rs +++ /dev/null @@ -1,574 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use core::prelude::v1::*; -use io::prelude::*; - -use core::cmp; -use io::{self, SeekFrom, Error, ErrorKind}; -use alloc::boxed::Box; -use alloc::vec::Vec; - -/// A `Cursor` wraps another type and provides it with a -/// [`Seek`](trait.Seek.html) implementation. -/// -/// Cursors are typically used with in-memory buffers to allow them to -/// implement `Read` and/or `Write`, allowing these buffers to be used -/// anywhere you might use a reader or writer that does actual I/O. -/// -/// The standard library implements some I/O traits on various types which -/// are commonly used as a buffer, like `Cursor>` and `Cursor<&[u8]>`. -/// -/// # Examples -/// -/// We may want to write bytes to a [`File`][file] in our production -/// code, but use an in-memory buffer in our tests. We can do this with -/// `Cursor`: -/// -/// [file]: ../fs/struct.File.html -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::io::{self, SeekFrom}; -/// use std::fs::File; -/// -/// // a library function we've written -/// fn write_ten_bytes_at_end(writer: &mut W) -> io::Result<()> { -/// try!(writer.seek(SeekFrom::End(-10))); -/// -/// for i in 0..10 { -/// try!(writer.write(&[i])); -/// } -/// -/// // all went well -/// Ok(()) -/// } -/// -/// # fn foo() -> io::Result<()> { -/// // Here's some code that uses this library function. -/// // -/// // We might want to use a BufReader here for efficiency, but let's -/// // keep this example focused. -/// let mut file = try!(File::create("foo.txt")); -/// -/// try!(write_ten_bytes_at_end(&mut file)); -/// # Ok(()) -/// # } -/// -/// // now let's write a test -/// #[test] -/// fn test_writes_bytes() { -/// // setting up a real File is much more slow than an in-memory buffer, -/// // let's use a cursor instead -/// use std::io::Cursor; -/// let mut buff = Cursor::new(vec![0; 15]); -/// -/// write_ten_bytes_at_end(&mut buff).unwrap(); -/// -/// assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); -/// } -/// ``` -#[derive(Clone, Debug)] -pub struct Cursor { - inner: T, - pos: u64, -} - -impl Cursor { - /// Creates a new cursor wrapping the provided underlying I/O object. - /// - /// # Examples - /// - /// ``` - /// use std::io::Cursor; - /// - /// let buff = Cursor::new(Vec::new()); - /// # fn force_inference(_: &Cursor>) {} - /// # force_inference(&buff); - /// ``` - pub fn new(inner: T) -> Cursor { - Cursor { pos: 0, inner: inner } - } - - /// Consumes this cursor, returning the underlying value. - /// - /// # Examples - /// - /// ``` - /// use std::io::Cursor; - /// - /// let buff = Cursor::new(Vec::new()); - /// # fn force_inference(_: &Cursor>) {} - /// # force_inference(&buff); - /// - /// let vec = buff.into_inner(); - /// ``` - pub fn into_inner(self) -> T { self.inner } - - /// Gets a reference to the underlying value in this cursor. - /// - /// # Examples - /// - /// ``` - /// use std::io::Cursor; - /// - /// let buff = Cursor::new(Vec::new()); - /// # fn force_inference(_: &Cursor>) {} - /// # force_inference(&buff); - /// - /// let reference = buff.get_ref(); - /// ``` - pub fn get_ref(&self) -> &T { &self.inner } - - /// Gets a mutable reference to the underlying value in this cursor. - /// - /// Care should be taken to avoid modifying the internal I/O state of the - /// underlying value as it may corrupt this cursor's position. - /// - /// # Examples - /// - /// ``` - /// use std::io::Cursor; - /// - /// let mut buff = Cursor::new(Vec::new()); - /// # fn force_inference(_: &Cursor>) {} - /// # force_inference(&buff); - /// - /// let reference = buff.get_mut(); - /// ``` - pub fn get_mut(&mut self) -> &mut T { &mut self.inner } - - /// Returns the current position of this cursor. - /// - /// # Examples - /// - /// ``` - /// use std::io::Cursor; - /// use std::io::prelude::*; - /// use std::io::SeekFrom; - /// - /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]); - /// - /// assert_eq!(buff.position(), 0); - /// - /// buff.seek(SeekFrom::Current(2)).unwrap(); - /// assert_eq!(buff.position(), 2); - /// - /// buff.seek(SeekFrom::Current(-1)).unwrap(); - /// assert_eq!(buff.position(), 1); - /// ``` - pub fn position(&self) -> u64 { self.pos } - - /// Sets the position of this cursor. - /// - /// # Examples - /// - /// ``` - /// use std::io::Cursor; - /// - /// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]); - /// - /// assert_eq!(buff.position(), 0); - /// - /// buff.set_position(2); - /// assert_eq!(buff.position(), 2); - /// - /// buff.set_position(4); - /// assert_eq!(buff.position(), 4); - /// ``` - pub fn set_position(&mut self, pos: u64) { self.pos = pos; } -} - -impl io::Seek for Cursor where T: AsRef<[u8]> { - fn seek(&mut self, style: SeekFrom) -> io::Result { - let pos = match style { - SeekFrom::Start(n) => { self.pos = n; return Ok(n) } - SeekFrom::End(n) => self.inner.as_ref().len() as i64 + n, - SeekFrom::Current(n) => self.pos as i64 + n, - }; - - if pos < 0 { - Err(Error::new(ErrorKind::InvalidInput, - "invalid seek to a negative position")) - } else { - self.pos = pos as u64; - Ok(self.pos) - } - } -} - -impl Read for Cursor where T: AsRef<[u8]> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let n = Read::read(&mut self.fill_buf()?, buf)?; - self.pos += n as u64; - Ok(n) - } -} - -impl BufRead for Cursor where T: AsRef<[u8]> { - fn fill_buf(&mut self) -> io::Result<&[u8]> { - let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64); - Ok(&self.inner.as_ref()[(amt as usize)..]) - } - fn consume(&mut self, amt: usize) { self.pos += amt as u64; } -} - -impl<'a> Write for Cursor<&'a mut [u8]> { - #[inline] - fn write(&mut self, data: &[u8]) -> io::Result { - let pos = cmp::min(self.pos, self.inner.len() as u64); - let amt = (&mut self.inner[(pos as usize)..]).write(data)?; - self.pos += amt as u64; - Ok(amt) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -impl Write for Cursor> { - fn write(&mut self, buf: &[u8]) -> io::Result { - // Make sure the internal buffer is as least as big as where we - // currently are - let pos = self.position(); - let amt = pos.saturating_sub(self.inner.len() as u64); - // use `resize` so that the zero filling is as efficient as possible - let len = self.inner.len(); - self.inner.resize(len + amt as usize, 0); - - // Figure out what bytes will be used to overwrite what's currently - // there (left), and what will be appended on the end (right) - { - let pos = pos as usize; - let space = self.inner.len() - pos; - let (left, right) = buf.split_at(cmp::min(space, buf.len())); - self.inner[pos..pos + left.len()].copy_from_slice(left); - self.inner.extend_from_slice(right); - } - - // Bump us forward - self.set_position(pos + buf.len() as u64); - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -impl Write for Cursor> { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - let pos = cmp::min(self.pos, self.inner.len() as u64); - let amt = (&mut self.inner[(pos as usize)..]).write(buf)?; - self.pos += amt as u64; - Ok(amt) - } - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -#[cfg(test)] -mod tests { - use io::prelude::*; - use io::{Cursor, SeekFrom}; - use vec::Vec; - - #[test] - fn test_vec_writer() { - let mut writer = Vec::new(); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(writer, b); - } - - #[test] - fn test_mem_writer() { - let mut writer = Cursor::new(Vec::new()); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - } - - #[test] - fn test_box_slice_writer() { - let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!(writer.position(), 8); - assert_eq!(writer.write(&[]).unwrap(), 0); - assert_eq!(writer.position(), 8); - - assert_eq!(writer.write(&[8, 9]).unwrap(), 1); - assert_eq!(writer.write(&[10]).unwrap(), 0); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(&**writer.get_ref(), b); - } - - #[test] - fn test_buf_writer() { - let mut buf = [0 as u8; 9]; - { - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!(writer.position(), 8); - assert_eq!(writer.write(&[]).unwrap(), 0); - assert_eq!(writer.position(), 8); - - assert_eq!(writer.write(&[8, 9]).unwrap(), 1); - assert_eq!(writer.write(&[10]).unwrap(), 0); - } - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(buf, b); - } - - #[test] - fn test_buf_writer_seek() { - let mut buf = [0 as u8; 8]; - { - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[1]).unwrap(), 1); - assert_eq!(writer.position(), 1); - - assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2); - assert_eq!(writer.position(), 2); - assert_eq!(writer.write(&[2]).unwrap(), 1); - assert_eq!(writer.position(), 3); - - assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[3]).unwrap(), 1); - assert_eq!(writer.position(), 2); - - assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7); - assert_eq!(writer.position(), 7); - assert_eq!(writer.write(&[4]).unwrap(), 1); - assert_eq!(writer.position(), 8); - - } - let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4]; - assert_eq!(buf, b); - } - - #[test] - fn test_buf_writer_error() { - let mut buf = [0 as u8; 2]; - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[0, 0]).unwrap(), 1); - assert_eq!(writer.write(&[0, 0]).unwrap(), 0); - } - - #[test] - fn test_mem_reader() { - let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7)); - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.position(), 5); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_boxed_slice_reader() { - let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7).into_boxed_slice()); - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.position(), 5); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn read_to_end() { - let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7)); - let mut v = Vec::new(); - reader.read_to_end(&mut v).unwrap(); - assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]); - } - - #[test] - fn test_slice_reader() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let mut reader = &mut &in_buf[..]; - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.len(), 7); - let b: &[_] = &[0]; - assert_eq!(&buf[..], b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.len(), 3); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(&buf[..], b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_buf_reader() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let mut reader = Cursor::new(&in_buf[..]); - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.position(), 5); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_read_char() { - let b = &b"Vi\xE1\xBB\x87t"[..]; - let mut c = Cursor::new(b).chars(); - assert_eq!(c.next().unwrap().unwrap(), 'V'); - assert_eq!(c.next().unwrap().unwrap(), 'i'); - assert_eq!(c.next().unwrap().unwrap(), 'ệ'); - assert_eq!(c.next().unwrap().unwrap(), 't'); - assert!(c.next().is_none()); - } - - #[test] - fn test_read_bad_char() { - let b = &b"\x80"[..]; - let mut c = Cursor::new(b).chars(); - assert!(c.next().unwrap().is_err()); - } - - #[test] - fn seek_past_end() { - let buf = [0xff]; - let mut r = Cursor::new(&buf[..]); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.read(&mut [0]).unwrap(), 0); - - let mut r = Cursor::new(vec!(10)); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.read(&mut [0]).unwrap(), 0); - - let mut buf = [0]; - let mut r = Cursor::new(&mut buf[..]); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.write(&[3]).unwrap(), 0); - - let mut r = Cursor::new(vec![10].into_boxed_slice()); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.write(&[3]).unwrap(), 0); - } - - #[test] - fn seek_before_0() { - let buf = [0xff]; - let mut r = Cursor::new(&buf[..]); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - - let mut r = Cursor::new(vec!(10)); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - - let mut buf = [0]; - let mut r = Cursor::new(&mut buf[..]); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - - let mut r = Cursor::new(vec!(10).into_boxed_slice()); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - } - - #[test] - fn test_seekable_mem_writer() { - let mut writer = Cursor::new(Vec::::new()); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!(writer.position(), 8); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[3, 4]).unwrap(), 2); - let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3); - assert_eq!(writer.write(&[0, 1]).unwrap(), 2); - let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7); - assert_eq!(writer.write(&[1, 2]).unwrap(), 2); - let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10); - assert_eq!(writer.write(&[1]).unwrap(), 1); - let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]; - assert_eq!(&writer.get_ref()[..], b); - } - - #[test] - fn vec_seek_past_end() { - let mut r = Cursor::new(Vec::new()); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.write(&[3]).unwrap(), 1); - } - - #[test] - fn vec_seek_before_0() { - let mut r = Cursor::new(Vec::new()); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - } -} diff --git a/artiq/firmware/libstd_artiq/io/error.rs b/artiq/firmware/libstd_artiq/io/error.rs deleted file mode 100644 index 942e4187c..000000000 --- a/artiq/firmware/libstd_artiq/io/error.rs +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[cfg(feature="io_error_alloc")] use alloc::boxed::Box; -#[cfg(not(feature="io_error_alloc"))] use ::FakeBox as Box; -use core::convert::Into; -use core::fmt; -use core::marker::{Send, Sync}; -use core::option::Option::{self, Some, None}; -use core::result; -use error; - -/// A specialized [`Result`](../result/enum.Result.html) type for I/O -/// operations. -/// -/// This type is broadly used across `std::io` for any operation which may -/// produce an error. -/// -/// This typedef is generally used to avoid writing out `io::Error` directly and -/// is otherwise a direct mapping to `Result`. -/// -/// While usual Rust style is to import types directly, aliases of `Result` -/// often are not, to make it easier to distinguish between them. `Result` is -/// generally assumed to be `std::result::Result`, and so users of this alias -/// will generally use `io::Result` instead of shadowing the prelude's import -/// of `std::result::Result`. -/// -/// # Examples -/// -/// A convenience function that bubbles an `io::Result` to its caller: -/// -/// ``` -/// use std::io; -/// -/// fn get_string() -> io::Result { -/// let mut buffer = String::new(); -/// -/// try!(io::stdin().read_line(&mut buffer)); -/// -/// Ok(buffer) -/// } -/// ``` -pub type Result = result::Result; - -/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and -/// associated traits. -/// -/// Errors mostly originate from the underlying OS, but custom instances of -/// `Error` can be created with crafted error messages and a particular value of -/// `ErrorKind`. -#[derive(Debug)] -pub struct Error { - repr: Repr, -} - -enum Repr { - Os(i32), - - #[cfg(feature="io_error_alloc")] - Custom(Box), - #[cfg(not(feature="io_error_alloc"))] - Custom(Custom), -} - -#[derive(Debug)] -struct Custom { - kind: ErrorKind, - #[cfg(feature="io_error_alloc")] - error: Box, - #[cfg(not(feature="io_error_alloc"))] - error: &'static str -} - -/// A list specifying general categories of I/O error. -/// -/// This list is intended to grow over time and it is not recommended to -/// exhaustively match against it. -#[derive(Copy, PartialEq, Eq, Clone, Debug)] -#[allow(deprecated)] -pub enum ErrorKind { - /// An entity was not found, often a file. - NotFound, - /// The operation lacked the necessary privileges to complete. - PermissionDenied, - /// The connection was refused by the remote server. - ConnectionRefused, - /// The connection was reset by the remote server. - ConnectionReset, - /// The connection was aborted (terminated) by the remote server. - ConnectionAborted, - /// The network operation failed because it was not connected yet. - NotConnected, - /// A socket address could not be bound because the address is already in - /// use elsewhere. - AddrInUse, - /// A nonexistent interface was requested or the requested address was not - /// local. - AddrNotAvailable, - /// The operation failed because a pipe was closed. - BrokenPipe, - /// An entity already exists, often a file. - AlreadyExists, - /// The operation needs to block to complete, but the blocking operation was - /// requested to not occur. - WouldBlock, - /// A parameter was incorrect. - InvalidInput, - /// Data not valid for the operation were encountered. - /// - /// Unlike `InvalidInput`, this typically means that the operation - /// parameters were valid, however the error was caused by malformed - /// input data. - /// - /// For example, a function that reads a file into a string will error with - /// `InvalidData` if the file's contents are not valid UTF-8. - InvalidData, - /// The I/O operation's timeout expired, causing it to be canceled. - TimedOut, - /// An error returned when an operation could not be completed because a - /// call to `write` returned `Ok(0)`. - /// - /// This typically means that an operation could only succeed if it wrote a - /// particular number of bytes but only a smaller number of bytes could be - /// written. - WriteZero, - /// This operation was interrupted. - /// - /// Interrupted operations can typically be retried. - Interrupted, - /// Any I/O error not part of this list. - Other, - - /// An error returned when an operation could not be completed because an - /// "end of file" was reached prematurely. - /// - /// This typically means that an operation could only succeed if it read a - /// particular number of bytes but only a smaller number of bytes could be - /// read. - UnexpectedEof, - - /// Any I/O error not part of this list. - #[doc(hidden)] - __Nonexhaustive, -} - -impl Error { - /// Creates a new I/O error from a known kind of error as well as an - /// arbitrary error payload. - /// - /// This function is used to generically create I/O errors which do not - /// originate from the OS itself. The `error` argument is an arbitrary - /// payload which will be contained in this `Error`. - /// - /// # Examples - /// - /// ``` - /// use std::io::{Error, ErrorKind}; - /// - /// // errors can be created from strings - /// let custom_error = Error::new(ErrorKind::Other, "oh no!"); - /// - /// // errors can also be created from other errors - /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error); - /// ``` - #[cfg(feature="io_error_alloc")] - pub fn new(kind: ErrorKind, error: E) -> Error - where E: Into> - { - Self::_new(kind, error.into()) - } - - #[cfg(not(feature="io_error_alloc"))] - pub fn new(kind: ErrorKind, error: E) -> Error - where E: Into<&'static str> - { - Self::_new(kind, error.into()) - } - - #[cfg(feature="io_error_alloc")] - fn _new(kind: ErrorKind, error: Box) -> Error { - Error { - repr: Repr::Custom(Box::new(Custom { - kind: kind, - error: error, - })) - } - } - - #[cfg(not(feature="io_error_alloc"))] - fn _new(kind: ErrorKind, error: &'static str) -> Error { - Error { - repr: Repr::Custom(Box::new(Custom { - kind: kind, - error: error, - })) - } - } - - /// Creates a new instance of an `Error` from a particular OS error code. - pub fn from_raw_os_error(code: i32) -> Error { - Error { repr: Repr::Os(code) } - } - - /// Returns the OS error that this error represents (if any). - /// - /// If this `Error` was constructed via `last_os_error` or - /// `from_raw_os_error`, then this function will return `Some`, otherwise - /// it will return `None`. - pub fn raw_os_error(&self) -> Option { - match self.repr { - Repr::Os(i) => Some(i), - Repr::Custom(..) => None, - } - } - - /// Returns a reference to the inner error wrapped by this error (if any). - /// - /// If this `Error` was constructed via `new` then this function will - /// return `Some`, otherwise it will return `None`. - #[cfg(feature="io_error_alloc")] - pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> { - match self.repr { - Repr::Os(..) => None, - Repr::Custom(ref c) => Some(&*c.error), - } - } - - /// Returns a mutable reference to the inner error wrapped by this error - /// (if any). - /// - /// If this `Error` was constructed via `new` then this function will - /// return `Some`, otherwise it will return `None`. - #[cfg(feature="io_error_alloc")] - pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> { - match self.repr { - Repr::Os(..) => None, - Repr::Custom(ref mut c) => Some(&mut *c.error), - } - } - - /// Consumes the `Error`, returning its inner error (if any). - /// - /// If this `Error` was constructed via `new` then this function will - /// return `Some`, otherwise it will return `None`. - #[cfg(feature="io_error_alloc")] - pub fn into_inner(self) -> Option> { - match self.repr { - Repr::Os(..) => None, - Repr::Custom(c) => Some(c.error) - } - } - - /// Returns the corresponding `ErrorKind` for this error. - pub fn kind(&self) -> ErrorKind { - match self.repr { - Repr::Os(_code) => ErrorKind::Other, - Repr::Custom(ref c) => c.kind, - } - } -} - -impl fmt::Debug for Repr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - Repr::Os(ref code) => - fmt.debug_struct("Os").field("code", code).finish(), - Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(), - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self.repr { - Repr::Os(code) => { - write!(fmt, "os error {}", code) - } - Repr::Custom(ref c) => c.error.fmt(fmt), - } - } -} - -impl error::Error for Error { - fn description(&self) -> &str { - match self.repr { - Repr::Os(..) => match self.kind() { - ErrorKind::NotFound => "entity not found", - ErrorKind::PermissionDenied => "permission denied", - ErrorKind::ConnectionRefused => "connection refused", - ErrorKind::ConnectionReset => "connection reset", - ErrorKind::ConnectionAborted => "connection aborted", - ErrorKind::NotConnected => "not connected", - ErrorKind::AddrInUse => "address in use", - ErrorKind::AddrNotAvailable => "address not available", - ErrorKind::BrokenPipe => "broken pipe", - ErrorKind::AlreadyExists => "entity already exists", - ErrorKind::WouldBlock => "operation would block", - ErrorKind::InvalidInput => "invalid input parameter", - ErrorKind::InvalidData => "invalid data", - ErrorKind::TimedOut => "timed out", - ErrorKind::WriteZero => "write zero", - ErrorKind::Interrupted => "operation interrupted", - ErrorKind::Other => "other os error", - ErrorKind::UnexpectedEof => "unexpected end of file", - ErrorKind::__Nonexhaustive => unreachable!() - }, - Repr::Custom(ref c) => { - #[cfg(feature="io_error_alloc")] - { c.error.description() } - #[cfg(not(feature="io_error_alloc"))] - { c.error } - }, - } - } - - fn cause(&self) -> Option<&error::Error> { - match self.repr { - Repr::Os(..) => None, - Repr::Custom(ref _c) => { - #[cfg(feature="io_error_alloc")] - { _c.error.cause() } - #[cfg(not(feature="io_error_alloc"))] - { None } - } - } - } -} - -fn _assert_error_is_sync_send() { - fn _is_sync_send() {} - _is_sync_send::(); -} - -#[cfg(test)] -mod test { - use prelude::v1::*; - use super::{Error, ErrorKind}; - use error; - use fmt; - use sys::os::error_string; - - #[test] - fn test_debug_error() { - let code = 6; - let msg = error_string(code); - let err = Error { repr: super::Repr::Os(code) }; - let expected = format!("Error {{ repr: Os {{ code: {:?}, message: {:?} }} }}", code, msg); - assert_eq!(format!("{:?}", err), expected); - } - - #[test] - fn test_downcasting() { - #[derive(Debug)] - struct TestError; - - impl fmt::Display for TestError { - fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { - Ok(()) - } - } - - impl error::Error for TestError { - fn description(&self) -> &str { - "asdf" - } - } - - // we have to call all of these UFCS style right now since method - // resolution won't implicitly drop the Send+Sync bounds - let mut err = Error::new(ErrorKind::Other, TestError); - assert!(err.get_ref().unwrap().is::()); - assert_eq!("asdf", err.get_ref().unwrap().description()); - assert!(err.get_mut().unwrap().is::()); - let extracted = err.into_inner().unwrap(); - extracted.downcast::().unwrap(); - } -} diff --git a/artiq/firmware/libstd_artiq/io/impls.rs b/artiq/firmware/libstd_artiq/io/impls.rs deleted file mode 100644 index 128e693ca..000000000 --- a/artiq/firmware/libstd_artiq/io/impls.rs +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - use alloc::boxed::Box; -use core::cmp; -use io::{self, SeekFrom, Read, Write, Seek, Error, ErrorKind}; - use io::BufRead; -use core::fmt; -use core::mem; - use alloc::string::String; - use alloc::vec::Vec; - -// ============================================================================= -// Forwarding implementations - -impl<'a, R: Read + ?Sized> Read for &'a mut R { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (**self).read(buf) - } - - - #[inline] - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - (**self).read_to_end(buf) - } - - - #[inline] - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - (**self).read_to_string(buf) - } - - #[inline] - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - (**self).read_exact(buf) - } -} -impl<'a, W: Write + ?Sized> Write for &'a mut W { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { (**self).write(buf) } - - #[inline] - fn flush(&mut self) -> io::Result<()> { (**self).flush() } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - (**self).write_all(buf) - } - - #[inline] - fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { - (**self).write_fmt(fmt) - } -} -impl<'a, S: Seek + ?Sized> Seek for &'a mut S { - #[inline] - fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) } -} - -impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B { - #[inline] - fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() } - - #[inline] - fn consume(&mut self, amt: usize) { (**self).consume(amt) } - - #[inline] - fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { - (**self).read_until(byte, buf) - } - - #[inline] - fn read_line(&mut self, buf: &mut String) -> io::Result { - (**self).read_line(buf) - } -} - - -impl Read for Box { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - (**self).read(buf) - } - - - #[inline] - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - (**self).read_to_end(buf) - } - - - #[inline] - fn read_to_string(&mut self, buf: &mut String) -> io::Result { - (**self).read_to_string(buf) - } - - #[inline] - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - (**self).read_exact(buf) - } -} - -impl Write for Box { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { (**self).write(buf) } - - #[inline] - fn flush(&mut self) -> io::Result<()> { (**self).flush() } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - (**self).write_all(buf) - } - - #[inline] - fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { - (**self).write_fmt(fmt) - } -} - -impl Seek for Box { - #[inline] - fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) } -} - -impl BufRead for Box { - #[inline] - fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() } - - #[inline] - fn consume(&mut self, amt: usize) { (**self).consume(amt) } - - #[inline] - fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { - (**self).read_until(byte, buf) - } - - #[inline] - fn read_line(&mut self, buf: &mut String) -> io::Result { - (**self).read_line(buf) - } -} - -// ============================================================================= -// In-memory buffer implementations - -impl<'a> Read for &'a [u8] { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let amt = cmp::min(buf.len(), self.len()); - let (a, b) = self.split_at(amt); - buf[..amt].copy_from_slice(a); - *self = b; - Ok(amt) - } - - #[inline] - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - if buf.len() > self.len() { - return Err(Error::new(ErrorKind::UnexpectedEof, - "failed to fill whole buffer")); - } - let (a, b) = self.split_at(buf.len()); - buf.copy_from_slice(a); - *self = b; - Ok(()) - } -} - - -impl<'a> BufRead for &'a [u8] { - #[inline] - fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) } - - #[inline] - fn consume(&mut self, amt: usize) { *self = &self[amt..]; } -} - -impl<'a> Write for &'a mut [u8] { - #[inline] - fn write(&mut self, data: &[u8]) -> io::Result { - let amt = cmp::min(data.len(), self.len()); - let (a, b) = mem::replace(self, &mut []).split_at_mut(amt); - a.copy_from_slice(&data[..amt]); - *self = b; - Ok(amt) - } - - #[inline] - fn write_all(&mut self, data: &[u8]) -> io::Result<()> { - if self.write(data)? == data.len() { - Ok(()) - } else { - Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer")) - } - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - - -impl Write for Vec { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.extend_from_slice(buf); - Ok(buf.len()) - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.extend_from_slice(buf); - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -#[cfg(test)] -mod tests { - use io::prelude::*; - use vec::Vec; - use test; - - #[bench] - fn bench_read_slice(b: &mut test::Bencher) { - let buf = [5; 1024]; - let mut dst = [0; 128]; - - b.iter(|| { - let mut rd = &buf[..]; - for _ in 0..8 { - let _ = rd.read(&mut dst); - test::black_box(&dst); - } - }) - } - - #[bench] - fn bench_write_slice(b: &mut test::Bencher) { - let mut buf = [0; 1024]; - let src = [5; 128]; - - b.iter(|| { - let mut wr = &mut buf[..]; - for _ in 0..8 { - let _ = wr.write_all(&src); - test::black_box(&wr); - } - }) - } - - #[bench] - fn bench_read_vec(b: &mut test::Bencher) { - let buf = vec![5; 1024]; - let mut dst = [0; 128]; - - b.iter(|| { - let mut rd = &buf[..]; - for _ in 0..8 { - let _ = rd.read(&mut dst); - test::black_box(&dst); - } - }) - } - - #[bench] - fn bench_write_vec(b: &mut test::Bencher) { - let mut buf = Vec::with_capacity(1024); - let src = [5; 128]; - - b.iter(|| { - let mut wr = &mut buf[..]; - for _ in 0..8 { - let _ = wr.write_all(&src); - test::black_box(&wr); - } - }) - } -} diff --git a/artiq/firmware/libstd_artiq/io/memchr.rs b/artiq/firmware/libstd_artiq/io/memchr.rs deleted file mode 100644 index 110cfac93..000000000 --- a/artiq/firmware/libstd_artiq/io/memchr.rs +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// -// Original implementation taken from rust-memchr -// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch - -pub use self::fallback::{memchr,memrchr}; - -#[allow(dead_code)] -mod fallback { - use core::cmp; - use core::mem; - - const LO_U64: u64 = 0x0101010101010101; - const HI_U64: u64 = 0x8080808080808080; - - // use truncation - const LO_USIZE: usize = LO_U64 as usize; - const HI_USIZE: usize = HI_U64 as usize; - - /// Return `true` if `x` contains any zero byte. - /// - /// From *Matters Computational*, J. Arndt - /// - /// "The idea is to subtract one from each of the bytes and then look for - /// bytes where the borrow propagated all the way to the most significant - /// bit." - #[inline] - fn contains_zero_byte(x: usize) -> bool { - x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0 - } - - #[cfg(target_pointer_width = "32")] - #[inline] - fn repeat_byte(b: u8) -> usize { - let mut rep = (b as usize) << 8 | b as usize; - rep = rep << 16 | rep; - rep - } - - #[cfg(target_pointer_width = "64")] - #[inline] - fn repeat_byte(b: u8) -> usize { - let mut rep = (b as usize) << 8 | b as usize; - rep = rep << 16 | rep; - rep = rep << 32 | rep; - rep - } - - /// Return the first index matching the byte `a` in `text`. - pub fn memchr(x: u8, text: &[u8]) -> Option { - // Scan for a single byte value by reading two `usize` words at a time. - // - // Split `text` in three parts - // - unaligned initial part, before the first word aligned address in text - // - body, scan by 2 words at a time - // - the last remaining part, < 2 word size - let len = text.len(); - let ptr = text.as_ptr(); - let usize_bytes = mem::size_of::(); - - // search up to an aligned boundary - let align = (ptr as usize) & (usize_bytes- 1); - let mut offset; - if align > 0 { - offset = cmp::min(usize_bytes - align, len); - if let Some(index) = text[..offset].iter().position(|elt| *elt == x) { - return Some(index); - } - } else { - offset = 0; - } - - // search the body of the text - let repeated_x = repeat_byte(x); - - if len >= 2 * usize_bytes { - while offset <= len - 2 * usize_bytes { - unsafe { - let u = *(ptr.offset(offset as isize) as *const usize); - let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize); - - // break if there is a matching byte - let zu = contains_zero_byte(u ^ repeated_x); - let zv = contains_zero_byte(v ^ repeated_x); - if zu || zv { - break; - } - } - offset += usize_bytes * 2; - } - } - - // find the byte after the point the body loop stopped - text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i) - } - - /// Return the last index matching the byte `a` in `text`. - pub fn memrchr(x: u8, text: &[u8]) -> Option { - // Scan for a single byte value by reading two `usize` words at a time. - // - // Split `text` in three parts - // - unaligned tail, after the last word aligned address in text - // - body, scan by 2 words at a time - // - the first remaining bytes, < 2 word size - let len = text.len(); - let ptr = text.as_ptr(); - let usize_bytes = mem::size_of::(); - - // search to an aligned boundary - let end_align = (ptr as usize + len) & (usize_bytes - 1); - let mut offset; - if end_align > 0 { - offset = len - cmp::min(usize_bytes - end_align, len); - if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) { - return Some(offset + index); - } - } else { - offset = len; - } - - // search the body of the text - let repeated_x = repeat_byte(x); - - while offset >= 2 * usize_bytes { - unsafe { - let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize); - let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize); - - // break if there is a matching byte - let zu = contains_zero_byte(u ^ repeated_x); - let zv = contains_zero_byte(v ^ repeated_x); - if zu || zv { - break; - } - } - offset -= 2 * usize_bytes; - } - - // find the byte before the point the body loop stopped - text[..offset].iter().rposition(|elt| *elt == x) - } - - // test fallback implementations on all plattforms - #[test] - fn matches_one() { - assert_eq!(Some(0), memchr(b'a', b"a")); - } - - #[test] - fn matches_begin() { - assert_eq!(Some(0), memchr(b'a', b"aaaa")); - } - - #[test] - fn matches_end() { - assert_eq!(Some(4), memchr(b'z', b"aaaaz")); - } - - #[test] - fn matches_nul() { - assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); - } - - #[test] - fn matches_past_nul() { - assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); - } - - #[test] - fn no_match_empty() { - assert_eq!(None, memchr(b'a', b"")); - } - - #[test] - fn no_match() { - assert_eq!(None, memchr(b'a', b"xyz")); - } - - #[test] - fn matches_one_reversed() { - assert_eq!(Some(0), memrchr(b'a', b"a")); - } - - #[test] - fn matches_begin_reversed() { - assert_eq!(Some(3), memrchr(b'a', b"aaaa")); - } - - #[test] - fn matches_end_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); - } - - #[test] - fn matches_nul_reversed() { - assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); - } - - #[test] - fn matches_past_nul_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); - } - - #[test] - fn no_match_empty_reversed() { - assert_eq!(None, memrchr(b'a', b"")); - } - - #[test] - fn no_match_reversed() { - assert_eq!(None, memrchr(b'a', b"xyz")); - } -} - -#[cfg(test)] -mod tests { - // test the implementations for the current plattform - use super::{memchr, memrchr}; - - #[test] - fn matches_one() { - assert_eq!(Some(0), memchr(b'a', b"a")); - } - - #[test] - fn matches_begin() { - assert_eq!(Some(0), memchr(b'a', b"aaaa")); - } - - #[test] - fn matches_end() { - assert_eq!(Some(4), memchr(b'z', b"aaaaz")); - } - - #[test] - fn matches_nul() { - assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); - } - - #[test] - fn matches_past_nul() { - assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); - } - - #[test] - fn no_match_empty() { - assert_eq!(None, memchr(b'a', b"")); - } - - #[test] - fn no_match() { - assert_eq!(None, memchr(b'a', b"xyz")); - } - - #[test] - fn matches_one_reversed() { - assert_eq!(Some(0), memrchr(b'a', b"a")); - } - - #[test] - fn matches_begin_reversed() { - assert_eq!(Some(3), memrchr(b'a', b"aaaa")); - } - - #[test] - fn matches_end_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); - } - - #[test] - fn matches_nul_reversed() { - assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); - } - - #[test] - fn matches_past_nul_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); - } - - #[test] - fn no_match_empty_reversed() { - assert_eq!(None, memrchr(b'a', b"")); - } - - #[test] - fn no_match_reversed() { - assert_eq!(None, memrchr(b'a', b"xyz")); - } -} diff --git a/artiq/firmware/libstd_artiq/io/mod.rs b/artiq/firmware/libstd_artiq/io/mod.rs deleted file mode 100644 index 6722b7485..000000000 --- a/artiq/firmware/libstd_artiq/io/mod.rs +++ /dev/null @@ -1,1844 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Traits, helpers, and type definitions for core I/O functionality. -//! -//! The `std::io` module contains a number of common things you'll need -//! when doing input and output. The most core part of this module is -//! the [`Read`][read] and [`Write`][write] traits, which provide the -//! most general interface for reading and writing input and output. -//! -//! [read]: trait.Read.html -//! [write]: trait.Write.html -//! -//! # Read and Write -//! -//! Because they are traits, `Read` and `Write` are implemented by a number -//! of other types, and you can implement them for your types too. As such, -//! you'll see a few different types of I/O throughout the documentation in -//! this module: `File`s, `TcpStream`s, and sometimes even `Vec`s. For -//! example, `Read` adds a `read()` method, which we can use on `File`s: -//! -//! ``` -//! use std::io; -//! use std::io::prelude::*; -//! use std::fs::File; -//! -//! # fn foo() -> io::Result<()> { -//! let mut f = try!(File::open("foo.txt")); -//! let mut buffer = [0; 10]; -//! -//! // read up to 10 bytes -//! try!(f.read(&mut buffer)); -//! -//! println!("The bytes: {:?}", buffer); -//! # Ok(()) -//! # } -//! ``` -//! -//! `Read` and `Write` are so important, implementors of the two traits have a -//! nickname: readers and writers. So you'll sometimes see 'a reader' instead -//! of 'a type that implements the `Read` trait'. Much easier! -//! -//! ## Seek and BufRead -//! -//! Beyond that, there are two important traits that are provided: [`Seek`][seek] -//! and [`BufRead`][bufread]. Both of these build on top of a reader to control -//! how the reading happens. `Seek` lets you control where the next byte is -//! coming from: -//! -//! ``` -//! use std::io; -//! use std::io::prelude::*; -//! use std::io::SeekFrom; -//! use std::fs::File; -//! -//! # fn foo() -> io::Result<()> { -//! let mut f = try!(File::open("foo.txt")); -//! let mut buffer = [0; 10]; -//! -//! // skip to the last 10 bytes of the file -//! try!(f.seek(SeekFrom::End(-10))); -//! -//! // read up to 10 bytes -//! try!(f.read(&mut buffer)); -//! -//! println!("The bytes: {:?}", buffer); -//! # Ok(()) -//! # } -//! ``` -//! -//! [seek]: trait.Seek.html -//! [bufread]: trait.BufRead.html -//! -//! `BufRead` uses an internal buffer to provide a number of other ways to read, but -//! to show it off, we'll need to talk about buffers in general. Keep reading! -//! -//! ## BufReader and BufWriter -//! -//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be -//! making near-constant calls to the operating system. To help with this, -//! `std::io` comes with two structs, `BufReader` and `BufWriter`, which wrap -//! readers and writers. The wrapper uses a buffer, reducing the number of -//! calls and providing nicer methods for accessing exactly what you want. -//! -//! For example, `BufReader` works with the `BufRead` trait to add extra -//! methods to any reader: -//! -//! ``` -//! use std::io; -//! use std::io::prelude::*; -//! use std::io::BufReader; -//! use std::fs::File; -//! -//! # fn foo() -> io::Result<()> { -//! let f = try!(File::open("foo.txt")); -//! let mut reader = BufReader::new(f); -//! let mut buffer = String::new(); -//! -//! // read a line into buffer -//! try!(reader.read_line(&mut buffer)); -//! -//! println!("{}", buffer); -//! # Ok(()) -//! # } -//! ``` -//! -//! `BufWriter` doesn't add any new ways of writing; it just buffers every call -//! to [`write()`][write()]: -//! -//! ``` -//! use std::io; -//! use std::io::prelude::*; -//! use std::io::BufWriter; -//! use std::fs::File; -//! -//! # fn foo() -> io::Result<()> { -//! let f = try!(File::create("foo.txt")); -//! { -//! let mut writer = BufWriter::new(f); -//! -//! // write a byte to the buffer -//! try!(writer.write(&[42])); -//! -//! } // the buffer is flushed once writer goes out of scope -//! -//! # Ok(()) -//! # } -//! ``` -//! -//! [write()]: trait.Write.html#tymethod.write -//! -//! ## Standard input and output -//! -//! A very common source of input is standard input: -//! -//! ``` -//! use std::io; -//! -//! # fn foo() -> io::Result<()> { -//! let mut input = String::new(); -//! -//! try!(io::stdin().read_line(&mut input)); -//! -//! println!("You typed: {}", input.trim()); -//! # Ok(()) -//! # } -//! ``` -//! -//! And a very common source of output is standard output: -//! -//! ``` -//! use std::io; -//! use std::io::prelude::*; -//! -//! # fn foo() -> io::Result<()> { -//! try!(io::stdout().write(&[42])); -//! # Ok(()) -//! # } -//! ``` -//! -//! Of course, using `io::stdout()` directly is less common than something like -//! `println!`. -//! -//! ## Iterator types -//! -//! A large number of the structures provided by `std::io` are for various -//! ways of iterating over I/O. For example, `Lines` is used to split over -//! lines: -//! -//! ``` -//! use std::io; -//! use std::io::prelude::*; -//! use std::io::BufReader; -//! use std::fs::File; -//! -//! # fn foo() -> io::Result<()> { -//! let f = try!(File::open("foo.txt")); -//! let reader = BufReader::new(f); -//! -//! for line in reader.lines() { -//! println!("{}", try!(line)); -//! } -//! -//! # Ok(()) -//! # } -//! ``` -//! -//! ## Functions -//! -//! There are a number of [functions][functions-list] that offer access to various -//! features. For example, we can use three of these functions to copy everything -//! from standard input to standard output: -//! -//! ``` -//! use std::io; -//! -//! # fn foo() -> io::Result<()> { -//! try!(io::copy(&mut io::stdin(), &mut io::stdout())); -//! # Ok(()) -//! # } -//! ``` -//! -//! [functions-list]: #functions-1 -//! -//! ## io::Result -//! -//! Last, but certainly not least, is [`io::Result`][result]. This type is used -//! as the return type of many `std::io` functions that can cause an error, and -//! can be returned from your own functions as well. Many of the examples in this -//! module use the [`try!`][try] macro: -//! -//! ``` -//! use std::io; -//! -//! fn read_input() -> io::Result<()> { -//! let mut input = String::new(); -//! -//! try!(io::stdin().read_line(&mut input)); -//! -//! println!("You typed: {}", input.trim()); -//! -//! Ok(()) -//! } -//! ``` -//! -//! The return type of `read_input()`, `io::Result<()>`, is a very common type -//! for functions which don't have a 'real' return value, but do want to return -//! errors if they happen. In this case, the only purpose of this function is -//! to read the line and print it, so we use `()`. -//! -//! [result]: type.Result.html -//! [try]: ../macro.try!.html -//! -//! ## Platform-specific behavior -//! -//! Many I/O functions throughout the standard library are documented to indicate -//! what various library or syscalls they are delegated to. This is done to help -//! applications both understand what's happening under the hood as well as investigate -//! any possibly unclear semantics. Note, however, that this is informative, not a binding -//! contract. The implementation of many of these functions are subject to change over -//! time and may call fewer or more syscalls/library functions. - -use core::cmp; -use core::fmt; -use core::iter::{Iterator}; -use core::marker::Sized; - use core::ops::{Drop, FnOnce}; -use core::option::Option::{self, Some, None}; -use core::result::Result::{Ok, Err}; -use core::result; - use alloc::string::String; - use alloc::vec::Vec; - use alloc::str; -mod memchr; - - pub use self::buffered::{BufReader, BufWriter, LineWriter}; - pub use self::buffered::IntoInnerError; - pub use self::cursor::Cursor; -pub use self::error::{Result, Error, ErrorKind}; -pub use self::util::{copy, sink, Sink, empty, Empty, repeat, Repeat}; - -pub mod prelude; - mod buffered; - mod cursor; -mod error; -mod impls; -mod util; - -const DEFAULT_BUF_SIZE: usize = 8 * 1024; - -// A few methods below (read_to_string, read_line) will append data into a -// `String` buffer, but we need to be pretty careful when doing this. The -// implementation will just call `.as_mut_vec()` and then delegate to a -// byte-oriented reading method, but we must ensure that when returning we never -// leave `buf` in a state such that it contains invalid UTF-8 in its bounds. -// -// To this end, we use an RAII guard (to protect against panics) which updates -// the length of the string when it is dropped. This guard initially truncates -// the string to the prior length and only after we've validated that the -// new contents are valid UTF-8 do we allow it to set a longer length. -// -// The unsafety in this function is twofold: -// -// 1. We're looking at the raw bytes of `buf`, so we take on the burden of UTF-8 -// checks. -// 2. We're passing a raw buffer to the function `f`, and it is expected that -// the function only *appends* bytes to the buffer. We'll get undefined -// behavior if existing bytes are overwritten to have non-UTF-8 data. - -fn append_to_string(buf: &mut String, f: F) -> Result - where F: FnOnce(&mut Vec) -> Result -{ - struct Guard<'a> { s: &'a mut Vec, len: usize } - impl<'a> Drop for Guard<'a> { - fn drop(&mut self) { - unsafe { self.s.set_len(self.len); } - } - } - - unsafe { - let mut g = Guard { len: buf.len(), s: buf.as_mut_vec() }; - let ret = f(g.s); - if str::from_utf8(&g.s[g.len..]).is_err() { - ret.and_then(|_| { - Err(Error::new(ErrorKind::InvalidData, - "stream did not contain valid UTF-8")) - }) - } else { - g.len = g.s.len(); - ret - } - } -} - -// This uses an adaptive system to extend the vector when it fills. We want to -// avoid paying to allocate and zero a huge chunk of memory if the reader only -// has 4 bytes while still making large reads if the reader does have a ton -// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every -// time is 4,500 times (!) slower than this if the reader has a very small -// amount of data to return. - -fn read_to_end(r: &mut R, buf: &mut Vec) -> Result { - let start_len = buf.len(); - let mut len = start_len; - let mut new_write_size = 16; - let ret; - loop { - if len == buf.len() { - if new_write_size < DEFAULT_BUF_SIZE { - new_write_size *= 2; - } - buf.resize(len + new_write_size, 0); - } - - match r.read(&mut buf[len..]) { - Ok(0) => { - ret = Ok(len - start_len); - break; - } - Ok(n) => len += n, - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => { - ret = Err(e); - break; - } - } - } - - buf.truncate(len); - ret -} - -/// The `Read` trait allows for reading bytes from a source. -/// -/// Implementors of the `Read` trait are sometimes called 'readers'. -/// -/// Readers are defined by one required method, `read()`. Each call to `read` -/// will attempt to pull bytes from this source into a provided buffer. A -/// number of other methods are implemented in terms of `read()`, giving -/// implementors a number of ways to read bytes while only needing to implement -/// a single method. -/// -/// Readers are intended to be composable with one another. Many implementors -/// throughout `std::io` take and provide types which implement the `Read` -/// trait. -/// -/// Please note that each call to `read` may involve a system call, and -/// therefore, using something that implements [`BufRead`][bufread], such as -/// [`BufReader`][bufreader], will be more efficient. -/// -/// [bufread]: trait.BufRead.html -/// [bufreader]: struct.BufReader.html -/// -/// # Examples -/// -/// [`File`][file]s implement `Read`: -/// -/// [file]: ../fs/struct.File.html -/// -/// ``` -/// use std::io; -/// use std::io::prelude::*; -/// use std::fs::File; -/// -/// # fn foo() -> io::Result<()> { -/// let mut f = try!(File::open("foo.txt")); -/// let mut buffer = [0; 10]; -/// -/// // read up to 10 bytes -/// try!(f.read(&mut buffer)); -/// -/// let mut buffer = vec![0; 10]; -/// // read the whole file -/// try!(f.read_to_end(&mut buffer)); -/// -/// // read into a String, so that you don't need to do the conversion. -/// let mut buffer = String::new(); -/// try!(f.read_to_string(&mut buffer)); -/// -/// // and more! See the other methods for more details. -/// # Ok(()) -/// # } -/// ``` -pub trait Read { - /// Pull some bytes from this source into the specified buffer, returning - /// how many bytes were read. - /// - /// This function does not provide any guarantees about whether it blocks - /// waiting for data, but if an object needs to block for a read but cannot - /// it will typically signal this via an `Err` return value. - /// - /// If the return value of this method is `Ok(n)`, then it must be - /// guaranteed that `0 <= n <= buf.len()`. A nonzero `n` value indicates - /// that the buffer `buf` has been filled in with `n` bytes of data from this - /// source. If `n` is `0`, then it can indicate one of two scenarios: - /// - /// 1. This reader has reached its "end of file" and will likely no longer - /// be able to produce bytes. Note that this does not mean that the - /// reader will *always* no longer be able to produce bytes. - /// 2. The buffer specified was 0 bytes in length. - /// - /// No guarantees are provided about the contents of `buf` when this - /// function is called, implementations cannot rely on any property of the - /// contents of `buf` being true. It is recommended that implementations - /// only write data to `buf` instead of reading its contents. - /// - /// # Errors - /// - /// If this function encounters any form of I/O or other error, an error - /// variant will be returned. If an error is returned then it must be - /// guaranteed that no bytes were read. - /// - /// # Examples - /// - /// [`File`][file]s implement `Read`: - /// - /// [file]: ../fs/struct.File.html - /// - /// ``` - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// # fn foo() -> io::Result<()> { - /// let mut f = try!(File::open("foo.txt")); - /// let mut buffer = [0; 10]; - /// - /// // read 10 bytes - /// try!(f.read(&mut buffer[..])); - /// # Ok(()) - /// # } - /// ``` - fn read(&mut self, buf: &mut [u8]) -> Result; - - /// Read all bytes until EOF in this source, placing them into `buf`. - /// - /// All bytes read from this source will be appended to the specified buffer - /// `buf`. This function will continuously call `read` to append more data to - /// `buf` until `read` returns either `Ok(0)` or an error of - /// non-`ErrorKind::Interrupted` kind. - /// - /// If successful, this function will return the total number of bytes read. - /// - /// # Errors - /// - /// If this function encounters an error of the kind - /// `ErrorKind::Interrupted` then the error is ignored and the operation - /// will continue. - /// - /// If any other read error is encountered then this function immediately - /// returns. Any bytes which have already been read will be appended to - /// `buf`. - /// - /// # Examples - /// - /// [`File`][file]s implement `Read`: - /// - /// [file]: ../fs/struct.File.html - /// - /// ``` - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// # fn foo() -> io::Result<()> { - /// let mut f = try!(File::open("foo.txt")); - /// let mut buffer = Vec::new(); - /// - /// // read the whole file - /// try!(f.read_to_end(&mut buffer)); - /// # Ok(()) - /// # } - /// ``` - - fn read_to_end(&mut self, buf: &mut Vec) -> Result { - read_to_end(self, buf) - } - - /// Read all bytes until EOF in this source, placing them into `buf`. - /// - /// If successful, this function returns the number of bytes which were read - /// and appended to `buf`. - /// - /// # Errors - /// - /// If the data in this stream is *not* valid UTF-8 then an error is - /// returned and `buf` is unchanged. - /// - /// See [`read_to_end()`][readtoend] for other error semantics. - /// - /// [readtoend]: #method.read_to_end - /// - /// # Examples - /// - /// [`File`][file]s implement `Read`: - /// - /// [file]: ../fs/struct.File.html - /// - /// ``` - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// # fn foo() -> io::Result<()> { - /// let mut f = try!(File::open("foo.txt")); - /// let mut buffer = String::new(); - /// - /// try!(f.read_to_string(&mut buffer)); - /// # Ok(()) - /// # } - /// ``` - - fn read_to_string(&mut self, buf: &mut String) -> Result { - // Note that we do *not* call `.read_to_end()` here. We are passing - // `&mut Vec` (the raw contents of `buf`) into the `read_to_end` - // method to fill it up. An arbitrary implementation could overwrite the - // entire contents of the vector, not just append to it (which is what - // we are expecting). - // - // To prevent extraneously checking the UTF-8-ness of the entire buffer - // we pass it to our hardcoded `read_to_end` implementation which we - // know is guaranteed to only read data into the end of the buffer. - append_to_string(buf, |b| read_to_end(self, b)) - } - - /// Read the exact number of bytes required to fill `buf`. - /// - /// This function reads as many bytes as necessary to completely fill the - /// specified buffer `buf`. - /// - /// No guarantees are provided about the contents of `buf` when this - /// function is called, implementations cannot rely on any property of the - /// contents of `buf` being true. It is recommended that implementations - /// only write data to `buf` instead of reading its contents. - /// - /// # Errors - /// - /// If this function encounters an error of the kind - /// `ErrorKind::Interrupted` then the error is ignored and the operation - /// will continue. - /// - /// If this function encounters an "end of file" before completely filling - /// the buffer, it returns an error of the kind `ErrorKind::UnexpectedEof`. - /// The contents of `buf` are unspecified in this case. - /// - /// If any other read error is encountered then this function immediately - /// returns. The contents of `buf` are unspecified in this case. - /// - /// If this function returns an error, it is unspecified how many bytes it - /// has read, but it will never read more than would be necessary to - /// completely fill the buffer. - /// - /// # Examples - /// - /// [`File`][file]s implement `Read`: - /// - /// [file]: ../fs/struct.File.html - /// - /// ``` - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// # fn foo() -> io::Result<()> { - /// let mut f = try!(File::open("foo.txt")); - /// let mut buffer = [0; 10]; - /// - /// // read exactly 10 bytes - /// try!(f.read_exact(&mut buffer)); - /// # Ok(()) - /// # } - /// ``` - fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> { - while !buf.is_empty() { - match self.read(buf) { - Ok(0) => break, - Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; } - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - if !buf.is_empty() { - Err(Error::new(ErrorKind::UnexpectedEof, - "failed to fill whole buffer")) - } else { - Ok(()) - } - } - - /// Creates a "by reference" adaptor for this instance of `Read`. - /// - /// The returned adaptor also implements `Read` and will simply borrow this - /// current reader. - /// - /// # Examples - /// - /// [`File`][file]s implement `Read`: - /// - /// [file]: ../fs/struct.File.html - /// - /// ``` - /// use std::io; - /// use std::io::Read; - /// use std::fs::File; - /// - /// # fn foo() -> io::Result<()> { - /// let mut f = try!(File::open("foo.txt")); - /// let mut buffer = Vec::new(); - /// let mut other_buffer = Vec::new(); - /// - /// { - /// let reference = f.by_ref(); - /// - /// // read at most 5 bytes - /// try!(reference.take(5).read_to_end(&mut buffer)); - /// - /// } // drop our &mut reference so we can use f again - /// - /// // original file still usable, read the rest - /// try!(f.read_to_end(&mut other_buffer)); - /// # Ok(()) - /// # } - /// ``` - fn by_ref(&mut self) -> &mut Self where Self: Sized { self } - - /// Transforms this `Read` instance to an `Iterator` over its bytes. - /// - /// The returned type implements `Iterator` where the `Item` is `Result`. The yielded item is `Ok` if a byte was successfully read and - /// `Err` otherwise for I/O errors. EOF is mapped to returning `None` from - /// this iterator. - /// - /// # Examples - /// - /// [`File`][file]s implement `Read`: - /// - /// [file]: ../fs/struct.File.html - /// - /// ``` - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// # fn foo() -> io::Result<()> { - /// let mut f = try!(File::open("foo.txt")); - /// - /// for byte in f.bytes() { - /// println!("{}", byte.unwrap()); - /// } - /// # Ok(()) - /// # } - /// ``` - fn bytes(self) -> Bytes where Self: Sized { - Bytes { inner: self } - } - - /// Transforms this `Read` instance to an `Iterator` over `char`s. - /// - /// This adaptor will attempt to interpret this reader as a UTF-8 encoded - /// sequence of characters. The returned iterator will return `None` once - /// EOF is reached for this reader. Otherwise each element yielded will be a - /// `Result` where `E` may contain information about what I/O error - /// occurred or where decoding failed. - /// - /// Currently this adaptor will discard intermediate data read, and should - /// be avoided if this is not desired. - /// - /// # Examples - /// - /// [`File`][file]s implement `Read`: - /// - /// [file]: ../fs/struct.File.html - /// - /// ``` - /// #![feature(io)] - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// # fn foo() -> io::Result<()> { - /// let mut f = try!(File::open("foo.txt")); - /// - /// for c in f.chars() { - /// println!("{}", c.unwrap()); - /// } - /// # Ok(()) - /// # } - /// ``` - fn chars(self) -> Chars where Self: Sized { - Chars { inner: self } - } - - /// Creates an adaptor which will chain this stream with another. - /// - /// The returned `Read` instance will first read all bytes from this object - /// until EOF is encountered. Afterwards the output is equivalent to the - /// output of `next`. - /// - /// # Examples - /// - /// [`File`][file]s implement `Read`: - /// - /// [file]: ../fs/struct.File.html - /// - /// ``` - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// # fn foo() -> io::Result<()> { - /// let mut f1 = try!(File::open("foo.txt")); - /// let mut f2 = try!(File::open("bar.txt")); - /// - /// let mut handle = f1.chain(f2); - /// let mut buffer = String::new(); - /// - /// // read the value into a String. We could use any Read method here, - /// // this is just one example. - /// try!(handle.read_to_string(&mut buffer)); - /// # Ok(()) - /// # } - /// ``` - fn chain(self, next: R) -> Chain where Self: Sized { - Chain { first: self, second: next, done_first: false } - } - - /// Creates an adaptor which will read at most `limit` bytes from it. - /// - /// This function returns a new instance of `Read` which will read at most - /// `limit` bytes, after which it will always return EOF (`Ok(0)`). Any - /// read errors will not count towards the number of bytes read and future - /// calls to `read` may succeed. - /// - /// # Examples - /// - /// [`File`][file]s implement `Read`: - /// - /// [file]: ../fs/struct.File.html - /// - /// ``` - /// use std::io; - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// # fn foo() -> io::Result<()> { - /// let mut f = try!(File::open("foo.txt")); - /// let mut buffer = [0; 5]; - /// - /// // read at most five bytes - /// let mut handle = f.take(5); - /// - /// try!(handle.read(&mut buffer)); - /// # Ok(()) - /// # } - /// ``` - fn take(self, limit: u64) -> Take where Self: Sized { - Take { inner: self, limit: limit } - } -} - -/// A trait for objects which are byte-oriented sinks. -/// -/// Implementors of the `Write` trait are sometimes called 'writers'. -/// -/// Writers are defined by two required methods, `write()` and `flush()`: -/// -/// * The `write()` method will attempt to write some data into the object, -/// returning how many bytes were successfully written. -/// -/// * The `flush()` method is useful for adaptors and explicit buffers -/// themselves for ensuring that all buffered data has been pushed out to the -/// 'true sink'. -/// -/// Writers are intended to be composable with one another. Many implementors -/// throughout `std::io` take and provide types which implement the `Write` -/// trait. -/// -/// # Examples -/// -/// ``` -/// use std::io::prelude::*; -/// use std::fs::File; -/// -/// # fn foo() -> std::io::Result<()> { -/// let mut buffer = try!(File::create("foo.txt")); -/// -/// try!(buffer.write(b"some bytes")); -/// # Ok(()) -/// # } -/// ``` -pub trait Write { - /// Write a buffer into this object, returning how many bytes were written. - /// - /// This function will attempt to write the entire contents of `buf`, but - /// the entire write may not succeed, or the write may also generate an - /// error. A call to `write` represents *at most one* attempt to write to - /// any wrapped object. - /// - /// Calls to `write` are not guaranteed to block waiting for data to be - /// written, and a write which would otherwise block can be indicated through - /// an `Err` variant. - /// - /// If the return value is `Ok(n)` then it must be guaranteed that - /// `0 <= n <= buf.len()`. A return value of `0` typically means that the - /// underlying object is no longer able to accept bytes and will likely not - /// be able to in the future as well, or that the buffer provided is empty. - /// - /// # Errors - /// - /// Each call to `write` may generate an I/O error indicating that the - /// operation could not be completed. If an error is returned then no bytes - /// in the buffer were written to this writer. - /// - /// It is **not** considered an error if the entire buffer could not be - /// written to this writer. - /// - /// # Examples - /// - /// ``` - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = try!(File::create("foo.txt")); - /// - /// try!(buffer.write(b"some bytes")); - /// # Ok(()) - /// # } - /// ``` - fn write(&mut self, buf: &[u8]) -> Result; - - /// Flush this output stream, ensuring that all intermediately buffered - /// contents reach their destination. - /// - /// # Errors - /// - /// It is considered an error if not all bytes could be written due to - /// I/O errors or EOF being reached. - /// - /// # Examples - /// - /// ``` - /// use std::io::prelude::*; - /// use std::io::BufWriter; - /// use std::fs::File; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = BufWriter::new(try!(File::create("foo.txt"))); - /// - /// try!(buffer.write(b"some bytes")); - /// try!(buffer.flush()); - /// # Ok(()) - /// # } - /// ``` - fn flush(&mut self) -> Result<()>; - - /// Attempts to write an entire buffer into this write. - /// - /// This method will continuously call `write` while there is more data to - /// write. This method will not return until the entire buffer has been - /// successfully written or an error occurs. The first error generated from - /// this method will be returned. - /// - /// # Errors - /// - /// This function will return the first error that `write` returns. - /// - /// # Examples - /// - /// ``` - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = try!(File::create("foo.txt")); - /// - /// try!(buffer.write_all(b"some bytes")); - /// # Ok(()) - /// # } - /// ``` - fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { - while !buf.is_empty() { - match self.write(buf) { - Ok(0) => return Err(Error::new(ErrorKind::WriteZero, - "failed to write whole buffer")), - Ok(n) => buf = &buf[n..], - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - Ok(()) - } - - /// Writes a formatted string into this writer, returning any error - /// encountered. - /// - /// This method is primarily used to interface with the - /// [`format_args!`][formatargs] macro, but it is rare that this should - /// explicitly be called. The [`write!`][write] macro should be favored to - /// invoke this method instead. - /// - /// [formatargs]: ../macro.format_args!.html - /// [write]: ../macro.write!.html - /// - /// This function internally uses the [`write_all`][writeall] method on - /// this trait and hence will continuously write data so long as no errors - /// are received. This also means that partial writes are not indicated in - /// this signature. - /// - /// [writeall]: #method.write_all - /// - /// # Errors - /// - /// This function will return any I/O error reported while formatting. - /// - /// # Examples - /// - /// ``` - /// use std::io::prelude::*; - /// use std::fs::File; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = try!(File::create("foo.txt")); - /// - /// // this call - /// try!(write!(buffer, "{:.*}", 2, 1.234567)); - /// // turns into this: - /// try!(buffer.write_fmt(format_args!("{:.*}", 2, 1.234567))); - /// # Ok(()) - /// # } - /// ``` - fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()> { - // Create a shim which translates a Write to a fmt::Write and saves - // off I/O errors. instead of discarding them - struct Adaptor<'a, T: ?Sized + 'a> { - inner: &'a mut T, - error: Result<()>, - } - - impl<'a, T: Write + ?Sized> fmt::Write for Adaptor<'a, T> { - fn write_str(&mut self, s: &str) -> fmt::Result { - match self.inner.write_all(s.as_bytes()) { - Ok(()) => Ok(()), - Err(e) => { - self.error = Err(e); - Err(fmt::Error) - } - } - } - } - - let mut output = Adaptor { inner: self, error: Ok(()) }; - match fmt::write(&mut output, fmt) { - Ok(()) => Ok(()), - Err(..) => { - // check if the error came from the underlying `Write` or not - if output.error.is_err() { - output.error - } else { - Err(Error::new(ErrorKind::Other, "formatter error")) - } - } - } - } - - /// Creates a "by reference" adaptor for this instance of `Write`. - /// - /// The returned adaptor also implements `Write` and will simply borrow this - /// current writer. - /// - /// # Examples - /// - /// ``` - /// use std::io::Write; - /// use std::fs::File; - /// - /// # fn foo() -> std::io::Result<()> { - /// let mut buffer = try!(File::create("foo.txt")); - /// - /// let reference = buffer.by_ref(); - /// - /// // we can use reference just like our original buffer - /// try!(reference.write_all(b"some bytes")); - /// # Ok(()) - /// # } - /// ``` - fn by_ref(&mut self) -> &mut Self where Self: Sized { self } -} - -/// The `Seek` trait provides a cursor which can be moved within a stream of -/// bytes. -/// -/// The stream typically has a fixed size, allowing seeking relative to either -/// end or the current offset. -/// -/// # Examples -/// -/// [`File`][file]s implement `Seek`: -/// -/// [file]: ../fs/struct.File.html -/// -/// ``` -/// use std::io; -/// use std::io::prelude::*; -/// use std::fs::File; -/// use std::io::SeekFrom; -/// -/// # fn foo() -> io::Result<()> { -/// let mut f = try!(File::open("foo.txt")); -/// -/// // move the cursor 42 bytes from the start of the file -/// try!(f.seek(SeekFrom::Start(42))); -/// # Ok(()) -/// # } -/// ``` -pub trait Seek { - /// Seek to an offset, in bytes, in a stream. - /// - /// A seek beyond the end of a stream is allowed, but implementation - /// defined. - /// - /// If the seek operation completed successfully, - /// this method returns the new position from the start of the stream. - /// That position can be used later with `SeekFrom::Start`. - /// - /// # Errors - /// - /// Seeking to a negative offset is considered an error. - fn seek(&mut self, pos: SeekFrom) -> Result; -} - -/// Enumeration of possible methods to seek within an I/O object. -#[derive(Copy, PartialEq, Eq, Clone, Debug)] -pub enum SeekFrom { - /// Set the offset to the provided number of bytes. - Start(u64), - - /// Set the offset to the size of this object plus the specified number of - /// bytes. - /// - /// It is possible to seek beyond the end of an object, but it's an error to - /// seek before byte 0. - End(i64), - - /// Set the offset to the current position plus the specified number of - /// bytes. - /// - /// It is possible to seek beyond the end of an object, but it's an error to - /// seek before byte 0. - Current(i64), -} - - -fn read_until(r: &mut R, delim: u8, buf: &mut Vec) - -> Result { - let mut read = 0; - loop { - let (done, used) = { - let available = match r.fill_buf() { - Ok(n) => n, - Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, - Err(e) => return Err(e) - }; - match memchr::memchr(delim, available) { - Some(i) => { - buf.extend_from_slice(&available[..i + 1]); - (true, i + 1) - } - None => { - buf.extend_from_slice(available); - (false, available.len()) - } - } - }; - r.consume(used); - read += used; - if done || used == 0 { - return Ok(read); - } - } -} - -/// A `BufRead` is a type of `Read`er which has an internal buffer, allowing it -/// to perform extra ways of reading. -/// -/// For example, reading line-by-line is inefficient without using a buffer, so -/// if you want to read by line, you'll need `BufRead`, which includes a -/// [`read_line()`][readline] method as well as a [`lines()`][lines] iterator. -/// -/// [readline]: #method.read_line -/// [lines]: #method.lines -/// -/// # Examples -/// -/// A locked standard input implements `BufRead`: -/// -/// ``` -/// use std::io; -/// use std::io::prelude::*; -/// -/// let stdin = io::stdin(); -/// for line in stdin.lock().lines() { -/// println!("{}", line.unwrap()); -/// } -/// ``` -/// -/// If you have something that implements `Read`, you can use the [`BufReader` -/// type][bufreader] to turn it into a `BufRead`. -/// -/// For example, [`File`][file] implements `Read`, but not `BufRead`. -/// `BufReader` to the rescue! -/// -/// [bufreader]: struct.BufReader.html -/// [file]: ../fs/struct.File.html -/// -/// ``` -/// use std::io::{self, BufReader}; -/// use std::io::prelude::*; -/// use std::fs::File; -/// -/// # fn foo() -> io::Result<()> { -/// let f = try!(File::open("foo.txt")); -/// let f = BufReader::new(f); -/// -/// for line in f.lines() { -/// println!("{}", line.unwrap()); -/// } -/// -/// # Ok(()) -/// # } -/// ``` -/// - -pub trait BufRead: Read { - /// Fills the internal buffer of this object, returning the buffer contents. - /// - /// This function is a lower-level call. It needs to be paired with the - /// [`consume`][consume] method to function properly. When calling this - /// method, none of the contents will be "read" in the sense that later - /// calling `read` may return the same contents. As such, `consume` must be - /// called with the number of bytes that are consumed from this buffer to - /// ensure that the bytes are never returned twice. - /// - /// [consume]: #tymethod.consume - /// - /// An empty buffer returned indicates that the stream has reached EOF. - /// - /// # Errors - /// - /// This function will return an I/O error if the underlying reader was - /// read, but returned an error. - /// - /// # Examples - /// - /// A locked standard input implements `BufRead`: - /// - /// ``` - /// use std::io; - /// use std::io::prelude::*; - /// - /// let stdin = io::stdin(); - /// let mut stdin = stdin.lock(); - /// - /// // we can't have two `&mut` references to `stdin`, so use a block - /// // to end the borrow early. - /// let length = { - /// let buffer = stdin.fill_buf().unwrap(); - /// - /// // work with buffer - /// println!("{:?}", buffer); - /// - /// buffer.len() - /// }; - /// - /// // ensure the bytes we worked with aren't returned again later - /// stdin.consume(length); - /// ``` - fn fill_buf(&mut self) -> Result<&[u8]>; - - /// Tells this buffer that `amt` bytes have been consumed from the buffer, - /// so they should no longer be returned in calls to `read`. - /// - /// This function is a lower-level call. It needs to be paired with the - /// [`fill_buf`][fillbuf] method to function properly. This function does - /// not perform any I/O, it simply informs this object that some amount of - /// its buffer, returned from `fill_buf`, has been consumed and should no - /// longer be returned. As such, this function may do odd things if - /// `fill_buf` isn't called before calling it. - /// - /// [fillbuf]: #tymethod.fill_buf - /// - /// The `amt` must be `<=` the number of bytes in the buffer returned by - /// `fill_buf`. - /// - /// # Examples - /// - /// Since `consume()` is meant to be used with [`fill_buf()`][fillbuf], - /// that method's example includes an example of `consume()`. - fn consume(&mut self, amt: usize); - - /// Read all bytes into `buf` until the delimiter `byte` is reached. - /// - /// This function will read bytes from the underlying stream until the - /// delimiter or EOF is found. Once found, all bytes up to, and including, - /// the delimiter (if found) will be appended to `buf`. - /// - /// If this reader is currently at EOF then this function will not modify - /// `buf` and will return `Ok(n)` where `n` is the number of bytes which - /// were read. - /// - /// # Errors - /// - /// This function will ignore all instances of `ErrorKind::Interrupted` and - /// will otherwise return any errors returned by `fill_buf`. - /// - /// If an I/O error is encountered then all bytes read so far will be - /// present in `buf` and its length will have been adjusted appropriately. - /// - /// # Examples - /// - /// A locked standard input implements `BufRead`. In this example, we'll - /// read from standard input until we see an `a` byte. - /// - /// ``` - /// use std::io; - /// use std::io::prelude::*; - /// - /// fn foo() -> io::Result<()> { - /// let stdin = io::stdin(); - /// let mut stdin = stdin.lock(); - /// let mut buffer = Vec::new(); - /// - /// try!(stdin.read_until(b'a', &mut buffer)); - /// - /// println!("{:?}", buffer); - /// # Ok(()) - /// # } - /// ``` - fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result { - read_until(self, byte, buf) - } - - /// Read all bytes until a newline (the 0xA byte) is reached, and append - /// them to the provided buffer. - /// - /// This function will read bytes from the underlying stream until the - /// newline delimiter (the 0xA byte) or EOF is found. Once found, all bytes - /// up to, and including, the delimiter (if found) will be appended to - /// `buf`. - /// - /// If this reader is currently at EOF then this function will not modify - /// `buf` and will return `Ok(n)` where `n` is the number of bytes which - /// were read. - /// - /// # Errors - /// - /// This function has the same error semantics as `read_until` and will also - /// return an error if the read bytes are not valid UTF-8. If an I/O error - /// is encountered then `buf` may contain some bytes already read in the - /// event that all data read so far was valid UTF-8. - /// - /// # Examples - /// - /// A locked standard input implements `BufRead`. In this example, we'll - /// read all of the lines from standard input. If we were to do this in - /// an actual project, the [`lines()`][lines] method would be easier, of - /// course. - /// - /// [lines]: #method.lines - /// - /// ``` - /// use std::io; - /// use std::io::prelude::*; - /// - /// let stdin = io::stdin(); - /// let mut stdin = stdin.lock(); - /// let mut buffer = String::new(); - /// - /// while stdin.read_line(&mut buffer).unwrap() > 0 { - /// // work with buffer - /// println!("{:?}", buffer); - /// - /// buffer.clear(); - /// } - /// ``` - fn read_line(&mut self, buf: &mut String) -> Result { - // Note that we are not calling the `.read_until` method here, but - // rather our hardcoded implementation. For more details as to why, see - // the comments in `read_to_end`. - append_to_string(buf, |b| read_until(self, b'\n', b)) - } - - /// Returns an iterator over the contents of this reader split on the byte - /// `byte`. - /// - /// The iterator returned from this function will return instances of - /// `io::Result>`. Each vector returned will *not* have the - /// delimiter byte at the end. - /// - /// This function will yield errors whenever `read_until` would have also - /// yielded an error. - /// - /// # Examples - /// - /// A locked standard input implements `BufRead`. In this example, we'll - /// read some input from standard input, splitting on commas. - /// - /// ``` - /// use std::io; - /// use std::io::prelude::*; - /// - /// let stdin = io::stdin(); - /// - /// for content in stdin.lock().split(b',') { - /// println!("{:?}", content.unwrap()); - /// } - /// ``` - fn split(self, byte: u8) -> Split where Self: Sized { - Split { buf: self, delim: byte } - } - - /// Returns an iterator over the lines of this reader. - /// - /// The iterator returned from this function will yield instances of - /// `io::Result`. Each string returned will *not* have a newline - /// byte (the 0xA byte) or CRLF (0xD, 0xA bytes) at the end. - /// - /// # Examples - /// - /// A locked standard input implements `BufRead`: - /// - /// ``` - /// use std::io; - /// use std::io::prelude::*; - /// - /// let stdin = io::stdin(); - /// - /// for line in stdin.lock().lines() { - /// println!("{}", line.unwrap()); - /// } - /// ``` - fn lines(self) -> Lines where Self: Sized { - Lines { buf: self } - } -} - -/// Adaptor to chain together two readers. -/// -/// This struct is generally created by calling [`chain()`][chain] on a reader. -/// Please see the documentation of `chain()` for more details. -/// -/// [chain]: trait.Read.html#method.chain -pub struct Chain { - first: T, - second: U, - done_first: bool, -} - -impl Read for Chain { - fn read(&mut self, buf: &mut [u8]) -> Result { - if !self.done_first { - match self.first.read(buf)? { - 0 => { self.done_first = true; } - n => return Ok(n), - } - } - self.second.read(buf) - } -} - - -impl BufRead for Chain { - fn fill_buf(&mut self) -> Result<&[u8]> { - if !self.done_first { - match self.first.fill_buf()? { - buf if buf.len() == 0 => { self.done_first = true; } - buf => return Ok(buf), - } - } - self.second.fill_buf() - } - - fn consume(&mut self, amt: usize) { - if !self.done_first { - self.first.consume(amt) - } else { - self.second.consume(amt) - } - } -} - -/// Reader adaptor which limits the bytes read from an underlying reader. -/// -/// This struct is generally created by calling [`take()`][take] on a reader. -/// Please see the documentation of `take()` for more details. -/// -/// [take]: trait.Read.html#method.take -pub struct Take { - inner: T, - limit: u64, -} - -impl Take { - /// Returns the number of bytes that can be read before this instance will - /// return EOF. - /// - /// # Note - /// - /// This instance may reach EOF after reading fewer bytes than indicated by - /// this method if the underlying `Read` instance reaches EOF. - pub fn limit(&self) -> u64 { self.limit } -} - -impl Read for Take { - fn read(&mut self, buf: &mut [u8]) -> Result { - // Don't call into inner reader at all at EOF because it may still block - if self.limit == 0 { - return Ok(0); - } - - let max = cmp::min(buf.len() as u64, self.limit) as usize; - let n = self.inner.read(&mut buf[..max])?; - self.limit -= n as u64; - Ok(n) - } -} - - -impl BufRead for Take { - fn fill_buf(&mut self) -> Result<&[u8]> { - // Don't call into inner reader at all at EOF because it may still block - if self.limit == 0 { - return Ok(&[]); - } - - let buf = self.inner.fill_buf()?; - let cap = cmp::min(buf.len() as u64, self.limit) as usize; - Ok(&buf[..cap]) - } - - fn consume(&mut self, amt: usize) { - // Don't let callers reset the limit by passing an overlarge value - let amt = cmp::min(amt as u64, self.limit) as usize; - self.limit -= amt as u64; - self.inner.consume(amt); - } -} - -/// An iterator over `u8` values of a reader. -/// -/// This struct is generally created by calling [`bytes()`][bytes] on a reader. -/// Please see the documentation of `bytes()` for more details. -/// -/// [bytes]: trait.Read.html#method.bytes -pub struct Bytes { - inner: R, -} - -impl Iterator for Bytes { - type Item = Result; - - fn next(&mut self) -> Option> { - let mut buf = [0]; - match self.inner.read(&mut buf) { - Ok(0) => None, - Ok(..) => Some(Ok(buf[0])), - Err(e) => Some(Err(e)), - } - } -} - -/// An iterator over the `char`s of a reader. -/// -/// This struct is generally created by calling [`chars()`][chars] on a reader. -/// Please see the documentation of `chars()` for more details. -/// -/// [chars]: trait.Read.html#method.chars -pub struct Chars { - inner: R, -} - -/// An enumeration of possible errors that can be generated from the `Chars` -/// adapter. -#[derive(Debug)] -pub enum CharsError { - /// Variant representing that the underlying stream was read successfully - /// but it did not contain valid utf8 data. - NotUtf8, - - /// Variant representing that an I/O error occurred. - Other(Error), -} - -impl Iterator for Chars { - type Item = result::Result; - - fn next(&mut self) -> Option> { - let mut buf = [0]; - let first_byte = match self.inner.read(&mut buf) { - Ok(0) => return None, - Ok(..) => buf[0], - Err(e) => return Some(Err(CharsError::Other(e))), - }; - let width = ::core::str::utf8_char_width(first_byte); - if width == 1 { return Some(Ok(first_byte as char)) } - if width == 0 { return Some(Err(CharsError::NotUtf8)) } - let mut buf = [first_byte, 0, 0, 0]; - { - let mut start = 1; - while start < width { - match self.inner.read(&mut buf[start..width]) { - Ok(0) => return Some(Err(CharsError::NotUtf8)), - Ok(n) => start += n, - Err(e) => return Some(Err(CharsError::Other(e))), - } - } - } - Some(match str::from_utf8(&buf[..width]).ok() { - Some(s) => Ok(s.chars().next().unwrap()), - None => Err(CharsError::NotUtf8), - }) - } -} - -impl fmt::Display for CharsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - CharsError::NotUtf8 => { - "byte stream did not contain valid utf8".fmt(f) - } - CharsError::Other(ref e) => e.fmt(f), - } - } -} - -/// An iterator over the contents of an instance of `BufRead` split on a -/// particular byte. -/// -/// This struct is generally created by calling [`split()`][split] on a -/// `BufRead`. Please see the documentation of `split()` for more details. -/// -/// [split]: trait.BufRead.html#method.split - -pub struct Split { - buf: B, - delim: u8, -} - - -impl Iterator for Split { - type Item = Result>; - - fn next(&mut self) -> Option>> { - let mut buf = Vec::new(); - match self.buf.read_until(self.delim, &mut buf) { - Ok(0) => None, - Ok(_n) => { - if buf[buf.len() - 1] == self.delim { - buf.pop(); - } - Some(Ok(buf)) - } - Err(e) => Some(Err(e)) - } - } -} - -/// An iterator over the lines of an instance of `BufRead`. -/// -/// This struct is generally created by calling [`lines()`][lines] on a -/// `BufRead`. Please see the documentation of `lines()` for more details. -/// -/// [lines]: trait.BufRead.html#method.lines - -pub struct Lines { - buf: B, -} - - -impl Iterator for Lines { - type Item = Result; - - fn next(&mut self) -> Option> { - let mut buf = String::new(); - match self.buf.read_line(&mut buf) { - Ok(0) => None, - Ok(_n) => { - if buf.ends_with("\n") { - buf.pop(); - if buf.ends_with("\r") { - buf.pop(); - } - } - Some(Ok(buf)) - } - Err(e) => Some(Err(e)) - } - } -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use io::prelude::*; - use io; - use super::Cursor; - use test; - use super::repeat; - - #[test] - fn read_until() { - let mut buf = Cursor::new(&b"12"[..]); - let mut v = Vec::new(); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 2); - assert_eq!(v, b"12"); - - let mut buf = Cursor::new(&b"1233"[..]); - let mut v = Vec::new(); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3); - assert_eq!(v, b"123"); - v.truncate(0); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1); - assert_eq!(v, b"3"); - v.truncate(0); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0); - assert_eq!(v, []); - } - - #[test] - fn split() { - let buf = Cursor::new(&b"12"[..]); - let mut s = buf.split(b'3'); - assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']); - assert!(s.next().is_none()); - - let buf = Cursor::new(&b"1233"[..]); - let mut s = buf.split(b'3'); - assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']); - assert_eq!(s.next().unwrap().unwrap(), vec![]); - assert!(s.next().is_none()); - } - - #[test] - fn read_line() { - let mut buf = Cursor::new(&b"12"[..]); - let mut v = String::new(); - assert_eq!(buf.read_line(&mut v).unwrap(), 2); - assert_eq!(v, "12"); - - let mut buf = Cursor::new(&b"12\n\n"[..]); - let mut v = String::new(); - assert_eq!(buf.read_line(&mut v).unwrap(), 3); - assert_eq!(v, "12\n"); - v.truncate(0); - assert_eq!(buf.read_line(&mut v).unwrap(), 1); - assert_eq!(v, "\n"); - v.truncate(0); - assert_eq!(buf.read_line(&mut v).unwrap(), 0); - assert_eq!(v, ""); - } - - #[test] - fn lines() { - let buf = Cursor::new(&b"12\r"[..]); - let mut s = buf.lines(); - assert_eq!(s.next().unwrap().unwrap(), "12\r".to_string()); - assert!(s.next().is_none()); - - let buf = Cursor::new(&b"12\r\n\n"[..]); - let mut s = buf.lines(); - assert_eq!(s.next().unwrap().unwrap(), "12".to_string()); - assert_eq!(s.next().unwrap().unwrap(), "".to_string()); - assert!(s.next().is_none()); - } - - #[test] - fn read_to_end() { - let mut c = Cursor::new(&b""[..]); - let mut v = Vec::new(); - assert_eq!(c.read_to_end(&mut v).unwrap(), 0); - assert_eq!(v, []); - - let mut c = Cursor::new(&b"1"[..]); - let mut v = Vec::new(); - assert_eq!(c.read_to_end(&mut v).unwrap(), 1); - assert_eq!(v, b"1"); - - let cap = 1024 * 1024; - let data = (0..cap).map(|i| (i / 3) as u8).collect::>(); - let mut v = Vec::new(); - let (a, b) = data.split_at(data.len() / 2); - assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len()); - assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len()); - assert_eq!(v, data); - } - - #[test] - fn read_to_string() { - let mut c = Cursor::new(&b""[..]); - let mut v = String::new(); - assert_eq!(c.read_to_string(&mut v).unwrap(), 0); - assert_eq!(v, ""); - - let mut c = Cursor::new(&b"1"[..]); - let mut v = String::new(); - assert_eq!(c.read_to_string(&mut v).unwrap(), 1); - assert_eq!(v, "1"); - - let mut c = Cursor::new(&b"\xff"[..]); - let mut v = String::new(); - assert!(c.read_to_string(&mut v).is_err()); - } - - #[test] - fn read_exact() { - let mut buf = [0; 4]; - - let mut c = Cursor::new(&b""[..]); - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), - io::ErrorKind::UnexpectedEof); - - let mut c = Cursor::new(&b"123"[..]).chain(Cursor::new(&b"456789"[..])); - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"1234"); - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"5678"); - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), - io::ErrorKind::UnexpectedEof); - } - - #[test] - fn read_exact_slice() { - let mut buf = [0; 4]; - - let mut c = &b""[..]; - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), - io::ErrorKind::UnexpectedEof); - - let mut c = &b"123"[..]; - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), - io::ErrorKind::UnexpectedEof); - // make sure the optimized (early returning) method is being used - assert_eq!(&buf, &[0; 4]); - - let mut c = &b"1234"[..]; - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"1234"); - - let mut c = &b"56789"[..]; - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"5678"); - assert_eq!(c, b"9"); - } - - #[test] - fn take_eof() { - struct R; - - impl Read for R { - fn read(&mut self, _: &mut [u8]) -> io::Result { - Err(io::Error::new(io::ErrorKind::Other, "")) - } - } - impl BufRead for R { - fn fill_buf(&mut self) -> io::Result<&[u8]> { - Err(io::Error::new(io::ErrorKind::Other, "")) - } - fn consume(&mut self, _amt: usize) { } - } - - let mut buf = [0; 1]; - assert_eq!(0, R.take(0).read(&mut buf).unwrap()); - assert_eq!(b"", R.take(0).fill_buf().unwrap()); - } - - fn cmp_bufread(mut br1: Br1, mut br2: Br2, exp: &[u8]) { - let mut cat = Vec::new(); - loop { - let consume = { - let buf1 = br1.fill_buf().unwrap(); - let buf2 = br2.fill_buf().unwrap(); - let minlen = if buf1.len() < buf2.len() { buf1.len() } else { buf2.len() }; - assert_eq!(buf1[..minlen], buf2[..minlen]); - cat.extend_from_slice(&buf1[..minlen]); - minlen - }; - if consume == 0 { - break; - } - br1.consume(consume); - br2.consume(consume); - } - assert_eq!(br1.fill_buf().unwrap().len(), 0); - assert_eq!(br2.fill_buf().unwrap().len(), 0); - assert_eq!(&cat[..], &exp[..]) - } - - #[test] - fn chain_bufread() { - let testdata = b"ABCDEFGHIJKL"; - let chain1 = (&testdata[..3]).chain(&testdata[3..6]) - .chain(&testdata[6..9]) - .chain(&testdata[9..]); - let chain2 = (&testdata[..4]).chain(&testdata[4..8]) - .chain(&testdata[8..]); - cmp_bufread(chain1, chain2, &testdata[..]); - } - - #[bench] - fn bench_read_to_end(b: &mut test::Bencher) { - b.iter(|| { - let mut lr = repeat(1).take(10000000); - let mut vec = Vec::with_capacity(1024); - super::read_to_end(&mut lr, &mut vec) - }); - } -} diff --git a/artiq/firmware/libstd_artiq/io/prelude.rs b/artiq/firmware/libstd_artiq/io/prelude.rs deleted file mode 100644 index 58df71e69..000000000 --- a/artiq/firmware/libstd_artiq/io/prelude.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The I/O Prelude -//! -//! The purpose of this module is to alleviate imports of many common I/O traits -//! by adding a glob import to the top of I/O heavy modules: -//! -//! ``` -//! # #![allow(unused_imports)] -//! use std::io::prelude::*; -//! ``` - -pub use super::{Read, Write, Seek}; - pub use super::BufRead; diff --git a/artiq/firmware/libstd_artiq/io/util.rs b/artiq/firmware/libstd_artiq/io/util.rs deleted file mode 100644 index b3c2d45fd..000000000 --- a/artiq/firmware/libstd_artiq/io/util.rs +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(missing_copy_implementations)] - -use io::{self, Read, Write, ErrorKind}; - use io::BufRead; - -/// Copies the entire contents of a reader into a writer. -/// -/// This function will continuously read data from `reader` and then -/// write it into `writer` in a streaming fashion until `reader` -/// returns EOF. -/// -/// On success, the total number of bytes that were copied from -/// `reader` to `writer` is returned. -/// -/// # Errors -/// -/// This function will return an error immediately if any call to `read` or -/// `write` returns an error. All instances of `ErrorKind::Interrupted` are -/// handled by this function and the underlying operation is retried. -/// -/// # Examples -/// -/// ``` -/// use std::io; -/// -/// # fn foo() -> io::Result<()> { -/// let mut reader: &[u8] = b"hello"; -/// let mut writer: Vec = vec![]; -/// -/// try!(io::copy(&mut reader, &mut writer)); -/// -/// assert_eq!(reader, &writer[..]); -/// # Ok(()) -/// # } -/// ``` -pub fn copy(reader: &mut R, writer: &mut W) -> io::Result - where R: Read, W: Write -{ - let mut buf = [0; super::DEFAULT_BUF_SIZE]; - let mut written = 0; - loop { - let len = match reader.read(&mut buf) { - Ok(0) => return Ok(written), - Ok(len) => len, - Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, - Err(e) => return Err(e), - }; - writer.write_all(&buf[..len])?; - written += len as u64; - } -} - -/// A reader which is always at EOF. -/// -/// This struct is generally created by calling [`empty()`][empty]. Please see -/// the documentation of `empty()` for more details. -/// -/// [empty]: fn.empty.html -pub struct Empty { _priv: () } - -/// Constructs a new handle to an empty reader. -/// -/// All reads from the returned reader will return `Ok(0)`. -/// -/// # Examples -/// -/// A slightly sad example of not reading anything into a buffer: -/// -/// ``` -/// use std::io::{self, Read}; -/// -/// let mut buffer = String::new(); -/// io::empty().read_to_string(&mut buffer).unwrap(); -/// assert!(buffer.is_empty()); -/// ``` -pub fn empty() -> Empty { Empty { _priv: () } } - -impl Read for Empty { - fn read(&mut self, _buf: &mut [u8]) -> io::Result { Ok(0) } -} - -impl BufRead for Empty { - fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) } - fn consume(&mut self, _n: usize) {} -} - -/// A reader which yields one byte over and over and over and over and over and... -/// -/// This struct is generally created by calling [`repeat()`][repeat]. Please -/// see the documentation of `repeat()` for more details. -/// -/// [repeat]: fn.repeat.html -pub struct Repeat { byte: u8 } - -/// Creates an instance of a reader that infinitely repeats one byte. -/// -/// All reads from this reader will succeed by filling the specified buffer with -/// the given byte. -/// -/// # Examples -/// -/// ``` -/// use std::io::{self, Read}; -/// -/// let mut buffer = [0; 3]; -/// io::repeat(0b101).read_exact(&mut buffer).unwrap(); -/// assert_eq!(buffer, [0b101, 0b101, 0b101]); -/// ``` -pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } } - -impl Read for Repeat { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - for slot in &mut *buf { - *slot = self.byte; - } - Ok(buf.len()) - } -} - -/// A writer which will move data into the void. -/// -/// This struct is generally created by calling [`sink()`][sink]. Please -/// see the documentation of `sink()` for more details. -/// -/// [sink]: fn.sink.html -pub struct Sink { _priv: () } - -/// Creates an instance of a writer which will successfully consume all data. -/// -/// All calls to `write` on the returned instance will return `Ok(buf.len())` -/// and the contents of the buffer will not be inspected. -/// -/// # Examples -/// -/// ```rust -/// use std::io::{self, Write}; -/// -/// let mut buffer = vec![1, 2, 3, 5, 8]; -/// let num_bytes = io::sink().write(&mut buffer).unwrap(); -/// assert_eq!(num_bytes, 5); -/// ``` -pub fn sink() -> Sink { Sink { _priv: () } } - -impl Write for Sink { - fn write(&mut self, buf: &[u8]) -> io::Result { Ok(buf.len()) } - fn flush(&mut self) -> io::Result<()> { Ok(()) } -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - - use io::prelude::*; - use io::{copy, sink, empty, repeat}; - - #[test] - fn copy_copies() { - let mut r = repeat(0).take(4); - let mut w = sink(); - assert_eq!(copy(&mut r, &mut w).unwrap(), 4); - - let mut r = repeat(0).take(1 << 17); - assert_eq!(copy(&mut r as &mut Read, &mut w as &mut Write).unwrap(), 1 << 17); - } - - #[test] - fn sink_sinks() { - let mut s = sink(); - assert_eq!(s.write(&[]).unwrap(), 0); - assert_eq!(s.write(&[0]).unwrap(), 1); - assert_eq!(s.write(&[0; 1024]).unwrap(), 1024); - assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024); - } - - #[test] - fn empty_reads() { - let mut e = empty(); - assert_eq!(e.read(&mut []).unwrap(), 0); - assert_eq!(e.read(&mut [0]).unwrap(), 0); - assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0); - assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0); - } - - #[test] - fn repeat_repeats() { - let mut r = repeat(4); - let mut b = [0; 1024]; - assert_eq!(r.read(&mut b).unwrap(), 1024); - assert!(b.iter().all(|b| *b == 4)); - } - - #[test] - fn take_some_bytes() { - assert_eq!(repeat(4).take(100).bytes().count(), 100); - assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4); - assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20); - } -} diff --git a/artiq/firmware/libstd_artiq/lib.rs b/artiq/firmware/libstd_artiq/lib.rs deleted file mode 100644 index 285d985e5..000000000 --- a/artiq/firmware/libstd_artiq/lib.rs +++ /dev/null @@ -1,43 +0,0 @@ -#![feature(lang_items, asm, alloc, needs_panic_runtime, - unicode, raw, int_error_internals, try_from, macro_reexport, - allow_internal_unstable, stmt_expr_attributes, str_internals)] -#![no_std] -#![needs_panic_runtime] - -extern crate std_unicode; -#[macro_use] -#[macro_reexport(vec, format)] -extern crate alloc; -extern crate failure; - -pub use core::{any, cell, clone, cmp, convert, default, hash, iter, marker, mem, num, - ops, option, ptr, result, sync, - char, i16, i32, i64, i8, isize, u16, u32, u64, u8, usize, f32, f64}; -pub use alloc::{arc, rc, raw_vec}; -pub use alloc::{binary_heap, borrow, boxed, btree_map, btree_set, fmt, linked_list, slice, - str, string, vec, vec_deque}; - -pub mod prelude { - pub mod v1 { - pub use core::prelude::v1::*; - pub use alloc::boxed::Box; - pub use alloc::borrow::ToOwned; - pub use alloc::string::{String, ToString}; - pub use alloc::vec::Vec; - } -} - -pub mod error; -pub mod io; - -// Provide Box::new wrapper -#[cfg(any(not(feature="alloc"), not(feature="io_error_alloc")))] -struct FakeBox(core::marker::PhantomData); -#[cfg(any(not(feature="alloc"), not(feature="io_error_alloc")))] -impl FakeBox { - fn new(val: T) -> T { - val - } -} - -impl failure::Fail for error::Error + Send + Sync {} diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 70875e37a..f7eb87ace 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -24,7 +24,6 @@ unwind_backtrace = { path = "../libunwind_backtrace" } io = { path = "../libio", features = ["byteorder"] } alloc_list = { path = "../liballoc_list" } board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp"] } -std_artiq = { path = "../libstd_artiq", features = ["alloc", "io_error_alloc"] } logger_artiq = { path = "../liblogger_artiq" } board_artiq = { path = "../libboard_artiq" } proto_artiq = { path = "../libproto_artiq", features = ["log", "alloc"] } diff --git a/artiq/firmware/runtime/analyzer.rs b/artiq/firmware/runtime/analyzer.rs index f6842e433..6ea47862e 100644 --- a/artiq/firmware/runtime/analyzer.rs +++ b/artiq/firmware/runtime/analyzer.rs @@ -1,6 +1,6 @@ -use io::{self, Write}; +use io::{Write, Error as IoError}; use board_misoc::{csr, cache}; -use sched::{Io, TcpListener, TcpStream}; +use sched::{Io, TcpListener, TcpStream, Error as SchedError}; use analyzer_proto::*; const BUFFER_SIZE: usize = 512 * 1024; @@ -35,7 +35,7 @@ fn disarm() { } } -fn worker(stream: &mut TcpStream) -> Result<(), io::Error<::std::io::Error>> { +fn worker(stream: &mut TcpStream) -> Result<(), IoError> { let data = unsafe { &BUFFER.data[..] }; let overflow_occurred = unsafe { csr::rtio_analyzer::message_encoder_overflow_read() != 0 }; let total_byte_count = unsafe { csr::rtio_analyzer::dma_byte_count_read() }; diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index c2bc6a651..aae7bc99c 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -1,5 +1,5 @@ use kernel_proto as kern; -use sched::Io; +use sched::{Io, Error as SchedError}; use session::{kern_acknowledge, kern_send, Error}; #[cfg(has_rtio_core)] use rtio_mgt; @@ -290,7 +290,7 @@ mod spi { } } -pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result> { +pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result> { match request { #[cfg(has_rtio_core)] &kern::RtioInitRequest => { diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index e43d11be1..deb78bf97 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -1,6 +1,8 @@ +#![feature(lang_items, alloc, global_allocator, try_from, nonzero, nll, needs_panic_runtime)] #![no_std] -#![feature(lang_items, alloc, global_allocator, try_from, nonzero, nll)] +#![needs_panic_runtime] +#[macro_use] extern crate alloc; extern crate failure; #[macro_use] @@ -19,8 +21,6 @@ extern crate io; #[macro_use] extern crate board_misoc; extern crate board_artiq; -#[macro_use] -extern crate std_artiq as std; extern crate logger_artiq; extern crate proto_artiq; diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 6cfe48017..222108885 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -4,11 +4,16 @@ use io::{Write, ProtoWrite, Error as IoError}; use board_misoc::boot; use logger_artiq::BufferLogger; use mgmt_proto::*; -use sched::Io; -use sched::{TcpListener, TcpStream}; +use sched::{Io, TcpListener, TcpStream, Error as SchedError}; use profiler; -fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error<::std::io::Error>> { +impl From for Error { + fn from(value: SchedError) -> Error { + Error::Io(IoError::Other(value)) + } +} + +fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error> { read_magic(stream)?; info!("new connection from {}", stream.remote_endpoint()); @@ -22,7 +27,7 @@ fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error<::std::io::Error> } Request::ClearLog => { - BufferLogger::with(|logger| -> Result<(), Error<::std::io::Error>> { + BufferLogger::with(|logger| -> Result<(), Error> { let mut buffer = io.until_ok(|| logger.buffer())?; Ok(buffer.clear()) })?; @@ -31,7 +36,7 @@ fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error<::std::io::Error> } Request::PullLog => { - BufferLogger::with(|logger| -> Result<(), Error<::std::io::Error>> { + BufferLogger::with(|logger| -> Result<(), Error> { loop { // Do this *before* acquiring the buffer, since that sets the log level // to OFF. diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index 9297bd11b..67b582ba2 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -1,8 +1,7 @@ use alloc::btree_map::BTreeMap; use moninj_proto::*; -use sched::Io; -use sched::{TcpListener, TcpStream}; +use sched::{Io, TcpListener, TcpStream, Error as SchedError}; use board_misoc::{clock, csr}; #[cfg(has_drtio)] use drtioaux; @@ -145,7 +144,7 @@ fn read_injection_status(channel: u32, probe: u8) -> u8 { 0 } -fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error<::std::io::Error>> { +fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error> { let mut watch_list = BTreeMap::new(); let mut next_check = 0; diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index d6f2efcb7..5578be444 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -6,14 +6,30 @@ use core::cell::{Cell, RefCell}; use alloc::Vec; use fringe::OwnedStack; use fringe::generator::{Generator, Yielder, State as GeneratorState}; +use smoltcp::Error as NetworkError; use smoltcp::wire::IpEndpoint; use smoltcp::socket::{SocketHandle, SocketRef}; use io::{Read, Write}; use board_misoc::clock; -use std::io::{Result, Error, ErrorKind}; use urc::Urc; +#[derive(Fail, Debug)] +pub enum Error { + #[fail(display = "interrupted")] + Interrupted, + #[fail(display = "timed out")] + TimedOut, + #[fail(display = "network error: {}", _0)] + Network(NetworkError) +} + +impl From for Error { + fn from(value: NetworkError) -> Error { + Error::Network(value) + } +} + type SocketSet = ::smoltcp::socket::SocketSet<'static, 'static, 'static>; #[derive(Debug)] @@ -194,7 +210,7 @@ impl<'a> Io<'a> { self.yielder.expect("cannot suspend the scheduler thread") } - pub fn sleep(&self, duration_ms: u64) -> Result<()> { + pub fn sleep(&self, duration_ms: u64) -> Result<(), Error> { let request = WaitRequest { timeout: Some(clock::get_ms() + duration_ms), event: None @@ -202,27 +218,27 @@ impl<'a> Io<'a> { match self.yielder().suspend(request) { WaitResult::TimedOut => Ok(()), - WaitResult::Interrupted => Err(Error::new(ErrorKind::Interrupted, "")), + WaitResult::Interrupted => Err(Error::Interrupted), _ => unreachable!() } } - fn suspend(&self, request: WaitRequest) -> Result<()> { + fn suspend(&self, request: WaitRequest) -> Result<(), Error> { match self.yielder().suspend(request) { WaitResult::Completed => Ok(()), - WaitResult::TimedOut => Err(Error::new(ErrorKind::TimedOut, "")), - WaitResult::Interrupted => Err(Error::new(ErrorKind::Interrupted, "")) + WaitResult::TimedOut => Err(Error::TimedOut), + WaitResult::Interrupted => Err(Error::Interrupted) } } - pub fn relinquish(&self) -> Result<()> { + pub fn relinquish(&self) -> Result<(), Error> { self.suspend(WaitRequest { timeout: None, event: None }) } - pub fn until bool>(&self, mut f: F) -> Result<()> { + pub fn until bool>(&self, mut f: F) -> Result<(), Error> { let f = unsafe { mem::transmute::<&mut FnMut() -> bool, *mut FnMut() -> bool>(&mut f) }; self.suspend(WaitRequest { timeout: None, @@ -230,7 +246,9 @@ impl<'a> Io<'a> { }) } - pub fn until_ok result::Result>(&self, mut f: F) -> Result { + pub fn until_ok(&self, mut f: F) -> Result + where F: FnMut() -> result::Result + { let mut value = None; self.until(|| { if let Ok(result) = f() { @@ -241,7 +259,7 @@ impl<'a> Io<'a> { Ok(value.unwrap()) } - pub fn join(&self, handle: ThreadHandle) -> Result<()> { + pub fn join(&self, handle: ThreadHandle) -> Result<(), Error> { self.until(move || handle.terminated()) } } @@ -257,11 +275,6 @@ macro_rules! until { }) } - -use ::smoltcp::Error as ErrorLower; -// https://github.com/rust-lang/rust/issues/26264 -// type ErrorLower = ::smoltcp::Error; - type TcpSocketBuffer = ::smoltcp::socket::TcpSocketBuffer<'static>; type TcpSocketLower = ::smoltcp::socket::TcpSocket<'static>; @@ -313,25 +326,17 @@ impl<'a> TcpListener<'a> { self.with_lower(|s| s.local_endpoint()) } - pub fn listen>(&self, endpoint: T) -> Result<()> { + pub fn listen>(&self, endpoint: T) -> Result<(), Error> { let endpoint = endpoint.into(); self.with_lower(|mut s| s.listen(endpoint)) .map(|()| { self.endpoint.set(endpoint); () }) - .map_err(|err| { - match err { - ErrorLower::Illegal => - Error::new(ErrorKind::Other, "already listening"), - ErrorLower::Unaddressable => - Error::new(ErrorKind::InvalidInput, "port cannot be zero"), - _ => unreachable!() - } - }) + .map_err(|err| err.into()) } - pub fn accept(&self) -> Result> { + pub fn accept(&self) -> Result, Error> { // We're waiting until at least one half of the connection becomes open. // This handles the case where a remote socket immediately sends a FIN-- // that still counts as accepting even though nothing may be sent. @@ -436,7 +441,7 @@ impl<'a> TcpStream<'a> { self.with_lower(|mut s| s.set_keep_alive(value)) } - pub fn close(&self) -> Result<()> { + pub fn close(&self) -> Result<(), Error> { self.with_lower(|mut s| s.close()); until!(self, TcpSocketLower, |s| !s.is_open())?; // right now the socket may be in TIME-WAIT state. if we don't give it a chance to send @@ -449,7 +454,7 @@ impl<'a> TcpStream<'a> { impl<'a> Read for TcpStream<'a> { type ReadError = Error; - fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> Result { // Only borrow the underlying socket for the span of the next statement. let result = self.with_lower(|mut s| s.recv_slice(buf)); match result { @@ -458,14 +463,14 @@ impl<'a> Read for TcpStream<'a> { until!(self, TcpSocketLower, |s| s.can_recv() || !s.may_recv())?; match self.with_lower(|mut s| s.recv_slice(buf)) { Ok(length) => Ok(length), - Err(ErrorLower::Illegal) => Ok(0), + Err(NetworkError::Illegal) => Ok(0), _ => unreachable!() } } // Fast path: we had data in buffer. Ok(length) => Ok(length), // Error path: the receive half of the socket is not open. - Err(ErrorLower::Illegal) => Ok(0), + Err(NetworkError::Illegal) => Ok(0), // No other error may be returned. Err(_) => unreachable!() } @@ -476,7 +481,7 @@ impl<'a> Write for TcpStream<'a> { type WriteError = Error; type FlushError = Error; - fn write(&mut self, buf: &[u8]) -> Result { + fn write(&mut self, buf: &[u8]) -> Result { // Only borrow the underlying socket for the span of the next statement. let result = self.with_lower(|mut s| s.send_slice(buf)); match result { @@ -485,25 +490,25 @@ impl<'a> Write for TcpStream<'a> { until!(self, TcpSocketLower, |s| s.can_send() || !s.may_send())?; match self.with_lower(|mut s| s.send_slice(buf)) { Ok(length) => Ok(length), - Err(ErrorLower::Illegal) => Ok(0), + Err(NetworkError::Illegal) => Ok(0), _ => unreachable!() } } // Fast path: we had space in buffer. Ok(length) => Ok(length), // Error path: the transmit half of the socket is not open. - Err(ErrorLower::Illegal) => Ok(0), + Err(NetworkError::Illegal) => Ok(0), // No other error may be returned. Err(_) => unreachable!() } } - fn flush(&mut self) -> Result<()> { + fn flush(&mut self) -> Result<(), Self::FlushError> { until!(self, TcpSocketLower, |s| s.send_queue() == 0 || !s.may_send())?; if self.with_lower(|s| s.send_queue()) == 0 { Ok(()) } else { - Err(Error::new(ErrorKind::ConnectionAborted, "connection aborted")) + Err(Error::Network(NetworkError::Illegal)) } } } diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 445b0ea5d..e1380c125 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -2,12 +2,11 @@ use core::{mem, str, cell::{Cell, RefCell}, fmt::Write as FmtWrite}; use alloc::{Vec, String}; use byteorder::{ByteOrder, NetworkEndian}; -use io::{self, Read, Write, Error as IoError}; +use io::{Read, Write, Error as IoError}; use board_misoc::{ident, cache, config}; use {mailbox, rpc_queue, kernel}; use urc::Urc; -use sched::{ThreadHandle, Io}; -use sched::{TcpListener, TcpStream}; +use sched::{ThreadHandle, Io, TcpListener, TcpStream, Error as SchedError}; #[cfg(has_rtio_core)] use rtio_mgt; use rtio_dma::Manager as DmaManager; @@ -45,14 +44,14 @@ impl From> for Error { } } -impl From<::std::io::Error> for Error<::std::io::Error> { - fn from(value: ::std::io::Error) -> Error<::std::io::Error> { - Error::Protocol(host::Error::Io(io::Error::Other(value))) +impl From for Error { + fn from(value: SchedError) -> Error { + Error::Protocol(host::Error::Io(IoError::Other(value))) } } -impl From> for Error<::std::io::Error> { - fn from(value: io::Error<::std::io::Error>) -> Error<::std::io::Error> { +impl From> for Error { + fn from(value: IoError) -> Error { Error::Protocol(host::Error::Io(value)) } } @@ -149,7 +148,7 @@ fn host_write(writer: &mut W, reply: host::Reply) -> Result<(), IoError Result<(), Error<::std::io::Error>> { +pub fn kern_send(io: &Io, request: &kern::Message) -> Result<(), Error> { match request { &kern::LoadRequest(_) => debug!("comm->kern LoadRequest(...)"), &kern::DmaRetrieveReply { trace, duration } => { @@ -165,8 +164,8 @@ pub fn kern_send(io: &Io, request: &kern::Message) -> Result<(), Error<::std::io Ok(io.until(mailbox::acknowledged)?) } -fn kern_recv_notrace(io: &Io, f: F) -> Result> - where F: FnOnce(&kern::Message) -> Result> { +fn kern_recv_notrace(io: &Io, f: F) -> Result> + where F: FnOnce(&kern::Message) -> Result> { io.until(|| mailbox::receive() != 0)?; if !kernel::validate(mailbox::receive()) { return Err(Error::InvalidPointer(mailbox::receive())) @@ -191,21 +190,21 @@ fn kern_recv_dotrace(reply: &kern::Message) { } #[inline(always)] -fn kern_recv(io: &Io, f: F) -> Result> - where F: FnOnce(&kern::Message) -> Result> { +fn kern_recv(io: &Io, f: F) -> Result> + where F: FnOnce(&kern::Message) -> Result> { kern_recv_notrace(io, |reply| { kern_recv_dotrace(reply); f(reply) }) } -pub fn kern_acknowledge() -> Result<(), Error<::std::io::Error>> { +pub fn kern_acknowledge() -> Result<(), Error> { mailbox::acknowledge(); Ok(()) } unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) - -> Result<(), Error<::std::io::Error>> { + -> Result<(), Error> { if session.running() { unexpected!("attempted to load a new kernel while a kernel was running") } @@ -229,7 +228,7 @@ unsafe fn kern_load(io: &Io, session: &mut Session, library: &[u8]) }) } -fn kern_run(session: &mut Session) -> Result<(), Error<::std::io::Error>> { +fn kern_run(session: &mut Session) -> Result<(), Error> { if session.kernel_state != KernelState::Loaded { unexpected!("attempted to run a kernel while not in Loaded state") } @@ -241,7 +240,7 @@ fn kern_run(session: &mut Session) -> Result<(), Error<::std::io::Error>> { fn process_host_message(io: &Io, stream: &mut TcpStream, - session: &mut Session) -> Result<(), Error<::std::io::Error>> { + session: &mut Session) -> Result<(), Error> { match host_read(stream)? { host::Request::SystemInfo => { host_write(stream, host::Reply::SystemInfo { @@ -326,7 +325,7 @@ fn process_host_message(io: &Io, other => unexpected!("unexpected reply from kernel CPU: {:?}", other) } })?; - rpc::recv_return(stream, &tag, slot, &|size| -> Result<_, Error<::std::io::Error>> { + rpc::recv_return(stream, &tag, slot, &|size| -> Result<_, Error> { kern_send(io, &kern::RpcRecvReply(Ok(size)))?; Ok(kern_recv(io, |reply| { match reply { @@ -374,7 +373,7 @@ fn process_host_message(io: &Io, } fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, - session: &mut Session) -> Result> { + session: &mut Session) -> Result> { kern_recv_notrace(io, |request| { match (request, session.kernel_state) { (&kern::LoadReply(_), KernelState::Loaded) | @@ -397,7 +396,7 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, match request { &kern::Log(args) => { - use std::fmt::Write; + use core::fmt::Write; session.log_buffer .write_fmt(args) .unwrap_or_else(|_| warn!("cannot append to session log buffer")); @@ -529,7 +528,7 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, } fn process_kern_queued_rpc(stream: &mut TcpStream, - _session: &mut Session) -> Result<(), Error<::std::io::Error>> { + _session: &mut Session) -> Result<(), Error> { rpc_queue::dequeue(|slice| { debug!("comm<-kern (async RPC)"); let length = NetworkEndian::read_u32(slice) as usize; @@ -542,7 +541,7 @@ fn process_kern_queued_rpc(stream: &mut TcpStream, fn host_kernel_worker(io: &Io, stream: &mut TcpStream, - congress: &mut Congress) -> Result<(), Error<::std::io::Error>> { + congress: &mut Congress) -> Result<(), Error> { let mut session = Session::new(congress); loop { @@ -581,7 +580,7 @@ fn host_kernel_worker(io: &Io, fn flash_kernel_worker(io: &Io, congress: &mut Congress, - config_key: &str) -> Result<(), Error<::std::io::Error>> { + config_key: &str) -> Result<(), Error> { let mut session = Session::new(congress); config::read(config_key, |result| { @@ -686,10 +685,10 @@ pub fn thread(io: Io) { let mut stream = TcpStream::from_handle(&io, stream); match host_kernel_worker(&io, &mut stream, &mut *congress) { Ok(()) => (), - Err(Error::Protocol(host::Error::Io(io::Error::UnexpectedEnd))) => + Err(Error::Protocol(host::Error::Io(IoError::UnexpectedEnd))) => info!("connection closed"), - Err(Error::Protocol(host::Error::Io(io::Error::Other(ref err)))) - if err.kind() == ::std::io::ErrorKind::Interrupted => + Err(Error::Protocol(host::Error::Io( + IoError::Other(SchedError::Interrupted)))) => info!("kernel interrupted"), Err(err) => { congress.finished_cleanly.set(false); @@ -708,10 +707,9 @@ pub fn thread(io: Io) { match flash_kernel_worker(&io, &mut *congress, "idle_kernel") { Ok(()) => info!("idle kernel finished, standing by"), - Err(Error::Protocol(host::Error::Io(io::Error::Other(ref err)))) - if err.kind() == ::std::io::ErrorKind::Interrupted => { - info!("idle kernel interrupted"); - } + Err(Error::Protocol(host::Error::Io( + IoError::Other(SchedError::Interrupted)))) => + info!("idle kernel interrupted"), Err(Error::KernelNotFound) => { info!("no idle kernel found"); while io.relinquish().is_ok() {} From 520aade8fe09a3b90a3290905350a6ee449045e9 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 15 May 2018 14:43:22 +0200 Subject: [PATCH 0771/2457] serwb/scrambler: cleanup/fix potential bug --- artiq/gateware/serwb/scrambler.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/artiq/gateware/serwb/scrambler.py b/artiq/gateware/serwb/scrambler.py index e1e8ac17e..d5149dfac 100644 --- a/artiq/gateware/serwb/scrambler.py +++ b/artiq/gateware/serwb/scrambler.py @@ -98,16 +98,17 @@ class Descrambler(Module): NextState("SYNC_DATA") ) fsm.act("SYNC_DATA", - If((sink.k[0] == 1) & - (sink.d[:8] == K(29,7)), - sink.ack.eq(1), - descrambler.reset.eq(1) - ).Else( - sink.ack.eq(source.ack), - source.stb.eq(sink.stb), - source.data.eq(descrambler.o), - If(source.stb & source.ack, - descrambler.ce.eq(1) + If(sink.stb, + If((sink.k == 1) & (sink.d == K(29,7)), + sink.ack.eq(1), + descrambler.reset.eq(1) + ).Else( + source.stb.eq(1), + source.data.eq(descrambler.o), + If(source.ack, + sink.ack.eq(1), + descrambler.ce.eq(1) + ) ) ) ) From 913d1e8e1272174d1cd465a73eab0261bc66ceb9 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 15 May 2018 16:39:39 +0200 Subject: [PATCH 0772/2457] serwb: add generic low-speed phy (125Mhz linerate, same phy for ultrascale/7-series) --- artiq/gateware/serwb/__init__.py | 2 +- artiq/gateware/serwb/genphy.py | 418 +++++++++++++++++++++++++++++++ 2 files changed, 419 insertions(+), 1 deletion(-) create mode 100644 artiq/gateware/serwb/genphy.py diff --git a/artiq/gateware/serwb/__init__.py b/artiq/gateware/serwb/__init__.py index 3ebf3f028..7c437f6f3 100644 --- a/artiq/gateware/serwb/__init__.py +++ b/artiq/gateware/serwb/__init__.py @@ -1 +1 @@ -from artiq.gateware.serwb import s7phy, kusphy, phy, core, packet, etherbone +from artiq.gateware.serwb import s7phy, kusphy, genphy, phy, core, packet, etherbone diff --git a/artiq/gateware/serwb/genphy.py b/artiq/gateware/serwb/genphy.py new file mode 100644 index 000000000..07ab731ad --- /dev/null +++ b/artiq/gateware/serwb/genphy.py @@ -0,0 +1,418 @@ +from migen import * +from migen.genlib.io import * +from migen.genlib.misc import BitSlip, WaitTimer + +from misoc.interconnect import stream +from misoc.interconnect.csr import * +from misoc.cores.code_8b10b import Encoder, Decoder + +from artiq.gateware.serwb.scrambler import Scrambler, Descrambler + + +def K(x, y): + return (y << 5) | x + + +class _SerdesClocking(Module): + def __init__(self, pads, mode="master"): + self.refclk = Signal() + + # # # + + # In Master mode, generate the clock with 180° phase shift so that Slave + # can use this clock to sample data + if mode == "master": + self.specials += DDROutput(0, 1, self.refclk) + self.specials += DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) + # In Slave mode, use the clock provided by Master + elif mode == "slave": + self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk) + + +class _SerdesTX(Module): + def __init__(self, pads, mode="master"): + # Control + self.idle = idle = Signal() + self.comma = comma = Signal() + + # Datapath + self.ce = ce = Signal() + self.k = k = Signal(4) + self.d = d = Signal(32) + + # # # + + # 8b10b encoder + self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) + self.comb += encoder.ce.eq(ce) + + # 40 --> 1 converter + converter = stream.Converter(40, 1) + self.submodules += converter + self.comb += [ + converter.sink.stb.eq(1), + converter.source.ack.eq(1), + # Enable pipeline when converter accepts the 40 bits + ce.eq(converter.sink.ack), + # If not idle, connect encoder to converter + If(~idle, + converter.sink.data.eq(Cat(*[encoder.output[i] for i in range(4)])) + ), + # If comma, send K28.5 + If(comma, + encoder.k[0].eq(1), + encoder.d[0].eq(K(28,5)), + # Else connect TX to encoder + ).Else( + encoder.k[0].eq(k[0]), + encoder.k[1].eq(k[1]), + encoder.k[2].eq(k[2]), + encoder.k[3].eq(k[3]), + encoder.d[0].eq(d[0:8]), + encoder.d[1].eq(d[8:16]), + encoder.d[2].eq(d[16:24]), + encoder.d[3].eq(d[24:32]) + ) + ] + + # Data output (on rising edge of sys_clk) + data = Signal() + self.sync += data.eq(converter.source.data) + self.specials += DifferentialOutput(data, pads.tx_p, pads.tx_n) + + +class _SerdesRX(Module): + def __init__(self, pads, mode="master"): + # Control + self.bitslip_value = bitslip_value = Signal(6) + + # Status + self.idle = idle = Signal() + self.comma = comma = Signal() + + # Datapath + self.ce = ce = Signal() + self.k = k = Signal(4) + self.d = d = Signal(32) + + # # # + + # Input data (on rising edge of sys_clk) + data = Signal() + data_d = Signal() + self.specials += DifferentialInput(pads.rx_p, pads.rx_n, data) + self.sync += data_d.eq(data) + + # 1 --> 40 converter and bitslip + converter = stream.Converter(1, 40) + self.submodules += converter + bitslip = CEInserter()(BitSlip(40)) + self.submodules += bitslip + self.comb += [ + converter.sink.stb.eq(1), + converter.source.ack.eq(1), + # Enable pipeline when converter outputs the 40 bits + ce.eq(converter.source.stb), + # Connect input data to converter + converter.sink.data.eq(data), + # Connect converter to bitslip + bitslip.ce.eq(ce), + bitslip.value.eq(bitslip_value), + bitslip.i.eq(converter.source.data) + ] + + # 8b10b decoder + self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] + self.comb += [decoders[i].ce.eq(ce) for i in range(4)] + self.comb += [ + # Connect bitslip to decoder + decoders[0].input.eq(bitslip.o[0:10]), + decoders[1].input.eq(bitslip.o[10:20]), + decoders[2].input.eq(bitslip.o[20:30]), + decoders[3].input.eq(bitslip.o[30:40]), + # Connect decoder to output + self.k.eq(Cat(*[decoders[i].k for i in range(4)])), + self.d.eq(Cat(*[decoders[i].d for i in range(4)])), + ] + + # Status + idle_timer = WaitTimer(256) + self.submodules += idle_timer + self.comb += [ + idle_timer.wait.eq(1), + self.idle.eq(idle_timer.done & + ((bitslip.o == 0) | (bitslip.o == (2**40-1)))), + self.comma.eq( + (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & + (decoders[1].k == 0) & (decoders[1].d == 0) & + (decoders[2].k == 0) & (decoders[2].d == 0) & + (decoders[3].k == 0) & (decoders[3].d == 0)) + ] + + +@ResetInserter() +class _Serdes(Module): + def __init__(self, pads, mode="master"): + self.submodules.clocking = _SerdesClocking(pads, mode) + self.submodules.tx = _SerdesTX(pads, mode) + self.submodules.rx = _SerdesRX(pads, mode) + + +# SERWB Master <--> Slave physical synchronization process: +# 1) Master sends idle patterns (zeroes) to Slave to reset it. +# 2) Master sends K28.5 commas to allow Slave to calibrate, Slave sends idle patterns. +# 3) Slave sends K28.5 commas to allow Master to calibrate, Master sends K28.5 commas. +# 4) Master stops sending K28.5 commas. +# 5) Slave stops sending K28.5 commas. +# 6) Physical link is ready. + + +@ResetInserter() +class _SerdesMasterInit(Module): + def __init__(self, serdes, timeout): + self.ready = Signal() + self.error = Signal() + + # # # + + self.bitslip = bitslip = Signal(max=40) + + self.submodules.timer = timer = WaitTimer(timeout) + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + fsm.act("IDLE", + NextValue(bitslip, 0), + NextState("RESET_SLAVE"), + serdes.tx.idle.eq(1) + ) + fsm.act("RESET_SLAVE", + timer.wait.eq(1), + If(timer.done, + timer.wait.eq(0), + NextState("SEND_PATTERN") + ), + serdes.tx.idle.eq(1) + ) + fsm.act("SEND_PATTERN", + If(~serdes.rx.idle, + timer.wait.eq(1), + If(timer.done, + NextState("CHECK_PATTERN") + ) + ), + serdes.tx.comma.eq(1) + ) + fsm.act("WAIT_STABLE", + timer.wait.eq(1), + If(timer.done, + timer.wait.eq(0), + NextState("CHECK_PATTERN") + ), + serdes.tx.comma.eq(1) + ) + fsm.act("CHECK_PATTERN", + If(serdes.rx.comma, + timer.wait.eq(1), + If(timer.done, + NextState("READY") + ) + ).Else( + NextState("INC_BITSLIP") + ), + serdes.tx.comma.eq(1) + ) + self.comb += serdes.rx.bitslip_value.eq(bitslip) + fsm.act("INC_BITSLIP", + NextState("WAIT_STABLE"), + If(bitslip == (40 - 1), + NextState("ERROR") + ).Else( + NextValue(bitslip, bitslip + 1) + ), + serdes.tx.comma.eq(1) + ) + fsm.act("READY", + self.ready.eq(1) + ) + fsm.act("ERROR", + self.error.eq(1) + ) + + +@ResetInserter() +class _SerdesSlaveInit(Module, AutoCSR): + def __init__(self, serdes, timeout): + self.ready = Signal() + self.error = Signal() + + # # # + + self.bitslip = bitslip = Signal(max=40) + + self.submodules.timer = timer = WaitTimer(timeout) + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + # reset + fsm.act("IDLE", + NextValue(bitslip, 0), + timer.wait.eq(1), + If(timer.done, + timer.wait.eq(0), + NextState("WAIT_STABLE"), + ), + serdes.tx.idle.eq(1) + ) + fsm.act("WAIT_STABLE", + timer.wait.eq(1), + If(timer.done, + timer.wait.eq(0), + NextState("CHECK_PATTERN") + ), + serdes.tx.idle.eq(1) + ) + fsm.act("CHECK_PATTERN", + If(serdes.rx.comma, + timer.wait.eq(1), + If(timer.done, + NextState("SEND_PATTERN") + ) + ).Else( + NextState("INC_BITSLIP") + ), + serdes.tx.idle.eq(1) + ) + self.comb += serdes.rx.bitslip_value.eq(bitslip) + fsm.act("INC_BITSLIP", + NextState("WAIT_STABLE"), + If(bitslip == (40 - 1), + NextState("ERROR") + ).Else( + NextValue(bitslip, bitslip + 1) + ), + serdes.tx.idle.eq(1) + ) + fsm.act("SEND_PATTERN", + timer.wait.eq(1), + If(timer.done, + If(~serdes.rx.comma, + NextState("READY") + ) + ), + serdes.tx.comma.eq(1) + ) + fsm.act("READY", + self.ready.eq(1) + ) + fsm.act("ERROR", + self.error.eq(1) + ) + + +class _SerdesControl(Module, AutoCSR): + def __init__(self, serdes, init, mode="master"): + if mode == "master": + self.reset = CSR() + self.ready = CSRStatus() + self.error = CSRStatus() + + self.bitslip = CSRStatus(6) + + self.scrambling_enable = CSRStorage() + + self.prbs_error = Signal() + self.prbs_start = CSR() + self.prbs_cycles = CSRStorage(32) + self.prbs_errors = CSRStatus(32) + + # # # + + if mode == "master": + # In Master mode, reset is coming from CSR, + # it resets the Master that will also reset + # the Slave by putting the link in idle. + self.sync += init.reset.eq(self.reset.re) + else: + # In Slave mode, reset is coming from link, + # Master reset the Slave by putting the link + # in idle. + self.sync += [ + init.reset.eq(serdes.rx.idle), + serdes.reset.eq(serdes.rx.idle) + ] + self.comb += [ + self.ready.status.eq(init.ready), + self.error.status.eq(init.error), + self.bitslip.status.eq(init.bitslip) + ] + + # prbs + prbs_cycles = Signal(32) + prbs_errors = self.prbs_errors.status + prbs_fsm = FSM(reset_state="IDLE") + self.submodules += prbs_fsm + prbs_fsm.act("IDLE", + NextValue(prbs_cycles, 0), + If(self.prbs_start.re, + NextValue(prbs_errors, 0), + NextState("CHECK") + ) + ) + prbs_fsm.act("CHECK", + NextValue(prbs_cycles, prbs_cycles + 1), + If(self.prbs_error, + NextValue(prbs_errors, prbs_errors + 1), + ), + If(prbs_cycles == self.prbs_cycles.storage, + NextState("IDLE") + ) + ) + + +class SERWBPHY(Module, AutoCSR): + def __init__(self, pads, mode="master", init_timeout=2**16): + self.sink = sink = stream.Endpoint([("data", 32)]) + self.source = source = stream.Endpoint([("data", 32)]) + assert mode in ["master", "slave"] + self.submodules.serdes = _Serdes(pads, mode) + if mode == "master": + self.submodules.init = _SerdesMasterInit(self.serdes, init_timeout) + else: + self.submodules.init = _SerdesSlaveInit(self.serdes, init_timeout) + self.submodules.control = _SerdesControl(self.serdes, self.init, mode) + + # scrambling + scrambler = Scrambler() + descrambler = Descrambler() + self.submodules += scrambler, descrambler + self.comb += [ + scrambler.enable.eq(self.control.scrambling_enable.storage), + descrambler.enable.eq(self.control.scrambling_enable.storage) + ] + + # tx dataflow + self.comb += \ + If(self.init.ready, + sink.connect(scrambler.sink), + scrambler.source.ack.eq(self.serdes.tx.ce), + If(scrambler.source.stb, + self.serdes.tx.d.eq(scrambler.source.d), + self.serdes.tx.k.eq(scrambler.source.k) + ) + ) + + # rx dataflow + self.comb += [ + If(self.init.ready, + descrambler.sink.stb.eq(self.serdes.rx.ce), + descrambler.sink.d.eq(self.serdes.rx.d), + descrambler.sink.k.eq(self.serdes.rx.k), + descrambler.source.connect(source) + ), + # For PRBS test we are using the scrambler/descrambler as PRBS, + # sending 0 to the scrambler and checking that descrambler + # output is always 0. + self.control.prbs_error.eq( + descrambler.source.stb & + descrambler.source.ack & + (descrambler.source.data != 0)) + ] From c18a73d45fbf7ac321aa7625f83e0d0a62b6eebd Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 15 May 2018 16:40:50 +0200 Subject: [PATCH 0773/2457] sayma_amc/rtm: use new serwb low-speed phy --- artiq/firmware/libboard_artiq/serwb.rs | 10 ---------- artiq/gateware/targets/sayma_amc.py | 2 +- artiq/gateware/targets/sayma_rtm.py | 17 +++++++++++------ 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/artiq/firmware/libboard_artiq/serwb.rs b/artiq/firmware/libboard_artiq/serwb.rs index 23a2db391..46fd6e97f 100644 --- a/artiq/firmware/libboard_artiq/serwb.rs +++ b/artiq/firmware/libboard_artiq/serwb.rs @@ -16,22 +16,12 @@ fn read_rtm_ident(buf: &mut [u8]) -> &str { unsafe fn debug_print(rtm: bool) { info!("AMC serwb settings:"); - info!(" delay_min_found: {}", csr::serwb_phy_amc::control_delay_min_found_read()); - info!(" delay_min: {}", csr::serwb_phy_amc::control_delay_min_read()); - info!(" delay_max_found: {}", csr::serwb_phy_amc::control_delay_max_found_read()); - info!(" delay_max: {}", csr::serwb_phy_amc::control_delay_max_read()); - info!(" delay: {}", csr::serwb_phy_amc::control_delay_read()); info!(" bitslip: {}", csr::serwb_phy_amc::control_bitslip_read()); info!(" ready: {}", csr::serwb_phy_amc::control_ready_read()); info!(" error: {}", csr::serwb_phy_amc::control_error_read()); if rtm { info!("RTM serwb settings:"); - info!(" delay_min_found: {}", csr::serwb_phy_rtm::control_delay_min_found_read()); - info!(" delay_min: {}", csr::serwb_phy_rtm::control_delay_min_read()); - info!(" delay_max_found: {}", csr::serwb_phy_rtm::control_delay_max_found_read()); - info!(" delay_max: {}", csr::serwb_phy_rtm::control_delay_max_read()); - info!(" delay: {}", csr::serwb_phy_rtm::control_delay_read()); info!(" bitslip: {}", csr::serwb_phy_rtm::control_bitslip_read()); info!(" ready: {}", csr::serwb_phy_rtm::control_ready_read()); info!(" error: {}", csr::serwb_phy_rtm::control_error_read()); diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 856adb965..fe98c0fac 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -174,7 +174,7 @@ class Standalone(MiniSoC, AMPSoC): # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") - serwb_phy_amc = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="master") + serwb_phy_amc = serwb.genphy.SERWBPHY(serwb_pads, mode="master") self.submodules.serwb_phy_amc = serwb_phy_amc self.csr_devices.append("serwb_phy_amc") diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 8aecc65ff..16c55c619 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -28,6 +28,11 @@ class CRG(Module): self.serwb_refclk = Signal() self.serwb_reset = Signal() + serwb_refclk_bufr = Signal() + serwb_refclk_bufg = Signal() + self.specials += Instance("BUFR", i_I=self.serwb_refclk, o_O=serwb_refclk_bufr) + self.specials += Instance("BUFG", i_I=serwb_refclk_bufr, o_O=serwb_refclk_bufg) + pll_locked = Signal() pll_fb = Signal() pll_sys4x = Signal() @@ -37,9 +42,9 @@ class CRG(Module): p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, # VCO @ 1GHz - p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=10.0, - p_CLKFBOUT_MULT_F=10, p_DIVCLK_DIVIDE=1, - i_CLKIN1=self.serwb_refclk, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, + p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=8.0, + p_CLKFBOUT_MULT_F=8, p_DIVCLK_DIVIDE=1, + i_CLKIN1=serwb_refclk_bufg, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, # 500MHz p_CLKOUT0_DIVIDE_F=2, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=pll_sys4x, @@ -145,11 +150,11 @@ class SaymaRTM(Module): # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") - platform.add_period_constraint(serwb_pads.clk_p, 10.) - serwb_phy_rtm = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="slave") + platform.add_period_constraint(serwb_pads.clk_p, 8.) + serwb_phy_rtm = serwb.genphy.SERWBPHY(serwb_pads, mode="slave") self.submodules.serwb_phy_rtm = serwb_phy_rtm self.comb += [ - self.crg.serwb_refclk.eq(serwb_phy_rtm.serdes.refclk), + self.crg.serwb_refclk.eq(serwb_phy_rtm.serdes.clocking.refclk), self.crg.serwb_reset.eq(serwb_phy_rtm.serdes.reset) ] csr_devices.append("serwb_phy_rtm") From b54926134c984defc24953b1fad2418026a71009 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 15 May 2018 14:33:30 +0000 Subject: [PATCH 0774/2457] firmware: update the signature of #[lang="panic_fmt"]. --- artiq/firmware/bootloader/main.rs | 5 +++-- artiq/firmware/ksupport/lib.rs | 5 +++-- artiq/firmware/runtime/main.rs | 5 +++-- artiq/firmware/satman/main.rs | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 398731e99..4498140b4 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -228,7 +228,8 @@ pub extern fn abort() { #[no_mangle] #[lang = "panic_fmt"] -pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! { - println!("panic at {}:{}: {}", file, line, args); +pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, + line: u32, column: u32) -> ! { + println!("panic at {}:{}:{}: {}", file, line, column, args); loop {} } diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index e2f7696a2..c3e05c138 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -49,8 +49,9 @@ macro_rules! recv { #[no_mangle] #[lang = "panic_fmt"] -pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! { - send(&Log(format_args!("panic at {}:{}: {}\n", file, line, args))); +pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, + line: u32, column: u32) -> ! { + send(&Log(format_args!("panic at {}:{}:{}: {}\n", file, line, column, args))); send(&RunAborted); loop {} } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index deb78bf97..2f075b573 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -303,8 +303,9 @@ pub extern fn abort() { #[no_mangle] #[lang = "panic_fmt"] -pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! { - println!("panic at {}:{}: {}", file, line, args); +pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, + line: u32, column: u32) -> ! { + println!("panic at {}:{}:{}: {}", file, line, column, args); println!("backtrace for software version {}:", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index faa343678..eb478cc6a 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -293,7 +293,8 @@ pub extern fn abort() { #[no_mangle] #[lang = "panic_fmt"] -pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32) -> ! { - println!("panic at {}:{}: {}", file, line, args); +pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, + line: u32, column: u32) -> ! { + println!("panic at {}:{}:{}: {}", file, line, column, args); loop {} } From e5796e26e182a200a309f749ceab14c5ee20d09c Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 15 May 2018 14:52:51 +0000 Subject: [PATCH 0775/2457] firmware: remove unused #![feature(untagged_unions)]. --- artiq/firmware/libdyld/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/firmware/libdyld/lib.rs b/artiq/firmware/libdyld/lib.rs index 1eeff2bf4..d16dc1cdd 100644 --- a/artiq/firmware/libdyld/lib.rs +++ b/artiq/firmware/libdyld/lib.rs @@ -1,5 +1,4 @@ #![no_std] -#![feature(untagged_unions)] use core::{mem, ptr, fmt, slice, str, convert}; use elf::*; From 9f5b76253c8b63bc2a1b9af8589e5f54acc49498 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 15 May 2018 15:01:30 +0000 Subject: [PATCH 0776/2457] firmware: remove some unnecessary unwraps. --- artiq/firmware/runtime/moninj.rs | 5 +++-- artiq/firmware/runtime/rtio_dma.rs | 4 +--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index 67b582ba2..d589d63d2 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -1,5 +1,6 @@ use alloc::btree_map::BTreeMap; +use io::Error as IoError; use moninj_proto::*; use sched::{Io, TcpListener, TcpStream, Error as SchedError}; use board_misoc::{clock, csr}; @@ -184,7 +185,7 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error next_check { for (&(channel, probe), previous) in watch_list.iter_mut() { let current = read_probe(channel, probe); - if previous.is_none() || (previous.unwrap() != current) { + if previous.is_none() || previous.unwrap() != current { let message = DeviceMessage::MonitorStatus { channel: channel, probe: probe, @@ -200,7 +201,7 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error Date: Tue, 15 May 2018 15:19:20 +0000 Subject: [PATCH 0777/2457] firmware: use upstream log_buffer. --- artiq/firmware/liblogger_artiq/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/liblogger_artiq/Cargo.toml b/artiq/firmware/liblogger_artiq/Cargo.toml index c33acd01f..4eaa98f09 100644 --- a/artiq/firmware/liblogger_artiq/Cargo.toml +++ b/artiq/firmware/liblogger_artiq/Cargo.toml @@ -9,5 +9,5 @@ path = "lib.rs" [dependencies] log = { version = "0.4", default-features = false } -log_buffer = { version = "1.2", git = "https://github.com/whitequark/rust-log_buffer", rev = "rust-1.25" } +log_buffer = { version = "1.2" } board_misoc = { path = "../libboard_misoc" } From 1b0384c513704378c49ce96a5e64b3fd97401069 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 15 May 2018 16:35:05 +0000 Subject: [PATCH 0778/2457] firmware: fix satman build. --- artiq/firmware/Cargo.lock | 8 ++- artiq/firmware/libboard_artiq/Cargo.toml | 2 + artiq/firmware/libboard_artiq/drtioaux.rs | 67 ++++++++++------------- artiq/firmware/libboard_artiq/lib.rs | 4 ++ artiq/firmware/satman/main.rs | 2 +- 5 files changed, 42 insertions(+), 41 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 12568fcff..e8ae40379 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -17,6 +17,8 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "io 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "proto_artiq 0.0.0", @@ -176,7 +178,7 @@ dependencies = [ [[package]] name = "log_buffer" version = "1.2.0" -source = "git+https://github.com/whitequark/rust-log_buffer?rev=rust-1.25#ff84e565d9954d5864d60aec12b9e1381505d72a" +source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "logger_artiq" @@ -184,7 +186,7 @@ version = "0.0.0" dependencies = [ "board_misoc 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log_buffer 1.2.0 (git+https://github.com/whitequark/rust-log_buffer?rev=rust-1.25)", + "log_buffer 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -340,7 +342,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" -"checksum log_buffer 1.2.0 (git+https://github.com/whitequark/rust-log_buffer?rev=rust-1.25)" = "" +"checksum log_buffer 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f033173c9486b7fe97a79c895c0a3483ae395ab6744c985d10078950e2492419" "checksum managed 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43e2737ecabe4ae36a68061398bf27d2bfd0763f4c3c837a398478459494c4b7" "checksum managed 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5a31885241e61ba264d780d2e6686e7e59561c947b4581470364eb3e10102d86" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" diff --git a/artiq/firmware/libboard_artiq/Cargo.toml b/artiq/firmware/libboard_artiq/Cargo.toml index 776392d42..b04990823 100644 --- a/artiq/firmware/libboard_artiq/Cargo.toml +++ b/artiq/firmware/libboard_artiq/Cargo.toml @@ -13,6 +13,8 @@ build_misoc = { path = "../libbuild_misoc" } build_artiq = { path = "../libbuild_artiq" } [dependencies] +failure = { version = "0.1", default-features = false } +failure_derive = { version = "0.1", default-features = false } bitflags = "1.0" byteorder = { version = "1.0", default-features = false } crc = { version = "1.7", default-features = false } diff --git a/artiq/firmware/libboard_artiq/drtioaux.rs b/artiq/firmware/libboard_artiq/drtioaux.rs index 207f7baf1..97a06e3b2 100644 --- a/artiq/firmware/libboard_artiq/drtioaux.rs +++ b/artiq/firmware/libboard_artiq/drtioaux.rs @@ -1,43 +1,36 @@ -use core::{slice, fmt, result}; +use core::slice; use crc; -use io::{Cursor, Error as IoError}; -use io::proto::{ProtoRead, ProtoWrite}; +use io::{ProtoRead, ProtoWrite, Cursor, Error as IoError}; use board_misoc::{csr::DRTIO, mem::DRTIO_AUX, clock}; +use proto_artiq::drtioaux_proto::Error as ProtocolError; pub use proto_artiq::drtioaux_proto::Packet; -pub type Result = result::Result; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Error { +// this is parametric over T because there's no impl Fail for !. +#[derive(Fail, Debug)] +pub enum Error { + #[fail(display = "packet CRC failed")] CorruptedPacket, + #[fail(display = "timed out waiting for data")] TimedOut, + #[fail(display = "invalid node number")] NoRoute, + #[fail(display = "gateware reported error")] GatewareError, - Io(IoError) + #[fail(display = "protocol error: {}", _0)] + Protocol(#[cause] ProtocolError) } -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &Error::CorruptedPacket => - write!(f, "packet CRC failed"), - &Error::TimedOut => - write!(f, "timed out waiting for data"), - &Error::NoRoute => - write!(f, "invalid node number"), - &Error::GatewareError => - write!(f, "gateware reported error"), - &Error::Io(ref io) => - write!(f, "I/O error ({})", io) - } +impl From> for Error { + fn from(value: ProtocolError) -> Error { + Error::Protocol(value) } } -impl From> for Error { - fn from(value: IoError) -> Error { - Error::Io(value) +impl From> for Error { + fn from(value: IoError) -> Error { + Error::Protocol(ProtocolError::Io(value)) } } @@ -63,8 +56,8 @@ fn has_rx_error(linkno: u8) -> bool { } } -fn receive(linkno: u8, f: F) -> Result> - where F: FnOnce(&[u8]) -> Result +fn receive(linkno: u8, f: F) -> Result, Error> + where F: FnOnce(&[u8]) -> Result> { let linkidx = linkno as usize; unsafe { @@ -80,14 +73,14 @@ fn receive(linkno: u8, f: F) -> Result> } } -pub fn recv_link(linkno: u8) -> Result> { +pub fn recv_link(linkno: u8) -> Result, Error> { if has_rx_error(linkno) { return Err(Error::GatewareError) } receive(linkno, |buffer| { if buffer.len() < 8 { - return Err(Error::Io(IoError::UnexpectedEof)) + return Err(IoError::UnexpectedEnd.into()) } let mut reader = Cursor::new(buffer); @@ -104,7 +97,7 @@ pub fn recv_link(linkno: u8) -> Result> { }) } -pub fn recv_timeout_link(linkno: u8, timeout_ms: Option) -> Result { +pub fn recv_timeout_link(linkno: u8, timeout_ms: Option) -> Result> { let timeout_ms = timeout_ms.unwrap_or(10); let limit = clock::get_ms() + timeout_ms; while clock::get_ms() < limit { @@ -116,8 +109,8 @@ pub fn recv_timeout_link(linkno: u8, timeout_ms: Option) -> Result Err(Error::TimedOut) } -fn transmit(linkno: u8, f: F) -> Result<()> - where F: FnOnce(&mut [u8]) -> Result +fn transmit(linkno: u8, f: F) -> Result<(), Error> + where F: FnOnce(&mut [u8]) -> Result> { let linkno = linkno as usize; unsafe { @@ -131,7 +124,7 @@ fn transmit(linkno: u8, f: F) -> Result<()> } } -pub fn send_link(linkno: u8, packet: &Packet) -> Result<()> { +pub fn send_link(linkno: u8, packet: &Packet) -> Result<(), Error> { transmit(linkno, |buffer| { let mut writer = Cursor::new(buffer); @@ -152,24 +145,24 @@ pub fn send_link(linkno: u8, packet: &Packet) -> Result<()> { } // TODO: routing -fn get_linkno(nodeno: u8) -> Result { +fn get_linkno(nodeno: u8) -> Result> { if nodeno == 0 || nodeno as usize > DRTIO.len() { return Err(Error::NoRoute) } Ok(nodeno - 1) } -pub fn recv(nodeno: u8) -> Result> { +pub fn recv(nodeno: u8) -> Result, Error> { let linkno = get_linkno(nodeno)?; recv_link(linkno) } -pub fn recv_timeout(nodeno: u8, timeout_ms: Option) -> Result { +pub fn recv_timeout(nodeno: u8, timeout_ms: Option) -> Result> { let linkno = get_linkno(nodeno)?; recv_timeout_link(linkno, timeout_ms) } -pub fn send(nodeno: u8, packet: &Packet) -> Result<()> { +pub fn send(nodeno: u8, packet: &Packet) -> Result<(), Error> { let linkno = get_linkno(nodeno)?; send_link(linkno, packet) } diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 6f22153c7..af8c1336a 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -1,6 +1,10 @@ #![feature(asm, lang_items, never_type)] #![no_std] +extern crate failure; +#[cfg(has_drtio)] +#[macro_use] +extern crate failure_derive; #[macro_use] extern crate bitflags; extern crate byteorder; diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index eb478cc6a..6cbadcecb 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -26,7 +26,7 @@ fn drtio_reset_phy(reset: bool) { } } -fn process_aux_packet(packet: drtioaux::Packet) -> drtioaux::Result<()> { +fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error> { // In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels, // and u16 otherwise; hence the `as _` conversion. match packet { From 8128a814f623c329bd58866a9af65c1e194ccdbb Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 15 May 2018 18:17:32 +0000 Subject: [PATCH 0779/2457] firmware: update dependencies. --- artiq/firmware/Cargo.lock | 50 +++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index e8ae40379..744e02371 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -4,19 +4,19 @@ version = "0.0.0" [[package]] name = "bitflags" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "board_artiq" version = "0.0.0" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "board_misoc 0.0.0", "build_artiq 0.0.0", "build_misoc 0.0.0", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "io 0.0.0", @@ -29,8 +29,8 @@ name = "board_misoc" version = "0.0.0" dependencies = [ "build_misoc 0.0.0", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", @@ -42,8 +42,8 @@ version = "0.0.0" dependencies = [ "board_misoc 0.0.0", "build_misoc 0.0.0", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", ] @@ -56,7 +56,7 @@ dependencies = [ [[package]] name = "build_const" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -65,17 +65,17 @@ version = "0.0.0" [[package]] name = "byteorder" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cc" -version = "1.0.9" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -85,10 +85,10 @@ source = "git+https://github.com/rust-lang-nursery/compiler-builtins#28daccd9159 [[package]] name = "crc" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -127,7 +127,7 @@ dependencies = [ name = "io" version = "0.0.0" dependencies = [ - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -172,7 +172,7 @@ name = "log" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -203,7 +203,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "proto_artiq" version = "0.0.0" dependencies = [ - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dyld 0.0.0", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -226,7 +226,7 @@ dependencies = [ "board_misoc 0.0.0", "build_artiq 0.0.0", "build_misoc 0.0.0", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -265,7 +265,7 @@ name = "smoltcp" version = "0.4.0" source = "git+https://github.com/m-labs/smoltcp?rev=181083f#181083f18c977b8a0463a67e360e4db20594fa21" dependencies = [ - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "managed 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -327,13 +327,13 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" -"checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9" -"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" -"checksum cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2b4911e4bdcb4100c7680e7e854ff38e23f1b34d4d9e079efae3da2801341ffc" -"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" +"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" +"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" +"checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba" +"checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18" "checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins)" = "" -"checksum crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5d02c0aac6bd68393ed69e00bbc2457f3e89075c6349db7189618dc4ddc1d7" +"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" From 7fe49a78d264b67905f3b9d38cc8960ebba7d45f Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 15 May 2018 23:47:47 +0200 Subject: [PATCH 0780/2457] firmware/runtime/session: fix compilation when no rtio core --- artiq/firmware/runtime/session.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index e1380c125..cbef8d7d8 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -295,7 +295,7 @@ fn process_host_message(io: &Io, } #[cfg(not(has_rtio_core))] - host_write(stream, host::Reply::ClockSwitchFailed) + host_write(stream, host::Reply::ClockSwitchFailed)? } host::Request::LoadKernel(kernel) => From 2c627cd06167ce77ab9a685e374db53cf8c26a21 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 15 May 2018 23:49:17 +0200 Subject: [PATCH 0781/2457] serwb/scrambler: simplify and set scrambler input data to 0 when sink.stb == 0 --- artiq/gateware/serwb/scrambler.py | 67 ++++++-------------- artiq/gateware/test/serwb/test_serwb_core.py | 4 +- 2 files changed, 23 insertions(+), 48 deletions(-) diff --git a/artiq/gateware/serwb/scrambler.py b/artiq/gateware/serwb/scrambler.py index d5149dfac..dc367fb6c 100644 --- a/artiq/gateware/serwb/scrambler.py +++ b/artiq/gateware/serwb/scrambler.py @@ -31,75 +31,51 @@ class _Scrambler(Module): class Scrambler(Module): - def __init__(self, sync_interval=1024): - self.enable = Signal() + def __init__(self, sync_interval=2**10): self.sink = sink = stream.Endpoint([("data", 32)]) self.source = source = stream.Endpoint([("d", 32), ("k", 4)]) # # # - # scrambler + # Scrambler self.submodules.scrambler = scrambler = _Scrambler(32) - # insert K.29.7 as sync character - # every sync_interval cycles + # Insert K29.7 SYNC character every "sync_interval" cycles count = Signal(max=sync_interval) - self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="DISABLE")) - self.comb += fsm.reset.eq(~self.enable) - fsm.act("DISABLE", - sink.connect(source, omit={"data"}), - source.k.eq(0b0000), - source.d.eq(sink.data), - NextState("SYNC") - ) - fsm.act("SYNC", - scrambler.reset.eq(1), + self.sync += If(source.ack, count.eq(count + 1)) + self.comb += [ source.stb.eq(1), - source.k[0].eq(1), - source.d[:8].eq(K(29, 7)), - NextValue(count, 0), - If(source.ack, - NextState("DATA") - ) - ) - fsm.act("DATA", - scrambler.i.eq(sink.data), - sink.ack.eq(source.ack), - source.stb.eq(1), - source.d.eq(scrambler.o), - If(source.stb & source.ack, - scrambler.ce.eq(1), - NextValue(count, count + 1), - If(count == (sync_interval - 1), - NextState("SYNC") + If(count == 0, + scrambler.reset.eq(1), + source.k.eq(0b1), + source.d.eq(K(29, 7)), + ).Else( + If(sink.stb, scrambler.i.eq(sink.data)), + source.k.eq(0), + source.d.eq(scrambler.o), + If(source.ack, + sink.ack.eq(1), + scrambler.ce.eq(1) ) ) - ) + ] class Descrambler(Module): def __init__(self): - self.enable = Signal() self.sink = sink = stream.Endpoint([("d", 32), ("k", 4)]) self.source = source = stream.Endpoint([("data", 32)]) # # # - # descrambler + # Descrambler self.submodules.descrambler = descrambler = _Scrambler(32) self.comb += descrambler.i.eq(sink.d) - # detect K29.7 and synchronize descrambler - self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="DISABLE")) - self.comb += fsm.reset.eq(~self.enable) - fsm.act("DISABLE", - sink.connect(source, omit={"d", "k"}), - source.data.eq(sink.d), - NextState("SYNC_DATA") - ) - fsm.act("SYNC_DATA", + # Detect K29.7 SYNC character and synchronize Descrambler + self.comb += \ If(sink.stb, - If((sink.k == 1) & (sink.d == K(29,7)), + If((sink.k == 0b1) & (sink.d == K(29,7)), sink.ack.eq(1), descrambler.reset.eq(1) ).Else( @@ -111,4 +87,3 @@ class Descrambler(Module): ) ) ) - ) diff --git a/artiq/gateware/test/serwb/test_serwb_core.py b/artiq/gateware/test/serwb/test_serwb_core.py index d0aeeaa25..0e964b5b1 100644 --- a/artiq/gateware/test/serwb/test_serwb_core.py +++ b/artiq/gateware/test/serwb/test_serwb_core.py @@ -101,7 +101,7 @@ class DUTCore(Module): class TestSERWBCore(unittest.TestCase): def test_scrambler(self): - def generator(dut): + def generator(dut, rand_level=50): # prepare test prng = random.Random(42) i = 0 @@ -115,7 +115,7 @@ class TestSERWBCore(unittest.TestCase): yield dut.scrambler.sink.data.eq(i) # check - yield dut.descrambler.source.ack.eq(prng.randrange(2)) + yield dut.descrambler.source.ack.eq(prng.randrange(prng.randrange(100) > rand_level) if (yield dut.descrambler.source.stb) & (yield dut.descrambler.source.ack): current_data = (yield dut.descrambler.source.data) if (current_data != (last_data + 1)): From f8a9dd930b0a42ac8c98c340c9fa4b8fc4467993 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 15 May 2018 23:51:14 +0200 Subject: [PATCH 0782/2457] serwb/genphy: add device parameter (not used here, but this way all the phys share the same parameters), scrambling is also now always enabled. --- artiq/gateware/serwb/genphy.py | 13 +++---------- artiq/gateware/targets/sayma_amc.py | 2 +- artiq/gateware/targets/sayma_rtm.py | 2 +- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/artiq/gateware/serwb/genphy.py b/artiq/gateware/serwb/genphy.py index 07ab731ad..3c385b0d3 100644 --- a/artiq/gateware/serwb/genphy.py +++ b/artiq/gateware/serwb/genphy.py @@ -317,8 +317,6 @@ class _SerdesControl(Module, AutoCSR): self.bitslip = CSRStatus(6) - self.scrambling_enable = CSRStorage() - self.prbs_error = Signal() self.prbs_start = CSR() self.prbs_cycles = CSRStorage(32) @@ -369,7 +367,7 @@ class _SerdesControl(Module, AutoCSR): class SERWBPHY(Module, AutoCSR): - def __init__(self, pads, mode="master", init_timeout=2**16): + def __init__(self, device, pads, mode="master", init_timeout=2**16): self.sink = sink = stream.Endpoint([("data", 32)]) self.source = source = stream.Endpoint([("data", 32)]) assert mode in ["master", "slave"] @@ -381,13 +379,8 @@ class SERWBPHY(Module, AutoCSR): self.submodules.control = _SerdesControl(self.serdes, self.init, mode) # scrambling - scrambler = Scrambler() - descrambler = Descrambler() - self.submodules += scrambler, descrambler - self.comb += [ - scrambler.enable.eq(self.control.scrambling_enable.storage), - descrambler.enable.eq(self.control.scrambling_enable.storage) - ] + self.submodules.scrambler = scrambler = Scrambler() + self.submodules.descrambler = descrambler = Descrambler() # tx dataflow self.comb += \ diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index fe98c0fac..09d686c3b 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -174,7 +174,7 @@ class Standalone(MiniSoC, AMPSoC): # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") - serwb_phy_amc = serwb.genphy.SERWBPHY(serwb_pads, mode="master") + serwb_phy_amc = serwb.genphy.SERWBPHY(platform.device, serwb_pads, mode="master") self.submodules.serwb_phy_amc = serwb_phy_amc self.csr_devices.append("serwb_phy_amc") diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 16c55c619..66855e4d8 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -151,7 +151,7 @@ class SaymaRTM(Module): # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") platform.add_period_constraint(serwb_pads.clk_p, 8.) - serwb_phy_rtm = serwb.genphy.SERWBPHY(serwb_pads, mode="slave") + serwb_phy_rtm = serwb.genphy.SERWBPHY(platform.device, serwb_pads, mode="slave") self.submodules.serwb_phy_rtm = serwb_phy_rtm self.comb += [ self.crg.serwb_refclk.eq(serwb_phy_rtm.serdes.clocking.refclk), From 3873d0969219e717c3e5a5e658a8a4ac7e5d9d89 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 15 May 2018 23:52:41 +0200 Subject: [PATCH 0783/2457] serwb: rewrite high-speed phys by splitting clocking/tx/rx, scrambling is now always enabled. --- artiq/gateware/serwb/__init__.py | 2 +- artiq/gateware/serwb/kuserdes.py | 213 ++++++++++++++++++++++++++++ artiq/gateware/serwb/kusphy.py | 218 ----------------------------- artiq/gateware/serwb/phy.py | 102 +++++++------- artiq/gateware/serwb/s7phy.py | 230 ------------------------------- artiq/gateware/serwb/s7serdes.py | 225 ++++++++++++++++++++++++++++++ 6 files changed, 486 insertions(+), 504 deletions(-) create mode 100644 artiq/gateware/serwb/kuserdes.py delete mode 100644 artiq/gateware/serwb/kusphy.py delete mode 100644 artiq/gateware/serwb/s7phy.py create mode 100644 artiq/gateware/serwb/s7serdes.py diff --git a/artiq/gateware/serwb/__init__.py b/artiq/gateware/serwb/__init__.py index 7c437f6f3..46938e85f 100644 --- a/artiq/gateware/serwb/__init__.py +++ b/artiq/gateware/serwb/__init__.py @@ -1 +1 @@ -from artiq.gateware.serwb import s7phy, kusphy, genphy, phy, core, packet, etherbone +from artiq.gateware.serwb import s7serdes, kuserdes, genphy, phy, core, packet, etherbone diff --git a/artiq/gateware/serwb/kuserdes.py b/artiq/gateware/serwb/kuserdes.py new file mode 100644 index 000000000..ced959eff --- /dev/null +++ b/artiq/gateware/serwb/kuserdes.py @@ -0,0 +1,213 @@ +from migen import * +from migen.genlib.io import * +from migen.genlib.misc import BitSlip, WaitTimer + +from misoc.interconnect import stream +from misoc.cores.code_8b10b import Encoder, Decoder + + +def K(x, y): + return (y << 5) | x + + +class _KUSerdesClocking(Module): + def __init__(self, pads, mode="master"): + self.refclk = Signal() + + # # # + + # In Master mode, generate the linerate/10 clock. Slave will re-multiply it. + if mode == "master": + converter = stream.Converter(40, 8) + self.submodules += converter + self.comb += [ + converter.sink.stb.eq(1), + converter.source.ack.eq(1), + converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), + ] + self.specials += [ + Instance("OSERDESE3", + p_DATA_WIDTH=8, p_INIT=0, + p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, + p_IS_RST_INVERTED=0, + + o_OQ=self.refclk, + i_RST=ResetSignal("sys"), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), + i_D=converter.source.data + ), + DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) + ] + + # In Slave mode, multiply the clock provided by Master with a PLL/MMCM + elif mode == "slave": + self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk) + + +class _KUSerdesTX(Module): + def __init__(self, pads, mode="master"): + # Control + self.idle = idle = Signal() + self.comma = comma = Signal() + + # Datapath + self.ce = ce = Signal() + self.k = k = Signal(4) + self.d = d = Signal(32) + + # # # + + # 8b10b encoder + self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) + self.comb += encoder.ce.eq(ce) + + # 40 --> 8 converter + converter = stream.Converter(40, 8) + self.submodules += converter + self.comb += [ + converter.sink.stb.eq(1), + converter.source.ack.eq(1), + # Enable pipeline when converter accepts the 40 bits + ce.eq(converter.sink.ack), + # If not idle, connect encoder to converter + If(~idle, + converter.sink.data.eq(Cat(*[encoder.output[i] for i in range(4)])) + ), + # If comma, send K28.5 + If(comma, + encoder.k[0].eq(1), + encoder.d[0].eq(K(28,5)), + # Else connect TX to encoder + ).Else( + encoder.k[0].eq(k[0]), + encoder.k[1].eq(k[1]), + encoder.k[2].eq(k[2]), + encoder.k[3].eq(k[3]), + encoder.d[0].eq(d[0:8]), + encoder.d[1].eq(d[8:16]), + encoder.d[2].eq(d[16:24]), + encoder.d[3].eq(d[24:32]) + ) + ] + + # Data output (DDR with sys4x) + data = Signal() + self.specials += [ + Instance("OSERDESE3", + p_DATA_WIDTH=8, p_INIT=0, + p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, + + o_OQ=data, + i_RST=ResetSignal("sys"), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), + i_D=converter.source.data + ), + DifferentialOutput(data, pads.tx_p, pads.tx_n) + ] + + +class _KUSerdesRX(Module): + def __init__(self, pads, mode="master"): + # Control + self.delay_rst = Signal() + self.delay_inc = Signal() + self.bitslip_value = bitslip_value = Signal(6) + + # Status + self.idle = idle = Signal() + self.comma = comma = Signal() + + # Datapath + self.ce = ce = Signal() + self.k = k = Signal(4) + self.d = d = Signal(32) + + # # # + + # Data input (DDR with sys4x) + data_nodelay = Signal() + data_delayed = Signal() + data_deserialized = Signal(8) + self.specials += [ + DifferentialInput(pads.rx_p, pads.rx_n, data_nodelay), + Instance("IDELAYE3", + p_CASCADE="NONE", p_UPDATE_MODE="ASYNC", p_REFCLK_FREQUENCY=200.0, + p_IS_CLK_INVERTED=0, p_IS_RST_INVERTED=0, + p_DELAY_FORMAT="COUNT", p_DELAY_SRC="IDATAIN", + p_DELAY_TYPE="VARIABLE", p_DELAY_VALUE=0, + + i_CLK=ClockSignal("sys"), + i_RST=self.delay_rst, i_LOAD=0, + i_INC=1, i_EN_VTC=0, + i_CE=self.delay_inc, + + i_IDATAIN=data_nodelay, o_DATAOUT=data_delayed + ), + Instance("ISERDESE3", + p_IS_CLK_INVERTED=0, + p_IS_CLK_B_INVERTED=1, + p_DATA_WIDTH=8, + + i_D=data_delayed, + i_RST=ResetSignal("sys"), + i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0, + i_CLK=ClockSignal("sys4x"), + i_CLK_B=ClockSignal("sys4x"), # locally inverted + i_CLKDIV=ClockSignal("sys"), + o_Q=data_deserialized + ) + ] + + # 8 --> 40 converter and bitslip + converter = stream.Converter(8, 40) + self.submodules += converter + bitslip = CEInserter()(BitSlip(40)) + self.submodules += bitslip + self.comb += [ + converter.sink.stb.eq(1), + converter.source.ack.eq(1), + # Enable pipeline when converter outputs the 40 bits + ce.eq(converter.source.stb), + # Connect input data to converter + converter.sink.data.eq(data_deserialized), + # Connect converter to bitslip + bitslip.ce.eq(ce), + bitslip.value.eq(bitslip_value), + bitslip.i.eq(converter.source.data) + ] + + # 8b10b decoder + self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] + self.comb += [decoders[i].ce.eq(ce) for i in range(4)] + self.comb += [ + # Connect bitslip to decoder + decoders[0].input.eq(bitslip.o[0:10]), + decoders[1].input.eq(bitslip.o[10:20]), + decoders[2].input.eq(bitslip.o[20:30]), + decoders[3].input.eq(bitslip.o[30:40]), + # Connect decoder to output + self.k.eq(Cat(*[decoders[i].k for i in range(4)])), + self.d.eq(Cat(*[decoders[i].d for i in range(4)])), + ] + + # Status + idle_timer = WaitTimer(256) + self.submodules += idle_timer + self.comb += [ + idle_timer.wait.eq(1), + self.idle.eq(idle_timer.done & + ((bitslip.o == 0) | (bitslip.o == (2**40-1)))), + self.comma.eq( + (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & + (decoders[1].k == 0) & (decoders[1].d == 0) & + (decoders[2].k == 0) & (decoders[2].d == 0) & + (decoders[3].k == 0) & (decoders[3].d == 0)) + ] + + +@ResetInserter() +class KUSerdes(Module): + def __init__(self, pads, mode="master"): + self.submodules.clocking = _KUSerdesClocking(pads, mode) + self.submodules.tx = _KUSerdesTX(pads, mode) + self.submodules.rx = _KUSerdesRX(pads, mode) diff --git a/artiq/gateware/serwb/kusphy.py b/artiq/gateware/serwb/kusphy.py deleted file mode 100644 index dd7cf6760..000000000 --- a/artiq/gateware/serwb/kusphy.py +++ /dev/null @@ -1,218 +0,0 @@ -from migen import * -from migen.genlib.misc import BitSlip -from migen.genlib.misc import WaitTimer - -from misoc.interconnect import stream -from misoc.cores.code_8b10b import Encoder, Decoder - - -def K(x, y): - return (y << 5) | x - - -@ResetInserter() -class KUSSerdes(Module): - def __init__(self, pads, mode="master"): - if mode == "slave": - self.refclk = Signal() - - self.tx_ce = Signal() - self.tx_k = Signal(4) - self.tx_d = Signal(32) - - self.rx_ce = Signal() - self.rx_k = Signal(4) - self.rx_d = Signal(32) - - self.tx_idle = Signal() - self.tx_comma = Signal() - self.rx_idle = Signal() - self.rx_comma = Signal() - - self.rx_bitslip_value = Signal(6) - self.rx_delay_rst = Signal() - self.rx_delay_inc = Signal() - - # # # - - self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) - self.comb += encoder.ce.eq(self.tx_ce) - self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] - self.comb += [decoders[i].ce.eq(self.rx_ce) for i in range(4)] - - # clocking: - - # In master mode: - # - linerate/10 refclk generated on clk_pads - # In Slave mode: - # - linerate/10 refclk provided by clk_pads - - # tx clock (linerate/10) - if mode == "master": - clk_converter = stream.Converter(40, 8) - self.submodules += clk_converter - self.comb += [ - clk_converter.sink.stb.eq(1), - clk_converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), - clk_converter.source.ack.eq(1) - ] - clk_o = Signal() - self.specials += [ - Instance("OSERDESE3", - p_DATA_WIDTH=8, p_INIT=0, - p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, - p_IS_RST_INVERTED=0, - - o_OQ=clk_o, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D=clk_converter.source.data - ), - Instance("OBUFDS", - i_I=clk_o, - o_O=pads.clk_p, - o_OB=pads.clk_n - ) - ] - - # tx datapath - # tx_data -> encoders -> converter -> serdes - self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) - self.comb += [ - tx_converter.sink.stb.eq(1), - self.tx_ce.eq(tx_converter.sink.ack), - tx_converter.source.ack.eq(1), - If(self.tx_idle, - tx_converter.sink.data.eq(0) - ).Else( - tx_converter.sink.data.eq( - Cat(*[encoder.output[i] for i in range(4)])) - ), - If(self.tx_comma, - encoder.k[0].eq(1), - encoder.d[0].eq(K(28,5)), - ).Else( - encoder.k[0].eq(self.tx_k[0]), - encoder.k[1].eq(self.tx_k[1]), - encoder.k[2].eq(self.tx_k[2]), - encoder.k[3].eq(self.tx_k[3]), - encoder.d[0].eq(self.tx_d[0:8]), - encoder.d[1].eq(self.tx_d[8:16]), - encoder.d[2].eq(self.tx_d[16:24]), - encoder.d[3].eq(self.tx_d[24:32]) - ) - ] - - serdes_o = Signal() - self.specials += [ - Instance("OSERDESE3", - p_DATA_WIDTH=8, p_INIT=0, - p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, - - o_OQ=serdes_o, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D=tx_converter.source.data - ), - Instance("OBUFDS", - i_I=serdes_o, - o_O=pads.tx_p, - o_OB=pads.tx_n - ) - ] - - # rx clock - use_bufr = True - if mode == "slave": - clk_i = Signal() - clk_i_bufg = Signal() - self.specials += [ - Instance("IBUFDS", - i_I=pads.clk_p, - i_IB=pads.clk_n, - o_O=clk_i - ) - ] - if use_bufr: - clk_i_bufr = Signal() - self.specials += [ - Instance("BUFR", i_I=clk_i, o_O=clk_i_bufr), - Instance("BUFG", i_I=clk_i_bufr, o_O=clk_i_bufg) - ] - else: - self.specials += Instance("BUFG", i_I=clk_i, o_O=clk_i_bufg) - self.comb += self.refclk.eq(clk_i_bufg) - - # rx datapath - # serdes -> converter -> bitslip -> decoders -> rx_data - self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) - self.comb += [ - self.rx_ce.eq(rx_converter.source.stb), - rx_converter.source.ack.eq(1) - ] - self.submodules.rx_bitslip = rx_bitslip = CEInserter()(BitSlip(40)) - self.comb += rx_bitslip.ce.eq(self.rx_ce) - - serdes_i_nodelay = Signal() - self.specials += [ - Instance("IBUFDS_DIFF_OUT", - i_I=pads.rx_p, - i_IB=pads.rx_n, - o_O=serdes_i_nodelay - ) - ] - - serdes_i_delayed = Signal() - serdes_q = Signal(8) - self.specials += [ - Instance("IDELAYE3", - p_CASCADE="NONE", p_UPDATE_MODE="ASYNC", p_REFCLK_FREQUENCY=200.0, - p_IS_CLK_INVERTED=0, p_IS_RST_INVERTED=0, - p_DELAY_FORMAT="COUNT", p_DELAY_SRC="IDATAIN", - p_DELAY_TYPE="VARIABLE", p_DELAY_VALUE=0, - - i_CLK=ClockSignal("sys"), - i_RST=self.rx_delay_rst, i_LOAD=0, - i_INC=1, i_EN_VTC=0, - i_CE=self.rx_delay_inc, - - i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed - ), - Instance("ISERDESE3", - p_IS_CLK_INVERTED=0, - p_IS_CLK_B_INVERTED=1, - p_DATA_WIDTH=8, - - i_D=serdes_i_delayed, - i_RST=ResetSignal("sys"), - i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0, - i_CLK=ClockSignal("sys4x"), - i_CLK_B=ClockSignal("sys4x"), # locally inverted - i_CLKDIV=ClockSignal("sys"), - o_Q=serdes_q - ) - ] - - self.comb += [ - rx_converter.sink.stb.eq(1), - rx_converter.sink.data.eq(serdes_q), - rx_bitslip.value.eq(self.rx_bitslip_value), - rx_bitslip.i.eq(rx_converter.source.data), - decoders[0].input.eq(rx_bitslip.o[0:10]), - decoders[1].input.eq(rx_bitslip.o[10:20]), - decoders[2].input.eq(rx_bitslip.o[20:30]), - decoders[3].input.eq(rx_bitslip.o[30:40]), - self.rx_k.eq(Cat(*[decoders[i].k for i in range(4)])), - self.rx_d.eq(Cat(*[decoders[i].d for i in range(4)])), - self.rx_comma.eq( - (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & - (decoders[1].k == 0) & (decoders[1].d == 0) & - (decoders[2].k == 0) & (decoders[2].d == 0) & - (decoders[3].k == 0) & (decoders[3].d == 0)) - ] - - idle_timer = WaitTimer(32) - self.submodules += idle_timer - self.comb += idle_timer.wait.eq(1) - self.sync += self.rx_idle.eq(idle_timer.done & - ((rx_bitslip.o == 0) | (rx_bitslip.o == (2**40-1)))) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index ecd6f527c..a7c201e65 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -1,13 +1,12 @@ from migen import * -from migen.genlib.cdc import MultiReg, PulseSynchronizer from migen.genlib.misc import WaitTimer from misoc.interconnect import stream from misoc.interconnect.csr import * from artiq.gateware.serwb.scrambler import Scrambler, Descrambler -from artiq.gateware.serwb.kusphy import KUSSerdes -from artiq.gateware.serwb.s7phy import S7Serdes +from artiq.gateware.serwb.kuserdes import KUSerdes +from artiq.gateware.serwb.s7serdes import S7Serdes # Master <--> Slave synchronization: @@ -21,7 +20,7 @@ from artiq.gateware.serwb.s7phy import S7Serdes @ResetInserter() class _SerdesMasterInit(Module): - def __init__(self, serdes, taps, timeout=2**15): + def __init__(self, serdes, taps, timeout): self.ready = Signal() self.error = Signal() @@ -43,10 +42,10 @@ class _SerdesMasterInit(Module): NextValue(delay_min_found, 0), NextValue(delay_max, 0), NextValue(delay_max_found, 0), - serdes.rx_delay_rst.eq(1), + serdes.rx.delay_rst.eq(1), NextValue(bitslip, 0), NextState("RESET_SLAVE"), - serdes.tx_idle.eq(1) + serdes.tx.idle.eq(1) ) fsm.act("RESET_SLAVE", timer.wait.eq(1), @@ -54,16 +53,16 @@ class _SerdesMasterInit(Module): timer.wait.eq(0), NextState("SEND_PATTERN") ), - serdes.tx_idle.eq(1) + serdes.tx.idle.eq(1) ) fsm.act("SEND_PATTERN", - If(~serdes.rx_idle, + If(~serdes.rx.idle, timer.wait.eq(1), If(timer.done, NextState("CHECK_PATTERN") ) ), - serdes.tx_comma.eq(1) + serdes.tx.comma.eq(1) ) fsm.act("WAIT_STABLE", timer.wait.eq(1), @@ -71,11 +70,11 @@ class _SerdesMasterInit(Module): timer.wait.eq(0), NextState("CHECK_PATTERN") ), - serdes.tx_comma.eq(1) + serdes.tx.comma.eq(1) ) fsm.act("CHECK_PATTERN", If(~delay_min_found, - If(serdes.rx_comma, + If(serdes.rx.comma, timer.wait.eq(1), If(timer.done, timer.wait.eq(0), @@ -86,7 +85,7 @@ class _SerdesMasterInit(Module): NextState("INC_DELAY_BITSLIP") ), ).Else( - If(~serdes.rx_comma, + If(~serdes.rx.comma, NextValue(delay_max, delay), NextValue(delay_max_found, 1), NextState("CHECK_SAMPLING_WINDOW") @@ -94,9 +93,9 @@ class _SerdesMasterInit(Module): NextState("INC_DELAY_BITSLIP") ) ), - serdes.tx_comma.eq(1) + serdes.tx.comma.eq(1) ) - self.comb += serdes.rx_bitslip_value.eq(bitslip) + self.comb += serdes.rx.bitslip_value.eq(bitslip) fsm.act("INC_DELAY_BITSLIP", NextState("WAIT_STABLE"), If(delay == (taps - 1), @@ -110,12 +109,12 @@ class _SerdesMasterInit(Module): NextValue(bitslip, bitslip + 1) ), NextValue(delay, 0), - serdes.rx_delay_rst.eq(1) + serdes.rx.delay_rst.eq(1) ).Else( NextValue(delay, delay + 1), - serdes.rx_delay_inc.eq(1) + serdes.rx.delay_inc.eq(1) ), - serdes.tx_comma.eq(1) + serdes.tx.comma.eq(1) ) fsm.act("CHECK_SAMPLING_WINDOW", If((delay_min == 0) | @@ -126,19 +125,19 @@ class _SerdesMasterInit(Module): NextState("WAIT_STABLE") ).Else( NextValue(delay, 0), - serdes.rx_delay_rst.eq(1), + serdes.rx.delay_rst.eq(1), NextState("CONFIGURE_SAMPLING_WINDOW") ), - serdes.tx_comma.eq(1) + serdes.tx.comma.eq(1) ) fsm.act("CONFIGURE_SAMPLING_WINDOW", If(delay == (delay_min + (delay_max - delay_min)[1:]), NextState("READY") ).Else( NextValue(delay, delay + 1), - serdes.rx_delay_inc.eq(1) + serdes.rx.delay_inc.eq(1) ), - serdes.tx_comma.eq(1) + serdes.tx.comma.eq(1) ) fsm.act("READY", self.ready.eq(1) @@ -150,7 +149,7 @@ class _SerdesMasterInit(Module): @ResetInserter() class _SerdesSlaveInit(Module, AutoCSR): - def __init__(self, serdes, taps, timeout=2**15): + def __init__(self, serdes, taps, timeout): self.ready = Signal() self.error = Signal() @@ -173,14 +172,14 @@ class _SerdesSlaveInit(Module, AutoCSR): NextValue(delay_min_found, 0), NextValue(delay_max, 0), NextValue(delay_max_found, 0), - serdes.rx_delay_rst.eq(1), + serdes.rx.delay_rst.eq(1), NextValue(bitslip, 0), timer.wait.eq(1), If(timer.done, timer.wait.eq(0), NextState("WAIT_STABLE"), ), - serdes.tx_idle.eq(1) + serdes.tx.idle.eq(1) ) fsm.act("WAIT_STABLE", timer.wait.eq(1), @@ -188,11 +187,11 @@ class _SerdesSlaveInit(Module, AutoCSR): timer.wait.eq(0), NextState("CHECK_PATTERN") ), - serdes.tx_idle.eq(1) + serdes.tx.idle.eq(1) ) fsm.act("CHECK_PATTERN", If(~delay_min_found, - If(serdes.rx_comma, + If(serdes.rx.comma, timer.wait.eq(1), If(timer.done, timer.wait.eq(0), @@ -203,7 +202,7 @@ class _SerdesSlaveInit(Module, AutoCSR): NextState("INC_DELAY_BITSLIP") ), ).Else( - If(~serdes.rx_comma, + If(~serdes.rx.comma, NextValue(delay_max, delay), NextValue(delay_max_found, 1), NextState("CHECK_SAMPLING_WINDOW") @@ -211,9 +210,9 @@ class _SerdesSlaveInit(Module, AutoCSR): NextState("INC_DELAY_BITSLIP") ) ), - serdes.tx_idle.eq(1) + serdes.tx.idle.eq(1) ) - self.comb += serdes.rx_bitslip_value.eq(bitslip) + self.comb += serdes.rx.bitslip_value.eq(bitslip) fsm.act("INC_DELAY_BITSLIP", NextState("WAIT_STABLE"), If(delay == (taps - 1), @@ -227,12 +226,12 @@ class _SerdesSlaveInit(Module, AutoCSR): NextValue(bitslip, bitslip + 1) ), NextValue(delay, 0), - serdes.rx_delay_rst.eq(1) + serdes.rx.delay_rst.eq(1) ).Else( NextValue(delay, delay + 1), - serdes.rx_delay_inc.eq(1) + serdes.rx.delay_inc.eq(1) ), - serdes.tx_idle.eq(1) + serdes.tx.idle.eq(1) ) fsm.act("CHECK_SAMPLING_WINDOW", If((delay_min == 0) | @@ -243,28 +242,28 @@ class _SerdesSlaveInit(Module, AutoCSR): NextState("WAIT_STABLE") ).Else( NextValue(delay, 0), - serdes.rx_delay_rst.eq(1), + serdes.rx.delay_rst.eq(1), NextState("CONFIGURE_SAMPLING_WINDOW") ), - serdes.tx_idle.eq(1) + serdes.tx.idle.eq(1) ) fsm.act("CONFIGURE_SAMPLING_WINDOW", If(delay == (delay_min + (delay_max - delay_min)[1:]), NextState("SEND_PATTERN") ).Else( NextValue(delay, delay + 1), - serdes.rx_delay_inc.eq(1), + serdes.rx.delay_inc.eq(1), ), - serdes.tx_idle.eq(1) + serdes.tx.idle.eq(1) ) fsm.act("SEND_PATTERN", timer.wait.eq(1), If(timer.done, - If(~serdes.rx_comma, + If(~serdes.rx.comma, NextState("READY") ) ), - serdes.tx_comma.eq(1) + serdes.tx.comma.eq(1) ) fsm.act("READY", self.ready.eq(1) @@ -288,8 +287,6 @@ class _SerdesControl(Module, AutoCSR): self.delay_max = CSRStatus(9) self.bitslip = CSRStatus(6) - self.scrambling_enable = CSRStorage() - self.prbs_error = Signal() self.prbs_start = CSR() self.prbs_cycles = CSRStorage(32) @@ -307,8 +304,8 @@ class _SerdesControl(Module, AutoCSR): # Master reset the Slave by putting the link # in idle. self.sync += [ - init.reset.eq(serdes.rx_idle), - serdes.reset.eq(serdes.rx_idle) + init.reset.eq(serdes.rx.idle), + serdes.reset.eq(serdes.rx.idle) ] self.comb += [ self.ready.status.eq(init.ready), @@ -364,31 +361,26 @@ class SERWBPHY(Module, AutoCSR): self.submodules.control = _SerdesControl(self.serdes, self.init, mode) # scrambling - scrambler = Scrambler() - descrambler = Descrambler() - self.submodules += scrambler, descrambler - self.comb += [ - scrambler.enable.eq(self.control.scrambling_enable.storage), - descrambler.enable.eq(self.control.scrambling_enable.storage) - ] + self.submodules.scrambler = scrambler = Scrambler() + self.submodules.descrambler = descrambler = Descrambler() # tx dataflow self.comb += \ If(self.init.ready, sink.connect(scrambler.sink), - scrambler.source.ack.eq(self.serdes.tx_ce), + scrambler.source.ack.eq(self.serdes.tx.ce), If(scrambler.source.stb, - self.serdes.tx_d.eq(scrambler.source.d), - self.serdes.tx_k.eq(scrambler.source.k) + self.serdes.tx.d.eq(scrambler.source.d), + self.serdes.tx.k.eq(scrambler.source.k) ) ) # rx dataflow self.comb += [ If(self.init.ready, - descrambler.sink.stb.eq(self.serdes.rx_ce), - descrambler.sink.d.eq(self.serdes.rx_d), - descrambler.sink.k.eq(self.serdes.rx_k), + descrambler.sink.stb.eq(self.serdes.rx.ce), + descrambler.sink.d.eq(self.serdes.rx.d), + descrambler.sink.k.eq(self.serdes.rx.k), descrambler.source.connect(source) ), # For PRBS test we are using the scrambler/descrambler as PRBS, diff --git a/artiq/gateware/serwb/s7phy.py b/artiq/gateware/serwb/s7phy.py deleted file mode 100644 index cc7cc4e30..000000000 --- a/artiq/gateware/serwb/s7phy.py +++ /dev/null @@ -1,230 +0,0 @@ -from migen import * -from migen.genlib.misc import BitSlip -from migen.genlib.misc import WaitTimer - -from misoc.interconnect import stream -from misoc.cores.code_8b10b import Encoder, Decoder - - -def K(x, y): - return (y << 5) | x - - -@ResetInserter() -class S7Serdes(Module): - def __init__(self, pads, mode="master"): - if mode == "slave": - self.refclk = Signal() - - self.tx_ce = Signal() - self.tx_k = Signal(4) - self.tx_d = Signal(32) - - self.rx_ce = Signal() - self.rx_k = Signal(4) - self.rx_d = Signal(32) - - self.tx_idle = Signal() - self.tx_comma = Signal() - self.rx_idle = Signal() - self.rx_comma = Signal() - - self.rx_bitslip_value = Signal(6) - self.rx_delay_rst = Signal() - self.rx_delay_inc = Signal() - - # # # - - self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) - self.comb += encoder.ce.eq(self.tx_ce) - self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] - self.comb += [decoders[i].ce.eq(self.rx_ce) for i in range(4)] - - # clocking: - - # In Master mode: - # - linerate/10 refclk is generated on clk_pads - # In Slave mode: - # - linerate/10 refclk is provided by clk_pads - - # tx clock (linerate/10) - if mode == "master": - clk_converter = stream.Converter(40, 8) - self.submodules += clk_converter - self.comb += [ - clk_converter.sink.stb.eq(1), - clk_converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), - clk_converter.source.ack.eq(1) - ] - clk_o = Signal() - self.specials += [ - Instance("OSERDESE2", - p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", - p_SERDES_MODE="MASTER", - - o_OQ=clk_o, - i_OCE=1, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D1=clk_converter.source.data[0], i_D2=clk_converter.source.data[1], - i_D3=clk_converter.source.data[2], i_D4=clk_converter.source.data[3], - i_D5=clk_converter.source.data[4], i_D6=clk_converter.source.data[5], - i_D7=clk_converter.source.data[6], i_D8=clk_converter.source.data[7] - ), - Instance("OBUFDS", - i_I=clk_o, - o_O=pads.clk_p, - o_OB=pads.clk_n - ) - ] - - # tx datapath - # tx_data -> encoders -> converter -> serdes - self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) - self.comb += [ - tx_converter.sink.stb.eq(1), - self.tx_ce.eq(tx_converter.sink.ack), - tx_converter.source.ack.eq(1), - If(self.tx_idle, - tx_converter.sink.data.eq(0) - ).Else( - tx_converter.sink.data.eq( - Cat(*[encoder.output[i] for i in range(4)])) - ), - If(self.tx_comma, - encoder.k[0].eq(1), - encoder.d[0].eq(K(28,5)), - ).Else( - encoder.k[0].eq(self.tx_k[0]), - encoder.k[1].eq(self.tx_k[1]), - encoder.k[2].eq(self.tx_k[2]), - encoder.k[3].eq(self.tx_k[3]), - encoder.d[0].eq(self.tx_d[0:8]), - encoder.d[1].eq(self.tx_d[8:16]), - encoder.d[2].eq(self.tx_d[16:24]), - encoder.d[3].eq(self.tx_d[24:32]) - ) - ] - - serdes_o = Signal() - self.specials += [ - Instance("OSERDESE2", - p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", - p_SERDES_MODE="MASTER", - - o_OQ=serdes_o, - i_OCE=1, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D1=tx_converter.source.data[0], i_D2=tx_converter.source.data[1], - i_D3=tx_converter.source.data[2], i_D4=tx_converter.source.data[3], - i_D5=tx_converter.source.data[4], i_D6=tx_converter.source.data[5], - i_D7=tx_converter.source.data[6], i_D8=tx_converter.source.data[7] - ), - Instance("OBUFDS", - i_I=serdes_o, - o_O=pads.tx_p, - o_OB=pads.tx_n - ) - ] - - # rx clock - use_bufr = True - if mode == "slave": - clk_i = Signal() - clk_i_bufg = Signal() - self.specials += [ - Instance("IBUFDS", - i_I=pads.clk_p, - i_IB=pads.clk_n, - o_O=clk_i - ) - ] - if use_bufr: - clk_i_bufr = Signal() - self.specials += [ - Instance("BUFR", i_I=clk_i, o_O=clk_i_bufr), - Instance("BUFG", i_I=clk_i_bufr, o_O=clk_i_bufg) - ] - else: - self.specials += Instance("BUFG", i_I=clk_i, o_O=clk_i_bufg) - self.comb += self.refclk.eq(clk_i_bufg) - - # rx datapath - # serdes -> converter -> bitslip -> decoders -> rx_data - self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) - self.comb += [ - self.rx_ce.eq(rx_converter.source.stb), - rx_converter.source.ack.eq(1) - ] - self.submodules.rx_bitslip = rx_bitslip = CEInserter()(BitSlip(40)) - self.comb += rx_bitslip.ce.eq(self.rx_ce) - - serdes_i_nodelay = Signal() - self.specials += [ - Instance("IBUFDS_DIFF_OUT", - i_I=pads.rx_p, - i_IB=pads.rx_n, - o_O=serdes_i_nodelay - ) - ] - - serdes_i_delayed = Signal() - serdes_q = Signal(8) - self.specials += [ - Instance("IDELAYE2", - p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA", - p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", - p_REFCLK_FREQUENCY=200.0, p_PIPE_SEL="FALSE", - p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=0, - - i_C=ClockSignal(), - i_LD=self.rx_delay_rst, - i_CE=self.rx_delay_inc, - i_LDPIPEEN=0, i_INC=1, - - i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed - ), - Instance("ISERDESE2", - p_DATA_WIDTH=8, p_DATA_RATE="DDR", - p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", - p_NUM_CE=1, p_IOBDELAY="IFD", - - i_DDLY=serdes_i_delayed, - i_CE1=1, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKB=~ClockSignal("sys4x"), - i_CLKDIV=ClockSignal("sys"), - i_BITSLIP=0, - o_Q8=serdes_q[0], o_Q7=serdes_q[1], - o_Q6=serdes_q[2], o_Q5=serdes_q[3], - o_Q4=serdes_q[4], o_Q3=serdes_q[5], - o_Q2=serdes_q[6], o_Q1=serdes_q[7] - ) - ] - - self.comb += [ - rx_converter.sink.stb.eq(1), - rx_converter.sink.data.eq(serdes_q), - rx_bitslip.value.eq(self.rx_bitslip_value), - rx_bitslip.i.eq(rx_converter.source.data), - decoders[0].input.eq(rx_bitslip.o[0:10]), - decoders[1].input.eq(rx_bitslip.o[10:20]), - decoders[2].input.eq(rx_bitslip.o[20:30]), - decoders[3].input.eq(rx_bitslip.o[30:40]), - self.rx_k.eq(Cat(*[decoders[i].k for i in range(4)])), - self.rx_d.eq(Cat(*[decoders[i].d for i in range(4)])), - self.rx_comma.eq( - (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & - (decoders[1].k == 0) & (decoders[1].d == 0) & - (decoders[2].k == 0) & (decoders[2].d == 0) & - (decoders[3].k == 0) & (decoders[3].d == 0)) - ] - - idle_timer = WaitTimer(32) - self.submodules += idle_timer - self.comb += idle_timer.wait.eq(1) - self.sync += self.rx_idle.eq(idle_timer.done & - ((rx_bitslip.o == 0) | (rx_bitslip.o == (2**40-1)))) diff --git a/artiq/gateware/serwb/s7serdes.py b/artiq/gateware/serwb/s7serdes.py new file mode 100644 index 000000000..12fabade0 --- /dev/null +++ b/artiq/gateware/serwb/s7serdes.py @@ -0,0 +1,225 @@ +from migen import * +from migen.genlib.io import * +from migen.genlib.misc import BitSlip, WaitTimer + +from misoc.interconnect import stream +from misoc.cores.code_8b10b import Encoder, Decoder + + +def K(x, y): + return (y << 5) | x + + +class _S7SerdesClocking(Module): + def __init__(self, pads, mode="master"): + self.refclk = Signal() + + # # # + + # In Master mode, generate the linerate/10 clock. Slave will re-multiply it. + if mode == "master": + converter = stream.Converter(40, 8) + self.submodules += converter + self.comb += [ + converter.sink.stb.eq(1), + converter.source.ack.eq(1), + converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), + ] + self.specials += [ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", + p_SERDES_MODE="MASTER", + + o_OQ=self.refclk, + i_OCE=1, + i_RST=ResetSignal("sys"), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), + i_D1=converter.source.data[0], i_D2=converter.source.data[1], + i_D3=converter.source.data[2], i_D4=converter.source.data[3], + i_D5=converter.source.data[4], i_D6=converter.source.data[5], + i_D7=converter.source.data[6], i_D8=converter.source.data[7] + ), + DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) + ] + + # In Slave mode, multiply the clock provided by Master with a PLL/MMCM + elif mode == "slave": + self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk) + + +class _S7SerdesTX(Module): + def __init__(self, pads, mode="master"): + # Control + self.idle = idle = Signal() + self.comma = comma = Signal() + + # Datapath + self.ce = ce = Signal() + self.k = k = Signal(4) + self.d = d = Signal(32) + + # # # + + # 8b10b encoder + self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) + self.comb += encoder.ce.eq(ce) + + # 40 --> 8 converter + converter = stream.Converter(40, 8) + self.submodules += converter + self.comb += [ + converter.sink.stb.eq(1), + converter.source.ack.eq(1), + # Enable pipeline when converter accepts the 40 bits + ce.eq(converter.sink.ack), + # If not idle, connect encoder to converter + If(~idle, + converter.sink.data.eq(Cat(*[encoder.output[i] for i in range(4)])) + ), + # If comma, send K28.5 + If(comma, + encoder.k[0].eq(1), + encoder.d[0].eq(K(28,5)), + # Else connect TX to encoder + ).Else( + encoder.k[0].eq(k[0]), + encoder.k[1].eq(k[1]), + encoder.k[2].eq(k[2]), + encoder.k[3].eq(k[3]), + encoder.d[0].eq(d[0:8]), + encoder.d[1].eq(d[8:16]), + encoder.d[2].eq(d[16:24]), + encoder.d[3].eq(d[24:32]) + ) + ] + + # Data output (DDR with sys4x) + data = Signal() + self.specials += [ + Instance("OSERDESE2", + p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", + p_SERDES_MODE="MASTER", + + o_OQ=data, + i_OCE=1, + i_RST=ResetSignal("sys"), + i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), + i_D1=converter.source.data[0], i_D2=converter.source.data[1], + i_D3=converter.source.data[2], i_D4=converter.source.data[3], + i_D5=converter.source.data[4], i_D6=converter.source.data[5], + i_D7=converter.source.data[6], i_D8=converter.source.data[7] + ), + DifferentialOutput(data, pads.tx_p, pads.tx_n) + ] + + +class _S7SerdesRX(Module): + def __init__(self, pads, mode="master"): + # Control + self.delay_rst = Signal() + self.delay_inc = Signal() + self.bitslip_value = bitslip_value = Signal(6) + + # Status + self.idle = idle = Signal() + self.comma = comma = Signal() + + # Datapath + self.ce = ce = Signal() + self.k = k = Signal(4) + self.d = d = Signal(32) + + # # # + + # Data input (DDR with sys4x) + data_nodelay = Signal() + data_delayed = Signal() + data_deserialized = Signal(8) + self.specials += [ + DifferentialInput(pads.rx_p, pads.rx_n, data_nodelay), + Instance("IDELAYE2", + p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA", + p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", + p_REFCLK_FREQUENCY=200.0, p_PIPE_SEL="FALSE", + p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=0, + + i_C=ClockSignal(), + i_LD=self.delay_rst, + i_CE=self.delay_inc, + i_LDPIPEEN=0, i_INC=1, + + i_IDATAIN=data_nodelay, o_DATAOUT=data_delayed + ), + Instance("ISERDESE2", + p_DATA_WIDTH=8, p_DATA_RATE="DDR", + p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", + p_NUM_CE=1, p_IOBDELAY="IFD", + + i_DDLY=data_delayed, + i_CE1=1, + i_RST=ResetSignal("sys"), + i_CLK=ClockSignal("sys4x"), i_CLKB=~ClockSignal("sys4x"), + i_CLKDIV=ClockSignal("sys"), + i_BITSLIP=0, + o_Q8=data_deserialized[0], o_Q7=data_deserialized[1], + o_Q6=data_deserialized[2], o_Q5=data_deserialized[3], + o_Q4=data_deserialized[4], o_Q3=data_deserialized[5], + o_Q2=data_deserialized[6], o_Q1=data_deserialized[7] + ) + ] + + # 8 --> 40 converter and bitslip + converter = stream.Converter(8, 40) + self.submodules += converter + bitslip = CEInserter()(BitSlip(40)) + self.submodules += bitslip + self.comb += [ + converter.sink.stb.eq(1), + converter.source.ack.eq(1), + # Enable pipeline when converter outputs the 40 bits + ce.eq(converter.source.stb), + # Connect input data to converter + converter.sink.data.eq(data_deserialized), + # Connect converter to bitslip + bitslip.ce.eq(ce), + bitslip.value.eq(bitslip_value), + bitslip.i.eq(converter.source.data) + ] + + # 8b10b decoder + self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] + self.comb += [decoders[i].ce.eq(ce) for i in range(4)] + self.comb += [ + # Connect bitslip to decoder + decoders[0].input.eq(bitslip.o[0:10]), + decoders[1].input.eq(bitslip.o[10:20]), + decoders[2].input.eq(bitslip.o[20:30]), + decoders[3].input.eq(bitslip.o[30:40]), + # Connect decoder to output + self.k.eq(Cat(*[decoders[i].k for i in range(4)])), + self.d.eq(Cat(*[decoders[i].d for i in range(4)])), + ] + + # Status + idle_timer = WaitTimer(256) + self.submodules += idle_timer + self.comb += [ + idle_timer.wait.eq(1), + self.idle.eq(idle_timer.done & + ((bitslip.o == 0) | (bitslip.o == (2**40-1)))), + self.comma.eq( + (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & + (decoders[1].k == 0) & (decoders[1].d == 0) & + (decoders[2].k == 0) & (decoders[2].d == 0) & + (decoders[3].k == 0) & (decoders[3].d == 0)) + ] + + +@ResetInserter() +class S7Serdes(Module): + def __init__(self, pads, mode="master"): + self.submodules.clocking = _S7SerdesClocking(pads, mode) + self.submodules.tx = _S7SerdesTX(pads, mode) + self.submodules.rx = _S7SerdesRX(pads, mode) From 77fc5c599fd53fc7dcc9f48925def5c592618f6b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 15 May 2018 23:52:58 +0200 Subject: [PATCH 0784/2457] serwb/test: update --- artiq/gateware/test/serwb/test_serwb_init.py | 39 +++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/artiq/gateware/test/serwb/test_serwb_init.py b/artiq/gateware/test/serwb/test_serwb_init.py index 1651489fa..c54e9cae9 100644 --- a/artiq/gateware/test/serwb/test_serwb_init.py +++ b/artiq/gateware/test/serwb/test_serwb_init.py @@ -8,14 +8,17 @@ from artiq.gateware.serwb.phy import _SerdesMasterInit, _SerdesSlaveInit class SerdesModel(Module): def __init__(self, taps, mode="slave"): - self.tx_idle = Signal() - self.tx_comma = Signal() - self.rx_idle = Signal() - self.rx_comma = Signal() + self.tx = Module() + self.rx = Module() - self.rx_bitslip_value = Signal(6) - self.rx_delay_rst = Signal() - self.rx_delay_inc = Signal() + self.tx.idle = Signal() + self.tx.comma = Signal() + self.rx.idle = Signal() + self.rx.comma = Signal() + + self.rx.bitslip_value = Signal(6) + self.rx.delay_rst = Signal() + self.rx.delay_inc = Signal() self.valid_bitslip = Signal(6) self.valid_delays = Signal(taps) @@ -30,29 +33,29 @@ class SerdesModel(Module): self.comb += valid_delays[taps-1-i].eq(self.valid_delays[i]) self.sync += [ - bitslip.eq(self.rx_bitslip_value), - If(self.rx_delay_rst, + bitslip.eq(self.rx.bitslip_value), + If(self.rx.delay_rst, delay.eq(0) - ).Elif(self.rx_delay_inc, + ).Elif(self.rx.delay_inc, delay.eq(delay + 1) ) ] if mode == "master": self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) - self.comb += self.fsm.reset.eq(self.tx_idle) + self.comb += self.fsm.reset.eq(self.tx.idle) fsm.act("IDLE", - If(self.tx_comma, + If(self.tx.comma, NextState("SEND_COMMA") ), - self.rx_idle.eq(1) + self.rx.idle.eq(1) ) fsm.act("SEND_COMMA", If(valid_delays[delay] & (bitslip == self.valid_bitslip), - self.rx_comma.eq(1) + self.rx.comma.eq(1) ), - If(~self.tx_comma, + If(~self.tx.comma, NextState("READY") ) ) @@ -60,15 +63,15 @@ class SerdesModel(Module): elif mode == "slave": self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", - self.rx_idle.eq(1), + self.rx.idle.eq(1), NextState("SEND_COMMA") ) fsm.act("SEND_COMMA", If(valid_delays[delay] & (bitslip == self.valid_bitslip), - self.rx_comma.eq(1) + self.rx.comma.eq(1) ), - If(~self.tx_idle, + If(~self.tx.idle, NextState("READY") ) ) From f77bcbebb5c23f0ea1d5ca8e9094d2b51d0c40d8 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 16 May 2018 08:34:53 +0200 Subject: [PATCH 0785/2457] serwb/test_serwb_core: fix --- artiq/gateware/test/serwb/test_serwb_core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/test/serwb/test_serwb_core.py b/artiq/gateware/test/serwb/test_serwb_core.py index 0e964b5b1..4a3fa7898 100644 --- a/artiq/gateware/test/serwb/test_serwb_core.py +++ b/artiq/gateware/test/serwb/test_serwb_core.py @@ -115,7 +115,7 @@ class TestSERWBCore(unittest.TestCase): yield dut.scrambler.sink.data.eq(i) # check - yield dut.descrambler.source.ack.eq(prng.randrange(prng.randrange(100) > rand_level) + yield dut.descrambler.source.ack.eq(prng.randrange(100) > rand_level) if (yield dut.descrambler.source.stb) & (yield dut.descrambler.source.ack): current_data = (yield dut.descrambler.source.data) if (current_data != (last_data + 1)): From b81b20caf8361c13f091ad85dcee31dd37d11d72 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 16 May 2018 16:25:44 +0800 Subject: [PATCH 0786/2457] conda: use h5py 2.8 For some reason, conda installs 2.7 by default, which causes messages such as: /home/sb/miniconda3/envs/py35/lib/python3.5/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`. --- conda/artiq-dev/meta.yaml | 2 +- conda/artiq/meta.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 62629e2a2..ec43ce29c 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -34,7 +34,7 @@ requirements: - sphinx-argparse - sphinxcontrib-wavedrom - sphinx_rtd_theme - - h5py + - h5py 2.8 - python-dateutil - pyqt >=5.5 - quamash diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index 192f79e40..8f699ec5b 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -37,7 +37,7 @@ requirements: - numpy - prettytable - asyncserial - - h5py + - h5py 2.8 - python-dateutil - pyqt >=5.5 - quamash From d446a3293ec2869aef4b2ec846b553975a38a01d Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 16 May 2018 13:50:44 +0000 Subject: [PATCH 0787/2457] frontend: merge core{config,log,boot,debug,profile} into coremgmt. --- .../profiler.py} | 77 +------ artiq/frontend/aqctl_corelog.py | 81 ------- artiq/frontend/artiq_coreboot.py | 51 ----- artiq/frontend/artiq_coreconfig.py | 79 ------- artiq/frontend/artiq_coredebug.py | 43 ---- artiq/frontend/artiq_corelog.py | 56 ----- artiq/frontend/artiq_coremgmt.py | 200 ++++++++++++++++++ setup.py | 6 +- 8 files changed, 205 insertions(+), 388 deletions(-) rename artiq/{frontend/artiq_coreprofile.py => coredevice/profiler.py} (50%) mode change 100755 => 100644 delete mode 100755 artiq/frontend/aqctl_corelog.py delete mode 100755 artiq/frontend/artiq_coreboot.py delete mode 100755 artiq/frontend/artiq_coreconfig.py delete mode 100755 artiq/frontend/artiq_coredebug.py delete mode 100755 artiq/frontend/artiq_corelog.py create mode 100644 artiq/frontend/artiq_coremgmt.py diff --git a/artiq/frontend/artiq_coreprofile.py b/artiq/coredevice/profiler.py old mode 100755 new mode 100644 similarity index 50% rename from artiq/frontend/artiq_coreprofile.py rename to artiq/coredevice/profiler.py index 5b300e911..5bbbe1996 --- a/artiq/frontend/artiq_coreprofile.py +++ b/artiq/coredevice/profiler.py @@ -1,20 +1,11 @@ -#!/usr/bin/env python3 - -import argparse -import sys -import struct from collections import defaultdict import subprocess -from artiq.tools import verbosity_args, init_logger -from artiq.master.databases import DeviceDB -from artiq.coredevice.comm_mgmt import CommMgmt - class Symbolizer: - def __init__(self, binary): + def __init__(self, binary, triple): self._addr2line = subprocess.Popen([ - "or1k-linux-addr2line", "--exe=" + binary, + triple + "-addr2line", "--exe=" + binary, "--addresses", "--demangle=rust", "--functions", "--inlines" ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True) @@ -39,13 +30,13 @@ class Symbolizer: class CallgrindWriter: - def __init__(self, output, binary, compression=True): + def __init__(self, output, binary, triple, compression=True): self._output = output self._binary = binary self._current = defaultdict(lambda: None) self._ids = defaultdict(lambda: {}) self._compression = compression - self._symbolizer = Symbolizer(binary) + self._symbolizer = Symbolizer(binary, triple) def _write(self, fmt, *args, **kwargs): self._output.write(fmt.format(*args, **kwargs)) @@ -93,63 +84,3 @@ class CallgrindWriter: self._spec("fn", function) self._spec("fl", file) self._write("0x{:08x} {} {}", caller, line, count) - - -def get_argparser(): - parser = argparse.ArgumentParser(description="ARTIQ core device profiling tool") - - verbosity_args(parser) - parser.add_argument("--device-db", default="device_db.py", - help="device database file (default: '%(default)s')") - - subparsers = parser.add_subparsers(dest="action") - subparsers.required = True - - p_start = subparsers.add_parser("start", - help="start profiling") - p_start.add_argument("--interval", metavar="MICROS", type=int, default=2000, - help="sampling interval, in microseconds") - p_start.add_argument("--hits-size", metavar="ENTRIES", type=int, default=8192, - help="hit buffer size") - p_start.add_argument("--edges-size", metavar="ENTRIES", type=int, default=0, - help="edge buffer size (edge profiling not implemented)") - - p_stop = subparsers.add_parser("stop", - help="stop profiling") - - p_save = subparsers.add_parser("save", - help="save profile") - p_save.add_argument("output", metavar="OUTPUT", type=argparse.FileType("w"), - help="file to save profile to, in Callgrind format") - p_save.add_argument("firmware", metavar="FIRMWARE", type=str, - help="path to firmware ELF file") - p_save.add_argument("--no-compression", default=False, action='store_true', - help="disable profile compression") - - return parser - - -def main(): - args = get_argparser().parse_args() - init_logger(args) - - core_addr = DeviceDB(args.device_db).get("core")["arguments"]["host"] - mgmt = CommMgmt(core_addr) - try: - if args.action == "start": - mgmt.start_profiler(args.interval, args.hits_size, args.edges_size) - elif args.action == "stop": - mgmt.stop_profiler() - elif args.action == "save": - hits, edges = mgmt.get_profile() - writer = CallgrindWriter(args.output, args.firmware, not args.no_compression) - writer.header() - for addr, count in hits.items(): - writer.hit(addr, count) - for (caller, callee), count in edges.items(): - writer.edge(caller, callee, count) - finally: - mgmt.close() - -if __name__ == "__main__": - main() diff --git a/artiq/frontend/aqctl_corelog.py b/artiq/frontend/aqctl_corelog.py deleted file mode 100755 index 7cee0b974..000000000 --- a/artiq/frontend/aqctl_corelog.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import asyncio -import struct -import logging -import re - -from artiq.tools import * -from artiq.protocols.pc_rpc import Server -from artiq.protocols.logging import log_with_name -from artiq.coredevice.comm_mgmt import Request, Reply - - -def get_argparser(): - parser = argparse.ArgumentParser( - description="ARTIQ controller for core device logs") - simple_network_args(parser, 1068) - parser.add_argument("core_addr", - help="hostname or IP address of the core device") - return parser - - -class PingTarget: - def ping(self): - return True - - -async def get_logs(host): - reader, writer = await asyncio.open_connection(host, 1380) - writer.write(b"ARTIQ management\n") - writer.write(struct.pack("B", Request.PullLog.value)) - await writer.drain() - - while True: - length, = struct.unpack(">l", await reader.readexactly(4)) - log = await reader.readexactly(length) - - for line in log.decode("utf-8").splitlines(): - m = re.match(r"^\[.+?\] (TRACE|DEBUG| INFO| WARN|ERROR)\((.+?)\): (.+)$", line) - levelname = m.group(1) - if levelname == 'TRACE': - level = logging.TRACE - elif levelname == 'DEBUG': - level = logging.DEBUG - elif levelname == ' INFO': - level = logging.INFO - elif levelname == ' WARN': - level = logging.WARN - elif levelname == 'ERROR': - level = logging.ERROR - name = 'firmware.' + m.group(2).replace('::', '.') - text = m.group(3) - log_with_name(name, level, text) - - -def main(): - args = get_argparser().parse_args() - - loop = asyncio.get_event_loop() - try: - get_logs_task = asyncio.ensure_future(get_logs(args.core_addr)) - try: - server = Server({"corelog": PingTarget()}, None, True) - loop.run_until_complete(server.start(bind_address_from_args(args), args.port)) - try: - multiline_log_config(logging.TRACE) - loop.run_until_complete(server.wait_terminate()) - finally: - loop.run_until_complete(server.stop()) - finally: - get_logs_task.cancel() - try: - loop.run_until_complete(get_logs_task) - except asyncio.CancelledError: - pass - finally: - loop.close() - -if __name__ == "__main__": - main() diff --git a/artiq/frontend/artiq_coreboot.py b/artiq/frontend/artiq_coreboot.py deleted file mode 100755 index c0136292e..000000000 --- a/artiq/frontend/artiq_coreboot.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import sys -import struct - -from artiq.tools import verbosity_args, init_logger -from artiq.master.databases import DeviceDB -from artiq.coredevice.comm_mgmt import CommMgmt - - -def get_argparser(): - parser = argparse.ArgumentParser(description="ARTIQ core device boot tool") - - verbosity_args(parser) - parser.add_argument("--device-db", default="device_db.py", - help="device database file (default: '%(default)s')") - - subparsers = parser.add_subparsers(dest="action") - - p_reboot = subparsers.add_parser("reboot", - help="reboot the currently running firmware") - - p_hotswap = subparsers.add_parser("hotswap", - help="load the specified firmware in RAM") - - p_hotswap.add_argument("image", metavar="IMAGE", type=argparse.FileType("rb"), - help="runtime image to be executed") - - return parser - - -def main(): - args = get_argparser().parse_args() - init_logger(args) - - core_addr = DeviceDB(args.device_db).get("core")["arguments"]["host"] - mgmt = CommMgmt(core_addr) - try: - if args.action == "reboot": - mgmt.reboot() - elif args.action == "hotswap": - mgmt.hotswap(args.image.read()) - else: - print("An action needs to be specified.", file=sys.stderr) - sys.exit(1) - finally: - mgmt.close() - -if __name__ == "__main__": - main() diff --git a/artiq/frontend/artiq_coreconfig.py b/artiq/frontend/artiq_coreconfig.py deleted file mode 100755 index 6f1ff2e42..000000000 --- a/artiq/frontend/artiq_coreconfig.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import struct - -from artiq.tools import verbosity_args, init_logger -from artiq.master.databases import DeviceDB -from artiq.master.worker_db import DeviceManager - - -def get_argparser(): - parser = argparse.ArgumentParser(description="ARTIQ core device " - "configuration tool") - - verbosity_args(parser) - parser.add_argument("--device-db", default="device_db.py", - help="device database file (default: '%(default)s')") - - subparsers = parser.add_subparsers(dest="action") - subparsers.required = True - - p_read = subparsers.add_parser("read", - help="read key from core device config") - p_read.add_argument("key", metavar="KEY", type=str, - help="key to be read from core device config") - - p_write = subparsers.add_parser("write", - help="write key-value records to core " - "device config") - p_write.add_argument("-s", "--string", nargs=2, action="append", - default=[], metavar=("KEY", "STRING"), type=str, - help="key-value records to be written to core device " - "config") - p_write.add_argument("-f", "--file", nargs=2, action="append", - type=str, default=[], - metavar=("KEY", "FILENAME"), - help="key and file whose content to be written to " - "core device config") - - p_delete = subparsers.add_parser("delete", - help="delete key from core device config") - p_delete.add_argument("key", metavar="KEY", nargs=argparse.REMAINDER, - default=[], type=str, - help="key to be deleted from core device config") - - subparsers.add_parser("erase", help="fully erase core device config") - return parser - - -def main(): - args = get_argparser().parse_args() - init_logger(args) - device_mgr = DeviceManager(DeviceDB(args.device_db)) - try: - comm = device_mgr.get("core").comm - comm.check_system_info() - - if args.action == "read": - value = comm.flash_storage_read(args.key) - if not value: - print("Key {} does not exist".format(args.key)) - else: - print(value) - elif args.action == "write": - for key, value in args.string: - comm.flash_storage_write(key, value.encode("utf-8")) - for key, filename in args.file: - with open(filename, "rb") as fi: - comm.flash_storage_write(key, fi.read()) - elif args.action == "delete": - for key in args.key: - comm.flash_storage_remove(key) - elif args.action == "erase": - comm.flash_storage_erase() - finally: - device_mgr.close_devices() - -if __name__ == "__main__": - main() diff --git a/artiq/frontend/artiq_coredebug.py b/artiq/frontend/artiq_coredebug.py deleted file mode 100755 index 55631e037..000000000 --- a/artiq/frontend/artiq_coredebug.py +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import sys -import struct - -from artiq.tools import verbosity_args, init_logger -from artiq.master.databases import DeviceDB -from artiq.coredevice.comm_mgmt import CommMgmt - - -def get_argparser(): - parser = argparse.ArgumentParser(description="ARTIQ core device debug tool") - - verbosity_args(parser) - parser.add_argument("--device-db", default="device_db.py", - help="device database file (default: '%(default)s')") - - subparsers = parser.add_subparsers(dest="action") - - p_allocator = subparsers.add_parser("allocator", - help="show heap layout") - - return parser - - -def main(): - args = get_argparser().parse_args() - init_logger(args) - - core_addr = DeviceDB(args.device_db).get("core")["arguments"]["host"] - mgmt = CommMgmt(core_addr) - try: - if args.action == "allocator": - mgmt.debug_allocator() - else: - print("An action needs to be specified.", file=sys.stderr) - sys.exit(1) - finally: - mgmt.close() - -if __name__ == "__main__": - main() diff --git a/artiq/frontend/artiq_corelog.py b/artiq/frontend/artiq_corelog.py deleted file mode 100755 index 0f7cd8759..000000000 --- a/artiq/frontend/artiq_corelog.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 - -import argparse - -from artiq.tools import verbosity_args, init_logger -from artiq.master.databases import DeviceDB -from artiq.coredevice.comm_mgmt import CommMgmt - - -def get_argparser(): - parser = argparse.ArgumentParser(description="ARTIQ core device " - "log tool") - verbosity_args(parser) - parser.add_argument("--device-db", default="device_db.py", - help="device database file (default: '%(default)s')") - - subparsers = parser.add_subparsers(dest="action") - - p_clear = subparsers.add_parser("clear", - help="clear log buffer") - - p_set_level = subparsers.add_parser("set_level", - help="set minimum level for messages to be logged") - p_set_level.add_argument("level", metavar="LEVEL", type=str, - help="log level (one of: OFF ERROR WARN INFO DEBUG TRACE)") - - p_set_uart_level = subparsers.add_parser("set_uart_level", - help="set minimum level for messages to be logged " - "to UART") - p_set_uart_level.add_argument("level", metavar="LEVEL", type=str, - help="log level (one of: OFF ERROR WARN INFO DEBUG TRACE)") - - return parser - - -def main(): - args = get_argparser().parse_args() - init_logger(args) - - core_addr = DeviceDB(args.device_db).get("core")["arguments"]["host"] - mgmt = CommMgmt(core_addr) - try: - if args.action == "set_level": - mgmt.set_log_level(args.level) - elif args.action == "set_uart_level": - mgmt.set_uart_log_level(args.level) - elif args.action == "clear": - mgmt.clear_log() - else: - print(mgmt.get_log(), end="") - finally: - mgmt.close() - - -if __name__ == "__main__": - main() diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py new file mode 100644 index 000000000..6013b7359 --- /dev/null +++ b/artiq/frontend/artiq_coremgmt.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python3 + +import argparse +import struct + +from artiq.tools import verbosity_args, init_logger +from artiq.master.databases import DeviceDB +from artiq.master.worker_db import DeviceManager +from artiq.coredevice.comm_kernel import CommKernel +from artiq.coredevice.comm_mgmt import CommMgmt +from artiq.coredevice.profiler import CallgrindWriter + + +def get_argparser(): + parser = argparse.ArgumentParser(description="ARTIQ core device " + "management tool") + + verbosity_args(parser) + parser.add_argument("--device-db", default="device_db.py", + help="device database file (default: '%(default)s')") + + tools = parser.add_subparsers(dest="tool") + tools.required = True + + # logging + t_log = tools.add_parser("log", + help="read logs and change log levels") + + subparsers = t_log.add_subparsers(dest="action") + + p_clear = subparsers.add_parser("clear", + help="clear log buffer") + + p_set_level = subparsers.add_parser("set_level", + help="set minimum level for messages to be logged") + p_set_level.add_argument("level", metavar="LEVEL", type=str, + help="log level (one of: OFF ERROR WARN INFO DEBUG TRACE)") + + p_set_uart_level = subparsers.add_parser("set_uart_level", + help="set minimum level for messages to be logged " + "to UART") + p_set_uart_level.add_argument("level", metavar="LEVEL", type=str, + help="log level (one of: OFF ERROR WARN INFO DEBUG TRACE)") + + # configuration + t_config = tools.add_parser("config", + help="read and change core device configuration") + + subparsers = t_config.add_subparsers(dest="action") + subparsers.required = True + + p_read = subparsers.add_parser("read", + help="read key from core device config") + p_read.add_argument("key", metavar="KEY", type=str, + help="key to be read from core device config") + + p_write = subparsers.add_parser("write", + help="write key-value records to core " + "device config") + p_write.add_argument("-s", "--string", nargs=2, action="append", + default=[], metavar=("KEY", "STRING"), type=str, + help="key-value records to be written to core device " + "config") + p_write.add_argument("-f", "--file", nargs=2, action="append", + type=str, default=[], + metavar=("KEY", "FILENAME"), + help="key and file whose content to be written to " + "core device config") + + p_delete = subparsers.add_parser("delete", + help="delete key from core device config") + p_delete.add_argument("key", metavar="KEY", nargs=argparse.REMAINDER, + default=[], type=str, + help="key to be deleted from core device config") + + subparsers.add_parser("erase", help="fully erase core device config") + + # booting + t_boot = tools.add_parser("reboot", + help="reboot the currently running firmware") + + t_hotswap = tools.add_parser("hotswap", + help="load the specified firmware in RAM") + + t_hotswap.add_argument("image", metavar="IMAGE", type=argparse.FileType("rb"), + help="runtime image to be executed") + + # profiling + t_profile = tools.add_parser("profile", + help="account for communications CPU time") + + subparsers = t_profile.add_subparsers(dest="action") + subparsers.required = True + + p_start = subparsers.add_parser("start", + help="start profiling") + p_start.add_argument("--interval", metavar="MICROS", type=int, default=2000, + help="sampling interval, in microseconds") + p_start.add_argument("--hits-size", metavar="ENTRIES", type=int, default=8192, + help="hit buffer size") + p_start.add_argument("--edges-size", metavar="ENTRIES", type=int, default=0, + help="edge buffer size (edge profiling not implemented)") + + p_stop = subparsers.add_parser("stop", + help="stop profiling") + + p_save = subparsers.add_parser("save", + help="save profile") + p_save.add_argument("output", metavar="OUTPUT", type=argparse.FileType("w"), + help="file to save profile to, in Callgrind format") + p_save.add_argument("firmware", metavar="FIRMWARE", type=str, + help="path to firmware ELF file") + p_save.add_argument("--no-compression", + dest="compression", default=True, action="store_false", + help="disable profile compression") + + # misc debug + t_debug = tools.add_parser("debug", + help="specialized debug functions") + + subparsers = t_debug.add_subparsers(dest="action") + subparsers.required = True + + p_allocator = subparsers.add_parser("allocator", + help="show heap layout") + + return parser + + +def main(): + args = get_argparser().parse_args() + init_logger(args) + + device_mgr = DeviceManager(DeviceDB(args.device_db)) + try: + core_addr = DeviceDB(args.device_db).get("core")["arguments"]["host"] + kern = CommKernel(core_addr) + mgmt = CommMgmt(core_addr) + + kern.check_system_info() + + if args.tool == "log": + if args.action == "set_level": + mgmt.set_log_level(args.level) + if args.action == "set_uart_level": + mgmt.set_uart_log_level(args.level) + if args.action == "clear": + mgmt.clear_log() + if args.action == None: + print(mgmt.get_log(), end="") + + if args.tool == "config": + if args.action == "read": + value = kern.flash_storage_read(args.key) + if not value: + print("Key {} does not exist".format(args.key)) + else: + print(value) + if args.action == "write": + for key, value in args.string: + kern.flash_storage_write(key, value.encode("utf-8")) + for key, filename in args.file: + with open(filename, "rb") as fi: + kern.flash_storage_write(key, fi.read()) + if args.action == "delete": + for key in args.key: + kern.flash_storage_remove(key) + if args.action == "erase": + kern.flash_storage_erase() + + if args.tool == "reboot": + mgmt.reboot() + + if args.tool == "hotswap": + mgmt.hotswap(args.image.read()) + + if args.tool == "profile": + if args.action == "start": + mgmt.start_profiler(args.interval, args.hits_size, args.edges_size) + elif args.action == "stop": + mgmt.stop_profiler() + elif args.action == "save": + hits, edges = mgmt.get_profile() + writer = CallgrindWriter(args.output, args.firmware, + "or1k-linux", args.compression) + writer.header() + for addr, count in hits.items(): + writer.hit(addr, count) + for (caller, callee), count in edges.items(): + writer.edge(caller, callee, count) + + if args.tool == "debug": + if args.action == "allocator": + mgmt.debug_allocator() + + finally: + device_mgr.close_devices() + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index 8806a4f65..a85f23ae5 100755 --- a/setup.py +++ b/setup.py @@ -22,11 +22,7 @@ console_scripts = [ "artiq_client = artiq.frontend.artiq_client:main", "artiq_compile = artiq.frontend.artiq_compile:main", "artiq_coreanalyzer = artiq.frontend.artiq_coreanalyzer:main", - "artiq_coreconfig = artiq.frontend.artiq_coreconfig:main", - "artiq_corelog = artiq.frontend.artiq_corelog:main", - "artiq_coreboot = artiq.frontend.artiq_coreboot:main", - "artiq_coredebug = artiq.frontend.artiq_coredebug:main", - "artiq_coreprofile = artiq.frontend.artiq_coreprofile:main", + "artiq_coremgmt = artiq.frontend.artiq_coremgmt:main", "artiq_ctlmgr = artiq.frontend.artiq_ctlmgr:main", "artiq_devtool = artiq.frontend.artiq_devtool:main", "artiq_pcap = artiq.frontend.artiq_pcap:main", From a39f8d663487871d1620a23d4db1d07614042278 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 16 May 2018 14:07:44 +0000 Subject: [PATCH 0788/2457] artiq_devtool: use CommMgmt instead of shelling out to artiq_coremgmt. (Which no longer exists.) This also fixes `artiq_devtool hotswap` to work without an `artiq_devtool connect` running in background. --- artiq/coredevice/comm.py | 37 +++++++++++++++++++++++++++++++++ artiq/coredevice/comm_kernel.py | 31 +++------------------------ artiq/coredevice/comm_mgmt.py | 13 ++++-------- artiq/frontend/artiq_devtool.py | 10 +++++++-- 4 files changed, 52 insertions(+), 39 deletions(-) create mode 100644 artiq/coredevice/comm.py diff --git a/artiq/coredevice/comm.py b/artiq/coredevice/comm.py new file mode 100644 index 000000000..19a104e54 --- /dev/null +++ b/artiq/coredevice/comm.py @@ -0,0 +1,37 @@ +import sys +import socket +import logging + + +logger = logging.getLogger(__name__) + + +def set_keepalive(sock, after_idle, interval, max_fails): + if sys.platform.startswith("linux"): + sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, after_idle) + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, interval) + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, max_fails) + elif sys.platform.startswith("win") or sys.platform.startswith("cygwin"): + # setting max_fails is not supported, typically ends up being 5 or 10 + # depending on Windows version + sock.ioctl(socket.SIO_KEEPALIVE_VALS, + (1, after_idle*1000, interval*1000)) + else: + logger.warning("TCP keepalive not supported on platform '%s', ignored", + sys.platform) + + +def initialize_connection(host, port, ssh_transport=None): + if ssh_transport is None: + sock = socket.create_connection((host, port), 5.0) + sock.settimeout(None) + set_keepalive(sock, 3, 2, 3) + logger.debug("connected to %s:%d", host, port) + else: + sock = ssh_transport.open_channel("direct-tcpip", (host, port), + ("localhost", 9999), timeout=5.0) + ssh_transport.set_keepalive(2) + logger.debug("connected to %s:%d via SSH transport to %s:%d", + host, port, *ssh_transport.getpeername()) + return sock diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 2a2a7f560..c02f226e7 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -1,7 +1,5 @@ import struct import logging -import socket -import sys import traceback import numpy from enum import Enum @@ -9,6 +7,7 @@ from fractions import Fraction from collections import namedtuple from artiq.coredevice import exceptions +from artiq.coredevice.comm import initialize_connection from artiq import __version__ as software_version @@ -85,30 +84,6 @@ class RPCReturnValueError(ValueError): RPCKeyword = namedtuple('RPCKeyword', ['name', 'value']) -def set_keepalive(sock, after_idle, interval, max_fails): - if sys.platform.startswith("linux"): - sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, after_idle) - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, interval) - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, max_fails) - elif sys.platform.startswith("win") or sys.platform.startswith("cygwin"): - # setting max_fails is not supported, typically ends up being 5 or 10 - # depending on Windows version - sock.ioctl(socket.SIO_KEEPALIVE_VALS, - (1, after_idle*1000, interval*1000)) - else: - logger.warning("TCP keepalive not supported on platform '%s', ignored", - sys.platform) - - -def initialize_connection(host, port): - sock = socket.create_connection((host, port), 5.0) - sock.settimeout(None) - set_keepalive(sock, 3, 2, 3) - logger.debug("connected to host %s on port %d", host, port) - return sock - - class CommKernelDummy: def __init__(self): pass @@ -143,10 +118,10 @@ class CommKernel: self.host = host self.port = port - def open(self): + def open(self, **kwargs): if hasattr(self, "socket"): return - self.socket = initialize_connection(self.host, self.port) + self.socket = initialize_connection(self.host, self.port, **kwargs) self.socket.sendall(b"ARTIQ coredev\n") def close(self): diff --git a/artiq/coredevice/comm_mgmt.py b/artiq/coredevice/comm_mgmt.py index 98ad07e2b..f235c584a 100644 --- a/artiq/coredevice/comm_mgmt.py +++ b/artiq/coredevice/comm_mgmt.py @@ -3,6 +3,8 @@ import logging import socket import struct +from artiq.coredevice.comm import initialize_connection + logger = logging.getLogger(__name__) @@ -44,22 +46,15 @@ class LogLevel(Enum): TRACE = 5 -def initialize_connection(host, port): - sock = socket.create_connection((host, port), 5.0) - sock.settimeout(None) - logger.debug("connected to host %s on port %d", host, port) - return sock - - class CommMgmt: def __init__(self, host, port=1380): self.host = host self.port = port - def open(self): + def open(self, **kwargs): if hasattr(self, "socket"): return - self.socket = initialize_connection(self.host, self.port) + self.socket = initialize_connection(self.host, self.port, **kwargs) self.socket.sendall(b"ARTIQ management\n") def close(self): diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 3ab31e776..58edba27d 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -18,6 +18,7 @@ import shlex from artiq.tools import verbosity_args, init_logger from artiq.remoting import SSHClient +from artiq.coredevice.comm_mgmt import CommMgmt logger = logging.getLogger(__name__) @@ -264,10 +265,15 @@ def main(): client.run_command(["flterm", serial, "--output-only"]) elif action == "hotswap": + lock() + logger.info("Hotswapping firmware") firmware = build_dir(variant, "software", firmware, firmware + ".bin") - command("artiq_coreboot", "hotswap", firmware, - on_failure="Hotswapping failed") + + mgmt = CommMgmt(device) + mgmt.open(ssh_transport=client.get_transport()) + with open(firmware, "rb") as f: + mgmt.hotswap(f.read()) else: logger.error("Unknown action {}".format(action)) From ca93b94aeaa1c38504235c35ed103896884c0df1 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 16 May 2018 14:32:49 +0000 Subject: [PATCH 0789/2457] firmware: move config requests to management protocol. They were only in session protocol because of historical reasons. --- artiq/coredevice/comm_kernel.py | 39 -------- artiq/coredevice/comm_mgmt.py | 37 ++++++++ artiq/firmware/libproto_artiq/mgmt_proto.rs | 48 +++++++++- .../firmware/libproto_artiq/session_proto.rs | 94 +++++++------------ artiq/firmware/runtime/mgmt.rs | 37 ++++++-- artiq/firmware/runtime/session.rs | 30 ------ artiq/frontend/artiq_coremgmt.py | 23 ++--- 7 files changed, 157 insertions(+), 151 deletions(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index c02f226e7..d8df2d878 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -28,11 +28,6 @@ class _H2DMsgType(Enum): RPC_REPLY = 7 RPC_EXCEPTION = 8 - FLASH_READ_REQUEST = 9 - FLASH_WRITE_REQUEST = 10 - FLASH_ERASE_REQUEST = 11 - FLASH_REMOVE_REQUEST = 12 - HOTSWAP = 14 @@ -52,10 +47,6 @@ class _D2HMsgType(Enum): RPC_REQUEST = 10 - FLASH_READ_REPLY = 11 - FLASH_OK_REPLY = 12 - FLASH_ERROR_REPLY = 13 - WATCHDOG_EXPIRED = 14 CLOCK_FAILURE = 15 @@ -277,36 +268,6 @@ class CommKernel: self._read_empty(_D2HMsgType.CLOCK_SWITCH_COMPLETED) - def flash_storage_read(self, key): - self._write_header(_H2DMsgType.FLASH_READ_REQUEST) - self._write_string(key) - - self._read_header() - self._read_expect(_D2HMsgType.FLASH_READ_REPLY) - return self._read_string() - - def flash_storage_write(self, key, value): - self._write_header(_H2DMsgType.FLASH_WRITE_REQUEST) - self._write_string(key) - self._write_bytes(value) - - self._read_header() - if self._read_type == _D2HMsgType.FLASH_ERROR_REPLY: - raise IOError("Flash storage is full") - else: - self._read_expect(_D2HMsgType.FLASH_OK_REPLY) - - def flash_storage_erase(self): - self._write_empty(_H2DMsgType.FLASH_ERASE_REQUEST) - - self._read_empty(_D2HMsgType.FLASH_OK_REPLY) - - def flash_storage_remove(self, key): - self._write_header(_H2DMsgType.FLASH_REMOVE_REQUEST) - self._write_string(key) - - self._read_empty(_D2HMsgType.FLASH_OK_REPLY) - def load(self, kernel_library): self._write_header(_H2DMsgType.LOAD_KERNEL) self._write_bytes(kernel_library) diff --git a/artiq/coredevice/comm_mgmt.py b/artiq/coredevice/comm_mgmt.py index f235c584a..6d8438495 100644 --- a/artiq/coredevice/comm_mgmt.py +++ b/artiq/coredevice/comm_mgmt.py @@ -16,6 +16,11 @@ class Request(Enum): SetLogFilter = 3 SetUartLogFilter = 6 + ConfigRead = 12 + ConfigWrite = 13 + ConfigRemove = 14 + ConfigErase = 15 + StartProfiler = 9 StopProfiler = 10 GetProfile = 11 @@ -28,10 +33,13 @@ class Request(Enum): class Reply(Enum): Success = 1 + Error = 6 Unavailable = 4 LogContent = 2 + ConfigData = 7 + Profile = 5 RebootImminent = 3 @@ -85,6 +93,9 @@ class CommMgmt: self._write_int32(len(value)) self._write(value) + def _write_string(self, value): + self._write_bytes(value.encode("utf-8")) + def _read(self, length): r = bytes() while len(r) < length: @@ -147,6 +158,32 @@ class CommMgmt: self._write_int8(getattr(LogLevel, level).value) self._read_expect(Reply.Success) + def config_read(self, key): + self._write_header(Request.ConfigRead) + self._write_string(key) + self._read_expect(Reply.ConfigData) + return self._read_string() + + def config_write(self, key, value): + self._write_header(Request.ConfigWrite) + self._write_string(key) + self._write_bytes(value) + ty = self._read_header() + if ty == Reply.Error: + raise IOError("Flash storage is full") + elif ty != Reply.Success: + raise IOError("Incorrect reply from device: {} (expected {})". + format(ty, Reply.Success)) + + def config_remove(self, key): + self._write_header(Request.ConfigRemove) + self._write_string(key) + self._read_expect(Reply.Success) + + def config_erase(self): + self._write_empty(Request.ConfigErase) + self._read_expect(Reply.Success) + def start_profiler(self, interval, edges_size, hits_size): self._write_header(Request.StartProfiler) self._write_int32(interval) diff --git a/artiq/firmware/libproto_artiq/mgmt_proto.rs b/artiq/firmware/libproto_artiq/mgmt_proto.rs index 9c44397e8..ffa2a9763 100644 --- a/artiq/firmware/libproto_artiq/mgmt_proto.rs +++ b/artiq/firmware/libproto_artiq/mgmt_proto.rs @@ -1,8 +1,9 @@ -use alloc::Vec; +use core::str::Utf8Error; +use alloc::{Vec, String}; #[cfg(feature = "log")] use log; -use io::{Read, ProtoRead, Write, ProtoWrite, Error as IoError}; +use io::{Read, ProtoRead, Write, ProtoWrite, Error as IoError, ReadStringError}; #[derive(Fail, Debug)] pub enum Error { @@ -12,6 +13,8 @@ pub enum Error { UnknownPacket(u8), #[fail(display = "unknown log level {}", _0)] UnknownLogLevel(u8), + #[fail(display = "invalid UTF-8: {}", _0)] + Utf8(Utf8Error), #[fail(display = "{}", _0)] Io(#[cause] IoError) } @@ -22,6 +25,15 @@ impl From> for Error { } } +impl From>> for Error { + fn from(value: ReadStringError>) -> Error { + match value { + ReadStringError::Utf8(err) => Error::Utf8(err), + ReadStringError::Other(err) => Error::Io(err) + } + } +} + pub fn read_magic(reader: &mut R) -> Result<(), Error> where R: Read + ?Sized { @@ -46,6 +58,11 @@ pub enum Request { #[cfg(feature = "log")] SetUartLogFilter(log::LevelFilter), + ConfigRead { key: String }, + ConfigWrite { key: String, value: Vec }, + ConfigRemove { key: String }, + ConfigErase, + StartProfiler { interval_us: u32, hits_size: u32, @@ -62,10 +79,13 @@ pub enum Request { pub enum Reply<'a> { Success, + Error, Unavailable, LogContent(&'a str), + ConfigData(&'a [u8]), + Profile, RebootImminent, @@ -97,6 +117,19 @@ impl Request { 3 => Request::SetLogFilter(read_log_level_filter(reader)?), #[cfg(feature = "log")] 6 => Request::SetUartLogFilter(read_log_level_filter(reader)?), + + 12 => Request::ConfigRead { + key: reader.read_string()? + }, + 13 => Request::ConfigWrite { + key: reader.read_string()?, + value: reader.read_bytes()? + }, + 14 => Request::ConfigRemove { + key: reader.read_string()? + }, + 15 => Request::ConfigErase, + 9 => Request::StartProfiler { interval_us: reader.read_u32()?, hits_size: reader.read_u32()?, @@ -104,9 +137,12 @@ impl Request { }, 10 => Request::StopProfiler, 11 => Request::GetProfile, + 4 => Request::Hotswap(reader.read_bytes()?), 5 => Request::Reboot, + 8 => Request::DebugAllocator, + ty => return Err(Error::UnknownPacket(ty)) }) } @@ -120,6 +156,9 @@ impl<'a> Reply<'a> { Reply::Success => { writer.write_u8(1)?; } + Reply::Error => { + writer.write_u8(6)?; + } Reply::Unavailable => { writer.write_u8(4)?; @@ -130,6 +169,11 @@ impl<'a> Reply<'a> { writer.write_string(log)?; } + Reply::ConfigData(ref bytes) => { + writer.write_u8(7)?; + writer.write_bytes(bytes)?; + }, + Reply::Profile => { writer.write_u8(5)?; // profile data follows diff --git a/artiq/firmware/libproto_artiq/session_proto.rs b/artiq/firmware/libproto_artiq/session_proto.rs index 7540ba513..54da5c5d3 100644 --- a/artiq/firmware/libproto_artiq/session_proto.rs +++ b/artiq/firmware/libproto_artiq/session_proto.rs @@ -79,51 +79,6 @@ pub enum Request { column: u32, function: String, }, - - FlashRead { key: String }, - FlashWrite { key: String, value: Vec }, - FlashRemove { key: String }, - FlashErase, -} - -impl Request { - pub fn read_from(reader: &mut R) -> Result> - where R: Read + ?Sized - { - read_sync(reader)?; - Ok(match reader.read_u8()? { - 3 => Request::SystemInfo, - 4 => Request::SwitchClock(reader.read_u8()?), - 5 => Request::LoadKernel(reader.read_bytes()?), - 6 => Request::RunKernel, - 7 => Request::RpcReply { - tag: reader.read_bytes()? - }, - 8 => Request::RpcException { - name: reader.read_string()?, - message: reader.read_string()?, - param: [reader.read_u64()? as i64, - reader.read_u64()? as i64, - reader.read_u64()? as i64], - file: reader.read_string()?, - line: reader.read_u32()?, - column: reader.read_u32()?, - function: reader.read_string()? - }, - 9 => Request::FlashRead { - key: reader.read_string()? - }, - 10 => Request::FlashWrite { - key: reader.read_string()?, - value: reader.read_bytes()? - }, - 11 => Request::FlashErase, - 12 => Request::FlashRemove { - key: reader.read_string()? - }, - ty => return Err(Error::UnknownPacket(ty)) - }) - } } #[derive(Debug)] @@ -153,14 +108,44 @@ pub enum Reply<'a> { RpcRequest { async: bool }, - FlashRead(&'a [u8]), - FlashOk, - FlashError, - WatchdogExpired, ClockFailure, } +impl Request { + pub fn read_from(reader: &mut R) -> Result> + where R: Read + ?Sized + { + read_sync(reader)?; + Ok(match reader.read_u8()? { + 3 => Request::SystemInfo, + 4 => Request::SwitchClock(reader.read_u8()?), + + 5 => Request::LoadKernel(reader.read_bytes()?), + 6 => Request::RunKernel, + + 7 => Request::RpcReply { + tag: reader.read_bytes()? + }, + 8 => Request::RpcException { + name: reader.read_string()?, + message: reader.read_string()?, + param: [reader.read_u64()? as i64, + reader.read_u64()? as i64, + reader.read_u64()? as i64], + file: reader.read_string()?, + line: reader.read_u32()?, + column: reader.read_u32()?, + function: reader.read_string()? + }, + + // 9-12 were flash requests + + ty => return Err(Error::UnknownPacket(ty)) + }) + } +} + impl<'a> Reply<'a> { pub fn write_to(&self, writer: &mut W) -> Result<(), IoError> where W: Write + ?Sized @@ -218,16 +203,7 @@ impl<'a> Reply<'a> { writer.write_u8(async as u8)?; }, - Reply::FlashRead(ref bytes) => { - writer.write_u8(11)?; - writer.write_bytes(bytes)?; - }, - Reply::FlashOk => { - writer.write_u8(12)?; - }, - Reply::FlashError => { - writer.write_u8(13)?; - }, + // 11-13 were flash requests Reply::WatchdogExpired => { writer.write_u8(14)?; diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 222108885..c03682e8a 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -1,7 +1,7 @@ use log::{self, LevelFilter}; use io::{Write, ProtoWrite, Error as IoError}; -use board_misoc::boot; +use board_misoc::{config, boot}; use logger_artiq::BufferLogger; use mgmt_proto::*; use sched::{Io, TcpListener, TcpStream, Error as SchedError}; @@ -25,7 +25,6 @@ fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error> { Reply::LogContent(buffer.extract()).write_to(stream) })?; } - Request::ClearLog => { BufferLogger::with(|logger| -> Result<(), Error> { let mut buffer = io.until_ok(|| logger.buffer())?; @@ -34,7 +33,6 @@ fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error> { Reply::Success.write_to(stream)?; } - Request::PullLog => { BufferLogger::with(|logger| -> Result<(), Error> { loop { @@ -64,13 +62,11 @@ fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error> { } })?; } - Request::SetLogFilter(level) => { info!("changing log level to {}", level); log::set_max_level(level); Reply::Success.write_to(stream)?; } - Request::SetUartLogFilter(level) => { info!("changing UART log level to {}", level); BufferLogger::with(|logger| @@ -78,6 +74,34 @@ fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error> { Reply::Success.write_to(stream)?; } + Request::ConfigRead { ref key } => { + config::read(key, |result| { + match result { + Ok(value) => Reply::ConfigData(&value).write_to(stream), + Err(_) => Reply::Error.write_to(stream) + } + })?; + } + Request::ConfigWrite { ref key, ref value } => { + match config::write(key, value) { + Ok(_) => Reply::Success.write_to(stream), + Err(_) => Reply::Error.write_to(stream) + }?; + } + Request::ConfigRemove { ref key } => { + match config::remove(key) { + Ok(()) => Reply::Success.write_to(stream), + Err(_) => Reply::Error.write_to(stream) + }?; + + } + Request::ConfigErase => { + match config::erase() { + Ok(()) => Reply::Success.write_to(stream), + Err(_) => Reply::Error.write_to(stream) + }?; + } + Request::StartProfiler { interval_us, hits_size, edges_size } => { match profiler::start(interval_us as u64, hits_size as usize, edges_size as usize) { @@ -85,12 +109,10 @@ fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error> { Err(()) => Reply::Unavailable.write_to(stream)? } } - Request::StopProfiler => { profiler::stop(); Reply::Success.write_to(stream)?; } - Request::GetProfile => { profiler::pause(|profile| { let profile = match profile { @@ -130,7 +152,6 @@ fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error> { warn!("hotswapping firmware"); unsafe { boot::hotswap(&firmware) } } - Request::Reboot => { Reply::RebootImminent.write_to(stream)?; stream.close()?; diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index cbef8d7d8..ca98fdbb6 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -250,36 +250,6 @@ fn process_host_message(io: &Io, session.congress.finished_cleanly.set(true) } - // artiq_coreconfig - host::Request::FlashRead { ref key } => { - config::read(key, |result| { - match result { - Ok(value) => host_write(stream, host::Reply::FlashRead(&value)), - Err(_) => host_write(stream, host::Reply::FlashError) - } - })?; - } - host::Request::FlashWrite { ref key, ref value } => { - match config::write(key, value) { - Ok(_) => host_write(stream, host::Reply::FlashOk), - Err(_) => host_write(stream, host::Reply::FlashError) - }?; - } - host::Request::FlashRemove { ref key } => { - match config::remove(key) { - Ok(()) => host_write(stream, host::Reply::FlashOk), - Err(_) => host_write(stream, host::Reply::FlashError), - }?; - - } - host::Request::FlashErase => { - match config::erase() { - Ok(()) => host_write(stream, host::Reply::FlashOk), - Err(_) => host_write(stream, host::Reply::FlashError), - }?; - } - - // artiq_run/artiq_master host::Request::SwitchClock(clk) => { if session.running() { unexpected!("attempted to switch RTIO clock while a kernel was running") diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index 6013b7359..d611b711c 100644 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -67,11 +67,11 @@ def get_argparser(): help="key and file whose content to be written to " "core device config") - p_delete = subparsers.add_parser("delete", - help="delete key from core device config") - p_delete.add_argument("key", metavar="KEY", nargs=argparse.REMAINDER, + p_remove = subparsers.add_parser("remove", + help="remove key from core device config") + p_remove.add_argument("key", metavar="KEY", nargs=argparse.REMAINDER, default=[], type=str, - help="key to be deleted from core device config") + help="key to be removed from core device config") subparsers.add_parser("erase", help="fully erase core device config") @@ -134,11 +134,8 @@ def main(): device_mgr = DeviceManager(DeviceDB(args.device_db)) try: core_addr = DeviceDB(args.device_db).get("core")["arguments"]["host"] - kern = CommKernel(core_addr) mgmt = CommMgmt(core_addr) - kern.check_system_info() - if args.tool == "log": if args.action == "set_level": mgmt.set_log_level(args.level) @@ -151,22 +148,22 @@ def main(): if args.tool == "config": if args.action == "read": - value = kern.flash_storage_read(args.key) + value = mgmt.config_read(args.key) if not value: print("Key {} does not exist".format(args.key)) else: print(value) if args.action == "write": for key, value in args.string: - kern.flash_storage_write(key, value.encode("utf-8")) + mgmt.config_write(key, value.encode("utf-8")) for key, filename in args.file: with open(filename, "rb") as fi: - kern.flash_storage_write(key, fi.read()) - if args.action == "delete": + mgmt.config_write(key, fi.read()) + if args.action == "remove": for key in args.key: - kern.flash_storage_remove(key) + mgmt.config_remove(key) if args.action == "erase": - kern.flash_storage_erase() + mgmt.config_erase() if args.tool == "reboot": mgmt.reboot() From 4d06c1d84bcd1cd101cf0f35a54a8600e5779220 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 16 May 2018 14:40:14 +0000 Subject: [PATCH 0790/2457] coredevice.CommKernel: modernize. NFC. --- artiq/coredevice/comm_kernel.py | 95 +++++++------------ .../firmware/libproto_artiq/session_proto.rs | 8 ++ 2 files changed, 43 insertions(+), 60 deletions(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index d8df2d878..e79f72f3d 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -14,52 +14,33 @@ from artiq import __version__ as software_version logger = logging.getLogger(__name__) -class _H2DMsgType(Enum): - LOG_REQUEST = 1 - LOG_CLEAR = 2 - LOG_FILTER = 13 +class Request(Enum): + SystemInfo = 3 + SwitchClock = 4 - SYSTEM_INFO_REQUEST = 3 - SWITCH_CLOCK = 4 + LoadKernel = 5 + RunKernel = 6 - LOAD_KERNEL = 5 - RUN_KERNEL = 6 - - RPC_REPLY = 7 - RPC_EXCEPTION = 8 - - HOTSWAP = 14 + RPCReply = 7 + RPCException = 8 -class _D2HMsgType(Enum): - LOG_REPLY = 1 +class Reply(Enum): + SystemInfo = 2 + ClockSwitchCompleted = 3 + ClockSwitchFailed = 4 - SYSTEM_INFO_REPLY = 2 - CLOCK_SWITCH_COMPLETED = 3 - CLOCK_SWITCH_FAILED = 4 + LoadCompleted = 5 + LoadFailed = 6 - LOAD_COMPLETED = 5 - LOAD_FAILED = 6 + KernelFinished = 7 + KernelStartupFailed = 8 + KernelException = 9 - KERNEL_FINISHED = 7 - KERNEL_STARTUP_FAILED = 8 - KERNEL_EXCEPTION = 9 + RPCRequest = 10 - RPC_REQUEST = 10 - - WATCHDOG_EXPIRED = 14 - CLOCK_FAILURE = 15 - - HOTSWAP_IMMINENT = 16 - - -class _LogLevel(Enum): - OFF = 0 - ERROR = 1 - WARN = 2 - INFO = 3 - DEBUG = 4 - TRACE = 5 + WatchdogExpired = 14 + ClockFailure = 15 class UnsupportedDevice(Exception): @@ -94,12 +75,6 @@ class CommKernelDummy: def check_system_info(self): pass - def get_log(self): - return "" - - def clear_log(self): - pass - class CommKernel: warned_of_mismatch = False @@ -152,7 +127,7 @@ class CommKernel: # Read message header. (raw_type, ) = struct.unpack("B", self.read(1)) - self._read_type = _D2HMsgType(raw_type) + self._read_type = Reply(raw_type) logger.debug("receiving message: type=%r", self._read_type) @@ -242,10 +217,10 @@ class CommKernel: self.write(struct.pack(">ll", 0x5a5a5a5a, 0)) def check_system_info(self): - self._write_empty(_H2DMsgType.SYSTEM_INFO_REQUEST) + self._write_empty(Request.SystemInfo) self._read_header() - self._read_expect(_D2HMsgType.SYSTEM_INFO_REPLY) + self._read_expect(Reply.SystemInfo) runtime_id = self._read_chunk(4) if runtime_id != b"AROR": raise UnsupportedDevice("Unsupported runtime ID: {}" @@ -263,23 +238,23 @@ class CommKernel: logger.warning("Previous kernel did not cleanly finish") def switch_clock(self, external): - self._write_header(_H2DMsgType.SWITCH_CLOCK) + self._write_header(Request.SwitchClock) self._write_int8(external) - self._read_empty(_D2HMsgType.CLOCK_SWITCH_COMPLETED) + self._read_empty(Reply.ClockSwitchCompleted) def load(self, kernel_library): - self._write_header(_H2DMsgType.LOAD_KERNEL) + self._write_header(Request.LoadKernel) self._write_bytes(kernel_library) self._read_header() - if self._read_type == _D2HMsgType.LOAD_FAILED: + if self._read_type == Reply.LoadFailed: raise LoadError(self._read_string()) else: - self._read_expect(_D2HMsgType.LOAD_COMPLETED) + self._read_expect(Reply.LoadCompleted) def run(self): - self._write_empty(_H2DMsgType.RUN_KERNEL) + self._write_empty(Request.RunKernel) logger.debug("running kernel") _rpc_sentinel = object() @@ -460,7 +435,7 @@ class CommKernel: result = service(*args, **kwargs) logger.debug("rpc service: %d %r %r = %r", service_id, args, kwargs, result) - self._write_header(_H2DMsgType.RPC_REPLY) + self._write_header(Request.RPCReply) self._write_bytes(return_tags) self._send_rpc_value(bytearray(return_tags), result, result, service) except RPCReturnValueError as exn: @@ -468,7 +443,7 @@ class CommKernel: except Exception as exn: logger.debug("rpc service: %d %r %r ! %r", service_id, args, kwargs, exn) - self._write_header(_H2DMsgType.RPC_EXCEPTION) + self._write_header(Request.RPCException) if hasattr(exn, "artiq_core_exception"): exn = exn.artiq_core_exception @@ -536,14 +511,14 @@ class CommKernel: def serve(self, embedding_map, symbolizer, demangler): while True: self._read_header() - if self._read_type == _D2HMsgType.RPC_REQUEST: + if self._read_type == Reply.RPCRequest: self._serve_rpc(embedding_map) - elif self._read_type == _D2HMsgType.KERNEL_EXCEPTION: + elif self._read_type == Reply.KernelException: self._serve_exception(embedding_map, symbolizer, demangler) - elif self._read_type == _D2HMsgType.WATCHDOG_EXPIRED: + elif self._read_type == Reply.WatchdogExpired: raise exceptions.WatchdogExpired - elif self._read_type == _D2HMsgType.CLOCK_FAILURE: + elif self._read_type == Reply.ClockFailure: raise exceptions.ClockFailure else: - self._read_expect(_D2HMsgType.KERNEL_FINISHED) + self._read_expect(Reply.KernelFinished) return diff --git a/artiq/firmware/libproto_artiq/session_proto.rs b/artiq/firmware/libproto_artiq/session_proto.rs index 54da5c5d3..c2867c7d4 100644 --- a/artiq/firmware/libproto_artiq/session_proto.rs +++ b/artiq/firmware/libproto_artiq/session_proto.rs @@ -118,6 +118,8 @@ impl Request { { read_sync(reader)?; Ok(match reader.read_u8()? { + // 1-2, 13 were log requests + 3 => Request::SystemInfo, 4 => Request::SwitchClock(reader.read_u8()?), @@ -141,6 +143,8 @@ impl Request { // 9-12 were flash requests + // 14 was hotswap request + ty => return Err(Error::UnknownPacket(ty)) }) } @@ -152,6 +156,8 @@ impl<'a> Reply<'a> { { write_sync(writer)?; match *self { + // 1 was log reply + Reply::SystemInfo { ident, finished_cleanly } => { writer.write_u8(2)?; writer.write(b"AROR")?; @@ -211,6 +217,8 @@ impl<'a> Reply<'a> { Reply::ClockFailure => { writer.write_u8(15)?; }, + + // 16 was hotswap imminent reply } Ok(()) } From 0aadd3a3612409935b74fbf0ad4f84496a8d7ef6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 16 May 2018 22:28:09 +0800 Subject: [PATCH 0791/2457] firmware/hmc830_7043: improve messaging --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 0e6e78703..35c1ac015 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -107,10 +107,11 @@ mod hmc830 { pub fn init() -> Result<(), &'static str> { spi_setup(); - info!("HMC830 configuration..."); + info!("loading configuration..."); for &(addr, data) in HMC830_WRITES.iter() { write(addr, data); } + info("...done"); let t = clock::get_ms(); info!("waiting for lock..."); @@ -125,6 +126,7 @@ mod hmc830 { return Err("HMC830 lock timeout"); } } + info!("...locked"); Ok(()) } @@ -217,7 +219,7 @@ pub mod hmc7043 { pub fn shutdown() -> Result<(), &'static str> { spi_setup(); - info!("HMC7043 shutdown..."); + info!("shutting down"); write(0x1, 0x1); // Sleep mode Ok(()) @@ -225,7 +227,7 @@ pub mod hmc7043 { pub fn init() -> Result<(), &'static str> { spi_setup(); - info!("HMC7043 configuration..."); + info!("loading configuration..."); write(0x0, 0x1); // Software reset write(0x0, 0x0); @@ -267,6 +269,8 @@ pub mod hmc7043 { write(channel_base + 0x8, 0x08) } + info!("...done"); + Ok(()) } From 1364cd2948228991ddaff5f4b9afaf218c80e3f0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 16 May 2018 22:46:14 +0800 Subject: [PATCH 0792/2457] firmware/hmc830_7043: break out HMC830 SPI mode selection --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 35c1ac015..1a12f39b7 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -52,8 +52,6 @@ mod hmc830 { fn spi_setup() { unsafe { while csr::converter_spi::idle_read() == 0 {} - // rising egde on CS since cs_polarity still 0 - // selects "HMC Mode" csr::converter_spi::offline_write(0); csr::converter_spi::end_write(1); csr::converter_spi::cs_polarity_write(0b0001); @@ -61,14 +59,21 @@ mod hmc830 { csr::converter_spi::clk_phase_write(0); csr::converter_spi::lsb_first_write(0); csr::converter_spi::half_duplex_write(0); + csr::converter_spi::length_write(32 - 1); csr::converter_spi::div_write(16 - 2); csr::converter_spi::cs_write(1 << csr::CONFIG_CONVERTER_SPI_HMC830_CS); + } + } + pub fn select_spi_mode() { + spi_setup(); + unsafe { + // rising egde on CS since cs_polarity still 0 + // selects "HMC Mode" // do a dummy cycle with cs still high to clear CS csr::converter_spi::length_write(0); csr::converter_spi::data_write(0); while csr::converter_spi::writable_read() == 0 {} - csr::converter_spi::length_write(32 - 1); } } @@ -111,7 +116,7 @@ mod hmc830 { for &(addr, data) in HMC830_WRITES.iter() { write(addr, data); } - info("...done"); + info!("...done"); let t = clock::get_ms(); info!("waiting for lock..."); @@ -295,7 +300,8 @@ pub mod hmc7043 { pub fn init() -> Result<(), &'static str> { clock_mux::init(); - /* must be the first SPI init because of HMC830 SPI mode selection */ + /* do not use other SPI devices before HMC830 SPI mode selection */ + hmc830::select_spi_mode(); hmc830::detect()?; hmc7043::detect()?; hmc7043::shutdown()?; From fedf7f0c87e007ce9a13adabeac63e85caa898b8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 16 May 2018 23:01:19 +0800 Subject: [PATCH 0793/2457] firmware/ad9154: cleanup sysref scan and run everytime --- artiq/firmware/libboard_artiq/ad9154.rs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 528b4c6cb..cda114b66 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -608,13 +608,10 @@ fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { dac_cfg(dacno) } -#[allow(dead_code)] fn dac_sysref_scan(dacno: u8) { - let mut sync_error_last = 0u16; - let mut phase_min_found = false; - let mut phase_min = 0u16; - let mut _phase_max_found = false; - let mut phase_max = 0u16; + let mut sync_error_last = 0; + let mut phase_min = None; + let mut phase_max = None; info!("AD9154-{} SYSREF scan/conf...", dacno); for phase in 0..512 { @@ -628,23 +625,19 @@ fn dac_sysref_scan(dacno: u8) { info!(" phase: {}, sync error: {}", phase, sync_error); } if sync_error != 0 { - if phase_min_found { + if phase_min.is_some() { if sync_error != sync_error_last { - _phase_max_found = true; - phase_max = phase - 1; + phase_max = Some(phase - 1); break; } } else { - phase_min_found = true; - phase_min = phase; + phase_min = Some(phase); } } sync_error_last = sync_error; } - let phase_opt = phase_min + (phase_max-phase_min)/2; - info!(" phase min: {}, phase max: {}, phase opt: {}", phase_min, phase_max, phase_opt); - hmc7043::cfg_dac_sysref(dacno, phase_opt); + info!(" phase min: {:?}, phase max: {:?}", phase_min, phase_max); } fn dac_sysref_cfg(dacno: u8, phase: u16) { @@ -660,6 +653,7 @@ pub fn init() -> Result<(), &'static str> { for dacno in 0..csr::AD9154.len() { let dacno = dacno as u8; debug!("setting up AD9154-{} DAC...", dacno); + dac_sysref_scan(dacno); dac_sysref_cfg(dacno, 88); dac_cfg_retry(dacno)?; dac_prbs(dacno)?; From a64004184432e3737fff0b7895a17e5d499a60d9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 16 May 2018 23:15:02 +0800 Subject: [PATCH 0794/2457] firmware: improve ad9154/hmc830/hmc7043 messaging --- artiq/firmware/libboard_artiq/ad9154.rs | 23 ++++++++++---------- artiq/firmware/libboard_artiq/hmc830_7043.rs | 12 +++++----- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index cda114b66..23f2aba77 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -146,12 +146,12 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { 1*ad9154_reg::SDOACTIVE_M | 1*ad9154_reg::SDOACTIVE); clock::spin_us(100); if (read(ad9154_reg::PRODIDH) as u16) << 8 | (read(ad9154_reg::PRODIDL) as u16) != 0x9154 { - return Err("AD9154 not found"); + return Err("invalid AD9154 identification"); } else { info!("AD9154-{} found", dacno); } - info!("AD9154-{} configuration...", dacno); + info!("AD9154-{} initializing...", dacno); write(ad9154_reg::PWRCNTRL0, 0*ad9154_reg::PD_DAC0 | 0*ad9154_reg::PD_DAC1 | 0*ad9154_reg::PD_DAC2 | 0*ad9154_reg::PD_DAC3 | @@ -348,7 +348,7 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { let t = clock::get_ms(); while read(ad9154_reg::PLL_STATUS) & ad9154_reg::SERDES_PLL_LOCK_RB == 0 { if clock::get_ms() > t + 200 { - return Err("AD9154 SERDES PLL lock timeout"); + return Err("SERDES PLL lock timeout"); } } @@ -375,13 +375,13 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { 0*ad9154_reg::SYNCCLRLAST); clock::spin_us(1000); // ensure at least one sysref edge if read(ad9154_reg::SYNC_CONTROL) & ad9154_reg::SYNCARM != 0 { - return Err("AD9154 no sysref edge"); + return Err("no sysref edge"); } if read(ad9154_reg::SYNC_STATUS) & ad9154_reg::SYNC_LOCK == 0 { - return Err("AD9154 no sync lock"); + return Err("no sync lock"); } if read(ad9154_reg::SYNC_STATUS) & ad9154_reg::SYNC_WLIM != 0 { - return Err("AD9154 sysref phase error"); + return Err("sysref phase error"); } write(ad9154_reg::XBAR_LN_0_1, 0*ad9154_reg::LOGICAL_LANE0_SRC | 1*ad9154_reg::LOGICAL_LANE1_SRC); @@ -395,6 +395,7 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { write(ad9154_reg::GENERAL_JRX_CTRL_0, 0x1*ad9154_reg::LINK_EN | 0*ad9154_reg::LINK_PAGE | 0*ad9154_reg::LINK_MODE | 0*ad9154_reg::CHECKSUM_MODE); + info!(" ...done"); Ok(()) } @@ -498,7 +499,7 @@ fn dac_prbs(dacno: u8) -> Result<(), &'static str> { let mut prbs_errors: u32 = 0; /* follow phy prbs testing (p58 of ad9154 datasheet) */ - info!("AD9154-{} PRBS test", dacno); + info!("AD9154-{} running PRBS test...", dacno); /* step 1: start sending prbs7 pattern from the transmitter */ jesd_prbs(dacno, true); @@ -546,7 +547,7 @@ fn dac_prbs(dacno: u8) -> Result<(), &'static str> { ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_MIDBITS) as u32) << 8) | ((read(ad9154_reg::PHY_PRBS_TEST_ERRCNT_HIBITS) as u32) << 16); if lane_errors > 0 { - warn!("AD9154-{} PRBS errors on lane{}: {:06x}", dacno, i, lane_errors); + warn!(" PRBS errors on lane{}: {:06x}", i, lane_errors); } prbs_errors += lane_errors } @@ -554,8 +555,9 @@ fn dac_prbs(dacno: u8) -> Result<(), &'static str> { jesd_prbs(dacno, false); if prbs_errors > 0 { - return Err("AD9154 PRBS failed") + return Err("PRBS failed") } + info!(" ...passed"); Ok(()) } @@ -613,7 +615,7 @@ fn dac_sysref_scan(dacno: u8) { let mut phase_min = None; let mut phase_max = None; - info!("AD9154-{} SYSREF scan/conf...", dacno); + info!("AD9154-{} SYSREF scan:", dacno); for phase in 0..512 { hmc7043::cfg_dac_sysref(dacno, phase); clock::spin_us(10000); @@ -652,7 +654,6 @@ pub fn init() -> Result<(), &'static str> { for dacno in 0..csr::AD9154.len() { let dacno = dacno as u8; - debug!("setting up AD9154-{} DAC...", dacno); dac_sysref_scan(dacno); dac_sysref_cfg(dacno, 88); dac_cfg_retry(dacno)?; diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 1a12f39b7..7ef32a317 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -116,22 +116,22 @@ mod hmc830 { for &(addr, data) in HMC830_WRITES.iter() { write(addr, data); } - info!("...done"); + info!(" ...done"); let t = clock::get_ms(); info!("waiting for lock..."); while read(0x12) & 0x02 == 0 { if clock::get_ms() > t + 2000 { - error!("HMC830 lock timeout. Register dump:"); + error!(" lock timeout. Register dump:"); for addr in 0x00..0x14 { // These registers don't exist (in the data sheet at least) if addr == 0x0d || addr == 0x0e { continue; } - error!("[0x{:02x}] = 0x{:04x}", addr, read(addr)); + error!(" [0x{:02x}] = 0x{:04x}", addr, read(addr)); } - return Err("HMC830 lock timeout"); + return Err("lock timeout"); } } - info!("...locked"); + info!(" ...locked"); Ok(()) } @@ -274,7 +274,7 @@ pub mod hmc7043 { write(channel_base + 0x8, 0x08) } - info!("...done"); + info!(" ...done"); Ok(()) } From 99f7672c79b4fd9e3fa400caeea16d33155b62ff Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 16 May 2018 14:27:51 +0000 Subject: [PATCH 0795/2457] ad53xx: tweak spi readback --- artiq/coredevice/ad53xx.py | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index fa41f7d9d..dfc347fbc 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -29,13 +29,13 @@ AD53XX_SPECIAL_OFS0 = 2 << 16 AD53XX_SPECIAL_OFS1 = 3 << 16 AD53XX_SPECIAL_READ = 5 << 16 -AD53XX_READ_X1A = 0X000 << 7 -AD53XX_READ_X1B = 0X040 << 7 -AD53XX_READ_OFFSET = 0X080 << 7 -AD53XX_READ_GAIN = 0X0C0 << 7 -AD53XX_READ_CONTROL = 0X101 << 7 -AD53XX_READ_OFS0 = 0X102 << 7 -AD53XX_READ_OFS1 = 0X103 << 7 +AD53XX_READ_X1A = 0x008 << 7 +AD53XX_READ_X1B = 0x048 << 7 +AD53XX_READ_OFFSET = 0x088 << 7 +AD53XX_READ_GAIN = 0x0C8 << 7 +AD53XX_READ_CONTROL = 0x101 << 7 +AD53XX_READ_OFS0 = 0x102 << 7 +AD53XX_READ_OFS1 = 0x103 << 7 @portable @@ -60,12 +60,11 @@ def ad53xx_cmd_read_ch(channel, op): :param channel: DAC channel to read (8 bits) :param op: The channel register to read, one of - :const:`AD53XX_CMD_DATA`, :const:`AD53XX_CMD_OFFSET` or - :const:`AD53XX_CMD_GAIN` - :return: The 24-bit word to be written to the DAC + :const:`AD53XX_READ_X1A`, :const:`AD53XX_READ_X1B`, + :const:`AD53XX_READ_OFFSET`, :const:`AD53XX_CMD_GAIN` etc. + :return: The 24-bit word to be written to the DAC to initiate read """ - return (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_READ | op | - ((channel + 8) << 7)) + return (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_READ | (op + (channel << 7))) @portable @@ -119,7 +118,7 @@ class AD53xx: "div_read", "vref", "core"} def __init__(self, dmgr, spi_device, ldac_device=None, clr_device=None, - chip_select=1, div_write=4, div_read=8, vref=5., + chip_select=1, div_write=4, div_read=16, vref=5., offset_dacs=8192, core="core"): self.bus = dmgr.get(spi_device) if ldac_device is None: @@ -157,12 +156,12 @@ class AD53xx: """Read a DAC register. This method advances the timeline by the duration of two SPI transfers - plus two RTIO coarse cycles. + plus two RTIO coarse cycles plus 270 ns and consumes all slack. - :param channel: Channel number to read from (default :0) + :param channel: Channel number to read from (default: 0) :param op: Operation to perform, one of :const:`AD53XX_READ_X1A`, :const:`AD53XX_READ_X1B`, :const:`AD53XX_READ_OFFSET`, - :const:`AD53XX_READ_GAIN` (default: :const:`AD53XX_READ_X1A`). + :const:`AD53XX_READ_GAIN` etc. (default: :const:`AD53XX_READ_X1A`). :return: The 16 bit register value """ self.bus.write(ad53xx_cmd_read_ch(channel, op) << 8) @@ -170,10 +169,9 @@ class AD53xx: self.div_read, self.chip_select) delay(270*ns) # t_21 min sync high in readback self.bus.write((AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_NOP) << 8) - self.bus.set_config_mu(SPI_AD53XX_CONFIG, 24, self.div_write, self.chip_select) - return self.bus.read() + return self.bus.read() & 0xffff @kernel def write_offset_dacs_mu(self, value): From 31c6c79204bade21c8450a321f00d5975fd3ce4b Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 16 May 2018 21:50:55 +0000 Subject: [PATCH 0796/2457] firmware: implement an edge profiler. It doesn't work extremely well, and the results can be somewhat confusing, and it needs a libunwind patch, but it's the best I could do and it seems still useful. --- artiq/coredevice/profiler.py | 40 ++++++++------- artiq/firmware/ksupport/glue.c | 6 +++ artiq/firmware/libboard_misoc/or1k/vectors.S | 39 ++++++++++++++ artiq/firmware/libunwind_backtrace/lib.rs | 29 +++++++++-- artiq/firmware/runtime/main.rs | 3 ++ artiq/firmware/runtime/profiler.rs | 53 ++++++++++++++++---- artiq/frontend/artiq_coremgmt.py | 11 ++-- 7 files changed, 145 insertions(+), 36 deletions(-) diff --git a/artiq/coredevice/profiler.py b/artiq/coredevice/profiler.py index 5bbbe1996..5ed431915 100644 --- a/artiq/coredevice/profiler.py +++ b/artiq/coredevice/profiler.py @@ -3,11 +3,15 @@ import subprocess class Symbolizer: - def __init__(self, binary, triple): - self._addr2line = subprocess.Popen([ + def __init__(self, binary, triple, demangle=True): + cmdline = [ triple + "-addr2line", "--exe=" + binary, - "--addresses", "--demangle=rust", "--functions", "--inlines" - ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True) + "--addresses", "--functions", "--inlines" + ] + if demangle: + cmdline.append("--demangle=rust") + self._addr2line = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE, + universal_newlines=True) def symbolize(self, addr): self._addr2line.stdin.write("0x{:08x}\n0\n".format(addr)) @@ -26,17 +30,17 @@ class Symbolizer: file, line = self._addr2line.stdout.readline().rstrip().split(":") - result.append((function, file, line)) + result.append((function, file, line, addr)) class CallgrindWriter: - def __init__(self, output, binary, triple, compression=True): + def __init__(self, output, binary, triple, compression=True, demangle=True): self._output = output self._binary = binary self._current = defaultdict(lambda: None) self._ids = defaultdict(lambda: {}) self._compression = compression - self._symbolizer = Symbolizer(binary, triple) + self._symbolizer = Symbolizer(binary, triple, demangle=demangle) def _write(self, fmt, *args, **kwargs): self._output.write(fmt.format(*args, **kwargs)) @@ -69,18 +73,20 @@ class CallgrindWriter: self._spec("cob", self._binary) def hit(self, addr, count): - for function, file, line in self._symbolizer.symbolize(addr): - self._spec("fn", function) + for function, file, line, addr in self._symbolizer.symbolize(addr): self._spec("fl", file) + self._spec("fn", function) self._write("0x{:08x} {} {}", addr, line, count) def edge(self, caller, callee, count): - function, file, line = next(self._symbolizer.symbolize(callee)) - self._spec("cfn", function) - self._spec("cfl", file) - self._write("calls={} 0x{:08x} {}", count, callee, line) + edges = self._symbolizer.symbolize(callee) + self._symbolizer.symbolize(caller) + for (callee, caller) in zip(edges, edges[1:]): + function, file, line, addr = callee + self._spec("cfl", file) + self._spec("cfn", function) + self._write("calls={} 0x{:08x} {}", count, addr, line) - function, file, line = next(self._symbolizer.symbolize(caller)) - self._spec("fn", function) - self._spec("fl", file) - self._write("0x{:08x} {} {}", caller, line, count) + function, file, line, addr = caller + self._spec("fl", file) + self._spec("fn", function) + self._write("0x{:08x} {} {}", addr, line, count) diff --git a/artiq/firmware/ksupport/glue.c b/artiq/firmware/ksupport/glue.c index 4e4ce318d..3828a6aea 100644 --- a/artiq/firmware/ksupport/glue.c +++ b/artiq/firmware/ksupport/glue.c @@ -21,6 +21,12 @@ void send_to_rtio_log(long long int timestamp, struct slice data); FILE *stderr; +/* called by libunwind */ +char *getenv(const char *var) +{ + return NULL; +} + /* called by libunwind */ int fprintf(FILE *stream, const char *fmt, ...) { diff --git a/artiq/firmware/libboard_misoc/or1k/vectors.S b/artiq/firmware/libboard_misoc/or1k/vectors.S index a92f97a69..708aed9df 100644 --- a/artiq/firmware/libboard_misoc/or1k/vectors.S +++ b/artiq/firmware/libboard_misoc/or1k/vectors.S @@ -171,35 +171,70 @@ _crt0: l.nop _exception_handler: + .cfi_startproc + .cfi_return_column 32 + .cfi_signal_frame + .cfi_def_cfa_offset EXCEPTION_STACK_SIZE l.sw 0x00(r1), r2 + .cfi_offset 2, 0x00-EXCEPTION_STACK_SIZE l.sw 0x04(r1), r3 + .cfi_offset 3, 0x04-EXCEPTION_STACK_SIZE l.sw 0x08(r1), r4 + .cfi_offset 4, 0x08-EXCEPTION_STACK_SIZE l.sw 0x0c(r1), r5 + .cfi_offset 5, 0x0c-EXCEPTION_STACK_SIZE l.sw 0x10(r1), r6 + .cfi_offset 6, 0x10-EXCEPTION_STACK_SIZE l.sw 0x14(r1), r7 + .cfi_offset 7, 0x14-EXCEPTION_STACK_SIZE l.sw 0x18(r1), r8 + .cfi_offset 8, 0x18-EXCEPTION_STACK_SIZE + /* r9 saved in HANDLE_EXCEPTION */ + .cfi_offset 9, 0x1c-EXCEPTION_STACK_SIZE l.sw 0x20(r1), r10 + .cfi_offset 10, 0x20-EXCEPTION_STACK_SIZE l.sw 0x24(r1), r11 + .cfi_offset 11, 0x24-EXCEPTION_STACK_SIZE l.sw 0x28(r1), r12 + .cfi_offset 12, 0x28-EXCEPTION_STACK_SIZE l.sw 0x2c(r1), r13 + .cfi_offset 13, 0x2c-EXCEPTION_STACK_SIZE l.sw 0x30(r1), r14 + .cfi_offset 14, 0x30-EXCEPTION_STACK_SIZE l.sw 0x34(r1), r15 + .cfi_offset 15, 0x34-EXCEPTION_STACK_SIZE l.sw 0x38(r1), r16 + .cfi_offset 16, 0x38-EXCEPTION_STACK_SIZE l.sw 0x3c(r1), r17 + .cfi_offset 17, 0x3c-EXCEPTION_STACK_SIZE l.sw 0x40(r1), r18 + .cfi_offset 18, 0x40-EXCEPTION_STACK_SIZE l.sw 0x44(r1), r19 + .cfi_offset 19, 0x44-EXCEPTION_STACK_SIZE l.sw 0x48(r1), r20 + .cfi_offset 20, 0x48-EXCEPTION_STACK_SIZE l.sw 0x4c(r1), r21 + .cfi_offset 21, 0x4c-EXCEPTION_STACK_SIZE l.sw 0x50(r1), r22 + .cfi_offset 22, 0x50-EXCEPTION_STACK_SIZE l.sw 0x54(r1), r23 + .cfi_offset 23, 0x54-EXCEPTION_STACK_SIZE l.sw 0x58(r1), r24 + .cfi_offset 24, 0x58-EXCEPTION_STACK_SIZE l.sw 0x5c(r1), r25 + .cfi_offset 25, 0x5c-EXCEPTION_STACK_SIZE l.sw 0x60(r1), r26 + .cfi_offset 26, 0x60-EXCEPTION_STACK_SIZE l.sw 0x64(r1), r27 + .cfi_offset 27, 0x64-EXCEPTION_STACK_SIZE l.sw 0x68(r1), r28 + .cfi_offset 28, 0x68-EXCEPTION_STACK_SIZE l.sw 0x6c(r1), r29 + .cfi_offset 29, 0x6c-EXCEPTION_STACK_SIZE l.sw 0x70(r1), r30 + .cfi_offset 30, 0x70-EXCEPTION_STACK_SIZE l.sw 0x74(r1), r31 + .cfi_offset 31, 0x74-EXCEPTION_STACK_SIZE /* Save return address */ l.or r14, r0, r9 @@ -210,6 +245,9 @@ _exception_handler: l.or r4, r0, r1 /* Extract exception PC */ l.mfspr r5, r0, SPR_EPCR_BASE + /* Tell exception PC to the unwinder */ + l.sw 0x78(r1), r5 + .cfi_offset 32, 0x78-EXCEPTION_STACK_SIZE /* Extract exception effective address */ l.mfspr r6, r0, SPR_EEAR_BASE /* Extract exception SR */ @@ -252,6 +290,7 @@ _exception_handler: l.lwz r31, 0x74(r1) l.jr r9 l.nop + .cfi_endproc .global _cache_init _cache_init: diff --git a/artiq/firmware/libunwind_backtrace/lib.rs b/artiq/firmware/libunwind_backtrace/lib.rs index 7e84e5e44..d1c71cf45 100644 --- a/artiq/firmware/libunwind_backtrace/lib.rs +++ b/artiq/firmware/libunwind_backtrace/lib.rs @@ -5,24 +5,43 @@ extern crate unwind; extern crate libc; use unwind as uw; -use libc::c_void; +use libc::{c_void, c_int}; -pub fn backtrace(mut f: F) -> Result<(), uw::_Unwind_Reason_Code> +const UW_REG_SP: c_int = -2; + +pub fn backtrace(f: F) -> Result<(), uw::_Unwind_Reason_Code> where F: FnMut(usize) -> () { + struct TraceContext { + step_fn: F, + prev_sp: uw::_Unwind_Word + } + extern fn trace(context: *mut uw::_Unwind_Context, arg: *mut c_void) -> uw::_Unwind_Reason_Code where F: FnMut(usize) -> () { unsafe { - let step_fn = &mut *(arg as *mut F); - step_fn(uw::_Unwind_GetIP(context)); + let trace_context = &mut *(arg as *mut TraceContext); + + // Detect the root of a libfringe thread + let cur_sp = uw::_Unwind_GetGR(context, UW_REG_SP); + if cur_sp == trace_context.prev_sp { + return uw::_URC_END_OF_STACK + } else { + trace_context.prev_sp = cur_sp; + } + + // GetIP gives us the return address, i.e. the address after the delay slot, + // but we're interested in the call instruction. + (trace_context.step_fn)(uw::_Unwind_GetIP(context) - 2 * 4); uw::_URC_NO_REASON } } unsafe { - match uw::_Unwind_Backtrace(trace::, &mut f as *mut _ as *mut c_void) { + let mut trace_context = TraceContext { step_fn: f, prev_sp: 0 }; + match uw::_Unwind_Backtrace(trace::, &mut trace_context as *mut _ as *mut c_void) { uw::_URC_NO_REASON => Ok(()), err => Err(err) } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 2f075b573..087f69167 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -57,6 +57,7 @@ mod moninj; mod analyzer; fn startup() { + irq::set_mask(0); irq::set_ie(true); clock::init(); info!("ARTIQ runtime starting..."); @@ -305,6 +306,8 @@ pub extern fn abort() { #[lang = "panic_fmt"] pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, line: u32, column: u32) -> ! { + irq::set_ie(false); + println!("panic at {}:{}:{}: {}", file, line, column, args); println!("backtrace for software version {}:", diff --git a/artiq/firmware/runtime/profiler.rs b/artiq/firmware/runtime/profiler.rs index e3c47e1a0..9765100cc 100644 --- a/artiq/firmware/runtime/profiler.rs +++ b/artiq/firmware/runtime/profiler.rs @@ -10,8 +10,8 @@ use managed::ManagedMap; pub struct Address(NonZeroUsize); impl Address { - pub fn new(raw: usize) -> Option
{ - NonZeroUsize::new(raw).map(Address) + pub fn new(raw: usize) -> Address { + Address(NonZeroUsize::new(raw).expect("null address")) } pub fn as_raw(&self) -> usize { @@ -50,6 +50,10 @@ impl Profile { self.edges.capacity() * edge_size } + pub fn has_edges(&self) -> bool { + self.edges.is_empty() + } + pub fn hits<'a>(&'a mut self) -> ManagedMap<'a, Address, u32> { ManagedMap::Borrowed(&mut self.hits[..]) } @@ -88,6 +92,7 @@ impl Profile { #[cfg(has_timer1)] mod imp { + use unwind_backtrace::backtrace; use board_misoc::{csr, irq}; use super::{Address, Profile}; @@ -192,22 +197,46 @@ mod imp { } } + // Skip frames: ::profiler::sample, ::exception, exception vector. + const SKIP_FRAMES: i32 = 3; + #[inline(always)] // make the top of backtrace predictable fn record(profile: &mut Profile, pc: usize) -> Result<(), ()> { - let callee = Address::new(pc).expect("null code address"); - profile.record_hit(callee)?; + let mut result = Ok(()); + let mut frame = -SKIP_FRAMES; - // TODO: record edges + // If we have storage for edges, use the DWARF unwinder. + // Otherwise, don't bother and use a much faster path that just looks at EPCR. + // Also, acquiring a meaningful backtrace requires libunwind + // with the https://reviews.llvm.org/D46971 patch applied. + if profile.has_edges() { + let mut prev_pc = 0; + let _ = backtrace(|pc| { + if frame == 0 { + result = result.and_then(|()| + profile.record_hit(Address::new(pc))); + prev_pc = pc; + } else if frame > 0 { + result = result.and_then(|()| + profile.record_edge(Address::new(pc), + Address::new(prev_pc))); + } + prev_pc = pc; + frame += 1; + }); + } - Ok(()) + // If we couldn't get anything useful out of a backtrace, at least + // record a hit at the exception PC. + if frame <= 0 { + result = profile.record_hit(Address::new(pc)); + } + + result } #[inline(never)] // see above pub fn sample(pc: usize) { - unsafe { - csr::timer1::ev_pending_write(1); - } - let result = { let mut profile = Lock::take().expect("cannot lock"); record(profile.as_mut().expect("profiler not running"), pc) @@ -216,6 +245,10 @@ mod imp { if result.is_err() { warn!("out of space"); stop(); + } else { + unsafe { + csr::timer1::ev_pending_write(1); + } } } } diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index d611b711c..0e9553c9d 100644 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -98,8 +98,8 @@ def get_argparser(): help="sampling interval, in microseconds") p_start.add_argument("--hits-size", metavar="ENTRIES", type=int, default=8192, help="hit buffer size") - p_start.add_argument("--edges-size", metavar="ENTRIES", type=int, default=0, - help="edge buffer size (edge profiling not implemented)") + p_start.add_argument("--edges-size", metavar="ENTRIES", type=int, default=8192, + help="edge buffer size") p_stop = subparsers.add_parser("stop", help="stop profiling") @@ -113,6 +113,9 @@ def get_argparser(): p_save.add_argument("--no-compression", dest="compression", default=True, action="store_false", help="disable profile compression") + p_save.add_argument("--no-demangle", + dest="demangle", default=True, action="store_false", + help="disable symbol demangling") # misc debug t_debug = tools.add_parser("debug", @@ -178,8 +181,8 @@ def main(): mgmt.stop_profiler() elif args.action == "save": hits, edges = mgmt.get_profile() - writer = CallgrindWriter(args.output, args.firmware, - "or1k-linux", args.compression) + writer = CallgrindWriter(args.output, args.firmware, "or1k-linux", + args.compression, args.demangle) writer.header() for addr, count in hits.items(): writer.hit(addr, count) From 3b61b7c30b08d4393ac09bd8f1ea46af1ebf15c8 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 16 May 2018 21:53:36 +0000 Subject: [PATCH 0797/2457] compiler: fix tests after 4d06c1d8. --- artiq/compiler/testbench/embedding.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/artiq/compiler/testbench/embedding.py b/artiq/compiler/testbench/embedding.py index 65435a7db..f79bb5a68 100644 --- a/artiq/compiler/testbench/embedding.py +++ b/artiq/compiler/testbench/embedding.py @@ -38,8 +38,6 @@ def main(): core.compile(testcase_vars["entrypoint"], (), {}) else: core.run(testcase_vars["entrypoint"], (), {}) - print(core.comm.get_log()) - core.comm.clear_log() except CompileError as error: if not diag: exit(1) From d4f074b1e162c80f3440fbdd6ea2b264bf72efb2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 17 May 2018 16:02:21 +0800 Subject: [PATCH 0798/2457] firmware: fix Allaki addressing. Closes #993 --- artiq/firmware/libboard_artiq/hmc542.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/hmc542.rs b/artiq/firmware/libboard_artiq/hmc542.rs index 509bc148c..fed25a78e 100644 --- a/artiq/firmware/libboard_artiq/hmc542.rs +++ b/artiq/firmware/libboard_artiq/hmc542.rs @@ -11,7 +11,7 @@ const CHANNELS: usize = 2; fn set_pins(card_index: usize, chan_index: usize, pins: u32) { let pins = pins ^ PIN_RST_N; - let shift = card_index * 2 + chan_index; + let shift = (card_index * 2 + chan_index)*4; unsafe { let state = csr::allaki_atts::out_read(); let state = state & !(0xf << shift); From 5744d97d59b1e41a3056ee1d35774c31ec0d8ea4 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 17 May 2018 08:13:39 +0000 Subject: [PATCH 0799/2457] firmware: adjust backtrace addresses correctly. --- artiq/firmware/libunwind_backtrace/lib.rs | 4 +--- artiq/firmware/runtime/main.rs | 4 +++- artiq/firmware/runtime/profiler.rs | 11 +++++++++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/libunwind_backtrace/lib.rs b/artiq/firmware/libunwind_backtrace/lib.rs index d1c71cf45..22c55a628 100644 --- a/artiq/firmware/libunwind_backtrace/lib.rs +++ b/artiq/firmware/libunwind_backtrace/lib.rs @@ -32,9 +32,7 @@ pub fn backtrace(f: F) -> Result<(), uw::_Unwind_Reason_Code> trace_context.prev_sp = cur_sp; } - // GetIP gives us the return address, i.e. the address after the delay slot, - // but we're interested in the call instruction. - (trace_context.step_fn)(uw::_Unwind_GetIP(context) - 2 * 4); + (trace_context.step_fn)(uw::_Unwind_GetIP(context)); uw::_URC_NO_REASON } } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 087f69167..f0bef4108 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -313,7 +313,9 @@ pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, println!("backtrace for software version {}:", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); let _ = unwind_backtrace::backtrace(|ip| { - println!("{:#08x}", ip); + // Backtrace gives us the return address, i.e. the address after the delay slot, + // but we're interested in the call instruction. + println!("{:#08x}", ip - 2 * 4); }); if config::read_str("panic_reset", |r| r == Ok("1")) { diff --git a/artiq/firmware/runtime/profiler.rs b/artiq/firmware/runtime/profiler.rs index 9765100cc..ac5097dfe 100644 --- a/artiq/firmware/runtime/profiler.rs +++ b/artiq/firmware/runtime/profiler.rs @@ -201,7 +201,7 @@ mod imp { const SKIP_FRAMES: i32 = 3; #[inline(always)] // make the top of backtrace predictable - fn record(profile: &mut Profile, pc: usize) -> Result<(), ()> { + fn record(profile: &mut Profile, exn_pc: usize) -> Result<(), ()> { let mut result = Ok(()); let mut frame = -SKIP_FRAMES; @@ -212,6 +212,12 @@ mod imp { if profile.has_edges() { let mut prev_pc = 0; let _ = backtrace(|pc| { + // Backtrace gives us the return address, i.e. the address after the delay slot, + // but we're interested in the call instruction, *except* when going through + // the frame directly below the exception frame, which has the address that's + // being executed. + let pc = if pc != exn_pc { pc - 2 * 4 } else { pc }; + if frame == 0 { result = result.and_then(|()| profile.record_hit(Address::new(pc))); @@ -221,6 +227,7 @@ mod imp { profile.record_edge(Address::new(pc), Address::new(prev_pc))); } + prev_pc = pc; frame += 1; }); @@ -229,7 +236,7 @@ mod imp { // If we couldn't get anything useful out of a backtrace, at least // record a hit at the exception PC. if frame <= 0 { - result = profile.record_hit(Address::new(pc)); + result = profile.record_hit(Address::new(exn_pc)); } result From bfff7552956a50ebc912252fce2f4014562a9caf Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 16 May 2018 19:12:00 +0000 Subject: [PATCH 0800/2457] urukul: do IO_RST also when blind --- artiq/coredevice/urukul.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 295281364..59dcceb5a 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -190,7 +190,9 @@ class CPLD: cfg = self.cfg_reg # Don't pulse MASTER_RESET (m-labs/artiq#940) self.cfg_reg = cfg | (0 << CFG_RST) | (1 << CFG_IO_RST) - if not blind: + if blind: + self.cfg_write(self.cfg_reg) + else: proto_rev = urukul_sta_proto_rev(self.sta_read()) if proto_rev != STA_PROTO_REV_MATCH: raise ValueError("Urukul proto_rev mismatch") From 6476219296a4f6516b246b612abcf18fad3d16b3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 May 2018 00:10:46 +0800 Subject: [PATCH 0801/2457] frontend: fix permissions --- artiq/frontend/artiq_coremgmt.py | 0 artiq/frontend/artiq_pcap.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 artiq/frontend/artiq_coremgmt.py mode change 100644 => 100755 artiq/frontend/artiq_pcap.py diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py old mode 100644 new mode 100755 diff --git a/artiq/frontend/artiq_pcap.py b/artiq/frontend/artiq_pcap.py old mode 100644 new mode 100755 From 826a85950bc102326fb382319ab87179b9c706e6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 May 2018 14:18:36 +0800 Subject: [PATCH 0802/2457] manual: add warning about developing section being for developers --- doc/manual/developing.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index b1bf15336..39eaa4602 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -1,6 +1,9 @@ Developing ARTIQ ^^^^^^^^^^^^^^^^ +.. warning:: + This section is only for software or FPGA developers who want to modify ARTIQ. The steps described here are not required if you simply want to run experiments with ARTIQ. + .. note:: Developing ARTIQ is currently only possible on Linux. From 73f8e614783cff68800f8c578bf0d02f421e5de7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 May 2018 16:13:50 +0800 Subject: [PATCH 0803/2457] kasli_sysu: fix TTL directions in example device_db --- artiq/examples/kasli_sysu/device_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/kasli_sysu/device_db.py b/artiq/examples/kasli_sysu/device_db.py index 1539994a9..bd1de2c82 100644 --- a/artiq/examples/kasli_sysu/device_db.py +++ b/artiq/examples/kasli_sysu/device_db.py @@ -42,7 +42,7 @@ for i in range(40): device_db["ttl" + str(i)] = { "type": "local", "module": "artiq.coredevice.ttl", - "class": "TTLInOut", + "class": "TTLInOut" if i < 4 else "TTLOut", "arguments": {"channel": i}, } From 37bd0c2566f76bf6fbd7f53eca72ad9f46eda362 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 May 2018 16:15:07 +0800 Subject: [PATCH 0804/2457] kasli: add USTC target --- artiq/examples/kasli_ustc/device_db.py | 189 +++++++++++++++++++ artiq/examples/kasli_ustc/repository/demo.py | 82 ++++++++ artiq/frontend/artiq_flash.py | 3 +- artiq/gateware/targets/kasli.py | 68 ++++++- 4 files changed, 339 insertions(+), 3 deletions(-) create mode 100644 artiq/examples/kasli_ustc/device_db.py create mode 100644 artiq/examples/kasli_ustc/repository/demo.py diff --git a/artiq/examples/kasli_ustc/device_db.py b/artiq/examples/kasli_ustc/device_db.py new file mode 100644 index 000000000..31b1bf03d --- /dev/null +++ b/artiq/examples/kasli_ustc/device_db.py @@ -0,0 +1,189 @@ +core_addr = "kasli-2.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + +for i in range(24): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": i}, + } + +device_db.update( + spi_urukul0={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 24} + }, + ttl_urukul0_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 25} + }, + ttl_urukul0_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 26} + }, + ttl_urukul0_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 27} + }, + ttl_urukul0_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 28} + }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 29} + }, + urukul0_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul0_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } + + +device_db.update( + spi_urukul1={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 30} + }, + ttl_urukul1_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 31} + }, + ttl_urukul1_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 32} + }, + ttl_urukul1_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 33} + }, + ttl_urukul1_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 34} + }, + ttl_urukul1_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 35} + }, + urukul1_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul1", + "io_update_device": "ttl_urukul1_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul1_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul1_cpld", + "sw_device": "ttl_urukul1_sw" + str(i) + } + } + +device_db.update( + led0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 36} + }, + led1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 37} + } +) diff --git a/artiq/examples/kasli_ustc/repository/demo.py b/artiq/examples/kasli_ustc/repository/demo.py new file mode 100644 index 000000000..169856a08 --- /dev/null +++ b/artiq/examples/kasli_ustc/repository/demo.py @@ -0,0 +1,82 @@ +from artiq.experiment import * + + +class UrukulTest(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("urukul0_cpld") + self.setattr_device("urukul0_ch0") + self.setattr_device("urukul0_ch1") + self.setattr_device("urukul0_ch2") + self.setattr_device("urukul0_ch3") + self.setattr_device("urukul1_cpld") + self.setattr_device("urukul1_ch0") + self.setattr_device("urukul1_ch1") + self.setattr_device("urukul1_ch2") + self.setattr_device("urukul1_ch3") + self.setattr_device("led0") + self.ttl = self.get_device("ttl16") + + @kernel + def run(self): + self.core.reset() + self.ttl.output() + delay(1*us) + + self.urukul0_cpld.init() + self.urukul0_ch0.init() + self.urukul0_ch1.init() + self.urukul0_ch2.init() + self.urukul0_ch3.init() + self.urukul1_cpld.init() + self.urukul1_ch0.init() + self.urukul1_ch1.init() + self.urukul1_ch2.init() + self.urukul1_ch3.init() + + delay(1000*us) + self.urukul0_ch0.set(10*MHz) + self.urukul0_ch0.sw.on() + self.urukul0_ch0.set_att(10.) + + delay(1000*us) + self.urukul0_ch1.set(20*MHz, 0.5) + self.urukul0_ch1.sw.on() + self.urukul0_ch1.set_att(8.) + + delay(1000*us) + self.urukul0_ch2.set(30*MHz) + self.urukul0_ch2.sw.on() + self.urukul0_ch2.set_att(6.) + + delay(1000*us) + self.urukul0_ch3.set(40*MHz) + self.urukul0_ch3.sw.on() + self.urukul0_ch3.set_att(4.) + + delay(1000*us) + self.urukul1_ch0.set(15*MHz) + self.urukul1_ch0.sw.on() + self.urukul1_ch0.set_att(10.) + + delay(1000*us) + self.urukul1_ch1.set(25*MHz, 0.5) + self.urukul1_ch1.sw.on() + self.urukul1_ch1.set_att(8.) + + delay(1000*us) + self.urukul1_ch2.set(35*MHz) + self.urukul1_ch2.sw.on() + self.urukul1_ch2.set_att(6.) + + delay(1000*us) + self.urukul1_ch3.set(45*MHz) + self.urukul1_ch3.sw.on() + self.urukul1_ch3.set_att(4.) + + while True: + with parallel: + self.ttl.pulse(100*ms) + self.urukul0_ch0.sw.pulse(100*ms) + delay(100*ms) + self.led0.pulse(100*ms) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index fb6610297..7058c287a 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -268,7 +268,8 @@ def main(): }, "kasli": { "programmer": partial(ProgrammerXC7, board="kasli", proxy="bscan_spi_xc7a100t.bit"), - "variants": ["opticlock", "suservo", "sysu", "mitll", "master", "satellite"], + "variants": ["opticlock", "suservo", "sysu", "mitll", "ustc", + "master", "satellite"], "gateware": ("spi0", 0x000000), "bootloader": ("spi0", 0x400000), "storage": ("spi0", 0x440000), diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b3bce96fe..b1d0ea70e 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -630,7 +630,11 @@ class SYSU(_StandaloneBase): for i in range(40): eem_offset, port = divmod(i, 8) pads = platform.request("eem{}".format(2 + eem_offset), port) - phy = ttl_serdes_7series.InOut_8X(pads.p, pads.n) + if i < 4: + cls = ttl_serdes_7series.InOut_8X + else: + cls = ttl_serdes_7series.Output_8X + phy = cls(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) @@ -727,6 +731,63 @@ class MITLL(_StandaloneBase): self.add_rtio(rtio_channels) +class USTC(_StandaloneBase): + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + + platform = self.platform + # TODO: grabber on eem0->eemA + platform.add_extension(_urukul("eem2", "eem1")) + platform.add_extension(_urukul("eem4", "eem3")) + platform.add_extension(_dio("eem5")) + platform.add_extension(_dio("eem6")) + platform.add_extension(_dio("eem7")) + + # EEM5-7: TTL + rtio_channels = [] + for i in range(24): + eem_offset, port = divmod(i, 8) + pads = platform.request("eem{}".format(5 + eem_offset), port) + phy = ttl_serdes_7series.InOut_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + # EEM2-4: Urukul + for eem in (2, 4): + phy = spi2.SPIMaster(self.platform.request("eem{}_spi_p".format(eem)), + self.platform.request("eem{}_spi_n".format(eem))) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + pads = platform.request("eem{}_dds_reset".format(eem)) + self.specials += DifferentialOutput(0, pads.p, pads.n) + + for signal in "io_update sw0 sw1 sw2 sw3".split(): + pads = platform.request("eem{}_{}".format(eem, signal)) + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + for i in (1, 2): + sfp_ctl = platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + print(len(rtio_channels)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) + rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(rtio_channels) + + class _RTIOClockMultiplier(Module): def __init__(self, rtio_clk_freq): self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) @@ -1037,7 +1098,8 @@ def main(): soc_kasli_args(parser) parser.set_defaults(output_dir="artiq_kasli") parser.add_argument("-V", "--variant", default="opticlock", - help="variant: opticlock/suservo/sysu/mitll/master/satellite " + help="variant: opticlock/suservo/sysu/mitll/ustc/" + "master/satellite " "(default: %(default)s)") args = parser.parse_args() @@ -1050,6 +1112,8 @@ def main(): cls = SYSU elif variant == "mitll": cls = MITLL + elif variant == "ustc": + cls = USTC elif variant == "master": cls = Master elif variant == "satellite": From 8a988d0feb041b6074c058da387230989999a654 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 May 2018 17:25:23 +0800 Subject: [PATCH 0805/2457] kasli: remove leftover debug print --- artiq/gateware/targets/kasli.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b1d0ea70e..b1c85b99b 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -779,8 +779,6 @@ class USTC(_StandaloneBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - print(len(rtio_channels)) - self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) From b10d3ee4b41f75cd14ecda7f89911b65ca1199be Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 May 2018 17:41:32 +0800 Subject: [PATCH 0806/2457] make RTIO clock switch optional and simplify Kasli no longer has an internal RTIO clock. Switching clocks dynamically is no longer supported. --- RELEASE_NOTES.rst | 2 + artiq/coredevice/comm_kernel.py | 12 --- artiq/coredevice/core.py | 8 +- .../firmware/libproto_artiq/session_proto.rs | 22 ----- artiq/firmware/runtime/rtio_mgt.rs | 93 ++++++++++--------- artiq/firmware/runtime/session.rs | 18 ---- artiq/gateware/targets/kasli.py | 17 ++-- artiq/gateware/targets/kc705.py | 2 + doc/manual/core_device.rst | 5 + doc/manual/installing.rst | 8 +- 10 files changed, 70 insertions(+), 117 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index f329d0c8d..83d10d2ac 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -35,6 +35,8 @@ ARTIQ-4 * ``artiq.coredevice.dds`` has been renamed to ``artiq.coredevice.ad9914`` and simplified. DDS batch mode is no longer supported. The ``core_dds`` device is no longer necessary. +* The configuration entry ``startup_clock`` is renamed ``rtio_clock``. Switching + clocks dynamically (i.e. without device restart) is no longer supported. ARTIQ-3 diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index e79f72f3d..5939fb52d 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -16,7 +16,6 @@ logger = logging.getLogger(__name__) class Request(Enum): SystemInfo = 3 - SwitchClock = 4 LoadKernel = 5 RunKernel = 6 @@ -27,8 +26,6 @@ class Request(Enum): class Reply(Enum): SystemInfo = 2 - ClockSwitchCompleted = 3 - ClockSwitchFailed = 4 LoadCompleted = 5 LoadFailed = 6 @@ -60,9 +57,6 @@ class CommKernelDummy: def __init__(self): pass - def switch_clock(self, external): - pass - def load(self, kernel_library): pass @@ -237,12 +231,6 @@ class CommKernel: if not finished_cleanly: logger.warning("Previous kernel did not cleanly finish") - def switch_clock(self, external): - self._write_header(Request.SwitchClock) - self._write_int8(external) - - self._read_empty(Reply.ClockSwitchCompleted) - def load(self, kernel_library): self._write_header(Request.LoadKernel) self._write_bytes(kernel_library) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 300085882..9f84efe60 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -62,8 +62,6 @@ class Core: clocked at 125MHz and a SERDES multiplication factor of 8, the reference period is 1ns. The time machine unit is equal to this period. - :param external_clock: whether the core device should switch to its - external RTIO clock input instead of using its internal oscillator. :param ref_multiplier: ratio between the RTIO fine timestamp frequency and the RTIO coarse timestamp frequency (e.g. SERDES multiplication factor). @@ -71,13 +69,10 @@ class Core: kernel_invariants = { "core", "ref_period", "coarse_ref_period", "ref_multiplier", - "external_clock", } - def __init__(self, dmgr, host, ref_period, external_clock=False, - ref_multiplier=8): + def __init__(self, dmgr, host, ref_period, ref_multiplier=8): self.ref_period = ref_period - self.external_clock = external_clock self.ref_multiplier = ref_multiplier self.coarse_ref_period = ref_period*ref_multiplier if host is None: @@ -129,7 +124,6 @@ class Core: if self.first_run: self.comm.check_system_info() - self.comm.switch_clock(self.external_clock) self.first_run = False self.comm.load(kernel_library) diff --git a/artiq/firmware/libproto_artiq/session_proto.rs b/artiq/firmware/libproto_artiq/session_proto.rs index c2867c7d4..cc0012da5 100644 --- a/artiq/firmware/libproto_artiq/session_proto.rs +++ b/artiq/firmware/libproto_artiq/session_proto.rs @@ -64,7 +64,6 @@ fn write_sync(writer: &mut W) -> Result<(), IoError> #[derive(Debug)] pub enum Request { SystemInfo, - SwitchClock(u8), LoadKernel(Vec), RunKernel, @@ -87,8 +86,6 @@ pub enum Reply<'a> { ident: &'a str, finished_cleanly: bool }, - ClockSwitchCompleted, - ClockSwitchFailed, LoadCompleted, LoadFailed(&'a str), @@ -118,10 +115,7 @@ impl Request { { read_sync(reader)?; Ok(match reader.read_u8()? { - // 1-2, 13 were log requests - 3 => Request::SystemInfo, - 4 => Request::SwitchClock(reader.read_u8()?), 5 => Request::LoadKernel(reader.read_bytes()?), 6 => Request::RunKernel, @@ -141,10 +135,6 @@ impl Request { function: reader.read_string()? }, - // 9-12 were flash requests - - // 14 was hotswap request - ty => return Err(Error::UnknownPacket(ty)) }) } @@ -156,20 +146,12 @@ impl<'a> Reply<'a> { { write_sync(writer)?; match *self { - // 1 was log reply - Reply::SystemInfo { ident, finished_cleanly } => { writer.write_u8(2)?; writer.write(b"AROR")?; writer.write_string(ident)?; writer.write_u8(finished_cleanly as u8)?; }, - Reply::ClockSwitchCompleted => { - writer.write_u8(3)?; - }, - Reply::ClockSwitchFailed => { - writer.write_u8(4)?; - }, Reply::LoadCompleted => { writer.write_u8(5)?; @@ -209,16 +191,12 @@ impl<'a> Reply<'a> { writer.write_u8(async as u8)?; }, - // 11-13 were flash requests - Reply::WatchdogExpired => { writer.write_u8(14)?; }, Reply::ClockFailure => { writer.write_u8(15)?; }, - - // 16 was hotswap imminent reply } Ok(()) } diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 01ba1a4b9..814c021e2 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -1,28 +1,32 @@ -use board_misoc::{csr, config}; +use board_misoc::csr; +#[cfg(has_rtio_clock_switch)] +use board_misoc::config; use sched::Io; #[cfg(has_rtio_crg)] pub mod crg { use board_misoc::{clock, csr}; - pub fn init() { - unsafe { csr::rtio_crg::pll_reset_write(0) } - } - pub fn check() -> bool { unsafe { csr::rtio_crg::pll_locked_read() != 0 } } - pub fn switch_clock(clk: u8) -> bool { + #[cfg(has_rtio_clock_switch)] + pub fn init(clk: u8) -> bool { unsafe { - let cur_clk = csr::rtio_crg::clock_sel_read(); - if clk != cur_clk { - csr::rtio_crg::pll_reset_write(1); - csr::rtio_crg::clock_sel_write(clk); - csr::rtio_crg::pll_reset_write(0); - } + csr::rtio_crg::pll_reset_write(1); + csr::rtio_crg::clock_sel_write(clk); + csr::rtio_crg::pll_reset_write(0); } + clock::spin_us(150); + return check() + } + #[cfg(not(has_rtio_clock_switch))] + pub fn init() -> bool { + unsafe { + csr::rtio_crg::pll_reset_write(0); + } clock::spin_us(150); return check() } @@ -30,9 +34,7 @@ pub mod crg { #[cfg(not(has_rtio_crg))] pub mod crg { - pub fn init() {} pub fn check() -> bool { true } - pub fn switch_clock(_clk: u8) -> bool { true } } #[cfg(has_drtio)] @@ -227,40 +229,43 @@ fn async_error_thread(io: Io) { } pub fn startup(io: &Io) { - crg::init(); + #[cfg(has_rtio_crg)] + { + #[cfg(has_rtio_clock_switch)] + { + #[derive(Debug)] + enum RtioClock { + Internal = 0, + External = 1 + }; - #[derive(Debug)] - enum RtioClock { - Internal = 0, - External = 1 - }; + let clk = config::read("rtio_clock", |result| { + match result { + Ok(b"i") => { + info!("using internal RTIO clock"); + RtioClock::Internal + }, + Ok(b"e") => { + info!("using external RTIO clock"); + RtioClock::External + }, + _ => { + info!("using internal RTIO clock (by default)"); + RtioClock::Internal + }, + } + }); - let clk = config::read("startup_clock", |result| { - match result { - Ok(b"i") => { - info!("using internal startup RTIO clock"); - RtioClock::Internal - }, - Ok(b"e") => { - info!("using external startup RTIO clock"); - RtioClock::External - }, - Err(_) => { - info!("using internal startup RTIO clock (by default)"); - RtioClock::Internal - }, - Ok(_) => { - error!("unrecognized startup_clock configuration entry, \ - using internal RTIO clock"); - RtioClock::Internal + if !crg::init(clk as u8) { + error!("RTIO clock failed"); + } + } + #[cfg(not(has_rtio_clock_switch))] + { + if !crg::init() { + error!("RTIO clock failed"); } } - }); - - if !crg::switch_clock(clk as u8) { - error!("startup RTIO clock failed"); - warn!("this may cause the system initialization to fail"); - warn!("fix clocking and reset the device"); } drtio::startup(io); diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index ca98fdbb6..d9812861b 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -250,24 +250,6 @@ fn process_host_message(io: &Io, session.congress.finished_cleanly.set(true) } - host::Request::SwitchClock(clk) => { - if session.running() { - unexpected!("attempted to switch RTIO clock while a kernel was running") - } - - #[cfg(has_rtio_core)] - { - if rtio_mgt::crg::switch_clock(clk) { - host_write(stream, host::Reply::ClockSwitchCompleted)?; - } else { - host_write(stream, host::Reply::ClockSwitchFailed)?; - } - } - - #[cfg(not(has_rtio_core))] - host_write(stream, host::Reply::ClockSwitchFailed)? - } - host::Request::LoadKernel(kernel) => match unsafe { kern_load(io, session, &kernel) } { Ok(()) => host_write(stream, host::Reply::LoadCompleted)?, diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b1c85b99b..bdc2b283d 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -29,25 +29,22 @@ from artiq import __version__ as artiq_version class _RTIOCRG(Module, AutoCSR): - def __init__(self, platform, rtio_internal_clk): - self._clock_sel = CSRStorage() + def __init__(self, platform): self._pll_reset = CSRStorage(reset=1) self._pll_locked = CSRStatus() self.clock_domains.cd_rtio = ClockDomain() self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) - rtio_external_clk = Signal() - clk_synth_se = Signal() clk_synth = platform.request("si5324_clkout_fabric") + clk_synth_se = Signal() + clk_synth_buffered = Signal() platform.add_period_constraint(clk_synth.p, 8.0) self.specials += [ Instance("IBUFGDS", p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE", i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se), - Instance("BUFG", i_I=clk_synth_se, o_O=rtio_external_clk), + Instance("BUFG", i_I=clk_synth_se, o_O=clk_synth_buffered), ] - platform.add_false_path_constraints( - rtio_external_clk, rtio_internal_clk) pll_locked = Signal() rtio_clk = Signal() @@ -59,9 +56,9 @@ class _RTIOCRG(Module, AutoCSR): p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0, - i_CLKIN1=rtio_internal_clk, i_CLKIN2=rtio_external_clk, + i_CLKIN2=clk_synth_buffered, # Warning: CLKINSEL=0 means CLKIN2 is selected - i_CLKINSEL=~self._clock_sel.storage, + i_CLKINSEL=0, # VCO @ 1GHz when using 125MHz input p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, @@ -123,7 +120,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.config["SI5324_SOFT_RESET"] = None def add_rtio(self, rtio_channels): - self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) + self.submodules.rtio_crg = _RTIOCRG(self.platform) self.csr_devices.append("rtio_crg") fix_serdes_timing_path(self.platform) self.submodules.rtio_core = rtio.Core(rtio_channels) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index a3eea1949..39f26afa8 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -256,6 +256,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): def add_rtio(self, rtio_channels): self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) self.csr_devices.append("rtio_crg") + self.config["HAS_RTIO_CLOCK_SWITCH"] = None self.submodules.rtio_core = rtio.Core(rtio_channels) self.csr_devices.append("rtio_core") self.submodules.rtio = rtio.KernelInitiator() @@ -502,6 +503,7 @@ class SMA_SPI(_StandaloneBase): self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk, use_sma=False) self.csr_devices.append("rtio_crg") + self.config["HAS_RTIO_CLOCK_SWITCH"] = None self.submodules.rtio_core = rtio.Core(rtio_channels) self.csr_devices.append("rtio_core") self.submodules.rtio = rtio.KernelInitiator() diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index ef269277f..e9dff441c 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -159,6 +159,11 @@ To avoid I/O contention, the startup kernel should first program the TCA6424A ex See :mod:`artiq.coredevice.i2c` for more details. +Clocking +++++++++ + +The KC705 supports an internal 125MHz RTIO clock (based on its crystal oscillator) and an external clock, that can be selected using the ``rtio_clock`` configuration entry. + Kasli ----- diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index da9affe38..7b726e2ec 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -189,12 +189,12 @@ The startup kernel is executed once when the core device powers up. It should in For DRTIO systems, the startup kernel should wait until the desired links are up, using :meth:`artiq.coredevice.Core.get_drtio_link_status`. -* (optional) Select the startup clock +* (optional) Select the RTIO clock source -The core device may use either an external clock signal or its internal clock. This clock can be switched dynamically after the PC is connected using the ``external_clock`` parameter of the core device driver; however, one may want to select the clock at power-up so that it is used for the startup and idle kernels. Use one of these commands: :: +Some core devices may use either an external clock signal or their internal clock. The clock is selected at power-up. Use one of these commands: :: - $ artiq_coreconfig write -s startup_clock i # internal clock (default) - $ artiq_coreconfig write -s startup_clock e # external clock + $ artiq_coreconfig write -s rtio_clock i # internal clock (default) + $ artiq_coreconfig write -s rtio_clock e # external clock .. rubric:: Footnotes From 9a4408a57073de3ae30f84b050f6547267f5941c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 May 2018 22:52:53 +0800 Subject: [PATCH 0807/2457] add Kasli TTL tester --- .../kasli_basic/repository/kasli_tester.py | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 artiq/examples/kasli_basic/repository/kasli_tester.py diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py new file mode 100644 index 000000000..8b199bc93 --- /dev/null +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -0,0 +1,141 @@ +import sys +import select + +from artiq.experiment import * + + +def chunker(seq, size): + res = [] + for el in seq: + res.append(el) + if len(res) == size: + yield res + res = [] + if res: + yield res + + +def is_enter_pressed() -> TBool: + if select.select([sys.stdin,], [], [], 0.0)[0]: + sys.stdin.read(1) + return True + else: + return False + + +class KasliTester(EnvExperiment): + def build(self): + self.setattr_device("core") + + self.leds = dict() + self.ttl_outs = dict() + self.ttl_ins = dict() + + ddb = self.get_device_db() + for name, desc in ddb.items(): + if isinstance(desc, dict) and desc["type"] == "local": + module, cls = desc["module"], desc["class"] + if (module, cls) == ("artiq.coredevice.ttl", "TTLOut"): + dev = self.get_device(name) + if "led" in name: # guess + self.leds[name] = dev + else: + self.ttl_outs[name] = dev + elif (module, cls) == ("artiq.coredevice.ttl", "TTLInOut"): + self.ttl_ins[name] = self.get_device(name) + + # Remove Urukul control signals from TTL outs (tested separately) + ddb = self.get_device_db() + for name, desc in ddb.items(): + if isinstance(desc, dict) and desc["type"] == "local": + module, cls = desc["module"], desc["class"] + if ((module, cls) == ("artiq.coredevice.ad9910", "AD9910") + or (module, cls) == ("artiq.coredevice.ad9912", "AD9912")): + sw_device = desc["arguments"]["sw_device"] + del self.ttl_outs[sw_device] + if (module, cls) == ("artiq.coredevice.urukul", "CPLD"): + io_update_device = desc["arguments"]["io_update_device"] + del self.ttl_outs[io_update_device] + + # Sort everything by RTIO channel number + self.leds = sorted(self.leds.items(), key=lambda x: x[1].channel) + self.ttl_outs = sorted(self.ttl_outs.items(), key=lambda x: x[1].channel) + self.ttl_ins = sorted(self.ttl_ins.items(), key=lambda x: x[1].channel) + + @kernel + def test_led(self, led): + while not is_enter_pressed(): + self.core.break_realtime() + # do not fill the FIFOs too much to avoid long response times + t = now_mu() - self.core.seconds_to_mu(0.2) + while self.core.get_rtio_counter_mu() < t: + pass + for i in range(3): + led.pulse(100*ms) + delay(100*ms) + + def test_leds(self): + print("*** Testing LEDs.") + print("Check for blinking. Press ENTER when done.") + + for led_name, led_dev in self.leds: + print("Testing LED: {}".format(led_name)) + self.test_led(led_dev) + + @kernel + def test_ttl_out_chunk(self, ttl_chunk): + while not is_enter_pressed(): + self.core.break_realtime() + for _ in range(50000): + i = 0 + for ttl in ttl_chunk: + i += 1 + for _ in range(i): + ttl.pulse(1*us) + delay(1*us) + delay(10*us) + + def test_ttl_outs(self): + print("*** Testing TTL outputs.") + print("Outputs are tested in groups of 4. Touch each TTL connector") + print("with the oscilloscope probe tip, and check that the number of") + print("pulses corresponds to its number in the group.") + print("Press ENTER when done.") + + ttl_outs = list(self.ttl_outs) + for ttl_chunk in chunker(ttl_outs, 4): + print("Testing TTL outputs: {}.".format(", ".join(name for name, dev in ttl_chunk))) + self.test_ttl_out_chunk([dev for name, dev in ttl_chunk]) + + @kernel + def test_ttl_in(self, ttl_out, ttl_in): + n = 42 + self.core.break_realtime() + with parallel: + ttl_in.gate_rising(1*ms) + with sequential: + delay(50*us) + for _ in range(n): + ttl_out.pulse(2*us) + delay(2*us) + return ttl_in.count() == n + + def test_ttl_ins(self): + print("*** Testing TTL inputs.") + + ttl_out_name, ttl_out_dev = next(iter(self.ttl_outs)) + for ttl_in_name, ttl_in_dev in self.ttl_ins: + print("Connect {} to {}. Press ENTER when done." + .format(ttl_out_name, ttl_in_name)) + input() + if self.test_ttl_in(ttl_out_dev, ttl_in_dev): + print("PASSED") + else: + print("FAILED") + + def run(self): + print("****** Kasli system tester ******") + print("") + self.test_leds() + self.test_ttl_outs() + self.test_ttl_ins() From 72aef5799e0739a146b20ce12ff8c87ebfc25795 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 May 2018 22:55:28 +0800 Subject: [PATCH 0808/2457] kasli/ustc: use TTLOut --- artiq/gateware/targets/kasli.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index bdc2b283d..049babe32 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -750,7 +750,11 @@ class USTC(_StandaloneBase): for i in range(24): eem_offset, port = divmod(i, 8) pads = platform.request("eem{}".format(5 + eem_offset), port) - phy = ttl_serdes_7series.InOut_8X(pads.p, pads.n) + if i < 4: + cls = ttl_serdes_7series.InOut_8X + else: + cls = ttl_serdes_7series.Output_8X + phy = cls(pads.p, pads.n) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From bdfd993818eed5ca1dc95d7c2420ac2998c5c869 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 May 2018 23:18:03 +0800 Subject: [PATCH 0809/2457] kasli_tester: add Urukul support --- .../kasli_basic/repository/kasli_tester.py | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index 8b199bc93..c24d83e7e 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -30,6 +30,8 @@ class KasliTester(EnvExperiment): self.leds = dict() self.ttl_outs = dict() self.ttl_ins = dict() + self.urukul_cplds = dict() + self.urukuls = dict() ddb = self.get_device_db() for name, desc in ddb.items(): @@ -43,6 +45,10 @@ class KasliTester(EnvExperiment): self.ttl_outs[name] = dev elif (module, cls) == ("artiq.coredevice.ttl", "TTLInOut"): self.ttl_ins[name] = self.get_device(name) + elif (module, cls) == ("artiq.coredevice.urukul", "CPLD"): + self.urukul_cplds[name] = self.get_device(name) + elif (module, cls) == ("artiq.coredevice.ad9910", "AD9910"): + self.urukuls[name] = self.get_device(name) # Remove Urukul control signals from TTL outs (tested separately) ddb = self.get_device_db() @@ -61,6 +67,7 @@ class KasliTester(EnvExperiment): self.leds = sorted(self.leds.items(), key=lambda x: x[1].channel) self.ttl_outs = sorted(self.ttl_outs.items(), key=lambda x: x[1].channel) self.ttl_ins = sorted(self.ttl_ins.items(), key=lambda x: x[1].channel) + self.urukuls = sorted(self.urukuls.items(), key=lambda x: x[1].sw.channel) @kernel def test_led(self, led): @@ -102,8 +109,7 @@ class KasliTester(EnvExperiment): print("pulses corresponds to its number in the group.") print("Press ENTER when done.") - ttl_outs = list(self.ttl_outs) - for ttl_chunk in chunker(ttl_outs, 4): + for ttl_chunk in chunker(self.ttl_outs, 4): print("Testing TTL outputs: {}.".format(", ".join(name for name, dev in ttl_chunk))) self.test_ttl_out_chunk([dev for name, dev in ttl_chunk]) @@ -133,9 +139,39 @@ class KasliTester(EnvExperiment): else: print("FAILED") + @kernel + def init_urukul(self, cpld): + self.core.break_realtime() + cpld.init() + + @kernel + def setup_urukul(self, channel, frequency): + self.core.break_realtime() + channel.set(frequency*MHz) + channel.sw.on() + channel.set_att(6.) + + # We assume that RTIO channels for switches are grouped by card. + def test_urukuls(self): + print("*** Testing Urukul DDSes.") + print("Initializing CPLDs...") + for name, cpld in sorted(self.urukul_cplds.items(), key=lambda x: x[0]): + print(name + "...") + self.init_urukul(cpld) + print("...done") + print("Frequencies:") + for card_n, channels in enumerate(chunker(self.urukuls, 4)): + for channel_n, (channel_name, channel_dev) in enumerate(channels): + frequency = 10*(card_n + 1) + channel_n + print("{}\t{}MHz".format(channel_name, frequency)) + self.setup_urukul(channel_dev, frequency) + print("Press ENTER when done.") + input() + def run(self): print("****** Kasli system tester ******") print("") self.test_leds() self.test_ttl_outs() self.test_ttl_ins() + self.test_urukuls() From 3cbcb3bff6a48f6d6d71ba45f25acb48cb203135 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 May 2018 23:20:40 +0800 Subject: [PATCH 0810/2457] move mitll, sysu and ustc device_dbs to kasli_basic --- .../device_db_mitll.py} | 0 .../device_db_sysu.py} | 0 .../device_db_ustc.py} | 0 artiq/examples/kasli_mitll/repository/demo.py | 54 ------------ artiq/examples/kasli_sysu/repository/demo.py | 52 ------------ artiq/examples/kasli_ustc/repository/demo.py | 82 ------------------- 6 files changed, 188 deletions(-) rename artiq/examples/{kasli_mitll/device_db.py => kasli_basic/device_db_mitll.py} (100%) rename artiq/examples/{kasli_sysu/device_db.py => kasli_basic/device_db_sysu.py} (100%) rename artiq/examples/{kasli_ustc/device_db.py => kasli_basic/device_db_ustc.py} (100%) delete mode 100644 artiq/examples/kasli_mitll/repository/demo.py delete mode 100644 artiq/examples/kasli_sysu/repository/demo.py delete mode 100644 artiq/examples/kasli_ustc/repository/demo.py diff --git a/artiq/examples/kasli_mitll/device_db.py b/artiq/examples/kasli_basic/device_db_mitll.py similarity index 100% rename from artiq/examples/kasli_mitll/device_db.py rename to artiq/examples/kasli_basic/device_db_mitll.py diff --git a/artiq/examples/kasli_sysu/device_db.py b/artiq/examples/kasli_basic/device_db_sysu.py similarity index 100% rename from artiq/examples/kasli_sysu/device_db.py rename to artiq/examples/kasli_basic/device_db_sysu.py diff --git a/artiq/examples/kasli_ustc/device_db.py b/artiq/examples/kasli_basic/device_db_ustc.py similarity index 100% rename from artiq/examples/kasli_ustc/device_db.py rename to artiq/examples/kasli_basic/device_db_ustc.py diff --git a/artiq/examples/kasli_mitll/repository/demo.py b/artiq/examples/kasli_mitll/repository/demo.py deleted file mode 100644 index eafb6d4ea..000000000 --- a/artiq/examples/kasli_mitll/repository/demo.py +++ /dev/null @@ -1,54 +0,0 @@ -from artiq.experiment import * - - -class UrukulTest(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("urukul0_cpld") - self.setattr_device("urukul0_ch0") - self.setattr_device("urukul0_ch1") - self.setattr_device("urukul0_ch2") - self.setattr_device("urukul0_ch3") - self.setattr_device("led0") - self.setattr_device("led1") - self.ttl = self.get_device("ttl0") - - @kernel - def run(self): - self.core.reset() - self.ttl.output() - delay(1*us) - - self.urukul0_cpld.init() - self.urukul0_ch0.init() - self.urukul0_ch1.init() - self.urukul0_ch2.init() - self.urukul0_ch3.init() - - delay(1000*us) - self.urukul0_ch0.set(10*MHz) - self.urukul0_ch0.sw.on() - self.urukul0_ch0.set_att(10.) - - delay(1000*us) - self.urukul0_ch1.set(20*MHz, 0.5) - self.urukul0_ch1.sw.on() - self.urukul0_ch1.set_att(8.) - - delay(1000*us) - self.urukul0_ch2.set(30*MHz) - self.urukul0_ch2.sw.on() - self.urukul0_ch2.set_att(6.) - - delay(1000*us) - self.urukul0_ch3.set(40*MHz) - self.urukul0_ch3.sw.on() - self.urukul0_ch3.set_att(4.) - - while True: - with parallel: - self.ttl.pulse(100*ms) - self.urukul0_ch0.sw.pulse(100*ms) - delay(100*ms) - self.led0.pulse(100*ms) - self.led1.pulse(100*ms) diff --git a/artiq/examples/kasli_sysu/repository/demo.py b/artiq/examples/kasli_sysu/repository/demo.py deleted file mode 100644 index bdb3b9361..000000000 --- a/artiq/examples/kasli_sysu/repository/demo.py +++ /dev/null @@ -1,52 +0,0 @@ -from artiq.experiment import * - - -class UrukulTest(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("urukul0_cpld") - self.setattr_device("urukul0_ch0") - self.setattr_device("urukul0_ch1") - self.setattr_device("urukul0_ch2") - self.setattr_device("urukul0_ch3") - self.setattr_device("led0") - self.ttl = self.get_device("ttl16") - - @kernel - def run(self): - self.core.reset() - self.ttl.output() - delay(1*us) - - self.urukul0_cpld.init() - self.urukul0_ch0.init() - self.urukul0_ch1.init() - self.urukul0_ch2.init() - self.urukul0_ch3.init() - - delay(1000*us) - self.urukul0_ch0.set(10*MHz) - self.urukul0_ch0.sw.on() - self.urukul0_ch0.set_att(10.) - - delay(1000*us) - self.urukul0_ch1.set(20*MHz, 0.5) - self.urukul0_ch1.sw.on() - self.urukul0_ch1.set_att(8.) - - delay(1000*us) - self.urukul0_ch2.set(30*MHz) - self.urukul0_ch2.sw.on() - self.urukul0_ch2.set_att(6.) - - delay(1000*us) - self.urukul0_ch3.set(40*MHz) - self.urukul0_ch3.sw.on() - self.urukul0_ch3.set_att(4.) - - while True: - with parallel: - self.ttl.pulse(100*ms) - self.urukul0_ch0.sw.pulse(100*ms) - delay(100*ms) - self.led0.pulse(100*ms) diff --git a/artiq/examples/kasli_ustc/repository/demo.py b/artiq/examples/kasli_ustc/repository/demo.py deleted file mode 100644 index 169856a08..000000000 --- a/artiq/examples/kasli_ustc/repository/demo.py +++ /dev/null @@ -1,82 +0,0 @@ -from artiq.experiment import * - - -class UrukulTest(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("urukul0_cpld") - self.setattr_device("urukul0_ch0") - self.setattr_device("urukul0_ch1") - self.setattr_device("urukul0_ch2") - self.setattr_device("urukul0_ch3") - self.setattr_device("urukul1_cpld") - self.setattr_device("urukul1_ch0") - self.setattr_device("urukul1_ch1") - self.setattr_device("urukul1_ch2") - self.setattr_device("urukul1_ch3") - self.setattr_device("led0") - self.ttl = self.get_device("ttl16") - - @kernel - def run(self): - self.core.reset() - self.ttl.output() - delay(1*us) - - self.urukul0_cpld.init() - self.urukul0_ch0.init() - self.urukul0_ch1.init() - self.urukul0_ch2.init() - self.urukul0_ch3.init() - self.urukul1_cpld.init() - self.urukul1_ch0.init() - self.urukul1_ch1.init() - self.urukul1_ch2.init() - self.urukul1_ch3.init() - - delay(1000*us) - self.urukul0_ch0.set(10*MHz) - self.urukul0_ch0.sw.on() - self.urukul0_ch0.set_att(10.) - - delay(1000*us) - self.urukul0_ch1.set(20*MHz, 0.5) - self.urukul0_ch1.sw.on() - self.urukul0_ch1.set_att(8.) - - delay(1000*us) - self.urukul0_ch2.set(30*MHz) - self.urukul0_ch2.sw.on() - self.urukul0_ch2.set_att(6.) - - delay(1000*us) - self.urukul0_ch3.set(40*MHz) - self.urukul0_ch3.sw.on() - self.urukul0_ch3.set_att(4.) - - delay(1000*us) - self.urukul1_ch0.set(15*MHz) - self.urukul1_ch0.sw.on() - self.urukul1_ch0.set_att(10.) - - delay(1000*us) - self.urukul1_ch1.set(25*MHz, 0.5) - self.urukul1_ch1.sw.on() - self.urukul1_ch1.set_att(8.) - - delay(1000*us) - self.urukul1_ch2.set(35*MHz) - self.urukul1_ch2.sw.on() - self.urukul1_ch2.set_att(6.) - - delay(1000*us) - self.urukul1_ch3.set(45*MHz) - self.urukul1_ch3.sw.on() - self.urukul1_ch3.set_att(4.) - - while True: - with parallel: - self.ttl.pulse(100*ms) - self.urukul0_ch0.sw.pulse(100*ms) - delay(100*ms) - self.led0.pulse(100*ms) From f457b59985c2a0d5036b0c1ec6261eeb0ee33524 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 May 2018 23:30:52 +0800 Subject: [PATCH 0811/2457] kasli_tester: bail out when run from ARTIQ master --- artiq/examples/kasli_basic/repository/kasli_tester.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index c24d83e7e..4cad877f8 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -25,6 +25,11 @@ def is_enter_pressed() -> TBool: class KasliTester(EnvExperiment): def build(self): + # hack to detect artiq_run + if self.get_device("scheduler").__class__.__name__ != "DummyScheduler": + raise NotImplementedError( + "must be run with artiq_run to support keyboard interaction") + self.setattr_device("core") self.leds = dict() From f953bee79e307ffe99ef907af71d4d0fd9733e49 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 May 2018 23:48:29 +0800 Subject: [PATCH 0812/2457] kasli_test: add RF switch control --- .../kasli_basic/repository/kasli_tester.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index 4cad877f8..da449576f 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -156,14 +156,28 @@ class KasliTester(EnvExperiment): channel.sw.on() channel.set_att(6.) + @kernel + def rf_switch_wave(self, channels): + while not is_enter_pressed(): + self.core.break_realtime() + # do not fill the FIFOs too much to avoid long response times + t = now_mu() - self.core.seconds_to_mu(0.2) + while self.core.get_rtio_counter_mu() < t: + pass + for channel in channels: + channel.sw.pulse(100*ms) + delay(100*ms) + # We assume that RTIO channels for switches are grouped by card. def test_urukuls(self): print("*** Testing Urukul DDSes.") + print("Initializing CPLDs...") for name, cpld in sorted(self.urukul_cplds.items(), key=lambda x: x[0]): print(name + "...") self.init_urukul(cpld) print("...done") + print("Frequencies:") for card_n, channels in enumerate(chunker(self.urukuls, 4)): for channel_n, (channel_name, channel_dev) in enumerate(channels): @@ -173,6 +187,9 @@ class KasliTester(EnvExperiment): print("Press ENTER when done.") input() + print("Testing RF switch control. Press ENTER when done.") + self.rf_switch_wave([channel_dev for channel_name, channel_dev in self.urukuls]) + def run(self): print("****** Kasli system tester ******") print("") From 21a0f26cd1f140b2f23d21bbabc44e37fca040d7 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 19 May 2018 15:24:15 +0000 Subject: [PATCH 0813/2457] compiler: do not emit nonstandard !unconditionally* LLVM metadata. This metadata was added by an LLVM patch that was removed because it was unsound. --- artiq/compiler/transforms/llvm_ir_generator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 57d60b429..6dc76c592 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -731,7 +731,7 @@ class LLVMIRGenerator: llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)], inbounds=True) llouterenv = self.llbuilder.load(llptr) - llouterenv.set_metadata('unconditionally.invariant.load', self.empty_metadata) + llouterenv.set_metadata('invariant.load', self.empty_metadata) llouterenv.set_metadata('nonnull', self.empty_metadata) return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name) @@ -739,7 +739,7 @@ class LLVMIRGenerator: assert isinstance(load, ll.LoadInstr) and isinstance(load.type, ll.PointerType) pointee_size = load.type.pointee.get_abi_size(self.lldatalayout, context=self.llcontext) metadata = self.llmodule.add_metadata([ll.Constant(lli64, pointee_size)]) - load.set_metadata('unconditionally_dereferenceable', metadata) + load.set_metadata('dereferenceable', metadata) def process_GetLocal(self, insn): env = insn.environment() @@ -875,7 +875,7 @@ class LLVMIRGenerator: inbounds=True, name="ptr.{}".format(insn.name)) llvalue = self.llbuilder.load(llptr, name="val.{}".format(insn.name)) if types.is_instance(typ) and attr in typ.constant_attributes: - llvalue.set_metadata('unconditionally.invariant.load', self.empty_metadata) + llvalue.set_metadata('invariant.load', self.empty_metadata) if isinstance(llvalue.type, ll.PointerType): self.mark_dereferenceable(llvalue) return llvalue @@ -1118,7 +1118,7 @@ class LLVMIRGenerator: llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)], inbounds=True) llouterenv = self.llbuilder.load(llptr) - llouterenv.set_metadata('unconditionally.invariant.load', self.empty_metadata) + llouterenv.set_metadata('invariant.load', self.empty_metadata) llouterenv.set_metadata('nonnull', self.empty_metadata) return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name) else: From dc1c4ebf1d504995eff5063a0c119d944e3bdf03 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 19 May 2018 16:57:30 +0000 Subject: [PATCH 0814/2457] compiler: use ARTIQ_IR_NO_LOC variable to control IR dump output. Useful e.g. in tests or for running diff on irgen output. --- artiq/compiler/ir.py | 3 ++- artiq/compiler/targets.py | 5 ++++- artiq/compiler/testbench/irgen.py | 6 +++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/artiq/compiler/ir.py b/artiq/compiler/ir.py index 6ae9bdf76..3184a4a61 100644 --- a/artiq/compiler/ir.py +++ b/artiq/compiler/ir.py @@ -303,6 +303,7 @@ class BasicBlock(NamedValue): :ivar instructions: (list of :class:`Instruction`) """ + _dump_loc = True def __init__(self, instructions, name=""): super().__init__(TBasicBlock(), name) @@ -383,7 +384,7 @@ class BasicBlock(NamedValue): # Annotated instructions loc = None for insn in self.instructions: - if loc != insn.loc: + if self._dump_loc and loc != insn.loc: loc = insn.loc if loc is None: diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index ffdb7d994..853d6c3eb 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -1,5 +1,5 @@ import os, sys, tempfile, subprocess, io -from artiq.compiler import types +from artiq.compiler import types, ir from llvmlite_artiq import ir as ll, binding as llvm llvm.initialize() @@ -131,6 +131,9 @@ class Target: print("====== MODULE_SIGNATURE DUMP ======", file=sys.stderr) print(module, file=sys.stderr) + if os.getenv("ARTIQ_IR_NO_LOC") is not None: + ir.BasicBlock._dump_loc = False + type_printer = types.TypePrinter() _dump(os.getenv("ARTIQ_DUMP_IR"), "ARTIQ IR", ".txt", lambda: "\n".join(fn.as_entity(type_printer) for fn in module.artiq_ir)) diff --git a/artiq/compiler/testbench/irgen.py b/artiq/compiler/testbench/irgen.py index fa1608e12..275f11c94 100644 --- a/artiq/compiler/testbench/irgen.py +++ b/artiq/compiler/testbench/irgen.py @@ -1,8 +1,12 @@ -import sys, fileinput +import sys, os, fileinput from pythonparser import diagnostic +from .. import ir from ..module import Module, Source def main(): + if os.getenv("ARTIQ_IR_NO_LOC") is not None: + ir.BasicBlock._dump_loc = False + def process_diagnostic(diag): print("\n".join(diag.render())) if diag.level in ("fatal", "error"): From fd110e9848a784b3d64278dd7b72114eda1b7c7e Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 19 May 2018 16:57:47 +0000 Subject: [PATCH 0815/2457] compiler: sort predecessors in IR dump output. Makes diffs more useful. --- artiq/compiler/ir.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/compiler/ir.py b/artiq/compiler/ir.py index 3184a4a61..d54ce0518 100644 --- a/artiq/compiler/ir.py +++ b/artiq/compiler/ir.py @@ -379,7 +379,7 @@ class BasicBlock(NamedValue): lines = ["{}:".format(escape_name(self.name))] if self.function is not None: lines[0] += " ; predecessors: {}".format( - ", ".join([escape_name(pred.name) for pred in self.predecessors()])) + ", ".join(sorted([escape_name(pred.name) for pred in self.predecessors()]))) # Annotated instructions loc = None From 9b4ad8b5af447dd95d73a546a9050bffa6ef2aaf Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 19 May 2018 17:05:34 +0000 Subject: [PATCH 0816/2457] compiler: implement local variable demotion. --- artiq/compiler/module.py | 2 + artiq/compiler/transforms/__init__.py | 1 + artiq/compiler/transforms/local_demoter.py | 51 ++++++++++++++++++++++ artiq/test/lit/local_demotion/closure.py | 15 +++++++ artiq/test/lit/local_demotion/demotion.py | 13 ++++++ 5 files changed, 82 insertions(+) create mode 100644 artiq/compiler/transforms/local_demoter.py create mode 100644 artiq/test/lit/local_demotion/closure.py create mode 100644 artiq/test/lit/local_demotion/demotion.py diff --git a/artiq/compiler/module.py b/artiq/compiler/module.py index 052a176ac..8e7091b81 100644 --- a/artiq/compiler/module.py +++ b/artiq/compiler/module.py @@ -60,6 +60,7 @@ class Module: ref_period=ref_period) dead_code_eliminator = transforms.DeadCodeEliminator(engine=self.engine) local_access_validator = validators.LocalAccessValidator(engine=self.engine) + local_demoter = transforms.LocalDemoter() devirtualization = analyses.Devirtualization() interleaver = transforms.Interleaver(engine=self.engine) invariant_detection = analyses.InvariantDetection(engine=self.engine) @@ -77,6 +78,7 @@ class Module: dead_code_eliminator.process(self.artiq_ir) interleaver.process(self.artiq_ir) local_access_validator.process(self.artiq_ir) + local_demoter.process(self.artiq_ir) if remarks: invariant_detection.process(self.artiq_ir) diff --git a/artiq/compiler/transforms/__init__.py b/artiq/compiler/transforms/__init__.py index 305cf614e..ccaab7636 100644 --- a/artiq/compiler/transforms/__init__.py +++ b/artiq/compiler/transforms/__init__.py @@ -5,6 +5,7 @@ from .cast_monomorphizer import CastMonomorphizer from .iodelay_estimator import IODelayEstimator from .artiq_ir_generator import ARTIQIRGenerator from .dead_code_eliminator import DeadCodeEliminator +from .local_demoter import LocalDemoter from .llvm_ir_generator import LLVMIRGenerator from .interleaver import Interleaver from .typedtree_printer import TypedtreePrinter diff --git a/artiq/compiler/transforms/local_demoter.py b/artiq/compiler/transforms/local_demoter.py new file mode 100644 index 000000000..4701e7a7c --- /dev/null +++ b/artiq/compiler/transforms/local_demoter.py @@ -0,0 +1,51 @@ +""" +:class:`LocalDemoter` is a constant propagation transform: +it replaces reads of any local variable with only one write +in a function without closures with the value that was written. + +:class:`LocalAccessValidator` must be run before this transform +to ensure that the transformation it performs is sound. +""" + +from collections import defaultdict +from .. import ir + +class LocalDemoter: + def process(self, functions): + for func in functions: + self.process_function(func) + + def process_function(self, func): + env_safe = {} + env_gets = defaultdict(lambda: set()) + env_sets = defaultdict(lambda: set()) + + for insn in func.instructions(): + if isinstance(insn, (ir.GetLocal, ir.SetLocal)): + if "$" in insn.var_name: + continue + + env = insn.environment() + + if env not in env_safe: + for use in env.uses: + if not isinstance(use, (ir.GetLocal, ir.SetLocal)): + env_safe[env] = False + break + else: + env_safe[env] = True + + if not env_safe[env]: + continue + + if isinstance(insn, ir.SetLocal): + env_sets[(env, insn.var_name)].add(insn) + else: + env_gets[(env, insn.var_name)].add(insn) + + for (env, var_name) in env_sets: + if len(env_sets[(env, var_name)]) == 1: + set_insn = next(iter(env_sets[(env, var_name)])) + for get_insn in env_gets[(env, var_name)]: + get_insn.replace_all_uses_with(set_insn.value()) + get_insn.erase() diff --git a/artiq/test/lit/local_demotion/closure.py b/artiq/test/lit/local_demotion/closure.py new file mode 100644 index 000000000..5786eb20e --- /dev/null +++ b/artiq/test/lit/local_demotion/closure.py @@ -0,0 +1,15 @@ +# RUN: %python -m artiq.compiler.testbench.irgen %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +def x(y): pass + +# CHECK-L: NoneType input.a(environment(...) %ARG.ENV, NoneType %ARG.self) { +# CHECK-L: setlocal('self') %ENV, NoneType %ARG.self +# CHECK-NOT-L: call (y:NoneType)->NoneType %LOC.x, NoneType %ARG.self + +def a(self): + def b(): + pass + x(self) + +a(None) diff --git a/artiq/test/lit/local_demotion/demotion.py b/artiq/test/lit/local_demotion/demotion.py new file mode 100644 index 000000000..c9b4ed0c5 --- /dev/null +++ b/artiq/test/lit/local_demotion/demotion.py @@ -0,0 +1,13 @@ +# RUN: %python -m artiq.compiler.testbench.irgen %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +def x(y): pass + +# CHECK-L: NoneType input.a(environment(...) %ARG.ENV, NoneType %ARG.self) { +# CHECK-NOT-L: getlocal('self') %ENV +# CHECK-L: call (y:NoneType)->NoneType %LOC.x, NoneType %ARG.self + +def a(self): + x(self) + +a(None) From 8513f0b0d473803910e57df4ba9e5cc0516a3871 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 May 2018 15:35:00 +0800 Subject: [PATCH 0817/2457] minor cleanup --- artiq/coredevice/sampler.py | 1 - artiq/examples/kasli_basic/device_db_mitll.py | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/sampler.py b/artiq/coredevice/sampler.py index 7ede3a21f..8cf80f071 100644 --- a/artiq/coredevice/sampler.py +++ b/artiq/coredevice/sampler.py @@ -1,4 +1,3 @@ - from artiq.language.core import kernel, delay, portable from artiq.language.units import ns diff --git a/artiq/examples/kasli_basic/device_db_mitll.py b/artiq/examples/kasli_basic/device_db_mitll.py index 45f13457b..e7ae94ac4 100644 --- a/artiq/examples/kasli_basic/device_db_mitll.py +++ b/artiq/examples/kasli_basic/device_db_mitll.py @@ -115,19 +115,19 @@ for i in range(2): "module": "artiq.coredevice.spi2", "class": "SPIMaster", "arguments": {"channel": 14+3*i+0} - }, + } device_db["ttl_zotino{}_ldac".format(i)] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 14+3*i+1} - }, + } device_db["ttl_zotino{}_clr".format(i)] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 14+3*i+2} - }, + } device_db["zotino{}".format(i)] = { "type": "local", "module": "artiq.coredevice.zotino", From 2e6b81d59a1210ff6e533df0d39d989fcf0d0712 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 May 2018 15:35:29 +0800 Subject: [PATCH 0818/2457] kasli_tester: reset core device --- artiq/examples/kasli_basic/repository/kasli_tester.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index da449576f..2b6842a11 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -193,6 +193,7 @@ class KasliTester(EnvExperiment): def run(self): print("****** Kasli system tester ******") print("") + self.core.reset() self.test_leds() self.test_ttl_outs() self.test_ttl_ins() From 4e5fe672e7b35e8765ec00fc3773621d597b0d6d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 May 2018 17:43:00 +0800 Subject: [PATCH 0819/2457] kasli: add tester target --- .../examples/kasli_basic/device_db_tester.py | 187 ++++++++++++++++++ artiq/frontend/artiq_flash.py | 2 +- artiq/gateware/targets/kasli.py | 99 +++++++++- 3 files changed, 286 insertions(+), 2 deletions(-) create mode 100644 artiq/examples/kasli_basic/device_db_tester.py diff --git a/artiq/examples/kasli_basic/device_db_tester.py b/artiq/examples/kasli_basic/device_db_tester.py new file mode 100644 index 000000000..ba72ee99b --- /dev/null +++ b/artiq/examples/kasli_basic/device_db_tester.py @@ -0,0 +1,187 @@ +core_addr = "kasli-2.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + + +for i in range(8): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": i}, + } + + +device_db.update( + spi_urukul0={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 8} + }, + ttl_urukul0_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 9} + }, + ttl_urukul0_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 10} + }, + ttl_urukul0_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 11} + }, + ttl_urukul0_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 12} + }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 13} + }, + urukul0_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul0_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } + + +device_db["spi_sampler0_adc"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 14} +} +device_db["spi_sampler0_pgia"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 15} +} +device_db["spi_sampler0_cnv"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 16}, +} +device_db["sampler0"] = { + "type": "local", + "module": "artiq.coredevice.sampler", + "class": "Sampler", + "arguments": { + "spi_adc_device": "spi_sampler0_adc", + "spi_pgia_device": "spi_sampler0_pgia", + "cnv_device": "spi_sampler0_cnv" + } +} + + +device_db["spi_zotino0"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 17} +} +device_db["ttl_zotino0_ldac"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 18} +} +device_db["ttl_zotino0_clr"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 19} +} +device_db["zotino0"] = { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino0", + "ldac_device": "ttl_zotino0_ldac", + "clr_device": "ttl_zotino0_clr" + } +} + +device_db.update( + led0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 20} + }, + led1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 21} + }, +) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 7058c287a..4f121e92e 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -269,7 +269,7 @@ def main(): "kasli": { "programmer": partial(ProgrammerXC7, board="kasli", proxy="bscan_spi_xc7a100t.bit"), "variants": ["opticlock", "suservo", "sysu", "mitll", "ustc", - "master", "satellite"], + "tester", "master", "satellite"], "gateware": ("spi0", 0x000000), "bootloader": ("spi0", 0x400000), "storage": ("spi0", 0x440000), diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 049babe32..7c03cd5a1 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -787,6 +787,101 @@ class USTC(_StandaloneBase): self.add_rtio(rtio_channels) +class Tester(_StandaloneBase): + """ + Configuration for CI tests. Contains the maximum number of different EEMs. + """ + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + # self.config["SI5324_EXT_REF"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + + platform = self.platform + platform.add_extension(_urukul("eem1", "eem0")) + platform.add_extension(_sampler("eem3", "eem2")) + platform.add_extension(_zotino("eem4")) + platform.add_extension(_dio("eem5")) + + try: + # EEM clock fan-out from Si5324, not MMCX, only Kasli/v1.0 + self.comb += platform.request("clk_sel").eq(1) + except ConstraintError: + pass + + # EEM5: TTL + rtio_channels = [] + for i in range(8): + pads = platform.request("eem5", i) + if i < 4: + cls = ttl_serdes_7series.InOut_8X + else: + cls = ttl_serdes_7series.Output_8X + phy = cls(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + # EEM0, EEM1: Urukul + phy = spi2.SPIMaster(self.platform.request("eem1_spi_p"), + self.platform.request("eem1_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + pads = platform.request("eem1_dds_reset") + self.specials += DifferentialOutput(0, pads.p, pads.n) + + for signal in "io_update sw0 sw1 sw2 sw3".split(): + pads = platform.request("eem1_{}".format(signal)) + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + # EEM2, EEM3: Sampler + phy = spi2.SPIMaster(self.platform.request("eem3_adc_spi_p"), + self.platform.request("eem3_adc_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + phy = spi2.SPIMaster(self.platform.request("eem3_pgia_spi_p"), + self.platform.request("eem3_pgia_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + pads = platform.request("eem3_cnv") + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + sdr = platform.request("eem3_sdr") + self.specials += DifferentialOutput(1, sdr.p, sdr.n) + + # EEM4: Zotino + phy = spi2.SPIMaster(self.platform.request("eem4_spi_p"), + self.platform.request("eem4_spi_n")) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + for signal in "ldac_n clr_n".split(): + pads = platform.request("eem4_{}".format(signal)) + phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + for i in (1, 2): + sfp_ctl = platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + print(len(rtio_channels)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) + rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(rtio_channels) + + class _RTIOClockMultiplier(Module): def __init__(self, rtio_clk_freq): self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) @@ -1098,7 +1193,7 @@ def main(): parser.set_defaults(output_dir="artiq_kasli") parser.add_argument("-V", "--variant", default="opticlock", help="variant: opticlock/suservo/sysu/mitll/ustc/" - "master/satellite " + "tester/master/satellite " "(default: %(default)s)") args = parser.parse_args() @@ -1113,6 +1208,8 @@ def main(): cls = MITLL elif variant == "ustc": cls = USTC + elif variant == "tester": + cls = Tester elif variant == "master": cls = Master elif variant == "satellite": From 4e863b32a170eee81512ca28cb52e0b0fe83511b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 21 May 2018 18:28:19 +0200 Subject: [PATCH 0820/2457] coredevice: configurable initial backing state Several core device drivers maintain a copy of some device state. Since this copy is not transferred between experiments this backing state can be different from device state when a new experiment is started. This commit adds support for injecting initial backing state into experiments via the device database and sets initial backing state where known. ad53xx (zotino): spi2 xfer_duration novogorny: pgia gains sampler: pgia gains, spi2 pgia and adc xfer_duration suservo: pgia gains, spi2 pgia xfer_duration urukul: cpld cfg (partial: rf_sw), attenuator register spi2: div/length for xfer_duration close #1003 --- artiq/coredevice/ad53xx.py | 4 +++- artiq/coredevice/novogorny.py | 7 +++++-- artiq/coredevice/sampler.py | 9 +++++++-- artiq/coredevice/spi2.py | 30 +++++++++++++++++++++++++++--- artiq/coredevice/suservo.py | 8 ++++++-- artiq/coredevice/urukul.py | 33 ++++++++++++++++++++++++++------- 6 files changed, 74 insertions(+), 17 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index dfc347fbc..0b10b3388 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -110,7 +110,8 @@ class AD53xx: valid) :param vref: DAC reference voltage (default: 5.) :param offset_dacs: Initial register value for the two offset DACs, device - dependent and must be set correctly for correct voltage to mu conversions + dependent and must be set correctly for correct voltage to mu conversions. + Knowledge of his state is not transferred between experiments. (default: 8192) :param core_device: Core device name (default: "core") """ @@ -121,6 +122,7 @@ class AD53xx: chip_select=1, div_write=4, div_read=16, vref=5., offset_dacs=8192, core="core"): self.bus = dmgr.get(spi_device) + self.bus.update_xfer_duration_mu(div_write, 24) if ldac_device is None: self.ldac = _DummyTTL() else: diff --git a/artiq/coredevice/novogorny.py b/artiq/coredevice/novogorny.py index f92b00e25..49bb9a22c 100644 --- a/artiq/coredevice/novogorny.py +++ b/artiq/coredevice/novogorny.py @@ -69,17 +69,20 @@ class Novogorny: :param spi_device: SPI bus device name :param cnv_device: CNV RTIO TTLOut channel name :param div: SPI clock divider (default: 8) + :param gains: Initial value for PGIA gains shift register + (default: 0x0000). Knowledge of this state is not transferred + between experiments. :param core_device: Core device name """ kernel_invariants = {"bus", "core", "cnv", "div", "v_ref"} - def __init__(self, dmgr, spi_device, cnv_device, div=8, + def __init__(self, dmgr, spi_device, cnv_device, div=8, gains=0x0000, core_device="core"): self.bus = dmgr.get(spi_device) self.core = dmgr.get(core_device) self.cnv = dmgr.get(cnv_device) self.div = div - self.gains = 0x0000 + self.gains = gains self.v_ref = 5. # 5 Volt reference @kernel diff --git a/artiq/coredevice/sampler.py b/artiq/coredevice/sampler.py index 8cf80f071..8679ad93c 100644 --- a/artiq/coredevice/sampler.py +++ b/artiq/coredevice/sampler.py @@ -45,18 +45,23 @@ class Sampler: :param spi_pgia_device: PGIA SPI bus device name :param cnv_device: CNV RTIO TTLOut channel name :param div: SPI clock divider (default: 8) + :param gains: Initial value for PGIA gains shift register + (default: 0x0000). Knowledge of this state is not transferred + between experiments. :param core_device: Core device name """ kernel_invariants = {"bus_adc", "bus_pgia", "core", "cnv", "div"} def __init__(self, dmgr, spi_adc_device, spi_pgia_device, cnv_device, - div=8, core_device="core"): + div=8, gains=0x0000, core_device="core"): self.bus_adc = dmgr.get(spi_adc_device) + self.bus_adc.update_xfer_duration_mu(div, 32) self.bus_pgia = dmgr.get(spi_pgia_device) + self.bus_pgia.update_xfer_duration_mu(div, 16) self.core = dmgr.get(core_device) self.cnv = dmgr.get(cnv_device) self.div = div - self.gains = 0x0000 + self.gains = gains @kernel def init(self): diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index d64f1ad17..c8749b082 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -57,16 +57,20 @@ class SPIMaster: register. :param channel: RTIO channel number of the SPI bus to control. + :param div: Initial CLK divider, see also: :meth:`update_xfer_duration_mu` + :param length: Initial transfer length, see also: + :meth:`update_xfer_duration_mu` + :param core_device: Core device name """ kernel_invariants = {"core", "ref_period_mu", "channel"} - def __init__(self, dmgr, channel, core_device="core"): + def __init__(self, dmgr, channel, div=0, length=0, core_device="core"): self.core = dmgr.get(core_device) self.ref_period_mu = self.core.seconds_to_mu( self.core.coarse_ref_period) assert self.ref_period_mu == self.core.ref_multiplier self.channel = channel - self.xfer_duration_mu = 2*self.ref_period_mu + self.update_xfer_duration_mu(div, length) @portable def frequency_to_div(self, f): @@ -162,11 +166,31 @@ class SPIMaster: raise ValueError("Invalid SPI transfer length") if div > 257 or div < 2: raise ValueError("Invalid SPI clock divider") - self.xfer_duration_mu = ((length + 1)*div + 1)*self.ref_period_mu rtio_output(now_mu(), self.channel, SPI_CONFIG_ADDR, flags | ((length - 1) << 8) | ((div - 2) << 16) | (cs << 24)) + self.update_xfer_duration_mu(div, length) delay_mu(self.ref_period_mu) + @portable + def update_xfer_duration_mu(self, div, length): + """Calculate and set the transfer duration. + + This method updates the SPI transfer duration which is used + in :meth:`write` to advance the timeline. + + Use this method (and avoid having to call :meth:`set_config_mu`) + when the divider and transfer length have been configured + (using :meth:`set_config` or :meth:`set_config_mu`) by previous + experiments and are known. + + This method is portable and can also be called from e.g. + ``__init__``. + + :param div: SPI clock divider (see: :meth:`set_config_mu`) + :param length: SPI transfer length (see: :meth:`set_config_mu`) + """ + self.xfer_duration_mu = ((length + 1)*div + 1)*self.ref_period_mu + @kernel def write(self, data): """Write SPI data to shift register register and start transfer. diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 5bd4860c1..20ca966cc 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -26,6 +26,9 @@ class SUServo: Urukul :param dds1_device: Name of the AD9910 device for the DDS on the second Urukul + :param gains: Initial value for PGIA gains shift register + (default: 0x0000). Knowledge of this state is not transferred + between experiments. :param core_device: Core device name """ kernel_invariants = {"channel", "core", "pgia", "cpld0", "cpld1", @@ -34,16 +37,17 @@ class SUServo: def __init__(self, dmgr, channel, pgia_device, cpld0_device, cpld1_device, dds0_device, dds1_device, - core_device="core"): + gains=0x0000, core_device="core"): self.core = dmgr.get(core_device) self.pgia = dmgr.get(pgia_device) + self.pgia.update_xfer_duration_mu(div=4, length=16) self.dds0 = dmgr.get(dds0_device) self.dds1 = dmgr.get(dds1_device) self.cpld0 = dmgr.get(cpld0_device) self.cpld1 = dmgr.get(cpld1_device) self.channel = channel - self.gains = 0x0000 + self.gains = gains self.ref_period_mu = self.core.seconds_to_mu( self.core.coarse_ref_period) assert self.ref_period_mu == self.core.ref_multiplier diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 59dcceb5a..f3d34b93f 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -119,14 +119,18 @@ class CPLD: MMCX or ob-board XO clock. 1 corresponds to the front panel SMA. :param sync_sel: SYNC clock selection. 0 corresponds to SYNC clock over EEM from FPGA. 1 corresponds to SYNC clock from DDS0. + :param rf_sw: Initial CPLD RF switch register setting (default: 0x0). + Knowledge of this state is not transferred between experiments. + :param att: Initial attenuator setting shift register (default: + 0x00000000). See also: :meth:`set_all_att_mu`. Knowledge of this state + is not transferred between experiments. :param core_device: Core device name """ kernel_invariants = {"refclk", "bus", "core", "io_update"} def __init__(self, dmgr, spi_device, io_update_device=None, - dds_reset_device=None, - sync_sel=0, clk_sel=0, - refclk=125e6, core_device="core"): + dds_reset_device=None, sync_sel=0, clk_sel=0, rf_sw=0, + refclk=125e6, att=0x00000000, core_device="core"): self.core = dmgr.get(core_device) self.refclk = refclk @@ -139,10 +143,10 @@ class CPLD: if dds_reset_device is not None: self.dds_reset = dmgr.get(dds_reset_device) - self.cfg_reg = urukul_cfg(rf_sw=0, led=0, profile=0, + self.cfg_reg = urukul_cfg(rf_sw=rf_sw, led=0, profile=0, io_update=0, mask_nu=0, clk_sel=clk_sel, sync_sel=sync_sel, rst=0, io_rst=0) - self.att_reg = 0 + self.att_reg = att @kernel def cfg_write(self, cfg): @@ -226,16 +230,28 @@ class CPLD: def set_att_mu(self, channel, att): """Set digital step attenuator in machine units. + This method will write the attenuator settings of all four channels. + :param channel: Attenuator channel (0-3). :param att: Digital attenuation setting: 255 minimum attenuation, 0 maximum attenuation (31.5 dB) """ a = self.att_reg & ~(0xff << (channel * 8)) a |= att << (channel * 8) + self.set_all_att_mu(a) + + @kernel + def set_all_att_mu(self, att_reg): + """Set all four digital step attenuators (in machine units). + + .. seealso:: :meth:`set_att_mu` + + :param att_reg: Attenuator setting string (32 bit) + """ self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32, SPIT_ATT_WR, CS_ATT) - self.bus.write(a) - self.att_reg = a + self.bus.write(att_reg) + self.att_reg = att_reg @kernel def set_att(self, channel, att): @@ -251,6 +267,9 @@ class CPLD: def get_att_mu(self): """Return the digital step attenuator settings in machine units. + This method will also (as a side effect) write the attenuator + settings of all four channels. + :return: 32 bit attenuator settings """ self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 32, From 9a86dfe70d782c0b5f45b95269353e168bfd14e0 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 22 May 2018 17:36:02 +0000 Subject: [PATCH 0821/2457] units: add mHz --- artiq/language/units.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/language/units.py b/artiq/language/units.py index d57fd860b..13f6f1535 100644 --- a/artiq/language/units.py +++ b/artiq/language/units.py @@ -15,7 +15,7 @@ def _register_unit(unit, prefixes): _register_unit("s", "pnum_") -_register_unit("Hz", "_kMG") +_register_unit("Hz", "m_kMG") _register_unit("dB", "_") _register_unit("V", "um_k") _register_unit("A", "um_") From fcd12e34728a94f1a48af591990a029e8947b9e5 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 22 May 2018 17:36:41 +0000 Subject: [PATCH 0822/2457] suservo: work around #1007 --- artiq/examples/kasli_suservo/repository/suservo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/kasli_suservo/repository/suservo.py b/artiq/examples/kasli_suservo/repository/suservo.py index 900e4e9ea..b6def6286 100644 --- a/artiq/examples/kasli_suservo/repository/suservo.py +++ b/artiq/examples/kasli_suservo/repository/suservo.py @@ -42,7 +42,7 @@ class SUServo(EnvExperiment): assert self.suservo0.get_status() & 0xff == 2 # set up profile 0 on channel 0: - delay(100*us) + delay(120*us) self.suservo0_ch0.set_y( profile=0, y=0. # clear integrator From ce3c8fcd3e7b3d604d4bc56ce882f557a39917dd Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 22 May 2018 18:14:06 +0000 Subject: [PATCH 0823/2457] compiler: add source location to SSA arguments. Fixes #1006. --- artiq/compiler/ir.py | 6 ++++++ artiq/compiler/transforms/artiq_ir_generator.py | 3 +++ 2 files changed, 9 insertions(+) diff --git a/artiq/compiler/ir.py b/artiq/compiler/ir.py index d54ce0518..c20359962 100644 --- a/artiq/compiler/ir.py +++ b/artiq/compiler/ir.py @@ -410,7 +410,13 @@ class BasicBlock(NamedValue): class Argument(NamedValue): """ A function argument. + + :ivar loc: (:class:`pythonparser.source.Range` or None) + source location """ + def __init__(self, typ, name): + super().__init__(typ, name) + self.loc = None def as_entity(self, type_printer): return self.as_operand(type_printer) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index df274b794..970803454 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -268,6 +268,9 @@ class ARTIQIRGenerator(algorithm.Visitor): self.current_args[arg_name] = arg optargs.append(arg) + for (arg, arg_node) in zip(args + optargs, node.args.args): + arg.loc = arg_node.loc + func = ir.Function(typ, ".".join(self.name), [env_arg] + args + optargs, loc=node.lambda_loc if is_lambda else node.keyword_loc) func.is_internal = is_internal From 0c6f6180560c9e51e1098107afe21c7070e8365d Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 22 May 2018 18:56:04 +0000 Subject: [PATCH 0824/2457] manual: update to reflect the new artiq_coremgmt tool. --- doc/manual/utilities.rst | 54 +++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/doc/manual/utilities.rst b/doc/manual/utilities.rst index 1a049b94f..bd5ac9b50 100644 --- a/doc/manual/utilities.rst +++ b/doc/manual/utilities.rst @@ -106,62 +106,66 @@ Flashing/Loading tool .. _core-device-configuration-tool: -Core device configuration tool ------------------------------- +Core device management tool +--------------------------- -The artiq_coreconfig utility gives remote access to the :ref:`core-device-flash-storage`. +The artiq_coremgmt utility gives remote access to the core device logs, the :ref:`core-device-flash-storage`, and other management functions. -To use this tool, you need to specify a ``device_db.py`` device database file which contains a ``comm`` device (an example is provided in ``examples/master/device_db.py``). This tells the tool how to connect to the core device and with which parameters (e.g. IP address, TCP port). When not specified, the artiq_coreconfig utility will assume that there is a file named ``device_db.py`` in the current directory. +To use this tool, you need to specify a ``device_db.py`` device database file which contains a ``comm`` device (an example is provided in ``examples/master/device_db.py``). This tells the tool how to connect to the core device and with which parameters (e.g. IP address, TCP port). When not specified, the artiq_coremgmt utility will assume that there is a file named ``device_db.py`` in the current directory. + +To read core device logs:: + + $ artiq_coremgmt log + +To set core device log level and UART log level (possible levels are ``DEBUG``, ``INFO``, ``WARN`` and ``ERROR``):: + + $ artiq_coremgmt log set_level LEVEL + $ artiq_coremgmt log set_uart_level LEVEL + +Note that enabling the ``DEBUG`` log level results in small core device slowdown, and printing large amounts of log messages to the UART results in significant core device slowdown. To read the record whose key is ``mac``:: - $ artiq_coreconfig read mac + $ artiq_coremgmt config read mac To write the value ``test_value`` in the key ``my_key``:: - $ artiq_coreconfig write -s my_key test_value - $ artiq_coreconfig read my_key + $ artiq_coremgmt config write -s my_key test_value + $ artiq_coremgmt config read my_key b'test_value' You can also write entire files in a record using the ``-f`` parameter. This is useful for instance to write the startup and idle kernels in the flash storage:: - $ artiq_coreconfig write -f idle_kernel idle.elf - $ artiq_coreconfig read idle_kernel | head -c9 + $ artiq_coremgmt config write -f idle_kernel idle.elf + $ artiq_coremgmt config read idle_kernel | head -c9 b'\x7fELF You can write several records at once:: - $ artiq_coreconfig write -s key1 value1 -f key2 filename -s key3 value3 + $ artiq_coremgmt config write -s key1 value1 -f key2 filename -s key3 value3 To remove the previously written key ``my_key``:: - $ artiq_coreconfig delete my_key + $ artiq_coremgmt config delete my_key You can remove several keys at once:: - $ artiq_coreconfig delete key1 key2 + $ artiq_coremgmt config delete key1 key2 To erase the entire flash storage area:: - $ artiq_coreconfig erase + $ artiq_coremgmt config erase You do not need to remove a record in order to change its value, just overwrite it:: - $ artiq_coreconfig write -s my_key some_value - $ artiq_coreconfig write -s my_key some_other_value - $ artiq_coreconfig read my_key + $ artiq_coremgmt config write -s my_key some_value + $ artiq_coremgmt config write -s my_key some_other_value + $ artiq_coremgmt config read my_key b'some_other_value' .. argparse:: - :ref: artiq.frontend.artiq_coreconfig.get_argparser - :prog: artiq_coreconfig - -Core device log download tool ------------------------------ - -.. argparse:: - :ref: artiq.frontend.artiq_corelog.get_argparser - :prog: artiq_corelog + :ref: artiq.frontend.artiq_coremgmt.get_argparser + :prog: artiq_coremgmt .. _core-device-rtio-analyzer-tool: From b55ce66a1b89ac347bdf5ebd38b744494a5c10d6 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 22 May 2018 21:31:34 +0000 Subject: [PATCH 0825/2457] Reinstate accidentally removed aqctl_corelog. Closes #1008. --- artiq/frontend/aqctl_corelog.py | 81 +++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100755 artiq/frontend/aqctl_corelog.py diff --git a/artiq/frontend/aqctl_corelog.py b/artiq/frontend/aqctl_corelog.py new file mode 100755 index 000000000..7cee0b974 --- /dev/null +++ b/artiq/frontend/aqctl_corelog.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 + +import argparse +import asyncio +import struct +import logging +import re + +from artiq.tools import * +from artiq.protocols.pc_rpc import Server +from artiq.protocols.logging import log_with_name +from artiq.coredevice.comm_mgmt import Request, Reply + + +def get_argparser(): + parser = argparse.ArgumentParser( + description="ARTIQ controller for core device logs") + simple_network_args(parser, 1068) + parser.add_argument("core_addr", + help="hostname or IP address of the core device") + return parser + + +class PingTarget: + def ping(self): + return True + + +async def get_logs(host): + reader, writer = await asyncio.open_connection(host, 1380) + writer.write(b"ARTIQ management\n") + writer.write(struct.pack("B", Request.PullLog.value)) + await writer.drain() + + while True: + length, = struct.unpack(">l", await reader.readexactly(4)) + log = await reader.readexactly(length) + + for line in log.decode("utf-8").splitlines(): + m = re.match(r"^\[.+?\] (TRACE|DEBUG| INFO| WARN|ERROR)\((.+?)\): (.+)$", line) + levelname = m.group(1) + if levelname == 'TRACE': + level = logging.TRACE + elif levelname == 'DEBUG': + level = logging.DEBUG + elif levelname == ' INFO': + level = logging.INFO + elif levelname == ' WARN': + level = logging.WARN + elif levelname == 'ERROR': + level = logging.ERROR + name = 'firmware.' + m.group(2).replace('::', '.') + text = m.group(3) + log_with_name(name, level, text) + + +def main(): + args = get_argparser().parse_args() + + loop = asyncio.get_event_loop() + try: + get_logs_task = asyncio.ensure_future(get_logs(args.core_addr)) + try: + server = Server({"corelog": PingTarget()}, None, True) + loop.run_until_complete(server.start(bind_address_from_args(args), args.port)) + try: + multiline_log_config(logging.TRACE) + loop.run_until_complete(server.wait_terminate()) + finally: + loop.run_until_complete(server.stop()) + finally: + get_logs_task.cancel() + try: + loop.run_until_complete(get_logs_task) + except asyncio.CancelledError: + pass + finally: + loop.close() + +if __name__ == "__main__": + main() From dfb4a437f5ff985d182ec43204a5dbeeb71dfb04 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 22 May 2018 21:32:00 +0000 Subject: [PATCH 0826/2457] manual: mention TRACE log level. --- doc/manual/utilities.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/utilities.rst b/doc/manual/utilities.rst index bd5ac9b50..595756ec3 100644 --- a/doc/manual/utilities.rst +++ b/doc/manual/utilities.rst @@ -117,12 +117,12 @@ To read core device logs:: $ artiq_coremgmt log -To set core device log level and UART log level (possible levels are ``DEBUG``, ``INFO``, ``WARN`` and ``ERROR``):: +To set core device log level and UART log level (possible levels are ``TRACE``, ``DEBUG``, ``INFO``, ``WARN`` and ``ERROR``):: $ artiq_coremgmt log set_level LEVEL $ artiq_coremgmt log set_uart_level LEVEL -Note that enabling the ``DEBUG`` log level results in small core device slowdown, and printing large amounts of log messages to the UART results in significant core device slowdown. +Note that enabling the ``TRACE`` log level results in small core device slowdown, and printing large amounts of log messages to the UART results in significant core device slowdown. To read the record whose key is ``mac``:: From 7aacc04f0ca7f5d7eaf0a2ad569599a76a7abd2d Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 22 May 2018 21:33:35 +0000 Subject: [PATCH 0827/2457] language: scan functions are not supported on core device. Closes #1009. --- artiq/language/scan.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/artiq/language/scan.py b/artiq/language/scan.py index 8c38ce63c..3df898ad0 100644 --- a/artiq/language/scan.py +++ b/artiq/language/scan.py @@ -42,12 +42,10 @@ class NoScan(ScanObject): self.value = value self.repetitions = repetitions - @portable def _gen(self): for i in range(self.repetitions): yield self.value - @portable def __iter__(self): return self._gen() @@ -81,7 +79,6 @@ class RangeScan(ScanObject): rng = random.Random(seed) random.shuffle(self.sequence, rng.random) - @portable def __iter__(self): return iter(self.sequence) @@ -101,7 +98,6 @@ class ExplicitScan(ScanObject): def __init__(self, sequence): self.sequence = sequence - @portable def __iter__(self): return iter(self.sequence) From 9715f774ac639b4cad8e62adc781800ba65c1dde Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 22 May 2018 22:12:25 +0000 Subject: [PATCH 0828/2457] artiq_influxdb: controller (add ping()) --- artiq/frontend/artiq_influxdb.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/frontend/artiq_influxdb.py b/artiq/frontend/artiq_influxdb.py index ca9c3f343..d13aca46a 100755 --- a/artiq/frontend/artiq_influxdb.py +++ b/artiq/frontend/artiq_influxdb.py @@ -208,6 +208,9 @@ class Filter: """Show existing patterns.""" return self.patterns + def ping(self): + return True + def main(): args = get_argparser().parse_args() From fa3b48737b2cb01216c6d9ba624a9c3d1d1aa052 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 24 May 2018 09:23:00 +0200 Subject: [PATCH 0829/2457] firmware/hmc830: Added magic word to HMC830 init sequence (from gkasprow & marmeladapk) --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 7ef32a317..8685d46bd 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -30,7 +30,7 @@ mod clock_mux { mod hmc830 { use board_misoc::{csr, clock}; - const HMC830_WRITES: [(u8, u32); 16] = [ + const HMC830_WRITES: [(u8, u32); 17] = [ (0x0, 0x20), (0x1, 0x2), (0x2, 0x2), // r_divider @@ -38,6 +38,7 @@ mod hmc830 { (0x5, 0x60a0), (0x5, 0xe110), (0x5, 0x2818), + (0x5, 0xf88), (0x5, 0x0), (0x6, 0x303ca), (0x7, 0x14d), From 19e52808245ead848c02067e1ea4fd5aa434d91c Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 24 May 2018 09:34:00 +0200 Subject: [PATCH 0830/2457] firmware/ad9154: cleanup DAC init - Split dac_setup in dac_reset, dat_detect & dac_setup. - Only do one reset/detection. - Configure before doing SYSREF scan (otherwise scan don't work at the first scan after power up). - Do the spi_setup in each function. --- artiq/firmware/libboard_artiq/ad9154.rs | 31 +++++++++++++++++++------ 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 23f2aba77..00b2364dd 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -131,7 +131,8 @@ const JESD_SETTINGS: JESDSettings = JESDSettings { jesdv: 1 }; -fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { +fn dac_reset(dacno: u8) { + spi_setup(dacno); // reset write(ad9154_reg::SPI_INTFCONFA, 1*ad9154_reg::SOFTRESET_M | 1*ad9154_reg::SOFTRESET | @@ -145,12 +146,20 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { 0*ad9154_reg::ADDRINC_M | 0*ad9154_reg::ADDRINC | 1*ad9154_reg::SDOACTIVE_M | 1*ad9154_reg::SDOACTIVE); clock::spin_us(100); +} + +fn dac_detect(dacno: u8) -> Result<(), &'static str> { + spi_setup(dacno); if (read(ad9154_reg::PRODIDH) as u16) << 8 | (read(ad9154_reg::PRODIDL) as u16) != 0x9154 { return Err("invalid AD9154 identification"); } else { info!("AD9154-{} found", dacno); } + Ok(()) +} +fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { + spi_setup(dacno); info!("AD9154-{} initializing...", dacno); write(ad9154_reg::PWRCNTRL0, 0*ad9154_reg::PD_DAC0 | 0*ad9154_reg::PD_DAC1 | @@ -336,7 +345,7 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { 0x5*ad9154_reg::SPI_CP_LEVEL_THRESHOLD_LOW | 0*ad9154_reg::SPI_CP_LEVEL_DET_PD); write(ad9154_reg::VCO_VARACTOR_CTRL_0, - 0xe*ad9154_reg::SPI_VCO_VARACTOR_OFFSET | + 0xe*ad9154_reg::SPI_VCO_VARACTOR_OFFSET | 0x7*ad9154_reg::SPI_VCO_VARACTOR_REF_TCF); write(ad9154_reg::VCO_VARACTOR_CTRL_1, 0x6*ad9154_reg::SPI_VCO_VARACTOR_REF); @@ -400,7 +409,8 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { } #[allow(dead_code)] -fn dac_status() { +fn dac_status(dacno: u8) { + spi_setup(dacno); info!("SERDES_PLL_LOCK: {}", (read(ad9154_reg::PLL_STATUS) & ad9154_reg::SERDES_PLL_LOCK_RB)); info!(""); @@ -452,7 +462,8 @@ fn dac_status() { info!("NITDISPARITY: 0x{:02x}", read(ad9154_reg::NIT_W)); } -fn dac_monitor() { +fn dac_monitor(dacno: u8) { + spi_setup(dacno); write(ad9154_reg::IRQ_STATUS0, 0x00); write(ad9154_reg::IRQ_STATUS1, 0x00); write(ad9154_reg::IRQ_STATUS2, 0x00); @@ -497,6 +508,7 @@ fn dac_monitor() { fn dac_prbs(dacno: u8) -> Result<(), &'static str> { let mut prbs_errors: u32 = 0; + spi_setup(dacno); /* follow phy prbs testing (p58 of ad9154 datasheet) */ info!("AD9154-{} running PRBS test...", dacno); @@ -572,7 +584,7 @@ fn dac_cfg(dacno: u8) -> Result<(), &'static str> { jesd_enable(dacno, false); clock::spin_us(10000); jesd_enable(dacno, true); - dac_monitor(); + dac_monitor(dacno); clock::spin_us(50000); let t = clock::get_ms(); while !jesd_ready(dacno) { @@ -654,10 +666,15 @@ pub fn init() -> Result<(), &'static str> { for dacno in 0..csr::AD9154.len() { let dacno = dacno as u8; - dac_sysref_scan(dacno); - dac_sysref_cfg(dacno, 88); + // Reset the DAC, detect and configure it + dac_reset(dacno); + dac_detect(dacno)?; dac_cfg_retry(dacno)?; + // Run the PRBS and SYSREF scan tests dac_prbs(dacno)?; + dac_sysref_scan(dacno); + // Set SYSREF phase and reconfigure the DAC + dac_sysref_cfg(dacno, 88); dac_cfg_retry(dacno)?; } From ad89c42acc77333d18483105b0d6812076b1d75d Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 24 May 2018 10:18:08 +0200 Subject: [PATCH 0831/2457] firmware/serwb: automatically adjust prbs test delay to prbs test cycles, increase prbs test cycles --- artiq/firmware/libboard_artiq/serwb.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libboard_artiq/serwb.rs b/artiq/firmware/libboard_artiq/serwb.rs index 46fd6e97f..919405805 100644 --- a/artiq/firmware/libboard_artiq/serwb.rs +++ b/artiq/firmware/libboard_artiq/serwb.rs @@ -43,16 +43,19 @@ pub fn wait_init() { info!("done."); unsafe { + let prbs_test_cycles : u32 = 1<<22; + let prbs_test_us : u64 = ((prbs_test_cycles as u64)*40)/125; // 40 bits @125MHz linerate + info!("RTM to AMC Link test"); - csr::serwb_phy_amc::control_prbs_cycles_write(1<<20); + csr::serwb_phy_amc::control_prbs_cycles_write(prbs_test_cycles); csr::serwb_phy_amc::control_prbs_start_write(1); - clock::spin_us(1000000); + clock::spin_us(prbs_test_us*110/100); // PRBS test time + 10% info!("{} errors", csr::serwb_phy_amc::control_prbs_errors_read()); info!("AMC to RTM Link test"); - csr::serwb_phy_rtm::control_prbs_cycles_write(1<<20); + csr::serwb_phy_rtm::control_prbs_cycles_write(prbs_test_cycles); csr::serwb_phy_rtm::control_prbs_start_write(1); - clock::spin_us(1000000); + clock::spin_us(prbs_test_us*110/100); // PRBS test time + 10% info!("{} errors", csr::serwb_phy_rtm::control_prbs_errors_read()); } From 19efd8b13e4f5030021ddb3551c9ab21e65ef55c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 24 May 2018 18:41:54 +0800 Subject: [PATCH 0832/2457] kasli: refactor EEM code --- artiq/gateware/eem.py | 349 +++++++++++++++ artiq/gateware/targets/kasli.py | 738 ++++++-------------------------- 2 files changed, 485 insertions(+), 602 deletions(-) create mode 100644 artiq/gateware/eem.py diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py new file mode 100644 index 000000000..7566651cd --- /dev/null +++ b/artiq/gateware/eem.py @@ -0,0 +1,349 @@ +from migen import * +from migen.build.generic_platform import * +from migen.genlib.io import DifferentialOutput + +from artiq.gateware import rtio +from artiq.gateware.rtio.phy import spi2 + + +def _eem_signal(i): + n = "d{}".format(i) + if i == 0: + n += "_cc" + return n + + +def _eem_pin(eem, i, pol): + return "eem{}:{}_{}".format(eem, _eem_signal(i), pol) + + +class _EEM: + @classmethod + def add_extension(cls, target, eem, *args): + name = cls.__name__ + target.platform.add_extension(cls.io(eem, *args)) + print("{} (EEM{}) starting at RTIO channel {}" + .format(name, eem, len(target.rtio_channels))) + + +class DIO(_EEM): + @staticmethod + def io(eem): + return [("dio{}".format(eem), i, + Subsignal("p", Pins(_eem_pin(eem, i, "p"))), + Subsignal("n", Pins(_eem_pin(eem, i, "n"))), + IOStandard("LVDS_25")) + for i in range(8)] + + @classmethod + def add_std(cls, target, eem, ttl03_cls, ttl47_cls): + cls.add_extension(target, eem) + + for i in range(4): + pads = target.platform.request("dio{}".format(eem), i) + phy = ttl03_cls(pads.p, pads.n) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy)) + for i in range(4): + pads = target.platform.request("dio{}".format(eem), 4+i) + phy = ttl47_cls(pads.p, pads.n) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy)) + + +class Urukul(_EEM): + @staticmethod + def io(eem, eem_aux): + ios = [ + ("urukul{}_spi_p".format(eem), 0, + Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), + Subsignal("mosi", Pins(_eem_pin(eem, 1, "p"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))), + Subsignal("cs_n", Pins( + *(_eem_pin(eem, i + 3, "p") for i in range(3)))), + IOStandard("LVDS_25"), + ), + ("urukul{}_spi_n".format(eem), 0, + Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), + Subsignal("mosi", Pins(_eem_pin(eem, 1, "n"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))), + Subsignal("cs_n", Pins( + *(_eem_pin(eem, i + 3, "n") for i in range(3)))), + IOStandard("LVDS_25"), + ), + ] + ttls = [(6, eem, "io_update"), + (7, eem, "dds_reset")] + if eem_aux is not None: + ttls += [(0, eem_aux, "sync_clk"), + (1, eem_aux, "sync_in"), + (2, eem_aux, "io_update_ret"), + (3, eem_aux, "nu_mosi3"), + (4, eem_aux, "sw0"), + (5, eem_aux, "sw1"), + (6, eem_aux, "sw2"), + (7, eem_aux, "sw3")] + for i, j, sig in ttls: + ios.append( + ("urukul{}_{}".format(eem, sig), 0, + Subsignal("p", Pins(_eem_pin(j, i, "p"))), + Subsignal("n", Pins(_eem_pin(j, i, "n"))), + IOStandard("LVDS_25") + )) + return ios + + @staticmethod + def io_qspi(eem0, eem1): + ios = [ + ("urukul{}_spi_p".format(eem0), 0, + Subsignal("clk", Pins(_eem_pin(eem0, 0, "p"))), + Subsignal("mosi", Pins(_eem_pin(eem0, 1, "p"))), + Subsignal("cs_n", Pins( + _eem_pin(eem0, 3, "p"), _eem_pin(eem0, 4, "p"))), + IOStandard("LVDS_25"), + ), + ("urukul{}_spi_n".format(eem0), 0, + Subsignal("clk", Pins(_eem_pin(eem0, 0, "n"))), + Subsignal("mosi", Pins(_eem_pin(eem0, 1, "n"))), + Subsignal("cs_n", Pins( + _eem_pin(eem0, 3, "n"), _eem_pin(eem0, 4, "n"))), + IOStandard("LVDS_25"), + ), + ] + ttls = [(6, eem0, "io_update"), + (7, eem0, "dds_reset"), + (4, eem1, "sw0"), + (5, eem1, "sw1"), + (6, eem1, "sw2"), + (7, eem1, "sw3")] + for i, j, sig in ttls: + ios.append( + ("urukul{}_{}".format(eem0, sig), 0, + Subsignal("p", Pins(_eem_pin(j, i, "p"))), + Subsignal("n", Pins(_eem_pin(j, i, "n"))), + IOStandard("LVDS_25") + )) + ios += [ + ("urukul{}_qspi_p".format(eem0), 0, + Subsignal("cs", Pins(_eem_pin(eem0, 5, "p"))), + Subsignal("clk", Pins(_eem_pin(eem0, 2, "p"))), + Subsignal("mosi0", Pins(_eem_pin(eem1, 0, "p"))), + Subsignal("mosi1", Pins(_eem_pin(eem1, 1, "p"))), + Subsignal("mosi2", Pins(_eem_pin(eem1, 2, "p"))), + Subsignal("mosi3", Pins(_eem_pin(eem1, 3, "p"))), + IOStandard("LVDS_25"), + ), + ("urukul{}_qspi_n".format(eem0), 0, + Subsignal("cs", Pins(_eem_pin(eem0, 5, "n"))), + Subsignal("clk", Pins(_eem_pin(eem0, 2, "n"))), + Subsignal("mosi0", Pins(_eem_pin(eem1, 0, "n"))), + Subsignal("mosi1", Pins(_eem_pin(eem1, 1, "n"))), + Subsignal("mosi2", Pins(_eem_pin(eem1, 2, "n"))), + Subsignal("mosi3", Pins(_eem_pin(eem1, 3, "n"))), + IOStandard("LVDS_25"), + ), + ] + return ios + + @classmethod + def add_std(cls, target, eem, eem_aux, ttl_out_cls): + cls.add_extension(target, eem, eem_aux) + + phy = spi2.SPIMaster(target.platform.request("urukul{}_spi_p".format(eem)), + target.platform.request("urukul{}_spi_n".format(eem))) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + pads = target.platform.request("urukul{}_dds_reset".format(eem)) + target.specials += DifferentialOutput(0, pads.p, pads.n) + + pads = target.platform.request("urukul{}_io_update".format(eem)) + phy = ttl_out_cls(pads.p, pads.n) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy)) + if eem_aux is not None: + for signal in "sw0 sw1 sw2 sw3".split(): + pads = target.platform.request("urukul{}_{}".format(eem, signal)) + phy = ttl_out_cls(pads.p, pads.n) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy)) + + +class Sampler(_EEM): + @staticmethod + def io(eem, eem_aux): + ios = [ + ("sampler{}_adc_spi_p".format(eem), 0, + Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), + Subsignal("miso", Pins(_eem_pin(eem, 1, "p"))), + IOStandard("LVDS_25"), + ), + ("sampler{}_adc_spi_n".format(eem), 0, + Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), + Subsignal("miso", Pins(_eem_pin(eem, 1, "n"))), + IOStandard("LVDS_25"), + ), + ("sampler{}_pgia_spi_p".format(eem), 0, + Subsignal("clk", Pins(_eem_pin(eem, 4, "p"))), + Subsignal("mosi", Pins(_eem_pin(eem, 5, "p"))), + Subsignal("miso", Pins(_eem_pin(eem, 6, "p"))), + Subsignal("cs_n", Pins(_eem_pin(eem, 7, "p"))), + IOStandard("LVDS_25"), + ), + ("sampler{}_pgia_spi_n".format(eem), 0, + Subsignal("clk", Pins(_eem_pin(eem, 4, "n"))), + Subsignal("mosi", Pins(_eem_pin(eem, 5, "n"))), + Subsignal("miso", Pins(_eem_pin(eem, 6, "n"))), + Subsignal("cs_n", Pins(_eem_pin(eem, 7, "n"))), + IOStandard("LVDS_25"), + ), + ] + [ + ("sampler{}_{}".format(eem, sig), 0, + Subsignal("p", Pins(_eem_pin(j, i, "p"))), + Subsignal("n", Pins(_eem_pin(j, i, "n"))), + IOStandard("LVDS_25") + ) for i, j, sig in [ + (2, eem, "sdr"), + (3, eem, "cnv") + ] + ] + if eem_aux is not None: + ios += [ + ("sampler{}_adc_data_p".format(eem), 0, + Subsignal("clkout", Pins(_eem_pin(eem_aux, 0, "p"))), + Subsignal("sdoa", Pins(_eem_pin(eem_aux, 1, "p"))), + Subsignal("sdob", Pins(_eem_pin(eem_aux, 2, "p"))), + Subsignal("sdoc", Pins(_eem_pin(eem_aux, 3, "p"))), + Subsignal("sdod", Pins(_eem_pin(eem_aux, 4, "p"))), + Misc("DIFF_TERM=TRUE"), + IOStandard("LVDS_25"), + ), + ("sampler{}_adc_data_n".format(eem), 0, + Subsignal("clkout", Pins(_eem_pin(eem_aux, 0, "n"))), + Subsignal("sdoa", Pins(_eem_pin(eem_aux, 1, "n"))), + Subsignal("sdob", Pins(_eem_pin(eem_aux, 2, "n"))), + Subsignal("sdoc", Pins(_eem_pin(eem_aux, 3, "n"))), + Subsignal("sdod", Pins(_eem_pin(eem_aux, 4, "n"))), + Misc("DIFF_TERM=TRUE"), + IOStandard("LVDS_25"), + ), + ] + return ios + + @classmethod + def add_std(cls, target, eem, eem_aux, ttl_out_cls): + cls.add_extension(target, eem, eem_aux) + + phy = spi2.SPIMaster( + target.platform.request("sampler{}_adc_spi_p".format(eem)), + target.platform.request("sampler{}_adc_spi_n".format(eem))) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + phy = spi2.SPIMaster( + target.platform.request("sampler{}_pgia_spi_p".format(eem)), + target.platform.request("sampler{}_pgia_spi_n".format(eem))) + target.submodules += phy + + target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + pads = target.platform.request("sampler{}_cnv".format(eem)) + phy = ttl_out_cls(pads.p, pads.n) + target.submodules += phy + + target.rtio_channels.append(rtio.Channel.from_phy(phy)) + sdr = target.platform.request("sampler{}_sdr".format(eem)) + target.specials += DifferentialOutput(1, sdr.p, sdr.n) + + +class Novogorny(_EEM): + @staticmethod + def io(eem): + return [ + ("novogorny{}_spi_p".format(eem), 0, + Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), + Subsignal("mosi", Pins(_eem_pin(eem, 1, "p"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))), + Subsignal("cs_n", Pins( + _eem_pin(eem, 3, "p"), _eem_pin(eem, 4, "p"))), + IOStandard("LVDS_25"), + ), + ("novogorny{}_spi_n".format(eem), 0, + Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), + Subsignal("mosi", Pins(_eem_pin(eem, 1, "n"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))), + Subsignal("cs_n", Pins( + _eem_pin(eem, 3, "n"), _eem_pin(eem, 4, "n"))), + IOStandard("LVDS_25"), + ), + ] + [ + ("novogorny{}_{}".format(eem, sig), 0, + Subsignal("p", Pins(_eem_pin(j, i, "p"))), + Subsignal("n", Pins(_eem_pin(j, i, "n"))), + IOStandard("LVDS_25") + ) for i, j, sig in [ + (5, eem, "cnv"), + (6, eem, "busy"), + (7, eem, "scko"), + ] + ] + + @classmethod + def add_std(cls, target, eem, ttl_out_cls): + cls.add_extension(target, eem) + + phy = spi2.SPIMaster(target.platform.request("novogorny{}_spi_p".format(eem)), + target.platform.request("novogorny{}_spi_n".format(eem))) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=16)) + + pads = target.platform.request("novogorny{}_cnv".format(eem)) + phy = ttl_out_cls(pads.p, pads.n) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy)) + + +class Zotino(_EEM): + @staticmethod + def io(eem): + return [ + ("zotino{}_spi_p".format(eem), 0, + Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), + Subsignal("mosi", Pins(_eem_pin(eem, 1, "p"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))), + Subsignal("cs_n", Pins( + _eem_pin(eem, 3, "p"), _eem_pin(eem, 4, "p"))), + IOStandard("LVDS_25"), + ), + ("zotino{}_spi_n".format(eem), 0, + Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), + Subsignal("mosi", Pins(_eem_pin(eem, 1, "n"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))), + Subsignal("cs_n", Pins( + _eem_pin(eem, 3, "n"), _eem_pin(eem, 4, "n"))), + IOStandard("LVDS_25"), + ), + ] + [ + ("zotino{}_{}".format(eem, sig), 0, + Subsignal("p", Pins(_eem_pin(j, i, "p"))), + Subsignal("n", Pins(_eem_pin(j, i, "n"))), + IOStandard("LVDS_25") + ) for i, j, sig in [ + (5, eem, "ldac_n"), + (6, eem, "busy"), + (7, eem, "clr_n"), + ] + ] + + @classmethod + def add_std(cls, target, eem, ttl_out_cls): + cls.add_extension(target, eem) + + phy = spi2.SPIMaster(target.platform.request("zotino{}_spi_p".format(eem)), + target.platform.request("zotino{}_spi_n".format(eem))) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + for signal in "ldac_n clr_n".split(): + pads = target.platform.request("zotino{}_{}".format(eem, signal)) + phy = ttl_out_cls(pads.p, pads.n) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy)) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 7c03cd5a1..de4dd9e15 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -5,7 +5,6 @@ import argparse from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.cdc import MultiReg -from migen.build.generic_platform import * from migen.genlib.io import DifferentialOutput from misoc.interconnect.csr import * @@ -20,6 +19,7 @@ from artiq.gateware import rtio from artiq.gateware.rtio.phy import ( ttl_simple, ttl_serdes_7series, spi2, servo as rtservo) from artiq.gateware.suservo import servo, pads as servo_pads +from artiq.gateware import eem from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer @@ -146,240 +146,6 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.csr_devices.append("rtio_analyzer") -def _eem_signal(i): - n = "d{}".format(i) - if i == 0: - n += "_cc" - return n - - -def _eem_pin(eem, i, pol): - return "{}:{}_{}".format(eem, _eem_signal(i), pol) - - -def _dio(eem): - return [(eem, i, - Subsignal("p", Pins(_eem_pin(eem, i, "p"))), - Subsignal("n", Pins(_eem_pin(eem, i, "n"))), - IOStandard("LVDS_25")) - for i in range(8)] - - -def _sampler(eem, eem_aux=None): - ios = [ - ("{}_adc_spi_p".format(eem), 0, - Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), - Subsignal("miso", Pins(_eem_pin(eem, 1, "p"))), - IOStandard("LVDS_25"), - ), - ("{}_adc_spi_n".format(eem), 0, - Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), - Subsignal("miso", Pins(_eem_pin(eem, 1, "n"))), - IOStandard("LVDS_25"), - ), - ("{}_pgia_spi_p".format(eem), 0, - Subsignal("clk", Pins(_eem_pin(eem, 4, "p"))), - Subsignal("mosi", Pins(_eem_pin(eem, 5, "p"))), - Subsignal("miso", Pins(_eem_pin(eem, 6, "p"))), - Subsignal("cs_n", Pins(_eem_pin(eem, 7, "p"))), - IOStandard("LVDS_25"), - ), - ("{}_pgia_spi_n".format(eem), 0, - Subsignal("clk", Pins(_eem_pin(eem, 4, "n"))), - Subsignal("mosi", Pins(_eem_pin(eem, 5, "n"))), - Subsignal("miso", Pins(_eem_pin(eem, 6, "n"))), - Subsignal("cs_n", Pins(_eem_pin(eem, 7, "n"))), - IOStandard("LVDS_25"), - ), - ] + [ - ("{}_{}".format(eem, sig), 0, - Subsignal("p", Pins(_eem_pin(j, i, "p"))), - Subsignal("n", Pins(_eem_pin(j, i, "n"))), - IOStandard("LVDS_25") - ) for i, j, sig in [ - (2, eem, "sdr"), - (3, eem, "cnv") - ] - ] - if eem_aux is not None: - ios += [ - ("{}_adc_data_p".format(eem), 0, - Subsignal("clkout", Pins(_eem_pin(eem_aux, 0, "p"))), - Subsignal("sdoa", Pins(_eem_pin(eem_aux, 1, "p"))), - Subsignal("sdob", Pins(_eem_pin(eem_aux, 2, "p"))), - Subsignal("sdoc", Pins(_eem_pin(eem_aux, 3, "p"))), - Subsignal("sdod", Pins(_eem_pin(eem_aux, 4, "p"))), - Misc("DIFF_TERM=TRUE"), - IOStandard("LVDS_25"), - ), - ("{}_adc_data_n".format(eem), 0, - Subsignal("clkout", Pins(_eem_pin(eem_aux, 0, "n"))), - Subsignal("sdoa", Pins(_eem_pin(eem_aux, 1, "n"))), - Subsignal("sdob", Pins(_eem_pin(eem_aux, 2, "n"))), - Subsignal("sdoc", Pins(_eem_pin(eem_aux, 3, "n"))), - Subsignal("sdod", Pins(_eem_pin(eem_aux, 4, "n"))), - Misc("DIFF_TERM=TRUE"), - IOStandard("LVDS_25"), - ), - ] - return ios - - -def _novogorny(eem): - return [ - ("{}_spi_p".format(eem), 0, - Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), - Subsignal("mosi", Pins(_eem_pin(eem, 1, "p"))), - Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))), - Subsignal("cs_n", Pins( - _eem_pin(eem, 3, "p"), _eem_pin(eem, 4, "p"))), - IOStandard("LVDS_25"), - ), - ("{}_spi_n".format(eem), 0, - Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), - Subsignal("mosi", Pins(_eem_pin(eem, 1, "n"))), - Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))), - Subsignal("cs_n", Pins( - _eem_pin(eem, 3, "n"), _eem_pin(eem, 4, "n"))), - IOStandard("LVDS_25"), - ), - ] + [ - ("{}_{}".format(eem, sig), 0, - Subsignal("p", Pins(_eem_pin(j, i, "p"))), - Subsignal("n", Pins(_eem_pin(j, i, "n"))), - IOStandard("LVDS_25") - ) for i, j, sig in [ - (5, eem, "cnv"), - (6, eem, "busy"), - (7, eem, "scko"), - ] - ] - - -def _zotino(eem): - return [ - ("{}_spi_p".format(eem), 0, - Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), - Subsignal("mosi", Pins(_eem_pin(eem, 1, "p"))), - Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))), - Subsignal("cs_n", Pins( - _eem_pin(eem, 3, "p"), _eem_pin(eem, 4, "p"))), - IOStandard("LVDS_25"), - ), - ("{}_spi_n".format(eem), 0, - Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), - Subsignal("mosi", Pins(_eem_pin(eem, 1, "n"))), - Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))), - Subsignal("cs_n", Pins( - _eem_pin(eem, 3, "n"), _eem_pin(eem, 4, "n"))), - IOStandard("LVDS_25"), - ), - ] + [ - ("{}_{}".format(eem, sig), 0, - Subsignal("p", Pins(_eem_pin(j, i, "p"))), - Subsignal("n", Pins(_eem_pin(j, i, "n"))), - IOStandard("LVDS_25") - ) for i, j, sig in [ - (5, eem, "ldac_n"), - (6, eem, "busy"), - (7, eem, "clr_n"), - ] - ] - - -def _urukul(eem, eem_aux=None): - ios = [ - ("{}_spi_p".format(eem), 0, - Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), - Subsignal("mosi", Pins(_eem_pin(eem, 1, "p"))), - Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))), - Subsignal("cs_n", Pins( - *(_eem_pin(eem, i + 3, "p") for i in range(3)))), - IOStandard("LVDS_25"), - ), - ("{}_spi_n".format(eem), 0, - Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), - Subsignal("mosi", Pins(_eem_pin(eem, 1, "n"))), - Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))), - Subsignal("cs_n", Pins( - *(_eem_pin(eem, i + 3, "n") for i in range(3)))), - IOStandard("LVDS_25"), - ), - ] - ttls = [(6, eem, "io_update"), - (7, eem, "dds_reset")] - if eem_aux is not None: - ttls += [(0, eem_aux, "sync_clk"), - (1, eem_aux, "sync_in"), - (2, eem_aux, "io_update_ret"), - (3, eem_aux, "nu_mosi3"), - (4, eem_aux, "sw0"), - (5, eem_aux, "sw1"), - (6, eem_aux, "sw2"), - (7, eem_aux, "sw3")] - for i, j, sig in ttls: - ios.append( - ("{}_{}".format(eem, sig), 0, - Subsignal("p", Pins(_eem_pin(j, i, "p"))), - Subsignal("n", Pins(_eem_pin(j, i, "n"))), - IOStandard("LVDS_25") - )) - return ios - - -def _urukul_qspi(eem0, eem1): - ios = [ - ("{}_spi_p".format(eem0), 0, - Subsignal("clk", Pins(_eem_pin(eem0, 0, "p"))), - Subsignal("mosi", Pins(_eem_pin(eem0, 1, "p"))), - Subsignal("cs_n", Pins( - _eem_pin(eem0, 3, "p"), _eem_pin(eem0, 4, "p"))), - IOStandard("LVDS_25"), - ), - ("{}_spi_n".format(eem0), 0, - Subsignal("clk", Pins(_eem_pin(eem0, 0, "n"))), - Subsignal("mosi", Pins(_eem_pin(eem0, 1, "n"))), - Subsignal("cs_n", Pins( - _eem_pin(eem0, 3, "n"), _eem_pin(eem0, 4, "n"))), - IOStandard("LVDS_25"), - ), - ] - ttls = [(6, eem0, "io_update"), - (7, eem0, "dds_reset"), - (4, eem1, "sw0"), - (5, eem1, "sw1"), - (6, eem1, "sw2"), - (7, eem1, "sw3")] - for i, j, sig in ttls: - ios.append( - ("{}_{}".format(eem0, sig), 0, - Subsignal("p", Pins(_eem_pin(j, i, "p"))), - Subsignal("n", Pins(_eem_pin(j, i, "n"))), - IOStandard("LVDS_25") - )) - ios += [ - ("{}_qspi_p".format(eem0), 0, - Subsignal("cs", Pins(_eem_pin(eem0, 5, "p"))), - Subsignal("clk", Pins(_eem_pin(eem0, 2, "p"))), - Subsignal("mosi0", Pins(_eem_pin(eem1, 0, "p"))), - Subsignal("mosi1", Pins(_eem_pin(eem1, 1, "p"))), - Subsignal("mosi2", Pins(_eem_pin(eem1, 2, "p"))), - Subsignal("mosi3", Pins(_eem_pin(eem1, 3, "p"))), - IOStandard("LVDS_25"), - ), - ("{}_qspi_n".format(eem0), 0, - Subsignal("cs", Pins(_eem_pin(eem0, 5, "n"))), - Subsignal("clk", Pins(_eem_pin(eem0, 2, "n"))), - Subsignal("mosi0", Pins(_eem_pin(eem1, 0, "n"))), - Subsignal("mosi1", Pins(_eem_pin(eem1, 1, "n"))), - Subsignal("mosi2", Pins(_eem_pin(eem1, 2, "n"))), - Subsignal("mosi3", Pins(_eem_pin(eem1, 3, "n"))), - IOStandard("LVDS_25"), - ), - ] - return ios - - class Opticlock(_StandaloneBase): """ Opticlock extension variant configuration @@ -392,99 +158,34 @@ class Opticlock(_StandaloneBase): self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) - platform = self.platform - platform.add_extension(_dio("eem0")) - platform.add_extension(_dio("eem1")) - platform.add_extension(_dio("eem2")) - platform.add_extension(_novogorny("eem3")) - platform.add_extension(_urukul("eem5", "eem4")) - platform.add_extension(_urukul("eem6")) - platform.add_extension(_zotino("eem7")) - - try: - # EEM clock fan-out from Si5324, not MMCX, only Kasli/v1.0 - self.comb += platform.request("clk_sel").eq(1) - except ConstraintError: - pass - - rtio_channels = [] - for i in range(24): - eem, port = divmod(i, 8) - pads = platform.request("eem{}".format(eem), port) - if i < 4: - cls = ttl_serdes_7series.InOut_8X - else: - cls = ttl_serdes_7series.Output_8X - phy = cls(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - # EEM3: Novogorny - phy = spi2.SPIMaster(self.platform.request("eem3_spi_p"), - self.platform.request("eem3_spi_n")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=16)) - - for signal in "cnv".split(): - pads = platform.request("eem3_{}".format(signal)) - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - # EEM5 + EEM4: Urukul - phy = spi2.SPIMaster(self.platform.request("eem5_spi_p"), - self.platform.request("eem5_spi_n")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - - pads = platform.request("eem5_dds_reset") - self.specials += DifferentialOutput(0, pads.p, pads.n) - - for signal in "io_update sw0 sw1 sw2 sw3".split(): - pads = platform.request("eem5_{}".format(signal)) - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + self.rtio_channels = [] + eem.DIO.add_std(self, 0, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 1, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 2, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.Novogorny.add_std(self, 3, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 5, 4, ttl_serdes_7series.Output_8X) for i in (1, 2): - sfp_ctl = platform.request("sfp_ctl", i) + sfp_ctl = self.platform.request("sfp_ctl", i) phy = ttl_simple.Output(sfp_ctl.led) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + self.rtio_channels.append(rtio.Channel.from_phy(phy)) - # EEM6: Urukul - phy = spi2.SPIMaster(self.platform.request("eem6_spi_p"), - self.platform.request("eem6_spi_n")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - - for signal in "io_update".split(): - pads = platform.request("eem6_{}".format(signal)) - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - pads = platform.request("eem6_dds_reset") - self.specials += DifferentialOutput(0, pads.p, pads.n) - - # EEM7: Zotino - phy = spi2.SPIMaster(self.platform.request("eem7_spi_p"), - self.platform.request("eem7_spi_n")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - - for signal in "ldac_n clr_n".split(): - pads = platform.request("eem7_{}".format(signal)) - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) - self.add_rtio(rtio_channels) + self.add_rtio(self.rtio_channels) class SUServo(_StandaloneBase): @@ -499,37 +200,25 @@ class SUServo(_StandaloneBase): self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) - platform = self.platform - platform.add_extension(_dio("eem0")) - platform.add_extension(_dio("eem1")) - platform.add_extension(_sampler("eem3", "eem2")) - platform.add_extension(_urukul_qspi("eem5", "eem4")) - platform.add_extension(_urukul_qspi("eem7", "eem6")) - - try: - # EEM clock fan-out from Si5324, not MMCX, only Kasli/v1.0 - self.comb += platform.request("clk_sel").eq(1) - except ConstraintError: - pass - - rtio_channels = [] - for i in range(16): - eem, port = divmod(i, 8) - pads = platform.request("eem{}".format(eem), port) - if i < 4: - cls = ttl_serdes_7series.InOut_8X - else: - cls = ttl_serdes_7series.Output_8X - phy = cls(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + self.rtio_channels = [] + # EEM0, EEM1: DIO + eem.DIO.add_std(self, 0, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 1, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) # EEM3, EEM2: Sampler - sampler_pads = servo_pads.SamplerPads(self.platform, "eem3") + self.platform.add_extension(eem.Sampler.io(3, 2)) + sampler_pads = servo_pads.SamplerPads(self.platform, "sampler3") # EEM5, EEM4 and EEM7, EEM6: Urukul + self.platform.add_extension(eem.Urukul.io_qspi(5, 4)) + self.platform.add_extension(eem.Urukul.io_qspi(7, 6)) urukul_pads = servo_pads.UrukulPads(self.platform, - "eem5", "eem7") + "urukul5", "urukul7") adc_p = servo.ADCParams(width=16, channels=8, lanes=4, t_cnvh=4, # account for SCK pipeline latency t_conv=57 - 4, t_rtt=4 + 4) @@ -543,124 +232,98 @@ class SUServo(_StandaloneBase): ctrls = [rtservo.RTServoCtrl(ctrl) for ctrl in su.iir.ctrl] self.submodules += ctrls - rtio_channels.extend(rtio.Channel.from_phy(ctrl) for ctrl in ctrls) + self.rtio_channels.extend(rtio.Channel.from_phy(ctrl) for ctrl in ctrls) mem = rtservo.RTServoMem(iir_p, su) self.submodules += mem - rtio_channels.append(rtio.Channel.from_phy(mem, ififo_depth=4)) + self.rtio_channels.append(rtio.Channel.from_phy(mem, ififo_depth=4)) # EEM3: Sampler - phy = spi2.SPIMaster(self.platform.request("eem3_pgia_spi_p"), - self.platform.request("eem3_pgia_spi_n")) + phy = spi2.SPIMaster(self.platform.request("sampler3_pgia_spi_p"), + self.platform.request("sampler3_pgia_spi_n")) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + self.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) # EEM5 + EEM4: Urukul - phy = spi2.SPIMaster(self.platform.request("eem5_spi_p"), - self.platform.request("eem5_spi_n")) + phy = spi2.SPIMaster(self.platform.request("urukul5_spi_p"), + self.platform.request("urukul5_spi_n")) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + self.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - pads = platform.request("eem5_dds_reset") + pads = self.platform.request("urukul5_dds_reset") self.specials += DifferentialOutput(0, pads.p, pads.n) for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): - pads = platform.request("eem5_{}".format(signal)) + pads = self.platform.request("urukul5_{}".format(signal)) self.specials += DifferentialOutput( su.iir.ctrl[i].en_out, pads.p, pads.n) # EEM7 + EEM6: Urukul - phy = spi2.SPIMaster(self.platform.request("eem7_spi_p"), - self.platform.request("eem7_spi_n")) + phy = spi2.SPIMaster(self.platform.request("urukul7_spi_p"), + self.platform.request("urukul7_spi_n")) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + self.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - pads = platform.request("eem7_dds_reset") + pads = self.platform.request("urukul7_dds_reset") self.specials += DifferentialOutput(0, pads.p, pads.n) for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): - pads = platform.request("eem7_{}".format(signal)) + pads = self.platform.request("urukul7_{}".format(signal)) self.specials += DifferentialOutput( su.iir.ctrl[i + 4].en_out, pads.p, pads.n) for i in (1, 2): - sfp_ctl = platform.request("sfp_ctl", i) + sfp_ctl = self.platform.request("sfp_ctl", i) phy = ttl_simple.Output(sfp_ctl.led) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + self.rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) - self.add_rtio(rtio_channels) + self.add_rtio(self.rtio_channels) - platform.add_false_path_constraints( + self.platform.add_false_path_constraints( sampler_pads.clkout_p, self.rtio_crg.cd_rtio.clk) - platform.add_false_path_constraints( + self.platform.add_false_path_constraints( sampler_pads.clkout_p, self.crg.cd_sys.clk) class SYSU(_StandaloneBase): - def __init__(self, **kwargs): - _StandaloneBase.__init__(self, **kwargs) + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.0" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) - platform = self.platform - platform.add_extension(_urukul("eem1", "eem0")) - platform.add_extension(_dio("eem2")) - platform.add_extension(_dio("eem3")) - platform.add_extension(_dio("eem4")) - platform.add_extension(_dio("eem5")) - platform.add_extension(_dio("eem6")) - - # EEM clock fan-out from Si5324, not MMCX - self.comb += platform.request("clk_sel").eq(1) - - # EEM2-6: TTL - rtio_channels = [] - for i in range(40): - eem_offset, port = divmod(i, 8) - pads = platform.request("eem{}".format(2 + eem_offset), port) - if i < 4: - cls = ttl_serdes_7series.InOut_8X - else: - cls = ttl_serdes_7series.Output_8X - phy = cls(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - # EEM0, EEM1: Urukul - phy = spi2.SPIMaster(self.platform.request("eem1_spi_p"), - self.platform.request("eem1_spi_n")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - - pads = platform.request("eem1_dds_reset") - self.specials += DifferentialOutput(0, pads.p, pads.n) - - for signal in "io_update sw0 sw1 sw2 sw3".split(): - pads = platform.request("eem1_{}".format(signal)) - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + self.rtio_channels = [] + eem.DIO.add_std(self, 2, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + for i in range(3, 7): + eem.DIO.add_std(self, i, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 1, 0, ttl_serdes_7series.Output_8X) for i in (1, 2): - sfp_ctl = platform.request("sfp_ctl", i) + sfp_ctl = self.platform.request("sfp_ctl", i) phy = ttl_simple.Output(sfp_ctl.led) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + self.rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) - self.add_rtio(rtio_channels) + self.add_rtio(self.rtio_channels) class MITLL(_StandaloneBase): @@ -671,61 +334,29 @@ class MITLL(_StandaloneBase): self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) - platform = self.platform + self.rtio_channels = [] # TODO: grabber on eem0->eemB eem1->eemA - platform.add_extension(_urukul("eem3", "eem2")) - platform.add_extension(_dio("eem4")) - platform.add_extension(_zotino("eem5")) - platform.add_extension(_zotino("eem6")) - - # EEM4: TTL - rtio_channels = [] - for i in range(8): - pads = platform.request("eem4", i) - phy = ttl_serdes_7series.InOut_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - # EEM2, EEM3: Urukul - phy = spi2.SPIMaster(self.platform.request("eem3_spi_p"), - self.platform.request("eem3_spi_n")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - - pads = platform.request("eem3_dds_reset") - self.specials += DifferentialOutput(0, pads.p, pads.n) - - for signal in "io_update sw0 sw1 sw2 sw3".split(): - pads = platform.request("eem3_{}".format(signal)) - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - # EEM5, EEM6: Zotino - for i in (5, 6): - phy = spi2.SPIMaster(self.platform.request("eem{}_spi_p".format(i)), - self.platform.request("eem{}_spi_n".format(i))) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - - for signal in "ldac_n clr_n".split(): - pads = platform.request("eem{}_{}".format(i, signal)) - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + eem.DIO.add_std(self, 4, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.InOut_8X) + eem.Urukul.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 5, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 6, ttl_serdes_7series.Output_8X) for i in (1, 2): - sfp_ctl = platform.request("sfp_ctl", i) + sfp_ctl = self.platform.request("sfp_ctl", i) phy = ttl_simple.Output(sfp_ctl.led) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + self.rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) - self.add_rtio(rtio_channels) + self.add_rtio(self.rtio_channels) class USTC(_StandaloneBase): @@ -736,55 +367,32 @@ class USTC(_StandaloneBase): self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) - platform = self.platform + self.rtio_channels = [] # TODO: grabber on eem0->eemA - platform.add_extension(_urukul("eem2", "eem1")) - platform.add_extension(_urukul("eem4", "eem3")) - platform.add_extension(_dio("eem5")) - platform.add_extension(_dio("eem6")) - platform.add_extension(_dio("eem7")) - - # EEM5-7: TTL - rtio_channels = [] - for i in range(24): - eem_offset, port = divmod(i, 8) - pads = platform.request("eem{}".format(5 + eem_offset), port) - if i < 4: - cls = ttl_serdes_7series.InOut_8X - else: - cls = ttl_serdes_7series.Output_8X - phy = cls(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - # EEM2-4: Urukul - for eem in (2, 4): - phy = spi2.SPIMaster(self.platform.request("eem{}_spi_p".format(eem)), - self.platform.request("eem{}_spi_n".format(eem))) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - - pads = platform.request("eem{}_dds_reset".format(eem)) - self.specials += DifferentialOutput(0, pads.p, pads.n) - - for signal in "io_update sw0 sw1 sw2 sw3".split(): - pads = platform.request("eem{}_{}".format(eem, signal)) - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + eem.DIO.add_std(self, 5, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 6, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 7, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 2, 1, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 4, 3, ttl_serdes_7series.Output_8X) for i in (1, 2): - sfp_ctl = platform.request("sfp_ctl", i) + sfp_ctl = self.platform.request("sfp_ctl", i) phy = ttl_simple.Output(sfp_ctl.led) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + self.rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) - self.add_rtio(rtio_channels) + self.add_rtio(self.rtio_channels) class Tester(_StandaloneBase): @@ -799,87 +407,28 @@ class Tester(_StandaloneBase): self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) - platform = self.platform - platform.add_extension(_urukul("eem1", "eem0")) - platform.add_extension(_sampler("eem3", "eem2")) - platform.add_extension(_zotino("eem4")) - platform.add_extension(_dio("eem5")) - - try: - # EEM clock fan-out from Si5324, not MMCX, only Kasli/v1.0 - self.comb += platform.request("clk_sel").eq(1) - except ConstraintError: - pass - - # EEM5: TTL - rtio_channels = [] - for i in range(8): - pads = platform.request("eem5", i) - if i < 4: - cls = ttl_serdes_7series.InOut_8X - else: - cls = ttl_serdes_7series.Output_8X - phy = cls(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - # EEM0, EEM1: Urukul - phy = spi2.SPIMaster(self.platform.request("eem1_spi_p"), - self.platform.request("eem1_spi_n")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - - pads = platform.request("eem1_dds_reset") - self.specials += DifferentialOutput(0, pads.p, pads.n) - - for signal in "io_update sw0 sw1 sw2 sw3".split(): - pads = platform.request("eem1_{}".format(signal)) - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - # EEM2, EEM3: Sampler - phy = spi2.SPIMaster(self.platform.request("eem3_adc_spi_p"), - self.platform.request("eem3_adc_spi_n")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - phy = spi2.SPIMaster(self.platform.request("eem3_pgia_spi_p"), - self.platform.request("eem3_pgia_spi_n")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - pads = platform.request("eem3_cnv") - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - sdr = platform.request("eem3_sdr") - self.specials += DifferentialOutput(1, sdr.p, sdr.n) - - # EEM4: Zotino - phy = spi2.SPIMaster(self.platform.request("eem4_spi_p"), - self.platform.request("eem4_spi_n")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - - for signal in "ldac_n clr_n".split(): - pads = platform.request("eem4_{}".format(signal)) - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - + self.rtio_channels = [] + eem.DIO.add_std(self, 5, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 1, 0, ttl_serdes_7series.Output_8X) + eem.Sampler.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 4, ttl_serdes_7series.Output_8X) + for i in (1, 2): - sfp_ctl = platform.request("sfp_ctl", i) + sfp_ctl = self.platform.request("sfp_ctl", i) phy = ttl_simple.Output(sfp_ctl.led) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - print(len(rtio_channels)) + self.rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) - self.add_rtio(rtio_channels) + self.add_rtio(self.rtio_channels) class _RTIOClockMultiplier(Module): @@ -1134,55 +683,40 @@ class Master(_MasterBase): def __init__(self, *args, **kwargs): _MasterBase.__init__(self, *args, **kwargs) - platform = self.platform - platform.add_extension(_dio("eem0")) + self.rtio_channels = [] - rtio_channels = [] - - phy = ttl_simple.Output(platform.request("user_led", 0)) + phy = ttl_simple.Output(self.platform.request("user_led", 0)) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + self.rtio_channels.append(rtio.Channel.from_phy(phy)) for sc in self.sfp_ctl: phy = ttl_simple.Output(sc.led) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - for i in range(8): - pads = platform.request("eem0", i) - phy = ttl_serdes_7series.InOut_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + eem.DIO.add_std(self, 0, ttl_serdes_7series.InOut_8X) self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) - self.add_rtio(rtio_channels) + self.add_rtio(self.rtio_channels) class Satellite(_SatelliteBase): def __init__(self, *args, **kwargs): _SatelliteBase.__init__(self, *args, **kwargs) - platform = self.platform - platform.add_extension(_dio("eem0")) - rtio_channels = [] - phy = ttl_simple.Output(platform.request("user_led", 0)) + self.rtio_channels = [] + phy = ttl_simple.Output(self.platform.request("user_led", 0)) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + self.rtio_channels.append(rtio.Channel.from_phy(phy)) for i in range(1, 3): - phy = ttl_simple.Output(platform.request("sfp_ctl", i).led) + phy = ttl_simple.Output(self.platform.request("sfp_ctl", i).led) self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + eem.DIO.add_std(self, 0, ttl_serdes_7series.InOut_8X) - for i in range(8): - pads = platform.request("eem0", i) - phy = ttl_serdes_7series.InOut_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.add_rtio(rtio_channels) + self.add_rtio(self.rtio_channels) def main(): From 353767bfdbd23db9f7927c08a24dd4cb582021bd Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 24 May 2018 16:49:49 +0200 Subject: [PATCH 0833/2457] firmware/hmc830: add VCO subsystem register 6 programming (suggested by hartytp, tested on hardware without regression) --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 8685d46bd..f713a1380 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -30,7 +30,7 @@ mod clock_mux { mod hmc830 { use board_misoc::{csr, clock}; - const HMC830_WRITES: [(u8, u32); 17] = [ + const HMC830_WRITES: [(u8, u32); 18] = [ (0x0, 0x20), (0x1, 0x2), (0x2, 0x2), // r_divider @@ -39,6 +39,7 @@ mod hmc830 { (0x5, 0xe110), (0x5, 0x2818), (0x5, 0xf88), + (0x5, 0x7fb0), (0x5, 0x0), (0x6, 0x303ca), (0x7, 0x14d), From bca296995747f19d1ef3127911d0e0e281d456dc Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 24 May 2018 16:53:10 +0200 Subject: [PATCH 0834/2457] sayma_rtm: add RTMScratch module to test remote Wishbone accesses --- artiq/gateware/targets/sayma_rtm.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 66855e4d8..3b795b2b5 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -76,6 +76,32 @@ class RTMMagic(Module, AutoCSR): self.comb += self.magic.status.eq(0x5352544d) # "SRTM" +class RTMScratch(Module, AutoCSR): + def __init__(self): + self.write_stb = write_stb = CSR() + self.write_ack = write_ack = CSRStatus() + self.write_data = write_data = CSRStorage(32) + + self.read_stb = read_stb = CSRStatus() + self.read_ack = read_ack = CSR() + self.read_data = read_data = CSRStatus(32) + + # # # + + fifo = stream.SyncFIFO([("data", 32)], 512, buffered=True) + self.submodules += fifo + self.comb += [ + # Connect registers to FIFO Sink + fifo.sink.stb.eq(write_stb.re), + write_ack.status.eq(fifo.sink.ack), + fifo.sink.data.eq(write_data.storage), + + # Connect FIFO Source to registers + read_stb.status.eq(fifo.source.stb), + fifo.source.ack.eq(read_ack.re), + read_data.status.eq(fifo.source.data) + ] + CSR_RANGE_SIZE = 0x800 @@ -90,6 +116,8 @@ class SaymaRTM(Module): csr_devices.append("rtm_magic") self.submodules.rtm_identifier = identifier.Identifier(artiq_version) csr_devices.append("rtm_identifier") + self.submodules.rtm_scratch = RTMScratch() + csr_devices.append("rtm_scratch") # clock mux: 100MHz ext SMA clock to HMC830 input self.submodules.clock_mux = gpio.GPIOOut(Cat( From bcb9c3d09da3048bbb46fb5cfc5be99fb3d53f59 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 24 May 2018 16:53:47 +0200 Subject: [PATCH 0835/2457] firmware/serwb: move prbs_test outside of wait_init, add wishbone_test --- artiq/firmware/libboard_artiq/serwb.rs | 70 ++++++++++++++++++++------ 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/artiq/firmware/libboard_artiq/serwb.rs b/artiq/firmware/libboard_artiq/serwb.rs index 919405805..e00f3395a 100644 --- a/artiq/firmware/libboard_artiq/serwb.rs +++ b/artiq/firmware/libboard_artiq/serwb.rs @@ -28,6 +28,57 @@ unsafe fn debug_print(rtm: bool) { } } +fn prbs_test() { + let prbs_test_cycles : u32 = 1<<22; + let prbs_test_us : u64 = ((prbs_test_cycles as u64)*40)/125; // 40 bits @125MHz linerate + + unsafe { + info!("RTM to AMC Link test"); + csr::serwb_phy_amc::control_prbs_cycles_write(prbs_test_cycles); + csr::serwb_phy_amc::control_prbs_start_write(1); + clock::spin_us(prbs_test_us*110/100); // PRBS test time + 10% + info!("{} errors", csr::serwb_phy_amc::control_prbs_errors_read()); + + info!("AMC to RTM Link test"); + csr::serwb_phy_rtm::control_prbs_cycles_write(prbs_test_cycles); + csr::serwb_phy_rtm::control_prbs_start_write(1); + clock::spin_us(prbs_test_us*110/100); // PRBS test time + 10% + info!("{} errors", csr::serwb_phy_rtm::control_prbs_errors_read()); + } +} + +fn prng32(seed: &mut u32) -> u32 { *seed = 1664525 * *seed + 1013904223; *seed } + +fn wishbone_test() { + let test_length: u32 = 512; + let mut test_errors : u32 = 0; + + let mut seed : u32; + + info!("Wishbone test..."); + unsafe { + // Alternate pseudo random write/read bursts of + // increasing size. + for length in 0..test_length { + // Pseudo random writes + seed = length; + for _ in 0..length { + csr::rtm_scratch::write_data_write(prng32(&mut seed)); + csr::rtm_scratch::write_stb_write(1); + } + // Pseudo random reads + seed = length; + for _ in 0..length { + if csr::rtm_scratch::read_data_read() != prng32(&mut seed) { + test_errors += 1; + } + csr::rtm_scratch::read_ack_write(1); + } + } + } + info!("{} errors", test_errors); +} + pub fn wait_init() { info!("waiting for AMC/RTM serwb bridge to be ready..."); unsafe { @@ -42,22 +93,11 @@ pub fn wait_init() { } info!("done."); - unsafe { - let prbs_test_cycles : u32 = 1<<22; - let prbs_test_us : u64 = ((prbs_test_cycles as u64)*40)/125; // 40 bits @125MHz linerate + // PRBS test + prbs_test(); - info!("RTM to AMC Link test"); - csr::serwb_phy_amc::control_prbs_cycles_write(prbs_test_cycles); - csr::serwb_phy_amc::control_prbs_start_write(1); - clock::spin_us(prbs_test_us*110/100); // PRBS test time + 10% - info!("{} errors", csr::serwb_phy_amc::control_prbs_errors_read()); - - info!("AMC to RTM Link test"); - csr::serwb_phy_rtm::control_prbs_cycles_write(prbs_test_cycles); - csr::serwb_phy_rtm::control_prbs_start_write(1); - clock::spin_us(prbs_test_us*110/100); // PRBS test time + 10% - info!("{} errors", csr::serwb_phy_rtm::control_prbs_errors_read()); - } + // Wishbone test + wishbone_test(); // Try reading the magic number register on the other side of the bridge. let rtm_magic = unsafe { From c9287cfc691eb03d1d88ad420b056ca630e475b1 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 24 May 2018 21:09:50 +0000 Subject: [PATCH 0836/2457] conda: put `noarch: python` on correct artiq-board package. Fixes #989. --- conda/artiq-board/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index db5a37cf9..dc4d04b74 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -16,9 +16,9 @@ build: outputs: - name: artiq-{{ environ["ARTIQ_TARGET"] }}-{{ environ["ARTIQ_VARIANT"] }} - noarch: generic + noarch: python files: - - lib + - site-packages requirements: run: - artiq {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} From 12d1b9819ce06a38e849bab48640867802d4a63f Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 25 May 2018 02:02:18 +0000 Subject: [PATCH 0837/2457] compiler: handle direct calls to class methods. Fixes #1005. --- artiq/compiler/transforms/__init__.py | 2 +- .../compiler/transforms/llvm_ir_generator.py | 13 ++++++++++-- .../lit/embedding/class_fn_direct_call.py | 20 +++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 artiq/test/lit/embedding/class_fn_direct_call.py diff --git a/artiq/compiler/transforms/__init__.py b/artiq/compiler/transforms/__init__.py index ccaab7636..64ee25c46 100644 --- a/artiq/compiler/transforms/__init__.py +++ b/artiq/compiler/transforms/__init__.py @@ -6,6 +6,6 @@ from .iodelay_estimator import IODelayEstimator from .artiq_ir_generator import ARTIQIRGenerator from .dead_code_eliminator import DeadCodeEliminator from .local_demoter import LocalDemoter -from .llvm_ir_generator import LLVMIRGenerator from .interleaver import Interleaver from .typedtree_printer import TypedtreePrinter +from .llvm_ir_generator import LLVMIRGenerator diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 6dc76c592..b2fea1852 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -9,6 +9,7 @@ from pythonparser import ast, diagnostic from llvmlite_artiq import ir as ll, binding as llvm from ...language import core as language_core from .. import types, builtins, ir +from ..embedding import SpecializedFunction llvoid = ll.VoidType() @@ -1549,8 +1550,16 @@ class LLVMIRGenerator: # RPC and C functions have no runtime representation. return ll.Constant(llty, ll.Undefined) elif types.is_function(typ): - return self.get_function_with_undef_env(typ.find(), - self.embedding_map.retrieve_function(value)) + try: + func = self.embedding_map.retrieve_function(value) + except KeyError: + # If a class function was embedded directly (e.g. by a `C.f(...)` call), + # but it also appears in a class hierarchy, we might need to fall back + # to the non-specialized one, since direct invocations do not cause + # monomorphization. + assert isinstance(value, SpecializedFunction) + func = self.embedding_map.retrieve_function(value.host_function) + return self.get_function_with_undef_env(typ.find(), func) elif types.is_method(typ): llclosure = self._quote(value.__func__, types.get_method_function(typ), lambda: path() + ['__func__']) diff --git a/artiq/test/lit/embedding/class_fn_direct_call.py b/artiq/test/lit/embedding/class_fn_direct_call.py new file mode 100644 index 000000000..91bdac519 --- /dev/null +++ b/artiq/test/lit/embedding/class_fn_direct_call.py @@ -0,0 +1,20 @@ +# RUN: %python -m artiq.compiler.testbench.embedding %s + +from artiq.language.core import * +from artiq.language.types import * + +class C: + @kernel + def f(self): + pass + +class D(C): + @kernel + def f(self): + # super().f() # super() not bound + C.f(self) # KeyError in compile + +di = D() +@kernel +def entrypoint(): + di.f() From fbf2c9a2fba42a48112606a28b196605f9227e04 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 25 May 2018 02:18:13 +0000 Subject: [PATCH 0838/2457] compiler: hoist loads of kernel invariants to function entry block. Addresses intraprocedural cases of #1007. --- artiq/compiler/module.py | 2 + artiq/compiler/transforms/__init__.py | 1 + artiq/compiler/transforms/constant_hoister.py | 44 +++++++++++++++++++ artiq/test/lit/constant_hoisting/device_db.py | 8 ++++ .../lit/constant_hoisting/invariant_load.py | 25 +++++++++++ 5 files changed, 80 insertions(+) create mode 100644 artiq/compiler/transforms/constant_hoister.py create mode 100644 artiq/test/lit/constant_hoisting/device_db.py create mode 100644 artiq/test/lit/constant_hoisting/invariant_load.py diff --git a/artiq/compiler/module.py b/artiq/compiler/module.py index 8e7091b81..cea86cddb 100644 --- a/artiq/compiler/module.py +++ b/artiq/compiler/module.py @@ -61,6 +61,7 @@ class Module: dead_code_eliminator = transforms.DeadCodeEliminator(engine=self.engine) local_access_validator = validators.LocalAccessValidator(engine=self.engine) local_demoter = transforms.LocalDemoter() + constant_hoister = transforms.ConstantHoister() devirtualization = analyses.Devirtualization() interleaver = transforms.Interleaver(engine=self.engine) invariant_detection = analyses.InvariantDetection(engine=self.engine) @@ -79,6 +80,7 @@ class Module: interleaver.process(self.artiq_ir) local_access_validator.process(self.artiq_ir) local_demoter.process(self.artiq_ir) + constant_hoister.process(self.artiq_ir) if remarks: invariant_detection.process(self.artiq_ir) diff --git a/artiq/compiler/transforms/__init__.py b/artiq/compiler/transforms/__init__.py index 64ee25c46..5696be95f 100644 --- a/artiq/compiler/transforms/__init__.py +++ b/artiq/compiler/transforms/__init__.py @@ -6,6 +6,7 @@ from .iodelay_estimator import IODelayEstimator from .artiq_ir_generator import ARTIQIRGenerator from .dead_code_eliminator import DeadCodeEliminator from .local_demoter import LocalDemoter +from .constant_hoister import ConstantHoister from .interleaver import Interleaver from .typedtree_printer import TypedtreePrinter from .llvm_ir_generator import LLVMIRGenerator diff --git a/artiq/compiler/transforms/constant_hoister.py b/artiq/compiler/transforms/constant_hoister.py new file mode 100644 index 000000000..0484b1c39 --- /dev/null +++ b/artiq/compiler/transforms/constant_hoister.py @@ -0,0 +1,44 @@ +""" +:class:`ConstantHoister` is a code motion transform: +it moves any invariant loads to the earliest point where +they may be executed. +""" + +from .. import types, ir + +class ConstantHoister: + def process(self, functions): + for func in functions: + self.process_function(func) + + def process_function(self, func): + entry = func.entry() + worklist = set(func.instructions()) + moved = set() + while len(worklist) > 0: + insn = worklist.pop() + + if (isinstance(insn, ir.GetAttr) and insn not in moved and + types.is_instance(insn.object().type) and + insn.attr in insn.object().type.constant_attributes): + has_variant_operands = False + index_in_entry = 0 + for operand in insn.operands: + if isinstance(operand, ir.Argument): + pass + elif isinstance(operand, ir.Instruction) and operand.basic_block == entry: + index_in_entry = entry.index(operand) + 1 + else: + has_variant_operands = True + break + + if has_variant_operands: + continue + + insn.remove_from_parent() + entry.instructions.insert(index_in_entry, insn) + moved.add(insn) + print(insn) + + for use in insn.uses: + worklist.add(use) diff --git a/artiq/test/lit/constant_hoisting/device_db.py b/artiq/test/lit/constant_hoisting/device_db.py new file mode 100644 index 000000000..e39c83c09 --- /dev/null +++ b/artiq/test/lit/constant_hoisting/device_db.py @@ -0,0 +1,8 @@ +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": None, "ref_period": 1e-9} + } +} diff --git a/artiq/test/lit/constant_hoisting/invariant_load.py b/artiq/test/lit/constant_hoisting/invariant_load.py new file mode 100644 index 000000000..62fac4202 --- /dev/null +++ b/artiq/test/lit/constant_hoisting/invariant_load.py @@ -0,0 +1,25 @@ +# RUN: env ARTIQ_DUMP_IR=%t ARTIQ_IR_NO_LOC=1 %python -m artiq.compiler.testbench.embedding +compile %s +# RUN: OutputCheck %s --file-to-check=%t.txt + +from artiq.language.core import * +from artiq.language.types import * + +# CHECK-L: %LOC.self.FLD.foo = numpy.int32 getattr('foo') %ARG.self +# CHECK-L: for.head: + +class c: + kernel_invariants = {"foo"} + + def __init__(self): + self.foo = 1 + + @kernel + def run(self): + for _ in range(10): + core_log(1.0 * self.foo) + +i = c() + +@kernel +def entrypoint(): + i.run() From 44910efd0a85ae76945190ed704de3aab78ae6cf Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 25 May 2018 02:23:18 +0000 Subject: [PATCH 0839/2457] conda: remove lib/python3.5 from artiq package paths as well. Following c9287cfc. --- conda/artiq/build.sh | 9 +++++++++ conda/artiq/meta.yaml | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 conda/artiq/build.sh diff --git a/conda/artiq/build.sh b/conda/artiq/build.sh new file mode 100644 index 000000000..a2bff5018 --- /dev/null +++ b/conda/artiq/build.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -e + +$PYTHON setup.py install \ + --prefix=$SP_DIR \ + --single-version-externally-managed \ + --record=record.txt \ + --no-compile diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index 8f699ec5b..3b696aded 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -18,7 +18,6 @@ build: - {{ entry_point }} {% endfor %} {% endfor %} - script: $PYTHON setup.py install --no-compile --single-version-externally-managed --record=record.txt ignore_prefix_files: True requirements: From 223b984385defb84a0829270ae14d65947ba5a86 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 25 May 2018 04:23:32 +0000 Subject: [PATCH 0840/2457] Fix non-exception-safe finally: handlers. Fixes #1013. --- artiq/protocols/logging.py | 4 +++- artiq/protocols/pc_rpc.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/artiq/protocols/logging.py b/artiq/protocols/logging.py index 5c282549a..542e8da35 100644 --- a/artiq/protocols/logging.py +++ b/artiq/protocols/logging.py @@ -168,6 +168,7 @@ class LogForwarder(logging.Handler, TaskObject): self._queue.put_nowait(record.source + ":" + self.format(record)) async def _do(self): + reader = writer = None while True: try: reader, writer = await asyncio.open_connection(self.host, @@ -182,4 +183,5 @@ class LogForwarder(logging.Handler, TaskObject): except: await asyncio.sleep(self.reconnect_timer) finally: - writer.close() + if writer is not None: + writer.close() diff --git a/artiq/protocols/pc_rpc.py b/artiq/protocols/pc_rpc.py index d99ca06fb..410cc8908 100644 --- a/artiq/protocols/pc_rpc.py +++ b/artiq/protocols/pc_rpc.py @@ -243,7 +243,8 @@ class AsyncioClient: No further method calls should be done after this method is called. """ - self.__writer.close() + if self.__writer is not None: + self.__writer.close() self.__reader = None self.__writer = None self.__target_names = None From c3c9ffcd4f111a257842effe4d2771ffbd62ae81 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 25 May 2018 06:45:46 +0000 Subject: [PATCH 0841/2457] conda: override --install-lib, not --prefix. --- conda/artiq/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq/build.sh b/conda/artiq/build.sh index a2bff5018..b3b1f7f73 100644 --- a/conda/artiq/build.sh +++ b/conda/artiq/build.sh @@ -3,7 +3,7 @@ set -e $PYTHON setup.py install \ - --prefix=$SP_DIR \ + --install-lib=$SP_DIR \ --single-version-externally-managed \ --record=record.txt \ --no-compile From bc86ade16050d3a6d5c05d5fef6d0c14307bcc5e Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 25 May 2018 08:41:19 +0000 Subject: [PATCH 0842/2457] conda: add ignore_prefix_files in the outputs section too. --- conda/artiq-board/meta.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index dc4d04b74..b9d82be0b 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -22,6 +22,7 @@ outputs: requirements: run: - artiq {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} + ignore_prefix_files: True requirements: build: From da851d8b7ba4f524870b149bb0c5fc0ff3b79957 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 25 May 2018 08:41:55 +0000 Subject: [PATCH 0843/2457] conda: fix installation path in artiq-board. --- conda/artiq-board/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-board/build.sh b/conda/artiq-board/build.sh index bac341b51..ecf684b33 100644 --- a/conda/artiq-board/build.sh +++ b/conda/artiq-board/build.sh @@ -2,7 +2,7 @@ set -e -SOC_PREFIX=$SP_DIR/artiq/binaries/${ARTIQ_TARGET}-${ARTIQ_VARIANT} +SOC_PREFIX=$PREFIX/site-packages/artiq/binaries/${ARTIQ_TARGET}-${ARTIQ_VARIANT} mkdir -p ${SOC_PREFIX} V=1 $PYTHON -m artiq.gateware.targets.${ARTIQ_TARGET} -V ${ARTIQ_VARIANT} From db4d1878d3528d65b9cace5a151030fa125648a2 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 25 May 2018 09:37:18 +0000 Subject: [PATCH 0844/2457] compiler: remove debug print. --- artiq/compiler/transforms/constant_hoister.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/compiler/transforms/constant_hoister.py b/artiq/compiler/transforms/constant_hoister.py index 0484b1c39..ea51046aa 100644 --- a/artiq/compiler/transforms/constant_hoister.py +++ b/artiq/compiler/transforms/constant_hoister.py @@ -38,7 +38,6 @@ class ConstantHoister: insn.remove_from_parent() entry.instructions.insert(index_in_entry, insn) moved.add(insn) - print(insn) for use in insn.uses: worklist.add(use) From b09d07905c7aa74f744fabbf280ab645098538ac Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 26 May 2018 21:52:57 +0000 Subject: [PATCH 0845/2457] kasli: add LUH/PTB/HUB variants and refactor/simplify variant selection --- artiq/examples/kasli_basic/device_db_hub.py | 169 ++++++++++++++ artiq/examples/kasli_basic/device_db_ptb.py | 233 ++++++++++++++++++++ artiq/gateware/targets/kasli.py | 163 ++++++++++++-- 3 files changed, 544 insertions(+), 21 deletions(-) create mode 100644 artiq/examples/kasli_basic/device_db_hub.py create mode 100644 artiq/examples/kasli_basic/device_db_ptb.py diff --git a/artiq/examples/kasli_basic/device_db_hub.py b/artiq/examples/kasli_basic/device_db_hub.py new file mode 100644 index 000000000..dc2fc2d59 --- /dev/null +++ b/artiq/examples/kasli_basic/device_db_hub.py @@ -0,0 +1,169 @@ +core_addr = "staging.ber.quartiq.de" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + + +device_db.update({ + "ttl" + str(i): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": i}, + } for i in range(24) +}) + + +device_db.update({ + "spi_sampler0_adc": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 24} + }, + "spi_sampler0_pgia": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 25} + }, + "spi_sampler0_cnv": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 26}, + }, + "sampler0": { + "type": "local", + "module": "artiq.coredevice.sampler", + "class": "Sampler", + "arguments": { + "spi_adc_device": "spi_sampler0_adc", + "spi_pgia_device": "spi_sampler0_pgia", + "cnv_device": "spi_sampler0_cnv" + } + } +}) + +for j in range(3): + device_db.update({ + "spi_urukul{}".format(j): { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 27 + 2*j} + }, + "ttl_urukul{}_io_update".format(j): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 28 + 2*j} + }, + "urukul{}_cpld".format(j): { + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul{}".format(j), + "io_update_device": "ttl_urukul{}_io_update".format(j), + "refclk": 100e6, + "clk_sel": 0 + } + } + }) + + device_db.update({ + "urukul{}_ch{}".format(j, i): { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 4 + i, + "cpld_device": "urukul{}_cpld".format(j) + } + } for i in range(4) + }) + + +device_db.update({ + "led0": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 33} + }, + "led1": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 34} + } +}) + + +device_db.update({ + "spi_zotino0": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 35} + }, + "ttl_zotino0_ldac": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 36} + }, + "ttl_zotino0_clr": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 37} + }, + "zotino0": { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino0", + "ldac_device": "ttl_zotino0_ldac", + "clr_device": "ttl_zotino0_clr" + } + } +}) diff --git a/artiq/examples/kasli_basic/device_db_ptb.py b/artiq/examples/kasli_basic/device_db_ptb.py new file mode 100644 index 000000000..cc04d1090 --- /dev/null +++ b/artiq/examples/kasli_basic/device_db_ptb.py @@ -0,0 +1,233 @@ +core_addr = "staging.ber.quartiq.de" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + + +device_db.update({ + "ttl" + str(i): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": i}, + } for i in range(24) +}) + + +device_db.update({ + "spi_sampler0_adc": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 24} + }, + "spi_sampler0_pgia": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 25} + }, + "spi_sampler0_cnv": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 26}, + }, + "sampler0": { + "type": "local", + "module": "artiq.coredevice.sampler", + "class": "Sampler", + "arguments": { + "spi_adc_device": "spi_sampler0_adc", + "spi_pgia_device": "spi_sampler0_pgia", + "cnv_device": "spi_sampler0_cnv" + } + } +}) + +device_db.update({ + "spi_urukul0": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 27} + }, + "ttl_urukul0_io_update": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 28} + }, + "ttl_urukul0_sw0": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 29} + }, + "ttl_urukul0_sw1": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 30} + }, + "ttl_urukul0_sw2": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 31} + }, + "ttl_urukul0_sw3": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 32} + }, + "urukul0_cpld": { + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 100e6, + "clk_sel": 0 + } + } +}) + +device_db.update({ + "urukul0_ch" + str(i): { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } for i in range(4) +}) + + +device_db.update({ + "spi_urukul1": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 33} + }, + "ttl_urukul1_io_update": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 34} + }, + "urukul1_cpld": { + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul1", + "io_update_device": "ttl_urukul1_io_update", + "refclk": 100e6, + "clk_sel": 0 + } + } +}) + +device_db.update({ + "urukul1_ch" + str(i): { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 4 + i, + "cpld_device": "urukul1_cpld" + } + } for i in range(4) +}) + + +device_db.update({ + "led0": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 35} + }, + "led1": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 36} + } +}) + + +device_db.update({ + "spi_zotino0": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 37} + }, + "ttl_zotino0_ldac": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 38} + }, + "ttl_zotino0_clr": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 39} + }, + "zotino0": { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino0", + "ldac_device": "ttl_zotino0_ldac", + "clr_device": "ttl_zotino0_clr" + } + } +}) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index de4dd9e15..72308a1c7 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -395,6 +395,139 @@ class USTC(_StandaloneBase): self.add_rtio(self.rtio_channels) +class PTB(_StandaloneBase): + """PTB Kasli variant + + F.k.a. ptb-schmidt, ptb-mehlstaeubler, ptb-huntemann-11, ptb-huntemann-19, + and ufr-warring in the artiq-setup repository + """ + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + # self.config["SI5324_EXT_REF"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) + + self.rtio_channels = [] + eem.DIO.add_std(self, 0, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 1, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 2, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 5, 4, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X) + + for i in (1, 2): + sfp_ctl = self.platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(self.rtio_channels) + + +class HUB(_StandaloneBase): + """HUB Kasli variant + + F.k.a. hub-krutzik, luh-ospelkaus-13, and luh-ospelkaus-14 + in the artiq-setup repository + """ + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + # self.config["SI5324_EXT_REF"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) + + self.rtio_channels = [] + eem.DIO.add_std(self, 0, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 1, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 2, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 4, None, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 5, None, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X) + + for i in (1, 2): + sfp_ctl = self.platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(self.rtio_channels) + + +class LUH(_StandaloneBase): + """LUH Kasli variant + + F.k.a. luh-ospelkaus-16, luh-ospelkaus-18 in the artiq-setup repository + """ + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + # self.config["SI5324_EXT_REF"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) + + self.rtio_channels = [] + eem.DIO.add_std(self, 0, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 1, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 2, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 4, None, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 5, None, ttl_serdes_7series.Output_8X) + eem.Grabber.add_std(self, 6, ttl_serdes_7series.Output_8X) + + for i in (1, 2): + sfp_ctl = self.platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(self.rtio_channels) + + class Tester(_StandaloneBase): """ Configuration for CI tests. Contains the maximum number of different EEMs. @@ -417,7 +550,7 @@ class Tester(_StandaloneBase): eem.Urukul.add_std(self, 1, 0, ttl_serdes_7series.Output_8X) eem.Sampler.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) eem.Zotino.add_std(self, 4, ttl_serdes_7series.Output_8X) - + for i in (1, 2): sfp_ctl = self.platform.request("sfp_ctl", i) phy = ttl_simple.Output(sfp_ctl.led) @@ -725,30 +858,18 @@ def main(): builder_args(parser) soc_kasli_args(parser) parser.set_defaults(output_dir="artiq_kasli") + variants = {cls.__name__.lower(): cls for cls in [ + Opticlock, SUServo, SYSU, MITLL, USTC, PTB, HUB, LUH, + Tester, Master, Satellite]} parser.add_argument("-V", "--variant", default="opticlock", - help="variant: opticlock/suservo/sysu/mitll/ustc/" - "tester/master/satellite " - "(default: %(default)s)") + help="variant: {} (default: %(default)s)".format( + "/".join(sorted(variants.keys())))) args = parser.parse_args() variant = args.variant.lower() - if variant == "opticlock": - cls = Opticlock - elif variant == "suservo": - cls = SUServo - elif variant == "sysu": - cls = SYSU - elif variant == "mitll": - cls = MITLL - elif variant == "ustc": - cls = USTC - elif variant == "tester": - cls = Tester - elif variant == "master": - cls = Master - elif variant == "satellite": - cls = Satellite - else: + try: + cls = variants[variant] + except KeyError: raise SystemExit("Invalid variant (-V/--variant)") soc = cls(**soc_kasli_argdict(args)) From 56cfe77c91ce17db37ee7b2342b2b0d3d3f6b78f Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Wed, 23 May 2018 09:33:24 +0200 Subject: [PATCH 0846/2457] environment: spelling --- artiq/language/environment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/language/environment.py b/artiq/language/environment.py index ccfdcdb72..a7d7ae55f 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -395,7 +395,7 @@ class EnvExperiment(Experiment, HasEnvironment): """Base class for top-level experiments that use the ``HasEnvironment`` environment manager. - Most experiment should derive from this class.""" + Most experiments should derive from this class.""" def prepare(self): """The default prepare method calls prepare for all children, in the order of instantiation, if the child has a prepare method.""" From bb248970df68eaeb6b136e2b60d6c8a0ae32d195 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 May 2018 10:40:05 +0800 Subject: [PATCH 0847/2457] style --- artiq/gateware/eem.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 7566651cd..9c4701e98 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -71,7 +71,7 @@ class Urukul(_EEM): *(_eem_pin(eem, i + 3, "n") for i in range(3)))), IOStandard("LVDS_25"), ), - ] + ] ttls = [(6, eem, "io_update"), (7, eem, "dds_reset")] if eem_aux is not None: @@ -109,7 +109,7 @@ class Urukul(_EEM): _eem_pin(eem0, 3, "n"), _eem_pin(eem0, 4, "n"))), IOStandard("LVDS_25"), ), - ] + ] ttls = [(6, eem0, "io_update"), (7, eem0, "dds_reset"), (4, eem1, "sw0"), @@ -321,7 +321,7 @@ class Zotino(_EEM): _eem_pin(eem, 3, "n"), _eem_pin(eem, 4, "n"))), IOStandard("LVDS_25"), ), - ] + [ + ] + [ ("zotino{}_{}".format(eem, sig), 0, Subsignal("p", Pins(_eem_pin(j, i, "p"))), Subsignal("n", Pins(_eem_pin(j, i, "n"))), @@ -331,7 +331,7 @@ class Zotino(_EEM): (6, eem, "busy"), (7, eem, "clr_n"), ] - ] + ] @classmethod def add_std(cls, target, eem, ttl_out_cls): From cc0ddf9d7245838f4a0d8fef3c3ea13f7ea76f10 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 May 2018 10:59:01 +0800 Subject: [PATCH 0848/2457] artiq_flash: do not check variants anymore Not very useful and adds to the maintainance when building new Kasli systems. --- artiq/frontend/artiq_flash.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 4f121e92e..813cd7846 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -260,7 +260,7 @@ def main(): config = { "kc705": { "programmer": partial(ProgrammerXC7, board="kc705", proxy="bscan_spi_xc7k325t.bit"), - "variants": ["nist_clock", "nist_qc2"], + "def_variant": "nist_clock", "gateware": ("spi0", 0x000000), "bootloader": ("spi0", 0xaf0000), "storage": ("spi0", 0xb30000), @@ -268,8 +268,7 @@ def main(): }, "kasli": { "programmer": partial(ProgrammerXC7, board="kasli", proxy="bscan_spi_xc7a100t.bit"), - "variants": ["opticlock", "suservo", "sysu", "mitll", "ustc", - "tester", "master", "satellite"], + "def_variant": "opticlock", "gateware": ("spi0", 0x000000), "bootloader": ("spi0", 0x400000), "storage": ("spi0", 0x440000), @@ -277,7 +276,7 @@ def main(): }, "sayma": { "programmer": ProgrammerSayma, - "variants": ["standalone", "master", "satellite"], + "def_variant": "standalone", "gateware": ("spi0", 0x000000), "bootloader": ("spi1", 0x000000), "storage": ("spi1", 0x040000), @@ -287,11 +286,8 @@ def main(): }[args.target] variant = args.variant - if "variants" in config: - if variant is not None and variant not in config["variants"]: - raise SystemExit("Invalid variant for this board") - if variant is None: - variant = config["variants"][0] + if variant is None: + variant = config["def_variant"] bin_dir = args.dir if bin_dir is None: From 4d3f76386502557c7e783b87dda134b6da684266 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 May 2018 11:02:44 +0800 Subject: [PATCH 0849/2457] move kasli_opticlock to kasli_basic --- .../device_db_opticlock.py} | 0 .../idle_kernel.py | 0 .../kasli_opticlock/repository/urukul.py | 49 ------------------- 3 files changed, 49 deletions(-) rename artiq/examples/{kasli_opticlock/device_db.py => kasli_basic/device_db_opticlock.py} (100%) rename artiq/examples/{kasli_opticlock => kasli_basic}/idle_kernel.py (100%) delete mode 100644 artiq/examples/kasli_opticlock/repository/urukul.py diff --git a/artiq/examples/kasli_opticlock/device_db.py b/artiq/examples/kasli_basic/device_db_opticlock.py similarity index 100% rename from artiq/examples/kasli_opticlock/device_db.py rename to artiq/examples/kasli_basic/device_db_opticlock.py diff --git a/artiq/examples/kasli_opticlock/idle_kernel.py b/artiq/examples/kasli_basic/idle_kernel.py similarity index 100% rename from artiq/examples/kasli_opticlock/idle_kernel.py rename to artiq/examples/kasli_basic/idle_kernel.py diff --git a/artiq/examples/kasli_opticlock/repository/urukul.py b/artiq/examples/kasli_opticlock/repository/urukul.py deleted file mode 100644 index 39b8ea3c2..000000000 --- a/artiq/examples/kasli_opticlock/repository/urukul.py +++ /dev/null @@ -1,49 +0,0 @@ -from artiq.experiment import * - - -class UrukulTest(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("urukul0_cpld") - self.setattr_device("urukul0_ch0") - self.setattr_device("urukul0_ch1") - self.setattr_device("urukul0_ch2") - self.setattr_device("urukul0_ch3") - self.setattr_device("led0") - - @kernel - def run(self): - self.core.reset() - self.led0.on() - delay(5*ms) - self.led0.off() - - self.urukul0_cpld.init() - self.urukul0_ch0.init() - self.urukul0_ch1.init() - self.urukul0_ch2.init() - self.urukul0_ch3.init() - - delay(1000*us) - self.urukul0_ch0.set(100*MHz) - self.urukul0_ch0.sw.on() - self.urukul0_ch0.set_att(10.) - - delay(1000*us) - self.urukul0_ch1.set(10*MHz, 0.5) - self.urukul0_ch1.sw.on() - self.urukul0_ch1.set_att(0.) - - delay(1000*us) - self.urukul0_ch2.set(400*MHz) - self.urukul0_ch2.sw.on() - self.urukul0_ch2.set_att(0.) - - delay(1000*us) - self.urukul0_ch3.set(1*MHz) - self.urukul0_ch3.sw.on() - self.urukul0_ch3.set_att(20.) - - while True: - self.urukul0_ch0.sw.pulse(5*ms) - delay(5*ms) From 80c69da17e3e927d35cf5acd18e3f0e5dfb9c6ab Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 May 2018 11:16:17 +0800 Subject: [PATCH 0850/2457] eem: add Grabber IOs and CC --- artiq/gateware/eem.py | 82 +++++++++++++++++++++++++++++++++ artiq/gateware/targets/kasli.py | 2 +- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 9c4701e98..127cb40ce 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -347,3 +347,85 @@ class Zotino(_EEM): phy = ttl_out_cls(pads.p, pads.n) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy)) + + +class Grabber(_EEM): + @staticmethod + def io(eem, eem_aux): + ios = [ + ("grabber{}_video".format(eem), 0, + Subsignal("xclk_p", Pins(_eem_pin(eem, 0, "p"))), + Subsignal("xclk_n", Pins(_eem_pin(eem, 0, "n"))), + Subsignal("x0_p", Pins(_eem_pin(eem, 1, "p"))), + Subsignal("x0_n", Pins(_eem_pin(eem, 1, "n"))), + Subsignal("x1_p", Pins(_eem_pin(eem, 2, "p"))), + Subsignal("x1_n", Pins(_eem_pin(eem, 2, "n"))), + Subsignal("x2_p", Pins(_eem_pin(eem, 3, "p"))), + Subsignal("x2_n", Pins(_eem_pin(eem, 3, "n"))), + Subsignal("x3_p", Pins(_eem_pin(eem, 4, "p"))), + Subsignal("x3_n", Pins(_eem_pin(eem, 4, "n"))), + IOStandard("LVDS_25") + ), + ("grabber{}_cc0".format(eem), 0, + Subsignal("p", Pins(_eem_pin(eem_aux, 5, "p"))), + Subsignal("n", Pins(_eem_pin(eem_aux, 5, "n"))), + IOStandard("LVDS_25") + ), + ("grabber{}_cc1".format(eem), 0, + Subsignal("p", Pins(_eem_pin(eem_aux, 6, "p"))), + Subsignal("n", Pins(_eem_pin(eem_aux, 6, "n"))), + IOStandard("LVDS_25") + ), + ("grabber{}_cc2".format(eem), 0, + Subsignal("p", Pins(_eem_pin(eem_aux, 7, "p"))), + Subsignal("n", Pins(_eem_pin(eem_aux, 7, "n"))), + IOStandard("LVDS_25") + ), + ] + if eem_aux is not None: + ios += [ + ("grabber{}_video_m".format(eem), 0, + Subsignal("yclk_p", Pins(_eem_pin(eem_aux, 0, "p"))), + Subsignal("yclk_n", Pins(_eem_pin(eem_aux, 0, "n"))), + Subsignal("y0_p", Pins(_eem_pin(eem_aux, 1, "p"))), + Subsignal("y0_n", Pins(_eem_pin(eem_aux, 1, "n"))), + Subsignal("y1_p", Pins(_eem_pin(eem_aux, 2, "p"))), + Subsignal("y1_n", Pins(_eem_pin(eem_aux, 2, "n"))), + Subsignal("y2_p", Pins(_eem_pin(eem_aux, 3, "p"))), + Subsignal("y2_n", Pins(_eem_pin(eem_aux, 3, "n"))), + Subsignal("y3_p", Pins(_eem_pin(eem_aux, 4, "p"))), + Subsignal("y3_n", Pins(_eem_pin(eem_aux, 4, "n"))), + IOStandard("LVDS_25") + ), + ("grabber{}_serrx".format(eem), 0, + Subsignal("p", Pins(_eem_pin(eem_aux, 5, "p"))), + Subsignal("n", Pins(_eem_pin(eem_aux, 5, "n"))), + IOStandard("LVDS_25") + ), + ("grabber{}_sertx".format(eem), 0, + Subsignal("p", Pins(_eem_pin(eem_aux, 6, "p"))), + Subsignal("n", Pins(_eem_pin(eem_aux, 6, "n"))), + IOStandard("LVDS_25") + ), + ("grabber{}_cc3".format(eem), 0, + Subsignal("p", Pins(_eem_pin(eem_aux, 7, "p"))), + Subsignal("n", Pins(_eem_pin(eem_aux, 7, "n"))), + IOStandard("LVDS_25") + ), + ] + return ios + + @classmethod + def add_std(cls, target, eem, eem_aux, ttl_out_cls): + cls.add_extension(target, eem, eem_aux) + + for signal in "cc0 cc1 cc2".split(): + pads = target.platform.request("grabber{}_{}".format(eem, signal)) + phy = ttl_out_cls(pads.p, pads.n) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy)) + if eem_aux is not None: + pads = target.platform.request("grabber{}_cc3".format(eem)) + phy = ttl_out_cls(pads.p, pads.n) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy)) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 72308a1c7..5eaecbc24 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -511,7 +511,7 @@ class LUH(_StandaloneBase): eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) eem.Urukul.add_std(self, 4, None, ttl_serdes_7series.Output_8X) eem.Urukul.add_std(self, 5, None, ttl_serdes_7series.Output_8X) - eem.Grabber.add_std(self, 6, ttl_serdes_7series.Output_8X) + eem.Grabber.add_std(self, 6, None, ttl_simple.Output) for i in (1, 2): sfp_ctl = self.platform.request("sfp_ctl", i) From b20a8c86b0b28e542b3db3dab5eaafddd1f8ec19 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 28 May 2018 07:29:08 +0200 Subject: [PATCH 0851/2457] kasli: don't bother with grabber ttls for now not used on target cameras --- artiq/gateware/targets/kasli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 5eaecbc24..e28ea61e5 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -511,7 +511,7 @@ class LUH(_StandaloneBase): eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) eem.Urukul.add_std(self, 4, None, ttl_serdes_7series.Output_8X) eem.Urukul.add_std(self, 5, None, ttl_serdes_7series.Output_8X) - eem.Grabber.add_std(self, 6, None, ttl_simple.Output) + eem.Grabber.add_std(self, 6) for i in (1, 2): sfp_ctl = self.platform.request("sfp_ctl", i) From c2890c6cf099ad8495dc89efbce6e47a6b68fe91 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 May 2018 14:22:06 +0800 Subject: [PATCH 0852/2457] kasli_tester: initialize DDS channels --- artiq/examples/kasli_basic/repository/kasli_tester.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index 2b6842a11..db1af4d2b 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -152,6 +152,7 @@ class KasliTester(EnvExperiment): @kernel def setup_urukul(self, channel, frequency): self.core.break_realtime() + channel.init() channel.set(frequency*MHz) channel.sw.on() channel.set_att(6.) From e21f14c0b31ca0b1ef3efe4e6e71d8eff9832293 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 28 May 2018 10:41:11 +0200 Subject: [PATCH 0853/2457] serwb/phy: typo (KUSSerdes --> KUSerdes) --- artiq/gateware/serwb/phy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index a7c201e65..83f47ed27 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -348,7 +348,7 @@ class SERWBPHY(Module, AutoCSR): assert mode in ["master", "slave"] if device[:4] == "xcku": taps = 512 - self.submodules.serdes = KUSSerdes(pads, mode) + self.submodules.serdes = KUSerdes(pads, mode) elif device[:4] == "xc7a": taps = 32 self.submodules.serdes = S7Serdes(pads, mode) From 2612fd1e721eda17a9e176f8d47b5ce3d1a1110d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 May 2018 22:42:27 +0800 Subject: [PATCH 0854/2457] rtio: add grabber deserializer and WIP PHY encapsulation --- artiq/gateware/grabber/__init__.py | 0 .../gateware/grabber/deserializer_7series.py | 124 ++++++++++++++++++ artiq/gateware/rtio/phy/grabber.py | 16 +++ 3 files changed, 140 insertions(+) create mode 100644 artiq/gateware/grabber/__init__.py create mode 100644 artiq/gateware/grabber/deserializer_7series.py create mode 100644 artiq/gateware/rtio/phy/grabber.py diff --git a/artiq/gateware/grabber/__init__.py b/artiq/gateware/grabber/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/artiq/gateware/grabber/deserializer_7series.py b/artiq/gateware/grabber/deserializer_7series.py new file mode 100644 index 000000000..b7336a578 --- /dev/null +++ b/artiq/gateware/grabber/deserializer_7series.py @@ -0,0 +1,124 @@ +from migen import * +from migen.genlib.cdc import MultiReg +from migen.genlib.resetsync import AsyncResetSynchronizer + +from misoc.interconnect.csr import * + + +# See: +# http://www.volkerschatz.com/hardware/clink.html + +class Deserializer(Module, AutoCSR): + def __init__(self, pins): + self.pll_reset = CSRStorage(reset=1) + self.pll_locked = CSRStatus() + self.phase_shift = CSR() + self.phase_shift_done = CSRStatus(reset=1) + self.clk_sampled = CSRStatus(7) + + self.q_clk = Signal(7) + self.q = Signal(7*len(pins.sdi_p)) + + self.clock_domains.cd_cl = ClockDomain() + self.clock_domains.cd_cl7x = ClockDomain() + + # # # + + clk_se = Signal() + self.specials += Instance("IBUFDS", + i_I=pins.clk_p, i_IB=pins.clk_n, o_O=clk_se) + + clk_se_iserdes = Signal() + self.specials += [ + Instance("ISERDESE2", + p_DATA_WIDTH=7, p_DATA_RATE="SDR", + p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", + p_NUM_CE=1, + + i_D=clk_se, + o_O=clk_se_iserdes, + i_CE1=1, + i_CLKDIV=ClockSignal("cl"), i_RST=ResetSignal("cl"), + i_CLK=ClockSignal("cl7x"), i_CLKB=~ClockSignal("cl7x"), + o_Q1=self.q_clk[6], + o_Q2=self.q_clk[5], o_Q3=self.q_clk[4], + o_Q4=self.q_clk[3], o_Q5=self.q_clk[2], + o_Q6=self.q_clk[1], o_Q7=self.q_clk[0] + ) + ] + + sdi_se = Signal(len(pins.sdi_p)) + for i in range(len(pins.sdi_p)): + self.specials += [ + Instance("IBUFDS", i_I=pins.sdi_p[i], i_IB=pins.sdi_n[i], + o_O=sdi_se[i]), + Instance("ISERDESE2", + p_DATA_WIDTH=7, p_DATA_RATE="SDR", + p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", + p_NUM_CE=1, + + i_D=sdi_se[i], + i_CE1=1, + i_CLKDIV=ClockSignal("cl"), i_RST=ResetSignal("cl"), + i_CLK=ClockSignal("cl7x"), i_CLKB=~ClockSignal("cl7x"), + o_Q1=self.q[7*i+6], + o_Q2=self.q[7*i+5], o_Q3=self.q[7*i+4], + o_Q4=self.q[7*i+3], o_Q5=self.q[7*i+2], + o_Q6=self.q[7*i+1], o_Q7=self.q[7*i+0] + ) + ] + + # CL clock frequency 40-85MHz + # A7-2 MMCM VCO frequency 600-1440MHz + # A7-2 PLL VCO frequency 800-1866MHz + # with current MMCM settings, CL frequency limited to 40-~68MHz + # TODO: switch to the PLL, whose VCO range better matches the CL + # clock frequencies. Needs DRP for dynamic phase shift, see XAPP888. + pll_reset = Signal(reset=1) + mmcm_fb = Signal() + mmcm_locked = Signal() + mmcm_ps_psdone = Signal() + cl_clk = Signal() + cl7x_clk = Signal() + phase = 257.0 + self.specials += [ + Instance("MMCME2_ADV", + p_CLKIN1_PERIOD=18.0, + i_CLKIN1=clk_se_iserdes, + i_RST=pll_reset, + i_CLKINSEL=1, # yes, 1=CLKIN1 0=CLKIN2 + + p_CLKFBOUT_MULT_F=21.0, + p_DIVCLK_DIVIDE=1, + o_LOCKED=mmcm_locked, + + o_CLKFBOUT=mmcm_fb, i_CLKFBIN=mmcm_fb, + + p_CLKOUT0_USE_FINE_PS="TRUE", + p_CLKOUT0_DIVIDE_F=21.0, + p_CLKOUT0_PHASE=phase, + o_CLKOUT0=cl_clk, + + p_CLKOUT1_USE_FINE_PS="TRUE", + p_CLKOUT1_DIVIDE=3, + p_CLKOUT1_PHASE=phase*7 % 360.0, + o_CLKOUT1=cl7x_clk, + + i_PSCLK=ClockSignal(), + i_PSEN=self.phase_shift.re, + i_PSINCDEC=self.phase_shift.r, + o_PSDONE=mmcm_ps_psdone, + ), + Instance("BUFG", i_I=cl_clk, o_O=self.cd_cl.clk), + Instance("BUFG", i_I=cl7x_clk, o_O=self.cd_cl7x.clk), + AsyncResetSynchronizer(self.cd_cl, ~mmcm_locked), + ] + self.sync += [ + If(self.phase_shift.re, self.phase_shift_done.status.eq(0)), + If(mmcm_ps_psdone, self.phase_shift_done.status.eq(1)) + ] + self.specials += MultiReg(self.q_clk, self.clk_sampled.status) + + self.specials += MultiReg(mmcm_locked, self.pll_locked.status) + pll_reset.attr.add("no_retiming") + self.sync += pll_reset.eq(self.pll_reset.storage) diff --git a/artiq/gateware/rtio/phy/grabber.py b/artiq/gateware/rtio/phy/grabber.py new file mode 100644 index 000000000..9d1a151d7 --- /dev/null +++ b/artiq/gateware/rtio/phy/grabber.py @@ -0,0 +1,16 @@ +from migen import * + +from artiq.gateware.rtio import rtlink +from artiq.gateware.grabber import deserializer_7series + + +class Grabber(Module): + def __init__(self, pins): + self.config = rtlink.Interface(rtlink.OInterface(10)) + self.gate_data = rtlink.Interface(rtlink.OInterface(1), + rtlink.IInterface(10)) + + self.submodules.deserializer = deserializer_7series.Deserializer(pins) + + def get_csrs(self): + return self.deserializer.get_csrs() From 563e434e15bf82ddb5b7a5581bc00eb1c7ef72dc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 May 2018 22:43:06 +0800 Subject: [PATCH 0855/2457] eem: finalize grabber support --- artiq/gateware/eem.py | 64 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 127cb40ce..007430338 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -3,7 +3,7 @@ from migen.build.generic_platform import * from migen.genlib.io import DifferentialOutput from artiq.gateware import rtio -from artiq.gateware.rtio.phy import spi2 +from artiq.gateware.rtio.phy import spi2, grabber def _eem_signal(i): @@ -354,16 +354,10 @@ class Grabber(_EEM): def io(eem, eem_aux): ios = [ ("grabber{}_video".format(eem), 0, - Subsignal("xclk_p", Pins(_eem_pin(eem, 0, "p"))), - Subsignal("xclk_n", Pins(_eem_pin(eem, 0, "n"))), - Subsignal("x0_p", Pins(_eem_pin(eem, 1, "p"))), - Subsignal("x0_n", Pins(_eem_pin(eem, 1, "n"))), - Subsignal("x1_p", Pins(_eem_pin(eem, 2, "p"))), - Subsignal("x1_n", Pins(_eem_pin(eem, 2, "n"))), - Subsignal("x2_p", Pins(_eem_pin(eem, 3, "p"))), - Subsignal("x2_n", Pins(_eem_pin(eem, 3, "n"))), - Subsignal("x3_p", Pins(_eem_pin(eem, 4, "p"))), - Subsignal("x3_n", Pins(_eem_pin(eem, 4, "n"))), + Subsignal("clk_p", Pins(_eem_pin(eem, 0, "p"))), + Subsignal("clk_n", Pins(_eem_pin(eem, 0, "n"))), + Subsignal("sdi_p", Pins(*[_eem_pin(eem, i, "p") for i in range(1, 5)])), + Subsignal("sdi_n", Pins(*[_eem_pin(eem, i, "n") for i in range(1, 5)])), IOStandard("LVDS_25") ), ("grabber{}_cc0".format(eem), 0, @@ -385,16 +379,10 @@ class Grabber(_EEM): if eem_aux is not None: ios += [ ("grabber{}_video_m".format(eem), 0, - Subsignal("yclk_p", Pins(_eem_pin(eem_aux, 0, "p"))), - Subsignal("yclk_n", Pins(_eem_pin(eem_aux, 0, "n"))), - Subsignal("y0_p", Pins(_eem_pin(eem_aux, 1, "p"))), - Subsignal("y0_n", Pins(_eem_pin(eem_aux, 1, "n"))), - Subsignal("y1_p", Pins(_eem_pin(eem_aux, 2, "p"))), - Subsignal("y1_n", Pins(_eem_pin(eem_aux, 2, "n"))), - Subsignal("y2_p", Pins(_eem_pin(eem_aux, 3, "p"))), - Subsignal("y2_n", Pins(_eem_pin(eem_aux, 3, "n"))), - Subsignal("y3_p", Pins(_eem_pin(eem_aux, 4, "p"))), - Subsignal("y3_n", Pins(_eem_pin(eem_aux, 4, "n"))), + Subsignal("clk_p", Pins(_eem_pin(eem_aux, 0, "p"))), + Subsignal("clk_n", Pins(_eem_pin(eem_aux, 0, "n"))), + Subsignal("sdi_p", Pins(*[_eem_pin(eem_aux, i, "p") for i in range(1, 5)])), + Subsignal("sdi_n", Pins(*[_eem_pin(eem_aux, i, "n") for i in range(1, 5)])), IOStandard("LVDS_25") ), ("grabber{}_serrx".format(eem), 0, @@ -416,16 +404,28 @@ class Grabber(_EEM): return ios @classmethod - def add_std(cls, target, eem, eem_aux, ttl_out_cls): + def add_std(cls, target, eem, eem_aux=None, ttl_out_cls=None): cls.add_extension(target, eem, eem_aux) - for signal in "cc0 cc1 cc2".split(): - pads = target.platform.request("grabber{}_{}".format(eem, signal)) - phy = ttl_out_cls(pads.p, pads.n) - target.submodules += phy - target.rtio_channels.append(rtio.Channel.from_phy(phy)) - if eem_aux is not None: - pads = target.platform.request("grabber{}_cc3".format(eem)) - phy = ttl_out_cls(pads.p, pads.n) - target.submodules += phy - target.rtio_channels.append(rtio.Channel.from_phy(phy)) + phy = grabber.Grabber(target.platform.request( + "grabber{}_video".format(eem))) + name = "grabber{}".format(len(target.grabber_csr_group)) + setattr(target.submodules, name, phy) + target.grabber_csr_group.append(name) + target.csr_devices.append(name) + target.rtio_channels += [ + rtio.Channel(phy.config), + rtio.Channel(phy.gate_data) + ] + + if ttl_out_cls is not None: + for signal in "cc0 cc1 cc2".split(): + pads = target.platform.request("grabber{}_{}".format(eem, signal)) + phy = ttl_out_cls(pads.p, pads.n) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy)) + if eem_aux is not None: + pads = target.platform.request("grabber{}_cc3".format(eem)) + phy = ttl_out_cls(pads.p, pads.n) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy)) From ad099edf63aef306d26b0785ea7e2318d8a55d73 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 May 2018 22:43:40 +0800 Subject: [PATCH 0856/2457] kasli: integrate grabber --- artiq/examples/kasli_basic/device_db_mitll.py | 4 ++-- artiq/examples/kasli_basic/device_db_ustc.py | 4 ++-- artiq/gateware/targets/kasli.py | 13 +++++++++++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/artiq/examples/kasli_basic/device_db_mitll.py b/artiq/examples/kasli_basic/device_db_mitll.py index e7ae94ac4..ea4402455 100644 --- a/artiq/examples/kasli_basic/device_db_mitll.py +++ b/artiq/examples/kasli_basic/device_db_mitll.py @@ -144,12 +144,12 @@ device_db.update( "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 20} + "arguments": {"channel": 22} }, led1={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 21} + "arguments": {"channel": 23} }, ) diff --git a/artiq/examples/kasli_basic/device_db_ustc.py b/artiq/examples/kasli_basic/device_db_ustc.py index 31b1bf03d..1c2810042 100644 --- a/artiq/examples/kasli_basic/device_db_ustc.py +++ b/artiq/examples/kasli_basic/device_db_ustc.py @@ -178,12 +178,12 @@ device_db.update( "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 36} + "arguments": {"channel": 38} }, led1={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 37} + "arguments": {"channel": 39} } ) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index e28ea61e5..f39576088 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -339,12 +339,13 @@ class MITLL(_StandaloneBase): self.comb += self.platform.request("clk_sel").eq(1) self.rtio_channels = [] - # TODO: grabber on eem0->eemB eem1->eemA + self.grabber_csr_group = [] eem.DIO.add_std(self, 4, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.InOut_8X) eem.Urukul.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) eem.Zotino.add_std(self, 5, ttl_serdes_7series.Output_8X) eem.Zotino.add_std(self, 6, ttl_serdes_7series.Output_8X) + eem.Grabber.add_std(self, 1, 0) for i in (1, 2): sfp_ctl = self.platform.request("sfp_ctl", i) @@ -357,6 +358,8 @@ class MITLL(_StandaloneBase): self.rtio_channels.append(rtio.LogChannel()) self.add_rtio(self.rtio_channels) + self.config["HAS_GRABBER"] = None + self.add_csr_group("grabber", self.grabber_csr_group) class USTC(_StandaloneBase): @@ -372,7 +375,7 @@ class USTC(_StandaloneBase): self.comb += self.platform.request("clk_sel").eq(1) self.rtio_channels = [] - # TODO: grabber on eem0->eemA + self.grabber_csr_group = [] eem.DIO.add_std(self, 5, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) eem.DIO.add_std(self, 6, @@ -381,6 +384,7 @@ class USTC(_StandaloneBase): ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) eem.Urukul.add_std(self, 2, 1, ttl_serdes_7series.Output_8X) eem.Urukul.add_std(self, 4, 3, ttl_serdes_7series.Output_8X) + eem.Grabber.add_std(self, 0) for i in (1, 2): sfp_ctl = self.platform.request("sfp_ctl", i) @@ -393,6 +397,8 @@ class USTC(_StandaloneBase): self.rtio_channels.append(rtio.LogChannel()) self.add_rtio(self.rtio_channels) + self.config["HAS_GRABBER"] = None + self.add_csr_group("grabber", self.grabber_csr_group) class PTB(_StandaloneBase): @@ -502,6 +508,7 @@ class LUH(_StandaloneBase): self.comb += self.platform.request("clk_sel").eq(1) self.rtio_channels = [] + self.grabber_csr_group = [] eem.DIO.add_std(self, 0, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) eem.DIO.add_std(self, 1, @@ -526,6 +533,8 @@ class LUH(_StandaloneBase): self.rtio_channels.append(rtio.LogChannel()) self.add_rtio(self.rtio_channels) + self.config["HAS_GRABBER"] = None + self.add_csr_group("grabber", self.grabber_csr_group) class Tester(_StandaloneBase): From 2b7d98eb0475f8de96db617c8da853252a3f0a84 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 28 May 2018 16:49:13 +0000 Subject: [PATCH 0857/2457] firmware: enable all log levels when creating UART logger. The default is all off. --- artiq/firmware/libboard_misoc/uart_logger.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_misoc/uart_logger.rs b/artiq/firmware/libboard_misoc/uart_logger.rs index c9308f34f..371073ae4 100644 --- a/artiq/firmware/libboard_misoc/uart_logger.rs +++ b/artiq/firmware/libboard_misoc/uart_logger.rs @@ -1,5 +1,5 @@ use core::fmt::Write; -use log::{Log, Metadata, Record, set_logger}; +use log::{Log, LevelFilter, Metadata, Record, set_logger, set_max_level}; use clock; use uart_console::Console; @@ -10,6 +10,7 @@ impl ConsoleLogger { pub fn register() { static LOGGER: ConsoleLogger = ConsoleLogger; set_logger(&LOGGER).expect("global logger can only be initialized once") + set_max_level(LevelFilter::Trace); } } From b860302a9ae03a7dd717b0b7f9e412cb01e61253 Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Mon, 28 May 2018 18:14:22 +0100 Subject: [PATCH 0858/2457] firmware: fix typo in UART logger --- artiq/firmware/libboard_misoc/uart_logger.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_misoc/uart_logger.rs b/artiq/firmware/libboard_misoc/uart_logger.rs index 371073ae4..751967c5a 100644 --- a/artiq/firmware/libboard_misoc/uart_logger.rs +++ b/artiq/firmware/libboard_misoc/uart_logger.rs @@ -9,7 +9,7 @@ pub struct ConsoleLogger; impl ConsoleLogger { pub fn register() { static LOGGER: ConsoleLogger = ConsoleLogger; - set_logger(&LOGGER).expect("global logger can only be initialized once") + set_logger(&LOGGER).expect("global logger can only be initialized once"); set_max_level(LevelFilter::Trace); } } From 560889372f3dc0e5ad8bca42dea78bed6e94f376 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 29 May 2018 10:26:36 +0800 Subject: [PATCH 0859/2457] firmware: grabber support --- artiq/firmware/libboard_artiq/grabber.rs | 93 ++++++++++++++++++++++++ artiq/firmware/libboard_artiq/lib.rs | 2 + artiq/firmware/runtime/main.rs | 10 +++ conda/artiq-dev/meta.yaml | 2 +- 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 artiq/firmware/libboard_artiq/grabber.rs diff --git a/artiq/firmware/libboard_artiq/grabber.rs b/artiq/firmware/libboard_artiq/grabber.rs new file mode 100644 index 000000000..a70cb0e28 --- /dev/null +++ b/artiq/firmware/libboard_artiq/grabber.rs @@ -0,0 +1,93 @@ +use board_misoc::csr; + +static mut GRABBER_UP: &'static mut [bool] = &mut [false; csr::GRABBER_LEN]; + +fn get_pll_reset(g: usize) -> bool { + unsafe { (csr::GRABBER[g].pll_reset_read)() != 0 } +} + +fn set_pll_reset(g: usize, reset: bool) { + let val = if reset { 1 } else { 0 }; + unsafe { (csr::GRABBER[g].pll_reset_write)(val) } +} + +fn pll_locked(g: usize) -> bool { + unsafe { (csr::GRABBER[g].pll_locked_read)() != 0 } +} + +fn clock_pattern_ok(g: usize) -> bool { + unsafe { (csr::GRABBER[g].clk_sampled_read)() == 0b1100011 } +} + +fn clock_pattern_ok_filter(g: usize) -> bool { + for _ in 0..128 { + if !clock_pattern_ok(g) { + return false; + } + } + true +} + +fn phase_shift(g: usize, direction: u8) { + unsafe { + (csr::GRABBER[g].phase_shift_write)(direction); + while (csr::GRABBER[g].phase_shift_done_read)() == 0 {} + } +} + +fn clock_align(g: usize) -> bool { + while clock_pattern_ok_filter(g) { + phase_shift(g, 1); + } + phase_shift(g, 1); + + let mut count = 0; + while !clock_pattern_ok_filter(g) { + phase_shift(g, 1); + count += 1; + if count > 1024 { + return false; + } + } + + let mut window = 1; + phase_shift(g, 1); + while clock_pattern_ok_filter(g) { + phase_shift(g, 1); + window += 1; + } + + for _ in 0..window/2 { + phase_shift(g, 0); + } + + true +} + +pub fn tick() { + for g in 0..csr::GRABBER.len() { + if unsafe { GRABBER_UP[g] } { + if !clock_pattern_ok(g) || !pll_locked(g) { + set_pll_reset(g, true); + unsafe { GRABBER_UP[g] = false; } + info!("grabber{} is down", g); + } + } else { + if get_pll_reset(g) { + set_pll_reset(g, false); + } else { + if pll_locked(g) { + info!("grabber{} PLL is locked", g); + if clock_align(g) { + info!("grabber{} is up", g); + unsafe { GRABBER_UP[g] = true; } + } else { + set_pll_reset(g, true); + } + } else { + set_pll_reset(g, true); + } + } + } + } +} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index af8c1336a..3402a1d2f 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -40,6 +40,8 @@ mod ad9154_reg; pub mod ad9154; #[cfg(has_allaki_atts)] pub mod hmc542; +#[cfg(has_grabber)] +pub mod grabber; #[cfg(has_drtio)] pub mod drtioaux; diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index f0bef4108..eaaa1721d 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -168,6 +168,14 @@ fn setup_si5324_as_synthesizer() board_artiq::si5324::Input::Ckin2).expect("cannot initialize Si5324"); } +#[cfg(has_grabber)] +fn grabber_thread(io: sched::Io) { + loop { + board_artiq::grabber::tick(); + io.sleep(200).unwrap(); + } +} + #[cfg(has_ethmac)] fn startup_ethernet() { let hardware_addr; @@ -237,6 +245,8 @@ fn startup_ethernet() { io.spawn(4096, moninj::thread); #[cfg(has_rtio_analyzer)] io.spawn(4096, analyzer::thread); + #[cfg(has_grabber)] + io.spawn(4096, grabber_thread); let mut net_stats = ethmac::EthernetStatistics::new(); loop { diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index ec43ce29c..8ecff1168 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_35+git9bc084a - - misoc 0.11 py35_14+gitc60ccfb2 + - misoc 0.11 py35_15+git7f63aff5 - jesd204b 0.5 - microscope - binutils-or1k-linux >=2.27 From 2e09307d8d4b0b60294f5c72c202d3021f86d3fa Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 29 May 2018 03:16:52 +0000 Subject: [PATCH 0860/2457] firmware: use writeln instead of write in UART logger. --- artiq/firmware/libboard_misoc/uart_logger.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_misoc/uart_logger.rs b/artiq/firmware/libboard_misoc/uart_logger.rs index 751967c5a..e3e26f6cf 100644 --- a/artiq/firmware/libboard_misoc/uart_logger.rs +++ b/artiq/firmware/libboard_misoc/uart_logger.rs @@ -25,8 +25,8 @@ impl Log for ConsoleLogger { let seconds = timestamp / 1_000_000; let micros = timestamp % 1_000_000; - let _ = write!(Console, "[{:6}.{:06}s] {:>5}({}): {}", - seconds, micros, record.level(), record.target(), record.args()); + let _ = writeln!(Console, "[{:6}.{:06}s] {:>5}({}): {}", + seconds, micros, record.level(), record.target(), record.args()); } } From d1df18ae6aeae3bc3acdc75a28f3fe73a333b79f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 29 May 2018 17:51:41 +0800 Subject: [PATCH 0861/2457] monkey_patches: work around Python issue 33678. Closes #1016 --- artiq/monkey_patches.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/artiq/monkey_patches.py b/artiq/monkey_patches.py index 715453931..930d8b118 100644 --- a/artiq/monkey_patches.py +++ b/artiq/monkey_patches.py @@ -1,4 +1,5 @@ import sys +import socket __all__ = [] @@ -11,3 +12,26 @@ if sys.version_info[:3] >= (3, 5, 2): def _ipaddr_info(host, port, family, type, proto): return None asyncio.base_events._ipaddr_info = _ipaddr_info + + # See https://github.com/m-labs/artiq/issues/1016 + @asyncio.coroutine + def sock_connect(self, sock, address): + """Connect to a remote socket at address. + + This method is a coroutine. + """ + if self._debug and sock.gettimeout() != 0: + raise ValueError("the socket must be non-blocking") + + if not hasattr(socket, 'AF_UNIX') or sock.family != socket.AF_UNIX: + socktype = sock.type & 0xf # WA https://bugs.python.org/issue21327 + resolved = asyncio.base_events._ensure_resolved( + address, family=sock.family, type=socktype, proto=sock.proto, loop=self) + if not resolved.done(): + yield from resolved + _, _, _, _, address = resolved.result()[0] + + fut = self.create_future() + self._sock_connect(fut, sock, address) + return (yield from fut) + asyncio.selector_events.BaseSelectorEventLoop.sock_connect = sock_connect From 8fd57e6ccb6e5070d3dc988a9d5550b295621d72 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 29 May 2018 22:36:42 +0800 Subject: [PATCH 0862/2457] kasli_tester: add Sampler and Zotino support --- .../kasli_basic/repository/kasli_tester.py | 86 ++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index db1af4d2b..6da122535 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -37,6 +37,8 @@ class KasliTester(EnvExperiment): self.ttl_ins = dict() self.urukul_cplds = dict() self.urukuls = dict() + self.samplers = dict() + self.zotinos = dict() ddb = self.get_device_db() for name, desc in ddb.items(): @@ -54,8 +56,13 @@ class KasliTester(EnvExperiment): self.urukul_cplds[name] = self.get_device(name) elif (module, cls) == ("artiq.coredevice.ad9910", "AD9910"): self.urukuls[name] = self.get_device(name) + elif (module, cls) == ("artiq.coredevice.sampler", "Sampler"): + self.samplers[name] = self.get_device(name) + elif (module, cls) == ("artiq.coredevice.zotino", "Zotino"): + self.zotinos[name] = self.get_device(name) - # Remove Urukul control signals from TTL outs (tested separately) + # Remove Urukul, Sampler and Zotino control signals + # from TTL outs (tested separately) ddb = self.get_device_db() for name, desc in ddb.items(): if isinstance(desc, dict) and desc["type"] == "local": @@ -64,15 +71,25 @@ class KasliTester(EnvExperiment): or (module, cls) == ("artiq.coredevice.ad9912", "AD9912")): sw_device = desc["arguments"]["sw_device"] del self.ttl_outs[sw_device] - if (module, cls) == ("artiq.coredevice.urukul", "CPLD"): + elif (module, cls) == ("artiq.coredevice.urukul", "CPLD"): io_update_device = desc["arguments"]["io_update_device"] del self.ttl_outs[io_update_device] + elif (module, cls) == ("artiq.coredevice.sampler", "Sampler"): + cnv_device = desc["arguments"]["cnv_device"] + del self.ttl_outs[cnv_device] + elif (module, cls) == ("artiq.coredevice.zotino", "Zotino"): + ldac_device = desc["arguments"]["ldac_device"] + clr_device = desc["arguments"]["clr_device"] + del self.ttl_outs[ldac_device] + del self.ttl_outs[clr_device] # Sort everything by RTIO channel number self.leds = sorted(self.leds.items(), key=lambda x: x[1].channel) self.ttl_outs = sorted(self.ttl_outs.items(), key=lambda x: x[1].channel) self.ttl_ins = sorted(self.ttl_ins.items(), key=lambda x: x[1].channel) self.urukuls = sorted(self.urukuls.items(), key=lambda x: x[1].sw.channel) + self.samplers = sorted(self.samplers.items(), key=lambda x: x[1].cnv.channel) + self.zotinos = sorted(self.zotinos.items(), key=lambda x: x[1].bus.channel) @kernel def test_led(self, led): @@ -191,6 +208,69 @@ class KasliTester(EnvExperiment): print("Testing RF switch control. Press ENTER when done.") self.rf_switch_wave([channel_dev for channel_name, channel_dev in self.urukuls]) + @kernel + def get_sampler_voltages(self, sampler, cb): + self.core.break_realtime() + sampler.init() + delay(5*ms) + for i in range(8): + sampler.set_gain_mu(i, 0) + delay(100*us) + smp = [0.0]*8 + sampler.sample(smp) + cb(smp) + + def test_samplers(self): + print("*** Testing Sampler ADCs.") + for card_name, card_dev in self.samplers: + print("Testing: ", card_name) + + for channel in range(8): + print("Apply 1.5V to channel {}. Press ENTER when done.".format(channel)) + input() + + voltages = [] + def setv(x): + nonlocal voltages + voltages = x + self.get_sampler_voltages(card_dev, setv) + + passed = True + for n, voltage in enumerate(voltages): + if n == channel: + if abs(voltage - 1.5) > 0.2: + passed = False + else: + if abs(voltage) > 0.2: + passed = False + if passed: + print("PASSED") + else: + print("FAILED") + print(" ".join(["{:.1f}".format(x) for x in voltages])) + + @kernel + def set_zotino_voltages(self, zotino, voltages): + self.core.break_realtime() + zotino.init() + delay(100*us) + i = 0 + for voltage in voltages: + zotino.write_dac(i, voltage) + delay(100*us) + i += 1 + zotino.load() + + def test_zotinos(self): + print("*** Testing Zotino DACs.") + print("Voltages:") + for card_n, (card_name, card_dev) in enumerate(self.zotinos): + voltages = [2*card_n + (-1)**i*0.1*(i//2+1) for i in range(32)] + print(card_name, " ".join(["{:.1f}".format(x) for x in voltages])) + self.set_zotino_voltages(card_dev, voltages) + print("Press ENTER when done.") + input() + def run(self): print("****** Kasli system tester ******") print("") @@ -199,3 +279,5 @@ class KasliTester(EnvExperiment): self.test_ttl_outs() self.test_ttl_ins() self.test_urukuls() + self.test_samplers() + self.test_zotinos() From 44c7a028cb0bc35b881467d88eb1b05fdc19f7a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82?= Date: Wed, 30 May 2018 14:02:28 +0200 Subject: [PATCH 0863/2457] Added second argument to DIO.add_STD in master and satellite variant of kasli (now builds properly) --- artiq/gateware/targets/kasli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index f39576088..c340df435 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -834,7 +834,7 @@ class Master(_MasterBase): phy = ttl_simple.Output(sc.led) self.submodules += phy self.rtio_channels.append(rtio.Channel.from_phy(phy)) - eem.DIO.add_std(self, 0, ttl_serdes_7series.InOut_8X) + eem.DIO.add_std(self, 0, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.InOut_8X) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) @@ -856,7 +856,7 @@ class Satellite(_SatelliteBase): phy = ttl_simple.Output(self.platform.request("sfp_ctl", i).led) self.submodules += phy self.rtio_channels.append(rtio.Channel.from_phy(phy)) - eem.DIO.add_std(self, 0, ttl_serdes_7series.InOut_8X) + eem.DIO.add_std(self, 0, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.InOut_8X) self.add_rtio(self.rtio_channels) From 38b51282226f9feb74805312abcde9b8f17fd693 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 30 May 2018 23:39:22 +0800 Subject: [PATCH 0864/2457] conda: bump jesd204 --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 8ecff1168..761ff37e4 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -16,7 +16,7 @@ requirements: - setuptools 33.1.1 - migen 0.7 py35_35+git9bc084a - misoc 0.11 py35_15+git7f63aff5 - - jesd204b 0.5 + - jesd204b 0.6 - microscope - binutils-or1k-linux >=2.27 - llvm-or1k 6.0.0 From 58f71e34fc83f0503939ff8d0b551fd18594924c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 28 May 2018 08:45:38 +0000 Subject: [PATCH 0865/2457] doc: add hut2 and lasersdk controller default ports --- doc/manual/default_network_ports.rst | 80 +++++++++++++++------------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/doc/manual/default_network_ports.rst b/doc/manual/default_network_ports.rst index 5c2652cd6..c64ecb22f 100644 --- a/doc/manual/default_network_ports.rst +++ b/doc/manual/default_network_ports.rst @@ -4,41 +4,45 @@ Default network ports +--------------------------------+--------------+ | Component | Default port | +================================+==============+ -| Core device (management) | 1380 | -+--------------------------------+--------------+ -| Core device (main) | 1381 | -+--------------------------------+--------------+ -| Core device (analyzer) | 1382 | -+--------------------------------+--------------+ -| Core device (mon/inj) | 1383 | -+--------------------------------+--------------+ -| Master (logging input) | 1066 | -+--------------------------------+--------------+ -| Master (broadcasts) | 1067 | -+--------------------------------+--------------+ -| Core device logging controller | 1068 | -+--------------------------------+--------------+ -| InfluxDB bridge | 3248 | -+--------------------------------+--------------+ -| Controller manager | 3249 | -+--------------------------------+--------------+ -| Master (notifications) | 3250 | -+--------------------------------+--------------+ -| Master (control) | 3251 | -+--------------------------------+--------------+ -| PDQ2 (out-of-tree) | 3252 | -+--------------------------------+--------------+ -| LDA | 3253 | -+--------------------------------+--------------+ -| Novatech 409B | 3254 | -+--------------------------------+--------------+ -| Thorlabs T-Cube | 3255 | -+--------------------------------+--------------+ -| Korad KA3005P | 3256 | -+--------------------------------+--------------+ -| Newfocus 8742 (out-of-tree) | 3257 | -+--------------------------------+--------------+ -| PICam (out-of-tree) | 3258 | -+--------------------------------+--------------+ -| PTB Drivers (out-of-tree) | 3259-3270 | -+--------------------------------+--------------+ +| Core device (management) | 1380 | +|---------------------------------+-----------| +| Core device (main) | 1381 | +|---------------------------------+-----------| +| Core device (analyzer) | 1382 | +|---------------------------------+-----------| +| Core device (mon/inj) | 1383 | +|---------------------------------+-----------| +| Master (logging input) | 1066 | +|---------------------------------+-----------| +| Master (broadcasts) | 1067 | +|---------------------------------+-----------| +| Core device logging controller | 1068 | +|---------------------------------+-----------| +| InfluxDB bridge | 3248 | +|---------------------------------+-----------| +| Controller manager | 3249 | +|---------------------------------+-----------| +| Master (notifications) | 3250 | +|---------------------------------+-----------| +| Master (control) | 3251 | +|---------------------------------+-----------| +| PDQ2 (out-of-tree) | 3252 | +|---------------------------------+-----------| +| LDA | 3253 | +|---------------------------------+-----------| +| Novatech 409B | 3254 | +|---------------------------------+-----------| +| Thorlabs T-Cube | 3255 | +|---------------------------------+-----------| +| Korad KA3005P | 3256 | +|---------------------------------+-----------| +| Newfocus 8742 (out-of-tree) | 3257 | +|---------------------------------+-----------| +| PICam (out-of-tree) | 3258 | +|---------------------------------+-----------| +| PTB Drivers (out-of-tree) | 3259-3270 | +|---------------------------------+-----------| +| HUT2 (out-of-tree) | 3271 | +|---------------------------------+-----------| +| TOPTICA Laser SDK (out-of-tree) | 3272 | +|---------------------------------+-----------| From 9b5a46dffd50b840a1030b696be1829cf7deb090 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 31 May 2018 15:56:11 +0000 Subject: [PATCH 0866/2457] suservo: fix restart counter assertion c.f. #788 --- artiq/gateware/suservo/servo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/suservo/servo.py b/artiq/gateware/suservo/servo.py index b19a6e73d..08b31a3bc 100644 --- a/artiq/gateware/suservo/servo.py +++ b/artiq/gateware/suservo/servo.py @@ -26,7 +26,7 @@ class Servo(Module): self.start = Signal() t_restart = t_cycle - t_adc + 1 - assert t_restart > 0 + assert t_restart > 1 cnt = Signal(max=t_restart) cnt_done = Signal() active = Signal(3) From e1b0fcc24ece81a53a0f44433e33ee5e75bfe6b0 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 31 May 2018 16:21:09 +0000 Subject: [PATCH 0867/2457] suservo: add documentation on settings and setup close #1015 --- artiq/coredevice/suservo.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 20ca966cc..93ca1fcf7 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -16,7 +16,27 @@ COEFF_SHIFT = 11 class SUServo: - """Sampler-Urukul Servo configuration device. + """Sampler-Urukul Servo parent and configuration device. + + Sampler-Urukul Servo is a integrated device controlling one + 8-channel ADC (Sampler) and two 4-channel DDS (Urukuls) with a DSP engine + connecting the ADC data and the DDS output amplitudes to enable + feedback. SUServo can for example be used to implement intensity + stabilization of laser beams with an AOM and a photodetector. + + Additionally SUServo supports multiple preconfigured profiles per channel + and features like automatic integrator hold. + + Notes: + + * See the SUServo variant of the Kasli target for an example of how to + connect the gateware and the devices. Sampler and each Urukul need + two EEM connections. + * Ensure that both Urukuls are AD9910 variants and have the on-board + dip switches set to 1100 (first two on, last two off). + * Refer to the Sampler and Urukul documentation and the SUServo + example device database for runtime configuration of the devices + (PLLs, gains, clock routing etc.) :param channel: RTIO channel number :param pgia_device: Name of the Sampler PGIA gain setting SPI bus From 5dbdc5650c60af87e3fe7fe8bc8dd030913bf0ca Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 31 May 2018 16:30:40 +0000 Subject: [PATCH 0868/2457] suservo: document set_config and get_status more close #1028 --- artiq/coredevice/suservo.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 93ca1fcf7..578cf7bd3 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -130,12 +130,15 @@ class SUServo: def set_config(self, enable): """Set SU Servo configuration. - Disabling takes up to 2 Servo cycles (~2.2 µs) to clear - the processing pipeline. - This method advances the timeline by one Servo memory access. + It does not support RTIO event replacement. - :param enable: Enable Servo operation. + :param enable (int): Enable Servo operation. Enabling starts servo + iterations beginning with the ADC sampling stage. This also + provides a mean for synchronization of Servo updates to other RTIO + activity. + Disabling takes up to 2 Servo cycles (~2.2 µs) to clear the + processing pipeline. """ self.write(CONFIG_ADDR, enable) @@ -144,7 +147,16 @@ class SUServo: """Get current SU Servo status. This method does not advance the timeline but consumes all slack. + + The ``done`` bit indicates that a SUServo cycle has completed. + It is pulsed for one RTIO cycle every SUServo cycle and asserted + continuously when the servo is not ``enabled`` and the pipeline has + drained (the last DDS update is done). + This method returns and clears the clip indicator for all channels. + An asserted clip indicator corresponds to the servo having encountered + an input signal on an active channel that would have resulted in the + IIR state exceeding the output range. :return: Status. Bit 0: enabled, bit 1: done, bits 8-15: channel clip indicators. From e136709cac59ceb1d9d2758c32faadb6469b5108 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 31 May 2018 16:36:53 +0000 Subject: [PATCH 0869/2457] suservo: document gain state close #1030 --- artiq/coredevice/suservo.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 578cf7bd3..0e5811163 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -199,6 +199,10 @@ class SUServo: This method does not advance the timeline but consumes all slack. + The PGIA gain setting must be known prior to using this method, either + by setting the gain (:meth:`set_pgia_mu`) or by supplying it + (:attr:`gains` or via the constructor/device database). + :param adc: ADC channel number (0-7) :return: ADC voltage """ From 36dcea3edf2daef9132c9f333e2e28fa92fa27ed Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 31 May 2018 16:44:14 +0000 Subject: [PATCH 0870/2457] suservo: refactor y_mu_to_full_scale as portable close #1032 --- artiq/coredevice/suservo.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 0e5811163..8eb1a6801 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -1,4 +1,4 @@ -from artiq.language.core import kernel, delay, now_mu, delay_mu +from artiq.language.core import kernel, delay, now_mu, delay_mu, portable from artiq.language.units import us, ns from artiq.coredevice.rtio import rtio_output, rtio_input_data from artiq.coredevice import spi2 as spi @@ -15,6 +15,21 @@ T_CYCLE = (2*(8 + 64) + 2 + 1)*8*ns COEFF_SHIFT = 11 +@portable +def y_mu_to_full_scale(y): + """Convert Servo Y data from machine units to units of full scale.""" + return y*(1./(1 << COEFF_WIDTH - 1)) + + +@portable +def adc_mu_to_volts(x, gain): + """Convert Servo ADC data from machine units to Volt.""" + val = (x >> 1) & 0xffff + mask = 1 << 15 + val = -(val & mask) + (val & ~mask) + return sampler.adc_mu_to_volt(val, gain) + + class SUServo: """Sampler-Urukul Servo parent and configuration device. @@ -69,7 +84,7 @@ class SUServo: self.channel = channel self.gains = gains self.ref_period_mu = self.core.seconds_to_mu( - self.core.coarse_ref_period) + self.core.coarse_ref_period) assert self.ref_period_mu == self.core.ref_multiplier @kernel @@ -206,11 +221,9 @@ class SUServo: :param adc: ADC channel number (0-7) :return: ADC voltage """ - val = (self.get_adc_mu(channel) >> 1) & 0xffff - mask = 1 << 15 - val = -(val & mask) + (val & ~mask) + val = self.get_adc_mu(channel) gain = (self.gains >> (channel*2)) & 0b11 - return sampler.adc_mu_to_volt(val, gain) + return adc_mu_to_volts(val, gain) class Channel: @@ -449,7 +462,7 @@ class Channel: :param profile: Profile number (0-31) :return: IIR filter output in Y0 units of full scale """ - return self.get_y_mu(profile)*(1./(1 << COEFF_WIDTH - 1)) + return y_mu_to_full_scale(self.get_y_mu(profile)) @kernel def set_y_mu(self, profile, y): From a42f77444038f67d3d8adf57b84836687ae102c4 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Thu, 31 May 2018 16:53:01 +0000 Subject: [PATCH 0871/2457] suservo: document offset range limits close #1034 --- artiq/coredevice/suservo.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 8eb1a6801..6f288287b 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -287,6 +287,8 @@ class Channel: :param frequency: DDS frequency in Hz :param offset: IIR offset (negative setpoint) in units of full scale. For positive ADC voltages as setpoints, this should be negative. + Due to rounding and representation as two's complement, + ``offset=1`` can not be represented while ``offset=-1`` can. :param phase: DDS phase in turns """ if self.servo_channel < 4: @@ -310,9 +312,9 @@ class Channel: Where: * :math:`y_n` and :math:`y_{n-1}` are the current and previous - filter outputs, clipped to :math:`[0, 1]`. + filter outputs, clipped to :math:`[0, 1[`. * :math:`x_n` and :math:`x_{n-1}` are the current and previous - filter inputs + filter inputs in :math:`[-1, 1[`. * :math:`o` is the offset * :math:`a_0` is the normalization factor :math:`2^{11}` * :math:`a_1` is the feedback gain From 22506e849f7ae764d01ba4292753fe93836f3b27 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 1 Jun 2018 06:14:30 +0000 Subject: [PATCH 0872/2457] suservo: clarify timings close #1027 --- artiq/coredevice/suservo.py | 91 +++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 6f288287b..2f55c20ca 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -17,13 +17,13 @@ COEFF_SHIFT = 11 @portable def y_mu_to_full_scale(y): - """Convert Servo Y data from machine units to units of full scale.""" + """Convert servo Y data from machine units to units of full scale.""" return y*(1./(1 << COEFF_WIDTH - 1)) @portable def adc_mu_to_volts(x, gain): - """Convert Servo ADC data from machine units to Volt.""" + """Convert servo ADC data from machine units to Volt.""" val = (x >> 1) & 0xffff mask = 1 << 15 val = -(val & mask) + (val & ~mask) @@ -36,20 +36,21 @@ class SUServo: Sampler-Urukul Servo is a integrated device controlling one 8-channel ADC (Sampler) and two 4-channel DDS (Urukuls) with a DSP engine connecting the ADC data and the DDS output amplitudes to enable - feedback. SUServo can for example be used to implement intensity - stabilization of laser beams with an AOM and a photodetector. + feedback. SU Servo can for example be used to implement intensity + stabilization of laser beams with an amplifier and AOM driven by Urukul + and a photodetector connected to Sampler. - Additionally SUServo supports multiple preconfigured profiles per channel + Additionally SU Servo supports multiple preconfigured profiles per channel and features like automatic integrator hold. Notes: - * See the SUServo variant of the Kasli target for an example of how to + * See the SU Servo variant of the Kasli target for an example of how to connect the gateware and the devices. Sampler and each Urukul need two EEM connections. * Ensure that both Urukuls are AD9910 variants and have the on-board dip switches set to 1100 (first two on, last two off). - * Refer to the Sampler and Urukul documentation and the SUServo + * Refer to the Sampler and Urukul documentation and the SU Servo example device database for runtime configuration of the devices (PLLs, gains, clock routing etc.) @@ -89,9 +90,10 @@ class SUServo: @kernel def init(self): - """Initialize the Servo, Sampler and both Urukuls. + """Initialize the servo, Sampler and both Urukuls. - Leaves the Servo disabled (see :meth:`set_config`), resets all DDS. + Leaves the servo disabled (see :meth:`set_config`), resets and + configures all DDS. Urukul initialization is performed blindly as there is no readback from the DDS or the CPLDs. @@ -120,7 +122,7 @@ class SUServo: @kernel def write(self, addr, value): - """Write to Servo memory. + """Write to servo memory. This method advances the timeline by one coarse RTIO cycle. @@ -132,7 +134,7 @@ class SUServo: @kernel def read(self, addr): - """Read from Servo memory. + """Read from servo memory. This method does not advance the timeline but consumes all slack. @@ -145,14 +147,16 @@ class SUServo: def set_config(self, enable): """Set SU Servo configuration. - This method advances the timeline by one Servo memory access. + This method advances the timeline by one servo memory access. It does not support RTIO event replacement. - :param enable (int): Enable Servo operation. Enabling starts servo - iterations beginning with the ADC sampling stage. This also - provides a mean for synchronization of Servo updates to other RTIO - activity. - Disabling takes up to 2 Servo cycles (~2.2 µs) to clear the + :param enable (int): Enable servo operation. Enabling starts servo + iterations beginning with the ADC sampling stage. The first DDS + update will happen about two servo cycles (~2.3 µs) after enabling + the servo. The delay is deterministic. + This also provides a mean for synchronization of servo updates to + other RTIO activity. + Disabling takes up to two servo cycles (~2.3 µs) to clear the processing pipeline. """ self.write(CONFIG_ADDR, enable) @@ -163,8 +167,8 @@ class SUServo: This method does not advance the timeline but consumes all slack. - The ``done`` bit indicates that a SUServo cycle has completed. - It is pulsed for one RTIO cycle every SUServo cycle and asserted + The ``done`` bit indicates that a SU Servo cycle has completed. + It is pulsed for one RTIO cycle every SU Servo cycle and asserted continuously when the servo is not ``enabled`` and the pipeline has drained (the last DDS update is done). @@ -246,10 +250,13 @@ class Channel: def set(self, en_out, en_iir=0, profile=0): """Operate channel. - This method does not advance the timeline. - Output RF switch setting takes effect immediately. - IIR updates take place once the RF switch has been enabled for the - configured delay and the profile setting has been stable. + This method does not advance the timeline. Output RF switch setting + takes effect immediately and is independent of any other activity + (profile settings, other channels). The RF switch behaves like + ``TTLOut``. RTIO event replacement is supported. IIR updates take place + once the RF switch has been enabled for the configured delay and the + profile setting has been stable. Profile changes take between one and + two servo cycles to reach the DDS. :param en_out: RF switch enable :param en_iir: IIR updates enable @@ -279,7 +286,7 @@ class Channel: def set_dds(self, profile, frequency, offset, phase=0.): """Set profile DDS coefficients. - This method advances the timeline by four Servo memory accesses. + This method advances the timeline by four servo memory accesses. Profile parameter changes are not synchronized. Activate a different profile or stop the servo to ensure synchronous changes. @@ -332,7 +339,7 @@ class Channel: :param b1: 18 bit signed B1 coefficient (old, X1 coefficient, feed forward, proportional gain) :param dly: IIR update suppression time. In units of IIR cycles - (~1.2 µs, 0-255) + (~1.2 µs, 0-255). """ base = (self.servo_channel << 8) | (profile << 3) self.servo.write(base + 3, adc | (dly << 8)) @@ -344,7 +351,7 @@ class Channel: def set_iir(self, profile, adc, gain, corner=0., limit=0., delay=0.): """Set profile IIR coefficients. - This method advances the timeline by four Servo memory accesses. + This method advances the timeline by four servo memory accesses. Profile parameter changes are not synchronized. Activate a different profile or stop the servo to ensure synchronous changes. @@ -374,7 +381,12 @@ class Channel: :param limit: Integrator gain limit (1). When 0 (the default) the integrator gain limit is infinite. Positive. :param delay: Delay (in seconds, 0-300 µs) before allowing IIR updates - after invoking :meth:`set`. + after invoking :meth:`set`. This is rounded to the nearest number + of servo cycles (~1.2 µs). Since the RF switch (:meth:`set`) can be + opened at any time relative to the servo cycle, the first DDS + update that carries updated IIR data will occur approximately + between ``delay + 1 cycle`` and ``delay + 2 cycles`` after + :meth:`set`. """ B_NORM = 1 << COEFF_SHIFT + 1 A_NORM = 1 << COEFF_SHIFT @@ -424,11 +436,14 @@ class Channel: def get_profile_mu(self, profile, data): """Retrieve profile data. - The data is returned in the `data` argument as: - `[ftw >> 16, b1, pow, adc | (delay << 8), offset, a1, ftw, b0]`. + Profile data is returned in the ``data`` argument in machine units + packed as: ``[ftw >> 16, b1, pow, adc | (delay << 8), offset, a1, + ftw & 0xffff, b0]``. + + .. seealso:: The individual fields are described in + :meth:`set_iir_mu` and :meth:`set_dds_mu`. This method advances the timeline by 32 µs and consumes all slack. - Profile data is returned :param profile: Profile number (0-31) :param data: List of 8 integers to write the profile data into @@ -473,11 +488,11 @@ class Channel: The IIR state is also know as the "integrator", or the DDS amplitude scale factor. It is 18 bits wide and unsigned. - This method must not be used when the Servo - could be writing to the same location. Either deactivate the profile, - or deactivate IIR updates, or disable Servo iterations. + This method must not be used when the servo could be writing to the + same location. Either deactivate the profile, or deactivate IIR + updates, or disable servo iterations. - This method advances the timeline by one Servo memory access. + This method advances the timeline by one servo memory access. :param profile: Profile number (0-31) :param y: 17 bit unsigned Y0 @@ -493,11 +508,11 @@ class Channel: The IIR state is also know as the "integrator", or the DDS amplitude scale factor. It is 18 bits wide and unsigned. - This method must not be used when the Servo - could be writing to the same location. Either deactivate the profile, - or deactivate IIR updates, or disable Servo iterations. + This method must not be used when the servo could be writing to the + same location. Either deactivate the profile, or deactivate IIR + updates, or disable servo iterations. - This method advances the timeline by one Servo memory access. + This method advances the timeline by one servo memory access. :param profile: Profile number (0-31) :param y: IIR state in units of full scale From f5d55c69023a37a54300874563946d781fed0918 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 1 Jun 2018 15:15:24 +0800 Subject: [PATCH 0873/2457] sawg: add 1 coarse RTIO cycle between spline resets This keeps all events in the same SED lane and limits the number of SED lanes required. Closes #1038 --- artiq/coredevice/sawg.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index cc071ffa0..e3ff38c03 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -342,7 +342,7 @@ class SAWG: settings. This method advances the timeline by the time required to perform all - seven writes to the configuration channel. + 7 writes to the configuration channel, plus 9 coarse RTIO cycles. """ self.config.set_div(0, 0) self.config.set_clr(1, 1, 1) @@ -352,11 +352,20 @@ class SAWG: self.config.set_out_min(-1.) self.config.set_out_max(1.) self.frequency0.set_mu(0) + delay_mu(self.core.ref_multiplier) self.frequency1.set_mu(0) + delay_mu(self.core.ref_multiplier) self.frequency2.set_mu(0) + delay_mu(self.core.ref_multiplier) self.phase0.set_mu(0) + delay_mu(self.core.ref_multiplier) self.phase1.set_mu(0) + delay_mu(self.core.ref_multiplier) self.phase2.set_mu(0) + delay_mu(self.core.ref_multiplier) self.amplitude1.set_mu(0) + delay_mu(self.core.ref_multiplier) self.amplitude2.set_mu(0) + delay_mu(self.core.ref_multiplier) self.offset.set_mu(0) + delay_mu(self.core.ref_multiplier) From e40824123342ea67a1b2b335369a2ccdd5b518c0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 1 Jun 2018 15:42:37 +0800 Subject: [PATCH 0874/2457] sawg: work around compiler not accepting delay_mu(int32) --- artiq/coredevice/sawg.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index e3ff38c03..50623d8ea 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -352,20 +352,21 @@ class SAWG: self.config.set_out_min(-1.) self.config.set_out_max(1.) self.frequency0.set_mu(0) - delay_mu(self.core.ref_multiplier) + coarse_cycle = int64(self.core.ref_multiplier) + delay_mu(coarse_cycle) self.frequency1.set_mu(0) - delay_mu(self.core.ref_multiplier) + delay_mu(coarse_cycle) self.frequency2.set_mu(0) - delay_mu(self.core.ref_multiplier) + delay_mu(coarse_cycle) self.phase0.set_mu(0) - delay_mu(self.core.ref_multiplier) + delay_mu(coarse_cycle) self.phase1.set_mu(0) - delay_mu(self.core.ref_multiplier) + delay_mu(coarse_cycle) self.phase2.set_mu(0) - delay_mu(self.core.ref_multiplier) + delay_mu(coarse_cycle) self.amplitude1.set_mu(0) - delay_mu(self.core.ref_multiplier) + delay_mu(coarse_cycle) self.amplitude2.set_mu(0) - delay_mu(self.core.ref_multiplier) + delay_mu(coarse_cycle) self.offset.set_mu(0) - delay_mu(self.core.ref_multiplier) + delay_mu(coarse_cycle) From 87d3ac9d250af838c7f8444185eeffcb9e8e6209 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 1 Jun 2018 09:38:18 +0000 Subject: [PATCH 0875/2457] suservo: swap transfer function parametrization The integrator is now parametrized through its gain and not the PI corner frequency. The integrator gain limit is given in absolute gain units and not relative to the proportional gain. close #1033 --- artiq/coredevice/suservo.py | 75 ++++++++----------- .../kasli_suservo/repository/suservo.py | 6 +- 2 files changed, 33 insertions(+), 48 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 2f55c20ca..58e15a9d0 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -348,7 +348,7 @@ class Channel: self.servo.write(base + 7, b0) @kernel - def set_iir(self, profile, adc, gain, corner=0., limit=0., delay=0.): + def set_iir(self, profile, adc, kp, ki=0., g=0., delay=0.): """Set profile IIR coefficients. This method advances the timeline by four servo memory accesses. @@ -361,25 +361,23 @@ class Channel: coefficient quantization errors): .. math:: - H(s) = K \\frac{1 + \\frac{s}{\\omega_0}} - {\\frac{1}{g} + \\frac{s}{\\omega_0}} + H(s) = k_p + \\frac{k_i}{s + \\frac{k_i}{g}} Where: * :math:`s = \\sigma + i\\omega` is the complex frequency - * :math:`K` is the proportional gain - * :math:`\\omega_0 = 2\\pi f_0` is the integrator corner frequency + * :math:`k_p` is the proportional gain + * :math:`k_i` is the integrator gain * :math:`g` is the integrator gain limit :param profile: Profile number (0-31) :param adc: ADC channel to take IIR input from (0-7) - :param gain: Proportional gain (1). This is usually negative (closed + :param kp: Proportional gain (1). This is usually negative (closed loop, positive ADC voltage, positive setpoint). When 0, this - implements a pure I controller with unit gain frequency at - `corner` (use the sign of `corner` for overall gain sign). - :param corner: Integrator corner frequency (Hz). When 0 (the default) - this implements a pure P controller. - :param limit: Integrator gain limit (1). When 0 (the default) the - integrator gain limit is infinite. Positive. + implements a pure I controller. + :param ki: Integrator gain (rad/s). When 0 (the default) + this implements a pure P controller. Same sign as ``kp``. + :param g: Integrator gain limit (1). When 0 (the default) the + integrator gain limit is infinite. Same sign as ``ki``. :param delay: Delay (in seconds, 0-300 µs) before allowing IIR updates after invoking :meth:`set`. This is rounded to the nearest number of servo cycles (~1.2 µs). Since the RF switch (:meth:`set`) can be @@ -390,47 +388,34 @@ class Channel: """ B_NORM = 1 << COEFF_SHIFT + 1 A_NORM = 1 << COEFF_SHIFT - PI_TS = 3.1415927*T_CYCLE COEFF_MAX = 1 << COEFF_WIDTH - 1 - gain *= B_NORM - corner *= PI_TS - - if corner == 0.: + kp *= B_NORM + if ki == 0.: # pure P - a1_ = 0 - b1_ = 0 - b0_ = int(round(gain)) + a1 = 0 + b1 = 0 + b0 = int(round(kp)) else: - a1_ = A_NORM - if gain == 0.: - # pure I - b0 = (2*B_NORM)*corner - b1_ = 0 + # I or PI + ki *= B_NORM*T_CYCLE/2. + if g == 0.: + c = 1. + a1 = A_NORM else: - # PI - k = gain*corner - b1 = k - gain - b0 = k + gain - if limit != 0.: - # PI with limit - q = corner/limit - qr = 1./(1. + q) - a1_ = int(round(a1_*(1. - q)*qr)) - b0 *= qr - b1 *= qr - b1_ = int(round(b1)) - b0_ = int(round(b0)) + c = 1./(1. + ki/(g*B_NORM)) + a1 = int(round((2.*c - 1.)*A_NORM)) + b0 = int(round(kp + ki*c)) + b1 = int(round(kp + (ki - 2.*kp)*c)) + if b1 == -b0: + raise ValueError("low integrator gain and/or gain limit") - if b1_ == -b0_: - raise ValueError("low corner, gain, limit") - - if (b0_ >= COEFF_MAX or b0_ < -COEFF_MAX or - b1_ >= COEFF_MAX or b1_ < -COEFF_MAX): - raise ValueError("high corner, gain, limit") + if (b0 >= COEFF_MAX or b0 < -COEFF_MAX or + b1 >= COEFF_MAX or b1 < -COEFF_MAX): + raise ValueError("high gains") dly = int(round(delay/T_CYCLE)) - self.set_iir_mu(profile, adc, a1_, b0_, b1_, dly) + self.set_iir_mu(profile, adc, a1, b0, b1, dly) @kernel def get_profile_mu(self, profile, data): diff --git a/artiq/examples/kasli_suservo/repository/suservo.py b/artiq/examples/kasli_suservo/repository/suservo.py index b6def6286..7bc887030 100644 --- a/artiq/examples/kasli_suservo/repository/suservo.py +++ b/artiq/examples/kasli_suservo/repository/suservo.py @@ -50,9 +50,9 @@ class SUServo(EnvExperiment): self.suservo0_ch0.set_iir( profile=0, adc=7, # take data from Sampler channel 7 - gain=-.1, # -0.1 P gain - corner=70*Hz, # very low corner frequency - limit=0., # unlimited integrator gain + kp=-.1, # -0.1 P gain + ki=-300./s, # low integrator gain + g=0., # no integrator gain limit delay=0. # no IIR update delay after enabling ) # setpoint 0.5 (5 V with above PGIA gain setting) From b56d37eb633128ea4981bb9ed6ff1f9b50198f77 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 1 Jun 2018 14:22:15 +0200 Subject: [PATCH 0876/2457] manual: fix table --- doc/manual/default_network_ports.rst | 91 ++++++++++++++-------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/doc/manual/default_network_ports.rst b/doc/manual/default_network_ports.rst index c64ecb22f..6bb699ab9 100644 --- a/doc/manual/default_network_ports.rst +++ b/doc/manual/default_network_ports.rst @@ -1,48 +1,49 @@ Default network ports ===================== -+--------------------------------+--------------+ -| Component | Default port | -+================================+==============+ -| Core device (management) | 1380 | -|---------------------------------+-----------| -| Core device (main) | 1381 | -|---------------------------------+-----------| -| Core device (analyzer) | 1382 | -|---------------------------------+-----------| -| Core device (mon/inj) | 1383 | -|---------------------------------+-----------| -| Master (logging input) | 1066 | -|---------------------------------+-----------| -| Master (broadcasts) | 1067 | -|---------------------------------+-----------| -| Core device logging controller | 1068 | -|---------------------------------+-----------| -| InfluxDB bridge | 3248 | -|---------------------------------+-----------| -| Controller manager | 3249 | -|---------------------------------+-----------| -| Master (notifications) | 3250 | -|---------------------------------+-----------| -| Master (control) | 3251 | -|---------------------------------+-----------| -| PDQ2 (out-of-tree) | 3252 | -|---------------------------------+-----------| -| LDA | 3253 | -|---------------------------------+-----------| -| Novatech 409B | 3254 | -|---------------------------------+-----------| -| Thorlabs T-Cube | 3255 | -|---------------------------------+-----------| -| Korad KA3005P | 3256 | -|---------------------------------+-----------| -| Newfocus 8742 (out-of-tree) | 3257 | -|---------------------------------+-----------| -| PICam (out-of-tree) | 3258 | -|---------------------------------+-----------| -| PTB Drivers (out-of-tree) | 3259-3270 | -|---------------------------------+-----------| -| HUT2 (out-of-tree) | 3271 | -|---------------------------------+-----------| -| TOPTICA Laser SDK (out-of-tree) | 3272 | -|---------------------------------+-----------| ++---------------------------------+--------------+ +| Component | Default port | ++=================================+==============+ +| Core device (management) | 1380 | ++---------------------------------+--------------+ +| Core device (main) | 1381 | ++---------------------------------+--------------+ +| Core device (analyzer) | 1382 | ++---------------------------------+--------------+ +| Core device (mon/inj) | 1383 | ++---------------------------------+--------------+ +| Master (logging input) | 1066 | ++---------------------------------+--------------+ +| Master (broadcasts) | 1067 | ++---------------------------------+--------------+ +| Core device logging controller | 1068 | ++---------------------------------+--------------+ +| InfluxDB bridge | 3248 | ++---------------------------------+--------------+ +| Controller manager | 3249 | ++---------------------------------+--------------+ +| Master (notifications) | 3250 | ++---------------------------------+--------------+ +| Master (control) | 3251 | ++---------------------------------+--------------+ +| PDQ2 (out-of-tree) | 3252 | ++---------------------------------+--------------+ +| LDA | 3253 | ++---------------------------------+--------------+ +| Novatech 409B | 3254 | ++---------------------------------+--------------+ +| Thorlabs T-Cube | 3255 | ++---------------------------------+--------------+ +| Korad KA3005P | 3256 | ++---------------------------------+--------------+ +| Newfocus 8742 (out-of-tree) | 3257 | ++---------------------------------+--------------+ +| PICam (out-of-tree) | 3258 | ++---------------------------------+--------------+ +| PTB Drivers (out-of-tree) | 3259-3270 | ++---------------------------------+--------------+ +| HUT2 (out-of-tree) | 3271 | ++---------------------------------+--------------+ +| TOPTICA Laser SDK (out-of-tree) | 3272 | ++---------------------------------+--------------+ + From 2c344686d9b0f8c3f8cc65db692468e7ac443310 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 1 Jun 2018 13:06:52 +0000 Subject: [PATCH 0877/2457] ad53xx/zotino: enable overtemp shutdown and readback control --- artiq/coredevice/ad53xx.py | 49 ++++++++++++++----- .../kasli_basic/repository/kasli_tester.py | 2 +- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 0b10b3388..bc61b2760 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -8,9 +8,11 @@ time is an error. # Designed from the data sheets and somewhat after the linux kernel # iio driver. +from numpy import int32 + from artiq.language.core import (kernel, portable, delay_mu, delay, now_mu, at_mu) -from artiq.language.units import ns +from artiq.language.units import ns, us from artiq.coredevice import spi2 as spi SPI_AD53XX_CONFIG = (0*spi.SPI_OFFLINE | 1*spi.SPI_END | @@ -28,14 +30,25 @@ AD53XX_SPECIAL_CONTROL = 1 << 16 AD53XX_SPECIAL_OFS0 = 2 << 16 AD53XX_SPECIAL_OFS1 = 3 << 16 AD53XX_SPECIAL_READ = 5 << 16 +AD53XX_SPECIAL_AB0 = 6 << 16 +AD53XX_SPECIAL_AB1 = 7 << 16 +AD53XX_SPECIAL_AB2 = 8 << 16 +AD53XX_SPECIAL_AB3 = 9 << 16 +AD53XX_SPECIAL_AB = 11 << 16 +# incorporate the channel offset (8, table 17) here AD53XX_READ_X1A = 0x008 << 7 AD53XX_READ_X1B = 0x048 << 7 AD53XX_READ_OFFSET = 0x088 << 7 AD53XX_READ_GAIN = 0x0C8 << 7 + AD53XX_READ_CONTROL = 0x101 << 7 AD53XX_READ_OFS0 = 0x102 << 7 AD53XX_READ_OFS1 = 0x103 << 7 +AD53XX_READ_AB0 = 0x106 << 7 +AD53XX_READ_AB1 = 0x107 << 7 +AD53XX_READ_AB2 = 0x108 << 7 +AD53XX_READ_AB3 = 0x109 << 7 @portable @@ -61,10 +74,10 @@ def ad53xx_cmd_read_ch(channel, op): :param channel: DAC channel to read (8 bits) :param op: The channel register to read, one of :const:`AD53XX_READ_X1A`, :const:`AD53XX_READ_X1B`, - :const:`AD53XX_READ_OFFSET`, :const:`AD53XX_CMD_GAIN` etc. + :const:`AD53XX_READ_OFFSET`, :const:`AD53XX_READ_GAIN` etc. :return: The 24-bit word to be written to the DAC to initiate read """ - return (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_READ | (op + (channel << 7))) + return AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_READ | (op + (channel << 7)) @portable @@ -110,9 +123,9 @@ class AD53xx: valid) :param vref: DAC reference voltage (default: 5.) :param offset_dacs: Initial register value for the two offset DACs, device - dependent and must be set correctly for correct voltage to mu conversions. - Knowledge of his state is not transferred between experiments. - (default: 8192) + dependent and must be set correctly for correct voltage to mu + conversions. Knowledge of his state is not transferred between + experiments. (default: 8192) :param core_device: Core device name (default: "core") """ kernel_invariants = {"bus", "ldac", "clr", "chip_select", "div_write", @@ -139,19 +152,32 @@ class AD53xx: self.core = dmgr.get(core) @kernel - def init(self): - """Configures the SPI bus, drives LDAC and CLR high and programmes - the offset DACss. + def init(self, blind=False): + """Configures the SPI bus, drives LDAC and CLR high, programmes + the offset DACs, and enables overtemperature shutdown. This method must be called before any other method at start-up or if the SPI bus has been accessed by another device. - This method advances the timeline by one coarse RTIO cycle. + This method advances the timeline by several SPI transfers plus 10 µs. + + :param blind: If ``True``, do not attempt to read back control register + or check for overtemperature. """ self.ldac.on() self.clr.on() self.bus.set_config_mu(SPI_AD53XX_CONFIG, 24, self.div_write, self.chip_select) self.write_offset_dacs_mu(self.offset_dacs) + self.bus.write( # enable overtemperature shutdown + (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_CONTROL | 0b0010) << 8) + if blind: + return + ctrl = self.read_reg(channel=0, op=AD53XX_READ_CONTROL) + if ctrl & 0b10000: + raise ValueError("DAC over temperature") + if ctrl != 0b0010: + raise ValueError("DAC CONTROL readback mismatch") + delay(10*us) @kernel def read_reg(self, channel=0, op=AD53XX_READ_X1A): @@ -173,7 +199,8 @@ class AD53xx: self.bus.write((AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_NOP) << 8) self.bus.set_config_mu(SPI_AD53XX_CONFIG, 24, self.div_write, self.chip_select) - return self.bus.read() & 0xffff + # FIXME: the int32 should not be needed to resolve unification + return self.bus.read() & int32(0xffff) @kernel def write_offset_dacs_mu(self, value): diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index 6da122535..0054c2cff 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -253,7 +253,7 @@ class KasliTester(EnvExperiment): def set_zotino_voltages(self, zotino, voltages): self.core.break_realtime() zotino.init() - delay(100*us) + delay(200*us) i = 0 for voltage in voltages: zotino.write_dac(i, voltage) From 5de2d065689bd1702a3f4934e8ce7e772b12aabb Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 1 Jun 2018 13:17:13 +0000 Subject: [PATCH 0878/2457] ad53xx/zotino: do not clear power down on overtemp --- artiq/coredevice/ad53xx.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index bc61b2760..21c85a1d4 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -158,7 +158,6 @@ class AD53xx: This method must be called before any other method at start-up or if the SPI bus has been accessed by another device. - This method advances the timeline by several SPI transfers plus 10 µs. :param blind: If ``True``, do not attempt to read back control register or check for overtemperature. @@ -168,16 +167,18 @@ class AD53xx: self.bus.set_config_mu(SPI_AD53XX_CONFIG, 24, self.div_write, self.chip_select) self.write_offset_dacs_mu(self.offset_dacs) - self.bus.write( # enable overtemperature shutdown + if not blind: + ctrl = self.read_reg(channel=0, op=AD53XX_READ_CONTROL) + if ctrl & 0b10000: + raise ValueError("DAC over temperature") + delay(10*us) + self.bus.write( # enable power and overtemperature shutdown (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_CONTROL | 0b0010) << 8) - if blind: - return - ctrl = self.read_reg(channel=0, op=AD53XX_READ_CONTROL) - if ctrl & 0b10000: - raise ValueError("DAC over temperature") - if ctrl != 0b0010: - raise ValueError("DAC CONTROL readback mismatch") - delay(10*us) + if not blind: + ctrl = self.read_reg(channel=0, op=AD53XX_READ_CONTROL) + if ctrl != 0b0010: + raise ValueError("DAC CONTROL readback mismatch") + delay(10*us) @kernel def read_reg(self, channel=0, op=AD53XX_READ_X1A): From f50aef1a2226fb6cfa64583d6e7ed2c6401b01e6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 1 Jun 2018 15:33:09 +0000 Subject: [PATCH 0879/2457] suservo: extract boilerplate closes #1041 --- artiq/examples/kasli_suservo/device_db.py | 30 ++++----- artiq/gateware/eem.py | 78 +++++++++++++++++++++++ artiq/gateware/targets/kasli.py | 76 +++------------------- 3 files changed, 101 insertions(+), 83 deletions(-) diff --git a/artiq/examples/kasli_suservo/device_db.py b/artiq/examples/kasli_suservo/device_db.py index 2da2df0cf..d33bfb280 100644 --- a/artiq/examples/kasli_suservo/device_db.py +++ b/artiq/examples/kasli_suservo/device_db.py @@ -1,4 +1,4 @@ -core_addr = "10.0.16.119" +core_addr = "10.0.16.121" device_db = { "core": { @@ -135,20 +135,6 @@ device_db = { "arguments": {"channel": 15}, }, - "suservo0": { - "type": "local", - "module": "artiq.coredevice.suservo", - "class": "SUServo", - "arguments": { - "channel": 24, - "pgia_device": "spi_sampler0_pgia", - "cpld0_device": "urukul0_cpld", - "cpld1_device": "urukul1_cpld", - "dds0_device": "urukul0_dds", - "dds1_device": "urukul1_dds" - } - }, - "suservo0_ch0": { "type": "local", "module": "artiq.coredevice.suservo", @@ -198,6 +184,20 @@ device_db = { "arguments": {"channel": 23, "servo_device": "suservo0"} }, + "suservo0": { + "type": "local", + "module": "artiq.coredevice.suservo", + "class": "SUServo", + "arguments": { + "channel": 24, + "pgia_device": "spi_sampler0_pgia", + "cpld0_device": "urukul0_cpld", + "cpld1_device": "urukul1_cpld", + "dds0_device": "urukul0_dds", + "dds1_device": "urukul1_dds" + } + }, + "spi_sampler0_pgia": { "type": "local", "module": "artiq.coredevice.spi2", diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 007430338..31879f324 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -4,6 +4,8 @@ from migen.genlib.io import DifferentialOutput from artiq.gateware import rtio from artiq.gateware.rtio.phy import spi2, grabber +from artiq.gateware.suservo import servo, pads as servo_pads +from artiq.gateware.rtio.phy import servo as rtservo def _eem_signal(i): @@ -429,3 +431,79 @@ class Grabber(_EEM): phy = ttl_out_cls(pads.p, pads.n) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy)) + + +class SUServo(_EEM): + @staticmethod + def io(*eems): + assert len(eems) == 6 + return (Sampler.io(*eems[0:2]) + + Urukul.io_qspi(*eems[2:4]) + + Urukul.io_qspi(*eems[4:6])) + + @classmethod + def add_std(cls, target, eems_sampler, eems_urukul0, eems_urukul1, + t_rtt=4, clk=1, shift=11, profile=5): + cls.add_extension( + target, *(eems_sampler + eems_urukul0 + eems_urukul1)) + eem_sampler = "sampler{}".format(eems_sampler[0]) + eem_urukul0 = "urukul{}".format(eems_urukul0[0]) + eem_urukul1 = "urukul{}".format(eems_urukul1[0]) + + sampler_pads = servo_pads.SamplerPads(target.platform, eem_sampler) + urukul_pads = servo_pads.UrukulPads( + target.platform, eem_urukul0, eem_urukul1) + # timings in units of RTIO coarse period + adc_p = servo.ADCParams(width=16, channels=8, lanes=4, t_cnvh=4, + # account for SCK pipeline latency + t_conv=57 - 4, t_rtt=t_rtt + 4) + iir_p = servo.IIRWidths(state=25, coeff=18, adc=16, asf=14, word=16, + accu=48, shift=shift, channel=3, + profile=profile) + dds_p = servo.DDSParams(width=8 + 32 + 16 + 16, + channels=adc_p.channels, clk=clk) + su = servo.Servo(sampler_pads, urukul_pads, adc_p, iir_p, dds_p) + su = ClockDomainsRenamer("rio_phy")(su) + target.submodules += sampler_pads, urukul_pads, su + + ctrls = [rtservo.RTServoCtrl(ctrl) for ctrl in su.iir.ctrl] + target.submodules += ctrls + target.rtio_channels.extend( + rtio.Channel.from_phy(ctrl) for ctrl in ctrls) + mem = rtservo.RTServoMem(iir_p, su) + target.submodules += mem + target.rtio_channels.append(rtio.Channel.from_phy(mem, ififo_depth=4)) + + phy = spi2.SPIMaster( + target.platform.request("{}_pgia_spi_p".format(eem_sampler)), + target.platform.request("{}_pgia_spi_n".format(eem_sampler))) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + phy = spi2.SPIMaster( + target.platform.request("{}_spi_p".format(eem_urukul0)), + target.platform.request("{}_spi_n".format(eem_urukul0))) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + pads = target.platform.request("{}_dds_reset".format(eem_urukul0)) + target.specials += DifferentialOutput(0, pads.p, pads.n) + + for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): + pads = target.platform.request("{}_{}".format(eem_urukul0, signal)) + target.specials += DifferentialOutput( + su.iir.ctrl[i].en_out, pads.p, pads.n) + + phy = spi2.SPIMaster( + target.platform.request("{}_spi_p".format(eem_urukul1)), + target.platform.request("{}_spi_n".format(eem_urukul1))) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + pads = target.platform.request("{}_dds_reset".format(eem_urukul1)) + target.specials += DifferentialOutput(0, pads.p, pads.n) + + for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): + pads = target.platform.request("{}_{}".format(eem_urukul1, signal)) + target.specials += DifferentialOutput( + su.iir.ctrl[i + 4].en_out, pads.p, pads.n) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index c340df435..858c8fb59 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -16,9 +16,7 @@ from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio -from artiq.gateware.rtio.phy import ( - ttl_simple, ttl_serdes_7series, spi2, servo as rtservo) -from artiq.gateware.suservo import servo, pads as servo_pads +from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series from artiq.gateware import eem from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series @@ -211,67 +209,10 @@ class SUServo(_StandaloneBase): eem.DIO.add_std(self, 1, ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) - # EEM3, EEM2: Sampler - self.platform.add_extension(eem.Sampler.io(3, 2)) - sampler_pads = servo_pads.SamplerPads(self.platform, "sampler3") - # EEM5, EEM4 and EEM7, EEM6: Urukul - self.platform.add_extension(eem.Urukul.io_qspi(5, 4)) - self.platform.add_extension(eem.Urukul.io_qspi(7, 6)) - urukul_pads = servo_pads.UrukulPads(self.platform, - "urukul5", "urukul7") - adc_p = servo.ADCParams(width=16, channels=8, lanes=4, t_cnvh=4, - # account for SCK pipeline latency - t_conv=57 - 4, t_rtt=4 + 4) - iir_p = servo.IIRWidths(state=25, coeff=18, adc=16, asf=14, word=16, - accu=48, shift=11, channel=3, profile=5) - dds_p = servo.DDSParams(width=8 + 32 + 16 + 16, - channels=adc_p.channels, clk=1) - su = servo.Servo(sampler_pads, urukul_pads, adc_p, iir_p, dds_p) - su = ClockDomainsRenamer("rio_phy")(su) - self.submodules += sampler_pads, urukul_pads, su - - ctrls = [rtservo.RTServoCtrl(ctrl) for ctrl in su.iir.ctrl] - self.submodules += ctrls - self.rtio_channels.extend(rtio.Channel.from_phy(ctrl) for ctrl in ctrls) - mem = rtservo.RTServoMem(iir_p, su) - self.submodules += mem - self.rtio_channels.append(rtio.Channel.from_phy(mem, ififo_depth=4)) - - # EEM3: Sampler - phy = spi2.SPIMaster(self.platform.request("sampler3_pgia_spi_p"), - self.platform.request("sampler3_pgia_spi_n")) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - - # EEM5 + EEM4: Urukul - phy = spi2.SPIMaster(self.platform.request("urukul5_spi_p"), - self.platform.request("urukul5_spi_n")) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - - pads = self.platform.request("urukul5_dds_reset") - self.specials += DifferentialOutput(0, pads.p, pads.n) - - for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): - pads = self.platform.request("urukul5_{}".format(signal)) - self.specials += DifferentialOutput( - su.iir.ctrl[i].en_out, - pads.p, pads.n) - - # EEM7 + EEM6: Urukul - phy = spi2.SPIMaster(self.platform.request("urukul7_spi_p"), - self.platform.request("urukul7_spi_n")) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - - pads = self.platform.request("urukul7_dds_reset") - self.specials += DifferentialOutput(0, pads.p, pads.n) - - for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): - pads = self.platform.request("urukul7_{}".format(signal)) - self.specials += DifferentialOutput( - su.iir.ctrl[i + 4].en_out, - pads.p, pads.n) + # EEM3/2: Sampler, EEM5/4: Urukul, EEM7/6: Urukul + eem.SUServo.add_std( + self, eems_sampler=(3, 2), + eems_urukul0=(5, 4), eems_urukul1=(7, 6)) for i in (1, 2): sfp_ctl = self.platform.request("sfp_ctl", i) @@ -285,12 +226,11 @@ class SUServo(_StandaloneBase): self.add_rtio(self.rtio_channels) + pads = self.platform.lookup_request("sampler3_adc_data_p") self.platform.add_false_path_constraints( - sampler_pads.clkout_p, - self.rtio_crg.cd_rtio.clk) + pads.clkout, self.rtio_crg.cd_rtio.clk) self.platform.add_false_path_constraints( - sampler_pads.clkout_p, - self.crg.cd_sys.clk) + pads.clkout, self.crg.cd_sys.clk) class SYSU(_StandaloneBase): From 62deffa7d2d1edbb437e7f8132a4ad2a2df10217 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Fri, 1 Jun 2018 15:39:23 +0000 Subject: [PATCH 0880/2457] opticlock: fix core device name --- artiq/examples/kasli_basic/device_db_opticlock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/kasli_basic/device_db_opticlock.py b/artiq/examples/kasli_basic/device_db_opticlock.py index 0da3c204d..068aba9fa 100644 --- a/artiq/examples/kasli_basic/device_db_opticlock.py +++ b/artiq/examples/kasli_basic/device_db_opticlock.py @@ -1,7 +1,7 @@ # This is an example device database that needs to be adapted to your setup. # The list of devices here is not exhaustive. -core_addr = "vettel.ber.quartiq.de" +core_addr = "hunt.ptb.quartiq.de" device_db = { "core": { From f1a80f12f85714ce16b8f66cda6234c0a1471089 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 1 Jun 2018 18:46:49 +0000 Subject: [PATCH 0881/2457] doc: note that coreanalyzer lacks SAWG support. Closes #1035. --- doc/manual/utilities.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/manual/utilities.rst b/doc/manual/utilities.rst index 595756ec3..9374a6930 100644 --- a/doc/manual/utilities.rst +++ b/doc/manual/utilities.rst @@ -176,6 +176,9 @@ Core device RTIO analyzer tool :ref: artiq.frontend.artiq_coreanalyzer.get_argparser :prog: artiq_coreanalyzer +.. note:: + The RTIO analyzer does not support SAWG. + Data to InfluxDB bridge ----------------------- From 985fd7377b853548b8fc22cd8b7d5358548a773c Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 1 Jun 2018 19:16:26 +0000 Subject: [PATCH 0882/2457] artiq_rpctool: use inspect.formatargspec instead of a NIH formatter. Fixes #1029. --- artiq/frontend/artiq_rpctool.py | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/artiq/frontend/artiq_rpctool.py b/artiq/frontend/artiq_rpctool.py index 74cb8890a..fb9844f29 100755 --- a/artiq/frontend/artiq_rpctool.py +++ b/artiq/frontend/artiq_rpctool.py @@ -6,6 +6,7 @@ import sys import traceback import numpy as np # Needed to use numpy in RPC call arguments on cmd line import pprint +import inspect from artiq.protocols.pc_rpc import AutoTarget, Client @@ -46,33 +47,7 @@ def list_methods(remote): print(doc["docstring"]) print() for name, (argspec, docstring) in sorted(doc["methods"].items()): - args = "" - for arg in argspec["args"]: - args += arg - if argspec["defaults"] is not None: - kword_index = len(argspec["defaults"]) - len(argspec["args"])\ - + argspec["args"].index(arg) - if kword_index >= 0: - if argspec["defaults"][kword_index] == Ellipsis: - args += "=..." - else: - args += "={}".format(argspec["defaults"][kword_index]) - if argspec["args"].index(arg) < len(argspec["args"]) - 1: - args += ", " - if argspec["varargs"] is not None: - args += ", *{}".format(argspec["varargs"]) - elif len(argspec["kwonlyargs"]) > 0: - args += ", *" - for kwonlyarg in argspec["kwonlyargs"]: - args += ", {}".format(kwonlyarg) - if kwonlyarg in argspec["kwonlydefaults"]: - if argspec["kwonlydefaults"][kwonlyarg] == Ellipsis: - args += "=..." - else: - args += "={}".format(argspec["kwonlydefaults"][kwonlyarg]) - if argspec["varkw"] is not None: - args += ", **{}".format(argspec["varkw"]) - print("{}({})".format(name, args)) + print(name + inspect.formatargspec(**argspec)) if docstring is not None: print(textwrap.indent(docstring, " ")) print() From d686d3309355ed43038a13b82920307467da6781 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 1 Jun 2018 21:17:59 +0000 Subject: [PATCH 0883/2457] runtime: print hex dumps around PC/EA in case of exception. For #1026. --- artiq/firmware/runtime/main.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index eaaa1721d..d222d7f2d 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -1,4 +1,4 @@ -#![feature(lang_items, alloc, global_allocator, try_from, nonzero, nll, needs_panic_runtime)] +#![feature(lang_items, alloc, global_allocator, try_from, nonzero, nll, needs_panic_runtime, asm)] #![no_std] #![needs_panic_runtime] @@ -302,7 +302,24 @@ pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { _ => panic!("spurious irq {}", irq::pending_mask().trailing_zeros()) } }, - _ => panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea) + _ => { + fn hexdump(addr: u32) { + let addr = (addr - addr % 4) as *const u32; + let mut ptr = addr; + println!("@ {:08p}", ptr); + for _ in 0..4 { + print!("+{:04x}: ", ptr as usize - addr as usize); + print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); + print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); + print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); + print!("{:08x}\n", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); + } + } + + hexdump(pc); + hexdump(ea); + panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea) + } } } From 07a1425e51432aa056adb49094eab252988d10ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 4 Jun 2018 08:51:28 +0200 Subject: [PATCH 0884/2457] SUservo EEM docs add documentation to eem.SUServo. Change parameterization of t_rtt to include delays on Sampler, as this seems simpler and more robust to changing RTIO frequencies in the future. c.f. #1046 --- artiq/gateware/eem.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 31879f324..1bcb71c12 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -443,7 +443,23 @@ class SUServo(_EEM): @classmethod def add_std(cls, target, eems_sampler, eems_urukul0, eems_urukul1, - t_rtt=4, clk=1, shift=11, profile=5): + t_rtt=8, clk=1, shift=11, profile=5): + """ Adds an 8-channel Sampler-Urukul servo to target. + + :param t_rtt: upper estimate for clock round-trip propagation time from + sck at the FPGA to clkout at the FPGA, measured in RTIO coarse + cycles (default: 8). This is the sum of the round-trip cabling + delay and the 8ns max propagation delay on Sampler. With all + other parameters at their default values, increasing t_rtt beyond 8 + increases the servo latency + :param clk: DDS SPI clock cycle half-width in RTIO coarse cycles + (default: 1) + :param shift: fixed-point scaling factor for IIR coefficients + (default: 11) + :param profile: log2 of the number of profiles for each DDS channel + (default: 5) + """ + cls.add_extension( target, *(eems_sampler + eems_urukul0 + eems_urukul1)) eem_sampler = "sampler{}".format(eems_sampler[0]) @@ -456,7 +472,7 @@ class SUServo(_EEM): # timings in units of RTIO coarse period adc_p = servo.ADCParams(width=16, channels=8, lanes=4, t_cnvh=4, # account for SCK pipeline latency - t_conv=57 - 4, t_rtt=t_rtt + 4) + t_conv=57 - 4, t_rtt=t_rtt) iir_p = servo.IIRWidths(state=25, coeff=18, adc=16, asf=14, word=16, accu=48, shift=shift, channel=3, profile=profile) From bb87976d4fdb6163c9a7fecad980630df9e1d3ae Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 4 Jun 2018 07:27:17 +0000 Subject: [PATCH 0885/2457] suservo: docstring fixes, revert parametrization of r_rtt --- artiq/gateware/eem.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 1bcb71c12..5b5180239 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -443,15 +443,16 @@ class SUServo(_EEM): @classmethod def add_std(cls, target, eems_sampler, eems_urukul0, eems_urukul1, - t_rtt=8, clk=1, shift=11, profile=5): - """ Adds an 8-channel Sampler-Urukul servo to target. + t_rtt=4, clk=1, shift=11, profile=5): + """Add a 8-channel Sampler-Urukul Servo :param t_rtt: upper estimate for clock round-trip propagation time from - sck at the FPGA to clkout at the FPGA, measured in RTIO coarse - cycles (default: 8). This is the sum of the round-trip cabling - delay and the 8ns max propagation delay on Sampler. With all - other parameters at their default values, increasing t_rtt beyond 8 - increases the servo latency + ``sck`` at the FPGA to ``clkout`` at the FPGA, measured in RTIO + coarse cycles (default: 4). This is the sum of the round-trip + cabling delay and the 8 ns max propagation delay on Sampler (ADC + and LVDS drivers). Increasing ``t_rtt`` increases servo latency. + With all other parameters at their default values, ``t_rtt`` values + above 4 also increase the servo period (reduce servo bandwidth). :param clk: DDS SPI clock cycle half-width in RTIO coarse cycles (default: 1) :param shift: fixed-point scaling factor for IIR coefficients @@ -459,7 +460,6 @@ class SUServo(_EEM): :param profile: log2 of the number of profiles for each DDS channel (default: 5) """ - cls.add_extension( target, *(eems_sampler + eems_urukul0 + eems_urukul1)) eem_sampler = "sampler{}".format(eems_sampler[0]) @@ -468,11 +468,12 @@ class SUServo(_EEM): sampler_pads = servo_pads.SamplerPads(target.platform, eem_sampler) urukul_pads = servo_pads.UrukulPads( - target.platform, eem_urukul0, eem_urukul1) + target.platform, eem_urukul0, eem_urukul1) # timings in units of RTIO coarse period adc_p = servo.ADCParams(width=16, channels=8, lanes=4, t_cnvh=4, - # account for SCK pipeline latency - t_conv=57 - 4, t_rtt=t_rtt) + # account for SCK DDR to CONV latency + # difference (4 cycles measured) + t_conv=57 - 4, t_rtt=t_rtt + 4) iir_p = servo.IIRWidths(state=25, coeff=18, adc=16, asf=14, word=16, accu=48, shift=shift, channel=3, profile=profile) From 925b47b077b5f84e2ec7a0c1b222afe6f7b249f9 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 4 Jun 2018 14:03:26 +0200 Subject: [PATCH 0886/2457] firmware/ad9154: reset the dac between each configuration attempt --- artiq/firmware/libboard_artiq/ad9154.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 00b2364dd..ace248fda 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -613,6 +613,7 @@ fn dac_cfg(dacno: u8) -> Result<(), &'static str> { fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { for i in 0..99 { + dac_reset(dacno); let outcome = dac_cfg(dacno); match outcome { Ok(_) => return outcome, From 07d4145a35c73978b2ef4b648bcf8630ea43a1e1 Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Mon, 4 Jun 2018 12:28:44 +0100 Subject: [PATCH 0887/2457] correct documented siphaser VCO frequency [NFC] --- artiq/gateware/drtio/siphaser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/siphaser.py b/artiq/gateware/drtio/siphaser.py index 893b9e91d..aa2cbb05f 100644 --- a/artiq/gateware/drtio/siphaser.py +++ b/artiq/gateware/drtio/siphaser.py @@ -14,7 +14,7 @@ class SiPhaser7Series(Module, AutoCSR): self.phase_shift_done = CSRStatus(reset=1) self.sample_result = CSRStatus() - # 125MHz/62.5MHz reference clock to 150MHz. VCO @ 625MHz. + # 125MHz/62.5MHz reference clock to 150MHz. VCO @ 750MHz. # Used to provide a startup clock to the transceiver through the Si, # we do not use the crystal reference so that the PFD (f3) frequency # can be high. From b82158a2def952b6b9c2220f9829b3ad43534ac3 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 5 Jun 2018 02:08:57 +0200 Subject: [PATCH 0888/2457] firmware/ad9154: add stpl test --- artiq/firmware/libboard_artiq/ad9154.rs | 61 ++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index ace248fda..02f2d7a77 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -573,6 +573,64 @@ fn dac_prbs(dacno: u8) -> Result<(), &'static str> { Ok(()) } +fn dac_stpl(dacno: u8, m: u8, s: u8) -> Result<(), &'static str> { + spi_setup(dacno); + + info!("AD9154-{} running STPL test...", dacno); + + fn prng(seed: u32) -> u32 { + return ((seed + 1)*0x31415979 + 1) & 0xffff; + } + + jesd_stpl(dacno, true); + for i in 0..m { + let mut data: u32; + let mut errors: u8 = 0; + for j in 0..s { + /* select converter */ + write(ad9154_reg::SHORT_TPL_TEST_0, + 0b0*ad9154_reg::SHORT_TPL_TEST_EN | + 0b0*ad9154_reg::SHORT_TPL_TEST_RESET | + i*ad9154_reg::SHORT_TPL_DAC_SEL | + j*ad9154_reg::SHORT_TPL_SP_SEL); + + /* set expected value */ + data = prng(((i as u32) << 8) | (j as u32)); + write(ad9154_reg::SHORT_TPL_TEST_1, (data & 0x00ff) as u8); + write(ad9154_reg::SHORT_TPL_TEST_2, ((data & 0xff00) >> 8) as u8); + + /* enable stpl */ + write(ad9154_reg::SHORT_TPL_TEST_0, + 0b1*ad9154_reg::SHORT_TPL_TEST_EN | + 0b0*ad9154_reg::SHORT_TPL_TEST_RESET | + i*ad9154_reg::SHORT_TPL_DAC_SEL | + j*ad9154_reg::SHORT_TPL_SP_SEL); + + /* reset stpl */ + write(ad9154_reg::SHORT_TPL_TEST_0, + 0b1*ad9154_reg::SHORT_TPL_TEST_EN | + 0b1*ad9154_reg::SHORT_TPL_TEST_RESET | + i*ad9154_reg::SHORT_TPL_DAC_SEL | + j*ad9154_reg::SHORT_TPL_SP_SEL); + + /* release reset stpl */ + write(ad9154_reg::SHORT_TPL_TEST_0, + 0b1*ad9154_reg::SHORT_TPL_TEST_EN | + 0b0*ad9154_reg::SHORT_TPL_TEST_RESET | + i*ad9154_reg::SHORT_TPL_DAC_SEL | + j*ad9154_reg::SHORT_TPL_SP_SEL); + errors += read(ad9154_reg::SHORT_TPL_TEST_3); + } + info!(" c{} errors: {}", i, errors); + if errors > 0 { + return Err("STPL failed") + } + } + jesd_stpl(dacno, false); + info!(" ...passed"); + Ok(()) +} + fn dac_cfg(dacno: u8) -> Result<(), &'static str> { spi_setup(dacno); jesd_enable(dacno, false); @@ -671,8 +729,9 @@ pub fn init() -> Result<(), &'static str> { dac_reset(dacno); dac_detect(dacno)?; dac_cfg_retry(dacno)?; - // Run the PRBS and SYSREF scan tests + // Run the PRBS, STPL and SYSREF scan tests dac_prbs(dacno)?; + dac_stpl(dacno, 4, 2)?; dac_sysref_scan(dacno); // Set SYSREF phase and reconfigure the DAC dac_sysref_cfg(dacno, 88); From ac5c4913ec99579e8035276e0da5b2933e2d3722 Mon Sep 17 00:00:00 2001 From: Thomas Harty Date: Mon, 4 Jun 2018 13:59:08 +0100 Subject: [PATCH 0889/2457] Sayma RTM: hold hmc7043 in reset/mute state during init. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 23 ++++++++++++-------- artiq/gateware/targets/sayma_rtm.py | 11 +++++++--- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index f713a1380..11dc77b2b 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -224,10 +224,17 @@ pub mod hmc7043 { Ok(()) } - pub fn shutdown() -> Result<(), &'static str> { + pub fn enable() -> Result<(), &'static str> { + info!("enabling hmc7043"); + + unsafe { + csr::crg::hmc7043_rst_write(0); + } + spi_setup(); - info!("shutting down"); - write(0x1, 0x1); // Sleep mode + write(0x0, 0x1); // Software reset + write(0x0, 0x0); // Normal operation + write(0x1, 0x48); // mute all outputs Ok(()) } @@ -236,10 +243,6 @@ pub mod hmc7043 { spi_setup(); info!("loading configuration..."); - write(0x0, 0x1); // Software reset - write(0x0, 0x0); - - write(0x1, 0x40); // Enable high-performace/low-noise mode write(0x3, 0x10); // Disable SYSREF timer write(0xA, 0x06); // Disable the REFSYNCIN input write(0xB, 0x07); // Enable the CLKIN input as LVPECL @@ -276,6 +279,7 @@ pub mod hmc7043 { write(channel_base + 0x8, 0x08) } + write(0x1, 0x40); // Unmute, high-performace/low-noise mode info!(" ...done"); Ok(()) @@ -305,8 +309,9 @@ pub fn init() -> Result<(), &'static str> { /* do not use other SPI devices before HMC830 SPI mode selection */ hmc830::select_spi_mode(); hmc830::detect()?; - hmc7043::detect()?; - hmc7043::shutdown()?; hmc830::init()?; + + hmc7043::enable()?; + hmc7043::detect()?; hmc7043::init() } diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 3b795b2b5..f71f9a9ca 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -19,8 +19,11 @@ from artiq.gateware import serwb from artiq import __version__ as artiq_version -class CRG(Module): +class CRG(Module, AutoCSR): def __init__(self, platform): + + self.hmc7043_rst = CSRStorage(reset=1) + self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) self.clock_domains.cd_clk200 = ClockDomain() @@ -31,7 +34,7 @@ class CRG(Module): serwb_refclk_bufr = Signal() serwb_refclk_bufg = Signal() self.specials += Instance("BUFR", i_I=self.serwb_refclk, o_O=serwb_refclk_bufr) - self.specials += Instance("BUFG", i_I=serwb_refclk_bufr, o_O=serwb_refclk_bufg) + self.specials += Instance("BUFG", i_I=serwb_refclk_bufr, o_O=serwb_refclk_bufg) pll_locked = Signal() pll_fb = Signal() @@ -110,6 +113,8 @@ class SaymaRTM(Module): csr_devices = [] self.submodules.crg = CRG(platform) + csr_devices.append("crg") + clk_freq = 125e6 self.submodules.rtm_magic = RTMMagic() @@ -174,7 +179,7 @@ class SaymaRTM(Module): platform.request("ad9154_spi", 0), platform.request("ad9154_spi", 1))) csr_devices.append("converter_spi") - self.comb += platform.request("hmc7043_reset").eq(0) + self.comb += platform.request("hmc7043_reset").eq(self.crg.hmc7043_rst.storage) # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") From bd1ac7cf3bffd383ef2c90ee51e429dbcf51f463 Mon Sep 17 00:00:00 2001 From: Thomas Harty Date: Tue, 5 Jun 2018 12:00:58 +0100 Subject: [PATCH 0890/2457] Configure HMC7043 to give deterministic phase differences between its outputs --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 11dc77b2b..9a2aa5ac6 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -146,6 +146,7 @@ pub mod hmc7043 { const DAC_CLK_DIV: u32 = 2; const FPGA_CLK_DIV: u32 = 8; const SYSREF_DIV: u32 = 128; + const HMC_SYSREF_DIV: u32 = SYSREF_DIV*8; // Must be <= 4MHz // enabled, divider, analog phase shift, digital phase shift const OUTPUT_CONFIG: [(bool, u32, u8, u8); 14] = [ @@ -243,7 +244,6 @@ pub mod hmc7043 { spi_setup(); info!("loading configuration..."); - write(0x3, 0x10); // Disable SYSREF timer write(0xA, 0x06); // Disable the REFSYNCIN input write(0xB, 0x07); // Enable the CLKIN input as LVPECL write(0x50, 0x1f); // Disable GPO pin @@ -257,14 +257,17 @@ pub mod hmc7043 { (1 << 4) | (1 << 5)); + write(0x5c, (HMC_SYSREF_DIV & 0xff) as u8); // Set SYSREF timer divider + write(0x5d, ((HMC_SYSREF_DIV & 0x0f) >> 8) as u8); + for channel in 0..14 { let channel_base = 0xc8 + 0x0a*(channel as u16); let (enabled, divider, aphase, dphase) = OUTPUT_CONFIG[channel]; if enabled { // Only clock channels need to be high-performance - if (channel % 2) == 0 { write(channel_base, 0x91); } - else { write(channel_base, 0x11); } + if (channel % 2) == 0 { write(channel_base, 0xd1); } + else { write(channel_base, 0x51); } } else { write(channel_base, 0x10); } write(channel_base + 0x1, (divider & 0x0ff) as u8); @@ -279,7 +282,11 @@ pub mod hmc7043 { write(channel_base + 0x8, 0x08) } + write(0x1, 0x4a); // Reset dividers and FSMs + write(0x1, 0x48); + write(0x1, 0xc8); // Synchronize dividers write(0x1, 0x40); // Unmute, high-performace/low-noise mode + info!(" ...done"); Ok(()) From 988054f4bbd13a42f779bdf28d3ef28a83fa5ef4 Mon Sep 17 00:00:00 2001 From: Thomas Harty Date: Tue, 5 Jun 2018 12:02:26 +0100 Subject: [PATCH 0891/2457] Sayma: fix mistake in HMC7043 init code. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 9a2aa5ac6..b44260ca8 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -270,8 +270,8 @@ pub mod hmc7043 { else { write(channel_base, 0x51); } } else { write(channel_base, 0x10); } - write(channel_base + 0x1, (divider & 0x0ff) as u8); - write(channel_base + 0x2, ((divider & 0x700) >> 8) as u8); + write(channel_base + 0x1, (divider & 0xff) as u8); + write(channel_base + 0x2, ((divider & 0x0f) >> 8) as u8); write(channel_base + 0x3, aphase & 0x1f); write(channel_base + 0x4, dphase & 0x1f); From af88c4c93e8df61dafb7400a0bdc6417eed1700c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Jun 2018 20:41:48 +0800 Subject: [PATCH 0892/2457] clean up hmc7043 reset --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 2 +- artiq/gateware/targets/sayma_rtm.py | 10 ++++------ conda/artiq-dev/meta.yaml | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index b44260ca8..bc4e94e9b 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -229,7 +229,7 @@ pub mod hmc7043 { info!("enabling hmc7043"); unsafe { - csr::crg::hmc7043_rst_write(0); + csr::hmc7043_reset::out_write(0); } spi_setup(); diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index f71f9a9ca..ac376f5d2 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -19,11 +19,8 @@ from artiq.gateware import serwb from artiq import __version__ as artiq_version -class CRG(Module, AutoCSR): +class CRG(Module): def __init__(self, platform): - - self.hmc7043_rst = CSRStorage(reset=1) - self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) self.clock_domains.cd_clk200 = ClockDomain() @@ -113,7 +110,6 @@ class SaymaRTM(Module): csr_devices = [] self.submodules.crg = CRG(platform) - csr_devices.append("crg") clk_freq = 125e6 @@ -179,7 +175,9 @@ class SaymaRTM(Module): platform.request("ad9154_spi", 0), platform.request("ad9154_spi", 1))) csr_devices.append("converter_spi") - self.comb += platform.request("hmc7043_reset").eq(self.crg.hmc7043_rst.storage) + self.submodules.hmc7043_reset = gpio.GPIOOut( + platform.request("hmc7043_reset"), reset_out=1) + csr_devices.append("hmc7043_reset") # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 761ff37e4..d9b47bd8f 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_35+git9bc084a - - misoc 0.11 py35_15+git7f63aff5 + - misoc 0.11 py35_18+gitfb92c5ee - jesd204b 0.6 - microscope - binutils-or1k-linux >=2.27 From c28fe47164f9b3983be249569717991a7114dbec Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Jun 2018 21:11:57 +0800 Subject: [PATCH 0893/2457] conda: fix misoc version --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index d9b47bd8f..89397a5c4 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_35+git9bc084a - - misoc 0.11 py35_18+gitfb92c5ee + - misoc 0.11 py35_19+git86c6fcb3 - jesd204b 0.6 - microscope - binutils-or1k-linux >=2.27 From 38dac16041ab5e0bfc13282fd0e6877814eb41a4 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 5 Jun 2018 23:23:40 +0000 Subject: [PATCH 0894/2457] compiler: don't crash when quoting builtin functions. Fixes #1051. --- artiq/compiler/transforms/llvm_ir_generator.py | 4 ++-- artiq/compiler/types.py | 8 ++++++++ artiq/test/coredevice/test_embedding.py | 5 +++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index b2fea1852..25d7c6859 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -1546,8 +1546,8 @@ class LLVMIRGenerator: lleltsptr = llglobal.bitcast(lleltsary.type.element.as_pointer()) llconst = ll.Constant(llty, [lleltsptr, ll.Constant(lli32, len(llelts))]) return llconst - elif types.is_rpc(typ) or types.is_c_function(typ): - # RPC and C functions have no runtime representation. + elif types.is_rpc(typ) or types.is_c_function(typ) or types.is_builtin_function(typ): + # RPC, C and builtin functions have no runtime representation. return ll.Constant(llty, ll.Undefined) elif types.is_function(typ): try: diff --git a/artiq/compiler/types.py b/artiq/compiler/types.py index be76adf5a..6e5015f48 100644 --- a/artiq/compiler/types.py +++ b/artiq/compiler/types.py @@ -605,6 +605,14 @@ def is_builtin(typ, name=None): return isinstance(typ, TBuiltin) and \ typ.name == name +def is_builtin_function(typ, name=None): + typ = typ.find() + if name is None: + return isinstance(typ, TBuiltinFunction) + else: + return isinstance(typ, TBuiltinFunction) and \ + typ.name == name + def is_constructor(typ, name=None): typ = typ.find() if name is not None: diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 26277a7c9..b0bcbbed3 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -211,6 +211,10 @@ class _RPCCalls(EnvExperiment): def numpy_full(self): return numpy.full(10, 20) + @kernel + def numpy_nan(self): + return numpy.full(10, numpy.nan) + @kernel def builtin(self): sleep(1.0) @@ -229,6 +233,7 @@ class RPCCallsTest(ExperimentCase): self.assertEqual(exp.numpy_things(), (numpy.int32(10), numpy.int64(20), numpy.array([42,]))) self.assertTrue((exp.numpy_full() == numpy.full(10, 20)).all()) + self.assertTrue(numpy.isnan(exp.numpy_nan()).all()) exp.builtin() From 0d1b36c89b7f7f1d4eb332e20768cc50496a6bc3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 6 Jun 2018 11:47:54 +0800 Subject: [PATCH 0895/2457] jesd204: bump --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 89397a5c4..37afb1ba3 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -16,7 +16,7 @@ requirements: - setuptools 33.1.1 - migen 0.7 py35_35+git9bc084a - misoc 0.11 py35_19+git86c6fcb3 - - jesd204b 0.6 + - jesd204b 0.7 - microscope - binutils-or1k-linux >=2.27 - llvm-or1k 6.0.0 From e21b7965b9d37da7527b42ae6569bc7c4b035f61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 6 Jun 2018 08:02:20 +0000 Subject: [PATCH 0896/2457] sayma_amc: change test patterns for 'without-sawg' --- artiq/gateware/targets/sayma_amc.py | 36 +++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 09d686c3b..b7aebf62f 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -122,11 +122,37 @@ class AD9154NoSAWG(Module, AutoCSR): self.sawgs = [] - for i, conv in enumerate(self.jesd.core.sink.flatten()): - ramp = Signal(16) - self.sync.rtio += ramp.eq(ramp + (1 << 9 + i)) - self.comb += conv.eq(Cat(ramp - for i in range(len(conv) // len(ramp)))) + ramp = Signal(4) + self.sync.rtio += ramp.eq(ramp + 1) + + samples = [[Signal(16) for i in range(4)] for j in range(4)] + self.comb += [ + a.eq(Cat(b)) for a, b in zip( + self.jesd.core.sink.flatten(), samples) + ] + # ch0: 16-step ramp with big carry toggles + for i in range(4): + self.comb += [ + samples[0][i][-4:].eq(ramp), + samples[0][i][:-4].eq(0x7ff if i % 2 else 0x800) + ] + # ch1: 50 MHz + from math import pi, cos + data = [int(round(cos(i/12*2*pi)*((1 << 15) - 1))) + for i in range(12)] + k = Signal(2) + self.sync.rtio += If(k == 2, k.eq(0)).Else(k.eq(k + 1)) + self.comb += [ + Case(k, { + i: [samples[1][j].eq(data[i*4 + j]) for j in range(4)] + for i in range(3) + }) + ] + # ch2: ch0, ch3: ch1 + self.comb += [ + Cat(samples[2]).eq(Cat(samples[0])), + Cat(samples[3]).eq(Cat(samples[1])) + ] class Standalone(MiniSoC, AMPSoC): From 38971d130a18892d5e1d5160068a6b92d4743730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 6 Jun 2018 12:21:42 +0200 Subject: [PATCH 0897/2457] comm_analyzer: fix data without any spi reads closes #1050 --- artiq/coredevice/comm_analyzer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/comm_analyzer.py b/artiq/coredevice/comm_analyzer.py index 6f432ea77..c6a2a3da4 100644 --- a/artiq/coredevice/comm_analyzer.py +++ b/artiq/coredevice/comm_analyzer.py @@ -381,7 +381,8 @@ class SPIMaster2Handler(WishboneHandler): else: raise ValueError("bad address", address) # process untimed reads and insert them here - while self._reads[0].rtio_counter < message.timestamp: + while (self._reads and + self._reads[0].rtio_counter < message.timestamp): read = self._reads.pop(0) logger.debug("SPI read @%d data=0x%08x", read.rtio_counter, read.data) From cae92f9b44d257cfcbb81e38b62408d09972e950 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 6 Jun 2018 19:03:45 +0800 Subject: [PATCH 0898/2457] kasli: add Tsinghua variant --- .../kasli_basic/device_db_tsinghua.py | 187 ++++++++++++++++++ artiq/gateware/targets/kasli.py | 38 +++- 2 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 artiq/examples/kasli_basic/device_db_tsinghua.py diff --git a/artiq/examples/kasli_basic/device_db_tsinghua.py b/artiq/examples/kasli_basic/device_db_tsinghua.py new file mode 100644 index 000000000..9c9cb979c --- /dev/null +++ b/artiq/examples/kasli_basic/device_db_tsinghua.py @@ -0,0 +1,187 @@ +core_addr = "kasli-1.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + + +for i in range(8): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": i}, + } + + +device_db.update( + spi_urukul0={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 8} + }, + ttl_urukul0_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 9} + }, + ttl_urukul0_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 10} + }, + ttl_urukul0_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 11} + }, + ttl_urukul0_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 12} + }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 13} + }, + urukul0_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul0_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } + + +device_db["spi_sampler0_adc"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 14} +} +device_db["spi_sampler0_pgia"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 15} +} +device_db["spi_sampler0_cnv"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 16}, +} +device_db["sampler0"] = { + "type": "local", + "module": "artiq.coredevice.sampler", + "class": "Sampler", + "arguments": { + "spi_adc_device": "spi_sampler0_adc", + "spi_pgia_device": "spi_sampler0_pgia", + "cnv_device": "spi_sampler0_cnv" + } +} + + +device_db["spi_zotino0"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 17} +} +device_db["ttl_zotino0_ldac"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 18} +} +device_db["ttl_zotino0_clr"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 19} +} +device_db["zotino0"] = { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino0", + "ldac_device": "ttl_zotino0_ldac", + "clr_device": "ttl_zotino0_clr" + } +} + +device_db.update( + led0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 22} + }, + led1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 23} + }, +) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 858c8fb59..6bd06ca50 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -341,6 +341,42 @@ class USTC(_StandaloneBase): self.add_csr_group("grabber", self.grabber_csr_group) +class Tsinghua(_StandaloneBase): + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) + + self.rtio_channels = [] + self.grabber_csr_group = [] + eem.DIO.add_std(self, 4, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) + eem.Sampler.add_std(self, 6, 5, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) + eem.Grabber.add_std(self, 1, 0) + + for i in (1, 2): + sfp_ctl = self.platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(self.rtio_channels) + self.config["HAS_GRABBER"] = None + self.add_csr_group("grabber", self.grabber_csr_group) + + class PTB(_StandaloneBase): """PTB Kasli variant @@ -808,7 +844,7 @@ def main(): soc_kasli_args(parser) parser.set_defaults(output_dir="artiq_kasli") variants = {cls.__name__.lower(): cls for cls in [ - Opticlock, SUServo, SYSU, MITLL, USTC, PTB, HUB, LUH, + Opticlock, SUServo, SYSU, MITLL, USTC, Tsinghua, PTB, HUB, LUH, Tester, Master, Satellite]} parser.add_argument("-V", "--variant", default="opticlock", help="variant: {} (default: %(default)s)".format( From 009db5eda93e226a1bd2bc2650a04e8281edefde Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 6 Jun 2018 16:20:06 +0200 Subject: [PATCH 0899/2457] serwb: revert 1gbps linerate --- artiq/gateware/targets/sayma_amc.py | 2 +- artiq/gateware/targets/sayma_rtm.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index b7aebf62f..0333a1c7f 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -200,7 +200,7 @@ class Standalone(MiniSoC, AMPSoC): # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") - serwb_phy_amc = serwb.genphy.SERWBPHY(platform.device, serwb_pads, mode="master") + serwb_phy_amc = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="master") self.submodules.serwb_phy_amc = serwb_phy_amc self.csr_devices.append("serwb_phy_amc") diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index ac376f5d2..faa290c28 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -42,8 +42,8 @@ class CRG(Module): p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, # VCO @ 1GHz - p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=8.0, - p_CLKFBOUT_MULT_F=8, p_DIVCLK_DIVIDE=1, + p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=10.0, + p_CLKFBOUT_MULT_F=10, p_DIVCLK_DIVIDE=1, i_CLKIN1=serwb_refclk_bufg, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, # 500MHz @@ -181,8 +181,8 @@ class SaymaRTM(Module): # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") - platform.add_period_constraint(serwb_pads.clk_p, 8.) - serwb_phy_rtm = serwb.genphy.SERWBPHY(platform.device, serwb_pads, mode="slave") + platform.add_period_constraint(serwb_pads.clk_p, 10.) + serwb_phy_rtm = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="slave") self.submodules.serwb_phy_rtm = serwb_phy_rtm self.comb += [ self.crg.serwb_refclk.eq(serwb_phy_rtm.serdes.clocking.refclk), From f427d451446218fb582a357ba7e67a1ac01ee218 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 6 Jun 2018 22:58:32 +0800 Subject: [PATCH 0900/2457] conda: bump migen --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 37afb1ba3..bc4055673 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_35+git9bc084a + - migen 0.7 py35_43+git6425844 - misoc 0.11 py35_19+git86c6fcb3 - jesd204b 0.7 - microscope From 28f31323a3bfb7fda14c2f6e7fbaf458e8deb253 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 6 Jun 2018 23:35:26 +0800 Subject: [PATCH 0901/2457] conda: bump migen (again) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index bc4055673..c4ee160d1 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_43+git6425844 + - migen 0.7 py35_44+gitca28f4e - misoc 0.11 py35_19+git86c6fcb3 - jesd204b 0.7 - microscope From b4c2b148d1deab5a78de20d06fe45aa2207e2dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 6 Jun 2018 15:50:53 +0000 Subject: [PATCH 0902/2457] sawg: don't use Mux for signed signals migen#75 --- artiq/gateware/dsp/sawg.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 2ac997ad2..c47be1978 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -203,8 +203,12 @@ class Channel(Module, SatAddMixin): o_y = Signal.like(y) self.comb += [ o_offset.eq(u.o.a0[-len(o):]), - o_x.eq(Mux(cfg.iq_en[0], x, 0)), - o_y.eq(Mux(cfg.iq_en[1], y, 0)), + If(cfg.iq_en[0], + o_x.eq(x) + ), + If(cfg.iq_en[1], + o_y.eq(y) + ), ] self.sync += [ o.eq(self.sat_add((o_offset, o_x, o_y), From 89797d08ed3247d12b05880cb76739f4ba1d3769 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Thu, 7 Jun 2018 15:13:56 +0200 Subject: [PATCH 0903/2457] serwb: revert to 125MHz linerate (until we understand why 1gbps version breaks between builds) --- artiq/gateware/targets/sayma_amc.py | 2 +- artiq/gateware/targets/sayma_rtm.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 0333a1c7f..b7aebf62f 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -200,7 +200,7 @@ class Standalone(MiniSoC, AMPSoC): # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") - serwb_phy_amc = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="master") + serwb_phy_amc = serwb.genphy.SERWBPHY(platform.device, serwb_pads, mode="master") self.submodules.serwb_phy_amc = serwb_phy_amc self.csr_devices.append("serwb_phy_amc") diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index faa290c28..ac376f5d2 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -42,8 +42,8 @@ class CRG(Module): p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, # VCO @ 1GHz - p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=10.0, - p_CLKFBOUT_MULT_F=10, p_DIVCLK_DIVIDE=1, + p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=8.0, + p_CLKFBOUT_MULT_F=8, p_DIVCLK_DIVIDE=1, i_CLKIN1=serwb_refclk_bufg, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, # 500MHz @@ -181,8 +181,8 @@ class SaymaRTM(Module): # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") - platform.add_period_constraint(serwb_pads.clk_p, 10.) - serwb_phy_rtm = serwb.phy.SERWBPHY(platform.device, serwb_pads, mode="slave") + platform.add_period_constraint(serwb_pads.clk_p, 8.) + serwb_phy_rtm = serwb.genphy.SERWBPHY(platform.device, serwb_pads, mode="slave") self.submodules.serwb_phy_rtm = serwb_phy_rtm self.comb += [ self.crg.serwb_refclk.eq(serwb_phy_rtm.serdes.clocking.refclk), From 7296a76f180a742682ddcd63892e3db0379b7efd Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 8 Jun 2018 12:15:00 +0200 Subject: [PATCH 0904/2457] serwb: move common datapath code to datapath.py, simplify flow control --- artiq/gateware/serwb/datapath.py | 198 +++++++++++++++++++++++++++++++ artiq/gateware/serwb/genphy.py | 155 ++++++------------------ artiq/gateware/serwb/kuserdes.py | 110 ++++------------- artiq/gateware/serwb/phy.py | 48 +++----- artiq/gateware/serwb/s7serdes.py | 109 ++++------------- 5 files changed, 297 insertions(+), 323 deletions(-) create mode 100644 artiq/gateware/serwb/datapath.py diff --git a/artiq/gateware/serwb/datapath.py b/artiq/gateware/serwb/datapath.py new file mode 100644 index 000000000..9d7f0bb19 --- /dev/null +++ b/artiq/gateware/serwb/datapath.py @@ -0,0 +1,198 @@ +from migen import * +from migen.genlib.io import * +from migen.genlib.misc import BitSlip, WaitTimer + +from misoc.interconnect import stream +from misoc.cores.code_8b10b import Encoder, Decoder + +from artiq.gateware.serwb.scrambler import Scrambler, Descrambler + + +def K(x, y): + return (y << 5) | x + + +class _8b10bEncoder(Module): + def __init__(self): + self.sink = sink = stream.Endpoint([("d", 32), ("k", 4)]) + self.source = source = stream.Endpoint([("data", 40)]) + + # # # + + encoder = CEInserter()(Encoder(4, True)) + self.submodules += encoder + + # control + self.comb += [ + source.stb.eq(sink.stb), + sink.ack.eq(source.ack), + encoder.ce.eq(source.stb & source.ack) + ] + + # datapath + for i in range(4): + self.comb += [ + encoder.k[i].eq(sink.k[i]), + encoder.d[i].eq(sink.d[8*i:8*(i+1)]), + source.data[10*i:10*(i+1)].eq(encoder.output[i]) + ] + + +class _8b10bDecoder(Module): + def __init__(self): + self.sink = sink = stream.Endpoint([("data", 40)]) + self.source = source = stream.Endpoint([("d", 32), ("k", 4)]) + + # # # + + decoders = [CEInserter()(Decoder(True)) for _ in range(4)] + self.submodules += decoders + + # control + self.comb += [ + source.stb.eq(sink.stb), + sink.ack.eq(source.ack) + ] + self.comb += [decoders[i].ce.eq(source.stb & source.ack) for i in range(4)] + + # datapath + for i in range(4): + self.comb += [ + decoders[i].input.eq(sink.data[10*i:10*(i+1)]), + source.k[i].eq(decoders[i].k), + source.d[8*i:8*(i+1)].eq(decoders[i].d) + ] + + +class _Bitslip(Module): + def __init__(self): + self.value = value = Signal(6) + self.sink = sink = stream.Endpoint([("data", 40)]) + self.source = source = stream.Endpoint([("data", 40)]) + + # # # + + bitslip = CEInserter()(BitSlip(40)) + self.submodules += bitslip + + # control + self.comb += [ + source.stb.eq(sink.stb), + sink.ack.eq(source.ack), + bitslip.value.eq(value), + bitslip.ce.eq(source.stb & source.ack) + ] + + # datapath + self.comb += [ + bitslip.i.eq(sink.data), + source.data.eq(bitslip.o) + ] + + +class TXDatapath(Module): + def __init__(self, phy_dw, with_scrambling=True): + self.idle = idle = Signal() + self.comma = comma = Signal() + self.sink = sink = stream.Endpoint([("data", 32)]) + self.source = source = stream.Endpoint([("data", phy_dw)]) + + # # # + + # scrambler + if with_scrambling: + self.submodules.scrambler = scrambler = Scrambler() + + # line coding + self.submodules.encoder = encoder = _8b10bEncoder() + + # converter + self.submodules.converter = converter = stream.Converter(40, phy_dw) + + # dataflow + if with_scrambling: + self.comb += [ + sink.connect(scrambler.sink), + If(comma, + encoder.sink.stb.eq(1), + encoder.sink.k.eq(1), + encoder.sink.d.eq(K(28,5)) + ).Else( + scrambler.source.connect(encoder.sink) + ) + ] + else: + self.comb += [ + If(comma, + encoder.sink.stb.eq(1), + encoder.sink.k.eq(1), + encoder.sink.d.eq(K(28,5)) + ).Else( + sink.connect(encoder.sink, omit={"data"}), + encoder.sink.d.eq(sink.data) + ), + ] + self.comb += [ + If(idle, + converter.sink.stb.eq(1), + converter.sink.data.eq(0) + ).Else( + encoder.source.connect(converter.sink), + ), + converter.source.connect(source) + ] + + +class RXDatapath(Module): + def __init__(self, phy_dw, with_scrambling=True): + self.bitslip_value = bitslip_value = Signal(6) + self.sink = sink = stream.Endpoint([("data", phy_dw)]) + self.source = source = stream.Endpoint([("data", 32)]) + self.idle = idle = Signal() + self.comma = comma = Signal() + + # # # + + # converter + self.submodules.converter = converter = stream.Converter(phy_dw, 40) + + # bitslip + self.submodules.bitslip = bitslip = _Bitslip() + self.comb += bitslip.value.eq(bitslip_value) + + # line coding + self.submodules.decoder = decoder = _8b10bDecoder() + + # descrambler + if with_scrambling: + self.submodules.descrambler = descrambler = Descrambler() + + # dataflow + self.comb += [ + sink.connect(converter.sink), + converter.source.connect(bitslip.sink), + bitslip.source.connect(decoder.sink) + ] + if with_scrambling: + self.comb += [ + decoder.source.connect(descrambler.sink), + descrambler.source.connect(source) + ] + else: + self.comb += [ + decoder.source.connect(source, omit={"d", "k"}), + source.data.eq(decoder.source.d) + ] + + # idle decoding + idle_timer = WaitTimer(256) + self.submodules += idle_timer + self.comb += [ + idle_timer.wait.eq(1), + idle.eq(idle_timer.done & ((converter.source.data == 0) | (converter.source.data == (2**40-1)))) + ] + # comma decoding + self.sync += \ + If(decoder.source.stb, + comma.eq((decoder.source.k == 1) & (decoder.source.d == K(28, 5))) + ) diff --git a/artiq/gateware/serwb/genphy.py b/artiq/gateware/serwb/genphy.py index 3c385b0d3..e3d2d3fbd 100644 --- a/artiq/gateware/serwb/genphy.py +++ b/artiq/gateware/serwb/genphy.py @@ -4,13 +4,8 @@ from migen.genlib.misc import BitSlip, WaitTimer from misoc.interconnect import stream from misoc.interconnect.csr import * -from misoc.cores.code_8b10b import Encoder, Decoder -from artiq.gateware.serwb.scrambler import Scrambler, Descrambler - - -def K(x, y): - return (y << 5) | x +from artiq.gateware.serwb.datapath import TXDatapath, RXDatapath class _SerdesClocking(Module): @@ -30,59 +25,33 @@ class _SerdesClocking(Module): class _SerdesTX(Module): - def __init__(self, pads, mode="master"): + def __init__(self, pads): # Control self.idle = idle = Signal() self.comma = comma = Signal() # Datapath - self.ce = ce = Signal() - self.k = k = Signal(4) - self.d = d = Signal(32) + self.sink = sink = stream.Endpoint([("data", 32)]) # # # - # 8b10b encoder - self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) - self.comb += encoder.ce.eq(ce) - - # 40 --> 1 converter - converter = stream.Converter(40, 1) - self.submodules += converter + # Datapath + self.submodules.datapath = datapath = TXDatapath(1) self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - # Enable pipeline when converter accepts the 40 bits - ce.eq(converter.sink.ack), - # If not idle, connect encoder to converter - If(~idle, - converter.sink.data.eq(Cat(*[encoder.output[i] for i in range(4)])) - ), - # If comma, send K28.5 - If(comma, - encoder.k[0].eq(1), - encoder.d[0].eq(K(28,5)), - # Else connect TX to encoder - ).Else( - encoder.k[0].eq(k[0]), - encoder.k[1].eq(k[1]), - encoder.k[2].eq(k[2]), - encoder.k[3].eq(k[3]), - encoder.d[0].eq(d[0:8]), - encoder.d[1].eq(d[8:16]), - encoder.d[2].eq(d[16:24]), - encoder.d[3].eq(d[24:32]) - ) + sink.connect(datapath.sink), + datapath.source.ack.eq(1), + datapath.idle.eq(idle), + datapath.comma.eq(comma) ] - # Data output (on rising edge of sys_clk) + # Output data (on rising edge of sys_clk) data = Signal() - self.sync += data.eq(converter.source.data) + self.sync += data.eq(datapath.source.data) self.specials += DifferentialOutput(data, pads.tx_p, pads.tx_n) class _SerdesRX(Module): - def __init__(self, pads, mode="master"): + def __init__(self, pads): # Control self.bitslip_value = bitslip_value = Signal(6) @@ -91,9 +60,7 @@ class _SerdesRX(Module): self.comma = comma = Signal() # Datapath - self.ce = ce = Signal() - self.k = k = Signal(4) - self.d = d = Signal(32) + self.source = source = stream.Endpoint([("data", 32)]) # # # @@ -103,50 +70,15 @@ class _SerdesRX(Module): self.specials += DifferentialInput(pads.rx_p, pads.rx_n, data) self.sync += data_d.eq(data) - # 1 --> 40 converter and bitslip - converter = stream.Converter(1, 40) - self.submodules += converter - bitslip = CEInserter()(BitSlip(40)) - self.submodules += bitslip + # Datapath + self.submodules.datapath = datapath = RXDatapath(1) self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - # Enable pipeline when converter outputs the 40 bits - ce.eq(converter.source.stb), - # Connect input data to converter - converter.sink.data.eq(data), - # Connect converter to bitslip - bitslip.ce.eq(ce), - bitslip.value.eq(bitslip_value), - bitslip.i.eq(converter.source.data) - ] - - # 8b10b decoder - self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] - self.comb += [decoders[i].ce.eq(ce) for i in range(4)] - self.comb += [ - # Connect bitslip to decoder - decoders[0].input.eq(bitslip.o[0:10]), - decoders[1].input.eq(bitslip.o[10:20]), - decoders[2].input.eq(bitslip.o[20:30]), - decoders[3].input.eq(bitslip.o[30:40]), - # Connect decoder to output - self.k.eq(Cat(*[decoders[i].k for i in range(4)])), - self.d.eq(Cat(*[decoders[i].d for i in range(4)])), - ] - - # Status - idle_timer = WaitTimer(256) - self.submodules += idle_timer - self.comb += [ - idle_timer.wait.eq(1), - self.idle.eq(idle_timer.done & - ((bitslip.o == 0) | (bitslip.o == (2**40-1)))), - self.comma.eq( - (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & - (decoders[1].k == 0) & (decoders[1].d == 0) & - (decoders[2].k == 0) & (decoders[2].d == 0) & - (decoders[3].k == 0) & (decoders[3].d == 0)) + datapath.sink.stb.eq(1), + datapath.sink.data.eq(data_d), + datapath.bitslip_value.eq(bitslip_value), + datapath.source.connect(source), + idle.eq(datapath.idle), + comma.eq(datapath.comma) ] @@ -154,8 +86,8 @@ class _SerdesRX(Module): class _Serdes(Module): def __init__(self, pads, mode="master"): self.submodules.clocking = _SerdesClocking(pads, mode) - self.submodules.tx = _SerdesTX(pads, mode) - self.submodules.rx = _SerdesRX(pads, mode) + self.submodules.tx = _SerdesTX(pads) + self.submodules.rx = _SerdesRX(pads) # SERWB Master <--> Slave physical synchronization process: @@ -378,34 +310,21 @@ class SERWBPHY(Module, AutoCSR): self.submodules.init = _SerdesSlaveInit(self.serdes, init_timeout) self.submodules.control = _SerdesControl(self.serdes, self.init, mode) - # scrambling - self.submodules.scrambler = scrambler = Scrambler() - self.submodules.descrambler = descrambler = Descrambler() - - # tx dataflow - self.comb += \ - If(self.init.ready, - sink.connect(scrambler.sink), - scrambler.source.ack.eq(self.serdes.tx.ce), - If(scrambler.source.stb, - self.serdes.tx.d.eq(scrambler.source.d), - self.serdes.tx.k.eq(scrambler.source.k) - ) - ) - - # rx dataflow + # tx/rx dataflow self.comb += [ If(self.init.ready, - descrambler.sink.stb.eq(self.serdes.rx.ce), - descrambler.sink.d.eq(self.serdes.rx.d), - descrambler.sink.k.eq(self.serdes.rx.k), - descrambler.source.connect(source) + sink.connect(self.serdes.tx.sink), + self.serdes.rx.source.connect(source) + ).Else( + self.serdes.rx.source.ack.eq(1) ), - # For PRBS test we are using the scrambler/descrambler as PRBS, - # sending 0 to the scrambler and checking that descrambler - # output is always 0. - self.control.prbs_error.eq( - descrambler.source.stb & - descrambler.source.ack & - (descrambler.source.data != 0)) + self.serdes.tx.sink.stb.eq(1) # always transmitting ] + + # For PRBS test we are using the scrambler/descrambler as PRBS, + # sending 0 to the scrambler and checking that descrambler + # output is always 0. + self.comb += self.control.prbs_error.eq( + source.stb & + source.ack & + (source.data != 0)) diff --git a/artiq/gateware/serwb/kuserdes.py b/artiq/gateware/serwb/kuserdes.py index ced959eff..f16d1919f 100644 --- a/artiq/gateware/serwb/kuserdes.py +++ b/artiq/gateware/serwb/kuserdes.py @@ -5,9 +5,7 @@ from migen.genlib.misc import BitSlip, WaitTimer from misoc.interconnect import stream from misoc.cores.code_8b10b import Encoder, Decoder - -def K(x, y): - return (y << 5) | x +from artiq.gateware.serwb.datapath import TXDatapath, RXDatapath class _KUSerdesClocking(Module): @@ -45,52 +43,27 @@ class _KUSerdesClocking(Module): class _KUSerdesTX(Module): - def __init__(self, pads, mode="master"): + def __init__(self, pads): # Control self.idle = idle = Signal() self.comma = comma = Signal() # Datapath - self.ce = ce = Signal() - self.k = k = Signal(4) - self.d = d = Signal(32) + self.sink = sink = stream.Endpoint([("data", 32)]) # # # - # 8b10b encoder - self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) - self.comb += encoder.ce.eq(ce) - # 40 --> 8 converter - converter = stream.Converter(40, 8) - self.submodules += converter + # Datapath + self.submodules.datapath = datapath = TXDatapath(8) self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - # Enable pipeline when converter accepts the 40 bits - ce.eq(converter.sink.ack), - # If not idle, connect encoder to converter - If(~idle, - converter.sink.data.eq(Cat(*[encoder.output[i] for i in range(4)])) - ), - # If comma, send K28.5 - If(comma, - encoder.k[0].eq(1), - encoder.d[0].eq(K(28,5)), - # Else connect TX to encoder - ).Else( - encoder.k[0].eq(k[0]), - encoder.k[1].eq(k[1]), - encoder.k[2].eq(k[2]), - encoder.k[3].eq(k[3]), - encoder.d[0].eq(d[0:8]), - encoder.d[1].eq(d[8:16]), - encoder.d[2].eq(d[16:24]), - encoder.d[3].eq(d[24:32]) - ) + sink.connect(datapath.sink), + datapath.source.ack.eq(1), + datapath.idle.eq(idle), + datapath.comma.eq(comma) ] - # Data output (DDR with sys4x) + # Output Data(DDR with sys4x) data = Signal() self.specials += [ Instance("OSERDESE3", @@ -100,14 +73,14 @@ class _KUSerdesTX(Module): o_OQ=data, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D=converter.source.data + i_D=datapath.source.data ), DifferentialOutput(data, pads.tx_p, pads.tx_n) ] class _KUSerdesRX(Module): - def __init__(self, pads, mode="master"): + def __init__(self, pads): # Control self.delay_rst = Signal() self.delay_inc = Signal() @@ -118,9 +91,7 @@ class _KUSerdesRX(Module): self.comma = comma = Signal() # Datapath - self.ce = ce = Signal() - self.k = k = Signal(4) - self.d = d = Signal(32) + self.source = source = stream.Endpoint([("data", 32)]) # # # @@ -158,50 +129,15 @@ class _KUSerdesRX(Module): ) ] - # 8 --> 40 converter and bitslip - converter = stream.Converter(8, 40) - self.submodules += converter - bitslip = CEInserter()(BitSlip(40)) - self.submodules += bitslip + # Datapath + self.submodules.datapath = datapath = RXDatapath(8) self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - # Enable pipeline when converter outputs the 40 bits - ce.eq(converter.source.stb), - # Connect input data to converter - converter.sink.data.eq(data_deserialized), - # Connect converter to bitslip - bitslip.ce.eq(ce), - bitslip.value.eq(bitslip_value), - bitslip.i.eq(converter.source.data) - ] - - # 8b10b decoder - self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] - self.comb += [decoders[i].ce.eq(ce) for i in range(4)] - self.comb += [ - # Connect bitslip to decoder - decoders[0].input.eq(bitslip.o[0:10]), - decoders[1].input.eq(bitslip.o[10:20]), - decoders[2].input.eq(bitslip.o[20:30]), - decoders[3].input.eq(bitslip.o[30:40]), - # Connect decoder to output - self.k.eq(Cat(*[decoders[i].k for i in range(4)])), - self.d.eq(Cat(*[decoders[i].d for i in range(4)])), - ] - - # Status - idle_timer = WaitTimer(256) - self.submodules += idle_timer - self.comb += [ - idle_timer.wait.eq(1), - self.idle.eq(idle_timer.done & - ((bitslip.o == 0) | (bitslip.o == (2**40-1)))), - self.comma.eq( - (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & - (decoders[1].k == 0) & (decoders[1].d == 0) & - (decoders[2].k == 0) & (decoders[2].d == 0) & - (decoders[3].k == 0) & (decoders[3].d == 0)) + datapath.sink.stb.eq(1), + datapath.sink.data.eq(data_deserialized), + datapath.bitslip_value.eq(bitslip_value), + datapath.source.connect(source), + idle.eq(datapath.idle), + comma.eq(datapath.comma) ] @@ -209,5 +145,5 @@ class _KUSerdesRX(Module): class KUSerdes(Module): def __init__(self, pads, mode="master"): self.submodules.clocking = _KUSerdesClocking(pads, mode) - self.submodules.tx = _KUSerdesTX(pads, mode) - self.submodules.rx = _KUSerdesRX(pads, mode) + self.submodules.tx = _KUSerdesTX(pads) + self.submodules.rx = _KUSerdesRX(pads) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index 83f47ed27..efb2463e2 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -4,14 +4,13 @@ from migen.genlib.misc import WaitTimer from misoc.interconnect import stream from misoc.interconnect.csr import * -from artiq.gateware.serwb.scrambler import Scrambler, Descrambler from artiq.gateware.serwb.kuserdes import KUSerdes from artiq.gateware.serwb.s7serdes import S7Serdes -# Master <--> Slave synchronization: -# 1) Master sends idle pattern (zeroes) to reset Slave. -# 2) Master sends K28.5 commas to allow Slave to calibrate, Slave sends idle pattern. +# SERWB Master <--> Slave physical synchronization process: +# 1) Master sends idle patterns (zeroes) to Slave to reset it. +# 2) Master sends K28.5 commas to allow Slave to calibrate, Slave sends idle patterns. # 3) Slave sends K28.5 commas to allow Master to calibrate, Master sends K28.5 commas. # 4) Master stops sending K28.5 commas. # 5) Slave stops sending K28.5 commas. @@ -360,34 +359,21 @@ class SERWBPHY(Module, AutoCSR): self.submodules.init = _SerdesSlaveInit(self.serdes, taps, init_timeout) self.submodules.control = _SerdesControl(self.serdes, self.init, mode) - # scrambling - self.submodules.scrambler = scrambler = Scrambler() - self.submodules.descrambler = descrambler = Descrambler() - - # tx dataflow - self.comb += \ - If(self.init.ready, - sink.connect(scrambler.sink), - scrambler.source.ack.eq(self.serdes.tx.ce), - If(scrambler.source.stb, - self.serdes.tx.d.eq(scrambler.source.d), - self.serdes.tx.k.eq(scrambler.source.k) - ) - ) - - # rx dataflow + # tx/rx dataflow self.comb += [ If(self.init.ready, - descrambler.sink.stb.eq(self.serdes.rx.ce), - descrambler.sink.d.eq(self.serdes.rx.d), - descrambler.sink.k.eq(self.serdes.rx.k), - descrambler.source.connect(source) + sink.connect(self.serdes.tx.sink), + self.serdes.rx.source.connect(source) + ).Else( + self.serdes.rx.source.ack.eq(1) ), - # For PRBS test we are using the scrambler/descrambler as PRBS, - # sending 0 to the scrambler and checking that descrambler - # output is always 0. - self.control.prbs_error.eq( - descrambler.source.stb & - descrambler.source.ack & - (descrambler.source.data != 0)) + self.serdes.tx.sink.stb.eq(1) # always transmitting ] + + # For PRBS test we are using the scrambler/descrambler as PRBS, + # sending 0 to the scrambler and checking that descrambler + # output is always 0. + self.comb += self.control.prbs_error.eq( + source.stb & + source.ack & + (source.data != 0)) diff --git a/artiq/gateware/serwb/s7serdes.py b/artiq/gateware/serwb/s7serdes.py index 12fabade0..9daee338a 100644 --- a/artiq/gateware/serwb/s7serdes.py +++ b/artiq/gateware/serwb/s7serdes.py @@ -5,9 +5,7 @@ from migen.genlib.misc import BitSlip, WaitTimer from misoc.interconnect import stream from misoc.cores.code_8b10b import Encoder, Decoder - -def K(x, y): - return (y << 5) | x +from artiq.gateware.serwb.datapath import TXDatapath, RXDatapath class _S7SerdesClocking(Module): @@ -55,46 +53,20 @@ class _S7SerdesTX(Module): self.comma = comma = Signal() # Datapath - self.ce = ce = Signal() - self.k = k = Signal(4) - self.d = d = Signal(32) + self.sink = sink = stream.Endpoint([("data", 32)]) # # # - # 8b10b encoder - self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) - self.comb += encoder.ce.eq(ce) - - # 40 --> 8 converter - converter = stream.Converter(40, 8) - self.submodules += converter + # Datapath + self.submodules.datapath = datapath = TXDatapath(8) self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - # Enable pipeline when converter accepts the 40 bits - ce.eq(converter.sink.ack), - # If not idle, connect encoder to converter - If(~idle, - converter.sink.data.eq(Cat(*[encoder.output[i] for i in range(4)])) - ), - # If comma, send K28.5 - If(comma, - encoder.k[0].eq(1), - encoder.d[0].eq(K(28,5)), - # Else connect TX to encoder - ).Else( - encoder.k[0].eq(k[0]), - encoder.k[1].eq(k[1]), - encoder.k[2].eq(k[2]), - encoder.k[3].eq(k[3]), - encoder.d[0].eq(d[0:8]), - encoder.d[1].eq(d[8:16]), - encoder.d[2].eq(d[16:24]), - encoder.d[3].eq(d[24:32]) - ) + sink.connect(datapath.sink), + datapath.source.ack.eq(1), + datapath.idle.eq(idle), + datapath.comma.eq(comma) ] - # Data output (DDR with sys4x) + # Output Data(DDR with sys4x) data = Signal() self.specials += [ Instance("OSERDESE2", @@ -106,10 +78,10 @@ class _S7SerdesTX(Module): i_OCE=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D1=converter.source.data[0], i_D2=converter.source.data[1], - i_D3=converter.source.data[2], i_D4=converter.source.data[3], - i_D5=converter.source.data[4], i_D6=converter.source.data[5], - i_D7=converter.source.data[6], i_D8=converter.source.data[7] + i_D1=datapath.source.data[0], i_D2=datapath.source.data[1], + i_D3=datapath.source.data[2], i_D4=datapath.source.data[3], + i_D5=datapath.source.data[4], i_D6=datapath.source.data[5], + i_D7=datapath.source.data[6], i_D8=datapath.source.data[7] ), DifferentialOutput(data, pads.tx_p, pads.tx_n) ] @@ -127,9 +99,7 @@ class _S7SerdesRX(Module): self.comma = comma = Signal() # Datapath - self.ce = ce = Signal() - self.k = k = Signal(4) - self.d = d = Signal(32) + self.source = source = stream.Endpoint([("data", 32)]) # # # @@ -170,50 +140,15 @@ class _S7SerdesRX(Module): ) ] - # 8 --> 40 converter and bitslip - converter = stream.Converter(8, 40) - self.submodules += converter - bitslip = CEInserter()(BitSlip(40)) - self.submodules += bitslip + # Datapath + self.submodules.datapath = datapath = RXDatapath(8) self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - # Enable pipeline when converter outputs the 40 bits - ce.eq(converter.source.stb), - # Connect input data to converter - converter.sink.data.eq(data_deserialized), - # Connect converter to bitslip - bitslip.ce.eq(ce), - bitslip.value.eq(bitslip_value), - bitslip.i.eq(converter.source.data) - ] - - # 8b10b decoder - self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] - self.comb += [decoders[i].ce.eq(ce) for i in range(4)] - self.comb += [ - # Connect bitslip to decoder - decoders[0].input.eq(bitslip.o[0:10]), - decoders[1].input.eq(bitslip.o[10:20]), - decoders[2].input.eq(bitslip.o[20:30]), - decoders[3].input.eq(bitslip.o[30:40]), - # Connect decoder to output - self.k.eq(Cat(*[decoders[i].k for i in range(4)])), - self.d.eq(Cat(*[decoders[i].d for i in range(4)])), - ] - - # Status - idle_timer = WaitTimer(256) - self.submodules += idle_timer - self.comb += [ - idle_timer.wait.eq(1), - self.idle.eq(idle_timer.done & - ((bitslip.o == 0) | (bitslip.o == (2**40-1)))), - self.comma.eq( - (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & - (decoders[1].k == 0) & (decoders[1].d == 0) & - (decoders[2].k == 0) & (decoders[2].d == 0) & - (decoders[3].k == 0) & (decoders[3].d == 0)) + datapath.sink.stb.eq(1), + datapath.sink.data.eq(data_deserialized), + datapath.bitslip_value.eq(bitslip_value), + datapath.source.connect(source), + idle.eq(datapath.idle), + comma.eq(datapath.comma) ] From 53e9e475d0af5e137d6551ea0fac78d64cdffb90 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 8 Jun 2018 16:10:31 +0200 Subject: [PATCH 0905/2457] serwb: transmit zeroes when nothing to transmit (for prbs), improve rx idle detection --- artiq/gateware/serwb/datapath.py | 10 ++++++---- artiq/gateware/serwb/genphy.py | 4 +++- artiq/gateware/serwb/phy.py | 4 +++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/serwb/datapath.py b/artiq/gateware/serwb/datapath.py index 9d7f0bb19..f91cd602f 100644 --- a/artiq/gateware/serwb/datapath.py +++ b/artiq/gateware/serwb/datapath.py @@ -185,11 +185,13 @@ class RXDatapath(Module): ] # idle decoding - idle_timer = WaitTimer(256) + idle_timer = WaitTimer(32) self.submodules += idle_timer - self.comb += [ - idle_timer.wait.eq(1), - idle.eq(idle_timer.done & ((converter.source.data == 0) | (converter.source.data == (2**40-1)))) + self.sync += [ + If(converter.source.stb, + idle_timer.wait.eq((converter.source.data == 0) | (converter.source.data == (2**40-1))) + ), + idle.eq(idle_timer.done) ] # comma decoding self.sync += \ diff --git a/artiq/gateware/serwb/genphy.py b/artiq/gateware/serwb/genphy.py index e3d2d3fbd..b9d6c02f2 100644 --- a/artiq/gateware/serwb/genphy.py +++ b/artiq/gateware/serwb/genphy.py @@ -313,7 +313,9 @@ class SERWBPHY(Module, AutoCSR): # tx/rx dataflow self.comb += [ If(self.init.ready, - sink.connect(self.serdes.tx.sink), + If(sink.stb, + sink.connect(self.serdes.tx.sink), + ), self.serdes.rx.source.connect(source) ).Else( self.serdes.rx.source.ack.eq(1) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py index efb2463e2..d878cfb17 100644 --- a/artiq/gateware/serwb/phy.py +++ b/artiq/gateware/serwb/phy.py @@ -362,7 +362,9 @@ class SERWBPHY(Module, AutoCSR): # tx/rx dataflow self.comb += [ If(self.init.ready, - sink.connect(self.serdes.tx.sink), + If(sink.stb, + sink.connect(self.serdes.tx.sink), + ), self.serdes.rx.source.connect(source) ).Else( self.serdes.rx.source.ack.eq(1) From e5f67501715bbd59c0508a173d0fed49d5fd810c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 8 Jun 2018 11:47:35 +0000 Subject: [PATCH 0906/2457] sawg: cleanup double assign --- artiq/gateware/dsp/sawg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index c47be1978..6f983ba90 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -194,7 +194,7 @@ class Channel(Module, SatAddMixin): limits=cfg.limits[1], clipped=cfg.clipped[1])), hbf[1].i.eq(self.sat_add((a1.yo[0], a2.yo[0]), width=len(hbf[1].i), - limits=cfg.limits[1], clipped=cfg.clipped[1])), + limits=cfg.limits[1])), ] # wire up outputs and q_{i,o} exchange for o, x, y in zip(self.o, b.xo, self.y_in): From 735e4e8561418ac86d055330855517fca31dfaff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 8 Jun 2018 18:55:46 +0800 Subject: [PATCH 0907/2457] pcu: spelling --- artiq/coredevice/pcu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/pcu.py b/artiq/coredevice/pcu.py index f9b77f553..6dd1ff150 100644 --- a/artiq/coredevice/pcu.py +++ b/artiq/coredevice/pcu.py @@ -41,7 +41,7 @@ class CorePCU: """ Configure and clear the kernel CPU performance counters. - The eight counters are configures to count the folloging events: + The eight counters are configured to count the following events: * Load or store * Instruction fetch * Data cache miss From 6a7983cf89a239706f0ebacd04e6b7ac8a82620b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 8 Jun 2018 14:37:13 +0000 Subject: [PATCH 0908/2457] conda: bump misoc closes #1039 closes #1040 closes #1022 closes #1058 closes #1044 --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index c4ee160d1..2243461ed 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_44+gitca28f4e - - misoc 0.11 py35_19+git86c6fcb3 + - misoc 0.11 py35_20+git2436a68d - jesd204b 0.7 - microscope - binutils-or1k-linux >=2.27 From 5b73dd8604fcc6d7683b5da71fccc0e7d9c53546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 8 Jun 2018 17:22:13 +0200 Subject: [PATCH 0909/2457] sawg: accurate unittest rtio freq --- artiq/gateware/test/dsp/test_sawg_fe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/test/dsp/test_sawg_fe.py b/artiq/gateware/test/dsp/test_sawg_fe.py index a6595e03c..d518e052a 100644 --- a/artiq/gateware/test/dsp/test_sawg_fe.py +++ b/artiq/gateware/test/dsp/test_sawg_fe.py @@ -42,7 +42,7 @@ class SAWGTest(unittest.TestCase): self.rtio_manager.patch(spline) self.rtio_manager.patch(sawg) self.core = sim_devices.Core({}) - self.core.coarse_ref_period = 6.66666 + self.core.coarse_ref_period = 20/3 self.core.ref_multiplier = 1 self.t = self.core.coarse_ref_period self.channel = mg.ClockDomainsRenamer({"rio_phy": "sys"})( From 0b086225a9ede6bd6a9fe8b8efe0056251554336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sat, 9 Jun 2018 07:33:47 +0000 Subject: [PATCH 0910/2457] sawg: don't use Cat() for signed signals c.f. #1039 #1040 #1022 #1058 #1044 --- artiq/gateware/dsp/sawg.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/dsp/sawg.py b/artiq/gateware/dsp/sawg.py index 6f983ba90..e0e9d1db4 100644 --- a/artiq/gateware/dsp/sawg.py +++ b/artiq/gateware/dsp/sawg.py @@ -183,8 +183,8 @@ class Channel(Module, SatAddMixin): b.ce.eq(cfg.ce), u.o.ack.eq(cfg.ce), Cat(b.clr, a1.clr, a2.clr).eq(cfg.clr), - Cat(b.xi).eq(Cat(hbf[0].o)), - Cat(b.yi).eq(Cat(hbf[1].o)), + [i.eq(j) for i, j in zip(b.xi, hbf[0].o)], + [i.eq(j) for i, j in zip(b.yi, hbf[1].o)], ] hbf[0].i.reset_less = True hbf[1].i.reset_less = True @@ -217,4 +217,4 @@ class Channel(Module, SatAddMixin): ] def connect_y(self, buddy): - self.comb += Cat(buddy.y_in).eq(Cat(self.b.yo)) + self.comb += [i.eq(j) for i, j in zip(buddy.y_in, self.b.yo)] From cb6e44b23a85428710af205a6f1c155eda7b2443 Mon Sep 17 00:00:00 2001 From: hartytp Date: Mon, 11 Jun 2018 21:19:57 +0100 Subject: [PATCH 0911/2457] Sayma: disable unused HMC7043 outputs. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index bc4e94e9b..dbbf1409b 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -142,7 +142,6 @@ mod hmc830 { pub mod hmc7043 { use board_misoc::csr; - // To do: check which output channels we actually need const DAC_CLK_DIV: u32 = 2; const FPGA_CLK_DIV: u32 = 8; const SYSREF_DIV: u32 = 128; @@ -156,11 +155,11 @@ pub mod hmc7043 { (true, SYSREF_DIV, 0x0, 0x0), // 3: DAC1_SYSREF (false, 0, 0x0, 0x0), // 4: ADC2_CLK (false, 0, 0x0, 0x0), // 5: ADC2_SYSREF - (true, FPGA_CLK_DIV, 0x0, 0x0), // 6: GTP_CLK2 + (false, 0, 0x0, 0x0), // 6: GTP_CLK2 (true, SYSREF_DIV, 0x0, 0x0), // 7: FPGA_DAC_SYSREF (true, FPGA_CLK_DIV, 0x0, 0x0), // 8: GTP_CLK1 - (true, FPGA_CLK_DIV, 0x0, 0x0), // 9: AMC_MASTER_AUX_CLK - (true, FPGA_CLK_DIV, 0x0, 0x0), // 10: RTM_MASTER_AUX_CLK + (false, 0, 0x0, 0x0), // 9: AMC_MASTER_AUX_CLK + (false, 0, 0x0, 0x0), // 10: RTM_MASTER_AUX_CLK (false, 0, 0x0, 0x0), // 11: FPGA_ADC_SYSREF (false, 0, 0x0, 0x0), // 12: ADC1_CLK (false, 0, 0x0, 0x0), // 13: ADC1_SYSREF From 4912f53ab4e00348e8d45bfaf9a7b89adef98847 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sat, 9 Jun 2018 20:03:22 +0800 Subject: [PATCH 0912/2457] slave_fpga: board_misoc --- artiq/firmware/libboard_artiq/slave_fpga.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/slave_fpga.rs b/artiq/firmware/libboard_artiq/slave_fpga.rs index 2a7377ff4..2fabe5b24 100644 --- a/artiq/firmware/libboard_artiq/slave_fpga.rs +++ b/artiq/firmware/libboard_artiq/slave_fpga.rs @@ -1,4 +1,4 @@ -use board::{csr, clock}; +use board_misoc::{csr, clock}; use core::slice; use byteorder::{ByteOrder, BigEndian}; From a143e238a8e58ae3ce79c6b6dade44d7fdc70be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sat, 9 Jun 2018 20:22:21 +0800 Subject: [PATCH 0913/2457] savel_fpga: get rid of unneeded config --- artiq/firmware/libboard_artiq/lib.rs | 2 +- artiq/firmware/runtime/main.rs | 2 +- artiq/gateware/targets/sayma_amc.py | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 3402a1d2f..6c26e8d0a 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -28,7 +28,7 @@ pub mod rpc_queue; #[cfg(has_si5324)] pub mod si5324; -#[cfg(has_slave_fpga)] +#[cfg(has_slave_fpga_cfg)] pub mod slave_fpga; #[cfg(has_serwb_phy_amc)] pub mod serwb; diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index d222d7f2d..f5c0a0202 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -82,7 +82,7 @@ fn startup() { _ => info!("UART log level set to INFO by default") } - #[cfg(has_slave_fpga)] + #[cfg(has_slave_fpga_cfg)] board_artiq::slave_fpga::load().expect("cannot load RTM FPGA gateware"); #[cfg(has_serwb_phy_amc)] board_artiq::serwb::wait_init(); diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index b7aebf62f..6f34e8663 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -194,8 +194,7 @@ class Standalone(MiniSoC, AMPSoC): slave_fpga_cfg.init_b, slave_fpga_cfg.program_b, ]) - self.csr_devices.append("slave_fpga_cfg") - # self.config["HAS_SLAVE_FPGA"] = None + # self.csr_devices.append("slave_fpga_cfg") self.config["SLAVE_FPGA_GATEWARE"] = 0x200000 # AMC/RTM serwb From a9d97101fc3b20fe237ae9df2158f9e49de12893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 12 Jun 2018 16:23:13 +0800 Subject: [PATCH 0914/2457] slave_fpga: add another check --- artiq/firmware/libboard_artiq/slave_fpga.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/slave_fpga.rs b/artiq/firmware/libboard_artiq/slave_fpga.rs index 2fabe5b24..d8ce4060a 100644 --- a/artiq/firmware/libboard_artiq/slave_fpga.rs +++ b/artiq/firmware/libboard_artiq/slave_fpga.rs @@ -60,6 +60,9 @@ pub fn load() -> Result<(), &'static str> { if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { return Err("Did not exit INIT after releasing PROGRAM"); } + if csr::slave_fpga_cfg::in_read() & DONE_BIT != 0 { + return Err("DONE high despite PROGRAM"); + } for i in slice::from_raw_parts(GATEWARE.offset(8), length) { shift_u8(*i); @@ -72,7 +75,6 @@ pub fn load() -> Result<(), &'static str> { while csr::slave_fpga_cfg::in_read() & DONE_BIT == 0 { if clock::get_ms() > t + 100 { error!("Timeout wating for DONE after loading"); - error!("Boards not populated correctly?"); return Err("Not DONE"); } shift_u8(0xff); From 7a0140ecb291df209fc49170d9374b57eb8adbdd Mon Sep 17 00:00:00 2001 From: hartytp Date: Tue, 12 Jun 2018 12:37:17 +0100 Subject: [PATCH 0915/2457] Sayma HMC830: update interface and register writes. (#1068) * Break the HMC830 init into separate functions for general purpose (but, integer-N) init, setting dividers and checking lock * Use 1.6mA ICP (which the loop filter was optimized for) * Go through the data sheet carefully and set all registers to the correct value (e.g. ensure that all settings are correctly optimized for integer-N usage) * Change divider values (now using 100MHz PFD, which should give lower noise in theory) --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 108 +++++++++++-------- 1 file changed, 62 insertions(+), 46 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index dbbf1409b..af4aaa279 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -1,15 +1,3 @@ -/* - * HMC830 config: - * 100MHz input, 1.2GHz output - * fvco = (refclk / r_divider) * n_divider - * fout = fvco/2 - * - * HMC7043 config: - * dac clock: 600MHz (div=2) - * fpga clock: 150MHz (div=8) - * sysref clock: 9.375MHz (div=128) - */ - mod clock_mux { use board_misoc::csr; @@ -30,27 +18,6 @@ mod clock_mux { mod hmc830 { use board_misoc::{csr, clock}; - const HMC830_WRITES: [(u8, u32); 18] = [ - (0x0, 0x20), - (0x1, 0x2), - (0x2, 0x2), // r_divider - (0x5, 0x1628), - (0x5, 0x60a0), - (0x5, 0xe110), - (0x5, 0x2818), - (0x5, 0xf88), - (0x5, 0x7fb0), - (0x5, 0x0), - (0x6, 0x303ca), - (0x7, 0x14d), - (0x8, 0xc1beff), - (0x9, 0x153fff), - (0xa, 0x2046), - (0xb, 0x7c061), - (0xf, 0x81), - (0x3, 0x30), // n_divider - ]; - fn spi_setup() { unsafe { while csr::converter_spi::idle_read() == 0 {} @@ -112,19 +79,65 @@ mod hmc830 { Ok(()) } - pub fn init() -> Result<(), &'static str> { + pub fn init() { + // Configure HMC830 for integer-N operation + // See "PLLs with integrated VCO- RF Applications Product & Operating + // Guide" spi_setup(); - info!("loading configuration..."); - for &(addr, data) in HMC830_WRITES.iter() { - write(addr, data); - } - info!(" ...done"); + info!("loading HMC830 configuration..."); + write(0x0, 0x20); // software reset + write(0x0, 0x00); // normal operation + write(0x6, 0x307ca); // integer-N mode (NB data sheet table 5.8 not self-consistent) + write(0x7, 0x4d); // digital lock detect, 1/2 cycle window (6.5ns window) + write(0x9, 0x2850); // charge pump: 1.6mA, no offset + write(0xa, 0x2045); // for wideband devices like the HMC830 + write(0xb, 0x7c061); // for HMC830 + + // VCO subsystem registers + // NB software reset does not seem to reset these registers, so always + // program them all! + write(0x5, 0xf88); // 1: defaults + write(0x5, 0x6010); // 2: mute output until output divider set + write(0x5, 0x2818); // 3: wideband PLL defaults + write(0x5, 0x60a0); // 4: HMC830 magic value + write(0x5, 0x1628); // 5: HMC830 magic value + write(0x5, 0x7fb0); // 6: HMC830 magic value + write(0x5, 0x0); // ready for VCO auto-cal + + info!(" ...done"); + } + + pub fn set_dividers(r_div: u32, n_div: u32, m_div: u32, out_div: u32) { + // VCO frequency: f_vco = (f_ref/r_div)*(n_int + n_frac/2**24) + // VCO frequency range [1.5GHz, 3GHz] + // Output frequency: f_out = f_vco/out_div + // Max PFD frequency: 125MHz for integer-N, 100MHz for fractional + // (mode B) + // Max reference frequency: 350MHz, however f_ref >= 200MHz requires + // setting 0x08[21]=1 + // + // :param r_div: reference divider [1, 16383] + // :param n_div: VCO divider, integer part. Integer-N mode: [16, 2**19-1] + // fractional mode: [20, 2**19-4] + // :param m_div: VCO divider, fractional part [0, 2**24-1] + // :param out_div: output divider [1, 62] (0 mutes output) + info!("setting HMC830 dividers..."); + write(0x5, 0x6010 + (out_div << 7) + (((out_div <= 2) as u32) << 15)); + write(0x5, 0x0); // ready for VCO auto-cal + write(0x2, r_div); + write(0x4, m_div); + write(0x3, n_div); + + info!(" ...done"); + } + + pub fn check_locked() -> Result<(), &'static str> { + info!("waiting for HMC830 lock..."); let t = clock::get_ms(); - info!("waiting for lock..."); while read(0x12) & 0x02 == 0 { if clock::get_ms() > t + 2000 { - error!(" lock timeout. Register dump:"); + error!("lock timeout. Register dump:"); for addr in 0x00..0x14 { // These registers don't exist (in the data sheet at least) if addr == 0x0d || addr == 0x0e { continue; } @@ -142,10 +155,11 @@ mod hmc830 { pub mod hmc7043 { use board_misoc::csr; - const DAC_CLK_DIV: u32 = 2; - const FPGA_CLK_DIV: u32 = 8; - const SYSREF_DIV: u32 = 128; - const HMC_SYSREF_DIV: u32 = SYSREF_DIV*8; // Must be <= 4MHz + // All frequencies assume 1.2GHz HMC830 output + const DAC_CLK_DIV: u32 = 2; // 600MHz + const FPGA_CLK_DIV: u32 = 8; // 150MHz + const SYSREF_DIV: u32 = 128; // 9.375MHz + const HMC_SYSREF_DIV: u32 = SYSREF_DIV*8; // 1.171875MHz (must be <= 4MHz) // enabled, divider, analog phase shift, digital phase shift const OUTPUT_CONFIG: [(bool, u32, u8, u8); 14] = [ @@ -315,7 +329,9 @@ pub fn init() -> Result<(), &'static str> { /* do not use other SPI devices before HMC830 SPI mode selection */ hmc830::select_spi_mode(); hmc830::detect()?; - hmc830::init()?; + hmc830::init(); + hmc830::set_dividers(1, 24, 0, 2); // 100MHz ref, 1.2GHz out + hmc830::check_locked()?; hmc7043::enable()?; hmc7043::detect()?; From c8935f7adfac19f2c4cd622f6e156db1f56a5a84 Mon Sep 17 00:00:00 2001 From: ion Date: Tue, 12 Jun 2018 12:56:04 +0100 Subject: [PATCH 0916/2457] Sayma: bypass dividers where possible to minimize noise (nb this changes the output skew). --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index af4aaa279..0a9298c25 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -288,8 +288,11 @@ pub mod hmc7043 { write(channel_base + 0x3, aphase & 0x1f); write(channel_base + 0x4, dphase & 0x1f); - // No analog phase shift on clock channels - if (channel % 2) == 0 { write(channel_base + 0x7, 0x00); } + // bypass analog phase shift on clock channels to reduce noise + if (channel % 2) == 0 { + if divider != 0 { write(channel_base + 0x7, 0x00); } // enable divider + else { write(channel_base + 0x7, 0x03); } // bypass divider for lowest noise + } else { write(channel_base + 0x7, 0x01); } write(channel_base + 0x8, 0x08) From 28ecf81c6ce7332ef4cdd0a99505fa27c4c71598 Mon Sep 17 00:00:00 2001 From: ion Date: Tue, 12 Jun 2018 13:10:26 +0100 Subject: [PATCH 0917/2457] Sayma: HMC7043 init and detect no longer need results. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index af4aaa279..cb8b787df 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -238,7 +238,7 @@ pub mod hmc7043 { Ok(()) } - pub fn enable() -> Result<(), &'static str> { + pub fn enable() { info!("enabling hmc7043"); unsafe { @@ -249,11 +249,9 @@ pub mod hmc7043 { write(0x0, 0x1); // Software reset write(0x0, 0x0); // Normal operation write(0x1, 0x48); // mute all outputs - - Ok(()) } - pub fn init() -> Result<(), &'static str> { + pub fn init() { spi_setup(); info!("loading configuration..."); @@ -301,8 +299,6 @@ pub mod hmc7043 { write(0x1, 0x40); // Unmute, high-performace/low-noise mode info!(" ...done"); - - Ok(()) } pub fn cfg_dac_sysref(dacno: u8, phase: u16) { @@ -333,7 +329,9 @@ pub fn init() -> Result<(), &'static str> { hmc830::set_dividers(1, 24, 0, 2); // 100MHz ref, 1.2GHz out hmc830::check_locked()?; - hmc7043::enable()?; + hmc7043::enable(); hmc7043::detect()?; - hmc7043::init() + hmc7043::init(); + + Ok(()) } From 2de5b0cf2510ec97b76cce4e33a5ca4c5ac877b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 13 Jun 2018 00:47:15 +0800 Subject: [PATCH 0918/2457] artiq_flash/sayma: check for DONE after load --- artiq/frontend/artiq_flash.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 813cd7846..d9589066d 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -114,6 +114,8 @@ class Programmer: self._loaded = defaultdict(lambda: None) self._script = ["init"] + add_commands(self._script, "source xilinx-stat.cfg") + def _transfer_script(self, script): if isinstance(self._client, LocalClient): return "[find {}]".format(script) @@ -144,6 +146,13 @@ class Programmer: "pld load {pld} {{{filename}}}", pld=pld, filename=bitfile) + def check_done(self, tap): + add_commands(self._script, + "set stat [xilinx_get_stat {tap}]", + "echo [format {{{tap} stat: 0b%032b}} $stat]", + "if ![expr $stat & 0x1000] {{echo \"not DONE\"; exit 1;}}", + tap=tap) + def load_proxy(self): raise NotImplementedError @@ -355,8 +364,10 @@ def main(): if args.target == "sayma": rtm_gateware_bit = artifact_path("rtm_gateware", "rtm.bit") programmer.load(rtm_gateware_bit, 0) + programmer.check_done("xc7.tap") gateware_bit = artifact_path(variant, "gateware", "top.bit") programmer.load(gateware_bit, 1) + programmer.check_done("xcu.tap") else: gateware_bit = artifact_path(variant, "gateware", "top.bit") programmer.load(gateware_bit, 0) From aff7fa008f8752cf192f8be79fb01acc162c3c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 12 Jun 2018 19:14:43 +0200 Subject: [PATCH 0919/2457] Revert "artiq_flash/sayma: check for DONE after load" This reverts commit 2de5b0cf2510ec97b76cce4e33a5ca4c5ac877b1. would make artiq uninstallable on windows as win buildbot is broken --- artiq/frontend/artiq_flash.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index d9589066d..813cd7846 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -114,8 +114,6 @@ class Programmer: self._loaded = defaultdict(lambda: None) self._script = ["init"] - add_commands(self._script, "source xilinx-stat.cfg") - def _transfer_script(self, script): if isinstance(self._client, LocalClient): return "[find {}]".format(script) @@ -146,13 +144,6 @@ class Programmer: "pld load {pld} {{{filename}}}", pld=pld, filename=bitfile) - def check_done(self, tap): - add_commands(self._script, - "set stat [xilinx_get_stat {tap}]", - "echo [format {{{tap} stat: 0b%032b}} $stat]", - "if ![expr $stat & 0x1000] {{echo \"not DONE\"; exit 1;}}", - tap=tap) - def load_proxy(self): raise NotImplementedError @@ -364,10 +355,8 @@ def main(): if args.target == "sayma": rtm_gateware_bit = artifact_path("rtm_gateware", "rtm.bit") programmer.load(rtm_gateware_bit, 0) - programmer.check_done("xc7.tap") gateware_bit = artifact_path(variant, "gateware", "top.bit") programmer.load(gateware_bit, 1) - programmer.check_done("xcu.tap") else: gateware_bit = artifact_path(variant, "gateware", "top.bit") programmer.load(gateware_bit, 0) From a9a25f26054906d7ce03b7dff900cb7ad6384ffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 12 Jun 2018 20:00:12 +0200 Subject: [PATCH 0920/2457] sayma_rtm: drive ref_lo_clk_sel, and set clk muxes early --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 4 +++- artiq/gateware/targets/sayma_rtm.py | 4 +++- conda/artiq-dev/meta.yaml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index c33131f54..e0ab1adc3 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -4,13 +4,15 @@ mod clock_mux { const CLK_SRC_EXT_SEL : u8 = 1 << 0; const REF_CLK_SRC_SEL : u8 = 1 << 1; const DAC_CLK_SRC_SEL : u8 = 1 << 2; + const REF_LO_CLK_SEL : u8 = 1 << 3; pub fn init() { unsafe { csr::clock_mux::out_write( 1*CLK_SRC_EXT_SEL | // use ext clk from sma 1*REF_CLK_SRC_SEL | - 1*DAC_CLK_SRC_SEL); + 1*DAC_CLK_SRC_SEL | + 0*REF_LO_CLK_SEL); } } } diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index ac376f5d2..e3fca7e3e 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -124,7 +124,9 @@ class SaymaRTM(Module): self.submodules.clock_mux = gpio.GPIOOut(Cat( platform.request("clk_src_ext_sel"), platform.request("ref_clk_src_sel"), - platform.request("dac_clk_src_sel"))) + platform.request("dac_clk_src_sel"), + platform.request("ref_lo_clk_sel")), + reset_out=0b0111) csr_devices.append("clock_mux") # UART loopback diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 2243461ed..c19a7f3b0 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_44+gitca28f4e + - migen 0.7 py35_46+git5947224c - misoc 0.11 py35_20+git2436a68d - jesd204b 0.7 - microscope From f8627952c83ba2b6f7ddf54414fe5b7ea41544c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 12 Jun 2018 20:25:28 +0200 Subject: [PATCH 0921/2457] conda: fix migen build string --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index c19a7f3b0..a268bb6d0 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_46+git5947224c + - migen 0.7 py35_46+git5947224 - misoc 0.11 py35_20+git2436a68d - jesd204b 0.7 - microscope From 68d16fc292064580a283a4af17c9dfe2391aa781 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Jun 2018 21:28:15 +0800 Subject: [PATCH 0922/2457] serwb: support single-ended signals Low-speed PHY only. --- artiq/gateware/serwb/genphy.py | 22 ++++++++++++++++++---- artiq/gateware/targets/sayma_rtm.py | 2 +- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/serwb/genphy.py b/artiq/gateware/serwb/genphy.py index b9d6c02f2..d4d5c0cc5 100644 --- a/artiq/gateware/serwb/genphy.py +++ b/artiq/gateware/serwb/genphy.py @@ -18,10 +18,18 @@ class _SerdesClocking(Module): # can use this clock to sample data if mode == "master": self.specials += DDROutput(0, 1, self.refclk) - self.specials += DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) + if hasattr(pads, "clk_p"): + self.specials += DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) + else: + self.comb += pads.clk.eq(self.refclk) # In Slave mode, use the clock provided by Master elif mode == "slave": - self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk) + if hasattr(pads, "clk_p"): + self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk) + else: + self.comb += self.refclk.eq(pads.clk) + else: + raise ValueError class _SerdesTX(Module): @@ -47,7 +55,10 @@ class _SerdesTX(Module): # Output data (on rising edge of sys_clk) data = Signal() self.sync += data.eq(datapath.source.data) - self.specials += DifferentialOutput(data, pads.tx_p, pads.tx_n) + if hasattr(pads, "tx_p"): + self.specials += DifferentialOutput(data, pads.tx_p, pads.tx_n) + else: + self.comb += pads.tx.eq(data) class _SerdesRX(Module): @@ -67,7 +78,10 @@ class _SerdesRX(Module): # Input data (on rising edge of sys_clk) data = Signal() data_d = Signal() - self.specials += DifferentialInput(pads.rx_p, pads.rx_n, data) + if hasattr(pads, "rx_p"): + self.specials += DifferentialInput(pads.rx_p, pads.rx_n, data) + else: + self.comb += data.eq(pads.rx) self.sync += data_d.eq(data) # Datapath diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index e3fca7e3e..ed440f891 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -183,7 +183,7 @@ class SaymaRTM(Module): # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") - platform.add_period_constraint(serwb_pads.clk_p, 8.) + platform.add_period_constraint(serwb_pads.clk, 8.) serwb_phy_rtm = serwb.genphy.SERWBPHY(platform.device, serwb_pads, mode="slave") self.submodules.serwb_phy_rtm = serwb_phy_rtm self.comb += [ From 1029ac870b337da258afc7fdb80c75320e1502e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 13 Jun 2018 16:11:30 +0000 Subject: [PATCH 0923/2457] sayma_rtm: don't drive txen pins pins disabled by config necessary for using that pin as DIN (#813) --- artiq/gateware/targets/sayma_rtm.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index ed440f891..c160228a2 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -168,8 +168,6 @@ class SaymaRTM(Module): # HMC clock chip and DAC control self.comb += [ platform.request("ad9154_rst_n").eq(1), - platform.request("ad9154_txen", 0).eq(0b11), - platform.request("ad9154_txen", 1).eq(0b11) ] self.submodules.converter_spi = spi2.SPIMaster(spi2.SPIInterface( From f385add8b17ff69919863a7b7a7882a4a46a8681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 13 Jun 2018 16:26:13 +0000 Subject: [PATCH 0924/2457] slave_fpga: disable cclk and din drive when done to guard against accidental contention (old rtm gateware but #813 rework done) --- artiq/firmware/libboard_artiq/slave_fpga.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/libboard_artiq/slave_fpga.rs b/artiq/firmware/libboard_artiq/slave_fpga.rs index d8ce4060a..90cc487d7 100644 --- a/artiq/firmware/libboard_artiq/slave_fpga.rs +++ b/artiq/firmware/libboard_artiq/slave_fpga.rs @@ -81,6 +81,7 @@ pub fn load() -> Result<(), &'static str> { } shift_u8(0xff); // "Compensate for Special Startup Conditions" csr::slave_fpga_cfg::out_write(PROGRAM_B_BIT); + csr::slave_fpga_cfg::oe_write(PROGRAM_B_BIT); } Ok(()) From edfae3c4bac7bbbd4d5899ab2f92de9def23fe27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 15 Jun 2018 14:24:31 +0000 Subject: [PATCH 0925/2457] hmc7043: make fpga fabric clocks lvds 2 V common and 1.9 Vpp swing is brutal to the banks (HP 1.8V AMC and RT 1.8V RTM) --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 36 ++++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index e0ab1adc3..dfbf4dfe7 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -163,22 +163,22 @@ pub mod hmc7043 { const SYSREF_DIV: u32 = 128; // 9.375MHz const HMC_SYSREF_DIV: u32 = SYSREF_DIV*8; // 1.171875MHz (must be <= 4MHz) - // enabled, divider, analog phase shift, digital phase shift - const OUTPUT_CONFIG: [(bool, u32, u8, u8); 14] = [ - (true, DAC_CLK_DIV, 0x0, 0x0), // 0: DAC2_CLK - (true, SYSREF_DIV, 0x0, 0x0), // 1: DAC2_SYSREF - (true, DAC_CLK_DIV, 0x0, 0x0), // 2: DAC1_CLK - (true, SYSREF_DIV, 0x0, 0x0), // 3: DAC1_SYSREF - (false, 0, 0x0, 0x0), // 4: ADC2_CLK - (false, 0, 0x0, 0x0), // 5: ADC2_SYSREF - (false, 0, 0x0, 0x0), // 6: GTP_CLK2 - (true, SYSREF_DIV, 0x0, 0x0), // 7: FPGA_DAC_SYSREF - (true, FPGA_CLK_DIV, 0x0, 0x0), // 8: GTP_CLK1 - (false, 0, 0x0, 0x0), // 9: AMC_MASTER_AUX_CLK - (false, 0, 0x0, 0x0), // 10: RTM_MASTER_AUX_CLK - (false, 0, 0x0, 0x0), // 11: FPGA_ADC_SYSREF - (false, 0, 0x0, 0x0), // 12: ADC1_CLK - (false, 0, 0x0, 0x0), // 13: ADC1_SYSREF + // enabled, divider, analog phase shift, digital phase shift, output config + const OUTPUT_CONFIG: [(bool, u32, u8, u8, u8); 14] = [ + (true, DAC_CLK_DIV, 0x0, 0x0, 0x08), // 0: DAC2_CLK + (true, SYSREF_DIV, 0x0, 0x0, 0x08), // 1: DAC2_SYSREF + (true, DAC_CLK_DIV, 0x0, 0x0, 0x08), // 2: DAC1_CLK + (true, SYSREF_DIV, 0x0, 0x0, 0x08), // 3: DAC1_SYSREF + (false, 0, 0x0, 0x0, 0x08), // 4: ADC2_CLK + (false, 0, 0x0, 0x0, 0x08), // 5: ADC2_SYSREF + (false, 0, 0x0, 0x0, 0x08), // 6: GTP_CLK2 + (true, SYSREF_DIV, 0x0, 0x0, 0x10), // 7: FPGA_DAC_SYSREF, LVDS + (true, FPGA_CLK_DIV, 0x0, 0x0, 0x08), // 8: GTP_CLK1 + (false, 0, 0x0, 0x0, 0x10), // 9: AMC_MASTER_AUX_CLK + (false, 0, 0x0, 0x0, 0x10), // 10: RTM_MASTER_AUX_CLK + (false, 0, 0x0, 0x0, 0x10), // 11: FPGA_ADC_SYSREF, LVDS + (false, 0, 0x0, 0x0, 0x08), // 12: ADC1_CLK + (false, 0, 0x0, 0x0, 0x08), // 13: ADC1_SYSREF ]; @@ -275,7 +275,7 @@ pub mod hmc7043 { for channel in 0..14 { let channel_base = 0xc8 + 0x0a*(channel as u16); - let (enabled, divider, aphase, dphase) = OUTPUT_CONFIG[channel]; + let (enabled, divider, aphase, dphase, outcfg) = OUTPUT_CONFIG[channel]; if enabled { // Only clock channels need to be high-performance @@ -295,7 +295,7 @@ pub mod hmc7043 { } else { write(channel_base + 0x7, 0x01); } - write(channel_base + 0x8, 0x08) + write(channel_base + 0x8, outcfg) } write(0x1, 0x4a); // Reset dividers and FSMs From 70fd369e2fe8f33f825646ca0d8a282ba0e187f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 15 Jun 2018 17:28:49 +0200 Subject: [PATCH 0926/2457] conda: bump migen (sayma lvds diff term) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index a268bb6d0..ca645ea41 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_46+git5947224 + - migen 0.7 py35_51+git9929b23 - misoc 0.11 py35_20+git2436a68d - jesd204b 0.7 - microscope From 40baa8ecba6bb39913ade5a52a750c211ec11e0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 15 Jun 2018 14:41:26 +0000 Subject: [PATCH 0927/2457] hmc7043: disable ch 10 and 11 group --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index dfbf4dfe7..4879427fa 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -267,8 +267,7 @@ pub mod hmc7043 { write(0x4, (1 << 0) | (1 << 1) | (1 << 3) | - (1 << 4) | - (1 << 5)); + (1 << 4)); write(0x5c, (HMC_SYSREF_DIV & 0xff) as u8); // Set SYSREF timer divider write(0x5d, ((HMC_SYSREF_DIV & 0x0f) >> 8) as u8); From f9910ab2428e79d39061cd58971a19b77523e389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 15 Jun 2018 19:35:01 +0200 Subject: [PATCH 0928/2457] i2c: support selecting multiple or no channels closes #1054 --- artiq/coredevice/i2c.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/artiq/coredevice/i2c.py b/artiq/coredevice/i2c.py index 92d66b8dd..44b3f9094 100644 --- a/artiq/coredevice/i2c.py +++ b/artiq/coredevice/i2c.py @@ -48,23 +48,28 @@ class PCA9548: self.address = address @kernel - def set(self, channel): - """Select one channel. + def select(self, mask): + """Enable/disable channels. - Selecting multiple channels at the same time is not supported by this - driver. - - :param channel: channel number (0-7) + :param mask: Bit mask of enabled channels """ i2c_start(self.busno) try: if not i2c_write(self.busno, self.address): raise I2CError("PCA9548 failed to ack address") - if not i2c_write(self.busno, 1 << channel): + if not i2c_write(self.busno, mask): raise I2CError("PCA9548 failed to ack control word") finally: i2c_stop(self.busno) + @kernel + def set(self, channel): + """Enable one channel. + + :param channel: channel number (0-7) + """ + self.select(1 << channel) + @kernel def readback(self): i2c_start(self.busno) From 53ab255c004baac1d0fdcd69f2f78dd035a01e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sat, 16 Jun 2018 12:47:26 +0200 Subject: [PATCH 0929/2457] sayma_amc: enable slave fpga loading (#813) --- artiq/gateware/targets/sayma_amc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 6f34e8663..fd389f8e4 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -194,7 +194,7 @@ class Standalone(MiniSoC, AMPSoC): slave_fpga_cfg.init_b, slave_fpga_cfg.program_b, ]) - # self.csr_devices.append("slave_fpga_cfg") + self.csr_devices.append("slave_fpga_cfg") self.config["SLAVE_FPGA_GATEWARE"] = 0x200000 # AMC/RTM serwb From 4f0c918dd3bbe35f9b32399c1ff9d80dbb13901f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 17 Jun 2018 00:27:27 +0800 Subject: [PATCH 0930/2457] slave_fpga: improve messaging --- artiq/firmware/libboard_artiq/slave_fpga.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/libboard_artiq/slave_fpga.rs b/artiq/firmware/libboard_artiq/slave_fpga.rs index 90cc487d7..a400af440 100644 --- a/artiq/firmware/libboard_artiq/slave_fpga.rs +++ b/artiq/firmware/libboard_artiq/slave_fpga.rs @@ -30,23 +30,21 @@ pub fn load() -> Result<(), &'static str> { let header = unsafe { slice::from_raw_parts(GATEWARE, 8) }; let magic = BigEndian::read_u32(&header[0..]); - info!("Magic: 0x{:08x}", magic); + let length = BigEndian::read_u32(&header[4..]) as usize; + info!(" magic: 0x{:08x}, length: 0x{:08x}", magic, length); if magic != 0x5352544d { // "SRTM", see sayma_rtm target as well return Err("Bad magic"); } - - let length = BigEndian::read_u32(&header[4..]) as usize; - info!("Length: 0x{:08x}", length); if length > 0x220000 { return Err("Too large (corrupted?)"); } unsafe { if csr::slave_fpga_cfg::in_read() & DONE_BIT != 0 { - info!("DONE before loading"); + info!(" DONE before loading"); } if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { - info!("INIT asserted before loading"); + info!(" INIT asserted before loading"); } csr::slave_fpga_cfg::out_write(0); @@ -74,8 +72,7 @@ pub fn load() -> Result<(), &'static str> { let t = clock::get_ms(); while csr::slave_fpga_cfg::in_read() & DONE_BIT == 0 { if clock::get_ms() > t + 100 { - error!("Timeout wating for DONE after loading"); - return Err("Not DONE"); + return Err("Timeout wating for DONE after loading"); } shift_u8(0xff); } @@ -84,5 +81,6 @@ pub fn load() -> Result<(), &'static str> { csr::slave_fpga_cfg::oe_write(PROGRAM_B_BIT); } + info!(" ...done"); Ok(()) } From 32484a62de59b53d97c89fcf21ca71b8fb5a8bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sun, 17 Jun 2018 19:09:02 +0800 Subject: [PATCH 0931/2457] sayma_amc: remove unused imports --- artiq/gateware/targets/sayma_amc.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index fd389f8e4..a6ad70a7c 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -7,15 +7,12 @@ import warnings from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer -from migen.genlib.io import DifferentialInput from microscope import * from misoc.cores import gpio -from misoc.cores.slave_fpga import SlaveFPGA from misoc.integration.soc_sdram import soc_sdram_args, soc_sdram_argdict from misoc.integration.builder import builder_args, builder_argdict -from misoc.interconnect import stream from misoc.interconnect.csr import * from misoc.targets.sayma_amc import BaseSoC, MiniSoC From 6272052d151cc23b608f9af7efb7a55281cb53af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 18 Jun 2018 08:04:07 +0000 Subject: [PATCH 0932/2457] ad9154: don't drive the bsm with txen pins --- artiq/firmware/libboard_artiq/ad9154.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 02f2d7a77..96d8ff8df 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -167,7 +167,9 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { 0*ad9154_reg::PD_BG); clock::spin_us(100); write(ad9154_reg::TXENMASK1, 0*ad9154_reg::DACA_MASK | - 0*ad9154_reg::DACB_MASK); // TX not controlled by TXEN pins + 0*ad9154_reg::DACB_MASK); // DAC PD not controlled by TXEN pins + write(ad9154_reg::PWRCNTRL3, 1*ad9154_reg::ENA_SPI_TXEN | + 1*ad9154_reg::SPI_TXEN); write(ad9154_reg::CLKCFG0, 0*ad9154_reg::REF_CLKDIV_EN | 1*ad9154_reg::RF_SYNC_EN | 1*ad9154_reg::DUTY_EN | 0*ad9154_reg::PD_CLK_REC | From 0e640a6d6ff2dc84754cd7b724e8d140170c9f7f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 18 Jun 2018 17:04:12 +0800 Subject: [PATCH 0933/2457] hmc7043: fix SYSREF to meet s/h at FPGA (#794) --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 4879427fa..f9018084e 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -172,7 +172,7 @@ pub mod hmc7043 { (false, 0, 0x0, 0x0, 0x08), // 4: ADC2_CLK (false, 0, 0x0, 0x0, 0x08), // 5: ADC2_SYSREF (false, 0, 0x0, 0x0, 0x08), // 6: GTP_CLK2 - (true, SYSREF_DIV, 0x0, 0x0, 0x10), // 7: FPGA_DAC_SYSREF, LVDS + (true, SYSREF_DIV, 0x0, 0x2, 0x10), // 7: FPGA_DAC_SYSREF, LVDS (true, FPGA_CLK_DIV, 0x0, 0x0, 0x08), // 8: GTP_CLK1 (false, 0, 0x0, 0x0, 0x10), // 9: AMC_MASTER_AUX_CLK (false, 0, 0x0, 0x0, 0x10), // 10: RTM_MASTER_AUX_CLK From 21a48711ec1c199181baf840aa8903c433eeaddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 18 Jun 2018 09:34:04 +0000 Subject: [PATCH 0934/2457] i2c: refactor common operations --- artiq/coredevice/i2c.py | 139 +++++++++++++++++++++++++++++++--------- 1 file changed, 109 insertions(+), 30 deletions(-) diff --git a/artiq/coredevice/i2c.py b/artiq/coredevice/i2c.py index 44b3f9094..61be474e4 100644 --- a/artiq/coredevice/i2c.py +++ b/artiq/coredevice/i2c.py @@ -33,6 +33,110 @@ def i2c_read(busno: TInt32, ack: TBool) -> TInt32: raise NotImplementedError("syscall not simulated") +@kernel +def i2c_poll(busno, busaddr): + """Poll I2C device at address. + + :param busno: I2C bus number + :param busaddr: 8 bit I2C device address (LSB=0) + :returns: True if the poll was ACKed + """ + i2c_start(busno) + ack = i2c_write(busno, busaddr) + i2c_stop(busno) + return ack + + +@kernel +def i2c_write_byte(busno, busaddr, data, ack=True): + """Write one byte to a device. + + :param busno: I2C bus number + :param busaddr: 8 bit I2C device address (LSB=0) + :param data: Data byte to be written + :param nack: Allow NACK + """ + i2c_start(busno) + try: + if not i2c_write(busno, busaddr): + raise I2CError("failed to ack bus address") + if not i2c_write(busno, data) and ack: + raise I2CError("failed to ack write data") + finally: + i2c_stop(busno) + + +@kernel +def i2c_read_byte(busno, busaddr): + """Read one byte from a device. + + :param busno: I2C bus number + :param busaddr: 8 bit I2C device address (LSB=0) + :returns: Byte read + """ + i2c_start(busno) + data = 0 + try: + if not i2c_write(busno, busaddr | 1): + raise I2CError("failed to ack bus read address") + data = i2c_read(busno, ack=False) + finally: + i2c_stop(busno) + return data + + +@kernel +def i2c_write_many(busno, busaddr, addr, data, ack_last=True): + """Transfer multiple bytes to a device. + + :param busno: I2c bus number + :param busaddr: 8 bit I2C device address (LSB=0) + :param addr: 8 bit data address + :param data: Data bytes to be written + :param ack_last: Expect I2C ACK of the last byte written. If `False`, + the last byte may be NACKed (e.g. EEPROM full page writes). + """ + n = len(data) + i2c_start(busno) + try: + if not i2c_write(busno, busaddr): + raise I2CError("failed to ack bus address") + if not i2c_write(busno, addr): + raise I2CError("failed to ack data address") + for i in range(n): + if not i2c_write(busno, data[i]) and ( + i < n - 1 or ack_last): + raise I2CError("failed to ack write data") + finally: + i2c_stop(busno) + + +@kernel +def i2c_read_many(busno, busaddr, addr, data): + """Transfer multiple bytes from a device. + + :param busno: I2c bus number + :param busaddr: 8 bit I2C device address (LSB=0) + :param addr: 8 bit data address + :param data: List of integers to be filled with the data read. + One entry ber byte. + """ + m = len(data) + i2c_start(busno) + try: + if not i2c_write(busno, busaddr): + raise I2CError("failed to ack bus address") + if not i2c_write(busno, addr): + raise I2CError("failed to ack data address") + i2c_restart(busno) + if not i2c_write(busno, busaddr | 1): + raise I2CError("failed to ack bus read address") + for i in range(m): + data[i] = i2c_read(busno, ack=i < m - 1) + finally: + i2c_stop(busno) + + class PCA9548: """Driver for the PCA9548 I2C bus switch. @@ -53,14 +157,7 @@ class PCA9548: :param mask: Bit mask of enabled channels """ - i2c_start(self.busno) - try: - if not i2c_write(self.busno, self.address): - raise I2CError("PCA9548 failed to ack address") - if not i2c_write(self.busno, mask): - raise I2CError("PCA9548 failed to ack control word") - finally: - i2c_stop(self.busno) + i2c_write_byte(self.busno, self.address, mask) @kernel def set(self, channel): @@ -72,15 +169,7 @@ class PCA9548: @kernel def readback(self): - i2c_start(self.busno) - r = 0 - try: - if not i2c_write(self.busno, self.address | 1): - raise I2CError("PCA9548 failed to ack address") - r = i2c_read(self.busno, False) - finally: - i2c_stop(self.busno) - return r + return i2c_read_byte(self.busno, self.address) class TCA6424A: @@ -97,19 +186,9 @@ class TCA6424A: self.address = address @kernel - def _write24(self, command, value): - i2c_start(self.busno) - try: - if not i2c_write(self.busno, self.address): - raise I2CError("TCA6424A failed to ack address") - if not i2c_write(self.busno, command): - raise I2CError("TCA6424A failed to ack command") - for i in range(3): - if not i2c_write(self.busno, value >> 16): - raise I2CError("TCA6424A failed to ack data") - value <<= 8 - finally: - i2c_stop(self.busno) + def _write24(self, addr, value): + i2c_write_many(self.busno, self.address, addr, + [value >> 16, value >> 8, value]) @kernel def set(self, outputs): From 6f3ed816261b33de65fbae44f2798714696163f1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 18 Jun 2018 17:46:53 +0800 Subject: [PATCH 0935/2457] targets/sayma_rtm: fix description --- artiq/gateware/targets/sayma_rtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index c160228a2..1872529fa 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -214,7 +214,7 @@ class SaymaRTM(Module): def main(): parser = argparse.ArgumentParser( - description="ARTIQ device binary builder for Kasli systems") + description="Sayma RTM gateware builder") parser.add_argument("--output-dir", default="artiq_sayma/rtm_gateware", help="output directory for generated " "source files and binaries") From d29b3dd588e853c19f569e0b3ef0805d50ba64d6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Jun 2018 13:47:32 +0800 Subject: [PATCH 0936/2457] hmc830: compile-time configurable reference frequency --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 8 +++++++- artiq/gateware/targets/sayma_amc.py | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index f9018084e..10651d0bf 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -330,7 +330,13 @@ pub fn init() -> Result<(), &'static str> { hmc830::select_spi_mode(); hmc830::detect()?; hmc830::init(); - hmc830::set_dividers(1, 24, 0, 2); // 100MHz ref, 1.2GHz out + + // 1.2GHz out + #[cfg(hmc830_ref = "100")] + hmc830::set_dividers(1, 24, 0, 2); + #[cfg(hmc830_ref = "150")] + hmc830::set_dividers(2, 32, 0, 2); + hmc830::check_locked()?; hmc7043::enable(); diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index a6ad70a7c..76993f28c 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -204,6 +204,8 @@ class Standalone(MiniSoC, AMPSoC): self.submodules += serwb_core self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) + self.config["HMC830_REF"] = "100" + # RTIO rtio_channels = [] for i in range(4): From 6403a0d5d15ea3b0b4bc3d667523960aa5d0c10c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Jun 2018 13:52:05 +0800 Subject: [PATCH 0937/2457] sayma_amc: update without-sawg description --- artiq/gateware/targets/sayma_amc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 76993f28c..f6e622f2f 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -494,7 +494,7 @@ def main(): parser.add_argument("--without-sawg", default=False, action="store_true", help="Remove SAWG RTIO channels feeding the JESD links (speeds up " - "compilation time). Replaces them with fixed sawtooth generators.") + "compilation time). Replaces them with fixed pattern generators.") args = parser.parse_args() variant = args.variant.lower() From 476cfa0f534ba6cb504b8a22b20af7df5dbdd6e0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Jun 2018 14:29:43 +0800 Subject: [PATCH 0938/2457] si5324: improve lock messaging --- artiq/firmware/libboard_artiq/si5324.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index a03aaccb2..0382cea1f 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -177,6 +177,7 @@ fn locked() -> Result { } fn monitor_lock() -> Result<()> { + info!("waiting for Si5324 lock...") let t = clock::get_ms(); while !locked()? { // Yes, lock can be really slow. @@ -184,7 +185,7 @@ fn monitor_lock() -> Result<()> { return Err("Si5324 lock timeout"); } } - info!("Si5324 is locked"); + info!(" ...locked"); Ok(()) } From 433273dd9571a5754247c332a58d5172c814b3b3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Jun 2018 14:33:48 +0800 Subject: [PATCH 0939/2457] sayma: support RTM FPGA, HMC830 and HMC7043 in DRTIO master and satellite --- artiq/firmware/satman/main.rs | 9 ++- artiq/gateware/targets/sayma_amc.py | 94 +++++++++++++++-------------- 2 files changed, 54 insertions(+), 49 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 6cbadcecb..e10ff0ed2 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -247,18 +247,21 @@ pub extern fn main() -> i32 { info!("software version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); info!("gateware version {}", ident::read(&mut [0; 64])); + #[cfg(has_slave_fpga_cfg)] + board_artiq::slave_fpga::load().expect("cannot load RTM FPGA gateware"); #[cfg(has_serwb_phy_amc)] serwb::wait_init(); - #[cfg(has_hmc830_7043)] - /* must be the first SPI init because of HMC830 SPI mode selection */ - hmc830_7043::init().expect("cannot initialize HMC830/7043"); i2c::init(); si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324"); unsafe { csr::drtio_transceiver::stable_clkin_write(1); } + #[cfg(has_hmc830_7043)] + /* must be the first SPI init because of HMC830 SPI mode selection */ + hmc830_7043::init().expect("cannot initialize HMC830/7043"); + loop { while !drtio_link_rx_up() { process_errors(); diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index f6e622f2f..84c44b599 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -8,8 +8,6 @@ import warnings from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer -from microscope import * - from misoc.cores import gpio from misoc.integration.soc_sdram import soc_sdram_args, soc_sdram_argdict from misoc.integration.builder import builder_args, builder_argdict @@ -152,26 +150,8 @@ class AD9154NoSAWG(Module, AutoCSR): ] -class Standalone(MiniSoC, AMPSoC): - mem_map = { - "cri_con": 0x10000000, - "rtio": 0x11000000, - "rtio_dma": 0x12000000, - "serwb": 0x13000000, - "mailbox": 0x70000000 - } - mem_map.update(MiniSoC.mem_map) - - def __init__(self, with_sawg, **kwargs): - MiniSoC.__init__(self, - cpu_type="or1k", - sdram_controller_type="minicon", - l2_size=128*1024, - ident=artiq_version, - ethmac_nrxslots=4, - ethmac_ntxslots=4, - **kwargs) - AMPSoC.__init__(self) +class RTMCommon: + def __init__(self): platform = self.platform # forward RTM UART to second FTDI UART channel @@ -204,8 +184,32 @@ class Standalone(MiniSoC, AMPSoC): self.submodules += serwb_core self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) + +class Standalone(MiniSoC, AMPSoC, RTMCommon): + mem_map = { + "cri_con": 0x10000000, + "rtio": 0x11000000, + "rtio_dma": 0x12000000, + "serwb": 0x13000000, + "mailbox": 0x70000000 + } + mem_map.update(MiniSoC.mem_map) + + def __init__(self, with_sawg, **kwargs): + MiniSoC.__init__(self, + cpu_type="or1k", + sdram_controller_type="minicon", + l2_size=128*1024, + ident=artiq_version, + ethmac_nrxslots=4, + ethmac_ntxslots=4, + **kwargs) + AMPSoC.__init__(self) + RTMCommon.__init__(self) self.config["HMC830_REF"] = "100" + platform = self.platform + # RTIO rtio_channels = [] for i in range(4): @@ -270,12 +274,13 @@ class Standalone(MiniSoC, AMPSoC): self.csr_devices.append("rtio_analyzer") -class Master(MiniSoC, AMPSoC): +class Master(MiniSoC, AMPSoC, RTMCommon): mem_map = { "cri_con": 0x10000000, - "rtio": 0x20000000, - "rtio_dma": 0x30000000, - "drtio_aux": 0x50000000, + "rtio": 0x11000000, + "rtio_dma": 0x12000000, + "serwb": 0x13000000, + "drtio_aux": 0x14000000, "mailbox": 0x70000000 } mem_map.update(MiniSoC.mem_map) @@ -290,6 +295,8 @@ class Master(MiniSoC, AMPSoC): ethmac_ntxslots=4, **kwargs) AMPSoC.__init__(self) + RTMCommon.__init__(self) + self.config["HMC830_REF"] = "150" if with_sawg: warnings.warn("SAWG is not implemented yet with DRTIO, ignoring.") @@ -297,9 +304,6 @@ class Master(MiniSoC, AMPSoC): platform = self.platform rtio_clk_freq = 150e6 - self.submodules += Microscope(platform.request("serial", 1), - self.clk_freq) - # Si5324 used as a free-running oscillator, to avoid dependency on RTM. self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) self.csr_devices.append("si5324_rst_n") @@ -390,9 +394,10 @@ class Master(MiniSoC, AMPSoC): self.register_kernel_cpu_csrdevice("cri_con") -class Satellite(BaseSoC): +class Satellite(BaseSoC, RTMCommon): mem_map = { - "drtio_aux": 0x50000000, + "serwb": 0x13000000, + "drtio_aux": 0x14000000, } mem_map.update(BaseSoC.mem_map) @@ -403,6 +408,8 @@ class Satellite(BaseSoC): l2_size=128*1024, ident=artiq_version, **kwargs) + RTMCommon.__init__(self) + self.config["HMC830_REF"] = "150" if with_sawg: warnings.warn("SAWG is not implemented yet with DRTIO, ignoring.") @@ -410,9 +417,6 @@ class Satellite(BaseSoC): platform = self.platform rtio_clk_freq = 150e6 - self.submodules += Microscope(platform.request("serial", 1), - self.clk_freq) - rtio_channels = [] for i in range(4): phy = ttl_simple.Output(platform.request("user_led", i)) @@ -508,18 +512,16 @@ def main(): raise SystemExit("Invalid variant (-V/--variant)") soc = cls(with_sawg=not args.without_sawg, **soc_sdram_argdict(args)) - # DRTIO variants do not use the RTM yet. - if variant not in {"master", "satellite"}: - remote_csr_regions = remote_csr.get_remote_csr_regions( - soc.mem_map["serwb"] | soc.shadow_base, - args.rtm_csr_csv) - for name, origin, busword, csrs in remote_csr_regions: - soc.add_csr_region(name, origin, busword, csrs) - # Configuration for RTM peripherals. Keep in sync with sayma_rtm.py! - soc.config["HAS_HMC830_7043"] = None - soc.config["CONVERTER_SPI_HMC830_CS"] = 0 - soc.config["CONVERTER_SPI_HMC7043_CS"] = 1 - soc.config["CONVERTER_SPI_FIRST_AD9154_CS"] = 2 + remote_csr_regions = remote_csr.get_remote_csr_regions( + soc.mem_map["serwb"] | soc.shadow_base, + args.rtm_csr_csv) + for name, origin, busword, csrs in remote_csr_regions: + soc.add_csr_region(name, origin, busword, csrs) + # Configuration for RTM peripherals. Keep in sync with sayma_rtm.py! + soc.config["HAS_HMC830_7043"] = None + soc.config["CONVERTER_SPI_HMC830_CS"] = 0 + soc.config["CONVERTER_SPI_HMC7043_CS"] = 1 + soc.config["CONVERTER_SPI_FIRST_AD9154_CS"] = 2 build_artiq_soc(soc, builder_argdict(args)) From c8624711650d53fc9d4697ede988a5dcbb7d6726 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Jun 2018 14:35:24 +0800 Subject: [PATCH 0940/2457] typo --- artiq/firmware/libboard_artiq/si5324.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 0382cea1f..6cfc5f827 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -177,7 +177,7 @@ fn locked() -> Result { } fn monitor_lock() -> Result<()> { - info!("waiting for Si5324 lock...") + info!("waiting for Si5324 lock..."); let t = clock::get_ms(); while !locked()? { // Yes, lock can be really slow. From 574892a4e549e5882a46dcfa51016f5051404869 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Jun 2018 15:11:03 +0800 Subject: [PATCH 0941/2457] firmware/serwb: cleanup and improve messaging --- artiq/firmware/libboard_artiq/serwb.rs | 116 +++++++++++++++---------- 1 file changed, 69 insertions(+), 47 deletions(-) diff --git a/artiq/firmware/libboard_artiq/serwb.rs b/artiq/firmware/libboard_artiq/serwb.rs index e00f3395a..7f9d750a0 100644 --- a/artiq/firmware/libboard_artiq/serwb.rs +++ b/artiq/firmware/libboard_artiq/serwb.rs @@ -1,53 +1,71 @@ use core::{cmp, str}; use board_misoc::{csr, clock}; -fn read_rtm_ident(buf: &mut [u8]) -> &str { - unsafe { - csr::rtm_identifier::address_write(0); - let len = csr::rtm_identifier::data_read(); - let len = cmp::min(len, buf.len() as u8); - for i in 0..len { - csr::rtm_identifier::address_write(1 + i); - buf[i as usize] = csr::rtm_identifier::data_read(); - } - str::from_utf8_unchecked(&buf[..len as usize]) - } -} - -unsafe fn debug_print(rtm: bool) { - info!("AMC serwb settings:"); - info!(" bitslip: {}", csr::serwb_phy_amc::control_bitslip_read()); - info!(" ready: {}", csr::serwb_phy_amc::control_ready_read()); - info!(" error: {}", csr::serwb_phy_amc::control_error_read()); +fn debug_print(rtm: bool) { + debug!("AMC serwb settings:"); + debug!(" bitslip: {}", unsafe { csr::serwb_phy_amc::control_bitslip_read() }); + debug!(" ready: {}", unsafe { csr::serwb_phy_amc::control_ready_read() }); + debug!(" error: {}", unsafe { csr::serwb_phy_amc::control_error_read() }); if rtm { - info!("RTM serwb settings:"); - info!(" bitslip: {}", csr::serwb_phy_rtm::control_bitslip_read()); - info!(" ready: {}", csr::serwb_phy_rtm::control_ready_read()); - info!(" error: {}", csr::serwb_phy_rtm::control_error_read()); + debug!("RTM serwb settings:"); + debug!(" bitslip: {}", unsafe { csr::serwb_phy_rtm::control_bitslip_read() }); + debug!(" ready: {}", unsafe { csr::serwb_phy_rtm::control_ready_read() }); + debug!(" error: {}", unsafe { csr::serwb_phy_rtm::control_error_read() }); } } fn prbs_test() { let prbs_test_cycles : u32 = 1<<22; - let prbs_test_us : u64 = ((prbs_test_cycles as u64)*40)/125; // 40 bits @125MHz linerate + // 40 bits @125MHz linerate + let prbs_test_us : u64 = ((prbs_test_cycles as u64)*40)/125; + info!("RTM to AMC link test..."); unsafe { - info!("RTM to AMC Link test"); csr::serwb_phy_amc::control_prbs_cycles_write(prbs_test_cycles); csr::serwb_phy_amc::control_prbs_start_write(1); - clock::spin_us(prbs_test_us*110/100); // PRBS test time + 10% - info!("{} errors", csr::serwb_phy_amc::control_prbs_errors_read()); + } + clock::spin_us(prbs_test_us*110/100); // PRBS test time + 10% + let errors = unsafe { + csr::serwb_phy_amc::control_prbs_errors_read() + }; + if errors == 0 { + info!(" ...passed") + } else { + error!(" {} errors found", errors); + } - info!("AMC to RTM Link test"); + info!("AMC to RTM link test..."); + unsafe { csr::serwb_phy_rtm::control_prbs_cycles_write(prbs_test_cycles); csr::serwb_phy_rtm::control_prbs_start_write(1); - clock::spin_us(prbs_test_us*110/100); // PRBS test time + 10% - info!("{} errors", csr::serwb_phy_rtm::control_prbs_errors_read()); + } + clock::spin_us(prbs_test_us*110/100); // PRBS test time + 10% + let errors = unsafe { + csr::serwb_phy_rtm::control_prbs_errors_read() + }; + if errors == 0 { + info!(" ...passed"); + } else { + error!(" {} errors found", errors); } } -fn prng32(seed: &mut u32) -> u32 { *seed = 1664525 * *seed + 1013904223; *seed } +fn magic_test() { + // Try reading the magic number register on the other side of the bridge. + let rtm_magic = unsafe { + csr::rtm_magic::magic_read() + }; + if rtm_magic != 0x5352544d { + error!("incorrect RTM magic number: 0x{:08x}", rtm_magic); + // proceed anyway + } +} + +fn prng32(seed: &mut u32) -> u32 { + *seed = 1664525 * *seed + 1013904223; + *seed +} fn wishbone_test() { let test_length: u32 = 512; @@ -76,7 +94,24 @@ fn wishbone_test() { } } } - info!("{} errors", test_errors); + if test_errors == 0 { + info!(" ...passed"); + } else { + error!(" {} errors found", test_errors); + } +} + +fn read_rtm_ident(buf: &mut [u8]) -> &str { + unsafe { + csr::rtm_identifier::address_write(0); + let len = csr::rtm_identifier::data_read(); + let len = cmp::min(len, buf.len() as u8); + for i in 0..len { + csr::rtm_identifier::address_write(1 + i); + buf[i as usize] = csr::rtm_identifier::data_read(); + } + str::from_utf8_unchecked(&buf[..len as usize]) + } } pub fn wait_init() { @@ -91,26 +126,13 @@ pub fn wait_init() { } } } - info!("done."); + info!(" ...done."); - // PRBS test prbs_test(); - - // Wishbone test + magic_test(); wishbone_test(); - // Try reading the magic number register on the other side of the bridge. - let rtm_magic = unsafe { - csr::rtm_magic::magic_read() - }; - if rtm_magic != 0x5352544d { - error!("incorrect RTM magic number: 0x{:08x}", rtm_magic); - // proceed anyway - } - - unsafe { - debug_print(true); - } + debug_print(true); info!("RTM gateware version {}", read_rtm_ident(&mut [0; 64])); } From 158b5e3083fa25283db656ce8ca367a0347ec762 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Jun 2018 18:09:05 +0800 Subject: [PATCH 0942/2457] satman: program Allaki --- artiq/firmware/satman/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index e10ff0ed2..7e0abd413 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -261,6 +261,8 @@ pub extern fn main() -> i32 { #[cfg(has_hmc830_7043)] /* must be the first SPI init because of HMC830 SPI mode selection */ hmc830_7043::init().expect("cannot initialize HMC830/7043"); + #[cfg(has_allaki_atts)] + board_artiq::hmc542::program_all(8/*=4dB*/); loop { while !drtio_link_rx_up() { From 1d594d0c97a7c8d82e98206596a82d41f4275a65 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Jun 2018 19:09:38 +0800 Subject: [PATCH 0943/2457] firmware: make DAC initialization failures non-fatal This allows using RTMs with one broken DAC for development. --- artiq/firmware/libboard_artiq/ad9154.rs | 36 ++++++++++++++----------- artiq/firmware/runtime/main.rs | 2 +- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 96d8ff8df..db191708f 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -720,25 +720,31 @@ fn dac_sysref_cfg(dacno: u8, phase: u16) { hmc7043::cfg_dac_sysref(dacno, phase); } -pub fn init() -> Result<(), &'static str> { +fn init_dac(dacno: u8) -> Result<(), &'static str> { + let dacno = dacno as u8; + // Reset the DAC, detect and configure it + dac_reset(dacno); + dac_detect(dacno)?; + dac_cfg_retry(dacno)?; + // Run the PRBS, STPL and SYSREF scan tests + dac_prbs(dacno)?; + dac_stpl(dacno, 4, 2)?; + dac_sysref_scan(dacno); + // Set SYSREF phase and reconfigure the DAC + dac_sysref_cfg(dacno, 88); + dac_cfg_retry(dacno)?; + Ok(()) +} + +pub fn init() { // Release the JESD clock domain reset late, as we need to // set up clock chips before. jesd_unreset(); for dacno in 0..csr::AD9154.len() { - let dacno = dacno as u8; - // Reset the DAC, detect and configure it - dac_reset(dacno); - dac_detect(dacno)?; - dac_cfg_retry(dacno)?; - // Run the PRBS, STPL and SYSREF scan tests - dac_prbs(dacno)?; - dac_stpl(dacno, 4, 2)?; - dac_sysref_scan(dacno); - // Set SYSREF phase and reconfigure the DAC - dac_sysref_cfg(dacno, 88); - dac_cfg_retry(dacno)?; + match init_dac(dacno as u8) { + Ok(_) => (), + Err(e) => error!("failed to initialize AD9154-{}: {}", dacno, e) + } } - - Ok(()) } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index f5c0a0202..900bd435f 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -109,7 +109,7 @@ fn startup() { /* must be the first SPI init because of HMC830 SPI mode selection */ board_artiq::hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] - board_artiq::ad9154::init().expect("cannot initialize AD9154"); + board_artiq::ad9154::init(); #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); From eb3259b847c688e44c9131f67ff03641afe4b3bb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Jun 2018 19:10:23 +0800 Subject: [PATCH 0944/2457] firmware: reduce number of DAC initialization attempts Faster startup when one DAC is broken. --- artiq/firmware/libboard_artiq/ad9154.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index db191708f..34a9cbe34 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -672,15 +672,21 @@ fn dac_cfg(dacno: u8) -> Result<(), &'static str> { } fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { - for i in 0..99 { + let mut attempt = 0; + loop { + attempt += 1; dac_reset(dacno); let outcome = dac_cfg(dacno); match outcome { Ok(_) => return outcome, - Err(e) => warn!("AD9154-{} config attempt #{} failed ({}), retrying", dacno, i, e) + Err(e) => { + warn!("AD9154-{} config attempt #{} failed ({})", dacno, attempt, e); + if attempt >= 10 { + return outcome; + } + } } } - dac_cfg(dacno) } fn dac_sysref_scan(dacno: u8) { From 75b6cea52ff6f5ba6b2afe07184867a9f3da3d26 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Jun 2018 19:12:10 +0800 Subject: [PATCH 0945/2457] sayma: add SAWG to DRTIO satellite --- artiq/firmware/satman/main.rs | 2 ++ artiq/gateware/targets/sayma_amc.py | 40 +++++++++++++++++++++-------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 7e0abd413..3f47537a4 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -261,6 +261,8 @@ pub extern fn main() -> i32 { #[cfg(has_hmc830_7043)] /* must be the first SPI init because of HMC830 SPI mode selection */ hmc830_7043::init().expect("cannot initialize HMC830/7043"); + #[cfg(has_ad9154)] + board_artiq::ad9154::init(); #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 84c44b599..08d7b0127 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -43,24 +43,28 @@ class AD9154CRG(Module, AutoCSR): linerate = int(6e9) refclk_freq = int(150e6) fabric_freq = int(125e6) - def __init__(self, platform): + + def __init__(self, platform, use_rtio_clock=False): self.jreset = CSRStorage(reset=1) self.jref = Signal() - self.refclk = Signal() - refclk2 = Signal() self.clock_domains.cd_jesd = ClockDomain() - refclk_pads = platform.request("dac_refclk", 0) + refclk2 = Signal() + refclk_pads = platform.request("dac_refclk", 0) platform.add_period_constraint(refclk_pads.p, 1e9/self.refclk_freq) self.specials += [ Instance("IBUFDS_GTE3", i_CEB=self.jreset.storage, p_REFCLK_HROW_CK_SEL=0b00, i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=self.refclk, o_ODIV2=refclk2), - Instance("BUFG_GT", i_I=refclk2, o_O=self.cd_jesd.clk), AsyncResetSynchronizer(self.cd_jesd, self.jreset.storage), ] + if use_rtio_clock: + self.comb += self.cd_jesd.clk.eq(ClockSignal("rtio")) + else: + self.specials += Instance("BUFG_GT", i_I=refclk2, o_O=self.cd_jesd.clk) + jref = platform.request("dac_sysref") self.specials += Instance("IBUFDS_IBUFDISABLE", p_USE_IBUFDISABLE="TRUE", p_SIM_DEVICE="ULTRASCALE", @@ -227,12 +231,11 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) + self.submodules.ad9154_crg = AD9154CRG(platform) if with_sawg: cls = AD9154 else: cls = AD9154NoSAWG - - self.submodules.ad9154_crg = AD9154CRG(platform) self.submodules.ad9154_0 = cls(platform, self.crg, self.ad9154_crg, 0) self.submodules.ad9154_1 = cls(platform, self.crg, self.ad9154_crg, 1) self.csr_devices.append("ad9154_crg") @@ -299,7 +302,7 @@ class Master(MiniSoC, AMPSoC, RTMCommon): self.config["HMC830_REF"] = "150" if with_sawg: - warnings.warn("SAWG is not implemented yet with DRTIO, ignoring.") + warnings.warn("SAWG is not implemented yet, ignoring.") platform = self.platform rtio_clk_freq = 150e6 @@ -411,9 +414,6 @@ class Satellite(BaseSoC, RTMCommon): RTMCommon.__init__(self) self.config["HMC830_REF"] = "150" - if with_sawg: - warnings.warn("SAWG is not implemented yet with DRTIO, ignoring.") - platform = self.platform rtio_clk_freq = 150e6 @@ -433,6 +433,24 @@ class Satellite(BaseSoC, RTMCommon): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) + self.submodules.ad9154_crg = AD9154CRG(platform, use_rtio_clock=True) + if with_sawg: + cls = AD9154 + else: + cls = AD9154NoSAWG + self.submodules.ad9154_0 = cls(platform, self.crg, self.ad9154_crg, 0) + self.submodules.ad9154_1 = cls(platform, self.crg, self.ad9154_crg, 1) + self.csr_devices.append("ad9154_crg") + self.csr_devices.append("ad9154_0") + self.csr_devices.append("ad9154_1") + self.config["HAS_AD9154"] = None + self.add_csr_group("ad9154", ["ad9154_0", "ad9154_1"]) + self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels) + rtio_channels.extend(rtio.Channel.from_phy(phy) + for sawg in self.ad9154_0.sawgs + + self.ad9154_1.sawgs + for phy in sawg.phys) + self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") From 740e6863c3848c324a266ccc357d158444e68a4b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Jun 2018 23:48:48 +0800 Subject: [PATCH 0946/2457] hmc7043: add delay after releasing hardware reset --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 10651d0bf..0e7f5a6ed 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -155,7 +155,7 @@ mod hmc830 { } pub mod hmc7043 { - use board_misoc::csr; + use board_misoc::{csr, clock}; // All frequencies assume 1.2GHz HMC830 output const DAC_CLK_DIV: u32 = 2; // 600MHz @@ -241,11 +241,12 @@ pub mod hmc7043 { } pub fn enable() { - info!("enabling hmc7043"); + info!("enabling HMC7043"); unsafe { csr::hmc7043_reset::out_write(0); } + clock::spin_us(10_000); spi_setup(); write(0x0, 0x1); // Software reset From 3d0e92aefdac58d2a2e5a731a402848cf3145b83 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Jun 2018 23:49:17 +0800 Subject: [PATCH 0947/2457] hmc7043: check that chip is disabled at startup --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 0e7f5a6ed..06292e831 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -227,10 +227,16 @@ pub mod hmc7043 { } } - pub fn detect() -> Result<(), &'static str> { + pub const CHIP_ID: u32 = 0xf17904; + + pub fn get_id() -> u32 { spi_setup(); - let id = (read(0x78) as u32) << 16 | (read(0x79) as u32) << 8 | read(0x7a) as u32; - if id != 0xf17904 { + (read(0x78) as u32) << 16 | (read(0x79) as u32) << 8 | read(0x7a) as u32 + } + + pub fn detect() -> Result<(), &'static str> { + let id = get_id(); + if id != CHIP_ID { error!("invalid HMC7043 ID: 0x{:08x}", id); return Err("invalid HMC7043 identification"); } else { @@ -340,6 +346,9 @@ pub fn init() -> Result<(), &'static str> { hmc830::check_locked()?; + if hmc7043::get_id() == hmc7043::CHIP_ID { + error!("HMC7043 detected while in reset (board rework missing?)"); + } hmc7043::enable(); hmc7043::detect()?; hmc7043::init(); From 4803ca379940166bd2c55118d035de6d50a03e7c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Jun 2018 23:50:26 +0800 Subject: [PATCH 0948/2457] examples/sayma_drtio: add SAWG channels --- artiq/examples/sayma_drtio/device_db.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/artiq/examples/sayma_drtio/device_db.py b/artiq/examples/sayma_drtio/device_db.py index dc0ef7aff..6a5cf31d2 100644 --- a/artiq/examples/sayma_drtio/device_db.py +++ b/artiq/examples/sayma_drtio/device_db.py @@ -134,3 +134,19 @@ device_db = { "arguments": {"spi_device": "rconverter_spi", "chip_select": 3} }, } + +for i in range(8): + device_db["sawg" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.sawg", + "class": "SAWG", + "arguments": {"channel_base": i*10+6, "parallelism": 4} + } + +for i in range(8): + device_db["sawg" + str(8+i)] = { + "type": "local", + "module": "artiq.coredevice.sawg", + "class": "SAWG", + "arguments": {"channel_base": i*10+0x010006, "parallelism": 4} + } From 0c32d07e8b59e60ee304753e732bfa0c07e0daa6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Jun 2018 00:15:58 +0800 Subject: [PATCH 0949/2457] ad9154: new sysref scan Print margins around the pre-defined fixed phase. Also report error if margins are too small. The fixed phase is also changed by this commit (the value 88 is from before the new HMC7043 initialization code, and is probably wrong). --- artiq/firmware/libboard_artiq/ad9154.rs | 75 ++++++++++++++++--------- 1 file changed, 49 insertions(+), 26 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 34a9cbe34..65a130311 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -689,36 +689,58 @@ fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { } } -fn dac_sysref_scan(dacno: u8) { - let mut sync_error_last = 0; - let mut phase_min = None; - let mut phase_max = None; +fn dac_get_sync_error(dacno: u8) -> u16 { + spi_setup(dacno); + let sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) | + ((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8)) + & 0x1ff; + sync_error +} - info!("AD9154-{} SYSREF scan:", dacno); - for phase in 0..512 { - hmc7043::cfg_dac_sysref(dacno, phase); +fn dac_sysref_scan(dacno: u8, center_phase: u16) { + let mut margin_minus = None; + let mut margin_plus = None; + + info!("AD9154-{} SYSREF scan...", dacno); + + hmc7043::cfg_dac_sysref(dacno, center_phase); + clock::spin_us(10000); + let mut sync_error_last = dac_get_sync_error(dacno); + for d in 0..128 { + hmc7043::cfg_dac_sysref(dacno, center_phase - d); clock::spin_us(10000); - spi_setup(dacno); - let sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) | - ((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8)) - & 0x1ff; + let sync_error = dac_get_sync_error(dacno); if sync_error != sync_error_last { - info!(" phase: {}, sync error: {}", phase, sync_error); + info!(" sync error-: {} -> {}", sync_error_last, sync_error); + margin_minus = Some(d); + break; } - if sync_error != 0 { - if phase_min.is_some() { - if sync_error != sync_error_last { - phase_max = Some(phase - 1); - break; - } - } else { - phase_min = Some(phase); - } - } - sync_error_last = sync_error; } - info!(" phase min: {:?}, phase max: {:?}", phase_min, phase_max); + hmc7043::cfg_dac_sysref(dacno, center_phase); + clock::spin_us(10000); + sync_error_last = dac_get_sync_error(dacno); + for d in 0..128 { + hmc7043::cfg_dac_sysref(dacno, center_phase + d); + clock::spin_us(10000); + let sync_error = dac_get_sync_error(dacno); + if sync_error != sync_error_last { + info!(" sync error+: {} -> {}", sync_error_last, sync_error); + margin_plus = Some(d); + break; + } + } + + if margin_minus.is_some() && margin_plus.is_some() { + let margin_minus = margin_minus.unwrap(); + let margin_plus = margin_plus.unwrap(); + info!(" margins: -{} +{}", margin_minus, margin_plus); + if margin_minus < 10 || margin_plus < 10 { + error!("SYSREF margins are too small"); + } + } else { + error!("Unable to determine SYSREF margins"); + } } fn dac_sysref_cfg(dacno: u8, phase: u16) { @@ -735,9 +757,10 @@ fn init_dac(dacno: u8) -> Result<(), &'static str> { // Run the PRBS, STPL and SYSREF scan tests dac_prbs(dacno)?; dac_stpl(dacno, 4, 2)?; - dac_sysref_scan(dacno); + let sysref_phase = 58; + dac_sysref_scan(dacno, sysref_phase); // Set SYSREF phase and reconfigure the DAC - dac_sysref_cfg(dacno, 88); + dac_sysref_cfg(dacno, sysref_phase); dac_cfg_retry(dacno)?; Ok(()) } From 5272c11704bb8fb144da75d0bd7bd0f7bee8dc8a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Jun 2018 17:02:54 +0800 Subject: [PATCH 0950/2457] typo --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 06292e831..6d6184e45 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -179,7 +179,7 @@ pub mod hmc7043 { (false, 0, 0x0, 0x0, 0x10), // 11: FPGA_ADC_SYSREF, LVDS (false, 0, 0x0, 0x0, 0x08), // 12: ADC1_CLK (false, 0, 0x0, 0x0, 0x08), // 13: ADC1_SYSREF - ]; + ]; fn spi_setup() { @@ -307,7 +307,7 @@ pub mod hmc7043 { write(0x1, 0x4a); // Reset dividers and FSMs write(0x1, 0x48); write(0x1, 0xc8); // Synchronize dividers - write(0x1, 0x40); // Unmute, high-performace/low-noise mode + write(0x1, 0x40); // Unmute, high-performance/low-noise mode info!(" ...done"); } From 9142a5ab8ad3e03d6f869bc7d350b8478033ee68 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Jun 2018 17:39:43 +0800 Subject: [PATCH 0951/2457] rtio: expose coarse timestamp in RTIO and DRTIO satellite cores --- artiq/gateware/drtio/core.py | 1 + artiq/gateware/rtio/core.py | 1 + 2 files changed, 2 insertions(+) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index ff64bf5f0..61c1d2eb4 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -90,6 +90,7 @@ class DRTIOSatellite(Module): coarse_ts.eq(coarse_ts + 1) ) self.comb += self.rt_packet.cri.counter.eq(coarse_ts << fine_ts_width) + self.coarse_ts = coarse_ts self.submodules.outputs = ClockDomainsRenamer("rio")( SED(channels, fine_ts_width, "sync", diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 484c64bbe..edab0bf08 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -73,6 +73,7 @@ class Core(Module, AutoCSR): coarse_ts_cdc.i.eq(coarse_ts), self.cri.counter.eq(coarse_ts_cdc.o << glbl_fine_ts_width) ] + self.coarse_ts = coarse_ts # Outputs/Inputs quash_channels = [n for n, c in enumerate(channels) if isinstance(c, LogChannel)] From 814d0583dbbea3cffa1f1f6f16b29b5ada0858d4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Jun 2018 17:40:48 +0800 Subject: [PATCH 0952/2457] hmc7043: improve smoothness of sysref phase control --- artiq/firmware/libboard_artiq/ad9154.rs | 2 +- artiq/firmware/libboard_artiq/hmc830_7043.rs | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 65a130311..703438a22 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -757,7 +757,7 @@ fn init_dac(dacno: u8) -> Result<(), &'static str> { // Run the PRBS, STPL and SYSREF scan tests dac_prbs(dacno)?; dac_stpl(dacno, 4, 2)?; - let sysref_phase = 58; + let sysref_phase = 61; dac_sysref_scan(dacno, sysref_phase); // Set SYSREF phase and reconfigure the DAC dac_sysref_cfg(dacno, sysref_phase); diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 6d6184e45..59a69ba90 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -318,12 +318,14 @@ pub mod hmc7043 { * Digital delay resolution: 1/2 input clock cycle = 416ps for 1.2GHz * 16*25ps = 400ps: limit analog delay to 16 steps instead of 32. */ + let analog_delay = (phase % 17) as u8; + let digital_delay = (phase / 17) as u8; if dacno == 0 { - write(0x00d5, (phase & 0xf) as u8); - write(0x00d6, ((phase >> 4) & 0x1f) as u8); + write(0x00d5, analog_delay); + write(0x00d6, digital_delay); } else if dacno == 1 { - write(0x00e9, (phase & 0xf) as u8); - write(0x00ea, ((phase >> 4) & 0x1f) as u8); + write(0x00e9, analog_delay); + write(0x00ea, digital_delay); } else { unimplemented!(); } From 28fb0fd754f620462e348452e105be327f7b9511 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Jun 2018 17:42:04 +0800 Subject: [PATCH 0953/2457] sayma: add SYSREF sampler gateware --- artiq/gateware/jesd204_tools.py | 107 ++++++++++++++++++++++++++++ artiq/gateware/targets/sayma_amc.py | 98 +++++-------------------- 2 files changed, 123 insertions(+), 82 deletions(-) create mode 100644 artiq/gateware/jesd204_tools.py diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py new file mode 100644 index 000000000..bc7a9c853 --- /dev/null +++ b/artiq/gateware/jesd204_tools.py @@ -0,0 +1,107 @@ +from collections import namedtuple + +from migen import * +from migen.genlib.cdc import MultiReg +from migen.genlib.resetsync import AsyncResetSynchronizer +from misoc.interconnect.csr import * + +from jesd204b.common import (JESD204BTransportSettings, + JESD204BPhysicalSettings, + JESD204BSettings) +from jesd204b.phy.gth import GTHChannelPLL as JESD204BGTHChannelPLL +from jesd204b.phy import JESD204BPhyTX +from jesd204b.core import JESD204BCoreTX +from jesd204b.core import JESD204BCoreTXControl + + +class UltrascaleCRG(Module, AutoCSR): + linerate = int(6e9) + refclk_freq = int(150e6) + fabric_freq = int(125e6) + + def __init__(self, platform, use_rtio_clock=False): + self.jreset = CSRStorage(reset=1) + self.jref = Signal() + self.refclk = Signal() + self.clock_domains.cd_jesd = ClockDomain() + + refclk2 = Signal() + refclk_pads = platform.request("dac_refclk", 0) + platform.add_period_constraint(refclk_pads.p, 1e9/self.refclk_freq) + self.specials += [ + Instance("IBUFDS_GTE3", i_CEB=self.jreset.storage, p_REFCLK_HROW_CK_SEL=0b00, + i_I=refclk_pads.p, i_IB=refclk_pads.n, + o_O=self.refclk, o_ODIV2=refclk2), + AsyncResetSynchronizer(self.cd_jesd, self.jreset.storage), + ] + + if use_rtio_clock: + self.comb += self.cd_jesd.clk.eq(ClockSignal("rtio")) + else: + self.specials += Instance("BUFG_GT", i_I=refclk2, o_O=self.cd_jesd.clk) + + jref = platform.request("dac_sysref") + jref_se = Signal() + self.specials += [ + Instance("IBUFDS_IBUFDISABLE", + p_USE_IBUFDISABLE="TRUE", p_SIM_DEVICE="ULTRASCALE", + i_IBUFDISABLE=self.jreset.storage, + i_I=jref.p, i_IB=jref.n, + o_O=jref_se), + # SYSREF normally meets s/h at the FPGA, except during margin + # scan. Be paranoid and use a double-register anyway. + MultiReg(jref_se, self.jref, "jesd") + ] + + +PhyPads = namedtuple("PhyPads", "txp txn") + + +class UltrascaleTX(Module, AutoCSR): + def __init__(self, platform, sys_crg, jesd_crg, dac): + ps = JESD204BPhysicalSettings(l=8, m=4, n=16, np=16) + ts = JESD204BTransportSettings(f=2, s=2, k=16, cs=0) + settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) + + jesd_pads = platform.request("dac_jesd", dac) + phys = [] + for i in range(len(jesd_pads.txp)): + cpll = JESD204BGTHChannelPLL( + jesd_crg.refclk, jesd_crg.refclk_freq, jesd_crg.linerate) + self.submodules += cpll + phy = JESD204BPhyTX( + cpll, PhyPads(jesd_pads.txp[i], jesd_pads.txn[i]), + jesd_crg.fabric_freq, transceiver="gth") + platform.add_period_constraint(phy.transmitter.cd_tx.clk, + 40*1e9/jesd_crg.linerate) + platform.add_false_path_constraints( + sys_crg.cd_sys.clk, + jesd_crg.cd_jesd.clk, + phy.transmitter.cd_tx.clk) + phys.append(phy) + + to_jesd = ClockDomainsRenamer("jesd") + self.submodules.core = core = to_jesd(JESD204BCoreTX( + phys, settings, converter_data_width=64)) + self.submodules.control = control = to_jesd(JESD204BCoreTXControl(core)) + core.register_jsync(platform.request("dac_sync", dac)) + core.register_jref(jesd_crg.jref) + + +# This assumes: +# * coarse RTIO frequency = 16*SYSREF frequency +# * JESD and coarse RTIO clocks are the same +# (only reset may differ). +# * SYSREF meets setup/hold at the FPGA when sampled +# in the JESD/RTIO domain. +# +# Look at the 4 LSBs of the coarse RTIO timestamp counter +# to determine SYSREF phase. + +class SysrefSampler(Module, AutoCSR): + def __init__(self, coarse_ts, jref): + self.sample_result = CSRStatus() + + sample = Signal() + self.sync.rtio += If(coarse_ts[:4] == 0, sample.eq(jref)) + self.specials += MultiReg(sample, self.sample_result.status) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 08d7b0127..3079de4a3 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -2,11 +2,9 @@ import argparse import os -from collections import namedtuple import warnings from migen import * -from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.cores import gpio from misoc.integration.soc_sdram import soc_sdram_args, soc_sdram_argdict @@ -14,18 +12,11 @@ from misoc.integration.builder import builder_args, builder_argdict from misoc.interconnect.csr import * from misoc.targets.sayma_amc import BaseSoC, MiniSoC -from jesd204b.common import (JESD204BTransportSettings, - JESD204BPhysicalSettings, - JESD204BSettings) -from jesd204b.phy.gth import GTHChannelPLL as JESD204BGTHChannelPLL -from jesd204b.phy import JESD204BPhyTX -from jesd204b.core import JESD204BCoreTX -from jesd204b.core import JESD204BCoreTXControl - from artiq.gateware.amp import AMPSoC from artiq.gateware import serwb from artiq.gateware import remote_csr from artiq.gateware import rtio +from artiq.gateware import jesd204_tools from artiq.gateware.rtio.phy import ttl_simple, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale from artiq.gateware.drtio.siphaser import SiPhaser7Series @@ -35,77 +26,10 @@ from artiq.build_soc import build_artiq_soc from artiq import __version__ as artiq_version -PhyPads = namedtuple("PhyPads", "txp txn") -to_jesd = ClockDomainsRenamer("jesd") - - -class AD9154CRG(Module, AutoCSR): - linerate = int(6e9) - refclk_freq = int(150e6) - fabric_freq = int(125e6) - - def __init__(self, platform, use_rtio_clock=False): - self.jreset = CSRStorage(reset=1) - self.jref = Signal() - self.refclk = Signal() - self.clock_domains.cd_jesd = ClockDomain() - - refclk2 = Signal() - refclk_pads = platform.request("dac_refclk", 0) - platform.add_period_constraint(refclk_pads.p, 1e9/self.refclk_freq) - self.specials += [ - Instance("IBUFDS_GTE3", i_CEB=self.jreset.storage, p_REFCLK_HROW_CK_SEL=0b00, - i_I=refclk_pads.p, i_IB=refclk_pads.n, - o_O=self.refclk, o_ODIV2=refclk2), - AsyncResetSynchronizer(self.cd_jesd, self.jreset.storage), - ] - - if use_rtio_clock: - self.comb += self.cd_jesd.clk.eq(ClockSignal("rtio")) - else: - self.specials += Instance("BUFG_GT", i_I=refclk2, o_O=self.cd_jesd.clk) - - jref = platform.request("dac_sysref") - self.specials += Instance("IBUFDS_IBUFDISABLE", - p_USE_IBUFDISABLE="TRUE", p_SIM_DEVICE="ULTRASCALE", - i_IBUFDISABLE=self.jreset.storage, - i_I=jref.p, i_IB=jref.n, - o_O=self.jref) - - -class AD9154JESD(Module, AutoCSR): - def __init__(self, platform, sys_crg, jesd_crg, dac): - ps = JESD204BPhysicalSettings(l=8, m=4, n=16, np=16) - ts = JESD204BTransportSettings(f=2, s=2, k=16, cs=0) - settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) - - jesd_pads = platform.request("dac_jesd", dac) - phys = [] - for i in range(len(jesd_pads.txp)): - cpll = JESD204BGTHChannelPLL( - jesd_crg.refclk, jesd_crg.refclk_freq, jesd_crg.linerate) - self.submodules += cpll - phy = JESD204BPhyTX( - cpll, PhyPads(jesd_pads.txp[i], jesd_pads.txn[i]), - jesd_crg.fabric_freq, transceiver="gth") - platform.add_period_constraint(phy.transmitter.cd_tx.clk, - 40*1e9/jesd_crg.linerate) - platform.add_false_path_constraints( - sys_crg.cd_sys.clk, - jesd_crg.cd_jesd.clk, - phy.transmitter.cd_tx.clk) - phys.append(phy) - - self.submodules.core = core = to_jesd(JESD204BCoreTX( - phys, settings, converter_data_width=64)) - self.submodules.control = control = to_jesd(JESD204BCoreTXControl(core)) - core.register_jsync(platform.request("dac_sync", dac)) - core.register_jref(jesd_crg.jref) - - class AD9154(Module, AutoCSR): def __init__(self, platform, sys_crg, jesd_crg, dac): - self.submodules.jesd = AD9154JESD(platform, sys_crg, jesd_crg, dac) + self.submodules.jesd = jesd204_tools.UltrascaleTX( + platform, sys_crg, jesd_crg, dac) self.sawgs = [sawg.Channel(width=16, parallelism=4) for i in range(4)] self.submodules += self.sawgs @@ -117,7 +41,8 @@ class AD9154(Module, AutoCSR): class AD9154NoSAWG(Module, AutoCSR): def __init__(self, platform, sys_crg, jesd_crg, dac): - self.submodules.jesd = AD9154JESD(platform, sys_crg, jesd_crg, dac) + self.submodules.jesd = jesd204_tools.UltrascaleTX( + platform, sys_crg, jesd_crg, dac) self.sawgs = [] @@ -231,7 +156,7 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - self.submodules.ad9154_crg = AD9154CRG(platform) + self.submodules.ad9154_crg = jesd204_tools.UltrascaleCRG(platform) if with_sawg: cls = AD9154 else: @@ -276,6 +201,10 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") + self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( + self.rtio_core.coarse_ts, self.ad9154_crg.jref) + self.csr_devices.append("sysref_sampler") + class Master(MiniSoC, AMPSoC, RTMCommon): mem_map = { @@ -433,7 +362,8 @@ class Satellite(BaseSoC, RTMCommon): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - self.submodules.ad9154_crg = AD9154CRG(platform, use_rtio_clock=True) + self.submodules.ad9154_crg = jesd204_tools.UltrascaleCRG( + platform, use_rtio_clock=True) if with_sawg: cls = AD9154 else: @@ -491,6 +421,10 @@ class Satellite(BaseSoC, RTMCommon): self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None + self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( + self.drtio0.coarse_ts, self.ad9154_crg.jref) + self.csr_devices.append("sysref_sampler") + rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] platform.add_period_constraint(gth.txoutclk, rtio_clk_period) From 9288301543183a262039c492e9e9b46ba89f1c91 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Jun 2018 22:39:40 +0800 Subject: [PATCH 0954/2457] examples: add DRTIO sines --- .../sayma_drtio/repository/sines_drtio.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 artiq/examples/sayma_drtio/repository/sines_drtio.py diff --git a/artiq/examples/sayma_drtio/repository/sines_drtio.py b/artiq/examples/sayma_drtio/repository/sines_drtio.py new file mode 100644 index 000000000..b7c26bdcb --- /dev/null +++ b/artiq/examples/sayma_drtio/repository/sines_drtio.py @@ -0,0 +1,27 @@ +from artiq.experiment import * + + +class SAWGTestDRTIO(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("ttl_sma_out") + self.sawgs = [self.get_device("sawg"+str(8+i)) for i in range(8)] + + @kernel + def run(self): + core_log("waiting for DRTIO ready...") + while not self.core.get_drtio_link_status(0): + pass + core_log("OK") + + self.core.reset() + + for sawg in self.sawgs: + delay(1*ms) + sawg.amplitude1.set(.4) + # Do not use a sub-multiple of oscilloscope sample rates. + sawg.frequency0.set(9*MHz) + + while True: + delay(0.5*ms) + self.ttl_sma_out.pulse(0.5*ms) From 5a91f820fd962629d569b5e9a2c98c9329fbaa37 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Jun 2018 22:40:04 +0800 Subject: [PATCH 0955/2457] examples: change Sayma sines frequency to 9MHz Well within Red Pitaya bandwidth. --- artiq/examples/sayma_standalone/repository/sines.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/sayma_standalone/repository/sines.py b/artiq/examples/sayma_standalone/repository/sines.py index 803164b3d..7207ba7ec 100644 --- a/artiq/examples/sayma_standalone/repository/sines.py +++ b/artiq/examples/sayma_standalone/repository/sines.py @@ -15,7 +15,7 @@ class SAWGTest(EnvExperiment): delay(1*ms) sawg.amplitude1.set(.4) # Do not use a sub-multiple of oscilloscope sample rates. - sawg.frequency0.set(49*MHz) + sawg.frequency0.set(9*MHz) while True: delay(0.5*ms) From 9260cdb2e85d2660efaea97186739d18eaa804b6 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 21 Jun 2018 00:40:45 +0000 Subject: [PATCH 0956/2457] compiler: support conversion of list to bytearray and bytes. Fixes #1077. --- artiq/compiler/transforms/artiq_ir_generator.py | 3 ++- artiq/test/coredevice/test_embedding.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 970803454..07967dcbb 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1637,7 +1637,7 @@ class ARTIQIRGenerator(algorithm.Visitor): else: assert False elif (types.is_builtin(typ, "list") or types.is_builtin(typ, "array") or - types.is_builtin(typ, "bytearray")): + types.is_builtin(typ, "bytearray") or types.is_builtin(typ, "bytes")): if len(node.args) == 0 and len(node.keywords) == 0: length = ir.Constant(0, builtins.TInt32()) return self.append(ir.Alloc([length], node.type)) @@ -1648,6 +1648,7 @@ class ARTIQIRGenerator(algorithm.Visitor): def body_gen(index): elt = self.iterable_get(arg, index) + elt = self.append(ir.Coerce(elt, builtins.get_iterable_elt(node.type))) self.append(ir.SetElem(result, index, elt)) return self.append(ir.Arith(ast.Add(loc=None), index, ir.Constant(1, length.type))) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index b0bcbbed3..8d0e64aba 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -140,6 +140,8 @@ class _RPCTypes(EnvExperiment): self.accept("foo") self.accept(b"foo") self.accept(bytearray(b"foo")) + self.accept(bytes([1, 2])) + self.accept(bytearray([1, 2])) self.accept((2, 3)) self.accept([1, 2]) self.accept(range(10)) From 095ee28fd93f759ae65cc810387780906148b161 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 21 Jun 2018 00:51:56 +0000 Subject: [PATCH 0957/2457] runtime: fix size values for bytes and bytearray RPCs. Fixes #1076. --- artiq/firmware/libproto_artiq/rpc_proto.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libproto_artiq/rpc_proto.rs b/artiq/firmware/libproto_artiq/rpc_proto.rs index 6f9fc2042..8c39251f7 100644 --- a/artiq/firmware/libproto_artiq/rpc_proto.rs +++ b/artiq/firmware/libproto_artiq/rpc_proto.rs @@ -256,8 +256,8 @@ mod tag { Tag::Int64 => 8, Tag::Float64 => 8, Tag::String => 4, - Tag::Bytes => 4, - Tag::ByteArray => 4, + Tag::Bytes => 8, + Tag::ByteArray => 8, Tag::Tuple(it, arity) => { let mut size = 0; for _ in 0..arity { From 7cc3da4fafba0059340855b1eed0e172b07baac0 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 21 Jun 2018 05:18:51 +0000 Subject: [PATCH 0958/2457] firmware: do not lose the ".dirty" suffix in build versions. Fixes #1074. --- artiq/firmware/libbuild_artiq/lib.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/artiq/firmware/libbuild_artiq/lib.rs b/artiq/firmware/libbuild_artiq/lib.rs index cd35a30a8..81c9ad97b 100644 --- a/artiq/firmware/libbuild_artiq/lib.rs +++ b/artiq/firmware/libbuild_artiq/lib.rs @@ -1,24 +1,21 @@ extern crate walkdir; use std::env; -use std::fs::File; -use std::io::Write; +use std::fs; use std::path::Path; use std::process::Command; use walkdir::WalkDir; pub fn git_describe() { - let git_dir = Path::new("../../../.git"); - - println!("cargo:rerun-if-changed={}", git_dir.join("HEAD").display()); - for entry in WalkDir::new(git_dir.join("refs")) { + let git_checkout = Path::new("../../.."); + for entry in WalkDir::new(git_checkout) { let entry = entry.unwrap(); println!("cargo:rerun-if-changed={}", entry.path().display()); } let version; - if git_dir.exists() { + if git_checkout.join(".git").exists() { let git_describe = Command::new("git") .arg("describe") @@ -43,6 +40,6 @@ pub fn git_describe() { } let out_dir = env::var("OUT_DIR").unwrap(); - let mut f = File::create(Path::new(&out_dir).join("git-describe")).unwrap(); - write!(f, "{}", version).unwrap(); + let git_describe = Path::new(&out_dir).join("git-describe"); + fs::write(&git_describe, version).unwrap(); } From 45e82632082600cb046c07db24a0b70965421560 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Jun 2018 10:11:52 +0800 Subject: [PATCH 0959/2457] hmc7043: do not configure phases during initial init They are determined later on. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 36 +++++++++----------- artiq/gateware/jesd204_tools.py | 3 +- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 59a69ba90..af032f159 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -163,22 +163,22 @@ pub mod hmc7043 { const SYSREF_DIV: u32 = 128; // 9.375MHz const HMC_SYSREF_DIV: u32 = SYSREF_DIV*8; // 1.171875MHz (must be <= 4MHz) - // enabled, divider, analog phase shift, digital phase shift, output config - const OUTPUT_CONFIG: [(bool, u32, u8, u8, u8); 14] = [ - (true, DAC_CLK_DIV, 0x0, 0x0, 0x08), // 0: DAC2_CLK - (true, SYSREF_DIV, 0x0, 0x0, 0x08), // 1: DAC2_SYSREF - (true, DAC_CLK_DIV, 0x0, 0x0, 0x08), // 2: DAC1_CLK - (true, SYSREF_DIV, 0x0, 0x0, 0x08), // 3: DAC1_SYSREF - (false, 0, 0x0, 0x0, 0x08), // 4: ADC2_CLK - (false, 0, 0x0, 0x0, 0x08), // 5: ADC2_SYSREF - (false, 0, 0x0, 0x0, 0x08), // 6: GTP_CLK2 - (true, SYSREF_DIV, 0x0, 0x2, 0x10), // 7: FPGA_DAC_SYSREF, LVDS - (true, FPGA_CLK_DIV, 0x0, 0x0, 0x08), // 8: GTP_CLK1 - (false, 0, 0x0, 0x0, 0x10), // 9: AMC_MASTER_AUX_CLK - (false, 0, 0x0, 0x0, 0x10), // 10: RTM_MASTER_AUX_CLK - (false, 0, 0x0, 0x0, 0x10), // 11: FPGA_ADC_SYSREF, LVDS - (false, 0, 0x0, 0x0, 0x08), // 12: ADC1_CLK - (false, 0, 0x0, 0x0, 0x08), // 13: ADC1_SYSREF + // enabled, divider, output config + const OUTPUT_CONFIG: [(bool, u32, u8); 14] = [ + (true, DAC_CLK_DIV, 0x08), // 0: DAC2_CLK + (true, SYSREF_DIV, 0x08), // 1: DAC2_SYSREF + (true, DAC_CLK_DIV, 0x08), // 2: DAC1_CLK + (true, SYSREF_DIV, 0x08), // 3: DAC1_SYSREF + (false, 0, 0x08), // 4: ADC2_CLK + (false, 0, 0x08), // 5: ADC2_SYSREF + (false, 0, 0x08), // 6: GTP_CLK2 + (true, SYSREF_DIV, 0x10), // 7: FPGA_DAC_SYSREF, LVDS + (true, FPGA_CLK_DIV, 0x08), // 8: GTP_CLK1 + (false, 0, 0x10), // 9: AMC_MASTER_AUX_CLK + (false, 0, 0x10), // 10: RTM_MASTER_AUX_CLK + (false, 0, 0x10), // 11: FPGA_ADC_SYSREF, LVDS + (false, 0, 0x08), // 12: ADC1_CLK + (false, 0, 0x08), // 13: ADC1_SYSREF ]; @@ -281,7 +281,7 @@ pub mod hmc7043 { for channel in 0..14 { let channel_base = 0xc8 + 0x0a*(channel as u16); - let (enabled, divider, aphase, dphase, outcfg) = OUTPUT_CONFIG[channel]; + let (enabled, divider, outcfg) = OUTPUT_CONFIG[channel]; if enabled { // Only clock channels need to be high-performance @@ -291,8 +291,6 @@ pub mod hmc7043 { else { write(channel_base, 0x10); } write(channel_base + 0x1, (divider & 0xff) as u8); write(channel_base + 0x2, ((divider & 0x0f) >> 8) as u8); - write(channel_base + 0x3, aphase & 0x1f); - write(channel_base + 0x4, dphase & 0x1f); // bypass analog phase shift on clock channels to reduce noise if (channel % 2) == 0 { diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index bc7a9c853..33d0ca025 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -49,7 +49,8 @@ class UltrascaleCRG(Module, AutoCSR): i_I=jref.p, i_IB=jref.n, o_O=jref_se), # SYSREF normally meets s/h at the FPGA, except during margin - # scan. Be paranoid and use a double-register anyway. + # scan and before full initialization. + # Be paranoid and use a double-register anyway. MultiReg(jref_se, self.jref, "jesd") ] From 9741654cad03b4c6b010b4b646b8983beab13069 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Jun 2018 10:44:26 +0800 Subject: [PATCH 0960/2457] hmc7043: style --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 29 ++++++++++++-------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index af032f159..8fa2e2ebb 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -181,7 +181,6 @@ pub mod hmc7043 { (false, 0, 0x08), // 13: ADC1_SYSREF ]; - fn spi_setup() { unsafe { while csr::converter_spi::idle_read() == 0 {} @@ -279,25 +278,33 @@ pub mod hmc7043 { write(0x5c, (HMC_SYSREF_DIV & 0xff) as u8); // Set SYSREF timer divider write(0x5d, ((HMC_SYSREF_DIV & 0x0f) >> 8) as u8); - for channel in 0..14 { + for channel in 0..OUTPUT_CONFIG.len() { let channel_base = 0xc8 + 0x0a*(channel as u16); let (enabled, divider, outcfg) = OUTPUT_CONFIG[channel]; if enabled { // Only clock channels need to be high-performance - if (channel % 2) == 0 { write(channel_base, 0xd1); } - else { write(channel_base, 0x51); } + if channel % 2 == 0 { + write(channel_base, 0xd1); + } else { + write(channel_base, 0x51); + } + } else { + write(channel_base, 0x10); } - else { write(channel_base, 0x10); } write(channel_base + 0x1, (divider & 0xff) as u8); write(channel_base + 0x2, ((divider & 0x0f) >> 8) as u8); - // bypass analog phase shift on clock channels to reduce noise - if (channel % 2) == 0 { - if divider != 0 { write(channel_base + 0x7, 0x00); } // enable divider - else { write(channel_base + 0x7, 0x03); } // bypass divider for lowest noise + // bypass analog phase shift on DCLK channels to reduce noise + if channel % 2 == 0 { + if divider != 0 { + write(channel_base + 0x7, 0x00); // enable divider + } else { + write(channel_base + 0x7, 0x03); // bypass divider for lowest noise + } + } else { + write(channel_base + 0x7, 0x01); } - else { write(channel_base + 0x7, 0x01); } write(channel_base + 0x8, outcfg) } @@ -311,13 +318,13 @@ pub mod hmc7043 { } pub fn cfg_dac_sysref(dacno: u8, phase: u16) { - spi_setup(); /* Analog delay resolution: 25ps * Digital delay resolution: 1/2 input clock cycle = 416ps for 1.2GHz * 16*25ps = 400ps: limit analog delay to 16 steps instead of 32. */ let analog_delay = (phase % 17) as u8; let digital_delay = (phase / 17) as u8; + spi_setup(); if dacno == 0 { write(0x00d5, analog_delay); write(0x00d6, digital_delay); From 05e908a0fd66709bc143587bb843730a1133535d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Jun 2018 15:54:30 +0800 Subject: [PATCH 0961/2457] hmc7043: align SYSREF with RTIO --- artiq/firmware/libboard_artiq/ad9154.rs | 6 ++ artiq/firmware/libboard_artiq/hmc830_7043.rs | 67 +++++++++++++++++++- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 703438a22..e637a4550 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -770,6 +770,12 @@ pub fn init() { // set up clock chips before. jesd_unreset(); + // This needs to take place once before DAC SYSREF scan, as + // the HMC7043 input clock (which defines slip resolution) + // is 2x the DAC clock, so there are two possible phases from + // the divider states. This deterministically selects one. + hmc7043::sysref_rtio_align(); + for dacno in 0..csr::AD9154.len() { match init_dac(dacno as u8) { Ok(_) => (), diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 8fa2e2ebb..9015bd917 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -283,11 +283,12 @@ pub mod hmc7043 { let (enabled, divider, outcfg) = OUTPUT_CONFIG[channel]; if enabled { - // Only clock channels need to be high-performance if channel % 2 == 0 { + // DCLK channel: enable high-performance mode write(channel_base, 0xd1); } else { - write(channel_base, 0x51); + // SYSREF channel: disable hi-perf mode, enable slip + write(channel_base, 0x71); } } else { write(channel_base, 0x10); @@ -336,6 +337,68 @@ pub mod hmc7043 { } } + fn cfg_fpga_sysref(phase: u16) { + let analog_delay = (phase % 17) as u8; + let digital_delay = (phase / 17) as u8; + spi_setup(); + write(0x0111, analog_delay); + write(0x0112, digital_delay); + } + + fn sysref_slip() { + spi_setup(); + write(0x0002, 0x02); + write(0x0002, 0x00); + } + + fn sysref_sample() -> bool { + unsafe { csr::sysref_sampler::sample_result_read() == 1 } + } + + pub fn sysref_rtio_align() { + info!("aligning SYSREF with RTIO..."); + + let phase_offset = 44; + let mut slips0 = 0; + let mut slips1 = 0; + + // meet setup/hold (assuming FPGA timing margins are OK) + cfg_fpga_sysref(phase_offset); + // if we are already in the 1 zone, get out of it + while sysref_sample() { + sysref_slip(); + slips0 += 1; + } + // get to the edge of the 0->1 transition (our final setpoint) + while !sysref_sample() { + sysref_slip(); + slips1 += 1; + } + + info!(" ...done ({}/{} slips), verifying timing margin", slips0, slips1); + + let mut margin = None; + for d in 0..phase_offset { + cfg_fpga_sysref(phase_offset - d); + if !sysref_sample() { + margin = Some(d); + break; + } + } + + // meet setup/hold + cfg_fpga_sysref(phase_offset); + + if margin.is_some() { + let margin = margin.unwrap(); + info!(" margin at FPGA: {}", margin); + if margin < 10 { + error!("SYSREF margin at FPGA is too small"); + } + } else { + error!("unable to determine SYSREF margin at FPGA"); + } + } } pub fn init() -> Result<(), &'static str> { From 5a2a857a2ff7d9b563a04c034101f4921034ddb2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Jun 2018 16:23:41 +0800 Subject: [PATCH 0962/2457] firmware: clean up SYSREF phase management --- artiq/firmware/libboard_artiq/ad9154.rs | 26 +++++++++----------- artiq/firmware/libboard_artiq/hmc830_7043.rs | 23 ++++++++--------- artiq/firmware/runtime/main.rs | 2 +- artiq/firmware/satman/main.rs | 2 +- 4 files changed, 23 insertions(+), 30 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index e637a4550..c4086ca02 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -703,11 +703,11 @@ fn dac_sysref_scan(dacno: u8, center_phase: u16) { info!("AD9154-{} SYSREF scan...", dacno); - hmc7043::cfg_dac_sysref(dacno, center_phase); + hmc7043::sysref_offset_dac(dacno, center_phase); clock::spin_us(10000); let mut sync_error_last = dac_get_sync_error(dacno); for d in 0..128 { - hmc7043::cfg_dac_sysref(dacno, center_phase - d); + hmc7043::sysref_offset_dac(dacno, center_phase - d); clock::spin_us(10000); let sync_error = dac_get_sync_error(dacno); if sync_error != sync_error_last { @@ -717,11 +717,11 @@ fn dac_sysref_scan(dacno: u8, center_phase: u16) { } } - hmc7043::cfg_dac_sysref(dacno, center_phase); + hmc7043::sysref_offset_dac(dacno, center_phase); clock::spin_us(10000); sync_error_last = dac_get_sync_error(dacno); for d in 0..128 { - hmc7043::cfg_dac_sysref(dacno, center_phase + d); + hmc7043::sysref_offset_dac(dacno, center_phase + d); clock::spin_us(10000); let sync_error = dac_get_sync_error(dacno); if sync_error != sync_error_last { @@ -743,12 +743,7 @@ fn dac_sysref_scan(dacno: u8, center_phase: u16) { } } -fn dac_sysref_cfg(dacno: u8, phase: u16) { - info!("AD9154-{} setting SYSREF phase to {}", dacno, phase); - hmc7043::cfg_dac_sysref(dacno, phase); -} - -fn init_dac(dacno: u8) -> Result<(), &'static str> { +fn init_dac(dacno: u8, sysref_phase: u16) -> Result<(), &'static str> { let dacno = dacno as u8; // Reset the DAC, detect and configure it dac_reset(dacno); @@ -757,15 +752,14 @@ fn init_dac(dacno: u8) -> Result<(), &'static str> { // Run the PRBS, STPL and SYSREF scan tests dac_prbs(dacno)?; dac_stpl(dacno, 4, 2)?; - let sysref_phase = 61; dac_sysref_scan(dacno, sysref_phase); // Set SYSREF phase and reconfigure the DAC - dac_sysref_cfg(dacno, sysref_phase); + hmc7043::sysref_offset_dac(dacno, sysref_phase); dac_cfg_retry(dacno)?; Ok(()) } -pub fn init() { +pub fn init(sysref_phase_fpga: u16, sysref_phase_dac: u16) { // Release the JESD clock domain reset late, as we need to // set up clock chips before. jesd_unreset(); @@ -774,10 +768,12 @@ pub fn init() { // the HMC7043 input clock (which defines slip resolution) // is 2x the DAC clock, so there are two possible phases from // the divider states. This deterministically selects one. - hmc7043::sysref_rtio_align(); + hmc7043::sysref_rtio_align(sysref_phase_fpga); for dacno in 0..csr::AD9154.len() { - match init_dac(dacno as u8) { + // We assume DCLK and SYSREF traces are matched on the PCB + // (they are on Sayma) so only one phase is needed. + match init_dac(dacno as u8, sysref_phase_dac) { Ok(_) => (), Err(e) => error!("failed to initialize AD9154-{}: {}", dacno, e) } diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 9015bd917..b3b5ece69 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -318,13 +318,13 @@ pub mod hmc7043 { info!(" ...done"); } - pub fn cfg_dac_sysref(dacno: u8, phase: u16) { + pub fn sysref_offset_dac(dacno: u8, phase_offset: u16) { /* Analog delay resolution: 25ps * Digital delay resolution: 1/2 input clock cycle = 416ps for 1.2GHz * 16*25ps = 400ps: limit analog delay to 16 steps instead of 32. */ - let analog_delay = (phase % 17) as u8; - let digital_delay = (phase / 17) as u8; + let analog_delay = (phase_offset % 17) as u8; + let digital_delay = (phase_offset / 17) as u8; spi_setup(); if dacno == 0 { write(0x00d5, analog_delay); @@ -337,9 +337,9 @@ pub mod hmc7043 { } } - fn cfg_fpga_sysref(phase: u16) { - let analog_delay = (phase % 17) as u8; - let digital_delay = (phase / 17) as u8; + fn sysref_offset_fpga(phase_offset: u16) { + let analog_delay = (phase_offset % 17) as u8; + let digital_delay = (phase_offset / 17) as u8; spi_setup(); write(0x0111, analog_delay); write(0x0112, digital_delay); @@ -355,15 +355,13 @@ pub mod hmc7043 { unsafe { csr::sysref_sampler::sample_result_read() == 1 } } - pub fn sysref_rtio_align() { + pub fn sysref_rtio_align(phase_offset: u16) { info!("aligning SYSREF with RTIO..."); - let phase_offset = 44; let mut slips0 = 0; let mut slips1 = 0; - // meet setup/hold (assuming FPGA timing margins are OK) - cfg_fpga_sysref(phase_offset); + sysref_offset_fpga(phase_offset); // if we are already in the 1 zone, get out of it while sysref_sample() { sysref_slip(); @@ -374,12 +372,11 @@ pub mod hmc7043 { sysref_slip(); slips1 += 1; } - info!(" ...done ({}/{} slips), verifying timing margin", slips0, slips1); let mut margin = None; for d in 0..phase_offset { - cfg_fpga_sysref(phase_offset - d); + sysref_offset_fpga(phase_offset - d); if !sysref_sample() { margin = Some(d); break; @@ -387,7 +384,7 @@ pub mod hmc7043 { } // meet setup/hold - cfg_fpga_sysref(phase_offset); + sysref_offset_fpga(phase_offset); if margin.is_some() { let margin = margin.unwrap(); diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 900bd435f..8e407d4c5 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -109,7 +109,7 @@ fn startup() { /* must be the first SPI init because of HMC830 SPI mode selection */ board_artiq::hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] - board_artiq::ad9154::init(); + board_artiq::ad9154::init(44, 61); #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 3f47537a4..302a0ef95 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -262,7 +262,7 @@ pub extern fn main() -> i32 { /* must be the first SPI init because of HMC830 SPI mode selection */ hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] - board_artiq::ad9154::init(); + board_artiq::ad9154::init(32, 61); #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); From e29536351dfd41334f1081dc76bbbb831ffe7113 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Jun 2018 17:00:32 +0800 Subject: [PATCH 0963/2457] drtio: resync SYSREF when TSC is loaded --- artiq/firmware/runtime/main.rs | 7 ++++++- artiq/firmware/satman/main.rs | 27 +++++++++++++++++++++++++-- artiq/gateware/drtio/core.py | 12 +++++++++++- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 8e407d4c5..1e39f9968 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -56,6 +56,11 @@ mod moninj; #[cfg(has_rtio_analyzer)] mod analyzer; +#[cfg(has_ad9154)] +const SYSREF_PHASE_FPGA: u16 = 32; +#[cfg(has_ad9154)] +const SYSREF_PHASE_DAC: u16 = 61; + fn startup() { irq::set_mask(0); irq::set_ie(true); @@ -109,7 +114,7 @@ fn startup() { /* must be the first SPI init because of HMC830 SPI mode selection */ board_artiq::hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] - board_artiq::ad9154::init(44, 61); + board_artiq::ad9154::init(SYSREF_PHASE_FPGA, SYSREF_PHASE_DAC); #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 302a0ef95..4e3a1a4c5 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -26,6 +26,16 @@ fn drtio_reset_phy(reset: bool) { } } +fn drtio_tsc_loaded() -> bool { + unsafe { + let tsc_loaded = (csr::DRTIO[0].tsc_loaded_read)() == 1; + if tsc_loaded { + (csr::DRTIO[0].tsc_loaded_write)(1); + } + tsc_loaded + } +} + fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error> { // In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels, // and u16 otherwise; hence the `as _` conversion. @@ -238,6 +248,12 @@ fn drtio_link_rx_up() -> bool { } } +const SIPHASER_PHASE: u16 = 32; +#[cfg(has_ad9154)] +const SYSREF_PHASE_FPGA: u16 = 32; +#[cfg(has_ad9154)] +const SYSREF_PHASE_DAC: u16 = 61; + #[no_mangle] pub extern fn main() -> i32 { clock::init(); @@ -262,7 +278,7 @@ pub extern fn main() -> i32 { /* must be the first SPI init because of HMC830 SPI mode selection */ hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] - board_artiq::ad9154::init(32, 61); + board_artiq::ad9154::init(SYSREF_PHASE_FPGA, SYSREF_PHASE_DAC); #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); @@ -272,16 +288,23 @@ pub extern fn main() -> i32 { } info!("link is up, switching to recovered clock"); si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); - si5324::siphaser::calibrate_skew(32).expect("failed to calibrate skew"); + si5324::siphaser::calibrate_skew(SIPHASER_PHASE).expect("failed to calibrate skew"); drtioaux::reset(0); drtio_reset(false); drtio_reset_phy(false); while drtio_link_rx_up() { process_errors(); process_aux_packets(); + #[cfg(has_hmc830_7043)] + { + if drtio_tsc_loaded() { + hmc830_7043::hmc7043::sysref_rtio_align(SYSREF_PHASE_FPGA); + } + } } drtio_reset_phy(true); drtio_reset(true); + drtio_tsc_loaded(); info!("link is down, switching to local crystal clock"); si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks"); } diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 61c1d2eb4..38c6d8a2a 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -2,6 +2,7 @@ from types import SimpleNamespace from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.cdc import PulseSynchronizer from misoc.interconnect.csr import * from artiq.gateware.rtio.sed.core import * @@ -34,6 +35,7 @@ class DRTIOSatellite(Module): lane_count=8, fifo_depth=128): self.reset = CSRStorage(reset=1) self.reset_phy = CSRStorage(reset=1) + self.tsc_loaded = CSR() self.clock_domains.cd_rio = ClockDomain() self.clock_domains.cd_rio_phy = ClockDomain() @@ -92,6 +94,14 @@ class DRTIOSatellite(Module): self.comb += self.rt_packet.cri.counter.eq(coarse_ts << fine_ts_width) self.coarse_ts = coarse_ts + ps_tsc_load = PulseSynchronizer("rtio", "sys") + self.submodules += ps_tsc_load + self.comb += ps_tsc_load.i.eq(self.rt_packet.tsc_load) + self.sync += [ + If(self.tsc_loaded.re, self.tsc_loaded.w.eq(0)), + If(ps_tsc_load.o, self.tsc_loaded.w.eq(1)) + ] + self.submodules.outputs = ClockDomainsRenamer("rio")( SED(channels, fine_ts_width, "sync", lane_count=lane_count, fifo_depth=fifo_depth, @@ -112,7 +122,7 @@ class DRTIOSatellite(Module): self.link_layer) def get_csrs(self): - return ([self.reset, self.reset_phy] + + return ([self.reset, self.reset_phy, self.tsc_loaded] + self.link_layer.get_csrs() + self.link_stats.get_csrs() + self.rt_errors.get_csrs() + self.aux_controller.get_csrs()) From 07bcdfd91ed7752c2edb47022c4b62f59720c3b0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Jun 2018 22:26:49 +0800 Subject: [PATCH 0964/2457] hmc7043: stricter check of FPGA SYSREF margin --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index b3b5ece69..3ecea703f 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -374,11 +374,11 @@ pub mod hmc7043 { } info!(" ...done ({}/{} slips), verifying timing margin", slips0, slips1); - let mut margin = None; + let mut margin_plus = None; for d in 0..phase_offset { sysref_offset_fpga(phase_offset - d); if !sysref_sample() { - margin = Some(d); + margin_plus = Some(d); break; } } @@ -386,10 +386,13 @@ pub mod hmc7043 { // meet setup/hold sysref_offset_fpga(phase_offset); - if margin.is_some() { - let margin = margin.unwrap(); - info!(" margin at FPGA: {}", margin); - if margin < 10 { + if margin_plus.is_some() { + let margin_plus = margin_plus.unwrap(); + // one phase slip (period of the 1.2GHz input clock) + let period = 2*17; // approximate: 2 digital coarse delay steps + let margin_minus = if period > margin_plus { period - margin_plus } else { 0 }; + info!(" margin at FPGA: -{} +{}", margin_minus, margin_plus); + if margin_minus < 10 || margin_plus < 10 { error!("SYSREF margin at FPGA is too small"); } } else { From b28ff587c5e17078e5066b1b2778f0f58e41fb61 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Jun 2018 22:28:34 +0800 Subject: [PATCH 0965/2457] sayma: add sysref sampler to DRTIO master --- artiq/gateware/targets/sayma_amc.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 3079de4a3..5c4f270bc 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -309,6 +309,12 @@ class Master(MiniSoC, AMPSoC, RTMCommon): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) + self.submodules.ad9154_crg = jesd204_tools.UltrascaleCRG(platform) + self.csr_devices.append("ad9154_crg") + platform.add_false_path_constraints( + self.crg.cd_sys.clk, + self.ad9154_crg.cd_jesd.clk) + self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") @@ -325,6 +331,10 @@ class Master(MiniSoC, AMPSoC, RTMCommon): [self.rtio_core.cri] + drtio_cri) self.register_kernel_cpu_csrdevice("cri_con") + self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( + self.rtio_core.coarse_ts, self.ad9154_crg.jref) + self.csr_devices.append("sysref_sampler") + class Satellite(BaseSoC, RTMCommon): mem_map = { From de7d64d482dcd51755be93040562896528670b68 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Jun 2018 22:32:41 +0800 Subject: [PATCH 0966/2457] sayma: clock JESD204 from GTP CLK2 This frees up GTP CLK1, which is routable to the SFP quads, for DRTIO. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 2 +- artiq/firmware/runtime/main.rs | 4 ++-- artiq/gateware/jesd204_tools.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 3ecea703f..a2c4a644f 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -171,7 +171,7 @@ pub mod hmc7043 { (true, SYSREF_DIV, 0x08), // 3: DAC1_SYSREF (false, 0, 0x08), // 4: ADC2_CLK (false, 0, 0x08), // 5: ADC2_SYSREF - (false, 0, 0x08), // 6: GTP_CLK2 + (true, FPGA_CLK_DIV, 0x08), // 6: GTP_CLK2 (true, SYSREF_DIV, 0x10), // 7: FPGA_DAC_SYSREF, LVDS (true, FPGA_CLK_DIV, 0x08), // 8: GTP_CLK1 (false, 0, 0x10), // 9: AMC_MASTER_AUX_CLK diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 1e39f9968..cfd420e04 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -57,9 +57,9 @@ mod moninj; mod analyzer; #[cfg(has_ad9154)] -const SYSREF_PHASE_FPGA: u16 = 32; +const SYSREF_PHASE_FPGA: u16 = 20; #[cfg(has_ad9154)] -const SYSREF_PHASE_DAC: u16 = 61; +const SYSREF_PHASE_DAC: u16 = 31; fn startup() { irq::set_mask(0); diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index 33d0ca025..3471073ea 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -26,7 +26,7 @@ class UltrascaleCRG(Module, AutoCSR): self.clock_domains.cd_jesd = ClockDomain() refclk2 = Signal() - refclk_pads = platform.request("dac_refclk", 0) + refclk_pads = platform.request("dac_refclk", 1) platform.add_period_constraint(refclk_pads.p, 1e9/self.refclk_freq) self.specials += [ Instance("IBUFDS_GTE3", i_CEB=self.jreset.storage, p_REFCLK_HROW_CK_SEL=0b00, From 8b3c12e6ebcf3e72f2a54f9cfea76475cdf73c6d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Jun 2018 22:34:44 +0800 Subject: [PATCH 0967/2457] sayma: clock DRTIO master transceiver from HMC7043 --- artiq/gateware/targets/sayma_amc.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 5c4f270bc..c8c33a5c3 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -236,23 +236,12 @@ class Master(MiniSoC, AMPSoC, RTMCommon): platform = self.platform rtio_clk_freq = 150e6 - # Si5324 used as a free-running oscillator, to avoid dependency on RTM. - self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) - self.csr_devices.append("si5324_rst_n") - i2c = self.platform.request("i2c") - self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) - self.csr_devices.append("i2c") - self.config["I2C_BUS_COUNT"] = 1 - self.config["HAS_SI5324"] = None - self.config["SI5324_AS_SYNTHESIZER"] = None - self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - self.comb += [ platform.request("sfp_tx_disable", i).eq(0) for i in range(2) ] self.submodules.drtio_transceiver = gth_ultrascale.GTH( - clock_pads=platform.request("si5324_clkout"), + clock_pads=platform.request("dac_refclk", 0), data_pads=[platform.request("sfp", i) for i in range(2)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) From c1db02a3513fe7f1f359e48f660b7b7deb753738 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Jun 2018 22:56:05 +0800 Subject: [PATCH 0968/2457] drtio/gth_ultrascale: disable IBUFDS_GTE3 until stable_clkin Precaution against HMC7043 noise issues. --- artiq/gateware/drtio/transceiver/gth_ultrascale.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index baad1d557..35969f233 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -637,8 +637,9 @@ class GTH(Module, TransceiverInterface): # # # refclk = Signal() + ibufds_ceb = Signal() self.specials += Instance("IBUFDS_GTE3", - i_CEB=0, + i_CEB=ibufds_ceb, i_I=clock_pads.p, i_IB=clock_pads.n, o_O=refclk) @@ -664,8 +665,10 @@ class GTH(Module, TransceiverInterface): self.submodules.tx_phase_alignment = GTHTXPhaseAlignement(self.gths) TransceiverInterface.__init__(self, channel_interfaces) - # GTH PLLs recover on their own from an interrupted clock input. - # stable_clkin can be ignored. + # GTH PLLs recover on their own from an interrupted clock input, + # but be paranoid about HMC7043 noise. + self.stable_clkin.storage.attr.add("no_retiming") + self.comb += ibufds_ceb.eq(~self.stable_clkin.storage) self.comb += [ self.cd_rtio.clk.eq(self.gths[master].cd_rtio_tx.clk), From 83428961ad3dd74c5aa58859da035630c2fc06cf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Jun 2018 00:04:22 +0800 Subject: [PATCH 0969/2457] sayma: add SAWG and JESD to DRTIO master --- .../sayma_drtio/repository/sines_drtio.py | 2 +- artiq/gateware/targets/sayma_amc.py | 21 +++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/artiq/examples/sayma_drtio/repository/sines_drtio.py b/artiq/examples/sayma_drtio/repository/sines_drtio.py index b7c26bdcb..7d4e2cf35 100644 --- a/artiq/examples/sayma_drtio/repository/sines_drtio.py +++ b/artiq/examples/sayma_drtio/repository/sines_drtio.py @@ -5,7 +5,7 @@ class SAWGTestDRTIO(EnvExperiment): def build(self): self.setattr_device("core") self.setattr_device("ttl_sma_out") - self.sawgs = [self.get_device("sawg"+str(8+i)) for i in range(8)] + self.sawgs = [self.get_device("sawg"+str(i)) for i in range(16)] @kernel def run(self): diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index c8c33a5c3..ce469bacf 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -230,9 +230,6 @@ class Master(MiniSoC, AMPSoC, RTMCommon): RTMCommon.__init__(self) self.config["HMC830_REF"] = "150" - if with_sawg: - warnings.warn("SAWG is not implemented yet, ignoring.") - platform = self.platform rtio_clk_freq = 150e6 @@ -299,10 +296,22 @@ class Master(MiniSoC, AMPSoC, RTMCommon): rtio_channels.append(rtio.Channel.from_phy(phy)) self.submodules.ad9154_crg = jesd204_tools.UltrascaleCRG(platform) + if with_sawg: + cls = AD9154 + else: + cls = AD9154NoSAWG + self.submodules.ad9154_0 = cls(platform, self.crg, self.ad9154_crg, 0) + self.submodules.ad9154_1 = cls(platform, self.crg, self.ad9154_crg, 1) self.csr_devices.append("ad9154_crg") - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - self.ad9154_crg.cd_jesd.clk) + self.csr_devices.append("ad9154_0") + self.csr_devices.append("ad9154_1") + self.config["HAS_AD9154"] = None + self.add_csr_group("ad9154", ["ad9154_0", "ad9154_1"]) + self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels) + rtio_channels.extend(rtio.Channel.from_phy(phy) + for sawg in self.ad9154_0.sawgs + + self.ad9154_1.sawgs + for phy in sawg.phys) self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") From e6d17267546a8a8f97d2a2c1d2c4a2c15f992a67 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Jun 2018 00:05:22 +0800 Subject: [PATCH 0970/2457] sayma: add RTIO log to DRTIO master --- artiq/gateware/targets/sayma_amc.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index ce469bacf..d0bd99450 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -313,6 +313,10 @@ class Master(MiniSoC, AMPSoC, RTMCommon): self.ad9154_1.sawgs for phy in sawg.phys) + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) + rtio_channels.append(rtio.LogChannel()) + self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") From 60b22217ce0e8f594ee642cc25f49071f7088a75 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Jun 2018 10:10:05 +0800 Subject: [PATCH 0971/2457] sayma: set DRTIO master HMC830_REF to 100MHz --- artiq/gateware/targets/sayma_amc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index d0bd99450..165d09c50 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -228,7 +228,7 @@ class Master(MiniSoC, AMPSoC, RTMCommon): **kwargs) AMPSoC.__init__(self) RTMCommon.__init__(self) - self.config["HMC830_REF"] = "150" + self.config["HMC830_REF"] = "100" platform = self.platform rtio_clk_freq = 150e6 From d9955fee769a739ab39c4c29e62e4d3825afbfe6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Jun 2018 11:00:56 +0800 Subject: [PATCH 0972/2457] jesd204: make sure IOB FF is used to sample SYSREF at FPGA --- artiq/gateware/jesd204_tools.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index 3471073ea..e467a87c9 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -42,6 +42,7 @@ class UltrascaleCRG(Module, AutoCSR): jref = platform.request("dac_sysref") jref_se = Signal() + jref_r = Signal() self.specials += [ Instance("IBUFDS_IBUFDISABLE", p_USE_IBUFDISABLE="TRUE", p_SIM_DEVICE="ULTRASCALE", @@ -51,7 +52,9 @@ class UltrascaleCRG(Module, AutoCSR): # SYSREF normally meets s/h at the FPGA, except during margin # scan and before full initialization. # Be paranoid and use a double-register anyway. - MultiReg(jref_se, self.jref, "jesd") + Instance("FD", i_C=ClockSignal("jesd"), i_D=jref_se, o_Q=jref_r, + attr={("IOB", "TRUE")}), + Instance("FD", i_C=ClockSignal("jesd"), i_D=jref_r, o_Q=self.jref) ] From 76fc63bbf77d2b2053201d0f4ca205623b937d63 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Jun 2018 11:38:18 +0800 Subject: [PATCH 0973/2457] jesd204: use separate controls for reset and input buffer disable --- artiq/firmware/libboard_artiq/ad9154.rs | 3 ++- artiq/gateware/jesd204_tools.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index c4086ca02..a1549b601 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -36,7 +36,8 @@ fn read(addr: u16) -> u8 { fn jesd_unreset() { unsafe { - csr::ad9154_crg::jreset_write(0) + csr::ad9154_crg::ibuf_disable_write(0); + csr::ad9154_crg::jreset_write(0); } } diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index e467a87c9..0e35b055e 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -20,6 +20,7 @@ class UltrascaleCRG(Module, AutoCSR): fabric_freq = int(125e6) def __init__(self, platform, use_rtio_clock=False): + self.ibuf_disable = CSRStorage(reset=1) self.jreset = CSRStorage(reset=1) self.jref = Signal() self.refclk = Signal() @@ -29,7 +30,7 @@ class UltrascaleCRG(Module, AutoCSR): refclk_pads = platform.request("dac_refclk", 1) platform.add_period_constraint(refclk_pads.p, 1e9/self.refclk_freq) self.specials += [ - Instance("IBUFDS_GTE3", i_CEB=self.jreset.storage, p_REFCLK_HROW_CK_SEL=0b00, + Instance("IBUFDS_GTE3", i_CEB=self.ibuf_disable.storage, p_REFCLK_HROW_CK_SEL=0b00, i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=self.refclk, o_ODIV2=refclk2), AsyncResetSynchronizer(self.cd_jesd, self.jreset.storage), @@ -46,7 +47,7 @@ class UltrascaleCRG(Module, AutoCSR): self.specials += [ Instance("IBUFDS_IBUFDISABLE", p_USE_IBUFDISABLE="TRUE", p_SIM_DEVICE="ULTRASCALE", - i_IBUFDISABLE=self.jreset.storage, + i_IBUFDISABLE=self.ibuf_disable.storage, i_I=jref.p, i_IB=jref.n, o_O=jref_se), # SYSREF normally meets s/h at the FPGA, except during margin From f87da95e57d253ff5b6f46c1fc636aaca2d30898 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Jun 2018 17:12:59 +0800 Subject: [PATCH 0974/2457] jesd204: use jesd clock domain for sysref sampler RTIO domain is still in reset during calibration. --- artiq/gateware/jesd204_tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index 0e35b055e..8187e4999 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -108,5 +108,5 @@ class SysrefSampler(Module, AutoCSR): self.sample_result = CSRStatus() sample = Signal() - self.sync.rtio += If(coarse_ts[:4] == 0, sample.eq(jref)) + self.sync.jesd += If(coarse_ts[:4] == 0, sample.eq(jref)) self.specials += MultiReg(sample, self.sample_result.status) From 51a5d8dff9670d0ff8ef43abc19fbdd73644fc8c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Jun 2018 18:57:49 +0800 Subject: [PATCH 0975/2457] examples: add Kasli SAWG master --- artiq/examples/kasli_sawgmaster/device_db.py | 42 +++++++++++++++++++ .../repository/sines_drtio.py | 27 ++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 artiq/examples/kasli_sawgmaster/device_db.py create mode 100644 artiq/examples/kasli_sawgmaster/repository/sines_drtio.py diff --git a/artiq/examples/kasli_sawgmaster/device_db.py b/artiq/examples/kasli_sawgmaster/device_db.py new file mode 100644 index 000000000..91ed71102 --- /dev/null +++ b/artiq/examples/kasli_sawgmaster/device_db.py @@ -0,0 +1,42 @@ +core_addr = "kasli-1.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1/(8*150e6)} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, +} + +for i in range(8): + device_db["sawg" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.sawg", + "class": "SAWG", + "arguments": {"channel_base": i*10+0x010006, "parallelism": 4} + } + +for i in range(8): + device_db["sawg" + str(8+i)] = { + "type": "local", + "module": "artiq.coredevice.sawg", + "class": "SAWG", + "arguments": {"channel_base": i*10+0x020006, "parallelism": 4} + } diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_drtio.py b/artiq/examples/kasli_sawgmaster/repository/sines_drtio.py new file mode 100644 index 000000000..f2d030f8e --- /dev/null +++ b/artiq/examples/kasli_sawgmaster/repository/sines_drtio.py @@ -0,0 +1,27 @@ +from artiq.experiment import * + + +class SAWGTestDRTIO(EnvExperiment): + def build(self): + self.setattr_device("core") + self.sawgs = [self.get_device("sawg"+str(i)) for i in range(16)] + + @kernel + def run(self): + while True: + print("waiting for DRTIO ready...") + while not (self.core.get_drtio_link_status(0) and + self.core.get_drtio_link_status(1)): + pass + print("OK") + + self.core.reset() + + for sawg in self.sawgs: + delay(1*ms) + sawg.amplitude1.set(.4) + # Do not use a sub-multiple of oscilloscope sample rates. + sawg.frequency0.set(9*MHz) + + while self.core.get_drtio_link_status(0) and self.core.get_drtio_link_status(1): + pass From 12fde6d34ba4c3401df0532ebaa2f3c5504f173a Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 23 Jun 2018 00:36:50 +0000 Subject: [PATCH 0976/2457] artiq_coremgmt: fix typo. Fixes #1056. --- artiq/coredevice/comm_mgmt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/comm_mgmt.py b/artiq/coredevice/comm_mgmt.py index 6d8438495..5b078b8da 100644 --- a/artiq/coredevice/comm_mgmt.py +++ b/artiq/coredevice/comm_mgmt.py @@ -181,7 +181,7 @@ class CommMgmt: self._read_expect(Reply.Success) def config_erase(self): - self._write_empty(Request.ConfigErase) + self._write_header(Request.ConfigErase) self._read_expect(Reply.Success) def start_profiler(self, interval, edges_size, hits_size): From b6dd9c8bb054945ba38cbb64294cad914bb71682 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 23 Jun 2018 00:56:21 +0000 Subject: [PATCH 0977/2457] runtime: support builds without RTIO DMA. Fixes #1079. --- artiq/firmware/ksupport/lib.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index c3e05c138..73360ce05 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -17,7 +17,6 @@ use core::{mem, ptr, slice, str}; use cslice::{CSlice, AsCSlice}; use io::Cursor; use dyld::Library; -use board_misoc::csr; use board_artiq::{mailbox, rpc_queue}; use proto_artiq::{kernel_proto, rpc_proto}; use kernel_proto::*; @@ -365,11 +364,13 @@ extern fn dma_retrieve(name: CSlice) -> DmaTrace { }) } -#[cfg(has_rtio)] +#[cfg(has_rtio_dma)] extern fn dma_playback(timestamp: i64, ptr: i32) { assert!(ptr % 64 == 0); unsafe { + use board_misoc::csr; + csr::rtio_dma::base_address_write(ptr as u64); csr::rtio_dma::time_offset_write(timestamp as u64); @@ -397,9 +398,9 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { } } -#[cfg(not(has_rtio))] -extern fn dma_playback(timestamp: i64, ptr: i32) { - unimplemented!("not(has_rtio)") +#[cfg(not(has_rtio_dma))] +extern fn dma_playback(_timestamp: i64, _ptr: i32) { + unimplemented!("not(has_rtio_dma)") } unsafe fn attribute_writeback(typeinfo: *const ()) { From 68530fde07aee7f96bf779210f0d7a0d600a89be Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 23 Jun 2018 10:35:25 +0800 Subject: [PATCH 0978/2457] sayma: generate 100MHz from Si5324 on standalone and master targets * Allow switching between DRTIO satellite and standalone without touching the hardware. * Allow operating standalone and master without an additional RF signal generator. --- artiq/firmware/runtime/main.rs | 19 ++++++++++++++++--- artiq/gateware/targets/sayma_amc.py | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index cfd420e04..a0af6667f 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -131,7 +131,7 @@ fn startup() { fn setup_si5324_as_synthesizer() { // 125MHz output, from 100MHz CLKIN2 reference, 586 Hz - #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref))] + #[cfg(all(not(si5324_sayma_ref), rtio_frequency = "125.0", si5324_ext_ref))] const SI5324_SETTINGS: board_artiq::si5324::FrequencySettings = board_artiq::si5324::FrequencySettings { n1_hs : 10, @@ -144,7 +144,7 @@ fn setup_si5324_as_synthesizer() crystal_ref: false }; // 125MHz output, from crystal, 7 Hz - #[cfg(all(rtio_frequency = "125.0", not(si5324_ext_ref)))] + #[cfg(all(not(si5324_sayma_ref), rtio_frequency = "125.0", not(si5324_ext_ref)))] const SI5324_SETTINGS: board_artiq::si5324::FrequencySettings = board_artiq::si5324::FrequencySettings { n1_hs : 10, @@ -157,7 +157,7 @@ fn setup_si5324_as_synthesizer() crystal_ref: true }; // 150MHz output, from crystal - #[cfg(all(rtio_frequency = "150.0", not(si5324_ext_ref)))] + #[cfg(all(not(si5324_sayma_ref), rtio_frequency = "150.0", not(si5324_ext_ref)))] const SI5324_SETTINGS: board_artiq::si5324::FrequencySettings = board_artiq::si5324::FrequencySettings { n1_hs : 9, @@ -169,6 +169,19 @@ fn setup_si5324_as_synthesizer() bwsel : 3, crystal_ref: true }; + // 100MHz output, from crystal (reference for HMC830) + #[cfg(si5324_sayma_ref)] + const SI5324_SETTINGS: board_artiq::si5324::FrequencySettings + = board_artiq::si5324::FrequencySettings { + n1_hs : 9, + nc1_ls : 6, + n2_hs : 10, + n2_ls : 33732, + n31 : 9370, + n32 : 7139, + bwsel : 3, + crystal_ref: true + }; board_artiq::si5324::setup(&SI5324_SETTINGS, board_artiq::si5324::Input::Ckin2).expect("cannot initialize Si5324"); } diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 165d09c50..abb614977 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -139,6 +139,16 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): platform = self.platform + self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) + self.csr_devices.append("si5324_rst_n") + i2c = self.platform.request("i2c") + self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) + self.csr_devices.append("i2c") + self.config["I2C_BUS_COUNT"] = 1 + self.config["HAS_SI5324"] = None + self.config["SI5324_AS_SYNTHESIZER"] = None + self.config["SI5324_SAYMA_REF"] = None + # RTIO rtio_channels = [] for i in range(4): @@ -233,6 +243,16 @@ class Master(MiniSoC, AMPSoC, RTMCommon): platform = self.platform rtio_clk_freq = 150e6 + self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) + self.csr_devices.append("si5324_rst_n") + i2c = self.platform.request("i2c") + self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) + self.csr_devices.append("i2c") + self.config["I2C_BUS_COUNT"] = 1 + self.config["HAS_SI5324"] = None + self.config["SI5324_AS_SYNTHESIZER"] = None + self.config["SI5324_SAYMA_REF"] = None + self.comb += [ platform.request("sfp_tx_disable", i).eq(0) for i in range(2) From 84b3d9ecc604e3fd30c3b2095b6f336eef3d11c2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 23 Jun 2018 11:28:12 +0800 Subject: [PATCH 0979/2457] bootloader: also check firmware CRC in SDRAM (#1065) --- artiq/firmware/bootloader/main.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 4498140b4..e5515fb20 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -129,17 +129,23 @@ fn flash_boot() { } let firmware_in_flash = unsafe { slice::from_raw_parts(FIRMWARE.offset(8), length) }; - let actual_crc = crc32::checksum_ieee(firmware_in_flash); + let actual_crc_flash = crc32::checksum_ieee(firmware_in_flash); - if actual_crc == expected_crc { + if actual_crc_flash == expected_crc { let firmware_in_sdram = unsafe { slice::from_raw_parts_mut(MAIN_RAM, length) }; firmware_in_sdram.copy_from_slice(firmware_in_flash); - println!("Starting firmware."); - unsafe { boot::jump(MAIN_RAM as usize) } + let actual_crc_sdram = crc32::checksum_ieee(firmware_in_sdram); + if actual_crc_sdram == expected_crc { + println!("Starting firmware."); + unsafe { boot::jump(MAIN_RAM as usize) } + } else { + println!("Firmware CRC failed in SDRAM (actual {:08x}, expected {:08x})", + actual_crc_sdram, expected_crc); + } } else { - println!("Firmware CRC failed (actual {:08x}, expected {:08x})", - actual_crc, expected_crc); + println!("Firmware CRC failed in flash (actual {:08x}, expected {:08x})", + actual_crc_flash, expected_crc); } } From c750de2955430b7abb146831d512a098db466dd1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 25 Jun 2018 18:21:22 +0800 Subject: [PATCH 0980/2457] sayma: add many-port pure DRTIO master --- artiq/gateware/targets/sayma_amc.py | 161 +++++++++++++++++++++++++--- conda/artiq-dev/meta.yaml | 2 +- 2 files changed, 150 insertions(+), 13 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index abb614977..35eaa5099 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -115,6 +115,9 @@ class RTMCommon: class Standalone(MiniSoC, AMPSoC, RTMCommon): + """ + Local DAC/SAWG channels only. + """ mem_map = { "cri_con": 0x10000000, "rtio": 0x11000000, @@ -216,7 +219,10 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): self.csr_devices.append("sysref_sampler") -class Master(MiniSoC, AMPSoC, RTMCommon): +class MasterDAC(MiniSoC, AMPSoC, RTMCommon): + """ + DRTIO master with local DAC/SAWG channels. + """ mem_map = { "cri_con": 0x10000000, "rtio": 0x11000000, @@ -358,7 +364,135 @@ class Master(MiniSoC, AMPSoC, RTMCommon): self.csr_devices.append("sysref_sampler") +class Master(MiniSoC, AMPSoC): + """ + DRTIO master with 2 SFP ports plus 8 lanes on RTM. + Use passive RTM adapter to connect to satellites. + Due to GTH clock routing restrictions, it is not possible + to use more RTM lanes without additional hardware. + """ + mem_map = { + "cri_con": 0x10000000, + "rtio": 0x11000000, + "rtio_dma": 0x12000000, + "drtio_aux": 0x14000000, + "mailbox": 0x70000000 + } + mem_map.update(MiniSoC.mem_map) + + def __init__(self, with_sawg, **kwargs): + MiniSoC.__init__(self, + cpu_type="or1k", + sdram_controller_type="minicon", + l2_size=128*1024, + ident=artiq_version, + ethmac_nrxslots=4, + ethmac_ntxslots=4, + **kwargs) + AMPSoC.__init__(self) + + platform = self.platform + rtio_clk_freq = 150e6 + + self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) + self.csr_devices.append("si5324_rst_n") + i2c = self.platform.request("i2c") + self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) + self.csr_devices.append("i2c") + self.config["I2C_BUS_COUNT"] = 1 + self.config["HAS_SI5324"] = None + self.config["SI5324_AS_SYNTHESIZER"] = None + self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) + + self.comb += [ + platform.request("sfp_tx_disable", i).eq(0) + for i in range(2) + ] + self.submodules.drtio_transceiver = gth_ultrascale.GTH( + clock_pads=platform.request("si5324_clkout", 0), + data_pads=[platform.request("sfp", i) for i in range(2)] + + [platform.request("rtm_gth", i) for i in range(8)], + sys_clk_freq=self.clk_freq, + rtio_clk_freq=rtio_clk_freq) + self.csr_devices.append("drtio_transceiver") + + drtio_csr_group = [] + drtio_memory_group = [] + drtio_cri = [] + for i in range(10): + core_name = "drtio" + str(i) + memory_name = "drtio" + str(i) + "_aux" + drtio_csr_group.append(core_name) + drtio_memory_group.append(memory_name) + + core = ClockDomainsRenamer({"rtio_rx": "rtio_rx"+str(i)})( + DRTIOMaster(self.drtio_transceiver.channels[i])) + setattr(self.submodules, core_name, core) + drtio_cri.append(core.cri) + self.csr_devices.append(core_name) + + memory_address = self.mem_map["drtio_aux"] + 0x800*i + self.add_wb_slave(memory_address, 0x800, + core.aux_controller.bus) + self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) + self.config["HAS_DRTIO"] = None + self.add_csr_group("drtio", drtio_csr_group) + self.add_memory_group("drtio_aux", drtio_memory_group) + + rtio_clk_period = 1e9/rtio_clk_freq + gth = self.drtio_transceiver.gths[0] + platform.add_period_constraint(gth.txoutclk, rtio_clk_period) + platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, + gth.txoutclk, gth.rxoutclk) + for gth in self.drtio_transceiver.gths[1:]: + platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, gth.rxoutclk) + + rtio_channels = [] + for i in range(4): + phy = ttl_simple.Output(platform.request("user_led", i)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + sma_io = platform.request("sma_io", 0) + self.comb += sma_io.direction.eq(1) + phy = ttl_simple.Output(sma_io.level) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + sma_io = platform.request("sma_io", 1) + self.comb += sma_io.direction.eq(0) + phy = ttl_simple.InOut(sma_io.level) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) + rtio_channels.append(rtio.LogChannel()) + + self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) + self.csr_devices.append("rtio_moninj") + + self.submodules.rtio_core = rtio.Core(rtio_channels, glbl_fine_ts_width=3) + self.csr_devices.append("rtio_core") + + self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( + rtio.DMA(self.get_native_sdram_if())) + self.register_kernel_cpu_csrdevice("rtio") + self.register_kernel_cpu_csrdevice("rtio_dma") + self.submodules.cri_con = rtio.CRIInterconnectShared( + [self.rtio.cri, self.rtio_dma.cri], + [self.rtio_core.cri] + drtio_cri) + self.register_kernel_cpu_csrdevice("cri_con") + + class Satellite(BaseSoC, RTMCommon): + """ + DRTIO satellite with local DAC/SAWG channels. + Use SFP0 to connect to master (Kasli/Sayma). + """ mem_map = { "serwb": 0x13000000, "drtio_aux": 0x14000000, @@ -474,7 +608,7 @@ def main(): parser.set_defaults(output_dir="artiq_sayma") parser.add_argument("-V", "--variant", default="standalone", help="variant: " - "standalone/master/satellite " + "standalone/masterdac/master/satellite " "(default: %(default)s)") parser.add_argument("--rtm-csr-csv", default=os.path.join("artiq_sayma", "rtm_gateware", "rtm_csr.csv"), @@ -488,6 +622,8 @@ def main(): variant = args.variant.lower() if variant == "standalone": cls = Standalone + elif variant == "masterdac": + cls = MasterDAC elif variant == "master": cls = Master elif variant == "satellite": @@ -496,16 +632,17 @@ def main(): raise SystemExit("Invalid variant (-V/--variant)") soc = cls(with_sawg=not args.without_sawg, **soc_sdram_argdict(args)) - remote_csr_regions = remote_csr.get_remote_csr_regions( - soc.mem_map["serwb"] | soc.shadow_base, - args.rtm_csr_csv) - for name, origin, busword, csrs in remote_csr_regions: - soc.add_csr_region(name, origin, busword, csrs) - # Configuration for RTM peripherals. Keep in sync with sayma_rtm.py! - soc.config["HAS_HMC830_7043"] = None - soc.config["CONVERTER_SPI_HMC830_CS"] = 0 - soc.config["CONVERTER_SPI_HMC7043_CS"] = 1 - soc.config["CONVERTER_SPI_FIRST_AD9154_CS"] = 2 + if variant != "master": + remote_csr_regions = remote_csr.get_remote_csr_regions( + soc.mem_map["serwb"] | soc.shadow_base, + args.rtm_csr_csv) + for name, origin, busword, csrs in remote_csr_regions: + soc.add_csr_region(name, origin, busword, csrs) + # Configuration for RTM peripherals. Keep in sync with sayma_rtm.py! + soc.config["HAS_HMC830_7043"] = None + soc.config["CONVERTER_SPI_HMC830_CS"] = 0 + soc.config["CONVERTER_SPI_HMC7043_CS"] = 1 + soc.config["CONVERTER_SPI_FIRST_AD9154_CS"] = 2 build_artiq_soc(soc, builder_argdict(args)) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index ca645ea41..a53b96a96 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_51+git9929b23 + - migen 0.7 py35_66+gitdcfec40 - misoc 0.11 py35_20+git2436a68d - jesd204b 0.7 - microscope From 811882943beb8f097da06d0504cca67afd26a113 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 25 Jun 2018 18:28:55 +0800 Subject: [PATCH 0981/2457] artiq_flash: RTM gateware is not required for master variant --- artiq/frontend/artiq_flash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 813cd7846..5fca7702a 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -332,7 +332,7 @@ def main(): gateware_bin = convert_gateware( artifact_path(variant, "gateware", "top.bit")) programmer.write_binary(*config["gateware"], gateware_bin) - if args.target == "sayma": + if args.target == "sayma" and args.variant != "master": rtm_gateware_bin = convert_gateware( artifact_path("rtm_gateware", "rtm.bit"), header=True) programmer.write_binary(*config["rtm_gateware"], From 5e5cdf0e6703a71813e2581977d7a7ce40d1c061 Mon Sep 17 00:00:00 2001 From: apatura-iris <40609843+apatura-iris@users.noreply.github.com> Date: Tue, 26 Jun 2018 12:55:39 -0600 Subject: [PATCH 0982/2457] Update installing.rst The file 99-openocd.rules as downloaded from githubusercontent.com seems to be outdated and does now work on Ubuntu 16.04. The version that ships with OpenOCD has an additional ``TAG+="uaccess"`` in the rules file and works fine. Thus I suggest to use the file that is bundled with OpenOCD. --- doc/manual/installing.rst | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 7b726e2ec..f2f666a84 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -117,11 +117,14 @@ Configuring OpenOCD Some additional steps are necessary to ensure that OpenOCD can communicate with the FPGA board. -On Linux, first ensure that the current user belongs to the ``plugdev`` group. If it does not, run ``sudo adduser $USER plugdev`` and relogin. Afterwards:: +On Linux, first ensure that the current user belongs to the ``plugdev`` group. If it does not, run ``sudo adduser $USER plugdev`` and relogin. Afterwards if you installed OpenOCD using conda:: - $ wget https://raw.githubusercontent.com/ntfreak/openocd/406f4d1c68330e3bf8d9db4e402fd8802a5c79e2/contrib/99-openocd.rules - $ sudo cp 99-openocd.rules /etc/udev/rules.d - $ sudo adduser $USER plugdev + $ sudo cp ~/.conda/envs/artiq-main/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d + $ sudo udevadm trigger + +if you installed it from source:: Assuming you installed OpenOCD in ``/usr/local``, otherwise please substitute the install directory:: + + $ sudo cp /usr/local/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d $ sudo udevadm trigger On Windows, a third-party tool, `Zadig `_, is necessary. Use it as follows: From e9a1e10221cb6978cb6bae3030c3a886f6286451 Mon Sep 17 00:00:00 2001 From: apatura-iris <40609843+apatura-iris@users.noreply.github.com> Date: Tue, 26 Jun 2018 21:41:04 -0600 Subject: [PATCH 0983/2457] Update installing.rst Added comment to clarify that ``artiq-main`` is the conda environment. --- doc/manual/installing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index f2f666a84..098d0b7d0 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -117,7 +117,7 @@ Configuring OpenOCD Some additional steps are necessary to ensure that OpenOCD can communicate with the FPGA board. -On Linux, first ensure that the current user belongs to the ``plugdev`` group. If it does not, run ``sudo adduser $USER plugdev`` and relogin. Afterwards if you installed OpenOCD using conda:: +On Linux, first ensure that the current user belongs to the ``plugdev`` group. If it does not, run ``sudo adduser $USER plugdev`` and relogin. If you installed OpenOCD using conda and are using the conda environment ``artiq-main``, then execute the statements below. If you are using a different environment, you will have to replace ``artiq-main`` with the name of your environment:: $ sudo cp ~/.conda/envs/artiq-main/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d $ sudo udevadm trigger From a8a2ad68d3799f0ac57e23eb95d39afa5322cbf1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 27 Jun 2018 17:31:29 +0800 Subject: [PATCH 0984/2457] runtime: tune Sayma SYSREF phases --- artiq/firmware/runtime/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index a0af6667f..2f119515a 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -57,9 +57,9 @@ mod moninj; mod analyzer; #[cfg(has_ad9154)] -const SYSREF_PHASE_FPGA: u16 = 20; +const SYSREF_PHASE_FPGA: u16 = 35; #[cfg(has_ad9154)] -const SYSREF_PHASE_DAC: u16 = 31; +const SYSREF_PHASE_DAC: u16 = 64; fn startup() { irq::set_mask(0); From 4bbdd43bdfd68c272750cd9d4e507ba75369ff15 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 27 Jun 2018 17:32:56 +0800 Subject: [PATCH 0985/2457] hmc7043: do not freeze if SYSREF slip fails --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index a2c4a644f..1446d9cbb 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -366,11 +366,19 @@ pub mod hmc7043 { while sysref_sample() { sysref_slip(); slips0 += 1; + if slips0 > 1024 { + error!(" failed to reach 1->0 transition"); + break; + } } // get to the edge of the 0->1 transition (our final setpoint) while !sysref_sample() { sysref_slip(); slips1 += 1; + if slips1 > 1024 { + error!(" failed to reach 0->1 transition"); + break; + } } info!(" ...done ({}/{} slips), verifying timing margin", slips0, slips1); From 7dfd70c5022980a19872109a5fe2632d3e8f7525 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 27 Jun 2018 17:35:26 +0800 Subject: [PATCH 0986/2457] hmc7043: make margin_{minus,plus} consistent with ad9154 --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 1446d9cbb..e41ae9361 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -382,24 +382,23 @@ pub mod hmc7043 { } info!(" ...done ({}/{} slips), verifying timing margin", slips0, slips1); - let mut margin_plus = None; + let mut margin_minus = None; for d in 0..phase_offset { sysref_offset_fpga(phase_offset - d); if !sysref_sample() { - margin_plus = Some(d); + margin_minus = Some(d); break; } } - // meet setup/hold sysref_offset_fpga(phase_offset); - if margin_plus.is_some() { - let margin_plus = margin_plus.unwrap(); + if margin_minus.is_some() { + let margin_minus = margin_minus.unwrap(); // one phase slip (period of the 1.2GHz input clock) let period = 2*17; // approximate: 2 digital coarse delay steps - let margin_minus = if period > margin_plus { period - margin_plus } else { 0 }; - info!(" margin at FPGA: -{} +{}", margin_minus, margin_plus); + let margin_plus = if period > margin_minus { period - margin_minus } else { 0 }; + info!(" margins at FPGA: -{} +{}", margin_minus, margin_plus); if margin_minus < 10 || margin_plus < 10 { error!("SYSREF margin at FPGA is too small"); } From 46c044099c9d7caf7f2886c828e6d5d5055c7984 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 27 Jun 2018 17:36:13 +0800 Subject: [PATCH 0987/2457] hmc7043,satman: verify alignment of SYSREF slips --- artiq/firmware/libboard_artiq/ad9154.rs | 2 +- artiq/firmware/libboard_artiq/hmc830_7043.rs | 17 ++++++++++------- artiq/firmware/satman/main.rs | 5 ++++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index a1549b601..4b0e11be1 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -769,7 +769,7 @@ pub fn init(sysref_phase_fpga: u16, sysref_phase_dac: u16) { // the HMC7043 input clock (which defines slip resolution) // is 2x the DAC clock, so there are two possible phases from // the divider states. This deterministically selects one. - hmc7043::sysref_rtio_align(sysref_phase_fpga); + hmc7043::sysref_rtio_align(sysref_phase_fpga, 1); for dacno in 0..csr::AD9154.len() { // We assume DCLK and SYSREF traces are matched on the PCB diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index e41ae9361..1dba30034 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -158,13 +158,13 @@ pub mod hmc7043 { use board_misoc::{csr, clock}; // All frequencies assume 1.2GHz HMC830 output - const DAC_CLK_DIV: u32 = 2; // 600MHz - const FPGA_CLK_DIV: u32 = 8; // 150MHz - const SYSREF_DIV: u32 = 128; // 9.375MHz - const HMC_SYSREF_DIV: u32 = SYSREF_DIV*8; // 1.171875MHz (must be <= 4MHz) + pub const DAC_CLK_DIV: u16 = 2; // 600MHz + pub const FPGA_CLK_DIV: u16 = 8; // 150MHz + pub const SYSREF_DIV: u16 = 128; // 9.375MHz + pub const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // 1.171875MHz (must be <= 4MHz) // enabled, divider, output config - const OUTPUT_CONFIG: [(bool, u32, u8); 14] = [ + const OUTPUT_CONFIG: [(bool, u16, u8); 14] = [ (true, DAC_CLK_DIV, 0x08), // 0: DAC2_CLK (true, SYSREF_DIV, 0x08), // 1: DAC2_SYSREF (true, DAC_CLK_DIV, 0x08), // 2: DAC1_CLK @@ -355,7 +355,7 @@ pub mod hmc7043 { unsafe { csr::sysref_sampler::sample_result_read() == 1 } } - pub fn sysref_rtio_align(phase_offset: u16) { + pub fn sysref_rtio_align(phase_offset: u16, expected_align: u16) { info!("aligning SYSREF with RTIO..."); let mut slips0 = 0; @@ -380,7 +380,10 @@ pub mod hmc7043 { break; } } - info!(" ...done ({}/{} slips), verifying timing margin", slips0, slips1); + info!(" ...done ({}/{} slips)", slips0, slips1); + if (slips0 + slips1) % expected_align != 0 { + error!(" unexpected slip alignment"); + } let mut margin_minus = None; for d in 0..phase_offset { diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 4e3a1a4c5..4ce7b2963 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -298,7 +298,10 @@ pub extern fn main() -> i32 { #[cfg(has_hmc830_7043)] { if drtio_tsc_loaded() { - hmc830_7043::hmc7043::sysref_rtio_align(SYSREF_PHASE_FPGA); + // Expected alignment: 1 RTIO clock period + hmc830_7043::hmc7043::sysref_rtio_align( + SYSREF_PHASE_FPGA, + hmc830_7043::hmc7043::FPGA_CLK_DIV); } } } From d49716dfacedb9fd0ac0d10a8e4494fedc511c88 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 27 Jun 2018 18:09:35 +0800 Subject: [PATCH 0988/2457] satman: tune Sayma SYSREF phases --- artiq/firmware/satman/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 4ce7b2963..e5b527312 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -250,9 +250,9 @@ fn drtio_link_rx_up() -> bool { const SIPHASER_PHASE: u16 = 32; #[cfg(has_ad9154)] -const SYSREF_PHASE_FPGA: u16 = 32; +const SYSREF_PHASE_FPGA: u16 = 53; #[cfg(has_ad9154)] -const SYSREF_PHASE_DAC: u16 = 61; +const SYSREF_PHASE_DAC: u16 = 64; #[no_mangle] pub extern fn main() -> i32 { From a65721d6497a8c604e6d2e766093aaf708cb21ac Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 27 Jun 2018 21:46:55 +0800 Subject: [PATCH 0989/2457] sayma: put RTM clock tree into the siphaser loop * Fixes one bug where siphaser was one Si5324 output and the rest of the system was clocked by the other. With the Si5324 settings we have, skew between the outputs is not controlled. * Puts the coaxial cable between AMC and RTM into the siphaser loop. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 2 +- artiq/firmware/satman/main.rs | 9 ++++++++- artiq/gateware/targets/sayma_amc.py | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 1dba30034..6c52df3ee 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -176,7 +176,7 @@ pub mod hmc7043 { (true, FPGA_CLK_DIV, 0x08), // 8: GTP_CLK1 (false, 0, 0x10), // 9: AMC_MASTER_AUX_CLK (false, 0, 0x10), // 10: RTM_MASTER_AUX_CLK - (false, 0, 0x10), // 11: FPGA_ADC_SYSREF, LVDS + (true, FPGA_CLK_DIV, 0x10), // 11: FPGA_ADC_SYSREF, LVDS -- repurposed for siphaser (false, 0, 0x08), // 12: ADC1_CLK (false, 0, 0x08), // 13: ADC1_SYSREF ]; diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index e5b527312..7afa21337 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -278,7 +278,7 @@ pub extern fn main() -> i32 { /* must be the first SPI init because of HMC830 SPI mode selection */ hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] - board_artiq::ad9154::init(SYSREF_PHASE_FPGA, SYSREF_PHASE_DAC); + let mut ad9154_initialized = false; #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); @@ -289,6 +289,13 @@ pub extern fn main() -> i32 { info!("link is up, switching to recovered clock"); si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); si5324::siphaser::calibrate_skew(SIPHASER_PHASE).expect("failed to calibrate skew"); + #[cfg(has_ad9154)] + { + if !ad9154_initialized { + board_artiq::ad9154::init(SYSREF_PHASE_FPGA, SYSREF_PHASE_DAC); + ad9154_initialized = true; + } + } drtioaux::reset(0); drtio_reset(false); drtio_reset_phy(false); diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 35eaa5099..7090805ba 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -573,7 +573,7 @@ class Satellite(BaseSoC, RTMCommon): self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), - si5324_clkout_fabric=platform.request("si5324_clkout_fabric")) + si5324_clkout_fabric=platform.request("adc_sysref")) platform.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets {mmcm_ps}]", mmcm_ps=self.siphaser.mmcm_ps_output) platform.add_false_path_constraints( From 729ce58f9818bc0f21d545445dd435a18c38fd33 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Jun 2018 11:23:40 +0800 Subject: [PATCH 0990/2457] sayma: use GTP_CLK1 to clock DRTIO satellite transceiver This is required to get constant skew between the DRTIO transceiver clock (which then generates the RTIO clock) and the siphaser reference clock. Both the Si5324 and the RTM clock tree have non-deterministic in-to-out skew at 150MHz due to dividers. --- artiq/firmware/satman/main.rs | 6 +++--- artiq/gateware/targets/sayma_amc.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 7afa21337..faac96946 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -270,13 +270,13 @@ pub extern fn main() -> i32 { i2c::init(); si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324"); + #[cfg(has_hmc830_7043)] + /* must be the first SPI init because of HMC830 SPI mode selection */ + hmc830_7043::init().expect("cannot initialize HMC830/7043"); unsafe { csr::drtio_transceiver::stable_clkin_write(1); } - #[cfg(has_hmc830_7043)] - /* must be the first SPI init because of HMC830 SPI mode selection */ - hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] let mut ad9154_initialized = false; #[cfg(has_allaki_atts)] diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 7090805ba..e9fcf3fd5 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -552,7 +552,7 @@ class Satellite(BaseSoC, RTMCommon): self.comb += platform.request("sfp_tx_disable", 0).eq(0) self.submodules.drtio_transceiver = gth_ultrascale.GTH( - clock_pads=platform.request("si5324_clkout"), + clock_pads=platform.request("dac_refclk", 0), data_pads=[platform.request("sfp", 0)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) From 04d6ff45c8bbb1725a7cd7d83bfa4c67e08eea0f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Jun 2018 17:01:48 +0800 Subject: [PATCH 0991/2457] kasli_sawgmaster: reset SAWGs Most importantly this resets the phase accumulators. --- artiq/examples/kasli_sawgmaster/repository/sines_drtio.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_drtio.py b/artiq/examples/kasli_sawgmaster/repository/sines_drtio.py index f2d030f8e..683a83523 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_drtio.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_drtio.py @@ -17,6 +17,10 @@ class SAWGTestDRTIO(EnvExperiment): self.core.reset() + for sawg in self.sawgs: + delay(1*ms) + sawg.reset() + for sawg in self.sawgs: delay(1*ms) sawg.amplitude1.set(.4) From 0483b8d14cbaa4b53d6f5f830b964445b3cb185d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Jun 2018 17:03:32 +0800 Subject: [PATCH 0992/2457] sayma_drtio: ditto --- artiq/examples/sayma_drtio/repository/sines_drtio.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/examples/sayma_drtio/repository/sines_drtio.py b/artiq/examples/sayma_drtio/repository/sines_drtio.py index 7d4e2cf35..7f242e4b8 100644 --- a/artiq/examples/sayma_drtio/repository/sines_drtio.py +++ b/artiq/examples/sayma_drtio/repository/sines_drtio.py @@ -16,6 +16,10 @@ class SAWGTestDRTIO(EnvExperiment): self.core.reset() + for sawg in self.sawgs: + delay(1*ms) + sawg.reset() + for sawg in self.sawgs: delay(1*ms) sawg.amplitude1.set(.4) From 540bdae99ce74676a25004b7ed2ffb223b49125f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 1 Jul 2018 09:28:51 +0800 Subject: [PATCH 0993/2457] grabber: enable DIFF_TERM on inputs --- artiq/gateware/eem.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 5b5180239..1f02382a1 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -360,7 +360,7 @@ class Grabber(_EEM): Subsignal("clk_n", Pins(_eem_pin(eem, 0, "n"))), Subsignal("sdi_p", Pins(*[_eem_pin(eem, i, "p") for i in range(1, 5)])), Subsignal("sdi_n", Pins(*[_eem_pin(eem, i, "n") for i in range(1, 5)])), - IOStandard("LVDS_25") + IOStandard("LVDS_25"), Misc("DIFF_TERM=TRUE") ), ("grabber{}_cc0".format(eem), 0, Subsignal("p", Pins(_eem_pin(eem_aux, 5, "p"))), @@ -385,12 +385,12 @@ class Grabber(_EEM): Subsignal("clk_n", Pins(_eem_pin(eem_aux, 0, "n"))), Subsignal("sdi_p", Pins(*[_eem_pin(eem_aux, i, "p") for i in range(1, 5)])), Subsignal("sdi_n", Pins(*[_eem_pin(eem_aux, i, "n") for i in range(1, 5)])), - IOStandard("LVDS_25") + IOStandard("LVDS_25"), Misc("DIFF_TERM=TRUE") ), ("grabber{}_serrx".format(eem), 0, Subsignal("p", Pins(_eem_pin(eem_aux, 5, "p"))), Subsignal("n", Pins(_eem_pin(eem_aux, 5, "n"))), - IOStandard("LVDS_25") + IOStandard("LVDS_25"), Misc("DIFF_TERM=TRUE") ), ("grabber{}_sertx".format(eem), 0, Subsignal("p", Pins(_eem_pin(eem_aux, 6, "p"))), From 16b917be5d2d4052c9a655a1591b83497e05c212 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 2 Jul 2018 16:23:12 +0800 Subject: [PATCH 0994/2457] doc: add reminder of what positive slack means. Closes #1084 --- doc/manual/rtio.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/rtio.rst b/doc/manual/rtio.rst index 1abdd25a3..2d093b755 100644 --- a/doc/manual/rtio.rst +++ b/doc/manual/rtio.rst @@ -166,7 +166,7 @@ If more than 20 rising edges were received it outputs a pulse:: The :meth:`artiq.coredevice.ttl.TTLInOut.count` method of an input channel can lead to a situation of negative slack (timeline cursor ``now`` smaller than the current wall clock ``rtio_counter``): The :meth:`artiq.coredevice.ttl.TTLInOut.gate_rising` method leaves the timeline cursor at the closure time of the gate and ``count()`` must necessarily wait until the gate closing event has actually been executed which is sometime with ``rtio_counter > now``. -In these situations where ``count()`` leads to a synchronization of timeline cursor and wall clock, a ``delay()`` is necessary to reestablish positive slack so that output events can be placed. +In these situations where ``count()`` leads to a synchronization of timeline cursor and wall clock, a ``delay()`` is necessary to reestablish positive slack (i.e. set the timeline cursor ``now`` greater than the current wall clock ``rtio_counter``) so that output events can be placed. Similar situations arise with methods such as :meth:`artiq.coredevice.ttl.TTLInOut.sample_get` and :meth:`artiq.coredevice.ttl.TTLInOut.watch_done`. From 4eb26c00503333e90112a3d800229809bfddaae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 3 Jul 2018 14:15:43 +0200 Subject: [PATCH 0995/2457] hmc7043: enable group 5 --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 6c52df3ee..2897aa92d 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -273,7 +273,8 @@ pub mod hmc7043 { write(0x4, (1 << 0) | (1 << 1) | (1 << 3) | - (1 << 4)); + (1 << 4) | + (1 << 5)); write(0x5c, (HMC_SYSREF_DIV & 0xff) as u8); // Set SYSREF timer divider write(0x5d, ((HMC_SYSREF_DIV & 0x0f) >> 8) as u8); From 509562ddbf268fef9ac94e1a9ec22d750882f441 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 6 Jul 2018 15:41:28 +0800 Subject: [PATCH 0996/2457] kasli: add WIPM target --- artiq/examples/kasli_basic/device_db_wipm.py | 250 +++++++++++++++++++ artiq/gateware/targets/kasli.py | 35 ++- 2 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 artiq/examples/kasli_basic/device_db_wipm.py diff --git a/artiq/examples/kasli_basic/device_db_wipm.py b/artiq/examples/kasli_basic/device_db_wipm.py new file mode 100644 index 000000000..42073ef4f --- /dev/null +++ b/artiq/examples/kasli_basic/device_db_wipm.py @@ -0,0 +1,250 @@ +core_addr = "kasli-2.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + + +for i in range(8): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": i}, + } + + +device_db.update( + spi_urukul0={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 8} + }, + ttl_urukul0_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 9} + }, + ttl_urukul0_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 10} + }, + ttl_urukul0_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 11} + }, + ttl_urukul0_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 12} + }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 13} + }, + urukul0_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul0_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } + +device_db.update( + spi_urukul1={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 14} + }, + ttl_urukul1_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 15} + }, + ttl_urukul1_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 16} + }, + ttl_urukul1_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 17} + }, + ttl_urukul1_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 18} + }, + ttl_urukul1_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 19} + }, + urukul1_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul1", + "io_update_device": "ttl_urukul1_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul1_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 8, + "chip_select": 4 + i, + "cpld_device": "urukul1_cpld", + "sw_device": "ttl_urukul1_sw" + str(i) + } + } + + +device_db["spi_sampler0_adc"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 20} +} +device_db["spi_sampler0_pgia"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 21} +} +device_db["spi_sampler0_cnv"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 22}, +} +device_db["sampler0"] = { + "type": "local", + "module": "artiq.coredevice.sampler", + "class": "Sampler", + "arguments": { + "spi_adc_device": "spi_sampler0_adc", + "spi_pgia_device": "spi_sampler0_pgia", + "cnv_device": "spi_sampler0_cnv" + } +} + + +device_db["spi_zotino0"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 23} +} +device_db["ttl_zotino0_ldac"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 24} +} +device_db["ttl_zotino0_clr"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 25} +} +device_db["zotino0"] = { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino0", + "ldac_device": "ttl_zotino0_ldac", + "clr_device": "ttl_zotino0_clr" + } +} + +device_db.update( + led0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 26} + }, + led1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 27} + }, +) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 6bd06ca50..f67e3fd47 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -377,6 +377,39 @@ class Tsinghua(_StandaloneBase): self.add_csr_group("grabber", self.grabber_csr_group) +class WIPM(_StandaloneBase): + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) + + self.rtio_channels = [] + eem.DIO.add_std(self, 4, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 1, 0, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) + eem.Sampler.add_std(self, 6, 5, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) + + for i in (1, 2): + sfp_ctl = self.platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(self.rtio_channels) + + class PTB(_StandaloneBase): """PTB Kasli variant @@ -844,7 +877,7 @@ def main(): soc_kasli_args(parser) parser.set_defaults(output_dir="artiq_kasli") variants = {cls.__name__.lower(): cls for cls in [ - Opticlock, SUServo, SYSU, MITLL, USTC, Tsinghua, PTB, HUB, LUH, + Opticlock, SUServo, SYSU, MITLL, USTC, Tsinghua, WIPM, PTB, HUB, LUH, Tester, Master, Satellite]} parser.add_argument("-V", "--variant", default="opticlock", help="variant: {} (default: %(default)s)".format( From ac3f360c2643c947606dc0041880a395c5b609f1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 6 Jul 2018 15:43:25 +0800 Subject: [PATCH 0997/2457] kasli_tester: fix AD9912 support --- artiq/examples/kasli_basic/repository/kasli_tester.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index 0054c2cff..d082e5bf2 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -56,6 +56,8 @@ class KasliTester(EnvExperiment): self.urukul_cplds[name] = self.get_device(name) elif (module, cls) == ("artiq.coredevice.ad9910", "AD9910"): self.urukuls[name] = self.get_device(name) + elif (module, cls) == ("artiq.coredevice.ad9912", "AD9912"): + self.urukuls[name] = self.get_device(name) elif (module, cls) == ("artiq.coredevice.sampler", "Sampler"): self.samplers[name] = self.get_device(name) elif (module, cls) == ("artiq.coredevice.zotino", "Zotino"): From 44200465023abd5e08fb7de6060767e95868ec06 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 6 Jul 2018 15:43:38 +0800 Subject: [PATCH 0998/2457] kasli_tester: support mixed AD9910/AD9912 systems --- artiq/examples/kasli_basic/repository/kasli_tester.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index d082e5bf2..a633ee02d 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -185,7 +185,7 @@ class KasliTester(EnvExperiment): while self.core.get_rtio_counter_mu() < t: pass for channel in channels: - channel.sw.pulse(100*ms) + channel.pulse(100*ms) delay(100*ms) # We assume that RTIO channels for switches are grouped by card. @@ -208,7 +208,7 @@ class KasliTester(EnvExperiment): input() print("Testing RF switch control. Press ENTER when done.") - self.rf_switch_wave([channel_dev for channel_name, channel_dev in self.urukuls]) + self.rf_switch_wave([channel_dev.sw for channel_name, channel_dev in self.urukuls]) @kernel def get_sampler_voltages(self, sampler, cb): From 9153c4d8a33470a6bf5cfb11dd7eaf06d0587b0d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 7 Jul 2018 17:04:56 +0800 Subject: [PATCH 0999/2457] use tokenize.open() to open Python source files Fixes encoding issues especially with device databases modified in obscure editors. --- artiq/compiler/testbench/embedding.py | 4 ++-- artiq/compiler/testbench/perf_embedding.py | 4 ++-- artiq/master/databases.py | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/artiq/compiler/testbench/embedding.py b/artiq/compiler/testbench/embedding.py index f79bb5a68..c637c4b3a 100644 --- a/artiq/compiler/testbench/embedding.py +++ b/artiq/compiler/testbench/embedding.py @@ -1,4 +1,4 @@ -import sys, os +import sys, os, tokenize from artiq.master.databases import DeviceDB from artiq.master.worker_db import DeviceManager @@ -27,7 +27,7 @@ def main(): ddb_path = os.path.join(os.path.dirname(sys.argv[1]), "device_db.py") dmgr = DeviceManager(DeviceDB(ddb_path)) - with open(sys.argv[1]) as f: + with tokenize.open(sys.argv[1]) as f: testcase_code = compile(f.read(), f.name, "exec") testcase_vars = {'__name__': 'testbench', 'dmgr': dmgr} exec(testcase_code, testcase_vars) diff --git a/artiq/compiler/testbench/perf_embedding.py b/artiq/compiler/testbench/perf_embedding.py index b94b88735..41f09cb04 100644 --- a/artiq/compiler/testbench/perf_embedding.py +++ b/artiq/compiler/testbench/perf_embedding.py @@ -1,4 +1,4 @@ -import sys, os +import sys, os, tokenize from pythonparser import diagnostic from ...language.environment import ProcessArgumentManager from ...master.databases import DeviceDB, DatasetDB @@ -22,7 +22,7 @@ def main(): engine = diagnostic.Engine() engine.process = process_diagnostic - with open(sys.argv[1]) as f: + with tokenize.open(sys.argv[1]) as f: testcase_code = compile(f.read(), f.name, "exec") testcase_vars = {'__name__': 'testbench'} exec(testcase_code, testcase_vars) diff --git a/artiq/master/databases.py b/artiq/master/databases.py index e71862d44..e279b3c56 100644 --- a/artiq/master/databases.py +++ b/artiq/master/databases.py @@ -1,4 +1,5 @@ import asyncio +import tokenize from artiq.protocols.sync_struct import Notifier, process_mod from artiq.protocols import pyon @@ -7,7 +8,7 @@ from artiq.tools import TaskObject def device_db_from_file(filename): glbs = dict() - with open(filename, "r") as f: + with tokenize.open(filename) as f: exec(f.read(), glbs) return glbs["device_db"] From 423929a125dcd6a12e0de115aff35800658fb99f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Jul 2018 18:00:24 +0800 Subject: [PATCH 1000/2457] test: relax min transfer rates from 2MB/s to 1.9MB/s --- artiq/test/coredevice/test_performance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index e6f70336b..8e91b7859 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -44,7 +44,7 @@ class TransferTest(ExperimentCase): exp = self.create(_Transfer) host_to_device_rate = exp.host_to_device() print(host_to_device_rate, "B/s") - self.assertGreater(host_to_device_rate, 2e6) + self.assertGreater(host_to_device_rate, 1.9e6) @unittest.skipUnless(artiq_low_latency, "timings are dependent on CPU load and network conditions") @@ -52,7 +52,7 @@ class TransferTest(ExperimentCase): exp = self.create(_Transfer) device_to_host_rate = exp.device_to_host() print(device_to_host_rate, "B/s") - self.assertGreater(device_to_host_rate, 2e6) + self.assertGreater(device_to_host_rate, 1.9e6) class _KernelOverhead(EnvExperiment): From d2c8e62cb71fea888af1d71f3d9e953840b6cdb4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Jul 2018 18:07:25 +0800 Subject: [PATCH 1001/2457] test_rtio: relax ClockGeneratorLoopback performance requirements --- artiq/test/coredevice/test_rtio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 4069e046a..401f4109b 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -92,7 +92,7 @@ class ClockGeneratorLoopback(EnvExperiment): self.core.reset() self.loop_clock_in.input() self.loop_clock_out.stop() - delay(20*us) + delay(200*us) with parallel: self.loop_clock_in.gate_rising(10*us) with sequential: From 4359a43732b7ffa63366193591828c4e2d6e384f Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 30 Jun 2018 19:29:34 +0100 Subject: [PATCH 1002/2457] compiler: Indirection status of TTuple depends on elements For instance, TTuple(TList(TInt32())) has indirections, while TTuple(TInt32()) does not. This fixes memory corruption with RPCs that return tuples of lists. Signed-off-by: David Nadlinger --- artiq/compiler/builtins.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/compiler/builtins.py b/artiq/compiler/builtins.py index 77e102d3b..1d69bcbae 100644 --- a/artiq/compiler/builtins.py +++ b/artiq/compiler/builtins.py @@ -311,9 +311,11 @@ def is_collection(typ): types.is_mono(typ, "list") def is_allocated(typ): + if types.is_tuple(typ): + return any(is_allocated(e.find()) for e in typ.elts) return not (is_none(typ) or is_bool(typ) or is_int(typ) or is_float(typ) or is_range(typ) or types._is_pointer(typ) or types.is_function(typ) or types.is_c_function(typ) or types.is_rpc(typ) or - types.is_method(typ) or types.is_tuple(typ) or + types.is_method(typ) or types.is_value(typ)) From 2d4af509c2c284e136b118adf34f3abef6536570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 9 Jul 2018 19:31:21 +0200 Subject: [PATCH 1003/2457] readthedocs.yml: drop (out of date, not working) --- .readthedocs.yml | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .readthedocs.yml diff --git a/.readthedocs.yml b/.readthedocs.yml deleted file mode 100644 index 7bbd24a41..000000000 --- a/.readthedocs.yml +++ /dev/null @@ -1,5 +0,0 @@ -python: - version: 3 - pip_install: false -conda: - file: conda/artiq-doc.yaml From 37e303dafc8af4e1aaae5a26cd3d1643827ff9b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 9 Jul 2018 19:32:29 +0200 Subject: [PATCH 1004/2457] gitmodules: remove empty file --- .gitmodules | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29bb..000000000 From 4f56710e4beb1c767dc10f7ddbdc283742540508 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 10 Jul 2018 02:06:37 +0800 Subject: [PATCH 1005/2457] grabber: add parser, report detected frame size in core device log --- artiq/firmware/libboard_artiq/grabber.rs | 26 ++++++-- artiq/gateware/grabber/core.py | 77 ++++++++++++++++++++++++ artiq/gateware/rtio/phy/grabber.py | 5 +- 3 files changed, 103 insertions(+), 5 deletions(-) create mode 100644 artiq/gateware/grabber/core.py diff --git a/artiq/firmware/libboard_artiq/grabber.rs b/artiq/firmware/libboard_artiq/grabber.rs index a70cb0e28..7df41d3cc 100644 --- a/artiq/firmware/libboard_artiq/grabber.rs +++ b/artiq/firmware/libboard_artiq/grabber.rs @@ -1,6 +1,13 @@ use board_misoc::csr; -static mut GRABBER_UP: &'static mut [bool] = &mut [false; csr::GRABBER_LEN]; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum State { + Down, + WaitResolution, + Up +} + +static mut GRABBER_STATE: &'static mut [State] = &mut [State::Down; csr::GRABBER_LEN]; fn get_pll_reset(g: usize) -> bool { unsafe { (csr::GRABBER[g].pll_reset_read)() != 0 } @@ -64,14 +71,25 @@ fn clock_align(g: usize) -> bool { true } +fn get_last_pixels(g: usize) -> (u16, u16) { + unsafe { ((csr::GRABBER[g].last_x_read)(), + (csr::GRABBER[g].last_y_read)()) } +} + pub fn tick() { for g in 0..csr::GRABBER.len() { - if unsafe { GRABBER_UP[g] } { + if unsafe { GRABBER_STATE[g] != State::Down } { if !clock_pattern_ok(g) || !pll_locked(g) { set_pll_reset(g, true); - unsafe { GRABBER_UP[g] = false; } + unsafe { GRABBER_STATE[g] = State::Down; } info!("grabber{} is down", g); } + if unsafe { GRABBER_STATE[g] == State::WaitResolution } { + let (last_x, last_y) = get_last_pixels(g); + info!("grabber{} detected frame size: {}x{}", + g, last_x + 1, last_y + 1); + unsafe { GRABBER_STATE[g] = State::Up; } + } } else { if get_pll_reset(g) { set_pll_reset(g, false); @@ -80,7 +98,7 @@ pub fn tick() { info!("grabber{} PLL is locked", g); if clock_align(g) { info!("grabber{} is up", g); - unsafe { GRABBER_UP[g] = true; } + unsafe { GRABBER_STATE[g] = State::WaitResolution; } } else { set_pll_reset(g, true); } diff --git a/artiq/gateware/grabber/core.py b/artiq/gateware/grabber/core.py new file mode 100644 index 000000000..6385a27ee --- /dev/null +++ b/artiq/gateware/grabber/core.py @@ -0,0 +1,77 @@ +from migen import * +from migen.genlib.cdc import MultiReg +from misoc.interconnect.csr import * + + +bitseq = [ + # 0 1 2 3 4 5 6 + 6, 5, 4, 3, 2, 1, 27, + + # 7 8 9 10 11 12 13 + 26, 0, 13, 12, 11, 10, 9, + + # 14 15 16 17 18 19 20 + 25, 24, 8, 7, 20, 19, 18, + + # 21 22 23 + 17, 23, 22 +] + +assert len(set(bitseq)) == 24 + + +class Parser(Module, AutoCSR): + """Parses 28 bit encoded words and track pixel coordinates.""" + def __init__(self, width=12): + self.cl = cl = Signal(28) + + self.last_x = CSRStatus(width) + self.last_y = CSRStatus(width) + + self.pix = pix = Record([ + ("x", width), + ("y", width), + ("a", 8), + ("b", 8), + ("c", 8), + ("stb", 1), # dval + ("eop", 1), # ~fval (i.e. not together with stb) + ]) + + # # # + + last_x = Signal(width) + last_y = Signal(width) + + lval = Signal() + fval = Signal() + dval = Signal() + self.comb += [ + Cat(dval, fval, lval).eq(cl[14:17]), + pix.stb.eq(dval), + pix.eop.eq(~fval), + Cat(pix.a, pix.b, pix.c).eq(Cat(cl[i] for i in bitseq)) + ] + last_lval = Signal() + last_fval = Signal() + self.sync.cl += [ + last_lval.eq(lval), + last_fval.eq(fval), + pix.x.eq(pix.x + 1), + If(~lval, + pix.x.eq(0), + If(last_lval, last_x.eq(pix.x)), + If(last_fval & last_lval, + pix.y.eq(pix.y + 1) + ) + ), + If(~fval, + If(last_fval, last_y.eq(pix.y)), + pix.y.eq(0) + ) + ] + + self.specials += [ + MultiReg(last_x, self.last_x.status), + MultiReg(last_y, self.last_y.status) + ] diff --git a/artiq/gateware/rtio/phy/grabber.py b/artiq/gateware/rtio/phy/grabber.py index 9d1a151d7..5639cfaae 100644 --- a/artiq/gateware/rtio/phy/grabber.py +++ b/artiq/gateware/rtio/phy/grabber.py @@ -2,6 +2,7 @@ from migen import * from artiq.gateware.rtio import rtlink from artiq.gateware.grabber import deserializer_7series +from artiq.gateware.grabber.core import * class Grabber(Module): @@ -11,6 +12,8 @@ class Grabber(Module): rtlink.IInterface(10)) self.submodules.deserializer = deserializer_7series.Deserializer(pins) + self.submodules.parser = Parser() + self.comb += self.parser.cl.eq(self.deserializer.q) def get_csrs(self): - return self.deserializer.get_csrs() + return self.deserializer.get_csrs() + self.parser.get_csrs() From edc314524c38a048957944b74ee42ad98b99e158 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 10 Jul 2018 01:10:18 +0100 Subject: [PATCH 1006/2457] test_embedding: Remove unused reference to `led` device --- artiq/test/coredevice/test_embedding.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 8d0e64aba..23afc9a20 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -80,7 +80,6 @@ class DefaultArgTest(ExperimentCase): class _RPCTypes(EnvExperiment): def build(self): self.setattr_device("core") - self.setattr_device("led") def return_bool(self) -> TBool: return True From 768b970debb564f88b057f9be83c980279d9ff14 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 10 Jul 2018 01:18:51 +0100 Subject: [PATCH 1007/2457] Fixup 4359a437 (tuples of lists), add regression tests --- artiq/compiler/builtins.py | 4 +- .../compiler/transforms/llvm_ir_generator.py | 2 +- artiq/test/coredevice/test_embedding.py | 40 +++++++++++++++++++ 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/artiq/compiler/builtins.py b/artiq/compiler/builtins.py index 1d69bcbae..77e102d3b 100644 --- a/artiq/compiler/builtins.py +++ b/artiq/compiler/builtins.py @@ -311,11 +311,9 @@ def is_collection(typ): types.is_mono(typ, "list") def is_allocated(typ): - if types.is_tuple(typ): - return any(is_allocated(e.find()) for e in typ.elts) return not (is_none(typ) or is_bool(typ) or is_int(typ) or is_float(typ) or is_range(typ) or types._is_pointer(typ) or types.is_function(typ) or types.is_c_function(typ) or types.is_rpc(typ) or - types.is_method(typ) or + types.is_method(typ) or types.is_tuple(typ) or types.is_value(typ)) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 25d7c6859..afbc6cbc9 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -1384,7 +1384,7 @@ class LLVMIRGenerator: self.llbuilder.position_at_end(lltail) llret = self.llbuilder.load(llslot, name="rpc.ret") - if not builtins.is_allocated(fun_type.ret): + if not fun_type.ret.fold(False, lambda r, t: r or builtins.is_allocated(t)): # We didn't allocate anything except the slot for the value itself. # Don't waste stack space. self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr]) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 23afc9a20..d8d85d5e0 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -58,6 +58,9 @@ class RoundtripTest(ExperimentCase): def test_object_list(self): self.assertRoundtrip([object(), object()]) + def test_list_tuple(self): + self.assertRoundtrip(([1, 2], [3, 4])) + class _DefaultArg(EnvExperiment): def build(self): @@ -296,3 +299,40 @@ class LargePayloadTest(ExperimentCase): def test_1MB(self): exp = self.create(_Payload1MB) exp.run() + + +class _ListTuple(EnvExperiment): + def build(self): + self.setattr_device("core") + + @kernel + def run(self): + # Make sure lifetime for the array data in tuples of lists is managed + # correctly. This is written in a somewhat convoluted fashion to provoke + # memory corruption even in the face of compiler optimizations. + for _ in range(self.get_num_iters()): + a, b = self.get_values(0, 1, 32) + c, d = self.get_values(2, 3, 64) + self.verify(a) + self.verify(c) + self.verify(b) + self.verify(d) + + @kernel + def verify(self, data): + for i in range(len(data)): + if data[i] != data[0] + i: + raise ValueError + + def get_num_iters(self) -> TInt32: + return 2 + + def get_values(self, base_a, base_b, n) -> TTuple([TList(TInt32), TList(TInt32)]): + return [numpy.int32(base_a + i) for i in range(n)], \ + [numpy.int32(base_b + i) for i in range(n)] + + +class ListTupleTest(ExperimentCase): + def test_list_tuple(self): + exp = self.create(_ListTuple) + exp.run() From d51294649e5b2486121b9c3952c18b5a3f76ffd0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 10 Jul 2018 12:26:24 +0800 Subject: [PATCH 1008/2457] conda: bump migen/misoc --- conda/artiq-dev/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index a53b96a96..fbee12943 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,8 +14,8 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_66+gitdcfec40 - - misoc 0.11 py35_20+git2436a68d + - migen 0.7 py35_69+gitb515b0e + - misoc 0.11 py35_27+git37dfced7 - jesd204b 0.7 - microscope - binutils-or1k-linux >=2.27 From c4e3c662656ccef3d705c521fbe4a298d639259f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 10 Jul 2018 12:37:32 +0800 Subject: [PATCH 1009/2457] grabber: add clock constraint --- artiq/gateware/eem.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 1f02382a1..2de10a145 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -409,8 +409,9 @@ class Grabber(_EEM): def add_std(cls, target, eem, eem_aux=None, ttl_out_cls=None): cls.add_extension(target, eem, eem_aux) - phy = grabber.Grabber(target.platform.request( - "grabber{}_video".format(eem))) + pads = target.platform.request("grabber{}_video".format(eem)) + target.platform.add_period_constraint(pads.clk_p, 14.71) + phy = grabber.Grabber(pads) name = "grabber{}".format(len(target.grabber_csr_group)) setattr(target.submodules, name, phy) target.grabber_csr_group.append(name) From 208dc7c218fb99cf939873ca59e93ebb17e99654 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 10 Jul 2018 12:56:37 +0800 Subject: [PATCH 1010/2457] grabber: prevent glitches in last_x/last_y cdc --- artiq/gateware/grabber/core.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/gateware/grabber/core.py b/artiq/gateware/grabber/core.py index 6385a27ee..f9559071c 100644 --- a/artiq/gateware/grabber/core.py +++ b/artiq/gateware/grabber/core.py @@ -71,6 +71,8 @@ class Parser(Module, AutoCSR): ) ] + last_x.attr.add("no_retiming") + last_y.attr.add("no_retiming") self.specials += [ MultiReg(last_x, self.last_x.status), MultiReg(last_y, self.last_y.status) From 6a77032fa535c90eb4674d6a20304744f7173a88 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 10 Jul 2018 13:30:38 +0800 Subject: [PATCH 1011/2457] grabber: use BUFR/BUFIO Less jitter and frees up BUFGs. --- artiq/gateware/grabber/deserializer_7series.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/artiq/gateware/grabber/deserializer_7series.py b/artiq/gateware/grabber/deserializer_7series.py index b7336a578..0224127fe 100644 --- a/artiq/gateware/grabber/deserializer_7series.py +++ b/artiq/gateware/grabber/deserializer_7series.py @@ -78,9 +78,7 @@ class Deserializer(Module, AutoCSR): mmcm_fb = Signal() mmcm_locked = Signal() mmcm_ps_psdone = Signal() - cl_clk = Signal() cl7x_clk = Signal() - phase = 257.0 self.specials += [ Instance("MMCME2_ADV", p_CLKIN1_PERIOD=18.0, @@ -94,14 +92,9 @@ class Deserializer(Module, AutoCSR): o_CLKFBOUT=mmcm_fb, i_CLKFBIN=mmcm_fb, - p_CLKOUT0_USE_FINE_PS="TRUE", - p_CLKOUT0_DIVIDE_F=21.0, - p_CLKOUT0_PHASE=phase, - o_CLKOUT0=cl_clk, - p_CLKOUT1_USE_FINE_PS="TRUE", p_CLKOUT1_DIVIDE=3, - p_CLKOUT1_PHASE=phase*7 % 360.0, + p_CLKOUT1_PHASE=0.0, o_CLKOUT1=cl7x_clk, i_PSCLK=ClockSignal(), @@ -109,8 +102,9 @@ class Deserializer(Module, AutoCSR): i_PSINCDEC=self.phase_shift.r, o_PSDONE=mmcm_ps_psdone, ), - Instance("BUFG", i_I=cl_clk, o_O=self.cd_cl.clk), - Instance("BUFG", i_I=cl7x_clk, o_O=self.cd_cl7x.clk), + Instance("BUFR", p_BUFR_DIVIDE="7", i_CLR=~mmcm_locked, + i_I=cl7x_clk, o_O=self.cd_cl.clk), + Instance("BUFIO", i_I=cl7x_clk, o_O=self.cd_cl7x.clk), AsyncResetSynchronizer(self.cd_cl, ~mmcm_locked), ] self.sync += [ From 701c93d46cf3c3695c155d9ee76e73b3c567cea6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 10 Jul 2018 14:28:23 +0800 Subject: [PATCH 1012/2457] grabber: add false path constraints --- artiq/gateware/eem.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 2de10a145..8690d9930 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -414,6 +414,14 @@ class Grabber(_EEM): phy = grabber.Grabber(pads) name = "grabber{}".format(len(target.grabber_csr_group)) setattr(target.submodules, name, phy) + + target.platform.add_false_path_constraints( + target.crg.cd_sys.clk, phy.deserializer.cd_cl.clk) + # Avoid bogus s/h violations at the clock input being sampled + # by the ISERDES. This uses dynamic calibration. + target.platform.add_false_path_constraints( + pads.clk_p, phy.deserializer.cd_cl7x.clk) + target.grabber_csr_group.append(name) target.csr_devices.append(name) target.rtio_channels += [ From d82beee5408082b5f25187d5f1c48fe63068e111 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 10 Jul 2018 17:04:07 +0800 Subject: [PATCH 1013/2457] grabber: make parser EOP a pulse --- artiq/gateware/grabber/core.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/grabber/core.py b/artiq/gateware/grabber/core.py index f9559071c..e300f6541 100644 --- a/artiq/gateware/grabber/core.py +++ b/artiq/gateware/grabber/core.py @@ -34,8 +34,8 @@ class Parser(Module, AutoCSR): ("a", 8), ("b", 8), ("c", 8), - ("stb", 1), # dval - ("eop", 1), # ~fval (i.e. not together with stb) + ("stb", 1), + ("eop", 1), ]) # # # @@ -46,14 +46,14 @@ class Parser(Module, AutoCSR): lval = Signal() fval = Signal() dval = Signal() + last_lval = Signal() + last_fval = Signal() self.comb += [ Cat(dval, fval, lval).eq(cl[14:17]), pix.stb.eq(dval), - pix.eop.eq(~fval), + pix.eop.eq(~fval & last_fval), Cat(pix.a, pix.b, pix.c).eq(Cat(cl[i] for i in bitseq)) ] - last_lval = Signal() - last_fval = Signal() self.sync.cl += [ last_lval.eq(lval), last_fval.eq(fval), From f8ceea20d07776f3c7f3c6b97d6f23bfc5ebd451 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 10 Jul 2018 17:06:17 +0800 Subject: [PATCH 1014/2457] grabber: add new ROI engine (untested) --- artiq/gateware/grabber/core.py | 60 ++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/artiq/gateware/grabber/core.py b/artiq/gateware/grabber/core.py index e300f6541..03c185859 100644 --- a/artiq/gateware/grabber/core.py +++ b/artiq/gateware/grabber/core.py @@ -77,3 +77,63 @@ class Parser(Module, AutoCSR): MultiReg(last_x, self.last_x.status), MultiReg(last_y, self.last_y.status) ] + + +class ROI(Module): + """ROI Engine. For each frame, accumulates pixels values within a + rectangular region of interest, and reports the total.""" + def __init__(self, pix, shift=0): + cnt_len = len(pix.x) + len(pix.y) + 16 - shift + + self.cfg = cfg = Record([ + ("x0", len(pix.x)), + ("x1", len(pix.x)), + ("y0", len(pix.y)), + ("y1", len(pix.y)), + ]) + self.out = out = Record([ + ("update", 1), + # register output - can be used as CDC input + ("cnt", cnt_len), + ]) + + # # # + + # stage 1 - generate "good" (in-ROI) signals + y_good = Signal() + x_good = Signal() + stb = Signal() + eop = Signal() + gray = Signal(16) + self.sync.cl += [ + If(pix.y == cfg.y0, + y_good.eq(1) + ), + If(pix.y == cfg.y1, + y_good.eq(0) + ), + If(pix.x == cfg.x0, + x_good.eq(1) + ), + If(pix.x == cfg.x1, + x_good.eq(0) + ), + gray.eq(Cat(pix.a, pix.b)[shift:]), + stb.eq(pix.stb), + eop.eq(pix.eop) + ] + + # stage 2 - accumulate + cnt = Signal(cnt_len) + self.sync.cl += [ + If(stb & x_good & y_good, + cnt.eq(cnt + gray), + ), + + out.update.eq(0), + If(eop, + cnt.eq(0), + out.update.eq(1), + out.cnt.eq(cnt) + ) + ] From 7f05e0c121daa5966144e7435d1b8da3816ebd4a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 11 Jul 2018 19:00:16 +0800 Subject: [PATCH 1015/2457] sayma_rtm: remove UART loopback RTM power supply issues are fixed now, plus this will get in the way of satman support. --- artiq/gateware/targets/sayma_rtm.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 1872529fa..7f4cc476d 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -129,10 +129,6 @@ class SaymaRTM(Module): reset_out=0b0111) csr_devices.append("clock_mux") - # UART loopback - serial = platform.request("serial") - self.comb += serial.tx.eq(serial.rx) - # Allaki: enable RF output, GPIO access to attenuator self.comb += [ platform.request("allaki0_rfsw0").eq(1), From 29e5c95afaeeba159770b291cc561eb3bbf21cd9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 11 Jul 2018 19:02:59 +0800 Subject: [PATCH 1016/2457] sayma_rtm: minor cleanup --- artiq/gateware/targets/sayma_rtm.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 7f4cc476d..5060b03fe 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -102,6 +102,7 @@ class RTMScratch(Module, AutoCSR): read_data.status.eq(fifo.source.data) ] + CSR_RANGE_SIZE = 0x800 @@ -162,10 +163,7 @@ class SaymaRTM(Module): csr_devices.append("allaki_atts") # HMC clock chip and DAC control - self.comb += [ - platform.request("ad9154_rst_n").eq(1), - ] - + self.comb += platform.request("ad9154_rst_n").eq(1) self.submodules.converter_spi = spi2.SPIMaster(spi2.SPIInterface( platform.request("hmc_spi"), platform.request("ad9154_spi", 0), From 88fb9ce4d6a7fa4eb3f2f07ba15259a6429e235d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 11 Jul 2018 19:04:29 +0800 Subject: [PATCH 1017/2457] sayma_rtm: add hmc7043_gpo monitoring --- artiq/gateware/targets/sayma_rtm.py | 3 +++ conda/artiq-dev/meta.yaml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 5060b03fe..e50656ed9 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -172,6 +172,9 @@ class SaymaRTM(Module): self.submodules.hmc7043_reset = gpio.GPIOOut( platform.request("hmc7043_reset"), reset_out=1) csr_devices.append("hmc7043_reset") + self.submodules.hmc7043_gpo = gpio.GPIOIn( + platform.request("hmc7043_gpo")) + csr_devices.append("hmc7043_gpo") # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index fbee12943..7fc0d5828 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_69+gitb515b0e + - migen 0.7 py35_70+git1ec3ea9 - misoc 0.11 py35_27+git37dfced7 - jesd204b 0.7 - microscope From 9397fa7f5ae590aa9018496eb6ee8b7c7942b22d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 11 Jul 2018 19:07:15 +0800 Subject: [PATCH 1018/2457] hmc7043: unstick SYSREF FSM (#1055) Troubleshooting by David. Additionally, register 7D is broken. Checking phase init state has to be done through another means. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 2897aa92d..757f2b7df 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -263,7 +263,8 @@ pub mod hmc7043 { spi_setup(); info!("loading configuration..."); - write(0xA, 0x06); // Disable the REFSYNCIN input + write(0x3, 0x14); // Disable the REFSYNCIN reseeder + write(0xA, 0x06); // Disable the REFSYNCIN input buffer write(0xB, 0x07); // Enable the CLKIN input as LVPECL write(0x50, 0x1f); // Disable GPO pin write(0x9F, 0x4d); // Unexplained high-performance mode From 4843832329da1e9872d1c3c662b1dc9462c6908d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 11 Jul 2018 19:45:24 +0800 Subject: [PATCH 1019/2457] hmc7043: check phase status on init. Closes #1055 Troubleshooting by David. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 32 +++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 757f2b7df..95eafa1f4 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -197,6 +197,12 @@ pub mod hmc7043 { } } + fn spi_wait_idle() { + unsafe { + while csr::converter_spi::idle_read() == 0 {} + } + } + fn write(addr: u16, data: u8) { let cmd = (0 << 15) | addr; let val = ((cmd as u32) << 8) | data as u32; @@ -259,6 +265,17 @@ pub mod hmc7043 { write(0x1, 0x48); // mute all outputs } + /* Read an HMC7043 internal status bit through the GPO interface. + * This method is required to work around bugs in the register interface. + */ + fn gpo_indirect_read(mux_setting: u8) -> bool { + write(0x50, (mux_setting << 2) | 0x3); + spi_wait_idle(); + unsafe { + csr::hmc7043_gpo::in_read() == 1 + } + } + pub fn init() { spi_setup(); info!("loading configuration..."); @@ -266,7 +283,6 @@ pub mod hmc7043 { write(0x3, 0x14); // Disable the REFSYNCIN reseeder write(0xA, 0x06); // Disable the REFSYNCIN input buffer write(0xB, 0x07); // Enable the CLKIN input as LVPECL - write(0x50, 0x1f); // Disable GPO pin write(0x9F, 0x4d); // Unexplained high-performance mode write(0xA0, 0xdf); // Unexplained high-performance mode @@ -320,6 +336,19 @@ pub mod hmc7043 { info!(" ...done"); } + pub fn check_phased() -> Result<(), &'static str> { + if !gpo_indirect_read(3) { + return Err("GPO reported phases did not align"); + } + // Should be the same as the GPO read + let sysref_fsm_status = read(0x91); + if sysref_fsm_status != 0x2 { + error!("Bad SYSREF FSM status: {:02x}", sysref_fsm_status); + return Err("Bad SYSREF FSM status"); + } + Ok(()) + } + pub fn sysref_offset_dac(dacno: u8, phase_offset: u16) { /* Analog delay resolution: 25ps * Digital delay resolution: 1/2 input clock cycle = 416ps for 1.2GHz @@ -434,6 +463,7 @@ pub fn init() -> Result<(), &'static str> { hmc7043::enable(); hmc7043::detect()?; hmc7043::init(); + hmc7043::check_phased()?; Ok(()) } From 141fcaaa8afa9baceaf98747cc1f8085d4535f3d Mon Sep 17 00:00:00 2001 From: David Nadligner Date: Wed, 11 Jul 2018 20:09:18 +0100 Subject: [PATCH 1020/2457] worker_db: Only warn on repeated archive read if dataset changed In larger experiments, it is quite natural for the same dataset to be read from multiple unrelated components. The only situation where multiple reads from an archived dataset are problematic is when the valeu actually changes between reads. Hence, this commit restricts the warning to the latter situation. --- artiq/master/worker_db.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/master/worker_db.py b/artiq/master/worker_db.py index 1a4ef61e6..22190a087 100644 --- a/artiq/master/worker_db.py +++ b/artiq/master/worker_db.py @@ -227,9 +227,9 @@ class DatasetManager: else: data = self.ddb.get(key) if archive: - if key in self.archive: - logger.warning("Dataset '%s' is already in archive, " - "overwriting", key, stack_info=True) + if self.archive.get(key, data) != data: + logger.warning("Older value of dataset '%s' is already in " + "archive, overwriting", key, stack_info=True) self.archive[key] = data return data From 773240bef42f2e12b1a32eea3900d182303f4c69 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jul 2018 11:30:24 +0800 Subject: [PATCH 1021/2457] hmc7043: test GPO before using Based on code by David. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 23 +++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 95eafa1f4..6866b92a6 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -265,6 +265,10 @@ pub mod hmc7043 { write(0x1, 0x48); // mute all outputs } + const GPO_MUX_CLK_OUT_PHASE: u8 = 3; + const GPO_MUX_FORCE1: u8 = 10; + const GPO_MUX_FORCE0: u8 = 11; + /* Read an HMC7043 internal status bit through the GPO interface. * This method is required to work around bugs in the register interface. */ @@ -336,8 +340,24 @@ pub mod hmc7043 { info!(" ...done"); } + pub fn test_gpo() -> Result<(), &'static str> { + info!("testing GPO..."); + for trial in 0..10 { + if !gpo_indirect_read(GPO_MUX_FORCE1) { + info!(" ...failed. GPO I/O did not go high (#{})", trial + 1); + return Err("GPO is not functioning"); + } + if gpo_indirect_read(GPO_MUX_FORCE0) { + info!(" ...failed. GPO I/O did not return low (#{})", trial + 1); + return Err("GPO is not functioning"); + } + } + info!(" ...passed"); + Ok(()) + } + pub fn check_phased() -> Result<(), &'static str> { - if !gpo_indirect_read(3) { + if !gpo_indirect_read(GPO_MUX_CLK_OUT_PHASE) { return Err("GPO reported phases did not align"); } // Should be the same as the GPO read @@ -463,6 +483,7 @@ pub fn init() -> Result<(), &'static str> { hmc7043::enable(); hmc7043::detect()?; hmc7043::init(); + hmc7043::test_gpo()?; hmc7043::check_phased()?; Ok(()) From 1c191a62bf7c3ae582d15712a29ac7dfa3590705 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jul 2018 11:30:57 +0800 Subject: [PATCH 1022/2457] sayma: tune SYSREF phases --- artiq/firmware/runtime/main.rs | 4 ++-- artiq/firmware/satman/main.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 2f119515a..cc67b64c4 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -57,9 +57,9 @@ mod moninj; mod analyzer; #[cfg(has_ad9154)] -const SYSREF_PHASE_FPGA: u16 = 35; +const SYSREF_PHASE_FPGA: u16 = 41; #[cfg(has_ad9154)] -const SYSREF_PHASE_DAC: u16 = 64; +const SYSREF_PHASE_DAC: u16 = 94; fn startup() { irq::set_mask(0); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index faac96946..b8a256fcd 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -250,9 +250,9 @@ fn drtio_link_rx_up() -> bool { const SIPHASER_PHASE: u16 = 32; #[cfg(has_ad9154)] -const SYSREF_PHASE_FPGA: u16 = 53; +const SYSREF_PHASE_FPGA: u16 = 54; #[cfg(has_ad9154)] -const SYSREF_PHASE_DAC: u16 = 64; +const SYSREF_PHASE_DAC: u16 = 61; #[no_mangle] pub extern fn main() -> i32 { From c66f9483f8b243bf21896e7f2094d42b946afbdf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jul 2018 12:33:50 +0800 Subject: [PATCH 1023/2457] hmc7043: wait after changing delays Allows for the SPI transaction to finish, and for the delay to stabilize. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 6866b92a6..0eb7f3ad1 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -386,6 +386,7 @@ pub mod hmc7043 { } else { unimplemented!(); } + clock::spin_us(100); } fn sysref_offset_fpga(phase_offset: u16) { @@ -394,12 +395,14 @@ pub mod hmc7043 { spi_setup(); write(0x0111, analog_delay); write(0x0112, digital_delay); + clock::spin_us(100); } fn sysref_slip() { spi_setup(); write(0x0002, 0x02); write(0x0002, 0x00); + clock::spin_us(100); } fn sysref_sample() -> bool { From 8802b930de0ebdd023da1ddca3937f27738dbed8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jul 2018 12:37:12 +0800 Subject: [PATCH 1024/2457] hmc7043: add delay after init Delay required at step 9 of the "Typical Programming Sequence" (page 24 of the datasheet) --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 0eb7f3ad1..b1d1cb3b9 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -131,6 +131,8 @@ mod hmc830 { write(0x4, m_div); write(0x3, n_div); + clock::spin_us(10_000); + info!(" ...done"); } From 29c35ee553ec963e77127ec74f5cd12e10574d3c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jul 2018 13:01:41 +0800 Subject: [PATCH 1025/2457] hmc7043: fix dumb mistake in previous commit --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index b1d1cb3b9..faa26630a 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -131,8 +131,6 @@ mod hmc830 { write(0x4, m_div); write(0x3, n_div); - clock::spin_us(10_000); - info!(" ...done"); } @@ -339,6 +337,8 @@ pub mod hmc7043 { write(0x1, 0xc8); // Synchronize dividers write(0x1, 0x40); // Unmute, high-performance/low-noise mode + clock::spin_us(10_000); + info!(" ...done"); } From 82def6b535234f89b1ebc87752ee0ca6ccc25779 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jul 2018 17:05:18 +0800 Subject: [PATCH 1026/2457] grabber: add frequency counter Cameras are a bit obscure about what they output, this can help with troubleshooting. --- artiq/firmware/libboard_artiq/grabber.rs | 10 ++++++++- artiq/gateware/grabber/core.py | 28 ++++++++++++++++++++++++ artiq/gateware/rtio/phy/grabber.py | 6 ++++- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/grabber.rs b/artiq/firmware/libboard_artiq/grabber.rs index 7df41d3cc..272b44447 100644 --- a/artiq/firmware/libboard_artiq/grabber.rs +++ b/artiq/firmware/libboard_artiq/grabber.rs @@ -76,6 +76,13 @@ fn get_last_pixels(g: usize) -> (u16, u16) { (csr::GRABBER[g].last_y_read)()) } } +fn get_video_clock(g: usize) -> u32 { + let freq_count = unsafe { + (csr::GRABBER[g].freq_count_read)() + } as u32; + 2*freq_count*(csr::CONFIG_CLOCK_FREQUENCY/1000000)/255 +} + pub fn tick() { for g in 0..csr::GRABBER.len() { if unsafe { GRABBER_STATE[g] != State::Down } { @@ -86,8 +93,9 @@ pub fn tick() { } if unsafe { GRABBER_STATE[g] == State::WaitResolution } { let (last_x, last_y) = get_last_pixels(g); - info!("grabber{} detected frame size: {}x{}", + info!("grabber{} frame size: {}x{}", g, last_x + 1, last_y + 1); + info!("grabber{} video clock: {}MHz", g, get_video_clock(g)); unsafe { GRABBER_STATE[g] = State::Up; } } } else { diff --git a/artiq/gateware/grabber/core.py b/artiq/gateware/grabber/core.py index 03c185859..477f11796 100644 --- a/artiq/gateware/grabber/core.py +++ b/artiq/gateware/grabber/core.py @@ -3,6 +3,34 @@ from migen.genlib.cdc import MultiReg from misoc.interconnect.csr import * +class FrequencyCounter(Module, AutoCSR): + def __init__(self, width=8): + self.freq_count = CSRStatus(width) + + # # # + + toggle = Signal(reset_less=True) + toggle_sys = Signal() + toggle.attr.add("no_retiming") + self.sync.cl += toggle.eq(~toggle) + self.specials += MultiReg(toggle, toggle_sys) + + timer = Signal(width+1) + tick = Signal(reset=1) + count = Signal(width) + toggle_sys_r = Signal() + self.sync += [ + Cat(timer, tick).eq(timer + 1), + toggle_sys_r.eq(toggle_sys), + If(tick, + self.freq_count.status.eq(count), + count.eq(0) + ).Else( + If(toggle_sys & ~toggle_sys_r, count.eq(count + 1)) + ) + ] + + bitseq = [ # 0 1 2 3 4 5 6 6, 5, 4, 3, 2, 1, 27, diff --git a/artiq/gateware/rtio/phy/grabber.py b/artiq/gateware/rtio/phy/grabber.py index 5639cfaae..a6c891e50 100644 --- a/artiq/gateware/rtio/phy/grabber.py +++ b/artiq/gateware/rtio/phy/grabber.py @@ -12,8 +12,12 @@ class Grabber(Module): rtlink.IInterface(10)) self.submodules.deserializer = deserializer_7series.Deserializer(pins) + self.submodules.frequency_counter = FrequencyCounter() self.submodules.parser = Parser() self.comb += self.parser.cl.eq(self.deserializer.q) def get_csrs(self): - return self.deserializer.get_csrs() + self.parser.get_csrs() + return ( + self.deserializer.get_csrs() + + self.frequency_counter.get_csrs() + + self.parser.get_csrs()) From 46fb5adac3e6f9be263a9d38882d3ea1e0d4f429 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Jul 2018 20:14:38 +0800 Subject: [PATCH 1027/2457] grabber: fix frequency counter formula --- artiq/firmware/libboard_artiq/grabber.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/grabber.rs b/artiq/firmware/libboard_artiq/grabber.rs index 272b44447..7c80ac81b 100644 --- a/artiq/firmware/libboard_artiq/grabber.rs +++ b/artiq/firmware/libboard_artiq/grabber.rs @@ -80,7 +80,7 @@ fn get_video_clock(g: usize) -> u32 { let freq_count = unsafe { (csr::GRABBER[g].freq_count_read)() } as u32; - 2*freq_count*(csr::CONFIG_CLOCK_FREQUENCY/1000000)/255 + 2*freq_count*(csr::CONFIG_CLOCK_FREQUENCY/1000)/(511*1000) } pub fn tick() { From ea7f9258521d31a813a2ba6d33899c90862149e4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 13 Jul 2018 10:41:06 +0800 Subject: [PATCH 1028/2457] Revert "worker_db: Only warn on repeated archive read if dataset changed" Breaks numpy arrays. This reverts commit 141fcaaa8afa9baceaf98747cc1f8085d4535f3d. --- artiq/master/worker_db.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/master/worker_db.py b/artiq/master/worker_db.py index 22190a087..1a4ef61e6 100644 --- a/artiq/master/worker_db.py +++ b/artiq/master/worker_db.py @@ -227,9 +227,9 @@ class DatasetManager: else: data = self.ddb.get(key) if archive: - if self.archive.get(key, data) != data: - logger.warning("Older value of dataset '%s' is already in " - "archive, overwriting", key, stack_info=True) + if key in self.archive: + logger.warning("Dataset '%s' is already in archive, " + "overwriting", key, stack_info=True) self.archive[key] = data return data From 8bcba82b650fc00e864e273929471472bda32669 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 15 Jul 2018 15:34:00 +0800 Subject: [PATCH 1029/2457] grabber: reset *_good signals on end of frame This reduces the amount of time the ROI engine produces invalid output after being reconfigured. --- artiq/gateware/grabber/core.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/gateware/grabber/core.py b/artiq/gateware/grabber/core.py index 477f11796..a1144000b 100644 --- a/artiq/gateware/grabber/core.py +++ b/artiq/gateware/grabber/core.py @@ -146,6 +146,10 @@ class ROI(Module): If(pix.x == cfg.x1, x_good.eq(0) ), + If(pix.eop, + y_good.eq(0), + x_good.eq(0) + ), gray.eq(Cat(pix.a, pix.b)[shift:]), stb.eq(pix.stb), eop.eq(pix.eop) From b6c70b3cb0e238da4de9b53465560b1b43eb47b7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 15 Jul 2018 15:35:04 +0800 Subject: [PATCH 1030/2457] eem: add Zotino monitoring. Closes #1095 --- artiq/gateware/eem.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 8690d9930..78155b19b 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -3,7 +3,7 @@ from migen.build.generic_platform import * from migen.genlib.io import DifferentialOutput from artiq.gateware import rtio -from artiq.gateware.rtio.phy import spi2, grabber +from artiq.gateware.rtio.phy import spi2, ad53xx_monitor, grabber from artiq.gateware.suservo import servo, pads as servo_pads from artiq.gateware.rtio.phy import servo as rtservo @@ -339,16 +339,24 @@ class Zotino(_EEM): def add_std(cls, target, eem, ttl_out_cls): cls.add_extension(target, eem) - phy = spi2.SPIMaster(target.platform.request("zotino{}_spi_p".format(eem)), + spi_phy = spi2.SPIMaster(target.platform.request("zotino{}_spi_p".format(eem)), target.platform.request("zotino{}_spi_n".format(eem))) - target.submodules += phy - target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + target.submodules += spi_phy + target.rtio_channels.append(rtio.Channel.from_phy(spi_phy, ififo_depth=4)) - for signal in "ldac_n clr_n".split(): - pads = target.platform.request("zotino{}_{}".format(eem, signal)) - phy = ttl_out_cls(pads.p, pads.n) - target.submodules += phy - target.rtio_channels.append(rtio.Channel.from_phy(phy)) + pads = target.platform.request("zotino{}_ldac_n".format(eem)) + ldac_phy = ttl_out_cls(pads.p, pads.n) + target.submodules += ldac_phy + target.rtio_channels.append(rtio.Channel.from_phy(ldac_phy)) + + pads = target.platform.request("zotino{}_clr_n".format(eem)) + clr_phy = ttl_out_cls(pads.p, pads.n) + target.submodules += clr_phy + target.rtio_channels.append(rtio.Channel.from_phy(clr_phy)) + + dac_monitor = ad53xx_monitor.AD53XXMonitor(spi_phy.rtlink, ldac_phy.rtlink) + target.submodules += dac_monitor + spi_phy.probes.extend(dac_monitor.probes) class Grabber(_EEM): From b27fa8964b91c624e42094bdfbe035446b39d39d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 15 Jul 2018 17:21:17 +0800 Subject: [PATCH 1031/2457] add variant in identifier string Also add without-sawg suffixes on Sayma. Closes #1060 Closes #1059 --- artiq/build_soc.py | 24 +++++++++++++ artiq/coredevice/comm_kernel.py | 2 +- artiq/firmware/Cargo.lock | 10 ------ artiq/firmware/libboard_artiq/Cargo.toml | 1 - artiq/firmware/libbuild_artiq/Cargo.toml | 11 ------ artiq/firmware/libbuild_artiq/lib.rs | 45 ------------------------ artiq/firmware/runtime/Cargo.toml | 1 - artiq/firmware/runtime/build.rs | 2 -- artiq/firmware/runtime/main.rs | 5 ++- artiq/firmware/satman/Cargo.toml | 1 - artiq/firmware/satman/build.rs | 2 -- artiq/firmware/satman/main.rs | 2 +- artiq/gateware/targets/kasli.py | 9 +++-- artiq/gateware/targets/kc705.py | 6 ++-- artiq/gateware/targets/sayma_amc.py | 11 +++--- 15 files changed, 40 insertions(+), 92 deletions(-) delete mode 100644 artiq/firmware/libbuild_artiq/Cargo.toml delete mode 100644 artiq/firmware/libbuild_artiq/lib.rs diff --git a/artiq/build_soc.py b/artiq/build_soc.py index ab2caf9ce..e13eba375 100644 --- a/artiq/build_soc.py +++ b/artiq/build_soc.py @@ -1,12 +1,36 @@ import os import subprocess +from misoc.cores import identifier from misoc.integration.builder import * from artiq.gateware.amp import AMPSoC +from artiq import __version__ as artiq_version from artiq import __artiq_dir__ as artiq_dir +__all__ = ["add_identifier", "build_artiq_soc"] + + +def get_identifier_string(soc, suffix="", add_class_name=True): + r = artiq_version + if suffix or add_class_name: + r += ";" + if add_class_name: + r += soc.__class__.__name__.lower() + r += suffix + return r + + +def add_identifier(soc, *args, **kwargs): + if hasattr(soc, "identifier"): + raise ValueError + identifier_str = get_identifier_string(soc, *args, **kwargs) + soc.submodules.identifier = identifier.Identifier(identifier_str) + soc.config["IDENTIFIER_STR"] = identifier_str + + + def build_artiq_soc(soc, argdict): firmware_dir = os.path.join(artiq_dir, "firmware") builder = Builder(soc, **argdict) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 5939fb52d..7bec59580 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -220,7 +220,7 @@ class CommKernel: raise UnsupportedDevice("Unsupported runtime ID: {}" .format(runtime_id)) - gateware_version = self._read_string() + gateware_version = self._read_string().split(";")[0] if gateware_version != software_version and not self.warned_of_mismatch: logger.warning("Mismatch between gateware (%s) " "and software (%s) versions", diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 744e02371..4908fc14f 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -13,7 +13,6 @@ version = "0.0.0" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "board_misoc 0.0.0", - "build_artiq 0.0.0", "build_misoc 0.0.0", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -47,13 +46,6 @@ dependencies = [ "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", ] -[[package]] -name = "build_artiq" -version = "0.0.0" -dependencies = [ - "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "build_const" version = "0.2.1" @@ -224,7 +216,6 @@ dependencies = [ "alloc_list 0.0.0", "board_artiq 0.0.0", "board_misoc 0.0.0", - "build_artiq 0.0.0", "build_misoc 0.0.0", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -255,7 +246,6 @@ version = "0.0.0" dependencies = [ "board_artiq 0.0.0", "board_misoc 0.0.0", - "build_artiq 0.0.0", "build_misoc 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/artiq/firmware/libboard_artiq/Cargo.toml b/artiq/firmware/libboard_artiq/Cargo.toml index b04990823..0f13ca2de 100644 --- a/artiq/firmware/libboard_artiq/Cargo.toml +++ b/artiq/firmware/libboard_artiq/Cargo.toml @@ -10,7 +10,6 @@ path = "lib.rs" [build-dependencies] build_misoc = { path = "../libbuild_misoc" } -build_artiq = { path = "../libbuild_artiq" } [dependencies] failure = { version = "0.1", default-features = false } diff --git a/artiq/firmware/libbuild_artiq/Cargo.toml b/artiq/firmware/libbuild_artiq/Cargo.toml deleted file mode 100644 index 19e810e99..000000000 --- a/artiq/firmware/libbuild_artiq/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -authors = ["M-Labs"] -name = "build_artiq" -version = "0.0.0" - -[lib] -name = "build_artiq" -path = "lib.rs" - -[dependencies] -walkdir = "1.0" diff --git a/artiq/firmware/libbuild_artiq/lib.rs b/artiq/firmware/libbuild_artiq/lib.rs deleted file mode 100644 index 81c9ad97b..000000000 --- a/artiq/firmware/libbuild_artiq/lib.rs +++ /dev/null @@ -1,45 +0,0 @@ -extern crate walkdir; - -use std::env; -use std::fs; -use std::path::Path; -use std::process::Command; - -use walkdir::WalkDir; - -pub fn git_describe() { - let git_checkout = Path::new("../../.."); - for entry in WalkDir::new(git_checkout) { - let entry = entry.unwrap(); - println!("cargo:rerun-if-changed={}", entry.path().display()); - } - - let version; - if git_checkout.join(".git").exists() { - let git_describe = - Command::new("git") - .arg("describe") - .arg("--tags") - .arg("--dirty") - .arg("--always") - .arg("--long") - .arg("--abbrev=8") - .output() - .ok() - .and_then(|o| String::from_utf8(o.stdout).ok()) - .map(|mut s| { - let len = s.trim_right().len(); - s.truncate(len); - s - }) - .unwrap(); - let parts = git_describe.split("-").collect::>(); - version = format!("{}+{}.{}", parts[0], parts[1], parts[2]); - } else { - version = "unknown".to_owned(); - } - - let out_dir = env::var("OUT_DIR").unwrap(); - let git_describe = Path::new(&out_dir).join("git-describe"); - fs::write(&git_describe, version).unwrap(); -} diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index f7eb87ace..ec0990aff 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -11,7 +11,6 @@ path = "main.rs" [build-dependencies] build_misoc = { path = "../libbuild_misoc" } -build_artiq = { path = "../libbuild_artiq" } [dependencies] failure = { version = "0.1", default-features = false } diff --git a/artiq/firmware/runtime/build.rs b/artiq/firmware/runtime/build.rs index 64a84fcb8..3548ea5ff 100644 --- a/artiq/firmware/runtime/build.rs +++ b/artiq/firmware/runtime/build.rs @@ -1,7 +1,5 @@ extern crate build_misoc; -extern crate build_artiq; fn main() { build_misoc::cfg(); - build_artiq::git_describe(); } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index cc67b64c4..26368104e 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -66,7 +66,7 @@ fn startup() { irq::set_ie(true); clock::init(); info!("ARTIQ runtime starting..."); - info!("software version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); + info!("software version {}", csr::CONFIG_IDENTIFIER_STR); info!("gateware version {}", ident::read(&mut [0; 64])); match config::read_str("log_level", |r| r.map(|s| s.parse())) { @@ -355,8 +355,7 @@ pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, println!("panic at {}:{}:{}: {}", file, line, column, args); - println!("backtrace for software version {}:", - include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); + println!("backtrace for software version {}:", csr::CONFIG_IDENTIFIER_STR); let _ = unwind_backtrace::backtrace(|ip| { // Backtrace gives us the return address, i.e. the address after the delay slot, // but we're interested in the call instruction. diff --git a/artiq/firmware/satman/Cargo.toml b/artiq/firmware/satman/Cargo.toml index 78c84ab87..fdccaf27a 100644 --- a/artiq/firmware/satman/Cargo.toml +++ b/artiq/firmware/satman/Cargo.toml @@ -11,7 +11,6 @@ path = "main.rs" [build-dependencies] build_misoc = { path = "../libbuild_misoc" } -build_artiq = { path = "../libbuild_artiq" } [dependencies] log = { version = "0.4", default-features = false } diff --git a/artiq/firmware/satman/build.rs b/artiq/firmware/satman/build.rs index 64a84fcb8..3548ea5ff 100644 --- a/artiq/firmware/satman/build.rs +++ b/artiq/firmware/satman/build.rs @@ -1,7 +1,5 @@ extern crate build_misoc; -extern crate build_artiq; fn main() { build_misoc::cfg(); - build_artiq::git_describe(); } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index b8a256fcd..d74d0480d 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -260,7 +260,7 @@ pub extern fn main() -> i32 { uart_logger::ConsoleLogger::register(); info!("ARTIQ satellite manager starting..."); - info!("software version {}", include_str!(concat!(env!("OUT_DIR"), "/git-describe"))); + info!("software version {}", csr::CONFIG_IDENTIFIER_STR); info!("gateware version {}", ident::read(&mut [0; 64])); #[cfg(has_slave_fpga_cfg)] diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index f67e3fd47..ab0abb2d2 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -22,8 +22,7 @@ from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite -from artiq.build_soc import build_artiq_soc -from artiq import __version__ as artiq_version +from artiq.build_soc import * class _RTIOCRG(Module, AutoCSR): @@ -100,11 +99,11 @@ class _StandaloneBase(MiniSoC, AMPSoC): cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, - ident=artiq_version, ethmac_nrxslots=4, ethmac_ntxslots=4, **kwargs) AMPSoC.__init__(self) + add_identifier(self) self.submodules.leds = gpio.GPIOOut(Cat( self.platform.request("user_led", 0))) @@ -622,11 +621,11 @@ class _MasterBase(MiniSoC, AMPSoC): cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, - ident=artiq_version, ethmac_nrxslots=4, ethmac_ntxslots=4, **kwargs) AMPSoC.__init__(self) + add_identifier(self) platform = self.platform rtio_clk_freq = 150e6 @@ -754,8 +753,8 @@ class _SatelliteBase(BaseSoC): cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, - ident=artiq_version, **kwargs) + add_identifier(self) platform = self.platform rtio_clk_freq = 150e6 diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 39f26afa8..795f3ee80 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -18,8 +18,7 @@ from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio, nist_clock, nist_qc2 from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series, dds, spi2, ad53xx_monitor) -from artiq.build_soc import build_artiq_soc -from artiq import __version__ as artiq_version +from artiq.build_soc import * class _RTIOCRG(Module, AutoCSR): @@ -219,11 +218,12 @@ class _StandaloneBase(MiniSoC, AMPSoC): cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, - ident=artiq_version, ethmac_nrxslots=4, ethmac_ntxslots=4, **kwargs) AMPSoC.__init__(self) + add_identifier(self) + if isinstance(self.platform.toolchain, XilinxVivadoToolchain): self.platform.toolchain.bitstream_commands.extend([ "set_property BITSTREAM.GENERAL.COMPRESS True [current_design]", diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index e9fcf3fd5..c52d8c3ca 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -22,8 +22,7 @@ from artiq.gateware.drtio.transceiver import gth_ultrascale from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite -from artiq.build_soc import build_artiq_soc -from artiq import __version__ as artiq_version +from artiq.build_soc import * class AD9154(Module, AutoCSR): @@ -132,12 +131,12 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, - ident=artiq_version, ethmac_nrxslots=4, ethmac_ntxslots=4, **kwargs) AMPSoC.__init__(self) RTMCommon.__init__(self) + add_identifier(self, suffix=".without-sawg" if not with_sawg else "") self.config["HMC830_REF"] = "100" platform = self.platform @@ -238,12 +237,12 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, - ident=artiq_version, ethmac_nrxslots=4, ethmac_ntxslots=4, **kwargs) AMPSoC.__init__(self) RTMCommon.__init__(self) + add_identifier(self, suffix=".without-sawg" if not with_sawg else "") self.config["HMC830_REF"] = "100" platform = self.platform @@ -385,11 +384,11 @@ class Master(MiniSoC, AMPSoC): cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, - ident=artiq_version, ethmac_nrxslots=4, ethmac_ntxslots=4, **kwargs) AMPSoC.__init__(self) + add_identifier(self) platform = self.platform rtio_clk_freq = 150e6 @@ -504,9 +503,9 @@ class Satellite(BaseSoC, RTMCommon): cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, - ident=artiq_version, **kwargs) RTMCommon.__init__(self) + add_identifier(self, suffix=".without-sawg" if not with_sawg else "") self.config["HMC830_REF"] = "150" platform = self.platform From 123e7bc05478eb448a1239a4efdd5029606a09c8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 15 Jul 2018 17:38:09 +0800 Subject: [PATCH 1032/2457] pyon: sort string dicts by key when pretty-printing. Closes #1010 --- artiq/protocols/pyon.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/artiq/protocols/pyon.py b/artiq/protocols/pyon.py index 092e46b52..932e95996 100644 --- a/artiq/protocols/pyon.py +++ b/artiq/protocols/pyon.py @@ -17,6 +17,7 @@ function call syntax to express special data types. """ +from operator import itemgetter import base64 from fractions import Fraction from collections import OrderedDict @@ -113,15 +114,20 @@ class _Encoder: return r def encode_dict(self, x): + if self.pretty and all(k.__class__ == str for k in x.keys()): + items = lambda: sorted(x.items(), key=itemgetter(0)) + else: + items = x.items + r = "{" if not self.pretty or len(x) < 2: r += ", ".join([self.encode(k) + ": " + self.encode(v) - for k, v in x.items()]) + for k, v in items()]) else: self.indent_level += 1 r += "\n" first = True - for k, v in x.items(): + for k, v in items(): if not first: r += ",\n" first = False From b2695d03ed0a4d0ec9e510a5004bb844567b3d3d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 15 Jul 2018 17:38:29 +0800 Subject: [PATCH 1033/2457] sayma: remove with_sawg from Master variant --- artiq/gateware/targets/sayma_amc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index c52d8c3ca..78aef215b 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -379,7 +379,7 @@ class Master(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, with_sawg, **kwargs): + def __init__(self, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -624,7 +624,7 @@ def main(): elif variant == "masterdac": cls = MasterDAC elif variant == "master": - cls = Master + cls = lambda dummy_with_sawg, **kwargs: Master(**kwargs) elif variant == "satellite": cls = Satellite else: From 13984385a8c47f7cce1b7d449767dbe478d36340 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 15 Jul 2018 17:40:17 +0800 Subject: [PATCH 1034/2457] =?UTF-8?q?firmware:=20version=20=E2=86=92=20ide?= =?UTF-8?q?nt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- artiq/firmware/runtime/main.rs | 4 ++-- artiq/firmware/satman/main.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 26368104e..b1615753c 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -66,8 +66,8 @@ fn startup() { irq::set_ie(true); clock::init(); info!("ARTIQ runtime starting..."); - info!("software version {}", csr::CONFIG_IDENTIFIER_STR); - info!("gateware version {}", ident::read(&mut [0; 64])); + info!("software ident {}", csr::CONFIG_IDENTIFIER_STR); + info!("gateware ident {}", ident::read(&mut [0; 64])); match config::read_str("log_level", |r| r.map(|s| s.parse())) { Ok(Ok(log_level_filter)) => { diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index d74d0480d..f1b94849d 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -260,8 +260,8 @@ pub extern fn main() -> i32 { uart_logger::ConsoleLogger::register(); info!("ARTIQ satellite manager starting..."); - info!("software version {}", csr::CONFIG_IDENTIFIER_STR); - info!("gateware version {}", ident::read(&mut [0; 64])); + info!("software ident {}", csr::CONFIG_IDENTIFIER_STR); + info!("gateware ident {}", ident::read(&mut [0; 64])); #[cfg(has_slave_fpga_cfg)] board_artiq::slave_fpga::load().expect("cannot load RTM FPGA gateware"); From 3168b193e664d1ee83a0494d32bed451311bfdde Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Jul 2018 17:48:57 +0800 Subject: [PATCH 1035/2457] kc705: remove Zotino and Urukul * use Kasli instead for using EEMs * code required outdated VHDCI adapter 1.0 --- artiq/examples/kc705_nist_clock/device_db.py | 192 +------------------ artiq/gateware/targets/kc705.py | 129 +------------ doc/manual/core_device.rst | 29 +-- 3 files changed, 5 insertions(+), 345 deletions(-) diff --git a/artiq/examples/kc705_nist_clock/device_db.py b/artiq/examples/kc705_nist_clock/device_db.py index 78b21e82d..d741ceded 100644 --- a/artiq/examples/kc705_nist_clock/device_db.py +++ b/artiq/examples/kc705_nist_clock/device_db.py @@ -119,34 +119,6 @@ device_db = { "arguments": {"channel": 26} }, - # FMC DIO used to connect to Zotino - "fmcdio_dirctl_clk": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 27} - }, - "fmcdio_dirctl_ser": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 28} - }, - "fmcdio_dirctl_latch": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 29} - }, - "fmcdio_dirctl": { - "type": "local", - "module": "artiq.coredevice.shiftreg", - "class": "ShiftReg", - "arguments": {"clk": "fmcdio_dirctl_clk", - "ser": "fmcdio_dirctl_ser", - "latch": "fmcdio_dirctl_latch"} - }, - # DAC "spi_ams101": { "type": "local", @@ -160,184 +132,26 @@ device_db = { "class": "TTLOut", "arguments": {"channel": 20} }, - "spi_zotino": { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 30} - }, - "ttl_zotino_ldac": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 31} - }, - "dac_zotino": { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino", - "ldac_device": "ttl_zotino_ldac", - "div_write": 30, - "div_read": 40 - } - }, - - "spi_urukul": { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 32} - }, - "ttl_urukul_io_update": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 33} - }, - "ttl_urukul_sw0": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 35} - }, - "ttl_urukul_sw1": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 36} - }, - "ttl_urukul_sw2": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 37} - }, - "ttl_urukul_sw3": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 38} - }, - "urukul_cpld": { - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul", - "io_update_device": "ttl_urukul_io_update", - "refclk": 100e6 - } - }, - "urukul_ch0a": { - "type": "local", - "module": "artiq.coredevice.ad9912", - "class": "AD9912", - "arguments": { - "pll_n": 10, - "chip_select": 4, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw0" - } - }, - "urukul_ch1a": { - "type": "local", - "module": "artiq.coredevice.ad9912", - "class": "AD9912", - "arguments": { - "pll_n": 10, - "chip_select": 5, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw1" - } - }, - "urukul_ch2a": { - "type": "local", - "module": "artiq.coredevice.ad9912", - "class": "AD9912", - "arguments": { - "pll_n": 10, - "chip_select": 6, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw2" - } - }, - "urukul_ch3a": { - "type": "local", - "module": "artiq.coredevice.ad9912", - "class": "AD9912", - "arguments": { - "pll_n": 10, - "chip_select": 7, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw3" - } - }, - "urukul_ch0b": { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 40, - "chip_select": 4, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw0" - } - }, - "urukul_ch1b": { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 40, - "chip_select": 5, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw1" - } - }, - "urukul_ch2b": { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 40, - "chip_select": 6, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw2" - } - }, - "urukul_ch3b": { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 40, - "chip_select": 7, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw3" - } - }, # AD9914 DDS "dds0": { "type": "local", "module": "artiq.coredevice.ad9914", "class": "AD9914", - "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 0}, + "arguments": {"sysclk": 3e9, "bus_channel": 27, "channel": 0}, "comment": "Comments work in DDS panel as well" }, "dds1": { "type": "local", "module": "artiq.coredevice.ad9914", "class": "AD9914", - "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 1} + "arguments": {"sysclk": 3e9, "bus_channel": 27, "channel": 1} }, "dds2": { "type": "local", "module": "artiq.coredevice.ad9914", "class": "AD9914", - "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 2} + "arguments": {"sysclk": 3e9, "bus_channel": 27, "channel": 2} }, # Aliases diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index 795f3ee80..eb32aedb2 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -16,8 +16,7 @@ from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio, nist_clock, nist_qc2 -from artiq.gateware.rtio.phy import (ttl_simple, ttl_serdes_7series, - dds, spi2, ad53xx_monitor) +from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds, spi2 from artiq.build_soc import * @@ -109,99 +108,6 @@ _sdcard_spi_33 = [ ) ] -_zotino = [ - ("fmcdio_dirctl", 0, - Subsignal("clk", Pins("HPC:LA32_N")), - Subsignal("ser", Pins("HPC:LA33_P")), - Subsignal("latch", Pins("HPC:LA32_P")), - IOStandard("LVCMOS25") - ), - ("zotino_spi_p", 0, - Subsignal("clk", Pins("HPC:LA08_P")), - Subsignal("mosi", Pins("HPC:LA09_P")), - Subsignal("miso", Pins("HPC:LA10_P")), - Subsignal("cs_n", Pins("HPC:LA11_P")), - IOStandard("LVDS_25") - ), - ("zotino_spi_n", 0, - Subsignal("clk", Pins("HPC:LA08_N")), - Subsignal("mosi", Pins("HPC:LA09_N")), - Subsignal("miso", Pins("HPC:LA10_N")), - Subsignal("cs_n", Pins("HPC:LA11_N")), - IOStandard("LVDS_25") - ), - ("zotino_ldac", 0, - Subsignal("p", Pins("HPC:LA13_P")), - Subsignal("n", Pins("HPC:LA13_N")), - IOStandard("LVDS_25"), Misc("DIFF_TERM=TRUE") - ) -] - - -# FMC DIO 32ch LVDS a v1.2 on HPC to VHDCI-Carrier v1.1 -# uring the upper/right VHDCI connector: LVDS7 and LVDS8 -# using the lower/left VHDCI connector: LVDS3 and LVDS4 -_urukul = [ - ("urukul_spi_p", 0, - Subsignal("clk", Pins("HPC:LA17_CC_P")), - Subsignal("mosi", Pins("HPC:LA16_P")), - Subsignal("miso", Pins("HPC:LA24_P")), - Subsignal("cs_n", Pins("HPC:LA19_P HPC:LA20_P HPC:LA21_P")), - IOStandard("LVDS_25"), - ), - ("urukul_spi_n", 0, - Subsignal("clk", Pins("HPC:LA17_CC_N")), - Subsignal("mosi", Pins("HPC:LA16_N")), - Subsignal("miso", Pins("HPC:LA24_N")), - Subsignal("cs_n", Pins("HPC:LA19_N HPC:LA20_N HPC:LA21_N")), - IOStandard("LVDS_25"), - ), - ("urukul_io_update", 0, - Subsignal("p", Pins("HPC:LA22_P")), - Subsignal("n", Pins("HPC:LA22_N")), - IOStandard("LVDS_25"), - ), - ("urukul_dds_reset", 0, - Subsignal("p", Pins("HPC:LA23_P")), - Subsignal("n", Pins("HPC:LA23_N")), - IOStandard("LVDS_25"), - ), - ("urukul_sync_clk", 0, - Subsignal("p", Pins("HPC:LA18_CC_P")), - Subsignal("n", Pins("HPC:LA18_CC_N")), - IOStandard("LVDS_25"), - ), - ("urukul_sync_in", 0, - Subsignal("p", Pins("HPC:LA25_P")), - Subsignal("n", Pins("HPC:LA25_N")), - IOStandard("LVDS_25"), - ), - ("urukul_io_update_ret", 0, - Subsignal("p", Pins("HPC:LA26_P")), - Subsignal("n", Pins("HPC:LA26_N")), - IOStandard("LVDS_25"), - ), - ("urukul_sw0", 0, - Subsignal("p", Pins("HPC:LA28_P")), - Subsignal("n", Pins("HPC:LA28_N")), - IOStandard("LVDS_25"), - ), - ("urukul_sw1", 0, - Subsignal("p", Pins("HPC:LA29_P")), - Subsignal("n", Pins("HPC:LA29_N")), - IOStandard("LVDS_25"), - ), - ("urukul_sw2", 0, - Subsignal("p", Pins("HPC:LA30_P")), - Subsignal("n", Pins("HPC:LA30_N")), - IOStandard("LVDS_25"), - ), - ("urukul_sw3", 0, - Subsignal("p", Pins("HPC:LA31_P")), - Subsignal("n", Pins("HPC:LA31_N")), - IOStandard("LVDS_25"), - ) -] class _StandaloneBase(MiniSoC, AMPSoC): @@ -243,8 +149,6 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.platform.add_extension(_sma33_io) self.platform.add_extension(_ams101_dac) self.platform.add_extension(_sdcard_spi_33) - self.platform.add_extension(_zotino) - self.platform.add_extension(_urukul) i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) @@ -340,37 +244,6 @@ class NIST_CLOCK(_StandaloneBase): rtio_channels.append(rtio.Channel.from_phy( phy, ififo_depth=4)) - fmcdio_dirctl = self.platform.request("fmcdio_dirctl") - for s in fmcdio_dirctl.clk, fmcdio_dirctl.ser, fmcdio_dirctl.latch: - phy = ttl_simple.Output(s) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - sdac_phy = spi2.SPIMaster(self.platform.request("zotino_spi_p"), - self.platform.request("zotino_spi_n")) - self.submodules += sdac_phy - rtio_channels.append(rtio.Channel.from_phy(sdac_phy, ififo_depth=4)) - - pads = platform.request("zotino_ldac") - ldac_phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += ldac_phy - rtio_channels.append(rtio.Channel.from_phy(ldac_phy)) - - dac_monitor = ad53xx_monitor.AD53XXMonitor(sdac_phy.rtlink, ldac_phy.rtlink) - self.submodules += dac_monitor - sdac_phy.probes.extend(dac_monitor.probes) - - phy = spi2.SPIMaster(self.platform.request("urukul_spi_p"), - self.platform.request("urukul_spi_n")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - - for signal in "io_update dds_reset sw0 sw1 sw2 sw3".split(): - pads = platform.request("urukul_{}".format(signal)) - phy = ttl_serdes_7series.Output_8X(pads.p, pads.n) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - phy = dds.AD9914(platform.request("dds"), 11, onehot=True) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index e9dff441c..8ff53fcbf 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -68,26 +68,6 @@ With the CLOCK hardware, the TTL lines are mapped as follows: +--------------------+-----------------------+--------------+ | 21 | LA32_P | Clock | +--------------------+-----------------------+--------------+ -| 27 | FMCDIO_DIRCTL_CLK | Output | -+--------------------+-----------------------+--------------+ -| 28 | FMCDIO_DIRCTL_SER | Output | -+--------------------+-----------------------+--------------+ -| 29 | FMCDIO_DIRCTL_LATCH | Output | -+--------------------+-----------------------+--------------+ -| 31 | ZOTINO_LDAC | Output | -+--------------------+-----------------------+--------------+ -| 33 | URUKUL_IO_UPDATE | Output | -+--------------------+-----------------------+--------------+ -| 34 | URUKUL_DDS_RESET | Output | -+--------------------+-----------------------+--------------+ -| 35 | URUKUL_SW0 | Output | -+--------------------+-----------------------+--------------+ -| 36 | URUKUL_SW1 | Output | -+--------------------+-----------------------+--------------+ -| 37 | URUKUL_SW2 | Output | -+--------------------+-----------------------+--------------+ -| 38 | URUKUL_SW3 | Output | -+--------------------+-----------------------+--------------+ The board has RTIO SPI buses mapped as follows: @@ -104,16 +84,9 @@ The board has RTIO SPI buses mapped as follows: +--------------+------------------+--------------+--------------+------------+ | 26 | MMC_SPI_CS_N | MMC_SPI_MOSI | MMC_SPI_MISO | MMC_SPI_CLK| +--------------+------------------+--------------+--------------+------------+ -| 30 | ZOTINO_CS_N | ZOTINO_MOSI | ZOTINO_MISO | ZOTINO_CLK | -+--------------+------------------+--------------+--------------+------------+ -| 32 | URUKUL_CS_N[0:2] | URUKUL_MOSI | URUKUL_MISO | URUKUL_CLK | -+--------------+------------------+--------------+--------------+------------+ -The DDS bus is on channel 39. +The DDS bus is on channel 27. -This configuration supports a Zotino and/or an Urukul connected to the KC705 FMC HPC through a FMC DIO 32ch LVDS v1.2 and a VHDCI breakout board rev 1.0 or rev 1.1. On the VHDCI breakout board, the VHDCI cable to the KC705 should be plugged into to the bottom connector. The EEM cable to the Zotino should be connected to J41 and the EEM cables to Urukul to J42 and J43. - -The shift registers on the FMC card should be configured to set the directions of its LVDS buffers, using :mod:`artiq.coredevice.shiftreg`. NIST QC2 ++++++++ From 9b016dcd6d405e9693a8fafe3563f808caf531e2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Jul 2018 18:55:17 +0800 Subject: [PATCH 1036/2457] eem: support specifying I/O standard Xilinx FPGAs require different LVDS I/O standard names depending on I/O bank voltage. --- artiq/gateware/eem.py | 122 +++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 60 deletions(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 78155b19b..34680a714 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -21,25 +21,25 @@ def _eem_pin(eem, i, pol): class _EEM: @classmethod - def add_extension(cls, target, eem, *args): + def add_extension(cls, target, eem, *args, **kwargs): name = cls.__name__ - target.platform.add_extension(cls.io(eem, *args)) + target.platform.add_extension(cls.io(eem, *args, **kwargs)) print("{} (EEM{}) starting at RTIO channel {}" .format(name, eem, len(target.rtio_channels))) class DIO(_EEM): @staticmethod - def io(eem): + def io(eem, iostandard="LVDS_25"): return [("dio{}".format(eem), i, Subsignal("p", Pins(_eem_pin(eem, i, "p"))), Subsignal("n", Pins(_eem_pin(eem, i, "n"))), - IOStandard("LVDS_25")) + IOStandard(iostandard)) for i in range(8)] @classmethod - def add_std(cls, target, eem, ttl03_cls, ttl47_cls): - cls.add_extension(target, eem) + def add_std(cls, target, eem, ttl03_cls, ttl47_cls, iostandard="LVDS_25"): + cls.add_extension(target, eem, iostandard=iostandard) for i in range(4): pads = target.platform.request("dio{}".format(eem), i) @@ -55,7 +55,7 @@ class DIO(_EEM): class Urukul(_EEM): @staticmethod - def io(eem, eem_aux): + def io(eem, eem_aux, iostandard="LVDS_25"): ios = [ ("urukul{}_spi_p".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), @@ -63,7 +63,7 @@ class Urukul(_EEM): Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))), Subsignal("cs_n", Pins( *(_eem_pin(eem, i + 3, "p") for i in range(3)))), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ("urukul{}_spi_n".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), @@ -71,7 +71,7 @@ class Urukul(_EEM): Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))), Subsignal("cs_n", Pins( *(_eem_pin(eem, i + 3, "n") for i in range(3)))), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ] ttls = [(6, eem, "io_update"), @@ -90,26 +90,26 @@ class Urukul(_EEM): ("urukul{}_{}".format(eem, sig), 0, Subsignal("p", Pins(_eem_pin(j, i, "p"))), Subsignal("n", Pins(_eem_pin(j, i, "n"))), - IOStandard("LVDS_25") + IOStandard(iostandard) )) return ios @staticmethod - def io_qspi(eem0, eem1): + def io_qspi(eem0, eem1, iostandard="LVDS_25"): ios = [ ("urukul{}_spi_p".format(eem0), 0, Subsignal("clk", Pins(_eem_pin(eem0, 0, "p"))), Subsignal("mosi", Pins(_eem_pin(eem0, 1, "p"))), Subsignal("cs_n", Pins( _eem_pin(eem0, 3, "p"), _eem_pin(eem0, 4, "p"))), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ("urukul{}_spi_n".format(eem0), 0, Subsignal("clk", Pins(_eem_pin(eem0, 0, "n"))), Subsignal("mosi", Pins(_eem_pin(eem0, 1, "n"))), Subsignal("cs_n", Pins( _eem_pin(eem0, 3, "n"), _eem_pin(eem0, 4, "n"))), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ] ttls = [(6, eem0, "io_update"), @@ -123,7 +123,7 @@ class Urukul(_EEM): ("urukul{}_{}".format(eem0, sig), 0, Subsignal("p", Pins(_eem_pin(j, i, "p"))), Subsignal("n", Pins(_eem_pin(j, i, "n"))), - IOStandard("LVDS_25") + IOStandard(iostandard) )) ios += [ ("urukul{}_qspi_p".format(eem0), 0, @@ -133,7 +133,7 @@ class Urukul(_EEM): Subsignal("mosi1", Pins(_eem_pin(eem1, 1, "p"))), Subsignal("mosi2", Pins(_eem_pin(eem1, 2, "p"))), Subsignal("mosi3", Pins(_eem_pin(eem1, 3, "p"))), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ("urukul{}_qspi_n".format(eem0), 0, Subsignal("cs", Pins(_eem_pin(eem0, 5, "n"))), @@ -142,14 +142,14 @@ class Urukul(_EEM): Subsignal("mosi1", Pins(_eem_pin(eem1, 1, "n"))), Subsignal("mosi2", Pins(_eem_pin(eem1, 2, "n"))), Subsignal("mosi3", Pins(_eem_pin(eem1, 3, "n"))), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ] return ios @classmethod - def add_std(cls, target, eem, eem_aux, ttl_out_cls): - cls.add_extension(target, eem, eem_aux) + def add_std(cls, target, eem, eem_aux, ttl_out_cls, iostandard="LVDS_25"): + cls.add_extension(target, eem, eem_aux, iostandard=iostandard) phy = spi2.SPIMaster(target.platform.request("urukul{}_spi_p".format(eem)), target.platform.request("urukul{}_spi_n".format(eem))) @@ -173,41 +173,41 @@ class Urukul(_EEM): class Sampler(_EEM): @staticmethod - def io(eem, eem_aux): + def io(eem, eem_aux, iostandard="LVDS_25"): ios = [ ("sampler{}_adc_spi_p".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), Subsignal("miso", Pins(_eem_pin(eem, 1, "p"))), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ("sampler{}_adc_spi_n".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), Subsignal("miso", Pins(_eem_pin(eem, 1, "n"))), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ("sampler{}_pgia_spi_p".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 4, "p"))), Subsignal("mosi", Pins(_eem_pin(eem, 5, "p"))), Subsignal("miso", Pins(_eem_pin(eem, 6, "p"))), Subsignal("cs_n", Pins(_eem_pin(eem, 7, "p"))), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ("sampler{}_pgia_spi_n".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 4, "n"))), Subsignal("mosi", Pins(_eem_pin(eem, 5, "n"))), Subsignal("miso", Pins(_eem_pin(eem, 6, "n"))), Subsignal("cs_n", Pins(_eem_pin(eem, 7, "n"))), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ] + [ ("sampler{}_{}".format(eem, sig), 0, Subsignal("p", Pins(_eem_pin(j, i, "p"))), Subsignal("n", Pins(_eem_pin(j, i, "n"))), - IOStandard("LVDS_25") + IOStandard(iostandard) ) for i, j, sig in [ (2, eem, "sdr"), (3, eem, "cnv") - ] + ] ] if eem_aux is not None: ios += [ @@ -218,7 +218,7 @@ class Sampler(_EEM): Subsignal("sdoc", Pins(_eem_pin(eem_aux, 3, "p"))), Subsignal("sdod", Pins(_eem_pin(eem_aux, 4, "p"))), Misc("DIFF_TERM=TRUE"), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ("sampler{}_adc_data_n".format(eem), 0, Subsignal("clkout", Pins(_eem_pin(eem_aux, 0, "n"))), @@ -227,14 +227,14 @@ class Sampler(_EEM): Subsignal("sdoc", Pins(_eem_pin(eem_aux, 3, "n"))), Subsignal("sdod", Pins(_eem_pin(eem_aux, 4, "n"))), Misc("DIFF_TERM=TRUE"), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ] return ios @classmethod - def add_std(cls, target, eem, eem_aux, ttl_out_cls): - cls.add_extension(target, eem, eem_aux) + def add_std(cls, target, eem, eem_aux, ttl_out_cls, iostandard="LVDS_25"): + cls.add_extension(target, eem, eem_aux, iostandard=iostandard) phy = spi2.SPIMaster( target.platform.request("sampler{}_adc_spi_p".format(eem)), @@ -258,7 +258,7 @@ class Sampler(_EEM): class Novogorny(_EEM): @staticmethod - def io(eem): + def io(eem, iostandard="LVDS_25"): return [ ("novogorny{}_spi_p".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), @@ -266,7 +266,7 @@ class Novogorny(_EEM): Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))), Subsignal("cs_n", Pins( _eem_pin(eem, 3, "p"), _eem_pin(eem, 4, "p"))), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ("novogorny{}_spi_n".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), @@ -274,23 +274,23 @@ class Novogorny(_EEM): Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))), Subsignal("cs_n", Pins( _eem_pin(eem, 3, "n"), _eem_pin(eem, 4, "n"))), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ] + [ ("novogorny{}_{}".format(eem, sig), 0, Subsignal("p", Pins(_eem_pin(j, i, "p"))), Subsignal("n", Pins(_eem_pin(j, i, "n"))), - IOStandard("LVDS_25") + IOStandard(iostandard) ) for i, j, sig in [ (5, eem, "cnv"), (6, eem, "busy"), (7, eem, "scko"), - ] + ] ] @classmethod - def add_std(cls, target, eem, ttl_out_cls): - cls.add_extension(target, eem) + def add_std(cls, target, eem, ttl_out_cls, iostandard="LVDS_25"): + cls.add_extension(target, eem, iostandard=iostandard) phy = spi2.SPIMaster(target.platform.request("novogorny{}_spi_p".format(eem)), target.platform.request("novogorny{}_spi_n".format(eem))) @@ -305,7 +305,7 @@ class Novogorny(_EEM): class Zotino(_EEM): @staticmethod - def io(eem): + def io(eem, iostandard="LVDS_25"): return [ ("zotino{}_spi_p".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), @@ -313,7 +313,7 @@ class Zotino(_EEM): Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))), Subsignal("cs_n", Pins( _eem_pin(eem, 3, "p"), _eem_pin(eem, 4, "p"))), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ("zotino{}_spi_n".format(eem), 0, Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), @@ -321,23 +321,23 @@ class Zotino(_EEM): Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))), Subsignal("cs_n", Pins( _eem_pin(eem, 3, "n"), _eem_pin(eem, 4, "n"))), - IOStandard("LVDS_25"), + IOStandard(iostandard), ), ] + [ ("zotino{}_{}".format(eem, sig), 0, Subsignal("p", Pins(_eem_pin(j, i, "p"))), Subsignal("n", Pins(_eem_pin(j, i, "n"))), - IOStandard("LVDS_25") + IOStandard(iostandard) ) for i, j, sig in [ (5, eem, "ldac_n"), (6, eem, "busy"), (7, eem, "clr_n"), - ] + ] ] @classmethod - def add_std(cls, target, eem, ttl_out_cls): - cls.add_extension(target, eem) + def add_std(cls, target, eem, ttl_out_cls, iostandard="LVDS_25"): + cls.add_extension(target, eem, iostandard=iostandard) spi_phy = spi2.SPIMaster(target.platform.request("zotino{}_spi_p".format(eem)), target.platform.request("zotino{}_spi_n".format(eem))) @@ -361,29 +361,29 @@ class Zotino(_EEM): class Grabber(_EEM): @staticmethod - def io(eem, eem_aux): + def io(eem, eem_aux, iostandard="LVDS_25"): ios = [ ("grabber{}_video".format(eem), 0, Subsignal("clk_p", Pins(_eem_pin(eem, 0, "p"))), Subsignal("clk_n", Pins(_eem_pin(eem, 0, "n"))), Subsignal("sdi_p", Pins(*[_eem_pin(eem, i, "p") for i in range(1, 5)])), Subsignal("sdi_n", Pins(*[_eem_pin(eem, i, "n") for i in range(1, 5)])), - IOStandard("LVDS_25"), Misc("DIFF_TERM=TRUE") + IOStandard(iostandard), Misc("DIFF_TERM=TRUE") ), ("grabber{}_cc0".format(eem), 0, Subsignal("p", Pins(_eem_pin(eem_aux, 5, "p"))), Subsignal("n", Pins(_eem_pin(eem_aux, 5, "n"))), - IOStandard("LVDS_25") + IOStandard(iostandard) ), ("grabber{}_cc1".format(eem), 0, Subsignal("p", Pins(_eem_pin(eem_aux, 6, "p"))), Subsignal("n", Pins(_eem_pin(eem_aux, 6, "n"))), - IOStandard("LVDS_25") + IOStandard(iostandard) ), ("grabber{}_cc2".format(eem), 0, Subsignal("p", Pins(_eem_pin(eem_aux, 7, "p"))), Subsignal("n", Pins(_eem_pin(eem_aux, 7, "n"))), - IOStandard("LVDS_25") + IOStandard(iostandard) ), ] if eem_aux is not None: @@ -393,29 +393,29 @@ class Grabber(_EEM): Subsignal("clk_n", Pins(_eem_pin(eem_aux, 0, "n"))), Subsignal("sdi_p", Pins(*[_eem_pin(eem_aux, i, "p") for i in range(1, 5)])), Subsignal("sdi_n", Pins(*[_eem_pin(eem_aux, i, "n") for i in range(1, 5)])), - IOStandard("LVDS_25"), Misc("DIFF_TERM=TRUE") + IOStandard(iostandard), Misc("DIFF_TERM=TRUE") ), ("grabber{}_serrx".format(eem), 0, Subsignal("p", Pins(_eem_pin(eem_aux, 5, "p"))), Subsignal("n", Pins(_eem_pin(eem_aux, 5, "n"))), - IOStandard("LVDS_25"), Misc("DIFF_TERM=TRUE") + IOStandard(iostandard), Misc("DIFF_TERM=TRUE") ), ("grabber{}_sertx".format(eem), 0, Subsignal("p", Pins(_eem_pin(eem_aux, 6, "p"))), Subsignal("n", Pins(_eem_pin(eem_aux, 6, "n"))), - IOStandard("LVDS_25") + IOStandard(iostandard) ), ("grabber{}_cc3".format(eem), 0, Subsignal("p", Pins(_eem_pin(eem_aux, 7, "p"))), Subsignal("n", Pins(_eem_pin(eem_aux, 7, "n"))), - IOStandard("LVDS_25") + IOStandard(iostandard) ), ] return ios @classmethod - def add_std(cls, target, eem, eem_aux=None, ttl_out_cls=None): - cls.add_extension(target, eem, eem_aux) + def add_std(cls, target, eem, eem_aux=None, ttl_out_cls=None, iostandard="LVDS_25"): + cls.add_extension(target, eem, eem_aux, iostandard=iostandard) pads = target.platform.request("grabber{}_video".format(eem)) target.platform.add_period_constraint(pads.clk_p, 14.71) @@ -452,15 +452,16 @@ class Grabber(_EEM): class SUServo(_EEM): @staticmethod - def io(*eems): + def io(*eems, iostandard="LVDS_25"): assert len(eems) == 6 - return (Sampler.io(*eems[0:2]) - + Urukul.io_qspi(*eems[2:4]) - + Urukul.io_qspi(*eems[4:6])) + return (Sampler.io(*eems[0:2], iostandard=iostandard) + + Urukul.io_qspi(*eems[2:4], iostandard=iostandard) + + Urukul.io_qspi(*eems[4:6], iostandard=iostandard)) @classmethod def add_std(cls, target, eems_sampler, eems_urukul0, eems_urukul1, - t_rtt=4, clk=1, shift=11, profile=5): + t_rtt=4, clk=1, shift=11, profile=5, + iostandard="LVDS_25"): """Add a 8-channel Sampler-Urukul Servo :param t_rtt: upper estimate for clock round-trip propagation time from @@ -478,7 +479,8 @@ class SUServo(_EEM): (default: 5) """ cls.add_extension( - target, *(eems_sampler + eems_urukul0 + eems_urukul1)) + target, *(eems_sampler + eems_urukul0 + eems_urukul1), + iostandard=iostandard) eem_sampler = "sampler{}".format(eems_sampler[0]) eem_urukul0 = "urukul{}".format(eems_urukul0[0]) eem_urukul1 = "urukul{}".format(eems_urukul1[0]) From 3645a6424e57459d337fac2d1dd99395f60d25cd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Jul 2018 18:56:33 +0800 Subject: [PATCH 1037/2457] sayma: fix Master build --- artiq/gateware/targets/sayma_amc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 78aef215b..03fc9928b 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -624,7 +624,7 @@ def main(): elif variant == "masterdac": cls = MasterDAC elif variant == "master": - cls = lambda dummy_with_sawg, **kwargs: Master(**kwargs) + cls = lambda with_sawg, **kwargs: Master(**kwargs) elif variant == "satellite": cls = Satellite else: From a0f2d8c2eaa6f5f6e23b1f81f49804c90409259f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Jul 2018 18:58:16 +0800 Subject: [PATCH 1038/2457] gateware: add FMCDIO/EEM adapter definitions --- artiq/gateware/fmcdio_vhdci_eem.py | 90 ++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 artiq/gateware/fmcdio_vhdci_eem.py diff --git a/artiq/gateware/fmcdio_vhdci_eem.py b/artiq/gateware/fmcdio_vhdci_eem.py new file mode 100644 index 000000000..17d7f2c76 --- /dev/null +++ b/artiq/gateware/fmcdio_vhdci_eem.py @@ -0,0 +1,90 @@ +from migen.build.generic_platform import * + + +io = [ + ("fmcdio_dirctl", 0, + Subsignal("clk", Pins("LPC:LA32_N")), + Subsignal("ser", Pins("LPC:LA33_P")), + Subsignal("latch", Pins("LPC:LA32_P")), + IOStandard("LVCMOS25") + ), +] + + +connectors = [ + ("eem0", { + "d0_cc_n": "LPC:LA00_CC_N", + "d0_cc_p": "LPC:LA00_CC_P", + "d1_n": "LPC:LA08_N", + "d1_p": "LPC:LA08_P", + "d2_n": "LPC:LA02_N", + "d2_p": "LPC:LA02_P", + "d3_n": "LPC:LA03_N", + "d3_p": "LPC:LA03_P", + "d4_n": "LPC:LA04_N", + "d4_p": "LPC:LA04_P", + "d5_n": "LPC:LA05_N", + "d5_p": "LPC:LA05_P", + "d6_n": "LPC:LA06_N", + "d6_p": "LPC:LA06_P", + "d7_n": "LPC:LA07_N", + "d7_p": "LPC:LA07_P", + }), + + ("eem1", { + "d0_cc_n": "LPC:LA01_CC_N", + "d0_cc_p": "LPC:LA01_CC_P", + "d1_n": "LPC:LA09_N", + "d1_p": "LPC:LA09_P", + "d2_n": "LPC:LA10_N", + "d2_p": "LPC:LA10_P", + "d3_n": "LPC:LA11_N", + "d3_p": "LPC:LA11_P", + "d4_n": "LPC:LA12_N", + "d4_p": "LPC:LA12_P", + "d5_n": "LPC:LA13_N", + "d5_p": "LPC:LA13_P", + "d6_n": "LPC:LA14_N", + "d6_p": "LPC:LA14_P", + "d7_n": "LPC:LA15_N", + "d7_p": "LPC:LA15_P", + }), + + ("eem2", { + "d0_cc_n": "LPC:LA17_CC_P", + "d0_cc_p": "LPC:LA17_CC_N", + "d1_n": "LPC:LA16_N", + "d1_p": "LPC:LA16_P", + "d2_n": "LPC:LA24_N", + "d2_p": "LPC:LA24_P", + "d3_n": "LPC:LA19_N", + "d3_p": "LPC:LA19_P", + "d4_n": "LPC:LA20_N", + "d4_p": "LPC:LA20_P", + "d5_n": "LPC:LA21_N", + "d5_p": "LPC:LA21_P", + "d6_n": "LPC:LA22_N", + "d6_p": "LPC:LA22_P", + "d7_n": "LPC:LA23_N", + "d7_p": "LPC:LA23_P", + }), + + ("eem3", { + "d0_cc_n": "LPC:LA18_CC_N", + "d0_cc_p": "LPC:LA18_CC_N", + "d1_n": "LPC:LA25_N", + "d1_p": "LPC:LA25_P", + "d2_n": "LPC:LA26_N", + "d2_p": "LPC:LA26_P", + "d3_n": "LPC:LA27_N", + "d3_p": "LPC:LA27_P", + "d4_n": "LPC:LA28_N", + "d4_p": "LPC:LA28_P", + "d5_n": "LPC:LA29_N", + "d5_p": "LPC:LA29_P", + "d6_n": "LPC:LA30_N", + "d6_p": "LPC:LA30_P", + "d7_n": "LPC:LA31_N", + "d7_p": "LPC:LA31_P", + }), +] From d724bd980cec01729227d1d5b3a1a33c625749e6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Jul 2018 18:58:23 +0800 Subject: [PATCH 1039/2457] sayma: add EEMs to Master --- artiq/gateware/targets/sayma_amc.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 03fc9928b..219def0fe 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -13,8 +13,9 @@ from misoc.interconnect.csr import * from misoc.targets.sayma_amc import BaseSoC, MiniSoC from artiq.gateware.amp import AMPSoC -from artiq.gateware import serwb -from artiq.gateware import remote_csr +from artiq.gateware import eem +from artiq.gateware import fmcdio_vhdci_eem +from artiq.gateware import serwb, remote_csr from artiq.gateware import rtio from artiq.gateware import jesd204_tools from artiq.gateware.rtio.phy import ttl_simple, sawg @@ -450,7 +451,7 @@ class Master(MiniSoC, AMPSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gth.rxoutclk) - rtio_channels = [] + self.rtio_channels = rtio_channels = [] for i in range(4): phy = ttl_simple.Output(platform.request("user_led", i)) self.submodules += phy @@ -466,6 +467,20 @@ class Master(MiniSoC, AMPSoC): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) + platform.add_extension(fmcdio_vhdci_eem.io) + platform.add_connectors(fmcdio_vhdci_eem.connectors) + fmcdio_dirctl = platform.request("fmcdio_dirctl") + for s in fmcdio_dirctl.clk, fmcdio_dirctl.ser, fmcdio_dirctl.latch: + phy = ttl_simple.Output(s) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + eem.Urukul.add_std(self, 1, 0, ttl_simple.Output, + iostandard="LVDS") + eem.DIO.add_std(self, 2, ttl_simple.Output, ttl_simple.Output, + iostandard="LVDS") + eem.Zotino.add_std(self, 3, ttl_simple.Output, + iostandard="LVDS") + self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) rtio_channels.append(rtio.LogChannel()) From 8f7c0c1646ff2195859b9c29423c88ba738a4cbf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Jul 2018 19:40:34 +0800 Subject: [PATCH 1040/2457] fmcdio_vhdci_eem: fix iostandard --- artiq/gateware/fmcdio_vhdci_eem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/fmcdio_vhdci_eem.py b/artiq/gateware/fmcdio_vhdci_eem.py index 17d7f2c76..65cd789a6 100644 --- a/artiq/gateware/fmcdio_vhdci_eem.py +++ b/artiq/gateware/fmcdio_vhdci_eem.py @@ -6,7 +6,7 @@ io = [ Subsignal("clk", Pins("LPC:LA32_N")), Subsignal("ser", Pins("LPC:LA33_P")), Subsignal("latch", Pins("LPC:LA32_P")), - IOStandard("LVCMOS25") + IOStandard("LVCMOS18") ), ] From 8335085fd63f6f61b0eaa8a4b84e37a1b6a7c271 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Jul 2018 19:50:34 +0800 Subject: [PATCH 1041/2457] fmcdio_vhdci_eem: fix cc pins --- artiq/gateware/fmcdio_vhdci_eem.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/fmcdio_vhdci_eem.py b/artiq/gateware/fmcdio_vhdci_eem.py index 65cd789a6..7acb3db34 100644 --- a/artiq/gateware/fmcdio_vhdci_eem.py +++ b/artiq/gateware/fmcdio_vhdci_eem.py @@ -51,8 +51,8 @@ connectors = [ }), ("eem2", { - "d0_cc_n": "LPC:LA17_CC_P", - "d0_cc_p": "LPC:LA17_CC_N", + "d0_cc_n": "LPC:LA17_CC_N", + "d0_cc_p": "LPC:LA17_CC_P", "d1_n": "LPC:LA16_N", "d1_p": "LPC:LA16_P", "d2_n": "LPC:LA24_N", @@ -71,7 +71,7 @@ connectors = [ ("eem3", { "d0_cc_n": "LPC:LA18_CC_N", - "d0_cc_p": "LPC:LA18_CC_N", + "d0_cc_p": "LPC:LA18_CC_P", "d1_n": "LPC:LA25_N", "d1_p": "LPC:LA25_P", "d2_n": "LPC:LA26_N", From 4fdc20bb11762266147315f3bc8b576ec782dbf5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Jul 2018 20:08:21 +0800 Subject: [PATCH 1042/2457] sayma: disable Urukul and Zotino for now Ultrascale I/Os are being a pain as usual and the SPI core won't compile. --- artiq/gateware/targets/sayma_amc.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 219def0fe..91605cd50 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -474,12 +474,12 @@ class Master(MiniSoC, AMPSoC): phy = ttl_simple.Output(s) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - eem.Urukul.add_std(self, 1, 0, ttl_simple.Output, - iostandard="LVDS") + #eem.Urukul.add_std(self, 1, 0, ttl_simple.Output, + # iostandard="LVDS") eem.DIO.add_std(self, 2, ttl_simple.Output, ttl_simple.Output, iostandard="LVDS") - eem.Zotino.add_std(self, 3, ttl_simple.Output, - iostandard="LVDS") + #eem.Zotino.add_std(self, 3, ttl_simple.Output, + # iostandard="LVDS") self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) From d4d12e264dabdd42521467ce6e56efcf4a5a1651 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Jul 2018 20:13:57 +0800 Subject: [PATCH 1043/2457] fmcdio_vhdci_eem: refactor This allows access to the pin allocation from kernels, which becomes useful to configure the direction shift register. --- artiq/coredevice/fmcdio_vhdci_eem.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 artiq/coredevice/fmcdio_vhdci_eem.py diff --git a/artiq/coredevice/fmcdio_vhdci_eem.py b/artiq/coredevice/fmcdio_vhdci_eem.py new file mode 100644 index 000000000..cdf874b58 --- /dev/null +++ b/artiq/coredevice/fmcdio_vhdci_eem.py @@ -0,0 +1,6 @@ +eem_fmc_connections = { + 0: [0, 8, 2, 3, 4, 5, 6, 7], + 1: [1, 9, 10, 11, 12, 13, 14, 15], + 2: [17, 16, 24, 19, 20, 21, 22, 23], + 3: [18, 25, 26, 27, 28, 29, 30, 31], +} From 7fe76426fe5598fee21a120dff5cbdf1928abb61 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Jul 2018 20:30:13 +0800 Subject: [PATCH 1044/2457] fmcdio_vhdci_eem: commit missing part of previous commit --- artiq/gateware/fmcdio_vhdci_eem.py | 90 +++++------------------------- 1 file changed, 14 insertions(+), 76 deletions(-) diff --git a/artiq/gateware/fmcdio_vhdci_eem.py b/artiq/gateware/fmcdio_vhdci_eem.py index 7acb3db34..c1ab62864 100644 --- a/artiq/gateware/fmcdio_vhdci_eem.py +++ b/artiq/gateware/fmcdio_vhdci_eem.py @@ -1,5 +1,7 @@ from migen.build.generic_platform import * +from artiq.coredevice.fmcdio_vhdci_eem import * + io = [ ("fmcdio_dirctl", 0, @@ -10,81 +12,17 @@ io = [ ), ] +def _get_connectors(): + connectors = [] + for i in range(4): + connections = dict() + for j, pair in enumerate(eem_fmc_connections[i]): + for pn in "n", "p": + cc = "cc_" if j == 0 else "" + connections["d{}_{}{}".format(j, cc, pn)] = \ + "LPC:LA{:02d}_{}{}".format(pair, cc.upper(), pn.upper()) + connectors.append(("eem{}".format(i), connections)) + return connectors -connectors = [ - ("eem0", { - "d0_cc_n": "LPC:LA00_CC_N", - "d0_cc_p": "LPC:LA00_CC_P", - "d1_n": "LPC:LA08_N", - "d1_p": "LPC:LA08_P", - "d2_n": "LPC:LA02_N", - "d2_p": "LPC:LA02_P", - "d3_n": "LPC:LA03_N", - "d3_p": "LPC:LA03_P", - "d4_n": "LPC:LA04_N", - "d4_p": "LPC:LA04_P", - "d5_n": "LPC:LA05_N", - "d5_p": "LPC:LA05_P", - "d6_n": "LPC:LA06_N", - "d6_p": "LPC:LA06_P", - "d7_n": "LPC:LA07_N", - "d7_p": "LPC:LA07_P", - }), - ("eem1", { - "d0_cc_n": "LPC:LA01_CC_N", - "d0_cc_p": "LPC:LA01_CC_P", - "d1_n": "LPC:LA09_N", - "d1_p": "LPC:LA09_P", - "d2_n": "LPC:LA10_N", - "d2_p": "LPC:LA10_P", - "d3_n": "LPC:LA11_N", - "d3_p": "LPC:LA11_P", - "d4_n": "LPC:LA12_N", - "d4_p": "LPC:LA12_P", - "d5_n": "LPC:LA13_N", - "d5_p": "LPC:LA13_P", - "d6_n": "LPC:LA14_N", - "d6_p": "LPC:LA14_P", - "d7_n": "LPC:LA15_N", - "d7_p": "LPC:LA15_P", - }), - - ("eem2", { - "d0_cc_n": "LPC:LA17_CC_N", - "d0_cc_p": "LPC:LA17_CC_P", - "d1_n": "LPC:LA16_N", - "d1_p": "LPC:LA16_P", - "d2_n": "LPC:LA24_N", - "d2_p": "LPC:LA24_P", - "d3_n": "LPC:LA19_N", - "d3_p": "LPC:LA19_P", - "d4_n": "LPC:LA20_N", - "d4_p": "LPC:LA20_P", - "d5_n": "LPC:LA21_N", - "d5_p": "LPC:LA21_P", - "d6_n": "LPC:LA22_N", - "d6_p": "LPC:LA22_P", - "d7_n": "LPC:LA23_N", - "d7_p": "LPC:LA23_P", - }), - - ("eem3", { - "d0_cc_n": "LPC:LA18_CC_N", - "d0_cc_p": "LPC:LA18_CC_P", - "d1_n": "LPC:LA25_N", - "d1_p": "LPC:LA25_P", - "d2_n": "LPC:LA26_N", - "d2_p": "LPC:LA26_P", - "d3_n": "LPC:LA27_N", - "d3_p": "LPC:LA27_P", - "d4_n": "LPC:LA28_N", - "d4_p": "LPC:LA28_P", - "d5_n": "LPC:LA29_N", - "d5_p": "LPC:LA29_P", - "d6_n": "LPC:LA30_N", - "d6_p": "LPC:LA30_P", - "d7_n": "LPC:LA31_N", - "d7_p": "LPC:LA31_P", - }), -] +connectors = _get_connectors() From c7d96c222303f709f4767b5b99657a0dbcd8c365 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Jul 2018 20:30:23 +0800 Subject: [PATCH 1045/2457] conda: bump migen --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 7fc0d5828..38885177d 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_70+git1ec3ea9 + - migen 0.7 py35_73+gitbef9dea - misoc 0.11 py35_27+git37dfced7 - jesd204b 0.7 - microscope From 82145b126360b7e1db95906ac47abaa321b36729 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Jul 2018 20:32:30 +0800 Subject: [PATCH 1046/2457] =?UTF-8?q?examples:=20sayma=5Fdrtio=20=E2=86=92?= =?UTF-8?q?=20sayma=5Fmasterdac?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- artiq/examples/{sayma_drtio => sayma_masterdac}/device_db.py | 0 .../{sayma_drtio => sayma_masterdac}/repository/ad9154_spi.py | 0 .../{sayma_drtio => sayma_masterdac}/repository/blink_forever.py | 0 .../{sayma_drtio => sayma_masterdac}/repository/pulse_rate.py | 0 .../{sayma_drtio => sayma_masterdac}/repository/sines_drtio.py | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename artiq/examples/{sayma_drtio => sayma_masterdac}/device_db.py (100%) rename artiq/examples/{sayma_drtio => sayma_masterdac}/repository/ad9154_spi.py (100%) rename artiq/examples/{sayma_drtio => sayma_masterdac}/repository/blink_forever.py (100%) rename artiq/examples/{sayma_drtio => sayma_masterdac}/repository/pulse_rate.py (100%) rename artiq/examples/{sayma_drtio => sayma_masterdac}/repository/sines_drtio.py (100%) diff --git a/artiq/examples/sayma_drtio/device_db.py b/artiq/examples/sayma_masterdac/device_db.py similarity index 100% rename from artiq/examples/sayma_drtio/device_db.py rename to artiq/examples/sayma_masterdac/device_db.py diff --git a/artiq/examples/sayma_drtio/repository/ad9154_spi.py b/artiq/examples/sayma_masterdac/repository/ad9154_spi.py similarity index 100% rename from artiq/examples/sayma_drtio/repository/ad9154_spi.py rename to artiq/examples/sayma_masterdac/repository/ad9154_spi.py diff --git a/artiq/examples/sayma_drtio/repository/blink_forever.py b/artiq/examples/sayma_masterdac/repository/blink_forever.py similarity index 100% rename from artiq/examples/sayma_drtio/repository/blink_forever.py rename to artiq/examples/sayma_masterdac/repository/blink_forever.py diff --git a/artiq/examples/sayma_drtio/repository/pulse_rate.py b/artiq/examples/sayma_masterdac/repository/pulse_rate.py similarity index 100% rename from artiq/examples/sayma_drtio/repository/pulse_rate.py rename to artiq/examples/sayma_masterdac/repository/pulse_rate.py diff --git a/artiq/examples/sayma_drtio/repository/sines_drtio.py b/artiq/examples/sayma_masterdac/repository/sines_drtio.py similarity index 100% rename from artiq/examples/sayma_drtio/repository/sines_drtio.py rename to artiq/examples/sayma_masterdac/repository/sines_drtio.py From 8b9a8be12a09895ddef108049b700ab621497dd2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Jul 2018 23:27:29 +0800 Subject: [PATCH 1047/2457] fmcdio_vhdci_eem: add dirctl word computation functions --- artiq/coredevice/fmcdio_vhdci_eem.py | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/artiq/coredevice/fmcdio_vhdci_eem.py b/artiq/coredevice/fmcdio_vhdci_eem.py index cdf874b58..13d6224b0 100644 --- a/artiq/coredevice/fmcdio_vhdci_eem.py +++ b/artiq/coredevice/fmcdio_vhdci_eem.py @@ -4,3 +4,36 @@ eem_fmc_connections = { 2: [17, 16, 24, 19, 20, 21, 22, 23], 3: [18, 25, 26, 27, 28, 29, 30, 31], } + + +def shiftreg_bits(eem, out_pins): + r = 0 + for i in range(8): + if i in out_pins: + shift = eem_fmc_connections[eem][i] + r |= 1 << shift + return r + + +dio_bank0_out_pins = set(range(4)) +dio_bank1_out_pins = set(range(4, 8)) +urukul_out_pins = { + 0, # clk + 1, # mosi + 3, 4, 5, # cs_n + 6, # io_update + 7, # dds_reset +} +urukul_out_pins_aux = { + 4, # sw0 + 5, # sw1 + 6, # sw2 + 7, # sw3 +} +zotino_out_pins = { + 0, # clk + 1, # mosi + 3, 4, # cs_n + 5, # ldac_n + 7, # clr_n +} From 5e62910a8d14690a8a7293414726b409ea443cc7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Jul 2018 23:27:56 +0800 Subject: [PATCH 1048/2457] examples: add Sayma VHDCI DIO --- artiq/examples/sayma_master/device_db.py | 61 +++++++++++++++++++ .../examples/sayma_master/repository/demo.py | 25 ++++++++ 2 files changed, 86 insertions(+) create mode 100644 artiq/examples/sayma_master/device_db.py create mode 100644 artiq/examples/sayma_master/repository/demo.py diff --git a/artiq/examples/sayma_master/device_db.py b/artiq/examples/sayma_master/device_db.py new file mode 100644 index 000000000..9b6b24df3 --- /dev/null +++ b/artiq/examples/sayma_master/device_db.py @@ -0,0 +1,61 @@ +core_addr = "sayma-1.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1/(8*150e6)} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "fmcdio_dirctl_clk": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 6} + }, + "fmcdio_dirctl_ser": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 7} + }, + "fmcdio_dirctl_latch": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 8} + }, + "fmcdio_dirctl": { + "type": "local", + "module": "artiq.coredevice.shiftreg", + "class": "ShiftReg", + "arguments": {"clk": "fmcdio_dirctl_clk", + "ser": "fmcdio_dirctl_ser", + "latch": "fmcdio_dirctl_latch"} + }, +} + +for i in range(8): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 9+i}, + } diff --git a/artiq/examples/sayma_master/repository/demo.py b/artiq/examples/sayma_master/repository/demo.py new file mode 100644 index 000000000..23add53c2 --- /dev/null +++ b/artiq/examples/sayma_master/repository/demo.py @@ -0,0 +1,25 @@ +from artiq.experiment import * +from artiq.coredevice.fmcdio_vhdci_eem import * + + +class Demo(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("fmcdio_dirctl") + + self.ttls = [self.get_device("ttl" + str(i)) for i in range(8)] + + self.dirctl_word = ( + shiftreg_bits(2, dio_bank0_out_pins) | + shiftreg_bits(2, dio_bank1_out_pins)) + + @kernel + def run(self): + self.core.reset() + delay(10*ms) + self.fmcdio_dirctl.set(self.dirctl_word) + delay(10*ms) + + while True: + for ttl in self.ttls: + ttl.pulse(1*ms) From 25170a53e54c9ef8b736075c48d163c1ebcf5d11 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 18 Jul 2018 10:27:54 +0800 Subject: [PATCH 1049/2457] sayma: add back Urukul and Zotino --- artiq/gateware/targets/sayma_amc.py | 8 ++++---- conda/artiq-dev/meta.yaml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 91605cd50..b24bf88fa 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -474,12 +474,12 @@ class Master(MiniSoC, AMPSoC): phy = ttl_simple.Output(s) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - #eem.Urukul.add_std(self, 1, 0, ttl_simple.Output, - # iostandard="LVDS") eem.DIO.add_std(self, 2, ttl_simple.Output, ttl_simple.Output, iostandard="LVDS") - #eem.Zotino.add_std(self, 3, ttl_simple.Output, - # iostandard="LVDS") + eem.Urukul.add_std(self, 1, 0, ttl_simple.Output, + iostandard="LVDS") + eem.Zotino.add_std(self, 3, ttl_simple.Output, + iostandard="LVDS") self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 38885177d..2ea57effb 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_73+gitbef9dea - - misoc 0.11 py35_27+git37dfced7 + - misoc 0.11 py35_29+git57ebe119 - jesd204b 0.7 - microscope - binutils-or1k-linux >=2.27 From 31f4f8792aaec382b451edf358fc8846c7a5eee7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 18 Jul 2018 10:31:55 +0800 Subject: [PATCH 1050/2457] sayma: add Urukul and Zotino to example device_db --- artiq/examples/sayma_master/device_db.py | 95 ++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/artiq/examples/sayma_master/device_db.py b/artiq/examples/sayma_master/device_db.py index 9b6b24df3..38e78821e 100644 --- a/artiq/examples/sayma_master/device_db.py +++ b/artiq/examples/sayma_master/device_db.py @@ -52,6 +52,7 @@ device_db = { }, } + for i in range(8): device_db["ttl" + str(i)] = { "type": "local", @@ -59,3 +60,97 @@ for i in range(8): "class": "TTLOut", "arguments": {"channel": 9+i}, } + + +device_db.update( + spi_urukul0={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 17} + }, + ttl_urukul0_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 18} + }, + ttl_urukul0_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 19} + }, + ttl_urukul0_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 20} + }, + ttl_urukul0_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 21} + }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 22} + }, + urukul0_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul0_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } + + +device_db["spi_zotino0"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 23} +} +device_db["ttl_zotino0_ldac"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 24} +} +device_db["ttl_zotino0_clr"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 25} +} +device_db["zotino0"] = { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino0", + "ldac_device": "ttl_zotino0_ldac", + "clr_device": "ttl_zotino0_clr" + } +} From e71cbe53a688172b399fe61c4370112de37256c6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 18 Jul 2018 10:37:43 +0800 Subject: [PATCH 1051/2457] firmware: cleanup Cargo.lock --- artiq/firmware/Cargo.lock | 43 --------------------------------------- 1 file changed, 43 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 4908fc14f..b9096a13e 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -124,15 +124,6 @@ dependencies = [ "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ksupport" version = "0.0.0" @@ -231,15 +222,6 @@ dependencies = [ "unwind_backtrace 0.0.0", ] -[[package]] -name = "same-file" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "satman" version = "0.0.0" @@ -296,26 +278,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "unwind_backtrace" version = "0.0.0" -[[package]] -name = "walkdir" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [metadata] "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" @@ -328,7 +290,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" "checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" @@ -336,12 +297,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum managed 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43e2737ecabe4ae36a68061398bf27d2bfd0763f4c3c837a398478459494c4b7" "checksum managed 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5a31885241e61ba264d780d2e6686e7e59561c947b4581470364eb3e10102d86" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)" = "" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" -"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" From fe93a454d68b6e6db697c0c0c6f550ec95bbb691 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 19 Jul 2018 14:10:36 +0800 Subject: [PATCH 1052/2457] fmcdio_vhdci_eem: fix direction shift register permutation and polarity --- artiq/coredevice/fmcdio_vhdci_eem.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/fmcdio_vhdci_eem.py b/artiq/coredevice/fmcdio_vhdci_eem.py index 13d6224b0..d10378feb 100644 --- a/artiq/coredevice/fmcdio_vhdci_eem.py +++ b/artiq/coredevice/fmcdio_vhdci_eem.py @@ -6,11 +6,20 @@ eem_fmc_connections = { } +fmcdio_shiftreg_permutation = [ + 1, 0, 3, 2, 5, 4, 7, 6, + 9, 8, 11, 10, 13, 12, 15, 14, + 17, 16, 19, 18, 21, 20, 23, 22, + 25, 24, 27, 26, 29, 28, 31, 30 +] + + def shiftreg_bits(eem, out_pins): r = 0 for i in range(8): - if i in out_pins: - shift = eem_fmc_connections[eem][i] + if i not in out_pins: + lvds_line = eem_fmc_connections[eem][i] + shift = fmcdio_shiftreg_permutation.index(lvds_line) r |= 1 << shift return r From 8dfcd463aa6af18880f918bf9e156a1e0069e133 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 19 Jul 2018 15:46:04 +0800 Subject: [PATCH 1053/2457] fmcdio_vhdci_eem: naming consistency --- artiq/coredevice/fmcdio_vhdci_eem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/fmcdio_vhdci_eem.py b/artiq/coredevice/fmcdio_vhdci_eem.py index d10378feb..13856663e 100644 --- a/artiq/coredevice/fmcdio_vhdci_eem.py +++ b/artiq/coredevice/fmcdio_vhdci_eem.py @@ -33,7 +33,7 @@ urukul_out_pins = { 6, # io_update 7, # dds_reset } -urukul_out_pins_aux = { +urukul_aux_out_pins = { 4, # sw0 5, # sw1 6, # sw2 From d152506ecbf05f97e6978a1f3c4549a0d4086d13 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 19 Jul 2018 15:47:20 +0800 Subject: [PATCH 1054/2457] sayma: update fmcdio_vhdci_eem demo --- .../examples/sayma_master/repository/demo.py | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/artiq/examples/sayma_master/repository/demo.py b/artiq/examples/sayma_master/repository/demo.py index 23add53c2..9b40f4b42 100644 --- a/artiq/examples/sayma_master/repository/demo.py +++ b/artiq/examples/sayma_master/repository/demo.py @@ -8,10 +8,15 @@ class Demo(EnvExperiment): self.setattr_device("fmcdio_dirctl") self.ttls = [self.get_device("ttl" + str(i)) for i in range(8)] + self.setattr_device("urukul0_cpld") + self.urukul_chs = [self.get_device("urukul0_ch" + str(i)) for i in range(4)] + self.setattr_device("zotino0") self.dirctl_word = ( - shiftreg_bits(2, dio_bank0_out_pins) | - shiftreg_bits(2, dio_bank1_out_pins)) + shiftreg_bits(1, urukul_out_pins) | + shiftreg_bits(0, urukul_aux_out_pins) | + shiftreg_bits(2, dio_bank0_out_pins | dio_bank1_out_pins) | + shiftreg_bits(3, zotino_out_pins)) @kernel def run(self): @@ -20,6 +25,17 @@ class Demo(EnvExperiment): self.fmcdio_dirctl.set(self.dirctl_word) delay(10*ms) + self.urukul0_cpld.init() + delay(10*ms) + + self.zotino0.init() + delay(1*ms) + for i in range(32): + self.zotino0.write_dac(i, i/4) + delay(1*ms) + while True: for ttl in self.ttls: - ttl.pulse(1*ms) + ttl.pulse(100*ms) + for urukul_ch in self.urukul_chs: + urukul_ch.sw.pulse(100*ms) From cab0ba408dfa20e96bf0a13eccd9b5e8146a659f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 20 Jul 2018 09:54:20 +0800 Subject: [PATCH 1055/2457] fmcdio_vhdci_eem: cleanup and document --- artiq/coredevice/fmcdio_vhdci_eem.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/artiq/coredevice/fmcdio_vhdci_eem.py b/artiq/coredevice/fmcdio_vhdci_eem.py index 13856663e..bddb55812 100644 --- a/artiq/coredevice/fmcdio_vhdci_eem.py +++ b/artiq/coredevice/fmcdio_vhdci_eem.py @@ -1,3 +1,5 @@ +# Definitions for using the "FMC DIO 32ch LVDS a" card with the VHDCI-EEM breakout v1.1 + eem_fmc_connections = { 0: [0, 8, 2, 3, 4, 5, 6, 7], 1: [1, 9, 10, 11, 12, 13, 14, 15], @@ -6,20 +8,21 @@ eem_fmc_connections = { } -fmcdio_shiftreg_permutation = [ - 1, 0, 3, 2, 5, 4, 7, 6, - 9, 8, 11, 10, 13, 12, 15, 14, - 17, 16, 19, 18, 21, 20, 23, 22, - 25, 24, 27, 26, 29, 28, 31, 30 -] - - def shiftreg_bits(eem, out_pins): + """ + Returns the bits that have to be set in the FMC card direction + shift register for the given EEM. + + Takes a set of pin numbers (0-7) at the EEM. Return values + of this function for different EEMs should be ORed together. + """ r = 0 for i in range(8): if i not in out_pins: lvds_line = eem_fmc_connections[eem][i] - shift = fmcdio_shiftreg_permutation.index(lvds_line) + # lines are swapped in pairs to ease PCB routing + # at the shift register + shift = lvds_line ^ 1 r |= 1 << shift return r From 766d87f626ad6b66774616006e6749a62d839b89 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 20 Jul 2018 11:59:07 +0800 Subject: [PATCH 1056/2457] =?UTF-8?q?doc:=20artiq=5Fcoreconfig=20=E2=86=92?= =?UTF-8?q?=20artiq=5Fcoremgmt=20config.=20Closes=20#1111?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/manual/core_device.rst | 2 +- doc/manual/installing.rst | 10 +++++----- doc/manual/utilities.rst | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst index 8ff53fcbf..96308af92 100644 --- a/doc/manual/core_device.rst +++ b/doc/manual/core_device.rst @@ -17,7 +17,7 @@ This storage area is used to store the core device MAC address, IP address and e The flash storage area is one sector (typically 64 kB) large and is organized as a list of key-value records. -This flash storage space can be accessed by using ``artiq_coreconfig`` (see: :ref:`core-device-configuration-tool`). +This flash storage space can be accessed by using ``artiq_coremgmt`` (see: :ref:`core-device-management-tool`). .. _board-ports: diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 098d0b7d0..05a761493 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -182,13 +182,13 @@ To flash the idle kernel: * Write it into the core device configuration flash storage: :: - $ artiq_coreconfig write -f idle_kernel idle.elf + $ artiq_coremgmt config -f idle_kernel idle.elf -.. note:: You can find more information about how to use the ``artiq_coreconfig`` utility on the :ref:`Utilities ` page. +.. note:: You can find more information about how to use the ``artiq_coremgmt`` utility on the :ref:`Utilities ` page. * (optional) Flash the startup kernel -The startup kernel is executed once when the core device powers up. It should initialize DDSes, set up TTL directions, etc. Proceed as with the idle kernel, but using the ``startup_kernel`` key in ``artiq_coreconfig``. +The startup kernel is executed once when the core device powers up. It should initialize DDSes, set up TTL directions, etc. Proceed as with the idle kernel, but using the ``startup_kernel`` key in the ``artiq_coremgmt`` command. For DRTIO systems, the startup kernel should wait until the desired links are up, using :meth:`artiq.coredevice.Core.get_drtio_link_status`. @@ -196,8 +196,8 @@ For DRTIO systems, the startup kernel should wait until the desired links are up Some core devices may use either an external clock signal or their internal clock. The clock is selected at power-up. Use one of these commands: :: - $ artiq_coreconfig write -s rtio_clock i # internal clock (default) - $ artiq_coreconfig write -s rtio_clock e # external clock + $ artiq_coremgmt config write -s rtio_clock i # internal clock (default) + $ artiq_coremgmt config write -s rtio_clock e # external clock .. rubric:: Footnotes diff --git a/doc/manual/utilities.rst b/doc/manual/utilities.rst index 9374a6930..5bf67bb48 100644 --- a/doc/manual/utilities.rst +++ b/doc/manual/utilities.rst @@ -104,7 +104,7 @@ Flashing/Loading tool :ref: artiq.frontend.artiq_flash.get_argparser :prog: artiq_flash -.. _core-device-configuration-tool: +.. _core-device-management-tool: Core device management tool --------------------------- From e3ba4b951694383ed96fc40d0ce5d4d497b27b92 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 21 Jul 2018 13:25:13 +0800 Subject: [PATCH 1057/2457] grabber: minor ROI engine cleanup, export count_len, cap count width to 31 --- artiq/gateware/grabber/core.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/grabber/core.py b/artiq/gateware/grabber/core.py index a1144000b..9c840fc11 100644 --- a/artiq/gateware/grabber/core.py +++ b/artiq/gateware/grabber/core.py @@ -50,7 +50,7 @@ assert len(set(bitseq)) == 24 class Parser(Module, AutoCSR): """Parses 28 bit encoded words and track pixel coordinates.""" - def __init__(self, width=12): + def __init__(self, width): self.cl = cl = Signal(28) self.last_x = CSRStatus(width) @@ -110,8 +110,14 @@ class Parser(Module, AutoCSR): class ROI(Module): """ROI Engine. For each frame, accumulates pixels values within a rectangular region of interest, and reports the total.""" - def __init__(self, pix, shift=0): - cnt_len = len(pix.x) + len(pix.y) + 16 - shift + + @staticmethod + def count_len(width, shift): + # limit width to 31 to avoid problems with CPUs and RTIO inputs + return min(31, 2*width + 16 - shift) + + def __init__(self, pix, shift): + count_len = ROI.count_len(len(pix.x), shift) self.cfg = cfg = Record([ ("x0", len(pix.x)), @@ -121,8 +127,8 @@ class ROI(Module): ]) self.out = out = Record([ ("update", 1), - # register output - can be used as CDC input - ("cnt", cnt_len), + # registered output - can be used as CDC input + ("count", count_len), ]) # # # @@ -156,16 +162,16 @@ class ROI(Module): ] # stage 2 - accumulate - cnt = Signal(cnt_len) + count = Signal(count_len) self.sync.cl += [ If(stb & x_good & y_good, - cnt.eq(cnt + gray), + count.eq(count + gray), ), out.update.eq(0), If(eop, cnt.eq(0), out.update.eq(1), - out.cnt.eq(cnt) + out.count.eq(count) ) ] From 031de58d21e175880f26cdca863f31d3066c753f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 21 Jul 2018 13:25:47 +0800 Subject: [PATCH 1058/2457] grabber: complete RTIO PHY, untested --- artiq/gateware/rtio/phy/grabber.py | 84 ++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/rtio/phy/grabber.py b/artiq/gateware/rtio/phy/grabber.py index a6c891e50..da744d210 100644 --- a/artiq/gateware/rtio/phy/grabber.py +++ b/artiq/gateware/rtio/phy/grabber.py @@ -1,20 +1,94 @@ from migen import * +from migen.genlib.cdc import MultiReg, PulseSynchronizer +from migen.genlib.fsm import FSM from artiq.gateware.rtio import rtlink from artiq.gateware.grabber import deserializer_7series from artiq.gateware.grabber.core import * +__all__ = ["Grabber"] + + +class Synchronizer(Module): + def __init__(self, roi_engines): + counts_in = [roi_engine.out.count for roi_engine in roi_engines] + + # This assumes all ROI engines update at the same time. + self.update = Signal() + # stays valid until the next frame after self.update is pulsed. + self.counts = [Signal.like(count) for count in counts_in] + + # # # + + for count in counts_in: + count.attr.add("no_retiming") + counts_rtio = [Signal.like(count) for count in counts_in] + self.specials += [MultiReg(i, o, "rtio") for i, o in zip(counts_in, self.counts)] + + ps = PulseSynchronizer("cl", "rtio") + self.submodules += ps + self.comb += ps.i.eq(roi_engines[0].out.update) + self.sync.rtio += self.update.eq(ps.o) + + +class Serializer(Module): + def __init__(self, update, counts, rtlink_i): + self.gate = Signal(len(counts)) + + # # # + + gate = Signal(len(counts)) + sentinel = 2**(len(rtlink_i.data) - 1) + + fsm = ClockDomainsRenamer("rio")(FSM()) + self.submodules += fsm + + fsm.act("INIT", + rtlink_i.data.eq(sentinel), + If(update & (self.gate != 0), + NextValue(gate, self.gate), + rtlink_i.stb.eq(1), + NextState(0) + ) + ) + for n, count in enumerate(counts): + last = n == len(counts)-1 + fsm.act(n, + rtlink_i.data.eq(count), + rtlink_i.stb.eq(gate[n]), + NextState("INIT" if last else n+1) + ) + + class Grabber(Module): - def __init__(self, pins): - self.config = rtlink.Interface(rtlink.OInterface(10)) - self.gate_data = rtlink.Interface(rtlink.OInterface(1), - rtlink.IInterface(10)) + def __init__(self, pins, roi_engine_count=16, res_width=12, count_shift=0): + self.config = rtlink.Interface( + rtlink.OInterface(res_width, + bits_for(4*roi_engine_count-1))) + self.gate_data = rtlink.Interface( + rtlink.OInterface(roi_engine_count), + rtlink.IInterface(1+ROI.count_len(res_width, count_shift), + timestamped=False)) self.submodules.deserializer = deserializer_7series.Deserializer(pins) self.submodules.frequency_counter = FrequencyCounter() - self.submodules.parser = Parser() + self.submodules.parser = Parser(res_width) self.comb += self.parser.cl.eq(self.deserializer.q) + self.roi_engines = [ROI(self.parser.pix, count_shift) for _ in range(roi_engine_count)] + self.submodules += self.roi_engines + self.submodules.synchronizer = Synchronizer(self.roi_engines) + self.submodules.serializer = Serializer(self.synchronizer.update, self.synchronizer.counts, + self.gate_data.i) + + for n, roi_engine in enumerate(self.roi_engines): + for offset, target in enumerate([roi_engine.cfg.x0, roi_engine.cfg.x1, + roi_engine.cfg.y0, roi_engine.cfg.y1]): + self.sync.rtio += If(self.config.o.stb & (self.config.o.address == 4*n+offset), + target.eq(self.config.o.data)) + + self.sync.rio += If(self.gate_data.o.stb, + self.serializer.gate.eq(self.gate_data.o.data)) def get_csrs(self): return ( From 3638a966e14848c5861e2331ca7f8066cf874c01 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 21 Jul 2018 13:26:13 +0800 Subject: [PATCH 1059/2457] kasli: add false path between RTIO and CL clocks --- artiq/gateware/targets/kasli.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index ab0abb2d2..b59b5c330 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -299,6 +299,8 @@ class MITLL(_StandaloneBase): self.add_rtio(self.rtio_channels) self.config["HAS_GRABBER"] = None self.add_csr_group("grabber", self.grabber_csr_group) + self.platform.add_false_path_constraints( + self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) class USTC(_StandaloneBase): @@ -338,6 +340,8 @@ class USTC(_StandaloneBase): self.add_rtio(self.rtio_channels) self.config["HAS_GRABBER"] = None self.add_csr_group("grabber", self.grabber_csr_group) + self.platform.add_false_path_constraints( + self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) class Tsinghua(_StandaloneBase): @@ -374,6 +378,8 @@ class Tsinghua(_StandaloneBase): self.add_rtio(self.rtio_channels) self.config["HAS_GRABBER"] = None self.add_csr_group("grabber", self.grabber_csr_group) + self.platform.add_false_path_constraints( + self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) class WIPM(_StandaloneBase): @@ -543,6 +549,8 @@ class LUH(_StandaloneBase): self.add_rtio(self.rtio_channels) self.config["HAS_GRABBER"] = None self.add_csr_group("grabber", self.grabber_csr_group) + self.platform.add_false_path_constraints( + self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) class Tester(_StandaloneBase): From 4a4d0f8e517bb262579b39f6266f7b673ed595b7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 21 Jul 2018 13:39:46 +0800 Subject: [PATCH 1060/2457] grabber: fix missing variable rename --- artiq/gateware/grabber/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/grabber/core.py b/artiq/gateware/grabber/core.py index 9c840fc11..c0378a9f1 100644 --- a/artiq/gateware/grabber/core.py +++ b/artiq/gateware/grabber/core.py @@ -170,7 +170,7 @@ class ROI(Module): out.update.eq(0), If(eop, - cnt.eq(0), + count.eq(0), out.update.eq(1), out.count.eq(count) ) From 7b75026391feb4e78ac9976e9fe520cc13022c0f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 21 Jul 2018 13:40:12 +0800 Subject: [PATCH 1061/2457] grabber: add MultiReg to transfer ROI boundaries --- artiq/gateware/rtio/phy/grabber.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/phy/grabber.py b/artiq/gateware/rtio/phy/grabber.py index da744d210..fe4e9e3c2 100644 --- a/artiq/gateware/rtio/phy/grabber.py +++ b/artiq/gateware/rtio/phy/grabber.py @@ -84,8 +84,11 @@ class Grabber(Module): for n, roi_engine in enumerate(self.roi_engines): for offset, target in enumerate([roi_engine.cfg.x0, roi_engine.cfg.x1, roi_engine.cfg.y0, roi_engine.cfg.y1]): + roi_boundary = Signal.like(target) + roi_boundary.attr.add("no_retiming") self.sync.rtio += If(self.config.o.stb & (self.config.o.address == 4*n+offset), - target.eq(self.config.o.data)) + roi_boundary.eq(self.config.o.data)) + self.specials += MultiReg(roi_boundary, target, "cl") self.sync.rio += If(self.gate_data.o.stb, self.serializer.gate.eq(self.gate_data.o.data)) From 015c592ab7a0c85fd2b304e9c8d54cb6b9e415aa Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 21 Jul 2018 15:49:40 +0800 Subject: [PATCH 1062/2457] conda: bump jesd204b --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 2ea57effb..7b79a6866 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -16,7 +16,7 @@ requirements: - setuptools 33.1.1 - migen 0.7 py35_73+gitbef9dea - misoc 0.11 py35_29+git57ebe119 - - jesd204b 0.7 + - jesd204b 0.8 - microscope - binutils-or1k-linux >=2.27 - llvm-or1k 6.0.0 From 60a7e0e40d5fe4329ce8c61337cad4e4bfbd3d3b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 24 Jul 2018 10:55:13 +0800 Subject: [PATCH 1063/2457] grabber: use usual order of ROI coordinates in cfg addresses --- artiq/gateware/rtio/phy/grabber.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/phy/grabber.py b/artiq/gateware/rtio/phy/grabber.py index fe4e9e3c2..8b9f05265 100644 --- a/artiq/gateware/rtio/phy/grabber.py +++ b/artiq/gateware/rtio/phy/grabber.py @@ -82,8 +82,8 @@ class Grabber(Module): self.gate_data.i) for n, roi_engine in enumerate(self.roi_engines): - for offset, target in enumerate([roi_engine.cfg.x0, roi_engine.cfg.x1, - roi_engine.cfg.y0, roi_engine.cfg.y1]): + for offset, target in enumerate([roi_engine.cfg.x0, roi_engine.cfg.y0, + roi_engine.cfg.x1, roi_engine.cfg.y1]): roi_boundary = Signal.like(target) roi_boundary.attr.add("no_retiming") self.sync.rtio += If(self.config.o.stb & (self.config.o.address == 4*n+offset), From b38c685857afb65609766fb5443375a9e971b57b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 24 Jul 2018 11:32:32 +0800 Subject: [PATCH 1064/2457] grabber: fix pix.stb --- artiq/gateware/grabber/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/grabber/core.py b/artiq/gateware/grabber/core.py index c0378a9f1..d9dac3d12 100644 --- a/artiq/gateware/grabber/core.py +++ b/artiq/gateware/grabber/core.py @@ -78,7 +78,7 @@ class Parser(Module, AutoCSR): last_fval = Signal() self.comb += [ Cat(dval, fval, lval).eq(cl[14:17]), - pix.stb.eq(dval), + pix.stb.eq(dval & fval & lval), pix.eop.eq(~fval & last_fval), Cat(pix.a, pix.b, pix.c).eq(Cat(cl[i] for i in bitseq)) ] From fb96c1140e2b65560a084493904487baeb957519 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 24 Jul 2018 18:06:44 +0800 Subject: [PATCH 1065/2457] grabber: add coredevice driver --- artiq/coredevice/grabber.py | 105 ++++++++++++++++++++++++++ doc/manual/core_drivers_reference.rst | 11 ++- 2 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 artiq/coredevice/grabber.py diff --git a/artiq/coredevice/grabber.py b/artiq/coredevice/grabber.py new file mode 100644 index 000000000..6406578ea --- /dev/null +++ b/artiq/coredevice/grabber.py @@ -0,0 +1,105 @@ +from numpy import int32, int64 + +from artiq.language.core import * +from artiq.language.types import * +from artiq.coredevice.rtio import rtio_output, rtio_input_data + + +class OutOfSyncException(Exception): + """Raised when an incorrect number of ROI engine outputs has been + retrieved from the RTIO input FIFO.""" + pass + + +class Grabber: + """Driver for the Grabber camera interface.""" + kernel_invariants = {"core", "channel_base", "sentinel"} + + def __init__(self, dmgr, channel_base, res_width=12, count_shift=0, + core_device="core"): + self.core = dmgr.get(core_device) + self.channel_base = channel_base + + count_width = min(31, 2*res_width + 16 - count_shift) + # This value is inserted by the gateware to mark the start of a series of + # ROI engine outputs for one video frame. + self.sentinel = int32(2**count_width) + + @kernel + def setup_roi(self, n, x0, y0, x1, y1): + """ + Defines the coordinates of a ROI. + + The coordinates are set around the current position of the RTIO time + cursor. + + The user must keep the ROI engine disabled for the duration of more + than one video frame after calling this function, as the output + generated for that video frame is undefined. + + Advances the timeline by 4 coarse RTIO cycles. + """ + c = int64(self.core.ref_multiplier) + rtio_output(now_mu(), self.channel_base, 4*n+0, x0) + delay_mu(c) + rtio_output(now_mu(), self.channel_base, 4*n+1, y0) + delay_mu(c) + rtio_output(now_mu(), self.channel_base, 4*n+2, x1) + delay_mu(c) + rtio_output(now_mu(), self.channel_base, 4*n+3, y1) + delay_mu(c) + + @kernel + def gate_roi(self, mask): + """ + Defines which ROI engines produce input events. + + At the end of each video frame, the output from each ROI engine that + has been enabled by the mask is enqueued into the RTIO input FIFO. + + This function sets the mask at the current position of the RTIO time + cursor. + + Setting the mask using this function is atomic; in other words, + if the system is in the middle of processing a frame and the mask + is changed, the processing will complete using the value of the mask + that it started with. + + :param mask: bitmask enabling or disabling each ROI engine. + """ + rtio_output(now_mu(), self.channel_base+1, 0, mask) + + @kernel + def gate_roi_pulse(self, mask, dt): + """Sets a temporary mask for the specified duration (in seconds), before + disabling all ROI engines.""" + self.gate_roi(mask) + delay(dt) + self.gate_roi(0) + + @kernel + def input_mu(self, data): + """ + Retrieves the accumulated values for one frame from the ROI engines. + Blocks until values are available. + + The input list must be a list of integers of the same length as there + are enabled ROI engines. This method replaces the elements of the + input list with the outputs of the enabled ROI engines, sorted by + number. + + If the number of elements in the list does not match the number of + ROI engines that produced output, an exception will be raised during + this call or the next. + """ + channel = self.channel_base + 1 + + sentinel = rtio_input_data(channel) + if sentinel != self.sentinel: + raise OutOfSyncException + + for i in range(len(data)): + roi_output = rtio_input_data(channel) + if roi_output == self.sentinel: + raise OutOfSyncException + data[i] = roi_output diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 06f1fd4ce..556f54096 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -134,11 +134,18 @@ DAC/ADC drivers :members: -Compound drivers ----------------- +Miscellaneous +------------- :mod:`artiq.coredevice.suservo` module ++++++++++++++++++++++++++++++++++++++ .. automodule:: artiq.coredevice.suservo :members: + + +:mod:`artiq.coredevice.grabber` module +++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.grabber + :members: From 19c51c644e8c983d35452abf47bcb34f9d1afabc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 24 Jul 2018 19:08:51 +0800 Subject: [PATCH 1066/2457] grabber: cleanup GRABBER_STATE --- artiq/firmware/libboard_artiq/grabber.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/grabber.rs b/artiq/firmware/libboard_artiq/grabber.rs index 7c80ac81b..2da0126e4 100644 --- a/artiq/firmware/libboard_artiq/grabber.rs +++ b/artiq/firmware/libboard_artiq/grabber.rs @@ -7,7 +7,7 @@ enum State { Up } -static mut GRABBER_STATE: &'static mut [State] = &mut [State::Down; csr::GRABBER_LEN]; +static mut GRABBER_STATE: [State; csr::GRABBER_LEN] = [State::Down; csr::GRABBER_LEN]; fn get_pll_reset(g: usize) -> bool { unsafe { (csr::GRABBER[g].pll_reset_read)() != 0 } From 0a9d3638eed9ed8ecaae9f03d2bb26267036e623 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 26 Jul 2018 14:49:32 +0800 Subject: [PATCH 1067/2457] config: add write_int --- artiq/firmware/libboard_misoc/config.rs | 38 +++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/artiq/firmware/libboard_misoc/config.rs b/artiq/firmware/libboard_misoc/config.rs index 443221d76..ba5da0d42 100644 --- a/artiq/firmware/libboard_misoc/config.rs +++ b/artiq/firmware/libboard_misoc/config.rs @@ -29,6 +29,35 @@ impl fmt::Display for Error { } } +struct FmtWrapper<'a> { + buf: &'a mut [u8], + offset: usize, +} + +impl<'a> FmtWrapper<'a> { + fn new(buf: &'a mut [u8]) -> Self { + FmtWrapper { + buf: buf, + offset: 0, + } + } + + fn contents(&self) -> &[u8] { + &self.buf[..self.offset] + } +} + +impl<'a> fmt::Write for FmtWrapper<'a> { + fn write_str(&mut self, s: &str) -> fmt::Result { + let bytes = s.as_bytes(); + let remainder = &mut self.buf[self.offset..]; + let remainder = &mut remainder[..bytes.len()]; + remainder.copy_from_slice(bytes); + self.offset += bytes.len(); + Ok(()) + } +} + #[cfg(has_spiflash)] mod imp { use core::str; @@ -36,6 +65,8 @@ mod imp { use cache; use spiflash; use super::Error; + use core::fmt::Write; + use super::FmtWrapper; // One flash sector immediately before the firmware. const ADDR: usize = ::mem::FLASH_BOOT_ADDRESS - spiflash::SECTOR_SIZE; @@ -224,6 +255,13 @@ mod imp { } } + pub fn write_int(key: &str, value: u32) -> Result<(), Error> { + let mut buf = [0; 16]; + let mut wrapper = FmtWrapper::new(&mut buf); + write!(&mut wrapper, "{}", value).unwrap(); + write(key, wrapper.contents()) + } + pub fn remove(key: &str) -> Result<(), Error> { write(key, &[]) } From d523d03f71a7bddca79a21925f6b006bbbf4dbd8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 26 Jul 2018 14:53:28 +0800 Subject: [PATCH 1068/2457] sayma: automated FPGA SYSREF phase offset calibration --- artiq/firmware/libboard_artiq/ad9154.rs | 14 +- artiq/firmware/libboard_artiq/hmc830_7043.rs | 63 +------- artiq/firmware/libboard_artiq/jesd204sync.rs | 144 +++++++++++++++++++ artiq/firmware/libboard_artiq/lib.rs | 3 + artiq/firmware/runtime/main.rs | 10 +- 5 files changed, 158 insertions(+), 76 deletions(-) create mode 100644 artiq/firmware/libboard_artiq/jesd204sync.rs diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 4b0e11be1..68ee06efa 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -34,7 +34,7 @@ fn read(addr: u16) -> u8 { } } -fn jesd_unreset() { +pub fn jesd_unreset() { unsafe { csr::ad9154_crg::ibuf_disable_write(0); csr::ad9154_crg::jreset_write(0); @@ -760,17 +760,7 @@ fn init_dac(dacno: u8, sysref_phase: u16) -> Result<(), &'static str> { Ok(()) } -pub fn init(sysref_phase_fpga: u16, sysref_phase_dac: u16) { - // Release the JESD clock domain reset late, as we need to - // set up clock chips before. - jesd_unreset(); - - // This needs to take place once before DAC SYSREF scan, as - // the HMC7043 input clock (which defines slip resolution) - // is 2x the DAC clock, so there are two possible phases from - // the divider states. This deterministically selects one. - hmc7043::sysref_rtio_align(sysref_phase_fpga, 1); - +pub fn init(sysref_phase_dac: u16) { for dacno in 0..csr::AD9154.len() { // We assume DCLK and SYSREF traces are matched on the PCB // (they are on Sayma) so only one phase is needed. diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index faa26630a..142ae11ea 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -391,7 +391,7 @@ pub mod hmc7043 { clock::spin_us(100); } - fn sysref_offset_fpga(phase_offset: u16) { + pub fn sysref_offset_fpga(phase_offset: u16) { let analog_delay = (phase_offset % 17) as u8; let digital_delay = (phase_offset / 17) as u8; spi_setup(); @@ -400,71 +400,12 @@ pub mod hmc7043 { clock::spin_us(100); } - fn sysref_slip() { + pub fn sysref_slip() { spi_setup(); write(0x0002, 0x02); write(0x0002, 0x00); clock::spin_us(100); } - - fn sysref_sample() -> bool { - unsafe { csr::sysref_sampler::sample_result_read() == 1 } - } - - pub fn sysref_rtio_align(phase_offset: u16, expected_align: u16) { - info!("aligning SYSREF with RTIO..."); - - let mut slips0 = 0; - let mut slips1 = 0; - // meet setup/hold (assuming FPGA timing margins are OK) - sysref_offset_fpga(phase_offset); - // if we are already in the 1 zone, get out of it - while sysref_sample() { - sysref_slip(); - slips0 += 1; - if slips0 > 1024 { - error!(" failed to reach 1->0 transition"); - break; - } - } - // get to the edge of the 0->1 transition (our final setpoint) - while !sysref_sample() { - sysref_slip(); - slips1 += 1; - if slips1 > 1024 { - error!(" failed to reach 0->1 transition"); - break; - } - } - info!(" ...done ({}/{} slips)", slips0, slips1); - if (slips0 + slips1) % expected_align != 0 { - error!(" unexpected slip alignment"); - } - - let mut margin_minus = None; - for d in 0..phase_offset { - sysref_offset_fpga(phase_offset - d); - if !sysref_sample() { - margin_minus = Some(d); - break; - } - } - // meet setup/hold - sysref_offset_fpga(phase_offset); - - if margin_minus.is_some() { - let margin_minus = margin_minus.unwrap(); - // one phase slip (period of the 1.2GHz input clock) - let period = 2*17; // approximate: 2 digital coarse delay steps - let margin_plus = if period > margin_minus { period - margin_minus } else { 0 }; - info!(" margins at FPGA: -{} +{}", margin_minus, margin_plus); - if margin_minus < 10 || margin_plus < 10 { - error!("SYSREF margin at FPGA is too small"); - } - } else { - error!("unable to determine SYSREF margin at FPGA"); - } - } } pub fn init() -> Result<(), &'static str> { diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs new file mode 100644 index 000000000..3879c7b41 --- /dev/null +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -0,0 +1,144 @@ +use board_misoc::csr; +use board_misoc::config; + +use hmc830_7043::hmc7043; + + +fn sysref_sample() -> bool { + unsafe { csr::sysref_sampler::sample_result_read() == 1 } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum SysrefSample { + Low, + High, + Unstable +} + +fn sysref_sample_stable(phase_offset: u16) -> SysrefSample { + hmc7043::sysref_offset_fpga(phase_offset); + let s1 = sysref_sample(); + hmc7043::sysref_offset_fpga(phase_offset-5); + let s2 = sysref_sample(); + if s1 == s2 { + if s1 { + return SysrefSample::High; + } else { + return SysrefSample::Low; + } + } else { + return SysrefSample::Unstable; + } +} + +fn sysref_cal_fpga() -> Result { + info!("calibrating SYSREF phase offset at FPGA..."); + + let initial_phase_offset = 136; + + let mut slips0 = 0; + let mut slips1 = 0; + // make sure we start in the 0 zone + while sysref_sample_stable(initial_phase_offset) != SysrefSample::Low { + hmc7043::sysref_slip(); + slips0 += 1; + if slips0 > 1024 { + return Err("failed to reach 1->0 transition (cal)"); + } + } + + // get near the edge of the 0->1 transition + while sysref_sample_stable(initial_phase_offset) != SysrefSample::High { + hmc7043::sysref_slip(); + slips1 += 1; + if slips1 > 1024 { + return Err("failed to reach 0->1 transition (cal)"); + } + } + + for d in 0..initial_phase_offset { + let phase_offset = initial_phase_offset - d; + hmc7043::sysref_offset_fpga(phase_offset); + if !sysref_sample() { + let result = phase_offset + 17; + info!(" ...done, phase offset: {}", result); + return Ok(result); + } + } + return Err("failed to reach 1->0 transition with fine delay"); +} + +fn sysref_rtio_align(phase_offset: u16, expected_align: u16) -> Result<(), &'static str> { + // This needs to take place once before DAC SYSREF scan, as + // the HMC7043 input clock (which defines slip resolution) + // is 2x the DAC clock, so there are two possible phases from + // the divider states. This deterministically selects one. + + info!("aligning SYSREF with RTIO..."); + + let mut slips0 = 0; + let mut slips1 = 0; + // meet setup/hold (assuming FPGA timing margins are OK) + hmc7043::sysref_offset_fpga(phase_offset); + // if we are already in the 1 zone, get out of it + while sysref_sample() { + hmc7043::sysref_slip(); + slips0 += 1; + if slips0 > 1024 { + return Err("failed to reach 1->0 transition"); + } + } + // get to the edge of the 0->1 transition (our final setpoint) + while !sysref_sample() { + hmc7043::sysref_slip(); + slips1 += 1; + if slips1 > 1024 { + return Err("failed to reach 0->1 transition"); + } + } + info!(" ...done ({}/{} slips)", slips0, slips1); + if (slips0 + slips1) % expected_align != 0 { + return Err("unexpected slip alignment"); + } + + let mut margin_minus = None; + for d in 0..phase_offset { + hmc7043::sysref_offset_fpga(phase_offset - d); + if !sysref_sample() { + margin_minus = Some(d); + break; + } + } + // meet setup/hold + hmc7043::sysref_offset_fpga(phase_offset); + + if margin_minus.is_some() { + let margin_minus = margin_minus.unwrap(); + // one phase slip (period of the 1.2GHz input clock) + let period = 2*17; // approximate: 2 digital coarse delay steps + let margin_plus = if period > margin_minus { period - margin_minus } else { 0 }; + info!(" margins at FPGA: -{} +{}", margin_minus, margin_plus); + if margin_minus < 10 || margin_plus < 10 { + return Err("SYSREF margin at FPGA is too small, board needs recalibration"); + } + } else { + return Err("unable to determine SYSREF margin at FPGA"); + } + + Ok(()) +} + +pub fn sysref_auto_rtio_align(expected_align: u16) -> Result<(), &'static str> { + let entry = config::read_str("sysref_phase_fpga", |r| r.map(|s| s.parse())); + let phase_offset = match entry { + Ok(Ok(phase)) => phase, + _ => { + let phase = sysref_cal_fpga()?; + if let Err(e) = config::write_int("sysref_phase_fpga", phase as u32) { + error!("failed to update FPGA SYSREF phase in config: {}", e); + } + phase + } + }; + sysref_rtio_align(phase_offset, expected_align) +} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 6c26e8d0a..443737441 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -38,8 +38,11 @@ pub mod hmc830_7043; mod ad9154_reg; #[cfg(has_ad9154)] pub mod ad9154; +#[cfg(has_ad9154)] +pub mod jesd204sync; #[cfg(has_allaki_atts)] pub mod hmc542; + #[cfg(has_grabber)] pub mod grabber; diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index b1615753c..edb9e4393 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -56,8 +56,6 @@ mod moninj; #[cfg(has_rtio_analyzer)] mod analyzer; -#[cfg(has_ad9154)] -const SYSREF_PHASE_FPGA: u16 = 41; #[cfg(has_ad9154)] const SYSREF_PHASE_DAC: u16 = 94; @@ -114,7 +112,13 @@ fn startup() { /* must be the first SPI init because of HMC830 SPI mode selection */ board_artiq::hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] - board_artiq::ad9154::init(SYSREF_PHASE_FPGA, SYSREF_PHASE_DAC); + { + board_artiq::ad9154::jesd_unreset(); + if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align(1) { + error!("failed to align SYSREF at FPGA: {}", e); + } + board_artiq::ad9154::init(SYSREF_PHASE_DAC); + } #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); From dbcf2fe9b40777661e4fa2d30eb28a2ecfc20b82 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 26 Jul 2018 16:07:37 +0800 Subject: [PATCH 1069/2457] firmware: remove 'chip found' messages on Sayma --- artiq/firmware/libboard_artiq/ad9154.rs | 2 -- artiq/firmware/libboard_artiq/hmc830_7043.rs | 4 ---- 2 files changed, 6 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 68ee06efa..2c3bb9339 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -153,8 +153,6 @@ fn dac_detect(dacno: u8) -> Result<(), &'static str> { spi_setup(dacno); if (read(ad9154_reg::PRODIDH) as u16) << 8 | (read(ad9154_reg::PRODIDL) as u16) != 0x9154 { return Err("invalid AD9154 identification"); - } else { - info!("AD9154-{} found", dacno); } Ok(()) } diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 142ae11ea..f15102902 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -74,8 +74,6 @@ mod hmc830 { if id != 0xa7975 { error!("invalid HMC830 ID: 0x{:08x}", id); return Err("invalid HMC830 identification"); - } else { - info!("HMC830 found"); } Ok(()) @@ -244,8 +242,6 @@ pub mod hmc7043 { if id != CHIP_ID { error!("invalid HMC7043 ID: 0x{:08x}", id); return Err("invalid HMC7043 identification"); - } else { - info!("HMC7043 found"); } Ok(()) From 32c95ac034df96ebe836f8b8286f583a5e36a5ae Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 26 Jul 2018 16:22:08 +0800 Subject: [PATCH 1070/2457] sayma: automated DAC SYSREF phase calibration --- artiq/firmware/libboard_artiq/ad9154.rs | 66 ++-------- artiq/firmware/libboard_artiq/jesd204sync.rs | 129 ++++++++++++++++++- artiq/firmware/runtime/main.rs | 8 +- 3 files changed, 138 insertions(+), 65 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 2c3bb9339..978f2a199 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -1,6 +1,5 @@ use board_misoc::{csr, clock}; use ad9154_reg; -use hmc830_7043::hmc7043; fn spi_setup(dacno: u8) { unsafe { @@ -688,7 +687,7 @@ fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { } } -fn dac_get_sync_error(dacno: u8) -> u16 { +pub fn dac_get_sync_error(dacno: u8) -> u16 { spi_setup(dacno); let sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) | ((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8)) @@ -696,73 +695,24 @@ fn dac_get_sync_error(dacno: u8) -> u16 { sync_error } -fn dac_sysref_scan(dacno: u8, center_phase: u16) { - let mut margin_minus = None; - let mut margin_plus = None; - - info!("AD9154-{} SYSREF scan...", dacno); - - hmc7043::sysref_offset_dac(dacno, center_phase); - clock::spin_us(10000); - let mut sync_error_last = dac_get_sync_error(dacno); - for d in 0..128 { - hmc7043::sysref_offset_dac(dacno, center_phase - d); - clock::spin_us(10000); - let sync_error = dac_get_sync_error(dacno); - if sync_error != sync_error_last { - info!(" sync error-: {} -> {}", sync_error_last, sync_error); - margin_minus = Some(d); - break; - } - } - - hmc7043::sysref_offset_dac(dacno, center_phase); - clock::spin_us(10000); - sync_error_last = dac_get_sync_error(dacno); - for d in 0..128 { - hmc7043::sysref_offset_dac(dacno, center_phase + d); - clock::spin_us(10000); - let sync_error = dac_get_sync_error(dacno); - if sync_error != sync_error_last { - info!(" sync error+: {} -> {}", sync_error_last, sync_error); - margin_plus = Some(d); - break; - } - } - - if margin_minus.is_some() && margin_plus.is_some() { - let margin_minus = margin_minus.unwrap(); - let margin_plus = margin_plus.unwrap(); - info!(" margins: -{} +{}", margin_minus, margin_plus); - if margin_minus < 10 || margin_plus < 10 { - error!("SYSREF margins are too small"); - } - } else { - error!("Unable to determine SYSREF margins"); - } -} - -fn init_dac(dacno: u8, sysref_phase: u16) -> Result<(), &'static str> { +fn init_dac(dacno: u8) -> Result<(), &'static str> { let dacno = dacno as u8; - // Reset the DAC, detect and configure it + dac_reset(dacno); dac_detect(dacno)?; dac_cfg_retry(dacno)?; - // Run the PRBS, STPL and SYSREF scan tests + dac_prbs(dacno)?; dac_stpl(dacno, 4, 2)?; - dac_sysref_scan(dacno, sysref_phase); - // Set SYSREF phase and reconfigure the DAC - hmc7043::sysref_offset_dac(dacno, sysref_phase); + dac_cfg_retry(dacno)?; + Ok(()) } -pub fn init(sysref_phase_dac: u16) { +pub fn init() { for dacno in 0..csr::AD9154.len() { - // We assume DCLK and SYSREF traces are matched on the PCB - // (they are on Sayma) so only one phase is needed. - match init_dac(dacno as u8, sysref_phase_dac) { + match init_dac(dacno as u8) { Ok(_) => (), Err(e) => error!("failed to initialize AD9154-{}: {}", dacno, e) } diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 3879c7b41..9eeaca300 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -1,8 +1,7 @@ -use board_misoc::csr; -use board_misoc::config; +use board_misoc::{csr, clock, config}; use hmc830_7043::hmc7043; - +use ad9154; fn sysref_sample() -> bool { unsafe { csr::sysref_sampler::sample_result_read() == 1 } @@ -142,3 +141,127 @@ pub fn sysref_auto_rtio_align(expected_align: u16) -> Result<(), &'static str> { }; sysref_rtio_align(phase_offset, expected_align) } + +fn sysref_cal_dac(dacno: u8) -> Result { + info!("calibrating SYSREF phase at DAC-{}...", dacno); + + let mut d = 0; + let dmin; + let dmax; + + hmc7043::sysref_offset_dac(dacno, d); + clock::spin_us(10000); + let sync_error_last = ad9154::dac_get_sync_error(dacno); + + loop { + hmc7043::sysref_offset_dac(dacno, d); + clock::spin_us(10000); + let sync_error = ad9154::dac_get_sync_error(dacno); + if sync_error != sync_error_last { + dmin = d; + break; + } + + d += 1; + if d > 128 { + return Err("no sync errors found when scanning delay"); + } + } + + d += 5; // get away from jitter + hmc7043::sysref_offset_dac(dacno, d); + clock::spin_us(10000); + let sync_error_last = ad9154::dac_get_sync_error(dacno); + + loop { + hmc7043::sysref_offset_dac(dacno, d); + clock::spin_us(10000); + let sync_error = ad9154::dac_get_sync_error(dacno); + if sync_error != sync_error_last { + dmax = d; + break; + } + + d += 1; + if d > 128 { + return Err("no sync errors found when scanning delay"); + } + } + + let phase = (dmin+dmax)/2; + info!(" ...done, min={}, max={}, result={}", dmin, dmax, phase); + Ok(phase) +} + +fn sysref_dac_align(dacno: u8, phase: u16) -> Result<(), &'static str> { + let mut margin_minus = None; + let mut margin_plus = None; + + info!("verifying SYSREF margins at DAC-{}...", dacno); + + hmc7043::sysref_offset_dac(dacno, phase); + clock::spin_us(10000); + let sync_error_last = ad9154::dac_get_sync_error(dacno); + for d in 0..128 { + hmc7043::sysref_offset_dac(dacno, phase - d); + clock::spin_us(10000); + let sync_error = ad9154::dac_get_sync_error(dacno); + if sync_error != sync_error_last { + info!(" sync error-: {} -> {}", sync_error_last, sync_error); + margin_minus = Some(d); + break; + } + } + + hmc7043::sysref_offset_dac(dacno, phase); + clock::spin_us(10000); + let sync_error_last = ad9154::dac_get_sync_error(dacno); + for d in 0..128 { + hmc7043::sysref_offset_dac(dacno, phase + d); + clock::spin_us(10000); + let sync_error = ad9154::dac_get_sync_error(dacno); + if sync_error != sync_error_last { + info!(" sync error+: {} -> {}", sync_error_last, sync_error); + margin_plus = Some(d); + break; + } + } + + if margin_minus.is_some() && margin_plus.is_some() { + let margin_minus = margin_minus.unwrap(); + let margin_plus = margin_plus.unwrap(); + info!(" margins: -{} +{}", margin_minus, margin_plus); + if margin_minus < 10 || margin_plus < 10 { + return Err("SYSREF margins at DAC are too small, board needs recalibration"); + } + } else { + return Err("Unable to determine SYSREF margins at DAC"); + } + + // Leave SYSREF at the correct setting + hmc7043::sysref_offset_dac(dacno, phase); + + Ok(()) +} + +pub fn sysref_auto_dac_align() -> Result<(), &'static str> { + // We assume that DAC SYSREF traces are length-matched so only one phase + // value is needed, and we use DAC-0 as calibration reference. + + let entry = config::read_str("sysref_phase_dac", |r| r.map(|s| s.parse())); + let phase = match entry { + Ok(Ok(phase)) => phase, + _ => { + let phase = sysref_cal_dac(0)?; + if let Err(e) = config::write_int("sysref_phase_dac", phase as u32) { + error!("failed to update DAC SYSREF phase in config: {}", e); + } + phase + } + }; + + for dacno in 0..csr::AD9154.len() { + sysref_dac_align(dacno as u8, phase)?; + } + Ok(()) +} diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index edb9e4393..e559db900 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -56,9 +56,6 @@ mod moninj; #[cfg(has_rtio_analyzer)] mod analyzer; -#[cfg(has_ad9154)] -const SYSREF_PHASE_DAC: u16 = 94; - fn startup() { irq::set_mask(0); irq::set_ie(true); @@ -114,10 +111,13 @@ fn startup() { #[cfg(has_ad9154)] { board_artiq::ad9154::jesd_unreset(); + board_artiq::ad9154::init(); if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align(1) { error!("failed to align SYSREF at FPGA: {}", e); } - board_artiq::ad9154::init(SYSREF_PHASE_DAC); + if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() { + error!("failed to align SYSREF at DAC: {}", e); + } } #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); From f8c17528e7b71ba98bcb1fc31540a71e50775dbf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 26 Jul 2018 16:26:57 +0800 Subject: [PATCH 1071/2457] satman: use new SYSREF code --- artiq/firmware/satman/main.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index f1b94849d..1897f8d1e 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -249,10 +249,6 @@ fn drtio_link_rx_up() -> bool { } const SIPHASER_PHASE: u16 = 32; -#[cfg(has_ad9154)] -const SYSREF_PHASE_FPGA: u16 = 54; -#[cfg(has_ad9154)] -const SYSREF_PHASE_DAC: u16 = 61; #[no_mangle] pub extern fn main() -> i32 { @@ -292,7 +288,14 @@ pub extern fn main() -> i32 { #[cfg(has_ad9154)] { if !ad9154_initialized { - board_artiq::ad9154::init(SYSREF_PHASE_FPGA, SYSREF_PHASE_DAC); + board_artiq::ad9154::jesd_unreset(); + board_artiq::ad9154::init(); + if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align(1) { + error!("failed to align SYSREF at FPGA: {}", e); + } + if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() { + error!("failed to align SYSREF at DAC: {}", e); + } ad9154_initialized = true; } } @@ -306,9 +309,10 @@ pub extern fn main() -> i32 { { if drtio_tsc_loaded() { // Expected alignment: 1 RTIO clock period - hmc830_7043::hmc7043::sysref_rtio_align( - SYSREF_PHASE_FPGA, - hmc830_7043::hmc7043::FPGA_CLK_DIV); + if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align( + hmc830_7043::hmc7043::FPGA_CLK_DIV) { + error!("failed to align SYSREF at FPGA: {}", e); + } } } } From 446f791180672bce6b4040f5c47b016410ca9bb5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 26 Jul 2018 19:37:59 +0800 Subject: [PATCH 1072/2457] firmware: simplify SYSREF DRTIO alignment --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 8 +++--- artiq/firmware/libboard_artiq/jesd204sync.rs | 11 +++----- artiq/firmware/runtime/main.rs | 2 +- artiq/firmware/satman/main.rs | 28 +++++++------------- 4 files changed, 18 insertions(+), 31 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index f15102902..8a7b09dee 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -156,10 +156,10 @@ pub mod hmc7043 { use board_misoc::{csr, clock}; // All frequencies assume 1.2GHz HMC830 output - pub const DAC_CLK_DIV: u16 = 2; // 600MHz - pub const FPGA_CLK_DIV: u16 = 8; // 150MHz - pub const SYSREF_DIV: u16 = 128; // 9.375MHz - pub const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // 1.171875MHz (must be <= 4MHz) + const DAC_CLK_DIV: u16 = 2; // 600MHz + const FPGA_CLK_DIV: u16 = 8; // 150MHz + const SYSREF_DIV: u16 = 128; // 9.375MHz + const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // 1.171875MHz (must be <= 4MHz) // enabled, divider, output config const OUTPUT_CONFIG: [(bool, u16, u8); 14] = [ diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 9eeaca300..81cf72cac 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -67,8 +67,8 @@ fn sysref_cal_fpga() -> Result { return Err("failed to reach 1->0 transition with fine delay"); } -fn sysref_rtio_align(phase_offset: u16, expected_align: u16) -> Result<(), &'static str> { - // This needs to take place once before DAC SYSREF scan, as +fn sysref_rtio_align(phase_offset: u16) -> Result<(), &'static str> { + // This needs to take place before DAC SYSREF scan, as // the HMC7043 input clock (which defines slip resolution) // is 2x the DAC clock, so there are two possible phases from // the divider states. This deterministically selects one. @@ -96,9 +96,6 @@ fn sysref_rtio_align(phase_offset: u16, expected_align: u16) -> Result<(), &'sta } } info!(" ...done ({}/{} slips)", slips0, slips1); - if (slips0 + slips1) % expected_align != 0 { - return Err("unexpected slip alignment"); - } let mut margin_minus = None; for d in 0..phase_offset { @@ -127,7 +124,7 @@ fn sysref_rtio_align(phase_offset: u16, expected_align: u16) -> Result<(), &'sta Ok(()) } -pub fn sysref_auto_rtio_align(expected_align: u16) -> Result<(), &'static str> { +pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { let entry = config::read_str("sysref_phase_fpga", |r| r.map(|s| s.parse())); let phase_offset = match entry { Ok(Ok(phase)) => phase, @@ -139,7 +136,7 @@ pub fn sysref_auto_rtio_align(expected_align: u16) -> Result<(), &'static str> { phase } }; - sysref_rtio_align(phase_offset, expected_align) + sysref_rtio_align(phase_offset) } fn sysref_cal_dac(dacno: u8) -> Result { diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index e559db900..7ca63ef31 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -112,7 +112,7 @@ fn startup() { { board_artiq::ad9154::jesd_unreset(); board_artiq::ad9154::init(); - if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align(1) { + if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { error!("failed to align SYSREF at FPGA: {}", e); } if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() { diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 1897f8d1e..d91637dc9 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -274,7 +274,10 @@ pub extern fn main() -> i32 { } #[cfg(has_ad9154)] - let mut ad9154_initialized = false; + { + board_artiq::ad9154::jesd_unreset(); + board_artiq::ad9154::init(); + } #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); @@ -285,34 +288,21 @@ pub extern fn main() -> i32 { info!("link is up, switching to recovered clock"); si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); si5324::siphaser::calibrate_skew(SIPHASER_PHASE).expect("failed to calibrate skew"); - #[cfg(has_ad9154)] - { - if !ad9154_initialized { - board_artiq::ad9154::jesd_unreset(); - board_artiq::ad9154::init(); - if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align(1) { - error!("failed to align SYSREF at FPGA: {}", e); - } - if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() { - error!("failed to align SYSREF at DAC: {}", e); - } - ad9154_initialized = true; - } - } drtioaux::reset(0); drtio_reset(false); drtio_reset_phy(false); while drtio_link_rx_up() { process_errors(); process_aux_packets(); - #[cfg(has_hmc830_7043)] + #[cfg(has_ad9154)] { if drtio_tsc_loaded() { - // Expected alignment: 1 RTIO clock period - if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align( - hmc830_7043::hmc7043::FPGA_CLK_DIV) { + if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { error!("failed to align SYSREF at FPGA: {}", e); } + if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() { + error!("failed to align SYSREF at DAC: {}", e); + } } } } From 83de8b2ba223b51c124aac4c31985eb13c6f5048 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 26 Jul 2018 20:27:53 +0800 Subject: [PATCH 1073/2457] drtio: add ping timeout during link init --- artiq/firmware/runtime/rtio_mgt.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 814c021e2..effa1db5e 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -101,6 +101,9 @@ pub mod drtio { return 0 } count += 1; + if count > 200 { + return 0; + } drtioaux::send_link(linkno, &drtioaux::Packet::EchoRequest).unwrap(); io.sleep(100).unwrap(); let pr = drtioaux::recv_link(linkno); From e4d48a78ebac60b14ec6a6f3a538e533d6ccbccb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 26 Jul 2018 20:28:17 +0800 Subject: [PATCH 1074/2457] drtio: wait for remote to ack TSC synchronization Sayma takes a long time after TSC sync to align SYSREF, and this caused two issues: 1. Aux packets getting lost and causing error reports 2. DRTIO links reported up and kernels proceeding despite the DACs not being properly synced. --- .../firmware/libproto_artiq/drtioaux_proto.rs | 4 +++ artiq/firmware/runtime/rtio_mgt.rs | 27 ++++++++++++++++++- artiq/firmware/satman/main.rs | 9 ++++--- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index ae103f44b..2d0a24e87 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -20,6 +20,7 @@ pub enum Packet { EchoReply, ResetRequest { phy: bool }, ResetAck, + TSCAck, RtioErrorRequest, RtioNoErrorReply, @@ -60,6 +61,7 @@ impl Packet { phy: reader.read_bool()? }, 0x03 => Packet::ResetAck, + 0x04 => Packet::TSCAck, 0x20 => Packet::RtioErrorRequest, 0x21 => Packet::RtioNoErrorReply, @@ -163,6 +165,8 @@ impl Packet { }, Packet::ResetAck => writer.write_u8(0x03)?, + Packet::TSCAck => + writer.write_u8(0x04)?, Packet::RtioErrorRequest => writer.write_u8(0x20)?, diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index effa1db5e..f2a606d86 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -114,6 +114,27 @@ pub mod drtio { } } + fn wait_tsc_ack(linkno: u8, io: &Io) -> bool { + loop { + let mut count = 0; + if !link_rx_up(linkno) { + return false; + } + count += 1; + if count > 200 { + return false; + } + io.sleep(100).unwrap(); + // TSCAck is the only aux packet that is sent spontaneously + // by the satellite, in response to a TSC set on the RT link. + let pr = drtioaux::recv_link(linkno); + match pr { + Ok(Some(drtioaux::Packet::TSCAck)) => return true, + _ => {} + } + } + } + fn process_local_errors(linkno: u8) { let errors; let linkidx = linkno as usize; @@ -173,7 +194,11 @@ pub mod drtio { set_link_up(linkno, true); init_buffer_space(linkno); sync_tsc(linkno); - info!("[LINK#{}] link initialization completed", linkno); + if !wait_tsc_ack(linkno, &io) { + info!("[LINK#{}] remote failed to ack TSC", linkno); + } else { + info!("[LINK#{}] link initialization completed", linkno); + } } else { info!("[LINK#{}] ping failed", linkno); } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index d91637dc9..fb0546cac 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -294,9 +294,9 @@ pub extern fn main() -> i32 { while drtio_link_rx_up() { process_errors(); process_aux_packets(); - #[cfg(has_ad9154)] - { - if drtio_tsc_loaded() { + if drtio_tsc_loaded() { + #[cfg(has_ad9154)] + { if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { error!("failed to align SYSREF at FPGA: {}", e); } @@ -304,6 +304,9 @@ pub extern fn main() -> i32 { error!("failed to align SYSREF at DAC: {}", e); } } + if let Err(e) = drtioaux::send_link(0, &drtioaux::Packet::TSCAck) { + error!("aux packet error: {}", e); + } } } drtio_reset_phy(true); From c00eb181fcac9543a5beb1d7f5f2b908e5d1caca Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 28 Jul 2018 13:17:44 +0800 Subject: [PATCH 1075/2457] conda: bump jesd204b --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 7b79a6866..84da9437a 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -16,7 +16,7 @@ requirements: - setuptools 33.1.1 - migen 0.7 py35_73+gitbef9dea - misoc 0.11 py35_29+git57ebe119 - - jesd204b 0.8 + - jesd204b 0.9 - microscope - binutils-or1k-linux >=2.27 - llvm-or1k 6.0.0 From 6b891065787ae6dbb0c578cb97a3a51f488be248 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 28 Jul 2018 23:45:48 +0100 Subject: [PATCH 1076/2457] ad53xx: Avoid sporadic RTIOUnderflow in init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I observed sporadic RTIO underflows on Kasli before, by ~2.5 µs, so 5 µs extra slack should be plenty. No underflows since. --- artiq/coredevice/ad53xx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 21c85a1d4..b19c246f5 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -171,7 +171,7 @@ class AD53xx: ctrl = self.read_reg(channel=0, op=AD53XX_READ_CONTROL) if ctrl & 0b10000: raise ValueError("DAC over temperature") - delay(10*us) + delay(15*us) self.bus.write( # enable power and overtemperature shutdown (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_CONTROL | 0b0010) << 8) if not blind: From 08ee91beb211bb11c1fdf886ed9911e40c7571e6 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 29 Jul 2018 01:55:51 +0100 Subject: [PATCH 1077/2457] ad9910: Clarify chip_select range [nfc] `assert 3 <= chip_select <= 7` is rather opaque without looking at the CPLD source code otherwise. --- artiq/coredevice/ad9910.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 6ef26a405..59ca91855 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -39,7 +39,8 @@ class AD9910: the digital step attenuator, and the RF switch. :param chip_select: Chip select configuration. On Urukul this is an - encoded chip select and not "one-hot". + encoded chip select and not "one-hot": 3 to address multiple chips + (as configured through CFG_MASK_NU), 4-7 for individual channels. :param cpld_device: Name of the Urukul CPLD this device is on. :param sw_device: Name of the RF switch device. The RF switch is a TTLOut channel available as the :attr:`sw` attribute of this instance. From 829fca611283710ff60e22aca3687dc3e36ebc9b Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 30 Jul 2018 11:08:56 +0100 Subject: [PATCH 1078/2457] pyon: Correctly deserialize bare NaNs This also fixes (non-numpy) lists containing NaNs. Previously, accidentally storing a NaN in a dataset would bring down large parts of the system. --- artiq/protocols/pyon.py | 1 + artiq/test/test_serialization.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/artiq/protocols/pyon.py b/artiq/protocols/pyon.py index 932e95996..cfdaa892e 100644 --- a/artiq/protocols/pyon.py +++ b/artiq/protocols/pyon.py @@ -194,6 +194,7 @@ _eval_dict = { "false": False, "true": True, "slice": slice, + "nan": numpy.nan, "Fraction": Fraction, "OrderedDict": OrderedDict, diff --git a/artiq/test/test_serialization.py b/artiq/test/test_serialization.py index e54234e00..803e42cde 100644 --- a/artiq/test/test_serialization.py +++ b/artiq/test/test_serialization.py @@ -26,6 +26,8 @@ class PYON(unittest.TestCase): with self.subTest(enc=enc): self.assertEqual(pyon.decode(enc(_pyon_test_object)), _pyon_test_object) + # NaNs don't compare equal, so test separately. + assert np.isnan(pyon.decode(enc(np.nan))) def test_encdec_array(self): orig = {k: (np.array(v), np.array([v])) From 5871d13da829e88fb4d3e3c80c90630ea7be9aca Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 1 Aug 2018 16:27:48 +0000 Subject: [PATCH 1079/2457] firmware: actually compact in config::compact(). Fixes #1116. --- artiq/firmware/libboard_misoc/config.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_misoc/config.rs b/artiq/firmware/libboard_misoc/config.rs index ba5da0d42..c44ee36bb 100644 --- a/artiq/firmware/libboard_misoc/config.rs +++ b/artiq/firmware/libboard_misoc/config.rs @@ -212,14 +212,19 @@ mod imp { // so it does not really matter. let mut offset = 0; let mut iter = Iter::new(old_data); - while let Some(result) = iter.next() { + 'iter: while let Some(result) = iter.next() { let (key, mut value) = result?; + if value.is_empty() { + // This is a removed entry, ignore it. + continue + } let mut next_iter = iter.clone(); while let Some(next_result) = next_iter.next() { - let (next_key, next_value) = next_result?; + let (next_key, _) = next_result?; if key == next_key { - value = next_value + // There's another entry that overwrites this one, ignore this one. + continue 'iter } } offset = unsafe { append_at(data, offset, key, value)? }; From e518a1f1d0232da19e2f7316e3f90bebcc089dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 30 Jul 2018 13:51:29 +0000 Subject: [PATCH 1080/2457] ad53xx: also increase slack after control readback --- artiq/coredevice/ad53xx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index b19c246f5..9acdd3104 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -178,7 +178,7 @@ class AD53xx: ctrl = self.read_reg(channel=0, op=AD53XX_READ_CONTROL) if ctrl != 0b0010: raise ValueError("DAC CONTROL readback mismatch") - delay(10*us) + delay(15*us) @kernel def read_reg(self, channel=0, op=AD53XX_READ_X1A): From 7d6a1b528d6cc5ad7b01df11ea5b01fd50d40ed0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 2 Aug 2018 11:19:04 +0000 Subject: [PATCH 1081/2457] ad9912: add ftw_to_frequency --- artiq/coredevice/ad9912.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index f8b139be8..56df7a7ea 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -157,6 +157,13 @@ class AD9912: """ return int64(round(self.ftw_per_hz*frequency)) + @portable(flags={"fast-math"}) + def ftw_to_frequency(self, ftw): + """Returns the frequency corresponding to the given + frequency tuning word. + """ + return ftw/self.ftw_per_hz + @portable(flags={"fast-math"}) def turns_to_pow(self, phase): """Returns the phase offset word corresponding to the given From 47740c89307846c491f7e7e6726195fbe55386ff Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Mon, 30 Jul 2018 23:43:19 +0100 Subject: [PATCH 1082/2457] share moninj injection state between dashboards Previously if one dashboard overrode a channel this was not visible on any other dashboard - the channel appeared to operate normally. --- artiq/coredevice/comm_moninj.py | 10 ++++-- artiq/dashboard/moninj.py | 17 +++++++--- artiq/firmware/libproto_artiq/moninj_proto.rs | 14 +++++--- artiq/firmware/runtime/moninj.rs | 33 ++++++++++++++++--- 4 files changed, 57 insertions(+), 17 deletions(-) diff --git a/artiq/coredevice/comm_moninj.py b/artiq/coredevice/comm_moninj.py index 25fd11ba0..9397c97e5 100644 --- a/artiq/coredevice/comm_moninj.py +++ b/artiq/coredevice/comm_moninj.py @@ -51,16 +51,20 @@ class CommMonInj: del self._reader del self._writer - def monitor(self, enable, channel, probe): + def monitor_probe(self, enable, channel, probe): packet = struct.pack(">bblb", 0, enable, channel, probe) self._writer.write(packet) + def monitor_injection(self, enable, channel, overrd): + packet = struct.pack(">bblb", 1, enable, channel, overrd) + self._writer.write(packet) + def inject(self, channel, override, value): - packet = struct.pack(">blbb", 1, channel, override, value) + packet = struct.pack(">blbb", 2, channel, override, value) self._writer.write(packet) def get_injection_status(self, channel, override): - packet = struct.pack(">blb", 2, channel, override) + packet = struct.pack(">blb", 3, channel, override) self._writer.write(packet) async def _receive_cr(self): diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py index d36807da3..bbd0b9a3e 100644 --- a/artiq/dashboard/moninj.py +++ b/artiq/dashboard/moninj.py @@ -339,18 +339,20 @@ class _DeviceManager: def setup_ttl_monitoring(self, enable, channel): if self.core_connection is not None: - self.core_connection.monitor(enable, channel, TTLProbe.level.value) - self.core_connection.monitor(enable, channel, TTLProbe.oe.value) + self.core_connection.monitor_probe(enable, channel, TTLProbe.level.value) + self.core_connection.monitor_probe(enable, channel, TTLProbe.oe.value) + self.core_connection.monitor_injection(enable, channel, TTLOverride.en.value) + self.core_connection.monitor_injection(enable, channel, TTLOverride.level.value) if enable: self.core_connection.get_injection_status(channel, TTLOverride.en.value) def setup_dds_monitoring(self, enable, bus_channel, channel): if self.core_connection is not None: - self.core_connection.monitor(enable, bus_channel, channel) + self.core_connection.monitor_probe(enable, bus_channel, channel) def setup_dac_monitoring(self, enable, spi_channel, channel): if self.core_connection is not None: - self.core_connection.monitor(enable, spi_channel, channel) + self.core_connection.monitor_probe(enable, spi_channel, channel) def monitor_cb(self, channel, probe, value): if channel in self.ttl_widgets: @@ -371,7 +373,12 @@ class _DeviceManager: def injection_status_cb(self, channel, override, value): if channel in self.ttl_widgets: - self.ttl_widgets[channel].cur_override = bool(value) + widget = self.ttl_widgets[channel] + if override == TTLOverride.en.value: + widget.cur_override = bool(value) + if override == TTLOverride.level.value: + widget.cur_level = bool(value) + widget.refresh_display() async def core_connector(self): while True: diff --git a/artiq/firmware/libproto_artiq/moninj_proto.rs b/artiq/firmware/libproto_artiq/moninj_proto.rs index d6f9a699b..283ecb0f3 100644 --- a/artiq/firmware/libproto_artiq/moninj_proto.rs +++ b/artiq/firmware/libproto_artiq/moninj_proto.rs @@ -32,7 +32,8 @@ pub fn read_magic(reader: &mut R) -> Result<(), Error> #[derive(Debug)] pub enum HostMessage { - Monitor { enable: bool, channel: u32, probe: u8 }, + MonitorProbe { enable: bool, channel: u32, probe: u8 }, + MonitorInjection { enable: bool, channel: u32, overrd: u8 }, Inject { channel: u32, overrd: u8, value: u8 }, GetInjectionStatus { channel: u32, overrd: u8 } } @@ -48,17 +49,22 @@ impl HostMessage { where R: Read + ?Sized { Ok(match reader.read_u8()? { - 0 => HostMessage::Monitor { + 0 => HostMessage::MonitorProbe { enable: if reader.read_u8()? == 0 { false } else { true }, channel: reader.read_u32()?, probe: reader.read_u8()? }, - 1 => HostMessage::Inject { + 1 => HostMessage::MonitorInjection { + enable: if reader.read_u8()? == 0 { false } else { true }, + channel: reader.read_u32()?, + overrd: reader.read_u8()? + }, + 2 => HostMessage::Inject { channel: reader.read_u32()?, overrd: reader.read_u8()?, value: reader.read_u8()? }, - 2 => HostMessage::GetInjectionStatus { + 3 => HostMessage::GetInjectionStatus { channel: reader.read_u32()?, overrd: reader.read_u8()? }, diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index d589d63d2..665927e39 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -146,7 +146,8 @@ fn read_injection_status(channel: u32, probe: u8) -> u8 { } fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error> { - let mut watch_list = BTreeMap::new(); + let mut probe_watch_list = BTreeMap::new(); + let mut inject_watch_list = BTreeMap::new(); let mut next_check = 0; read_magic(&mut stream)?; @@ -158,11 +159,18 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error { + HostMessage::MonitorProbe { enable, channel, probe } => { if enable { - let _ = watch_list.entry((channel, probe)).or_insert(None); + let _ = probe_watch_list.entry((channel, probe)).or_insert(None); } else { - let _ = watch_list.remove(&(channel, probe)); + let _ = probe_watch_list.remove(&(channel, probe)); + } + }, + HostMessage::MonitorInjection { enable, channel, overrd } => { + if enable { + let _ = inject_watch_list.entry((channel, overrd)).or_insert(None); + } else { + let _ = inject_watch_list.remove(&(channel, overrd)); } }, HostMessage::Inject { channel, overrd, value } => inject(channel, overrd, value), @@ -183,7 +191,7 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error next_check { - for (&(channel, probe), previous) in watch_list.iter_mut() { + for (&(channel, probe), previous) in probe_watch_list.iter_mut() { let current = read_probe(channel, probe); if previous.is_none() || previous.unwrap() != current { let message = DeviceMessage::MonitorStatus { @@ -198,6 +206,21 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Errorhost {:?}", message); + message.write_to(stream)?; + + *previous = Some(current); + } + } next_check = clock::get_ms() + 200; } From 04cbc3237be395155da788475021bc785b6bc7fb Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Thu, 2 Aug 2018 11:40:05 +0100 Subject: [PATCH 1083/2457] test_moninj: test injection monitoring --- artiq/test/coredevice/test_moninj.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_moninj.py b/artiq/test/coredevice/test_moninj.py index 2d95e4f8e..bda590bc8 100644 --- a/artiq/test/coredevice/test_moninj.py +++ b/artiq/test/coredevice/test_moninj.py @@ -25,7 +25,9 @@ class MonInjTest(ExperimentCase): loop.run_until_complete(moninj_comm.connect(core_host)) try: moninj_comm.get_injection_status(loop_out_channel, TTLOverride.en.value) - moninj_comm.monitor(True, loop_in_channel, TTLProbe.level.value) + moninj_comm.monitor_probe(True, loop_in_channel, TTLProbe.level.value) + moninj_comm.monitor_injection(True, loop_out_channel, TTLOverride.level.en.value) + loop.run_until_complete(asyncio.sleep(0.5)) moninj_comm.inject(loop_out_channel, TTLOverride.level.value, 0) moninj_comm.inject(loop_out_channel, TTLOverride.level.en.value, 1) loop.run_until_complete(asyncio.sleep(0.5)) @@ -50,5 +52,7 @@ class MonInjTest(ExperimentCase): ]) self.assertEqual(injection_statuses, [ (loop_out_channel, TTLOverride.en.value, 0), + (loop_out_channel, TTLOverride.en.value, 0), + (loop_out_channel, TTLOverride.en.value, 1), (loop_out_channel, TTLOverride.en.value, 1) ]) From 6fc8439399d48c5308bdb6ecc6a692a843865b33 Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Thu, 2 Aug 2018 12:29:43 +0100 Subject: [PATCH 1084/2457] tweak moninj to allow old dashboard with new firmware --- artiq/coredevice/comm_moninj.py | 6 +++--- artiq/firmware/libproto_artiq/moninj_proto.rs | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/artiq/coredevice/comm_moninj.py b/artiq/coredevice/comm_moninj.py index 9397c97e5..08cbcc779 100644 --- a/artiq/coredevice/comm_moninj.py +++ b/artiq/coredevice/comm_moninj.py @@ -56,15 +56,15 @@ class CommMonInj: self._writer.write(packet) def monitor_injection(self, enable, channel, overrd): - packet = struct.pack(">bblb", 1, enable, channel, overrd) + packet = struct.pack(">bblb", 3, enable, channel, overrd) self._writer.write(packet) def inject(self, channel, override, value): - packet = struct.pack(">blbb", 2, channel, override, value) + packet = struct.pack(">blbb", 1, channel, override, value) self._writer.write(packet) def get_injection_status(self, channel, override): - packet = struct.pack(">blb", 3, channel, override) + packet = struct.pack(">blb", 2, channel, override) self._writer.write(packet) async def _receive_cr(self): diff --git a/artiq/firmware/libproto_artiq/moninj_proto.rs b/artiq/firmware/libproto_artiq/moninj_proto.rs index 283ecb0f3..dba2f84bc 100644 --- a/artiq/firmware/libproto_artiq/moninj_proto.rs +++ b/artiq/firmware/libproto_artiq/moninj_proto.rs @@ -54,17 +54,17 @@ impl HostMessage { channel: reader.read_u32()?, probe: reader.read_u8()? }, - 1 => HostMessage::MonitorInjection { - enable: if reader.read_u8()? == 0 { false } else { true }, - channel: reader.read_u32()?, - overrd: reader.read_u8()? - }, - 2 => HostMessage::Inject { + 1 => HostMessage::Inject { channel: reader.read_u32()?, overrd: reader.read_u8()?, value: reader.read_u8()? }, - 3 => HostMessage::GetInjectionStatus { + 2 => HostMessage::GetInjectionStatus { + channel: reader.read_u32()?, + overrd: reader.read_u8()? + }, + 3 => HostMessage::MonitorInjection { + enable: if reader.read_u8()? == 0 { false } else { true }, channel: reader.read_u32()?, overrd: reader.read_u8()? }, From e83ee3a07a3aec91e295ac67d15157c308c412a4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 3 Aug 2018 10:03:52 +0800 Subject: [PATCH 1085/2457] hmc7043: disable GTP_CLK1 when not in use Termination and biasing are not active at the FPGA when IBUFDS_GTE3 is not instantiated, and driving a clock then leads to overvoltage. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 3 +++ artiq/gateware/targets/sayma_amc.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 8a7b09dee..acb8af556 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -171,7 +171,10 @@ pub mod hmc7043 { (false, 0, 0x08), // 5: ADC2_SYSREF (true, FPGA_CLK_DIV, 0x08), // 6: GTP_CLK2 (true, SYSREF_DIV, 0x10), // 7: FPGA_DAC_SYSREF, LVDS +#[cfg(hmc7043_enable_clk1)] (true, FPGA_CLK_DIV, 0x08), // 8: GTP_CLK1 +#[cfg(not(hmc7043_enable_clk1))] + (false, 0, 0x08), // 8: GTP_CLK1 (false, 0, 0x10), // 9: AMC_MASTER_AUX_CLK (false, 0, 0x10), // 10: RTM_MASTER_AUX_CLK (true, FPGA_CLK_DIV, 0x10), // 11: FPGA_ADC_SYSREF, LVDS -- repurposed for siphaser diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index b24bf88fa..8d7def6a0 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -269,6 +269,7 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") + self.config["HMC7043_ENABLE_CLK1"] = None drtio_csr_group = [] drtio_memory_group = [] @@ -571,6 +572,8 @@ class Satellite(BaseSoC, RTMCommon): sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") + self.config["HMC7043_ENABLE_CLK1"] = None + rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) self.submodules.drtio0 = rx0(DRTIOSatellite( From b023865b42cbc51c876e29f80a1766306e2aaf3d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 5 Aug 2018 23:02:41 +0800 Subject: [PATCH 1086/2457] sayma: instantiate dummy IBUFDS_GTE3 on unused but driven Si5324 clock pins Solve same problem as e83ee3a0 but channels cannot be independently disabled. --- artiq/gateware/targets/sayma_amc.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 8d7def6a0..99af7073e 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -151,6 +151,11 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): self.config["HAS_SI5324"] = None self.config["SI5324_AS_SYNTHESIZER"] = None self.config["SI5324_SAYMA_REF"] = None + # ensure pins are properly biased and terminated + si5324_clkout = platform.request("si5324_clkout", 0) + self.specials += Instance( + "IBUFDS_GTE3", i_CEB=0, i_I=si5324_clkout.p, i_IB=si5324_clkout.n, + attr={("DONT_TOUCH", "true")}) # RTIO rtio_channels = [] @@ -258,6 +263,11 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.config["HAS_SI5324"] = None self.config["SI5324_AS_SYNTHESIZER"] = None self.config["SI5324_SAYMA_REF"] = None + # ensure pins are properly biased and terminated + si5324_clkout = platform.request("si5324_clkout", 0) + self.specials += Instance( + "IBUFDS_GTE3", i_CEB=0, i_I=si5324_clkout.p, i_IB=si5324_clkout.n, + attr={("DONT_TOUCH", "true")}) self.comb += [ platform.request("sfp_tx_disable", i).eq(0) @@ -603,6 +613,11 @@ class Satellite(BaseSoC, RTMCommon): self.csr_devices.append("i2c") self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None + # ensure pins are properly biased and terminated + si5324_clkout = platform.request("si5324_clkout", 0) + self.specials += Instance( + "IBUFDS_GTE3", i_CEB=0, i_I=si5324_clkout.p, i_IB=si5324_clkout.n, + attr={("DONT_TOUCH", "true")}) self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( self.drtio0.coarse_ts, self.ad9154_crg.jref) From bd968211de27b556448e420dfa8ada76edc3914f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Aug 2018 00:27:10 +0800 Subject: [PATCH 1087/2457] ad9154: use continuous sync mode --- artiq/firmware/libboard_artiq/ad9154.rs | 29 +++++--------------- artiq/firmware/libboard_artiq/jesd204sync.rs | 22 +++++++-------- 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 978f2a199..87aa8e29f 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -371,27 +371,9 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { write(ad9154_reg::LMFC_VAR_1, 0x0a); write(ad9154_reg::SYNC_ERRWINDOW, 0); // +- 1/2 DAC clock write(ad9154_reg::SYNC_CONTROL, - 0x9*ad9154_reg::SYNCMODE | 0*ad9154_reg::SYNCENABLE | - 0*ad9154_reg::SYNCARM | 1*ad9154_reg::SYNCCLRSTKY | + 0x2*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | 1*ad9154_reg::SYNCCLRLAST); - write(ad9154_reg::SYNC_CONTROL, - 0x9*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | - 0*ad9154_reg::SYNCARM | 1*ad9154_reg::SYNCCLRSTKY | - 1*ad9154_reg::SYNCCLRLAST); - write(ad9154_reg::SYNC_CONTROL, - 0x9*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | - 1*ad9154_reg::SYNCARM | 0*ad9154_reg::SYNCCLRSTKY | - 0*ad9154_reg::SYNCCLRLAST); - clock::spin_us(1000); // ensure at least one sysref edge - if read(ad9154_reg::SYNC_CONTROL) & ad9154_reg::SYNCARM != 0 { - return Err("no sysref edge"); - } - if read(ad9154_reg::SYNC_STATUS) & ad9154_reg::SYNC_LOCK == 0 { - return Err("no sync lock"); - } - if read(ad9154_reg::SYNC_STATUS) & ad9154_reg::SYNC_WLIM != 0 { - return Err("sysref phase error"); - } + write(ad9154_reg::XBAR_LN_0_1, 0*ad9154_reg::LOGICAL_LANE0_SRC | 1*ad9154_reg::LOGICAL_LANE1_SRC); write(ad9154_reg::XBAR_LN_2_3, @@ -689,9 +671,12 @@ fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { pub fn dac_get_sync_error(dacno: u8) -> u16 { spi_setup(dacno); - let sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) | - ((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8)) + let sync_error = ((read(ad9154_reg::SYNC_LASTERR_L) as u16) | + ((read(ad9154_reg::SYNC_LASTERR_H) as u16) << 8)) & 0x1ff; + write(ad9154_reg::SYNC_CONTROL, + 0x2*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | + 1*ad9154_reg::SYNCCLRLAST); sync_error } diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 81cf72cac..4510de794 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -148,13 +148,13 @@ fn sysref_cal_dac(dacno: u8) -> Result { hmc7043::sysref_offset_dac(dacno, d); clock::spin_us(10000); - let sync_error_last = ad9154::dac_get_sync_error(dacno); + ad9154::dac_get_sync_error(dacno); // clear SYNC_LASTERR loop { hmc7043::sysref_offset_dac(dacno, d); clock::spin_us(10000); let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != sync_error_last { + if sync_error != 0 { dmin = d; break; } @@ -165,16 +165,16 @@ fn sysref_cal_dac(dacno: u8) -> Result { } } - d += 5; // get away from jitter + d += 17; // get away from jitter hmc7043::sysref_offset_dac(dacno, d); clock::spin_us(10000); - let sync_error_last = ad9154::dac_get_sync_error(dacno); + ad9154::dac_get_sync_error(dacno); // clear SYNC_LASTERR loop { hmc7043::sysref_offset_dac(dacno, d); clock::spin_us(10000); let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != sync_error_last { + if sync_error != 0 { dmax = d; break; } @@ -198,13 +198,13 @@ fn sysref_dac_align(dacno: u8, phase: u16) -> Result<(), &'static str> { hmc7043::sysref_offset_dac(dacno, phase); clock::spin_us(10000); - let sync_error_last = ad9154::dac_get_sync_error(dacno); + ad9154::dac_get_sync_error(dacno); // clear SYNC_LASTERR for d in 0..128 { hmc7043::sysref_offset_dac(dacno, phase - d); clock::spin_us(10000); let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != sync_error_last { - info!(" sync error-: {} -> {}", sync_error_last, sync_error); + if sync_error != 0 { + info!(" sync error-: {}", sync_error); margin_minus = Some(d); break; } @@ -212,13 +212,13 @@ fn sysref_dac_align(dacno: u8, phase: u16) -> Result<(), &'static str> { hmc7043::sysref_offset_dac(dacno, phase); clock::spin_us(10000); - let sync_error_last = ad9154::dac_get_sync_error(dacno); + ad9154::dac_get_sync_error(dacno); // clear SYNC_LASTERR for d in 0..128 { hmc7043::sysref_offset_dac(dacno, phase + d); clock::spin_us(10000); let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != sync_error_last { - info!(" sync error+: {} -> {}", sync_error_last, sync_error); + if sync_error != 0 { + info!(" sync error+: {}", sync_error); margin_plus = Some(d); break; } From 65f198bdeed0553984db7787de9c202ab0e5ce1d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Aug 2018 16:53:13 +0800 Subject: [PATCH 1088/2457] kasli: use tester EEMs for DRTIO, add Urukul-Sayma sync example --- artiq/examples/kasli_sawgmaster/device_db.py | 71 +++++++++++++++++++ .../{sines_drtio.py => sines_2sayma.py} | 2 +- artiq/gateware/targets/kasli.py | 10 ++- 3 files changed, 79 insertions(+), 4 deletions(-) rename artiq/examples/kasli_sawgmaster/repository/{sines_drtio.py => sines_2sayma.py} (96%) diff --git a/artiq/examples/kasli_sawgmaster/device_db.py b/artiq/examples/kasli_sawgmaster/device_db.py index 91ed71102..fe60a48d6 100644 --- a/artiq/examples/kasli_sawgmaster/device_db.py +++ b/artiq/examples/kasli_sawgmaster/device_db.py @@ -25,6 +25,77 @@ device_db = { }, } +for i in range(8): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": 3+i}, + } + +device_db.update( + spi_urukul0={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 11} + }, + ttl_urukul0_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 12} + }, + ttl_urukul0_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 13} + }, + ttl_urukul0_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 14} + }, + ttl_urukul0_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 15} + }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 16} + }, + urukul0_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 150e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul0_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 26, # 975MHz sample rate + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } + for i in range(8): device_db["sawg" + str(i)] = { "type": "local", diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_drtio.py b/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py similarity index 96% rename from artiq/examples/kasli_sawgmaster/repository/sines_drtio.py rename to artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py index 683a83523..9b8e4d661 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_drtio.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py @@ -1,7 +1,7 @@ from artiq.experiment import * -class SAWGTestDRTIO(EnvExperiment): +class Sines2Sayma(EnvExperiment): def build(self): self.setattr_device("core") self.sawgs = [self.get_device("sawg"+str(i)) for i in range(16)] diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b59b5c330..091ed573d 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -850,7 +850,10 @@ class Master(_MasterBase): phy = ttl_simple.Output(sc.led) self.submodules += phy self.rtio_channels.append(rtio.Channel.from_phy(phy)) - eem.DIO.add_std(self, 0, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.InOut_8X) + # matches Tester EEM numbers + eem.DIO.add_std(self, 5, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 1, 0, ttl_serdes_7series.Output_8X) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) @@ -863,7 +866,6 @@ class Satellite(_SatelliteBase): def __init__(self, *args, **kwargs): _SatelliteBase.__init__(self, *args, **kwargs) - self.rtio_channels = [] phy = ttl_simple.Output(self.platform.request("user_led", 0)) self.submodules += phy @@ -872,7 +874,9 @@ class Satellite(_SatelliteBase): phy = ttl_simple.Output(self.platform.request("sfp_ctl", i).led) self.submodules += phy self.rtio_channels.append(rtio.Channel.from_phy(phy)) - eem.DIO.add_std(self, 0, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.InOut_8X) + # matches Tester EEM numbers + eem.DIO.add_std(self, 5, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) self.add_rtio(self.rtio_channels) From f32f0126e2cedfe2adaffdaa1ff2e22ff346d892 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Aug 2018 16:59:53 +0800 Subject: [PATCH 1089/2457] Revert "ad9154: use continuous sync mode" The HMC7043 is not really glitchless. This reverts commit bd968211de27b556448e420dfa8ada76edc3914f. --- artiq/firmware/libboard_artiq/ad9154.rs | 29 +++++++++++++++----- artiq/firmware/libboard_artiq/jesd204sync.rs | 22 +++++++-------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 87aa8e29f..978f2a199 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -371,9 +371,27 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { write(ad9154_reg::LMFC_VAR_1, 0x0a); write(ad9154_reg::SYNC_ERRWINDOW, 0); // +- 1/2 DAC clock write(ad9154_reg::SYNC_CONTROL, - 0x2*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | + 0x9*ad9154_reg::SYNCMODE | 0*ad9154_reg::SYNCENABLE | + 0*ad9154_reg::SYNCARM | 1*ad9154_reg::SYNCCLRSTKY | 1*ad9154_reg::SYNCCLRLAST); - + write(ad9154_reg::SYNC_CONTROL, + 0x9*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | + 0*ad9154_reg::SYNCARM | 1*ad9154_reg::SYNCCLRSTKY | + 1*ad9154_reg::SYNCCLRLAST); + write(ad9154_reg::SYNC_CONTROL, + 0x9*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | + 1*ad9154_reg::SYNCARM | 0*ad9154_reg::SYNCCLRSTKY | + 0*ad9154_reg::SYNCCLRLAST); + clock::spin_us(1000); // ensure at least one sysref edge + if read(ad9154_reg::SYNC_CONTROL) & ad9154_reg::SYNCARM != 0 { + return Err("no sysref edge"); + } + if read(ad9154_reg::SYNC_STATUS) & ad9154_reg::SYNC_LOCK == 0 { + return Err("no sync lock"); + } + if read(ad9154_reg::SYNC_STATUS) & ad9154_reg::SYNC_WLIM != 0 { + return Err("sysref phase error"); + } write(ad9154_reg::XBAR_LN_0_1, 0*ad9154_reg::LOGICAL_LANE0_SRC | 1*ad9154_reg::LOGICAL_LANE1_SRC); write(ad9154_reg::XBAR_LN_2_3, @@ -671,12 +689,9 @@ fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { pub fn dac_get_sync_error(dacno: u8) -> u16 { spi_setup(dacno); - let sync_error = ((read(ad9154_reg::SYNC_LASTERR_L) as u16) | - ((read(ad9154_reg::SYNC_LASTERR_H) as u16) << 8)) + let sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) | + ((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8)) & 0x1ff; - write(ad9154_reg::SYNC_CONTROL, - 0x2*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | - 1*ad9154_reg::SYNCCLRLAST); sync_error } diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 4510de794..81cf72cac 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -148,13 +148,13 @@ fn sysref_cal_dac(dacno: u8) -> Result { hmc7043::sysref_offset_dac(dacno, d); clock::spin_us(10000); - ad9154::dac_get_sync_error(dacno); // clear SYNC_LASTERR + let sync_error_last = ad9154::dac_get_sync_error(dacno); loop { hmc7043::sysref_offset_dac(dacno, d); clock::spin_us(10000); let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != 0 { + if sync_error != sync_error_last { dmin = d; break; } @@ -165,16 +165,16 @@ fn sysref_cal_dac(dacno: u8) -> Result { } } - d += 17; // get away from jitter + d += 5; // get away from jitter hmc7043::sysref_offset_dac(dacno, d); clock::spin_us(10000); - ad9154::dac_get_sync_error(dacno); // clear SYNC_LASTERR + let sync_error_last = ad9154::dac_get_sync_error(dacno); loop { hmc7043::sysref_offset_dac(dacno, d); clock::spin_us(10000); let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != 0 { + if sync_error != sync_error_last { dmax = d; break; } @@ -198,13 +198,13 @@ fn sysref_dac_align(dacno: u8, phase: u16) -> Result<(), &'static str> { hmc7043::sysref_offset_dac(dacno, phase); clock::spin_us(10000); - ad9154::dac_get_sync_error(dacno); // clear SYNC_LASTERR + let sync_error_last = ad9154::dac_get_sync_error(dacno); for d in 0..128 { hmc7043::sysref_offset_dac(dacno, phase - d); clock::spin_us(10000); let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != 0 { - info!(" sync error-: {}", sync_error); + if sync_error != sync_error_last { + info!(" sync error-: {} -> {}", sync_error_last, sync_error); margin_minus = Some(d); break; } @@ -212,13 +212,13 @@ fn sysref_dac_align(dacno: u8, phase: u16) -> Result<(), &'static str> { hmc7043::sysref_offset_dac(dacno, phase); clock::spin_us(10000); - ad9154::dac_get_sync_error(dacno); // clear SYNC_LASTERR + let sync_error_last = ad9154::dac_get_sync_error(dacno); for d in 0..128 { hmc7043::sysref_offset_dac(dacno, phase + d); clock::spin_us(10000); let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != 0 { - info!(" sync error+: {}", sync_error); + if sync_error != sync_error_last { + info!(" sync error+: {} -> {}", sync_error_last, sync_error); margin_plus = Some(d); break; } From 7f0b2ff5943364fb43ecd0d022840a70fa5a2bc2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Aug 2018 17:42:53 +0800 Subject: [PATCH 1090/2457] jesd204sync: work around HMC7043 poor behavior with combined delays The HMC7043 outputs poorly controlled signals when adjusting two delays at once. This commit puts the DAC in one-shot SYSREF mode, and only triggers synchronizations when SYSREF is stable. --- artiq/firmware/libboard_artiq/ad9154.rs | 47 +++++++++----------- artiq/firmware/libboard_artiq/jesd204sync.rs | 41 +++++++---------- 2 files changed, 36 insertions(+), 52 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 978f2a199..a1c384da9 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -370,28 +370,7 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { write(ad9154_reg::LMFC_VAR_0, 0x0a); // receive buffer delay write(ad9154_reg::LMFC_VAR_1, 0x0a); write(ad9154_reg::SYNC_ERRWINDOW, 0); // +- 1/2 DAC clock - write(ad9154_reg::SYNC_CONTROL, - 0x9*ad9154_reg::SYNCMODE | 0*ad9154_reg::SYNCENABLE | - 0*ad9154_reg::SYNCARM | 1*ad9154_reg::SYNCCLRSTKY | - 1*ad9154_reg::SYNCCLRLAST); - write(ad9154_reg::SYNC_CONTROL, - 0x9*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | - 0*ad9154_reg::SYNCARM | 1*ad9154_reg::SYNCCLRSTKY | - 1*ad9154_reg::SYNCCLRLAST); - write(ad9154_reg::SYNC_CONTROL, - 0x9*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | - 1*ad9154_reg::SYNCARM | 0*ad9154_reg::SYNCCLRSTKY | - 0*ad9154_reg::SYNCCLRLAST); - clock::spin_us(1000); // ensure at least one sysref edge - if read(ad9154_reg::SYNC_CONTROL) & ad9154_reg::SYNCARM != 0 { - return Err("no sysref edge"); - } - if read(ad9154_reg::SYNC_STATUS) & ad9154_reg::SYNC_LOCK == 0 { - return Err("no sync lock"); - } - if read(ad9154_reg::SYNC_STATUS) & ad9154_reg::SYNC_WLIM != 0 { - return Err("sysref phase error"); - } + write(ad9154_reg::XBAR_LN_0_1, 0*ad9154_reg::LOGICAL_LANE0_SRC | 1*ad9154_reg::LOGICAL_LANE1_SRC); write(ad9154_reg::XBAR_LN_2_3, @@ -687,12 +666,26 @@ fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { } } -pub fn dac_get_sync_error(dacno: u8) -> u16 { +pub fn dac_sync(dacno: u8) -> Result { spi_setup(dacno); - let sync_error = ((read(ad9154_reg::SYNC_CURRERR_L) as u16) | - ((read(ad9154_reg::SYNC_CURRERR_H) as u16) << 8)) - & 0x1ff; - sync_error + + write(ad9154_reg::SYNC_CONTROL, + 0x1*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | + 1*ad9154_reg::SYNCARM | 1*ad9154_reg::SYNCCLRSTKY); + clock::spin_us(1000); // ensure at least one sysref edge + let sync_status = read(ad9154_reg::SYNC_STATUS); + + if sync_status & ad9154_reg::SYNC_BUSY != 0 { + return Err("sync logic busy"); + } + if sync_status & ad9154_reg::SYNC_LOCK == 0 { + return Err("no sync lock"); + } + if sync_status & ad9154_reg::SYNC_TRIP == 0 { + return Err("no sysref edge"); + } + let realign_occured = sync_status & ad9154_reg::SYNC_ROTATE != 0; + Ok(realign_occured) } fn init_dac(dacno: u8) -> Result<(), &'static str> { diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 81cf72cac..c4cc18810 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -1,4 +1,4 @@ -use board_misoc::{csr, clock, config}; +use board_misoc::{csr, config}; use hmc830_7043::hmc7043; use ad9154; @@ -147,14 +147,12 @@ fn sysref_cal_dac(dacno: u8) -> Result { let dmax; hmc7043::sysref_offset_dac(dacno, d); - clock::spin_us(10000); - let sync_error_last = ad9154::dac_get_sync_error(dacno); + ad9154::dac_sync(dacno)?; loop { hmc7043::sysref_offset_dac(dacno, d); - clock::spin_us(10000); - let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != sync_error_last { + let realign_occured = ad9154::dac_sync(dacno)?; + if realign_occured { dmin = d; break; } @@ -165,16 +163,14 @@ fn sysref_cal_dac(dacno: u8) -> Result { } } - d += 5; // get away from jitter + d += 17; // get away from jitter hmc7043::sysref_offset_dac(dacno, d); - clock::spin_us(10000); - let sync_error_last = ad9154::dac_get_sync_error(dacno); + ad9154::dac_sync(dacno)?; loop { hmc7043::sysref_offset_dac(dacno, d); - clock::spin_us(10000); - let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != sync_error_last { + let realign_occured = ad9154::dac_sync(dacno)?; + if realign_occured { dmax = d; break; } @@ -197,28 +193,22 @@ fn sysref_dac_align(dacno: u8, phase: u16) -> Result<(), &'static str> { info!("verifying SYSREF margins at DAC-{}...", dacno); hmc7043::sysref_offset_dac(dacno, phase); - clock::spin_us(10000); - let sync_error_last = ad9154::dac_get_sync_error(dacno); + ad9154::dac_sync(dacno)?; for d in 0..128 { hmc7043::sysref_offset_dac(dacno, phase - d); - clock::spin_us(10000); - let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != sync_error_last { - info!(" sync error-: {} -> {}", sync_error_last, sync_error); + let realign_occured = ad9154::dac_sync(dacno)?; + if realign_occured { margin_minus = Some(d); break; } } hmc7043::sysref_offset_dac(dacno, phase); - clock::spin_us(10000); - let sync_error_last = ad9154::dac_get_sync_error(dacno); + ad9154::dac_sync(dacno)?; for d in 0..128 { hmc7043::sysref_offset_dac(dacno, phase + d); - clock::spin_us(10000); - let sync_error = ad9154::dac_get_sync_error(dacno); - if sync_error != sync_error_last { - info!(" sync error+: {} -> {}", sync_error_last, sync_error); + let realign_occured = ad9154::dac_sync(dacno)?; + if realign_occured { margin_plus = Some(d); break; } @@ -235,8 +225,9 @@ fn sysref_dac_align(dacno: u8, phase: u16) -> Result<(), &'static str> { return Err("Unable to determine SYSREF margins at DAC"); } - // Leave SYSREF at the correct setting + // Put SYSREF at the correct phase and sync DAC hmc7043::sysref_offset_dac(dacno, phase); + ad9154::dac_sync(dacno)?; Ok(()) } From bbe36b94f7da6244a473349221ca35eb2dacfe0d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Aug 2018 19:02:27 +0800 Subject: [PATCH 1091/2457] ad9154: enable sync in init --- artiq/firmware/libboard_artiq/ad9154.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index a1c384da9..c210301fd 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -370,6 +370,11 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { write(ad9154_reg::LMFC_VAR_0, 0x0a); // receive buffer delay write(ad9154_reg::LMFC_VAR_1, 0x0a); write(ad9154_reg::SYNC_ERRWINDOW, 0); // +- 1/2 DAC clock + // datasheet seems to say ENABLE and ARM should be separate steps, + // so enable now so it can be armed in dac_sync(). + write(ad9154_reg::SYNC_CONTROL, + 0x1*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | + 0*ad9154_reg::SYNCARM | 0*ad9154_reg::SYNCCLRSTKY); write(ad9154_reg::XBAR_LN_0_1, 0*ad9154_reg::LOGICAL_LANE0_SRC | 1*ad9154_reg::LOGICAL_LANE1_SRC); From 2008d02f4d1b4dddf69037118910e7e13bf4cc44 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 7 Aug 2018 10:30:50 +0800 Subject: [PATCH 1092/2457] runtime: use different default IP and MAC for different kinds of boards This helps reduce conflicts when having many boards on a development network. --- artiq/firmware/runtime/main.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 7ca63ef31..494c3ff87 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -207,7 +207,18 @@ fn startup_ethernet() { info!("using MAC address {}", hardware_addr); } _ => { - hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); + #[cfg(soc_platform = "kasli")] + { + hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x21]); + } + #[cfg(soc_platform = "sayma_amc")] + { + hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x11]); + } + #[cfg(soc_platform = "kc705")] + { + hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); + } warn!("using default MAC address {}; consider changing it", hardware_addr); } } @@ -219,7 +230,18 @@ fn startup_ethernet() { info!("using IP address {}", protocol_addr); } _ => { - protocol_addr = IpAddress::v4(192, 168, 1, 50); + #[cfg(soc_platform = "kasli")] + { + protocol_addr = IpAddress::v4(192, 168, 1, 70); + } + #[cfg(soc_platform = "sayma_amc")] + { + protocol_addr = IpAddress::v4(192, 168, 1, 60); + } + #[cfg(soc_platform = "kc705")] + { + protocol_addr = IpAddress::v4(192, 168, 1, 50); + } info!("using default IP address {}", protocol_addr); } } From a74958f01fe2fa5e043d33ff9c53e5149b4442e1 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 7 Aug 2018 05:53:13 +0000 Subject: [PATCH 1093/2457] ksupport: raise RuntimeError on reraise with no inflight exception. Fixes #1123. --- artiq/compiler/builtins.py | 3 +++ artiq/coredevice/comm_kernel.py | 2 +- artiq/coredevice/exceptions.py | 1 + artiq/firmware/ksupport/eh.rs | 18 ++++++++++++++++-- artiq/firmware/ksupport/lib.rs | 8 ++++---- 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/artiq/compiler/builtins.py b/artiq/compiler/builtins.py index 77e102d3b..d60db0840 100644 --- a/artiq/compiler/builtins.py +++ b/artiq/compiler/builtins.py @@ -169,6 +169,9 @@ def fn_ValueError(): def fn_ZeroDivisionError(): return types.TExceptionConstructor(TException("ZeroDivisionError")) +def fn_RuntimeError(): + return types.TExceptionConstructor(TException("RuntimeError")) + def fn_range(): return types.TBuiltinFunction("range") diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 7bec59580..2cadd0d60 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -447,7 +447,7 @@ class CommKernel: self._write_string(function) else: exn_type = type(exn) - if exn_type in (ZeroDivisionError, ValueError, IndexError) or \ + if exn_type in (ZeroDivisionError, ValueError, IndexError, RuntimeError) or \ hasattr(exn, "artiq_builtin"): self._write_string("0:{}".format(exn_type.__name__)) else: diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index 8264c7a55..017266729 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -10,6 +10,7 @@ from artiq.coredevice.runtime import source_loader ZeroDivisionError = builtins.ZeroDivisionError ValueError = builtins.ValueError IndexError = builtins.IndexError +RuntimeError = builtins.RuntimeError class CoreException: diff --git a/artiq/firmware/ksupport/eh.rs b/artiq/firmware/ksupport/eh.rs index 5cd220bbc..73ba51ae2 100644 --- a/artiq/firmware/ksupport/eh.rs +++ b/artiq/firmware/ksupport/eh.rs @@ -392,7 +392,7 @@ static mut INFLIGHT: ExceptionInfo = ExceptionInfo { private: [0; uw::unwinder_private_data_size], }, exception: None, - handled: false, + handled: true, backtrace: [0; MAX_BACKTRACE_SIZE], backtrace_size: 0 }; @@ -418,8 +418,22 @@ pub unsafe extern fn raise(exception: *const Exception) -> ! { #[export_name="__artiq_reraise"] #[unwind(allowed)] pub unsafe extern fn reraise() -> ! { + use cslice::AsCSlice; + if INFLIGHT.handled { - raise(&INFLIGHT.exception.unwrap()) + match INFLIGHT.exception { + Some(ref exception) => raise(exception), + None => raise(&Exception { + name: "0:artiq.coredevice.exceptions.RuntimeError".as_c_slice(), + file: file!().as_c_slice(), + line: line!(), + column: column!(), + // https://github.com/rust-lang/rfcs/pull/1719 + function: "__artiq_reraise".as_c_slice(), + message: "No active exception to reraise".as_c_slice(), + param: [0, 0, 0] + }) + } } else { uw::_Unwind_Resume(&mut INFLIGHT.uw_exception) } diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 73360ce05..b3a18bf1a 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -68,13 +68,13 @@ macro_rules! raise { ($name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => ({ use cslice::AsCSlice; let exn = $crate::eh::Exception { - name: concat!("0:artiq.coredevice.exceptions.", $name).as_bytes().as_c_slice(), - file: file!().as_bytes().as_c_slice(), + name: concat!("0:artiq.coredevice.exceptions.", $name).as_c_slice(), + file: file!().as_c_slice(), line: line!(), column: column!(), // https://github.com/rust-lang/rfcs/pull/1719 - function: "(Rust function)".as_bytes().as_c_slice(), - message: $message.as_bytes().as_c_slice(), + function: "(Rust function)".as_c_slice(), + message: $message.as_c_slice(), param: [$param0, $param1, $param2] }; #[allow(unused_unsafe)] From 259f1576c3cadc71059252160f6859edd8856d4a Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 7 Aug 2018 06:06:49 +0000 Subject: [PATCH 1094/2457] Fix tests after a74958f0. --- artiq/test/libartiq_support/lib.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/artiq/test/libartiq_support/lib.rs b/artiq/test/libartiq_support/lib.rs index d9c609fe0..b3188e17a 100644 --- a/artiq/test/libartiq_support/lib.rs +++ b/artiq/test/libartiq_support/lib.rs @@ -34,6 +34,20 @@ mod cslice { } } } + + pub trait AsCSlice<'a, T> { + fn as_c_slice(&'a self) -> CSlice<'a, T>; + } + + impl<'a> AsCSlice<'a, u8> for str { + fn as_c_slice(&'a self) -> CSlice<'a, u8> { + CSlice { + base: self.as_ptr(), + len: self.len() as u32, + phantom: PhantomData + } + } + } } #[path = "../../firmware/ksupport/eh.rs"] From 7bd7b6592a531c0f78fbec1ee612f7bcf5a3bf79 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 7 Aug 2018 06:47:09 +0000 Subject: [PATCH 1095/2457] rpc_proto: serialize keywords correctly. Fixes #1109. --- artiq/firmware/libproto_artiq/rpc_proto.rs | 4 +-- artiq/test/coredevice/test_portability.py | 29 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libproto_artiq/rpc_proto.rs b/artiq/firmware/libproto_artiq/rpc_proto.rs index 8c39251f7..dfd1a1dfa 100644 --- a/artiq/firmware/libproto_artiq/rpc_proto.rs +++ b/artiq/firmware/libproto_artiq/rpc_proto.rs @@ -151,11 +151,11 @@ unsafe fn send_value(writer: &mut W, tag: Tag, data: &mut *const ()) Ok(()) } Tag::Keyword(it) => { - struct Keyword<'a> { name: CSlice<'a, u8>, contents: () }; + struct Keyword<'a> { name: CSlice<'a, u8> }; consume_value!(Keyword, |ptr| { writer.write_string(str::from_utf8((*ptr).name.as_ref()).unwrap())?; let tag = it.clone().next().expect("truncated tag"); - let mut data = &(*ptr).contents as *const (); + let mut data = ptr.offset(1) as *const (); send_value(writer, tag, &mut data) }) // Tag::Keyword never appears in composite types, so we don't have diff --git a/artiq/test/coredevice/test_portability.py b/artiq/test/coredevice/test_portability.py index cd301d29b..2238ea805 100644 --- a/artiq/test/coredevice/test_portability.py +++ b/artiq/test/coredevice/test_portability.py @@ -202,6 +202,20 @@ class _RPCExceptions(EnvExperiment): self.success = True +class _Keywords(EnvExperiment): + def build(self, value, output): + self.setattr_device("core") + self.value = value + self.output = output + + def rpc(self, kw): + self.output.append(kw) + + @kernel + def run(self): + self.rpc(kw=self.value) + + class HostVsDeviceCase(ExperimentCase): def test_primes(self): l_device, l_host = [], [] @@ -245,3 +259,18 @@ class HostVsDeviceCase(ExperimentCase): f(_RPCExceptions, catch=False) uut = self.execute(_RPCExceptions, catch=True) self.assertTrue(uut.success) + + def test_keywords(self): + for f in self.execute, _run_on_host: + output = [] + f(_Keywords, value=0, output=output) + self.assertEqual(output, [0]) + output = [] + f(_Keywords, value=1, output=output) + self.assertEqual(output, [1]) + output = [] + f(_Keywords, value=False, output=output) + self.assertEqual(output, [False]) + output = [] + f(_Keywords, value=True, output=output) + self.assertEqual(output, [True]) From 93af5d2a03a4dafcd52df509cefddf925dff3014 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 7 Aug 2018 07:06:53 +0000 Subject: [PATCH 1096/2457] compiler: handle async RPC as last statement in try block. Fixes #1107. --- artiq/compiler/transforms/llvm_ir_generator.py | 6 ++++++ artiq/test/coredevice/test_embedding.py | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index afbc6cbc9..013d2a5ea 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -1339,6 +1339,12 @@ class LLVMIRGenerator: self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr]) if fun_type.async: + # If this RPC is called using an `invoke` ARTIQ IR instruction, there will be + # no other instructions in this basic block. Since this RPC is async, it cannot + # possibly raise an exception, so add an explicit jump to the normal successor. + if llunwindblock: + self.llbuilder.branch(llnormalblock) + return ll.Undefined # T result = { diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index d8d85d5e0..21f0c14f2 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -223,6 +223,17 @@ class _RPCCalls(EnvExperiment): def builtin(self): sleep(1.0) + @rpc(flags={"async"}) + def async_rpc(self): + pass + + @kernel + def async_in_try(self): + try: + self.async_rpc() + except ValueError: + pass + class RPCCallsTest(ExperimentCase): def test_args(self): @@ -239,6 +250,7 @@ class RPCCallsTest(ExperimentCase): self.assertTrue((exp.numpy_full() == numpy.full(10, 20)).all()) self.assertTrue(numpy.isnan(exp.numpy_nan()).all()) exp.builtin() + exp.async_in_try() class _Annotation(EnvExperiment): From 474bc7b65bac3fb5ab97436ba9ac51090243eced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 7 Aug 2018 12:57:01 +0200 Subject: [PATCH 1097/2457] browser: handle windows file urls for feeding h5py close #1014 --- artiq/browser/experiments.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/browser/experiments.py b/artiq/browser/experiments.py index c1a531152..da501e038 100644 --- a/artiq/browser/experiments.py +++ b/artiq/browser/experiments.py @@ -258,8 +258,9 @@ class _ExperimentDock(QtWidgets.QMdiSubWindow): def dropEvent(self, ev): for uri in ev.mimeData().urls(): if uri.scheme() == "file": - logger.debug("Loading HDF5 arguments from %s", uri.path()) - asyncio.ensure_future(self.load_hdf5_task(uri.path())) + filename = QtCore.QDir.toNativeSeparators(uri.toLocalFile()) + logger.debug("Loading HDF5 arguments from %s", filename) + asyncio.ensure_future(self.load_hdf5_task(filename)) break async def compute_arginfo(self): From 8aa88cfe7013e437662ad78e4844af640ec85b4b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 7 Aug 2018 17:21:31 +0800 Subject: [PATCH 1098/2457] kasli_sawgmaster: add Urukul-Sayma example --- .../repository/sines_urukul_sayma.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py new file mode 100644 index 000000000..2ba4bb21b --- /dev/null +++ b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py @@ -0,0 +1,42 @@ +from artiq.experiment import * + + +class SinesUrukulSayma(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("urukul0_cpld") + self.urukul_chs = [self.get_device("urukul0_ch" + str(i)) for i in range(4)] + self.sawgs = [self.get_device("sawg"+str(i)) for i in range(8)] + + @kernel + def run(self): + # Note: when testing sync, do not reboot Urukul, as it is not + # synchronized to the FPGA (yet). + self.core.reset() + self.urukul0_cpld.init() + for urukul_ch in self.urukul_chs: + delay(1*ms) + urukul_ch.init() + urukul_ch.set(9*MHz) + urukul_ch.set_att(6.) + urukul_ch.sw.on() + + while True: + print("waiting for DRTIO ready...") + while not self.core.get_drtio_link_status(0): + pass + print("OK") + + self.core.reset() + + for sawg in self.sawgs: + delay(1*ms) + sawg.reset() + + for sawg in self.sawgs: + delay(1*ms) + sawg.amplitude1.set(.4) + sawg.frequency0.set(9*MHz) + + while self.core.get_drtio_link_status(0): + pass From 9ce623392697b45a75e168b782699128fc892740 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 7 Aug 2018 19:28:40 +0800 Subject: [PATCH 1099/2457] kasli: fix SYSU TTL directions --- artiq/examples/kasli_basic/device_db_sysu.py | 2 +- artiq/gateware/targets/kasli.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/artiq/examples/kasli_basic/device_db_sysu.py b/artiq/examples/kasli_basic/device_db_sysu.py index bd1de2c82..e5e71b9d9 100644 --- a/artiq/examples/kasli_basic/device_db_sysu.py +++ b/artiq/examples/kasli_basic/device_db_sysu.py @@ -42,7 +42,7 @@ for i in range(40): device_db["ttl" + str(i)] = { "type": "local", "module": "artiq.coredevice.ttl", - "class": "TTLInOut" if i < 4 else "TTLOut", + "class": "TTLInOut" if i < 16 else "TTLOut", "arguments": {"channel": i}, } diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 091ed573d..883997f9f 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -246,8 +246,10 @@ class SYSU(_StandaloneBase): self.rtio_channels = [] eem.DIO.add_std(self, 2, - ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) - for i in range(3, 7): + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.InOut_8X) + eem.DIO.add_std(self, 3, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.InOut_8X) + for i in range(4, 7): eem.DIO.add_std(self, i, ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) eem.Urukul.add_std(self, 1, 0, ttl_serdes_7series.Output_8X) From 8b8e1844f057c149484bb60c2f19ee6d79771a7b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 7 Aug 2018 20:07:21 +0800 Subject: [PATCH 1100/2457] kasli_sawgmaster: roughly match Urukul and Sayma amplitudes --- .../examples/kasli_sawgmaster/repository/sines_urukul_sayma.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py index 2ba4bb21b..318a6e1ab 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py @@ -17,7 +17,7 @@ class SinesUrukulSayma(EnvExperiment): for urukul_ch in self.urukul_chs: delay(1*ms) urukul_ch.init() - urukul_ch.set(9*MHz) + urukul_ch.set(9*MHz, amplitude=0.5) urukul_ch.set_att(6.) urukul_ch.sw.on() From e2a49ce368a7952285b62cfd0eb9d8837aaf3de5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 7 Aug 2018 20:52:45 +0800 Subject: [PATCH 1101/2457] drtio: support external IBUFDS_GTE3 --- .../drtio/transceiver/gth_ultrascale.py | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index 35969f233..30eed79fa 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -636,13 +636,17 @@ class GTH(Module, TransceiverInterface): # # # - refclk = Signal() - ibufds_ceb = Signal() - self.specials += Instance("IBUFDS_GTE3", - i_CEB=ibufds_ceb, - i_I=clock_pads.p, - i_IB=clock_pads.n, - o_O=refclk) + create_buf = hasattr(clock_pads, "p") + if create_buf: + refclk = Signal() + ibufds_ceb = Signal() + self.specials += Instance("IBUFDS_GTE3", + i_CEB=ibufds_ceb, + i_I=clock_pads.p, + i_IB=clock_pads.n, + o_O=refclk) + else: + refclk = clock_pads rtio_tx_clk = Signal() channel_interfaces = [] @@ -665,10 +669,11 @@ class GTH(Module, TransceiverInterface): self.submodules.tx_phase_alignment = GTHTXPhaseAlignement(self.gths) TransceiverInterface.__init__(self, channel_interfaces) - # GTH PLLs recover on their own from an interrupted clock input, - # but be paranoid about HMC7043 noise. - self.stable_clkin.storage.attr.add("no_retiming") - self.comb += ibufds_ceb.eq(~self.stable_clkin.storage) + if create_buf: + # GTH PLLs recover on their own from an interrupted clock input, + # but be paranoid about HMC7043 noise. + self.stable_clkin.storage.attr.add("no_retiming") + self.comb += ibufds_ceb.eq(~self.stable_clkin.storage) self.comb += [ self.cd_rtio.clk.eq(self.gths[master].cd_rtio_tx.clk), From 49f7a1610f47b11e32286e3120970ec782ff2c1b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 7 Aug 2018 20:53:14 +0800 Subject: [PATCH 1102/2457] sayma: use GTP_CLK1 only for all variants (#1080) --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 5 +---- artiq/gateware/jesd204_tools.py | 2 +- artiq/gateware/targets/sayma_amc.py | 11 +++++------ 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index acb8af556..f0a67e86d 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -169,12 +169,9 @@ pub mod hmc7043 { (true, SYSREF_DIV, 0x08), // 3: DAC1_SYSREF (false, 0, 0x08), // 4: ADC2_CLK (false, 0, 0x08), // 5: ADC2_SYSREF - (true, FPGA_CLK_DIV, 0x08), // 6: GTP_CLK2 + (false, 0, 0x08), // 6: GTP_CLK2 (true, SYSREF_DIV, 0x10), // 7: FPGA_DAC_SYSREF, LVDS -#[cfg(hmc7043_enable_clk1)] (true, FPGA_CLK_DIV, 0x08), // 8: GTP_CLK1 -#[cfg(not(hmc7043_enable_clk1))] - (false, 0, 0x08), // 8: GTP_CLK1 (false, 0, 0x10), // 9: AMC_MASTER_AUX_CLK (false, 0, 0x10), // 10: RTM_MASTER_AUX_CLK (true, FPGA_CLK_DIV, 0x10), // 11: FPGA_ADC_SYSREF, LVDS -- repurposed for siphaser diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index 8187e4999..167a05f3a 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -27,7 +27,7 @@ class UltrascaleCRG(Module, AutoCSR): self.clock_domains.cd_jesd = ClockDomain() refclk2 = Signal() - refclk_pads = platform.request("dac_refclk", 1) + refclk_pads = platform.request("dac_refclk", 0) platform.add_period_constraint(refclk_pads.p, 1e9/self.refclk_freq) self.specials += [ Instance("IBUFDS_GTE3", i_CEB=self.ibuf_disable.storage, p_REFCLK_HROW_CK_SEL=0b00, diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 99af7073e..6e7872278 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -269,17 +269,19 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): "IBUFDS_GTE3", i_CEB=0, i_I=si5324_clkout.p, i_IB=si5324_clkout.n, attr={("DONT_TOUCH", "true")}) + self.submodules.ad9154_crg = jesd204_tools.UltrascaleCRG(platform) + self.csr_devices.append("ad9154_crg") + self.comb += [ platform.request("sfp_tx_disable", i).eq(0) for i in range(2) ] self.submodules.drtio_transceiver = gth_ultrascale.GTH( - clock_pads=platform.request("dac_refclk", 0), + clock_pads=self.ad9154_crg.refclk, data_pads=[platform.request("sfp", i) for i in range(2)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") - self.config["HMC7043_ENABLE_CLK1"] = None drtio_csr_group = [] drtio_memory_group = [] @@ -332,14 +334,12 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - self.submodules.ad9154_crg = jesd204_tools.UltrascaleCRG(platform) if with_sawg: cls = AD9154 else: cls = AD9154NoSAWG self.submodules.ad9154_0 = cls(platform, self.crg, self.ad9154_crg, 0) self.submodules.ad9154_1 = cls(platform, self.crg, self.ad9154_crg, 1) - self.csr_devices.append("ad9154_crg") self.csr_devices.append("ad9154_0") self.csr_devices.append("ad9154_1") self.config["HAS_AD9154"] = None @@ -577,12 +577,11 @@ class Satellite(BaseSoC, RTMCommon): self.comb += platform.request("sfp_tx_disable", 0).eq(0) self.submodules.drtio_transceiver = gth_ultrascale.GTH( - clock_pads=platform.request("dac_refclk", 0), + clock_pads=self.ad9154_crg.refclk, data_pads=[platform.request("sfp", 0)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") - self.config["HMC7043_ENABLE_CLK1"] = None rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) From 99a15ca0c63584e6ffdcd481cbc748d8f7d1163e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 7 Aug 2018 13:45:03 +0200 Subject: [PATCH 1103/2457] grabber: rationalize derived traits --- artiq/firmware/libboard_artiq/grabber.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/grabber.rs b/artiq/firmware/libboard_artiq/grabber.rs index 2da0126e4..fd9a0bf00 100644 --- a/artiq/firmware/libboard_artiq/grabber.rs +++ b/artiq/firmware/libboard_artiq/grabber.rs @@ -1,6 +1,6 @@ use board_misoc::csr; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(PartialEq)] enum State { Down, WaitResolution, From 6cd2432e309d999258d7bb152f5e27ddb2739f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 7 Aug 2018 16:13:21 +0200 Subject: [PATCH 1104/2457] grabber: log all resolution changes close #1120 --- artiq/firmware/libboard_artiq/grabber.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/grabber.rs b/artiq/firmware/libboard_artiq/grabber.rs index fd9a0bf00..3e6e89a83 100644 --- a/artiq/firmware/libboard_artiq/grabber.rs +++ b/artiq/firmware/libboard_artiq/grabber.rs @@ -8,6 +8,7 @@ enum State { } static mut GRABBER_STATE: [State; csr::GRABBER_LEN] = [State::Down; csr::GRABBER_LEN]; +static mut GRABBER_RESOLUTION: [(u16, u16); csr::GRABBER_LEN] = [(0, 0); csr::GRABBER_LEN]; fn get_pll_reset(g: usize) -> bool { unsafe { (csr::GRABBER[g].pll_reset_read)() != 0 } @@ -92,11 +93,19 @@ pub fn tick() { info!("grabber{} is down", g); } if unsafe { GRABBER_STATE[g] == State::WaitResolution } { - let (last_x, last_y) = get_last_pixels(g); + let last_xy = get_last_pixels(g); + unsafe { GRABBER_RESOLUTION[g] = last_xy; } info!("grabber{} frame size: {}x{}", - g, last_x + 1, last_y + 1); + g, last_xy.0 + 1, last_xy.1 + 1); info!("grabber{} video clock: {}MHz", g, get_video_clock(g)); unsafe { GRABBER_STATE[g] = State::Up; } + } else { + let last_xy = get_last_pixels(g); + if unsafe { last_xy != GRABBER_RESOLUTION[g] } { + info!("grabber{} frame size: {}x{}", + g, last_xy.0 + 1, last_xy.1 + 1); + unsafe { GRABBER_RESOLUTION[g] = last_xy; } + } } } else { if get_pll_reset(g) { From f7678cc24add13c80565f290703f7147bada8c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 7 Aug 2018 17:27:36 +0200 Subject: [PATCH 1105/2457] grabber: refactor state machine --- artiq/firmware/libboard_artiq/grabber.rs | 94 +++++++++++++++--------- 1 file changed, 60 insertions(+), 34 deletions(-) diff --git a/artiq/firmware/libboard_artiq/grabber.rs b/artiq/firmware/libboard_artiq/grabber.rs index 3e6e89a83..2973dc2e9 100644 --- a/artiq/firmware/libboard_artiq/grabber.rs +++ b/artiq/firmware/libboard_artiq/grabber.rs @@ -1,14 +1,21 @@ use board_misoc::csr; -#[derive(PartialEq)] +#[derive(PartialEq, Clone, Copy)] enum State { - Down, - WaitResolution, - Up + Reset, + ExitReset, + Lock, + Align, + Watch } -static mut GRABBER_STATE: [State; csr::GRABBER_LEN] = [State::Down; csr::GRABBER_LEN]; -static mut GRABBER_RESOLUTION: [(u16, u16); csr::GRABBER_LEN] = [(0, 0); csr::GRABBER_LEN]; +struct Info { + state: State, + frame_size: (u16, u16), +} + +static mut INFO: [Info; csr::GRABBER_LEN] = + [Info { state: State::Reset, frame_size: (0, 0) }; csr::GRABBER_LEN]; fn get_pll_reset(g: usize) -> bool { unsafe { (csr::GRABBER[g].pll_reset_read)() != 0 } @@ -16,7 +23,7 @@ fn get_pll_reset(g: usize) -> bool { fn set_pll_reset(g: usize, reset: bool) { let val = if reset { 1 } else { 0 }; - unsafe { (csr::GRABBER[g].pll_reset_write)(val) } + unsafe { (csr::GRABBER[g].pll_reset_write)(val) } } fn pll_locked(g: usize) -> bool { @@ -86,43 +93,62 @@ fn get_video_clock(g: usize) -> u32 { pub fn tick() { for g in 0..csr::GRABBER.len() { - if unsafe { GRABBER_STATE[g] != State::Down } { - if !clock_pattern_ok(g) || !pll_locked(g) { + let next = match unsafe { INFO[g].state } { + State::Reset => { set_pll_reset(g, true); - unsafe { GRABBER_STATE[g] = State::Down; } - info!("grabber{} is down", g); + unsafe { INFO[g].frame_size = (0, 0); } + State::ExitReset } - if unsafe { GRABBER_STATE[g] == State::WaitResolution } { - let last_xy = get_last_pixels(g); - unsafe { GRABBER_RESOLUTION[g] = last_xy; } - info!("grabber{} frame size: {}x{}", - g, last_xy.0 + 1, last_xy.1 + 1); - info!("grabber{} video clock: {}MHz", g, get_video_clock(g)); - unsafe { GRABBER_STATE[g] = State::Up; } - } else { - let last_xy = get_last_pixels(g); - if unsafe { last_xy != GRABBER_RESOLUTION[g] } { - info!("grabber{} frame size: {}x{}", - g, last_xy.0 + 1, last_xy.1 + 1); - unsafe { GRABBER_RESOLUTION[g] = last_xy; } + State::ExitReset => { + if get_pll_reset(g) { + set_pll_reset(g, false); + State::Lock + } else { + State::ExitReset } } - } else { - if get_pll_reset(g) { - set_pll_reset(g, false); - } else { + State::Lock => { + if pll_locked(g) { + info!("grabber{} locked: {}MHz", g, get_video_clock(g)); + State::Align + } else { + State::Lock + } + } + State::Align => { if pll_locked(g) { - info!("grabber{} PLL is locked", g); if clock_align(g) { - info!("grabber{} is up", g); - unsafe { GRABBER_STATE[g] = State::WaitResolution; } + info!("grabber{} alignment success", g); + State::Watch } else { - set_pll_reset(g, true); + info!("grabber{} alignment failure", g); + State::Reset } } else { - set_pll_reset(g, true); + info!("grabber{} lock lost", g); + State::Reset } } - } + State::Watch => { + if pll_locked(g) { + if clock_pattern_ok(g) { + let last_xy = get_last_pixels(g); + if last_xy != unsafe { INFO[g].frame_size } { + info!("grabber{} frame size: {}x{}", + g, last_xy.0 + 1, last_xy.1 + 1); + unsafe { INFO[g].frame_size = last_xy } + } + State::Watch + } else { + info!("grabber{} alignment lost", g); + State::Reset + } + } else { + info!("grabber{} lock lost", g); + State::Reset + } + } + }; + unsafe { INFO[g].state = next; } } } From a061ba25051382455ef8818c1b946542a7de723b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 8 Aug 2018 12:43:44 +0200 Subject: [PATCH 1106/2457] grabber/kasli_basic: add grabber test close #1121 --- .../kasli_basic/repository/kasli_tester.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index a633ee02d..685271217 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -39,6 +39,7 @@ class KasliTester(EnvExperiment): self.urukuls = dict() self.samplers = dict() self.zotinos = dict() + self.grabbers = dict() ddb = self.get_device_db() for name, desc in ddb.items(): @@ -62,6 +63,8 @@ class KasliTester(EnvExperiment): self.samplers[name] = self.get_device(name) elif (module, cls) == ("artiq.coredevice.zotino", "Zotino"): self.zotinos[name] = self.get_device(name) + elif (module, cls) == ("artiq.coredevice.grabber", "Grabber"): + self.grabbers[name] = self.get_device(name) # Remove Urukul, Sampler and Zotino control signals # from TTL outs (tested separately) @@ -92,6 +95,7 @@ class KasliTester(EnvExperiment): self.urukuls = sorted(self.urukuls.items(), key=lambda x: x[1].sw.channel) self.samplers = sorted(self.samplers.items(), key=lambda x: x[1].cnv.channel) self.zotinos = sorted(self.zotinos.items(), key=lambda x: x[1].bus.channel) + self.grabbers = sorted(self.grabbers.items(), key=lambda x: x[1].channel_base) @kernel def test_led(self, led): @@ -273,6 +277,40 @@ class KasliTester(EnvExperiment): print("Press ENTER when done.") input() + def test_grabbers(self): + rois = [[0, 0, 0, 2, 2], [1, 0, 0, 2048, 2048]] + print("*** Testing Grabber Frame Grabbers.") + print("ROIs: %s".format(rois)) + print("Press ENTER, activate the camera's frame grabber output, " + "and trigger it once. Type 's' to skip the test.") + if input().strip().lower() == "s": + print("skipping...") + return + for card_n, (card_name, card_dev) in enumerate(self.grabbers): + print(card_name) + self.grabber_capture(card_dev, rois) + + @kernel + def grabber_capture(self, card_dev, rois): + self.core.break_realtime() + delay(10*us) + mask = 0 + for i in range(len(rois)): + i = rois[i][0] + x0 = rois[i][1] + y0 = rois[i][2] + x1 = rois[i][3] + y1 = rois[i][4] + mask |= 1 << i + card_dev.setup_roi(i, x0, y0, x1, y1) + card_dev.gate_roi(mask) + n = [0]*len(rois) + card_dev.input_mu(n) + self.core.break_realtime() + card_dev.gate_roi(0) + print("ROI sums:") + print(n) + def run(self): print("****** Kasli system tester ******") print("") @@ -283,3 +321,4 @@ class KasliTester(EnvExperiment): self.test_urukuls() self.test_samplers() self.test_zotinos() + self.test_grabbers() From bf78e0c7d242f6b9f159451eb444b1608f678c2d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 9 Aug 2018 16:51:12 +0800 Subject: [PATCH 1107/2457] test: fix handling of missing devices --- artiq/test/coredevice/test_moninj.py | 15 ++++++++++++--- artiq/test/hardware_testbench.py | 10 +++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/artiq/test/coredevice/test_moninj.py b/artiq/test/coredevice/test_moninj.py index bda590bc8..3d9481ae0 100644 --- a/artiq/test/coredevice/test_moninj.py +++ b/artiq/test/coredevice/test_moninj.py @@ -1,3 +1,4 @@ +import unittest import asyncio from artiq.coredevice.comm_moninj import * @@ -6,9 +7,17 @@ from artiq.test.hardware_testbench import ExperimentCase class MonInjTest(ExperimentCase): def test_moninj(self): - core_host = self.device_mgr.get_desc("core")["arguments"]["host"] - loop_out_channel = self.device_mgr.get_desc("loop_out")["arguments"]["channel"] - loop_in_channel = self.device_mgr.get_desc("loop_in")["arguments"]["channel"] + try: + core = self.device_mgr.get_desc("core") + loop_out = self.device_mgr.get_desc("loop_out") + loop_in = self.device_mgr.get_desc("loop_in") + except KeyError as e: + # skip if ddb does not match requirements + raise unittest.SkipTest( + "test device not available: `{}`".format(*e.args)) + core_host = core["arguments"]["host"] + loop_out_channel = loop_out["arguments"]["channel"] + loop_in_channel = loop_in["arguments"]["channel"] notifications = [] injection_statuses = [] diff --git a/artiq/test/hardware_testbench.py b/artiq/test/hardware_testbench.py index 4ce3114c3..32bc8cd4a 100644 --- a/artiq/test/hardware_testbench.py +++ b/artiq/test/hardware_testbench.py @@ -11,7 +11,7 @@ import time import socket from artiq.master.databases import DeviceDB, DatasetDB -from artiq.master.worker_db import DeviceManager, DatasetManager +from artiq.master.worker_db import DeviceManager, DatasetManager, DeviceError from artiq.coredevice.core import CompileError from artiq.frontend.artiq_run import DummyScheduler from artiq.protocols.pc_rpc import AutoTarget, Client @@ -113,12 +113,12 @@ class ExperimentCase(unittest.TestCase): exp = cls( (self.device_mgr, self.dataset_mgr, None), *args, **kwargs) - exp.prepare() - return exp - except KeyError as e: + except DeviceError as e: # skip if ddb does not match requirements raise unittest.SkipTest( - "device_db entry `{}` not found".format(*e.args)) + "test device not available: `{}`".format(*e.args)) + exp.prepare() + return exp def execute(self, cls, *args, **kwargs): expid = { From bbc98410e40a32563a5e63a7e1b474c71dfab8e2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 9 Aug 2018 16:55:07 +0800 Subject: [PATCH 1108/2457] =?UTF-8?q?test:=20dds=20=E2=86=92=20ad9914dds?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevent confusion with Urukul. --- artiq/examples/kc705_nist_clock/device_db.py | 10 ++++----- artiq/examples/master/device_db.py | 10 ++++----- artiq/test/coredevice/test_rtio.py | 22 ++++++++++---------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/artiq/examples/kc705_nist_clock/device_db.py b/artiq/examples/kc705_nist_clock/device_db.py index d741ceded..140fbd716 100644 --- a/artiq/examples/kc705_nist_clock/device_db.py +++ b/artiq/examples/kc705_nist_clock/device_db.py @@ -134,20 +134,20 @@ device_db = { }, # AD9914 DDS - "dds0": { + "ad9914dds0": { "type": "local", "module": "artiq.coredevice.ad9914", "class": "AD9914", "arguments": {"sysclk": 3e9, "bus_channel": 27, "channel": 0}, "comment": "Comments work in DDS panel as well" }, - "dds1": { + "ad9914dds1": { "type": "local", "module": "artiq.coredevice.ad9914", "class": "AD9914", "arguments": {"sysclk": 3e9, "bus_channel": 27, "channel": 1} }, - "dds2": { + "ad9914dds2": { "type": "local", "module": "artiq.coredevice.ad9914", "class": "AD9914", @@ -164,8 +164,8 @@ device_db = { "loop_clock_in": "ttl7", "pmt": "ttl3", - "bd_dds": "dds0", + "bd_dds": "ad9914dds0", "bd_sw": "ttl0", - "bdd_dds": "dds1", + "bdd_dds": "ad9914dds1", "bdd_sw": "ttl1" } diff --git a/artiq/examples/master/device_db.py b/artiq/examples/master/device_db.py index 69ed74c8f..ad4bc65b6 100644 --- a/artiq/examples/master/device_db.py +++ b/artiq/examples/master/device_db.py @@ -321,20 +321,20 @@ device_db = { }, # AD9914 DDS - "dds0": { + "ad9914dds0": { "type": "local", "module": "artiq.coredevice.ad9914", "class": "AD9914", "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 0}, "comment": "Comments work in DDS panel as well" }, - "dds1": { + "ad9914dds1": { "type": "local", "module": "artiq.coredevice.ad9914", "class": "AD9914", "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 1} }, - "dds2": { + "ad9914dds2": { "type": "local", "module": "artiq.coredevice.ad9914", "class": "AD9914", @@ -351,8 +351,8 @@ device_db = { "loop_clock_in": "ttl7", "pmt": "ttl3", - "bd_dds": "dds0", + "bd_dds": "ad9914dds0", "bd_sw": "ttl0", - "bdd_dds": "dds1", + "bdd_dds": "ad9914dds1", "bdd_sw": "ttl1" } diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 401f4109b..7513d63d1 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -124,25 +124,25 @@ class PulseRate(EnvExperiment): return -class PulseRateDDS(EnvExperiment): +class PulseRateAD9914DDS(EnvExperiment): def build(self): self.setattr_device("core") - self.setattr_device("dds0") - self.setattr_device("dds1") + self.setattr_device("ad9914dds0") + self.setattr_device("ad9914dds1") @kernel def run(self): self.core.reset() dt = self.core.seconds_to_mu(5*us) - freq = self.dds0.frequency_to_ftw(100*MHz) + freq = self.ad9914dds0.frequency_to_ftw(100*MHz) while True: delay(10*ms) for i in range(1250): try: - delay_mu(-self.dds0.set_duration_mu) - self.dds0.set_mu(freq) - delay_mu(self.dds0.set_duration_mu) - self.dds1.set_mu(freq) + delay_mu(-self.ad9914dds0.set_duration_mu) + self.ad9914dds0.set_mu(freq) + delay_mu(self.ad9914dds0.set_duration_mu) + self.ad9914dds1.set_mu(freq) delay_mu(dt) except RTIOUnderflow: dt += 100 @@ -395,9 +395,9 @@ class CoredeviceTest(ExperimentCase): self.assertGreater(rate, 100*ns) self.assertLess(rate, 700*ns) - def test_pulse_rate_dds(self): - """Minimum interval for sustained DDS frequency switching""" - self.execute(PulseRateDDS) + def test_pulse_rate_ad9914_dds(self): + """Minimum interval for sustained AD9914 DDS frequency switching""" + self.execute(PulseRateAD9914DDS) rate = self.dataset_mgr.get("pulse_rate") print(rate) self.assertGreater(rate, 1*us) From 957645a7e728b95ce8b1264e07ee7401fb905b41 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 9 Aug 2018 18:07:44 +0800 Subject: [PATCH 1109/2457] examples: move kasli tester out of kasli_basic --- .../device_db_tester.py => kasli_tester/device_db.py} | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) rename artiq/examples/{kasli_basic/device_db_tester.py => kasli_tester/device_db.py} (97%) diff --git a/artiq/examples/kasli_basic/device_db_tester.py b/artiq/examples/kasli_tester/device_db.py similarity index 97% rename from artiq/examples/kasli_basic/device_db_tester.py rename to artiq/examples/kasli_tester/device_db.py index ba72ee99b..c44707314 100644 --- a/artiq/examples/kasli_basic/device_db_tester.py +++ b/artiq/examples/kasli_tester/device_db.py @@ -1,4 +1,4 @@ -core_addr = "kasli-2.lab.m-labs.hk" +core_addr = "kasli-1.lab.m-labs.hk" device_db = { "core": { @@ -185,3 +185,8 @@ device_db.update( "arguments": {"channel": 21} }, ) + +device_db.update( + "ttl_out": "ttl4", + "ttl_out_serdes": "ttl4", +) From 052e400f1217dfb3ff02458abf98bb4b4237bbe2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 9 Aug 2018 18:08:21 +0800 Subject: [PATCH 1110/2457] test: skip test_dma_playback_time on Kasli (#946) --- artiq/test/coredevice/test_rtio.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 7513d63d1..8a2a7f6e6 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -644,6 +644,12 @@ class DMATest(ExperimentCase): self.assertLess(dt/count, 20*us) def test_dma_playback_time(self): + # Skip on Kasli until #946 is resolved. + try: + # hack to detect Kasli. + self.device_mgr.get_desc("ad9914dds0") + except KeyError: + raise unittest.SkipTest("skipped on Kasli for now") exp = self.create(_DMA) count = 20000 exp.record_many(40) From fab6e5cdff1541d4d96f462ce584a867ceffe5e8 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 10 Aug 2018 12:02:49 +0000 Subject: [PATCH 1111/2457] compiler: skip functional values in attribute writeback. Fixes #1088. --- artiq/compiler/transforms/llvm_ir_generator.py | 14 +++++++++----- artiq/test/lit/embedding/fn_ptr_list.py | 15 +++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 artiq/test/lit/embedding/fn_ptr_list.py diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 013d2a5ea..b39c2b5bc 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -525,11 +525,10 @@ class LLVMIRGenerator: print(typ) assert False - if not (types.is_function(typ) or types.is_method(typ) or types.is_rpc(typ) or - name == "__objectid__"): - rpctag = b"Os" + self._rpc_tag(typ, error_handler=rpc_tag_error) + b":n" - else: + if name == "__objectid__": rpctag = b"" + else: + rpctag = b"Os" + self._rpc_tag(typ, error_handler=rpc_tag_error) + b":n" llrpcattrinit = ll.Constant(llrpcattrty, [ ll.Constant(lli32, offset), @@ -562,7 +561,10 @@ class LLVMIRGenerator: offset += alignment - (offset % alignment) if types.is_instance(typ) and attr not in typ.constant_attributes: - llrpcattrs.append(llrpcattr_of_attr(offset, attr, attrtyp)) + try: + llrpcattrs.append(llrpcattr_of_attr(offset, attr, attrtyp)) + except ValueError: + continue offset += size @@ -1267,6 +1269,8 @@ class LLVMIRGenerator: elif ir.is_keyword(typ): return b"k" + self._rpc_tag(typ.params["value"], error_handler) + elif types.is_function(typ) or types.is_method(typ) or types.is_rpc(typ): + raise ValueError("RPC tag for functional value") elif '__objectid__' in typ.attributes: return b"O" else: diff --git a/artiq/test/lit/embedding/fn_ptr_list.py b/artiq/test/lit/embedding/fn_ptr_list.py new file mode 100644 index 000000000..73e6ad3be --- /dev/null +++ b/artiq/test/lit/embedding/fn_ptr_list.py @@ -0,0 +1,15 @@ +# RUN: %python -m artiq.compiler.testbench.embedding %s + +from artiq.language.core import * +from artiq.language.types import * + +@kernel +def a(): + pass + +fns = [a, a] + +@kernel +def entrypoint(): + fns[0]() + fns[1]() From bc3e715a8ff9883f0f24a71d2f6840a06a4ad845 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 11 Aug 2018 10:51:42 +0800 Subject: [PATCH 1112/2457] examples: fix kasli_tester --- artiq/examples/kasli_tester/device_db.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/examples/kasli_tester/device_db.py b/artiq/examples/kasli_tester/device_db.py index c44707314..2af42ea07 100644 --- a/artiq/examples/kasli_tester/device_db.py +++ b/artiq/examples/kasli_tester/device_db.py @@ -187,6 +187,6 @@ device_db.update( ) device_db.update( - "ttl_out": "ttl4", - "ttl_out_serdes": "ttl4", + ttl_out="ttl4", + ttl_out_serdes="ttl4", ) From 738d2c6bcbe628f55d08acad3d1d597aaaf93df5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 11 Aug 2018 12:07:17 +0800 Subject: [PATCH 1113/2457] =?UTF-8?q?hmc7043:=20REFSYNCIN=20=E2=86=92=20RF?= =?UTF-8?q?SYNCIN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index f0a67e86d..6d2787ad7 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -280,8 +280,8 @@ pub mod hmc7043 { spi_setup(); info!("loading configuration..."); - write(0x3, 0x14); // Disable the REFSYNCIN reseeder - write(0xA, 0x06); // Disable the REFSYNCIN input buffer + write(0x3, 0x14); // Disable the RFSYNCIN reseeder + write(0xA, 0x06); // Disable the RFSYNCIN input buffer write(0xB, 0x07); // Enable the CLKIN input as LVPECL write(0x9F, 0x4d); // Unexplained high-performance mode write(0xA0, 0xdf); // Unexplained high-performance mode From e48d440fd4ad28cacb6b6f9d24117b38dc9655f8 Mon Sep 17 00:00:00 2001 From: Stewart Mackenzie Date: Sun, 6 Mar 2016 23:54:07 +0800 Subject: [PATCH 1114/2457] Problem: ARTIQ setup via conda or src is complex Solution: Provide a single command to download, compile and install dependencies. --- nix/README.rst | 22 +++++++ nix/artiq.nix | 125 +++++++++++++++++++++++++++++++++++++++ nix/binutils-or1k.nix | 32 ++++++++++ nix/default.nix | 15 +++++ nix/fetch-llvm-clang.nix | 22 +++++++ nix/llvm-or1k.nix | 36 +++++++++++ nix/llvmlite.nix | 20 +++++++ 7 files changed, 272 insertions(+) create mode 100644 nix/README.rst create mode 100644 nix/artiq.nix create mode 100644 nix/binutils-or1k.nix create mode 100644 nix/default.nix create mode 100644 nix/fetch-llvm-clang.nix create mode 100644 nix/llvm-or1k.nix create mode 100644 nix/llvmlite.nix diff --git a/nix/README.rst b/nix/README.rst new file mode 100644 index 000000000..c2d6df2eb --- /dev/null +++ b/nix/README.rst @@ -0,0 +1,22 @@ +Install ARTIQ via the Nix Package Manager +=========================== + +Nix does not support windows. + +* Install the nix package manager + + * many linux distros already have a package for the `nix package manager `_ + + * for example: $ apt-get install nix + + * if you would like to install via sh (please be sure you `understand `_ the dangers involved when curl piping to sh. Also ensure you have read the contents of the script and feel comfortable executing it. Otherwise there is the `manual `_) + + * $ curl https://nixos.org/nix/install | sh + + * $ source ~/.nix-profile/etc/profile.d/nix.sh + +* $ git clone github.com/m-labs/artiq +* $ cd artiq/nix +* $ nix-env -i -f default.nix + +The above command will setup your entire environment. diff --git a/nix/artiq.nix b/nix/artiq.nix new file mode 100644 index 000000000..af5c20737 --- /dev/null +++ b/nix/artiq.nix @@ -0,0 +1,125 @@ +{ stdenv, fetchFromGitHub, fetchsvn, python35Packages, qt5Full, llvm-or1k, llvmlite, python35}: + +let + +levenshtein = python35Packages.buildPythonPackage rec { + name = "levenshtein"; + src = fetchFromGitHub { + owner = "ztane"; + repo = "python-Levenshtein"; + rev = "854e61a05bb8b750e990add96df412cd5448b75e"; + sha256 = "1yf21kg1g2ivm5a4dx1jra9k0c33np54d0hk5ymnfyc4f6pg386q"; + }; + doCheck = false; +}; + +sphinx-argparse = python35Packages.buildPythonPackage rec { + name = "sphinx-argparse"; + src = fetchFromGitHub { + owner = "ribozz"; + repo = "sphinx-argparse"; + rev = "cc95938b8fbf870f7a5c012d4d84a29cfbac5e06"; + sha256 = "1rsjlsnrpd4i4zx2sylilf6lfi77k0fclbhilrgx1m53ixllwg38"; + }; + buildInputs = with python35Packages; [ sphinx ]; + doCheck = false; +}; + +pythonparser = python35Packages.buildPythonPackage rec { + name = "pythonparser"; + src = fetchFromGitHub { + owner = "m-labs"; + repo = "pythonparser"; + rev = "8bdc7badbd08e2196b864e12889ea9191ca6e09c"; + sha256 = "1f538wnjlqah0dsvq256k2rv7s7bffsvjcxy8fq0x3a4g0s6pm9d"; + }; + buildInputs = with python35Packages; [ regex ]; + doCheck = false; +}; + +ml-pyserial = python35Packages.buildPythonPackage rec { + name = "pyserial"; + src = fetchFromGitHub { + owner = "m-labs"; + repo = "pyserial"; + rev = "f30653b23f01c1cc27eb9731afc8ad66a723a4c0"; + sha256 = "18xwsmpklggrm07b17ficpyjxnfgpw0k9lbz44nq4iflr8gmf33f"; + }; + buildInputs = with python35Packages; [ regex ]; + doCheck = false; +}; + +pyqtgraph = python35Packages.buildPythonPackage rec { + name = "pyqtgraph"; + src = fetchFromGitHub { + owner = "m-labs"; + repo = "pyqtgraph"; + rev = "8e9ee6fd3cabcc06d25cde5f13921e5d9d11c588"; + sha256 = "0ynhsd4nlbz4pgwch0w767a9ybazn5f33rakpjdrcwldvrrrng6y"; + }; + buildInputs = with python35Packages; [ numpy ]; + doCheck = false; +}; + +outputcheck = python35Packages.buildPythonPackage rec { + name = "outputcheck"; + version = "0.4.2"; + src = fetchFromGitHub { + owner = "stp"; + repo = "OutputCheck"; + rev = "e0f533d3c5af2949349856c711bf4bca50022b48"; + sha256 = "1y27vz6jq6sywas07kz3v01sqjd0sga9yv9w2cksqac3v7wmf2a0"; + }; + prePatch = '' + substituteInPlace setup.py \ + --replace "version.get_git_version()" "\"${version}\"" \ + --replace "import version" "" + ''; + doCheck = false; +}; + +quamash = python35Packages.buildPythonPackage rec { + name = "quamash"; + src = fetchFromGitHub { + owner = "harvimt"; + repo = "quamash"; + rev = "bbab9e30e10b71a95687b03a93524173fb7b43f0"; + sha256 = "08hp2q4ifj6z2ww05c7zsy0cd732k9rnaims1j43vr4hhxx950mk"; + }; + buildInputs = with python35Packages; [ pyqt5 ]; + doCheck = false; +}; + +lit = python35Packages.buildPythonPackage rec { + name = "lit"; + version = "262719"; + source = fetchsvn { + url = "http://llvm.org/svn/llvm-project/llvm/trunk/"; + rev = "${version}"; + sha256 = "1iashczfh30v9ark4xijk6z2q07c1kb70nar00mwnfix77gkb2v6"; + }; + src = source + /utils/lit; + doCheck = false; +}; + +in + +python35Packages.buildPythonPackage rec { + version = "336482"; + name = "artiq-${version}"; + src = ./..; + buildInputs = with python35Packages; [ + llvm-or1k llvmlite sphinx-argparse levenshtein + pyqtgraph aiohttp pygit2 pythonparser numpy + dateutil sphinx quamash scipy outputcheck + prettytable lit ml-pyserial h5py cython regex qt5Full pyqt5 ]; + doCheck = false; + meta = with stdenv.lib; { + description = ""; + homepage = https://m-labs/artiq; + license = licenses.gpl3; + maintainers = [ maintainers.sjmackenzie ]; + platforms = [ "x86_64-linux" ]; + }; +} + diff --git a/nix/binutils-or1k.nix b/nix/binutils-or1k.nix new file mode 100644 index 000000000..0ebdbcd24 --- /dev/null +++ b/nix/binutils-or1k.nix @@ -0,0 +1,32 @@ +{ stdenv +, fetchurl +}: + +stdenv.mkDerivation rec { + basename = "binutils"; + platform = "or1k"; + version = "2.26"; + name = "${basename}_${platform}-${version}"; + src = fetchurl { + url = "https://ftp.gnu.org/gnu/binutils/${basename}-${version}.tar.bz2"; + sha256 = "1ngc2h3knhiw8s22l8y6afycfaxr5grviqy7mwvm4bsl14cf9b62"; + }; + configureFlags = + [ "--enable-shared" "--enable-deterministic-archives" "--target=or1k-linux"]; + enableParallelBuilding = true; + meta = { + description = "Tools for manipulating binaries (linker, assembler, etc.)"; + longDescription = '' + The GNU Binutils are a collection of binary tools. The main + ones are `ld' (the GNU linker) and `as' (the GNU assembler). + They also include the BFD (Binary File Descriptor) library, + `gprof', `nm', `strip', etc. + ''; + homepage = http://www.gnu.org/software/binutils/; + license = stdenv.lib.licenses.gpl3Plus; + /* Give binutils a lower priority than gcc-wrapper to prevent a + collision due to the ld/as wrappers/symlinks in the latter. */ + priority = "10"; + }; +} + diff --git a/nix/default.nix b/nix/default.nix new file mode 100644 index 000000000..3561ff763 --- /dev/null +++ b/nix/default.nix @@ -0,0 +1,15 @@ +{system ? builtins.currentSystem}: +let + pkgs = import {inherit system;}; + callPackage = pkgs.lib.callPackageWith (pkgs // self ); + +self = { + binutils-ork1 = callPackage ./binutils-or1k.nix {}; + llvm-src = callPackage ./fetch-llvm-clang.nix {}; + llvm-or1k = callPackage ./llvm-or1k.nix {}; + llvmlite = callPackage ./llvmlite.nix {}; + artiq = callPackage ./artiq.nix { }; +}; +artiq = self.artiq; +in +artiq diff --git a/nix/fetch-llvm-clang.nix b/nix/fetch-llvm-clang.nix new file mode 100644 index 000000000..cb53f93d0 --- /dev/null +++ b/nix/fetch-llvm-clang.nix @@ -0,0 +1,22 @@ +{ runCommand, fetchFromGitHub, git }: + +let +llvm-src = fetchFromGitHub { + rev = "ff2fe8c318eb7c934a2f2ac8da61a00d62becf1f"; + owner = "openrisc"; + repo = "llvm-or1k"; + sha256 = "061pvc4z5i92s1xwz9ir6yqnk5vb0xd8cs9php4yy01dyvpblql7"; +}; +clang-src = fetchFromGitHub { + rev = "030259ccc14261d02163cce28adb0c11243d0a99"; + owner = "openrisc"; + repo = "clang-or1k"; + sha256 = "1w7dk469svskr1c7ywcl9xsxbnvl40c28nffivpclijcvsh43463"; +}; +in +runCommand "llvm_or1k_src" {}'' +mkdir -p $out +mkdir -p $out/tools/clang +cp -r ${llvm-src}/* $out/ +cp -r ${clang-src}/* $out/tools/clang +'' diff --git a/nix/llvm-or1k.nix b/nix/llvm-or1k.nix new file mode 100644 index 000000000..95d74061e --- /dev/null +++ b/nix/llvm-or1k.nix @@ -0,0 +1,36 @@ +{ stdenv +, git +, llvm-src +, perl, groff, cmake, libxml2, python, libffi, valgrind +, ... +}: + +stdenv.mkDerivation rec { + name = "llvm_or1k"; + src = llvm-src; + + buildInputs = [ perl groff cmake libxml2 python libffi ] ++ stdenv.lib.optional stdenv.isLinux valgrind; + + preBuild = '' + NIX_BUILD_CORES=4 + makeFlagsArray=(-j''$NIX_BUILD_CORES) + mkdir -p $out/ + ''; + + cmakeFlags = with stdenv; [ + "-DLLVM_TARGETS_TO_BUILD=OR1K;X86" + "-DCMAKE_BUILD_TYPE=Rel" + "-DLLVM_ENABLE_ASSERTIONS=ON" + "-DCMAKE_BUILD_TYPE=Release" + ]; + + enableParallelBuilding = true; + meta = { + description = "Collection of modular and reusable compiler and toolchain technologies"; + homepage = http://llvm.org/; + license = stdenv.lib.licenses.bsd3; + maintainers = with stdenv.lib.maintainers; [ sj_mackenzie ]; + platforms = stdenv.lib.platforms.all; + }; +} + diff --git a/nix/llvmlite.nix b/nix/llvmlite.nix new file mode 100644 index 000000000..4fd99a482 --- /dev/null +++ b/nix/llvmlite.nix @@ -0,0 +1,20 @@ +{ stdenv, fetchgit, llvm-or1k, makeWrapper, python35, ncurses, zlib }: +let +version = "0f4ebae"; +in +stdenv.mkDerivation rec { + name = "llvmlite-${version}"; + src = fetchgit { + url = "https://github.com/m-labs/llvmlite"; + rev = "0f4ebae43c2d2a084deb8b693e3d42a7b2c82222"; + sha256 = "0lnxxyjw2dapzqanms6jx64zxwhyrcria1yz49dzlb1306hzclj0"; + leaveDotGit = true; + }; + + buildInputs = [ makeWrapper python35 ncurses zlib llvm-or1k]; + + installPhase = '' + LLVM_CONFIG=${llvm-or1k}/llvm_or1k/bin/llvm-config + python3 setup.py install --prefix=$out + ''; +} From d2e47844dddf90b8661492898605507adee2fde7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 12 Aug 2018 21:20:02 +0800 Subject: [PATCH 1115/2457] nix: fixes --- nix/artiq.nix | 16 ++++++++++++++-- nix/llvmlite.nix | 6 +++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/nix/artiq.nix b/nix/artiq.nix index af5c20737..5be35279e 100644 --- a/nix/artiq.nix +++ b/nix/artiq.nix @@ -49,6 +49,18 @@ ml-pyserial = python35Packages.buildPythonPackage rec { doCheck = false; }; +asyncserial = python35Packages.buildPythonPackage rec { + name = "asyncserial"; + src = fetchFromGitHub { + owner = "m-labs"; + repo = "asyncserial"; + rev = "d95bc1d6c791b0e9785935d2f62f628eb5cdf98d"; + sha256 = "0yzkka9jk3612v8gx748x6ziwykq5lr7zmr9wzkcls0v2yilqx9k"; + }; + buildInputs = with python35Packages; [ ml-pyserial ]; + doCheck = false; +}; + pyqtgraph = python35Packages.buildPythonPackage rec { name = "pyqtgraph"; src = fetchFromGitHub { @@ -108,11 +120,11 @@ python35Packages.buildPythonPackage rec { version = "336482"; name = "artiq-${version}"; src = ./..; - buildInputs = with python35Packages; [ + propagatedBuildInputs = with python35Packages; [ llvm-or1k llvmlite sphinx-argparse levenshtein pyqtgraph aiohttp pygit2 pythonparser numpy dateutil sphinx quamash scipy outputcheck - prettytable lit ml-pyserial h5py cython regex qt5Full pyqt5 ]; + prettytable lit ml-pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; doCheck = false; meta = with stdenv.lib; { description = ""; diff --git a/nix/llvmlite.nix b/nix/llvmlite.nix index 4fd99a482..762c09cf7 100644 --- a/nix/llvmlite.nix +++ b/nix/llvmlite.nix @@ -1,4 +1,4 @@ -{ stdenv, fetchgit, llvm-or1k, makeWrapper, python35, ncurses, zlib }: +{ stdenv, fetchgit, llvm-or1k, makeWrapper, python35, ncurses, zlib, python35Packages }: let version = "0f4ebae"; in @@ -7,11 +7,11 @@ stdenv.mkDerivation rec { src = fetchgit { url = "https://github.com/m-labs/llvmlite"; rev = "0f4ebae43c2d2a084deb8b693e3d42a7b2c82222"; - sha256 = "0lnxxyjw2dapzqanms6jx64zxwhyrcria1yz49dzlb1306hzclj0"; + sha256 = "0n90w0x001k0zyn8zz6jxc9i78agqv15m55vz2raw1y0rfw16mfl"; leaveDotGit = true; }; - buildInputs = [ makeWrapper python35 ncurses zlib llvm-or1k]; + buildInputs = [ makeWrapper python35 ncurses zlib llvm-or1k python35Packages.setuptools ]; installPhase = '' LLVM_CONFIG=${llvm-or1k}/llvm_or1k/bin/llvm-config From 2648b1b7a1b13e2591c9ba8a53f25022862f17e2 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 10 Aug 2018 15:24:51 +0000 Subject: [PATCH 1116/2457] firmware: migrate to Rust 1.28.0. This also updates / is a prerequisite for updating smoltcp. Rationale for changes made: * compiler_builtins is now shipped in the rust prefix. * rustc's libpanic_unwind no longer works for us because it has a hard dependency on Box (and it's a horrible hack); fortunately, we only ever needed a personality function from it. * panic and oom handlers are now set in a completely different way. * allocators are quite different (and finally stable). * NLL caused internal compiler errors in runtime, so code using NLL was rewritten to not rely on it and it was turned off. --- artiq/firmware/Cargo.lock | 47 +-- artiq/firmware/bootloader/Cargo.toml | 2 +- artiq/firmware/bootloader/bootloader.ld | 7 + artiq/firmware/bootloader/main.rs | 23 +- artiq/firmware/ksupport/Cargo.toml | 1 + artiq/firmware/ksupport/api.rs | 6 +- artiq/firmware/ksupport/eh.rs | 465 ---------------------- artiq/firmware/ksupport/eh_artiq.rs | 203 ++++++++++ artiq/firmware/ksupport/lib.rs | 56 ++- artiq/firmware/liballoc_list/lib.rs | 23 +- artiq/firmware/libboard_misoc/Cargo.toml | 3 +- artiq/firmware/libboard_misoc/ethmac.rs | 5 +- artiq/firmware/libboard_misoc/lib.rs | 3 +- artiq/firmware/libeh/Cargo.toml | 11 + artiq/firmware/libeh/dwarf.rs | 243 +++++++++++ artiq/firmware/libeh/eh_rust.rs | 88 ++++ artiq/firmware/libeh/lib.rs | 9 + artiq/firmware/runtime/Cargo.toml | 9 +- artiq/firmware/runtime/main.rs | 44 +- artiq/firmware/runtime/profiler.rs | 26 +- artiq/firmware/runtime/sched.rs | 9 +- artiq/test/coredevice/test_performance.py | 4 +- artiq/test/libartiq_support/lib.rs | 11 +- artiq/test/lit/lit.cfg | 2 +- conda/artiq-dev/meta.yaml | 2 +- 25 files changed, 721 insertions(+), 581 deletions(-) delete mode 100644 artiq/firmware/ksupport/eh.rs create mode 100644 artiq/firmware/ksupport/eh_artiq.rs create mode 100644 artiq/firmware/libeh/Cargo.toml create mode 100644 artiq/firmware/libeh/dwarf.rs create mode 100644 artiq/firmware/libeh/eh_rust.rs create mode 100644 artiq/firmware/libeh/lib.rs diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index b9096a13e..885310773 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -30,9 +30,8 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=2139686)", ] [[package]] @@ -43,7 +42,7 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=2139686)", ] [[package]] @@ -70,11 +69,6 @@ name = "cfg-if" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "compiler_builtins" -version = "0.1.0" -source = "git+https://github.com/rust-lang-nursery/compiler-builtins#28daccd9159d33fac5e36394e4f9618db8870dc0" - [[package]] name = "crc" version = "1.8.1" @@ -92,6 +86,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "dyld" version = "0.0.0" +[[package]] +name = "eh" +version = "0.0.0" +dependencies = [ + "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "failure" version = "0.1.1" @@ -110,7 +111,7 @@ dependencies = [ [[package]] name = "fringe" version = "1.1.0" -source = "git+https://github.com/m-labs/libfringe?rev=bd23494#bd2349467157969324ca7da5d2ae033c7ffac0c0" +source = "git+https://github.com/m-labs/libfringe?rev=b8a6d8f#b8a6d8f68df0edaa3d67d9f3b7b62af9d3bb64a5" dependencies = [ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -133,6 +134,7 @@ dependencies = [ "build_misoc 0.0.0", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dyld 0.0.0", + "eh 0.0.0", "io 0.0.0", "proto_artiq 0.0.0", ] @@ -174,12 +176,7 @@ dependencies = [ [[package]] name = "managed" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "managed" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -210,15 +207,16 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "eh 0.0.0", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)", + "fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=b8a6d8f)", "io 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "logger_artiq 0.0.0", - "managed 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "proto_artiq 0.0.0", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=2139686)", "unwind_backtrace 0.0.0", ] @@ -235,11 +233,12 @@ dependencies = [ [[package]] name = "smoltcp" version = "0.4.0" -source = "git+https://github.com/m-labs/smoltcp?rev=181083f#181083f18c977b8a0463a67e360e4db20594fa21" +source = "git+https://github.com/m-labs/smoltcp?rev=2139686#21396867114d267da06f19cc54cc4a1883b900a5" dependencies = [ + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "managed 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -284,20 +283,18 @@ version = "0.0.0" "checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" "checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba" "checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18" -"checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins)" = "" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" -"checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=bd23494)" = "" +"checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=b8a6d8f)" = "" "checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum log_buffer 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f033173c9486b7fe97a79c895c0a3483ae395ab6744c985d10078950e2492419" -"checksum managed 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43e2737ecabe4ae36a68061398bf27d2bfd0763f4c3c837a398478459494c4b7" -"checksum managed 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5a31885241e61ba264d780d2e6686e7e59561c947b4581470364eb3e10102d86" +"checksum managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba6713e624266d7600e9feae51b1926c6a6a6bebb18ec5a8e11a5f1d5661baba" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=181083f)" = "" +"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=2139686)" = "" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml index 519e587ba..5ab62863a 100644 --- a/artiq/firmware/bootloader/Cargo.toml +++ b/artiq/firmware/bootloader/Cargo.toml @@ -19,6 +19,6 @@ board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "181083f" +rev = "2139686" default-features = false features = ["proto-ipv4", "socket-tcp"] diff --git a/artiq/firmware/bootloader/bootloader.ld b/artiq/firmware/bootloader/bootloader.ld index 6331f920e..d4976d534 100644 --- a/artiq/firmware/bootloader/bootloader.ld +++ b/artiq/firmware/bootloader/bootloader.ld @@ -15,6 +15,13 @@ SECTIONS *(.text .text.*) } > rom + /* + * The compiler_builtins crate includes some GOTPC relocations, which require a GOT symbol, + * but don't actually need a GOT. This really ought to be fixed on rustc level, but I'm afraid + * it will add further complications to our build system that aren't pulling their weight. + */ + _GLOBAL_OFFSET_TABLE_ = .; + .rodata : { *(.rodata.*) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index e5515fb20..c48adf77f 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(lang_items)] +#![feature(panic_implementation, panic_info_message)] extern crate crc; extern crate byteorder; @@ -188,7 +188,8 @@ fn network_boot() { println!("Waiting for connections..."); loop { - match interface.poll(&mut sockets, clock::get_ms()) { + let timestamp = smoltcp::time::Instant::from_millis(clock::get_ms() as i64); + match interface.poll(&mut sockets, timestamp) { Ok(_) => (), Err(smoltcp::Error::Unrecognized) => (), Err(err) => println!("Network error: {}", err) @@ -232,10 +233,18 @@ pub extern fn abort() { loop {} } -#[no_mangle] -#[lang = "panic_fmt"] -pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, - line: u32, column: u32) -> ! { - println!("panic at {}:{}:{}: {}", file, line, column, args); +#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647} +#[panic_implementation] +pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! { + if let Some(location) = info.location() { + print!("panic at {}:{}:{}", location.file(), location.line(), location.column()); + } else { + print!("panic at unknown location"); + } + if let Some(message) = info.message() { + println!(": {}", message); + } else { + println!(""); + } loop {} } diff --git a/artiq/firmware/ksupport/Cargo.toml b/artiq/firmware/ksupport/Cargo.toml index 3318dc44d..ba53a7c9a 100644 --- a/artiq/firmware/ksupport/Cargo.toml +++ b/artiq/firmware/ksupport/Cargo.toml @@ -14,6 +14,7 @@ build_misoc = { path = "../libbuild_misoc" } [dependencies] cslice = { version = "0.3" } +eh = { path = "../libeh" } io = { path = "../libio", features = ["byteorder"] } dyld = { path = "../libdyld" } board_misoc = { path = "../libboard_misoc" } diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 20efa1411..77d8b1edc 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -71,9 +71,9 @@ static mut API: &'static [(&'static str, *const ())] = &[ /* exceptions */ api!(_Unwind_Resume = ::unwind::_Unwind_Resume), - api!(__artiq_personality = ::eh::personality), - api!(__artiq_raise = ::eh::raise), - api!(__artiq_reraise = ::eh::reraise), + api!(__artiq_personality = ::eh_artiq::personality), + api!(__artiq_raise = ::eh_artiq::raise), + api!(__artiq_reraise = ::eh_artiq::reraise), /* proxified syscalls */ api!(core_log), diff --git a/artiq/firmware/ksupport/eh.rs b/artiq/firmware/ksupport/eh.rs deleted file mode 100644 index 73ba51ae2..000000000 --- a/artiq/firmware/ksupport/eh.rs +++ /dev/null @@ -1,465 +0,0 @@ -// Portions of the code in this file are derived from code by: -// -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -#![allow(non_upper_case_globals, non_camel_case_types, dead_code)] - -use core::{ptr, mem}; -use cslice::CSlice; -use unwind as uw; -use libc::{c_int, c_void}; - -type _Unwind_Stop_Fn = extern "C" fn(version: c_int, - actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, - exception_object: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context, - stop_parameter: *mut c_void) - -> uw::_Unwind_Reason_Code; -extern { - fn _Unwind_ForcedUnwind(exception: *mut uw::_Unwind_Exception, - stop_fn: _Unwind_Stop_Fn, - stop_parameter: *mut c_void) -> uw::_Unwind_Reason_Code; -} - -const DW_EH_PE_omit: u8 = 0xFF; -const DW_EH_PE_absptr: u8 = 0x00; - -const DW_EH_PE_uleb128: u8 = 0x01; -const DW_EH_PE_udata2: u8 = 0x02; -const DW_EH_PE_udata4: u8 = 0x03; -const DW_EH_PE_udata8: u8 = 0x04; -const DW_EH_PE_sleb128: u8 = 0x09; -const DW_EH_PE_sdata2: u8 = 0x0A; -const DW_EH_PE_sdata4: u8 = 0x0B; -const DW_EH_PE_sdata8: u8 = 0x0C; - -const DW_EH_PE_pcrel: u8 = 0x10; -const DW_EH_PE_textrel: u8 = 0x20; -const DW_EH_PE_datarel: u8 = 0x30; -const DW_EH_PE_funcrel: u8 = 0x40; -const DW_EH_PE_aligned: u8 = 0x50; - -const DW_EH_PE_indirect: u8 = 0x80; - -#[derive(Clone)] -struct DwarfReader { - pub ptr: *const u8, -} - -impl DwarfReader { - fn new(ptr: *const u8) -> DwarfReader { - DwarfReader { ptr: ptr } - } - - // DWARF streams are packed, so e.g. a u32 would not necessarily be aligned - // on a 4-byte boundary. This may cause problems on platforms with strict - // alignment requirements. By wrapping data in a "packed" struct, we are - // telling the backend to generate "misalignment-safe" code. - unsafe fn read(&mut self) -> T { - let result = ptr::read_unaligned(self.ptr as *const T); - self.ptr = self.ptr.offset(mem::size_of::() as isize); - result - } - - // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable - // Length Data". - unsafe fn read_uleb128(&mut self) -> u64 { - let mut shift: usize = 0; - let mut result: u64 = 0; - let mut byte: u8; - loop { - byte = self.read::(); - result |= ((byte & 0x7F) as u64) << shift; - shift += 7; - if byte & 0x80 == 0 { - break; - } - } - result - } - - unsafe fn read_sleb128(&mut self) -> i64 { - let mut shift: usize = 0; - let mut result: u64 = 0; - let mut byte: u8; - loop { - byte = self.read::(); - result |= ((byte & 0x7F) as u64) << shift; - shift += 7; - if byte & 0x80 == 0 { - break; - } - } - // sign-extend - if shift < 8 * mem::size_of::() && (byte & 0x40) != 0 { - result |= (!0 as u64) << shift; - } - result as i64 - } - - unsafe fn read_encoded_pointer(&mut self, encoding: u8) -> usize { - fn round_up(unrounded: usize, align: usize) -> usize { - debug_assert!(align.is_power_of_two()); - (unrounded + align - 1) & !(align - 1) - } - - debug_assert!(encoding != DW_EH_PE_omit); - - // DW_EH_PE_aligned implies it's an absolute pointer value - if encoding == DW_EH_PE_aligned { - self.ptr = round_up(self.ptr as usize, mem::size_of::()) as *const u8; - return self.read::() - } - - let value_ptr = self.ptr; - let mut result = match encoding & 0x0F { - DW_EH_PE_absptr => self.read::(), - DW_EH_PE_uleb128 => self.read_uleb128() as usize, - DW_EH_PE_udata2 => self.read::() as usize, - DW_EH_PE_udata4 => self.read::() as usize, - DW_EH_PE_udata8 => self.read::() as usize, - DW_EH_PE_sleb128 => self.read_sleb128() as usize, - DW_EH_PE_sdata2 => self.read::() as usize, - DW_EH_PE_sdata4 => self.read::() as usize, - DW_EH_PE_sdata8 => self.read::() as usize, - _ => panic!(), - }; - - result += match encoding & 0x70 { - DW_EH_PE_absptr => 0, - // relative to address of the encoded value, despite the name - DW_EH_PE_pcrel => value_ptr as usize, - _ => panic!(), - }; - - if encoding & DW_EH_PE_indirect != 0 { - result = *(result as *const usize); - } - - result - } -} - -fn encoding_size(encoding: u8) -> usize { - if encoding == DW_EH_PE_omit { - return 0 - } - - match encoding & 0x0F { - DW_EH_PE_absptr => mem::size_of::(), - DW_EH_PE_udata2 => 2, - DW_EH_PE_udata4 => 4, - DW_EH_PE_udata8 => 8, - DW_EH_PE_sdata2 => 2, - DW_EH_PE_sdata4 => 4, - DW_EH_PE_sdata8 => 8, - _ => panic!() - } -} - -pub enum EHAction { - None, - Cleanup(usize), - Catch(usize), - Terminate, -} - -unsafe fn find_eh_action(lsda: *const u8, func_start: usize, ip: usize, - exn_name: CSlice) -> EHAction { - if lsda.is_null() { - return EHAction::None - } - - let mut reader = DwarfReader::new(lsda); - - let start_encoding = reader.read::(); - // base address for landing pad offsets - let lpad_base = if start_encoding != DW_EH_PE_omit { - reader.read_encoded_pointer(start_encoding) - } else { - func_start - }; - - let ttype_encoding = reader.read::(); - let ttype_encoding_size = encoding_size(ttype_encoding) as isize; - - let class_info; - if ttype_encoding != DW_EH_PE_omit { - let class_info_offset = reader.read_uleb128(); - class_info = reader.ptr.offset(class_info_offset as isize); - } else { - class_info = ptr::null(); - } - assert!(!class_info.is_null()); - - let call_site_encoding = reader.read::(); - let call_site_table_length = reader.read_uleb128(); - let action_table = reader.ptr.offset(call_site_table_length as isize); - - while reader.ptr < action_table { - let cs_start = reader.read_encoded_pointer(call_site_encoding); - let cs_len = reader.read_encoded_pointer(call_site_encoding); - let cs_lpad = reader.read_encoded_pointer(call_site_encoding); - let cs_action = reader.read_uleb128(); - - if ip < func_start + cs_start { - // Callsite table is sorted by cs_start, so if we've passed the ip, we - // may stop searching. - break - } - if ip > func_start + cs_start + cs_len { - continue - } - - if cs_lpad == 0 { - return EHAction::None - } - - let lpad = lpad_base + cs_lpad; - if cs_action == 0 { - return EHAction::Cleanup(lpad) - } - - let action_entry = action_table.offset((cs_action - 1) as isize); - let mut action_reader = DwarfReader::new(action_entry); - loop { - let type_info_offset = action_reader.read_sleb128() as isize; - let action_offset = action_reader.clone().read_sleb128() as isize; - assert!(type_info_offset >= 0); - - if type_info_offset > 0 { - let type_info_ptr_ptr = class_info.offset(-type_info_offset * ttype_encoding_size); - let type_info_ptr = DwarfReader::new(type_info_ptr_ptr) - .read_encoded_pointer(ttype_encoding); - let type_info = *(type_info_ptr as *const CSlice); - - if type_info.as_ref() == exn_name.as_ref() { - return EHAction::Catch(lpad) - } - - if type_info.len() == 0 { - // This is a catch-all clause. We don't compare type_info_ptr with null here - // because, in PIC mode, the OR1K LLVM backend emits a literal zero - // encoded with DW_EH_PE_pcrel, which of course doesn't result in - // a proper null pointer. - return EHAction::Catch(lpad) - } - } - - if action_offset == 0 { - break - } else { - action_reader.ptr = action_reader.ptr.offset(action_offset) - } - } - - return EHAction::None - } - - // the function has a personality but no landing pads; this is fine - EHAction::None -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct Exception<'a> { - pub name: CSlice<'a, u8>, - pub file: CSlice<'a, u8>, - pub line: u32, - pub column: u32, - pub function: CSlice<'a, u8>, - pub message: CSlice<'a, u8>, - pub param: [i64; 3] -} - -const EXCEPTION_CLASS: uw::_Unwind_Exception_Class = 0x4d_4c_42_53_41_52_54_51; /* 'MLBSARTQ' */ - -const MAX_BACKTRACE_SIZE: usize = 128; - -#[repr(C)] -struct ExceptionInfo { - uw_exception: uw::_Unwind_Exception, - exception: Option>, - handled: bool, - backtrace: [usize; MAX_BACKTRACE_SIZE], - backtrace_size: usize -} - -#[cfg(target_arch = "x86_64")] -const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX - -#[cfg(any(target_arch = "or1k"))] -const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 - -#[export_name="__artiq_personality"] -pub extern fn personality(version: c_int, - actions: uw::_Unwind_Action, - uw_exception_class: uw::_Unwind_Exception_Class, - uw_exception: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context) - -> uw::_Unwind_Reason_Code { - unsafe { - if version != 1 || uw_exception_class != EXCEPTION_CLASS { - return uw::_URC_FATAL_PHASE1_ERROR - } - - let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8; - let ip = uw::_Unwind_GetIP(context) - 1; - let func_start = uw::_Unwind_GetRegionStart(context); - - let exception_info = &mut *(uw_exception as *mut ExceptionInfo); - let exception = &exception_info.exception.unwrap(); - - let eh_action = find_eh_action(lsda, func_start, ip, exception.name); - if actions as u32 & uw::_UA_SEARCH_PHASE as u32 != 0 { - match eh_action { - EHAction::None | - EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND, - EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND, - EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR, - } - } else { - match eh_action { - EHAction::None => return uw::_URC_CONTINUE_UNWIND, - EHAction::Cleanup(lpad) | - EHAction::Catch(lpad) => { - if actions as u32 & uw::_UA_HANDLER_FRAME as u32 != 0 { - exception_info.handled = true - } - - // Pass a pair of the unwinder exception and ARTIQ exception - // (which immediately follows). - uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, - uw_exception as uw::_Unwind_Word); - uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, - exception as *const _ as uw::_Unwind_Word); - uw::_Unwind_SetIP(context, lpad); - return uw::_URC_INSTALL_CONTEXT; - } - EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR, - } - } - } -} - -extern fn cleanup(_unwind_code: uw::_Unwind_Reason_Code, - uw_exception: *mut uw::_Unwind_Exception) { - unsafe { - let exception_info = &mut *(uw_exception as *mut ExceptionInfo); - - exception_info.exception = None; - } -} - -extern fn uncaught_exception(_version: c_int, - actions: uw::_Unwind_Action, - _uw_exception_class: uw::_Unwind_Exception_Class, - uw_exception: *mut uw::_Unwind_Exception, - context: *mut uw::_Unwind_Context, - _stop_parameter: *mut c_void) - -> uw::_Unwind_Reason_Code { - unsafe { - let exception_info = &mut *(uw_exception as *mut ExceptionInfo); - - if exception_info.backtrace_size < exception_info.backtrace.len() { - let ip = uw::_Unwind_GetIP(context); - exception_info.backtrace[exception_info.backtrace_size] = ip; - exception_info.backtrace_size += 1; - } - - if actions as u32 & uw::_UA_END_OF_STACK as u32 != 0 { - ::terminate(&exception_info.exception.unwrap(), - exception_info.backtrace[..exception_info.backtrace_size].as_mut()) - } else { - uw::_URC_NO_REASON - } - } -} - -// We can unfortunately not use mem::zeroed in a static, so Option<> is used as a workaround. -// See https://github.com/rust-lang/rust/issues/39498. -static mut INFLIGHT: ExceptionInfo = ExceptionInfo { - uw_exception: uw::_Unwind_Exception { - exception_class: EXCEPTION_CLASS, - exception_cleanup: cleanup, - private: [0; uw::unwinder_private_data_size], - }, - exception: None, - handled: true, - backtrace: [0; MAX_BACKTRACE_SIZE], - backtrace_size: 0 -}; - -#[export_name="__artiq_raise"] -#[unwind(allowed)] -pub unsafe extern fn raise(exception: *const Exception) -> ! { - // Zing! The Exception<'a> to Exception<'static> transmute is not really sound in case - // the exception is ever captured. Fortunately, they currently aren't, and we save - // on the hassle of having to allocate exceptions somewhere except on stack. - INFLIGHT.exception = Some(mem::transmute::>(*exception)); - INFLIGHT.handled = false; - - let result = uw::_Unwind_RaiseException(&mut INFLIGHT.uw_exception); - assert!(result == uw::_URC_END_OF_STACK); - - INFLIGHT.backtrace_size = 0; - let _result = _Unwind_ForcedUnwind(&mut INFLIGHT.uw_exception, - uncaught_exception, ptr::null_mut()); - unreachable!() -} - -#[export_name="__artiq_reraise"] -#[unwind(allowed)] -pub unsafe extern fn reraise() -> ! { - use cslice::AsCSlice; - - if INFLIGHT.handled { - match INFLIGHT.exception { - Some(ref exception) => raise(exception), - None => raise(&Exception { - name: "0:artiq.coredevice.exceptions.RuntimeError".as_c_slice(), - file: file!().as_c_slice(), - line: line!(), - column: column!(), - // https://github.com/rust-lang/rfcs/pull/1719 - function: "__artiq_reraise".as_c_slice(), - message: "No active exception to reraise".as_c_slice(), - param: [0, 0, 0] - }) - } - } else { - uw::_Unwind_Resume(&mut INFLIGHT.uw_exception) - } -} - -// Stub implementations for the functions the panic_unwind crate expects to be provided. -// These all do nothing in libunwind, but aren't built for OR1K. -pub mod stubs { - #![allow(bad_style, unused_variables)] - - use super::{uw, c_int}; - - #[export_name="_Unwind_GetIPInfo"] - pub unsafe extern fn _Unwind_GetIPInfo(ctx: *mut uw::_Unwind_Context, - ip_before_insn: *mut c_int) -> uw::_Unwind_Word { - *ip_before_insn = 0; - uw::_Unwind_GetIP(ctx) - } - - #[export_name="_Unwind_GetTextRelBase"] - pub unsafe extern fn _Unwind_GetTextRelBase(ctx: *mut uw::_Unwind_Context) -> uw::_Unwind_Ptr { - unimplemented!() - } - - #[export_name="_Unwind_GetDataRelBase"] - pub unsafe extern fn _Unwind_GetDataRelBase(ctx: *mut uw::_Unwind_Context) -> uw::_Unwind_Ptr { - unimplemented!() - } -} diff --git a/artiq/firmware/ksupport/eh_artiq.rs b/artiq/firmware/ksupport/eh_artiq.rs new file mode 100644 index 000000000..8bfc171a0 --- /dev/null +++ b/artiq/firmware/ksupport/eh_artiq.rs @@ -0,0 +1,203 @@ +// Portions of the code in this file are derived from code by: +// +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![allow(private_no_mangle_fns, non_camel_case_types)] + +use core::{ptr, mem}; +use cslice::CSlice; +use unwind as uw; +use libc::{c_int, c_void}; + +use eh::dwarf::{self, EHAction}; + +type _Unwind_Stop_Fn = extern "C" fn(version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context, + stop_parameter: *mut c_void) + -> uw::_Unwind_Reason_Code; +extern { + fn _Unwind_ForcedUnwind(exception: *mut uw::_Unwind_Exception, + stop_fn: _Unwind_Stop_Fn, + stop_parameter: *mut c_void) -> uw::_Unwind_Reason_Code; +} + +#[repr(C)] +#[derive(Clone, Copy)] +pub struct Exception<'a> { + pub name: CSlice<'a, u8>, + pub file: CSlice<'a, u8>, + pub line: u32, + pub column: u32, + pub function: CSlice<'a, u8>, + pub message: CSlice<'a, u8>, + pub param: [i64; 3] +} + +const EXCEPTION_CLASS: uw::_Unwind_Exception_Class = 0x4d_4c_42_53_41_52_54_51; /* 'MLBSARTQ' */ + +const MAX_BACKTRACE_SIZE: usize = 128; + +#[repr(C)] +struct ExceptionInfo { + uw_exception: uw::_Unwind_Exception, + exception: Option>, + handled: bool, + backtrace: [usize; MAX_BACKTRACE_SIZE], + backtrace_size: usize +} + +#[cfg(target_arch = "x86_64")] +const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX + +#[cfg(any(target_arch = "or1k"))] +const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 + +#[export_name="__artiq_personality"] +pub extern fn personality(version: c_int, + actions: uw::_Unwind_Action, + uw_exception_class: uw::_Unwind_Exception_Class, + uw_exception: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code { + unsafe { + if version != 1 || uw_exception_class != EXCEPTION_CLASS { + return uw::_URC_FATAL_PHASE1_ERROR + } + + let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8; + let ip = uw::_Unwind_GetIP(context) - 1; + let func_start = uw::_Unwind_GetRegionStart(context); + + let exception_info = &mut *(uw_exception as *mut ExceptionInfo); + let exception = &exception_info.exception.unwrap(); + + let eh_action = dwarf::find_eh_action(lsda, func_start, ip, exception.name); + if actions as u32 & uw::_UA_SEARCH_PHASE as u32 != 0 { + match eh_action { + EHAction::None | + EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND, + EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND, + EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR, + } + } else { + match eh_action { + EHAction::None => return uw::_URC_CONTINUE_UNWIND, + EHAction::Cleanup(lpad) | + EHAction::Catch(lpad) => { + if actions as u32 & uw::_UA_HANDLER_FRAME as u32 != 0 { + exception_info.handled = true + } + + // Pass a pair of the unwinder exception and ARTIQ exception + // (which immediately follows). + uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, + uw_exception as uw::_Unwind_Word); + uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, + exception as *const _ as uw::_Unwind_Word); + uw::_Unwind_SetIP(context, lpad); + return uw::_URC_INSTALL_CONTEXT; + } + EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR, + } + } + } +} + +extern fn cleanup(_unwind_code: uw::_Unwind_Reason_Code, + uw_exception: *mut uw::_Unwind_Exception) { + unsafe { + let exception_info = &mut *(uw_exception as *mut ExceptionInfo); + + exception_info.exception = None; + } +} + +extern fn uncaught_exception(_version: c_int, + actions: uw::_Unwind_Action, + _uw_exception_class: uw::_Unwind_Exception_Class, + uw_exception: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context, + _stop_parameter: *mut c_void) + -> uw::_Unwind_Reason_Code { + unsafe { + let exception_info = &mut *(uw_exception as *mut ExceptionInfo); + + if exception_info.backtrace_size < exception_info.backtrace.len() { + let ip = uw::_Unwind_GetIP(context); + exception_info.backtrace[exception_info.backtrace_size] = ip; + exception_info.backtrace_size += 1; + } + + if actions as u32 & uw::_UA_END_OF_STACK as u32 != 0 { + ::terminate(&exception_info.exception.unwrap(), + exception_info.backtrace[..exception_info.backtrace_size].as_mut()) + } else { + uw::_URC_NO_REASON + } + } +} + +// We can unfortunately not use mem::zeroed in a static, so Option<> is used as a workaround. +// See https://github.com/rust-lang/rust/issues/39498. +static mut INFLIGHT: ExceptionInfo = ExceptionInfo { + uw_exception: uw::_Unwind_Exception { + exception_class: EXCEPTION_CLASS, + exception_cleanup: cleanup, + private: [0; uw::unwinder_private_data_size], + }, + exception: None, + handled: true, + backtrace: [0; MAX_BACKTRACE_SIZE], + backtrace_size: 0 +}; + +#[export_name="__artiq_raise"] +#[unwind(allowed)] +pub unsafe extern fn raise(exception: *const Exception) -> ! { + // Zing! The Exception<'a> to Exception<'static> transmute is not really sound in case + // the exception is ever captured. Fortunately, they currently aren't, and we save + // on the hassle of having to allocate exceptions somewhere except on stack. + INFLIGHT.exception = Some(mem::transmute::>(*exception)); + INFLIGHT.handled = false; + + let result = uw::_Unwind_RaiseException(&mut INFLIGHT.uw_exception); + assert!(result == uw::_URC_END_OF_STACK); + + INFLIGHT.backtrace_size = 0; + let _result = _Unwind_ForcedUnwind(&mut INFLIGHT.uw_exception, + uncaught_exception, ptr::null_mut()); + unreachable!() +} + +#[export_name="__artiq_reraise"] +#[unwind(allowed)] +pub unsafe extern fn reraise() -> ! { + use cslice::AsCSlice; + + if INFLIGHT.handled { + match INFLIGHT.exception { + Some(ref exception) => raise(exception), + None => raise(&Exception { + name: "0:artiq.coredevice.exceptions.RuntimeError".as_c_slice(), + file: file!().as_c_slice(), + line: line!(), + column: column!(), + // https://github.com/rust-lang/rfcs/pull/1719 + function: "__artiq_reraise".as_c_slice(), + message: "No active exception to reraise".as_c_slice(), + param: [0, 0, 0] + }) + } + } else { + uw::_Unwind_Resume(&mut INFLIGHT.uw_exception) + } +} diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index b3a18bf1a..bd4552dd2 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -1,12 +1,12 @@ -#![feature(lang_items, asm, libc, panic_unwind, unwind_attributes, global_allocator, - needs_panic_runtime)] +#![feature(lang_items, asm, panic_unwind, libc, unwind_attributes, + panic_implementation, panic_info_message)] #![no_std] -#![needs_panic_runtime] -extern crate cslice; -extern crate unwind; extern crate libc; +extern crate unwind; +extern crate cslice; +extern crate eh; extern crate io; extern crate dyld; extern crate board_misoc; @@ -46,11 +46,20 @@ macro_rules! recv { } } -#[no_mangle] -#[lang = "panic_fmt"] -pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, - line: u32, column: u32) -> ! { - send(&Log(format_args!("panic at {}:{}:{}: {}\n", file, line, column, args))); +#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647} +#[panic_implementation] +pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! { + if let Some(location) = info.location() { + send(&Log(format_args!("panic at {}:{}:{}", + location.file(), location.line(), location.column()))); + } else { + send(&Log(format_args!("panic at unknown location"))); + } + if let Some(message) = info.message() { + send(&Log(format_args!("{}\n", message))); + } else { + send(&Log(format_args!("\n"))); + } send(&RunAborted); loop {} } @@ -67,7 +76,7 @@ macro_rules! println { macro_rules! raise { ($name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => ({ use cslice::AsCSlice; - let exn = $crate::eh::Exception { + let exn = $crate::eh_artiq::Exception { name: concat!("0:artiq.coredevice.exceptions.", $name).as_c_slice(), file: file!().as_c_slice(), line: line!(), @@ -78,14 +87,14 @@ macro_rules! raise { param: [$param0, $param1, $param2] }; #[allow(unused_unsafe)] - unsafe { $crate::eh::raise(&exn) } + unsafe { $crate::eh_artiq::raise(&exn) } }); ($name:expr, $message:expr) => ({ raise!($name, $message, 0, 0, 0) }); } -pub mod eh; +mod eh_artiq; mod api; mod rtio; mod nrt_bus; @@ -109,6 +118,7 @@ pub extern fn send_to_rtio_log(timestamp: i64, text: CSlice) { rtio::log(timestamp, text.as_ref()) } +#[unwind(aborts)] extern fn rpc_send(service: u32, tag: CSlice, data: *const *const ()) { while !rpc_queue::empty() {} send(&RpcSend { @@ -119,6 +129,7 @@ extern fn rpc_send(service: u32, tag: CSlice, data: *const *const ()) { }) } +#[unwind(aborts)] extern fn rpc_send_async(service: u32, tag: CSlice, data: *const *const ()) { while rpc_queue::full() {} rpc_queue::enqueue(|mut slice| { @@ -141,6 +152,7 @@ extern fn rpc_send_async(service: u32, tag: CSlice, data: *const *const ()) }) } +#[unwind(allowed)] extern fn rpc_recv(slot: *mut ()) -> usize { send(&RpcRecvRequest(slot)); recv!(&RpcRecvReply(ref result) => { @@ -148,7 +160,7 @@ extern fn rpc_recv(slot: *mut ()) -> usize { &Ok(alloc_size) => alloc_size, &Err(ref exception) => unsafe { - eh::raise(&eh::Exception { + eh_artiq::raise(&eh_artiq::Exception { name: exception.name.as_bytes().as_c_slice(), file: exception.file.as_bytes().as_c_slice(), line: exception.line, @@ -162,7 +174,7 @@ extern fn rpc_recv(slot: *mut ()) -> usize { }) } -fn terminate(exception: &eh::Exception, backtrace: &mut [usize]) -> ! { +fn terminate(exception: &eh_artiq::Exception, backtrace: &mut [usize]) -> ! { let mut cursor = 0; for index in 0..backtrace.len() { if backtrace[index] > kernel_proto::KERNELCPU_PAYLOAD_ADDRESS { @@ -188,6 +200,7 @@ fn terminate(exception: &eh::Exception, backtrace: &mut [usize]) -> ! { loop {} } +#[unwind(allowed)] extern fn watchdog_set(ms: i64) -> i32 { if ms < 0 { raise!("ValueError", "cannot set a watchdog with a negative timeout") @@ -197,10 +210,12 @@ extern fn watchdog_set(ms: i64) -> i32 { recv!(&WatchdogSetReply { id } => id) as i32 } +#[unwind(aborts)] extern fn watchdog_clear(id: i32) { send(&WatchdogClear { id: id as usize }) } +#[unwind(aborts)] extern fn cache_get(key: CSlice) -> CSlice<'static, i32> { send(&CacheGetRequest { key: str::from_utf8(key.as_ref()).unwrap() @@ -208,6 +223,7 @@ extern fn cache_get(key: CSlice) -> CSlice<'static, i32> { recv!(&CacheGetReply { value } => value.as_c_slice()) } +#[unwind(allowed)] extern fn cache_put(key: CSlice, list: CSlice) { send(&CachePutRequest { key: str::from_utf8(key.as_ref()).unwrap(), @@ -241,6 +257,7 @@ fn dma_record_flush() { } } +#[unwind(allowed)] extern fn dma_record_start(name: CSlice) { let name = str::from_utf8(name.as_ref()).unwrap(); @@ -260,6 +277,7 @@ extern fn dma_record_start(name: CSlice) { } } +#[unwind(allowed)] extern fn dma_record_stop(duration: i64) { unsafe { dma_record_flush(); @@ -281,10 +299,12 @@ extern fn dma_record_stop(duration: i64) { } } +#[unwind(aborts)] extern fn dma_record_output(timestamp: i64, channel: i32, address: i32, word: i32) { dma_record_output_wide(timestamp, channel, address, [word].as_c_slice()) } +#[unwind(aborts)] extern fn dma_record_output_wide(timestamp: i64, channel: i32, address: i32, words: CSlice) { assert!(words.len() <= 16); // enforce the hardware limit @@ -333,6 +353,7 @@ extern fn dma_record_output_wide(timestamp: i64, channel: i32, address: i32, wor } } +#[unwind(aborts)] extern fn dma_erase(name: CSlice) { let name = str::from_utf8(name.as_ref()).unwrap(); @@ -345,6 +366,7 @@ struct DmaTrace { address: i32, } +#[unwind(allowed)] extern fn dma_retrieve(name: CSlice) -> DmaTrace { let name = str::from_utf8(name.as_ref()).unwrap(); @@ -365,6 +387,7 @@ extern fn dma_retrieve(name: CSlice) -> DmaTrace { } #[cfg(has_rtio_dma)] +#[unwind(allowed)] extern fn dma_playback(timestamp: i64, ptr: i32) { assert!(ptr % 64 == 0); @@ -399,6 +422,7 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { } #[cfg(not(has_rtio_dma))] +#[unwind(allowed)] extern fn dma_playback(_timestamp: i64, _ptr: i32) { unimplemented!("not(has_rtio_dma)") } @@ -485,11 +509,13 @@ pub unsafe fn main() { } #[no_mangle] +#[unwind(allowed)] pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea) } #[no_mangle] +#[unwind(allowed)] pub extern fn abort() { panic!("aborted") } diff --git a/artiq/firmware/liballoc_list/lib.rs b/artiq/firmware/liballoc_list/lib.rs index 4854575bb..f01262007 100644 --- a/artiq/firmware/liballoc_list/lib.rs +++ b/artiq/firmware/liballoc_list/lib.rs @@ -1,10 +1,7 @@ -#![feature(alloc, allocator_api)] #![no_std] -extern crate alloc; - -use core::{mem, fmt}; -use alloc::allocator::{Layout, AllocErr, Alloc}; +use core::{ptr, mem, fmt}; +use core::alloc::{GlobalAlloc, Layout}; // The minimum alignment guaranteed by the architecture. const MIN_ALIGN: usize = 4; @@ -42,10 +39,10 @@ impl ListAlloc { } } -unsafe impl<'a> Alloc for &'a ListAlloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { +unsafe impl GlobalAlloc for ListAlloc { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { if layout.align() > MIN_ALIGN { - return Err(AllocErr::Unsupported { details: "alignment too large" }) + panic!("cannot allocate with alignment {}", layout.align()) } let header_size = mem::size_of::
(); @@ -83,7 +80,7 @@ unsafe impl<'a> Alloc for &'a ListAlloc { if (*curr).size >= size { (*curr).magic = MAGIC_BUSY; - return Ok(curr.offset(1) as *mut u8) + return curr.offset(1) as *mut u8 } }, _ => panic!("heap corruption detected at {:p}", curr) @@ -92,20 +89,16 @@ unsafe impl<'a> Alloc for &'a ListAlloc { curr = (*curr).next; } - Err(AllocErr::Exhausted { request: layout }) + ptr::null_mut() } - unsafe fn dealloc(&mut self, ptr: *mut u8, _layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { let curr = (ptr as *mut Header).offset(-1); if (*curr).magic != MAGIC_BUSY { panic!("heap corruption detected at {:p}", curr) } (*curr).magic = MAGIC_FREE; } - - fn oom(&mut self, err: AllocErr) -> ! { - panic!("heap view: {}\ncannot allocate: {:?}", self, err) - } } impl fmt::Display for ListAlloc { diff --git a/artiq/firmware/libboard_misoc/Cargo.toml b/artiq/firmware/libboard_misoc/Cargo.toml index 35851cfb5..1efd23a4e 100644 --- a/artiq/firmware/libboard_misoc/Cargo.toml +++ b/artiq/firmware/libboard_misoc/Cargo.toml @@ -13,13 +13,12 @@ cc = "1.0" build_misoc = { path = "../libbuild_misoc" } [dependencies] -compiler_builtins = { git = "https://github.com/rust-lang-nursery/compiler-builtins", features = ["mem"] } byteorder = { version = "1.0", default-features = false } log = { version = "0.4", default-features = false, optional = true } [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "181083f" +rev = "2139686" # NB: also change in runtime/Cargo.toml default-features = false optional = true diff --git a/artiq/firmware/libboard_misoc/ethmac.rs b/artiq/firmware/libboard_misoc/ethmac.rs index ce8af0e42..263f8122d 100644 --- a/artiq/firmware/libboard_misoc/ethmac.rs +++ b/artiq/firmware/libboard_misoc/ethmac.rs @@ -1,5 +1,6 @@ use core::{slice, fmt}; use smoltcp::Result; +use smoltcp::time::Instant; use smoltcp::phy::{self, DeviceCapabilities, Device}; use csr; @@ -95,7 +96,7 @@ impl<'a> Device<'a> for EthernetDevice { pub struct EthernetRxSlot(usize); impl phy::RxToken for EthernetRxSlot { - fn consume(self, _timestamp: u64, f: F) -> Result + fn consume(self, _timestamp: Instant, f: F) -> Result where F: FnOnce(&[u8]) -> Result { unsafe { @@ -110,7 +111,7 @@ impl phy::RxToken for EthernetRxSlot { pub struct EthernetTxSlot(usize); impl phy::TxToken for EthernetTxSlot { - fn consume(self, _timestamp: u64, length: usize, f: F) -> Result + fn consume(self, _timestamp: Instant, length: usize, f: F) -> Result where F: FnOnce(&mut [u8]) -> Result { debug_assert!(length < SLOT_SIZE); diff --git a/artiq/firmware/libboard_misoc/lib.rs b/artiq/firmware/libboard_misoc/lib.rs index 690f29e99..ad941f00a 100644 --- a/artiq/firmware/libboard_misoc/lib.rs +++ b/artiq/firmware/libboard_misoc/lib.rs @@ -1,7 +1,6 @@ #![no_std] -#![feature(compiler_builtins_lib, asm, try_from)] +#![feature(asm, try_from)] -extern crate compiler_builtins; extern crate byteorder; #[cfg(feature = "log")] extern crate log; diff --git a/artiq/firmware/libeh/Cargo.toml b/artiq/firmware/libeh/Cargo.toml new file mode 100644 index 000000000..c1bea6f4f --- /dev/null +++ b/artiq/firmware/libeh/Cargo.toml @@ -0,0 +1,11 @@ +[package] +authors = ["M-Labs"] +name = "eh" +version = "0.0.0" + +[lib] +name = "eh" +path = "lib.rs" + +[dependencies] +cslice = { version = "0.3" } diff --git a/artiq/firmware/libeh/dwarf.rs b/artiq/firmware/libeh/dwarf.rs new file mode 100644 index 000000000..0956dc267 --- /dev/null +++ b/artiq/firmware/libeh/dwarf.rs @@ -0,0 +1,243 @@ +#![allow(non_upper_case_globals, dead_code)] + +use core::{ptr, mem}; +use cslice::CSlice; + +const DW_EH_PE_omit: u8 = 0xFF; +const DW_EH_PE_absptr: u8 = 0x00; + +const DW_EH_PE_uleb128: u8 = 0x01; +const DW_EH_PE_udata2: u8 = 0x02; +const DW_EH_PE_udata4: u8 = 0x03; +const DW_EH_PE_udata8: u8 = 0x04; +const DW_EH_PE_sleb128: u8 = 0x09; +const DW_EH_PE_sdata2: u8 = 0x0A; +const DW_EH_PE_sdata4: u8 = 0x0B; +const DW_EH_PE_sdata8: u8 = 0x0C; + +const DW_EH_PE_pcrel: u8 = 0x10; +const DW_EH_PE_textrel: u8 = 0x20; +const DW_EH_PE_datarel: u8 = 0x30; +const DW_EH_PE_funcrel: u8 = 0x40; +const DW_EH_PE_aligned: u8 = 0x50; + +const DW_EH_PE_indirect: u8 = 0x80; + +#[derive(Clone)] +struct DwarfReader { + pub ptr: *const u8, +} + +impl DwarfReader { + fn new(ptr: *const u8) -> DwarfReader { + DwarfReader { ptr: ptr } + } + + // DWARF streams are packed, so e.g. a u32 would not necessarily be aligned + // on a 4-byte boundary. This may cause problems on platforms with strict + // alignment requirements. By wrapping data in a "packed" struct, we are + // telling the backend to generate "misalignment-safe" code. + unsafe fn read(&mut self) -> T { + let result = ptr::read_unaligned(self.ptr as *const T); + self.ptr = self.ptr.offset(mem::size_of::() as isize); + result + } + + // ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable + // Length Data". + unsafe fn read_uleb128(&mut self) -> u64 { + let mut shift: usize = 0; + let mut result: u64 = 0; + let mut byte: u8; + loop { + byte = self.read::(); + result |= ((byte & 0x7F) as u64) << shift; + shift += 7; + if byte & 0x80 == 0 { + break; + } + } + result + } + + unsafe fn read_sleb128(&mut self) -> i64 { + let mut shift: usize = 0; + let mut result: u64 = 0; + let mut byte: u8; + loop { + byte = self.read::(); + result |= ((byte & 0x7F) as u64) << shift; + shift += 7; + if byte & 0x80 == 0 { + break; + } + } + // sign-extend + if shift < 8 * mem::size_of::() && (byte & 0x40) != 0 { + result |= (!0 as u64) << shift; + } + result as i64 + } + + unsafe fn read_encoded_pointer(&mut self, encoding: u8) -> usize { + fn round_up(unrounded: usize, align: usize) -> usize { + debug_assert!(align.is_power_of_two()); + (unrounded + align - 1) & !(align - 1) + } + + debug_assert!(encoding != DW_EH_PE_omit); + + // DW_EH_PE_aligned implies it's an absolute pointer value + if encoding == DW_EH_PE_aligned { + self.ptr = round_up(self.ptr as usize, mem::size_of::()) as *const u8; + return self.read::() + } + + let value_ptr = self.ptr; + let mut result = match encoding & 0x0F { + DW_EH_PE_absptr => self.read::(), + DW_EH_PE_uleb128 => self.read_uleb128() as usize, + DW_EH_PE_udata2 => self.read::() as usize, + DW_EH_PE_udata4 => self.read::() as usize, + DW_EH_PE_udata8 => self.read::() as usize, + DW_EH_PE_sleb128 => self.read_sleb128() as usize, + DW_EH_PE_sdata2 => self.read::() as usize, + DW_EH_PE_sdata4 => self.read::() as usize, + DW_EH_PE_sdata8 => self.read::() as usize, + _ => panic!(), + }; + + result += match encoding & 0x70 { + DW_EH_PE_absptr => 0, + // relative to address of the encoded value, despite the name + DW_EH_PE_pcrel => value_ptr as usize, + _ => panic!(), + }; + + if encoding & DW_EH_PE_indirect != 0 { + result = *(result as *const usize); + } + + result + } +} + +fn encoding_size(encoding: u8) -> usize { + if encoding == DW_EH_PE_omit { + return 0 + } + + match encoding & 0x0F { + DW_EH_PE_absptr => mem::size_of::(), + DW_EH_PE_udata2 => 2, + DW_EH_PE_udata4 => 4, + DW_EH_PE_udata8 => 8, + DW_EH_PE_sdata2 => 2, + DW_EH_PE_sdata4 => 4, + DW_EH_PE_sdata8 => 8, + _ => panic!() + } +} + +pub enum EHAction { + None, + Cleanup(usize), + Catch(usize), + Terminate, +} + +pub unsafe fn find_eh_action(lsda: *const u8, func_start: usize, ip: usize, + exn_name: CSlice) -> EHAction { + if lsda.is_null() { + return EHAction::None + } + + let mut reader = DwarfReader::new(lsda); + + let start_encoding = reader.read::(); + // base address for landing pad offsets + let lpad_base = if start_encoding != DW_EH_PE_omit { + reader.read_encoded_pointer(start_encoding) + } else { + func_start + }; + + let ttype_encoding = reader.read::(); + let ttype_encoding_size = encoding_size(ttype_encoding) as isize; + + let class_info; + if ttype_encoding != DW_EH_PE_omit { + let class_info_offset = reader.read_uleb128(); + class_info = reader.ptr.offset(class_info_offset as isize); + } else { + class_info = ptr::null(); + } + assert!(!class_info.is_null()); + + let call_site_encoding = reader.read::(); + let call_site_table_length = reader.read_uleb128(); + let action_table = reader.ptr.offset(call_site_table_length as isize); + + while reader.ptr < action_table { + let cs_start = reader.read_encoded_pointer(call_site_encoding); + let cs_len = reader.read_encoded_pointer(call_site_encoding); + let cs_lpad = reader.read_encoded_pointer(call_site_encoding); + let cs_action = reader.read_uleb128(); + + if ip < func_start + cs_start { + // Callsite table is sorted by cs_start, so if we've passed the ip, we + // may stop searching. + break + } + if ip > func_start + cs_start + cs_len { + continue + } + + if cs_lpad == 0 { + return EHAction::None + } + + let lpad = lpad_base + cs_lpad; + if cs_action == 0 { + return EHAction::Cleanup(lpad) + } + + let action_entry = action_table.offset((cs_action - 1) as isize); + let mut action_reader = DwarfReader::new(action_entry); + loop { + let type_info_offset = action_reader.read_sleb128() as isize; + let action_offset = action_reader.clone().read_sleb128() as isize; + assert!(type_info_offset >= 0); + + if type_info_offset > 0 { + let type_info_ptr_ptr = class_info.offset(-type_info_offset * ttype_encoding_size); + let type_info_ptr = DwarfReader::new(type_info_ptr_ptr) + .read_encoded_pointer(ttype_encoding); + let type_info = *(type_info_ptr as *const CSlice); + + if type_info.as_ref() == exn_name.as_ref() { + return EHAction::Catch(lpad) + } + + if type_info.len() == 0 { + // This is a catch-all clause. We don't compare type_info_ptr with null here + // because, in PIC mode, the OR1K LLVM backend emits a literal zero + // encoded with DW_EH_PE_pcrel, which of course doesn't result in + // a proper null pointer. + return EHAction::Catch(lpad) + } + } + + if action_offset == 0 { + break + } else { + action_reader.ptr = action_reader.ptr.offset(action_offset) + } + } + + return EHAction::None + } + + // the function has a personality but no landing pads; this is fine + EHAction::None +} diff --git a/artiq/firmware/libeh/eh_rust.rs b/artiq/firmware/libeh/eh_rust.rs new file mode 100644 index 000000000..7fb14193d --- /dev/null +++ b/artiq/firmware/libeh/eh_rust.rs @@ -0,0 +1,88 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This is the Rust personality function, adapted for use in ARTIQ. We never actually panic +// from Rust or recover from Rust exceptions (there's nothing to catch the panics), but we +// need a personality function to step back through Rust frames in order to make a backtrace. +// +// By design, this personality function is only ever called in the search phase, although +// to keep things simple and close to upstream, it is not modified +#![allow(private_no_mangle_fns)] + +use unwind as uw; +use libc::{c_int, uintptr_t}; +use cslice::AsCSlice; + +use dwarf::{self, EHAction}; + +// Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister() +// and TargetLowering::getExceptionSelectorRegister() for each architecture, +// then mapped to DWARF register numbers via register definition tables +// (typically RegisterInfo.td, search for "DwarfRegNum"). +// See also http://llvm.org/docs/WritingAnLLVMBackend.html#defining-a-register. + +#[cfg(target_arch = "x86")] +const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX + +#[cfg(target_arch = "x86_64")] +const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX + +#[cfg(any(target_arch = "or1k"))] +const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 + +// The following code is based on GCC's C and C++ personality routines. For reference, see: +// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc +// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c +#[lang = "eh_personality"] +#[no_mangle] +#[allow(unused)] +unsafe extern "C" fn rust_eh_personality(version: c_int, + actions: uw::_Unwind_Action, + exception_class: uw::_Unwind_Exception_Class, + exception_object: *mut uw::_Unwind_Exception, + context: *mut uw::_Unwind_Context) + -> uw::_Unwind_Reason_Code { + if version != 1 { + return uw::_URC_FATAL_PHASE1_ERROR; + } + let eh_action = match find_eh_action(context) { + Ok(action) => action, + Err(_) => return uw::_URC_FATAL_PHASE1_ERROR, + }; + if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 { + match eh_action { + EHAction::None | + EHAction::Cleanup(_) => return uw::_URC_CONTINUE_UNWIND, + EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND, + EHAction::Terminate => return uw::_URC_FATAL_PHASE1_ERROR, + } + } else { + match eh_action { + EHAction::None => return uw::_URC_CONTINUE_UNWIND, + EHAction::Cleanup(lpad) | + EHAction::Catch(lpad) => { + uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t); + uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0); + uw::_Unwind_SetIP(context, lpad); + return uw::_URC_INSTALL_CONTEXT; + } + EHAction::Terminate => return uw::_URC_FATAL_PHASE2_ERROR, + } + } +} + +unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) + -> Result +{ + let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8; + let func = uw::_Unwind_GetRegionStart(context); + let ip = uw::_Unwind_GetIP(context); + Ok(dwarf::find_eh_action(lsda, func, ip, [].as_c_slice())) +} diff --git a/artiq/firmware/libeh/lib.rs b/artiq/firmware/libeh/lib.rs new file mode 100644 index 000000000..da209ea25 --- /dev/null +++ b/artiq/firmware/libeh/lib.rs @@ -0,0 +1,9 @@ +#![feature(lang_items, panic_unwind, libc, unwind_attributes)] +#![no_std] + +extern crate cslice; +extern crate unwind; +extern crate libc; + +pub mod dwarf; +pub mod eh_rust; diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index ec0990aff..8be210b35 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -18,7 +18,8 @@ failure_derive = { version = "0.1", default-features = false } byteorder = { version = "1.0", default-features = false } cslice = { version = "0.3" } log = { version = "0.4", default-features = false } -managed = { version = "0.6", default-features = false, features = ["alloc", "map"] } +managed = { version = "= 0.7.0", default-features = false, features = ["alloc", "map"] } +eh = { path = "../libeh" } unwind_backtrace = { path = "../libunwind_backtrace" } io = { path = "../libio", features = ["byteorder"] } alloc_list = { path = "../liballoc_list" } @@ -29,12 +30,12 @@ proto_artiq = { path = "../libproto_artiq", features = ["log", "alloc"] } [dependencies.fringe] git = "https://github.com/m-labs/libfringe" -rev = "bd23494" +rev = "b8a6d8f" default-features = false features = ["alloc"] [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "181083f" +rev = "2139686" # NB: also change in libboard_misoc/Cargo.toml default-features = false -features = ["alloc", "log", "proto-ipv4", "socket-tcp"] +features = ["rust-1.28", "alloc", "log", "proto-ipv4", "socket-tcp"] diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 494c3ff87..77e76cc09 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -1,7 +1,8 @@ -#![feature(lang_items, alloc, global_allocator, try_from, nonzero, nll, needs_panic_runtime, asm)] +#![feature(lang_items, alloc, try_from, nonzero, asm, + panic_implementation, panic_info_message)] #![no_std] -#![needs_panic_runtime] +extern crate eh; #[macro_use] extern crate alloc; extern crate failure; @@ -250,18 +251,18 @@ fn startup_ethernet() { net_device.reset_phy_if_any(); let net_device = { + use smoltcp::time::Instant; use smoltcp::wire::PrettyPrinter; use smoltcp::wire::EthernetFrame; - fn net_trace_writer(timestamp: u64, printer: PrettyPrinter>) { - let seconds = timestamp / 1000; - let micros = timestamp % 1000 * 1000; - print!("\x1b[37m[{:6}.{:06}s]\n{}\x1b[0m\n", seconds, micros, printer) + fn net_trace_writer(timestamp: Instant, printer: PrettyPrinter>) { + print!("\x1b[37m[{:6}.{:03}s]\n{}\x1b[0m\n", + timestamp.secs(), timestamp.millis(), printer) } - fn net_trace_silent(_timestamp: u64, _printer: PrettyPrinter>) {} + fn net_trace_silent(_timestamp: Instant, _printer: PrettyPrinter>) {} - let net_trace_fn: fn(u64, PrettyPrinter>); + let net_trace_fn: fn(Instant, PrettyPrinter>); match config::read_str("net_trace", |r| r.map(|s| s == "1")) { Ok(true) => net_trace_fn = net_trace_writer, _ => net_trace_fn = net_trace_silent @@ -299,7 +300,8 @@ fn startup_ethernet() { { let sockets = &mut *scheduler.sockets().borrow_mut(); loop { - match interface.poll(sockets, clock::get_ms()) { + let timestamp = smoltcp::time::Instant::from_millis(clock::get_ms() as i64); + match interface.poll(sockets, timestamp) { Ok(true) => (), Ok(false) => break, Err(smoltcp::Error::Unrecognized) => (), @@ -373,13 +375,27 @@ pub extern fn abort() { loop {} } -#[no_mangle] -#[lang = "panic_fmt"] -pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, - line: u32, column: u32) -> ! { +#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647} +#[lang = "oom"] // https://github.com/rust-lang/rust/issues/51540 +pub fn oom(layout: core::alloc::Layout) -> ! { + panic!("heap view: {}\ncannot allocate layout: {:?}", unsafe { &ALLOC }, layout) +} + +#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647} +#[panic_implementation] +pub fn panic_impl(info: &core::panic::PanicInfo) -> ! { irq::set_ie(false); - println!("panic at {}:{}:{}: {}", file, line, column, args); + if let Some(location) = info.location() { + print!("panic at {}:{}:{}", location.file(), location.line(), location.column()); + } else { + print!("panic at unknown location"); + } + if let Some(message) = info.message() { + println!("{}", message); + } else { + println!(""); + } println!("backtrace for software version {}:", csr::CONFIG_IDENTIFIER_STR); let _ = unwind_backtrace::backtrace(|ip| { diff --git a/artiq/firmware/runtime/profiler.rs b/artiq/firmware/runtime/profiler.rs index ac5097dfe..6df9c3f8c 100644 --- a/artiq/firmware/runtime/profiler.rs +++ b/artiq/firmware/runtime/profiler.rs @@ -64,27 +64,23 @@ impl Profile { pub fn record_hit(&mut self, addr: Address) -> Result<(), ()> { let mut hits = self.hits(); - match hits.get_mut(&addr) { - Some(count) => *count = count.saturating_add(1), - None => { - if let Err(_) = hits.insert(addr, 1) { - return Err(()) - } - } + if let Some(count) = hits.get_mut(&addr) { + return Ok(*count = count.saturating_add(1)) } - Ok(()) + if let Err(_) = hits.insert(addr, 1) { + return Err(()) + } + return Ok(()) } #[allow(dead_code)] pub fn record_edge(&mut self, caller: Address, callee: Address) -> Result<(), ()> { let mut edges = self.edges(); - match edges.get_mut(&(caller, callee)) { - Some(count) => *count = count.saturating_add(1), - None => { - if let Err(_) = edges.insert((caller, callee), 1) { - return Err(()) - } - } + if let Some(count) = edges.get_mut(&(caller, callee)) { + return Ok(*count = count.saturating_add(1)) + } + if let Err(_) = edges.insert((caller, callee), 1) { + return Err(()) } Ok(()) } diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index 5578be444..c28fff956 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -6,6 +6,7 @@ use core::cell::{Cell, RefCell}; use alloc::Vec; use fringe::OwnedStack; use fringe::generator::{Generator, Yielder, State as GeneratorState}; +use smoltcp::time::Duration; use smoltcp::Error as NetworkError; use smoltcp::wire::IpEndpoint; use smoltcp::socket::{SocketHandle, SocketRef}; @@ -426,19 +427,19 @@ impl<'a> TcpStream<'a> { } pub fn timeout(&self) -> Option { - self.with_lower(|s| s.timeout()) + self.with_lower(|s| s.timeout().as_ref().map(Duration::millis)) } pub fn set_timeout(&self, value: Option) { - self.with_lower(|mut s| s.set_timeout(value)) + self.with_lower(|mut s| s.set_timeout(value.map(Duration::from_millis))) } pub fn keep_alive(&self) -> Option { - self.with_lower(|s| s.keep_alive()) + self.with_lower(|s| s.keep_alive().as_ref().map(Duration::millis)) } pub fn set_keep_alive(&self, value: Option) { - self.with_lower(|mut s| s.set_keep_alive(value)) + self.with_lower(|mut s| s.set_keep_alive(value.map(Duration::from_millis))) } pub fn close(&self) -> Result<(), Error> { diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index 8e91b7859..19d1a41af 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -44,7 +44,7 @@ class TransferTest(ExperimentCase): exp = self.create(_Transfer) host_to_device_rate = exp.host_to_device() print(host_to_device_rate, "B/s") - self.assertGreater(host_to_device_rate, 1.9e6) + self.assertGreater(host_to_device_rate, 1.8e6) @unittest.skipUnless(artiq_low_latency, "timings are dependent on CPU load and network conditions") @@ -52,7 +52,7 @@ class TransferTest(ExperimentCase): exp = self.create(_Transfer) device_to_host_rate = exp.device_to_host() print(device_to_host_rate, "B/s") - self.assertGreater(device_to_host_rate, 1.9e6) + self.assertGreater(device_to_host_rate, 1.8e6) class _KernelOverhead(EnvExperiment): diff --git a/artiq/test/libartiq_support/lib.rs b/artiq/test/libartiq_support/lib.rs index b3188e17a..51344b402 100644 --- a/artiq/test/libartiq_support/lib.rs +++ b/artiq/test/libartiq_support/lib.rs @@ -50,12 +50,17 @@ mod cslice { } } -#[path = "../../firmware/ksupport/eh.rs"] -pub mod eh; +#[path = "."] +pub mod eh { + #[path = "../../firmware/libeh/dwarf.rs"] + pub mod dwarf; +} +#[path = "../../firmware/ksupport/eh_artiq.rs"] +pub mod eh_artiq; use std::{str, process}; -fn terminate(exception: &eh::Exception, mut _backtrace: &mut [usize]) -> ! { +fn terminate(exception: &eh_artiq::Exception, mut _backtrace: &mut [usize]) -> ! { println!("Uncaught {}: {} ({}, {}, {})", str::from_utf8(exception.name.as_ref()).unwrap(), str::from_utf8(exception.message.as_ref()).unwrap(), diff --git a/artiq/test/lit/lit.cfg b/artiq/test/lit/lit.cfg index c31490091..daa4c1723 100644 --- a/artiq/test/lit/lit.cfg +++ b/artiq/test/lit/lit.cfg @@ -30,7 +30,7 @@ if os.name == "posix": support_build = os.path.join(root, "libartiq_support") if subprocess.call(["rustc", os.path.join(support_build, "lib.rs"), "--out-dir", support_build, - "-Cpanic=abort", "-g"]) != 0: + "-Cpanic=unwind", "-g"]) != 0: lit_config.fatal("Unable to build JIT support library") support_lib = os.path.join(support_build, "libartiq_support.so") diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 84da9437a..e9f878df5 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -21,7 +21,7 @@ requirements: - binutils-or1k-linux >=2.27 - llvm-or1k 6.0.0 - llvmlite-artiq 0.23.0.dev py35_4 - - rust-core-or1k 1.26.0 21 + - rust-core-or1k 1.28.0 21 - openocd 0.10.0 6 - lit - outputcheck From bdd18de2c1bcd7fe588e73f79b71a4ffab81e596 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 12 Aug 2018 19:11:48 +0000 Subject: [PATCH 1117/2457] firmware: globally enable LTO. This used to crash with earlier rustc versions, but doesn't anymore, and gives significant speedup (e.g. 2x on test_dma_record_time). --- artiq/firmware/Cargo.toml | 1 + artiq/firmware/bootloader/Makefile | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/Cargo.toml b/artiq/firmware/Cargo.toml index 8ab755b00..1d2f871f3 100644 --- a/artiq/firmware/Cargo.toml +++ b/artiq/firmware/Cargo.toml @@ -3,4 +3,5 @@ members = ["bootloader", "runtime", "ksupport", "satman"] [profile.dev] incremental = false # incompatible with LTO +lto = true debug = 2 diff --git a/artiq/firmware/bootloader/Makefile b/artiq/firmware/bootloader/Makefile index f247c0994..ee70ff22f 100644 --- a/artiq/firmware/bootloader/Makefile +++ b/artiq/firmware/bootloader/Makefile @@ -7,8 +7,7 @@ all:: bootloader.bin .PHONY: $(RUSTOUT)/libbootloader.a $(RUSTOUT)/libbootloader.a: - $(cargo) --manifest-path $(BOOTLOADER_DIRECTORY)/Cargo.toml -- \ - -Clto + $(cargo) --manifest-path $(BOOTLOADER_DIRECTORY)/Cargo.toml bootloader.elf: $(RUSTOUT)/libbootloader.a $(link) -T $(BOOTLOADER_DIRECTORY)/bootloader.ld From 38d60100ffa14c1a8ac0818aabd13288d02ca459 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 12 Aug 2018 19:12:36 +0000 Subject: [PATCH 1118/2457] firmware: optimize dma_record_output. This removes a number of bounds checks and adds a fast path for outputting exactly one word to DMA, which is the most common operation. --- artiq/firmware/ksupport/lib.rs | 67 ++++++++++++++++++------------ artiq/test/coredevice/test_rtio.py | 2 +- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index bd4552dd2..d4a6615d2 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -1,5 +1,5 @@ #![feature(lang_items, asm, panic_unwind, libc, unwind_attributes, - panic_implementation, panic_info_message)] + panic_implementation, panic_info_message, nll)] #![no_std] extern crate libc; @@ -300,19 +300,24 @@ extern fn dma_record_stop(duration: i64) { } #[unwind(aborts)] -extern fn dma_record_output(timestamp: i64, channel: i32, address: i32, word: i32) { - dma_record_output_wide(timestamp, channel, address, [word].as_c_slice()) -} - -#[unwind(aborts)] -extern fn dma_record_output_wide(timestamp: i64, channel: i32, address: i32, words: CSlice) { - assert!(words.len() <= 16); // enforce the hardware limit - +#[inline(always)] +unsafe fn dma_record_output_prepare(timestamp: i64, channel: i32, address: i32, + words: usize) -> &'static mut [u8] { // See gateware/rtio/dma.py. - let header_length = /*length*/1 + /*channel*/3 + /*timestamp*/8 + /*address*/2; - let length = header_length + /*data*/words.len() * 4; + const HEADER_LENGTH: usize = /*length*/1 + /*channel*/3 + /*timestamp*/8 + /*address*/2; + let length = HEADER_LENGTH + /*data*/words * 4; - let header = [ + if DMA_RECORDER.buffer.len() - DMA_RECORDER.data_len < length { + dma_record_flush() + } + + let record = &mut DMA_RECORDER.buffer[DMA_RECORDER.data_len.. + DMA_RECORDER.data_len + length]; + DMA_RECORDER.data_len += length; + + let (header, data) = record.split_at_mut(HEADER_LENGTH); + + header.copy_from_slice(&[ (length >> 0) as u8, (channel >> 0) as u8, (channel >> 8) as u8, @@ -327,29 +332,39 @@ extern fn dma_record_output_wide(timestamp: i64, channel: i32, address: i32, wor (timestamp >> 56) as u8, (address >> 0) as u8, (address >> 8) as u8, - ]; + ]); - let mut data = [0; 16 * 4]; - for (i, &word) in words.as_ref().iter().enumerate() { - let part = [ + data +} + +#[unwind(aborts)] +extern fn dma_record_output(timestamp: i64, channel: i32, address: i32, word: i32) { + unsafe { + let data = dma_record_output_prepare(timestamp, channel, address, 1); + data.copy_from_slice(&[ (word >> 0) as u8, (word >> 8) as u8, (word >> 16) as u8, (word >> 24) as u8, - ]; - data[i * 4..(i + 1) * 4].copy_from_slice(&part[..]); + ]); } - let data = &data[..words.len() * 4]; +} + +#[unwind(aborts)] +extern fn dma_record_output_wide(timestamp: i64, channel: i32, address: i32, words: CSlice) { + assert!(words.len() <= 16); // enforce the hardware limit unsafe { - if DMA_RECORDER.buffer.len() - DMA_RECORDER.data_len < length { - dma_record_flush() + let mut data = dma_record_output_prepare(timestamp, channel, address, 1); + for word in words.as_ref().iter() { + data[..4].copy_from_slice(&[ + (word >> 0) as u8, + (word >> 8) as u8, + (word >> 16) as u8, + (word >> 24) as u8, + ]); + data = &mut data[4..]; } - let dst = &mut DMA_RECORDER.buffer[DMA_RECORDER.data_len.. - DMA_RECORDER.data_len + length]; - dst[..header_length].copy_from_slice(&header[..]); - dst[header_length..].copy_from_slice(&data[..]); - DMA_RECORDER.data_len += length; } } diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 8a2a7f6e6..7556302be 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -641,7 +641,7 @@ class DMATest(ExperimentCase): exp.record_many(count) dt = self.dataset_mgr.get("dma_record_time") print("dt={}, dt/count={}".format(dt, dt/count)) - self.assertLess(dt/count, 20*us) + self.assertLess(dt/count, 11*us) def test_dma_playback_time(self): # Skip on Kasli until #946 is resolved. From 46bd96abd1a1979efc57bf6acee2aa1b6e090199 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 12 Aug 2018 19:12:52 +0000 Subject: [PATCH 1119/2457] artiq_devtool: make kasli-tester the default configuration. --- artiq/frontend/artiq_devtool.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index 58edba27d..aacd813c7 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -31,7 +31,7 @@ def get_argparser(): verbosity_args(parser) parser.add_argument("-t", "--target", metavar="TARGET", - type=str, default="kc705", + type=str, default="kasli", help="target to build, one of: " "kc705 kasli sayma") parser.add_argument("-V", "--variant", metavar="VARIANT", @@ -91,7 +91,7 @@ def main(): variant = "standalone" if args.variant is None else args.variant elif args.target == "kasli": board_type, firmware = "kasli", "runtime" - variant = "opticlock" if args.variant is None else args.variant + variant = "tester" if args.variant is None else args.variant else: raise NotImplementedError("unknown target {}".format(args.target)) From e285fe0d566777343b615083391eee15829a5194 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 12 Aug 2018 20:17:37 +0000 Subject: [PATCH 1120/2457] test: tighten required TransferTest timings. smoltcp performs significantly better with LTO. --- artiq/test/coredevice/test_performance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index 19d1a41af..9d423714d 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -44,7 +44,7 @@ class TransferTest(ExperimentCase): exp = self.create(_Transfer) host_to_device_rate = exp.host_to_device() print(host_to_device_rate, "B/s") - self.assertGreater(host_to_device_rate, 1.8e6) + self.assertGreater(host_to_device_rate, 2.1e6) @unittest.skipUnless(artiq_low_latency, "timings are dependent on CPU load and network conditions") @@ -52,7 +52,7 @@ class TransferTest(ExperimentCase): exp = self.create(_Transfer) device_to_host_rate = exp.device_to_host() print(device_to_host_rate, "B/s") - self.assertGreater(device_to_host_rate, 1.8e6) + self.assertGreater(device_to_host_rate, 2.4e6) class _KernelOverhead(EnvExperiment): From 0e32a165c297481aa34b30b4f852bfa63c1e816b Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 13 Aug 2018 00:12:21 +0100 Subject: [PATCH 1121/2457] satman: Fix build with Rust 1.28 The build was broken in 2648b1b7a1b13e2591c9ba8a53f25022862f17e2. --- artiq/firmware/satman/main.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index fb0546cac..b109ef96f 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -1,4 +1,4 @@ -#![feature(lang_items, never_type)] +#![feature(never_type, panic_implementation, panic_info_message)] #![no_std] #[macro_use] @@ -328,10 +328,18 @@ pub extern fn abort() { loop {} } -#[no_mangle] -#[lang = "panic_fmt"] -pub extern fn panic_fmt(args: core::fmt::Arguments, file: &'static str, - line: u32, column: u32) -> ! { - println!("panic at {}:{}:{}: {}", file, line, column, args); +#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647} +#[panic_implementation] +pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! { + if let Some(location) = info.location() { + print!("panic at {}:{}:{}", location.file(), location.line(), location.column()); + } else { + print!("panic at unknown location"); + } + if let Some(message) = info.message() { + println!(": {}", message); + } else { + println!(""); + } loop {} } From 34329cf3665728c198beef65b98432ecaf6c70eb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 13 Aug 2018 12:12:36 +0800 Subject: [PATCH 1122/2457] artiq_flash: target Kasli by default --- RELEASE_NOTES.rst | 2 ++ artiq/frontend/artiq_flash.py | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 83d10d2ac..0c96a5cd4 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -21,6 +21,8 @@ ARTIQ-4 server address argument and the notify port. * The master now has a ``--name`` argument. If given, the dashboard is labelled with this name rather than the server address. +* ``artiq_flash`` targets Kasli by default. Use ``-t kc705`` to flash a KC705 + instead. * ``artiq_flash -m/--adapter`` has been changed to ``artiq_flash -V/--variant``. * The ``proxy`` action of ``artiq_flash`` is determined automatically and should not be specified manually anymore. diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 5fca7702a..b8b2754bb 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -51,9 +51,9 @@ Prerequisites: parser.add_argument("-J", "--jump", type=str, default=None, help="SSH host to jump through") - parser.add_argument("-t", "--target", default="kc705", + parser.add_argument("-t", "--target", default="kasli", help="target board, default: %(default)s, one of: " - "kc705 kasli sayma") + "kasli sayma kc705") parser.add_argument("-V", "--variant", default=None, help="board variant") parser.add_argument("-I", "--preinit-command", default=[], action="append", @@ -258,14 +258,6 @@ def main(): init_logger(args) config = { - "kc705": { - "programmer": partial(ProgrammerXC7, board="kc705", proxy="bscan_spi_xc7k325t.bit"), - "def_variant": "nist_clock", - "gateware": ("spi0", 0x000000), - "bootloader": ("spi0", 0xaf0000), - "storage": ("spi0", 0xb30000), - "firmware": ("spi0", 0xb40000), - }, "kasli": { "programmer": partial(ProgrammerXC7, board="kasli", proxy="bscan_spi_xc7a100t.bit"), "def_variant": "opticlock", @@ -283,6 +275,14 @@ def main(): "firmware": ("spi1", 0x050000), "rtm_gateware": ("spi1", 0x200000), }, + "kc705": { + "programmer": partial(ProgrammerXC7, board="kc705", proxy="bscan_spi_xc7k325t.bit"), + "def_variant": "nist_clock", + "gateware": ("spi0", 0x000000), + "bootloader": ("spi0", 0xaf0000), + "storage": ("spi0", 0xb30000), + "firmware": ("spi0", 0xb40000), + }, }[args.target] variant = args.variant From c172ec6de9e436d3dcc5758880d8cda2484c0450 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 13 Aug 2018 12:12:36 +0800 Subject: [PATCH 1123/2457] artiq_flash: target Kasli by default --- RELEASE_NOTES.rst | 2 ++ artiq/frontend/artiq_flash.py | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 83d10d2ac..0c96a5cd4 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -21,6 +21,8 @@ ARTIQ-4 server address argument and the notify port. * The master now has a ``--name`` argument. If given, the dashboard is labelled with this name rather than the server address. +* ``artiq_flash`` targets Kasli by default. Use ``-t kc705`` to flash a KC705 + instead. * ``artiq_flash -m/--adapter`` has been changed to ``artiq_flash -V/--variant``. * The ``proxy`` action of ``artiq_flash`` is determined automatically and should not be specified manually anymore. diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 5fca7702a..b8b2754bb 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -51,9 +51,9 @@ Prerequisites: parser.add_argument("-J", "--jump", type=str, default=None, help="SSH host to jump through") - parser.add_argument("-t", "--target", default="kc705", + parser.add_argument("-t", "--target", default="kasli", help="target board, default: %(default)s, one of: " - "kc705 kasli sayma") + "kasli sayma kc705") parser.add_argument("-V", "--variant", default=None, help="board variant") parser.add_argument("-I", "--preinit-command", default=[], action="append", @@ -258,14 +258,6 @@ def main(): init_logger(args) config = { - "kc705": { - "programmer": partial(ProgrammerXC7, board="kc705", proxy="bscan_spi_xc7k325t.bit"), - "def_variant": "nist_clock", - "gateware": ("spi0", 0x000000), - "bootloader": ("spi0", 0xaf0000), - "storage": ("spi0", 0xb30000), - "firmware": ("spi0", 0xb40000), - }, "kasli": { "programmer": partial(ProgrammerXC7, board="kasli", proxy="bscan_spi_xc7a100t.bit"), "def_variant": "opticlock", @@ -283,6 +275,14 @@ def main(): "firmware": ("spi1", 0x050000), "rtm_gateware": ("spi1", 0x200000), }, + "kc705": { + "programmer": partial(ProgrammerXC7, board="kc705", proxy="bscan_spi_xc7k325t.bit"), + "def_variant": "nist_clock", + "gateware": ("spi0", 0x000000), + "bootloader": ("spi0", 0xaf0000), + "storage": ("spi0", 0xb30000), + "firmware": ("spi0", 0xb40000), + }, }[args.target] variant = args.variant From ec97d636170fd64894fde297b834dcea780b4669 Mon Sep 17 00:00:00 2001 From: Stewart Mackenzie Date: Mon, 13 Aug 2018 17:42:25 +0800 Subject: [PATCH 1124/2457] nix: separated buildtime & runtime dependencies --- nix/artiq.nix | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/nix/artiq.nix b/nix/artiq.nix index 5be35279e..e9a287250 100644 --- a/nix/artiq.nix +++ b/nix/artiq.nix @@ -120,11 +120,8 @@ python35Packages.buildPythonPackage rec { version = "336482"; name = "artiq-${version}"; src = ./..; - propagatedBuildInputs = with python35Packages; [ - llvm-or1k llvmlite sphinx-argparse levenshtein - pyqtgraph aiohttp pygit2 pythonparser numpy - dateutil sphinx quamash scipy outputcheck - prettytable lit ml-pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; + buildInputs = with python35Packages; [ lit outputcheck sphinx sphinx-argparse ]; + propagatedBuildInputs = with python35Packages; [ llvm-or1k llvmlite levenshtein pyqtgraph aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable ml-pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; doCheck = false; meta = with stdenv.lib; { description = ""; From 2463e5667d1b226fff8c59b2afcd2aa9a6aae5c6 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 14 Aug 2018 13:33:14 +0100 Subject: [PATCH 1125/2457] compiler: Fix attribute writeback with skipped fields offset wasn't advanced for skipped fields previously, leading to memory corruption/unaligned accesses at runtime. --- artiq/compiler/transforms/llvm_ir_generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index b39c2b5bc..b27d2c868 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -564,7 +564,7 @@ class LLVMIRGenerator: try: llrpcattrs.append(llrpcattr_of_attr(offset, attr, attrtyp)) except ValueError: - continue + pass offset += size From 700383506215a79b750d42f2c5edf447ef177295 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 16 Aug 2018 00:21:51 +0800 Subject: [PATCH 1126/2457] nix: update license --- nix/artiq.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/artiq.nix b/nix/artiq.nix index e9a287250..7819bc774 100644 --- a/nix/artiq.nix +++ b/nix/artiq.nix @@ -126,7 +126,7 @@ python35Packages.buildPythonPackage rec { meta = with stdenv.lib; { description = ""; homepage = https://m-labs/artiq; - license = licenses.gpl3; + license = licenses.lgpl3; maintainers = [ maintainers.sjmackenzie ]; platforms = [ "x86_64-linux" ]; }; From 487720d13b2be827f211b7cf8ea424b8cdad9e31 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 16 Aug 2018 00:25:01 +0800 Subject: [PATCH 1127/2457] nix: remove sphinx (used for building doc, not running ARTIQ) --- nix/artiq.nix | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/nix/artiq.nix b/nix/artiq.nix index 7819bc774..f94103894 100644 --- a/nix/artiq.nix +++ b/nix/artiq.nix @@ -13,18 +13,6 @@ levenshtein = python35Packages.buildPythonPackage rec { doCheck = false; }; -sphinx-argparse = python35Packages.buildPythonPackage rec { - name = "sphinx-argparse"; - src = fetchFromGitHub { - owner = "ribozz"; - repo = "sphinx-argparse"; - rev = "cc95938b8fbf870f7a5c012d4d84a29cfbac5e06"; - sha256 = "1rsjlsnrpd4i4zx2sylilf6lfi77k0fclbhilrgx1m53ixllwg38"; - }; - buildInputs = with python35Packages; [ sphinx ]; - doCheck = false; -}; - pythonparser = python35Packages.buildPythonPackage rec { name = "pythonparser"; src = fetchFromGitHub { @@ -120,7 +108,7 @@ python35Packages.buildPythonPackage rec { version = "336482"; name = "artiq-${version}"; src = ./..; - buildInputs = with python35Packages; [ lit outputcheck sphinx sphinx-argparse ]; + buildInputs = with python35Packages; [ lit outputcheck ]; propagatedBuildInputs = with python35Packages; [ llvm-or1k llvmlite levenshtein pyqtgraph aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable ml-pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; doCheck = false; meta = with stdenv.lib; { From 0b1ce0ea3236d60589dd42a46f0747e122a67469 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 16 Aug 2018 00:25:55 +0800 Subject: [PATCH 1128/2457] nix: use original pyqtgraph and pyserial --- nix/artiq.nix | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/nix/artiq.nix b/nix/artiq.nix index f94103894..b270c21ba 100644 --- a/nix/artiq.nix +++ b/nix/artiq.nix @@ -25,18 +25,6 @@ pythonparser = python35Packages.buildPythonPackage rec { doCheck = false; }; -ml-pyserial = python35Packages.buildPythonPackage rec { - name = "pyserial"; - src = fetchFromGitHub { - owner = "m-labs"; - repo = "pyserial"; - rev = "f30653b23f01c1cc27eb9731afc8ad66a723a4c0"; - sha256 = "18xwsmpklggrm07b17ficpyjxnfgpw0k9lbz44nq4iflr8gmf33f"; - }; - buildInputs = with python35Packages; [ regex ]; - doCheck = false; -}; - asyncserial = python35Packages.buildPythonPackage rec { name = "asyncserial"; src = fetchFromGitHub { @@ -45,19 +33,7 @@ asyncserial = python35Packages.buildPythonPackage rec { rev = "d95bc1d6c791b0e9785935d2f62f628eb5cdf98d"; sha256 = "0yzkka9jk3612v8gx748x6ziwykq5lr7zmr9wzkcls0v2yilqx9k"; }; - buildInputs = with python35Packages; [ ml-pyserial ]; - doCheck = false; -}; - -pyqtgraph = python35Packages.buildPythonPackage rec { - name = "pyqtgraph"; - src = fetchFromGitHub { - owner = "m-labs"; - repo = "pyqtgraph"; - rev = "8e9ee6fd3cabcc06d25cde5f13921e5d9d11c588"; - sha256 = "0ynhsd4nlbz4pgwch0w767a9ybazn5f33rakpjdrcwldvrrrng6y"; - }; - buildInputs = with python35Packages; [ numpy ]; + buildInputs = with python35Packages; [ pyserial ]; doCheck = false; }; @@ -109,7 +85,7 @@ python35Packages.buildPythonPackage rec { name = "artiq-${version}"; src = ./..; buildInputs = with python35Packages; [ lit outputcheck ]; - propagatedBuildInputs = with python35Packages; [ llvm-or1k llvmlite levenshtein pyqtgraph aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable ml-pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; + propagatedBuildInputs = with python35Packages; [ llvm-or1k llvmlite levenshtein pyqtgraph aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; doCheck = false; meta = with stdenv.lib; { description = ""; From 73cf071b1a88dabcfead6e9c8b1536b4d49c1d09 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 16 Aug 2018 00:33:52 +0800 Subject: [PATCH 1129/2457] nix: update LLVM and llvmlite, remove clang (not needed for running) --- nix/fetch-llvm-clang.nix | 14 +++----------- nix/llvm-or1k.nix | 16 +++++++++++++--- nix/llvmlite.nix | 6 +++--- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/nix/fetch-llvm-clang.nix b/nix/fetch-llvm-clang.nix index cb53f93d0..d337eaa8e 100644 --- a/nix/fetch-llvm-clang.nix +++ b/nix/fetch-llvm-clang.nix @@ -2,21 +2,13 @@ let llvm-src = fetchFromGitHub { - rev = "ff2fe8c318eb7c934a2f2ac8da61a00d62becf1f"; - owner = "openrisc"; + rev = "527aa86b578da5dfb9cf4510b71f0f46a11249f7"; + owner = "m-labs"; repo = "llvm-or1k"; - sha256 = "061pvc4z5i92s1xwz9ir6yqnk5vb0xd8cs9php4yy01dyvpblql7"; -}; -clang-src = fetchFromGitHub { - rev = "030259ccc14261d02163cce28adb0c11243d0a99"; - owner = "openrisc"; - repo = "clang-or1k"; - sha256 = "1w7dk469svskr1c7ywcl9xsxbnvl40c28nffivpclijcvsh43463"; + sha256 = "0lmcg9xj66pf4mb6racipw67vm8kwm84dl861hyqnywd61kvhrwa"; }; in runCommand "llvm_or1k_src" {}'' mkdir -p $out -mkdir -p $out/tools/clang cp -r ${llvm-src}/* $out/ -cp -r ${clang-src}/* $out/tools/clang '' diff --git a/nix/llvm-or1k.nix b/nix/llvm-or1k.nix index 95d74061e..403e95fd3 100644 --- a/nix/llvm-or1k.nix +++ b/nix/llvm-or1k.nix @@ -18,10 +18,20 @@ stdenv.mkDerivation rec { ''; cmakeFlags = with stdenv; [ - "-DLLVM_TARGETS_TO_BUILD=OR1K;X86" - "-DCMAKE_BUILD_TYPE=Rel" - "-DLLVM_ENABLE_ASSERTIONS=ON" "-DCMAKE_BUILD_TYPE=Release" + "-DLLVM_BUILD_LLVM_DYLIB=ON" + "-DLLVM_LINK_LLVM_DYLIB=ON" + "-DLLVM_TARGETS_TO_BUILD=X86" + "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=OR1K" + "-DLLVM_ENABLE_ASSERTIONS=OFF" + "-DLLVM_INSTALL_UTILS=ON" + "-DLLVM_INCLUDE_TESTS=OFF" + "-DLLVM_INCLUDE_DOCS=OFF" + "-DLLVM_INCLUDE_EXAMPLES=OFF" + "-DCLANG_ENABLE_ARCMT=OFF" + "-DCLANG_ENABLE_STATIC_ANALYZER=OFF" + "-DCLANG_INCLUDE_TESTS=OFF" + "-DCLANG_INCLUDE_DOCS=OFF" ]; enableParallelBuilding = true; diff --git a/nix/llvmlite.nix b/nix/llvmlite.nix index 762c09cf7..6f5d1516d 100644 --- a/nix/llvmlite.nix +++ b/nix/llvmlite.nix @@ -6,15 +6,15 @@ stdenv.mkDerivation rec { name = "llvmlite-${version}"; src = fetchgit { url = "https://github.com/m-labs/llvmlite"; - rev = "0f4ebae43c2d2a084deb8b693e3d42a7b2c82222"; - sha256 = "0n90w0x001k0zyn8zz6jxc9i78agqv15m55vz2raw1y0rfw16mfl"; + rev = "401dfb713166bdd2bc0d3ab2b7ebf12e7a434130"; + sha256 = "1ci1pnpspv1pqz712yix1nmplq7568vpsr6gzzl3a33w9s0sw2nq"; leaveDotGit = true; }; buildInputs = [ makeWrapper python35 ncurses zlib llvm-or1k python35Packages.setuptools ]; installPhase = '' - LLVM_CONFIG=${llvm-or1k}/llvm_or1k/bin/llvm-config + LLVM_CONFIG=${llvm-or1k}/bin/llvm-config python3 setup.py install --prefix=$out ''; } From 477dcdbad4d05d4308b0a193efd06ad14bdd3a49 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 16 Aug 2018 09:39:21 +0800 Subject: [PATCH 1130/2457] nix: use latest python3 --- nix/artiq.nix | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/nix/artiq.nix b/nix/artiq.nix index b270c21ba..f029b0ce5 100644 --- a/nix/artiq.nix +++ b/nix/artiq.nix @@ -1,8 +1,8 @@ -{ stdenv, fetchFromGitHub, fetchsvn, python35Packages, qt5Full, llvm-or1k, llvmlite, python35}: +{ stdenv, fetchFromGitHub, fetchsvn, python3Packages, qt5Full, llvm-or1k, llvmlite, python3}: let -levenshtein = python35Packages.buildPythonPackage rec { +levenshtein = python3Packages.buildPythonPackage rec { name = "levenshtein"; src = fetchFromGitHub { owner = "ztane"; @@ -13,7 +13,7 @@ levenshtein = python35Packages.buildPythonPackage rec { doCheck = false; }; -pythonparser = python35Packages.buildPythonPackage rec { +pythonparser = python3Packages.buildPythonPackage rec { name = "pythonparser"; src = fetchFromGitHub { owner = "m-labs"; @@ -21,11 +21,11 @@ pythonparser = python35Packages.buildPythonPackage rec { rev = "8bdc7badbd08e2196b864e12889ea9191ca6e09c"; sha256 = "1f538wnjlqah0dsvq256k2rv7s7bffsvjcxy8fq0x3a4g0s6pm9d"; }; - buildInputs = with python35Packages; [ regex ]; + buildInputs = with python3Packages; [ regex ]; doCheck = false; }; -asyncserial = python35Packages.buildPythonPackage rec { +asyncserial = python3Packages.buildPythonPackage rec { name = "asyncserial"; src = fetchFromGitHub { owner = "m-labs"; @@ -33,11 +33,11 @@ asyncserial = python35Packages.buildPythonPackage rec { rev = "d95bc1d6c791b0e9785935d2f62f628eb5cdf98d"; sha256 = "0yzkka9jk3612v8gx748x6ziwykq5lr7zmr9wzkcls0v2yilqx9k"; }; - buildInputs = with python35Packages; [ pyserial ]; + buildInputs = with python3Packages; [ pyserial ]; doCheck = false; }; -outputcheck = python35Packages.buildPythonPackage rec { +outputcheck = python3Packages.buildPythonPackage rec { name = "outputcheck"; version = "0.4.2"; src = fetchFromGitHub { @@ -54,7 +54,7 @@ outputcheck = python35Packages.buildPythonPackage rec { doCheck = false; }; -quamash = python35Packages.buildPythonPackage rec { +quamash = python3Packages.buildPythonPackage rec { name = "quamash"; src = fetchFromGitHub { owner = "harvimt"; @@ -62,11 +62,11 @@ quamash = python35Packages.buildPythonPackage rec { rev = "bbab9e30e10b71a95687b03a93524173fb7b43f0"; sha256 = "08hp2q4ifj6z2ww05c7zsy0cd732k9rnaims1j43vr4hhxx950mk"; }; - buildInputs = with python35Packages; [ pyqt5 ]; + buildInputs = with python3Packages; [ pyqt5 ]; doCheck = false; }; -lit = python35Packages.buildPythonPackage rec { +lit = python3Packages.buildPythonPackage rec { name = "lit"; version = "262719"; source = fetchsvn { @@ -80,12 +80,12 @@ lit = python35Packages.buildPythonPackage rec { in -python35Packages.buildPythonPackage rec { +python3Packages.buildPythonPackage rec { version = "336482"; name = "artiq-${version}"; src = ./..; - buildInputs = with python35Packages; [ lit outputcheck ]; - propagatedBuildInputs = with python35Packages; [ llvm-or1k llvmlite levenshtein pyqtgraph aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; + buildInputs = with python3Packages; [ lit outputcheck ]; + propagatedBuildInputs = with python3Packages; [ llvm-or1k llvmlite levenshtein pyqtgraph aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; doCheck = false; meta = with stdenv.lib; { description = ""; From c3759379bd9140082c4013d7fe1003c8fba4216b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 16 Aug 2018 09:53:15 +0800 Subject: [PATCH 1131/2457] nix: upgrade pyqtgraph and switch it to Qt5 --- nix/artiq.nix | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/nix/artiq.nix b/nix/artiq.nix index f029b0ce5..49cedf765 100644 --- a/nix/artiq.nix +++ b/nix/artiq.nix @@ -66,6 +66,19 @@ quamash = python3Packages.buildPythonPackage rec { doCheck = false; }; +pyqtgraph-qt5 = python3Packages.buildPythonPackage rec { + name = "pyqtgraph_qt5-${version}"; + version = "0.10.0"; + doCheck = false; + src = fetchFromGitHub { + owner = "pyqtgraph"; + repo = "pyqtgraph"; + rev = "1426e334e1d20542400d77c72c132b04c6d17ddb"; + sha256 = "1079haxyr316jf0wpirxdj0ry6j8mr16cqr0dyyrd5cnxwl7zssh"; + }; + propagatedBuildInputs = with python3Packages; [ scipy numpy pyqt5 pyopengl ]; +}; + lit = python3Packages.buildPythonPackage rec { name = "lit"; version = "262719"; @@ -85,7 +98,7 @@ python3Packages.buildPythonPackage rec { name = "artiq-${version}"; src = ./..; buildInputs = with python3Packages; [ lit outputcheck ]; - propagatedBuildInputs = with python3Packages; [ llvm-or1k llvmlite levenshtein pyqtgraph aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; + propagatedBuildInputs = with python3Packages; [ llvm-or1k llvmlite levenshtein pyqtgraph-qt5 aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; doCheck = false; meta = with stdenv.lib; { description = ""; From 57bd3e4109d692b9f75bc97fdaa6516abba27c99 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 16 Aug 2018 10:01:48 +0800 Subject: [PATCH 1132/2457] nix: also use latest python3 for llvmlite --- nix/llvmlite.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix/llvmlite.nix b/nix/llvmlite.nix index 6f5d1516d..e03f408e8 100644 --- a/nix/llvmlite.nix +++ b/nix/llvmlite.nix @@ -1,4 +1,4 @@ -{ stdenv, fetchgit, llvm-or1k, makeWrapper, python35, ncurses, zlib, python35Packages }: +{ stdenv, fetchgit, llvm-or1k, makeWrapper, python3, ncurses, zlib, python3Packages }: let version = "0f4ebae"; in @@ -11,7 +11,7 @@ stdenv.mkDerivation rec { leaveDotGit = true; }; - buildInputs = [ makeWrapper python35 ncurses zlib llvm-or1k python35Packages.setuptools ]; + buildInputs = [ makeWrapper python3 ncurses zlib llvm-or1k python3Packages.setuptools ]; installPhase = '' LLVM_CONFIG=${llvm-or1k}/bin/llvm-config From ac9dcb74978d291e3f8c250adc7ce4e1bfdc3d49 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 16 Aug 2018 10:05:07 +0800 Subject: [PATCH 1133/2457] nix: fix and update binutils-or1k --- nix/binutils-or1k.nix | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/nix/binutils-or1k.nix b/nix/binutils-or1k.nix index 0ebdbcd24..f9fa99ad0 100644 --- a/nix/binutils-or1k.nix +++ b/nix/binutils-or1k.nix @@ -1,18 +1,21 @@ -{ stdenv -, fetchurl +{ stdenv, buildPackages +, fetchurl, zlib }: stdenv.mkDerivation rec { basename = "binutils"; platform = "or1k"; - version = "2.26"; + version = "2.30"; name = "${basename}_${platform}-${version}"; src = fetchurl { - url = "https://ftp.gnu.org/gnu/binutils/${basename}-${version}.tar.bz2"; - sha256 = "1ngc2h3knhiw8s22l8y6afycfaxr5grviqy7mwvm4bsl14cf9b62"; + url = "https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.bz2"; + sha256 = "028cklfqaab24glva1ks2aqa1zxa6w6xmc8q34zs1sb7h22dxspg"; }; configureFlags = [ "--enable-shared" "--enable-deterministic-archives" "--target=or1k-linux"]; + outputs = [ "out" "info" "man" ]; + depsBuildBuild = [ buildPackages.stdenv.cc ]; + buildInputs = [ zlib ]; enableParallelBuilding = true; meta = { description = "Tools for manipulating binaries (linker, assembler, etc.)"; @@ -29,4 +32,3 @@ stdenv.mkDerivation rec { priority = "10"; }; } - From 2e6c0b6a6d5a9ac2cc67ff4c5783333e151e5f9f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 16 Aug 2018 10:06:03 +0800 Subject: [PATCH 1134/2457] nix: propagate artiq subdependencies --- nix/artiq.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nix/artiq.nix b/nix/artiq.nix index 49cedf765..a21df0105 100644 --- a/nix/artiq.nix +++ b/nix/artiq.nix @@ -21,7 +21,7 @@ pythonparser = python3Packages.buildPythonPackage rec { rev = "8bdc7badbd08e2196b864e12889ea9191ca6e09c"; sha256 = "1f538wnjlqah0dsvq256k2rv7s7bffsvjcxy8fq0x3a4g0s6pm9d"; }; - buildInputs = with python3Packages; [ regex ]; + propagatedBuildInputs = with python3Packages; [ regex ]; doCheck = false; }; @@ -33,7 +33,7 @@ asyncserial = python3Packages.buildPythonPackage rec { rev = "d95bc1d6c791b0e9785935d2f62f628eb5cdf98d"; sha256 = "0yzkka9jk3612v8gx748x6ziwykq5lr7zmr9wzkcls0v2yilqx9k"; }; - buildInputs = with python3Packages; [ pyserial ]; + propagatedBuildInputs = with python3Packages; [ pyserial ]; doCheck = false; }; @@ -62,7 +62,7 @@ quamash = python3Packages.buildPythonPackage rec { rev = "bbab9e30e10b71a95687b03a93524173fb7b43f0"; sha256 = "08hp2q4ifj6z2ww05c7zsy0cd732k9rnaims1j43vr4hhxx950mk"; }; - buildInputs = with python3Packages; [ pyqt5 ]; + propagatedBuildInputs = with python3Packages; [ pyqt5 ]; doCheck = false; }; From 2c55f2ce4b2eeb6462534df6eaacbbde3f344740 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 16 Aug 2018 10:06:23 +0800 Subject: [PATCH 1135/2457] nix: install binutils-or1k --- nix/artiq.nix | 4 ++-- nix/default.nix | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nix/artiq.nix b/nix/artiq.nix index a21df0105..930389a4e 100644 --- a/nix/artiq.nix +++ b/nix/artiq.nix @@ -1,4 +1,4 @@ -{ stdenv, fetchFromGitHub, fetchsvn, python3Packages, qt5Full, llvm-or1k, llvmlite, python3}: +{ stdenv, fetchFromGitHub, fetchsvn, python3Packages, qt5Full, binutils-or1k, llvm-or1k, llvmlite, python3}: let @@ -98,7 +98,7 @@ python3Packages.buildPythonPackage rec { name = "artiq-${version}"; src = ./..; buildInputs = with python3Packages; [ lit outputcheck ]; - propagatedBuildInputs = with python3Packages; [ llvm-or1k llvmlite levenshtein pyqtgraph-qt5 aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; + propagatedBuildInputs = with python3Packages; [ binutils-or1k llvm-or1k llvmlite levenshtein pyqtgraph-qt5 aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; doCheck = false; meta = with stdenv.lib; { description = ""; diff --git a/nix/default.nix b/nix/default.nix index 3561ff763..b536227ba 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -4,7 +4,7 @@ let callPackage = pkgs.lib.callPackageWith (pkgs // self ); self = { - binutils-ork1 = callPackage ./binutils-or1k.nix {}; + binutils-or1k = callPackage ./binutils-or1k.nix {}; llvm-src = callPackage ./fetch-llvm-clang.nix {}; llvm-or1k = callPackage ./llvm-or1k.nix {}; llvmlite = callPackage ./llvmlite.nix {}; From 4155853482160da3c9a514b38c566ed7389c2c13 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 16 Aug 2018 13:03:55 +0800 Subject: [PATCH 1136/2457] nix: add Clang back --- nix/fetch-llvm-clang.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nix/fetch-llvm-clang.nix b/nix/fetch-llvm-clang.nix index d337eaa8e..686aef9a6 100644 --- a/nix/fetch-llvm-clang.nix +++ b/nix/fetch-llvm-clang.nix @@ -7,8 +7,16 @@ llvm-src = fetchFromGitHub { repo = "llvm-or1k"; sha256 = "0lmcg9xj66pf4mb6racipw67vm8kwm84dl861hyqnywd61kvhrwa"; }; +clang-src = fetchFromGitHub { + rev = "9e996136d52ed506ed8f57ef8b13b0f0f735e6a3"; + owner = "m-labs"; + repo = "clang-or1k"; + sha256 = "0w5f450i76y162aswi2c7jip8x3arzljaxhbqp8qfdffm0rdbjp4"; +}; in runCommand "llvm_or1k_src" {}'' mkdir -p $out +mkdir -p $out/tools/clang cp -r ${llvm-src}/* $out/ +cp -r ${clang-src}/* $out/tools/clang '' From 3d332ccc0bdc9769fbeee893412373c9568b0429 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 17 Aug 2018 12:19:16 +0800 Subject: [PATCH 1137/2457] nix: update README --- nix/README.rst | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/nix/README.rst b/nix/README.rst index c2d6df2eb..ce0e0931c 100644 --- a/nix/README.rst +++ b/nix/README.rst @@ -1,22 +1,28 @@ Install ARTIQ via the Nix Package Manager -=========================== +========================================= -Nix does not support windows. +These instructions provide an alternative route to install ARTIQ for people who do not wish to use conda. -* Install the nix package manager +This sets up an environment suitable for using ARTIQ, including the ARTIQ-Python compiler, device drivers, and the graphical user interfaces. This works correctly on Linux, and partially works with WSL introduced in Windows 10. - * many linux distros already have a package for the `nix package manager `_ +ARTIQ firmware and gateware development tools (e.g. rustc, Migen) and ARTIQ core device flashing tools (OpenOCD, proxy bitstreams) are currently not available on Nix. Pull requests welcome! - * for example: $ apt-get install nix +* Install the Nix package manager - * if you would like to install via sh (please be sure you `understand `_ the dangers involved when curl piping to sh. Also ensure you have read the contents of the script and feel comfortable executing it. Otherwise there is the `manual `_) + * many Linux distros already have a package for the `Nix package manager `_ - * $ curl https://nixos.org/nix/install | sh + * for example: ``$ apt-get install nix`` - * $ source ~/.nix-profile/etc/profile.d/nix.sh + * if you would like to install via sh -* $ git clone github.com/m-labs/artiq -* $ cd artiq/nix -* $ nix-env -i -f default.nix + * $ ``wget https://nixos.org/nix/install`` + + * $ ``sh install`` + + * $ ``source ~/.nix-profile/etc/profile.d/nix.sh`` + +* $ ``git clone github.com/m-labs/artiq`` +* $ ``cd artiq/nix`` +* $ ``nix-env -i -f default.nix`` The above command will setup your entire environment. From 233c841f2e9e65e4bf2f3d48d1ffe78a9801eef1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 17 Aug 2018 12:19:38 +0800 Subject: [PATCH 1138/2457] nix: remove bogus version string --- nix/artiq.nix | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/nix/artiq.nix b/nix/artiq.nix index 930389a4e..2b4b4c603 100644 --- a/nix/artiq.nix +++ b/nix/artiq.nix @@ -1,4 +1,4 @@ -{ stdenv, fetchFromGitHub, fetchsvn, python3Packages, qt5Full, binutils-or1k, llvm-or1k, llvmlite, python3}: +{ stdenv, fetchFromGitHub, fetchsvn, python3Packages, qt5Full, binutils-or1k, llvm-or1k, llvmlite, python3 }: let @@ -94,8 +94,7 @@ lit = python3Packages.buildPythonPackage rec { in python3Packages.buildPythonPackage rec { - version = "336482"; - name = "artiq-${version}"; + name = "artiq"; src = ./..; buildInputs = with python3Packages; [ lit outputcheck ]; propagatedBuildInputs = with python3Packages; [ binutils-or1k llvm-or1k llvmlite levenshtein pyqtgraph-qt5 aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; @@ -108,4 +107,3 @@ python3Packages.buildPythonPackage rec { platforms = [ "x86_64-linux" ]; }; } - From e978430c54dc1ec400d89ee2b26f53fcb6921075 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 17 Aug 2018 12:27:17 +0800 Subject: [PATCH 1139/2457] nix: add warnings to README --- nix/README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix/README.rst b/nix/README.rst index ce0e0931c..7df289bd4 100644 --- a/nix/README.rst +++ b/nix/README.rst @@ -3,7 +3,7 @@ Install ARTIQ via the Nix Package Manager These instructions provide an alternative route to install ARTIQ for people who do not wish to use conda. -This sets up an environment suitable for using ARTIQ, including the ARTIQ-Python compiler, device drivers, and the graphical user interfaces. This works correctly on Linux, and partially works with WSL introduced in Windows 10. +This sets up an environment suitable for using ARTIQ, including the ARTIQ-Python compiler, device drivers, and the graphical user interfaces. This works correctly on Linux, and partially works (but not to a level that we would consider usable) with WSL introduced in Windows 10. ARTIQ firmware and gateware development tools (e.g. rustc, Migen) and ARTIQ core device flashing tools (OpenOCD, proxy bitstreams) are currently not available on Nix. Pull requests welcome! @@ -25,4 +25,4 @@ ARTIQ firmware and gateware development tools (e.g. rustc, Migen) and ARTIQ core * $ ``cd artiq/nix`` * $ ``nix-env -i -f default.nix`` -The above command will setup your entire environment. +The above command will setup your entire environment. Note that it will compile LLVM and Clang, which uses a lot of CPU time and disk space. From 341437ea5007248c96e962396df3459d337711c0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 17 Aug 2018 13:20:56 +0800 Subject: [PATCH 1140/2457] nix: remove outputcheck and lit --- nix/artiq.nix | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/nix/artiq.nix b/nix/artiq.nix index 2b4b4c603..9f360e538 100644 --- a/nix/artiq.nix +++ b/nix/artiq.nix @@ -37,23 +37,6 @@ asyncserial = python3Packages.buildPythonPackage rec { doCheck = false; }; -outputcheck = python3Packages.buildPythonPackage rec { - name = "outputcheck"; - version = "0.4.2"; - src = fetchFromGitHub { - owner = "stp"; - repo = "OutputCheck"; - rev = "e0f533d3c5af2949349856c711bf4bca50022b48"; - sha256 = "1y27vz6jq6sywas07kz3v01sqjd0sga9yv9w2cksqac3v7wmf2a0"; - }; - prePatch = '' - substituteInPlace setup.py \ - --replace "version.get_git_version()" "\"${version}\"" \ - --replace "import version" "" - ''; - doCheck = false; -}; - quamash = python3Packages.buildPythonPackage rec { name = "quamash"; src = fetchFromGitHub { @@ -79,24 +62,11 @@ pyqtgraph-qt5 = python3Packages.buildPythonPackage rec { propagatedBuildInputs = with python3Packages; [ scipy numpy pyqt5 pyopengl ]; }; -lit = python3Packages.buildPythonPackage rec { - name = "lit"; - version = "262719"; - source = fetchsvn { - url = "http://llvm.org/svn/llvm-project/llvm/trunk/"; - rev = "${version}"; - sha256 = "1iashczfh30v9ark4xijk6z2q07c1kb70nar00mwnfix77gkb2v6"; - }; - src = source + /utils/lit; - doCheck = false; -}; - in python3Packages.buildPythonPackage rec { name = "artiq"; src = ./..; - buildInputs = with python3Packages; [ lit outputcheck ]; propagatedBuildInputs = with python3Packages; [ binutils-or1k llvm-or1k llvmlite levenshtein pyqtgraph-qt5 aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; doCheck = false; meta = with stdenv.lib; { From 1ba12e1cdbd28ccbdb25860e550724639d6dd9ea Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 17 Aug 2018 13:21:36 +0800 Subject: [PATCH 1141/2457] gui/log: print messages in tooltips This helps reading long messages in small log windows. --- artiq/gui/log.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/artiq/gui/log.py b/artiq/gui/log.py index a6d68cb3d..2b5d7185f 100644 --- a/artiq/gui/log.py +++ b/artiq/gui/log.py @@ -161,8 +161,13 @@ class _Model(QtCore.QAbstractItemModel): return v[3][item.row+1] elif role == QtCore.Qt.ToolTipRole: v = self.entries[msgnum] + if item.parent is self: + lineno = 0 + else: + lineno = item.row + 1 return (log_level_to_name(v[0]) + ", " + - time.strftime("%m/%d %H:%M:%S", time.localtime(v[2]))) + time.strftime("%m/%d %H:%M:%S", time.localtime(v[2])) + + "\n" + v[3][lineno]) class LogDock(QDockWidgetCloseDetect): From d707d2f4feb6cddc5d25d074cb08a7b7cc945599 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 17 Aug 2018 13:35:16 +0800 Subject: [PATCH 1142/2457] test: relax TTL timing requirements to support DIO EEM --- artiq/test/coredevice/test_analyzer.py | 3 ++- artiq/test/coredevice/test_rtio.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/artiq/test/coredevice/test_analyzer.py b/artiq/test/coredevice/test_analyzer.py index 0098e78dd..ea3c93fe2 100644 --- a/artiq/test/coredevice/test_analyzer.py +++ b/artiq/test/coredevice/test_analyzer.py @@ -59,9 +59,10 @@ class AnalyzerTest(ExperimentCase): input_messages = [msg for msg in dump.messages if isinstance(msg, InputMessage)] self.assertEqual(len(input_messages), 2) + # on Kasli systems, this has to go through the isolated DIO card self.assertAlmostEqual( abs(input_messages[0].timestamp - input_messages[1].timestamp), - 1000, delta=1) + 1000, delta=4) def test_rtio_log(self): core_host = self.device_mgr.get_desc("core")["arguments"]["host"] diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 7556302be..8fde4bcc4 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -379,8 +379,9 @@ class CoredeviceTest(ExperimentCase): self.execute(Loopback) rtt = self.dataset_mgr.get("rtt") print(rtt) - self.assertGreater(rtt, 0*ns) - self.assertLess(rtt, 140*ns) + self.assertGreater(rtt, 20*ns) + # on Kasli systems, this has to go through the isolated DIO card + self.assertLess(rtt, 170*ns) def test_clock_generator_loopback(self): self.execute(ClockGeneratorLoopback) From 66e33a66d673ebf38795fecb3df942638dc66f8d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 17 Aug 2018 13:35:55 +0800 Subject: [PATCH 1143/2457] test: enable TTL loopback tests on Kasli --- artiq/examples/kasli_tester/device_db.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/examples/kasli_tester/device_db.py b/artiq/examples/kasli_tester/device_db.py index 2af42ea07..f6cba7fea 100644 --- a/artiq/examples/kasli_tester/device_db.py +++ b/artiq/examples/kasli_tester/device_db.py @@ -189,4 +189,7 @@ device_db.update( device_db.update( ttl_out="ttl4", ttl_out_serdes="ttl4", + + loop_out="ttl4", + loop_in="ttl0", ) From 5c3e834c4d1c6bbede94c2a5bf7b993733edd438 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 17 Aug 2018 20:52:05 +0800 Subject: [PATCH 1144/2457] ad9154: retry DAC initialization on STPL or PRBS failure Works around #1127 --- artiq/firmware/libboard_artiq/ad9154.rs | 26 +++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index c210301fd..29e1a901e 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -653,12 +653,25 @@ fn dac_cfg(dacno: u8) -> Result<(), &'static str> { Ok(()) } -fn dac_cfg_retry(dacno: u8) -> Result<(), &'static str> { +fn dac_cfg_and_test(dacno: u8) -> Result<(), &'static str> { + dac_cfg(dacno)?; + dac_prbs(dacno)?; + dac_stpl(dacno, 4, 2)?; + dac_cfg(dacno)?; + Ok(()) +} + +/* + * work around for: + * https://github.com/m-labs/artiq/issues/727 + * https://github.com/m-labs/artiq/issues/1127 + */ +fn dac_cfg_and_test_retry(dacno: u8) -> Result<(), &'static str> { let mut attempt = 0; loop { attempt += 1; dac_reset(dacno); - let outcome = dac_cfg(dacno); + let outcome = dac_cfg_and_test(dacno); match outcome { Ok(_) => return outcome, Err(e) => { @@ -695,16 +708,9 @@ pub fn dac_sync(dacno: u8) -> Result { fn init_dac(dacno: u8) -> Result<(), &'static str> { let dacno = dacno as u8; - dac_reset(dacno); dac_detect(dacno)?; - dac_cfg_retry(dacno)?; - - dac_prbs(dacno)?; - dac_stpl(dacno, 4, 2)?; - - dac_cfg_retry(dacno)?; - + dac_cfg_and_test_retry(dacno)?; Ok(()) } From 041dc0f64a1c4ca65c165eac2c337fc2f11d2d18 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 17 Aug 2018 22:50:07 +0800 Subject: [PATCH 1145/2457] jesd204: update core to v0.10 Closes #727 Closes #1127 --- artiq/gateware/jesd204_tools.py | 11 +++++------ conda/artiq-dev/meta.yaml | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index 167a05f3a..cdba0f7f6 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -85,12 +85,11 @@ class UltrascaleTX(Module, AutoCSR): phy.transmitter.cd_tx.clk) phys.append(phy) - to_jesd = ClockDomainsRenamer("jesd") - self.submodules.core = core = to_jesd(JESD204BCoreTX( - phys, settings, converter_data_width=64)) - self.submodules.control = control = to_jesd(JESD204BCoreTXControl(core)) - core.register_jsync(platform.request("dac_sync", dac)) - core.register_jref(jesd_crg.jref) + self.submodules.core = JESD204BCoreTX( + phys, settings, converter_data_width=64) + self.submodules.control = JESD204BCoreTXControl(self.core) + self.core.register_jsync(platform.request("dac_sync", dac)) + self.core.register_jref(jesd_crg.jref) # This assumes: diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index e9f878df5..488e4f40d 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -16,7 +16,7 @@ requirements: - setuptools 33.1.1 - migen 0.7 py35_73+gitbef9dea - misoc 0.11 py35_29+git57ebe119 - - jesd204b 0.9 + - jesd204b 0.10 - microscope - binutils-or1k-linux >=2.27 - llvm-or1k 6.0.0 From 167e97efd20313a9cfad12bcf3ae2eec45f319fb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 17 Aug 2018 22:57:54 +0800 Subject: [PATCH 1146/2457] sayma: support external RTM clocking --- artiq/firmware/libboard_artiq/ad9154.rs | 5 ++-- artiq/firmware/libboard_artiq/hmc830_7043.rs | 13 ++++++++ artiq/firmware/runtime/main.rs | 2 +- artiq/firmware/satman/main.rs | 31 ++++++++++++++++---- artiq/gateware/targets/sayma_amc.py | 9 ++---- 5 files changed, 44 insertions(+), 16 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 29e1a901e..e9b7db5db 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -33,10 +33,9 @@ fn read(addr: u16) -> u8 { } } -pub fn jesd_unreset() { +pub fn jesd_reset(reset: bool) { unsafe { - csr::ad9154_crg::ibuf_disable_write(0); - csr::ad9154_crg::jreset_write(0); + csr::ad9154_crg::jreset_write(if reset { 1 } else { 0 }); } } diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 6d2787ad7..30bef71c9 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -367,6 +367,18 @@ pub mod hmc7043 { Ok(()) } + pub fn enable_fpga_ibuf() { + /* + * Never missing an opportunity to be awful, the HMC7043 produces broadband noise + * prior to intialization, which can upset the FPGA. + * One mitigation technique is to disable the input buffer until the HMC7043 is + * slightly better behaved. + */ + unsafe { + csr::ad9154_crg::ibuf_disable_write(0); + } + } + pub fn sysref_offset_dac(dacno: u8, phase_offset: u16) { /* Analog delay resolution: 25ps * Digital delay resolution: 1/2 input clock cycle = 416ps for 1.2GHz @@ -427,6 +439,7 @@ pub fn init() -> Result<(), &'static str> { hmc7043::init(); hmc7043::test_gpo()?; hmc7043::check_phased()?; + hmc7043::enable_fpga_ibuf(); Ok(()) } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 77e76cc09..c4c3f674a 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -111,7 +111,7 @@ fn startup() { board_artiq::hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] { - board_artiq::ad9154::jesd_unreset(); + board_artiq::ad9154::jesd_reset(false); board_artiq::ad9154::init(); if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { error!("failed to align SYSREF at FPGA: {}", e); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index b109ef96f..849901e88 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -273,11 +273,6 @@ pub extern fn main() -> i32 { csr::drtio_transceiver::stable_clkin_write(1); } - #[cfg(has_ad9154)] - { - board_artiq::ad9154::jesd_unreset(); - board_artiq::ad9154::init(); - } #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); @@ -285,12 +280,34 @@ pub extern fn main() -> i32 { while !drtio_link_rx_up() { process_errors(); } + info!("link is up, switching to recovered clock"); si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); si5324::siphaser::calibrate_skew(SIPHASER_PHASE).expect("failed to calibrate skew"); + + #[cfg(has_ad9154)] + { + /* + * One side of the JESD204 elastic buffer is clocked by the Si5324, the other + * by the RTM. + * The elastic buffer can operate only when those two clocks are derived from + * the same oscillator. + * This is the case when either of those conditions is true: + * (1) The DRTIO master and the RTM are clocked directly from a common external + * source, *and* the Si5324 has locked to the recovered clock. + * This clocking scheme provides less noise and phase drift at the DACs. + * (2) The RTM clock is connected to the Si5324 output. + * To handle those cases, we simply keep the JESD204 core in reset unless the + * Si5324 is locked to the recovered clock. + */ + board_artiq::ad9154::jesd_reset(false); + board_artiq::ad9154::init(); + } + drtioaux::reset(0); drtio_reset(false); drtio_reset_phy(false); + while drtio_link_rx_up() { process_errors(); process_aux_packets(); @@ -309,6 +326,10 @@ pub extern fn main() -> i32 { } } } + + #[cfg(has_ad9154)] + board_artiq::ad9154::jesd_reset(true); + drtio_reset_phy(true); drtio_reset(true); drtio_tsc_loaded(); diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 6e7872278..289363184 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -577,7 +577,7 @@ class Satellite(BaseSoC, RTMCommon): self.comb += platform.request("sfp_tx_disable", 0).eq(0) self.submodules.drtio_transceiver = gth_ultrascale.GTH( - clock_pads=self.ad9154_crg.refclk, + clock_pads=platform.request("si5324_clkout"), data_pads=[platform.request("sfp", 0)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) @@ -599,7 +599,7 @@ class Satellite(BaseSoC, RTMCommon): self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), - si5324_clkout_fabric=platform.request("adc_sysref")) + si5324_clkout_fabric=platform.request("si5324_clkout_fabric")) platform.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets {mmcm_ps}]", mmcm_ps=self.siphaser.mmcm_ps_output) platform.add_false_path_constraints( @@ -612,11 +612,6 @@ class Satellite(BaseSoC, RTMCommon): self.csr_devices.append("i2c") self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None - # ensure pins are properly biased and terminated - si5324_clkout = platform.request("si5324_clkout", 0) - self.specials += Instance( - "IBUFDS_GTE3", i_CEB=0, i_I=si5324_clkout.p, i_IB=si5324_clkout.n, - attr={("DONT_TOUCH", "true")}) self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( self.drtio0.coarse_ts, self.ad9154_crg.jref) From fc09144baa20a7438e70f8d95da49e84fac223aa Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 18 Aug 2018 10:46:08 +0800 Subject: [PATCH 1147/2457] artiq_coremgmt: remove unnecessary DeviceManager --- artiq/frontend/artiq_coremgmt.py | 105 +++++++++++++++---------------- 1 file changed, 50 insertions(+), 55 deletions(-) diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index 0e9553c9d..8a9dd6c27 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -5,7 +5,6 @@ import struct from artiq.tools import verbosity_args, init_logger from artiq.master.databases import DeviceDB -from artiq.master.worker_db import DeviceManager from artiq.coredevice.comm_kernel import CommKernel from artiq.coredevice.comm_mgmt import CommMgmt from artiq.coredevice.profiler import CallgrindWriter @@ -134,67 +133,63 @@ def main(): args = get_argparser().parse_args() init_logger(args) - device_mgr = DeviceManager(DeviceDB(args.device_db)) - try: - core_addr = DeviceDB(args.device_db).get("core")["arguments"]["host"] - mgmt = CommMgmt(core_addr) + core_addr = DeviceDB(args.device_db).get("core")["arguments"]["host"] + mgmt = CommMgmt(core_addr) - if args.tool == "log": - if args.action == "set_level": - mgmt.set_log_level(args.level) - if args.action == "set_uart_level": - mgmt.set_uart_log_level(args.level) - if args.action == "clear": - mgmt.clear_log() - if args.action == None: - print(mgmt.get_log(), end="") + if args.tool == "log": + if args.action == "set_level": + mgmt.set_log_level(args.level) + if args.action == "set_uart_level": + mgmt.set_uart_log_level(args.level) + if args.action == "clear": + mgmt.clear_log() + if args.action == None: + print(mgmt.get_log(), end="") - if args.tool == "config": - if args.action == "read": - value = mgmt.config_read(args.key) - if not value: - print("Key {} does not exist".format(args.key)) - else: - print(value) - if args.action == "write": - for key, value in args.string: - mgmt.config_write(key, value.encode("utf-8")) - for key, filename in args.file: - with open(filename, "rb") as fi: - mgmt.config_write(key, fi.read()) - if args.action == "remove": - for key in args.key: - mgmt.config_remove(key) - if args.action == "erase": - mgmt.config_erase() + if args.tool == "config": + if args.action == "read": + value = mgmt.config_read(args.key) + if not value: + print("Key {} does not exist".format(args.key)) + else: + print(value) + if args.action == "write": + for key, value in args.string: + mgmt.config_write(key, value.encode("utf-8")) + for key, filename in args.file: + with open(filename, "rb") as fi: + mgmt.config_write(key, fi.read()) + if args.action == "remove": + for key in args.key: + mgmt.config_remove(key) + if args.action == "erase": + mgmt.config_erase() - if args.tool == "reboot": - mgmt.reboot() + if args.tool == "reboot": + mgmt.reboot() - if args.tool == "hotswap": - mgmt.hotswap(args.image.read()) + if args.tool == "hotswap": + mgmt.hotswap(args.image.read()) - if args.tool == "profile": - if args.action == "start": - mgmt.start_profiler(args.interval, args.hits_size, args.edges_size) - elif args.action == "stop": - mgmt.stop_profiler() - elif args.action == "save": - hits, edges = mgmt.get_profile() - writer = CallgrindWriter(args.output, args.firmware, "or1k-linux", - args.compression, args.demangle) - writer.header() - for addr, count in hits.items(): - writer.hit(addr, count) - for (caller, callee), count in edges.items(): - writer.edge(caller, callee, count) + if args.tool == "profile": + if args.action == "start": + mgmt.start_profiler(args.interval, args.hits_size, args.edges_size) + elif args.action == "stop": + mgmt.stop_profiler() + elif args.action == "save": + hits, edges = mgmt.get_profile() + writer = CallgrindWriter(args.output, args.firmware, "or1k-linux", + args.compression, args.demangle) + writer.header() + for addr, count in hits.items(): + writer.hit(addr, count) + for (caller, callee), count in edges.items(): + writer.edge(caller, callee, count) - if args.tool == "debug": - if args.action == "allocator": - mgmt.debug_allocator() + if args.tool == "debug": + if args.action == "allocator": + mgmt.debug_allocator() - finally: - device_mgr.close_devices() if __name__ == "__main__": main() From a7810502f6c2064a982bb14f07934ac383f3f875 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 18 Aug 2018 10:58:40 +0800 Subject: [PATCH 1148/2457] artiq_coremgmt: add option to specify core device address directly --- artiq/frontend/artiq_coremgmt.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index 8a9dd6c27..11b75628d 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -17,6 +17,9 @@ def get_argparser(): verbosity_args(parser) parser.add_argument("--device-db", default="device_db.py", help="device database file (default: '%(default)s')") + parser.add_argument("-D", "--device", default=None, + help="use specified core device address instead of " + "reading device database") tools = parser.add_subparsers(dest="tool") tools.required = True @@ -133,7 +136,10 @@ def main(): args = get_argparser().parse_args() init_logger(args) - core_addr = DeviceDB(args.device_db).get("core")["arguments"]["host"] + if args.device is None: + core_addr = DeviceDB(args.device_db).get("core")["arguments"]["host"] + else: + core_addr = args.device mgmt = CommMgmt(core_addr) if args.tool == "log": From c498b28f88889f9cc428d1806779a8714d7d689a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 18 Aug 2018 11:42:57 +0800 Subject: [PATCH 1149/2457] hmc7043: disable FPGA_ADC_SYSREF --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 30bef71c9..80b05fc4c 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -174,7 +174,7 @@ pub mod hmc7043 { (true, FPGA_CLK_DIV, 0x08), // 8: GTP_CLK1 (false, 0, 0x10), // 9: AMC_MASTER_AUX_CLK (false, 0, 0x10), // 10: RTM_MASTER_AUX_CLK - (true, FPGA_CLK_DIV, 0x10), // 11: FPGA_ADC_SYSREF, LVDS -- repurposed for siphaser + (false, 0, 0x10), // 11: FPGA_ADC_SYSREF, LVDS (false, 0, 0x08), // 12: ADC1_CLK (false, 0, 0x08), // 13: ADC1_SYSREF ]; From f75a317446ac8856e30d4d86b7fd5ccc30e4c089 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 18 Aug 2018 11:43:23 +0800 Subject: [PATCH 1150/2457] hmc7043: automatically determine output groups --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 80b05fc4c..afa9c1c2a 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -287,11 +287,15 @@ pub mod hmc7043 { write(0xA0, 0xdf); // Unexplained high-performance mode // Enable required output groups - write(0x4, (1 << 0) | - (1 << 1) | - (1 << 3) | - (1 << 4) | - (1 << 5)); + let mut output_group_en = 0; + for channel in 0..OUTPUT_CONFIG.len() { + let enabled = OUTPUT_CONFIG[channel].0; + if enabled { + let group = channel/2; + output_group_en |= 1 << group; + } + } + write(0x4, output_group_en); write(0x5c, (HMC_SYSREF_DIV & 0xff) as u8); // Set SYSREF timer divider write(0x5d, ((HMC_SYSREF_DIV & 0x0f) >> 8) as u8); From d1d26e2aa3ce9e81fd1cf48c9aef6c601e492ba9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 18 Aug 2018 11:43:40 +0800 Subject: [PATCH 1151/2457] hmc7043: add explanation about HMC_SYSREF_DIV --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index afa9c1c2a..2b381e60d 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -297,7 +297,9 @@ pub mod hmc7043 { } write(0x4, output_group_en); - write(0x5c, (HMC_SYSREF_DIV & 0xff) as u8); // Set SYSREF timer divider + // Set SYSREF timer divider. + // We don't need this "feature", but the HMC7043 won't work without. + write(0x5c, (HMC_SYSREF_DIV & 0xff) as u8); write(0x5d, ((HMC_SYSREF_DIV & 0x0f) >> 8) as u8); for channel in 0..OUTPUT_CONFIG.len() { From d6992f6a0c83f1930197d0ab6fbb3b538bb4d231 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 18 Aug 2018 23:15:59 +0800 Subject: [PATCH 1152/2457] conda: work around 'received dictionary as spec' conda bug --- conda/artiq-board/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-board/meta.yaml b/conda/artiq-board/meta.yaml index b9d82be0b..fc9aa04ad 100644 --- a/conda/artiq-board/meta.yaml +++ b/conda/artiq-board/meta.yaml @@ -26,7 +26,7 @@ outputs: requirements: build: - - artiq-dev {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} + - artiq-dev {{ "{tag} {number}+git{hash}".format(tag=environ.get("GIT_DESCRIBE_TAG", "condabug"), number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} about: home: https://m-labs.hk/artiq From 9b6ea47b7a0773ac9244218a205c114cc7896851 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 19 Aug 2018 13:04:41 +0800 Subject: [PATCH 1153/2457] kasli: use SFP LEDs to show DRTIO link status. Closes #1073 --- artiq/examples/kasli_sawgmaster/device_db.py | 14 +++++++------- artiq/gateware/targets/kasli.py | 18 +++++++----------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/artiq/examples/kasli_sawgmaster/device_db.py b/artiq/examples/kasli_sawgmaster/device_db.py index fe60a48d6..6d3f9d7ec 100644 --- a/artiq/examples/kasli_sawgmaster/device_db.py +++ b/artiq/examples/kasli_sawgmaster/device_db.py @@ -30,7 +30,7 @@ for i in range(8): "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLInOut" if i < 4 else "TTLOut", - "arguments": {"channel": 3+i}, + "arguments": {"channel": 1+i}, } device_db.update( @@ -38,37 +38,37 @@ device_db.update( "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 11} + "arguments": {"channel": 9} }, ttl_urukul0_io_update={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 12} + "arguments": {"channel": 10} }, ttl_urukul0_sw0={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 13} + "arguments": {"channel": 11} }, ttl_urukul0_sw1={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 14} + "arguments": {"channel": 12} }, ttl_urukul0_sw2={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 15} + "arguments": {"channel": 13} }, ttl_urukul0_sw3={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 16} + "arguments": {"channel": 14} }, urukul0_cpld={ "type": "local", diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 883997f9f..f3e400da2 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -649,8 +649,8 @@ class _MasterBase(MiniSoC, AMPSoC): self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - self.sfp_ctl = [platform.request("sfp_ctl", i) for i in range(1, 3)] - self.comb += [sc.tx_disable.eq(0) for sc in self.sfp_ctl] + sfp_ctls = [platform.request("sfp_ctl", i) for i in range(1, 3)] + self.comb += [sc.tx_disable.eq(0) for sc in sfp_ctls] self.submodules.drtio_transceiver = gtp_7series.GTP( qpll_channel=self.drtio_qpll_channel, data_pads=[platform.request("sfp", i) for i in range(1, 3)], @@ -659,6 +659,8 @@ class _MasterBase(MiniSoC, AMPSoC): self.csr_devices.append("drtio_transceiver") self.sync += self.disable_si5324_ibuf.eq( ~self.drtio_transceiver.stable_clkin.storage) + self.comb += [sfp_ctl.led.eq(channel.rx_ready) + for sfp_ctl, channel in zip(sfp_ctls, self.drtio_transceiver.channels)] drtio_csr_group = [] drtio_memory_group = [] @@ -785,7 +787,8 @@ class _SatelliteBase(BaseSoC): qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings) self.submodules += qpll - self.comb += platform.request("sfp_ctl", 0).tx_disable.eq(0) + sfp_ctl = platform.request("sfp_ctl", 0) + self.comb += sfp_ctl.tx_disable.eq(0) self.submodules.drtio_transceiver = gtp_7series.GTP( qpll_channel=qpll.channels[0], data_pads=[platform.request("sfp", 0)], @@ -794,6 +797,7 @@ class _SatelliteBase(BaseSoC): self.csr_devices.append("drtio_transceiver") self.sync += disable_si5324_ibuf.eq( ~self.drtio_transceiver.stable_clkin.storage) + self.comb += sfp_ctl.led.eq(self.drtio_transceiver.channels[0].rx_ready) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( @@ -848,10 +852,6 @@ class Master(_MasterBase): phy = ttl_simple.Output(self.platform.request("user_led", 0)) self.submodules += phy self.rtio_channels.append(rtio.Channel.from_phy(phy)) - for sc in self.sfp_ctl: - phy = ttl_simple.Output(sc.led) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) # matches Tester EEM numbers eem.DIO.add_std(self, 5, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) @@ -872,10 +872,6 @@ class Satellite(_SatelliteBase): phy = ttl_simple.Output(self.platform.request("user_led", 0)) self.submodules += phy self.rtio_channels.append(rtio.Channel.from_phy(phy)) - for i in range(1, 3): - phy = ttl_simple.Output(self.platform.request("sfp_ctl", i).led) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) # matches Tester EEM numbers eem.DIO.add_std(self, 5, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) From 23ea8c81f3320a9fad3ca178ef79c9e6b57acb75 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 19 Aug 2018 21:18:40 +0800 Subject: [PATCH 1154/2457] nix: update pythonparser --- nix/artiq.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix/artiq.nix b/nix/artiq.nix index 9f360e538..c959c8a17 100644 --- a/nix/artiq.nix +++ b/nix/artiq.nix @@ -18,8 +18,8 @@ pythonparser = python3Packages.buildPythonPackage rec { src = fetchFromGitHub { owner = "m-labs"; repo = "pythonparser"; - rev = "8bdc7badbd08e2196b864e12889ea9191ca6e09c"; - sha256 = "1f538wnjlqah0dsvq256k2rv7s7bffsvjcxy8fq0x3a4g0s6pm9d"; + rev = "5b391fe86f43bb9f4f96c5bc0532e2a112db2936"; + sha256 = "1gw1fk4y2l6bwq0fg2a9dfc1rvq8cv492dyil96amjdhsxvnx35b"; }; propagatedBuildInputs = with python3Packages; [ regex ]; doCheck = false; From 0e7419450ec926227cc577f1b8b322ad9686f42c Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 20 Aug 2018 00:26:31 +0000 Subject: [PATCH 1155/2457] firmware: update smoltcp. This adds TCP window scaling support. --- artiq/firmware/Cargo.lock | 10 +++++----- artiq/firmware/bootloader/Cargo.toml | 2 +- artiq/firmware/libboard_misoc/Cargo.toml | 2 +- artiq/firmware/runtime/Cargo.toml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 885310773..de1abb72b 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -31,7 +31,7 @@ dependencies = [ "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=2139686)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=92e970b)", ] [[package]] @@ -42,7 +42,7 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=2139686)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=92e970b)", ] [[package]] @@ -216,7 +216,7 @@ dependencies = [ "logger_artiq 0.0.0", "managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "proto_artiq 0.0.0", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=2139686)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=92e970b)", "unwind_backtrace 0.0.0", ] @@ -233,7 +233,7 @@ dependencies = [ [[package]] name = "smoltcp" version = "0.4.0" -source = "git+https://github.com/m-labs/smoltcp?rev=2139686#21396867114d267da06f19cc54cc4a1883b900a5" +source = "git+https://github.com/m-labs/smoltcp?rev=92e970b#92e970b3798737cfaa2a829d3f1bb7a7353696ee" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -294,7 +294,7 @@ version = "0.0.0" "checksum log_buffer 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f033173c9486b7fe97a79c895c0a3483ae395ab6744c985d10078950e2492419" "checksum managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba6713e624266d7600e9feae51b1926c6a6a6bebb18ec5a8e11a5f1d5661baba" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=2139686)" = "" +"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=92e970b)" = "" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml index 5ab62863a..be9ab36e9 100644 --- a/artiq/firmware/bootloader/Cargo.toml +++ b/artiq/firmware/bootloader/Cargo.toml @@ -19,6 +19,6 @@ board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "2139686" +rev = "92e970b" default-features = false features = ["proto-ipv4", "socket-tcp"] diff --git a/artiq/firmware/libboard_misoc/Cargo.toml b/artiq/firmware/libboard_misoc/Cargo.toml index 1efd23a4e..aae40b6b1 100644 --- a/artiq/firmware/libboard_misoc/Cargo.toml +++ b/artiq/firmware/libboard_misoc/Cargo.toml @@ -18,7 +18,7 @@ log = { version = "0.4", default-features = false, optional = true } [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "2139686" # NB: also change in runtime/Cargo.toml +rev = "92e970b" # NB: also change in runtime/Cargo.toml default-features = false optional = true diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 8be210b35..1a7da3375 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -36,6 +36,6 @@ features = ["alloc"] [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "2139686" # NB: also change in libboard_misoc/Cargo.toml +rev = "92e970b" # NB: also change in libboard_misoc/Cargo.toml default-features = false features = ["rust-1.28", "alloc", "log", "proto-ipv4", "socket-tcp"] From 7f523e7e50e3b52086cf6f5e4eda8aa7f2aa2840 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 24 Aug 2018 19:03:25 +0800 Subject: [PATCH 1156/2457] nix: add shell starter --- nix/shell.nix | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 nix/shell.nix diff --git a/nix/shell.nix b/nix/shell.nix new file mode 100644 index 000000000..8fbdadb65 --- /dev/null +++ b/nix/shell.nix @@ -0,0 +1,8 @@ +{system ? builtins.currentSystem}: +let + pkgs = import {inherit system;}; + artiq = pkgs.callPackage ./default.nix {}; +in +pkgs.mkShell { + buildInputs = [ artiq ]; +} From ea71a0491bf91a415ef4aa1cbabc479cd419d9ad Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Aug 2018 13:37:46 +0800 Subject: [PATCH 1157/2457] conda: bump misoc. Closes #1057 --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 488e4f40d..5507adb1b 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.7 py35_73+gitbef9dea - - misoc 0.11 py35_29+git57ebe119 + - misoc 0.11 py35_31+git5ce139dd - jesd204b 0.10 - microscope - binutils-or1k-linux >=2.27 From ba6094c3e5807366f390ff5eba8838d2b1b24587 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Aug 2018 16:47:48 +0800 Subject: [PATCH 1158/2457] test: relax network transfer rates Due to lower Kasli system clock frequency. --- artiq/test/coredevice/test_performance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index 9d423714d..35723f79d 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -44,7 +44,7 @@ class TransferTest(ExperimentCase): exp = self.create(_Transfer) host_to_device_rate = exp.host_to_device() print(host_to_device_rate, "B/s") - self.assertGreater(host_to_device_rate, 2.1e6) + self.assertGreater(host_to_device_rate, 2.0e6) @unittest.skipUnless(artiq_low_latency, "timings are dependent on CPU load and network conditions") @@ -52,7 +52,7 @@ class TransferTest(ExperimentCase): exp = self.create(_Transfer) device_to_host_rate = exp.device_to_host() print(device_to_host_rate, "B/s") - self.assertGreater(device_to_host_rate, 2.4e6) + self.assertGreater(device_to_host_rate, 2.3e6) class _KernelOverhead(EnvExperiment): From a5cd7d27612fb21c04c7f3b14d9deb0bd05e20d9 Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 28 Aug 2018 20:00:32 +0000 Subject: [PATCH 1159/2457] doc: update manual/developing.rst. --- doc/manual/developing.rst | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index 39eaa4602..5d1edc998 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -95,9 +95,9 @@ and the ARTIQ kernels. * Install LLVM and Clang: :: $ cd ~/artiq-dev - $ git clone -b artiq-4.0 https://github.com/m-labs/llvm-or1k + $ git clone -b artiq-6.0 https://github.com/m-labs/llvm-or1k $ cd llvm-or1k - $ git clone -b artiq-4.0 https://github.com/m-labs/clang-or1k tools/clang + $ git clone -b artiq-6.0 https://github.com/m-labs/clang-or1k tools/clang $ mkdir build $ cd build @@ -108,7 +108,7 @@ and the ARTIQ kernels. * Install Rust: :: $ cd ~/artiq-dev - $ git clone -b artiq-1.23.0 https://github.com/m-labs/rust + $ git clone -b artiq-1.28.0 https://github.com/m-labs/rust $ cd rust $ git submodule update --init --recursive $ mkdir build @@ -118,18 +118,18 @@ and the ARTIQ kernels. $ sudo chown $USER.$USER /usr/local/rust-or1k $ make install - $ libs="core std_unicode alloc" - $ rustc="/usr/local/rust-or1k/bin/rustc --target or1k-unknown-none -C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s -g --crate-type rlib -L ." $ destdir="/usr/local/rust-or1k/lib/rustlib/or1k-unknown-none/lib/" - $ mkdir ../build-or1k - $ cd ../build-or1k - $ for lib in ${libs}; do ${rustc} --crate-name ${lib} ../src/lib${lib}/lib.rs; done - $ ${rustc} --crate-name libc ../src/liblibc_mini/lib.rs - $ ${rustc} --crate-name unwind ../src/libunwind/lib.rs - $ ${rustc} -Cpanic=abort --crate-name panic_abort ../src/libpanic_abort/lib.rs - $ ${rustc} -Cpanic=unwind --crate-name panic_unwind ../src/libpanic_unwind/lib.rs --cfg llvm_libunwind + $ rustc="rustc --out-dir ${destdir} -L ${destdir} --target or1k-unknown-none -g -C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s --crate-type rlib" $ mkdir -p ${destdir} - $ cp *.rlib ${destdir} + $ ${rustc} --crate-name core src/libcore/lib.rs + $ ${rustc} --crate-name compiler_builtins src/libcompiler_builtins/src/lib.rs --cfg $ 'feature="compiler-builtins"' --cfg 'feature="mem"' + $ ${rustc} --crate-name std_unicode src/libstd_unicode/lib.rs + $ ${rustc} --crate-name alloc src/liballoc/lib.rs + $ ${rustc} --crate-name libc src/liblibc_mini/lib.rs + $ ${rustc} --crate-name unwind src/libunwind/lib.rs + $ ${rustc} -Cpanic=abort --crate-name panic_abort src/libpanic_abort/lib.rs + $ ${rustc} -Cpanic=unwind --crate-name panic_unwind src/libpanic_unwind/lib.rs \ + --cfg llvm_libunwind .. note:: Compilation of LLVM can take more than 30 min on some machines. Compilation of Rust can take more than two hours. From aa64e6c1c6ad2b43988b2988649daadc36de42ed Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 29 Aug 2018 15:16:43 +0800 Subject: [PATCH 1160/2457] cri: add buffer space request protocol --- artiq/gateware/drtio/rt_packet_satellite.py | 14 ++++++++++---- artiq/gateware/rtio/cri.py | 13 +++++++++---- artiq/gateware/rtio/sed/core.py | 5 ++++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 02a5a98b1..ef0de8335 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -113,7 +113,7 @@ class RTPacketSatellite(Module): rx_plm.types["echo_request"]: echo_req.eq(1), rx_plm.types["set_time"]: NextState("SET_TIME"), rx_plm.types["write"]: NextState("WRITE"), - rx_plm.types["buffer_space_request"]: NextState("BUFFER_SPACE"), + rx_plm.types["buffer_space_request"]: NextState("BUFFER_SPACE_REQUEST"), rx_plm.types["read_request"]: NextState("READ_REQUEST"), "default": self.unknown_packet_type.eq(1) }) @@ -142,10 +142,16 @@ class RTPacketSatellite(Module): ) ) ) + rx_fsm.act("BUFFER_SPACE_REQUEST", + self.cri.cmd.eq(cri.commands["get_buffer_space"]), + NextState("BUFFER_SPACE") + ) rx_fsm.act("BUFFER_SPACE", - buffer_space_set.eq(1), - buffer_space_update.eq(1), - NextState("INPUT") + If(self.cri.o_buffer_space_valid, + buffer_space_set.eq(1), + buffer_space_update.eq(1), + NextState("INPUT") + ) ) rx_fsm.act("READ_REQUEST", diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 2a871f736..4a889bc27 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -13,11 +13,13 @@ from misoc.interconnect.csr import * commands = { "nop": 0, - "write": 1, # i_status should have the "wait for status" bit set until # an event is available, or timestamp is reached. - "read": 2 + "read": 2, + # targets must assert o_buffer_space_valid in response + # to this command + "get_buffer_space": 3 } @@ -32,8 +34,11 @@ layout = [ # o_status bits: # <0:wait> <1:underflow> <2:link error> ("o_status", 3, DIR_S_TO_M), - # targets may optionally report a pessimistic estimate of the number - # of outputs events that can be written without waiting. + + # pessimistic estimate of the number of outputs events that can be + # written without waiting. + # this feature may be omitted on systems without DRTIO. + ("o_buffer_space_valid", 1, DIR_S_TO_M), ("o_buffer_space", 16, DIR_S_TO_M), ("i_data", 32, DIR_S_TO_M), diff --git a/artiq/gateware/rtio/sed/core.py b/artiq/gateware/rtio/sed/core.py index ca757e976..7d0b0de4e 100644 --- a/artiq/gateware/rtio/sed/core.py +++ b/artiq/gateware/rtio/sed/core.py @@ -55,7 +55,10 @@ class SED(Module): self.comb += i.eq(o) if report_buffer_space: - self.comb += self.cri.o_buffer_space.eq(self.fifos.buffer_space) + self.comb += [ + self.cri.o_buffer_space_valid.eq(1), + self.cri.o_buffer_space.eq(self.fifos.buffer_space) + ] @property def cri(self): From ccc58a0f847eda935330aab6d93d62597f311a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 29 Aug 2018 15:37:37 +0000 Subject: [PATCH 1161/2457] satman: add 125 MHz Si5324 settings from cjbe --- artiq/firmware/satman/main.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 849901e88..ad2252955 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -242,6 +242,19 @@ const SI5324_SETTINGS: si5324::FrequencySettings crystal_ref: true }; +#[cfg(rtio_frequency = "125.0")] +const SI5324_SETTINGS: si5324::FrequencySettings + = si5324::FrequencySettings { + n1_hs : 5, + nc1_ls : 8, + n2_hs : 7, + n2_ls : 360, + n31 : 63, + n32 : 63, + bwsel : 4, + crystal_ref: true +}; + fn drtio_link_rx_up() -> bool { unsafe { (csr::DRTIO[0].rx_up_read)() == 1 From eb9e9634df60095387ab576294b5704ffbeae2ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 29 Aug 2018 16:16:37 +0000 Subject: [PATCH 1162/2457] siphaser: support 125 MHz rtio clk keep the phase shift increment/decrement at 1/(56*8) rtio_clk cycles --- artiq/gateware/drtio/siphaser.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/drtio/siphaser.py b/artiq/gateware/drtio/siphaser.py index aa2cbb05f..adbf72749 100644 --- a/artiq/gateware/drtio/siphaser.py +++ b/artiq/gateware/drtio/siphaser.py @@ -4,17 +4,20 @@ from migen.genlib.cdc import MultiReg from misoc.interconnect.csr import * -# This code assumes 125/62.5MHz reference clock and 150MHz RTIO frequency. +# This code assumes 125/62.5MHz reference clock and 125MHz or 150MHz RTIO +# frequency. class SiPhaser7Series(Module, AutoCSR): def __init__(self, si5324_clkin, si5324_clkout_fabric, - ref_clk=None, ref_div2=False): + ref_clk=None, ref_div2=False, rtio_clk_freq=150e6): self.switch_clocks = CSRStorage() self.phase_shift = CSR() self.phase_shift_done = CSRStatus(reset=1) self.sample_result = CSRStatus() - # 125MHz/62.5MHz reference clock to 150MHz. VCO @ 750MHz. + assert rtio_clk_freq in (125e6, 150e6) + + # 125MHz/62.5MHz reference clock to 125MHz/150MHz. VCO @ 750MHz. # Used to provide a startup clock to the transceiver through the Si, # we do not use the crystal reference so that the PFD (f3) frequency # can be high. @@ -31,18 +34,20 @@ class SiPhaser7Series(Module, AutoCSR): o_CLKFBOUT=mmcm_freerun_fb, i_CLKFBIN=mmcm_freerun_fb, - p_CLKOUT0_DIVIDE_F=5.0, o_CLKOUT0=mmcm_freerun_output, + p_CLKOUT0_DIVIDE_F=750e6/rtio_clk_freq, + o_CLKOUT0=mmcm_freerun_output, ) - - # 150MHz to 150MHz with controllable phase shift, VCO @ 1200MHz. - # Inserted between CDR and output to Si, used to correct + + # 125MHz/150MHz to 125MHz/150MHz with controllable phase shift, + # VCO @ 1000MHz/1200MHz. + # Inserted between CDR and output to Si, used to correct # non-determinstic skew of Si5324. mmcm_ps_fb = Signal() mmcm_ps_output = Signal() mmcm_ps_psdone = Signal() self.specials += \ Instance("MMCME2_ADV", - p_CLKIN1_PERIOD=1e9/150e6, + p_CLKIN1_PERIOD=1e9/rtio_clk_freq, i_CLKIN1=ClockSignal("rtio_rx0"), i_RST=ResetSignal("rtio_rx0"), i_CLKINSEL=1, # yes, 1=CLKIN1 0=CLKIN2 @@ -86,7 +91,7 @@ class SiPhaser7Series(Module, AutoCSR): p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE", i_I=si5324_clkout_fabric.p, i_IB=si5324_clkout_fabric.n, o_O=si5324_clkout_se), - + clkout_sample1 = Signal() # IOB register self.sync.rtio_rx0 += clkout_sample1.eq(si5324_clkout_se) self.specials += MultiReg(clkout_sample1, self.sample_result.status) From 9584c30a1f327574fc1da1cf4032700d260cf055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 29 Aug 2018 16:20:44 +0000 Subject: [PATCH 1163/2457] kasli: DRTIO Base: flexible rtio_clk_freq --- artiq/gateware/targets/kasli.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index f3e400da2..744bb983b 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -626,7 +626,7 @@ class _MasterBase(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, **kwargs): + def __init__(self, rtio_clk_freq=150e6, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -638,7 +638,6 @@ class _MasterBase(MiniSoC, AMPSoC): add_identifier(self) platform = self.platform - rtio_clk_freq = 150e6 i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) @@ -760,7 +759,7 @@ class _SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, **kwargs): + def __init__(self, rtio_clk_freq=150e6, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -769,7 +768,6 @@ class _SatelliteBase(BaseSoC): add_identifier(self) platform = self.platform - rtio_clk_freq = 150e6 disable_si5324_ibuf = Signal(reset=1) disable_si5324_ibuf.attr.add("no_retiming") @@ -803,7 +801,8 @@ class _SatelliteBase(BaseSoC): self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), si5324_clkout_fabric=platform.request("si5324_clkout_fabric"), - ref_clk=self.crg.clk125_div2, ref_div2=True) + ref_clk=self.crg.clk125_div2, ref_div2=True, + rtio_clk_freq=rtio_clk_freq) platform.add_false_path_constraints( self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) self.csr_devices.append("siphaser") From fbf05db5abed2dee6502a3b35b5c00894a6850df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 29 Aug 2018 16:22:00 +0000 Subject: [PATCH 1164/2457] kasli: add VLBAI Master and Satellite --- artiq/gateware/targets/kasli.py | 58 ++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 744bb983b..d6d7296ea 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -878,6 +878,62 @@ class Satellite(_SatelliteBase): self.add_rtio(self.rtio_channels) +class VLBAIMaster(_MasterBase): + def __init__(self, hw_rev=None, *args, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _MasterBase.__init__(self, rtio_clk_freq=125e6, hw_rev=hw_rev, *args, + **kwargs) + + self.rtio_channels = [] + eem.DIO.add_std(self, 0, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 1, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 2, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 5, 4, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) + + phy = ttl_simple.Output(self.platform.request("user_led", 0)) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(self.rtio_channels) + + +class VLBAISatellite(_SatelliteBase): + def __init__(self, hw_rev=None, *args, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _SatelliteBase.__init__(self, rtio_clk_freq=125e6, hw_rev=hw_rev, + *args, **kwargs) + + self.rtio_channels = [] + eem.DIO.add_std(self, 0, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 1, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 2, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 5, 4, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) + + phy = ttl_simple.Output(self.platform.request("user_led", 0)) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.add_rtio(self.rtio_channels) + + def main(): parser = argparse.ArgumentParser( description="ARTIQ device binary builder for Kasli systems") @@ -886,7 +942,7 @@ def main(): parser.set_defaults(output_dir="artiq_kasli") variants = {cls.__name__.lower(): cls for cls in [ Opticlock, SUServo, SYSU, MITLL, USTC, Tsinghua, WIPM, PTB, HUB, LUH, - Tester, Master, Satellite]} + VLBAIMaster, VLBAISatellite, Tester, Master, Satellite]} parser.add_argument("-V", "--variant", default="opticlock", help="variant: {} (default: %(default)s)".format( "/".join(sorted(variants.keys())))) From b58ec2d78e2dc59e4042d404a15a70c767fa9c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 29 Aug 2018 17:33:05 +0000 Subject: [PATCH 1165/2457] artiq_flash: treat all variants ending in `satellite` as such --- artiq/frontend/artiq_flash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index b8b2754bb..efcb06168 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -344,7 +344,7 @@ def main(): storage_img = args.storage programmer.write_binary(*config["storage"], storage_img) elif action == "firmware": - if variant == "satellite": + if variant.endswith("satellite"): firmware = "satman" else: firmware = "runtime" From e7dba344759c0d72f163d59843e44a61eb9dc0fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 29 Aug 2018 16:19:31 +0000 Subject: [PATCH 1166/2457] kasli/tester: fill all 12 EEM --- artiq/examples/kasli_tester/device_db.py | 140 ++++++++++++++++++++++- artiq/gateware/targets/kasli.py | 15 ++- 2 files changed, 152 insertions(+), 3 deletions(-) diff --git a/artiq/examples/kasli_tester/device_db.py b/artiq/examples/kasli_tester/device_db.py index f6cba7fea..e9779af5d 100644 --- a/artiq/examples/kasli_tester/device_db.py +++ b/artiq/examples/kasli_tester/device_db.py @@ -39,6 +39,7 @@ device_db = { } +# DIO (EEM5) starting at RTIO channel 0 for i in range(8): device_db["ttl" + str(i)] = { "type": "local", @@ -48,6 +49,7 @@ for i in range(8): } +# Urukul (EEM1) starting at RTIO channel 8 device_db.update( spi_urukul0={ "type": "local", @@ -112,6 +114,7 @@ for i in range(4): } +# Sampler (EEM3) starting at RTIO channel 14 device_db["spi_sampler0_adc"] = { "type": "local", "module": "artiq.coredevice.spi2", @@ -142,6 +145,7 @@ device_db["sampler0"] = { } +# Zotino (EEM4) starting at RTIO channel 17 device_db["spi_zotino0"] = { "type": "local", "module": "artiq.coredevice.spi2", @@ -171,18 +175,150 @@ device_db["zotino0"] = { } } + +# Grabber (EEM6) starting at RTIO channel 20 +device_db["grabber0"] = { + "type": "local", + "module": "artiq.coredevice.grabber", + "class": "Grabber", + "arguments": {"channel_base": 20} +} + + +# Urukul (EEM7) starting at RTIO channel 22 +device_db.update( + spi_urukul1={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 22} + }, + ttl_urukul1_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 23} + }, + urukul1_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul1", + "io_update_device": "ttl_urukul1_io_update", + "refclk": 100e6, + "clk_sel": 1 + } + } +) + +for i in range(4): + device_db["urukul1_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 4 + i, + "cpld_device": "urukul1_cpld" + } + } + + +# DIO (EEM8) starting at RTIO channel 24 +for i in range(8): + device_db["ttl" + str(8 + i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 24 + i}, + } + + +# DIO (EEM9) starting at RTIO channel 32 +for i in range(8): + device_db["ttl" + str(16 + i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 32 + i}, + } + + +# Sampler (EEM10) starting at RTIO channel 40 +device_db["spi_sampler1_adc"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 40} +} +device_db["spi_sampler1_pgia"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 41} +} +device_db["spi_sampler1_cnv"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 42}, +} +device_db["sampler1"] = { + "type": "local", + "module": "artiq.coredevice.sampler", + "class": "Sampler", + "arguments": { + "spi_adc_device": "spi_sampler1_adc", + "spi_pgia_device": "spi_sampler1_pgia", + "cnv_device": "spi_sampler1_cnv" + } +} + + +# Zotino (EEM11) starting at RTIO channel 43 +device_db["spi_zotino1"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 43} +} +device_db["ttl_zotino1_ldac"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 44} +} +device_db["ttl_zotino1_clr"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 45} +} +device_db["zotino1"] = { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino1", + "ldac_device": "ttl_zotino1_ldac", + "clr_device": "ttl_zotino1_clr" + } +} + + device_db.update( led0={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 20} + "arguments": {"channel": 46} }, led1={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 21} + "arguments": {"channel": 47} }, ) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index d6d7296ea..b9759a99e 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -572,11 +572,20 @@ class Tester(_StandaloneBase): self.comb += self.platform.request("clk_sel").eq(1) self.rtio_channels = [] + self.grabber_csr_group = [] eem.DIO.add_std(self, 5, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) eem.Urukul.add_std(self, 1, 0, ttl_serdes_7series.Output_8X) eem.Sampler.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) eem.Zotino.add_std(self, 4, ttl_serdes_7series.Output_8X) + eem.Grabber.add_std(self, 6) + eem.Urukul.add_std(self, 7, None, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 8, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 9, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.Sampler.add_std(self, 10, None, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 11, ttl_serdes_7series.Output_8X) for i in (1, 2): sfp_ctl = self.platform.request("sfp_ctl", i) @@ -587,9 +596,13 @@ class Tester(_StandaloneBase): self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) self.rtio_channels.append(rtio.LogChannel()) - self.add_rtio(self.rtio_channels) + self.config["HAS_GRABBER"] = None + self.add_csr_group("grabber", self.grabber_csr_group) + self.platform.add_false_path_constraints( + self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) + class _RTIOClockMultiplier(Module): def __init__(self, rtio_clk_freq): From ce6e390d5f1fefc0bcf5db88fd1dc0f24f6dc53f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 30 Aug 2018 12:41:09 +0800 Subject: [PATCH 1167/2457] drtio: expose internal satellite CRI --- artiq/gateware/drtio/__init__.py | 2 +- artiq/gateware/drtio/core.py | 72 ++++++++++++++------ artiq/gateware/drtio/rt_errors_satellite.py | 24 +++---- artiq/gateware/drtio/rt_packet_satellite.py | 6 +- artiq/gateware/test/drtio/test_full_stack.py | 10 ++- 5 files changed, 75 insertions(+), 39 deletions(-) diff --git a/artiq/gateware/drtio/__init__.py b/artiq/gateware/drtio/__init__.py index 7e3143e30..7b83c1934 100644 --- a/artiq/gateware/drtio/__init__.py +++ b/artiq/gateware/drtio/__init__.py @@ -1,2 +1,2 @@ -from artiq.gateware.drtio.core import DRTIOSatellite, DRTIOMaster +from artiq.gateware.drtio.core import SyncRTIO, DRTIOSatellite, DRTIOMaster diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 38c6d8a2a..a60e30b81 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -5,6 +5,7 @@ from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.cdc import PulseSynchronizer from misoc.interconnect.csr import * +from artiq.gateware.rtio import cri from artiq.gateware.rtio.sed.core import * from artiq.gateware.rtio.input_collector import * from artiq.gateware.drtio import (link_layer, aux_controller, @@ -13,6 +14,11 @@ from artiq.gateware.drtio import (link_layer, aux_controller, from artiq.gateware.drtio.rx_synchronizer import GenericRXSynchronizer +__all__ = ["ChannelInterface", "TransceiverInterface", + "SyncRTIO", + "DRTIOSatellite", "DRTIOMaster"] + + class ChannelInterface: def __init__(self, encoder, decoders): self.rx_ready = Signal() @@ -30,12 +36,49 @@ class TransceiverInterface(AutoCSR): self.channels = channel_interfaces +async_errors_layout = [ + ("sequence_error", 1), + ("sequence_error_channel", 16), + ("collision", 1), + ("collision_channel", 16), + ("busy", 1), + ("busy_channel", 16) +] + + +class SyncRTIO(Module): + def __init__(self, channels, fine_ts_width=3, lane_count=8, fifo_depth=128): + self.cri = cri.Interface() + self.async_errors = Record(async_errors_layout) + self.coarse_ts = Signal(64 - fine_ts_width) + + self.comb += self.cri.counter.eq(self.coarse_ts << fine_ts_width) + + self.submodules.outputs = ClockDomainsRenamer("rio")( + SED(channels, fine_ts_width, "sync", + lane_count=lane_count, fifo_depth=fifo_depth, + enable_spread=False, report_buffer_space=True, + interface=self.cri)) + self.comb += self.outputs.coarse_timestamp.eq(self.coarse_ts) + self.sync.rtio += self.outputs.minimum_coarse_timestamp.eq(self.coarse_ts + 16) + + self.submodules.inputs = ClockDomainsRenamer("rio")( + InputCollector(channels, fine_ts_width, "sync", + interface=self.cri)) + self.comb += self.inputs.coarse_timestamp.eq(self.coarse_ts) + + for attr, _ in async_errors_layout: + self.comb += getattr(self.async_errors, attr).eq(getattr(self.outputs, attr)) + + class DRTIOSatellite(Module): - def __init__(self, chanif, channels, rx_synchronizer=None, fine_ts_width=3, - lane_count=8, fifo_depth=128): + def __init__(self, chanif, rx_synchronizer=None, fine_ts_width=3): self.reset = CSRStorage(reset=1) self.reset_phy = CSRStorage(reset=1) self.tsc_loaded = CSR() + # master interface in the rtio domain + self.cri = cri.Interface() + self.async_errors = Record(async_errors_layout) self.clock_domains.cd_rio = ClockDomain() self.clock_domains.cd_rio_phy = ClockDomain() @@ -81,18 +124,16 @@ class DRTIOSatellite(Module): ) self.submodules.link_stats = link_layer.LinkLayerStats(link_layer_sync, "rtio") self.submodules.rt_packet = ClockDomainsRenamer("rtio")( - rt_packet_satellite.RTPacketSatellite(link_layer_sync)) + rt_packet_satellite.RTPacketSatellite(link_layer_sync, interface=self.cri)) self.comb += self.rt_packet.reset.eq(self.cd_rio.rst) - coarse_ts = Signal(64 - fine_ts_width) + self.coarse_ts = Signal(64 - fine_ts_width) self.sync.rtio += \ If(self.rt_packet.tsc_load, - coarse_ts.eq(self.rt_packet.tsc_load_value) + self.coarse_ts.eq(self.rt_packet.tsc_load_value) ).Else( - coarse_ts.eq(coarse_ts + 1) + self.coarse_ts.eq(self.coarse_ts + 1) ) - self.comb += self.rt_packet.cri.counter.eq(coarse_ts << fine_ts_width) - self.coarse_ts = coarse_ts ps_tsc_load = PulseSynchronizer("rtio", "sys") self.submodules += ps_tsc_load @@ -102,21 +143,8 @@ class DRTIOSatellite(Module): If(ps_tsc_load.o, self.tsc_loaded.w.eq(1)) ] - self.submodules.outputs = ClockDomainsRenamer("rio")( - SED(channels, fine_ts_width, "sync", - lane_count=lane_count, fifo_depth=fifo_depth, - enable_spread=False, report_buffer_space=True, - interface=self.rt_packet.cri)) - self.comb += self.outputs.coarse_timestamp.eq(coarse_ts) - self.sync.rtio += self.outputs.minimum_coarse_timestamp.eq(coarse_ts + 16) - - self.submodules.inputs = ClockDomainsRenamer("rio")( - InputCollector(channels, fine_ts_width, "sync", - interface=self.rt_packet.cri)) - self.comb += self.inputs.coarse_timestamp.eq(coarse_ts) - self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite( - self.rt_packet, self.outputs) + self.rt_packet, self.cri, self.async_errors) self.submodules.aux_controller = aux_controller.AuxController( self.link_layer) diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index 8d563a3dc..50f0b53af 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -7,7 +7,7 @@ from artiq.gateware.rtio.cdc import BlindTransfer class RTErrorsSatellite(Module, AutoCSR): - def __init__(self, rt_packet, outputs): + def __init__(self, rt_packet, cri, async_errors): self.protocol_error = CSR(4) self.underflow_channel = CSRStatus(16) self.underflow_timestamp_event = CSRStatus(64) @@ -56,11 +56,11 @@ class RTErrorsSatellite(Module, AutoCSR): underflow_error_cri = Signal(16+64+64) underflow_error_csr = Signal(16+64+64) self.comb += [ - underflow.eq(outputs.cri.o_status[1]), - overflow.eq(outputs.cri.o_status[0]), - underflow_error_cri.eq(Cat(outputs.cri.chan_sel[:16], - outputs.cri.timestamp, - outputs.cri.counter)), + underflow.eq(cri.o_status[1]), + overflow.eq(cri.o_status[0]), + underflow_error_cri.eq(Cat(cri.chan_sel[:16], + cri.timestamp, + cri.counter)), Cat(self.underflow_channel.status, self.underflow_timestamp_event.status, self.underflow_timestamp_counter.status).eq(underflow_error_csr) @@ -73,10 +73,10 @@ class RTErrorsSatellite(Module, AutoCSR): ) error_csr(self.rtio_error, - (outputs.sequence_error, False, - outputs.sequence_error_channel, self.sequence_error_channel.status), - (outputs.collision, False, - outputs.collision_channel, self.collision_channel.status), - (outputs.busy, False, - outputs.busy_channel, self.busy_channel.status) + (async_errors.sequence_error, False, + async_errors.sequence_error_channel, self.sequence_error_channel.status), + (async_errors.collision, False, + async_errors.collision_channel, self.collision_channel.status), + (async_errors.busy, False, + async_errors.busy_channel, self.busy_channel.status) ) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index ef0de8335..c5266e33b 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -8,7 +8,7 @@ from artiq.gateware.drtio.rt_serializer import * class RTPacketSatellite(Module): - def __init__(self, link_layer): + def __init__(self, link_layer, interface=None): self.reset = Signal() self.unknown_packet_type = Signal() @@ -17,7 +17,9 @@ class RTPacketSatellite(Module): self.tsc_load = Signal() self.tsc_load_value = Signal(64) - self.cri = cri.Interface() + if interface is None: + interface = cri.Interface() + self.cri = interface # # # diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index feade41d4..4abfe9e3c 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -67,12 +67,18 @@ class DUT(Module): rtio.Channel.from_phy(self.phy2), ] self.submodules.satellite = DRTIOSatellite( - self.transceivers.bob, rtio_channels, rx_synchronizer, - lane_count=4, fifo_depth=8, fine_ts_width=0) + self.transceivers.bob, rx_synchronizer, fine_ts_width=0) self.satellite.reset.storage.reset = 0 self.satellite.reset.storage_full.reset = 0 self.satellite.reset_phy.storage.reset = 0 self.satellite.reset_phy.storage_full.reset = 0 + self.submodules.satellite_rtio = SyncRTIO( + rtio_channels, fine_ts_width=0, lane_count=4, fifo_depth=8) + self.comb += [ + self.satellite_rtio.coarse_ts.eq(self.satellite.coarse_ts), + self.satellite.cri.connect(self.satellite_rtio.cri), + self.satellite.async_errors.eq(self.satellite_rtio.async_errors), + ] class OutputsTestbench: From 4f963e1e11491ba51842e3b67459643ef85f59fb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 30 Aug 2018 15:15:32 +0800 Subject: [PATCH 1168/2457] drtio: minor cleanup --- artiq/gateware/drtio/core.py | 9 ++++++--- artiq/gateware/drtio/rt_controller_master.py | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index a60e30b81..e4f69d1e5 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -156,7 +156,7 @@ class DRTIOSatellite(Module): class DRTIOMaster(Module): - def __init__(self, chanif, channel_count=1024, fine_ts_width=3): + def __init__(self, chanif, fine_ts_width=3): self.submodules.link_layer = link_layer.LinkLayer( chanif.encoder, chanif.decoders) self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready) @@ -164,9 +164,8 @@ class DRTIOMaster(Module): self.submodules.link_stats = link_layer.LinkLayerStats(self.link_layer, "rtio_rx") self.submodules.rt_packet = rt_packet_master.RTPacketMaster(self.link_layer) self.submodules.rt_controller = rt_controller_master.RTController( - self.rt_packet, channel_count, fine_ts_width) + self.rt_packet, fine_ts_width) self.submodules.rt_manager = rt_controller_master.RTManager(self.rt_packet) - self.cri = self.rt_controller.cri self.submodules.aux_controller = aux_controller.AuxController( self.link_layer) @@ -177,3 +176,7 @@ class DRTIOMaster(Module): self.rt_controller.get_csrs() + self.rt_manager.get_csrs() + self.aux_controller.get_csrs()) + + @property + def cri(self): + return self.rt_controller.cri diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 786e2aa97..c3ef0214b 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -45,7 +45,7 @@ class RTIOCounter(Module): class RTController(Module): - def __init__(self, rt_packet, channel_count, fine_ts_width): + def __init__(self, rt_packet, fine_ts_width): self.csrs = _CSRs() self.cri = cri.Interface() From 6057cb797cfe27cc5cde18a6795ffab6b028fad8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 31 Aug 2018 16:28:33 +0800 Subject: [PATCH 1169/2457] drtio: reorganize tests --- artiq/gateware/test/drtio/test_cdc.py | 94 +++++++++++++++++++ ..._packet.py => test_rt_packet_satellite.py} | 91 ------------------ 2 files changed, 94 insertions(+), 91 deletions(-) create mode 100644 artiq/gateware/test/drtio/test_cdc.py rename artiq/gateware/test/drtio/{test_rt_packet.py => test_rt_packet_satellite.py} (56%) diff --git a/artiq/gateware/test/drtio/test_cdc.py b/artiq/gateware/test/drtio/test_cdc.py new file mode 100644 index 000000000..689df6221 --- /dev/null +++ b/artiq/gateware/test/drtio/test_cdc.py @@ -0,0 +1,94 @@ +import unittest +import random + +from migen import * + +from artiq.gateware.drtio.rt_packet_master import (_CrossDomainRequest, + _CrossDomainNotification) + +class TestCDC(unittest.TestCase): + def test_cross_domain_request(self): + prng = random.Random(1) + for sys_freq in 3, 6, 11: + for srv_freq in 3, 6, 11: + req_stb = Signal() + req_ack = Signal() + req_data = Signal(8) + srv_stb = Signal() + srv_ack = Signal() + srv_data = Signal(8) + test_seq = [93, 92, 19, 39, 91, 30, 12, 91, 38, 42] + received_seq = [] + + def requester(): + for data in test_seq: + yield req_data.eq(data) + yield req_stb.eq(1) + yield + while not (yield req_ack): + yield + yield req_stb.eq(0) + for j in range(prng.randrange(0, 10)): + yield + + def server(): + for i in range(len(test_seq)): + while not (yield srv_stb): + yield + received_seq.append((yield srv_data)) + for j in range(prng.randrange(0, 10)): + yield + yield srv_ack.eq(1) + yield + yield srv_ack.eq(0) + yield + + dut = _CrossDomainRequest("srv", + req_stb, req_ack, req_data, + srv_stb, srv_ack, srv_data) + run_simulation(dut, + {"sys": requester(), "srv": server()}, + {"sys": sys_freq, "srv": srv_freq}) + self.assertEqual(test_seq, received_seq) + + def test_cross_domain_notification(self): + prng = random.Random(1) + + emi_stb = Signal() + emi_data = Signal(8) + rec_stb = Signal() + rec_ack = Signal() + rec_data = Signal(8) + + test_seq = [23, 12, 8, 3, 28] + received_seq = [] + + def emitter(): + for data in test_seq: + yield emi_stb.eq(1) + yield emi_data.eq(data) + yield + yield emi_stb.eq(0) + yield + for j in range(prng.randrange(0, 3)): + yield + + def receiver(): + for i in range(len(test_seq)): + while not (yield rec_stb): + yield + received_seq.append((yield rec_data)) + yield rec_ack.eq(1) + yield + yield rec_ack.eq(0) + yield + for j in range(prng.randrange(0, 3)): + yield + + dut = _CrossDomainNotification("emi", + emi_stb, emi_data, + rec_stb, rec_ack, rec_data) + run_simulation(dut, + {"emi": emitter(), "sys": receiver()}, + {"emi": 13, "sys": 3}) + self.assertEqual(test_seq, received_seq) diff --git a/artiq/gateware/test/drtio/test_rt_packet.py b/artiq/gateware/test/drtio/test_rt_packet_satellite.py similarity index 56% rename from artiq/gateware/test/drtio/test_rt_packet.py rename to artiq/gateware/test/drtio/test_rt_packet_satellite.py index 05d80aa4d..5bbdb44f7 100644 --- a/artiq/gateware/test/drtio/test_rt_packet.py +++ b/artiq/gateware/test/drtio/test_rt_packet_satellite.py @@ -1,13 +1,10 @@ import unittest from types import SimpleNamespace -import random from migen import * from artiq.gateware.drtio.rt_serializer import * from artiq.gateware.drtio.rt_packet_satellite import RTPacketSatellite -from artiq.gateware.drtio.rt_packet_master import (_CrossDomainRequest, - _CrossDomainNotification) class PacketInterface: @@ -123,91 +120,3 @@ class TestSatellite(unittest.TestCase): yield run_simulation(dut, [send(), receive()]) self.assertEqual(tx_times, rx_times) - - -class TestCDC(unittest.TestCase): - def test_cross_domain_request(self): - prng = random.Random(1) - for sys_freq in 3, 6, 11: - for srv_freq in 3, 6, 11: - req_stb = Signal() - req_ack = Signal() - req_data = Signal(8) - srv_stb = Signal() - srv_ack = Signal() - srv_data = Signal(8) - test_seq = [93, 92, 19, 39, 91, 30, 12, 91, 38, 42] - received_seq = [] - - def requester(): - for data in test_seq: - yield req_data.eq(data) - yield req_stb.eq(1) - yield - while not (yield req_ack): - yield - yield req_stb.eq(0) - for j in range(prng.randrange(0, 10)): - yield - - def server(): - for i in range(len(test_seq)): - while not (yield srv_stb): - yield - received_seq.append((yield srv_data)) - for j in range(prng.randrange(0, 10)): - yield - yield srv_ack.eq(1) - yield - yield srv_ack.eq(0) - yield - - dut = _CrossDomainRequest("srv", - req_stb, req_ack, req_data, - srv_stb, srv_ack, srv_data) - run_simulation(dut, - {"sys": requester(), "srv": server()}, - {"sys": sys_freq, "srv": srv_freq}) - self.assertEqual(test_seq, received_seq) - - def test_cross_domain_notification(self): - prng = random.Random(1) - - emi_stb = Signal() - emi_data = Signal(8) - rec_stb = Signal() - rec_ack = Signal() - rec_data = Signal(8) - - test_seq = [23, 12, 8, 3, 28] - received_seq = [] - - def emitter(): - for data in test_seq: - yield emi_stb.eq(1) - yield emi_data.eq(data) - yield - yield emi_stb.eq(0) - yield - for j in range(prng.randrange(0, 3)): - yield - - def receiver(): - for i in range(len(test_seq)): - while not (yield rec_stb): - yield - received_seq.append((yield rec_data)) - yield rec_ack.eq(1) - yield - yield rec_ack.eq(0) - yield - for j in range(prng.randrange(0, 3)): - yield - - dut = _CrossDomainNotification("emi", - emi_stb, emi_data, - rec_stb, rec_ack, rec_data) - run_simulation(dut, - {"emi": emitter(), "sys": receiver()}, - {"emi": 13, "sys": 3}) - self.assertEqual(test_seq, received_seq) From 078c862618d2c13fb25dca1203e140de4276cb8d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 1 Sep 2018 21:07:55 +0800 Subject: [PATCH 1170/2457] drtio: add repeater (WIP, write only) --- artiq/gateware/drtio/__init__.py | 2 +- artiq/gateware/drtio/core.py | 24 ++++- artiq/gateware/drtio/rt_packet_repeater.py | 92 +++++++++++++++++++ artiq/gateware/test/drtio/packet_interface.py | 72 +++++++++++++++ .../test/drtio/test_rt_packet_repeater.py | 62 +++++++++++++ .../test/drtio/test_rt_packet_satellite.py | 88 ++---------------- 6 files changed, 260 insertions(+), 80 deletions(-) create mode 100644 artiq/gateware/drtio/rt_packet_repeater.py create mode 100644 artiq/gateware/test/drtio/packet_interface.py create mode 100644 artiq/gateware/test/drtio/test_rt_packet_repeater.py diff --git a/artiq/gateware/drtio/__init__.py b/artiq/gateware/drtio/__init__.py index 7b83c1934..76cb979c7 100644 --- a/artiq/gateware/drtio/__init__.py +++ b/artiq/gateware/drtio/__init__.py @@ -1,2 +1,2 @@ -from artiq.gateware.drtio.core import SyncRTIO, DRTIOSatellite, DRTIOMaster +from artiq.gateware.drtio.core import SyncRTIO, DRTIOSatellite, DRTIOMaster, DRTIORepeater diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index e4f69d1e5..209a3b58d 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -16,7 +16,7 @@ from artiq.gateware.drtio.rx_synchronizer import GenericRXSynchronizer __all__ = ["ChannelInterface", "TransceiverInterface", "SyncRTIO", - "DRTIOSatellite", "DRTIOMaster"] + "DRTIOSatellite", "DRTIOMaster", "DRTIORepeater"] class ChannelInterface: @@ -180,3 +180,25 @@ class DRTIOMaster(Module): @property def cri(self): return self.rt_controller.cri + + +class DRTIORepeater(Module): + def __init__(self, chanif): + self.submodules.link_layer = link_layer.LinkLayer( + chanif.encoder, chanif.decoders) + self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready) + + self.submodules.link_stats = link_layer.LinkLayerStats(self.link_layer, "rtio_rx") + self.submodules.rt_packet = rt_packet_repeater.RTPacketRepeater(self.link_layer) + + self.submodules.aux_controller = aux_controller.AuxController( + self.link_layer) + + def get_csrs(self): + return (self.link_layer.get_csrs() + + self.link_stats.get_csrs() + + self.aux_controller.get_csrs()) + + @property + def cri(self): + return self.rt_packet.cri diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py new file mode 100644 index 000000000..0eb9edfb3 --- /dev/null +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -0,0 +1,92 @@ +from migen import * +from migen.genlib.fsm import * + +from artiq.gateware.rtio import cri +from artiq.gateware.drtio.rt_serializer import * + + +class RTPacketRepeater(Module): + def __init__(self, link_layer): + self.cri = cri.Interface() + + # RX/TX datapath + assert len(link_layer.tx_rt_data) == len(link_layer.rx_rt_data) + assert len(link_layer.tx_rt_data) % 8 == 0 + ws = len(link_layer.tx_rt_data) + tx_plm = get_m2s_layouts(ws) + tx_dp = ClockDomainsRenamer("rtio")(TransmitDatapath( + link_layer.tx_rt_frame, link_layer.tx_rt_data, tx_plm)) + self.submodules += tx_dp + rx_plm = get_s2m_layouts(ws) + rx_dp = ClockDomainsRenamer("rtio_rx")(ReceiveDatapath( + link_layer.rx_rt_frame, link_layer.rx_rt_data, rx_plm)) + self.submodules += rx_dp + + # Write buffer and extra data count + wb_timestamp = Signal(64) + wb_channel = Signal(16) + wb_address = Signal(16) + wb_data = Signal(512) + self.sync.rtio += If(self.cri.cmd == cri.commands["write"], + wb_timestamp.eq(self.cri.timestamp), + wb_channel.eq(self.cri.chan_sel), + wb_address.eq(self.cri.o_address), + wb_data.eq(self.cri.o_data)) + + wb_extra_data_cnt = Signal(8) + short_data_len = tx_plm.field_length("write", "short_data") + wb_extra_data_a = Signal(512) + self.comb += wb_extra_data_a.eq(self.cri.o_data[short_data_len:]) + for i in range(512//ws): + self.sync.rtio += If(self.cri.cmd == cri.commands["write"], + If(wb_extra_data_a[ws*i:ws*(i+1)] != 0, wb_extra_data_cnt.eq(i+1))) + + wb_extra_data = Signal(512) + self.sync.rtio += If(self.cri.cmd == cri.commands["write"], + wb_extra_data.eq(wb_extra_data_a)) + + extra_data_ce = Signal() + extra_data_last = Signal() + extra_data_counter = Signal(max=512//ws+1) + self.comb += [ + Case(extra_data_counter, + {i+1: tx_dp.raw_data.eq(wb_extra_data[i*ws:(i+1)*ws]) + for i in range(512//ws)}), + extra_data_last.eq(extra_data_counter == wb_extra_data_cnt) + ] + self.sync.rtio += \ + If(extra_data_ce, + extra_data_counter.eq(extra_data_counter + 1), + ).Else( + extra_data_counter.eq(1) + ) + + # TX FSM + tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) + self.submodules += tx_fsm + + tx_fsm.act("IDLE", + If(self.cri.cmd == cri.commands["write"], NextState("WRITE")) + ) + tx_fsm.act("WRITE", + tx_dp.send("write", + timestamp=wb_timestamp, + channel=wb_channel, + address=wb_address, + extra_data_cnt=wb_extra_data_cnt, + short_data=wb_data[:short_data_len]), + If(tx_dp.packet_last, + If(wb_extra_data_cnt == 0, + NextState("IDLE") + ).Else( + NextState("WRITE_EXTRA") + ) + ) + ) + tx_fsm.act("WRITE_EXTRA", + tx_dp.raw_stb.eq(1), + extra_data_ce.eq(1), + If(extra_data_last, + NextState("IDLE") + ) + ) diff --git a/artiq/gateware/test/drtio/packet_interface.py b/artiq/gateware/test/drtio/packet_interface.py new file mode 100644 index 000000000..c6d2979a2 --- /dev/null +++ b/artiq/gateware/test/drtio/packet_interface.py @@ -0,0 +1,72 @@ +from migen import * + +from artiq.gateware.drtio.rt_serializer import * + + +class PacketInterface: + def __init__(self, direction, ws): + if direction == "m2s": + self.plm = get_m2s_layouts(ws) + elif direction == "s2m": + self.plm = get_s2m_layouts(ws) + else: + raise ValueError + self.frame = Signal() + self.data = Signal(ws) + + def send(self, ty, **kwargs): + idx = 8 + value = self.plm.types[ty] + for field_name, field_size in self.plm.layouts[ty][1:]: + try: + fvalue = kwargs[field_name] + del kwargs[field_name] + except KeyError: + fvalue = 0 + value = value | (fvalue << idx) + idx += field_size + if kwargs: + raise ValueError + + ws = len(self.data) + yield self.frame.eq(1) + for i in range(idx//ws): + yield self.data.eq(value) + value >>= ws + yield + yield self.frame.eq(0) + yield + + @passive + def receive(self, callback): + previous_frame = 0 + frame_words = [] + while True: + frame = yield self.frame + if frame: + frame_words.append((yield self.data)) + if previous_frame and not frame: + packet_type = self.plm.type_names[frame_words[0] & 0xff] + packet_nwords = layout_len(self.plm.layouts[packet_type]) \ + //len(self.data) + packet, trailer = frame_words[:packet_nwords], \ + frame_words[packet_nwords:] + + n = 0 + packet_int = 0 + for w in packet: + packet_int |= (w << n) + n += len(self.data) + + field_dict = dict() + idx = 0 + for field_name, field_size in self.plm.layouts[packet_type]: + v = (packet_int >> idx) & (2**field_size - 1) + field_dict[field_name] = v + idx += field_size + + callback(packet_type, field_dict, trailer) + + frame_words = [] + previous_frame = frame + yield diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py new file mode 100644 index 000000000..760a7a9ac --- /dev/null +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -0,0 +1,62 @@ +import unittest +from types import SimpleNamespace + +from migen import * + +from artiq.gateware.rtio import cri +from artiq.gateware.test.drtio.packet_interface import PacketInterface +from artiq.gateware.drtio.rt_packet_repeater import RTPacketRepeater + + +def create_dut(nwords): + pt = PacketInterface("s2m", nwords*8) + pr = PacketInterface("m2s", nwords*8) + dut = ClockDomainsRenamer({"rtio": "sys", "rtio_rx": "sys"})( + RTPacketRepeater(SimpleNamespace( + rx_rt_frame=pt.frame, rx_rt_data=pt.data, + tx_rt_frame=pr.frame, tx_rt_data=pr.data))) + return pt, pr, dut + + +class TestRepeater(unittest.TestCase): + def test_output(self): + test_writes = [ + (1, 10, 21, 0x42), + (2, 11, 34, 0x2342), + (3, 12, 83, 0x2345566633), + (4, 13, 25, 0x98da14959a19498ae1), + (5, 14, 75, 0x3998a1883ae14f828ae24958ea2479) + ] + + for nwords in range(1, 8): + pt, pr, dut = create_dut(nwords) + + def send(): + for channel, timestamp, address, data in test_writes: + yield dut.cri.chan_sel.eq(channel) + yield dut.cri.timestamp.eq(timestamp) + yield dut.cri.o_address.eq(address) + yield dut.cri.o_data.eq(data) + yield dut.cri.cmd.eq(cri.commands["write"]) + yield + yield dut.cri.cmd.eq(cri.commands["nop"]) + yield + for i in range(30): + yield + for i in range(50): + yield + + short_data_len = pr.plm.field_length("write", "short_data") + + received = [] + def receive(packet_type, field_dict, trailer): + self.assertEqual(packet_type, "write") + self.assertEqual(len(trailer), field_dict["extra_data_cnt"]) + data = field_dict["short_data"] + for n, te in enumerate(trailer): + data |= te << (n*nwords*8 + short_data_len) + received.append((field_dict["channel"], field_dict["timestamp"], + field_dict["address"], data)) + + run_simulation(dut, [send(), pr.receive(receive)]) + self.assertEqual(test_writes, received) diff --git a/artiq/gateware/test/drtio/test_rt_packet_satellite.py b/artiq/gateware/test/drtio/test_rt_packet_satellite.py index 5bbdb44f7..1d934b8df 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_satellite.py +++ b/artiq/gateware/test/drtio/test_rt_packet_satellite.py @@ -3,91 +3,23 @@ from types import SimpleNamespace from migen import * -from artiq.gateware.drtio.rt_serializer import * +from artiq.gateware.test.drtio.packet_interface import PacketInterface from artiq.gateware.drtio.rt_packet_satellite import RTPacketSatellite -class PacketInterface: - def __init__(self, direction, ws): - if direction == "m2s": - self.plm = get_m2s_layouts(ws) - elif direction == "s2m": - self.plm = get_s2m_layouts(ws) - else: - raise ValueError - self.frame = Signal() - self.data = Signal(ws) - - def send(self, ty, **kwargs): - idx = 8 - value = self.plm.types[ty] - for field_name, field_size in self.plm.layouts[ty][1:]: - try: - fvalue = kwargs[field_name] - del kwargs[field_name] - except KeyError: - fvalue = 0 - value = value | (fvalue << idx) - idx += field_size - if kwargs: - raise ValueError - - ws = len(self.data) - yield self.frame.eq(1) - for i in range(idx//ws): - yield self.data.eq(value) - value >>= ws - yield - yield self.frame.eq(0) - yield - - @passive - def receive(self, callback): - previous_frame = 0 - frame_words = [] - while True: - frame = yield self.frame - if frame: - frame_words.append((yield self.data)) - if previous_frame and not frame: - packet_type = self.plm.type_names[frame_words[0] & 0xff] - packet_nwords = layout_len(self.plm.layouts[packet_type]) \ - //len(self.data) - packet, trailer = frame_words[:packet_nwords], \ - frame_words[packet_nwords:] - - n = 0 - packet_int = 0 - for w in packet: - packet_int |= (w << n) - n += len(self.data) - - field_dict = dict() - idx = 0 - for field_name, field_size in self.plm.layouts[packet_type]: - v = (packet_int >> idx) & (2**field_size - 1) - field_dict[field_name] = v - idx += field_size - - callback(packet_type, field_dict, trailer) - - frame_words = [] - previous_frame = frame - yield +def create_dut(nwords): + pt = PacketInterface("m2s", nwords*8) + pr = PacketInterface("s2m", nwords*8) + dut = RTPacketSatellite(SimpleNamespace( + rx_rt_frame=pt.frame, rx_rt_data=pt.data, + tx_rt_frame=pr.frame, tx_rt_data=pr.data)) + return pt, pr, dut class TestSatellite(unittest.TestCase): - def create_dut(self, nwords): - pt = PacketInterface("m2s", nwords*8) - pr = PacketInterface("s2m", nwords*8) - dut = RTPacketSatellite(SimpleNamespace( - rx_rt_frame=pt.frame, rx_rt_data=pt.data, - tx_rt_frame=pr.frame, tx_rt_data=pr.data)) - return pt, pr, dut - def test_echo(self): for nwords in range(1, 8): - pt, pr, dut = self.create_dut(nwords) + pt, pr, dut = create_dut(nwords) completed = False def send(): yield from pt.send("echo_request") @@ -102,7 +34,7 @@ class TestSatellite(unittest.TestCase): def test_set_time(self): for nwords in range(1, 8): - pt, _, dut = self.create_dut(nwords) + pt, _, dut = create_dut(nwords) tx_times = [0x12345678aabbccdd, 0x0102030405060708, 0xaabbccddeeff1122] def send(): From 88b7529d099b8698627265201b091d31c3a27d18 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Sep 2018 14:37:23 +0800 Subject: [PATCH 1171/2457] drtio: share CDC --- artiq/gateware/drtio/rt_packet_master.py | 61 ++---------------------- artiq/gateware/test/drtio/test_cdc.py | 8 ++-- 2 files changed, 9 insertions(+), 60 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index 2e07dcbc7..39598aba7 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -3,63 +3,12 @@ from migen import * from migen.genlib.fsm import * from migen.genlib.fifo import AsyncFIFO -from migen.genlib.cdc import PulseSynchronizer from artiq.gateware.rtio.cdc import GrayCodeTransfer, BlindTransfer +from artiq.gateware.drtio.cdc import CrossDomainRequest, CrossDomainNotification from artiq.gateware.drtio.rt_serializer import * -class _CrossDomainRequest(Module): - def __init__(self, domain, - req_stb, req_ack, req_data, - srv_stb, srv_ack, srv_data): - dsync = getattr(self.sync, domain) - - request = PulseSynchronizer("sys", domain) - reply = PulseSynchronizer(domain, "sys") - self.submodules += request, reply - - ongoing = Signal() - self.comb += request.i.eq(~ongoing & req_stb) - self.sync += [ - req_ack.eq(reply.o), - If(req_stb, ongoing.eq(1)), - If(req_ack, ongoing.eq(0)) - ] - if req_data is not None: - req_data_r = Signal.like(req_data) - req_data_r.attr.add("no_retiming") - self.sync += If(req_stb, req_data_r.eq(req_data)) - dsync += [ - If(request.o, srv_stb.eq(1)), - If(srv_ack, srv_stb.eq(0)) - ] - if req_data is not None: - dsync += If(request.o, srv_data.eq(req_data_r)) - self.comb += reply.i.eq(srv_stb & srv_ack) - - -class _CrossDomainNotification(Module): - def __init__(self, domain, - emi_stb, emi_data, - rec_stb, rec_ack, rec_data): - emi_data_r = Signal(len(emi_data)) - emi_data_r.attr.add("no_retiming") - dsync = getattr(self.sync, domain) - dsync += If(emi_stb, emi_data_r.eq(emi_data)) - - ps = PulseSynchronizer(domain, "sys") - self.submodules += ps - self.comb += ps.i.eq(emi_stb) - self.sync += [ - If(rec_ack, rec_stb.eq(0)), - If(ps.o, - rec_data.eq(emi_data_r), - rec_stb.eq(1) - ) - ] - - class RTPacketMaster(Module): def __init__(self, link_layer, sr_fifo_depth=4): # all interface signals in sys domain unless otherwise specified @@ -206,19 +155,19 @@ class RTPacketMaster(Module): # CDC buffer_space_not = Signal() buffer_space = Signal(16) - self.submodules += _CrossDomainNotification("rtio_rx", + self.submodules += CrossDomainNotification("rtio_rx", "sys", buffer_space_not, buffer_space, self.buffer_space_not, self.buffer_space_not_ack, self.buffer_space) set_time_stb = Signal() set_time_ack = Signal() - self.submodules += _CrossDomainRequest("rtio", + self.submodules += CrossDomainRequest("rtio", self.set_time_stb, self.set_time_ack, None, set_time_stb, set_time_ack, None) echo_stb = Signal() echo_ack = Signal() - self.submodules += _CrossDomainRequest("rtio", + self.submodules += CrossDomainRequest("rtio", self.echo_stb, self.echo_ack, None, echo_stb, echo_ack, None) @@ -227,7 +176,7 @@ class RTPacketMaster(Module): read_is_overflow = Signal() read_data = Signal(32) read_timestamp = Signal(64) - self.submodules += _CrossDomainNotification("rtio_rx", + self.submodules += CrossDomainNotification("rtio_rx", "sys", read_not, Cat(read_no_event, read_is_overflow, read_data, read_timestamp), diff --git a/artiq/gateware/test/drtio/test_cdc.py b/artiq/gateware/test/drtio/test_cdc.py index 689df6221..5598fd68b 100644 --- a/artiq/gateware/test/drtio/test_cdc.py +++ b/artiq/gateware/test/drtio/test_cdc.py @@ -3,8 +3,8 @@ import random from migen import * -from artiq.gateware.drtio.rt_packet_master import (_CrossDomainRequest, - _CrossDomainNotification) +from artiq.gateware.drtio.cdc import CrossDomainRequest, CrossDomainNotification + class TestCDC(unittest.TestCase): def test_cross_domain_request(self): @@ -43,7 +43,7 @@ class TestCDC(unittest.TestCase): yield srv_ack.eq(0) yield - dut = _CrossDomainRequest("srv", + dut = CrossDomainRequest("srv", req_stb, req_ack, req_data, srv_stb, srv_ack, srv_data) run_simulation(dut, @@ -85,7 +85,7 @@ class TestCDC(unittest.TestCase): for j in range(prng.randrange(0, 3)): yield - dut = _CrossDomainNotification("emi", + dut = CrossDomainNotification("emi", "sys", emi_stb, emi_data, rec_stb, rec_ack, rec_data) run_simulation(dut, From 6768dbab6c428e18f7733240c8dfc02b4a504a64 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Sep 2018 14:38:37 +0800 Subject: [PATCH 1172/2457] drtio: add buffer space support to rt_packet_repeater --- artiq/gateware/drtio/rt_packet_master.py | 4 +- artiq/gateware/drtio/rt_packet_repeater.py | 80 ++++++++++++++++++- artiq/gateware/drtio/rt_serializer.py | 2 +- .../test/drtio/test_rt_packet_repeater.py | 36 +++++++++ 4 files changed, 118 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index 39598aba7..b38ce0abf 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -15,7 +15,7 @@ class RTPacketMaster(Module): # standard request interface # - # notwrite=1 address=0 buffer space request + # notwrite=1 address=0 buffer space request # notwrite=1 address=1 read request # # optimized for write throughput @@ -252,7 +252,7 @@ class RTPacketMaster(Module): ) ) tx_fsm.act("BUFFER_SPACE", - tx_dp.send("buffer_space_request"), + tx_dp.send("buffer_space_request", destination=sr_channel), If(tx_dp.packet_last, sr_buf_re.eq(1), NextState("IDLE") diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 0eb9edfb3..e570b39d6 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -1,14 +1,25 @@ from migen import * from migen.genlib.fsm import * +from migen.genlib.misc import WaitTimer + from artiq.gateware.rtio import cri +from artiq.gateware.drtio.cdc import CrossDomainNotification from artiq.gateware.drtio.rt_serializer import * class RTPacketRepeater(Module): def __init__(self, link_layer): + # CRI target interface in rtio domain self.cri = cri.Interface() + # in rtio_rx domain + self.err_unknown_packet_type = Signal() + self.err_packet_truncated = Signal() + + # in rtio domain + self.buffer_space_timeout = Signal() + # RX/TX datapath assert len(link_layer.tx_rt_data) == len(link_layer.rx_rt_data) assert len(link_layer.tx_rt_data) % 8 == 0 @@ -61,12 +72,30 @@ class RTPacketRepeater(Module): extra_data_counter.eq(1) ) + # Buffer space + buffer_space_destination = Signal(8) + self.sync.rtio += If(self.cri.cmd == cri.commands["get_buffer_space"], + buffer_space_destination.eq(self.cri.chan_sel[16:])) + + rx_buffer_space_not = Signal() + rx_buffer_space = Signal(16) + buffer_space_not = Signal() + buffer_space_not_ack = Signal() + self.submodules += CrossDomainNotification("rtio_rx", "rtio", + rx_buffer_space_not, rx_buffer_space, + buffer_space_not, buffer_space_not_ack, + self.cri.o_buffer_space) + + timeout_counter = WaitTimer(8191) + self.submodules += timeout_counter + # TX FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) self.submodules += tx_fsm tx_fsm.act("IDLE", - If(self.cri.cmd == cri.commands["write"], NextState("WRITE")) + If(self.cri.cmd == cri.commands["write"], NextState("WRITE")), + If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")) ) tx_fsm.act("WRITE", tx_dp.send("write", @@ -90,3 +119,52 @@ class RTPacketRepeater(Module): NextState("IDLE") ) ) + tx_fsm.act("BUFFER_SPACE", + tx_dp.send("buffer_space_request", destination=buffer_space_destination), + If(tx_dp.packet_last, + buffer_space_not_ack.eq(1), + NextState("WAIT_BUFFER_SPACE") + ) + ) + tx_fsm.act("WAIT_BUFFER_SPACE", + timeout_counter.wait.eq(1), + If(timeout_counter.done, + self.buffer_space_timeout.eq(1), + NextState("IDLE") + ).Else( + If(buffer_space_not, + self.cri.o_buffer_space_valid.eq(1), + NextState("IDLE") + ), + ) + ) + + # RX FSM + rx_fsm = ClockDomainsRenamer("rtio_rx")(FSM(reset_state="INPUT")) + self.submodules += rx_fsm + + ongoing_packet_next = Signal() + ongoing_packet = Signal() + self.sync.rtio_rx += ongoing_packet.eq(ongoing_packet_next) + + rx_fsm.act("INPUT", + If(rx_dp.frame_r, + rx_dp.packet_buffer_load.eq(1), + If(rx_dp.packet_last, + Case(rx_dp.packet_type, { + rx_plm.types["buffer_space_reply"]: NextState("BUFFER_SPACE"), + "default": self.err_unknown_packet_type.eq(1) + }) + ).Else( + ongoing_packet_next.eq(1) + ) + ), + If(~rx_dp.frame_r & ongoing_packet, + self.err_packet_truncated.eq(1) + ) + ) + rx_fsm.act("BUFFER_SPACE", + rx_buffer_space_not.eq(1), + rx_buffer_space.eq(rx_dp.packet_as["buffer_space_reply"].space), + NextState("INPUT") + ) diff --git a/artiq/gateware/drtio/rt_serializer.py b/artiq/gateware/drtio/rt_serializer.py index 00a46299f..069680d9e 100644 --- a/artiq/gateware/drtio/rt_serializer.py +++ b/artiq/gateware/drtio/rt_serializer.py @@ -53,7 +53,7 @@ def get_m2s_layouts(alignment): ("address", 16), ("extra_data_cnt", 8), ("short_data", short_data_len)) - plm.add_type("buffer_space_request") + plm.add_type("buffer_space_request", ("destination", 8)) plm.add_type("read_request", ("channel", 16), ("timeout", 64)) diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index 760a7a9ac..b62fe3329 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -60,3 +60,39 @@ class TestRepeater(unittest.TestCase): run_simulation(dut, [send(), pr.receive(receive)]) self.assertEqual(test_writes, received) + + def test_buffer_space(self): + for nwords in range(1, 8): + pt, pr, dut = create_dut(nwords) + + def send_requests(): + for i in range(10): + yield dut.cri.chan_sel.eq(i << 16) + yield dut.cri.cmd.eq(cri.commands["get_buffer_space"]) + yield + yield dut.cri.cmd.eq(cri.commands["nop"]) + yield + while not (yield dut.cri.o_buffer_space_valid): + yield + buffer_space = yield dut.cri.o_buffer_space + self.assertEqual(buffer_space, 2*i) + + current_request = None + + @passive + def send_replies(): + nonlocal current_request + while True: + while current_request is None: + yield + yield from pt.send("buffer_space_reply", space=2*current_request) + current_request = None + + def receive(packet_type, field_dict, trailer): + nonlocal current_request + self.assertEqual(packet_type, "buffer_space_request") + self.assertEqual(trailer, []) + self.assertEqual(current_request, None) + current_request = field_dict["destination"] + + run_simulation(dut, [send_requests(), send_replies(), pr.receive(receive)]) From 0fe2a6801eebb65fa3debcf4af6e385af6d0b8f5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Sep 2018 15:50:23 +0800 Subject: [PATCH 1173/2457] drtio: forward destination with channel --- artiq/gateware/drtio/rt_controller_master.py | 3 +-- artiq/gateware/drtio/rt_packet_master.py | 20 +++++++++---------- artiq/gateware/drtio/rt_packet_repeater.py | 6 +++--- artiq/gateware/drtio/rt_packet_satellite.py | 4 ++-- artiq/gateware/drtio/rt_serializer.py | 4 ++-- artiq/gateware/rtio/cri.py | 3 ++- .../test/drtio/test_rt_packet_repeater.py | 2 +- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index c3ef0214b..ec1fd5182 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -93,11 +93,10 @@ class RTController(Module): ] # common packet fields - chan_sel = self.cri.chan_sel[:16] rt_packet_buffer_request = Signal() rt_packet_read_request = Signal() self.comb += [ - rt_packet.sr_channel.eq(chan_sel), + rt_packet.sr_chan_sel.eq(self.cri.chan_sel), rt_packet.sr_address.eq(self.cri.o_address), rt_packet.sr_data.eq(self.cri.o_data), rt_packet.sr_timestamp.eq(self.cri.timestamp), diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index b38ce0abf..45ffe1278 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -26,7 +26,7 @@ class RTPacketMaster(Module): self.sr_ack = Signal() self.sr_notwrite = Signal() self.sr_timestamp = Signal(64) - self.sr_channel = Signal(16) + self.sr_chan_sel = Signal(24) self.sr_address = Signal(16) self.sr_data = Signal(512) @@ -85,19 +85,19 @@ class RTPacketMaster(Module): # Write FIFO and extra data count sr_fifo = ClockDomainsRenamer({"write": "sys_with_rst", "read": "rtio_with_rst"})( - AsyncFIFO(1+64+16+16+512, sr_fifo_depth)) + AsyncFIFO(1+64+24+16+512, sr_fifo_depth)) self.submodules += sr_fifo sr_notwrite_d = Signal() sr_timestamp_d = Signal(64) - sr_channel_d = Signal(16) + sr_chan_sel_d = Signal(24) sr_address_d = Signal(16) sr_data_d = Signal(512) self.comb += [ sr_fifo.we.eq(self.sr_stb), self.sr_ack.eq(sr_fifo.writable), - sr_fifo.din.eq(Cat(self.sr_notwrite, self.sr_timestamp, self.sr_channel, + sr_fifo.din.eq(Cat(self.sr_notwrite, self.sr_timestamp, self.sr_chan_sel, self.sr_address, self.sr_data)), - Cat(sr_notwrite_d, sr_timestamp_d, sr_channel_d, + Cat(sr_notwrite_d, sr_timestamp_d, sr_chan_sel_d, sr_address_d, sr_data_d).eq(sr_fifo.dout) ] @@ -114,7 +114,7 @@ class RTPacketMaster(Module): sr_notwrite = Signal() sr_timestamp = Signal(64) - sr_channel = Signal(16) + sr_chan_sel = Signal(24) sr_address = Signal(16) sr_extra_data_cnt = Signal(8) sr_data = Signal(512) @@ -122,7 +122,7 @@ class RTPacketMaster(Module): self.sync.rtio += If(sr_fifo.re, sr_notwrite.eq(sr_notwrite_d), sr_timestamp.eq(sr_timestamp_d), - sr_channel.eq(sr_channel_d), + sr_chan_sel.eq(sr_chan_sel_d), sr_address.eq(sr_address_d), sr_data.eq(sr_data_d)) @@ -230,7 +230,7 @@ class RTPacketMaster(Module): tx_fsm.act("WRITE", tx_dp.send("write", timestamp=sr_timestamp, - channel=sr_channel, + chan_sel=sr_chan_sel, address=sr_address, extra_data_cnt=sr_extra_data_cnt, short_data=sr_data[:short_data_len]), @@ -252,14 +252,14 @@ class RTPacketMaster(Module): ) ) tx_fsm.act("BUFFER_SPACE", - tx_dp.send("buffer_space_request", destination=sr_channel), + tx_dp.send("buffer_space_request", destination=sr_chan_sel[16:]), If(tx_dp.packet_last, sr_buf_re.eq(1), NextState("IDLE") ) ) tx_fsm.act("READ", - tx_dp.send("read_request", channel=sr_channel, timeout=sr_timestamp), + tx_dp.send("read_request", chan_sel=sr_chan_sel, timeout=sr_timestamp), If(tx_dp.packet_last, sr_buf_re.eq(1), NextState("IDLE") diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index e570b39d6..d6f27ecc9 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -35,12 +35,12 @@ class RTPacketRepeater(Module): # Write buffer and extra data count wb_timestamp = Signal(64) - wb_channel = Signal(16) + wb_chan_sel = Signal(24) wb_address = Signal(16) wb_data = Signal(512) self.sync.rtio += If(self.cri.cmd == cri.commands["write"], wb_timestamp.eq(self.cri.timestamp), - wb_channel.eq(self.cri.chan_sel), + wb_chan_sel.eq(self.cri.chan_sel), wb_address.eq(self.cri.o_address), wb_data.eq(self.cri.o_data)) @@ -100,7 +100,7 @@ class RTPacketRepeater(Module): tx_fsm.act("WRITE", tx_dp.send("write", timestamp=wb_timestamp, - channel=wb_channel, + chan_sel=wb_chan_sel, address=wb_address, extra_data_cnt=wb_extra_data_cnt, short_data=wb_data[:short_data_len]), diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index c5266e33b..4760e11ac 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -83,12 +83,12 @@ class RTPacketSatellite(Module): rx_dp.packet_as["set_time"].timestamp), If(load_read_request | read_request_pending, self.cri.chan_sel.eq( - rx_dp.packet_as["read_request"].channel), + rx_dp.packet_as["read_request"].chan_sel), self.cri.timestamp.eq( rx_dp.packet_as["read_request"].timeout) ).Else( self.cri.chan_sel.eq( - rx_dp.packet_as["write"].channel), + rx_dp.packet_as["write"].chan_sel), self.cri.timestamp.eq( rx_dp.packet_as["write"].timestamp) ), diff --git a/artiq/gateware/drtio/rt_serializer.py b/artiq/gateware/drtio/rt_serializer.py index 069680d9e..4b62dbfb6 100644 --- a/artiq/gateware/drtio/rt_serializer.py +++ b/artiq/gateware/drtio/rt_serializer.py @@ -49,13 +49,13 @@ def get_m2s_layouts(alignment): plm.add_type("set_time", ("timestamp", 64)) plm.add_type("write", ("timestamp", 64), - ("channel", 16), + ("chan_sel", 24), ("address", 16), ("extra_data_cnt", 8), ("short_data", short_data_len)) plm.add_type("buffer_space_request", ("destination", 8)) - plm.add_type("read_request", ("channel", 16), ("timeout", 64)) + plm.add_type("read_request", ("chan_sel", 24), ("timeout", 64)) return plm diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 4a889bc27..af3511928 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -25,7 +25,8 @@ commands = { layout = [ ("cmd", 2, DIR_M_TO_S), - # 8 MSBs of chan_sel are used to select core + # 8 MSBs of chan_sel = routing destination + # 16 LSBs of chan_sel = channel within the destination ("chan_sel", 24, DIR_M_TO_S), ("timestamp", 64, DIR_M_TO_S), diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index b62fe3329..bdc753853 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -55,7 +55,7 @@ class TestRepeater(unittest.TestCase): data = field_dict["short_data"] for n, te in enumerate(trailer): data |= te << (n*nwords*8 + short_data_len) - received.append((field_dict["channel"], field_dict["timestamp"], + received.append((field_dict["chan_sel"], field_dict["timestamp"], field_dict["address"], data)) run_simulation(dut, [send(), pr.receive(receive)]) From f3fe818049d7f02d2034bf016924f62248772500 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 3 Sep 2018 09:48:12 +0800 Subject: [PATCH 1174/2457] rtio: refactor TSC to allow sharing between cores --- artiq/gateware/drtio/core.py | 40 +++++++++---------- artiq/gateware/drtio/rt_controller_master.py | 31 +++----------- artiq/gateware/drtio/rt_errors_satellite.py | 4 +- artiq/gateware/rtio/__init__.py | 1 + artiq/gateware/rtio/core.py | 26 +++--------- artiq/gateware/rtio/cri.py | 11 ++--- artiq/gateware/rtio/input_collector.py | 13 +++--- artiq/gateware/test/drtio/test_full_stack.py | 16 ++++---- artiq/gateware/test/rtio/test_dma.py | 3 +- .../test/rtio/test_input_collector.py | 5 +-- 10 files changed, 56 insertions(+), 94 deletions(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 209a3b58d..47a56ce0c 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -5,7 +5,7 @@ from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.cdc import PulseSynchronizer from misoc.interconnect.csr import * -from artiq.gateware.rtio import cri +from artiq.gateware.rtio import cri, rtlink from artiq.gateware.rtio.sed.core import * from artiq.gateware.rtio.input_collector import * from artiq.gateware.drtio import (link_layer, aux_controller, @@ -47,32 +47,33 @@ async_errors_layout = [ class SyncRTIO(Module): - def __init__(self, channels, fine_ts_width=3, lane_count=8, fifo_depth=128): + def __init__(self, tsc, channels, lane_count=8, fifo_depth=128): self.cri = cri.Interface() self.async_errors = Record(async_errors_layout) - self.coarse_ts = Signal(64 - fine_ts_width) - self.comb += self.cri.counter.eq(self.coarse_ts << fine_ts_width) + chan_fine_ts_width = max(max(rtlink.get_fine_ts_width(channel.interface.o) + for channel in channels), + max(rtlink.get_fine_ts_width(channel.interface.i) + for channel in channels)) + assert tsc.glbl_fine_ts_width >= chan_fine_ts_width self.submodules.outputs = ClockDomainsRenamer("rio")( - SED(channels, fine_ts_width, "sync", + SED(channels, tsc.glbl_fine_ts_width, "sync", lane_count=lane_count, fifo_depth=fifo_depth, enable_spread=False, report_buffer_space=True, interface=self.cri)) - self.comb += self.outputs.coarse_timestamp.eq(self.coarse_ts) - self.sync.rtio += self.outputs.minimum_coarse_timestamp.eq(self.coarse_ts + 16) + self.comb += self.outputs.coarse_timestamp.eq(tsc.coarse_ts) + self.sync.rtio += self.outputs.minimum_coarse_timestamp.eq(tsc.coarse_ts + 16) self.submodules.inputs = ClockDomainsRenamer("rio")( - InputCollector(channels, fine_ts_width, "sync", - interface=self.cri)) - self.comb += self.inputs.coarse_timestamp.eq(self.coarse_ts) + InputCollector(tsc, channels, "sync", interface=self.cri)) for attr, _ in async_errors_layout: self.comb += getattr(self.async_errors, attr).eq(getattr(self.outputs, attr)) class DRTIOSatellite(Module): - def __init__(self, chanif, rx_synchronizer=None, fine_ts_width=3): + def __init__(self, tsc, chanif, rx_synchronizer=None): self.reset = CSRStorage(reset=1) self.reset_phy = CSRStorage(reset=1) self.tsc_loaded = CSR() @@ -127,13 +128,10 @@ class DRTIOSatellite(Module): rt_packet_satellite.RTPacketSatellite(link_layer_sync, interface=self.cri)) self.comb += self.rt_packet.reset.eq(self.cd_rio.rst) - self.coarse_ts = Signal(64 - fine_ts_width) - self.sync.rtio += \ - If(self.rt_packet.tsc_load, - self.coarse_ts.eq(self.rt_packet.tsc_load_value) - ).Else( - self.coarse_ts.eq(self.coarse_ts + 1) - ) + self.comb += [ + tsc.load.eq(self.rt_packet.tsc_load), + tsc.load_value.eq(self.rt_packet.tsc_load_value) + ] ps_tsc_load = PulseSynchronizer("rtio", "sys") self.submodules += ps_tsc_load @@ -144,7 +142,7 @@ class DRTIOSatellite(Module): ] self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite( - self.rt_packet, self.cri, self.async_errors) + self.rt_packet, tsc, self.cri, self.async_errors) self.submodules.aux_controller = aux_controller.AuxController( self.link_layer) @@ -156,7 +154,7 @@ class DRTIOSatellite(Module): class DRTIOMaster(Module): - def __init__(self, chanif, fine_ts_width=3): + def __init__(self, tsc, chanif): self.submodules.link_layer = link_layer.LinkLayer( chanif.encoder, chanif.decoders) self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready) @@ -164,7 +162,7 @@ class DRTIOMaster(Module): self.submodules.link_stats = link_layer.LinkLayerStats(self.link_layer, "rtio_rx") self.submodules.rt_packet = rt_packet_master.RTPacketMaster(self.link_layer) self.submodules.rt_controller = rt_controller_master.RTController( - self.rt_packet, fine_ts_width) + tsc, self.rt_packet) self.submodules.rt_manager = rt_controller_master.RTManager(self.rt_packet) self.submodules.aux_controller = aux_controller.AuxController( diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index ec1fd5182..fa2efd457 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -7,7 +7,6 @@ from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.interconnect.csr import * -from artiq.gateware.rtio.cdc import GrayCodeTransfer from artiq.gateware.rtio import cri @@ -26,26 +25,8 @@ class _CSRs(AutoCSR): self.o_wait = CSRStatus() -class RTIOCounter(Module): - def __init__(self, width): - self.width = width - # Timestamp counter in RTIO domain - self.value_rtio = Signal(width) - # Timestamp counter resynchronized to sys domain - # Lags behind value_rtio, monotonic and glitch-free - self.value_sys = Signal(width) - - # # # - - # note: counter is in rtio domain and never affected by the reset CSRs - self.sync.rtio += self.value_rtio.eq(self.value_rtio + 1) - gt = GrayCodeTransfer(width) - self.submodules += gt - self.comb += gt.i.eq(self.value_rtio), self.value_sys.eq(gt.o) - - class RTController(Module): - def __init__(self, rt_packet, fine_ts_width): + def __init__(self, tsc, rt_packet): self.csrs = _CSRs() self.cri = cri.Interface() @@ -80,11 +61,9 @@ class RTController(Module): self.comb += self.csrs.protocol_error.w.eq( Cat(err_unknown_packet_type, err_packet_truncated, err_buffer_space_timeout)) - # master RTIO counter and counter synchronization - self.submodules.counter = RTIOCounter(64-fine_ts_width) + # TSC synchronization self.comb += [ - self.cri.counter.eq(self.counter.value_sys << fine_ts_width), - rt_packet.tsc_value.eq(self.counter.value_rtio), + rt_packet.tsc_value.eq(tsc.coarse_ts), self.csrs.set_time.w.eq(rt_packet.set_time_stb) ] self.sync += [ @@ -130,8 +109,8 @@ class RTController(Module): self.submodules += timeout_counter cond_underflow = Signal() - self.comb += cond_underflow.eq((self.cri.timestamp[fine_ts_width:] - - self.csrs.underflow_margin.storage[fine_ts_width:]) < self.counter.value_sys) + self.comb += cond_underflow.eq((self.cri.timestamp[tsc.glbl_fine_ts_width:] + - self.csrs.underflow_margin.storage[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) buffer_space = Signal(16) diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index 50f0b53af..764365730 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -7,7 +7,7 @@ from artiq.gateware.rtio.cdc import BlindTransfer class RTErrorsSatellite(Module, AutoCSR): - def __init__(self, rt_packet, cri, async_errors): + def __init__(self, rt_packet, tsc, cri, async_errors): self.protocol_error = CSR(4) self.underflow_channel = CSRStatus(16) self.underflow_timestamp_event = CSRStatus(64) @@ -60,7 +60,7 @@ class RTErrorsSatellite(Module, AutoCSR): overflow.eq(cri.o_status[0]), underflow_error_cri.eq(Cat(cri.chan_sel[:16], cri.timestamp, - cri.counter)), + tsc.full_ts_cri)), Cat(self.underflow_channel.status, self.underflow_timestamp_event.status, self.underflow_timestamp_counter.status).eq(underflow_error_csr) diff --git a/artiq/gateware/rtio/__init__.py b/artiq/gateware/rtio/__init__.py index 718f2bc7f..a144f593c 100644 --- a/artiq/gateware/rtio/__init__.py +++ b/artiq/gateware/rtio/__init__.py @@ -1,3 +1,4 @@ +from artiq.gateware.rtio.tsc import TSC from artiq.gateware.rtio.cri import KernelInitiator, CRIInterconnectShared from artiq.gateware.rtio.channel import Channel, LogChannel from artiq.gateware.rtio.core import Core diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index edab0bf08..b76308f62 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -14,8 +14,7 @@ from artiq.gateware.rtio.input_collector import * class Core(Module, AutoCSR): - def __init__(self, channels, lane_count=8, fifo_depth=128, - glbl_fine_ts_width=None): + def __init__(self, tsc, channels, lane_count=8, fifo_depth=128): self.cri = cri.Interface() self.reset = CSR() self.reset_phy = CSR() @@ -61,36 +60,23 @@ class Core(Module, AutoCSR): for channel in channels), max(rtlink.get_fine_ts_width(channel.interface.i) for channel in channels)) - if glbl_fine_ts_width is None: - glbl_fine_ts_width = chan_fine_ts_width - assert glbl_fine_ts_width >= chan_fine_ts_width - - coarse_ts = Signal(64-glbl_fine_ts_width) - self.sync.rtio += coarse_ts.eq(coarse_ts + 1) - coarse_ts_cdc = GrayCodeTransfer(len(coarse_ts)) # from rtio to sys - self.submodules += coarse_ts_cdc - self.comb += [ - coarse_ts_cdc.i.eq(coarse_ts), - self.cri.counter.eq(coarse_ts_cdc.o << glbl_fine_ts_width) - ] - self.coarse_ts = coarse_ts + assert tsc.glbl_fine_ts_width >= chan_fine_ts_width # Outputs/Inputs quash_channels = [n for n, c in enumerate(channels) if isinstance(c, LogChannel)] - outputs = SED(channels, glbl_fine_ts_width, "async", + outputs = SED(channels, tsc.glbl_fine_ts_width, "async", quash_channels=quash_channels, lane_count=lane_count, fifo_depth=fifo_depth, interface=self.cri) self.submodules += outputs - self.comb += outputs.coarse_timestamp.eq(coarse_ts) - self.sync += outputs.minimum_coarse_timestamp.eq(coarse_ts_cdc.o + 16) + self.comb += outputs.coarse_timestamp.eq(tsc.coarse_ts) + self.sync += outputs.minimum_coarse_timestamp.eq(tsc.coarse_ts_sys + 16) - inputs = InputCollector(channels, glbl_fine_ts_width, "async", + inputs = InputCollector(tsc, channels, "async", quash_channels=quash_channels, interface=self.cri) self.submodules += inputs - self.comb += inputs.coarse_timestamp.eq(coarse_ts) # Asychronous output errors o_collision_sync = BlindTransfer(data_width=16) diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index af3511928..d78c5da36 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -49,11 +49,6 @@ layout = [ # <3:link error> # <0> and <1> are mutually exclusive. <1> has higher priority. ("i_status", 4, DIR_S_TO_M), - - # value of the timestamp counter transferred into the CRI clock domain. - # monotonic, may lag behind the counter in the IO clock domain, but - # not be ahead of it. - ("counter", 64, DIR_S_TO_M) ] @@ -63,8 +58,10 @@ class Interface(Record): class KernelInitiator(Module, AutoCSR): - def __init__(self, cri=None): + def __init__(self, tsc, cri=None): self.chan_sel = CSRStorage(24) + # monotonic, may lag behind the counter in the IO clock domain, but + # not be ahead of it. self.timestamp = CSRStorage(64) # Writing timestamp clears o_data. This implements automatic @@ -109,7 +106,7 @@ class KernelInitiator(Module, AutoCSR): self.o_data.dat_w.eq(0), self.o_data.we.eq(self.timestamp.re), ] - self.sync += If(self.counter_update.re, self.counter.status.eq(self.cri.counter)) + self.sync += If(self.counter_update.re, self.counter.status.eq(tsc.full_ts_cri)) class CRIDecoder(Module): diff --git a/artiq/gateware/rtio/input_collector.py b/artiq/gateware/rtio/input_collector.py index cff5aeaf8..ce9bcbc20 100644 --- a/artiq/gateware/rtio/input_collector.py +++ b/artiq/gateware/rtio/input_collector.py @@ -24,11 +24,10 @@ def get_channel_layout(coarse_ts_width, interface): class InputCollector(Module): - def __init__(self, channels, glbl_fine_ts_width, mode, quash_channels=[], interface=None): + def __init__(self, tsc, channels, mode, quash_channels=[], interface=None): if interface is None: interface = cri.Interface() self.cri = interface - self.coarse_timestamp = Signal(64 - glbl_fine_ts_width) # # # @@ -55,7 +54,7 @@ class InputCollector(Module): continue # FIFO - layout = get_channel_layout(len(self.coarse_timestamp), iif) + layout = get_channel_layout(len(tsc.coarse_ts), iif) fifo = fifo_factory(layout_len(layout), channel.ififo_depth) self.submodules += fifo fifo_in = Record(layout) @@ -67,10 +66,10 @@ class InputCollector(Module): # FIFO write if iif.delay: - counter_rtio = Signal.like(self.coarse_timestamp, reset_less=True) - sync_io += counter_rtio.eq(self.coarse_timestamp - (iif.delay + 1)) + counter_rtio = Signal.like(tsc.coarse_ts, reset_less=True) + sync_io += counter_rtio.eq(tsc.coarse_ts - (iif.delay + 1)) else: - counter_rtio = self.coarse_timestamp + counter_rtio = tsc.coarse_ts if hasattr(fifo_in, "data"): self.comb += fifo_in.data.eq(iif.data) if hasattr(fifo_in, "timestamp"): @@ -130,7 +129,7 @@ class InputCollector(Module): self.cri.i_data.eq(Array(i_datas)[sel]), self.cri.i_timestamp.eq(Array(i_timestamps)[sel]), ), - If((self.cri.counter >= input_timeout) | (i_status_raw != 0), + If((tsc.full_ts_cri >= input_timeout) | (i_status_raw != 0), If(input_pending, i_ack.eq(1)), input_pending.eq(0) ), diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 4abfe9e3c..eafb438c1 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -52,9 +52,11 @@ class DUT(Module): self.ttl1 = Signal() self.transceivers = DummyTransceiverPair(nwords) - self.submodules.master = DRTIOMaster(self.transceivers.alice, - fine_ts_width=0) - self.submodules.master_ki = rtio.KernelInitiator(self.master.cri) + self.submodules.tsc_master = rtio.TSC("async") + self.submodules.master = DRTIOMaster(self.tsc_master, + self.transceivers.alice) + self.submodules.master_ki = rtio.KernelInitiator(self.tsc_master, + self.master.cri) self.master.rt_controller.csrs.link_up.storage.reset = 1 rx_synchronizer = DummyRXSynchronizer() @@ -66,16 +68,16 @@ class DUT(Module): rtio.Channel.from_phy(self.phy1), rtio.Channel.from_phy(self.phy2), ] + self.submodules.tsc_satellite = rtio.TSC("sync") self.submodules.satellite = DRTIOSatellite( - self.transceivers.bob, rx_synchronizer, fine_ts_width=0) + self.tsc_satellite, self.transceivers.bob, rx_synchronizer) self.satellite.reset.storage.reset = 0 self.satellite.reset.storage_full.reset = 0 self.satellite.reset_phy.storage.reset = 0 self.satellite.reset_phy.storage_full.reset = 0 self.submodules.satellite_rtio = SyncRTIO( - rtio_channels, fine_ts_width=0, lane_count=4, fifo_depth=8) + self.tsc_satellite, rtio_channels, lane_count=4, fifo_depth=8) self.comb += [ - self.satellite_rtio.coarse_ts.eq(self.satellite.coarse_ts), self.satellite.cri.connect(self.satellite_rtio.cri), self.satellite.async_errors.eq(self.satellite_rtio.async_errors), ] @@ -106,7 +108,7 @@ class OutputsTestbench: def sync(self): t = self.now + 15 - while (yield self.dut.master.cri.counter) < t: + while (yield self.dut.tsc_master.full_ts_cri) < t: yield def write(self, channel, data): diff --git a/artiq/gateware/test/rtio/test_dma.py b/artiq/gateware/test/rtio/test_dma.py index 536575b32..ee546e2da 100644 --- a/artiq/gateware/test/rtio/test_dma.py +++ b/artiq/gateware/test/rtio/test_dma.py @@ -127,7 +127,8 @@ class FullStackTB(Module): self.submodules.memory = wishbone.SRAM( 256, init=sequence, bus=bus) self.submodules.dut = dma.DMA(bus) - self.submodules.rtio = rtio.Core(rtio_channels) + self.submodules.tsc = rtio.TSC("async") + self.submodules.rtio = rtio.Core(self.tsc, rtio_channels) self.comb += self.dut.cri.connect(self.rtio.cri) diff --git a/artiq/gateware/test/rtio/test_input_collector.py b/artiq/gateware/test/rtio/test_input_collector.py index c67f2aa53..0c682b28c 100644 --- a/artiq/gateware/test/rtio/test_input_collector.py +++ b/artiq/gateware/test/rtio/test_input_collector.py @@ -38,9 +38,8 @@ class DUT(Module): rtio.Channel.from_phy(self.phy0, ififo_depth=4), rtio.Channel.from_phy(self.phy1, ififo_depth=4) ] - self.submodules.input_collector = InputCollector(rtio_channels, 0, "sync") - self.sync += self.input_collector.coarse_timestamp.eq(self.input_collector.coarse_timestamp + 1) - self.comb += self.input_collector.cri.counter.eq(self.input_collector.coarse_timestamp) + self.submodules.tsc = ClockDomainsRenamer({"rtio": "sys"})(rtio.TSC("sync")) + self.submodules.input_collector = InputCollector(self.tsc, rtio_channels, "sync") @property def cri(self): From 00fabee1ca7ccdfa6cf3b3877bc4e410629599ad Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 3 Sep 2018 09:57:04 +0800 Subject: [PATCH 1175/2457] drtio: fix rt_packet_repeater timeout --- artiq/gateware/drtio/rt_packet_repeater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index d6f27ecc9..9f5e513f9 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -86,7 +86,7 @@ class RTPacketRepeater(Module): buffer_space_not, buffer_space_not_ack, self.cri.o_buffer_space) - timeout_counter = WaitTimer(8191) + timeout_counter = ClockDomainsRenamer("rtio")(WaitTimer(8191)) self.submodules += timeout_counter # TX FSM From c55460f59fa9dff195eaf86a0d14799f83ff8cd7 Mon Sep 17 00:00:00 2001 From: hartytp Date: Mon, 3 Sep 2018 10:44:22 +0100 Subject: [PATCH 1176/2457] suservo: fix doc typo --- artiq/gateware/suservo/iir.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/suservo/iir.py b/artiq/gateware/suservo/iir.py index 72501afae..ba00dd97e 100644 --- a/artiq/gateware/suservo/iir.py +++ b/artiq/gateware/suservo/iir.py @@ -104,7 +104,7 @@ class IIR(Module): will be abbreviated W here. It reads 1 << W.channels input channels (typically from an ADC) - and on each iteration processes the data on using a first-order IIR filter. + and on each iteration processes the data using a first-order IIR filter. At the end of the cycle each the output of the filter together with additional data (typically frequency tunning word and phase offset word for a DDS) are presented at the 1 << W.channels outputs of the module. From 778f1de121e2194037f4647943902fff9d473bb7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 3 Sep 2018 18:26:13 +0800 Subject: [PATCH 1177/2457] drtio: add TSC sync and missed command detection to rt_packet_repeater --- artiq/gateware/drtio/rt_packet_repeater.py | 34 +++++++++++++++++-- .../test/drtio/test_rt_packet_repeater.py | 26 ++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 9f5e513f9..081d444a3 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -18,8 +18,16 @@ class RTPacketRepeater(Module): self.err_packet_truncated = Signal() # in rtio domain + self.command_missed = Signal() self.buffer_space_timeout = Signal() + # set_time interface, in rtio domain + self.set_time_stb = Signal() + self.set_time_ack = Signal() + self.tsc_value = Signal(64) + + # # # + # RX/TX datapath assert len(link_layer.tx_rt_data) == len(link_layer.rx_rt_data) assert len(link_layer.tx_rt_data) % 8 == 0 @@ -33,6 +41,11 @@ class RTPacketRepeater(Module): link_layer.rx_rt_frame, link_layer.rx_rt_data, rx_plm)) self.submodules += rx_dp + # TSC sync + tsc_value = Signal(64) + tsc_value_load = Signal() + self.sync.rtio += If(tsc_value_load, tsc_value.eq(self.tsc_value)) + # Write buffer and extra data count wb_timestamp = Signal(64) wb_chan_sel = Signal(24) @@ -89,13 +102,30 @@ class RTPacketRepeater(Module): timeout_counter = ClockDomainsRenamer("rtio")(WaitTimer(8191)) self.submodules += timeout_counter + # Missed commands + cri_ready = Signal() + self.sync.rtio += self.command_missed.eq(~cri_ready & (self.cri.cmd != cri.commands["nop"])) + # TX FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) self.submodules += tx_fsm tx_fsm.act("IDLE", - If(self.cri.cmd == cri.commands["write"], NextState("WRITE")), - If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")) + If(self.set_time_stb, + tsc_value_load.eq(1), + NextState("SET_TIME") + ).Else( + cri_ready.eq(1), + If(self.cri.cmd == cri.commands["write"], NextState("WRITE")), + If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")) + ) + ) + tx_fsm.act("SET_TIME", + tx_dp.send("set_time", timestamp=tsc_value), + If(tx_dp.packet_last, + self.set_time_ack.eq(1), + NextState("IDLE") + ) ) tx_fsm.act("WRITE", tx_dp.send("write", diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index bdc753853..c778d1724 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -19,6 +19,32 @@ def create_dut(nwords): class TestRepeater(unittest.TestCase): + def test_set_time(self): + nwords = 2 + pt, pr, dut = create_dut(nwords) + + def send(): + yield dut.tsc_value.eq(0x12345678) + yield dut.set_time_stb.eq(1) + while not (yield dut.set_time_ack): + yield + yield dut.set_time_stb.eq(0) + yield + for _ in range(30): + yield + + received = False + def receive(packet_type, field_dict, trailer): + nonlocal received + self.assertEqual(packet_type, "set_time") + self.assertEqual(trailer, []) + self.assertEqual(field_dict["timestamp"], 0x12345678) + self.assertEqual(received, False) + received = True + + run_simulation(dut, [send(), pr.receive(receive)]) + self.assertEqual(received, True) + def test_output(self): test_writes = [ (1, 10, 21, 0x42), From 47eb37e2125552b779d6e0a3e25076c3924446c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 4 Sep 2018 10:39:45 +0000 Subject: [PATCH 1178/2457] VLBAI{Master,Slave}: align rtio channels with PTB --- artiq/gateware/targets/kasli.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b9759a99e..ef1fa64f7 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -908,11 +908,13 @@ class VLBAIMaster(_MasterBase): eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) eem.Urukul.add_std(self, 5, 4, ttl_serdes_7series.Output_8X) eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) - phy = ttl_simple.Output(self.platform.request("user_led", 0)) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) + for i in (0, 1): + phy = ttl_simple.Output(self.platform.request("user_led", i)) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) @@ -938,11 +940,13 @@ class VLBAISatellite(_SatelliteBase): eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) eem.Urukul.add_std(self, 5, 4, ttl_serdes_7series.Output_8X) eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) - phy = ttl_simple.Output(self.platform.request("user_led", 0)) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) + for i in (0, 1): + phy = ttl_simple.Output(self.platform.request("user_led", i)) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) self.add_rtio(self.rtio_channels) From bf36786d45153082bf9533026a952cba04397aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 4 Sep 2018 10:59:19 +0000 Subject: [PATCH 1179/2457] kasli_tester: clean up grabber test --- .../kasli_basic/repository/kasli_tester.py | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index 685271217..2c00b1620 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -277,23 +277,10 @@ class KasliTester(EnvExperiment): print("Press ENTER when done.") input() - def test_grabbers(self): - rois = [[0, 0, 0, 2, 2], [1, 0, 0, 2048, 2048]] - print("*** Testing Grabber Frame Grabbers.") - print("ROIs: %s".format(rois)) - print("Press ENTER, activate the camera's frame grabber output, " - "and trigger it once. Type 's' to skip the test.") - if input().strip().lower() == "s": - print("skipping...") - return - for card_n, (card_name, card_dev) in enumerate(self.grabbers): - print(card_name) - self.grabber_capture(card_dev, rois) - @kernel def grabber_capture(self, card_dev, rois): self.core.break_realtime() - delay(10*us) + delay(100*us) mask = 0 for i in range(len(rois)): i = rois[i][0] @@ -308,8 +295,21 @@ class KasliTester(EnvExperiment): card_dev.input_mu(n) self.core.break_realtime() card_dev.gate_roi(0) - print("ROI sums:") - print(n) + print("ROI sums: {}".format(n)) + + def test_grabbers(self): + print("*** Testing Grabber Frame Grabbers.") + print("Activate the camera's frame grabber output, type 'g', press " + "ENTER, and trigger the camera.") + print("Just press ENTER to skip the test.") + if input().strip().lower() != "g": + print("skipping...") + return + rois = [[0, 0, 0, 2, 2], [1, 0, 0, 2048, 2048]] + print("ROIs: {}".format(rois)) + for card_n, (card_name, card_dev) in enumerate(self.grabbers): + print(card_name) + self.grabber_capture(card_dev, rois) def run(self): print("****** Kasli system tester ******") From 15b16695c673426e334777e7d794794862ab914a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 4 Sep 2018 19:04:27 +0800 Subject: [PATCH 1180/2457] frontend: add artiq_route --- artiq/frontend/artiq_route.py | 83 +++++++++++++++++++++++++++++++++++ setup.py | 1 + 2 files changed, 84 insertions(+) create mode 100755 artiq/frontend/artiq_route.py diff --git a/artiq/frontend/artiq_route.py b/artiq/frontend/artiq_route.py new file mode 100755 index 000000000..c818237ce --- /dev/null +++ b/artiq/frontend/artiq_route.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 + +import argparse + + +def get_argparser(): + parser = argparse.ArgumentParser(description="ARTIQ DRTIO routing table " + "manipulation tool") + + parser.add_argument("file", metavar="FILE", type=str, + help="target file") + + action = parser.add_subparsers(dest="action") + action.required = True + + action.add_parser("init", help="create a new empty routing table") + + action.add_parser("show", help="show contents of routing table") + + a_set = action.add_parser("set", help="set routing table entry") + a_set.add_argument("destination", metavar="DESTINATION", type=int, + help="destination to operate on") + a_set.add_argument("hop", metavar="HOP", type=int, nargs="*", + help="hop(s) to the destination") + + return parser + + +ENTRY_COUNT = 256 +MAX_HOPS = 32 + + +def init(filename): + with open(filename, "wb") as f: + f.write(b"\xff"*(ENTRY_COUNT*MAX_HOPS)) + + +def show_routes(filename): + routes = [] + with open(filename, "rb") as f: + for i in range(ENTRY_COUNT): + hops = [int.from_bytes(f.read(1), "big") for j in range(MAX_HOPS)] + routes.append(hops) + + for destination, route in enumerate(routes): + if route[0] != 0xff: + fmt = "{:3d}:".format(destination) + for hop in route: + if hop == 0xff: + break + fmt += " {:3d}".format(hop) + print(fmt) + + +def set_route(filename, destination, hops): + with open(filename, "r+b") as f: + if destination >= ENTRY_COUNT: + raise ValueError("destination must be less than {}".format(ENTRY_COUNT)) + f.seek(destination*MAX_HOPS) + + if len(hops) + 1 >= MAX_HOPS: + raise ValueError("too many hops") + for hop in hops: + if hop >= 0xff: + raise ValueError("all hops must be less than 255") + + hops = hops + [0xff]*(MAX_HOPS-len(hops)) + f.write(bytes(hops)) + + +def main(): + args = get_argparser().parse_args() + if args.action == "init": + init(args.file) + elif args.action == "show": + show_routes(args.file) + elif args.action == "set": + set_route(args.file, args.destination, args.hop) + else: + raise ValueError + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index a85f23ae5..b4c25b027 100755 --- a/setup.py +++ b/setup.py @@ -30,6 +30,7 @@ console_scripts = [ "artiq_master = artiq.frontend.artiq_master:main", "artiq_mkfs = artiq.frontend.artiq_mkfs:main", "artiq_session = artiq.frontend.artiq_session:main", + "artiq_route = artiq.frontend.artiq_route:main", "artiq_rpctool = artiq.frontend.artiq_rpctool:main", "artiq_run = artiq.frontend.artiq_run:main", "artiq_flash = artiq.frontend.artiq_flash:main", From 4e4398afa6434a038a598a7a60be9d945bbf9118 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 12:06:20 +0800 Subject: [PATCH 1181/2457] analyzer: adapt to TSC changes --- artiq/gateware/rtio/analyzer.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/rtio/analyzer.py b/artiq/gateware/rtio/analyzer.py index f958ca8d6..144c62701 100644 --- a/artiq/gateware/rtio/analyzer.py +++ b/artiq/gateware/rtio/analyzer.py @@ -43,7 +43,7 @@ assert layout_len(stopped_layout) == message_len class MessageEncoder(Module, AutoCSR): - def __init__(self, cri, enable): + def __init__(self, tsc, cri, enable): self.source = stream.Endpoint([("data", message_len)]) self.overflow = CSRStatus() @@ -67,7 +67,7 @@ class MessageEncoder(Module, AutoCSR): self.comb += [ input_output.channel.eq(cri.chan_sel), input_output.address_padding.eq(cri.o_address), - input_output.rtio_counter.eq(cri.counter), + input_output.rtio_counter.eq(tsc.full_ts_cri), If(cri.cmd == cri_commands["write"], input_output.message_type.eq(MessageType.output.value), input_output.timestamp.eq(cri.timestamp), @@ -85,7 +85,7 @@ class MessageEncoder(Module, AutoCSR): self.comb += [ exception.message_type.eq(MessageType.exception.value), exception.channel.eq(cri.chan_sel), - exception.rtio_counter.eq(cri.counter), + exception.rtio_counter.eq(tsc.full_ts_cri), ] just_written = Signal() self.sync += just_written.eq(cri.cmd == cri_commands["write"]) @@ -103,7 +103,7 @@ class MessageEncoder(Module, AutoCSR): stopped = Record(stopped_layout) self.comb += [ stopped.message_type.eq(MessageType.stopped.value), - stopped.rtio_counter.eq(cri.counter), + stopped.rtio_counter.eq(tsc.full_ts_cri), ] enable_r = Signal() @@ -193,13 +193,13 @@ class DMAWriter(Module, AutoCSR): class Analyzer(Module, AutoCSR): - def __init__(self, cri, membus, fifo_depth=128): + def __init__(self, tsc, cri, membus, fifo_depth=128): # shutdown procedure: set enable to 0, wait until busy=0 self.enable = CSRStorage() self.busy = CSRStatus() self.submodules.message_encoder = MessageEncoder( - cri, self.enable.storage) + tsc, cri, self.enable.storage) self.submodules.fifo = stream.SyncFIFO( [("data", message_len)], fifo_depth, True) self.submodules.converter = stream.Converter( From 3d531cc923ddee2fad16ca69c09aef81e3a0b81e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 12:06:47 +0800 Subject: [PATCH 1182/2457] kasli: adapt to TSC and DRTIOSatellite changes --- artiq/gateware/targets/kasli.py | 51 ++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index f3e400da2..b8d1be155 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -21,7 +21,7 @@ from artiq.gateware import eem from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer -from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite +from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite, SyncRTIO from artiq.build_soc import * @@ -120,9 +120,10 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.submodules.rtio_crg = _RTIOCRG(self.platform) self.csr_devices.append("rtio_crg") fix_serdes_timing_path(self.platform) - self.submodules.rtio_core = rtio.Core(rtio_channels) + self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") @@ -138,7 +139,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.crg.cd_sys.clk, self.rtio_crg.cd_rtio.clk) - self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri, + self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.rtio_core.cri, self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") @@ -662,6 +663,8 @@ class _MasterBase(MiniSoC, AMPSoC): self.comb += [sfp_ctl.led.eq(channel.rx_ready) for sfp_ctl, channel in zip(sfp_ctls, self.drtio_transceiver.channels)] + self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + drtio_csr_group = [] drtio_memory_group = [] self.drtio_cri = [] @@ -672,7 +675,7 @@ class _MasterBase(MiniSoC, AMPSoC): drtio_memory_group.append(memory_name) core = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)})( - DRTIOMaster(self.drtio_transceiver.channels[i])) + DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) setattr(self.submodules, core_name, core) self.drtio_cri.append(core.cri) self.csr_devices.append(core_name) @@ -704,10 +707,10 @@ class _MasterBase(MiniSoC, AMPSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.submodules.rtio_core = rtio.Core(rtio_channels, glbl_fine_ts_width=3) + self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") @@ -717,7 +720,7 @@ class _MasterBase(MiniSoC, AMPSoC): [self.rtio_core.cri] + self.drtio_cri) self.register_kernel_cpu_csrdevice("cri_con") - self.submodules.rtio_analyzer = rtio.Analyzer(self.cri_con.switch.slave, + self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.cri_con.switch.slave, self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") @@ -799,6 +802,21 @@ class _SatelliteBase(BaseSoC): ~self.drtio_transceiver.stable_clkin.storage) self.comb += sfp_ctl.led.eq(self.drtio_transceiver.channels[0].rx_ready) + self.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) + + rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) + self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) + self.submodules.drtio0 = rx0(DRTIOSatellite( + self.rtio_tsc, self.drtio_transceiver.channels[0], + self.rx_synchronizer)) + self.csr_devices.append("drtio0") + self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, + self.drtio0.aux_controller.bus) + self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) + self.config["HAS_DRTIO"] = None + self.add_csr_group("drtio", ["drtio0"]) + self.add_memory_group("drtio_aux", ["drtio0_aux"]) + self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), @@ -829,18 +847,11 @@ class _SatelliteBase(BaseSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) - self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) - self.submodules.drtio0 = rx0(DRTIOSatellite( - self.drtio_transceiver.channels[0], rtio_channels, - self.rx_synchronizer)) - self.csr_devices.append("drtio0") - self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, - self.drtio0.aux_controller.bus) - self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) - self.config["HAS_DRTIO"] = None - self.add_csr_group("drtio", ["drtio0"]) - self.add_memory_group("drtio_aux", ["drtio0_aux"]) + self.submodules.drtio0_io = SyncRTIO(self.rtio_tsc, rtio_channels) + self.comb += [ + self.drtio0.cri.connect(self.drtio0_io.cri), + self.drtio0.async_errors.eq(self.drtio0_io.async_errors), + ] class Master(_MasterBase): From 19ae9ac1b1be5dc6225071113b7887c324c621da Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 12:07:24 +0800 Subject: [PATCH 1183/2457] kc705: adapt to TSC changes --- artiq/gateware/targets/kc705.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index eb32aedb2..24a11cf96 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -161,9 +161,10 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) self.csr_devices.append("rtio_crg") self.config["HAS_RTIO_CLOCK_SWITCH"] = None - self.submodules.rtio_core = rtio.Core(rtio_channels) + self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") @@ -180,7 +181,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.crg.cd_sys.clk, self.rtio_crg.cd_rtio.clk) - self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri, + self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.rtio_core.cri, self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") @@ -377,9 +378,10 @@ class SMA_SPI(_StandaloneBase): use_sma=False) self.csr_devices.append("rtio_crg") self.config["HAS_RTIO_CLOCK_SWITCH"] = None - self.submodules.rtio_core = rtio.Core(rtio_channels) + self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") @@ -395,7 +397,7 @@ class SMA_SPI(_StandaloneBase): self.crg.cd_sys.clk, self.rtio_crg.cd_rtio.clk) - self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri, + self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.rtio_core.cri, self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") From 1450e17a738477b680f8a500d2b5094713a0d174 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 12:10:41 +0800 Subject: [PATCH 1184/2457] sayma: adapt to TSC and DRTIOSatellite changes --- artiq/gateware/targets/sayma_amc.py | 41 +++++++++++++++++++---------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 289363184..3e925baa4 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -22,7 +22,7 @@ from artiq.gateware.rtio.phy import ttl_simple, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer -from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite +from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite, SyncRTIO from artiq.build_soc import * @@ -201,9 +201,10 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): self.cd_rtio.clk.eq(ClockSignal("jesd")), self.cd_rtio.rst.eq(ResetSignal("jesd")) ] - self.submodules.rtio_core = rtio.Core(rtio_channels) + self.submodules.rtio_tsc = rtio.TSC("async") + self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") @@ -215,12 +216,12 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_core.cri, + self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.rtio_core.cri, self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( - self.rtio_core.coarse_ts, self.ad9154_crg.jref) + self.rtio_tsc.coarse_ts, self.ad9154_crg.jref) self.csr_devices.append("sysref_sampler") @@ -283,6 +284,8 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") + self.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + drtio_csr_group = [] drtio_memory_group = [] drtio_cri = [] @@ -293,7 +296,7 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): drtio_memory_group.append(memory_name) core = ClockDomainsRenamer({"rtio_rx": "rtio_rx"+str(i)})( - DRTIOMaster(self.drtio_transceiver.channels[i])) + DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) setattr(self.submodules, core_name, core) drtio_cri.append(core.cri) self.csr_devices.append(core_name) @@ -357,10 +360,10 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.submodules.rtio_core = rtio.Core(rtio_channels, glbl_fine_ts_width=3) + self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") @@ -371,7 +374,7 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.register_kernel_cpu_csrdevice("cri_con") self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( - self.rtio_core.coarse_ts, self.ad9154_crg.jref) + self.rtio_tsc.coarse_ts, self.ad9154_crg.jref) self.csr_devices.append("sysref_sampler") @@ -427,6 +430,8 @@ class Master(MiniSoC, AMPSoC): rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") + self.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + drtio_csr_group = [] drtio_memory_group = [] drtio_cri = [] @@ -437,7 +442,7 @@ class Master(MiniSoC, AMPSoC): drtio_memory_group.append(memory_name) core = ClockDomainsRenamer({"rtio_rx": "rtio_rx"+str(i)})( - DRTIOMaster(self.drtio_transceiver.channels[i])) + DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) setattr(self.submodules, core_name, core) drtio_cri.append(core.cri) self.csr_devices.append(core_name) @@ -499,10 +504,10 @@ class Master(MiniSoC, AMPSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.submodules.rtio_core = rtio.Core(rtio_channels, glbl_fine_ts_width=3) + self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator() + self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( rtio.DMA(self.get_native_sdram_if())) self.register_kernel_cpu_csrdevice("rtio") @@ -583,10 +588,12 @@ class Satellite(BaseSoC, RTMCommon): rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") + self.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) + rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) self.submodules.drtio0 = rx0(DRTIOSatellite( - self.drtio_transceiver.channels[0], rtio_channels, + self.rtio_tsc, self.drtio_transceiver.channels[0], self.rx_synchronizer)) self.csr_devices.append("drtio0") self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, @@ -596,6 +603,12 @@ class Satellite(BaseSoC, RTMCommon): self.add_csr_group("drtio", ["drtio0"]) self.add_memory_group("drtio_aux", ["drtio0_aux"]) + self.submodules.drtio0_io = SyncRTIO(self.rtio_tsc, rtio_channels) + self.comb += [ + self.drtio0.cri.connect(self.drtio0_io.cri), + self.drtio0.async_errors.eq(self.drtio0_io.async_errors), + ] + self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), @@ -614,7 +627,7 @@ class Satellite(BaseSoC, RTMCommon): self.config["HAS_SI5324"] = None self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( - self.drtio0.coarse_ts, self.ad9154_crg.jref) + self.rtio_tsc.coarse_ts, self.ad9154_crg.jref) self.csr_devices.append("sysref_sampler") rtio_clk_period = 1e9/rtio_clk_freq From 5f20d79408fb6ee0fc81c712d4a1f44700f625b3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 14:00:09 +0800 Subject: [PATCH 1185/2457] drtio: add timeout on satellite internal CRI buffer space request --- artiq/firmware/satman/main.rs | 5 ++++- artiq/gateware/drtio/rt_errors_satellite.py | 3 ++- artiq/gateware/drtio/rt_packet_satellite.py | 10 ++++++++++ artiq/gateware/test/drtio/test_full_stack.py | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 849901e88..85143253d 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -210,6 +210,9 @@ fn process_errors() { error!("received truncated packet"); } if errors & 4 != 0 { + error!("timeout attempting to get buffer space from CRI") + } + if errors & 8 != 0 { let channel; let timestamp_event; let timestamp_counter; @@ -221,7 +224,7 @@ fn process_errors() { error!("write underflow, channel={}, timestamp={}, counter={}, slack={}", channel, timestamp_event, timestamp_counter, timestamp_event-timestamp_counter); } - if errors & 8 != 0 { + if errors & 16 != 0 { error!("write overflow"); } unsafe { diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index 764365730..2bf190a0f 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -8,7 +8,7 @@ from artiq.gateware.rtio.cdc import BlindTransfer class RTErrorsSatellite(Module, AutoCSR): def __init__(self, rt_packet, tsc, cri, async_errors): - self.protocol_error = CSR(4) + self.protocol_error = CSR(5) self.underflow_channel = CSRStatus(16) self.underflow_timestamp_event = CSRStatus(64) self.underflow_timestamp_counter = CSRStatus(64) @@ -68,6 +68,7 @@ class RTErrorsSatellite(Module, AutoCSR): error_csr(self.protocol_error, (rt_packet.unknown_packet_type, False, None, None), (rt_packet.packet_truncated, False, None, None), + (rt_packet.buffer_space_timeout, False, None, None), (underflow, True, underflow_error_cri, underflow_error_csr), (overflow, True, None, None) ) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 4760e11ac..1656f41cd 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -2,6 +2,7 @@ from migen import * from migen.genlib.fsm import * +from migen.genlib.misc import WaitTimer from artiq.gateware.rtio import cri from artiq.gateware.drtio.rt_serializer import * @@ -13,6 +14,7 @@ class RTPacketSatellite(Module): self.unknown_packet_type = Signal() self.packet_truncated = Signal() + self.buffer_space_timeout = Signal() self.tsc_load = Signal() self.tsc_load_value = Signal(64) @@ -105,6 +107,9 @@ class RTPacketSatellite(Module): ongoing_packet = Signal() self.sync += ongoing_packet.eq(ongoing_packet_next) + timeout_counter = WaitTimer(8191) + self.submodules += timeout_counter + rx_fsm.act("INPUT", If(rx_dp.frame_r, rx_dp.packet_buffer_load.eq(1), @@ -149,6 +154,11 @@ class RTPacketSatellite(Module): NextState("BUFFER_SPACE") ) rx_fsm.act("BUFFER_SPACE", + timeout_counter.wait.eq(1), + If(timeout_counter.done, + self.buffer_space_timeout.eq(1), + NextState("INPUT") + ), If(self.cri.o_buffer_space_valid, buffer_space_set.eq(1), buffer_space_update.eq(1), diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index eafb438c1..69f89b094 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -236,7 +236,7 @@ class TestFullStack(unittest.TestCase): errors = yield from saterr.protocol_error.read() underflow_channel = yield from saterr.underflow_channel.read() underflow_timestamp_event = yield from saterr.underflow_timestamp_event.read() - self.assertEqual(errors, 4) # write underflow + self.assertEqual(errors, 8) # write underflow self.assertEqual(underflow_channel, 42) self.assertEqual(underflow_timestamp_event, 100) yield from saterr.protocol_error.write(errors) From 839f748a1dda4089a23e933945f2dd1081b83e85 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 15:55:20 +0800 Subject: [PATCH 1186/2457] drtio: add external TSC to repeater --- artiq/gateware/drtio/core.py | 4 ++-- artiq/gateware/drtio/rt_packet_repeater.py | 5 ++--- .../test/drtio/test_rt_packet_repeater.py | 19 +++++++++++-------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 47a56ce0c..13afbab46 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -181,13 +181,13 @@ class DRTIOMaster(Module): class DRTIORepeater(Module): - def __init__(self, chanif): + def __init__(self, tsc, chanif): self.submodules.link_layer = link_layer.LinkLayer( chanif.encoder, chanif.decoders) self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready) self.submodules.link_stats = link_layer.LinkLayerStats(self.link_layer, "rtio_rx") - self.submodules.rt_packet = rt_packet_repeater.RTPacketRepeater(self.link_layer) + self.submodules.rt_packet = rt_packet_repeater.RTPacketRepeater(tsc, self.link_layer) self.submodules.aux_controller = aux_controller.AuxController( self.link_layer) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 081d444a3..379a445ec 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -9,7 +9,7 @@ from artiq.gateware.drtio.rt_serializer import * class RTPacketRepeater(Module): - def __init__(self, link_layer): + def __init__(self, tsc, link_layer): # CRI target interface in rtio domain self.cri = cri.Interface() @@ -24,7 +24,6 @@ class RTPacketRepeater(Module): # set_time interface, in rtio domain self.set_time_stb = Signal() self.set_time_ack = Signal() - self.tsc_value = Signal(64) # # # @@ -44,7 +43,7 @@ class RTPacketRepeater(Module): # TSC sync tsc_value = Signal(64) tsc_value_load = Signal() - self.sync.rtio += If(tsc_value_load, tsc_value.eq(self.tsc_value)) + self.sync.rtio += If(tsc_value_load, tsc_value.eq(tsc.coarse_ts)) # Write buffer and extra data count wb_timestamp = Signal(64) diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index c778d1724..d348a5efc 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -11,20 +11,23 @@ from artiq.gateware.drtio.rt_packet_repeater import RTPacketRepeater def create_dut(nwords): pt = PacketInterface("s2m", nwords*8) pr = PacketInterface("m2s", nwords*8) + ts = Signal(64) dut = ClockDomainsRenamer({"rtio": "sys", "rtio_rx": "sys"})( - RTPacketRepeater(SimpleNamespace( - rx_rt_frame=pt.frame, rx_rt_data=pt.data, - tx_rt_frame=pr.frame, tx_rt_data=pr.data))) - return pt, pr, dut + RTPacketRepeater( + SimpleNamespace(coarse_ts=ts), + SimpleNamespace( + rx_rt_frame=pt.frame, rx_rt_data=pt.data, + tx_rt_frame=pr.frame, tx_rt_data=pr.data))) + return pt, pr, ts, dut class TestRepeater(unittest.TestCase): def test_set_time(self): nwords = 2 - pt, pr, dut = create_dut(nwords) + pt, pr, ts, dut = create_dut(nwords) def send(): - yield dut.tsc_value.eq(0x12345678) + yield ts.eq(0x12345678) yield dut.set_time_stb.eq(1) while not (yield dut.set_time_ack): yield @@ -55,7 +58,7 @@ class TestRepeater(unittest.TestCase): ] for nwords in range(1, 8): - pt, pr, dut = create_dut(nwords) + pt, pr, ts, dut = create_dut(nwords) def send(): for channel, timestamp, address, data in test_writes: @@ -89,7 +92,7 @@ class TestRepeater(unittest.TestCase): def test_buffer_space(self): for nwords in range(1, 8): - pt, pr, dut = create_dut(nwords) + pt, pr, ts, dut = create_dut(nwords) def send_requests(): for i in range(10): From 2884d595b363428388790dc06904e59dfc4cd4bf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 16:08:40 +0800 Subject: [PATCH 1187/2457] drtio: add rt_controller_repeater --- artiq/gateware/drtio/core.py | 5 ++- .../gateware/drtio/rt_controller_repeater.py | 42 +++++++++++++++++++ artiq/gateware/drtio/rt_packet_repeater.py | 8 ++-- 3 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 artiq/gateware/drtio/rt_controller_repeater.py diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 13afbab46..f7a625e09 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -10,7 +10,8 @@ from artiq.gateware.rtio.sed.core import * from artiq.gateware.rtio.input_collector import * from artiq.gateware.drtio import (link_layer, aux_controller, rt_packet_satellite, rt_errors_satellite, - rt_packet_master, rt_controller_master) + rt_packet_master, rt_controller_master, + rt_controller_repeater) from artiq.gateware.drtio.rx_synchronizer import GenericRXSynchronizer @@ -188,6 +189,7 @@ class DRTIORepeater(Module): self.submodules.link_stats = link_layer.LinkLayerStats(self.link_layer, "rtio_rx") self.submodules.rt_packet = rt_packet_repeater.RTPacketRepeater(tsc, self.link_layer) + self.submodules.rt_controller = rt_controller_repeater.RTController(self.rt_packet) self.submodules.aux_controller = aux_controller.AuxController( self.link_layer) @@ -195,6 +197,7 @@ class DRTIORepeater(Module): def get_csrs(self): return (self.link_layer.get_csrs() + self.link_stats.get_csrs() + + self.rt_controller.get_csrs() + self.aux_controller.get_csrs()) @property diff --git a/artiq/gateware/drtio/rt_controller_repeater.py b/artiq/gateware/drtio/rt_controller_repeater.py new file mode 100644 index 000000000..97de2d70e --- /dev/null +++ b/artiq/gateware/drtio/rt_controller_repeater.py @@ -0,0 +1,42 @@ +from migen import * + +from misoc.interconnect.csr import * + +from artiq.gateware.rtio.cdc import BlindTransfer + + +class RTController(Module, AutoCSR): + def __init__(self, rt_packet): + self.set_time = CSR() + self.protocol_error = CSR(4) + + set_time_stb = Signal() + set_time_ack = Signal() + self.submodules += CrossDomainRequest("rtio", + set_time_stb, set_time_ack, None, + rt_packet.set_time_stb, rt_packet.set_time_ack, None) + self.sync += [ + If(set_time_ack, set_time_stb.eq(0)), + If(self.set_time.re, set_time_stb.eq(1)) + ] + self.comb += self.set_time.w.eq(set_time_stb) + + errors = [ + (rt_packet.err_unknown_packet_type, "rtio_rx"), + (rt_packet.err_packet_truncated, "rtio_rx"), + (rt_packet.err_command_missed, "rtio"), + (rt_packet.err_buffer_space_timeout, "rtio") + ] + + for n, (err_i, err_cd) in enumerate(errors): + xfer = BlindTransfer(err_cd, "sys") + self.submodules += xfer + + self.comb += xfer.i.eq(err_i) + + err_pending = Signal() + self.sync += [ + If(self.protocol_error.re & self.protocol_error.r[n], err_pending.eq(0)), + If(xfer.o, err_pending.eq(1)) + ] + self.comb += self.protocol_error.w[n].eq(err_pending) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 379a445ec..5ccd8dd70 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -18,8 +18,8 @@ class RTPacketRepeater(Module): self.err_packet_truncated = Signal() # in rtio domain - self.command_missed = Signal() - self.buffer_space_timeout = Signal() + self.err_command_missed = Signal() + self.err_buffer_space_timeout = Signal() # set_time interface, in rtio domain self.set_time_stb = Signal() @@ -103,7 +103,7 @@ class RTPacketRepeater(Module): # Missed commands cri_ready = Signal() - self.sync.rtio += self.command_missed.eq(~cri_ready & (self.cri.cmd != cri.commands["nop"])) + self.sync.rtio += self.err_command_missed.eq(~cri_ready & (self.cri.cmd != cri.commands["nop"])) # TX FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) @@ -158,7 +158,7 @@ class RTPacketRepeater(Module): tx_fsm.act("WAIT_BUFFER_SPACE", timeout_counter.wait.eq(1), If(timeout_counter.done, - self.buffer_space_timeout.eq(1), + self.err_buffer_space_timeout.eq(1), NextState("IDLE") ).Else( If(buffer_space_not, From 92be9324df06aea4ae8a925a0b4400977b0f6a18 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 16:09:02 +0800 Subject: [PATCH 1188/2457] add missing files --- artiq/gateware/drtio/cdc.py | 55 +++++++++++++++++++++++++++++++++++++ artiq/gateware/rtio/tsc.py | 48 ++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 artiq/gateware/drtio/cdc.py create mode 100644 artiq/gateware/rtio/tsc.py diff --git a/artiq/gateware/drtio/cdc.py b/artiq/gateware/drtio/cdc.py new file mode 100644 index 000000000..9edd8a1b4 --- /dev/null +++ b/artiq/gateware/drtio/cdc.py @@ -0,0 +1,55 @@ +from migen import * + +from migen.genlib.cdc import PulseSynchronizer + + +class CrossDomainRequest(Module): + def __init__(self, domain, + req_stb, req_ack, req_data, + srv_stb, srv_ack, srv_data): + dsync = getattr(self.sync, domain) + + request = PulseSynchronizer("sys", domain) + reply = PulseSynchronizer(domain, "sys") + self.submodules += request, reply + + ongoing = Signal() + self.comb += request.i.eq(~ongoing & req_stb) + self.sync += [ + req_ack.eq(reply.o), + If(req_stb, ongoing.eq(1)), + If(req_ack, ongoing.eq(0)) + ] + if req_data is not None: + req_data_r = Signal.like(req_data) + req_data_r.attr.add("no_retiming") + self.sync += If(req_stb, req_data_r.eq(req_data)) + dsync += [ + If(request.o, srv_stb.eq(1)), + If(srv_ack, srv_stb.eq(0)) + ] + if req_data is not None: + dsync += If(request.o, srv_data.eq(req_data_r)) + self.comb += reply.i.eq(srv_stb & srv_ack) + + +class CrossDomainNotification(Module): + def __init__(self, domain, rdomain, + emi_stb, emi_data, + rec_stb, rec_ack, rec_data): + emi_data_r = Signal(len(emi_data)) + emi_data_r.attr.add("no_retiming") + dsync = getattr(self.sync, domain) + dsync += If(emi_stb, emi_data_r.eq(emi_data)) + + ps = PulseSynchronizer(domain, rdomain) + self.submodules += ps + self.comb += ps.i.eq(emi_stb) + rsync = getattr(self.sync, rdomain) + rsync += [ + If(rec_ack, rec_stb.eq(0)), + If(ps.o, + rec_data.eq(emi_data_r), + rec_stb.eq(1) + ) + ] diff --git a/artiq/gateware/rtio/tsc.py b/artiq/gateware/rtio/tsc.py new file mode 100644 index 000000000..e93744553 --- /dev/null +++ b/artiq/gateware/rtio/tsc.py @@ -0,0 +1,48 @@ +from migen import * + +from artiq.gateware.rtio.cdc import GrayCodeTransfer + + +class TSC(Module): + def __init__(self, mode, glbl_fine_ts_width=0): + self.glbl_fine_ts_width = glbl_fine_ts_width + + # in rtio domain + self.coarse_ts = Signal(64 - glbl_fine_ts_width) + self.full_ts = Signal(64) + + # in sys domain + # monotonic, may lag behind the counter in the IO clock domain, but + # not be ahead of it. + self.coarse_ts_sys = Signal.like(self.coarse_ts) + self.full_ts_sys = Signal(64) + + # in rtio domain + self.load = Signal() + self.load_value = Signal.like(self.coarse_ts) + + if mode == "async": + self.full_ts_cri = self.full_ts_sys + elif mode == "sync": + self.full_ts_cri = self.full_ts + else: + raise ValueError + + # # # + + self.sync.rtio += If(self.load, + self.coarse_ts.eq(self.load_value) + ).Else( + self.coarse_ts.eq(self.coarse_ts + 1) + ) + coarse_ts_cdc = GrayCodeTransfer(len(self.coarse_ts)) # from rtio to sys + self.submodules += coarse_ts_cdc + self.comb += [ + coarse_ts_cdc.i.eq(self.coarse_ts), + self.coarse_ts_sys.eq(coarse_ts_cdc.o) + ] + + self.comb += [ + self.full_ts.eq(self.coarse_ts << glbl_fine_ts_width), + self.full_ts_sys.eq(self.coarse_ts_sys << glbl_fine_ts_width) + ] From 87e0384e97fa2f26497e8a70fd322d1de569abbf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Sep 2018 17:56:56 +0800 Subject: [PATCH 1189/2457] drtio: separate aux controller This helps with managing CSR groups and heterogeneous (satellite/repeaters) DRTIO cores. --- artiq/firmware/libboard_artiq/drtioaux.rs | 30 +++---- artiq/firmware/satman/main.rs | 34 ++++---- artiq/gateware/drtio/__init__.py | 2 +- artiq/gateware/drtio/aux_controller.py | 2 +- artiq/gateware/drtio/core.py | 19 +---- artiq/gateware/targets/kasli.py | 54 ++++++++----- artiq/gateware/targets/sayma_amc.py | 81 ++++++++++++------- .../test/drtio/test_aux_controller.py | 2 +- 8 files changed, 123 insertions(+), 101 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtioaux.rs b/artiq/firmware/libboard_artiq/drtioaux.rs index 97a06e3b2..9c189e148 100644 --- a/artiq/firmware/libboard_artiq/drtioaux.rs +++ b/artiq/firmware/libboard_artiq/drtioaux.rs @@ -2,7 +2,7 @@ use core::slice; use crc; use io::{ProtoRead, ProtoWrite, Cursor, Error as IoError}; -use board_misoc::{csr::DRTIO, mem::DRTIO_AUX, clock}; +use board_misoc::{csr::DRTIOAUX, mem::DRTIOAUX_MEM, clock}; use proto_artiq::drtioaux_proto::Error as ProtocolError; pub use proto_artiq::drtioaux_proto::Packet; @@ -40,17 +40,17 @@ pub fn reset(linkno: u8) { // clear buffer first to limit race window with buffer overflow // error. We assume the CPU is fast enough so that no two packets // will be received between the buffer and the error flag are cleared. - (DRTIO[linkno].aux_rx_present_write)(1); - (DRTIO[linkno].aux_rx_error_write)(1); + (DRTIOAUX[linkno].aux_rx_present_write)(1); + (DRTIOAUX[linkno].aux_rx_error_write)(1); } } fn has_rx_error(linkno: u8) -> bool { let linkno = linkno as usize; unsafe { - let error = (DRTIO[linkno].aux_rx_error_read)() != 0; + let error = (DRTIOAUX[linkno].aux_rx_error_read)() != 0; if error { - (DRTIO[linkno].aux_rx_error_write)(1) + (DRTIOAUX[linkno].aux_rx_error_write)(1) } error } @@ -61,11 +61,11 @@ fn receive(linkno: u8, f: F) -> Result, Error> { let linkidx = linkno as usize; unsafe { - if (DRTIO[linkidx].aux_rx_present_read)() == 1 { - let ptr = DRTIO_AUX[linkidx].base + DRTIO_AUX[linkidx].size / 2; - let len = (DRTIO[linkidx].aux_rx_length_read)(); + if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 { + let ptr = DRTIOAUX_MEM[linkidx].base + DRTIOAUX_MEM[linkidx].size / 2; + let len = (DRTIOAUX[linkidx].aux_rx_length_read)(); let result = f(slice::from_raw_parts(ptr as *mut u8, len as usize)); - (DRTIO[linkidx].aux_rx_present_write)(1); + (DRTIOAUX[linkidx].aux_rx_present_write)(1); Ok(Some(result?)) } else { Ok(None) @@ -114,12 +114,12 @@ fn transmit(linkno: u8, f: F) -> Result<(), Error> { let linkno = linkno as usize; unsafe { - while (DRTIO[linkno].aux_tx_read)() != 0 {} - let ptr = DRTIO_AUX[linkno].base; - let len = DRTIO_AUX[linkno].size / 2; + while (DRTIOAUX[linkno].aux_tx_read)() != 0 {} + let ptr = DRTIOAUX_MEM[linkno].base; + let len = DRTIOAUX_MEM[linkno].size / 2; let len = f(slice::from_raw_parts_mut(ptr as *mut u8, len))?; - (DRTIO[linkno].aux_tx_length_write)(len as u16); - (DRTIO[linkno].aux_tx_write)(1); + (DRTIOAUX[linkno].aux_tx_length_write)(len as u16); + (DRTIOAUX[linkno].aux_tx_write)(1); Ok(()) } } @@ -146,7 +146,7 @@ pub fn send_link(linkno: u8, packet: &Packet) -> Result<(), Error> { // TODO: routing fn get_linkno(nodeno: u8) -> Result> { - if nodeno == 0 || nodeno as usize > DRTIO.len() { + if nodeno == 0 || nodeno as usize > DRTIOAUX.len() { return Err(Error::NoRoute) } Ok(nodeno - 1) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 85143253d..c7e7fb73e 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -16,21 +16,21 @@ use board_artiq::hmc830_7043; fn drtio_reset(reset: bool) { unsafe { - (csr::DRTIO[0].reset_write)(if reset { 1 } else { 0 }); + csr::drtiosat::reset_write(if reset { 1 } else { 0 }); } } fn drtio_reset_phy(reset: bool) { unsafe { - (csr::DRTIO[0].reset_phy_write)(if reset { 1 } else { 0 }); + csr::drtiosat::reset_phy_write(if reset { 1 } else { 0 }); } } fn drtio_tsc_loaded() -> bool { unsafe { - let tsc_loaded = (csr::DRTIO[0].tsc_loaded_read)() == 1; + let tsc_loaded = csr::drtiosat::tsc_loaded_read() == 1; if tsc_loaded { - (csr::DRTIO[0].tsc_loaded_write)(1); + csr::drtiosat::tsc_loaded_write(1); } tsc_loaded } @@ -56,29 +56,29 @@ fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error drtioaux::Packet::RtioErrorRequest => { let errors; unsafe { - errors = (csr::DRTIO[0].rtio_error_read)(); + errors = csr::drtiosat::rtio_error_read(); } if errors & 1 != 0 { let channel; unsafe { - channel = (csr::DRTIO[0].sequence_error_channel_read)(); - (csr::DRTIO[0].rtio_error_write)(1); + channel = csr::drtiosat::sequence_error_channel_read(); + csr::drtiosat::rtio_error_write(1); } drtioaux::send_link(0, &drtioaux::Packet::RtioErrorSequenceErrorReply { channel }) } else if errors & 2 != 0 { let channel; unsafe { - channel = (csr::DRTIO[0].collision_channel_read)(); - (csr::DRTIO[0].rtio_error_write)(2); + channel = csr::drtiosat::collision_channel_read(); + csr::drtiosat::rtio_error_write(2); } drtioaux::send_link(0, &drtioaux::Packet::RtioErrorCollisionReply { channel }) } else if errors & 4 != 0 { let channel; unsafe { - channel = (csr::DRTIO[0].busy_channel_read)(); - (csr::DRTIO[0].rtio_error_write)(4); + channel = csr::drtiosat::busy_channel_read(); + csr::drtiosat::rtio_error_write(4); } drtioaux::send_link(0, &drtioaux::Packet::RtioErrorBusyReply { channel }) @@ -201,7 +201,7 @@ fn process_aux_packets() { fn process_errors() { let errors; unsafe { - errors = (csr::DRTIO[0].protocol_error_read)(); + errors = csr::drtiosat::protocol_error_read(); } if errors & 1 != 0 { error!("received packet of an unknown type"); @@ -217,9 +217,9 @@ fn process_errors() { let timestamp_event; let timestamp_counter; unsafe { - channel = (csr::DRTIO[0].underflow_channel_read)(); - timestamp_event = (csr::DRTIO[0].underflow_timestamp_event_read)() as i64; - timestamp_counter = (csr::DRTIO[0].underflow_timestamp_counter_read)() as i64; + channel = csr::drtiosat::underflow_channel_read(); + timestamp_event = csr::drtiosat::underflow_timestamp_event_read() as i64; + timestamp_counter = csr::drtiosat::underflow_timestamp_counter_read() as i64; } error!("write underflow, channel={}, timestamp={}, counter={}, slack={}", channel, timestamp_event, timestamp_counter, timestamp_event-timestamp_counter); @@ -228,7 +228,7 @@ fn process_errors() { error!("write overflow"); } unsafe { - (csr::DRTIO[0].protocol_error_write)(errors); + csr::drtiosat::protocol_error_write(errors); } } @@ -247,7 +247,7 @@ const SI5324_SETTINGS: si5324::FrequencySettings fn drtio_link_rx_up() -> bool { unsafe { - (csr::DRTIO[0].rx_up_read)() == 1 + csr::drtiosat::rx_up_read() == 1 } } diff --git a/artiq/gateware/drtio/__init__.py b/artiq/gateware/drtio/__init__.py index 76cb979c7..6efb44361 100644 --- a/artiq/gateware/drtio/__init__.py +++ b/artiq/gateware/drtio/__init__.py @@ -1,2 +1,2 @@ from artiq.gateware.drtio.core import SyncRTIO, DRTIOSatellite, DRTIOMaster, DRTIORepeater - +from artiq.gateware.drtio.aux_controller import DRTIOAuxController diff --git a/artiq/gateware/drtio/aux_controller.py b/artiq/gateware/drtio/aux_controller.py index b60167dea..8effda67d 100644 --- a/artiq/gateware/drtio/aux_controller.py +++ b/artiq/gateware/drtio/aux_controller.py @@ -211,7 +211,7 @@ class Receiver(Module, AutoCSR): # TODO: FullMemoryWE should be applied by migen.build @FullMemoryWE() -class AuxController(Module): +class DRTIOAuxController(Module): def __init__(self, link_layer): self.bus = wishbone.Interface() self.submodules.transmitter = Transmitter(link_layer, len(self.bus.dat_w)) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index f7a625e09..b1fd8a88a 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -8,7 +8,7 @@ from misoc.interconnect.csr import * from artiq.gateware.rtio import cri, rtlink from artiq.gateware.rtio.sed.core import * from artiq.gateware.rtio.input_collector import * -from artiq.gateware.drtio import (link_layer, aux_controller, +from artiq.gateware.drtio import (link_layer, rt_packet_satellite, rt_errors_satellite, rt_packet_master, rt_controller_master, rt_controller_repeater) @@ -145,13 +145,10 @@ class DRTIOSatellite(Module): self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite( self.rt_packet, tsc, self.cri, self.async_errors) - self.submodules.aux_controller = aux_controller.AuxController( - self.link_layer) - def get_csrs(self): return ([self.reset, self.reset_phy, self.tsc_loaded] + self.link_layer.get_csrs() + self.link_stats.get_csrs() + - self.rt_errors.get_csrs() + self.aux_controller.get_csrs()) + self.rt_errors.get_csrs()) class DRTIOMaster(Module): @@ -166,15 +163,11 @@ class DRTIOMaster(Module): tsc, self.rt_packet) self.submodules.rt_manager = rt_controller_master.RTManager(self.rt_packet) - self.submodules.aux_controller = aux_controller.AuxController( - self.link_layer) - def get_csrs(self): return (self.link_layer.get_csrs() + self.link_stats.get_csrs() + self.rt_controller.get_csrs() + - self.rt_manager.get_csrs() + - self.aux_controller.get_csrs()) + self.rt_manager.get_csrs()) @property def cri(self): @@ -191,14 +184,10 @@ class DRTIORepeater(Module): self.submodules.rt_packet = rt_packet_repeater.RTPacketRepeater(tsc, self.link_layer) self.submodules.rt_controller = rt_controller_repeater.RTController(self.rt_packet) - self.submodules.aux_controller = aux_controller.AuxController( - self.link_layer) - def get_csrs(self): return (self.link_layer.get_csrs() + self.link_stats.get_csrs() + - self.rt_controller.get_csrs() + - self.aux_controller.get_csrs()) + self.rt_controller.get_csrs()) @property def cri(self): diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b8d1be155..0aa181ca3 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -21,7 +21,7 @@ from artiq.gateware import eem from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer -from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite, SyncRTIO +from artiq.gateware.drtio import * from artiq.build_soc import * @@ -622,7 +622,7 @@ class _MasterBase(MiniSoC, AMPSoC): "cri_con": 0x10000000, "rtio": 0x20000000, "rtio_dma": 0x30000000, - "drtio_aux": 0x50000000, + "drtioaux": 0x50000000, "mailbox": 0x70000000 } mem_map.update(MiniSoC.mem_map) @@ -666,27 +666,36 @@ class _MasterBase(MiniSoC, AMPSoC): self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) drtio_csr_group = [] - drtio_memory_group = [] + drtioaux_csr_group = [] + drtioaux_memory_group = [] self.drtio_cri = [] for i in range(2): core_name = "drtio" + str(i) - memory_name = "drtio" + str(i) + "_aux" + coreaux_name = "drtioaux" + str(i) + memory_name = "drtioaux" + str(i) + "_mem" drtio_csr_group.append(core_name) - drtio_memory_group.append(memory_name) + drtioaux_csr_group.append(coreaux_name) + drtioaux_memory_group.append(memory_name) - core = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)})( - DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) + cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)}) + + core = cdr(DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) setattr(self.submodules, core_name, core) self.drtio_cri.append(core.cri) self.csr_devices.append(core_name) - memory_address = self.mem_map["drtio_aux"] + 0x800*i + coreaux = cdr(DRTIOAuxController(core.link_layer)) + setattr(self.submodules, coreaux_name, coreaux) + self.csr_devices.append(coreaux_name) + + memory_address = self.mem_map["drtioaux"] + 0x800*i self.add_wb_slave(memory_address, 0x800, - core.aux_controller.bus) + coreaux.bus) self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None self.add_csr_group("drtio", drtio_csr_group) - self.add_memory_group("drtio_aux", drtio_memory_group) + self.add_csr_group("drtioaux", drtioaux_csr_group) + self.add_memory_group("drtioaux_mem", drtioaux_memory_group) rtio_clk_period = 1e9/rtio_clk_freq gtp = self.drtio_transceiver.gtps[0] @@ -759,7 +768,7 @@ class _MasterBase(MiniSoC, AMPSoC): class _SatelliteBase(BaseSoC): mem_map = { - "drtio_aux": 0x50000000, + "drtioaux": 0x50000000, } mem_map.update(BaseSoC.mem_map) @@ -806,16 +815,19 @@ class _SatelliteBase(BaseSoC): rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) - self.submodules.drtio0 = rx0(DRTIOSatellite( + self.submodules.drtiosat = rx0(DRTIOSatellite( self.rtio_tsc, self.drtio_transceiver.channels[0], self.rx_synchronizer)) - self.csr_devices.append("drtio0") - self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, - self.drtio0.aux_controller.bus) - self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) + self.csr_devices.append("drtiosat") + self.submodules.drtioaux0 = rx0(DRTIOAuxController( + self.drtiosat.link_layer)) + self.csr_devices.append("drtioaux0") + self.add_wb_slave(self.mem_map["drtioaux"], 0x800, + self.drtioaux0.bus) + self.add_memory_region("drtioaux0_mem", self.mem_map["drtioaux"] | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None - self.add_csr_group("drtio", ["drtio0"]) - self.add_memory_group("drtio_aux", ["drtio0_aux"]) + self.add_csr_group("drtioaux", ["drtioaux0"]) + self.add_memory_group("drtioaux_mem", ["drtioaux0_mem"]) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( @@ -847,10 +859,10 @@ class _SatelliteBase(BaseSoC): self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") - self.submodules.drtio0_io = SyncRTIO(self.rtio_tsc, rtio_channels) + self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels) self.comb += [ - self.drtio0.cri.connect(self.drtio0_io.cri), - self.drtio0.async_errors.eq(self.drtio0_io.async_errors), + self.drtiosat.cri.connect(self.local_io.cri), + self.drtiosat.async_errors.eq(self.local_io.async_errors) ] diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 3e925baa4..0c731002a 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -22,7 +22,7 @@ from artiq.gateware.rtio.phy import ttl_simple, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer -from artiq.gateware.drtio import DRTIOMaster, DRTIOSatellite, SyncRTIO +from artiq.gateware.drtio import * from artiq.build_soc import * @@ -234,7 +234,7 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): "rtio": 0x11000000, "rtio_dma": 0x12000000, "serwb": 0x13000000, - "drtio_aux": 0x14000000, + "drtioaux": 0x14000000, "mailbox": 0x70000000 } mem_map.update(MiniSoC.mem_map) @@ -287,27 +287,36 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) drtio_csr_group = [] - drtio_memory_group = [] + drtioaux_csr_group = [] + drtioaux_memory_group = [] drtio_cri = [] for i in range(2): core_name = "drtio" + str(i) - memory_name = "drtio" + str(i) + "_aux" + coreaux_name = "drtioaux" + str(i) + memory_name = "drtioaux" + str(i) + "_mem" drtio_csr_group.append(core_name) - drtio_memory_group.append(memory_name) + drtioaux_csr_group.append(coreaux_name) + drtioaux_memory_group.append(memory_name) - core = ClockDomainsRenamer({"rtio_rx": "rtio_rx"+str(i)})( - DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) + cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)}) + + core = cdr(DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) setattr(self.submodules, core_name, core) drtio_cri.append(core.cri) self.csr_devices.append(core_name) - memory_address = self.mem_map["drtio_aux"] + 0x800*i + coreaux = cdr(DRTIOAuxController(core.link_layer)) + setattr(self.submodules, coreaux_name, coreaux) + self.csr_devices.append(coreaux_name) + + memory_address = self.mem_map["drtioaux"] + 0x800*i self.add_wb_slave(memory_address, 0x800, - core.aux_controller.bus) + coreaux.bus) self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None self.add_csr_group("drtio", drtio_csr_group) - self.add_memory_group("drtio_aux", drtio_memory_group) + self.add_csr_group("drtioaux", drtioaux_csr_group) + self.add_memory_group("drtioaux_mem", drtioaux_memory_group) rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] @@ -389,7 +398,7 @@ class Master(MiniSoC, AMPSoC): "cri_con": 0x10000000, "rtio": 0x11000000, "rtio_dma": 0x12000000, - "drtio_aux": 0x14000000, + "drtioaux": 0x14000000, "mailbox": 0x70000000 } mem_map.update(MiniSoC.mem_map) @@ -433,27 +442,36 @@ class Master(MiniSoC, AMPSoC): self.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) drtio_csr_group = [] - drtio_memory_group = [] + drtioaux_csr_group = [] + drtioaux_memory_group = [] drtio_cri = [] for i in range(10): core_name = "drtio" + str(i) - memory_name = "drtio" + str(i) + "_aux" + coreaux_name = "drtioaux" + str(i) + memory_name = "drtioaux" + str(i) + "_mem" drtio_csr_group.append(core_name) - drtio_memory_group.append(memory_name) + drtioaux_csr_group.append(coreaux_name) + drtioaux_memory_group.append(memory_name) - core = ClockDomainsRenamer({"rtio_rx": "rtio_rx"+str(i)})( - DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) + cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)}) + + core = cdr(DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) setattr(self.submodules, core_name, core) drtio_cri.append(core.cri) self.csr_devices.append(core_name) - memory_address = self.mem_map["drtio_aux"] + 0x800*i + coreaux = cdr(DRTIOAuxController(core.link_layer)) + setattr(self.submodules, coreaux_name, coreaux) + self.csr_devices.append(coreaux_name) + + memory_address = self.mem_map["drtioaux"] + 0x800*i self.add_wb_slave(memory_address, 0x800, - core.aux_controller.bus) + coreaux.bus) self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None self.add_csr_group("drtio", drtio_csr_group) - self.add_memory_group("drtio_aux", drtio_memory_group) + self.add_csr_group("drtioaux", drtioaux_csr_group) + self.add_memory_group("drtioaux_mem", drtioaux_memory_group) rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] @@ -525,7 +543,7 @@ class Satellite(BaseSoC, RTMCommon): """ mem_map = { "serwb": 0x13000000, - "drtio_aux": 0x14000000, + "drtioaux": 0x14000000, } mem_map.update(BaseSoC.mem_map) @@ -592,21 +610,24 @@ class Satellite(BaseSoC, RTMCommon): rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) - self.submodules.drtio0 = rx0(DRTIOSatellite( + self.submodules.drtiosat = rx0(DRTIOSatellite( self.rtio_tsc, self.drtio_transceiver.channels[0], self.rx_synchronizer)) - self.csr_devices.append("drtio0") - self.add_wb_slave(self.mem_map["drtio_aux"], 0x800, - self.drtio0.aux_controller.bus) - self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800) + self.csr_devices.append("drtiosat") + self.submodules.drtioaux0 = rx0(DRTIOAuxController( + self.drtiosat.link_layer)) + self.csr_devices.append("drtioaux0") + self.add_wb_slave(self.mem_map["drtioaux"], 0x800, + self.drtioaux0.bus) + self.add_memory_region("drtioaux0_mem", self.mem_map["drtioaux"] | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None - self.add_csr_group("drtio", ["drtio0"]) - self.add_memory_group("drtio_aux", ["drtio0_aux"]) + self.add_csr_group("drtioaux", ["drtioaux0"]) + self.add_memory_group("drtioaux_mem", ["drtioaux0_mem"]) - self.submodules.drtio0_io = SyncRTIO(self.rtio_tsc, rtio_channels) + self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels) self.comb += [ - self.drtio0.cri.connect(self.drtio0_io.cri), - self.drtio0.async_errors.eq(self.drtio0_io.async_errors), + self.drtiosat.cri.connect(self.local_io.cri), + self.drtiosat.async_errors.eq(self.local_io.async_errors), ] self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) diff --git a/artiq/gateware/test/drtio/test_aux_controller.py b/artiq/gateware/test/drtio/test_aux_controller.py index f07f5eb6d..64e2e15d7 100644 --- a/artiq/gateware/test/drtio/test_aux_controller.py +++ b/artiq/gateware/test/drtio/test_aux_controller.py @@ -36,7 +36,7 @@ class TB(Module): def __init__(self, nwords): self.submodules.link_layer = Loopback(nwords) self.submodules.aux_controller = ClockDomainsRenamer( - {"rtio": "sys", "rtio_rx": "sys"})(AuxController(self.link_layer)) + {"rtio": "sys", "rtio_rx": "sys"})(DRTIOAuxController(self.link_layer)) class TestAuxController(unittest.TestCase): From 4d73fb5bc9773a546980d6e08737f276e84a3c9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 6 Sep 2018 11:01:08 +0200 Subject: [PATCH 1190/2457] grabber: only advance when DVAL --- artiq/gateware/grabber/core.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/grabber/core.py b/artiq/gateware/grabber/core.py index d9dac3d12..60c40ce2d 100644 --- a/artiq/gateware/grabber/core.py +++ b/artiq/gateware/grabber/core.py @@ -85,10 +85,12 @@ class Parser(Module, AutoCSR): self.sync.cl += [ last_lval.eq(lval), last_fval.eq(fval), - pix.x.eq(pix.x + 1), + If(dval, + pix.x.eq(pix.x + 1), + ), If(~lval, - pix.x.eq(0), If(last_lval, last_x.eq(pix.x)), + pix.x.eq(0), If(last_fval & last_lval, pix.y.eq(pix.y + 1) ) From ec62eb937352ae9559b2ae3a394273a620d1e932 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 30 Aug 2018 15:15:32 +0800 Subject: [PATCH 1191/2457] drtio: minor cleanup --- artiq/gateware/drtio/core.py | 9 ++++++--- artiq/gateware/drtio/rt_controller_master.py | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 38c6d8a2a..8eee8f4d0 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -128,7 +128,7 @@ class DRTIOSatellite(Module): class DRTIOMaster(Module): - def __init__(self, chanif, channel_count=1024, fine_ts_width=3): + def __init__(self, chanif, fine_ts_width=3): self.submodules.link_layer = link_layer.LinkLayer( chanif.encoder, chanif.decoders) self.comb += self.link_layer.rx_ready.eq(chanif.rx_ready) @@ -136,9 +136,8 @@ class DRTIOMaster(Module): self.submodules.link_stats = link_layer.LinkLayerStats(self.link_layer, "rtio_rx") self.submodules.rt_packet = rt_packet_master.RTPacketMaster(self.link_layer) self.submodules.rt_controller = rt_controller_master.RTController( - self.rt_packet, channel_count, fine_ts_width) + self.rt_packet, fine_ts_width) self.submodules.rt_manager = rt_controller_master.RTManager(self.rt_packet) - self.cri = self.rt_controller.cri self.submodules.aux_controller = aux_controller.AuxController( self.link_layer) @@ -149,3 +148,7 @@ class DRTIOMaster(Module): self.rt_controller.get_csrs() + self.rt_manager.get_csrs() + self.aux_controller.get_csrs()) + + @property + def cri(self): + return self.rt_controller.cri diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 786e2aa97..c3ef0214b 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -45,7 +45,7 @@ class RTIOCounter(Module): class RTController(Module): - def __init__(self, rt_packet, channel_count, fine_ts_width): + def __init__(self, rt_packet, fine_ts_width): self.csrs = _CSRs() self.cri = cri.Interface() From 312256a18d31916cb8f1f28f119cf11c5719fca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 7 Sep 2018 15:30:04 +0200 Subject: [PATCH 1192/2457] grabber: fix frame size off-by-1 --- artiq/firmware/libboard_artiq/grabber.rs | 6 +++++- artiq/gateware/grabber/core.py | 12 +++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/libboard_artiq/grabber.rs b/artiq/firmware/libboard_artiq/grabber.rs index 2973dc2e9..ba5e2a4db 100644 --- a/artiq/firmware/libboard_artiq/grabber.rs +++ b/artiq/firmware/libboard_artiq/grabber.rs @@ -134,8 +134,12 @@ pub fn tick() { if clock_pattern_ok(g) { let last_xy = get_last_pixels(g); if last_xy != unsafe { INFO[g].frame_size } { + // x capture is on ~LVAL which is after + // the last increment on DVAL + // y capture is on ~FVAL which coincides with the + // last increment on ~LVAL info!("grabber{} frame size: {}x{}", - g, last_xy.0 + 1, last_xy.1 + 1); + g, last_xy.0, last_xy.1 + 1); unsafe { INFO[g].frame_size = last_xy } } State::Watch diff --git a/artiq/gateware/grabber/core.py b/artiq/gateware/grabber/core.py index 60c40ce2d..4baaf98c3 100644 --- a/artiq/gateware/grabber/core.py +++ b/artiq/gateware/grabber/core.py @@ -89,14 +89,16 @@ class Parser(Module, AutoCSR): pix.x.eq(pix.x + 1), ), If(~lval, - If(last_lval, last_x.eq(pix.x)), - pix.x.eq(0), - If(last_fval & last_lval, + If(last_lval, + last_x.eq(pix.x), pix.y.eq(pix.y + 1) - ) + ), + pix.x.eq(0) ), If(~fval, - If(last_fval, last_y.eq(pix.y)), + If(last_fval, + last_y.eq(pix.y) + ), pix.y.eq(0) ) ] From df61b859882f9d266fbca8b2e00ea37c72276402 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 9 Sep 2018 14:11:21 +0800 Subject: [PATCH 1193/2457] drtio: fix imports --- artiq/gateware/drtio/core.py | 2 +- artiq/gateware/drtio/rt_controller_repeater.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index b1fd8a88a..b3d722825 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -11,7 +11,7 @@ from artiq.gateware.rtio.input_collector import * from artiq.gateware.drtio import (link_layer, rt_packet_satellite, rt_errors_satellite, rt_packet_master, rt_controller_master, - rt_controller_repeater) + rt_packet_repeater, rt_controller_repeater) from artiq.gateware.drtio.rx_synchronizer import GenericRXSynchronizer diff --git a/artiq/gateware/drtio/rt_controller_repeater.py b/artiq/gateware/drtio/rt_controller_repeater.py index 97de2d70e..d75e87f64 100644 --- a/artiq/gateware/drtio/rt_controller_repeater.py +++ b/artiq/gateware/drtio/rt_controller_repeater.py @@ -3,6 +3,7 @@ from migen import * from misoc.interconnect.csr import * from artiq.gateware.rtio.cdc import BlindTransfer +from artiq.gateware.drtio.cdc import CrossDomainRequest class RTController(Module, AutoCSR): From d5577ec0d0b06fae5399b4a2a26e1af0f884fcba Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 9 Sep 2018 16:26:48 +0800 Subject: [PATCH 1194/2457] cri: add routing table support --- artiq/gateware/rtio/cri.py | 62 ++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index d78c5da36..18ca1956b 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -2,6 +2,7 @@ from migen import * from migen.genlib.record import * +from migen.genlib.cdc import MultiReg from misoc.interconnect.csr import * @@ -109,8 +110,8 @@ class KernelInitiator(Module, AutoCSR): self.sync += If(self.counter_update.re, self.counter.status.eq(tsc.full_ts_cri)) -class CRIDecoder(Module): - def __init__(self, slaves=2, master=None): +class CRIDecoder(Module, AutoCSR): + def __init__(self, slaves=2, master=None, mode="async", enable_routing=False): if isinstance(slaves, int): slaves = [Interface() for _ in range(slaves)] if master is None: @@ -118,10 +119,41 @@ class CRIDecoder(Module): self.slaves = slaves self.master = master + slave_bits = bits_for(len(slaves)-1) + if enable_routing: + self.routing_destination = CSRStorage(8) + self.routing_hop = CSR(slave_bits) + # # # - selected = Signal(8, reset_less=True) - self.sync += selected.eq(self.master.chan_sel[16:]) + # routing + selected = Signal(slave_bits) + + if enable_routing: + self.specials.routing_table = Memory(slave_bits, 8) + + rtp_csr = self.routing_table.get_port(write_capable=True) + self.specials += rtp_csr + self.comb += [ + rtp_csr.adr.eq(self.routing_destination.storage), + rtp_csr.dat_w.eq(self.routing_hop.r), + rtp_csr.we.eq(self.routing_hop.re), + self.routing_hop.w.eq(rtp_csr.dat_r) + ] + + if mode == "async": + rtp_decoder = self.routing_table.get_port() + elif mode == "sync": + rtp_decoder = self.routing_table.get_port(clock_domain="rtio") + else: + raise ValueError + self.specials += rtp_decoder + self.comb += [ + rtp_decoder.adr.eq(self.master.chan_sel[16:]), + selected.eq(rtp_decoder.dat_r) + ] + else: + self.sync += selected.eq(self.master.chan_sel[16:]) # master -> slave for n, slave in enumerate(slaves): @@ -141,7 +173,7 @@ class CRIDecoder(Module): class CRISwitch(Module, AutoCSR): - def __init__(self, masters=2, slave=None): + def __init__(self, masters=2, slave=None, mode="async"): if isinstance(masters, int): masters = [Interface() for _ in range(masters)] if slave is None: @@ -153,6 +185,15 @@ class CRISwitch(Module, AutoCSR): # # # + if mode == "async": + selected = self.selected.storage + elif mode == "sync": + self.selected.storage.attr.add("no_retiming") + selected = Signal.like(self.selected.storage) + self.specials += MultiReg(self.selected.storage, selected, "rtio") + else: + raise ValueError + if len(masters) == 1: self.comb += masters[0].connect(slave) else: @@ -160,7 +201,7 @@ class CRISwitch(Module, AutoCSR): for name, size, direction in layout: if direction == DIR_M_TO_S: choices = Array(getattr(m, name) for m in masters) - self.comb += getattr(slave, name).eq(choices[self.selected.storage]) + self.comb += getattr(slave, name).eq(choices[selected]) # connect slave->master signals for name, size, direction in layout: @@ -170,11 +211,12 @@ class CRISwitch(Module, AutoCSR): dest = getattr(m, name) self.comb += dest.eq(source) + class CRIInterconnectShared(Module): - def __init__(self, masters=2, slaves=2): + def __init__(self, masters=2, slaves=2, mode="async", enable_routing=False): shared = Interface() - self.submodules.switch = CRISwitch(masters, shared) - self.submodules.decoder = CRIDecoder(slaves, shared) + self.submodules.switch = CRISwitch(masters, shared, mode) + self.submodules.decoder = CRIDecoder(slaves, shared, mode, enable_routing) def get_csrs(self): - return self.switch.get_csrs() + return self.switch.get_csrs() + self.decoder.get_csrs() From ec302747e0302e0639cd7dc76298d0292ff0e26a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 9 Sep 2018 16:27:39 +0800 Subject: [PATCH 1195/2457] kasli: add DRTIO repeaters --- artiq/gateware/targets/kasli.py | 77 +++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 22 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 0aa181ca3..43b7628b8 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -799,35 +799,63 @@ class _SatelliteBase(BaseSoC): qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings) self.submodules += qpll - sfp_ctl = platform.request("sfp_ctl", 0) - self.comb += sfp_ctl.tx_disable.eq(0) + sfp_ctls = [platform.request("sfp_ctl", i) for i in range(3)] + self.comb += [sc.tx_disable.eq(0) for sc in sfp_ctls] self.submodules.drtio_transceiver = gtp_7series.GTP( qpll_channel=qpll.channels[0], - data_pads=[platform.request("sfp", 0)], + data_pads=[platform.request("sfp", i) for i in range(3)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") self.sync += disable_si5324_ibuf.eq( ~self.drtio_transceiver.stable_clkin.storage) - self.comb += sfp_ctl.led.eq(self.drtio_transceiver.channels[0].rx_ready) + self.comb += [sfp_ctl.led.eq(channel.rx_ready) + for sfp_ctl, channel in zip(sfp_ctls, self.drtio_transceiver.channels)] self.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) - rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) - self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) - self.submodules.drtiosat = rx0(DRTIOSatellite( - self.rtio_tsc, self.drtio_transceiver.channels[0], - self.rx_synchronizer)) - self.csr_devices.append("drtiosat") - self.submodules.drtioaux0 = rx0(DRTIOAuxController( - self.drtiosat.link_layer)) - self.csr_devices.append("drtioaux0") - self.add_wb_slave(self.mem_map["drtioaux"], 0x800, - self.drtioaux0.bus) - self.add_memory_region("drtioaux0_mem", self.mem_map["drtioaux"] | self.shadow_base, 0x800) + drtioaux_csr_group = [] + drtioaux_memory_group = [] + drtiorep_csr_group = [] + self.drtio_cri = [] + for i in range(3): + coreaux_name = "drtioaux" + str(i) + memory_name = "drtioaux" + str(i) + "_mem" + drtioaux_csr_group.append(coreaux_name) + drtioaux_memory_group.append(memory_name) + + cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)}) + + if i == 0: + self.submodules.rx_synchronizer = cdr(XilinxRXSynchronizer()) + core = cdr(DRTIOSatellite( + self.rtio_tsc, self.drtio_transceiver.channels[i], + self.rx_synchronizer)) + self.submodules.drtiosat = core + self.csr_devices.append("drtiosat") + else: + corerep_name = "drtiorep" + str(i-1) + drtiorep_csr_group.append(corerep_name) + + core = cdr(DRTIORepeater( + self.rtio_tsc, self.drtio_transceiver.channels[i])) + setattr(self.submodules, corerep_name, core) + self.drtio_cri.append(core.cri) + self.csr_devices.append(corerep_name) + + coreaux = cdr(DRTIOAuxController(core.link_layer)) + setattr(self.submodules, coreaux_name, coreaux) + self.csr_devices.append(coreaux_name) + + memory_address = self.mem_map["drtioaux"] + 0x800*i + self.add_wb_slave(memory_address, 0x800, + coreaux.bus) + self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None - self.add_csr_group("drtioaux", ["drtioaux0"]) - self.add_memory_group("drtioaux_mem", ["drtioaux0_mem"]) + self.add_csr_group("drtioaux", drtioaux_csr_group) + self.add_memory_group("drtioaux_mem", drtioaux_memory_group) + self.config["HAS_DRTIOREP"] = None + self.add_csr_group("drtiorep", drtiorep_csr_group) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( @@ -851,6 +879,10 @@ class _SatelliteBase(BaseSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.txoutclk, gtp.rxoutclk) + for gtp in self.drtio_transceiver.gtps[1:]: + platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, gtp.rxoutclk) self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) fix_serdes_timing_path(platform) @@ -860,10 +892,11 @@ class _SatelliteBase(BaseSoC): self.csr_devices.append("rtio_moninj") self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels) - self.comb += [ - self.drtiosat.cri.connect(self.local_io.cri), - self.drtiosat.async_errors.eq(self.local_io.async_errors) - ] + self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors) + self.submodules.cri_con = rtio.CRIInterconnectShared( + [self.drtiosat.cri], + [self.local_io.cri] + self.drtio_cri, + mode="sync", enable_routing=True) class Master(_MasterBase): From 496d1b08fd97f5460d7bc2effae26fb083930265 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 9 Sep 2018 21:48:12 +0800 Subject: [PATCH 1196/2457] kasli: enable routing in Master --- artiq/gateware/targets/kasli.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 43b7628b8..b19b9ab30 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -693,6 +693,7 @@ class _MasterBase(MiniSoC, AMPSoC): coreaux.bus) self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None + self.config["HAS_DRTIO_ROUTING"] = None self.add_csr_group("drtio", drtio_csr_group) self.add_csr_group("drtioaux", drtioaux_csr_group) self.add_memory_group("drtioaux_mem", drtioaux_memory_group) @@ -726,7 +727,8 @@ class _MasterBase(MiniSoC, AMPSoC): self.register_kernel_cpu_csrdevice("rtio_dma") self.submodules.cri_con = rtio.CRIInterconnectShared( [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri] + self.drtio_cri) + [self.rtio_core.cri] + self.drtio_cri, + enable_routing=True) self.register_kernel_cpu_csrdevice("cri_con") self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.cri_con.switch.slave, From 7ae44f341788850a35b57b96ebffedd21614111c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 9 Sep 2018 21:49:28 +0800 Subject: [PATCH 1197/2457] firmware: add routing table (WIP) --- .../firmware/libboard_artiq/drtio_routing.rs | 59 +++++++++++++++++++ artiq/firmware/libboard_artiq/lib.rs | 2 + artiq/frontend/artiq_route.py | 10 ++-- artiq/gateware/targets/kasli.py | 2 +- 4 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 artiq/firmware/libboard_artiq/drtio_routing.rs diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs new file mode 100644 index 000000000..810043297 --- /dev/null +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -0,0 +1,59 @@ +use board_misoc::{csr, config}; + +pub const DEST_COUNT: usize = 256; +pub const MAX_HOPS: usize = 32; +pub const INVALID_HOP: u8 = 0xff; + +pub struct RoutingTable([[u8; MAX_HOPS]; DEST_COUNT]); + +impl RoutingTable { + // default routing table is for star topology with no hops + fn default_master() -> RoutingTable { + let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]); + for i in 0..csr::DRTIO.len() { + ret.0[i][0] = i as u8; + } + for i in 1..csr::DRTIO.len() { + ret.0[i][1] = 0x00; + } + ret + } + + // satellites receive the routing table from the master + // by default, block everything + fn default_satellite() -> RoutingTable { + RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]) + } +} + +pub fn config_routing_table() -> RoutingTable { + let mut ret = RoutingTable::default_master(); + let ok = config::read("routing_table", |result| { + if let Ok(data) = result { + if data.len() == DEST_COUNT*MAX_HOPS { + for i in 0..DEST_COUNT { + for j in 0..MAX_HOPS { + ret.0[i][j] = data[i*MAX_HOPS+j]; + } + } + return true; + } + } + false + }); + if !ok { + warn!("could not read routing table from configuration, using default"); + } + ret +} + +pub fn program_interconnect(rt: &RoutingTable, rank: u8) +{ + for i in 0..DEST_COUNT { + let hop = rt.0[i][rank as usize]; + unsafe { + csr::cri_con::routing_destination_write(i as _); + csr::cri_con::routing_hop_write(hop); + } + } +} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 443737441..228f6ed5e 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -48,3 +48,5 @@ pub mod grabber; #[cfg(has_drtio)] pub mod drtioaux; +#[cfg(has_drtio_routing)] +pub mod drtio_routing; diff --git a/artiq/frontend/artiq_route.py b/artiq/frontend/artiq_route.py index c818237ce..739a649e2 100755 --- a/artiq/frontend/artiq_route.py +++ b/artiq/frontend/artiq_route.py @@ -26,19 +26,19 @@ def get_argparser(): return parser -ENTRY_COUNT = 256 +DEST_COUNT = 256 MAX_HOPS = 32 def init(filename): with open(filename, "wb") as f: - f.write(b"\xff"*(ENTRY_COUNT*MAX_HOPS)) + f.write(b"\xff"*(DEST_COUNT*MAX_HOPS)) def show_routes(filename): routes = [] with open(filename, "rb") as f: - for i in range(ENTRY_COUNT): + for i in range(DEST_COUNT): hops = [int.from_bytes(f.read(1), "big") for j in range(MAX_HOPS)] routes.append(hops) @@ -54,8 +54,8 @@ def show_routes(filename): def set_route(filename, destination, hops): with open(filename, "r+b") as f: - if destination >= ENTRY_COUNT: - raise ValueError("destination must be less than {}".format(ENTRY_COUNT)) + if destination >= DEST_COUNT: + raise ValueError("destination must be less than {}".format(DEST_COUNT)) f.seek(destination*MAX_HOPS) if len(hops) + 1 >= MAX_HOPS: diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b19b9ab30..19b4c3e62 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -854,9 +854,9 @@ class _SatelliteBase(BaseSoC): coreaux.bus) self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None + self.config["HAS_DRTIO_ROUTING"] = None self.add_csr_group("drtioaux", drtioaux_csr_group) self.add_memory_group("drtioaux_mem", drtioaux_memory_group) - self.config["HAS_DRTIOREP"] = None self.add_csr_group("drtiorep", drtiorep_csr_group) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) From 014cfd8dbd8246fcdcf98d6e4762461be977f2cc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 9 Sep 2018 22:44:25 +0800 Subject: [PATCH 1198/2457] firmware: add drtioaux routing packets --- .../firmware/libproto_artiq/drtioaux_proto.rs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 2d0a24e87..babb40571 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -28,6 +28,10 @@ pub enum Packet { RtioErrorCollisionReply { channel: u16 }, RtioErrorBusyReply { channel: u16 }, + RoutingSetPath { destination: u8, hops: [u8; 32] }, + RoutingSetRank { rank: u8 }, + RoutingAck, + MonitorRequest { channel: u16, probe: u8 }, MonitorReply { value: u32 }, InjectionRequest { channel: u16, overrd: u8, value: u8 }, @@ -75,6 +79,20 @@ impl Packet { channel: reader.read_u16()? }, + 0x30 => { + let destination = reader.read_u8()?; + let mut hops = [0; 32]; + reader.read_exact(&mut hops)?; + Packet::RoutingSetPath { + destination: destination, + hops: hops + } + }, + 0x31 => Packet::RoutingSetRank { + rank: reader.read_u8()? + }, + 0x32 => Packet::RoutingAck, + 0x40 => Packet::MonitorRequest { channel: reader.read_u16()?, probe: reader.read_u8()? @@ -185,6 +203,18 @@ impl Packet { writer.write_u16(channel)?; }, + Packet::RoutingSetPath { destination, hops } => { + writer.write_u8(0x30)?; + writer.write_u8(destination)?; + writer.write_all(&hops)?; + }, + Packet::RoutingSetRank { rank } => { + writer.write_u8(0x31)?; + writer.write_u8(rank)?; + }, + Packet::RoutingAck => + writer.write_u8(0x32)?, + Packet::MonitorRequest { channel, probe } => { writer.write_u8(0x40)?; writer.write_u16(channel)?; From 7ec45efdcf9d27cc3cc6a3d5d14f3bb8be287ce8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 20:16:09 +0800 Subject: [PATCH 1199/2457] kasli: add missing cri_con to Satellite --- artiq/gateware/targets/kasli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 19b4c3e62..75c3fa5e9 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -899,6 +899,7 @@ class _SatelliteBase(BaseSoC): [self.drtiosat.cri], [self.local_io.cri] + self.drtio_cri, mode="sync", enable_routing=True) + self.csr_devices.append("cri_con") class Master(_MasterBase): From 31bef9918e4cd962b61171c5540f040bca7d76a3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 20:16:42 +0800 Subject: [PATCH 1200/2457] firmware: fix drtio_routing compatibility with master and satellite --- artiq/firmware/libboard_artiq/drtio_routing.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index 810043297..f5b7c735c 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -8,12 +8,12 @@ pub struct RoutingTable([[u8; MAX_HOPS]; DEST_COUNT]); impl RoutingTable { // default routing table is for star topology with no hops - fn default_master() -> RoutingTable { + fn default_master(default_n_links: usize) -> RoutingTable { let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]); - for i in 0..csr::DRTIO.len() { + for i in 0..default_n_links { ret.0[i][0] = i as u8; } - for i in 1..csr::DRTIO.len() { + for i in 1..default_n_links { ret.0[i][1] = 0x00; } ret @@ -26,8 +26,8 @@ impl RoutingTable { } } -pub fn config_routing_table() -> RoutingTable { - let mut ret = RoutingTable::default_master(); +pub fn config_routing_table(default_n_links: usize) -> RoutingTable { + let mut ret = RoutingTable::default_master(default_n_links); let ok = config::read("routing_table", |result| { if let Ok(data) = result { if data.len() == DEST_COUNT*MAX_HOPS { From bc1d3fda6a1eadeebeebbf481deb7f1c1908247b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 20:17:02 +0800 Subject: [PATCH 1201/2457] satman: ping repeater links Tested OK on hardware. --- artiq/firmware/satman/main.rs | 67 ++++++++++++------- artiq/firmware/satman/repeater.rs | 104 ++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 25 deletions(-) create mode 100644 artiq/firmware/satman/repeater.rs diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index c7e7fb73e..d53dca4f0 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -1,4 +1,4 @@ -#![feature(never_type, panic_implementation, panic_info_message)] +#![feature(never_type, panic_implementation, panic_info_message, const_slice_len)] #![no_std] #[macro_use] @@ -14,19 +14,27 @@ use board_artiq::serwb; #[cfg(has_hmc830_7043)] use board_artiq::hmc830_7043; -fn drtio_reset(reset: bool) { +mod repeater; + +fn drtiosat_reset(reset: bool) { unsafe { csr::drtiosat::reset_write(if reset { 1 } else { 0 }); } } -fn drtio_reset_phy(reset: bool) { +fn drtiosat_reset_phy(reset: bool) { unsafe { csr::drtiosat::reset_phy_write(if reset { 1 } else { 0 }); } } -fn drtio_tsc_loaded() -> bool { +fn drtiosat_link_rx_up() -> bool { + unsafe { + csr::drtiosat::rx_up_read() == 1 + } +} + +fn drtiosat_tsc_loaded() -> bool { unsafe { let tsc_loaded = csr::drtiosat::tsc_loaded_read() == 1; if tsc_loaded { @@ -44,11 +52,11 @@ fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error drtioaux::send_link(0, &drtioaux::Packet::EchoReply), drtioaux::Packet::ResetRequest { phy } => { if phy { - drtio_reset_phy(true); - drtio_reset_phy(false); + drtiosat_reset_phy(true); + drtiosat_reset_phy(false); } else { - drtio_reset(true); - drtio_reset(false); + drtiosat_reset(true); + drtiosat_reset(false); } drtioaux::send_link(0, &drtioaux::Packet::ResetAck) }, @@ -198,7 +206,7 @@ fn process_aux_packets() { } } -fn process_errors() { +fn drtiosat_process_errors() { let errors; unsafe { errors = csr::drtiosat::protocol_error_read(); @@ -245,12 +253,6 @@ const SI5324_SETTINGS: si5324::FrequencySettings crystal_ref: true }; -fn drtio_link_rx_up() -> bool { - unsafe { - csr::drtiosat::rx_up_read() == 1 - } -} - const SIPHASER_PHASE: u16 = 32; #[no_mangle] @@ -279,9 +281,21 @@ pub extern fn main() -> i32 { #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); + #[cfg(has_drtio_routing)] + let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()]; + #[cfg(not(has_drtio_routing))] + let mut repeaters = [repeater::Repeater::default(); 0]; + + for i in 0..repeaters.len() { + repeaters[i] = repeater::Repeater::new(i as u8); + } + loop { - while !drtio_link_rx_up() { - process_errors(); + while !drtiosat_link_rx_up() { + drtiosat_process_errors(); + for mut rep in repeaters.iter_mut() { + rep.service(); + } } info!("link is up, switching to recovered clock"); @@ -308,13 +322,16 @@ pub extern fn main() -> i32 { } drtioaux::reset(0); - drtio_reset(false); - drtio_reset_phy(false); + drtiosat_reset(false); + drtiosat_reset_phy(false); - while drtio_link_rx_up() { - process_errors(); + while drtiosat_link_rx_up() { + drtiosat_process_errors(); process_aux_packets(); - if drtio_tsc_loaded() { + for mut rep in repeaters.iter_mut() { + rep.service(); + } + if drtiosat_tsc_loaded() { #[cfg(has_ad9154)] { if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { @@ -333,9 +350,9 @@ pub extern fn main() -> i32 { #[cfg(has_ad9154)] board_artiq::ad9154::jesd_reset(true); - drtio_reset_phy(true); - drtio_reset(true); - drtio_tsc_loaded(); + drtiosat_reset_phy(true); + drtiosat_reset(true); + drtiosat_tsc_loaded(); info!("link is down, switching to local crystal clock"); si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks"); } diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs new file mode 100644 index 000000000..aabd0e3a7 --- /dev/null +++ b/artiq/firmware/satman/repeater.rs @@ -0,0 +1,104 @@ +use board_misoc::{csr, clock}; +use board_artiq::drtioaux; + +#[cfg(has_drtio_routing)] +fn rep_link_rx_up(linkno: u8) -> bool { + let linkno = linkno as usize; + unsafe { + (csr::DRTIOREP[linkno].rx_up_read)() == 1 + } +} + +#[derive(Clone, Copy)] +enum RepeaterState { + Down, + SendPing { ping_count: u16 }, + WaitPingReply { ping_count: u16, timeout: u64 }, + Up, + Failed +} + +impl Default for RepeaterState { + fn default() -> RepeaterState { RepeaterState::Down } +} + +#[derive(Clone, Copy, Default)] +pub struct Repeater { + repno: u8, + auxno: u8, + state: RepeaterState +} + +#[cfg(has_drtio_routing)] +impl Repeater { + pub fn new(repno: u8) -> Repeater { + Repeater { + repno: repno, + auxno: repno + 1, + state: RepeaterState::Down + } + } + + pub fn service(&mut self) { + match self.state { + RepeaterState::Down => { + if rep_link_rx_up(self.repno) { + info!("[REP#{}] link RX became up, pinging", self.repno); + self.state = RepeaterState::SendPing { ping_count: 0 }; + } + } + RepeaterState::SendPing { ping_count } => { + if rep_link_rx_up(self.repno) { + drtioaux::send_link(self.auxno, &drtioaux::Packet::EchoRequest).unwrap(); + self.state = RepeaterState::WaitPingReply { + ping_count: ping_count + 1, + timeout: clock::get_ms() + 100 + } + } else { + info!("[REP#{}] link RX went down during ping", self.repno); + self.state = RepeaterState::Down; + } + } + RepeaterState::WaitPingReply { ping_count, timeout } => { + if rep_link_rx_up(self.repno) { + if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv_link(self.auxno) { + info!("[REP#{}] remote replied after {} packets", self.repno, ping_count); + // TODO: send TSC, routing table, and rank + self.state = RepeaterState::Up; + } else { + if clock::get_ms() > timeout { + if ping_count > 200 { + info!("[REP#{}] ping failed", self.repno); + self.state = RepeaterState::Failed; + } else { + self.state = RepeaterState::SendPing { ping_count: ping_count }; + } + } + } + } else { + info!("[REP#{}] link RX went down during ping", self.repno); + self.state = RepeaterState::Down; + } + } + RepeaterState::Up => { + if !rep_link_rx_up(self.repno) { + info!("[REP#{}] link is down", self.repno); + self.state = RepeaterState::Down; + } + } + RepeaterState::Failed => { + if !rep_link_rx_up(self.repno) { + info!("[REP#{}] link is down", self.repno); + self.state = RepeaterState::Down; + } + } + } + } +} + +#[cfg(not(has_drtio_routing))] +impl Repeater { + pub fn new(_repno: u8) -> Repeater { Repeater::default() } + + pub fn service(&self) { } +} From 663432adbdbd4a594ead321fc73f6c1d6efa97ea Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 20:33:44 +0800 Subject: [PATCH 1202/2457] satman: load TSCs of downstream devices --- artiq/firmware/satman/main.rs | 4 ++++ artiq/firmware/satman/repeater.rs | 40 +++++++++++++++++++++++++++---- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index d53dca4f0..2bce73681 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -332,6 +332,7 @@ pub extern fn main() -> i32 { rep.service(); } if drtiosat_tsc_loaded() { + info!("TSC loaded"); #[cfg(has_ad9154)] { if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { @@ -341,6 +342,9 @@ pub extern fn main() -> i32 { error!("failed to align SYSREF at DAC: {}", e); } } + for rep in repeaters.iter() { + rep.sync_tsc(); + } if let Err(e) = drtioaux::send_link(0, &drtioaux::Packet::TSCAck) { error!("aux packet error: {}", e); } diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index aabd0e3a7..686b3acbb 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -55,7 +55,7 @@ impl Repeater { timeout: clock::get_ms() + 100 } } else { - info!("[REP#{}] link RX went down during ping", self.repno); + error!("[REP#{}] link RX went down during ping", self.repno); self.state = RepeaterState::Down; } } @@ -63,12 +63,17 @@ impl Repeater { if rep_link_rx_up(self.repno) { if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv_link(self.auxno) { info!("[REP#{}] remote replied after {} packets", self.repno, ping_count); - // TODO: send TSC, routing table, and rank + if !self.sync_tsc() { + error!("[REP#{}] remote failed to ack TSC", self.repno); + self.state = RepeaterState::Failed; + return; + } + // TODO: send routing table and rank self.state = RepeaterState::Up; } else { if clock::get_ms() > timeout { if ping_count > 200 { - info!("[REP#{}] ping failed", self.repno); + error!("[REP#{}] ping failed", self.repno); self.state = RepeaterState::Failed; } else { self.state = RepeaterState::SendPing { ping_count: ping_count }; @@ -76,7 +81,7 @@ impl Repeater { } } } else { - info!("[REP#{}] link RX went down during ping", self.repno); + error!("[REP#{}] link RX went down during ping", self.repno); self.state = RepeaterState::Down; } } @@ -94,11 +99,36 @@ impl Repeater { } } } + + pub fn sync_tsc(&self) -> bool { + let repno = self.repno as usize; + unsafe { + (csr::DRTIOREP[repno].set_time_write)(1); + while (csr::DRTIOREP[repno].set_time_read)() == 1 {} + } + + let timeout = clock::get_ms() + 200; + loop { + if !rep_link_rx_up(self.repno) { + return false; + } + if clock::get_ms() > timeout { + return false; + } + // TSCAck is the only aux packet that is sent spontaneously + // by the satellite, in response to a TSC set on the RT link. + if let Ok(Some(drtioaux::Packet::TSCAck)) = drtioaux::recv_link(self.auxno) { + return true; + } + } + } } #[cfg(not(has_drtio_routing))] impl Repeater { - pub fn new(_repno: u8) -> Repeater { Repeater::default() } + pub fn new(_repno: u8) -> Repeater { Repeater::default() } pub fn service(&self) { } + + pub fn sync_tsc(&self) { } } From 4d889c0c4ebd3354d8fc966621b815d976200006 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 21:40:02 +0800 Subject: [PATCH 1203/2457] firmware: improve DRTIO log messages --- artiq/firmware/runtime/rtio_mgt.rs | 18 ++++++++---------- artiq/firmware/satman/main.rs | 10 ++++++---- artiq/firmware/satman/repeater.rs | 18 +++++++++++------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index f2a606d86..a8685e1bd 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -114,23 +114,21 @@ pub mod drtio { } } - fn wait_tsc_ack(linkno: u8, io: &Io) -> bool { + fn wait_tsc_ack(linkno: u8, io: &Io) -> Result<(), &'static str> { loop { let mut count = 0; if !link_rx_up(linkno) { - return false; + return Err("link went down"); } count += 1; if count > 200 { - return false; + return Err("timeout"); } io.sleep(100).unwrap(); // TSCAck is the only aux packet that is sent spontaneously // by the satellite, in response to a TSC set on the RT link. - let pr = drtioaux::recv_link(linkno); - match pr { - Ok(Some(drtioaux::Packet::TSCAck)) => return true, - _ => {} + if let Ok(Some(drtioaux::Packet::TSCAck)) = drtioaux::recv_link(linkno) { + return Ok(()) } } } @@ -194,13 +192,13 @@ pub mod drtio { set_link_up(linkno, true); init_buffer_space(linkno); sync_tsc(linkno); - if !wait_tsc_ack(linkno, &io) { - info!("[LINK#{}] remote failed to ack TSC", linkno); + if wait_tsc_ack(linkno, &io).is_err() { + error!("[LINK#{}] remote failed to ack TSC", linkno); } else { info!("[LINK#{}] link initialization completed", linkno); } } else { - info!("[LINK#{}] ping failed", linkno); + error!("[LINK#{}] ping failed", linkno); } } } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 2bce73681..8ca8a6b6a 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -298,7 +298,7 @@ pub extern fn main() -> i32 { } } - info!("link is up, switching to recovered clock"); + info!("uplink is up, switching to recovered clock"); si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); si5324::siphaser::calibrate_skew(SIPHASER_PHASE).expect("failed to calibrate skew"); @@ -332,7 +332,7 @@ pub extern fn main() -> i32 { rep.service(); } if drtiosat_tsc_loaded() { - info!("TSC loaded"); + info!("TSC loaded from uplink"); #[cfg(has_ad9154)] { if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { @@ -343,7 +343,9 @@ pub extern fn main() -> i32 { } } for rep in repeaters.iter() { - rep.sync_tsc(); + if rep.sync_tsc().is_err() { + error!("remote failed to ack TSC"); + } } if let Err(e) = drtioaux::send_link(0, &drtioaux::Packet::TSCAck) { error!("aux packet error: {}", e); @@ -357,7 +359,7 @@ pub extern fn main() -> i32 { drtiosat_reset_phy(true); drtiosat_reset(true); drtiosat_tsc_loaded(); - info!("link is down, switching to local crystal clock"); + info!("uplink is down, switching to local crystal clock"); si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks"); } } diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index 686b3acbb..d677c362e 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -9,7 +9,7 @@ fn rep_link_rx_up(linkno: u8) -> bool { } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq)] enum RepeaterState { Down, SendPing { ping_count: u16 }, @@ -63,7 +63,7 @@ impl Repeater { if rep_link_rx_up(self.repno) { if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv_link(self.auxno) { info!("[REP#{}] remote replied after {} packets", self.repno, ping_count); - if !self.sync_tsc() { + if self.sync_tsc().is_err() { error!("[REP#{}] remote failed to ack TSC", self.repno); self.state = RepeaterState::Failed; return; @@ -100,7 +100,11 @@ impl Repeater { } } - pub fn sync_tsc(&self) -> bool { + pub fn sync_tsc(&self) -> Result<(), &'static str> { + if self.state != RepeaterState::Up { + return Ok(()); + } + let repno = self.repno as usize; unsafe { (csr::DRTIOREP[repno].set_time_write)(1); @@ -110,15 +114,15 @@ impl Repeater { let timeout = clock::get_ms() + 200; loop { if !rep_link_rx_up(self.repno) { - return false; + return Err("link went down"); } if clock::get_ms() > timeout { - return false; + return Err("timeout"); } // TSCAck is the only aux packet that is sent spontaneously // by the satellite, in response to a TSC set on the RT link. if let Ok(Some(drtioaux::Packet::TSCAck)) = drtioaux::recv_link(self.auxno) { - return true; + return Ok(()); } } } @@ -130,5 +134,5 @@ impl Repeater { pub fn service(&self) { } - pub fn sync_tsc(&self) { } + pub fn sync_tsc(&self) -> Result<(), &'static str> { Ok(()) } } From e01efbcb8a2fbd8ab2b1c4c96d1f55e68a7bd0db Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 22:17:00 +0800 Subject: [PATCH 1204/2457] runtime: merge sync_tsc and wait_tsc_ack --- artiq/firmware/runtime/rtio_mgt.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index a8685e1bd..abb3a4fba 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -76,14 +76,6 @@ pub mod drtio { } } - fn sync_tsc(linkno: u8) { - let linkno = linkno as usize; - unsafe { - (csr::DRTIO[linkno].set_time_write)(1); - while (csr::DRTIO[linkno].set_time_read)() == 1 {} - } - } - fn init_buffer_space(linkno: u8) { let linkidx = linkno as usize; unsafe { @@ -114,7 +106,12 @@ pub mod drtio { } } - fn wait_tsc_ack(linkno: u8, io: &Io) -> Result<(), &'static str> { + fn sync_tsc(linkno: u8, io: &Io) -> Result<(), &'static str> { + unsafe { + (csr::DRTIO[linkno as usize].set_time_write)(1); + while (csr::DRTIO[linkno as usize].set_time_read)() == 1 {} + } + loop { let mut count = 0; if !link_rx_up(linkno) { @@ -191,8 +188,7 @@ pub mod drtio { info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); set_link_up(linkno, true); init_buffer_space(linkno); - sync_tsc(linkno); - if wait_tsc_ack(linkno, &io).is_err() { + if sync_tsc(linkno, &io).is_err() { error!("[LINK#{}] remote failed to ack TSC", linkno); } else { info!("[LINK#{}] link initialization completed", linkno); From 264078baba45995a106e41879f807ce90710c71f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 22:29:35 +0800 Subject: [PATCH 1205/2457] style --- artiq/firmware/runtime/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index c4c3f674a..e5bed91df 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -34,7 +34,7 @@ use board_misoc::ethmac; #[cfg(has_drtio)] use board_artiq::drtioaux; use board_artiq::{mailbox, rpc_queue}; -use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto,kernel_proto}; +use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_proto}; #[cfg(has_rtio_analyzer)] use proto_artiq::analyzer_proto; From 19a14b68b15c73b20e97fc5ce7a53d16862422ae Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 22:48:56 +0800 Subject: [PATCH 1206/2457] runtime: program DRTIO routing table into gateware --- artiq/firmware/runtime/main.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index e5bed91df..b4a9454bb 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -33,6 +33,8 @@ use board_misoc::{csr, irq, ident, clock, boot, config}; use board_misoc::ethmac; #[cfg(has_drtio)] use board_artiq::drtioaux; +#[cfg(has_drtio_routing)] +use board_artiq::drtio_routing; use board_artiq::{mailbox, rpc_queue}; use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_proto}; #[cfg(has_rtio_analyzer)] @@ -280,16 +282,24 @@ fn startup_ethernet() { .ip_addrs([IpCidr::new(protocol_addr, 0)]) .finalize(); + #[cfg(has_drtio_routing)] + let drtio_routing_table = drtio_routing::config_routing_table(csr::DRTIO.len()); + #[cfg(has_drtio_routing)] + drtio_routing::program_interconnect(&drtio_routing_table, 0); + let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); + #[cfg(has_rtio_core)] rtio_mgt::startup(&io); + io.spawn(4096, mgmt::thread); io.spawn(16384, session::thread); #[cfg(any(has_rtio_moninj, has_drtio))] io.spawn(4096, moninj::thread); #[cfg(has_rtio_analyzer)] io.spawn(4096, analyzer::thread); + #[cfg(has_grabber)] io.spawn(4096, grabber_thread); From 2fff96802b605ac4fa29f6264c2ab37a4bb1497f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 10 Sep 2018 23:09:02 +0800 Subject: [PATCH 1207/2457] runtime: remove support for building without RTIO --- artiq/firmware/runtime/kern_hwreq.rs | 5 ----- artiq/firmware/runtime/main.rs | 2 -- artiq/firmware/runtime/session.rs | 17 +++++------------ 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index aae7bc99c..4e758ec8d 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -1,7 +1,6 @@ use kernel_proto as kern; use sched::{Io, Error as SchedError}; use session::{kern_acknowledge, kern_send, Error}; -#[cfg(has_rtio_core)] use rtio_mgt; #[cfg(has_drtio)] @@ -292,25 +291,21 @@ mod spi { pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result> { match request { - #[cfg(has_rtio_core)] &kern::RtioInitRequest => { info!("resetting RTIO"); rtio_mgt::init_core(false); kern_acknowledge() } - #[cfg(has_rtio_core)] &kern::DrtioLinkStatusRequest { linkno } => { let up = rtio_mgt::drtio::link_up(linkno); kern_send(io, &kern::DrtioLinkStatusReply { up: up }) } - #[cfg(has_rtio_core)] &kern::DrtioPacketCountRequest { linkno } => { let (tx_cnt, rx_cnt) = rtio_mgt::drtio_dbg::get_packet_counts(linkno); kern_send(io, &kern::DrtioPacketCountReply { tx_cnt: tx_cnt, rx_cnt: rx_cnt }) } - #[cfg(has_rtio_core)] &kern::DrtioBufferSpaceReqCountRequest { linkno } => { let cnt = rtio_mgt::drtio_dbg::get_buffer_space_req_count(linkno); kern_send(io, &kern::DrtioBufferSpaceReqCountReply { cnt: cnt }) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index b4a9454bb..4a567ed82 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -40,7 +40,6 @@ use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_pro #[cfg(has_rtio_analyzer)] use proto_artiq::analyzer_proto; -#[cfg(has_rtio_core)] mod rtio_mgt; mod urc; @@ -290,7 +289,6 @@ fn startup_ethernet() { let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); - #[cfg(has_rtio_core)] rtio_mgt::startup(&io); io.spawn(4096, mgmt::thread); diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index d9812861b..d5a2722d2 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -7,7 +7,6 @@ use board_misoc::{ident, cache, config}; use {mailbox, rpc_queue, kernel}; use urc::Urc; use sched::{ThreadHandle, Io, TcpListener, TcpStream, Error as SchedError}; -#[cfg(has_rtio_core)] use rtio_mgt; use rtio_dma::Manager as DmaManager; use cache::Cache; @@ -517,12 +516,9 @@ fn host_kernel_worker(io: &Io, return Err(Error::WatchdogExpired(idx)) } - #[cfg(has_rtio_core)] - { - if !rtio_mgt::crg::check() { - host_write(stream, host::Reply::ClockFailure)?; - return Err(Error::ClockFailure) - } + if !rtio_mgt::crg::check() { + host_write(stream, host::Reply::ClockFailure)?; + return Err(Error::ClockFailure) } } @@ -562,11 +558,8 @@ fn flash_kernel_worker(io: &Io, return Err(Error::WatchdogExpired(idx)) } - #[cfg(has_rtio_core)] - { - if !rtio_mgt::crg::check() { - return Err(Error::ClockFailure) - } + if !rtio_mgt::crg::check() { + return Err(Error::ClockFailure) } io.relinquish()? From 3d29a7ed14b9445397368a950dea03b73a388674 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 11:27:56 +0800 Subject: [PATCH 1208/2457] firmware: add fmt::Display to RoutingTable --- .../firmware/libboard_artiq/drtio_routing.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index f5b7c735c..4a3a08c12 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -1,4 +1,5 @@ use board_misoc::{csr, config}; +use core::fmt; pub const DEST_COUNT: usize = 256; pub const MAX_HOPS: usize = 32; @@ -26,6 +27,26 @@ impl RoutingTable { } } +impl fmt::Display for RoutingTable { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "RoutingTable {{")?; + for i in 0..DEST_COUNT { + if self.0[i][0] != INVALID_HOP { + write!(f, "{}:", i)?; + for j in 0..MAX_HOPS { + if self.0[i][j] == INVALID_HOP { + break; + } + write!(f, " {}", self.0[i][j])?; + } + write!(f, ";")?; + } + } + write!(f, " }}")?; + Ok(()) + } +} + pub fn config_routing_table(default_n_links: usize) -> RoutingTable { let mut ret = RoutingTable::default_master(default_n_links); let ok = config::read("routing_table", |result| { From b38c57d73bbcd5d9b52e410b5b582e00fe032822 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 14:12:41 +0800 Subject: [PATCH 1209/2457] firmware: send DRTIO routing table to satellite --- .../firmware/libboard_artiq/drtio_routing.rs | 11 +-- artiq/firmware/libboard_artiq/lib.rs | 1 - .../firmware/libproto_artiq/drtioaux_proto.rs | 2 +- artiq/firmware/runtime/main.rs | 11 ++- artiq/firmware/runtime/rtio_mgt.rs | 90 +++++++++++++------ artiq/firmware/satman/main.rs | 9 +- artiq/firmware/satman/repeater.rs | 4 +- 7 files changed, 87 insertions(+), 41 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index 4a3a08c12..c0242aeb7 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -5,11 +5,11 @@ pub const DEST_COUNT: usize = 256; pub const MAX_HOPS: usize = 32; pub const INVALID_HOP: u8 = 0xff; -pub struct RoutingTable([[u8; MAX_HOPS]; DEST_COUNT]); +pub struct RoutingTable(pub [[u8; MAX_HOPS]; DEST_COUNT]); impl RoutingTable { // default routing table is for star topology with no hops - fn default_master(default_n_links: usize) -> RoutingTable { + pub fn default_master(default_n_links: usize) -> RoutingTable { let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]); for i in 0..default_n_links { ret.0[i][0] = i as u8; @@ -20,9 +20,9 @@ impl RoutingTable { ret } - // satellites receive the routing table from the master - // by default, block everything - fn default_satellite() -> RoutingTable { + // use this by default on satellite, as they receive + // the routing table from the master + pub fn default_empty() -> RoutingTable { RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]) } } @@ -68,6 +68,7 @@ pub fn config_routing_table(default_n_links: usize) -> RoutingTable { ret } +#[cfg(has_drtio_routing)] pub fn program_interconnect(rt: &RoutingTable, rank: u8) { for i in 0..DEST_COUNT { diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 228f6ed5e..bcfdf8d9e 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -48,5 +48,4 @@ pub mod grabber; #[cfg(has_drtio)] pub mod drtioaux; -#[cfg(has_drtio_routing)] pub mod drtio_routing; diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index babb40571..e20194442 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -14,7 +14,7 @@ impl From> for Error { } } -#[derive(Debug)] +#[derive(PartialEq, Debug)] pub enum Packet { EchoRequest, EchoReply, diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 4a567ed82..555f5adce 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -25,6 +25,7 @@ extern crate board_artiq; extern crate logger_artiq; extern crate proto_artiq; +use core::cell::RefCell; use core::convert::TryFrom; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; @@ -282,14 +283,16 @@ fn startup_ethernet() { .finalize(); #[cfg(has_drtio_routing)] - let drtio_routing_table = drtio_routing::config_routing_table(csr::DRTIO.len()); - #[cfg(has_drtio_routing)] - drtio_routing::program_interconnect(&drtio_routing_table, 0); + let drtio_routing_table = urc::Urc::new(RefCell::new( + drtio_routing::config_routing_table(csr::DRTIO.len()))); let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); - rtio_mgt::startup(&io); + #[cfg(has_drtio_routing)] + rtio_mgt::startup(&io, &drtio_routing_table); + #[cfg(not(has_drtio_routing))] + rtio_mgt::startup(&io, &drtio_routing::RoutingTable::default_empty()); io.spawn(4096, mgmt::thread); io.spawn(16384, session::thread); diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index abb3a4fba..a70596b1d 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -1,6 +1,9 @@ -use board_misoc::csr; +use core::cell::RefCell; +use urc::Urc; +use board_misoc::{csr, clock}; #[cfg(has_rtio_clock_switch)] use board_misoc::config; +use board_artiq::drtio_routing; use sched::Io; #[cfg(has_rtio_crg)] @@ -42,11 +45,15 @@ pub mod drtio { use super::*; use drtioaux; - pub fn startup(io: &Io) { + pub fn startup(io: &Io, routing_table: &Urc>) { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } - io.spawn(4096, link_thread); + let routing_table = routing_table.clone(); + io.spawn(4096, move |io| { + let routing_table = routing_table.borrow(); + link_thread(io, &routing_table) + }); } fn link_rx_up(linkno: u8) -> bool { @@ -106,28 +113,51 @@ pub mod drtio { } } - fn sync_tsc(linkno: u8, io: &Io) -> Result<(), &'static str> { + fn recv_aux_timeout(io: &Io, linkno: u8, timeout: u32) -> Result { + let max_time = clock::get_ms() + timeout as u64; + loop { + if !link_rx_up(linkno) { + return Err("link went down"); + } + if clock::get_ms() > max_time { + return Err("timeout"); + } + match drtioaux::recv_link(linkno) { + Ok(Some(packet)) => return Ok(packet), + Ok(None) => (), + Err(_) => return Err("aux packet error") + } + io.relinquish().unwrap(); + } + } + + fn sync_tsc(io: &Io, linkno: u8) -> Result<(), &'static str> { unsafe { (csr::DRTIO[linkno as usize].set_time_write)(1); while (csr::DRTIO[linkno as usize].set_time_read)() == 1 {} } + // TSCAck is the only aux packet that is sent spontaneously + // by the satellite, in response to a TSC set on the RT link. + let reply = recv_aux_timeout(io, linkno, 10000)?; + if reply == drtioaux::Packet::TSCAck { + return Ok(()); + } else { + return Err("unexpected reply"); + } + } - loop { - let mut count = 0; - if !link_rx_up(linkno) { - return Err("link went down"); - } - count += 1; - if count > 200 { - return Err("timeout"); - } - io.sleep(100).unwrap(); - // TSCAck is the only aux packet that is sent spontaneously - // by the satellite, in response to a TSC set on the RT link. - if let Ok(Some(drtioaux::Packet::TSCAck)) = drtioaux::recv_link(linkno) { - return Ok(()) + fn load_routing_table(io: &Io, linkno: u8, routing_table: &drtio_routing::RoutingTable) -> Result<(), &'static str> { + for i in 0..drtio_routing::DEST_COUNT { + drtioaux::send_link(linkno, &drtioaux::Packet::RoutingSetPath { + destination: i as u8, + hops: routing_table.0[i] + }).unwrap(); + let reply = recv_aux_timeout(io, linkno, 200)?; + if reply != drtioaux::Packet::RoutingAck { + return Err("unexpected reply"); } } + Ok(()) } fn process_local_errors(linkno: u8) { @@ -166,7 +196,7 @@ pub mod drtio { } } - pub fn link_thread(io: Io) { + pub fn link_thread(io: Io, routing_table: &drtio_routing::RoutingTable) { loop { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; @@ -188,11 +218,13 @@ pub mod drtio { info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); set_link_up(linkno, true); init_buffer_space(linkno); - if sync_tsc(linkno, &io).is_err() { - error!("[LINK#{}] remote failed to ack TSC", linkno); - } else { - info!("[LINK#{}] link initialization completed", linkno); + if let Err(e) = sync_tsc(&io, linkno) { + error!("[LINK#{}] failed to sync TSC ({})", linkno, e); } + if let Err(e) = load_routing_table(&io, linkno, routing_table) { + error!("[LINK#{}] failed to load routing table ({})", linkno, e); + } + info!("[LINK#{}] link initialization completed", linkno); } else { error!("[LINK#{}] ping failed", linkno); } @@ -223,7 +255,7 @@ pub mod drtio { pub mod drtio { use super::*; - pub fn startup(_io: &Io) {} + pub fn startup(_io: &Io, _routing_table: &Urc>) {} pub fn init() {} pub fn link_up(_linkno: u8) -> bool { false } } @@ -250,7 +282,7 @@ fn async_error_thread(io: Io) { } } -pub fn startup(io: &Io) { +pub fn startup(io: &Io, routing_table: &Urc>) { #[cfg(has_rtio_crg)] { #[cfg(has_rtio_clock_switch)] @@ -290,7 +322,13 @@ pub fn startup(io: &Io) { } } - drtio::startup(io); + #[cfg(has_drtio_routing)] + { + let routing_table = routing_table.clone(); + drtio_routing::program_interconnect(&routing_table.borrow(), 0); + } + + drtio::startup(io, &routing_table); init_core(true); io.spawn(4096, async_error_thread); } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 8ca8a6b6a..019ac767a 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -96,6 +96,11 @@ fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error } } + drtioaux::Packet::RoutingSetPath { destination, hops } => { + info!("routing: {} -> {:?}", destination, hops); + drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + } + drtioaux::Packet::MonitorRequest { channel, probe } => { let value; #[cfg(has_rtio_moninj)] @@ -343,8 +348,8 @@ pub extern fn main() -> i32 { } } for rep in repeaters.iter() { - if rep.sync_tsc().is_err() { - error!("remote failed to ack TSC"); + if let Err(e) = rep.sync_tsc() { + error!("failed to sync TSC ({})", e); } } if let Err(e) = drtioaux::send_link(0, &drtioaux::Packet::TSCAck) { diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index d677c362e..a2d17e285 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -63,8 +63,8 @@ impl Repeater { if rep_link_rx_up(self.repno) { if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv_link(self.auxno) { info!("[REP#{}] remote replied after {} packets", self.repno, ping_count); - if self.sync_tsc().is_err() { - error!("[REP#{}] remote failed to ack TSC", self.repno); + if let Err(e) = self.sync_tsc() { + error!("[REP#{}] failed to sync TSC ({})", self.repno, e); self.state = RepeaterState::Failed; return; } From f5b386c0d8734284b73ead2e0c3290ef8c099d37 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 18:22:45 +0800 Subject: [PATCH 1210/2457] firmware: fix routing table formatting --- artiq/firmware/libboard_artiq/drtio_routing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index c0242aeb7..d3a7bcea7 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -32,7 +32,7 @@ impl fmt::Display for RoutingTable { write!(f, "RoutingTable {{")?; for i in 0..DEST_COUNT { if self.0[i][0] != INVALID_HOP { - write!(f, "{}:", i)?; + write!(f, " {}:", i)?; for j in 0..MAX_HOPS { if self.0[i][j] == INVALID_HOP { break; From a23af67f2bb323d851da4dd47f470fc3336df95c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 18:23:36 +0800 Subject: [PATCH 1211/2457] satman: print better debugging information on exception --- artiq/firmware/satman/main.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 019ac767a..f927681ab 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -1,4 +1,4 @@ -#![feature(never_type, panic_implementation, panic_info_message, const_slice_len)] +#![feature(never_type, panic_implementation, panic_info_message, const_slice_len, try_from)] #![no_std] #[macro_use] @@ -7,7 +7,8 @@ extern crate log; extern crate board_misoc; extern crate board_artiq; -use board_misoc::{csr, ident, clock, uart_logger}; +use core::convert::TryFrom; +use board_misoc::{csr, irq, ident, clock, uart_logger}; use board_artiq::{i2c, spi, si5324, drtioaux}; #[cfg(has_serwb_phy_amc)] use board_artiq::serwb; @@ -371,6 +372,23 @@ pub extern fn main() -> i32 { #[no_mangle] pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) { + let vect = irq::Exception::try_from(vect).expect("unknown exception"); + + fn hexdump(addr: u32) { + let addr = (addr - addr % 4) as *const u32; + let mut ptr = addr; + println!("@ {:08p}", ptr); + for _ in 0..4 { + print!("+{:04x}: ", ptr as usize - addr as usize); + print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); + print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); + print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); + print!("{:08x}\n", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); + } + } + + hexdump(pc); + hexdump(ea); panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea) } From c0c5867f9e96ae5888e3c3ed17292c36d9916f8c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 18:23:51 +0800 Subject: [PATCH 1212/2457] satman: increase stack size Prevents crashing when running the routing code. Will have to be shrunk back on Sayma RTM. --- artiq/firmware/satman/satman.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/satman/satman.ld b/artiq/firmware/satman/satman.ld index efae5d319..69cc737d2 100644 --- a/artiq/firmware/satman/satman.ld +++ b/artiq/firmware/satman/satman.ld @@ -49,7 +49,7 @@ SECTIONS .stack : { _estack = .; - . += 0x1000; + . += 0x10000; _fstack = . - 4; } > main_ram } From 2679a35082d06545c5f71ca40de1758e3e1e26b1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 18:28:17 +0800 Subject: [PATCH 1213/2457] firwmare: propagate DRTIO routing table and rank all the way --- artiq/firmware/runtime/rtio_mgt.rs | 17 +++++- artiq/firmware/satman/main.rs | 53 ++++++++++++++--- artiq/firmware/satman/repeater.rs | 91 ++++++++++++++++++++++++------ 3 files changed, 135 insertions(+), 26 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index a70596b1d..a8055c943 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -146,7 +146,8 @@ pub mod drtio { } } - fn load_routing_table(io: &Io, linkno: u8, routing_table: &drtio_routing::RoutingTable) -> Result<(), &'static str> { + fn load_routing_table(io: &Io, linkno: u8, routing_table: &drtio_routing::RoutingTable) + -> Result<(), &'static str> { for i in 0..drtio_routing::DEST_COUNT { drtioaux::send_link(linkno, &drtioaux::Packet::RoutingSetPath { destination: i as u8, @@ -160,6 +161,17 @@ pub mod drtio { Ok(()) } + fn set_rank(io: &Io, linkno: u8, rank: u8) -> Result<(), &'static str> { + drtioaux::send_link(linkno, &drtioaux::Packet::RoutingSetRank { + rank: rank + }).unwrap(); + let reply = recv_aux_timeout(io, linkno, 200)?; + if reply != drtioaux::Packet::RoutingAck { + return Err("unexpected reply"); + } + Ok(()) + } + fn process_local_errors(linkno: u8) { let errors; let linkidx = linkno as usize; @@ -224,6 +236,9 @@ pub mod drtio { if let Err(e) = load_routing_table(&io, linkno, routing_table) { error!("[LINK#{}] failed to load routing table ({})", linkno, e); } + if let Err(e) = set_rank(&io, linkno, 1) { + error!("[LINK#{}] failed to set rank ({})", linkno, e); + } info!("[LINK#{}] link initialization completed", linkno); } else { error!("[LINK#{}] ping failed", linkno); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index f927681ab..12bb9d945 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -12,6 +12,7 @@ use board_misoc::{csr, irq, ident, clock, uart_logger}; use board_artiq::{i2c, spi, si5324, drtioaux}; #[cfg(has_serwb_phy_amc)] use board_artiq::serwb; +use board_artiq::drtio_routing; #[cfg(has_hmc830_7043)] use board_artiq::hmc830_7043; @@ -45,7 +46,9 @@ fn drtiosat_tsc_loaded() -> bool { } } -fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error> { +fn process_aux_packet(_repeaters: &mut [repeater::Repeater], + _routing_table: &mut drtio_routing::RoutingTable, _rank: &mut u8, + packet: drtioaux::Packet) -> Result<(), drtioaux::Error> { // In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels, // and u16 otherwise; hence the `as _` conversion. match packet { @@ -97,8 +100,40 @@ fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error } } + #[cfg(has_drtio_routing)] drtioaux::Packet::RoutingSetPath { destination, hops } => { - info!("routing: {} -> {:?}", destination, hops); + _routing_table.0[destination as usize] = hops; + for rep in _repeaters.iter() { + if let Err(e) = rep.set_path(destination, &hops) { + error!("failed to set path ({})", e); + } + } + drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + } + #[cfg(has_drtio_routing)] + drtioaux::Packet::RoutingSetRank { rank } => { + *_rank = rank; + drtio_routing::program_interconnect(_routing_table, rank); + + let rep_rank = rank + 1; + for rep in _repeaters.iter() { + if let Err(e) = rep.set_rank(rep_rank) { + error!("failed to set rank ({})", e); + } + } + + info!("rank: {}", rank); + info!("routing table: {}", _routing_table); + + drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + } + + #[cfg(not(has_drtio_routing))] + drtioaux::Packet::RoutingSetPath { _destination, _hops } => { + drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + } + #[cfg(not(has_drtio_routing))] + drtioaux::Packet::RoutingSetRank { _rank } => { drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) } @@ -197,11 +232,12 @@ fn process_aux_packet(packet: drtioaux::Packet) -> Result<(), drtioaux::Error } } -fn process_aux_packets() { +fn process_aux_packets(repeaters: &mut [repeater::Repeater], + routing_table: &mut drtio_routing::RoutingTable, rank: &mut u8) { let result = drtioaux::recv_link(0).and_then(|packet| { if let Some(packet) = packet { - process_aux_packet(packet) + process_aux_packet(repeaters, routing_table, rank, packet) } else { Ok(()) } @@ -291,16 +327,17 @@ pub extern fn main() -> i32 { let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()]; #[cfg(not(has_drtio_routing))] let mut repeaters = [repeater::Repeater::default(); 0]; - for i in 0..repeaters.len() { repeaters[i] = repeater::Repeater::new(i as u8); } + let mut routing_table = drtio_routing::RoutingTable::default_empty(); + let mut rank = 1; loop { while !drtiosat_link_rx_up() { drtiosat_process_errors(); for mut rep in repeaters.iter_mut() { - rep.service(); + rep.service(&routing_table, rank); } } @@ -333,9 +370,9 @@ pub extern fn main() -> i32 { while drtiosat_link_rx_up() { drtiosat_process_errors(); - process_aux_packets(); + process_aux_packets(&mut repeaters, &mut routing_table, &mut rank); for mut rep in repeaters.iter_mut() { - rep.service(); + rep.service(&routing_table, rank); } if drtiosat_tsc_loaded() { info!("TSC loaded from uplink"); diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index a2d17e285..4c2dd7287 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -1,5 +1,5 @@ use board_misoc::{csr, clock}; -use board_artiq::drtioaux; +use board_artiq::{drtioaux, drtio_routing}; #[cfg(has_drtio_routing)] fn rep_link_rx_up(linkno: u8) -> bool { @@ -39,7 +39,7 @@ impl Repeater { } } - pub fn service(&mut self) { + pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8) { match self.state { RepeaterState::Down => { if rep_link_rx_up(self.repno) { @@ -63,13 +63,22 @@ impl Repeater { if rep_link_rx_up(self.repno) { if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv_link(self.auxno) { info!("[REP#{}] remote replied after {} packets", self.repno, ping_count); + self.state = RepeaterState::Up; if let Err(e) = self.sync_tsc() { error!("[REP#{}] failed to sync TSC ({})", self.repno, e); self.state = RepeaterState::Failed; return; } - // TODO: send routing table and rank - self.state = RepeaterState::Up; + if let Err(e) = self.load_routing_table(routing_table) { + error!("[REP#{}] failed to sync TSC ({})", self.repno, e); + self.state = RepeaterState::Failed; + return; + } + if let Err(e) = self.set_rank(rank) { + error!("[REP#{}] failed to sync TSC ({})", self.repno, e); + self.state = RepeaterState::Failed; + return; + } } else { if clock::get_ms() > timeout { if ping_count > 200 { @@ -100,6 +109,23 @@ impl Repeater { } } + fn recv_aux_timeout(&self, timeout: u32) -> Result { + let max_time = clock::get_ms() + timeout as u64; + loop { + if !rep_link_rx_up(self.repno) { + return Err("link went down"); + } + if clock::get_ms() > max_time { + return Err("timeout"); + } + match drtioaux::recv_link(self.auxno) { + Ok(Some(packet)) => return Ok(packet), + Ok(None) => (), + Err(_) => return Err("aux packet error") + } + } + } + pub fn sync_tsc(&self) -> Result<(), &'static str> { if self.state != RepeaterState::Up { return Ok(()); @@ -111,21 +137,52 @@ impl Repeater { while (csr::DRTIOREP[repno].set_time_read)() == 1 {} } - let timeout = clock::get_ms() + 200; - loop { - if !rep_link_rx_up(self.repno) { - return Err("link went down"); - } - if clock::get_ms() > timeout { - return Err("timeout"); - } - // TSCAck is the only aux packet that is sent spontaneously - // by the satellite, in response to a TSC set on the RT link. - if let Ok(Some(drtioaux::Packet::TSCAck)) = drtioaux::recv_link(self.auxno) { - return Ok(()); - } + // TSCAck is the only aux packet that is sent spontaneously + // by the satellite, in response to a TSC set on the RT link. + let reply = self.recv_aux_timeout(10000)?; + if reply == drtioaux::Packet::TSCAck { + return Ok(()); + } else { + return Err("unexpected reply"); } } + + pub fn set_path(&self, destination: u8, hops: &[u8; drtio_routing::MAX_HOPS]) -> Result<(), &'static str> { + if self.state != RepeaterState::Up { + return Ok(()); + } + + drtioaux::send_link(self.auxno, &drtioaux::Packet::RoutingSetPath { + destination: destination, + hops: *hops + }).unwrap(); + let reply = self.recv_aux_timeout(200)?; + if reply != drtioaux::Packet::RoutingAck { + return Err("unexpected reply"); + } + Ok(()) + } + + pub fn load_routing_table(&self, routing_table: &drtio_routing::RoutingTable) -> Result<(), &'static str> { + for i in 0..drtio_routing::DEST_COUNT { + self.set_path(i as u8, &routing_table.0[i])?; + } + Ok(()) + } + + pub fn set_rank(&self, rank: u8) -> Result<(), &'static str> { + if self.state != RepeaterState::Up { + return Ok(()); + } + drtioaux::send_link(self.auxno, &drtioaux::Packet::RoutingSetRank { + rank: rank + }).unwrap(); + let reply = self.recv_aux_timeout(200)?; + if reply != drtioaux::Packet::RoutingAck { + return Err("unexpected reply"); + } + Ok(()) + } } #[cfg(not(has_drtio_routing))] From e6bd835b5d713f9d57e4da39aa22736ec389d2d9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 20:04:51 +0800 Subject: [PATCH 1214/2457] satman: fix rank setting --- artiq/firmware/satman/repeater.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index 4c2dd7287..052fe47ad 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -74,7 +74,7 @@ impl Repeater { self.state = RepeaterState::Failed; return; } - if let Err(e) = self.set_rank(rank) { + if let Err(e) = self.set_rank(rank + 1) { error!("[REP#{}] failed to sync TSC ({})", self.repno, e); self.state = RepeaterState::Failed; return; From 36e3fedfc6726b5068d11da3d5a1d132fe285d7d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 20:10:33 +0800 Subject: [PATCH 1215/2457] runtime: print routing table at boot --- artiq/firmware/libboard_artiq/drtio_routing.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index d3a7bcea7..4302cd880 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -64,7 +64,8 @@ pub fn config_routing_table(default_n_links: usize) -> RoutingTable { }); if !ok { warn!("could not read routing table from configuration, using default"); - } + } + info!("routing table: {}", ret); ret } From 5439abaa9d940f47e20f6c4aea1a53806c1c381a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 20:10:52 +0800 Subject: [PATCH 1216/2457] satman: fix error messages --- artiq/firmware/satman/repeater.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index 052fe47ad..c58d4b846 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -70,12 +70,12 @@ impl Repeater { return; } if let Err(e) = self.load_routing_table(routing_table) { - error!("[REP#{}] failed to sync TSC ({})", self.repno, e); + error!("[REP#{}] failed to load routing table ({})", self.repno, e); self.state = RepeaterState::Failed; return; } if let Err(e) = self.set_rank(rank + 1) { - error!("[REP#{}] failed to sync TSC ({})", self.repno, e); + error!("[REP#{}] failed to set rank ({})", self.repno, e); self.state = RepeaterState::Failed; return; } From 251b9a2b0d04bfab5894098324be3479a8322376 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 22:17:57 +0800 Subject: [PATCH 1217/2457] drtio: do not lock up master when satellite repeatedly fails to answer buffer space reqs --- artiq/gateware/drtio/rt_controller_master.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index fa2efd457..a1e4f11c9 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -189,7 +189,7 @@ class RTController(Module): timeout_counter.wait.eq(1), If(timeout_counter.done, signal_buffer_space_timeout.eq(1), - NextState("GET_BUFFER_SPACE") + NextState("IDLE") ) ) fsm.act("READ", From 051bafbfd973fe6938d7a6f59984c0b033d6caeb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 22:18:42 +0800 Subject: [PATCH 1218/2457] drtio: ensure 2 cycles between frames on the link This gives time for setting chan_sel before cmd on CRI. --- artiq/gateware/drtio/rt_packet_master.py | 4 ++++ artiq/gateware/drtio/rt_packet_repeater.py | 4 ++++ artiq/gateware/test/drtio/test_rt_packet_repeater.py | 3 +++ 3 files changed, 11 insertions(+) diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index 45ffe1278..42370a09d 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -208,6 +208,10 @@ class RTPacketMaster(Module): self.sync.rtio += If(tsc_value_load, tsc_value.eq(self.tsc_value)) tx_fsm.act("IDLE", + # Ensure 2 cycles between frames on the link. + NextState("READY") + ) + tx_fsm.act("READY", If(sr_buf_readable, If(sr_notwrite, Case(sr_address[0], { diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 5ccd8dd70..1798b6da8 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -110,6 +110,10 @@ class RTPacketRepeater(Module): self.submodules += tx_fsm tx_fsm.act("IDLE", + # Ensure 2 cycles between frames on the link. + NextState("READY") + ) + tx_fsm.act("READY", If(self.set_time_stb, tsc_value_load.eq(1), NextState("SET_TIME") diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index d348a5efc..70f25adb0 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -27,6 +27,7 @@ class TestRepeater(unittest.TestCase): pt, pr, ts, dut = create_dut(nwords) def send(): + yield yield ts.eq(0x12345678) yield dut.set_time_stb.eq(1) while not (yield dut.set_time_ack): @@ -61,6 +62,7 @@ class TestRepeater(unittest.TestCase): pt, pr, ts, dut = create_dut(nwords) def send(): + yield for channel, timestamp, address, data in test_writes: yield dut.cri.chan_sel.eq(channel) yield dut.cri.timestamp.eq(timestamp) @@ -96,6 +98,7 @@ class TestRepeater(unittest.TestCase): def send_requests(): for i in range(10): + yield yield dut.cri.chan_sel.eq(i << 16) yield dut.cri.cmd.eq(cri.commands["get_buffer_space"]) yield From 41972d67739e4f0b4fb2da0630ae7307803b6207 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 22:19:55 +0800 Subject: [PATCH 1219/2457] drtio: rt_packet_satellite CRI fixes --- artiq/gateware/drtio/rt_packet_satellite.py | 36 ++++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 1656f41cd..4aba55dcb 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -79,18 +79,25 @@ class RTPacketSatellite(Module): ] # RX FSM - read = Signal() + cri_read = Signal() + cri_buffer_space = Signal() self.comb += [ self.tsc_load_value.eq( rx_dp.packet_as["set_time"].timestamp), - If(load_read_request | read_request_pending, + If(cri_read | read_request_pending, self.cri.chan_sel.eq( rx_dp.packet_as["read_request"].chan_sel), - self.cri.timestamp.eq( - rx_dp.packet_as["read_request"].timeout) + ).Elif(cri_buffer_space, + self.cri.chan_sel.eq( + rx_dp.packet_as["buffer_space_request"].destination << 16) ).Else( self.cri.chan_sel.eq( rx_dp.packet_as["write"].chan_sel), + ), + If(cri_read | read_request_pending, + self.cri.timestamp.eq( + rx_dp.packet_as["read_request"].timeout) + ).Else( self.cri.timestamp.eq( rx_dp.packet_as["write"].timestamp) ), @@ -139,8 +146,7 @@ class RTPacketSatellite(Module): rx_fsm.act("WRITE", If(write_data_buffer_cnt == rx_dp.packet_as["write"].extra_data_cnt, - self.cri.cmd.eq(cri.commands["write"]), - NextState("INPUT") + NextState("WRITE_CMD") ).Else( write_data_buffer_load.eq(1), If(~rx_dp.frame_r, @@ -149,7 +155,17 @@ class RTPacketSatellite(Module): ) ) ) + rx_fsm.act("WRITE_CMD", + self.cri.cmd.eq(cri.commands["write"]), + NextState("INPUT") + ) + rx_fsm.act("BUFFER_SPACE_REQUEST", + cri_buffer_space.eq(1), + NextState("BUFFER_SPACE_REQUEST_CMD") + ) + rx_fsm.act("BUFFER_SPACE_REQUEST_CMD", + cri_buffer_space.eq(1), self.cri.cmd.eq(cri.commands["get_buffer_space"]), NextState("BUFFER_SPACE") ) @@ -158,8 +174,7 @@ class RTPacketSatellite(Module): If(timeout_counter.done, self.buffer_space_timeout.eq(1), NextState("INPUT") - ), - If(self.cri.o_buffer_space_valid, + ).Elif(self.cri.o_buffer_space_valid, buffer_space_set.eq(1), buffer_space_update.eq(1), NextState("INPUT") @@ -167,7 +182,12 @@ class RTPacketSatellite(Module): ) rx_fsm.act("READ_REQUEST", + cri_read.eq(1), + NextState("READ_REQUEST_CMD") + ) + rx_fsm.act("READ_REQUEST_CMD", load_read_request.eq(1), + cri_read.eq(1), self.cri.cmd.eq(cri.commands["read"]), NextState("INPUT") ) From 8227037a84293727f50a6e9dbee361eeae6bcffb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 11 Sep 2018 22:20:18 +0800 Subject: [PATCH 1220/2457] examples: add kasli_drtioswitching --- .../kasli_drtioswitching/device_db.py | 34 +++++++++++++++++++ .../kasli_drtioswitching/repository/blink.py | 17 ++++++++++ 2 files changed, 51 insertions(+) create mode 100644 artiq/examples/kasli_drtioswitching/device_db.py create mode 100644 artiq/examples/kasli_drtioswitching/repository/blink.py diff --git a/artiq/examples/kasli_drtioswitching/device_db.py b/artiq/examples/kasli_drtioswitching/device_db.py new file mode 100644 index 000000000..f04ee1869 --- /dev/null +++ b/artiq/examples/kasli_drtioswitching/device_db.py @@ -0,0 +1,34 @@ +core_addr = "kasli-1.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1/(8*150e6)} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, +} + +for i in range(3): + device_db["led" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": i << 16}, + } diff --git a/artiq/examples/kasli_drtioswitching/repository/blink.py b/artiq/examples/kasli_drtioswitching/repository/blink.py new file mode 100644 index 000000000..e5068efda --- /dev/null +++ b/artiq/examples/kasli_drtioswitching/repository/blink.py @@ -0,0 +1,17 @@ +from artiq.experiment import * + + +class Blink(EnvExperiment): + def build(self): + self.setattr_device("core") + self.leds = [self.get_device("led0"), self.get_device("led2")] + + @kernel + def run(self): + while True: + self.core.reset() + + while True: + for led in self.leds: + led.pulse(200*ms) + delay(200*ms) From 95432a4ac140a93366b68dbd2725bfcdd699c1b6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 13:01:27 +0800 Subject: [PATCH 1221/2457] drtio: remove old debugging features --- artiq/coredevice/drtio_dbg.py | 17 ----------- artiq/firmware/ksupport/api.rs | 2 -- artiq/firmware/ksupport/rtio.rs | 15 ---------- artiq/firmware/libproto_artiq/kernel_proto.rs | 5 ---- artiq/firmware/runtime/kern_hwreq.rs | 9 ------ artiq/firmware/runtime/rtio_mgt.rs | 28 ------------------- artiq/gateware/drtio/core.py | 4 +-- artiq/gateware/drtio/rt_controller_master.py | 23 --------------- artiq/gateware/test/drtio/test_full_stack.py | 21 +++++++------- 9 files changed, 11 insertions(+), 113 deletions(-) delete mode 100644 artiq/coredevice/drtio_dbg.py diff --git a/artiq/coredevice/drtio_dbg.py b/artiq/coredevice/drtio_dbg.py deleted file mode 100644 index 56482c6dc..000000000 --- a/artiq/coredevice/drtio_dbg.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -DRTIO debugging functions. - -Those syscalls are intended for ARTIQ developers only. -""" - -from artiq.language.core import syscall -from artiq.language.types import TTuple, TInt32, TInt64, TNone - - -@syscall(flags={"nounwind", "nowrite"}) -def drtio_get_packet_counts(linkno: TInt32) -> TTuple([TInt32, TInt32]): - raise NotImplementedError("syscall not simulated") - -@syscall(flags={"nounwind", "nowrite"}) -def drtio_get_fifo_space_req_count(linkno: TInt32) -> TInt32: - raise NotImplementedError("syscall not simulated") diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 77d8b1edc..c1a0c22ff 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -109,8 +109,6 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(dma_playback = ::dma_playback), api!(drtio_get_link_status = ::rtio::drtio::get_link_status), - api!(drtio_get_packet_counts = ::rtio::drtio::get_packet_counts), - api!(drtio_get_buffer_space_req_count = ::rtio::drtio::get_buffer_space_req_count), api!(i2c_start = ::nrt_bus::i2c::start), api!(i2c_restart = ::nrt_bus::i2c::restart), diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index 123d15d07..119fab8f5 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -219,19 +219,4 @@ pub mod drtio { send(&DrtioLinkStatusRequest { linkno: linkno as u8 }); recv!(&DrtioLinkStatusReply { up } => up) } - - #[repr(C)] - pub struct PacketCounts(i32, i32); - - pub extern fn get_packet_counts(linkno: i32) -> PacketCounts { - send(&DrtioPacketCountRequest { linkno: linkno as u8 }); - recv!(&DrtioPacketCountReply { tx_cnt, rx_cnt } - => PacketCounts(tx_cnt as i32, rx_cnt as i32)) - } - - pub extern fn get_buffer_space_req_count(linkno: i32) -> i32 { - send(&DrtioBufferSpaceReqCountRequest { linkno: linkno as u8 }); - recv!(&DrtioBufferSpaceReqCountReply { cnt } - => cnt as i32) - } } diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index ae794ec34..477c00a1b 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -49,11 +49,6 @@ pub enum Message<'a> { DrtioLinkStatusRequest { linkno: u8 }, DrtioLinkStatusReply { up: bool }, - DrtioPacketCountRequest { linkno: u8 }, - DrtioPacketCountReply { tx_cnt: u32, rx_cnt: u32 }, - DrtioBufferSpaceReqCountRequest { linkno: u8 }, - DrtioBufferSpaceReqCountReply { cnt: u32 }, - RunFinished, RunException { exception: Exception<'a>, diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index 4e758ec8d..c1bfbf7b0 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -302,15 +302,6 @@ pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result { - let (tx_cnt, rx_cnt) = rtio_mgt::drtio_dbg::get_packet_counts(linkno); - kern_send(io, &kern::DrtioPacketCountReply { tx_cnt: tx_cnt, rx_cnt: rx_cnt }) - } - &kern::DrtioBufferSpaceReqCountRequest { linkno } => { - let cnt = rtio_mgt::drtio_dbg::get_buffer_space_req_count(linkno); - kern_send(io, &kern::DrtioBufferSpaceReqCountReply { cnt: cnt }) - } - &kern::I2cStartRequest { busno } => { let succeeded = i2c::start(busno).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index a8055c943..4f9b6d718 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -357,31 +357,3 @@ pub fn init_core(phy: bool) { } drtio::init() } - -#[cfg(has_drtio)] -pub mod drtio_dbg { - use board_misoc::csr; - - pub fn get_packet_counts(linkno: u8) -> (u32, u32) { - let linkno = linkno as usize; - unsafe { - (csr::DRTIO[linkno].update_packet_cnt_write)(1); - ((csr::DRTIO[linkno].packet_cnt_tx_read)(), - (csr::DRTIO[linkno].packet_cnt_rx_read)()) - } - } - - pub fn get_buffer_space_req_count(linkno: u8) -> u32 { - let linkno = linkno as usize; - unsafe { - (csr::DRTIO[linkno].o_dbg_buffer_space_req_cnt_read)() - } - } -} - -#[cfg(not(has_drtio))] -pub mod drtio_dbg { - pub fn get_packet_counts(_linkno: u8) -> (u32, u32) { (0, 0) } - - pub fn get_buffer_space_req_count(_linkno: u8) -> u32 { 0 } -} diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index b3d722825..52e2bb948 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -161,13 +161,11 @@ class DRTIOMaster(Module): self.submodules.rt_packet = rt_packet_master.RTPacketMaster(self.link_layer) self.submodules.rt_controller = rt_controller_master.RTController( tsc, self.rt_packet) - self.submodules.rt_manager = rt_controller_master.RTManager(self.rt_packet) def get_csrs(self): return (self.link_layer.get_csrs() + self.link_stats.get_csrs() + - self.rt_controller.get_csrs() + - self.rt_manager.get_csrs()) + self.rt_controller.get_csrs()) @property def cri(self): diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index a1e4f11c9..473d2126d 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -220,26 +220,3 @@ class RTController(Module): def get_csrs(self): return self.csrs.get_csrs() - - -class RTManager(Module, AutoCSR): - def __init__(self, rt_packet): - self.request_echo = CSR() - - self.update_packet_cnt = CSR() - self.packet_cnt_tx = CSRStatus(32) - self.packet_cnt_rx = CSRStatus(32) - - # # # - - self.comb += self.request_echo.w.eq(rt_packet.echo_stb) - self.sync += [ - If(rt_packet.echo_ack, rt_packet.echo_stb.eq(0)), - If(self.request_echo.re, rt_packet.echo_stb.eq(1)) - ] - - self.sync += \ - If(self.update_packet_cnt.re, - self.packet_cnt_tx.status.eq(rt_packet.packet_cnt_tx), - self.packet_cnt_rx.status.eq(rt_packet.packet_cnt_rx) - ) diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 69f89b094..8a23b2db9 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -291,26 +291,25 @@ class TestFullStack(unittest.TestCase): def test_echo(self): dut = DUT(2) - csrs = dut.master.rt_controller.csrs - mgr = dut.master.rt_manager + packet = dut.master.rt_packet def test(): while not (yield from dut.master.link_layer.rx_up.read()): yield - yield from mgr.update_packet_cnt.write(1) - yield - self.assertEqual((yield from mgr.packet_cnt_tx.read()), 0) - self.assertEqual((yield from mgr.packet_cnt_rx.read()), 0) + self.assertEqual((yield dut.master.rt_packet.packet_cnt_tx), 0) + self.assertEqual((yield dut.master.rt_packet.packet_cnt_rx), 0) - yield from mgr.request_echo.write(1) + yield dut.master.rt_packet.echo_stb.eq(1) + yield + while not (yield dut.master.rt_packet.echo_ack): + yield + yield dut.master.rt_packet.echo_stb.eq(0) for i in range(15): yield - yield from mgr.update_packet_cnt.write(1) - yield - self.assertEqual((yield from mgr.packet_cnt_tx.read()), 1) - self.assertEqual((yield from mgr.packet_cnt_rx.read()), 1) + self.assertEqual((yield dut.master.rt_packet.packet_cnt_tx), 1) + self.assertEqual((yield dut.master.rt_packet.packet_cnt_rx), 1) run_simulation(dut, test(), self.clocks) From edf403b837258ce42ed91886579ac82d85629e9f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 15:44:34 +0800 Subject: [PATCH 1222/2457] drtio: improve error reporting --- artiq/firmware/satman/main.rs | 6 ++- artiq/firmware/satman/repeater.rs | 39 +++++++++++++++++-- artiq/gateware/drtio/core.py | 2 +- .../gateware/drtio/rt_controller_repeater.py | 25 +++++++++--- artiq/gateware/drtio/rt_errors_satellite.py | 7 +++- artiq/gateware/drtio/rt_packet_repeater.py | 6 +-- artiq/gateware/drtio/rt_packet_satellite.py | 2 + 7 files changed, 71 insertions(+), 16 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 12bb9d945..56345ae7a 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -260,7 +260,11 @@ fn drtiosat_process_errors() { error!("received truncated packet"); } if errors & 4 != 0 { - error!("timeout attempting to get buffer space from CRI") + let destination; + unsafe { + destination = csr::drtiosat::buffer_space_timeout_dest_read(); + } + error!("timeout attempting to get buffer space from CRI, destination=0x{:02x}", destination) } if errors & 8 != 0 { let channel; diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index c58d4b846..6f5b7b28f 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -2,10 +2,10 @@ use board_misoc::{csr, clock}; use board_artiq::{drtioaux, drtio_routing}; #[cfg(has_drtio_routing)] -fn rep_link_rx_up(linkno: u8) -> bool { - let linkno = linkno as usize; +fn rep_link_rx_up(repno: u8) -> bool { + let repno = repno as usize; unsafe { - (csr::DRTIOREP[linkno].rx_up_read)() == 1 + (csr::DRTIOREP[repno].rx_up_read)() == 1 } } @@ -40,6 +40,8 @@ impl Repeater { } pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8) { + self.process_errors(); + match self.state { RepeaterState::Down => { if rep_link_rx_up(self.repno) { @@ -109,6 +111,37 @@ impl Repeater { } } + fn process_errors(&self) { + let repno = self.repno as usize; + let errors; + unsafe { + errors = (csr::DRTIOREP[repno].protocol_error_read)(); + } + if errors & 1 != 0 { + error!("[REP#{}] received packet of an unknown type", repno); + } + if errors & 2 != 0 { + error!("[REP#{}] received truncated packet", repno); + } + if errors & 4 != 0 { + let chan_sel; + unsafe { + chan_sel = (csr::DRTIOREP[repno].command_missed_chan_sel_read)(); + } + error!("[REP#{}] CRI command missed, chan_sel=0x{:06x}", repno, chan_sel) + } + if errors & 8 != 0 { + let destination; + unsafe { + destination = (csr::DRTIOREP[repno].buffer_space_timeout_dest_read)(); + } + error!("[REP#{}] timeout attempting to get remote buffer space, destination=0x{:02x}", repno, destination); + } + unsafe { + (csr::DRTIOREP[repno].protocol_error_write)(errors); + } + } + fn recv_aux_timeout(&self, timeout: u32) -> Result { let max_time = clock::get_ms() + timeout as u64; loop { diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 52e2bb948..55176b1ce 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -143,7 +143,7 @@ class DRTIOSatellite(Module): ] self.submodules.rt_errors = rt_errors_satellite.RTErrorsSatellite( - self.rt_packet, tsc, self.cri, self.async_errors) + self.rt_packet, tsc, self.async_errors) def get_csrs(self): return ([self.reset, self.reset_phy, self.tsc_loaded] + diff --git a/artiq/gateware/drtio/rt_controller_repeater.py b/artiq/gateware/drtio/rt_controller_repeater.py index d75e87f64..655bf641e 100644 --- a/artiq/gateware/drtio/rt_controller_repeater.py +++ b/artiq/gateware/drtio/rt_controller_repeater.py @@ -10,6 +10,8 @@ class RTController(Module, AutoCSR): def __init__(self, rt_packet): self.set_time = CSR() self.protocol_error = CSR(4) + self.command_missed_chan_sel = CSRStatus(24) + self.buffer_space_timeout_dest = CSRStatus(8) set_time_stb = Signal() set_time_ack = Signal() @@ -23,14 +25,21 @@ class RTController(Module, AutoCSR): self.comb += self.set_time.w.eq(set_time_stb) errors = [ - (rt_packet.err_unknown_packet_type, "rtio_rx"), - (rt_packet.err_packet_truncated, "rtio_rx"), - (rt_packet.err_command_missed, "rtio"), - (rt_packet.err_buffer_space_timeout, "rtio") + (rt_packet.err_unknown_packet_type, "rtio_rx", None, None), + (rt_packet.err_packet_truncated, "rtio_rx", None, None), + (rt_packet.err_command_missed, "rtio", + rt_packet.cri.chan_sel, self.command_missed_chan_sel.status), + (rt_packet.err_buffer_space_timeout, "rtio", + rt_packet.buffer_space_destination, self.buffer_space_timeout_dest.status) ] - for n, (err_i, err_cd) in enumerate(errors): - xfer = BlindTransfer(err_cd, "sys") + for n, (err_i, err_cd, din, dout) in enumerate(errors): + if din is not None: + data_width = len(din) + else: + data_width = 0 + + xfer = BlindTransfer(err_cd, "sys", data_width=data_width) self.submodules += xfer self.comb += xfer.i.eq(err_i) @@ -41,3 +50,7 @@ class RTController(Module, AutoCSR): If(xfer.o, err_pending.eq(1)) ] self.comb += self.protocol_error.w[n].eq(err_pending) + + if din is not None: + self.comb += xfer.data_i.eq(din) + self.sync += If(xfer.o & ~err_pending, dout.eq(xfer.data_o)) diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index 2bf190a0f..1d857654c 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -7,11 +7,12 @@ from artiq.gateware.rtio.cdc import BlindTransfer class RTErrorsSatellite(Module, AutoCSR): - def __init__(self, rt_packet, tsc, cri, async_errors): + def __init__(self, rt_packet, tsc, async_errors): self.protocol_error = CSR(5) self.underflow_channel = CSRStatus(16) self.underflow_timestamp_event = CSRStatus(64) self.underflow_timestamp_counter = CSRStatus(64) + self.buffer_space_timeout_dest = CSRStatus(8) self.rtio_error = CSR(3) self.sequence_error_channel = CSRStatus(16) @@ -47,6 +48,7 @@ class RTErrorsSatellite(Module, AutoCSR): self.comb += xfer.data_i.eq(din) self.sync += If(xfer.o & ~pending, dout.eq(xfer.data_o)) + cri = rt_packet.cri # The master is normally responsible for avoiding output overflows # and output underflows. The error reports here are only for diagnosing @@ -68,7 +70,8 @@ class RTErrorsSatellite(Module, AutoCSR): error_csr(self.protocol_error, (rt_packet.unknown_packet_type, False, None, None), (rt_packet.packet_truncated, False, None, None), - (rt_packet.buffer_space_timeout, False, None, None), + (rt_packet.buffer_space_timeout, False, + cri.chan_sel[16:], self.buffer_space_timeout_dest.status), (underflow, True, underflow_error_cri, underflow_error_csr), (overflow, True, None, None) ) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 1798b6da8..0ecd353a8 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -20,6 +20,7 @@ class RTPacketRepeater(Module): # in rtio domain self.err_command_missed = Signal() self.err_buffer_space_timeout = Signal() + self.buffer_space_destination = Signal(8) # set_time interface, in rtio domain self.set_time_stb = Signal() @@ -85,9 +86,8 @@ class RTPacketRepeater(Module): ) # Buffer space - buffer_space_destination = Signal(8) self.sync.rtio += If(self.cri.cmd == cri.commands["get_buffer_space"], - buffer_space_destination.eq(self.cri.chan_sel[16:])) + self.buffer_space_destination.eq(self.cri.chan_sel[16:])) rx_buffer_space_not = Signal() rx_buffer_space = Signal(16) @@ -153,7 +153,7 @@ class RTPacketRepeater(Module): ) ) tx_fsm.act("BUFFER_SPACE", - tx_dp.send("buffer_space_request", destination=buffer_space_destination), + tx_dp.send("buffer_space_request", destination=self.buffer_space_destination), If(tx_dp.packet_last, buffer_space_not_ack.eq(1), NextState("WAIT_BUFFER_SPACE") diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 4aba55dcb..49ea2c3d0 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -144,6 +144,7 @@ class RTPacketSatellite(Module): NextState("INPUT") ) + # CRI mux defaults to write information rx_fsm.act("WRITE", If(write_data_buffer_cnt == rx_dp.packet_as["write"].extra_data_cnt, NextState("WRITE_CMD") @@ -170,6 +171,7 @@ class RTPacketSatellite(Module): NextState("BUFFER_SPACE") ) rx_fsm.act("BUFFER_SPACE", + cri_buffer_space.eq(1), timeout_counter.wait.eq(1), If(timeout_counter.done, self.buffer_space_timeout.eq(1), From 5bcd40ff59d9b2048875f9f6ba9f8ee31e6dbf4b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 17:30:55 +0800 Subject: [PATCH 1223/2457] cri: fix routing table depth --- artiq/gateware/rtio/cri.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 18ca1956b..0ed0d50e2 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -130,7 +130,7 @@ class CRIDecoder(Module, AutoCSR): selected = Signal(slave_bits) if enable_routing: - self.specials.routing_table = Memory(slave_bits, 8) + self.specials.routing_table = Memory(slave_bits, 256) rtp_csr = self.routing_table.get_port(write_capable=True) self.specials += rtp_csr From e36a8536d7fb0e390acd1517fc7c6a14e06e7904 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 17:31:23 +0800 Subject: [PATCH 1224/2457] runtime: better handling of aux timeouts --- artiq/firmware/runtime/rtio_mgt.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 4f9b6d718..093b37d79 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -193,9 +193,9 @@ pub mod drtio { } } - fn process_aux_errors(linkno: u8) { + fn process_aux_errors(io: &Io, linkno: u8) { drtioaux::send_link(linkno, &drtioaux::Packet::RtioErrorRequest).unwrap(); - match drtioaux::recv_timeout_link(linkno, None) { + match recv_aux_timeout(io, linkno, 200) { Ok(drtioaux::Packet::RtioNoErrorReply) => (), Ok(drtioaux::Packet::RtioErrorSequenceErrorReply { channel }) => error!("[LINK#{}] RTIO sequence error involving channel {}", linkno, channel), @@ -204,7 +204,7 @@ pub mod drtio { Ok(drtioaux::Packet::RtioErrorBusyReply { channel }) => error!("[LINK#{}] RTIO busy error involving channel {}", linkno, channel), Ok(_) => error!("[LINK#{}] received unexpected aux packet", linkno), - Err(e) => error!("[LINK#{}] aux packet error ({})", linkno, e) + Err(e) => error!("[LINK#{}] communication failed ({})", linkno, e) } } @@ -216,7 +216,7 @@ pub mod drtio { /* link was previously up */ if link_rx_up(linkno) { process_local_errors(linkno); - process_aux_errors(linkno); + process_aux_errors(&io, linkno); } else { info!("[LINK#{}] link is down", linkno); set_link_up(linkno, false); From 420e1cb1d0676a0dd0b3c5187fb33adb595e4125 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 18:08:16 +0800 Subject: [PATCH 1225/2457] cri: fix firmware routing table access --- .../firmware/libboard_artiq/drtio_routing.rs | 4 +-- artiq/gateware/rtio/__init__.py | 2 +- artiq/gateware/rtio/cri.py | 34 +++++++++++-------- artiq/gateware/targets/kasli.py | 4 +++ 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index 4302cd880..c78b5cddd 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -75,8 +75,8 @@ pub fn program_interconnect(rt: &RoutingTable, rank: u8) for i in 0..DEST_COUNT { let hop = rt.0[i][rank as usize]; unsafe { - csr::cri_con::routing_destination_write(i as _); - csr::cri_con::routing_hop_write(hop); + csr::routing_table::destination_write(i as _); + csr::routing_table::hop_write(hop); } } } diff --git a/artiq/gateware/rtio/__init__.py b/artiq/gateware/rtio/__init__.py index a144f593c..af4989f7c 100644 --- a/artiq/gateware/rtio/__init__.py +++ b/artiq/gateware/rtio/__init__.py @@ -1,5 +1,5 @@ from artiq.gateware.rtio.tsc import TSC -from artiq.gateware.rtio.cri import KernelInitiator, CRIInterconnectShared +from artiq.gateware.rtio.cri import KernelInitiator, CRIInterconnectShared, RoutingTableAccess from artiq.gateware.rtio.channel import Channel, LogChannel from artiq.gateware.rtio.core import Core from artiq.gateware.rtio.analyzer import Analyzer diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 0ed0d50e2..b60164ba2 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -119,28 +119,15 @@ class CRIDecoder(Module, AutoCSR): self.slaves = slaves self.master = master - slave_bits = bits_for(len(slaves)-1) - if enable_routing: - self.routing_destination = CSRStorage(8) - self.routing_hop = CSR(slave_bits) - # # # # routing + slave_bits = bits_for(len(slaves)-1) selected = Signal(slave_bits) if enable_routing: self.specials.routing_table = Memory(slave_bits, 256) - rtp_csr = self.routing_table.get_port(write_capable=True) - self.specials += rtp_csr - self.comb += [ - rtp_csr.adr.eq(self.routing_destination.storage), - rtp_csr.dat_w.eq(self.routing_hop.r), - rtp_csr.we.eq(self.routing_hop.re), - self.routing_hop.w.eq(rtp_csr.dat_r) - ] - if mode == "async": rtp_decoder = self.routing_table.get_port() elif mode == "sync": @@ -220,3 +207,22 @@ class CRIInterconnectShared(Module): def get_csrs(self): return self.switch.get_csrs() + self.decoder.get_csrs() + + +class RoutingTableAccess(Module, AutoCSR): + def __init__(self, interconnect): + if isinstance(interconnect, CRIInterconnectShared): + interconnect = interconnect.decoder + + rtp_csr = interconnect.routing_table.get_port(write_capable=True) + self.specials += rtp_csr + + self.destination = CSRStorage(8) + self.hop = CSR(len(rtp_csr.dat_w)) + + self.comb += [ + rtp_csr.adr.eq(self.destination.storage), + rtp_csr.dat_w.eq(self.hop.r), + rtp_csr.we.eq(self.hop.re), + self.hop.w.eq(rtp_csr.dat_r) + ] diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 75c3fa5e9..9070bf241 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -730,6 +730,8 @@ class _MasterBase(MiniSoC, AMPSoC): [self.rtio_core.cri] + self.drtio_cri, enable_routing=True) self.register_kernel_cpu_csrdevice("cri_con") + self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) + self.csr_devices.append("routing_table") self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.cri_con.switch.slave, self.get_native_sdram_if()) @@ -900,6 +902,8 @@ class _SatelliteBase(BaseSoC): [self.local_io.cri] + self.drtio_cri, mode="sync", enable_routing=True) self.csr_devices.append("cri_con") + self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) + self.csr_devices.append("routing_table") class Master(_MasterBase): From 0befec7d26671eb486ed50100d09a9e18966d632 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 20:54:01 +0800 Subject: [PATCH 1226/2457] drtio: improve repeater error reports --- artiq/firmware/satman/repeater.rs | 4 +++- artiq/gateware/drtio/rt_controller_repeater.py | 4 +++- artiq/gateware/drtio/rt_packet_repeater.py | 8 +++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index 6f5b7b28f..889e4aba7 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -124,11 +124,13 @@ impl Repeater { error!("[REP#{}] received truncated packet", repno); } if errors & 4 != 0 { + let cmd; let chan_sel; unsafe { + cmd = (csr::DRTIOREP[repno].command_missed_cmd_read)(); chan_sel = (csr::DRTIOREP[repno].command_missed_chan_sel_read)(); } - error!("[REP#{}] CRI command missed, chan_sel=0x{:06x}", repno, chan_sel) + error!("[REP#{}] CRI command missed, cmd={}, chan_sel=0x{:06x}", repno, cmd, chan_sel) } if errors & 8 != 0 { let destination; diff --git a/artiq/gateware/drtio/rt_controller_repeater.py b/artiq/gateware/drtio/rt_controller_repeater.py index 655bf641e..b877700b1 100644 --- a/artiq/gateware/drtio/rt_controller_repeater.py +++ b/artiq/gateware/drtio/rt_controller_repeater.py @@ -10,6 +10,7 @@ class RTController(Module, AutoCSR): def __init__(self, rt_packet): self.set_time = CSR() self.protocol_error = CSR(4) + self.command_missed_cmd = CSRStatus(2) self.command_missed_chan_sel = CSRStatus(24) self.buffer_space_timeout_dest = CSRStatus(8) @@ -28,7 +29,8 @@ class RTController(Module, AutoCSR): (rt_packet.err_unknown_packet_type, "rtio_rx", None, None), (rt_packet.err_packet_truncated, "rtio_rx", None, None), (rt_packet.err_command_missed, "rtio", - rt_packet.cri.chan_sel, self.command_missed_chan_sel.status), + Cat(rt_packet.command_missed_cmd, rt_packet.command_missed_chan_sel), + Cat(self.command_missed_cmd.status, self.command_missed_chan_sel.status)), (rt_packet.err_buffer_space_timeout, "rtio", rt_packet.buffer_space_destination, self.buffer_space_timeout_dest.status) ] diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 0ecd353a8..7f709589f 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -19,6 +19,8 @@ class RTPacketRepeater(Module): # in rtio domain self.err_command_missed = Signal() + self.command_missed_cmd = Signal(2) + self.command_missed_chan_sel = Signal(24) self.err_buffer_space_timeout = Signal() self.buffer_space_destination = Signal(8) @@ -103,7 +105,11 @@ class RTPacketRepeater(Module): # Missed commands cri_ready = Signal() - self.sync.rtio += self.err_command_missed.eq(~cri_ready & (self.cri.cmd != cri.commands["nop"])) + self.sync.rtio += [ + self.err_command_missed.eq(~cri_ready & (self.cri.cmd != cri.commands["nop"])), + self.command_missed_chan_sel.eq(self.cri.chan_sel), + self.command_missed_cmd.eq(self.cri.cmd) + ] # TX FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) From 5a9cc004f2f62f81a89a2749b3b00ad65d5772d9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 22:57:21 +0800 Subject: [PATCH 1227/2457] drtio: receive and print unsolicited aux packets Helps with debugging and prevents the aux channel from getting stuck after packets arrive after the timeout. --- artiq/firmware/runtime/rtio_mgt.rs | 9 +++++++++ artiq/firmware/satman/repeater.rs | 13 +++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 093b37d79..ea34792c4 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -172,6 +172,14 @@ pub mod drtio { Ok(()) } + fn process_unsolicited_aux(linkno: u8) { + match drtioaux::recv_link(linkno) { + Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet), + Ok(None) => (), + Err(_) => warn!("[LINK#{}] aux packet error", linkno) + } + } + fn process_local_errors(linkno: u8) { let errors; let linkidx = linkno as usize; @@ -215,6 +223,7 @@ pub mod drtio { if link_up(linkno) { /* link was previously up */ if link_rx_up(linkno) { + process_unsolicited_aux(linkno); process_local_errors(linkno); process_aux_errors(&io, linkno); } else { diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index 889e4aba7..9b1f39849 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -40,7 +40,7 @@ impl Repeater { } pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8) { - self.process_errors(); + self.process_local_errors(); match self.state { RepeaterState::Down => { @@ -97,6 +97,7 @@ impl Repeater { } } RepeaterState::Up => { + self.process_unsolicited_aux(); if !rep_link_rx_up(self.repno) { info!("[REP#{}] link is down", self.repno); self.state = RepeaterState::Down; @@ -111,7 +112,15 @@ impl Repeater { } } - fn process_errors(&self) { + fn process_unsolicited_aux(&self) { + match drtioaux::recv_link(self.auxno) { + Ok(Some(packet)) => warn!("[REP#{}] unsolicited aux packet: {:?}", self.repno, packet), + Ok(None) => (), + Err(_) => warn!("[REP#{}] aux packet error", self.repno) + } + } + + fn process_local_errors(&self) { let repno = self.repno as usize; let errors; unsafe { From 6cf3db3485f8241c2cefa7744c9944b59b407573 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Sep 2018 23:02:54 +0800 Subject: [PATCH 1228/2457] satman: forward RTIO resets --- artiq/firmware/satman/main.rs | 6 ++++++ artiq/firmware/satman/repeater.rs | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 56345ae7a..e8c0b60f4 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -55,6 +55,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::Packet::EchoRequest => drtioaux::send_link(0, &drtioaux::Packet::EchoReply), drtioaux::Packet::ResetRequest { phy } => { + info!("resetting RTIO"); if phy { drtiosat_reset_phy(true); drtiosat_reset_phy(false); @@ -62,6 +63,11 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtiosat_reset(true); drtiosat_reset(false); } + for rep in _repeaters.iter() { + if let Err(e) = rep.rtio_reset(phy) { + error!("failed to issue RTIO reset ({})", e); + } + } drtioaux::send_link(0, &drtioaux::Packet::ResetAck) }, diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index 9b1f39849..bd2fe8999 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -227,6 +227,20 @@ impl Repeater { } Ok(()) } + + pub fn rtio_reset(&self, phy: bool) -> Result<(), &'static str> { + if self.state != RepeaterState::Up { + return Ok(()); + } + drtioaux::send_link(self.auxno, &drtioaux::Packet::ResetRequest { + phy: phy + }).unwrap(); + let reply = self.recv_aux_timeout(200)?; + if reply != drtioaux::Packet::ResetAck { + return Err("unexpected reply"); + } + Ok(()) + } } #[cfg(not(has_drtio_routing))] From fa872c33414f0b758a46c356de7069adf7aa8b1c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 13 Sep 2018 12:00:29 +0800 Subject: [PATCH 1229/2457] firmware: implement DRTIO destination survey --- artiq/firmware/libboard_artiq/drtioaux.rs | 15 +++- .../firmware/libproto_artiq/drtioaux_proto.rs | 46 ++++++---- artiq/firmware/runtime/rtio_mgt.rs | 67 +++++++++++--- artiq/firmware/satman/main.rs | 89 +++++++++++++------ artiq/firmware/satman/repeater.rs | 36 +++++--- 5 files changed, 175 insertions(+), 78 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtioaux.rs b/artiq/firmware/libboard_artiq/drtioaux.rs index 9c189e148..d176e67da 100644 --- a/artiq/firmware/libboard_artiq/drtioaux.rs +++ b/artiq/firmware/libboard_artiq/drtioaux.rs @@ -10,14 +10,21 @@ pub use proto_artiq::drtioaux_proto::Packet; // this is parametric over T because there's no impl Fail for !. #[derive(Fail, Debug)] pub enum Error { - #[fail(display = "packet CRC failed")] - CorruptedPacket, - #[fail(display = "timed out waiting for data")] - TimedOut, #[fail(display = "invalid node number")] NoRoute, + #[fail(display = "gateware reported error")] GatewareError, + #[fail(display = "packet CRC failed")] + CorruptedPacket, + + #[fail(display = "link is down")] + LinkDown, + #[fail(display = "timed out waiting for data")] + TimedOut, + #[fail(display = "unexpected reply")] + UnexpectedReply, + #[fail(display = "protocol error: {}", _0)] Protocol(#[cause] ProtocolError) } diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index e20194442..044f9b80e 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -22,11 +22,12 @@ pub enum Packet { ResetAck, TSCAck, - RtioErrorRequest, - RtioNoErrorReply, - RtioErrorSequenceErrorReply { channel: u16 }, - RtioErrorCollisionReply { channel: u16 }, - RtioErrorBusyReply { channel: u16 }, + DestinationStatusRequest { destination: u8 }, + DestinationDownReply, + DestinationOkReply, + DestinationSequenceErrorReply { channel: u16 }, + DestinationCollisionReply { channel: u16 }, + DestinationBusyReply { channel: u16 }, RoutingSetPath { destination: u8, hops: [u8; 32] }, RoutingSetRank { rank: u8 }, @@ -67,15 +68,18 @@ impl Packet { 0x03 => Packet::ResetAck, 0x04 => Packet::TSCAck, - 0x20 => Packet::RtioErrorRequest, - 0x21 => Packet::RtioNoErrorReply, - 0x22 => Packet::RtioErrorSequenceErrorReply { + 0x20 => Packet::DestinationStatusRequest { + destination: reader.read_u8()? + }, + 0x21 => Packet::DestinationDownReply, + 0x22 => Packet::DestinationOkReply, + 0x23 => Packet::DestinationSequenceErrorReply { channel: reader.read_u16()? }, - 0x23 => Packet::RtioErrorCollisionReply { + 0x24 => Packet::DestinationCollisionReply { channel: reader.read_u16()? }, - 0x24 => Packet::RtioErrorBusyReply { + 0x25 => Packet::DestinationBusyReply { channel: reader.read_u16()? }, @@ -186,22 +190,26 @@ impl Packet { Packet::TSCAck => writer.write_u8(0x04)?, - Packet::RtioErrorRequest => - writer.write_u8(0x20)?, - Packet::RtioNoErrorReply => - writer.write_u8(0x21)?, - Packet::RtioErrorSequenceErrorReply { channel } => { - writer.write_u8(0x22)?; - writer.write_u16(channel)?; + Packet::DestinationStatusRequest {destination } => { + writer.write_u8(0x20)?; + writer.write_u8(destination)?; }, - Packet::RtioErrorCollisionReply { channel } => { + Packet::DestinationDownReply => + writer.write_u8(0x21)?, + Packet::DestinationOkReply => + writer.write_u8(0x22)?, + Packet::DestinationSequenceErrorReply { channel } => { writer.write_u8(0x23)?; writer.write_u16(channel)?; }, - Packet::RtioErrorBusyReply { channel } => { + Packet::DestinationCollisionReply { channel } => { writer.write_u8(0x24)?; writer.write_u16(channel)?; }, + Packet::DestinationBusyReply { channel } => { + writer.write_u8(0x25)?; + writer.write_u16(channel)?; + }, Packet::RoutingSetPath { destination, hops } => { writer.write_u8(0x30)?; diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index ea34792c4..c6ba76d43 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -201,22 +201,63 @@ pub mod drtio { } } - fn process_aux_errors(io: &Io, linkno: u8) { - drtioaux::send_link(linkno, &drtioaux::Packet::RtioErrorRequest).unwrap(); - match recv_aux_timeout(io, linkno, 200) { - Ok(drtioaux::Packet::RtioNoErrorReply) => (), - Ok(drtioaux::Packet::RtioErrorSequenceErrorReply { channel }) => - error!("[LINK#{}] RTIO sequence error involving channel {}", linkno, channel), - Ok(drtioaux::Packet::RtioErrorCollisionReply { channel }) => - error!("[LINK#{}] RTIO collision involving channel {}", linkno, channel), - Ok(drtioaux::Packet::RtioErrorBusyReply { channel }) => - error!("[LINK#{}] RTIO busy error involving channel {}", linkno, channel), - Ok(_) => error!("[LINK#{}] received unexpected aux packet", linkno), - Err(e) => error!("[LINK#{}] communication failed ({})", linkno, e) + fn destination_survey(io: &Io, routing_table: &drtio_routing::RoutingTable, + up_destinations: &mut [bool; drtio_routing::DEST_COUNT]) { + for destination in 0..drtio_routing::DEST_COUNT { + let hop = routing_table.0[destination][0]; + + if hop == 0 { + /* local RTIO */ + up_destinations[destination] = true; + } else if hop as usize <= csr::DRTIO.len() { + let linkno = hop - 1; + if up_destinations[destination] { + if link_up(linkno) { + drtioaux::send_link(linkno, &drtioaux::Packet::DestinationStatusRequest { + destination: destination as u8 + }).unwrap(); + match recv_aux_timeout(io, linkno, 200) { + Ok(drtioaux::Packet::DestinationDownReply) => { + info!("[DEST#{}] destination is down", destination); + up_destinations[destination] = false; + }, + Ok(drtioaux::Packet::DestinationOkReply) => (), + Ok(drtioaux::Packet::DestinationSequenceErrorReply { channel }) => + error!("[DEST#{}] RTIO sequence error involving channel 0x{:04x}", destination, channel), + Ok(drtioaux::Packet::DestinationCollisionReply { channel }) => + error!("[DEST#{}] RTIO collision involving channel 0x{:04x}", destination, channel), + Ok(drtioaux::Packet::DestinationBusyReply { channel }) => + error!("[DEST#{}] RTIO busy error involving channel 0x{:04x}", destination, channel), + Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), + Err(e) => error!("[DEST#{}] communication failed ({})", destination, e) + } + } else { + info!("[DEST#{}] destination is down", destination); + up_destinations[destination] = false; + } + } else { + if link_up(linkno) { + drtioaux::send_link(linkno, &drtioaux::Packet::DestinationStatusRequest { + destination: destination as u8 + }).unwrap(); + match recv_aux_timeout(io, linkno, 200) { + Ok(drtioaux::Packet::DestinationDownReply) => (), + Ok(drtioaux::Packet::DestinationOkReply) => { + info!("[DEST#{}] destination is up", destination); + up_destinations[destination] = true; + /* TODO: get buffer space */ + }, + Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), + Err(e) => error!("[DEST#{}] communication failed ({})", destination, e) + } + } + } + } } } pub fn link_thread(io: Io, routing_table: &drtio_routing::RoutingTable) { + let mut up_destinations = [false; drtio_routing::DEST_COUNT]; loop { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; @@ -225,7 +266,6 @@ pub mod drtio { if link_rx_up(linkno) { process_unsolicited_aux(linkno); process_local_errors(linkno); - process_aux_errors(&io, linkno); } else { info!("[LINK#{}] link is down", linkno); set_link_up(linkno, false); @@ -255,6 +295,7 @@ pub mod drtio { } } } + destination_survey(&io, routing_table, &mut up_destinations); io.sleep(200).unwrap(); } } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index e8c0b60f4..8e3b22e7d 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -71,39 +71,70 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::send_link(0, &drtioaux::Packet::ResetAck) }, - drtioaux::Packet::RtioErrorRequest => { - let errors; - unsafe { - errors = csr::drtiosat::rtio_error_read(); - } - if errors & 1 != 0 { - let channel; + drtioaux::Packet::DestinationStatusRequest { destination } => { + #[cfg(has_drtio_routing)] + let hop = _routing_table.0[destination as usize][*_rank as usize]; + #[cfg(not(has_drtio_routing))] + let hop = 0; + + if hop == 0 { + let errors; unsafe { - channel = csr::drtiosat::sequence_error_channel_read(); - csr::drtiosat::rtio_error_write(1); + errors = csr::drtiosat::rtio_error_read(); } - drtioaux::send_link(0, - &drtioaux::Packet::RtioErrorSequenceErrorReply { channel }) - } else if errors & 2 != 0 { - let channel; - unsafe { - channel = csr::drtiosat::collision_channel_read(); - csr::drtiosat::rtio_error_write(2); + if errors & 1 != 0 { + let channel; + unsafe { + channel = csr::drtiosat::sequence_error_channel_read(); + csr::drtiosat::rtio_error_write(1); + } + drtioaux::send_link(0, + &drtioaux::Packet::DestinationSequenceErrorReply { channel })?; + } else if errors & 2 != 0 { + let channel; + unsafe { + channel = csr::drtiosat::collision_channel_read(); + csr::drtiosat::rtio_error_write(2); + } + drtioaux::send_link(0, + &drtioaux::Packet::DestinationCollisionReply { channel })?; + } else if errors & 4 != 0 { + let channel; + unsafe { + channel = csr::drtiosat::busy_channel_read(); + csr::drtiosat::rtio_error_write(4); + } + drtioaux::send_link(0, + &drtioaux::Packet::DestinationBusyReply { channel })?; } - drtioaux::send_link(0, - &drtioaux::Packet::RtioErrorCollisionReply { channel }) - } else if errors & 4 != 0 { - let channel; - unsafe { - channel = csr::drtiosat::busy_channel_read(); - csr::drtiosat::rtio_error_write(4); + else { + drtioaux::send_link(0, &drtioaux::Packet::DestinationOkReply)?; } - drtioaux::send_link(0, - &drtioaux::Packet::RtioErrorBusyReply { channel }) } - else { - drtioaux::send_link(0, &drtioaux::Packet::RtioNoErrorReply) + + #[cfg(has_drtio_routing)] + { + if hop != 0 { + let hop = hop as usize; + if hop <= csr::DRTIOREP.len() { + let repno = hop - 1; + match _repeaters[repno].aux_forward(&drtioaux::Packet::DestinationStatusRequest { + destination: destination + }) { + Ok(()) => (), + Err(drtioaux::Error::LinkDown) => drtioaux::send_link(0, &drtioaux::Packet::DestinationDownReply)?, + Err(e) => { + drtioaux::send_link(0, &drtioaux::Packet::DestinationDownReply)?; + error!("aux error when handling destination status request: {}", e); + }, + } + } else { + drtioaux::send_link(0, &drtioaux::Packet::DestinationDownReply)?; + } + } } + + Ok(()) } #[cfg(has_drtio_routing)] @@ -135,11 +166,11 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } #[cfg(not(has_drtio_routing))] - drtioaux::Packet::RoutingSetPath { _destination, _hops } => { + drtioaux::Packet::RoutingSetPath { destination, hops } => { drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) } #[cfg(not(has_drtio_routing))] - drtioaux::Packet::RoutingSetRank { _rank } => { + drtioaux::Packet::RoutingSetRank { rank } => { drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) } diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index bd2fe8999..c97ece3e5 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -153,24 +153,34 @@ impl Repeater { } } - fn recv_aux_timeout(&self, timeout: u32) -> Result { + fn recv_aux_timeout(&self, timeout: u32) -> Result> { let max_time = clock::get_ms() + timeout as u64; loop { if !rep_link_rx_up(self.repno) { - return Err("link went down"); + return Err(drtioaux::Error::LinkDown); } if clock::get_ms() > max_time { - return Err("timeout"); + return Err(drtioaux::Error::TimedOut); } match drtioaux::recv_link(self.auxno) { Ok(Some(packet)) => return Ok(packet), Ok(None) => (), - Err(_) => return Err("aux packet error") + Err(e) => return Err(e) } } } - pub fn sync_tsc(&self) -> Result<(), &'static str> { + pub fn aux_forward(&self, request: &drtioaux::Packet) -> Result<(), drtioaux::Error> { + if self.state != RepeaterState::Up { + return Err(drtioaux::Error::LinkDown); + } + drtioaux::send_link(self.auxno, request).unwrap(); + let reply = self.recv_aux_timeout(200)?; + drtioaux::send_link(0, &reply).unwrap(); + Ok(()) + } + + pub fn sync_tsc(&self) -> Result<(), drtioaux::Error> { if self.state != RepeaterState::Up { return Ok(()); } @@ -187,11 +197,11 @@ impl Repeater { if reply == drtioaux::Packet::TSCAck { return Ok(()); } else { - return Err("unexpected reply"); + return Err(drtioaux::Error::UnexpectedReply); } } - pub fn set_path(&self, destination: u8, hops: &[u8; drtio_routing::MAX_HOPS]) -> Result<(), &'static str> { + pub fn set_path(&self, destination: u8, hops: &[u8; drtio_routing::MAX_HOPS]) -> Result<(), drtioaux::Error> { if self.state != RepeaterState::Up { return Ok(()); } @@ -202,19 +212,19 @@ impl Repeater { }).unwrap(); let reply = self.recv_aux_timeout(200)?; if reply != drtioaux::Packet::RoutingAck { - return Err("unexpected reply"); + return Err(drtioaux::Error::UnexpectedReply); } Ok(()) } - pub fn load_routing_table(&self, routing_table: &drtio_routing::RoutingTable) -> Result<(), &'static str> { + pub fn load_routing_table(&self, routing_table: &drtio_routing::RoutingTable) -> Result<(), drtioaux::Error> { for i in 0..drtio_routing::DEST_COUNT { self.set_path(i as u8, &routing_table.0[i])?; } Ok(()) } - pub fn set_rank(&self, rank: u8) -> Result<(), &'static str> { + pub fn set_rank(&self, rank: u8) -> Result<(), drtioaux::Error> { if self.state != RepeaterState::Up { return Ok(()); } @@ -223,12 +233,12 @@ impl Repeater { }).unwrap(); let reply = self.recv_aux_timeout(200)?; if reply != drtioaux::Packet::RoutingAck { - return Err("unexpected reply"); + return Err(drtioaux::Error::UnexpectedReply); } Ok(()) } - pub fn rtio_reset(&self, phy: bool) -> Result<(), &'static str> { + pub fn rtio_reset(&self, phy: bool) -> Result<(), drtioaux::Error> { if self.state != RepeaterState::Up { return Ok(()); } @@ -237,7 +247,7 @@ impl Repeater { }).unwrap(); let reply = self.recv_aux_timeout(200)?; if reply != drtioaux::Packet::ResetAck { - return Err("unexpected reply"); + return Err(drtioaux::Error::UnexpectedReply); } Ok(()) } From 042b0065de036737641d7052d9d1e1efa79dcd74 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 13 Sep 2018 14:10:52 +0800 Subject: [PATCH 1230/2457] runtime: print destination up message for local RTIO --- artiq/firmware/runtime/rtio_mgt.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index c6ba76d43..f9df23b38 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -208,7 +208,10 @@ pub mod drtio { if hop == 0 { /* local RTIO */ - up_destinations[destination] = true; + if !up_destinations[destination] { + info!("[DEST#{}] destination is up", destination); + up_destinations[destination] = true; + } } else if hop as usize <= csr::DRTIO.len() { let linkno = hop - 1; if up_destinations[destination] { From e95638e0a73f7ac3daf65565d856b3ee13275edb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 13 Sep 2018 15:54:28 +0800 Subject: [PATCH 1231/2457] style --- artiq/firmware/libproto_artiq/drtioaux_proto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 044f9b80e..288913282 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -190,7 +190,7 @@ impl Packet { Packet::TSCAck => writer.write_u8(0x04)?, - Packet::DestinationStatusRequest {destination } => { + Packet::DestinationStatusRequest { destination } => { writer.write_u8(0x20)?; writer.write_u8(destination)?; }, From 1ef39a98a7ae605c659fea980673afdd8281051f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 13 Sep 2018 16:16:32 +0800 Subject: [PATCH 1232/2457] drtio: implement per-destination buffer space --- artiq/firmware/runtime/rtio_mgt.rs | 26 +++++++------- artiq/gateware/drtio/rt_controller_master.py | 36 ++++++++++++++++---- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index f9df23b38..2153e9986 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -83,16 +83,6 @@ pub mod drtio { } } - fn init_buffer_space(linkno: u8) { - let linkidx = linkno as usize; - unsafe { - (csr::DRTIO[linkidx].o_get_buffer_space_write)(1); - while (csr::DRTIO[linkidx].o_wait_read)() == 1 {} - info!("[LINK#{}] buffer space is {}", - linkno, (csr::DRTIO[linkidx].o_dbg_buffer_space_read)()); - } - } - fn ping_remote(linkno: u8, io: &Io) -> u32 { let mut count = 0; loop { @@ -172,6 +162,19 @@ pub mod drtio { Ok(()) } + fn init_buffer_space(destination: u8, linkno: u8) { + let linkno = linkno as usize; + unsafe { + (csr::DRTIO[linkno].destination_write)(destination); + (csr::DRTIO[linkno].force_destination_write)(1); + (csr::DRTIO[linkno].o_get_buffer_space_write)(1); + while (csr::DRTIO[linkno].o_wait_read)() == 1 {} + info!("[DEST#{}] buffer space is {}", + destination, (csr::DRTIO[linkno].o_dbg_buffer_space_read)()); + (csr::DRTIO[linkno].force_destination_write)(0); + } + } + fn process_unsolicited_aux(linkno: u8) { match drtioaux::recv_link(linkno) { Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet), @@ -248,7 +251,7 @@ pub mod drtio { Ok(drtioaux::Packet::DestinationOkReply) => { info!("[DEST#{}] destination is up", destination); up_destinations[destination] = true; - /* TODO: get buffer space */ + init_buffer_space(destination as u8, linkno); }, Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), Err(e) => error!("[DEST#{}] communication failed ({})", destination, e) @@ -281,7 +284,6 @@ pub mod drtio { if ping_count > 0 { info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); set_link_up(linkno, true); - init_buffer_space(linkno); if let Err(e) = sync_tsc(&io, linkno) { error!("[LINK#{}] failed to sync TSC ({})", linkno, e); } diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 473d2126d..d1e0dd1e2 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -19,6 +19,9 @@ class _CSRs(AutoCSR): self.set_time = CSR() self.underflow_margin = CSRStorage(16, reset=300) + self.force_destination = CSRStorage() + self.destination = CSRStorage(8) + self.o_get_buffer_space = CSR() self.o_dbg_buffer_space = CSRStatus(16) self.o_dbg_buffer_space_req_cnt = CSRStatus(32) @@ -71,11 +74,17 @@ class RTController(Module): If(self.csrs.set_time.re, rt_packet.set_time_stb.eq(1)) ] + # chan_sel forcing + chan_sel = Signal(24) + self.comb += chan_sel.eq(Mux(self.csrs.force_destination.storage, + self.csrs.destination.storage << 16, + self.cri.chan_sel)) + # common packet fields rt_packet_buffer_request = Signal() rt_packet_read_request = Signal() self.comb += [ - rt_packet.sr_chan_sel.eq(self.cri.chan_sel), + rt_packet.sr_chan_sel.eq(chan_sel), rt_packet.sr_address.eq(self.cri.o_address), rt_packet.sr_data.eq(self.cri.o_data), rt_packet.sr_timestamp.eq(self.cri.timestamp), @@ -112,7 +121,22 @@ class RTController(Module): self.comb += cond_underflow.eq((self.cri.timestamp[tsc.glbl_fine_ts_width:] - self.csrs.underflow_margin.storage[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) - buffer_space = Signal(16) + # buffer space + buffer_space = Memory(16, 256) + buffer_space_port = buffer_space.get_port(write_capable=True) + self.specials += buffer_space, buffer_space_port + + buffer_space_load = Signal() + buffer_space_dec = Signal() + self.comb += [ + buffer_space_port.adr.eq(chan_sel[16:]), + buffer_space_port.we.eq(buffer_space_load | buffer_space_dec), + If(buffer_space_load, + buffer_space_port.dat_w.eq(rt_packet.buffer_space) + ).Else( + buffer_space_port.dat_w.eq(buffer_space_port.dat_r - 1) + ) + ] # input status i_status_wait_event = Signal() @@ -158,8 +182,8 @@ class RTController(Module): o_status_wait.eq(1), rt_packet.sr_stb.eq(1), If(rt_packet.sr_ack, - NextValue(buffer_space, buffer_space - 1), - If(buffer_space <= 1, + buffer_space_dec.eq(1), + If(buffer_space_port.dat_r <= 1, NextState("GET_BUFFER_SPACE") ).Else( NextState("IDLE") @@ -177,7 +201,7 @@ class RTController(Module): ) fsm.act("GET_BUFFER_SPACE_REPLY", o_status_wait.eq(1), - NextValue(buffer_space, rt_packet.buffer_space), + buffer_space_load.eq(1), rt_packet.buffer_space_not_ack.eq(1), If(rt_packet.buffer_space_not, If(rt_packet.buffer_space != 0, @@ -211,7 +235,7 @@ class RTController(Module): ) # debug CSRs - self.comb += self.csrs.o_dbg_buffer_space.status.eq(buffer_space), + self.comb += self.csrs.o_dbg_buffer_space.status.eq(buffer_space_port.dat_r), self.sync += \ If((rt_packet.sr_stb & rt_packet.sr_ack & rt_packet_buffer_request), self.csrs.o_dbg_buffer_space_req_cnt.status.eq( From ae72e3a51efaf472eca899b704109b50c9503508 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 14 Sep 2018 20:26:39 +0800 Subject: [PATCH 1233/2457] firmware: add support for moninj and kern_hwreq over DRTIO switching --- artiq/firmware/libboard_artiq/drtioaux.rs | 29 +- .../firmware/libproto_artiq/drtioaux_proto.rs | 66 +++-- artiq/firmware/runtime/kern_hwreq.rs | 255 ++++++----------- artiq/firmware/runtime/main.rs | 18 +- artiq/firmware/runtime/moninj.rs | 264 +++++++++--------- artiq/firmware/runtime/session.rs | 28 +- artiq/firmware/satman/main.rs | 54 +++- 7 files changed, 332 insertions(+), 382 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtioaux.rs b/artiq/firmware/libboard_artiq/drtioaux.rs index d176e67da..a0465b230 100644 --- a/artiq/firmware/libboard_artiq/drtioaux.rs +++ b/artiq/firmware/libboard_artiq/drtioaux.rs @@ -10,9 +10,6 @@ pub use proto_artiq::drtioaux_proto::Packet; // this is parametric over T because there's no impl Fail for !. #[derive(Fail, Debug)] pub enum Error { - #[fail(display = "invalid node number")] - NoRoute, - #[fail(display = "gateware reported error")] GatewareError, #[fail(display = "packet CRC failed")] @@ -25,6 +22,9 @@ pub enum Error { #[fail(display = "unexpected reply")] UnexpectedReply, + #[fail(display = "routing error")] + RoutingError, + #[fail(display = "protocol error: {}", _0)] Protocol(#[cause] ProtocolError) } @@ -150,26 +150,3 @@ pub fn send_link(linkno: u8, packet: &Packet) -> Result<(), Error> { Ok(writer.position()) }) } - -// TODO: routing -fn get_linkno(nodeno: u8) -> Result> { - if nodeno == 0 || nodeno as usize > DRTIOAUX.len() { - return Err(Error::NoRoute) - } - Ok(nodeno - 1) -} - -pub fn recv(nodeno: u8) -> Result, Error> { - let linkno = get_linkno(nodeno)?; - recv_link(linkno) -} - -pub fn recv_timeout(nodeno: u8, timeout_ms: Option) -> Result> { - let linkno = get_linkno(nodeno)?; - recv_timeout_link(linkno, timeout_ms) -} - -pub fn send(nodeno: u8, packet: &Packet) -> Result<(), Error> { - let linkno = get_linkno(nodeno)?; - send_link(linkno, packet) -} diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 288913282..3d526734d 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -33,24 +33,24 @@ pub enum Packet { RoutingSetRank { rank: u8 }, RoutingAck, - MonitorRequest { channel: u16, probe: u8 }, + MonitorRequest { destination: u8, channel: u16, probe: u8 }, MonitorReply { value: u32 }, - InjectionRequest { channel: u16, overrd: u8, value: u8 }, - InjectionStatusRequest { channel: u16, overrd: u8 }, + InjectionRequest { destination: u8, channel: u16, overrd: u8, value: u8 }, + InjectionStatusRequest { destination: u8, channel: u16, overrd: u8 }, InjectionStatusReply { value: u8 }, - I2cStartRequest { busno: u8 }, - I2cRestartRequest { busno: u8 }, - I2cStopRequest { busno: u8 }, - I2cWriteRequest { busno: u8, data: u8 }, + I2cStartRequest { destination: u8, busno: u8 }, + I2cRestartRequest { destination: u8, busno: u8 }, + I2cStopRequest { destination: u8, busno: u8 }, + I2cWriteRequest { destination: u8, busno: u8, data: u8 }, I2cWriteReply { succeeded: bool, ack: bool }, - I2cReadRequest { busno: u8, ack: bool }, + I2cReadRequest { destination: u8, busno: u8, ack: bool }, I2cReadReply { succeeded: bool, data: u8 }, I2cBasicReply { succeeded: bool }, - SpiSetConfigRequest { busno: u8, flags: u8, length: u8, div: u8, cs: u8 }, - SpiWriteRequest { busno: u8, data: u32 }, - SpiReadRequest { busno: u8 }, + SpiSetConfigRequest { destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8 }, + SpiWriteRequest { destination: u8, busno: u8, data: u32 }, + SpiReadRequest { destination: u8, busno: u8 }, SpiReadReply { succeeded: bool, data: u32 }, SpiBasicReply { succeeded: bool }, } @@ -98,6 +98,7 @@ impl Packet { 0x32 => Packet::RoutingAck, 0x40 => Packet::MonitorRequest { + destination: reader.read_u8()?, channel: reader.read_u16()?, probe: reader.read_u8()? }, @@ -105,11 +106,13 @@ impl Packet { value: reader.read_u32()? }, 0x50 => Packet::InjectionRequest { + destination: reader.read_u8()?, channel: reader.read_u16()?, overrd: reader.read_u8()?, value: reader.read_u8()? }, 0x51 => Packet::InjectionStatusRequest { + destination: reader.read_u8()?, channel: reader.read_u16()?, overrd: reader.read_u8()? }, @@ -118,15 +121,19 @@ impl Packet { }, 0x80 => Packet::I2cStartRequest { + destination: reader.read_u8()?, busno: reader.read_u8()? }, 0x81 => Packet::I2cRestartRequest { + destination: reader.read_u8()?, busno: reader.read_u8()? }, 0x82 => Packet::I2cStopRequest { + destination: reader.read_u8()?, busno: reader.read_u8()? }, 0x83 => Packet::I2cWriteRequest { + destination: reader.read_u8()?, busno: reader.read_u8()?, data: reader.read_u8()? }, @@ -135,6 +142,7 @@ impl Packet { ack: reader.read_bool()? }, 0x85 => Packet::I2cReadRequest { + destination: reader.read_u8()?, busno: reader.read_u8()?, ack: reader.read_bool()? }, @@ -147,6 +155,7 @@ impl Packet { }, 0x90 => Packet::SpiSetConfigRequest { + destination: reader.read_u8()?, busno: reader.read_u8()?, flags: reader.read_u8()?, length: reader.read_u8()?, @@ -155,10 +164,12 @@ impl Packet { }, /* 0x91: was Packet::SpiSetXferRequest */ 0x92 => Packet::SpiWriteRequest { + destination: reader.read_u8()?, busno: reader.read_u8()?, data: reader.read_u32()? }, 0x93 => Packet::SpiReadRequest { + destination: reader.read_u8()?, busno: reader.read_u8()? }, 0x94 => Packet::SpiReadReply { @@ -223,8 +234,9 @@ impl Packet { Packet::RoutingAck => writer.write_u8(0x32)?, - Packet::MonitorRequest { channel, probe } => { + Packet::MonitorRequest { destination, channel, probe } => { writer.write_u8(0x40)?; + writer.write_u8(destination)?; writer.write_u16(channel)?; writer.write_u8(probe)?; }, @@ -232,14 +244,16 @@ impl Packet { writer.write_u8(0x41)?; writer.write_u32(value)?; }, - Packet::InjectionRequest { channel, overrd, value } => { + Packet::InjectionRequest { destination, channel, overrd, value } => { writer.write_u8(0x50)?; + writer.write_u8(destination)?; writer.write_u16(channel)?; writer.write_u8(overrd)?; writer.write_u8(value)?; }, - Packet::InjectionStatusRequest { channel, overrd } => { + Packet::InjectionStatusRequest { destination, channel, overrd } => { writer.write_u8(0x51)?; + writer.write_u8(destination)?; writer.write_u16(channel)?; writer.write_u8(overrd)?; }, @@ -248,20 +262,24 @@ impl Packet { writer.write_u8(value)?; }, - Packet::I2cStartRequest { busno } => { + Packet::I2cStartRequest { destination, busno } => { writer.write_u8(0x80)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; }, - Packet::I2cRestartRequest { busno } => { + Packet::I2cRestartRequest { destination, busno } => { writer.write_u8(0x81)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; }, - Packet::I2cStopRequest { busno } => { + Packet::I2cStopRequest { destination, busno } => { writer.write_u8(0x82)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; }, - Packet::I2cWriteRequest { busno, data } => { + Packet::I2cWriteRequest { destination, busno, data } => { writer.write_u8(0x83)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; writer.write_u8(data)?; }, @@ -270,8 +288,9 @@ impl Packet { writer.write_bool(succeeded)?; writer.write_bool(ack)?; }, - Packet::I2cReadRequest { busno, ack } => { + Packet::I2cReadRequest { destination, busno, ack } => { writer.write_u8(0x85)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; writer.write_bool(ack)?; }, @@ -285,21 +304,24 @@ impl Packet { writer.write_bool(succeeded)?; }, - Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => { + Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => { writer.write_u8(0x90)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; writer.write_u8(flags)?; writer.write_u8(length)?; writer.write_u8(div)?; writer.write_u8(cs)?; }, - Packet::SpiWriteRequest { busno, data } => { + Packet::SpiWriteRequest { destination, busno, data } => { writer.write_u8(0x92)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; writer.write_u32(data)?; }, - Packet::SpiReadRequest { busno } => { + Packet::SpiReadRequest { destination, busno } => { writer.write_u8(0x93)?; + writer.write_u8(destination)?; writer.write_u8(busno)?; }, Packet::SpiReadReply { succeeded, data } => { diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index c1bfbf7b0..00d20be3b 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -2,13 +2,16 @@ use kernel_proto as kern; use sched::{Io, Error as SchedError}; use session::{kern_acknowledge, kern_send, Error}; use rtio_mgt; +use board_artiq::drtio_routing; +use board_artiq::i2c as local_i2c; +use board_artiq::spi as local_spi; #[cfg(has_drtio)] -mod drtio_i2c { +mod remote_i2c { use drtioaux; - fn basic_reply(nodeno: u8) -> Result<(), ()> { - match drtioaux::recv_timeout(nodeno, None) { + fn basic_reply(linkno: u8) -> Result<(), ()> { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } @@ -23,39 +26,49 @@ mod drtio_i2c { } } - pub fn start(nodeno: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cStartRequest { busno: busno }; - if drtioaux::send(nodeno, &request).is_err() { + pub fn start(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let request = drtioaux::Packet::I2cStartRequest { + destination: destination, + busno: busno + }; + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn restart(nodeno: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cRestartRequest { busno: busno }; - if drtioaux::send(nodeno, &request).is_err() { + pub fn restart(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let request = drtioaux::Packet::I2cRestartRequest { + destination: destination, + busno: busno + }; + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn stop(nodeno: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cStopRequest { busno: busno }; - if drtioaux::send(nodeno, &request).is_err() { + pub fn stop(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let request = drtioaux::Packet::I2cStopRequest { + destination: destination, + busno: busno + }; + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn write(nodeno: u8, busno: u8, data: u8) -> Result { + pub fn write(linkno: u8, destination: u8, busno: u8, data: u8) -> Result { let request = drtioaux::Packet::I2cWriteRequest { + destination: destination, busno: busno, data: data }; - if drtioaux::send(nodeno, &request).is_err() { + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::I2cWriteReply { succeeded, ack }) => { if succeeded { Ok(ack) } else { Err(()) } } @@ -70,15 +83,16 @@ mod drtio_i2c { } } - pub fn read(nodeno: u8, busno: u8, ack: bool) -> Result { + pub fn read(linkno: u8, destination: u8, busno: u8, ack: bool) -> Result { let request = drtioaux::Packet::I2cReadRequest { + destination: destination, busno: busno, ack: ack }; - if drtioaux::send(nodeno, &request).is_err() { + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::I2cReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } @@ -94,90 +108,12 @@ mod drtio_i2c { } } -#[cfg(not(has_drtio))] -mod drtio_i2c { - pub fn start(_nodeno: u8, _busno: u8) -> Result<(), ()> { - Err(()) - } - - pub fn restart(_nodeno: u8, _busno: u8) -> Result<(), ()> { - Err(()) - } - - pub fn stop(_nodeno: u8, _busno: u8) -> Result<(), ()> { - Err(()) - } - - pub fn write(_nodeno: u8, _busno: u8, _data: u8) -> Result { - Err(()) - } - - pub fn read(_nodeno: u8, _busno: u8, _ack: bool) -> Result { - Err(()) - } -} - -mod i2c { - use board_artiq::i2c as local_i2c; - use super::drtio_i2c; - - pub fn start(busno: u32) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::start(node_busno) - } else { - drtio_i2c::start(nodeno, node_busno) - } - } - - pub fn restart(busno: u32) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::restart(node_busno) - } else { - drtio_i2c::restart(nodeno, node_busno) - } - } - - pub fn stop(busno: u32) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::stop(node_busno) - } else { - drtio_i2c::stop(nodeno, node_busno) - } - } - - pub fn write(busno: u32, data: u8) -> Result { - let nodeno = (busno >> 16 )as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::write(node_busno, data) - } else { - drtio_i2c::write(nodeno, node_busno, data) - } - } - - pub fn read(busno: u32, ack: bool) -> Result { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_i2c::read(node_busno, ack) - } else { - drtio_i2c::read(nodeno, node_busno, ack) - } - } -} - #[cfg(has_drtio)] -mod drtio_spi { +mod remote_spi { use drtioaux; - fn basic_reply(nodeno: u8) -> Result<(), ()> { - match drtioaux::recv_timeout(nodeno, None) { + fn basic_reply(linkno: u8) -> Result<(), ()> { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::SpiBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } @@ -192,37 +128,42 @@ mod drtio_spi { } } - pub fn set_config(nodeno: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { + pub fn set_config(linkno: u8, destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { let request = drtioaux::Packet::SpiSetConfigRequest { + destination: destination, busno: busno, flags: flags, length: length, div: div, cs: cs }; - if drtioaux::send(nodeno, &request).is_err() { + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn write(nodeno: u8, busno: u8, data: u32) -> Result<(), ()> { + pub fn write(linkno: u8, destination: u8, busno: u8, data: u32) -> Result<(), ()> { let request = drtioaux::Packet::SpiWriteRequest { + destination: destination, busno: busno, data: data }; - if drtioaux::send(nodeno, &request).is_err() { + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - basic_reply(nodeno) + basic_reply(linkno) } - pub fn read(nodeno: u8, busno: u8) -> Result { - let request = drtioaux::Packet::SpiReadRequest { busno: busno }; - if drtioaux::send(nodeno, &request).is_err() { + pub fn read(linkno: u8, destination: u8, busno: u8) -> Result { + let request = drtioaux::Packet::SpiReadRequest { + destination: destination, + busno: busno + }; + if drtioaux::send_link(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout(nodeno, None) { + match drtioaux::recv_timeout_link(linkno, None) { Ok(drtioaux::Packet::SpiReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } @@ -238,58 +179,32 @@ mod drtio_spi { } } + +#[cfg(has_drtio)] +macro_rules! dispatch { + ($mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ + let destination = ($busno >> 16) as u8; + let busno = $busno as u8; + let hop = $routing_table.0[destination as usize][0]; + if hop == 0 { + $mod_local::$func(busno, $($param, )*) + } else { + let linkno = hop - 1; + $mod_remote::$func(linkno, destination, busno, $($param, )*) + } + }} +} + #[cfg(not(has_drtio))] -mod drtio_spi { - pub fn set_config(_nodeno: u8, _busno: u8, _flags: u8, - _length: u8, _div: u8, _cs: u8) -> Result<(), ()> { - Err(()) - } - - pub fn write(_nodeno: u8, _busno: u8, _data: u32) -> Result<(), ()> { - Err(()) - } - - pub fn read(_nodeno: u8, _busno: u8) -> Result { - Err(()) - } +macro_rules! dispatch { + ($mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ + let busno = $busno as u8; + $mod_local::$func(busno, $($param, )*) + }} } -mod spi { - use board_artiq::spi as local_spi; - use super::drtio_spi; - - pub fn set_config(busno: u32, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_spi::set_config(node_busno, flags, length, div, cs) - } else { - drtio_spi::set_config(nodeno, node_busno, flags, length, div, cs) - } - } - - pub fn write(busno: u32, data: u32) -> Result<(), ()> { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_spi::write(node_busno, data) - } else { - drtio_spi::write(nodeno, node_busno, data) - } - } - - pub fn read(busno: u32) -> Result { - let nodeno = (busno >> 16) as u8; - let node_busno = busno as u8; - if nodeno == 0 { - local_spi::read(node_busno) - } else { - drtio_spi::read(nodeno, node_busno) - } - } -} - -pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result> { +pub fn process_kern_hwreq(io: &Io, _routing_table: &drtio_routing::RoutingTable, + request: &kern::Message) -> Result> { match request { &kern::RtioInitRequest => { info!("resetting RTIO"); @@ -303,40 +218,42 @@ pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> Result { - let succeeded = i2c::start(busno).is_ok(); + let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, start).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cRestartRequest { busno } => { - let succeeded = i2c::restart(busno).is_ok(); + let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, restart).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cStopRequest { busno } => { - let succeeded = i2c::stop(busno).is_ok(); + let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, stop).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cWriteRequest { busno, data } => { - match i2c::write(busno, data) { + match dispatch!(local_i2c, remote_i2c, _routing_table, busno, write, data) { Ok(ack) => kern_send(io, &kern::I2cWriteReply { succeeded: true, ack: ack }), Err(_) => kern_send(io, &kern::I2cWriteReply { succeeded: false, ack: false }) } } &kern::I2cReadRequest { busno, ack } => { - match i2c::read(busno, ack) { + match dispatch!(local_i2c, remote_i2c, _routing_table, busno, read, ack) { Ok(data) => kern_send(io, &kern::I2cReadReply { succeeded: true, data: data }), Err(_) => kern_send(io, &kern::I2cReadReply { succeeded: false, data: 0xff }) } } &kern::SpiSetConfigRequest { busno, flags, length, div, cs } => { - let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); + let succeeded = dispatch!(local_spi, remote_spi, _routing_table, busno, + set_config, flags, length, div, cs).is_ok(); kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) }, &kern::SpiWriteRequest { busno, data } => { - let succeeded = spi::write(busno, data).is_ok(); + let succeeded = dispatch!(local_spi, remote_spi, _routing_table, busno, + write, data).is_ok(); kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) } &kern::SpiReadRequest { busno } => { - match spi::read(busno) { + match dispatch!(local_spi, remote_spi, _routing_table, busno, read) { Ok(data) => kern_send(io, &kern::SpiReadReply { succeeded: true, data: data }), Err(_) => kern_send(io, &kern::SpiReadReply { succeeded: false, data: 0 }) } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 555f5adce..16f0fca05 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -282,22 +282,28 @@ fn startup_ethernet() { .ip_addrs([IpCidr::new(protocol_addr, 0)]) .finalize(); - #[cfg(has_drtio_routing)] + #[cfg(has_drtio)] let drtio_routing_table = urc::Urc::new(RefCell::new( drtio_routing::config_routing_table(csr::DRTIO.len()))); + #[cfg(not(has_drtio))] + let drtio_routing_table = urc::Urc::new(RefCell::new( + drtio_routing::RoutingTable::default_empty())); let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); - #[cfg(has_drtio_routing)] rtio_mgt::startup(&io, &drtio_routing_table); - #[cfg(not(has_drtio_routing))] - rtio_mgt::startup(&io, &drtio_routing::RoutingTable::default_empty()); io.spawn(4096, mgmt::thread); - io.spawn(16384, session::thread); + { + let drtio_routing_table = drtio_routing_table.clone(); + io.spawn(16384, move |io| { session::thread(io, &drtio_routing_table) }); + } #[cfg(any(has_rtio_moninj, has_drtio))] - io.spawn(4096, moninj::thread); + { + let drtio_routing_table = drtio_routing_table.clone(); + io.spawn(4096, move |io| { moninj::thread(io, &drtio_routing_table) }); + } #[cfg(has_rtio_analyzer)] io.spawn(4096, analyzer::thread); diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index 665927e39..a1a0765ac 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -1,151 +1,137 @@ use alloc::btree_map::BTreeMap; +use core::cell::RefCell; use io::Error as IoError; use moninj_proto::*; use sched::{Io, TcpListener, TcpStream, Error as SchedError}; -use board_misoc::{clock, csr}; -#[cfg(has_drtio)] -use drtioaux; +use urc::Urc; +use board_misoc::clock; +use board_artiq::drtio_routing; #[cfg(has_rtio_moninj)] -fn read_probe_local(channel: u16, probe: u8) -> u32 { - unsafe { - csr::rtio_moninj::mon_chan_sel_write(channel as _); - csr::rtio_moninj::mon_probe_sel_write(probe); - csr::rtio_moninj::mon_value_update_write(1); - csr::rtio_moninj::mon_value_read() as u32 +mod local_moninj { + use board_misoc::csr; + + pub fn read_probe(channel: u16, probe: u8) -> u32 { + unsafe { + csr::rtio_moninj::mon_chan_sel_write(channel as _); + csr::rtio_moninj::mon_probe_sel_write(probe); + csr::rtio_moninj::mon_value_update_write(1); + csr::rtio_moninj::mon_value_read() as u32 + } + } + + pub fn inject(channel: u16, overrd: u8, value: u8) { + unsafe { + csr::rtio_moninj::inj_chan_sel_write(channel as _); + csr::rtio_moninj::inj_override_sel_write(overrd); + csr::rtio_moninj::inj_value_write(value); + } + } + + pub fn read_injection_status(channel: u16, overrd: u8) -> u8 { + unsafe { + csr::rtio_moninj::inj_chan_sel_write(channel as _); + csr::rtio_moninj::inj_override_sel_write(overrd); + csr::rtio_moninj::inj_value_read() + } + } +} + +#[cfg(not(has_rtio_moninj))] +mod local_moninj { + pub fn read_probe(_channel: u16, _probe: u8) -> u32 { 0 } + + pub fn inject(_channel: u16, _overrd: u8, _value: u8) { } + + pub fn read_injection_status(_channel: u16, _overrd: u8) -> u8 { 0 } +} + +#[cfg(has_drtio)] +mod remote_moninj { + use drtioaux; + + pub fn read_probe(linkno: u8, destination: u8, channel: u16, probe: u8) -> u32 { + let request = drtioaux::Packet::MonitorRequest { + destination: destination, + channel: channel, + probe: probe + }; + match drtioaux::send_link(linkno, &request) { + Ok(_) => (), + Err(e) => { + error!("aux packet error ({})", e); + return 0; + } + } + match drtioaux::recv_timeout_link(linkno, None) { + Ok(drtioaux::Packet::MonitorReply { value }) => return value, + Ok(_) => error!("received unexpected aux packet"), + Err(e) => error!("aux packet error ({})", e) + } + 0 + } + + pub fn inject(linkno: u8, destination: u8, channel: u16, overrd: u8, value: u8) { + let request = drtioaux::Packet::InjectionRequest { + destination: destination, + channel: channel, + overrd: overrd, + value: value + }; + match drtioaux::send_link(linkno, &request) { + Ok(_) => (), + Err(e) => error!("aux packet error ({})", e) + } + } + + pub fn read_injection_status(linkno: u8, destination: u8, channel: u16, overrd: u8) -> u8 { + let request = drtioaux::Packet::InjectionStatusRequest { + destination: destination, + channel: channel, + overrd: overrd + }; + match drtioaux::send_link(linkno, &request) { + Ok(_) => (), + Err(e) => { + error!("aux packet error ({})", e); + return 0; + } + } + match drtioaux::recv_timeout_link(linkno, None) { + Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value, + Ok(_) => error!("received unexpected aux packet"), + Err(e) => error!("aux packet error ({})", e) + } + 0 } } #[cfg(has_drtio)] -fn read_probe_drtio(nodeno: u8, channel: u16, probe: u8) -> u32 { - let request = drtioaux::Packet::MonitorRequest { channel: channel, probe: probe }; - match drtioaux::send(nodeno, &request) { - Ok(_) => (), - Err(e) => { - error!("aux packet error ({})", e); - return 0; +macro_rules! dispatch { + ($routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ + let destination = ($channel >> 16) as u8; + let channel = $channel as u16; + let hop = $routing_table.0[destination as usize][0]; + if hop == 0 { + local_moninj::$func(channel, $($param, )*) + } else { + let linkno = hop - 1; + remote_moninj::$func(linkno, destination, channel, $($param, )*) } - } - match drtioaux::recv_timeout(nodeno, None) { - Ok(drtioaux::Packet::MonitorReply { value }) => return value, - Ok(_) => error!("received unexpected aux packet"), - Err(e) => error!("aux packet error ({})", e) - } - 0 + }} } -fn read_probe(channel: u32, probe: u8) -> u32 { - let nodeno = (channel >> 16) as u8; - let node_channel = channel as u16; - #[cfg(has_rtio_moninj)] - { - if nodeno == 0 { - return read_probe_local(node_channel, probe) - } - } - #[cfg(has_drtio)] - { - if nodeno != 0 { - return read_probe_drtio(nodeno, node_channel, probe) - } - } - error!("read_probe: unrecognized channel number {}", channel); - 0 +#[cfg(not(has_drtio))] +macro_rules! dispatch { + ($routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ + let channel = $channel as u8; + local_moninj::$func(channel, $($param, )*) + }} } -#[cfg(has_rtio_moninj)] -fn inject_local(channel: u16, overrd: u8, value: u8) { - unsafe { - csr::rtio_moninj::inj_chan_sel_write(channel as _); - csr::rtio_moninj::inj_override_sel_write(overrd); - csr::rtio_moninj::inj_value_write(value); - } -} - -#[cfg(has_drtio)] -fn inject_drtio(nodeno: u8, channel: u16, overrd: u8, value: u8) { - let request = drtioaux::Packet::InjectionRequest { - channel: channel, - overrd: overrd, - value: value - }; - match drtioaux::send(nodeno, &request) { - Ok(_) => (), - Err(e) => error!("aux packet error ({})", e) - } -} - -fn inject(channel: u32, overrd: u8, value: u8) { - let nodeno = (channel >> 16) as u8; - let node_channel = channel as u16; - #[cfg(has_rtio_moninj)] - { - if nodeno == 0 { - inject_local(node_channel, overrd, value); - return - } - } - #[cfg(has_drtio)] - { - if nodeno != 0 { - inject_drtio(nodeno, node_channel, overrd, value); - return - } - } - error!("inject: unrecognized channel number {}", channel); -} - -#[cfg(has_rtio_moninj)] -fn read_injection_status_local(channel: u16, overrd: u8) -> u8 { - unsafe { - csr::rtio_moninj::inj_chan_sel_write(channel as _); - csr::rtio_moninj::inj_override_sel_write(overrd); - csr::rtio_moninj::inj_value_read() - } -} - -#[cfg(has_drtio)] -fn read_injection_status_drtio(nodeno: u8, channel: u16, overrd: u8) -> u8 { - let request = drtioaux::Packet::InjectionStatusRequest { - channel: channel, - overrd: overrd - }; - match drtioaux::send(nodeno, &request) { - Ok(_) => (), - Err(e) => { - error!("aux packet error ({})", e); - return 0; - } - } - match drtioaux::recv_timeout(nodeno, None) { - Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value, - Ok(_) => error!("received unexpected aux packet"), - Err(e) => error!("aux packet error ({})", e) - } - 0 -} - -fn read_injection_status(channel: u32, probe: u8) -> u8 { - let nodeno = (channel >> 16) as u8; - let node_channel = channel as u16; - #[cfg(has_rtio_moninj)] - { - if nodeno == 0 { - return read_injection_status_local(node_channel, probe) - } - } - #[cfg(has_drtio)] - { - if nodeno != 0 { - return read_injection_status_drtio(nodeno, node_channel, probe) - } - } - error!("read_injection_status: unrecognized channel number {}", channel); - 0 -} - -fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error> { +fn connection_worker(io: &Io, _routing_table: &drtio_routing::RoutingTable, + mut stream: &mut TcpStream) -> Result<(), Error> { let mut probe_watch_list = BTreeMap::new(); let mut inject_watch_list = BTreeMap::new(); let mut next_check = 0; @@ -173,9 +159,9 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error inject(channel, overrd, value), + HostMessage::Inject { channel, overrd, value } => dispatch!(_routing_table, channel, inject, overrd, value), HostMessage::GetInjectionStatus { channel, overrd } => { - let value = read_injection_status(channel, overrd); + let value = dispatch!(_routing_table, channel, read_injection_status, overrd); let reply = DeviceMessage::InjectionStatus { channel: channel, overrd: overrd, @@ -192,7 +178,7 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error next_check { for (&(channel, probe), previous) in probe_watch_list.iter_mut() { - let current = read_probe(channel, probe); + let current = dispatch!(_routing_table, channel, read_probe, probe); if previous.is_none() || previous.unwrap() != current { let message = DeviceMessage::MonitorStatus { channel: channel, @@ -207,7 +193,7 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> Result<(), Error Result<(), Error>) { let listener = TcpListener::new(&io, 2047); listener.listen(1383).expect("moninj: cannot listen"); loop { + let routing_table = routing_table.clone(); let stream = listener.accept().expect("moninj: cannot accept").into_handle(); io.spawn(16384, move |io| { + let routing_table = routing_table.borrow(); let mut stream = TcpStream::from_handle(&io, stream); - match connection_worker(&io, &mut stream) { + match connection_worker(&io, &routing_table, &mut stream) { Ok(()) => {}, Err(err) => error!("moninj aborted: {}", err) } diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index d5a2722d2..4c081810e 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -12,6 +12,7 @@ use rtio_dma::Manager as DmaManager; use cache::Cache; use kern_hwreq; use watchdog::WatchdogSet; +use board_artiq::drtio_routing; use rpc_proto as rpc; use session_proto as host; @@ -323,7 +324,8 @@ fn process_host_message(io: &Io, Ok(()) } -fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, +fn process_kern_message(io: &Io, routing_table: &drtio_routing::RoutingTable, + mut stream: Option<&mut TcpStream>, session: &mut Session) -> Result> { kern_recv_notrace(io, |request| { match (request, session.kernel_state) { @@ -341,7 +343,7 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, kern_recv_dotrace(request); - if kern_hwreq::process_kern_hwreq(io, request)? { + if kern_hwreq::process_kern_hwreq(io, routing_table, request)? { return Ok(false) } @@ -490,7 +492,7 @@ fn process_kern_queued_rpc(stream: &mut TcpStream, }) } -fn host_kernel_worker(io: &Io, +fn host_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, stream: &mut TcpStream, congress: &mut Congress) -> Result<(), Error> { let mut session = Session::new(congress); @@ -507,7 +509,7 @@ fn host_kernel_worker(io: &Io, } if mailbox::receive() != 0 { - process_kern_message(io, Some(stream), &mut session)?; + process_kern_message(io, routing_table, Some(stream), &mut session)?; } if session.kernel_state == KernelState::Running { @@ -526,7 +528,7 @@ fn host_kernel_worker(io: &Io, } } -fn flash_kernel_worker(io: &Io, +fn flash_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, congress: &mut Congress, config_key: &str) -> Result<(), Error> { let mut session = Session::new(congress); @@ -549,7 +551,7 @@ fn flash_kernel_worker(io: &Io, } if mailbox::receive() != 0 { - if process_kern_message(io, None, &mut session)? { + if process_kern_message(io, routing_table, None, &mut session)? { return Ok(()) } } @@ -581,7 +583,7 @@ fn respawn(io: &Io, handle: &mut Option, f: F) *handle = Some(io.spawn(16384, f)) } -pub fn thread(io: Io) { +pub fn thread(io: Io, routing_table: &Urc>) { let listener = TcpListener::new(&io, 65535); listener.listen(1381).expect("session: cannot listen"); info!("accepting network sessions"); @@ -590,11 +592,13 @@ pub fn thread(io: Io) { let mut kernel_thread = None; { + let routing_table = routing_table.clone(); let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { + let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); info!("running startup kernel"); - match flash_kernel_worker(&io, &mut congress, "startup_kernel") { + match flash_kernel_worker(&io, &routing_table, &mut congress, "startup_kernel") { Ok(()) => info!("startup kernel finished"), Err(Error::KernelNotFound) => @@ -623,12 +627,14 @@ pub fn thread(io: Io) { } info!("new connection from {}", stream.remote_endpoint()); + let routing_table = routing_table.clone(); let congress = congress.clone(); let stream = stream.into_handle(); respawn(&io, &mut kernel_thread, move |io| { + let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); let mut stream = TcpStream::from_handle(&io, stream); - match host_kernel_worker(&io, &mut stream, &mut *congress) { + match host_kernel_worker(&io, &routing_table, &mut stream, &mut *congress) { Ok(()) => (), Err(Error::Protocol(host::Error::Io(IoError::UnexpectedEnd))) => info!("connection closed"), @@ -646,10 +652,12 @@ pub fn thread(io: Io) { if kernel_thread.as_ref().map_or(true, |h| h.terminated()) { info!("no connection, starting idle kernel"); + let routing_table = routing_table.clone(); let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { + let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); - match flash_kernel_worker(&io, &mut *congress, "idle_kernel") { + match flash_kernel_worker(&io, &routing_table, &mut *congress, "idle_kernel") { Ok(()) => info!("idle kernel finished, standing by"), Err(Error::Protocol(host::Error::Io( diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 8e3b22e7d..1bb4c6155 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -46,6 +46,27 @@ fn drtiosat_tsc_loaded() -> bool { } } + +#[cfg(has_drtio_routing)] +macro_rules! forward { + ($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr) => {{ + let hop = $routing_table.0[$destination as usize][$rank as usize]; + if hop != 0 { + let repno = (hop - 1) as usize; + if repno < $repeaters.len() { + return $repeaters[repno].aux_forward($packet); + } else { + return Err(drtioaux::Error::RoutingError); + } + } + }} +} + +#[cfg(not(has_drtio_routing))] +macro_rules! forward { + ($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr) => {} +} + fn process_aux_packet(_repeaters: &mut [repeater::Repeater], _routing_table: &mut drtio_routing::RoutingTable, _rank: &mut u8, packet: drtioaux::Packet) -> Result<(), drtioaux::Error> { @@ -174,7 +195,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) } - drtioaux::Packet::MonitorRequest { channel, probe } => { + drtioaux::Packet::MonitorRequest { destination, channel, probe } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let value; #[cfg(has_rtio_moninj)] unsafe { @@ -190,7 +212,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], let reply = drtioaux::Packet::MonitorReply { value: value as u32 }; drtioaux::send_link(0, &reply) }, - drtioaux::Packet::InjectionRequest { channel, overrd, value } => { + drtioaux::Packet::InjectionRequest { destination, channel, overrd, value } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); #[cfg(has_rtio_moninj)] unsafe { csr::rtio_moninj::inj_chan_sel_write(channel as _); @@ -199,7 +222,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } Ok(()) }, - drtioaux::Packet::InjectionStatusRequest { channel, overrd } => { + drtioaux::Packet::InjectionStatusRequest { destination, channel, overrd } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let value; #[cfg(has_rtio_moninj)] unsafe { @@ -214,19 +238,23 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::send_link(0, &drtioaux::Packet::InjectionStatusReply { value: value }) }, - drtioaux::Packet::I2cStartRequest { busno } => { + drtioaux::Packet::I2cStartRequest { destination, busno } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::start(busno).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cRestartRequest { busno } => { + drtioaux::Packet::I2cRestartRequest { destination, busno } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::restart(busno).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cStopRequest { busno } => { + drtioaux::Packet::I2cStopRequest { destination, busno } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::stop(busno).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cWriteRequest { busno, data } => { + drtioaux::Packet::I2cWriteRequest { destination, busno, data } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); match i2c::write(busno, data) { Ok(ack) => drtioaux::send_link(0, &drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }), @@ -234,7 +262,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], &drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false }) } } - drtioaux::Packet::I2cReadRequest { busno, ack } => { + drtioaux::Packet::I2cReadRequest { destination, busno, ack } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); match i2c::read(busno, ack) { Ok(data) => drtioaux::send_link(0, &drtioaux::Packet::I2cReadReply { succeeded: true, data: data }), @@ -243,17 +272,20 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } } - drtioaux::Packet::SpiSetConfigRequest { busno, flags, length, div, cs } => { + drtioaux::Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) }, - drtioaux::Packet::SpiWriteRequest { busno, data } => { + drtioaux::Packet::SpiWriteRequest { destination, busno, data } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = spi::write(busno, data).is_ok(); drtioaux::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) } - drtioaux::Packet::SpiReadRequest { busno } => { + drtioaux::Packet::SpiReadRequest { destination, busno } => { + forward!(_routing_table, destination, *_rank, _repeaters, &packet); match spi::read(busno) { Ok(data) => drtioaux::send_link(0, &drtioaux::Packet::SpiReadReply { succeeded: true, data: data }), From d19550daf8fa3af5ff8eca25735fdaa03ed967f5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 14 Sep 2018 20:32:09 +0800 Subject: [PATCH 1234/2457] firmware: simplify drtioaux function names --- artiq/firmware/libboard_artiq/drtioaux.rs | 8 ++-- artiq/firmware/runtime/kern_hwreq.rs | 26 +++++------ artiq/firmware/runtime/moninj.rs | 10 ++-- artiq/firmware/runtime/rtio_mgt.rs | 20 ++++---- artiq/firmware/satman/main.rs | 56 +++++++++++------------ artiq/firmware/satman/repeater.rs | 18 ++++---- 6 files changed, 69 insertions(+), 69 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtioaux.rs b/artiq/firmware/libboard_artiq/drtioaux.rs index a0465b230..f72072702 100644 --- a/artiq/firmware/libboard_artiq/drtioaux.rs +++ b/artiq/firmware/libboard_artiq/drtioaux.rs @@ -80,7 +80,7 @@ fn receive(linkno: u8, f: F) -> Result, Error> } } -pub fn recv_link(linkno: u8) -> Result, Error> { +pub fn recv(linkno: u8) -> Result, Error> { if has_rx_error(linkno) { return Err(Error::GatewareError) } @@ -104,11 +104,11 @@ pub fn recv_link(linkno: u8) -> Result, Error> { }) } -pub fn recv_timeout_link(linkno: u8, timeout_ms: Option) -> Result> { +pub fn recv_timeout(linkno: u8, timeout_ms: Option) -> Result> { let timeout_ms = timeout_ms.unwrap_or(10); let limit = clock::get_ms() + timeout_ms; while clock::get_ms() < limit { - match recv_link(linkno)? { + match recv(linkno)? { None => (), Some(packet) => return Ok(packet), } @@ -131,7 +131,7 @@ fn transmit(linkno: u8, f: F) -> Result<(), Error> } } -pub fn send_link(linkno: u8, packet: &Packet) -> Result<(), Error> { +pub fn send(linkno: u8, packet: &Packet) -> Result<(), Error> { transmit(linkno, |buffer| { let mut writer = Cursor::new(buffer); diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index 00d20be3b..7a9ce6061 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -11,7 +11,7 @@ mod remote_i2c { use drtioaux; fn basic_reply(linkno: u8) -> Result<(), ()> { - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } @@ -31,7 +31,7 @@ mod remote_i2c { destination: destination, busno: busno }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } basic_reply(linkno) @@ -42,7 +42,7 @@ mod remote_i2c { destination: destination, busno: busno }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } basic_reply(linkno) @@ -53,7 +53,7 @@ mod remote_i2c { destination: destination, busno: busno }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } basic_reply(linkno) @@ -65,10 +65,10 @@ mod remote_i2c { busno: busno, data: data }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::I2cWriteReply { succeeded, ack }) => { if succeeded { Ok(ack) } else { Err(()) } } @@ -89,10 +89,10 @@ mod remote_i2c { busno: busno, ack: ack }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::I2cReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } @@ -113,7 +113,7 @@ mod remote_spi { use drtioaux; fn basic_reply(linkno: u8) -> Result<(), ()> { - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::SpiBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } @@ -137,7 +137,7 @@ mod remote_spi { div: div, cs: cs }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } basic_reply(linkno) @@ -149,7 +149,7 @@ mod remote_spi { busno: busno, data: data }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } basic_reply(linkno) @@ -160,10 +160,10 @@ mod remote_spi { destination: destination, busno: busno }; - if drtioaux::send_link(linkno, &request).is_err() { + if drtioaux::send(linkno, &request).is_err() { return Err(()) } - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::SpiReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index a1a0765ac..d2713bd4c 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -57,14 +57,14 @@ mod remote_moninj { channel: channel, probe: probe }; - match drtioaux::send_link(linkno, &request) { + match drtioaux::send(linkno, &request) { Ok(_) => (), Err(e) => { error!("aux packet error ({})", e); return 0; } } - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::MonitorReply { value }) => return value, Ok(_) => error!("received unexpected aux packet"), Err(e) => error!("aux packet error ({})", e) @@ -79,7 +79,7 @@ mod remote_moninj { overrd: overrd, value: value }; - match drtioaux::send_link(linkno, &request) { + match drtioaux::send(linkno, &request) { Ok(_) => (), Err(e) => error!("aux packet error ({})", e) } @@ -91,14 +91,14 @@ mod remote_moninj { channel: channel, overrd: overrd }; - match drtioaux::send_link(linkno, &request) { + match drtioaux::send(linkno, &request) { Ok(_) => (), Err(e) => { error!("aux packet error ({})", e); return 0; } } - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value, Ok(_) => error!("received unexpected aux packet"), Err(e) => error!("aux packet error ({})", e) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 2153e9986..c3b67567d 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -93,9 +93,9 @@ pub mod drtio { if count > 200 { return 0; } - drtioaux::send_link(linkno, &drtioaux::Packet::EchoRequest).unwrap(); + drtioaux::send(linkno, &drtioaux::Packet::EchoRequest).unwrap(); io.sleep(100).unwrap(); - let pr = drtioaux::recv_link(linkno); + let pr = drtioaux::recv(linkno); match pr { Ok(Some(drtioaux::Packet::EchoReply)) => return count, _ => {} @@ -112,7 +112,7 @@ pub mod drtio { if clock::get_ms() > max_time { return Err("timeout"); } - match drtioaux::recv_link(linkno) { + match drtioaux::recv(linkno) { Ok(Some(packet)) => return Ok(packet), Ok(None) => (), Err(_) => return Err("aux packet error") @@ -139,7 +139,7 @@ pub mod drtio { fn load_routing_table(io: &Io, linkno: u8, routing_table: &drtio_routing::RoutingTable) -> Result<(), &'static str> { for i in 0..drtio_routing::DEST_COUNT { - drtioaux::send_link(linkno, &drtioaux::Packet::RoutingSetPath { + drtioaux::send(linkno, &drtioaux::Packet::RoutingSetPath { destination: i as u8, hops: routing_table.0[i] }).unwrap(); @@ -152,7 +152,7 @@ pub mod drtio { } fn set_rank(io: &Io, linkno: u8, rank: u8) -> Result<(), &'static str> { - drtioaux::send_link(linkno, &drtioaux::Packet::RoutingSetRank { + drtioaux::send(linkno, &drtioaux::Packet::RoutingSetRank { rank: rank }).unwrap(); let reply = recv_aux_timeout(io, linkno, 200)?; @@ -176,7 +176,7 @@ pub mod drtio { } fn process_unsolicited_aux(linkno: u8) { - match drtioaux::recv_link(linkno) { + match drtioaux::recv(linkno) { Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet), Ok(None) => (), Err(_) => warn!("[LINK#{}] aux packet error", linkno) @@ -219,7 +219,7 @@ pub mod drtio { let linkno = hop - 1; if up_destinations[destination] { if link_up(linkno) { - drtioaux::send_link(linkno, &drtioaux::Packet::DestinationStatusRequest { + drtioaux::send(linkno, &drtioaux::Packet::DestinationStatusRequest { destination: destination as u8 }).unwrap(); match recv_aux_timeout(io, linkno, 200) { @@ -243,7 +243,7 @@ pub mod drtio { } } else { if link_up(linkno) { - drtioaux::send_link(linkno, &drtioaux::Packet::DestinationStatusRequest { + drtioaux::send(linkno, &drtioaux::Packet::DestinationStatusRequest { destination: destination as u8 }).unwrap(); match recv_aux_timeout(io, linkno, 200) { @@ -309,9 +309,9 @@ pub mod drtio { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; if link_up(linkno) { - drtioaux::send_link(linkno, + drtioaux::send(linkno, &drtioaux::Packet::ResetRequest { phy: false }).unwrap(); - match drtioaux::recv_timeout_link(linkno, None) { + match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::ResetAck) => (), Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno), Err(e) => error!("[LINK#{}] reset failed, aux packet error ({})", linkno, e) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 1bb4c6155..7c47011ee 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -74,7 +74,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], // and u16 otherwise; hence the `as _` conversion. match packet { drtioaux::Packet::EchoRequest => - drtioaux::send_link(0, &drtioaux::Packet::EchoReply), + drtioaux::send(0, &drtioaux::Packet::EchoReply), drtioaux::Packet::ResetRequest { phy } => { info!("resetting RTIO"); if phy { @@ -89,7 +89,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], error!("failed to issue RTIO reset ({})", e); } } - drtioaux::send_link(0, &drtioaux::Packet::ResetAck) + drtioaux::send(0, &drtioaux::Packet::ResetAck) }, drtioaux::Packet::DestinationStatusRequest { destination } => { @@ -109,7 +109,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], channel = csr::drtiosat::sequence_error_channel_read(); csr::drtiosat::rtio_error_write(1); } - drtioaux::send_link(0, + drtioaux::send(0, &drtioaux::Packet::DestinationSequenceErrorReply { channel })?; } else if errors & 2 != 0 { let channel; @@ -117,7 +117,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], channel = csr::drtiosat::collision_channel_read(); csr::drtiosat::rtio_error_write(2); } - drtioaux::send_link(0, + drtioaux::send(0, &drtioaux::Packet::DestinationCollisionReply { channel })?; } else if errors & 4 != 0 { let channel; @@ -125,11 +125,11 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], channel = csr::drtiosat::busy_channel_read(); csr::drtiosat::rtio_error_write(4); } - drtioaux::send_link(0, + drtioaux::send(0, &drtioaux::Packet::DestinationBusyReply { channel })?; } else { - drtioaux::send_link(0, &drtioaux::Packet::DestinationOkReply)?; + drtioaux::send(0, &drtioaux::Packet::DestinationOkReply)?; } } @@ -143,14 +143,14 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], destination: destination }) { Ok(()) => (), - Err(drtioaux::Error::LinkDown) => drtioaux::send_link(0, &drtioaux::Packet::DestinationDownReply)?, + Err(drtioaux::Error::LinkDown) => drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?, Err(e) => { - drtioaux::send_link(0, &drtioaux::Packet::DestinationDownReply)?; + drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?; error!("aux error when handling destination status request: {}", e); }, } } else { - drtioaux::send_link(0, &drtioaux::Packet::DestinationDownReply)?; + drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?; } } } @@ -166,7 +166,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], error!("failed to set path ({})", e); } } - drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + drtioaux::send(0, &drtioaux::Packet::RoutingAck) } #[cfg(has_drtio_routing)] drtioaux::Packet::RoutingSetRank { rank } => { @@ -183,16 +183,16 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], info!("rank: {}", rank); info!("routing table: {}", _routing_table); - drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + drtioaux::send(0, &drtioaux::Packet::RoutingAck) } #[cfg(not(has_drtio_routing))] drtioaux::Packet::RoutingSetPath { destination, hops } => { - drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + drtioaux::send(0, &drtioaux::Packet::RoutingAck) } #[cfg(not(has_drtio_routing))] drtioaux::Packet::RoutingSetRank { rank } => { - drtioaux::send_link(0, &drtioaux::Packet::RoutingAck) + drtioaux::send(0, &drtioaux::Packet::RoutingAck) } drtioaux::Packet::MonitorRequest { destination, channel, probe } => { @@ -210,7 +210,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], value = 0; } let reply = drtioaux::Packet::MonitorReply { value: value as u32 }; - drtioaux::send_link(0, &reply) + drtioaux::send(0, &reply) }, drtioaux::Packet::InjectionRequest { destination, channel, overrd, value } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); @@ -235,39 +235,39 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], { value = 0; } - drtioaux::send_link(0, &drtioaux::Packet::InjectionStatusReply { value: value }) + drtioaux::send(0, &drtioaux::Packet::InjectionStatusReply { value: value }) }, drtioaux::Packet::I2cStartRequest { destination, busno } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::start(busno).is_ok(); - drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) + drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } drtioaux::Packet::I2cRestartRequest { destination, busno } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::restart(busno).is_ok(); - drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) + drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } drtioaux::Packet::I2cStopRequest { destination, busno } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = i2c::stop(busno).is_ok(); - drtioaux::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) + drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } drtioaux::Packet::I2cWriteRequest { destination, busno, data } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); match i2c::write(busno, data) { - Ok(ack) => drtioaux::send_link(0, + Ok(ack) => drtioaux::send(0, &drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }), - Err(_) => drtioaux::send_link(0, + Err(_) => drtioaux::send(0, &drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false }) } } drtioaux::Packet::I2cReadRequest { destination, busno, ack } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); match i2c::read(busno, ack) { - Ok(data) => drtioaux::send_link(0, + Ok(data) => drtioaux::send(0, &drtioaux::Packet::I2cReadReply { succeeded: true, data: data }), - Err(_) => drtioaux::send_link(0, + Err(_) => drtioaux::send(0, &drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff }) } } @@ -275,21 +275,21 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); - drtioaux::send_link(0, + drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) }, drtioaux::Packet::SpiWriteRequest { destination, busno, data } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); let succeeded = spi::write(busno, data).is_ok(); - drtioaux::send_link(0, + drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) } drtioaux::Packet::SpiReadRequest { destination, busno } => { forward!(_routing_table, destination, *_rank, _repeaters, &packet); match spi::read(busno) { - Ok(data) => drtioaux::send_link(0, + Ok(data) => drtioaux::send(0, &drtioaux::Packet::SpiReadReply { succeeded: true, data: data }), - Err(_) => drtioaux::send_link(0, + Err(_) => drtioaux::send(0, &drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 }) } } @@ -304,7 +304,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], fn process_aux_packets(repeaters: &mut [repeater::Repeater], routing_table: &mut drtio_routing::RoutingTable, rank: &mut u8) { let result = - drtioaux::recv_link(0).and_then(|packet| { + drtioaux::recv(0).and_then(|packet| { if let Some(packet) = packet { process_aux_packet(repeaters, routing_table, rank, packet) } else { @@ -463,7 +463,7 @@ pub extern fn main() -> i32 { error!("failed to sync TSC ({})", e); } } - if let Err(e) = drtioaux::send_link(0, &drtioaux::Packet::TSCAck) { + if let Err(e) = drtioaux::send(0, &drtioaux::Packet::TSCAck) { error!("aux packet error: {}", e); } } diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index c97ece3e5..dae775364 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -51,7 +51,7 @@ impl Repeater { } RepeaterState::SendPing { ping_count } => { if rep_link_rx_up(self.repno) { - drtioaux::send_link(self.auxno, &drtioaux::Packet::EchoRequest).unwrap(); + drtioaux::send(self.auxno, &drtioaux::Packet::EchoRequest).unwrap(); self.state = RepeaterState::WaitPingReply { ping_count: ping_count + 1, timeout: clock::get_ms() + 100 @@ -63,7 +63,7 @@ impl Repeater { } RepeaterState::WaitPingReply { ping_count, timeout } => { if rep_link_rx_up(self.repno) { - if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv_link(self.auxno) { + if let Ok(Some(drtioaux::Packet::EchoReply)) = drtioaux::recv(self.auxno) { info!("[REP#{}] remote replied after {} packets", self.repno, ping_count); self.state = RepeaterState::Up; if let Err(e) = self.sync_tsc() { @@ -113,7 +113,7 @@ impl Repeater { } fn process_unsolicited_aux(&self) { - match drtioaux::recv_link(self.auxno) { + match drtioaux::recv(self.auxno) { Ok(Some(packet)) => warn!("[REP#{}] unsolicited aux packet: {:?}", self.repno, packet), Ok(None) => (), Err(_) => warn!("[REP#{}] aux packet error", self.repno) @@ -162,7 +162,7 @@ impl Repeater { if clock::get_ms() > max_time { return Err(drtioaux::Error::TimedOut); } - match drtioaux::recv_link(self.auxno) { + match drtioaux::recv(self.auxno) { Ok(Some(packet)) => return Ok(packet), Ok(None) => (), Err(e) => return Err(e) @@ -174,9 +174,9 @@ impl Repeater { if self.state != RepeaterState::Up { return Err(drtioaux::Error::LinkDown); } - drtioaux::send_link(self.auxno, request).unwrap(); + drtioaux::send(self.auxno, request).unwrap(); let reply = self.recv_aux_timeout(200)?; - drtioaux::send_link(0, &reply).unwrap(); + drtioaux::send(0, &reply).unwrap(); Ok(()) } @@ -206,7 +206,7 @@ impl Repeater { return Ok(()); } - drtioaux::send_link(self.auxno, &drtioaux::Packet::RoutingSetPath { + drtioaux::send(self.auxno, &drtioaux::Packet::RoutingSetPath { destination: destination, hops: *hops }).unwrap(); @@ -228,7 +228,7 @@ impl Repeater { if self.state != RepeaterState::Up { return Ok(()); } - drtioaux::send_link(self.auxno, &drtioaux::Packet::RoutingSetRank { + drtioaux::send(self.auxno, &drtioaux::Packet::RoutingSetRank { rank: rank }).unwrap(); let reply = self.recv_aux_timeout(200)?; @@ -242,7 +242,7 @@ impl Repeater { if self.state != RepeaterState::Up { return Ok(()); } - drtioaux::send_link(self.auxno, &drtioaux::Packet::ResetRequest { + drtioaux::send(self.auxno, &drtioaux::Packet::ResetRequest { phy: phy }).unwrap(); let reply = self.recv_aux_timeout(200)?; From 65da1fee4a22707865db333386c7069e4aadd99f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 14 Sep 2018 20:38:41 +0800 Subject: [PATCH 1235/2457] firmware: fix build without DRTIO --- artiq/firmware/libboard_artiq/drtio_routing.rs | 4 +++- artiq/firmware/runtime/main.rs | 1 - artiq/firmware/runtime/moninj.rs | 2 +- artiq/firmware/runtime/rtio_mgt.rs | 4 +++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index c78b5cddd..fe51c3cc4 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -1,4 +1,6 @@ -use board_misoc::{csr, config}; +use board_misoc::config; +#[cfg(has_drtio_routing)] +use board_misoc::csr; use core::fmt; pub const DEST_COUNT: usize = 256; diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 16f0fca05..6ecf79dd0 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -34,7 +34,6 @@ use board_misoc::{csr, irq, ident, clock, boot, config}; use board_misoc::ethmac; #[cfg(has_drtio)] use board_artiq::drtioaux; -#[cfg(has_drtio_routing)] use board_artiq::drtio_routing; use board_artiq::{mailbox, rpc_queue}; use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_proto}; diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index d2713bd4c..b049806df 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -125,7 +125,7 @@ macro_rules! dispatch { #[cfg(not(has_drtio))] macro_rules! dispatch { ($routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ - let channel = $channel as u8; + let channel = $channel as u16; local_moninj::$func(channel, $($param, )*) }} } diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index c3b67567d..1635586a0 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -1,6 +1,8 @@ use core::cell::RefCell; use urc::Urc; -use board_misoc::{csr, clock}; +use board_misoc::csr; +#[cfg(has_drtio))] +use board_misoc::clock; #[cfg(has_rtio_clock_switch)] use board_misoc::config; use board_artiq::drtio_routing; From f8c6fa5ad6179b6f7248d35506ffa942d1fd93ca Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 10:43:36 +0800 Subject: [PATCH 1236/2457] typo --- artiq/firmware/runtime/rtio_mgt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 1635586a0..237b71667 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -1,7 +1,7 @@ use core::cell::RefCell; use urc::Urc; use board_misoc::csr; -#[cfg(has_drtio))] +#[cfg(has_drtio)] use board_misoc::clock; #[cfg(has_rtio_clock_switch)] use board_misoc::config; From 20ed393c1e7677f4f0d0f6952f5c019cfd647a25 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 10:43:50 +0800 Subject: [PATCH 1237/2457] style --- artiq/frontend/aqctl_corelog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/aqctl_corelog.py b/artiq/frontend/aqctl_corelog.py index 7cee0b974..9df2c3a8d 100755 --- a/artiq/frontend/aqctl_corelog.py +++ b/artiq/frontend/aqctl_corelog.py @@ -16,7 +16,7 @@ def get_argparser(): parser = argparse.ArgumentParser( description="ARTIQ controller for core device logs") simple_network_args(parser, 1068) - parser.add_argument("core_addr", + parser.add_argument("core_addr", metavar="CORE_ADDR", help="hostname or IP address of the core device") return parser From 2f010e0109d6d0ddec64fd4e9abfe2aa0cc54109 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 10:44:41 +0800 Subject: [PATCH 1238/2457] runtime: improve moninj aux error logging --- artiq/firmware/runtime/moninj.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index b049806df..5ffaa96a0 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -66,7 +66,7 @@ mod remote_moninj { } match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::MonitorReply { value }) => return value, - Ok(_) => error!("received unexpected aux packet"), + Ok(packet) => error!("received unexpected aux packet: {:?}", packet), Err(e) => error!("aux packet error ({})", e) } 0 @@ -100,7 +100,7 @@ mod remote_moninj { } match drtioaux::recv_timeout(linkno, None) { Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value, - Ok(_) => error!("received unexpected aux packet"), + Ok(packet) => error!("received unexpected aux packet: {:?}", packet), Err(e) => error!("aux packet error ({})", e) } 0 From 0017cb756ef4f384a6eac1fc646fe87923ef0b2b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 10:44:59 +0800 Subject: [PATCH 1239/2457] frontend: add artiq_rtiomon --- artiq/frontend/artiq_rtiomon.py | 39 +++++++++++++++++++++++++++++++++ setup.py | 1 + 2 files changed, 40 insertions(+) create mode 100755 artiq/frontend/artiq_rtiomon.py diff --git a/artiq/frontend/artiq_rtiomon.py b/artiq/frontend/artiq_rtiomon.py new file mode 100755 index 000000000..eed6a9074 --- /dev/null +++ b/artiq/frontend/artiq_rtiomon.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +import argparse +import asyncio + +from artiq.coredevice.comm_moninj import * + + +def get_argparser(): + parser = argparse.ArgumentParser( + description="ARTIQ RTIO monitor") + parser.add_argument("core_addr", metavar="CORE_ADDR", + help="hostname or IP address of the core device") + parser.add_argument("channel", metavar="CHANNEL", type=lambda x: int(x, 0), nargs="+", + help="channel(s) to monitor") + return parser + + +def main(): + args = get_argparser().parse_args() + + loop = asyncio.get_event_loop() + try: + comm = CommMonInj( + lambda channel, probe, value: print("0x{:06x}: {}".format(channel, value)), + lambda channel, override, value: None) + loop.run_until_complete(comm.connect(args.core_addr)) + try: + for channel in args.channel: + comm.monitor_probe(True, channel, 0) + loop.run_forever() + finally: + loop.run_until_complete(comm.close()) + finally: + loop.close() + + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index b4c25b027..a10ec254b 100755 --- a/setup.py +++ b/setup.py @@ -29,6 +29,7 @@ console_scripts = [ "artiq_influxdb = artiq.frontend.artiq_influxdb:main", "artiq_master = artiq.frontend.artiq_master:main", "artiq_mkfs = artiq.frontend.artiq_mkfs:main", + "artiq_rtiomon = artiq.frontend.artiq_rtiomon:main", "artiq_session = artiq.frontend.artiq_session:main", "artiq_route = artiq.frontend.artiq_route:main", "artiq_rpctool = artiq.frontend.artiq_rpctool:main", From f097b4104cf93bea62ce20d8cc66a67a6c9a749c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 11:33:18 +0800 Subject: [PATCH 1240/2457] satman: not(has_drtio_routing) fixes --- artiq/firmware/satman/main.rs | 54 +++++++++++++++---------------- artiq/firmware/satman/repeater.rs | 17 ++++++++-- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 7c47011ee..8fb9c287e 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -92,9 +92,9 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::send(0, &drtioaux::Packet::ResetAck) }, - drtioaux::Packet::DestinationStatusRequest { destination } => { + drtioaux::Packet::DestinationStatusRequest { destination: _destination } => { #[cfg(has_drtio_routing)] - let hop = _routing_table.0[destination as usize][*_rank as usize]; + let hop = _routing_table.0[_destination as usize][*_rank as usize]; #[cfg(not(has_drtio_routing))] let hop = 0; @@ -140,7 +140,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], if hop <= csr::DRTIOREP.len() { let repno = hop - 1; match _repeaters[repno].aux_forward(&drtioaux::Packet::DestinationStatusRequest { - destination: destination + destination: _destination }) { Ok(()) => (), Err(drtioaux::Error::LinkDown) => drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?, @@ -187,16 +187,16 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } #[cfg(not(has_drtio_routing))] - drtioaux::Packet::RoutingSetPath { destination, hops } => { + drtioaux::Packet::RoutingSetPath { destination: _, hops: _ } => { drtioaux::send(0, &drtioaux::Packet::RoutingAck) } #[cfg(not(has_drtio_routing))] - drtioaux::Packet::RoutingSetRank { rank } => { + drtioaux::Packet::RoutingSetRank { rank: _ } => { drtioaux::send(0, &drtioaux::Packet::RoutingAck) } - drtioaux::Packet::MonitorRequest { destination, channel, probe } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::MonitorRequest { destination: _destination, channel, probe } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let value; #[cfg(has_rtio_moninj)] unsafe { @@ -212,8 +212,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], let reply = drtioaux::Packet::MonitorReply { value: value as u32 }; drtioaux::send(0, &reply) }, - drtioaux::Packet::InjectionRequest { destination, channel, overrd, value } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::InjectionRequest { destination: _destination, channel, overrd, value } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); #[cfg(has_rtio_moninj)] unsafe { csr::rtio_moninj::inj_chan_sel_write(channel as _); @@ -222,8 +222,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } Ok(()) }, - drtioaux::Packet::InjectionStatusRequest { destination, channel, overrd } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::InjectionStatusRequest { destination: _destination, channel, overrd } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let value; #[cfg(has_rtio_moninj)] unsafe { @@ -238,23 +238,23 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtioaux::send(0, &drtioaux::Packet::InjectionStatusReply { value: value }) }, - drtioaux::Packet::I2cStartRequest { destination, busno } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::I2cStartRequest { destination: _destination, busno } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let succeeded = i2c::start(busno).is_ok(); drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cRestartRequest { destination, busno } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::I2cRestartRequest { destination: _destination, busno } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let succeeded = i2c::restart(busno).is_ok(); drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cStopRequest { destination, busno } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::I2cStopRequest { destination: _destination, busno } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let succeeded = i2c::stop(busno).is_ok(); drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) } - drtioaux::Packet::I2cWriteRequest { destination, busno, data } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::I2cWriteRequest { destination: _destination, busno, data } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); match i2c::write(busno, data) { Ok(ack) => drtioaux::send(0, &drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }), @@ -262,8 +262,8 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], &drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false }) } } - drtioaux::Packet::I2cReadRequest { destination, busno, ack } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::I2cReadRequest { destination: _destination, busno, ack } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); match i2c::read(busno, ack) { Ok(data) => drtioaux::send(0, &drtioaux::Packet::I2cReadReply { succeeded: true, data: data }), @@ -272,20 +272,20 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } } - drtioaux::Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::SpiSetConfigRequest { destination: _destination, busno, flags, length, div, cs } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) }, - drtioaux::Packet::SpiWriteRequest { destination, busno, data } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::SpiWriteRequest { destination: _destination, busno, data } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); let succeeded = spi::write(busno, data).is_ok(); drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }) } - drtioaux::Packet::SpiReadRequest { destination, busno } => { - forward!(_routing_table, destination, *_rank, _repeaters, &packet); + drtioaux::Packet::SpiReadRequest { destination: _destination, busno } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); match spi::read(busno) { Ok(data) => drtioaux::send(0, &drtioaux::Packet::SpiReadReply { succeeded: true, data: data }), diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index dae775364..d5b04a94f 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -1,5 +1,6 @@ -use board_misoc::{csr, clock}; use board_artiq::{drtioaux, drtio_routing}; +#[cfg(has_drtio_routing)] +use board_misoc::{csr, clock}; #[cfg(has_drtio_routing)] fn rep_link_rx_up(repno: u8) -> bool { @@ -9,6 +10,7 @@ fn rep_link_rx_up(repno: u8) -> bool { } } +#[cfg(has_drtio_routing)] #[derive(Clone, Copy, PartialEq)] enum RepeaterState { Down, @@ -18,10 +20,12 @@ enum RepeaterState { Failed } +#[cfg(has_drtio_routing)] impl Default for RepeaterState { fn default() -> RepeaterState { RepeaterState::Down } } +#[cfg(has_drtio_routing)] #[derive(Clone, Copy, Default)] pub struct Repeater { repno: u8, @@ -253,11 +257,18 @@ impl Repeater { } } +#[cfg(not(has_drtio_routing))] +#[derive(Clone, Copy, Default)] +pub struct Repeater { +} + #[cfg(not(has_drtio_routing))] impl Repeater { pub fn new(_repno: u8) -> Repeater { Repeater::default() } - pub fn service(&self) { } + pub fn service(&self, _routing_table: &drtio_routing::RoutingTable, _rank: u8) { } - pub fn sync_tsc(&self) -> Result<(), &'static str> { Ok(()) } + pub fn sync_tsc(&self) -> Result<(), drtioaux::Error> { Ok(()) } + + pub fn rtio_reset(&self, _phy: bool) -> Result<(), drtioaux::Error> { Ok(()) } } From c0c413196a912f7d36ab04cb8f5561b5fc18e83c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 12:08:06 +0800 Subject: [PATCH 1241/2457] frontend: remove artiq_pcap. Closes #1152 --- artiq/frontend/artiq_pcap.py | 57 ------------------------------------ setup.py | 1 - 2 files changed, 58 deletions(-) delete mode 100755 artiq/frontend/artiq_pcap.py diff --git a/artiq/frontend/artiq_pcap.py b/artiq/frontend/artiq_pcap.py deleted file mode 100755 index 59f124734..000000000 --- a/artiq/frontend/artiq_pcap.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 - -# This script makes the following assumptions: -# * tcpdump has CAP_NET_RAW capabilities set -# use # setcap cap_net_raw+eip /usr/sbin/tcpdump - -import os -import argparse -import subprocess - -from artiq.tools import verbosity_args, init_logger, logger, SSHClient - - -def get_argparser(): - parser = argparse.ArgumentParser(description="ARTIQ core device " - "packet capture tool") - - verbosity_args(parser) - - parser.add_argument("-H", "--host", metavar="HOST", - type=str, default="lab.m-labs.hk", - help="SSH host where the development board is located") - parser.add_argument("-D", "--device", metavar="DEVICE", - type=str, default="kc705.lab.m-labs.hk", - help="address or domain corresponding to the development board") - parser.add_argument("-f", "--file", metavar="PCAP_FILE", - type=str, default="coredevice.pcap", - help="Location to retrieve the pcap file into") - - parser.add_argument("command", metavar="COMMAND", - type=str, default=[], nargs=argparse.REMAINDER, - help="command to execute while capturing") - - return parser - - -def main(): - args = get_argparser().parse_args() - init_logger(args) - - client = SSHClient(args.host) - - sftp = client.get_sftp() - tcpdump = client.spawn_command( - "/usr/sbin/tcpdump host {device} -w {tmp}/trace.pcap", get_pty=True, - device=args.device) - - try: - subprocess.check_call(args.command) - except subprocess.CalledProcessError: - logger.error("Command failed") - - tcpdump.close() - sftp.get("{tmp}/trace.pcap".format(tmp=client.tmp), - args.file + ".new") - os.rename(args.file + ".new", args.file) - logger.info("Pcap file {file} retrieved".format(file=args.file)) diff --git a/setup.py b/setup.py index a10ec254b..70187c8b2 100755 --- a/setup.py +++ b/setup.py @@ -25,7 +25,6 @@ console_scripts = [ "artiq_coremgmt = artiq.frontend.artiq_coremgmt:main", "artiq_ctlmgr = artiq.frontend.artiq_ctlmgr:main", "artiq_devtool = artiq.frontend.artiq_devtool:main", - "artiq_pcap = artiq.frontend.artiq_pcap:main", "artiq_influxdb = artiq.frontend.artiq_influxdb:main", "artiq_master = artiq.frontend.artiq_master:main", "artiq_mkfs = artiq.frontend.artiq_mkfs:main", From eaeab0c9bd36212971a814e114110455029c8f23 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 10:44:59 +0800 Subject: [PATCH 1242/2457] frontend: add artiq_rtiomon --- artiq/frontend/artiq_rtiomon.py | 39 +++++++++++++++++++++++++++++++++ setup.py | 1 + 2 files changed, 40 insertions(+) create mode 100755 artiq/frontend/artiq_rtiomon.py diff --git a/artiq/frontend/artiq_rtiomon.py b/artiq/frontend/artiq_rtiomon.py new file mode 100755 index 000000000..eed6a9074 --- /dev/null +++ b/artiq/frontend/artiq_rtiomon.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +import argparse +import asyncio + +from artiq.coredevice.comm_moninj import * + + +def get_argparser(): + parser = argparse.ArgumentParser( + description="ARTIQ RTIO monitor") + parser.add_argument("core_addr", metavar="CORE_ADDR", + help="hostname or IP address of the core device") + parser.add_argument("channel", metavar="CHANNEL", type=lambda x: int(x, 0), nargs="+", + help="channel(s) to monitor") + return parser + + +def main(): + args = get_argparser().parse_args() + + loop = asyncio.get_event_loop() + try: + comm = CommMonInj( + lambda channel, probe, value: print("0x{:06x}: {}".format(channel, value)), + lambda channel, override, value: None) + loop.run_until_complete(comm.connect(args.core_addr)) + try: + for channel in args.channel: + comm.monitor_probe(True, channel, 0) + loop.run_forever() + finally: + loop.run_until_complete(comm.close()) + finally: + loop.close() + + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index a85f23ae5..0c7b31cc2 100755 --- a/setup.py +++ b/setup.py @@ -29,6 +29,7 @@ console_scripts = [ "artiq_influxdb = artiq.frontend.artiq_influxdb:main", "artiq_master = artiq.frontend.artiq_master:main", "artiq_mkfs = artiq.frontend.artiq_mkfs:main", + "artiq_rtiomon = artiq.frontend.artiq_rtiomon:main", "artiq_session = artiq.frontend.artiq_session:main", "artiq_rpctool = artiq.frontend.artiq_rpctool:main", "artiq_run = artiq.frontend.artiq_run:main", From 7565d816e45e295b7919f587e2b37c1ab4122651 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 12:08:06 +0800 Subject: [PATCH 1243/2457] frontend: remove artiq_pcap. Closes #1152 --- artiq/frontend/artiq_pcap.py | 57 ------------------------------------ setup.py | 1 - 2 files changed, 58 deletions(-) delete mode 100755 artiq/frontend/artiq_pcap.py diff --git a/artiq/frontend/artiq_pcap.py b/artiq/frontend/artiq_pcap.py deleted file mode 100755 index 59f124734..000000000 --- a/artiq/frontend/artiq_pcap.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 - -# This script makes the following assumptions: -# * tcpdump has CAP_NET_RAW capabilities set -# use # setcap cap_net_raw+eip /usr/sbin/tcpdump - -import os -import argparse -import subprocess - -from artiq.tools import verbosity_args, init_logger, logger, SSHClient - - -def get_argparser(): - parser = argparse.ArgumentParser(description="ARTIQ core device " - "packet capture tool") - - verbosity_args(parser) - - parser.add_argument("-H", "--host", metavar="HOST", - type=str, default="lab.m-labs.hk", - help="SSH host where the development board is located") - parser.add_argument("-D", "--device", metavar="DEVICE", - type=str, default="kc705.lab.m-labs.hk", - help="address or domain corresponding to the development board") - parser.add_argument("-f", "--file", metavar="PCAP_FILE", - type=str, default="coredevice.pcap", - help="Location to retrieve the pcap file into") - - parser.add_argument("command", metavar="COMMAND", - type=str, default=[], nargs=argparse.REMAINDER, - help="command to execute while capturing") - - return parser - - -def main(): - args = get_argparser().parse_args() - init_logger(args) - - client = SSHClient(args.host) - - sftp = client.get_sftp() - tcpdump = client.spawn_command( - "/usr/sbin/tcpdump host {device} -w {tmp}/trace.pcap", get_pty=True, - device=args.device) - - try: - subprocess.check_call(args.command) - except subprocess.CalledProcessError: - logger.error("Command failed") - - tcpdump.close() - sftp.get("{tmp}/trace.pcap".format(tmp=client.tmp), - args.file + ".new") - os.rename(args.file + ".new", args.file) - logger.info("Pcap file {file} retrieved".format(file=args.file)) diff --git a/setup.py b/setup.py index 0c7b31cc2..5370cb6d0 100755 --- a/setup.py +++ b/setup.py @@ -25,7 +25,6 @@ console_scripts = [ "artiq_coremgmt = artiq.frontend.artiq_coremgmt:main", "artiq_ctlmgr = artiq.frontend.artiq_ctlmgr:main", "artiq_devtool = artiq.frontend.artiq_devtool:main", - "artiq_pcap = artiq.frontend.artiq_pcap:main", "artiq_influxdb = artiq.frontend.artiq_influxdb:main", "artiq_master = artiq.frontend.artiq_master:main", "artiq_mkfs = artiq.frontend.artiq_mkfs:main", From cd61ee858ce3b651896f061d900e66529bfa8328 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 14:06:54 +0800 Subject: [PATCH 1244/2457] kasli: fix satellite TSC instantiation --- artiq/gateware/targets/kasli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 9070bf241..9c37c2220 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -816,7 +816,7 @@ class _SatelliteBase(BaseSoC): self.comb += [sfp_ctl.led.eq(channel.rx_ready) for sfp_ctl, channel in zip(sfp_ctls, self.drtio_transceiver.channels)] - self.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) + self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) drtioaux_csr_group = [] drtioaux_memory_group = [] From 1990ab35d387b1fa12e2991643cf2fa3f06e1a44 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 15 Sep 2018 07:35:35 +0000 Subject: [PATCH 1245/2457] firmware: implement mutexes. --- artiq/firmware/runtime/sched.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index c28fff956..4c027e895 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -265,6 +265,28 @@ impl<'a> Io<'a> { } } +pub struct Mutex(Urc>); + +impl Mutex { + pub fn new() -> Mutex { + Mutex(Urc::new(Cell::new(false))) + } + + pub fn lock<'a>(&'a self, io: Io) -> Result, Error> { + io.until(|| !self.0.get())?; + self.0.set(true); + Ok(MutexGuard(&*self.0)) + } +} + +pub struct MutexGuard<'a>(&'a Cell); + +impl<'a> Drop for MutexGuard<'a> { + fn drop(&mut self) { + self.0.set(false) + } +} + macro_rules! until { ($socket:expr, $ty:ty, |$var:ident| $cond:expr) => ({ let (sockets, handle) = ($socket.io.sockets.clone(), $socket.handle); From d38755feff1c25c456854cbfa8beb72d4b52c628 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 15:55:45 +0800 Subject: [PATCH 1246/2457] drtio: implement destination state checks on operations --- artiq/coredevice/exceptions.py | 2 +- artiq/firmware/ksupport/lib.rs | 4 +-- artiq/firmware/ksupport/rtio.rs | 32 +++++++++---------- .../firmware/libboard_artiq/drtio_routing.rs | 28 +++++++++++----- artiq/firmware/runtime/rtio_mgt.rs | 10 +++--- artiq/firmware/satman/main.rs | 2 +- artiq/gateware/drtio/rt_controller_master.py | 6 ++-- artiq/gateware/rtio/cri.py | 15 +++++++-- artiq/gateware/test/drtio/test_full_stack.py | 4 +-- artiq/gateware/test/rtio/test_dma.py | 4 +-- 10 files changed, 63 insertions(+), 44 deletions(-) diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index 017266729..0d84d49c0 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -91,7 +91,7 @@ class RTIOOverflow(Exception): artiq_builtin = True -class RTIOLinkError(Exception): +class RTIODestinationUnreachable(Exception): """Raised with a RTIO operation could not be completed due to a DRTIO link being down. """ diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index d4a6615d2..35ac00eb4 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -428,8 +428,8 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { timestamp as i64, channel as i64, 0); } if error & 2 != 0 { - raise!("RTIOLinkError", - "RTIO output link error at {0} mu, channel {1}", + raise!("RTIODestinationUnreachable", + "RTIO destination unreachable, output, at {0} mu, channel {1}", timestamp as i64, channel as i64, 0); } } diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index 119fab8f5..e0368b593 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -7,13 +7,13 @@ mod imp { use ::send; use kernel_proto::*; - pub const RTIO_O_STATUS_WAIT: u8 = 1; - pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2; - pub const RTIO_O_STATUS_LINK_ERROR: u8 = 4; - pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1; - pub const RTIO_I_STATUS_OVERFLOW: u8 = 2; - pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4; - pub const RTIO_I_STATUS_LINK_ERROR: u8 = 8; + pub const RTIO_O_STATUS_WAIT: u8 = 1; + pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2; + pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: u8 = 4; + pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1; + pub const RTIO_I_STATUS_OVERFLOW: u8 = 2; + pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4; + pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: u8 = 8; pub extern fn init() { send(&RtioInitRequest); @@ -49,9 +49,9 @@ mod imp { "RTIO underflow at {0} mu, channel {1}, slack {2} mu", timestamp, channel as i64, timestamp - get_counter()); } - if status & RTIO_O_STATUS_LINK_ERROR != 0 { - raise!("RTIOLinkError", - "RTIO output link error at {0} mu, channel {1}", + if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 { + raise!("RTIODestinationUnreachable", + "RTIO destination unreachable, output, at {0} mu, channel {1}", timestamp, channel as i64, 0); } } @@ -108,9 +108,9 @@ mod imp { if status & RTIO_I_STATUS_WAIT_EVENT != 0 { return !0 } - if status & RTIO_I_STATUS_LINK_ERROR != 0 { - raise!("RTIOLinkError", - "RTIO input link error on channel {0}", + if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { + raise!("RTIODestinationUnreachable", + "RTIO destination unreachable, input, on channel {0}", channel as i64, 0, 0); } @@ -135,9 +135,9 @@ mod imp { "RTIO input overflow on channel {0}", channel as i64, 0, 0); } - if status & RTIO_I_STATUS_LINK_ERROR != 0 { - raise!("RTIOLinkError", - "RTIO input link error on channel {0}", + if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { + raise!("RTIODestinationUnreachable", + "RTIO destination unreachable, input, on channel {0}", channel as i64, 0, 0); } diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index fe51c3cc4..cc49c7b54 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -72,13 +72,25 @@ pub fn config_routing_table(default_n_links: usize) -> RoutingTable { } #[cfg(has_drtio_routing)] -pub fn program_interconnect(rt: &RoutingTable, rank: u8) -{ - for i in 0..DEST_COUNT { - let hop = rt.0[i][rank as usize]; - unsafe { - csr::routing_table::destination_write(i as _); - csr::routing_table::hop_write(hop); - } +pub fn interconnect_enable(routing_table: &RoutingTable, rank: u8, destination: u8) { + let hop = routing_table.0[destination as usize][rank as usize]; + unsafe { + csr::routing_table::destination_write(destination); + csr::routing_table::hop_write(hop); + } +} + +#[cfg(has_drtio_routing)] +pub fn interconnect_disable(destination: u8) { + unsafe { + csr::routing_table::destination_write(destination); + csr::routing_table::hop_write(INVALID_HOP); + } +} + +#[cfg(has_drtio_routing)] +pub fn interconnect_enable_all(routing_table: &RoutingTable, rank: u8) { + for i in 0..DEST_COUNT { + interconnect_enable(routing_table, rank, i as u8); } } diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 237b71667..042db050f 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -216,6 +216,7 @@ pub mod drtio { if !up_destinations[destination] { info!("[DEST#{}] destination is up", destination); up_destinations[destination] = true; + drtio_routing::interconnect_enable(routing_table, 0, destination as u8); } } else if hop as usize <= csr::DRTIO.len() { let linkno = hop - 1; @@ -228,6 +229,7 @@ pub mod drtio { Ok(drtioaux::Packet::DestinationDownReply) => { info!("[DEST#{}] destination is down", destination); up_destinations[destination] = false; + drtio_routing::interconnect_disable(destination as u8); }, Ok(drtioaux::Packet::DestinationOkReply) => (), Ok(drtioaux::Packet::DestinationSequenceErrorReply { channel }) => @@ -242,6 +244,7 @@ pub mod drtio { } else { info!("[DEST#{}] destination is down", destination); up_destinations[destination] = false; + drtio_routing::interconnect_disable(destination as u8); } } else { if link_up(linkno) { @@ -253,6 +256,7 @@ pub mod drtio { Ok(drtioaux::Packet::DestinationOkReply) => { info!("[DEST#{}] destination is up", destination); up_destinations[destination] = true; + drtio_routing::interconnect_enable(routing_table, 0, destination as u8); init_buffer_space(destination as u8, linkno); }, Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), @@ -394,12 +398,6 @@ pub fn startup(io: &Io, routing_table: &Urc } } - #[cfg(has_drtio_routing)] - { - let routing_table = routing_table.clone(); - drtio_routing::program_interconnect(&routing_table.borrow(), 0); - } - drtio::startup(io, &routing_table); init_core(true); io.spawn(4096, async_error_thread); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 8fb9c287e..1e69111b2 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -171,7 +171,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], #[cfg(has_drtio_routing)] drtioaux::Packet::RoutingSetRank { rank } => { *_rank = rank; - drtio_routing::program_interconnect(_routing_table, rank); + drtio_routing::interconnect_enable_all(_routing_table, rank); let rep_rank = rank + 1; for rep in _repeaters.iter() { diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index d1e0dd1e2..40014dce0 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -102,8 +102,7 @@ class RTController(Module): o_status_wait = Signal() o_status_underflow = Signal() self.comb += [ - self.cri.o_status.eq(Cat( - o_status_wait, o_status_underflow, ~self.csrs.link_up.storage)), + self.cri.o_status.eq(Cat(o_status_wait, o_status_underflow)), self.csrs.o_wait.status.eq(o_status_wait) ] o_underflow_set = Signal() @@ -143,8 +142,7 @@ class RTController(Module): i_status_overflow = Signal() i_status_wait_status = Signal() self.comb += self.cri.i_status.eq(Cat( - i_status_wait_event, i_status_overflow, i_status_wait_status, - ~self.csrs.link_up.storage)) + i_status_wait_event, i_status_overflow, i_status_wait_status)) load_read_reply = Signal() self.sync.sys_with_rst += [ diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index b60164ba2..adafa8d29 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -34,7 +34,7 @@ layout = [ ("o_data", 512, DIR_M_TO_S), ("o_address", 16, DIR_M_TO_S), # o_status bits: - # <0:wait> <1:underflow> <2:link error> + # <0:wait> <1:underflow> <2:destination unreachable> ("o_status", 3, DIR_S_TO_M), # pessimistic estimate of the number of outputs events that can be @@ -47,7 +47,7 @@ layout = [ ("i_timestamp", 64, DIR_S_TO_M), # i_status bits: # <0:wait for event (command timeout)> <1:overflow> <2:wait for status> - # <3:link error> + # <3:destination unreachable> # <0> and <1> are mutually exclusive. <1> has higher priority. ("i_status", 4, DIR_S_TO_M), ] @@ -122,6 +122,17 @@ class CRIDecoder(Module, AutoCSR): # # # # routing + if enable_routing: + destination_unreachable = Interface() + self.comb += [ + destination_unreachable.o_status.eq(4), + destination_unreachable.i_status.eq(8) + ] + slaves = slaves[:] + slaves.append(destination_unreachable) + target_len = 2**(len(slaves) - 1).bit_length() + slaves += [destination_unreachable]*(target_len - len(slaves)) + slave_bits = bits_for(len(slaves)-1) selected = Signal(slave_bits) diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 8a23b2db9..579d78f9b 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -125,7 +125,7 @@ class OutputsTestbench: if status & 0x2: raise RTIOUnderflow if status & 0x4: - raise RTIOLinkError + raise RTIODestinationUnreachable yield wlen += 1 return wlen @@ -264,7 +264,7 @@ class TestFullStack(unittest.TestCase): if status & 0x2: return "overflow" if status & 0x8: - return "link error" + return "destination unreachable" return ((yield from kcsrs.i_data.read()), (yield from kcsrs.i_timestamp.read())) diff --git a/artiq/gateware/test/rtio/test_dma.py b/artiq/gateware/test/rtio/test_dma.py index ee546e2da..1ff14c8d4 100644 --- a/artiq/gateware/test/rtio/test_dma.py +++ b/artiq/gateware/test/rtio/test_dma.py @@ -5,7 +5,7 @@ import itertools from migen import * from misoc.interconnect import wishbone -from artiq.coredevice.exceptions import RTIOUnderflow, RTIOLinkError +from artiq.coredevice.exceptions import RTIOUnderflow, RTIODestinationUnreachable from artiq.gateware import rtio from artiq.gateware.rtio import dma, cri from artiq.gateware.rtio.phy import ttl_simple @@ -61,7 +61,7 @@ def do_dma(dut, address): if error & 1: raise RTIOUnderflow if error & 2: - raise RTIOLinkError + raise RTIODestinationUnreachable test_writes1 = [ From 3cbdf2fbac8902e4968f94b6dccdbcf8f9753491 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 18:43:27 +0800 Subject: [PATCH 1247/2457] kasli: cleanup drtio blink example --- .../examples/kasli_drtioswitching/repository/blink.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/artiq/examples/kasli_drtioswitching/repository/blink.py b/artiq/examples/kasli_drtioswitching/repository/blink.py index e5068efda..2af2d1233 100644 --- a/artiq/examples/kasli_drtioswitching/repository/blink.py +++ b/artiq/examples/kasli_drtioswitching/repository/blink.py @@ -8,10 +8,9 @@ class Blink(EnvExperiment): @kernel def run(self): - while True: - self.core.reset() + self.core.reset() - while True: - for led in self.leds: - led.pulse(200*ms) - delay(200*ms) + while True: + for led in self.leds: + led.pulse(200*ms) + delay(200*ms) From f7ad7a99e309b17e168ae99e951697dfeadf6fcb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 19:10:52 +0800 Subject: [PATCH 1248/2457] firmware: set DEST_COUNT to 0 without routing --- artiq/firmware/libboard_artiq/drtio_routing.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index cc49c7b54..562517342 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -3,7 +3,10 @@ use board_misoc::config; use board_misoc::csr; use core::fmt; +#[cfg(has_drtio_routing)] pub const DEST_COUNT: usize = 256; +#[cfg(not(has_drtio_routing))] +pub const DEST_COUNT: usize = 0; pub const MAX_HOPS: usize = 32; pub const INVALID_HOP: u8 = 0xff; From c8cd830118c04953474bdb60ef31e191a7c854cd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 15 Sep 2018 19:11:22 +0800 Subject: [PATCH 1249/2457] drtio: implement get_rtio_destination_status for kernels --- artiq/coredevice/core.py | 12 ++-- .../repository/sines_2sayma.py | 6 +- .../repository/sines_urukul_sayma.py | 4 +- .../sayma_masterdac/repository/sines_drtio.py | 2 +- artiq/firmware/ksupport/api.rs | 3 +- artiq/firmware/ksupport/rtio.rs | 21 +++--- artiq/firmware/libproto_artiq/kernel_proto.rs | 6 +- artiq/firmware/runtime/kern_hwreq.rs | 18 +++-- artiq/firmware/runtime/main.rs | 7 +- artiq/firmware/runtime/rtio_mgt.rs | 69 +++++++++++-------- artiq/firmware/runtime/session.rs | 32 ++++++--- doc/manual/installing.rst | 2 +- 12 files changed, 110 insertions(+), 72 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 9f84efe60..4c33fd266 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -44,11 +44,11 @@ def rtio_init() -> TNone: raise NotImplementedError("syscall not simulated") @syscall(flags={"nounwind", "nowrite"}) -def rtio_get_counter() -> TInt64: +def rtio_get_destination_status(linkno: TInt32) -> TBool: raise NotImplementedError("syscall not simulated") @syscall(flags={"nounwind", "nowrite"}) -def drtio_get_link_status(linkno: TInt32) -> TBool: +def rtio_get_counter() -> TInt64: raise NotImplementedError("syscall not simulated") @@ -154,12 +154,12 @@ class Core: return rtio_get_counter() @kernel - def get_drtio_link_status(self, linkno): - """Returns whether the specified DRTIO link is up. + def get_rtio_destination_status(self, destination): + """Returns whether the specified RTIO destination is up. This is particularly useful in startup kernels to delay - startup until certain DRTIO links are up.""" - return drtio_get_link_status(linkno) + startup until certain DRTIO destinations are up.""" + return rtio_get_destination_status(destination) @kernel def reset(self): diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py index 9b8e4d661..b6bc7884c 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py @@ -10,8 +10,8 @@ class Sines2Sayma(EnvExperiment): def run(self): while True: print("waiting for DRTIO ready...") - while not (self.core.get_drtio_link_status(0) and - self.core.get_drtio_link_status(1)): + while not (self.core.get_rtio_destination_status(0) and + self.core.get_rtio_destination_status(1)): pass print("OK") @@ -27,5 +27,5 @@ class Sines2Sayma(EnvExperiment): # Do not use a sub-multiple of oscilloscope sample rates. sawg.frequency0.set(9*MHz) - while self.core.get_drtio_link_status(0) and self.core.get_drtio_link_status(1): + while self.core.get_rtio_destination_status(0) and self.core.get_rtio_destination_status(1): pass diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py index 318a6e1ab..9b9ab68de 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py @@ -23,7 +23,7 @@ class SinesUrukulSayma(EnvExperiment): while True: print("waiting for DRTIO ready...") - while not self.core.get_drtio_link_status(0): + while not self.core.get_rtio_destination_status(0): pass print("OK") @@ -38,5 +38,5 @@ class SinesUrukulSayma(EnvExperiment): sawg.amplitude1.set(.4) sawg.frequency0.set(9*MHz) - while self.core.get_drtio_link_status(0): + while self.core.get_rtio_destination_status(0): pass diff --git a/artiq/examples/sayma_masterdac/repository/sines_drtio.py b/artiq/examples/sayma_masterdac/repository/sines_drtio.py index 7f242e4b8..70a7b3484 100644 --- a/artiq/examples/sayma_masterdac/repository/sines_drtio.py +++ b/artiq/examples/sayma_masterdac/repository/sines_drtio.py @@ -10,7 +10,7 @@ class SAWGTestDRTIO(EnvExperiment): @kernel def run(self): core_log("waiting for DRTIO ready...") - while not self.core.get_drtio_link_status(0): + while not self.core.get_rtio_destination_status(0): pass core_log("OK") diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index c1a0c22ff..be616256f 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -95,6 +95,7 @@ static mut API: &'static [(&'static str, *const ())] = &[ /* direct syscalls */ api!(rtio_init = ::rtio::init), + api!(rtio_get_destination_status = ::rtio::get_destination_status), api!(rtio_get_counter = ::rtio::get_counter), api!(rtio_log), api!(rtio_output = ::rtio::output), @@ -108,8 +109,6 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(dma_retrieve = ::dma_retrieve), api!(dma_playback = ::dma_playback), - api!(drtio_get_link_status = ::rtio::drtio::get_link_status), - api!(i2c_start = ::nrt_bus::i2c::start), api!(i2c_restart = ::nrt_bus::i2c::restart), api!(i2c_stop = ::nrt_bus::i2c::stop), diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index e0368b593..1324c0353 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -5,6 +5,7 @@ mod imp { use board_misoc::csr; use ::send; + use ::recv; use kernel_proto::*; pub const RTIO_O_STATUS_WAIT: u8 = 1; @@ -19,6 +20,15 @@ mod imp { send(&RtioInitRequest); } + pub extern fn get_destination_status(destination: i32) -> bool { + if 0 <= destination && destination <= 255 { + send(&RtioDestinationStatusRequest { destination: destination as u8 }); + recv!(&RtioDestinationStatusReply { up } => up) + } else { + false + } + } + pub extern fn get_counter() -> i64 { unsafe { csr::rtio::counter_update_write(1); @@ -209,14 +219,3 @@ mod imp { } pub use self::imp::*; - -pub mod drtio { - use ::send; - use ::recv; - use kernel_proto::*; - - pub extern fn get_link_status(linkno: i32) -> bool { - send(&DrtioLinkStatusRequest { linkno: linkno as u8 }); - recv!(&DrtioLinkStatusReply { up } => up) - } -} diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index 477c00a1b..73c9e2765 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -28,6 +28,9 @@ pub enum Message<'a> { RtioInitRequest, + RtioDestinationStatusRequest { destination: u8 }, + RtioDestinationStatusReply { up: bool }, + DmaRecordStart(&'a str), DmaRecordAppend(&'a [u8]), DmaRecordStop { @@ -46,9 +49,6 @@ pub enum Message<'a> { duration: u64 }, - DrtioLinkStatusRequest { linkno: u8 }, - DrtioLinkStatusReply { up: bool }, - RunFinished, RunException { exception: Exception<'a>, diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index 7a9ce6061..631209923 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -1,7 +1,9 @@ +use core::cell::RefCell; use kernel_proto as kern; use sched::{Io, Error as SchedError}; use session::{kern_acknowledge, kern_send, Error}; use rtio_mgt; +use urc::Urc; use board_artiq::drtio_routing; use board_artiq::i2c as local_i2c; use board_artiq::spi as local_spi; @@ -203,7 +205,9 @@ macro_rules! dispatch { }} } -pub fn process_kern_hwreq(io: &Io, _routing_table: &drtio_routing::RoutingTable, +pub fn process_kern_hwreq(io: &Io, + _routing_table: &drtio_routing::RoutingTable, + _up_destinations: &Urc>, request: &kern::Message) -> Result> { match request { &kern::RtioInitRequest => { @@ -212,9 +216,15 @@ pub fn process_kern_hwreq(io: &Io, _routing_table: &drtio_routing::RoutingTable, kern_acknowledge() } - &kern::DrtioLinkStatusRequest { linkno } => { - let up = rtio_mgt::drtio::link_up(linkno); - kern_send(io, &kern::DrtioLinkStatusReply { up: up }) + &kern::RtioDestinationStatusRequest { destination: _destination } => { + #[cfg(has_drtio)] + let up = { + let up_destinations = _up_destinations.borrow(); + up_destinations[_destination as usize] + }; + #[cfg(not(has_drtio))] + let up = true; + kern_send(io, &kern::RtioDestinationStatusReply { up: up }) } &kern::I2cStartRequest { busno } => { diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 6ecf79dd0..fe7a26d91 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -287,16 +287,19 @@ fn startup_ethernet() { #[cfg(not(has_drtio))] let drtio_routing_table = urc::Urc::new(RefCell::new( drtio_routing::RoutingTable::default_empty())); + let up_destinations = urc::Urc::new(RefCell::new( + [false; drtio_routing::DEST_COUNT])); let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); - rtio_mgt::startup(&io, &drtio_routing_table); + rtio_mgt::startup(&io, &drtio_routing_table, &up_destinations); io.spawn(4096, mgmt::thread); { let drtio_routing_table = drtio_routing_table.clone(); - io.spawn(16384, move |io| { session::thread(io, &drtio_routing_table) }); + let up_destinations = up_destinations.clone(); + io.spawn(16384, move |io| { session::thread(io, &drtio_routing_table, &up_destinations) }); } #[cfg(any(has_rtio_moninj, has_drtio))] { diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 042db050f..e3688fb57 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -47,14 +47,16 @@ pub mod drtio { use super::*; use drtioaux; - pub fn startup(io: &Io, routing_table: &Urc>) { + pub fn startup(io: &Io, routing_table: &Urc>, + up_destinations: &Urc>) { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } let routing_table = routing_table.clone(); + let up_destinations = up_destinations.clone(); io.spawn(4096, move |io| { let routing_table = routing_table.borrow(); - link_thread(io, &routing_table) + link_thread(io, &routing_table, &up_destinations); }); } @@ -206,31 +208,46 @@ pub mod drtio { } } + fn destination_set_up(routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>, + destination: u8, up: bool) { + let mut up_destinations = up_destinations.borrow_mut(); + up_destinations[destination as usize] = up; + if up { + drtio_routing::interconnect_enable(routing_table, 0, destination); + info!("[DEST#{}] destination is up", destination); + } else { + drtio_routing::interconnect_disable(destination); + info!("[DEST#{}] destination is down", destination); + } + } + + fn destination_up(up_destinations: &Urc>, destination: u8) -> bool { + let up_destinations = up_destinations.borrow(); + up_destinations[destination as usize] + } + fn destination_survey(io: &Io, routing_table: &drtio_routing::RoutingTable, - up_destinations: &mut [bool; drtio_routing::DEST_COUNT]) { + up_destinations: &Urc>) { for destination in 0..drtio_routing::DEST_COUNT { let hop = routing_table.0[destination][0]; + let destination = destination as u8; if hop == 0 { /* local RTIO */ - if !up_destinations[destination] { - info!("[DEST#{}] destination is up", destination); - up_destinations[destination] = true; - drtio_routing::interconnect_enable(routing_table, 0, destination as u8); + if !destination_up(up_destinations, destination) { + destination_set_up(routing_table, up_destinations, destination, true); } } else if hop as usize <= csr::DRTIO.len() { let linkno = hop - 1; - if up_destinations[destination] { + if destination_up(up_destinations, destination) { if link_up(linkno) { drtioaux::send(linkno, &drtioaux::Packet::DestinationStatusRequest { - destination: destination as u8 + destination: destination }).unwrap(); match recv_aux_timeout(io, linkno, 200) { - Ok(drtioaux::Packet::DestinationDownReply) => { - info!("[DEST#{}] destination is down", destination); - up_destinations[destination] = false; - drtio_routing::interconnect_disable(destination as u8); - }, + Ok(drtioaux::Packet::DestinationDownReply) => + destination_set_up(routing_table, up_destinations, destination, false), Ok(drtioaux::Packet::DestinationOkReply) => (), Ok(drtioaux::Packet::DestinationSequenceErrorReply { channel }) => error!("[DEST#{}] RTIO sequence error involving channel 0x{:04x}", destination, channel), @@ -242,21 +259,17 @@ pub mod drtio { Err(e) => error!("[DEST#{}] communication failed ({})", destination, e) } } else { - info!("[DEST#{}] destination is down", destination); - up_destinations[destination] = false; - drtio_routing::interconnect_disable(destination as u8); + destination_set_up(routing_table, up_destinations, destination, false); } } else { if link_up(linkno) { drtioaux::send(linkno, &drtioaux::Packet::DestinationStatusRequest { - destination: destination as u8 + destination: destination }).unwrap(); match recv_aux_timeout(io, linkno, 200) { Ok(drtioaux::Packet::DestinationDownReply) => (), Ok(drtioaux::Packet::DestinationOkReply) => { - info!("[DEST#{}] destination is up", destination); - up_destinations[destination] = true; - drtio_routing::interconnect_enable(routing_table, 0, destination as u8); + destination_set_up(routing_table, up_destinations, destination, true); init_buffer_space(destination as u8, linkno); }, Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), @@ -268,8 +281,8 @@ pub mod drtio { } } - pub fn link_thread(io: Io, routing_table: &drtio_routing::RoutingTable) { - let mut up_destinations = [false; drtio_routing::DEST_COUNT]; + pub fn link_thread(io: Io, routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>) { loop { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; @@ -306,7 +319,7 @@ pub mod drtio { } } } - destination_survey(&io, routing_table, &mut up_destinations); + destination_survey(&io, routing_table, up_destinations); io.sleep(200).unwrap(); } } @@ -331,7 +344,8 @@ pub mod drtio { pub mod drtio { use super::*; - pub fn startup(_io: &Io, _routing_table: &Urc>) {} + pub fn startup(_io: &Io, _routing_table: &Urc>, + _up_destinations: &Urc>) {} pub fn init() {} pub fn link_up(_linkno: u8) -> bool { false } } @@ -358,7 +372,8 @@ fn async_error_thread(io: Io) { } } -pub fn startup(io: &Io, routing_table: &Urc>) { +pub fn startup(io: &Io, routing_table: &Urc>, + up_destinations: &Urc>) { #[cfg(has_rtio_crg)] { #[cfg(has_rtio_clock_switch)] @@ -398,7 +413,7 @@ pub fn startup(io: &Io, routing_table: &Urc } } - drtio::startup(io, &routing_table); + drtio::startup(io, routing_table, up_destinations); init_core(true); io.spawn(4096, async_error_thread); } diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 4c081810e..e413e8749 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -324,7 +324,9 @@ fn process_host_message(io: &Io, Ok(()) } -fn process_kern_message(io: &Io, routing_table: &drtio_routing::RoutingTable, +fn process_kern_message(io: &Io, + routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>, mut stream: Option<&mut TcpStream>, session: &mut Session) -> Result> { kern_recv_notrace(io, |request| { @@ -343,7 +345,7 @@ fn process_kern_message(io: &Io, routing_table: &drtio_routing::RoutingTable, kern_recv_dotrace(request); - if kern_hwreq::process_kern_hwreq(io, routing_table, request)? { + if kern_hwreq::process_kern_hwreq(io, routing_table, up_destinations, request)? { return Ok(false) } @@ -492,7 +494,9 @@ fn process_kern_queued_rpc(stream: &mut TcpStream, }) } -fn host_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, +fn host_kernel_worker(io: &Io, + routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>, stream: &mut TcpStream, congress: &mut Congress) -> Result<(), Error> { let mut session = Session::new(congress); @@ -509,7 +513,9 @@ fn host_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, } if mailbox::receive() != 0 { - process_kern_message(io, routing_table, Some(stream), &mut session)?; + process_kern_message(io, + routing_table, up_destinations, + Some(stream), &mut session)?; } if session.kernel_state == KernelState::Running { @@ -528,7 +534,9 @@ fn host_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, } } -fn flash_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, +fn flash_kernel_worker(io: &Io, + routing_table: &drtio_routing::RoutingTable, + up_destinations: &Urc>, congress: &mut Congress, config_key: &str) -> Result<(), Error> { let mut session = Session::new(congress); @@ -551,7 +559,7 @@ fn flash_kernel_worker(io: &Io, routing_table: &drtio_routing::RoutingTable, } if mailbox::receive() != 0 { - if process_kern_message(io, routing_table, None, &mut session)? { + if process_kern_message(io, routing_table, up_destinations, None, &mut session)? { return Ok(()) } } @@ -583,7 +591,8 @@ fn respawn(io: &Io, handle: &mut Option, f: F) *handle = Some(io.spawn(16384, f)) } -pub fn thread(io: Io, routing_table: &Urc>) { +pub fn thread(io: Io, routing_table: &Urc>, + up_destinations: &Urc>) { let listener = TcpListener::new(&io, 65535); listener.listen(1381).expect("session: cannot listen"); info!("accepting network sessions"); @@ -593,12 +602,13 @@ pub fn thread(io: Io, routing_table: &Urc>) let mut kernel_thread = None; { let routing_table = routing_table.clone(); + let up_destinations = up_destinations.clone(); let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); info!("running startup kernel"); - match flash_kernel_worker(&io, &routing_table, &mut congress, "startup_kernel") { + match flash_kernel_worker(&io, &routing_table, &up_destinations, &mut congress, "startup_kernel") { Ok(()) => info!("startup kernel finished"), Err(Error::KernelNotFound) => @@ -628,13 +638,14 @@ pub fn thread(io: Io, routing_table: &Urc>) info!("new connection from {}", stream.remote_endpoint()); let routing_table = routing_table.clone(); + let up_destinations = up_destinations.clone(); let congress = congress.clone(); let stream = stream.into_handle(); respawn(&io, &mut kernel_thread, move |io| { let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); let mut stream = TcpStream::from_handle(&io, stream); - match host_kernel_worker(&io, &routing_table, &mut stream, &mut *congress) { + match host_kernel_worker(&io, &routing_table, &up_destinations, &mut stream, &mut *congress) { Ok(()) => (), Err(Error::Protocol(host::Error::Io(IoError::UnexpectedEnd))) => info!("connection closed"), @@ -653,11 +664,12 @@ pub fn thread(io: Io, routing_table: &Urc>) info!("no connection, starting idle kernel"); let routing_table = routing_table.clone(); + let up_destinations = up_destinations.clone(); let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); - match flash_kernel_worker(&io, &routing_table, &mut *congress, "idle_kernel") { + match flash_kernel_worker(&io, &routing_table, &up_destinations, &mut *congress, "idle_kernel") { Ok(()) => info!("idle kernel finished, standing by"), Err(Error::Protocol(host::Error::Io( diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 05a761493..5030d63d1 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -190,7 +190,7 @@ To flash the idle kernel: The startup kernel is executed once when the core device powers up. It should initialize DDSes, set up TTL directions, etc. Proceed as with the idle kernel, but using the ``startup_kernel`` key in the ``artiq_coremgmt`` command. -For DRTIO systems, the startup kernel should wait until the desired links are up, using :meth:`artiq.coredevice.Core.get_drtio_link_status`. +For DRTIO systems, the startup kernel should wait until the desired destinations (including local RTIO) are up, using :meth:`artiq.coredevice.Core.get_rtio_destination_status`. * (optional) Select the RTIO clock source From c33f74dabef9793f7847df2c15958d4243755f98 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 15 Sep 2018 15:24:31 +0000 Subject: [PATCH 1250/2457] firmware: derive Clone for Mutex. --- artiq/firmware/runtime/sched.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index 4c027e895..770ac3f6c 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -265,6 +265,7 @@ impl<'a> Io<'a> { } } +#[derive(Clone)] pub struct Mutex(Urc>); impl Mutex { From 2b44786f73c7f0619ecf80d4e48a7d608187aa3f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 17 Sep 2018 23:45:27 +0800 Subject: [PATCH 1251/2457] drtio: add repeater input support --- artiq/gateware/drtio/rt_packet_repeater.py | 102 ++++++++++++++++-- .../test/drtio/test_rt_packet_repeater.py | 62 +++++++++++ 2 files changed, 158 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 7f709589f..150704f75 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -103,6 +103,61 @@ class RTPacketRepeater(Module): timeout_counter = ClockDomainsRenamer("rtio")(WaitTimer(8191)) self.submodules += timeout_counter + # Read + rb_chan_sel = Signal(24) + rb_timeout = Signal(64) + self.sync.rtio += If(self.cri.cmd == cri.commands["read"], + rb_chan_sel.eq(self.cri.chan_sel), + rb_timeout.eq(self.cri.timestamp)) + + read_not = Signal() + read_no_event = Signal() + read_is_overflow = Signal() + read_data = Signal(32) + read_timestamp = Signal(64) + rtio_read_not = Signal() + rtio_read_not_ack = Signal() + rtio_read_no_event = Signal() + rtio_read_is_overflow = Signal() + rtio_read_data = Signal(32) + rtio_read_timestamp = Signal(64) + self.submodules += CrossDomainNotification("rtio_rx", "rtio", + read_not, + Cat(read_no_event, read_is_overflow, read_data, read_timestamp), + + rtio_read_not, rtio_read_not_ack, + Cat(rtio_read_no_event, rtio_read_is_overflow, + rtio_read_data, rtio_read_timestamp)) + self.comb += [ + read_is_overflow.eq(rx_dp.packet_as["read_reply_noevent"].overflow), + read_data.eq(rx_dp.packet_as["read_reply"].data), + read_timestamp.eq(rx_dp.packet_as["read_reply"].timestamp) + ] + + # input status + i_status_wait_event = Signal() + i_status_overflow = Signal() + i_status_wait_status = Signal() + self.comb += self.cri.i_status.eq(Cat( + i_status_wait_event, i_status_overflow, i_status_wait_status)) + + load_read_reply = Signal() + self.sync.rtio += [ + If(load_read_reply, + i_status_wait_event.eq(0), + i_status_overflow.eq(0), + If(rtio_read_no_event, + If(rtio_read_is_overflow, + i_status_overflow.eq(1) + ).Else( + i_status_wait_event.eq(1) + ) + ), + self.cri.i_data.eq(rtio_read_data), + self.cri.i_timestamp.eq(rtio_read_timestamp) + ) + ] + # Missed commands cri_ready = Signal() self.sync.rtio += [ @@ -111,7 +166,7 @@ class RTPacketRepeater(Module): self.command_missed_cmd.eq(self.cri.cmd) ] - # TX FSM + # TX and CRI FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) self.submodules += tx_fsm @@ -126,9 +181,11 @@ class RTPacketRepeater(Module): ).Else( cri_ready.eq(1), If(self.cri.cmd == cri.commands["write"], NextState("WRITE")), - If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")) + If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")), + If(self.cri.cmd == cri.commands["read"], NextState("READ")) ) ) + tx_fsm.act("SET_TIME", tx_dp.send("set_time", timestamp=tsc_value), If(tx_dp.packet_last, @@ -136,6 +193,7 @@ class RTPacketRepeater(Module): NextState("IDLE") ) ) + tx_fsm.act("WRITE", tx_dp.send("write", timestamp=wb_timestamp, @@ -158,26 +216,46 @@ class RTPacketRepeater(Module): NextState("IDLE") ) ) + tx_fsm.act("BUFFER_SPACE", tx_dp.send("buffer_space_request", destination=self.buffer_space_destination), If(tx_dp.packet_last, buffer_space_not_ack.eq(1), - NextState("WAIT_BUFFER_SPACE") + NextState("GET_BUFFER_SPACE_REPLY") ) ) - tx_fsm.act("WAIT_BUFFER_SPACE", + tx_fsm.act("GET_BUFFER_SPACE_REPLY", timeout_counter.wait.eq(1), If(timeout_counter.done, self.err_buffer_space_timeout.eq(1), - NextState("IDLE") + NextState("READY") ).Else( If(buffer_space_not, self.cri.o_buffer_space_valid.eq(1), - NextState("IDLE") + NextState("READY") ), ) ) + tx_fsm.act("READ", + i_status_wait_status.eq(1), + tx_dp.send("read_request", + chan_sel=rb_chan_sel, + timeout=rb_timeout), + rtio_read_not_ack.eq(1), + If(tx_dp.packet_last, + NextState("GET_READ_REPLY") + ) + ) + tx_fsm.act("GET_READ_REPLY", + i_status_wait_status.eq(1), + rtio_read_not_ack.eq(1), + If(rtio_read_not, + load_read_reply.eq(1), + NextState("READY") + ) + ) + # RX FSM rx_fsm = ClockDomainsRenamer("rtio_rx")(FSM(reset_state="INPUT")) self.submodules += rx_fsm @@ -192,6 +270,8 @@ class RTPacketRepeater(Module): If(rx_dp.packet_last, Case(rx_dp.packet_type, { rx_plm.types["buffer_space_reply"]: NextState("BUFFER_SPACE"), + rx_plm.types["read_reply"]: NextState("READ_REPLY"), + rx_plm.types["read_reply_noevent"]: NextState("READ_REPLY_NOEVENT"), "default": self.err_unknown_packet_type.eq(1) }) ).Else( @@ -207,3 +287,13 @@ class RTPacketRepeater(Module): rx_buffer_space.eq(rx_dp.packet_as["buffer_space_reply"].space), NextState("INPUT") ) + rx_fsm.act("READ_REPLY", + read_not.eq(1), + read_no_event.eq(0), + NextState("INPUT") + ) + rx_fsm.act("READ_REPLY_NOEVENT", + read_not.eq(1), + read_no_event.eq(1), + NextState("INPUT") + ) diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index 70f25adb0..0bf80eb3d 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -128,3 +128,65 @@ class TestRepeater(unittest.TestCase): current_request = field_dict["destination"] run_simulation(dut, [send_requests(), send_replies(), pr.receive(receive)]) + + def test_input(self): + for nwords in range(1, 8): + pt, pr, ts, dut = create_dut(nwords) + + def read(chan_sel, timeout): + yield dut.cri.chan_sel.eq(chan_sel) + yield dut.cri.timestamp.eq(timeout) + yield dut.cri.cmd.eq(cri.commands["read"]) + yield + yield dut.cri.cmd.eq(cri.commands["nop"]) + yield + status = yield dut.cri.i_status + while status & 4: + yield + status = yield dut.cri.i_status + if status & 0x1: + return "timeout" + if status & 0x2: + return "overflow" + if status & 0x8: + return "destination unreachable" + return ((yield dut.cri.i_data), + (yield dut.cri.i_timestamp)) + + def send_requests(): + for timeout in range(20, 200000, 100000): + for chan_sel in range(3): + data, timestamp = yield from read(chan_sel, timeout) + self.assertEqual(data, chan_sel*2) + self.assertEqual(timestamp, timeout//2) + + i2 = yield from read(10, 400000) + self.assertEqual(i2, "timeout") + i3 = yield from read(11, 400000) + self.assertEqual(i3, "overflow") + + current_request = None + + @passive + def send_replies(): + nonlocal current_request + while True: + while current_request is None: + yield + chan_sel, timeout = current_request + if chan_sel == 10: + yield from pt.send("read_reply_noevent", overflow=0) + elif chan_sel == 11: + yield from pt.send("read_reply_noevent", overflow=1) + else: + yield from pt.send("read_reply", data=chan_sel*2, timestamp=timeout//2) + current_request = None + + def receive(packet_type, field_dict, trailer): + nonlocal current_request + self.assertEqual(packet_type, "read_request") + self.assertEqual(trailer, []) + self.assertEqual(current_request, None) + current_request = (field_dict["chan_sel"], field_dict["timeout"]) + + run_simulation(dut, [send_requests(), send_replies(), pr.receive(receive)]) From eda15a596c2e40e2ae08855cef3b76260ce0fb6d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 18 Sep 2018 15:27:25 +0800 Subject: [PATCH 1252/2457] drtio: add buffering to repeater --- artiq/gateware/drtio/rt_packet_repeater.py | 104 +++++++++++++-------- 1 file changed, 66 insertions(+), 38 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 150704f75..1cbd45750 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -48,16 +48,57 @@ class RTPacketRepeater(Module): tsc_value_load = Signal() self.sync.rtio += If(tsc_value_load, tsc_value.eq(tsc.coarse_ts)) - # Write buffer and extra data count - wb_timestamp = Signal(64) - wb_chan_sel = Signal(24) - wb_address = Signal(16) - wb_data = Signal(512) - self.sync.rtio += If(self.cri.cmd == cri.commands["write"], - wb_timestamp.eq(self.cri.timestamp), - wb_chan_sel.eq(self.cri.chan_sel), - wb_address.eq(self.cri.o_address), - wb_data.eq(self.cri.o_data)) + # CRI buffer stage 1 + cb0_loaded = Signal() + cb0_ack = Signal() + + cb0_cmd = Signal(2) + cb0_timestamp = Signal(64) + cb0_chan_sel = Signal(24) + cb0_o_address = Signal(16) + cb0_o_data = Signal(512) + self.sync.rtio += [ + If(cb0_ack, + cb0_loaded.eq(0), + cb0_cmd.eq(cri.commands["nop"]) + ), + If(~cb0_loaded & (self.cri.cmd != cri.commands["nop"]), + cb0_loaded.eq(1), + cb0_cmd.eq(self.cri.cmd), + cb0_timestamp.eq(self.cri.timestamp), + cb0_chan_sel.eq(self.cri.chan_sel), + cb0_o_address.eq(self.cri.o_address), + cb0_o_data.eq(self.cri.o_data) + ), + self.err_command_missed.eq(cb0_loaded & (self.cri.cmd != cri.commands["nop"])), + self.command_missed_chan_sel.eq(self.cri.chan_sel), + self.command_missed_cmd.eq(self.cri.cmd) + ] + + # CRI buffer stage 2 and write data slicer + cb_loaded = Signal() + cb_ack = Signal() + + cb_cmd = Signal(2) + cb_timestamp = Signal(64) + cb_chan_sel = Signal(24) + cb_o_address = Signal(16) + cb_o_data = Signal(512) + self.sync.rtio += [ + If(cb_ack, + cb_loaded.eq(0), + cb_cmd.eq(cri.commands["nop"]) + ), + If(~cb_loaded & cb0_loaded, + cb_loaded.eq(1), + cb_cmd.eq(cb0_cmd), + cb_timestamp.eq(cb0_timestamp), + cb_chan_sel.eq(cb0_chan_sel), + cb_o_address.eq(cb0_o_address), + cb_o_data.eq(cb0_o_data) + ) + ] + self.comb += cb0_ack.eq(~cb_loaded) wb_extra_data_cnt = Signal(8) short_data_len = tx_plm.field_length("write", "short_data") @@ -104,12 +145,6 @@ class RTPacketRepeater(Module): self.submodules += timeout_counter # Read - rb_chan_sel = Signal(24) - rb_timeout = Signal(64) - self.sync.rtio += If(self.cri.cmd == cri.commands["read"], - rb_chan_sel.eq(self.cri.chan_sel), - rb_timeout.eq(self.cri.timestamp)) - read_not = Signal() read_no_event = Signal() read_is_overflow = Signal() @@ -137,9 +172,8 @@ class RTPacketRepeater(Module): # input status i_status_wait_event = Signal() i_status_overflow = Signal() - i_status_wait_status = Signal() self.comb += self.cri.i_status.eq(Cat( - i_status_wait_event, i_status_overflow, i_status_wait_status)) + i_status_wait_event, i_status_overflow, cb0_loaded | cb_loaded)) load_read_reply = Signal() self.sync.rtio += [ @@ -158,14 +192,6 @@ class RTPacketRepeater(Module): ) ] - # Missed commands - cri_ready = Signal() - self.sync.rtio += [ - self.err_command_missed.eq(~cri_ready & (self.cri.cmd != cri.commands["nop"])), - self.command_missed_chan_sel.eq(self.cri.chan_sel), - self.command_missed_cmd.eq(self.cri.cmd) - ] - # TX and CRI FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) self.submodules += tx_fsm @@ -179,10 +205,9 @@ class RTPacketRepeater(Module): tsc_value_load.eq(1), NextState("SET_TIME") ).Else( - cri_ready.eq(1), - If(self.cri.cmd == cri.commands["write"], NextState("WRITE")), - If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")), - If(self.cri.cmd == cri.commands["read"], NextState("READ")) + If(cb_cmd == cri.commands["write"], NextState("WRITE")), + If(cb_cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")), + If(cb_cmd == cri.commands["read"], NextState("READ")) ) ) @@ -196,13 +221,14 @@ class RTPacketRepeater(Module): tx_fsm.act("WRITE", tx_dp.send("write", - timestamp=wb_timestamp, - chan_sel=wb_chan_sel, - address=wb_address, + timestamp=cb_timestamp, + chan_sel=cb_chan_sel, + address=cb_o_address, extra_data_cnt=wb_extra_data_cnt, - short_data=wb_data[:short_data_len]), + short_data=cb_o_data[:short_data_len]), If(tx_dp.packet_last, If(wb_extra_data_cnt == 0, + cb_ack.eq(1), NextState("IDLE") ).Else( NextState("WRITE_EXTRA") @@ -213,6 +239,7 @@ class RTPacketRepeater(Module): tx_dp.raw_stb.eq(1), extra_data_ce.eq(1), If(extra_data_last, + cb_ack.eq(1), NextState("IDLE") ) ) @@ -228,30 +255,31 @@ class RTPacketRepeater(Module): timeout_counter.wait.eq(1), If(timeout_counter.done, self.err_buffer_space_timeout.eq(1), + cb_ack.eq(1), NextState("READY") ).Else( If(buffer_space_not, self.cri.o_buffer_space_valid.eq(1), + cb_ack.eq(1), NextState("READY") ), ) ) tx_fsm.act("READ", - i_status_wait_status.eq(1), tx_dp.send("read_request", - chan_sel=rb_chan_sel, - timeout=rb_timeout), + chan_sel=cb_chan_sel, + timeout=cb_timestamp), rtio_read_not_ack.eq(1), If(tx_dp.packet_last, NextState("GET_READ_REPLY") ) ) tx_fsm.act("GET_READ_REPLY", - i_status_wait_status.eq(1), rtio_read_not_ack.eq(1), If(rtio_read_not, load_read_reply.eq(1), + cb_ack.eq(1), NextState("READY") ) ) From 970d1bf147ddcdcdda08c0b4d47c42e95986dc1a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 18 Sep 2018 15:27:52 +0800 Subject: [PATCH 1253/2457] drtio: add switching unittest --- artiq/gateware/test/drtio/test_switching.py | 165 ++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 artiq/gateware/test/drtio/test_switching.py diff --git a/artiq/gateware/test/drtio/test_switching.py b/artiq/gateware/test/drtio/test_switching.py new file mode 100644 index 000000000..66a9c9e69 --- /dev/null +++ b/artiq/gateware/test/drtio/test_switching.py @@ -0,0 +1,165 @@ +import unittest +from types import SimpleNamespace +import random + +from migen import * + +from artiq.gateware.drtio import * +from artiq.gateware.drtio import rt_serializer, rt_packet_repeater +from artiq.gateware import rtio +from artiq.gateware.rtio import cri +from artiq.coredevice.exceptions import * +from artiq.gateware.test.drtio.packet_interface import PacketInterface + + +class DummyTransceiverPair: + def __init__(self, nwords): + a2b_k = [Signal() for _ in range(nwords)] + a2b_d = [Signal(8) for _ in range(nwords)] + b2a_k = [Signal() for _ in range(nwords)] + b2a_d = [Signal(8) for _ in range(nwords)] + + self.alice = SimpleNamespace( + encoder=SimpleNamespace(k=a2b_k, d=a2b_d), + decoders=[SimpleNamespace(k=k, d=d) for k, d in zip(b2a_k, b2a_d)], + rx_ready=1 + ) + self.bob = SimpleNamespace( + encoder=SimpleNamespace(k=b2a_k, d=b2a_d), + decoders=[SimpleNamespace(k=k, d=d) for k, d in zip(a2b_k, a2b_d)], + rx_ready=1 + ) + + +class DummyRXSynchronizer: + def resync(self, signal): + return signal + + +class DUT(Module): + def __init__(self, nwords): + self.transceivers = DummyTransceiverPair(nwords) + + self.submodules.tsc_master = rtio.TSC("async") + self.submodules.master = DRTIOMaster(self.tsc_master, + self.transceivers.alice) + self.master.rt_controller.csrs.link_up.storage.reset = 1 + + rx_synchronizer = DummyRXSynchronizer() + self.submodules.tsc_satellite = rtio.TSC("sync") + self.submodules.satellite = DRTIOSatellite( + self.tsc_satellite, self.transceivers.bob, rx_synchronizer) + self.satellite.reset.storage.reset = 0 + self.satellite.reset.storage_full.reset = 0 + self.satellite.reset_phy.storage.reset = 0 + self.satellite.reset_phy.storage_full.reset = 0 + + self.pt = PacketInterface("s2m", nwords*8) + self.pr = PacketInterface("m2s", nwords*8) + rep_if = SimpleNamespace( + rx_rt_frame=self.pt.frame, rx_rt_data=self.pt.data, + tx_rt_frame=self.pr.frame, tx_rt_data=self.pr.data) + self.submodules.repeater = rt_packet_repeater.RTPacketRepeater( + self.tsc_satellite, rep_if) + self.comb += self.satellite.cri.connect(self.repeater.cri) + + +class Testbench: + def __init__(self): + self.dut = DUT(2) + self.now = 0 + + def init(self): + yield from self.dut.master.rt_controller.csrs.underflow_margin.write(100) + while not (yield from self.dut.master.link_layer.rx_up.read()): + yield + yield from self.get_buffer_space() + + def get_buffer_space(self): + csrs = self.dut.master.rt_controller.csrs + yield from csrs.o_get_buffer_space.write(1) + yield + while (yield from csrs.o_wait.read()): + yield + r = (yield from csrs.o_dbg_buffer_space.read()) + return r + + def delay(self, dt): + self.now += dt + + def write(self, channel, data): + mcri = self.dut.master.cri + yield mcri.chan_sel.eq(channel) + yield mcri.timestamp.eq(self.now) + yield mcri.o_data.eq(data) + yield + yield mcri.cmd.eq(cri.commands["write"]) + yield + yield mcri.cmd.eq(cri.commands["nop"]) + yield + status = yield mcri.o_status + while status & 0x1: + yield + status = yield mcri.o_status + if status & 0x2: + return "underflow" + if status & 0x4: + return "destination unreachable" + + +class TestSwitching(unittest.TestCase): + clocks = {"sys": 8, "rtio": 5, "rtio_rx": 5, + "rio": 5, "rio_phy": 5, + "sys_with_rst": 8, "rtio_with_rst": 5} + + def test_switching(self): + tb = Testbench() + + def test(): + yield from tb.init() + tb.delay(200) + yield from tb.write(1, 20) + for _ in range(40): + yield + + current_request = None + + def get_request(): + nonlocal current_request + while current_request is None: + yield + r = current_request + current_request = None + return r + + def expect_buffer_space_request(destination, space): + packet_type, field_dict, trailer = yield from get_request() + self.assertEqual(packet_type, "buffer_space_request") + self.assertEqual(trailer, []) + self.assertEqual(field_dict["destination"], destination) + yield from tb.dut.pt.send("buffer_space_reply", space=space) + + def expect_write(timestamp, channel, data): + packet_type, field_dict, trailer = yield from get_request() + self.assertEqual(packet_type, "write") + self.assertEqual(trailer, []) + self.assertEqual(field_dict["timestamp"], timestamp) + self.assertEqual(field_dict["chan_sel"], channel) + self.assertEqual(field_dict["short_data"], data) + + @passive + def send_replies(): + yield from expect_buffer_space_request(0, 1) + yield from expect_write(200, 1, 20) + yield from expect_buffer_space_request(0, 1) + + unexpected = yield from get_request() + self.fail("unexpected packet: {}".format(unexpected)) + + def receive(packet_type, field_dict, trailer): + nonlocal current_request + self.assertEqual(current_request, None) + current_request = (packet_type, field_dict, trailer) + + run_simulation(tb.dut, + {"sys": test(), "rtio": tb.dut.pr.receive(receive), "rtio_rx": send_replies()}, self.clocks) From b482f5feaedde7bd10903fd9e7cad249e596f88b Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 14 Sep 2018 17:01:00 +0100 Subject: [PATCH 1254/2457] firmware: Use larger ARP cache This works around a problematic interaction between ARP cache expiry in smoltcp (with its 3 seconds timeout before a discovery request is sent) and our TCP keepalive settings, where the timeout is reached before the keepalive had a chance to be sent. GitHub: Closes #1150. --- artiq/firmware/runtime/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index c4c3f674a..d617c55e9 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -270,9 +270,8 @@ fn startup_ethernet() { smoltcp::phy::EthernetTracer::new(net_device, net_trace_fn) }; - let mut neighbor_map = [None; 8]; let neighbor_cache = - smoltcp::iface::NeighborCache::new(&mut neighbor_map[..]); + smoltcp::iface::NeighborCache::new(alloc::btree_map::BTreeMap::new()); let mut interface = smoltcp::iface::EthernetInterfaceBuilder::new(net_device) .neighbor_cache(neighbor_cache) From 62642957cd9e36c6e87cd2ca4aabfba8c616d71b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 19 Sep 2018 11:16:21 +0800 Subject: [PATCH 1255/2457] runtime: fix DRTIO aux channel race condition --- artiq/firmware/runtime/kern_hwreq.rs | 186 ++++++++++++++------------- artiq/firmware/runtime/main.rs | 9 +- artiq/firmware/runtime/moninj.rs | 66 ++++------ artiq/firmware/runtime/rtio_mgt.rs | 127 ++++++++++-------- artiq/firmware/runtime/sched.rs | 2 +- artiq/firmware/runtime/session.rs | 26 ++-- 6 files changed, 215 insertions(+), 201 deletions(-) diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index 631209923..aa4d21bcf 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -1,6 +1,6 @@ use core::cell::RefCell; use kernel_proto as kern; -use sched::{Io, Error as SchedError}; +use sched::{Io, Mutex, Error as SchedError}; use session::{kern_acknowledge, kern_send, Error}; use rtio_mgt; use urc::Urc; @@ -11,14 +11,20 @@ use board_artiq::spi as local_spi; #[cfg(has_drtio)] mod remote_i2c { use drtioaux; + use rtio_mgt::drtio; + use sched::{Io, Mutex}; - fn basic_reply(linkno: u8) -> Result<(), ()> { - match drtioaux::recv_timeout(linkno, None) { + pub fn start(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cStartRequest { + destination: destination, + busno: busno + }); + match reply { Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } - Ok(_) => { - error!("received unexpected aux packet"); + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); Err(()) } Err(e) => { @@ -28,49 +34,53 @@ mod remote_i2c { } } - pub fn start(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cStartRequest { + pub fn restart(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cRestartRequest { destination: destination, busno: busno - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) + }); + match reply { + Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => { + if succeeded { Ok(()) } else { Err(()) } + } + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); + Err(()) + } + Err(e) => { + error!("aux packet error ({})", e); + Err(()) + } } - basic_reply(linkno) } - pub fn restart(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cRestartRequest { + pub fn stop(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cStopRequest { destination: destination, busno: busno - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) + }); + match reply { + Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => { + if succeeded { Ok(()) } else { Err(()) } + } + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); + Err(()) + } + Err(e) => { + error!("aux packet error ({})", e); + Err(()) + } } - basic_reply(linkno) } - pub fn stop(linkno: u8, destination: u8, busno: u8) -> Result<(), ()> { - let request = drtioaux::Packet::I2cStopRequest { - destination: destination, - busno: busno - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) - } - basic_reply(linkno) - } - - pub fn write(linkno: u8, destination: u8, busno: u8, data: u8) -> Result { - let request = drtioaux::Packet::I2cWriteRequest { + pub fn write(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, data: u8) -> Result { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cWriteRequest { destination: destination, busno: busno, data: data - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) - } - match drtioaux::recv_timeout(linkno, None) { + }); + match reply { Ok(drtioaux::Packet::I2cWriteReply { succeeded, ack }) => { if succeeded { Ok(ack) } else { Err(()) } } @@ -85,16 +95,13 @@ mod remote_i2c { } } - pub fn read(linkno: u8, destination: u8, busno: u8, ack: bool) -> Result { - let request = drtioaux::Packet::I2cReadRequest { + pub fn read(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, ack: bool) -> Result { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::I2cReadRequest { destination: destination, busno: busno, ack: ack - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) - } - match drtioaux::recv_timeout(linkno, None) { + }); + match reply { Ok(drtioaux::Packet::I2cReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } @@ -113,14 +120,24 @@ mod remote_i2c { #[cfg(has_drtio)] mod remote_spi { use drtioaux; + use rtio_mgt::drtio; + use sched::{Io, Mutex}; - fn basic_reply(linkno: u8) -> Result<(), ()> { - match drtioaux::recv_timeout(linkno, None) { + pub fn set_config(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::SpiSetConfigRequest { + destination: destination, + busno: busno, + flags: flags, + length: length, + div: div, + cs: cs + }); + match reply { Ok(drtioaux::Packet::SpiBasicReply { succeeded }) => { if succeeded { Ok(()) } else { Err(()) } } - Ok(_) => { - error!("received unexpected aux packet"); + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); Err(()) } Err(e) => { @@ -130,47 +147,38 @@ mod remote_spi { } } - pub fn set_config(linkno: u8, destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8) -> Result<(), ()> { - let request = drtioaux::Packet::SpiSetConfigRequest { - destination: destination, - busno: busno, - flags: flags, - length: length, - div: div, - cs: cs - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) - } - basic_reply(linkno) - } - - pub fn write(linkno: u8, destination: u8, busno: u8, data: u32) -> Result<(), ()> { - let request = drtioaux::Packet::SpiWriteRequest { + pub fn write(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8, data: u32) -> Result<(), ()> { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::SpiWriteRequest { destination: destination, busno: busno, data: data - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) + }); + match reply { + Ok(drtioaux::Packet::SpiBasicReply { succeeded }) => { + if succeeded { Ok(()) } else { Err(()) } + } + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); + Err(()) + } + Err(e) => { + error!("aux packet error ({})", e); + Err(()) + } } - basic_reply(linkno) } - pub fn read(linkno: u8, destination: u8, busno: u8) -> Result { - let request = drtioaux::Packet::SpiReadRequest { + pub fn read(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, busno: u8) -> Result { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::SpiReadRequest { destination: destination, busno: busno - }; - if drtioaux::send(linkno, &request).is_err() { - return Err(()) - } - match drtioaux::recv_timeout(linkno, None) { + }); + match reply { Ok(drtioaux::Packet::SpiReadReply { succeeded, data }) => { if succeeded { Ok(data) } else { Err(()) } } - Ok(_) => { - error!("received unexpected aux packet"); + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); Err(()) } Err(e) => { @@ -184,7 +192,7 @@ mod remote_spi { #[cfg(has_drtio)] macro_rules! dispatch { - ($mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ + ($io:ident, $aux_mutex:ident, $mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ let destination = ($busno >> 16) as u8; let busno = $busno as u8; let hop = $routing_table.0[destination as usize][0]; @@ -192,27 +200,27 @@ macro_rules! dispatch { $mod_local::$func(busno, $($param, )*) } else { let linkno = hop - 1; - $mod_remote::$func(linkno, destination, busno, $($param, )*) + $mod_remote::$func($io, $aux_mutex, linkno, destination, busno, $($param, )*) } }} } #[cfg(not(has_drtio))] macro_rules! dispatch { - ($mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ + ($io:ident, $aux_mutex:ident,$mod_local:ident, $mod_remote:ident, $routing_table:ident, $busno:expr, $func:ident $(, $param:expr)*) => {{ let busno = $busno as u8; $mod_local::$func(busno, $($param, )*) }} } -pub fn process_kern_hwreq(io: &Io, +pub fn process_kern_hwreq(io: &Io, aux_mutex: &Mutex, _routing_table: &drtio_routing::RoutingTable, _up_destinations: &Urc>, request: &kern::Message) -> Result> { match request { &kern::RtioInitRequest => { info!("resetting RTIO"); - rtio_mgt::init_core(false); + rtio_mgt::init_core(io, aux_mutex, false); kern_acknowledge() } @@ -228,42 +236,42 @@ pub fn process_kern_hwreq(io: &Io, } &kern::I2cStartRequest { busno } => { - let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, start).is_ok(); + let succeeded = dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, start).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cRestartRequest { busno } => { - let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, restart).is_ok(); + let succeeded = dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, restart).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cStopRequest { busno } => { - let succeeded = dispatch!(local_i2c, remote_i2c, _routing_table, busno, stop).is_ok(); + let succeeded = dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, stop).is_ok(); kern_send(io, &kern::I2cBasicReply { succeeded: succeeded }) } &kern::I2cWriteRequest { busno, data } => { - match dispatch!(local_i2c, remote_i2c, _routing_table, busno, write, data) { + match dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, write, data) { Ok(ack) => kern_send(io, &kern::I2cWriteReply { succeeded: true, ack: ack }), Err(_) => kern_send(io, &kern::I2cWriteReply { succeeded: false, ack: false }) } } &kern::I2cReadRequest { busno, ack } => { - match dispatch!(local_i2c, remote_i2c, _routing_table, busno, read, ack) { + match dispatch!(io, aux_mutex, local_i2c, remote_i2c, _routing_table, busno, read, ack) { Ok(data) => kern_send(io, &kern::I2cReadReply { succeeded: true, data: data }), Err(_) => kern_send(io, &kern::I2cReadReply { succeeded: false, data: 0xff }) } } &kern::SpiSetConfigRequest { busno, flags, length, div, cs } => { - let succeeded = dispatch!(local_spi, remote_spi, _routing_table, busno, + let succeeded = dispatch!(io, aux_mutex, local_spi, remote_spi, _routing_table, busno, set_config, flags, length, div, cs).is_ok(); kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) }, &kern::SpiWriteRequest { busno, data } => { - let succeeded = dispatch!(local_spi, remote_spi, _routing_table, busno, + let succeeded = dispatch!(io, aux_mutex, local_spi, remote_spi, _routing_table, busno, write, data).is_ok(); kern_send(io, &kern::SpiBasicReply { succeeded: succeeded }) } &kern::SpiReadRequest { busno } => { - match dispatch!(local_spi, remote_spi, _routing_table, busno, read) { + match dispatch!(io, aux_mutex, local_spi, remote_spi, _routing_table, busno, read) { Ok(data) => kern_send(io, &kern::SpiReadReply { succeeded: true, data: data }), Err(_) => kern_send(io, &kern::SpiReadReply { succeeded: false, data: 0 }) } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index fe7a26d91..d79de3b83 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -289,22 +289,25 @@ fn startup_ethernet() { drtio_routing::RoutingTable::default_empty())); let up_destinations = urc::Urc::new(RefCell::new( [false; drtio_routing::DEST_COUNT])); + let aux_mutex = sched::Mutex::new(); let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); - rtio_mgt::startup(&io, &drtio_routing_table, &up_destinations); + rtio_mgt::startup(&io, &aux_mutex, &drtio_routing_table, &up_destinations); io.spawn(4096, mgmt::thread); { + let aux_mutex = aux_mutex.clone(); let drtio_routing_table = drtio_routing_table.clone(); let up_destinations = up_destinations.clone(); - io.spawn(16384, move |io| { session::thread(io, &drtio_routing_table, &up_destinations) }); + io.spawn(16384, move |io| { session::thread(io, &aux_mutex, &drtio_routing_table, &up_destinations) }); } #[cfg(any(has_rtio_moninj, has_drtio))] { + let aux_mutex = aux_mutex.clone(); let drtio_routing_table = drtio_routing_table.clone(); - io.spawn(4096, move |io| { moninj::thread(io, &drtio_routing_table) }); + io.spawn(4096, move |io| { moninj::thread(io, &aux_mutex, &drtio_routing_table) }); } #[cfg(has_rtio_analyzer)] io.spawn(4096, analyzer::thread); diff --git a/artiq/firmware/runtime/moninj.rs b/artiq/firmware/runtime/moninj.rs index 5ffaa96a0..8534376d5 100644 --- a/artiq/firmware/runtime/moninj.rs +++ b/artiq/firmware/runtime/moninj.rs @@ -3,7 +3,7 @@ use core::cell::RefCell; use io::Error as IoError; use moninj_proto::*; -use sched::{Io, TcpListener, TcpStream, Error as SchedError}; +use sched::{Io, Mutex, TcpListener, TcpStream, Error as SchedError}; use urc::Urc; use board_misoc::clock; use board_artiq::drtio_routing; @@ -50,21 +50,16 @@ mod local_moninj { #[cfg(has_drtio)] mod remote_moninj { use drtioaux; + use rtio_mgt::drtio; + use sched::{Io, Mutex}; - pub fn read_probe(linkno: u8, destination: u8, channel: u16, probe: u8) -> u32 { - let request = drtioaux::Packet::MonitorRequest { + pub fn read_probe(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, channel: u16, probe: u8) -> u32 { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::MonitorRequest { destination: destination, channel: channel, probe: probe - }; - match drtioaux::send(linkno, &request) { - Ok(_) => (), - Err(e) => { - error!("aux packet error ({})", e); - return 0; - } - } - match drtioaux::recv_timeout(linkno, None) { + }); + match reply { Ok(drtioaux::Packet::MonitorReply { value }) => return value, Ok(packet) => error!("received unexpected aux packet: {:?}", packet), Err(e) => error!("aux packet error ({})", e) @@ -72,33 +67,23 @@ mod remote_moninj { 0 } - pub fn inject(linkno: u8, destination: u8, channel: u16, overrd: u8, value: u8) { - let request = drtioaux::Packet::InjectionRequest { + pub fn inject(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, channel: u16, overrd: u8, value: u8) { + let _lock = aux_mutex.lock(io).unwrap(); + drtioaux::send(linkno, &drtioaux::Packet::InjectionRequest { destination: destination, channel: channel, overrd: overrd, value: value - }; - match drtioaux::send(linkno, &request) { - Ok(_) => (), - Err(e) => error!("aux packet error ({})", e) - } + }).unwrap(); } - pub fn read_injection_status(linkno: u8, destination: u8, channel: u16, overrd: u8) -> u8 { - let request = drtioaux::Packet::InjectionStatusRequest { + pub fn read_injection_status(io: &Io, aux_mutex: &Mutex, linkno: u8, destination: u8, channel: u16, overrd: u8) -> u8 { + let reply = drtio::aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::InjectionStatusRequest { destination: destination, channel: channel, overrd: overrd - }; - match drtioaux::send(linkno, &request) { - Ok(_) => (), - Err(e) => { - error!("aux packet error ({})", e); - return 0; - } - } - match drtioaux::recv_timeout(linkno, None) { + }); + match reply { Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value, Ok(packet) => error!("received unexpected aux packet: {:?}", packet), Err(e) => error!("aux packet error ({})", e) @@ -109,7 +94,7 @@ mod remote_moninj { #[cfg(has_drtio)] macro_rules! dispatch { - ($routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ + ($io:ident, $aux_mutex:ident, $routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ let destination = ($channel >> 16) as u8; let channel = $channel as u16; let hop = $routing_table.0[destination as usize][0]; @@ -117,20 +102,20 @@ macro_rules! dispatch { local_moninj::$func(channel, $($param, )*) } else { let linkno = hop - 1; - remote_moninj::$func(linkno, destination, channel, $($param, )*) + remote_moninj::$func($io, $aux_mutex, linkno, destination, channel, $($param, )*) } }} } #[cfg(not(has_drtio))] macro_rules! dispatch { - ($routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ + ($io:ident, $aux_mutex:ident, $routing_table:ident, $channel:expr, $func:ident $(, $param:expr)*) => {{ let channel = $channel as u16; local_moninj::$func(channel, $($param, )*) }} } -fn connection_worker(io: &Io, _routing_table: &drtio_routing::RoutingTable, +fn connection_worker(io: &Io, _aux_mutex: &Mutex, _routing_table: &drtio_routing::RoutingTable, mut stream: &mut TcpStream) -> Result<(), Error> { let mut probe_watch_list = BTreeMap::new(); let mut inject_watch_list = BTreeMap::new(); @@ -159,9 +144,9 @@ fn connection_worker(io: &Io, _routing_table: &drtio_routing::RoutingTable, let _ = inject_watch_list.remove(&(channel, overrd)); } }, - HostMessage::Inject { channel, overrd, value } => dispatch!(_routing_table, channel, inject, overrd, value), + HostMessage::Inject { channel, overrd, value } => dispatch!(io, _aux_mutex, _routing_table, channel, inject, overrd, value), HostMessage::GetInjectionStatus { channel, overrd } => { - let value = dispatch!(_routing_table, channel, read_injection_status, overrd); + let value = dispatch!(io, _aux_mutex, _routing_table, channel, read_injection_status, overrd); let reply = DeviceMessage::InjectionStatus { channel: channel, overrd: overrd, @@ -178,7 +163,7 @@ fn connection_worker(io: &Io, _routing_table: &drtio_routing::RoutingTable, if clock::get_ms() > next_check { for (&(channel, probe), previous) in probe_watch_list.iter_mut() { - let current = dispatch!(_routing_table, channel, read_probe, probe); + let current = dispatch!(io, _aux_mutex, _routing_table, channel, read_probe, probe); if previous.is_none() || previous.unwrap() != current { let message = DeviceMessage::MonitorStatus { channel: channel, @@ -193,7 +178,7 @@ fn connection_worker(io: &Io, _routing_table: &drtio_routing::RoutingTable, } } for (&(channel, overrd), previous) in inject_watch_list.iter_mut() { - let current = dispatch!(_routing_table, channel, read_injection_status, overrd); + let current = dispatch!(io, _aux_mutex, _routing_table, channel, read_injection_status, overrd); if previous.is_none() || previous.unwrap() != current { let message = DeviceMessage::InjectionStatus { channel: channel, @@ -214,17 +199,18 @@ fn connection_worker(io: &Io, _routing_table: &drtio_routing::RoutingTable, } } -pub fn thread(io: Io, routing_table: &Urc>) { +pub fn thread(io: Io, aux_mutex: &Mutex, routing_table: &Urc>) { let listener = TcpListener::new(&io, 2047); listener.listen(1383).expect("moninj: cannot listen"); loop { + let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let stream = listener.accept().expect("moninj: cannot accept").into_handle(); io.spawn(16384, move |io| { let routing_table = routing_table.borrow(); let mut stream = TcpStream::from_handle(&io, stream); - match connection_worker(&io, &routing_table, &mut stream) { + match connection_worker(&io, &aux_mutex, &routing_table, &mut stream) { Ok(()) => {}, Err(err) => error!("moninj aborted: {}", err) } diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index e3688fb57..69233dd60 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -7,6 +7,7 @@ use board_misoc::clock; use board_misoc::config; use board_artiq::drtio_routing; use sched::Io; +use sched::Mutex; #[cfg(has_rtio_crg)] pub mod crg { @@ -47,16 +48,18 @@ pub mod drtio { use super::*; use drtioaux; - pub fn startup(io: &Io, routing_table: &Urc>, + pub fn startup(io: &Io, aux_mutex: &Mutex, + routing_table: &Urc>, up_destinations: &Urc>) { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } + let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); io.spawn(4096, move |io| { let routing_table = routing_table.borrow(); - link_thread(io, &routing_table, &up_destinations); + link_thread(io, &aux_mutex, &routing_table, &up_destinations); }); } @@ -87,26 +90,6 @@ pub mod drtio { } } - fn ping_remote(linkno: u8, io: &Io) -> u32 { - let mut count = 0; - loop { - if !link_rx_up(linkno) { - return 0 - } - count += 1; - if count > 200 { - return 0; - } - drtioaux::send(linkno, &drtioaux::Packet::EchoRequest).unwrap(); - io.sleep(100).unwrap(); - let pr = drtioaux::recv(linkno); - match pr { - Ok(Some(drtioaux::Packet::EchoReply)) => return count, - _ => {} - } - } - } - fn recv_aux_timeout(io: &Io, linkno: u8, timeout: u32) -> Result { let max_time = clock::get_ms() + timeout as u64; loop { @@ -125,7 +108,35 @@ pub mod drtio { } } - fn sync_tsc(io: &Io, linkno: u8) -> Result<(), &'static str> { + pub fn aux_transact(io: &Io, aux_mutex: &Mutex, + linkno: u8, request: &drtioaux::Packet) -> Result { + let _lock = aux_mutex.lock(io).unwrap(); + drtioaux::send(linkno, request).unwrap(); + recv_aux_timeout(io, linkno, 200) + } + + fn ping_remote(io: &Io, aux_mutex: &Mutex, linkno: u8) -> u32 { + let mut count = 0; + loop { + if !link_rx_up(linkno) { + return 0 + } + count += 1; + if count > 100 { + return 0; + } + let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::EchoRequest); + match reply { + Ok(drtioaux::Packet::EchoReply) => return count, + _ => {} + } + io.relinquish().unwrap(); + } + } + + fn sync_tsc(io: &Io, aux_mutex: &Mutex, linkno: u8) -> Result<(), &'static str> { + let _lock = aux_mutex.lock(io).unwrap(); + unsafe { (csr::DRTIO[linkno as usize].set_time_write)(1); while (csr::DRTIO[linkno as usize].set_time_read)() == 1 {} @@ -140,14 +151,13 @@ pub mod drtio { } } - fn load_routing_table(io: &Io, linkno: u8, routing_table: &drtio_routing::RoutingTable) + fn load_routing_table(io: &Io, aux_mutex: &Mutex, linkno: u8, routing_table: &drtio_routing::RoutingTable) -> Result<(), &'static str> { for i in 0..drtio_routing::DEST_COUNT { - drtioaux::send(linkno, &drtioaux::Packet::RoutingSetPath { + let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::RoutingSetPath { destination: i as u8, hops: routing_table.0[i] - }).unwrap(); - let reply = recv_aux_timeout(io, linkno, 200)?; + })?; if reply != drtioaux::Packet::RoutingAck { return Err("unexpected reply"); } @@ -155,11 +165,10 @@ pub mod drtio { Ok(()) } - fn set_rank(io: &Io, linkno: u8, rank: u8) -> Result<(), &'static str> { - drtioaux::send(linkno, &drtioaux::Packet::RoutingSetRank { + fn set_rank(io: &Io, aux_mutex: &Mutex, linkno: u8, rank: u8) -> Result<(), &'static str> { + let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::RoutingSetRank { rank: rank - }).unwrap(); - let reply = recv_aux_timeout(io, linkno, 200)?; + })?; if reply != drtioaux::Packet::RoutingAck { return Err("unexpected reply"); } @@ -179,7 +188,8 @@ pub mod drtio { } } - fn process_unsolicited_aux(linkno: u8) { + fn process_unsolicited_aux(io: &Io, aux_mutex: &Mutex, linkno: u8) { + let _lock = aux_mutex.lock(io).unwrap(); match drtioaux::recv(linkno) { Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet), Ok(None) => (), @@ -227,7 +237,7 @@ pub mod drtio { up_destinations[destination as usize] } - fn destination_survey(io: &Io, routing_table: &drtio_routing::RoutingTable, + fn destination_survey(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>) { for destination in 0..drtio_routing::DEST_COUNT { let hop = routing_table.0[destination][0]; @@ -242,10 +252,10 @@ pub mod drtio { let linkno = hop - 1; if destination_up(up_destinations, destination) { if link_up(linkno) { - drtioaux::send(linkno, &drtioaux::Packet::DestinationStatusRequest { + let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::DestinationStatusRequest { destination: destination - }).unwrap(); - match recv_aux_timeout(io, linkno, 200) { + }); + match reply { Ok(drtioaux::Packet::DestinationDownReply) => destination_set_up(routing_table, up_destinations, destination, false), Ok(drtioaux::Packet::DestinationOkReply) => (), @@ -263,10 +273,10 @@ pub mod drtio { } } else { if link_up(linkno) { - drtioaux::send(linkno, &drtioaux::Packet::DestinationStatusRequest { + let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::DestinationStatusRequest { destination: destination - }).unwrap(); - match recv_aux_timeout(io, linkno, 200) { + }); + match reply { Ok(drtioaux::Packet::DestinationDownReply) => (), Ok(drtioaux::Packet::DestinationOkReply) => { destination_set_up(routing_table, up_destinations, destination, true); @@ -281,7 +291,8 @@ pub mod drtio { } } - pub fn link_thread(io: Io, routing_table: &drtio_routing::RoutingTable, + pub fn link_thread(io: Io, aux_mutex: &Mutex, + routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>) { loop { for linkno in 0..csr::DRTIO.len() { @@ -289,7 +300,7 @@ pub mod drtio { if link_up(linkno) { /* link was previously up */ if link_rx_up(linkno) { - process_unsolicited_aux(linkno); + process_unsolicited_aux(&io, aux_mutex, linkno); process_local_errors(linkno); } else { info!("[LINK#{}] link is down", linkno); @@ -299,17 +310,17 @@ pub mod drtio { /* link was previously down */ if link_rx_up(linkno) { info!("[LINK#{}] link RX became up, pinging", linkno); - let ping_count = ping_remote(linkno, &io); + let ping_count = ping_remote(&io, aux_mutex, linkno); if ping_count > 0 { info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); set_link_up(linkno, true); - if let Err(e) = sync_tsc(&io, linkno) { + if let Err(e) = sync_tsc(&io, aux_mutex, linkno) { error!("[LINK#{}] failed to sync TSC ({})", linkno, e); } - if let Err(e) = load_routing_table(&io, linkno, routing_table) { + if let Err(e) = load_routing_table(&io, aux_mutex, linkno, routing_table) { error!("[LINK#{}] failed to load routing table ({})", linkno, e); } - if let Err(e) = set_rank(&io, linkno, 1) { + if let Err(e) = set_rank(&io, aux_mutex, linkno, 1) { error!("[LINK#{}] failed to set rank ({})", linkno, e); } info!("[LINK#{}] link initialization completed", linkno); @@ -319,18 +330,18 @@ pub mod drtio { } } } - destination_survey(&io, routing_table, up_destinations); + destination_survey(&io, aux_mutex, routing_table, up_destinations); io.sleep(200).unwrap(); } } - pub fn init() { + pub fn init(io: &Io, aux_mutex: &Mutex) { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; if link_up(linkno) { - drtioaux::send(linkno, - &drtioaux::Packet::ResetRequest { phy: false }).unwrap(); - match drtioaux::recv_timeout(linkno, None) { + let reply = aux_transact(io, aux_mutex, linkno, + &drtioaux::Packet::ResetRequest { phy: false }); + match reply { Ok(drtioaux::Packet::ResetAck) => (), Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno), Err(e) => error!("[LINK#{}] reset failed, aux packet error ({})", linkno, e) @@ -344,9 +355,10 @@ pub mod drtio { pub mod drtio { use super::*; - pub fn startup(_io: &Io, _routing_table: &Urc>, + pub fn startup(_io: &Io, _aux_mutex: &Mutex, + _routing_table: &Urc>, _up_destinations: &Urc>) {} - pub fn init() {} + pub fn init(_io: &Io, _aux_mutex: &Mutex) {} pub fn link_up(_linkno: u8) -> bool { false } } @@ -372,7 +384,8 @@ fn async_error_thread(io: Io) { } } -pub fn startup(io: &Io, routing_table: &Urc>, +pub fn startup(io: &Io, aux_mutex: &Mutex, + routing_table: &Urc>, up_destinations: &Urc>) { #[cfg(has_rtio_crg)] { @@ -413,17 +426,17 @@ pub fn startup(io: &Io, routing_table: &Urc } } - drtio::startup(io, routing_table, up_destinations); - init_core(true); + drtio::startup(io, aux_mutex, routing_table, up_destinations); + init_core(io, aux_mutex, true); io.spawn(4096, async_error_thread); } -pub fn init_core(phy: bool) { +pub fn init_core(io: &Io, aux_mutex: &Mutex, phy: bool) { unsafe { csr::rtio_core::reset_write(1); if phy { csr::rtio_core::reset_phy_write(1); } } - drtio::init() + drtio::init(io, aux_mutex) } diff --git a/artiq/firmware/runtime/sched.rs b/artiq/firmware/runtime/sched.rs index 770ac3f6c..7a2a85723 100644 --- a/artiq/firmware/runtime/sched.rs +++ b/artiq/firmware/runtime/sched.rs @@ -273,7 +273,7 @@ impl Mutex { Mutex(Urc::new(Cell::new(false))) } - pub fn lock<'a>(&'a self, io: Io) -> Result, Error> { + pub fn lock<'a>(&'a self, io: &Io) -> Result, Error> { io.until(|| !self.0.get())?; self.0.set(true); Ok(MutexGuard(&*self.0)) diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index e413e8749..ae23c3410 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -6,7 +6,7 @@ use io::{Read, Write, Error as IoError}; use board_misoc::{ident, cache, config}; use {mailbox, rpc_queue, kernel}; use urc::Urc; -use sched::{ThreadHandle, Io, TcpListener, TcpStream, Error as SchedError}; +use sched::{ThreadHandle, Io, Mutex, TcpListener, TcpStream, Error as SchedError}; use rtio_mgt; use rtio_dma::Manager as DmaManager; use cache::Cache; @@ -324,7 +324,7 @@ fn process_host_message(io: &Io, Ok(()) } -fn process_kern_message(io: &Io, +fn process_kern_message(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>, mut stream: Option<&mut TcpStream>, @@ -345,7 +345,7 @@ fn process_kern_message(io: &Io, kern_recv_dotrace(request); - if kern_hwreq::process_kern_hwreq(io, routing_table, up_destinations, request)? { + if kern_hwreq::process_kern_hwreq(io, aux_mutex, routing_table, up_destinations, request)? { return Ok(false) } @@ -494,7 +494,7 @@ fn process_kern_queued_rpc(stream: &mut TcpStream, }) } -fn host_kernel_worker(io: &Io, +fn host_kernel_worker(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>, stream: &mut TcpStream, @@ -513,7 +513,7 @@ fn host_kernel_worker(io: &Io, } if mailbox::receive() != 0 { - process_kern_message(io, + process_kern_message(io, aux_mutex, routing_table, up_destinations, Some(stream), &mut session)?; } @@ -534,7 +534,7 @@ fn host_kernel_worker(io: &Io, } } -fn flash_kernel_worker(io: &Io, +fn flash_kernel_worker(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>, congress: &mut Congress, @@ -559,7 +559,7 @@ fn flash_kernel_worker(io: &Io, } if mailbox::receive() != 0 { - if process_kern_message(io, routing_table, up_destinations, None, &mut session)? { + if process_kern_message(io, aux_mutex, routing_table, up_destinations, None, &mut session)? { return Ok(()) } } @@ -591,7 +591,8 @@ fn respawn(io: &Io, handle: &mut Option, f: F) *handle = Some(io.spawn(16384, f)) } -pub fn thread(io: Io, routing_table: &Urc>, +pub fn thread(io: Io, aux_mutex: &Mutex, + routing_table: &Urc>, up_destinations: &Urc>) { let listener = TcpListener::new(&io, 65535); listener.listen(1381).expect("session: cannot listen"); @@ -601,6 +602,7 @@ pub fn thread(io: Io, routing_table: &Urc>, let mut kernel_thread = None; { + let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); let congress = congress.clone(); @@ -608,7 +610,7 @@ pub fn thread(io: Io, routing_table: &Urc>, let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); info!("running startup kernel"); - match flash_kernel_worker(&io, &routing_table, &up_destinations, &mut congress, "startup_kernel") { + match flash_kernel_worker(&io, &aux_mutex, &routing_table, &up_destinations, &mut congress, "startup_kernel") { Ok(()) => info!("startup kernel finished"), Err(Error::KernelNotFound) => @@ -637,6 +639,7 @@ pub fn thread(io: Io, routing_table: &Urc>, } info!("new connection from {}", stream.remote_endpoint()); + let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); let congress = congress.clone(); @@ -645,7 +648,7 @@ pub fn thread(io: Io, routing_table: &Urc>, let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); let mut stream = TcpStream::from_handle(&io, stream); - match host_kernel_worker(&io, &routing_table, &up_destinations, &mut stream, &mut *congress) { + match host_kernel_worker(&io, &aux_mutex, &routing_table, &up_destinations, &mut stream, &mut *congress) { Ok(()) => (), Err(Error::Protocol(host::Error::Io(IoError::UnexpectedEnd))) => info!("connection closed"), @@ -663,13 +666,14 @@ pub fn thread(io: Io, routing_table: &Urc>, if kernel_thread.as_ref().map_or(true, |h| h.terminated()) { info!("no connection, starting idle kernel"); + let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); let congress = congress.clone(); respawn(&io, &mut kernel_thread, move |io| { let routing_table = routing_table.borrow(); let mut congress = congress.borrow_mut(); - match flash_kernel_worker(&io, &routing_table, &up_destinations, &mut *congress, "idle_kernel") { + match flash_kernel_worker(&io, &aux_mutex, &routing_table, &up_destinations, &mut *congress, "idle_kernel") { Ok(()) => info!("idle kernel finished, standing by"), Err(Error::Protocol(host::Error::Io( From 142c952e3d24fba16c48df7c2e58ab78a5baf3c6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 19 Sep 2018 17:03:15 +0800 Subject: [PATCH 1256/2457] drtio: implement per-destination underflow margins --- .../firmware/libboard_artiq/drtio_routing.rs | 12 ++++++++++ artiq/firmware/runtime/rtio_mgt.rs | 23 +++++++++++++++++++ artiq/gateware/drtio/rt_controller_master.py | 16 +++++++++++-- artiq/gateware/test/drtio/test_full_stack.py | 3 +-- artiq/gateware/test/drtio/test_switching.py | 1 - 5 files changed, 50 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index 562517342..6c8469ae2 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -30,6 +30,18 @@ impl RoutingTable { pub fn default_empty() -> RoutingTable { RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]) } + + pub fn hop_count(&self, destination: u8) -> u8 { + let mut count = 0; + for i in 0..MAX_HOPS { + if self.0[destination as usize][i] == INVALID_HOP { + break; + } else { + count += 1; + } + } + count + } } impl fmt::Display for RoutingTable { diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 69233dd60..95b43c586 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -54,6 +54,12 @@ pub mod drtio { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } + + { + let routing_table = routing_table.borrow(); + program_underflow_margins(&routing_table); + } + let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); @@ -63,6 +69,23 @@ pub mod drtio { }); } + fn program_underflow_margins(routing_table: &drtio_routing::RoutingTable) { + for destination in 0..drtio_routing::DEST_COUNT { + let hop_count = routing_table.hop_count(destination as u8); + if hop_count > 1 { + let underflow_margin = (hop_count as u16 - 1)*300; + info!("[DEST#{}] setting underflow margin to {}", destination, underflow_margin); + let linkno = (routing_table.0[destination][0] - 1) as usize; + unsafe { + (csr::DRTIO[linkno].destination_write)(destination as u8); + (csr::DRTIO[linkno].force_destination_write)(1); + (csr::DRTIO[linkno].set_underflow_margin_write)(underflow_margin); + (csr::DRTIO[linkno].force_destination_write)(0); + } + } + } + } + fn link_rx_up(linkno: u8) -> bool { let linkno = linkno as usize; unsafe { diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 40014dce0..3209f1739 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -17,11 +17,13 @@ class _CSRs(AutoCSR): self.protocol_error = CSR(3) self.set_time = CSR() - self.underflow_margin = CSRStorage(16, reset=300) self.force_destination = CSRStorage() self.destination = CSRStorage(8) + self.set_underflow_margin = CSRStorage(16) + self.dbg_underflow_margin = CSRStatus(16) + self.o_get_buffer_space = CSR() self.o_dbg_buffer_space = CSRStatus(16) self.o_dbg_buffer_space_req_cnt = CSRStatus(32) @@ -116,9 +118,19 @@ class RTController(Module): timeout_counter = WaitTimer(8191) self.submodules += timeout_counter + underflow_margin = Memory(16, 256, init=[100]*256) + underflow_margin_port = underflow_margin.get_port(write_capable=True) + self.specials += underflow_margin, underflow_margin_port + self.comb += [ + underflow_margin_port.adr.eq(chan_sel[16:]), + underflow_margin_port.dat_w.eq(self.csrs.set_underflow_margin.storage), + underflow_margin_port.we.eq(self.csrs.set_underflow_margin.re), + self.csrs.dbg_underflow_margin.status.eq(underflow_margin_port.dat_r) + ] + cond_underflow = Signal() self.comb += cond_underflow.eq((self.cri.timestamp[tsc.glbl_fine_ts_width:] - - self.csrs.underflow_margin.storage[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) + - underflow_margin_port.dat_r[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) # buffer space buffer_space = Memory(16, 256) diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 579d78f9b..a4e239b99 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -89,7 +89,6 @@ class OutputsTestbench: self.now = 0 def init(self): - yield from self.dut.master.rt_controller.csrs.underflow_margin.write(100) while not (yield from self.dut.master.link_layer.rx_up.read()): yield yield from self.get_buffer_space() @@ -228,7 +227,7 @@ class TestFullStack(unittest.TestCase): yield from tb.init() errors = yield from saterr.protocol_error.read() self.assertEqual(errors, 0) - yield from csrs.underflow_margin.write(0) + yield from csrs.set_underflow_margin.write(0) tb.delay(100) yield from tb.write(42, 1) for i in range(12): diff --git a/artiq/gateware/test/drtio/test_switching.py b/artiq/gateware/test/drtio/test_switching.py index 66a9c9e69..589115abe 100644 --- a/artiq/gateware/test/drtio/test_switching.py +++ b/artiq/gateware/test/drtio/test_switching.py @@ -70,7 +70,6 @@ class Testbench: self.now = 0 def init(self): - yield from self.dut.master.rt_controller.csrs.underflow_margin.write(100) while not (yield from self.dut.master.link_layer.rx_up.read()): yield yield from self.get_buffer_space() From 3d965910f7e326467c84bc35d5ab68b7b5250025 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 19 Sep 2018 17:05:48 +0800 Subject: [PATCH 1257/2457] Revert "drtio: implement per-destination underflow margins" This reverts commit 142c952e3d24fba16c48df7c2e58ab78a5baf3c6. --- .../firmware/libboard_artiq/drtio_routing.rs | 12 ---------- artiq/firmware/runtime/rtio_mgt.rs | 23 ------------------- artiq/gateware/drtio/rt_controller_master.py | 16 ++----------- artiq/gateware/test/drtio/test_full_stack.py | 3 ++- artiq/gateware/test/drtio/test_switching.py | 1 + 5 files changed, 5 insertions(+), 50 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index 6c8469ae2..562517342 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -30,18 +30,6 @@ impl RoutingTable { pub fn default_empty() -> RoutingTable { RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]) } - - pub fn hop_count(&self, destination: u8) -> u8 { - let mut count = 0; - for i in 0..MAX_HOPS { - if self.0[destination as usize][i] == INVALID_HOP { - break; - } else { - count += 1; - } - } - count - } } impl fmt::Display for RoutingTable { diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 95b43c586..69233dd60 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -54,12 +54,6 @@ pub mod drtio { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } - - { - let routing_table = routing_table.borrow(); - program_underflow_margins(&routing_table); - } - let aux_mutex = aux_mutex.clone(); let routing_table = routing_table.clone(); let up_destinations = up_destinations.clone(); @@ -69,23 +63,6 @@ pub mod drtio { }); } - fn program_underflow_margins(routing_table: &drtio_routing::RoutingTable) { - for destination in 0..drtio_routing::DEST_COUNT { - let hop_count = routing_table.hop_count(destination as u8); - if hop_count > 1 { - let underflow_margin = (hop_count as u16 - 1)*300; - info!("[DEST#{}] setting underflow margin to {}", destination, underflow_margin); - let linkno = (routing_table.0[destination][0] - 1) as usize; - unsafe { - (csr::DRTIO[linkno].destination_write)(destination as u8); - (csr::DRTIO[linkno].force_destination_write)(1); - (csr::DRTIO[linkno].set_underflow_margin_write)(underflow_margin); - (csr::DRTIO[linkno].force_destination_write)(0); - } - } - } - } - fn link_rx_up(linkno: u8) -> bool { let linkno = linkno as usize; unsafe { diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 3209f1739..40014dce0 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -17,13 +17,11 @@ class _CSRs(AutoCSR): self.protocol_error = CSR(3) self.set_time = CSR() + self.underflow_margin = CSRStorage(16, reset=300) self.force_destination = CSRStorage() self.destination = CSRStorage(8) - self.set_underflow_margin = CSRStorage(16) - self.dbg_underflow_margin = CSRStatus(16) - self.o_get_buffer_space = CSR() self.o_dbg_buffer_space = CSRStatus(16) self.o_dbg_buffer_space_req_cnt = CSRStatus(32) @@ -118,19 +116,9 @@ class RTController(Module): timeout_counter = WaitTimer(8191) self.submodules += timeout_counter - underflow_margin = Memory(16, 256, init=[100]*256) - underflow_margin_port = underflow_margin.get_port(write_capable=True) - self.specials += underflow_margin, underflow_margin_port - self.comb += [ - underflow_margin_port.adr.eq(chan_sel[16:]), - underflow_margin_port.dat_w.eq(self.csrs.set_underflow_margin.storage), - underflow_margin_port.we.eq(self.csrs.set_underflow_margin.re), - self.csrs.dbg_underflow_margin.status.eq(underflow_margin_port.dat_r) - ] - cond_underflow = Signal() self.comb += cond_underflow.eq((self.cri.timestamp[tsc.glbl_fine_ts_width:] - - underflow_margin_port.dat_r[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) + - self.csrs.underflow_margin.storage[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) # buffer space buffer_space = Memory(16, 256) diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index a4e239b99..579d78f9b 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -89,6 +89,7 @@ class OutputsTestbench: self.now = 0 def init(self): + yield from self.dut.master.rt_controller.csrs.underflow_margin.write(100) while not (yield from self.dut.master.link_layer.rx_up.read()): yield yield from self.get_buffer_space() @@ -227,7 +228,7 @@ class TestFullStack(unittest.TestCase): yield from tb.init() errors = yield from saterr.protocol_error.read() self.assertEqual(errors, 0) - yield from csrs.set_underflow_margin.write(0) + yield from csrs.underflow_margin.write(0) tb.delay(100) yield from tb.write(42, 1) for i in range(12): diff --git a/artiq/gateware/test/drtio/test_switching.py b/artiq/gateware/test/drtio/test_switching.py index 589115abe..66a9c9e69 100644 --- a/artiq/gateware/test/drtio/test_switching.py +++ b/artiq/gateware/test/drtio/test_switching.py @@ -70,6 +70,7 @@ class Testbench: self.now = 0 def init(self): + yield from self.dut.master.rt_controller.csrs.underflow_margin.write(100) while not (yield from self.dut.master.link_layer.rx_up.read()): yield yield from self.get_buffer_space() From 08be1763690ed1e8453b34e356f3f446919cada6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 19 Sep 2018 17:50:18 +0800 Subject: [PATCH 1258/2457] drtio: fix satellite i_status handling --- artiq/gateware/drtio/rt_packet_satellite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 49ea2c3d0..a045c020d 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -201,8 +201,8 @@ class RTPacketSatellite(Module): tx_fsm.act("IDLE", If(echo_req, NextState("ECHO")), If(buffer_space_req, NextState("BUFFER_SPACE")), - If(read_request_pending, - If(~self.cri.i_status[2], NextState("READ")), + If(read_request_pending & ~self.cri.i_status[2], + NextState("READ"), If(self.cri.i_status[0], NextState("READ_TIMEOUT")), If(self.cri.i_status[1], NextState("READ_OVERFLOW")) ) From b86b6dcc0965698c673cc22f1586aaa9d05b517f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 19 Sep 2018 17:50:29 +0800 Subject: [PATCH 1259/2457] drtio: add switching input test --- artiq/gateware/test/drtio/test_switching.py | 90 ++++++++++++++++++++- 1 file changed, 87 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/test/drtio/test_switching.py b/artiq/gateware/test/drtio/test_switching.py index 66a9c9e69..2d3330484 100644 --- a/artiq/gateware/test/drtio/test_switching.py +++ b/artiq/gateware/test/drtio/test_switching.py @@ -69,11 +69,12 @@ class Testbench: self.dut = DUT(2) self.now = 0 - def init(self): + def init(self, with_buffer_space=True): yield from self.dut.master.rt_controller.csrs.underflow_margin.write(100) while not (yield from self.dut.master.link_layer.rx_up.read()): yield - yield from self.get_buffer_space() + if with_buffer_space: + yield from self.get_buffer_space() def get_buffer_space(self): csrs = self.dut.master.rt_controller.csrs @@ -106,13 +107,35 @@ class Testbench: if status & 0x4: return "destination unreachable" + def read(self, channel, timeout): + mcri = self.dut.master.cri + yield mcri.chan_sel.eq(channel) + yield mcri.timestamp.eq(timeout) + yield + yield mcri.cmd.eq(cri.commands["read"]) + yield + yield mcri.cmd.eq(cri.commands["nop"]) + yield + status = yield mcri.i_status + while status & 0x4: + yield + status = yield mcri.i_status + if status & 0x1: + return "timeout" + if status & 0x2: + return "overflow" + if status & 0x8: + return "destination unreachable" + return ((yield mcri.i_timestamp), + (yield mcri.i_data)) + class TestSwitching(unittest.TestCase): clocks = {"sys": 8, "rtio": 5, "rtio_rx": 5, "rio": 5, "rio_phy": 5, "sys_with_rst": 8, "rtio_with_rst": 5} - def test_switching(self): + def test_outputs(self): tb = Testbench() def test(): @@ -163,3 +186,64 @@ class TestSwitching(unittest.TestCase): run_simulation(tb.dut, {"sys": test(), "rtio": tb.dut.pr.receive(receive), "rtio_rx": send_replies()}, self.clocks) + + + def test_inputs(self): + tb = Testbench() + + def test(): + yield from tb.init(with_buffer_space=False) + reply = yield from tb.read(19, 145) + self.assertEqual(reply, (333, 23)) + reply = yield from tb.read(20, 146) + self.assertEqual(reply, (334, 24)) + reply = yield from tb.read(10, 34) + self.assertEqual(reply, "timeout") + reply = yield from tb.read(1, 20) + self.assertEqual(reply, "overflow") + reply = yield from tb.read(21, 147) + self.assertEqual(reply, (335, 25)) + for _ in range(40): + yield + + current_request = None + + def get_request(): + nonlocal current_request + while current_request is None: + yield + r = current_request + current_request = None + return r + + def expect_read(chan_sel, timeout, reply): + packet_type, field_dict, trailer = yield from get_request() + self.assertEqual(packet_type, "read_request") + self.assertEqual(trailer, []) + self.assertEqual(field_dict["chan_sel"], chan_sel) + self.assertEqual(field_dict["timeout"], timeout) + if reply == "timeout": + yield from tb.dut.pt.send("read_reply_noevent", overflow=0) + elif reply == "overflow": + yield from tb.dut.pt.send("read_reply_noevent", overflow=1) + else: + timestamp, data = reply + yield from tb.dut.pt.send("read_reply", timestamp=timestamp, data=data) + + @passive + def send_replies(): + yield from expect_read(19, 145, (333, 23)) + yield from expect_read(20, 146, (334, 24)) + yield from expect_read(10, 34, "timeout") + yield from expect_read(1, 20, "overflow") + yield from expect_read(21, 147, (335, 25)) + unexpected = yield from get_request() + self.fail("unexpected packet: {}".format(unexpected)) + + def receive(packet_type, field_dict, trailer): + nonlocal current_request + self.assertEqual(current_request, None) + current_request = (packet_type, field_dict, trailer) + + run_simulation(tb.dut, + {"sys": test(), "rtio": tb.dut.pr.receive(receive), "rtio_rx": send_replies()}, self.clocks) From 69d060b639f6f0968b59f02cbc104e752f78d0a8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 19 Sep 2018 17:50:18 +0800 Subject: [PATCH 1260/2457] drtio: fix satellite i_status handling --- artiq/gateware/drtio/rt_packet_satellite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 02a5a98b1..8d7281bfa 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -161,8 +161,8 @@ class RTPacketSatellite(Module): tx_fsm.act("IDLE", If(echo_req, NextState("ECHO")), If(buffer_space_req, NextState("BUFFER_SPACE")), - If(read_request_pending, - If(~self.cri.i_status[2], NextState("READ")), + If(read_request_pending & ~self.cri.i_status[2], + NextState("READ"), If(self.cri.i_status[0], NextState("READ_TIMEOUT")), If(self.cri.i_status[1], NextState("READ_OVERFLOW")) ) From 251d90c3d5c44e301a588c82c0dc0527da7b4cf1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 20 Sep 2018 08:53:45 +0800 Subject: [PATCH 1261/2457] drtio: clear read request in satellite only after reply has been fully sent Otherwise, chan_sel become invalid before the end of the packet, which can cause the interconnect to invalidate i_timestamp and i_data which results in corruption of the end of the packet. --- artiq/gateware/drtio/rt_packet_satellite.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index a045c020d..557640749 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -227,16 +227,14 @@ class RTPacketSatellite(Module): tx_fsm.act("READ_OVERFLOW", tx_dp.send("read_reply_noevent", overflow=1), clear_read_request.eq(1), - If(tx_dp.packet_last, - NextState("IDLE") - ) + If(tx_dp.packet_last, NextState("IDLE")) ) tx_fsm.act("READ", tx_dp.send("read_reply", timestamp=self.cri.i_timestamp, data=self.cri.i_data), - clear_read_request.eq(1), If(tx_dp.packet_last, + clear_read_request.eq(1), NextState("IDLE") ) ) From 53a979e74d8ed11a4d6078f467e7d204246e2ac4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 20 Sep 2018 10:58:38 +0800 Subject: [PATCH 1262/2457] rtio: cleanup resets --- artiq/firmware/runtime/kern_hwreq.rs | 2 +- artiq/firmware/runtime/main.rs | 3 +- artiq/firmware/runtime/rtio_mgt.rs | 64 ++++++++----------- artiq/firmware/satman/main.rs | 1 + artiq/firmware/satman/repeater.rs | 8 +++ artiq/gateware/drtio/rt_controller_master.py | 26 ++------ .../gateware/drtio/rt_controller_repeater.py | 4 ++ artiq/gateware/drtio/rt_packet_master.py | 2 +- artiq/gateware/drtio/rt_packet_repeater.py | 13 ++-- artiq/gateware/test/drtio/test_full_stack.py | 4 +- artiq/gateware/test/drtio/test_switching.py | 4 +- 11 files changed, 61 insertions(+), 70 deletions(-) diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index aa4d21bcf..008a3e9ec 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -220,7 +220,7 @@ pub fn process_kern_hwreq(io: &Io, aux_mutex: &Mutex, match request { &kern::RtioInitRequest => { info!("resetting RTIO"); - rtio_mgt::init_core(io, aux_mutex, false); + rtio_mgt::reset(io, aux_mutex); kern_acknowledge() } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index d79de3b83..b3e2bbb94 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -1,5 +1,6 @@ #![feature(lang_items, alloc, try_from, nonzero, asm, - panic_implementation, panic_info_message)] + panic_implementation, panic_info_message, + const_slice_len)] #![no_std] extern crate eh; diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 69233dd60..cedfb8686 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -70,26 +70,6 @@ pub mod drtio { } } - pub fn link_up(linkno: u8) -> bool { - let linkno = linkno as usize; - /* This function may be called by kernels with arbitrary - * linkno values. - */ - if linkno >= csr::DRTIO.len() { - return false; - } - unsafe { - (csr::DRTIO[linkno].link_up_read)() == 1 - } - } - - fn set_link_up(linkno: u8, up: bool) { - let linkno = linkno as usize; - unsafe { - (csr::DRTIO[linkno].link_up_write)(if up { 1 } else { 0 }); - } - } - fn recv_aux_timeout(io: &Io, linkno: u8, timeout: u32) -> Result { let max_time = clock::get_ms() + timeout as u64; loop { @@ -238,6 +218,7 @@ pub mod drtio { } fn destination_survey(io: &Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, + up_links: &[bool], up_destinations: &Urc>) { for destination in 0..drtio_routing::DEST_COUNT { let hop = routing_table.0[destination][0]; @@ -251,7 +232,7 @@ pub mod drtio { } else if hop as usize <= csr::DRTIO.len() { let linkno = hop - 1; if destination_up(up_destinations, destination) { - if link_up(linkno) { + if up_links[linkno as usize] { let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::DestinationStatusRequest { destination: destination }); @@ -272,7 +253,7 @@ pub mod drtio { destination_set_up(routing_table, up_destinations, destination, false); } } else { - if link_up(linkno) { + if up_links[linkno as usize] { let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::DestinationStatusRequest { destination: destination }); @@ -294,17 +275,18 @@ pub mod drtio { pub fn link_thread(io: Io, aux_mutex: &Mutex, routing_table: &drtio_routing::RoutingTable, up_destinations: &Urc>) { + let mut up_links = [false; csr::DRTIO.len()]; loop { for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; - if link_up(linkno) { + if up_links[linkno as usize] { /* link was previously up */ if link_rx_up(linkno) { process_unsolicited_aux(&io, aux_mutex, linkno); process_local_errors(linkno); } else { info!("[LINK#{}] link is down", linkno); - set_link_up(linkno, false); + up_links[linkno as usize] = false; } } else { /* link was previously down */ @@ -313,7 +295,7 @@ pub mod drtio { let ping_count = ping_remote(&io, aux_mutex, linkno); if ping_count > 0 { info!("[LINK#{}] remote replied after {} packets", linkno, ping_count); - set_link_up(linkno, true); + up_links[linkno as usize] = true; if let Err(e) = sync_tsc(&io, aux_mutex, linkno) { error!("[LINK#{}] failed to sync TSC ({})", linkno, e); } @@ -330,15 +312,27 @@ pub mod drtio { } } } - destination_survey(&io, aux_mutex, routing_table, up_destinations); + destination_survey(&io, aux_mutex, routing_table, &up_links, up_destinations); io.sleep(200).unwrap(); } } - pub fn init(io: &Io, aux_mutex: &Mutex) { + pub fn reset(io: &Io, aux_mutex: &Mutex) { + for linkno in 0..csr::DRTIO.len() { + unsafe { + (csr::DRTIO[linkno].reset_write)(1); + } + } + io.sleep(1).unwrap(); + for linkno in 0..csr::DRTIO.len() { + unsafe { + (csr::DRTIO[linkno].reset_write)(0); + } + } + for linkno in 0..csr::DRTIO.len() { let linkno = linkno as u8; - if link_up(linkno) { + if link_rx_up(linkno) { let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::ResetRequest { phy: false }); match reply { @@ -358,8 +352,7 @@ pub mod drtio { pub fn startup(_io: &Io, _aux_mutex: &Mutex, _routing_table: &Urc>, _up_destinations: &Urc>) {} - pub fn init(_io: &Io, _aux_mutex: &Mutex) {} - pub fn link_up(_linkno: u8) -> bool { false } + pub fn reset(_io: &Io, _aux_mutex: &Mutex) {} } fn async_error_thread(io: Io) { @@ -425,18 +418,17 @@ pub fn startup(io: &Io, aux_mutex: &Mutex, } } } + unsafe { + csr::rtio_core::reset_phy_write(1); + } drtio::startup(io, aux_mutex, routing_table, up_destinations); - init_core(io, aux_mutex, true); io.spawn(4096, async_error_thread); } -pub fn init_core(io: &Io, aux_mutex: &Mutex, phy: bool) { +pub fn reset(io: &Io, aux_mutex: &Mutex) { unsafe { csr::rtio_core::reset_write(1); - if phy { - csr::rtio_core::reset_phy_write(1); - } } - drtio::init(io, aux_mutex) + drtio::reset(io, aux_mutex) } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 1e69111b2..bc12bccfd 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -82,6 +82,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], drtiosat_reset_phy(false); } else { drtiosat_reset(true); + clock::spin_us(100); drtiosat_reset(false); } for rep in _repeaters.iter() { diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index d5b04a94f..ca0531ac5 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -243,9 +243,17 @@ impl Repeater { } pub fn rtio_reset(&self, phy: bool) -> Result<(), drtioaux::Error> { + let repno = self.repno as usize; + if !phy { + unsafe { (csr::DRTIOREP[repno].reset_write)(1); } + clock::spin_us(100); + unsafe { (csr::DRTIOREP[repno].reset_write)(0); } + } + if self.state != RepeaterState::Up { return Ok(()); } + drtioaux::send(self.auxno, &drtioaux::Packet::ResetRequest { phy: phy }).unwrap(); diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 40014dce0..0126184c6 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -3,7 +3,6 @@ from migen import * from migen.genlib.cdc import MultiReg from migen.genlib.misc import WaitTimer -from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.interconnect.csr import * @@ -12,7 +11,7 @@ from artiq.gateware.rtio import cri class _CSRs(AutoCSR): def __init__(self): - self.link_up = CSRStorage() + self.reset = CSRStorage() self.protocol_error = CSR(3) @@ -33,25 +32,12 @@ class RTController(Module): self.csrs = _CSRs() self.cri = cri.Interface() - # reset - local_reset = Signal(reset=1) - self.sync += local_reset.eq(~self.csrs.link_up.storage) - local_reset.attr.add("no_retiming") - self.clock_domains.cd_sys_with_rst = ClockDomain() - self.clock_domains.cd_rtio_with_rst = ClockDomain() - self.comb += [ - self.cd_sys_with_rst.clk.eq(ClockSignal()), - self.cd_sys_with_rst.rst.eq(local_reset) - ] - self.comb += self.cd_rtio_with_rst.clk.eq(ClockSignal("rtio")) - self.specials += AsyncResetSynchronizer(self.cd_rtio_with_rst, local_reset) - # protocol errors err_unknown_packet_type = Signal() err_packet_truncated = Signal() signal_buffer_space_timeout = Signal() err_buffer_space_timeout = Signal() - self.sync.sys_with_rst += [ + self.sync += [ If(self.csrs.protocol_error.re, If(self.csrs.protocol_error.r[0], err_unknown_packet_type.eq(0)), If(self.csrs.protocol_error.r[1], err_packet_truncated.eq(0)), @@ -106,7 +92,7 @@ class RTController(Module): self.csrs.o_wait.status.eq(o_status_wait) ] o_underflow_set = Signal() - self.sync.sys_with_rst += [ + self.sync += [ If(self.cri.cmd == cri.commands["write"], o_status_underflow.eq(0) ), @@ -145,7 +131,7 @@ class RTController(Module): i_status_wait_event, i_status_overflow, i_status_wait_status)) load_read_reply = Signal() - self.sync.sys_with_rst += [ + self.sync += [ If(load_read_reply, i_status_wait_event.eq(0), i_status_overflow.eq(0), @@ -162,7 +148,7 @@ class RTController(Module): ] # FSM - fsm = ClockDomainsRenamer("sys_with_rst")(FSM()) + fsm = FSM() self.submodules += fsm fsm.act("IDLE", @@ -226,7 +212,7 @@ class RTController(Module): fsm.act("GET_READ_REPLY", i_status_wait_status.eq(1), rt_packet.read_not_ack.eq(1), - If(rt_packet.read_not, + If(self.csrs.reset.storage | rt_packet.read_not, load_read_reply.eq(1), NextState("IDLE") ) diff --git a/artiq/gateware/drtio/rt_controller_repeater.py b/artiq/gateware/drtio/rt_controller_repeater.py index b877700b1..4cd192054 100644 --- a/artiq/gateware/drtio/rt_controller_repeater.py +++ b/artiq/gateware/drtio/rt_controller_repeater.py @@ -1,4 +1,5 @@ from migen import * +from migen.genlib.cdc import MultiReg from misoc.interconnect.csr import * @@ -8,12 +9,15 @@ from artiq.gateware.drtio.cdc import CrossDomainRequest class RTController(Module, AutoCSR): def __init__(self, rt_packet): + self.reset = CSRStorage() self.set_time = CSR() self.protocol_error = CSR(4) self.command_missed_cmd = CSRStatus(2) self.command_missed_chan_sel = CSRStatus(24) self.buffer_space_timeout_dest = CSRStatus(8) + self.specials += MultiReg(self.reset.storage, rt_packet.reset, "rtio") + set_time_stb = Signal() set_time_ack = Signal() self.submodules += CrossDomainRequest("rtio", diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index 42370a09d..f91ac7667 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -84,7 +84,7 @@ class RTPacketMaster(Module): self.submodules += rx_dp # Write FIFO and extra data count - sr_fifo = ClockDomainsRenamer({"write": "sys_with_rst", "read": "rtio_with_rst"})( + sr_fifo = ClockDomainsRenamer({"write": "sys", "read": "rtio"})( AsyncFIFO(1+64+24+16+512, sr_fifo_depth)) self.submodules += sr_fifo sr_notwrite_d = Signal() diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 1cbd45750..4788283f9 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -10,6 +10,9 @@ from artiq.gateware.drtio.rt_serializer import * class RTPacketRepeater(Module): def __init__(self, tsc, link_layer): + # in rtio domain + self.reset = Signal() + # CRI target interface in rtio domain self.cri = cri.Interface() @@ -58,11 +61,11 @@ class RTPacketRepeater(Module): cb0_o_address = Signal(16) cb0_o_data = Signal(512) self.sync.rtio += [ - If(cb0_ack, + If(self.reset | cb0_ack, cb0_loaded.eq(0), cb0_cmd.eq(cri.commands["nop"]) ), - If(~cb0_loaded & (self.cri.cmd != cri.commands["nop"]), + If(~self.reset & ~cb0_loaded & (self.cri.cmd != cri.commands["nop"]), cb0_loaded.eq(1), cb0_cmd.eq(self.cri.cmd), cb0_timestamp.eq(self.cri.timestamp), @@ -85,11 +88,11 @@ class RTPacketRepeater(Module): cb_o_address = Signal(16) cb_o_data = Signal(512) self.sync.rtio += [ - If(cb_ack, + If(self.reset | cb_ack, cb_loaded.eq(0), cb_cmd.eq(cri.commands["nop"]) ), - If(~cb_loaded & cb0_loaded, + If(~self.reset & ~cb_loaded & cb0_loaded, cb_loaded.eq(1), cb_cmd.eq(cb0_cmd), cb_timestamp.eq(cb0_timestamp), @@ -277,7 +280,7 @@ class RTPacketRepeater(Module): ) tx_fsm.act("GET_READ_REPLY", rtio_read_not_ack.eq(1), - If(rtio_read_not, + If(self.reset | rtio_read_not, load_read_reply.eq(1), cb_ack.eq(1), NextState("READY") diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index 579d78f9b..e9bc6160a 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -57,7 +57,6 @@ class DUT(Module): self.transceivers.alice) self.submodules.master_ki = rtio.KernelInitiator(self.tsc_master, self.master.cri) - self.master.rt_controller.csrs.link_up.storage.reset = 1 rx_synchronizer = DummyRXSynchronizer() self.submodules.phy0 = ttl_simple.Output(self.ttl0) @@ -146,8 +145,7 @@ class OutputsTestbench: class TestFullStack(unittest.TestCase): clocks = {"sys": 8, "rtio": 5, "rtio_rx": 5, - "rio": 5, "rio_phy": 5, - "sys_with_rst": 8, "rtio_with_rst": 5} + "rio": 5, "rio_phy": 5} def test_pulses(self): tb = OutputsTestbench() diff --git a/artiq/gateware/test/drtio/test_switching.py b/artiq/gateware/test/drtio/test_switching.py index 2d3330484..eb691fcf7 100644 --- a/artiq/gateware/test/drtio/test_switching.py +++ b/artiq/gateware/test/drtio/test_switching.py @@ -43,7 +43,6 @@ class DUT(Module): self.submodules.tsc_master = rtio.TSC("async") self.submodules.master = DRTIOMaster(self.tsc_master, self.transceivers.alice) - self.master.rt_controller.csrs.link_up.storage.reset = 1 rx_synchronizer = DummyRXSynchronizer() self.submodules.tsc_satellite = rtio.TSC("sync") @@ -132,8 +131,7 @@ class Testbench: class TestSwitching(unittest.TestCase): clocks = {"sys": 8, "rtio": 5, "rtio_rx": 5, - "rio": 5, "rio_phy": 5, - "sys_with_rst": 8, "rtio_with_rst": 5} + "rio": 5, "rio_phy": 5} def test_outputs(self): tb = Testbench() From 1b7f403a4b832a312fc3ef76f23e1844753867a6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 20 Sep 2018 11:10:32 +0800 Subject: [PATCH 1263/2457] drtio: remove remote RTIO PHY resets --- artiq/firmware/libproto_artiq/drtioaux_proto.rs | 12 ++++-------- artiq/firmware/runtime/rtio_mgt.rs | 4 ++-- artiq/firmware/satman/main.rs | 15 +++++---------- artiq/firmware/satman/repeater.rs | 16 ++++++---------- 4 files changed, 17 insertions(+), 30 deletions(-) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 3d526734d..64e279614 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -18,7 +18,7 @@ impl From> for Error { pub enum Packet { EchoRequest, EchoReply, - ResetRequest { phy: bool }, + ResetRequest, ResetAck, TSCAck, @@ -62,9 +62,7 @@ impl Packet { Ok(match reader.read_u8()? { 0x00 => Packet::EchoRequest, 0x01 => Packet::EchoReply, - 0x02 => Packet::ResetRequest { - phy: reader.read_bool()? - }, + 0x02 => Packet::ResetRequest, 0x03 => Packet::ResetAck, 0x04 => Packet::TSCAck, @@ -192,10 +190,8 @@ impl Packet { writer.write_u8(0x00)?, Packet::EchoReply => writer.write_u8(0x01)?, - Packet::ResetRequest { phy } => { - writer.write_u8(0x02)?; - writer.write_bool(phy)?; - }, + Packet::ResetRequest => + writer.write_u8(0x02)?, Packet::ResetAck => writer.write_u8(0x03)?, Packet::TSCAck => diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index cedfb8686..726edc886 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -334,7 +334,7 @@ pub mod drtio { let linkno = linkno as u8; if link_rx_up(linkno) { let reply = aux_transact(io, aux_mutex, linkno, - &drtioaux::Packet::ResetRequest { phy: false }); + &drtioaux::Packet::ResetRequest); match reply { Ok(drtioaux::Packet::ResetAck) => (), Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno), @@ -419,7 +419,7 @@ pub fn startup(io: &Io, aux_mutex: &Mutex, } } unsafe { - csr::rtio_core::reset_phy_write(1); + csr::rtio_core::reset_phy_write(1); } drtio::startup(io, aux_mutex, routing_table, up_destinations); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index bc12bccfd..22fb5cd75 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -75,18 +75,13 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], match packet { drtioaux::Packet::EchoRequest => drtioaux::send(0, &drtioaux::Packet::EchoReply), - drtioaux::Packet::ResetRequest { phy } => { + drtioaux::Packet::ResetRequest => { info!("resetting RTIO"); - if phy { - drtiosat_reset_phy(true); - drtiosat_reset_phy(false); - } else { - drtiosat_reset(true); - clock::spin_us(100); - drtiosat_reset(false); - } + drtiosat_reset(true); + clock::spin_us(100); + drtiosat_reset(false); for rep in _repeaters.iter() { - if let Err(e) = rep.rtio_reset(phy) { + if let Err(e) = rep.rtio_reset() { error!("failed to issue RTIO reset ({})", e); } } diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index ca0531ac5..f51d413aa 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -242,21 +242,17 @@ impl Repeater { Ok(()) } - pub fn rtio_reset(&self, phy: bool) -> Result<(), drtioaux::Error> { + pub fn rtio_reset(&self) -> Result<(), drtioaux::Error> { let repno = self.repno as usize; - if !phy { - unsafe { (csr::DRTIOREP[repno].reset_write)(1); } - clock::spin_us(100); - unsafe { (csr::DRTIOREP[repno].reset_write)(0); } - } + unsafe { (csr::DRTIOREP[repno].reset_write)(1); } + clock::spin_us(100); + unsafe { (csr::DRTIOREP[repno].reset_write)(0); } if self.state != RepeaterState::Up { return Ok(()); } - drtioaux::send(self.auxno, &drtioaux::Packet::ResetRequest { - phy: phy - }).unwrap(); + drtioaux::send(self.auxno, &drtioaux::Packet::ResetRequest).unwrap(); let reply = self.recv_aux_timeout(200)?; if reply != drtioaux::Packet::ResetAck { return Err(drtioaux::Error::UnexpectedReply); @@ -278,5 +274,5 @@ impl Repeater { pub fn sync_tsc(&self) -> Result<(), drtioaux::Error> { Ok(()) } - pub fn rtio_reset(&self, _phy: bool) -> Result<(), drtioaux::Error> { Ok(()) } + pub fn rtio_reset(&self) -> Result<(), drtioaux::Error> { Ok(()) } } From 73f0de7c79a34e07235de861663e4e6960a1c034 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 20 Sep 2018 11:15:45 +0800 Subject: [PATCH 1264/2457] sayma: DRTIO master fixes --- artiq/gateware/targets/sayma_amc.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 0c731002a..499cd55ca 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -314,6 +314,7 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): coreaux.bus) self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None + self.config["HAS_DRTIO_ROUTING"] = None self.add_csr_group("drtio", drtio_csr_group) self.add_csr_group("drtioaux", drtioaux_csr_group) self.add_memory_group("drtioaux_mem", drtioaux_memory_group) @@ -379,8 +380,11 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.register_kernel_cpu_csrdevice("rtio_dma") self.submodules.cri_con = rtio.CRIInterconnectShared( [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri] + drtio_cri) + [self.rtio_core.cri] + drtio_cri, + enable_routing=True) self.register_kernel_cpu_csrdevice("cri_con") + self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) + self.csr_devices.append("routing_table") self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( self.rtio_tsc.coarse_ts, self.ad9154_crg.jref) @@ -469,6 +473,7 @@ class Master(MiniSoC, AMPSoC): coreaux.bus) self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) self.config["HAS_DRTIO"] = None + self.config["HAS_DRTIO_ROUTING"] = None self.add_csr_group("drtio", drtio_csr_group) self.add_csr_group("drtioaux", drtioaux_csr_group) self.add_memory_group("drtioaux_mem", drtioaux_memory_group) @@ -532,8 +537,11 @@ class Master(MiniSoC, AMPSoC): self.register_kernel_cpu_csrdevice("rtio_dma") self.submodules.cri_con = rtio.CRIInterconnectShared( [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri] + drtio_cri) + [self.rtio_core.cri] + drtio_cri, + enable_routing=True) self.register_kernel_cpu_csrdevice("cri_con") + self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) + self.csr_devices.append("routing_table") class Satellite(BaseSoC, RTMCommon): From 20cddb6a2505ec943592abd515f7373e53331396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 24 Sep 2018 09:19:28 +0000 Subject: [PATCH 1265/2457] tester: handle no available ttl outputs --- artiq/examples/kasli_basic/repository/kasli_tester.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index 2c00b1620..475925db2 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -156,7 +156,9 @@ class KasliTester(EnvExperiment): def test_ttl_ins(self): print("*** Testing TTL inputs.") - + if not self.ttl_outs: + print("No TTL output channel available to use as stimulus.") + return ttl_out_name, ttl_out_dev = next(iter(self.ttl_outs)) for ttl_in_name, ttl_in_dev in self.ttl_ins: print("Connect {} to {}. Press ENTER when done." From 212892d92f4fcb1c46823f86e1ed3401e73b7f89 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 26 Sep 2018 10:13:33 +0800 Subject: [PATCH 1266/2457] style --- artiq/gateware/targets/kasli.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 9c37c2220..cbe9645cc 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -27,8 +27,8 @@ from artiq.build_soc import * class _RTIOCRG(Module, AutoCSR): def __init__(self, platform): - self._pll_reset = CSRStorage(reset=1) - self._pll_locked = CSRStatus() + self.pll_reset = CSRStorage(reset=1) + self.pll_locked = CSRStatus() self.clock_domains.cd_rtio = ClockDomain() self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) @@ -60,7 +60,7 @@ class _RTIOCRG(Module, AutoCSR): # VCO @ 1GHz when using 125MHz input p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, i_CLKFBIN=self.cd_rtio.clk, - i_RST=self._pll_reset.storage, + i_RST=self.pll_reset.storage, o_CLKFBOUT=rtio_clk, @@ -70,7 +70,7 @@ class _RTIOCRG(Module, AutoCSR): Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), AsyncResetSynchronizer(self.cd_rtio, ~pll_locked), - MultiReg(pll_locked, self._pll_locked.status) + MultiReg(pll_locked, self.pll_locked.status) ] From 53c7a5f2c66df7ac3ba1b99091511a43c46ea251 Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Fri, 31 Aug 2018 21:08:20 +0100 Subject: [PATCH 1267/2457] dashboard: fix TTL moninj level display --- artiq/dashboard/moninj.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py index bbd0b9a3e..8502667f3 100644 --- a/artiq/dashboard/moninj.py +++ b/artiq/dashboard/moninj.py @@ -74,6 +74,7 @@ class _TTLWidget(QtWidgets.QFrame): self.cur_level = False self.cur_oe = False self.cur_override = False + self.cur_override_level = False self.refresh_display() def enterEvent(self, event): @@ -106,7 +107,9 @@ class _TTLWidget(QtWidgets.QFrame): self.set_mode(self.channel, "0") def refresh_display(self): - value_s = "1" if self.cur_level else "0" + level = self.cur_override_level if self.cur_override else self.cur_level + value_s = "1" if level else "0" + if self.cur_override: value_s = "" + value_s + "" color = " color=\"red\"" @@ -377,7 +380,7 @@ class _DeviceManager: if override == TTLOverride.en.value: widget.cur_override = bool(value) if override == TTLOverride.level.value: - widget.cur_level = bool(value) + widget.cur_override_level = bool(value) widget.refresh_display() async def core_connector(self): From b92350b0f6cce35c16138329bad6e8fde2bd3ee2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 26 Sep 2018 10:52:08 +0800 Subject: [PATCH 1268/2457] drtio: monitor RTIOClockMultiplier PLL (#1155) Debugging by Tom Harty --- artiq/firmware/runtime/rtio_mgt.rs | 5 ++++- artiq/firmware/satman/main.rs | 18 ++++++++++++++++++ artiq/gateware/targets/kasli.py | 18 +++++++++++++----- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 726edc886..00f9cc3ef 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -380,6 +380,10 @@ fn async_error_thread(io: Io) { pub fn startup(io: &Io, aux_mutex: &Mutex, routing_table: &Urc>, up_destinations: &Urc>) { + // The RTIO CRG may depend on the DRTIO transceiver clock. + // Initialize DRTIO first to bring up transceiver clocking. + drtio::startup(io, aux_mutex, routing_table, up_destinations); + #[cfg(has_rtio_crg)] { #[cfg(has_rtio_clock_switch)] @@ -422,7 +426,6 @@ pub fn startup(io: &Io, aux_mutex: &Mutex, csr::rtio_core::reset_phy_write(1); } - drtio::startup(io, aux_mutex, routing_table, up_destinations); io.spawn(4096, async_error_thread); } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 22fb5cd75..89efeef68 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -351,6 +351,23 @@ fn drtiosat_process_errors() { } } + +#[cfg(has_rtio_crg)] +fn init_rtio_crg() { + unsafe { + csr::rtio_crg::pll_reset_write(0); + } + clock::spin_us(150); + let locked = unsafe { csr::rtio_crg::pll_locked_read() != 0 }; + if !locked { + error!("RTIO clock failed"); + } +} + +#[cfg(not(has_rtio_crg))] +fn init_rtio_crg() { } + + #[cfg(rtio_frequency = "150.0")] const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings { @@ -388,6 +405,7 @@ pub extern fn main() -> i32 { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } + init_rtio_crg(); #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index cbe9645cc..00c2d68b8 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -592,19 +592,23 @@ class Tester(_StandaloneBase): self.add_rtio(self.rtio_channels) -class _RTIOClockMultiplier(Module): +class _RTIOClockMultiplier(Module, AutoCSR): def __init__(self, rtio_clk_freq): + self.pll_reset = CSRStorage(reset=1) + self.pll_locked = CSRStatus() self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) # See "Global Clock Network Deskew Using Two BUFGs" in ug472. clkfbout = Signal() clkfbin = Signal() rtiox4_clk = Signal() + pll_locked = Signal() self.specials += [ Instance("MMCME2_BASE", p_CLKIN1_PERIOD=1e9/rtio_clk_freq, i_CLKIN1=ClockSignal("rtio"), - i_RST=ResetSignal("rtio"), + i_RST=self.pll_reset.storage, + o_LOCKED=pll_locked, p_CLKFBOUT_MULT_F=8.0, p_DIVCLK_DIVIDE=1, @@ -613,7 +617,9 @@ class _RTIOClockMultiplier(Module): p_CLKOUT0_DIVIDE_F=2.0, o_CLKOUT0=rtiox4_clk, ), Instance("BUFG", i_I=clkfbout, o_O=clkfbin), - Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk) + Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), + + MultiReg(pll_locked, self.pll_locked.status) ] @@ -710,7 +716,8 @@ class _MasterBase(MiniSoC, AMPSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.rxoutclk) - self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) + self.submodules.rtio_crg = _RTIOClockMultiplier(rtio_clk_freq) + self.csr_devices.append("rtio_crg") fix_serdes_timing_path(platform) def add_rtio(self, rtio_channels): @@ -888,7 +895,8 @@ class _SatelliteBase(BaseSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.rxoutclk) - self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) + self.submodules.rtio_crg = _RTIOClockMultiplier(rtio_clk_freq) + self.csr_devices.append("rtio_crg") fix_serdes_timing_path(platform) def add_rtio(self, rtio_channels): From c71e44292992650e49b5109ea8cb8efceb9f1999 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 26 Sep 2018 12:12:37 +0800 Subject: [PATCH 1269/2457] documentation improvements Based on PR #1101 by @drewrisinger --- artiq/coredevice/ad9914.py | 12 +++++------ artiq/coredevice/dma.py | 2 +- artiq/coredevice/spi2.py | 2 +- artiq/coredevice/suservo.py | 2 +- artiq/coredevice/ttl.py | 20 +++++++++--------- artiq/language/core.py | 7 ++++--- artiq/language/environment.py | 27 ++++++++++++++----------- artiq/protocols/asyncio_server.py | 12 +++++++---- artiq/protocols/pc_rpc.py | 21 ++++++++++--------- artiq/protocols/remote_exec.py | 4 ++-- artiq/protocols/sync_struct.py | 20 +++++++++--------- doc/manual/core_language_reference.rst | 2 +- doc/manual/developing_a_ndsp.rst | 4 ++-- doc/manual/environment.rst | 2 +- doc/manual/getting_started_core.rst | 28 +++++++++++++------------- doc/manual/management_system.rst | 18 +++++++++-------- 16 files changed, 97 insertions(+), 86 deletions(-) diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index e892ba65d..bd2ec4db0 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -162,16 +162,16 @@ class AD9914: def set_phase_mode(self, phase_mode): """Sets the phase mode of the DDS channel. Supported phase modes are: - * ``PHASE_MODE_CONTINUOUS``: the phase accumulator is unchanged when + * :const:`PHASE_MODE_CONTINUOUS`: the phase accumulator is unchanged when switching frequencies. The DDS phase is the sum of the phase accumulator and the phase offset. The only discrete jumps in the DDS output phase come from changes to the phase offset. - * ``PHASE_MODE_ABSOLUTE``: the phase accumulator is reset when + * :const:`PHASE_MODE_ABSOLUTE`: the phase accumulator is reset when switching frequencies. Thus, the phase of the DDS at the time of the frequency change is equal to the phase offset. - * ``PHASE_MODE_TRACKING``: when switching frequencies, the phase + * :const:`PHASE_MODE_TRACKING`: when switching frequencies, the phase accumulator is set to the value it would have if the DDS had been running at the specified frequency since the start of the experiment. @@ -193,7 +193,7 @@ class AD9914: :param ftw: frequency to generate. :param pow: adds an offset to the phase. :param phase_mode: if specified, overrides the default phase mode set - by ``set_phase_mode`` for this call. + by :meth:`set_phase_mode` for this call. :param ref_time: reference time used to compute phase. Specifying this makes it easier to have a well-defined phase relationship between DDSes on the same bus that are updated at a similar time. @@ -270,7 +270,7 @@ class AD9914: @kernel def set(self, frequency, phase=0.0, phase_mode=_PHASE_MODE_DEFAULT, amplitude=1.0): - """Like ``set_mu``, but uses Hz and turns.""" + """Like :meth:`set_mu`, but uses Hz and turns.""" self.set_mu(self.frequency_to_ftw(frequency), self.turns_to_pow(phase), phase_mode, self.amplitude_to_asf(amplitude)) @@ -323,7 +323,7 @@ class AD9914: @kernel def set_x(self, frequency, amplitude=1.0): - """Like ``set_x_mu``, but uses Hz and turns. + """Like :meth:`set_x_mu`, but uses Hz and turns. Note that the precision of ``float`` is less than the precision of the extended frequency tuning word. diff --git a/artiq/coredevice/dma.py b/artiq/coredevice/dma.py index eafe98e6c..261a6bcfe 100644 --- a/artiq/coredevice/dma.py +++ b/artiq/coredevice/dma.py @@ -34,7 +34,7 @@ def dma_playback(timestamp: TInt64, ptr: TInt32) -> TNone: class DMARecordContextManager: - """Context manager returned by ``CoreDMA.record()``. + """Context manager returned by :meth:`CoreDMA.record()`. Upon entering, starts recording a DMA trace. All RTIO operations are redirected to a newly created DMA buffer after this call, and ``now`` diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index c8749b082..205251084 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -184,7 +184,7 @@ class SPIMaster: experiments and are known. This method is portable and can also be called from e.g. - ``__init__``. + :meth:`__init__`. :param div: SPI clock divider (see: :meth:`set_config_mu`) :param length: SPI transfer length (see: :meth:`set_config_mu`) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 58e15a9d0..850cb98e4 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -253,7 +253,7 @@ class Channel: This method does not advance the timeline. Output RF switch setting takes effect immediately and is independent of any other activity (profile settings, other channels). The RF switch behaves like - ``TTLOut``. RTIO event replacement is supported. IIR updates take place + :class:`artiq.coredevice.ttl.TTLOut`. RTIO event replacement is supported. IIR updates take place once the RF switch has been enabled for the configured delay and the profile setting has been stable. Profile changes take between one and two servo cycles to reach the DDS. diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 76b443eb7..09732fccc 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -2,8 +2,8 @@ Drivers for TTL signals on RTIO. TTL channels (including the clock generator) all support output event -replacement. For example, pulses of "zero" length (e.g. ``on()`` -immediately followed by ``off()``, without a delay) are suppressed. +replacement. For example, pulses of "zero" length (e.g. :meth:`TTLInOut.on` +immediately followed by :meth:`TTLInOut.off`, without a delay) are suppressed. """ import numpy @@ -107,8 +107,8 @@ class TTLInOut: This should be used with bidirectional channels. Note that the channel is in input mode by default. If you need to drive a - signal, you must call ``output``. If the channel is in output mode most of - the time in your setup, it is a good idea to call ``output`` in the + signal, you must call :meth:`output`. If the channel is in output mode most of + the time in your setup, it is a good idea to call :meth:`output` in the startup kernel. There are three input APIs: gating, sampling and watching. When one @@ -301,10 +301,10 @@ class TTLInOut: @kernel def sample_get(self): """Returns the value of a sample previously obtained with - ``sample_input``. + :meth:`sample_input`. Multiple samples may be queued (using multiple calls to - ``sample_input``) into the RTIO FIFOs and subsequently read out using + :meth:`sample_input`) into the RTIO FIFOs and subsequently read out using multiple calls to this function. This function does not interact with the time cursor.""" @@ -324,11 +324,11 @@ class TTLInOut: @kernel def watch_stay_on(self): """Checks that the input is at a high level at the position - of the time cursor and keep checking until ``watch_done`` + of the time cursor and keep checking until :meth:`watch_done` is called. Returns ``True`` if the input is high. A call to this function - must always be followed by an eventual call to ``watch_done`` + must always be followed by an eventual call to :meth:`watch_done` (use e.g. a try/finally construct to ensure this). The time cursor is not modified by this function. @@ -338,7 +338,7 @@ class TTLInOut: @kernel def watch_stay_off(self): - """Like ``watch_stay_on``, but for low levels.""" + """Like :meth:`watch_stay_on`, but for low levels.""" rtio_output(now_mu(), self.channel, 3, 1) # gate rising return rtio_input_data(self.channel) == 0 @@ -419,7 +419,7 @@ class TTLClockGen: @kernel def set(self, frequency): - """Like ``set_mu``, but using Hz.""" + """Like :meth:`set_mu`, but using Hz.""" self.set_mu(self.frequency_to_ftw(frequency)) @kernel diff --git a/artiq/language/core.py b/artiq/language/core.py index 47c1746f3..e6cd1a498 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -28,19 +28,20 @@ def kernel(arg=None, flags={}): This decorator marks an object's method for execution on the core device. - When a decorated method is called from the Python interpreter, the ``core`` + When a decorated method is called from the Python interpreter, the :attr:`core` attribute of the object is retrieved and used as core device driver. The core device driver will typically compile, transfer and run the method (kernel) on the device. When kernels call another method: - - if the method is a kernel for the same core device, is it compiled + + - if the method is a kernel for the same core device, it is compiled and sent in the same binary. Calls between kernels happen entirely on the device. - if the method is a regular Python method (not a kernel), it generates a remote procedure call (RPC) for execution on the host. - The decorator takes an optional parameter that defaults to ``core`` and + The decorator takes an optional parameter that defaults to :attr`core` and specifies the name of the attribute to use as core device driver. This decorator must be present in the global namespace of all modules using diff --git a/artiq/language/environment.py b/artiq/language/environment.py index a7d7ae55f..3bb33647d 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -230,7 +230,7 @@ class HasEnvironment: instead: when the repository is scanned to build the list of available experiments and when the dataset browser ``artiq_browser`` is used to open or run the analysis stage of an experiment. Do not - rely on being able to operate on devices or arguments in ``build()``. + rely on being able to operate on devices or arguments in :meth:`build`. Datasets are read-only in this method. @@ -277,7 +277,7 @@ class HasEnvironment: def setattr_device(self, key): """Sets a device driver as attribute. The names of the device driver - and of the attribute are the same. + and of the attribute are the same. The key is added to the instance's kernel invariants.""" setattr(self, key, self.get_device(key)) @@ -328,8 +328,10 @@ class HasEnvironment: By default, datasets obtained by this method are archived into the output HDF5 file of the experiment. If an archived dataset is requested more than one time (and therefore its value has potentially changed) or is - modified, a warning is emitted. Archival can be turned off by setting - the ``archive`` argument to ``False``. + modified, a warning is emitted. + + :param archive: Set to ``False`` to prevent archival together with the run's results. + Default is ``True`` """ try: return self.__dataset_mgr.get(key, archive) @@ -355,7 +357,7 @@ class Experiment: """Entry point for pre-computing data necessary for running the experiment. - Doing such computations outside of ``run`` enables more efficient + Doing such computations outside of :meth:`run` enables more efficient scheduling of multiple experiments that need to access the shared hardware during part of their execution. @@ -371,8 +373,8 @@ class Experiment: This method may interact with the hardware. - The experiment may call the scheduler's ``pause`` method while in - ``run``. + The experiment may call the scheduler's :meth:`pause` method while in + :meth:`run`. """ raise NotImplementedError @@ -382,7 +384,7 @@ class Experiment: This method may be overloaded by the user to implement the analysis phase of the experiment, for example fitting curves. - Splitting this phase from ``run`` enables tweaking the analysis + Splitting this phase from :meth:`run` enables tweaking the analysis algorithm on pre-existing data, and CPU-bound analyses to be run overlapped with the next experiment in a pipelined manner. @@ -392,13 +394,14 @@ class Experiment: class EnvExperiment(Experiment, HasEnvironment): - """Base class for top-level experiments that use the ``HasEnvironment`` - environment manager. + """Base class for top-level experiments that use the + :class:`~artiq.language.environment.HasEnvironment` environment manager. Most experiments should derive from this class.""" def prepare(self): - """The default prepare method calls prepare for all children, in the - order of instantiation, if the child has a prepare method.""" + """This default prepare method calls :meth:`~artiq.language.environment.Experiment.prepare` + for all children, in the order of instantiation, if the child has a + :meth:`~artiq.language.environment.Experiment.prepare` method.""" for child in self.children: if hasattr(child, "prepare"): child.prepare() diff --git a/artiq/protocols/asyncio_server.py b/artiq/protocols/asyncio_server.py index e7e300eed..4eef0374b 100644 --- a/artiq/protocols/asyncio_server.py +++ b/artiq/protocols/asyncio_server.py @@ -6,7 +6,8 @@ class AsyncioServer: """Generic TCP server based on asyncio. Users of this class must derive from it and define the - ``_handle_connection_cr`` method and coroutine. + :meth:`~artiq.protocols.asyncio_server.AsyncioServer._handle_connection_cr` + method/coroutine. """ def __init__(self): self._client_tasks = set() @@ -14,10 +15,10 @@ class AsyncioServer: async def start(self, host, port): """Starts the server. - The user must call ``stop`` to free resources properly after this - method completes successfully. + The user must call :meth:`stop` + to free resources properly after this method completes successfully. - This method is a `coroutine`. + This method is a *coroutine*. :param host: Bind address of the server (see ``asyncio.start_server`` from the Python standard library). @@ -48,3 +49,6 @@ class AsyncioServer: task = asyncio.ensure_future(self._handle_connection_cr(reader, writer)) self._client_tasks.add(task) task.add_done_callback(self._client_done) + + async def _handle_connection_cr(self, reader, writer): + raise NotImplementedError diff --git a/artiq/protocols/pc_rpc.py b/artiq/protocols/pc_rpc.py index 410cc8908..adecf25df 100644 --- a/artiq/protocols/pc_rpc.py +++ b/artiq/protocols/pc_rpc.py @@ -1,7 +1,7 @@ """ This module provides a remote procedure call (RPC) mechanism over sockets between conventional computers (PCs) running Python. It strives to be -transparent and uses ``artiq.protocols.pyon`` internally so that e.g. Numpy +transparent and uses :mod:`artiq.protocols.pyon` internally so that e.g. Numpy arrays can be easily used. Note that the server operates on copies of objects provided by the client, @@ -61,18 +61,18 @@ class Client: can be used as if they were local methods. For example, if the server provides method ``foo``, and ``c`` is a local - ``Client`` object, then the method can be called as: :: + :class:`.Client` object, then the method can be called as: :: result = c.foo(param1, param2) - The parameters and the result are automatically transferred with the + The parameters and the result are automatically transferred from the server. Only methods are supported. Attributes must be accessed by providing and using "get" and/or "set" methods on the server side. At object initialization, the connection to the remote server is - automatically attempted. The user must call ``close_rpc`` to + automatically attempted. The user must call :meth:`~artiq.protocols.pc_rpc.Client.close_rpc` to free resources properly after initialization completes successfully. :param host: Identifier of the server. The string can represent a @@ -81,11 +81,11 @@ class Client: :param port: TCP port to use. :param target_name: Target name to select. ``IncompatibleServer`` is raised if the target does not exist. - Use ``AutoTarget`` for automatic selection if the server has only one + Use :class:`.AutoTarget` for automatic selection if the server has only one target. Use ``None`` to skip selecting a target. The list of targets can then - be retrieved using ``get_rpc_id`` and then one can be selected later - using ``select_rpc_target``. + be retrieved using :meth:`~artiq.protocols.pc_rpc.Client.get_rpc_id` + and then one can be selected later using :meth:`~artiq.protocols.pc_rpc.Client.select_rpc_target`. :param timeout: Socket operation timeout. Use ``None`` for blocking (default), ``0`` for non-blocking, and a finite value to raise ``socket.timeout`` if an operation does not complete within the @@ -198,7 +198,7 @@ class AsyncioClient: async def connect_rpc(self, host, port, target_name): """Connects to the server. This cannot be done in __init__ because - this method is a coroutine. See ``Client`` for a description of the + this method is a coroutine. See :class:`artiq.protocols.pc_rpc.Client` for a description of the parameters.""" self.__reader, self.__writer = \ await asyncio.open_connection(host, port, limit=100*1024*1024) @@ -447,7 +447,8 @@ class _PrettyPrintCall: class Server(_AsyncioServer): """This class creates a TCP server that handles requests coming from - ``Client`` objects. + *Client* objects (whether :class:`.Client`, :class:`.BestEffortClient`, + or :class:`.AsyncioClient`). The server is designed using ``asyncio`` so that it can easily support multiple connections without the locking issues that arise in @@ -591,7 +592,7 @@ def simple_server_loop(targets, host, port, description=None): """Runs a server until an exception is raised (e.g. the user hits Ctrl-C) or termination is requested by a client. - See ``Server`` for a description of the parameters. + See :class:`artiq.protocols.pc_rpc.Server` for a description of the parameters. """ loop = asyncio.get_event_loop() try: diff --git a/artiq/protocols/remote_exec.py b/artiq/protocols/remote_exec.py index 0b7f2419c..ae9870c30 100644 --- a/artiq/protocols/remote_exec.py +++ b/artiq/protocols/remote_exec.py @@ -7,10 +7,10 @@ large amounts of data with it, and only exchange higher-level, processed data with the experiment (and over the network). Controllers with support for remote execution contain an additional target -that gives RPC access to instances of ``RemoteExecServer``. One such instance +that gives RPC access to instances of :class:`.RemoteExecServer`. One such instance is created per client (experiment) connection and manages one Python namespace in which the experiment can execute arbitrary code by calling the methods of -``RemoteExecServer``. +:class:`.RemoteExecServer`. The namespaces are initialized with the following global values: diff --git a/artiq/protocols/sync_struct.py b/artiq/protocols/sync_struct.py index 35b72ff75..ca48c5356 100644 --- a/artiq/protocols/sync_struct.py +++ b/artiq/protocols/sync_struct.py @@ -117,10 +117,10 @@ class Subscriber: class Notifier: """Encapsulates a structure whose changes need to be published. - All mutations to the structure must be made through the ``Notifier``. The + All mutations to the structure must be made through the :class:`.Notifier`. The original structure must only be accessed for reads. - In addition to the list methods below, the ``Notifier`` supports the index + In addition to the list methods below, the :class:`.Notifier` supports the index syntax for modification and deletion of elements. Modification of nested structures can be also done using the index syntax, for example: @@ -131,11 +131,11 @@ class Notifier: [[42]] This class does not perform any network I/O and is meant to be used with - e.g. the ``Publisher`` for this purpose. Only one publisher at most can be - associated with a ``Notifier``. + e.g. the :class:`.Publisher` for this purpose. Only one publisher at most can be + associated with a :class:`.Notifier`. :param backing_struct: Structure to encapsulate. For convenience, it - also becomes available as the ``read`` property of the ``Notifier``. + also becomes available as the ``read`` property of the :class:`.Notifier`. """ def __init__(self, backing_struct, root=None, path=[]): self.read = backing_struct @@ -168,7 +168,7 @@ class Notifier: def pop(self, i=-1): """Pop an element from a list. The returned element is not - encapsulated in a ``Notifier`` and its mutations are no longer + encapsulated in a :class:`.Notifier` and its mutations are no longer tracked.""" r = self._backing_struct.pop(i) if self.root.publish is not None: @@ -199,11 +199,11 @@ class Notifier: class Publisher(AsyncioServer): """A network server that publish changes to structures encapsulated in - ``Notifiers``. + a :class:`.Notifier`. :param notifiers: A dictionary containing the notifiers to associate with - the ``Publisher``. The keys of the dictionary are the names of the - notifiers to be used with ``Subscriber``. + the :class:`.Publisher`. The keys of the dictionary are the names of the + notifiers to be used with :class:`.Subscriber`. """ def __init__(self, notifiers): AsyncioServer.__init__(self) @@ -245,7 +245,7 @@ class Publisher(AsyncioServer): finally: self._recipients[notifier_name].remove(queue) except (ConnectionResetError, ConnectionAbortedError, BrokenPipeError): - # subscribers disconnecting are a normal occurence + # subscribers disconnecting are a normal occurrence pass finally: writer.close() diff --git a/doc/manual/core_language_reference.rst b/doc/manual/core_language_reference.rst index 8982f9231..228d33590 100644 --- a/doc/manual/core_language_reference.rst +++ b/doc/manual/core_language_reference.rst @@ -1,7 +1,7 @@ Core language reference ======================= -The most commonly used features from the ARTIQ language modules and from the core device modules are bundled together in ``artiq.experiment`` and can be imported with ``from artiq.experiment import *``. +The most commonly used features from the ARTIQ language modules and from the core device modules are bundled together in :mod:`artiq.experiment` and can be imported with ``from artiq.experiment import *``. :mod:`artiq.language.core` module --------------------------------- diff --git a/doc/manual/developing_a_ndsp.rst b/doc/manual/developing_a_ndsp.rst index a48b7aa2b..4989aded6 100644 --- a/doc/manual/developing_a_ndsp.rst +++ b/doc/manual/developing_a_ndsp.rst @@ -1,5 +1,5 @@ -Developing a network device support package -=========================================== +Developing a Network Device Support Package (NDSP) +================================================== Most ARTIQ devices are interfaced through "controllers" that expose RPC interfaces to the network (based on :class:`artiq.protocols.pc_rpc`). The master never does direct I/O to the devices, but issues RPCs to the controllers when needed. As opposed to running everything on the master, this architecture has those main advantages: diff --git a/doc/manual/environment.rst b/doc/manual/environment.rst index 924c54509..5a2df7a89 100644 --- a/doc/manual/environment.rst +++ b/doc/manual/environment.rst @@ -10,7 +10,7 @@ The device database The device database contains information about the devices available in a ARTIQ installation, what drivers to use, what controllers to use and on what machine, and where the devices are connected. -The master (or ``artiq_run``) instantiates the device drivers (and the RPC clients in the case of controllers) for the experiments based on the contents of the device database. +The master (or :mod:`~artiq.frontend.artiq_run`) instantiates the device drivers (and the RPC clients in the case of controllers) for the experiments based on the contents of the device database. The device database is stored in the memory of the master and is generated by a Python script typically called ``device_db.py``. That script must define a global variable ``device_db`` with the contents of the database. The device database is a Python dictionary whose keys are the device names, and values can have several types. diff --git a/doc/manual/getting_started_core.rst b/doc/manual/getting_started_core.rst index eca62fd03..a5d77cd38 100644 --- a/doc/manual/getting_started_core.rst +++ b/doc/manual/getting_started_core.rst @@ -21,7 +21,7 @@ As a very first step, we will turn on a LED on the core device. Create a file `` self.core.reset() self.led.on() -The central part of our code is our ``LED`` class, that derives from :class:`artiq.language.environment.EnvExperiment`. Among other features, ``EnvExperiment`` calls our ``build`` method and provides the ``setattr_device`` method that interfaces to the device database to create the appropriate device drivers and make those drivers accessible as ``self.core`` and ``self.led``. The ``@kernel`` decorator tells the system that the ``run`` method must be compiled for and executed on the core device (instead of being interpreted and executed as regular Python code on the host). The decorator uses ``self.core`` internally, which is why we request the core device using ``setattr_device`` like any other. +The central part of our code is our ``LED`` class, which derives from :class:`artiq.language.environment.EnvExperiment`. Among other features, :class:`~artiq.language.environment.EnvExperiment` calls our :meth:`~artiq.language.environment.Experiment.build` method and provides the :meth:`~artiq.language.environment.HasEnvironment.setattr_device` method that interfaces to the device database to create the appropriate device drivers and make those drivers accessible as ``self.core`` and ``self.led``. The :func:`~artiq.language.core.kernel` decorator (``@kernel``) tells the system that the :meth:`~artiq.language.environment.Experiment.run` method must be compiled for and executed on the core device (instead of being interpreted and executed as regular Python code on the host). The decorator uses ``self.core`` internally, which is why we request the core device using :meth:`~artiq.language.environment.HasEnvironment.setattr_device` like any other. Copy the file ``device_db.py`` (containing the device database) from the ``examples/master`` folder of ARTIQ into the same directory as ``led.py`` (alternatively, you can use the ``--device-db`` option of ``artiq_run``). You will probably want to set the IP address of the core device in ``device_db.py`` so that the computer can connect to it (it is the ``host`` parameter of the ``comm`` entry). See :ref:`device-db` for more information. The example device database is designed for the ``nist_clock`` hardware adapter on the KC705; see :ref:`board-ports` for RTIO channel assignments if you need to adapt the device database to a different hardware platform. @@ -69,18 +69,18 @@ You can then turn the LED off and on by entering 0 or 1 at the prompt that appea $ artiq_run led.py Enter desired LED state: 0 -What happens is the ARTIQ compiler notices that the ``input_led_state`` function does not have a ``@kernel`` decorator and thus must be executed on the host. When the core device calls it, it sends a request to the host to execute it. The host displays the prompt, collects user input, and sends the result back to the core device, which sets the LED state accordingly. +What happens is the ARTIQ compiler notices that the :meth:`input_led_state` function does not have a ``@kernel`` decorator (:func:`~artiq.language.core.kernel`) and thus must be executed on the host. When the core device calls it, it sends a request to the host to execute it. The host displays the prompt, collects user input, and sends the result back to the core device, which sets the LED state accordingly. RPC functions must always return a value of the same type. When they return a value that is not ``None``, the compiler should be informed in advance of the type of the value, which is what the ``-> TBool`` annotation is for. -Without the ``break_realtime()`` call, the RTIO events emitted by ``self.led.on()`` or ``self.led.off()`` would be scheduled at a fixed and very short delay after entering ``run()``. -These events would fail because the RPC to ``input_led_state()`` can take an arbitrary amount of time and therefore the deadline for submission of RTIO events would have long passed when ``self.led.on()`` or ``self.led.off()`` are called. -The ``break_realtime()`` call is necessary to waive the real-time requirements of the LED state change. +Without the :meth:`~artiq.coredevice.core.Core.break_realtime` call, the RTIO events emitted by :func:`self.led.on()` or :func:`self.led.off()` would be scheduled at a fixed and very short delay after entering :meth:`~artiq.language.environment.Experiment.run()`. +These events would fail because the RPC to :meth:`input_led_state()` can take an arbitrary amount of time and therefore the deadline for submission of RTIO events would have long passed when :func:`self.led.on()` or :func:`self.led.off()` are called. +The :meth:`~artiq.coredevice.core.Core.break_realtime` call is necessary to waive the real-time requirements of the LED state change. It advances the timeline far enough to ensure that events can meet the submission deadline. -Real-time I/O (RTIO) --------------------- +Real-time Input/Output (RTIO) +----------------------------- The point of running code on the core device is the ability to meet demanding real-time constraints. In particular, the core device can respond to an incoming stimulus or the result of a measurement with a low and predictable latency. We will see how to use inputs later; first, we must familiarize ourselves with how time is managed in kernels. @@ -102,11 +102,11 @@ Create a new file ``rtio.py`` containing the following: :: delay(2*us) self.ttl0.pulse(2*us) -In its ``build()`` method, the experiment obtains the core device and a TTL device called ``ttl0`` as defined in the device database. +In its :meth:`~artiq.language.environment.Experiment.build` method, the experiment obtains the core device and a TTL device called ``ttl0`` as defined in the device database. In ARTIQ, TTL is used roughly synonymous with "a single generic digital signal" and does not refer to a specific signaling standard or voltage/current levels. -When ``run()``, the experiment first ensures that ``ttl0`` is in output mode and actively driving the device it is connected to. -Bidirectional TTL channels (i.e. ``TTLInOut``) are in input (high impedance) mode by default, output-only TTL channels (``TTLOut``) are always in output mode. +When :meth:`~artiq.language.environment.Experiment.run`, the experiment first ensures that ``ttl0`` is in output mode and actively driving the device it is connected to. +Bidirectional TTL channels (i.e. :class:`~artiq.devices.ttl.TTLInOut`) are in input (high impedance) mode by default, output-only TTL channels (:class:`~artiq.devices.ttl.TTLOut`) are always in output mode. There are no input-only TTL channels. The experiment then drives one million 2 µs long pulses separated by 2 µs each. @@ -118,7 +118,7 @@ Any asymmetry in the overhead would manifest itself in a distorted and variable Instead, inside the core device, output timing is generated by the gateware and the CPU only programs switching commands with certain timestamps that the CPU computes. -This guarantees precise timing as long as the CPU can keep generating timestamps that are increasing fast enough. In case it fails to do that (and attempts to program an event with a timestamp smaller than the current RTIO clock timestamp), a :class:`artiq.coredevice.exceptions.RTIOUnderflow` exception is raised. The kernel causing it may catch it (using a regular ``try... except...`` construct), or it will be propagated to the host. +This guarantees precise timing as long as the CPU can keep generating timestamps that are increasing fast enough. In case it fails to do that (and attempts to program an event with a timestamp smaller than the current RTIO clock timestamp), a :exc:`~artiq.coredevice.exceptions.RTIOUnderflow` exception is raised. The kernel causing it may catch it (using a regular ``try... except...`` construct), or it will be propagated to the host. Try reducing the period of the generated waveform until the CPU cannot keep up with the generation of switching events and the underflow exception is raised. Then try catching it: :: @@ -161,7 +161,7 @@ ARTIQ can implement ``with parallel`` blocks without having to resort to any of It simply remembers the position on the timeline when entering the ``parallel`` block and then seeks back to that position after submitting the events generated by each statement. In other words, the statements in the ``parallel`` block are actually executed sequentially, only the RTIO events generated by them are scheduled to be executed in parallel. Note that if a statement takes a lot of CPU time to execute (this different from the events scheduled by a statement taking a long time), it may cause a subsequent statement to miss the deadline for timely submission of its events. -This then causes a ``RTIOUnderflow`` exception to be raised. +This then causes a :exc:`~artiq.coredevice.exceptions.RTIOUnderflow` exception to be raised. Within a parallel block, some statements can be made sequential again using a ``with sequential`` construct. Observe the pulses generated by this code: :: @@ -199,8 +199,8 @@ The core device records the real-time I/O waveforms into a circular buffer. It i Afterwards, the recorded data can be extracted and written to a VCD file using ``artiq_coreanalyzer -w rtio.vcd`` (see: :ref:`core-device-rtio-analyzer-tool`). VCD files can be viewed using third-party tools such as GtkWave. -DMA ---- +Direct Memory Access (DMA) +-------------------------- DMA allows you to store fixed sequences of pulses in system memory, and have the DMA core in the FPGA play them back at high speed. Pulse sequences that are too fast for the CPU (i.e. would cause RTIO underflows) can still be generated using DMA. The only modification of the sequence that the DMA core supports is shifting it in time (so it can be played back at any position of the timeline), everything else is fixed at the time of recording the sequence. diff --git a/doc/manual/management_system.rst b/doc/manual/management_system.rst index cd771b226..12f5e45d6 100644 --- a/doc/manual/management_system.rst +++ b/doc/manual/management_system.rst @@ -1,7 +1,7 @@ Management system ================= -The management system described below is optional: experiments can be run one by one using ``artiq_run``, and the controllers can run stand-alone (without a controller manager). For their very first steps with ARTIQ or in simple or particular cases, users do not need to deploy the management system. +The management system described below is optional: experiments can be run one by one using :mod:`~artiq.frontend.artiq_run`, and the controllers can run stand-alone (without a controller manager). For their very first steps with ARTIQ or in simple or particular cases, users do not need to deploy the management system. Components ********** @@ -42,13 +42,15 @@ Basics To use hardware resources more efficiently, potentially compute-intensive pre-computation and analysis phases of other experiments is executed in parallel with the body of the current experiment that accesses the hardware. +.. seealso:: These steps are implemented in :class:`~artiq.language.environment.Experiment`. However, user-written experiments should usually derive from (sub-class) :class:`artiq.language.environment.EnvExperiment`. + Experiments are divided into three phases that are programmed by the user: -1. The preparation stage, that pre-fetches and pre-computes any data that necessary to run the experiment. Users may implement this stage by overloading the ``prepare`` method. It is not permitted to access hardware in this stage, as doing so may conflict with other experiments using the same devices. -2. The running stage, that corresponds to the body of the experiment, and typically accesses hardware. Users must implement this stage and overload the ``run`` method. -3. The analysis stage, where raw results collected in the running stage are post-processed and may lead to updates of the parameter database. This stage may be implemented by overloading the ``analyze`` method. +1. The **preparation** stage, that pre-fetches and pre-computes any data that necessary to run the experiment. Users may implement this stage by overloading the :meth:`~artiq.language.environment.Experiment.prepare` method. It is not permitted to access hardware in this stage, as doing so may conflict with other experiments using the same devices. +2. The **running** stage, that corresponds to the body of the experiment, and typically accesses hardware. Users must implement this stage and overload the :meth:`~artiq.language.environment.Experiment.run` method. +3. The **analysis** stage, where raw results collected in the running stage are post-processed and may lead to updates of the parameter database. This stage may be implemented by overloading the :meth:`~artiq.language.environment.Experiment.analyze` method. -.. note:: Only the ``run`` method implementation is mandatory; if the experiment does not fit into the pipelined scheduling model, it can leave one or both of the other methods empty (which is the default). +.. note:: Only the :meth:`~artiq.language.environment.Experiment.run` method implementation is mandatory; if the experiment does not fit into the pipelined scheduling model, it can leave one or both of the other methods empty (which is the default). The three phases of several experiments are then executed in a pipelined manner by the scheduler in the ARTIQ master: experiment A executes its preparation stage, then experiment A executes its running stage while experiment B executes its preparation stage, and so on. @@ -70,11 +72,11 @@ If there are other experiments with higher priority (e.g. a high-priority timed Otherwise, ``pause()`` returns immediately. To check whether ``pause()`` would in fact *not* return immediately, use :meth:`artiq.master.scheduler.Scheduler.check_pause`. -The experiment must place the hardware in a safe state and disconnect from the core device (typically, by using ``self.core.comm.close()``) before calling ``pause``. +The experiment must place the hardware in a safe state and disconnect from the core device (typically, by calling ``self.coredevice.comm.close()`` from the kernel, which is equivalent to :meth:`artiq.coredevice.core.Core.close`) before calling ``pause()``. -Accessing the ``pause`` and ``check_pause`` methods is done through a virtual device called ``scheduler`` that is accessible to all experiments. The scheduler virtual device is requested like regular devices using ``get_device`` or ``attr_device``. +Accessing the ``pause()`` and :meth:`~artiq.master.scheduler.Scheduler.check_pause` methods is done through a virtual device called ``scheduler`` that is accessible to all experiments. The scheduler virtual device is requested like regular devices using :meth:`~artiq.language.environment.HasEnvironment.get_device` (``self.get_device()``) or :meth:`~artiq.language.environment.HasEnvironment.setattr_device` (``self.setattr_device()``). -``check_pause`` can be called (via RPC) from a kernel, but ``pause`` must not. +:meth:`~artiq.master.scheduler.Scheduler.check_pause` can be called (via RPC) from a kernel, but ``pause()`` must not. Multiple pipelines ------------------ From 998a4689831711a9168e30454ecc1e0ca5b9c5a7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 27 Sep 2018 16:09:25 +0800 Subject: [PATCH 1270/2457] examples: add grabber to device databases --- artiq/examples/kasli_basic/device_db_mitll.py | 7 +++++++ artiq/examples/kasli_basic/device_db_tsinghua.py | 7 +++++++ artiq/examples/kasli_basic/device_db_ustc.py | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/artiq/examples/kasli_basic/device_db_mitll.py b/artiq/examples/kasli_basic/device_db_mitll.py index ea4402455..66a757176 100644 --- a/artiq/examples/kasli_basic/device_db_mitll.py +++ b/artiq/examples/kasli_basic/device_db_mitll.py @@ -139,6 +139,13 @@ for i in range(2): } } +device_db["grabber0"] = { + "type": "local", + "module": "artiq.coredevice.grabber", + "class": "Grabber", + "arguments": {"channel_base": 20} +} + device_db.update( led0={ "type": "local", diff --git a/artiq/examples/kasli_basic/device_db_tsinghua.py b/artiq/examples/kasli_basic/device_db_tsinghua.py index 9c9cb979c..9c20b8c83 100644 --- a/artiq/examples/kasli_basic/device_db_tsinghua.py +++ b/artiq/examples/kasli_basic/device_db_tsinghua.py @@ -171,6 +171,13 @@ device_db["zotino0"] = { } } +device_db["grabber0"] = { + "type": "local", + "module": "artiq.coredevice.grabber", + "class": "Grabber", + "arguments": {"channel_base": 20} +} + device_db.update( led0={ "type": "local", diff --git a/artiq/examples/kasli_basic/device_db_ustc.py b/artiq/examples/kasli_basic/device_db_ustc.py index 1c2810042..4828b18d0 100644 --- a/artiq/examples/kasli_basic/device_db_ustc.py +++ b/artiq/examples/kasli_basic/device_db_ustc.py @@ -173,6 +173,13 @@ for i in range(4): } } +device_db["grabber0"] = { + "type": "local", + "module": "artiq.coredevice.grabber", + "class": "Grabber", + "arguments": {"channel_base": 36} +} + device_db.update( led0={ "type": "local", From 3b3fddb5a42255ca29d2622e010a524387125b3a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 27 Sep 2018 23:21:52 +0800 Subject: [PATCH 1271/2457] kasli: add mitll2 --- .../examples/kasli_basic/device_db_mitll2.py | 225 ++++++++++++++++++ artiq/gateware/targets/kasli.py | 41 +++- 2 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 artiq/examples/kasli_basic/device_db_mitll2.py diff --git a/artiq/examples/kasli_basic/device_db_mitll2.py b/artiq/examples/kasli_basic/device_db_mitll2.py new file mode 100644 index 000000000..dcd003c23 --- /dev/null +++ b/artiq/examples/kasli_basic/device_db_mitll2.py @@ -0,0 +1,225 @@ +core_addr = "kasli-1.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + +for i in range(8): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": i}, + } + +device_db.update( + spi_urukul0={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 8} + }, + ttl_urukul0_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 9} + }, + ttl_urukul0_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 10} + }, + ttl_urukul0_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 11} + }, + ttl_urukul0_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 12} + }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 13} + }, + urukul0_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul0_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } + +device_db.update( + spi_urukul1={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 14} + }, + ttl_urukul1_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 15} + }, + ttl_urukul1_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 16} + }, + ttl_urukul1_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 17} + }, + ttl_urukul1_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 18} + }, + ttl_urukul1_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 19} + }, + urukul1_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul1", + "io_update_device": "ttl_urukul1_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul1_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul1_cpld", + "sw_device": "ttl_urukul1_sw" + str(i) + } + } + +for i in range(2): + device_db["spi_zotino{}".format(i)] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 20+3*i+0} + } + device_db["ttl_zotino{}_ldac".format(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 20+3*i+1} + } + device_db["ttl_zotino{}_clr".format(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 20+3*i+2} + } + device_db["zotino{}".format(i)] = { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino{}".format(i), + "ldac_device": "ttl_zotino{}_ldac".format(i), + "clr_device": "ttl_zotino{}_clr".format(i) + } + } + +device_db["grabber0"] = { + "type": "local", + "module": "artiq.coredevice.grabber", + "class": "Grabber", + "arguments": {"channel_base": 26} +} + +device_db.update( + led0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 28} + }, + led1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 29} + }, +) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index ef1fa64f7..2a9839487 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -305,6 +305,45 @@ class MITLL(_StandaloneBase): self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) +class MITLL2(_StandaloneBase): + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) + + self.rtio_channels = [] + self.grabber_csr_group = [] + eem.DIO.add_std(self, 5, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 2, 1, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 4, 3, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 6, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) + eem.Grabber.add_std(self, 0) + + for i in (1, 2): + sfp_ctl = self.platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(self.rtio_channels) + self.config["HAS_GRABBER"] = None + self.add_csr_group("grabber", self.grabber_csr_group) + self.platform.add_false_path_constraints( + self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) + + class USTC(_StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: @@ -958,7 +997,7 @@ def main(): soc_kasli_args(parser) parser.set_defaults(output_dir="artiq_kasli") variants = {cls.__name__.lower(): cls for cls in [ - Opticlock, SUServo, SYSU, MITLL, USTC, Tsinghua, WIPM, PTB, HUB, LUH, + Opticlock, SUServo, SYSU, MITLL, MITLL2, USTC, Tsinghua, WIPM, PTB, HUB, LUH, VLBAIMaster, VLBAISatellite, Tester, Master, Satellite]} parser.add_argument("-V", "--variant", default="opticlock", help="variant: {} (default: %(default)s)".format( From fad7128a52903965006fea752da48b3a1a9537a4 Mon Sep 17 00:00:00 2001 From: Drew Risinger Date: Thu, 27 Sep 2018 00:31:06 -0400 Subject: [PATCH 1272/2457] Create Docs Makefile for Windows. #1159 Allows building Sphinx documentation on Windows, (not just Linux as previously). Closes #1159. --- doc/manual/make.bat | 263 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 doc/manual/make.bat diff --git a/doc/manual/make.bat b/doc/manual/make.bat new file mode 100644 index 000000000..55f81a205 --- /dev/null +++ b/doc/manual/make.bat @@ -0,0 +1,263 @@ +@ECHO OFF + +REM Command file for Sphinx documentation + +REM TODO: missing latexpdf and latexpdfja cmds of ./Makefile + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% +set I18NSPHINXOPTS=%SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% + set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. epub3 to make an epub3 + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. texinfo to make Texinfo files + echo. gettext to make PO message catalogs + echo. changes to make an overview over all changed/added/deprecated items + echo. xml to make Docutils-native XML files + echo. pseudoxml to make pseudoxml-XML files for display purposes + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + + +REM Check if sphinx-build is available and fallback to Python version if any +%SPHINXBUILD% 1>NUL 2>NUL +if errorlevel 9009 goto sphinx_python +goto sphinx_ok + +:sphinx_python + +set SPHINXBUILD=python -m sphinx.__init__ +%SPHINXBUILD% 2> nul +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +:sphinx_ok + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + REM echo.^> qcollectiongenerator %BUILDDIR%\qthelp\ARTIQ.qhcp + REM echo.To view the help file: + REM echo.^> assistant -collectionFile %BUILDDIR%\qthelp\ARTIQ.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "epub3" ( + %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdf" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "latexpdfja" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + cd %BUILDDIR%/latex + make all-pdf-ja + cd %~dp0 + echo. + echo.Build finished; the PDF files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "texinfo" ( + %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. + goto end +) + +if "%1" == "gettext" ( + %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The message catalogs are in %BUILDDIR%/locale. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +if "%1" == "xml" ( + %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The XML files are in %BUILDDIR%/xml. + goto end +) + +if "%1" == "pseudoxml" ( + %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. + goto end +) + +:end From 0fef2afccbf7460dacac839caaab86ff376f3e03 Mon Sep 17 00:00:00 2001 From: Drew Risinger Date: Thu, 27 Sep 2018 01:29:57 -0400 Subject: [PATCH 1273/2457] make.bat: fix typo --- doc/manual/make.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/make.bat b/doc/manual/make.bat index 55f81a205..5567edd05 100644 --- a/doc/manual/make.bat +++ b/doc/manual/make.bat @@ -8,7 +8,7 @@ if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% From d0ee2c2955e23c835e122b04b915e03c3cecfa46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 28 Sep 2018 19:05:18 +0200 Subject: [PATCH 1274/2457] opticlock: external 100 MHz --- artiq/gateware/targets/kasli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 2a9839487..f33788550 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -153,7 +153,7 @@ class Opticlock(_StandaloneBase): _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None - # self.config["SI5324_EXT_REF"] = None + self.config["SI5324_EXT_REF"] = None self.config["RTIO_FREQUENCY"] = "125.0" if hw_rev == "v1.0": # EEM clock fan-out from Si5324, not MMCX From 9f96b6bcda7d998ba9555d6cc912f55839d38bb9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 4 Oct 2018 10:41:01 +0800 Subject: [PATCH 1275/2457] kasli: use 125MHz DRTIO freq for testing --- artiq/gateware/targets/kasli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 8fbaa0ec1..904464cbf 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -685,7 +685,7 @@ class _MasterBase(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, rtio_clk_freq=150e6, **kwargs): + def __init__(self, rtio_clk_freq=125e6, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -834,7 +834,7 @@ class _SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, rtio_clk_freq=150e6, **kwargs): + def __init__(self, rtio_clk_freq=125e6, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", From a89bd6b6848799c70b5571fa29ccae4649d2c704 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 4 Oct 2018 23:19:31 +0800 Subject: [PATCH 1276/2457] kasli: swap Urukul EEMs for Tester Updated to Urukul 1.3. --- artiq/gateware/targets/kasli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index f33788550..ef454235a 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -614,7 +614,7 @@ class Tester(_StandaloneBase): self.grabber_csr_group = [] eem.DIO.add_std(self, 5, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 1, 0, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 0, 1, ttl_serdes_7series.Output_8X) eem.Sampler.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) eem.Zotino.add_std(self, 4, ttl_serdes_7series.Output_8X) eem.Grabber.add_std(self, 6) From 86fe6b05949e508b909695f2a78396e7c4f6d40a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 4 Oct 2018 23:20:09 +0800 Subject: [PATCH 1277/2457] kasli: add NUDT variant --- artiq/gateware/targets/kasli.py | 35 ++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index ef454235a..34f0241dd 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -456,6 +456,39 @@ class WIPM(_StandaloneBase): self.add_rtio(self.rtio_channels) +class NUDT(_StandaloneBase): + # Like Tester, but fewer peripherals and newer Sampler + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + # self.config["SI5324_EXT_REF"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) + + self.rtio_channels = [] + eem.DIO.add_std(self, 5, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 0, 1, ttl_serdes_7series.Output_8X) + eem.Sampler.add_std(self, 2, 3, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 4, ttl_serdes_7series.Output_8X) + + for i in (1, 2): + sfp_ctl = self.platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + self.add_rtio(self.rtio_channels) + + class PTB(_StandaloneBase): """PTB Kasli variant @@ -997,7 +1030,7 @@ def main(): soc_kasli_args(parser) parser.set_defaults(output_dir="artiq_kasli") variants = {cls.__name__.lower(): cls for cls in [ - Opticlock, SUServo, SYSU, MITLL, MITLL2, USTC, Tsinghua, WIPM, PTB, HUB, LUH, + Opticlock, SUServo, SYSU, MITLL, MITLL2, USTC, Tsinghua, WIPM, NUDT, PTB, HUB, LUH, VLBAIMaster, VLBAISatellite, Tester, Master, Satellite]} parser.add_argument("-V", "--variant", default="opticlock", help="variant: {} (default: %(default)s)".format( From 9a509e50701d9a1c29590478be2f4ae52ec50b72 Mon Sep 17 00:00:00 2001 From: hartytp Date: Sat, 6 Oct 2018 14:19:49 +0100 Subject: [PATCH 1278/2457] Zotino: increase delay after register read in init method to avoid underflows --- artiq/coredevice/ad53xx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 9acdd3104..7e8654d63 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -171,7 +171,7 @@ class AD53xx: ctrl = self.read_reg(channel=0, op=AD53XX_READ_CONTROL) if ctrl & 0b10000: raise ValueError("DAC over temperature") - delay(15*us) + delay(25*us) self.bus.write( # enable power and overtemperature shutdown (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_CONTROL | 0b0010) << 8) if not blind: From 5de319d76acb01234d13d94c9f923523b016c886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 8 Oct 2018 10:13:03 +0200 Subject: [PATCH 1279/2457] bit2bin: don't print string terminator --- artiq/frontend/bit2bin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/bit2bin.py b/artiq/frontend/bit2bin.py index f511c0559..df3927415 100755 --- a/artiq/frontend/bit2bin.py +++ b/artiq/frontend/bit2bin.py @@ -32,7 +32,7 @@ def bit2bin(bit, bin, flip=False): if key in "abcd": d = bit.read(*struct.unpack(">H", bit.read(2))) assert d.endswith(b"\x00") - d = d.decode() + d = d[:-1].decode() name = { "a": "Design", "b": "Part name", From 1a1b454ed9d78c95b76e4a38852dedc10b69ebf6 Mon Sep 17 00:00:00 2001 From: hartytp Date: Mon, 8 Oct 2018 10:06:51 +0100 Subject: [PATCH 1280/2457] Urukul: flake8 (NFC) --- artiq/coredevice/urukul.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index f3d34b93f..8964097e8 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -1,15 +1,15 @@ from artiq.language.core import kernel, delay, portable from artiq.language.units import us, ms -from numpy import int32, int64 +from numpy import int32 from artiq.coredevice import spi2 as spi SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | - 0*spi.SPI_INPUT | 1*spi.SPI_CS_POLARITY | - 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | - 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) + 0*spi.SPI_INPUT | 1*spi.SPI_CS_POLARITY | + 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | + 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) # SPI clock write and read dividers SPIT_CFG_WR = 2 @@ -52,7 +52,7 @@ CS_DDS_CH3 = 7 @portable def urukul_cfg(rf_sw, led, profile, io_update, mask_nu, - clk_sel, sync_sel, rst, io_rst): + clk_sel, sync_sel, rst, io_rst): """Build Urukul CPLD configuration register""" return ((rf_sw << CFG_RF_SW) | (led << CFG_LED) | @@ -129,10 +129,10 @@ class CPLD: kernel_invariants = {"refclk", "bus", "core", "io_update"} def __init__(self, dmgr, spi_device, io_update_device=None, - dds_reset_device=None, sync_sel=0, clk_sel=0, rf_sw=0, - refclk=125e6, att=0x00000000, core_device="core"): + dds_reset_device=None, sync_sel=0, clk_sel=0, rf_sw=0, + refclk=125e6, att=0x00000000, core_device="core"): - self.core = dmgr.get(core_device) + self.core = dmgr.get(core_device) self.refclk = refclk self.bus = dmgr.get(spi_device) @@ -144,8 +144,8 @@ class CPLD: self.dds_reset = dmgr.get(dds_reset_device) self.cfg_reg = urukul_cfg(rf_sw=rf_sw, led=0, profile=0, - io_update=0, mask_nu=0, clk_sel=clk_sel, - sync_sel=sync_sel, rst=0, io_rst=0) + io_update=0, mask_nu=0, clk_sel=clk_sel, + sync_sel=sync_sel, rst=0, io_rst=0) self.att_reg = att @kernel @@ -158,7 +158,7 @@ class CPLD: :attr:`cfg_reg`. """ self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 24, - SPIT_CFG_WR, CS_CFG) + SPIT_CFG_WR, CS_CFG) self.bus.write(cfg << 8) self.cfg_reg = cfg @@ -177,7 +177,7 @@ class CPLD: :return: The status register value. """ self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 24, - SPIT_CFG_RD, CS_CFG) + SPIT_CFG_RD, CS_CFG) self.bus.write(self.cfg_reg << 8) return self.bus.read() @@ -249,7 +249,7 @@ class CPLD: :param att_reg: Attenuator setting string (32 bit) """ self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32, - SPIT_ATT_WR, CS_ATT) + SPIT_ATT_WR, CS_ATT) self.bus.write(att_reg) self.att_reg = att_reg @@ -273,6 +273,6 @@ class CPLD: :return: 32 bit attenuator settings """ self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 32, - SPIT_ATT_RD, CS_ATT) + SPIT_ATT_RD, CS_ATT) self.bus.write(self.att_reg) return self.bus.read() From 9cf88329b2ca62537ee44b148d56b04dce49663b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 8 Oct 2018 11:20:37 +0200 Subject: [PATCH 1281/2457] CONTRIBUTING: correct default licensing --- CONTRIBUTING.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 65fe5d11f..5b4ed45a9 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -119,4 +119,4 @@ then you just add a line saying using your legal name (sorry, no pseudonyms or anonymous contributions.) ARTIQ files that do not contain a license header are copyrighted by M-Labs Limited -and are licensed under GNU GPL version 3. +and are licensed under GNU LGPL version 3 or later. From 469a66db61da4c40d72b8627053821df169a8dbe Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 26 Sep 2018 10:52:08 +0800 Subject: [PATCH 1282/2457] drtio: monitor RTIOClockMultiplier PLL (#1155) Debugging by Tom Harty --- artiq/firmware/runtime/rtio_mgt.rs | 5 ++++- artiq/firmware/satman/main.rs | 18 ++++++++++++++++++ artiq/gateware/targets/kasli.py | 18 +++++++++++++----- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index f2a606d86..a54e8c77a 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -257,6 +257,10 @@ fn async_error_thread(io: Io) { } pub fn startup(io: &Io) { + // The RTIO CRG may depend on the DRTIO transceiver clock. + // Initialize DRTIO first to bring up transceiver clocking. + drtio::startup(io); + #[cfg(has_rtio_crg)] { #[cfg(has_rtio_clock_switch)] @@ -296,7 +300,6 @@ pub fn startup(io: &Io) { } } - drtio::startup(io); init_core(true); io.spawn(4096, async_error_thread); } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index ad2252955..a734e8355 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -229,6 +229,23 @@ fn process_errors() { } } + +#[cfg(has_rtio_crg)] +fn init_rtio_crg() { + unsafe { + csr::rtio_crg::pll_reset_write(0); + } + clock::spin_us(150); + let locked = unsafe { csr::rtio_crg::pll_locked_read() != 0 }; + if !locked { + error!("RTIO clock failed"); + } +} + +#[cfg(not(has_rtio_crg))] +fn init_rtio_crg() { } + + #[cfg(rtio_frequency = "150.0")] const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings { @@ -285,6 +302,7 @@ pub extern fn main() -> i32 { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } + init_rtio_crg(); #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 34f0241dd..cb51e16ec 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -676,19 +676,23 @@ class Tester(_StandaloneBase): self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) -class _RTIOClockMultiplier(Module): +class _RTIOClockMultiplier(Module, AutoCSR): def __init__(self, rtio_clk_freq): + self.pll_reset = CSRStorage(reset=1) + self.pll_locked = CSRStatus() self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) # See "Global Clock Network Deskew Using Two BUFGs" in ug472. clkfbout = Signal() clkfbin = Signal() rtiox4_clk = Signal() + pll_locked = Signal() self.specials += [ Instance("MMCME2_BASE", p_CLKIN1_PERIOD=1e9/rtio_clk_freq, i_CLKIN1=ClockSignal("rtio"), - i_RST=ResetSignal("rtio"), + i_RST=self.pll_reset.storage, + o_LOCKED=pll_locked, p_CLKFBOUT_MULT_F=8.0, p_DIVCLK_DIVIDE=1, @@ -697,7 +701,9 @@ class _RTIOClockMultiplier(Module): p_CLKOUT0_DIVIDE_F=2.0, o_CLKOUT0=rtiox4_clk, ), Instance("BUFG", i_I=clkfbout, o_O=clkfbin), - Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk) + Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), + + MultiReg(pll_locked, self.pll_locked.status) ] @@ -781,7 +787,8 @@ class _MasterBase(MiniSoC, AMPSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.rxoutclk) - self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) + self.submodules.rtio_crg = _RTIOClockMultiplier(rtio_clk_freq) + self.csr_devices.append("rtio_crg") fix_serdes_timing_path(platform) def add_rtio(self, rtio_channels): @@ -906,7 +913,8 @@ class _SatelliteBase(BaseSoC): self.crg.cd_sys.clk, gtp.txoutclk, gtp.rxoutclk) - self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) + self.submodules.rtio_crg = _RTIOClockMultiplier(rtio_clk_freq) + self.csr_devices.append("rtio_crg") fix_serdes_timing_path(platform) def add_rtio(self, rtio_channels): From 08074d52754af33781a9683a3392c12099b37c5c Mon Sep 17 00:00:00 2001 From: hartytp Date: Tue, 9 Oct 2018 22:16:26 +0100 Subject: [PATCH 1283/2457] Urukul: add support for hardware v1.3 clocking options --- artiq/coredevice/urukul.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 8964097e8..7f844ee64 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -25,7 +25,8 @@ CFG_LED = 4 CFG_PROFILE = 8 CFG_IO_UPDATE = 12 CFG_MASK_NU = 13 -CFG_CLK_SEL = 17 +CFG_CLK_SEL0 = 17 +CFG_CLK_SEL1 = 21 CFG_SYNC_SEL = 18 CFG_RST = 19 CFG_IO_RST = 20 @@ -59,7 +60,8 @@ def urukul_cfg(rf_sw, led, profile, io_update, mask_nu, (profile << CFG_PROFILE) | (io_update << CFG_IO_UPDATE) | (mask_nu << CFG_MASK_NU) | - (clk_sel << CFG_CLK_SEL) | + ((clk_sel & 0x01) << CFG_CLK_SEL0) | + ((clk_sel & 0x02) << (CFG_CLK_SEL1-1)) | (sync_sel << CFG_SYNC_SEL) | (rst << CFG_RST) | (io_rst << CFG_IO_RST)) @@ -115,8 +117,11 @@ class CPLD: :param dds_reset_device: DDS reset RTIO TTLOut channel name :param refclk: Reference clock (SMA, MMCX or on-board 100 MHz oscillator) frequency in Hz - :param clk_sel: Reference clock selection. 0 corresponds to the internal - MMCX or ob-board XO clock. 1 corresponds to the front panel SMA. + :param clk_sel: Reference clock selection. For hardware revision >= 1.3 + valid options are: 0 - internal 100MHz XO; 1 - front-panel SMA; 2 + internal MMCX. For hardware revision <= v1.2 valid options are: 0 - + either XO or MMCX dependent on component population; 1 SMA. Unsupported + clocking options are silently ignored. :param sync_sel: SYNC clock selection. 0 corresponds to SYNC clock over EEM from FPGA. 1 corresponds to SYNC clock from DDS0. :param rf_sw: Initial CPLD RF switch register setting (default: 0x0). From 661dd00c4cbe1f9e1c48be467b34f30b96409289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 11 Oct 2018 15:16:08 +0200 Subject: [PATCH 1284/2457] ad9912: phase offset is 14 bit LSB aligned c.f. sinara-hw/Urukul#15 --- artiq/coredevice/ad9912.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 56df7a7ea..a74e98331 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -169,7 +169,7 @@ class AD9912: """Returns the phase offset word corresponding to the given phase. """ - return int32(round((1 << 16)*phase)) + return int32(round((1 << 14)*phase)) @kernel def set(self, frequency, phase=0.0): From 4641ddf002e10fba917d1d379ac649f9492b3653 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 8 Mar 2018 18:58:08 +0000 Subject: [PATCH 1285/2457] master: Remove unused import [nfc] --- artiq/master/log.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/master/log.py b/artiq/master/log.py index 958076505..d759d1309 100644 --- a/artiq/master/log.py +++ b/artiq/master/log.py @@ -1,7 +1,6 @@ import logging import logging.handlers -from artiq.protocols.sync_struct import Notifier from artiq.protocols.logging import SourceFilter From 64b9a377da40cc4544531144996a1589cf9add5c Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 8 Mar 2018 21:40:05 +0000 Subject: [PATCH 1286/2457] master: Factor RIDCounter out into own module, explain worker_db module [nfc] The docstrings are quite minimal still, but should already help with navigating the different layers when getting accustomed with the code base. RIDCounter was moved to its own module, as it isn't really related to the other classes (used from master only). --- artiq/frontend/artiq_master.py | 2 +- artiq/master/rid_counter.py | 84 ++++++++++++++++++++++++++++++++++ artiq/master/worker_db.py | 81 +++----------------------------- 3 files changed, 91 insertions(+), 76 deletions(-) create mode 100644 artiq/master/rid_counter.py diff --git a/artiq/frontend/artiq_master.py b/artiq/frontend/artiq_master.py index 91672f9c6..4583ed6d4 100755 --- a/artiq/frontend/artiq_master.py +++ b/artiq/frontend/artiq_master.py @@ -15,7 +15,7 @@ from artiq.protocols.broadcast import Broadcaster from artiq.master.log import log_args, init_log from artiq.master.databases import DeviceDB, DatasetDB from artiq.master.scheduler import Scheduler -from artiq.master.worker_db import RIDCounter +from artiq.master.rid_counter import RIDCounter from artiq.master.experiments import (FilesystemBackend, GitBackend, ExperimentDB) diff --git a/artiq/master/rid_counter.py b/artiq/master/rid_counter.py new file mode 100644 index 000000000..b4bbbd033 --- /dev/null +++ b/artiq/master/rid_counter.py @@ -0,0 +1,84 @@ +import logging +import os +import tempfile +import re + +logger = logging.getLogger(__name__) + + +class RIDCounter: + """Monotonically incrementing counter for RIDs (experiment run ids). + + A cache is used, but if necessary, the last used rid will be determined + from the given results directory. + """ + + def __init__(self, cache_filename="last_rid.pyon", results_dir="results"): + self.cache_filename = cache_filename + self.results_dir = results_dir + self._next_rid = self._last_rid() + 1 + logger.debug("Next RID is %d", self._next_rid) + + def get(self): + rid = self._next_rid + self._next_rid += 1 + self._update_cache(rid) + return rid + + def _last_rid(self): + try: + rid = self._last_rid_from_cache() + except FileNotFoundError: + logger.debug("Last RID cache not found, scanning results") + rid = self._last_rid_from_results() + self._update_cache(rid) + return rid + else: + logger.debug("Using last RID from cache") + return rid + + def _update_cache(self, rid): + contents = str(rid) + "\n" + directory = os.path.abspath(os.path.dirname(self.cache_filename)) + with tempfile.NamedTemporaryFile("w", dir=directory, delete=False + ) as f: + f.write(contents) + tmpname = f.name + os.replace(tmpname, self.cache_filename) + + def _last_rid_from_cache(self): + with open(self.cache_filename, "r") as f: + return int(f.read()) + + def _last_rid_from_results(self): + r = -1 + try: + day_folders = os.listdir(self.results_dir) + except: + return r + day_folders = filter( + lambda x: re.fullmatch("\\d\\d\\d\\d-\\d\\d-\\d\\d", x), + day_folders) + for df in day_folders: + day_path = os.path.join(self.results_dir, df) + try: + hm_folders = os.listdir(day_path) + except: + continue + hm_folders = filter(lambda x: re.fullmatch("\\d\\d(-\\d\\d)?", x), + hm_folders) + for hmf in hm_folders: + hm_path = os.path.join(day_path, hmf) + try: + h5files = os.listdir(hm_path) + except: + continue + for x in h5files: + m = re.fullmatch( + "(\\d\\d\\d\\d\\d\\d\\d\\d\\d)-.*\\.h5", x) + if m is None: + continue + rid = int(m.group(1)) + if rid > r: + r = rid + return r diff --git a/artiq/master/worker_db.py b/artiq/master/worker_db.py index 1a4ef61e6..3551d4fc9 100644 --- a/artiq/master/worker_db.py +++ b/artiq/master/worker_db.py @@ -1,10 +1,13 @@ +"""Client-side interfaces to the master databases (devices, datasets). + +These artefacts are intended for out-of-process use (i.e. from workers or the +standalone command line tools). +""" + from operator import setitem from collections import OrderedDict import importlib import logging -import os -import tempfile -import re from artiq.protocols.sync_struct import Notifier from artiq.protocols.pc_rpc import AutoTarget, Client, BestEffortClient @@ -13,78 +16,6 @@ from artiq.protocols.pc_rpc import AutoTarget, Client, BestEffortClient logger = logging.getLogger(__name__) -class RIDCounter: - def __init__(self, cache_filename="last_rid.pyon", results_dir="results"): - self.cache_filename = cache_filename - self.results_dir = results_dir - self._next_rid = self._last_rid() + 1 - logger.debug("Next RID is %d", self._next_rid) - - def get(self): - rid = self._next_rid - self._next_rid += 1 - self._update_cache(rid) - return rid - - def _last_rid(self): - try: - rid = self._last_rid_from_cache() - except FileNotFoundError: - logger.debug("Last RID cache not found, scanning results") - rid = self._last_rid_from_results() - self._update_cache(rid) - return rid - else: - logger.debug("Using last RID from cache") - return rid - - def _update_cache(self, rid): - contents = str(rid) + "\n" - directory = os.path.abspath(os.path.dirname(self.cache_filename)) - with tempfile.NamedTemporaryFile("w", dir=directory, delete=False - ) as f: - f.write(contents) - tmpname = f.name - os.replace(tmpname, self.cache_filename) - - def _last_rid_from_cache(self): - with open(self.cache_filename, "r") as f: - return int(f.read()) - - def _last_rid_from_results(self): - r = -1 - try: - day_folders = os.listdir(self.results_dir) - except: - return r - day_folders = filter( - lambda x: re.fullmatch("\\d\\d\\d\\d-\\d\\d-\\d\\d", x), - day_folders) - for df in day_folders: - day_path = os.path.join(self.results_dir, df) - try: - hm_folders = os.listdir(day_path) - except: - continue - hm_folders = filter(lambda x: re.fullmatch("\\d\\d(-\\d\\d)?", x), - hm_folders) - for hmf in hm_folders: - hm_path = os.path.join(day_path, hmf) - try: - h5files = os.listdir(hm_path) - except: - continue - for x in h5files: - m = re.fullmatch( - "(\\d\\d\\d\\d\\d\\d\\d\\d\\d)-.*\\.h5", x) - if m is None: - continue - rid = int(m.group(1)) - if rid > r: - r = rid - return r - - class DummyDevice: pass From e3cfbfed0656076c35b853b9fe2ee3e7f8634bc2 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 8 Mar 2018 21:50:48 +0000 Subject: [PATCH 1287/2457] master: Add minimal docstring to worker_impl [nfc] --- artiq/master/worker_impl.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index a3db42d1a..6a2df4cfd 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -1,3 +1,11 @@ +"""Worker process implementation. + +This module contains the worker process main() function and the glue code +necessary to connect the global artefacts used from experiment code (scheduler, +device database, etc.) to their actual implementation in the parent master +process via IPC. +""" + import sys import time import os From 6357a50d33fdc168a0f445f01c546c88a48f821a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 15 Oct 2018 18:04:57 +0800 Subject: [PATCH 1288/2457] kasli: update nudt variant --- artiq/examples/kasli_basic/device_db_nudt.py | 192 +++++++++++++++++++ artiq/gateware/targets/kasli.py | 3 +- 2 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 artiq/examples/kasli_basic/device_db_nudt.py diff --git a/artiq/examples/kasli_basic/device_db_nudt.py b/artiq/examples/kasli_basic/device_db_nudt.py new file mode 100644 index 000000000..b21b53ccb --- /dev/null +++ b/artiq/examples/kasli_basic/device_db_nudt.py @@ -0,0 +1,192 @@ +core_addr = "kasli-1.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + + +# DIO (EEM5) starting at RTIO channel 0 +# DIO (EEM6) starting at RTIO channel 8 +for i in range(16): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": i}, + } + + +# Urukul (EEM1) starting at RTIO channel 16 +device_db.update( + spi_urukul0={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 16} + }, + ttl_urukul0_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 17} + }, + ttl_urukul0_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 18} + }, + ttl_urukul0_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 19} + }, + ttl_urukul0_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 20} + }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 21} + }, + urukul0_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul0_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } + + +# Sampler (EEM3) starting at RTIO channel 22 +device_db["spi_sampler0_adc"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 22} +} +device_db["spi_sampler0_pgia"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 23} +} +device_db["spi_sampler0_cnv"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 24}, +} +device_db["sampler0"] = { + "type": "local", + "module": "artiq.coredevice.sampler", + "class": "Sampler", + "arguments": { + "spi_adc_device": "spi_sampler0_adc", + "spi_pgia_device": "spi_sampler0_pgia", + "cnv_device": "spi_sampler0_cnv" + } +} + + +# Zotino (EEM4) starting at RTIO channel 25 +device_db["spi_zotino0"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 25} +} +device_db["ttl_zotino0_ldac"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 26} +} +device_db["ttl_zotino0_clr"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 27} +} +device_db["zotino0"] = { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino0", + "ldac_device": "ttl_zotino0_ldac", + "clr_device": "ttl_zotino0_clr" + } +} + +device_db.update( + led0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 28} + }, + led1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 29} + }, +) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index cb51e16ec..79c93dfcc 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -457,7 +457,6 @@ class WIPM(_StandaloneBase): class NUDT(_StandaloneBase): - # Like Tester, but fewer peripherals and newer Sampler def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" @@ -473,6 +472,8 @@ class NUDT(_StandaloneBase): self.rtio_channels = [] eem.DIO.add_std(self, 5, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 6, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) eem.Urukul.add_std(self, 0, 1, ttl_serdes_7series.Output_8X) eem.Sampler.add_std(self, 2, 3, ttl_serdes_7series.Output_8X) eem.Zotino.add_std(self, 4, ttl_serdes_7series.Output_8X) From 3318925f4ebbd1996a09e4e558e51f0592292e5b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Tue, 16 Oct 2018 09:40:39 +0200 Subject: [PATCH 1289/2457] firmware/liboard_misoc/sdram: use similar loops on read_level_scan and read_level for consistent results --- artiq/firmware/libboard_misoc/sdram.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/libboard_misoc/sdram.rs b/artiq/firmware/libboard_misoc/sdram.rs index a4de6fcb8..0c41e6c0e 100644 --- a/artiq/firmware/libboard_misoc/sdram.rs +++ b/artiq/firmware/libboard_misoc/sdram.rs @@ -244,13 +244,13 @@ mod ddr { ddrphy::rdly_dq_rst_write(1); for _ in 0..DDRPHY_MAX_DELAY { - sdram_phy::command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS| - DFII_COMMAND_RDDATA); - spin_cycles(15); - let mut working = true; - for p in 0..DFII_NPHASES { - for _ in 0..1024 { + for _ in 0..256 { + sdram_phy::command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS| + DFII_COMMAND_RDDATA); + spin_cycles(15); + + for p in 0..DFII_NPHASES { for &offset in [n, n + DQS_SIGNAL_COUNT].iter() { let addr = DFII_PIX_RDDATA_ADDR[p].offset(offset as isize); let data = prs[DFII_PIX_DATA_SIZE * p + offset]; From c52a6ca8e98ab9b2229e9e4012af0e0646f6eace Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 20 Oct 2018 20:40:07 +0800 Subject: [PATCH 1290/2457] typo (#1179) --- artiq/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/tools.py b/artiq/tools.py index f7a399db7..69d8351b5 100644 --- a/artiq/tools.py +++ b/artiq/tools.py @@ -117,7 +117,7 @@ def simple_network_args(parser, default_port): group = parser.add_argument_group("network server") group.add_argument( "--bind", default=[], action="append", - help="additional hostname or IP addresse to bind to; " + help="additional hostname or IP address to bind to; " "use '*' to bind to all interfaces (default: %(default)s)") group.add_argument( "--no-localhost-bind", default=False, action="store_true", From a84c6c6d749d674008f18024defee286f1c1bd7c Mon Sep 17 00:00:00 2001 From: Drew Date: Sat, 20 Oct 2018 08:43:19 -0400 Subject: [PATCH 1291/2457] Add issue & pull request templates (#1163) --- .github/ISSUE_TEMPLATE/1_Bug_Report.md | 48 ++++++++++++++ .github/ISSUE_TEMPLATE/2_Feature_Request.md | 28 +++++++++ .github/ISSUE_TEMPLATE/3_Question.md | 25 ++++++++ .github/pull_request_template.md | 69 +++++++++++++++++++++ 4 files changed, 170 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/1_Bug_Report.md create mode 100644 .github/ISSUE_TEMPLATE/2_Feature_Request.md create mode 100644 .github/ISSUE_TEMPLATE/3_Question.md create mode 100644 .github/pull_request_template.md diff --git a/.github/ISSUE_TEMPLATE/1_Bug_Report.md b/.github/ISSUE_TEMPLATE/1_Bug_Report.md new file mode 100644 index 000000000..0442cafa4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1_Bug_Report.md @@ -0,0 +1,48 @@ +--- +name: Bug report +about: Report a bug in ARTIQ + +--- + + + +# Bug Report + + + +## One-Line Summary + +Short summary. + +## Issue Details + +### Steps to Reproduce + +1. Step 1. +2. Step 2. +3. Step 3. + +### Expected Behavior + +Behavior + +### Actual (undesired) Behavior + +* Text description +* Log message, tracebacks, screen shots where relevant + +### Your System + +* Operating System: +* Conda version: +* ARTIQ version: (package or git commit id, versions for bitstream, bootloader, runtime and host software). Run `conda list` +* Hardware involved: + + diff --git a/.github/ISSUE_TEMPLATE/2_Feature_Request.md b/.github/ISSUE_TEMPLATE/2_Feature_Request.md new file mode 100644 index 000000000..d0d02f1e0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2_Feature_Request.md @@ -0,0 +1,28 @@ +--- +name: Feature request +about: Suggest an idea for ARTIQ + +--- + + + +# ARTIQ Feature Request + +## Problem this request addresses + +A clear and concise description of what the problem is. + +## Describe the solution you'd like + +A clear and concise description of what you want to happen. + +## Additional context + +Add any other context about the feature request here. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/3_Question.md b/.github/ISSUE_TEMPLATE/3_Question.md new file mode 100644 index 000000000..8455c7966 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3_Question.md @@ -0,0 +1,25 @@ +--- +name: Support question +about: Questions about ARTIQ that are not covered in the documentation (Latest: https://m-labs.hk/artiq/manual-master/ or Stable: https://m-labs.hk/artiq/manual/) + +--- + +# Question + + + +## Category: FILL_IN + + + +## Description + +Question text diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..22b5b9ba2 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,69 @@ + + +# ARTIQ Pull Request + +## Steps (Choose relevant, delete irrelevant before submitting) + +### All Pull Requests + +- [x] Use correct spelling and grammar. +- [ ] Update [RELEASE_NOTES.md](../RELEASE_NOTES.md) if there are noteworthy changes, especially if there are changes to existing APIs. +- [ ] Close/update issues. +- [ ] Check the copyright situation of your changes and sign off your patches (`git commit --signoff`, see [copyright](../CONTRIBUTING.rst#copyright-and-sign-off)). + +### Code Changes + +- [ ] Run `flake8` to check code style (follow PEP-8 style). `flake8` has issues with parsing Migen/gateware code, ignore as necessary. +- [ ] Test your changes or have someone test them. Mention what was tested and how. +- [ ] Add and check docstrings and comments +- [ ] Check, test, and update the conda recipes in [conda/](../doc/) +- [ ] Check, test, and update the [unittests in /artiq/test/](../artiq/test/) or [gateware simulations in /artiq/gateware/test](../artiq/gateware/test) + +### Documentation Changes + +- [ ] Check, test, and update the documentation in [doc/](../doc/). Build documentation (`cd doc; make html`) to ensure no errors. + +### Git Logistics + +- [ ] Split your contribution into logically separate changes (`git rebase --interactive`). Merge/squash/fixup commits that just fix or amend previous commits. Remove unintended changes & cleanup. See [tutorial](https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase). +- [ ] Write short & meaningful commit messages. Review each commit for messages (`git show`). Format: + ``` + [topic]: description. < 50 characters total. + Longer description. < 70 characters per line + ``` +## Description of Changes + +### Related Issue + + + +## Type of Changes + + +| | Type | +| ------------- | ------------- | +| ✓ | :bug: Bug fix | +| ✓ | :sparkles: New feature | +| ✓ | :hammer: Refactoring | +| ✓ | :scroll: Docs | + + +### Licensing + +See [copyright & licensing for more info](https://github.com/m-labs/artiq/blob/master/CONTRIBUTING.rst#copyright-and-sign-off). +ARTIQ files that do not contain a license header are copyrighted by M-Labs Limited and are licensed under LGPLv3+. From 029f9d983ae6e8d79013ea9045c398cab03d371f Mon Sep 17 00:00:00 2001 From: Marius Weber Date: Sat, 20 Oct 2018 13:49:15 +0100 Subject: [PATCH 1292/2457] Tpz fixes (#1178) * flake8 * fix TPZ constructor after move to asyncio * Tcube fix docummentation in set_channel_enable_state --- artiq/devices/thorlabs_tcube/driver.py | 104 ++++++++++++++----------- artiq/frontend/aqctl_thorlabs_tcube.py | 2 + 2 files changed, 59 insertions(+), 47 deletions(-) diff --git a/artiq/devices/thorlabs_tcube/driver.py b/artiq/devices/thorlabs_tcube/driver.py index 545887e18..10bb6ea9c 100644 --- a/artiq/devices/thorlabs_tcube/driver.py +++ b/artiq/devices/thorlabs_tcube/driver.py @@ -207,7 +207,8 @@ class _Tcube: # derived classes must implement this raise NotImplementedError - async def send_request(self, msgreq_id, wait_for_msgs, param1=0, param2=0, data=None): + async def send_request(self, msgreq_id, wait_for_msgs, param1=0, param2=0, + data=None): await self.send(Message(msgreq_id, param1, param2, data=data)) msg = None while msg is None or msg.id not in wait_for_msgs: @@ -218,7 +219,7 @@ class _Tcube: async def set_channel_enable_state(self, activated): """Enable or Disable channel 1. - :param activated: 1 to enable channel, 2 to disable it. + :param activated: 1 to enable channel, 0 to disable it. """ if activated: @@ -283,9 +284,13 @@ class _Tcube: class Tpz(_Tcube): + """Either :py:meth:`set_tpz_io_settings()` + or :py:meth:`get_tpz_io_settings()` must + be completed to finish initialising the driver. + """ def __init__(self, serial_dev): _Tcube.__init__(self, serial_dev) - self.voltage_limit = self.get_tpz_io_settings()[0] + self.voltage_limit = None async def handle_message(self, msg): msg_id = msg.id @@ -336,7 +341,7 @@ class Tpz(_Tcube): :rtype: int """ get_msg = await self.send_request(MGMSG.PZ_REQ_POSCONTROLMODE, - [MGMSG.PZ_GET_POSCONTROLMODE], 1) + [MGMSG.PZ_GET_POSCONTROLMODE], 1) return get_msg.param2 async def set_output_volts(self, voltage): @@ -348,9 +353,8 @@ class Tpz(_Tcube): :param voltage: The output voltage applied to the piezo when operating in open loop mode. The voltage value must be in range [0; voltage_limit]. Voltage_limit being set by the - :py:meth:`set_tpz_io_settings() - ` method - between the three values 75 V, 100 V and 150 V. + :py:meth:`set_tpz_io_settings()` + method between the three values 75 V, 100 V and 150 V. """ if voltage < 0 or voltage > self.voltage_limit: raise ValueError("Voltage must be in range [0;{}]" @@ -366,7 +370,7 @@ class Tpz(_Tcube): :rtype: float """ get_msg = await self.send_request(MGMSG.PZ_REQ_OUTPUTVOLTS, - [MGMSG.PZ_GET_OUTPUTVOLTS], 1) + [MGMSG.PZ_GET_OUTPUTVOLTS], 1) return st.unpack("` method. + ` method. 0x01 External Signal: Unit sums the differential signal on the rear panel EXT IN(+) and EXT IN(-) connectors with the voltage set @@ -426,13 +430,12 @@ class Tpz(_Tcube): amplifier circuit. :return: Value which selects the various analog sources, cf. - :py:meth:`set_input_volts_source() - ` method - docstring for meaning of bits. + :py:meth:`set_input_volts_source()` + method docstring for meaning of bits. :rtype: int """ get_msg = await self.send_request(MGMSG.PZ_REQ_INPUTVOLTSSRC, - [MGMSG.PZ_GET_INPUTVOLTSSRC], 1) + [MGMSG.PZ_GET_INPUTVOLTSSRC], 1) return st.unpack("` + ` function), then only the first cyclelength values need to be set. In this manner, any arbitrary voltage waveform can be programmed into the LUT. Note. The LUT values are output by the system at a maximum @@ -499,8 +502,8 @@ class Tpz(_Tcube): to 512 for TPZ). :param output: The voltage value to be set. Values are in the range [0; voltage_limit]. Voltage_limit being set with the - :py:meth:`set_tpz_io_settings - ` method. + :py:meth:`set_tpz_io_settings` + method. """ volt = round(output*32767/self.voltage_limit) payload = st.pack("` for the - meaning of those parameters. + ` for + the meaning of those parameters. :rtype: a 2 elements tuple (int, int) """ get_msg = await self.send_request(MGMSG.PZ_REQ_TPZ_IOSETTINGS, @@ -760,8 +764,7 @@ class Tdc(_Tcube): :return: An 8 int tuple containing the following values: zero_wnd, vel1, wnd1, vel2, wnd2, vel3, wnd3, vel4. See - :py:meth:`set_pot_parameters() - ` for a + :py:meth:`set_pot_parameters()` for a description of each tuple element meaning. :rtype: An 8 int tuple """ @@ -839,7 +842,7 @@ class Tdc(_Tcube): return st.unpack("` + ` method. :rtype: A 2 int tuple. """ @@ -1001,11 +1005,13 @@ class Tdc(_Tcube): The relative distance parameter used for the move will be the parameter sent previously by a :py:meth:`set_move_relative_parameters() - ` + ` command. """ await self.send_request(MGMSG.MOT_MOVE_RELATIVE, - [MGMSG.MOT_MOVE_COMPLETED, MGMSG.MOT_MOVE_STOPPED], 1) + [MGMSG.MOT_MOVE_COMPLETED, + MGMSG.MOT_MOVE_STOPPED], + 1) async def move_relative(self, relative_distance): """Start a relative move @@ -1015,7 +1021,8 @@ class Tdc(_Tcube): """ payload = st.pack("` + ` command. """ await self.send_request(MGMSG.MOT_MOVE_ABSOLUTE, - [MGMSG.MOT_MOVE_COMPLETED, MGMSG.MOT_MOVE_STOPPED], + [MGMSG.MOT_MOVE_COMPLETED, + MGMSG.MOT_MOVE_STOPPED], param1=1) async def move_absolute(self, absolute_distance): @@ -1039,7 +1047,8 @@ class Tdc(_Tcube): """ payload = st.pack("` - command until a :py:meth:`move_stop() - ` command (either + ` + command until a :py:meth:`move_stop()` command (either StopImmediate or StopProfiled) is called, or a limit switch is reached. :param direction: The direction to jog: 1 to move forward, 2 to move backward. """ - await self.send(Message(MGMSG.MOT_MOVE_VELOCITY, param1=1, param2=direction)) + await self.send(Message(MGMSG.MOT_MOVE_VELOCITY, param1=1, + param2=direction)) async def move_stop(self, stop_mode): """Stop any type of motor move. @@ -1080,11 +1090,11 @@ class Tdc(_Tcube): if await self.is_moving(): await self.send_request(MGMSG.MOT_MOVE_STOP, [MGMSG.MOT_MOVE_STOPPED, - MGMSG.MOT_MOVE_COMPLETED], + MGMSG.MOT_MOVE_COMPLETED], 1, stop_mode) async def set_dc_pid_parameters(self, proportional, integral, differential, - integral_limit, filter_control=0x0F): + integral_limit, filter_control=0x0F): """Set the position control loop parameters. :param proportional: The proportional gain, values in range [0; 32767]. @@ -1108,8 +1118,8 @@ class Tdc(_Tcube): :return: A 5 int tuple containing in this order: proportional gain, integral gain, differential gain, integral limit and filter control. Cf. :py:meth:`set_dc_pid_parameters() - ` for - precise description. + ` + for precise description. :rtype: A 5 int tuple. """ get_msg = await self.send_request(MGMSG.MOT_REQ_DCPIDPARAMS, @@ -1151,10 +1161,10 @@ class Tdc(_Tcube): :param mode: If set to 1, the buttons are used to jog the motor. Once set to this mode, the move parameters for the buttons are taken from the arguments of the :py:meth:`set_jog_parameters() - ` method. - If set to 2, each button can be programmed with a differente - position value such that the controller will move the motor to that - position when the specific button is pressed. + ` + method. If set to 2, each button can be programmed with a + differente position value such that the controller will move the + motor to that position when the specific button is pressed. :param position1: The position (in encoder counts) to which the motor will move when the top button is pressed. :param position2: The position (in encoder counts) to which the motor @@ -1169,8 +1179,8 @@ class Tdc(_Tcube): :return: A 3 int tuple containing in this order: button mode, position1 and position2. Cf. :py:meth:`set_button_parameters() - ` for - description. + ` + for description. :rtype: A 3 int tuple """ get_msg = await self.send_request(MGMSG.MOT_REQ_BUTTONPARAMS, diff --git a/artiq/frontend/aqctl_thorlabs_tcube.py b/artiq/frontend/aqctl_thorlabs_tcube.py index bb9e5b716..e8e489c3e 100755 --- a/artiq/frontend/aqctl_thorlabs_tcube.py +++ b/artiq/frontend/aqctl_thorlabs_tcube.py @@ -53,6 +53,8 @@ def main(): dev = Tdc(args.device) elif product == "tpz001": dev = Tpz(args.device) + loop = asyncio.get_event_loop() + loop.run_until_complete(dev.get_tpz_io_settings()) else: print("Invalid product string (-P/--product), " "choose from tdc001 or tpz001") From 979363228288c836229578bb183928671250be7c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 21 Oct 2018 12:08:34 +0800 Subject: [PATCH 1293/2457] enviromnment: rename 'save' in set_dataset to 'archive'. Closes #1171 --- RELEASE_NOTES.rst | 2 ++ artiq/examples/no_hardware/repository/code_applet.py | 2 +- .../no_hardware/repository/flopping_f_simulation.py | 10 +++++----- artiq/examples/no_hardware/repository/histograms.py | 6 +++--- .../no_hardware/repository/remote_exec_demo.py | 12 ++++++------ artiq/language/environment.py | 12 +++++++++--- artiq/master/worker_db.py | 4 ++-- 7 files changed, 28 insertions(+), 20 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 0c96a5cd4..ab4196181 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -39,6 +39,8 @@ ARTIQ-4 is no longer necessary. * The configuration entry ``startup_clock`` is renamed ``rtio_clock``. Switching clocks dynamically (i.e. without device restart) is no longer supported. +* ``set_dataset(..., save=True)`` has been renamed + ``set_dataset(..., archive=True)``. ARTIQ-3 diff --git a/artiq/examples/no_hardware/repository/code_applet.py b/artiq/examples/no_hardware/repository/code_applet.py index a1e5f2f56..4026cea55 100644 --- a/artiq/examples/no_hardware/repository/code_applet.py +++ b/artiq/examples/no_hardware/repository/code_applet.py @@ -23,7 +23,7 @@ class CreateCodeApplet(EnvExperiment): "code_applet_dataset", code=f.read(), group="autoapplet") for i in reversed(range(10)): self.set_dataset("code_applet_dataset", i, - broadcast=True, save=False) + broadcast=True, archive=False) time.sleep(1) self.ccb.issue("disable_applet", "code_applet_example", group="autoapplet") diff --git a/artiq/examples/no_hardware/repository/flopping_f_simulation.py b/artiq/examples/no_hardware/repository/flopping_f_simulation.py index c8f9b94ea..d79aa11ba 100644 --- a/artiq/examples/no_hardware/repository/flopping_f_simulation.py +++ b/artiq/examples/no_hardware/repository/flopping_f_simulation.py @@ -35,12 +35,12 @@ class FloppingF(EnvExperiment): l = len(self.frequency_scan) self.set_dataset("flopping_f_frequency", np.full(l, np.nan), - broadcast=True, save=False) + broadcast=True, archive=False) self.set_dataset("flopping_f_brightness", np.full(l, np.nan), broadcast=True) self.set_dataset("flopping_f_fit", np.full(l, np.nan), - broadcast=True, save=False) + broadcast=True, archive=False) self.ccb.issue("create_applet", "flopping_f", "${artiq_applet}plot_xy " @@ -66,14 +66,14 @@ class FloppingF(EnvExperiment): frequency = np.fromiter(self.frequency_scan, np.float) assert frequency.shape == brightness.shape self.set_dataset("flopping_f_frequency", frequency, - broadcast=True, save=False) + broadcast=True, archive=False) popt, pcov = curve_fit(model, frequency, brightness, p0=[self.get_dataset("flopping_freq", 1500.0, archive=False)]) perr = np.sqrt(np.diag(pcov)) if perr < 0.1: F0 = float(popt) - self.set_dataset("flopping_freq", F0, persist=True, save=False) + self.set_dataset("flopping_freq", F0, persist=True, archive=False) self.set_dataset("flopping_f_fit", np.array([model(x, F0) for x in frequency]), - broadcast=True, save=False) + broadcast=True, archive=False) diff --git a/artiq/examples/no_hardware/repository/histograms.py b/artiq/examples/no_hardware/repository/histograms.py index c7a0d1a3c..8f12d8eb6 100644 --- a/artiq/examples/no_hardware/repository/histograms.py +++ b/artiq/examples/no_hardware/repository/histograms.py @@ -13,15 +13,15 @@ class Histograms(EnvExperiment): bin_boundaries = np.linspace(-10, 30, nbins + 1) self.set_dataset("hd_bins", bin_boundaries, - broadcast=True, save=False) + broadcast=True, archive=False) xs = np.empty(npoints) xs.fill(np.nan) self.set_dataset("hd_xs", xs, - broadcast=True, save=False) + broadcast=True, archive=False) self.set_dataset("hd_counts", np.empty((npoints, nbins)), - broadcast=True, save=False) + broadcast=True, archive=False) for i in range(npoints): histogram, _ = np.histogram(np.random.normal(i, size=1000), diff --git a/artiq/examples/no_hardware/repository/remote_exec_demo.py b/artiq/examples/no_hardware/repository/remote_exec_demo.py index a4028f764..c347d43be 100644 --- a/artiq/examples/no_hardware/repository/remote_exec_demo.py +++ b/artiq/examples/no_hardware/repository/remote_exec_demo.py @@ -25,10 +25,10 @@ class RemoteExecDemo(EnvExperiment): def transfer_parameters(self, parameters): w, h, cx, cy = parameters - self.set_dataset("rexec_demo.gaussian_w", w, save=False, broadcast=True) - self.set_dataset("rexec_demo.gaussian_h", h, save=False, broadcast=True) - self.set_dataset("rexec_demo.gaussian_cx", cx, save=False, broadcast=True) - self.set_dataset("rexec_demo.gaussian_cy", cy, save=False, broadcast=True) + self.set_dataset("rexec_demo.gaussian_w", w, archive=False, broadcast=True) + self.set_dataset("rexec_demo.gaussian_h", h, archive=False, broadcast=True) + self.set_dataset("rexec_demo.gaussian_cx", cx, archive=False, broadcast=True) + self.set_dataset("rexec_demo.gaussian_cy", cy, archive=False, broadcast=True) def fps_meter(self): t = time.monotonic() @@ -37,7 +37,7 @@ class RemoteExecDemo(EnvExperiment): dt = t - self.last_pt_update if dt >= 5: pt = dt/self.iter_count - self.set_dataset("rexec_demo.picture_pt", pt, save=False, broadcast=True) + self.set_dataset("rexec_demo.picture_pt", pt, archive=False, broadcast=True) self.last_pt_update = t self.iter_count = 0 else: @@ -50,7 +50,7 @@ class RemoteExecDemo(EnvExperiment): data = self.camera_sim.get_picture() if self.show_picture: self.set_dataset("rexec_demo.picture", data, - save=False, broadcast=True) + archive=False, broadcast=True) if self.enable_fit: p = remote_exec_processing.fit(data, self.get_dataset) self.transfer_parameters(p) diff --git a/artiq/language/environment.py b/artiq/language/environment.py index 3bb33647d..b7db5d54d 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -1,3 +1,4 @@ +import warnings from collections import OrderedDict from inspect import isclass @@ -286,7 +287,7 @@ class HasEnvironment: @rpc(flags={"async"}) def set_dataset(self, key, value, - broadcast=False, persist=False, save=True): + broadcast=False, persist=False, archive=True, save=None): """Sets the contents and handling modes of a dataset. Datasets must be scalars (``bool``, ``int``, ``float`` or NumPy scalar) @@ -296,10 +297,15 @@ class HasEnvironment: dispatches it. :param persist: the master should store the data on-disk. Implies broadcast. - :param save: the data is saved into the local storage of the current + :param archive: the data is saved into the local storage of the current run (archived as a HDF5 file). + :param save: deprecated. """ - self.__dataset_mgr.set(key, value, broadcast, persist, save) + if save is not None: + warnings.warn("set_dataset save parameter is deprecated, " + "use archive instead", DeprecationWarning) + archive = save + self.__dataset_mgr.set(key, value, broadcast, persist, archive) @rpc(flags={"async"}) def mutate_dataset(self, key, index, value): diff --git a/artiq/master/worker_db.py b/artiq/master/worker_db.py index 3551d4fc9..356a79bef 100644 --- a/artiq/master/worker_db.py +++ b/artiq/master/worker_db.py @@ -117,7 +117,7 @@ class DatasetManager: self.ddb = ddb self.broadcast.publish = ddb.update - def set(self, key, value, broadcast=False, persist=False, save=True): + def set(self, key, value, broadcast=False, persist=False, archive=True): if key in self.archive: logger.warning("Modifying dataset '%s' which is in archive, " "archive will remain untouched", @@ -129,7 +129,7 @@ class DatasetManager: self.broadcast[key] = persist, value elif key in self.broadcast.read: del self.broadcast[key] - if save: + if archive: self.local[key] = value elif key in self.local: del self.local[key] From 48a142ed6335c3687775a8197e817d081d7bf120 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 21 Oct 2018 12:14:51 +0800 Subject: [PATCH 1294/2457] use FutureWarning instead of DeprecationWarning DeprecationWarning is disabled by default and too easy to ignore. --- artiq/gateware/rtio/channel.py | 2 +- artiq/language/environment.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/channel.py b/artiq/gateware/rtio/channel.py index 5e85a1add..d7b9a60e4 100644 --- a/artiq/gateware/rtio/channel.py +++ b/artiq/gateware/rtio/channel.py @@ -17,7 +17,7 @@ class Channel: if ofifo_depth is None: ofifo_depth = 64 else: - warnings.warn("ofifo_depth is deprecated", DeprecationWarning) + warnings.warn("ofifo_depth is deprecated", FutureWarning) self.ofifo_depth = ofifo_depth self.ififo_depth = ififo_depth diff --git a/artiq/language/environment.py b/artiq/language/environment.py index b7db5d54d..5eb4e8d81 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -303,7 +303,7 @@ class HasEnvironment: """ if save is not None: warnings.warn("set_dataset save parameter is deprecated, " - "use archive instead", DeprecationWarning) + "use archive instead", FutureWarning) archive = save self.__dataset_mgr.set(key, value, broadcast, persist, archive) From 0b43ec4719dd67aa0d839a9e9c69e26783481bdf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 21 Oct 2018 14:33:14 +0800 Subject: [PATCH 1295/2457] conda: bump migen --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 5507adb1b..48d448b2e 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,7 +14,7 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.7 py35_73+gitbef9dea + - migen 0.8 py35_0+git2d62c0c - misoc 0.11 py35_31+git5ce139dd - jesd204b 0.10 - microscope From 761d30d9986d6552e771a6f0e94cefe58259d3c1 Mon Sep 17 00:00:00 2001 From: Drew Date: Mon, 22 Oct 2018 14:22:55 -0400 Subject: [PATCH 1296/2457] [template]: Reorder pull request template PR template wasn't in a logical order, hard for maintainers to read. Reorganized. Fix directory where docs are built from. Signed-off-by: Drew Risinger --- .github/pull_request_template.md | 58 ++++++++++++++++---------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 22b5b9ba2..7c50ac1cd 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -12,35 +12,6 @@ Based on https://raw.githubusercontent.com/PyCQA/pylint/master/.github/PULL_REQU # ARTIQ Pull Request -## Steps (Choose relevant, delete irrelevant before submitting) - -### All Pull Requests - -- [x] Use correct spelling and grammar. -- [ ] Update [RELEASE_NOTES.md](../RELEASE_NOTES.md) if there are noteworthy changes, especially if there are changes to existing APIs. -- [ ] Close/update issues. -- [ ] Check the copyright situation of your changes and sign off your patches (`git commit --signoff`, see [copyright](../CONTRIBUTING.rst#copyright-and-sign-off)). - -### Code Changes - -- [ ] Run `flake8` to check code style (follow PEP-8 style). `flake8` has issues with parsing Migen/gateware code, ignore as necessary. -- [ ] Test your changes or have someone test them. Mention what was tested and how. -- [ ] Add and check docstrings and comments -- [ ] Check, test, and update the conda recipes in [conda/](../doc/) -- [ ] Check, test, and update the [unittests in /artiq/test/](../artiq/test/) or [gateware simulations in /artiq/gateware/test](../artiq/gateware/test) - -### Documentation Changes - -- [ ] Check, test, and update the documentation in [doc/](../doc/). Build documentation (`cd doc; make html`) to ensure no errors. - -### Git Logistics - -- [ ] Split your contribution into logically separate changes (`git rebase --interactive`). Merge/squash/fixup commits that just fix or amend previous commits. Remove unintended changes & cleanup. See [tutorial](https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase). -- [ ] Write short & meaningful commit messages. Review each commit for messages (`git show`). Format: - ``` - [topic]: description. < 50 characters total. - Longer description. < 70 characters per line - ``` ## Description of Changes ### Related Issue @@ -62,6 +33,35 @@ Closes #XXX | ✓ | :hammer: Refactoring | | ✓ | :scroll: Docs | +## Steps (Choose relevant, delete irrelevant before submitting) + +### All Pull Requests + +- [x] Use correct spelling and grammar. +- [ ] Update [RELEASE_NOTES.md](../RELEASE_NOTES.md) if there are noteworthy changes, especially if there are changes to existing APIs. +- [ ] Close/update issues. +- [ ] Check the copyright situation of your changes and sign off your patches (`git commit --signoff`, see [copyright](../CONTRIBUTING.rst#copyright-and-sign-off)). + +### Code Changes + +- [ ] Run `flake8` to check code style (follow PEP-8 style). `flake8` has issues with parsing Migen/gateware code, ignore as necessary. +- [ ] Test your changes or have someone test them. Mention what was tested and how. +- [ ] Add and check docstrings and comments +- [ ] Check, test, and update the conda recipes in [conda/](../doc/) +- [ ] Check, test, and update the [unittests in /artiq/test/](../artiq/test/) or [gateware simulations in /artiq/gateware/test](../artiq/gateware/test) + +### Documentation Changes + +- [ ] Check, test, and update the documentation in [doc/](../doc/). Build documentation (`cd doc/manual/; make html`) to ensure no errors. + +### Git Logistics + +- [ ] Split your contribution into logically separate changes (`git rebase --interactive`). Merge/squash/fixup commits that just fix or amend previous commits. Remove unintended changes & cleanup. See [tutorial](https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase). +- [ ] Write short & meaningful commit messages. Review each commit for messages (`git show`). Format: + ``` + [topic]: description. < 50 characters total. + Longer description. < 70 characters per line + ``` ### Licensing From 4e04b6b4dd029a50baf923dcd0c0391fc8e5eb4b Mon Sep 17 00:00:00 2001 From: Drew Date: Mon, 22 Oct 2018 19:41:51 -0400 Subject: [PATCH 1297/2457] [template]: fix 3_question.md template use of ":" Question.md didn't display on ARTIQ new issue page. Solution: Cannot use ":" in Markdown header Signed-off-by: Drew Risinger --- .github/ISSUE_TEMPLATE/3_Question.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/3_Question.md b/.github/ISSUE_TEMPLATE/3_Question.md index 8455c7966..4a463d293 100644 --- a/.github/ISSUE_TEMPLATE/3_Question.md +++ b/.github/ISSUE_TEMPLATE/3_Question.md @@ -1,6 +1,6 @@ --- name: Support question -about: Questions about ARTIQ that are not covered in the documentation (Latest: https://m-labs.hk/artiq/manual-master/ or Stable: https://m-labs.hk/artiq/manual/) +about: Questions about ARTIQ that are not covered in the documentation. (Latest = https://m-labs.hk/artiq/manual-master/ or Stable = https://m-labs.hk/artiq/manual/) --- From 89a961fb00188f0de1876f5f5da547b9fb44c595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 24 Oct 2018 11:01:13 +0000 Subject: [PATCH 1298/2457] urukul, ad9912, ad9910: expose CFG RF switch better * conincident setting of multiple switches * per channel setting --- artiq/coredevice/ad9910.py | 10 ++++++++++ artiq/coredevice/ad9912.py | 10 ++++++++++ artiq/coredevice/urukul.py | 8 ++++++++ 3 files changed, 28 insertions(+) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 59ca91855..c7e1b49a1 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -230,3 +230,13 @@ class AD9910: :param att: Attenuation in dB. """ self.cpld.set_att(self.chip_select - 4, att) + + @kernel + def cfg_sw(self, state): + """Set CPLD CFG RF switch state. The RF switch is controlled by the + logical or of the CPLD configuration shift register + RF switch bit and the SW TTL line (if used). + + :param state: CPLD CFG RF switch bit + """ + self.cpld.cfg_sw(self.chip_select - 4, state) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index a74e98331..749fd5e00 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -182,3 +182,13 @@ class AD9912: """ self.set_mu(self.frequency_to_ftw(frequency), self.turns_to_pow(phase)) + + @kernel + def cfg_sw(self, state): + """Set CPLD CFG RF switch state. The RF switch is controlled by the + logical or of the CPLD configuration shift register + RF switch bit and the SW TTL line (if used). + + :param state: CPLD CFG RF switch bit + """ + self.cpld.cfg_sw(self.chip_select - 4, state) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 7f844ee64..fe9c1a68c 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -231,6 +231,14 @@ class CPLD: c &= ~(1 << channel) self.cfg_write(c) + @kernel + def cfg_switches(self, state): + """Configure all four RF switches through the configuration register. + + :param state: RF switch state as a 4 bit integer. + """ + self.cfg_write((self.cfg_reg & ~0xf) | state) + @kernel def set_att_mu(self, channel, att): """Set digital step attenuator in machine units. From 91f0d640e246086550e3c3021337e2cd19853ab7 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 25 Oct 2018 22:01:14 +0100 Subject: [PATCH 1299/2457] .github: Match suggested commit message format to established convention This changes the suggested format for commit messages to match the convention actually used here (no square brackets). --- .github/pull_request_template.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 7c50ac1cd..43e978157 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -59,7 +59,8 @@ Closes #XXX - [ ] Split your contribution into logically separate changes (`git rebase --interactive`). Merge/squash/fixup commits that just fix or amend previous commits. Remove unintended changes & cleanup. See [tutorial](https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase). - [ ] Write short & meaningful commit messages. Review each commit for messages (`git show`). Format: ``` - [topic]: description. < 50 characters total. + topic: description. < 50 characters total. + Longer description. < 70 characters per line ``` From bc4a8157c0c8f27b18af35ed7cb93c1268d3b7f9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 1 Nov 2018 18:26:37 +0800 Subject: [PATCH 1300/2457] kasli: add tsinghua2 --- .../kasli_basic/device_db_tsinghua2.py | 195 ++++++++++++++++++ artiq/gateware/targets/kasli.py | 43 +++- 2 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 artiq/examples/kasli_basic/device_db_tsinghua2.py diff --git a/artiq/examples/kasli_basic/device_db_tsinghua2.py b/artiq/examples/kasli_basic/device_db_tsinghua2.py new file mode 100644 index 000000000..7cf7a18da --- /dev/null +++ b/artiq/examples/kasli_basic/device_db_tsinghua2.py @@ -0,0 +1,195 @@ +core_addr = "kasli-1.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + + +for i in range(8): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": i}, + } + + +device_db.update( + spi_urukul0={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 8} + }, + ttl_urukul0_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 9} + }, + ttl_urukul0_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 10} + }, + ttl_urukul0_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 11} + }, + ttl_urukul0_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 12} + }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 13} + }, + urukul0_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 125e6, + "clk_sel": 2 + } + } +) + +for i in range(4): + device_db["urukul0_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } + + +device_db["spi_sampler0_adc"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 14} +} +device_db["spi_sampler0_pgia"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 15} +} +device_db["spi_sampler0_cnv"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 16}, +} +device_db["sampler0"] = { + "type": "local", + "module": "artiq.coredevice.sampler", + "class": "Sampler", + "arguments": { + "spi_adc_device": "spi_sampler0_adc", + "spi_pgia_device": "spi_sampler0_pgia", + "cnv_device": "spi_sampler0_cnv" + } +} + + +for i in range(3): + device_db["spi_zotino{}".format(i)] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 17+3*i} + } + device_db["ttl_zotino{}_ldac".format(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 18+3*i} + } + device_db["ttl_zotino{}_clr".format(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 19+3*i} + } + device_db["zotino{}".format(i)] = { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino{}".format(i), + "ldac_device": "ttl_zotino{}_ldac".format(i), + "clr_device": "ttl_zotino{}_clr".format(i) + } + } + +device_db["grabber0"] = { + "type": "local", + "module": "artiq.coredevice.grabber", + "class": "Grabber", + "arguments": {"channel_base": 26} +} + +device_db.update( + led0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 28} + }, + led1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 29} + }, +) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 79c93dfcc..fc7eaf92a 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -423,6 +423,46 @@ class Tsinghua(_StandaloneBase): self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) +class Tsinghua2(_StandaloneBase): + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) + + self.rtio_channels = [] + self.grabber_csr_group = [] + eem.DIO.add_std(self, 4, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 2, 3, ttl_serdes_7series.Output_8X) + eem.Sampler.add_std(self, 5, 6, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 8, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 9, ttl_serdes_7series.Output_8X) + eem.Grabber.add_std(self, 1, 0) + + for i in (1, 2): + sfp_ctl = self.platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(self.rtio_channels) + self.config["HAS_GRABBER"] = None + self.add_csr_group("grabber", self.grabber_csr_group) + self.platform.add_false_path_constraints( + self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) + + class WIPM(_StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: @@ -1039,7 +1079,8 @@ def main(): soc_kasli_args(parser) parser.set_defaults(output_dir="artiq_kasli") variants = {cls.__name__.lower(): cls for cls in [ - Opticlock, SUServo, SYSU, MITLL, MITLL2, USTC, Tsinghua, WIPM, NUDT, PTB, HUB, LUH, + Opticlock, SUServo, SYSU, MITLL, MITLL2, USTC, + Tsinghua, Tsinghua2, WIPM, NUDT, PTB, HUB, LUH, VLBAIMaster, VLBAISatellite, Tester, Master, Satellite]} parser.add_argument("-V", "--variant", default="opticlock", help="variant: {} (default: %(default)s)".format( From 7f11411127f000595aa6d2bcfe15eb8c1809f6ca Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 3 Nov 2018 20:17:28 +0800 Subject: [PATCH 1301/2457] RELEASE_NOTES: 3.7 --- RELEASE_NOTES.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index ab4196181..a72edc9b4 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -46,6 +46,12 @@ ARTIQ-4 ARTIQ-3 ------- +3.7 +*** + +No further notes. + + 3.6 *** From cbfbe24d7a69567f4d1da969ad66fc4604320082 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 23 Jul 2018 12:28:45 +0100 Subject: [PATCH 1302/2457] ttl: Remove broken TTLClockGen.sync The code currently doesn't compile because of a typo in the timestamp field name. However, tracking event timestamps in software is problematic anyway (e.g. with DMA, see GitHub #1113), so just remove `sync()` altogether. --- artiq/coredevice/ttl.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 09732fccc..802715df9 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -378,8 +378,6 @@ class TTLClockGen: self.core = dmgr.get(core_device) self.channel = channel - # in RTIO cycles - self.previous_timestamp = numpy.int64(0) self.acc_width = numpy.int64(24) @portable @@ -415,7 +413,6 @@ class TTLClockGen: that are not powers of two cause jitter of one RTIO clock cycle at the output.""" rtio_output(now_mu(), self.channel, 0, frequency) - self.previous_timestamp = now_mu() @kernel def set(self, frequency): @@ -426,10 +423,3 @@ class TTLClockGen: def stop(self): """Stop the toggling of the clock and set the output level to 0.""" self.set_mu(0) - - @kernel - def sync(self): - """Busy-wait until all programmed frequency switches and stops have - been effected.""" - while self.core.get_rtio_counter_mu() < self.o_previous_timestamp: - pass From 11e8c9d5f73e944207a816610c3ec929cc9ca928 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 23 Jul 2018 15:24:41 +0100 Subject: [PATCH 1303/2457] coredevice: Add Core.wait_until_mu() (This supersedes TTLOut.sync(), see see GitHub #1113.) --- artiq/coredevice/core.py | 11 +++++++++++ artiq/test/coredevice/test_rtio.py | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 9f84efe60..0caf31edb 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -153,6 +153,17 @@ class Core: def get_rtio_counter_mu(self): return rtio_get_counter() + @kernel + def wait_until_mu(self, cursor_mu): + """Block execution until the hardware RTIO counter reaches the given + value (see :meth:`get_rtio_counter_mu`). + + If the hardware counter has already passed the given time, the function + returns immediately. + """ + while self.get_rtio_counter_mu() < cursor_mu: + pass + @kernel def get_drtio_link_status(self, linkno): """Returns whether the specified DRTIO link is up. diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 8fde4bcc4..9631cd38e 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -29,6 +29,23 @@ class RTIOCounter(EnvExperiment): self.set_dataset("dt", self.core.mu_to_seconds(t1 - t0)) +class InvalidCounter(Exception): + pass + + +class WaitForRTIOCounter(EnvExperiment): + def build(self): + self.setattr_device("core") + + @kernel + def run(self): + self.core.break_realtime() + target_mu = now_mu() + 10000 + self.core.wait_until_mu(target_mu) + if self.core.get_rtio_counter_mu() < target_mu: + raise InvalidCounter + + class PulseNotReceived(Exception): pass @@ -375,6 +392,9 @@ class CoredeviceTest(ExperimentCase): self.assertGreater(dt, 50*ns) self.assertLess(dt, 1*us) + def test_wait_for_rtio_counter(self): + self.execute(WaitForRTIOCounter) + def test_loopback(self): self.execute(Loopback) rtt = self.dataset_mgr.get("rtt") From 17a5fb2dce0a68cb6ad56a68f417a2c2eabb0359 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 23 Jul 2018 14:36:03 +0100 Subject: [PATCH 1304/2457] ttl: Remove error-prone sync() calls These methods are problematic, as with DMA in the picture, the timestamp member variables did not necessarily reflect the last submitted event timestamp (see GitHub #1113). sync() is only very rarely used in typical experimental code, so the methods are removed without a transition period. Core.wait_until() can be used to busy-wait for a specified RTIO timestamp value on the core device CPU instead. --- artiq/coredevice/ttl.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 802715df9..292a5cfbe 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -35,9 +35,6 @@ class TTLOut: self.core = dmgr.get(core_device) self.channel = channel - # in RTIO cycles - self.o_previous_timestamp = numpy.int64(0) - @kernel def output(self): pass @@ -45,14 +42,6 @@ class TTLOut: @kernel def set_o(self, o): rtio_output(now_mu(), self.channel, 0, 1 if o else 0) - self.o_previous_timestamp = now_mu() - - @kernel - def sync(self): - """Busy-wait until all programmed level switches have been - effected.""" - while self.core.get_rtio_counter_mu() < self.o_previous_timestamp: - pass @kernel def on(self): @@ -123,8 +112,6 @@ class TTLInOut: self.core = dmgr.get(core_device) self.channel = channel - # in RTIO cycles - self.o_previous_timestamp = numpy.int64(0) self.i_previous_timestamp = numpy.int64(0) self.queued_samples = 0 @@ -153,14 +140,6 @@ class TTLInOut: @kernel def set_o(self, o): rtio_output(now_mu(), self.channel, 0, 1 if o else 0) - self.o_previous_timestamp = now_mu() - - @kernel - def sync(self): - """Busy-wait until all programmed level switches have been - effected.""" - while self.core.get_rtio_counter_mu() < self.o_previous_timestamp: - pass @kernel def on(self): From 2a0e1dabfb5be8d607b97d8d360cf97dee8028ed Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 23 Jul 2018 15:33:52 +0100 Subject: [PATCH 1305/2457] ttl: Remove unused attribute [nfc] --- artiq/coredevice/ttl.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 292a5cfbe..df1036c2c 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -113,7 +113,6 @@ class TTLInOut: self.channel = channel self.i_previous_timestamp = numpy.int64(0) - self.queued_samples = 0 @kernel def set_oe(self, oe): From cbdef0225c274979478fed3057b31b5beed5a2be Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 23 Jul 2018 15:34:18 +0100 Subject: [PATCH 1306/2457] ttl: Add target RTIO time argument to timestamp/count functions Software-based tracking of timestamps is problematic (e.g. when using DMA, see GitHub #1113). --- artiq/coredevice/ttl.py | 58 +++++++++++++------ .../kasli_basic/repository/kasli_tester.py | 2 +- .../repository/photon_histogram.py | 4 +- .../kc705_nist_clock/repository/tdr.py | 4 +- .../no_hardware/repository/al_spectroscopy.py | 5 +- artiq/sim/devices.py | 4 +- artiq/test/coredevice/test_analyzer.py | 3 +- artiq/test/coredevice/test_rtio.py | 8 +-- doc/manual/rtio.rst | 3 +- 9 files changed, 55 insertions(+), 36 deletions(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index df1036c2c..5746172b7 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -112,8 +112,6 @@ class TTLInOut: self.core = dmgr.get(core_device) self.channel = channel - self.i_previous_timestamp = numpy.int64(0) - @kernel def set_oe(self, oe): rtio_output(now_mu(), self.channel, 1, 1 if oe else 0) @@ -184,88 +182,112 @@ class TTLInOut: @kernel def _set_sensitivity(self, value): rtio_output(now_mu(), self.channel, 2, value) - self.i_previous_timestamp = now_mu() @kernel def gate_rising_mu(self, duration): """Register rising edge events for the specified duration (in machine units). - The time cursor is advanced by the specified duration.""" + The time cursor is advanced by the specified duration. + + :return: The timeline cursor at the end of the gate window. + """ self._set_sensitivity(1) delay_mu(duration) self._set_sensitivity(0) + return now_mu() @kernel def gate_falling_mu(self, duration): """Register falling edge events for the specified duration (in machine units). - The time cursor is advanced by the specified duration.""" + The time cursor is advanced by the specified duration. + + :return: The timeline cursor at the end of the gate window. + """ self._set_sensitivity(2) delay_mu(duration) self._set_sensitivity(0) + return now_mu() @kernel def gate_both_mu(self, duration): """Register both rising and falling edge events for the specified duration (in machine units). - The time cursor is advanced by the specified duration.""" + The time cursor is advanced by the specified duration. + + :return: The timeline cursor at the end of the gate window. + """ self._set_sensitivity(3) delay_mu(duration) self._set_sensitivity(0) + return now_mu() @kernel def gate_rising(self, duration): """Register rising edge events for the specified duration (in seconds). - The time cursor is advanced by the specified duration.""" + The time cursor is advanced by the specified duration. + + :return: The timeline cursor at the end of the gate window. + """ self._set_sensitivity(1) delay(duration) self._set_sensitivity(0) + return now_mu() @kernel def gate_falling(self, duration): """Register falling edge events for the specified duration (in seconds). - The time cursor is advanced by the specified duration.""" + The time cursor is advanced by the specified duration. + + :return: The timeline cursor at the end of the gate window. + """ self._set_sensitivity(2) delay(duration) self._set_sensitivity(0) + return now_mu() @kernel def gate_both(self, duration): """Register both rising and falling edge events for the specified duration (in seconds). - The time cursor is advanced by the specified duration.""" + The time cursor is advanced by the specified duration. + + :return: The timeline cursor at the end of the gate window. + """ self._set_sensitivity(3) delay(duration) self._set_sensitivity(0) + return now_mu() @kernel - def count(self): - """Poll the RTIO input during all the previously programmed gate - openings, and returns the number of registered events. + def count(self, up_to_timestamp_mu): + """Poll the RTIO input up to the specified timestamp, and returns the + number of registered events. - This function does not interact with the time cursor.""" + This function does not interact with the timeline cursor.""" count = 0 - while rtio_input_timestamp(self.i_previous_timestamp, self.channel) >= 0: + while rtio_input_timestamp(up_to_timestamp_mu, self.channel) >= 0: count += 1 return count @kernel - def timestamp_mu(self): + def timestamp_mu(self, up_to_timestamp_mu): """Poll the RTIO input and returns an event timestamp (in machine - units), according to the gating. + units) according to the selected gates, or -1 if no event occured before + the specified timestamp. If the gate is permanently closed, returns a negative value. - This function does not interact with the time cursor.""" - return rtio_input_timestamp(self.i_previous_timestamp, self.channel) + This function does not interact with the timeline cursor.""" + return rtio_input_timestamp(up_to_timestamp_mu, self.channel) # Input API: sampling @kernel diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index 475925db2..b47a1e0c6 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -152,7 +152,7 @@ class KasliTester(EnvExperiment): for _ in range(n): ttl_out.pulse(2*us) delay(2*us) - return ttl_in.count() == n + return ttl_in.count(now_mu()) == n def test_ttl_ins(self): print("*** Testing TTL inputs.") diff --git a/artiq/examples/kc705_nist_clock/repository/photon_histogram.py b/artiq/examples/kc705_nist_clock/repository/photon_histogram.py index 6d860db0e..4a9166a8a 100644 --- a/artiq/examples/kc705_nist_clock/repository/photon_histogram.py +++ b/artiq/examples/kc705_nist_clock/repository/photon_histogram.py @@ -38,13 +38,13 @@ class PhotonHistogram(EnvExperiment): self.bd_dds.set(self.detect_f) with parallel: self.bd_sw.pulse(self.detect_t) - self.pmt.gate_rising(self.detect_t) + gate_end_mu = self.pmt.gate_rising(self.detect_t) self.program_cooling() self.bd_sw.on() self.bdd_sw.on() - return self.pmt.count() + return self.pmt.count(gate_end_mu) @kernel def run(self): diff --git a/artiq/examples/kc705_nist_clock/repository/tdr.py b/artiq/examples/kc705_nist_clock/repository/tdr.py index a32015a7b..c304f268a 100644 --- a/artiq/examples/kc705_nist_clock/repository/tdr.py +++ b/artiq/examples/kc705_nist_clock/repository/tdr.py @@ -66,8 +66,8 @@ class TDR(EnvExperiment): self.pmt0.gate_both_mu(2*p) self.ttl2.pulse_mu(p) for i in range(len(self.t)): - ti = self.pmt0.timestamp_mu() + ti = self.pmt0.timestamp_mu(now_mu()) if ti <= 0: raise PulseNotReceivedError() self.t[i] = int(self.t[i] + ti - t0) - self.pmt0.count() # flush + self.pmt0.count(now_mu()) # flush diff --git a/artiq/examples/no_hardware/repository/al_spectroscopy.py b/artiq/examples/no_hardware/repository/al_spectroscopy.py index de1cc51cc..d48c2ead7 100644 --- a/artiq/examples/no_hardware/repository/al_spectroscopy.py +++ b/artiq/examples/no_hardware/repository/al_spectroscopy.py @@ -21,7 +21,7 @@ class AluminumSpectroscopy(EnvExperiment): state_0_count = 0 for count in range(100): self.mains_sync.gate_rising(1*s/60) - at_mu(self.mains_sync.timestamp_mu() + 100*us) + at_mu(self.mains_sync.timestamp_mu(now_mu()) + 100*us) delay(10*us) self.laser_cooling.pulse(100*MHz, 100*us) delay(5*us) @@ -35,8 +35,7 @@ class AluminumSpectroscopy(EnvExperiment): delay(5*us) with parallel: self.state_detection.pulse(100*MHz, 10*us) - self.pmt.gate_rising(10*us) - photon_count = self.pmt.count() + photon_count = self.pmt.count(self.pmt.gate_rising(10*us)) if (photon_count < self.photon_limit_low or photon_count > self.photon_limit_high): break diff --git a/artiq/sim/devices.py b/artiq/sim/devices.py index ff8e5eb57..41b7b59c5 100644 --- a/artiq/sim/devices.py +++ b/artiq/sim/devices.py @@ -49,13 +49,13 @@ class Input: delay(duration) @kernel - def count(self): + def count(self, up_to_timestamp_mu): result = self.prng.randrange(0, 100) time.manager.event(("count", self.name, result)) return result @kernel - def timestamp_mu(self): + def timestamp_mu(self, up_to_timestamp_mu): result = time.manager.get_time_mu() result += self.prng.randrange(100, 1000) time.manager.event(("timestamp_mu", self.name, result)) diff --git a/artiq/test/coredevice/test_analyzer.py b/artiq/test/coredevice/test_analyzer.py index ea3c93fe2..335c941c3 100644 --- a/artiq/test/coredevice/test_analyzer.py +++ b/artiq/test/coredevice/test_analyzer.py @@ -21,11 +21,10 @@ class CreateTTLPulse(EnvExperiment): def run(self): self.core.break_realtime() with parallel: - self.loop_in.gate_both_mu(1200) with sequential: delay_mu(100) self.loop_out.pulse_mu(1000) - self.loop_in.count() + self.loop_in.count(self.loop_in.gate_both_mu(1200)) class WriteLog(EnvExperiment): diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 9631cd38e..12f167c1b 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -68,7 +68,7 @@ class RTT(EnvExperiment): delay(1*us) t0 = now_mu() self.ttl_inout.pulse(1*us) - t1 = self.ttl_inout.timestamp_mu() + t1 = self.ttl_inout.timestamp_mu(now_mu()) if t1 < 0: raise PulseNotReceived() self.set_dataset("rtt", self.core.mu_to_seconds(t1 - t0)) @@ -92,7 +92,7 @@ class Loopback(EnvExperiment): delay(1*us) t0 = now_mu() self.loop_out.pulse(1*us) - t1 = self.loop_in.timestamp_mu() + t1 = self.loop_in.timestamp_mu(now_mu()) if t1 < 0: raise PulseNotReceived() self.set_dataset("rtt", self.core.mu_to_seconds(t1 - t0)) @@ -115,7 +115,7 @@ class ClockGeneratorLoopback(EnvExperiment): with sequential: delay(200*ns) self.loop_clock_out.set(1*MHz) - self.set_dataset("count", self.loop_clock_in.count()) + self.set_dataset("count", self.loop_clock_in.count(now_mu())) class PulseRate(EnvExperiment): @@ -203,7 +203,7 @@ class LoopbackCount(EnvExperiment): for i in range(self.npulses): delay(25*ns) self.loop_out.pulse(25*ns) - self.set_dataset("count", self.loop_in.count()) + self.set_dataset("count", self.loop_in.count(now_mu())) class IncorrectLevel(Exception): diff --git a/doc/manual/rtio.rst b/doc/manual/rtio.rst index 2d093b755..ce69b2bcd 100644 --- a/doc/manual/rtio.rst +++ b/doc/manual/rtio.rst @@ -159,8 +159,7 @@ Input channels detect events, timestamp them, and place them in a buffer for the The following example counts the rising edges occurring during a precisely timed 500 ns interval. If more than 20 rising edges were received it outputs a pulse:: - input.gate_rising(500*ns) - if input.count() > 20: + if input.count(input.gate_rising(500*ns)) > 20: delay(2*us) output.pulse(500*ns) From d6fcc0529f74dd6561025d5223829ba26da5136e Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 26 Oct 2018 11:56:33 +0100 Subject: [PATCH 1307/2457] coredevice: Imperative mood in docstrings [nfc] This follows Python conventions (PEP257) and unifies the style with other comments. --- artiq/coredevice/core.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 0caf31edb..60abcf96b 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -134,7 +134,7 @@ class Core: @portable def seconds_to_mu(self, seconds): - """Converts seconds to the corresponding number of machine units + """Convert seconds to the corresponding number of machine units (RTIO cycles). :param seconds: time (in seconds) to convert. @@ -143,7 +143,7 @@ class Core: @portable def mu_to_seconds(self, mu): - """Converts machine units (RTIO cycles) to seconds. + """Convert machine units (RTIO cycles) to seconds. :param mu: cycle count to convert. """ @@ -166,7 +166,7 @@ class Core: @kernel def get_drtio_link_status(self, linkno): - """Returns whether the specified DRTIO link is up. + """Return whether the specified DRTIO link is up. This is particularly useful in startup kernels to delay startup until certain DRTIO links are up.""" From 5d2e3f975f0e9018fcdd75ca2f6505bc249ba574 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 26 Oct 2018 12:16:57 +0100 Subject: [PATCH 1308/2457] coredevice: Add get_rtio_counter_mu() docstring [nfc] --- artiq/coredevice/core.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 60abcf96b..5144b6010 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -151,6 +151,15 @@ class Core: @kernel def get_rtio_counter_mu(self): + """Retrieve the current value of the hardware RTIO timeline counter. + + As the timing of kernel code executed on the CPU is inherently + non-deterministic, the return value is by necessity only a lower bound + for the actual value of the hardware register at the instant when + execution resumes in the caller. + + For a more detailed description of these concepts, see :doc:`/rtio`. + """ return rtio_get_counter() @kernel From e7d3f36b912e9330b200534e13e0a8c9c23e6b9e Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 26 Oct 2018 12:26:24 +0100 Subject: [PATCH 1309/2457] doc: Fix ancient trigger code in slides These examples were already broken before my recent changes to the artiq.coredevice.ttl API. --- doc/slides/artiq_overview.tex | 4 ++-- doc/slides/taaccs.tex | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/slides/artiq_overview.tex b/doc/slides/artiq_overview.tex index e20655e5b..9f9851aeb 100644 --- a/doc/slides/artiq_overview.tex +++ b/doc/slides/artiq_overview.tex @@ -90,8 +90,8 @@ inner sep=.3mm] at (current page.south east) {% \footnotesize \begin{minted}[frame=leftline]{python} -trigger.sync() # wait for trigger input -start = now_mu() # capture trigger time +# wait for trigger input and capture timestamp +start = trigger.timestamp_mu(trigger.gate_rising(100*ms)) for i in range(3): delay(5*us) dds.pulse(900*MHz, 7*us) # first pulse 5 µs after trigger diff --git a/doc/slides/taaccs.tex b/doc/slides/taaccs.tex index df497c578..7b7f5dbc3 100644 --- a/doc/slides/taaccs.tex +++ b/doc/slides/taaccs.tex @@ -106,8 +106,8 @@ inner sep=.3mm] at (current page.south east) {% \footnotesize \begin{minted}[frame=leftline]{python} -trigger.sync() # wait for trigger input -start = now_mu() # capture trigger time +# wait for trigger input and capture timestamp +start = trigger.timestamp_mu(trigger.gate_rising(100*ms)) for i in range(3): delay(5*us) dds.pulse(900*MHz, 7*us) # first pulse 5 µs after trigger From f02ceee6268e60441a80d1bee247e4729dfa93ac Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 26 Oct 2018 12:46:08 +0100 Subject: [PATCH 1310/2457] language: Clarify now_mu() docstring [nfc] --- artiq/language/core.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/artiq/language/core.py b/artiq/language/core.py index e6cd1a498..40b932fb4 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -199,7 +199,12 @@ def delay_mu(duration): def now_mu(): - """Retrieves the current RTIO time, in machine units.""" + """Retrieve the current RTIO timeline cursor, in machine units. + + Note the conceptual difference between this and the current value of the + hardware RTIO counter; see e.g. + :meth:`artiq.coredevice.core.Core.get_rtio_counter_mu` for the latter. + """ return _time_manager.get_time_mu() From f79b9d9e1e54e7b5a64c75340a26a23e3d61384b Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 26 Oct 2018 16:08:08 +0100 Subject: [PATCH 1311/2457] ttl: Expand input gate/count API docstrings --- artiq/coredevice/ttl.py | 87 ++++++++++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 14 deletions(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 5746172b7..2548bab70 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -190,7 +190,8 @@ class TTLInOut: The time cursor is advanced by the specified duration. - :return: The timeline cursor at the end of the gate window. + :return: The timeline cursor at the end of the gate window, for + convenience when used with :meth:`count`/:meth:`timestamp_mu`. """ self._set_sensitivity(1) delay_mu(duration) @@ -204,7 +205,8 @@ class TTLInOut: The time cursor is advanced by the specified duration. - :return: The timeline cursor at the end of the gate window. + :return: The timeline cursor at the end of the gate window, for + convenience when used with :meth:`count`/:meth:`timestamp_mu`. """ self._set_sensitivity(2) delay_mu(duration) @@ -218,7 +220,8 @@ class TTLInOut: The time cursor is advanced by the specified duration. - :return: The timeline cursor at the end of the gate window. + :return: The timeline cursor at the end of the gate window, for + convenience when used with :meth:`count`/:meth:`timestamp_mu`. """ self._set_sensitivity(3) delay_mu(duration) @@ -232,7 +235,8 @@ class TTLInOut: The time cursor is advanced by the specified duration. - :return: The timeline cursor at the end of the gate window. + :return: The timeline cursor at the end of the gate window, for + convenience when used with :meth:`count`/:meth:`timestamp_mu`. """ self._set_sensitivity(1) delay(duration) @@ -246,7 +250,9 @@ class TTLInOut: The time cursor is advanced by the specified duration. - :return: The timeline cursor at the end of the gate window. + :return: The timeline cursor at the end of the gate window, for + convenience when used with :meth:`count`/:meth:`timestamp_mu`. + """ self._set_sensitivity(2) delay(duration) @@ -260,7 +266,8 @@ class TTLInOut: The time cursor is advanced by the specified duration. - :return: The timeline cursor at the end of the gate window. + :return: The timeline cursor at the end of the gate window, for + convenience when used with :meth:`count`/:meth:`timestamp_mu`. """ self._set_sensitivity(3) delay(duration) @@ -269,10 +276,52 @@ class TTLInOut: @kernel def count(self, up_to_timestamp_mu): - """Poll the RTIO input up to the specified timestamp, and returns the - number of registered events. + """Consume RTIO input events until the hardware timestamp counter has + reached the specified timestamp and return the number of observed + events. - This function does not interact with the timeline cursor.""" + This function does not interact with the timeline cursor. + + See the ``gate_*()`` family of methods to select the input transitions + that generate events, and :meth:`timestamp_mu` to obtain the timestamp + of the first event rather than an accumulated count. + + :param up_to_timestamp_mu: The timestamp up to which execution is + blocked, that is, up to which input events are guaranteed to be + taken into account. (Events with later timestamps might still be + registered if they are already available.) + + :return: The number of events before the timeout elapsed (0 if none + observed). + + Examples: + To count events on channel ``ttl_input``, up to the current timeline + position:: + + ttl_input.count(now_mu()) + + If other events are scheduled between the end of the input gate + period and when the number of events is counted, using ``now_mu()`` + as timeout consumes an unnecessary amount of timeline slack. In + such cases, it can be beneficial to pass a more precise timestamp, + for example:: + + gate_end_mu = ttl_input.gate_rising(100 * us) + + # Schedule a long pulse sequence, represented here by a delay. + delay(10 * ms) + + # Get number of rising edges. This will block until the end of + # the gate window, but does not wait for the long pulse sequence + # afterwards, thus (likely) completing with a large amount of + # slack left. + num_rising_edges = ttl_input.count(gate_end_mu) + + The ``gate_*()`` family of methods return the cursor at the end + of the window, allowing this to be expressed in a compact fashion:: + + ttl_input.count(ttl_input.gate_rising(100 * us)) + """ count = 0 while rtio_input_timestamp(up_to_timestamp_mu, self.channel) >= 0: count += 1 @@ -280,13 +329,23 @@ class TTLInOut: @kernel def timestamp_mu(self, up_to_timestamp_mu): - """Poll the RTIO input and returns an event timestamp (in machine - units) according to the selected gates, or -1 if no event occured before - the specified timestamp. + """Return the timestamp of the next RTIO input event, or -1 if the + hardware timestamp counter reaches the given value before an event is + received. - If the gate is permanently closed, returns a negative value. + This function does not interact with the timeline cursor. - This function does not interact with the timeline cursor.""" + See the ``gate_*()`` family of methods to select the input transitions + that generate events, and :meth:`count` for usage examples. + + :param up_to_timestamp_mu: The timestamp up to which execution is + blocked, that is, up to which input events are guaranteed to be + taken into account. (Events with later timestamps might still be + registered if they are already available.) + + :return: The timestamp (in machine units) of the first event received; + -1 on timeout. + """ return rtio_input_timestamp(up_to_timestamp_mu, self.channel) # Input API: sampling From 8b5df9c151e52b9c2e38db98fd8045930313e641 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 26 Oct 2018 16:54:46 +0100 Subject: [PATCH 1312/2457] RELEASE_NOTES: TTL timeline cursor API changes --- RELEASE_NOTES.rst | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index a72edc9b4..498a0b4b3 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -9,6 +9,32 @@ ARTIQ-4 4.0 *** +* The ``artiq.coredevice.ttl`` drivers no longer track the timestamps of + submitted events in software, requiring the user to explicitly specify the + timeout for ``count()``/``timestamp_mu()``. Support for ``sync()`` has been dropped. + + Now that RTIO has gained DMA support, there is no longer a reliable way for + the kernel CPU to track the individual events submitted on any one channel. + Requiring the timeouts to be specified explicitly ensures consistent API + behavior. To make this more convenient, the ``TTLInOut.gate_*()`` functions + now return the cursor position at the end of the gate, e.g.:: + + ttl_input.count(ttl_input.gate_rising(100 * us)) + + In most situations – that is, unless the timeline cursor is rewound after the + respective ``gate_*()`` call – simply passing ``now_mu()`` is also a valid + upgrade path:: + + ttl_input.count(now_mu()) + + The latter might use up more timeline slack than necessary, though. + + In place of ``TTL(In)Out.sync``, the new ``Core.wait_until_mu()`` method can + be used, which blocks execution until the hardware RTIO cursor reaches the + given timestamp:: + + ttl_output.pulse(10 * us) + self.core.wait_until_mu(now_mu()) * RTIO outputs use a new architecture called Scalable Event Dispatcher (SED), which allows building systems with large number of RTIO channels more efficiently. From abad916383370c0293e20e0d373efc2f2eb2622b Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 28 Oct 2018 04:12:40 +0000 Subject: [PATCH 1313/2457] RELEASE_NOTES: Fix typo --- RELEASE_NOTES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 498a0b4b3..155b86e2c 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -53,7 +53,7 @@ ARTIQ-4 * The ``proxy`` action of ``artiq_flash`` is determined automatically and should not be specified manually anymore. * ``kc705_dds`` has been renamed ``kc705``. -* the ``-H/--hw-adapter`` option of ``kc705`` has ben renamed ``-V/--variant``. +* The ``-H/--hw-adapter`` option of ``kc705`` has been renamed ``-V/--variant``. * SPI masters have been switched from misoc-spi to misoc-spi2. This affects all out-of-tree RTIO core device drivers using those buses. See the various commits on e.g. the ``ad53xx`` driver for an example how to port from the old From f755a4682a8a262b9dd6ff7ead659ec4897a36a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 25 Oct 2018 10:13:15 +0000 Subject: [PATCH 1314/2457] device_db_ptb: fix zotino clr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/examples/kasli_basic/device_db_ptb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/kasli_basic/device_db_ptb.py b/artiq/examples/kasli_basic/device_db_ptb.py index cc04d1090..5aa1c6e6a 100644 --- a/artiq/examples/kasli_basic/device_db_ptb.py +++ b/artiq/examples/kasli_basic/device_db_ptb.py @@ -218,7 +218,7 @@ device_db.update({ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 39} + "arguments": {"channel": 40} }, "zotino0": { "type": "local", From f62c1ff0bb1129c2383e9062cd3445ad31c3a8ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 25 Oct 2018 09:52:00 +0000 Subject: [PATCH 1315/2457] TTLClockGen: expose acc_width MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ttl.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 09732fccc..4069c62aa 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -371,16 +371,17 @@ class TTLClockGen: The time cursor is not modified by any function in this class. :param channel: channel number + :param acc_width: accumulator width in bits """ kernel_invariants = {"core", "channel", "acc_width"} - def __init__(self, dmgr, channel, core_device="core"): + def __init__(self, dmgr, channel, acc_width=24, core_device="core"): self.core = dmgr.get(core_device) self.channel = channel # in RTIO cycles self.previous_timestamp = numpy.int64(0) - self.acc_width = numpy.int64(24) + self.acc_width = numpy.int64(acc_width) @portable def frequency_to_ftw(self, frequency): From 0433e8f4fe27303f4efbcfa35cdcbb189e0ba146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 25 Oct 2018 09:51:21 +0000 Subject: [PATCH 1316/2457] urukul: add sync_in generator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for #1143 Signed-off-by: Robert Jördens --- artiq/coredevice/urukul.py | 27 ++++++++++++-- artiq/examples/kasli_basic/device_db_ptb.py | 41 ++++++++++++++------- artiq/gateware/eem.py | 11 ++++-- artiq/gateware/targets/kasli.py | 6 ++- 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index fe9c1a68c..459f10f58 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -115,6 +115,7 @@ class CPLD: :param spi_device: SPI bus device name :param io_update_device: IO update RTIO TTLOut channel name :param dds_reset_device: DDS reset RTIO TTLOut channel name + :param sync_device: AD9910 SYNC_IN RTIO TTLClockGen channel name :param refclk: Reference clock (SMA, MMCX or on-board 100 MHz oscillator) frequency in Hz :param clk_sel: Reference clock selection. For hardware revision >= 1.3 @@ -122,8 +123,8 @@ class CPLD: internal MMCX. For hardware revision <= v1.2 valid options are: 0 - either XO or MMCX dependent on component population; 1 SMA. Unsupported clocking options are silently ignored. - :param sync_sel: SYNC clock selection. 0 corresponds to SYNC clock over EEM - from FPGA. 1 corresponds to SYNC clock from DDS0. + :param sync_sel: SYNC_IN selection. 0 corresponds to SYNC_IN over EEM + from FPGA. 1 corresponds to SYNC_IN from DDS0. :param rf_sw: Initial CPLD RF switch register setting (default: 0x0). Knowledge of this state is not transferred between experiments. :param att: Initial attenuator setting shift register (default: @@ -134,7 +135,8 @@ class CPLD: kernel_invariants = {"refclk", "bus", "core", "io_update"} def __init__(self, dmgr, spi_device, io_update_device=None, - dds_reset_device=None, sync_sel=0, clk_sel=0, rf_sw=0, + dds_reset_device=None, sync_device=None, + sync_sel=0, clk_sel=0, rf_sw=0, refclk=125e6, att=0x00000000, core_device="core"): self.core = dmgr.get(core_device) @@ -147,6 +149,8 @@ class CPLD: self.io_update = _RegIOUpdate(self) if dds_reset_device is not None: self.dds_reset = dmgr.get(dds_reset_device) + if sync_device is not None: + self.sync = dmgr.get(sync_device) self.cfg_reg = urukul_cfg(rf_sw=rf_sw, led=0, profile=0, io_update=0, mask_nu=0, clk_sel=clk_sel, @@ -289,3 +293,20 @@ class CPLD: SPIT_ATT_RD, CS_ATT) self.bus.write(self.att_reg) return self.bus.read() + + @kernel + def set_sync_div(self, div): + """Set the SYNC_IN AD9910 pulse generator frequency + and align it to the current RTIO timestamp. + + The SYNC_IN signal is derived from the coarse RTIO clock + and the divider must be a power of two two. + Configure ``sync_sel == 0``. + + :param div: SYNC_IN frequency divider. Must be a power of two. + Minimum division ratio is 2. Maximum division ratio is 16. + """ + ftw_max = 1 << 4 + ftw = ftw_max//div + assert ftw*div == ftw_max + self.sync.set_mu(ftw) diff --git a/artiq/examples/kasli_basic/device_db_ptb.py b/artiq/examples/kasli_basic/device_db_ptb.py index 5aa1c6e6a..a3c64bba7 100644 --- a/artiq/examples/kasli_basic/device_db_ptb.py +++ b/artiq/examples/kasli_basic/device_db_ptb.py @@ -87,36 +87,42 @@ device_db.update({ "class": "SPIMaster", "arguments": {"channel": 27} }, - "ttl_urukul0_io_update": { + "ttl_urukul0_sync": { "type": "local", "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 28} + "class": "TTLClockGen", + "arguments": {"channel": 28, "acc_width": 4} }, - "ttl_urukul0_sw0": { + "ttl_urukul0_io_update": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 29} }, - "ttl_urukul0_sw1": { + "ttl_urukul0_sw0": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 30} }, - "ttl_urukul0_sw2": { + "ttl_urukul0_sw1": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 31} }, - "ttl_urukul0_sw3": { + "ttl_urukul0_sw2": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 32} }, + "ttl_urukul0_sw3": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 33} + }, "urukul0_cpld": { "type": "local", "module": "artiq.coredevice.urukul", @@ -124,6 +130,7 @@ device_db.update({ "arguments": { "spi_device": "spi_urukul0", "io_update_device": "ttl_urukul0_io_update", + "sync_device": "ttl_urukul0_sync", "refclk": 100e6, "clk_sel": 0 } @@ -150,13 +157,19 @@ device_db.update({ "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 33} + "arguments": {"channel": 34} + }, + "ttl_urukul1_sync": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLClockGen", + "arguments": {"channel": 35, "acc_width": 4} }, "ttl_urukul1_io_update": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 34} + "arguments": {"channel": 36} }, "urukul1_cpld": { "type": "local", @@ -190,13 +203,13 @@ device_db.update({ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 35} + "arguments": {"channel": 37} }, "led1": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 36} + "arguments": {"channel": 38} } }) @@ -206,19 +219,19 @@ device_db.update({ "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 37} + "arguments": {"channel": 39} }, "ttl_zotino0_ldac": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 38} + "arguments": {"channel": 40} }, "ttl_zotino0_clr": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 40} + "arguments": {"channel": 41} }, "zotino0": { "type": "local", diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 34680a714..3c556a4ce 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -148,7 +148,8 @@ class Urukul(_EEM): return ios @classmethod - def add_std(cls, target, eem, eem_aux, ttl_out_cls, iostandard="LVDS_25"): + def add_std(cls, target, eem, eem_aux, ttl_out_cls, sync_gen_cls=None, + iostandard="LVDS_25"): cls.add_extension(target, eem, eem_aux, iostandard=iostandard) phy = spi2.SPIMaster(target.platform.request("urukul{}_spi_p".format(eem)), @@ -157,7 +158,12 @@ class Urukul(_EEM): target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) pads = target.platform.request("urukul{}_dds_reset".format(eem)) - target.specials += DifferentialOutput(0, pads.p, pads.n) + pad = Signal(reset=0) + target.specials += DifferentialOutput(pad, pads.p, pads.n) + if sync_gen_cls is not None: # AD9910 variant and SYNC_IN from EEM + phy = sync_gen_cls(pad, ftw_width=4) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy)) pads = target.platform.request("urukul{}_io_update".format(eem)) phy = ttl_out_cls(pads.p, pads.n) @@ -170,7 +176,6 @@ class Urukul(_EEM): target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy)) - class Sampler(_EEM): @staticmethod def io(eem, eem_aux, iostandard="LVDS_25"): diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 79c93dfcc..b061ef648 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -516,8 +516,10 @@ class PTB(_StandaloneBase): eem.DIO.add_std(self, 2, ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 5, 4, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 5, 4, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) + eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) for i in (1, 2): sfp_ctl = self.platform.request("sfp_ctl", i) From 35384448769a92503cd52a528716d3e50959491e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 26 Oct 2018 08:02:28 +0000 Subject: [PATCH 1317/2457] urukul: add sync_in to eem0-7 name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/gateware/eem.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 3c556a4ce..96050b748 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -75,7 +75,7 @@ class Urukul(_EEM): ), ] ttls = [(6, eem, "io_update"), - (7, eem, "dds_reset")] + (7, eem, "dds_reset_sync_in")] if eem_aux is not None: ttls += [(0, eem_aux, "sync_clk"), (1, eem_aux, "sync_in"), @@ -113,7 +113,7 @@ class Urukul(_EEM): ), ] ttls = [(6, eem0, "io_update"), - (7, eem0, "dds_reset"), + (7, eem0, "dds_reset_sync_in"), (4, eem1, "sw0"), (5, eem1, "sw1"), (6, eem1, "sw2"), @@ -157,7 +157,7 @@ class Urukul(_EEM): target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - pads = target.platform.request("urukul{}_dds_reset".format(eem)) + pads = target.platform.request("urukul{}_dds_reset_sync_in".format(eem)) pad = Signal(reset=0) target.specials += DifferentialOutput(pad, pads.p, pads.n) if sync_gen_cls is not None: # AD9910 variant and SYNC_IN from EEM @@ -527,7 +527,7 @@ class SUServo(_EEM): target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - pads = target.platform.request("{}_dds_reset".format(eem_urukul0)) + pads = target.platform.request("{}_dds_reset_sync_in".format(eem_urukul0)) target.specials += DifferentialOutput(0, pads.p, pads.n) for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): From 0b3b07a7da67ca532b77b92e0e81ebdf1b64de33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 25 Oct 2018 16:02:54 +0000 Subject: [PATCH 1318/2457] ad9910: add power down method MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index c7e1b49a1..442b40210 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -165,6 +165,16 @@ class AD9910: return raise ValueError("PLL lock timeout") + @kernel + def power_down(self, bits=0b1111): + """Power down DDS. + + :param bits: power down bits, see datasheet + """ + self.write32(_AD9910_REG_CFR1, 0x00000002 | (bits << 4)) + delay(1*us) + self.cpld.io_update.pulse(1*us) + @kernel def set_mu(self, ftw, pow=0, asf=0x3fff): """Set profile 0 data in machine units. From 8dbf5f87fd789ba32c7a655c828bab6cffcded73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 25 Oct 2018 16:02:13 +0000 Subject: [PATCH 1319/2457] ad9910: simplify io_update pulsing on init, set_mu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 442b40210..0617bc952 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -136,7 +136,7 @@ class AD9910: """ # Set SPI mode self.write32(_AD9910_REG_CFR1, 0x00000002) - self.cpld.io_update.pulse(2*us) + self.cpld.io_update.pulse(1*us) delay(1*ms) if not blind: # Use the AUX DAC setting to identify and confirm presence @@ -146,13 +146,13 @@ class AD9910: delay(50*us) # slack # Configure PLL settings and bring up PLL self.write32(_AD9910_REG_CFR2, 0x01400020) - self.cpld.io_update.pulse(2*us) + self.cpld.io_update.pulse(1*us) cfr3 = (0x0807c100 | (self.pll_vco << 24) | (self.pll_cp << 19) | (self.pll_n << 1)) self.write32(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset - self.cpld.io_update.pulse(100*us) + self.cpld.io_update.pulse(1*us) self.write32(_AD9910_REG_CFR3, cfr3) - self.cpld.io_update.pulse(100*us) + self.cpld.io_update.pulse(1*us) if blind: delay(100*ms) return @@ -172,7 +172,6 @@ class AD9910: :param bits: power down bits, see datasheet """ self.write32(_AD9910_REG_CFR1, 0x00000002 | (bits << 4)) - delay(1*us) self.cpld.io_update.pulse(1*us) @kernel @@ -187,7 +186,7 @@ class AD9910: :param asf: Amplitude scale factor: 14 bit unsigned. """ self.write64(_AD9910_REG_PR0, (asf << 16) | pow, ftw) - self.cpld.io_update.pulse(10*ns) + self.cpld.io_update.pulse_mu(8) @portable(flags={"fast-math"}) def frequency_to_ftw(self, frequency): From 65e2ebf9600f28da0b3e3c5d7422ccf2b59134bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 26 Oct 2018 09:00:07 +0000 Subject: [PATCH 1320/2457] ad9910: add sync delay control, auto tuning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * expose multi device sync functionality * sync delay configuration interface * auto-tuning of sync delay from device_db seed for #1143 Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 49 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 0617bc952..0ac288d07 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -6,6 +6,7 @@ from artiq.language.units import us, ns, ms from artiq.coredevice import spi2 as spi from artiq.coredevice import urukul urukul_sta_pll_lock = urukul.urukul_sta_pll_lock +urukul_sta_smp_err = urukul.urukul_sta_smp_err _AD9910_REG_CFR1 = 0x00 @@ -49,12 +50,15 @@ class AD9910: Urukul CPLD instance). :param pll_cp: DDS PLL charge pump setting. :param pll_vco: DDS PLL VCO range selection. + :param sync_delay_seed: SYNC_IN delay tuning starting value. + To stabilize the SYNC_IN delay tuning, run :meth:`tune_sync_delay` once and + set this to the delay tap number returned by :meth:`tune_sync_delay`. """ kernel_invariants = {"chip_select", "cpld", "core", "bus", - "ftw_per_hz", "pll_n", "pll_cp", "pll_vco"} + "ftw_per_hz", "pll_n", "pll_cp", "pll_vco", "sync_delay_seed"} def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, - pll_n=40, pll_cp=7, pll_vco=5): + pll_n=40, pll_cp=7, pll_vco=5, sync_delay_seed=8): self.cpld = dmgr.get(cpld_device) self.core = self.cpld.core self.bus = self.cpld.bus @@ -76,6 +80,7 @@ class AD9910: self.pll_vco = pll_vco assert 0 <= pll_cp <= 7 self.pll_cp = pll_cp + self.sync_delay_seed = sync_delay_seed @kernel def write32(self, addr, data): @@ -249,3 +254,43 @@ class AD9910: :param state: CPLD CFG RF switch bit """ self.cpld.cfg_sw(self.chip_select - 4, state) + + @kernel + def set_sync(self, in_delay, window, preset=0): + self.write32(_AD9910_REG_MSYNC, + (window << 28) | # SYNC S/H validation delay + (1 << 27) | # SYNC receiver enable + (0 << 26) | # SYNC generator disable + (0 << 25) | # SYNC generator SYS rising edge + (preset << 18) | # SYNC preset + (0 << 11) | # SYNC output delay + (in_delay << 3)) # SYNC receiver delay + self.write32(_AD9910_REG_CFR2, 0x01400020) # clear SMP_ERR + self.cpld.io_update.pulse(1*us) + self.write32(_AD9910_REG_CFR2, 0x01400000) # enable SMP_ERR + self.cpld.io_update.pulse(1*us) + + @kernel + def tune_sync_delay(self): + dt = 14 # 1/(f_SYSCLK*75ps) taps per SYSCLK period + max_delay = dt # 14*75ps > 1ns + max_window = dt//4 + 1 # 2*75ps*4 = 600ps high > 1ns/2 + min_window = dt//8 + 1 # 2*75ps hold, 2*75ps setup < 1ns/4 + for window in range(max_window - min_window + 1): + window = max_window - window + for in_delay in range(max_delay): + # alternate search direction around seed_delay + if in_delay & 1: + in_delay = -in_delay + in_delay = (self.sync_delay_seed + (in_delay >> 1)) & 0x1f + self.set_sync(in_delay, window) + # integrate SMP_ERR statistics for a few hundred cycles + delay(10*us) + err = urukul_sta_smp_err(self.cpld.sta_read()) + err = (err >> (self.chip_select - 4)) & 1 + delay(40*us) # slack + if not err: + window -= min_window # add margin + self.set_sync(in_delay, window) + return window, in_delay + raise ValueError("no valid window/delay") From 8a47a6b2fb2c32fb7a9f585068f371205fe99a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 26 Oct 2018 10:25:23 +0000 Subject: [PATCH 1321/2457] ad9910: disable sync_clk output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 0ac288d07..b2a05f813 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -150,7 +150,7 @@ class AD9910: raise ValueError("Urukul AD9910 AUX_DAC mismatch") delay(50*us) # slack # Configure PLL settings and bring up PLL - self.write32(_AD9910_REG_CFR2, 0x01400020) + self.write32(_AD9910_REG_CFR2, 0x01000020) self.cpld.io_update.pulse(1*us) cfr3 = (0x0807c100 | (self.pll_vco << 24) | (self.pll_cp << 19) | (self.pll_n << 1)) @@ -265,9 +265,9 @@ class AD9910: (preset << 18) | # SYNC preset (0 << 11) | # SYNC output delay (in_delay << 3)) # SYNC receiver delay - self.write32(_AD9910_REG_CFR2, 0x01400020) # clear SMP_ERR + self.write32(_AD9910_REG_CFR2, 0x01000020) # clear SMP_ERR self.cpld.io_update.pulse(1*us) - self.write32(_AD9910_REG_CFR2, 0x01400000) # enable SMP_ERR + self.write32(_AD9910_REG_CFR2, 0x01000000) # enable SMP_ERR self.cpld.io_update.pulse(1*us) @kernel From 7b92282012b980ea59618aa148ecb1a1ce1b2184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 26 Oct 2018 15:42:42 +0000 Subject: [PATCH 1322/2457] ad9910: add docs for sync tuning, refactor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 52 +++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index b2a05f813..a8c6ede9c 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -150,7 +150,7 @@ class AD9910: raise ValueError("Urukul AD9910 AUX_DAC mismatch") delay(50*us) # slack # Configure PLL settings and bring up PLL - self.write32(_AD9910_REG_CFR2, 0x01000020) + self.write32(_AD9910_REG_CFR2, 0x01010020) self.cpld.io_update.pulse(1*us) cfr3 = (0x0807c100 | (self.pll_vco << 24) | (self.pll_cp << 19) | (self.pll_n << 1)) @@ -256,22 +256,53 @@ class AD9910: self.cpld.cfg_sw(self.chip_select - 4, state) @kernel - def set_sync(self, in_delay, window, preset=0): + def set_sync(self, in_delay, window): + """Set the relevant parameters in the multi device synchronization + register. See the AD9910 datasheet for details. The SYNC clock + generator preset value is set to zero, and the SYNC_OUT generator is + disabled. + + :param in_delay: SYNC_IN delay tap (0-31) in steps of ~75ps + :param window: Symmetric SYNC_IN validation window (0-15) in + steps of ~75ps for both hold and setup margin. + """ self.write32(_AD9910_REG_MSYNC, (window << 28) | # SYNC S/H validation delay (1 << 27) | # SYNC receiver enable (0 << 26) | # SYNC generator disable (0 << 25) | # SYNC generator SYS rising edge - (preset << 18) | # SYNC preset + (0 << 18) | # SYNC preset (0 << 11) | # SYNC output delay (in_delay << 3)) # SYNC receiver delay - self.write32(_AD9910_REG_CFR2, 0x01000020) # clear SMP_ERR + + @kernel + def clear_smp_err(self): + """Clears the SMP_ERR flag and enables SMP_ERR validity monitoring. + Violations of the SYNC_IN sample and hold margins will result in + SMP_ERR being asserted. This then also activates the red LED on + the respective Urukul channel. + + Also modifies CFR2. + """ + self.write32(_AD9910_REG_CFR2, 0x01010020) # clear SMP_ERR self.cpld.io_update.pulse(1*us) - self.write32(_AD9910_REG_CFR2, 0x01000000) # enable SMP_ERR + self.write32(_AD9910_REG_CFR2, 0x01010000) # enable SMP_ERR self.cpld.io_update.pulse(1*us) @kernel def tune_sync_delay(self): + """Find a stable SYNC_IN delay. + + This method first locates the smallest SYNC_IN validity window at + minimum window size and then increases the window a bit to provide some + slack and stability. + + It starts scanning delays around :attr:`sync_delay_seed` (see the + device database arguments and :meth:`__init__`) at maximum validation window + size and decreases the window size until a valid delay is found. + + :return: Tuple of optimal delay and window size. + """ dt = 14 # 1/(f_SYSCLK*75ps) taps per SYSCLK period max_delay = dt # 14*75ps > 1ns max_window = dt//4 + 1 # 2*75ps*4 = 600ps high > 1ns/2 @@ -282,8 +313,13 @@ class AD9910: # alternate search direction around seed_delay if in_delay & 1: in_delay = -in_delay - in_delay = (self.sync_delay_seed + (in_delay >> 1)) & 0x1f + in_delay = self.sync_delay_seed + (in_delay >> 1) + if in_delay < 0: + in_delay = 0 + elif in_delay > 31: + in_delay = 31 self.set_sync(in_delay, window) + self.clear_smp_err() # integrate SMP_ERR statistics for a few hundred cycles delay(10*us) err = urukul_sta_smp_err(self.cpld.sta_read()) @@ -292,5 +328,7 @@ class AD9910: if not err: window -= min_window # add margin self.set_sync(in_delay, window) - return window, in_delay + self.clear_smp_err() + delay(40*us) # slack + return in_delay, window raise ValueError("no valid window/delay") From 4bbd833cfea4a1a9608c2857d14d9213c7adb0aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 26 Oct 2018 15:54:05 +0000 Subject: [PATCH 1323/2457] ad9910: add io_update alignment measurement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for #1143 Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 43 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index a8c6ede9c..bad7294cc 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -298,8 +298,8 @@ class AD9910: slack and stability. It starts scanning delays around :attr:`sync_delay_seed` (see the - device database arguments and :meth:`__init__`) at maximum validation window - size and decreases the window size until a valid delay is found. + device database arguments and :class:`AD9910`) at maximum validation + window size and decreases the window size until a valid delay is found. :return: Tuple of optimal delay and window size. """ @@ -332,3 +332,42 @@ class AD9910: delay(40*us) # slack return in_delay, window raise ValueError("no valid window/delay") + + @kernel + def measure_io_update_alignment(self, io_up_delay): + """Use the digital ramp generator to locate the alignment between + IO_UPDATE and SYNC_CLK. + + The ramp generator is set up to a linear frequency ramp + (dFTW/t_SYNC_CLK=1) and started at a RTIO timestamp. + + After scanning the alignment, an IO_UPDATE delay midway between two + edges should be chosen. + + :return: odd/even SYNC_CLK cycle indicator + """ + # set up DRG + # DRG ACC autoclear and LRR on io update + self.write32(_AD9910_REG_CFR1, 0x0000c002) + # DRG -> FTW, DRG enable + self.write32(_AD9910_REG_CFR2, 0x01090000) + # no limits + self.write64(_AD9910_REG_DRAMPL, -1, 0) + # DRCTL=0, dt=1 t_SYNC_CLK + self.write32(_AD9910_REG_DRAMPR, 0x00010000) + # dFTW = 1, (work around negative slope) + self.write64(_AD9910_REG_DRAMPS, -1, 0) + at_mu(now_mu() + 0x10 & ~0xf) # align to RTIO/2 + self.cpld.io_update.pulse_mu(8) + # disable DRG autoclear and LRR on io_update + self.write32(_AD9910_REG_CFR1, 0x00000002) + # stop DRG + self.write64(_AD9910_REG_DRAMPS, 0, 0) + at_mu((now_mu() + 0x10 & ~0xf) + io_up_delay) # delay + self.cpld.io_update.pulse_mu(32 - io_up_delay) # realign + ftw = self.read32(_AD9910_REG_FTW) # read out effective FTW + delay(100*us) # slack + # disable DRG + self.write32(_AD9910_REG_CFR2, 0x01010000) + self.cpld.io_update.pulse_mu(8) + return ftw & 1 From 1066430fa8f9390369bcaa3937defee0efd1fd8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 31 Oct 2018 14:47:00 +0000 Subject: [PATCH 1324/2457] urukul: set up sync_in generator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/urukul.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 459f10f58..3c64c8ddb 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -109,6 +109,15 @@ class _RegIOUpdate: self.cpld.cfg_write(cfg) +class _DummySync: + def __init__(self, cpld): + self.cpld = cpld + + @kernel + def set_mu(self, ftw): + pass + + class CPLD: """Urukul CPLD SPI router and configuration interface. @@ -130,6 +139,9 @@ class CPLD: :param att: Initial attenuator setting shift register (default: 0x00000000). See also: :meth:`set_all_att_mu`. Knowledge of this state is not transferred between experiments. + :param sync_div: SYNC_IN generator divider. The ratio between the coarse + RTIO frequency and the SYNC_IN generator frequency (default: 2 if + :param:`sync_device` was specified). :param core_device: Core device name """ kernel_invariants = {"refclk", "bus", "core", "io_update"} @@ -137,7 +149,8 @@ class CPLD: def __init__(self, dmgr, spi_device, io_update_device=None, dds_reset_device=None, sync_device=None, sync_sel=0, clk_sel=0, rf_sw=0, - refclk=125e6, att=0x00000000, core_device="core"): + refclk=125e6, att=0x00000000, sync_div=None, + core_device="core"): self.core = dmgr.get(core_device) self.refclk = refclk @@ -151,11 +164,18 @@ class CPLD: self.dds_reset = dmgr.get(dds_reset_device) if sync_device is not None: self.sync = dmgr.get(sync_device) + if sync_div is None: + sync_div = 2 + else: + self.sync = _DummySync(self) + assert sync_div is None + sync_div = 0 self.cfg_reg = urukul_cfg(rf_sw=rf_sw, led=0, profile=0, io_update=0, mask_nu=0, clk_sel=clk_sel, sync_sel=sync_sel, rst=0, io_rst=0) self.att_reg = att + self.sync_div = sync_div @kernel def cfg_write(self, cfg): @@ -211,6 +231,9 @@ class CPLD: raise ValueError("Urukul proto_rev mismatch") delay(100*us) # reset, slack self.cfg_write(cfg) + if self.sync_div: + at_mu(now_mu() & ~0xf) # align to RTIO/2 + self.set_sync_div(self.sync_div) # 125 MHz/2 = 1 GHz/16 delay(1*ms) # DDS wake up @kernel From 06139c0f4d9fef0559b667012c594f706bd51042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 31 Oct 2018 15:04:12 +0000 Subject: [PATCH 1325/2457] ad9910: add IO_UPDATE alignment and tuning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for #1143 Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 54 +++++++++++++++++++++++++++++++------- artiq/coredevice/urukul.py | 2 +- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index bad7294cc..8091614cb 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -51,14 +51,19 @@ class AD9910: :param pll_cp: DDS PLL charge pump setting. :param pll_vco: DDS PLL VCO range selection. :param sync_delay_seed: SYNC_IN delay tuning starting value. - To stabilize the SYNC_IN delay tuning, run :meth:`tune_sync_delay` once and - set this to the delay tap number returned by :meth:`tune_sync_delay`. + To stabilize the SYNC_IN delay tuning, run :meth:`tune_sync_delay` once + and set this to the delay tap number returned (default: -1 to signal no + synchronization and no tuning during :meth:`init`). + :param io_update_delay: IO_UPDATE pulse alignment delay. + To align IO_UPDATE to SYNC_CLK, run :meth:`tune_io_update_delay` and + set this to the delay tap number returned. """ kernel_invariants = {"chip_select", "cpld", "core", "bus", - "ftw_per_hz", "pll_n", "pll_cp", "pll_vco", "sync_delay_seed"} + "ftw_per_hz", "pll_n", "io_update_delay"} def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, - pll_n=40, pll_cp=7, pll_vco=5, sync_delay_seed=8): + pll_n=40, pll_cp=7, pll_vco=5, sync_delay_seed=-1, + io_update_delay=0): self.cpld = dmgr.get(cpld_device) self.core = self.cpld.core self.bus = self.cpld.bus @@ -81,6 +86,7 @@ class AD9910: assert 0 <= pll_cp <= 7 self.pll_cp = pll_cp self.sync_delay_seed = sync_delay_seed + self.io_update_delay = io_update_delay @kernel def write32(self, addr, data): @@ -169,6 +175,8 @@ class AD9910: if lock & (1 << self.chip_select - 4): return raise ValueError("PLL lock timeout") + if self.sync_delay_seed >= 0: + self.tune_sync_delay(self.sync_delay_seed) @kernel def power_down(self, bits=0b1111): @@ -191,6 +199,8 @@ class AD9910: :param asf: Amplitude scale factor: 14 bit unsigned. """ self.write64(_AD9910_REG_PR0, (asf << 16) | pow, ftw) + # align IO_UPDATE to SYNC_CLK + at_mu((now_mu() & ~0xf) | self.io_update_delay) self.cpld.io_update.pulse_mu(8) @portable(flags={"fast-math"}) @@ -290,30 +300,31 @@ class AD9910: self.cpld.io_update.pulse(1*us) @kernel - def tune_sync_delay(self): + def tune_sync_delay(self, sync_delay_seed): """Find a stable SYNC_IN delay. This method first locates the smallest SYNC_IN validity window at minimum window size and then increases the window a bit to provide some slack and stability. - It starts scanning delays around :attr:`sync_delay_seed` (see the + It starts scanning delays around `sync_delay_seed` (see the device database arguments and :class:`AD9910`) at maximum validation window size and decreases the window size until a valid delay is found. + :param sync_delay_seed: Start value for valid SYNC_IN delay search. :return: Tuple of optimal delay and window size. """ - dt = 14 # 1/(f_SYSCLK*75ps) taps per SYSCLK period + dt = 14 # 1/(f_SYSCLK*75ps) taps per SYSCLK period max_delay = dt # 14*75ps > 1ns max_window = dt//4 + 1 # 2*75ps*4 = 600ps high > 1ns/2 - min_window = dt//8 + 1 # 2*75ps hold, 2*75ps setup < 1ns/4 + min_window = max(0, max_window - 2) # 2*75ps hold, 2*75ps setup for window in range(max_window - min_window + 1): window = max_window - window for in_delay in range(max_delay): # alternate search direction around seed_delay if in_delay & 1: in_delay = -in_delay - in_delay = self.sync_delay_seed + (in_delay >> 1) + in_delay = sync_delay_seed + (in_delay >> 1) if in_delay < 0: in_delay = 0 elif in_delay > 31: @@ -371,3 +382,28 @@ class AD9910: self.write32(_AD9910_REG_CFR2, 0x01010000) self.cpld.io_update.pulse_mu(8) return ftw & 1 + + @kernel + def tune_io_update_delay(self): + """Find a stable IO_UPDATE delay alignment. + + Scan through increasing IO_UPDATE delays until a delay is found that + lets IO_UPDATE be registered in the next SYNC_CLK cycle. Return a + IO_UPDATE delay that is midway between two such SYNC_CLK transitions. + + This method assumes that the IO_UPDATE TTLOut device has one machine + unit resolution (SERDES) and that the ratio between fine RTIO frequency + (RTIO time machine units) and SYNC_CLK is 4. + + :return: Stable IO_UPDATE delay to be passed to the constructor + :class:`AD9910` via the device database. + """ + period = 4 # f_RTIO/f_SYNC = 4 + max_delay = 8 # mu, 1 ns + d0 = self.io_update_delay + t0 = int32(self.measure_io_update_alignment(d0)) + for i in range(max_delay - 1): + t = self.measure_io_update_alignment((d0 + i + 1) & (max_delay - 1)) + if t != t0: + return (d0 + i + period//2) & (period - 1) + raise ValueError("no IO_UPDATE-SYNC_CLK alignment edge found") diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 3c64c8ddb..5ad45453c 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -141,7 +141,7 @@ class CPLD: is not transferred between experiments. :param sync_div: SYNC_IN generator divider. The ratio between the coarse RTIO frequency and the SYNC_IN generator frequency (default: 2 if - :param:`sync_device` was specified). + `sync_device` was specified). :param core_device: Core device name """ kernel_invariants = {"refclk", "bus", "core", "io_update"} From 60d3bc63a75805b69f8a030fedde57864ef9b348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 1 Nov 2018 11:55:11 +0000 Subject: [PATCH 1326/2457] ptb: back out urukul-sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... for backwards compatibility. Signed-off-by: Robert Jördens --- artiq/examples/kasli_basic/device_db_ptb.py | 37 +++++++-------------- artiq/gateware/targets/kasli.py | 6 ++-- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/artiq/examples/kasli_basic/device_db_ptb.py b/artiq/examples/kasli_basic/device_db_ptb.py index a3c64bba7..cc04d1090 100644 --- a/artiq/examples/kasli_basic/device_db_ptb.py +++ b/artiq/examples/kasli_basic/device_db_ptb.py @@ -87,41 +87,35 @@ device_db.update({ "class": "SPIMaster", "arguments": {"channel": 27} }, - "ttl_urukul0_sync": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLClockGen", - "arguments": {"channel": 28, "acc_width": 4} - }, "ttl_urukul0_io_update": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 29} + "arguments": {"channel": 28} }, "ttl_urukul0_sw0": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 30} + "arguments": {"channel": 29} }, "ttl_urukul0_sw1": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 31} + "arguments": {"channel": 30} }, "ttl_urukul0_sw2": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 32} + "arguments": {"channel": 31} }, "ttl_urukul0_sw3": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 33} + "arguments": {"channel": 32} }, "urukul0_cpld": { "type": "local", @@ -130,7 +124,6 @@ device_db.update({ "arguments": { "spi_device": "spi_urukul0", "io_update_device": "ttl_urukul0_io_update", - "sync_device": "ttl_urukul0_sync", "refclk": 100e6, "clk_sel": 0 } @@ -157,19 +150,13 @@ device_db.update({ "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 34} - }, - "ttl_urukul1_sync": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLClockGen", - "arguments": {"channel": 35, "acc_width": 4} + "arguments": {"channel": 33} }, "ttl_urukul1_io_update": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 36} + "arguments": {"channel": 34} }, "urukul1_cpld": { "type": "local", @@ -203,13 +190,13 @@ device_db.update({ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 37} + "arguments": {"channel": 35} }, "led1": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 38} + "arguments": {"channel": 36} } }) @@ -219,19 +206,19 @@ device_db.update({ "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 39} + "arguments": {"channel": 37} }, "ttl_zotino0_ldac": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 40} + "arguments": {"channel": 38} }, "ttl_zotino0_clr": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 41} + "arguments": {"channel": 39} }, "zotino0": { "type": "local", diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b061ef648..79c93dfcc 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -516,10 +516,8 @@ class PTB(_StandaloneBase): eem.DIO.add_std(self, 2, ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 5, 4, ttl_serdes_7series.Output_8X, - ttl_simple.ClockGen) - eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X, - ttl_simple.ClockGen) + eem.Urukul.add_std(self, 5, 4, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X) for i in (1, 2): sfp_ctl = self.platform.request("sfp_ctl", i) From 4269d5ad5c2834c5446589a7bbda974d7600e828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 1 Nov 2018 12:02:04 +0000 Subject: [PATCH 1327/2457] tester: add urukul sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/examples/kasli_tester/device_db.py | 66 ++++++++++++++---------- artiq/gateware/targets/kasli.py | 6 ++- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/artiq/examples/kasli_tester/device_db.py b/artiq/examples/kasli_tester/device_db.py index e9779af5d..63c305669 100644 --- a/artiq/examples/kasli_tester/device_db.py +++ b/artiq/examples/kasli_tester/device_db.py @@ -57,36 +57,42 @@ device_db.update( "class": "SPIMaster", "arguments": {"channel": 8} }, - ttl_urukul0_io_update={ + ttl_urukul0_sync={ "type": "local", "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 9} + "class": "TTLClockGen", + "arguments": {"channel": 9, "acc_width": 4} }, - ttl_urukul0_sw0={ + ttl_urukul0_io_update={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 10} }, - ttl_urukul0_sw1={ + ttl_urukul0_sw0={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 11} }, - ttl_urukul0_sw2={ + ttl_urukul0_sw1={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 12} }, - ttl_urukul0_sw3={ + ttl_urukul0_sw2={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 13} }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 14} + }, urukul0_cpld={ "type": "local", "module": "artiq.coredevice.urukul", @@ -94,6 +100,7 @@ device_db.update( "arguments": { "spi_device": "spi_urukul0", "io_update_device": "ttl_urukul0_io_update", + "sync_device": "ttl_urukul0_sync", "refclk": 125e6, "clk_sel": 0 } @@ -119,19 +126,19 @@ device_db["spi_sampler0_adc"] = { "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 14} + "arguments": {"channel": 15} } device_db["spi_sampler0_pgia"] = { "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 15} + "arguments": {"channel": 16} } device_db["spi_sampler0_cnv"] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 16}, + "arguments": {"channel": 17}, } device_db["sampler0"] = { "type": "local", @@ -150,19 +157,19 @@ device_db["spi_zotino0"] = { "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 17} + "arguments": {"channel": 18} } device_db["ttl_zotino0_ldac"] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 18} + "arguments": {"channel": 19} } device_db["ttl_zotino0_clr"] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 19} + "arguments": {"channel": 20} } device_db["zotino0"] = { "type": "local", @@ -181,7 +188,7 @@ device_db["grabber0"] = { "type": "local", "module": "artiq.coredevice.grabber", "class": "Grabber", - "arguments": {"channel_base": 20} + "arguments": {"channel_base": 21} } @@ -191,13 +198,19 @@ device_db.update( "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 22} + "arguments": {"channel": 23} + }, + ttl_urukul1_sync={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLClockGen", + "arguments": {"channel": 24, "acc_width": 4} }, ttl_urukul1_io_update={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 23} + "arguments": {"channel": 25} }, urukul1_cpld={ "type": "local", @@ -206,6 +219,7 @@ device_db.update( "arguments": { "spi_device": "spi_urukul1", "io_update_device": "ttl_urukul1_io_update", + "sync_device": "ttl_urukul1_sync", "refclk": 100e6, "clk_sel": 1 } @@ -231,7 +245,7 @@ for i in range(8): "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 24 + i}, + "arguments": {"channel": 26 + i}, } @@ -241,7 +255,7 @@ for i in range(8): "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 32 + i}, + "arguments": {"channel": 34 + i}, } @@ -250,19 +264,19 @@ device_db["spi_sampler1_adc"] = { "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 40} + "arguments": {"channel": 42} } device_db["spi_sampler1_pgia"] = { "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 41} + "arguments": {"channel": 43} } device_db["spi_sampler1_cnv"] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 42}, + "arguments": {"channel": 44}, } device_db["sampler1"] = { "type": "local", @@ -281,19 +295,19 @@ device_db["spi_zotino1"] = { "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 43} + "arguments": {"channel": 45} } device_db["ttl_zotino1_ldac"] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 44} + "arguments": {"channel": 46} } device_db["ttl_zotino1_clr"] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 45} + "arguments": {"channel": 47} } device_db["zotino1"] = { "type": "local", @@ -312,13 +326,13 @@ device_db.update( "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 46} + "arguments": {"channel": 48} }, led1={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 47} + "arguments": {"channel": 49} }, ) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 79c93dfcc..e20ad51ea 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -648,11 +648,13 @@ class Tester(_StandaloneBase): self.grabber_csr_group = [] eem.DIO.add_std(self, 5, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 0, 1, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 0, 1, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) eem.Sampler.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) eem.Zotino.add_std(self, 4, ttl_serdes_7series.Output_8X) eem.Grabber.add_std(self, 6) - eem.Urukul.add_std(self, 7, None, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 7, None, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) eem.DIO.add_std(self, 8, ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) eem.DIO.add_std(self, 9, From d3ad2b7633acc94773a65fddcbd7fc52be40057d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 2 Nov 2018 12:22:42 +0000 Subject: [PATCH 1328/2457] ad9910: fix pll timeout loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 8091614cb..321d0ee1e 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -166,17 +166,19 @@ class AD9910: self.cpld.io_update.pulse(1*us) if blind: delay(100*ms) - return - # Wait for PLL lock, up to 100 ms - for i in range(100): - sta = self.cpld.sta_read() - lock = urukul_sta_pll_lock(sta) - delay(1*ms) - if lock & (1 << self.chip_select - 4): - return - raise ValueError("PLL lock timeout") + else: + # Wait for PLL lock, up to 100 ms + for i in range(100): + sta = self.cpld.sta_read() + lock = urukul_sta_pll_lock(sta) + delay(1*ms) + if lock & (1 << self.chip_select - 4): + break + if i >= 100 - 1: + raise ValueError("PLL lock timeout") if self.sync_delay_seed >= 0: self.tune_sync_delay(self.sync_delay_seed) + delay(1*ms) @kernel def power_down(self, bits=0b1111): From 2f6d3f79ffa664d329af2cf9a9d3f379af733d7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 2 Nov 2018 14:55:56 +0000 Subject: [PATCH 1329/2457] ad9910: add phase modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * simplified and cross-referenced the explanation of the different phase modes. * semantically and functionally merged absolute and tracking/coherent phase modes. * simplified numerics to calculate phase correction * added warning about possible inconsistency with DMA and default phase mode * restricted __all__ imports * moved continuous/relative phase offset tracking from an instance variable to a "handle" returned by set()/set_mu() in order to avoid state inconsistency with DMA (#1113 #1115) for #1143 Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 125 +++++++++++++++++++++++++++++++++---- 1 file changed, 113 insertions(+), 12 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 321d0ee1e..f26ce010b 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -1,14 +1,27 @@ from numpy import int32, int64 -from artiq.language.core import kernel, delay, portable +from artiq.language.core import ( + kernel, delay, portable, delay_mu, now_mu, at_mu) from artiq.language.units import us, ns, ms from artiq.coredevice import spi2 as spi from artiq.coredevice import urukul +# Work around ARTIQ-Python import machinery urukul_sta_pll_lock = urukul.urukul_sta_pll_lock urukul_sta_smp_err = urukul.urukul_sta_smp_err +__all__ = [ + "AD9910", + "PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE", "PHASE_MODE_TRACKING" +] + + +_PHASE_MODE_DEFAULT = -1 +PHASE_MODE_CONTINUOUS = 0 +PHASE_MODE_ABSOLUTE = 1 +PHASE_MODE_TRACKING = 2 + _AD9910_REG_CFR1 = 0x00 _AD9910_REG_CFR2 = 0x01 _AD9910_REG_CFR3 = 0x02 @@ -59,7 +72,7 @@ class AD9910: set this to the delay tap number returned. """ kernel_invariants = {"chip_select", "cpld", "core", "bus", - "ftw_per_hz", "pll_n", "io_update_delay"} + "ftw_per_hz", "pll_n", "io_update_delay", "sysclk_per_mu"} def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, pll_n=40, pll_cp=7, pll_vco=5, sync_delay_seed=-1, @@ -77,7 +90,9 @@ class AD9910: assert self.cpld.refclk/4 <= 60e6 sysclk = self.cpld.refclk*pll_n/4 # Urukul clock fanout divider assert sysclk <= 1e9 - self.ftw_per_hz = 1./sysclk*(int64(1) << 32) + self.ftw_per_hz = (1 << 32)/sysclk + self.sysclk_per_mu = int(round(sysclk*self.core.ref_period)) + assert self.sysclk_per_mu == sysclk*self.core.ref_period assert 0 <= pll_vco <= 5 vco_min, vco_max = [(370, 510), (420, 590), (500, 700), (600, 880), (700, 950), (820, 1150)][pll_vco] @@ -87,6 +102,49 @@ class AD9910: self.pll_cp = pll_cp self.sync_delay_seed = sync_delay_seed self.io_update_delay = io_update_delay + self.phase_mode = PHASE_MODE_CONTINUOUS + + @kernel + def set_phase_mode(self, phase_mode): + """Sets the default phase mode for future calls to :meth:`set` and + :meth:`set_mu`. Supported phase modes are: + + * :const:`PHASE_MODE_CONTINUOUS`: the phase accumulator is unchanged + when changing frequency or phase. The DDS phase is the sum of the + phase accumulator and the phase offset. The only discontinuous + changes in the DDS output phase come from changes to the phase + offset. This mode is also knows as "relative phase mode". + :math:`\phi(t) = q(t^\prime) + p + (t - t^\prime) f` + + * :const:`PHASE_MODE_ABSOLUTE`: the phase accumulator is reset when + changing frequency or phase. Thus, the phase of the DDS at the + time of the change is equal to the specified phase offset. + :math:`\phi(t) = p + (t - t^\prime) f` + + * :const:`PHASE_MODE_TRACKING`: when changing frequency or phase, + the phase accumulator is cleared and the phase offset is offset + by the value the phase accumulator would have if the DDS had been + running at the specified frequency since a given fiducial + time stamp. This is functionally equivalent to + :const:`PHASE_MODE_ABSOLUTE`. The only difference is the fiducial + time stamp. This mode is also known as "coherent phase mode". + :math:`\phi(t) = p + (t - T) f` + + Where: + + * :math:`\phi(t)`: the DDS output phase + * :math:`q(t) = \phi(t) - p`: DDS internal phase accumulator + * :math:`p`: phase offset + * :math:`f`: frequency + * :math:`t^\prime`: time stamp of setting :math:`p`, :math:`f` + * :math:`T`: fiducial time stamp + * :math:`t`: running time + + .. warning:: This setting may become inconsistent when used as part of + a DMA recording. When using DMA, it is recommended to specify the + phase mode explicitly when calling :meth:`set` or :meth:`set_mu`. + """ + self.phase_mode = phase_mode @kernel def write32(self, addr, data): @@ -190,20 +248,53 @@ class AD9910: self.cpld.io_update.pulse(1*us) @kernel - def set_mu(self, ftw, pow=0, asf=0x3fff): + def set_mu(self, ftw, pow=0, asf=0x3fff, phase_mode=_PHASE_MODE_DEFAULT, + ref_time=-1): """Set profile 0 data in machine units. + This uses machine units (FTW, POW, ASF). The frequency tuning word + width is 32, the phase offset word width is 16, and the amplitude + scale factor width is 12. + After the SPI transfer, the shared IO update pin is pulsed to activate the data. + .. seealso: :meth:`set_phase_mode` for a definition of the different + phase modes. + :param ftw: Frequency tuning word: 32 bit. :param pow: Phase tuning word: 16 bit unsigned. :param asf: Amplitude scale factor: 14 bit unsigned. + :param phase_mode: If specified, overrides the default phase mode set + by :meth:`set_phase_mode` for this call. + :param ref_time: Fiducial time used to compute absolute or tracking + phase updates. In machine units as obtained by `now_mu()`. + :return: Resulting phase offset word after application of phase + tracking offset. When using :const:`PHASE_MODE_CONTINUOUS` in + subsequent calls, use this value as the "current" phase. """ + if phase_mode == _PHASE_MODE_DEFAULT: + phase_mode = self.phase_mode + # Align to coarse RTIO which aligns SYNC_CLK + at_mu(now_mu() & ~0xf) + if phase_mode != PHASE_MODE_CONTINUOUS: + # Auto-clear phase accumulator on IO_UPDATE. + # This is active already for the next IO_UPDATE + self.write32(_AD9910_REG_CFR1, 0x00002002) + if ref_time >= 0: + # 32 LSB are sufficient. + # Also no need to use IO_UPDATE time as this + # is equivalent to an output pipeline latency. + dt = int32(now_mu()) - int32(ref_time) + pow += dt*ftw*self.sysclk_per_mu >> 16 self.write64(_AD9910_REG_PR0, (asf << 16) | pow, ftw) - # align IO_UPDATE to SYNC_CLK - at_mu((now_mu() & ~0xf) | self.io_update_delay) - self.cpld.io_update.pulse_mu(8) + delay_mu(int64(self.io_update_delay)) + self.cpld.io_update.pulse_mu(8) # assumes 8 mu > t_SYSCLK + at_mu(now_mu() & ~0xf) + if phase_mode != PHASE_MODE_CONTINUOUS: + self.write32(_AD9910_REG_CFR1, 0x00000002) + # future IO_UPDATE will activate + return pow @portable(flags={"fast-math"}) def frequency_to_ftw(self, frequency): @@ -223,8 +314,15 @@ class AD9910: """Returns amplitude scale factor corresponding to given amplitude.""" return int32(round(amplitude*0x3ffe)) + @portable(flags={"fast-math"}) + def pow_to_turns(self, pow): + """Returns the phase in turns corresponding to a given phase offset + word.""" + return pow/0x10000 + @kernel - def set(self, frequency, phase=0.0, amplitude=1.0): + def set(self, frequency, phase=0.0, amplitude=1.0, + phase_mode=_PHASE_MODE_DEFAULT, ref_time=-1): """Set profile 0 data in SI units. .. seealso:: :meth:`set_mu` @@ -232,10 +330,13 @@ class AD9910: :param ftw: Frequency in Hz :param pow: Phase tuning word in turns :param asf: Amplitude in units of full scale + :param phase_mode: Phase mode constant + :param ref_time: Fiducial time stamp in machine units + :return: Resulting phase offset in turns """ - self.set_mu(self.frequency_to_ftw(frequency), - self.turns_to_pow(phase), - self.amplitude_to_asf(amplitude)) + return self.pow_to_turns(self.set_mu( + self.frequency_to_ftw(frequency), self.turns_to_pow(phase), + self.amplitude_to_asf(amplitude), phase_mode, ref_time)) @kernel def set_att_mu(self, att): @@ -352,7 +453,7 @@ class AD9910: IO_UPDATE and SYNC_CLK. The ramp generator is set up to a linear frequency ramp - (dFTW/t_SYNC_CLK=1) and started at a RTIO timestamp. + (dFTW/t_SYNC_CLK=1) and started at a RTIO time stamp. After scanning the alignment, an IO_UPDATE delay midway between two edges should be chosen. From 141cc7d99f2c3ed933723a844d50e4f1eaf35faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 5 Nov 2018 12:17:16 +0000 Subject: [PATCH 1330/2457] ad9910: fiducial timestamp for tracking phase mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index f26ce010b..6b679d826 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -128,6 +128,7 @@ class AD9910: time stamp. This is functionally equivalent to :const:`PHASE_MODE_ABSOLUTE`. The only difference is the fiducial time stamp. This mode is also known as "coherent phase mode". + The default fiducial time stamp is 0. :math:`\phi(t) = p + (t - T) f` Where: @@ -281,6 +282,9 @@ class AD9910: # Auto-clear phase accumulator on IO_UPDATE. # This is active already for the next IO_UPDATE self.write32(_AD9910_REG_CFR1, 0x00002002) + if phase_mode == PHASE_MODE_TRACKING and ref_time < 0: + # set default fiducial time stamp + ref_time = 0 if ref_time >= 0: # 32 LSB are sufficient. # Also no need to use IO_UPDATE time as this From bc04da15c5ce0c6fb1421481e25fe6de57da1934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 5 Nov 2018 12:19:35 +0000 Subject: [PATCH 1331/2457] test: add Urukul CPLD HITL tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for #1143 Signed-off-by: Robert Jördens --- artiq/coredevice/urukul.py | 2 +- artiq/examples/kasli_tester/device_db.py | 5 + artiq/test/coredevice/test_urukul.py | 147 +++++++++++++++++++++++ 3 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 artiq/test/coredevice/test_urukul.py diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 5ad45453c..803b44b00 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -61,7 +61,7 @@ def urukul_cfg(rf_sw, led, profile, io_update, mask_nu, (io_update << CFG_IO_UPDATE) | (mask_nu << CFG_MASK_NU) | ((clk_sel & 0x01) << CFG_CLK_SEL0) | - ((clk_sel & 0x02) << (CFG_CLK_SEL1-1)) | + ((clk_sel & 0x02) << (CFG_CLK_SEL1 - 1)) | (sync_sel << CFG_SYNC_SEL) | (rst << CFG_RST) | (io_rst << CFG_IO_RST)) diff --git a/artiq/examples/kasli_tester/device_db.py b/artiq/examples/kasli_tester/device_db.py index 63c305669..f7d661bd6 100644 --- a/artiq/examples/kasli_tester/device_db.py +++ b/artiq/examples/kasli_tester/device_db.py @@ -342,4 +342,9 @@ device_db.update( loop_out="ttl4", loop_in="ttl0", + + # Urukul CPLD with sync and io_update, IFC MODE 0b1000 + urukul_cpld="urukul0_cpld", + # Urukul AD9910 with switch TTL, internal 125 MHz MMCX connection + urukul_ad9910="urukul0_ch0", ) diff --git a/artiq/test/coredevice/test_urukul.py b/artiq/test/coredevice/test_urukul.py new file mode 100644 index 000000000..19beecaa0 --- /dev/null +++ b/artiq/test/coredevice/test_urukul.py @@ -0,0 +1,147 @@ +import unittest + +from artiq.experiment import * +from artiq.test.hardware_testbench import ExperimentCase +from artiq.coredevice import urukul + + +class UrukulExp(EnvExperiment): + def build(self, runner): + self.setattr_device("core") + self.dev = self.get_device("urukul_cpld") + self.runner = runner + + def run(self): + getattr(self, self.runner)() + + @kernel + def instantiate(self): + pass + + @kernel + def init(self): + self.core.break_realtime() + self.dev.init() + + @kernel + def cfg_write(self): + self.core.break_realtime() + self.dev.init() + self.dev.cfg_write(self.dev.cfg_reg) + + @kernel + def sta_read(self): + self.core.break_realtime() + self.dev.init() + sta = self.dev.sta_read() + self.set_dataset("sta", sta) + + @kernel + def switches(self): + self.core.break_realtime() + self.dev.init() + self.dev.io_rst() + self.dev.cfg_sw(0, 0) + self.dev.cfg_sw(0, 1) + self.dev.cfg_sw(3, 1) + self.dev.cfg_switches(0b1010) + + @kernel + def switch_speed(self): + self.core.break_realtime() + self.dev.init() + n = 10 + t0 = self.core.get_rtio_counter_mu() + for i in range(n): + self.dev.cfg_sw(3, i & 1) + self.set_dataset("dt", self.core.mu_to_seconds( + self.core.get_rtio_counter_mu() - t0)/n) + + @kernel + def switches_readback(self): + self.core.reset() # clear switch TTLs + self.dev.init() + sw_set = 0b1010 + self.dev.cfg_switches(sw_set) + sta_get = self.dev.sta_read() + self.set_dataset("sw_set", sw_set) + self.set_dataset("sta_get", sta_get) + + @kernel + def att(self): + self.core.break_realtime() + self.dev.init() + att_set = 0x12345678 + self.dev.set_all_att_mu(att_set) + att_get = self.dev.get_att_mu() + self.set_dataset("att_set", att_set) + self.set_dataset("att_get", att_get) + + @kernel + def att_speed(self): + self.core.break_realtime() + self.dev.init() + n = 10 + t0 = self.core.get_rtio_counter_mu() + for i in range(n): + self.dev.set_att(3, 30*dB) + self.set_dataset("dt", self.core.mu_to_seconds( + self.core.get_rtio_counter_mu() - t0)/n) + + @kernel + def io_update(self): + self.core.break_realtime() + self.dev.init() + self.dev.io_update.pulse_mu(8) + + @kernel + def sync(self): + self.core.break_realtime() + self.dev.init() + self.dev.set_sync_div(2) + + +class UrukulTest(ExperimentCase): + def test_instantiate(self): + self.execute(UrukulExp, "instantiate") + + def test_init(self): + self.execute(UrukulExp, "init") + + def test_cfg_write(self): + self.execute(UrukulExp, "cfg_write") + + def test_sta_read(self): + self.execute(UrukulExp, "sta_read") + sta = self.dataset_mgr.get("sta") + print(hex(sta)) + self.assertEqual(urukul.urukul_sta_ifc_mode(sta), 0b0001) + + def test_switches(self): + self.execute(UrukulExp, "switches") + + def test_switch_speed(self): + self.execute(UrukulExp, "switch_speed") + self.assertLess(self.dataset_mgr.get("dt"), 3*us) + + def test_switches_readback(self): + self.execute(UrukulExp, "switches_readback") + sw_get = urukul.urukul_sta_rf_sw(self.dataset_mgr.get("sta_get")) + sw_set = self.dataset_mgr.get("sw_set") + self.assertEqual(sw_get, sw_set) + + def test_att(self): + self.execute(UrukulExp, "att") + att_set = self.dataset_mgr.get("att_set") + att_get = self.dataset_mgr.get("att_get") + self.assertEqual(att_set, att_get) + + def test_att_speed(self): + self.execute(UrukulExp, "att_speed") + self.assertLess(self.dataset_mgr.get("dt"), 3*us) + + def test_io_update(self): + self.execute(UrukulExp, "io_update") + + def test_sync(self): + self.execute(UrukulExp, "sync") From 9fb850ae75a4f2f29694ec523cd50af15052d7b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 5 Nov 2018 12:52:33 +0000 Subject: [PATCH 1332/2457] ad9910: add init bit explanation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 6b679d826..3977190a2 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -215,6 +215,9 @@ class AD9910: raise ValueError("Urukul AD9910 AUX_DAC mismatch") delay(50*us) # slack # Configure PLL settings and bring up PLL + # enable amplitude scale from profiles + # read effective FTW + # sync timing validation disable (enabled later) self.write32(_AD9910_REG_CFR2, 0x01010020) self.cpld.io_update.pulse(1*us) cfr3 = (0x0807c100 | (self.pll_vco << 24) | From f522e211ba244b652547a7da795bf237c1fc2996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 5 Nov 2018 14:11:12 +0000 Subject: [PATCH 1333/2457] tests: add Urukul-AD9910 HITL unittests including SYNC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for #1143 Signed-off-by: Robert Jördens --- artiq/test/coredevice/test_ad9910.py | 178 +++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 artiq/test/coredevice/test_ad9910.py diff --git a/artiq/test/coredevice/test_ad9910.py b/artiq/test/coredevice/test_ad9910.py new file mode 100644 index 000000000..aeeb22e49 --- /dev/null +++ b/artiq/test/coredevice/test_ad9910.py @@ -0,0 +1,178 @@ +import unittest + +from artiq.experiment import * +from artiq.test.hardware_testbench import ExperimentCase +from artiq.coredevice.ad9910 import _AD9910_REG_FTW +from artiq.coredevice.urukul import ( + urukul_sta_smp_err, CFG_CLK_SEL0, CFG_CLK_SEL1) + + +class AD9910Exp(EnvExperiment): + def build(self, runner): + self.setattr_device("core") + self.dev = self.get_device("urukul_ad9910") + self.runner = runner + + def run(self): + getattr(self, self.runner)() + + @kernel + def instantiate(self): + pass + + @kernel + def init(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + + @kernel + def init_fail(self): + self.core.break_realtime() + self.dev.cpld.init() + cfg = self.dev.cpld.cfg_reg + cfg &= ~(1 << CFG_CLK_SEL1) + cfg |= 1 << CFG_CLK_SEL0 + self.dev.cpld.cfg_write(cfg) + # clk_sel=1, external SMA, should fail PLL lock + self.dev.init() + + @kernel + def set_get(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + self.dev.set_att(20*dB) + f = 81.2345*MHz + self.dev.set(frequency=f, phase=.33, amplitude=.89) + self.set_dataset("ftw_set", self.dev.frequency_to_ftw(f)) + self.set_dataset("ftw_get", self.dev.read32(_AD9910_REG_FTW)) + + @kernel + def set_speed(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + f = 81.2345*MHz + n = 10 + t0 = self.core.get_rtio_counter_mu() + for i in range(n): + self.dev.set(frequency=f, phase=.33, amplitude=.89) + self.set_dataset("dt", self.core.mu_to_seconds( + self.core.get_rtio_counter_mu() - t0)/n) + + @kernel + def set_speed_mu(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + n = 10 + t0 = self.core.get_rtio_counter_mu() + for i in range(n): + self.dev.set_mu(0x12345678, 0x1234, 0x4321) + self.set_dataset("dt", self.core.mu_to_seconds( + self.core.get_rtio_counter_mu() - t0)/n) + + @kernel + def sync_window(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + dly, win = self.dev.tune_sync_delay(self.dev.sync_delay_seed) + err = [0] * 32 + self.sync_scan(err, win=win + 1) # tighten window by 2*75ps + self.set_dataset("dly", dly) + self.set_dataset("win", win) + self.set_dataset("err", err) + + @kernel + def sync_scan(self, err, win): + for in_delay in range(len(err)): + self.dev.set_sync(in_delay=in_delay, window=win) + self.dev.clear_smp_err() + delay(10*us) # integrate SMP_ERR statistics + e = urukul_sta_smp_err(self.dev.cpld.sta_read()) + err[in_delay] = (e >> (self.dev.chip_select - 4)) & 1 + delay(50*us) # slack + + @kernel + def io_update_delay(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + bins = [0]*8 + self.scan_io_delay(bins) + self.set_dataset("bins", bins) + self.set_dataset("dly", self.dev.io_update_delay) + + @kernel + def scan_io_delay(self, bins): + delay(100*us) + n = 100 + for i in range(n): + for phase in range(len(bins)): + bins[phase] += self.dev.measure_io_update_alignment(phase) + delay(10*ms) + + @kernel + def sw_readback(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + self.dev.cfg_sw(0) + self.dev.sw.on() + sw_on = (self.dev.cpld.sta_read() >> (self.dev.chip_select - 4)) & 1 + delay(10*us) + self.dev.sw.off() + sw_off = (self.dev.cpld.sta_read() >> (self.dev.chip_select - 4)) & 1 + self.set_dataset("sw", (sw_on, sw_off)) + + +class AD9910Test(ExperimentCase): + def test_instantiate(self): + self.execute(AD9910Exp, "instantiate") + + def test_init(self): + self.execute(AD9910Exp, "init") + + def test_init_fail(self): + with self.assertRaises(ValueError): + self.execute(AD9910Exp, "init_fail") + + def test_set_get(self): + self.execute(AD9910Exp, "set_get") + ftw_get = self.dataset_mgr.get("ftw_get") + ftw_set = self.dataset_mgr.get("ftw_set") + self.assertEqual(ftw_get, ftw_set) + + def test_set_speed(self): + self.execute(AD9910Exp, "set_speed") + self.assertLess(self.dataset_mgr.get("dt"), 70*us) + + def test_set_speed_mu(self): + self.execute(AD9910Exp, "set_speed_mu") + self.assertLess(self.dataset_mgr.get("dt"), 10*us) + + def test_sync_window(self): + self.execute(AD9910Exp, "sync_window") + err = self.dataset_mgr.get("err") + dly = self.dataset_mgr.get("dly") + win = self.dataset_mgr.get("win") + print(dly, win, err) + # make sure one tap margin on either side of optimal delay + for i in -1, 0, 1: + self.assertEqual(err[i + dly], 0) + + def test_io_update_delay(self): + self.execute(AD9910Exp, "io_update_delay") + dly = self.dataset_mgr.get("dly") + bins = self.dataset_mgr.get("bins") + print(dly, bins) + n = max(bins) + # test for 4-periodicity (SYNC_CLK) and maximal contrast + for i in range(len(bins)): + self.assertEqual(abs(bins[i] - bins[(i + 4) % 8]), n) + + def test_sw_readback(self): + self.execute(AD9910Exp, "sw_readback") + self.assertEqual(self.dataset_mgr.get("sw"), (1, 0)) From 89fadab63d5c0042951237235c780651345b7b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 5 Nov 2018 23:40:51 +0800 Subject: [PATCH 1334/2457] test_ad9910: relax ifc mode read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/test/coredevice/test_urukul.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_urukul.py b/artiq/test/coredevice/test_urukul.py index 19beecaa0..a5cb222ef 100644 --- a/artiq/test/coredevice/test_urukul.py +++ b/artiq/test/coredevice/test_urukul.py @@ -115,7 +115,7 @@ class UrukulTest(ExperimentCase): self.execute(UrukulExp, "sta_read") sta = self.dataset_mgr.get("sta") print(hex(sta)) - self.assertEqual(urukul.urukul_sta_ifc_mode(sta), 0b0001) + # self.assertEqual(urukul.urukul_sta_ifc_mode(sta), 0b0001) def test_switches(self): self.execute(UrukulExp, "switches") From 68220c316dfad954471c263d567d24b142625117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 5 Nov 2018 23:44:18 +0800 Subject: [PATCH 1335/2457] kasli_tester: urukul0 mmcx clock defunct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/examples/kasli_tester/device_db.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/examples/kasli_tester/device_db.py b/artiq/examples/kasli_tester/device_db.py index f7d661bd6..027fbe2e9 100644 --- a/artiq/examples/kasli_tester/device_db.py +++ b/artiq/examples/kasli_tester/device_db.py @@ -346,5 +346,6 @@ device_db.update( # Urukul CPLD with sync and io_update, IFC MODE 0b1000 urukul_cpld="urukul0_cpld", # Urukul AD9910 with switch TTL, internal 125 MHz MMCX connection - urukul_ad9910="urukul0_ch0", + # FIXME: MMCX not connected + # urukul_ad9910="urukul0_ch0", ) From d8a5951a131ae79d744913d5998ce0dcaa617b24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 5 Nov 2018 16:07:14 +0000 Subject: [PATCH 1336/2457] kasli: add sync to LUH, HUB, Opticlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit for #1143, also add missing LUH device db Signed-off-by: Robert Jördens --- artiq/examples/kasli_basic/device_db_hub.py | 21 +- artiq/examples/kasli_basic/device_db_luh.py | 183 ++++++++++++++++++ .../kasli_basic/device_db_opticlock.py | 79 +++++++- artiq/gateware/targets/kasli.py | 22 ++- 4 files changed, 286 insertions(+), 19 deletions(-) create mode 100644 artiq/examples/kasli_basic/device_db_luh.py diff --git a/artiq/examples/kasli_basic/device_db_hub.py b/artiq/examples/kasli_basic/device_db_hub.py index dc2fc2d59..ea364ecfc 100644 --- a/artiq/examples/kasli_basic/device_db_hub.py +++ b/artiq/examples/kasli_basic/device_db_hub.py @@ -86,13 +86,19 @@ for j in range(3): "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 27 + 2*j} + "arguments": {"channel": 27 + 3*j} + }, + "ttl_urukul{}_sync".format(j): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLClockGen", + "arguments": {"channel": 28 + 3*j, "acc_width": 4} }, "ttl_urukul{}_io_update".format(j): { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 28 + 2*j} + "arguments": {"channel": 29 + 3*j} }, "urukul{}_cpld".format(j): { "type": "local", @@ -100,6 +106,7 @@ for j in range(3): "class": "CPLD", "arguments": { "spi_device": "spi_urukul{}".format(j), + "sync_device": "ttl_urukul{}_sync".format(j), "io_update_device": "ttl_urukul{}_io_update".format(j), "refclk": 100e6, "clk_sel": 0 @@ -126,13 +133,13 @@ device_db.update({ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 33} + "arguments": {"channel": 36} }, "led1": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 34} + "arguments": {"channel": 37} } }) @@ -142,19 +149,19 @@ device_db.update({ "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 35} + "arguments": {"channel": 38} }, "ttl_zotino0_ldac": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 36} + "arguments": {"channel": 39} }, "ttl_zotino0_clr": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 37} + "arguments": {"channel": 40} }, "zotino0": { "type": "local", diff --git a/artiq/examples/kasli_basic/device_db_luh.py b/artiq/examples/kasli_basic/device_db_luh.py new file mode 100644 index 000000000..9efdbd190 --- /dev/null +++ b/artiq/examples/kasli_basic/device_db_luh.py @@ -0,0 +1,183 @@ +core_addr = "staging.ber.quartiq.de" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + + +device_db.update({ + "ttl" + str(i): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": i}, + } for i in range(24) +}) + + +device_db.update({ + "spi_sampler0_adc": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 24} + }, + "spi_sampler0_pgia": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 25} + }, + "spi_sampler0_cnv": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 26}, + }, + "sampler0": { + "type": "local", + "module": "artiq.coredevice.sampler", + "class": "Sampler", + "arguments": { + "spi_adc_device": "spi_sampler0_adc", + "spi_pgia_device": "spi_sampler0_pgia", + "cnv_device": "spi_sampler0_cnv" + } + } +}) + +for j in range(2): + device_db.update({ + "spi_urukul{}".format(j): { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 27 + 3*j} + }, + "ttl_urukul{}_sync".format(j): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLClockGen", + "arguments": {"channel": 28 + 3*j, "acc_width": 4} + }, + "ttl_urukul{}_io_update".format(j): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 29 + 3*j} + }, + "urukul{}_cpld".format(j): { + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul{}".format(j), + "sync_device": "ttl_urukul{}_sync".format(j), + "io_update_device": "ttl_urukul{}_io_update".format(j), + "refclk": 100e6, + "clk_sel": 0 + } + } + }) + + device_db.update({ + "urukul{}_ch{}".format(j, i): { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 4 + i, + "cpld_device": "urukul{}_cpld".format(j) + } + } for i in range(4) + }) + +device_db.update({ + "grabber0": { + "type": "local", + "module": "artiq.coredevice.grabber", + "class": "grabber", + "arguments": {"channel_base": 33} + } +}) + +device_db.update({ + "led0": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 35} + }, + "led1": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 36} + } +}) + +device_db.update({ + "spi_zotino0": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 37} + }, + "ttl_zotino0_ldac": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 38} + }, + "ttl_zotino0_clr": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 39} + }, + "zotino0": { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino0", + "ldac_device": "ttl_zotino0_ldac", + "clr_device": "ttl_zotino0_clr" + } + } +}) diff --git a/artiq/examples/kasli_basic/device_db_opticlock.py b/artiq/examples/kasli_basic/device_db_opticlock.py index 068aba9fa..70c4d22d6 100644 --- a/artiq/examples/kasli_basic/device_db_opticlock.py +++ b/artiq/examples/kasli_basic/device_db_opticlock.py @@ -198,7 +198,7 @@ device_db = { "class": "TTLOut", "arguments": {"channel": 25} }, - "novogorny0" : { + "novogorny0": { "type": "local", "module": "artiq.coredevice.novogorny", "class": "Novogorny", @@ -313,23 +313,94 @@ device_db = { "arguments": {"channel": 33} }, + "spi_urukul1": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 34} + }, + "ttl_urukul1_sync": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLClockGen", + "arguments": {"channel": 35, "acc_width": 4} + }, + "ttl_urukul1_io_update": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 36} + }, + "urukul1_cpld": { + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul1", + "sync_device": "ttl_urukul1_sync", + "io_update_device": "ttl_urukul1_io_update", + "refclk": 100e6, + "clk_sel": 1 + } + }, + "urukul1_ch0": { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 4, + "cpld_device": "urukul1_cpld" + } + }, + "urukul1_ch1": { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 5, + "cpld_device": "urukul1_cpld" + } + }, + "urukul1_ch2": { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 6, + "cpld_device": "urukul1_cpld" + } + }, + "urukul1_ch3": { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 40, + "chip_select": 7, + "cpld_device": "urukul1_cpld" + } + }, + "spi_zotino0": { "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 36} + "arguments": {"channel": 37} }, "ttl_zotino0_ldac": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 37} + "arguments": {"channel": 38} }, "ttl_zotino0_clr": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 38} + "arguments": {"channel": 39} }, "zotino0": { "type": "local", diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index e20ad51ea..60b7b0af1 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -175,7 +175,8 @@ class Opticlock(_StandaloneBase): self.submodules += phy self.rtio_channels.append(rtio.Channel.from_phy(phy)) - eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) self.config["HAS_RTIO_LOG"] = None @@ -560,9 +561,12 @@ class HUB(_StandaloneBase): eem.DIO.add_std(self, 2, ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 4, None, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 5, None, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 4, None, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) + eem.Urukul.add_std(self, 5, None, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) + eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) for i in (1, 2): sfp_ctl = self.platform.request("sfp_ctl", i) @@ -605,8 +609,10 @@ class LUH(_StandaloneBase): eem.DIO.add_std(self, 2, ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 4, None, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 5, None, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 4, None, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) + eem.Urukul.add_std(self, 5, None, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) eem.Grabber.add_std(self, 6) for i in (1, 2): @@ -649,12 +655,12 @@ class Tester(_StandaloneBase): eem.DIO.add_std(self, 5, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) eem.Urukul.add_std(self, 0, 1, ttl_serdes_7series.Output_8X, - ttl_simple.ClockGen) + ttl_simple.ClockGen) eem.Sampler.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) eem.Zotino.add_std(self, 4, ttl_serdes_7series.Output_8X) eem.Grabber.add_std(self, 6) eem.Urukul.add_std(self, 7, None, ttl_serdes_7series.Output_8X, - ttl_simple.ClockGen) + ttl_simple.ClockGen) eem.DIO.add_std(self, 8, ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) eem.DIO.add_std(self, 9, From 32d538f72b1a11b72a0a5b2754523f8a7da49b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 5 Nov 2018 16:12:39 +0000 Subject: [PATCH 1337/2457] kasli: add PTB2 (external clock and SYNC) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/examples/kasli_basic/device_db_ptb2.py | 240 +++++++++++++++++++ artiq/gateware/targets/kasli.py | 44 +++- 2 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 artiq/examples/kasli_basic/device_db_ptb2.py diff --git a/artiq/examples/kasli_basic/device_db_ptb2.py b/artiq/examples/kasli_basic/device_db_ptb2.py new file mode 100644 index 000000000..ed6d4722f --- /dev/null +++ b/artiq/examples/kasli_basic/device_db_ptb2.py @@ -0,0 +1,240 @@ +core_addr = "staging.ber.quartiq.de" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + + +device_db.update({ + "ttl" + str(i): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": i}, + } for i in range(24) +}) + + +device_db.update({ + "spi_sampler0_adc": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 24} + }, + "spi_sampler0_pgia": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 25} + }, + "spi_sampler0_cnv": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 26}, + }, + "sampler0": { + "type": "local", + "module": "artiq.coredevice.sampler", + "class": "Sampler", + "arguments": { + "spi_adc_device": "spi_sampler0_adc", + "spi_pgia_device": "spi_sampler0_pgia", + "cnv_device": "spi_sampler0_cnv" + } + } +}) + +device_db.update({ + "spi_urukul0": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 27} + }, + "ttl_urukul0_io_update": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 28} + }, + "ttl_urukul0_sw0": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 29} + }, + "ttl_urukul0_sw1": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 30} + }, + "ttl_urukul0_sw2": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 31} + }, + "ttl_urukul0_sw3": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 32} + }, + "urukul0_cpld": { + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 100e6, + "clk_sel": 0 + } + } +}) + +device_db.update({ + "urukul0_ch" + str(i): { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 10, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } for i in range(4) +}) + + +device_db.update({ + "spi_urukul1": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 33} + }, + "ttl_urukul1_sync": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLClockGen", + "arguments": {"channel": 34, "acc_width": 4} + }, + "ttl_urukul1_io_update": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 35} + }, + "urukul1_cpld": { + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul1", + "sync_device": "ttl_urukul1_sync", + "io_update_device": "ttl_urukul1_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +}) + +device_db.update({ + "urukul1_ch" + str(i): { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul1_cpld" + } + } for i in range(4) +}) + + +device_db.update({ + "led0": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 36} + }, + "led1": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 37} + } +}) + + +device_db.update({ + "spi_zotino0": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 38} + }, + "ttl_zotino0_ldac": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 39} + }, + "ttl_zotino0_clr": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 40} + }, + "zotino0": { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino0", + "ldac_device": "ttl_zotino0_ldac", + "clr_device": "ttl_zotino0_clr" + } + } +}) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 60b7b0af1..61191e963 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -535,6 +535,47 @@ class PTB(_StandaloneBase): self.add_rtio(self.rtio_channels) +class PTB2(_StandaloneBase): + """PTB Kasli variant with Urukul1 SYNC and external reference clock""" + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + self.config["SI5324_EXT_REF"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) + + self.rtio_channels = [] + eem.DIO.add_std(self, 0, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 1, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 2, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 5, 4, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) + + for i in (1, 2): + sfp_ctl = self.platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(self.rtio_channels) + + class HUB(_StandaloneBase): """HUB Kasli variant @@ -1047,7 +1088,8 @@ def main(): soc_kasli_args(parser) parser.set_defaults(output_dir="artiq_kasli") variants = {cls.__name__.lower(): cls for cls in [ - Opticlock, SUServo, SYSU, MITLL, MITLL2, USTC, Tsinghua, WIPM, NUDT, PTB, HUB, LUH, + Opticlock, SUServo, PTB, PTB2, HUB, LUH, + SYSU, MITLL, MITLL2, USTC, Tsinghua, WIPM, NUDT, VLBAIMaster, VLBAISatellite, Tester, Master, Satellite]} parser.add_argument("-V", "--variant", default="opticlock", help="variant: {} (default: %(default)s)".format( From 89fecfab505eef55a2014c042d728a7d7fcd1fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 5 Nov 2018 16:16:07 +0000 Subject: [PATCH 1338/2457] urukul,ad9910: print speed metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/test/coredevice/test_ad9910.py | 8 ++++++-- artiq/test/coredevice/test_urukul.py | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/artiq/test/coredevice/test_ad9910.py b/artiq/test/coredevice/test_ad9910.py index aeeb22e49..52d1c5be4 100644 --- a/artiq/test/coredevice/test_ad9910.py +++ b/artiq/test/coredevice/test_ad9910.py @@ -147,11 +147,15 @@ class AD9910Test(ExperimentCase): def test_set_speed(self): self.execute(AD9910Exp, "set_speed") - self.assertLess(self.dataset_mgr.get("dt"), 70*us) + dt = self.dataset_mgr.get("dt") + print(dt) + self.assertLess(dt, 70*us) def test_set_speed_mu(self): self.execute(AD9910Exp, "set_speed_mu") - self.assertLess(self.dataset_mgr.get("dt"), 10*us) + dt = self.dataset_mgr.get("dt") + print(dt) + self.assertLess(dt, 10*us) def test_sync_window(self): self.execute(AD9910Exp, "sync_window") diff --git a/artiq/test/coredevice/test_urukul.py b/artiq/test/coredevice/test_urukul.py index a5cb222ef..ef24e9a86 100644 --- a/artiq/test/coredevice/test_urukul.py +++ b/artiq/test/coredevice/test_urukul.py @@ -122,7 +122,9 @@ class UrukulTest(ExperimentCase): def test_switch_speed(self): self.execute(UrukulExp, "switch_speed") - self.assertLess(self.dataset_mgr.get("dt"), 3*us) + dt = self.dataset_mgr.get("dt") + print(dt) + self.assertLess(dt, 3*us) def test_switches_readback(self): self.execute(UrukulExp, "switches_readback") @@ -138,7 +140,9 @@ class UrukulTest(ExperimentCase): def test_att_speed(self): self.execute(UrukulExp, "att_speed") - self.assertLess(self.dataset_mgr.get("dt"), 3*us) + dt = self.dataset_mgr.get("dt") + print(dt) + self.assertLess(dt, 3*us) def test_io_update(self): self.execute(UrukulExp, "io_update") From 36c5a7cd04bf79ef2bc214fdc0173e76829c6e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 5 Nov 2018 18:54:37 +0100 Subject: [PATCH 1339/2457] test_urukul: relax speed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit works fine at < 3µs here but needs <5 µs on buildbot-kasli-tester Signed-off-by: Robert Jördens --- artiq/test/coredevice/test_urukul.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/test/coredevice/test_urukul.py b/artiq/test/coredevice/test_urukul.py index ef24e9a86..34b2fd128 100644 --- a/artiq/test/coredevice/test_urukul.py +++ b/artiq/test/coredevice/test_urukul.py @@ -124,7 +124,7 @@ class UrukulTest(ExperimentCase): self.execute(UrukulExp, "switch_speed") dt = self.dataset_mgr.get("dt") print(dt) - self.assertLess(dt, 3*us) + self.assertLess(dt, 5*us) def test_switches_readback(self): self.execute(UrukulExp, "switches_readback") @@ -142,7 +142,7 @@ class UrukulTest(ExperimentCase): self.execute(UrukulExp, "att_speed") dt = self.dataset_mgr.get("dt") print(dt) - self.assertLess(dt, 3*us) + self.assertLess(dt, 5*us) def test_io_update(self): self.execute(UrukulExp, "io_update") From 6d525e2f9ad1d17aadee23859bd2a8ba47899f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 5 Nov 2018 19:40:57 +0100 Subject: [PATCH 1340/2457] urukul/ad9910 test: remove unused import MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/test/coredevice/test_ad9910.py | 2 -- artiq/test/coredevice/test_urukul.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/artiq/test/coredevice/test_ad9910.py b/artiq/test/coredevice/test_ad9910.py index 52d1c5be4..407755df6 100644 --- a/artiq/test/coredevice/test_ad9910.py +++ b/artiq/test/coredevice/test_ad9910.py @@ -1,5 +1,3 @@ -import unittest - from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase from artiq.coredevice.ad9910 import _AD9910_REG_FTW diff --git a/artiq/test/coredevice/test_urukul.py b/artiq/test/coredevice/test_urukul.py index 34b2fd128..2141303c4 100644 --- a/artiq/test/coredevice/test_urukul.py +++ b/artiq/test/coredevice/test_urukul.py @@ -1,5 +1,3 @@ -import unittest - from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase from artiq.coredevice import urukul From 832690af9a49a485fb47bff366b15c9a13bafa27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 5 Nov 2018 19:44:51 +0100 Subject: [PATCH 1341/2457] ad9910: flake8 [nfc] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 47 +++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 3977190a2..9bdfd37fb 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -2,7 +2,7 @@ from numpy import int32, int64 from artiq.language.core import ( kernel, delay, portable, delay_mu, now_mu, at_mu) -from artiq.language.units import us, ns, ms +from artiq.language.units import us, ms from artiq.coredevice import spi2 as spi from artiq.coredevice import urukul @@ -72,11 +72,12 @@ class AD9910: set this to the delay tap number returned. """ kernel_invariants = {"chip_select", "cpld", "core", "bus", - "ftw_per_hz", "pll_n", "io_update_delay", "sysclk_per_mu"} + "ftw_per_hz", "pll_n", "io_update_delay", + "sysclk_per_mu"} def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, - pll_n=40, pll_cp=7, pll_vco=5, sync_delay_seed=-1, - io_update_delay=0): + pll_n=40, pll_cp=7, pll_vco=5, sync_delay_seed=-1, + io_update_delay=0): self.cpld = dmgr.get(cpld_device) self.core = self.cpld.core self.bus = self.cpld.bus @@ -95,7 +96,7 @@ class AD9910: assert self.sysclk_per_mu == sysclk*self.core.ref_period assert 0 <= pll_vco <= 5 vco_min, vco_max = [(370, 510), (420, 590), (500, 700), - (600, 880), (700, 950), (820, 1150)][pll_vco] + (600, 880), (700, 950), (820, 1150)][pll_vco] assert vco_min <= sysclk/1e6 <= vco_max self.pll_vco = pll_vco assert 0 <= pll_cp <= 7 @@ -106,7 +107,9 @@ class AD9910: @kernel def set_phase_mode(self, phase_mode): - """Sets the default phase mode for future calls to :meth:`set` and + """Set the default phase mode. + + for future calls to :meth:`set` and :meth:`set_mu`. Supported phase modes are: * :const:`PHASE_MODE_CONTINUOUS`: the phase accumulator is unchanged @@ -155,10 +158,10 @@ class AD9910: :param data: Data to be written """ self.bus.set_config_mu(urukul.SPI_CONFIG, 8, - urukul.SPIT_DDS_WR, self.chip_select) + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write(addr << 24) self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32, - urukul.SPIT_DDS_WR, self.chip_select) + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write(data) @kernel @@ -168,11 +171,11 @@ class AD9910: :param addr: Register address """ self.bus.set_config_mu(urukul.SPI_CONFIG, 8, - urukul.SPIT_DDS_WR, self.chip_select) + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write((addr | 0x80) << 24) - self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END - | spi.SPI_INPUT, 32, - urukul.SPIT_DDS_RD, self.chip_select) + self.bus.set_config_mu( + urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, + 32, urukul.SPIT_DDS_RD, self.chip_select) self.bus.write(0) return self.bus.read() @@ -185,13 +188,13 @@ class AD9910: :param data_low: Low (LSB) 32 data bits """ self.bus.set_config_mu(urukul.SPI_CONFIG, 8, - urukul.SPIT_DDS_WR, self.chip_select) + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write(addr << 24) self.bus.set_config_mu(urukul.SPI_CONFIG, 32, - urukul.SPIT_DDS_WR, self.chip_select) + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write(data_high) self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32, - urukul.SPIT_DDS_WR, self.chip_select) + urukul.SPIT_DDS_WR, self.chip_select) self.bus.write(data_low) @kernel @@ -305,25 +308,25 @@ class AD9910: @portable(flags={"fast-math"}) def frequency_to_ftw(self, frequency): - """Returns the frequency tuning word corresponding to the given + """Return the frequency tuning word corresponding to the given frequency. """ return int32(round(self.ftw_per_hz*frequency)) @portable(flags={"fast-math"}) def turns_to_pow(self, turns): - """Returns the phase offset word corresponding to the given phase + """Return the phase offset word corresponding to the given phase in turns.""" return int32(round(turns*0x10000)) @portable(flags={"fast-math"}) def amplitude_to_asf(self, amplitude): - """Returns amplitude scale factor corresponding to given amplitude.""" + """Return amplitude scale factor corresponding to given amplitude.""" return int32(round(amplitude*0x3ffe)) @portable(flags={"fast-math"}) def pow_to_turns(self, pow): - """Returns the phase in turns corresponding to a given phase offset + """Return the phase in turns corresponding to a given phase offset word.""" return pow/0x10000 @@ -397,7 +400,8 @@ class AD9910: @kernel def clear_smp_err(self): - """Clears the SMP_ERR flag and enables SMP_ERR validity monitoring. + """Clear the SMP_ERR flag and enables SMP_ERR validity monitoring. + Violations of the SYNC_IN sample and hold margins will result in SMP_ERR being asserted. This then also activates the red LED on the respective Urukul channel. @@ -513,7 +517,8 @@ class AD9910: d0 = self.io_update_delay t0 = int32(self.measure_io_update_alignment(d0)) for i in range(max_delay - 1): - t = self.measure_io_update_alignment((d0 + i + 1) & (max_delay - 1)) + t = self.measure_io_update_alignment( + (d0 + i + 1) & (max_delay - 1)) if t != t0: return (d0 + i + period//2) & (period - 1) raise ValueError("no IO_UPDATE-SYNC_CLK alignment edge found") From 6fb18270a210671dfaa369c5bb1f23ee1bd8d2ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 5 Nov 2018 19:45:24 +0100 Subject: [PATCH 1342/2457] urukul: flake8 [nfc] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/urukul.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 803b44b00..9f96a92ed 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -1,4 +1,4 @@ -from artiq.language.core import kernel, delay, portable +from artiq.language.core import kernel, delay, portable, at_mu, now_mu from artiq.language.units import us, ms from numpy import int32 From fb12df7e01ed1d084e8de9c804006c96c486442b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 6 Nov 2018 14:33:21 +0800 Subject: [PATCH 1343/2457] Revert "kasli_tester: urukul0 mmcx clock defunct" This reverts commit 68220c316dfad954471c263d567d24b142625117. --- artiq/examples/kasli_tester/device_db.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/examples/kasli_tester/device_db.py b/artiq/examples/kasli_tester/device_db.py index 027fbe2e9..f7d661bd6 100644 --- a/artiq/examples/kasli_tester/device_db.py +++ b/artiq/examples/kasli_tester/device_db.py @@ -346,6 +346,5 @@ device_db.update( # Urukul CPLD with sync and io_update, IFC MODE 0b1000 urukul_cpld="urukul0_cpld", # Urukul AD9910 with switch TTL, internal 125 MHz MMCX connection - # FIXME: MMCX not connected - # urukul_ad9910="urukul0_ch0", + urukul_ad9910="urukul0_ch0", ) From 9a3d81ffeea542f04ab7e2616b4b437a82e063b0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 6 Nov 2018 14:49:21 +0800 Subject: [PATCH 1344/2457] kasli: fix tester clk_sel --- artiq/examples/kasli_tester/device_db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/kasli_tester/device_db.py b/artiq/examples/kasli_tester/device_db.py index f7d661bd6..dcfc297c3 100644 --- a/artiq/examples/kasli_tester/device_db.py +++ b/artiq/examples/kasli_tester/device_db.py @@ -102,7 +102,7 @@ device_db.update( "io_update_device": "ttl_urukul0_io_update", "sync_device": "ttl_urukul0_sync", "refclk": 125e6, - "clk_sel": 0 + "clk_sel": 2 } } ) From 73b7124091ac8341cea41fcb36f63c36c6e98676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 6 Nov 2018 17:03:37 +0800 Subject: [PATCH 1345/2457] test_ad9910: print sync scan for debugging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/test/coredevice/test_ad9910.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_ad9910.py b/artiq/test/coredevice/test_ad9910.py index 407755df6..d2d0bc793 100644 --- a/artiq/test/coredevice/test_ad9910.py +++ b/artiq/test/coredevice/test_ad9910.py @@ -76,8 +76,12 @@ class AD9910Exp(EnvExperiment): self.core.break_realtime() self.dev.cpld.init() self.dev.init() - dly, win = self.dev.tune_sync_delay(self.dev.sync_delay_seed) err = [0] * 32 + for i in range(6): + self.sync_scan(err, win=i) + print(err) + self.core.break_realtime() + dly, win = self.dev.tune_sync_delay(self.dev.sync_delay_seed) self.sync_scan(err, win=win + 1) # tighten window by 2*75ps self.set_dataset("dly", dly) self.set_dataset("win", win) From e17e458c583e0ec1fdf8807d11614f88416bf3de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 6 Nov 2018 10:06:22 +0000 Subject: [PATCH 1346/2457] ptb2: add sync to urukul0 for ad9910 usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/examples/kasli_basic/device_db_ptb2.py | 36 ++++++++++++-------- artiq/gateware/targets/kasli.py | 3 +- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/artiq/examples/kasli_basic/device_db_ptb2.py b/artiq/examples/kasli_basic/device_db_ptb2.py index ed6d4722f..78b4d28e1 100644 --- a/artiq/examples/kasli_basic/device_db_ptb2.py +++ b/artiq/examples/kasli_basic/device_db_ptb2.py @@ -87,36 +87,42 @@ device_db.update({ "class": "SPIMaster", "arguments": {"channel": 27} }, - "ttl_urukul0_io_update": { + "ttl_urukul0_sync": { "type": "local", "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 28} + "class": "TTLClockGen", + "arguments": {"channel": 28, "acc_width": 4} }, - "ttl_urukul0_sw0": { + "ttl_urukul0_io_update": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 29} }, - "ttl_urukul0_sw1": { + "ttl_urukul0_sw0": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 30} }, - "ttl_urukul0_sw2": { + "ttl_urukul0_sw1": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 31} }, - "ttl_urukul0_sw3": { + "ttl_urukul0_sw2": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 32} }, + "ttl_urukul0_sw3": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 33} + }, "urukul0_cpld": { "type": "local", "module": "artiq.coredevice.urukul", @@ -150,19 +156,19 @@ device_db.update({ "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 33} + "arguments": {"channel": 34} }, "ttl_urukul1_sync": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLClockGen", - "arguments": {"channel": 34, "acc_width": 4} + "arguments": {"channel": 35, "acc_width": 4} }, "ttl_urukul1_io_update": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 35} + "arguments": {"channel": 36} }, "urukul1_cpld": { "type": "local", @@ -197,13 +203,13 @@ device_db.update({ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 36} + "arguments": {"channel": 37} }, "led1": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 37} + "arguments": {"channel": 38} } }) @@ -213,19 +219,19 @@ device_db.update({ "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 38} + "arguments": {"channel": 39} }, "ttl_zotino0_ldac": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 39} + "arguments": {"channel": 40} }, "ttl_zotino0_clr": { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 40} + "arguments": {"channel": 41} }, "zotino0": { "type": "local", diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 0475fd9a6..bf1586a92 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -597,7 +597,8 @@ class PTB2(_StandaloneBase): eem.DIO.add_std(self, 2, ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) eem.Sampler.add_std(self, 3, None, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 5, 4, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 5, 4, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) eem.Urukul.add_std(self, 6, None, ttl_serdes_7series.Output_8X, ttl_simple.ClockGen) From b6e4961b0f4dc9f5cb7d347e852dad2d1a2461f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 6 Nov 2018 11:43:19 +0000 Subject: [PATCH 1347/2457] kasli: lower RTIO clock jitter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * high bandwidth since the si5324 is good * no low power ibufgds * drop bufg between ibufgds and pll * increase pll vco frequency to 1.5 GHz Signed-off-by: Robert Jördens --- artiq/gateware/targets/kasli.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index bf1586a92..4d6af5736 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -34,13 +34,11 @@ class _RTIOCRG(Module, AutoCSR): clk_synth = platform.request("si5324_clkout_fabric") clk_synth_se = Signal() - clk_synth_buffered = Signal() platform.add_period_constraint(clk_synth.p, 8.0) self.specials += [ Instance("IBUFGDS", - p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE", + p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="FALSE", i_I=clk_synth.p, i_IB=clk_synth.n, o_O=clk_synth_se), - Instance("BUFG", i_I=clk_synth_se, o_O=clk_synth_buffered), ] pll_locked = Signal() @@ -50,21 +48,21 @@ class _RTIOCRG(Module, AutoCSR): self.specials += [ Instance("PLLE2_ADV", p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, - - p_REF_JITTER1=0.01, + p_BANDWIDTH="HIGH", + p_REF_JITTER1=0.001, p_CLKIN1_PERIOD=8.0, p_CLKIN2_PERIOD=8.0, - i_CLKIN2=clk_synth_buffered, + i_CLKIN2=clk_synth_se, # Warning: CLKINSEL=0 means CLKIN2 is selected i_CLKINSEL=0, - # VCO @ 1GHz when using 125MHz input - p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, + # VCO @ 1.5GHz when using 125MHz input + p_CLKFBOUT_MULT=12, p_DIVCLK_DIVIDE=1, i_CLKFBIN=self.cd_rtio.clk, i_RST=self._pll_reset.storage, o_CLKFBOUT=rtio_clk, - p_CLKOUT0_DIVIDE=2, p_CLKOUT0_PHASE=0.0, + p_CLKOUT0_DIVIDE=3, p_CLKOUT0_PHASE=0.0, o_CLKOUT0=rtiox4_clk), Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk), Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), From ba4bf6e59bc090f9c5d321fb09a4277317b79c22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 6 Nov 2018 11:58:55 +0000 Subject: [PATCH 1348/2457] kasli: don't pass rtio pll feedback through bufg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UG472: "The MMCM performance increases because the feedback clock is not subjected to noise on the core supply since it never passes through a block powered by this supply." Signed-off-by: Robert Jördens --- artiq/gateware/targets/kasli.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 4d6af5736..e232e2296 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -44,7 +44,7 @@ class _RTIOCRG(Module, AutoCSR): pll_locked = Signal() rtio_clk = Signal() rtiox4_clk = Signal() - ext_clkout_clk = Signal() + fb_clk = Signal() self.specials += [ Instance("PLLE2_ADV", p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, @@ -57,13 +57,16 @@ class _RTIOCRG(Module, AutoCSR): # VCO @ 1.5GHz when using 125MHz input p_CLKFBOUT_MULT=12, p_DIVCLK_DIVIDE=1, - i_CLKFBIN=self.cd_rtio.clk, + i_CLKFBIN=fb_clk, i_RST=self._pll_reset.storage, - o_CLKFBOUT=rtio_clk, + o_CLKFBOUT=fb_clk, p_CLKOUT0_DIVIDE=3, p_CLKOUT0_PHASE=0.0, - o_CLKOUT0=rtiox4_clk), + o_CLKOUT0=rtiox4_clk, + + p_CLKOUT1_DIVIDE=12, p_CLKOUT1_PHASE=0.0, + o_CLKOUT1=rtio_clk), Instance("BUFG", i_I=rtio_clk, o_O=self.cd_rtio.clk), Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), From 0b2661a34d0d31b05f89a4e74e6968fdade8ec94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 6 Nov 2018 12:40:15 +0000 Subject: [PATCH 1349/2457] ad9910: robustify SYNC window finding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit don't integrate too long, find the window tip fast and early a couple 100 SYNC pulses are sufficient Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 2 +- artiq/test/coredevice/test_ad9910.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 9bdfd37fb..d988ee9e9 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -446,7 +446,7 @@ class AD9910: self.set_sync(in_delay, window) self.clear_smp_err() # integrate SMP_ERR statistics for a few hundred cycles - delay(10*us) + # delay(10*us) err = urukul_sta_smp_err(self.cpld.sta_read()) err = (err >> (self.chip_select - 4)) & 1 delay(40*us) # slack diff --git a/artiq/test/coredevice/test_ad9910.py b/artiq/test/coredevice/test_ad9910.py index d2d0bc793..d60972878 100644 --- a/artiq/test/coredevice/test_ad9910.py +++ b/artiq/test/coredevice/test_ad9910.py @@ -92,7 +92,7 @@ class AD9910Exp(EnvExperiment): for in_delay in range(len(err)): self.dev.set_sync(in_delay=in_delay, window=win) self.dev.clear_smp_err() - delay(10*us) # integrate SMP_ERR statistics + # delay(10*us) # integrate SMP_ERR statistics e = urukul_sta_smp_err(self.dev.cpld.sta_read()) err[in_delay] = (e >> (self.dev.chip_select - 4)) & 1 delay(50*us) # slack From 172633c7dae6026594258e60129d382f7f4bd18f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 6 Nov 2018 17:35:57 +0100 Subject: [PATCH 1350/2457] test_ad9910: default to a useful seed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 8 +++----- artiq/test/coredevice/test_ad9910.py | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index d988ee9e9..5fa75a82b 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -414,7 +414,7 @@ class AD9910: self.cpld.io_update.pulse(1*us) @kernel - def tune_sync_delay(self, sync_delay_seed): + def tune_sync_delay(self, sync_delay_seed=8): """Find a stable SYNC_IN delay. This method first locates the smallest SYNC_IN validity window at @@ -439,10 +439,8 @@ class AD9910: if in_delay & 1: in_delay = -in_delay in_delay = sync_delay_seed + (in_delay >> 1) - if in_delay < 0: - in_delay = 0 - elif in_delay > 31: - in_delay = 31 + if in_delay < 0 or in_delay > 31: + continue self.set_sync(in_delay, window) self.clear_smp_err() # integrate SMP_ERR statistics for a few hundred cycles diff --git a/artiq/test/coredevice/test_ad9910.py b/artiq/test/coredevice/test_ad9910.py index d60972878..1243760cc 100644 --- a/artiq/test/coredevice/test_ad9910.py +++ b/artiq/test/coredevice/test_ad9910.py @@ -81,7 +81,7 @@ class AD9910Exp(EnvExperiment): self.sync_scan(err, win=i) print(err) self.core.break_realtime() - dly, win = self.dev.tune_sync_delay(self.dev.sync_delay_seed) + dly, win = self.dev.tune_sync_delay() self.sync_scan(err, win=win + 1) # tighten window by 2*75ps self.set_dataset("dly", dly) self.set_dataset("win", win) From 6c00ab57c06856653006c1db3cca12019793dc67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 6 Nov 2018 17:37:48 +0100 Subject: [PATCH 1351/2457] test_ad9910: relax SYNC window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 5fa75a82b..740d7a36f 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -414,7 +414,7 @@ class AD9910: self.cpld.io_update.pulse(1*us) @kernel - def tune_sync_delay(self, sync_delay_seed=8): + def tune_sync_delay(self, sync_delay_seed=9): """Find a stable SYNC_IN delay. This method first locates the smallest SYNC_IN validity window at @@ -430,8 +430,8 @@ class AD9910: """ dt = 14 # 1/(f_SYSCLK*75ps) taps per SYSCLK period max_delay = dt # 14*75ps > 1ns - max_window = dt//4 + 1 # 2*75ps*4 = 600ps high > 1ns/2 - min_window = max(0, max_window - 2) # 2*75ps hold, 2*75ps setup + max_window = dt//4 + 1 # 75ps*4 = 300ps setup and hold + min_window = 1 # 1*75ps setup and hold for window in range(max_window - min_window + 1): window = max_window - window for in_delay in range(max_delay): @@ -446,9 +446,8 @@ class AD9910: # integrate SMP_ERR statistics for a few hundred cycles # delay(10*us) err = urukul_sta_smp_err(self.cpld.sta_read()) - err = (err >> (self.chip_select - 4)) & 1 delay(40*us) # slack - if not err: + if not (err >> (self.chip_select - 4)) & 1: window -= min_window # add margin self.set_sync(in_delay, window) self.clear_smp_err() From efd735a6ab3d2c4b1493fd2e032559d2c1bd525d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Nov 2018 22:01:03 +0800 Subject: [PATCH 1352/2457] Revert "drtio: monitor RTIOClockMultiplier PLL (#1155)" This reverts commit 469a66db61da4c40d72b8627053821df169a8dbe. --- artiq/firmware/runtime/rtio_mgt.rs | 5 +---- artiq/firmware/satman/main.rs | 18 ------------------ artiq/gateware/targets/kasli.py | 18 +++++------------- 3 files changed, 6 insertions(+), 35 deletions(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index a54e8c77a..f2a606d86 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -257,10 +257,6 @@ fn async_error_thread(io: Io) { } pub fn startup(io: &Io) { - // The RTIO CRG may depend on the DRTIO transceiver clock. - // Initialize DRTIO first to bring up transceiver clocking. - drtio::startup(io); - #[cfg(has_rtio_crg)] { #[cfg(has_rtio_clock_switch)] @@ -300,6 +296,7 @@ pub fn startup(io: &Io) { } } + drtio::startup(io); init_core(true); io.spawn(4096, async_error_thread); } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index a734e8355..ad2252955 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -229,23 +229,6 @@ fn process_errors() { } } - -#[cfg(has_rtio_crg)] -fn init_rtio_crg() { - unsafe { - csr::rtio_crg::pll_reset_write(0); - } - clock::spin_us(150); - let locked = unsafe { csr::rtio_crg::pll_locked_read() != 0 }; - if !locked { - error!("RTIO clock failed"); - } -} - -#[cfg(not(has_rtio_crg))] -fn init_rtio_crg() { } - - #[cfg(rtio_frequency = "150.0")] const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings { @@ -302,7 +285,6 @@ pub extern fn main() -> i32 { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } - init_rtio_crg(); #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 0475fd9a6..49e6f5670 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -766,23 +766,19 @@ class Tester(_StandaloneBase): self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) -class _RTIOClockMultiplier(Module, AutoCSR): +class _RTIOClockMultiplier(Module): def __init__(self, rtio_clk_freq): - self.pll_reset = CSRStorage(reset=1) - self.pll_locked = CSRStatus() self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) # See "Global Clock Network Deskew Using Two BUFGs" in ug472. clkfbout = Signal() clkfbin = Signal() rtiox4_clk = Signal() - pll_locked = Signal() self.specials += [ Instance("MMCME2_BASE", p_CLKIN1_PERIOD=1e9/rtio_clk_freq, i_CLKIN1=ClockSignal("rtio"), - i_RST=self.pll_reset.storage, - o_LOCKED=pll_locked, + i_RST=ResetSignal("rtio"), p_CLKFBOUT_MULT_F=8.0, p_DIVCLK_DIVIDE=1, @@ -791,9 +787,7 @@ class _RTIOClockMultiplier(Module, AutoCSR): p_CLKOUT0_DIVIDE_F=2.0, o_CLKOUT0=rtiox4_clk, ), Instance("BUFG", i_I=clkfbout, o_O=clkfbin), - Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), - - MultiReg(pll_locked, self.pll_locked.status) + Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk) ] @@ -877,8 +871,7 @@ class _MasterBase(MiniSoC, AMPSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.rxoutclk) - self.submodules.rtio_crg = _RTIOClockMultiplier(rtio_clk_freq) - self.csr_devices.append("rtio_crg") + self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) fix_serdes_timing_path(platform) def add_rtio(self, rtio_channels): @@ -1003,8 +996,7 @@ class _SatelliteBase(BaseSoC): self.crg.cd_sys.clk, gtp.txoutclk, gtp.rxoutclk) - self.submodules.rtio_crg = _RTIOClockMultiplier(rtio_clk_freq) - self.csr_devices.append("rtio_crg") + self.submodules.rtio_clkmul = _RTIOClockMultiplier(rtio_clk_freq) fix_serdes_timing_path(platform) def add_rtio(self, rtio_channels): From e6efe830c486b078d72ba0317741f8ca7069a4e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 7 Nov 2018 14:52:03 +0000 Subject: [PATCH 1353/2457] ad9910: rewire sync delay tuning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * search from wide window end * decouple margins and minimum window size * add note about kasli jitter Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 58 ++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 740d7a36f..d0538f5be 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -414,45 +414,55 @@ class AD9910: self.cpld.io_update.pulse(1*us) @kernel - def tune_sync_delay(self, sync_delay_seed=9): + def tune_sync_delay(self, search_seed=15): """Find a stable SYNC_IN delay. - This method first locates the smallest SYNC_IN validity window at - minimum window size and then increases the window a bit to provide some - slack and stability. + This method first locates a valid SYNC_IN delay at zero validation + window size (setup/hold margin) by scanning around `search_seed`. It + then looks for similar valid delays at successively larger validation + window sizes until none can be found. It then deacreses the validation + window a bit to provide some slack and stability and returns the + optimal values. - It starts scanning delays around `sync_delay_seed` (see the - device database arguments and :class:`AD9910`) at maximum validation - window size and decreases the window size until a valid delay is found. - - :param sync_delay_seed: Start value for valid SYNC_IN delay search. + :param search_seed: Start value for valid SYNC_IN delay search. + Defaults to 15 (half range). :return: Tuple of optimal delay and window size. """ - dt = 14 # 1/(f_SYSCLK*75ps) taps per SYSCLK period - max_delay = dt # 14*75ps > 1ns - max_window = dt//4 + 1 # 75ps*4 = 300ps setup and hold - min_window = 1 # 1*75ps setup and hold - for window in range(max_window - min_window + 1): - window = max_window - window - for in_delay in range(max_delay): - # alternate search direction around seed_delay + search_span = 31 + # FIXME https://github.com/sinara-hw/Urukul/issues/16 + # should both be 2-4 once kasli sync_in jitter is identified + min_window = 0 + margin = 1 # 1*75ps setup and hold + for window in range(16): + next_seed = -1 + for in_delay in range(search_span - 2*window): + # alternate search direction around search_seed if in_delay & 1: in_delay = -in_delay - in_delay = sync_delay_seed + (in_delay >> 1) + in_delay = search_seed + (in_delay >> 1) if in_delay < 0 or in_delay > 31: continue self.set_sync(in_delay, window) self.clear_smp_err() # integrate SMP_ERR statistics for a few hundred cycles - # delay(10*us) + delay(100*us) err = urukul_sta_smp_err(self.cpld.sta_read()) delay(40*us) # slack if not (err >> (self.chip_select - 4)) & 1: - window -= min_window # add margin - self.set_sync(in_delay, window) - self.clear_smp_err() - delay(40*us) # slack - return in_delay, window + next_seed = in_delay + break + if next_seed >= 0: # valid delay found, scan next window + search_seed = next_seed + continue + elif window > min_window: + # no valid delay found here, roll back and add margin + window = max(min_window, window - 1 - margin) + self.set_sync(search_seed, window) + self.clear_smp_err() + delay(100*us) # slack + return search_seed, window + else: + break raise ValueError("no valid window/delay") @kernel From 3d0c3cc1cf84a1b6688afa4b41ba0c7789717915 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Nov 2018 23:39:55 +0800 Subject: [PATCH 1354/2457] gateware,runtime: optimize RTIO output interface * reduce address to 8 bits * merge core, channel and address into 32-bit pre-computable "target" * merge we register into data register --- artiq/coredevice/rtio.py | 5 ++--- artiq/firmware/ksupport/lib.rs | 21 ++++++++++----------- artiq/firmware/ksupport/rtio.rs | 25 ++++++++++--------------- artiq/gateware/rtio/cri.py | 12 +++++------- artiq/gateware/rtio/dma.py | 2 +- 5 files changed, 28 insertions(+), 37 deletions(-) diff --git a/artiq/coredevice/rtio.py b/artiq/coredevice/rtio.py index 471a48c31..3445b6baf 100644 --- a/artiq/coredevice/rtio.py +++ b/artiq/coredevice/rtio.py @@ -3,13 +3,12 @@ from artiq.language.types import TInt64, TInt32, TNone, TList @syscall(flags={"nowrite"}) -def rtio_output(time_mu: TInt64, channel: TInt32, addr: TInt32, data: TInt32 - ) -> TNone: +def rtio_output(time_mu: TInt64, target: TInt32, data: TInt32) -> TNone: raise NotImplementedError("syscall not simulated") @syscall(flags={"nowrite"}) -def rtio_output_wide(time_mu: TInt64, channel: TInt32, addr: TInt32, +def rtio_output_wide(time_mu: TInt64, target: TInt32, data: TList(TInt32)) -> TNone: raise NotImplementedError("syscall not simulated") diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 35ac00eb4..946f6fe94 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -301,10 +301,10 @@ extern fn dma_record_stop(duration: i64) { #[unwind(aborts)] #[inline(always)] -unsafe fn dma_record_output_prepare(timestamp: i64, channel: i32, address: i32, +unsafe fn dma_record_output_prepare(timestamp: i64, target: i32, words: usize) -> &'static mut [u8] { // See gateware/rtio/dma.py. - const HEADER_LENGTH: usize = /*length*/1 + /*channel*/3 + /*timestamp*/8 + /*address*/2; + const HEADER_LENGTH: usize = /*length*/1 + /*channel*/3 + /*timestamp*/8 + /*address*/1; let length = HEADER_LENGTH + /*data*/words * 4; if DMA_RECORDER.buffer.len() - DMA_RECORDER.data_len < length { @@ -319,9 +319,9 @@ unsafe fn dma_record_output_prepare(timestamp: i64, channel: i32, address: i32, header.copy_from_slice(&[ (length >> 0) as u8, - (channel >> 0) as u8, - (channel >> 8) as u8, - (channel >> 16) as u8, + (target >> 8) as u8, + (target >> 16) as u8, + (target >> 24) as u8, (timestamp >> 0) as u8, (timestamp >> 8) as u8, (timestamp >> 16) as u8, @@ -330,17 +330,16 @@ unsafe fn dma_record_output_prepare(timestamp: i64, channel: i32, address: i32, (timestamp >> 40) as u8, (timestamp >> 48) as u8, (timestamp >> 56) as u8, - (address >> 0) as u8, - (address >> 8) as u8, + (target >> 0) as u8, ]); data } #[unwind(aborts)] -extern fn dma_record_output(timestamp: i64, channel: i32, address: i32, word: i32) { +extern fn dma_record_output(timestamp: i64, target: i32, word: i32) { unsafe { - let data = dma_record_output_prepare(timestamp, channel, address, 1); + let data = dma_record_output_prepare(timestamp, target, 1); data.copy_from_slice(&[ (word >> 0) as u8, (word >> 8) as u8, @@ -351,11 +350,11 @@ extern fn dma_record_output(timestamp: i64, channel: i32, address: i32, word: i3 } #[unwind(aborts)] -extern fn dma_record_output_wide(timestamp: i64, channel: i32, address: i32, words: CSlice) { +extern fn dma_record_output_wide(timestamp: i64, target: i32, words: CSlice) { assert!(words.len() <= 16); // enforce the hardware limit unsafe { - let mut data = dma_record_output_prepare(timestamp, channel, address, 1); + let mut data = dma_record_output_prepare(timestamp, target, 1); for word in words.as_ref().iter() { data[..4].copy_from_slice(&[ (word >> 0) as u8, diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index 1324c0353..04cfd0fce 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -36,6 +36,7 @@ mod imp { } } + // writing the LSB of o_data (offset=0) triggers the RTIO write #[inline(always)] pub unsafe fn rtio_o_data_write(offset: usize, data: u32) { write_volatile( @@ -66,41 +67,37 @@ mod imp { } } - pub extern fn output(timestamp: i64, channel: i32, addr: i32, data: i32) { + pub extern fn output(timestamp: i64, target: i32, data: i32) { unsafe { - csr::rtio::chan_sel_write(channel as _); + csr::rtio::target_write(target as u32); // writing timestamp clears o_data csr::rtio::timestamp_write(timestamp as u64); - csr::rtio::o_address_write(addr as _); rtio_o_data_write(0, data as _); - csr::rtio::o_we_write(1); let status = csr::rtio::o_status_read(); if status != 0 { - process_exceptional_status(timestamp, channel, status); + process_exceptional_status(timestamp, target >> 8, status); } } } - pub extern fn output_wide(timestamp: i64, channel: i32, addr: i32, data: CSlice) { + pub extern fn output_wide(timestamp: i64, target: i32, data: CSlice) { unsafe { - csr::rtio::chan_sel_write(channel as _); + csr::rtio::target_write(target as u32); // writing timestamp clears o_data csr::rtio::timestamp_write(timestamp as u64); - csr::rtio::o_address_write(addr as _); for i in 0..data.len() { rtio_o_data_write(i, data[i] as _) } - csr::rtio::o_we_write(1); let status = csr::rtio::o_status_read(); if status != 0 { - process_exceptional_status(timestamp, channel, status); + process_exceptional_status(timestamp, target >> 8, status); } } } pub extern fn input_timestamp(timeout: i64, channel: i32) -> u64 { unsafe { - csr::rtio::chan_sel_write(channel as _); + csr::rtio::target_write((channel as u32) << 8); csr::rtio::timestamp_write(timeout as u64); csr::rtio::i_request_write(1); @@ -130,7 +127,7 @@ mod imp { pub extern fn input_data(channel: i32) -> i32 { unsafe { - csr::rtio::chan_sel_write(channel as _); + csr::rtio::target_write((channel as u32) << 8); csr::rtio::timestamp_write(0xffffffff_ffffffff); csr::rtio::i_request_write(1); @@ -158,7 +155,7 @@ mod imp { #[cfg(has_rtio_log)] pub fn log(timestamp: i64, data: &[u8]) { unsafe { - csr::rtio::chan_sel_write(csr::CONFIG_RTIO_LOG_CHANNEL); + csr::rtio::target_write(csr::CONFIG_RTIO_LOG_CHANNEL << 8); csr::rtio::timestamp_write(timestamp as u64); let mut word: u32 = 0; @@ -167,14 +164,12 @@ mod imp { word |= data[i] as u32; if i % 4 == 3 { rtio_o_data_write(0, word); - csr::rtio::o_we_write(1); word = 0; } } if word != 0 { rtio_o_data_write(0, word); - csr::rtio::o_we_write(1); } } } diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index adafa8d29..bd1e336b3 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -32,7 +32,7 @@ layout = [ ("timestamp", 64, DIR_M_TO_S), ("o_data", 512, DIR_M_TO_S), - ("o_address", 16, DIR_M_TO_S), + ("o_address", 8, DIR_M_TO_S), # o_status bits: # <0:wait> <1:underflow> <2:destination unreachable> ("o_status", 3, DIR_S_TO_M), @@ -60,7 +60,7 @@ class Interface(Record): class KernelInitiator(Module, AutoCSR): def __init__(self, tsc, cri=None): - self.chan_sel = CSRStorage(24) + self.target = CSRStorage(32) # monotonic, may lag behind the counter in the IO clock domain, but # not be ahead of it. self.timestamp = CSRStorage(64) @@ -69,8 +69,6 @@ class KernelInitiator(Module, AutoCSR): # zero-extension of output event data by the gateware. When staging an # output event, always write timestamp before o_data. self.o_data = CSRStorage(512, write_from_dev=True) - self.o_address = CSRStorage(16) - self.o_we = CSR() self.o_status = CSRStatus(3) self.i_data = CSRStatus(32) @@ -90,14 +88,14 @@ class KernelInitiator(Module, AutoCSR): self.comb += [ self.cri.cmd.eq(commands["nop"]), - If(self.o_we.re, self.cri.cmd.eq(commands["write"])), + If(self.o_data.re, self.cri.cmd.eq(commands["write"])), If(self.i_request.re, self.cri.cmd.eq(commands["read"])), - self.cri.chan_sel.eq(self.chan_sel.storage), + self.cri.chan_sel.eq(self.target.storage[8:]), self.cri.timestamp.eq(self.timestamp.storage), self.cri.o_data.eq(self.o_data.storage), - self.cri.o_address.eq(self.o_address.storage), + self.cri.o_address.eq(self.target.storage[:8]), self.o_status.status.eq(self.cri.o_status), self.i_data.status.eq(self.cri.i_data), diff --git a/artiq/gateware/rtio/dma.py b/artiq/gateware/rtio/dma.py index 735d52f54..a538bb978 100644 --- a/artiq/gateware/rtio/dma.py +++ b/artiq/gateware/rtio/dma.py @@ -148,7 +148,7 @@ record_layout = [ ("length", 8), # of whole record (header+data) ("channel", 24), ("timestamp", 64), - ("address", 16), + ("address", 8), ("data", 512) # variable length ] From fae95e73ada0e541383429fe4ef67ee114715951 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Nov 2018 23:41:43 +0800 Subject: [PATCH 1355/2457] ttl: use optimized rtio_output API --- artiq/coredevice/ttl.py | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index f7bf48bb9..9bd50d682 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -29,11 +29,12 @@ class TTLOut: :param channel: channel number """ - kernel_invariants = {"core", "channel"} + kernel_invariants = {"core", "channel", "target_o"} def __init__(self, dmgr, channel, core_device="core"): self.core = dmgr.get(core_device) self.channel = channel + self.target_o = channel << 8 @kernel def output(self): @@ -41,7 +42,7 @@ class TTLOut: @kernel def set_o(self, o): - rtio_output(now_mu(), self.channel, 0, 1 if o else 0) + rtio_output(now_mu(), self.target_o, 1 if o else 0) @kernel def on(self): @@ -106,15 +107,20 @@ class TTLInOut: :param channel: channel number """ - kernel_invariants = {"core", "channel"} + kernel_invariants = {"core", "channel", + "target_o", "target_oe", "target_sens", "target_sample"} def __init__(self, dmgr, channel, core_device="core"): self.core = dmgr.get(core_device) self.channel = channel + self.target_o = (channel << 8) + 0 + self.target_oe = (channel << 8) + 1 + self.target_sens = (channel << 8) + 2 + self.target_sample = (channel << 8) + 3 @kernel def set_oe(self, oe): - rtio_output(now_mu(), self.channel, 1, 1 if oe else 0) + rtio_output(now_mu(), self.target_oe, 1 if oe else 0) @kernel def output(self): @@ -136,7 +142,7 @@ class TTLInOut: @kernel def set_o(self, o): - rtio_output(now_mu(), self.channel, 0, 1 if o else 0) + rtio_output(now_mu(), self.target_o, 1 if o else 0) @kernel def on(self): @@ -181,7 +187,7 @@ class TTLInOut: # Input API: gating @kernel def _set_sensitivity(self, value): - rtio_output(now_mu(), self.channel, 2, value) + rtio_output(now_mu(), self.target_sens, value) @kernel def gate_rising_mu(self, duration): @@ -355,7 +361,7 @@ class TTLInOut: position of the time cursor. The time cursor is not modified by this function.""" - rtio_output(now_mu(), self.channel, 3, 0) + rtio_output(now_mu(), self.target_sample, 0) @kernel def sample_get(self): @@ -392,13 +398,13 @@ class TTLInOut: The time cursor is not modified by this function. """ - rtio_output(now_mu(), self.channel, 3, 2) # gate falling + rtio_output(now_mu(), self.target_sample, 2) # gate falling return rtio_input_data(self.channel) == 1 @kernel def watch_stay_off(self): """Like :meth:`watch_stay_on`, but for low levels.""" - rtio_output(now_mu(), self.channel, 3, 1) # gate rising + rtio_output(now_mu(), self.target_sample, 1) # gate rising return rtio_input_data(self.channel) == 0 @kernel @@ -411,7 +417,7 @@ class TTLInOut: The time cursor is not modified by this function. This function always makes the slack negative. """ - rtio_output(now_mu(), self.channel, 2, 0) + rtio_output(now_mu(), self.target_sens, 0) success = True try: while rtio_input_timestamp(now_mu(), self.channel) != -1: @@ -432,11 +438,12 @@ class TTLClockGen: :param channel: channel number :param acc_width: accumulator width in bits """ - kernel_invariants = {"core", "channel", "acc_width"} + kernel_invariants = {"core", "channel", "target", "acc_width"} def __init__(self, dmgr, channel, acc_width=24, core_device="core"): self.core = dmgr.get(core_device) self.channel = channel + self.target = channel << 8 self.acc_width = numpy.int64(acc_width) @@ -472,7 +479,7 @@ class TTLClockGen: Due to the way the clock generator operates, frequency tuning words that are not powers of two cause jitter of one RTIO clock cycle at the output.""" - rtio_output(now_mu(), self.channel, 0, frequency) + rtio_output(now_mu(), self.target, frequency) @kernel def set(self, frequency): From aadf5112b7e97d234cbdb5bb8de967cf79aef510 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Nov 2018 00:02:44 +0800 Subject: [PATCH 1356/2457] rtio: remove incorrect comment --- artiq/gateware/rtio/cri.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index bd1e336b3..f3b968d60 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -61,8 +61,6 @@ class Interface(Record): class KernelInitiator(Module, AutoCSR): def __init__(self, tsc, cri=None): self.target = CSRStorage(32) - # monotonic, may lag behind the counter in the IO clock domain, but - # not be ahead of it. self.timestamp = CSRStorage(64) # Writing timestamp clears o_data. This implements automatic From fcb611d1d2ccb7b69feb1a4eb9d1e46dc564601a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 7 Nov 2018 18:18:35 +0100 Subject: [PATCH 1357/2457] test_ad9910: don't expect large SYNC_IN delay margins MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sinara-hw/Urukul#16 Signed-off-by: Robert Jördens --- artiq/test/coredevice/test_ad9910.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_ad9910.py b/artiq/test/coredevice/test_ad9910.py index 1243760cc..4ce47fdee 100644 --- a/artiq/test/coredevice/test_ad9910.py +++ b/artiq/test/coredevice/test_ad9910.py @@ -82,7 +82,9 @@ class AD9910Exp(EnvExperiment): print(err) self.core.break_realtime() dly, win = self.dev.tune_sync_delay() - self.sync_scan(err, win=win + 1) # tighten window by 2*75ps + self.sync_scan(err, win=win) + # FIXME: win + 1 # tighten window by 2*75ps + # after https://github.com/sinara-hw/Urukul/issues/16 self.set_dataset("dly", dly) self.set_dataset("win", win) self.set_dataset("err", err) From 8caea0e6d3a91e625f84172e455229920dca930f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Nov 2018 18:29:24 +0800 Subject: [PATCH 1358/2457] gateware,runtime: optimize RTIO kernel interface further * now pinning (TODO: atomicity) * for inputs, merge request and timeout registers --- .../compiler/transforms/artiq_ir_generator.py | 3 +- .../compiler/transforms/llvm_ir_generator.py | 4 +-- artiq/coredevice/rtio.py | 5 ++- artiq/coredevice/ttl.py | 18 +++++----- artiq/firmware/ksupport/api.rs | 4 ++- artiq/firmware/ksupport/glue.c | 8 ++--- artiq/firmware/ksupport/lib.rs | 9 ++--- artiq/firmware/ksupport/rtio.rs | 28 +++++++-------- artiq/firmware/libproto_artiq/kernel_proto.rs | 4 --- artiq/firmware/runtime/session.rs | 10 ------ artiq/gateware/drtio/rt_controller_master.py | 8 +++-- artiq/gateware/drtio/rt_errors_satellite.py | 2 +- artiq/gateware/drtio/rt_packet_repeater.py | 6 +++- artiq/gateware/drtio/rt_packet_satellite.py | 11 +++--- artiq/gateware/rtio/analyzer.py | 2 +- artiq/gateware/rtio/cri.py | 34 ++++++++++++++----- artiq/gateware/rtio/dma.py | 2 +- artiq/gateware/rtio/input_collector.py | 4 +-- artiq/gateware/rtio/sed/lane_distributor.py | 6 ++-- artiq/gateware/test/drtio/test_full_stack.py | 11 +++--- .../test/drtio/test_rt_packet_repeater.py | 4 +-- artiq/gateware/test/drtio/test_switching.py | 4 +-- artiq/gateware/test/rtio/test_dma.py | 6 ++-- .../test/rtio/test_input_collector.py | 2 +- .../test/rtio/test_sed_lane_distributor.py | 2 +- artiq/gateware/test/rtio/test_sed_top.py | 2 +- 26 files changed, 99 insertions(+), 100 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 07967dcbb..25dd1d14a 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1946,8 +1946,7 @@ class ARTIQIRGenerator(algorithm.Visitor): def printf(format_string, *args): format = ir.Constant(format_string, builtins.TStr()) if as_rtio: - now_mu = self.append(ir.Builtin("now_mu", [], builtins.TInt64())) - self.append(ir.Builtin("rtio_log", [now_mu, format, *args], builtins.TNone())) + self.append(ir.Builtin("rtio_log", [format, *args], builtins.TNone())) else: self.append(ir.Builtin("printf", [format, *args], builtins.TNone())) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index b27d2c868..2ea7c9e5d 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -336,7 +336,7 @@ class LLVMIRGenerator: elif name == self.target.print_function: llty = ll.FunctionType(llvoid, [llptr], var_arg=True) elif name == "rtio_log": - llty = ll.FunctionType(llvoid, [lli64, llptr], var_arg=True) + llty = ll.FunctionType(llvoid, [llptr], var_arg=True) elif name == "__artiq_personality": llty = ll.FunctionType(lli32, [], var_arg=True) elif name == "__artiq_raise": @@ -1137,7 +1137,7 @@ class LLVMIRGenerator: lloperands = [] for i, operand in enumerate(insn.operands): lloperand = self.map(operand) - if i == 0 and insn.op == "printf" or i == 1 and insn.op == "rtio_log": + if i == 0 and (insn.op == "printf" or insn.op == "rtio_log"): lloperands.append(self.llbuilder.extract_value(lloperand, 0)) elif builtins.is_str(operand.type) or builtins.is_bytes(operand.type): lloperands.append(self.llbuilder.extract_value(lloperand, 1)) diff --git a/artiq/coredevice/rtio.py b/artiq/coredevice/rtio.py index 3445b6baf..bde9d5064 100644 --- a/artiq/coredevice/rtio.py +++ b/artiq/coredevice/rtio.py @@ -3,13 +3,12 @@ from artiq.language.types import TInt64, TInt32, TNone, TList @syscall(flags={"nowrite"}) -def rtio_output(time_mu: TInt64, target: TInt32, data: TInt32) -> TNone: +def rtio_output(target: TInt32, data: TInt32) -> TNone: raise NotImplementedError("syscall not simulated") @syscall(flags={"nowrite"}) -def rtio_output_wide(time_mu: TInt64, target: TInt32, - data: TList(TInt32)) -> TNone: +def rtio_output_wide(target: TInt32, data: TList(TInt32)) -> TNone: raise NotImplementedError("syscall not simulated") diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 9bd50d682..59002f12d 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -42,7 +42,7 @@ class TTLOut: @kernel def set_o(self, o): - rtio_output(now_mu(), self.target_o, 1 if o else 0) + rtio_output(self.target_o, 1 if o else 0) @kernel def on(self): @@ -120,7 +120,7 @@ class TTLInOut: @kernel def set_oe(self, oe): - rtio_output(now_mu(), self.target_oe, 1 if oe else 0) + rtio_output(self.target_oe, 1 if oe else 0) @kernel def output(self): @@ -142,7 +142,7 @@ class TTLInOut: @kernel def set_o(self, o): - rtio_output(now_mu(), self.target_o, 1 if o else 0) + rtio_output(self.target_o, 1 if o else 0) @kernel def on(self): @@ -187,7 +187,7 @@ class TTLInOut: # Input API: gating @kernel def _set_sensitivity(self, value): - rtio_output(now_mu(), self.target_sens, value) + rtio_output(self.target_sens, value) @kernel def gate_rising_mu(self, duration): @@ -361,7 +361,7 @@ class TTLInOut: position of the time cursor. The time cursor is not modified by this function.""" - rtio_output(now_mu(), self.target_sample, 0) + rtio_output(self.target_sample, 0) @kernel def sample_get(self): @@ -398,13 +398,13 @@ class TTLInOut: The time cursor is not modified by this function. """ - rtio_output(now_mu(), self.target_sample, 2) # gate falling + rtio_output(self.target_sample, 2) # gate falling return rtio_input_data(self.channel) == 1 @kernel def watch_stay_off(self): """Like :meth:`watch_stay_on`, but for low levels.""" - rtio_output(now_mu(), self.target_sample, 1) # gate rising + rtio_output(self.target_sample, 1) # gate rising return rtio_input_data(self.channel) == 0 @kernel @@ -417,7 +417,7 @@ class TTLInOut: The time cursor is not modified by this function. This function always makes the slack negative. """ - rtio_output(now_mu(), self.target_sens, 0) + rtio_output(self.target_sens, 0) success = True try: while rtio_input_timestamp(now_mu(), self.channel) != -1: @@ -479,7 +479,7 @@ class TTLClockGen: Due to the way the clock generator operates, frequency tuning words that are not powers of two cause jitter of one RTIO clock cycle at the output.""" - rtio_output(now_mu(), self.target, frequency) + rtio_output(self.target, frequency) @kernel def set(self, frequency): diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index be616256f..ffd0d38b8 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -1,3 +1,5 @@ +use board_misoc::csr; + macro_rules! api { ($i:ident) => ({ extern { static $i: u8; } @@ -78,7 +80,7 @@ static mut API: &'static [(&'static str, *const ())] = &[ /* proxified syscalls */ api!(core_log), - api!(now = &::NOW as *const _), + api!(now = csr::rtio::NOW_HI_ADDR as *const _), api!(watchdog_set = ::watchdog_set), api!(watchdog_clear = ::watchdog_clear), diff --git a/artiq/firmware/ksupport/glue.c b/artiq/firmware/ksupport/glue.c index 3828a6aea..c1155b732 100644 --- a/artiq/firmware/ksupport/glue.c +++ b/artiq/firmware/ksupport/glue.c @@ -12,7 +12,7 @@ struct slice { }; void send_to_core_log(struct slice str); -void send_to_rtio_log(long long int timestamp, struct slice data); +void send_to_rtio_log(struct slice data); #define KERNELCPU_EXEC_ADDRESS 0x40800000 #define KERNELCPU_PAYLOAD_ADDRESS 0x40840000 @@ -139,8 +139,8 @@ int core_log(const char *fmt, ...) } /* called by kernel */ -void rtio_log(long long int timestamp, const char *fmt, ...); -void rtio_log(long long int timestamp, const char *fmt, ...) +void rtio_log(const char *fmt, ...); +void rtio_log(const char *fmt, ...) { va_list args; @@ -154,5 +154,5 @@ void rtio_log(long long int timestamp, const char *fmt, ...) va_end(args); struct slice str = { buf, size }; - send_to_rtio_log(timestamp, str); + send_to_rtio_log(str); } diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 946f6fe94..348c189dc 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -99,7 +99,6 @@ mod api; mod rtio; mod nrt_bus; -static mut NOW: u64 = 0; static mut LIBRARY: Option> = None; #[no_mangle] @@ -114,8 +113,8 @@ pub extern fn send_to_core_log(text: CSlice) { } #[no_mangle] -pub extern fn send_to_rtio_log(timestamp: i64, text: CSlice) { - rtio::log(timestamp, text.as_ref()) +pub extern fn send_to_rtio_log(text: CSlice) { + rtio::log(text.as_ref()) } #[unwind(aborts)] @@ -184,7 +183,6 @@ fn terminate(exception: &eh_artiq::Exception, backtrace: &mut [usize]) -> ! { } let backtrace = &mut backtrace.as_mut()[0..cursor]; - send(&NowSave(unsafe { NOW })); send(&RunException { exception: kernel_proto::Exception { name: str::from_utf8(exception.name.as_ref()).unwrap(), @@ -508,10 +506,7 @@ pub unsafe fn main() { ptr::write_bytes(__bss_start as *mut u8, 0, (_end - __bss_start) as usize); - send(&NowInitRequest); - recv!(&NowInitReply(now) => NOW = now); (mem::transmute::(__modinit__))(); - send(&NowSave(NOW)); if let Some(typeinfo) = typeinfo { attribute_writeback(typeinfo as *const ()); diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index 04cfd0fce..338dbcbdc 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -51,7 +51,8 @@ mod imp { } #[inline(never)] - unsafe fn process_exceptional_status(timestamp: i64, channel: i32, status: u8) { + unsafe fn process_exceptional_status(channel: i32, status: u8) { + let timestamp = *(csr::rtio::NOW_HI_ADDR as *const i64); if status & RTIO_O_STATUS_WAIT != 0 { while csr::rtio::o_status_read() & RTIO_O_STATUS_WAIT != 0 {} } @@ -67,30 +68,28 @@ mod imp { } } - pub extern fn output(timestamp: i64, target: i32, data: i32) { + pub extern fn output(target: i32, data: i32) { unsafe { csr::rtio::target_write(target as u32); - // writing timestamp clears o_data - csr::rtio::timestamp_write(timestamp as u64); + // writing target clears o_data rtio_o_data_write(0, data as _); let status = csr::rtio::o_status_read(); if status != 0 { - process_exceptional_status(timestamp, target >> 8, status); + process_exceptional_status(target >> 8, status); } } } - pub extern fn output_wide(timestamp: i64, target: i32, data: CSlice) { + pub extern fn output_wide(target: i32, data: CSlice) { unsafe { csr::rtio::target_write(target as u32); - // writing timestamp clears o_data - csr::rtio::timestamp_write(timestamp as u64); + // writing target clears o_data for i in 0..data.len() { rtio_o_data_write(i, data[i] as _) } let status = csr::rtio::o_status_read(); if status != 0 { - process_exceptional_status(timestamp, target >> 8, status); + process_exceptional_status(target >> 8, status); } } } @@ -98,8 +97,7 @@ mod imp { pub extern fn input_timestamp(timeout: i64, channel: i32) -> u64 { unsafe { csr::rtio::target_write((channel as u32) << 8); - csr::rtio::timestamp_write(timeout as u64); - csr::rtio::i_request_write(1); + csr::rtio::i_timeout_write(timeout as u64); let mut status = RTIO_I_STATUS_WAIT_STATUS; while status & RTIO_I_STATUS_WAIT_STATUS != 0 { @@ -128,8 +126,7 @@ mod imp { pub extern fn input_data(channel: i32) -> i32 { unsafe { csr::rtio::target_write((channel as u32) << 8); - csr::rtio::timestamp_write(0xffffffff_ffffffff); - csr::rtio::i_request_write(1); + csr::rtio::i_timeout_write(0xffffffff_ffffffff); let mut status = RTIO_I_STATUS_WAIT_STATUS; while status & RTIO_I_STATUS_WAIT_STATUS != 0 { @@ -153,10 +150,9 @@ mod imp { } #[cfg(has_rtio_log)] - pub fn log(timestamp: i64, data: &[u8]) { + pub fn log(data: &[u8]) { unsafe { csr::rtio::target_write(csr::CONFIG_RTIO_LOG_CHANNEL << 8); - csr::rtio::timestamp_write(timestamp as u64); let mut word: u32 = 0; for i in 0..data.len() { @@ -175,7 +171,7 @@ mod imp { } #[cfg(not(has_rtio_log))] - pub fn log(_timestamp: i64, _data: &[u8]) { + pub fn log(_data: &[u8]) { unimplemented!("not(has_rtio_log)") } } diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index 73c9e2765..cefc27ee5 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -22,10 +22,6 @@ pub enum Message<'a> { LoadRequest(&'a [u8]), LoadReply(Result<(), dyld::Error<'a>>), - NowInitRequest, - NowInitReply(u64), - NowSave(u64), - RtioInitRequest, RtioDestinationStatusRequest { destination: u8 }, diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index ae23c3410..3ab46cad9 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -63,7 +63,6 @@ macro_rules! unexpected { // Persistent state #[derive(Debug)] struct Congress { - now: u64, cache: Cache, dma_manager: DmaManager, finished_cleanly: Cell @@ -72,7 +71,6 @@ struct Congress { impl Congress { fn new() -> Congress { Congress { - now: 0, cache: Cache::new(), dma_manager: DmaManager::new(), finished_cleanly: Cell::new(true) @@ -365,14 +363,6 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, kern_acknowledge() } - &kern::NowInitRequest => - kern_send(io, &kern::NowInitReply(session.congress.now)), - - &kern::NowSave(now) => { - session.congress.now = now; - kern_acknowledge() - } - &kern::DmaRecordStart(name) => { session.congress.dma_manager.record_start(name); kern_acknowledge() diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index 0126184c6..fdd340be8 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -73,7 +73,11 @@ class RTController(Module): rt_packet.sr_chan_sel.eq(chan_sel), rt_packet.sr_address.eq(self.cri.o_address), rt_packet.sr_data.eq(self.cri.o_data), - rt_packet.sr_timestamp.eq(self.cri.timestamp), + If(rt_packet_read_request, + rt_packet.sr_timestamp.eq(self.cri.i_timeout) + ).Else( + rt_packet.sr_timestamp.eq(self.cri.o_timestamp) + ), If(rt_packet_buffer_request, rt_packet.sr_notwrite.eq(1), rt_packet.sr_address.eq(0) @@ -103,7 +107,7 @@ class RTController(Module): self.submodules += timeout_counter cond_underflow = Signal() - self.comb += cond_underflow.eq((self.cri.timestamp[tsc.glbl_fine_ts_width:] + self.comb += cond_underflow.eq((self.cri.o_timestamp[tsc.glbl_fine_ts_width:] - self.csrs.underflow_margin.storage[tsc.glbl_fine_ts_width:]) < tsc.coarse_ts_sys) # buffer space diff --git a/artiq/gateware/drtio/rt_errors_satellite.py b/artiq/gateware/drtio/rt_errors_satellite.py index 1d857654c..90250969f 100644 --- a/artiq/gateware/drtio/rt_errors_satellite.py +++ b/artiq/gateware/drtio/rt_errors_satellite.py @@ -61,7 +61,7 @@ class RTErrorsSatellite(Module, AutoCSR): underflow.eq(cri.o_status[1]), overflow.eq(cri.o_status[0]), underflow_error_cri.eq(Cat(cri.chan_sel[:16], - cri.timestamp, + cri.o_timestamp, tsc.full_ts_cri)), Cat(self.underflow_channel.status, self.underflow_timestamp_event.status, diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 4788283f9..9b55fe2ab 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -68,7 +68,11 @@ class RTPacketRepeater(Module): If(~self.reset & ~cb0_loaded & (self.cri.cmd != cri.commands["nop"]), cb0_loaded.eq(1), cb0_cmd.eq(self.cri.cmd), - cb0_timestamp.eq(self.cri.timestamp), + If(self.cri.cmd == cri.commands["read"], + cb0_timestamp.eq(self.cri.i_timeout) + ).Else( + cb0_timestamp.eq(self.cri.o_timestamp) + ), cb0_chan_sel.eq(self.cri.chan_sel), cb0_o_address.eq(self.cri.o_address), cb0_o_data.eq(self.cri.o_data) diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 557640749..79a48f493 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -94,13 +94,10 @@ class RTPacketSatellite(Module): self.cri.chan_sel.eq( rx_dp.packet_as["write"].chan_sel), ), - If(cri_read | read_request_pending, - self.cri.timestamp.eq( - rx_dp.packet_as["read_request"].timeout) - ).Else( - self.cri.timestamp.eq( - rx_dp.packet_as["write"].timestamp) - ), + self.cri.i_timeout.eq( + rx_dp.packet_as["read_request"].timeout), + self.cri.o_timestamp.eq( + rx_dp.packet_as["write"].timestamp), self.cri.o_address.eq( rx_dp.packet_as["write"].address), self.cri.o_data.eq( diff --git a/artiq/gateware/rtio/analyzer.py b/artiq/gateware/rtio/analyzer.py index 144c62701..342da2acf 100644 --- a/artiq/gateware/rtio/analyzer.py +++ b/artiq/gateware/rtio/analyzer.py @@ -70,7 +70,7 @@ class MessageEncoder(Module, AutoCSR): input_output.rtio_counter.eq(tsc.full_ts_cri), If(cri.cmd == cri_commands["write"], input_output.message_type.eq(MessageType.output.value), - input_output.timestamp.eq(cri.timestamp), + input_output.timestamp.eq(cri.o_timestamp), input_output.data.eq(cri.o_data) ).Else( input_output.message_type.eq(MessageType.input.value), diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index f3b968d60..c03c2edc1 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -29,8 +29,8 @@ layout = [ # 8 MSBs of chan_sel = routing destination # 16 LSBs of chan_sel = channel within the destination ("chan_sel", 24, DIR_M_TO_S), - ("timestamp", 64, DIR_M_TO_S), + ("o_timestamp", 64, DIR_M_TO_S), ("o_data", 512, DIR_M_TO_S), ("o_address", 8, DIR_M_TO_S), # o_status bits: @@ -43,6 +43,7 @@ layout = [ ("o_buffer_space_valid", 1, DIR_S_TO_M), ("o_buffer_space", 16, DIR_S_TO_M), + ("i_timeout", 64, DIR_M_TO_S), ("i_data", 32, DIR_S_TO_M), ("i_timestamp", 64, DIR_S_TO_M), # i_status bits: @@ -61,17 +62,19 @@ class Interface(Record): class KernelInitiator(Module, AutoCSR): def __init__(self, tsc, cri=None): self.target = CSRStorage(32) - self.timestamp = CSRStorage(64) + # not using CSRStorage atomic_write feature here to make storage reset_less + self.now_hi = CSR(32) + self.now_lo = CSR(32) - # Writing timestamp clears o_data. This implements automatic + # Writing target clears o_data. This implements automatic # zero-extension of output event data by the gateware. When staging an - # output event, always write timestamp before o_data. + # output event, always write target before o_data. self.o_data = CSRStorage(512, write_from_dev=True) self.o_status = CSRStatus(3) + self.i_timeout = CSRStorage(64) self.i_data = CSRStatus(32) self.i_timestamp = CSRStatus(64) - self.i_request = CSR() self.i_status = CSRStatus(4) self.i_overflow_reset = CSR() @@ -84,24 +87,39 @@ class KernelInitiator(Module, AutoCSR): # # # + now_lo_backing = Signal(32) + now = Signal(64, reset_less=True) + self.sync += [ + # TODO: fix compiler and make atomic + #If(self.now_lo.re, now_lo_backing.eq(self.now_lo.r)), + #If(self.now_hi.re, now.eq(Cat(now_lo_backing, self.now_hi.r))) + If(self.now_lo.re, now[:32].eq(self.now_lo.r)), + If(self.now_hi.re, now[32:].eq(self.now_hi.r)) + ] + self.comb += [ + self.now_lo.w.eq(now[:32]), + self.now_hi.w.eq(now[32:]) + ] + self.comb += [ self.cri.cmd.eq(commands["nop"]), If(self.o_data.re, self.cri.cmd.eq(commands["write"])), - If(self.i_request.re, self.cri.cmd.eq(commands["read"])), + If(self.i_timeout.re, self.cri.cmd.eq(commands["read"])), self.cri.chan_sel.eq(self.target.storage[8:]), - self.cri.timestamp.eq(self.timestamp.storage), + self.cri.o_timestamp.eq(now), self.cri.o_data.eq(self.o_data.storage), self.cri.o_address.eq(self.target.storage[:8]), self.o_status.status.eq(self.cri.o_status), + self.cri.i_timeout.eq(self.i_timeout.storage), self.i_data.status.eq(self.cri.i_data), self.i_timestamp.status.eq(self.cri.i_timestamp), self.i_status.status.eq(self.cri.i_status), self.o_data.dat_w.eq(0), - self.o_data.we.eq(self.timestamp.re), + self.o_data.we.eq(self.target.re), ] self.sync += If(self.counter_update.re, self.counter.status.eq(tsc.full_ts_cri)) diff --git a/artiq/gateware/rtio/dma.py b/artiq/gateware/rtio/dma.py index a538bb978..03f479e03 100644 --- a/artiq/gateware/rtio/dma.py +++ b/artiq/gateware/rtio/dma.py @@ -274,7 +274,7 @@ class CRIMaster(Module, AutoCSR): self.comb += [ self.cri.chan_sel.eq(self.sink.channel), - self.cri.timestamp.eq(self.sink.timestamp), + self.cri.o_timestamp.eq(self.sink.timestamp), self.cri.o_address.eq(self.sink.address), self.cri.o_data.eq(self.sink.data) ] diff --git a/artiq/gateware/rtio/input_collector.py b/artiq/gateware/rtio/input_collector.py index ce9bcbc20..922a99ca4 100644 --- a/artiq/gateware/rtio/input_collector.py +++ b/artiq/gateware/rtio/input_collector.py @@ -118,7 +118,7 @@ class InputCollector(Module): i_status_raw = Signal(2) self.comb += i_status_raw.eq(Array(i_statuses)[sel]) - input_timeout = Signal.like(self.cri.timestamp, reset_less=True) + input_timeout = Signal.like(self.cri.i_timeout, reset_less=True) input_pending = Signal() self.cri.i_data.reset_less = True self.cri.i_timestamp.reset_less = True @@ -134,7 +134,7 @@ class InputCollector(Module): input_pending.eq(0) ), If(self.cri.cmd == cri.commands["read"], - input_timeout.eq(self.cri.timestamp), + input_timeout.eq(self.cri.i_timeout), input_pending.eq(1), self.cri.i_status.eq(0b100) ) diff --git a/artiq/gateware/rtio/sed/lane_distributor.py b/artiq/gateware/rtio/sed/lane_distributor.py index 4f8b7e146..08a3fa716 100644 --- a/artiq/gateware/rtio/sed/lane_distributor.py +++ b/artiq/gateware/rtio/sed/lane_distributor.py @@ -60,7 +60,7 @@ class LaneDistributor(Module): self.comb += [ lio.seqn.eq(seqn), lio.payload.channel.eq(self.cri.chan_sel[:16]), - lio.payload.timestamp.eq(self.cri.timestamp), + lio.payload.timestamp.eq(self.cri.o_timestamp), ] if hasattr(lio.payload, "address"): self.comb += lio.payload.address.eq(self.cri.o_address) @@ -69,7 +69,7 @@ class LaneDistributor(Module): # when timestamp and channel arrive in cycle #1, prepare computations coarse_timestamp = Signal(us_timestamp_width) - self.comb += coarse_timestamp.eq(self.cri.timestamp[glbl_fine_ts_width:]) + self.comb += coarse_timestamp.eq(self.cri.o_timestamp[glbl_fine_ts_width:]) min_minus_timestamp = Signal((us_timestamp_width + 1, True), reset_less=True) laneAmin_minus_timestamp = Signal.like(min_minus_timestamp) @@ -141,7 +141,7 @@ class LaneDistributor(Module): Array(lio.we for lio in self.output)[use_lanen].eq(do_write) ] compensated_timestamp = Signal(64) - self.comb += compensated_timestamp.eq(self.cri.timestamp + (compensation << glbl_fine_ts_width)) + self.comb += compensated_timestamp.eq(self.cri.o_timestamp + (compensation << glbl_fine_ts_width)) self.sync += [ If(do_write, current_lane.eq(use_lanen), diff --git a/artiq/gateware/test/drtio/test_full_stack.py b/artiq/gateware/test/drtio/test_full_stack.py index e9bc6160a..02535b7e6 100644 --- a/artiq/gateware/test/drtio/test_full_stack.py +++ b/artiq/gateware/test/drtio/test_full_stack.py @@ -112,10 +112,10 @@ class OutputsTestbench: def write(self, channel, data): kcsrs = self.dut.master_ki - yield from kcsrs.chan_sel.write(channel) - yield from kcsrs.timestamp.write(self.now) + yield from kcsrs.target.write(channel << 8) + yield from kcsrs.now_hi.write(self.now >> 32) + yield from kcsrs.now_lo.write(self.now & 0xffffffff) yield from kcsrs.o_data.write(data) - yield from kcsrs.o_we.write(1) yield status = 1 wlen = 0 @@ -249,9 +249,8 @@ class TestFullStack(unittest.TestCase): kcsrs = dut.master_ki def get_input(timeout): - yield from kcsrs.chan_sel.write(2) - yield from kcsrs.timestamp.write(10) - yield from kcsrs.i_request.write(1) + yield from kcsrs.target.write(2 << 8) + yield from kcsrs.i_timeout.write(10) yield status = yield from kcsrs.i_status.read() while status & 0x4: diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index 0bf80eb3d..9c73af625 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -65,7 +65,7 @@ class TestRepeater(unittest.TestCase): yield for channel, timestamp, address, data in test_writes: yield dut.cri.chan_sel.eq(channel) - yield dut.cri.timestamp.eq(timestamp) + yield dut.cri.o_timestamp.eq(timestamp) yield dut.cri.o_address.eq(address) yield dut.cri.o_data.eq(data) yield dut.cri.cmd.eq(cri.commands["write"]) @@ -135,7 +135,7 @@ class TestRepeater(unittest.TestCase): def read(chan_sel, timeout): yield dut.cri.chan_sel.eq(chan_sel) - yield dut.cri.timestamp.eq(timeout) + yield dut.cri.i_timeout.eq(timeout) yield dut.cri.cmd.eq(cri.commands["read"]) yield yield dut.cri.cmd.eq(cri.commands["nop"]) diff --git a/artiq/gateware/test/drtio/test_switching.py b/artiq/gateware/test/drtio/test_switching.py index eb691fcf7..dddfb9bd2 100644 --- a/artiq/gateware/test/drtio/test_switching.py +++ b/artiq/gateware/test/drtio/test_switching.py @@ -90,7 +90,7 @@ class Testbench: def write(self, channel, data): mcri = self.dut.master.cri yield mcri.chan_sel.eq(channel) - yield mcri.timestamp.eq(self.now) + yield mcri.o_timestamp.eq(self.now) yield mcri.o_data.eq(data) yield yield mcri.cmd.eq(cri.commands["write"]) @@ -109,7 +109,7 @@ class Testbench: def read(self, channel, timeout): mcri = self.dut.master.cri yield mcri.chan_sel.eq(channel) - yield mcri.timestamp.eq(timeout) + yield mcri.i_timeout.eq(timeout) yield yield mcri.cmd.eq(cri.commands["read"]) yield diff --git a/artiq/gateware/test/rtio/test_dma.py b/artiq/gateware/test/rtio/test_dma.py index 1ff14c8d4..84bc4a3ff 100644 --- a/artiq/gateware/test/rtio/test_dma.py +++ b/artiq/gateware/test/rtio/test_dma.py @@ -26,7 +26,7 @@ def encode_record(channel, timestamp, address, data): r = [] r += encode_n(channel, 3, 3) r += encode_n(timestamp, 8, 8) - r += encode_n(address, 2, 2) + r += encode_n(address, 1, 1) r += encode_n(data, 1, 64) return encode_n(len(r)+1, 1, 1) + r @@ -66,7 +66,7 @@ def do_dma(dut, address): test_writes1 = [ (0x01, 0x23, 0x12, 0x33), - (0x901, 0x902, 0x911, 0xeeeeeeeeeeeeeefffffffffffffffffffffffffffffff28888177772736646717738388488), + (0x901, 0x902, 0x11, 0xeeeeeeeeeeeeeefffffffffffffffffffffffffffffff28888177772736646717738388488), (0x81, 0x288, 0x88, 0x8888) ] @@ -150,7 +150,7 @@ class TestDMA(unittest.TestCase): pass elif cmd == cri.commands["write"]: channel = yield dut_cri.chan_sel - timestamp = yield dut_cri.timestamp + timestamp = yield dut_cri.o_timestamp address = yield dut_cri.o_address data = yield dut_cri.o_data received.append((channel, timestamp, address, data)) diff --git a/artiq/gateware/test/rtio/test_input_collector.py b/artiq/gateware/test/rtio/test_input_collector.py index 0c682b28c..bf68a17e4 100644 --- a/artiq/gateware/test/rtio/test_input_collector.py +++ b/artiq/gateware/test/rtio/test_input_collector.py @@ -54,7 +54,7 @@ def simulate(wait_cycles, ts_timeouts): yield for ts_timeout in ts_timeouts: - yield dut.cri.timestamp.eq(ts_timeout) + yield dut.cri.i_timeout.eq(ts_timeout) yield dut.cri.cmd.eq(cri.commands["read"]) yield yield dut.cri.cmd.eq(cri.commands["nop"]) diff --git a/artiq/gateware/test/rtio/test_sed_lane_distributor.py b/artiq/gateware/test/rtio/test_sed_lane_distributor.py index 609877643..6c9135c86 100644 --- a/artiq/gateware/test/rtio/test_sed_lane_distributor.py +++ b/artiq/gateware/test/rtio/test_sed_lane_distributor.py @@ -21,7 +21,7 @@ def simulate(input_events, compensation=None, wait=True): def gen(): for channel, timestamp in input_events: yield dut.cri.chan_sel.eq(channel) - yield dut.cri.timestamp.eq(timestamp) + yield dut.cri.o_timestamp.eq(timestamp) yield yield dut.cri.cmd.eq(cri.commands["write"]) diff --git a/artiq/gateware/test/rtio/test_sed_top.py b/artiq/gateware/test/rtio/test_sed_top.py index fb97caac6..5efc257a0 100644 --- a/artiq/gateware/test/rtio/test_sed_top.py +++ b/artiq/gateware/test/rtio/test_sed_top.py @@ -38,7 +38,7 @@ def simulate(input_events, **kwargs): def gen(): yield dut.sed.cri.chan_sel.eq(0) for timestamp, data in input_events: - yield dut.sed.cri.timestamp.eq(timestamp) + yield dut.sed.cri.o_timestamp.eq(timestamp) yield dut.sed.cri.o_data.eq(data) yield From f74dda639f0d2cdf533c0d73935444b839a18193 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Nov 2018 18:36:20 +0800 Subject: [PATCH 1359/2457] drtio: 8-bit address --- artiq/gateware/drtio/rt_packet_master.py | 8 ++++---- artiq/gateware/drtio/rt_packet_repeater.py | 4 ++-- artiq/gateware/drtio/rt_serializer.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index f91ac7667..2d7b14631 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -27,7 +27,7 @@ class RTPacketMaster(Module): self.sr_notwrite = Signal() self.sr_timestamp = Signal(64) self.sr_chan_sel = Signal(24) - self.sr_address = Signal(16) + self.sr_address = Signal(8) self.sr_data = Signal(512) # buffer space reply interface @@ -85,12 +85,12 @@ class RTPacketMaster(Module): # Write FIFO and extra data count sr_fifo = ClockDomainsRenamer({"write": "sys", "read": "rtio"})( - AsyncFIFO(1+64+24+16+512, sr_fifo_depth)) + AsyncFIFO(1+64+24+8+512, sr_fifo_depth)) self.submodules += sr_fifo sr_notwrite_d = Signal() sr_timestamp_d = Signal(64) sr_chan_sel_d = Signal(24) - sr_address_d = Signal(16) + sr_address_d = Signal(8) sr_data_d = Signal(512) self.comb += [ sr_fifo.we.eq(self.sr_stb), @@ -115,7 +115,7 @@ class RTPacketMaster(Module): sr_notwrite = Signal() sr_timestamp = Signal(64) sr_chan_sel = Signal(24) - sr_address = Signal(16) + sr_address = Signal(8) sr_extra_data_cnt = Signal(8) sr_data = Signal(512) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 9b55fe2ab..9374d1a18 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -58,7 +58,7 @@ class RTPacketRepeater(Module): cb0_cmd = Signal(2) cb0_timestamp = Signal(64) cb0_chan_sel = Signal(24) - cb0_o_address = Signal(16) + cb0_o_address = Signal(8) cb0_o_data = Signal(512) self.sync.rtio += [ If(self.reset | cb0_ack, @@ -89,7 +89,7 @@ class RTPacketRepeater(Module): cb_cmd = Signal(2) cb_timestamp = Signal(64) cb_chan_sel = Signal(24) - cb_o_address = Signal(16) + cb_o_address = Signal(8) cb_o_data = Signal(512) self.sync.rtio += [ If(self.reset | cb_ack, diff --git a/artiq/gateware/drtio/rt_serializer.py b/artiq/gateware/drtio/rt_serializer.py index 4b62dbfb6..01e5cf19e 100644 --- a/artiq/gateware/drtio/rt_serializer.py +++ b/artiq/gateware/drtio/rt_serializer.py @@ -50,7 +50,7 @@ def get_m2s_layouts(alignment): plm.add_type("write", ("timestamp", 64), ("chan_sel", 24), - ("address", 16), + ("address", 8), ("extra_data_cnt", 8), ("short_data", short_data_len)) plm.add_type("buffer_space_request", ("destination", 8)) From 9740032a9410a282ab34a7f0dd3c00cb9fa16250 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 4 Nov 2018 18:13:25 +0000 Subject: [PATCH 1360/2457] firmware: Fix dma_record_output_wide --- artiq/firmware/ksupport/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index d4a6615d2..8d481f7b5 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -355,7 +355,7 @@ extern fn dma_record_output_wide(timestamp: i64, channel: i32, address: i32, wor assert!(words.len() <= 16); // enforce the hardware limit unsafe { - let mut data = dma_record_output_prepare(timestamp, channel, address, 1); + let mut data = dma_record_output_prepare(timestamp, channel, address, words.len()); for word in words.as_ref().iter() { data[..4].copy_from_slice(&[ (word >> 0) as u8, From 2549e623c1cb2dd1791c4361230fb1e263e19265 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Nov 2018 19:15:44 +0800 Subject: [PATCH 1361/2457] ad9914: use new rtio_output() API --- artiq/coredevice/ad9914.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index bd2ec4db0..aceb79f17 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -84,7 +84,7 @@ class AD9914: @kernel def write(self, addr, data): - rtio_output(now_mu(), self.bus_channel, addr, data) + rtio_output((self.bus_channel << 8) | addr, data) delay_mu(self.write_duration_mu) @kernel From d18546550e8c4d803602fecbdd5cac9e657f3a0a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Nov 2018 19:15:50 +0800 Subject: [PATCH 1362/2457] grabber: use new rtio_output() API --- artiq/coredevice/grabber.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/grabber.py b/artiq/coredevice/grabber.py index 6406578ea..7a00549db 100644 --- a/artiq/coredevice/grabber.py +++ b/artiq/coredevice/grabber.py @@ -40,13 +40,13 @@ class Grabber: Advances the timeline by 4 coarse RTIO cycles. """ c = int64(self.core.ref_multiplier) - rtio_output(now_mu(), self.channel_base, 4*n+0, x0) + rtio_output((self.channel_base << 8) | (4*n+0), x0) delay_mu(c) - rtio_output(now_mu(), self.channel_base, 4*n+1, y0) + rtio_output((self.channel_base << 8) | (4*n+1), y0) delay_mu(c) - rtio_output(now_mu(), self.channel_base, 4*n+2, x1) + rtio_output((self.channel_base << 8) | (4*n+2), x1) delay_mu(c) - rtio_output(now_mu(), self.channel_base, 4*n+3, y1) + rtio_output((self.channel_base << 8) | (4*n+3), y1) delay_mu(c) @kernel @@ -67,7 +67,7 @@ class Grabber: :param mask: bitmask enabling or disabling each ROI engine. """ - rtio_output(now_mu(), self.channel_base+1, 0, mask) + rtio_output((self.channel_base + 1) << 8, mask) @kernel def gate_roi_pulse(self, mask, dt): From e8d58b35b470328eb68a8bb1ae9a068e35bee442 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Nov 2018 20:09:37 +0800 Subject: [PATCH 1363/2457] spi2: use new rtio_output() API --- artiq/coredevice/spi2.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index 205251084..50487ba34 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -7,7 +7,7 @@ Output event replacement is not supported and issuing commands at the same time is an error. """ -from artiq.language.core import syscall, kernel, portable, now_mu, delay_mu +from artiq.language.core import syscall, kernel, portable, delay_mu from artiq.language.types import TInt32, TNone from artiq.coredevice.rtio import rtio_output, rtio_input_data @@ -166,7 +166,7 @@ class SPIMaster: raise ValueError("Invalid SPI transfer length") if div > 257 or div < 2: raise ValueError("Invalid SPI clock divider") - rtio_output(now_mu(), self.channel, SPI_CONFIG_ADDR, flags | + rtio_output((self.channel << 8) | SPI_CONFIG_ADDR, flags | ((length - 1) << 8) | ((div - 2) << 16) | (cs << 24)) self.update_xfer_duration_mu(div, length) delay_mu(self.ref_period_mu) @@ -216,7 +216,7 @@ class SPIMaster: :param data: SPI output data to be written. """ - rtio_output(now_mu(), self.channel, SPI_DATA_ADDR, data) + rtio_output((self.channel << 8) | SPI_DATA_ADDR, data) delay_mu(self.xfer_duration_mu) @kernel From bec25cbaa03b44274514aea95ac81bd7f5026e60 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Nov 2018 20:13:14 +0800 Subject: [PATCH 1364/2457] suservo: use new rtio_output() API --- artiq/coredevice/suservo.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 850cb98e4..2864413ac 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -1,4 +1,4 @@ -from artiq.language.core import kernel, delay, now_mu, delay_mu, portable +from artiq.language.core import kernel, delay, delay_mu, portable from artiq.language.units import us, ns from artiq.coredevice.rtio import rtio_output, rtio_input_data from artiq.coredevice import spi2 as spi @@ -129,7 +129,7 @@ class SUServo: :param addr: Memory location address. :param value: Data to be written. """ - rtio_output(now_mu(), self.channel, addr | WE, value) + rtio_output((self.channel << 8) | addr | WE, value) delay_mu(self.ref_period_mu) @kernel @@ -140,7 +140,7 @@ class SUServo: :param addr: Memory location address. """ - rtio_output(now_mu(), self.channel, addr, 0) + rtio_output((self.channel << 8) | addr, 0) return rtio_input_data(self.channel) @kernel @@ -262,7 +262,7 @@ class Channel: :param en_iir: IIR updates enable :param profile: Active profile (0-31) """ - rtio_output(now_mu(), self.channel, 0, + rtio_output(self.channel << 8, en_out | (en_iir << 1) | (profile << 2)) @kernel From 0bee43aa5831f1b5de337fcde3ada3da9e5f9864 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Nov 2018 20:16:30 +0800 Subject: [PATCH 1365/2457] sawg: use new rtio_output() API --- artiq/coredevice/sawg.py | 16 ++++++++-------- artiq/coredevice/spline.py | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/artiq/coredevice/sawg.py b/artiq/coredevice/sawg.py index 50623d8ea..0a5905fa7 100644 --- a/artiq/coredevice/sawg.py +++ b/artiq/coredevice/sawg.py @@ -10,7 +10,7 @@ Output event replacement is supported except on the configuration channel. from artiq.language.types import TInt32, TFloat from numpy import int32, int64 -from artiq.language.core import kernel, now_mu +from artiq.language.core import kernel from artiq.coredevice.spline import Spline from artiq.coredevice.rtio import rtio_output @@ -69,7 +69,7 @@ class Config: ``t_sawg_spline/t_rtio_coarse = div + 1``. Default: ``0``. :param n: Current value of the counter. Default: ``0``. """ - rtio_output(now_mu(), self.channel, _SAWG_DIV, div | (n << 16)) + rtio_output((self.channel << 8) | _SAWG_DIV, div | (n << 16)) delay_mu(self._rtio_interval) @kernel @@ -108,7 +108,7 @@ class Config: :param clr2: Auto-clear phase accumulator of the ``phase2``/ ``frequency2`` DDS. Default: ``True`` """ - rtio_output(now_mu(), self.channel, _SAWG_CLR, clr0 | + rtio_output((self.channel << 8) | _SAWG_CLR, clr0 | (clr1 << 1) | (clr2 << 2)) delay_mu(self._rtio_interval) @@ -135,7 +135,7 @@ class Config: DUC-DDS data of this SAWG's *buddy* channel to *this* DAC channel. Default: ``0``. """ - rtio_output(now_mu(), self.channel, _SAWG_IQ_EN, i_enable | + rtio_output((self.channel << 8) | _SAWG_IQ_EN, i_enable | (q_enable << 1)) delay_mu(self._rtio_interval) @@ -151,25 +151,25 @@ class Config: .. seealso:: :meth:`set_duc_max` """ - rtio_output(now_mu(), self.channel, _SAWG_DUC_MAX, limit) + rtio_output((self.channel << 8) | _SAWG_DUC_MAX, limit) delay_mu(self._rtio_interval) @kernel def set_duc_min_mu(self, limit: TInt32): """.. seealso:: :meth:`set_duc_max_mu`""" - rtio_output(now_mu(), self.channel, _SAWG_DUC_MIN, limit) + rtio_output((self.channel << 8) | _SAWG_DUC_MIN, limit) delay_mu(self._rtio_interval) @kernel def set_out_max_mu(self, limit: TInt32): """.. seealso:: :meth:`set_duc_max_mu`""" - rtio_output(now_mu(), self.channel, _SAWG_OUT_MAX, limit) + rtio_output((self.channel << 8) | _SAWG_OUT_MAX, limit) delay_mu(self._rtio_interval) @kernel def set_out_min_mu(self, limit: TInt32): """.. seealso:: :meth:`set_duc_max_mu`""" - rtio_output(now_mu(), self.channel, _SAWG_OUT_MIN, limit) + rtio_output((self.channel << 8) | _SAWG_OUT_MIN, limit) delay_mu(self._rtio_interval) @kernel diff --git a/artiq/coredevice/spline.py b/artiq/coredevice/spline.py index 3aeedf57a..9f8310d1e 100644 --- a/artiq/coredevice/spline.py +++ b/artiq/coredevice/spline.py @@ -1,5 +1,5 @@ from numpy import int32, int64 -from artiq.language.core import kernel, now_mu, portable, delay +from artiq.language.core import kernel, portable, delay from artiq.coredevice.rtio import rtio_output, rtio_output_wide from artiq.language.types import TInt32, TInt64, TFloat @@ -65,7 +65,7 @@ class Spline: :param value: Spline value in integer machine units. """ - rtio_output(now_mu(), self.channel, 0, value) + rtio_output(self.channel << 8, value) @kernel(flags={"fast-math"}) def set(self, value: TFloat): @@ -76,9 +76,9 @@ class Spline: if self.width > 32: l = [int32(0)] * 2 self.pack_coeff_mu([self.to_mu64(value)], l) - rtio_output_wide(now_mu(), self.channel, 0, l) + rtio_output_wide(self.channel << 8, l) else: - rtio_output(now_mu(), self.channel, 0, self.to_mu(value)) + rtio_output(self.channel << 8, self.to_mu(value)) @kernel def set_coeff_mu(self, value): # TList(TInt32) @@ -86,7 +86,7 @@ class Spline: :param value: Spline packed raw values. """ - rtio_output_wide(now_mu(), self.channel, 0, value) + rtio_output_wide(self.channel << 8, value) @portable(flags={"fast-math"}) def pack_coeff_mu(self, coeff, packed): # TList(TInt64), TList(TInt32) From a0cc7311ad7d267c81f0bba97233ab850733f2af Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Nov 2018 20:17:55 +0800 Subject: [PATCH 1366/2457] test: tighten test_pulse_rate --- artiq/test/coredevice/test_rtio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 12f167c1b..ebc28a19f 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -414,7 +414,7 @@ class CoredeviceTest(ExperimentCase): rate = self.dataset_mgr.get("pulse_rate") print(rate) self.assertGreater(rate, 100*ns) - self.assertLess(rate, 700*ns) + self.assertLess(rate, 480*ns) def test_pulse_rate_ad9914_dds(self): """Minimum interval for sustained AD9914 DDS frequency switching""" From 998be50f07e483044b768808baa2f11b46297813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 9 Nov 2018 13:19:44 +0100 Subject: [PATCH 1367/2457] urukul: handle MSB in att_reg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/urukul.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 9f96a92ed..b37590e1a 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -174,7 +174,7 @@ class CPLD: self.cfg_reg = urukul_cfg(rf_sw=rf_sw, led=0, profile=0, io_update=0, mask_nu=0, clk_sel=clk_sel, sync_sel=sync_sel, rst=0, io_rst=0) - self.att_reg = att + self.att_reg = int32(att) self.sync_div = sync_div @kernel From e565ca6b823c0d749698994cbffdf9b25dad25d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 9 Nov 2018 13:21:18 +0100 Subject: [PATCH 1368/2457] urukul: slow down att write to datasheet limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/urukul.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index b37590e1a..6605d852b 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -14,7 +14,8 @@ SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | # SPI clock write and read dividers SPIT_CFG_WR = 2 SPIT_CFG_RD = 16 -SPIT_ATT_WR = 2 +# 30 MHz fmax, 20 ns setup, 40 ns shift to latch (limiting) +SPIT_ATT_WR = 6 SPIT_ATT_RD = 16 SPIT_DDS_WR = 2 SPIT_DDS_RD = 16 From 38c6878d498da26e3608b0cb347ce46f4f80ef68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 9 Nov 2018 13:32:05 +0100 Subject: [PATCH 1369/2457] urukul: mention min/max attenuation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/urukul.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 6605d852b..59b528e62 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -300,7 +300,8 @@ class CPLD: :param channel: Attenuator channel (0-3). :param att: Attenuation setting in dB. Higher value is more - attenuation. + attenuation. Minimum attenuation is 0*dB, maximum attenuation is + 31.5*dB. """ self.set_att_mu(channel, 255 - int32(round(att*8))) From fe3d6661ebf1b851676fa69b56ed27ffb5d2558c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 9 Nov 2018 15:00:59 +0100 Subject: [PATCH 1370/2457] manual: kasli device name for zadig on windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- doc/manual/installing.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 05a761493..1e8642a0d 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -131,7 +131,8 @@ On Windows, a third-party tool, `Zadig `_, is necessary. 1. Make sure the FPGA board's JTAG USB port is connected to your computer. 2. Activate Options → List All Devices. -3. Select the "Digilent Adept USB Device (Interface 0)" device from the drop-down list. +3. Select the "Digilent Adept USB Device (Interface 0)" or "FTDI Quad-RS232 HS" (or similar) + device from the drop-down list. 4. Select WinUSB from the spinner list. 5. Click "Install Driver" or "Replace Driver". From e509ab85531df2daec1ad271d4ba949d7cb86468 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 9 Nov 2018 22:10:46 +0800 Subject: [PATCH 1371/2457] test/dsp: use absolute import path Avoids "ImportError: attempted relative import with no known parent package" when doing a simple "python -m unittest test_XXX.py". --- artiq/gateware/test/dsp/test_sawg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/test/dsp/test_sawg.py b/artiq/gateware/test/dsp/test_sawg.py index a5eea31bd..fd392607d 100644 --- a/artiq/gateware/test/dsp/test_sawg.py +++ b/artiq/gateware/test/dsp/test_sawg.py @@ -4,7 +4,7 @@ from migen import * from migen.fhdl.verilog import convert from artiq.gateware.dsp import sawg -from .tools import xfer +from artiq.gateware.test.dsp.tools import xfer def _test_gen_dds(dut, o): From 1f7858b80b620b37bdb5ab63d50536fcaedc8cf7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 9 Nov 2018 22:11:44 +0800 Subject: [PATCH 1372/2457] test/dsp: fix rtio_output --- artiq/gateware/test/dsp/test_sawg_fe.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/test/dsp/test_sawg_fe.py b/artiq/gateware/test/dsp/test_sawg_fe.py index d518e052a..1f7cdc08c 100644 --- a/artiq/gateware/test/dsp/test_sawg_fe.py +++ b/artiq/gateware/test/dsp/test_sawg_fe.py @@ -14,8 +14,10 @@ class RTIOManager: def __init__(self): self.outputs = [] - def rtio_output(self, now, channel, addr, data): - self.outputs.append((now, channel, addr, data)) + def rtio_output(self, target, data): + channel = target >> 8 + addr = target & 0xff + self.outputs.append((now_mu(), channel, addr, data)) def rtio_output_wide(self, *args, **kwargs): self.rtio_output(*args, **kwargs) From 14b6b63916b6344e52cf76f64c09174b0c0b4aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 9 Nov 2018 18:21:33 +0000 Subject: [PATCH 1373/2457] ad9910: rewire io_delay tuning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This now reliably locates the SYNC_CLK-IO_UPDATE edge by doing two scans at different delays between start and stop IO_UPDATE. It also works well when one delay is very close to the edge. And it correctly identifies which (start or stop) pulse hit or crossed the SYNC_CLK edge. for #1143 Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 61 ++++++++++++++++++---------- artiq/test/coredevice/test_ad9910.py | 31 ++++++++------ 2 files changed, 57 insertions(+), 35 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index d0538f5be..a37f48705 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -466,17 +466,18 @@ class AD9910: raise ValueError("no valid window/delay") @kernel - def measure_io_update_alignment(self, io_up_delay): + def measure_io_update_alignment(self, delay_start, delay_stop): """Use the digital ramp generator to locate the alignment between IO_UPDATE and SYNC_CLK. The ramp generator is set up to a linear frequency ramp - (dFTW/t_SYNC_CLK=1) and started at a RTIO time stamp. + (dFTW/t_SYNC_CLK=1) and started at a coarse RTIO time stamp plus + `delay_start` and stopped at a coarse RTIO time stamp plus + `delay_stop`. - After scanning the alignment, an IO_UPDATE delay midway between two - edges should be chosen. - - :return: odd/even SYNC_CLK cycle indicator + :param delay_start: Start IO_UPDATE delay in machine units. + :param delay_stop: Stop IO_UPDATE delay in machine units. + :return: Odd/even SYNC_CLK cycle indicator. """ # set up DRG # DRG ACC autoclear and LRR on io update @@ -489,14 +490,16 @@ class AD9910: self.write32(_AD9910_REG_DRAMPR, 0x00010000) # dFTW = 1, (work around negative slope) self.write64(_AD9910_REG_DRAMPS, -1, 0) - at_mu(now_mu() + 0x10 & ~0xf) # align to RTIO/2 - self.cpld.io_update.pulse_mu(8) + # delay io_update after RTIO/2 edge + t = now_mu() + 0x10 & ~0xf + at_mu(t + delay_start) + self.cpld.io_update.pulse_mu(32 - delay_start) # realign # disable DRG autoclear and LRR on io_update self.write32(_AD9910_REG_CFR1, 0x00000002) # stop DRG self.write64(_AD9910_REG_DRAMPS, 0, 0) - at_mu((now_mu() + 0x10 & ~0xf) + io_up_delay) # delay - self.cpld.io_update.pulse_mu(32 - io_up_delay) # realign + at_mu(t + 0x1000 + delay_stop) + self.cpld.io_update.pulse_mu(32 - delay_stop) # realign ftw = self.read32(_AD9910_REG_FTW) # read out effective FTW delay(100*us) # slack # disable DRG @@ -510,22 +513,36 @@ class AD9910: Scan through increasing IO_UPDATE delays until a delay is found that lets IO_UPDATE be registered in the next SYNC_CLK cycle. Return a - IO_UPDATE delay that is midway between two such SYNC_CLK transitions. + IO_UPDATE delay that is as far away from that SYNC_CLK edge + as possible. This method assumes that the IO_UPDATE TTLOut device has one machine - unit resolution (SERDES) and that the ratio between fine RTIO frequency - (RTIO time machine units) and SYNC_CLK is 4. + unit resolution (SERDES). :return: Stable IO_UPDATE delay to be passed to the constructor :class:`AD9910` via the device database. """ - period = 4 # f_RTIO/f_SYNC = 4 - max_delay = 8 # mu, 1 ns - d0 = self.io_update_delay - t0 = int32(self.measure_io_update_alignment(d0)) - for i in range(max_delay - 1): - t = self.measure_io_update_alignment( - (d0 + i + 1) & (max_delay - 1)) - if t != t0: - return (d0 + i + period//2) & (period - 1) + period = self.sysclk_per_mu * 4 # SYNC_CLK period + repeat = 100 + for i in range(period): + t = 0 + # check whether the sync edge is strictly between i, i+2 + for j in range(repeat): + t += self.measure_io_update_alignment(i, i + 2) + if t != 0: # no certain edge + continue + # check left/right half: i,i+1 and i+1,i+2 + t1 = [0, 0] + for j in range(repeat): + t1[0] += self.measure_io_update_alignment(i, i + 1) + t1[1] += self.measure_io_update_alignment(i + 1, i + 2) + if ((t1[0] == 0 and t1[1] == repeat) or # edge left of i + 1 + (t1[0] == repeat and t1[1] == 0) or # edge right of i + 1 + (t1[0] != 0 and t1[1] != 0 and # edge very close to i + 1 + t1[0] != repeat and t1[1] != repeat)): + # the good delay is period//2 after the edge + return (i + 1 + period//2) & (period - 1) + else: # can't interpret result + raise ValueError( + "no clear IO_UPDATE-SYNC_CLK alignment edge found") raise ValueError("no IO_UPDATE-SYNC_CLK alignment edge found") diff --git a/artiq/test/coredevice/test_ad9910.py b/artiq/test/coredevice/test_ad9910.py index 4ce47fdee..93e77c0b4 100644 --- a/artiq/test/coredevice/test_ad9910.py +++ b/artiq/test/coredevice/test_ad9910.py @@ -104,18 +104,21 @@ class AD9910Exp(EnvExperiment): self.core.break_realtime() self.dev.cpld.init() self.dev.init() - bins = [0]*8 - self.scan_io_delay(bins) - self.set_dataset("bins", bins) - self.set_dataset("dly", self.dev.io_update_delay) + bins1 = [0]*4 + bins2 = [0]*4 + self.scan_io_delay(bins1, bins2) + self.set_dataset("bins1", bins1) + self.set_dataset("bins2", bins2) + self.set_dataset("dly", self.dev.tune_io_update_delay()) @kernel - def scan_io_delay(self, bins): + def scan_io_delay(self, bins1, bins2): delay(100*us) n = 100 for i in range(n): - for phase in range(len(bins)): - bins[phase] += self.dev.measure_io_update_alignment(phase) + for j in range(len(bins1)): + bins1[j] += self.dev.measure_io_update_alignment(j, j + 1) + bins2[j] += self.dev.measure_io_update_alignment(j, j + 2) delay(10*ms) @kernel @@ -174,12 +177,14 @@ class AD9910Test(ExperimentCase): def test_io_update_delay(self): self.execute(AD9910Exp, "io_update_delay") dly = self.dataset_mgr.get("dly") - bins = self.dataset_mgr.get("bins") - print(dly, bins) - n = max(bins) - # test for 4-periodicity (SYNC_CLK) and maximal contrast - for i in range(len(bins)): - self.assertEqual(abs(bins[i] - bins[(i + 4) % 8]), n) + bins1 = self.dataset_mgr.get("bins1") + bins2 = self.dataset_mgr.get("bins2") + print(dly, bins1, bins2) + n = max(bins2) + # no edge at optimal delay + self.assertEqual(bins2[(dly + 1) & 3], 0) + # edge at expected position + self.assertEqual(bins2[(dly + 3) & 3], n) def test_sw_readback(self): self.execute(AD9910Exp, "sw_readback") From e92755182745b39438f0d0c2e38f5480d23f8c3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 9 Nov 2018 19:39:11 +0100 Subject: [PATCH 1374/2457] manual: add highfinesse-net port --- doc/manual/default_network_ports.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/manual/default_network_ports.rst b/doc/manual/default_network_ports.rst index 6bb699ab9..33fa74a05 100644 --- a/doc/manual/default_network_ports.rst +++ b/doc/manual/default_network_ports.rst @@ -46,4 +46,6 @@ Default network ports +---------------------------------+--------------+ | TOPTICA Laser SDK (out-of-tree) | 3272 | +---------------------------------+--------------+ +| HighFinesse (out-of-tree) | 3273 | ++---------------------------------+--------------+ From a4997c56cfe8670bc26cff6c136ffcfab59c1a9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 9 Nov 2018 18:54:34 +0000 Subject: [PATCH 1375/2457] ad9910: simplify edge detection logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index a37f48705..ff5954874 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -536,13 +536,12 @@ class AD9910: for j in range(repeat): t1[0] += self.measure_io_update_alignment(i, i + 1) t1[1] += self.measure_io_update_alignment(i + 1, i + 2) - if ((t1[0] == 0 and t1[1] == repeat) or # edge left of i + 1 - (t1[0] == repeat and t1[1] == 0) or # edge right of i + 1 - (t1[0] != 0 and t1[1] != 0 and # edge very close to i + 1 - t1[0] != repeat and t1[1] != repeat)): - # the good delay is period//2 after the edge - return (i + 1 + period//2) & (period - 1) - else: # can't interpret result + if ((t1[0] == 0 and t1[1] == 0) or + (t1[0] == repeat and t1[1] == repeat)): + # edge is not close to i + 1, can't interpret result raise ValueError( "no clear IO_UPDATE-SYNC_CLK alignment edge found") + else: + # the good delay is period//2 after the edge + return (i + 1 + period//2) & (period - 1) raise ValueError("no IO_UPDATE-SYNC_CLK alignment edge found") From 84a6b3d09b140ac1254d9464861987104a7ee390 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 10 Nov 2018 14:14:55 +0800 Subject: [PATCH 1376/2457] runtime: fix DMA recording after now-pinning --- artiq/firmware/ksupport/lib.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 2e7e6eb98..5b3c2bdfd 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -20,6 +20,8 @@ use dyld::Library; use board_artiq::{mailbox, rpc_queue}; use proto_artiq::{kernel_proto, rpc_proto}; use kernel_proto::*; +#[cfg(has_rtio_dma)] +use board_misoc::csr; fn send(request: &Message) { unsafe { mailbox::send(request as *const _ as usize) } @@ -335,8 +337,9 @@ unsafe fn dma_record_output_prepare(timestamp: i64, target: i32, } #[unwind(aborts)] -extern fn dma_record_output(timestamp: i64, target: i32, word: i32) { +extern fn dma_record_output(target: i32, word: i32) { unsafe { + let timestamp = *(csr::rtio::NOW_HI_ADDR as *const i64); let data = dma_record_output_prepare(timestamp, target, 1); data.copy_from_slice(&[ (word >> 0) as u8, @@ -348,10 +351,11 @@ extern fn dma_record_output(timestamp: i64, target: i32, word: i32) { } #[unwind(aborts)] -extern fn dma_record_output_wide(timestamp: i64, target: i32, words: CSlice) { +extern fn dma_record_output_wide(target: i32, words: CSlice) { assert!(words.len() <= 16); // enforce the hardware limit unsafe { + let timestamp = *(csr::rtio::NOW_HI_ADDR as *const i64); let mut data = dma_record_output_prepare(timestamp, target, words.len()); for word in words.as_ref().iter() { data[..4].copy_from_slice(&[ @@ -404,8 +408,6 @@ extern fn dma_playback(timestamp: i64, ptr: i32) { assert!(ptr % 64 == 0); unsafe { - use board_misoc::csr; - csr::rtio_dma::base_address_write(ptr as u64); csr::rtio_dma::time_offset_write(timestamp as u64); From 59033d258881d5667fbff85e027501274e9ab647 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 12 Nov 2018 19:51:54 +0800 Subject: [PATCH 1377/2457] firmware: workaround for RPC failures --- artiq/firmware/ksupport/lib.rs | 5 +++++ artiq/firmware/libproto_artiq/kernel_proto.rs | 4 ++++ artiq/firmware/runtime/session.rs | 10 ++++++++++ 3 files changed, 19 insertions(+) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 5b3c2bdfd..a44a5ccb2 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -101,6 +101,7 @@ mod api; mod rtio; mod nrt_bus; +static mut NOW: u64 = 0; static mut LIBRARY: Option> = None; #[no_mangle] @@ -185,6 +186,7 @@ fn terminate(exception: &eh_artiq::Exception, backtrace: &mut [usize]) -> ! { } let backtrace = &mut backtrace.as_mut()[0..cursor]; + send(&NowSave(unsafe { NOW })); send(&RunException { exception: kernel_proto::Exception { name: str::from_utf8(exception.name.as_ref()).unwrap(), @@ -508,7 +510,10 @@ pub unsafe fn main() { ptr::write_bytes(__bss_start as *mut u8, 0, (_end - __bss_start) as usize); + send(&NowInitRequest); + recv!(&NowInitReply(now) => NOW = now); (mem::transmute::(__modinit__))(); + send(&NowSave(NOW)); if let Some(typeinfo) = typeinfo { attribute_writeback(typeinfo as *const ()); diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index cefc27ee5..73c9e2765 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -22,6 +22,10 @@ pub enum Message<'a> { LoadRequest(&'a [u8]), LoadReply(Result<(), dyld::Error<'a>>), + NowInitRequest, + NowInitReply(u64), + NowSave(u64), + RtioInitRequest, RtioDestinationStatusRequest { destination: u8 }, diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 3ab46cad9..ae23c3410 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -63,6 +63,7 @@ macro_rules! unexpected { // Persistent state #[derive(Debug)] struct Congress { + now: u64, cache: Cache, dma_manager: DmaManager, finished_cleanly: Cell @@ -71,6 +72,7 @@ struct Congress { impl Congress { fn new() -> Congress { Congress { + now: 0, cache: Cache::new(), dma_manager: DmaManager::new(), finished_cleanly: Cell::new(true) @@ -363,6 +365,14 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, kern_acknowledge() } + &kern::NowInitRequest => + kern_send(io, &kern::NowInitReply(session.congress.now)), + + &kern::NowSave(now) => { + session.congress.now = now; + kern_acknowledge() + } + &kern::DmaRecordStart(name) => { session.congress.dma_manager.record_start(name); kern_acknowledge() From 0edae64afb69a8fbf3ed7e04e6f6ad68abc527ce Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 12 Nov 2018 15:28:27 +0000 Subject: [PATCH 1378/2457] firmware: fix TOCTTOU race in sync/async RPC code. Before this commit, the main loop in session code was laid like: 1. process_kern_queued_rpc 2. process_host_message 3. process_kern_message If a host message (such as an RPC reply) caused the kernel to exit, then any async RPCs would not complete, since RunFinished immediately shuts down the kernel. Fix this by reordering 1 and 2. --- artiq/firmware/runtime/session.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index ae23c3410..0ed5a3b62 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -502,16 +502,16 @@ fn host_kernel_worker(io: &Io, aux_mutex: &Mutex, let mut session = Session::new(congress); loop { - while !rpc_queue::empty() { - process_kern_queued_rpc(stream, &mut session)? - } - if stream.can_recv() { process_host_message(io, stream, &mut session)? } else if !stream.may_recv() { return Ok(()) } + while !rpc_queue::empty() { + process_kern_queued_rpc(stream, &mut session)? + } + if mailbox::receive() != 0 { process_kern_message(io, aux_mutex, routing_table, up_destinations, From 583bba8777d926647b82e729009f200036249272 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 12 Nov 2018 15:36:36 +0000 Subject: [PATCH 1379/2457] Revert "firmware: workaround for RPC failures" This reverts commit 59033d258881d5667fbff85e027501274e9ab647. --- artiq/firmware/ksupport/lib.rs | 5 ----- artiq/firmware/libproto_artiq/kernel_proto.rs | 4 ---- artiq/firmware/runtime/session.rs | 10 ---------- 3 files changed, 19 deletions(-) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index a44a5ccb2..5b3c2bdfd 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -101,7 +101,6 @@ mod api; mod rtio; mod nrt_bus; -static mut NOW: u64 = 0; static mut LIBRARY: Option> = None; #[no_mangle] @@ -186,7 +185,6 @@ fn terminate(exception: &eh_artiq::Exception, backtrace: &mut [usize]) -> ! { } let backtrace = &mut backtrace.as_mut()[0..cursor]; - send(&NowSave(unsafe { NOW })); send(&RunException { exception: kernel_proto::Exception { name: str::from_utf8(exception.name.as_ref()).unwrap(), @@ -510,10 +508,7 @@ pub unsafe fn main() { ptr::write_bytes(__bss_start as *mut u8, 0, (_end - __bss_start) as usize); - send(&NowInitRequest); - recv!(&NowInitReply(now) => NOW = now); (mem::transmute::(__modinit__))(); - send(&NowSave(NOW)); if let Some(typeinfo) = typeinfo { attribute_writeback(typeinfo as *const ()); diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index 73c9e2765..cefc27ee5 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -22,10 +22,6 @@ pub enum Message<'a> { LoadRequest(&'a [u8]), LoadReply(Result<(), dyld::Error<'a>>), - NowInitRequest, - NowInitReply(u64), - NowSave(u64), - RtioInitRequest, RtioDestinationStatusRequest { destination: u8 }, diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 0ed5a3b62..cab4ef25a 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -63,7 +63,6 @@ macro_rules! unexpected { // Persistent state #[derive(Debug)] struct Congress { - now: u64, cache: Cache, dma_manager: DmaManager, finished_cleanly: Cell @@ -72,7 +71,6 @@ struct Congress { impl Congress { fn new() -> Congress { Congress { - now: 0, cache: Cache::new(), dma_manager: DmaManager::new(), finished_cleanly: Cell::new(true) @@ -365,14 +363,6 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, kern_acknowledge() } - &kern::NowInitRequest => - kern_send(io, &kern::NowInitReply(session.congress.now)), - - &kern::NowSave(now) => { - session.congress.now = now; - kern_acknowledge() - } - &kern::DmaRecordStart(name) => { session.congress.dma_manager.record_start(name); kern_acknowledge() From dd829afebd76123a2abe0b3cd7acc595ad7d9085 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 12 Nov 2018 15:39:55 +0000 Subject: [PATCH 1380/2457] firmware: fix another TOCTTOU race in sync/async RPC code. --- artiq/firmware/ksupport/lib.rs | 13 +++++++++++++ artiq/firmware/libproto_artiq/kernel_proto.rs | 1 + artiq/firmware/runtime/session.rs | 10 ++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 5b3c2bdfd..74ab757ef 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -514,6 +514,19 @@ pub unsafe fn main() { attribute_writeback(typeinfo as *const ()); } + // Make sure all async RPCs are processed before exiting. + // Otherwise, if the comms and kernel CPU run in the following sequence: + // + // comms kernel + // ----------------------- ----------------------- + // check for async RPC + // post async RPC + // post RunFinished + // check for mailbox + // + // the async RPC would be missed. + send(&RpcFlush); + send(&RunFinished); loop {} diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index cefc27ee5..f7fef6eb0 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -64,6 +64,7 @@ pub enum Message<'a> { }, RpcRecvRequest(*mut ()), RpcRecvReply(Result>), + RpcFlush, CacheGetRequest { key: &'a str }, CacheGetReply { value: &'static [i32] }, diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index cab4ef25a..c0498ef4a 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -410,7 +410,13 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, kern_acknowledge() } } - } + }, + &kern::RpcFlush => { + // See ksupport/lib.rs for the reason this request exists. + // We do not need to do anything here because of how the main loop is + // structured. + kern_acknowledge() + }, &kern::CacheGetRequest { key } => { let value = session.congress.cache.get(key); @@ -581,7 +587,7 @@ fn respawn(io: &Io, handle: &mut Option, f: F) *handle = Some(io.spawn(16384, f)) } -pub fn thread(io: Io, aux_mutex: &Mutex, +pub fn thread(io: Io, aux_mutex: &Mutex, routing_table: &Urc>, up_destinations: &Urc>) { let listener = TcpListener::new(&io, 65535); From 68aad3e4822921d4d2cdaf60fed76ccf3e3e7bf7 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 12 Nov 2018 15:28:27 +0000 Subject: [PATCH 1381/2457] firmware: fix TOCTTOU race in sync/async RPC code. Before this commit, the main loop in session code was laid like: 1. process_kern_queued_rpc 2. process_host_message 3. process_kern_message If a host message (such as an RPC reply) caused the kernel to exit, then any async RPCs would not complete, since RunFinished immediately shuts down the kernel. Fix this by reordering 1 and 2. --- artiq/firmware/runtime/session.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index d9812861b..28dbcadef 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -497,16 +497,16 @@ fn host_kernel_worker(io: &Io, let mut session = Session::new(congress); loop { - while !rpc_queue::empty() { - process_kern_queued_rpc(stream, &mut session)? - } - if stream.can_recv() { process_host_message(io, stream, &mut session)? } else if !stream.may_recv() { return Ok(()) } + while !rpc_queue::empty() { + process_kern_queued_rpc(stream, &mut session)? + } + if mailbox::receive() != 0 { process_kern_message(io, Some(stream), &mut session)?; } From 248c1cf7dce15b358f857c8fce009cb33559ff78 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 12 Nov 2018 15:39:55 +0000 Subject: [PATCH 1382/2457] firmware: fix another TOCTTOU race in sync/async RPC code. --- artiq/firmware/ksupport/lib.rs | 13 +++++++++++++ artiq/firmware/libproto_artiq/kernel_proto.rs | 1 + artiq/firmware/runtime/session.rs | 8 +++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 8d481f7b5..d176f5551 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -518,6 +518,19 @@ pub unsafe fn main() { attribute_writeback(typeinfo as *const ()); } + // Make sure all async RPCs are processed before exiting. + // Otherwise, if the comms and kernel CPU run in the following sequence: + // + // comms kernel + // ----------------------- ----------------------- + // check for async RPC + // post async RPC + // post RunFinished + // check for mailbox + // + // the async RPC would be missed. + send(&RpcFlush); + send(&RunFinished); loop {} diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index ae794ec34..1dd60e77f 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -73,6 +73,7 @@ pub enum Message<'a> { }, RpcRecvRequest(*mut ()), RpcRecvReply(Result>), + RpcFlush, CacheGetRequest { key: &'a str }, CacheGetReply { value: &'static [i32] }, diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 28dbcadef..f95febc4a 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -417,7 +417,13 @@ fn process_kern_message(io: &Io, mut stream: Option<&mut TcpStream>, kern_acknowledge() } } - } + }, + &kern::RpcFlush => { + // See ksupport/lib.rs for the reason this request exists. + // We do not need to do anything here because of how the main loop is + // structured. + kern_acknowledge() + }, &kern::CacheGetRequest { key } => { let value = session.congress.cache.get(key); From 2af6edb8f550c5a9b61dd18123eeccffc3e9389f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 13 Nov 2018 13:00:37 +0000 Subject: [PATCH 1383/2457] eem: fix reset/sync in suservo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/gateware/eem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 96050b748..56f9cb25e 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -541,7 +541,7 @@ class SUServo(_EEM): target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - pads = target.platform.request("{}_dds_reset".format(eem_urukul1)) + pads = target.platform.request("{}_dds_reset_sync_in".format(eem_urukul1)) target.specials += DifferentialOutput(0, pads.p, pads.n) for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): From a52d1be1407e43ffa88533acd541913e898665ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 14 Nov 2018 07:43:56 +0100 Subject: [PATCH 1384/2457] urukul: expose PROFILE setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add documentation * add unittest Signed-off-by: Robert Jördens --- artiq/coredevice/urukul.py | 12 ++++++++++++ artiq/test/coredevice/test_urukul.py | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 59b528e62..8bb514c09 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -335,3 +335,15 @@ class CPLD: ftw = ftw_max//div assert ftw*div == ftw_max self.sync.set_mu(ftw) + + @kernel + def set_profile(self, profile): + """Set the PROFILE pins. + + The PROFILE pins are common to all four DDS channels. + + :param profile: PROFILE pins in numeric representation (0-7). + """ + cfg = self.cfg_reg & ~(7 << CFG_PROFILE) + cfg |= (profile & 7) << CFG_PROFILE + self.cfg_write(cfg) diff --git a/artiq/test/coredevice/test_urukul.py b/artiq/test/coredevice/test_urukul.py index 2141303c4..878b37d32 100644 --- a/artiq/test/coredevice/test_urukul.py +++ b/artiq/test/coredevice/test_urukul.py @@ -98,6 +98,13 @@ class UrukulExp(EnvExperiment): self.dev.init() self.dev.set_sync_div(2) + @kernel + def profile(self): + self.core.break_realtime() + self.dev.init() + self.dev.set_profile(7) + self.dev.set_profile(0) + class UrukulTest(ExperimentCase): def test_instantiate(self): @@ -147,3 +154,6 @@ class UrukulTest(ExperimentCase): def test_sync(self): self.execute(UrukulExp, "sync") + + def test_profile(self): + self.execute(UrukulExp, "profile") From d0cadfeb4bfb46c281a728ff16424b909f026302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 14 Nov 2018 07:55:01 +0100 Subject: [PATCH 1385/2457] ad9910: more idiomatic register names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index ff5954874..96993447b 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -26,22 +26,22 @@ _AD9910_REG_CFR1 = 0x00 _AD9910_REG_CFR2 = 0x01 _AD9910_REG_CFR3 = 0x02 _AD9910_REG_AUX_DAC = 0x03 -_AD9910_REG_IO_UPD = 0x04 +_AD9910_REG_IO_UPDATE = 0x04 _AD9910_REG_FTW = 0x07 _AD9910_REG_POW = 0x08 _AD9910_REG_ASF = 0x09 -_AD9910_REG_MSYNC = 0x0A -_AD9910_REG_DRAMPL = 0x0B -_AD9910_REG_DRAMPS = 0x0C -_AD9910_REG_DRAMPR = 0x0D -_AD9910_REG_PR0 = 0x0E -_AD9910_REG_PR1 = 0x0F -_AD9910_REG_PR2 = 0x10 -_AD9910_REG_PR3 = 0x11 -_AD9910_REG_PR4 = 0x12 -_AD9910_REG_PR5 = 0x13 -_AD9910_REG_PR6 = 0x14 -_AD9910_REG_PR7 = 0x15 +_AD9910_REG_SYNC = 0x0a +_AD9910_REG_RAMP_LIMIT = 0x0b +_AD9910_REG_RAMP_STEP = 0x0c +_AD9910_REG_RAMP_RATE = 0x0d +_AD9910_REG_PROFILE0 = 0x0e +_AD9910_REG_PROFILE1 = 0x0f +_AD9910_REG_PROFILE2 = 0x10 +_AD9910_REG_PROFILE3 = 0x11 +_AD9910_REG_PROFILE4 = 0x12 +_AD9910_REG_PROFILE5 = 0x13 +_AD9910_REG_PROFILE6 = 0x14 +_AD9910_REG_PROFILE7 = 0x15 _AD9910_REG_RAM = 0x16 @@ -297,7 +297,7 @@ class AD9910: # is equivalent to an output pipeline latency. dt = int32(now_mu()) - int32(ref_time) pow += dt*ftw*self.sysclk_per_mu >> 16 - self.write64(_AD9910_REG_PR0, (asf << 16) | pow, ftw) + self.write64(_AD9910_REG_PROFILE0, (asf << 16) | pow, ftw) delay_mu(int64(self.io_update_delay)) self.cpld.io_update.pulse_mu(8) # assumes 8 mu > t_SYSCLK at_mu(now_mu() & ~0xf) @@ -389,7 +389,7 @@ class AD9910: :param window: Symmetric SYNC_IN validation window (0-15) in steps of ~75ps for both hold and setup margin. """ - self.write32(_AD9910_REG_MSYNC, + self.write32(_AD9910_REG_SYNC, (window << 28) | # SYNC S/H validation delay (1 << 27) | # SYNC receiver enable (0 << 26) | # SYNC generator disable @@ -485,11 +485,11 @@ class AD9910: # DRG -> FTW, DRG enable self.write32(_AD9910_REG_CFR2, 0x01090000) # no limits - self.write64(_AD9910_REG_DRAMPL, -1, 0) + self.write64(_AD9910_REG_RAMP_LIMIT, -1, 0) # DRCTL=0, dt=1 t_SYNC_CLK - self.write32(_AD9910_REG_DRAMPR, 0x00010000) + self.write32(_AD9910_REG_RAMP_RATE, 0x00010000) # dFTW = 1, (work around negative slope) - self.write64(_AD9910_REG_DRAMPS, -1, 0) + self.write64(_AD9910_REG_RAMP_STEP, -1, 0) # delay io_update after RTIO/2 edge t = now_mu() + 0x10 & ~0xf at_mu(t + delay_start) @@ -497,7 +497,7 @@ class AD9910: # disable DRG autoclear and LRR on io_update self.write32(_AD9910_REG_CFR1, 0x00000002) # stop DRG - self.write64(_AD9910_REG_DRAMPS, 0, 0) + self.write64(_AD9910_REG_RAMP_STEP, 0, 0) at_mu(t + 0x1000 + delay_stop) self.cpld.io_update.pulse_mu(32 - delay_stop) # realign ftw = self.read32(_AD9910_REG_FTW) # read out effective FTW From c3178c2cab5638544957d5c487897945873bb17f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 14 Nov 2018 08:30:28 +0100 Subject: [PATCH 1386/2457] ad9910: profile support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 10 ++++++---- artiq/test/coredevice/test_ad9910.py | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 96993447b..ae5842808 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -256,7 +256,7 @@ class AD9910: @kernel def set_mu(self, ftw, pow=0, asf=0x3fff, phase_mode=_PHASE_MODE_DEFAULT, - ref_time=-1): + ref_time=-1, profile=0): """Set profile 0 data in machine units. This uses machine units (FTW, POW, ASF). The frequency tuning word @@ -276,6 +276,7 @@ class AD9910: by :meth:`set_phase_mode` for this call. :param ref_time: Fiducial time used to compute absolute or tracking phase updates. In machine units as obtained by `now_mu()`. + :param profile: Profile number to set (0-7, default: 0). :return: Resulting phase offset word after application of phase tracking offset. When using :const:`PHASE_MODE_CONTINUOUS` in subsequent calls, use this value as the "current" phase. @@ -297,7 +298,7 @@ class AD9910: # is equivalent to an output pipeline latency. dt = int32(now_mu()) - int32(ref_time) pow += dt*ftw*self.sysclk_per_mu >> 16 - self.write64(_AD9910_REG_PROFILE0, (asf << 16) | pow, ftw) + self.write64(_AD9910_REG_PROFILE0 + profile, (asf << 16) | pow, ftw) delay_mu(int64(self.io_update_delay)) self.cpld.io_update.pulse_mu(8) # assumes 8 mu > t_SYSCLK at_mu(now_mu() & ~0xf) @@ -332,7 +333,7 @@ class AD9910: @kernel def set(self, frequency, phase=0.0, amplitude=1.0, - phase_mode=_PHASE_MODE_DEFAULT, ref_time=-1): + phase_mode=_PHASE_MODE_DEFAULT, ref_time=-1, profile=0): """Set profile 0 data in SI units. .. seealso:: :meth:`set_mu` @@ -342,11 +343,12 @@ class AD9910: :param asf: Amplitude in units of full scale :param phase_mode: Phase mode constant :param ref_time: Fiducial time stamp in machine units + :param profile: Profile to affect :return: Resulting phase offset in turns """ return self.pow_to_turns(self.set_mu( self.frequency_to_ftw(frequency), self.turns_to_pow(phase), - self.amplitude_to_asf(amplitude), phase_mode, ref_time)) + self.amplitude_to_asf(amplitude), phase_mode, ref_time, profile)) @kernel def set_att_mu(self, att): diff --git a/artiq/test/coredevice/test_ad9910.py b/artiq/test/coredevice/test_ad9910.py index 93e77c0b4..fe5ad6a66 100644 --- a/artiq/test/coredevice/test_ad9910.py +++ b/artiq/test/coredevice/test_ad9910.py @@ -134,6 +134,20 @@ class AD9910Exp(EnvExperiment): sw_off = (self.dev.cpld.sta_read() >> (self.dev.chip_select - 4)) & 1 self.set_dataset("sw", (sw_on, sw_off)) + @kernel + def profile_readback(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + for i in range(8): + self.dev.set_mu(ftw=i, profile=i) + ftw = [0] * 8 + for i in range(8): + self.dev.cpld.set_profile(i) + ftw[i] = self.dev.read32(_AD9910_REG_FTW) + delay(100*us) + self.set_dataset("ftw", ftw) + class AD9910Test(ExperimentCase): def test_instantiate(self): @@ -189,3 +203,7 @@ class AD9910Test(ExperimentCase): def test_sw_readback(self): self.execute(AD9910Exp, "sw_readback") self.assertEqual(self.dataset_mgr.get("sw"), (1, 0)) + + def test_profile_readback(self): + self.execute(AD9910Exp, "profile_readback") + self.assertEqual(self.dataset_mgr.get("ftw"), list(range(8))) From f77a75ab1728b452856337a1d83200f04b1190b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 14 Nov 2018 07:41:24 +0000 Subject: [PATCH 1387/2457] test_ad9910: robustify w.r.t. profile synchronization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/test/coredevice/test_ad9910.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/test/coredevice/test_ad9910.py b/artiq/test/coredevice/test_ad9910.py index fe5ad6a66..b5294e80e 100644 --- a/artiq/test/coredevice/test_ad9910.py +++ b/artiq/test/coredevice/test_ad9910.py @@ -144,6 +144,10 @@ class AD9910Exp(EnvExperiment): ftw = [0] * 8 for i in range(8): self.dev.cpld.set_profile(i) + # If PROFILE is not alligned to SYNC_CLK a multi-bit change + # doesn't transfer cleanly. Use IO_UPDATE to load the profile + # again. + self.dev.cpld.io_update.pulse_mu(8) ftw[i] = self.dev.read32(_AD9910_REG_FTW) delay(100*us) self.set_dataset("ftw", ftw) From 494ffca4d3d027da4557ae7badaaea92837a4d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 14 Nov 2018 21:47:22 +0100 Subject: [PATCH 1388/2457] gui,scan: add CenterScan Scannable variant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * parametrized by center/span/step instead of start/stop/npoints which is more convenient in some applications * no scan widget support so far Signed-off-by: Robert Jördens --- artiq/gui/entries.py | 79 ++++++++++++++++++++++++++++++++++++++++++ artiq/language/scan.py | 40 ++++++++++++++++++++- 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/artiq/gui/entries.py b/artiq/gui/entries.py index 2469edfbf..bfb4f405d 100644 --- a/artiq/gui/entries.py +++ b/artiq/gui/entries.py @@ -275,6 +275,78 @@ class _RangeScan(LayoutWidget): randomize.setChecked(state["randomize"]) +class _CenterScan(LayoutWidget): + def __init__(self, procdesc, state): + LayoutWidget.__init__(self) + + scale = procdesc["scale"] + + def apply_properties(widget): + widget.setDecimals(procdesc["ndecimals"]) + if procdesc["global_min"] is not None: + widget.setMinimum(procdesc["global_min"]/scale) + else: + widget.setMinimum(float("-inf")) + if procdesc["global_max"] is not None: + widget.setMaximum(procdesc["global_max"]/scale) + else: + widget.setMaximum(float("inf")) + if procdesc["global_step"] is not None: + widget.setSingleStep(procdesc["global_step"]/scale) + if procdesc["unit"]: + widget.setSuffix(" " + procdesc["unit"]) + + center = ScientificSpinBox() + disable_scroll_wheel(center) + apply_properties(center) + center.setPrecision() + center.setRelativeStep() + center.setValue(state["center"]) + self.addWidget(center, 0, 1) + self.addWidget(QtWidgets.QLabel("Center:"), 0, 0) + + span = ScientificSpinBox() + disable_scroll_wheel(span) + apply_properties(span) + span.setPrecision() + span.setRelativeStep() + span.setMinimum(0) + span.setValue(state["span"]) + self.addWidget(span, 1, 1) + self.addWidget(QtWidgets.QLabel("Span:"), 1, 0) + + step = ScientificSpinBox() + disable_scroll_wheel(step) + apply_properties(step) + step.setPrecision() + step.setRelativeStep() + step.setMinimum(0) + step.setValue(state["step"]) + self.addWidget(step, 2, 1) + self.addWidget(QtWidgets.QLabel("Step:"), 2, 0) + + randomize = QtWidgets.QCheckBox("Randomize") + self.addWidget(randomize, 3, 1) + randomize.setChecked(state["randomize"]) + + def update_center(value): + state["center"] = value*scale + + def update_span(value): + state["span"] = value*scale + + def update_step(value): + state["step"] = value*scale + + def update_randomize(value): + state["randomize"] = value + + center.valueChanged.connect(update_center) + span.valueChanged.connect(update_span) + step.valueChanged.connect(update_step) + randomize.stateChanged.connect(update_randomize) + + class _ExplicitScan(LayoutWidget): def __init__(self, state): LayoutWidget.__init__(self) @@ -307,6 +379,7 @@ class ScanEntry(LayoutWidget): self.widgets = OrderedDict() self.widgets["NoScan"] = _NoScan(procdesc, state["NoScan"]) self.widgets["RangeScan"] = _RangeScan(procdesc, state["RangeScan"]) + self.widgets["CenterScan"] = _CenterScan(procdesc, state["CenterScan"]) self.widgets["ExplicitScan"] = _ExplicitScan(state["ExplicitScan"]) for widget in self.widgets.values(): self.stack.addWidget(widget) @@ -314,6 +387,7 @@ class ScanEntry(LayoutWidget): self.radiobuttons = OrderedDict() self.radiobuttons["NoScan"] = QtWidgets.QRadioButton("No scan") self.radiobuttons["RangeScan"] = QtWidgets.QRadioButton("Range") + self.radiobuttons["CenterScan"] = QtWidgets.QRadioButton("Center") self.radiobuttons["ExplicitScan"] = QtWidgets.QRadioButton("Explicit") scan_type = QtWidgets.QButtonGroup() for n, b in enumerate(self.radiobuttons.values()): @@ -343,6 +417,8 @@ class ScanEntry(LayoutWidget): "NoScan": {"value": 0.0, "repetitions": 1}, "RangeScan": {"start": 0.0, "stop": 100.0*scale, "npoints": 10, "randomize": False}, + "CenterScan": {"center": 0.*scale, "span": 100.*scale, + "step": 10.*scale, "randomize": False}, "ExplicitScan": {"sequence": []} } if "default" in procdesc: @@ -361,6 +437,9 @@ class ScanEntry(LayoutWidget): state[ty]["npoints"] = default["npoints"] state[ty]["randomize"] = default["randomize"] state[ty]["seed"] = default["seed"] + elif ty == "CenterScan": + for key in "center span step randomize seed".split(): + state[ty][key] = default[key] elif ty == "ExplicitScan": state[ty]["sequence"] = default["sequence"] else: diff --git a/artiq/language/scan.py b/artiq/language/scan.py index 3df898ad0..4dd4cdd1b 100644 --- a/artiq/language/scan.py +++ b/artiq/language/scan.py @@ -27,7 +27,7 @@ from artiq.language import units __all__ = ["ScanObject", - "NoScan", "RangeScan", "ExplicitScan", + "NoScan", "RangeScan", "CenterScan", "ExplicitScan", "Scannable", "MultiScanManager"] @@ -93,6 +93,43 @@ class RangeScan(ScanObject): "seed": self.seed} +class CenterScan(ScanObject): + """A scan object that yields evenly spaced values within a span around a + center. If ``step`` is finite, then ``center`` is always included. + Values outside ``span`` around center are never included. + If ``randomize`` is True the points are randomly ordered.""" + def __init__(self, center, span, step, randomize=False, seed=None): + self.center = center + self.span = span + self.step = step + self.randomize = randomize + self.seed = seed + + if step == 0.: + self.sequence = [] + else: + n = 1 + int(span/(2.*step)) + self.sequence = [center + sign*i*step + for i in range(n) for sign in [-1, 1]][1:] + + if randomize: + rng = random.Random(seed) + random.shuffle(self.sequence, rng.random) + + def __iter__(self): + return iter(self.sequence) + + def __len__(self): + return len(self.sequence) + + def describe(self): + return {"ty": "CenterScan", + "center": self.center, "step": self.step, + "span": self.span, + "randomize": self.randomize, + "seed": self.seed} + + class ExplicitScan(ScanObject): """A scan object that yields values from an explicitly defined sequence.""" def __init__(self, sequence): @@ -111,6 +148,7 @@ class ExplicitScan(ScanObject): _ty_to_scan = { "NoScan": NoScan, "RangeScan": RangeScan, + "CenterScan": CenterScan, "ExplicitScan": ExplicitScan } From d3483c1d26ad8049384e656ad773b5637517df52 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Nov 2018 19:40:35 +0800 Subject: [PATCH 1389/2457] kasli: fix SDRAM read delay reset/wrap issue. Closes #1149 --- artiq/firmware/libboard_misoc/sdram.rs | 18 ++++++++++++++++++ conda/artiq-dev/meta.yaml | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_misoc/sdram.rs b/artiq/firmware/libboard_misoc/sdram.rs index 0c41e6c0e..6e3071c4b 100644 --- a/artiq/firmware/libboard_misoc/sdram.rs +++ b/artiq/firmware/libboard_misoc/sdram.rs @@ -242,6 +242,12 @@ mod ddr { ddrphy::dly_sel_write(1 << (DQS_SIGNAL_COUNT - n - 1)); ddrphy::rdly_dq_rst_write(1); + #[cfg(soc_platform = "kasli")] + { + for _ in 0..3 { + ddrphy::rdly_dq_bitslip_write(1); + } + } for _ in 0..DDRPHY_MAX_DELAY { let mut working = true; @@ -327,6 +333,12 @@ mod ddr { let mut max_seen_valid = 0; ddrphy::rdly_dq_rst_write(1); + #[cfg(soc_platform = "kasli")] + { + for _ in 0..3 { + ddrphy::rdly_dq_bitslip_write(1); + } + } for delay in 0..DDRPHY_MAX_DELAY { let mut valid = true; @@ -384,6 +396,12 @@ mod ddr { // Set delay to the middle ddrphy::rdly_dq_rst_write(1); + #[cfg(soc_platform = "kasli")] + { + for _ in 0..3 { + ddrphy::rdly_dq_bitslip_write(1); + } + } for _ in 0..mean_delay { ddrphy::rdly_dq_inc_write(1); } diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 48d448b2e..4b596ccd1 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.8 py35_0+git2d62c0c - - misoc 0.11 py35_31+git5ce139dd + - misoc 0.11 py35_33+git128750aa - jesd204b 0.10 - microscope - binutils-or1k-linux >=2.27 From de9d21ffc87e4d1bb9299b235439490b6dd2ac03 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 16 Nov 2018 15:14:20 +0800 Subject: [PATCH 1390/2457] nix: use fetchFromGitHub for llvmlite --- nix/llvmlite.nix | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nix/llvmlite.nix b/nix/llvmlite.nix index e03f408e8..5db02ca35 100644 --- a/nix/llvmlite.nix +++ b/nix/llvmlite.nix @@ -1,14 +1,14 @@ -{ stdenv, fetchgit, llvm-or1k, makeWrapper, python3, ncurses, zlib, python3Packages }: +{ stdenv, fetchFromGitHub, llvm-or1k, makeWrapper, python3, ncurses, zlib, python3Packages }: let version = "0f4ebae"; in stdenv.mkDerivation rec { name = "llvmlite-${version}"; - src = fetchgit { - url = "https://github.com/m-labs/llvmlite"; + src = fetchFromGitHub { rev = "401dfb713166bdd2bc0d3ab2b7ebf12e7a434130"; - sha256 = "1ci1pnpspv1pqz712yix1nmplq7568vpsr6gzzl3a33w9s0sw2nq"; - leaveDotGit = true; + owner = "m-labs"; + repo = "llvmlite"; + sha256 = "1hqahd87ihwgjsaxv0y2iywldi1zgyjxjfy3sy3rr1gnwvxb47xw"; }; buildInputs = [ makeWrapper python3 ncurses zlib llvm-or1k python3Packages.setuptools ]; From d1eee7c0ea4d8e19404dbfa5dacd1ee4272b28b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 16 Nov 2018 13:17:43 +0000 Subject: [PATCH 1391/2457] ad9910: ensure sync is driven when required MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #1194 Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index ae5842808..5d171ac55 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -101,6 +101,8 @@ class AD9910: self.pll_vco = pll_vco assert 0 <= pll_cp <= 7 self.pll_cp = pll_cp + if sync_delay_seed >= 0 and not self.cpld.sync_div: + raise ValueError("parent cpld does not drive SYNC") self.sync_delay_seed = sync_delay_seed self.io_update_delay = io_update_delay self.phase_mode = PHASE_MODE_CONTINUOUS @@ -430,6 +432,8 @@ class AD9910: Defaults to 15 (half range). :return: Tuple of optimal delay and window size. """ + if not self.cpld.sync_div: + raise ValueError("parent cpld does not drive SYNC") search_span = 31 # FIXME https://github.com/sinara-hw/Urukul/issues/16 # should both be 2-4 once kasli sync_in jitter is identified From 3ad68f65c51348c834bf094058edd41c3d030ea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 16 Nov 2018 14:56:26 +0000 Subject: [PATCH 1392/2457] urukul: make get_att_mu() not alter state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/urukul.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 8bb514c09..52221a018 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -309,15 +309,17 @@ class CPLD: def get_att_mu(self): """Return the digital step attenuator settings in machine units. - This method will also (as a side effect) write the attenuator - settings of all four channels. - :return: 32 bit attenuator settings """ - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 32, + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT, 32, SPIT_ATT_RD, CS_ATT) - self.bus.write(self.att_reg) - return self.bus.read() + self.bus.write(0) # shift in zeros, shift out current value + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32, + SPIT_ATT_WR, CS_ATT) + delay(10*us) + self.att_reg = self.bus.read() + self.bus.write(self.att_reg) # shift in current value again and latch + return self.att_reg @kernel def set_sync_div(self, div): From 69e699c7bdd16e3df186f8d0cca3806dfb45cf39 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 17 Nov 2018 21:45:45 +0800 Subject: [PATCH 1393/2457] ttl: compensate for SED latency in input gating Closes #1137 --- artiq/coredevice/ttl.py | 18 ++++++--- artiq/test/coredevice/test_rtio.py | 63 ++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index f7bf48bb9..3a56ea74f 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -106,11 +106,19 @@ class TTLInOut: :param channel: channel number """ - kernel_invariants = {"core", "channel"} + kernel_invariants = {"core", "channel", "gate_latency_mu"} - def __init__(self, dmgr, channel, core_device="core"): + def __init__(self, dmgr, channel, gate_latency_mu=None, + core_device="core"): self.core = dmgr.get(core_device) self.channel = channel + # With TTLs inputs, the gate control is connected to a high-latency + # path through SED. When looking at the RTIO counter to determine if + # the gate has closed, we need to take this latency into account. + # See: https://github.com/m-labs/artiq/issues/1137 + if gate_latency_mu is None: + gate_latency_mu = 13*self.core.ref_multiplier + self.gate_latency_mu = gate_latency_mu @kernel def set_oe(self, oe): @@ -323,7 +331,7 @@ class TTLInOut: ttl_input.count(ttl_input.gate_rising(100 * us)) """ count = 0 - while rtio_input_timestamp(up_to_timestamp_mu, self.channel) >= 0: + while rtio_input_timestamp(up_to_timestamp_mu + self.gate_latency_mu, self.channel) >= 0: count += 1 return count @@ -346,7 +354,7 @@ class TTLInOut: :return: The timestamp (in machine units) of the first event received; -1 on timeout. """ - return rtio_input_timestamp(up_to_timestamp_mu, self.channel) + return rtio_input_timestamp(up_to_timestamp_mu + self.gate_latency_mu, self.channel) # Input API: sampling @kernel @@ -414,7 +422,7 @@ class TTLInOut: rtio_output(now_mu(), self.channel, 2, 0) success = True try: - while rtio_input_timestamp(now_mu(), self.channel) != -1: + while rtio_input_timestamp(now_mu() + self.gate_latency_mu, self.channel) != -1: success = False except RTIOOverflow: success = False diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 12f167c1b..b9c7539de 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -206,6 +206,66 @@ class LoopbackCount(EnvExperiment): self.set_dataset("count", self.loop_in.count(now_mu())) +class IncorrectPulseTiming(Exception): + pass + + +class LoopbackGateTiming(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("loop_in") + self.setattr_device("loop_out") + + @kernel + def run(self): + # Make sure there are no leftover events. + self.core.reset() + self.loop_in.input() + self.loop_out.output() + delay_mu(500) + self.loop_out.off() + delay_mu(5000) + + # Determine loop delay. + with parallel: + self.loop_in.gate_rising_mu(10000) + with sequential: + delay_mu(5000) + out_mu = now_mu() + self.loop_out.pulse_mu(1000) + in_mu = self.loop_in.timestamp_mu(now_mu()) + if in_mu < 0: + raise PulseNotReceived("Cannot determine loop delay") + loop_delay_mu = in_mu - out_mu + + # With the exact delay known, make sure tight gate timings work. + # In the most common configuration, 24 mu == 24 ns == 3 coarse periods, + # which should be plenty of slack. + delay_mu(10000) + + gate_start_mu = now_mu() + self.loop_in.gate_both_mu(24) + gate_end_mu = now_mu() + + # gateware latency offset between gate and input + lat_offset = 12*8 + out_mu = gate_start_mu - loop_delay_mu + lat_offset + at_mu(out_mu) + self.loop_out.pulse_mu(24) + + in_mu = self.loop_in.timestamp_mu(gate_end_mu) + if in_mu < 0: + raise PulseNotReceived() + if not (gate_start_mu <= (in_mu - lat_offset) <= gate_end_mu): + raise IncorrectPulseTiming("Input event should occur during gate") + if not (-2 < (in_mu - out_mu - loop_delay_mu) < 2): + raise IncorrectPulseTiming("Loop delay should not change") + + in_mu = self.loop_in.timestamp_mu(gate_end_mu) + if in_mu > 0: + raise IncorrectPulseTiming("Only one pulse should be received") + + class IncorrectLevel(Exception): pass @@ -430,6 +490,9 @@ class CoredeviceTest(ExperimentCase): count = self.dataset_mgr.get("count") self.assertEqual(count, npulses) + def test_loopback_gate_timing(self): + self.execute(LoopbackGateTiming) + def test_level(self): self.execute(Level) From 78d4b3a7da3c7c14283c6ba37b18df251b1d9e89 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 17 Nov 2018 21:47:32 +0800 Subject: [PATCH 1394/2457] gateware/targets: expose variant lists This allows writing scripts that build all variants. --- artiq/gateware/targets/kasli.py | 14 ++++++++------ artiq/gateware/targets/kc705.py | 13 ++++++------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index e232e2296..cee924fdf 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -1123,24 +1123,26 @@ class VLBAISatellite(_SatelliteBase): self.add_rtio(self.rtio_channels) +VARIANTS = {cls.__name__.lower(): cls for cls in [ + Opticlock, SUServo, PTB, PTB2, HUB, LUH, + SYSU, MITLL, MITLL2, USTC, Tsinghua, Tsinghua2, WIPM, NUDT, + VLBAIMaster, VLBAISatellite, Tester, Master, Satellite]} + + def main(): parser = argparse.ArgumentParser( description="ARTIQ device binary builder for Kasli systems") builder_args(parser) soc_kasli_args(parser) parser.set_defaults(output_dir="artiq_kasli") - variants = {cls.__name__.lower(): cls for cls in [ - Opticlock, SUServo, PTB, PTB2, HUB, LUH, - SYSU, MITLL, MITLL2, USTC, Tsinghua, Tsinghua2, WIPM, NUDT, - VLBAIMaster, VLBAISatellite, Tester, Master, Satellite]} parser.add_argument("-V", "--variant", default="opticlock", help="variant: {} (default: %(default)s)".format( - "/".join(sorted(variants.keys())))) + "/".join(sorted(VARIANTS.keys())))) args = parser.parse_args() variant = args.variant.lower() try: - cls = variants[variant] + cls = VARIANTS[variant] except KeyError: raise SystemExit("Invalid variant (-V/--variant)") diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index eb32aedb2..2b9975ec8 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -400,6 +400,9 @@ class SMA_SPI(_StandaloneBase): self.csr_devices.append("rtio_analyzer") +VARIANTS = {cls.__name__.lower(): cls for cls in [NIST_CLOCK, NIST_QC2, SMA_SPI]} + + def main(): parser = argparse.ArgumentParser( description="KC705 gateware and firmware builder") @@ -413,13 +416,9 @@ def main(): args = parser.parse_args() variant = args.variant.lower() - if variant == "nist_clock": - cls = NIST_CLOCK - elif variant == "nist_qc2": - cls = NIST_QC2 - elif variant == "sma_spi": - cls = SMA_SPI - else: + try: + cls = VARIANTS[variant] + except KeyError: raise SystemExit("Invalid variant (-V/--variant)") soc = cls(**soc_kc705_argdict(args)) From a3e0b1c5b4e325d7040a55608603aab9a670e534 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 17 Nov 2018 22:00:49 +0800 Subject: [PATCH 1395/2457] ad9914,spi2: add warnings about driver state and DMA. Closes #1113 --- artiq/coredevice/ad9914.py | 9 +++++++++ artiq/coredevice/spi2.py | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index bd2ec4db0..d37efec8b 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -175,6 +175,10 @@ class AD9914: accumulator is set to the value it would have if the DDS had been running at the specified frequency since the start of the experiment. + + .. warning:: This setting may become inconsistent when used as part of + a DMA recording. When using DMA, it is recommended to specify the + phase mode explicitly when calling :meth:`set` or :meth:`set_mu`. """ self.phase_mode = phase_mode @@ -190,6 +194,11 @@ class AD9914: The "frequency update" pulse is sent to the DDS with a fixed latency with respect to the current position of the time cursor. + When switching from other phase modes to the continuous phase mode, + there is no jump in the DDS phase. This is however not true when + using the continuous phase mode after playing back a DMA sequence + that contained the other phase modes. + :param ftw: frequency to generate. :param pow: adds an offset to the phase. :param phase_mode: if specified, overrides the default phase mode set diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index 205251084..70210841e 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -186,6 +186,12 @@ class SPIMaster: This method is portable and can also be called from e.g. :meth:`__init__`. + .. warning:: If this method is called while recording a DMA + sequence, the playback of the sequence will not update the + driver state. + When required, update the driver state manually (by calling + this method) after playing back a DMA sequence. + :param div: SPI clock divider (see: :meth:`set_config_mu`) :param length: SPI transfer length (see: :meth:`set_config_mu`) """ From b5cdb1c1e0bff04f5918d77c0ac9b343984d38c8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 18 Nov 2018 22:32:17 +0800 Subject: [PATCH 1396/2457] try to work around conda problem From f5befba5c973808ac5150ec062eb9d9be7f2fd36 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 19 Nov 2018 13:24:28 +0800 Subject: [PATCH 1397/2457] conda: bump misoc (attempt to WA conda problem) --- conda/artiq-dev/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 4b596ccd1..5b87fb011 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.8 py35_0+git2d62c0c - - misoc 0.11 py35_33+git128750aa + - misoc 0.11 py35_34+git714ea689 - jesd204b 0.10 - microscope - binutils-or1k-linux >=2.27 From 22a223bf821099a9bf7d4b7dfae61f8344b5625d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 19 Nov 2018 21:42:36 +0800 Subject: [PATCH 1398/2457] examples/master: clean up remnants of early urukul tests --- artiq/examples/master/device_db.py | 192 +---------------------------- 1 file changed, 3 insertions(+), 189 deletions(-) diff --git a/artiq/examples/master/device_db.py b/artiq/examples/master/device_db.py index ad4bc65b6..0d7a2d5e8 100644 --- a/artiq/examples/master/device_db.py +++ b/artiq/examples/master/device_db.py @@ -120,34 +120,6 @@ device_db = { "arguments": {"channel": 26} }, - # FMC DIO used to connect to Zotino - "fmcdio_dirctl_clk": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 27} - }, - "fmcdio_dirctl_ser": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 28} - }, - "fmcdio_dirctl_latch": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 29} - }, - "fmcdio_dirctl": { - "type": "local", - "module": "artiq.coredevice.shiftreg", - "class": "ShiftReg", - "arguments": {"clk": "fmcdio_dirctl_clk", - "ser": "fmcdio_dirctl_ser", - "latch": "fmcdio_dirctl_latch"} - }, - # DAC "spi_ams101": { "type": "local", @@ -161,184 +133,26 @@ device_db = { "class": "TTLOut", "arguments": {"channel": 20} }, - "spi_zotino": { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 30} - }, - "ttl_zotino_ldac": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 31} - }, - "dac_zotino": { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino", - "ldac_device": "ttl_zotino_ldac", - "div_write": 30, - "div_read": 40 - } - }, - - "spi_urukul": { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 32} - }, - "ttl_urukul_io_update": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 33} - }, - "ttl_urukul_sw0": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 35} - }, - "ttl_urukul_sw1": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 36} - }, - "ttl_urukul_sw2": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 37} - }, - "ttl_urukul_sw3": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 38} - }, - "urukul_cpld": { - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul", - "io_update_device": "ttl_urukul_io_update", - "refclk": 100e6 - } - }, - "urukul_ch0a": { - "type": "local", - "module": "artiq.coredevice.ad9912", - "class": "AD9912", - "arguments": { - "pll_n": 10, - "chip_select": 4, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw0" - } - }, - "urukul_ch1a": { - "type": "local", - "module": "artiq.coredevice.ad9912", - "class": "AD9912", - "arguments": { - "pll_n": 10, - "chip_select": 5, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw1" - } - }, - "urukul_ch2a": { - "type": "local", - "module": "artiq.coredevice.ad9912", - "class": "AD9912", - "arguments": { - "pll_n": 10, - "chip_select": 6, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw2" - } - }, - "urukul_ch3a": { - "type": "local", - "module": "artiq.coredevice.ad9912", - "class": "AD9912", - "arguments": { - "pll_n": 10, - "chip_select": 7, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw3" - } - }, - "urukul_ch0b": { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 40, - "chip_select": 4, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw0" - } - }, - "urukul_ch1b": { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 40, - "chip_select": 5, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw1" - } - }, - "urukul_ch2b": { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 40, - "chip_select": 6, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw2" - } - }, - "urukul_ch3b": { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 40, - "chip_select": 7, - "cpld_device": "urukul_cpld", - "sw_device": "ttl_urukul_sw3" - } - }, # AD9914 DDS "ad9914dds0": { "type": "local", "module": "artiq.coredevice.ad9914", "class": "AD9914", - "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 0}, + "arguments": {"sysclk": 3e9, "bus_channel": 27, "channel": 0}, "comment": "Comments work in DDS panel as well" }, "ad9914dds1": { "type": "local", "module": "artiq.coredevice.ad9914", "class": "AD9914", - "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 1} + "arguments": {"sysclk": 3e9, "bus_channel": 27, "channel": 1} }, "ad9914dds2": { "type": "local", "module": "artiq.coredevice.ad9914", "class": "AD9914", - "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 2} + "arguments": {"sysclk": 3e9, "bus_channel": 27, "channel": 2} }, # Aliases From 8f9858be4c93f86774316ef406c40f4be6c28467 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 19 Nov 2018 22:00:20 +0800 Subject: [PATCH 1399/2457] ad9914: remove automatic continuous phase compensation (like Urukul) --- RELEASE_NOTES.rst | 5 +++++ artiq/coredevice/ad9914.py | 20 ++++++++------------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 155b86e2c..37c7f7c20 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -67,6 +67,11 @@ ARTIQ-4 clocks dynamically (i.e. without device restart) is no longer supported. * ``set_dataset(..., save=True)`` has been renamed ``set_dataset(..., archive=True)``. +* On the AD9914 DDS, when switching to ``PHASE_MODE_CONTINUOUS`` from another mode, + use the returned value of the last ``set_mu`` call as the phase offset for + ``PHASE_MODE_CONTINUOUS`` to avoid a phase discontinuity. This is no longer done + automatically. If one phase glitch when entering ``PHASE_MODE_CONTINUOUS`` is not + an issue, this recommendation can be ignored. ARTIQ-3 diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index d37efec8b..f3cd8e1c4 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -80,8 +80,6 @@ class AD9914: self.set_x_duration_mu = 7 * self.write_duration_mu self.exit_x_duration_mu = 3 * self.write_duration_mu - self.continuous_phase_comp = 0 - @kernel def write(self, addr, data): rtio_output(now_mu(), self.bus_channel, addr, data) @@ -194,18 +192,16 @@ class AD9914: The "frequency update" pulse is sent to the DDS with a fixed latency with respect to the current position of the time cursor. - When switching from other phase modes to the continuous phase mode, - there is no jump in the DDS phase. This is however not true when - using the continuous phase mode after playing back a DMA sequence - that contained the other phase modes. - :param ftw: frequency to generate. :param pow: adds an offset to the phase. :param phase_mode: if specified, overrides the default phase mode set by :meth:`set_phase_mode` for this call. :param ref_time: reference time used to compute phase. Specifying this makes it easier to have a well-defined phase relationship between - DDSes on the same bus that are updated at a similar time. + DDSes on the same bus that are updated at a similar time. + :return: Resulting phase offset word after application of phase + tracking offset. When using :const:`PHASE_MODE_CONTINUOUS` in + subsequent calls, use this value as the "current" phase. """ if phase_mode == _PHASE_MODE_DEFAULT: phase_mode = self.phase_mode @@ -224,7 +220,6 @@ class AD9914: # Do not clear phase accumulator on FUD # Disable autoclear phase accumulator and enables OSK. self.write(AD9914_REG_CFR1L, 0x0108) - pow += self.continuous_phase_comp else: # Clear phase accumulator on FUD # Enable autoclear phase accumulator and enables OSK. @@ -233,11 +228,11 @@ class AD9914: pow -= int32((ref_time - fud_time) * self.sysclk_per_mu * ftw >> (32 - 16)) if phase_mode == PHASE_MODE_TRACKING: pow += int32(ref_time * self.sysclk_per_mu * ftw >> (32 - 16)) - self.continuous_phase_comp = pow self.write(AD9914_REG_POW, pow) self.write(AD9914_REG_ASF, asf) self.write(AD9914_FUD, 0) + return pow @portable(flags={"fast-math"}) def frequency_to_ftw(self, frequency): @@ -280,9 +275,10 @@ class AD9914: def set(self, frequency, phase=0.0, phase_mode=_PHASE_MODE_DEFAULT, amplitude=1.0): """Like :meth:`set_mu`, but uses Hz and turns.""" - self.set_mu(self.frequency_to_ftw(frequency), + return self.pow_to_turns( + self.set_mu(self.frequency_to_ftw(frequency), self.turns_to_pow(phase), phase_mode, - self.amplitude_to_asf(amplitude)) + self.amplitude_to_asf(amplitude))) # Extended-resolution functions @kernel From bf50dcf76d9afa4d4943aa237767c129cb1ca2d1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 20 Nov 2018 17:15:53 +0800 Subject: [PATCH 1400/2457] conda: use misoc release --- RELEASE_NOTES.rst | 8 ++++++++ conda/artiq-dev/meta.yaml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 37c7f7c20..b48faa796 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -3,6 +3,14 @@ Release notes ============= +ARTIQ-5 +------- + +5.0 +*** + + + ARTIQ-4 ------- diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 5b87fb011..8212a62c1 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.8 py35_0+git2d62c0c - - misoc 0.11 py35_34+git714ea689 + - misoc 0.12 py35_0+git714ea689 - jesd204b 0.10 - microscope - binutils-or1k-linux >=2.27 From 58ea111b8bc645794a37613cdd5c271c47015d53 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 20 Nov 2018 18:40:12 +0800 Subject: [PATCH 1401/2457] create 5.0.dev From a81c12de947aa09a877efc1bf6840007b71a265f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sun, 25 Nov 2018 16:56:45 +0100 Subject: [PATCH 1402/2457] urukul: work around windows numpy int peculiarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "OverflowError: Python int too large to convert to C long" otherwise opticlock#74 Signed-off-by: Robert Jördens --- artiq/coredevice/urukul.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 52221a018..2371c8f3c 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -1,7 +1,7 @@ from artiq.language.core import kernel, delay, portable, at_mu, now_mu from artiq.language.units import us, ms -from numpy import int32 +from numpy import int32, int64 from artiq.coredevice import spi2 as spi @@ -175,7 +175,7 @@ class CPLD: self.cfg_reg = urukul_cfg(rf_sw=rf_sw, led=0, profile=0, io_update=0, mask_nu=0, clk_sel=clk_sel, sync_sel=sync_sel, rst=0, io_rst=0) - self.att_reg = int32(att) + self.att_reg = int32(int64(att)) self.sync_div = sync_div @kernel From af9ea1f3240477039d89877db430e3feb5c97442 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 26 Nov 2018 01:01:36 +0800 Subject: [PATCH 1403/2457] gui: update background --- artiq/gui/logo_ver.svg | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/artiq/gui/logo_ver.svg b/artiq/gui/logo_ver.svg index e24387b27..43a4dcd3b 100644 --- a/artiq/gui/logo_ver.svg +++ b/artiq/gui/logo_ver.svg @@ -18,11 +18,11 @@ enable-background="new 0 0 800 800" xml:space="preserve" id="svg2" - inkscape:version="0.92.2 5c3e80d, 2017-08-06" + inkscape:version="0.92.3 (2405546, 2018-03-11)" sodipodi:docname="logo_ver.svg">image/svg+xml \ No newline at end of file + aria-label="5" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:96px;line-height:25px;font-family:'Droid Sans Thai';-inkscape-font-specification:'Droid Sans Thai, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:none" + id="text38"> \ No newline at end of file From ae8ef18f47778da6e01cbd10c2c77b6096448ec5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 26 Nov 2018 01:14:02 +0800 Subject: [PATCH 1404/2457] rtlink: sanity-check parameters --- artiq/gateware/rtio/rtlink.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/artiq/gateware/rtio/rtlink.py b/artiq/gateware/rtio/rtlink.py index 66e678412..f1c4e2fe0 100644 --- a/artiq/gateware/rtio/rtlink.py +++ b/artiq/gateware/rtio/rtlink.py @@ -8,6 +8,10 @@ class OInterface: self.stb = Signal() self.busy = Signal() + assert 0 <= data_width <= 512 + assert 0 <= address_width <= 8 + assert 0 <= fine_ts_width <= 4 + if data_width: self.data = Signal(data_width, reset_less=True) if address_width: @@ -35,6 +39,9 @@ class IInterface: timestamped=True, fine_ts_width=0, delay=0): self.stb = Signal() + assert 0 <= data_width <= 32 + assert 0 <= fine_ts_width <= 4 + if data_width: self.data = Signal(data_width, reset_less=True) if fine_ts_width: From 450a035f9ef0dd9637325e04c6e708e97f7bfdb4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 26 Nov 2018 06:54:20 +0800 Subject: [PATCH 1405/2457] suservo: move overflowing RTIO address bits into data --- artiq/coredevice/suservo.py | 9 +++++++-- artiq/gateware/rtio/phy/servo.py | 30 +++++++++++++++++++----------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 2864413ac..96fd1e487 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -129,7 +129,10 @@ class SUServo: :param addr: Memory location address. :param value: Data to be written. """ - rtio_output((self.channel << 8) | addr | WE, value) + addr |= WE + value |= (addr >> 8) << COEFF_WIDTH + addr = addr & 0xff + rtio_output((self.channel << 8) | addr, value) delay_mu(self.ref_period_mu) @kernel @@ -140,7 +143,9 @@ class SUServo: :param addr: Memory location address. """ - rtio_output((self.channel << 8) | addr, 0) + value = (addr >> 8) << COEFF_WIDTH + addr = addr & 0xff + rtio_output((self.channel << 8) | addr, value) return rtio_input_data(self.channel) @kernel diff --git a/artiq/gateware/rtio/phy/servo.py b/artiq/gateware/rtio/phy/servo.py index a4ef729a4..5fb4f57c7 100644 --- a/artiq/gateware/rtio/phy/servo.py +++ b/artiq/gateware/rtio/phy/servo.py @@ -43,11 +43,16 @@ class RTServoMem(Module): # ensure that the DDS word data fits into the coefficient mem assert w.coeff >= w.word + # coeff, profile, channel, 2 mems, rw + # this exceeds the 8-bit RTIO address, so we move the extra ("overflow") + # address bits into data. + internal_address_width = 3 + w.profile + w.channel + 1 + 1 + rtlink_address_width = min(8, internal_address_width) + overflow_address_width = internal_address_width - rtlink_address_width self.rtlink = rtlink.Interface( rtlink.OInterface( - data_width=w.coeff, - # coeff, profile, channel, 2 mems, rw - address_width=3 + w.profile + w.channel + 1 + 1, + data_width=overflow_address_width + w.coeff, + address_width=rtlink_address_width, enable_replace=False), rtlink.IInterface( data_width=w.coeff, @@ -65,30 +70,33 @@ class RTServoMem(Module): [_.clip for _ in servo.iir.ctrl])) ] - assert len(self.rtlink.o.address) == ( + assert len(self.rtlink.o.address) + len(self.rtlink.o.data) - w.coeff == ( 1 + # we 1 + # state_sel 1 + # high_coeff len(m_coeff.adr)) # ensure that we can fit config/status into the state address space - assert len(self.rtlink.o.address) >= ( + assert len(self.rtlink.o.address) + len(self.rtlink.o.data) - w.coeff >= ( 1 + # we 1 + # state_sel 1 + # config_sel len(m_state.adr)) - we = self.rtlink.o.address[-1] - state_sel = self.rtlink.o.address[-2] - config_sel = self.rtlink.o.address[-3] - high_coeff = self.rtlink.o.address[0] + internal_address = Signal(internal_address_width) + self.comb += internal_address.eq(Cat(self.rtlink.o.address, self.rtlink.o.data[w.coeff:])) + + we = internal_address[-1] + state_sel = internal_address[-2] + config_sel = internal_address[-3] + high_coeff = internal_address[0] self.comb += [ self.rtlink.o.busy.eq(0), - m_coeff.adr.eq(self.rtlink.o.address[1:]), + m_coeff.adr.eq(internal_address[1:]), m_coeff.dat_w.eq(Cat(self.rtlink.o.data, self.rtlink.o.data)), m_coeff.we[0].eq(self.rtlink.o.stb & ~high_coeff & we & ~state_sel), m_coeff.we[1].eq(self.rtlink.o.stb & high_coeff & we & ~state_sel), - m_state.adr.eq(self.rtlink.o.address), + m_state.adr.eq(internal_address), m_state.dat_w[w.state - w.coeff:].eq(self.rtlink.o.data), m_state.we.eq(self.rtlink.o.stb & we & state_sel & ~config_sel), ] From 09141e5bee6bce0bdd7eb490b53b789d21a3f2da Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 26 Nov 2018 07:38:06 +0800 Subject: [PATCH 1406/2457] rtio/wishbone: support write-only interface --- artiq/gateware/rtio/phy/wishbone.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/rtio/phy/wishbone.py b/artiq/gateware/rtio/phy/wishbone.py index d8fa752c2..937e66a70 100644 --- a/artiq/gateware/rtio/phy/wishbone.py +++ b/artiq/gateware/rtio/phy/wishbone.py @@ -5,18 +5,18 @@ from artiq.gateware.rtio import rtlink class RT2WB(Module): - def __init__(self, address_width, wb=None, rtio_enable_replace=False): + def __init__(self, address_width, wb=None, rtio_enable_replace=False, write_only=False): if wb is None: wb = wishbone.Interface() self.wb = wb self.rtlink = rtlink.Interface( rtlink.OInterface( len(wb.dat_w), - address_width + 1, + address_width + 1 if not write_only else address_width, enable_replace=rtio_enable_replace), rtlink.IInterface( len(wb.dat_r), - timestamped=False) + timestamped=False) if not write_only else None ) # # # @@ -26,7 +26,7 @@ class RT2WB(Module): If(self.rtlink.o.stb, active.eq(1), wb.adr.eq(self.rtlink.o.address[:address_width]), - wb.we.eq(~self.rtlink.o.address[address_width]), + wb.we.eq(~self.rtlink.o.address[address_width] if not write_only else 1), wb.dat_w.eq(self.rtlink.o.data), wb.sel.eq(2**len(wb.sel) - 1) ), @@ -38,7 +38,10 @@ class RT2WB(Module): self.rtlink.o.busy.eq(active), wb.cyc.eq(active), wb.stb.eq(active), - - self.rtlink.i.stb.eq(wb.ack & ~wb.we), - self.rtlink.i.data.eq(wb.dat_r) ] + + if not write_only: + self.comb += [ + self.rtlink.i.stb.eq(wb.ack & ~wb.we), + self.rtlink.i.data.eq(wb.dat_r) + ] From c56c0ba41f4b3adfb38162191360d5153a110ef9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 26 Nov 2018 07:38:15 +0800 Subject: [PATCH 1407/2457] rtio/dds: use write-only RT2WB This saves one address bit and prevents issues with AD9914 and 8-bit addresses. --- artiq/gateware/rtio/phy/dds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/phy/dds.py b/artiq/gateware/rtio/phy/dds.py index 7e5011bd4..c542937fa 100644 --- a/artiq/gateware/rtio/phy/dds.py +++ b/artiq/gateware/rtio/phy/dds.py @@ -8,7 +8,7 @@ class AD9914(Module): def __init__(self, pads, nchannels, onehot=False, **kwargs): self.submodules._ll = ClockDomainsRenamer("rio_phy")( ad9_dds.AD9_DDS(pads, **kwargs)) - self.submodules._rt2wb = RT2WB(len(pads.a)+1, self._ll.bus) + self.submodules._rt2wb = RT2WB(len(pads.a)+1, self._ll.bus, write_only=True) self.rtlink = self._rt2wb.rtlink self.probes = [Signal(32) for i in range(nchannels)] From 0507101e3192c7ec6d16f8fdab3c6e678feab7b4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 26 Nov 2018 16:50:09 +0800 Subject: [PATCH 1408/2457] manual/drtio: update output internal description (SED, 'destination' switching terminology) --- doc/manual/drtio.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/drtio.rst b/doc/manual/drtio.rst index 199d6ea4d..4f0c98cff 100644 --- a/doc/manual/drtio.rst +++ b/doc/manual/drtio.rst @@ -74,7 +74,7 @@ As part of the DRTIO link initialization, a real-time packet is sent by the core RTIO outputs ++++++++++++ -Controlling a remote RTIO output involves placing the RTIO event into the FIFO of the remote device. The core device maintains a cache of the space available in each channel FIFO of the remote device. If, according to the cache, there is space available, then a packet containing the event information (timestamp, address, channel, data) is sent immediately and the cached value is decremented by one. If, according to the cache, no space is available, then the core device sends a request for the space available in the remote FIFO and updates the cache. The process repeats until at least one FIFO entry is available for the event, at which point a packet containing the event information is sent as before. +Controlling a remote RTIO output involves placing the RTIO event into the buffer of the destination. The core device maintains a cache of the buffer space available in each destination. If, according to the cache, there is space available, then a packet containing the event information (timestamp, address, channel, data) is sent immediately and the cached value is decremented by one. If, according to the cache, no space is available, then the core device sends a request for the space available in the destination and updates the cache. The process repeats until at least one remote buffer entry is available for the event, at which point a packet containing the event information is sent as before. Detecting underflow conditions is the responsibility of the core device; should an underflow occur then no DRTIO packet is transmitted. Sequence errors are handled similarly. From 5c162ed5e658c51cf7b4fb90019f8ffb987ca41f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 26 Nov 2018 17:53:28 +0800 Subject: [PATCH 1409/2457] manual: document usage of DRTIO switching. Closes #1156 --- doc/manual/drtio.rst | 64 +++++++++++++++++++++++++++++++++++++-- doc/manual/installing.rst | 2 ++ doc/manual/utilities.rst | 9 ++++++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/doc/manual/drtio.rst b/doc/manual/drtio.rst index 4f0c98cff..40662e0a2 100644 --- a/doc/manual/drtio.rst +++ b/doc/manual/drtio.rst @@ -22,12 +22,72 @@ The lower layers of DRTIO are similar to White Rabbit, with the following main d From ARTIQ kernels, DRTIO channels are used in the same way as local RTIO channels. +.. _using-drtio: + Using DRTIO ----------- -Remote RTIO channels are accessed in the same was as local ones. Bits 16-24 of the RTIO channel number are used to select between local RTIO channels or one of the connected DRTIO satellites. Bits 0-15 of the RTIO channel number select the channel within one device (local or remote). +Terminology ++++++++++++ -This scheme will be expanded later with the introduction of DRTIO switches. +In a system of interconnected DRTIO devices, each RTIO core (driving RTIO PHYs; for example a RTIO core would connect to a large bank of TTL signals) is assigned a number and is called a *destination*. One DRTIO device normally contains one RTIO core. + +On one DRTIO device, the immediate path that a RTIO request must take is called a *hop*: the request can be sent to the local RTIO core, or to another device downstream. Each possible hop is assigned a number. Hop 0 is normally the local RTIO core, and hops 1 and above correspond to the respective downstream ports of the device. + +DRTIO devices are arranged in a tree topology, with the core device at the root. For each device, its distance from the root (in number of devices that are crossed) is called its *rank*. The root has rank 0, the devices immediately connected to it have rank 1, and so on. + +The routing table ++++++++++++++++++ + +The routing table defines, for each destination, the list of hops ("route") that must be taken from the root in order to reach it. + +It is stored in a binary format that can be manipulated with the :ref:`artiq_route utility `. The binary file is then programmed into the flash storage of the core device under the ``routing_table`` key. It is automatically distributed to downstream devices when the connections are established. Modifying the routing table requires rebooting the core device for the new table to be taken into account. + +All routes must end with the local RTIO core of the last device (0). + +The local RTIO core of the core device is a destination like any other, and it needs to be explicitly part of the routing table for kernels to be able to access it. + +If no routing table is programmed, the core device takes a default routing table for a star topology (i.e. with no devices of rank 2 or above), with destination 0 being the core device's local RTIO core and destinations 1 and above corresponding to devices on the respective downstream ports. + +Here is an example of creating and programming a routing table for a chain of 3 devices: :: + + # create an empty routing table + $ artiq_route rt.bin init + + # set destination 0 to the local RTIO core + $ artiq_route rt.bin set 0 0 + + # for destination 1, first use hop 1 (the first downstream port) + # then use the local RTIO core of that second device. + $ artiq_route rt.bin set 1 1 0 + + # for destination 2, use hop 1 and reach the second device as + # before, then use hop 1 on that device to reach the third + # device, and finally use the local RTIO core (hop 0) of the + # third device. + $ artiq_route rt.bin set 2 1 1 0 + + $ artiq_route rt.bin show + 0: 0 + 1: 1 0 + 2: 1 1 0 + + $ artiq_coremgmt config write -f routing_table rt.bin + +Addressing distributed RTIO cores from kernels +++++++++++++++++++++++++++++++++++++++++++++++ + +Remote RTIO channels are accessed in the same was as local ones. Bits 16-24 of the RTIO channel number define the destination. Bits 0-15 of the RTIO channel number select the channel within the destination. + +Link establishment +++++++++++++++++++ + +After devices have booted, it takes several seconds for all links in a DRTIO system to become established (especially with the long locking times of low-bandwidth PLLs that are used for jitter reduction purposes). Kernels should not attempt to access destinations until all required links are up (when this happens, the ``RTIODestinationUnreachable`` exception is raised). ARTIQ provides the method :meth:`~artiq.coredevice.core.Core.get_rtio_destination_status` that determines whether a destination can be reached. We recommend calling it in a loop in your startup kernel for each important destination, to delay startup until they all can be reached. + +Latency ++++++++ + +Each hop increases the RTIO latency of a destination by a significant amount; that latency is however constant and can be compensated for in kernels. To limit latency in a system, fully utilize the downstream ports of devices to reduce the depth of the tree, instead of creating chains. Internal details ---------------- diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 6745928c7..f16c2a814 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -160,6 +160,8 @@ Configuring the core device This should be done after either installation method (conda or source). +* (optional) If you are using DRTIO and the default routing table (for a star topology) is not suitable to your needs, prepare the routing table and add it to the ``flash_storage.img`` created in the next step. The routing table can be easily changed later, so you can skip this step if you are just getting started and only want to test local channels. See :ref:`Using DRTIO `. + .. _flash-mac-ip-addr: * Set the MAC and IP address in the :ref:`core device configuration flash storage ` (see above for the ``-t`` and ``-m`` options to ``artiq_flash`` that may be required): :: diff --git a/doc/manual/utilities.rst b/doc/manual/utilities.rst index 5bf67bb48..ab31d5d1c 100644 --- a/doc/manual/utilities.rst +++ b/doc/manual/utilities.rst @@ -179,6 +179,15 @@ Core device RTIO analyzer tool .. note:: The RTIO analyzer does not support SAWG. +.. _routing-table-tool: + +DRTIO routing table manipulation tool +------------------------------------- + +.. argparse:: + :ref: artiq.frontend.artiq_route.get_argparser + :prog: artiq_route + Data to InfluxDB bridge ----------------------- From 3fd95b86c21203dd40f1ecb01180907edc8808b0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 26 Nov 2018 17:54:55 +0800 Subject: [PATCH 1410/2457] typo --- doc/manual/drtio.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/drtio.rst b/doc/manual/drtio.rst index 40662e0a2..1b05cf25c 100644 --- a/doc/manual/drtio.rst +++ b/doc/manual/drtio.rst @@ -77,7 +77,7 @@ Here is an example of creating and programming a routing table for a chain of 3 Addressing distributed RTIO cores from kernels ++++++++++++++++++++++++++++++++++++++++++++++ -Remote RTIO channels are accessed in the same was as local ones. Bits 16-24 of the RTIO channel number define the destination. Bits 0-15 of the RTIO channel number select the channel within the destination. +Remote RTIO channels are accessed in the same way as local ones. Bits 16-24 of the RTIO channel number define the destination. Bits 0-15 of the RTIO channel number select the channel within the destination. Link establishment ++++++++++++++++++ From 57caa7b149685585dbc777528d7c86514bcb4874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20K?= Date: Wed, 28 Nov 2018 11:33:32 +0100 Subject: [PATCH 1411/2457] artiq_flash: add command to erase flash memory (#1197) --- artiq/frontend/artiq_flash.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index efcb06168..783bc6264 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -28,6 +28,7 @@ Valid actions: * storage: write storage image to flash * firmware: write firmware to flash * load: load gateware bitstream into device (volatile but fast) + * erase: erase flash memory * start: trigger the target to (re)load its gateware bitstream from flash Prerequisites: @@ -132,6 +133,13 @@ class Programmer: "flash bank {name} jtagspi 0 0 0 0 {tap}.{name}.proxy {ir:#x}", tap=tap, name=name, ir=0x02 + index) + def erase_flash(self, bankname): + self.load_proxy() + add_commands(self._script, + "flash probe {bankname}", + "flash erase_sector {bankname} 0 last", + bankname=bankname) + def load(self, bitfile, pld): os.stat(bitfile) # check for existence @@ -362,6 +370,12 @@ def main(): programmer.load(gateware_bit, 0) elif action == "start": programmer.start() + elif action == "erase": + if args.target == "sayma": + programmer.erase_flash("spi0") + programmer.erase_flash("spi1") + else: + programmer.erase_flash("spi0") else: raise ValueError("invalid action", action) From 156afb48eef15d37d5cb5d0cd7fb1d0f6aec55a9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 30 Nov 2018 17:59:24 +0800 Subject: [PATCH 1412/2457] language: fix syscall arg handling --- artiq/language/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/language/core.py b/artiq/language/core.py index 40b932fb4..fe1a7e814 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -118,7 +118,7 @@ def syscall(arg=None, flags={}): def inner_decorator(function): function.artiq_embedded = \ _ARTIQEmbeddedInfo(core_name=None, portable=False, function=None, - syscall=function.__name__, forbidden=False, + syscall=arg, forbidden=False, flags=set(flags)) return function return inner_decorator From dce4f036db75e0f7380472bc1b0ec8bea977111b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 30 Nov 2018 18:41:14 +0800 Subject: [PATCH 1413/2457] grabber: work around windows numpy int peculiarity (same as a81c12de9) --- artiq/coredevice/grabber.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/grabber.py b/artiq/coredevice/grabber.py index 7a00549db..6f29debe3 100644 --- a/artiq/coredevice/grabber.py +++ b/artiq/coredevice/grabber.py @@ -23,7 +23,7 @@ class Grabber: count_width = min(31, 2*res_width + 16 - count_shift) # This value is inserted by the gateware to mark the start of a series of # ROI engine outputs for one video frame. - self.sentinel = int32(2**count_width) + self.sentinel = int32(int64(2**count_width)) @kernel def setup_roi(self, n, x0, y0, x1, y1): From 7f55376c751fa93510857b88d484307f6503c0b5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 1 Dec 2018 18:06:22 +0800 Subject: [PATCH 1414/2457] test_loopback_gate_timing: print input timing for debugging --- artiq/test/coredevice/test_rtio.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 9dd2e6197..6291a4e60 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -254,6 +254,7 @@ class LoopbackGateTiming(EnvExperiment): self.loop_out.pulse_mu(24) in_mu = self.loop_in.timestamp_mu(gate_end_mu) + print("timings: ", gate_start_mu, in_mu - lat_offset, gate_end_mu) if in_mu < 0: raise PulseNotReceived() if not (gate_start_mu <= (in_mu - lat_offset) <= gate_end_mu): From fd00021a520df7f6e84c6c4e15b1768836f56ebd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 1 Dec 2018 18:06:53 +0800 Subject: [PATCH 1415/2457] ctlmgr: do not raise exceptions in Controllers.__setitem__. Closes #1198 --- artiq/devices/ctlmgr.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/artiq/devices/ctlmgr.py b/artiq/devices/ctlmgr.py index 69dd1b4db..52f203545 100644 --- a/artiq/devices/ctlmgr.py +++ b/artiq/devices/ctlmgr.py @@ -178,13 +178,17 @@ class Controllers: raise ValueError def __setitem__(self, k, v): - if (isinstance(v, dict) and v["type"] == "controller" and - self.host_filter in get_ip_addresses(v["host"])): - v["command"] = v["command"].format(name=k, - bind=self.host_filter, - port=v["port"]) - self.queue.put_nowait(("set", (k, v))) - self.active_or_queued.add(k) + try: + if (isinstance(v, dict) and v["type"] == "controller" and + self.host_filter in get_ip_addresses(v["host"])): + v["command"] = v["command"].format(name=k, + bind=self.host_filter, + port=v["port"]) + self.queue.put_nowait(("set", (k, v))) + self.active_or_queued.add(k) + except: + logger.error("Failed to process device database entry %s", k, + exc_info=True) def __delitem__(self, k): if k in self.active_or_queued: From 7e14f3ca4ee9ef7c2e51b0337a9b41ce45d6053a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Dec 2018 05:06:46 +0800 Subject: [PATCH 1416/2457] compiler,gateware: atomic now stores --- .../compiler/transforms/llvm_ir_generator.py | 26 ++++++++++++------- artiq/gateware/rtio/cri.py | 13 ++++------ conda/artiq-dev/meta.yaml | 2 +- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 2ea7c9e5d..a752f5c51 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -149,10 +149,6 @@ class LLVMIRGenerator: self.tbaa_tree, ll.Constant(lli64, 1) ]) - self.tbaa_now = self.llmodule.add_metadata([ - ll.MetaDataString(self.llmodule, "timeline position"), - self.tbaa_tree - ]) def needs_sret(self, lltyp, may_be_large=True): if isinstance(lltyp, ll.VoidType): @@ -1152,20 +1148,30 @@ class LLVMIRGenerator: return self.map(insn.operands[0]) elif insn.op == "now_mu": llnow = self.llbuilder.load(self.llbuiltin("now"), name=insn.name) - llnow.set_metadata("tbaa", self.tbaa_now) return llnow elif insn.op == "at_mu": time, = insn.operands - return self.llbuilder.store(self.map(time), self.llbuiltin("now")) + lltime = self.map(time) + lltime_hi = self.llbuilder.trunc(self.llbuilder.lshr(lltime, ll.Constant(lli64, 32)), lli32) + lltime_lo = self.llbuilder.trunc(lltime, lli32) + llnow_hiptr = self.llbuilder.bitcast(self.llbuiltin("now"), lli32.as_pointer()) + llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) + llstore_hi = self.llbuilder.store_atomic(lltime_hi, llnow_hiptr, ordering="seq_cst", align=4) + llstore_lo = self.llbuilder.store_atomic(lltime_lo, llnow_loptr, ordering="seq_cst", align=4) + return llstore_lo elif insn.op == "delay_mu": interval, = insn.operands llnowptr = self.llbuiltin("now") llnow = self.llbuilder.load(llnowptr, name="now.old") - llnow.set_metadata("tbaa", self.tbaa_now) lladjusted = self.llbuilder.add(llnow, self.map(interval), name="now.new") - llnowstore = self.llbuilder.store(lladjusted, llnowptr) - llnowstore.set_metadata("tbaa", self.tbaa_now) - return llnowstore + + lladjusted_hi = self.llbuilder.trunc(self.llbuilder.lshr(lladjusted, ll.Constant(lli64, 32)), lli32) + lladjusted_lo = self.llbuilder.trunc(lladjusted, lli32) + llnow_hiptr = self.llbuilder.bitcast(llnowptr, lli32.as_pointer()) + llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) + llstore_hi = self.llbuilder.store_atomic(lladjusted_hi, llnow_hiptr, ordering="seq_cst", align=4) + llstore_lo = self.llbuilder.store_atomic(lladjusted_lo, llnow_loptr, ordering="seq_cst", align=4) + return llstore_lo elif insn.op == "watchdog_set": interval, = insn.operands return self.llbuilder.call(self.llbuiltin("watchdog_set"), [self.map(interval)]) diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index c03c2edc1..72acc879b 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -87,18 +87,15 @@ class KernelInitiator(Module, AutoCSR): # # # - now_lo_backing = Signal(32) + now_hi_backing = Signal(32) now = Signal(64, reset_less=True) self.sync += [ - # TODO: fix compiler and make atomic - #If(self.now_lo.re, now_lo_backing.eq(self.now_lo.r)), - #If(self.now_hi.re, now.eq(Cat(now_lo_backing, self.now_hi.r))) - If(self.now_lo.re, now[:32].eq(self.now_lo.r)), - If(self.now_hi.re, now[32:].eq(self.now_hi.r)) + If(self.now_hi.re, now_hi_backing.eq(self.now_hi.r)), + If(self.now_lo.re, now.eq(Cat(self.now_lo.r, now_hi_backing))) ] self.comb += [ - self.now_lo.w.eq(now[:32]), - self.now_hi.w.eq(now[32:]) + self.now_hi.w.eq(now[32:]), + self.now_lo.w.eq(now[:32]) ] self.comb += [ diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 8212a62c1..1544cebf6 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -20,7 +20,7 @@ requirements: - microscope - binutils-or1k-linux >=2.27 - llvm-or1k 6.0.0 - - llvmlite-artiq 0.23.0.dev py35_4 + - llvmlite-artiq 0.23.0.dev py35_5 - rust-core-or1k 1.28.0 21 - openocd 0.10.0 6 - lit From ad39c76a560bcbe077effad3c870e28a297dbc09 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Dec 2018 06:40:00 +0800 Subject: [PATCH 1417/2457] conda: fix llvmlite dependency --- conda/artiq/meta.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index 3b696aded..548b68f49 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -26,7 +26,7 @@ requirements: - setuptools 33.1.1 run: - python >=3.5.3,<3.6 - - llvmlite-artiq 0.23.0.dev py35_4 + - llvmlite-artiq 0.23.0.dev py35_5 - binutils-or1k-linux >=2.27 - pythonparser >=1.1 - openocd 0.10.0 6 From 2e66788c6c9c310de50914ee7b47d36c69324b74 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Dec 2018 17:40:34 +0800 Subject: [PATCH 1418/2457] compiler: support little endian target when storing now --- artiq/compiler/transforms/llvm_ir_generator.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index a752f5c51..0097ce0bf 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -150,6 +150,9 @@ class LLVMIRGenerator: ll.Constant(lli64, 1) ]) + assert self.llmodule.data_layout[0] in "eE" + self.little_endian = self.llmodule.data_layout[0] == "e" + def needs_sret(self, lltyp, may_be_large=True): if isinstance(lltyp, ll.VoidType): return False @@ -1156,6 +1159,8 @@ class LLVMIRGenerator: lltime_lo = self.llbuilder.trunc(lltime, lli32) llnow_hiptr = self.llbuilder.bitcast(self.llbuiltin("now"), lli32.as_pointer()) llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) + if self.little_endian: + lltime_hi, lltime_lo = lltime_lo, lltime_hi llstore_hi = self.llbuilder.store_atomic(lltime_hi, llnow_hiptr, ordering="seq_cst", align=4) llstore_lo = self.llbuilder.store_atomic(lltime_lo, llnow_loptr, ordering="seq_cst", align=4) return llstore_lo @@ -1169,6 +1174,8 @@ class LLVMIRGenerator: lladjusted_lo = self.llbuilder.trunc(lladjusted, lli32) llnow_hiptr = self.llbuilder.bitcast(llnowptr, lli32.as_pointer()) llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) + if self.little_endian: + lladjusted_hi, lladjusted_lo = lladjusted_lo, lladjusted_hi llstore_hi = self.llbuilder.store_atomic(lladjusted_hi, llnow_hiptr, ordering="seq_cst", align=4) llstore_lo = self.llbuilder.store_atomic(lladjusted_lo, llnow_loptr, ordering="seq_cst", align=4) return llstore_lo From 8940009e1a65a2d5b80e5c3b5e0ab91ddca18ce1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Dec 2018 18:26:19 +0800 Subject: [PATCH 1419/2457] compiler: pass data_layout string to llvm.create_target_data before determining endianness --- artiq/compiler/transforms/llvm_ir_generator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 0097ce0bf..93b1bfc9b 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -150,8 +150,8 @@ class LLVMIRGenerator: ll.Constant(lli64, 1) ]) - assert self.llmodule.data_layout[0] in "eE" - self.little_endian = self.llmodule.data_layout[0] == "e" + assert self.lldatalayout in "eE" + self.little_endian = self.self.lldatalayout[0] == "e" def needs_sret(self, lltyp, may_be_large=True): if isinstance(lltyp, ll.VoidType): From dd03fdfd1a53bf58fe135280828be6a93a401bcb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Dec 2018 18:26:54 +0800 Subject: [PATCH 1420/2457] typo --- artiq/compiler/transforms/llvm_ir_generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 93b1bfc9b..d67d582ad 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -151,7 +151,7 @@ class LLVMIRGenerator: ]) assert self.lldatalayout in "eE" - self.little_endian = self.self.lldatalayout[0] == "e" + self.little_endian = self.lldatalayout[0] == "e" def needs_sret(self, lltyp, may_be_large=True): if isinstance(lltyp, ll.VoidType): From d931967e5c3bb34592c5e7652df7c85e2e9fe90e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Dec 2018 18:32:03 +0800 Subject: [PATCH 1421/2457] fix previous commits --- artiq/compiler/transforms/llvm_ir_generator.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index d67d582ad..fa619d48c 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -150,8 +150,9 @@ class LLVMIRGenerator: ll.Constant(lli64, 1) ]) - assert self.lldatalayout in "eE" - self.little_endian = self.lldatalayout[0] == "e" + data_layout = str(self.lldatalayout) + assert data_layout[0] in "eE" + self.little_endian = data_layout[0] == "e" def needs_sret(self, lltyp, may_be_large=True): if isinstance(lltyp, ll.VoidType): From 981a77834a2d0af95751c1043b80122c45045bf4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Dec 2018 18:52:13 +0800 Subject: [PATCH 1422/2457] compiler: use default triple to determine data_layout for JIT --- artiq/compiler/targets.py | 4 ++++ artiq/compiler/transforms/llvm_ir_generator.py | 8 ++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index 853d6c3eb..5c74e4120 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -239,6 +239,9 @@ class NativeTarget(Target): def __init__(self): super().__init__() self.triple = llvm.get_default_triple() + host_data_layout = str(llvm.targets.Target.from_default_triple().create_target_machine().target_data) + assert host_data_layout[0] in "eE" + self.little_endian = host_data_layout[0] == "e" class OR1KTarget(Target): triple = "or1k-linux" @@ -246,3 +249,4 @@ class OR1KTarget(Target): "f64:32:32-v64:32:32-v128:32:32-a0:0:32-n32" features = ["mul", "div", "ffl1", "cmov", "addc"] print_function = "core_log" + little_endian = False diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index fa619d48c..fdcbe8ab3 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -150,10 +150,6 @@ class LLVMIRGenerator: ll.Constant(lli64, 1) ]) - data_layout = str(self.lldatalayout) - assert data_layout[0] in "eE" - self.little_endian = data_layout[0] == "e" - def needs_sret(self, lltyp, may_be_large=True): if isinstance(lltyp, ll.VoidType): return False @@ -1160,7 +1156,7 @@ class LLVMIRGenerator: lltime_lo = self.llbuilder.trunc(lltime, lli32) llnow_hiptr = self.llbuilder.bitcast(self.llbuiltin("now"), lli32.as_pointer()) llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) - if self.little_endian: + if self.target.little_endian: lltime_hi, lltime_lo = lltime_lo, lltime_hi llstore_hi = self.llbuilder.store_atomic(lltime_hi, llnow_hiptr, ordering="seq_cst", align=4) llstore_lo = self.llbuilder.store_atomic(lltime_lo, llnow_loptr, ordering="seq_cst", align=4) @@ -1175,7 +1171,7 @@ class LLVMIRGenerator: lladjusted_lo = self.llbuilder.trunc(lladjusted, lli32) llnow_hiptr = self.llbuilder.bitcast(llnowptr, lli32.as_pointer()) llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) - if self.little_endian: + if self.target.little_endian: lladjusted_hi, lladjusted_lo = lladjusted_lo, lladjusted_hi llstore_hi = self.llbuilder.store_atomic(lladjusted_hi, llnow_hiptr, ordering="seq_cst", align=4) llstore_lo = self.llbuilder.store_atomic(lladjusted_lo, llnow_loptr, ordering="seq_cst", align=4) From 421834fa3e191759388e1073803a6fcde7fc3022 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Dec 2018 19:07:18 +0800 Subject: [PATCH 1423/2457] compiler: document Target.little_endian --- artiq/compiler/targets.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index 5c74e4120..a10058211 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -75,11 +75,15 @@ class Target: :var print_function: (string) Name of a formatted print functions (with the signature of ``printf``) provided by the target, e.g. ``"printf"``. + :var little_endian: (boolean) + Whether the code will be executed on a little-endian machine. This cannot be always + determined from data_layout due to JIT. """ triple = "unknown" data_layout = "" features = [] print_function = "printf" + little_endian = False def __init__(self): From 6aa341bc4470faa92b66da3e9e46d21e896b9a69 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 2 Dec 2018 20:52:32 +0800 Subject: [PATCH 1424/2457] test_loopback_gate_timing: fix lat_offset --- artiq/test/coredevice/test_rtio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 6291a4e60..11204b4ef 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -248,7 +248,7 @@ class LoopbackGateTiming(EnvExperiment): gate_end_mu = now_mu() # gateware latency offset between gate and input - lat_offset = 12*8 + lat_offset = 11*8 out_mu = gate_start_mu - loop_delay_mu + lat_offset at_mu(out_mu) self.loop_out.pulse_mu(24) From cc143d5fec7a14f9ac0ccd55d066884867070c89 Mon Sep 17 00:00:00 2001 From: Kaifeng Date: Wed, 5 Dec 2018 21:06:45 +0800 Subject: [PATCH 1425/2457] kasli_tester: add support for windows platform. (#1204) --- .../kasli_basic/repository/kasli_tester.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index b47a1e0c6..8cc708d53 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -1,8 +1,12 @@ import sys +import os import select from artiq.experiment import * +if os.name == "nt": + import msvcrt + def chunker(seq, size): res = [] @@ -16,11 +20,17 @@ def chunker(seq, size): def is_enter_pressed() -> TBool: - if select.select([sys.stdin,], [], [], 0.0)[0]: - sys.stdin.read(1) - return True + if os.name == "nt": + if msvcrt.kbhit() and msvcrt.getch() == b"\r": + return True + else: + return False else: - return False + if select.select([sys.stdin, ], [], [], 0.0)[0]: + sys.stdin.read(1) + return True + else: + return False class KasliTester(EnvExperiment): From baf88050fd7f0b80bd7039d0dfd9e73df88c629f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 4 Dec 2018 15:36:24 +0000 Subject: [PATCH 1426/2457] urukul: expand attenuator HITL unittests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * read back with cleared backing state * individual channel settings * check backing state Signed-off-by: Robert Jördens --- artiq/coredevice/urukul.py | 5 ++-- artiq/test/coredevice/test_urukul.py | 36 ++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 2371c8f3c..8c8ee340a 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -138,8 +138,9 @@ class CPLD: :param rf_sw: Initial CPLD RF switch register setting (default: 0x0). Knowledge of this state is not transferred between experiments. :param att: Initial attenuator setting shift register (default: - 0x00000000). See also: :meth:`set_all_att_mu`. Knowledge of this state - is not transferred between experiments. + 0x00000000). See also :meth:`get_att_mu` which retrieves the hardware + state without side effects. Knowledge of this state is not transferred + between experiments. :param sync_div: SYNC_IN generator divider. The ratio between the coarse RTIO frequency and the SYNC_IN generator frequency (default: 2 if `sync_device` was specified). diff --git a/artiq/test/coredevice/test_urukul.py b/artiq/test/coredevice/test_urukul.py index 878b37d32..be43e6641 100644 --- a/artiq/test/coredevice/test_urukul.py +++ b/artiq/test/coredevice/test_urukul.py @@ -69,11 +69,37 @@ class UrukulExp(EnvExperiment): def att(self): self.core.break_realtime() self.dev.init() + # clear backing state + self.dev.att_reg = 0 att_set = 0x12345678 self.dev.set_all_att_mu(att_set) + # confirm that we can set all attenuators and read back att_get = self.dev.get_att_mu() + # confirm backing state + att_reg = self.dev.att_reg self.set_dataset("att_set", att_set) self.set_dataset("att_get", att_get) + self.set_dataset("att_reg", att_reg) + + @kernel + def att_channel(self): + self.core.break_realtime() + self.dev.init() + # clear backing state + self.dev.att_reg = 0 + att_set = int32(0x87654321) + # set individual attenuators + self.dev.set_att_mu(0, 0x21) + self.dev.set_att_mu(1, 0x43) + self.dev.set_att_mu(2, 0x65) + self.dev.set_att_mu(3, 0x87) + # confirm that we can set all attenuators and read back + att_get = self.dev.get_att_mu() + # confirm backing state + att_reg = self.dev.att_reg + self.set_dataset("att_set", att_set) + self.set_dataset("att_get", att_get) + self.set_dataset("att_reg", att_reg) @kernel def att_speed(self): @@ -140,8 +166,14 @@ class UrukulTest(ExperimentCase): def test_att(self): self.execute(UrukulExp, "att") att_set = self.dataset_mgr.get("att_set") - att_get = self.dataset_mgr.get("att_get") - self.assertEqual(att_set, att_get) + self.assertEqual(att_set, self.dataset_mgr.get("att_get")) + self.assertEqual(att_set, self.dataset_mgr.get("att_reg")) + + def test_att_channel(self): + self.execute(UrukulExp, "att_channel") + att_set = self.dataset_mgr.get("att_set") + self.assertEqual(att_set, self.dataset_mgr.get("att_get")) + self.assertEqual(att_set, self.dataset_mgr.get("att_reg")) def test_att_speed(self): self.execute(UrukulExp, "att_speed") From d90eb3ae88b20933d7991fce95ee3f6e58a2592d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 7 Dec 2018 21:27:00 +0000 Subject: [PATCH 1427/2457] ad9910: add read64() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 22 ++++++++++++++++++++++ artiq/test/coredevice/test_ad9910.py | 21 ++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 5d171ac55..00e45f23c 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -181,6 +181,28 @@ class AD9910: self.bus.write(0) return self.bus.read() + @kernel + def read64(self, addr): + """Read from 64 bit register. + + :param addr: Register address + :return: 64 bit integer register value + """ + self.bus.set_config_mu(urukul.SPI_CONFIG, 8, + urukul.SPIT_DDS_WR, self.chip_select) + self.bus.write((addr | 0x80) << 24) + self.bus.set_config_mu( + urukul.SPI_CONFIG | spi.SPI_INPUT, 32, + urukul.SPIT_DDS_RD, self.chip_select) + self.bus.write(0) + self.bus.set_config_mu( + urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 32, + urukul.SPIT_DDS_RD, self.chip_select) + self.bus.write(0) + hi = self.bus.read() + lo = self.bus.read() + return (int64(hi) << 32) | lo + @kernel def write64(self, addr, data_high, data_low): """Write to 64 bit register. diff --git a/artiq/test/coredevice/test_ad9910.py b/artiq/test/coredevice/test_ad9910.py index b5294e80e..923ff4508 100644 --- a/artiq/test/coredevice/test_ad9910.py +++ b/artiq/test/coredevice/test_ad9910.py @@ -1,6 +1,6 @@ from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase -from artiq.coredevice.ad9910 import _AD9910_REG_FTW +from artiq.coredevice.ad9910 import _AD9910_REG_FTW, _AD9910_REG_PROFILE0 from artiq.coredevice.urukul import ( urukul_sta_smp_err, CFG_CLK_SEL0, CFG_CLK_SEL1) @@ -46,6 +46,19 @@ class AD9910Exp(EnvExperiment): self.set_dataset("ftw_set", self.dev.frequency_to_ftw(f)) self.set_dataset("ftw_get", self.dev.read32(_AD9910_REG_FTW)) + @kernel + def read_write64(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + lo = 0x12345678 + hi = 0x09abcdef + self.dev.write64(_AD9910_REG_PROFILE0, hi, lo) + self.dev.cpld.io_update.pulse_mu(8) + read = self.dev.read64(_AD9910_REG_PROFILE0) + self.set_dataset("write", (int64(hi) << 32) | lo) + self.set_dataset("read", read) + @kernel def set_speed(self): self.core.break_realtime() @@ -170,6 +183,12 @@ class AD9910Test(ExperimentCase): ftw_set = self.dataset_mgr.get("ftw_set") self.assertEqual(ftw_get, ftw_set) + def test_read_write64(self): + self.execute(AD9910Exp, "read_write64") + write = self.dataset_mgr.get("write") + read = self.dataset_mgr.get("read") + self.assertEqual(hex(write), hex(read)) + def test_set_speed(self): self.execute(AD9910Exp, "set_speed") dt = self.dataset_mgr.get("dt") From d4c393b2a8b1b30debab5b02b60cb3f5a6787219 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 11 Dec 2018 01:21:24 +0000 Subject: [PATCH 1428/2457] firmware/ksupport: Update `cfg(not(has_rtio))` stub signatures This fixes up 8caea0e6d3a91e625f84172e455229920dca930f, but it is unclear whether anyone even uses a `not(has_rtio)` configuration at this point. --- artiq/firmware/ksupport/rtio.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index 338dbcbdc..27e893a97 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -184,15 +184,19 @@ mod imp { unimplemented!("not(has_rtio)") } + pub extern fn get_destination_status(_destination: i32) -> bool { + unimplemented!("not(has_rtio)") + } + pub extern fn get_counter() -> i64 { unimplemented!("not(has_rtio)") } - pub extern fn output(_timestamp: i64, _channel: i32, _addr: i32, _data: i32) { + pub extern fn output(_target: i32, _data: i32) { unimplemented!("not(has_rtio)") } - pub extern fn output_wide(_timestamp: i64, _channel: i32, _addr: i32, _data: CSlice) { + pub extern fn output_wide(_target: i32, _data: CSlice) { unimplemented!("not(has_rtio)") } @@ -204,7 +208,7 @@ mod imp { unimplemented!("not(has_rtio)") } - pub fn log(_timestamp: i64, _data: &[u8]) { + pub fn log(_data: &[u8]) { unimplemented!("not(has_rtio)") } } From efd400b02c2e9235300c5d3c8265ee50884603b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 11 Dec 2018 09:15:25 +0000 Subject: [PATCH 1429/2457] ad9910: style [nfc] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 00e45f23c..2c35d3214 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -109,7 +109,7 @@ class AD9910: @kernel def set_phase_mode(self, phase_mode): - """Set the default phase mode. + r"""Set the default phase mode. for future calls to :meth:`set` and :meth:`set_mu`. Supported phase modes are: @@ -188,7 +188,8 @@ class AD9910: :param addr: Register address :return: 64 bit integer register value """ - self.bus.set_config_mu(urukul.SPI_CONFIG, 8, + self.bus.set_config_mu( + urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select) self.bus.write((addr | 0x80) << 24) self.bus.set_config_mu( From 6df4ae934f07e57f6e61be1bafacf91179b40b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 11 Dec 2018 10:34:01 +0000 Subject: [PATCH 1430/2457] eem: name the servo submodule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows the migen namer to derive names for the ADC return clock domain in the case of multiple SUServos close #1201 Signed-off-by: Robert Jördens --- artiq/gateware/eem.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 56f9cb25e..a63d82005 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -493,6 +493,7 @@ class SUServo(_EEM): sampler_pads = servo_pads.SamplerPads(target.platform, eem_sampler) urukul_pads = servo_pads.UrukulPads( target.platform, eem_urukul0, eem_urukul1) + target.submodules += sampler_pads, urukul_pads # timings in units of RTIO coarse period adc_p = servo.ADCParams(width=16, channels=8, lanes=4, t_cnvh=4, # account for SCK DDR to CONV latency @@ -505,7 +506,9 @@ class SUServo(_EEM): channels=adc_p.channels, clk=clk) su = servo.Servo(sampler_pads, urukul_pads, adc_p, iir_p, dds_p) su = ClockDomainsRenamer("rio_phy")(su) - target.submodules += sampler_pads, urukul_pads, su + # explicitly name the servo submodule to enable the migen namer to derive + # a name for the adc return clock domain + setattr(target.submodules, "suservo_eem{}".format(eems_sampler[0]), su) ctrls = [rtservo.RTServoCtrl(ctrl) for ctrl in su.iir.ctrl] target.submodules += ctrls From 79eadb9465f601b4d0d3d6d81afb940994e51873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 10 Dec 2018 10:56:06 +0000 Subject: [PATCH 1431/2457] ad9910: add RAM mode methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * also refactor the CFR1 access into a method c.f. #1154 Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 177 +++++++++++++++++++++++++++++++++---- 1 file changed, 158 insertions(+), 19 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 2c35d3214..04315607b 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -13,7 +13,10 @@ urukul_sta_smp_err = urukul.urukul_sta_smp_err __all__ = [ "AD9910", - "PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE", "PHASE_MODE_TRACKING" + "PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE", "PHASE_MODE_TRACKING", + "RAM_DEST_FTW", "RAM_DEST_POW", "RAM_DEST_ASF", "RAM_DEST_POWASF", + "RAM_MODE_DIRECTSWITCH", "RAM_MODE_RAMPUP", "RAM_MODE_BIDIR_RAMP", + "RAM_MODE_CONT_BIDIR_RAMP", "RAM_MODE_CONT_RECIRCULATE", ] @@ -44,6 +47,19 @@ _AD9910_REG_PROFILE6 = 0x14 _AD9910_REG_PROFILE7 = 0x15 _AD9910_REG_RAM = 0x16 +# RAM destination +RAM_DEST_FTW = 0 +RAM_DEST_POW = 1 +RAM_DEST_ASF = 2 +RAM_DEST_POWASF = 3 + +# RAM MODES +RAM_MODE_DIRECTSWITCH = 0 +RAM_MODE_RAMPUP = 1 +RAM_MODE_BIDIR_RAMP = 2 +RAM_MODE_CONT_BIDIR_RAMP = 3 +RAM_MODE_CONT_RECIRCULATE = 4 + class AD9910: """ @@ -222,6 +238,82 @@ class AD9910: urukul.SPIT_DDS_WR, self.chip_select) self.bus.write(data_low) + @kernel + def write_ram(self, data): + """Write data to RAM. + + The profile to write to and the step, start, and end address + need to be configured before and separately using + :meth:`set_profile_ram` and the parent CPLD `set_profile`. + + :param data List(int32): Data to be written to RAM. + """ + self.bus.set_config_mu(urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, + self.chip_select) + self.bus.write(_AD9910_REG_RAM << 24) + self.bus.set_config_mu(urukul.SPI_CONFIG, 32, + urukul.SPIT_DDS_WR, self.chip_select) + for i in range(len(data) - 1): + self.bus.write(data[i]) + self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32, + urukul.SPIT_DDS_WR, self.chip_select) + self.bus.write(data[len(data) - 1]) + + @kernel + def read_ram(self, data): + """Read data from RAM. + + The profile to read from and the step, start, and end address + need to be configured before and separately using + :meth:`set_profile_ram` and the parent CPLD `set_profile`. + + :param data List(int32): List to be filled with data read from RAM. + """ + self.bus.set_config_mu(urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, + self.chip_select) + self.bus.write((_AD9910_REG_RAM | 0x80) << 24) + self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_INPUT, 32, + urukul.SPIT_DDS_RD, self.chip_select) + preload = 8 + for i in range(len(data) - 1): + self.bus.write(0) + if i >= preload: + data[i - preload] = self.bus.read() + self.bus.set_config_mu( + urukul.SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, 32, + urukul.SPIT_DDS_RD, self.chip_select) + self.bus.write(0) + for i in range(preload + 1): + data[(len(data) - preload - 1) + i] = self.bus.read() + + @kernel + def set_cfr1(self, power_down=0b0000, phase_autoclear=0, + drg_load_lrr=0, drg_autoclear=0, + internal_profile=0, ram_destination=0, ram_enable=0): + """Set CFR1. See the AD9910 datasheet for parameter meanings. + + This method does not pulse IO_UPDATE. + + :param power_down: Power down bits. + :param phase_autoclear: Autoclear phase accumulator. + :param drg_load_lrr: Load digital ramp generator LRR. + :param drg_autoclear: Autoclear digital ramp generator. + :param internal_profile: Internal profile control. + :param ram_destination: RAM destination + (:const:`_AD9910_RAM_DEST_FTW`, :const:`_AD9910_RAM_DEST_POW`, + :const:`_AD9910_RAM_DEST_ASF`, :const:`_AD9910_RAM_DEST_POWASF`). + :param ram_enable: RAM mode enable. + """ + self.write32(_AD9910_REG_CFR1, + (ram_enable << 31) | + (ram_destination << 29) | + (internal_profile << 17) | + (drg_load_lrr << 15) | + (drg_autoclear << 14) | + (phase_autoclear << 13) | + (power_down << 4) | + 2) # SDIO input only, MSB first + @kernel def init(self, blind=False): """Initialize and configure the DDS. @@ -233,7 +325,7 @@ class AD9910: :param blind: Do not read back DDS identity and do not wait for lock. """ # Set SPI mode - self.write32(_AD9910_REG_CFR1, 0x00000002) + self.set_cfr1() self.cpld.io_update.pulse(1*us) delay(1*ms) if not blind: @@ -274,13 +366,13 @@ class AD9910: def power_down(self, bits=0b1111): """Power down DDS. - :param bits: power down bits, see datasheet + :param bits: Power down bits, see datasheet """ - self.write32(_AD9910_REG_CFR1, 0x00000002 | (bits << 4)) + self.set_cfr1(power_down=bits) self.cpld.io_update.pulse(1*us) @kernel - def set_mu(self, ftw, pow=0, asf=0x3fff, phase_mode=_PHASE_MODE_DEFAULT, + def set_mu(self, ftw, pow_=0, asf=0x3fff, phase_mode=_PHASE_MODE_DEFAULT, ref_time=-1, profile=0): """Set profile 0 data in machine units. @@ -295,7 +387,7 @@ class AD9910: phase modes. :param ftw: Frequency tuning word: 32 bit. - :param pow: Phase tuning word: 16 bit unsigned. + :param pow_: Phase tuning word: 16 bit unsigned. :param asf: Amplitude scale factor: 14 bit unsigned. :param phase_mode: If specified, overrides the default phase mode set by :meth:`set_phase_mode` for this call. @@ -313,7 +405,7 @@ class AD9910: if phase_mode != PHASE_MODE_CONTINUOUS: # Auto-clear phase accumulator on IO_UPDATE. # This is active already for the next IO_UPDATE - self.write32(_AD9910_REG_CFR1, 0x00002002) + self.set_cfr1(phase_autoclear=1) if phase_mode == PHASE_MODE_TRACKING and ref_time < 0: # set default fiducial time stamp ref_time = 0 @@ -322,15 +414,51 @@ class AD9910: # Also no need to use IO_UPDATE time as this # is equivalent to an output pipeline latency. dt = int32(now_mu()) - int32(ref_time) - pow += dt*ftw*self.sysclk_per_mu >> 16 - self.write64(_AD9910_REG_PROFILE0 + profile, (asf << 16) | pow, ftw) + pow_ += dt*ftw*self.sysclk_per_mu >> 16 + self.write64(_AD9910_REG_PROFILE0 + profile, (asf << 16) | pow_, ftw) delay_mu(int64(self.io_update_delay)) self.cpld.io_update.pulse_mu(8) # assumes 8 mu > t_SYSCLK at_mu(now_mu() & ~0xf) if phase_mode != PHASE_MODE_CONTINUOUS: - self.write32(_AD9910_REG_CFR1, 0x00000002) + self.set_cfr1() # future IO_UPDATE will activate - return pow + return pow_ + + @kernel + def set_profile_ram(self, start, end, step=1, profile=0, nodwell_high=0, + zero_crossing=0, mode=1): + """Set the RAM profile settings. + + :param start: Profile start address in RAM. + :param end: Profile end address in RAM (last address). + :param step: Profile address step size (default: 1). + :param profile: Profile index (0 to 7) (default: 0). + :param nodwell_high: No-dwell high bit (default: 0, + see AD9910 documentation). + :param zero_crossing: Zero crossing bit (default: 0, + see AD9910 documentation). + :param mode: Profile RAM mode (:const:`RAM_MODE_DIRECTSWITCH`, + :const:`RAM_MODE_RAMPUP`, :const:`RAM_MODE_BIDIR_RAMP`, + :const:`RAM_MODE_CONT_BIDIR_RAMP`, or + :const:`RAM_MODE_CONT_RECIRCULATE`, default: + :const:`RAM_MODE_RAMPUP`) + """ + hi = (step << 8) | (end >> 2) + lo = ((end << 30) | (start << 14) | (nodwell_high << 5) | + (zero_crossing << 3) | mode) + self.write64(_AD9910_REG_PROFILE0 + profile, hi, lo) + + @kernel + def set_ftw(self, ftw): + self.write32(_AD9910_REG_FTW, ftw) + + @kernel + def set_asf(self, asf): + self.write32(_AD9910_REG_ASF, asf) + + @kernel + def set_pow(self, pow_): + self.write32(_AD9910_REG_POW, pow_) @portable(flags={"fast-math"}) def frequency_to_ftw(self, frequency): @@ -351,10 +479,22 @@ class AD9910: return int32(round(amplitude*0x3ffe)) @portable(flags={"fast-math"}) - def pow_to_turns(self, pow): + def pow_to_turns(self, pow_): """Return the phase in turns corresponding to a given phase offset word.""" - return pow/0x10000 + return pow_/0x10000 + + @kernel + def set_frequency(self, frequency): + return self.set_ftw(self.frequency_to_ftw(frequency)) + + @kernel + def set_amplitude(self, amplitude): + return self.set_asf(self.amplitude_to_asf(amplitude)) + + @kernel + def set_phase(self, turns): + return self.set_pow(self.turns_to_pow(turns)) @kernel def set(self, frequency, phase=0.0, amplitude=1.0, @@ -363,9 +503,9 @@ class AD9910: .. seealso:: :meth:`set_mu` - :param ftw: Frequency in Hz - :param pow: Phase tuning word in turns - :param asf: Amplitude in units of full scale + :param frequency: Frequency in Hz + :param phase: Phase tuning word in turns + :param amplitude: Amplitude in units of full scale :param phase_mode: Phase mode constant :param ref_time: Fiducial time stamp in machine units :param profile: Profile to affect @@ -509,8 +649,7 @@ class AD9910: :return: Odd/even SYNC_CLK cycle indicator. """ # set up DRG - # DRG ACC autoclear and LRR on io update - self.write32(_AD9910_REG_CFR1, 0x0000c002) + self.set_cfr1(drg_load_lrr=1, drg_autoclear=1) # DRG -> FTW, DRG enable self.write32(_AD9910_REG_CFR2, 0x01090000) # no limits @@ -524,7 +663,7 @@ class AD9910: at_mu(t + delay_start) self.cpld.io_update.pulse_mu(32 - delay_start) # realign # disable DRG autoclear and LRR on io_update - self.write32(_AD9910_REG_CFR1, 0x00000002) + self.set_cfr1() # stop DRG self.write64(_AD9910_REG_RAMP_STEP, 0, 0) at_mu(t + 0x1000 + delay_stop) From 73941d46616598e3c326a93c4fa60684d5d8741f Mon Sep 17 00:00:00 2001 From: Joachim Schiele Date: Wed, 12 Dec 2018 23:24:55 +0100 Subject: [PATCH 1432/2457] nix: add rustc, migen and misoc This allows firmware compilation. --- nix/default.nix | 28 +-- nix/llvm-or1k.nix | 1 - nix/pkgs/python3Packages.nix | 113 ++++++++++ nix/pkgs/rust/binaryBuild.nix | 117 ++++++++++ nix/pkgs/rust/bootstrap.nix | 42 ++++ nix/pkgs/rust/cargo.nix | 70 ++++++ nix/pkgs/rust/default.nix | 90 ++++++++ .../patches/disable-test-inherit-env.patch | 10 + .../rust/patches/net-tcp-disable-tests.patch | 104 +++++++++ .../patches/stdsimd-disable-doctest.patch | 20 ++ nix/pkgs/rust/print-hashes.sh | 38 ++++ nix/pkgs/rust/rust-src.nix | 11 + nix/pkgs/rust/rustc.nix | 199 ++++++++++++++++++ nix/shell.nix | 27 ++- 14 files changed, 849 insertions(+), 21 deletions(-) create mode 100644 nix/pkgs/python3Packages.nix create mode 100644 nix/pkgs/rust/binaryBuild.nix create mode 100644 nix/pkgs/rust/bootstrap.nix create mode 100644 nix/pkgs/rust/cargo.nix create mode 100644 nix/pkgs/rust/default.nix create mode 100644 nix/pkgs/rust/patches/disable-test-inherit-env.patch create mode 100644 nix/pkgs/rust/patches/net-tcp-disable-tests.patch create mode 100644 nix/pkgs/rust/patches/stdsimd-disable-doctest.patch create mode 100755 nix/pkgs/rust/print-hashes.sh create mode 100644 nix/pkgs/rust/rust-src.nix create mode 100644 nix/pkgs/rust/rustc.nix diff --git a/nix/default.nix b/nix/default.nix index b536227ba..f06b6d289 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -1,15 +1,17 @@ -{system ? builtins.currentSystem}: +{ pkgs ? import {}}: +with pkgs; let - pkgs = import {inherit system;}; - callPackage = pkgs.lib.callPackageWith (pkgs // self ); - -self = { - binutils-or1k = callPackage ./binutils-or1k.nix {}; + # this code was copied from nipxkgs rev. ffafe9 (nixcloud team) and slightly modified + rust = callPackage ./pkgs/rust + (stdenv.lib.optionalAttrs (stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { + stdenv = overrideCC stdenv gcc6; # with gcc-7: undefined reference to `__divmoddi4' + }); llvm-src = callPackage ./fetch-llvm-clang.nix {}; - llvm-or1k = callPackage ./llvm-or1k.nix {}; - llvmlite = callPackage ./llvmlite.nix {}; - artiq = callPackage ./artiq.nix { }; -}; -artiq = self.artiq; -in -artiq +in rec { + inherit (rust) cargo rustc; + inherit (callPackage ./pkgs/python3Packages.nix {}) migen misoc; + binutils-or1k = callPackage ./binutils-or1k.nix {}; + llvm-or1k = callPackage ./llvm-or1k.nix { inherit llvm-src; }; + llvmlite = callPackage ./llvmlite.nix { inherit llvm-or1k; }; + #artiq = callPackage ./artiq.nix { inherit binutils-or1k; }; +} diff --git a/nix/llvm-or1k.nix b/nix/llvm-or1k.nix index 403e95fd3..622e12f70 100644 --- a/nix/llvm-or1k.nix +++ b/nix/llvm-or1k.nix @@ -43,4 +43,3 @@ stdenv.mkDerivation rec { platforms = stdenv.lib.platforms.all; }; } - diff --git a/nix/pkgs/python3Packages.nix b/nix/pkgs/python3Packages.nix new file mode 100644 index 000000000..0396772f6 --- /dev/null +++ b/nix/pkgs/python3Packages.nix @@ -0,0 +1,113 @@ +{ pkgs, stdenv, fetchFromGitHub, python, python3Packages }: + +rec { + asyncserial = python3Packages.buildPythonPackage rec { + version = "git-09a9fc"; + pname = "asyncserial"; + name = "${pname}-${version}"; + + src = fetchFromGitHub { + owner = "m-labs"; + repo = "asyncserial"; + rev = "d95bc1d6c791b0e9785935d2f62f628eb5cdf98d"; + sha256 = "0yzkka9jk3612v8gx748x6ziwykq5lr7zmr9wzkcls0v2yilqx9k"; + fetchSubmodules = true; + }; + + propagatedBuildInputs = with python3Packages; [ pyserial ] ++ (with pkgs; [ ]); + + meta = with stdenv.lib; { + description = "asyncio support for pyserial"; + homepage = "https://m-labs.hk/gateware.html"; + license = licenses.bsd2; + platforms = platforms.unix; + }; + }; + misoc = python3Packages.buildPythonPackage rec { + version = "git-714ea6"; + pname = "misoc"; + name = "${pname}-${version}"; + + # you can use the src definition to point to your local git checkout (don't forget the submodules) so + # hacking is easier! + #src = /home/bar/misoc; + + # instead of this (nixcloud team) + src = fetchFromGitHub { + owner = "m-labs"; + repo = "misoc"; + rev = "308b4728bdb1900fe3c9d71c10cc84322ad3e4ed"; + sha256 = "0fc1axrwjhb86m2dwkj6h3qwwci9xw0jsvg8pzb2r8hci2v8432h"; + fetchSubmodules = true; + }; + + # there are still so many tests failing (nixcloud team) + # ====================================================================== + # ERROR: framebuffer (unittest.loader._FailedTest) + # ---------------------------------------------------------------------- + # ImportError: Failed to import test module: framebuffer + # Traceback (most recent call last): + # File "/nix/store/bwfygfcdvis9wd1c1v51xwnwhw1hx0a0-python3-3.6.6/lib/python3.6/unittest/loader.py", line 153, in loadTestsFromName + # module = __import__(module_name) + # File "/build/source/misoc/cores/framebuffer/__init__.py", line 1, in + # from misoc.cores.framebuffer.core import Framebuffer + # File "/build/source/misoc/cores/framebuffer/core.py", line 2, in + # from migen.flow.network import * + # ModuleNotFoundError: No module named 'migen.flow' + # + # + # watch for these messages: + # writing manifest file 'misoc.egg-info/SOURCES.txt' + # running build_ext + # /nix/store/w7cmmmzafv81wwhkadpar6vdvbqphzdf-python3.6-bootstrapped-pip-18.1/lib/python3.6/site-packages/setuptools/dist.py:398: UserWarning: Normalizing '0.6.dev' to '0.6.dev0' + # normalized_version, + # debug (unittest.loader._FailedTest) + # Run the test without collecting errors in a TestResult ... ERROR + # framebuffer (unittest.loader._FailedTest) ... ERROR + # sdram_model (unittest.loader._FailedTest) ... ERROR + # test (unittest.loader._FailedTest) ... ERROR + # test_df (unittest.loader._FailedTest) ... ERROR + # test_wb (unittest.loader._FailedTest) ... ERROR + # test_refresher (unittest.loader._FailedTest) ... ERROR + # test_common (unittest.loader._FailedTest) ... ERROR + # test_lasmi (unittest.loader._FailedTest) ... ERROR + # test_bankmachine (unittest.loader._FailedTest) ... ERROR + # + # you can disable the tests (which is a bad idea, fix them instead) + # doCheck = false; + + propagatedBuildInputs = with python3Packages; [ pyserial jinja2 numpy asyncserial migen ]; + + meta = with stdenv.lib; { + description = "A high performance and small footprint system-on-chip based on Migen https://m-labs.hk"; + homepage = "https://m-labs.hk/gateware.html"; + license = licenses.bsd2; + platforms = platforms.unix; + }; + }; + migen = python3Packages.buildPythonPackage rec { + version = "git-3d8a58"; + pname = "migen"; + name = "${pname}-${version}"; + + src = fetchFromGitHub { + owner = "m-labs"; + repo = "migen"; + rev = "3d8a58033ea0e90e435db0d14c25c86ee7d2fee2"; + sha256 = "0fw70bzang79wylwsw9b47vssjnhx6mwzm00dg3b49iyg57jymvh"; + fetchSubmodules = true; + }; + + # FileNotFoundError: [Errno 2] No such file or directory: '/usr/local/diamond' (nixcloud team) + doCheck = false; + + propagatedBuildInputs = with python3Packages; [ colorama sphinx sphinx_rtd_theme ] ++ (with pkgs; [ verilator ]); + + meta = with stdenv.lib; { + description = "A Python toolbox for building complex digital hardware"; + homepage = "https://m-labs.hk/gateware.html"; + license = licenses.bsd2; + platforms = platforms.unix; + }; + }; +} diff --git a/nix/pkgs/rust/binaryBuild.nix b/nix/pkgs/rust/binaryBuild.nix new file mode 100644 index 000000000..488d43a6f --- /dev/null +++ b/nix/pkgs/rust/binaryBuild.nix @@ -0,0 +1,117 @@ +{ stdenv, makeWrapper, bash, buildRustPackage, curl, darwin +, version +, src +, platform +, versionType +}: + +let + inherit (stdenv.lib) optionalString; + inherit (darwin.apple_sdk.frameworks) Security; + + bootstrapping = versionType == "bootstrap"; + + installComponents + = "rustc,rust-std-${platform}" + + (optionalString bootstrapping ",cargo") + ; +in + +rec { + inherit buildRustPackage; + + rustc = stdenv.mkDerivation rec { + name = "rustc-${versionType}-${version}"; + + inherit version; + inherit src; + + meta = with stdenv.lib; { + homepage = http://www.rust-lang.org/; + description = "A safe, concurrent, practical language"; + maintainers = with maintainers; [ qknight ]; + license = [ licenses.mit licenses.asl20 ]; + }; + + buildInputs = [ bash ] ++ stdenv.lib.optional stdenv.isDarwin Security; + + postPatch = '' + patchShebangs . + ''; + + installPhase = '' + ./install.sh --prefix=$out \ + --components=${installComponents} + + ${optionalString (stdenv.isLinux && bootstrapping) '' + patchelf \ + --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) \ + "$out/bin/rustc" + patchelf \ + --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) \ + "$out/bin/rustdoc" + patchelf \ + --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) \ + "$out/bin/cargo" + ''} + + ${optionalString (stdenv.isDarwin && bootstrapping) '' + install_name_tool -change /usr/lib/libresolv.9.dylib '${darwin.libresolv}/lib/libresolv.9.dylib' "$out/bin/rustc" + install_name_tool -change /usr/lib/libresolv.9.dylib '${darwin.libresolv}/lib/libresolv.9.dylib' "$out/bin/rustdoc" + install_name_tool -change /usr/lib/libiconv.2.dylib '${darwin.libiconv}/lib/libiconv.2.dylib' "$out/bin/cargo" + install_name_tool -change /usr/lib/libresolv.9.dylib '${darwin.libresolv}/lib/libresolv.9.dylib' "$out/bin/cargo" + install_name_tool -change /usr/lib/libcurl.4.dylib '${stdenv.lib.getLib curl}/lib/libcurl.4.dylib' "$out/bin/cargo" + for f in $out/lib/lib*.dylib; do + install_name_tool -change /usr/lib/libresolv.9.dylib '${darwin.libresolv}/lib/libresolv.9.dylib' "$f" + done + ''} + + # Do NOT, I repeat, DO NOT use `wrapProgram` on $out/bin/rustc + # (or similar) here. It causes strange effects where rustc loads + # the wrong libraries in a bootstrap-build causing failures that + # are very hard to track down. For details, see + # https://github.com/rust-lang/rust/issues/34722#issuecomment-232164943 + ''; + }; + + cargo = stdenv.mkDerivation rec { + name = "cargo-${versionType}-${version}"; + + inherit version; + inherit src; + + meta = with stdenv.lib; { + homepage = http://www.rust-lang.org/; + description = "A safe, concurrent, practical language"; + maintainers = with maintainers; [ qknight ]; + license = [ licenses.mit licenses.asl20 ]; + }; + + buildInputs = [ makeWrapper bash ] ++ stdenv.lib.optional stdenv.isDarwin Security; + + postPatch = '' + patchShebangs . + ''; + + installPhase = '' + patchShebangs ./install.sh + ./install.sh --prefix=$out \ + --components=cargo + + ${optionalString (stdenv.isLinux && bootstrapping) '' + patchelf \ + --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) \ + "$out/bin/cargo" + ''} + + ${optionalString (stdenv.isDarwin && bootstrapping) '' + install_name_tool -change /usr/lib/libiconv.2.dylib '${darwin.libiconv}/lib/libiconv.2.dylib' "$out/bin/cargo" + install_name_tool -change /usr/lib/libresolv.9.dylib '${darwin.libresolv}/lib/libresolv.9.dylib' "$out/bin/cargo" + install_name_tool -change /usr/lib/libcurl.4.dylib '${stdenv.lib.getLib curl}/lib/libcurl.4.dylib' "$out/bin/cargo" + ''} + + wrapProgram "$out/bin/cargo" \ + --suffix PATH : "${rustc}/bin" + ''; + }; +} diff --git a/nix/pkgs/rust/bootstrap.nix b/nix/pkgs/rust/bootstrap.nix new file mode 100644 index 000000000..55348c579 --- /dev/null +++ b/nix/pkgs/rust/bootstrap.nix @@ -0,0 +1,42 @@ +{ stdenv, fetchurl, callPackage }: + +let + # Note: the version MUST be one version prior to the version we're + # building + version = "1.28.0"; + + # fetch hashes by running `print-hashes.sh 1.24.1` + hashes = { + i686-unknown-linux-gnu = "de7cdb4e665e897ea9b10bf6fd545f900683296456d6a11d8510397bb330455f"; + x86_64-unknown-linux-gnu = "2a1390340db1d24a9498036884e6b2748e9b4b057fc5219694e298bdaa37b810"; + armv7-unknown-linux-gnueabihf = "346558d14050853b87049e5e1fbfae0bf0360a2f7c57433c6985b1a879c349a2"; + aarch64-unknown-linux-gnu = "9b6fbcee73070332c811c0ddff399fa31965bec62ef258656c0c90354f6231c1"; + i686-apple-darwin = "752e2c9182e057c4a54152d1e0b3949482c225d02bb69d9d9a4127dc2a65fb68"; + x86_64-apple-darwin = "5d7a70ed4701fe9410041c1eea025c95cad97e5b3d8acc46426f9ac4f9f02393"; + }; + + platform = + if stdenv.hostPlatform.system == "i686-linux" + then "i686-unknown-linux-gnu" + else if stdenv.hostPlatform.system == "x86_64-linux" + then "x86_64-unknown-linux-gnu" + else if stdenv.hostPlatform.system == "armv7l-linux" + then "armv7-unknown-linux-gnueabihf" + else if stdenv.hostPlatform.system == "aarch64-linux" + then "aarch64-unknown-linux-gnu" + else if stdenv.hostPlatform.system == "i686-darwin" + then "i686-apple-darwin" + else if stdenv.hostPlatform.system == "x86_64-darwin" + then "x86_64-apple-darwin" + else throw "missing bootstrap url for platform ${stdenv.hostPlatform.system}"; + + src = fetchurl { + url = "https://static.rust-lang.org/dist/rust-${version}-${platform}.tar.gz"; + sha256 = hashes."${platform}"; + }; + +in callPackage ./binaryBuild.nix + { inherit version src platform; + buildRustPackage = null; + versionType = "bootstrap"; + } diff --git a/nix/pkgs/rust/cargo.nix b/nix/pkgs/rust/cargo.nix new file mode 100644 index 000000000..bfe379c81 --- /dev/null +++ b/nix/pkgs/rust/cargo.nix @@ -0,0 +1,70 @@ +{ stdenv, fetchurl, file, curl, pkgconfig, python, openssl, cmake, zlib +, makeWrapper, libiconv, cacert, rustPlatform, rustc, libgit2, darwin +, version +, patches ? [] +, src }: + +let + inherit (darwin.apple_sdk.frameworks) CoreFoundation; + src_rustc = fetchurl { + url = "https://static.rust-lang.org/dist/rustc-1.28.0-src.tar.gz"; + sha256 = "11k4rn77bca2rikykkk9fmprrgjswd4x4kaq7fia08vgkir82nhx"; + }; +in + +rustPlatform.buildRustPackage rec { + name = "cargo-${version}"; + inherit version src patches; + + # the rust source tarball already has all the dependencies vendored, no need to fetch them again + cargoVendorDir = "src/vendor"; + preBuild = "cd src; pushd tools/cargo"; + postBuild = "popd"; + + passthru.rustc = rustc; + + # changes hash of vendor directory otherwise + dontUpdateAutotoolsGnuConfigScripts = true; + + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ cacert file curl python openssl cmake zlib makeWrapper libgit2 ] + ++ stdenv.lib.optionals stdenv.isDarwin [ CoreFoundation libiconv ]; + + LIBGIT2_SYS_USE_PKG_CONFIG=1; + + # fixes: the cargo feature `edition` requires a nightly version of Cargo, but this is the `stable` channel + RUSTC_BOOTSTRAP=1; + + preConfigure = '' + tar xf ${src_rustc} + mv rustc-1.28.0-src/src/vendor/ src/vendor + ''; + + postInstall = '' + # NOTE: We override the `http.cainfo` option usually specified in + # `.cargo/config`. This is an issue when users want to specify + # their own certificate chain as environment variables take + # precedence + wrapProgram "$out/bin/cargo" \ + --suffix PATH : "${rustc}/bin" \ + --set CARGO_HTTP_CAINFO "${cacert}/etc/ssl/certs/ca-bundle.crt" \ + --set SSL_CERT_FILE "${cacert}/etc/ssl/certs/ca-bundle.crt" + ''; + + checkPhase = '' + # Disable cross compilation tests + export CFG_DISABLE_CROSS_TESTS=1 + cargo test + ''; + + # Disable check phase as there are failures (4 tests fail) + doCheck = false; + + meta = with stdenv.lib; { + homepage = https://crates.io; + description = "Downloads your Rust project's dependencies and builds your project"; + maintainers = with maintainers; [ wizeman retrry ]; + license = [ licenses.mit licenses.asl20 ]; + platforms = platforms.unix; + }; +} diff --git a/nix/pkgs/rust/default.nix b/nix/pkgs/rust/default.nix new file mode 100644 index 000000000..1a392124e --- /dev/null +++ b/nix/pkgs/rust/default.nix @@ -0,0 +1,90 @@ +{ stdenv, callPackage, recurseIntoAttrs, makeRustPlatform, llvm, fetchurl +, targets ? [] +, targetToolchains ? [] +, targetPatches ? [] +, fetchFromGitHub +}: + +let + rustPlatform = recurseIntoAttrs (makeRustPlatform (callPackage ./bootstrap.nix {})); + version = "1.28.0"; + cargoVersion = "1.28.0"; + src = fetchFromGitHub { + owner = "m-labs"; + repo = "rust"; + sha256 = "03lfps3xvvv7wv1nnwn3n1ji13z099vx8c3fpbzp9rnasrwzp5jy"; + rev = "f305fb024318e96997fbe6e4a105b0cc1052aad4"; # artiq-1.28.0 branch + fetchSubmodules = true; + }; +in rec { + # nixcloud team code + or1k-crates = stdenv.mkDerivation { + name = "or1k-crates"; + inherit src; + phases = [ "unpackPhase" "buildPhase" ]; + buildPhase = '' + destdir=$out + rustc="${rustc_internal}/bin/rustc --out-dir ''${destdir} -L ''${destdir} --target or1k-unknown-none -g -C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s --crate-type rlib" + + mkdir -p ''${destdir} + ''${rustc} --crate-name core src/libcore/lib.rs + ''${rustc} --crate-name compiler_builtins src/libcompiler_builtins/src/lib.rs --cfg 'feature="compiler-builtins"' --cfg 'feature="mem"' + ''${rustc} --crate-name std_unicode src/libstd_unicode/lib.rs + ''${rustc} --crate-name alloc src/liballoc/lib.rs + ''${rustc} --crate-name libc src/liblibc_mini/lib.rs + ''${rustc} --crate-name unwind src/libunwind/lib.rs + ''${rustc} -Cpanic=abort --crate-name panic_abort src/libpanic_abort/lib.rs + ''${rustc} -Cpanic=unwind --crate-name panic_unwind src/libpanic_unwind/lib.rs --cfg llvm_libunwind + ''; + }; + # nixcloud team code + # this is basically a wrapper, which uses rustc_internal and inserts or1k-crates into it + rustc = stdenv.mkDerivation { + name = "rustc"; + src = ./.; + installPhase = '' + mkdir $out + mkdir -p $out/lib/rustlib/or1k-unknown-none/lib/ + cp -r ${or1k-crates}/* $out/lib/rustlib/or1k-unknown-none/lib/ + cp -r ${rustc_internal}/* $out + ''; + }; + # nixcloud team code + # originally rustc but now renamed to rustc_internal + rustc_internal = callPackage ./rustc.nix { + inherit stdenv llvm targets targetPatches targetToolchains rustPlatform version src; + + patches = [ + ./patches/net-tcp-disable-tests.patch + + # Re-evaluate if this we need to disable this one + #./patches/stdsimd-disable-doctest.patch + + # Fails on hydra - not locally; the exact reason is unknown. + # Comments in the test suggest that some non-reproducible environment + # variables such $RANDOM can make it fail. + ./patches/disable-test-inherit-env.patch + ]; + + forceBundledLLVM = true; + + #configureFlags = [ "--release-channel=stable" ]; + + # 1. Upstream is not running tests on aarch64: + # see https://github.com/rust-lang/rust/issues/49807#issuecomment-380860567 + # So we do the same. + # 2. Tests run out of memory for i686 + #doCheck = !stdenv.isAarch64 && !stdenv.isi686; + + # Disabled for now; see https://github.com/NixOS/nixpkgs/pull/42348#issuecomment-402115598. + doCheck = false; + }; + + cargo = callPackage ./cargo.nix rec { + version = cargoVersion; + inherit src; + inherit stdenv; + inherit rustc; # the rustc that will be wrapped by cargo + inherit rustPlatform; # used to build cargo + }; +} diff --git a/nix/pkgs/rust/patches/disable-test-inherit-env.patch b/nix/pkgs/rust/patches/disable-test-inherit-env.patch new file mode 100644 index 000000000..fcb75ed09 --- /dev/null +++ b/nix/pkgs/rust/patches/disable-test-inherit-env.patch @@ -0,0 +1,10 @@ +--- rustc-1.26.2-src.org/src/libstd/process.rs 2018-06-01 21:40:11.000000000 +0100 ++++ rustc-1.26.2-src/src/libstd/process.rs 2018-06-08 07:50:23.023828658 +0100 +@@ -1745,6 +1745,7 @@ + } + + #[test] ++ #[ignore] + fn test_inherit_env() { + use env; + diff --git a/nix/pkgs/rust/patches/net-tcp-disable-tests.patch b/nix/pkgs/rust/patches/net-tcp-disable-tests.patch new file mode 100644 index 000000000..10713b6b7 --- /dev/null +++ b/nix/pkgs/rust/patches/net-tcp-disable-tests.patch @@ -0,0 +1,104 @@ +diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs +index 0f60b5b3e..9b08415e7 100644 +--- a/src/libstd/net/tcp.rs ++++ b/src/libstd/net/tcp.rs +@@ -962,6 +962,7 @@ mod tests { + } + } + ++ #[cfg_attr(target_os = "macos", ignore)] + #[test] + fn listen_localhost() { + let socket_addr = next_test_ip4(); +@@ -1020,6 +1021,7 @@ mod tests { + }) + } + ++ #[cfg_attr(target_os = "macos", ignore)] + #[test] + fn read_eof() { + each_ip(&mut |addr| { +@@ -1039,6 +1041,7 @@ mod tests { + }) + } + ++ #[cfg_attr(target_os = "macos", ignore)] + #[test] + fn write_close() { + each_ip(&mut |addr| { +@@ -1065,6 +1068,7 @@ mod tests { + }) + } + ++ #[cfg_attr(target_os = "macos", ignore)] + #[test] + fn multiple_connect_serial() { + each_ip(&mut |addr| { +@@ -1087,6 +1091,7 @@ mod tests { + }) + } + ++ #[cfg_attr(target_os = "macos", ignore)] + #[test] + fn multiple_connect_interleaved_greedy_schedule() { + const MAX: usize = 10; +@@ -1123,6 +1128,7 @@ mod tests { + } + + #[test] ++ #[cfg_attr(target_os = "macos", ignore)] + fn multiple_connect_interleaved_lazy_schedule() { + const MAX: usize = 10; + each_ip(&mut |addr| { +@@ -1401,6 +1407,7 @@ mod tests { + } + + #[test] ++ #[cfg_attr(target_os = "macos", ignore)] + fn clone_while_reading() { + each_ip(&mut |addr| { + let accept = t!(TcpListener::bind(&addr)); +@@ -1421,7 +1422,10 @@ mod tests { + + // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code + // no longer has rounding errors. +- #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] ++ #[cfg_attr(any(target_os = "bitrig", ++ target_os = "netbsd", ++ target_os = "openbsd", ++ target_os = "macos"), ignore)] + #[test] + fn timeouts() { + let addr = next_test_ip4(); +@@ -1596,6 +1603,7 @@ mod tests { + drop(listener); + } + ++ #[cfg_attr(target_os = "macos", ignore)] + #[test] + fn nodelay() { + let addr = next_test_ip4(); +@@ -1610,6 +1618,7 @@ mod tests { + assert_eq!(false, t!(stream.nodelay())); + } + ++ #[cfg_attr(target_os = "macos", ignore)] + #[test] + fn ttl() { + let ttl = 100; +@@ -1647,6 +1656,7 @@ mod tests { + } + } + ++ #[cfg_attr(target_os = "macos", ignore)] + #[test] + fn peek() { + each_ip(&mut |addr| { +@@ -1679,6 +1689,7 @@ mod tests { + } + + #[test] ++ #[cfg_attr(any(target_os = "linux", target_os = "macos"), ignore)] + fn connect_timeout_unroutable() { + // this IP is unroutable, so connections should always time out, + // provided the network is reachable to begin with. diff --git a/nix/pkgs/rust/patches/stdsimd-disable-doctest.patch b/nix/pkgs/rust/patches/stdsimd-disable-doctest.patch new file mode 100644 index 000000000..6ef7fd0f7 --- /dev/null +++ b/nix/pkgs/rust/patches/stdsimd-disable-doctest.patch @@ -0,0 +1,20 @@ +diff --git a/src/stdsimd/coresimd/x86/mod.rs b/src/stdsimd/coresimd/x86/mod.rs +index 32915c332..7cb54f31e 100644 +--- a/src/stdsimd/coresimd/x86/mod.rs ++++ b/src/stdsimd/coresimd/x86/mod.rs +@@ -279,7 +279,6 @@ types! { + /// + /// # Examples + /// +- /// ``` + /// # #![feature(cfg_target_feature, target_feature, stdsimd)] + /// # #![cfg_attr(not(dox), no_std)] + /// # #[cfg(not(dox))] +@@ -301,7 +300,6 @@ types! { + /// # } + /// # if is_x86_feature_detected!("sse") { unsafe { foo() } } + /// # } +- /// ``` + pub struct __m256(f32, f32, f32, f32, f32, f32, f32, f32); + + /// 256-bit wide set of four `f64` types, x86-specific diff --git a/nix/pkgs/rust/print-hashes.sh b/nix/pkgs/rust/print-hashes.sh new file mode 100755 index 000000000..7eb00a30a --- /dev/null +++ b/nix/pkgs/rust/print-hashes.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -euo pipefail + +# All rust-related downloads can be found at +# https://static.rust-lang.org/dist/index.html. To find the date on +# which a particular thing was last updated, look for the *-date.txt +# file, e.g. +# https://static.rust-lang.org/dist/channel-rust-beta-date.txt + +PLATFORMS=( + i686-unknown-linux-gnu + x86_64-unknown-linux-gnu + armv7-unknown-linux-gnueabihf + aarch64-unknown-linux-gnu + i686-apple-darwin + x86_64-apple-darwin +) +BASEURL=https://static.rust-lang.org/dist +VERSION=${1:-} +DATE=${2:-} + +if [[ -z $VERSION ]] +then + echo "No version supplied" + exit -1 +fi + +if [[ -n $DATE ]] +then + BASEURL=$BASEURL/$DATE +fi + +for PLATFORM in "${PLATFORMS[@]}" +do + URL="$BASEURL/rust-$VERSION-$PLATFORM.tar.gz.sha256" + SHA256=$(curl -sSfL $URL | cut -d ' ' -f 1) + echo "$PLATFORM = \"$SHA256\";" +done diff --git a/nix/pkgs/rust/rust-src.nix b/nix/pkgs/rust/rust-src.nix new file mode 100644 index 000000000..1b819a7f6 --- /dev/null +++ b/nix/pkgs/rust/rust-src.nix @@ -0,0 +1,11 @@ +{ stdenv, rustc }: + +stdenv.mkDerivation { + name = "rust-src"; + src = rustc.src; + phases = [ "unpackPhase" "installPhase" ]; + installPhase = '' + mv src $out + rm -rf $out/{ci,doc,driver,etc,grammar,llvm,rt,rtstartup,rustllvm,test,tools,vendor} + ''; +} diff --git a/nix/pkgs/rust/rustc.nix b/nix/pkgs/rust/rustc.nix new file mode 100644 index 000000000..a1dbc5ba5 --- /dev/null +++ b/nix/pkgs/rust/rustc.nix @@ -0,0 +1,199 @@ +{ stdenv, targetPackages +, fetchurl, fetchgit, fetchzip, file, python2, tzdata, ps +, llvm, jemalloc, ncurses, darwin, rustPlatform, git, cmake, curl +, which, libffi, gdb +, version +, forceBundledLLVM ? false +, src +, configureFlags ? [] +, patches +, targets +, targetPatches +, targetToolchains +, doCheck ? true +, broken ? false +, pkgs +}: + +let + inherit (stdenv.lib) optional optionalString; + inherit (darwin.apple_sdk.frameworks) Security; + + llvmShared = llvm.override { enableSharedLibraries = true; }; + llvmOR1k = (import ../../default.nix {}).llvm-or1k; + + target = builtins.replaceStrings [" "] [","] (builtins.toString targets); + src_rustc = fetchurl { + url = "https://static.rust-lang.org/dist/rustc-1.28.0-src.tar.gz"; + sha256 = "11k4rn77bca2rikykkk9fmprrgjswd4x4kaq7fia08vgkir82nhx"; + }; + +in + +stdenv.mkDerivation { + name = "rustc-${version}"; + inherit version; + + inherit src; + + __darwinAllowLocalNetworking = true; + + # rustc complains about modified source files otherwise + dontUpdateAutotoolsGnuConfigScripts = true; + + # Running the default `strip -S` command on Darwin corrupts the + # .rlib files in "lib/". + # + # See https://github.com/NixOS/nixpkgs/pull/34227 + stripDebugList = if stdenv.isDarwin then [ "bin" ] else null; + + NIX_LDFLAGS = optionalString stdenv.isDarwin "-rpath ${llvmShared}/lib"; + + # Enable nightly features in stable compiles (used for + # bootstrapping, see https://github.com/rust-lang/rust/pull/37265). + # This loosens the hard restrictions on bootstrapping-compiler + # versions. + RUSTC_BOOTSTRAP = "1"; + + # Increase codegen units to introduce parallelism within the compiler. + RUSTFLAGS = "-Ccodegen-units=10"; + + # We need rust to build rust. If we don't provide it, configure will try to download it. + # Reference: https://github.com/rust-lang/rust/blob/master/src/bootstrap/configure.py + configureFlags = configureFlags + ++ [ "--enable-local-rust" "--local-rust-root=${rustPlatform.rust.rustc}" "--enable-rpath" ] + ++ [ "--enable-vendor" ] + # ++ [ "--jemalloc-root=${jemalloc}/lib" + ++ [ "--default-linker=${targetPackages.stdenv.cc}/bin/cc" ] + ++ optional (!forceBundledLLVM) [ "--enable-llvm-link-shared" ] + ++ optional (targets != []) "--target=${target}" + #++ optional (!forceBundledLLVM) "--llvm-root=${llvmShared}" + ++ [ "--llvm-root=${llvmOR1k}" ] ; + + # The bootstrap.py will generated a Makefile that then executes the build. + # The BOOTSTRAP_ARGS used by this Makefile must include all flags to pass + # to the bootstrap builder. + postConfigure = '' + substituteInPlace Makefile --replace 'BOOTSTRAP_ARGS :=' 'BOOTSTRAP_ARGS := --jobs $(NIX_BUILD_CORES)' + ''; + + # FIXME: qknight, readd deleted vendor folder from 1.28 rustc + preConfigure = '' + export HOME=$out + # HACK: we add the vendor folder from rustc 1.28 to make the compiling work + tar xf ${src_rustc} + mv rustc-1.28.0-src/src/vendor/ src/vendor + cp -R ${llvmOR1k} src/llvm + ''; + + patches = patches ++ targetPatches; + + # the rust build system complains that nix alters the checksums + dontFixLibtool = true; + + passthru.target = target; + + postPatch = '' + patchShebangs src/etc + + # Fix dynamic linking against llvm + #${optionalString (!forceBundledLLVM) ''sed -i 's/, kind = \\"static\\"//g' src/etc/mklldeps.py''} + + # Fix the configure script to not require curl as we won't use it + sed -i configure \ + -e '/probe_need CFG_CURL curl/d' + + # Fix the use of jemalloc prefixes which our jemalloc doesn't have + # TODO: reenable if we can figure out how to get our jemalloc to work + #[ -f src/liballoc_jemalloc/lib.rs ] && sed -i 's,je_,,g' src/liballoc_jemalloc/lib.rs + #[ -f src/liballoc/heap.rs ] && sed -i 's,je_,,g' src/liballoc/heap.rs # Remove for 1.4.0+ + + # Disable fragile tests. + rm -vr src/test/run-make/linker-output-non-utf8 || true + rm -vr src/test/run-make/issue-26092 || true + + # Remove test targeted at LLVM 3.9 - https://github.com/rust-lang/rust/issues/36835 + rm -vr src/test/run-pass/issue-36023.rs || true + + # Disable test getting stuck on hydra - possible fix: + # https://reviews.llvm.org/rL281650 + rm -vr src/test/run-pass/issue-36474.rs || true + + # On Hydra: `TcpListener::bind(&addr)`: Address already in use (os error 98)' + sed '/^ *fn fast_rebind()/i#[ignore]' -i src/libstd/net/tcp.rs + + # https://github.com/rust-lang/rust/issues/39522 + echo removing gdb-version-sensitive tests... + find src/test/debuginfo -type f -execdir grep -q ignore-gdb-version '{}' \; -print -delete + rm src/test/debuginfo/{borrowed-c-style-enum.rs,c-style-enum-in-composite.rs,gdb-pretty-struct-and-enums-pre-gdb-7-7.rs,generic-enum-with-different-disr-sizes.rs} + + # Useful debugging parameter + # export VERBOSE=1 + '' + optionalString stdenv.isDarwin '' + # Disable all lldb tests. + # error: Can't run LLDB test because LLDB's python path is not set + rm -vr src/test/debuginfo/* + rm -v src/test/run-pass/backtrace-debuginfo.rs + + # error: No such file or directory + rm -v src/test/run-pass/issue-45731.rs + + # Disable tests that fail when sandboxing is enabled. + substituteInPlace src/libstd/sys/unix/ext/net.rs \ + --replace '#[test]' '#[test] #[ignore]' + substituteInPlace src/test/run-pass/env-home-dir.rs \ + --replace 'home_dir().is_some()' true + rm -v src/test/run-pass/fds-are-cloexec.rs # FIXME: pipes? + rm -v src/test/run-pass/sync-send-in-std.rs # FIXME: ??? + ''; + + # rustc unfortunately need cmake for compiling llvm-rt but doesn't + # use it for the normal build. This disables cmake in Nix. + dontUseCmakeConfigure = true; + + # ps is needed for one of the test cases + nativeBuildInputs = + [ file python2 ps rustPlatform.rust.rustc git cmake + which libffi + ] + # Only needed for the debuginfo tests + ++ optional (!stdenv.isDarwin) gdb; + + buildInputs = [ ncurses pkgs.zlib ] ++ targetToolchains + ++ optional stdenv.isDarwin Security + ++ optional (!forceBundledLLVM) llvmShared; + + outputs = [ "out" "man" "doc" ]; + setOutputFlags = false; + + # Disable codegen units and hardening for the tests. + preCheck = '' + export RUSTFLAGS= + export TZDIR=${tzdata}/share/zoneinfo + export hardeningDisable=all + '' + + # Ensure TMPDIR is set, and disable a test that removing the HOME + # variable from the environment falls back to another home + # directory. + optionalString stdenv.isDarwin '' + export TMPDIR=/tmp + sed -i '28s/home_dir().is_some()/true/' ./src/test/run-pass/env-home-dir.rs + ''; + + inherit doCheck; + + configurePlatforms = []; + + # https://github.com/NixOS/nixpkgs/pull/21742#issuecomment-272305764 + # https://github.com/rust-lang/rust/issues/30181 + # enableParallelBuilding = false; + + meta = with stdenv.lib; { + homepage = https://www.rust-lang.org/; + description = "A safe, concurrent, practical language"; + maintainers = with maintainers; [ madjar cstrahan wizeman globin havvy wkennington ]; + license = [ licenses.mit licenses.asl20 ]; + platforms = platforms.linux ++ platforms.darwin; + broken = broken; + }; +} diff --git a/nix/shell.nix b/nix/shell.nix index 8fbdadb65..19515cc54 100644 --- a/nix/shell.nix +++ b/nix/shell.nix @@ -1,8 +1,21 @@ -{system ? builtins.currentSystem}: -let - pkgs = import {inherit system;}; - artiq = pkgs.callPackage ./default.nix {}; +let + pkgs = import {}; + artiqpkgs = import ./default.nix { inherit pkgs; }; in -pkgs.mkShell { - buildInputs = [ artiq ]; -} + pkgs.mkShell { + # with this configuration we can't build kasli target(s) because misoc packaged via nix does not work correctly + # want to build using nix-shell anyway? easy: + # 1. remove misoc from the list below + # 2. nix-shell + # 3. export PYTHONPATH=$PYTHONPATH:/home/joachim/Desktop/projects/artiq-toolchain/misoc + # 4. cd artiq/gateware/targets + # 5. python kasli.py --no-compile-gateware + buildInputs = with artiqpkgs; [ rustc cargo binutils-or1k llvm-or1k llvmlite migen misoc ] + ++ (with pkgs; [ python3 python36Packages.jinja2 python36Packages.numpy ]); # for artiq the python lib... + shellHook = '' + export TARGET_AR=${artiqpkgs.binutils-or1k}/bin/or1k-linux-ar + export PYTHONPATH=$PYTHONPATH:`pwd`/.. + + echo "please see comments in nix/shell.nix and nix/pkgs/python3Packages.nix (nixcloud team)" + ''; + } From c09ab8502ce6e236b1f2eb2a8c5aab086e2b0f42 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 13 Dec 2018 06:57:10 +0800 Subject: [PATCH 1433/2457] nix: cleanup --- nix/default.nix | 2 +- nix/pkgs/python3Packages.nix | 43 +++--------------------------------- nix/shell.nix | 12 +--------- 3 files changed, 5 insertions(+), 52 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index f06b6d289..72210c430 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -13,5 +13,5 @@ in rec { binutils-or1k = callPackage ./binutils-or1k.nix {}; llvm-or1k = callPackage ./llvm-or1k.nix { inherit llvm-src; }; llvmlite = callPackage ./llvmlite.nix { inherit llvm-or1k; }; - #artiq = callPackage ./artiq.nix { inherit binutils-or1k; }; + artiq = callPackage ./artiq.nix { inherit binutils-or1k; inherit llvm-or1k; inherit llvmlite; }; } diff --git a/nix/pkgs/python3Packages.nix b/nix/pkgs/python3Packages.nix index 0396772f6..cd102f416 100644 --- a/nix/pkgs/python3Packages.nix +++ b/nix/pkgs/python3Packages.nix @@ -28,11 +28,6 @@ rec { pname = "misoc"; name = "${pname}-${version}"; - # you can use the src definition to point to your local git checkout (don't forget the submodules) so - # hacking is easier! - #src = /home/bar/misoc; - - # instead of this (nixcloud team) src = fetchFromGitHub { owner = "m-labs"; repo = "misoc"; @@ -41,40 +36,8 @@ rec { fetchSubmodules = true; }; - # there are still so many tests failing (nixcloud team) - # ====================================================================== - # ERROR: framebuffer (unittest.loader._FailedTest) - # ---------------------------------------------------------------------- - # ImportError: Failed to import test module: framebuffer - # Traceback (most recent call last): - # File "/nix/store/bwfygfcdvis9wd1c1v51xwnwhw1hx0a0-python3-3.6.6/lib/python3.6/unittest/loader.py", line 153, in loadTestsFromName - # module = __import__(module_name) - # File "/build/source/misoc/cores/framebuffer/__init__.py", line 1, in - # from misoc.cores.framebuffer.core import Framebuffer - # File "/build/source/misoc/cores/framebuffer/core.py", line 2, in - # from migen.flow.network import * - # ModuleNotFoundError: No module named 'migen.flow' - # - # - # watch for these messages: - # writing manifest file 'misoc.egg-info/SOURCES.txt' - # running build_ext - # /nix/store/w7cmmmzafv81wwhkadpar6vdvbqphzdf-python3.6-bootstrapped-pip-18.1/lib/python3.6/site-packages/setuptools/dist.py:398: UserWarning: Normalizing '0.6.dev' to '0.6.dev0' - # normalized_version, - # debug (unittest.loader._FailedTest) - # Run the test without collecting errors in a TestResult ... ERROR - # framebuffer (unittest.loader._FailedTest) ... ERROR - # sdram_model (unittest.loader._FailedTest) ... ERROR - # test (unittest.loader._FailedTest) ... ERROR - # test_df (unittest.loader._FailedTest) ... ERROR - # test_wb (unittest.loader._FailedTest) ... ERROR - # test_refresher (unittest.loader._FailedTest) ... ERROR - # test_common (unittest.loader._FailedTest) ... ERROR - # test_lasmi (unittest.loader._FailedTest) ... ERROR - # test_bankmachine (unittest.loader._FailedTest) ... ERROR - # - # you can disable the tests (which is a bad idea, fix them instead) - # doCheck = false; + # TODO: fix misoc bitrot and re-enable tests + doCheck = false; propagatedBuildInputs = with python3Packages; [ pyserial jinja2 numpy asyncserial migen ]; @@ -98,7 +61,7 @@ rec { fetchSubmodules = true; }; - # FileNotFoundError: [Errno 2] No such file or directory: '/usr/local/diamond' (nixcloud team) + # TODO: fix migen platform issues and re-enable tests doCheck = false; propagatedBuildInputs = with python3Packages; [ colorama sphinx sphinx_rtd_theme ] ++ (with pkgs; [ verilator ]); diff --git a/nix/shell.nix b/nix/shell.nix index 19515cc54..cbcea74f3 100644 --- a/nix/shell.nix +++ b/nix/shell.nix @@ -3,19 +3,9 @@ let artiqpkgs = import ./default.nix { inherit pkgs; }; in pkgs.mkShell { - # with this configuration we can't build kasli target(s) because misoc packaged via nix does not work correctly - # want to build using nix-shell anyway? easy: - # 1. remove misoc from the list below - # 2. nix-shell - # 3. export PYTHONPATH=$PYTHONPATH:/home/joachim/Desktop/projects/artiq-toolchain/misoc - # 4. cd artiq/gateware/targets - # 5. python kasli.py --no-compile-gateware - buildInputs = with artiqpkgs; [ rustc cargo binutils-or1k llvm-or1k llvmlite migen misoc ] + buildInputs = with artiqpkgs; [ rustc cargo binutils-or1k llvm-or1k llvmlite migen misoc artiq ] ++ (with pkgs; [ python3 python36Packages.jinja2 python36Packages.numpy ]); # for artiq the python lib... shellHook = '' export TARGET_AR=${artiqpkgs.binutils-or1k}/bin/or1k-linux-ar - export PYTHONPATH=$PYTHONPATH:`pwd`/.. - - echo "please see comments in nix/shell.nix and nix/pkgs/python3Packages.nix (nixcloud team)" ''; } From 38ce7ab8ff6ce02af51ed598e91d02821114b5c0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 13 Dec 2018 06:58:54 +0800 Subject: [PATCH 1434/2457] sync_struct: handle TimeoutError as subscriber disconnection. Closes #1215 --- artiq/protocols/sync_struct.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/protocols/sync_struct.py b/artiq/protocols/sync_struct.py index ca48c5356..1095e45ef 100644 --- a/artiq/protocols/sync_struct.py +++ b/artiq/protocols/sync_struct.py @@ -244,7 +244,7 @@ class Publisher(AsyncioServer): await writer.drain() finally: self._recipients[notifier_name].remove(queue) - except (ConnectionResetError, ConnectionAbortedError, BrokenPipeError): + except (ConnectionResetError, ConnectionAbortedError, BrokenPipeError, TimeoutError): # subscribers disconnecting are a normal occurrence pass finally: From 8e30c4574b468b9ef920d46683f1e29055a77bf0 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 12 Dec 2018 00:37:48 +0000 Subject: [PATCH 1435/2457] firmware: Treat timestamps consistently as signed [nfc] This matches other functions and the ARTIQ Python side, but isn't actually an ABI change. --- artiq/firmware/ksupport/rtio.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index 27e893a97..8c112ea50 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -94,7 +94,7 @@ mod imp { } } - pub extern fn input_timestamp(timeout: i64, channel: i32) -> u64 { + pub extern fn input_timestamp(timeout: i64, channel: i32) -> i64 { unsafe { csr::rtio::target_write((channel as u32) << 8); csr::rtio::i_timeout_write(timeout as u64); @@ -111,7 +111,7 @@ mod imp { channel as i64, 0, 0); } if status & RTIO_I_STATUS_WAIT_EVENT != 0 { - return !0 + return -1 } if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { raise!("RTIODestinationUnreachable", @@ -119,7 +119,7 @@ mod imp { channel as i64, 0, 0); } - csr::rtio::i_timestamp_read() + csr::rtio::i_timestamp_read() as i64 } } @@ -200,7 +200,7 @@ mod imp { unimplemented!("not(has_rtio)") } - pub extern fn input_timestamp(_timeout: i64, _channel: i32) -> u64 { + pub extern fn input_timestamp(_timeout: i64, _channel: i32) -> i64 { unimplemented!("not(has_rtio)") } From e608d6ffd3b3a597aa89a30c005c075fe9f64873 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 11 Dec 2018 20:49:42 +0000 Subject: [PATCH 1436/2457] coredevice, firmware: Add rtio_input_timestamped_data Integration tests to follow as part of an RTIO counter phy that makes use of this. --- artiq/coredevice/rtio.py | 11 ++++++++- artiq/firmware/ksupport/api.rs | 1 + artiq/firmware/ksupport/rtio.rs | 44 +++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/rtio.py b/artiq/coredevice/rtio.py index bde9d5064..7b5ab38a2 100644 --- a/artiq/coredevice/rtio.py +++ b/artiq/coredevice/rtio.py @@ -1,5 +1,5 @@ from artiq.language.core import syscall -from artiq.language.types import TInt64, TInt32, TNone, TList +from artiq.language.types import TInt32, TInt64, TList, TNone, TTuple @syscall(flags={"nowrite"}) @@ -20,3 +20,12 @@ def rtio_input_timestamp(timeout_mu: TInt64, channel: TInt32) -> TInt64: @syscall(flags={"nowrite"}) def rtio_input_data(channel: TInt32) -> TInt32: raise NotImplementedError("syscall not simulated") + + +@syscall(flags={"nowrite"}) +def rtio_input_timestamped_data(timeout_mu: TInt64, + channel: TInt32) -> TTuple([TInt64, TInt32]): + """Wait for an input event up to timeout_mu on the given channel, and + return a tuple of timestamp and attached data, or (-1, 0) if the timeout is + reached.""" + raise NotImplementedError("syscall not simulated") diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index ffd0d38b8..00c0f23e6 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -104,6 +104,7 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(rtio_output_wide = ::rtio::output_wide), api!(rtio_input_timestamp = ::rtio::input_timestamp), api!(rtio_input_data = ::rtio::input_data), + api!(rtio_input_timestamped_data = ::rtio::input_timestamped_data), api!(dma_record_start = ::dma_record_start), api!(dma_record_stop = ::dma_record_stop), diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index 8c112ea50..fc64f554b 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -1,7 +1,14 @@ +#[repr(C)] +pub struct TimestampedData { + timestamp: i64, + data: i32, +} + #[cfg(has_rtio)] mod imp { use core::ptr::{read_volatile, write_volatile}; use cslice::CSlice; + use rtio::TimestampedData; use board_misoc::csr; use ::send; @@ -149,6 +156,38 @@ mod imp { } } + pub extern fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedData { + unsafe { + csr::rtio::target_write((channel as u32) << 8); + csr::rtio::i_timeout_write(timeout as u64); + + let mut status = RTIO_I_STATUS_WAIT_STATUS; + while status & RTIO_I_STATUS_WAIT_STATUS != 0 { + status = csr::rtio::i_status_read(); + } + + if status & RTIO_I_STATUS_OVERFLOW != 0 { + csr::rtio::i_overflow_reset_write(1); + raise!("RTIOOverflow", + "RTIO input overflow on channel {0}", + channel as i64, 0, 0); + } + if status & RTIO_I_STATUS_WAIT_EVENT != 0 { + return TimestampedData { timestamp: -1, data: 0 } + } + if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { + raise!("RTIODestinationUnreachable", + "RTIO destination unreachable, input, on channel {0}", + channel as i64, 0, 0); + } + + TimestampedData { + timestamp: csr::rtio::i_timestamp_read() as i64, + data: rtio_i_data_read(0) as i32 + } + } + } + #[cfg(has_rtio_log)] pub fn log(data: &[u8]) { unsafe { @@ -179,6 +218,7 @@ mod imp { #[cfg(not(has_rtio))] mod imp { use cslice::CSlice; + use rtio::TimestampedData; pub extern fn init() { unimplemented!("not(has_rtio)") @@ -208,6 +248,10 @@ mod imp { unimplemented!("not(has_rtio)") } + pub extern fn input_timestamped_data(_timeout: i64, _channel: i32) -> TimestampedData { + unimplemented!("not(has_rtio)") + } + pub fn log(_data: &[u8]) { unimplemented!("not(has_rtio)") } From a7d4d3bda9c74e98463fb8893bf251794ce2456a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 17 Dec 2018 13:25:00 +0000 Subject: [PATCH 1437/2457] ad9910: CONT_RECIRCULATE -> CONT_RAMPUP --- artiq/coredevice/ad9910.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 04315607b..160cf11d9 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -58,7 +58,7 @@ RAM_MODE_DIRECTSWITCH = 0 RAM_MODE_RAMPUP = 1 RAM_MODE_BIDIR_RAMP = 2 RAM_MODE_CONT_BIDIR_RAMP = 3 -RAM_MODE_CONT_RECIRCULATE = 4 +RAM_MODE_CONT_RAMPUP = 4 class AD9910: From d60b95f481bb2a9e424ee9e1813bcd36ca7f47d8 Mon Sep 17 00:00:00 2001 From: Drew Date: Tue, 18 Dec 2018 13:47:09 -0500 Subject: [PATCH 1438/2457] tdr.py: typo (#1220) --- artiq/examples/kc705_nist_clock/repository/tdr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/examples/kc705_nist_clock/repository/tdr.py b/artiq/examples/kc705_nist_clock/repository/tdr.py index c304f268a..21dc9338a 100644 --- a/artiq/examples/kc705_nist_clock/repository/tdr.py +++ b/artiq/examples/kc705_nist_clock/repository/tdr.py @@ -44,7 +44,7 @@ class TDR(EnvExperiment): try: self.many(n, self.core.seconds_to_mu(pulse)) except PulseNotReceivedError: - print("to few edges: cable too long or wiring bad") + print("too few edges: cable too long or wiring bad") else: print(self.t) t_rise = mu_to_seconds(self.t[0], self.core)/n - latency From e80d80f13323536840dcb1b1806d378ae1026648 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 21 Dec 2018 10:37:08 +0800 Subject: [PATCH 1439/2457] manual: move to correct directory for building rust crates. Closes #1222 --- doc/manual/developing.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index 5d1edc998..e562e1af6 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -117,6 +117,7 @@ and the ARTIQ kernels. $ sudo mkdir /usr/local/rust-or1k $ sudo chown $USER.$USER /usr/local/rust-or1k $ make install + $ cd .. $ destdir="/usr/local/rust-or1k/lib/rustlib/or1k-unknown-none/lib/" $ rustc="rustc --out-dir ${destdir} -L ${destdir} --target or1k-unknown-none -g -C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s --crate-type rlib" From 421ad9c9168e1125bfd900d7fb0ec005d5c6d043 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 22 Dec 2018 14:01:52 +0800 Subject: [PATCH 1440/2457] nix: bump llvmlite --- nix/llvmlite.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix/llvmlite.nix b/nix/llvmlite.nix index 5db02ca35..a56977dc4 100644 --- a/nix/llvmlite.nix +++ b/nix/llvmlite.nix @@ -5,10 +5,10 @@ in stdenv.mkDerivation rec { name = "llvmlite-${version}"; src = fetchFromGitHub { - rev = "401dfb713166bdd2bc0d3ab2b7ebf12e7a434130"; + rev = "1d167be4eec5d6c32498952be8b3ac17dd30df8d"; owner = "m-labs"; repo = "llvmlite"; - sha256 = "1hqahd87ihwgjsaxv0y2iywldi1zgyjxjfy3sy3rr1gnwvxb47xw"; + sha256 = "0ranbjhcz2v3crmdbw1sxdwqwqbbm7dd53d8qaqb69ma9fkxy8x7"; }; buildInputs = [ makeWrapper python3 ncurses zlib llvm-or1k python3Packages.setuptools ]; From 1e7ba3227f94959304584e7431f8b8197967feb6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Jan 2019 22:25:56 +0800 Subject: [PATCH 1441/2457] nix: add development environment --- nix/README.rst | 17 ++++++++---- nix/artiq-dev.nix | 33 +++++++++++++++++++++++ nix/default.nix | 1 + nix/pkgs/openocd.nix | 63 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 nix/artiq-dev.nix create mode 100644 nix/pkgs/openocd.nix diff --git a/nix/README.rst b/nix/README.rst index 7df289bd4..c6f69e4d6 100644 --- a/nix/README.rst +++ b/nix/README.rst @@ -1,12 +1,10 @@ -Install ARTIQ via the Nix Package Manager -========================================= +Use ARTIQ via the Nix Package Manager +===================================== These instructions provide an alternative route to install ARTIQ for people who do not wish to use conda. This sets up an environment suitable for using ARTIQ, including the ARTIQ-Python compiler, device drivers, and the graphical user interfaces. This works correctly on Linux, and partially works (but not to a level that we would consider usable) with WSL introduced in Windows 10. -ARTIQ firmware and gateware development tools (e.g. rustc, Migen) and ARTIQ core device flashing tools (OpenOCD, proxy bitstreams) are currently not available on Nix. Pull requests welcome! - * Install the Nix package manager * many Linux distros already have a package for the `Nix package manager `_ @@ -25,4 +23,13 @@ ARTIQ firmware and gateware development tools (e.g. rustc, Migen) and ARTIQ core * $ ``cd artiq/nix`` * $ ``nix-env -i -f default.nix`` -The above command will setup your entire environment. Note that it will compile LLVM and Clang, which uses a lot of CPU time and disk space. +The above command will setup your entire environment. Note that it will compile LLVM, which uses a lot of CPU time and disk space. + +ARTIQ development environment with Nix +====================================== + +Run ``nix-shell artiq-dev.nix`` to obtain an environment containing Migen, MiSoC, Clang, Rust, Cargo, and OpenOCD in addition to the user environment above. + +This creates a FHS chroot environment in order to simplify the installation and patching of Xilinx Vivado (it needs to be installed manually e.g. in your home folder). + +You can then build the firmware and gateware with a command such as ``python -m artiq.gateware.targets.kasli --gateware-toolchain-path ~/Xilinx/Vivado``. diff --git a/nix/artiq-dev.nix b/nix/artiq-dev.nix new file mode 100644 index 000000000..89c079379 --- /dev/null +++ b/nix/artiq-dev.nix @@ -0,0 +1,33 @@ +let + pkgs = import {}; + artiqpkgs = import ./default.nix { inherit pkgs; }; +in +( + pkgs.buildFHSUserEnv { + name = "artiq-dev"; + targetPkgs = pkgs: ( + with pkgs; [ + ncurses5 + gnumake + xorg.libSM + xorg.libICE + xorg.libXrender + xorg.libX11 + xorg.libXext + xorg.libXtst + xorg.libXi + (python3.withPackages(ps: with ps; [ jinja2 numpy artiqpkgs.migen artiqpkgs.misoc artiqpkgs.artiq ])) + ] ++ + (with artiqpkgs; [ + rustc + cargo + binutils-or1k + llvm-or1k + openocd + ]) + ); + profile = '' + export TARGET_AR=${artiqpkgs.binutils-or1k}/bin/or1k-linux-ar + ''; + } +).env diff --git a/nix/default.nix b/nix/default.nix index 72210c430..5aaaf7621 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -14,4 +14,5 @@ in rec { llvm-or1k = callPackage ./llvm-or1k.nix { inherit llvm-src; }; llvmlite = callPackage ./llvmlite.nix { inherit llvm-or1k; }; artiq = callPackage ./artiq.nix { inherit binutils-or1k; inherit llvm-or1k; inherit llvmlite; }; + openocd = callPackage ./pkgs/openocd.nix {}; } diff --git a/nix/pkgs/openocd.nix b/nix/pkgs/openocd.nix new file mode 100644 index 000000000..c820d4c14 --- /dev/null +++ b/nix/pkgs/openocd.nix @@ -0,0 +1,63 @@ +{ stdenv, fetchFromGitHub, autoreconfHook, libftdi, libusb1, pkgconfig, hidapi }: + +stdenv.mkDerivation rec { + name = "openocd-${version}"; + version = "0.10.0"; + + src = fetchFromGitHub { + owner = "m-labs"; + repo = "openocd"; + fetchSubmodules = true; + rev = "c383a57adcff332b2c5cf8d55a84626285b42c2c"; + sha256 = "0xlj9cs72acx3zqagvr7f1c0v6lnqhl8fgrlhgmhmvk5n9knk492"; + }; + + nativeBuildInputs = [ pkgconfig ]; + buildInputs = [ autoreconfHook libftdi libusb1 hidapi ]; + + configureFlags = [ + "--enable-jtag_vpi" + "--enable-usb_blaster_libftdi" + "--enable-amtjtagaccel" + "--enable-gw16012" + "--enable-presto_libftdi" + "--enable-openjtag_ftdi" + "--enable-oocd_trace" + "--enable-buspirate" + "--enable-sysfsgpio" + "--enable-remote-bitbang" + ]; + + NIX_CFLAGS_COMPILE = [ + "-Wno-implicit-fallthrough" + "-Wno-format-truncation" + "-Wno-format-overflow" + ]; + + postInstall = '' + mkdir -p "$out/etc/udev/rules.d" + rules="$out/share/openocd/contrib/60-openocd.rules" + if [ ! -f "$rules" ]; then + echo "$rules is missing, must update the Nix file." + exit 1 + fi + ln -s "$rules" "$out/etc/udev/rules.d/" + ''; + + meta = with stdenv.lib; { + description = "Free and Open On-Chip Debugging, In-System Programming and Boundary-Scan Testing"; + longDescription = '' + OpenOCD provides on-chip programming and debugging support with a layered + architecture of JTAG interface and TAP support, debug target support + (e.g. ARM, MIPS), and flash chip drivers (e.g. CFI, NAND, etc.). Several + network interfaces are available for interactiving with OpenOCD: HTTP, + telnet, TCL, and GDB. The GDB server enables OpenOCD to function as a + "remote target" for source-level debugging of embedded systems using the + GNU GDB program. + ''; + homepage = http://openocd.sourceforge.net/; + license = licenses.gpl2Plus; + maintainers = with maintainers; [ bjornfor ]; + platforms = platforms.linux; + }; +} From e2799803cb396f6fe6ad7738a75a4bb1fa20b1be Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Jan 2019 23:35:55 +0800 Subject: [PATCH 1442/2457] nix: do not install development packages in user environment --- nix/shell.nix | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/nix/shell.nix b/nix/shell.nix index cbcea74f3..2c324158a 100644 --- a/nix/shell.nix +++ b/nix/shell.nix @@ -3,9 +3,5 @@ let artiqpkgs = import ./default.nix { inherit pkgs; }; in pkgs.mkShell { - buildInputs = with artiqpkgs; [ rustc cargo binutils-or1k llvm-or1k llvmlite migen misoc artiq ] - ++ (with pkgs; [ python3 python36Packages.jinja2 python36Packages.numpy ]); # for artiq the python lib... - shellHook = '' - export TARGET_AR=${artiqpkgs.binutils-or1k}/bin/or1k-linux-ar - ''; + buildInputs = with artiqpkgs; [ binutils-or1k llvm-or1k llvmlite artiq ]; } From 48793b7ecf70160ca1cdbc821c39826264d8bba5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Jan 2019 23:39:38 +0800 Subject: [PATCH 1443/2457] nix: reorganize .nix files --- nix/default.nix | 8 ++++---- nix/{ => pkgs}/artiq.nix | 2 +- nix/{ => pkgs}/binutils-or1k.nix | 0 nix/{ => pkgs}/llvm-or1k.nix | 0 nix/{ => pkgs}/llvmlite.nix | 0 5 files changed, 5 insertions(+), 5 deletions(-) rename nix/{ => pkgs}/artiq.nix (99%) rename nix/{ => pkgs}/binutils-or1k.nix (100%) rename nix/{ => pkgs}/llvm-or1k.nix (100%) rename nix/{ => pkgs}/llvmlite.nix (100%) diff --git a/nix/default.nix b/nix/default.nix index 5aaaf7621..a5df6aa72 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -10,9 +10,9 @@ let in rec { inherit (rust) cargo rustc; inherit (callPackage ./pkgs/python3Packages.nix {}) migen misoc; - binutils-or1k = callPackage ./binutils-or1k.nix {}; - llvm-or1k = callPackage ./llvm-or1k.nix { inherit llvm-src; }; - llvmlite = callPackage ./llvmlite.nix { inherit llvm-or1k; }; - artiq = callPackage ./artiq.nix { inherit binutils-or1k; inherit llvm-or1k; inherit llvmlite; }; + binutils-or1k = callPackage ./pkgs/binutils-or1k.nix {}; + llvm-or1k = callPackage ./pkgs/llvm-or1k.nix { inherit llvm-src; }; + llvmlite = callPackage ./pkgs/llvmlite.nix { inherit llvm-or1k; }; + artiq = callPackage ./pkgs/artiq.nix { inherit binutils-or1k; inherit llvm-or1k; inherit llvmlite; }; openocd = callPackage ./pkgs/openocd.nix {}; } diff --git a/nix/artiq.nix b/nix/pkgs/artiq.nix similarity index 99% rename from nix/artiq.nix rename to nix/pkgs/artiq.nix index c959c8a17..e5ee192da 100644 --- a/nix/artiq.nix +++ b/nix/pkgs/artiq.nix @@ -66,7 +66,7 @@ in python3Packages.buildPythonPackage rec { name = "artiq"; - src = ./..; + src = ./../..; propagatedBuildInputs = with python3Packages; [ binutils-or1k llvm-or1k llvmlite levenshtein pyqtgraph-qt5 aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; doCheck = false; meta = with stdenv.lib; { diff --git a/nix/binutils-or1k.nix b/nix/pkgs/binutils-or1k.nix similarity index 100% rename from nix/binutils-or1k.nix rename to nix/pkgs/binutils-or1k.nix diff --git a/nix/llvm-or1k.nix b/nix/pkgs/llvm-or1k.nix similarity index 100% rename from nix/llvm-or1k.nix rename to nix/pkgs/llvm-or1k.nix diff --git a/nix/llvmlite.nix b/nix/pkgs/llvmlite.nix similarity index 100% rename from nix/llvmlite.nix rename to nix/pkgs/llvmlite.nix From 7a6bdcb041a4c7d9742843777bcdd54b47870821 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 Jan 2019 16:04:25 +0800 Subject: [PATCH 1444/2457] nix: fix m-labs URLs --- nix/pkgs/python3Packages.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nix/pkgs/python3Packages.nix b/nix/pkgs/python3Packages.nix index cd102f416..4ce508f41 100644 --- a/nix/pkgs/python3Packages.nix +++ b/nix/pkgs/python3Packages.nix @@ -18,7 +18,7 @@ rec { meta = with stdenv.lib; { description = "asyncio support for pyserial"; - homepage = "https://m-labs.hk/gateware.html"; + homepage = "https://m-labs.hk"; license = licenses.bsd2; platforms = platforms.unix; }; @@ -43,7 +43,7 @@ rec { meta = with stdenv.lib; { description = "A high performance and small footprint system-on-chip based on Migen https://m-labs.hk"; - homepage = "https://m-labs.hk/gateware.html"; + homepage = "https://m-labs.hk/migen"; license = licenses.bsd2; platforms = platforms.unix; }; @@ -68,7 +68,7 @@ rec { meta = with stdenv.lib; { description = "A Python toolbox for building complex digital hardware"; - homepage = "https://m-labs.hk/gateware.html"; + homepage = "https://m-labs.hk/migen"; license = licenses.bsd2; platforms = platforms.unix; }; From d42d6075476861e77aa3a16c9a9259993356d541 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 Jan 2019 16:13:08 +0800 Subject: [PATCH 1445/2457] nix: add microscope --- nix/artiq-dev.nix | 2 +- nix/default.nix | 2 +- nix/pkgs/python3Packages.nix | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/nix/artiq-dev.nix b/nix/artiq-dev.nix index 89c079379..ad6ada554 100644 --- a/nix/artiq-dev.nix +++ b/nix/artiq-dev.nix @@ -16,7 +16,7 @@ in xorg.libXext xorg.libXtst xorg.libXi - (python3.withPackages(ps: with ps; [ jinja2 numpy artiqpkgs.migen artiqpkgs.misoc artiqpkgs.artiq ])) + (python3.withPackages(ps: with ps; [ jinja2 numpy artiqpkgs.migen artiqpkgs.microscope artiqpkgs.misoc artiqpkgs.artiq ])) ] ++ (with artiqpkgs; [ rustc diff --git a/nix/default.nix b/nix/default.nix index a5df6aa72..66c626540 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -9,7 +9,7 @@ let llvm-src = callPackage ./fetch-llvm-clang.nix {}; in rec { inherit (rust) cargo rustc; - inherit (callPackage ./pkgs/python3Packages.nix {}) migen misoc; + inherit (callPackage ./pkgs/python3Packages.nix {}) migen microscope misoc; binutils-or1k = callPackage ./pkgs/binutils-or1k.nix {}; llvm-or1k = callPackage ./pkgs/llvm-or1k.nix { inherit llvm-src; }; llvmlite = callPackage ./pkgs/llvmlite.nix { inherit llvm-or1k; }; diff --git a/nix/pkgs/python3Packages.nix b/nix/pkgs/python3Packages.nix index 4ce508f41..b34b0a9a1 100644 --- a/nix/pkgs/python3Packages.nix +++ b/nix/pkgs/python3Packages.nix @@ -73,4 +73,25 @@ rec { platforms = platforms.unix; }; }; + microscope = python3Packages.buildPythonPackage rec { + version = "git-02cffc"; + pname = "microscope"; + name = "${pname}-${version}"; + + src = fetchFromGitHub { + owner = "m-labs"; + repo = "microscope"; + rev = "02cffc360ec5a234c589de6cb9616b057ed22253"; + sha256 = "09yvgk16xfv5r5cf55vcg0f14wam42w53r4snlalcyw5gkm0rlhq"; + }; + + propagatedBuildInputs = with python3Packages; [ pyserial prettytable msgpack-python migen ]; + + meta = with stdenv.lib; { + description = "Finding the bacteria in rotting FPGA designs"; + homepage = "https://m-labs.hk/migen"; + license = licenses.bsd2; + platforms = platforms.unix; + }; + }; } From ec52a1003ddb0ed67547b2ea460b3914065ea76d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 Jan 2019 16:34:11 +0800 Subject: [PATCH 1446/2457] nix: add jesd204b --- nix/artiq-dev.nix | 2 +- nix/default.nix | 2 +- nix/pkgs/python3Packages.nix | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/nix/artiq-dev.nix b/nix/artiq-dev.nix index ad6ada554..38ef2dc9c 100644 --- a/nix/artiq-dev.nix +++ b/nix/artiq-dev.nix @@ -16,7 +16,7 @@ in xorg.libXext xorg.libXtst xorg.libXi - (python3.withPackages(ps: with ps; [ jinja2 numpy artiqpkgs.migen artiqpkgs.microscope artiqpkgs.misoc artiqpkgs.artiq ])) + (python3.withPackages(ps: with ps; [ jinja2 numpy artiqpkgs.migen artiqpkgs.microscope artiqpkgs.misoc artiqpkgs.jesd204b artiqpkgs.artiq ])) ] ++ (with artiqpkgs; [ rustc diff --git a/nix/default.nix b/nix/default.nix index 66c626540..90063b48d 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -9,7 +9,7 @@ let llvm-src = callPackage ./fetch-llvm-clang.nix {}; in rec { inherit (rust) cargo rustc; - inherit (callPackage ./pkgs/python3Packages.nix {}) migen microscope misoc; + inherit (callPackage ./pkgs/python3Packages.nix {}) migen microscope misoc jesd204b; binutils-or1k = callPackage ./pkgs/binutils-or1k.nix {}; llvm-or1k = callPackage ./pkgs/llvm-or1k.nix { inherit llvm-src; }; llvmlite = callPackage ./pkgs/llvmlite.nix { inherit llvm-or1k; }; diff --git a/nix/pkgs/python3Packages.nix b/nix/pkgs/python3Packages.nix index b34b0a9a1..f69f38887 100644 --- a/nix/pkgs/python3Packages.nix +++ b/nix/pkgs/python3Packages.nix @@ -94,4 +94,25 @@ rec { platforms = platforms.unix; }; }; + jesd204b = python3Packages.buildPythonPackage rec { + version = "git-02cffc"; + pname = "jesd204b"; + name = "${pname}-${version}"; + + src = fetchFromGitHub { + owner = "m-labs"; + repo = "jesd204b"; + rev = "03d3280690727b12b6522cbd294138e66dd157c9"; + sha256 = "1hpx4y8ynhsmwsq4ry748q6bkh8jvv2hy8b7hifxjmlh174y8rb0"; + }; + + propagatedBuildInputs = with python3Packages; [ migen misoc ]; + + meta = with stdenv.lib; { + description = "JESD204B core for Migen/MiSoC"; + homepage = "https://m-labs.hk/migen"; + license = licenses.bsd2; + platforms = platforms.unix; + }; + }; } From e85df13127a004261492437b45d65bea53864a55 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 Jan 2019 16:34:29 +0800 Subject: [PATCH 1447/2457] nix: update docs --- nix/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/README.rst b/nix/README.rst index c6f69e4d6..f0ac1eb40 100644 --- a/nix/README.rst +++ b/nix/README.rst @@ -28,7 +28,7 @@ The above command will setup your entire environment. Note that it will compile ARTIQ development environment with Nix ====================================== -Run ``nix-shell artiq-dev.nix`` to obtain an environment containing Migen, MiSoC, Clang, Rust, Cargo, and OpenOCD in addition to the user environment above. +Run ``nix-shell artiq-dev.nix`` to obtain an environment containing Migen, MiSoC, Microscope, jesd204b, Clang, Rust, Cargo, and OpenOCD in addition to the user environment above. This creates a FHS chroot environment in order to simplify the installation and patching of Xilinx Vivado (it needs to be installed manually e.g. in your home folder). From f5cda3689e36f564a1825828b3706223934981c8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 Jan 2019 16:41:11 +0800 Subject: [PATCH 1448/2457] sayma_amc: enable DRTIO on master SATA connector for MasterDAC variant --- artiq/gateware/targets/sayma_amc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 499cd55ca..4865203cc 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -279,7 +279,7 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): ] self.submodules.drtio_transceiver = gth_ultrascale.GTH( clock_pads=self.ad9154_crg.refclk, - data_pads=[platform.request("sfp", i) for i in range(2)], + data_pads=[platform.request("sata")] + [platform.request("sfp", i) for i in range(2)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") @@ -290,7 +290,7 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): drtioaux_csr_group = [] drtioaux_memory_group = [] drtio_cri = [] - for i in range(2): + for i in range(3): core_name = "drtio" + str(i) coreaux_name = "drtioaux" + str(i) memory_name = "drtioaux" + str(i) + "_mem" From cc58318500ecfa537abf24127f2c22e8fe66e0f8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 Jan 2019 22:29:27 +0800 Subject: [PATCH 1449/2457] siphaser: autocalibrate skew using RX synchronizer * removes the hardcoded, (poorly) manually determined skew value * does not need si5324_clkout_fabric anymore (broken on Sayma RTM due to wrong IO voltage) --- artiq/firmware/libboard_artiq/si5324.rs | 79 +++++++++---------------- artiq/firmware/satman/main.rs | 4 +- artiq/gateware/drtio/rx_synchronizer.py | 4 +- artiq/gateware/drtio/siphaser.py | 32 ++++++---- artiq/gateware/targets/kasli.py | 2 +- artiq/gateware/targets/sayma_amc.py | 2 +- 6 files changed, 54 insertions(+), 69 deletions(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 6cfc5f827..1f20438f0 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -291,66 +291,45 @@ pub mod siphaser { clock::spin_us(500); } - fn get_phaser_sample() -> bool { - let mut sample = true; - for _ in 0..32 { - if unsafe { csr::siphaser::sample_result_read() } == 0 { - sample = false; - } + fn has_error() -> bool { + unsafe { + csr::siphaser::error_write(1); + } + clock::spin_us(5000); + unsafe { + csr::siphaser::error_read() != 0 } - sample } - const PS_MARGIN: u32 = 28; + fn find_edge(target: bool) -> Result { + let mut nshifts = 0; - fn get_stable_phaser_sample() -> (bool, u32) { - let mut nshifts: u32 = 0; + let mut previous = has_error(); loop { - let s1 = get_phaser_sample(); - for _ in 0..PS_MARGIN { - phase_shift(1); - } - let s2 = get_phaser_sample(); - for _ in 0..PS_MARGIN { - phase_shift(1); - } - let s3 = get_phaser_sample(); - nshifts += 2*PS_MARGIN; - if s1 == s2 && s2 == s3 { - for _ in 0..PS_MARGIN { - phase_shift(0); - } - nshifts -= PS_MARGIN; - return (s2, nshifts); - } - } - } - - pub fn calibrate_skew(skew: u16) -> Result<()> { - // Get into a 0 region - let (s1, mut nshifts) = get_stable_phaser_sample(); - if s1 { - while get_phaser_sample() { - phase_shift(1); - nshifts += 1; - } - for _ in 0..PS_MARGIN { - phase_shift(1); - } - nshifts += PS_MARGIN; - } - - // Get to the 0->1 transition - while !get_phaser_sample() { phase_shift(1); nshifts += 1; + let current = has_error(); + if previous != target && current == target { + return Ok(nshifts); + } + if nshifts > 5000 { + return Err("failed to find timing error edge"); + } + previous = current; } - info!("nshifts to 0->1 siphaser transition: {} ({}deg)", nshifts, nshifts*360/(56*8)); + } - // Apply specified skew referenced to that transition - for _ in 0..skew { - phase_shift(1); + pub fn calibrate_skew() -> Result<()> { + let lead = find_edge(false)?; + let width = find_edge(true)?; + info!("calibration successful, lead: {}, width: {} ({}deg)", lead, width, width*360/(56*8)); + + // Apply reverse phase shift for half the width to get into the + // middle of the working region. + for _ in 0..width/2 { + phase_shift(0); } + Ok(()) } } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index a631af5a2..ede250c1b 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -394,8 +394,6 @@ const SI5324_SETTINGS: si5324::FrequencySettings crystal_ref: true }; -const SIPHASER_PHASE: u16 = 32; - #[no_mangle] pub extern fn main() -> i32 { clock::init(); @@ -443,7 +441,7 @@ pub extern fn main() -> i32 { info!("uplink is up, switching to recovered clock"); si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); - si5324::siphaser::calibrate_skew(SIPHASER_PHASE).expect("failed to calibrate skew"); + si5324::siphaser::calibrate_skew().expect("failed to calibrate skew"); #[cfg(has_ad9154)] { diff --git a/artiq/gateware/drtio/rx_synchronizer.py b/artiq/gateware/drtio/rx_synchronizer.py index 904e3cf17..90fddb97c 100644 --- a/artiq/gateware/drtio/rx_synchronizer.py +++ b/artiq/gateware/drtio/rx_synchronizer.py @@ -29,8 +29,8 @@ class XilinxRXSynchronizer(Module): """Deterministic RX synchronizer using a relatively placed macro to put the clock-domain-crossing FFs right next to each other. - To meet setup/hold constraints receiving FFs, adjust the phase shift - of the Si5324. + To meet setup/hold constraints at the receiving FFs, adjust the phase shift + of the jitter cleaner. We assume that FPGA routing variations are small enough to be negligible. """ diff --git a/artiq/gateware/drtio/siphaser.py b/artiq/gateware/drtio/siphaser.py index adbf72749..c9791d6de 100644 --- a/artiq/gateware/drtio/siphaser.py +++ b/artiq/gateware/drtio/siphaser.py @@ -1,5 +1,5 @@ from migen import * -from migen.genlib.cdc import MultiReg +from migen.genlib.cdc import MultiReg, PulseSynchronizer from misoc.interconnect.csr import * @@ -8,12 +8,12 @@ from misoc.interconnect.csr import * # frequency. class SiPhaser7Series(Module, AutoCSR): - def __init__(self, si5324_clkin, si5324_clkout_fabric, + def __init__(self, si5324_clkin, rx_synchronizer, ref_clk=None, ref_div2=False, rtio_clk_freq=150e6): self.switch_clocks = CSRStorage() self.phase_shift = CSR() self.phase_shift_done = CSRStatus(reset=1) - self.sample_result = CSRStatus() + self.error = CSR() assert rtio_clk_freq in (125e6, 150e6) @@ -85,16 +85,24 @@ class SiPhaser7Series(Module, AutoCSR): ) ] - si5324_clkout_se = Signal() - self.specials += \ - Instance("IBUFDS", - p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE", - i_I=si5324_clkout_fabric.p, i_IB=si5324_clkout_fabric.n, - o_O=si5324_clkout_se), + # The RX synchronizer is tested for setup/hold violations by feeding it a + # toggling pattern and checking that the same toggling pattern comes out. + toggle_in = Signal() + self.sync.rtio_rx0 += toggle_in.eq(~toggle_in) + toggle_out = rx_synchronizer.resync(toggle_in) - clkout_sample1 = Signal() # IOB register - self.sync.rtio_rx0 += clkout_sample1.eq(si5324_clkout_se) - self.specials += MultiReg(clkout_sample1, self.sample_result.status) + toggle_out_expected = Signal() + self.sync.rtio += toggle_out_expected.eq(~toggle_out) + + error = Signal() + error_clear = PulseSynchronizer("sys", "rtio") + self.submodules += error_clear + self.sync.rtio += [ + If(toggle_out != toggle_out_expected, error.eq(1)), + If(error_clear.o, error.eq(0)) + ] + self.specials += MultiReg(error, self.error.w) + self.comb += error_clear.i.eq(self.error.re) # expose MMCM outputs - used for clock constraints self.mmcm_freerun_output = mmcm_freerun_output diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 2d7f872d0..3b61a1a3b 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -1046,7 +1046,7 @@ class _SatelliteBase(BaseSoC): self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), - si5324_clkout_fabric=platform.request("si5324_clkout_fabric"), + rx_synchronizer=self.rx_synchronizer, ref_clk=self.crg.clk125_div2, ref_div2=True, rtio_clk_freq=rtio_clk_freq) platform.add_false_path_constraints( diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 4865203cc..98e46ebd0 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -641,7 +641,7 @@ class Satellite(BaseSoC, RTMCommon): self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), - si5324_clkout_fabric=platform.request("si5324_clkout_fabric")) + rx_synchronizer=self.rx_synchronizer) platform.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets {mmcm_ps}]", mmcm_ps=self.siphaser.mmcm_ps_output) platform.add_false_path_constraints( From ab9ca0ee0a6b77c051a5afd93de2ee6507dea2bf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 Jan 2019 23:03:57 +0800 Subject: [PATCH 1450/2457] kasli: use 150MHz for DRTIO by default (Sayma compatibility) --- artiq/gateware/targets/kasli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 3b61a1a3b..b5886e862 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -810,7 +810,7 @@ class _MasterBase(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, rtio_clk_freq=125e6, **kwargs): + def __init__(self, rtio_clk_freq=150e6, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -959,7 +959,7 @@ class _SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, rtio_clk_freq=125e6, **kwargs): + def __init__(self, rtio_clk_freq=150e6, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", From 77126ce5b384e0deaec3bfcce7cac76bac41d7ea Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 2 Jan 2019 23:04:20 +0800 Subject: [PATCH 1451/2457] kasli: use hwrev 1.1 by default for DRTIO examples --- artiq/gateware/targets/kasli.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b5886e862..0c335feb5 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -1091,8 +1091,10 @@ class _SatelliteBase(BaseSoC): class Master(_MasterBase): - def __init__(self, *args, **kwargs): - _MasterBase.__init__(self, *args, **kwargs) + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _MasterBase.__init__(self, hw_rev=hw_rev, **kwargs) self.rtio_channels = [] @@ -1112,8 +1114,10 @@ class Master(_MasterBase): class Satellite(_SatelliteBase): - def __init__(self, *args, **kwargs): - _SatelliteBase.__init__(self, *args, **kwargs) + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _SatelliteBase.__init__(self, hw_rev=hw_rev, **kwargs) self.rtio_channels = [] phy = ttl_simple.Output(self.platform.request("user_led", 0)) From 175f8b8ccc831971a4868e051123825c8c985fbe Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 3 Jan 2019 20:14:18 +0800 Subject: [PATCH 1452/2457] drtio/gth_ultrascale: generate multiplied RTIO clock from BUFG_GT (#792) --- .../drtio/transceiver/gth_ultrascale.py | 19 ++++++++++++------- artiq/gateware/targets/sayma_amc.py | 6 +++--- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index 30eed79fa..7ee7d54e8 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -14,7 +14,7 @@ from artiq.gateware.drtio.transceiver.gth_ultrascale_init import * class GTHSingle(Module): - def __init__(self, refclk, pads, sys_clk_freq, rtio_clk_freq, dw, mode): + def __init__(self, refclk, pads, sys_clk_freq, rtio_clk_freq, rtiox_mul, dw, mode): assert (dw == 20) or (dw == 40) assert mode in ["single", "master", "slave"] self.mode = mode @@ -441,7 +441,7 @@ class GTHSingle(Module): p_TX_PMADATA_OPT =0b0, p_TX_PMA_POWER_SAVE =0b0, p_TX_PROGCLK_SEL ="PREPI", - p_TX_PROGDIV_CFG =0.0, + p_TX_PROGDIV_CFG =dw/rtiox_mul, p_TX_QPI_STATUS_EN =0b0, p_TX_RXDETECT_CFG =0b00000000110010, p_TX_RXDETECT_REF =0b100, @@ -469,7 +469,7 @@ class GTHSingle(Module): o_TXOUTCLK=self.txoutclk, i_TXSYSCLKSEL=0b00, i_TXPLLCLKSEL=0b00, - i_TXOUTCLKSEL=0b11, + i_TXOUTCLKSEL=0b101, # TX Startup/Reset i_GTTXRESET=tx_init.gtXxreset, @@ -558,9 +558,12 @@ class GTHSingle(Module): tx_reset_deglitched.attr.add("no_retiming") self.sync += tx_reset_deglitched.eq(~tx_init.done) self.clock_domains.cd_rtio_tx = ClockDomain() + self.clock_domains.cd_rtiox_tx = ClockDomain() if mode == "master" or mode == "single": - self.specials += \ - Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk, i_DIV=0) + self.specials += [ + Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_rtiox_tx.clk, i_DIV=0), + Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk, i_DIV=rtiox_mul-1) + ] self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched) # rx clocking @@ -630,7 +633,7 @@ class GTHTXPhaseAlignement(Module): class GTH(Module, TransceiverInterface): - def __init__(self, clock_pads, data_pads, sys_clk_freq, rtio_clk_freq, dw=20, master=0): + def __init__(self, clock_pads, data_pads, sys_clk_freq, rtio_clk_freq, rtiox_mul=2, dw=20, master=0): self.nchannels = nchannels = len(data_pads) self.gths = [] @@ -655,7 +658,7 @@ class GTH(Module, TransceiverInterface): mode = "single" else: mode = "master" if i == master else "slave" - gth = GTHSingle(refclk, data_pads[i], sys_clk_freq, rtio_clk_freq, dw, mode) + gth = GTHSingle(refclk, data_pads[i], sys_clk_freq, rtio_clk_freq, rtiox_mul, dw, mode) if mode == "master": self.comb += rtio_tx_clk.eq(gth.cd_rtio_tx.clk) elif mode == "slave": @@ -669,6 +672,7 @@ class GTH(Module, TransceiverInterface): self.submodules.tx_phase_alignment = GTHTXPhaseAlignement(self.gths) TransceiverInterface.__init__(self, channel_interfaces) + self.cd_rtiox = ClockDomain(reset_less=True) if create_buf: # GTH PLLs recover on their own from an interrupted clock input, # but be paranoid about HMC7043 noise. @@ -677,6 +681,7 @@ class GTH(Module, TransceiverInterface): self.comb += [ self.cd_rtio.clk.eq(self.gths[master].cd_rtio_tx.clk), + self.cd_rtiox.clk.eq(self.gths[master].cd_rtiox_tx.clk), self.cd_rtio.rst.eq(reduce(or_, [gth.cd_rtio_tx.rst for gth in self.gths])) ] for i in range(nchannels): diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 98e46ebd0..bdf7a55ae 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -321,7 +321,7 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] - platform.add_period_constraint(gth.txoutclk, rtio_clk_period) + platform.add_period_constraint(gth.txoutclk, rtio_clk_period/2) platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( self.crg.cd_sys.clk, @@ -480,7 +480,7 @@ class Master(MiniSoC, AMPSoC): rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] - platform.add_period_constraint(gth.txoutclk, rtio_clk_period) + platform.add_period_constraint(gth.txoutclk, rtio_clk_period/2) platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( self.crg.cd_sys.clk, @@ -661,7 +661,7 @@ class Satellite(BaseSoC, RTMCommon): rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] - platform.add_period_constraint(gth.txoutclk, rtio_clk_period) + platform.add_period_constraint(gth.txoutclk, rtio_clk_period/2) platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( self.crg.cd_sys.clk, From 4af8fd6a0d02d0107cf2b846ae0b65221ca7d241 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 3 Jan 2019 20:14:54 +0800 Subject: [PATCH 1453/2457] ttl_serdes_ultrascale: fix Input --- artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py b/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py index c9e47fcf8..744e11a74 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py @@ -110,7 +110,7 @@ class InOut(ttl_serdes_generic.InOut): class Input(ttl_serdes_generic.InOut): - def __init__(self, pad, pad_n=None): + def __init__(self, dw, pad, pad_n=None): serdes = _ISERDESE3(dw, pad, pad_n) self.submodules += serdes ttl_serdes_generic.InOut.__init__(self, serdes) From d6a3172a3e7a0368d13494f6df69e71104739ffb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 3 Jan 2019 20:21:34 +0800 Subject: [PATCH 1454/2457] update copyright year --- README.rst | 2 +- artiq/firmware/bootloader/main.rs | 2 +- doc/manual/conf.py | 2 +- doc/manual/introduction.rst | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 5f6397c8b..fa93628a3 100644 --- a/README.rst +++ b/README.rst @@ -29,7 +29,7 @@ Website: https://m-labs.hk/artiq License ======= -Copyright (C) 2014-2018 M-Labs Limited. +Copyright (C) 2014-2019 M-Labs Limited. ARTIQ is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index c48adf77f..fc084d5e4 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -207,7 +207,7 @@ pub extern fn main() -> i32 { println!(r"|_| |_|_|____/ \___/ \____|"); println!(""); println!("MiSoC Bootloader"); - println!("Copyright (c) 2017-2018 M-Labs Limited"); + println!("Copyright (c) 2017-2019 M-Labs Limited"); println!(""); if startup() { diff --git a/doc/manual/conf.py b/doc/manual/conf.py index e32cf6a5a..fceb3d805 100644 --- a/doc/manual/conf.py +++ b/doc/manual/conf.py @@ -84,7 +84,7 @@ master_doc = 'index' # General information about the project. project = 'ARTIQ' -copyright = '2014-2018, M-Labs Limited' +copyright = '2014-2019, M-Labs Limited' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/doc/manual/introduction.rst b/doc/manual/introduction.rst index d628d2554..050ff3954 100644 --- a/doc/manual/introduction.rst +++ b/doc/manual/introduction.rst @@ -27,4 +27,4 @@ Website: https://m-labs.hk/artiq `Cite ARTIQ `_ as ``Bourdeauducq, Sébastien et al. (2016). ARTIQ 1.0. Zenodo. 10.5281/zenodo.51303``. -Copyright (C) 2014-2018 M-Labs Limited. Licensed under GNU LGPL version 3+. +Copyright (C) 2014-2019 M-Labs Limited. Licensed under GNU LGPL version 3+. From 10ebf63c47d01c673104ccaa42efea1809335bab Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 3 Jan 2019 20:22:35 +0800 Subject: [PATCH 1455/2457] jesd204_tools: get the Vivado timing analyzer to behave --- artiq/gateware/jesd204_tools.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index cdba0f7f6..5e8c5e85d 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -37,6 +37,7 @@ class UltrascaleCRG(Module, AutoCSR): ] if use_rtio_clock: + self.cd_jesd.clk.attr.add("keep") self.comb += self.cd_jesd.clk.eq(ClockSignal("rtio")) else: self.specials += Instance("BUFG_GT", i_I=refclk2, o_O=self.cd_jesd.clk) From f007895fad8fef840e73244492be6925184b9d44 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 3 Jan 2019 20:49:38 +0800 Subject: [PATCH 1456/2457] drtio/gth_ultrascale: fix rtiox clock domain --- artiq/gateware/drtio/transceiver/gth_ultrascale.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index 7ee7d54e8..e0d81bd5c 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -672,7 +672,7 @@ class GTH(Module, TransceiverInterface): self.submodules.tx_phase_alignment = GTHTXPhaseAlignement(self.gths) TransceiverInterface.__init__(self, channel_interfaces) - self.cd_rtiox = ClockDomain(reset_less=True) + self.clock_domains.cd_rtiox = ClockDomain(reset_less=True) if create_buf: # GTH PLLs recover on their own from an interrupted clock input, # but be paranoid about HMC7043 noise. From 0972d61e818ed425225ddd04e8151efdcb2b76ed Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 3 Jan 2019 20:50:04 +0800 Subject: [PATCH 1457/2457] ttl_serdes_ultrascale: use GTH clock domains --- artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py b/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py index 744e11a74..4231a8940 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_ultrascale.py @@ -3,9 +3,6 @@ from migen import * from artiq.gateware.rtio.phy import ttl_serdes_generic -# SERDES clocks are in dedicated domains to make the implementation -# of the convoluted clocking schemes from AR#67885 less tedious. - class _OSERDESE3(Module): def __init__(self, dw, pad, pad_n=None): self.o = Signal(dw) @@ -20,8 +17,8 @@ class _OSERDESE3(Module): p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, o_OQ=pad_o, o_T_OUT=self.t_out, - i_RST=ResetSignal("rtio_serdes"), - i_CLK=ClockSignal("rtiox_serdes"), i_CLKDIV=ClockSignal("rtio_serdes"), + i_RST=ResetSignal("rtio"), + i_CLK=ClockSignal("rtiox"), i_CLKDIV=ClockSignal("rtio"), i_D=self.o, i_T=self.t_in) if pad_n is None: self.comb += pad.eq(pad_o) @@ -49,11 +46,11 @@ class _ISERDESE3(Module): p_DATA_WIDTH=dw, i_D=pad_i, - i_RST=ResetSignal("rtio_serdes"), + i_RST=ResetSignal("rtio"), i_FIFO_RD_EN=0, - i_CLK=ClockSignal("rtiox_serdes"), - i_CLK_B=ClockSignal("rtiox_serdes"), # locally inverted - i_CLKDIV=ClockSignal("rtio_serdes"), + i_CLK=ClockSignal("rtiox"), + i_CLK_B=ClockSignal("rtiox"), # locally inverted + i_CLKDIV=ClockSignal("rtio"), o_Q=Cat(*[self.i[i] for i in reversed(range(dw))])) if pad_n is None: self.comb += pad_i.eq(pad) From 62d7c89c4841775285bbcdd9c47d00e5e0f52e13 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 3 Jan 2019 20:50:38 +0800 Subject: [PATCH 1458/2457] sayma_amc: use high-resolution TTL on SMAs (#792) --- artiq/gateware/targets/sayma_amc.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index bdf7a55ae..fe56269c8 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -18,7 +18,7 @@ from artiq.gateware import fmcdio_vhdci_eem from artiq.gateware import serwb, remote_csr from artiq.gateware import rtio from artiq.gateware import jesd204_tools -from artiq.gateware.rtio.phy import ttl_simple, sawg +from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_ultrascale, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer @@ -163,6 +163,9 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): phy = ttl_simple.Output(platform.request("user_led", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) + # To work around Ultrascale issues (https://www.xilinx.com/support/answers/67885.html), + # we generate the multiplied RTIO clock using the DRTIO GTH transceiver. + # Since there is no DRTIO here and therefoere no multiplied clock, we use ttl_simple. sma_io = platform.request("sma_io", 0) self.comb += sma_io.direction.eq(1) phy = ttl_simple.Output(sma_io.level) @@ -338,12 +341,12 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 0) self.comb += sma_io.direction.eq(1) - phy = ttl_simple.Output(sma_io.level) + phy = ttl_serdes_ultrascale.Output(4, sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 1) self.comb += sma_io.direction.eq(0) - phy = ttl_simple.InOut(sma_io.level) + phy = ttl_serdes_ultrascale.InOut(4, sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) @@ -497,12 +500,12 @@ class Master(MiniSoC, AMPSoC): rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 0) self.comb += sma_io.direction.eq(1) - phy = ttl_simple.Output(sma_io.level) + phy = ttl_serdes_ultrascale.Output(4, sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 1) self.comb += sma_io.direction.eq(0) - phy = ttl_simple.InOut(sma_io.level) + phy = ttl_serdes_ultrascale.InOut(4, sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) @@ -575,12 +578,12 @@ class Satellite(BaseSoC, RTMCommon): rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 0) self.comb += sma_io.direction.eq(1) - phy = ttl_simple.Output(sma_io.level) + phy = ttl_serdes_ultrascale.Output(4, sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) sma_io = platform.request("sma_io", 1) self.comb += sma_io.direction.eq(0) - phy = ttl_simple.InOut(sma_io.level) + phy = ttl_serdes_ultrascale.InOut(4, sma_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From a93fdb8c9d0a3f5c31bee776d50057d97d681541 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 4 Jan 2019 23:38:00 +0800 Subject: [PATCH 1459/2457] drtio: disable all destinations in gateware at startup Otherwise, kernels fail to get a RTIODestinationUnreachable exception when attempting to reach a DRTIO destination that has never been up. --- artiq/firmware/libboard_artiq/drtio_routing.rs | 7 +++++++ artiq/firmware/runtime/main.rs | 2 ++ 2 files changed, 9 insertions(+) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index 562517342..8e6c526fb 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -97,3 +97,10 @@ pub fn interconnect_enable_all(routing_table: &RoutingTable, rank: u8) { interconnect_enable(routing_table, rank, i as u8); } } + +#[cfg(has_drtio_routing)] +pub fn interconnect_disable_all() { + for i in 0..DEST_COUNT { + interconnect_disable(i as u8); + } +} diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index cbaeb1e26..c905d5df4 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -289,6 +289,8 @@ fn startup_ethernet() { drtio_routing::RoutingTable::default_empty())); let up_destinations = urc::Urc::new(RefCell::new( [false; drtio_routing::DEST_COUNT])); + #[cfg(has_drtio_routing)] + drtio_routing::interconnect_disable_all(); let aux_mutex = sched::Mutex::new(); let mut scheduler = sched::Scheduler::new(); From 3e5cea5d89e06d0ca38a287619733557a01a70d0 Mon Sep 17 00:00:00 2001 From: Drew Date: Tue, 27 Nov 2018 18:51:01 -0500 Subject: [PATCH 1460/2457] Docs: instructions to check if in plugdev group --- doc/manual/installing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index f16c2a814..fbe88517d 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -117,7 +117,7 @@ Configuring OpenOCD Some additional steps are necessary to ensure that OpenOCD can communicate with the FPGA board. -On Linux, first ensure that the current user belongs to the ``plugdev`` group. If it does not, run ``sudo adduser $USER plugdev`` and relogin. If you installed OpenOCD using conda and are using the conda environment ``artiq-main``, then execute the statements below. If you are using a different environment, you will have to replace ``artiq-main`` with the name of your environment:: +On Linux, first ensure that the current user belongs to the ``plugdev`` group (i.e. `plugdev` shown when you run `$ groups`). If it does not, run ``sudo adduser $USER plugdev`` and relogin. If you installed OpenOCD using conda and are using the conda environment ``artiq-main``, then execute the statements below. If you are using a different environment, you will have to replace ``artiq-main`` with the name of your environment:: $ sudo cp ~/.conda/envs/artiq-main/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d $ sudo udevadm trigger From b58d59a9e7eff3f6dcd1d0184d7b014f1446bc31 Mon Sep 17 00:00:00 2001 From: Drew Risinger Date: Fri, 4 Jan 2019 12:07:45 -0500 Subject: [PATCH 1461/2457] pyon: fix grammar in module docstring. Signed-off-by: Drew Risinger --- artiq/protocols/pyon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/protocols/pyon.py b/artiq/protocols/pyon.py index cfdaa892e..3ddef16a9 100644 --- a/artiq/protocols/pyon.py +++ b/artiq/protocols/pyon.py @@ -1,5 +1,5 @@ """ -This module provide serialization and deserialization functions for Python +This module provides serialization and deserialization functions for Python objects. Its main features are: * Human-readable format compatible with the Python syntax. From 94cdad6c1d8f34dc8990313f5779e2be98c6df27 Mon Sep 17 00:00:00 2001 From: Drew Date: Fri, 4 Jan 2019 21:22:12 -0500 Subject: [PATCH 1462/2457] artiq_flash: change docs from old `-m` arg to `-V` (#1224) (#1227) `-m` argument is deprecated. Changed to newer `-V` argument Closes #1224 Signed-off-by: Drew Risinger --- doc/manual/installing.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index fbe88517d..628f8bba5 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -147,7 +147,7 @@ Then, you can flash the board: * For the KC705 board (selecting the appropriate hardware peripheral):: - $ artiq_flash -t kc705 -m [nist_clock/nist_qc2] + $ artiq_flash -t kc705 -V [nist_clock/nist_qc2] The SW13 switches also need to be set to 00001. @@ -164,10 +164,10 @@ This should be done after either installation method (conda or source). .. _flash-mac-ip-addr: -* Set the MAC and IP address in the :ref:`core device configuration flash storage ` (see above for the ``-t`` and ``-m`` options to ``artiq_flash`` that may be required): :: +* Set the MAC and IP address in the :ref:`core device configuration flash storage ` (see above for the ``-t`` and ``-V`` options to ``artiq_flash`` that may be required): :: $ artiq_mkfs flash_storage.img -s mac xx:xx:xx:xx:xx:xx -s ip xx.xx.xx.xx - $ artiq_flash -t [board] -m [adapter] -f flash_storage.img storage start + $ artiq_flash -t [board] -V [adapter] -f flash_storage.img storage start * (optional) Flash the idle kernel From 2100a8b1f1b3ab281bac1e8450d61df1b57d30a2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 5 Jan 2019 12:25:30 +0800 Subject: [PATCH 1463/2457] sayma_amc: more fighting with vivado timing analyzer --- artiq/gateware/targets/sayma_amc.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index fe56269c8..3561eb7b6 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -326,13 +326,19 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): gth = self.drtio_transceiver.gths[0] platform.add_period_constraint(gth.txoutclk, rtio_clk_period/2) platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) + self.drtio_transceiver.cd_rtio.clk.attr.add("keep") platform.add_false_path_constraints( self.crg.cd_sys.clk, - gth.txoutclk, gth.rxoutclk) + self.drtio_transceiver.cd_rtio.clk, gth.rxoutclk) + platform.add_false_path_constraints(self.crg.cd_sys.clk, gth.txoutclk) for gth in self.drtio_transceiver.gths[1:]: platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( self.crg.cd_sys.clk, gth.rxoutclk) + platform.add_false_path_constraints( + self.drtio_transceiver.cd_rtio.clk, gth.rxoutclk) + platform.add_false_path_constraints(self.ad9154_crg.cd_jesd.clk, + self.drtio_transceiver.cd_rtio.clk) rtio_channels = [] for i in range(4): From d6fea221742f40cf4b3c4ad41c52c4d7db2aa11e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 5 Jan 2019 12:38:54 +0800 Subject: [PATCH 1464/2457] manual: update firmware/gateware build/flashing instructions. Closes #1223 --- doc/manual/developing.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index e562e1af6..1abea614e 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -56,7 +56,7 @@ Preparing the build environment for the core device --------------------------------------------------- These steps are required to generate code that can run on the core -device. They are necessary both for building the MiSoC BIOS +device. They are necessary both for building the firmware and the ARTIQ kernels. * Install required host packages: :: @@ -226,6 +226,10 @@ These steps are required to generate gateware bitstream (``.bit``) files, build .. _build-target-binaries: + * For Kasli:: + + $ python3 -m artiq.gateware.targets.kasli -V + * For KC705:: $ python3 -m artiq.gateware.targets.kc705 -V nist_clock # or nist_qc2 @@ -234,13 +238,9 @@ These steps are required to generate gateware bitstream (``.bit``) files, build .. _flash-target-binaries: -* Then, gather the binaries and flash them: :: +* Then, flash the binaries: :: - $ mkdir binaries - $ cp misoc_nist_qcX_/gateware/top.bit binaries - $ cp misoc_nist_qcX_/software/bios/bios.bin binaries - $ cp misoc_nist_qcX_/software/runtime/runtime.fbi binaries - $ artiq_flash -d binaries + $ artiq_flash --srcbuild artiq_kasli -V * Check that the board boots by running a serial terminal program (you may need to press its FPGA reconfiguration button or power-cycle it to load the gateware bitstream that was newly written into the flash): :: From 2c3510497b4ff4b7d6757ca89853c1494ea10c63 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 5 Jan 2019 23:40:03 +0800 Subject: [PATCH 1465/2457] firmware: fix not(has_spiflash) build --- artiq/firmware/libboard_misoc/config.rs | 79 +++++++++++++------------ 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/artiq/firmware/libboard_misoc/config.rs b/artiq/firmware/libboard_misoc/config.rs index c44ee36bb..7ed368efd 100644 --- a/artiq/firmware/libboard_misoc/config.rs +++ b/artiq/firmware/libboard_misoc/config.rs @@ -7,7 +7,8 @@ pub enum Error { Truncated { offset: usize }, InvalidSize { offset: usize, size: usize }, MissingSeparator { offset: usize }, - Utf8Error(str::Utf8Error) + Utf8Error(str::Utf8Error), + NoFlash, } impl fmt::Display for Error { @@ -24,40 +25,13 @@ impl fmt::Display for Error { &Error::MissingSeparator { offset } => write!(f, "missing separator at offset {}", offset), &Error::Utf8Error(err) => - write!(f, "{}", err) + write!(f, "{}", err), + &Error::NoFlash => + write!(f, "flash memory is not present"), } } } -struct FmtWrapper<'a> { - buf: &'a mut [u8], - offset: usize, -} - -impl<'a> FmtWrapper<'a> { - fn new(buf: &'a mut [u8]) -> Self { - FmtWrapper { - buf: buf, - offset: 0, - } - } - - fn contents(&self) -> &[u8] { - &self.buf[..self.offset] - } -} - -impl<'a> fmt::Write for FmtWrapper<'a> { - fn write_str(&mut self, s: &str) -> fmt::Result { - let bytes = s.as_bytes(); - let remainder = &mut self.buf[self.offset..]; - let remainder = &mut remainder[..bytes.len()]; - remainder.copy_from_slice(bytes); - self.offset += bytes.len(); - Ok(()) - } -} - #[cfg(has_spiflash)] mod imp { use core::str; @@ -65,8 +39,37 @@ mod imp { use cache; use spiflash; use super::Error; + use core::fmt; use core::fmt::Write; - use super::FmtWrapper; + + struct FmtWrapper<'a> { + buf: &'a mut [u8], + offset: usize, + } + + impl<'a> FmtWrapper<'a> { + fn new(buf: &'a mut [u8]) -> Self { + FmtWrapper { + buf: buf, + offset: 0, + } + } + + fn contents(&self) -> &[u8] { + &self.buf[..self.offset] + } + } + + impl<'a> fmt::Write for FmtWrapper<'a> { + fn write_str(&mut self, s: &str) -> fmt::Result { + let bytes = s.as_bytes(); + let remainder = &mut self.buf[self.offset..]; + let remainder = &mut remainder[..bytes.len()]; + remainder.copy_from_slice(bytes); + self.offset += bytes.len(); + Ok(()) + } + } // One flash sector immediately before the firmware. const ADDR: usize = ::mem::FLASH_BOOT_ADDRESS - spiflash::SECTOR_SIZE; @@ -284,24 +287,26 @@ mod imp { #[cfg(not(has_spiflash))] mod imp { + use super::Error; + pub fn read) -> R, R>(_key: &str, f: F) -> R { - f(Err(())) + f(Err(Error::NoFlash)) } pub fn read_str) -> R, R>(_key: &str, f: F) -> R { - f(Err(())) + f(Err(Error::NoFlash)) } pub fn write(_key: &str, _value: &[u8]) -> Result<(), Error> { - Err(()) + Err(Error::NoFlash) } pub fn remove(_key: &str) -> Result<(), Error> { - Err(()) + Err(Error::NoFlash) } pub fn erase() -> Result<(), Error> { - Err(()) + Err(Error::NoFlash) } } From cf9447ab77c847dfc3a5c329c82f55ba55e8555f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 5 Jan 2019 23:40:45 +0800 Subject: [PATCH 1466/2457] rtio/cri: remove unneeded CSR management --- artiq/gateware/rtio/cri.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 72acc879b..0c135a5b4 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -121,7 +121,7 @@ class KernelInitiator(Module, AutoCSR): self.sync += If(self.counter_update.re, self.counter.status.eq(tsc.full_ts_cri)) -class CRIDecoder(Module, AutoCSR): +class CRIDecoder(Module): def __init__(self, slaves=2, master=None, mode="async", enable_routing=False): if isinstance(slaves, int): slaves = [Interface() for _ in range(slaves)] @@ -228,7 +228,7 @@ class CRIInterconnectShared(Module): self.submodules.decoder = CRIDecoder(slaves, shared, mode, enable_routing) def get_csrs(self): - return self.switch.get_csrs() + self.decoder.get_csrs() + return self.switch.get_csrs() class RoutingTableAccess(Module, AutoCSR): From 6e43c411038c01ec6d3423db481790861d70e47c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 5 Jan 2019 23:41:30 +0800 Subject: [PATCH 1467/2457] firmware: support building without SDRAM --- artiq/firmware/libboard_misoc/lib.rs | 2 ++ artiq/firmware/libboard_misoc/or1k/cache.rs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/artiq/firmware/libboard_misoc/lib.rs b/artiq/firmware/libboard_misoc/lib.rs index ad941f00a..1b1b597d9 100644 --- a/artiq/firmware/libboard_misoc/lib.rs +++ b/artiq/firmware/libboard_misoc/lib.rs @@ -15,7 +15,9 @@ pub use arch::*; include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/mem.rs")); include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/csr.rs")); +#[cfg(has_dfii)] include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/sdram_phy.rs")); +#[cfg(has_dfii)] pub mod sdram; pub mod ident; pub mod clock; diff --git a/artiq/firmware/libboard_misoc/or1k/cache.rs b/artiq/firmware/libboard_misoc/or1k/cache.rs index 8e79b11ec..9357917c9 100644 --- a/artiq/firmware/libboard_misoc/or1k/cache.rs +++ b/artiq/firmware/libboard_misoc/or1k/cache.rs @@ -1,6 +1,9 @@ +#[cfg(has_ddrphy)] use core::ptr; use super::spr::*; +#[cfg(has_ddrphy)] use csr; +#[cfg(has_ddrphy)] use mem; pub fn flush_cpu_icache() { @@ -35,6 +38,7 @@ pub fn flush_cpu_dcache() { } } +#[cfg(has_ddrphy)] pub fn flush_l2_cache() { unsafe { for i in 0..2 * (csr::CONFIG_L2_SIZE as usize) / 4 { From 66b3132c28c4e8a02ee1c7169606b06dbc4f3c7b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Jan 2019 14:54:32 +0800 Subject: [PATCH 1468/2457] sayma_amc: fix RTIO TSC instantiation --- artiq/gateware/targets/sayma_amc.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 3561eb7b6..efefc2f45 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -287,7 +287,7 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") - self.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) drtio_csr_group = [] drtioaux_csr_group = [] @@ -452,7 +452,7 @@ class Master(MiniSoC, AMPSoC): rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") - self.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) + self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) drtio_csr_group = [] drtioaux_csr_group = [] @@ -623,7 +623,7 @@ class Satellite(BaseSoC, RTMCommon): rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") - self.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) + self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) rx0 = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) self.submodules.rx_synchronizer = rx0(XilinxRXSynchronizer()) From b5501aaf00852bda9ccc439a2236da5493548fcd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Jan 2019 14:54:52 +0800 Subject: [PATCH 1469/2457] firmware: program I2C switch on Sayma RTM --- artiq/firmware/libboard_artiq/si5324.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 1f20438f0..06b72ef74 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -11,6 +11,7 @@ const ADDRESS: u8 = 0x68; #[cfg(any(soc_platform = "kasli", soc_platform = "sayma_amc", + soc_platform = "sayma_rtm", soc_platform = "kc705"))] fn pca9548_select(address: u8, channels: u8) -> Result<()> { i2c::start(BUSNO).unwrap(); @@ -202,6 +203,8 @@ pub fn setup(settings: &FrequencySettings, input: Input) -> Result<()> { } #[cfg(soc_platform = "sayma_amc")] pca9548_select(0x70, 1 << 4)?; + #[cfg(soc_platform = "sayma_rtm")] + pca9548_select(0x77, 1 << 5)?; #[cfg(soc_platform = "kc705")] pca9548_select(0x74, 1 << 7)?; From 321748882404a782f0a93c14df8998dbdc537db7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 7 Jan 2019 00:13:47 +0800 Subject: [PATCH 1470/2457] add Sayma RTM DRTIO target --- artiq/gateware/targets/sayma_rtm_drtio.py | 223 ++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100755 artiq/gateware/targets/sayma_rtm_drtio.py diff --git a/artiq/gateware/targets/sayma_rtm_drtio.py b/artiq/gateware/targets/sayma_rtm_drtio.py new file mode 100755 index 000000000..22226aa87 --- /dev/null +++ b/artiq/gateware/targets/sayma_rtm_drtio.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python3 + +import argparse +import os +import subprocess +import struct + +from migen import * +from migen.genlib.cdc import MultiReg + +from misoc.interconnect.csr import * +from misoc.cores import gpio +from misoc.cores.a7_gtp import * +from misoc.targets.sayma_rtm import BaseSoC +from misoc.integration.builder import Builder, builder_args, builder_argdict + +from artiq.gateware import rtio +from artiq.gateware.rtio.phy import ttl_serdes_7series +from artiq.gateware.drtio.transceiver import gtp_7series +from artiq.gateware.drtio.siphaser import SiPhaser7Series +from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer +from artiq.gateware.drtio import * +from artiq.build_soc import add_identifier +from artiq import __artiq_dir__ as artiq_dir + + +def fix_serdes_timing_path(platform): + # ignore timing of path from OSERDESE2 through the pad to ISERDESE2 + platform.add_platform_command( + "set_false_path -quiet " + "-through [get_pins -filter {{REF_PIN_NAME == OQ || REF_PIN_NAME == TQ}} " + "-of [get_cells -filter {{REF_NAME == OSERDESE2}}]] " + "-to [get_pins -filter {{REF_PIN_NAME == D}} " + "-of [get_cells -filter {{REF_NAME == ISERDESE2}}]]" + ) + + +class _RTIOClockMultiplier(Module, AutoCSR): + def __init__(self, rtio_clk_freq): + self.pll_reset = CSRStorage(reset=1) + self.pll_locked = CSRStatus() + self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) + + # See "Global Clock Network Deskew Using Two BUFGs" in ug472. + clkfbout = Signal() + clkfbin = Signal() + rtiox4_clk = Signal() + pll_locked = Signal() + self.specials += [ + Instance("MMCME2_BASE", + p_CLKIN1_PERIOD=1e9/rtio_clk_freq, + i_CLKIN1=ClockSignal("rtio"), + i_RST=self.pll_reset.storage, + o_LOCKED=pll_locked, + + p_CLKFBOUT_MULT_F=8.0, p_DIVCLK_DIVIDE=1, + + o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbin, + + p_CLKOUT0_DIVIDE_F=2.0, o_CLKOUT0=rtiox4_clk, + ), + Instance("BUFG", i_I=clkfbout, o_O=clkfbin), + Instance("BUFG", i_I=rtiox4_clk, o_O=self.cd_rtiox4.clk), + + MultiReg(pll_locked, self.pll_locked.status) + ] + + +class _SatelliteBase(BaseSoC): + mem_map = { + "drtioaux": 0x50000000, + } + mem_map.update(BaseSoC.mem_map) + + def __init__(self, rtio_clk_freq=150e6, **kwargs): + BaseSoC.__init__(self, + cpu_type="or1k", + **kwargs) + add_identifier(self) + + platform = self.platform + + disable_si5324_ibuf = Signal(reset=1) + disable_si5324_ibuf.attr.add("no_retiming") + si5324_clkout = platform.request("si5324_clkout") + si5324_clkout_buf = Signal() + self.specials += Instance("IBUFDS_GTE2", + i_CEB=disable_si5324_ibuf, + i_I=si5324_clkout.p, i_IB=si5324_clkout.n, + o_O=si5324_clkout_buf) + qpll_drtio_settings = QPLLSettings( + refclksel=0b001, + fbdiv=4, + fbdiv_45=5, + refclk_div=1) + qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings) + self.submodules += qpll + + self.submodules.drtio_transceiver = gtp_7series.GTP( + qpll_channel=qpll.channels[0], + data_pads=[platform.request("sata", 0)], + sys_clk_freq=self.clk_freq, + rtio_clk_freq=rtio_clk_freq) + self.csr_devices.append("drtio_transceiver") + self.sync += disable_si5324_ibuf.eq( + ~self.drtio_transceiver.stable_clkin.storage) + + self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) + + cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"}) + + self.submodules.rx_synchronizer = cdr(XilinxRXSynchronizer()) + core = cdr(DRTIOSatellite( + self.rtio_tsc, self.drtio_transceiver.channels[0], + self.rx_synchronizer)) + self.submodules.drtiosat = core + self.csr_devices.append("drtiosat") + + coreaux = cdr(DRTIOAuxController(core.link_layer)) + self.submodules.drtioaux0 = coreaux + self.csr_devices.append("drtioaux0") + + memory_address = self.mem_map["drtioaux"] + self.add_wb_slave(memory_address, 0x800, + coreaux.bus) + self.add_memory_region("drtioaux0_mem", memory_address | self.shadow_base, 0x800) + + self.config["HAS_DRTIO"] = None + self.add_csr_group("drtioaux", ["drtioaux0"]) + self.add_memory_group("drtioaux_mem", ["drtioaux0_mem"]) + + self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) + self.submodules.siphaser = SiPhaser7Series( + si5324_clkin=platform.request("si5324_clkin"), + rx_synchronizer=self.rx_synchronizer, + ref_clk=self.crg.cd_sys.clk, ref_div2=True, + rtio_clk_freq=rtio_clk_freq) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) + self.csr_devices.append("siphaser") + self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("hmc7043_reset")) + self.csr_devices.append("si5324_rst_n") + i2c = self.platform.request("i2c") + self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) + self.csr_devices.append("i2c") + self.config["I2C_BUS_COUNT"] = 1 + self.config["HAS_SI5324"] = None + + rtio_clk_period = 1e9/rtio_clk_freq + gtp = self.drtio_transceiver.gtps[0] + platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) + platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, + gtp.txoutclk, gtp.rxoutclk) + + self.submodules.rtio_crg = _RTIOClockMultiplier(rtio_clk_freq) + self.csr_devices.append("rtio_crg") + fix_serdes_timing_path(platform) + + def add_rtio(self, rtio_channels): + self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) + self.csr_devices.append("rtio_moninj") + + self.submodules.local_io = SyncRTIO(self.rtio_tsc, rtio_channels) + self.comb += self.drtiosat.async_errors.eq(self.local_io.async_errors) + self.comb += self.drtiosat.cri.connect(self.local_io.cri) + + +class Satellite(_SatelliteBase): + def __init__(self, **kwargs): + _SatelliteBase.__init__(self, **kwargs) + + self.rtio_channels = [] + phy = ttl_serdes_7series.Output_8X(self.platform.request("allaki0_rfsw0")) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + phy = ttl_serdes_7series.Output_8X(self.platform.request("allaki0_rfsw1")) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.add_rtio(self.rtio_channels) + + +class SatmanSoCBuilder(Builder): + def __init__(self, *args, **kwargs): + Builder.__init__(self, *args, **kwargs) + firmware_dir = os.path.join(artiq_dir, "firmware") + self.software_packages = [] + self.add_software_package("satman", os.path.join(firmware_dir, "satman")) + + def initialize_memory(self): + satman = os.path.join(self.output_dir, "software", "satman", + "satman.bin") + with open(satman, "rb") as boot_file: + boot_data = [] + unpack_endian = ">I" + while True: + w = boot_file.read(4) + if not w: + break + boot_data.append(struct.unpack(unpack_endian, w)[0]) + + self.soc.main_ram.mem.init = boot_data + + +def main(): + parser = argparse.ArgumentParser( + description="ARTIQ device binary builder for Kasli systems") + builder_args(parser) + parser.set_defaults(output_dir="artiq_sayma_rtm") + args = parser.parse_args() + + soc = Satellite() + builder = SatmanSoCBuilder(soc, **builder_argdict(args)) + try: + builder.build() + except subprocess.CalledProcessError as e: + raise SystemExit("Command {} failed".format(" ".join(e.cmd))) + + +if __name__ == "__main__": + main() From 332bd6090f5a1494ae736c031a613078f5d48bbe Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 7 Jan 2019 17:09:19 +0800 Subject: [PATCH 1471/2457] satman: wait for CPLL/QPLL lock after setting drtio_transceiver::stable_clkin --- artiq/firmware/satman/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index ede250c1b..d7f757b99 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -416,6 +416,7 @@ pub extern fn main() -> i32 { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } + clock::spin_us(1500); // wait for CPLL/QPLL lock init_rtio_crg(); #[cfg(has_allaki_atts)] From 4d793d71496204884694ba8252ec76206aabbc19 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 8 Jan 2019 02:08:13 +0000 Subject: [PATCH 1472/2457] ad9910: Truncate phase word to 16 bits This avoids overflowing into the asf portion of the register. --- artiq/coredevice/ad9910.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 160cf11d9..3e2ac0094 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -415,7 +415,8 @@ class AD9910: # is equivalent to an output pipeline latency. dt = int32(now_mu()) - int32(ref_time) pow_ += dt*ftw*self.sysclk_per_mu >> 16 - self.write64(_AD9910_REG_PROFILE0 + profile, (asf << 16) | pow_, ftw) + self.write64(_AD9910_REG_PROFILE0 + profile, + (asf << 16) | (pow_ & 0xffff), ftw) delay_mu(int64(self.io_update_delay)) self.cpld.io_update.pulse_mu(8) # assumes 8 mu > t_SYSCLK at_mu(now_mu() & ~0xf) From 7bcdeb825be05a34adadbefa2eb7980d0f655335 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 8 Jan 2019 02:16:42 +0000 Subject: [PATCH 1473/2457] ad9910: Add inverse FTW/ASF conversions --- artiq/coredevice/ad9910.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 3e2ac0094..e08313de3 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -468,23 +468,37 @@ class AD9910: """ return int32(round(self.ftw_per_hz*frequency)) + @portable(flags={"fast-math"}) + def ftw_to_frequency(self, ftw): + """Return the frequency corresponding to the given frequency tuning + word. + """ + return ftw / self.ftw_per_hz + @portable(flags={"fast-math"}) def turns_to_pow(self, turns): """Return the phase offset word corresponding to the given phase in turns.""" return int32(round(turns*0x10000)) - @portable(flags={"fast-math"}) - def amplitude_to_asf(self, amplitude): - """Return amplitude scale factor corresponding to given amplitude.""" - return int32(round(amplitude*0x3ffe)) - @portable(flags={"fast-math"}) def pow_to_turns(self, pow_): """Return the phase in turns corresponding to a given phase offset word.""" return pow_/0x10000 + @portable(flags={"fast-math"}) + def amplitude_to_asf(self, amplitude): + """Return amplitude scale factor corresponding to given fractional + amplitude.""" + return int32(round(amplitude*0x3ffe)) + + @portable(flags={"fast-math"}) + def asf_to_amplitude(self, asf): + """Return amplitude as a fraction of full scale corresponding to given + amplitude scale factor.""" + return asf / float(0x3ffe) + @kernel def set_frequency(self, frequency): return self.set_ftw(self.frequency_to_ftw(frequency)) From cadde970e12fc0ce92a9999987d49f254d62e76c Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 8 Jan 2019 02:37:58 +0000 Subject: [PATCH 1474/2457] urukul: Expand CPLD sync_sel explanation [nfc] --- artiq/coredevice/urukul.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 8c8ee340a..620eaf7da 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -133,8 +133,10 @@ class CPLD: internal MMCX. For hardware revision <= v1.2 valid options are: 0 - either XO or MMCX dependent on component population; 1 SMA. Unsupported clocking options are silently ignored. - :param sync_sel: SYNC_IN selection. 0 corresponds to SYNC_IN over EEM - from FPGA. 1 corresponds to SYNC_IN from DDS0. + :param sync_sel: SYNC (multi-chip synchronisation) signal source selection. + 0 corresponds to SYNC_IN being supplied by the FPGA via the EEM + connector. 1 corresponds to SYNC_OUT from DDS0 being distributed to the + other chips. :param rf_sw: Initial CPLD RF switch register setting (default: 0x0). Knowledge of this state is not transferred between experiments. :param att: Initial attenuator setting shift register (default: From 887cb110a74bc947022b7176fe00c2c2231ff96b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 8 Jan 2019 20:46:53 +0800 Subject: [PATCH 1475/2457] firmware: fix default DRTIO routing table --- artiq/firmware/libboard_artiq/drtio_routing.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index 8e6c526fb..27234d22c 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -16,10 +16,11 @@ impl RoutingTable { // default routing table is for star topology with no hops pub fn default_master(default_n_links: usize) -> RoutingTable { let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]); - for i in 0..default_n_links { + let n_entries = default_n_links + 1; // include local RTIO + for i in 0..n_entries { ret.0[i][0] = i as u8; } - for i in 1..default_n_links { + for i in 1..n_entries { ret.0[i][1] = 0x00; } ret From 0d3e7ba805b52bbc382784070d0a962ae4cd27c8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 8 Jan 2019 20:47:09 +0800 Subject: [PATCH 1476/2457] nix: add zlib in artiq-dev Needed by the Vivado installer. --- nix/artiq-dev.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nix/artiq-dev.nix b/nix/artiq-dev.nix index 38ef2dc9c..f5b125e65 100644 --- a/nix/artiq-dev.nix +++ b/nix/artiq-dev.nix @@ -9,6 +9,7 @@ in with pkgs; [ ncurses5 gnumake + zlib xorg.libSM xorg.libICE xorg.libXrender From 4fb434674da1fce78c7ec0fd1f3da4f44416d05a Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 8 Jan 2019 18:55:26 +0000 Subject: [PATCH 1477/2457] coredevice: Fix ad9910 __all__ exports --- artiq/coredevice/ad9910.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index e08313de3..53073db3c 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -16,7 +16,7 @@ __all__ = [ "PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE", "PHASE_MODE_TRACKING", "RAM_DEST_FTW", "RAM_DEST_POW", "RAM_DEST_ASF", "RAM_DEST_POWASF", "RAM_MODE_DIRECTSWITCH", "RAM_MODE_RAMPUP", "RAM_MODE_BIDIR_RAMP", - "RAM_MODE_CONT_BIDIR_RAMP", "RAM_MODE_CONT_RECIRCULATE", + "RAM_MODE_CONT_BIDIR_RAMP", "RAM_MODE_CONT_RAMPUP", ] From 40370c4d457f5038d107fe57ad55e8a67d8b6974 Mon Sep 17 00:00:00 2001 From: Drew Date: Tue, 8 Jan 2019 22:39:23 -0500 Subject: [PATCH 1478/2457] Docs: fix build warnings (#1234) * ad9910: finish CONT_RECIRCULATE -> CONT_RAMPUP Found while building docs. Forgot to refactor strings. Signed-off-by: Drew Risinger * spi2: reformat update_xfer_duration_mu docstring update_xfer_duration_mu docstring threw warning while building docs, didn't use consistent indent in warning. Signed-off-by: Drew Risinger --- artiq/coredevice/ad9910.py | 2 +- artiq/coredevice/spi2.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 53073db3c..2021b2830 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -441,7 +441,7 @@ class AD9910: :param mode: Profile RAM mode (:const:`RAM_MODE_DIRECTSWITCH`, :const:`RAM_MODE_RAMPUP`, :const:`RAM_MODE_BIDIR_RAMP`, :const:`RAM_MODE_CONT_BIDIR_RAMP`, or - :const:`RAM_MODE_CONT_RECIRCULATE`, default: + :const:`RAM_MODE_CONT_RAMPUP`, default: :const:`RAM_MODE_RAMPUP`) """ hi = (step << 8) | (end >> 2) diff --git a/artiq/coredevice/spi2.py b/artiq/coredevice/spi2.py index d6024b607..aa1045973 100644 --- a/artiq/coredevice/spi2.py +++ b/artiq/coredevice/spi2.py @@ -187,10 +187,10 @@ class SPIMaster: :meth:`__init__`. .. warning:: If this method is called while recording a DMA - sequence, the playback of the sequence will not update the - driver state. - When required, update the driver state manually (by calling - this method) after playing back a DMA sequence. + sequence, the playback of the sequence will not update the + driver state. + When required, update the driver state manually (by calling + this method) after playing back a DMA sequence. :param div: SPI clock divider (see: :meth:`set_config_mu`) :param length: SPI transfer length (see: :meth:`set_config_mu`) From 101ed5d534bfe697d5fbfaede98020e555775788 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 9 Jan 2019 03:40:15 +0000 Subject: [PATCH 1479/2457] examples: Fix DRTIO destination indices (#1231) Using the default routing table, links numbers and destinations are offset by 1, as destination 0 is local RTIO. --- .../kasli_sawgmaster/repository/sines_2sayma.py | 12 +++++++++--- .../repository/sines_urukul_sayma.py | 11 +++++++++-- .../sayma_masterdac/repository/sines_drtio.py | 5 +++-- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py index b6bc7884c..fab0c3693 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py @@ -6,12 +6,18 @@ class Sines2Sayma(EnvExperiment): self.setattr_device("core") self.sawgs = [self.get_device("sawg"+str(i)) for i in range(16)] + @kernel + def drtio_is_up(self): + for i in range(3): + if not self.core.get_rtio_destination_status(i): + return False + return True + @kernel def run(self): while True: print("waiting for DRTIO ready...") - while not (self.core.get_rtio_destination_status(0) and - self.core.get_rtio_destination_status(1)): + while not self.drtio_is_up(): pass print("OK") @@ -27,5 +33,5 @@ class Sines2Sayma(EnvExperiment): # Do not use a sub-multiple of oscilloscope sample rates. sawg.frequency0.set(9*MHz) - while self.core.get_rtio_destination_status(0) and self.core.get_rtio_destination_status(1): + while self.drtio_is_up(): pass diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py index 9b9ab68de..c23ea99a6 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py @@ -8,6 +8,13 @@ class SinesUrukulSayma(EnvExperiment): self.urukul_chs = [self.get_device("urukul0_ch" + str(i)) for i in range(4)] self.sawgs = [self.get_device("sawg"+str(i)) for i in range(8)] + @kernel + def drtio_is_up(self): + for i in range(2): + if not self.core.get_rtio_destination_status(i): + return False + return True + @kernel def run(self): # Note: when testing sync, do not reboot Urukul, as it is not @@ -23,7 +30,7 @@ class SinesUrukulSayma(EnvExperiment): while True: print("waiting for DRTIO ready...") - while not self.core.get_rtio_destination_status(0): + while not self.drtio_is_up(): pass print("OK") @@ -38,5 +45,5 @@ class SinesUrukulSayma(EnvExperiment): sawg.amplitude1.set(.4) sawg.frequency0.set(9*MHz) - while self.core.get_rtio_destination_status(0): + while self.drtio_is_up(): pass diff --git a/artiq/examples/sayma_masterdac/repository/sines_drtio.py b/artiq/examples/sayma_masterdac/repository/sines_drtio.py index 70a7b3484..ea1060940 100644 --- a/artiq/examples/sayma_masterdac/repository/sines_drtio.py +++ b/artiq/examples/sayma_masterdac/repository/sines_drtio.py @@ -10,8 +10,9 @@ class SAWGTestDRTIO(EnvExperiment): @kernel def run(self): core_log("waiting for DRTIO ready...") - while not self.core.get_rtio_destination_status(0): - pass + for i in range(3): + while not self.core.get_rtio_destination_status(i): + pass core_log("OK") self.core.reset() From b3b0b6f0a55baf41d3e5917afd0ea8e62ec3d8f8 Mon Sep 17 00:00:00 2001 From: Drew Date: Tue, 8 Jan 2019 22:40:55 -0500 Subject: [PATCH 1480/2457] artiq_influxdb: clarify argparse groups (#1212) Make names of argparse group variables relate to what they're doing. Meets Flake8. Signed-off-by: Drew Risinger --- artiq/frontend/artiq_influxdb.py | 45 ++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/artiq/frontend/artiq_influxdb.py b/artiq/frontend/artiq_influxdb.py index d13aca46a..3cc524f68 100755 --- a/artiq/frontend/artiq_influxdb.py +++ b/artiq/frontend/artiq_influxdb.py @@ -11,7 +11,10 @@ import time import numpy as np import aiohttp -from artiq.tools import * +from artiq.tools import ( + simple_network_args, verbosity_args, atexit_register_coroutine, + bind_address_from_args, init_logger, TaskObject +) from artiq.protocols.sync_struct import Subscriber from artiq.protocols.pc_rpc import Server from artiq.protocols import pyon @@ -27,34 +30,34 @@ def get_argparser(): "The default action on a key (dataset name) is to log it. " "Then the patterns are traversed in order and glob-matched " "with the key. " - "Optional + and - pattern prefixes specify whether to ignore or " + "Optional + and - pattern prefixes specify to either ignore or " "log keys matching the rest of the pattern. " "Default (in the absence of prefix) is to ignore. Last matched " "pattern takes precedence.") - group = parser.add_argument_group("master") - group.add_argument( + master_group = parser.add_argument_group("master") + master_group.add_argument( "--server-master", default="::1", help="hostname or IP of the master to connect to") - group.add_argument( + master_group.add_argument( "--port-master", default=3250, type=int, - help="TCP port to use to connect to the master") - group.add_argument( + help="TCP port to use to connect to the master (default: %(default)s") + master_group.add_argument( "--retry-master", default=5.0, type=float, help="retry timer for reconnecting to master") - group = parser.add_argument_group("database") - group.add_argument( + database_group = parser.add_argument_group("database") + database_group.add_argument( "--baseurl-db", default="http://localhost:8086", help="base URL to access InfluxDB (default: %(default)s)") - group.add_argument( + database_group.add_argument( "--user-db", default="", help="InfluxDB username") - group.add_argument( + database_group.add_argument( "--password-db", default="", help="InfluxDB password") - group.add_argument( + database_group.add_argument( "--database", default="db", help="database name to use") - group.add_argument( + database_group.add_argument( "--table", default="lab", help="table name to use") - group = parser.add_argument_group("filter") - group.add_argument( + filter_group = parser.add_argument_group("filter") + filter_group.add_argument( "--pattern-file", default="influxdb_patterns.cfg", help="file to load the patterns from (default: %(default)s). " "If the file is not found, no patterns are loaded " @@ -98,18 +101,20 @@ class DBWriter(TaskObject): while True: k, v, t = await self._queue.get() url = self.base_url + "/write" - params = {"u": self.user, "p": self.password, "db": self.database, - "precision": "ms"} + params = {"u": self.user, "p": self.password, + "db": self.database, "precision": "ms"} data = "{},dataset={} {} {}".format( self.table, k, format_influxdb(v), round(t*1e3)) try: - response = await session.post(url, params=params, data=data) - except: + response = await session.post(url, params=params, + data=data) + except Exception: logger.warning("got exception trying to update '%s'", k, exc_info=True) else: if response.status not in (200, 204): - content = (await response.content.read()).decode().strip() + content = (await response.content.read()).decode() \ + .strip() logger.warning("got HTTP status %d " "trying to update '%s': %s", response.status, k, content) From 62599c5f91982b9c9151144fbae16e6fa39be96a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 9 Jan 2019 13:46:18 +0800 Subject: [PATCH 1481/2457] firmware: use consistent terminology --- artiq/firmware/libboard_artiq/drtio_routing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/drtio_routing.rs b/artiq/firmware/libboard_artiq/drtio_routing.rs index 27234d22c..10ce489b1 100644 --- a/artiq/firmware/libboard_artiq/drtio_routing.rs +++ b/artiq/firmware/libboard_artiq/drtio_routing.rs @@ -13,7 +13,7 @@ pub const INVALID_HOP: u8 = 0xff; pub struct RoutingTable(pub [[u8; MAX_HOPS]; DEST_COUNT]); impl RoutingTable { - // default routing table is for star topology with no hops + // default routing table is for star topology with no repeaters pub fn default_master(default_n_links: usize) -> RoutingTable { let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]); let n_entries = default_n_links + 1; // include local RTIO From c7b18952b88311457925873eea4df14a51f85106 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 9 Jan 2019 13:47:08 +0800 Subject: [PATCH 1482/2457] sayma_amc: work around Ultrascale LVDS Toutbuf_delay_td_pad --- artiq/gateware/targets/sayma_amc.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index efefc2f45..25aa85b90 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -400,6 +400,17 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.csr_devices.append("sysref_sampler") +def workaround_us_lvds_tristate(platform): + # Those shoddy Kintex Ultrascale FPGAs take almost a microsecond to change the direction of a + # LVDS I/O buffer. The application has to cope with it and this cannot be handled at static + # timing analysis. Disable the latter for IOBUFDS. + # See: + # https://forums.xilinx.com/t5/Timing-Analysis/Delay-890-ns-in-OBUFTDS-in-Kintex-UltraScale/td-p/868364 + # FIXME: this is a bit zealous. Xilinx SR in progress to find a more selective command. + platform.add_platform_command( + "set_false_path -through [get_pins -filter {{REF_PIN_NAME == O}} -of [get_cells -filter {{REF_NAME == IOBUFDS}}]]") + + class Master(MiniSoC, AMPSoC): """ DRTIO master with 2 SFP ports plus 8 lanes on RTM. @@ -528,6 +539,7 @@ class Master(MiniSoC, AMPSoC): iostandard="LVDS") eem.Zotino.add_std(self, 3, ttl_simple.Output, iostandard="LVDS") + workaround_us_lvds_tristate(platform) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) From 9b213b17af129200ce5afa046021de9a7736487c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 9 Jan 2019 18:57:57 +0800 Subject: [PATCH 1483/2457] sayma_amc: forward RTM UART in Master variant as well --- artiq/gateware/targets/sayma_amc.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 25aa85b90..c8f68a5f0 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -441,6 +441,14 @@ class Master(MiniSoC, AMPSoC): platform = self.platform rtio_clk_freq = 150e6 + # forward RTM UART to second FTDI UART channel + serial_1 = platform.request("serial", 1) + serial_rtm = platform.request("serial_rtm") + self.comb += [ + serial_1.tx.eq(serial_rtm.rx), + serial_rtm.tx.eq(serial_1.rx) + ] + self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) self.csr_devices.append("si5324_rst_n") i2c = self.platform.request("i2c") From f8a94725e9a1aa28cafaca7d4df907b5a8775142 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 9 Jan 2019 18:58:22 +0800 Subject: [PATCH 1484/2457] manual: add precision about sequence errors --- doc/manual/rtio.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/manual/rtio.rst b/doc/manual/rtio.rst index ce69b2bcd..24e352131 100644 --- a/doc/manual/rtio.rst +++ b/doc/manual/rtio.rst @@ -126,7 +126,8 @@ Internally, the gateware stores output events in an array of FIFO buffers (the " Notes: * Strictly increasing timestamps never cause sequence errors. -* Configuring the gateware with more lanes for the RTIO core reduces the frequency of sequence errors. +* Configuring the gateware with more lanes for the RTIO core reduces the frequency of sequence errors. +* The number of lanes is a hard limit on the number of simultaneous RTIO output events. * Whether a particular sequence of timestamps causes a sequence error or not is fully deterministic (starting from a known RTIO state, e.g. after a reset). Adding a constant offset to the whole sequence does not affect the result. The offending event is discarded and the RTIO core keeps operating. From b25ab1fc88c27401f7e137cb1ef3fc2ac318c0cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 9 Jan 2019 16:07:31 +0000 Subject: [PATCH 1485/2457] ad9910: add more slack in tune_sync_delay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #1235 Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 2021b2830..732aa54f4 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -631,7 +631,7 @@ class AD9910: # integrate SMP_ERR statistics for a few hundred cycles delay(100*us) err = urukul_sta_smp_err(self.cpld.sta_read()) - delay(40*us) # slack + delay(100*us) # slack if not (err >> (self.chip_select - 4)) & 1: next_seed = in_delay break From 19748fe4958e732c1987fa39f80ab35216a118ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 9 Jan 2019 17:08:11 +0000 Subject: [PATCH 1486/2457] ad9910: fix RTIO fine timestamp nudging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the TSC was truncated to an even coarse RTIO periods before doing the setting SPI xfer. Afterwards the the IO update pulse would introduce at least one but less than two RTIO cycles. Ultimately the RTIO TSC was truncated again to even. If the SPI xfer takes an odd number of RTIO periods, then a subsequent xfer would collide. close #1229 Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 732aa54f4..37e48723f 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -400,8 +400,9 @@ class AD9910: """ if phase_mode == _PHASE_MODE_DEFAULT: phase_mode = self.phase_mode - # Align to coarse RTIO which aligns SYNC_CLK - at_mu(now_mu() & ~0xf) + # Align to coarse RTIO which aligns SYNC_CLK. I.e. clear fine TSC + # This will not cause a collision or sequence error. + at_mu(now_mu() & ~7) if phase_mode != PHASE_MODE_CONTINUOUS: # Auto-clear phase accumulator on IO_UPDATE. # This is active already for the next IO_UPDATE @@ -418,8 +419,8 @@ class AD9910: self.write64(_AD9910_REG_PROFILE0 + profile, (asf << 16) | (pow_ & 0xffff), ftw) delay_mu(int64(self.io_update_delay)) - self.cpld.io_update.pulse_mu(8) # assumes 8 mu > t_SYSCLK - at_mu(now_mu() & ~0xf) + self.cpld.io_update.pulse_mu(8) # assumes 8 mu > t_SYN_CCLK + at_mu(now_mu() & ~7) # clear fine TSC again if phase_mode != PHASE_MODE_CONTINUOUS: self.set_cfr1() # future IO_UPDATE will activate @@ -673,16 +674,17 @@ class AD9910: self.write32(_AD9910_REG_RAMP_RATE, 0x00010000) # dFTW = 1, (work around negative slope) self.write64(_AD9910_REG_RAMP_STEP, -1, 0) - # delay io_update after RTIO/2 edge - t = now_mu() + 0x10 & ~0xf + # delay io_update after RTIO edge + t = now_mu() + 8 & ~7 at_mu(t + delay_start) - self.cpld.io_update.pulse_mu(32 - delay_start) # realign + # assumes a maximum t_SYNC_CLK period + self.cpld.io_update.pulse_mu(16 - delay_start) # realign # disable DRG autoclear and LRR on io_update self.set_cfr1() # stop DRG self.write64(_AD9910_REG_RAMP_STEP, 0, 0) at_mu(t + 0x1000 + delay_stop) - self.cpld.io_update.pulse_mu(32 - delay_stop) # realign + self.cpld.io_update.pulse_mu(16 - delay_stop) # realign ftw = self.read32(_AD9910_REG_FTW) # read out effective FTW delay(100*us) # slack # disable DRG From 088530604ee269047f9ebaaba948f512d76d42bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 9 Jan 2019 17:27:42 +0000 Subject: [PATCH 1487/2457] test_ad9910: relax tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * tune_sync_delay: the opposite IO_UPDATE to SYNC_CLK alignment may not be perfectly mis-aligned * set_mu_speed: seems to be slower on the buildbot Signed-off-by: Robert Jördens --- artiq/test/coredevice/test_ad9910.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/test/coredevice/test_ad9910.py b/artiq/test/coredevice/test_ad9910.py index 923ff4508..462db210f 100644 --- a/artiq/test/coredevice/test_ad9910.py +++ b/artiq/test/coredevice/test_ad9910.py @@ -199,7 +199,7 @@ class AD9910Test(ExperimentCase): self.execute(AD9910Exp, "set_speed_mu") dt = self.dataset_mgr.get("dt") print(dt) - self.assertLess(dt, 10*us) + self.assertLess(dt, 11*us) def test_sync_window(self): self.execute(AD9910Exp, "sync_window") @@ -220,8 +220,8 @@ class AD9910Test(ExperimentCase): n = max(bins2) # no edge at optimal delay self.assertEqual(bins2[(dly + 1) & 3], 0) - # edge at expected position - self.assertEqual(bins2[(dly + 3) & 3], n) + # many edges near expected position + self.assertGreater(bins2[(dly + 3) & 3], n*.9) def test_sw_readback(self): self.execute(AD9910Exp, "sw_readback") From 721c6f3bcce8c09f75843dccdd2ba521122a81cf Mon Sep 17 00:00:00 2001 From: Drew Date: Wed, 9 Jan 2019 23:13:22 -0500 Subject: [PATCH 1488/2457] pc_rpc: fix handling of type annotations --- artiq/protocols/pc_rpc.py | 33 +++++++++++++++++++++++------- artiq/test/test_pc_rpc.py | 43 ++++++++++++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/artiq/protocols/pc_rpc.py b/artiq/protocols/pc_rpc.py index adecf25df..5fa6f0820 100644 --- a/artiq/protocols/pc_rpc.py +++ b/artiq/protocols/pc_rpc.py @@ -11,12 +11,12 @@ client passes a list as a parameter of an RPC method, and that method client's list. """ -import socket import asyncio +import inspect +import logging +import socket import threading import time -import logging -import inspect from operator import itemgetter from artiq.monkey_patches import * @@ -24,7 +24,6 @@ from artiq.protocols import pyon from artiq.protocols.asyncio_server import AsyncioServer as _AsyncioServer from artiq.protocols.packed_exceptions import * - logger = logging.getLogger(__name__) @@ -487,6 +486,27 @@ class Server(_AsyncioServer): else: self._noparallel = asyncio.Lock() + @staticmethod + def _document_function(function): + """ + Turn a function into a tuple of its arguments and documentation. + + Allows remote inspection of what methods are available on a local device. + + Args: + function (Callable): a Python function to be documented. + + Returns: + Tuple[dict, str]: tuple of (argument specifications, + function documentation). + Any type annotations are converted to strings (for PYON serialization). + """ + argspec_dict = dict(inspect.getfullargspec(function)._asdict()) + # Fix issue #1186: PYON can't serialize type annotations. + if any(argspec_dict.get("annotations", {})): + argspec_dict["annotations"] = str(argspec_dict["annotations"]) + return argspec_dict, inspect.getdoc(function) + async def _process_action(self, target, obj): if self._noparallel is not None: await self._noparallel.acquire() @@ -501,9 +521,7 @@ class Server(_AsyncioServer): if name.startswith("_"): continue method = getattr(target, name) - argspec = inspect.getfullargspec(method) - doc["methods"][name] = (dict(argspec._asdict()), - inspect.getdoc(method)) + doc["methods"][name] = self._document_function(method) if self.builtin_terminate: doc["methods"]["terminate"] = ( { @@ -515,6 +533,7 @@ class Server(_AsyncioServer): "kwonlydefaults": [], }, "Terminate the server.") + logger.debug("RPC docs for %s: %s", target, doc) return {"status": "ok", "ret": doc} elif obj["action"] == "call": logger.debug("calling %s", _PrettyPrintCall(obj)) diff --git a/artiq/test/test_pc_rpc.py b/artiq/test/test_pc_rpc.py index bd8ed96fd..2a3c3e866 100644 --- a/artiq/test/test_pc_rpc.py +++ b/artiq/test/test_pc_rpc.py @@ -1,13 +1,13 @@ -import unittest -import sys -import subprocess import asyncio +import inspect +import subprocess +import sys import time +import unittest import numpy as np -from artiq.protocols import pc_rpc, fire_and_forget - +from artiq.protocols import fire_and_forget, pc_rpc, pyon test_address = "::1" test_port = 7777 @@ -92,6 +92,38 @@ class RPCCase(unittest.TestCase): def test_asyncio_echo_autotarget(self): self._run_server_and_test(self._loop_asyncio_echo, pc_rpc.AutoTarget) + def test_rpc_encode_function(self): + """Test that `pc_rpc` can encode a function properly. + + Used in `get_rpc_method_list` part of + :meth:`artiq.protocols.pc_rpc.Server._process_action` + """ + + def _annotated_function( + arg1: str, arg2: np.ndarray = np.array([1, 2]) + ) -> np.ndarray: + """Sample docstring.""" + return arg1 + + argspec_documented, docstring = pc_rpc.Server._document_function( + _annotated_function + ) + print(argspec_documented) + self.assertEqual(docstring, "Sample docstring.") + + # purposefully ignore how argspec["annotations"] is treated. + # allows option to change PYON later to encode annotations. + argspec_master = dict(inspect.getfullargspec(_annotated_function)._asdict()) + argspec_without_annotation = argspec_master.copy() + del argspec_without_annotation["annotations"] + # check if all items (excluding annotations) are same in both dictionaries + self.assertLessEqual( + argspec_without_annotation.items(), argspec_documented.items() + ) + self.assertDictEqual( + argspec_documented, pyon.decode(pyon.encode(argspec_documented)) + ) + class FireAndForgetCase(unittest.TestCase): def _set_ok(self): @@ -130,5 +162,6 @@ def run_server(): finally: loop.close() + if __name__ == "__main__": run_server() From 99a0f61b353ef02863af9cdaa136485546baacc5 Mon Sep 17 00:00:00 2001 From: Drew Date: Wed, 9 Jan 2019 23:58:11 -0500 Subject: [PATCH 1489/2457] artiq_client: remove custom input validation for built-in argparse (#1185) --- artiq/frontend/artiq_client.py | 58 ++++++++++++++++------------------ 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/artiq/frontend/artiq_client.py b/artiq/frontend/artiq_client.py index 7f5c63d7c..cc1b45858 100755 --- a/artiq/frontend/artiq_client.py +++ b/artiq/frontend/artiq_client.py @@ -1,4 +1,10 @@ #!/usr/bin/env python3 +""" +Client to send commands to :mod:`artiq_master` and display results locally. + +The client can perform actions such as accessing/setting datasets, +scanning devices, scheduling experiments, and looking for experiments/devices. +""" import argparse import logging @@ -15,7 +21,7 @@ from artiq.protocols.pc_rpc import Client from artiq.protocols.sync_struct import Subscriber from artiq.protocols.broadcast import Receiver from artiq.protocols import pyon -from artiq.tools import short_format +from artiq.tools import short_format, parse_arguments def clear_screen(): @@ -46,7 +52,8 @@ def get_argparser(): "scheduling, default: %(default)s)") parser_add.add_argument("-t", "--timed", default=None, type=str, help="set a due date for the experiment") - parser_add.add_argument("-f", "--flush", default=False, action="store_true", + parser_add.add_argument("-f", "--flush", default=False, + action="store_true", help="flush the pipeline before preparing " "the experiment") parser_add.add_argument("-R", "--repository", default=False, @@ -80,10 +87,12 @@ def get_argparser(): help="name of the dataset") parser_set_dataset.add_argument("value", metavar="VALUE", help="value in PYON format") - parser_set_dataset.add_argument("-p", "--persist", action="store_true", - help="make the dataset persistent") - parser_set_dataset.add_argument("-n", "--no-persist", action="store_true", - help="make the dataset non-persistent") + + persist_group = parser_set_dataset.add_mutually_exclusive_group() + persist_group.add_argument("-p", "--persist", action="store_true", + help="make the dataset persistent") + persist_group.add_argument("-n", "--no-persist", action="store_true", + help="make the dataset non-persistent") parser_del_dataset = subparsers.add_parser( "del-dataset", help="delete a dataset") @@ -93,7 +102,8 @@ def get_argparser(): "show", help="show schedule, log, devices or datasets") parser_show.add_argument( "what", metavar="WHAT", - help="select object to show: schedule/log/devices/datasets") + choices=["schedule", "log", "ccb", "devices", "datasets"], + help="select object to show: %(choices)s") subparsers.add_parser( "scan-devices", help="trigger a device database (re)scan") @@ -114,20 +124,11 @@ def get_argparser(): return parser -def _parse_arguments(arguments): - d = {} - for argument in arguments: - name, value = argument.split("=") - d[name] = pyon.decode(value) - return d - - def _action_submit(remote, args): try: - arguments = _parse_arguments(args.arguments) - except: - print("Failed to parse run arguments") - sys.exit(1) + arguments = parse_arguments(args.arguments) + except Exception as err: + raise ValueError("Failed to parse run arguments") from err expid = { "log_level": logging.WARNING + args.quiet*10 - args.verbose*10, @@ -154,10 +155,6 @@ def _action_delete(remote, args): def _action_set_dataset(remote, args): - if args.persist and args.no_persist: - print("Options --persist and --no-persist cannot be specified " - "at the same time") - sys.exit(1) persist = None if args.persist: persist = True @@ -190,13 +187,13 @@ def _action_ls(remote, args): def _show_schedule(schedule): clear_screen() if schedule: - l = sorted(schedule.items(), - key=lambda x: (-x[1]["priority"], - x[1]["due_date"] or 0, - x[0])) + sorted_schedule = sorted(schedule.items(), + key=lambda x: (-x[1]["priority"], + x[1]["due_date"] or 0, + x[0])) table = PrettyTable(["RID", "Pipeline", " Status ", "Prio", "Due date", "Revision", "File", "Class name"]) - for rid, v in l: + for rid, v in sorted_schedule: row = [rid, v["pipeline"], v["status"], v["priority"]] if v["due_date"] is None: row.append("") @@ -252,6 +249,7 @@ def _run_subscriber(host, port, subscriber): def _show_dict(args, notifier_name, display_fun): d = dict() + def init_d(x): d.clear() d.update(x) @@ -299,8 +297,7 @@ def main(): elif args.what == "datasets": _show_dict(args, "datasets", _show_datasets) else: - print("Unknown object to show, use -h to list valid names.") - sys.exit(1) + raise ValueError else: port = 3251 if args.port is None else args.port target_name = { @@ -318,5 +315,6 @@ def main(): finally: remote.close_rpc() + if __name__ == "__main__": main() From 58e872e7b5951d4e4d4c65f0f7716f69a737daf1 Mon Sep 17 00:00:00 2001 From: Drew Date: Thu, 10 Jan 2019 00:01:36 -0500 Subject: [PATCH 1490/2457] doc: document artiq_coreanalyzer usage. (#1233) --- doc/manual/getting_started_core.rst | 1 + doc/manual/utilities.rst | 2 ++ 2 files changed, 3 insertions(+) diff --git a/doc/manual/getting_started_core.rst b/doc/manual/getting_started_core.rst index a5d77cd38..f4d3c8300 100644 --- a/doc/manual/getting_started_core.rst +++ b/doc/manual/getting_started_core.rst @@ -174,6 +174,7 @@ Within a parallel block, some statements can be made sequential again using a `` self.ttl1.pulse(4*us) delay(4*us) +.. _rtio-analyzer-example: RTIO analyzer ------------- diff --git a/doc/manual/utilities.rst b/doc/manual/utilities.rst index ab31d5d1c..6bb712f78 100644 --- a/doc/manual/utilities.rst +++ b/doc/manual/utilities.rst @@ -172,6 +172,8 @@ You do not need to remove a record in order to change its value, just overwrite Core device RTIO analyzer tool ------------------------------ +:mod:`~artiq.frontend.artiq_coreanalyzer` is a tool to convert core device RTIO logs to VCD waveform files that are readable by third-party tools such as GtkWave. This tool extracts pre-recorded data from an ARTIQ core device buffer (or from a file with the ``-r`` option), and converts it to a standard VCD file format. See :ref:`rtio-analyzer-example` for an example, or :mod:`artiq.test.coredevice.test_analyzer` for a relevant unit test. + .. argparse:: :ref: artiq.frontend.artiq_coreanalyzer.get_argparser :prog: artiq_coreanalyzer From 101671fbbf20f06b8143bbf3baf09908e0098e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 10 Jan 2019 19:32:58 +0100 Subject: [PATCH 1491/2457] core_analyzer: support uniform VCD time intervals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #1236 Signed-off-by: Robert Jördens --- artiq/coredevice/comm_analyzer.py | 23 +++++++++++++++++++---- artiq/frontend/artiq_coreanalyzer.py | 15 +++++++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/artiq/coredevice/comm_analyzer.py b/artiq/coredevice/comm_analyzer.py index c6a2a3da4..be5902724 100644 --- a/artiq/coredevice/comm_analyzer.py +++ b/artiq/coredevice/comm_analyzer.py @@ -501,11 +501,13 @@ def get_message_time(message): return getattr(message, "timestamp", message.rtio_counter) -def decoded_dump_to_vcd(fileobj, devices, dump): +def decoded_dump_to_vcd(fileobj, devices, dump, uniform_interval=False): vcd_manager = VCDManager(fileobj) ref_period = get_ref_period(devices) + if ref_period is not None: - vcd_manager.set_timescale_ps(ref_period*1e12) + if not uniform_interval: + vcd_manager.set_timescale_ps(ref_period*1e12) else: logger.warning("unable to determine core device ref_period") ref_period = 1e-9 # guess @@ -527,6 +529,12 @@ def decoded_dump_to_vcd(fileobj, devices, dump): vcd_log_channels = get_vcd_log_channels(dump.log_channel, messages) channel_handlers[dump.log_channel] = LogHandler( vcd_manager, vcd_log_channels) + if uniform_interval: + # RTIO event timestamp in machine units + timestamp = vcd_manager.get_channel("timestamp", 64) + # RTIO time interval between this and the next timed event + # in SI seconds + interval = vcd_manager.get_channel("interval", 64) slack = vcd_manager.get_channel("rtio_slack", 64) vcd_manager.set_time(0) @@ -536,11 +544,18 @@ def decoded_dump_to_vcd(fileobj, devices, dump): if start_time: break - for message in messages: + t0 = 0 + for i, message in enumerate(messages): if message.channel in channel_handlers: t = get_message_time(message) - start_time if t >= 0: - vcd_manager.set_time(t) + if uniform_interval: + interval.set_value_double((t - t0)*ref_period) + vcd_manager.set_time(i) + timestamp.set_value("{:064b}".format(t)) + t0 = t + else: + vcd_manager.set_time(t) channel_handlers[message.channel].process_message(message) if isinstance(message, OutputMessage): slack.set_value_double( diff --git a/artiq/frontend/artiq_coreanalyzer.py b/artiq/frontend/artiq_coreanalyzer.py index 0a5fad21b..96ea83ee6 100755 --- a/artiq/frontend/artiq_coreanalyzer.py +++ b/artiq/frontend/artiq_coreanalyzer.py @@ -16,16 +16,22 @@ def get_argparser(): verbosity_args(parser) parser.add_argument("--device-db", default="device_db.py", - help="device database file (default: '%(default)s')") + help="device database file (default: '%(default)s')") parser.add_argument("-r", "--read-dump", type=str, default=None, help="read raw dump file instead of accessing device") - parser.add_argument("-p", "--print-decoded", default=False, action="store_true", - help="print raw decoded messages") + parser.add_argument("-p", "--print-decoded", default=False, + action="store_true", help="print raw decoded messages") parser.add_argument("-w", "--write-vcd", type=str, default=None, help="format and write contents to VCD file") parser.add_argument("-d", "--write-dump", type=str, default=None, help="write raw dump file") + + parser.add_argument("-u", "--vcd-uniform-interval", action="store_true", + help="emit uniform time intervals between timed VCD " + "events and show RTIO event interval (in SI " + "seconds) and timestamp (in machine units) as " + "separate VCD channels") return parser @@ -54,7 +60,8 @@ def main(): if args.write_vcd: with open(args.write_vcd, "w") as f: decoded_dump_to_vcd(f, device_mgr.get_device_db(), - decoded_dump) + decoded_dump, + uniform_interval=args.vcd_uniform_interval) if args.write_dump: with open(args.write_dump, "wb") as f: f.write(dump) From 66861e6708f901230664b983f9850ffc142e918b Mon Sep 17 00:00:00 2001 From: Drew Date: Thu, 10 Jan 2019 21:15:44 -0500 Subject: [PATCH 1492/2457] test_pc_rpc: fix equality bug (#1188) (#1239) Fixes bug from 5108ed8. Truth value of multi-element numpy array is not defined. Completes #1186 and fixes/amends #1188. Signed-off-by: Drew Risinger --- artiq/test/test_pc_rpc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/test_pc_rpc.py b/artiq/test/test_pc_rpc.py index 2a3c3e866..4ca81d020 100644 --- a/artiq/test/test_pc_rpc.py +++ b/artiq/test/test_pc_rpc.py @@ -100,7 +100,7 @@ class RPCCase(unittest.TestCase): """ def _annotated_function( - arg1: str, arg2: np.ndarray = np.array([1, 2]) + arg1: str, arg2: np.ndarray = np.array([1,]) ) -> np.ndarray: """Sample docstring.""" return arg1 From b3ef6e22532456426367b0e799e02ce10425ac0e Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 12 Jan 2019 00:13:24 +0000 Subject: [PATCH 1493/2457] doc: Minor typo fix/rewording in drtio.rst --- doc/manual/drtio.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual/drtio.rst b/doc/manual/drtio.rst index 1b05cf25c..350a4b8b4 100644 --- a/doc/manual/drtio.rst +++ b/doc/manual/drtio.rst @@ -98,14 +98,14 @@ Real-time and auxiliary packets DRTIO is a packet-based protocol that uses two types of packets: * real-time packets, which are transmitted at high priority at a high bandwidth and are used for the bulk of RTIO commands and data. In the ARTIQ DRTIO implementation, real-time packets are processed entirely in gateware. -* auxiliary packets, which are lower-bandwidth and are used for ancilliary tasks such as housekeeping and monitoring/injection. Auxiliary packets are low-priority and their transmission has no impact on the timing of real-time packets (however, transmission of real-time packets slows down the transmission of auxiliary packets). In the ARTIQ DRTIO implementation, the contents of the auxiliary packets are read and written directly by the firmware, with the gateware simply handling the transmission of the raw data. +* auxiliary packets, which are lower-bandwidth and are used for ancillary tasks such as housekeeping and monitoring/injection. Auxiliary packets are low-priority and their transmission has no impact on the timing of real-time packets (however, transmission of real-time packets slows down the transmission of auxiliary packets). In the ARTIQ DRTIO implementation, the contents of the auxiliary packets are read and written directly by the firmware, with the gateware simply handling the transmission of the raw data. Link layer ++++++++++ The lower layer of the DRTIO protocol stack is the link layer, which is responsible for delimiting real-time and auxiliary packets, and assisting with the establishment of a fixed-latency high speed serial transceiver link. -DRTIO uses the IBM (Widmer and Franaszek) 8b/10b encoding. The two types of 8b/10b codes are used: D characters, that always transmit real-time packet data, and K characters, that are used for idling and transmitting auxiliary packet data. +DRTIO uses the IBM (Widmer and Franaszek) 8b/10b encoding. D characters (the encoded 8b symbols) always transmit real-time packet data, whereas K characters are used for idling and transmitting auxiliary packet data. At every logic clock cycle, the high-speed transceiver hardware transmits some amount N of 8b/10b characters (typically, N is 2 or 4) and receives the same amount. With DRTIO, those characters must be all of the D type or all of the K type; mixing D and K characters in the same logic clock cycle is not allowed. @@ -119,7 +119,7 @@ The series of K selection words is then used to form auxiliary packets and the i Both real-time traffic and K selection words are scrambled in order to make the generated electromagnetic interference practically independent from the DRTIO traffic. A multiplicative scrambler is used and its state is shared between the real-time traffic and K selection words, so that real-time data can be descrambled immediately after the scrambler has been synchronized from the K characters. Another positive effect of the scrambling is that commas always appear regularly in the absence of any traffic (and in practice also appear regularly on a busy link). This makes a receiver always able to synchronize itself to an idling transmitter, which removes the need for relatively complex link initialization states. -Due to the use of K characters both as delimiters for real-time packets and as information carrier for auxiliary packets, auxiliary traffic is guaranteed a minimum bandwith simply by having a maximum size limit on real-time packets. +Due to the use of K characters both as delimiters for real-time packets and as information carrier for auxiliary packets, auxiliary traffic is guaranteed a minimum bandwidth simply by having a maximum size limit on real-time packets. Clocking ++++++++ From 3e84ec2bf1d32e063dd22f59f65aef62a24c9911 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 12 Jan 2019 00:43:15 +0000 Subject: [PATCH 1494/2457] coredevice.ad9910: Fix phase tracking ref_time passing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is difficult to test without hardware mocks or some form of phase readback, but the symptom was that e.g. `self.dds.set(…, ref_time=now_mu() - 1)` would fail periodically, that is, whenever bit 32 of the timestamp would be set (which would be turned into the sign bit). This is a fairly sinister issue, and is probably a compiler bug of some sort (either accepts-invalid or wrong type inference). --- artiq/coredevice/ad9910.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 37e48723f..6b5717655 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -371,9 +371,11 @@ class AD9910: self.set_cfr1(power_down=bits) self.cpld.io_update.pulse(1*us) + # KLUDGE: ref_time default argument is explicitly marked int64() to avoid + # silent truncation of explicitly passed timestamps. (Compiler bug?) @kernel def set_mu(self, ftw, pow_=0, asf=0x3fff, phase_mode=_PHASE_MODE_DEFAULT, - ref_time=-1, profile=0): + ref_time=int64(-1), profile=0): """Set profile 0 data in machine units. This uses machine units (FTW, POW, ASF). The frequency tuning word @@ -514,7 +516,7 @@ class AD9910: @kernel def set(self, frequency, phase=0.0, amplitude=1.0, - phase_mode=_PHASE_MODE_DEFAULT, ref_time=-1, profile=0): + phase_mode=_PHASE_MODE_DEFAULT, ref_time=int64(-1), profile=0): """Set profile 0 data in SI units. .. seealso:: :meth:`set_mu` From f2c1d32e54e4a2a5a51952d67e96426d3b0a1de8 Mon Sep 17 00:00:00 2001 From: Drew Date: Fri, 11 Jan 2019 20:47:47 -0500 Subject: [PATCH 1495/2457] frontend: add --version flag to cmd line args (#1181) --- RELEASE_NOTES.rst | 2 +- artiq/frontend/aqctl_korad_ka3005p.py | 2 +- artiq/frontend/aqctl_lda.py | 2 +- artiq/frontend/aqctl_novatech409b.py | 2 +- artiq/frontend/aqctl_thorlabs_tcube.py | 2 +- artiq/frontend/artiq_browser.py | 4 ++-- artiq/frontend/artiq_client.py | 7 ++---- artiq/frontend/artiq_compile.py | 2 +- artiq/frontend/artiq_coreanalyzer.py | 4 ++-- artiq/frontend/artiq_coremgmt.py | 4 ++-- artiq/frontend/artiq_ctlmgr.py | 8 ++----- artiq/frontend/artiq_dashboard.py | 4 ++-- artiq/frontend/artiq_devtool.py | 4 ++-- artiq/frontend/artiq_flash.py | 4 ++-- artiq/frontend/artiq_influxdb.py | 2 +- artiq/frontend/artiq_run.py | 2 +- artiq/tools.py | 33 ++++++++++++++++---------- doc/manual/developing_a_ndsp.rst | 6 ++--- 18 files changed, 48 insertions(+), 46 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index b48faa796..6e6c3c6ce 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -8,7 +8,7 @@ ARTIQ-5 5.0 *** - +* :func:`~artiq.tools.verbosity_args` renamed to :func:`~artiq.tools.add_common_args`. New feature: adds an option to print the ARTIQ version. ARTIQ-4 diff --git a/artiq/frontend/aqctl_korad_ka3005p.py b/artiq/frontend/aqctl_korad_ka3005p.py index fb9ba6712..850e46262 100755 --- a/artiq/frontend/aqctl_korad_ka3005p.py +++ b/artiq/frontend/aqctl_korad_ka3005p.py @@ -26,7 +26,7 @@ def get_argparser(): parser.add_argument( "--simulation", action="store_true", help="Put the driver in simulation mode, even if --device is used.") - verbosity_args(parser) + add_common_args(parser) return parser diff --git a/artiq/frontend/aqctl_lda.py b/artiq/frontend/aqctl_lda.py index cf3a36aae..429e0e6df 100755 --- a/artiq/frontend/aqctl_lda.py +++ b/artiq/frontend/aqctl_lda.py @@ -23,7 +23,7 @@ def get_argparser(): "available device will be used.") parser.add_argument("--simulation", action="store_true", help="Put the driver in simulation mode.") - verbosity_args(parser) + add_common_args(parser) return parser diff --git a/artiq/frontend/aqctl_novatech409b.py b/artiq/frontend/aqctl_novatech409b.py index 3cc9ce7a4..60b6c92de 100755 --- a/artiq/frontend/aqctl_novatech409b.py +++ b/artiq/frontend/aqctl_novatech409b.py @@ -26,7 +26,7 @@ def get_argparser(): parser.add_argument( "--simulation", action="store_true", help="Put the driver in simulation mode, even if --device is used.") - verbosity_args(parser) + add_common_args(parser) return parser diff --git a/artiq/frontend/aqctl_thorlabs_tcube.py b/artiq/frontend/aqctl_thorlabs_tcube.py index e8e489c3e..dea1a0d65 100755 --- a/artiq/frontend/aqctl_thorlabs_tcube.py +++ b/artiq/frontend/aqctl_thorlabs_tcube.py @@ -22,7 +22,7 @@ def get_argparser(): help="Put the driver in simulation mode, even if " "--device is used.") simple_network_args(parser, 3255) - verbosity_args(parser) + add_common_args(parser) return parser diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index 692558616..5076225c7 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -10,7 +10,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets from quamash import QEventLoop from artiq import __artiq_dir__ as artiq_dir -from artiq.tools import (verbosity_args, atexit_register_coroutine, +from artiq.tools import (add_common_args, atexit_register_coroutine, get_user_config_dir) from artiq.gui import state, applets, models, log from artiq.browser import datasets, files, experiments @@ -38,7 +38,7 @@ def get_argparser(): help="TCP port to use to connect to the master") parser.add_argument("select", metavar="SELECT", nargs="?", help="directory to browse or file to load") - verbosity_args(parser) + add_common_args(parser) return parser diff --git a/artiq/frontend/artiq_client.py b/artiq/frontend/artiq_client.py index cc1b45858..e197d9896 100755 --- a/artiq/frontend/artiq_client.py +++ b/artiq/frontend/artiq_client.py @@ -21,7 +21,7 @@ from artiq.protocols.pc_rpc import Client from artiq.protocols.sync_struct import Subscriber from artiq.protocols.broadcast import Receiver from artiq.protocols import pyon -from artiq.tools import short_format, parse_arguments +from artiq.tools import short_format, add_common_args, parse_arguments def clear_screen(): @@ -64,10 +64,7 @@ def get_argparser(): "(defaults to head, ignored without -R)") parser_add.add_argument("-c", "--class-name", default=None, help="name of the class to run") - parser_add.add_argument("-v", "--verbose", default=0, action="count", - help="increase logging level of the experiment") - parser_add.add_argument("-q", "--quiet", default=0, action="count", - help="decrease logging level of the experiment") + add_common_args(parser) parser_add.add_argument("file", metavar="FILE", help="file containing the experiment to run") parser_add.add_argument("arguments", metavar="ARGUMENTS", nargs="*", diff --git a/artiq/frontend/artiq_compile.py b/artiq/frontend/artiq_compile.py index 83cf3c079..766190200 100755 --- a/artiq/frontend/artiq_compile.py +++ b/artiq/frontend/artiq_compile.py @@ -15,7 +15,7 @@ logger = logging.getLogger(__name__) def get_argparser(): parser = argparse.ArgumentParser(description="ARTIQ static compiler") - verbosity_args(parser) + add_common_args(parser) parser.add_argument("--device-db", default="device_db.py", help="device database file (default: '%(default)s')") parser.add_argument("--dataset-db", default="dataset_db.pyon", diff --git a/artiq/frontend/artiq_coreanalyzer.py b/artiq/frontend/artiq_coreanalyzer.py index 96ea83ee6..2bd965004 100755 --- a/artiq/frontend/artiq_coreanalyzer.py +++ b/artiq/frontend/artiq_coreanalyzer.py @@ -3,7 +3,7 @@ import argparse import sys -from artiq.tools import verbosity_args, init_logger +from artiq.tools import add_common_args, init_logger from artiq.master.databases import DeviceDB from artiq.master.worker_db import DeviceManager from artiq.coredevice.comm_analyzer import (get_analyzer_dump, @@ -14,7 +14,7 @@ def get_argparser(): parser = argparse.ArgumentParser(description="ARTIQ core device " "RTIO analysis tool") - verbosity_args(parser) + add_common_args(parser) parser.add_argument("--device-db", default="device_db.py", help="device database file (default: '%(default)s')") diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index 11b75628d..270e01cc4 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -3,7 +3,7 @@ import argparse import struct -from artiq.tools import verbosity_args, init_logger +from artiq.tools import add_common_args, init_logger from artiq.master.databases import DeviceDB from artiq.coredevice.comm_kernel import CommKernel from artiq.coredevice.comm_mgmt import CommMgmt @@ -14,7 +14,7 @@ def get_argparser(): parser = argparse.ArgumentParser(description="ARTIQ core device " "management tool") - verbosity_args(parser) + add_common_args(parser) parser.add_argument("--device-db", default="device_db.py", help="device database file (default: '%(default)s')") parser.add_argument("-D", "--device", default=None, diff --git a/artiq/frontend/artiq_ctlmgr.py b/artiq/frontend/artiq_ctlmgr.py index 6aeaee0f6..c16ed9b50 100755 --- a/artiq/frontend/artiq_ctlmgr.py +++ b/artiq/frontend/artiq_ctlmgr.py @@ -10,18 +10,14 @@ import platform from artiq.protocols.pc_rpc import Server from artiq.protocols.logging import LogForwarder, SourceFilter from artiq.tools import (simple_network_args, atexit_register_coroutine, - bind_address_from_args) + bind_address_from_args, add_common_args) from artiq.devices.ctlmgr import ControllerManager def get_argparser(): parser = argparse.ArgumentParser(description="ARTIQ controller manager") - group = parser.add_argument_group("verbosity") - group.add_argument("-v", "--verbose", default=0, action="count", - help="increase logging level of the manager process") - group.add_argument("-q", "--quiet", default=0, action="count", - help="decrease logging level of the manager process") + add_common_args(parser) parser.add_argument( "-s", "--server", default="::1", diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index 3ee539713..98d3c2e53 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -10,7 +10,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets from quamash import QEventLoop from artiq import __artiq_dir__ as artiq_dir, __version__ as artiq_version -from artiq.tools import (atexit_register_coroutine, verbosity_args, +from artiq.tools import (atexit_register_coroutine, add_common_args, get_user_config_dir) from artiq.protocols.pc_rpc import AsyncioClient, Client from artiq.protocols.broadcast import Receiver @@ -39,7 +39,7 @@ def get_argparser(): help="database file for local GUI settings, " "by default in {} and dependant on master hostname".format( get_user_config_dir())) - verbosity_args(parser) + add_common_args(parser) return parser diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py index aacd813c7..e23f766fe 100755 --- a/artiq/frontend/artiq_devtool.py +++ b/artiq/frontend/artiq_devtool.py @@ -16,7 +16,7 @@ import shutil import re import shlex -from artiq.tools import verbosity_args, init_logger +from artiq.tools import add_common_args, init_logger from artiq.remoting import SSHClient from artiq.coredevice.comm_mgmt import CommMgmt @@ -28,7 +28,7 @@ def get_argparser(): description="ARTIQ core device development tool", formatter_class=argparse.ArgumentDefaultsHelpFormatter) - verbosity_args(parser) + add_common_args(parser) parser.add_argument("-t", "--target", metavar="TARGET", type=str, default="kasli", diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 783bc6264..bece15b71 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -11,7 +11,7 @@ from functools import partial from collections import defaultdict from artiq import __artiq_dir__ as artiq_dir -from artiq.tools import verbosity_args, init_logger +from artiq.tools import add_common_args, init_logger from artiq.remoting import SSHClient, LocalClient from artiq.frontend.bit2bin import bit2bin @@ -41,7 +41,7 @@ Prerequisites: plugdev group: 'sudo adduser $USER plugdev' and re-login. """) - verbosity_args(parser) + add_common_args(parser) parser.add_argument("-n", "--dry-run", default=False, action="store_true", diff --git a/artiq/frontend/artiq_influxdb.py b/artiq/frontend/artiq_influxdb.py index 3cc524f68..9650f5a7c 100755 --- a/artiq/frontend/artiq_influxdb.py +++ b/artiq/frontend/artiq_influxdb.py @@ -63,7 +63,7 @@ def get_argparser(): "If the file is not found, no patterns are loaded " "(everything is logged).") simple_network_args(parser, [("control", "control", 3248)]) - verbosity_args(parser) + add_common_args(parser) return parser diff --git a/artiq/frontend/artiq_run.py b/artiq/frontend/artiq_run.py index 962e7a5e5..bc4f81ff5 100755 --- a/artiq/frontend/artiq_run.py +++ b/artiq/frontend/artiq_run.py @@ -126,7 +126,7 @@ def get_argparser(with_file=True): parser = argparse.ArgumentParser( description="Local experiment running tool") - verbosity_args(parser) + add_common_args(parser) parser.add_argument("--device-db", default="device_db.py", help="device database file (default: '%(default)s')") parser.add_argument("--dataset-db", default="dataset_db.pyon", diff --git a/artiq/tools.py b/artiq/tools.py index 69d8351b5..e5517bebe 100644 --- a/artiq/tools.py +++ b/artiq/tools.py @@ -1,22 +1,21 @@ +import asyncio +import atexit +import collections import importlib.machinery import logging -import sys -import asyncio -import collections -import atexit -import string import os +import string +import sys import numpy as np +from artiq import __version__ as artiq_version +from artiq.appdirs import user_config_dir from artiq.language.environment import is_experiment from artiq.protocols import pyon -from artiq.appdirs import user_config_dir -from artiq import __version__ as artiq_version - __all__ = ["parse_arguments", "elide", "short_format", "file_import", - "get_experiment", "verbosity_args", "simple_network_args", + "get_experiment", "add_common_args", "simple_network_args", "multiline_log_config", "init_logger", "bind_address_from_args", "atexit_register_coroutine", "exc_to_warning", "asyncio_wait_or_cancel", "TaskObject", "Condition", @@ -105,12 +104,22 @@ def get_experiment(module, experiment=None): return exps[0][1] -def verbosity_args(parser): - group = parser.add_argument_group("verbosity") +def add_common_args(parser): + """Add common utility arguments to the cmd parser. + + Arguments added: + * `-v`/`-q`: increase or decrease the default logging levels. + Repeat for higher levels. + * `--version`: print the ARTIQ version + """ + group = parser.add_argument_group("common") group.add_argument("-v", "--verbose", default=0, action="count", help="increase logging level") group.add_argument("-q", "--quiet", default=0, action="count", help="decrease logging level") + group.add_argument("--version", action="version", + version="ARTIQ v{}".format(artiq_version), + help="print the ARTIQ version number") def simple_network_args(parser, default_port): @@ -127,7 +136,7 @@ def simple_network_args(parser, default_port): help="TCP port to listen on (default: %(default)d)") else: for name, purpose, default in default_port: - h = ("TCP port to listen on for {} connections (default: {})" + h = ("TCP port for {} connections (default: {})" .format(purpose, default)) group.add_argument("--port-" + name, default=default, type=int, help=h) diff --git a/doc/manual/developing_a_ndsp.rst b/doc/manual/developing_a_ndsp.rst index 4989aded6..1d786ca97 100644 --- a/doc/manual/developing_a_ndsp.rst +++ b/doc/manual/developing_a_ndsp.rst @@ -132,14 +132,14 @@ We suggest that you define a function ``get_argparser`` that returns the argumen Logging ------- -For the debug, information and warning messages, use the ``logging`` Python module and print the log on the standard error output (the default setting). The logging level is by default "WARNING", meaning that only warning messages and more critical messages will get printed (and no debug nor information messages). By calling the ``verbosity_args()`` with the parser as argument, you add support for the ``--verbose`` (``-v``) and ``--quiet`` (``-q``) arguments in the parser. Each occurence of ``-v`` (resp. ``-q``) in the arguments will increase (resp. decrease) the log level of the logging module. For instance, if only one ``-v`` is present in the arguments, then more messages (info, warning and above) will get printed. If only one ``-q`` is present in the arguments, then only errors and critical messages will get printed. If ``-qq`` is present in the arguments, then only critical messages will get printed, but no debug/info/warning/error. +For the debug, information and warning messages, use the ``logging`` Python module and print the log on the standard error output (the default setting). The logging level is by default "WARNING", meaning that only warning messages and more critical messages will get printed (and no debug nor information messages). By calling :func:`artiq.tools.add_common_args` with the parser as argument, you add support for the ``--verbose`` (``-v``) and ``--quiet`` (``-q``) arguments in the parser. Each occurence of ``-v`` (resp. ``-q``) in the arguments will increase (resp. decrease) the log level of the logging module. For instance, if only one ``-v`` is present in the arguments, then more messages (info, warning and above) will get printed. If only one ``-q`` is present in the arguments, then only errors and critical messages will get printed. If ``-qq`` is present in the arguments, then only critical messages will get printed, but no debug/info/warning/error. The program below exemplifies how to use logging: :: import argparse import logging - from artiq.tools import verbosity_args, init_logger + from artiq.tools import add_common_args, init_logger # get a logger that prints the module name @@ -151,7 +151,7 @@ The program below exemplifies how to use logging: :: parser.add_argument("--someargument", help="some argument") # [...] - verbosity_args(parser) # This adds the -q and -v handling + add_common_args(parser) # This adds the -q and -v handling return parser From 48fc175a6b619d02cfd728ceef009c518bd1be88 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 12 Jan 2019 12:01:55 +0000 Subject: [PATCH 1496/2457] coredevice.ttl: More imperative mood in docstrings [nfc] This follows Python conventions (PEP257) and unifies the style with other comments. --- artiq/coredevice/ttl.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 4c281904a..78f36ef8b 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -46,7 +46,7 @@ class TTLOut: @kernel def on(self): - """Sets the output to a logic high state at the current position + """Set the output to a logic high state at the current position of the time cursor. The time cursor is not modified by this function.""" @@ -176,7 +176,7 @@ class TTLInOut: @kernel def pulse_mu(self, duration): - """Pulses the output high for the specified duration + """Pulse the output high for the specified duration (in machine units). The time cursor is advanced by the specified duration.""" @@ -186,7 +186,7 @@ class TTLInOut: @kernel def pulse(self, duration): - """Pulses the output high for the specified duration + """Pulse the output high for the specified duration (in seconds). The time cursor is advanced by the specified duration.""" From f3323a35d56bc1a833ee9140f2a90f948ba7f324 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 12 Jan 2019 12:02:22 +0000 Subject: [PATCH 1497/2457] artiq_influxdb: Unbreak after verbosity_args rename This fixes commit f2c1d32e54e4a2a5a51952d67e96426d3b0a1de8. --- artiq/frontend/artiq_influxdb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_influxdb.py b/artiq/frontend/artiq_influxdb.py index 9650f5a7c..f0ffa350d 100755 --- a/artiq/frontend/artiq_influxdb.py +++ b/artiq/frontend/artiq_influxdb.py @@ -12,7 +12,7 @@ import numpy as np import aiohttp from artiq.tools import ( - simple_network_args, verbosity_args, atexit_register_coroutine, + simple_network_args, add_common_args, atexit_register_coroutine, bind_address_from_args, init_logger, TaskObject ) from artiq.protocols.sync_struct import Subscriber From cd725a8352618cfc3309b6bdaf2a5a84987dc316 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 12 Jan 2019 12:11:03 +0000 Subject: [PATCH 1498/2457] manual: Slightly untangle rtio input paragraph [nfc] This is just an attempt at making the explanation slightly easier to skim, based on user feedback. --- doc/manual/rtio.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/manual/rtio.rst b/doc/manual/rtio.rst index 24e352131..769e6a27a 100644 --- a/doc/manual/rtio.rst +++ b/doc/manual/rtio.rst @@ -158,15 +158,14 @@ Input channels and events Input channels detect events, timestamp them, and place them in a buffer for the experiment to read out. The following example counts the rising edges occurring during a precisely timed 500 ns interval. -If more than 20 rising edges were received it outputs a pulse:: +If more than 20 rising edges are received, it outputs a pulse:: if input.count(input.gate_rising(500*ns)) > 20: delay(2*us) output.pulse(500*ns) -The :meth:`artiq.coredevice.ttl.TTLInOut.count` method of an input channel can lead to a situation of negative slack (timeline cursor ``now`` smaller than the current wall clock ``rtio_counter``): -The :meth:`artiq.coredevice.ttl.TTLInOut.gate_rising` method leaves the timeline cursor at the closure time of the gate and ``count()`` must necessarily wait until the gate closing event has actually been executed which is sometime with ``rtio_counter > now``. -In these situations where ``count()`` leads to a synchronization of timeline cursor and wall clock, a ``delay()`` is necessary to reestablish positive slack (i.e. set the timeline cursor ``now`` greater than the current wall clock ``rtio_counter``) so that output events can be placed. +The :meth:`artiq.coredevice.ttl.TTLInOut.count` method of an input channel will often lead to a situation of negative slack (timeline cursor ``now`` smaller than the current wall clock ``rtio_counter``): +The :meth:`artiq.coredevice.ttl.TTLInOut.gate_rising` method leaves the timeline cursor at the closing time of the gate. ``count()`` must necessarily wait until the gate closing event has actually been executed, at which point ``rtio_counter > now``: ``count()`` synchronizes timeline cursor (``now``) and wall clock (``rtio_counter``). In these situations, a ``delay()`` is necessary to re-establish positive slack so that further output events can be placed. Similar situations arise with methods such as :meth:`artiq.coredevice.ttl.TTLInOut.sample_get` and :meth:`artiq.coredevice.ttl.TTLInOut.watch_done`. From 49682d015951d37adf006af1b819eeca5441721d Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 12 Jan 2019 13:17:59 +0000 Subject: [PATCH 1499/2457] Improve Python 3.7 compatibility. async is now a full (non-contextual) keyword. There are two more instances: - artiq/frontend/artiq_client.py - artiq/devices/thorlabs_tcube/driver.py It is not immediately clear how to fix those, so they are left for later work. --- artiq/compiler/embedding.py | 2 +- artiq/compiler/transforms/llvm_ir_generator.py | 4 ++-- artiq/compiler/types.py | 12 ++++++------ artiq/coredevice/comm_kernel.py | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index 539e4ddad..f7cea0b7f 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -1019,7 +1019,7 @@ class Stitcher: function_type = types.TRPC(ret_type, service=self.embedding_map.store_object(host_function), - async=is_async) + is_async=is_async) self.functions[function] = function_type return function_type diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index fdcbe8ab3..b05467743 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -1342,7 +1342,7 @@ class LLVMIRGenerator: llargptr = self.llbuilder.gep(llargs, [ll.Constant(lli32, index)]) self.llbuilder.store(llargslot, llargptr) - if fun_type.async: + if fun_type.is_async: self.llbuilder.call(self.llbuiltin("rpc_send_async"), [llservice, lltagptr, llargs]) else: @@ -1352,7 +1352,7 @@ class LLVMIRGenerator: # Don't waste stack space on saved arguments. self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr]) - if fun_type.async: + if fun_type.is_async: # If this RPC is called using an `invoke` ARTIQ IR instruction, there will be # no other instructions in this basic block. Since this RPC is async, it cannot # possibly raise an exception, so add an explicit jump to the normal successor. diff --git a/artiq/compiler/types.py b/artiq/compiler/types.py index 6e5015f48..a8a2e5703 100644 --- a/artiq/compiler/types.py +++ b/artiq/compiler/types.py @@ -311,14 +311,14 @@ class TRPC(Type): :ivar ret: (:class:`Type`) return type :ivar service: (int) RPC service number - :ivar async: (bool) whether the RPC blocks until return + :ivar is_async: (bool) whether the RPC blocks until return """ attributes = OrderedDict() - def __init__(self, ret, service, async=False): + def __init__(self, ret, service, is_async=False): assert isinstance(ret, Type) - self.ret, self.service, self.async = ret, service, async + self.ret, self.service, self.is_async = ret, service, is_async def find(self): return self @@ -326,7 +326,7 @@ class TRPC(Type): def unify(self, other): if isinstance(other, TRPC) and \ self.service == other.service and \ - self.async == other.async: + self.is_async == other.is_async: self.ret.unify(other.ret) elif isinstance(other, TVar): other.unify(self) @@ -343,7 +343,7 @@ class TRPC(Type): def __eq__(self, other): return isinstance(other, TRPC) and \ self.service == other.service and \ - self.async == other.async + self.is_async == other.is_async def __ne__(self, other): return not (self == other) @@ -742,7 +742,7 @@ class TypePrinter(object): return signature elif isinstance(typ, TRPC): return "[rpc{} #{}](...)->{}".format(typ.service, - " async" if typ.async else "", + " async" if typ.is_async else "", self.name(typ.ret, depth + 1)) elif isinstance(typ, TBuiltinFunction): return "".format(typ.name) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 2cadd0d60..6fa4113e4 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -403,7 +403,7 @@ class CommKernel: return msg def _serve_rpc(self, embedding_map): - async = self._read_bool() + is_async = self._read_bool() service_id = self._read_int32() args, kwargs = self._receive_rpc_args(embedding_map) return_tags = self._read_bytes() @@ -413,9 +413,9 @@ class CommKernel: else: service = embedding_map.retrieve_object(service_id) logger.debug("rpc service: [%d]%r%s %r %r -> %s", service_id, service, - (" (async)" if async else ""), args, kwargs, return_tags) + (" (async)" if is_async else ""), args, kwargs, return_tags) - if async: + if is_async: service(*args, **kwargs) return From 425cd7851e32dcf61dcf7369b28e77c264bf0f46 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sat, 12 Jan 2019 13:37:20 +0000 Subject: [PATCH 1500/2457] compiler: first monomorphize ints, then casts. Fixes #1242. --- artiq/compiler/module.py | 2 +- artiq/compiler/transforms/cast_monomorphizer.py | 1 + artiq/test/lit/monomorphism/bug_1242.py | 8 ++++++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 artiq/test/lit/monomorphism/bug_1242.py diff --git a/artiq/compiler/module.py b/artiq/compiler/module.py index cea86cddb..d43404b20 100644 --- a/artiq/compiler/module.py +++ b/artiq/compiler/module.py @@ -66,8 +66,8 @@ class Module: interleaver = transforms.Interleaver(engine=self.engine) invariant_detection = analyses.InvariantDetection(engine=self.engine) - cast_monomorphizer.visit(src.typedtree) int_monomorphizer.visit(src.typedtree) + cast_monomorphizer.visit(src.typedtree) inferencer.visit(src.typedtree) monomorphism_validator.visit(src.typedtree) escape_validator.visit(src.typedtree) diff --git a/artiq/compiler/transforms/cast_monomorphizer.py b/artiq/compiler/transforms/cast_monomorphizer.py index 50e2bda4f..8e373ab1e 100644 --- a/artiq/compiler/transforms/cast_monomorphizer.py +++ b/artiq/compiler/transforms/cast_monomorphizer.py @@ -18,6 +18,7 @@ class CastMonomorphizer(algorithm.Visitor): types.is_builtin(node.func.type, "int64")): typ = node.type.find() if (not types.is_var(typ["width"]) and + len(node.args) == 1 and builtins.is_int(node.args[0].type) and types.is_var(node.args[0].type.find()["width"])): if isinstance(node.args[0], asttyped.BinOpT): diff --git a/artiq/test/lit/monomorphism/bug_1242.py b/artiq/test/lit/monomorphism/bug_1242.py new file mode 100644 index 000000000..8918a30cc --- /dev/null +++ b/artiq/test/lit/monomorphism/bug_1242.py @@ -0,0 +1,8 @@ +# RUN: %python -m artiq.compiler.testbench.signature %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +x = 0x100000000 +# CHECK-L: x: numpy.int64 + +y = int32(x) +# CHECK-L: y: numpy.int32 From 24b1b9a480a691133fff79846837632269148a9a Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 12 Jan 2019 13:49:32 +0000 Subject: [PATCH 1501/2457] Add smoke test for frontend commands This ensures that at least --help works for all the commands, preventing regressions like that in f3323a35d56bc1a833ee9140f2a90f948ba7f324. --- artiq/test/test_frontends.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 artiq/test/test_frontends.py diff --git a/artiq/test/test_frontends.py b/artiq/test/test_frontends.py new file mode 100644 index 000000000..adb209e54 --- /dev/null +++ b/artiq/test/test_frontends.py @@ -0,0 +1,35 @@ +"""Generic tests for frontend commands.""" +import subprocess +import sys +import unittest + + +class TestFrontends(unittest.TestCase): + def test_help(self): + """Test --help as a simple smoke test against catastrophic breakage.""" + commands = { + "aqctl": [ + "corelog", "korad_ka3005p", "lda", "novatech409b", + "thorlabs_tcube" + ], + "artiq": [ + "client", "compile", "coreanalyzer", "coremgmt", "ctlmgr", + "devtool", "flash", "influxdb", "master", "mkfs", "route", + "rpctool", "rtiomon", "run", "session" + ] + } + + # Skip tests for GUI programs on headless CI environments. + try: + from PyQt5 import QtGui, QtWidgets + commands["artiq"] += ["browser", "dashboard"] + except ImportError: + pass + + for module in (prefix + "_" + name + for prefix, names in commands.items() + for name in names): + subprocess.check_call( + [sys.executable, "-m", "artiq.frontend." + module, "--help"], + stdout=subprocess.DEVNULL, + stderr=subprocess.STDOUT) From 6c52359e59772546b8040f2ec93f85cac481d557 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 12 Jan 2019 17:34:32 +0000 Subject: [PATCH 1502/2457] coredevice: Add _mu suffix to AD991x ref_time arguments GitHub: Fixes #1243. --- RELEASE_NOTES.rst | 5 +++++ artiq/coredevice/ad9910.py | 20 ++++++++++---------- artiq/coredevice/ad9914.py | 12 ++++++------ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 6e6c3c6ce..00da9c9b0 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -8,6 +8,11 @@ ARTIQ-5 5.0 *** + +* The :class:`~artiq.coredevice.ad9910.AD9910` and + :class:`~artiq.coredevice.ad9914.AD9914` phase reference timestamp parameters + have been renamed to ``ref_time_mu`` for consistency, as they are in machine + units. * :func:`~artiq.tools.verbosity_args` renamed to :func:`~artiq.tools.add_common_args`. New feature: adds an option to print the ARTIQ version. diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 6b5717655..e23c0428d 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -371,11 +371,11 @@ class AD9910: self.set_cfr1(power_down=bits) self.cpld.io_update.pulse(1*us) - # KLUDGE: ref_time default argument is explicitly marked int64() to avoid + # KLUDGE: ref_time_mu default argument is explicitly marked int64() to avoid # silent truncation of explicitly passed timestamps. (Compiler bug?) @kernel def set_mu(self, ftw, pow_=0, asf=0x3fff, phase_mode=_PHASE_MODE_DEFAULT, - ref_time=int64(-1), profile=0): + ref_time_mu=int64(-1), profile=0): """Set profile 0 data in machine units. This uses machine units (FTW, POW, ASF). The frequency tuning word @@ -393,7 +393,7 @@ class AD9910: :param asf: Amplitude scale factor: 14 bit unsigned. :param phase_mode: If specified, overrides the default phase mode set by :meth:`set_phase_mode` for this call. - :param ref_time: Fiducial time used to compute absolute or tracking + :param ref_time_mu: Fiducial time used to compute absolute or tracking phase updates. In machine units as obtained by `now_mu()`. :param profile: Profile number to set (0-7, default: 0). :return: Resulting phase offset word after application of phase @@ -409,14 +409,14 @@ class AD9910: # Auto-clear phase accumulator on IO_UPDATE. # This is active already for the next IO_UPDATE self.set_cfr1(phase_autoclear=1) - if phase_mode == PHASE_MODE_TRACKING and ref_time < 0: + if phase_mode == PHASE_MODE_TRACKING and ref_time_mu < 0: # set default fiducial time stamp - ref_time = 0 - if ref_time >= 0: + ref_time_mu = 0 + if ref_time_mu >= 0: # 32 LSB are sufficient. # Also no need to use IO_UPDATE time as this # is equivalent to an output pipeline latency. - dt = int32(now_mu()) - int32(ref_time) + dt = int32(now_mu()) - int32(ref_time_mu) pow_ += dt*ftw*self.sysclk_per_mu >> 16 self.write64(_AD9910_REG_PROFILE0 + profile, (asf << 16) | (pow_ & 0xffff), ftw) @@ -516,7 +516,7 @@ class AD9910: @kernel def set(self, frequency, phase=0.0, amplitude=1.0, - phase_mode=_PHASE_MODE_DEFAULT, ref_time=int64(-1), profile=0): + phase_mode=_PHASE_MODE_DEFAULT, ref_time_mu=int64(-1), profile=0): """Set profile 0 data in SI units. .. seealso:: :meth:`set_mu` @@ -525,13 +525,13 @@ class AD9910: :param phase: Phase tuning word in turns :param amplitude: Amplitude in units of full scale :param phase_mode: Phase mode constant - :param ref_time: Fiducial time stamp in machine units + :param ref_time_mu: Fiducial time stamp in machine units :param profile: Profile to affect :return: Resulting phase offset in turns """ return self.pow_to_turns(self.set_mu( self.frequency_to_ftw(frequency), self.turns_to_pow(phase), - self.amplitude_to_asf(amplitude), phase_mode, ref_time, profile)) + self.amplitude_to_asf(amplitude), phase_mode, ref_time_mu, profile)) @kernel def set_att_mu(self, att): diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index c034ce09a..647ce58f1 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -182,7 +182,7 @@ class AD9914: @kernel def set_mu(self, ftw, pow=0, phase_mode=_PHASE_MODE_DEFAULT, - asf=0x0fff, ref_time=-1): + asf=0x0fff, ref_time_mu=-1): """Sets the DDS channel to the specified frequency and phase. This uses machine units (FTW and POW). The frequency tuning word width @@ -196,7 +196,7 @@ class AD9914: :param pow: adds an offset to the phase. :param phase_mode: if specified, overrides the default phase mode set by :meth:`set_phase_mode` for this call. - :param ref_time: reference time used to compute phase. Specifying this + :param ref_time_mu: reference time used to compute phase. Specifying this makes it easier to have a well-defined phase relationship between DDSes on the same bus that are updated at a similar time. :return: Resulting phase offset word after application of phase @@ -205,8 +205,8 @@ class AD9914: """ if phase_mode == _PHASE_MODE_DEFAULT: phase_mode = self.phase_mode - if ref_time < 0: - ref_time = now_mu() + if ref_time_mu < 0: + ref_time_mu = now_mu() delay_mu(-self.set_duration_mu) self.write(AD9914_GPIO, (1 << self.channel) << 1) @@ -225,9 +225,9 @@ class AD9914: # Enable autoclear phase accumulator and enables OSK. self.write(AD9914_REG_CFR1L, 0x2108) fud_time = now_mu() + 2 * self.write_duration_mu - pow -= int32((ref_time - fud_time) * self.sysclk_per_mu * ftw >> (32 - 16)) + pow -= int32((ref_time_mu - fud_time) * self.sysclk_per_mu * ftw >> (32 - 16)) if phase_mode == PHASE_MODE_TRACKING: - pow += int32(ref_time * self.sysclk_per_mu * ftw >> (32 - 16)) + pow += int32(ref_time_mu * self.sysclk_per_mu * ftw >> (32 - 16)) self.write(AD9914_REG_POW, pow) self.write(AD9914_REG_ASF, asf) From 4cb9f77fd86cb4ead92592ec0a0602965fa57308 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 Jan 2019 13:53:07 +0800 Subject: [PATCH 1503/2457] sayma_amc: fix Master timing constraints --- artiq/gateware/targets/sayma_amc.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index c8f68a5f0..472331944 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -507,16 +507,16 @@ class Master(MiniSoC, AMPSoC): self.add_memory_group("drtioaux_mem", drtioaux_memory_group) rtio_clk_period = 1e9/rtio_clk_freq - gth = self.drtio_transceiver.gths[0] - platform.add_period_constraint(gth.txoutclk, rtio_clk_period/2) - platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) + gth0 = self.drtio_transceiver.gths[0] + platform.add_period_constraint(gth0.txoutclk, rtio_clk_period/2) + platform.add_period_constraint(gth0.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( self.crg.cd_sys.clk, - gth.txoutclk, gth.rxoutclk) + gth0.txoutclk, gth0.rxoutclk) for gth in self.drtio_transceiver.gths[1:]: platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( - self.crg.cd_sys.clk, gth.rxoutclk) + self.crg.cd_sys.clk, gth0.txoutclk, gth.rxoutclk) self.rtio_channels = rtio_channels = [] for i in range(4): From b8a230a67ef808be6bf911b54e97b4c42677cca9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 14 Jan 2019 00:03:14 +0800 Subject: [PATCH 1504/2457] nix: update quamash (#1245) --- nix/pkgs/artiq.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix/pkgs/artiq.nix b/nix/pkgs/artiq.nix index e5ee192da..67085fa81 100644 --- a/nix/pkgs/artiq.nix +++ b/nix/pkgs/artiq.nix @@ -42,8 +42,8 @@ quamash = python3Packages.buildPythonPackage rec { src = fetchFromGitHub { owner = "harvimt"; repo = "quamash"; - rev = "bbab9e30e10b71a95687b03a93524173fb7b43f0"; - sha256 = "08hp2q4ifj6z2ww05c7zsy0cd732k9rnaims1j43vr4hhxx950mk"; + rev = "e513b30f137415c5e098602fa383e45debab85e7"; + sha256 = "117rp9r4lz0kfz4dmmpa35hp6nhbh6b4xq0jmgvqm68g9hwdxmqa"; }; propagatedBuildInputs = with python3Packages; [ pyqt5 ]; doCheck = false; From 3c0e3e5910b2d75ddbb5b360ad62c36c2ea23c75 Mon Sep 17 00:00:00 2001 From: TPH Date: Tue, 15 Jan 2019 09:57:07 +0000 Subject: [PATCH 1505/2457] issue template: remind users to update the docs --- .github/ISSUE_TEMPLATE/3_Question.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/3_Question.md b/.github/ISSUE_TEMPLATE/3_Question.md index 4a463d293..10f3f616f 100644 --- a/.github/ISSUE_TEMPLATE/3_Question.md +++ b/.github/ISSUE_TEMPLATE/3_Question.md @@ -6,14 +6,16 @@ about: Questions about ARTIQ that are not covered in the documentation. (Latest # Question - ## Category: FILL_IN From a565f77538e4301977682b8d532adace0c1a478e Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 10 Dec 2018 22:21:26 +0000 Subject: [PATCH 1506/2457] Add gateware input event counter --- artiq/coredevice/edge_counter.py | 236 ++++++++++++++++++ artiq/gateware/eem.py | 14 +- artiq/gateware/rtio/phy/edge_counter.py | 79 ++++++ artiq/gateware/rtio/phy/ttl_serdes_generic.py | 5 + artiq/gateware/rtio/phy/ttl_simple.py | 12 +- artiq/gateware/test/rtio/test_edge_counter.py | 134 ++++++++++ artiq/test/coredevice/test_edge_counter.py | 97 +++++++ doc/manual/core_drivers_reference.rst | 6 + 8 files changed, 580 insertions(+), 3 deletions(-) create mode 100755 artiq/coredevice/edge_counter.py create mode 100644 artiq/gateware/rtio/phy/edge_counter.py create mode 100644 artiq/gateware/test/rtio/test_edge_counter.py create mode 100644 artiq/test/coredevice/test_edge_counter.py diff --git a/artiq/coredevice/edge_counter.py b/artiq/coredevice/edge_counter.py new file mode 100755 index 000000000..e7782064e --- /dev/null +++ b/artiq/coredevice/edge_counter.py @@ -0,0 +1,236 @@ +"""Driver for RTIO-enabled TTL edge counter. + +Like for the TTL input PHYs, sensitivity can be configured over RTIO +(``gate_rising()``, etc.). In contrast to the former, however, the count is +accumulated in gateware, and only a single input event is generated at the end +of each gate period:: + + with parallel: + doppler_cool() + self.pmt_counter.gate_rising(1 * ms) + + with parallel: + readout() + self.pmt_counter.gate_rising(100 * us) + + print("Doppler cooling counts:", self.pmt_counter.fetch_count()) + print("Readout counts:", self.pmt_counter.fetch_count()) + +For applications where the timestamps of the individual input events are not +required, this has two advantages over ``TTLInOut.count()`` beyond raw +throughput. First, it is easy to count events during multiple separate periods +without blocking to read back counts in between, as illustrated in the above +example. Secondly, as each count total only takes up a single input event, it +is much easier to acquire counts on several channels in parallel without +risking input FIFO overflows:: + + # Using the TTLInOut driver, pmt_1 input events are only processed + # after pmt_0 is done counting. To avoid RTIOOverflows, a round-robin + # scheme would have to be implemented manually. + + with parallel: + self.pmt_0.gate_rising(10 * ms) + self.pmt_1.gate_rising(10 * ms) + + counts_0 = self.pmt_0.count(now_mu()) # blocks + counts_1 = self.pmt_1.count(now_mu()) + + # + + # Using gateware counters, only a single input event each is + # generated, greatly reducing the load on the input FIFOs: + + with parallel: + self.pmt_0_counter.gate_rising(10 * ms) + self.pmt_1_counter.gate_rising(10 * ms) + + counts_0 = self.pmt_0_counter.fetch_count() # blocks + counts_1 = self.pmt_1_counter.fetch_count() + +See :mod:`artiq.gateware.rtio.phy.edge_counter` and +:meth:`artiq.gateware.eem.DIO.add_std` for the gateware components. +""" + +from artiq.language.core import * +from artiq.language.types import * +from artiq.coredevice.rtio import (rtio_output, rtio_input_data, + rtio_input_timestamped_data) +from numpy import int32, int64 + +CONFIG_COUNT_RISING = 0b0001 +CONFIG_COUNT_FALLING = 0b0010 +CONFIG_SEND_COUNT_EVENT = 0b0100 +CONFIG_RESET_TO_ZERO = 0b1000 + + +class CounterOverflow(Exception): + """Raised when an edge counter value is read which indicates that the + counter might have overflowed.""" + pass + + +class EdgeCounter: + """RTIO TTL edge counter driver driver. + + Like for regular TTL inputs, timeline periods where the counter is + sensitive to a chosen set of input transitions can be specified. Unlike the + former, however, the specified edges do not create individual input events; + rather, the total count can be requested as a single input event from the + core (typically at the end of the gate window). + + :param channel: The RTIO channel of the gateware phy. + :param gateware_width: The width of the gateware counter register, in + bits. This is only used for overflow handling; to change the size, + the gateware needs to be rebuilt. + """ + + kernel_invariants = {"core", "channel", "counter_max"} + + def __init__(self, dmgr, channel, gateware_width=31, core_device="core"): + self.core = dmgr.get(core_device) + self.channel = channel + self.counter_max = (1 << (gateware_width - 1)) - 1 + + @kernel + def gate_rising(self, duration): + """Count rising edges for the given duration and request the total at + the end. + + The counter is reset at the beginning of the gate period. Use + :meth:`set_config` directly for more detailed control. + + :param duration: The duration for which the gate is to stay open. + + :return: The timestamp at the end of the gate period, in machine units. + """ + return self.gate_rising_mu(self.core.seconds_to_mu(duration)) + + @kernel + def gate_falling(self, duration): + """Count falling edges for the given duration and request the total at + the end. + + The counter is reset at the beginning of the gate period. Use + :meth:`set_config` directly for more detailed control. + + :param duration: The duration for which the gate is to stay open. + + :return: The timestamp at the end of the gate period, in machine units. + """ + return self.gate_falling_mu(self.core.seconds_to_mu(duration)) + + @kernel + def gate_both(self, duration): + """Count both rising and falling edges for the given duration, and + request the total at the end. + + The counter is reset at the beginning of the gate period. Use + :meth:`set_config` directly for more detailed control. + + :param duration: The duration for which the gate is to stay open. + + :return: The timestamp at the end of the gate period, in machine units. + """ + return self.gate_both_mu(self.core.seconds_to_mu(duration)) + + @kernel + def gate_rising_mu(self, duration_mu): + """See :meth:`gate_rising`.""" + return self._gate_mu( + duration_mu, count_rising=True, count_falling=False) + + @kernel + def gate_falling_mu(self, duration_mu): + """See :meth:`gate_falling`.""" + return self._gate_mu( + duration_mu, count_rising=False, count_falling=True) + + @kernel + def gate_both_mu(self, duration_mu): + """See :meth:`gate_both_mu`.""" + return self._gate_mu( + duration_mu, count_rising=True, count_falling=True) + + @kernel + def _gate_mu(self, duration_mu, count_rising, count_falling): + self.set_config( + count_rising=count_rising, + count_falling=count_falling, + send_count_event=False, + reset_to_zero=True) + delay_mu(duration_mu) + self.set_config( + count_rising=False, + count_falling=False, + send_count_event=True, + reset_to_zero=False) + return now_mu() + + @kernel + def set_config(self, count_rising: TBool, count_falling: TBool, + send_count_event: TBool, reset_to_zero: TBool): + """Emit an RTIO event at the current timeline position to set the + gateware configuration. + + For most use cases, the `gate_*` wrappers will be more convenient. + + :param count_rising: Whether to count rising signal edges. + :param count_falling: Whether to count falling signal edges. + :param send_count_event: If `True`, an input event with the current + counter value is generated on the next clock cycle (once). + :param reset_to_zero: If `True`, the counter value is reset to zero on + the next clock cycle (once). + """ + config = int32(0) + if count_rising: + config |= CONFIG_COUNT_RISING + if count_falling: + config |= CONFIG_COUNT_FALLING + if send_count_event: + config |= CONFIG_SEND_COUNT_EVENT + if reset_to_zero: + config |= CONFIG_RESET_TO_ZERO + rtio_output(self.channel << 8, config) + + @kernel + def fetch_count(self) -> TInt32: + """Wait for and return count total from previously requested input + event. + + It is valid to trigger multiple gate periods without immediately + reading back the count total; the results will be returned in order on + subsequent fetch calls. + + This function blocks until a result becomes available. + """ + count = rtio_input_data(self.channel) + if count == self.counter_max: + raise CounterOverflow( + "Input edge counter overflow on RTIO channel {0}", + int64(self.channel)) + return count + + @kernel + def fetch_timestamped_count( + self, timeout_mu=int64(-1)) -> TTuple([TInt64, TInt32]): + """Wait for and return the timestamp and count total of a previously + requested input event. + + It is valid to trigger multiple gate periods without immediately + reading back the count total; the results will be returned in order on + subsequent fetch calls. + + This function blocks until a result becomes available or the given + timeout elapses. + + :return: A tuple of timestamp (-1 if timeout elapsed) and counter + value. (The timestamp is that of the requested input event – + typically the gate closing time – and not that of any input edges.) + """ + timestamp, count = rtio_input_timestamped_data(timeout_mu, + self.channel) + if count == self.counter_max: + raise CounterOverflow( + "Input edge counter overflow on RTIO channel {0}", + int64(self.channel)) + return timestamp, count diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index a63d82005..cff344bd3 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -38,20 +38,32 @@ class DIO(_EEM): for i in range(8)] @classmethod - def add_std(cls, target, eem, ttl03_cls, ttl47_cls, iostandard="LVDS_25"): + def add_std(cls, target, eem, ttl03_cls, ttl47_cls, iostandard="LVDS_25", + edge_counter_cls=None): cls.add_extension(target, eem, iostandard=iostandard) + phys = [] for i in range(4): pads = target.platform.request("dio{}".format(eem), i) phy = ttl03_cls(pads.p, pads.n) + phys.append(phy) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy)) for i in range(4): pads = target.platform.request("dio{}".format(eem), 4+i) phy = ttl47_cls(pads.p, pads.n) + phys.append(phy) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy)) + if edge_counter_cls is not None: + for phy in phys: + state = getattr(phy, "input_state", None) + if state is not None: + counter = edge_counter_cls(state) + target.submodules += counter + target.rtio_channels.append(rtio.Channel.from_phy(counter)) + class Urukul(_EEM): @staticmethod diff --git a/artiq/gateware/rtio/phy/edge_counter.py b/artiq/gateware/rtio/phy/edge_counter.py new file mode 100644 index 000000000..6c295abe8 --- /dev/null +++ b/artiq/gateware/rtio/phy/edge_counter.py @@ -0,0 +1,79 @@ +from migen import * +from artiq.gateware.rtio import rtlink + + +class SimpleEdgeCounter(Module): + """Counts rising/falling edges of an input signal. + + Control (sensitivity/zeroing) is done via a single RTIO output channel, + which is is also used to request an input event to be emitted with the + current counter value. + + :param input_state: The (scalar) input signal to detect edges of. This + should already be in the rio_phy clock domain. + :param counter_width: The width of the counter register, in bits. Defaults + to 31 to match integers being signed in ARTIQ Python. + """ + + def __init__(self, input_state, counter_width=31): + assert counter_width >= 2 + + # RTIO interface: + # - output 0: 4 bits, + # - input 0: 32 bits, accumulated edge count + self.rtlink = rtlink.Interface( + rtlink.OInterface(4, enable_replace=False), + rtlink.IInterface(counter_width)) + + # # # + + current_count = Signal(counter_width) + + count_rising = Signal() + count_falling = Signal() + send_event_stb = Signal() + zero_counter_stb = Signal() + + # Read configuration from RTIO output events. + self.sync.rio += [ + If(self.rtlink.o.stb, + count_rising.eq(self.rtlink.o.data[0]), + count_falling.eq(self.rtlink.o.data[1]), + send_event_stb.eq(self.rtlink.o.data[2]), + zero_counter_stb.eq(self.rtlink.o.data[3]) + ).Else( + send_event_stb.eq(0), + zero_counter_stb.eq(0) + ) + ] + + # Generate RTIO input event with current count if requested. + event_data = Signal.like(current_count) + self.comb += [ + self.rtlink.i.stb.eq(send_event_stb), + self.rtlink.i.data.eq(event_data) + ] + + # Keep previous input state for edge detection. + input_state_d = Signal() + self.sync.rio_phy += input_state_d.eq(input_state) + + # Count input edges, saturating at the maximum. + new_count = Signal.like(current_count) + self.comb += new_count.eq( + current_count + Mux(current_count == 2**counter_width - 1, + 0, + (count_rising & (input_state & ~input_state_d)) | + (count_falling & (~input_state & input_state_d)) + ) + ) + + self.sync.rio += [ + event_data.eq(new_count), + current_count.eq(Mux(zero_counter_stb, 0, new_count)) + ] + + +if __name__ == '__main__': + input = Signal(name="input") + print(fhdl.verilog.convert(SimpleEdgeCounter(input))) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_generic.py b/artiq/gateware/rtio/phy/ttl_serdes_generic.py index 1fc79673d..72d3175f3 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_generic.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_generic.py @@ -67,6 +67,10 @@ class InOut(Module): override_oe = Signal() self.overrides = [override_en, override_o, override_oe] + #: LSB of the input state (for edge detection; arbitrary choice, support for + #: short pulses will need a more involved solution). + self.input_state = Signal() + # # # # Output @@ -100,6 +104,7 @@ class InOut(Module): ] i = serdes.i[-1] + self.comb += self.input_state.eq(i) i_d = Signal() self.sync.rio_phy += [ i_d.eq(i), diff --git a/artiq/gateware/rtio/phy/ttl_simple.py b/artiq/gateware/rtio/phy/ttl_simple.py index fc83065f3..aef84cb69 100644 --- a/artiq/gateware/rtio/phy/ttl_simple.py +++ b/artiq/gateware/rtio/phy/ttl_simple.py @@ -41,6 +41,9 @@ class Input(Module): self.overrides = [] self.probes = [] + #: Registered copy of the input state, in the rio_phy clock domain. + self.input_state = Signal() + # # # sensitivity = Signal(2) @@ -69,7 +72,8 @@ class Input(Module): (sensitivity[0] & ( i & ~i_d)) | (sensitivity[1] & (~i & i_d)) ), - self.rtlink.i.data.eq(i) + self.rtlink.i.data.eq(i), + self.input_state.eq(i) ] self.probes += [i] @@ -86,6 +90,9 @@ class InOut(Module): self.overrides = [override_en, override_o, override_oe] self.probes = [] + # Registered copy of the input state, in the rio_phy clock domain. + self.input_state = Signal() + # # # ts = TSTriple() @@ -126,7 +133,8 @@ class InOut(Module): (sensitivity[0] & ( i & ~i_d)) | (sensitivity[1] & (~i & i_d)) ), - self.rtlink.i.data.eq(i) + self.rtlink.i.data.eq(i), + self.input_state.eq(i) ] self.probes += [i, ts.oe] diff --git a/artiq/gateware/test/rtio/test_edge_counter.py b/artiq/gateware/test/rtio/test_edge_counter.py new file mode 100644 index 000000000..89a388f2b --- /dev/null +++ b/artiq/gateware/test/rtio/test_edge_counter.py @@ -0,0 +1,134 @@ +import unittest + +from migen import * +from artiq.gateware.rtio.phy.edge_counter import * + +CONFIG_COUNT_RISING = 0b0001 +CONFIG_COUNT_FALLING = 0b0010 +CONFIG_SEND_COUNT_EVENT = 0b0100 +CONFIG_RESET_TO_ZERO = 0b1000 + + +class TimeoutError(Exception): + pass + + +class Testbench: + def __init__(self, counter_width=32): + self.input = Signal() + self.dut = SimpleEdgeCounter(self.input, counter_width=counter_width) + + self.fragment = self.dut.get_fragment() + cd = ClockDomain("rio") + self.fragment.clock_domains.append(cd) + self.rio_rst = cd.rst + + def write_config(self, config): + bus = self.dut.rtlink.o + yield bus.data.eq(config) + yield bus.stb.eq(1) + yield + yield bus.stb.eq(0) + yield + + def read_event(self, timeout): + bus = self.dut.rtlink.i + for _ in range(timeout): + if (yield bus.stb): + break + yield + else: + raise TimeoutError + return (yield bus.data) + + def fetch_count(self, zero=False): + c = CONFIG_SEND_COUNT_EVENT + if zero: + c |= CONFIG_RESET_TO_ZERO + yield from self.write_config(c) + return (yield from self.read_event(1)) + + def toggle_input(self): + yield self.input.eq(1) + yield + yield self.input.eq(0) + yield + + def reset_rio(self): + yield self.rio_rst.eq(1) + yield + yield self.rio_rst.eq(0) + yield + + def run(self, gen): + run_simulation(self.fragment, gen, + clocks={n: 5 for n in ["sys", "rio", "rio_phy"]}) + + +class TestEdgeCounter(unittest.TestCase): + def test_init(self): + tb = Testbench() + + def gen(): + # No counts initially... + self.assertEqual((yield from tb.fetch_count()), 0) + + # ...nor any sensitivity. + yield from tb.toggle_input() + self.assertEqual((yield from tb.fetch_count()), 0) + + tb.run(gen()) + + def test_sensitivity(self): + tb = Testbench() + + def gen(sensitivity_config, expected_rising, expected_falling): + yield from tb.write_config(sensitivity_config) + yield tb.input.eq(1) + yield + self.assertEqual((yield from tb.fetch_count(zero=True)), + expected_rising) + + yield from tb.write_config(sensitivity_config) + yield tb.input.eq(0) + yield + self.assertEqual((yield from tb.fetch_count()), expected_falling) + + yield + with self.assertRaises(TimeoutError): + # Make sure there are no more suprious events. + yield from tb.read_event(10) + + tb.run(gen(CONFIG_COUNT_RISING, 1, 0)) + tb.run(gen(CONFIG_COUNT_FALLING, 0, 1)) + tb.run(gen(CONFIG_COUNT_RISING | CONFIG_COUNT_FALLING, 1, 1)) + + def test_reset(self): + tb = Testbench() + + def gen(): + # Generate one count. + yield from tb.write_config(CONFIG_COUNT_RISING) + yield from tb.toggle_input() + self.assertEqual((yield from tb.fetch_count()), 1) + + # Make sure it is gone after an RTIO reset, and the counter isn't + # sensitive anymore. + yield from tb.write_config(CONFIG_COUNT_RISING) + yield from tb.reset_rio() + yield from tb.toggle_input() + self.assertEqual((yield from tb.fetch_count()), 0) + + tb.run(gen()) + + def test_saturation(self): + for width in range(3, 5): + tb = Testbench(counter_width=width) + + def gen(): + yield from tb.write_config(CONFIG_COUNT_RISING) + for _ in range(2**width + 1): + yield from tb.toggle_input() + self.assertEqual((yield from tb.fetch_count()), 2**width - 1) + + tb.run(gen()) diff --git a/artiq/test/coredevice/test_edge_counter.py b/artiq/test/coredevice/test_edge_counter.py new file mode 100644 index 000000000..1199af6a5 --- /dev/null +++ b/artiq/test/coredevice/test_edge_counter.py @@ -0,0 +1,97 @@ +from artiq.experiment import * +from artiq.test.hardware_testbench import ExperimentCase + + +class EdgeCounterExp(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("loop_in_counter") + self.setattr_device("loop_out") + + @kernel + def count_pulse_edges(self, gate_fn): + self.core.break_realtime() + with parallel: + with sequential: + delay(5 * us) + self.loop_out.pulse(10 * us) + with sequential: + gate_fn(10 * us) + delay(1 * us) + gate_fn(10 * us) + return (self.loop_in_counter.fetch_count(), + self.loop_in_counter.fetch_count()) + + @kernel + def timeout_timestamp(self): + self.core.break_realtime() + timestamp_mu, _ = self.loop_in_counter.fetch_timestamped_count( + now_mu()) + return timestamp_mu + + @kernel + def gate_relative_timestamp(self): + self.core.break_realtime() + gate_end_mu = self.loop_in_counter.gate_rising(1 * us) + timestamp_mu, _ = self.loop_in_counter.fetch_timestamped_count() + return timestamp_mu - gate_end_mu + + @kernel + def many_pulses_split(self, num_pulses): + self.core.break_realtime() + + self.loop_in_counter.set_config( + count_rising=True, + count_falling=True, + send_count_event=False, + reset_to_zero=True) + + for _ in range(num_pulses): + self.loop_out.pulse(5 * us) + delay(5 * us) + + self.loop_in_counter.set_config( + count_rising=True, + count_falling=True, + send_count_event=True, + reset_to_zero=False) + + for _ in range(num_pulses): + self.loop_out.pulse(5 * us) + delay(5 * us) + + self.loop_in_counter.set_config( + count_rising=False, + count_falling=False, + send_count_event=True, + reset_to_zero=False) + + return (self.loop_in_counter.fetch_count(), + self.loop_in_counter.fetch_count()) + + +class EdgeCounterTest(ExperimentCase): + def setUp(self): + super().setUp() + self.exp = self.create(EdgeCounterExp) + + def test_sensitivity(self): + c = self.exp.loop_in_counter + self.assertEqual(self.exp.count_pulse_edges(c.gate_rising), (1, 0)) + self.assertEqual(self.exp.count_pulse_edges(c.gate_falling), (0, 1)) + self.assertEqual(self.exp.count_pulse_edges(c.gate_both), (1, 1)) + + def test_timeout_timestamp(self): + self.assertEqual(self.exp.timeout_timestamp(), -1) + + def test_gate_timestamp(self): + # The input event should be received at some point after it was + # requested, with some extra latency as it makes its way through the + # DRTIO machinery. (We only impose a somewhat arbitrary upper limit + # on the latency here.) + delta_mu = self.exp.gate_relative_timestamp() + self.assertGreaterEqual(delta_mu, 0) + self.assertLess(delta_mu, 100) + + def test_many_pulses_split(self): + self.assertEqual(self.exp.many_pulses_split(500), (1000, 2000)) diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 556f54096..fd6f36fca 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -41,6 +41,12 @@ Digital I/O drivers .. automodule:: artiq.coredevice.ttl :members: +:mod:`artiq.coredevice.edge_counter` module +++++++++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.edge_counter + :members: + :mod:`artiq.coredevice.shiftreg` module +++++++++++++++++++++++++++++++++++++++ From 67a6882e910bd2bd1407d8ecb7556b74d93b555c Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 16 Dec 2018 20:27:03 +0000 Subject: [PATCH 1507/2457] examples: Fix kasli_tester device_db offset comments --- artiq/examples/kasli_tester/device_db.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/artiq/examples/kasli_tester/device_db.py b/artiq/examples/kasli_tester/device_db.py index dcfc297c3..a403d60ea 100644 --- a/artiq/examples/kasli_tester/device_db.py +++ b/artiq/examples/kasli_tester/device_db.py @@ -121,7 +121,7 @@ for i in range(4): } -# Sampler (EEM3) starting at RTIO channel 14 +# Sampler (EEM3) starting at RTIO channel 15 device_db["spi_sampler0_adc"] = { "type": "local", "module": "artiq.coredevice.spi2", @@ -152,7 +152,7 @@ device_db["sampler0"] = { } -# Zotino (EEM4) starting at RTIO channel 17 +# Zotino (EEM4) starting at RTIO channel 18 device_db["spi_zotino0"] = { "type": "local", "module": "artiq.coredevice.spi2", @@ -183,7 +183,7 @@ device_db["zotino0"] = { } -# Grabber (EEM6) starting at RTIO channel 20 +# Grabber (EEM6) starting at RTIO channel 21 device_db["grabber0"] = { "type": "local", "module": "artiq.coredevice.grabber", @@ -192,7 +192,7 @@ device_db["grabber0"] = { } -# Urukul (EEM7) starting at RTIO channel 22 +# Urukul (EEM7) starting at RTIO channel 23 device_db.update( spi_urukul1={ "type": "local", @@ -239,7 +239,7 @@ for i in range(4): } -# DIO (EEM8) starting at RTIO channel 24 +# DIO (EEM8) starting at RTIO channel 26 for i in range(8): device_db["ttl" + str(8 + i)] = { "type": "local", @@ -249,7 +249,7 @@ for i in range(8): } -# DIO (EEM9) starting at RTIO channel 32 +# DIO (EEM9) starting at RTIO channel 34 for i in range(8): device_db["ttl" + str(16 + i)] = { "type": "local", @@ -259,7 +259,7 @@ for i in range(8): } -# Sampler (EEM10) starting at RTIO channel 40 +# Sampler (EEM10) starting at RTIO channel 42 device_db["spi_sampler1_adc"] = { "type": "local", "module": "artiq.coredevice.spi2", @@ -290,7 +290,7 @@ device_db["sampler1"] = { } -# Zotino (EEM11) starting at RTIO channel 43 +# Zotino (EEM11) starting at RTIO channel 45 device_db["spi_zotino1"] = { "type": "local", "module": "artiq.coredevice.spi2", From 1c71ae636aaa713e88893e535db7e06a6d5235a9 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 16 Dec 2018 20:33:15 +0000 Subject: [PATCH 1508/2457] examples: Add edge counters to kasli_tester variant This enables test_edge_counter on the CI system. --- artiq/examples/kasli_tester/device_db.py | 79 +++++++++++++----------- artiq/gateware/targets/kasli.py | 5 +- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/artiq/examples/kasli_tester/device_db.py b/artiq/examples/kasli_tester/device_db.py index a403d60ea..bcffa8fa2 100644 --- a/artiq/examples/kasli_tester/device_db.py +++ b/artiq/examples/kasli_tester/device_db.py @@ -47,51 +47,57 @@ for i in range(8): "class": "TTLInOut" if i < 4 else "TTLOut", "arguments": {"channel": i}, } + device_db["ttl{}_counter".format(i)] = { + "type": "local", + "module": "artiq.coredevice.edge_counter", + "class": "EdgeCounter", + "arguments": {"channel": 8 + i}, + } -# Urukul (EEM1) starting at RTIO channel 8 +# Urukul (EEM1) starting at RTIO channel 12 device_db.update( spi_urukul0={ "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 8} + "arguments": {"channel": 12} }, ttl_urukul0_sync={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLClockGen", - "arguments": {"channel": 9, "acc_width": 4} + "arguments": {"channel": 13, "acc_width": 4} }, ttl_urukul0_io_update={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 10} + "arguments": {"channel": 14} }, ttl_urukul0_sw0={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 11} + "arguments": {"channel": 15} }, ttl_urukul0_sw1={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 12} + "arguments": {"channel": 16} }, ttl_urukul0_sw2={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 13} + "arguments": {"channel": 17} }, ttl_urukul0_sw3={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 14} + "arguments": {"channel": 18} }, urukul0_cpld={ "type": "local", @@ -121,24 +127,24 @@ for i in range(4): } -# Sampler (EEM3) starting at RTIO channel 15 +# Sampler (EEM3) starting at RTIO channel 19 device_db["spi_sampler0_adc"] = { "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 15} + "arguments": {"channel": 19} } device_db["spi_sampler0_pgia"] = { "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 16} + "arguments": {"channel": 20} } device_db["spi_sampler0_cnv"] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 17}, + "arguments": {"channel": 21}, } device_db["sampler0"] = { "type": "local", @@ -152,24 +158,24 @@ device_db["sampler0"] = { } -# Zotino (EEM4) starting at RTIO channel 18 +# Zotino (EEM4) starting at RTIO channel 22 device_db["spi_zotino0"] = { "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 18} + "arguments": {"channel": 22} } device_db["ttl_zotino0_ldac"] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 19} + "arguments": {"channel": 23} } device_db["ttl_zotino0_clr"] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 20} + "arguments": {"channel": 24} } device_db["zotino0"] = { "type": "local", @@ -183,34 +189,34 @@ device_db["zotino0"] = { } -# Grabber (EEM6) starting at RTIO channel 21 +# Grabber (EEM6) starting at RTIO channel 25 device_db["grabber0"] = { "type": "local", "module": "artiq.coredevice.grabber", "class": "Grabber", - "arguments": {"channel_base": 21} + "arguments": {"channel_base": 25} } -# Urukul (EEM7) starting at RTIO channel 23 +# Urukul (EEM7) starting at RTIO channel 27 device_db.update( spi_urukul1={ "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 23} + "arguments": {"channel": 27} }, ttl_urukul1_sync={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLClockGen", - "arguments": {"channel": 24, "acc_width": 4} + "arguments": {"channel": 28, "acc_width": 4} }, ttl_urukul1_io_update={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 25} + "arguments": {"channel": 29} }, urukul1_cpld={ "type": "local", @@ -239,44 +245,44 @@ for i in range(4): } -# DIO (EEM8) starting at RTIO channel 26 +# DIO (EEM8) starting at RTIO channel 30 for i in range(8): device_db["ttl" + str(8 + i)] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 26 + i}, + "arguments": {"channel": 30 + i}, } -# DIO (EEM9) starting at RTIO channel 34 +# DIO (EEM9) starting at RTIO channel 38 for i in range(8): device_db["ttl" + str(16 + i)] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 34 + i}, + "arguments": {"channel": 38 + i}, } -# Sampler (EEM10) starting at RTIO channel 42 +# Sampler (EEM10) starting at RTIO channel 46 device_db["spi_sampler1_adc"] = { "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 42} + "arguments": {"channel": 46} } device_db["spi_sampler1_pgia"] = { "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 43} + "arguments": {"channel": 47} } device_db["spi_sampler1_cnv"] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 44}, + "arguments": {"channel": 48}, } device_db["sampler1"] = { "type": "local", @@ -290,24 +296,24 @@ device_db["sampler1"] = { } -# Zotino (EEM11) starting at RTIO channel 45 +# Zotino (EEM11) starting at RTIO channel 49 device_db["spi_zotino1"] = { "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 45} + "arguments": {"channel": 49} } device_db["ttl_zotino1_ldac"] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 46} + "arguments": {"channel": 50} } device_db["ttl_zotino1_clr"] = { "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 47} + "arguments": {"channel": 51} } device_db["zotino1"] = { "type": "local", @@ -326,13 +332,13 @@ device_db.update( "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 48} + "arguments": {"channel": 52} }, led1={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 49} + "arguments": {"channel": 53} }, ) @@ -342,6 +348,7 @@ device_db.update( loop_out="ttl4", loop_in="ttl0", + loop_in_counter="ttl0_counter", # Urukul CPLD with sync and io_update, IFC MODE 0b1000 urukul_cpld="urukul0_cpld", diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 0c335feb5..966a5f44c 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -16,7 +16,7 @@ from misoc.integration.builder import builder_args, builder_argdict from artiq.gateware.amp import AMPSoC from artiq.gateware import rtio -from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series +from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, edge_counter from artiq.gateware import eem from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series @@ -737,7 +737,8 @@ class Tester(_StandaloneBase): self.rtio_channels = [] self.grabber_csr_group = [] eem.DIO.add_std(self, 5, - ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X, + edge_counter_cls=edge_counter.SimpleEdgeCounter) eem.Urukul.add_std(self, 0, 1, ttl_serdes_7series.Output_8X, ttl_simple.ClockGen) eem.Sampler.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) From 05f6dafb2cca4e6df2d1d8517e3c44d7528072e9 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 12 Jan 2019 19:37:03 +0000 Subject: [PATCH 1509/2457] RELEASE_NOTES: Mention new edge counter RTIO PHY --- RELEASE_NOTES.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 00da9c9b0..59846a38f 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -14,6 +14,11 @@ ARTIQ-5 have been renamed to ``ref_time_mu`` for consistency, as they are in machine units. * :func:`~artiq.tools.verbosity_args` renamed to :func:`~artiq.tools.add_common_args`. New feature: adds an option to print the ARTIQ version. +* A gateware-level input edge counter has been added, which offers higher + throughput and increased flexibility over the usual TTL input PHYs where + edge timestamps are not required. See :mod:`artiq.coredevice.edge_counter` for + the core device driver and :mod:`artiq.gateware.rtio.phy.edge_counter`/ + :meth:`artiq.gateware.eem.DIO.add_std` for the gateware components. ARTIQ-4 @@ -22,7 +27,7 @@ ARTIQ-4 4.0 *** -* The ``artiq.coredevice.ttl`` drivers no longer track the timestamps of +* The ``artiq.coredevice.ttl`` drivers no longer track the timestamps of submitted events in software, requiring the user to explicitly specify the timeout for ``count()``/``timestamp_mu()``. Support for ``sync()`` has been dropped. From 689714965b7e28354a7f0d5989c6bac6934e5913 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 15 Jan 2019 20:29:20 +0800 Subject: [PATCH 1510/2457] monkey_patches: disable for Python >= 3.6.7 3.6 >=7 are fixed 3.7.0 is incompatible with the monkey patches and they do more harm than good 3.7 >=1 are fixed --- artiq/monkey_patches.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/monkey_patches.py b/artiq/monkey_patches.py index 930d8b118..f6c31ad48 100644 --- a/artiq/monkey_patches.py +++ b/artiq/monkey_patches.py @@ -5,7 +5,7 @@ import socket __all__ = [] -if sys.version_info[:3] >= (3, 5, 2): +if sys.version_info[:3] >= (3, 5, 2) and sys.version_info[:3] <= (3, 6, 6): import asyncio # See https://github.com/m-labs/artiq/issues/506 From 4e142dfbeb94e0ac7676b74dac517a53119f56b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 16 Jan 2019 12:40:58 +0100 Subject: [PATCH 1511/2457] doc/installing: cleanup and fixes * fix broken and old URLs to anaconda/miniconda * append conda-forge, do not prepend it (consistent with conda-forge instructions and does not blindly prefer packages in conda-forge over packages in defaults) * shorten m-labs repo --- doc/manual/installing.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 628f8bba5..e02139ffe 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -21,7 +21,7 @@ The conda package contains pre-built binaries that you can directly flash to you Installing Anaconda or Miniconda -------------------------------- -You can either install Anaconda (choose Python 3.5) from https://store.continuum.io/cshop/anaconda/ or install the more minimalistic Miniconda (choose Python 3.5) from http://conda.pydata.org/miniconda.html +You can either install Anaconda from https://www.anaconda.com/download/ or install the more minimalistic Miniconda from https://conda.io/miniconda.html After installing either Anaconda or Miniconda, open a new terminal (also known as command line, console, or shell and denoted here as lines starting with ``$``) and verify the following command works:: @@ -35,17 +35,17 @@ Installing the ARTIQ packages .. note:: On a system with a pre-existing conda installation, it is recommended to update conda to the latest version prior to installing ARTIQ. -First add the conda-forge repository containing ARTIQ dependencies to your conda configuration:: +Add the M-Labs ``main`` Anaconda package repository containing stable releases and release candidates:: - $ conda config --prepend channels http://conda.anaconda.org/conda-forge/label/main - -Then add the M-Labs ``main`` Anaconda package repository containing stable releases and release candidates:: - - $ conda config --prepend channels http://conda.anaconda.org/m-labs/label/main + $ conda config --prepend channels m-labs .. note:: - To use the development versions of ARTIQ, also add the ``dev`` label (http://conda.anaconda.org/m-labs/label/dev). - Development versions are built for every change and contain more features, but are not as well-tested and are more likely to contain more bugs or inconsistencies than the releases in the ``main`` label. + To use the development versions of ARTIQ, also add the ``dev`` label (m-labs/label/dev). + Development versions are built for every change and contain more features, but are not as well-tested and are more likely to contain more bugs or inconsistencies than the releases in the default ``main`` label. + +Add the conda-forge repository containing ARTIQ dependencies to your conda configuration:: + + $ conda config --add channels conda-forge Then prepare to create a new conda environment with the ARTIQ package and the matching binaries for your hardware: choose a suitable name for the environment, for example ``artiq-main`` if you intend to track the main label, ``artiq-3`` for the 3.x release series, or ``artiq-2016-04-01`` if you consider the environment a snapshot of ARTIQ on 2016-04-01. From 1e3ef15446362a66509057ae63c2d07a102fc928 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 Jan 2019 09:49:27 +0800 Subject: [PATCH 1512/2457] nix: make versioneer work --- nix/pkgs/artiq.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nix/pkgs/artiq.nix b/nix/pkgs/artiq.nix index 67085fa81..08b5578b3 100644 --- a/nix/pkgs/artiq.nix +++ b/nix/pkgs/artiq.nix @@ -1,4 +1,4 @@ -{ stdenv, fetchFromGitHub, fetchsvn, python3Packages, qt5Full, binutils-or1k, llvm-or1k, llvmlite, python3 }: +{ stdenv, git, fetchFromGitHub, fetchsvn, python3Packages, qt5Full, binutils-or1k, llvm-or1k, llvmlite, python3 }: let @@ -67,6 +67,7 @@ in python3Packages.buildPythonPackage rec { name = "artiq"; src = ./../..; + buildInputs = [ git ]; propagatedBuildInputs = with python3Packages; [ binutils-or1k llvm-or1k llvmlite levenshtein pyqtgraph-qt5 aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; doCheck = false; meta = with stdenv.lib; { From a467b8f8515de3e2dec44c1f6c1ba4f067f4f307 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 Jan 2019 10:28:51 +0800 Subject: [PATCH 1513/2457] nix: update metadata --- nix/pkgs/artiq.nix | 4 ++-- nix/pkgs/llvm-or1k.nix | 2 +- nix/pkgs/openocd.nix | 2 +- nix/pkgs/rust/binaryBuild.nix | 4 ++-- nix/pkgs/rust/cargo.nix | 2 +- nix/pkgs/rust/rustc.nix | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/nix/pkgs/artiq.nix b/nix/pkgs/artiq.nix index 08b5578b3..aceab292d 100644 --- a/nix/pkgs/artiq.nix +++ b/nix/pkgs/artiq.nix @@ -71,10 +71,10 @@ python3Packages.buildPythonPackage rec { propagatedBuildInputs = with python3Packages; [ binutils-or1k llvm-or1k llvmlite levenshtein pyqtgraph-qt5 aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; doCheck = false; meta = with stdenv.lib; { - description = ""; + description = "A leading-edge control system for quantum information experiments"; homepage = https://m-labs/artiq; license = licenses.lgpl3; - maintainers = [ maintainers.sjmackenzie ]; + maintainers = [ maintainers.sb0 ]; platforms = [ "x86_64-linux" ]; }; } diff --git a/nix/pkgs/llvm-or1k.nix b/nix/pkgs/llvm-or1k.nix index 622e12f70..744a384ca 100644 --- a/nix/pkgs/llvm-or1k.nix +++ b/nix/pkgs/llvm-or1k.nix @@ -39,7 +39,7 @@ stdenv.mkDerivation rec { description = "Collection of modular and reusable compiler and toolchain technologies"; homepage = http://llvm.org/; license = stdenv.lib.licenses.bsd3; - maintainers = with stdenv.lib.maintainers; [ sj_mackenzie ]; + maintainers = with stdenv.lib.maintainers; [ sb0 ]; platforms = stdenv.lib.platforms.all; }; } diff --git a/nix/pkgs/openocd.nix b/nix/pkgs/openocd.nix index c820d4c14..ab75bc9f2 100644 --- a/nix/pkgs/openocd.nix +++ b/nix/pkgs/openocd.nix @@ -57,7 +57,7 @@ stdenv.mkDerivation rec { ''; homepage = http://openocd.sourceforge.net/; license = licenses.gpl2Plus; - maintainers = with maintainers; [ bjornfor ]; + maintainers = with maintainers; [ sb0 ]; platforms = platforms.linux; }; } diff --git a/nix/pkgs/rust/binaryBuild.nix b/nix/pkgs/rust/binaryBuild.nix index 488d43a6f..a40383df7 100644 --- a/nix/pkgs/rust/binaryBuild.nix +++ b/nix/pkgs/rust/binaryBuild.nix @@ -29,7 +29,7 @@ rec { meta = with stdenv.lib; { homepage = http://www.rust-lang.org/; description = "A safe, concurrent, practical language"; - maintainers = with maintainers; [ qknight ]; + maintainers = with maintainers; [ sb0 ]; license = [ licenses.mit licenses.asl20 ]; }; @@ -83,7 +83,7 @@ rec { meta = with stdenv.lib; { homepage = http://www.rust-lang.org/; description = "A safe, concurrent, practical language"; - maintainers = with maintainers; [ qknight ]; + maintainers = with maintainers; [ sb0 ]; license = [ licenses.mit licenses.asl20 ]; }; diff --git a/nix/pkgs/rust/cargo.nix b/nix/pkgs/rust/cargo.nix index bfe379c81..d89eaaa47 100644 --- a/nix/pkgs/rust/cargo.nix +++ b/nix/pkgs/rust/cargo.nix @@ -63,7 +63,7 @@ rustPlatform.buildRustPackage rec { meta = with stdenv.lib; { homepage = https://crates.io; description = "Downloads your Rust project's dependencies and builds your project"; - maintainers = with maintainers; [ wizeman retrry ]; + maintainers = with maintainers; [ sb0 ]; license = [ licenses.mit licenses.asl20 ]; platforms = platforms.unix; }; diff --git a/nix/pkgs/rust/rustc.nix b/nix/pkgs/rust/rustc.nix index a1dbc5ba5..3c0caf283 100644 --- a/nix/pkgs/rust/rustc.nix +++ b/nix/pkgs/rust/rustc.nix @@ -191,7 +191,7 @@ stdenv.mkDerivation { meta = with stdenv.lib; { homepage = https://www.rust-lang.org/; description = "A safe, concurrent, practical language"; - maintainers = with maintainers; [ madjar cstrahan wizeman globin havvy wkennington ]; + maintainers = with maintainers; [ sb0 ]; license = [ licenses.mit licenses.asl20 ]; platforms = platforms.linux ++ platforms.darwin; broken = broken; From 2bea5e3d585fb338bfb66b00deb2f65463144d9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 18 Jan 2019 10:02:18 +0000 Subject: [PATCH 1514/2457] urukul: support configurable refclk divider for #1248 --- artiq/coredevice/urukul.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 620eaf7da..723db47fd 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -31,6 +31,7 @@ CFG_CLK_SEL1 = 21 CFG_SYNC_SEL = 18 CFG_RST = 19 CFG_IO_RST = 20 +CFG_CLK_DIV = 22 # STA status register bit offsets STA_RF_SW = 0 @@ -54,7 +55,7 @@ CS_DDS_CH3 = 7 @portable def urukul_cfg(rf_sw, led, profile, io_update, mask_nu, - clk_sel, sync_sel, rst, io_rst): + clk_sel, sync_sel, rst, io_rst, clk_div): """Build Urukul CPLD configuration register""" return ((rf_sw << CFG_RF_SW) | (led << CFG_LED) | @@ -65,7 +66,8 @@ def urukul_cfg(rf_sw, led, profile, io_update, mask_nu, ((clk_sel & 0x02) << (CFG_CLK_SEL1 - 1)) | (sync_sel << CFG_SYNC_SEL) | (rst << CFG_RST) | - (io_rst << CFG_IO_RST)) + (io_rst << CFG_IO_RST) | + (clk_div << CFG_CLK_DIV)) @portable @@ -133,6 +135,11 @@ class CPLD: internal MMCX. For hardware revision <= v1.2 valid options are: 0 - either XO or MMCX dependent on component population; 1 SMA. Unsupported clocking options are silently ignored. + :param clk_div: Reference clock divider. Valid options are 0: variant + dependent default (divide-by-4 for AD9910 and divide-by-1 for AD9912); + 1: divide-by-1; 2: divide-by-2; 3: divide-by-4. + On Urukul boards with CPLD gateware before v1.3.1 only the default + (0, i.e. variant dependent divider) is valid. :param sync_sel: SYNC (multi-chip synchronisation) signal source selection. 0 corresponds to SYNC_IN being supplied by the FPGA via the EEM connector. 1 corresponds to SYNC_OUT from DDS0 being distributed to the @@ -148,16 +155,18 @@ class CPLD: `sync_device` was specified). :param core_device: Core device name """ - kernel_invariants = {"refclk", "bus", "core", "io_update"} + kernel_invariants = {"refclk", "bus", "core", "io_update", "clk_div"} def __init__(self, dmgr, spi_device, io_update_device=None, dds_reset_device=None, sync_device=None, - sync_sel=0, clk_sel=0, rf_sw=0, + sync_sel=0, clk_sel=0, clk_div=0, rf_sw=0, refclk=125e6, att=0x00000000, sync_div=None, core_device="core"): self.core = dmgr.get(core_device) self.refclk = refclk + assert 0 <= clk_div <= 3 + self.clk_div = clk_div self.bus = dmgr.get(spi_device) if io_update_device is not None: @@ -177,7 +186,8 @@ class CPLD: self.cfg_reg = urukul_cfg(rf_sw=rf_sw, led=0, profile=0, io_update=0, mask_nu=0, clk_sel=clk_sel, - sync_sel=sync_sel, rst=0, io_rst=0) + sync_sel=sync_sel, + rst=0, io_rst=0, clk_div=clk_div) self.att_reg = int32(int64(att)) self.sync_div = sync_div From 385916a9a421426298e345f81181269b58777103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 18 Jan 2019 12:06:33 +0000 Subject: [PATCH 1515/2457] ad9912: support configurable clk_div --- artiq/coredevice/ad9912.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 749fd5e00..62694bbbe 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -21,14 +21,14 @@ class AD9912: :param sw_device: Name of the RF switch device. The RF switch is a TTLOut channel available as the :attr:`sw` attribute of this instance. :param pll_n: DDS PLL multiplier. The DDS sample clock is - f_ref*pll_n where f_ref is the reference frequency (set in the parent - Urukul CPLD instance). + f_ref/clk_div*pll_n where f_ref is the reference frequency and clk_div + is the reference clock divider (both set in the parent Urukul CPLD + instance). """ - kernel_invariants = {"chip_select", "cpld", "core", "bus", - "ftw_per_hz", "sysclk", "pll_n"} + kernel_invariants = {"chip_select", "cpld", "core", "bus", "ftw_per_hz"} def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, - pll_n=10): + pll_n=10): self.cpld = dmgr.get(cpld_device) self.core = self.cpld.core self.bus = self.cpld.bus @@ -38,9 +38,9 @@ class AD9912: self.sw = dmgr.get(sw_device) self.kernel_invariants.add("sw") self.pll_n = pll_n - self.sysclk = self.cpld.refclk*pll_n - assert self.sysclk <= 1e9 - self.ftw_per_hz = 1/self.sysclk*(int64(1) << 48) + sysclk = self.cpld.refclk/[1, 1, 2, 4][self.cpld.clk_div]*pll_n + assert sysclk <= 1e9 + self.ftw_per_hz = 1/sysclk*(int64(1) << 48) @kernel def write(self, addr, data, length): From 40187d1957608325c027214ef3e4b78d397a756a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 18 Jan 2019 10:02:26 +0000 Subject: [PATCH 1516/2457] ad9910: support configurable refclk divider and pll bypass for #1248 * also always keep refclk input divider (by two) reset --- artiq/coredevice/ad9910.py | 72 ++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index e23c0428d..42f6945be 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -75,8 +75,10 @@ class AD9910: :param sw_device: Name of the RF switch device. The RF switch is a TTLOut channel available as the :attr:`sw` attribute of this instance. :param pll_n: DDS PLL multiplier. The DDS sample clock is - f_ref/4*pll_n where f_ref is the reference frequency (set in the parent + f_ref/clk_div*pll_n where f_ref is the reference frequency and + clk_div is the reference clock divider (both set in the parent Urukul CPLD instance). + :param pll_en: PLL enable bit, set to 0 to bypass PLL (default: 1). :param pll_cp: DDS PLL charge pump setting. :param pll_vco: DDS PLL VCO range selection. :param sync_delay_seed: SYNC_IN delay tuning starting value. @@ -88,12 +90,11 @@ class AD9910: set this to the delay tap number returned. """ kernel_invariants = {"chip_select", "cpld", "core", "bus", - "ftw_per_hz", "pll_n", "io_update_delay", - "sysclk_per_mu"} + "ftw_per_hz", "io_update_delay", "sysclk_per_mu"} def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, pll_n=40, pll_cp=7, pll_vco=5, sync_delay_seed=-1, - io_update_delay=0): + io_update_delay=0, pll_en=1): self.cpld = dmgr.get(cpld_device) self.core = self.cpld.core self.bus = self.cpld.bus @@ -102,24 +103,30 @@ class AD9910: if sw_device: self.sw = dmgr.get(sw_device) self.kernel_invariants.add("sw") - assert 12 <= pll_n <= 127 + clk = self.cpld.refclk/[4, 1, 2, 4][self.cpld.clk_div] + self.pll_en = pll_en self.pll_n = pll_n - assert self.cpld.refclk/4 <= 60e6 - sysclk = self.cpld.refclk*pll_n/4 # Urukul clock fanout divider + self.pll_vco = pll_vco + self.pll_cp = pll_cp + if pll_en: + sysclk = clk*pll_n + assert clk <= 60e6 + assert 12 <= pll_n <= 127 + assert 0 <= pll_vco <= 5 + vco_min, vco_max = [(370, 510), (420, 590), (500, 700), + (600, 880), (700, 950), (820, 1150)][pll_vco] + assert vco_min <= sysclk/1e6 <= vco_max + assert 0 <= pll_cp <= 7 + else: + sysclk = clk assert sysclk <= 1e9 self.ftw_per_hz = (1 << 32)/sysclk self.sysclk_per_mu = int(round(sysclk*self.core.ref_period)) - assert self.sysclk_per_mu == sysclk*self.core.ref_period - assert 0 <= pll_vco <= 5 - vco_min, vco_max = [(370, 510), (420, 590), (500, 700), - (600, 880), (700, 950), (820, 1150)][pll_vco] - assert vco_min <= sysclk/1e6 <= vco_max - self.pll_vco = pll_vco - assert 0 <= pll_cp <= 7 - self.pll_cp = pll_cp if sync_delay_seed >= 0 and not self.cpld.sync_div: raise ValueError("parent cpld does not drive SYNC") self.sync_delay_seed = sync_delay_seed + if self.sync_delay_seed >= 0: + assert self.sysclk_per_mu == sysclk*self.core.ref_period self.io_update_delay = io_update_delay self.phase_mode = PHASE_MODE_CONTINUOUS @@ -340,24 +347,27 @@ class AD9910: # sync timing validation disable (enabled later) self.write32(_AD9910_REG_CFR2, 0x01010020) self.cpld.io_update.pulse(1*us) - cfr3 = (0x0807c100 | (self.pll_vco << 24) | - (self.pll_cp << 19) | (self.pll_n << 1)) + cfr3 = (0x08078000 | (self.pll_vco << 24) | + (self.pll_cp << 19) | (self.pll_en << 8) | + (self.pll_n << 1)) self.write32(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset self.cpld.io_update.pulse(1*us) - self.write32(_AD9910_REG_CFR3, cfr3) - self.cpld.io_update.pulse(1*us) - if blind: - delay(100*ms) - else: - # Wait for PLL lock, up to 100 ms - for i in range(100): - sta = self.cpld.sta_read() - lock = urukul_sta_pll_lock(sta) - delay(1*ms) - if lock & (1 << self.chip_select - 4): - break - if i >= 100 - 1: - raise ValueError("PLL lock timeout") + if self.pll_en: + self.write32(_AD9910_REG_CFR3, cfr3) + self.cpld.io_update.pulse(1*us) + if blind: + delay(100*ms) + else: + # Wait for PLL lock, up to 100 ms + for i in range(100): + sta = self.cpld.sta_read() + lock = urukul_sta_pll_lock(sta) + delay(1*ms) + if lock & (1 << self.chip_select - 4): + break + if i >= 100 - 1: + raise ValueError("PLL lock timeout") + delay(10*us) # slack if self.sync_delay_seed >= 0: self.tune_sync_delay(self.sync_delay_seed) delay(1*ms) From a2ff2cc1736663a77809a94867906368b84ea8fd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 19 Jan 2019 11:47:50 +0800 Subject: [PATCH 1517/2457] sayma_amc: use more selective IOBUFDS false path --- artiq/gateware/targets/sayma_amc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 472331944..bba5d3711 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -406,9 +406,9 @@ def workaround_us_lvds_tristate(platform): # timing analysis. Disable the latter for IOBUFDS. # See: # https://forums.xilinx.com/t5/Timing-Analysis/Delay-890-ns-in-OBUFTDS-in-Kintex-UltraScale/td-p/868364 - # FIXME: this is a bit zealous. Xilinx SR in progress to find a more selective command. platform.add_platform_command( - "set_false_path -through [get_pins -filter {{REF_PIN_NAME == O}} -of [get_cells -filter {{REF_NAME == IOBUFDS}}]]") + "set_false_path -through [get_pins -filter {{REF_PIN_NAME == T}} -of [get_cells -filter {{REF_NAME == IOBUFDS}}]]" + " -through [get_pins -filter {{REF_PIN_NAME == O}} -of [get_cells -filter {{REF_NAME == IOBUFDS}}]]") class Master(MiniSoC, AMPSoC): From 90c144a685b9ed2bdcaf396f87bfea14bef7dbe3 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 19 Jan 2019 20:17:10 +0000 Subject: [PATCH 1518/2457] test_pc_rpc: Remove leftover debug print [nfc] This tidies up the test suite output, and we have verbose asserts to show further information on breakage, should it occur. --- artiq/test/test_pc_rpc.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/test/test_pc_rpc.py b/artiq/test/test_pc_rpc.py index 4ca81d020..8b095fe9e 100644 --- a/artiq/test/test_pc_rpc.py +++ b/artiq/test/test_pc_rpc.py @@ -108,7 +108,6 @@ class RPCCase(unittest.TestCase): argspec_documented, docstring = pc_rpc.Server._document_function( _annotated_function ) - print(argspec_documented) self.assertEqual(docstring, "Sample docstring.") # purposefully ignore how argspec["annotations"] is treated. From bd718524272124732359c584d33093c1635cb97c Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 8 Mar 2018 18:18:52 +0000 Subject: [PATCH 1519/2457] sync_struct: Tweak variable name to avoid confusion with `init` mod action [nfc] --- artiq/protocols/sync_struct.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/protocols/sync_struct.py b/artiq/protocols/sync_struct.py index 1095e45ef..ee1c0a75c 100644 --- a/artiq/protocols/sync_struct.py +++ b/artiq/protocols/sync_struct.py @@ -19,7 +19,7 @@ from artiq.protocols import pyon from artiq.protocols.asyncio_server import AsyncioServer -_init_string = b"ARTIQ sync_struct\n" +_protocol_banner = b"ARTIQ sync_struct\n" def process_mod(target, mod): @@ -71,7 +71,7 @@ class Subscriber: try: if before_receive_cb is not None: before_receive_cb() - self.writer.write(_init_string) + self.writer.write(_protocol_banner) self.writer.write((self.notifier_name + "\n").encode()) self.receive_task = asyncio.ensure_future(self._receive_cr()) except: @@ -217,7 +217,7 @@ class Publisher(AsyncioServer): async def _handle_connection_cr(self, reader, writer): try: line = await reader.readline() - if line != _init_string: + if line != _protocol_banner: return line = await reader.readline() From c213ab13baa50fc34289d6008a3420830a6ffaf4 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 8 Mar 2018 18:58:38 +0000 Subject: [PATCH 1520/2457] sync_struct: Notifier.{read -> raw_view}, factor out common dict update code [nfc] --- artiq/master/databases.py | 24 +++++++++-------------- artiq/master/experiments.py | 13 ++----------- artiq/master/scheduler.py | 6 ++++-- artiq/master/worker_db.py | 35 ++++++++++++++++++---------------- artiq/protocols/sync_struct.py | 32 ++++++++++++++++++++++++++----- artiq/test/test_sync_struct.py | 2 +- 6 files changed, 62 insertions(+), 50 deletions(-) diff --git a/artiq/master/databases.py b/artiq/master/databases.py index e279b3c56..c96deb9ab 100644 --- a/artiq/master/databases.py +++ b/artiq/master/databases.py @@ -1,7 +1,7 @@ import asyncio import tokenize -from artiq.protocols.sync_struct import Notifier, process_mod +from artiq.protocols.sync_struct import Notifier, process_mod, update_from_dict from artiq.protocols import pyon from artiq.tools import TaskObject @@ -19,20 +19,14 @@ class DeviceDB: self.data = Notifier(device_db_from_file(self.backing_file)) def scan(self): - new_data = device_db_from_file(self.backing_file) - - for k in list(self.data.read.keys()): - if k not in new_data: - del self.data[k] - for k in new_data.keys(): - if k not in self.data.read or self.data.read[k] != new_data[k]: - self.data[k] = new_data[k] + update_from_dict(self.data, + device_db_from_file(self.backing_file)) def get_device_db(self): - return self.data.read + return self.data.raw_view def get(self, key): - return self.data.read[key] + return self.data.raw_view[key] class DatasetDB(TaskObject): @@ -47,7 +41,7 @@ class DatasetDB(TaskObject): self.data = Notifier({k: (True, v) for k, v in file_data.items()}) def save(self): - data = {k: v[1] for k, v in self.data.read.items() if v[0]} + data = {k: v[1] for k, v in self.data.raw_view.items() if v[0]} pyon.store_file(self.persist_file, data) async def _do(self): @@ -59,7 +53,7 @@ class DatasetDB(TaskObject): self.save() def get(self, key): - return self.data.read[key][1] + return self.data.raw_view[key][1] def update(self, mod): process_mod(self.data, mod) @@ -67,8 +61,8 @@ class DatasetDB(TaskObject): # convenience functions (update() can be used instead) def set(self, key, value, persist=None): if persist is None: - if key in self.data.read: - persist = self.data.read[key][0] + if key in self.data.raw_view: + persist = self.data.raw_view[key][0] else: persist = False self.data[key] = (persist, value) diff --git a/artiq/master/experiments.py b/artiq/master/experiments.py index fc2787476..dc17915fc 100644 --- a/artiq/master/experiments.py +++ b/artiq/master/experiments.py @@ -5,7 +5,7 @@ import shutil import time import logging -from artiq.protocols.sync_struct import Notifier +from artiq.protocols.sync_struct import Notifier, update_from_dict from artiq.master.worker import (Worker, WorkerInternalException, log_worker_exception) from artiq.tools import get_windows_drives, exc_to_warning @@ -81,15 +81,6 @@ class _RepoScanner: return r -def _sync_explist(target, source): - for k in list(target.read.keys()): - if k not in source: - del target[k] - for k in source.keys(): - if k not in target.read or target.read[k] != source[k]: - target[k] = source[k] - - class ExperimentDB: def __init__(self, repo_backend, worker_handlers): self.repo_backend = repo_backend @@ -125,7 +116,7 @@ class ExperimentDB: new_explist = await _RepoScanner(self.worker_handlers).scan(wd) logger.info("repository scan took %d seconds", time.monotonic()-t1) - _sync_explist(self.explist, new_explist) + update_from_dict(self.explist, new_explist) finally: self._scanning = False self.status["scanning"] = False diff --git a/artiq/master/scheduler.py b/artiq/master/scheduler.py index 941df76e4..f094ae4f3 100644 --- a/artiq/master/scheduler.py +++ b/artiq/master/scheduler.py @@ -442,8 +442,10 @@ class Scheduler: def get_status(self): """Returns a dictionary containing information about the runs currently - tracked by the scheduler.""" - return self.notifier.read + tracked by the scheduler. + + Must not be modified.""" + return self.notifier.raw_view def check_pause(self, rid): """Returns ``True`` if there is a condition that could make ``pause`` diff --git a/artiq/master/worker_db.py b/artiq/master/worker_db.py index 356a79bef..a1555037f 100644 --- a/artiq/master/worker_db.py +++ b/artiq/master/worker_db.py @@ -110,12 +110,12 @@ class DeviceManager: class DatasetManager: def __init__(self, ddb): - self.broadcast = Notifier(dict()) + self._broadcaster = Notifier(dict()) self.local = dict() self.archive = dict() self.ddb = ddb - self.broadcast.publish = ddb.update + self._broadcaster.publish = ddb.update def set(self, key, value, broadcast=False, persist=False, archive=True): if key in self.archive: @@ -125,10 +125,12 @@ class DatasetManager: if persist: broadcast = True + if broadcast: - self.broadcast[key] = persist, value - elif key in self.broadcast.read: - del self.broadcast[key] + self._broadcaster[key] = persist, value + elif key in self._broadcaster.raw_view: + del self._broadcaster[key] + if archive: self.local[key] = value elif key in self.local: @@ -138,10 +140,10 @@ class DatasetManager: target = None if key in self.local: target = self.local[key] - if key in self.broadcast.read: + if key in self._broadcaster.raw_view: if target is not None: - assert target is self.broadcast.read[key][1] - target = self.broadcast[key][1] + assert target is self._broadcaster.raw_view[key][1] + target = self._broadcaster[key][1] if target is None: raise KeyError("Cannot mutate non-existing dataset") @@ -155,19 +157,20 @@ class DatasetManager: def get(self, key, archive=False): if key in self.local: return self.local[key] - else: - data = self.ddb.get(key) - if archive: - if key in self.archive: - logger.warning("Dataset '%s' is already in archive, " - "overwriting", key, stack_info=True) - self.archive[key] = data - return data + + data = self.ddb.get(key) + if archive: + if key in self.archive: + logger.warning("Dataset '%s' is already in archive, " + "overwriting", key, stack_info=True) + self.archive[key] = data + return data def write_hdf5(self, f): datasets_group = f.create_group("datasets") for k, v in self.local.items(): datasets_group[k] = v + archive_group = f.create_group("archive") for k, v in self.archive.items(): archive_group[k] = v diff --git a/artiq/protocols/sync_struct.py b/artiq/protocols/sync_struct.py index ee1c0a75c..762aa6a62 100644 --- a/artiq/protocols/sync_struct.py +++ b/artiq/protocols/sync_struct.py @@ -127,18 +127,19 @@ class Notifier: >>> n = Notifier([]) >>> n.append([]) >>> n[0].append(42) - >>> n.read + >>> n.raw_view [[42]] This class does not perform any network I/O and is meant to be used with e.g. the :class:`.Publisher` for this purpose. Only one publisher at most can be associated with a :class:`.Notifier`. - :param backing_struct: Structure to encapsulate. For convenience, it - also becomes available as the ``read`` property of the :class:`.Notifier`. + :param backing_struct: Structure to encapsulate. """ def __init__(self, backing_struct, root=None, path=[]): - self.read = backing_struct + #: The raw data encapsulated (read-only!). + self.raw_view = backing_struct + if root is None: self.root = self self.publish = None @@ -197,6 +198,27 @@ class Notifier: return Notifier(item, self.root, self._path + [key]) +def update_from_dict(target, source): + """Updates notifier contents from given source dictionary. + + Only the necessary changes are performed; unchanged fields are not written. + (Currently, modifications are only performed at the top level. That is, + whenever there is a change to a child array/struct the entire member is + updated instead of choosing a more optimal set of mods.) + """ + curr = target.raw_view + + # Delete removed keys. + for k in list(curr.keys()): + if k not in source: + del target[k] + + # Insert/update changed data. + for k in source.keys(): + if k not in curr or curr[k] != source[k]: + target[k] = source[k] + + class Publisher(AsyncioServer): """A network server that publish changes to structures encapsulated in a :class:`.Notifier`. @@ -230,7 +252,7 @@ class Publisher(AsyncioServer): except KeyError: return - obj = {"action": "init", "struct": notifier.read} + obj = {"action": "init", "struct": notifier.raw_view} line = pyon.encode(obj) + "\n" writer.write(line.encode()) diff --git a/artiq/test/test_sync_struct.py b/artiq/test/test_sync_struct.py index fbc199e0f..2352508ac 100644 --- a/artiq/test/test_sync_struct.py +++ b/artiq/test/test_sync_struct.py @@ -63,7 +63,7 @@ class SyncStructCase(unittest.TestCase): await subscriber.close() await publisher.stop() - self.assertEqual(self.received_dict, test_dict.read) + self.assertEqual(self.received_dict, test_dict.raw_view) def test_recv(self): self.loop.run_until_complete(self._do_test_recv()) From e165a9a35290e583aa616b8832c6f948d44b6fe8 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 8 Mar 2018 19:53:33 +0000 Subject: [PATCH 1521/2457] sync_struct: Factor action strings out into enum and document them [nfc] --- artiq/protocols/sync_struct.py | 85 ++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 20 deletions(-) diff --git a/artiq/protocols/sync_struct.py b/artiq/protocols/sync_struct.py index 762aa6a62..49a2e2af4 100644 --- a/artiq/protocols/sync_struct.py +++ b/artiq/protocols/sync_struct.py @@ -4,13 +4,15 @@ modified by one process (the *publisher*) with copies of it (the Synchronization is achieved by sending a full copy of the structure to each subscriber upon connection (*initialization*), followed by dictionaries -describing each modification made to the structure (*mods*). +describing each modification made to the structure (*mods*, see +:class:`ModAction`). Structures must be PYON serializable and contain only lists, dicts, and immutable types. Lists and dicts can be nested arbitrarily. """ import asyncio +from enum import Enum, unique from operator import getitem from functools import partial @@ -22,23 +24,66 @@ from artiq.protocols.asyncio_server import AsyncioServer _protocol_banner = b"ARTIQ sync_struct\n" +@unique +class ModAction(Enum): + """Describes the type of incremental modification. + + `Mods` are represented by a dictionary ``m``. ``m["action"]`` describes + the type of modification, as per this enum, serialized as a string if + required. + + The path (member field) the change applies to is given in + ``m["path"]`` as a list; elements give successive levels of indexing. (There + is no ``path`` on initial initialization.) + + Details on the modification are stored in additional data fields specific + to each type. + + For example, this represents appending the value ``42`` to an array + ``data.counts[0]``: :: + + { + "action": "append", + "path": ["data", "counts", 0], + "x": 42 + } + """ + + #: A full copy of the data is sent in `struct`; no `path` given. + init = "init" + + #: Appends `x` to target list. + append = "append" + + #: Inserts `x` into target list at index `i`. + insert = "insert" + + #: Removes index `i` from target list. + pop = "pop" + + #: Sets target's `key` to `value`. + setitem = "setitem" + + #: Removes target's `key`. + delitem = "delitem" + + +# Handlers to apply a given mod to a target dict, invoked with (target, mod). +_mod_appliers = { + ModAction.append: lambda t, m: t.append(m["x"]), + ModAction.insert: lambda t, m: t.insert(m["i"], m["x"]), + ModAction.pop: lambda t, m: t.pop(m["i"]), + ModAction.setitem: lambda t, m: t.__setitem__(m["key"], m["value"]), + ModAction.delitem: lambda t, m: t.__delitem__(m["key"]) +} + + def process_mod(target, mod): """Apply a *mod* to the target, mutating it.""" for key in mod["path"]: target = getitem(target, key) - action = mod["action"] - if action == "append": - target.append(mod["x"]) - elif action == "insert": - target.insert(mod["i"], mod["x"]) - elif action == "pop": - target.pop(mod["i"]) - elif action == "setitem": - target.__setitem__(mod["key"], mod["value"]) - elif action == "delitem": - target.__delitem__(mod["key"]) - else: - raise ValueError + + _mod_appliers[ModAction(mod["action"])](target, mod) class Subscriber: @@ -155,7 +200,7 @@ class Notifier: """Append to a list.""" self._backing_struct.append(x) if self.root.publish is not None: - self.root.publish({"action": "append", + self.root.publish({"action": ModAction.append.value, "path": self._path, "x": x}) @@ -163,7 +208,7 @@ class Notifier: """Insert an element into a list.""" self._backing_struct.insert(i, x) if self.root.publish is not None: - self.root.publish({"action": "insert", + self.root.publish({"action": ModAction.insert.value, "path": self._path, "i": i, "x": x}) @@ -173,7 +218,7 @@ class Notifier: tracked.""" r = self._backing_struct.pop(i) if self.root.publish is not None: - self.root.publish({"action": "pop", + self.root.publish({"action": ModAction.pop.value, "path": self._path, "i": i}) return r @@ -181,7 +226,7 @@ class Notifier: def __setitem__(self, key, value): self._backing_struct.__setitem__(key, value) if self.root.publish is not None: - self.root.publish({"action": "setitem", + self.root.publish({"action": ModAction.setitem.value, "path": self._path, "key": key, "value": value}) @@ -189,7 +234,7 @@ class Notifier: def __delitem__(self, key): self._backing_struct.__delitem__(key) if self.root.publish is not None: - self.root.publish({"action": "delitem", + self.root.publish({"action": ModAction.delitem.value, "path": self._path, "key": key}) @@ -252,7 +297,7 @@ class Publisher(AsyncioServer): except KeyError: return - obj = {"action": "init", "struct": notifier.raw_view} + obj = {"action": ModAction.init.value, "struct": notifier.raw_view} line = pyon.encode(obj) + "\n" writer.write(line.encode()) From 5c62648ed67d05bcb207a68d35d3f036d22c35f5 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 20 Jan 2019 19:26:43 +0000 Subject: [PATCH 1522/2457] manual: Minor grammar fixes --- doc/manual/management_system.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/management_system.rst b/doc/manual/management_system.rst index 12f5e45d6..7f8561712 100644 --- a/doc/manual/management_system.rst +++ b/doc/manual/management_system.rst @@ -40,7 +40,7 @@ Experiment scheduling Basics ------ -To use hardware resources more efficiently, potentially compute-intensive pre-computation and analysis phases of other experiments is executed in parallel with the body of the current experiment that accesses the hardware. +To use hardware resources more efficiently, potentially compute-intensive pre-computation and analysis phases of other experiments are executed in parallel with the body of the current experiment that accesses the hardware. .. seealso:: These steps are implemented in :class:`~artiq.language.environment.Experiment`. However, user-written experiments should usually derive from (sub-class) :class:`artiq.language.environment.EnvExperiment`. @@ -83,7 +83,7 @@ Multiple pipelines Multiple pipelines can operate in parallel inside the same master. It is the responsibility of the user to ensure that experiments scheduled in one pipeline will never conflict with those of another pipeline over resources (e.g. same devices). -Pipelines are identified by their name, and are automatically created (when an experiment is scheduled with a pipeline name that does not exist) and destroyed (when it runs empty). +Pipelines are identified by their name, and are automatically created (when an experiment is scheduled with a pipeline name that does not exist) and destroyed (when they run empty). Git integration From 8aac5f7695bb22fad49718c40024645a9bd53a3b Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 20 Jan 2019 19:32:58 +0000 Subject: [PATCH 1523/2457] manual/management_system: Cross-reference frontend tools --- doc/manual/management_system.rst | 37 ++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/doc/manual/management_system.rst b/doc/manual/management_system.rst index 7f8561712..b699d310e 100644 --- a/doc/manual/management_system.rst +++ b/doc/manual/management_system.rst @@ -9,14 +9,14 @@ Components Master ------ -The master is responsible for managing the parameter and device databases, the experiment repository, scheduling and running experiments, archiving results, and distributing real-time results. +The :ref:`master ` is responsible for managing the parameter and device databases, the experiment repository, scheduling and running experiments, archiving results, and distributing real-time results. The master is a headless component, and one or several clients (command-line or GUI) use the network to interact with it. Controller manager ------------------ -Controller managers are responsible for running and stopping controllers on a machine. There is one controller manager per network node that runs controllers. +:ref:`Controller managers ` are responsible for running and stopping controllers on a machine. There is one controller manager per network node that runs controllers. A controller manager connects to the master and uses the device database to determine what controllers need to be run. Changes in the device database are tracked by the manager and controllers are started and stopped accordingly. @@ -27,12 +27,12 @@ Controller managers use the local network address of the connection to the maste Command-line client ------------------- -The command-line client connects to the master and permits modification and monitoring of the databases, monitoring the experiment schedule and log, and submitting experiments. +The :ref:`command-line client ` connects to the master and permits modification and monitoring of the databases, monitoring the experiment schedule and log, and submitting experiments. Dashboard --------- -The dashboard connects to the master and is the main way of interacting with it. The main features of the dashboard are scheduling of experiments, setting of their arguments, examining the schedule, displaying real-time results, and debugging TTL and DDS channels in real time. +The :ref:`dashboard ` connects to the master and is the main way of interacting with it. The main features of the dashboard are scheduling of experiments, setting of their arguments, examining the schedule, displaying real-time results, and debugging TTL and DDS channels in real time. Experiment scheduling ********************* @@ -138,25 +138,54 @@ CCBs are used by experiments to configure applets in the dashboard, for example .. autoclass:: artiq.dashboard.applets_ccb.AppletsCCBDock :members: + Front-end tool reference ************************ + +.. _frontend-artiq-master: + +artiq_master +------------ + .. argparse:: :ref: artiq.frontend.artiq_master.get_argparser :prog: artiq_master + +.. _frontend-artiq-ctlmgr: + +artiq_ctlmgr +------------ + .. argparse:: :ref: artiq.frontend.artiq_ctlmgr.get_argparser :prog: artiq_ctlmgr + +.. _frontend-artiq-client: + +artiq_client +------------ + .. argparse:: :ref: artiq.frontend.artiq_client.get_argparser :prog: artiq_client + +.. _frontend-artiq-dashboard: + +artiq_dashboard +--------------- + .. argparse:: :ref: artiq.frontend.artiq_dashboard.get_argparser :prog: artiq_dashboard + +artiq_session +--------------- + .. argparse:: :ref: artiq.frontend.artiq_session.get_argparser :prog: artiq_session From e24e8933039a091bf33700a85996d6257b389883 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 19 Jan 2019 00:07:14 +0000 Subject: [PATCH 1524/2457] master/scheduler: Fix misleading indentation [nfc] --- artiq/master/scheduler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/master/scheduler.py b/artiq/master/scheduler.py index f094ae4f3..4d88bee96 100644 --- a/artiq/master/scheduler.py +++ b/artiq/master/scheduler.py @@ -214,7 +214,7 @@ class PrepareStage(TaskObject): if run.worker.closed.is_set(): break if run.worker.closed.is_set(): - continue + continue run.status = RunStatus.preparing try: await run.build() From 0dab7ecd73d8af0dc20cb1317cbb67ad321ca1cc Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 19 Jan 2019 21:01:48 +0000 Subject: [PATCH 1525/2457] master: Include RID in worker exception messages This helps when debugging unexpected shutdown problems after the fact. --- artiq/master/worker.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/artiq/master/worker.py b/artiq/master/worker.py index 69b6d9a28..ac12ba4b1 100644 --- a/artiq/master/worker.py +++ b/artiq/master/worker.py @@ -165,12 +165,15 @@ class Worker: ifs, timeout=self.send_timeout, return_when=asyncio.FIRST_COMPLETED) if all(f.cancelled() for f in fs): - raise WorkerTimeout("Timeout sending data to worker") + raise WorkerTimeout( + "Timeout sending data to worker (RID {})".format(self.rid)) for f in fs: if not f.cancelled() and f.done(): f.result() # raise any exceptions if cancellable and self.closed.is_set(): - raise WorkerError("Data transmission to worker cancelled") + raise WorkerError( + "Data transmission to worker cancelled (RID {})".format( + self.rid)) async def _recv(self, timeout): assert self.io_lock.locked() @@ -178,16 +181,22 @@ class Worker: [self.ipc.readline(), self.closed.wait()], timeout=timeout, return_when=asyncio.FIRST_COMPLETED) if all(f.cancelled() for f in fs): - raise WorkerTimeout("Timeout receiving data from worker") + raise WorkerTimeout( + "Timeout receiving data from worker (RID {})".format(self.rid)) if self.closed.is_set(): - raise WorkerError("Data transmission to worker cancelled") + raise WorkerError( + "Receiving data from worker cancelled (RID {})".format( + self.rid)) line = fs[0].result() if not line: - raise WorkerError("Worker ended while attempting to receive data") + raise WorkerError( + "Worker ended while attempting to receive data (RID {})". + format(self.rid)) try: obj = pyon.decode(line.decode()) except: - raise WorkerError("Worker sent invalid PYON data") + raise WorkerError("Worker sent invalid PYON data (RID {})".format( + self.rid)) return obj async def _handle_worker_requests(self): From 4ba4e9c540bc4325b27e98bb298768ee74640efd Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 19 Jan 2019 21:36:42 +0000 Subject: [PATCH 1526/2457] test_scheduler: Test for hang when exiting with running experiments The respective code path in artiq.master.scheduler._mk_worker_method wasn't previously covered. --- artiq/test/test_scheduler.py | 47 ++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/artiq/test/test_scheduler.py b/artiq/test/test_scheduler.py index b95a97d9b..e9cc3ceee 100644 --- a/artiq/test/test_scheduler.py +++ b/artiq/test/test_scheduler.py @@ -42,7 +42,7 @@ def _get_expid(name): def _get_basic_steps(rid, expid, priority=0, flush=False): return [ - {"action": "setitem", "key": rid, "value": + {"action": "setitem", "key": rid, "value": {"pipeline": "main", "status": "pending", "priority": priority, "expid": expid, "due_date": None, "flush": flush, "repo_msg": None}, @@ -152,7 +152,7 @@ class SchedulerCase(unittest.TestCase): if mod == {"path": [0], "value": "deleting", "key": "status", - "action": "setitem"}: + "action": "setitem"}: background_completed.set() if mod == {"path": [1], "value": "prepare_done", @@ -185,6 +185,49 @@ class SchedulerCase(unittest.TestCase): loop.run_until_complete(scheduler.stop()) + def test_close_with_active_runs(self): + """Check scheduler exits with experiments still running""" + loop = self.loop + + scheduler = Scheduler(_RIDCounter(0), {}, None) + + expid_bg = _get_expid("BackgroundExperiment") + # Suppress the SystemExit backtrace when worker process is killed. + expid_bg["log_level"] = logging.CRITICAL + expid = _get_expid("EmptyExperiment") + + background_running = asyncio.Event() + empty_ready = asyncio.Event() + background_completed = asyncio.Event() + def notify(mod): + if mod == {"path": [0], + "value": "running", + "key": "status", + "action": "setitem"}: + background_running.set() + if mod == {"path": [0], + "value": "deleting", + "key": "status", + "action": "setitem"}: + background_completed.set() + if mod == {"path": [1], + "value": "prepare_done", + "key": "status", + "action": "setitem"}: + empty_ready.set() + scheduler.notifier.publish = notify + + scheduler.start() + scheduler.submit("main", expid_bg, -99, None, False) + loop.run_until_complete(background_running.wait()) + + scheduler.submit("main", expid, 0, None, False) + loop.run_until_complete(empty_ready.wait()) + + # At this point, (at least) BackgroundExperiment is still running; make + # sure we can stop the scheduler without hanging. + loop.run_until_complete(scheduler.stop()) + def test_flush(self): loop = self.loop scheduler = Scheduler(_RIDCounter(0), dict(), None) From bc532e00880694c2c5cd9528cfdfbb11f87c785e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Jan 2019 17:43:00 +0800 Subject: [PATCH 1527/2457] nix: add libuuid to artiq-dev Required by ISE. --- nix/artiq-dev.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nix/artiq-dev.nix b/nix/artiq-dev.nix index f5b125e65..35d0699ab 100644 --- a/nix/artiq-dev.nix +++ b/nix/artiq-dev.nix @@ -10,6 +10,7 @@ in ncurses5 gnumake zlib + libuuid xorg.libSM xorg.libICE xorg.libXrender From a987d2b2e5fd2f444ae756c915ca4ca5d363a23f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Jan 2019 17:43:48 +0800 Subject: [PATCH 1528/2457] kasli_tester: skip Grabber test when no Grabber is present --- .../kasli_basic/repository/kasli_tester.py | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index 8cc708d53..e6ba1c68f 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -310,18 +310,19 @@ class KasliTester(EnvExperiment): print("ROI sums: {}".format(n)) def test_grabbers(self): - print("*** Testing Grabber Frame Grabbers.") - print("Activate the camera's frame grabber output, type 'g', press " - "ENTER, and trigger the camera.") - print("Just press ENTER to skip the test.") - if input().strip().lower() != "g": - print("skipping...") - return - rois = [[0, 0, 0, 2, 2], [1, 0, 0, 2048, 2048]] - print("ROIs: {}".format(rois)) - for card_n, (card_name, card_dev) in enumerate(self.grabbers): - print(card_name) - self.grabber_capture(card_dev, rois) + if self.grabbers: + print("*** Testing Grabber Frame Grabbers.") + print("Activate the camera's frame grabber output, type 'g', press " + "ENTER, and trigger the camera.") + print("Just press ENTER to skip the test.") + if input().strip().lower() != "g": + print("skipping...") + return + rois = [[0, 0, 0, 2, 2], [1, 0, 0, 2048, 2048]] + print("ROIs: {}".format(rois)) + for card_n, (card_name, card_dev) in enumerate(self.grabbers): + print(card_name) + self.grabber_capture(card_dev, rois) def run(self): print("****** Kasli system tester ******") From bff8c8cb05d1181596c4afbe6836af01ba59d479 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Jan 2019 17:44:17 +0800 Subject: [PATCH 1529/2457] kasli: add Berkeley variant --- .../kasli_basic/device_db_berkeley.py | 234 ++++++++++++++++++ artiq/gateware/targets/kasli.py | 41 ++- 2 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 artiq/examples/kasli_basic/device_db_berkeley.py diff --git a/artiq/examples/kasli_basic/device_db_berkeley.py b/artiq/examples/kasli_basic/device_db_berkeley.py new file mode 100644 index 000000000..3f53550f6 --- /dev/null +++ b/artiq/examples/kasli_basic/device_db_berkeley.py @@ -0,0 +1,234 @@ +core_addr = "kasli-1.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + + +device_db.update({ + "ttl" + str(i): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": i}, + } for i in range(16) +}) + + +for j in range(3): + device_db.update({ + "spi_urukul{}".format(j): { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 16 + 7*j} + }, + "ttl_urukul{}_sync".format(j): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLClockGen", + "arguments": {"channel": 17 + 7*j, "acc_width": 4} + }, + "ttl_urukul{}_io_update".format(j): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 18 + 7*j} + }, + "ttl_urukul{}_sw0".format(j): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 19 + 7*j} + }, + "ttl_urukul{}_sw1".format(j): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 20 + 7*j} + }, + "ttl_urukul{}_sw2".format(j): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 21 + 7*j} + }, + "ttl_urukul{}_sw3".format(j): { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 22 + 7*j} + }, + "urukul{}_cpld".format(j): { + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul{}".format(j), + "sync_device": "ttl_urukul{}_sync".format(j), + "io_update_device": "ttl_urukul{}_io_update".format(j), + "refclk": 125e6, + "clk_sel": 2 + } + } + }) + + device_db.update({ + "urukul{}_ch{}".format(j, i): { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul{}_cpld".format(j), + "sw_device": "ttl_urukul{}_sw{}".format(j, i) + } + } for i in range(4) + }) + + +device_db.update( + spi_urukul3={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 37} + }, + ttl_urukul3_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 38} + }, + ttl_urukul3_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 39} + }, + ttl_urukul3_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 40} + }, + ttl_urukul3_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 41} + }, + ttl_urukul3_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 42} + }, + urukul3_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul3", + "io_update_device": "ttl_urukul3_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul3_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 8, + "chip_select": 4 + i, + "cpld_device": "urukul3_cpld", + "sw_device": "ttl_urukul3_sw" + str(i) + } + } + + +device_db.update({ + "spi_zotino0": { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 43} + }, + "ttl_zotino0_ldac": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 44} + }, + "ttl_zotino0_clr": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 45} + }, + "zotino0": { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino0", + "ldac_device": "ttl_zotino0_ldac", + "clr_device": "ttl_zotino0_clr" + } + } +}) + + +device_db.update({ + "led0": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 46} + }, + "led1": { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 47} + } +}) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 966a5f44c..3fee013ba 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -533,6 +533,45 @@ class NUDT(_StandaloneBase): self.add_rtio(self.rtio_channels) +class Berkeley(_StandaloneBase): + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + # self.config["SI5324_EXT_REF"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) + + self.rtio_channels = [] + eem.DIO.add_std(self, 0, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 1, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 2, 3, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) + eem.Urukul.add_std(self, 4, 5, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) + eem.Urukul.add_std(self, 6, 7, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) + eem.Urukul.add_std(self, 9, 8, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 10, ttl_serdes_7series.Output_8X) + + for i in (1, 2): + sfp_ctl = self.platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + self.add_rtio(self.rtio_channels) + + class PTB(_StandaloneBase): """PTB Kasli variant @@ -1193,7 +1232,7 @@ class VLBAISatellite(_SatelliteBase): VARIANTS = {cls.__name__.lower(): cls for cls in [ Opticlock, SUServo, PTB, PTB2, HUB, LUH, - SYSU, MITLL, MITLL2, USTC, Tsinghua, Tsinghua2, WIPM, NUDT, + SYSU, MITLL, MITLL2, USTC, Tsinghua, Tsinghua2, WIPM, NUDT, Berkeley, VLBAIMaster, VLBAISatellite, Tester, Master, Satellite]} From 30b2f54baa51a7498461f7a656481ab32bba6820 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Jan 2019 18:11:41 +0800 Subject: [PATCH 1530/2457] kasli_tester: skip Zotino test when no Zotino is present --- .../kasli_basic/repository/kasli_tester.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index e6ba1c68f..f86efe5a0 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -280,14 +280,15 @@ class KasliTester(EnvExperiment): zotino.load() def test_zotinos(self): - print("*** Testing Zotino DACs.") - print("Voltages:") - for card_n, (card_name, card_dev) in enumerate(self.zotinos): - voltages = [2*card_n + (-1)**i*0.1*(i//2+1) for i in range(32)] - print(card_name, " ".join(["{:.1f}".format(x) for x in voltages])) - self.set_zotino_voltages(card_dev, voltages) - print("Press ENTER when done.") - input() + if self.zotinos: + print("*** Testing Zotino DACs.") + print("Voltages:") + for card_n, (card_name, card_dev) in enumerate(self.zotinos): + voltages = [2*card_n + (-1)**i*0.1*(i//2+1) for i in range(32)] + print(card_name, " ".join(["{:.1f}".format(x) for x in voltages])) + self.set_zotino_voltages(card_dev, voltages) + print("Press ENTER when done.") + input() @kernel def grabber_capture(self, card_dev, rois): From 30051133b7ee42d2a36f98aa45ece1cdffb12ea0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Jan 2019 19:37:33 +0800 Subject: [PATCH 1531/2457] urukul: fix typos --- artiq/coredevice/ad9910.py | 2 +- artiq/coredevice/urukul.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 42f6945be..d396c3d44 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -615,7 +615,7 @@ class AD9910: This method first locates a valid SYNC_IN delay at zero validation window size (setup/hold margin) by scanning around `search_seed`. It then looks for similar valid delays at successively larger validation - window sizes until none can be found. It then deacreses the validation + window sizes until none can be found. It then decreases the validation window a bit to provide some slack and stability and returns the optimal values. diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 723db47fd..e506775c5 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -340,7 +340,7 @@ class CPLD: and align it to the current RTIO timestamp. The SYNC_IN signal is derived from the coarse RTIO clock - and the divider must be a power of two two. + and the divider must be a power of two. Configure ``sync_sel == 0``. :param div: SYNC_IN frequency divider. Must be a power of two. From 84f7d006e86c451b552bde1f1bcfce7196396917 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Jan 2019 19:38:03 +0800 Subject: [PATCH 1532/2457] ad9910: add precision about tune_io_update_delay/tune_sync_delay order --- artiq/coredevice/ad9910.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index d396c3d44..1db942648 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -619,6 +619,8 @@ class AD9910: window a bit to provide some slack and stability and returns the optimal values. + This method and :meth:`tune_io_update_delay` can be run in any order. + :param search_seed: Start value for valid SYNC_IN delay search. Defaults to 15 (half range). :return: Tuple of optimal delay and window size. @@ -716,6 +718,8 @@ class AD9910: This method assumes that the IO_UPDATE TTLOut device has one machine unit resolution (SERDES). + This method and :meth:`tune_sync_delay` can be run in any order. + :return: Stable IO_UPDATE delay to be passed to the constructor :class:`AD9910` via the device database. """ From e024fa89e5f05fe05cdcdbf9aa28dc844d166c9e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Jan 2019 22:53:57 +0800 Subject: [PATCH 1533/2457] nix: disable maintainer entries for now Causes problem with hydra when building against release nixpkgs, where the sb0 maintainer entry is not present yet. --- nix/pkgs/artiq.nix | 2 +- nix/pkgs/llvm-or1k.nix | 2 +- nix/pkgs/openocd.nix | 2 +- nix/pkgs/rust/binaryBuild.nix | 4 ++-- nix/pkgs/rust/cargo.nix | 2 +- nix/pkgs/rust/rustc.nix | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/nix/pkgs/artiq.nix b/nix/pkgs/artiq.nix index aceab292d..e3db4cbfd 100644 --- a/nix/pkgs/artiq.nix +++ b/nix/pkgs/artiq.nix @@ -74,7 +74,7 @@ python3Packages.buildPythonPackage rec { description = "A leading-edge control system for quantum information experiments"; homepage = https://m-labs/artiq; license = licenses.lgpl3; - maintainers = [ maintainers.sb0 ]; + #maintainers = [ maintainers.sb0 ]; platforms = [ "x86_64-linux" ]; }; } diff --git a/nix/pkgs/llvm-or1k.nix b/nix/pkgs/llvm-or1k.nix index 744a384ca..8b4112499 100644 --- a/nix/pkgs/llvm-or1k.nix +++ b/nix/pkgs/llvm-or1k.nix @@ -39,7 +39,7 @@ stdenv.mkDerivation rec { description = "Collection of modular and reusable compiler and toolchain technologies"; homepage = http://llvm.org/; license = stdenv.lib.licenses.bsd3; - maintainers = with stdenv.lib.maintainers; [ sb0 ]; + #maintainers = with stdenv.lib.maintainers; [ sb0 ]; platforms = stdenv.lib.platforms.all; }; } diff --git a/nix/pkgs/openocd.nix b/nix/pkgs/openocd.nix index ab75bc9f2..23e2f9a19 100644 --- a/nix/pkgs/openocd.nix +++ b/nix/pkgs/openocd.nix @@ -57,7 +57,7 @@ stdenv.mkDerivation rec { ''; homepage = http://openocd.sourceforge.net/; license = licenses.gpl2Plus; - maintainers = with maintainers; [ sb0 ]; + #maintainers = with maintainers; [ sb0 ]; platforms = platforms.linux; }; } diff --git a/nix/pkgs/rust/binaryBuild.nix b/nix/pkgs/rust/binaryBuild.nix index a40383df7..872c4bd03 100644 --- a/nix/pkgs/rust/binaryBuild.nix +++ b/nix/pkgs/rust/binaryBuild.nix @@ -29,7 +29,7 @@ rec { meta = with stdenv.lib; { homepage = http://www.rust-lang.org/; description = "A safe, concurrent, practical language"; - maintainers = with maintainers; [ sb0 ]; + #maintainers = with maintainers; [ sb0 ]; license = [ licenses.mit licenses.asl20 ]; }; @@ -83,7 +83,7 @@ rec { meta = with stdenv.lib; { homepage = http://www.rust-lang.org/; description = "A safe, concurrent, practical language"; - maintainers = with maintainers; [ sb0 ]; + #maintainers = with maintainers; [ sb0 ]; license = [ licenses.mit licenses.asl20 ]; }; diff --git a/nix/pkgs/rust/cargo.nix b/nix/pkgs/rust/cargo.nix index d89eaaa47..cdeca0fa8 100644 --- a/nix/pkgs/rust/cargo.nix +++ b/nix/pkgs/rust/cargo.nix @@ -63,7 +63,7 @@ rustPlatform.buildRustPackage rec { meta = with stdenv.lib; { homepage = https://crates.io; description = "Downloads your Rust project's dependencies and builds your project"; - maintainers = with maintainers; [ sb0 ]; + #maintainers = with maintainers; [ sb0 ]; license = [ licenses.mit licenses.asl20 ]; platforms = platforms.unix; }; diff --git a/nix/pkgs/rust/rustc.nix b/nix/pkgs/rust/rustc.nix index 3c0caf283..34ca3acc5 100644 --- a/nix/pkgs/rust/rustc.nix +++ b/nix/pkgs/rust/rustc.nix @@ -191,7 +191,7 @@ stdenv.mkDerivation { meta = with stdenv.lib; { homepage = https://www.rust-lang.org/; description = "A safe, concurrent, practical language"; - maintainers = with maintainers; [ sb0 ]; + #maintainers = with maintainers; [ sb0 ]; license = [ licenses.mit licenses.asl20 ]; platforms = platforms.linux ++ platforms.darwin; broken = broken; From a9678dd9f2a7d09a4226b613a03f52b558dd8e55 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Jan 2019 23:41:07 +0800 Subject: [PATCH 1534/2457] test_frontends: always skip GUI programs The "import PyQt5" hack breaks on nix/hydra. --- artiq/test/test_frontends.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/artiq/test/test_frontends.py b/artiq/test/test_frontends.py index adb209e54..844812c7a 100644 --- a/artiq/test/test_frontends.py +++ b/artiq/test/test_frontends.py @@ -7,6 +7,7 @@ import unittest class TestFrontends(unittest.TestCase): def test_help(self): """Test --help as a simple smoke test against catastrophic breakage.""" + # Skip tests for GUI programs on headless CI environments. commands = { "aqctl": [ "corelog", "korad_ka3005p", "lda", "novatech409b", @@ -19,13 +20,6 @@ class TestFrontends(unittest.TestCase): ] } - # Skip tests for GUI programs on headless CI environments. - try: - from PyQt5 import QtGui, QtWidgets - commands["artiq"] += ["browser", "dashboard"] - except ImportError: - pass - for module in (prefix + "_" + name for prefix, names in commands.items() for name in names): From 79ffd1e0bfbcf8124e504573592ed56ee5e19191 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Jan 2019 23:42:10 +0800 Subject: [PATCH 1535/2457] nix: enable pythonparser and artiq unittests --- nix/pkgs/artiq.nix | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nix/pkgs/artiq.nix b/nix/pkgs/artiq.nix index e3db4cbfd..bf2dd8a5d 100644 --- a/nix/pkgs/artiq.nix +++ b/nix/pkgs/artiq.nix @@ -22,7 +22,6 @@ pythonparser = python3Packages.buildPythonPackage rec { sha256 = "1gw1fk4y2l6bwq0fg2a9dfc1rvq8cv492dyil96amjdhsxvnx35b"; }; propagatedBuildInputs = with python3Packages; [ regex ]; - doCheck = false; }; asyncserial = python3Packages.buildPythonPackage rec { @@ -69,7 +68,7 @@ python3Packages.buildPythonPackage rec { src = ./../..; buildInputs = [ git ]; propagatedBuildInputs = with python3Packages; [ binutils-or1k llvm-or1k llvmlite levenshtein pyqtgraph-qt5 aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; - doCheck = false; + checkPhase = "python -m unittest discover -v artiq.test"; meta = with stdenv.lib; { description = "A leading-edge control system for quantum information experiments"; homepage = https://m-labs/artiq; From 4869636a55ba1bb18b5a0fcf43b075f720b43753 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Jan 2019 23:55:25 +0800 Subject: [PATCH 1536/2457] nix: remove broken version strings --- nix/pkgs/llvmlite.nix | 5 +---- nix/pkgs/python3Packages.nix | 20 +++++--------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/nix/pkgs/llvmlite.nix b/nix/pkgs/llvmlite.nix index a56977dc4..7905dbae8 100644 --- a/nix/pkgs/llvmlite.nix +++ b/nix/pkgs/llvmlite.nix @@ -1,9 +1,6 @@ { stdenv, fetchFromGitHub, llvm-or1k, makeWrapper, python3, ncurses, zlib, python3Packages }: -let -version = "0f4ebae"; -in stdenv.mkDerivation rec { - name = "llvmlite-${version}"; + name = "llvmlite"; src = fetchFromGitHub { rev = "1d167be4eec5d6c32498952be8b3ac17dd30df8d"; owner = "m-labs"; diff --git a/nix/pkgs/python3Packages.nix b/nix/pkgs/python3Packages.nix index f69f38887..f4b16a396 100644 --- a/nix/pkgs/python3Packages.nix +++ b/nix/pkgs/python3Packages.nix @@ -2,9 +2,7 @@ rec { asyncserial = python3Packages.buildPythonPackage rec { - version = "git-09a9fc"; - pname = "asyncserial"; - name = "${pname}-${version}"; + name = "asyncserial"; src = fetchFromGitHub { owner = "m-labs"; @@ -24,9 +22,7 @@ rec { }; }; misoc = python3Packages.buildPythonPackage rec { - version = "git-714ea6"; - pname = "misoc"; - name = "${pname}-${version}"; + name = "misoc"; src = fetchFromGitHub { owner = "m-labs"; @@ -49,9 +45,7 @@ rec { }; }; migen = python3Packages.buildPythonPackage rec { - version = "git-3d8a58"; - pname = "migen"; - name = "${pname}-${version}"; + name = "migen"; src = fetchFromGitHub { owner = "m-labs"; @@ -74,9 +68,7 @@ rec { }; }; microscope = python3Packages.buildPythonPackage rec { - version = "git-02cffc"; - pname = "microscope"; - name = "${pname}-${version}"; + name = "microscope"; src = fetchFromGitHub { owner = "m-labs"; @@ -95,9 +87,7 @@ rec { }; }; jesd204b = python3Packages.buildPythonPackage rec { - version = "git-02cffc"; - pname = "jesd204b"; - name = "${pname}-${version}"; + name = "jesd204b"; src = fetchFromGitHub { owner = "m-labs"; From 81ff3d4b29fe7b43e13386e7dbbabcc71fc696c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 21 Jan 2019 17:10:58 +0000 Subject: [PATCH 1537/2457] ad9912: add some slack after init --- artiq/coredevice/ad9912.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 62694bbbe..03aafaa58 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -107,6 +107,7 @@ class AD9912: # I_cp = 375 µA, VCO high range self.write(AD9912_PLLCFG, 0b00000101, length=1) self.cpld.io_update.pulse(2*us) + delay(1*ms) @kernel def set_att_mu(self, att): From 217493523199aea8649c7f91a63b0bbe3173d645 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 22 Jan 2019 15:06:13 +0800 Subject: [PATCH 1538/2457] nix: update package descriptions --- nix/pkgs/llvmlite.nix | 8 ++++++++ nix/pkgs/python3Packages.nix | 2 +- nix/pkgs/rust/default.nix | 7 +++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/nix/pkgs/llvmlite.nix b/nix/pkgs/llvmlite.nix index 7905dbae8..9c7ef6e4b 100644 --- a/nix/pkgs/llvmlite.nix +++ b/nix/pkgs/llvmlite.nix @@ -14,4 +14,12 @@ stdenv.mkDerivation rec { LLVM_CONFIG=${llvm-or1k}/bin/llvm-config python3 setup.py install --prefix=$out ''; + + meta = with stdenv.lib; { + description = "A lightweight LLVM python binding for writing JIT compilers"; + homepage = "http://llvmlite.pydata.org/"; + #maintainers = with maintainers; [ sb0 ]; + license = licenses.bsd2; + platforms = platforms.unix; + }; } diff --git a/nix/pkgs/python3Packages.nix b/nix/pkgs/python3Packages.nix index f4b16a396..538df4d5e 100644 --- a/nix/pkgs/python3Packages.nix +++ b/nix/pkgs/python3Packages.nix @@ -38,7 +38,7 @@ rec { propagatedBuildInputs = with python3Packages; [ pyserial jinja2 numpy asyncserial migen ]; meta = with stdenv.lib; { - description = "A high performance and small footprint system-on-chip based on Migen https://m-labs.hk"; + description = "A high performance and small footprint system-on-chip based on Migen"; homepage = "https://m-labs.hk/migen"; license = licenses.bsd2; platforms = platforms.unix; diff --git a/nix/pkgs/rust/default.nix b/nix/pkgs/rust/default.nix index 1a392124e..fa8f93856 100644 --- a/nix/pkgs/rust/default.nix +++ b/nix/pkgs/rust/default.nix @@ -48,6 +48,13 @@ in rec { cp -r ${or1k-crates}/* $out/lib/rustlib/or1k-unknown-none/lib/ cp -r ${rustc_internal}/* $out ''; + meta = with stdenv.lib; { + homepage = https://www.rust-lang.org/; + description = "A safe, concurrent, practical language"; + #maintainers = with maintainers; [ sb0 ]; + license = [ licenses.mit licenses.asl20 ]; + platforms = platforms.linux ++ platforms.darwin; + }; }; # nixcloud team code # originally rustc but now renamed to rustc_internal From 91e375ce6acd6b626b1040abefd1af7c1cdb9d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 22 Jan 2019 09:36:21 +0000 Subject: [PATCH 1539/2457] ad9910: don't reset the input divide-by-two MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit suspected of causing weird PLL lock timout errors https://freenode.irclog.whitequark.org/m-labs/2019-01-22#1548148750-1548143221; Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 1db942648..5ef117c38 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -347,7 +347,7 @@ class AD9910: # sync timing validation disable (enabled later) self.write32(_AD9910_REG_CFR2, 0x01010020) self.cpld.io_update.pulse(1*us) - cfr3 = (0x08078000 | (self.pll_vco << 24) | + cfr3 = (0x0807c000 | (self.pll_vco << 24) | (self.pll_cp << 19) | (self.pll_en << 8) | (self.pll_n << 1)) self.write32(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset From 9ee5fea88d4d08f41f1cfe19bee88e58b2ac602d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 22 Jan 2019 18:04:33 +0800 Subject: [PATCH 1540/2457] kasli: support optional SATA port for DRTIO --- artiq/gateware/targets/kasli.py | 37 ++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 3fee013ba..46cb578e1 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -850,7 +850,7 @@ class _MasterBase(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, rtio_clk_freq=150e6, **kwargs): + def __init__(self, rtio_clk_freq=150e6, enable_sata=False, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -872,18 +872,29 @@ class _MasterBase(MiniSoC, AMPSoC): self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) + drtio_data_pads = [] + if enable_sata: + drtio_data_pads.append(platform.request("sata")) + drtio_data_pads += [platform.request("sfp", i) for i in range(1, 3)] + sfp_ctls = [platform.request("sfp_ctl", i) for i in range(1, 3)] self.comb += [sc.tx_disable.eq(0) for sc in sfp_ctls] + self.submodules.drtio_transceiver = gtp_7series.GTP( qpll_channel=self.drtio_qpll_channel, - data_pads=[platform.request("sfp", i) for i in range(1, 3)], + data_pads=drtio_data_pads, sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") self.sync += self.disable_si5324_ibuf.eq( ~self.drtio_transceiver.stable_clkin.storage) + + if enable_sata: + sfp_channels = self.drtio_transceiver.channels[1:] + else: + sfp_channels = self.drtio_transceiver.channels self.comb += [sfp_ctl.led.eq(channel.rx_ready) - for sfp_ctl, channel in zip(sfp_ctls, self.drtio_transceiver.channels)] + for sfp_ctl, channel in zip(sfp_ctls, sfp_channels)] self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) @@ -891,7 +902,7 @@ class _MasterBase(MiniSoC, AMPSoC): drtioaux_csr_group = [] drtioaux_memory_group = [] self.drtio_cri = [] - for i in range(2): + for i in range(len(self.drtio_transceiver.channels)): core_name = "drtio" + str(i) coreaux_name = "drtioaux" + str(i) memory_name = "drtioaux" + str(i) + "_mem" @@ -999,7 +1010,7 @@ class _SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, rtio_clk_freq=150e6, **kwargs): + def __init__(self, rtio_clk_freq=150e6, enable_sata=False, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -1025,18 +1036,28 @@ class _SatelliteBase(BaseSoC): qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings) self.submodules += qpll + drtio_data_pads = [] + if enable_sata: + drtio_data_pads.append(platform.request("sata")) + drtio_data_pads += [platform.request("sfp", i) for i in range(3)] + sfp_ctls = [platform.request("sfp_ctl", i) for i in range(3)] self.comb += [sc.tx_disable.eq(0) for sc in sfp_ctls] self.submodules.drtio_transceiver = gtp_7series.GTP( qpll_channel=qpll.channels[0], - data_pads=[platform.request("sfp", i) for i in range(3)], + data_pads=drtio_data_pads, sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") self.sync += disable_si5324_ibuf.eq( ~self.drtio_transceiver.stable_clkin.storage) + + if enable_sata: + sfp_channels = self.drtio_transceiver.channels[1:] + else: + sfp_channels = self.drtio_transceiver.channels self.comb += [sfp_ctl.led.eq(channel.rx_ready) - for sfp_ctl, channel in zip(sfp_ctls, self.drtio_transceiver.channels)] + for sfp_ctl, channel in zip(sfp_ctls, sfp_channels)] self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) @@ -1044,7 +1065,7 @@ class _SatelliteBase(BaseSoC): drtioaux_memory_group = [] drtiorep_csr_group = [] self.drtio_cri = [] - for i in range(3): + for i in range(len(self.drtio_transceiver.channels)): coreaux_name = "drtioaux" + str(i) memory_name = "drtioaux" + str(i) + "_mem" drtioaux_csr_group.append(coreaux_name) From 2e3555de85af322ff68d6474fb60d876cbfccba3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 22 Jan 2019 19:35:46 +0800 Subject: [PATCH 1541/2457] firmware: fix compilation error with more than 1 Grabber --- artiq/firmware/libboard_artiq/grabber.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/libboard_artiq/grabber.rs b/artiq/firmware/libboard_artiq/grabber.rs index ba5e2a4db..e9266015a 100644 --- a/artiq/firmware/libboard_artiq/grabber.rs +++ b/artiq/firmware/libboard_artiq/grabber.rs @@ -9,6 +9,7 @@ enum State { Watch } +#[derive(Clone, Copy)] struct Info { state: State, frame_size: (u16, u16), From a0eba5b09ba25d05ff522360515a73929d4738fe Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 22 Jan 2019 19:36:13 +0800 Subject: [PATCH 1542/2457] satman: support Grabber --- artiq/firmware/satman/main.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index d7f757b99..180ccbcba 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -367,6 +367,14 @@ fn init_rtio_crg() { #[cfg(not(has_rtio_crg))] fn init_rtio_crg() { } +fn hardware_tick(ts: &mut u64) { + let now = clock::get_ms(); + if now > *ts { + #[cfg(has_grabber)] + board_artiq::grabber::tick(); + *ts = now + 200; + } +} #[cfg(rtio_frequency = "150.0")] const SI5324_SETTINGS: si5324::FrequencySettings @@ -432,12 +440,15 @@ pub extern fn main() -> i32 { let mut routing_table = drtio_routing::RoutingTable::default_empty(); let mut rank = 1; + let mut hardware_tick_ts = 0; + loop { while !drtiosat_link_rx_up() { drtiosat_process_errors(); for mut rep in repeaters.iter_mut() { rep.service(&routing_table, rank); } + hardware_tick(&mut hardware_tick_ts); } info!("uplink is up, switching to recovered clock"); @@ -473,6 +484,7 @@ pub extern fn main() -> i32 { for mut rep in repeaters.iter_mut() { rep.service(&routing_table, rank); } + hardware_tick(&mut hardware_tick_ts); if drtiosat_tsc_loaded() { info!("TSC loaded from uplink"); #[cfg(has_ad9154)] From b692981c8e3bbeb48b70846fa8f2a0fb97285bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 22 Jan 2019 11:49:09 +0000 Subject: [PATCH 1543/2457] ad9910: add note about red front panel led MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 5ef117c38..17c3c7a33 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -79,6 +79,7 @@ class AD9910: clk_div is the reference clock divider (both set in the parent Urukul CPLD instance). :param pll_en: PLL enable bit, set to 0 to bypass PLL (default: 1). + Note that when bypassing the PLL the red front panel LED may remain on. :param pll_cp: DDS PLL charge pump setting. :param pll_vco: DDS PLL VCO range selection. :param sync_delay_seed: SYNC_IN delay tuning starting value. From 01f1df7e505fbc5d991042ea531cb136d47e85f9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 23 Jan 2019 11:17:48 +0800 Subject: [PATCH 1544/2457] nix: fix version strings in artiq-dev environment --- nix/artiq-dev.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nix/artiq-dev.nix b/nix/artiq-dev.nix index 35d0699ab..7d93ae476 100644 --- a/nix/artiq-dev.nix +++ b/nix/artiq-dev.nix @@ -19,6 +19,7 @@ in xorg.libXtst xorg.libXi (python3.withPackages(ps: with ps; [ jinja2 numpy artiqpkgs.migen artiqpkgs.microscope artiqpkgs.misoc artiqpkgs.jesd204b artiqpkgs.artiq ])) + git ] ++ (with artiqpkgs; [ rustc From 81f2b2c86414e9032220672b66fd5b9a5cd7931e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 23 Jan 2019 12:14:44 +0800 Subject: [PATCH 1545/2457] kasli: remove unpopulated Tester EEMs * matches hardware and avoids issues with programs that process the DDB (e.g. kasli_tester) * shortens compilation times --- artiq/examples/kasli_tester/device_db.py | 142 +---------------------- artiq/gateware/targets/kasli.py | 15 --- 2 files changed, 2 insertions(+), 155 deletions(-) diff --git a/artiq/examples/kasli_tester/device_db.py b/artiq/examples/kasli_tester/device_db.py index bcffa8fa2..96cd249e8 100644 --- a/artiq/examples/kasli_tester/device_db.py +++ b/artiq/examples/kasli_tester/device_db.py @@ -189,156 +189,18 @@ device_db["zotino0"] = { } -# Grabber (EEM6) starting at RTIO channel 25 -device_db["grabber0"] = { - "type": "local", - "module": "artiq.coredevice.grabber", - "class": "Grabber", - "arguments": {"channel_base": 25} -} - - -# Urukul (EEM7) starting at RTIO channel 27 -device_db.update( - spi_urukul1={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 27} - }, - ttl_urukul1_sync={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLClockGen", - "arguments": {"channel": 28, "acc_width": 4} - }, - ttl_urukul1_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 29} - }, - urukul1_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul1", - "io_update_device": "ttl_urukul1_io_update", - "sync_device": "ttl_urukul1_sync", - "refclk": 100e6, - "clk_sel": 1 - } - } -) - -for i in range(4): - device_db["urukul1_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9912", - "class": "AD9912", - "arguments": { - "pll_n": 10, - "chip_select": 4 + i, - "cpld_device": "urukul1_cpld" - } - } - - -# DIO (EEM8) starting at RTIO channel 30 -for i in range(8): - device_db["ttl" + str(8 + i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 30 + i}, - } - - -# DIO (EEM9) starting at RTIO channel 38 -for i in range(8): - device_db["ttl" + str(16 + i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 38 + i}, - } - - -# Sampler (EEM10) starting at RTIO channel 46 -device_db["spi_sampler1_adc"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 46} -} -device_db["spi_sampler1_pgia"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 47} -} -device_db["spi_sampler1_cnv"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 48}, -} -device_db["sampler1"] = { - "type": "local", - "module": "artiq.coredevice.sampler", - "class": "Sampler", - "arguments": { - "spi_adc_device": "spi_sampler1_adc", - "spi_pgia_device": "spi_sampler1_pgia", - "cnv_device": "spi_sampler1_cnv" - } -} - - -# Zotino (EEM11) starting at RTIO channel 49 -device_db["spi_zotino1"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 49} -} -device_db["ttl_zotino1_ldac"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 50} -} -device_db["ttl_zotino1_clr"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 51} -} -device_db["zotino1"] = { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino1", - "ldac_device": "ttl_zotino1_ldac", - "clr_device": "ttl_zotino1_clr" - } -} - - device_db.update( led0={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 52} + "arguments": {"channel": 25} }, led1={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 53} + "arguments": {"channel": 26} }, ) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 46cb578e1..8c17c765a 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -774,7 +774,6 @@ class Tester(_StandaloneBase): self.comb += self.platform.request("clk_sel").eq(1) self.rtio_channels = [] - self.grabber_csr_group = [] eem.DIO.add_std(self, 5, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X, edge_counter_cls=edge_counter.SimpleEdgeCounter) @@ -782,15 +781,6 @@ class Tester(_StandaloneBase): ttl_simple.ClockGen) eem.Sampler.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) eem.Zotino.add_std(self, 4, ttl_serdes_7series.Output_8X) - eem.Grabber.add_std(self, 6) - eem.Urukul.add_std(self, 7, None, ttl_serdes_7series.Output_8X, - ttl_simple.ClockGen) - eem.DIO.add_std(self, 8, - ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) - eem.DIO.add_std(self, 9, - ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) - eem.Sampler.add_std(self, 10, None, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 11, ttl_serdes_7series.Output_8X) for i in (1, 2): sfp_ctl = self.platform.request("sfp_ctl", i) @@ -803,11 +793,6 @@ class Tester(_StandaloneBase): self.rtio_channels.append(rtio.LogChannel()) self.add_rtio(self.rtio_channels) - self.config["HAS_GRABBER"] = None - self.add_csr_group("grabber", self.grabber_csr_group) - self.platform.add_false_path_constraints( - self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) - class _RTIOClockMultiplier(Module, AutoCSR): def __init__(self, rtio_clk_freq): From d7e6f104d29e7ac2d35a09e801fc7cb55eeb2ad5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 23 Jan 2019 14:11:51 +0800 Subject: [PATCH 1546/2457] kasli: add HUST variants --- artiq/examples/kasli_basic/device_db_hust.py | 323 +++++++++++++++++++ artiq/gateware/targets/kasli.py | 51 ++- 2 files changed, 373 insertions(+), 1 deletion(-) create mode 100644 artiq/examples/kasli_basic/device_db_hust.py diff --git a/artiq/examples/kasli_basic/device_db_hust.py b/artiq/examples/kasli_basic/device_db_hust.py new file mode 100644 index 000000000..07d861766 --- /dev/null +++ b/artiq/examples/kasli_basic/device_db_hust.py @@ -0,0 +1,323 @@ +core_addr = "kasli-1.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + +kasli2 = 0x010000 + +for i in range(16): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": i}, + } + +for i in range(8): + device_db["ttl" + str(16+i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": kasli2 | i}, + } + +device_db.update( + spi_urukul0={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 16} + }, + ttl_urukul0_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 17} + }, + ttl_urukul0_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 18} + }, + ttl_urukul0_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 19} + }, + ttl_urukul0_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 20} + }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 21} + }, + urukul0_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 125e6, + "clk_sel": 2 + } + } +) + +for i in range(4): + device_db["urukul0_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } + + +device_db.update( + spi_urukul1={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 22} + }, + ttl_urukul1_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 23} + }, + ttl_urukul1_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 24} + }, + ttl_urukul1_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 25} + }, + ttl_urukul1_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 26} + }, + ttl_urukul1_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 27} + }, + urukul1_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul1", + "io_update_device": "ttl_urukul1_io_update", + "refclk": 125e6, + "clk_sel": 2 + } + } +) + +for i in range(4): + device_db["urukul1_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul1_cpld", + "sw_device": "ttl_urukul1_sw" + str(i) + } + } + + +device_db.update( + spi_urukul2={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": kasli2 | 12} + }, + ttl_urukul2_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": kasli2 | 13} + }, + ttl_urukul2_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": kasli2 | 14} + }, + ttl_urukul2_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": kasli2 | 15} + }, + ttl_urukul2_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": kasli2 | 16} + }, + ttl_urukul2_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": kasli2 | 17} + }, + urukul2_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul2", + "io_update_device": "ttl_urukul2_io_update", + "refclk": 125e6, + "clk_sel": 0 + } + } +) + +for i in range(4): + device_db["urukul2_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": { + "pll_n": 8, + "chip_select": 4 + i, + "cpld_device": "urukul2_cpld", + "sw_device": "ttl_urukul2_sw" + str(i) + } + } + + +device_db["spi_sampler0_adc"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 28} +} +device_db["spi_sampler0_pgia"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 29} +} +device_db["spi_sampler0_cnv"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 30}, +} +device_db["sampler0"] = { + "type": "local", + "module": "artiq.coredevice.sampler", + "class": "Sampler", + "arguments": { + "spi_adc_device": "spi_sampler0_adc", + "spi_pgia_device": "spi_sampler0_pgia", + "cnv_device": "spi_sampler0_cnv" + } +} + + +device_db["grabber0"] = { + "type": "local", + "module": "artiq.coredevice.grabber", + "class": "Grabber", + "arguments": {"channel_base": kasli2 | 8} +} + +device_db["grabber1"] = { + "type": "local", + "module": "artiq.coredevice.grabber", + "class": "Grabber", + "arguments": {"channel_base": kasli2 | 10} +} + + +device_db["spi_zotino0"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": kasli2 | 18} +} +device_db["ttl_zotino0_ldac"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": kasli2 | 19} +} +device_db["ttl_zotino0_clr"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": kasli2 | 20} +} +device_db["zotino0"] = { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino0", + "ldac_device": "ttl_zotino0_ldac", + "clr_device": "ttl_zotino0_clr" + } +} diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 8c17c765a..b7d12dc0b 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -1236,10 +1236,59 @@ class VLBAISatellite(_SatelliteBase): self.add_rtio(self.rtio_channels) +class HUSTMaster(_MasterBase): + def __init__(self, hw_rev=None, *args, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _MasterBase.__init__(self, rtio_clk_freq=125e6, hw_rev=hw_rev, + enable_sata=True, *args, **kwargs) + + self.rtio_channels = [] + eem.DIO.add_std(self, 0, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.DIO.add_std(self, 1, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 2, 3, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 4, 5, ttl_serdes_7series.Output_8X) + eem.Sampler.add_std(self, 6, 7, ttl_serdes_7series.Output_8X) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(self.rtio_channels) + + +class HUSTSatellite(_SatelliteBase): + def __init__(self, hw_rev=None, *args, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _SatelliteBase.__init__(self, rtio_clk_freq=125e6, hw_rev=hw_rev, + enable_sata=True, *args, **kwargs) + + self.rtio_channels = [] + self.grabber_csr_group = [] + eem.DIO.add_std(self, 0, + ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) + eem.Grabber.add_std(self, 1, 2) + eem.Grabber.add_std(self, 3, 4) + eem.Urukul.add_std(self, 5, 6, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) + + self.add_rtio(self.rtio_channels) + self.config["HAS_GRABBER"] = None + self.add_csr_group("grabber", self.grabber_csr_group) + self.platform.add_false_path_constraints( + self.drtio_transceiver.gtps[0].txoutclk, self.grabber0.deserializer.cd_cl.clk) + self.platform.add_false_path_constraints( + self.drtio_transceiver.gtps[0].txoutclk, self.grabber1.deserializer.cd_cl.clk) + + VARIANTS = {cls.__name__.lower(): cls for cls in [ Opticlock, SUServo, PTB, PTB2, HUB, LUH, SYSU, MITLL, MITLL2, USTC, Tsinghua, Tsinghua2, WIPM, NUDT, Berkeley, - VLBAIMaster, VLBAISatellite, Tester, Master, Satellite]} + VLBAIMaster, VLBAISatellite, HUSTMaster, HUSTSatellite, + Tester, Master, Satellite]} def main(): From 390f05f762c34d4ce7f2d7c0a5414870f0f0f351 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 23 Jan 2019 16:15:05 +0800 Subject: [PATCH 1547/2457] firmware: use smoltcp release --- artiq/firmware/Cargo.lock | 12 ++++++------ artiq/firmware/bootloader/Cargo.toml | 7 +------ artiq/firmware/libboard_misoc/Cargo.toml | 7 +------ artiq/firmware/runtime/Cargo.toml | 7 +------ 4 files changed, 9 insertions(+), 24 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index de1abb72b..5f68ddb78 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -31,7 +31,7 @@ dependencies = [ "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=92e970b)", + "smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -42,7 +42,7 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=92e970b)", + "smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -216,7 +216,7 @@ dependencies = [ "logger_artiq 0.0.0", "managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "proto_artiq 0.0.0", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=92e970b)", + "smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "unwind_backtrace 0.0.0", ] @@ -232,8 +232,8 @@ dependencies = [ [[package]] name = "smoltcp" -version = "0.4.0" -source = "git+https://github.com/m-labs/smoltcp?rev=92e970b#92e970b3798737cfaa2a829d3f1bb7a7353696ee" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -294,7 +294,7 @@ version = "0.0.0" "checksum log_buffer 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f033173c9486b7fe97a79c895c0a3483ae395ab6744c985d10078950e2492419" "checksum managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba6713e624266d7600e9feae51b1926c6a6a6bebb18ec5a8e11a5f1d5661baba" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=92e970b)" = "" +"checksum smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fef582369edb298c6c41319a544ca9c4e83622f226055ccfcb35974fbb55ed34" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml index be9ab36e9..2a43b72f5 100644 --- a/artiq/firmware/bootloader/Cargo.toml +++ b/artiq/firmware/bootloader/Cargo.toml @@ -16,9 +16,4 @@ build_misoc = { path = "../libbuild_misoc" } byteorder = { version = "1.0", default-features = false } crc = { version = "1.7", default-features = false } board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp"] } - -[dependencies.smoltcp] -git = "https://github.com/m-labs/smoltcp" -rev = "92e970b" -default-features = false -features = ["proto-ipv4", "socket-tcp"] +smoltcp = { version = "0.5.0", default-features = false, features = ["proto-ipv4", "socket-tcp"] } diff --git a/artiq/firmware/libboard_misoc/Cargo.toml b/artiq/firmware/libboard_misoc/Cargo.toml index aae40b6b1..8847d0a0d 100644 --- a/artiq/firmware/libboard_misoc/Cargo.toml +++ b/artiq/firmware/libboard_misoc/Cargo.toml @@ -15,12 +15,7 @@ build_misoc = { path = "../libbuild_misoc" } [dependencies] byteorder = { version = "1.0", default-features = false } log = { version = "0.4", default-features = false, optional = true } - -[dependencies.smoltcp] -git = "https://github.com/m-labs/smoltcp" -rev = "92e970b" # NB: also change in runtime/Cargo.toml -default-features = false -optional = true +smoltcp = { version = "0.5.0", default-features = false, optional = true } [features] uart_console = [] diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 1a7da3375..4c187b1ff 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -27,15 +27,10 @@ board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp logger_artiq = { path = "../liblogger_artiq" } board_artiq = { path = "../libboard_artiq" } proto_artiq = { path = "../libproto_artiq", features = ["log", "alloc"] } +smoltcp = { version = "0.5.0", default-features = false, features = ["rust-1_28", "alloc", "log", "proto-ipv4", "socket-tcp"] } [dependencies.fringe] git = "https://github.com/m-labs/libfringe" rev = "b8a6d8f" default-features = false features = ["alloc"] - -[dependencies.smoltcp] -git = "https://github.com/m-labs/smoltcp" -rev = "92e970b" # NB: also change in libboard_misoc/Cargo.toml -default-features = false -features = ["rust-1.28", "alloc", "log", "proto-ipv4", "socket-tcp"] From 330c5610e9f1876c73d629bb10931952a115aae7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 23 Jan 2019 17:59:08 +0800 Subject: [PATCH 1548/2457] ad9912: fix imports --- artiq/coredevice/ad9912.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 03aafaa58..adcfcb4dc 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -1,7 +1,7 @@ from numpy import int32, int64 from artiq.language.core import kernel, delay, portable -from artiq.language.units import us, ns +from artiq.language.units import ms, us, ns from artiq.coredevice.ad9912_reg import * from artiq.coredevice import spi2 as spi From 3b5fd3ac116feba15eb12e9cfd8d9d6f53b32467 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 23 Jan 2019 17:59:25 +0800 Subject: [PATCH 1549/2457] kasli_tester: fix grabber test --- artiq/examples/kasli_basic/repository/kasli_tester.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index f86efe5a0..4acdecd73 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -308,7 +308,7 @@ class KasliTester(EnvExperiment): card_dev.input_mu(n) self.core.break_realtime() card_dev.gate_roi(0) - print("ROI sums: {}".format(n)) + print("ROI sums:", n) def test_grabbers(self): if self.grabbers: @@ -320,7 +320,7 @@ class KasliTester(EnvExperiment): print("skipping...") return rois = [[0, 0, 0, 2, 2], [1, 0, 0, 2048, 2048]] - print("ROIs: {}".format(rois)) + print("ROIs:", rois) for card_n, (card_name, card_dev) in enumerate(self.grabbers): print(card_name) self.grabber_capture(card_dev, rois) From 154269b77af2f04e8ae461b57cc24da8558f0d08 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 23 Jan 2019 17:59:43 +0800 Subject: [PATCH 1550/2457] kasli: fix HUST satellite Urukul --- artiq/gateware/targets/kasli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b7d12dc0b..b84f19995 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -1272,7 +1272,7 @@ class HUSTSatellite(_SatelliteBase): ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) eem.Grabber.add_std(self, 1, 2) eem.Grabber.add_std(self, 3, 4) - eem.Urukul.add_std(self, 5, 6, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 6, 5, ttl_serdes_7series.Output_8X) eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) self.add_rtio(self.rtio_channels) From 3917a0ef4691912fa506ec2f38636a63585f4898 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 23 Jan 2019 21:59:39 +0800 Subject: [PATCH 1551/2457] nix: support reusing dev environment in build scripts --- nix/README.rst | 2 +- nix/artiq-dev.nix | 7 ++++--- nix/shell-dev.nix | 4 ++++ 3 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 nix/shell-dev.nix diff --git a/nix/README.rst b/nix/README.rst index f0ac1eb40..24998d2dd 100644 --- a/nix/README.rst +++ b/nix/README.rst @@ -28,7 +28,7 @@ The above command will setup your entire environment. Note that it will compile ARTIQ development environment with Nix ====================================== -Run ``nix-shell artiq-dev.nix`` to obtain an environment containing Migen, MiSoC, Microscope, jesd204b, Clang, Rust, Cargo, and OpenOCD in addition to the user environment above. +Run ``nix-shell shell-dev.nix`` to obtain an environment containing Migen, MiSoC, Microscope, jesd204b, Clang, Rust, Cargo, and OpenOCD in addition to the user environment above. This creates a FHS chroot environment in order to simplify the installation and patching of Xilinx Vivado (it needs to be installed manually e.g. in your home folder). diff --git a/nix/artiq-dev.nix b/nix/artiq-dev.nix index 7d93ae476..eab47ef59 100644 --- a/nix/artiq-dev.nix +++ b/nix/artiq-dev.nix @@ -1,8 +1,9 @@ +{runScript ? "", extraProfile ? ""}: + let pkgs = import {}; artiqpkgs = import ./default.nix { inherit pkgs; }; in -( pkgs.buildFHSUserEnv { name = "artiq-dev"; targetPkgs = pkgs: ( @@ -29,8 +30,8 @@ in openocd ]) ); + runScript = runScript; profile = '' export TARGET_AR=${artiqpkgs.binutils-or1k}/bin/or1k-linux-ar - ''; + '' + extraProfile; } -).env diff --git a/nix/shell-dev.nix b/nix/shell-dev.nix new file mode 100644 index 000000000..ee2e8a764 --- /dev/null +++ b/nix/shell-dev.nix @@ -0,0 +1,4 @@ +let + artiq-dev = import ./artiq-dev.nix {}; +in + artiq-dev.env From 0a0e8c3c933c050aa9d71aac2e404e3f98e9b900 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 24 Jan 2019 16:20:02 +0800 Subject: [PATCH 1552/2457] nix: bump migen/misoc --- nix/pkgs/python3Packages.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nix/pkgs/python3Packages.nix b/nix/pkgs/python3Packages.nix index 538df4d5e..4ec3b531b 100644 --- a/nix/pkgs/python3Packages.nix +++ b/nix/pkgs/python3Packages.nix @@ -27,8 +27,8 @@ rec { src = fetchFromGitHub { owner = "m-labs"; repo = "misoc"; - rev = "308b4728bdb1900fe3c9d71c10cc84322ad3e4ed"; - sha256 = "0fc1axrwjhb86m2dwkj6h3qwwci9xw0jsvg8pzb2r8hci2v8432h"; + rev = "8e033c2cb77f78c95d2b2e08125324891d07fa34"; + sha256 = "0pv1akhvr85iswqmhzcqh9gfnyha11k68qmhqizma8fdccvvzm4y"; fetchSubmodules = true; }; @@ -50,8 +50,8 @@ rec { src = fetchFromGitHub { owner = "m-labs"; repo = "migen"; - rev = "3d8a58033ea0e90e435db0d14c25c86ee7d2fee2"; - sha256 = "0fw70bzang79wylwsw9b47vssjnhx6mwzm00dg3b49iyg57jymvh"; + rev = "57c44674c2a6c38bd01804e69db61a9efd287524"; + sha256 = "1xl7bb21ijp6i25hf12gyjwjmv52sbv81fz44fmkiz5b25xlbmaq"; fetchSubmodules = true; }; From 31592fc8e472a740241cf5a3f792a5e07a08d1b6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 24 Jan 2019 16:47:37 +0800 Subject: [PATCH 1553/2457] nix: install flash proxy bitstreams with OpenOCD --- nix/pkgs/openocd.nix | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/nix/pkgs/openocd.nix b/nix/pkgs/openocd.nix index 23e2f9a19..4ec524e33 100644 --- a/nix/pkgs/openocd.nix +++ b/nix/pkgs/openocd.nix @@ -2,14 +2,20 @@ stdenv.mkDerivation rec { name = "openocd-${version}"; - version = "0.10.0"; + version = "0.10.0.mlabs"; src = fetchFromGitHub { - owner = "m-labs"; - repo = "openocd"; - fetchSubmodules = true; - rev = "c383a57adcff332b2c5cf8d55a84626285b42c2c"; - sha256 = "0xlj9cs72acx3zqagvr7f1c0v6lnqhl8fgrlhgmhmvk5n9knk492"; + owner = "m-labs"; + repo = "openocd"; + fetchSubmodules = true; + rev = "c383a57adcff332b2c5cf8d55a84626285b42c2c"; + sha256 = "0xlj9cs72acx3zqagvr7f1c0v6lnqhl8fgrlhgmhmvk5n9knk492"; + }; + bscan_spi_bitstreams = fetchFromGitHub { + owner = "quartiq"; + repo = "bscan_spi_bitstreams"; + rev = "a628956da7dc794e6e3c95b31ff9ce3af58bc763"; + sha256 = "1cydbym3wv9jwxh6lw9im1mjzr7w8rzzx95bxkjschmzjq4h13vk"; }; nativeBuildInputs = [ pkgconfig ]; @@ -42,6 +48,9 @@ stdenv.mkDerivation rec { exit 1 fi ln -s "$rules" "$out/etc/udev/rules.d/" + + mkdir -p "$out/share/bscan-spi-bitstreams" + cp ${bscan_spi_bitstreams}/*.bit "$out/share/bscan-spi-bitstreams" ''; meta = with stdenv.lib; { From 07b5b0d36d55fe65ff7305f938f963d9fcf60f6e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 24 Jan 2019 18:27:15 +0800 Subject: [PATCH 1554/2457] kasli: adapt Master target to new hardware --- artiq/examples/kasli_sawgmaster/device_db.py | 2 +- artiq/gateware/targets/kasli.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/examples/kasli_sawgmaster/device_db.py b/artiq/examples/kasli_sawgmaster/device_db.py index 6d3f9d7ec..b93d777d1 100644 --- a/artiq/examples/kasli_sawgmaster/device_db.py +++ b/artiq/examples/kasli_sawgmaster/device_db.py @@ -78,7 +78,7 @@ device_db.update( "spi_device": "spi_urukul0", "io_update_device": "ttl_urukul0_io_update", "refclk": 150e6, - "clk_sel": 0 + "clk_sel": 2 } } ) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index b84f19995..16c27c452 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -1150,7 +1150,7 @@ class Master(_MasterBase): # matches Tester EEM numbers eem.DIO.add_std(self, 5, ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 1, 0, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 0, 1, ttl_serdes_7series.Output_8X) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) From f8b39b0b9a986b7e43ef386ca92bfebc28f7d6ee Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 24 Jan 2019 18:28:01 +0800 Subject: [PATCH 1555/2457] sayma: enable 2X DAC interpolation Seems to work just fine and gets one clock divider out of the way. --- artiq/firmware/libboard_artiq/ad9154.rs | 2 +- artiq/firmware/libboard_artiq/hmc830_7043.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index e9b7db5db..5b876b371 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -184,7 +184,7 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { write(ad9154_reg::SPI_PAGEINDX, 0x3); // A and B dual - write(ad9154_reg::INTERP_MODE, 0); // 1x + write(ad9154_reg::INTERP_MODE, 0x01); // 2x write(ad9154_reg::MIX_MODE, 0); write(ad9154_reg::DATA_FORMAT, 0*ad9154_reg::BINARY_FORMAT); // s16 write(ad9154_reg::DATAPATH_CTRL, diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 2b381e60d..8156c5d36 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -156,7 +156,7 @@ pub mod hmc7043 { use board_misoc::{csr, clock}; // All frequencies assume 1.2GHz HMC830 output - const DAC_CLK_DIV: u16 = 2; // 600MHz + const DAC_CLK_DIV: u16 = 1; // 1200MHz const FPGA_CLK_DIV: u16 = 8; // 150MHz const SYSREF_DIV: u16 = 128; // 9.375MHz const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // 1.171875MHz (must be <= 4MHz) From a92cc91dcbf6bfb5d9eb68a7ffd5d0cdeb2f4b5f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 24 Jan 2019 19:37:14 +0800 Subject: [PATCH 1556/2457] kasli_sawgmaster: correctly tune DDS and SAWG --- artiq/examples/kasli_sawgmaster/device_db.py | 3 ++- .../kasli_sawgmaster/repository/sines_urukul_sayma.py | 11 +++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/artiq/examples/kasli_sawgmaster/device_db.py b/artiq/examples/kasli_sawgmaster/device_db.py index b93d777d1..70fa47ab1 100644 --- a/artiq/examples/kasli_sawgmaster/device_db.py +++ b/artiq/examples/kasli_sawgmaster/device_db.py @@ -89,7 +89,8 @@ for i in range(4): "module": "artiq.coredevice.ad9910", "class": "AD9910", "arguments": { - "pll_n": 26, # 975MHz sample rate + "pll_n": 16, # 600MHz sample rate + "pll_vco": 2, "chip_select": 4 + i, "cpld_device": "urukul0_cpld", "sw_device": "ttl_urukul0_sw" + str(i) diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py index c23ea99a6..9732b8295 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py @@ -17,6 +17,13 @@ class SinesUrukulSayma(EnvExperiment): @kernel def run(self): + f = 9*MHz + dds_ftw = self.urukul_chs[0].frequency_to_ftw(f) + sawg_ftw = self.sawgs[0].frequency0.to_mu(f) + if dds_ftw != sawg_ftw: + print("DDS and SAWG FTWs do not match:", dds_ftw, sawg_ftw) + return + # Note: when testing sync, do not reboot Urukul, as it is not # synchronized to the FPGA (yet). self.core.reset() @@ -24,7 +31,7 @@ class SinesUrukulSayma(EnvExperiment): for urukul_ch in self.urukul_chs: delay(1*ms) urukul_ch.init() - urukul_ch.set(9*MHz, amplitude=0.5) + urukul_ch.set_mu(dds_ftw, asf=urukul_ch.amplitude_to_asf(0.5)) urukul_ch.set_att(6.) urukul_ch.sw.on() @@ -43,7 +50,7 @@ class SinesUrukulSayma(EnvExperiment): for sawg in self.sawgs: delay(1*ms) sawg.amplitude1.set(.4) - sawg.frequency0.set(9*MHz) + sawg.frequency0.set_mu(sawg_ftw) while self.drtio_is_up(): pass From bbac92442f5db6d12cf4a080c58d686e58226207 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 24 Jan 2019 20:13:43 +0800 Subject: [PATCH 1557/2457] sayma: check hmc7043 slip period --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 8 +-- artiq/firmware/libboard_artiq/jesd204sync.rs | 56 ++++++++++++++------ 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 8156c5d36..b3972d911 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -156,10 +156,10 @@ pub mod hmc7043 { use board_misoc::{csr, clock}; // All frequencies assume 1.2GHz HMC830 output - const DAC_CLK_DIV: u16 = 1; // 1200MHz - const FPGA_CLK_DIV: u16 = 8; // 150MHz - const SYSREF_DIV: u16 = 128; // 9.375MHz - const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // 1.171875MHz (must be <= 4MHz) + pub const DAC_CLK_DIV: u16 = 1; // 1200MHz + pub const FPGA_CLK_DIV: u16 = 8; // 150MHz + pub const SYSREF_DIV: u16 = 128; // 9.375MHz + const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // 1.171875MHz (must be <= 4MHz) // enabled, divider, output config const OUTPUT_CONFIG: [(bool, u16, u8); 14] = [ diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index c4cc18810..8d66f81bc 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -67,6 +67,42 @@ fn sysref_cal_fpga() -> Result { return Err("failed to reach 1->0 transition with fine delay"); } +fn sysref_rtio_slip_to(target: bool) -> Result { + let mut slips = 0; + while sysref_sample() != target { + hmc7043::sysref_slip(); + slips += 1; + if slips > 1024 { + return Err("failed to reach SYSREF transition"); + } + } + Ok(slips) +} + +fn sysref_rtio_check_period(phase_offset: u16) -> Result<(), &'static str> { + const N: usize = 32; + let mut nslips = [0; N]; + let mut error = false; + + // meet setup/hold (assuming FPGA timing margins are OK) + hmc7043::sysref_offset_fpga(phase_offset); + // if we are already in the 1 zone, get out of it + sysref_rtio_slip_to(false)?; + for i in 0..N { + nslips[i] = sysref_rtio_slip_to(i % 2 == 0)?; + if nslips[i] != hmc7043::SYSREF_DIV/2 { + error = true; + } + } + if error { + info!(" SYSREF slip half-periods: {:?}", nslips); + return Err("unexpected SYSREF slip half-periods seen"); + } else { + info!(" SYSREF slip half-periods at FPGA have expected length ({})", hmc7043::SYSREF_DIV/2); + } + Ok(()) +} + fn sysref_rtio_align(phase_offset: u16) -> Result<(), &'static str> { // This needs to take place before DAC SYSREF scan, as // the HMC7043 input clock (which defines slip resolution) @@ -75,26 +111,14 @@ fn sysref_rtio_align(phase_offset: u16) -> Result<(), &'static str> { info!("aligning SYSREF with RTIO..."); - let mut slips0 = 0; - let mut slips1 = 0; + sysref_rtio_check_period(phase_offset)?; + // meet setup/hold (assuming FPGA timing margins are OK) hmc7043::sysref_offset_fpga(phase_offset); // if we are already in the 1 zone, get out of it - while sysref_sample() { - hmc7043::sysref_slip(); - slips0 += 1; - if slips0 > 1024 { - return Err("failed to reach 1->0 transition"); - } - } + let slips0 = sysref_rtio_slip_to(false)?; // get to the edge of the 0->1 transition (our final setpoint) - while !sysref_sample() { - hmc7043::sysref_slip(); - slips1 += 1; - if slips1 > 1024 { - return Err("failed to reach 0->1 transition"); - } - } + let slips1 = sysref_rtio_slip_to(true)?; info!(" ...done ({}/{} slips)", slips0, slips1); let mut margin_minus = None; From 8c5a50259149cb4963ca23bfd55b8c1d8912a9fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 24 Jan 2019 14:46:38 +0000 Subject: [PATCH 1558/2457] ad53xx: ignore F3 (reserved) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad53xx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index 7e8654d63..c19239583 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -176,7 +176,7 @@ class AD53xx: (AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_CONTROL | 0b0010) << 8) if not blind: ctrl = self.read_reg(channel=0, op=AD53XX_READ_CONTROL) - if ctrl != 0b0010: + if (ctrl & 0b10111) != 0b00010: raise ValueError("DAC CONTROL readback mismatch") delay(15*us) From cc9420d2c8ee1e30f93f6d0511f00f089f7e343a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 25 Jan 2019 11:48:02 +0800 Subject: [PATCH 1559/2457] hmc7043: fix divider programming --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index b3972d911..9d62a774f 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -300,7 +300,7 @@ pub mod hmc7043 { // Set SYSREF timer divider. // We don't need this "feature", but the HMC7043 won't work without. write(0x5c, (HMC_SYSREF_DIV & 0xff) as u8); - write(0x5d, ((HMC_SYSREF_DIV & 0x0f) >> 8) as u8); + write(0x5d, ((HMC_SYSREF_DIV & 0xf00) >> 8) as u8); for channel in 0..OUTPUT_CONFIG.len() { let channel_base = 0xc8 + 0x0a*(channel as u16); @@ -318,7 +318,7 @@ pub mod hmc7043 { write(channel_base, 0x10); } write(channel_base + 0x1, (divider & 0xff) as u8); - write(channel_base + 0x2, ((divider & 0x0f) >> 8) as u8); + write(channel_base + 0x2, ((divider & 0xf00) >> 8) as u8); // bypass analog phase shift on DCLK channels to reduce noise if channel % 2 == 0 { From 4941fb33005cbe4694a66596338fabe0ef4fc171 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 25 Jan 2019 13:47:04 +0800 Subject: [PATCH 1560/2457] sayma: 2.4GHz DAC clocking (4X interpolation) * gets another clock divider out of the way * gets one cycle within range of the HMC7043 analog delay alone * SYSREF/RTIO alignment removed, to be replaced with DDMTD-based scheme --- artiq/firmware/libboard_artiq/ad9154.rs | 2 +- artiq/firmware/libboard_artiq/hmc830_7043.rs | 41 ++--- artiq/firmware/libboard_artiq/jesd204sync.rs | 176 +------------------ artiq/firmware/runtime/main.rs | 3 + artiq/firmware/satman/main.rs | 3 + artiq/gateware/jesd204_tools.py | 19 -- artiq/gateware/targets/sayma_amc.py | 12 -- 7 files changed, 29 insertions(+), 227 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 5b876b371..ff5f08311 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -184,7 +184,7 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { write(ad9154_reg::SPI_PAGEINDX, 0x3); // A and B dual - write(ad9154_reg::INTERP_MODE, 0x01); // 2x + write(ad9154_reg::INTERP_MODE, 0x03); // 4x write(ad9154_reg::MIX_MODE, 0); write(ad9154_reg::DATA_FORMAT, 0*ad9154_reg::BINARY_FORMAT); // s16 write(ad9154_reg::DATAPATH_CTRL, diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 9d62a774f..6e6212808 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -117,6 +117,9 @@ mod hmc830 { // Max reference frequency: 350MHz, however f_ref >= 200MHz requires // setting 0x08[21]=1 // + // Warning: Output divider is not synchronized! Set to 1 for deterministic + // phase at the output. + // // :param r_div: reference divider [1, 16383] // :param n_div: VCO divider, integer part. Integer-N mode: [16, 2**19-1] // fractional mode: [20, 2**19-4] @@ -155,10 +158,11 @@ mod hmc830 { pub mod hmc7043 { use board_misoc::{csr, clock}; - // All frequencies assume 1.2GHz HMC830 output - pub const DAC_CLK_DIV: u16 = 1; // 1200MHz - pub const FPGA_CLK_DIV: u16 = 8; // 150MHz - pub const SYSREF_DIV: u16 = 128; // 9.375MHz + // Warning: dividers are not synchronized with HMC830 clock input! + // Set DAC_CLK_DIV to 1 for deterministic phase. + pub const DAC_CLK_DIV: u16 = 1; // 2400MHz + pub const FPGA_CLK_DIV: u16 = 16; // 150MHz + pub const SYSREF_DIV: u16 = 256; // 9.375MHz const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // 1.171875MHz (must be <= 4MHz) // enabled, divider, output config @@ -385,35 +389,18 @@ pub mod hmc7043 { } } - pub fn sysref_offset_dac(dacno: u8, phase_offset: u16) { - /* Analog delay resolution: 25ps - * Digital delay resolution: 1/2 input clock cycle = 416ps for 1.2GHz - * 16*25ps = 400ps: limit analog delay to 16 steps instead of 32. - */ - let analog_delay = (phase_offset % 17) as u8; - let digital_delay = (phase_offset / 17) as u8; + pub fn sysref_offset_dac(dacno: u8, phase_offset: u8) { spi_setup(); if dacno == 0 { - write(0x00d5, analog_delay); - write(0x00d6, digital_delay); + write(0x00d5, phase_offset); } else if dacno == 1 { - write(0x00e9, analog_delay); - write(0x00ea, digital_delay); + write(0x00e9, phase_offset); } else { unimplemented!(); } clock::spin_us(100); } - pub fn sysref_offset_fpga(phase_offset: u16) { - let analog_delay = (phase_offset % 17) as u8; - let digital_delay = (phase_offset / 17) as u8; - spi_setup(); - write(0x0111, analog_delay); - write(0x0112, digital_delay); - clock::spin_us(100); - } - pub fn sysref_slip() { spi_setup(); write(0x0002, 0x02); @@ -429,11 +416,11 @@ pub fn init() -> Result<(), &'static str> { hmc830::detect()?; hmc830::init(); - // 1.2GHz out + // 2.4GHz out #[cfg(hmc830_ref = "100")] - hmc830::set_dividers(1, 24, 0, 2); + hmc830::set_dividers(1, 24, 0, 1); #[cfg(hmc830_ref = "150")] - hmc830::set_dividers(2, 32, 0, 2); + hmc830::set_dividers(2, 32, 0, 1); hmc830::check_locked()?; diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 8d66f81bc..eb51590e1 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -3,167 +3,7 @@ use board_misoc::{csr, config}; use hmc830_7043::hmc7043; use ad9154; -fn sysref_sample() -> bool { - unsafe { csr::sysref_sampler::sample_result_read() == 1 } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum SysrefSample { - Low, - High, - Unstable -} - -fn sysref_sample_stable(phase_offset: u16) -> SysrefSample { - hmc7043::sysref_offset_fpga(phase_offset); - let s1 = sysref_sample(); - hmc7043::sysref_offset_fpga(phase_offset-5); - let s2 = sysref_sample(); - if s1 == s2 { - if s1 { - return SysrefSample::High; - } else { - return SysrefSample::Low; - } - } else { - return SysrefSample::Unstable; - } -} - -fn sysref_cal_fpga() -> Result { - info!("calibrating SYSREF phase offset at FPGA..."); - - let initial_phase_offset = 136; - - let mut slips0 = 0; - let mut slips1 = 0; - // make sure we start in the 0 zone - while sysref_sample_stable(initial_phase_offset) != SysrefSample::Low { - hmc7043::sysref_slip(); - slips0 += 1; - if slips0 > 1024 { - return Err("failed to reach 1->0 transition (cal)"); - } - } - - // get near the edge of the 0->1 transition - while sysref_sample_stable(initial_phase_offset) != SysrefSample::High { - hmc7043::sysref_slip(); - slips1 += 1; - if slips1 > 1024 { - return Err("failed to reach 0->1 transition (cal)"); - } - } - - for d in 0..initial_phase_offset { - let phase_offset = initial_phase_offset - d; - hmc7043::sysref_offset_fpga(phase_offset); - if !sysref_sample() { - let result = phase_offset + 17; - info!(" ...done, phase offset: {}", result); - return Ok(result); - } - } - return Err("failed to reach 1->0 transition with fine delay"); -} - -fn sysref_rtio_slip_to(target: bool) -> Result { - let mut slips = 0; - while sysref_sample() != target { - hmc7043::sysref_slip(); - slips += 1; - if slips > 1024 { - return Err("failed to reach SYSREF transition"); - } - } - Ok(slips) -} - -fn sysref_rtio_check_period(phase_offset: u16) -> Result<(), &'static str> { - const N: usize = 32; - let mut nslips = [0; N]; - let mut error = false; - - // meet setup/hold (assuming FPGA timing margins are OK) - hmc7043::sysref_offset_fpga(phase_offset); - // if we are already in the 1 zone, get out of it - sysref_rtio_slip_to(false)?; - for i in 0..N { - nslips[i] = sysref_rtio_slip_to(i % 2 == 0)?; - if nslips[i] != hmc7043::SYSREF_DIV/2 { - error = true; - } - } - if error { - info!(" SYSREF slip half-periods: {:?}", nslips); - return Err("unexpected SYSREF slip half-periods seen"); - } else { - info!(" SYSREF slip half-periods at FPGA have expected length ({})", hmc7043::SYSREF_DIV/2); - } - Ok(()) -} - -fn sysref_rtio_align(phase_offset: u16) -> Result<(), &'static str> { - // This needs to take place before DAC SYSREF scan, as - // the HMC7043 input clock (which defines slip resolution) - // is 2x the DAC clock, so there are two possible phases from - // the divider states. This deterministically selects one. - - info!("aligning SYSREF with RTIO..."); - - sysref_rtio_check_period(phase_offset)?; - - // meet setup/hold (assuming FPGA timing margins are OK) - hmc7043::sysref_offset_fpga(phase_offset); - // if we are already in the 1 zone, get out of it - let slips0 = sysref_rtio_slip_to(false)?; - // get to the edge of the 0->1 transition (our final setpoint) - let slips1 = sysref_rtio_slip_to(true)?; - info!(" ...done ({}/{} slips)", slips0, slips1); - - let mut margin_minus = None; - for d in 0..phase_offset { - hmc7043::sysref_offset_fpga(phase_offset - d); - if !sysref_sample() { - margin_minus = Some(d); - break; - } - } - // meet setup/hold - hmc7043::sysref_offset_fpga(phase_offset); - - if margin_minus.is_some() { - let margin_minus = margin_minus.unwrap(); - // one phase slip (period of the 1.2GHz input clock) - let period = 2*17; // approximate: 2 digital coarse delay steps - let margin_plus = if period > margin_minus { period - margin_minus } else { 0 }; - info!(" margins at FPGA: -{} +{}", margin_minus, margin_plus); - if margin_minus < 10 || margin_plus < 10 { - return Err("SYSREF margin at FPGA is too small, board needs recalibration"); - } - } else { - return Err("unable to determine SYSREF margin at FPGA"); - } - - Ok(()) -} - -pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { - let entry = config::read_str("sysref_phase_fpga", |r| r.map(|s| s.parse())); - let phase_offset = match entry { - Ok(Ok(phase)) => phase, - _ => { - let phase = sysref_cal_fpga()?; - if let Err(e) = config::write_int("sysref_phase_fpga", phase as u32) { - error!("failed to update FPGA SYSREF phase in config: {}", e); - } - phase - } - }; - sysref_rtio_align(phase_offset) -} - -fn sysref_cal_dac(dacno: u8) -> Result { +fn sysref_cal_dac(dacno: u8) -> Result { info!("calibrating SYSREF phase at DAC-{}...", dacno); let mut d = 0; @@ -182,12 +22,12 @@ fn sysref_cal_dac(dacno: u8) -> Result { } d += 1; - if d > 128 { + if d > 23 { return Err("no sync errors found when scanning delay"); } } - d += 17; // get away from jitter + d += 5; // get away from jitter hmc7043::sysref_offset_dac(dacno, d); ad9154::dac_sync(dacno)?; @@ -200,7 +40,7 @@ fn sysref_cal_dac(dacno: u8) -> Result { } d += 1; - if d > 128 { + if d > 23 { return Err("no sync errors found when scanning delay"); } } @@ -210,7 +50,7 @@ fn sysref_cal_dac(dacno: u8) -> Result { Ok(phase) } -fn sysref_dac_align(dacno: u8, phase: u16) -> Result<(), &'static str> { +fn sysref_dac_align(dacno: u8, phase: u8) -> Result<(), &'static str> { let mut margin_minus = None; let mut margin_plus = None; @@ -218,7 +58,7 @@ fn sysref_dac_align(dacno: u8, phase: u16) -> Result<(), &'static str> { hmc7043::sysref_offset_dac(dacno, phase); ad9154::dac_sync(dacno)?; - for d in 0..128 { + for d in 0..24 { hmc7043::sysref_offset_dac(dacno, phase - d); let realign_occured = ad9154::dac_sync(dacno)?; if realign_occured { @@ -229,7 +69,7 @@ fn sysref_dac_align(dacno: u8, phase: u16) -> Result<(), &'static str> { hmc7043::sysref_offset_dac(dacno, phase); ad9154::dac_sync(dacno)?; - for d in 0..128 { + for d in 0..24 { hmc7043::sysref_offset_dac(dacno, phase + d); let realign_occured = ad9154::dac_sync(dacno)?; if realign_occured { @@ -242,7 +82,7 @@ fn sysref_dac_align(dacno: u8, phase: u16) -> Result<(), &'static str> { let margin_minus = margin_minus.unwrap(); let margin_plus = margin_plus.unwrap(); info!(" margins: -{} +{}", margin_minus, margin_plus); - if margin_minus < 10 || margin_plus < 10 { + if margin_minus < 5 || margin_plus < 5 { return Err("SYSREF margins at DAC are too small, board needs recalibration"); } } else { diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index c905d5df4..11866e389 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -115,9 +115,12 @@ fn startup() { { board_artiq::ad9154::jesd_reset(false); board_artiq::ad9154::init(); + /* + TODO: if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { error!("failed to align SYSREF at FPGA: {}", e); } + */ if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() { error!("failed to align SYSREF at DAC: {}", e); } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 180ccbcba..2f226f4ab 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -489,9 +489,12 @@ pub extern fn main() -> i32 { info!("TSC loaded from uplink"); #[cfg(has_ad9154)] { + /* + TODO: if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { error!("failed to align SYSREF at FPGA: {}", e); } + */ if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() { error!("failed to align SYSREF at DAC: {}", e); } diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index 5e8c5e85d..1aa605a8d 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -91,22 +91,3 @@ class UltrascaleTX(Module, AutoCSR): self.submodules.control = JESD204BCoreTXControl(self.core) self.core.register_jsync(platform.request("dac_sync", dac)) self.core.register_jref(jesd_crg.jref) - - -# This assumes: -# * coarse RTIO frequency = 16*SYSREF frequency -# * JESD and coarse RTIO clocks are the same -# (only reset may differ). -# * SYSREF meets setup/hold at the FPGA when sampled -# in the JESD/RTIO domain. -# -# Look at the 4 LSBs of the coarse RTIO timestamp counter -# to determine SYSREF phase. - -class SysrefSampler(Module, AutoCSR): - def __init__(self, coarse_ts, jref): - self.sample_result = CSRStatus() - - sample = Signal() - self.sync.jesd += If(coarse_ts[:4] == 0, sample.eq(jref)) - self.specials += MultiReg(sample, self.sample_result.status) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index bba5d3711..2970877c5 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -223,10 +223,6 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") - self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( - self.rtio_tsc.coarse_ts, self.ad9154_crg.jref) - self.csr_devices.append("sysref_sampler") - class MasterDAC(MiniSoC, AMPSoC, RTMCommon): """ @@ -395,10 +391,6 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) self.csr_devices.append("routing_table") - self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( - self.rtio_tsc.coarse_ts, self.ad9154_crg.jref) - self.csr_devices.append("sysref_sampler") - def workaround_us_lvds_tristate(platform): # Those shoddy Kintex Ultrascale FPGAs take almost a microsecond to change the direction of a @@ -684,10 +676,6 @@ class Satellite(BaseSoC, RTMCommon): self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None - self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( - self.rtio_tsc.coarse_ts, self.ad9154_crg.jref) - self.csr_devices.append("sysref_sampler") - rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] platform.add_period_constraint(gth.txoutclk, rtio_clk_period/2) From 3356717316ae6b90611588927d805c058b1a3346 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 25 Jan 2019 16:00:31 +0800 Subject: [PATCH 1561/2457] sayma: DDMTD SYSREF measurement demonstration --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 2 +- artiq/firmware/libboard_artiq/jesd204sync.rs | 9 +++ artiq/firmware/runtime/main.rs | 3 - artiq/firmware/satman/main.rs | 3 - artiq/gateware/jesd204_tools.py | 68 +++++++++++++++++++- artiq/gateware/targets/sayma_amc.py | 9 +++ 6 files changed, 86 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 6e6212808..56435807d 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -178,7 +178,7 @@ pub mod hmc7043 { (true, FPGA_CLK_DIV, 0x08), // 8: GTP_CLK1 (false, 0, 0x10), // 9: AMC_MASTER_AUX_CLK (false, 0, 0x10), // 10: RTM_MASTER_AUX_CLK - (false, 0, 0x10), // 11: FPGA_ADC_SYSREF, LVDS + (true, FPGA_CLK_DIV, 0x10), // 11: FPGA_ADC_SYSREF, LVDS, used for DDMTD RTIO/SYSREF alignment (false, 0, 0x08), // 12: ADC1_CLK (false, 0, 0x08), // 13: ADC1_SYSREF ]; diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index eb51590e1..062135896 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -3,6 +3,15 @@ use board_misoc::{csr, config}; use hmc830_7043::hmc7043; use ad9154; +pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { + for _ in 0..256 { + hmc7043::sysref_slip(); + let dt = unsafe { csr::sysref_ddmtd::dt_read() }; + info!("dt={}", dt); + } + Ok(()) +} + fn sysref_cal_dac(dacno: u8) -> Result { info!("calibrating SYSREF phase at DAC-{}...", dacno); diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 11866e389..c905d5df4 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -115,12 +115,9 @@ fn startup() { { board_artiq::ad9154::jesd_reset(false); board_artiq::ad9154::init(); - /* - TODO: if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { error!("failed to align SYSREF at FPGA: {}", e); } - */ if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() { error!("failed to align SYSREF at DAC: {}", e); } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 2f226f4ab..180ccbcba 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -489,12 +489,9 @@ pub extern fn main() -> i32 { info!("TSC loaded from uplink"); #[cfg(has_ad9154)] { - /* - TODO: if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { error!("failed to align SYSREF at FPGA: {}", e); } - */ if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() { error!("failed to align SYSREF at DAC: {}", e); } diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index 1aa605a8d..b029c86c2 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -1,7 +1,7 @@ from collections import namedtuple from migen import * -from migen.genlib.cdc import MultiReg +from migen.genlib.cdc import MultiReg, BusSynchronizer from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.interconnect.csr import * @@ -91,3 +91,69 @@ class UltrascaleTX(Module, AutoCSR): self.submodules.control = JESD204BCoreTXControl(self.core) self.core.register_jsync(platform.request("dac_sync", dac)) self.core.register_jref(jesd_crg.jref) + + +# See "Digital femtosecond time difference circuit for CERN's timing system" +# by P. Moreira and I. Darwazeh +class DDMTD(Module, AutoCSR): + def __init__(self, input_pads, rtio_clk_freq=150e6): + N = 64 + self.dt = CSRStatus(N.bit_length()) + + # # # + + self.clock_domains.cd_helper = ClockDomain(reset_less=True) + helper_fb = Signal() + helper_output = Signal() + + input_se = Signal() + beat1 = Signal() + beat2 = Signal() + self.specials += [ + Instance("MMCME2_BASE", + p_CLKIN1_PERIOD=1e9/rtio_clk_freq, + i_CLKIN1=ClockSignal("rtio"), + i_RST=ResetSignal("rtio"), + + # VCO at 1200MHz with 150MHz RTIO frequency + p_CLKFBOUT_MULT_F=8.0, + p_DIVCLK_DIVIDE=1, + + o_CLKFBOUT=helper_fb, i_CLKFBIN=helper_fb, + + # helper PLL ratio: 64/65 (N=64) + p_CLKOUT0_DIVIDE_F=8.125, + o_CLKOUT0=helper_output, + ), + Instance("BUFG", i_I=helper_output, o_O=self.cd_helper.clk), + Instance("IBUFDS", i_I=input_pads.p, i_IB=input_pads.n, o_O=input_se), + Instance("FD", i_C=self.cd_helper.clk, i_D=input_se, o_Q=beat1), + Instance("FD", i_C=self.cd_helper.clk, i_D=ClockSignal("rtio"), o_Q=beat2), + ] + + counting = Signal() + counter = Signal(N.bit_length()) + + beat1_r = Signal() + beat2_r = Signal() + result = Signal.like(counter) + + self.sync.helper += [ + If(counting, + counter.eq(counter + 1) + ).Else( + result.eq(counter) + ), + + beat1_r.eq(beat1), + If(beat1 & ~beat1_r, counting.eq(1), counter.eq(0)), + beat2_r.eq(beat2), + If(beat2 & ~beat2_r, counting.eq(0)) + ] + + bsync = BusSynchronizer(len(result), "helper", "sys") + self.submodules += bsync + self.comb += [ + bsync.i.eq(result), + self.dt.status.eq(bsync.o) + ] diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 2970877c5..d82bbcc8e 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -223,6 +223,9 @@ class Standalone(MiniSoC, AMPSoC, RTMCommon): self.get_native_sdram_if()) self.csr_devices.append("rtio_analyzer") + self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) + self.csr_devices.append("sysref_ddmtd") + class MasterDAC(MiniSoC, AMPSoC, RTMCommon): """ @@ -391,6 +394,9 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) self.csr_devices.append("routing_table") + self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) + self.csr_devices.append("sysref_ddmtd") + def workaround_us_lvds_tristate(platform): # Those shoddy Kintex Ultrascale FPGAs take almost a microsecond to change the direction of a @@ -676,6 +682,9 @@ class Satellite(BaseSoC, RTMCommon): self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None + self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) + self.csr_devices.append("sysref_ddmtd") + rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] platform.add_period_constraint(gth.txoutclk, rtio_clk_period/2) From cb04230f8675f754bb1ea3cdf90b88ef4ddf3645 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 25 Jan 2019 16:58:58 +0800 Subject: [PATCH 1562/2457] sayma: SYSREF setup/hold validation demonstration This also removes the standalone target as the ISERDES used for setup/hold check requires the fine RTIO clock, which in turn requires a DRTIO transceiver due to the Ultrascale TPWS bug. --- artiq/firmware/libboard_artiq/jesd204sync.rs | 15 ++- artiq/gateware/jesd204_tools.py | 76 ++++++++--- artiq/gateware/targets/sayma_amc.py | 132 ++----------------- 3 files changed, 83 insertions(+), 140 deletions(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 062135896..685f61822 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -1,13 +1,24 @@ -use board_misoc::{csr, config}; +use board_misoc::{csr, clock, config}; use hmc830_7043::hmc7043; use ad9154; +fn sysref_sh_error() -> bool { + unsafe { + csr::sysref_sampler::sh_error_reset_write(1); + clock::spin_us(1); + csr::sysref_sampler::sh_error_reset_write(0); + clock::spin_us(10); + csr::sysref_sampler::sh_error_read() != 0 + } +} + pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { for _ in 0..256 { hmc7043::sysref_slip(); let dt = unsafe { csr::sysref_ddmtd::dt_read() }; - info!("dt={}", dt); + let sh_error = sysref_sh_error(); + info!("dt={} sysref_sh_error={}", dt, sh_error); } Ok(()) } diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index b029c86c2..b960366b4 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -22,7 +22,6 @@ class UltrascaleCRG(Module, AutoCSR): def __init__(self, platform, use_rtio_clock=False): self.ibuf_disable = CSRStorage(reset=1) self.jreset = CSRStorage(reset=1) - self.jref = Signal() self.refclk = Signal() self.clock_domains.cd_jesd = ClockDomain() @@ -42,23 +41,6 @@ class UltrascaleCRG(Module, AutoCSR): else: self.specials += Instance("BUFG_GT", i_I=refclk2, o_O=self.cd_jesd.clk) - jref = platform.request("dac_sysref") - jref_se = Signal() - jref_r = Signal() - self.specials += [ - Instance("IBUFDS_IBUFDISABLE", - p_USE_IBUFDISABLE="TRUE", p_SIM_DEVICE="ULTRASCALE", - i_IBUFDISABLE=self.ibuf_disable.storage, - i_I=jref.p, i_IB=jref.n, - o_O=jref_se), - # SYSREF normally meets s/h at the FPGA, except during margin - # scan and before full initialization. - # Be paranoid and use a double-register anyway. - Instance("FD", i_C=ClockSignal("jesd"), i_D=jref_se, o_Q=jref_r, - attr={("IOB", "TRUE")}), - Instance("FD", i_C=ClockSignal("jesd"), i_D=jref_r, o_Q=self.jref) - ] - PhyPads = namedtuple("PhyPads", "txp txn") @@ -90,7 +72,6 @@ class UltrascaleTX(Module, AutoCSR): phys, settings, converter_data_width=64) self.submodules.control = JESD204BCoreTXControl(self.core) self.core.register_jsync(platform.request("dac_sync", dac)) - self.core.register_jref(jesd_crg.jref) # See "Digital femtosecond time difference circuit for CERN's timing system" @@ -157,3 +138,60 @@ class DDMTD(Module, AutoCSR): bsync.i.eq(result), self.dt.status.eq(bsync.o) ] + + +# This assumes: +# * coarse RTIO frequency = 16*SYSREF frequency +# * fine RTIO frequency (rtiox) = 2*RTIO frequency +# * JESD and coarse RTIO clocks are the same +# (only reset may differ). +# +# Look at the 4 LSBs of the coarse RTIO timestamp counter +# to determine SYSREF phase. + +class SysrefSampler(Module, AutoCSR): + def __init__(self, sysref_pads, coarse_ts): + self.sh_error = CSRStatus() + self.sh_error_reset = CSRStorage() + self.sample_result = CSRStatus() + + self.jref = Signal() + + # # # + + sysref_se = Signal() + sysref_oversample = Signal(4) + self.specials += [ + Instance("IBUFDS", i_I=sysref_pads.p, i_IB=sysref_pads.n, o_O=sysref_se), + Instance("ISERDESE3", + p_IS_CLK_INVERTED=0, + p_IS_CLK_B_INVERTED=1, + p_DATA_WIDTH=4, + + i_D=sysref_se, + i_RST=ResetSignal("rtio"), + i_FIFO_RD_EN=0, + i_CLK=ClockSignal("rtiox"), + i_CLK_B=ClockSignal("rtiox"), # locally inverted + i_CLKDIV=ClockSignal("rtio"), + o_Q=sysref_oversample) + ] + + self.comb += self.jref.eq(sysref_oversample[1]) + sh_error = Signal() + sh_error_reset = Signal() + self.sync.rtio += [ + If(~( (sysref_oversample[0] == sysref_oversample[1]) + & (sysref_oversample[1] == sysref_oversample[2])), + sh_error.eq(1) + ), + If(sh_error_reset, sh_error.eq(0)) + ] + self.specials += [ + MultiReg(self.sh_error_reset.storage, sh_error_reset, "rtio"), + MultiReg(sh_error, self.sh_error.status) + ] + + sample = Signal() + self.sync.rtio += If(coarse_ts[:4] == 0, sample.eq(self.jref)) + self.specials += MultiReg(sample, self.sample_result.status) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index d82bbcc8e..96e22a7d5 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -114,119 +114,6 @@ class RTMCommon: self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) -class Standalone(MiniSoC, AMPSoC, RTMCommon): - """ - Local DAC/SAWG channels only. - """ - mem_map = { - "cri_con": 0x10000000, - "rtio": 0x11000000, - "rtio_dma": 0x12000000, - "serwb": 0x13000000, - "mailbox": 0x70000000 - } - mem_map.update(MiniSoC.mem_map) - - def __init__(self, with_sawg, **kwargs): - MiniSoC.__init__(self, - cpu_type="or1k", - sdram_controller_type="minicon", - l2_size=128*1024, - ethmac_nrxslots=4, - ethmac_ntxslots=4, - **kwargs) - AMPSoC.__init__(self) - RTMCommon.__init__(self) - add_identifier(self, suffix=".without-sawg" if not with_sawg else "") - self.config["HMC830_REF"] = "100" - - platform = self.platform - - self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) - self.csr_devices.append("si5324_rst_n") - i2c = self.platform.request("i2c") - self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) - self.csr_devices.append("i2c") - self.config["I2C_BUS_COUNT"] = 1 - self.config["HAS_SI5324"] = None - self.config["SI5324_AS_SYNTHESIZER"] = None - self.config["SI5324_SAYMA_REF"] = None - # ensure pins are properly biased and terminated - si5324_clkout = platform.request("si5324_clkout", 0) - self.specials += Instance( - "IBUFDS_GTE3", i_CEB=0, i_I=si5324_clkout.p, i_IB=si5324_clkout.n, - attr={("DONT_TOUCH", "true")}) - - # RTIO - rtio_channels = [] - for i in range(4): - phy = ttl_simple.Output(platform.request("user_led", i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - # To work around Ultrascale issues (https://www.xilinx.com/support/answers/67885.html), - # we generate the multiplied RTIO clock using the DRTIO GTH transceiver. - # Since there is no DRTIO here and therefoere no multiplied clock, we use ttl_simple. - sma_io = platform.request("sma_io", 0) - self.comb += sma_io.direction.eq(1) - phy = ttl_simple.Output(sma_io.level) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - sma_io = platform.request("sma_io", 1) - self.comb += sma_io.direction.eq(0) - phy = ttl_simple.InOut(sma_io.level) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.submodules.ad9154_crg = jesd204_tools.UltrascaleCRG(platform) - if with_sawg: - cls = AD9154 - else: - cls = AD9154NoSAWG - self.submodules.ad9154_0 = cls(platform, self.crg, self.ad9154_crg, 0) - self.submodules.ad9154_1 = cls(platform, self.crg, self.ad9154_crg, 1) - self.csr_devices.append("ad9154_crg") - self.csr_devices.append("ad9154_0") - self.csr_devices.append("ad9154_1") - self.config["HAS_AD9154"] = None - self.add_csr_group("ad9154", ["ad9154_0", "ad9154_1"]) - self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels) - rtio_channels.extend(rtio.Channel.from_phy(phy) - for sawg in self.ad9154_0.sawgs + - self.ad9154_1.sawgs - for phy in sawg.phys) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) - - self.clock_domains.cd_rtio = ClockDomain() - self.comb += [ - self.cd_rtio.clk.eq(ClockSignal("jesd")), - self.cd_rtio.rst.eq(ResetSignal("jesd")) - ] - self.submodules.rtio_tsc = rtio.TSC("async") - self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) - self.csr_devices.append("rtio_core") - self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) - self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( - rtio.DMA(self.get_native_sdram_if())) - self.register_kernel_cpu_csrdevice("rtio") - self.register_kernel_cpu_csrdevice("rtio_dma") - self.submodules.cri_con = rtio.CRIInterconnectShared( - [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri]) - self.register_kernel_cpu_csrdevice("cri_con") - self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) - self.csr_devices.append("rtio_moninj") - - self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio_tsc, self.rtio_core.cri, - self.get_native_sdram_if()) - self.csr_devices.append("rtio_analyzer") - - self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) - self.csr_devices.append("sysref_ddmtd") - - class MasterDAC(MiniSoC, AMPSoC, RTMCommon): """ DRTIO master with local DAC/SAWG channels. @@ -396,6 +283,11 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) self.csr_devices.append("sysref_ddmtd") + self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( + platform.request("dac_sysref"), self.rtio_tsc.coarse_ts) + self.csr_devices.append("sysref_sampler") + self.ad9154_0.jesd.core.register_jref(self.sysref_sampler.jref) + self.ad9154_1.jesd.core.register_jref(self.sysref_sampler.jref) def workaround_us_lvds_tristate(platform): @@ -684,6 +576,11 @@ class Satellite(BaseSoC, RTMCommon): self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) self.csr_devices.append("sysref_ddmtd") + self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( + platform.request("dac_sysref"), self.rtio_tsc.coarse_ts) + self.csr_devices.append("sysref_sampler") + self.ad9154_0.jesd.core.register_jref(self.sysref_sampler.jref) + self.ad9154_1.jesd.core.register_jref(self.sysref_sampler.jref) rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] @@ -700,9 +597,8 @@ def main(): builder_args(parser) soc_sdram_args(parser) parser.set_defaults(output_dir="artiq_sayma") - parser.add_argument("-V", "--variant", default="standalone", - help="variant: " - "standalone/masterdac/master/satellite " + parser.add_argument("-V", "--variant", default="masterdac", + help="variant: masterdac/master/satellite " "(default: %(default)s)") parser.add_argument("--rtm-csr-csv", default=os.path.join("artiq_sayma", "rtm_gateware", "rtm_csr.csv"), @@ -714,9 +610,7 @@ def main(): args = parser.parse_args() variant = args.variant.lower() - if variant == "standalone": - cls = Standalone - elif variant == "masterdac": + if variant == "masterdac": cls = MasterDAC elif variant == "master": cls = lambda with_sawg, **kwargs: Master(**kwargs) From 359fb1f2075e469ca1a850517f8edf313f8687e6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 25 Jan 2019 23:39:19 +0800 Subject: [PATCH 1563/2457] sayma: fix DDMTD STA --- artiq/gateware/targets/sayma_amc.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 96e22a7d5..7d30699bf 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -283,6 +283,8 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) self.csr_devices.append("sysref_ddmtd") + platform.add_false_path_constraints(self.ad9154_crg.cd_jesd.clk, + self.sysref_ddmtd.cd_helper.clk) self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( platform.request("dac_sysref"), self.rtio_tsc.coarse_ts) self.csr_devices.append("sysref_sampler") @@ -576,6 +578,8 @@ class Satellite(BaseSoC, RTMCommon): self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) self.csr_devices.append("sysref_ddmtd") + platform.add_false_path_constraints(self.ad9154_crg.cd_jesd.clk, + self.sysref_ddmtd.cd_helper.clk) self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( platform.request("dac_sysref"), self.rtio_tsc.coarse_ts) self.csr_devices.append("sysref_sampler") From 9966e789fcb7a1668a07d6979e3f29b76dffca5a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 25 Jan 2019 23:40:48 +0800 Subject: [PATCH 1564/2457] sayma: simplify Ultrascale LVDS T false path Recommended by Xilinx. --- artiq/gateware/targets/sayma_amc.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 7d30699bf..6f5201ac4 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -299,8 +299,7 @@ def workaround_us_lvds_tristate(platform): # See: # https://forums.xilinx.com/t5/Timing-Analysis/Delay-890-ns-in-OBUFTDS-in-Kintex-UltraScale/td-p/868364 platform.add_platform_command( - "set_false_path -through [get_pins -filter {{REF_PIN_NAME == T}} -of [get_cells -filter {{REF_NAME == IOBUFDS}}]]" - " -through [get_pins -filter {{REF_PIN_NAME == O}} -of [get_cells -filter {{REF_NAME == IOBUFDS}}]]") + "set_false_path -through [get_pins -filter {{REF_PIN_NAME == T}} -of [get_cells -filter {{REF_NAME == IOBUFDS}}]]") class Master(MiniSoC, AMPSoC): From d1ef0369486e025938e3e47273769aefabf570f6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 27 Jan 2019 09:49:31 +0800 Subject: [PATCH 1565/2457] kasli_sawgmaster: initialize SAWG phase according to RTIO TSC --- artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py index 9732b8295..755235905 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py @@ -51,6 +51,7 @@ class SinesUrukulSayma(EnvExperiment): delay(1*ms) sawg.amplitude1.set(.4) sawg.frequency0.set_mu(sawg_ftw) + sawg.phase0.set_mu(sawg_ftw*now_mu() >> 17) while self.drtio_is_up(): pass From 8632b553d20e4c3e922ba37f2892e0ee8bf02c30 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 27 Jan 2019 09:50:02 +0800 Subject: [PATCH 1566/2457] ddmtd: use IOB register to sample input --- artiq/gateware/jesd204_tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index b960366b4..8409a409b 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -108,7 +108,7 @@ class DDMTD(Module, AutoCSR): ), Instance("BUFG", i_I=helper_output, o_O=self.cd_helper.clk), Instance("IBUFDS", i_I=input_pads.p, i_IB=input_pads.n, o_O=input_se), - Instance("FD", i_C=self.cd_helper.clk, i_D=input_se, o_Q=beat1), + Instance("FD", i_C=self.cd_helper.clk, i_D=input_se, o_Q=beat1, attr={("IOB", "TRUE")}), Instance("FD", i_C=self.cd_helper.clk, i_D=ClockSignal("rtio"), o_Q=beat2), ] From f73ffe44f957bac803a07ee5fd88d130ae39292f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 27 Jan 2019 09:51:24 +0800 Subject: [PATCH 1567/2457] firmware: implement DDMTD-based SYSREF/RTIO alignment (draft) Mostly works and usually gets the DAC synchronized at 2.4GHz with Urukul across DRTIO. Needs cleanup and optimization/characterization. --- artiq/firmware/libboard_artiq/jesd204sync.rs | 217 ++++++++++++++++++- 1 file changed, 209 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 685f61822..ffd7cd143 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -3,6 +3,67 @@ use board_misoc::{csr, clock, config}; use hmc830_7043::hmc7043; use ad9154; +fn average_2phases(a: i32, b:i32, modulo: i32) -> i32 { + let diff = ((a - b + modulo/2 + modulo) % modulo) - modulo/2; + return (modulo + b + diff/2) % modulo; +} + +fn average_phases(phases: &[i32], modulo: i32) -> i32 { + if phases.len() == 1 { + panic!("input array length must be a power of 2"); + } else if phases.len() == 2 { + average_2phases(phases[0], phases[1], modulo) + } else { + let cut = phases.len()/2; + average_2phases( + average_phases(&phases[..cut], modulo), + average_phases(&phases[cut..], modulo), + modulo) + } +} + +const DDMTD_N_SHIFT: i32 = 6; +const DDMTD_N: i32 = 1 << DDMTD_N_SHIFT; + +const SYSREF_SH_PRECISION_SHIFT: i32 = 5; +const SYSREF_SH_PRECISION: i32 = 1 << SYSREF_SH_PRECISION_SHIFT; +const SYSREF_SH_MOD: i32 = 1 << (DDMTD_N_SHIFT + SYSREF_SH_PRECISION_SHIFT); + + +fn measure_ddmdt_phase_raw() -> i32 { + unsafe { csr::sysref_ddmtd::dt_read() as i32 } +} + +fn measure_ddmdt_phase() -> i32 { + let mut measurements = [0; SYSREF_SH_PRECISION as usize]; + for i in 0..SYSREF_SH_PRECISION { + measurements[i as usize] = measure_ddmdt_phase_raw() << SYSREF_SH_PRECISION_SHIFT; + clock::spin_us(10); + } + average_phases(&measurements, SYSREF_SH_MOD) >> SYSREF_SH_PRECISION_SHIFT +} + +fn test_slip_ddmtd() -> Result<(), &'static str> { + // expected_step = (RTIO clock frequency)*(DDMTD N)/(HMC7043 CLKIN frequency) + let expected_step = 4; + let tolerance = 1; + + info!("testing HMC7043 SYSREF slip against DDMTD..."); + let mut old_phase = measure_ddmdt_phase(); + for _ in 0..1024 { + hmc7043::sysref_slip(); + let phase = measure_ddmdt_phase(); + let step = (DDMTD_N + old_phase - phase) % DDMTD_N; + if (step - expected_step).abs() > tolerance { + error!(" ...got unexpected step: {}", step); + return Err("HMC7043 SYSREF slip produced unexpected DDMTD step"); + } + old_phase = phase; + } + info!(" ...passed"); + Ok(()) +} + fn sysref_sh_error() -> bool { unsafe { csr::sysref_sampler::sh_error_reset_write(1); @@ -13,13 +74,150 @@ fn sysref_sh_error() -> bool { } } -pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { - for _ in 0..256 { +#[derive(Default)] +struct SysrefShLimits { + rising_phases: [i32; SYSREF_SH_PRECISION as usize], + falling_phases: [i32; SYSREF_SH_PRECISION as usize], +} + +fn measure_sysref_sh_limits() -> Result { + let mut ret = SysrefShLimits::default(); + let mut nslips = 0; + let mut rising_n = 0; + let mut falling_n = 0; + + let mut previous = sysref_sh_error(); + while rising_n < SYSREF_SH_PRECISION || falling_n < SYSREF_SH_PRECISION { hmc7043::sysref_slip(); - let dt = unsafe { csr::sysref_ddmtd::dt_read() }; - let sh_error = sysref_sh_error(); - info!("dt={} sysref_sh_error={}", dt, sh_error); + nslips += 1; + if nslips > 1024 { + return Err("too many slips and not enough SYSREF S/H error transitions"); + } + + let current = sysref_sh_error(); + let phase = measure_ddmdt_phase(); + if current && !previous && rising_n < SYSREF_SH_PRECISION { + ret.rising_phases[rising_n as usize] = phase << SYSREF_SH_PRECISION_SHIFT; + rising_n += 1; + } + if !current && previous && falling_n < SYSREF_SH_PRECISION { + ret.falling_phases[falling_n as usize] = phase << SYSREF_SH_PRECISION_SHIFT; + falling_n += 1; + } + previous = current; } + Ok(ret) +} + +fn max_phase_deviation(average: i32, phases: &[i32]) -> i32 { + let mut ret = 0; + for phase in phases.iter() { + let deviation = (phase - average).abs(); + if deviation > ret { + ret = deviation; + } + } + return ret; +} + +fn reach_sysref_ddmtd_target(target: i32, tolerance: i32) -> Result<(), &'static str> { + let mut phase = measure_ddmdt_phase(); + let mut nslips = 0; + while (phase - target).abs() > tolerance { + hmc7043::sysref_slip(); + nslips += 1; + if nslips > 1024 { + return Err("failed to reach SYSREF DDMTD phase target"); + } + phase = measure_ddmdt_phase(); + } + Ok(()) +} + +fn calibrate_sysref_target(rising_average: i32, falling_average: i32) -> Result { + let coarse_target = (falling_average - 16 + DDMTD_N) % DDMTD_N; // HACK + info!("SYSREF calibration coarse target: {}", coarse_target); + reach_sysref_ddmtd_target(coarse_target, 2)?; + let target = measure_ddmdt_phase(); + info!("SYSREF calibrated target: {}", target); + Ok(target) +} + +fn sysref_get_sample() -> Result { + if sysref_sh_error() { + return Err("SYSREF failed S/H timing"); + } + let ret = unsafe { csr::sysref_sampler::sample_result_read() } != 0; + Ok(ret) +} + +fn sysref_slip_rtio_cycle() { + for _ in 0..hmc7043::FPGA_CLK_DIV { + hmc7043::sysref_slip(); + } +} + +pub fn sysref_rtio_align() -> Result<(), &'static str> { + let mut previous_sample = sysref_get_sample()?; + let mut nslips = 0; + loop { + sysref_slip_rtio_cycle(); + let sample = sysref_get_sample()?; + if sample && !previous_sample { + info!("SYSREF aligned with RTIO TSC"); + return Ok(()) + } + previous_sample = sample; + + nslips += 1; + if nslips > hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV { + return Err("failed to find SYSREF transition aligned with RTIO TSC"); + } + } +} + +pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { + test_slip_ddmtd()?; + + let sysref_sh_limits = measure_sysref_sh_limits()?; + let rising_average = average_phases(&sysref_sh_limits.rising_phases, SYSREF_SH_MOD); + let falling_average = average_phases(&sysref_sh_limits.falling_phases, SYSREF_SH_MOD); + let rising_max_deviation = max_phase_deviation(rising_average, &sysref_sh_limits.rising_phases); + let falling_max_deviation = max_phase_deviation(falling_average, &sysref_sh_limits.falling_phases); + + let rising_average = rising_average >> SYSREF_SH_PRECISION_SHIFT; + let falling_average = falling_average >> SYSREF_SH_PRECISION_SHIFT; + let rising_max_deviation = rising_max_deviation >> SYSREF_SH_PRECISION_SHIFT; + let falling_max_deviation = falling_max_deviation >> SYSREF_SH_PRECISION_SHIFT; + + info!("SYSREF S/H average limits (DDMTD phases): {} {}", rising_average, falling_average); + info!("SYSREF S/H maximum limit deviation: {} {}", rising_max_deviation, falling_max_deviation); + if rising_max_deviation > 4 || falling_max_deviation > 4 { + return Err("excessive SYSREF S/H limit deviation"); + } + + let entry = config::read_str("sysref_ddmtd_phase_fpga", |r| r.map(|s| s.parse())); + let target_phase = match entry { + Ok(Ok(phase)) => { + info!("using FPGA SYSREF DDMTD phase target from config: {}", phase); + phase + } + _ => { + let phase = calibrate_sysref_target(rising_average, falling_average)?; + if let Err(e) = config::write_int("sysref_ddmtd_phase_fpga", phase as u32) { + error!("failed to update FPGA SYSREF DDMTD phase target in config: {}", e); + } + phase + } + }; + + reach_sysref_ddmtd_target(target_phase, 1)?; + if sysref_sh_error() { + return Err("SYSREF does not meet S/H timing at DDMTD phase target"); + } + + sysref_rtio_align()?; + Ok(()) } @@ -120,12 +318,15 @@ pub fn sysref_auto_dac_align() -> Result<(), &'static str> { // We assume that DAC SYSREF traces are length-matched so only one phase // value is needed, and we use DAC-0 as calibration reference. - let entry = config::read_str("sysref_phase_dac", |r| r.map(|s| s.parse())); + let entry = config::read_str("sysref_7043_phase_dac", |r| r.map(|s| s.parse())); let phase = match entry { - Ok(Ok(phase)) => phase, + Ok(Ok(phase)) => { + info!("using DAC SYSREF phase from config: {}", phase); + phase + }, _ => { let phase = sysref_cal_dac(0)?; - if let Err(e) = config::write_int("sysref_phase_dac", phase as u32) { + if let Err(e) = config::write_int("sysref_7043_phase_dac", phase as u32) { error!("failed to update DAC SYSREF phase in config: {}", e); } phase From 7e5c062c2c61edddef9601b6dfe4bc85007a265b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 27 Jan 2019 11:49:34 +0800 Subject: [PATCH 1568/2457] firmware: bypass channel divider for HMC7043 DCLK --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 56435807d..c425d71d5 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -159,8 +159,9 @@ pub mod hmc7043 { use board_misoc::{csr, clock}; // Warning: dividers are not synchronized with HMC830 clock input! - // Set DAC_CLK_DIV to 1 for deterministic phase. - pub const DAC_CLK_DIV: u16 = 1; // 2400MHz + // Set DAC_CLK_DIV to 1 or 0 for deterministic phase. + // (0 bypasses the divider and reduces noise) + pub const DAC_CLK_DIV: u16 = 0; // 2400MHz pub const FPGA_CLK_DIV: u16 = 16; // 150MHz pub const SYSREF_DIV: u16 = 256; // 9.375MHz const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // 1.171875MHz (must be <= 4MHz) From fdbf1cc2b2cf63bdfaff871f30c02145cbf50b69 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 27 Jan 2019 14:04:43 +0800 Subject: [PATCH 1569/2457] sayma: rework DAC SYSREF margin validation Previous code did not work when delay range was not enough for two rotations. This removes autocalibration, to be done later. Uses hardcoded value for now. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 4 +- artiq/firmware/libboard_artiq/jesd204sync.rs | 121 ++++++------------- 2 files changed, 39 insertions(+), 86 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index c425d71d5..eb28bafd9 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -158,6 +158,8 @@ mod hmc830 { pub mod hmc7043 { use board_misoc::{csr, clock}; + pub const ANALOG_DELAY_RANGE: u8 = 24; + // Warning: dividers are not synchronized with HMC830 clock input! // Set DAC_CLK_DIV to 1 or 0 for deterministic phase. // (0 bypasses the divider and reduces noise) @@ -390,7 +392,7 @@ pub mod hmc7043 { } } - pub fn sysref_offset_dac(dacno: u8, phase_offset: u8) { + pub fn sysref_delay_dac(dacno: u8, phase_offset: u8) { spi_setup(); if dacno == 0 { write(0x00d5, phase_offset); diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index ffd7cd143..92985d9ce 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -222,119 +222,70 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { } fn sysref_cal_dac(dacno: u8) -> Result { + // TODO info!("calibrating SYSREF phase at DAC-{}...", dacno); - - let mut d = 0; - let dmin; - let dmax; - - hmc7043::sysref_offset_dac(dacno, d); - ad9154::dac_sync(dacno)?; - - loop { - hmc7043::sysref_offset_dac(dacno, d); - let realign_occured = ad9154::dac_sync(dacno)?; - if realign_occured { - dmin = d; - break; - } - - d += 1; - if d > 23 { - return Err("no sync errors found when scanning delay"); - } - } - - d += 5; // get away from jitter - hmc7043::sysref_offset_dac(dacno, d); - ad9154::dac_sync(dacno)?; - - loop { - hmc7043::sysref_offset_dac(dacno, d); - let realign_occured = ad9154::dac_sync(dacno)?; - if realign_occured { - dmax = d; - break; - } - - d += 1; - if d > 23 { - return Err("no sync errors found when scanning delay"); - } - } - - let phase = (dmin+dmax)/2; - info!(" ...done, min={}, max={}, result={}", dmin, dmax, phase); - Ok(phase) + info!(" ...done"); + Ok(7) } -fn sysref_dac_align(dacno: u8, phase: u8) -> Result<(), &'static str> { - let mut margin_minus = None; - let mut margin_plus = None; +fn sysref_dac_align(dacno: u8, delay: u8) -> Result<(), &'static str> { + let tolerance = 5; info!("verifying SYSREF margins at DAC-{}...", dacno); - hmc7043::sysref_offset_dac(dacno, phase); + // avoid spurious rotation at delay=0 + hmc7043::sysref_delay_dac(dacno, 0); ad9154::dac_sync(dacno)?; - for d in 0..24 { - hmc7043::sysref_offset_dac(dacno, phase - d); - let realign_occured = ad9154::dac_sync(dacno)?; - if realign_occured { - margin_minus = Some(d); - break; + + let mut rotation_seen = false; + for scan_delay in 0..hmc7043::ANALOG_DELAY_RANGE { + hmc7043::sysref_delay_dac(dacno, scan_delay); + if ad9154::dac_sync(dacno)? { + rotation_seen = true; + let distance = (scan_delay as i16 - delay as i16).abs(); + if distance < tolerance { + error!(" rotation at delay={} is {} delay steps from target (FAIL)", scan_delay, distance); + return Err("insufficient SYSREF margin at DAC"); + } else { + info!(" rotation at delay={} is {} delay steps from target (PASS)", scan_delay, distance); + } } } - hmc7043::sysref_offset_dac(dacno, phase); - ad9154::dac_sync(dacno)?; - for d in 0..24 { - hmc7043::sysref_offset_dac(dacno, phase + d); - let realign_occured = ad9154::dac_sync(dacno)?; - if realign_occured { - margin_plus = Some(d); - break; - } + if !rotation_seen { + return Err("no rotation seen when scanning DAC SYSREF delay"); } - if margin_minus.is_some() && margin_plus.is_some() { - let margin_minus = margin_minus.unwrap(); - let margin_plus = margin_plus.unwrap(); - info!(" margins: -{} +{}", margin_minus, margin_plus); - if margin_minus < 5 || margin_plus < 5 { - return Err("SYSREF margins at DAC are too small, board needs recalibration"); - } - } else { - return Err("Unable to determine SYSREF margins at DAC"); - } + info!(" ...done"); - // Put SYSREF at the correct phase and sync DAC - hmc7043::sysref_offset_dac(dacno, phase); + // We tested that the value is correct - now use it + hmc7043::sysref_delay_dac(dacno, delay); ad9154::dac_sync(dacno)?; Ok(()) } pub fn sysref_auto_dac_align() -> Result<(), &'static str> { - // We assume that DAC SYSREF traces are length-matched so only one phase + // We assume that DAC SYSREF traces are length-matched so only one delay // value is needed, and we use DAC-0 as calibration reference. - let entry = config::read_str("sysref_7043_phase_dac", |r| r.map(|s| s.parse())); - let phase = match entry { - Ok(Ok(phase)) => { - info!("using DAC SYSREF phase from config: {}", phase); - phase + let entry = config::read_str("sysref_7043_delay_dac", |r| r.map(|s| s.parse())); + let delay = match entry { + Ok(Ok(delay)) => { + info!("using DAC SYSREF delay from config: {}", delay); + delay }, _ => { - let phase = sysref_cal_dac(0)?; - if let Err(e) = config::write_int("sysref_7043_phase_dac", phase as u32) { - error!("failed to update DAC SYSREF phase in config: {}", e); + let delay = sysref_cal_dac(0)?; + if let Err(e) = config::write_int("sysref_7043_delay_dac", delay as u32) { + error!("failed to update DAC SYSREF delay in config: {}", e); } - phase + delay } }; for dacno in 0..csr::AD9154.len() { - sysref_dac_align(dacno as u8, phase)?; + sysref_dac_align(dacno as u8, delay)?; } Ok(()) } From 214394e3b0928dfa6ddae6f85c86bd8f091c210f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 27 Jan 2019 15:28:39 +0800 Subject: [PATCH 1570/2457] sayma: reimplement DAC SYSREF autocalibration --- artiq/firmware/libboard_artiq/jesd204sync.rs | 46 ++++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 92985d9ce..f457b5f24 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -222,10 +222,48 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { } fn sysref_cal_dac(dacno: u8) -> Result { - // TODO - info!("calibrating SYSREF phase at DAC-{}...", dacno); - info!(" ...done"); - Ok(7) + info!("calibrating SYSREF delay at DAC-{}...", dacno); + + // Allocate for more than expected as jitter may create spurious entries. + let mut limits_buf = [0; 8]; + let mut n_limits = 0; + + limits_buf[n_limits] = -1; + n_limits += 1; + + // avoid spurious rotation at delay=0 + hmc7043::sysref_delay_dac(dacno, 0); + ad9154::dac_sync(dacno)?; + + for scan_delay in 0..hmc7043::ANALOG_DELAY_RANGE { + hmc7043::sysref_delay_dac(dacno, scan_delay); + if ad9154::dac_sync(dacno)? { + limits_buf[n_limits] = scan_delay as i16; + n_limits += 1; + if n_limits >= limits_buf.len() - 1 { + break; + } + } + } + + limits_buf[n_limits] = hmc7043::ANALOG_DELAY_RANGE as i16; + n_limits += 1; + + info!(" using limits: {:?}", &limits_buf[..n_limits]); + + let mut delay = 0; + let mut best_margin = 0; + + for i in 0..(n_limits-1) { + let margin = limits_buf[i+1] - limits_buf[i]; + if margin > best_margin { + best_margin = margin; + delay = ((limits_buf[i+1] + limits_buf[i])/2) as u8; + } + } + + info!(" ...done, value={}", delay); + Ok(delay) } fn sysref_dac_align(dacno: u8, delay: u8) -> Result<(), &'static str> { From 82545605779d5dee5ba292744279792c31ed39c0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 27 Jan 2019 16:00:36 +0800 Subject: [PATCH 1571/2457] sayma: properly determine SYSREF coarse calibration target --- artiq/firmware/libboard_artiq/jesd204sync.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index f457b5f24..298f84bb6 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -135,7 +135,12 @@ fn reach_sysref_ddmtd_target(target: i32, tolerance: i32) -> Result<(), &'static } fn calibrate_sysref_target(rising_average: i32, falling_average: i32) -> Result { - let coarse_target = (falling_average - 16 + DDMTD_N) % DDMTD_N; // HACK + let coarse_target = + if rising_average < falling_average { + (rising_average + falling_average)/2 + } else { + ((falling_average - (DDMTD_N - rising_average))/2 + DDMTD_N) % DDMTD_N + }; info!("SYSREF calibration coarse target: {}", coarse_target); reach_sysref_ddmtd_target(coarse_target, 2)?; let target = measure_ddmdt_phase(); From 81b0046f98ae8c9afc5ca108ff99832bd9abe3bc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 27 Jan 2019 20:38:41 +0800 Subject: [PATCH 1572/2457] ddmtd: add deglitchers --- artiq/gateware/jesd204_tools.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index 8409a409b..9c8bb61e9 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -74,6 +74,22 @@ class UltrascaleTX(Module, AutoCSR): self.core.register_jsync(platform.request("dac_sync", dac)) +class DDMTDEdgeDetector(Module): + def __init__(self, i): + self.rising = Signal() + + history = Signal(4) + deglitched = Signal() + self.sync.helper += history.eq(Cat(history[1:], i)) + self.comb += deglitched.eq(i | history[0] | history[1] | history[2] | history[3]) + + deglitched_r = Signal() + self.sync.helper += [ + deglitched_r.eq(deglitched), + self.rising.eq(deglitched & ~deglitched_r) + ] + + # See "Digital femtosecond time difference circuit for CERN's timing system" # by P. Moreira and I. Darwazeh class DDMTD(Module, AutoCSR): @@ -112,13 +128,13 @@ class DDMTD(Module, AutoCSR): Instance("FD", i_C=self.cd_helper.clk, i_D=ClockSignal("rtio"), o_Q=beat2), ] + ed1 = DDMTDEdgeDetector(beat1) + ed2 = DDMTDEdgeDetector(beat2) + self.submodules += ed1, ed2 + counting = Signal() counter = Signal(N.bit_length()) - - beat1_r = Signal() - beat2_r = Signal() result = Signal.like(counter) - self.sync.helper += [ If(counting, counter.eq(counter + 1) @@ -126,10 +142,8 @@ class DDMTD(Module, AutoCSR): result.eq(counter) ), - beat1_r.eq(beat1), - If(beat1 & ~beat1_r, counting.eq(1), counter.eq(0)), - beat2_r.eq(beat2), - If(beat2 & ~beat2_r, counting.eq(0)) + If(ed1.rising, counting.eq(1), counter.eq(0)), + If(ed2.rising, counting.eq(0)) ] bsync = BusSynchronizer(len(result), "helper", "sys") From 74fdd04622a68eeb5025de24fc86cb14458649f5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 27 Jan 2019 20:39:12 +0800 Subject: [PATCH 1573/2457] firmware: test DDMTD stability --- artiq/firmware/libboard_artiq/jesd204sync.rs | 42 ++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 298f84bb6..67bfe3c1d 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -43,6 +43,47 @@ fn measure_ddmdt_phase() -> i32 { average_phases(&measurements, SYSREF_SH_MOD) >> SYSREF_SH_PRECISION_SHIFT } +fn test_ddmtd_stability() -> Result<(), &'static str> { + let tolerance = 4; + + info!("testing DDMTD stability..."); + + let mut max_pkpk = 0; + for _ in 0..32 { + let modulo_fix_ref = measure_ddmdt_phase(); + let modulo_fix = + if modulo_fix_ref < DDMTD_N/4 || (modulo_fix_ref > 3*DDMTD_N/4) { + DDMTD_N/2 + } else { + 0 + }; + + let mut min = DDMTD_N; + let mut max = 0; + for _ in 0..500000 { + let m = (measure_ddmdt_phase_raw() + modulo_fix) % DDMTD_N; + if m < min { + min = m; + } + if m > max { + max = m; + } + } + let pkpk = max - min; + if pkpk > max_pkpk { + max_pkpk = pkpk; + } + if pkpk > tolerance { + error!(" ...excessive peak-peak jitter: {}", pkpk); + return Err("excessive DDMTD peak-peak jitter"); + } + hmc7043::sysref_slip(); + } + + info!(" ...passed, peak-peak jitter: {}", max_pkpk); + Ok(()) +} + fn test_slip_ddmtd() -> Result<(), &'static str> { // expected_step = (RTIO clock frequency)*(DDMTD N)/(HMC7043 CLKIN frequency) let expected_step = 4; @@ -182,6 +223,7 @@ pub fn sysref_rtio_align() -> Result<(), &'static str> { } pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { + test_ddmtd_stability()?; test_slip_ddmtd()?; let sysref_sh_limits = measure_sysref_sh_limits()?; From 3b6f47886efa8cfa52c0633e764f2f1545fdb4ca Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 27 Jan 2019 23:06:11 +0800 Subject: [PATCH 1574/2457] firmware: print more info on DDMTD stability error --- artiq/firmware/libboard_artiq/jesd204sync.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 67bfe3c1d..9193bb149 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -74,7 +74,8 @@ fn test_ddmtd_stability() -> Result<(), &'static str> { max_pkpk = pkpk; } if pkpk > tolerance { - error!(" ...excessive peak-peak jitter: {}", pkpk); + error!(" ...excessive peak-peak jitter: {} (min={} max={} modulo_fix={})", pkpk, + min, max, modulo_fix); return Err("excessive DDMTD peak-peak jitter"); } hmc7043::sysref_slip(); From 443d6d868800384c73796a09158f8a9233503b2c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Jan 2019 09:49:03 +0800 Subject: [PATCH 1575/2457] sayma_amc: pass RTIO clock frequency to SiPhaser --- artiq/gateware/targets/sayma_amc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 6f5201ac4..c30a2eede 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -561,7 +561,8 @@ class Satellite(BaseSoC, RTMCommon): self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), - rx_synchronizer=self.rx_synchronizer) + rx_synchronizer=self.rx_synchronizer, + rtio_clk_freq=rtio_clk_freq) platform.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets {mmcm_ps}]", mmcm_ps=self.siphaser.mmcm_ps_output) platform.add_false_path_constraints( From 47312e55d376c142a5deb046d96a6ae64758a730 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Jan 2019 13:43:28 +0800 Subject: [PATCH 1576/2457] sayma: set RTIO_FREQUENCY in MasterDAC --- artiq/gateware/targets/sayma_amc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index c30a2eede..4f8bc554f 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -153,6 +153,7 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.config["HAS_SI5324"] = None self.config["SI5324_AS_SYNTHESIZER"] = None self.config["SI5324_SAYMA_REF"] = None + self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) # ensure pins are properly biased and terminated si5324_clkout = platform.request("si5324_clkout", 0) self.specials += Instance( From bdd4e52a53b5cad406d38b3d20ad8e3b93a2b2f5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Jan 2019 13:43:52 +0800 Subject: [PATCH 1577/2457] ad9154: support 125MHz RTIO --- artiq/firmware/libboard_artiq/ad9154.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index ff5f08311..a671c32a1 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -70,9 +70,9 @@ fn jesd_jsync(dacno: u8) -> bool { } // ad9154 mode 1 -// linerate 6Gbps -// deviceclock_fpga=150MHz -// deviceclock_dac=600MHz +// linerate 5Gbps or 6Gbps +// deviceclock_fpga 125MHz or 150MHz +// deviceclock_dac 500MHz or 600MHz struct JESDSettings { did: u8, @@ -615,13 +615,18 @@ fn dac_stpl(dacno: u8, m: u8, s: u8) -> Result<(), &'static str> { } fn dac_cfg(dacno: u8) -> Result<(), &'static str> { + #[cfg(rtio_frequency = "125.0")] + const LINERATE: u64 = 5_000_000_000; + #[cfg(rtio_frequency = "150.0")] + const LINERATE: u64 = 5_000_000_000; + spi_setup(dacno); jesd_enable(dacno, false); jesd_prbs(dacno, false); jesd_stpl(dacno, false); clock::spin_us(10000); jesd_enable(dacno, true); - dac_setup(dacno, 6_000_000_000)?; + dac_setup(dacno, LINERATE)?; jesd_enable(dacno, false); clock::spin_us(10000); jesd_enable(dacno, true); From 2b0d63db23ccc618364956834f9797dd7697c96f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Jan 2019 13:44:08 +0800 Subject: [PATCH 1578/2457] hmc830_7043: support 125MHz RTIO --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 27 +++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index eb28bafd9..2348f6091 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -163,10 +163,10 @@ pub mod hmc7043 { // Warning: dividers are not synchronized with HMC830 clock input! // Set DAC_CLK_DIV to 1 or 0 for deterministic phase. // (0 bypasses the divider and reduces noise) - pub const DAC_CLK_DIV: u16 = 0; // 2400MHz - pub const FPGA_CLK_DIV: u16 = 16; // 150MHz - pub const SYSREF_DIV: u16 = 256; // 9.375MHz - const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // 1.171875MHz (must be <= 4MHz) + pub const DAC_CLK_DIV: u16 = 0; + pub const FPGA_CLK_DIV: u16 = 16; + pub const SYSREF_DIV: u16 = 256; + const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // must be <= 4MHz // enabled, divider, output config const OUTPUT_CONFIG: [(bool, u16, u8); 14] = [ @@ -413,17 +413,26 @@ pub mod hmc7043 { } pub fn init() -> Result<(), &'static str> { + // used by MasterDAC - HMC830 is clocked from 100MHz reference + #[cfg(all(hmc830_ref = "100", rtio_frequency = "125.0"))] + const DIV: (u32, u32, u32, u32) = (1, 20, 0, 1); // 100MHz -> 2.0GHz + #[cfg(all(hmc830_ref = "100", rtio_frequency = "150.0"))] + const DIV: (u32, u32, u32, u32) = (1, 24, 0, 1); // 100MHz -> 2.4GHz + + // used by Satellite - HMC830 is clocked by recovered clock + // (or a clock of the same frequency derived from the same oscillator) + #[cfg(all(hmc830_ref = "125", rtio_frequency = "125.0"))] + const DIV: (u32, u32, u32, u32) = (2, 32, 0, 1); // 125MHz -> 2.0GHz + #[cfg(all(hmc830_ref = "150", rtio_frequency = "150.0"))] + const DIV: (u32, u32, u32, u32) = (2, 32, 0, 1); // 150MHz -> 2.4GHz + clock_mux::init(); /* do not use other SPI devices before HMC830 SPI mode selection */ hmc830::select_spi_mode(); hmc830::detect()?; hmc830::init(); - // 2.4GHz out - #[cfg(hmc830_ref = "100")] - hmc830::set_dividers(1, 24, 0, 1); - #[cfg(hmc830_ref = "150")] - hmc830::set_dividers(2, 32, 0, 1); + hmc830::set_dividers(DIV.0, DIV.1, DIV.2, DIV.3); hmc830::check_locked()?; From cfe66549ff40488be5b336f14a2cd170d1bb05f8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Jan 2019 14:14:50 +0800 Subject: [PATCH 1579/2457] jesd204sync: cleanup DDMTD averaging code --- artiq/firmware/libboard_artiq/jesd204sync.rs | 21 +++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 9193bb149..2fc44c283 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -25,22 +25,21 @@ fn average_phases(phases: &[i32], modulo: i32) -> i32 { const DDMTD_N_SHIFT: i32 = 6; const DDMTD_N: i32 = 1 << DDMTD_N_SHIFT; -const SYSREF_SH_PRECISION_SHIFT: i32 = 5; -const SYSREF_SH_PRECISION: i32 = 1 << SYSREF_SH_PRECISION_SHIFT; -const SYSREF_SH_MOD: i32 = 1 << (DDMTD_N_SHIFT + SYSREF_SH_PRECISION_SHIFT); - - fn measure_ddmdt_phase_raw() -> i32 { unsafe { csr::sysref_ddmtd::dt_read() as i32 } } fn measure_ddmdt_phase() -> i32 { - let mut measurements = [0; SYSREF_SH_PRECISION as usize]; - for i in 0..SYSREF_SH_PRECISION { - measurements[i as usize] = measure_ddmdt_phase_raw() << SYSREF_SH_PRECISION_SHIFT; + const AVG_PRECISION_SHIFT: i32 = 5; + const AVG_PRECISION: i32 = 1 << AVG_PRECISION_SHIFT; + const AVG_MOD: i32 = 1 << (DDMTD_N_SHIFT + AVG_PRECISION_SHIFT); + + let mut measurements = [0; AVG_PRECISION as usize]; + for i in 0..AVG_PRECISION { + measurements[i as usize] = measure_ddmdt_phase_raw() << AVG_PRECISION_SHIFT; clock::spin_us(10); } - average_phases(&measurements, SYSREF_SH_MOD) >> SYSREF_SH_PRECISION_SHIFT + average_phases(&measurements, AVG_MOD) >> AVG_PRECISION_SHIFT } fn test_ddmtd_stability() -> Result<(), &'static str> { @@ -116,6 +115,10 @@ fn sysref_sh_error() -> bool { } } +const SYSREF_SH_PRECISION_SHIFT: i32 = 5; +const SYSREF_SH_PRECISION: i32 = 1 << SYSREF_SH_PRECISION_SHIFT; +const SYSREF_SH_MOD: i32 = 1 << (DDMTD_N_SHIFT + SYSREF_SH_PRECISION_SHIFT); + #[derive(Default)] struct SysrefShLimits { rising_phases: [i32; SYSREF_SH_PRECISION as usize], From 3acee87df2ea5b2b64a077e4b46d6dcd9543bf66 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Jan 2019 16:03:40 +0800 Subject: [PATCH 1580/2457] firmware: improve DDMTD resolution using dithering/averaging --- artiq/firmware/libboard_artiq/jesd204sync.rs | 48 ++++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 2fc44c283..5ee13c233 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -22,7 +22,10 @@ fn average_phases(phases: &[i32], modulo: i32) -> i32 { } } -const DDMTD_N_SHIFT: i32 = 6; +const RAW_DDMTD_N_SHIFT: i32 = 6; +const RAW_DDMTD_N: i32 = 1 << RAW_DDMTD_N_SHIFT; +const DDMTD_DITHER_BITS: i32 = 1; +const DDMTD_N_SHIFT: i32 = RAW_DDMTD_N_SHIFT + DDMTD_DITHER_BITS; const DDMTD_N: i32 = 1 << DDMTD_N_SHIFT; fn measure_ddmdt_phase_raw() -> i32 { @@ -30,37 +33,41 @@ fn measure_ddmdt_phase_raw() -> i32 { } fn measure_ddmdt_phase() -> i32 { - const AVG_PRECISION_SHIFT: i32 = 5; + const AVG_PRECISION_SHIFT: i32 = 6; const AVG_PRECISION: i32 = 1 << AVG_PRECISION_SHIFT; - const AVG_MOD: i32 = 1 << (DDMTD_N_SHIFT + AVG_PRECISION_SHIFT); + const AVG_MOD: i32 = 1 << (RAW_DDMTD_N_SHIFT + AVG_PRECISION_SHIFT + DDMTD_DITHER_BITS); let mut measurements = [0; AVG_PRECISION as usize]; for i in 0..AVG_PRECISION { - measurements[i as usize] = measure_ddmdt_phase_raw() << AVG_PRECISION_SHIFT; + measurements[i as usize] = measure_ddmdt_phase_raw() << (AVG_PRECISION_SHIFT + DDMTD_DITHER_BITS); clock::spin_us(10); } average_phases(&measurements, AVG_MOD) >> AVG_PRECISION_SHIFT } -fn test_ddmtd_stability() -> Result<(), &'static str> { - let tolerance = 4; +fn test_ddmtd_stability(raw: bool, tolerance: i32) -> Result<(), &'static str> { + info!("testing DDMTD stability (raw={}, tolerance={})...", raw, tolerance); - info!("testing DDMTD stability..."); + let modulo = if raw { RAW_DDMTD_N } else { DDMTD_N }; + let measurement = if raw { measure_ddmdt_phase_raw } else { measure_ddmdt_phase }; + let ntests = if raw { 250000 } else { 150 }; let mut max_pkpk = 0; for _ in 0..32 { - let modulo_fix_ref = measure_ddmdt_phase(); - let modulo_fix = - if modulo_fix_ref < DDMTD_N/4 || (modulo_fix_ref > 3*DDMTD_N/4) { - DDMTD_N/2 + // If we are near the edges, wraparound can throw off the simple min/max computation. + // In this case, add an offset to get near the center. + let quadrant = measure_ddmdt_phase(); + let center_offset = + if quadrant < DDMTD_N/4 || quadrant > 3*DDMTD_N/4 { + modulo/2 } else { 0 }; - let mut min = DDMTD_N; + let mut min = modulo; let mut max = 0; - for _ in 0..500000 { - let m = (measure_ddmdt_phase_raw() + modulo_fix) % DDMTD_N; + for _ in 0..ntests { + let m = (measurement() + center_offset) % modulo; if m < min { min = m; } @@ -73,8 +80,8 @@ fn test_ddmtd_stability() -> Result<(), &'static str> { max_pkpk = pkpk; } if pkpk > tolerance { - error!(" ...excessive peak-peak jitter: {} (min={} max={} modulo_fix={})", pkpk, - min, max, modulo_fix); + error!(" ...excessive peak-peak jitter: {} (min={} max={} center_offset={})", pkpk, + min, max, center_offset); return Err("excessive DDMTD peak-peak jitter"); } hmc7043::sysref_slip(); @@ -86,7 +93,7 @@ fn test_ddmtd_stability() -> Result<(), &'static str> { fn test_slip_ddmtd() -> Result<(), &'static str> { // expected_step = (RTIO clock frequency)*(DDMTD N)/(HMC7043 CLKIN frequency) - let expected_step = 4; + let expected_step = 8; let tolerance = 1; info!("testing HMC7043 SYSREF slip against DDMTD..."); @@ -187,7 +194,7 @@ fn calibrate_sysref_target(rising_average: i32, falling_average: i32) -> Result< ((falling_average - (DDMTD_N - rising_average))/2 + DDMTD_N) % DDMTD_N }; info!("SYSREF calibration coarse target: {}", coarse_target); - reach_sysref_ddmtd_target(coarse_target, 2)?; + reach_sysref_ddmtd_target(coarse_target, 4)?; let target = measure_ddmdt_phase(); info!("SYSREF calibrated target: {}", target); Ok(target) @@ -227,7 +234,8 @@ pub fn sysref_rtio_align() -> Result<(), &'static str> { } pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { - test_ddmtd_stability()?; + test_ddmtd_stability(true, 4)?; + test_ddmtd_stability(false, 1)?; test_slip_ddmtd()?; let sysref_sh_limits = measure_sysref_sh_limits()?; @@ -262,7 +270,7 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { } }; - reach_sysref_ddmtd_target(target_phase, 1)?; + reach_sysref_ddmtd_target(target_phase, 3)?; if sysref_sh_error() { return Err("SYSREF does not meet S/H timing at DDMTD phase target"); } From ba21dc8498886382a6dc52c1e155ea21d4caf762 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Jan 2019 18:08:20 +0800 Subject: [PATCH 1581/2457] jesd204sync: improve messaging --- artiq/firmware/libboard_artiq/jesd204sync.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 5ee13c233..794c59915 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -187,16 +187,17 @@ fn reach_sysref_ddmtd_target(target: i32, tolerance: i32) -> Result<(), &'static } fn calibrate_sysref_target(rising_average: i32, falling_average: i32) -> Result { + info!("calibrating SYSREF DDMTD target phase..."); let coarse_target = if rising_average < falling_average { (rising_average + falling_average)/2 } else { ((falling_average - (DDMTD_N - rising_average))/2 + DDMTD_N) % DDMTD_N }; - info!("SYSREF calibration coarse target: {}", coarse_target); + info!(" SYSREF calibration coarse target: {}", coarse_target); reach_sysref_ddmtd_target(coarse_target, 4)?; let target = measure_ddmdt_phase(); - info!("SYSREF calibrated target: {}", target); + info!(" ...done, target={}", target); Ok(target) } @@ -215,13 +216,14 @@ fn sysref_slip_rtio_cycle() { } pub fn sysref_rtio_align() -> Result<(), &'static str> { + info!("aligning SYSREF with RTIO TSC..."); let mut previous_sample = sysref_get_sample()?; let mut nslips = 0; loop { sysref_slip_rtio_cycle(); let sample = sysref_get_sample()?; if sample && !previous_sample { - info!("SYSREF aligned with RTIO TSC"); + info!(" ...done"); return Ok(()) } previous_sample = sample; @@ -238,6 +240,7 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { test_ddmtd_stability(false, 1)?; test_slip_ddmtd()?; + info!("determining SYSREF S/H limits..."); let sysref_sh_limits = measure_sysref_sh_limits()?; let rising_average = average_phases(&sysref_sh_limits.rising_phases, SYSREF_SH_MOD); let falling_average = average_phases(&sysref_sh_limits.falling_phases, SYSREF_SH_MOD); @@ -249,11 +252,12 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { let rising_max_deviation = rising_max_deviation >> SYSREF_SH_PRECISION_SHIFT; let falling_max_deviation = falling_max_deviation >> SYSREF_SH_PRECISION_SHIFT; - info!("SYSREF S/H average limits (DDMTD phases): {} {}", rising_average, falling_average); - info!("SYSREF S/H maximum limit deviation: {} {}", rising_max_deviation, falling_max_deviation); + info!(" SYSREF S/H average limits (DDMTD phases): {} {}", rising_average, falling_average); + info!(" SYSREF S/H maximum limit deviation: {} {}", rising_max_deviation, falling_max_deviation); if rising_max_deviation > 4 || falling_max_deviation > 4 { return Err("excessive SYSREF S/H limit deviation"); } + info!(" ...done"); let entry = config::read_str("sysref_ddmtd_phase_fpga", |r| r.map(|s| s.parse())); let target_phase = match entry { @@ -270,10 +274,12 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { } }; + info!("aligning SYSREF with RTIO clock..."); reach_sysref_ddmtd_target(target_phase, 3)?; if sysref_sh_error() { return Err("SYSREF does not meet S/H timing at DDMTD phase target"); } + info!(" ...done"); sysref_rtio_align()?; From 145f08f3fe72c4e11d22f587a7af177c4ef124be Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Jan 2019 18:21:30 +0800 Subject: [PATCH 1582/2457] jesd204sync: update SYSREF S/H limit deviation tolerance Follows the increased DDMTD resolution. --- artiq/firmware/libboard_artiq/jesd204sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 794c59915..49dd55ce8 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -254,7 +254,7 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { info!(" SYSREF S/H average limits (DDMTD phases): {} {}", rising_average, falling_average); info!(" SYSREF S/H maximum limit deviation: {} {}", rising_max_deviation, falling_max_deviation); - if rising_max_deviation > 4 || falling_max_deviation > 4 { + if rising_max_deviation > 8 || falling_max_deviation > 8 { return Err("excessive SYSREF S/H limit deviation"); } info!(" ...done"); From b9e3fab49c672b3b5a03616ee6ca16bf20a41e71 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Jan 2019 18:37:46 +0800 Subject: [PATCH 1583/2457] jesd204sync: improve messaging --- artiq/firmware/libboard_artiq/jesd204sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 49dd55ce8..075656d76 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -327,7 +327,7 @@ fn sysref_cal_dac(dacno: u8) -> Result { } } - info!(" ...done, value={}", delay); + info!(" ...done, delay={}", delay); Ok(delay) } From eebff6d77f4e89c7077a39204353bab460a573e0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Jan 2019 18:38:18 +0800 Subject: [PATCH 1584/2457] jesd204sync: fix max_phase_deviation --- artiq/firmware/libboard_artiq/jesd204sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 075656d76..3959e7ccd 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -164,7 +164,7 @@ fn measure_sysref_sh_limits() -> Result { fn max_phase_deviation(average: i32, phases: &[i32]) -> i32 { let mut ret = 0; for phase in phases.iter() { - let deviation = (phase - average).abs(); + let deviation = (phase - average + DDMTD_N) % DDMTD_N; if deviation > ret { ret = deviation; } From 1a42e23fb4916401032d01bcd0079ed5589bf11a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Jan 2019 18:39:16 +0800 Subject: [PATCH 1585/2457] jesd204sync: print DDMTD SYSREF final alignment delta --- artiq/firmware/libboard_artiq/jesd204sync.rs | 21 +++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 3959e7ccd..79659b736 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -172,18 +172,15 @@ fn max_phase_deviation(average: i32, phases: &[i32]) -> i32 { return ret; } -fn reach_sysref_ddmtd_target(target: i32, tolerance: i32) -> Result<(), &'static str> { - let mut phase = measure_ddmdt_phase(); - let mut nslips = 0; - while (phase - target).abs() > tolerance { - hmc7043::sysref_slip(); - nslips += 1; - if nslips > 1024 { - return Err("failed to reach SYSREF DDMTD phase target"); +fn reach_sysref_ddmtd_target(target: i32, tolerance: i32) -> Result { + for _ in 0..1024 { + let delta = (measure_ddmdt_phase() - target + DDMTD_N) % DDMTD_N; + if delta <= tolerance { + return Ok(delta) } - phase = measure_ddmdt_phase(); + hmc7043::sysref_slip(); } - Ok(()) + Err("failed to reach SYSREF DDMTD phase target") } fn calibrate_sysref_target(rising_average: i32, falling_average: i32) -> Result { @@ -275,11 +272,11 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { }; info!("aligning SYSREF with RTIO clock..."); - reach_sysref_ddmtd_target(target_phase, 3)?; + let delta = reach_sysref_ddmtd_target(target_phase, 3)?; if sysref_sh_error() { return Err("SYSREF does not meet S/H timing at DDMTD phase target"); } - info!(" ...done"); + info!(" ...done, delta={}", delta); sysref_rtio_align()?; From 7a5d28b73d6607320f391b28301103fde32efce1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 28 Jan 2019 19:11:38 +0800 Subject: [PATCH 1586/2457] jesd204sync: test SYSREF period --- artiq/firmware/libboard_artiq/jesd204sync.rs | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 79659b736..5580f801c 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -232,6 +232,27 @@ pub fn sysref_rtio_align() -> Result<(), &'static str> { } } +pub fn test_sysref_period() -> Result<(), &'static str> { + info!("testing SYSREF period..."); + let half_sysref_period = hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV/2; + for _ in 0..32 { + for _ in 0..half_sysref_period { + if !sysref_get_sample()? { + return Err("unexpected SYSREF value during period test"); + } + sysref_slip_rtio_cycle(); + } + for _ in 0..half_sysref_period { + if sysref_get_sample()? { + return Err("unexpected SYSREF value during period test"); + } + sysref_slip_rtio_cycle(); + } + } + info!(" ...done"); + Ok(()) +} + pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { test_ddmtd_stability(true, 4)?; test_ddmtd_stability(false, 1)?; @@ -279,6 +300,7 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { info!(" ...done, delta={}", delta); sysref_rtio_align()?; + test_sysref_period()?; Ok(()) } From 90c9fa446f79a942cec961dcca6e711f7f6eadc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 28 Jan 2019 14:29:53 +0000 Subject: [PATCH 1587/2457] test: add array transfer test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 200 kB/s, more than a factor of 10 slower than the bare string transfer Signed-off-by: Robert Jördens --- artiq/test/coredevice/test_performance.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index 35723f79d..4be415bec 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -22,6 +22,10 @@ class _Transfer(EnvExperiment): def sink(self, data): assert data == self.data + @rpc(flags={"async"}) + def sink_array(self, data): + assert data == [0]*(1 << 15) + @kernel def host_to_device(self): t0 = self.core.get_rtio_counter_mu() @@ -36,6 +40,16 @@ class _Transfer(EnvExperiment): t1 = self.core.get_rtio_counter_mu() return len(self.data)/self.core.mu_to_seconds(t1-t0) + @kernel + def device_to_host_array(self): + #data = [[0]*8 for _ in range(1 << 12)] + data = [0]*(1 << 15) + t0 = self.core.get_rtio_counter_mu() + self.sink_array(data) + t1 = self.core.get_rtio_counter_mu() + return ((len(data)*4)/ + self.core.mu_to_seconds(t1-t0)) + class TransferTest(ExperimentCase): @unittest.skipUnless(artiq_low_latency, @@ -54,6 +68,14 @@ class TransferTest(ExperimentCase): print(device_to_host_rate, "B/s") self.assertGreater(device_to_host_rate, 2.3e6) + @unittest.skipUnless(artiq_low_latency, + "timings are dependent on CPU load and network conditions") + def test_device_to_host_array(self): + exp = self.create(_Transfer) + rate = exp.device_to_host_array() + print(rate, "B/s") + self.assertGreater(rate, .15e6) + class _KernelOverhead(EnvExperiment): def build(self): From 9ae57fd51e4bd2434b6ce06352c875812eeda37f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 29 Jan 2019 15:00:49 +0800 Subject: [PATCH 1588/2457] sayma: pass rtio_clk_freq to DDMTD core --- artiq/gateware/targets/sayma_amc.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 4f8bc554f..734ffa015 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -282,7 +282,8 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) self.csr_devices.append("routing_table") - self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) + self.submodules.sysref_ddmtd = jesd204_tools.DDMTD( + platform.request("adc_sysref"), rtio_clk_freq) self.csr_devices.append("sysref_ddmtd") platform.add_false_path_constraints(self.ad9154_crg.cd_jesd.clk, self.sysref_ddmtd.cd_helper.clk) @@ -577,7 +578,8 @@ class Satellite(BaseSoC, RTMCommon): self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None - self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(platform.request("adc_sysref")) + self.submodules.sysref_ddmtd = jesd204_tools.DDMTD( + platform.request("adc_sysref"), rtio_clk_freq) self.csr_devices.append("sysref_ddmtd") platform.add_false_path_constraints(self.ad9154_crg.cd_jesd.clk, self.sysref_ddmtd.cd_helper.clk) From 2e8decbce37eaee6ae60e0eeedc8cd11e818d70e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 29 Jan 2019 15:02:38 +0800 Subject: [PATCH 1589/2457] kasli_sawgmaster: generate a HMC830 clock with Urukul --- .../repository/sines_urukul_sayma.py | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py index 755235905..af43db1c1 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py @@ -5,7 +5,20 @@ class SinesUrukulSayma(EnvExperiment): def build(self): self.setattr_device("core") self.setattr_device("urukul0_cpld") - self.urukul_chs = [self.get_device("urukul0_ch" + str(i)) for i in range(4)] + + # Urukul clock output syntonized to the RTIO clock. + # Can be used as HMC830 reference on Sayma RTM. + # The clock output on Sayma AMC cannot be used, as it is derived from + # another Si5324 output than the GTH, and the two Si5324 output dividers + # are not synchronized with each other. + # When using this reference, Sayma must be recalibrated every time Urukul + # is rebooted, as Urukul is not synchronized to the Kasli. + self.urukul_hmc_ref = self.get_device("urukul0_ch3") + + # Urukul measurement channels - compare with SAWG outputs. + # When testing sync, do not reboot Urukul, as it is not + # synchronized to the Kasli. + self.urukul_meas = [self.get_device("urukul0_ch" + str(i)) for i in range(3)] self.sawgs = [self.get_device("sawg"+str(i)) for i in range(8)] @kernel @@ -18,17 +31,22 @@ class SinesUrukulSayma(EnvExperiment): @kernel def run(self): f = 9*MHz - dds_ftw = self.urukul_chs[0].frequency_to_ftw(f) + dds_ftw = self.urukul_meas[0].frequency_to_ftw(f) sawg_ftw = self.sawgs[0].frequency0.to_mu(f) if dds_ftw != sawg_ftw: print("DDS and SAWG FTWs do not match:", dds_ftw, sawg_ftw) return - # Note: when testing sync, do not reboot Urukul, as it is not - # synchronized to the FPGA (yet). self.core.reset() self.urukul0_cpld.init() - for urukul_ch in self.urukul_chs: + + delay(1*ms) + self.urukul_hmc_ref.init() + self.urukul_hmc_ref.set_mu(0x40000000, asf=self.urukul_hmc_ref.amplitude_to_asf(0.6)) + self.urukul_hmc_ref.set_att(6.) + self.urukul_hmc_ref.sw.on() + + for urukul_ch in self.urukul_meas: delay(1*ms) urukul_ch.init() urukul_ch.set_mu(dds_ftw, asf=urukul_ch.amplitude_to_asf(0.5)) From ed6aa29897c58bdc6f847bf7caafe59f638a8f5c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 29 Jan 2019 16:47:29 +0800 Subject: [PATCH 1590/2457] jesd204sync: print more information on test_slip_ddmtd error --- artiq/firmware/libboard_artiq/jesd204sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 5580f801c..8067ab438 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -103,7 +103,7 @@ fn test_slip_ddmtd() -> Result<(), &'static str> { let phase = measure_ddmdt_phase(); let step = (DDMTD_N + old_phase - phase) % DDMTD_N; if (step - expected_step).abs() > tolerance { - error!(" ...got unexpected step: {}", step); + error!(" ...got unexpected step: {} ({} -> {})", step, old_phase, phase); return Err("HMC7043 SYSREF slip produced unexpected DDMTD step"); } old_phase = phase; From 9d0d02a561bb28e77b27583d8ed694eee75df7b0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 29 Jan 2019 16:48:43 +0800 Subject: [PATCH 1591/2457] jesd204sync: increase tolerance for coarse->final target in calibrate_sysref_target There is plenty of slack (it only needs to meet timing at the RTIO frequency). --- artiq/firmware/libboard_artiq/jesd204sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 8067ab438..30d5aef3b 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -192,7 +192,7 @@ fn calibrate_sysref_target(rising_average: i32, falling_average: i32) -> Result< ((falling_average - (DDMTD_N - rising_average))/2 + DDMTD_N) % DDMTD_N }; info!(" SYSREF calibration coarse target: {}", coarse_target); - reach_sysref_ddmtd_target(coarse_target, 4)?; + reach_sysref_ddmtd_target(coarse_target, 8)?; let target = measure_ddmdt_phase(); info!(" ...done, target={}", target); Ok(target) From c591009220db046b9d3be821cd3d73743a167074 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 29 Jan 2019 23:30:01 +0800 Subject: [PATCH 1592/2457] sayma: report TSC phase of SYSREF (TSC LSBs on SYSREF rising edge) in SYSREF sampler Better visibility, better diagnostics, allows some changing of SYSREF frequency while keeping the same gateware. --- artiq/firmware/libboard_artiq/jesd204sync.rs | 79 +++++++++++++------- artiq/gateware/jesd204_tools.py | 21 +++--- 2 files changed, 62 insertions(+), 38 deletions(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 30d5aef3b..1804e8cbe 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -198,32 +198,75 @@ fn calibrate_sysref_target(rising_average: i32, falling_average: i32) -> Result< Ok(target) } -fn sysref_get_sample() -> Result { +fn sysref_get_tsc_phase_raw() -> Result { if sysref_sh_error() { return Err("SYSREF failed S/H timing"); } - let ret = unsafe { csr::sysref_sampler::sample_result_read() } != 0; + let ret = unsafe { csr::sysref_sampler::sysref_phase_read() }; Ok(ret) } +// Note: the code below assumes RTIO/SYSREF frequency ratio is a power of 2 + +fn sysref_get_tsc_phase() -> Result { + let mask = (hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV - 1) as u8; + Ok((sysref_get_tsc_phase_raw()? & mask) as i32) +} + +pub fn test_sysref_frequency() -> Result<(), &'static str> { + info!("testing SYSREF frequency against raw TSC phase bit toggles..."); + + let mut all_toggles = 0; + let initial_phase = sysref_get_tsc_phase_raw()?; + for _ in 0..20000 { + clock::spin_us(1); + all_toggles |= sysref_get_tsc_phase_raw()? ^ initial_phase; + } + + let ratio = (hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV) as u8; + let expected_toggles = 0xff ^ (ratio - 1); + if all_toggles == expected_toggles { + info!(" ...done (0x{:02x})", all_toggles); + Ok(()) + } else { + error!(" ...unexpected toggles: got 0x{:02x}, expected 0x{:02x}", + all_toggles, expected_toggles); + Err("unexpected toggles") + } +} + fn sysref_slip_rtio_cycle() { for _ in 0..hmc7043::FPGA_CLK_DIV { hmc7043::sysref_slip(); } } +pub fn test_slip_tsc() -> Result<(), &'static str> { + info!("testing HMC7043 SYSREF slip against TSC phase..."); + let initial_phase = sysref_get_tsc_phase()?; + let modulo = (hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV) as i32; + for i in 0..128 { + sysref_slip_rtio_cycle(); + let expected_phase = (initial_phase + i + 1) % modulo; + let phase = sysref_get_tsc_phase()?; + if phase != expected_phase { + error!(" ...unexpected TSC phase: got {}, expected {} ", phase, expected_phase); + return Err("HMC7043 SYSREF slip produced unexpected TSC phase"); + } + } + info!(" ...done"); + Ok(()) +} + pub fn sysref_rtio_align() -> Result<(), &'static str> { info!("aligning SYSREF with RTIO TSC..."); - let mut previous_sample = sysref_get_sample()?; let mut nslips = 0; loop { sysref_slip_rtio_cycle(); - let sample = sysref_get_sample()?; - if sample && !previous_sample { + if sysref_get_tsc_phase()? == 0 { info!(" ...done"); return Ok(()) } - previous_sample = sample; nslips += 1; if nslips > hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV { @@ -232,27 +275,6 @@ pub fn sysref_rtio_align() -> Result<(), &'static str> { } } -pub fn test_sysref_period() -> Result<(), &'static str> { - info!("testing SYSREF period..."); - let half_sysref_period = hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV/2; - for _ in 0..32 { - for _ in 0..half_sysref_period { - if !sysref_get_sample()? { - return Err("unexpected SYSREF value during period test"); - } - sysref_slip_rtio_cycle(); - } - for _ in 0..half_sysref_period { - if sysref_get_sample()? { - return Err("unexpected SYSREF value during period test"); - } - sysref_slip_rtio_cycle(); - } - } - info!(" ...done"); - Ok(()) -} - pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { test_ddmtd_stability(true, 4)?; test_ddmtd_stability(false, 1)?; @@ -299,8 +321,9 @@ pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { } info!(" ...done, delta={}", delta); + test_sysref_frequency()?; + test_slip_tsc()?; sysref_rtio_align()?; - test_sysref_period()?; Ok(()) } diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index 9c8bb61e9..1806b90ca 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -155,19 +155,15 @@ class DDMTD(Module, AutoCSR): # This assumes: -# * coarse RTIO frequency = 16*SYSREF frequency # * fine RTIO frequency (rtiox) = 2*RTIO frequency # * JESD and coarse RTIO clocks are the same # (only reset may differ). -# -# Look at the 4 LSBs of the coarse RTIO timestamp counter -# to determine SYSREF phase. - class SysrefSampler(Module, AutoCSR): - def __init__(self, sysref_pads, coarse_ts): + def __init__(self, sysref_pads, coarse_ts, sysref_phase_bits=8): self.sh_error = CSRStatus() self.sh_error_reset = CSRStorage() - self.sample_result = CSRStatus() + # Note: only the lower log2(RTIO frequency / SYSREF frequency) bits are stable + self.sysref_phase = CSRStatus(8) self.jref = Signal() @@ -206,6 +202,11 @@ class SysrefSampler(Module, AutoCSR): MultiReg(sh_error, self.sh_error.status) ] - sample = Signal() - self.sync.rtio += If(coarse_ts[:4] == 0, sample.eq(self.jref)) - self.specials += MultiReg(sample, self.sample_result.status) + jref_r = Signal() + sysref_phase_rtio = Signal(sysref_phase_bits) + self.sync.rtio += [ + jref_r.eq(self.jref), + If(self.jref & ~jref_r, sysref_phase_rtio.eq(coarse_ts)) + ] + sysref_phase_rtio.attr.add("no_retiming") + self.specials += MultiReg(sysref_phase_rtio, self.sysref_phase.status) From ec8560911fb19de164710dea3abd01217741a103 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 30 Jan 2019 16:56:38 +0800 Subject: [PATCH 1593/2457] siphaser: bugfixes * Fix integer overflow in degree computation * Add some phase slips after the first transition to get out of the jitter zone and avoid intermittent short windows --- artiq/firmware/libboard_artiq/si5324.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 06b72ef74..0e38fa6c0 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -304,7 +304,7 @@ pub mod siphaser { } } - fn find_edge(target: bool) -> Result { + fn find_edge(target: bool) -> Result { let mut nshifts = 0; let mut previous = has_error(); @@ -323,8 +323,13 @@ pub mod siphaser { } pub fn calibrate_skew() -> Result<()> { + let jitter_margin = 32; let lead = find_edge(false)?; - let width = find_edge(true)?; + for _ in 0..jitter_margin { + phase_shift(1); + } + let width = find_edge(true)? + jitter_margin; + // width is 360 degrees (one full rotation of the phase between s/h limits) minus jitter info!("calibration successful, lead: {}, width: {} ({}deg)", lead, width, width*360/(56*8)); // Apply reverse phase shift for half the width to get into the From fa3b40141d5d53b478323a4c6906d3932c6fae8d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 31 Jan 2019 15:10:11 +0800 Subject: [PATCH 1594/2457] hmc830_7043: document sayma clock muxes --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 2348f6091..2a1654134 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -9,10 +9,10 @@ mod clock_mux { pub fn init() { unsafe { csr::clock_mux::out_write( - 1*CLK_SRC_EXT_SEL | // use ext clk from sma - 1*REF_CLK_SRC_SEL | - 1*DAC_CLK_SRC_SEL | - 0*REF_LO_CLK_SEL); + 1*CLK_SRC_EXT_SEL | // 1= ext clk from sma, 0= RF backplane (IC46) to IC45 + 1*REF_CLK_SRC_SEL | // 1= low-noise clock, 0= Si5324 output (IC45) to HMC830 + 1*DAC_CLK_SRC_SEL | // 1= HMC830 output, 1= clock mezzanine (IC54) to HMC7043 and J58/J59 + 0*REF_LO_CLK_SEL); // 1= clock mezzanine, 0= HMC830 input (IC52) to AFEs and J56/J57 } } } From d3c608aaec80dad003bb3279d288bb4afc9755a0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 31 Jan 2019 15:11:16 +0800 Subject: [PATCH 1595/2457] jesd204sync: reset and check lock status of DDMTD helper PLL in firmware --- artiq/firmware/libboard_artiq/jesd204sync.rs | 15 +++++++++++++++ artiq/gateware/jesd204_tools.py | 7 ++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 1804e8cbe..29f533a5a 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -28,6 +28,20 @@ const DDMTD_DITHER_BITS: i32 = 1; const DDMTD_N_SHIFT: i32 = RAW_DDMTD_N_SHIFT + DDMTD_DITHER_BITS; const DDMTD_N: i32 = 1 << DDMTD_N_SHIFT; +fn init_ddmtd() -> Result<(), &'static str> { + unsafe { + csr::sysref_ddmtd::reset_write(1); + clock::spin_us(1); + csr::sysref_ddmtd::reset_write(0); + clock::spin_us(100); + if csr::sysref_ddmtd::locked_read() != 0 { + Ok(()) + } else { + Err("DDMTD helper PLL failed to lock") + } + } +} + fn measure_ddmdt_phase_raw() -> i32 { unsafe { csr::sysref_ddmtd::dt_read() as i32 } } @@ -276,6 +290,7 @@ pub fn sysref_rtio_align() -> Result<(), &'static str> { } pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { + init_ddmtd()?; test_ddmtd_stability(true, 4)?; test_ddmtd_stability(false, 1)?; test_slip_ddmtd()?; diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index 1806b90ca..a5151acf3 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -95,11 +95,14 @@ class DDMTDEdgeDetector(Module): class DDMTD(Module, AutoCSR): def __init__(self, input_pads, rtio_clk_freq=150e6): N = 64 + self.reset = CSRStorage(reset=1) + self.locked = CSRStatus() self.dt = CSRStatus(N.bit_length()) # # # self.clock_domains.cd_helper = ClockDomain(reset_less=True) + helper_locked = Signal() helper_fb = Signal() helper_output = Signal() @@ -110,7 +113,8 @@ class DDMTD(Module, AutoCSR): Instance("MMCME2_BASE", p_CLKIN1_PERIOD=1e9/rtio_clk_freq, i_CLKIN1=ClockSignal("rtio"), - i_RST=ResetSignal("rtio"), + i_RST=self.reset.storage, + o_LOCKED=helper_locked, # VCO at 1200MHz with 150MHz RTIO frequency p_CLKFBOUT_MULT_F=8.0, @@ -122,6 +126,7 @@ class DDMTD(Module, AutoCSR): p_CLKOUT0_DIVIDE_F=8.125, o_CLKOUT0=helper_output, ), + MultiReg(helper_locked, self.locked.status), Instance("BUFG", i_I=helper_output, o_O=self.cd_helper.clk), Instance("IBUFDS", i_I=input_pads.p, i_IB=input_pads.n, o_O=input_se), Instance("FD", i_C=self.cd_helper.clk, i_D=input_se, o_Q=beat1, attr={("IOB", "TRUE")}), From bdb6678cec10412e835b6fc992eac0e5cc533bbf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 31 Jan 2019 15:13:17 +0800 Subject: [PATCH 1596/2457] nix: bump migen --- nix/pkgs/python3Packages.nix | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nix/pkgs/python3Packages.nix b/nix/pkgs/python3Packages.nix index 4ec3b531b..d35d80aba 100644 --- a/nix/pkgs/python3Packages.nix +++ b/nix/pkgs/python3Packages.nix @@ -50,9 +50,8 @@ rec { src = fetchFromGitHub { owner = "m-labs"; repo = "migen"; - rev = "57c44674c2a6c38bd01804e69db61a9efd287524"; - sha256 = "1xl7bb21ijp6i25hf12gyjwjmv52sbv81fz44fmkiz5b25xlbmaq"; - fetchSubmodules = true; + rev = "afe4405becdbc76539f0195c319367187012b05e"; + sha256 = "1f288a7ll1d1gjmml716wsjf1jyq9y903i2312bxb8pwrg7fwgvz"; }; # TODO: fix migen platform issues and re-enable tests From 8bbd4207d8aac90bf5778f396a086a3805078b4e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 31 Jan 2019 19:35:56 +0800 Subject: [PATCH 1597/2457] si5324: use consistent bitmask --- artiq/firmware/libboard_artiq/si5324.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 0e38fa6c0..f812f085f 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -224,7 +224,7 @@ pub fn setup(settings: &FrequencySettings, input: Input) -> Result<()> { } write(2, (read(2)? & 0x0f) | (s.bwsel << 4))?; write(21, read(21)? & 0xfe)?; // CKSEL_PIN=0 - write(3, (read(3)? & 0x3f) | (cksel_reg << 6) | 0x10)?; // CKSEL_REG, SQ_ICAL=1 + write(3, (read(3)? & 0x2f) | (cksel_reg << 6) | 0x10)?; // CKSEL_REG, SQ_ICAL=1 write(4, (read(4)? & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00 write(6, (read(6)? & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111 write(25, (s.n1_hs << 5 ) as u8)?; From 82106dcd95c9b9dc79602604edeebd2f48c75375 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 31 Jan 2019 19:38:55 +0800 Subject: [PATCH 1598/2457] si5324: add bypass function --- artiq/firmware/libboard_artiq/si5324.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index f812f085f..e722c44d3 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -190,9 +190,7 @@ fn monitor_lock() -> Result<()> { Ok(()) } -pub fn setup(settings: &FrequencySettings, input: Input) -> Result<()> { - let s = map_frequency_settings(settings)?; - +fn init() -> Result<()> { #[cfg(not(si5324_soft_reset))] hard_reset(); @@ -214,11 +212,31 @@ pub fn setup(settings: &FrequencySettings, input: Input) -> Result<()> { #[cfg(si5324_soft_reset)] soft_reset()?; + Ok(()) +} +pub fn bypass(input: Input) -> Result<()> { let cksel_reg = match input { Input::Ckin1 => 0b00, Input::Ckin2 => 0b01, }; + init()?; + write(21, read(21)? & 0xfe)?; // CKSEL_PIN=0 + write(3, (read(3)? & 0x3f) | (cksel_reg << 6))?; // CKSEL_REG + write(4, (read(4)? & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00 + write(6, (read(6)? & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111 + write(0, (read(0)? & 0xfd) | 0x02)?; // BYPASS_REG=1 + Ok(()) +} + +pub fn setup(settings: &FrequencySettings, input: Input) -> Result<()> { + let s = map_frequency_settings(settings)?; + let cksel_reg = match input { + Input::Ckin1 => 0b00, + Input::Ckin2 => 0b01, + }; + + init()?; if settings.crystal_ref { write(0, read(0)? | 0x40)?; // FREE_RUN=1 } From 8119000982eab514ac7c189e071de6569bfd589e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 31 Jan 2019 19:43:54 +0800 Subject: [PATCH 1599/2457] sayma_rtm_drtio: use Si5324 soft reset Needs easy board rework to cut trace at pin 1 of Si5324. The Si5324 contains an internal pull-up on that pin. Allows using Si5324 + HMC7043 chips at the same time. Allows the Si5324 bypass hack for DDMTD experiments on the RTM. --- artiq/gateware/targets/sayma_rtm_drtio.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm_drtio.py b/artiq/gateware/targets/sayma_rtm_drtio.py index 22226aa87..bdff03b2f 100755 --- a/artiq/gateware/targets/sayma_rtm_drtio.py +++ b/artiq/gateware/targets/sayma_rtm_drtio.py @@ -138,13 +138,12 @@ class _SatelliteBase(BaseSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) self.csr_devices.append("siphaser") - self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("hmc7043_reset")) - self.csr_devices.append("si5324_rst_n") i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) self.csr_devices.append("i2c") self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None + self.config["SI5324_SOFT_RESET"] = None rtio_clk_period = 1e9/rtio_clk_freq gtp = self.drtio_transceiver.gtps[0] From ec230d65608f86c79d3fc3e8f6e75ac859fa45fb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 31 Jan 2019 20:39:31 +0800 Subject: [PATCH 1600/2457] sayma: move SYSREF DDMTD to the RTM Put RTM Si5324 into bypass mode before running. Needs rework to cut RTM Si5324 reset trace. Needs rework to fix LVDS termination on RTM R310/R313 and R314/R315. Needs uFL jumper cables between RTM "REF LO DIAG" and "CRD AUX CLKIN" (sic). --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 36 ++++++++++---------- artiq/firmware/libboard_artiq/jesd204sync.rs | 2 +- artiq/gateware/targets/sayma_amc.py | 10 ------ artiq/gateware/targets/sayma_rtm.py | 10 ++++++ 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 2a1654134..c4e2882ce 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -169,21 +169,21 @@ pub mod hmc7043 { const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // must be <= 4MHz // enabled, divider, output config - const OUTPUT_CONFIG: [(bool, u16, u8); 14] = [ - (true, DAC_CLK_DIV, 0x08), // 0: DAC2_CLK - (true, SYSREF_DIV, 0x08), // 1: DAC2_SYSREF - (true, DAC_CLK_DIV, 0x08), // 2: DAC1_CLK - (true, SYSREF_DIV, 0x08), // 3: DAC1_SYSREF - (false, 0, 0x08), // 4: ADC2_CLK - (false, 0, 0x08), // 5: ADC2_SYSREF - (false, 0, 0x08), // 6: GTP_CLK2 - (true, SYSREF_DIV, 0x10), // 7: FPGA_DAC_SYSREF, LVDS - (true, FPGA_CLK_DIV, 0x08), // 8: GTP_CLK1 - (false, 0, 0x10), // 9: AMC_MASTER_AUX_CLK - (false, 0, 0x10), // 10: RTM_MASTER_AUX_CLK - (true, FPGA_CLK_DIV, 0x10), // 11: FPGA_ADC_SYSREF, LVDS, used for DDMTD RTIO/SYSREF alignment - (false, 0, 0x08), // 12: ADC1_CLK - (false, 0, 0x08), // 13: ADC1_SYSREF + const OUTPUT_CONFIG: [(bool, u16, u8, bool); 14] = [ + (true, DAC_CLK_DIV, 0x08, false), // 0: DAC2_CLK + (true, SYSREF_DIV, 0x08, true), // 1: DAC2_SYSREF + (true, DAC_CLK_DIV, 0x08, false), // 2: DAC1_CLK + (true, SYSREF_DIV, 0x08, true), // 3: DAC1_SYSREF + (false, 0, 0x08, false), // 4: ADC2_CLK + (false, 0, 0x08, true), // 5: ADC2_SYSREF + (false, 0, 0x08, false), // 6: GTP_CLK2 + (true, SYSREF_DIV, 0x10, true), // 7: FPGA_DAC_SYSREF, LVDS + (true, FPGA_CLK_DIV, 0x08, false), // 8: GTP_CLK1 + (false, 0, 0x10, true), // 9: AMC_MASTER_AUX_CLK + (true, FPGA_CLK_DIV, 0x10, true), // 10: RTM_MASTER_AUX_CLK, LVDS, used for DDMTD RTIO/SYSREF alignment + (false, 0, 0x10, true), // 11: FPGA_ADC_SYSREF + (false, 0, 0x08, false), // 12: ADC1_CLK + (false, 0, 0x08, true), // 13: ADC1_SYSREF ]; fn spi_setup() { @@ -311,10 +311,10 @@ pub mod hmc7043 { for channel in 0..OUTPUT_CONFIG.len() { let channel_base = 0xc8 + 0x0a*(channel as u16); - let (enabled, divider, outcfg) = OUTPUT_CONFIG[channel]; + let (enabled, divider, outcfg, is_sysref) = OUTPUT_CONFIG[channel]; if enabled { - if channel % 2 == 0 { + if !is_sysref { // DCLK channel: enable high-performance mode write(channel_base, 0xd1); } else { @@ -328,7 +328,7 @@ pub mod hmc7043 { write(channel_base + 0x2, ((divider & 0xf00) >> 8) as u8); // bypass analog phase shift on DCLK channels to reduce noise - if channel % 2 == 0 { + if !is_sysref { if divider != 0 { write(channel_base + 0x7, 0x00); // enable divider } else { diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs index 29f533a5a..3d7924374 100644 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ b/artiq/firmware/libboard_artiq/jesd204sync.rs @@ -64,7 +64,7 @@ fn test_ddmtd_stability(raw: bool, tolerance: i32) -> Result<(), &'static str> { let modulo = if raw { RAW_DDMTD_N } else { DDMTD_N }; let measurement = if raw { measure_ddmdt_phase_raw } else { measure_ddmdt_phase }; - let ntests = if raw { 250000 } else { 150 }; + let ntests = if raw { 15000 } else { 150 }; let mut max_pkpk = 0; for _ in 0..32 { diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 734ffa015..5978d2e89 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -282,11 +282,6 @@ class MasterDAC(MiniSoC, AMPSoC, RTMCommon): self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) self.csr_devices.append("routing_table") - self.submodules.sysref_ddmtd = jesd204_tools.DDMTD( - platform.request("adc_sysref"), rtio_clk_freq) - self.csr_devices.append("sysref_ddmtd") - platform.add_false_path_constraints(self.ad9154_crg.cd_jesd.clk, - self.sysref_ddmtd.cd_helper.clk) self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( platform.request("dac_sysref"), self.rtio_tsc.coarse_ts) self.csr_devices.append("sysref_sampler") @@ -578,11 +573,6 @@ class Satellite(BaseSoC, RTMCommon): self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None - self.submodules.sysref_ddmtd = jesd204_tools.DDMTD( - platform.request("adc_sysref"), rtio_clk_freq) - self.csr_devices.append("sysref_ddmtd") - platform.add_false_path_constraints(self.ad9154_crg.cd_jesd.clk, - self.sysref_ddmtd.cd_helper.clk) self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( platform.request("dac_sysref"), self.rtio_tsc.coarse_ts) self.csr_devices.append("sysref_sampler") diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index e50656ed9..6a2cdd64f 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -16,6 +16,7 @@ from misoc.integration.wb_slaves import WishboneSlaveManager from misoc.integration.cpu_interface import get_csr_csv from artiq.gateware import serwb +from artiq.gateware import jesd204_tools from artiq import __version__ as artiq_version @@ -176,6 +177,15 @@ class SaymaRTM(Module): platform.request("hmc7043_gpo")) csr_devices.append("hmc7043_gpo") + # DDMTD + self.clock_domains.cd_rtio = ClockDomain(reset_less=True) + rtio_clock_pads = platform.request("si5324_clkout_fabric") + self.specials += Instance("IBUFGDS", i_I=rtio_clock_pads.p, i_IB=rtio_clock_pads.n, + o_O=self.cd_rtio.clk) + self.submodules.sysref_ddmtd = jesd204_tools.DDMTD( + platform.request("rtm_master_aux_clk"), 125e6) + csr_devices.append("sysref_ddmtd") + # AMC/RTM serwb serwb_pads = platform.request("amc_rtm_serwb") platform.add_period_constraint(serwb_pads.clk, 8.) From ea431b6982d67e29778ef5ca1ca82d9ef8096385 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 31 Jan 2019 20:43:44 +0800 Subject: [PATCH 1601/2457] sayma_rtm: use 150MHz RTIO freq for DDMTD --- artiq/gateware/targets/sayma_rtm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 6a2cdd64f..a4d61b666 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -183,7 +183,7 @@ class SaymaRTM(Module): self.specials += Instance("IBUFGDS", i_I=rtio_clock_pads.p, i_IB=rtio_clock_pads.n, o_O=self.cd_rtio.clk) self.submodules.sysref_ddmtd = jesd204_tools.DDMTD( - platform.request("rtm_master_aux_clk"), 125e6) + platform.request("rtm_master_aux_clk"), 150e6) csr_devices.append("sysref_ddmtd") # AMC/RTM serwb From 5a7460a38ef4a5e313801eafdc903843be272792 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 1 Feb 2019 22:14:03 +0800 Subject: [PATCH 1602/2457] kasli: add sync delays to device_db_berkeley --- artiq/examples/kasli_basic/device_db_berkeley.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/artiq/examples/kasli_basic/device_db_berkeley.py b/artiq/examples/kasli_basic/device_db_berkeley.py index 3f53550f6..87c70e87a 100644 --- a/artiq/examples/kasli_basic/device_db_berkeley.py +++ b/artiq/examples/kasli_basic/device_db_berkeley.py @@ -48,6 +48,17 @@ device_db.update({ } for i in range(16) }) +sync_delay_seeds = [ + [17, 17, 16, 16], + [16, 15, 17, 20], + [18, 19, 20, 20], +] + +io_update_delays = [ + [3, 3, 3, 3], + [1, 1, 1, 1], + [3, 3, 3, 3], +] for j in range(3): device_db.update({ @@ -116,7 +127,9 @@ for j in range(3): "pll_n": 32, "chip_select": 4 + i, "cpld_device": "urukul{}_cpld".format(j), - "sw_device": "ttl_urukul{}_sw{}".format(j, i) + "sw_device": "ttl_urukul{}_sw{}".format(j, i), + "sync_delay_seed": sync_delay_seeds[j][i], + "io_update_delay": io_update_delays[j][i], } } for i in range(4) }) From 2f7364563c5e0d4f031289cf30b371c68b4cb48e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 4 Feb 2019 19:28:36 +0800 Subject: [PATCH 1603/2457] nix: fix breakage introduced by nixpkgs 6f05dea3 --- nix/artiq-dev.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/artiq-dev.nix b/nix/artiq-dev.nix index eab47ef59..709607f25 100644 --- a/nix/artiq-dev.nix +++ b/nix/artiq-dev.nix @@ -1,4 +1,4 @@ -{runScript ? "", extraProfile ? ""}: +{runScript ? "bash", extraProfile ? ""}: let pkgs = import {}; From d0b6f92b11be9d39692aaec88594ea1e964453e3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 4 Feb 2019 19:31:09 +0800 Subject: [PATCH 1604/2457] nix: bump jesd204b --- nix/pkgs/python3Packages.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix/pkgs/python3Packages.nix b/nix/pkgs/python3Packages.nix index d35d80aba..898bd97a9 100644 --- a/nix/pkgs/python3Packages.nix +++ b/nix/pkgs/python3Packages.nix @@ -91,8 +91,8 @@ rec { src = fetchFromGitHub { owner = "m-labs"; repo = "jesd204b"; - rev = "03d3280690727b12b6522cbd294138e66dd157c9"; - sha256 = "1hpx4y8ynhsmwsq4ry748q6bkh8jvv2hy8b7hifxjmlh174y8rb0"; + rev = "2fd6391c0a9197580d60f7d8a146191dc7337b03"; + sha256 = "1lhw8f0dp42xx4g6d7hyhqhrnd6i5ll4a1wcg265rqz3600i4009"; }; propagatedBuildInputs = with python3Packages; [ migen misoc ]; From b56c7cec1ed348c48fea06db0d7293fe56bc52d7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Feb 2019 11:24:45 +0800 Subject: [PATCH 1605/2457] kasli: use 100MHz RTIO and 800MHz Urukul frequencies on Berkeley target Urukul sync is not reliable at 125/1000 --- artiq/examples/kasli_basic/device_db_berkeley.py | 13 +++++++------ artiq/firmware/runtime/main.rs | 4 ++-- artiq/gateware/targets/kasli.py | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/artiq/examples/kasli_basic/device_db_berkeley.py b/artiq/examples/kasli_basic/device_db_berkeley.py index 87c70e87a..4981ccbcd 100644 --- a/artiq/examples/kasli_basic/device_db_berkeley.py +++ b/artiq/examples/kasli_basic/device_db_berkeley.py @@ -5,7 +5,7 @@ device_db = { "type": "local", "module": "artiq.coredevice.core", "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1e-9} + "arguments": {"host": core_addr, "ref_period": 1.25e-9} }, "core_log": { "type": "controller", @@ -49,9 +49,9 @@ device_db.update({ }) sync_delay_seeds = [ - [17, 17, 16, 16], - [16, 15, 17, 20], - [18, 19, 20, 20], + [15, 15, 15, 16], + [14, 15, 16, 16], + [18, 18, 20, 19], ] io_update_delays = [ @@ -112,7 +112,7 @@ for j in range(3): "spi_device": "spi_urukul{}".format(j), "sync_device": "ttl_urukul{}_sync".format(j), "io_update_device": "ttl_urukul{}_io_update".format(j), - "refclk": 125e6, + "refclk": 100e6, "clk_sel": 2 } } @@ -125,6 +125,7 @@ for j in range(3): "class": "AD9910", "arguments": { "pll_n": 32, + "pll_vco": 4, "chip_select": 4 + i, "cpld_device": "urukul{}_cpld".format(j), "sw_device": "ttl_urukul{}_sw{}".format(j, i), @@ -179,7 +180,7 @@ device_db.update( "arguments": { "spi_device": "spi_urukul3", "io_update_device": "ttl_urukul3_io_update", - "refclk": 125e6, + "refclk": 100e6, "clk_sel": 0 } } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index c905d5df4..cc86c2217 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -176,8 +176,8 @@ fn setup_si5324_as_synthesizer() bwsel : 3, crystal_ref: true }; - // 100MHz output, from crystal (reference for HMC830) - #[cfg(si5324_sayma_ref)] + // 100MHz output, from crystal. Also used as reference for Sayma HMC830. + #[cfg(any(si5324_sayma_ref, all(rtio_frequency = "100.0", not(si5324_ext_ref))))] const SI5324_SETTINGS: board_artiq::si5324::FrequencySettings = board_artiq::si5324::FrequencySettings { n1_hs : 9, diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 16c27c452..1db7af0e1 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -541,7 +541,7 @@ class Berkeley(_StandaloneBase): self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None - self.config["RTIO_FREQUENCY"] = "125.0" + self.config["RTIO_FREQUENCY"] = "100.0" if hw_rev == "v1.0": # EEM clock fan-out from Si5324, not MMCX self.comb += self.platform.request("clk_sel").eq(1) From 0da799fa46c01e22fa5503777c1c166644dd1705 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 6 Feb 2019 23:36:44 +0000 Subject: [PATCH 1606/2457] conda: Require recent aiohttp artiq_influxdb doesn't work with aiohttp 0.17 (anymore), as the ClientSession API changed. I have not looked up precisely which is the first version that works, but 3.x has been out for almost a year and is available on the Anaconda/conda-forge channels. --- conda/artiq-dev/meta.yaml | 2 +- conda/artiq/meta.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 1544cebf6..b7c0b9c90 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -40,7 +40,7 @@ requirements: - quamash - pyqtgraph 0.10.0 - pygit2 - - aiohttp + - aiohttp >=3 - pythonparser >=1.1 - levenshtein diff --git a/conda/artiq/meta.yaml b/conda/artiq/meta.yaml index 548b68f49..31cf6bf4a 100644 --- a/conda/artiq/meta.yaml +++ b/conda/artiq/meta.yaml @@ -42,7 +42,7 @@ requirements: - quamash - pyqtgraph 0.10.0 - pygit2 - - aiohttp + - aiohttp >=3 - levenshtein test: From d6eb2b023a432ed6d7097c70f8416133b054ef86 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 7 Feb 2019 06:07:55 +0000 Subject: [PATCH 1607/2457] compiler: monomorphize casts first, but more carefully. This reverts 425cd7851, which broke the use of casts to define integer width. Instead of it, two steps are taken: * First, literals are monomorphized, leading to predictable result. * Second, casts are monomorphized, in a top-bottom way. I.e. consider the expression `int64(round(x))`. If round() was visited first, the intermediate precision would be 32-bit, which is clearly undesirable. Therefore, contextual rules should take priority over non-contextual ones. Fixes #1252. --- .../compiler/transforms/cast_monomorphizer.py | 19 +++++++++++++++++-- .../compiler/transforms/int_monomorphizer.py | 19 ------------------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/artiq/compiler/transforms/cast_monomorphizer.py b/artiq/compiler/transforms/cast_monomorphizer.py index 8e373ab1e..c0935ff1f 100644 --- a/artiq/compiler/transforms/cast_monomorphizer.py +++ b/artiq/compiler/transforms/cast_monomorphizer.py @@ -11,8 +11,6 @@ class CastMonomorphizer(algorithm.Visitor): self.engine = engine def visit_CallT(self, node): - self.generic_visit(node) - if (types.is_builtin(node.func.type, "int") or types.is_builtin(node.func.type, "int32") or types.is_builtin(node.func.type, "int64")): @@ -30,3 +28,20 @@ class CastMonomorphizer(algorithm.Visitor): node.args[0].type.unify(typ) + if types.is_builtin(node.func.type, "int") or \ + types.is_builtin(node.func.type, "round"): + typ = node.type.find() + if types.is_var(typ["width"]): + typ["width"].unify(types.TValue(32)) + + self.generic_visit(node) + + def visit_CoerceT(self, node): + if isinstance(node.value, asttyped.NumT) and \ + builtins.is_int(node.type) and \ + builtins.is_int(node.value.type) and \ + not types.is_var(node.type["width"]) and \ + types.is_var(node.value.type["width"]): + node.value.type.unify(node.type) + + self.generic_visit(node) diff --git a/artiq/compiler/transforms/int_monomorphizer.py b/artiq/compiler/transforms/int_monomorphizer.py index 5002bb086..adab3b165 100644 --- a/artiq/compiler/transforms/int_monomorphizer.py +++ b/artiq/compiler/transforms/int_monomorphizer.py @@ -26,22 +26,3 @@ class IntMonomorphizer(algorithm.Visitor): return node.type["width"].unify(types.TValue(width)) - - def visit_CallT(self, node): - self.generic_visit(node) - - if types.is_builtin(node.func.type, "int") or \ - types.is_builtin(node.func.type, "round"): - typ = node.type.find() - if types.is_var(typ["width"]): - typ["width"].unify(types.TValue(32)) - - def visit_CoerceT(self, node): - if isinstance(node.value, asttyped.NumT) and \ - builtins.is_int(node.type) and \ - builtins.is_int(node.value.type) and \ - not types.is_var(node.type["width"]) and \ - types.is_var(node.value.type["width"]): - node.value.type.unify(node.type) - - self.generic_visit(node) From 87e85bcc14ed9a227337bde43cada6194a0b7f31 Mon Sep 17 00:00:00 2001 From: hartytp Date: Thu, 31 Jan 2019 14:59:58 +0000 Subject: [PATCH 1608/2457] suservo: fix coefficient data writing Signed-off-by: Thomas Harty --- artiq/gateware/rtio/phy/servo.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) mode change 100644 => 100755 artiq/gateware/rtio/phy/servo.py diff --git a/artiq/gateware/rtio/phy/servo.py b/artiq/gateware/rtio/phy/servo.py old mode 100644 new mode 100755 index 5fb4f57c7..bebbabada --- a/artiq/gateware/rtio/phy/servo.py +++ b/artiq/gateware/rtio/phy/servo.py @@ -81,8 +81,13 @@ class RTServoMem(Module): 1 + # state_sel 1 + # config_sel len(m_state.adr)) + internal_address = Signal(internal_address_width) - self.comb += internal_address.eq(Cat(self.rtlink.o.address, self.rtlink.o.data[w.coeff:])) + self.comb += internal_address.eq(Cat(self.rtlink.o.address, + self.rtlink.o.data[w.coeff:])) + + coeff_data = Signal(w.coeff) + self.comb += coeff_data.eq(self.rtlink.o.data[:w.coeff]) we = internal_address[-1] state_sel = internal_address[-2] @@ -91,7 +96,7 @@ class RTServoMem(Module): self.comb += [ self.rtlink.o.busy.eq(0), m_coeff.adr.eq(internal_address[1:]), - m_coeff.dat_w.eq(Cat(self.rtlink.o.data, self.rtlink.o.data)), + m_coeff.dat_w.eq(Cat(coeff_data, coeff_data)), m_coeff.we[0].eq(self.rtlink.o.stb & ~high_coeff & we & ~state_sel), m_coeff.we[1].eq(self.rtlink.o.stb & high_coeff & From df6c1fca2c3b649ad17ededae5febb14cbd35100 Mon Sep 17 00:00:00 2001 From: hartytp Date: Thu, 7 Feb 2019 15:13:44 +0000 Subject: [PATCH 1609/2457] SUServo: flake8 [NFC] (#1267) Signed-off-by: Thomas Harty --- artiq/coredevice/suservo.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 96fd1e487..956950380 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -258,10 +258,10 @@ class Channel: This method does not advance the timeline. Output RF switch setting takes effect immediately and is independent of any other activity (profile settings, other channels). The RF switch behaves like - :class:`artiq.coredevice.ttl.TTLOut`. RTIO event replacement is supported. IIR updates take place - once the RF switch has been enabled for the configured delay and the - profile setting has been stable. Profile changes take between one and - two servo cycles to reach the DDS. + :class:`artiq.coredevice.ttl.TTLOut`. RTIO event replacement is + supported. IIR updates take place once the RF switch has been enabled + for the configured delay and the profile setting has been stable. + Profile changes take between one and two servo cycles to reach the DDS. :param en_out: RF switch enable :param en_iir: IIR updates enable From fe63c9b366cb8747a7defbf6a85202638830ee91 Mon Sep 17 00:00:00 2001 From: hartytp Date: Thu, 7 Feb 2019 15:29:32 +0000 Subject: [PATCH 1610/2457] SUServo: remove references to non-existent a0 parameter (#1268) Signed-off-by: Thomas Harty --- artiq/coredevice/suservo.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 956950380..7a58812c1 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -319,7 +319,7 @@ class Channel: The recurrence relation is (all data signed and MSB aligned): .. math:: - a_0 y_n = a_1 y_{n - 1} + b_0 (x_n + o)/2 + b_1 (x_{n - 1} + o)/2 + y_n = a_1 y_{n - 1} + b_0 (x_n + o)/2 + b_1 (x_{n - 1} + o)/2 Where: @@ -328,7 +328,6 @@ class Channel: * :math:`x_n` and :math:`x_{n-1}` are the current and previous filter inputs in :math:`[-1, 1[`. * :math:`o` is the offset - * :math:`a_0` is the normalization factor :math:`2^{11}` * :math:`a_1` is the feedback gain * :math:`b_0` and :math:`b_1` are the feedforward gains for the two delays From f6142816b86b5fc7a6ed9d91a82ed54592cff709 Mon Sep 17 00:00:00 2001 From: hartytp Date: Thu, 7 Feb 2019 15:57:43 +0000 Subject: [PATCH 1611/2457] Revert "SUServo: remove references to non-existent a0 parameter" (#1270) This reverts commit f3aab2b89156bbc1b12f847093a87a8933293df2. Signed-off-by: TPH --- artiq/coredevice/suservo.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 7a58812c1..956950380 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -319,7 +319,7 @@ class Channel: The recurrence relation is (all data signed and MSB aligned): .. math:: - y_n = a_1 y_{n - 1} + b_0 (x_n + o)/2 + b_1 (x_{n - 1} + o)/2 + a_0 y_n = a_1 y_{n - 1} + b_0 (x_n + o)/2 + b_1 (x_{n - 1} + o)/2 Where: @@ -328,6 +328,7 @@ class Channel: * :math:`x_n` and :math:`x_{n-1}` are the current and previous filter inputs in :math:`[-1, 1[`. * :math:`o` is the offset + * :math:`a_0` is the normalization factor :math:`2^{11}` * :math:`a_1` is the feedback gain * :math:`b_0` and :math:`b_1` are the feedforward gains for the two delays From 0ebff04ad74d35455c2fb1e8b3d65cabd89f4efa Mon Sep 17 00:00:00 2001 From: hartytp Date: Thu, 7 Feb 2019 15:43:18 +0000 Subject: [PATCH 1612/2457] SUServo: apply bit masks to servo memory writes to prevent overflows Signed-off-by: TPH --- artiq/coredevice/suservo.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 956950380..f1ce004e5 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -130,6 +130,7 @@ class SUServo: :param value: Data to be written. """ addr |= WE + value &= (1 << COEFF_WIDTH) - 1 value |= (addr >> 8) << COEFF_WIDTH addr = addr & 0xff rtio_output((self.channel << 8) | addr, value) From eaa1b44b00ddc9a8037ec60c8db9622112b6d860 Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Sat, 2 Feb 2019 16:34:38 +0000 Subject: [PATCH 1613/2457] ctlmgr: ignore controllers without a "command" field Allow controllers to be specified without a "command" field. The user takes responsibility for ensuring the controller is running: the controller manager does not attempt to ping the controller. This is useful when one has a common controller shared between several masters. --- artiq/devices/ctlmgr.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/devices/ctlmgr.py b/artiq/devices/ctlmgr.py index 52f203545..93306df6d 100644 --- a/artiq/devices/ctlmgr.py +++ b/artiq/devices/ctlmgr.py @@ -180,7 +180,8 @@ class Controllers: def __setitem__(self, k, v): try: if (isinstance(v, dict) and v["type"] == "controller" and - self.host_filter in get_ip_addresses(v["host"])): + self.host_filter in get_ip_addresses(v["host"]) and + "command" in v): v["command"] = v["command"].format(name=k, bind=self.host_filter, port=v["port"]) From ef934ad9580b4061e5f0c5a262aafc9f3c082aa0 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 7 Feb 2019 21:51:08 +0000 Subject: [PATCH 1614/2457] Add test/release notes for command-less controllers See eaa1b44b00ddc9a8037ec60c8db9622112b6d860 for the actual change. --- RELEASE_NOTES.rst | 6 +++++- artiq/test/test_ctlmgr.py | 11 +++++++++++ artiq/tools.py | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 59846a38f..a3beab361 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -13,12 +13,16 @@ ARTIQ-5 :class:`~artiq.coredevice.ad9914.AD9914` phase reference timestamp parameters have been renamed to ``ref_time_mu`` for consistency, as they are in machine units. -* :func:`~artiq.tools.verbosity_args` renamed to :func:`~artiq.tools.add_common_args`. New feature: adds an option to print the ARTIQ version. +* :func:`~artiq.tools.verbosity_args` has been renamed to + :func:`~artiq.tools.add_common_args`, and now adds a ``--version`` flag. * A gateware-level input edge counter has been added, which offers higher throughput and increased flexibility over the usual TTL input PHYs where edge timestamps are not required. See :mod:`artiq.coredevice.edge_counter` for the core device driver and :mod:`artiq.gateware.rtio.phy.edge_counter`/ :meth:`artiq.gateware.eem.DIO.add_std` for the gateware components. +* The controller manager now ignores device database entries without the + ``"command"`` key set to facilitate sharing of devices between multiple + masters. ARTIQ-4 diff --git a/artiq/test/test_ctlmgr.py b/artiq/test/test_ctlmgr.py index 825fad38c..cfadbd4f7 100644 --- a/artiq/test/test_ctlmgr.py +++ b/artiq/test/test_ctlmgr.py @@ -6,6 +6,7 @@ import asyncio from artiq.devices.ctlmgr import Controllers from artiq.protocols.pc_rpc import AsyncioClient +from artiq.tools import expect_no_log_messages logger = logging.getLogger(__name__) @@ -70,3 +71,13 @@ class ControllerCase(unittest.TestCase): await remote.ping() self.loop.run_until_complete(test()) + + def test_no_command_controller(self): + entry = { + "type": "controller", + "host": "::1", + "port": 3253 + } + with expect_no_log_messages(logging.ERROR): + self.controllers["lda_sim"] = entry + self.assertTrue(self.controllers.queue.empty()) diff --git a/artiq/tools.py b/artiq/tools.py index e5517bebe..30941e7a6 100644 --- a/artiq/tools.py +++ b/artiq/tools.py @@ -1,6 +1,7 @@ import asyncio import atexit import collections +import contextlib import importlib.machinery import logging import os @@ -16,6 +17,7 @@ from artiq.protocols import pyon __all__ = ["parse_arguments", "elide", "short_format", "file_import", "get_experiment", "add_common_args", "simple_network_args", + "UnexpectedLogMessageError", "expect_no_log_messages", "multiline_log_config", "init_logger", "bind_address_from_args", "atexit_register_coroutine", "exc_to_warning", "asyncio_wait_or_cancel", "TaskObject", "Condition", @@ -142,6 +144,36 @@ def simple_network_args(parser, default_port): help=h) +class UnexpectedLogMessageError(Exception): + pass + + +class FailingLogHandler(logging.Handler): + def emit(self, record): + raise UnexpectedLogMessageError("Unexpected log message: '{}'".format( + record.getMessage())) + + +@contextlib.contextmanager +def expect_no_log_messages(level, logger=None): + """Raise an UnexpectedLogMessageError if a log message of the given level + (or above) is emitted while the context is active. + + Example: :: + + with expect_no_log_messages(logging.ERROR): + do_stuff_that_should_not_log_errors() + """ + if logger is None: + logger = logging.getLogger() + handler = FailingLogHandler(level) + logger.addHandler(handler) + try: + yield + finally: + logger.removeHandler(handler) + + class MultilineFormatter(logging.Formatter): def __init__(self): logging.Formatter.__init__( From 3e8fe3f29d80d85bc96fb62b4a415ab4337e93de Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Feb 2019 14:54:02 +0800 Subject: [PATCH 1615/2457] suservo: fix permissions --- artiq/gateware/rtio/phy/servo.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 artiq/gateware/rtio/phy/servo.py diff --git a/artiq/gateware/rtio/phy/servo.py b/artiq/gateware/rtio/phy/servo.py old mode 100755 new mode 100644 From 6f1bb5c351446e63e31bdce8a0a7662f88e2d856 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Feb 2019 15:23:31 +0800 Subject: [PATCH 1616/2457] nix: add experimental derivation to build conda package deterministically --- nix/disciplined-conda.nix | 61 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 nix/disciplined-conda.nix diff --git a/nix/disciplined-conda.nix b/nix/disciplined-conda.nix new file mode 100644 index 000000000..df8a2a190 --- /dev/null +++ b/nix/disciplined-conda.nix @@ -0,0 +1,61 @@ +# nix-build -E "with import {}; callPackage ./disciplined-conda.nix {}" + +{ stdenv +, fetchurl +, runCommand +, buildFHSUserEnv +, libselinux +, xorg +}: + +let + condaDeps = [ stdenv.cc xorg.libSM xorg.libICE xorg.libXrender libselinux ]; + # Use the full Anaconda distribution, which already contains conda-build and its many dependencies, + # so we don't have to manually deal with them. + condaInstaller = fetchurl { + url = "https://repo.anaconda.com/archive/Anaconda3-2018.12-Linux-x86_64.sh"; + sha256 = "006fgyz75ihd00qzbr1cny97xf1mwnzibbqyhskghraqgs2x068h"; + }; + condaSrcChmod = runCommand "conda-src-chmod" { } "mkdir $out; cp ${condaInstaller} $out/conda-installer.sh; chmod +x $out/conda-installer.sh"; + condaInstallerEnv = buildFHSUserEnv { + name = "conda-installer-env"; + targetPkgs = pkgs: ([ condaSrcChmod ] ++ condaDeps); + }; + + # Git depends on libiconv + condaIconv = fetchurl { + url = "https://anaconda.org/conda-forge/libiconv/1.15/download/linux-64/libiconv-1.15-h14c3975_1004.tar.bz2"; + sha256 = "167j8jpr6mnyrzwp18dr52xr3xjsf39q452ag247ijlmp092v8ns"; + }; + condaGit = fetchurl { + url = "https://anaconda.org/conda-forge/git/2.20.1/download/linux-64/git-2.20.1-pl526hc122a05_1001.tar.bz2"; + sha256 = "03s01xq2jj7zbx7jfzz6agy40jj7xkq6dwar3lw1z5j2rbmh8h0h"; + }; + condaInstalled = runCommand "conda-installed" { } + '' + ${condaInstallerEnv}/bin/conda-installer-env -c "${condaSrcChmod}/conda-installer.sh -p $out -b" + ${condaInstallerEnv}/bin/conda-installer-env -c "$out/bin/conda install ${condaIconv}" + ${condaInstallerEnv}/bin/conda-installer-env -c "$out/bin/conda install ${condaGit}" + ''; + condaBuilderEnv = buildFHSUserEnv { + name = "conda-builder-env"; + targetPkgs = pkgs: [ condaInstalled ] ++ condaDeps; + }; + +in stdenv.mkDerivation { + name = "conda-artiq"; + src = ../.; + buildInputs = [ condaBuilderEnv ]; + buildCommand = + '' + HOME=`pwd` + # Build requirements make conda-build fail when disconnected from the internet, e.g. in the nix sandbox. + # Just ignore them - python and setuptools are installed anyway. + cat << EOF > clobber.yaml + requirements: + build: + EOF + mkdir $out + ${condaBuilderEnv}/bin/conda-builder-env -c "conda build --clobber-file clobber.yaml --no-anaconda-upload --no-test --output-folder $out $src/conda/artiq" + ''; +} From 744ef03fa13c298c01db021a0127dc20473145b6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Feb 2019 15:50:02 +0800 Subject: [PATCH 1617/2457] conda: remove --install-lib workaround --- conda/artiq/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/artiq/build.sh b/conda/artiq/build.sh index b3b1f7f73..cae6a8e21 100644 --- a/conda/artiq/build.sh +++ b/conda/artiq/build.sh @@ -3,7 +3,7 @@ set -e $PYTHON setup.py install \ - --install-lib=$SP_DIR \ + --prefix=$PREFIX \ --single-version-externally-managed \ --record=record.txt \ --no-compile From 306d9cf5d0f987a3b782550746ac8f3f4fd8b589 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Feb 2019 15:50:24 +0800 Subject: [PATCH 1618/2457] nix: work around lack of PYTHON environment variable in conda build --- nix/disciplined-conda.nix | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nix/disciplined-conda.nix b/nix/disciplined-conda.nix index df8a2a190..dbf731714 100644 --- a/nix/disciplined-conda.nix +++ b/nix/disciplined-conda.nix @@ -54,8 +54,12 @@ in stdenv.mkDerivation { cat << EOF > clobber.yaml requirements: build: + + build: + script_env: + - PYTHON EOF mkdir $out - ${condaBuilderEnv}/bin/conda-builder-env -c "conda build --clobber-file clobber.yaml --no-anaconda-upload --no-test --output-folder $out $src/conda/artiq" + ${condaBuilderEnv}/bin/conda-builder-env -c "PYTHON=python conda build --clobber-file clobber.yaml --no-anaconda-upload --no-test --output-folder $out $src/conda/artiq" ''; } From 1cfd26dc2e5684734752111209aee2b6908202c3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Feb 2019 17:51:51 +0800 Subject: [PATCH 1619/2457] kasli: add UNSW variant --- artiq/examples/kasli_basic/device_db_unsw.py | 195 +++++++++++++++++++ artiq/gateware/targets/kasli.py | 35 +++- 2 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 artiq/examples/kasli_basic/device_db_unsw.py diff --git a/artiq/examples/kasli_basic/device_db_unsw.py b/artiq/examples/kasli_basic/device_db_unsw.py new file mode 100644 index 000000000..a3fce313a --- /dev/null +++ b/artiq/examples/kasli_basic/device_db_unsw.py @@ -0,0 +1,195 @@ +core_addr = "kasli-1.lab.m-labs.hk" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1e-9} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }, + + "i2c_switch0": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe0} + }, + "i2c_switch1": { + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {"address": 0xe2} + }, +} + + +for i in range(8): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut" if i < 4 else "TTLOut", + "arguments": {"channel": i}, + } + + +device_db.update( + spi_urukul0={ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 8} + }, + ttl_urukul0_sync={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLClockGen", + "arguments": {"channel": 9, "acc_width": 4} + }, + ttl_urukul0_io_update={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 10} + }, + ttl_urukul0_sw0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 11} + }, + ttl_urukul0_sw1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 12} + }, + ttl_urukul0_sw2={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 13} + }, + ttl_urukul0_sw3={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 14} + }, + urukul0_cpld={ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": { + "spi_device": "spi_urukul0", + "sync_device": "ttl_urukul0_sync", + "io_update_device": "ttl_urukul0_io_update", + "refclk": 125e6, + "clk_sel": 2 + } + } +) + +for i in range(4): + device_db["urukul0_ch" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": { + "pll_n": 32, + "chip_select": 4 + i, + "cpld_device": "urukul0_cpld", + "sw_device": "ttl_urukul0_sw" + str(i) + } + } + + +device_db["spi_sampler0_adc"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 15} +} +device_db["spi_sampler0_pgia"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 16} +} +device_db["spi_sampler0_cnv"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 17}, +} +device_db["sampler0"] = { + "type": "local", + "module": "artiq.coredevice.sampler", + "class": "Sampler", + "arguments": { + "spi_adc_device": "spi_sampler0_adc", + "spi_pgia_device": "spi_sampler0_pgia", + "cnv_device": "spi_sampler0_cnv" + } +} + + +device_db["spi_zotino0"] = { + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {"channel": 18} +} +device_db["ttl_zotino0_ldac"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 19} +} +device_db["ttl_zotino0_clr"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 20} +} +device_db["zotino0"] = { + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": { + "spi_device": "spi_zotino0", + "ldac_device": "ttl_zotino0_ldac", + "clr_device": "ttl_zotino0_clr" + } +} + + +device_db.update( + led0={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 21} + }, + led1={ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": 22} + }, +) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 1db7af0e1..a5ec2c880 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -572,6 +572,39 @@ class Berkeley(_StandaloneBase): self.add_rtio(self.rtio_channels) +class UNSW(_StandaloneBase): + def __init__(self, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = "v1.1" + _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + # self.config["SI5324_EXT_REF"] = None + self.config["RTIO_FREQUENCY"] = "125.0" + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) + + self.rtio_channels = [] + eem.DIO.add_std(self, 0, + ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) + eem.Urukul.add_std(self, 1, 2, ttl_serdes_7series.Output_8X, + ttl_simple.ClockGen) + eem.Sampler.add_std(self, 3, 4, ttl_serdes_7series.Output_8X) + eem.Zotino.add_std(self, 5, ttl_serdes_7series.Output_8X) + + for i in (1, 2): + sfp_ctl = self.platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + self.add_rtio(self.rtio_channels) + + class PTB(_StandaloneBase): """PTB Kasli variant @@ -1286,7 +1319,7 @@ class HUSTSatellite(_SatelliteBase): VARIANTS = {cls.__name__.lower(): cls for cls in [ Opticlock, SUServo, PTB, PTB2, HUB, LUH, - SYSU, MITLL, MITLL2, USTC, Tsinghua, Tsinghua2, WIPM, NUDT, Berkeley, + SYSU, MITLL, MITLL2, USTC, Tsinghua, Tsinghua2, WIPM, NUDT, Berkeley, UNSW, VLBAIMaster, VLBAISatellite, HUSTMaster, HUSTSatellite, Tester, Master, Satellite]} From 7994c294af58fdb7c49445a1fb09f5f0a87db44f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Feb 2019 23:14:32 +0800 Subject: [PATCH 1620/2457] nix: set up hydra to provide conda package --- nix/{disciplined-conda.nix => conda-build.nix} | 5 ++++- nix/release.nix | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) rename nix/{disciplined-conda.nix => conda-build.nix} (92%) create mode 100644 nix/release.nix diff --git a/nix/disciplined-conda.nix b/nix/conda-build.nix similarity index 92% rename from nix/disciplined-conda.nix rename to nix/conda-build.nix index dbf731714..c333b9e04 100644 --- a/nix/disciplined-conda.nix +++ b/nix/conda-build.nix @@ -1,4 +1,4 @@ -# nix-build -E "with import {}; callPackage ./disciplined-conda.nix {}" +# nix-build -E "with import {}; callPackage ./conda-build.nix {}" { stdenv , fetchurl @@ -61,5 +61,8 @@ in stdenv.mkDerivation { EOF mkdir $out ${condaBuilderEnv}/bin/conda-builder-env -c "PYTHON=python conda build --clobber-file clobber.yaml --no-anaconda-upload --no-test --output-folder $out $src/conda/artiq" + + mkdir -p $out/nix-support + echo file conda $out/noarch/*.tar.bz2 >> $out/nix-support/hydra-build-products ''; } diff --git a/nix/release.nix b/nix/release.nix new file mode 100644 index 000000000..7c65a6454 --- /dev/null +++ b/nix/release.nix @@ -0,0 +1,9 @@ +{ pkgs ? import {}}: +with pkgs; +let + artiqPkgs = import ./default.nix {}; + jobs = rec { + conda-artiq = callPackage ./conda-build.nix {}; + } // artiqPkgs; +in + jobs From 2de1eaa5213a982960181dbe7826986143ea5c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 6 Feb 2019 19:08:27 +0100 Subject: [PATCH 1621/2457] dashboard: reconnect to core moninj MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * handle disconnects like core device address changes and do a disconnect/connect iteration * after connection failure wait 10 seconds and try again * this addresses the slight regression from release-2 to release-3 where the moninj protocol was made stateful (#838 and #1125) * it would be much better to fix smoltcp/runtime to no loose the connection under pressure (#1125) * the crashes reported in #838 look more like a race condition * master disconnects still require dashboard restarts Signed-off-by: Robert Jördens --- artiq/dashboard/moninj.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py index 8502667f3..5de911826 100644 --- a/artiq/dashboard/moninj.py +++ b/artiq/dashboard/moninj.py @@ -243,7 +243,7 @@ def setup_from_ddb(ddb): class _DeviceManager: def __init__(self): self.core_addr = None - self.new_core_addr = asyncio.Event() + self.reconnect_core = asyncio.Event() self.core_connection = None self.core_connector_task = asyncio.ensure_future(self.core_connector()) @@ -268,7 +268,7 @@ class _DeviceManager: if core_addr != self.core_addr: self.core_addr = core_addr - self.new_core_addr.set() + self.reconnect_core.set() self.dds_sysclk = dds_sysclk @@ -383,19 +383,25 @@ class _DeviceManager: widget.cur_override_level = bool(value) widget.refresh_display() + def disconnect_cb(self): + logger.error("lost connection to core device moninj") + self.reconnect_core.set() + async def core_connector(self): while True: - await self.new_core_addr.wait() - self.new_core_addr.clear() + await self.reconnect_core.wait() + self.reconnect_core.clear() if self.core_connection is not None: await self.core_connection.close() self.core_connection = None new_core_connection = CommMonInj(self.monitor_cb, self.injection_status_cb, - lambda: logger.error("lost connection to core device moninj")) + self.disconnect_cb) try: await new_core_connection.connect(self.core_addr, 1383) except: logger.error("failed to connect to core device moninj", exc_info=True) + await asyncio.sleep(10.) + self.reconnect_core.set() else: self.core_connection = new_core_connection for ttl_channel in self.ttl_widgets.keys(): From f0f50bf1dcd569c8b290e8d052dde828d1452553 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 9 Feb 2019 10:24:22 +0800 Subject: [PATCH 1622/2457] nix: cleanup --- nix/artiq-dev.nix | 6 ++---- nix/conda-build.nix | 10 ++-------- nix/release.nix | 5 ++--- nix/shell-dev.nix | 4 +++- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/nix/artiq-dev.nix b/nix/artiq-dev.nix index 709607f25..479352d2c 100644 --- a/nix/artiq-dev.nix +++ b/nix/artiq-dev.nix @@ -1,7 +1,6 @@ -{runScript ? "bash", extraProfile ? ""}: +{ pkgs ? import {}}: let - pkgs = import {}; artiqpkgs = import ./default.nix { inherit pkgs; }; in pkgs.buildFHSUserEnv { @@ -30,8 +29,7 @@ in openocd ]) ); - runScript = runScript; profile = '' export TARGET_AR=${artiqpkgs.binutils-or1k}/bin/or1k-linux-ar - '' + extraProfile; + ''; } diff --git a/nix/conda-build.nix b/nix/conda-build.nix index c333b9e04..6780ff3c7 100644 --- a/nix/conda-build.nix +++ b/nix/conda-build.nix @@ -1,12 +1,6 @@ -# nix-build -E "with import {}; callPackage ./conda-build.nix {}" +{ pkgs ? import {}}: -{ stdenv -, fetchurl -, runCommand -, buildFHSUserEnv -, libselinux -, xorg -}: +with pkgs; let condaDeps = [ stdenv.cc xorg.libSM xorg.libICE xorg.libXrender libselinux ]; diff --git a/nix/release.nix b/nix/release.nix index 7c65a6454..e67ba467b 100644 --- a/nix/release.nix +++ b/nix/release.nix @@ -1,9 +1,8 @@ { pkgs ? import {}}: -with pkgs; let - artiqPkgs = import ./default.nix {}; + artiqPkgs = import ./default.nix { inherit pkgs; }; jobs = rec { - conda-artiq = callPackage ./conda-build.nix {}; + conda-artiq = import ./conda-build.nix { inherit pkgs; }; } // artiqPkgs; in jobs diff --git a/nix/shell-dev.nix b/nix/shell-dev.nix index ee2e8a764..d7ff9a076 100644 --- a/nix/shell-dev.nix +++ b/nix/shell-dev.nix @@ -1,4 +1,6 @@ +{ pkgs ? import {}}: + let - artiq-dev = import ./artiq-dev.nix {}; + artiq-dev = import ./artiq-dev.nix { inherit pkgs; }; in artiq-dev.env From 07ac42505bf1fed62d4fe76a157f4c8aefaf1d70 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 9 Feb 2019 10:36:20 +0800 Subject: [PATCH 1623/2457] nix: add firmware derivation (WIP) --- nix/artiq-board.nix | 56 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 nix/artiq-board.nix diff --git a/nix/artiq-board.nix b/nix/artiq-board.nix new file mode 100644 index 000000000..d68537503 --- /dev/null +++ b/nix/artiq-board.nix @@ -0,0 +1,56 @@ +let + pkgs = import {}; + fetchcargo = import { + inherit (pkgs) stdenv cacert git rust cargo-vendor; + }; + myVendoredSrcFetchCargo = fetchcargo rec { + name = "myVendoredSrcFetchCargo"; + sourceRoot = null; + srcs = null; + src = ../artiq/firmware; + cargoUpdateHook = ""; + patches = []; + sha256 = "1xzjn9i4rkd9124v2gbdplsgsvp1hlx7czdgc58n316vsnrkbr86"; + }; + + myVendoredSrc = pkgs.stdenv.mkDerivation { + name = "myVendoredSrc"; + src = myVendoredSrcFetchCargo; + phases = [ "unpackPhase" "installPhase" ]; + installPhase = '' + mkdir -p $out/.cargo/registry + cat > $out/.cargo/config << EOF + [source.crates-io] + registry = "https://github.com/rust-lang/crates.io-index" + replace-with = "vendored-sources" + + [source."https://github.com/m-labs/libfringe"] + git = "https://github.com/m-labs/libfringe" + rev = "b8a6d8f" + replace-with = "vendored-sources" + + [source.vendored-sources] + directory = "$out/.cargo/registry" + EOF + cp -R * $out/.cargo/registry + ''; + }; + + buildenv = import ./artiq-dev.nix { inherit pkgs; }; + +in pkgs.stdenv.mkDerivation { + name = "artiq-board"; + src = null; + phases = [ "buildPhase" "installPhase" ]; + buildPhase = + '' + ${buildenv}/bin/artiq-dev -c "HOME=${myVendoredSrc} python -m artiq.gateware.targets.kasli -V satellite --no-compile-gateware" + ''; + installPhase = + '' + mkdir $out + #cp artiq_kasli/satellite/gateware/top.bit $out + cp artiq_kasli/satellite/software/bootloader/bootloader.bin $out + cp artiq_kasli/satellite/software/satman/satman.{elf,fbi} $out + ''; +} From 7584639acd2e9de886a66f730e3bef98c18f743d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 9 Feb 2019 11:06:44 +0800 Subject: [PATCH 1624/2457] nix/artiq-board: cleanup --- nix/artiq-board.nix | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/nix/artiq-board.nix b/nix/artiq-board.nix index d68537503..caed8b693 100644 --- a/nix/artiq-board.nix +++ b/nix/artiq-board.nix @@ -1,25 +1,24 @@ -let - pkgs = import {}; - fetchcargo = import { - inherit (pkgs) stdenv cacert git rust cargo-vendor; +{ pkgs ? import {}}: + +let + artiqPkgs = import ./default.nix { inherit pkgs; }; + fetchcargo = import ./fetchcargo.nix { + inherit (pkgs) stdenv cacert git cargo cargo-vendor; }; - myVendoredSrcFetchCargo = fetchcargo rec { - name = "myVendoredSrcFetchCargo"; - sourceRoot = null; - srcs = null; + cargoDeps = fetchcargo rec { + name = "artiq-firmware-cargo-deps"; src = ../artiq/firmware; - cargoUpdateHook = ""; - patches = []; sha256 = "1xzjn9i4rkd9124v2gbdplsgsvp1hlx7czdgc58n316vsnrkbr86"; }; - myVendoredSrc = pkgs.stdenv.mkDerivation { - name = "myVendoredSrc"; - src = myVendoredSrcFetchCargo; + cargoVendored = pkgs.stdenv.mkDerivation { + name = "artiq-firmware-cargo-vendored"; + src = cargoDeps; phases = [ "unpackPhase" "installPhase" ]; - installPhase = '' - mkdir -p $out/.cargo/registry - cat > $out/.cargo/config << EOF + installPhase = + '' + mkdir -p $out/registry + cat > $out/config <<-EOF [source.crates-io] registry = "https://github.com/rust-lang/crates.io-index" replace-with = "vendored-sources" @@ -30,10 +29,10 @@ let replace-with = "vendored-sources" [source.vendored-sources] - directory = "$out/.cargo/registry" + directory = "$out/registry" EOF - cp -R * $out/.cargo/registry - ''; + cp -R * $out/registry + ''; }; buildenv = import ./artiq-dev.nix { inherit pkgs; }; @@ -44,7 +43,7 @@ in pkgs.stdenv.mkDerivation { phases = [ "buildPhase" "installPhase" ]; buildPhase = '' - ${buildenv}/bin/artiq-dev -c "HOME=${myVendoredSrc} python -m artiq.gateware.targets.kasli -V satellite --no-compile-gateware" + ${buildenv}/bin/artiq-dev -c "CARGO_HOME=${cargoVendored} python -m artiq.gateware.targets.kasli -V satellite --no-compile-gateware" ''; installPhase = '' From e4249270497e89efeb2b1dc78e414e0029548622 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 9 Feb 2019 14:19:34 +0800 Subject: [PATCH 1625/2457] nix: use nixpkgs cargo This simplifies the code and avoids multiplication of cargo versions. This installs cargo 1.27, but it is compatible enough with artiq rustc 1.28 not to cause any problems for our purposes. --- nix/artiq-dev.nix | 2 +- nix/default.nix | 2 +- nix/pkgs/rust/cargo.nix | 70 --------------------------------------- nix/pkgs/rust/default.nix | 9 ----- 4 files changed, 2 insertions(+), 81 deletions(-) delete mode 100644 nix/pkgs/rust/cargo.nix diff --git a/nix/artiq-dev.nix b/nix/artiq-dev.nix index 479352d2c..33e888d81 100644 --- a/nix/artiq-dev.nix +++ b/nix/artiq-dev.nix @@ -20,10 +20,10 @@ in xorg.libXi (python3.withPackages(ps: with ps; [ jinja2 numpy artiqpkgs.migen artiqpkgs.microscope artiqpkgs.misoc artiqpkgs.jesd204b artiqpkgs.artiq ])) git + cargo ] ++ (with artiqpkgs; [ rustc - cargo binutils-or1k llvm-or1k openocd diff --git a/nix/default.nix b/nix/default.nix index 90063b48d..5b27187aa 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -8,7 +8,7 @@ let }); llvm-src = callPackage ./fetch-llvm-clang.nix {}; in rec { - inherit (rust) cargo rustc; + inherit (rust) rustc; inherit (callPackage ./pkgs/python3Packages.nix {}) migen microscope misoc jesd204b; binutils-or1k = callPackage ./pkgs/binutils-or1k.nix {}; llvm-or1k = callPackage ./pkgs/llvm-or1k.nix { inherit llvm-src; }; diff --git a/nix/pkgs/rust/cargo.nix b/nix/pkgs/rust/cargo.nix deleted file mode 100644 index cdeca0fa8..000000000 --- a/nix/pkgs/rust/cargo.nix +++ /dev/null @@ -1,70 +0,0 @@ -{ stdenv, fetchurl, file, curl, pkgconfig, python, openssl, cmake, zlib -, makeWrapper, libiconv, cacert, rustPlatform, rustc, libgit2, darwin -, version -, patches ? [] -, src }: - -let - inherit (darwin.apple_sdk.frameworks) CoreFoundation; - src_rustc = fetchurl { - url = "https://static.rust-lang.org/dist/rustc-1.28.0-src.tar.gz"; - sha256 = "11k4rn77bca2rikykkk9fmprrgjswd4x4kaq7fia08vgkir82nhx"; - }; -in - -rustPlatform.buildRustPackage rec { - name = "cargo-${version}"; - inherit version src patches; - - # the rust source tarball already has all the dependencies vendored, no need to fetch them again - cargoVendorDir = "src/vendor"; - preBuild = "cd src; pushd tools/cargo"; - postBuild = "popd"; - - passthru.rustc = rustc; - - # changes hash of vendor directory otherwise - dontUpdateAutotoolsGnuConfigScripts = true; - - nativeBuildInputs = [ pkgconfig ]; - buildInputs = [ cacert file curl python openssl cmake zlib makeWrapper libgit2 ] - ++ stdenv.lib.optionals stdenv.isDarwin [ CoreFoundation libiconv ]; - - LIBGIT2_SYS_USE_PKG_CONFIG=1; - - # fixes: the cargo feature `edition` requires a nightly version of Cargo, but this is the `stable` channel - RUSTC_BOOTSTRAP=1; - - preConfigure = '' - tar xf ${src_rustc} - mv rustc-1.28.0-src/src/vendor/ src/vendor - ''; - - postInstall = '' - # NOTE: We override the `http.cainfo` option usually specified in - # `.cargo/config`. This is an issue when users want to specify - # their own certificate chain as environment variables take - # precedence - wrapProgram "$out/bin/cargo" \ - --suffix PATH : "${rustc}/bin" \ - --set CARGO_HTTP_CAINFO "${cacert}/etc/ssl/certs/ca-bundle.crt" \ - --set SSL_CERT_FILE "${cacert}/etc/ssl/certs/ca-bundle.crt" - ''; - - checkPhase = '' - # Disable cross compilation tests - export CFG_DISABLE_CROSS_TESTS=1 - cargo test - ''; - - # Disable check phase as there are failures (4 tests fail) - doCheck = false; - - meta = with stdenv.lib; { - homepage = https://crates.io; - description = "Downloads your Rust project's dependencies and builds your project"; - #maintainers = with maintainers; [ sb0 ]; - license = [ licenses.mit licenses.asl20 ]; - platforms = platforms.unix; - }; -} diff --git a/nix/pkgs/rust/default.nix b/nix/pkgs/rust/default.nix index fa8f93856..3971c6f57 100644 --- a/nix/pkgs/rust/default.nix +++ b/nix/pkgs/rust/default.nix @@ -8,7 +8,6 @@ let rustPlatform = recurseIntoAttrs (makeRustPlatform (callPackage ./bootstrap.nix {})); version = "1.28.0"; - cargoVersion = "1.28.0"; src = fetchFromGitHub { owner = "m-labs"; repo = "rust"; @@ -86,12 +85,4 @@ in rec { # Disabled for now; see https://github.com/NixOS/nixpkgs/pull/42348#issuecomment-402115598. doCheck = false; }; - - cargo = callPackage ./cargo.nix rec { - version = cargoVersion; - inherit src; - inherit stdenv; - inherit rustc; # the rustc that will be wrapped by cargo - inherit rustPlatform; # used to build cargo - }; } From 13c4d935a27dbbf9e6e66224def6ff7998e93753 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 9 Feb 2019 14:23:36 +0800 Subject: [PATCH 1626/2457] nix/artiq-board: build tester variant --- nix/artiq-board.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nix/artiq-board.nix b/nix/artiq-board.nix index caed8b693..791ee66d2 100644 --- a/nix/artiq-board.nix +++ b/nix/artiq-board.nix @@ -43,13 +43,13 @@ in pkgs.stdenv.mkDerivation { phases = [ "buildPhase" "installPhase" ]; buildPhase = '' - ${buildenv}/bin/artiq-dev -c "CARGO_HOME=${cargoVendored} python -m artiq.gateware.targets.kasli -V satellite --no-compile-gateware" + ${buildenv}/bin/artiq-dev -c "CARGO_HOME=${cargoVendored} python -m artiq.gateware.targets.kasli -V tester --no-compile-gateware" ''; installPhase = '' mkdir $out - #cp artiq_kasli/satellite/gateware/top.bit $out - cp artiq_kasli/satellite/software/bootloader/bootloader.bin $out - cp artiq_kasli/satellite/software/satman/satman.{elf,fbi} $out + #cp artiq_kasli/tester/gateware/top.bit $out + cp artiq_kasli/tester/software/bootloader/bootloader.bin $out + cp artiq_kasli/tester/software/runtime/runtime.{elf,fbi} $out ''; } From a52234b5ff7b6824aa4f08b1b2fe72f847e7d181 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 9 Feb 2019 14:29:37 +0800 Subject: [PATCH 1627/2457] nix: build firmware on hydra --- nix/release.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nix/release.nix b/nix/release.nix index e67ba467b..cd2388b69 100644 --- a/nix/release.nix +++ b/nix/release.nix @@ -3,6 +3,7 @@ let artiqPkgs = import ./default.nix { inherit pkgs; }; jobs = rec { conda-artiq = import ./conda-build.nix { inherit pkgs; }; + artiq-board = import ./artiq-board.nix { inherit pkgs; }; } // artiqPkgs; in jobs From 2aab84453d9517a8a954905b3f2ce372dfd01266 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 9 Feb 2019 14:44:32 +0800 Subject: [PATCH 1628/2457] nix: commit missing file --- nix/fetchcargo.nix | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 nix/fetchcargo.nix diff --git a/nix/fetchcargo.nix b/nix/fetchcargo.nix new file mode 100644 index 000000000..6195a7238 --- /dev/null +++ b/nix/fetchcargo.nix @@ -0,0 +1,35 @@ +{ stdenv, cacert, git, cargo, cargo-vendor }: +{ name, src, sha256 }: +stdenv.mkDerivation { + name = "${name}-vendor"; + nativeBuildInputs = [ cacert git cargo cargo-vendor ]; + inherit src; + + phases = "unpackPhase patchPhase installPhase"; + + installPhase = '' + if [[ ! -f Cargo.lock ]]; then + echo + echo "ERROR: The Cargo.lock file doesn't exist" + echo + echo "Cargo.lock is needed to make sure that cargoSha256 doesn't change" + echo "when the registry is updated." + echo + + exit 1 + fi + + export CARGO_HOME=$(mktemp -d cargo-home.XXX) + + cargo vendor + + cp -ar vendor $out + ''; + + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + outputHash = sha256; + + impureEnvVars = stdenv.lib.fetchers.proxyImpureEnvVars; + preferLocalBuild = true; +} From ee611c5c30d8fca46046f5db9a34d47108955bfb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 9 Feb 2019 15:07:16 +0800 Subject: [PATCH 1629/2457] nix: build gateware --- nix/artiq-board.nix | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nix/artiq-board.nix b/nix/artiq-board.nix index 791ee66d2..020ddaece 100644 --- a/nix/artiq-board.nix +++ b/nix/artiq-board.nix @@ -1,3 +1,6 @@ +# Install Vivado in /opt and add to /etc/nixos/configuration.nix: +# nix.sandboxPaths = ["/opt"]; + { pkgs ? import {}}: let @@ -43,12 +46,12 @@ in pkgs.stdenv.mkDerivation { phases = [ "buildPhase" "installPhase" ]; buildPhase = '' - ${buildenv}/bin/artiq-dev -c "CARGO_HOME=${cargoVendored} python -m artiq.gateware.targets.kasli -V tester --no-compile-gateware" + ${buildenv}/bin/artiq-dev -c "CARGO_HOME=${cargoVendored} python -m artiq.gateware.targets.kasli -V tester" ''; installPhase = '' mkdir $out - #cp artiq_kasli/tester/gateware/top.bit $out + cp artiq_kasli/tester/gateware/top.bit $out cp artiq_kasli/tester/software/bootloader/bootloader.bin $out cp artiq_kasli/tester/software/runtime/runtime.{elf,fbi} $out ''; From 7c6abfb2ce0fd9f54105ad62c5594816c22fa316 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 9 Feb 2019 17:58:46 +0800 Subject: [PATCH 1630/2457] nix: cleanup --- nix/artiq-board.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/artiq-board.nix b/nix/artiq-board.nix index 020ddaece..cde05539d 100644 --- a/nix/artiq-board.nix +++ b/nix/artiq-board.nix @@ -21,7 +21,7 @@ let installPhase = '' mkdir -p $out/registry - cat > $out/config <<-EOF + cat << EOF > $out/config [source.crates-io] registry = "https://github.com/rust-lang/crates.io-index" replace-with = "vendored-sources" From 8194f74252e546f9fdf22d6a09a569e1a1d2731e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 9 Feb 2019 18:06:36 +0800 Subject: [PATCH 1631/2457] nix: build board conda package --- nix/conda-board.nix | 60 +++++++++++++++++++++++++++++++++++++++++++++ nix/conda-build.nix | 9 ++++--- nix/release.nix | 13 ++++++++-- 3 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 nix/conda-board.nix diff --git a/nix/conda-board.nix b/nix/conda-board.nix new file mode 100644 index 000000000..d8152bfc3 --- /dev/null +++ b/nix/conda-board.nix @@ -0,0 +1,60 @@ +{ pkgs ? import {}}: +{ artiqSrc, boardBinaries }: + +with pkgs; + +let + target = "kasli"; + variant = "tester"; + + fakeCondaSource = runCommand "fake-conda-source-${target}-${variant}" { } + '' + cp --no-preserve=mode,ownership -R ${artiqSrc} $out + mkdir $out/fake-conda; + + cat << EOF > $out/fake-conda/meta.yaml + package: + name: artiq-${target}-${variant} + version: {{ environ["GIT_DESCRIBE_TAG"] }} + + source: + git_url: .. + + build: + noarch: python + number: {{ environ["GIT_DESCRIBE_NUMBER"] }} + string: {{ environ["GIT_DESCRIBE_NUMBER"] }}+git{{ environ["GIT_FULL_HASH"][:8] }} + ignore_prefix_files: True + + outputs: + - name: artiq-${target}-${variant} + noarch: python + files: + - site-packages + requirements: + run: + - artiq {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} + ignore_prefix_files: True + + about: + home: https://m-labs.hk/artiq + license: LGPL + summary: 'Bitstream, BIOS and firmware for the ${target}-${variant} board variant' + EOF + + cat << EOF > $out/fake-conda/build.sh + #!/bin/bash + set -e + SOC_PREFIX=\$PREFIX/site-packages/artiq/binaries/${target}-${variant} + mkdir -p \$SOC_PREFIX + cp ${boardBinaries}/* \$SOC_PREFIX + EOF + chmod 755 $out/fake-conda/build.sh + ''; + conda-board = import ./conda-build.nix { inherit pkgs; } { + name = "conda-board-${target}-${variant}"; + src = fakeCondaSource; + recipe = "fake-conda"; + }; +in + conda-board diff --git a/nix/conda-build.nix b/nix/conda-build.nix index 6780ff3c7..22dd9eb6d 100644 --- a/nix/conda-build.nix +++ b/nix/conda-build.nix @@ -1,4 +1,8 @@ +# We need to pass the whole source to conda for the git variables to work. +# recipe must be a string pointing to a path within the source. + { pkgs ? import {}}: +{ name, src, recipe }: with pkgs; @@ -37,8 +41,7 @@ let }; in stdenv.mkDerivation { - name = "conda-artiq"; - src = ../.; + inherit name src; buildInputs = [ condaBuilderEnv ]; buildCommand = '' @@ -54,7 +57,7 @@ in stdenv.mkDerivation { - PYTHON EOF mkdir $out - ${condaBuilderEnv}/bin/conda-builder-env -c "PYTHON=python conda build --clobber-file clobber.yaml --no-anaconda-upload --no-test --output-folder $out $src/conda/artiq" + ${condaBuilderEnv}/bin/conda-builder-env -c "PYTHON=python conda build --clobber-file clobber.yaml --no-anaconda-upload --no-test --output-folder $out $src/${recipe}" mkdir -p $out/nix-support echo file conda $out/noarch/*.tar.bz2 >> $out/nix-support/hydra-build-products diff --git a/nix/release.nix b/nix/release.nix index cd2388b69..ac927d991 100644 --- a/nix/release.nix +++ b/nix/release.nix @@ -1,9 +1,18 @@ { pkgs ? import {}}: let artiqPkgs = import ./default.nix { inherit pkgs; }; + artiq-board = import ./artiq-board.nix { inherit pkgs; }; jobs = rec { - conda-artiq = import ./conda-build.nix { inherit pkgs; }; - artiq-board = import ./artiq-board.nix { inherit pkgs; }; + conda-artiq = import ./conda-build.nix { inherit pkgs; } { + name = "conda-artiq"; + src = ../.; + recipe = "conda/artiq"; + }; + inherit artiq-board; + conda-artiq-board = import ./conda-board.nix { inherit pkgs; } { + artiqSrc = ../.; + boardBinaries = artiq-board; + }; } // artiqPkgs; in jobs From f673ce276f886e6ab4286a1e82c27b549981081c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 9 Feb 2019 18:55:50 +0800 Subject: [PATCH 1632/2457] nix: consistent naming of board artifacts --- nix/artiq-board.nix | 2 +- nix/conda-board.nix | 4 ++-- nix/release.nix | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/nix/artiq-board.nix b/nix/artiq-board.nix index cde05539d..944044ecb 100644 --- a/nix/artiq-board.nix +++ b/nix/artiq-board.nix @@ -41,7 +41,7 @@ let buildenv = import ./artiq-dev.nix { inherit pkgs; }; in pkgs.stdenv.mkDerivation { - name = "artiq-board"; + name = "artiq-board-kasli-tester"; src = null; phases = [ "buildPhase" "installPhase" ]; buildPhase = diff --git a/nix/conda-board.nix b/nix/conda-board.nix index d8152bfc3..51775887d 100644 --- a/nix/conda-board.nix +++ b/nix/conda-board.nix @@ -14,7 +14,7 @@ let cat << EOF > $out/fake-conda/meta.yaml package: - name: artiq-${target}-${variant} + name: artiq-board-${target}-${variant} version: {{ environ["GIT_DESCRIBE_TAG"] }} source: @@ -27,7 +27,7 @@ let ignore_prefix_files: True outputs: - - name: artiq-${target}-${variant} + - name: artiq-board-${target}-${variant} noarch: python files: - site-packages diff --git a/nix/release.nix b/nix/release.nix index ac927d991..ba91ff029 100644 --- a/nix/release.nix +++ b/nix/release.nix @@ -1,17 +1,17 @@ { pkgs ? import {}}: let artiqPkgs = import ./default.nix { inherit pkgs; }; - artiq-board = import ./artiq-board.nix { inherit pkgs; }; + artiq-board-kasli-tester = import ./artiq-board.nix { inherit pkgs; }; jobs = rec { conda-artiq = import ./conda-build.nix { inherit pkgs; } { name = "conda-artiq"; src = ../.; recipe = "conda/artiq"; }; - inherit artiq-board; - conda-artiq-board = import ./conda-board.nix { inherit pkgs; } { + inherit artiq-board-kasli-tester; + conda-artiq-board-kasli-tester = import ./conda-board.nix { inherit pkgs; } { artiqSrc = ../.; - boardBinaries = artiq-board; + boardBinaries = artiq-board-kasli-tester; }; } // artiqPkgs; in From 3a21794b79dc7178ea08e8673247832210b04091 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 10 Feb 2019 01:01:16 +0800 Subject: [PATCH 1633/2457] nix: update user instructions --- nix/README.rst | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/nix/README.rst b/nix/README.rst index 24998d2dd..07b99dab8 100644 --- a/nix/README.rst +++ b/nix/README.rst @@ -19,11 +19,14 @@ This sets up an environment suitable for using ARTIQ, including the ARTIQ-Python * $ ``source ~/.nix-profile/etc/profile.d/nix.sh`` -* $ ``git clone github.com/m-labs/artiq`` -* $ ``cd artiq/nix`` -* $ ``nix-env -i -f default.nix`` - -The above command will setup your entire environment. Note that it will compile LLVM, which uses a lot of CPU time and disk space. +* $ ``nix-channel --add https://nixbld.m-labs.hk/project/artiq/channel/latest m-labs`` +* $ ``nix-channel --update`` +* create the file ``~/.config/nix/nix.conf`` with the following content: +`` +substituters = https://cache.nixos.org https://nixbld.m-labs.hk +trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc= +`` +* $ ``nix-env -i python3.6-artiq`` ARTIQ development environment with Nix ====================================== From d83251098aa08d026bd40e3cfcf4b086692868a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Sun, 10 Feb 2019 01:04:28 +0800 Subject: [PATCH 1634/2457] nix: fix user instructions formatting --- nix/README.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/nix/README.rst b/nix/README.rst index 07b99dab8..91c14c3ef 100644 --- a/nix/README.rst +++ b/nix/README.rst @@ -13,20 +13,20 @@ This sets up an environment suitable for using ARTIQ, including the ARTIQ-Python * if you would like to install via sh - * $ ``wget https://nixos.org/nix/install`` + * ``$ wget https://nixos.org/nix/install`` - * $ ``sh install`` + * ``$ sh install`` - * $ ``source ~/.nix-profile/etc/profile.d/nix.sh`` + * ``$ source ~/.nix-profile/etc/profile.d/nix.sh`` -* $ ``nix-channel --add https://nixbld.m-labs.hk/project/artiq/channel/latest m-labs`` -* $ ``nix-channel --update`` +* ``$ nix-channel --add https://nixbld.m-labs.hk/project/artiq/channel/latest m-labs`` +* ``$ nix-channel --update`` * create the file ``~/.config/nix/nix.conf`` with the following content: -`` +``` substituters = https://cache.nixos.org https://nixbld.m-labs.hk trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc= -`` -* $ ``nix-env -i python3.6-artiq`` +``` +* ``$ nix-env -i python3.6-artiq`` ARTIQ development environment with Nix ====================================== From 566f5094d902cde6bd3e0054b74e9db87f0d3cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Sun, 10 Feb 2019 01:07:55 +0800 Subject: [PATCH 1635/2457] nix: more .rst struggles --- nix/README.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/nix/README.rst b/nix/README.rst index 91c14c3ef..9cf5902c2 100644 --- a/nix/README.rst +++ b/nix/README.rst @@ -21,11 +21,10 @@ This sets up an environment suitable for using ARTIQ, including the ARTIQ-Python * ``$ nix-channel --add https://nixbld.m-labs.hk/project/artiq/channel/latest m-labs`` * ``$ nix-channel --update`` -* create the file ``~/.config/nix/nix.conf`` with the following content: -``` -substituters = https://cache.nixos.org https://nixbld.m-labs.hk -trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc= -``` +* create the file ``~/.config/nix/nix.conf`` with the following content: :: + substituters = https://cache.nixos.org https://nixbld.m-labs.hk + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc=\ + * ``$ nix-env -i python3.6-artiq`` ARTIQ development environment with Nix From e3cf4fd342bb9390a77378bf0a476a30c73704e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Sun, 10 Feb 2019 01:13:54 +0800 Subject: [PATCH 1636/2457] nix: another attempt at getting github .rst formatter to behave --- nix/README.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nix/README.rst b/nix/README.rst index 9cf5902c2..4a1a8f515 100644 --- a/nix/README.rst +++ b/nix/README.rst @@ -21,7 +21,10 @@ This sets up an environment suitable for using ARTIQ, including the ARTIQ-Python * ``$ nix-channel --add https://nixbld.m-labs.hk/project/artiq/channel/latest m-labs`` * ``$ nix-channel --update`` -* create the file ``~/.config/nix/nix.conf`` with the following content: :: +* create the file ``~/.config/nix/nix.conf`` with the following content: + +:: + substituters = https://cache.nixos.org https://nixbld.m-labs.hk trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc=\ From dc14f8258f67c1f58c35a3cb8a7a58bd7cea875a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Sun, 10 Feb 2019 01:16:19 +0800 Subject: [PATCH 1637/2457] nix: fix README.rst --- nix/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/README.rst b/nix/README.rst index 4a1a8f515..4aea10cc2 100644 --- a/nix/README.rst +++ b/nix/README.rst @@ -26,7 +26,7 @@ This sets up an environment suitable for using ARTIQ, including the ARTIQ-Python :: substituters = https://cache.nixos.org https://nixbld.m-labs.hk - trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc=\ + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc= * ``$ nix-env -i python3.6-artiq`` From 820326960e4e60a8485443b486bcc6e248e42075 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 8 Feb 2019 01:13:07 +0000 Subject: [PATCH 1638/2457] test: Add basic experiment dataset interface tests --- artiq/test/test_datasets.py | 69 +++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 artiq/test/test_datasets.py diff --git a/artiq/test/test_datasets.py b/artiq/test/test_datasets.py new file mode 100644 index 000000000..710e34116 --- /dev/null +++ b/artiq/test/test_datasets.py @@ -0,0 +1,69 @@ +"""Tests for the (Env)Experiment-facing dataset interface.""" + +import copy +import unittest + +from artiq.experiment import EnvExperiment +from artiq.master.worker_db import DatasetManager +from artiq.protocols.sync_struct import process_mod + + +class MockDatasetDB: + def __init__(self): + self.data = dict() + + def get(self, key): + return self.data[key][1] + + def update(self, mod): + # Copy mod before applying to avoid sharing references to objects + # between this and the DatasetManager, which would lead to mods being + # applied twice. + process_mod(self.data, copy.deepcopy(mod)) + + def delete(self, key): + del self.data[key] + + +class TestExperiment(EnvExperiment): + def get(self, key): + return self.get_dataset(key) + + def set(self, key, value, **kwargs): + self.set_dataset(key, value, **kwargs) + + +KEY = "foo" + + +class ExperimentDatasetCase(unittest.TestCase): + def setUp(self): + # Create an instance of TestExperiment locally in this process and a + # mock dataset db to back it. When used from the master, the worker IPC + # connection would marshal updates between dataset_mgr and dataset_db. + self.dataset_db = MockDatasetDB() + self.dataset_mgr = DatasetManager(self.dataset_db) + self.exp = TestExperiment((None, self.dataset_mgr, None)) + + def test_set_local(self): + with self.assertRaises(KeyError): + self.exp.get(KEY) + + for i in range(2): + self.exp.set(KEY, i) + self.assertEqual(self.exp.get(KEY), i) + with self.assertRaises(KeyError): + self.dataset_db.get(KEY) + + def test_set_broadcast(self): + with self.assertRaises(KeyError): + self.exp.get(KEY) + + self.exp.set(KEY, 0, broadcast=True) + self.assertEqual(self.exp.get(KEY), 0) + self.assertEqual(self.dataset_db.get(KEY), 0) + + self.exp.set(KEY, 1, broadcast=False) + self.assertEqual(self.exp.get(KEY), 1) + with self.assertRaises(KeyError): + self.dataset_db.get(KEY) From bf84226c7d19b4bceecaf2842391b6dcef5828b6 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 25 Jun 2018 10:52:25 +0100 Subject: [PATCH 1639/2457] language: Support appending to datasets --- RELEASE_NOTES.rst | 2 ++ artiq/language/environment.py | 12 ++++++++++++ artiq/master/worker_db.py | 16 ++++++++++------ artiq/test/test_datasets.py | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index a3beab361..453c4ed2b 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -20,6 +20,8 @@ ARTIQ-5 edge timestamps are not required. See :mod:`artiq.coredevice.edge_counter` for the core device driver and :mod:`artiq.gateware.rtio.phy.edge_counter`/ :meth:`artiq.gateware.eem.DIO.add_std` for the gateware components. +* List datasets can now be efficiently appended to from experiments using + :meth:`artiq.language.environment.HasEnvironment.append_to_dataset`. * The controller manager now ignores device database entries without the ``"command"`` key set to facilitate sharing of devices between multiple masters. diff --git a/artiq/language/environment.py b/artiq/language/environment.py index 5eb4e8d81..0e1b2b918 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -321,6 +321,18 @@ class HasEnvironment: as ``slice(*sub_tuple)`` (multi-dimensional slicing).""" self.__dataset_mgr.mutate(key, index, value) + @rpc(flags={"async"}) + def append_to_dataset(self, key, value): + """Append a value to a dataset. + + The target dataset must be a list (i.e. support ``append()``), and must + have previously been set from this experiment. + + The broadcast/persist/archive mode of the given key remains unchanged + from when the dataset was last set. Appended values are transmitted + efficiently as incremental modifications in broadcast mode.""" + self.__dataset_mgr.append_to(key, value) + def get_dataset(self, key, default=NoDefault, archive=True): """Returns the contents of a dataset. diff --git a/artiq/master/worker_db.py b/artiq/master/worker_db.py index a1555037f..d2dd628f5 100644 --- a/artiq/master/worker_db.py +++ b/artiq/master/worker_db.py @@ -136,17 +136,18 @@ class DatasetManager: elif key in self.local: del self.local[key] - def mutate(self, key, index, value): - target = None - if key in self.local: - target = self.local[key] + def _get_mutation_target(self, key): + target = self.local.get(key, None) if key in self._broadcaster.raw_view: if target is not None: assert target is self._broadcaster.raw_view[key][1] - target = self._broadcaster[key][1] + return self._broadcaster[key][1] if target is None: - raise KeyError("Cannot mutate non-existing dataset") + raise KeyError("Cannot mutate nonexistent dataset '{}'".format(key)) + return target + def mutate(self, key, index, value): + target = self._get_mutation_target(key) if isinstance(index, tuple): if isinstance(index[0], tuple): index = tuple(slice(*e) for e in index) @@ -154,6 +155,9 @@ class DatasetManager: index = slice(*index) setitem(target, index, value) + def append_to(self, key, value): + self._get_mutation_target(key).append(value) + def get(self, key, archive=False): if key in self.local: return self.local[key] diff --git a/artiq/test/test_datasets.py b/artiq/test/test_datasets.py index 710e34116..db35d7f34 100644 --- a/artiq/test/test_datasets.py +++ b/artiq/test/test_datasets.py @@ -32,6 +32,9 @@ class TestExperiment(EnvExperiment): def set(self, key, value, **kwargs): self.set_dataset(key, value, **kwargs) + def append(self, key, value): + self.append_to_dataset(key, value) + KEY = "foo" @@ -67,3 +70,35 @@ class ExperimentDatasetCase(unittest.TestCase): self.assertEqual(self.exp.get(KEY), 1) with self.assertRaises(KeyError): self.dataset_db.get(KEY) + + def test_append_local(self): + self.exp.set(KEY, []) + self.exp.append(KEY, 0) + self.assertEqual(self.exp.get(KEY), [0]) + self.exp.append(KEY, 1) + self.assertEqual(self.exp.get(KEY), [0, 1]) + + def test_append_broadcast(self): + self.exp.set(KEY, [], broadcast=True) + self.exp.append(KEY, 0) + self.assertEqual(self.dataset_db.data[KEY][1], [0]) + self.exp.append(KEY, 1) + self.assertEqual(self.dataset_db.data[KEY][1], [0, 1]) + + def test_append_array(self): + for broadcast in (True, False): + self.exp.set(KEY, [], broadcast=broadcast) + self.exp.append(KEY, []) + self.exp.append(KEY, []) + self.assertEqual(self.exp.get(KEY), [[], []]) + + def test_append_scalar_fails(self): + for broadcast in (True, False): + with self.assertRaises(AttributeError): + self.exp.set(KEY, 0, broadcast=broadcast) + self.exp.append(KEY, 1) + + def test_append_nonexistent_fails(self): + with self.assertRaises(KeyError): + self.exp.append(KEY, 0) + From 56b2e0c2625298afe104a8090f531c8024a5d4d3 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 30 Jun 2018 19:37:03 +0100 Subject: [PATCH 1640/2457] artiq_influxdb: Support append() in dataset _Mock This went undetected as append mods were not actually in use in any part of the codebase previously. --- artiq/frontend/artiq_influxdb.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/frontend/artiq_influxdb.py b/artiq/frontend/artiq_influxdb.py index f0ffa350d..0dbd740c5 100755 --- a/artiq/frontend/artiq_influxdb.py +++ b/artiq/frontend/artiq_influxdb.py @@ -131,6 +131,9 @@ class _Mock: def __delitem__(self, k): pass + def append(self, v): + pass + class Datasets: def __init__(self, filter_function, writer, init): From 01c3000ef3962a2c4ab3d1a13b70df15f4370081 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 25 Jun 2018 10:50:30 +0100 Subject: [PATCH 1641/2457] master: Print offending key on HDF5 dataset type error This helps debugging the cause of TypeErrors arising from types not handled by the HDF5 serializer, as the backtrace doesn't otherwise include any useful information. --- artiq/master/worker_db.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/artiq/master/worker_db.py b/artiq/master/worker_db.py index d2dd628f5..3a3f7ef25 100644 --- a/artiq/master/worker_db.py +++ b/artiq/master/worker_db.py @@ -173,8 +173,18 @@ class DatasetManager: def write_hdf5(self, f): datasets_group = f.create_group("datasets") for k, v in self.local.items(): - datasets_group[k] = v + _write(datasets_group, k, v) archive_group = f.create_group("archive") for k, v in self.archive.items(): - archive_group[k] = v + _write(archive_group, k, v) + + +def _write(group, k, v): + # Add context to exception message when the user writes a dataset that is + # not representable in HDF5. + try: + group[k] = v + except TypeError as e: + raise TypeError("Error writing dataset '{}' of type '{}': {}".format( + k, type(v), e)) From 0a84dd38c13dd573b0d53af44aafb512fd4a9c9d Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 10 Feb 2019 07:25:48 +0000 Subject: [PATCH 1642/2457] Add missing test from d6eb2b02. --- artiq/test/lit/monomorphism/bug_1252.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 artiq/test/lit/monomorphism/bug_1252.py diff --git a/artiq/test/lit/monomorphism/bug_1252.py b/artiq/test/lit/monomorphism/bug_1252.py new file mode 100644 index 000000000..e00a899ab --- /dev/null +++ b/artiq/test/lit/monomorphism/bug_1252.py @@ -0,0 +1,8 @@ +# RUN: %python -m artiq.compiler.testbench.irgen %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +# CHECK-L: %BLT.round = numpy.int64 builtin(round) float +def frequency_to_ftw(frequency): + return int64(round(1e-9*frequency)) + +frequency_to_ftw(1e9) From c32bf770ab0d600f388b7afeb85d4b6a10c517e9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Feb 2019 12:28:58 +0800 Subject: [PATCH 1643/2457] nix: give openocd a better name to distinguish from nixpkgs version --- nix/pkgs/openocd.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix/pkgs/openocd.nix b/nix/pkgs/openocd.nix index 4ec524e33..df6588ab9 100644 --- a/nix/pkgs/openocd.nix +++ b/nix/pkgs/openocd.nix @@ -1,8 +1,8 @@ { stdenv, fetchFromGitHub, autoreconfHook, libftdi, libusb1, pkgconfig, hidapi }: stdenv.mkDerivation rec { - name = "openocd-${version}"; - version = "0.10.0.mlabs"; + name = "openocd-mlabs-${version}"; + version = "0.10.0"; src = fetchFromGitHub { owner = "m-labs"; From ed030704d28ee4723cba93a9e8cd817230e94eb6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Feb 2019 19:05:33 +0800 Subject: [PATCH 1644/2457] nix: place board binaries where artiq_flash looks for them --- nix/artiq-board.nix | 14 ++++++++------ nix/conda-board.nix | 7 ++----- nix/release.nix | 8 ++++++-- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/nix/artiq-board.nix b/nix/artiq-board.nix index 944044ecb..b6a8a4091 100644 --- a/nix/artiq-board.nix +++ b/nix/artiq-board.nix @@ -2,6 +2,7 @@ # nix.sandboxPaths = ["/opt"]; { pkgs ? import {}}: +{ target, variant }: let artiqPkgs = import ./default.nix { inherit pkgs; }; @@ -41,18 +42,19 @@ let buildenv = import ./artiq-dev.nix { inherit pkgs; }; in pkgs.stdenv.mkDerivation { - name = "artiq-board-kasli-tester"; + name = "artiq-board-${target}-${variant}"; src = null; phases = [ "buildPhase" "installPhase" ]; buildPhase = '' - ${buildenv}/bin/artiq-dev -c "CARGO_HOME=${cargoVendored} python -m artiq.gateware.targets.kasli -V tester" + ${buildenv}/bin/artiq-dev -c "CARGO_HOME=${cargoVendored} python -m artiq.gateware.targets.${target} -V ${variant} --gateware-toolchain-path /home/sb/opt/Xilinx/Vivado" ''; installPhase = '' - mkdir $out - cp artiq_kasli/tester/gateware/top.bit $out - cp artiq_kasli/tester/software/bootloader/bootloader.bin $out - cp artiq_kasli/tester/software/runtime/runtime.{elf,fbi} $out + TARGET_DIR=$out/${pkgs.python3Packages.python.sitePackages}/artiq/binaries/${target}-${variant} + mkdir -p $TARGET_DIR + cp artiq_${target}/${variant}/gateware/top.bit $TARGET_DIR + cp artiq_${target}/${variant}/software/bootloader/bootloader.bin $TARGET_DIR + cp artiq_${target}/${variant}/software/runtime/runtime.{elf,fbi} $TARGET_DIR ''; } diff --git a/nix/conda-board.nix b/nix/conda-board.nix index 51775887d..7f222f6c8 100644 --- a/nix/conda-board.nix +++ b/nix/conda-board.nix @@ -1,12 +1,9 @@ { pkgs ? import {}}: -{ artiqSrc, boardBinaries }: +{ artiqSrc, boardBinaries, target, variant }: with pkgs; let - target = "kasli"; - variant = "tester"; - fakeCondaSource = runCommand "fake-conda-source-${target}-${variant}" { } '' cp --no-preserve=mode,ownership -R ${artiqSrc} $out @@ -47,7 +44,7 @@ let set -e SOC_PREFIX=\$PREFIX/site-packages/artiq/binaries/${target}-${variant} mkdir -p \$SOC_PREFIX - cp ${boardBinaries}/* \$SOC_PREFIX + cp ${boardBinaries}/${pkgs.python3Packages.python.sitePackages}/artiq/binaries/${target}-${variant}/* \$SOC_PREFIX EOF chmod 755 $out/fake-conda/build.sh ''; diff --git a/nix/release.nix b/nix/release.nix index ba91ff029..56023fe63 100644 --- a/nix/release.nix +++ b/nix/release.nix @@ -1,17 +1,21 @@ { pkgs ? import {}}: let artiqPkgs = import ./default.nix { inherit pkgs; }; - artiq-board-kasli-tester = import ./artiq-board.nix { inherit pkgs; }; jobs = rec { conda-artiq = import ./conda-build.nix { inherit pkgs; } { name = "conda-artiq"; src = ../.; recipe = "conda/artiq"; }; - inherit artiq-board-kasli-tester; + artiq-board-kasli-tester = import ./artiq-board.nix { inherit pkgs; } { + target = "kasli"; + variant = "tester"; + }; conda-artiq-board-kasli-tester = import ./conda-board.nix { inherit pkgs; } { artiqSrc = ../.; boardBinaries = artiq-board-kasli-tester; + target = "kasli"; + variant = "tester"; }; } // artiqPkgs; in From edb12a6a5deb701a60a3bdb7fab2480c27aef50e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Feb 2019 19:24:02 +0800 Subject: [PATCH 1645/2457] nix: revert accidentally committed local modification --- nix/artiq-board.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/artiq-board.nix b/nix/artiq-board.nix index b6a8a4091..3c55332a8 100644 --- a/nix/artiq-board.nix +++ b/nix/artiq-board.nix @@ -47,7 +47,7 @@ in pkgs.stdenv.mkDerivation { phases = [ "buildPhase" "installPhase" ]; buildPhase = '' - ${buildenv}/bin/artiq-dev -c "CARGO_HOME=${cargoVendored} python -m artiq.gateware.targets.${target} -V ${variant} --gateware-toolchain-path /home/sb/opt/Xilinx/Vivado" + ${buildenv}/bin/artiq-dev -c "CARGO_HOME=${cargoVendored} python -m artiq.gateware.targets.${target} -V ${variant} ''; installPhase = '' From 3a84790c449fd8de8166328306f9a45d9ce7b5dc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Feb 2019 19:27:50 +0800 Subject: [PATCH 1646/2457] nix: build kc705 nist_clock packages --- nix/release.nix | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/nix/release.nix b/nix/release.nix index 56023fe63..710030351 100644 --- a/nix/release.nix +++ b/nix/release.nix @@ -1,22 +1,40 @@ { pkgs ? import {}}: let artiqPkgs = import ./default.nix { inherit pkgs; }; - jobs = rec { + + boards = [ + { + target = "kasli"; + variant = "tester"; + } + { + target = "kc705"; + variant = "nist_clock"; + } + ]; + boardJobs = pkgs.lib.lists.foldr (board: start: + let + boardBinaries = import ./artiq-board.nix { inherit pkgs; } { + target = board.target; + variant = board.variant; + }; + in + start // { + "artiq-board-${board.target}-${board.variant}" = boardBinaries; + "conda-artiq-board-${board.target}-${board.variant}" = import ./conda-board.nix { inherit pkgs; } { + artiqSrc = ../.; + boardBinaries = boardBinaries; + target = board.target; + variant = board.variant; + }; + }) {} boards; + + jobs = { conda-artiq = import ./conda-build.nix { inherit pkgs; } { name = "conda-artiq"; src = ../.; recipe = "conda/artiq"; }; - artiq-board-kasli-tester = import ./artiq-board.nix { inherit pkgs; } { - target = "kasli"; - variant = "tester"; - }; - conda-artiq-board-kasli-tester = import ./conda-board.nix { inherit pkgs; } { - artiqSrc = ../.; - boardBinaries = artiq-board-kasli-tester; - target = "kasli"; - variant = "tester"; - }; - } // artiqPkgs; + } // boardJobs // artiqPkgs; in jobs From 74c16e038eac8afb460859a1d067125627c92d5d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Feb 2019 20:10:19 +0800 Subject: [PATCH 1647/2457] nix: fix edb12a6a5deb701a60a3bdb7fab2480c27aef50e --- nix/artiq-board.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/artiq-board.nix b/nix/artiq-board.nix index 3c55332a8..6f2a2a8e7 100644 --- a/nix/artiq-board.nix +++ b/nix/artiq-board.nix @@ -47,7 +47,7 @@ in pkgs.stdenv.mkDerivation { phases = [ "buildPhase" "installPhase" ]; buildPhase = '' - ${buildenv}/bin/artiq-dev -c "CARGO_HOME=${cargoVendored} python -m artiq.gateware.targets.${target} -V ${variant} + ${buildenv}/bin/artiq-dev -c "CARGO_HOME=${cargoVendored} python -m artiq.gateware.targets.${target} -V ${variant}" ''; installPhase = '' From ff4e4f15ed33ccbf33eda1ce20e577f8c4192667 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 12 Feb 2019 18:33:27 +0800 Subject: [PATCH 1648/2457] kasli: expose base SoC classes --- artiq/gateware/targets/kasli.py | 98 ++++++++++++++++----------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index a5ec2c880..098364512 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -86,7 +86,7 @@ def fix_serdes_timing_path(platform): ) -class _StandaloneBase(MiniSoC, AMPSoC): +class StandaloneBase(MiniSoC, AMPSoC): mem_map = { "cri_con": 0x10000000, "rtio": 0x20000000, @@ -145,14 +145,14 @@ class _StandaloneBase(MiniSoC, AMPSoC): self.csr_devices.append("rtio_analyzer") -class Opticlock(_StandaloneBase): +class Opticlock(StandaloneBase): """ Opticlock extension variant configuration """ def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.0" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["SI5324_EXT_REF"] = None @@ -188,14 +188,14 @@ class Opticlock(_StandaloneBase): self.add_rtio(self.rtio_channels) -class SUServo(_StandaloneBase): +class SUServo(StandaloneBase): """ SUServo (Sampler-Urukul-Servo) extension variant configuration """ def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None @@ -235,11 +235,11 @@ class SUServo(_StandaloneBase): pads.clkout, self.crg.cd_sys.clk) -class SYSU(_StandaloneBase): +class SYSU(StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.0" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" @@ -270,11 +270,11 @@ class SYSU(_StandaloneBase): self.add_rtio(self.rtio_channels) -class MITLL(_StandaloneBase): +class MITLL(StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" @@ -308,11 +308,11 @@ class MITLL(_StandaloneBase): self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) -class MITLL2(_StandaloneBase): +class MITLL2(StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" @@ -347,11 +347,11 @@ class MITLL2(_StandaloneBase): self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) -class USTC(_StandaloneBase): +class USTC(StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" @@ -388,11 +388,11 @@ class USTC(_StandaloneBase): self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) -class Tsinghua(_StandaloneBase): +class Tsinghua(StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" @@ -426,11 +426,11 @@ class Tsinghua(_StandaloneBase): self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) -class Tsinghua2(_StandaloneBase): +class Tsinghua2(StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" @@ -466,11 +466,11 @@ class Tsinghua2(_StandaloneBase): self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) -class WIPM(_StandaloneBase): +class WIPM(StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = "125.0" @@ -499,11 +499,11 @@ class WIPM(_StandaloneBase): self.add_rtio(self.rtio_channels) -class NUDT(_StandaloneBase): +class NUDT(StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None @@ -533,11 +533,11 @@ class NUDT(_StandaloneBase): self.add_rtio(self.rtio_channels) -class Berkeley(_StandaloneBase): +class Berkeley(StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None @@ -572,11 +572,11 @@ class Berkeley(_StandaloneBase): self.add_rtio(self.rtio_channels) -class UNSW(_StandaloneBase): +class UNSW(StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None @@ -605,7 +605,7 @@ class UNSW(_StandaloneBase): self.add_rtio(self.rtio_channels) -class PTB(_StandaloneBase): +class PTB(StandaloneBase): """PTB Kasli variant F.k.a. ptb-schmidt, ptb-mehlstaeubler, ptb-huntemann-11, ptb-huntemann-19, @@ -614,7 +614,7 @@ class PTB(_StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None @@ -649,12 +649,12 @@ class PTB(_StandaloneBase): self.add_rtio(self.rtio_channels) -class PTB2(_StandaloneBase): +class PTB2(StandaloneBase): """PTB Kasli variant with Urukul1 SYNC and external reference clock""" def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None self.config["SI5324_EXT_REF"] = None @@ -691,7 +691,7 @@ class PTB2(_StandaloneBase): self.add_rtio(self.rtio_channels) -class HUB(_StandaloneBase): +class HUB(StandaloneBase): """HUB Kasli variant F.k.a. hub-krutzik, luh-ospelkaus-13, and luh-ospelkaus-14 @@ -700,7 +700,7 @@ class HUB(_StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None @@ -739,7 +739,7 @@ class HUB(_StandaloneBase): self.add_rtio(self.rtio_channels) -class LUH(_StandaloneBase): +class LUH(StandaloneBase): """LUH Kasli variant F.k.a. luh-ospelkaus-16, luh-ospelkaus-18 in the artiq-setup repository @@ -747,7 +747,7 @@ class LUH(_StandaloneBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None @@ -790,14 +790,14 @@ class LUH(_StandaloneBase): self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) -class Tester(_StandaloneBase): +class Tester(StandaloneBase): """ Configuration for CI tests. Contains the maximum number of different EEMs. """ def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None # self.config["SI5324_EXT_REF"] = None @@ -858,7 +858,7 @@ class _RTIOClockMultiplier(Module, AutoCSR): ] -class _MasterBase(MiniSoC, AMPSoC): +class MasterBase(MiniSoC, AMPSoC): mem_map = { "cri_con": 0x10000000, "rtio": 0x20000000, @@ -1022,7 +1022,7 @@ class _MasterBase(MiniSoC, AMPSoC): self.drtio_qpll_channel, self.ethphy_qpll_channel = qpll.channels -class _SatelliteBase(BaseSoC): +class SatelliteBase(BaseSoC): mem_map = { "drtioaux": 0x50000000, } @@ -1169,11 +1169,11 @@ class _SatelliteBase(BaseSoC): self.csr_devices.append("routing_table") -class Master(_MasterBase): +class Master(MasterBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _MasterBase.__init__(self, hw_rev=hw_rev, **kwargs) + MasterBase.__init__(self, hw_rev=hw_rev, **kwargs) self.rtio_channels = [] @@ -1192,11 +1192,11 @@ class Master(_MasterBase): self.add_rtio(self.rtio_channels) -class Satellite(_SatelliteBase): +class Satellite(SatelliteBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _SatelliteBase.__init__(self, hw_rev=hw_rev, **kwargs) + SatelliteBase.__init__(self, hw_rev=hw_rev, **kwargs) self.rtio_channels = [] phy = ttl_simple.Output(self.platform.request("user_led", 0)) @@ -1209,11 +1209,11 @@ class Satellite(_SatelliteBase): self.add_rtio(self.rtio_channels) -class VLBAIMaster(_MasterBase): +class VLBAIMaster(MasterBase): def __init__(self, hw_rev=None, *args, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _MasterBase.__init__(self, rtio_clk_freq=125e6, hw_rev=hw_rev, *args, + MasterBase.__init__(self, rtio_clk_freq=125e6, hw_rev=hw_rev, *args, **kwargs) self.rtio_channels = [] @@ -1241,11 +1241,11 @@ class VLBAIMaster(_MasterBase): self.add_rtio(self.rtio_channels) -class VLBAISatellite(_SatelliteBase): +class VLBAISatellite(SatelliteBase): def __init__(self, hw_rev=None, *args, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _SatelliteBase.__init__(self, rtio_clk_freq=125e6, hw_rev=hw_rev, + SatelliteBase.__init__(self, rtio_clk_freq=125e6, hw_rev=hw_rev, *args, **kwargs) self.rtio_channels = [] @@ -1269,11 +1269,11 @@ class VLBAISatellite(_SatelliteBase): self.add_rtio(self.rtio_channels) -class HUSTMaster(_MasterBase): +class HUSTMaster(MasterBase): def __init__(self, hw_rev=None, *args, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _MasterBase.__init__(self, rtio_clk_freq=125e6, hw_rev=hw_rev, + MasterBase.__init__(self, rtio_clk_freq=125e6, hw_rev=hw_rev, enable_sata=True, *args, **kwargs) self.rtio_channels = [] @@ -1292,11 +1292,11 @@ class HUSTMaster(_MasterBase): self.add_rtio(self.rtio_channels) -class HUSTSatellite(_SatelliteBase): +class HUSTSatellite(SatelliteBase): def __init__(self, hw_rev=None, *args, **kwargs): if hw_rev is None: hw_rev = "v1.1" - _SatelliteBase.__init__(self, rtio_clk_freq=125e6, hw_rev=hw_rev, + SatelliteBase.__init__(self, rtio_clk_freq=125e6, hw_rev=hw_rev, enable_sata=True, *args, **kwargs) self.rtio_channels = [] From 2104a93f781d66a64c96fb653a64211e339e3179 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 12 Feb 2019 18:33:52 +0800 Subject: [PATCH 1649/2457] build_soc: allow overriding SoC class name --- artiq/build_soc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/build_soc.py b/artiq/build_soc.py index e13eba375..7c1f49e8d 100644 --- a/artiq/build_soc.py +++ b/artiq/build_soc.py @@ -17,7 +17,7 @@ def get_identifier_string(soc, suffix="", add_class_name=True): if suffix or add_class_name: r += ";" if add_class_name: - r += soc.__class__.__name__.lower() + r += getattr(soc, "class_name_override", soc.__class__.__name__.lower()) r += suffix return r From 6ad2e13515d3315390d7c507216b58119cfa8771 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 12 Feb 2019 19:16:16 +0800 Subject: [PATCH 1650/2457] kasli: add generic builder (WIP) --- artiq/gateware/targets/kasli_generic.py | 152 ++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100755 artiq/gateware/targets/kasli_generic.py diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py new file mode 100755 index 000000000..cea12dfd9 --- /dev/null +++ b/artiq/gateware/targets/kasli_generic.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 + +import argparse +import json + +from misoc.integration.builder import builder_args, builder_argdict +from misoc.targets.kasli import soc_kasli_args, soc_kasli_argdict + +from artiq.gateware import rtio +from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, edge_counter +from artiq.gateware import eem +from artiq.gateware.targets.kasli import StandaloneBase, MasterBase, SatelliteBase +from artiq.build_soc import * + + +def peripheral_dio(module, peripheral): + ttl_classes = { + "input": ttl_serdes_7series.InOut_8X, + "output": ttl_serdes_7series.Output_8X + } + if len(peripheral["ports"]) != 1: + raise ValueError("wrong number of ports") + eem.DIO.add_std(module, peripheral["ports"][0], + ttl_classes[peripheral["bank_direction_low"]], + ttl_classes[peripheral["bank_direction_high"]]) + + +def peripheral_urukul(module, peripheral): + if len(peripheral["ports"]) == 1: + port, port_aux = peripheral["ports"][0], None + elif len(peripheral["ports"]) == 2: + port, port_aux = peripheral["ports"] + else: + raise ValueError("wrong number of ports") + if peripheral.get("synchronization", False): + sync_gen_cls = ttl_simple.ClockGen + else: + sync_gen_cls = None + eem.Urukul.add_std(module, port, port_aux, ttl_serdes_7series.Output_8X, + sync_gen_cls) + + +def peripheral_sampler(module, peripheral): + if len(peripheral["ports"]) == 1: + port, port_aux = peripheral["ports"][0], None + elif len(peripheral["ports"]) == 2: + port, port_aux = peripheral["ports"] + else: + raise ValueError("wrong number of ports") + eem.Sampler.add_std(module, port, port_aux, ttl_serdes_7series.Output_8X) + + +def peripheral_zotino(module, peripheral): + if len(peripheral["ports"]) != 1: + raise ValueError("wrong number of ports") + eem.Zotino.add_std(module, peripheral["ports"][0], + ttl_serdes_7series.Output_8X) + + +def peripheral_grabber(module, peripheral): + if len(peripheral["ports"]) == 1: + port, port_aux = peripheral["ports"][0], None + elif len(peripheral["ports"]) == 2: + port, port_aux = peripheral["ports"] + else: + raise ValueError("wrong number of ports") + eem.Grabber.add_std(module, port, port_aux) + + +def add_peripherals(module, peripherals): + peripheral_processors = { + "dio": peripheral_dio, + "urukul": peripheral_urukul, + "sampler": peripheral_sampler, + "zotino": peripheral_zotino, + "grabber": peripheral_grabber, + } + for peripheral in peripherals: + peripheral_processors[peripheral["type"]](module, peripheral) + + +class GenericStandalone(StandaloneBase): + def __init__(self, description, hw_rev=None,**kwargs): + if hw_rev is None: + hw_rev = description["hw_rev"] + StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) + + self.config["SI5324_AS_SYNTHESIZER"] = None + self.config["RTIO_FREQUENCY"] = "{:.1f}".format(description.get("rtio_frequency", 125e6)/1e6) + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) + + has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"]) + if has_grabber: + self.grabber_csr_group = [] + + self.rtio_channels = [] + add_peripherals(self, description["peripherals"]) + for i in (1, 2): + print("SFP LED at RTIO channel {}".format(len(self.rtio_channels))) + sfp_ctl = self.platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) + + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(self.rtio_channels) + if has_grabber: + self.config["HAS_GRABBER"] = None + self.add_csr_group("grabber", self.grabber_csr_group) + for grabber in self.grabber_csr_group: + self.platform.add_false_path_constraints( + self.rtio_crg.cd_rtio.clk, getattr(self, grabber).deserializer.cd_cl.clk) + + +def main(): + parser = argparse.ArgumentParser( + description="ARTIQ device binary builder for generic Kasli systems") + builder_args(parser) + soc_kasli_args(parser) + parser.set_defaults(output_dir="artiq_kasli") + parser.add_argument("description", metavar="DESCRIPTION", + help="JSON system description file") + args = parser.parse_args() + + with open(args.description, "r") as f: + description = json.load(f) + + if description["target"] != "kasli": + raise ValueError("Description is for a different target") + + if description["base"] == "standalone": + cls = GenericStandalone + elif description["base"] == "master": + cls = GenericMaster + elif description["base"] == "satellite": + cls = GenericSatellite + else: + raise ValueError("Invalid base") + + soc = cls(description, **soc_kasli_argdict(args)) + soc.class_name_override = description["variant"] + args.variant = description["variant"] + build_artiq_soc(soc, builder_argdict(args)) + + +if __name__ == "__main__": + main() From ea2956bcb8271afab7a0233a33429119d3aa55fb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 12 Feb 2019 19:32:58 +0800 Subject: [PATCH 1651/2457] nix: allow overriding artiq-board build command --- nix/artiq-board.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix/artiq-board.nix b/nix/artiq-board.nix index 6f2a2a8e7..857cf65dc 100644 --- a/nix/artiq-board.nix +++ b/nix/artiq-board.nix @@ -2,7 +2,7 @@ # nix.sandboxPaths = ["/opt"]; { pkgs ? import {}}: -{ target, variant }: +{ target, variant, buildCommand ? "python -m artiq.gateware.targets.${target} -V ${variant}" }: let artiqPkgs = import ./default.nix { inherit pkgs; }; @@ -47,7 +47,7 @@ in pkgs.stdenv.mkDerivation { phases = [ "buildPhase" "installPhase" ]; buildPhase = '' - ${buildenv}/bin/artiq-dev -c "CARGO_HOME=${cargoVendored} python -m artiq.gateware.targets.${target} -V ${variant}" + ${buildenv}/bin/artiq-dev -c "CARGO_HOME=${cargoVendored} ${buildCommand}" ''; installPhase = '' From bd22c8e20041c771bb4ca07924e67f2737561c78 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Feb 2019 00:22:01 +0800 Subject: [PATCH 1652/2457] nix: name consistency --- nix/conda-board.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/conda-board.nix b/nix/conda-board.nix index 7f222f6c8..0e73b72bd 100644 --- a/nix/conda-board.nix +++ b/nix/conda-board.nix @@ -49,7 +49,7 @@ let chmod 755 $out/fake-conda/build.sh ''; conda-board = import ./conda-build.nix { inherit pkgs; } { - name = "conda-board-${target}-${variant}"; + name = "conda-artiq-board-${target}-${variant}"; src = fakeCondaSource; recipe = "fake-conda"; }; From 30fb7c1049104c0d36b9c1259c364ec8ec303c84 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Feb 2019 11:55:14 +0800 Subject: [PATCH 1653/2457] conda: add installation script for Hydra packages --- conda/install-artiq.py | 63 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 conda/install-artiq.py diff --git a/conda/install-artiq.py b/conda/install-artiq.py new file mode 100644 index 000000000..00ac529c1 --- /dev/null +++ b/conda/install-artiq.py @@ -0,0 +1,63 @@ +# This script installs ARTIQ using the conda packages built by the new Nix/Hydra system. +# It needs to be run in the root (base) conda environment with "python install-artiq.py" +# It supports Linux and Windows, but it really is just an ugly collection of workarounds +# and conda is awful; if you are running Linux, you're better off using Nix which is not +# buggy and needs none of this mess. + +# EDIT THIS: +# The name of the conda environment to create +CONDA_ENV_NAME = "artiq" +# The conda packages to download from hydra and install. +# Each entry is ("hydra build name", "conda package name"). Hydra builds are: +# * main: core ARTIQ packages +# * sinara-systems: firmware and gateware builds for generic Sinara systems +CONDA_PACKAGES = [ + ("main", "artiq"), + ("main", "artiq-board-kc705-nist_clock"), + ("main", "artiq-board-kasli-tester"), + ("sinara-systems", "artiq-board-kasli-mitll") +] +# Set to False if you have already set up conda channels +ADD_CHANNELS = True + +# You should not need to modify the rest of the script below. + +import os +import tempfile + +def run(command): + r = os.system(command) + if r != 0: + raise SystemExit("command '{}' returned non-zero exit status: {}".format(command, r)) + +if ADD_CHANNELS: + run("conda config --add channels m-labs") + run("conda config --add channels conda-forge") +run("conda install -y conda-build curl") + +# Another silly conda decision is to ignore dependencies when installing .tar.bz2's directly. +# Work around it by creating a channel for our packages. +with tempfile.TemporaryDirectory() as channel_dir: + print("Creating conda channel in {channel_dir}...".format(channel_dir=channel_dir)) + previous_dir = os.getcwd() + os.chdir(channel_dir) + try: + os.mkdir("noarch") + # curl -OJL won't take the correct filename and it will save the output as "conda". + # wget --content-disposition is better-behaved but wget cannot be used on Windows. + # Amazingly, conda doesn't do something stupid when package files are renamed, + # so we can get away by generating our own names that don't contain the version number. + for hydra_build, package in CONDA_PACKAGES: + run("curl https://nixbld.m-labs.hk/job/artiq/{hydra_build}/conda-{package}/latest/download-by-type/file/conda -L -o noarch/{package}.tar.bz2" + .format(hydra_build=hydra_build, package=package)) + run("conda index") + + # Creating the environment first with python 3.5 hits fewer bugs in conda's broken dependency solver. + run("conda create -y -n {CONDA_ENV_NAME} python=3.5".format(CONDA_ENV_NAME=CONDA_ENV_NAME)) + for _, package in CONDA_PACKAGES: + # Do not activate the environment yet - otherwise "conda install" may not find the SSL module anymore on Windows. + # Installing into the environment from the outside works around this conda bug. + run("conda install -y -n {CONDA_ENV_NAME} -c {channel_dir} {package}" + .format(CONDA_ENV_NAME=CONDA_ENV_NAME, channel_dir=channel_dir, package=package)) + finally: + os.chdir(previous_dir) From aa17037193b85b80f8418adc15d3f65a6cd6be4c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Feb 2019 12:19:57 +0800 Subject: [PATCH 1654/2457] nix: do not make conda-board package depend on a specific ARTIQ version numbers --- nix/conda-board.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/conda-board.nix b/nix/conda-board.nix index 0e73b72bd..08c9fc18b 100644 --- a/nix/conda-board.nix +++ b/nix/conda-board.nix @@ -30,7 +30,7 @@ let - site-packages requirements: run: - - artiq {{ "{tag} {number}+git{hash}".format(tag=environ["GIT_DESCRIBE_TAG"], number=environ["GIT_DESCRIBE_NUMBER"], hash=environ["GIT_FULL_HASH"][:8]) }} + - artiq ignore_prefix_files: True about: From 0b08baef102374c4f785fd18997fe2b892ec5510 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Feb 2019 20:29:26 +0800 Subject: [PATCH 1655/2457] nix: attempt to create hydra channel properly --- nix/release.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nix/release.nix b/nix/release.nix index 710030351..e992db74c 100644 --- a/nix/release.nix +++ b/nix/release.nix @@ -35,6 +35,11 @@ let src = ../.; recipe = "conda/artiq"; }; + mainchannel = pkgs.releaseTools.channel { + name = "mainchannel"; + src = ./.; + constituents = [ ]; + }; } // boardJobs // artiqPkgs; in jobs From af9988c79c42742bf7defcd77353859c5ce276c7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Feb 2019 20:50:08 +0800 Subject: [PATCH 1656/2457] nix: fix hydra channel --- nix/release.nix | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/nix/release.nix b/nix/release.nix index e992db74c..da00ba021 100644 --- a/nix/release.nix +++ b/nix/release.nix @@ -35,11 +35,12 @@ let src = ../.; recipe = "conda/artiq"; }; - mainchannel = pkgs.releaseTools.channel { - name = "mainchannel"; - src = ./.; - constituents = [ ]; - }; } // boardJobs // artiqPkgs; in - jobs + jobs // { + channel = pkgs.releaseTools.channel { + name = "main"; + src = ./.; + constitutents = builtins.attrValues jobs; + }; + } From f657c44e3d6a61225ee22f6ce259b9b4e4940f4d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Feb 2019 20:52:33 +0800 Subject: [PATCH 1657/2457] nix: fix typo --- nix/release.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/release.nix b/nix/release.nix index da00ba021..625e798e3 100644 --- a/nix/release.nix +++ b/nix/release.nix @@ -41,6 +41,6 @@ in channel = pkgs.releaseTools.channel { name = "main"; src = ./.; - constitutents = builtins.attrValues jobs; + constituents = builtins.attrValues jobs; }; } From 322861225e0eb059e0acc0e4db41ca2064e35b1b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Feb 2019 00:08:43 +0800 Subject: [PATCH 1658/2457] nix: use filterSource --- nix/pkgs/artiq.nix | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nix/pkgs/artiq.nix b/nix/pkgs/artiq.nix index bf2dd8a5d..4b694f5f3 100644 --- a/nix/pkgs/artiq.nix +++ b/nix/pkgs/artiq.nix @@ -65,7 +65,9 @@ in python3Packages.buildPythonPackage rec { name = "artiq"; - src = ./../..; + src = builtins.filterSource + (path: type: type != "directory" || builtins.baseNameOf path != ".nix") + ./../..; buildInputs = [ git ]; propagatedBuildInputs = with python3Packages; [ binutils-or1k llvm-or1k llvmlite levenshtein pyqtgraph-qt5 aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; checkPhase = "python -m unittest discover -v artiq.test"; From 944a3b34c3cc9cc8ff8497afce6bea0151aa7a30 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 13 Feb 2019 17:16:02 +0000 Subject: [PATCH 1659/2457] doc: Fix typo in getting_started_rtio GitHub: Fixes #1276. --- doc/manual/getting_started_core.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/getting_started_core.rst b/doc/manual/getting_started_core.rst index f4d3c8300..66f0c1240 100644 --- a/doc/manual/getting_started_core.rst +++ b/doc/manual/getting_started_core.rst @@ -221,7 +221,7 @@ Try this: :: with self.core_dma.record("pulses"): # all RTIO operations now go to the "pulses" # DMA buffer, instead of being executed immediately. - for i in range(100): + for i in range(50): self.ttl0.pulse(100*ns) delay(100*ns) From a486756890dd9f60ab43a0cf6b7be63859d320a2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Feb 2019 20:12:33 +0800 Subject: [PATCH 1660/2457] nix: remove unnecessary fetchsvn --- nix/pkgs/artiq.nix | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nix/pkgs/artiq.nix b/nix/pkgs/artiq.nix index 4b694f5f3..383e3e755 100644 --- a/nix/pkgs/artiq.nix +++ b/nix/pkgs/artiq.nix @@ -1,4 +1,4 @@ -{ stdenv, git, fetchFromGitHub, fetchsvn, python3Packages, qt5Full, binutils-or1k, llvm-or1k, llvmlite, python3 }: +{ stdenv, git, fetchFromGitHub, python3Packages, qt5Full, binutils-or1k, llvm-or1k, llvmlite, python3 }: let @@ -21,6 +21,7 @@ pythonparser = python3Packages.buildPythonPackage rec { rev = "5b391fe86f43bb9f4f96c5bc0532e2a112db2936"; sha256 = "1gw1fk4y2l6bwq0fg2a9dfc1rvq8cv492dyil96amjdhsxvnx35b"; }; + patches = [ ./python37hack.patch ]; propagatedBuildInputs = with python3Packages; [ regex ]; }; @@ -71,6 +72,7 @@ python3Packages.buildPythonPackage rec { buildInputs = [ git ]; propagatedBuildInputs = with python3Packages; [ binutils-or1k llvm-or1k llvmlite levenshtein pyqtgraph-qt5 aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; checkPhase = "python -m unittest discover -v artiq.test"; + doCheck = false; meta = with stdenv.lib; { description = "A leading-edge control system for quantum information experiments"; homepage = https://m-labs/artiq; From bcda53ee2f6c7b362774502af1d7406e6e92f8d5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Feb 2019 20:14:19 +0800 Subject: [PATCH 1661/2457] nix: revert local mods --- nix/pkgs/artiq.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/nix/pkgs/artiq.nix b/nix/pkgs/artiq.nix index 383e3e755..bad9693a1 100644 --- a/nix/pkgs/artiq.nix +++ b/nix/pkgs/artiq.nix @@ -21,7 +21,6 @@ pythonparser = python3Packages.buildPythonPackage rec { rev = "5b391fe86f43bb9f4f96c5bc0532e2a112db2936"; sha256 = "1gw1fk4y2l6bwq0fg2a9dfc1rvq8cv492dyil96amjdhsxvnx35b"; }; - patches = [ ./python37hack.patch ]; propagatedBuildInputs = with python3Packages; [ regex ]; }; @@ -72,7 +71,6 @@ python3Packages.buildPythonPackage rec { buildInputs = [ git ]; propagatedBuildInputs = with python3Packages; [ binutils-or1k llvm-or1k llvmlite levenshtein pyqtgraph-qt5 aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; checkPhase = "python -m unittest discover -v artiq.test"; - doCheck = false; meta = with stdenv.lib; { description = "A leading-edge control system for quantum information experiments"; homepage = https://m-labs/artiq; From 1cd0f5a552cd02758e88b0335db886142a327c7d Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 15 Feb 2019 17:40:27 +0000 Subject: [PATCH 1662/2457] conda: Bump migen/misoc commits to fix Sayma build --- conda/artiq-dev/meta.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index b7c0b9c90..5817fd27b 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -14,8 +14,8 @@ requirements: run: - python >=3.5.3,<3.6 - setuptools 33.1.1 - - migen 0.8 py35_0+git2d62c0c - - misoc 0.12 py35_0+git714ea689 + - migen 0.8 py35_63+gitafe4405 + - misoc 0.12 py35_11+git8e033c2c - jesd204b 0.10 - microscope - binutils-or1k-linux >=2.27 From 861ad0a62c246a014c5d292ab0735ee6aab73fa9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 17 Feb 2019 14:49:22 +0800 Subject: [PATCH 1663/2457] remove nix scripts (moved to dedicated repository) --- nix/README.rst => doc/nix.rst | 2 +- nix/artiq-board.nix | 60 ------ nix/artiq-dev.nix | 35 --- nix/conda-board.nix | 57 ----- nix/conda-build.nix | 65 ------ nix/default.nix | 18 -- nix/fetch-llvm-clang.nix | 22 -- nix/fetchcargo.nix | 35 --- nix/pkgs/artiq.nix | 81 ------- nix/pkgs/binutils-or1k.nix | 34 --- nix/pkgs/llvm-or1k.nix | 45 ---- nix/pkgs/llvmlite.nix | 25 --- nix/pkgs/openocd.nix | 72 ------- nix/pkgs/python3Packages.nix | 107 ---------- nix/pkgs/rust/binaryBuild.nix | 117 ---------- nix/pkgs/rust/bootstrap.nix | 42 ---- nix/pkgs/rust/default.nix | 88 -------- .../patches/disable-test-inherit-env.patch | 10 - .../rust/patches/net-tcp-disable-tests.patch | 104 --------- .../patches/stdsimd-disable-doctest.patch | 20 -- nix/pkgs/rust/print-hashes.sh | 38 ---- nix/pkgs/rust/rust-src.nix | 11 - nix/pkgs/rust/rustc.nix | 199 ------------------ nix/release.nix | 46 ---- nix/shell-dev.nix | 6 - nix/shell.nix | 7 - 26 files changed, 1 insertion(+), 1345 deletions(-) rename nix/README.rst => doc/nix.rst (88%) delete mode 100644 nix/artiq-board.nix delete mode 100644 nix/artiq-dev.nix delete mode 100644 nix/conda-board.nix delete mode 100644 nix/conda-build.nix delete mode 100644 nix/default.nix delete mode 100644 nix/fetch-llvm-clang.nix delete mode 100644 nix/fetchcargo.nix delete mode 100644 nix/pkgs/artiq.nix delete mode 100644 nix/pkgs/binutils-or1k.nix delete mode 100644 nix/pkgs/llvm-or1k.nix delete mode 100644 nix/pkgs/llvmlite.nix delete mode 100644 nix/pkgs/openocd.nix delete mode 100644 nix/pkgs/python3Packages.nix delete mode 100644 nix/pkgs/rust/binaryBuild.nix delete mode 100644 nix/pkgs/rust/bootstrap.nix delete mode 100644 nix/pkgs/rust/default.nix delete mode 100644 nix/pkgs/rust/patches/disable-test-inherit-env.patch delete mode 100644 nix/pkgs/rust/patches/net-tcp-disable-tests.patch delete mode 100644 nix/pkgs/rust/patches/stdsimd-disable-doctest.patch delete mode 100755 nix/pkgs/rust/print-hashes.sh delete mode 100644 nix/pkgs/rust/rust-src.nix delete mode 100644 nix/pkgs/rust/rustc.nix delete mode 100644 nix/release.nix delete mode 100644 nix/shell-dev.nix delete mode 100644 nix/shell.nix diff --git a/nix/README.rst b/doc/nix.rst similarity index 88% rename from nix/README.rst rename to doc/nix.rst index 4aea10cc2..73f25123d 100644 --- a/nix/README.rst +++ b/doc/nix.rst @@ -33,7 +33,7 @@ This sets up an environment suitable for using ARTIQ, including the ARTIQ-Python ARTIQ development environment with Nix ====================================== -Run ``nix-shell shell-dev.nix`` to obtain an environment containing Migen, MiSoC, Microscope, jesd204b, Clang, Rust, Cargo, and OpenOCD in addition to the user environment above. +Run ``nix-shell -I artiqSrc=path_to_artiq_sources shell-dev.nix`` to obtain an environment containing Migen, MiSoC, Microscope, jesd204b, Clang, Rust, Cargo, and OpenOCD in addition to the user environment above. This creates a FHS chroot environment in order to simplify the installation and patching of Xilinx Vivado (it needs to be installed manually e.g. in your home folder). diff --git a/nix/artiq-board.nix b/nix/artiq-board.nix deleted file mode 100644 index 857cf65dc..000000000 --- a/nix/artiq-board.nix +++ /dev/null @@ -1,60 +0,0 @@ -# Install Vivado in /opt and add to /etc/nixos/configuration.nix: -# nix.sandboxPaths = ["/opt"]; - -{ pkgs ? import {}}: -{ target, variant, buildCommand ? "python -m artiq.gateware.targets.${target} -V ${variant}" }: - -let - artiqPkgs = import ./default.nix { inherit pkgs; }; - fetchcargo = import ./fetchcargo.nix { - inherit (pkgs) stdenv cacert git cargo cargo-vendor; - }; - cargoDeps = fetchcargo rec { - name = "artiq-firmware-cargo-deps"; - src = ../artiq/firmware; - sha256 = "1xzjn9i4rkd9124v2gbdplsgsvp1hlx7czdgc58n316vsnrkbr86"; - }; - - cargoVendored = pkgs.stdenv.mkDerivation { - name = "artiq-firmware-cargo-vendored"; - src = cargoDeps; - phases = [ "unpackPhase" "installPhase" ]; - installPhase = - '' - mkdir -p $out/registry - cat << EOF > $out/config - [source.crates-io] - registry = "https://github.com/rust-lang/crates.io-index" - replace-with = "vendored-sources" - - [source."https://github.com/m-labs/libfringe"] - git = "https://github.com/m-labs/libfringe" - rev = "b8a6d8f" - replace-with = "vendored-sources" - - [source.vendored-sources] - directory = "$out/registry" - EOF - cp -R * $out/registry - ''; - }; - - buildenv = import ./artiq-dev.nix { inherit pkgs; }; - -in pkgs.stdenv.mkDerivation { - name = "artiq-board-${target}-${variant}"; - src = null; - phases = [ "buildPhase" "installPhase" ]; - buildPhase = - '' - ${buildenv}/bin/artiq-dev -c "CARGO_HOME=${cargoVendored} ${buildCommand}" - ''; - installPhase = - '' - TARGET_DIR=$out/${pkgs.python3Packages.python.sitePackages}/artiq/binaries/${target}-${variant} - mkdir -p $TARGET_DIR - cp artiq_${target}/${variant}/gateware/top.bit $TARGET_DIR - cp artiq_${target}/${variant}/software/bootloader/bootloader.bin $TARGET_DIR - cp artiq_${target}/${variant}/software/runtime/runtime.{elf,fbi} $TARGET_DIR - ''; -} diff --git a/nix/artiq-dev.nix b/nix/artiq-dev.nix deleted file mode 100644 index 33e888d81..000000000 --- a/nix/artiq-dev.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ pkgs ? import {}}: - -let - artiqpkgs = import ./default.nix { inherit pkgs; }; -in - pkgs.buildFHSUserEnv { - name = "artiq-dev"; - targetPkgs = pkgs: ( - with pkgs; [ - ncurses5 - gnumake - zlib - libuuid - xorg.libSM - xorg.libICE - xorg.libXrender - xorg.libX11 - xorg.libXext - xorg.libXtst - xorg.libXi - (python3.withPackages(ps: with ps; [ jinja2 numpy artiqpkgs.migen artiqpkgs.microscope artiqpkgs.misoc artiqpkgs.jesd204b artiqpkgs.artiq ])) - git - cargo - ] ++ - (with artiqpkgs; [ - rustc - binutils-or1k - llvm-or1k - openocd - ]) - ); - profile = '' - export TARGET_AR=${artiqpkgs.binutils-or1k}/bin/or1k-linux-ar - ''; - } diff --git a/nix/conda-board.nix b/nix/conda-board.nix deleted file mode 100644 index 08c9fc18b..000000000 --- a/nix/conda-board.nix +++ /dev/null @@ -1,57 +0,0 @@ -{ pkgs ? import {}}: -{ artiqSrc, boardBinaries, target, variant }: - -with pkgs; - -let - fakeCondaSource = runCommand "fake-conda-source-${target}-${variant}" { } - '' - cp --no-preserve=mode,ownership -R ${artiqSrc} $out - mkdir $out/fake-conda; - - cat << EOF > $out/fake-conda/meta.yaml - package: - name: artiq-board-${target}-${variant} - version: {{ environ["GIT_DESCRIBE_TAG"] }} - - source: - git_url: .. - - build: - noarch: python - number: {{ environ["GIT_DESCRIBE_NUMBER"] }} - string: {{ environ["GIT_DESCRIBE_NUMBER"] }}+git{{ environ["GIT_FULL_HASH"][:8] }} - ignore_prefix_files: True - - outputs: - - name: artiq-board-${target}-${variant} - noarch: python - files: - - site-packages - requirements: - run: - - artiq - ignore_prefix_files: True - - about: - home: https://m-labs.hk/artiq - license: LGPL - summary: 'Bitstream, BIOS and firmware for the ${target}-${variant} board variant' - EOF - - cat << EOF > $out/fake-conda/build.sh - #!/bin/bash - set -e - SOC_PREFIX=\$PREFIX/site-packages/artiq/binaries/${target}-${variant} - mkdir -p \$SOC_PREFIX - cp ${boardBinaries}/${pkgs.python3Packages.python.sitePackages}/artiq/binaries/${target}-${variant}/* \$SOC_PREFIX - EOF - chmod 755 $out/fake-conda/build.sh - ''; - conda-board = import ./conda-build.nix { inherit pkgs; } { - name = "conda-artiq-board-${target}-${variant}"; - src = fakeCondaSource; - recipe = "fake-conda"; - }; -in - conda-board diff --git a/nix/conda-build.nix b/nix/conda-build.nix deleted file mode 100644 index 22dd9eb6d..000000000 --- a/nix/conda-build.nix +++ /dev/null @@ -1,65 +0,0 @@ -# We need to pass the whole source to conda for the git variables to work. -# recipe must be a string pointing to a path within the source. - -{ pkgs ? import {}}: -{ name, src, recipe }: - -with pkgs; - -let - condaDeps = [ stdenv.cc xorg.libSM xorg.libICE xorg.libXrender libselinux ]; - # Use the full Anaconda distribution, which already contains conda-build and its many dependencies, - # so we don't have to manually deal with them. - condaInstaller = fetchurl { - url = "https://repo.anaconda.com/archive/Anaconda3-2018.12-Linux-x86_64.sh"; - sha256 = "006fgyz75ihd00qzbr1cny97xf1mwnzibbqyhskghraqgs2x068h"; - }; - condaSrcChmod = runCommand "conda-src-chmod" { } "mkdir $out; cp ${condaInstaller} $out/conda-installer.sh; chmod +x $out/conda-installer.sh"; - condaInstallerEnv = buildFHSUserEnv { - name = "conda-installer-env"; - targetPkgs = pkgs: ([ condaSrcChmod ] ++ condaDeps); - }; - - # Git depends on libiconv - condaIconv = fetchurl { - url = "https://anaconda.org/conda-forge/libiconv/1.15/download/linux-64/libiconv-1.15-h14c3975_1004.tar.bz2"; - sha256 = "167j8jpr6mnyrzwp18dr52xr3xjsf39q452ag247ijlmp092v8ns"; - }; - condaGit = fetchurl { - url = "https://anaconda.org/conda-forge/git/2.20.1/download/linux-64/git-2.20.1-pl526hc122a05_1001.tar.bz2"; - sha256 = "03s01xq2jj7zbx7jfzz6agy40jj7xkq6dwar3lw1z5j2rbmh8h0h"; - }; - condaInstalled = runCommand "conda-installed" { } - '' - ${condaInstallerEnv}/bin/conda-installer-env -c "${condaSrcChmod}/conda-installer.sh -p $out -b" - ${condaInstallerEnv}/bin/conda-installer-env -c "$out/bin/conda install ${condaIconv}" - ${condaInstallerEnv}/bin/conda-installer-env -c "$out/bin/conda install ${condaGit}" - ''; - condaBuilderEnv = buildFHSUserEnv { - name = "conda-builder-env"; - targetPkgs = pkgs: [ condaInstalled ] ++ condaDeps; - }; - -in stdenv.mkDerivation { - inherit name src; - buildInputs = [ condaBuilderEnv ]; - buildCommand = - '' - HOME=`pwd` - # Build requirements make conda-build fail when disconnected from the internet, e.g. in the nix sandbox. - # Just ignore them - python and setuptools are installed anyway. - cat << EOF > clobber.yaml - requirements: - build: - - build: - script_env: - - PYTHON - EOF - mkdir $out - ${condaBuilderEnv}/bin/conda-builder-env -c "PYTHON=python conda build --clobber-file clobber.yaml --no-anaconda-upload --no-test --output-folder $out $src/${recipe}" - - mkdir -p $out/nix-support - echo file conda $out/noarch/*.tar.bz2 >> $out/nix-support/hydra-build-products - ''; -} diff --git a/nix/default.nix b/nix/default.nix deleted file mode 100644 index 5b27187aa..000000000 --- a/nix/default.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ pkgs ? import {}}: -with pkgs; -let - # this code was copied from nipxkgs rev. ffafe9 (nixcloud team) and slightly modified - rust = callPackage ./pkgs/rust - (stdenv.lib.optionalAttrs (stdenv.cc.isGNU && stdenv.hostPlatform.isi686) { - stdenv = overrideCC stdenv gcc6; # with gcc-7: undefined reference to `__divmoddi4' - }); - llvm-src = callPackage ./fetch-llvm-clang.nix {}; -in rec { - inherit (rust) rustc; - inherit (callPackage ./pkgs/python3Packages.nix {}) migen microscope misoc jesd204b; - binutils-or1k = callPackage ./pkgs/binutils-or1k.nix {}; - llvm-or1k = callPackage ./pkgs/llvm-or1k.nix { inherit llvm-src; }; - llvmlite = callPackage ./pkgs/llvmlite.nix { inherit llvm-or1k; }; - artiq = callPackage ./pkgs/artiq.nix { inherit binutils-or1k; inherit llvm-or1k; inherit llvmlite; }; - openocd = callPackage ./pkgs/openocd.nix {}; -} diff --git a/nix/fetch-llvm-clang.nix b/nix/fetch-llvm-clang.nix deleted file mode 100644 index 686aef9a6..000000000 --- a/nix/fetch-llvm-clang.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ runCommand, fetchFromGitHub, git }: - -let -llvm-src = fetchFromGitHub { - rev = "527aa86b578da5dfb9cf4510b71f0f46a11249f7"; - owner = "m-labs"; - repo = "llvm-or1k"; - sha256 = "0lmcg9xj66pf4mb6racipw67vm8kwm84dl861hyqnywd61kvhrwa"; -}; -clang-src = fetchFromGitHub { - rev = "9e996136d52ed506ed8f57ef8b13b0f0f735e6a3"; - owner = "m-labs"; - repo = "clang-or1k"; - sha256 = "0w5f450i76y162aswi2c7jip8x3arzljaxhbqp8qfdffm0rdbjp4"; -}; -in -runCommand "llvm_or1k_src" {}'' -mkdir -p $out -mkdir -p $out/tools/clang -cp -r ${llvm-src}/* $out/ -cp -r ${clang-src}/* $out/tools/clang -'' diff --git a/nix/fetchcargo.nix b/nix/fetchcargo.nix deleted file mode 100644 index 6195a7238..000000000 --- a/nix/fetchcargo.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ stdenv, cacert, git, cargo, cargo-vendor }: -{ name, src, sha256 }: -stdenv.mkDerivation { - name = "${name}-vendor"; - nativeBuildInputs = [ cacert git cargo cargo-vendor ]; - inherit src; - - phases = "unpackPhase patchPhase installPhase"; - - installPhase = '' - if [[ ! -f Cargo.lock ]]; then - echo - echo "ERROR: The Cargo.lock file doesn't exist" - echo - echo "Cargo.lock is needed to make sure that cargoSha256 doesn't change" - echo "when the registry is updated." - echo - - exit 1 - fi - - export CARGO_HOME=$(mktemp -d cargo-home.XXX) - - cargo vendor - - cp -ar vendor $out - ''; - - outputHashAlgo = "sha256"; - outputHashMode = "recursive"; - outputHash = sha256; - - impureEnvVars = stdenv.lib.fetchers.proxyImpureEnvVars; - preferLocalBuild = true; -} diff --git a/nix/pkgs/artiq.nix b/nix/pkgs/artiq.nix deleted file mode 100644 index bad9693a1..000000000 --- a/nix/pkgs/artiq.nix +++ /dev/null @@ -1,81 +0,0 @@ -{ stdenv, git, fetchFromGitHub, python3Packages, qt5Full, binutils-or1k, llvm-or1k, llvmlite, python3 }: - -let - -levenshtein = python3Packages.buildPythonPackage rec { - name = "levenshtein"; - src = fetchFromGitHub { - owner = "ztane"; - repo = "python-Levenshtein"; - rev = "854e61a05bb8b750e990add96df412cd5448b75e"; - sha256 = "1yf21kg1g2ivm5a4dx1jra9k0c33np54d0hk5ymnfyc4f6pg386q"; - }; - doCheck = false; -}; - -pythonparser = python3Packages.buildPythonPackage rec { - name = "pythonparser"; - src = fetchFromGitHub { - owner = "m-labs"; - repo = "pythonparser"; - rev = "5b391fe86f43bb9f4f96c5bc0532e2a112db2936"; - sha256 = "1gw1fk4y2l6bwq0fg2a9dfc1rvq8cv492dyil96amjdhsxvnx35b"; - }; - propagatedBuildInputs = with python3Packages; [ regex ]; -}; - -asyncserial = python3Packages.buildPythonPackage rec { - name = "asyncserial"; - src = fetchFromGitHub { - owner = "m-labs"; - repo = "asyncserial"; - rev = "d95bc1d6c791b0e9785935d2f62f628eb5cdf98d"; - sha256 = "0yzkka9jk3612v8gx748x6ziwykq5lr7zmr9wzkcls0v2yilqx9k"; - }; - propagatedBuildInputs = with python3Packages; [ pyserial ]; - doCheck = false; -}; - -quamash = python3Packages.buildPythonPackage rec { - name = "quamash"; - src = fetchFromGitHub { - owner = "harvimt"; - repo = "quamash"; - rev = "e513b30f137415c5e098602fa383e45debab85e7"; - sha256 = "117rp9r4lz0kfz4dmmpa35hp6nhbh6b4xq0jmgvqm68g9hwdxmqa"; - }; - propagatedBuildInputs = with python3Packages; [ pyqt5 ]; - doCheck = false; -}; - -pyqtgraph-qt5 = python3Packages.buildPythonPackage rec { - name = "pyqtgraph_qt5-${version}"; - version = "0.10.0"; - doCheck = false; - src = fetchFromGitHub { - owner = "pyqtgraph"; - repo = "pyqtgraph"; - rev = "1426e334e1d20542400d77c72c132b04c6d17ddb"; - sha256 = "1079haxyr316jf0wpirxdj0ry6j8mr16cqr0dyyrd5cnxwl7zssh"; - }; - propagatedBuildInputs = with python3Packages; [ scipy numpy pyqt5 pyopengl ]; -}; - -in - -python3Packages.buildPythonPackage rec { - name = "artiq"; - src = builtins.filterSource - (path: type: type != "directory" || builtins.baseNameOf path != ".nix") - ./../..; - buildInputs = [ git ]; - propagatedBuildInputs = with python3Packages; [ binutils-or1k llvm-or1k llvmlite levenshtein pyqtgraph-qt5 aiohttp pygit2 pythonparser numpy dateutil quamash scipy prettytable pyserial asyncserial h5py cython regex qt5Full pyqt5 ]; - checkPhase = "python -m unittest discover -v artiq.test"; - meta = with stdenv.lib; { - description = "A leading-edge control system for quantum information experiments"; - homepage = https://m-labs/artiq; - license = licenses.lgpl3; - #maintainers = [ maintainers.sb0 ]; - platforms = [ "x86_64-linux" ]; - }; -} diff --git a/nix/pkgs/binutils-or1k.nix b/nix/pkgs/binutils-or1k.nix deleted file mode 100644 index f9fa99ad0..000000000 --- a/nix/pkgs/binutils-or1k.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ stdenv, buildPackages -, fetchurl, zlib -}: - -stdenv.mkDerivation rec { - basename = "binutils"; - platform = "or1k"; - version = "2.30"; - name = "${basename}_${platform}-${version}"; - src = fetchurl { - url = "https://ftp.gnu.org/gnu/binutils/binutils-${version}.tar.bz2"; - sha256 = "028cklfqaab24glva1ks2aqa1zxa6w6xmc8q34zs1sb7h22dxspg"; - }; - configureFlags = - [ "--enable-shared" "--enable-deterministic-archives" "--target=or1k-linux"]; - outputs = [ "out" "info" "man" ]; - depsBuildBuild = [ buildPackages.stdenv.cc ]; - buildInputs = [ zlib ]; - enableParallelBuilding = true; - meta = { - description = "Tools for manipulating binaries (linker, assembler, etc.)"; - longDescription = '' - The GNU Binutils are a collection of binary tools. The main - ones are `ld' (the GNU linker) and `as' (the GNU assembler). - They also include the BFD (Binary File Descriptor) library, - `gprof', `nm', `strip', etc. - ''; - homepage = http://www.gnu.org/software/binutils/; - license = stdenv.lib.licenses.gpl3Plus; - /* Give binutils a lower priority than gcc-wrapper to prevent a - collision due to the ld/as wrappers/symlinks in the latter. */ - priority = "10"; - }; -} diff --git a/nix/pkgs/llvm-or1k.nix b/nix/pkgs/llvm-or1k.nix deleted file mode 100644 index 8b4112499..000000000 --- a/nix/pkgs/llvm-or1k.nix +++ /dev/null @@ -1,45 +0,0 @@ -{ stdenv -, git -, llvm-src -, perl, groff, cmake, libxml2, python, libffi, valgrind -, ... -}: - -stdenv.mkDerivation rec { - name = "llvm_or1k"; - src = llvm-src; - - buildInputs = [ perl groff cmake libxml2 python libffi ] ++ stdenv.lib.optional stdenv.isLinux valgrind; - - preBuild = '' - NIX_BUILD_CORES=4 - makeFlagsArray=(-j''$NIX_BUILD_CORES) - mkdir -p $out/ - ''; - - cmakeFlags = with stdenv; [ - "-DCMAKE_BUILD_TYPE=Release" - "-DLLVM_BUILD_LLVM_DYLIB=ON" - "-DLLVM_LINK_LLVM_DYLIB=ON" - "-DLLVM_TARGETS_TO_BUILD=X86" - "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=OR1K" - "-DLLVM_ENABLE_ASSERTIONS=OFF" - "-DLLVM_INSTALL_UTILS=ON" - "-DLLVM_INCLUDE_TESTS=OFF" - "-DLLVM_INCLUDE_DOCS=OFF" - "-DLLVM_INCLUDE_EXAMPLES=OFF" - "-DCLANG_ENABLE_ARCMT=OFF" - "-DCLANG_ENABLE_STATIC_ANALYZER=OFF" - "-DCLANG_INCLUDE_TESTS=OFF" - "-DCLANG_INCLUDE_DOCS=OFF" - ]; - - enableParallelBuilding = true; - meta = { - description = "Collection of modular and reusable compiler and toolchain technologies"; - homepage = http://llvm.org/; - license = stdenv.lib.licenses.bsd3; - #maintainers = with stdenv.lib.maintainers; [ sb0 ]; - platforms = stdenv.lib.platforms.all; - }; -} diff --git a/nix/pkgs/llvmlite.nix b/nix/pkgs/llvmlite.nix deleted file mode 100644 index 9c7ef6e4b..000000000 --- a/nix/pkgs/llvmlite.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ stdenv, fetchFromGitHub, llvm-or1k, makeWrapper, python3, ncurses, zlib, python3Packages }: -stdenv.mkDerivation rec { - name = "llvmlite"; - src = fetchFromGitHub { - rev = "1d167be4eec5d6c32498952be8b3ac17dd30df8d"; - owner = "m-labs"; - repo = "llvmlite"; - sha256 = "0ranbjhcz2v3crmdbw1sxdwqwqbbm7dd53d8qaqb69ma9fkxy8x7"; - }; - - buildInputs = [ makeWrapper python3 ncurses zlib llvm-or1k python3Packages.setuptools ]; - - installPhase = '' - LLVM_CONFIG=${llvm-or1k}/bin/llvm-config - python3 setup.py install --prefix=$out - ''; - - meta = with stdenv.lib; { - description = "A lightweight LLVM python binding for writing JIT compilers"; - homepage = "http://llvmlite.pydata.org/"; - #maintainers = with maintainers; [ sb0 ]; - license = licenses.bsd2; - platforms = platforms.unix; - }; -} diff --git a/nix/pkgs/openocd.nix b/nix/pkgs/openocd.nix deleted file mode 100644 index df6588ab9..000000000 --- a/nix/pkgs/openocd.nix +++ /dev/null @@ -1,72 +0,0 @@ -{ stdenv, fetchFromGitHub, autoreconfHook, libftdi, libusb1, pkgconfig, hidapi }: - -stdenv.mkDerivation rec { - name = "openocd-mlabs-${version}"; - version = "0.10.0"; - - src = fetchFromGitHub { - owner = "m-labs"; - repo = "openocd"; - fetchSubmodules = true; - rev = "c383a57adcff332b2c5cf8d55a84626285b42c2c"; - sha256 = "0xlj9cs72acx3zqagvr7f1c0v6lnqhl8fgrlhgmhmvk5n9knk492"; - }; - bscan_spi_bitstreams = fetchFromGitHub { - owner = "quartiq"; - repo = "bscan_spi_bitstreams"; - rev = "a628956da7dc794e6e3c95b31ff9ce3af58bc763"; - sha256 = "1cydbym3wv9jwxh6lw9im1mjzr7w8rzzx95bxkjschmzjq4h13vk"; - }; - - nativeBuildInputs = [ pkgconfig ]; - buildInputs = [ autoreconfHook libftdi libusb1 hidapi ]; - - configureFlags = [ - "--enable-jtag_vpi" - "--enable-usb_blaster_libftdi" - "--enable-amtjtagaccel" - "--enable-gw16012" - "--enable-presto_libftdi" - "--enable-openjtag_ftdi" - "--enable-oocd_trace" - "--enable-buspirate" - "--enable-sysfsgpio" - "--enable-remote-bitbang" - ]; - - NIX_CFLAGS_COMPILE = [ - "-Wno-implicit-fallthrough" - "-Wno-format-truncation" - "-Wno-format-overflow" - ]; - - postInstall = '' - mkdir -p "$out/etc/udev/rules.d" - rules="$out/share/openocd/contrib/60-openocd.rules" - if [ ! -f "$rules" ]; then - echo "$rules is missing, must update the Nix file." - exit 1 - fi - ln -s "$rules" "$out/etc/udev/rules.d/" - - mkdir -p "$out/share/bscan-spi-bitstreams" - cp ${bscan_spi_bitstreams}/*.bit "$out/share/bscan-spi-bitstreams" - ''; - - meta = with stdenv.lib; { - description = "Free and Open On-Chip Debugging, In-System Programming and Boundary-Scan Testing"; - longDescription = '' - OpenOCD provides on-chip programming and debugging support with a layered - architecture of JTAG interface and TAP support, debug target support - (e.g. ARM, MIPS), and flash chip drivers (e.g. CFI, NAND, etc.). Several - network interfaces are available for interactiving with OpenOCD: HTTP, - telnet, TCL, and GDB. The GDB server enables OpenOCD to function as a - "remote target" for source-level debugging of embedded systems using the - GNU GDB program. - ''; - homepage = http://openocd.sourceforge.net/; - license = licenses.gpl2Plus; - #maintainers = with maintainers; [ sb0 ]; - platforms = platforms.linux; - }; -} diff --git a/nix/pkgs/python3Packages.nix b/nix/pkgs/python3Packages.nix deleted file mode 100644 index 898bd97a9..000000000 --- a/nix/pkgs/python3Packages.nix +++ /dev/null @@ -1,107 +0,0 @@ -{ pkgs, stdenv, fetchFromGitHub, python, python3Packages }: - -rec { - asyncserial = python3Packages.buildPythonPackage rec { - name = "asyncserial"; - - src = fetchFromGitHub { - owner = "m-labs"; - repo = "asyncserial"; - rev = "d95bc1d6c791b0e9785935d2f62f628eb5cdf98d"; - sha256 = "0yzkka9jk3612v8gx748x6ziwykq5lr7zmr9wzkcls0v2yilqx9k"; - fetchSubmodules = true; - }; - - propagatedBuildInputs = with python3Packages; [ pyserial ] ++ (with pkgs; [ ]); - - meta = with stdenv.lib; { - description = "asyncio support for pyserial"; - homepage = "https://m-labs.hk"; - license = licenses.bsd2; - platforms = platforms.unix; - }; - }; - misoc = python3Packages.buildPythonPackage rec { - name = "misoc"; - - src = fetchFromGitHub { - owner = "m-labs"; - repo = "misoc"; - rev = "8e033c2cb77f78c95d2b2e08125324891d07fa34"; - sha256 = "0pv1akhvr85iswqmhzcqh9gfnyha11k68qmhqizma8fdccvvzm4y"; - fetchSubmodules = true; - }; - - # TODO: fix misoc bitrot and re-enable tests - doCheck = false; - - propagatedBuildInputs = with python3Packages; [ pyserial jinja2 numpy asyncserial migen ]; - - meta = with stdenv.lib; { - description = "A high performance and small footprint system-on-chip based on Migen"; - homepage = "https://m-labs.hk/migen"; - license = licenses.bsd2; - platforms = platforms.unix; - }; - }; - migen = python3Packages.buildPythonPackage rec { - name = "migen"; - - src = fetchFromGitHub { - owner = "m-labs"; - repo = "migen"; - rev = "afe4405becdbc76539f0195c319367187012b05e"; - sha256 = "1f288a7ll1d1gjmml716wsjf1jyq9y903i2312bxb8pwrg7fwgvz"; - }; - - # TODO: fix migen platform issues and re-enable tests - doCheck = false; - - propagatedBuildInputs = with python3Packages; [ colorama sphinx sphinx_rtd_theme ] ++ (with pkgs; [ verilator ]); - - meta = with stdenv.lib; { - description = "A Python toolbox for building complex digital hardware"; - homepage = "https://m-labs.hk/migen"; - license = licenses.bsd2; - platforms = platforms.unix; - }; - }; - microscope = python3Packages.buildPythonPackage rec { - name = "microscope"; - - src = fetchFromGitHub { - owner = "m-labs"; - repo = "microscope"; - rev = "02cffc360ec5a234c589de6cb9616b057ed22253"; - sha256 = "09yvgk16xfv5r5cf55vcg0f14wam42w53r4snlalcyw5gkm0rlhq"; - }; - - propagatedBuildInputs = with python3Packages; [ pyserial prettytable msgpack-python migen ]; - - meta = with stdenv.lib; { - description = "Finding the bacteria in rotting FPGA designs"; - homepage = "https://m-labs.hk/migen"; - license = licenses.bsd2; - platforms = platforms.unix; - }; - }; - jesd204b = python3Packages.buildPythonPackage rec { - name = "jesd204b"; - - src = fetchFromGitHub { - owner = "m-labs"; - repo = "jesd204b"; - rev = "2fd6391c0a9197580d60f7d8a146191dc7337b03"; - sha256 = "1lhw8f0dp42xx4g6d7hyhqhrnd6i5ll4a1wcg265rqz3600i4009"; - }; - - propagatedBuildInputs = with python3Packages; [ migen misoc ]; - - meta = with stdenv.lib; { - description = "JESD204B core for Migen/MiSoC"; - homepage = "https://m-labs.hk/migen"; - license = licenses.bsd2; - platforms = platforms.unix; - }; - }; -} diff --git a/nix/pkgs/rust/binaryBuild.nix b/nix/pkgs/rust/binaryBuild.nix deleted file mode 100644 index 872c4bd03..000000000 --- a/nix/pkgs/rust/binaryBuild.nix +++ /dev/null @@ -1,117 +0,0 @@ -{ stdenv, makeWrapper, bash, buildRustPackage, curl, darwin -, version -, src -, platform -, versionType -}: - -let - inherit (stdenv.lib) optionalString; - inherit (darwin.apple_sdk.frameworks) Security; - - bootstrapping = versionType == "bootstrap"; - - installComponents - = "rustc,rust-std-${platform}" - + (optionalString bootstrapping ",cargo") - ; -in - -rec { - inherit buildRustPackage; - - rustc = stdenv.mkDerivation rec { - name = "rustc-${versionType}-${version}"; - - inherit version; - inherit src; - - meta = with stdenv.lib; { - homepage = http://www.rust-lang.org/; - description = "A safe, concurrent, practical language"; - #maintainers = with maintainers; [ sb0 ]; - license = [ licenses.mit licenses.asl20 ]; - }; - - buildInputs = [ bash ] ++ stdenv.lib.optional stdenv.isDarwin Security; - - postPatch = '' - patchShebangs . - ''; - - installPhase = '' - ./install.sh --prefix=$out \ - --components=${installComponents} - - ${optionalString (stdenv.isLinux && bootstrapping) '' - patchelf \ - --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) \ - "$out/bin/rustc" - patchelf \ - --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) \ - "$out/bin/rustdoc" - patchelf \ - --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) \ - "$out/bin/cargo" - ''} - - ${optionalString (stdenv.isDarwin && bootstrapping) '' - install_name_tool -change /usr/lib/libresolv.9.dylib '${darwin.libresolv}/lib/libresolv.9.dylib' "$out/bin/rustc" - install_name_tool -change /usr/lib/libresolv.9.dylib '${darwin.libresolv}/lib/libresolv.9.dylib' "$out/bin/rustdoc" - install_name_tool -change /usr/lib/libiconv.2.dylib '${darwin.libiconv}/lib/libiconv.2.dylib' "$out/bin/cargo" - install_name_tool -change /usr/lib/libresolv.9.dylib '${darwin.libresolv}/lib/libresolv.9.dylib' "$out/bin/cargo" - install_name_tool -change /usr/lib/libcurl.4.dylib '${stdenv.lib.getLib curl}/lib/libcurl.4.dylib' "$out/bin/cargo" - for f in $out/lib/lib*.dylib; do - install_name_tool -change /usr/lib/libresolv.9.dylib '${darwin.libresolv}/lib/libresolv.9.dylib' "$f" - done - ''} - - # Do NOT, I repeat, DO NOT use `wrapProgram` on $out/bin/rustc - # (or similar) here. It causes strange effects where rustc loads - # the wrong libraries in a bootstrap-build causing failures that - # are very hard to track down. For details, see - # https://github.com/rust-lang/rust/issues/34722#issuecomment-232164943 - ''; - }; - - cargo = stdenv.mkDerivation rec { - name = "cargo-${versionType}-${version}"; - - inherit version; - inherit src; - - meta = with stdenv.lib; { - homepage = http://www.rust-lang.org/; - description = "A safe, concurrent, practical language"; - #maintainers = with maintainers; [ sb0 ]; - license = [ licenses.mit licenses.asl20 ]; - }; - - buildInputs = [ makeWrapper bash ] ++ stdenv.lib.optional stdenv.isDarwin Security; - - postPatch = '' - patchShebangs . - ''; - - installPhase = '' - patchShebangs ./install.sh - ./install.sh --prefix=$out \ - --components=cargo - - ${optionalString (stdenv.isLinux && bootstrapping) '' - patchelf \ - --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker) \ - "$out/bin/cargo" - ''} - - ${optionalString (stdenv.isDarwin && bootstrapping) '' - install_name_tool -change /usr/lib/libiconv.2.dylib '${darwin.libiconv}/lib/libiconv.2.dylib' "$out/bin/cargo" - install_name_tool -change /usr/lib/libresolv.9.dylib '${darwin.libresolv}/lib/libresolv.9.dylib' "$out/bin/cargo" - install_name_tool -change /usr/lib/libcurl.4.dylib '${stdenv.lib.getLib curl}/lib/libcurl.4.dylib' "$out/bin/cargo" - ''} - - wrapProgram "$out/bin/cargo" \ - --suffix PATH : "${rustc}/bin" - ''; - }; -} diff --git a/nix/pkgs/rust/bootstrap.nix b/nix/pkgs/rust/bootstrap.nix deleted file mode 100644 index 55348c579..000000000 --- a/nix/pkgs/rust/bootstrap.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ stdenv, fetchurl, callPackage }: - -let - # Note: the version MUST be one version prior to the version we're - # building - version = "1.28.0"; - - # fetch hashes by running `print-hashes.sh 1.24.1` - hashes = { - i686-unknown-linux-gnu = "de7cdb4e665e897ea9b10bf6fd545f900683296456d6a11d8510397bb330455f"; - x86_64-unknown-linux-gnu = "2a1390340db1d24a9498036884e6b2748e9b4b057fc5219694e298bdaa37b810"; - armv7-unknown-linux-gnueabihf = "346558d14050853b87049e5e1fbfae0bf0360a2f7c57433c6985b1a879c349a2"; - aarch64-unknown-linux-gnu = "9b6fbcee73070332c811c0ddff399fa31965bec62ef258656c0c90354f6231c1"; - i686-apple-darwin = "752e2c9182e057c4a54152d1e0b3949482c225d02bb69d9d9a4127dc2a65fb68"; - x86_64-apple-darwin = "5d7a70ed4701fe9410041c1eea025c95cad97e5b3d8acc46426f9ac4f9f02393"; - }; - - platform = - if stdenv.hostPlatform.system == "i686-linux" - then "i686-unknown-linux-gnu" - else if stdenv.hostPlatform.system == "x86_64-linux" - then "x86_64-unknown-linux-gnu" - else if stdenv.hostPlatform.system == "armv7l-linux" - then "armv7-unknown-linux-gnueabihf" - else if stdenv.hostPlatform.system == "aarch64-linux" - then "aarch64-unknown-linux-gnu" - else if stdenv.hostPlatform.system == "i686-darwin" - then "i686-apple-darwin" - else if stdenv.hostPlatform.system == "x86_64-darwin" - then "x86_64-apple-darwin" - else throw "missing bootstrap url for platform ${stdenv.hostPlatform.system}"; - - src = fetchurl { - url = "https://static.rust-lang.org/dist/rust-${version}-${platform}.tar.gz"; - sha256 = hashes."${platform}"; - }; - -in callPackage ./binaryBuild.nix - { inherit version src platform; - buildRustPackage = null; - versionType = "bootstrap"; - } diff --git a/nix/pkgs/rust/default.nix b/nix/pkgs/rust/default.nix deleted file mode 100644 index 3971c6f57..000000000 --- a/nix/pkgs/rust/default.nix +++ /dev/null @@ -1,88 +0,0 @@ -{ stdenv, callPackage, recurseIntoAttrs, makeRustPlatform, llvm, fetchurl -, targets ? [] -, targetToolchains ? [] -, targetPatches ? [] -, fetchFromGitHub -}: - -let - rustPlatform = recurseIntoAttrs (makeRustPlatform (callPackage ./bootstrap.nix {})); - version = "1.28.0"; - src = fetchFromGitHub { - owner = "m-labs"; - repo = "rust"; - sha256 = "03lfps3xvvv7wv1nnwn3n1ji13z099vx8c3fpbzp9rnasrwzp5jy"; - rev = "f305fb024318e96997fbe6e4a105b0cc1052aad4"; # artiq-1.28.0 branch - fetchSubmodules = true; - }; -in rec { - # nixcloud team code - or1k-crates = stdenv.mkDerivation { - name = "or1k-crates"; - inherit src; - phases = [ "unpackPhase" "buildPhase" ]; - buildPhase = '' - destdir=$out - rustc="${rustc_internal}/bin/rustc --out-dir ''${destdir} -L ''${destdir} --target or1k-unknown-none -g -C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s --crate-type rlib" - - mkdir -p ''${destdir} - ''${rustc} --crate-name core src/libcore/lib.rs - ''${rustc} --crate-name compiler_builtins src/libcompiler_builtins/src/lib.rs --cfg 'feature="compiler-builtins"' --cfg 'feature="mem"' - ''${rustc} --crate-name std_unicode src/libstd_unicode/lib.rs - ''${rustc} --crate-name alloc src/liballoc/lib.rs - ''${rustc} --crate-name libc src/liblibc_mini/lib.rs - ''${rustc} --crate-name unwind src/libunwind/lib.rs - ''${rustc} -Cpanic=abort --crate-name panic_abort src/libpanic_abort/lib.rs - ''${rustc} -Cpanic=unwind --crate-name panic_unwind src/libpanic_unwind/lib.rs --cfg llvm_libunwind - ''; - }; - # nixcloud team code - # this is basically a wrapper, which uses rustc_internal and inserts or1k-crates into it - rustc = stdenv.mkDerivation { - name = "rustc"; - src = ./.; - installPhase = '' - mkdir $out - mkdir -p $out/lib/rustlib/or1k-unknown-none/lib/ - cp -r ${or1k-crates}/* $out/lib/rustlib/or1k-unknown-none/lib/ - cp -r ${rustc_internal}/* $out - ''; - meta = with stdenv.lib; { - homepage = https://www.rust-lang.org/; - description = "A safe, concurrent, practical language"; - #maintainers = with maintainers; [ sb0 ]; - license = [ licenses.mit licenses.asl20 ]; - platforms = platforms.linux ++ platforms.darwin; - }; - }; - # nixcloud team code - # originally rustc but now renamed to rustc_internal - rustc_internal = callPackage ./rustc.nix { - inherit stdenv llvm targets targetPatches targetToolchains rustPlatform version src; - - patches = [ - ./patches/net-tcp-disable-tests.patch - - # Re-evaluate if this we need to disable this one - #./patches/stdsimd-disable-doctest.patch - - # Fails on hydra - not locally; the exact reason is unknown. - # Comments in the test suggest that some non-reproducible environment - # variables such $RANDOM can make it fail. - ./patches/disable-test-inherit-env.patch - ]; - - forceBundledLLVM = true; - - #configureFlags = [ "--release-channel=stable" ]; - - # 1. Upstream is not running tests on aarch64: - # see https://github.com/rust-lang/rust/issues/49807#issuecomment-380860567 - # So we do the same. - # 2. Tests run out of memory for i686 - #doCheck = !stdenv.isAarch64 && !stdenv.isi686; - - # Disabled for now; see https://github.com/NixOS/nixpkgs/pull/42348#issuecomment-402115598. - doCheck = false; - }; -} diff --git a/nix/pkgs/rust/patches/disable-test-inherit-env.patch b/nix/pkgs/rust/patches/disable-test-inherit-env.patch deleted file mode 100644 index fcb75ed09..000000000 --- a/nix/pkgs/rust/patches/disable-test-inherit-env.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- rustc-1.26.2-src.org/src/libstd/process.rs 2018-06-01 21:40:11.000000000 +0100 -+++ rustc-1.26.2-src/src/libstd/process.rs 2018-06-08 07:50:23.023828658 +0100 -@@ -1745,6 +1745,7 @@ - } - - #[test] -+ #[ignore] - fn test_inherit_env() { - use env; - diff --git a/nix/pkgs/rust/patches/net-tcp-disable-tests.patch b/nix/pkgs/rust/patches/net-tcp-disable-tests.patch deleted file mode 100644 index 10713b6b7..000000000 --- a/nix/pkgs/rust/patches/net-tcp-disable-tests.patch +++ /dev/null @@ -1,104 +0,0 @@ -diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs -index 0f60b5b3e..9b08415e7 100644 ---- a/src/libstd/net/tcp.rs -+++ b/src/libstd/net/tcp.rs -@@ -962,6 +962,7 @@ mod tests { - } - } - -+ #[cfg_attr(target_os = "macos", ignore)] - #[test] - fn listen_localhost() { - let socket_addr = next_test_ip4(); -@@ -1020,6 +1021,7 @@ mod tests { - }) - } - -+ #[cfg_attr(target_os = "macos", ignore)] - #[test] - fn read_eof() { - each_ip(&mut |addr| { -@@ -1039,6 +1041,7 @@ mod tests { - }) - } - -+ #[cfg_attr(target_os = "macos", ignore)] - #[test] - fn write_close() { - each_ip(&mut |addr| { -@@ -1065,6 +1068,7 @@ mod tests { - }) - } - -+ #[cfg_attr(target_os = "macos", ignore)] - #[test] - fn multiple_connect_serial() { - each_ip(&mut |addr| { -@@ -1087,6 +1091,7 @@ mod tests { - }) - } - -+ #[cfg_attr(target_os = "macos", ignore)] - #[test] - fn multiple_connect_interleaved_greedy_schedule() { - const MAX: usize = 10; -@@ -1123,6 +1128,7 @@ mod tests { - } - - #[test] -+ #[cfg_attr(target_os = "macos", ignore)] - fn multiple_connect_interleaved_lazy_schedule() { - const MAX: usize = 10; - each_ip(&mut |addr| { -@@ -1401,6 +1407,7 @@ mod tests { - } - - #[test] -+ #[cfg_attr(target_os = "macos", ignore)] - fn clone_while_reading() { - each_ip(&mut |addr| { - let accept = t!(TcpListener::bind(&addr)); -@@ -1421,7 +1422,10 @@ mod tests { - - // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code - // no longer has rounding errors. -- #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] -+ #[cfg_attr(any(target_os = "bitrig", -+ target_os = "netbsd", -+ target_os = "openbsd", -+ target_os = "macos"), ignore)] - #[test] - fn timeouts() { - let addr = next_test_ip4(); -@@ -1596,6 +1603,7 @@ mod tests { - drop(listener); - } - -+ #[cfg_attr(target_os = "macos", ignore)] - #[test] - fn nodelay() { - let addr = next_test_ip4(); -@@ -1610,6 +1618,7 @@ mod tests { - assert_eq!(false, t!(stream.nodelay())); - } - -+ #[cfg_attr(target_os = "macos", ignore)] - #[test] - fn ttl() { - let ttl = 100; -@@ -1647,6 +1656,7 @@ mod tests { - } - } - -+ #[cfg_attr(target_os = "macos", ignore)] - #[test] - fn peek() { - each_ip(&mut |addr| { -@@ -1679,6 +1689,7 @@ mod tests { - } - - #[test] -+ #[cfg_attr(any(target_os = "linux", target_os = "macos"), ignore)] - fn connect_timeout_unroutable() { - // this IP is unroutable, so connections should always time out, - // provided the network is reachable to begin with. diff --git a/nix/pkgs/rust/patches/stdsimd-disable-doctest.patch b/nix/pkgs/rust/patches/stdsimd-disable-doctest.patch deleted file mode 100644 index 6ef7fd0f7..000000000 --- a/nix/pkgs/rust/patches/stdsimd-disable-doctest.patch +++ /dev/null @@ -1,20 +0,0 @@ -diff --git a/src/stdsimd/coresimd/x86/mod.rs b/src/stdsimd/coresimd/x86/mod.rs -index 32915c332..7cb54f31e 100644 ---- a/src/stdsimd/coresimd/x86/mod.rs -+++ b/src/stdsimd/coresimd/x86/mod.rs -@@ -279,7 +279,6 @@ types! { - /// - /// # Examples - /// -- /// ``` - /// # #![feature(cfg_target_feature, target_feature, stdsimd)] - /// # #![cfg_attr(not(dox), no_std)] - /// # #[cfg(not(dox))] -@@ -301,7 +300,6 @@ types! { - /// # } - /// # if is_x86_feature_detected!("sse") { unsafe { foo() } } - /// # } -- /// ``` - pub struct __m256(f32, f32, f32, f32, f32, f32, f32, f32); - - /// 256-bit wide set of four `f64` types, x86-specific diff --git a/nix/pkgs/rust/print-hashes.sh b/nix/pkgs/rust/print-hashes.sh deleted file mode 100755 index 7eb00a30a..000000000 --- a/nix/pkgs/rust/print-hashes.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# All rust-related downloads can be found at -# https://static.rust-lang.org/dist/index.html. To find the date on -# which a particular thing was last updated, look for the *-date.txt -# file, e.g. -# https://static.rust-lang.org/dist/channel-rust-beta-date.txt - -PLATFORMS=( - i686-unknown-linux-gnu - x86_64-unknown-linux-gnu - armv7-unknown-linux-gnueabihf - aarch64-unknown-linux-gnu - i686-apple-darwin - x86_64-apple-darwin -) -BASEURL=https://static.rust-lang.org/dist -VERSION=${1:-} -DATE=${2:-} - -if [[ -z $VERSION ]] -then - echo "No version supplied" - exit -1 -fi - -if [[ -n $DATE ]] -then - BASEURL=$BASEURL/$DATE -fi - -for PLATFORM in "${PLATFORMS[@]}" -do - URL="$BASEURL/rust-$VERSION-$PLATFORM.tar.gz.sha256" - SHA256=$(curl -sSfL $URL | cut -d ' ' -f 1) - echo "$PLATFORM = \"$SHA256\";" -done diff --git a/nix/pkgs/rust/rust-src.nix b/nix/pkgs/rust/rust-src.nix deleted file mode 100644 index 1b819a7f6..000000000 --- a/nix/pkgs/rust/rust-src.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ stdenv, rustc }: - -stdenv.mkDerivation { - name = "rust-src"; - src = rustc.src; - phases = [ "unpackPhase" "installPhase" ]; - installPhase = '' - mv src $out - rm -rf $out/{ci,doc,driver,etc,grammar,llvm,rt,rtstartup,rustllvm,test,tools,vendor} - ''; -} diff --git a/nix/pkgs/rust/rustc.nix b/nix/pkgs/rust/rustc.nix deleted file mode 100644 index 34ca3acc5..000000000 --- a/nix/pkgs/rust/rustc.nix +++ /dev/null @@ -1,199 +0,0 @@ -{ stdenv, targetPackages -, fetchurl, fetchgit, fetchzip, file, python2, tzdata, ps -, llvm, jemalloc, ncurses, darwin, rustPlatform, git, cmake, curl -, which, libffi, gdb -, version -, forceBundledLLVM ? false -, src -, configureFlags ? [] -, patches -, targets -, targetPatches -, targetToolchains -, doCheck ? true -, broken ? false -, pkgs -}: - -let - inherit (stdenv.lib) optional optionalString; - inherit (darwin.apple_sdk.frameworks) Security; - - llvmShared = llvm.override { enableSharedLibraries = true; }; - llvmOR1k = (import ../../default.nix {}).llvm-or1k; - - target = builtins.replaceStrings [" "] [","] (builtins.toString targets); - src_rustc = fetchurl { - url = "https://static.rust-lang.org/dist/rustc-1.28.0-src.tar.gz"; - sha256 = "11k4rn77bca2rikykkk9fmprrgjswd4x4kaq7fia08vgkir82nhx"; - }; - -in - -stdenv.mkDerivation { - name = "rustc-${version}"; - inherit version; - - inherit src; - - __darwinAllowLocalNetworking = true; - - # rustc complains about modified source files otherwise - dontUpdateAutotoolsGnuConfigScripts = true; - - # Running the default `strip -S` command on Darwin corrupts the - # .rlib files in "lib/". - # - # See https://github.com/NixOS/nixpkgs/pull/34227 - stripDebugList = if stdenv.isDarwin then [ "bin" ] else null; - - NIX_LDFLAGS = optionalString stdenv.isDarwin "-rpath ${llvmShared}/lib"; - - # Enable nightly features in stable compiles (used for - # bootstrapping, see https://github.com/rust-lang/rust/pull/37265). - # This loosens the hard restrictions on bootstrapping-compiler - # versions. - RUSTC_BOOTSTRAP = "1"; - - # Increase codegen units to introduce parallelism within the compiler. - RUSTFLAGS = "-Ccodegen-units=10"; - - # We need rust to build rust. If we don't provide it, configure will try to download it. - # Reference: https://github.com/rust-lang/rust/blob/master/src/bootstrap/configure.py - configureFlags = configureFlags - ++ [ "--enable-local-rust" "--local-rust-root=${rustPlatform.rust.rustc}" "--enable-rpath" ] - ++ [ "--enable-vendor" ] - # ++ [ "--jemalloc-root=${jemalloc}/lib" - ++ [ "--default-linker=${targetPackages.stdenv.cc}/bin/cc" ] - ++ optional (!forceBundledLLVM) [ "--enable-llvm-link-shared" ] - ++ optional (targets != []) "--target=${target}" - #++ optional (!forceBundledLLVM) "--llvm-root=${llvmShared}" - ++ [ "--llvm-root=${llvmOR1k}" ] ; - - # The bootstrap.py will generated a Makefile that then executes the build. - # The BOOTSTRAP_ARGS used by this Makefile must include all flags to pass - # to the bootstrap builder. - postConfigure = '' - substituteInPlace Makefile --replace 'BOOTSTRAP_ARGS :=' 'BOOTSTRAP_ARGS := --jobs $(NIX_BUILD_CORES)' - ''; - - # FIXME: qknight, readd deleted vendor folder from 1.28 rustc - preConfigure = '' - export HOME=$out - # HACK: we add the vendor folder from rustc 1.28 to make the compiling work - tar xf ${src_rustc} - mv rustc-1.28.0-src/src/vendor/ src/vendor - cp -R ${llvmOR1k} src/llvm - ''; - - patches = patches ++ targetPatches; - - # the rust build system complains that nix alters the checksums - dontFixLibtool = true; - - passthru.target = target; - - postPatch = '' - patchShebangs src/etc - - # Fix dynamic linking against llvm - #${optionalString (!forceBundledLLVM) ''sed -i 's/, kind = \\"static\\"//g' src/etc/mklldeps.py''} - - # Fix the configure script to not require curl as we won't use it - sed -i configure \ - -e '/probe_need CFG_CURL curl/d' - - # Fix the use of jemalloc prefixes which our jemalloc doesn't have - # TODO: reenable if we can figure out how to get our jemalloc to work - #[ -f src/liballoc_jemalloc/lib.rs ] && sed -i 's,je_,,g' src/liballoc_jemalloc/lib.rs - #[ -f src/liballoc/heap.rs ] && sed -i 's,je_,,g' src/liballoc/heap.rs # Remove for 1.4.0+ - - # Disable fragile tests. - rm -vr src/test/run-make/linker-output-non-utf8 || true - rm -vr src/test/run-make/issue-26092 || true - - # Remove test targeted at LLVM 3.9 - https://github.com/rust-lang/rust/issues/36835 - rm -vr src/test/run-pass/issue-36023.rs || true - - # Disable test getting stuck on hydra - possible fix: - # https://reviews.llvm.org/rL281650 - rm -vr src/test/run-pass/issue-36474.rs || true - - # On Hydra: `TcpListener::bind(&addr)`: Address already in use (os error 98)' - sed '/^ *fn fast_rebind()/i#[ignore]' -i src/libstd/net/tcp.rs - - # https://github.com/rust-lang/rust/issues/39522 - echo removing gdb-version-sensitive tests... - find src/test/debuginfo -type f -execdir grep -q ignore-gdb-version '{}' \; -print -delete - rm src/test/debuginfo/{borrowed-c-style-enum.rs,c-style-enum-in-composite.rs,gdb-pretty-struct-and-enums-pre-gdb-7-7.rs,generic-enum-with-different-disr-sizes.rs} - - # Useful debugging parameter - # export VERBOSE=1 - '' + optionalString stdenv.isDarwin '' - # Disable all lldb tests. - # error: Can't run LLDB test because LLDB's python path is not set - rm -vr src/test/debuginfo/* - rm -v src/test/run-pass/backtrace-debuginfo.rs - - # error: No such file or directory - rm -v src/test/run-pass/issue-45731.rs - - # Disable tests that fail when sandboxing is enabled. - substituteInPlace src/libstd/sys/unix/ext/net.rs \ - --replace '#[test]' '#[test] #[ignore]' - substituteInPlace src/test/run-pass/env-home-dir.rs \ - --replace 'home_dir().is_some()' true - rm -v src/test/run-pass/fds-are-cloexec.rs # FIXME: pipes? - rm -v src/test/run-pass/sync-send-in-std.rs # FIXME: ??? - ''; - - # rustc unfortunately need cmake for compiling llvm-rt but doesn't - # use it for the normal build. This disables cmake in Nix. - dontUseCmakeConfigure = true; - - # ps is needed for one of the test cases - nativeBuildInputs = - [ file python2 ps rustPlatform.rust.rustc git cmake - which libffi - ] - # Only needed for the debuginfo tests - ++ optional (!stdenv.isDarwin) gdb; - - buildInputs = [ ncurses pkgs.zlib ] ++ targetToolchains - ++ optional stdenv.isDarwin Security - ++ optional (!forceBundledLLVM) llvmShared; - - outputs = [ "out" "man" "doc" ]; - setOutputFlags = false; - - # Disable codegen units and hardening for the tests. - preCheck = '' - export RUSTFLAGS= - export TZDIR=${tzdata}/share/zoneinfo - export hardeningDisable=all - '' + - # Ensure TMPDIR is set, and disable a test that removing the HOME - # variable from the environment falls back to another home - # directory. - optionalString stdenv.isDarwin '' - export TMPDIR=/tmp - sed -i '28s/home_dir().is_some()/true/' ./src/test/run-pass/env-home-dir.rs - ''; - - inherit doCheck; - - configurePlatforms = []; - - # https://github.com/NixOS/nixpkgs/pull/21742#issuecomment-272305764 - # https://github.com/rust-lang/rust/issues/30181 - # enableParallelBuilding = false; - - meta = with stdenv.lib; { - homepage = https://www.rust-lang.org/; - description = "A safe, concurrent, practical language"; - #maintainers = with maintainers; [ sb0 ]; - license = [ licenses.mit licenses.asl20 ]; - platforms = platforms.linux ++ platforms.darwin; - broken = broken; - }; -} diff --git a/nix/release.nix b/nix/release.nix deleted file mode 100644 index 625e798e3..000000000 --- a/nix/release.nix +++ /dev/null @@ -1,46 +0,0 @@ -{ pkgs ? import {}}: -let - artiqPkgs = import ./default.nix { inherit pkgs; }; - - boards = [ - { - target = "kasli"; - variant = "tester"; - } - { - target = "kc705"; - variant = "nist_clock"; - } - ]; - boardJobs = pkgs.lib.lists.foldr (board: start: - let - boardBinaries = import ./artiq-board.nix { inherit pkgs; } { - target = board.target; - variant = board.variant; - }; - in - start // { - "artiq-board-${board.target}-${board.variant}" = boardBinaries; - "conda-artiq-board-${board.target}-${board.variant}" = import ./conda-board.nix { inherit pkgs; } { - artiqSrc = ../.; - boardBinaries = boardBinaries; - target = board.target; - variant = board.variant; - }; - }) {} boards; - - jobs = { - conda-artiq = import ./conda-build.nix { inherit pkgs; } { - name = "conda-artiq"; - src = ../.; - recipe = "conda/artiq"; - }; - } // boardJobs // artiqPkgs; -in - jobs // { - channel = pkgs.releaseTools.channel { - name = "main"; - src = ./.; - constituents = builtins.attrValues jobs; - }; - } diff --git a/nix/shell-dev.nix b/nix/shell-dev.nix deleted file mode 100644 index d7ff9a076..000000000 --- a/nix/shell-dev.nix +++ /dev/null @@ -1,6 +0,0 @@ -{ pkgs ? import {}}: - -let - artiq-dev = import ./artiq-dev.nix { inherit pkgs; }; -in - artiq-dev.env diff --git a/nix/shell.nix b/nix/shell.nix deleted file mode 100644 index 2c324158a..000000000 --- a/nix/shell.nix +++ /dev/null @@ -1,7 +0,0 @@ -let - pkgs = import {}; - artiqpkgs = import ./default.nix { inherit pkgs; }; -in - pkgs.mkShell { - buildInputs = with artiqpkgs; [ binutils-or1k llvm-or1k llvmlite artiq ]; - } From 40a0cf806d1c323d7241278ae9f4c74ffae77114 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 17 Feb 2019 14:49:45 +0800 Subject: [PATCH 1664/2457] support overriding versioneer --- artiq/_version.py | 6 ++++++ versioneer.py | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/artiq/_version.py b/artiq/_version.py index 0452994dd..8f9af10f8 100644 --- a/artiq/_version.py +++ b/artiq/_version.py @@ -481,6 +481,12 @@ def get_versions(): # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which # case we can only use expanded keywords. + override = os.getenv("VERSIONEER_OVERRIDE") + if override: + return {"version": override, "full-revisionid": None, + "dirty": None, + "error": None, "date": None} + cfg = get_config() verbose = cfg.verbose diff --git a/versioneer.py b/versioneer.py index f115f7998..0539490d3 100644 --- a/versioneer.py +++ b/versioneer.py @@ -901,6 +901,12 @@ def get_versions(): # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which # case we can only use expanded keywords. + override = os.getenv("VERSIONEER_OVERRIDE") + if override: + return {"version": override, "full-revisionid": None, + "dirty": None, + "error": None, "date": None} + cfg = get_config() verbose = cfg.verbose @@ -1404,6 +1410,12 @@ def get_versions(verbose=False): Returns dict with two keys: 'version' and 'full'. """ + override = os.getenv("VERSIONEER_OVERRIDE") + if override: + return {"version": override, "full-revisionid": None, + "dirty": None, + "error": None, "date": None} + if "versioneer" in sys.modules: # see the discussion in cmdclass.py:get_cmdclass() del sys.modules["versioneer"] From 596d3e20d7aea06abe13cd2c38cdf7a68353d085 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 19 Feb 2019 15:43:04 +0800 Subject: [PATCH 1665/2457] dashboard,browser: do not call get_user_config_dir() in argparse This caused two problems when building the docs: * the path printed in the docs depends on the machine where they are built * it pollutes ~/.config, and also breaks Nix builds --- artiq/frontend/artiq_browser.py | 6 +++--- artiq/frontend/artiq_dashboard.py | 4 +--- doc/manual/faq.rst | 6 ++++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index 5076225c7..da5bead60 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -20,10 +20,8 @@ logger = logging.getLogger(__name__) def get_argparser(): - default_db_file = os.path.join(get_user_config_dir(), "artiq_browser.pyon") - parser = argparse.ArgumentParser(description="ARTIQ Browser") - parser.add_argument("--db-file", default=default_db_file, + parser.add_argument("--db-file", default=None, help="database file for local browser settings " "(default: %(default)s)") parser.add_argument("--browse-root", default="", @@ -132,6 +130,8 @@ class Browser(QtWidgets.QMainWindow): def main(): # initialize application args = get_argparser().parse_args() + if args.db_file is None: + args.db_file = os.path.join(get_user_config_dir(), "artiq_browser.pyon") widget_log_handler = log.init_log(args, "browser") app = QtWidgets.QApplication(["ARTIQ Browser"]) diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index 98d3c2e53..855781720 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -36,9 +36,7 @@ def get_argparser(): help="TCP port to connect to for broadcasts") parser.add_argument( "--db-file", default=None, - help="database file for local GUI settings, " - "by default in {} and dependant on master hostname".format( - get_user_config_dir())) + help="database file for local GUI settings") add_common_args(parser) return parser diff --git a/doc/manual/faq.rst b/doc/manual/faq.rst index 8df0258d8..a550392a8 100644 --- a/doc/manual/faq.rst +++ b/doc/manual/faq.rst @@ -107,3 +107,9 @@ The core device tests require the following TTL devices and connections: * ``loop_clock_in``: any input-capable TTL. Must be physically connected to ``loop_clock_out``. If TTL devices are missing, the corresponding tests are skipped. + +find the dashboard and browser configuration files are stored? +-------------------------------------------------------------- + +:: + python -c "from artiq.tools import get_user_config_dir; print(get_user_config_dir())" From 5557491cc72c10b0e0b751cd4e92fd8fcd999aac Mon Sep 17 00:00:00 2001 From: Stephan Maka Date: Tue, 19 Feb 2019 17:31:02 +0100 Subject: [PATCH 1666/2457] manual: fix wavedrom extension json syntax The leading empty line seems to be required by Sphinx 1.8.3. The arguments must be strict JSON when prerendering for a target that is not "html". Browser JSON parsing may have been more lenient. Signed-off-by: Stephan Maka --- doc/manual/rtio.rst | 95 ++++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 45 deletions(-) diff --git a/doc/manual/rtio.rst b/doc/manual/rtio.rst index 769e6a27a..03f3b4d06 100644 --- a/doc/manual/rtio.rst +++ b/doc/manual/rtio.rst @@ -55,21 +55,22 @@ Then later, when the wall clock reaches the respective timestamps the RTIO gatew The following diagram shows what is going on at the different levels of the software and gateware stack (assuming one machine unit of time is 1 ns): .. wavedrom:: + { - signal: [ - {name: 'kernel', wave: 'x32.3x', data: ['on()', 'delay(2*us)', 'off()'], node: '..A.XB'}, - {name: 'now', wave: '2...2.', data: ['7000', '9000'], node: '..P..Q'}, + "signal": [ + {"name": "kernel", "wave": "x32.3x", "data": ["on()", "delay(2*us)", "off()"], "node": "..A.XB"}, + {"name": "now", "wave": "2...2.", "data": ["7000", "9000"], "node": "..P..Q"}, {}, - {name: 'slack', wave: 'x2x.2x', data: ['4400', '5800']}, + {"name": "slack", "wave": "x2x.2x", "data": ["4400", "5800"]}, {}, - {name: 'rtio_counter', wave: 'x2x|2x|2x2x', data: ['2600', '3200', '7000', '9000'], node: ' V.W'}, - {name: 'ttl', wave: 'x1.0', node: ' R.S', phase: -6.5}, - { node: ' T.U', phase: -6.5} - ], - edge: [ - 'A~>R', 'P~>R', 'V~>R', 'B~>S', 'Q~>S', 'W~>S', - 'R-T', 'S-U', 'T<->U 2µs' + {"name": "rtio_counter", "wave": "x2x|2x|2x2x", "data": ["2600", "3200", "7000", "9000"], "node": " V.W"}, + {"name": "ttl", "wave": "x1.0", "node": " R.S", "phase": -6.5}, + { "node": " T.U", "phase": -6.5} ], + "edge": [ + "A~>R", "P~>R", "V~>R", "B~>S", "Q~>S", "W~>S", + "R-T", "S-U", "T<->U 2µs" + ] } The sequence is exactly equivalent to:: @@ -95,19 +96,20 @@ The experiment attempts to handle the exception by moving the cursor forward and ttl.on() .. wavedrom:: + { - signal: [ - {name: 'kernel', wave: 'x34..2.3x', data: ['on()', 'RTIOUnderflow', 'delay()', 'on()'], node: '..AB....C', phase: -3}, - {name: 'now_mu', wave: '2.....2', data: ['t0', 't1'], node: '.D.....E', phase: -4}, + "signal": [ + {"name": "kernel", "wave": "x34..2.3x", "data": ["on()", "RTIOUnderflow", "delay()", "on()"], "node": "..AB....C", "phase": -3}, + {"name": "now_mu", "wave": "2.....2", "data": ["t0", "t1"], "node": ".D.....E", "phase": -4}, {}, - {name: 'slack', wave: '2x....2', data: ['< 0', '> 0'], node: '.T', phase: -4}, + {"name": "slack", "wave": "2x....2", "data": ["< 0", "> 0"], "node": ".T", "phase": -4}, {}, - {name: 'rtio_counter', wave: 'x2x.2x....2x2', data: ['t0', '> t0', '< t1', 't1'], node: '............P'}, - {name: 'tll', wave: 'x...........1', node: '.R..........S', phase: -.5} + {"name": "rtio_counter", "wave": "x2x.2x....2x2", "data": ["t0", "> t0", "< t1", "t1"], "node": "............P"}, + {"name": "tll", "wave": "x...........1", "node": ".R..........S", "phase": -0.5} ], - edge: [ - 'A-~>R forbidden', 'D-~>R', 'T-~B exception', - 'C~>S allowed', 'E~>S', 'P~>S' + "edge": [ + "A-~>R forbidden", "D-~>R", "T-~B exception", + "C~>S allowed", "E~>S", "P~>S" ] } @@ -170,17 +172,18 @@ The :meth:`artiq.coredevice.ttl.TTLInOut.gate_rising` method leaves the timeline Similar situations arise with methods such as :meth:`artiq.coredevice.ttl.TTLInOut.sample_get` and :meth:`artiq.coredevice.ttl.TTLInOut.watch_done`. .. wavedrom:: + { - signal: [ - {name: 'kernel', wave: '3..5.|2.3..x..', data: ['gate_rising()', 'count()', 'delay()', 'pulse()'], node: '.A.B..C.ZD.E'}, - {name: 'now_mu', wave: '2.2..|..2.2.', node: '.P.Q....XV.W'}, + "signal": [ + {"name": "kernel", "wave": "3..5.|2.3..x..", "data": ["gate_rising()", "count()", "delay()", "pulse()"], "node": ".A.B..C.ZD.E"}, + {"name": "now_mu", "wave": "2.2..|..2.2.", "node": ".P.Q....XV.W"}, {}, {}, - {name: 'input gate', wave: 'x1.0', node: '.T.U', phase: -2.5}, - {name: 'output', wave: 'x1.0', node: '.R.S', phase: -10.5} + {"name": "input gate", "wave": "x1.0", "node": ".T.U", "phase": -2.5}, + {"name": "output", "wave": "x1.0", "node": ".R.S", "phase": -10.5} ], - edge: [ - 'A~>T', 'P~>T', 'B~>U', 'Q~>U', 'U~>C', 'D~>R', 'E~>S', 'V~>R', 'W~>S' + "edge": [ + "A~>T", "P~>T", "B~>U", "Q~>U", "U~>C", "D~>R", "E~>S", "V~>R", "W~>S" ] } @@ -214,20 +217,21 @@ This is demonstrated in the following example where a pulse is split across two Here, ``run()`` calls ``k1()`` which exits leaving the cursor one second after the rising edge and ``k2()`` then submits a falling edge at that position. .. wavedrom:: + { - signal: [ - {name: 'kernel', wave: '3.2..2..|3.', data: ['k1: on()', 'k1: delay(dt)', 'k1->k2 swap', 'k2: off()'], node: '..A........B'}, - {name: 'now', wave: '2....2...|.', data: ['t', 't+dt'], node: '..P........Q'}, + "signal": [ + {"name": "kernel", "wave": "3.2..2..|3.", "data": ["k1: on()", "k1: delay(dt)", "k1->k2 swap", "k2: off()"], "node": "..A........B"}, + {"name": "now", "wave": "2....2...|.", "data": ["t", "t+dt"], "node": "..P........Q"}, {}, {}, - {name: 'rtio_counter', wave: 'x......|2xx|2', data: ['t', 't+dt'], node: '........V...W'}, - {name: 'ttl', wave: 'x1...0', node: '.R...S', phase: -7.5}, - { node: ' T...U', phase: -7.5} - ], - edge: [ - 'A~>R', 'P~>R', 'V~>R', 'B~>S', 'Q~>S', 'W~>S', - 'R-T', 'S-U', 'T<->U dt' + {"name": "rtio_counter", "wave": "x......|2xx|2", "data": ["t", "t+dt"], "node": "........V...W"}, + {"name": "ttl", "wave": "x1...0", "node": ".R...S", "phase": -7.5}, + { "node": " T...U", "phase": -7.5} ], + "edge": [ + "A~>R", "P~>R", "V~>R", "B~>S", "Q~>S", "W~>S", + "R-T", "S-U", "T<->U dt" + ] } @@ -239,18 +243,19 @@ If a previous kernel sets timeline cursor far in the future this effectively loc When a kernel should wait until all the events on a particular channel have been executed, use the :meth:`artiq.coredevice.ttl.TTLOut.sync` method of a channel: .. wavedrom:: + { - signal: [ - {name: 'kernel', wave: 'x3x.|5.|x', data: ['on()', 'sync()'], node: '..A.....Y'}, - {name: 'now', wave: '2..', data: ['7000'], node: '..P'}, + "signal": [ + {"name": "kernel", "wave": "x3x.|5.|x", "data": ["on()", "sync()"], "node": "..A.....Y"}, + {"name": "now", "wave": "2..", "data": ["7000"], "node": "..P"}, {}, {}, - {name: 'rtio_counter', wave: 'x2x.|..2x', data: ['2000', '7000'], node: ' ....V'}, - {name: 'ttl', wave: 'x1', node: ' R', phase: -6.5}, - ], - edge: [ - 'A~>R', 'P~>R', 'V~>R', 'V~>Y' + {"name": "rtio_counter", "wave": "x2x.|..2x", "data": ["2000", "7000"], "node": " ....V"}, + {"name": "ttl", "wave": "x1", "node": " R", "phase": -6.5} ], + "edge": [ + "A~>R", "P~>R", "V~>R", "V~>Y" + ] } RTIO reset From 7c0353b4be5f748a87dcc476171da68146e324f5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Feb 2019 11:24:25 +0800 Subject: [PATCH 1667/2457] install-artiq: more polite comments --- conda/install-artiq.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/conda/install-artiq.py b/conda/install-artiq.py index 00ac529c1..b17f3658c 100644 --- a/conda/install-artiq.py +++ b/conda/install-artiq.py @@ -1,8 +1,7 @@ # This script installs ARTIQ using the conda packages built by the new Nix/Hydra system. # It needs to be run in the root (base) conda environment with "python install-artiq.py" -# It supports Linux and Windows, but it really is just an ugly collection of workarounds -# and conda is awful; if you are running Linux, you're better off using Nix which is not -# buggy and needs none of this mess. +# It supports Linux and Windows, but Linux users should consider using the higher-quality +# Nix package manager instead of Conda. # EDIT THIS: # The name of the conda environment to create @@ -35,7 +34,7 @@ if ADD_CHANNELS: run("conda config --add channels conda-forge") run("conda install -y conda-build curl") -# Another silly conda decision is to ignore dependencies when installing .tar.bz2's directly. +# A questionable conda decision is to ignore dependencies when installing .tar.bz2's directly. # Work around it by creating a channel for our packages. with tempfile.TemporaryDirectory() as channel_dir: print("Creating conda channel in {channel_dir}...".format(channel_dir=channel_dir)) @@ -45,8 +44,8 @@ with tempfile.TemporaryDirectory() as channel_dir: os.mkdir("noarch") # curl -OJL won't take the correct filename and it will save the output as "conda". # wget --content-disposition is better-behaved but wget cannot be used on Windows. - # Amazingly, conda doesn't do something stupid when package files are renamed, - # so we can get away by generating our own names that don't contain the version number. + # Amazingly, conda doesn't break when package files are renamed, so we can get away + # by generating our own names that don't contain the version number. for hydra_build, package in CONDA_PACKAGES: run("curl https://nixbld.m-labs.hk/job/artiq/{hydra_build}/conda-{package}/latest/download-by-type/file/conda -L -o noarch/{package}.tar.bz2" .format(hydra_build=hydra_build, package=package)) From 84619adbaba7a84676aa9ccf11ae78ed55facfdc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Feb 2019 18:30:25 +0800 Subject: [PATCH 1668/2457] manual: revamp installation instructions --- doc/manual/installing.rst | 253 ++++++++++++++++++++++---------------- 1 file changed, 148 insertions(+), 105 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index e02139ffe..921cb343d 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -1,130 +1,172 @@ -.. _install-from-conda: - Installing ARTIQ ================ -The preferred way of installing ARTIQ is through the use of the conda package manager. -The conda package contains pre-built binaries that you can directly flash to your board. +ARTIQ can be installed using the Nix (on Linux) or Conda (on Windows or Linux) package managers. -.. warning:: - NIST users on Linux need to pay close attention to their ``umask``. - The sledgehammer called ``secureconfig`` leaves you (and root) with umask 027 and files created by root (for example through ``sudo make install``) inaccessible to you. - The usual umask is 022. +Nix is an innovative, robust, fast, and high-quality solution that comes with a larger collection of packages and features than Conda. However, Windows support is poor (using it with Windows Subsystem for Linux still has many problems) and Nix can be harder to learn. +Conda has a more traditional approach to package management, is much more limited, slow, and lower-quality than Nix, but it supports Windows and it is simpler to use when it functions correctly. -.. warning:: - Conda packages are supported for Linux (64-bit) and Windows (64-bit). - Users of other operating systems (32-bit Linux or Windows, BSD, OSX ...) should and can :ref:`install from source `. +In the current state of affairs, we recommend that Linux users install ARTIQ via Nix and Windows users install it via Conda. -.. _install-anaconda: +Installing via Nix (Linux) +-------------------------- -Installing Anaconda or Miniconda --------------------------------- +First, install the Nix package manager. Some distributions provide a package for the Nix package manager, otherwise, it can be installed via the script on the `Nix website `_. -You can either install Anaconda from https://www.anaconda.com/download/ or install the more minimalistic Miniconda from https://conda.io/miniconda.html +Once Nix is installed, add the M-Labs package channels with: :: + + nix-channel --add https://nixbld.m-labs.hk/channel/custom/artiq/main/channel m-labs + nix-channel --add https://nixbld.m-labs.hk/channel/custom/artiq/sinara-systems/channel sinara + nix-channel --update + +Those channels track `nixpkgs 18.09 `_. You can check the latest status through the `Hydra interface `_. + +Nix won't install packages without verifying their cryptographic signature. Add the M-Labs public key by creating the file ``~/.config/nix/nix.conf`` with the following contents: + +:: + + substituters = https://cache.nixos.org https://nixbld.m-labs.hk + trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc= + +The easiest way to obtain ARTIQ is then to install it into the user environment with ``nix-env -i python3.6-artiq``. This provides a minimal installation of ARTIQ where the usual commands (``artiq_master``, ``artiq_dashboard``, ``artiq_run``, etc.) are available. + +This installation is however quite limited, as Nix creates a dedicated Python environment for the ARTIQ commands alone. This means that other useful Python packages that you may want (pandas, matplotlib, ...) are not available to them, and this restriction also applies to the M-Labs packages containing board binaries, which means that ``artiq_flash`` will not automatically find them. + +Installing multiple packages and making them visible to the ARTIQ commands requires using the Nix language. Create a file ``my-artiq-env.nix`` with the following contents: + +:: + + let + # Contains the NixOS package collection. ARTIQ depends on some of them, and + # you may also want certain packages from there. + pkgs = import {}; + # Contains the main ARTIQ packages, their dependencies, and board packages + # for systems used in CI. + # List: https://nixbld.m-labs.hk/channel/custom/artiq/main/channel + m-labs = import {}; + # Contains the board packages for the majority of systems. + # List: https://nixbld.m-labs.hk/channel/custom/artiq/sinara-systems/channel + sinara = import {}; + in + pkgs.mkShell { + buildInputs = [ + (pkgs.python3.withPackages(ps: [ + # List desired Python packages here. + # The board packages are also "Python" packages. You only need a board + # package if you intend to reflash that board. + m-labs.artiq + m-labs.artiq-board-kc705-nist_clock + sinara.artiq-board-kasli-wipm + # from the NixOS package collection: + ps.pandas + ps.numpy + ps.scipy + ps.numba + ps.matplotlib.override { enableQt = true; } + ps.bokeh + ])) + # List desired non-Python packages here + m-labs.openocd # needed for flashing boards + pkgs.spyder + ]; + } + +Then spawn a shell containing the packages with ``nix-shell my-artiq-env.nix``. The ARTIQ commands with all the additional packages should now be available. + +You can exit the shell by typing Control-D. The next time ``nix-shell my-artiq-env.nix`` is invoked, Nix uses the cached packages so the shell startup is fast. + +You can edit this file according to your needs, and also create multiple ``.nix`` files that correspond to different sets of packages. If you are familiar with Conda, using Nix in this way is similar to having multiple Conda environments. + +If your favorite package is not available with Nix, contact us. + +Installing via Conda (Windows, Linux) +------------------------------------- + +First, install `Anaconda `_ or the more minimalistic `Miniconda `_. After installing either Anaconda or Miniconda, open a new terminal (also known as command line, console, or shell and denoted here as lines starting with ``$``) and verify the following command works:: $ conda -Executing just ``conda`` should print the help of the ``conda`` command [1]_. +Executing just ``conda`` should print the help of the ``conda`` command. If your shell does not find the ``conda`` command, make sure that the Conda binaries are in your ``$PATH``. If ``$ echo $PATH`` does not show the Conda directories, add them: execute ``$ export PATH=$HOME/miniconda3/bin:$PATH`` if you installed Conda into ``~/miniconda3``. -Installing the ARTIQ packages ------------------------------ +Download the `ARTIQ installer script `_ and edit its beginning to define the Conda environment name (you can leave the default environment name if you are just getting started) and select the desired ARTIQ packages. Non-ARTIQ packages should be installed manually later. If you do not need to flash boards, the ``artiq`` package from the ``main`` Hydra build is sufficient. -.. note:: - On a system with a pre-existing conda installation, it is recommended to update conda to the latest version prior to installing ARTIQ. +Make sure the base Conda environment is activated and then run the installer script: :: -Add the M-Labs ``main`` Anaconda package repository containing stable releases and release candidates:: + $ conda activate base + $ python install-artiq.py - $ conda config --prepend channels m-labs +After the installation, activate the newly created environment by name. :: -.. note:: - To use the development versions of ARTIQ, also add the ``dev`` label (m-labs/label/dev). - Development versions are built for every change and contain more features, but are not as well-tested and are more likely to contain more bugs or inconsistencies than the releases in the default ``main`` label. - -Add the conda-forge repository containing ARTIQ dependencies to your conda configuration:: - - $ conda config --add channels conda-forge - -Then prepare to create a new conda environment with the ARTIQ package and the matching binaries for your hardware: -choose a suitable name for the environment, for example ``artiq-main`` if you intend to track the main label, ``artiq-3`` for the 3.x release series, or ``artiq-2016-04-01`` if you consider the environment a snapshot of ARTIQ on 2016-04-01. -Choose the package containing the binaries for your hardware: - - * ``artiq-kc705-nist_clock`` for the KC705 board with the NIST "clock" FMC backplane and AD9914 DDS chips. - * ``artiq-kc705-nist_qc2`` for the KC705 board with the NIST QC2 FMC backplane and AD9914 DDS chips. - -Conda will create the environment, automatically resolve, download, and install the necessary dependencies and install the packages you select:: - - $ conda create -n artiq-main artiq-kc705-nist_clock - -After the installation, activate the newly created environment by name. -On Unix:: - - $ source activate artiq-main - -On Windows:: - - $ activate artiq-main + $ conda activate artiq This activation has to be performed in every new shell you open to make the ARTIQ tools from that environment available. .. note:: - Some ARTIQ examples also require matplotlib and numba, and they must be installed manually for running those examples. They are available in conda. - + Some ARTIQ examples also require matplotlib and numba, and they must be installed manually for running those examples. They are available in Conda. Upgrading ARTIQ --------------- -When upgrading ARTIQ or when testing different versions it is recommended that new environments are created instead of upgrading the packages in existing environments. +When upgrading ARTIQ or when testing different versions it is recommended that new Conda environments are created instead of upgrading the packages in existing environments. Keep previous environments around until you are certain that they are not needed anymore and a new environment is known to work correctly. -You can create a new conda environment specifically to test a certain version of ARTIQ:: - $ conda create -n artiq-test-1.0rc2 artiq-kc705-nist_clock=1.0rc2 +To install the latest version, just select a different environment name and run the installer script again. + +Switching between Conda environments using commands such as ``$ conda deactivate artiq-6`` and ``$ conda activate artiq-5`` is the recommended way to roll back to previous versions of ARTIQ. + +You may need to reflash the gateware and firmware of the core device to keep it synchronized with the software. -Switching between conda environments using ``$ source deactivate artiq-1.0rc2`` and ``$ source activate artiq-1.0rc1`` is the recommended way to roll back to previous versions of ARTIQ. You can list the environments you have created using:: $ conda env list -See also the `conda documentation `_ for managing environments. +Flashing gateware and firmware into the core device +--------------------------------------------------- -Preparing the core device FPGA board ------------------------------------- +.. note:: + If you have purchased a pre-assembled system from M-Labs or QUARTIQ, the gateware and firmware are already flashed and you can skip those steps, unless you want to replace them with a different version of ARTIQ. You now need to write three binary images onto the FPGA board: 1. The FPGA gateware bitstream -2. The BIOS -3. The ARTIQ runtime +2. The bootloader +3. The ARTIQ runtime or satellite manager -They are all shipped in the conda packages, along with the required flash proxy gateware bitstreams. - -.. _install-openocd: +They are all shipped in the Nix and Conda packages, along with the required flash proxy gateware bitstreams. Installing OpenOCD ^^^^^^^^^^^^^^^^^^ OpenOCD can be used to write the binary images into the core device FPGA board's flash memory. -The ``artiq`` or ``artiq-dev`` conda packages install ``openocd`` automatically but it can also be installed explicitly using conda on both Linux and Windows:: + +With Nix, add ``m-labs.openocd`` to the shell packages. Be careful not to add ``pkgs.openocd`` instead - this would install OpenOCD from the NixOS package collection, which does not support ARTIQ boards. + +With Conda, the ``artiq`` package installs ``openocd`` automatically but it can also be installed explicitly on both Linux and Windows:: $ conda install openocd -.. _setup-openocd: - Configuring OpenOCD ^^^^^^^^^^^^^^^^^^^ Some additional steps are necessary to ensure that OpenOCD can communicate with the FPGA board. -On Linux, first ensure that the current user belongs to the ``plugdev`` group (i.e. `plugdev` shown when you run `$ groups`). If it does not, run ``sudo adduser $USER plugdev`` and relogin. If you installed OpenOCD using conda and are using the conda environment ``artiq-main``, then execute the statements below. If you are using a different environment, you will have to replace ``artiq-main`` with the name of your environment:: +On Linux, first ensure that the current user belongs to the ``plugdev`` group (i.e. ``plugdev`` shown when you run ``$ groups``). If it does not, run ``sudo adduser $USER plugdev`` and re-login. - $ sudo cp ~/.conda/envs/artiq-main/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d - $ sudo udevadm trigger +If you installed OpenOCD on Linux using Nix, use the ``which`` command to determine the path to OpenOCD, and then copy the udev rules: :: -if you installed it from source:: Assuming you installed OpenOCD in ``/usr/local``, otherwise please substitute the install directory:: + $ which openocd + /nix/store/2bmsssvk3d0y5hra06pv54s2324m4srs-openocd-mlabs-0.10.0/bin/openocd + $ sudo cp /nix/store/2bmsssvk3d0y5hra06pv54s2324m4srs-openocd-mlabs-0.10.0/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d + $ sudo udevadm trigger - $ sudo cp /usr/local/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d +NixOS users should of course configure OpenOCD through ``/etc/nixos/configuration.nix`` instead. + +If you installed OpenOCD on Linux using Conda and are using the Conda environment ``artiq``, then execute the statements below. If you are using a different environment, you will have to replace ``artiq`` with the name of your environment:: + + $ sudo cp ~/.conda/envs/artiq/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d $ sudo udevadm trigger On Windows, a third-party tool, `Zadig `_, is necessary. Use it as follows: @@ -140,70 +182,71 @@ You may need to repeat these steps every time you plug the FPGA board into a por .. _flashing-core-device: -Flashing the core device -^^^^^^^^^^^^^^^^^^^^^^^^ +Writing the flash +^^^^^^^^^^^^^^^^^ -Then, you can flash the board: +Then, you write the flash: -* For the KC705 board (selecting the appropriate hardware peripheral):: +* For Kasli:: + + $ artiq_flash -V [your board variant] + +* For the KC705 board:: $ artiq_flash -t kc705 -V [nist_clock/nist_qc2] - The SW13 switches also need to be set to 00001. + The SW13 switches need to be set to 00001. -The next step is to flash the MAC and IP addresses to the board. See :ref:`those instructions `. +Setting up the core device IP networking +---------------------------------------- -.. _configuring-core-device: +For Kasli, insert a SFP/RJ45 transceiver (normally included with purchases from M-Labs and QUARTIQ) into the SFP0 port and connect it to a gigabit Ethernet port in your network. It is necessary that the port be gigabit - 10/100 ports cannot be used. If you need to interface Kasli with 10/100 network equipment, connect them through a gigabit switch. -Configuring the core device ---------------------------- +You can also insert other types of SFP transceivers into Kasli if you wish to use it directly in e.g. an optical fiber Ethernet network. -This should be done after either installation method (conda or source). +If you purchased a device from M-Labs, it already comes with a valid MAC address and an IP address, usually ``192.168.1.75``. Once you can reach this IP, it can be changed with: :: -* (optional) If you are using DRTIO and the default routing table (for a star topology) is not suitable to your needs, prepare the routing table and add it to the ``flash_storage.img`` created in the next step. The routing table can be easily changed later, so you can skip this step if you are just getting started and only want to test local channels. See :ref:`Using DRTIO `. + artiq_coremgmt -D 192.168.1.75 config write -s ip [new IP] -.. _flash-mac-ip-addr: +and then reboot the device (with ``artiq_flash start`` or a power cycle). -* Set the MAC and IP address in the :ref:`core device configuration flash storage ` (see above for the ``-t`` and ``-V`` options to ``artiq_flash`` that may be required): :: +In other cases, install OpenOCD as before, and flash the IP and MAC addresses directly: :: $ artiq_mkfs flash_storage.img -s mac xx:xx:xx:xx:xx:xx -s ip xx.xx.xx.xx $ artiq_flash -t [board] -V [adapter] -f flash_storage.img storage start -* (optional) Flash the idle kernel +Check that you can ping the device. If ping fails, check that the Ethernet link LED is ON - on Kasli, it is the LED next to the SFP0 connector. As a next step, look at the messages emitted on the UART during boot. Use a program such as flterm or PuTTY to connect to the device's serial port at 115200bps 8-N-1 and reboot the device. On Kasli, the serial port is on FTDI channel 2 with v1.1 hardware (with channel 0 being JTAG) and on FTDI channel 1 with v1.0 hardware. + +Miscellaneous configuration of the core device +---------------------------------------------- + +Those steps are optional. The core device usually needs to be restarted for changes to take effect. + +* Load the idle kernel The idle kernel is the kernel (some piece of code running on the core device) which the core device runs whenever it is not connected to a PC via Ethernet. This kernel is therefore stored in the :ref:`core device configuration flash storage `. -To flash the idle kernel: - * Compile the idle experiment: - The idle experiment's ``run()`` method must be a kernel: it must be decorated with the ``@kernel`` decorator (see :ref:`next topic ` for more information about kernels). +To flash the idle kernel, first compile the idle experiment. The idle experiment's ``run()`` method must be a kernel: it must be decorated with the ``@kernel`` decorator (see :ref:`next topic ` for more information about kernels). Since the core device is not connected to the PC, RPCs (calling Python code running on the PC from the kernel) are forbidden in the idle experiment. Then write it into the core device configuration flash storage: :: - Since the core device is not connected to the PC, RPCs (calling Python code running on the PC from the kernel) are forbidden in the idle experiment. - :: - - $ artiq_compile idle.py - - * Write it into the core device configuration flash storage: :: - - $ artiq_coremgmt config -f idle_kernel idle.elf + $ artiq_compile idle.py + $ artiq_coremgmt config write -f idle_kernel idle.elf .. note:: You can find more information about how to use the ``artiq_coremgmt`` utility on the :ref:`Utilities ` page. -* (optional) Flash the startup kernel +* Load the startup kernel The startup kernel is executed once when the core device powers up. It should initialize DDSes, set up TTL directions, etc. Proceed as with the idle kernel, but using the ``startup_kernel`` key in the ``artiq_coremgmt`` command. For DRTIO systems, the startup kernel should wait until the desired destinations (including local RTIO) are up, using :meth:`artiq.coredevice.Core.get_rtio_destination_status`. -* (optional) Select the RTIO clock source +* Load the DRTIO routing table -Some core devices may use either an external clock signal or their internal clock. The clock is selected at power-up. Use one of these commands: :: +If you are using DRTIO and the default routing table (for a star topology) is not suitable to your needs, prepare and load a different routing table. See :ref:`Using DRTIO `. + +* Select the RTIO clock source (KC705 only) + +The KC705 may use either an external clock signal or its internal clock. The clock is selected at power-up. Use one of these commands: :: $ artiq_coremgmt config write -s rtio_clock i # internal clock (default) $ artiq_coremgmt config write -s rtio_clock e # external clock - - -.. rubric:: Footnotes - -.. [1] [Linux] If your shell does not find the ``conda`` command, make sure that the conda binaries are in your ``$PATH``: - If ``$ echo $PATH`` does not show the conda directories, add them: execute ``$ export PATH=$HOME/miniconda3/bin:$PATH`` if you installed conda into ``~/miniconda3``. From 87a1ea6587a7f93bf4a130b7d68c0a38b9569e9e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Feb 2019 19:01:55 +0800 Subject: [PATCH 1669/2457] manual: minor polishing --- doc/manual/installing.rst | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 921cb343d..e340f5278 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -44,10 +44,10 @@ Installing multiple packages and making them visible to the ARTIQ commands requi # Contains the main ARTIQ packages, their dependencies, and board packages # for systems used in CI. # List: https://nixbld.m-labs.hk/channel/custom/artiq/main/channel - m-labs = import {}; + m-labs = import { inherit pkgs; }; # Contains the board packages for the majority of systems. # List: https://nixbld.m-labs.hk/channel/custom/artiq/sinara-systems/channel - sinara = import {}; + sinara = import { inherit pkgs; }; in pkgs.mkShell { buildInputs = [ @@ -153,7 +153,7 @@ Configuring OpenOCD Some additional steps are necessary to ensure that OpenOCD can communicate with the FPGA board. -On Linux, first ensure that the current user belongs to the ``plugdev`` group (i.e. ``plugdev`` shown when you run ``$ groups``). If it does not, run ``sudo adduser $USER plugdev`` and re-login. +On Linux, first ensure that the current user belongs to the ``plugdev`` group (i.e. ``plugdev`` shown when you run ``$ groups``). If it does not, run ``$ sudo adduser $USER plugdev`` and re-login. If you installed OpenOCD on Linux using Nix, use the ``which`` command to determine the path to OpenOCD, and then copy the udev rules: :: @@ -180,16 +180,14 @@ On Windows, a third-party tool, `Zadig `_, is necessary. You may need to repeat these steps every time you plug the FPGA board into a port where it has not been plugged into previously on the same system. -.. _flashing-core-device: - Writing the flash ^^^^^^^^^^^^^^^^^ -Then, you write the flash: +Then, you can write the flash: * For Kasli:: - $ artiq_flash -V [your board variant] + $ artiq_flash -V [your system variant] * For the KC705 board:: @@ -213,7 +211,7 @@ and then reboot the device (with ``artiq_flash start`` or a power cycle). In other cases, install OpenOCD as before, and flash the IP and MAC addresses directly: :: $ artiq_mkfs flash_storage.img -s mac xx:xx:xx:xx:xx:xx -s ip xx.xx.xx.xx - $ artiq_flash -t [board] -V [adapter] -f flash_storage.img storage start + $ artiq_flash -t [board] -V [variant] -f flash_storage.img storage start Check that you can ping the device. If ping fails, check that the Ethernet link LED is ON - on Kasli, it is the LED next to the SFP0 connector. As a next step, look at the messages emitted on the UART during boot. Use a program such as flterm or PuTTY to connect to the device's serial port at 115200bps 8-N-1 and reboot the device. On Kasli, the serial port is on FTDI channel 2 with v1.1 hardware (with channel 0 being JTAG) and on FTDI channel 1 with v1.0 hardware. From 62bfccc2646c14cd54df5cc9b991762fabc289ed Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Feb 2019 19:45:24 +0800 Subject: [PATCH 1670/2457] manual: add info about upgrade/rollback with Nix --- doc/manual/installing.rst | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index e340f5278..fde3879da 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -107,8 +107,17 @@ This activation has to be performed in every new shell you open to make the ARTI .. note:: Some ARTIQ examples also require matplotlib and numba, and they must be installed manually for running those examples. They are available in Conda. -Upgrading ARTIQ ---------------- +Upgrading ARTIQ (with Nix) +-------------------------- + +Run ``nix-channel --update`` to retrieve information about the latest versions, and then either reinstall ARTIQ into the user environment (``nix-env -i python3.6-artiq``) or re-run the ``nix-shell`` command. + +To rollback to the previous version, use ``nix-channel --rollback`` and then re-do the second step. You can switch between versions by passing a parameter to ``--rollback`` (see the ``nix-channel`` documentation). + +You may need to reflash the gateware and firmware of the core device to keep it synchronized with the software. + +Upgrading ARTIQ (with Conda) +---------------------------- When upgrading ARTIQ or when testing different versions it is recommended that new Conda environments are created instead of upgrading the packages in existing environments. Keep previous environments around until you are certain that they are not needed anymore and a new environment is known to work correctly. From 2a60914cb929a9d26b5e15608aa9aefb81631d22 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 21 Feb 2019 00:57:22 +0800 Subject: [PATCH 1671/2457] manual: revamp developing section --- doc/manual/developing.rst | 325 +++----------------------------------- doc/manual/installing.rst | 4 + 2 files changed, 25 insertions(+), 304 deletions(-) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index 1abea614e..c9a3bd457 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -2,307 +2,24 @@ Developing ARTIQ ^^^^^^^^^^^^^^^^ .. warning:: - This section is only for software or FPGA developers who want to modify ARTIQ. The steps described here are not required if you simply want to run experiments with ARTIQ. - -.. note:: - Developing ARTIQ is currently only possible on Linux. - -We describe two different approaches to creating a development environment for ARTIQ. - -The first method uses existing pre-compiled Anaconda packages and the ``artiq-dev`` meta-package for the development environment. -This is fast and convenient because it avoids compiling the entire toolchain. -Consequently, some ARTIQ developers as well as the buildbot that's used for continuous integration all employ this method to build the ``artiq`` Anaconda packages and the bitstreams. -It is completely sufficient to develop and tweak the ARTIQ code and to build -bitstreams. - -But with the meta-pakage developing individual components within the toolchain requires extra care. -Consequently, the second method builds most components in the toolchain from their sources. -This takes time and care to reproduce accurately but it gives absolute control over the components and an immediate handle at developing them. -Some ARTIQ developers use this second method of building the entire toolchain -from sources. -It is only recommended for developers and advanced users. - -.. _develop-from-conda: - -ARTIQ Anaconda development environment -====================================== - - 1. Install ``git`` as recommended for your operating system and distribution. - 2. Obtain ARTIQ:: - - $ git clone --recursive https://github.com/m-labs/artiq ~/artiq-dev/artiq - $ cd ~/artiq-dev/artiq - - Add ``-b release-X`` to the ``git clone`` command if you are building a stable branch of ARTIQ. Replace ``X`` with the major release. The default will fetch the development ``master`` branch. - 3. :ref:`Install Anaconda or Miniconda ` - 4. Create and activate a conda environment named ``artiq-dev`` and install the ``artiq-dev`` package which pulls in all the packages required to develop ARTIQ:: - - $ conda env create -f conda/artiq-dev.yaml - $ source activate artiq-dev - 5. Add the ARTIQ source tree to the environment's search path:: - - $ pip install -e . - 6. :ref:`Install Vivado ` - 7. :ref:`Configure OpenOCD ` - 8. :ref:`Build target binaries ` - 9. :ref:`Flash target binaries ` - -.. _install-from-source: - -Installing ARTIQ from source -============================ - -Preparing the build environment for the core device ---------------------------------------------------- - -These steps are required to generate code that can run on the core -device. They are necessary both for building the firmware -and the ARTIQ kernels. - -* Install required host packages: :: - - $ sudo apt-get install python3.5 pip3 build-essential cmake cargo - -* Create a development directory: :: - - $ mkdir ~/artiq-dev - -* Clone ARTIQ repository: :: - - $ cd ~/artiq-dev - $ git clone --recursive https://github.com/m-labs/artiq - - Add ``-b release-X`` to the ``git clone`` command if you are building a stable branch of ARTIQ (the default will fetch the development ``master`` branch). - -* Install OpenRISC binutils (or1k-linux-...): :: - - $ cd ~/artiq-dev - $ wget https://ftp.gnu.org/gnu/binutils/binutils-2.27.tar.bz2 - $ tar xvf binutils-2.27.tar.bz2 - $ cd binutils-2.27 - $ curl -L 'https://raw.githubusercontent.com/m-labs/conda-recipes/c3effbc26e96c6e246d6e8035f8a07bc52d8ded1/conda/binutils-or1k-linux/fix-R_OR1K_GOTOFF-relocations.patch' | patch -p1 - - $ mkdir build - $ cd build - $ ../configure --target=or1k-linux --prefix=/usr/local - $ make -j4 - $ sudo make install - -.. note:: - We're using an ``or1k-linux`` target because it is necessary to enable - shared library support in ``ld``, not because Linux is involved. - -* Install LLVM and Clang: :: - - $ cd ~/artiq-dev - $ git clone -b artiq-6.0 https://github.com/m-labs/llvm-or1k - $ cd llvm-or1k - $ git clone -b artiq-6.0 https://github.com/m-labs/clang-or1k tools/clang - - $ mkdir build - $ cd build - $ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/llvm-or1k -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=OR1K -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_INSTALL_UTILS=ON -DCLANG_ENABLE_ARCMT=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF - $ make -j4 - $ sudo make install - -* Install Rust: :: - - $ cd ~/artiq-dev - $ git clone -b artiq-1.28.0 https://github.com/m-labs/rust - $ cd rust - $ git submodule update --init --recursive - $ mkdir build - $ cd build - $ ../configure --prefix=/usr/local/rust-or1k --llvm-root=/usr/local/llvm-or1k --disable-manage-submodules --disable-docs - $ sudo mkdir /usr/local/rust-or1k - $ sudo chown $USER.$USER /usr/local/rust-or1k - $ make install - $ cd .. - - $ destdir="/usr/local/rust-or1k/lib/rustlib/or1k-unknown-none/lib/" - $ rustc="rustc --out-dir ${destdir} -L ${destdir} --target or1k-unknown-none -g -C target-feature=+mul,+div,+ffl1,+cmov,+addc -C opt-level=s --crate-type rlib" - $ mkdir -p ${destdir} - $ ${rustc} --crate-name core src/libcore/lib.rs - $ ${rustc} --crate-name compiler_builtins src/libcompiler_builtins/src/lib.rs --cfg $ 'feature="compiler-builtins"' --cfg 'feature="mem"' - $ ${rustc} --crate-name std_unicode src/libstd_unicode/lib.rs - $ ${rustc} --crate-name alloc src/liballoc/lib.rs - $ ${rustc} --crate-name libc src/liblibc_mini/lib.rs - $ ${rustc} --crate-name unwind src/libunwind/lib.rs - $ ${rustc} -Cpanic=abort --crate-name panic_abort src/libpanic_abort/lib.rs - $ ${rustc} -Cpanic=unwind --crate-name panic_unwind src/libpanic_unwind/lib.rs \ - --cfg llvm_libunwind - -.. note:: - Compilation of LLVM can take more than 30 min on some machines. Compilation of Rust can take more than two hours. - -Preparing the core device FPGA board ------------------------------------- - -These steps are required to generate gateware bitstream (``.bit``) files, build the MiSoC BIOS and ARTIQ runtime, and flash FPGA boards. If the board is already flashed, you may skip those steps and go directly to `Installing the host-side software`. - -.. _install-xilinx: - -* Install the FPGA vendor tools (i.e. Vivado): - - * Get Vivado from http://www.xilinx.com/support/download/index.htm. - - * The "appropriate" Vivado version to use for building the bitstream can - vary. Some versions contain bugs that lead to hidden or visible failures, - others work fine. - Refer to the `M-Labs buildbot logs `_ to - determine which version is currently used when building the binary - packages. - - * During the Vivado installation, uncheck ``Install cable drivers`` (they are not required as we use better and open source alternatives). - -* Install Migen: :: - - $ cd ~/artiq-dev - $ git clone https://github.com/m-labs/migen - $ cd migen - $ python3 setup.py develop --user - -.. note:: - The options ``develop`` and ``--user`` are for setup.py to install Migen in ``~/.local/lib/python3.5``. - -.. _install-bscan-spi: - -* Install the required flash proxy gateware bitstreams: - - The purpose of the flash proxy gateware bitstream is to give programming software fast JTAG access to the flash connected to the FPGA. - - * KC705: - - :: - - $ cd ~/artiq-dev - $ wget https://raw.githubusercontent.com/jordens/bscan_spi_bitstreams/master/bscan_spi_xc7k325t.bit - - Then move ``~/artiq-dev/bscan_spi_xc7k325t.bit`` to ``~/.migen``, ``/usr/local/share/migen``, or ``/usr/share/migen``. - -* :ref:`Download and install OpenOCD `. - -* Download and install ``asyncserial``: :: - - $ cd ~/artiq-dev - $ git clone https://www.github.com/m-labs/asyncserial - $ cd asyncserial - $ python3 setup.py develop --user - -* Download and install MiSoC: :: - - $ cd ~/artiq-dev - $ git clone --recursive https://github.com/m-labs/misoc - $ cd misoc - $ python3 setup.py develop --user - -* Download and install ``pythonparser``: :: - - $ cd ~/artiq-dev - $ git clone https://www.github.com/m-labs/pythonparser - $ cd pythonparser - $ python3 setup.py develop --user - -* Download and install ARTIQ: :: - - $ cd ~/artiq-dev - $ git clone --recursive https://github.com/m-labs/artiq - $ cd artiq - $ python3 setup.py develop --user - -.. note:: - If you have any trouble during ARTIQ setup about ``pygit2`` installation, - refer to the section dealing with - :ref:`installing the host-side software `. - - -* Build the gateware bitstream, BIOS and runtime by running: - :: - - $ cd ~/artiq-dev - $ export PATH=/usr/local/llvm-or1k/bin:$PATH - - .. note:: Make sure that ``/usr/local/llvm-or1k/bin`` is first in your ``PATH``, so that the ``clang`` command you just built is found instead of the system one, if any. - -.. _build-target-binaries: - - * For Kasli:: - - $ python3 -m artiq.gateware.targets.kasli -V - - * For KC705:: - - $ python3 -m artiq.gateware.targets.kc705 -V nist_clock # or nist_qc2 - - .. note:: Add ``--toolchain ise`` if you wish to use ISE instead of Vivado. ISE needs a separate installation step. - -.. _flash-target-binaries: - -* Then, flash the binaries: :: - - $ artiq_flash --srcbuild artiq_kasli -V - -* Check that the board boots by running a serial terminal program (you may need to press its FPGA reconfiguration button or power-cycle it to load the gateware bitstream that was newly written into the flash): :: - - $ flterm /dev/ttyUSB1 - MiSoC BIOS http://m-labs.hk - [...] - Booting from flash... - Loading xxxxx bytes from flash... - Executing booted program. - ARTIQ runtime built - -.. note:: flterm is part of MiSoC. If you installed MiSoC with ``setup.py develop --user``, the flterm launcher is in ``~/.local/bin``. - -The communication parameters are 115200 8-N-1. Ensure that your user has access -to the serial device (``sudo adduser $USER dialout`` assuming standard setup). - -.. _installing-the-host-side-software: - -Installing the host-side software ---------------------------------- - -* Install the llvmlite Python bindings: :: - - $ cd ~/artiq-dev - $ git clone https://github.com/m-labs/llvmlite - $ cd llvmlite - $ git checkout artiq-3.9 - $ LLVM_CONFIG=/usr/local/llvm-or1k/bin/llvm-config python3 setup.py install --user - -* Install ARTIQ: :: - - $ cd ~/artiq-dev - $ git clone --recursive https://github.com/m-labs/artiq # if not already done - $ cd artiq - $ python3 setup.py develop --user - -.. note:: - If you have any trouble during ARTIQ setup about ``pygit2`` installation, - you can install it by using ``pip``: - - On Ubuntu 14.04:: - - $ python3 `which pip3` install --user pygit2==0.19.1 - - On Ubuntu 14.10:: - - $ python3 `which pip3` install --user pygit2==0.20.3 - - On Ubuntu 15.04 and 15.10:: - - $ python3 `which pip3` install --user pygit2==0.22.1 - - On Ubuntu 16.04:: - - $ python3 `which pip3` install --user pygit2==0.24.1 - - The rationale behind this is that pygit2 and libgit2 must have the same - major.minor version numbers. - - See http://www.pygit2.org/install.html#version-numbers - -* Build the documentation: :: - - $ cd ~/artiq-dev/artiq/doc/manual - $ make html + This section is only for software or FPGA developers who want to modify ARTIQ. The steps described here are not required if you simply want to run experiments with ARTIQ. If you purchased a system from M-Labs or QUARTIQ, we normally provide board binaries for you. + +The easiest way to obtain an ARTIQ development environment is via the Nix package manager on Linux. The Nix system is used on the `M-Labs Hydra server `_ to build ARTIQ and its dependencies continuously; it ensures that all build instructions are up-to-date and allows binary packages to be used on developers' machines, in particular for large tools such as the Rust compiler. +ARTIQ itself does not depend on Nix, and it is also possible to compile everything from source (look into the ``.nix`` files from the ``nix-scripts`` repository and run the commands manually) - but Nix makes the process a lot easier. + +* Install the `Nix package manager `_ and Git (e.g. ``nix-shell -p git``). +* Set up the M-Labs Hydra channels (:ref:`same procedure as the user section `) to allow binaries to be downloaded. Otherwise, tools such as LLVM and the Rust compiler will be compiled on your machine, which uses a lot of CPU time, memory, and disk space. Simply setting up the channels is sufficient, Nix will automatically detect when a binary can be downloaded instead of being compiled locally. +* Clone the repositories https://github.com/m-labs/artiq and https://github.com/m-labs/nix-scripts. +* Run ``nix-shell -I artiqSrc=path_to_artiq_sources shell-dev.nix`` to obtain an environment containing all the required development tools (e.g. Migen, MiSoC, Clang, Rust, OpenOCD...) in addition to the ARTIQ user environment. ``artiqSrc`` should point to the root of the cloned ``artiq`` repository, and ``shell-dev.nix`` can be found in the ``artiq`` folder of the ``nix-scripts`` repository. +* This enters a FHS chroot environment that simplifies the installation and patching of Xilinx Vivado. +* Download Vivado from Xilinx and install it (by running the official installer in the FHS chroot environment). If you do not want to write to ``/opt``, you can install it in a folder of your home directory. The "appropriate" Vivado version to use for building the bitstream can vary. Some versions contain bugs that lead to hidden or visible failures, others work fine. Refer to the `M-Labs Hydra logs `_ to determine which version is currently used when building the binary packages. +* During the Vivado installation, uncheck ``Install cable drivers`` (they are not required as we use better and open source alternatives). +* You can then build the firmware and gateware with a command such as ``python -m artiq.gateware.targets.kasli``. +* If you did not install Vivado in ``/opt``, add a command line option such as ``--gateware-toolchain-path ~/Xilinx/Vivado``. +* Flash the binaries into the FPGA board with a command such as ``artiq_flash --srcbuild artiq_kasli -V ``. You need to configure OpenOCD as explained :ref:`in the user section `. OpenOCD is already part of the shell started by ``shell-dev.nix``. +* Check that the board boots and examine the UART messages by running a serial terminal program, e.g. ``flterm /dev/ttyUSB1`` (``flterm`` is part of MiSoC and installed by ``shell-dev.nix``). Leave the terminal running while you are flashing the board, so that you see the startup messages when the board boots immediately after flashing. You can also restart the board (without reflashing it) with ``artiq_flash start``. +* The communication parameters are 115200 8-N-1. Ensure that your user has access to the serial device (``sudo adduser $USER dialout`` assuming standard setup). +* If you are modifying a dependency of ARTIQ, in addition to updating the relevant part of ``nix-scripts``, rebuild and upload the corresponding Conda packages manually, and update their version numbers in ``conda-artiq.nix``. For Conda, only the main ARTIQ package and the board packages are handled automatically on Hydra. + +.. warning:: + Nix will make a read-only copy of the ARTIQ source to use in the shell environment. Therefore, any modifications that you make to the source after the shell is started will not be taken into account. A solution applicable to ARTIQ (and several other Python packages such as Migen and MiSoC) is to set the ``PYTHONPATH`` environment variable in the shell to the root of the ARTIQ source. If you want this to be done by default, edit ``profile`` in ``artiq-dev.nix``. diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index fde3879da..99c2b3963 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -9,6 +9,8 @@ Conda has a more traditional approach to package management, is much more limite In the current state of affairs, we recommend that Linux users install ARTIQ via Nix and Windows users install it via Conda. +.. _installing-nix-users: + Installing via Nix (Linux) -------------------------- @@ -157,6 +159,8 @@ With Conda, the ``artiq`` package installs ``openocd`` automatically but it can $ conda install openocd +.. _configuring-openocd: + Configuring OpenOCD ^^^^^^^^^^^^^^^^^^^ From b57cad77ad82d4f7140a90e6426406ca6f58b11a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 21 Feb 2019 14:47:31 +0000 Subject: [PATCH 1672/2457] ad9910: make ram read work for short segments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit also cleanup and style Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 17c3c7a33..29ee86460 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -280,10 +280,12 @@ class AD9910: self.bus.set_config_mu(urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select) self.bus.write((_AD9910_REG_RAM | 0x80) << 24) - self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_INPUT, 32, - urukul.SPIT_DDS_RD, self.chip_select) - preload = 8 - for i in range(len(data) - 1): + n = len(data) - 1 + if n > 0: + self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_INPUT, 32, + urukul.SPIT_DDS_RD, self.chip_select) + preload = min(n, 8) + for i in range(n): self.bus.write(0) if i >= preload: data[i - preload] = self.bus.read() @@ -292,12 +294,12 @@ class AD9910: urukul.SPIT_DDS_RD, self.chip_select) self.bus.write(0) for i in range(preload + 1): - data[(len(data) - preload - 1) + i] = self.bus.read() + data[(n - preload) + i] = self.bus.read() @kernel def set_cfr1(self, power_down=0b0000, phase_autoclear=0, - drg_load_lrr=0, drg_autoclear=0, - internal_profile=0, ram_destination=0, ram_enable=0): + drg_load_lrr=0, drg_autoclear=0, + internal_profile=0, ram_destination=0, ram_enable=0): """Set CFR1. See the AD9910 datasheet for parameter meanings. This method does not pulse IO_UPDATE. @@ -382,8 +384,8 @@ class AD9910: self.set_cfr1(power_down=bits) self.cpld.io_update.pulse(1*us) - # KLUDGE: ref_time_mu default argument is explicitly marked int64() to avoid - # silent truncation of explicitly passed timestamps. (Compiler bug?) + # KLUDGE: ref_time_mu default argument is explicitly marked int64() to + # avoid silent truncation of explicitly passed timestamps. (Compiler bug?) @kernel def set_mu(self, ftw, pow_=0, asf=0x3fff, phase_mode=_PHASE_MODE_DEFAULT, ref_time_mu=int64(-1), profile=0): @@ -430,7 +432,7 @@ class AD9910: dt = int32(now_mu()) - int32(ref_time_mu) pow_ += dt*ftw*self.sysclk_per_mu >> 16 self.write64(_AD9910_REG_PROFILE0 + profile, - (asf << 16) | (pow_ & 0xffff), ftw) + (asf << 16) | (pow_ & 0xffff), ftw) delay_mu(int64(self.io_update_delay)) self.cpld.io_update.pulse_mu(8) # assumes 8 mu > t_SYN_CCLK at_mu(now_mu() & ~7) # clear fine TSC again @@ -446,7 +448,8 @@ class AD9910: :param start: Profile start address in RAM. :param end: Profile end address in RAM (last address). - :param step: Profile address step size (default: 1). + :param step: Profile time step in units of t_DDS, typically 4 ns + (default: 1). :param profile: Profile index (0 to 7) (default: 0). :param nodwell_high: No-dwell high bit (default: 0, see AD9910 documentation). @@ -542,7 +545,8 @@ class AD9910: """ return self.pow_to_turns(self.set_mu( self.frequency_to_ftw(frequency), self.turns_to_pow(phase), - self.amplitude_to_asf(amplitude), phase_mode, ref_time_mu, profile)) + self.amplitude_to_asf(amplitude), phase_mode, ref_time_mu, + profile)) @kernel def set_att_mu(self, att): @@ -739,7 +743,7 @@ class AD9910: t1[0] += self.measure_io_update_alignment(i, i + 1) t1[1] += self.measure_io_update_alignment(i + 1, i + 2) if ((t1[0] == 0 and t1[1] == 0) or - (t1[0] == repeat and t1[1] == repeat)): + (t1[0] == repeat and t1[1] == repeat)): # edge is not close to i + 1, can't interpret result raise ValueError( "no clear IO_UPDATE-SYNC_CLK alignment edge found") From ec6588174bf354b4cecbb962c133b97b91369a37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 21 Feb 2019 14:48:16 +0000 Subject: [PATCH 1673/2457] ad9910: add ram operation unittests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/test/coredevice/test_ad9910.py | 125 ++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_ad9910.py b/artiq/test/coredevice/test_ad9910.py index 462db210f..417ac9c25 100644 --- a/artiq/test/coredevice/test_ad9910.py +++ b/artiq/test/coredevice/test_ad9910.py @@ -1,6 +1,8 @@ from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase -from artiq.coredevice.ad9910 import _AD9910_REG_FTW, _AD9910_REG_PROFILE0 +from artiq.coredevice.ad9910 import ( + _AD9910_REG_FTW, _AD9910_REG_PROFILE0, RAM_MODE_RAMPUP, + RAM_DEST_FTW) from artiq.coredevice.urukul import ( urukul_sta_smp_err, CFG_CLK_SEL0, CFG_CLK_SEL1) @@ -165,6 +167,107 @@ class AD9910Exp(EnvExperiment): delay(100*us) self.set_dataset("ftw", ftw) + @kernel + def ram_write(self): + n = 1 << 10 + write = [0]*n + for i in range(n): + write[i] = i | (i << 16) + read = [0]*n + + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + self.dev.set_cfr1(ram_enable=0) + self.dev.cpld.io_update.pulse_mu(8) + self.dev.set_profile_ram( + start=0, end=0 + n - 1, step=1, + profile=0, mode=RAM_MODE_RAMPUP) + self.dev.cpld.set_profile(0) + self.dev.cpld.io_update.pulse_mu(8) + delay(1*ms) + self.dev.write_ram(write) + delay(1*ms) + self.dev.read_ram(read) + self.set_dataset("w", write) + self.set_dataset("r", read) + + @kernel + def ram_read_overlapping(self): + write = [0]*989 + for i in range(len(write)): + write[i] = i + read = [0]*100 + offset = 367 + + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + self.dev.set_cfr1(ram_enable=0) + self.dev.cpld.io_update.pulse_mu(8) + + self.dev.set_profile_ram( + start=0, end=0 + len(write) - 1, step=1, + profile=0, mode=RAM_MODE_RAMPUP) + self.dev.set_profile_ram( + start=offset, end=offset + len(read) - 1, step=1, + profile=1, mode=RAM_MODE_RAMPUP) + + self.dev.cpld.set_profile(0) + self.dev.cpld.io_update.pulse_mu(8) + delay(1*ms) + self.dev.write_ram(write) + delay(1*ms) + self.dev.cpld.set_profile(1) + self.dev.cpld.io_update.pulse_mu(8) + self.dev.read_ram(read) + + # RAM profile addresses are apparently aligned + # to the last address of the RAM + start = len(write) - offset - len(read) + end = len(write) - offset + self.set_dataset("w", write[start:end]) + self.set_dataset("r", read) + + @kernel + def ram_exec(self): + ftw0 = [0x12345678]*10 + ftw1 = [0x55aaaa55]*10 + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + self.dev.set_cfr1(ram_enable=0) + self.dev.cpld.io_update.pulse_mu(8) + + self.dev.set_profile_ram( + start=100, end=100 + len(ftw0) - 1, step=1, + profile=3, mode=RAM_MODE_RAMPUP) + self.dev.set_profile_ram( + start=200, end=200 + len(ftw1) - 1, step=1, + profile=4, mode=RAM_MODE_RAMPUP) + + self.dev.cpld.set_profile(3) + self.dev.cpld.io_update.pulse_mu(8) + self.dev.write_ram(ftw0) + + self.dev.cpld.set_profile(4) + self.dev.cpld.io_update.pulse_mu(8) + self.dev.write_ram(ftw1) + + self.dev.set_cfr1(ram_enable=1, ram_destination=RAM_DEST_FTW) + self.dev.cpld.io_update.pulse_mu(8) + + self.dev.cpld.set_profile(3) + self.dev.cpld.io_update.pulse_mu(8) + ftw0r = self.dev.read32(_AD9910_REG_FTW) + delay(100*us) + + self.dev.cpld.set_profile(4) + self.dev.cpld.io_update.pulse_mu(8) + ftw1r = self.dev.read32(_AD9910_REG_FTW) + + self.set_dataset("ftw", [ftw0[0], ftw0r, ftw1[0], ftw1r]) + class AD9910Test(ExperimentCase): def test_instantiate(self): @@ -230,3 +333,23 @@ class AD9910Test(ExperimentCase): def test_profile_readback(self): self.execute(AD9910Exp, "profile_readback") self.assertEqual(self.dataset_mgr.get("ftw"), list(range(8))) + + def test_ram_write(self): + self.execute(AD9910Exp, "ram_write") + read = self.dataset_mgr.get("r") + write = self.dataset_mgr.get("w") + self.assertEqual(len(read), len(write)) + self.assertEqual(read, write) + + def test_ram_read_overlapping(self): + self.execute(AD9910Exp, "ram_read_overlapping") + read = self.dataset_mgr.get("r") + write = self.dataset_mgr.get("w") + self.assertEqual(len(read), 100) + self.assertEqual(read, write) + + def test_ram_exec(self): + self.execute(AD9910Exp, "ram_exec") + ftw = self.dataset_mgr.get("ftw") + self.assertEqual(ftw[0], ftw[1]) + self.assertEqual(ftw[2], ftw[3]) From aee896589777f7327c9ce51d09fed06e50519c01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 21 Feb 2019 15:59:52 +0000 Subject: [PATCH 1674/2457] ad9910: add ram conversion tooling and unittests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robert Jördens --- artiq/coredevice/ad9910.py | 58 ++++++++++++++++++++++++++- artiq/test/coredevice/test_ad9910.py | 59 +++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 29ee86460..8da06b275 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -310,8 +310,8 @@ class AD9910: :param drg_autoclear: Autoclear digital ramp generator. :param internal_profile: Internal profile control. :param ram_destination: RAM destination - (:const:`_AD9910_RAM_DEST_FTW`, :const:`_AD9910_RAM_DEST_POW`, - :const:`_AD9910_RAM_DEST_ASF`, :const:`_AD9910_RAM_DEST_POWASF`). + (:const:`RAM_DEST_FTW`, :const:`RAM_DEST_POW`, + :const:`RAM_DEST_ASF`, :const:`RAM_DEST_POWASF`). :param ram_enable: RAM mode enable. """ self.write32(_AD9910_REG_CFR1, @@ -516,6 +516,60 @@ class AD9910: amplitude scale factor.""" return asf / float(0x3ffe) + @portable(flags={"fast-math"}) + def frequency_to_ram(self, frequency, ram): + """Convert frequency values to RAM profile data. + + To be used with :const:`RAM_DEST_FTW`. + + :param frequency: List of frequency values in Hz. + :param ram: List to write RAM data into. + Suitable for :meth:`write_ram`. + """ + for i in range(len(ram)): + ram[i] = self.frequency_to_ftw(frequency[i]) + + @portable(flags={"fast-math"}) + def turns_to_ram(self, turns, ram): + """Convert phase values to RAM profile data. + + To be used with :const:`RAM_DEST_POW`. + + :param turns: List of phase values in turns. + :param ram: List to write RAM data into. + Suitable for :meth:`write_ram`. + """ + for i in range(len(ram)): + ram[i] = self.turns_to_pow(turns[i]) << 16 + + @portable(flags={"fast-math"}) + def amplitude_to_ram(self, amplitude, ram): + """Convert amplitude values to RAM profile data. + + To be used with :const:`RAM_DEST_ASF`. + + :param amplitude: List of amplitude values in units of full scale. + :param ram: List to write RAM data into. + Suitable for :meth:`write_ram`. + """ + for i in range(len(ram)): + ram[i] = self.amplitude_to_asf(amplitude[i]) << 16 + + @portable(flags={"fast-math"}) + def turns_amplitude_to_ram(self, turns, amplitude, ram): + """Convert phase and amplitude values to RAM profile data. + + To be used with :const:`RAM_DEST_POWASF`. + + :param turns: List of phase values in turns. + :param amplitude: List of amplitude values in units of full scale. + :param ram: List to write RAM data into. + Suitable for :meth:`write_ram`. + """ + for i in range(len(ram)): + ram[i] = ((self.turns_to_pow(turns[i]) << 16) | + self.amplitude_to_asf(amplitude[i])) + @kernel def set_frequency(self, frequency): return self.set_ftw(self.frequency_to_ftw(frequency)) diff --git a/artiq/test/coredevice/test_ad9910.py b/artiq/test/coredevice/test_ad9910.py index 417ac9c25..4af554784 100644 --- a/artiq/test/coredevice/test_ad9910.py +++ b/artiq/test/coredevice/test_ad9910.py @@ -231,8 +231,8 @@ class AD9910Exp(EnvExperiment): @kernel def ram_exec(self): - ftw0 = [0x12345678]*10 - ftw1 = [0x55aaaa55]*10 + ftw0 = [0x12345678]*2 + ftw1 = [0x55aaaa55]*2 self.core.break_realtime() self.dev.cpld.init() self.dev.init() @@ -268,6 +268,40 @@ class AD9910Exp(EnvExperiment): self.set_dataset("ftw", [ftw0[0], ftw0r, ftw1[0], ftw1r]) + @kernel + def ram_convert_frequency(self): + freq = [33*MHz]*2 + ram = [0]*len(freq) + self.dev.frequency_to_ram(freq, ram) + + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + self.dev.set_cfr1(ram_enable=0) + self.dev.cpld.io_update.pulse_mu(8) + self.dev.set_profile_ram( + start=100, end=100 + len(ram) - 1, step=1, + profile=6, mode=RAM_MODE_RAMPUP) + self.dev.cpld.set_profile(6) + self.dev.cpld.io_update.pulse_mu(8) + self.dev.write_ram(ram) + self.dev.set_cfr1(ram_enable=1, ram_destination=RAM_DEST_FTW) + self.dev.cpld.io_update.pulse_mu(8) + ftw_read = self.dev.read32(_AD9910_REG_FTW) + self.set_dataset("ram", ram) + self.set_dataset("ftw_read", ftw_read) + self.set_dataset("freq", freq) + + @kernel + def ram_convert_powasf(self): + amplitude = [.1, .9] + turns = [.3, .5] + ram = [0]*2 + self.dev.turns_amplitude_to_ram(turns, amplitude, ram) + self.set_dataset("amplitude", amplitude) + self.set_dataset("turns", turns) + self.set_dataset("ram", ram) + class AD9910Test(ExperimentCase): def test_instantiate(self): @@ -353,3 +387,24 @@ class AD9910Test(ExperimentCase): ftw = self.dataset_mgr.get("ftw") self.assertEqual(ftw[0], ftw[1]) self.assertEqual(ftw[2], ftw[3]) + + def test_ram_convert_frequency(self): + exp = self.execute(AD9910Exp, "ram_convert_frequency") + ram = self.dataset_mgr.get("ram") + ftw_read = self.dataset_mgr.get("ftw_read") + self.assertEqual(ftw_read, ram[0]) + freq = self.dataset_mgr.get("freq") + self.assertEqual(ftw_read, exp.dev.frequency_to_ftw(freq[0])) + self.assertAlmostEqual(freq[0], exp.dev.ftw_to_frequency(ftw_read), + delta=.25) + + def test_ram_convert_powasf(self): + exp = self.execute(AD9910Exp, "ram_convert_powasf") + ram = self.dataset_mgr.get("ram") + amplitude = self.dataset_mgr.get("amplitude") + turns = self.dataset_mgr.get("turns") + for i in range(len(ram)): + self.assertEqual((ram[i] >> 16) & 0xffff, + exp.dev.turns_to_pow(turns[i])) + self.assertEqual(ram[i] & 0xffff, + exp.dev.amplitude_to_asf(amplitude[i])) From 8edc2318ab6d1bd9aa49a97913e61b5f445546a0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Feb 2019 17:19:20 +0800 Subject: [PATCH 1675/2457] style --- artiq/gateware/targets/kasli_generic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index cea12dfd9..efb530b4c 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -124,7 +124,7 @@ def main(): soc_kasli_args(parser) parser.set_defaults(output_dir="artiq_kasli") parser.add_argument("description", metavar="DESCRIPTION", - help="JSON system description file") + help="JSON system description file") args = parser.parse_args() with open(args.description, "r") as f: From 8049c52d0665217a25ea65a41d3ea016c5c66b26 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Feb 2019 17:19:48 +0800 Subject: [PATCH 1676/2457] frontend: add artiq_ddb_template (WIP, TTL only) --- artiq/frontend/artiq_ddb_template.py | 176 +++++++++++++++++++++++++++ setup.py | 1 + 2 files changed, 177 insertions(+) create mode 100755 artiq/frontend/artiq_ddb_template.py diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py new file mode 100755 index 000000000..072a4400a --- /dev/null +++ b/artiq/frontend/artiq_ddb_template.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python3 + +import argparse +import sys +import json +import textwrap +from collections import defaultdict + + +def process_header(output, description): + if description["target"] != "kasli": + raise NotImplementedError + + print(textwrap.dedent(""" + # Autogenerated for the {variant} variant + core_addr = "{core_addr}" + + device_db = {{ + "core": {{ + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {{"host": core_addr, "ref_period": {ref_period}}} + }}, + "core_log": {{ + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {{port}} --bind {{bind}} " + core_addr + }}, + "core_cache": {{ + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }}, + "core_dma": {{ + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + }}, + + "i2c_switch0": {{ + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {{"address": 0xe0}} + }}, + "i2c_switch1": {{ + "type": "local", + "module": "artiq.coredevice.i2c", + "class": "PCA9548", + "arguments": {{"address": 0xe2}} + }}, + }} + """).format( + variant=description["variant"], + core_addr=description.get("core_addr", "192.168.1.70"), + ref_period=1/(8*description.get("rtio_frequency", 125e6))), + file=output) + + +class PeripheralManager: + def __init__(self, output, master_description): + self.counts = defaultdict(int) + self.output = output + self.master_description = master_description + + def get_name(self, ty): + count = self.counts[ty] + self.counts[ty] = count + 1 + return "{}{}".format(ty, count) + + def process_dio(self, rtio_offset, peripheral): + class_names = { + "input": "TTLInOut", + "output": "TTLOut" + } + classes = [ + class_names[peripheral["bank_direction_low"]], + class_names[peripheral["bank_direction_high"]] + ] + for i in range(8): + print(textwrap.dedent(""" + device_db["{name}"] = {{ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "{class_name}", + "arguments": {{"channel": 0x{channel:06x}}}, + }} + """.format( + name=self.get_name("ttl"), + class_name=classes[i//4], + channel=rtio_offset+i)), + file=self.output) + return 8 + + def process_urukul(self, rtio_offset, peripheral): + return 0 + + + def process_sampler(self, rtio_offset, peripheral): + return 0 + + + def process_zotino(self, rtio_offset, peripheral): + return 0 + + + def process_grabber(self, rtio_offset, peripheral): + return 0 + + def process(self, rtio_offset, peripheral): + processor = getattr(self, "process_"+str(peripheral["type"])) + return processor(rtio_offset, peripheral) + + +def process(output, master_description, satellites): + base = master_description["base"] + if base not in ("standalone", "master"): + raise ValueError("Invalid master base") + + if base == "standalone" and satellites: + raise ValueError("A standalone system cannot have satellites") + + process_header(output, master_description) + + pm = PeripheralManager(output, master_description) + + print("# {} peripherals".format(base), file=output) + rtio_offset = 0 + for peripheral in master_description["peripherals"]: + n_channels = pm.process(rtio_offset, peripheral) + rtio_offset += n_channels + + for destination, description in satellites: + if description["base"] != "satellite": + raise ValueError("Invalid base for satellite at destination {}".format(destination)) + + print("# DEST#{} peripherals".format(destination), file=output) + rtio_offset = destination << 16 + for peripheral in description["peripherals"]: + n_channels = pm.process(rtio_offset, peripheral) + rtio_offset += n_channels + + +def main(): + parser = argparse.ArgumentParser( + description="ARTIQ device database template builder") + parser.add_argument("master_description", metavar="MASTER_DESCRIPTION", + help="JSON system description file for the standalone or master node") + parser.add_argument("-o", "--output", + help="output file, defaults to standard output if omitted") + parser.add_argument("-s", "--satellite", nargs=2, action="append", + default=[], metavar=("DESTINATION", "DESCRIPTION"), type=str, + help="add DRTIO satellite at the given destination number with " + "devices from the given JSON description") + + args = parser.parse_args() + + with open(args.master_description, "r") as f: + master_description = json.load(f) + + satellites = [] + for destination, description in args.satellite: + with open(description, "r") as f: + satellites.append((destination, json.load(f))) + + if args.output is not None: + with open(args.output, "w") as f: + process(f, master_description, satellites) + else: + process(sys.stdout, master_description, satellites) + + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index 70187c8b2..a067957d7 100755 --- a/setup.py +++ b/setup.py @@ -24,6 +24,7 @@ console_scripts = [ "artiq_coreanalyzer = artiq.frontend.artiq_coreanalyzer:main", "artiq_coremgmt = artiq.frontend.artiq_coremgmt:main", "artiq_ctlmgr = artiq.frontend.artiq_ctlmgr:main", + "artiq_ddb_template = artiq.frontend.artiq_ddb_template:main", "artiq_devtool = artiq.frontend.artiq_devtool:main", "artiq_influxdb = artiq.frontend.artiq_influxdb:main", "artiq_master = artiq.frontend.artiq_master:main", From 269f0a4d6fa8dd708edd58fba227a668e4caebcb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Feb 2019 19:20:46 +0800 Subject: [PATCH 1677/2457] artiq_ddb_template: add Urukul support --- artiq/frontend/artiq_ddb_template.py | 116 ++++++++++++++++++++++++--- 1 file changed, 106 insertions(+), 10 deletions(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 072a4400a..afe5e2924 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -5,6 +5,7 @@ import sys import json import textwrap from collections import defaultdict +from itertools import count def process_header(output, description): @@ -70,6 +71,9 @@ class PeripheralManager: self.counts[ty] = count + 1 return "{}{}".format(ty, count) + def gen(self, string, **kwargs): + print(textwrap.dedent(string).format(**kwargs), file=self.output) + def process_dio(self, rtio_offset, peripheral): class_names = { "input": "TTLInOut", @@ -80,32 +84,124 @@ class PeripheralManager: class_names[peripheral["bank_direction_high"]] ] for i in range(8): - print(textwrap.dedent(""" + self.gen(""" device_db["{name}"] = {{ "type": "local", "module": "artiq.coredevice.ttl", "class": "{class_name}", "arguments": {{"channel": 0x{channel:06x}}}, }} - """.format( - name=self.get_name("ttl"), - class_name=classes[i//4], - channel=rtio_offset+i)), - file=self.output) + """, + name=self.get_name("ttl"), + class_name=classes[i//4], + channel=rtio_offset+i) return 8 + # TODO: support 1-EEM mode def process_urukul(self, rtio_offset, peripheral): - return 0 - + urukul_name = self.get_name("urukul") + synchronization = peripheral.get("synchronization", False) + channel = count(0) + self.gen(""" + device_db["spi_{name}"]={{ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {{"channel": 0x{channel:06x}}} + }}""", + name=urukul_name, + channel=rtio_offset+next(channel)) + if synchronization: + self.gen(""" + device_db["ttl_{name}_sync"] = {{ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLClockGen", + "arguments": {{"channel": 0x{channel:06x}, "acc_width": 4}} + }}""", + name=urukul_name, + channel=rtio_offset+next(channel)) + self.gen(""" + device_db["ttl_{name}_io_update"] = {{ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {{"channel": 0x{channel:06x}}} + }}""", + name=urukul_name, + channel=rtio_offset+next(channel)) + for i in range(4): + self.gen(""" + device_db["ttl_{name}_sw{uchn}"] = {{ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {{"channel": 0x{channel:06x}}} + }}""", + name=urukul_name, + uchn=i, + channel=rtio_offset+next(channel)) + self.gen(""" + device_db["{name}_cpld"] = {{ + "type": "local", + "module": "artiq.coredevice.urukul", + "class": "CPLD", + "arguments": {{ + "spi_device": "spi_{name}", + "sync_device": {sync_device}, + "io_update_device": "ttl_{name}_io_update", + "refclk": {refclk}, + "clk_sel": {clk_sel} + }} + }}""", + name=urukul_name, + sync_device="\"ttl_{name}_sync\"".format(name=urukul_name) if synchronization else "None", + refclk=peripheral.get("refclk", self.master_description.get("rtio_frequency", 125e6)), + clk_sel=peripheral["clk_sel"]) + dds = peripheral.get("dds", "ad9910") + for i in range(4): + if dds == "ad9910": + self.gen(""" + device_db["{name}_ch{uchn}"] = {{ + "type": "local", + "module": "artiq.coredevice.ad9910", + "class": "AD9910", + "arguments": {{ + "pll_n": 32, + "chip_select": {chip_select}, + "cpld_device": "{name}_cpld", + "sw_device": "ttl_{name}_sw{uchn}" + }} + }}""", + name=urukul_name, + chip_select=4 + i, + uchn=i) + elif dds == "ad9912": + self.gen(""" + device_db["{name}_ch{uchn}"] = {{ + "type": "local", + "module": "artiq.coredevice.ad9912", + "class": "AD9912", + "arguments": {{ + "pll_n": 8, + "chip_select": {chip_select}, + "cpld_device": "{name}_cpld", + "sw_device": "ttl_{name}_sw{uchn}" + }} + }}""", + name=urukul_name, + chip_select=4 + i, + uchn=i) + else: + raise ValueError + return next(channel) def process_sampler(self, rtio_offset, peripheral): return 0 - def process_zotino(self, rtio_offset, peripheral): return 0 - def process_grabber(self, rtio_offset, peripheral): return 0 From cd60803f21c5b004c373a10ce174353bef032bcd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Feb 2019 20:07:15 +0800 Subject: [PATCH 1678/2457] device_ddb_template: add Sampler, Zotino, Grabber and SFP LED support --- artiq/frontend/artiq_ddb_template.py | 97 +++++++++++++++++++++++++++- 1 file changed, 94 insertions(+), 3 deletions(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index afe5e2924..f1c9c3af1 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -197,18 +197,106 @@ class PeripheralManager: return next(channel) def process_sampler(self, rtio_offset, peripheral): - return 0 + self.gen(""" + device_db["spi_{name}_adc"] = {{ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {{"channel": 0x{adc_channel:06x}}} + }} + device_db["spi_{name}_pgia"] = {{ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {{"channel": 0x{pgia_channel:06x}}} + }} + device_db["spi_{name}_cnv"] = {{ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {{"channel": 0x{cnv_channel:06x}}}, + }} + device_db["{name}"] = {{ + "type": "local", + "module": "artiq.coredevice.sampler", + "class": "Sampler", + "arguments": {{ + "spi_adc_device": "spi_{name}_adc", + "spi_pgia_device": "spi_{name}_pgia", + "cnv_device": "spi_{name}_cnv" + }} + }}""", + name=self.get_name("sampler"), + adc_channel=rtio_offset, + pgia_channel=rtio_offset + 1, + cnv_channel=rtio_offset + 2) + return 3 def process_zotino(self, rtio_offset, peripheral): - return 0 + self.gen(""" + device_db["spi_{name}"] = {{ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {{"channel": 0x{spi_channel:06x}}} + }} + device_db["ttl_{name}_ldac"] = {{ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {{"channel": 0x{ldac_channel:06x}}} + }} + device_db["ttl_{name}_clr"] = {{ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {{"channel": 0x{clr_channel:06x}}} + }} + device_db["{name}"] = {{ + "type": "local", + "module": "artiq.coredevice.zotino", + "class": "Zotino", + "arguments": {{ + "spi_device": "spi_{name}", + "ldac_device": "ttl_{name}_ldac", + "clr_device": "ttl_{name}_clr" + }} + }}""", + name=self.get_name("zotino"), + spi_channel=rtio_offset, + ldac_channel=rtio_offset + 1, + clr_channel=rtio_offset + 2) + return 3 def process_grabber(self, rtio_offset, peripheral): - return 0 + self.gen(""" + device_db["{name}"] = {{ + "type": "local", + "module": "artiq.coredevice.grabber", + "class": "Grabber", + "arguments": {{"channel_base": 0x{channel:06x}}} + }}""", + name=self.get_name("grabber"), + channel=rtio_offset) + return 2 def process(self, rtio_offset, peripheral): processor = getattr(self, "process_"+str(peripheral["type"])) return processor(rtio_offset, peripheral) + def add_sfp_leds(self, rtio_offset): + for i in range(2): + self.gen(""" + device_db["{name}"] = {{ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {{"channel": 0x{channel:06x}}} + }}""", + name=self.get_name("led"), + channel=rtio_offset+i) + return 2 + def process(output, master_description, satellites): base = master_description["base"] @@ -227,6 +315,9 @@ def process(output, master_description, satellites): for peripheral in master_description["peripherals"]: n_channels = pm.process(rtio_offset, peripheral) rtio_offset += n_channels + if base == "standalone": + n_channels = pm.add_sfp_leds(rtio_offset) + rtio_offset += n_channels for destination, description in satellites: if description["base"] != "satellite": From 05b128469f8aeecd04487ce8b5e283ff7ce92cb8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Feb 2019 22:59:20 +0800 Subject: [PATCH 1679/2457] artiq_ddb_template: support setting Urukul pll_vco --- artiq/frontend/artiq_ddb_template.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index f1c9c3af1..2665aa215 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -159,6 +159,7 @@ class PeripheralManager: refclk=peripheral.get("refclk", self.master_description.get("rtio_frequency", 125e6)), clk_sel=peripheral["clk_sel"]) dds = peripheral.get("dds", "ad9910") + pll_vco = peripheral.get("pll_vco", None) for i in range(4): if dds == "ad9910": self.gen(""" @@ -170,12 +171,13 @@ class PeripheralManager: "pll_n": 32, "chip_select": {chip_select}, "cpld_device": "{name}_cpld", - "sw_device": "ttl_{name}_sw{uchn}" + "sw_device": "ttl_{name}_sw{uchn}"{pll_vco} }} }}""", name=urukul_name, chip_select=4 + i, - uchn=i) + uchn=i, + pll_vco=",\n\"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "") elif dds == "ad9912": self.gen(""" device_db["{name}_ch{uchn}"] = {{ @@ -186,12 +188,13 @@ class PeripheralManager: "pll_n": 8, "chip_select": {chip_select}, "cpld_device": "{name}_cpld", - "sw_device": "ttl_{name}_sw{uchn}" + "sw_device": "ttl_{name}_sw{uchn}"{pll_vco} }} }}""", name=urukul_name, chip_select=4 + i, - uchn=i) + uchn=i, + pll_vco=",\n\"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "") else: raise ValueError return next(channel) From 1c35c051a5a06ce1e04629ce26867759b9f8c38d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Feb 2019 23:08:49 +0800 Subject: [PATCH 1680/2457] kasli: remove variants supported by generic builder --- .../kasli_basic/device_db_berkeley.py | 248 ------------ artiq/examples/kasli_basic/device_db_mitll.py | 162 -------- .../examples/kasli_basic/device_db_mitll2.py | 225 ----------- artiq/examples/kasli_basic/device_db_nudt.py | 192 --------- artiq/examples/kasli_basic/device_db_sysu.py | 125 ------ .../kasli_basic/device_db_tsinghua.py | 194 --------- .../kasli_basic/device_db_tsinghua2.py | 195 --------- artiq/examples/kasli_basic/device_db_unsw.py | 195 --------- artiq/examples/kasli_basic/device_db_ustc.py | 196 --------- artiq/examples/kasli_basic/device_db_wipm.py | 250 ------------ artiq/gateware/targets/kasli.py | 371 ------------------ 11 files changed, 2353 deletions(-) delete mode 100644 artiq/examples/kasli_basic/device_db_berkeley.py delete mode 100644 artiq/examples/kasli_basic/device_db_mitll.py delete mode 100644 artiq/examples/kasli_basic/device_db_mitll2.py delete mode 100644 artiq/examples/kasli_basic/device_db_nudt.py delete mode 100644 artiq/examples/kasli_basic/device_db_sysu.py delete mode 100644 artiq/examples/kasli_basic/device_db_tsinghua.py delete mode 100644 artiq/examples/kasli_basic/device_db_tsinghua2.py delete mode 100644 artiq/examples/kasli_basic/device_db_unsw.py delete mode 100644 artiq/examples/kasli_basic/device_db_ustc.py delete mode 100644 artiq/examples/kasli_basic/device_db_wipm.py diff --git a/artiq/examples/kasli_basic/device_db_berkeley.py b/artiq/examples/kasli_basic/device_db_berkeley.py deleted file mode 100644 index 4981ccbcd..000000000 --- a/artiq/examples/kasli_basic/device_db_berkeley.py +++ /dev/null @@ -1,248 +0,0 @@ -core_addr = "kasli-1.lab.m-labs.hk" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1.25e-9} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, - - "i2c_switch0": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe0} - }, - "i2c_switch1": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe2} - }, -} - - -device_db.update({ - "ttl" + str(i): { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut" if i < 4 else "TTLOut", - "arguments": {"channel": i}, - } for i in range(16) -}) - -sync_delay_seeds = [ - [15, 15, 15, 16], - [14, 15, 16, 16], - [18, 18, 20, 19], -] - -io_update_delays = [ - [3, 3, 3, 3], - [1, 1, 1, 1], - [3, 3, 3, 3], -] - -for j in range(3): - device_db.update({ - "spi_urukul{}".format(j): { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 16 + 7*j} - }, - "ttl_urukul{}_sync".format(j): { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLClockGen", - "arguments": {"channel": 17 + 7*j, "acc_width": 4} - }, - "ttl_urukul{}_io_update".format(j): { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 18 + 7*j} - }, - "ttl_urukul{}_sw0".format(j): { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 19 + 7*j} - }, - "ttl_urukul{}_sw1".format(j): { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 20 + 7*j} - }, - "ttl_urukul{}_sw2".format(j): { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 21 + 7*j} - }, - "ttl_urukul{}_sw3".format(j): { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 22 + 7*j} - }, - "urukul{}_cpld".format(j): { - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul{}".format(j), - "sync_device": "ttl_urukul{}_sync".format(j), - "io_update_device": "ttl_urukul{}_io_update".format(j), - "refclk": 100e6, - "clk_sel": 2 - } - } - }) - - device_db.update({ - "urukul{}_ch{}".format(j, i): { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "pll_vco": 4, - "chip_select": 4 + i, - "cpld_device": "urukul{}_cpld".format(j), - "sw_device": "ttl_urukul{}_sw{}".format(j, i), - "sync_delay_seed": sync_delay_seeds[j][i], - "io_update_delay": io_update_delays[j][i], - } - } for i in range(4) - }) - - -device_db.update( - spi_urukul3={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 37} - }, - ttl_urukul3_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 38} - }, - ttl_urukul3_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 39} - }, - ttl_urukul3_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 40} - }, - ttl_urukul3_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 41} - }, - ttl_urukul3_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 42} - }, - urukul3_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul3", - "io_update_device": "ttl_urukul3_io_update", - "refclk": 100e6, - "clk_sel": 0 - } - } -) - -for i in range(4): - device_db["urukul3_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9912", - "class": "AD9912", - "arguments": { - "pll_n": 8, - "chip_select": 4 + i, - "cpld_device": "urukul3_cpld", - "sw_device": "ttl_urukul3_sw" + str(i) - } - } - - -device_db.update({ - "spi_zotino0": { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 43} - }, - "ttl_zotino0_ldac": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 44} - }, - "ttl_zotino0_clr": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 45} - }, - "zotino0": { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino0", - "ldac_device": "ttl_zotino0_ldac", - "clr_device": "ttl_zotino0_clr" - } - } -}) - - -device_db.update({ - "led0": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 46} - }, - "led1": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 47} - } -}) diff --git a/artiq/examples/kasli_basic/device_db_mitll.py b/artiq/examples/kasli_basic/device_db_mitll.py deleted file mode 100644 index 66a757176..000000000 --- a/artiq/examples/kasli_basic/device_db_mitll.py +++ /dev/null @@ -1,162 +0,0 @@ -core_addr = "kasli-2.lab.m-labs.hk" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1e-9} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, - - "i2c_switch0": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe0} - }, - "i2c_switch1": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe2} - }, -} - -for i in range(8): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut", - "arguments": {"channel": i}, - } - -device_db.update( - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 8} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 9} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 10} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 11} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 12} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 13} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", - "refclk": 125e6, - "clk_sel": 0 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - -for i in range(2): - device_db["spi_zotino{}".format(i)] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 14+3*i+0} - } - device_db["ttl_zotino{}_ldac".format(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 14+3*i+1} - } - device_db["ttl_zotino{}_clr".format(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 14+3*i+2} - } - device_db["zotino{}".format(i)] = { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino{}".format(i), - "ldac_device": "ttl_zotino{}_ldac".format(i), - "clr_device": "ttl_zotino{}_clr".format(i) - } - } - -device_db["grabber0"] = { - "type": "local", - "module": "artiq.coredevice.grabber", - "class": "Grabber", - "arguments": {"channel_base": 20} -} - -device_db.update( - led0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 22} - }, - led1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 23} - }, -) diff --git a/artiq/examples/kasli_basic/device_db_mitll2.py b/artiq/examples/kasli_basic/device_db_mitll2.py deleted file mode 100644 index dcd003c23..000000000 --- a/artiq/examples/kasli_basic/device_db_mitll2.py +++ /dev/null @@ -1,225 +0,0 @@ -core_addr = "kasli-1.lab.m-labs.hk" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1e-9} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, - - "i2c_switch0": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe0} - }, - "i2c_switch1": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe2} - }, -} - -for i in range(8): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut" if i < 4 else "TTLOut", - "arguments": {"channel": i}, - } - -device_db.update( - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 8} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 9} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 10} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 11} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 12} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 13} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", - "refclk": 125e6, - "clk_sel": 0 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - -device_db.update( - spi_urukul1={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 14} - }, - ttl_urukul1_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 15} - }, - ttl_urukul1_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 16} - }, - ttl_urukul1_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 17} - }, - ttl_urukul1_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 18} - }, - ttl_urukul1_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 19} - }, - urukul1_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul1", - "io_update_device": "ttl_urukul1_io_update", - "refclk": 125e6, - "clk_sel": 0 - } - } -) - -for i in range(4): - device_db["urukul1_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul1_cpld", - "sw_device": "ttl_urukul1_sw" + str(i) - } - } - -for i in range(2): - device_db["spi_zotino{}".format(i)] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 20+3*i+0} - } - device_db["ttl_zotino{}_ldac".format(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 20+3*i+1} - } - device_db["ttl_zotino{}_clr".format(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 20+3*i+2} - } - device_db["zotino{}".format(i)] = { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino{}".format(i), - "ldac_device": "ttl_zotino{}_ldac".format(i), - "clr_device": "ttl_zotino{}_clr".format(i) - } - } - -device_db["grabber0"] = { - "type": "local", - "module": "artiq.coredevice.grabber", - "class": "Grabber", - "arguments": {"channel_base": 26} -} - -device_db.update( - led0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 28} - }, - led1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 29} - }, -) diff --git a/artiq/examples/kasli_basic/device_db_nudt.py b/artiq/examples/kasli_basic/device_db_nudt.py deleted file mode 100644 index b21b53ccb..000000000 --- a/artiq/examples/kasli_basic/device_db_nudt.py +++ /dev/null @@ -1,192 +0,0 @@ -core_addr = "kasli-1.lab.m-labs.hk" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1e-9} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, - - "i2c_switch0": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe0} - }, - "i2c_switch1": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe2} - }, -} - - -# DIO (EEM5) starting at RTIO channel 0 -# DIO (EEM6) starting at RTIO channel 8 -for i in range(16): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut" if i < 4 else "TTLOut", - "arguments": {"channel": i}, - } - - -# Urukul (EEM1) starting at RTIO channel 16 -device_db.update( - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 16} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 17} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 18} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 19} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 20} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 21} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", - "refclk": 125e6, - "clk_sel": 0 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - - -# Sampler (EEM3) starting at RTIO channel 22 -device_db["spi_sampler0_adc"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 22} -} -device_db["spi_sampler0_pgia"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 23} -} -device_db["spi_sampler0_cnv"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 24}, -} -device_db["sampler0"] = { - "type": "local", - "module": "artiq.coredevice.sampler", - "class": "Sampler", - "arguments": { - "spi_adc_device": "spi_sampler0_adc", - "spi_pgia_device": "spi_sampler0_pgia", - "cnv_device": "spi_sampler0_cnv" - } -} - - -# Zotino (EEM4) starting at RTIO channel 25 -device_db["spi_zotino0"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 25} -} -device_db["ttl_zotino0_ldac"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 26} -} -device_db["ttl_zotino0_clr"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 27} -} -device_db["zotino0"] = { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino0", - "ldac_device": "ttl_zotino0_ldac", - "clr_device": "ttl_zotino0_clr" - } -} - -device_db.update( - led0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 28} - }, - led1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 29} - }, -) diff --git a/artiq/examples/kasli_basic/device_db_sysu.py b/artiq/examples/kasli_basic/device_db_sysu.py deleted file mode 100644 index e5e71b9d9..000000000 --- a/artiq/examples/kasli_basic/device_db_sysu.py +++ /dev/null @@ -1,125 +0,0 @@ -core_addr = "kasli-1.lab.m-labs.hk" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1e-9} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, - - "i2c_switch0": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe0} - }, - "i2c_switch1": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe2} - }, -} - -for i in range(40): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut" if i < 16 else "TTLOut", - "arguments": {"channel": i}, - } - -device_db.update( - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 40} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 41} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 42} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 43} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 44} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 45} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", - "refclk": 125e6, - "clk_sel": 0 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - -device_db.update( - led0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 46} - }, - led1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 47} - } -) diff --git a/artiq/examples/kasli_basic/device_db_tsinghua.py b/artiq/examples/kasli_basic/device_db_tsinghua.py deleted file mode 100644 index 9c20b8c83..000000000 --- a/artiq/examples/kasli_basic/device_db_tsinghua.py +++ /dev/null @@ -1,194 +0,0 @@ -core_addr = "kasli-1.lab.m-labs.hk" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1e-9} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, - - "i2c_switch0": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe0} - }, - "i2c_switch1": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe2} - }, -} - - -for i in range(8): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut" if i < 4 else "TTLOut", - "arguments": {"channel": i}, - } - - -device_db.update( - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 8} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 9} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 10} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 11} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 12} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 13} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", - "refclk": 125e6, - "clk_sel": 0 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - - -device_db["spi_sampler0_adc"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 14} -} -device_db["spi_sampler0_pgia"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 15} -} -device_db["spi_sampler0_cnv"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 16}, -} -device_db["sampler0"] = { - "type": "local", - "module": "artiq.coredevice.sampler", - "class": "Sampler", - "arguments": { - "spi_adc_device": "spi_sampler0_adc", - "spi_pgia_device": "spi_sampler0_pgia", - "cnv_device": "spi_sampler0_cnv" - } -} - - -device_db["spi_zotino0"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 17} -} -device_db["ttl_zotino0_ldac"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 18} -} -device_db["ttl_zotino0_clr"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 19} -} -device_db["zotino0"] = { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino0", - "ldac_device": "ttl_zotino0_ldac", - "clr_device": "ttl_zotino0_clr" - } -} - -device_db["grabber0"] = { - "type": "local", - "module": "artiq.coredevice.grabber", - "class": "Grabber", - "arguments": {"channel_base": 20} -} - -device_db.update( - led0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 22} - }, - led1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 23} - }, -) diff --git a/artiq/examples/kasli_basic/device_db_tsinghua2.py b/artiq/examples/kasli_basic/device_db_tsinghua2.py deleted file mode 100644 index 7cf7a18da..000000000 --- a/artiq/examples/kasli_basic/device_db_tsinghua2.py +++ /dev/null @@ -1,195 +0,0 @@ -core_addr = "kasli-1.lab.m-labs.hk" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1e-9} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, - - "i2c_switch0": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe0} - }, - "i2c_switch1": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe2} - }, -} - - -for i in range(8): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut" if i < 4 else "TTLOut", - "arguments": {"channel": i}, - } - - -device_db.update( - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 8} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 9} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 10} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 11} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 12} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 13} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", - "refclk": 125e6, - "clk_sel": 2 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - - -device_db["spi_sampler0_adc"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 14} -} -device_db["spi_sampler0_pgia"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 15} -} -device_db["spi_sampler0_cnv"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 16}, -} -device_db["sampler0"] = { - "type": "local", - "module": "artiq.coredevice.sampler", - "class": "Sampler", - "arguments": { - "spi_adc_device": "spi_sampler0_adc", - "spi_pgia_device": "spi_sampler0_pgia", - "cnv_device": "spi_sampler0_cnv" - } -} - - -for i in range(3): - device_db["spi_zotino{}".format(i)] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 17+3*i} - } - device_db["ttl_zotino{}_ldac".format(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 18+3*i} - } - device_db["ttl_zotino{}_clr".format(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 19+3*i} - } - device_db["zotino{}".format(i)] = { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino{}".format(i), - "ldac_device": "ttl_zotino{}_ldac".format(i), - "clr_device": "ttl_zotino{}_clr".format(i) - } - } - -device_db["grabber0"] = { - "type": "local", - "module": "artiq.coredevice.grabber", - "class": "Grabber", - "arguments": {"channel_base": 26} -} - -device_db.update( - led0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 28} - }, - led1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 29} - }, -) diff --git a/artiq/examples/kasli_basic/device_db_unsw.py b/artiq/examples/kasli_basic/device_db_unsw.py deleted file mode 100644 index a3fce313a..000000000 --- a/artiq/examples/kasli_basic/device_db_unsw.py +++ /dev/null @@ -1,195 +0,0 @@ -core_addr = "kasli-1.lab.m-labs.hk" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1e-9} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, - - "i2c_switch0": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe0} - }, - "i2c_switch1": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe2} - }, -} - - -for i in range(8): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut" if i < 4 else "TTLOut", - "arguments": {"channel": i}, - } - - -device_db.update( - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 8} - }, - ttl_urukul0_sync={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLClockGen", - "arguments": {"channel": 9, "acc_width": 4} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 10} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 11} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 12} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 13} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 14} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "sync_device": "ttl_urukul0_sync", - "io_update_device": "ttl_urukul0_io_update", - "refclk": 125e6, - "clk_sel": 2 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - - -device_db["spi_sampler0_adc"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 15} -} -device_db["spi_sampler0_pgia"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 16} -} -device_db["spi_sampler0_cnv"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 17}, -} -device_db["sampler0"] = { - "type": "local", - "module": "artiq.coredevice.sampler", - "class": "Sampler", - "arguments": { - "spi_adc_device": "spi_sampler0_adc", - "spi_pgia_device": "spi_sampler0_pgia", - "cnv_device": "spi_sampler0_cnv" - } -} - - -device_db["spi_zotino0"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 18} -} -device_db["ttl_zotino0_ldac"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 19} -} -device_db["ttl_zotino0_clr"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 20} -} -device_db["zotino0"] = { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino0", - "ldac_device": "ttl_zotino0_ldac", - "clr_device": "ttl_zotino0_clr" - } -} - - -device_db.update( - led0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 21} - }, - led1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 22} - }, -) diff --git a/artiq/examples/kasli_basic/device_db_ustc.py b/artiq/examples/kasli_basic/device_db_ustc.py deleted file mode 100644 index 4828b18d0..000000000 --- a/artiq/examples/kasli_basic/device_db_ustc.py +++ /dev/null @@ -1,196 +0,0 @@ -core_addr = "kasli-2.lab.m-labs.hk" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1e-9} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, - - "i2c_switch0": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe0} - }, - "i2c_switch1": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe2} - }, -} - -for i in range(24): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut" if i < 4 else "TTLOut", - "arguments": {"channel": i}, - } - -device_db.update( - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 24} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 25} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 26} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 27} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 28} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 29} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", - "refclk": 125e6, - "clk_sel": 0 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - - -device_db.update( - spi_urukul1={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 30} - }, - ttl_urukul1_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 31} - }, - ttl_urukul1_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 32} - }, - ttl_urukul1_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 33} - }, - ttl_urukul1_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 34} - }, - ttl_urukul1_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 35} - }, - urukul1_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul1", - "io_update_device": "ttl_urukul1_io_update", - "refclk": 125e6, - "clk_sel": 0 - } - } -) - -for i in range(4): - device_db["urukul1_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul1_cpld", - "sw_device": "ttl_urukul1_sw" + str(i) - } - } - -device_db["grabber0"] = { - "type": "local", - "module": "artiq.coredevice.grabber", - "class": "Grabber", - "arguments": {"channel_base": 36} -} - -device_db.update( - led0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 38} - }, - led1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 39} - } -) diff --git a/artiq/examples/kasli_basic/device_db_wipm.py b/artiq/examples/kasli_basic/device_db_wipm.py deleted file mode 100644 index 42073ef4f..000000000 --- a/artiq/examples/kasli_basic/device_db_wipm.py +++ /dev/null @@ -1,250 +0,0 @@ -core_addr = "kasli-2.lab.m-labs.hk" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1e-9} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, - - "i2c_switch0": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe0} - }, - "i2c_switch1": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe2} - }, -} - - -for i in range(8): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut" if i < 4 else "TTLOut", - "arguments": {"channel": i}, - } - - -device_db.update( - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 8} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 9} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 10} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 11} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 12} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 13} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", - "refclk": 125e6, - "clk_sel": 0 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - -device_db.update( - spi_urukul1={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 14} - }, - ttl_urukul1_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 15} - }, - ttl_urukul1_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 16} - }, - ttl_urukul1_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 17} - }, - ttl_urukul1_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 18} - }, - ttl_urukul1_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 19} - }, - urukul1_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul1", - "io_update_device": "ttl_urukul1_io_update", - "refclk": 125e6, - "clk_sel": 0 - } - } -) - -for i in range(4): - device_db["urukul1_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9912", - "class": "AD9912", - "arguments": { - "pll_n": 8, - "chip_select": 4 + i, - "cpld_device": "urukul1_cpld", - "sw_device": "ttl_urukul1_sw" + str(i) - } - } - - -device_db["spi_sampler0_adc"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 20} -} -device_db["spi_sampler0_pgia"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 21} -} -device_db["spi_sampler0_cnv"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 22}, -} -device_db["sampler0"] = { - "type": "local", - "module": "artiq.coredevice.sampler", - "class": "Sampler", - "arguments": { - "spi_adc_device": "spi_sampler0_adc", - "spi_pgia_device": "spi_sampler0_pgia", - "cnv_device": "spi_sampler0_cnv" - } -} - - -device_db["spi_zotino0"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 23} -} -device_db["ttl_zotino0_ldac"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 24} -} -device_db["ttl_zotino0_clr"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 25} -} -device_db["zotino0"] = { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino0", - "ldac_device": "ttl_zotino0_ldac", - "clr_device": "ttl_zotino0_clr" - } -} - -device_db.update( - led0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 26} - }, - led1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 27} - }, -) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 098364512..a7853f8eb 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -235,376 +235,6 @@ class SUServo(StandaloneBase): pads.clkout, self.crg.cd_sys.clk) -class SYSU(StandaloneBase): - def __init__(self, hw_rev=None, **kwargs): - if hw_rev is None: - hw_rev = "v1.0" - StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - - self.config["SI5324_AS_SYNTHESIZER"] = None - self.config["RTIO_FREQUENCY"] = "125.0" - if hw_rev == "v1.0": - # EEM clock fan-out from Si5324, not MMCX - self.comb += self.platform.request("clk_sel").eq(1) - - self.rtio_channels = [] - eem.DIO.add_std(self, 2, - ttl_serdes_7series.InOut_8X, ttl_serdes_7series.InOut_8X) - eem.DIO.add_std(self, 3, - ttl_serdes_7series.InOut_8X, ttl_serdes_7series.InOut_8X) - for i in range(4, 7): - eem.DIO.add_std(self, i, - ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 1, 0, ttl_serdes_7series.Output_8X) - - for i in (1, 2): - sfp_ctl = self.platform.request("sfp_ctl", i) - phy = ttl_simple.Output(sfp_ctl.led) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) - self.rtio_channels.append(rtio.LogChannel()) - - self.add_rtio(self.rtio_channels) - - -class MITLL(StandaloneBase): - def __init__(self, hw_rev=None, **kwargs): - if hw_rev is None: - hw_rev = "v1.1" - StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - - self.config["SI5324_AS_SYNTHESIZER"] = None - self.config["RTIO_FREQUENCY"] = "125.0" - if hw_rev == "v1.0": - # EEM clock fan-out from Si5324, not MMCX - self.comb += self.platform.request("clk_sel").eq(1) - - self.rtio_channels = [] - self.grabber_csr_group = [] - eem.DIO.add_std(self, 4, - ttl_serdes_7series.InOut_8X, ttl_serdes_7series.InOut_8X) - eem.Urukul.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 5, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 6, ttl_serdes_7series.Output_8X) - eem.Grabber.add_std(self, 1, 0) - - for i in (1, 2): - sfp_ctl = self.platform.request("sfp_ctl", i) - phy = ttl_simple.Output(sfp_ctl.led) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) - self.rtio_channels.append(rtio.LogChannel()) - - self.add_rtio(self.rtio_channels) - self.config["HAS_GRABBER"] = None - self.add_csr_group("grabber", self.grabber_csr_group) - self.platform.add_false_path_constraints( - self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) - - -class MITLL2(StandaloneBase): - def __init__(self, hw_rev=None, **kwargs): - if hw_rev is None: - hw_rev = "v1.1" - StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - - self.config["SI5324_AS_SYNTHESIZER"] = None - self.config["RTIO_FREQUENCY"] = "125.0" - if hw_rev == "v1.0": - # EEM clock fan-out from Si5324, not MMCX - self.comb += self.platform.request("clk_sel").eq(1) - - self.rtio_channels = [] - self.grabber_csr_group = [] - eem.DIO.add_std(self, 5, - ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 2, 1, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 4, 3, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 6, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) - eem.Grabber.add_std(self, 0) - - for i in (1, 2): - sfp_ctl = self.platform.request("sfp_ctl", i) - phy = ttl_simple.Output(sfp_ctl.led) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) - self.rtio_channels.append(rtio.LogChannel()) - - self.add_rtio(self.rtio_channels) - self.config["HAS_GRABBER"] = None - self.add_csr_group("grabber", self.grabber_csr_group) - self.platform.add_false_path_constraints( - self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) - - -class USTC(StandaloneBase): - def __init__(self, hw_rev=None, **kwargs): - if hw_rev is None: - hw_rev = "v1.1" - StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - - self.config["SI5324_AS_SYNTHESIZER"] = None - self.config["RTIO_FREQUENCY"] = "125.0" - if hw_rev == "v1.0": - # EEM clock fan-out from Si5324, not MMCX - self.comb += self.platform.request("clk_sel").eq(1) - - self.rtio_channels = [] - self.grabber_csr_group = [] - eem.DIO.add_std(self, 5, - ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) - eem.DIO.add_std(self, 6, - ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) - eem.DIO.add_std(self, 7, - ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 2, 1, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 4, 3, ttl_serdes_7series.Output_8X) - eem.Grabber.add_std(self, 0) - - for i in (1, 2): - sfp_ctl = self.platform.request("sfp_ctl", i) - phy = ttl_simple.Output(sfp_ctl.led) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) - self.rtio_channels.append(rtio.LogChannel()) - - self.add_rtio(self.rtio_channels) - self.config["HAS_GRABBER"] = None - self.add_csr_group("grabber", self.grabber_csr_group) - self.platform.add_false_path_constraints( - self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) - - -class Tsinghua(StandaloneBase): - def __init__(self, hw_rev=None, **kwargs): - if hw_rev is None: - hw_rev = "v1.1" - StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - - self.config["SI5324_AS_SYNTHESIZER"] = None - self.config["RTIO_FREQUENCY"] = "125.0" - if hw_rev == "v1.0": - # EEM clock fan-out from Si5324, not MMCX - self.comb += self.platform.request("clk_sel").eq(1) - - self.rtio_channels = [] - self.grabber_csr_group = [] - eem.DIO.add_std(self, 4, - ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) - eem.Sampler.add_std(self, 6, 5, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) - eem.Grabber.add_std(self, 1, 0) - - for i in (1, 2): - sfp_ctl = self.platform.request("sfp_ctl", i) - phy = ttl_simple.Output(sfp_ctl.led) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) - self.rtio_channels.append(rtio.LogChannel()) - - self.add_rtio(self.rtio_channels) - self.config["HAS_GRABBER"] = None - self.add_csr_group("grabber", self.grabber_csr_group) - self.platform.add_false_path_constraints( - self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) - - -class Tsinghua2(StandaloneBase): - def __init__(self, hw_rev=None, **kwargs): - if hw_rev is None: - hw_rev = "v1.1" - StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - - self.config["SI5324_AS_SYNTHESIZER"] = None - self.config["RTIO_FREQUENCY"] = "125.0" - if hw_rev == "v1.0": - # EEM clock fan-out from Si5324, not MMCX - self.comb += self.platform.request("clk_sel").eq(1) - - self.rtio_channels = [] - self.grabber_csr_group = [] - eem.DIO.add_std(self, 4, - ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 2, 3, ttl_serdes_7series.Output_8X) - eem.Sampler.add_std(self, 5, 6, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 8, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 9, ttl_serdes_7series.Output_8X) - eem.Grabber.add_std(self, 1, 0) - - for i in (1, 2): - sfp_ctl = self.platform.request("sfp_ctl", i) - phy = ttl_simple.Output(sfp_ctl.led) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) - self.rtio_channels.append(rtio.LogChannel()) - - self.add_rtio(self.rtio_channels) - self.config["HAS_GRABBER"] = None - self.add_csr_group("grabber", self.grabber_csr_group) - self.platform.add_false_path_constraints( - self.rtio_crg.cd_rtio.clk, self.grabber0.deserializer.cd_cl.clk) - - -class WIPM(StandaloneBase): - def __init__(self, hw_rev=None, **kwargs): - if hw_rev is None: - hw_rev = "v1.1" - StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - - self.config["SI5324_AS_SYNTHESIZER"] = None - self.config["RTIO_FREQUENCY"] = "125.0" - if hw_rev == "v1.0": - # EEM clock fan-out from Si5324, not MMCX - self.comb += self.platform.request("clk_sel").eq(1) - - self.rtio_channels = [] - eem.DIO.add_std(self, 4, - ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 1, 0, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) - eem.Sampler.add_std(self, 6, 5, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) - - for i in (1, 2): - sfp_ctl = self.platform.request("sfp_ctl", i) - phy = ttl_simple.Output(sfp_ctl.led) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) - self.rtio_channels.append(rtio.LogChannel()) - - self.add_rtio(self.rtio_channels) - - -class NUDT(StandaloneBase): - def __init__(self, hw_rev=None, **kwargs): - if hw_rev is None: - hw_rev = "v1.1" - StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - - self.config["SI5324_AS_SYNTHESIZER"] = None - # self.config["SI5324_EXT_REF"] = None - self.config["RTIO_FREQUENCY"] = "125.0" - if hw_rev == "v1.0": - # EEM clock fan-out from Si5324, not MMCX - self.comb += self.platform.request("clk_sel").eq(1) - - self.rtio_channels = [] - eem.DIO.add_std(self, 5, - ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) - eem.DIO.add_std(self, 6, - ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 0, 1, ttl_serdes_7series.Output_8X) - eem.Sampler.add_std(self, 2, 3, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 4, ttl_serdes_7series.Output_8X) - - for i in (1, 2): - sfp_ctl = self.platform.request("sfp_ctl", i) - phy = ttl_simple.Output(sfp_ctl.led) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) - self.rtio_channels.append(rtio.LogChannel()) - self.add_rtio(self.rtio_channels) - - -class Berkeley(StandaloneBase): - def __init__(self, hw_rev=None, **kwargs): - if hw_rev is None: - hw_rev = "v1.1" - StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - - self.config["SI5324_AS_SYNTHESIZER"] = None - # self.config["SI5324_EXT_REF"] = None - self.config["RTIO_FREQUENCY"] = "100.0" - if hw_rev == "v1.0": - # EEM clock fan-out from Si5324, not MMCX - self.comb += self.platform.request("clk_sel").eq(1) - - self.rtio_channels = [] - eem.DIO.add_std(self, 0, - ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) - eem.DIO.add_std(self, 1, - ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 2, 3, ttl_serdes_7series.Output_8X, - ttl_simple.ClockGen) - eem.Urukul.add_std(self, 4, 5, ttl_serdes_7series.Output_8X, - ttl_simple.ClockGen) - eem.Urukul.add_std(self, 6, 7, ttl_serdes_7series.Output_8X, - ttl_simple.ClockGen) - eem.Urukul.add_std(self, 9, 8, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 10, ttl_serdes_7series.Output_8X) - - for i in (1, 2): - sfp_ctl = self.platform.request("sfp_ctl", i) - phy = ttl_simple.Output(sfp_ctl.led) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) - self.rtio_channels.append(rtio.LogChannel()) - self.add_rtio(self.rtio_channels) - - -class UNSW(StandaloneBase): - def __init__(self, hw_rev=None, **kwargs): - if hw_rev is None: - hw_rev = "v1.1" - StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) - - self.config["SI5324_AS_SYNTHESIZER"] = None - # self.config["SI5324_EXT_REF"] = None - self.config["RTIO_FREQUENCY"] = "125.0" - if hw_rev == "v1.0": - # EEM clock fan-out from Si5324, not MMCX - self.comb += self.platform.request("clk_sel").eq(1) - - self.rtio_channels = [] - eem.DIO.add_std(self, 0, - ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 1, 2, ttl_serdes_7series.Output_8X, - ttl_simple.ClockGen) - eem.Sampler.add_std(self, 3, 4, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 5, ttl_serdes_7series.Output_8X) - - for i in (1, 2): - sfp_ctl = self.platform.request("sfp_ctl", i) - phy = ttl_simple.Output(sfp_ctl.led) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) - self.rtio_channels.append(rtio.LogChannel()) - self.add_rtio(self.rtio_channels) - - class PTB(StandaloneBase): """PTB Kasli variant @@ -1319,7 +949,6 @@ class HUSTSatellite(SatelliteBase): VARIANTS = {cls.__name__.lower(): cls for cls in [ Opticlock, SUServo, PTB, PTB2, HUB, LUH, - SYSU, MITLL, MITLL2, USTC, Tsinghua, Tsinghua2, WIPM, NUDT, Berkeley, UNSW, VLBAIMaster, VLBAISatellite, HUSTMaster, HUSTSatellite, Tester, Master, Satellite]} From 62985fbd294d75fda09167507d037ff5abd2b1f5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Feb 2019 23:18:01 +0800 Subject: [PATCH 1681/2457] binaries -> board-support --- artiq/frontend/artiq_flash.py | 2 +- conda/artiq-board/build.sh | 2 +- conda/artiq-sayma_rtm/build.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index bece15b71..a311a1647 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -302,7 +302,7 @@ def main(): bin_name = args.target if variant: bin_name += "-" + variant - bin_dir = os.path.join(artiq_dir, "binaries", bin_name) + bin_dir = os.path.join(artiq_dir, "board-support", bin_name) if args.host is None: client = LocalClient() diff --git a/conda/artiq-board/build.sh b/conda/artiq-board/build.sh index ecf684b33..af9264562 100644 --- a/conda/artiq-board/build.sh +++ b/conda/artiq-board/build.sh @@ -2,7 +2,7 @@ set -e -SOC_PREFIX=$PREFIX/site-packages/artiq/binaries/${ARTIQ_TARGET}-${ARTIQ_VARIANT} +SOC_PREFIX=$PREFIX/site-packages/artiq/board-support/${ARTIQ_TARGET}-${ARTIQ_VARIANT} mkdir -p ${SOC_PREFIX} V=1 $PYTHON -m artiq.gateware.targets.${ARTIQ_TARGET} -V ${ARTIQ_VARIANT} diff --git a/conda/artiq-sayma_rtm/build.sh b/conda/artiq-sayma_rtm/build.sh index eceae8698..4371b299c 100644 --- a/conda/artiq-sayma_rtm/build.sh +++ b/conda/artiq-sayma_rtm/build.sh @@ -2,7 +2,7 @@ set -e -SOC_PREFIX=$SP_DIR/artiq/binaries/sayma_rtm +SOC_PREFIX=$SP_DIR/artiq/board-support/sayma_rtm mkdir -p $SOC_PREFIX $PYTHON -m artiq.gateware.targets.sayma_rtm From d79a6ee41c2d5c6be12b7d42d937e36d05db68b3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 22 Feb 2019 23:50:30 +0800 Subject: [PATCH 1682/2457] artiq_ddb_template: fix pll_vco indentation --- artiq/frontend/artiq_ddb_template.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 2665aa215..42466d541 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -177,7 +177,7 @@ class PeripheralManager: name=urukul_name, chip_select=4 + i, uchn=i, - pll_vco=",\n\"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "") + pll_vco=",\n \"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "") elif dds == "ad9912": self.gen(""" device_db["{name}_ch{uchn}"] = {{ @@ -194,7 +194,7 @@ class PeripheralManager: name=urukul_name, chip_select=4 + i, uchn=i, - pll_vco=",\n\"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "") + pll_vco=",\n \"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "") else: raise ValueError return next(channel) From d39338d59fd84762d02ed035726fc8d8916d6c9a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 23 Feb 2019 15:27:18 +0800 Subject: [PATCH 1683/2457] artiq_ddb_template: fix --satellite --- artiq/frontend/artiq_ddb_template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 42466d541..a625a2fc7 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -353,7 +353,7 @@ def main(): satellites = [] for destination, description in args.satellite: with open(description, "r") as f: - satellites.append((destination, json.load(f))) + satellites.append((int(destination, 0), json.load(f))) if args.output is not None: with open(args.output, "w") as f: From 791f830ef6774a6592ebc843aad249d8e930c1eb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 23 Feb 2019 15:41:05 +0800 Subject: [PATCH 1684/2457] kasli_generic: support DRTIO --- artiq/gateware/targets/kasli_generic.py | 64 +++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index efb530b4c..6f5310acd 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -117,6 +117,70 @@ class GenericStandalone(StandaloneBase): self.rtio_crg.cd_rtio.clk, getattr(self, grabber).deserializer.cd_cl.clk) +class GenericMaster(MasterBase): + def __init__(self, description, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = description["hw_rev"] + MasterBase.__init__(self, + hw_rev=hw_rev, + rtio_clk_freq=description.get("rtio_frequency", 125e6), + enable_sata=description.get("enable_sata_drtio", False), + **kwargs) + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) + + has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"]) + if has_grabber: + self.grabber_csr_group = [] + + self.rtio_channels = [] + add_peripherals(self, description["peripherals"]) + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(self.rtio_channels) + if has_grabber: + self.config["HAS_GRABBER"] = None + self.add_csr_group("grabber", self.grabber_csr_group) + for grabber in self.grabber_csr_group: + self.platform.add_false_path_constraints( + self.drtio_transceiver.gtps[0].txoutclk, getattr(self, grabber).deserializer.cd_cl.clk) + + +class GenericSatellite(SatelliteBase): + def __init__(self, description, hw_rev=None, **kwargs): + if hw_rev is None: + hw_rev = description["hw_rev"] + SatelliteBase.__init__(self, + hw_rev=hw_rev, + rtio_clk_freq=description.get("rtio_frequency", 125e6), + enable_sata=description.get("enable_sata_drtio", False), + **kwargs) + if hw_rev == "v1.0": + # EEM clock fan-out from Si5324, not MMCX + self.comb += self.platform.request("clk_sel").eq(1) + + has_grabber = any(peripheral["type"] == "grabber" for peripheral in description["peripherals"]) + if has_grabber: + self.grabber_csr_group = [] + + self.rtio_channels = [] + add_peripherals(self, description["peripherals"]) + self.config["HAS_RTIO_LOG"] = None + self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) + self.rtio_channels.append(rtio.LogChannel()) + + self.add_rtio(self.rtio_channels) + if has_grabber: + self.config["HAS_GRABBER"] = None + self.add_csr_group("grabber", self.grabber_csr_group) + for grabber in self.grabber_csr_group: + self.platform.add_false_path_constraints( + self.drtio_transceiver.gtps[0].txoutclk, getattr(self, grabber).deserializer.cd_cl.clk) + + def main(): parser = argparse.ArgumentParser( description="ARTIQ device binary builder for generic Kasli systems") From de3992bbdd106bc30eed6614e12e258ad0f9b3cb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 23 Feb 2019 15:44:17 +0800 Subject: [PATCH 1685/2457] kasli: remove HUST variants (supported by kasli_generic) --- artiq/examples/kasli_basic/device_db_hust.py | 323 ------------------- artiq/gateware/targets/kasli.py | 50 +-- 2 files changed, 1 insertion(+), 372 deletions(-) delete mode 100644 artiq/examples/kasli_basic/device_db_hust.py diff --git a/artiq/examples/kasli_basic/device_db_hust.py b/artiq/examples/kasli_basic/device_db_hust.py deleted file mode 100644 index 07d861766..000000000 --- a/artiq/examples/kasli_basic/device_db_hust.py +++ /dev/null @@ -1,323 +0,0 @@ -core_addr = "kasli-1.lab.m-labs.hk" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1e-9} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - "core_dma": { - "type": "local", - "module": "artiq.coredevice.dma", - "class": "CoreDMA" - }, - - "i2c_switch0": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe0} - }, - "i2c_switch1": { - "type": "local", - "module": "artiq.coredevice.i2c", - "class": "PCA9548", - "arguments": {"address": 0xe2} - }, -} - -kasli2 = 0x010000 - -for i in range(16): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut" if i < 4 else "TTLOut", - "arguments": {"channel": i}, - } - -for i in range(8): - device_db["ttl" + str(16+i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": kasli2 | i}, - } - -device_db.update( - spi_urukul0={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 16} - }, - ttl_urukul0_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 17} - }, - ttl_urukul0_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 18} - }, - ttl_urukul0_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 19} - }, - ttl_urukul0_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 20} - }, - ttl_urukul0_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 21} - }, - urukul0_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul0", - "io_update_device": "ttl_urukul0_io_update", - "refclk": 125e6, - "clk_sel": 2 - } - } -) - -for i in range(4): - device_db["urukul0_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) - } - } - - -device_db.update( - spi_urukul1={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 22} - }, - ttl_urukul1_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 23} - }, - ttl_urukul1_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 24} - }, - ttl_urukul1_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 25} - }, - ttl_urukul1_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 26} - }, - ttl_urukul1_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 27} - }, - urukul1_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul1", - "io_update_device": "ttl_urukul1_io_update", - "refclk": 125e6, - "clk_sel": 2 - } - } -) - -for i in range(4): - device_db["urukul1_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9910", - "class": "AD9910", - "arguments": { - "pll_n": 32, - "chip_select": 4 + i, - "cpld_device": "urukul1_cpld", - "sw_device": "ttl_urukul1_sw" + str(i) - } - } - - -device_db.update( - spi_urukul2={ - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": kasli2 | 12} - }, - ttl_urukul2_io_update={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": kasli2 | 13} - }, - ttl_urukul2_sw0={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": kasli2 | 14} - }, - ttl_urukul2_sw1={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": kasli2 | 15} - }, - ttl_urukul2_sw2={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": kasli2 | 16} - }, - ttl_urukul2_sw3={ - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": kasli2 | 17} - }, - urukul2_cpld={ - "type": "local", - "module": "artiq.coredevice.urukul", - "class": "CPLD", - "arguments": { - "spi_device": "spi_urukul2", - "io_update_device": "ttl_urukul2_io_update", - "refclk": 125e6, - "clk_sel": 0 - } - } -) - -for i in range(4): - device_db["urukul2_ch" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ad9912", - "class": "AD9912", - "arguments": { - "pll_n": 8, - "chip_select": 4 + i, - "cpld_device": "urukul2_cpld", - "sw_device": "ttl_urukul2_sw" + str(i) - } - } - - -device_db["spi_sampler0_adc"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 28} -} -device_db["spi_sampler0_pgia"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": 29} -} -device_db["spi_sampler0_cnv"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 30}, -} -device_db["sampler0"] = { - "type": "local", - "module": "artiq.coredevice.sampler", - "class": "Sampler", - "arguments": { - "spi_adc_device": "spi_sampler0_adc", - "spi_pgia_device": "spi_sampler0_pgia", - "cnv_device": "spi_sampler0_cnv" - } -} - - -device_db["grabber0"] = { - "type": "local", - "module": "artiq.coredevice.grabber", - "class": "Grabber", - "arguments": {"channel_base": kasli2 | 8} -} - -device_db["grabber1"] = { - "type": "local", - "module": "artiq.coredevice.grabber", - "class": "Grabber", - "arguments": {"channel_base": kasli2 | 10} -} - - -device_db["spi_zotino0"] = { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "SPIMaster", - "arguments": {"channel": kasli2 | 18} -} -device_db["ttl_zotino0_ldac"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": kasli2 | 19} -} -device_db["ttl_zotino0_clr"] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": kasli2 | 20} -} -device_db["zotino0"] = { - "type": "local", - "module": "artiq.coredevice.zotino", - "class": "Zotino", - "arguments": { - "spi_device": "spi_zotino0", - "ldac_device": "ttl_zotino0_ldac", - "clr_device": "ttl_zotino0_clr" - } -} diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index a7853f8eb..e47bb3d1d 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -899,57 +899,9 @@ class VLBAISatellite(SatelliteBase): self.add_rtio(self.rtio_channels) -class HUSTMaster(MasterBase): - def __init__(self, hw_rev=None, *args, **kwargs): - if hw_rev is None: - hw_rev = "v1.1" - MasterBase.__init__(self, rtio_clk_freq=125e6, hw_rev=hw_rev, - enable_sata=True, *args, **kwargs) - - self.rtio_channels = [] - eem.DIO.add_std(self, 0, - ttl_serdes_7series.InOut_8X, ttl_serdes_7series.Output_8X) - eem.DIO.add_std(self, 1, - ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 2, 3, ttl_serdes_7series.Output_8X) - eem.Urukul.add_std(self, 4, 5, ttl_serdes_7series.Output_8X) - eem.Sampler.add_std(self, 6, 7, ttl_serdes_7series.Output_8X) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) - self.rtio_channels.append(rtio.LogChannel()) - - self.add_rtio(self.rtio_channels) - - -class HUSTSatellite(SatelliteBase): - def __init__(self, hw_rev=None, *args, **kwargs): - if hw_rev is None: - hw_rev = "v1.1" - SatelliteBase.__init__(self, rtio_clk_freq=125e6, hw_rev=hw_rev, - enable_sata=True, *args, **kwargs) - - self.rtio_channels = [] - self.grabber_csr_group = [] - eem.DIO.add_std(self, 0, - ttl_serdes_7series.Output_8X, ttl_serdes_7series.Output_8X) - eem.Grabber.add_std(self, 1, 2) - eem.Grabber.add_std(self, 3, 4) - eem.Urukul.add_std(self, 6, 5, ttl_serdes_7series.Output_8X) - eem.Zotino.add_std(self, 7, ttl_serdes_7series.Output_8X) - - self.add_rtio(self.rtio_channels) - self.config["HAS_GRABBER"] = None - self.add_csr_group("grabber", self.grabber_csr_group) - self.platform.add_false_path_constraints( - self.drtio_transceiver.gtps[0].txoutclk, self.grabber0.deserializer.cd_cl.clk) - self.platform.add_false_path_constraints( - self.drtio_transceiver.gtps[0].txoutclk, self.grabber1.deserializer.cd_cl.clk) - - VARIANTS = {cls.__name__.lower(): cls for cls in [ Opticlock, SUServo, PTB, PTB2, HUB, LUH, - VLBAIMaster, VLBAISatellite, HUSTMaster, HUSTSatellite, + VLBAIMaster, VLBAISatellite, Tester, Master, Satellite]} From d45249197c82f227a2ee7a79629e9abc1fab4cfb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 25 Feb 2019 23:00:01 +0800 Subject: [PATCH 1686/2457] siphaser: improve ultrascale clock routing --- artiq/gateware/drtio/siphaser.py | 11 ++++++++--- artiq/gateware/targets/sayma_amc.py | 3 +-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/drtio/siphaser.py b/artiq/gateware/drtio/siphaser.py index c9791d6de..81dacaed0 100644 --- a/artiq/gateware/drtio/siphaser.py +++ b/artiq/gateware/drtio/siphaser.py @@ -9,7 +9,7 @@ from misoc.interconnect.csr import * class SiPhaser7Series(Module, AutoCSR): def __init__(self, si5324_clkin, rx_synchronizer, - ref_clk=None, ref_div2=False, rtio_clk_freq=150e6): + ref_clk=None, ref_div2=False, ultrascale=False, rtio_clk_freq=150e6): self.switch_clocks = CSRStorage() self.phase_shift = CSR() self.phase_shift_done = CSRStatus(reset=1) @@ -22,7 +22,7 @@ class SiPhaser7Series(Module, AutoCSR): # we do not use the crystal reference so that the PFD (f3) frequency # can be high. mmcm_freerun_fb = Signal() - mmcm_freerun_output = Signal() + mmcm_freerun_output_raw = Signal() self.specials += \ Instance("MMCME2_BASE", p_CLKIN1_PERIOD=16.0 if ref_div2 else 8.0, @@ -35,8 +35,13 @@ class SiPhaser7Series(Module, AutoCSR): o_CLKFBOUT=mmcm_freerun_fb, i_CLKFBIN=mmcm_freerun_fb, p_CLKOUT0_DIVIDE_F=750e6/rtio_clk_freq, - o_CLKOUT0=mmcm_freerun_output, + o_CLKOUT0=mmcm_freerun_output_raw, ) + if ultrascale: + mmcm_freerun_output = Signal() + self.specials += Instance("BUFG", i_I=mmcm_freerun_output_raw, o_O=mmcm_freerun_output) + else: + mmcm_freerun_output = mmcm_freerun_output_raw # 125MHz/150MHz to 125MHz/150MHz with controllable phase shift, # VCO @ 1000MHz/1200MHz. diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 5978d2e89..e19c49fe2 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -559,9 +559,8 @@ class Satellite(BaseSoC, RTMCommon): self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), rx_synchronizer=self.rx_synchronizer, + ultrascale=True, rtio_clk_freq=rtio_clk_freq) - platform.add_platform_command("set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets {mmcm_ps}]", - mmcm_ps=self.siphaser.mmcm_ps_output) platform.add_false_path_constraints( self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) self.csr_devices.append("siphaser") From 62c7f75a9ec11891a43410c1a6e36cfcf801e60b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 25 Feb 2019 23:49:45 +0800 Subject: [PATCH 1687/2457] sayma_amc: support hardware revisions --- artiq/gateware/targets/sayma_amc.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index e19c49fe2..d0bf62571 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -7,10 +7,9 @@ import warnings from migen import * from misoc.cores import gpio -from misoc.integration.soc_sdram import soc_sdram_args, soc_sdram_argdict from misoc.integration.builder import builder_args, builder_argdict from misoc.interconnect.csr import * -from misoc.targets.sayma_amc import BaseSoC, MiniSoC +from misoc.targets.sayma_amc import * from artiq.gateware.amp import AMPSoC from artiq.gateware import eem @@ -591,7 +590,7 @@ def main(): parser = argparse.ArgumentParser( description="Sayma AMC gateware and firmware builder") builder_args(parser) - soc_sdram_args(parser) + soc_sayma_amc_args(parser) parser.set_defaults(output_dir="artiq_sayma") parser.add_argument("-V", "--variant", default="masterdac", help="variant: masterdac/master/satellite " @@ -614,7 +613,7 @@ def main(): cls = Satellite else: raise SystemExit("Invalid variant (-V/--variant)") - soc = cls(with_sawg=not args.without_sawg, **soc_sdram_argdict(args)) + soc = cls(with_sawg=not args.without_sawg, **soc_sayma_amc_argdict(args)) if variant != "master": remote_csr_regions = remote_csr.get_remote_csr_regions( From 4db115aef39fb856e09b0db40a9b1ac4925ba3c7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 26 Feb 2019 16:46:01 +0800 Subject: [PATCH 1688/2457] remove old nix instructions (merged into manual) --- doc/nix.rst | 40 ---------------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 doc/nix.rst diff --git a/doc/nix.rst b/doc/nix.rst deleted file mode 100644 index 73f25123d..000000000 --- a/doc/nix.rst +++ /dev/null @@ -1,40 +0,0 @@ -Use ARTIQ via the Nix Package Manager -===================================== - -These instructions provide an alternative route to install ARTIQ for people who do not wish to use conda. - -This sets up an environment suitable for using ARTIQ, including the ARTIQ-Python compiler, device drivers, and the graphical user interfaces. This works correctly on Linux, and partially works (but not to a level that we would consider usable) with WSL introduced in Windows 10. - -* Install the Nix package manager - - * many Linux distros already have a package for the `Nix package manager `_ - - * for example: ``$ apt-get install nix`` - - * if you would like to install via sh - - * ``$ wget https://nixos.org/nix/install`` - - * ``$ sh install`` - - * ``$ source ~/.nix-profile/etc/profile.d/nix.sh`` - -* ``$ nix-channel --add https://nixbld.m-labs.hk/project/artiq/channel/latest m-labs`` -* ``$ nix-channel --update`` -* create the file ``~/.config/nix/nix.conf`` with the following content: - -:: - - substituters = https://cache.nixos.org https://nixbld.m-labs.hk - trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc= - -* ``$ nix-env -i python3.6-artiq`` - -ARTIQ development environment with Nix -====================================== - -Run ``nix-shell -I artiqSrc=path_to_artiq_sources shell-dev.nix`` to obtain an environment containing Migen, MiSoC, Microscope, jesd204b, Clang, Rust, Cargo, and OpenOCD in addition to the user environment above. - -This creates a FHS chroot environment in order to simplify the installation and patching of Xilinx Vivado (it needs to be installed manually e.g. in your home folder). - -You can then build the firmware and gateware with a command such as ``python -m artiq.gateware.targets.kasli --gateware-toolchain-path ~/Xilinx/Vivado``. From ceead218bc902fc30365adfe68618d3a4215e19c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 26 Feb 2019 16:48:24 +0800 Subject: [PATCH 1689/2457] manual: update metadata --- doc/manual/conf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual/conf.py b/doc/manual/conf.py index fceb3d805..1e3539031 100644 --- a/doc/manual/conf.py +++ b/doc/manual/conf.py @@ -238,7 +238,7 @@ latex_elements = { # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'ARTIQ.tex', 'ARTIQ Documentation', - 'M-Labs / NIST Ion Storage Group', 'manual'), + 'M-Labs and contributors', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -268,7 +268,7 @@ latex_documents = [ # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'artiq', 'ARTIQ Documentation', - ['M-Labs / NIST Ion Storage Group'], 1) + ['M-Labs and contributors'], 1) ] # If true, show URL addresses after external links. @@ -282,7 +282,7 @@ man_pages = [ # dir menu entry, description, category) texinfo_documents = [ ('index', 'ARTIQ', 'ARTIQ Documentation', - 'M-Labs / NIST Ion Storage Group', 'ARTIQ', 'One line description of project.', + 'M-Labs and contributors', 'ARTIQ', 'A leading-edge control system for quantum information experiments.', 'Miscellaneous'), ] From ec966de007e865b5972279532f7df3d17edc693e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 26 Feb 2019 16:50:19 +0800 Subject: [PATCH 1690/2457] thorlabs_tcube: cleanup --- artiq/devices/thorlabs_tcube/driver.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/devices/thorlabs_tcube/driver.py b/artiq/devices/thorlabs_tcube/driver.py index 10bb6ea9c..51ac2643b 100644 --- a/artiq/devices/thorlabs_tcube/driver.py +++ b/artiq/devices/thorlabs_tcube/driver.py @@ -1435,13 +1435,13 @@ class TdcSim: def move_absolute(self, absolute_distance): pass - def move_jog(self, direction, async=False): + def move_jog(self, direction): pass def move_velocity(self, direction): pass - def move_stop(self, stop_mode, async=False): + def move_stop(self, stop_mode): pass def set_dc_pid_parameters(self, proportional, integral, differential, From 0d05d4b813424c2a98f965d4ef36d5ce7960c61a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 26 Feb 2019 17:09:38 +0800 Subject: [PATCH 1691/2457] artiq_client: python 3.7 compatibility --- artiq/frontend/artiq_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_client.py b/artiq/frontend/artiq_client.py index e197d9896..d0c7101f4 100755 --- a/artiq/frontend/artiq_client.py +++ b/artiq/frontend/artiq_client.py @@ -169,7 +169,7 @@ def _action_scan_devices(remote, args): def _action_scan_repository(remote, args): - if args.async: + if getattr(args, "async"): remote.scan_repository_async(args.revision) else: remote.scan_repository(args.revision) From f65bcbcbb22fdd36d075b2379e72a8f6b481b53b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 26 Feb 2019 17:11:16 +0800 Subject: [PATCH 1692/2457] manual: clean up build and make compatible with python 3.7 --- doc/manual/conf.py | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/doc/manual/conf.py b/doc/manual/conf.py index 1e3539031..262ea2b88 100644 --- a/doc/manual/conf.py +++ b/doc/manual/conf.py @@ -15,9 +15,9 @@ import sys import os +from unittest.mock import Mock import sphinx_rtd_theme -from unittest.mock import MagicMock # Hack-patch Sphinx so that ARTIQ-Python types are correctly printed @@ -26,21 +26,14 @@ from sphinx.ext import autodoc autodoc.repr = str -class Mock(MagicMock): - @classmethod - def __getattr__(cls, name): - if name == "_mock_methods": - return None - return Mock() - - -mock_modules = ["artiq.gui.moninj", - "artiq.gui.waitingspinnerwidget", +mock_modules = ["artiq.gui.waitingspinnerwidget", "artiq.gui.flowlayout", + "artiq.compiler.module", + "artiq.compiler.embedding", "quamash", "pyqtgraph", "matplotlib", "numpy", "dateutil", "dateutil.parser", "prettytable", "PyQt5", "h5py", "serial", "scipy", "scipy.interpolate", "asyncserial", - "llvmlite_artiq", "Levenshtein", "aiohttp"] + "llvmlite_artiq", "Levenshtein", "aiohttp", "pythonparser"] for module in mock_modules: sys.modules[module] = Mock() From 0d86702503f778c77166927dcf16788e2d6bbe0e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 4 Mar 2019 11:02:28 +0800 Subject: [PATCH 1693/2457] manual: cleanup --- doc/manual/installing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 99c2b3963..2fc0f64d2 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -179,8 +179,8 @@ NixOS users should of course configure OpenOCD through ``/etc/nixos/configuratio If you installed OpenOCD on Linux using Conda and are using the Conda environment ``artiq``, then execute the statements below. If you are using a different environment, you will have to replace ``artiq`` with the name of your environment:: - $ sudo cp ~/.conda/envs/artiq/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d - $ sudo udevadm trigger + $ sudo cp ~/.conda/envs/artiq/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d + $ sudo udevadm trigger On Windows, a third-party tool, `Zadig `_, is necessary. Use it as follows: From 26dd4e51600878583abd3023a5a1bf95533c3c97 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 4 Mar 2019 11:02:50 +0800 Subject: [PATCH 1694/2457] manual: document how to switch to nixpkgs release --- doc/manual/installing.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 2fc0f64d2..2efc15f54 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -20,9 +20,15 @@ Once Nix is installed, add the M-Labs package channels with: :: nix-channel --add https://nixbld.m-labs.hk/channel/custom/artiq/main/channel m-labs nix-channel --add https://nixbld.m-labs.hk/channel/custom/artiq/sinara-systems/channel sinara - nix-channel --update -Those channels track `nixpkgs 18.09 `_. You can check the latest status through the `Hydra interface `_. +Those channels track `nixpkgs 18.09 `_. You can check the latest status through the `Hydra interface `_. As the Nix package manager default installation uses the development version of nixpkgs, we need to tell it to switch to the release: :: + + nix-channel --remove nixpkgs + nix-channel --add https://nixos.org/channels/nixos-18.09 nixpkgs + +Finally, make all the channel changes effective: :: + + nix-channel --update Nix won't install packages without verifying their cryptographic signature. Add the M-Labs public key by creating the file ``~/.config/nix/nix.conf`` with the following contents: From 24a3b31f22045b76f4799876fe9145bb3719d8ae Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 4 Mar 2019 11:06:20 +0800 Subject: [PATCH 1695/2457] manual: use $ for shell prompts consistently --- doc/manual/developing.rst | 12 ++++++------ doc/manual/installing.rst | 34 +++++++++++++++++----------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index c9a3bd457..eb64ab6b6 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -7,18 +7,18 @@ Developing ARTIQ The easiest way to obtain an ARTIQ development environment is via the Nix package manager on Linux. The Nix system is used on the `M-Labs Hydra server `_ to build ARTIQ and its dependencies continuously; it ensures that all build instructions are up-to-date and allows binary packages to be used on developers' machines, in particular for large tools such as the Rust compiler. ARTIQ itself does not depend on Nix, and it is also possible to compile everything from source (look into the ``.nix`` files from the ``nix-scripts`` repository and run the commands manually) - but Nix makes the process a lot easier. -* Install the `Nix package manager `_ and Git (e.g. ``nix-shell -p git``). +* Install the `Nix package manager `_ and Git (e.g. ``$ nix-shell -p git``). * Set up the M-Labs Hydra channels (:ref:`same procedure as the user section `) to allow binaries to be downloaded. Otherwise, tools such as LLVM and the Rust compiler will be compiled on your machine, which uses a lot of CPU time, memory, and disk space. Simply setting up the channels is sufficient, Nix will automatically detect when a binary can be downloaded instead of being compiled locally. * Clone the repositories https://github.com/m-labs/artiq and https://github.com/m-labs/nix-scripts. -* Run ``nix-shell -I artiqSrc=path_to_artiq_sources shell-dev.nix`` to obtain an environment containing all the required development tools (e.g. Migen, MiSoC, Clang, Rust, OpenOCD...) in addition to the ARTIQ user environment. ``artiqSrc`` should point to the root of the cloned ``artiq`` repository, and ``shell-dev.nix`` can be found in the ``artiq`` folder of the ``nix-scripts`` repository. +* Run ``$ nix-shell -I artiqSrc=path_to_artiq_sources shell-dev.nix`` to obtain an environment containing all the required development tools (e.g. Migen, MiSoC, Clang, Rust, OpenOCD...) in addition to the ARTIQ user environment. ``artiqSrc`` should point to the root of the cloned ``artiq`` repository, and ``shell-dev.nix`` can be found in the ``artiq`` folder of the ``nix-scripts`` repository. * This enters a FHS chroot environment that simplifies the installation and patching of Xilinx Vivado. * Download Vivado from Xilinx and install it (by running the official installer in the FHS chroot environment). If you do not want to write to ``/opt``, you can install it in a folder of your home directory. The "appropriate" Vivado version to use for building the bitstream can vary. Some versions contain bugs that lead to hidden or visible failures, others work fine. Refer to the `M-Labs Hydra logs `_ to determine which version is currently used when building the binary packages. * During the Vivado installation, uncheck ``Install cable drivers`` (they are not required as we use better and open source alternatives). -* You can then build the firmware and gateware with a command such as ``python -m artiq.gateware.targets.kasli``. +* You can then build the firmware and gateware with a command such as ``$ python -m artiq.gateware.targets.kasli``. * If you did not install Vivado in ``/opt``, add a command line option such as ``--gateware-toolchain-path ~/Xilinx/Vivado``. -* Flash the binaries into the FPGA board with a command such as ``artiq_flash --srcbuild artiq_kasli -V ``. You need to configure OpenOCD as explained :ref:`in the user section `. OpenOCD is already part of the shell started by ``shell-dev.nix``. -* Check that the board boots and examine the UART messages by running a serial terminal program, e.g. ``flterm /dev/ttyUSB1`` (``flterm`` is part of MiSoC and installed by ``shell-dev.nix``). Leave the terminal running while you are flashing the board, so that you see the startup messages when the board boots immediately after flashing. You can also restart the board (without reflashing it) with ``artiq_flash start``. -* The communication parameters are 115200 8-N-1. Ensure that your user has access to the serial device (``sudo adduser $USER dialout`` assuming standard setup). +* Flash the binaries into the FPGA board with a command such as ``$ artiq_flash --srcbuild artiq_kasli -V ``. You need to configure OpenOCD as explained :ref:`in the user section `. OpenOCD is already part of the shell started by ``shell-dev.nix``. +* Check that the board boots and examine the UART messages by running a serial terminal program, e.g. ``$ flterm /dev/ttyUSB1`` (``flterm`` is part of MiSoC and installed by ``shell-dev.nix``). Leave the terminal running while you are flashing the board, so that you see the startup messages when the board boots immediately after flashing. You can also restart the board (without reflashing it) with ``$ artiq_flash start``. +* The communication parameters are 115200 8-N-1. Ensure that your user has access to the serial device (``$ sudo adduser $USER dialout`` assuming standard setup). * If you are modifying a dependency of ARTIQ, in addition to updating the relevant part of ``nix-scripts``, rebuild and upload the corresponding Conda packages manually, and update their version numbers in ``conda-artiq.nix``. For Conda, only the main ARTIQ package and the board packages are handled automatically on Hydra. .. warning:: diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 2efc15f54..b11d122ff 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -18,17 +18,17 @@ First, install the Nix package manager. Some distributions provide a package for Once Nix is installed, add the M-Labs package channels with: :: - nix-channel --add https://nixbld.m-labs.hk/channel/custom/artiq/main/channel m-labs - nix-channel --add https://nixbld.m-labs.hk/channel/custom/artiq/sinara-systems/channel sinara + $ nix-channel --add https://nixbld.m-labs.hk/channel/custom/artiq/main/channel m-labs + $ nix-channel --add https://nixbld.m-labs.hk/channel/custom/artiq/sinara-systems/channel sinara Those channels track `nixpkgs 18.09 `_. You can check the latest status through the `Hydra interface `_. As the Nix package manager default installation uses the development version of nixpkgs, we need to tell it to switch to the release: :: - nix-channel --remove nixpkgs - nix-channel --add https://nixos.org/channels/nixos-18.09 nixpkgs + $ nix-channel --remove nixpkgs + $ nix-channel --add https://nixos.org/channels/nixos-18.09 nixpkgs Finally, make all the channel changes effective: :: - nix-channel --update + $ nix-channel --update Nix won't install packages without verifying their cryptographic signature. Add the M-Labs public key by creating the file ``~/.config/nix/nix.conf`` with the following contents: @@ -37,7 +37,7 @@ Nix won't install packages without verifying their cryptographic signature. Add substituters = https://cache.nixos.org https://nixbld.m-labs.hk trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc= -The easiest way to obtain ARTIQ is then to install it into the user environment with ``nix-env -i python3.6-artiq``. This provides a minimal installation of ARTIQ where the usual commands (``artiq_master``, ``artiq_dashboard``, ``artiq_run``, etc.) are available. +The easiest way to obtain ARTIQ is then to install it into the user environment with ``$ nix-env -i python3.6-artiq``. This provides a minimal installation of ARTIQ where the usual commands (``artiq_master``, ``artiq_dashboard``, ``artiq_run``, etc.) are available. This installation is however quite limited, as Nix creates a dedicated Python environment for the ARTIQ commands alone. This means that other useful Python packages that you may want (pandas, matplotlib, ...) are not available to them, and this restriction also applies to the M-Labs packages containing board binaries, which means that ``artiq_flash`` will not automatically find them. @@ -80,9 +80,9 @@ Installing multiple packages and making them visible to the ARTIQ commands requi ]; } -Then spawn a shell containing the packages with ``nix-shell my-artiq-env.nix``. The ARTIQ commands with all the additional packages should now be available. +Then spawn a shell containing the packages with ``$ nix-shell my-artiq-env.nix``. The ARTIQ commands with all the additional packages should now be available. -You can exit the shell by typing Control-D. The next time ``nix-shell my-artiq-env.nix`` is invoked, Nix uses the cached packages so the shell startup is fast. +You can exit the shell by typing Control-D. The next time ``$ nix-shell my-artiq-env.nix`` is invoked, Nix uses the cached packages so the shell startup is fast. You can edit this file according to your needs, and also create multiple ``.nix`` files that correspond to different sets of packages. If you are familiar with Conda, using Nix in this way is similar to having multiple Conda environments. @@ -118,9 +118,9 @@ This activation has to be performed in every new shell you open to make the ARTI Upgrading ARTIQ (with Nix) -------------------------- -Run ``nix-channel --update`` to retrieve information about the latest versions, and then either reinstall ARTIQ into the user environment (``nix-env -i python3.6-artiq``) or re-run the ``nix-shell`` command. +Run ``$ nix-channel --update`` to retrieve information about the latest versions, and then either reinstall ARTIQ into the user environment (``$ nix-env -i python3.6-artiq``) or re-run the ``nix-shell`` command. -To rollback to the previous version, use ``nix-channel --rollback`` and then re-do the second step. You can switch between versions by passing a parameter to ``--rollback`` (see the ``nix-channel`` documentation). +To rollback to the previous version, use ``$ nix-channel --rollback`` and then re-do the second step. You can switch between versions by passing a parameter to ``--rollback`` (see the ``nix-channel`` documentation). You may need to reflash the gateware and firmware of the core device to keep it synchronized with the software. @@ -223,14 +223,14 @@ You can also insert other types of SFP transceivers into Kasli if you wish to us If you purchased a device from M-Labs, it already comes with a valid MAC address and an IP address, usually ``192.168.1.75``. Once you can reach this IP, it can be changed with: :: - artiq_coremgmt -D 192.168.1.75 config write -s ip [new IP] + $ artiq_coremgmt -D 192.168.1.75 config write -s ip [new IP] and then reboot the device (with ``artiq_flash start`` or a power cycle). In other cases, install OpenOCD as before, and flash the IP and MAC addresses directly: :: - $ artiq_mkfs flash_storage.img -s mac xx:xx:xx:xx:xx:xx -s ip xx.xx.xx.xx - $ artiq_flash -t [board] -V [variant] -f flash_storage.img storage start + $ artiq_mkfs flash_storage.img -s mac xx:xx:xx:xx:xx:xx -s ip xx.xx.xx.xx + $ artiq_flash -t [board] -V [variant] -f flash_storage.img storage start Check that you can ping the device. If ping fails, check that the Ethernet link LED is ON - on Kasli, it is the LED next to the SFP0 connector. As a next step, look at the messages emitted on the UART during boot. Use a program such as flterm or PuTTY to connect to the device's serial port at 115200bps 8-N-1 and reboot the device. On Kasli, the serial port is on FTDI channel 2 with v1.1 hardware (with channel 0 being JTAG) and on FTDI channel 1 with v1.0 hardware. @@ -246,8 +246,8 @@ This kernel is therefore stored in the :ref:`core device configuration flash sto To flash the idle kernel, first compile the idle experiment. The idle experiment's ``run()`` method must be a kernel: it must be decorated with the ``@kernel`` decorator (see :ref:`next topic ` for more information about kernels). Since the core device is not connected to the PC, RPCs (calling Python code running on the PC from the kernel) are forbidden in the idle experiment. Then write it into the core device configuration flash storage: :: - $ artiq_compile idle.py - $ artiq_coremgmt config write -f idle_kernel idle.elf + $ artiq_compile idle.py + $ artiq_coremgmt config write -f idle_kernel idle.elf .. note:: You can find more information about how to use the ``artiq_coremgmt`` utility on the :ref:`Utilities ` page. @@ -265,5 +265,5 @@ If you are using DRTIO and the default routing table (for a star topology) is no The KC705 may use either an external clock signal or its internal clock. The clock is selected at power-up. Use one of these commands: :: - $ artiq_coremgmt config write -s rtio_clock i # internal clock (default) - $ artiq_coremgmt config write -s rtio_clock e # external clock + $ artiq_coremgmt config write -s rtio_clock i # internal clock (default) + $ artiq_coremgmt config write -s rtio_clock e # external clock From bffb1cf14160f5fdb6f9afbd96b6c083391a2460 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Mar 2019 21:23:04 +0800 Subject: [PATCH 1696/2457] manual: suggest faster and less memory-intensive nix-env command Simple "nix-env -i" is slow and runs out of memory on old computers. https://github.com/NixOS/nix/issues/421 --- doc/manual/installing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index b11d122ff..6c539414b 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -37,7 +37,7 @@ Nix won't install packages without verifying their cryptographic signature. Add substituters = https://cache.nixos.org https://nixbld.m-labs.hk trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc= -The easiest way to obtain ARTIQ is then to install it into the user environment with ``$ nix-env -i python3.6-artiq``. This provides a minimal installation of ARTIQ where the usual commands (``artiq_master``, ``artiq_dashboard``, ``artiq_run``, etc.) are available. +The easiest way to obtain ARTIQ is then to install it into the user environment with ``$ nix-env -f "" -iA artiq``. This provides a minimal installation of ARTIQ where the usual commands (``artiq_master``, ``artiq_dashboard``, ``artiq_run``, etc.) are available. This installation is however quite limited, as Nix creates a dedicated Python environment for the ARTIQ commands alone. This means that other useful Python packages that you may want (pandas, matplotlib, ...) are not available to them, and this restriction also applies to the M-Labs packages containing board binaries, which means that ``artiq_flash`` will not automatically find them. From 6ff7fce4bdb080386dc9c76cbd746bd4c2e47f6a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 6 Mar 2019 11:56:27 +0800 Subject: [PATCH 1697/2457] manual: document some nix issues --- doc/manual/installing.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 6c539414b..1b7649ff3 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -14,6 +14,9 @@ In the current state of affairs, we recommend that Linux users install ARTIQ via Installing via Nix (Linux) -------------------------- +.. note:: + Make sure you are using a 64-bit x86 Linux system. If you are using other systems, such as 32-bit x86, Nix will attempt to compile a number of dependencies from source on your machine. This may work, but the installation process will use a lot of CPU time, memory, and disk space. + First, install the Nix package manager. Some distributions provide a package for the Nix package manager, otherwise, it can be installed via the script on the `Nix website `_. Once Nix is installed, add the M-Labs package channels with: :: @@ -39,6 +42,9 @@ Nix won't install packages without verifying their cryptographic signature. Add The easiest way to obtain ARTIQ is then to install it into the user environment with ``$ nix-env -f "" -iA artiq``. This provides a minimal installation of ARTIQ where the usual commands (``artiq_master``, ``artiq_dashboard``, ``artiq_run``, etc.) are available. +.. note:: + If you are getting the error message ``file 'm-labs' was not found in the Nix search path``, you are probably encountering `this Nix bug `_. As a workaround, enter the command ``$ export NIX_PATH=~/.nix-defexpr/channels:$NIX_PATH`` and try again. + This installation is however quite limited, as Nix creates a dedicated Python environment for the ARTIQ commands alone. This means that other useful Python packages that you may want (pandas, matplotlib, ...) are not available to them, and this restriction also applies to the M-Labs packages containing board binaries, which means that ``artiq_flash`` will not automatically find them. Installing multiple packages and making them visible to the ARTIQ commands requires using the Nix language. Create a file ``my-artiq-env.nix`` with the following contents: From b2bee3da9669bab2827c33c484f71a83b14976d6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 6 Mar 2019 23:02:03 +0800 Subject: [PATCH 1698/2457] manual: use artiq-env package with nix-env The wrapper hack used by nix-env when installing a Python library directly breaks when Python subprocesses are created. --- doc/manual/installing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 1b7649ff3..883673197 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -40,7 +40,7 @@ Nix won't install packages without verifying their cryptographic signature. Add substituters = https://cache.nixos.org https://nixbld.m-labs.hk trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc= -The easiest way to obtain ARTIQ is then to install it into the user environment with ``$ nix-env -f "" -iA artiq``. This provides a minimal installation of ARTIQ where the usual commands (``artiq_master``, ``artiq_dashboard``, ``artiq_run``, etc.) are available. +The easiest way to obtain ARTIQ is then to install it into the user environment with ``$ nix-env -f "" -iA artiq-env``. This provides a minimal installation of ARTIQ where the usual commands (``artiq_master``, ``artiq_dashboard``, ``artiq_run``, etc.) are available. .. note:: If you are getting the error message ``file 'm-labs' was not found in the Nix search path``, you are probably encountering `this Nix bug `_. As a workaround, enter the command ``$ export NIX_PATH=~/.nix-defexpr/channels:$NIX_PATH`` and try again. From ed2d8dfa7a75513afa4df3ee762782775c137af6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Mar 2019 12:43:06 +0800 Subject: [PATCH 1699/2457] artiq_flash: resolve openocd symbolic links On NixOS, openocd may be a symlink in /run/current-system/sw/bin when installed system-wide. --- artiq/frontend/artiq_flash.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index a311a1647..7895d867d 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -76,7 +76,7 @@ def scripts_path(): if os.name == "nt": p.insert(0, "Library") p = os.path.abspath(os.path.join( - os.path.dirname(shutil.which("openocd")), + os.path.dirname(os.path.realpath(shutil.which("openocd"))), "..", *p)) return p @@ -84,7 +84,7 @@ def scripts_path(): def proxy_path(): p = ["share", "bscan-spi-bitstreams"] p = os.path.abspath(os.path.join( - os.path.dirname(shutil.which("openocd")), + os.path.dirname(os.path.realpath(shutil.which("openocd"))), "..", *p)) return p From 3be51123630172a66ee10d86e7df24fe8a8403b7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Mar 2019 19:31:11 +0800 Subject: [PATCH 1700/2457] manual: document artiq_flash -H dependency --- doc/manual/installing.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 883673197..560653a2a 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -73,6 +73,7 @@ Installing multiple packages and making them visible to the ARTIQ commands requi m-labs.artiq-board-kc705-nist_clock sinara.artiq-board-kasli-wipm # from the NixOS package collection: + ps.paramiko # needed for flashing boards remotely (artiq_flash -H) ps.pandas ps.numpy ps.scipy @@ -81,7 +82,7 @@ Installing multiple packages and making them visible to the ARTIQ commands requi ps.bokeh ])) # List desired non-Python packages here - m-labs.openocd # needed for flashing boards + m-labs.openocd # needed for flashing boards locally pkgs.spyder ]; } From 25bcebd1f648d85185d23de66053f1ba6d295af0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Mar 2019 19:35:20 +0800 Subject: [PATCH 1701/2457] artiq_flash: not all boards are development boards --- artiq/frontend/artiq_flash.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 7895d867d..24daa0fbb 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -48,7 +48,7 @@ Prerequisites: help="only show the openocd script that would be run") parser.add_argument("-H", "--host", metavar="HOSTNAME", type=str, default=None, - help="SSH host where the development board is located") + help="SSH host where the board is located") parser.add_argument("-J", "--jump", type=str, default=None, help="SSH host to jump through") @@ -59,8 +59,7 @@ Prerequisites: help="board variant") parser.add_argument("-I", "--preinit-command", default=[], action="append", help="add a pre-initialization OpenOCD command. " - "Useful for selecting a development board " - "when several are connected.") + "Useful for selecting a board when several are connected.") parser.add_argument("-f", "--storage", help="write file to storage area") parser.add_argument("-d", "--dir", help="look for files in this directory") parser.add_argument("--srcbuild", help="look for bitstream, bootloader and firmware in this " From fc9d4c7bdc17b3965213f19bb7b75081174b1388 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Mar 2019 19:36:35 +0800 Subject: [PATCH 1702/2457] artiq_flash: fix sayma master detection --- artiq/frontend/artiq_flash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 24daa0fbb..ffdfdabed 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -339,7 +339,7 @@ def main(): gateware_bin = convert_gateware( artifact_path(variant, "gateware", "top.bit")) programmer.write_binary(*config["gateware"], gateware_bin) - if args.target == "sayma" and args.variant != "master": + if args.target == "sayma" and variant != "master": rtm_gateware_bin = convert_gateware( artifact_path("rtm_gateware", "rtm.bit"), header=True) programmer.write_binary(*config["rtm_gateware"], From b219f8b5c7127f5367e515872aa85378cab451d4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Mar 2019 19:47:24 +0800 Subject: [PATCH 1703/2457] artiq_flash: autodetect variant --- RELEASE_NOTES.rst | 2 ++ artiq/frontend/artiq_flash.py | 66 ++++++++++++++++++++++------------- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 453c4ed2b..e63662807 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -25,6 +25,8 @@ ARTIQ-5 * The controller manager now ignores device database entries without the ``"command"`` key set to facilitate sharing of devices between multiple masters. +* The meaning of the ``-d/--dir`` and ``--srcbuild`` options of ``artiq_flash`` + has changed. ARTIQ-4 diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index ffdfdabed..bc6100589 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -56,14 +56,14 @@ Prerequisites: help="target board, default: %(default)s, one of: " "kasli sayma kc705") parser.add_argument("-V", "--variant", default=None, - help="board variant") + help="board variant. Autodetected if only one is installed.") parser.add_argument("-I", "--preinit-command", default=[], action="append", help="add a pre-initialization OpenOCD command. " "Useful for selecting a board when several are connected.") parser.add_argument("-f", "--storage", help="write file to storage area") - parser.add_argument("-d", "--dir", help="look for files in this directory") - parser.add_argument("--srcbuild", help="look for bitstream, bootloader and firmware in this " - "ARTIQ source build tree") + parser.add_argument("-d", "--dir", help="look for board binaries in this directory") + parser.add_argument("--srcbuild", help="board binaries directory is laid out as a source build tree", + default=False, action="store_true") parser.add_argument("action", metavar="ACTION", nargs="*", default="gateware bootloader firmware start".split(), help="actions to perform, default: %(default)s") @@ -267,7 +267,6 @@ def main(): config = { "kasli": { "programmer": partial(ProgrammerXC7, board="kasli", proxy="bscan_spi_xc7a100t.bit"), - "def_variant": "opticlock", "gateware": ("spi0", 0x000000), "bootloader": ("spi0", 0x400000), "storage": ("spi0", 0x440000), @@ -275,7 +274,6 @@ def main(): }, "sayma": { "programmer": ProgrammerSayma, - "def_variant": "standalone", "gateware": ("spi0", 0x000000), "bootloader": ("spi1", 0x000000), "storage": ("spi1", 0x040000), @@ -284,7 +282,6 @@ def main(): }, "kc705": { "programmer": partial(ProgrammerXC7, board="kc705", proxy="bscan_spi_xc7k325t.bit"), - "def_variant": "nist_clock", "gateware": ("spi0", 0x000000), "bootloader": ("spi0", 0xaf0000), "storage": ("spi0", 0xb30000), @@ -292,16 +289,33 @@ def main(): }, }[args.target] - variant = args.variant - if variant is None: - variant = config["def_variant"] - bin_dir = args.dir if bin_dir is None: - bin_name = args.target - if variant: - bin_name += "-" + variant - bin_dir = os.path.join(artiq_dir, "board-support", bin_name) + bin_dir = os.path.join(artiq_dir, "board-support") + + variant = args.variant + if variant is None: + variants = [] + if args.srcbuild: + for entry in os.scandir(bin_dir): + if entry.is_dir(): + variants.append(entry.name) + else: + prefix = args.target + "-" + for entry in os.scandir(bin_dir): + if entry.is_dir() and entry.name.startswith(prefix): + variants.append(entry.name[len(prefix):]) + if len(variants) == 0: + raise FileNotFoundError("no variants found, did you install a board binary package?") + elif len(variants) == 1: + variant = variants[0] + else: + raise ValueError("more than one variant found for selected board, specify -V. " + "Found variants: {}".format(" ".join(sorted(variants)))) + if args.srcbuild: + variant_dir = variant + else: + variant_dir = args.target + "-" + variant if args.host is None: client = LocalClient() @@ -310,12 +324,14 @@ def main(): programmer = config["programmer"](client, preinit_script=args.preinit_command) - def artifact_path(*path_filename): - if args.srcbuild is None: - *path, filename = path_filename - return os.path.join(bin_dir, filename) + def artifact_path(this_variant_dir, *path_filename): + if args.srcbuild: + # source tree - use path elements to locate file + return os.path.join(bin_dir, this_variant_dir, *path_filename) else: - return os.path.join(args.srcbuild, *path_filename) + # flat tree - all files in the same directory, discard path elements + *_, filename = path_filename + return os.path.join(bin_dir, this_variant_dir, filename) def convert_gateware(bit_filename, header=False): bin_handle, bin_filename = tempfile.mkstemp( @@ -337,7 +353,7 @@ def main(): for action in args.action: if action == "gateware": gateware_bin = convert_gateware( - artifact_path(variant, "gateware", "top.bit")) + artifact_path(variant_dir, "gateware", "top.bit")) programmer.write_binary(*config["gateware"], gateware_bin) if args.target == "sayma" and variant != "master": rtm_gateware_bin = convert_gateware( @@ -345,7 +361,7 @@ def main(): programmer.write_binary(*config["rtm_gateware"], rtm_gateware_bin) elif action == "bootloader": - bootloader_bin = artifact_path(variant, "software", "bootloader", "bootloader.bin") + bootloader_bin = artifact_path(variant_dir, "software", "bootloader", "bootloader.bin") programmer.write_binary(*config["bootloader"], bootloader_bin) elif action == "storage": storage_img = args.storage @@ -356,16 +372,16 @@ def main(): else: firmware = "runtime" - firmware_fbi = artifact_path(variant, "software", firmware, firmware + ".fbi") + firmware_fbi = artifact_path(variant_dir, "software", firmware, firmware + ".fbi") programmer.write_binary(*config["firmware"], firmware_fbi) elif action == "load": if args.target == "sayma": rtm_gateware_bit = artifact_path("rtm_gateware", "rtm.bit") programmer.load(rtm_gateware_bit, 0) - gateware_bit = artifact_path(variant, "gateware", "top.bit") + gateware_bit = artifact_path(variant_dir, "gateware", "top.bit") programmer.load(gateware_bit, 1) else: - gateware_bit = artifact_path(variant, "gateware", "top.bit") + gateware_bit = artifact_path(variant_dir, "gateware", "top.bit") programmer.load(gateware_bit, 0) elif action == "start": programmer.start() From e47ba4b35e4144e8476ebc583bf90d72be039b48 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 8 Mar 2019 19:57:20 +0800 Subject: [PATCH 1704/2457] kasli_generic: fix identifier string --- artiq/gateware/targets/kasli_generic.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index 6f5310acd..fe54ba9ec 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -83,6 +83,7 @@ class GenericStandalone(StandaloneBase): def __init__(self, description, hw_rev=None,**kwargs): if hw_rev is None: hw_rev = description["hw_rev"] + self.class_name_override = description["variant"] StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None @@ -121,6 +122,7 @@ class GenericMaster(MasterBase): def __init__(self, description, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = description["hw_rev"] + self.class_name_override = description["variant"] MasterBase.__init__(self, hw_rev=hw_rev, rtio_clk_freq=description.get("rtio_frequency", 125e6), @@ -153,6 +155,7 @@ class GenericSatellite(SatelliteBase): def __init__(self, description, hw_rev=None, **kwargs): if hw_rev is None: hw_rev = description["hw_rev"] + self.class_name_override = description["variant"] SatelliteBase.__init__(self, hw_rev=hw_rev, rtio_clk_freq=description.get("rtio_frequency", 125e6), @@ -207,7 +210,6 @@ def main(): raise ValueError("Invalid base") soc = cls(description, **soc_kasli_argdict(args)) - soc.class_name_override = description["variant"] args.variant = description["variant"] build_artiq_soc(soc, builder_argdict(args)) From 5fd92a617506dd6d572a8e63ceb6fb01f6898c66 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 10 Mar 2019 20:44:14 +0000 Subject: [PATCH 1705/2457] gui: Fix crash when quickly opening/closing applets Quickly closing/reopening applets (e.g. quickly clicking the checkbox on an entire folder of applets) would previously lead to an occasional KeyError on the self.dock_to_item access in on_dock_closed, as close() would be invoked more than once. The geometry/checked state handling can potentially be cleaned up further, but at least this avoid the crash. --- artiq/gui/applets.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/artiq/gui/applets.py b/artiq/gui/applets.py index d440120fa..ebf735595 100644 --- a/artiq/gui/applets.py +++ b/artiq/gui/applets.py @@ -321,7 +321,6 @@ class AppletsDock(QtWidgets.QDockWidget): self.main_window = main_window self.datasets_sub = datasets_sub - self.dock_to_item = dict() self.applet_uids = set() self.table = QtWidgets.QTreeWidget() @@ -414,12 +413,12 @@ class AppletsDock(QtWidgets.QDockWidget): finally: self.table.itemChanged.connect(self.item_changed) - def create(self, uid, name, spec): - dock = _AppletDock(self.datasets_sub, uid, name, spec) + def create(self, item, name, spec): + dock = _AppletDock(self.datasets_sub, item.applet_uid, name, spec) self.main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock) dock.setFloating(True) asyncio.ensure_future(dock.start()) - dock.sigClosed.connect(partial(self.on_dock_closed, dock)) + dock.sigClosed.connect(partial(self.on_dock_closed, item, dock)) return dock def item_changed(self, item, column): @@ -437,15 +436,15 @@ class AppletsDock(QtWidgets.QDockWidget): if item.applet_dock is None: name = item.text(0) spec = self.get_spec(item) - dock = self.create(item.applet_uid, name, spec) + dock = self.create(item, name, spec) item.applet_dock = dock if item.applet_geometry is not None: dock.restoreGeometry(item.applet_geometry) # geometry is now handled by main window state item.applet_geometry = None - self.dock_to_item[dock] = item else: dock = item.applet_dock + item.applet_dock = None if dock is not None: # This calls self.on_dock_closed dock.close() @@ -455,12 +454,9 @@ class AppletsDock(QtWidgets.QDockWidget): else: raise ValueError - def on_dock_closed(self, dock): - item = self.dock_to_item[dock] - item.applet_dock = None + def on_dock_closed(self, item, dock): item.applet_geometry = dock.saveGeometry() asyncio.ensure_future(dock.terminate()) - del self.dock_to_item[dock] item.setCheckState(0, QtCore.Qt.Unchecked) def get_untitled(self): From b3db3ea6fc82099a91f6d0c5c8a680967ac961aa Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 10 Mar 2019 20:12:28 +0000 Subject: [PATCH 1706/2457] dashboard: Sort TTL moninj channels by name With growing system complexity, the moninj channel index is no longer a very intuitive ordering for typical end users. --- artiq/dashboard/moninj.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py index 5de911826..3969809c3 100644 --- a/artiq/dashboard/moninj.py +++ b/artiq/dashboard/moninj.py @@ -20,6 +20,7 @@ class _TTLWidget(QtWidgets.QFrame): self.channel = channel self.set_mode = dm.ttl_set_mode self.force_out = force_out + self.title = title self.setFrameShape(QtWidgets.QFrame.Box) self.setFrameShadow(QtWidgets.QFrame.Raised) @@ -131,7 +132,7 @@ class _TTLWidget(QtWidgets.QFrame): self.programmatic_change = False def sort_key(self): - return self.channel + return self.title class _SimpleDisplayWidget(QtWidgets.QFrame): From 227c729f56f65113924239b56dc9da41b3497d72 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Mar 2019 20:43:28 +0800 Subject: [PATCH 1707/2457] fix permissions --- artiq/coredevice/edge_counter.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 artiq/coredevice/edge_counter.py diff --git a/artiq/coredevice/edge_counter.py b/artiq/coredevice/edge_counter.py old mode 100755 new mode 100644 From b2177eff8110e22fba325949a2cb9a441a3c7181 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Mar 2019 21:06:28 +0800 Subject: [PATCH 1708/2457] kasli_tester: run test_i2c_switch --- artiq/examples/kasli_tester/device_db.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/examples/kasli_tester/device_db.py b/artiq/examples/kasli_tester/device_db.py index 96cd249e8..b0888317f 100644 --- a/artiq/examples/kasli_tester/device_db.py +++ b/artiq/examples/kasli_tester/device_db.py @@ -205,6 +205,8 @@ device_db.update( ) device_db.update( + i2c_switch="i2c_switch0", + ttl_out="ttl4", ttl_out_serdes="ttl4", From 8659c769cb2cf9a5c5787b0f266faac9b011e2fa Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Sat, 2 Feb 2019 22:47:57 +0000 Subject: [PATCH 1709/2457] master/language: add methods to set experiment pipeline/priority/flush defaults --- artiq/language/environment.py | 17 +++++++++++++++++ artiq/master/experiments.py | 4 ++-- artiq/master/worker.py | 4 ++-- artiq/master/worker_impl.py | 7 ++++--- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/artiq/language/environment.py b/artiq/language/environment.py index 0e1b2b918..2709643c5 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -207,10 +207,12 @@ class HasEnvironment: self.__device_mgr = managers_or_parent[0] self.__dataset_mgr = managers_or_parent[1] self.__argument_mgr = managers_or_parent[2] + self.__scheduler_defaults = managers_or_parent[3] else: self.__device_mgr = managers_or_parent.__device_mgr self.__dataset_mgr = managers_or_parent.__dataset_mgr self.__argument_mgr = managers_or_parent.__argument_mgr + self.__scheduler_defaults = {} managers_or_parent.register_child(self) self.__in_build = True @@ -364,6 +366,21 @@ class HasEnvironment: dataset and of the attribute are the same.""" setattr(self, key, self.get_dataset(key, default, archive)) + def set_default_scheduling(self, priority=None, pipeline_name=None, flush=None): + """Sets the default scheduling options. + + This function should only be called from ``build``.""" + if not self.__in_build: + raise TypeError("set_default_scheduling() should only " + "be called from build()") + + if priority is not None: + self.__scheduler_defaults["priority"] = int(priority) + if pipeline_name is not None: + self.__scheduler_defaults["pipeline_name"] = pipeline_name + if flush is not None: + self.__scheduler_defaults["flush"] = flush + class Experiment: """Base class for top-level experiments. diff --git a/artiq/master/experiments.py b/artiq/master/experiments.py index dc17915fc..892d6d30a 100644 --- a/artiq/master/experiments.py +++ b/artiq/master/experiments.py @@ -46,7 +46,8 @@ class _RepoScanner: entry = { "file": filename, "class_name": class_name, - "arginfo": arginfo + "arginfo": arginfo, + "scheduler_defaults": class_desc["scheduler_defaults"] } entry_dict[name] = entry @@ -115,7 +116,6 @@ class ExperimentDB: t1 = time.monotonic() new_explist = await _RepoScanner(self.worker_handlers).scan(wd) logger.info("repository scan took %d seconds", time.monotonic()-t1) - update_from_dict(self.explist, new_explist) finally: self._scanning = False diff --git a/artiq/master/worker.py b/artiq/master/worker.py index ac12ba4b1..293d0f180 100644 --- a/artiq/master/worker.py +++ b/artiq/master/worker.py @@ -303,8 +303,8 @@ class Worker: await self._create_process(logging.WARNING) r = dict() - def register(class_name, name, arginfo): - r[class_name] = {"name": name, "arginfo": arginfo} + def register(class_name, name, arginfo, scheduler_defaults): + r[class_name] = {"name": name, "arginfo": arginfo, "scheduler_defaults": scheduler_defaults} self.register_experiment = register await self._worker_action({"action": "examine", "file": file}, timeout) diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index 6a2df4cfd..b9fa404de 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -174,11 +174,12 @@ def examine(device_mgr, dataset_mgr, file): if name[-1] == ".": name = name[:-1] argument_mgr = TraceArgumentManager() - exp_class((device_mgr, dataset_mgr, argument_mgr)) + scheduler_defaults = {} + cls = exp_class((device_mgr, dataset_mgr, argument_mgr, scheduler_defaults)) arginfo = OrderedDict( (k, (proc.describe(), group, tooltip)) for k, (proc, group, tooltip) in argument_mgr.requested_args.items()) - register_experiment(class_name, name, arginfo) + register_experiment(class_name, name, arginfo, scheduler_defaults) finally: new_keys = set(sys.modules.keys()) for key in new_keys - previous_keys: @@ -277,7 +278,7 @@ def main(): os.makedirs(dirname, exist_ok=True) os.chdir(dirname) argument_mgr = ProcessArgumentManager(expid["arguments"]) - exp_inst = exp((device_mgr, dataset_mgr, argument_mgr)) + exp_inst = exp((device_mgr, dataset_mgr, argument_mgr, {})) put_object({"action": "completed"}) elif action == "prepare": exp_inst.prepare() From c56c3e5588791b6eff46906600b93fd4330f8711 Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Sat, 2 Feb 2019 22:58:49 +0000 Subject: [PATCH 1710/2457] dashboard: add support for experiment pipeline/priority/flush defaults --- artiq/dashboard/experiments.py | 48 +++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/artiq/dashboard/experiments.py b/artiq/dashboard/experiments.py index 78f6a15b0..1b6637f39 100644 --- a/artiq/dashboard/experiments.py +++ b/artiq/dashboard/experiments.py @@ -162,14 +162,14 @@ class _ArgumentEditor(QtWidgets.QTreeWidget): async def _recompute_argument(self, name): try: - arginfo = await self.manager.compute_arginfo(self.expurl) + expdesc = await self.manager.compute_expdesc(self.expurl) except: logger.error("Could not recompute argument '%s' of '%s'", name, self.expurl, exc_info=True) return argument = self.manager.get_submission_arguments(self.expurl)[name] - procdesc = arginfo[name][0] + procdesc = expdesc["arginfo"][name][0] state = procdesc_to_entry(procdesc).default_state(procdesc) argument["desc"] = procdesc argument["state"] = state @@ -272,7 +272,8 @@ class _ExperimentDock(QtWidgets.QMdiSubWindow): scheduling["due_date"] = due_date datetime_en.stateChanged.connect(update_datetime_en) - pipeline_name = QtWidgets.QLineEdit() + self.pipeline_name = QtWidgets.QLineEdit() + pipeline_name = self.pipeline_name self.layout.addWidget(QtWidgets.QLabel("Pipeline:"), 1, 2) self.layout.addWidget(pipeline_name, 1, 3) @@ -280,9 +281,10 @@ class _ExperimentDock(QtWidgets.QMdiSubWindow): def update_pipeline_name(text): scheduling["pipeline_name"] = text - pipeline_name.textEdited.connect(update_pipeline_name) + pipeline_name.textChanged.connect(update_pipeline_name) - priority = QtWidgets.QSpinBox() + self.priority = QtWidgets.QSpinBox() + priority = self.priority priority.setRange(-99, 99) self.layout.addWidget(QtWidgets.QLabel("Priority:"), 2, 0) self.layout.addWidget(priority, 2, 1) @@ -293,7 +295,8 @@ class _ExperimentDock(QtWidgets.QMdiSubWindow): scheduling["priority"] = value priority.valueChanged.connect(update_priority) - flush = QtWidgets.QCheckBox("Flush") + self.flush = QtWidgets.QCheckBox("Flush") + flush = self.flush flush.setToolTip("Flush the pipeline (of current- and higher-priority " "experiments) before starting the experiment") self.layout.addWidget(flush, 2, 2, 1, 2) @@ -386,11 +389,12 @@ class _ExperimentDock(QtWidgets.QMdiSubWindow): async def _recompute_arguments_task(self, overrides=dict()): try: - arginfo = await self.manager.compute_arginfo(self.expurl) + expdesc = await self.manager.compute_expdesc(self.expurl) except: - logger.error("Could not recompute arguments of '%s'", + logger.error("Could not recompute experiment description of '%s'", self.expurl, exc_info=True) return + arginfo = expdesc["arginfo"] for k, v in overrides.items(): # Some values (e.g. scans) may have multiple defaults in a list if ("default" in arginfo[k][0] @@ -407,6 +411,28 @@ class _ExperimentDock(QtWidgets.QMdiSubWindow): self.argeditor.restore_state(argeditor_state) self.layout.addWidget(self.argeditor, 0, 0, 1, 5) + def contextMenuEvent(self, event): + menu = QtWidgets.QMenu(self) + reset_sched = menu.addAction("Reset scheduler settings") + action = menu.exec_(self.mapToGlobal(event.pos())) + if action == reset_sched: + asyncio.ensure_future(self._recompute_sched_options_task()) + + async def _recompute_sched_options_task(self): + try: + expdesc = await self.manager.compute_expdesc(self.expurl) + except: + logger.error("Could not recompute experiment description of '%s'", + self.expurl, exc_info=True) + return + sched_defaults = expdesc["scheduler_defaults"] + + scheduling = self.manager.get_submission_scheduling(self.expurl) + scheduling.update(sched_defaults) + self.priority.setValue(scheduling["priority"]) + self.pipeline_name.setText(scheduling["pipeline_name"]) + self.flush.setChecked(scheduling["flush"]) + def _load_hdf5_clicked(self): asyncio.ensure_future(self._load_hdf5_task()) @@ -508,6 +534,8 @@ class ExperimentManager: "due_date": None, "flush": False } + if expurl[:5] == "repo:": + scheduling.update(self.explist[expurl[5:]]["scheduler_defaults"]) self.submission_scheduling[expurl] = scheduling return scheduling @@ -640,7 +668,7 @@ class ExperimentManager: rids.append(rid) asyncio.ensure_future(self._request_term_multiple(rids)) - async def compute_arginfo(self, expurl): + async def compute_expdesc(self, expurl): file, class_name, use_repository = self.resolve_expurl(expurl) if use_repository: revision = self.get_submission_options(expurl)["repo_rev"] @@ -648,7 +676,7 @@ class ExperimentManager: revision = None description = await self.experiment_db_ctl.examine( file, use_repository, revision) - return description[class_name]["arginfo"] + return description[class_name] async def open_file(self, file): description = await self.experiment_db_ctl.examine(file, False) From 8a5789d616fdc8b7f566618def6e1108d64884f8 Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Sat, 2 Feb 2019 23:35:55 +0000 Subject: [PATCH 1711/2457] RELEASE_NOTES: mention methods to set experiment pipeline/priority/flush defaults --- RELEASE_NOTES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index e63662807..abbc6d44f 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -27,6 +27,7 @@ ARTIQ-5 masters. * The meaning of the ``-d/--dir`` and ``--srcbuild`` options of ``artiq_flash`` has changed. +* Experiments can now programatically set their default pipeline, priority, and flush flag. ARTIQ-4 From 964a349a19684be00bdf48bfb21f1d103e43af7f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Mar 2019 15:33:50 +0800 Subject: [PATCH 1712/2457] add Kasli I2C driver --- artiq/coredevice/kasli_i2c.py | 73 +++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 artiq/coredevice/kasli_i2c.py diff --git a/artiq/coredevice/kasli_i2c.py b/artiq/coredevice/kasli_i2c.py new file mode 100644 index 000000000..11c69172f --- /dev/null +++ b/artiq/coredevice/kasli_i2c.py @@ -0,0 +1,73 @@ +from numpy import int32 + +from artiq.experiment import * +from artiq.coredevice.i2c import i2c_write_many, i2c_read_many, i2c_poll + + +port_mapping = { + "EEM0": 7, + "EEM1": 5, + "EEM2": 4, + "EEM3": 3, + "EEM4": 2, + "EEM5": 1, + "EEM6": 0, + "EEM7": 6, + "EEM8": 12, + "EEM9": 13, + "EEM10": 15, + "EEM11": 14, + "SFP0": 8, + "SFP1": 9, + "SFP2": 10, + "LOC0": 11, +} + + +class KasliEEPROM: + def __init__(self, dmgr, port, busno=0, + core_device="core", sw0_device="i2c_switch0", sw1_device="i2c_switch1"): + self.core = dmgr.get(core_device) + self.sw0 = dmgr.get(sw0_device) + self.sw1 = dmgr.get(sw1_device) + self.busno = busno + self.port = port_mapping[port] + self.address = 0xa0 # i2c 8 bit + + @kernel + def select(self): + mask = 1 << self.port + self.sw0.select(mask) + self.sw1.select(mask >> 8) + + @kernel + def deselect(self): + self.sw0.select(0) + self.sw1.select(0) + + @kernel + def write_i32(self, addr, value): + self.select() + try: + data = [0]*4 + for i in range(4): + data[i] = (value >> 24) & 0xff + value <<= 8 + i2c_write_many(self.busno, self.address, addr, data) + i2c_poll(self.busno, self.address) + finally: + self.deselect() + + @kernel + def read_i32(self, addr): + self.select() + try: + data = [0]*4 + i2c_read_many(self.busno, self.address, addr, data) + value = int32(0) + for i in range(4): + value <<= 8 + value |= data[i] + finally: + self.deselect() + return value From 852048dce4f72dbedd1e5859c6bce75a4c4b8cf1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Mar 2019 15:34:23 +0800 Subject: [PATCH 1713/2457] artiq_ddb_template: create Urukul EEPROM device --- artiq/frontend/artiq_ddb_template.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index a625a2fc7..62a189f01 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -103,6 +103,13 @@ class PeripheralManager: synchronization = peripheral.get("synchronization", False) channel = count(0) self.gen(""" + device_db["eeprom_{name}"]={{ + "type": "local", + "module": "artiq.coredevice.kasli_i2c", + "class": "KasliEEPROM", + "arguments": {{"port": "EEM{eem}"}} + }}, + device_db["spi_{name}"]={{ "type": "local", "module": "artiq.coredevice.spi2", @@ -110,6 +117,7 @@ class PeripheralManager: "arguments": {{"channel": 0x{channel:06x}}} }}""", name=urukul_name, + eem=peripheral["ports"][0], channel=rtio_offset+next(channel)) if synchronization: self.gen(""" From 04e0c23e78074c5a49ef5464625aba5b6fce9c80 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Mar 2019 15:34:47 +0800 Subject: [PATCH 1714/2457] ad9910: support reading synchronization values from EEPROM --- artiq/coredevice/ad9910.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 8da06b275..38bc4ce43 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -1,4 +1,5 @@ from numpy import int32, int64 +import functools from artiq.language.core import ( kernel, delay, portable, delay_mu, now_mu, at_mu) @@ -86,9 +87,13 @@ class AD9910: To stabilize the SYNC_IN delay tuning, run :meth:`tune_sync_delay` once and set this to the delay tap number returned (default: -1 to signal no synchronization and no tuning during :meth:`init`). + Can be a string of the form "eeprom_device:byte_offset" to read the value + from a I2C EEPROM. :param io_update_delay: IO_UPDATE pulse alignment delay. To align IO_UPDATE to SYNC_CLK, run :meth:`tune_io_update_delay` and set this to the delay tap number returned. + Can be a string of the form "eeprom_device:byte_offset" to read the value + from a I2C EEPROM. """ kernel_invariants = {"chip_select", "cpld", "core", "bus", "ftw_per_hz", "io_update_delay", "sysclk_per_mu"} @@ -123,12 +128,39 @@ class AD9910: assert sysclk <= 1e9 self.ftw_per_hz = (1 << 32)/sysclk self.sysclk_per_mu = int(round(sysclk*self.core.ref_period)) + + @functools.lru_cache(maxsize=2) + def get_eeprom_sync_data(eeprom_str): + device, offset = eeprom_str.split(":") + device = dmgr.get(device) + offset = int(offset) + + word = device.read_i32(offset) >> 16 + sync_delay_seed = word >> 8 + if sync_delay_seed >= 0: + io_update_delay = word & 0xff + else: + io_update_delay = 0 + return device, offset, sync_delay_seed, io_update_delay + + if isinstance(sync_delay_seed, str): + self.sync_delay_seed_eeprom, self.sync_delay_seed_offset, sync_delay_seed, _ = \ + get_eeprom_sync_data(sync_delay_seed) + else: + self.sync_delay_seed_eeprom, self.sync_delay_seed_offset = None, None + if isinstance(io_update_delay, str): + self.io_update_delay_eeprom, self.io_update_delay_offset, _, io_update_delay = \ + get_eeprom_sync_data(io_update_delay) + else: + self.io_update_delay_eeprom, self.io_update_delay_offset = None, None + if sync_delay_seed >= 0 and not self.cpld.sync_div: raise ValueError("parent cpld does not drive SYNC") self.sync_delay_seed = sync_delay_seed if self.sync_delay_seed >= 0: assert self.sysclk_per_mu == sysclk*self.core.ref_period self.io_update_delay = io_update_delay + self.phase_mode = PHASE_MODE_CONTINUOUS @kernel From 346299e7f8532423a8f645e1210f384438d3f9b0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Mar 2019 15:35:23 +0800 Subject: [PATCH 1715/2457] kasli_tester: enable EEPROM for Urukul synchronization --- artiq/examples/kasli_tester/device_db.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/artiq/examples/kasli_tester/device_db.py b/artiq/examples/kasli_tester/device_db.py index b0888317f..d9cf9d34b 100644 --- a/artiq/examples/kasli_tester/device_db.py +++ b/artiq/examples/kasli_tester/device_db.py @@ -57,6 +57,12 @@ for i in range(8): # Urukul (EEM1) starting at RTIO channel 12 device_db.update( + eeprom_urukul0={ + "type": "local", + "module": "artiq.coredevice.kasli_i2c", + "class": "KasliEEPROM", + "arguments": {"port": "EEM1"} + }, spi_urukul0={ "type": "local", "module": "artiq.coredevice.spi2", @@ -122,7 +128,9 @@ for i in range(4): "pll_n": 32, "chip_select": 4 + i, "cpld_device": "urukul0_cpld", - "sw_device": "ttl_urukul0_sw" + str(i) + "sw_device": "ttl_urukul0_sw" + str(i), + "sync_delay_seed": "eeprom_urukul0:" + str(48 + 4*i), + "io_update_delay": "eeprom_urukul0:" + str(48 + 4*i), } } From e504262b67e6f3774f15ad9443d83a05789ef793 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Mar 2019 15:36:05 +0800 Subject: [PATCH 1716/2457] kasli_tester: calibrate Urukul synchronization and write to EEPROM --- .../kasli_basic/repository/kasli_tester.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/artiq/examples/kasli_basic/repository/kasli_tester.py b/artiq/examples/kasli_basic/repository/kasli_tester.py index 4acdecd73..37f14c67e 100644 --- a/artiq/examples/kasli_basic/repository/kasli_tester.py +++ b/artiq/examples/kasli_basic/repository/kasli_tester.py @@ -184,6 +184,14 @@ class KasliTester(EnvExperiment): self.core.break_realtime() cpld.init() + @kernel + def calibrate_urukul(self, channel): + self.core.break_realtime() + sync_delay_seed, _ = channel.tune_sync_delay() + self.core.break_realtime() + io_update_delay = channel.tune_io_update_delay() + return sync_delay_seed, io_update_delay + @kernel def setup_urukul(self, channel, frequency): self.core.break_realtime() @@ -214,6 +222,23 @@ class KasliTester(EnvExperiment): self.init_urukul(cpld) print("...done") + print("Calibrating inter-device synchronization...") + for channel_name, channel_dev in self.urukuls: + if channel_dev.sync_delay_seed_eeprom is None and channel_dev.io_update_delay_eeprom is None: + print("{}\tno synchronization".format(channel_name)) + elif channel_dev.sync_delay_seed_eeprom is not channel_dev.io_update_delay_eeprom: + print("{}\tunsupported EEPROM configuration".format(channel_name)) + elif channel_dev.sync_delay_seed_offset != channel_dev.io_update_delay_offset: + print("{}\tunsupported EEPROM offsets".format(channel_name)) + else: + eeprom = channel_dev.sync_delay_seed_eeprom + offset = channel_dev.sync_delay_seed_offset + sync_delay_seed, io_update_delay = self.calibrate_urukul(channel_dev) + print("{}\t{} {}".format(channel_name, sync_delay_seed, io_update_delay)) + eeprom_word = (sync_delay_seed << 24) | (io_update_delay << 16) + eeprom.write_i32(offset, eeprom_word) + print("...done") + print("Frequencies:") for card_n, channels in enumerate(chunker(self.urukuls, 4)): for channel_n, (channel_name, channel_dev) in enumerate(channels): From 5e7c83c9cfd417f86a02f29429418bb06585f3c5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 13 Mar 2019 15:42:51 +0800 Subject: [PATCH 1717/2457] artiq_ddb_template: enable Urukul synchronization from EEPROM --- artiq/frontend/artiq_ddb_template.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 62a189f01..245f4a766 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -179,13 +179,15 @@ class PeripheralManager: "pll_n": 32, "chip_select": {chip_select}, "cpld_device": "{name}_cpld", - "sw_device": "ttl_{name}_sw{uchn}"{pll_vco} + "sw_device": "ttl_{name}_sw{uchn}"{pll_vco}{sync_delay_seed}{io_update_delay} }} }}""", name=urukul_name, chip_select=4 + i, uchn=i, - pll_vco=",\n \"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "") + pll_vco=",\n \"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "", + sync_delay_seed=",\n \"sync_delay_seed\": \"eeprom_{}:{}\"".format(urukul_name, 48 + 4*i) if synchronization else "", + io_update_delay=",\n \"io_update_delay\": \"eeprom_{}:{}\"".format(urukul_name, 48 + 4*i) if synchronization else "") elif dds == "ad9912": self.gen(""" device_db["{name}_ch{uchn}"] = {{ From fcf8828cb64cd3e5e6172b68dbc47e99949ac4aa Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Wed, 13 Mar 2019 15:20:41 +0000 Subject: [PATCH 1718/2457] fix tests, artiq_run after implementing scheduler defaults (#1290) --- artiq/frontend/artiq_run.py | 2 +- artiq/test/test_datasets.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_run.py b/artiq/frontend/artiq_run.py index bc4f81ff5..263b3cf08 100755 --- a/artiq/frontend/artiq_run.py +++ b/artiq/frontend/artiq_run.py @@ -149,7 +149,7 @@ def get_argparser(with_file=True): def _build_experiment(device_mgr, dataset_mgr, args): arguments = parse_arguments(args.arguments) argument_mgr = ProcessArgumentManager(arguments) - managers = (device_mgr, dataset_mgr, argument_mgr) + managers = (device_mgr, dataset_mgr, argument_mgr, {}) if hasattr(args, "file"): is_elf = args.file.endswith(".elf") is_ll = args.file.endswith(".ll") diff --git a/artiq/test/test_datasets.py b/artiq/test/test_datasets.py index db35d7f34..4ea48cc6e 100644 --- a/artiq/test/test_datasets.py +++ b/artiq/test/test_datasets.py @@ -46,7 +46,7 @@ class ExperimentDatasetCase(unittest.TestCase): # connection would marshal updates between dataset_mgr and dataset_db. self.dataset_db = MockDatasetDB() self.dataset_mgr = DatasetManager(self.dataset_db) - self.exp = TestExperiment((None, self.dataset_mgr, None)) + self.exp = TestExperiment((None, self.dataset_mgr, None, None)) def test_set_local(self): with self.assertRaises(KeyError): From e61320d409a8a60da6f7fe320711f115a15c83e8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Mar 2019 13:24:35 +0800 Subject: [PATCH 1719/2457] improve system-related questions in issue template --- .github/ISSUE_TEMPLATE/1_Bug_Report.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/1_Bug_Report.md b/.github/ISSUE_TEMPLATE/1_Bug_Report.md index 0442cafa4..eb979554f 100644 --- a/.github/ISSUE_TEMPLATE/1_Bug_Report.md +++ b/.github/ISSUE_TEMPLATE/1_Bug_Report.md @@ -10,7 +10,7 @@ about: Report a bug in ARTIQ ## One-Line Summary @@ -37,8 +37,10 @@ Behavior ### Your System * Operating System: -* Conda version: -* ARTIQ version: (package or git commit id, versions for bitstream, bootloader, runtime and host software). Run `conda list` +* ARTIQ version: (with recent versions of ARTIQ, run ``artiq_client --version``) +* Version of the gateware and runtime loaded in the core device: (in the output of ``artiq_coremgmt -D .... log``) +* If using Nix, version of nixpkgs: +* If using Conda, output of `conda list`: * Hardware involved: @@ -34,13 +34,12 @@ Behavior * Text description * Log message, tracebacks, screen shots where relevant -### Your System +### Your System (omit irrelevant parts) * Operating System: * ARTIQ version: (with recent versions of ARTIQ, run ``artiq_client --version``) * Version of the gateware and runtime loaded in the core device: (in the output of ``artiq_coremgmt -D .... log``) -* If using Nix, version of nixpkgs (run ``nix-instantiate --eval -E '(import {}).lib.version'``): -* If using Conda, output of `conda list`: +* If using Conda, output of `conda list` (please submit as a file attachment, as this tends to be long) * Hardware involved: phy - packetizer.source.connect(tx_fifo.sink), - tx_fifo.source.connect(phy.sink), - - # phy --> core - phy.source.connect(rx_fifo.sink), - rx_fifo.source.connect(depacketizer.sink), - - # etherbone <--> core - depacketizer.source.connect(etherbone.sink), - etherbone.source.connect(packetizer.sink) - ] diff --git a/artiq/gateware/serwb/datapath.py b/artiq/gateware/serwb/datapath.py deleted file mode 100644 index f91cd602f..000000000 --- a/artiq/gateware/serwb/datapath.py +++ /dev/null @@ -1,200 +0,0 @@ -from migen import * -from migen.genlib.io import * -from migen.genlib.misc import BitSlip, WaitTimer - -from misoc.interconnect import stream -from misoc.cores.code_8b10b import Encoder, Decoder - -from artiq.gateware.serwb.scrambler import Scrambler, Descrambler - - -def K(x, y): - return (y << 5) | x - - -class _8b10bEncoder(Module): - def __init__(self): - self.sink = sink = stream.Endpoint([("d", 32), ("k", 4)]) - self.source = source = stream.Endpoint([("data", 40)]) - - # # # - - encoder = CEInserter()(Encoder(4, True)) - self.submodules += encoder - - # control - self.comb += [ - source.stb.eq(sink.stb), - sink.ack.eq(source.ack), - encoder.ce.eq(source.stb & source.ack) - ] - - # datapath - for i in range(4): - self.comb += [ - encoder.k[i].eq(sink.k[i]), - encoder.d[i].eq(sink.d[8*i:8*(i+1)]), - source.data[10*i:10*(i+1)].eq(encoder.output[i]) - ] - - -class _8b10bDecoder(Module): - def __init__(self): - self.sink = sink = stream.Endpoint([("data", 40)]) - self.source = source = stream.Endpoint([("d", 32), ("k", 4)]) - - # # # - - decoders = [CEInserter()(Decoder(True)) for _ in range(4)] - self.submodules += decoders - - # control - self.comb += [ - source.stb.eq(sink.stb), - sink.ack.eq(source.ack) - ] - self.comb += [decoders[i].ce.eq(source.stb & source.ack) for i in range(4)] - - # datapath - for i in range(4): - self.comb += [ - decoders[i].input.eq(sink.data[10*i:10*(i+1)]), - source.k[i].eq(decoders[i].k), - source.d[8*i:8*(i+1)].eq(decoders[i].d) - ] - - -class _Bitslip(Module): - def __init__(self): - self.value = value = Signal(6) - self.sink = sink = stream.Endpoint([("data", 40)]) - self.source = source = stream.Endpoint([("data", 40)]) - - # # # - - bitslip = CEInserter()(BitSlip(40)) - self.submodules += bitslip - - # control - self.comb += [ - source.stb.eq(sink.stb), - sink.ack.eq(source.ack), - bitslip.value.eq(value), - bitslip.ce.eq(source.stb & source.ack) - ] - - # datapath - self.comb += [ - bitslip.i.eq(sink.data), - source.data.eq(bitslip.o) - ] - - -class TXDatapath(Module): - def __init__(self, phy_dw, with_scrambling=True): - self.idle = idle = Signal() - self.comma = comma = Signal() - self.sink = sink = stream.Endpoint([("data", 32)]) - self.source = source = stream.Endpoint([("data", phy_dw)]) - - # # # - - # scrambler - if with_scrambling: - self.submodules.scrambler = scrambler = Scrambler() - - # line coding - self.submodules.encoder = encoder = _8b10bEncoder() - - # converter - self.submodules.converter = converter = stream.Converter(40, phy_dw) - - # dataflow - if with_scrambling: - self.comb += [ - sink.connect(scrambler.sink), - If(comma, - encoder.sink.stb.eq(1), - encoder.sink.k.eq(1), - encoder.sink.d.eq(K(28,5)) - ).Else( - scrambler.source.connect(encoder.sink) - ) - ] - else: - self.comb += [ - If(comma, - encoder.sink.stb.eq(1), - encoder.sink.k.eq(1), - encoder.sink.d.eq(K(28,5)) - ).Else( - sink.connect(encoder.sink, omit={"data"}), - encoder.sink.d.eq(sink.data) - ), - ] - self.comb += [ - If(idle, - converter.sink.stb.eq(1), - converter.sink.data.eq(0) - ).Else( - encoder.source.connect(converter.sink), - ), - converter.source.connect(source) - ] - - -class RXDatapath(Module): - def __init__(self, phy_dw, with_scrambling=True): - self.bitslip_value = bitslip_value = Signal(6) - self.sink = sink = stream.Endpoint([("data", phy_dw)]) - self.source = source = stream.Endpoint([("data", 32)]) - self.idle = idle = Signal() - self.comma = comma = Signal() - - # # # - - # converter - self.submodules.converter = converter = stream.Converter(phy_dw, 40) - - # bitslip - self.submodules.bitslip = bitslip = _Bitslip() - self.comb += bitslip.value.eq(bitslip_value) - - # line coding - self.submodules.decoder = decoder = _8b10bDecoder() - - # descrambler - if with_scrambling: - self.submodules.descrambler = descrambler = Descrambler() - - # dataflow - self.comb += [ - sink.connect(converter.sink), - converter.source.connect(bitslip.sink), - bitslip.source.connect(decoder.sink) - ] - if with_scrambling: - self.comb += [ - decoder.source.connect(descrambler.sink), - descrambler.source.connect(source) - ] - else: - self.comb += [ - decoder.source.connect(source, omit={"d", "k"}), - source.data.eq(decoder.source.d) - ] - - # idle decoding - idle_timer = WaitTimer(32) - self.submodules += idle_timer - self.sync += [ - If(converter.source.stb, - idle_timer.wait.eq((converter.source.data == 0) | (converter.source.data == (2**40-1))) - ), - idle.eq(idle_timer.done) - ] - # comma decoding - self.sync += \ - If(decoder.source.stb, - comma.eq((decoder.source.k == 1) & (decoder.source.d == K(28, 5))) - ) diff --git a/artiq/gateware/serwb/etherbone.py b/artiq/gateware/serwb/etherbone.py deleted file mode 100644 index f0fcf2632..000000000 --- a/artiq/gateware/serwb/etherbone.py +++ /dev/null @@ -1,741 +0,0 @@ -""" -Etherbone - -CERN's Etherbone protocol is initially used to run a Wishbone bus over an -ethernet network. This re-implementation is meant to be run over serdes -and introduces some limitations: -- no probing (pf/pr) -- no address spaces (rca/bca/wca/wff) -- 32bits data and address -- 1 record per frame -""" - -from migen import * - -from misoc.interconnect import stream -from misoc.interconnect import wishbone - -from artiq.gateware.serwb.packet import * - - -class _Packetizer(Module): - def __init__(self, sink_description, source_description, header): - self.sink = sink = stream.Endpoint(sink_description) - self.source = source = stream.Endpoint(source_description) - self.header = Signal(header.length*8) - - # # # - - dw = len(self.sink.data) - - header_reg = Signal(header.length*8, reset_less=True) - header_words = (header.length*8)//dw - load = Signal() - shift = Signal() - counter = Signal(max=max(header_words, 2)) - counter_reset = Signal() - counter_ce = Signal() - self.sync += \ - If(counter_reset, - counter.eq(0) - ).Elif(counter_ce, - counter.eq(counter + 1) - ) - - self.comb += header.encode(sink, self.header) - if header_words == 1: - self.sync += [ - If(load, - header_reg.eq(self.header) - ) - ] - else: - self.sync += [ - If(load, - header_reg.eq(self.header) - ).Elif(shift, - header_reg.eq(Cat(header_reg[dw:], Signal(dw))) - ) - ] - - fsm = FSM(reset_state="IDLE") - self.submodules += fsm - - if header_words == 1: - idle_next_state = "COPY" - else: - idle_next_state = "SEND_HEADER" - - fsm.act("IDLE", - sink.ack.eq(1), - counter_reset.eq(1), - If(sink.stb, - sink.ack.eq(0), - source.stb.eq(1), - source.eop.eq(0), - source.data.eq(self.header[:dw]), - If(source.stb & source.ack, - load.eq(1), - NextState(idle_next_state) - ) - ) - ) - if header_words != 1: - fsm.act("SEND_HEADER", - source.stb.eq(1), - source.eop.eq(0), - source.data.eq(header_reg[dw:2*dw]), - If(source.stb & source.ack, - shift.eq(1), - counter_ce.eq(1), - If(counter == header_words-2, - NextState("COPY") - ) - ) - ) - if hasattr(sink, "error"): - self.comb += source.error.eq(sink.error) - fsm.act("COPY", - source.stb.eq(sink.stb), - source.eop.eq(sink.eop), - source.data.eq(sink.data), - If(source.stb & source.ack, - sink.ack.eq(1), - If(source.eop, - NextState("IDLE") - ) - ) - ) - - -class _Depacketizer(Module): - def __init__(self, sink_description, source_description, header): - self.sink = sink = stream.Endpoint(sink_description) - self.source = source = stream.Endpoint(source_description) - self.header = Signal(header.length*8) - - # # # - - dw = len(sink.data) - - header_reg = Signal(header.length*8, reset_less=True) - header_words = (header.length*8)//dw - - shift = Signal() - counter = Signal(max=max(header_words, 2)) - counter_reset = Signal() - counter_ce = Signal() - self.sync += \ - If(counter_reset, - counter.eq(0) - ).Elif(counter_ce, - counter.eq(counter + 1) - ) - - if header_words == 1: - self.sync += \ - If(shift, - header_reg.eq(sink.data) - ) - else: - self.sync += \ - If(shift, - header_reg.eq(Cat(header_reg[dw:], sink.data)) - ) - self.comb += self.header.eq(header_reg) - - fsm = FSM(reset_state="IDLE") - self.submodules += fsm - - if header_words == 1: - idle_next_state = "COPY" - else: - idle_next_state = "RECEIVE_HEADER" - - fsm.act("IDLE", - sink.ack.eq(1), - counter_reset.eq(1), - If(sink.stb, - shift.eq(1), - NextState(idle_next_state) - ) - ) - if header_words != 1: - fsm.act("RECEIVE_HEADER", - sink.ack.eq(1), - If(sink.stb, - counter_ce.eq(1), - shift.eq(1), - If(counter == header_words-2, - NextState("COPY") - ) - ) - ) - no_payload = Signal() - self.sync += \ - If(fsm.before_entering("COPY"), - no_payload.eq(sink.eop) - ) - - if hasattr(sink, "error"): - self.comb += source.error.eq(sink.error) - self.comb += [ - source.eop.eq(sink.eop | no_payload), - source.data.eq(sink.data), - header.decode(self.header, source) - ] - fsm.act("COPY", - sink.ack.eq(source.ack), - source.stb.eq(sink.stb | no_payload), - If(source.stb & source.ack & source.eop, - NextState("IDLE") - ) - ) - - -etherbone_magic = 0x4e6f -etherbone_version = 1 -etherbone_packet_header_length = 8 -etherbone_packet_header_fields = { - "magic": HeaderField(0, 0, 16), - - "version": HeaderField(2, 4, 4), - "nr": HeaderField(2, 2, 1), - "pr": HeaderField(2, 1, 1), # unused - "pf": HeaderField(2, 0, 1), # unused - - "addr_size": HeaderField(3, 4, 4), # static - "port_size": HeaderField(3, 0, 4) # static -} -etherbone_packet_header = Header(etherbone_packet_header_fields, - etherbone_packet_header_length, - swap_field_bytes=True) - -etherbone_record_header_length = 4 -etherbone_record_header_fields = { - "bca": HeaderField(0, 0, 1), # unused - "rca": HeaderField(0, 1, 1), # unused - "rff": HeaderField(0, 2, 1), # unused - "cyc": HeaderField(0, 4, 1), # unused - "wca": HeaderField(0, 5, 1), # unused - "wff": HeaderField(0, 6, 1), # unused - - "byte_enable": HeaderField(1, 0, 8), - - "wcount": HeaderField(2, 0, 8), - - "rcount": HeaderField(3, 0, 8) -} -etherbone_record_header = Header(etherbone_record_header_fields, - etherbone_record_header_length, - swap_field_bytes=True) - -def _remove_from_layout(layout, *args): - r = [] - for f in layout: - remove = False - for arg in args: - if f[0] == arg: - remove = True - if not remove: - r.append(f) - return r - -def etherbone_packet_description(dw): - layout = etherbone_packet_header.get_layout() - layout += [("data", dw)] - return stream.EndpointDescription(layout) - -def etherbone_packet_user_description(dw): - layout = etherbone_packet_header.get_layout() - layout = _remove_from_layout(layout, - "magic", - "portsize", - "addrsize", - "version") - layout += user_description(dw).payload_layout - return stream.EndpointDescription(layout) - -def etherbone_record_description(dw): - layout = etherbone_record_header.get_layout() - layout += [("data", dw)] - return stream.EndpointDescription(layout) - -def etherbone_mmap_description(dw): - layout = [ - ("we", 1), - ("count", 8), - ("base_addr", 32), - ("be", dw//8), - ("addr", 32), - ("data", dw) - ] - return stream.EndpointDescription(layout) - - -# etherbone packet - -class _EtherbonePacketPacketizer(_Packetizer): - def __init__(self): - _Packetizer.__init__(self, - etherbone_packet_description(32), - user_description(32), - etherbone_packet_header) - - -class _EtherbonePacketTX(Module): - def __init__(self): - self.sink = sink = stream.Endpoint(etherbone_packet_user_description(32)) - self.source = source = stream.Endpoint(user_description(32)) - - # # # - - self.submodules.packetizer = packetizer = _EtherbonePacketPacketizer() - self.comb += [ - packetizer.sink.stb.eq(sink.stb), - packetizer.sink.eop.eq(sink.eop), - sink.ack.eq(packetizer.sink.ack), - - packetizer.sink.magic.eq(etherbone_magic), - packetizer.sink.port_size.eq(32//8), - packetizer.sink.addr_size.eq(32//8), - packetizer.sink.nr.eq(sink.nr), - packetizer.sink.version.eq(etherbone_version), - - packetizer.sink.data.eq(sink.data) - ] - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - packetizer.source.ack.eq(1), - If(packetizer.source.stb, - packetizer.source.ack.eq(0), - NextState("SEND") - ) - ) - fsm.act("SEND", - packetizer.source.connect(source), - source.length.eq(sink.length + etherbone_packet_header.length), - If(source.stb & source.eop & source.ack, - NextState("IDLE") - ) - ) - - -class _EtherbonePacketDepacketizer(_Depacketizer): - def __init__(self): - _Depacketizer.__init__(self, - user_description(32), - etherbone_packet_description(32), - etherbone_packet_header) - - -class _EtherbonePacketRX(Module): - def __init__(self): - self.sink = sink = stream.Endpoint(user_description(32)) - self.source = source = stream.Endpoint(etherbone_packet_user_description(32)) - - # # # - - self.submodules.depacketizer = depacketizer = _EtherbonePacketDepacketizer() - self.comb += sink.connect(depacketizer.sink) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - depacketizer.source.ack.eq(1), - If(depacketizer.source.stb, - depacketizer.source.ack.eq(0), - NextState("CHECK") - ) - ) - stb = Signal() - self.sync += stb.eq( - depacketizer.source.stb & - (depacketizer.source.magic == etherbone_magic) - ) - fsm.act("CHECK", - If(stb, - NextState("PRESENT") - ).Else( - NextState("DROP") - ) - ) - self.comb += [ - source.eop.eq(depacketizer.source.eop), - - source.nr.eq(depacketizer.source.nr), - - source.data.eq(depacketizer.source.data), - - source.length.eq(sink.length - etherbone_packet_header.length) - ] - fsm.act("PRESENT", - source.stb.eq(depacketizer.source.stb), - depacketizer.source.ack.eq(source.ack), - If(source.stb & source.eop & source.ack, - NextState("IDLE") - ) - ) - fsm.act("DROP", - depacketizer.source.ack.eq(1), - If(depacketizer.source.stb & - depacketizer.source.eop & - depacketizer.source.ack, - NextState("IDLE") - ) - ) - - -class _EtherbonePacket(Module): - def __init__(self, port_sink, port_source): - self.submodules.tx = tx = _EtherbonePacketTX() - self.submodules.rx = rx = _EtherbonePacketRX() - self.comb += [ - tx.source.connect(port_sink), - port_source.connect(rx.sink) - ] - self.sink, self.source = self.tx.sink, self.rx.source - -# etherbone record - -class _EtherboneRecordPacketizer(_Packetizer): - def __init__(self): - _Packetizer.__init__(self, - etherbone_record_description(32), - etherbone_packet_user_description(32), - etherbone_record_header) - - -class _EtherboneRecordDepacketizer(_Depacketizer): - def __init__(self): - _Depacketizer.__init__(self, - etherbone_packet_user_description(32), - etherbone_record_description(32), - etherbone_record_header) - - -class _EtherboneRecordReceiver(Module): - def __init__(self, buffer_depth=4): - self.sink = sink = stream.Endpoint(etherbone_record_description(32)) - self.source = source = stream.Endpoint(etherbone_mmap_description(32)) - - # # # - - fifo = stream.SyncFIFO(etherbone_record_description(32), buffer_depth, - buffered=True) - self.submodules += fifo - self.comb += sink.connect(fifo.sink) - - base_addr = Signal(32) - base_addr_update = Signal() - self.sync += If(base_addr_update, base_addr.eq(fifo.source.data)) - - counter = Signal(max=512) - counter_reset = Signal() - counter_ce = Signal() - self.sync += \ - If(counter_reset, - counter.eq(0) - ).Elif(counter_ce, - counter.eq(counter + 1) - ) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - fifo.source.ack.eq(1), - counter_reset.eq(1), - If(fifo.source.stb, - base_addr_update.eq(1), - If(fifo.source.wcount, - NextState("RECEIVE_WRITES") - ).Elif(fifo.source.rcount, - NextState("RECEIVE_READS") - - ) - ) - ) - fsm.act("RECEIVE_WRITES", - source.stb.eq(fifo.source.stb), - source.eop.eq(counter == fifo.source.wcount-1), - source.count.eq(fifo.source.wcount), - source.be.eq(fifo.source.byte_enable), - source.addr.eq(base_addr[2:] + counter), - source.we.eq(1), - source.data.eq(fifo.source.data), - fifo.source.ack.eq(source.ack), - If(source.stb & source.ack, - counter_ce.eq(1), - If(source.eop, - If(fifo.source.rcount, - NextState("RECEIVE_BASE_RET_ADDR") - ).Else( - NextState("IDLE") - ) - ) - ) - ) - fsm.act("RECEIVE_BASE_RET_ADDR", - counter_reset.eq(1), - If(fifo.source.stb, - base_addr_update.eq(1), - NextState("RECEIVE_READS") - ) - ) - fsm.act("RECEIVE_READS", - source.stb.eq(fifo.source.stb), - source.eop.eq(counter == fifo.source.rcount-1), - source.count.eq(fifo.source.rcount), - source.base_addr.eq(base_addr), - source.addr.eq(fifo.source.data[2:]), - fifo.source.ack.eq(source.ack), - If(source.stb & source.ack, - counter_ce.eq(1), - If(source.eop, - NextState("IDLE") - ) - ) - ) - - -class _EtherboneRecordSender(Module): - def __init__(self, buffer_depth=4): - self.sink = sink = stream.Endpoint(etherbone_mmap_description(32)) - self.source = source = stream.Endpoint(etherbone_record_description(32)) - - # # # - - pbuffer = stream.SyncFIFO(etherbone_mmap_description(32), buffer_depth, - buffered=True) - self.submodules += pbuffer - self.comb += sink.connect(pbuffer.sink) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - pbuffer.source.ack.eq(1), - If(pbuffer.source.stb, - pbuffer.source.ack.eq(0), - NextState("SEND_BASE_ADDRESS") - ) - ) - self.comb += [ - source.byte_enable.eq(pbuffer.source.be), - If(pbuffer.source.we, - source.wcount.eq(pbuffer.source.count) - ).Else( - source.rcount.eq(pbuffer.source.count) - ) - ] - - fsm.act("SEND_BASE_ADDRESS", - source.stb.eq(pbuffer.source.stb), - source.eop.eq(0), - source.data.eq(pbuffer.source.base_addr), - If(source.ack, - NextState("SEND_DATA") - ) - ) - fsm.act("SEND_DATA", - source.stb.eq(pbuffer.source.stb), - source.eop.eq(pbuffer.source.eop), - source.data.eq(pbuffer.source.data), - If(source.stb & source.ack, - pbuffer.source.ack.eq(1), - If(source.eop, - NextState("IDLE") - ) - ) - ) - - -class _EtherboneRecord(Module): - def __init__(self): - self.sink = sink = stream.Endpoint(etherbone_packet_user_description(32)) - self.source = source = stream.Endpoint(etherbone_packet_user_description(32)) - - # # # - - # receive record, decode it and generate mmap stream - self.submodules.depacketizer = depacketizer = _EtherboneRecordDepacketizer() - self.submodules.receiver = receiver = _EtherboneRecordReceiver() - self.comb += [ - sink.connect(depacketizer.sink), - depacketizer.source.connect(receiver.sink) - ] - - # receive mmap stream, encode it and send records - self.submodules.sender = sender = _EtherboneRecordSender() - self.submodules.packetizer = packetizer = _EtherboneRecordPacketizer() - self.comb += [ - sender.source.connect(packetizer.sink), - packetizer.source.connect(source), - source.length.eq(etherbone_record_header.length + - (sender.source.wcount != 0)*4 + sender.source.wcount*4 + - (sender.source.rcount != 0)*4 + sender.source.rcount*4) - ] - - -# etherbone wishbone - -class _EtherboneWishboneMaster(Module): - def __init__(self): - self.sink = sink = stream.Endpoint(etherbone_mmap_description(32)) - self.source = source = stream.Endpoint(etherbone_mmap_description(32)) - self.bus = bus = wishbone.Interface() - - # # # - - data = Signal(32) - data_update = Signal() - self.sync += If(data_update, data.eq(bus.dat_r)) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - sink.ack.eq(1), - If(sink.stb, - sink.ack.eq(0), - If(sink.we, - NextState("WRITE_DATA") - ).Else( - NextState("READ_DATA") - ) - ) - ) - fsm.act("WRITE_DATA", - bus.adr.eq(sink.addr), - bus.dat_w.eq(sink.data), - bus.sel.eq(sink.be), - bus.stb.eq(sink.stb), - bus.we.eq(1), - bus.cyc.eq(1), - If(bus.stb & bus.ack, - sink.ack.eq(1), - If(sink.eop, - NextState("IDLE") - ) - ) - ) - fsm.act("READ_DATA", - bus.adr.eq(sink.addr), - bus.sel.eq(sink.be), - bus.stb.eq(sink.stb), - bus.cyc.eq(1), - If(bus.stb & bus.ack, - data_update.eq(1), - NextState("SEND_DATA") - ) - ) - fsm.act("SEND_DATA", - source.stb.eq(sink.stb), - source.eop.eq(sink.eop), - source.base_addr.eq(sink.base_addr), - source.addr.eq(sink.addr), - source.count.eq(sink.count), - source.be.eq(sink.be), - source.we.eq(1), - source.data.eq(data), - If(source.stb & source.ack, - sink.ack.eq(1), - If(source.eop, - NextState("IDLE") - ).Else( - NextState("READ_DATA") - ) - ) - ) - - -class _EtherboneWishboneSlave(Module): - def __init__(self): - self.bus = bus = wishbone.Interface() - self.ready = Signal(reset=1) - self.sink = sink = stream.Endpoint(etherbone_mmap_description(32)) - self.source = source = stream.Endpoint(etherbone_mmap_description(32)) - - # # # - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - sink.ack.eq(1), - If(bus.stb & bus.cyc, - If(self.ready, - If(bus.we, - NextState("SEND_WRITE") - ).Else( - NextState("SEND_READ") - ) - ).Else( - NextState("SEND_ERROR") - ) - ) - ) - fsm.act("SEND_WRITE", - If(~self.ready, - NextState("SEND_ERROR") - ).Else( - source.stb.eq(1), - source.eop.eq(1), - source.base_addr[2:].eq(bus.adr), - source.count.eq(1), - source.be.eq(bus.sel), - source.we.eq(1), - source.data.eq(bus.dat_w), - If(source.stb & source.ack, - bus.ack.eq(1), - NextState("IDLE") - ) - ) - ) - fsm.act("SEND_READ", - If(~self.ready, - NextState("SEND_ERROR") - ).Else( - source.stb.eq(1), - source.eop.eq(1), - source.base_addr.eq(0), - source.count.eq(1), - source.be.eq(bus.sel), - source.we.eq(0), - source.data[2:].eq(bus.adr), - If(source.stb & source.ack, - NextState("WAIT_READ") - ) - ) - ) - fsm.act("WAIT_READ", - sink.ack.eq(1), - If(~self.ready, - NextState("SEND_ERROR") - ).Elif(sink.stb & sink.we, - bus.ack.eq(1), - bus.dat_r.eq(sink.data), - NextState("IDLE") - ) - ) - fsm.act("SEND_ERROR", - bus.ack.eq(1), - bus.err.eq(1) - ) - -# etherbone - -class Etherbone(Module): - def __init__(self, mode="master"): - self.sink = sink = stream.Endpoint(user_description(32)) - self.source = source = stream.Endpoint(user_description(32)) - - # # # - - self.submodules.packet = _EtherbonePacket(source, sink) - self.submodules.record = _EtherboneRecord() - if mode == "master": - self.submodules.wishbone = _EtherboneWishboneMaster() - elif mode == "slave": - self.submodules.wishbone = _EtherboneWishboneSlave() - else: - raise ValueError - - self.comb += [ - self.packet.source.connect(self.record.sink), - self.record.source.connect(self.packet.sink), - self.record.receiver.source.connect(self.wishbone.sink), - self.wishbone.source.connect(self.record.sender.sink) - ] diff --git a/artiq/gateware/serwb/genphy.py b/artiq/gateware/serwb/genphy.py deleted file mode 100644 index d4d5c0cc5..000000000 --- a/artiq/gateware/serwb/genphy.py +++ /dev/null @@ -1,346 +0,0 @@ -from migen import * -from migen.genlib.io import * -from migen.genlib.misc import BitSlip, WaitTimer - -from misoc.interconnect import stream -from misoc.interconnect.csr import * - -from artiq.gateware.serwb.datapath import TXDatapath, RXDatapath - - -class _SerdesClocking(Module): - def __init__(self, pads, mode="master"): - self.refclk = Signal() - - # # # - - # In Master mode, generate the clock with 180° phase shift so that Slave - # can use this clock to sample data - if mode == "master": - self.specials += DDROutput(0, 1, self.refclk) - if hasattr(pads, "clk_p"): - self.specials += DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) - else: - self.comb += pads.clk.eq(self.refclk) - # In Slave mode, use the clock provided by Master - elif mode == "slave": - if hasattr(pads, "clk_p"): - self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk) - else: - self.comb += self.refclk.eq(pads.clk) - else: - raise ValueError - - -class _SerdesTX(Module): - def __init__(self, pads): - # Control - self.idle = idle = Signal() - self.comma = comma = Signal() - - # Datapath - self.sink = sink = stream.Endpoint([("data", 32)]) - - # # # - - # Datapath - self.submodules.datapath = datapath = TXDatapath(1) - self.comb += [ - sink.connect(datapath.sink), - datapath.source.ack.eq(1), - datapath.idle.eq(idle), - datapath.comma.eq(comma) - ] - - # Output data (on rising edge of sys_clk) - data = Signal() - self.sync += data.eq(datapath.source.data) - if hasattr(pads, "tx_p"): - self.specials += DifferentialOutput(data, pads.tx_p, pads.tx_n) - else: - self.comb += pads.tx.eq(data) - - -class _SerdesRX(Module): - def __init__(self, pads): - # Control - self.bitslip_value = bitslip_value = Signal(6) - - # Status - self.idle = idle = Signal() - self.comma = comma = Signal() - - # Datapath - self.source = source = stream.Endpoint([("data", 32)]) - - # # # - - # Input data (on rising edge of sys_clk) - data = Signal() - data_d = Signal() - if hasattr(pads, "rx_p"): - self.specials += DifferentialInput(pads.rx_p, pads.rx_n, data) - else: - self.comb += data.eq(pads.rx) - self.sync += data_d.eq(data) - - # Datapath - self.submodules.datapath = datapath = RXDatapath(1) - self.comb += [ - datapath.sink.stb.eq(1), - datapath.sink.data.eq(data_d), - datapath.bitslip_value.eq(bitslip_value), - datapath.source.connect(source), - idle.eq(datapath.idle), - comma.eq(datapath.comma) - ] - - -@ResetInserter() -class _Serdes(Module): - def __init__(self, pads, mode="master"): - self.submodules.clocking = _SerdesClocking(pads, mode) - self.submodules.tx = _SerdesTX(pads) - self.submodules.rx = _SerdesRX(pads) - - -# SERWB Master <--> Slave physical synchronization process: -# 1) Master sends idle patterns (zeroes) to Slave to reset it. -# 2) Master sends K28.5 commas to allow Slave to calibrate, Slave sends idle patterns. -# 3) Slave sends K28.5 commas to allow Master to calibrate, Master sends K28.5 commas. -# 4) Master stops sending K28.5 commas. -# 5) Slave stops sending K28.5 commas. -# 6) Physical link is ready. - - -@ResetInserter() -class _SerdesMasterInit(Module): - def __init__(self, serdes, timeout): - self.ready = Signal() - self.error = Signal() - - # # # - - self.bitslip = bitslip = Signal(max=40) - - self.submodules.timer = timer = WaitTimer(timeout) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - NextValue(bitslip, 0), - NextState("RESET_SLAVE"), - serdes.tx.idle.eq(1) - ) - fsm.act("RESET_SLAVE", - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("SEND_PATTERN") - ), - serdes.tx.idle.eq(1) - ) - fsm.act("SEND_PATTERN", - If(~serdes.rx.idle, - timer.wait.eq(1), - If(timer.done, - NextState("CHECK_PATTERN") - ) - ), - serdes.tx.comma.eq(1) - ) - fsm.act("WAIT_STABLE", - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("CHECK_PATTERN") - ), - serdes.tx.comma.eq(1) - ) - fsm.act("CHECK_PATTERN", - If(serdes.rx.comma, - timer.wait.eq(1), - If(timer.done, - NextState("READY") - ) - ).Else( - NextState("INC_BITSLIP") - ), - serdes.tx.comma.eq(1) - ) - self.comb += serdes.rx.bitslip_value.eq(bitslip) - fsm.act("INC_BITSLIP", - NextState("WAIT_STABLE"), - If(bitslip == (40 - 1), - NextState("ERROR") - ).Else( - NextValue(bitslip, bitslip + 1) - ), - serdes.tx.comma.eq(1) - ) - fsm.act("READY", - self.ready.eq(1) - ) - fsm.act("ERROR", - self.error.eq(1) - ) - - -@ResetInserter() -class _SerdesSlaveInit(Module, AutoCSR): - def __init__(self, serdes, timeout): - self.ready = Signal() - self.error = Signal() - - # # # - - self.bitslip = bitslip = Signal(max=40) - - self.submodules.timer = timer = WaitTimer(timeout) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - # reset - fsm.act("IDLE", - NextValue(bitslip, 0), - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("WAIT_STABLE"), - ), - serdes.tx.idle.eq(1) - ) - fsm.act("WAIT_STABLE", - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("CHECK_PATTERN") - ), - serdes.tx.idle.eq(1) - ) - fsm.act("CHECK_PATTERN", - If(serdes.rx.comma, - timer.wait.eq(1), - If(timer.done, - NextState("SEND_PATTERN") - ) - ).Else( - NextState("INC_BITSLIP") - ), - serdes.tx.idle.eq(1) - ) - self.comb += serdes.rx.bitslip_value.eq(bitslip) - fsm.act("INC_BITSLIP", - NextState("WAIT_STABLE"), - If(bitslip == (40 - 1), - NextState("ERROR") - ).Else( - NextValue(bitslip, bitslip + 1) - ), - serdes.tx.idle.eq(1) - ) - fsm.act("SEND_PATTERN", - timer.wait.eq(1), - If(timer.done, - If(~serdes.rx.comma, - NextState("READY") - ) - ), - serdes.tx.comma.eq(1) - ) - fsm.act("READY", - self.ready.eq(1) - ) - fsm.act("ERROR", - self.error.eq(1) - ) - - -class _SerdesControl(Module, AutoCSR): - def __init__(self, serdes, init, mode="master"): - if mode == "master": - self.reset = CSR() - self.ready = CSRStatus() - self.error = CSRStatus() - - self.bitslip = CSRStatus(6) - - self.prbs_error = Signal() - self.prbs_start = CSR() - self.prbs_cycles = CSRStorage(32) - self.prbs_errors = CSRStatus(32) - - # # # - - if mode == "master": - # In Master mode, reset is coming from CSR, - # it resets the Master that will also reset - # the Slave by putting the link in idle. - self.sync += init.reset.eq(self.reset.re) - else: - # In Slave mode, reset is coming from link, - # Master reset the Slave by putting the link - # in idle. - self.sync += [ - init.reset.eq(serdes.rx.idle), - serdes.reset.eq(serdes.rx.idle) - ] - self.comb += [ - self.ready.status.eq(init.ready), - self.error.status.eq(init.error), - self.bitslip.status.eq(init.bitslip) - ] - - # prbs - prbs_cycles = Signal(32) - prbs_errors = self.prbs_errors.status - prbs_fsm = FSM(reset_state="IDLE") - self.submodules += prbs_fsm - prbs_fsm.act("IDLE", - NextValue(prbs_cycles, 0), - If(self.prbs_start.re, - NextValue(prbs_errors, 0), - NextState("CHECK") - ) - ) - prbs_fsm.act("CHECK", - NextValue(prbs_cycles, prbs_cycles + 1), - If(self.prbs_error, - NextValue(prbs_errors, prbs_errors + 1), - ), - If(prbs_cycles == self.prbs_cycles.storage, - NextState("IDLE") - ) - ) - - -class SERWBPHY(Module, AutoCSR): - def __init__(self, device, pads, mode="master", init_timeout=2**16): - self.sink = sink = stream.Endpoint([("data", 32)]) - self.source = source = stream.Endpoint([("data", 32)]) - assert mode in ["master", "slave"] - self.submodules.serdes = _Serdes(pads, mode) - if mode == "master": - self.submodules.init = _SerdesMasterInit(self.serdes, init_timeout) - else: - self.submodules.init = _SerdesSlaveInit(self.serdes, init_timeout) - self.submodules.control = _SerdesControl(self.serdes, self.init, mode) - - # tx/rx dataflow - self.comb += [ - If(self.init.ready, - If(sink.stb, - sink.connect(self.serdes.tx.sink), - ), - self.serdes.rx.source.connect(source) - ).Else( - self.serdes.rx.source.ack.eq(1) - ), - self.serdes.tx.sink.stb.eq(1) # always transmitting - ] - - # For PRBS test we are using the scrambler/descrambler as PRBS, - # sending 0 to the scrambler and checking that descrambler - # output is always 0. - self.comb += self.control.prbs_error.eq( - source.stb & - source.ack & - (source.data != 0)) diff --git a/artiq/gateware/serwb/kuserdes.py b/artiq/gateware/serwb/kuserdes.py deleted file mode 100644 index f16d1919f..000000000 --- a/artiq/gateware/serwb/kuserdes.py +++ /dev/null @@ -1,149 +0,0 @@ -from migen import * -from migen.genlib.io import * -from migen.genlib.misc import BitSlip, WaitTimer - -from misoc.interconnect import stream -from misoc.cores.code_8b10b import Encoder, Decoder - -from artiq.gateware.serwb.datapath import TXDatapath, RXDatapath - - -class _KUSerdesClocking(Module): - def __init__(self, pads, mode="master"): - self.refclk = Signal() - - # # # - - # In Master mode, generate the linerate/10 clock. Slave will re-multiply it. - if mode == "master": - converter = stream.Converter(40, 8) - self.submodules += converter - self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), - ] - self.specials += [ - Instance("OSERDESE3", - p_DATA_WIDTH=8, p_INIT=0, - p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, - p_IS_RST_INVERTED=0, - - o_OQ=self.refclk, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D=converter.source.data - ), - DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) - ] - - # In Slave mode, multiply the clock provided by Master with a PLL/MMCM - elif mode == "slave": - self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk) - - -class _KUSerdesTX(Module): - def __init__(self, pads): - # Control - self.idle = idle = Signal() - self.comma = comma = Signal() - - # Datapath - self.sink = sink = stream.Endpoint([("data", 32)]) - - # # # - - - # Datapath - self.submodules.datapath = datapath = TXDatapath(8) - self.comb += [ - sink.connect(datapath.sink), - datapath.source.ack.eq(1), - datapath.idle.eq(idle), - datapath.comma.eq(comma) - ] - - # Output Data(DDR with sys4x) - data = Signal() - self.specials += [ - Instance("OSERDESE3", - p_DATA_WIDTH=8, p_INIT=0, - p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, - - o_OQ=data, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D=datapath.source.data - ), - DifferentialOutput(data, pads.tx_p, pads.tx_n) - ] - - -class _KUSerdesRX(Module): - def __init__(self, pads): - # Control - self.delay_rst = Signal() - self.delay_inc = Signal() - self.bitslip_value = bitslip_value = Signal(6) - - # Status - self.idle = idle = Signal() - self.comma = comma = Signal() - - # Datapath - self.source = source = stream.Endpoint([("data", 32)]) - - # # # - - # Data input (DDR with sys4x) - data_nodelay = Signal() - data_delayed = Signal() - data_deserialized = Signal(8) - self.specials += [ - DifferentialInput(pads.rx_p, pads.rx_n, data_nodelay), - Instance("IDELAYE3", - p_CASCADE="NONE", p_UPDATE_MODE="ASYNC", p_REFCLK_FREQUENCY=200.0, - p_IS_CLK_INVERTED=0, p_IS_RST_INVERTED=0, - p_DELAY_FORMAT="COUNT", p_DELAY_SRC="IDATAIN", - p_DELAY_TYPE="VARIABLE", p_DELAY_VALUE=0, - - i_CLK=ClockSignal("sys"), - i_RST=self.delay_rst, i_LOAD=0, - i_INC=1, i_EN_VTC=0, - i_CE=self.delay_inc, - - i_IDATAIN=data_nodelay, o_DATAOUT=data_delayed - ), - Instance("ISERDESE3", - p_IS_CLK_INVERTED=0, - p_IS_CLK_B_INVERTED=1, - p_DATA_WIDTH=8, - - i_D=data_delayed, - i_RST=ResetSignal("sys"), - i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0, - i_CLK=ClockSignal("sys4x"), - i_CLK_B=ClockSignal("sys4x"), # locally inverted - i_CLKDIV=ClockSignal("sys"), - o_Q=data_deserialized - ) - ] - - # Datapath - self.submodules.datapath = datapath = RXDatapath(8) - self.comb += [ - datapath.sink.stb.eq(1), - datapath.sink.data.eq(data_deserialized), - datapath.bitslip_value.eq(bitslip_value), - datapath.source.connect(source), - idle.eq(datapath.idle), - comma.eq(datapath.comma) - ] - - -@ResetInserter() -class KUSerdes(Module): - def __init__(self, pads, mode="master"): - self.submodules.clocking = _KUSerdesClocking(pads, mode) - self.submodules.tx = _KUSerdesTX(pads) - self.submodules.rx = _KUSerdesRX(pads) diff --git a/artiq/gateware/serwb/packet.py b/artiq/gateware/serwb/packet.py deleted file mode 100644 index f22e2d944..000000000 --- a/artiq/gateware/serwb/packet.py +++ /dev/null @@ -1,173 +0,0 @@ -from math import ceil - -from migen import * -from migen.genlib.misc import WaitTimer - -from misoc.interconnect import stream - - -def reverse_bytes(signal): - n = ceil(len(signal)/8) - return Cat(iter([signal[i*8:(i+1)*8] for i in reversed(range(n))])) - - -class HeaderField: - def __init__(self, byte, offset, width): - self.byte = byte - self.offset = offset - self.width = width - - -class Header: - def __init__(self, fields, length, swap_field_bytes=True): - self.fields = fields - self.length = length - self.swap_field_bytes = swap_field_bytes - - def get_layout(self): - layout = [] - for k, v in sorted(self.fields.items()): - layout.append((k, v.width)) - return layout - - def get_field(self, obj, name, width): - if "_lsb" in name: - field = getattr(obj, name.replace("_lsb", ""))[:width] - elif "_msb" in name: - field = getattr(obj, name.replace("_msb", ""))[width:2*width] - else: - field = getattr(obj, name) - if len(field) != width: - raise ValueError("Width mismatch on " + name + " field") - return field - - def encode(self, obj, signal): - r = [] - for k, v in sorted(self.fields.items()): - start = v.byte*8 + v.offset - end = start + v.width - field = self.get_field(obj, k, v.width) - if self.swap_field_bytes: - field = reverse_bytes(field) - r.append(signal[start:end].eq(field)) - return r - - def decode(self, signal, obj): - r = [] - for k, v in sorted(self.fields.items()): - start = v.byte*8 + v.offset - end = start + v.width - field = self.get_field(obj, k, v.width) - if self.swap_field_bytes: - r.append(field.eq(reverse_bytes(signal[start:end]))) - else: - r.append(field.eq(signal[start:end])) - return r - -def phy_description(dw): - layout = [("data", dw)] - return stream.EndpointDescription(layout) - - -def user_description(dw): - layout = [ - ("data", 32), - ("length", 32) - ] - return stream.EndpointDescription(layout) - - -class Packetizer(Module): - def __init__(self): - self.sink = sink = stream.Endpoint(user_description(32)) - self.source = source = stream.Endpoint(phy_description(32)) - - # # # - - # Packet description - # - preamble : 4 bytes - # - length : 4 bytes - # - payload - - fsm = FSM(reset_state="PREAMBLE") - self.submodules += fsm - - fsm.act("PREAMBLE", - If(sink.stb, - source.stb.eq(1), - source.data.eq(0x5aa55aa5), - If(source.ack, - NextState("LENGTH") - ) - ) - ) - fsm.act("LENGTH", - source.stb.eq(1), - source.data.eq(sink.length), - If(source.ack, - NextState("DATA") - ) - ) - fsm.act("DATA", - source.stb.eq(sink.stb), - source.data.eq(sink.data), - sink.ack.eq(source.ack), - If(source.ack & sink.eop, - NextState("PREAMBLE") - ) - ) - - -class Depacketizer(Module): - def __init__(self, clk_freq, timeout=10): - self.sink = sink = stream.Endpoint(phy_description(32)) - self.source = source = stream.Endpoint(user_description(32)) - - # # # - - count = Signal(len(source.length)) - length = Signal(len(source.length)) - - # Packet description - # - preamble : 4 bytes - # - length : 4 bytes - # - payload - - fsm = FSM(reset_state="PREAMBLE") - self.submodules += fsm - - timer = WaitTimer(clk_freq*timeout) - self.submodules += timer - - fsm.act("PREAMBLE", - sink.ack.eq(1), - If(sink.stb & - (sink.data == 0x5aa55aa5), - NextState("LENGTH") - ) - ) - fsm.act("LENGTH", - sink.ack.eq(1), - If(sink.stb, - NextValue(count, 0), - NextValue(length, sink.data), - NextState("DATA") - ), - timer.wait.eq(1) - ) - fsm.act("DATA", - source.stb.eq(sink.stb), - source.eop.eq(count == (length[2:] - 1)), - source.length.eq(length), - source.data.eq(sink.data), - sink.ack.eq(source.ack), - If(timer.done, - NextState("PREAMBLE") - ).Elif(source.stb & source.ack, - NextValue(count, count + 1), - If(source.eop, - NextState("PREAMBLE") - ) - ), - timer.wait.eq(1) - ) diff --git a/artiq/gateware/serwb/phy.py b/artiq/gateware/serwb/phy.py deleted file mode 100644 index d878cfb17..000000000 --- a/artiq/gateware/serwb/phy.py +++ /dev/null @@ -1,381 +0,0 @@ -from migen import * -from migen.genlib.misc import WaitTimer - -from misoc.interconnect import stream -from misoc.interconnect.csr import * - -from artiq.gateware.serwb.kuserdes import KUSerdes -from artiq.gateware.serwb.s7serdes import S7Serdes - - -# SERWB Master <--> Slave physical synchronization process: -# 1) Master sends idle patterns (zeroes) to Slave to reset it. -# 2) Master sends K28.5 commas to allow Slave to calibrate, Slave sends idle patterns. -# 3) Slave sends K28.5 commas to allow Master to calibrate, Master sends K28.5 commas. -# 4) Master stops sending K28.5 commas. -# 5) Slave stops sending K28.5 commas. -# 6) Physical link is ready. - - -@ResetInserter() -class _SerdesMasterInit(Module): - def __init__(self, serdes, taps, timeout): - self.ready = Signal() - self.error = Signal() - - # # # - - self.delay = delay = Signal(max=taps) - self.delay_min = delay_min = Signal(max=taps) - self.delay_min_found = delay_min_found = Signal() - self.delay_max = delay_max = Signal(max=taps) - self.delay_max_found = delay_max_found = Signal() - self.bitslip = bitslip = Signal(max=40) - - self.submodules.timer = timer = WaitTimer(timeout) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - NextValue(delay, 0), - NextValue(delay_min, 0), - NextValue(delay_min_found, 0), - NextValue(delay_max, 0), - NextValue(delay_max_found, 0), - serdes.rx.delay_rst.eq(1), - NextValue(bitslip, 0), - NextState("RESET_SLAVE"), - serdes.tx.idle.eq(1) - ) - fsm.act("RESET_SLAVE", - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("SEND_PATTERN") - ), - serdes.tx.idle.eq(1) - ) - fsm.act("SEND_PATTERN", - If(~serdes.rx.idle, - timer.wait.eq(1), - If(timer.done, - NextState("CHECK_PATTERN") - ) - ), - serdes.tx.comma.eq(1) - ) - fsm.act("WAIT_STABLE", - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("CHECK_PATTERN") - ), - serdes.tx.comma.eq(1) - ) - fsm.act("CHECK_PATTERN", - If(~delay_min_found, - If(serdes.rx.comma, - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextValue(delay_min, delay), - NextValue(delay_min_found, 1) - ) - ).Else( - NextState("INC_DELAY_BITSLIP") - ), - ).Else( - If(~serdes.rx.comma, - NextValue(delay_max, delay), - NextValue(delay_max_found, 1), - NextState("CHECK_SAMPLING_WINDOW") - ).Else( - NextState("INC_DELAY_BITSLIP") - ) - ), - serdes.tx.comma.eq(1) - ) - self.comb += serdes.rx.bitslip_value.eq(bitslip) - fsm.act("INC_DELAY_BITSLIP", - NextState("WAIT_STABLE"), - If(delay == (taps - 1), - If(bitslip == (40 - 1), - NextState("ERROR") - ).Else( - NextValue(delay_min_found, 0), - NextValue(delay_min, 0), - NextValue(delay_max_found, 0), - NextValue(delay_max, 0), - NextValue(bitslip, bitslip + 1) - ), - NextValue(delay, 0), - serdes.rx.delay_rst.eq(1) - ).Else( - NextValue(delay, delay + 1), - serdes.rx.delay_inc.eq(1) - ), - serdes.tx.comma.eq(1) - ) - fsm.act("CHECK_SAMPLING_WINDOW", - If((delay_min == 0) | - (delay_max == (taps - 1)) | - ((delay_max - delay_min) < taps//16), - NextValue(delay_min_found, 0), - NextValue(delay_max_found, 0), - NextState("WAIT_STABLE") - ).Else( - NextValue(delay, 0), - serdes.rx.delay_rst.eq(1), - NextState("CONFIGURE_SAMPLING_WINDOW") - ), - serdes.tx.comma.eq(1) - ) - fsm.act("CONFIGURE_SAMPLING_WINDOW", - If(delay == (delay_min + (delay_max - delay_min)[1:]), - NextState("READY") - ).Else( - NextValue(delay, delay + 1), - serdes.rx.delay_inc.eq(1) - ), - serdes.tx.comma.eq(1) - ) - fsm.act("READY", - self.ready.eq(1) - ) - fsm.act("ERROR", - self.error.eq(1) - ) - - -@ResetInserter() -class _SerdesSlaveInit(Module, AutoCSR): - def __init__(self, serdes, taps, timeout): - self.ready = Signal() - self.error = Signal() - - # # # - - self.delay = delay = Signal(max=taps) - self.delay_min = delay_min = Signal(max=taps) - self.delay_min_found = delay_min_found = Signal() - self.delay_max = delay_max = Signal(max=taps) - self.delay_max_found = delay_max_found = Signal() - self.bitslip = bitslip = Signal(max=40) - - self.submodules.timer = timer = WaitTimer(timeout) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - # reset - fsm.act("IDLE", - NextValue(delay, 0), - NextValue(delay_min, 0), - NextValue(delay_min_found, 0), - NextValue(delay_max, 0), - NextValue(delay_max_found, 0), - serdes.rx.delay_rst.eq(1), - NextValue(bitslip, 0), - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("WAIT_STABLE"), - ), - serdes.tx.idle.eq(1) - ) - fsm.act("WAIT_STABLE", - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextState("CHECK_PATTERN") - ), - serdes.tx.idle.eq(1) - ) - fsm.act("CHECK_PATTERN", - If(~delay_min_found, - If(serdes.rx.comma, - timer.wait.eq(1), - If(timer.done, - timer.wait.eq(0), - NextValue(delay_min, delay), - NextValue(delay_min_found, 1) - ) - ).Else( - NextState("INC_DELAY_BITSLIP") - ), - ).Else( - If(~serdes.rx.comma, - NextValue(delay_max, delay), - NextValue(delay_max_found, 1), - NextState("CHECK_SAMPLING_WINDOW") - ).Else( - NextState("INC_DELAY_BITSLIP") - ) - ), - serdes.tx.idle.eq(1) - ) - self.comb += serdes.rx.bitslip_value.eq(bitslip) - fsm.act("INC_DELAY_BITSLIP", - NextState("WAIT_STABLE"), - If(delay == (taps - 1), - If(bitslip == (40 - 1), - NextState("ERROR") - ).Else( - NextValue(delay_min_found, 0), - NextValue(delay_min, 0), - NextValue(delay_max_found, 0), - NextValue(delay_max, 0), - NextValue(bitslip, bitslip + 1) - ), - NextValue(delay, 0), - serdes.rx.delay_rst.eq(1) - ).Else( - NextValue(delay, delay + 1), - serdes.rx.delay_inc.eq(1) - ), - serdes.tx.idle.eq(1) - ) - fsm.act("CHECK_SAMPLING_WINDOW", - If((delay_min == 0) | - (delay_max == (taps - 1)) | - ((delay_max - delay_min) < taps//16), - NextValue(delay_min_found, 0), - NextValue(delay_max_found, 0), - NextState("WAIT_STABLE") - ).Else( - NextValue(delay, 0), - serdes.rx.delay_rst.eq(1), - NextState("CONFIGURE_SAMPLING_WINDOW") - ), - serdes.tx.idle.eq(1) - ) - fsm.act("CONFIGURE_SAMPLING_WINDOW", - If(delay == (delay_min + (delay_max - delay_min)[1:]), - NextState("SEND_PATTERN") - ).Else( - NextValue(delay, delay + 1), - serdes.rx.delay_inc.eq(1), - ), - serdes.tx.idle.eq(1) - ) - fsm.act("SEND_PATTERN", - timer.wait.eq(1), - If(timer.done, - If(~serdes.rx.comma, - NextState("READY") - ) - ), - serdes.tx.comma.eq(1) - ) - fsm.act("READY", - self.ready.eq(1) - ) - fsm.act("ERROR", - self.error.eq(1) - ) - - -class _SerdesControl(Module, AutoCSR): - def __init__(self, serdes, init, mode="master"): - if mode == "master": - self.reset = CSR() - self.ready = CSRStatus() - self.error = CSRStatus() - - self.delay = CSRStatus(9) - self.delay_min_found = CSRStatus() - self.delay_min = CSRStatus(9) - self.delay_max_found = CSRStatus() - self.delay_max = CSRStatus(9) - self.bitslip = CSRStatus(6) - - self.prbs_error = Signal() - self.prbs_start = CSR() - self.prbs_cycles = CSRStorage(32) - self.prbs_errors = CSRStatus(32) - - # # # - - if mode == "master": - # In Master mode, reset is coming from CSR, - # it resets the Master that will also reset - # the Slave by putting the link in idle. - self.sync += init.reset.eq(self.reset.re) - else: - # In Slave mode, reset is coming from link, - # Master reset the Slave by putting the link - # in idle. - self.sync += [ - init.reset.eq(serdes.rx.idle), - serdes.reset.eq(serdes.rx.idle) - ] - self.comb += [ - self.ready.status.eq(init.ready), - self.error.status.eq(init.error), - self.delay.status.eq(init.delay), - self.delay_min_found.status.eq(init.delay_min_found), - self.delay_min.status.eq(init.delay_min), - self.delay_max_found.status.eq(init.delay_max_found), - self.delay_max.status.eq(init.delay_max), - self.bitslip.status.eq(init.bitslip) - ] - - # prbs - prbs_cycles = Signal(32) - prbs_errors = self.prbs_errors.status - prbs_fsm = FSM(reset_state="IDLE") - self.submodules += prbs_fsm - prbs_fsm.act("IDLE", - NextValue(prbs_cycles, 0), - If(self.prbs_start.re, - NextValue(prbs_errors, 0), - NextState("CHECK") - ) - ) - prbs_fsm.act("CHECK", - NextValue(prbs_cycles, prbs_cycles + 1), - If(self.prbs_error, - NextValue(prbs_errors, prbs_errors + 1), - ), - If(prbs_cycles == self.prbs_cycles.storage, - NextState("IDLE") - ) - ) - - -class SERWBPHY(Module, AutoCSR): - def __init__(self, device, pads, mode="master", init_timeout=2**15): - self.sink = sink = stream.Endpoint([("data", 32)]) - self.source = source = stream.Endpoint([("data", 32)]) - assert mode in ["master", "slave"] - if device[:4] == "xcku": - taps = 512 - self.submodules.serdes = KUSerdes(pads, mode) - elif device[:4] == "xc7a": - taps = 32 - self.submodules.serdes = S7Serdes(pads, mode) - else: - raise NotImplementedError - if mode == "master": - self.submodules.init = _SerdesMasterInit(self.serdes, taps, init_timeout) - else: - self.submodules.init = _SerdesSlaveInit(self.serdes, taps, init_timeout) - self.submodules.control = _SerdesControl(self.serdes, self.init, mode) - - # tx/rx dataflow - self.comb += [ - If(self.init.ready, - If(sink.stb, - sink.connect(self.serdes.tx.sink), - ), - self.serdes.rx.source.connect(source) - ).Else( - self.serdes.rx.source.ack.eq(1) - ), - self.serdes.tx.sink.stb.eq(1) # always transmitting - ] - - # For PRBS test we are using the scrambler/descrambler as PRBS, - # sending 0 to the scrambler and checking that descrambler - # output is always 0. - self.comb += self.control.prbs_error.eq( - source.stb & - source.ack & - (source.data != 0)) diff --git a/artiq/gateware/serwb/s7serdes.py b/artiq/gateware/serwb/s7serdes.py deleted file mode 100644 index 9daee338a..000000000 --- a/artiq/gateware/serwb/s7serdes.py +++ /dev/null @@ -1,160 +0,0 @@ -from migen import * -from migen.genlib.io import * -from migen.genlib.misc import BitSlip, WaitTimer - -from misoc.interconnect import stream -from misoc.cores.code_8b10b import Encoder, Decoder - -from artiq.gateware.serwb.datapath import TXDatapath, RXDatapath - - -class _S7SerdesClocking(Module): - def __init__(self, pads, mode="master"): - self.refclk = Signal() - - # # # - - # In Master mode, generate the linerate/10 clock. Slave will re-multiply it. - if mode == "master": - converter = stream.Converter(40, 8) - self.submodules += converter - self.comb += [ - converter.sink.stb.eq(1), - converter.source.ack.eq(1), - converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), - ] - self.specials += [ - Instance("OSERDESE2", - p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", - p_SERDES_MODE="MASTER", - - o_OQ=self.refclk, - i_OCE=1, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D1=converter.source.data[0], i_D2=converter.source.data[1], - i_D3=converter.source.data[2], i_D4=converter.source.data[3], - i_D5=converter.source.data[4], i_D6=converter.source.data[5], - i_D7=converter.source.data[6], i_D8=converter.source.data[7] - ), - DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) - ] - - # In Slave mode, multiply the clock provided by Master with a PLL/MMCM - elif mode == "slave": - self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk) - - -class _S7SerdesTX(Module): - def __init__(self, pads, mode="master"): - # Control - self.idle = idle = Signal() - self.comma = comma = Signal() - - # Datapath - self.sink = sink = stream.Endpoint([("data", 32)]) - - # # # - - # Datapath - self.submodules.datapath = datapath = TXDatapath(8) - self.comb += [ - sink.connect(datapath.sink), - datapath.source.ack.eq(1), - datapath.idle.eq(idle), - datapath.comma.eq(comma) - ] - - # Output Data(DDR with sys4x) - data = Signal() - self.specials += [ - Instance("OSERDESE2", - p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, - p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", - p_SERDES_MODE="MASTER", - - o_OQ=data, - i_OCE=1, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), - i_D1=datapath.source.data[0], i_D2=datapath.source.data[1], - i_D3=datapath.source.data[2], i_D4=datapath.source.data[3], - i_D5=datapath.source.data[4], i_D6=datapath.source.data[5], - i_D7=datapath.source.data[6], i_D8=datapath.source.data[7] - ), - DifferentialOutput(data, pads.tx_p, pads.tx_n) - ] - - -class _S7SerdesRX(Module): - def __init__(self, pads, mode="master"): - # Control - self.delay_rst = Signal() - self.delay_inc = Signal() - self.bitslip_value = bitslip_value = Signal(6) - - # Status - self.idle = idle = Signal() - self.comma = comma = Signal() - - # Datapath - self.source = source = stream.Endpoint([("data", 32)]) - - # # # - - # Data input (DDR with sys4x) - data_nodelay = Signal() - data_delayed = Signal() - data_deserialized = Signal(8) - self.specials += [ - DifferentialInput(pads.rx_p, pads.rx_n, data_nodelay), - Instance("IDELAYE2", - p_DELAY_SRC="IDATAIN", p_SIGNAL_PATTERN="DATA", - p_CINVCTRL_SEL="FALSE", p_HIGH_PERFORMANCE_MODE="TRUE", - p_REFCLK_FREQUENCY=200.0, p_PIPE_SEL="FALSE", - p_IDELAY_TYPE="VARIABLE", p_IDELAY_VALUE=0, - - i_C=ClockSignal(), - i_LD=self.delay_rst, - i_CE=self.delay_inc, - i_LDPIPEEN=0, i_INC=1, - - i_IDATAIN=data_nodelay, o_DATAOUT=data_delayed - ), - Instance("ISERDESE2", - p_DATA_WIDTH=8, p_DATA_RATE="DDR", - p_SERDES_MODE="MASTER", p_INTERFACE_TYPE="NETWORKING", - p_NUM_CE=1, p_IOBDELAY="IFD", - - i_DDLY=data_delayed, - i_CE1=1, - i_RST=ResetSignal("sys"), - i_CLK=ClockSignal("sys4x"), i_CLKB=~ClockSignal("sys4x"), - i_CLKDIV=ClockSignal("sys"), - i_BITSLIP=0, - o_Q8=data_deserialized[0], o_Q7=data_deserialized[1], - o_Q6=data_deserialized[2], o_Q5=data_deserialized[3], - o_Q4=data_deserialized[4], o_Q3=data_deserialized[5], - o_Q2=data_deserialized[6], o_Q1=data_deserialized[7] - ) - ] - - # Datapath - self.submodules.datapath = datapath = RXDatapath(8) - self.comb += [ - datapath.sink.stb.eq(1), - datapath.sink.data.eq(data_deserialized), - datapath.bitslip_value.eq(bitslip_value), - datapath.source.connect(source), - idle.eq(datapath.idle), - comma.eq(datapath.comma) - ] - - -@ResetInserter() -class S7Serdes(Module): - def __init__(self, pads, mode="master"): - self.submodules.clocking = _S7SerdesClocking(pads, mode) - self.submodules.tx = _S7SerdesTX(pads, mode) - self.submodules.rx = _S7SerdesRX(pads, mode) diff --git a/artiq/gateware/serwb/scrambler.py b/artiq/gateware/serwb/scrambler.py deleted file mode 100644 index dc367fb6c..000000000 --- a/artiq/gateware/serwb/scrambler.py +++ /dev/null @@ -1,89 +0,0 @@ -from functools import reduce -from operator import xor - -from migen import * - -from misoc.interconnect import stream - - -def K(x, y): - return (y << 5) | x - - -@ResetInserter() -@CEInserter() -class _Scrambler(Module): - def __init__(self, n_io, n_state=23, taps=[17, 22]): - self.i = Signal(n_io) - self.o = Signal(n_io) - - # # # - - state = Signal(n_state, reset=1) - curval = [state[i] for i in range(n_state)] - for i in reversed(range(n_io)): - flip = reduce(xor, [curval[tap] for tap in taps]) - self.comb += self.o[i].eq(flip ^ self.i[i]) - curval.insert(0, flip) - curval.pop() - - self.sync += state.eq(Cat(*curval[:n_state])) - - -class Scrambler(Module): - def __init__(self, sync_interval=2**10): - self.sink = sink = stream.Endpoint([("data", 32)]) - self.source = source = stream.Endpoint([("d", 32), ("k", 4)]) - - # # # - - # Scrambler - self.submodules.scrambler = scrambler = _Scrambler(32) - - # Insert K29.7 SYNC character every "sync_interval" cycles - count = Signal(max=sync_interval) - self.sync += If(source.ack, count.eq(count + 1)) - self.comb += [ - source.stb.eq(1), - If(count == 0, - scrambler.reset.eq(1), - source.k.eq(0b1), - source.d.eq(K(29, 7)), - ).Else( - If(sink.stb, scrambler.i.eq(sink.data)), - source.k.eq(0), - source.d.eq(scrambler.o), - If(source.ack, - sink.ack.eq(1), - scrambler.ce.eq(1) - ) - ) - ] - - -class Descrambler(Module): - def __init__(self): - self.sink = sink = stream.Endpoint([("d", 32), ("k", 4)]) - self.source = source = stream.Endpoint([("data", 32)]) - - # # # - - # Descrambler - self.submodules.descrambler = descrambler = _Scrambler(32) - self.comb += descrambler.i.eq(sink.d) - - # Detect K29.7 SYNC character and synchronize Descrambler - self.comb += \ - If(sink.stb, - If((sink.k == 0b1) & (sink.d == K(29,7)), - sink.ack.eq(1), - descrambler.reset.eq(1) - ).Else( - source.stb.eq(1), - source.data.eq(descrambler.o), - If(source.ack, - sink.ack.eq(1), - descrambler.ce.eq(1) - ) - ) - ) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index ca5ff169c..78809671b 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -14,7 +14,6 @@ from misoc.targets.sayma_amc import * from artiq.gateware.amp import AMPSoC from artiq.gateware import eem from artiq.gateware import fmcdio_vhdci_eem -from artiq.gateware import serwb, remote_csr from artiq.gateware import rtio from artiq.gateware import jesd204_tools from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_ultrascale, sawg @@ -216,10 +215,19 @@ class AD9154NoSAWG(Module, AutoCSR): ] -class RTMSerWb: - def __init__(self): +class Satellite(SatelliteBase): + """ + DRTIO satellite with local DAC/SAWG channels. + """ + def __init__(self, with_sawg, **kwargs): + SatelliteBase.__init__(self, 150e6, + identifier_suffix=".without-sawg" if not with_sawg else "", + **kwargs) + platform = self.platform + self.submodules += RTMUARTForward(platform) + # RTM bitstream upload slave_fpga_cfg = self.platform.request("rtm_fpga_cfg") self.submodules.slave_fpga_cfg = gpio.GPIOTristate([ @@ -232,36 +240,6 @@ class RTMSerWb: self.csr_devices.append("slave_fpga_cfg") self.config["SLAVE_FPGA_GATEWARE"] = 0x200000 - # AMC/RTM serwb - serwb_pads = platform.request("amc_rtm_serwb") - serwb_phy_amc = serwb.genphy.SERWBPHY(platform.device, serwb_pads, mode="master") - self.submodules.serwb_phy_amc = serwb_phy_amc - self.csr_devices.append("serwb_phy_amc") - - serwb_core = serwb.core.SERWBCore(serwb_phy_amc, int(self.clk_freq), mode="slave") - self.submodules += serwb_core - self.add_wb_slave(self.mem_map["serwb"], 8192, serwb_core.etherbone.wishbone.bus) - - -class Satellite(SatelliteBase, RTMSerWb): - """ - DRTIO satellite with local DAC/SAWG channels. - """ - mem_map = { - "serwb": 0x13000000, - } - mem_map.update(SatelliteBase.mem_map) - - def __init__(self, with_sawg, **kwargs): - SatelliteBase.__init__(self, 150e6, - identifier_suffix=".without-sawg" if not with_sawg else "", - **kwargs) - RTMSerWb.__init__(self) - - platform = self.platform - - self.submodules += RTMUARTForward(platform) - rtio_channels = [] for i in range(4): phy = ttl_simple.Output(platform.request("user_led", i)) @@ -509,16 +487,6 @@ def main(): variant = args.variant.lower() if variant == "satellite": soc = Satellite(with_sawg=not args.without_sawg, **soc_sayma_amc_argdict(args)) - remote_csr_regions = remote_csr.get_remote_csr_regions( - soc.mem_map["serwb"] | soc.shadow_base, - args.rtm_csr_csv) - for name, origin, busword, csrs in remote_csr_regions: - soc.add_csr_region(name, origin, busword, csrs) - # Configuration for RTM peripherals. Keep in sync with sayma_rtm.py! - soc.config["HAS_HMC830_7043"] = None - soc.config["CONVERTER_SPI_HMC830_CS"] = 0 - soc.config["CONVERTER_SPI_HMC7043_CS"] = 1 - soc.config["CONVERTER_SPI_FIRST_AD9154_CS"] = 2 elif variant == "simplesatellite": soc = SimpleSatellite(**soc_sayma_amc_argdict(args)) elif variant == "master": diff --git a/artiq/gateware/test/serwb/__init__.py b/artiq/gateware/test/serwb/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/artiq/gateware/test/serwb/test_serwb_core.py b/artiq/gateware/test/serwb/test_serwb_core.py deleted file mode 100644 index 4a3fa7898..000000000 --- a/artiq/gateware/test/serwb/test_serwb_core.py +++ /dev/null @@ -1,158 +0,0 @@ -import unittest -import random - -from migen import * - -from artiq.gateware.serwb import scrambler -from artiq.gateware.serwb import core - -from misoc.interconnect import stream -from misoc.interconnect.wishbone import SRAM - - -class FakeInit(Module): - def __init__(self): - self.ready = Signal(reset=1) - - -class FakeSerdes(Module): - def __init__(self): - self.tx_ce = Signal() - self.tx_k = Signal(4) - self.tx_d = Signal(32) - self.rx_ce = Signal() - self.rx_k = Signal(4) - self.rx_d = Signal(32) - - # # # - - data_ce = Signal(5, reset=0b00001) - self.sync += data_ce.eq(Cat(data_ce[1:], data_ce[0])) - - self.comb += [ - self.tx_ce.eq(data_ce[0]), - self.rx_ce.eq(data_ce[0]) - ] - -class FakePHY(Module): - def __init__(self): - self.sink = sink = stream.Endpoint([("data", 32)]) - self.source = source = stream.Endpoint([("data", 32)]) - - # # # - - self.submodules.init = FakeInit() - self.submodules.serdes = FakeSerdes() - - # tx dataflow - self.comb += \ - If(self.init.ready, - sink.ack.eq(self.serdes.tx_ce), - If(sink.stb, - self.serdes.tx_d.eq(sink.data) - ) - ) - - # rx dataflow - self.comb += \ - If(self.init.ready, - source.stb.eq(self.serdes.rx_ce), - source.data.eq(self.serdes.rx_d) - ) - - -class DUTScrambler(Module): - def __init__(self): - self.submodules.scrambler = scrambler.Scrambler(sync_interval=16) - self.submodules.descrambler = scrambler.Descrambler() - self.comb += self.scrambler.source.connect(self.descrambler.sink) - - -class DUTCore(Module): - def __init__(self): - # wishbone slave - phy_slave = FakePHY() - serwb_slave = core.SERWBCore(phy_slave, int(1e6), "slave") - self.submodules += phy_slave, serwb_slave - - # wishbone master - phy_master = FakePHY() - serwb_master = core.SERWBCore(phy_master, int(1e6), "master") - self.submodules += phy_master, serwb_master - - # connect phy - self.comb += [ - phy_master.serdes.rx_ce.eq(phy_slave.serdes.tx_ce), - phy_master.serdes.rx_k.eq(phy_slave.serdes.tx_k), - phy_master.serdes.rx_d.eq(phy_slave.serdes.tx_d), - - phy_slave.serdes.rx_ce.eq(phy_master.serdes.tx_ce), - phy_slave.serdes.rx_k.eq(phy_master.serdes.tx_k), - phy_slave.serdes.rx_d.eq(phy_master.serdes.tx_d) - ] - - # add wishbone sram to wishbone master - sram = SRAM(1024, bus=serwb_master.etherbone.wishbone.bus) - self.submodules += sram - - # expose wishbone slave - self.wishbone = serwb_slave.etherbone.wishbone.bus - - -class TestSERWBCore(unittest.TestCase): - def test_scrambler(self): - def generator(dut, rand_level=50): - # prepare test - prng = random.Random(42) - i = 0 - last_data = -1 - # test loop - while i != 256: - # stim - yield dut.scrambler.sink.stb.eq(1) - if (yield dut.scrambler.sink.stb) & (yield dut.scrambler.sink.ack): - i += 1 - yield dut.scrambler.sink.data.eq(i) - - # check - yield dut.descrambler.source.ack.eq(prng.randrange(100) > rand_level) - if (yield dut.descrambler.source.stb) & (yield dut.descrambler.source.ack): - current_data = (yield dut.descrambler.source.data) - if (current_data != (last_data + 1)): - dut.errors += 1 - last_data = current_data - - # cycle - yield - - dut = DUTScrambler() - dut.errors = 0 - run_simulation(dut, generator(dut)) - self.assertEqual(dut.errors, 0) - - def test_serwb(self): - def generator(dut): - # prepare test - prng = random.Random(42) - data_base = 0x100 - data_length = 4 - datas_w = [prng.randrange(2**32) for i in range(data_length)] - datas_r = [] - - # write - for i in range(data_length): - yield from dut.wishbone.write(data_base + i, datas_w[i]) - - # read - for i in range(data_length): - datas_r.append((yield from dut.wishbone.read(data_base + i))) - - # check - for i in range(data_length): - if datas_r[i] != datas_w[i]: - dut.errors += 1 - - dut = DUTCore() - dut.errors = 0 - run_simulation(dut, generator(dut)) - self.assertEqual(dut.errors, 0) diff --git a/artiq/gateware/test/serwb/test_serwb_init.py b/artiq/gateware/test/serwb/test_serwb_init.py deleted file mode 100644 index c54e9cae9..000000000 --- a/artiq/gateware/test/serwb/test_serwb_init.py +++ /dev/null @@ -1,144 +0,0 @@ -import unittest - -from migen import * - -from artiq.gateware.serwb import packet -from artiq.gateware.serwb.phy import _SerdesMasterInit, _SerdesSlaveInit - - -class SerdesModel(Module): - def __init__(self, taps, mode="slave"): - self.tx = Module() - self.rx = Module() - - self.tx.idle = Signal() - self.tx.comma = Signal() - self.rx.idle = Signal() - self.rx.comma = Signal() - - self.rx.bitslip_value = Signal(6) - self.rx.delay_rst = Signal() - self.rx.delay_inc = Signal() - - self.valid_bitslip = Signal(6) - self.valid_delays = Signal(taps) - - # # # - - delay = Signal(max=taps) - bitslip = Signal(6) - - valid_delays = Array(Signal() for i in range(taps)) - for i in range(taps): - self.comb += valid_delays[taps-1-i].eq(self.valid_delays[i]) - - self.sync += [ - bitslip.eq(self.rx.bitslip_value), - If(self.rx.delay_rst, - delay.eq(0) - ).Elif(self.rx.delay_inc, - delay.eq(delay + 1) - ) - ] - - if mode == "master": - self.submodules.fsm = fsm = ResetInserter()(FSM(reset_state="IDLE")) - self.comb += self.fsm.reset.eq(self.tx.idle) - fsm.act("IDLE", - If(self.tx.comma, - NextState("SEND_COMMA") - ), - self.rx.idle.eq(1) - ) - fsm.act("SEND_COMMA", - If(valid_delays[delay] & - (bitslip == self.valid_bitslip), - self.rx.comma.eq(1) - ), - If(~self.tx.comma, - NextState("READY") - ) - ) - fsm.act("READY") - elif mode == "slave": - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - self.rx.idle.eq(1), - NextState("SEND_COMMA") - ) - fsm.act("SEND_COMMA", - If(valid_delays[delay] & - (bitslip == self.valid_bitslip), - self.rx.comma.eq(1) - ), - If(~self.tx.idle, - NextState("READY") - ) - ) - fsm.act("READY") - - -class DUTMaster(Module): - def __init__(self, taps=32): - self.submodules.serdes = SerdesModel(taps, mode="master") - self.submodules.init = _SerdesMasterInit(self.serdes, taps, timeout=1) - - -class DUTSlave(Module): - def __init__(self, taps=32): - self.submodules.serdes = SerdesModel(taps, mode="slave") - self.submodules.init = _SerdesSlaveInit(self.serdes, taps, timeout=1) - - -def generator(test, dut, valid_bitslip, valid_delays, check_success): - yield dut.serdes.valid_bitslip.eq(valid_bitslip) - yield dut.serdes.valid_delays.eq(valid_delays) - while not ((yield dut.init.ready) or - (yield dut.init.error)): - yield - if check_success: - ready = (yield dut.init.ready) - error = (yield dut.init.error) - delay_min = (yield dut.init.delay_min) - delay_max = (yield dut.init.delay_max) - delay = (yield dut.init.delay) - bitslip = (yield dut.init.bitslip) - test.assertEqual(ready, 1) - test.assertEqual(error, 0) - test.assertEqual(delay_min, 4) - test.assertEqual(delay_max, 9) - test.assertEqual(delay, 6) - test.assertEqual(bitslip, valid_bitslip) - else: - ready = (yield dut.init.ready) - error = (yield dut.init.error) - test.assertEqual(ready, 0) - test.assertEqual(error, 1) - - -class TestSERWBInit(unittest.TestCase): - def test_master_init_success(self): - dut = DUTMaster() - valid_bitslip = 2 - valid_delays = 0b10001111100000111110000011111000 - run_simulation(dut, generator(self, dut, valid_bitslip, valid_delays, True)) - - def test_master_init_failure(self): - # too small window - dut = DUTMaster() - valid_bitslip = 2 - valid_delays = 0b00000000000000010000000000000000 - run_simulation(dut, generator(self, dut, valid_bitslip, valid_delays, False)) - - def test_slave_init_success(self): - dut = DUTSlave() - valid_bitslip = 2 - valid_delays = 0b10001111100000111110000011111000 - run_simulation(dut, generator(self, dut, valid_bitslip, valid_delays, True)) - - def test_slave_init_failure(self): - # too small window - dut = DUTSlave() - valid_bitslip = 2 - valid_delays = 0b00000000000000010000000000000000 - run_simulation(dut, generator(self, dut, valid_bitslip, valid_delays, False)) From e6ff44301b97ab3d2130b2854589698d3ff42fda Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Oct 2019 18:11:43 +0800 Subject: [PATCH 1919/2457] sayma_amc: cleanup (v2.0 only) --- artiq/gateware/targets/sayma_amc.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 78809671b..fa7360a70 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -63,9 +63,10 @@ class SatelliteBase(BaseSoC): # Use SFP0 to connect to master (Kasli) self.comb += platform.request("sfp_tx_disable", 0).eq(0) - drtio_data_pads = [platform.request("sfp", 0)] - if self.hw_rev == "v2.0": - drtio_data_pads.append(platform.request("rtm_amc_link")) + drtio_data_pads = [ + platform.request("sfp", 0), + platform.request("rtm_amc_link") + ] self.submodules.drtio_transceiver = gth_ultrascale.GTH( clock_pads=platform.request("cdr_clk_clean"), data_pads=drtio_data_pads, @@ -119,8 +120,7 @@ class SatelliteBase(BaseSoC): self.add_csr_group("drtiorep", drtiorep_csr_group) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - if self.hw_rev == "v2.0": - self.comb += platform.request("filtered_clk_sel").eq(1) + self.comb += platform.request("filtered_clk_sel").eq(1) self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("si5324_clkin"), rx_synchronizer=self.rx_synchronizer, From 5ad65b9d30112d2e8373c362ad0b055ebcb51b3d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Oct 2019 18:13:27 +0800 Subject: [PATCH 1920/2457] hmc830_7043: remove clock_mux --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 28 -------------------- 1 file changed, 28 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index a507f6591..04fd4d6b4 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -1,30 +1,3 @@ -#[cfg(hw_rev = "v1.0")] -mod clock_mux { - use board_misoc::csr; - - const CLK_SRC_EXT_SEL : u8 = 1 << 0; - const REF_CLK_SRC_SEL : u8 = 1 << 1; - const DAC_CLK_SRC_SEL : u8 = 1 << 2; - const REF_LO_CLK_SEL : u8 = 1 << 3; - - pub fn init() { - unsafe { - csr::clock_mux::out_write( - 1*CLK_SRC_EXT_SEL | // 1= ext clk from sma, 0= RF backplane (IC46) to IC45 - 1*REF_CLK_SRC_SEL | // 1= low-noise clock, 0= Si5324 output (IC45) to HMC830 - 1*DAC_CLK_SRC_SEL | // 1= HMC830 output, 1= clock mezzanine (IC54) to HMC7043 and J58/J59 - 0*REF_LO_CLK_SEL); // 1= clock mezzanine, 0= HMC830 input (IC52) to AFEs and J56/J57 - } - } -} - -#[cfg(hw_rev = "v2.0")] -mod clock_mux { - pub fn init() { - // TODO - } -} - mod hmc830 { use board_misoc::{csr, clock}; @@ -426,7 +399,6 @@ pub fn init() -> Result<(), &'static str> { #[cfg(all(hmc830_ref = "150", rtio_frequency = "150.0"))] const DIV: (u32, u32, u32, u32) = (2, 32, 0, 1); // 150MHz -> 2.4GHz - clock_mux::init(); /* do not use other SPI devices before HMC830 SPI mode selection */ hmc830::select_spi_mode(); hmc830::detect()?; From ad63908aff8586860cce15681030a8e5ed88b366 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Oct 2019 18:13:59 +0800 Subject: [PATCH 1921/2457] hmc830_7043: enable_fpga_ibuf -> unmute --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 04fd4d6b4..2dbee9bef 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -361,15 +361,14 @@ pub mod hmc7043 { Ok(()) } - pub fn enable_fpga_ibuf() { + pub fn unmute() { /* * Never missing an opportunity to be awful, the HMC7043 produces broadband noise - * prior to intialization, which can upset the FPGA. - * One mitigation technique is to disable the input buffer until the HMC7043 is - * slightly better behaved. + * prior to intialization, which can upset the AMC FPGA. + * External circuitry mutes it. */ unsafe { - csr::ad9154_crg::ibuf_disable_write(0); + csr::hmc7043_out_en::out_write(1); } } @@ -416,7 +415,7 @@ pub fn init() -> Result<(), &'static str> { hmc7043::init(); hmc7043::test_gpo()?; hmc7043::check_phased()?; - hmc7043::enable_fpga_ibuf(); + hmc7043::unmute(); Ok(()) } From 1c6c22fde9523611870b855739529ef767e5ee59 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Oct 2019 18:15:37 +0800 Subject: [PATCH 1922/2457] sayma_amc: HMC830_REF moved to RTM side --- artiq/gateware/targets/sayma_amc.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index fa7360a70..5d70ce2d2 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -256,7 +256,6 @@ class Satellite(SatelliteBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - self.config["HMC830_REF"] = "150" self.submodules.ad9154_crg = jesd204_tools.UltrascaleCRG( platform, use_rtio_clock=True) if with_sawg: From fdba0bfbbc1c5155bc7cb0ee83cd7d0500acea5f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Oct 2019 19:22:46 +0800 Subject: [PATCH 1923/2457] satman: move now-unrelated hmc830_7043 init away from DRTIO transceiver init --- artiq/firmware/satman/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index b71386d70..b0c41543f 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -414,15 +414,15 @@ pub extern fn main() -> i32 { i2c::init(); si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324"); - #[cfg(has_hmc830_7043)] - /* must be the first SPI init because of HMC830 SPI mode selection */ - hmc830_7043::init().expect("cannot initialize HMC830/7043"); unsafe { csr::drtio_transceiver::stable_clkin_write(1); } clock::spin_us(1500); // wait for CPLL/QPLL lock init_rtio_crg(); + #[cfg(has_hmc830_7043)] + /* must be the first SPI init because of HMC830 SPI mode selection */ + hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); From c4c884b8ce2257adfe29ee9fcb2f9c23b8c85a94 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Oct 2019 20:06:54 +0800 Subject: [PATCH 1924/2457] ad9154: simplify, focus on AD9154 config and do not include JESD --- artiq/firmware/libboard_artiq/ad9154.rs | 200 ++---------------------- 1 file changed, 10 insertions(+), 190 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index a671c32a1..86de3dbee 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -33,42 +33,6 @@ fn read(addr: u16) -> u8 { } } -pub fn jesd_reset(reset: bool) { - unsafe { - csr::ad9154_crg::jreset_write(if reset { 1 } else { 0 }); - } -} - -fn jesd_enable(dacno: u8, en: bool) { - unsafe { - (csr::AD9154[dacno as usize].jesd_control_enable_write)(if en {1} else {0}) - } -} - -fn jesd_ready(dacno: u8) -> bool { - unsafe { - (csr::AD9154[dacno as usize].jesd_control_ready_read)() != 0 - } -} - -fn jesd_prbs(dacno: u8, en: bool) { - unsafe { - (csr::AD9154[dacno as usize].jesd_control_prbs_config_write)(if en {0b01} else {0b00}) - } -} - -fn jesd_stpl(dacno: u8, en: bool) { - unsafe { - (csr::AD9154[dacno as usize].jesd_control_stpl_enable_write)(if en {1} else {0}) - } -} - -fn jesd_jsync(dacno: u8) -> bool { - unsafe { - (csr::AD9154[dacno as usize].jesd_control_jsync_read)() != 0 - } -} - // ad9154 mode 1 // linerate 5Gbps or 6Gbps // deviceclock_fpga 125MHz or 150MHz @@ -130,7 +94,7 @@ const JESD_SETTINGS: JESDSettings = JESDSettings { jesdv: 1 }; -fn dac_reset(dacno: u8) { +pub fn reset_and_detect(dacno: u8) -> Result<(), &'static str> { spi_setup(dacno); // reset write(ad9154_reg::SPI_INTFCONFA, @@ -145,17 +109,15 @@ fn dac_reset(dacno: u8) { 0*ad9154_reg::ADDRINC_M | 0*ad9154_reg::ADDRINC | 1*ad9154_reg::SDOACTIVE_M | 1*ad9154_reg::SDOACTIVE); clock::spin_us(100); -} - -fn dac_detect(dacno: u8) -> Result<(), &'static str> { - spi_setup(dacno); if (read(ad9154_reg::PRODIDH) as u16) << 8 | (read(ad9154_reg::PRODIDL) as u16) != 0x9154 { return Err("invalid AD9154 identification"); + } else { + info!("AD9154-{} found", dacno); } Ok(()) } -fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { +pub fn setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { spi_setup(dacno); info!("AD9154-{} initializing...", dacno); write(ad9154_reg::PWRCNTRL0, @@ -370,7 +332,7 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { write(ad9154_reg::LMFC_VAR_1, 0x0a); write(ad9154_reg::SYNC_ERRWINDOW, 0); // +- 1/2 DAC clock // datasheet seems to say ENABLE and ARM should be separate steps, - // so enable now so it can be armed in dac_sync(). + // so enable now so it can be armed in sync(). write(ad9154_reg::SYNC_CONTROL, 0x1*ad9154_reg::SYNCMODE | 1*ad9154_reg::SYNCENABLE | 0*ad9154_reg::SYNCARM | 0*ad9154_reg::SYNCCLRSTKY); @@ -392,7 +354,7 @@ fn dac_setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { } #[allow(dead_code)] -fn dac_status(dacno: u8) { +fn status(dacno: u8) { spi_setup(dacno); info!("SERDES_PLL_LOCK: {}", (read(ad9154_reg::PLL_STATUS) & ad9154_reg::SERDES_PLL_LOCK_RB)); @@ -445,61 +407,13 @@ fn dac_status(dacno: u8) { info!("NITDISPARITY: 0x{:02x}", read(ad9154_reg::NIT_W)); } -fn dac_monitor(dacno: u8) { - spi_setup(dacno); - write(ad9154_reg::IRQ_STATUS0, 0x00); - write(ad9154_reg::IRQ_STATUS1, 0x00); - write(ad9154_reg::IRQ_STATUS2, 0x00); - write(ad9154_reg::IRQ_STATUS3, 0x00); - - write(ad9154_reg::IRQEN_STATUSMODE0, - ad9154_reg::IRQEN_SMODE_LANEFIFOERR | - ad9154_reg::IRQEN_SMODE_SERPLLLOCK | - ad9154_reg::IRQEN_SMODE_SERPLLLOST | - ad9154_reg::IRQEN_SMODE_DACPLLLOCK | - ad9154_reg::IRQEN_SMODE_DACPLLLOST); - - write(ad9154_reg::IRQEN_STATUSMODE1, - ad9154_reg::IRQEN_SMODE_PRBS0 | - ad9154_reg::IRQEN_SMODE_PRBS1 | - ad9154_reg::IRQEN_SMODE_PRBS2 | - ad9154_reg::IRQEN_SMODE_PRBS3); - - write(ad9154_reg::IRQEN_STATUSMODE2, - ad9154_reg::IRQEN_SMODE_SYNC_TRIP0 | - ad9154_reg::IRQEN_SMODE_SYNC_WLIM0 | - ad9154_reg::IRQEN_SMODE_SYNC_ROTATE0 | - ad9154_reg::IRQEN_SMODE_SYNC_LOCK0 | - ad9154_reg::IRQEN_SMODE_NCO_ALIGN0 | - ad9154_reg::IRQEN_SMODE_BLNKDONE0 | - ad9154_reg::IRQEN_SMODE_PDPERR0); - - write(ad9154_reg::IRQEN_STATUSMODE3, - ad9154_reg::IRQEN_SMODE_SYNC_TRIP1 | - ad9154_reg::IRQEN_SMODE_SYNC_WLIM1 | - ad9154_reg::IRQEN_SMODE_SYNC_ROTATE1 | - ad9154_reg::IRQEN_SMODE_SYNC_LOCK1 | - ad9154_reg::IRQEN_SMODE_NCO_ALIGN1 | - ad9154_reg::IRQEN_SMODE_BLNKDONE1 | - ad9154_reg::IRQEN_SMODE_PDPERR1); - - write(ad9154_reg::IRQ_STATUS0, 0x00); - write(ad9154_reg::IRQ_STATUS1, 0x00); - write(ad9154_reg::IRQ_STATUS2, 0x00); - write(ad9154_reg::IRQ_STATUS3, 0x00); -} - -fn dac_prbs(dacno: u8) -> Result<(), &'static str> { +pub fn prbs(dacno: u8) -> Result<(), &'static str> { let mut prbs_errors: u32 = 0; spi_setup(dacno); /* follow phy prbs testing (p58 of ad9154 datasheet) */ info!("AD9154-{} running PRBS test...", dacno); - /* step 1: start sending prbs7 pattern from the transmitter */ - jesd_prbs(dacno, true); - clock::spin_us(500000); - /* step 2: select prbs mode */ write(ad9154_reg::PHY_PRBS_TEST_CTRL, 0b00*ad9154_reg::PHY_PRBS_PAT_SEL); @@ -547,8 +461,6 @@ fn dac_prbs(dacno: u8) -> Result<(), &'static str> { prbs_errors += lane_errors } - jesd_prbs(dacno, false); - if prbs_errors > 0 { return Err("PRBS failed") } @@ -556,7 +468,7 @@ fn dac_prbs(dacno: u8) -> Result<(), &'static str> { Ok(()) } -fn dac_stpl(dacno: u8, m: u8, s: u8) -> Result<(), &'static str> { +pub fn stpl(dacno: u8, m: u8, s: u8) -> Result<(), &'static str> { spi_setup(dacno); info!("AD9154-{} running STPL test...", dacno); @@ -565,7 +477,6 @@ fn dac_stpl(dacno: u8, m: u8, s: u8) -> Result<(), &'static str> { return ((seed + 1)*0x31415979 + 1) & 0xffff; } - jesd_stpl(dacno, true); for i in 0..m { let mut data: u32; let mut errors: u8 = 0; @@ -609,86 +520,12 @@ fn dac_stpl(dacno: u8, m: u8, s: u8) -> Result<(), &'static str> { return Err("STPL failed") } } - jesd_stpl(dacno, false); + info!(" ...passed"); Ok(()) } -fn dac_cfg(dacno: u8) -> Result<(), &'static str> { - #[cfg(rtio_frequency = "125.0")] - const LINERATE: u64 = 5_000_000_000; - #[cfg(rtio_frequency = "150.0")] - const LINERATE: u64 = 5_000_000_000; - - spi_setup(dacno); - jesd_enable(dacno, false); - jesd_prbs(dacno, false); - jesd_stpl(dacno, false); - clock::spin_us(10000); - jesd_enable(dacno, true); - dac_setup(dacno, LINERATE)?; - jesd_enable(dacno, false); - clock::spin_us(10000); - jesd_enable(dacno, true); - dac_monitor(dacno); - clock::spin_us(50000); - let t = clock::get_ms(); - while !jesd_ready(dacno) { - if clock::get_ms() > t + 200 { - return Err("JESD ready timeout"); - } - } - clock::spin_us(10000); - if read(ad9154_reg::CODEGRPSYNCFLG) != 0xff { - return Err("bad CODEGRPSYNCFLG") - } - if !jesd_jsync(dacno) { - return Err("bad SYNC") - } - if read(ad9154_reg::FRAMESYNCFLG) != 0xff { - return Err("bad FRAMESYNCFLG") - } - if read(ad9154_reg::GOODCHKSUMFLG) != 0xff { - return Err("bad GOODCHECKSUMFLG") - } - if read(ad9154_reg::INITLANESYNCFLG) != 0xff { - return Err("bad INITLANESYNCFLG") - } - Ok(()) -} - -fn dac_cfg_and_test(dacno: u8) -> Result<(), &'static str> { - dac_cfg(dacno)?; - dac_prbs(dacno)?; - dac_stpl(dacno, 4, 2)?; - dac_cfg(dacno)?; - Ok(()) -} - -/* - * work around for: - * https://github.com/m-labs/artiq/issues/727 - * https://github.com/m-labs/artiq/issues/1127 - */ -fn dac_cfg_and_test_retry(dacno: u8) -> Result<(), &'static str> { - let mut attempt = 0; - loop { - attempt += 1; - dac_reset(dacno); - let outcome = dac_cfg_and_test(dacno); - match outcome { - Ok(_) => return outcome, - Err(e) => { - warn!("AD9154-{} config attempt #{} failed ({})", dacno, attempt, e); - if attempt >= 10 { - return outcome; - } - } - } - } -} - -pub fn dac_sync(dacno: u8) -> Result { +pub fn sync(dacno: u8) -> Result { spi_setup(dacno); write(ad9154_reg::SYNC_CONTROL, @@ -709,20 +546,3 @@ pub fn dac_sync(dacno: u8) -> Result { let realign_occured = sync_status & ad9154_reg::SYNC_ROTATE != 0; Ok(realign_occured) } - -fn init_dac(dacno: u8) -> Result<(), &'static str> { - let dacno = dacno as u8; - dac_reset(dacno); - dac_detect(dacno)?; - dac_cfg_and_test_retry(dacno)?; - Ok(()) -} - -pub fn init() { - for dacno in 0..csr::AD9154.len() { - match init_dac(dacno as u8) { - Ok(_) => (), - Err(e) => error!("failed to initialize AD9154-{}: {}", dacno, e) - } - } -} From f62dc7e1d4aad251a2b5a17f878d9462273f1ae2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Oct 2019 20:15:09 +0800 Subject: [PATCH 1925/2457] sayma: refactor JESD DAC channel groups --- artiq/firmware/libboard_artiq/jdcg.rs | 37 +++++++++++++++++++++++++++ artiq/firmware/libboard_artiq/lib.rs | 6 +++-- artiq/gateware/targets/sayma_amc.py | 33 ++++++++++++------------ 3 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 artiq/firmware/libboard_artiq/jdcg.rs diff --git a/artiq/firmware/libboard_artiq/jdcg.rs b/artiq/firmware/libboard_artiq/jdcg.rs new file mode 100644 index 000000000..b93d28336 --- /dev/null +++ b/artiq/firmware/libboard_artiq/jdcg.rs @@ -0,0 +1,37 @@ +use board_misoc::csr; + +pub fn jesd_reset(reset: bool) { + unsafe { + csr::jesd_crg::jreset_write(if reset {1} else {0}); + } +} + +fn jesd_enable(dacno: u8, en: bool) { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_enable_write)(if en {1} else {0}) + } +} + +fn jesd_ready(dacno: u8) -> bool { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_ready_read)() != 0 + } +} + +fn jesd_prbs(dacno: u8, en: bool) { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_prbs_config_write)(if en {0b01} else {0b00}) + } +} + +fn jesd_stpl(dacno: u8, en: bool) { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_stpl_enable_write)(if en {1} else {0}) + } +} + +fn jesd_jsync(dacno: u8) -> bool { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_jsync_read)() != 0 + } +} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 241002879..24594414f 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -40,8 +40,10 @@ pub mod hmc830_7043; mod ad9154_reg; #[cfg(has_ad9154)] pub mod ad9154; -#[cfg(has_ad9154)] -pub mod jesd204sync; +/* TODO: #[cfg(has_jdcg)] +pub mod jesd204sync; */ +#[cfg(has_jdcg)] +pub mod jdcg; #[cfg(has_allaki_atts)] pub mod hmc542; diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 5d70ce2d2..be74a43f6 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -162,7 +162,8 @@ class SatelliteBase(BaseSoC): self.csr_devices.append("routing_table") -class AD9154(Module, AutoCSR): +# JESD204 DAC Channel Group +class JDCG(Module, AutoCSR): def __init__(self, platform, sys_crg, jesd_crg, dac): self.submodules.jesd = jesd204_tools.UltrascaleTX( platform, sys_crg, jesd_crg, dac) @@ -175,7 +176,7 @@ class AD9154(Module, AutoCSR): self.sync.jesd += conv.eq(Cat(ch.o)) -class AD9154NoSAWG(Module, AutoCSR): +class JDCGNoSAWG(Module, AutoCSR): def __init__(self, platform, sys_crg, jesd_crg, dac): self.submodules.jesd = jesd204_tools.UltrascaleTX( platform, sys_crg, jesd_crg, dac) @@ -256,23 +257,23 @@ class Satellite(SatelliteBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - self.submodules.ad9154_crg = jesd204_tools.UltrascaleCRG( + self.submodules.jesd_crg = jesd204_tools.UltrascaleCRG( platform, use_rtio_clock=True) if with_sawg: - cls = AD9154 + cls = JDCG else: - cls = AD9154NoSAWG - self.submodules.ad9154_0 = cls(platform, self.crg, self.ad9154_crg, 0) - self.submodules.ad9154_1 = cls(platform, self.crg, self.ad9154_crg, 1) - self.csr_devices.append("ad9154_crg") - self.csr_devices.append("ad9154_0") - self.csr_devices.append("ad9154_1") - self.config["HAS_AD9154"] = None - self.add_csr_group("ad9154", ["ad9154_0", "ad9154_1"]) + cls = JDCGNoSAWG + self.submodules.jdcg_0 = cls(platform, self.crg, self.jesd_crg, 0) + self.submodules.jdcg_1 = cls(platform, self.crg, self.jesd_crg, 1) + self.csr_devices.append("jesd_crg") + self.csr_devices.append("jdcg_0") + self.csr_devices.append("jdcg_1") + self.config["HAS_JDCG"] = None + self.add_csr_group("jdcg", ["jdcg_0", "jdcg_1"]) self.config["RTIO_FIRST_SAWG_CHANNEL"] = len(rtio_channels) rtio_channels.extend(rtio.Channel.from_phy(phy) - for sawg in self.ad9154_0.sawgs + - self.ad9154_1.sawgs + for sawg in self.jdcg_0.sawgs + + self.jdcg_1.sawgs for phy in sawg.phys) self.add_rtio(rtio_channels) @@ -280,8 +281,8 @@ class Satellite(SatelliteBase): self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( platform.request("dac_sysref"), self.rtio_tsc.coarse_ts) self.csr_devices.append("sysref_sampler") - self.ad9154_0.jesd.core.register_jref(self.sysref_sampler.jref) - self.ad9154_1.jesd.core.register_jref(self.sysref_sampler.jref) + self.jdcg_0.jesd.core.register_jref(self.sysref_sampler.jref) + self.jdcg_1.jesd.core.register_jref(self.sysref_sampler.jref) class SimpleSatellite(SatelliteBase): From f8e4cc37d0c570084b8396541a1655aa2c72c029 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Oct 2019 20:15:27 +0800 Subject: [PATCH 1926/2457] sayma_rtm: reset and detect DACs --- artiq/firmware/satman/main.rs | 20 +++++++++++++------- artiq/gateware/targets/sayma_rtm.py | 3 +++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index b0c41543f..e9cc3c1ed 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -423,6 +423,12 @@ pub extern fn main() -> i32 { #[cfg(has_hmc830_7043)] /* must be the first SPI init because of HMC830 SPI mode selection */ hmc830_7043::init().expect("cannot initialize HMC830/7043"); + #[cfg(has_ad9154)] + { + for dacno in 0..csr::CONFIG_AD9154_COUNT { + board_artiq::ad9154::reset_and_detect(dacno as u8).expect("AD9154 DAC not detected"); + } + } #[cfg(has_allaki_atts)] board_artiq::hmc542::program_all(8/*=4dB*/); @@ -451,7 +457,7 @@ pub extern fn main() -> i32 { si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); si5324::siphaser::calibrate_skew().expect("failed to calibrate skew"); - #[cfg(has_ad9154)] + #[cfg(has_jdcg)] { /* * One side of the JESD204 elastic buffer is clocked by the Si5324, the other @@ -466,8 +472,8 @@ pub extern fn main() -> i32 { * To handle those cases, we simply keep the JESD204 core in reset unless the * Si5324 is locked to the recovered clock. */ - board_artiq::ad9154::jesd_reset(false); - board_artiq::ad9154::init(); + board_artiq::jdcg::jesd_reset(false); + // TODO: board_artiq::ad9154::init(); } drtioaux::reset(0); @@ -483,7 +489,7 @@ pub extern fn main() -> i32 { hardware_tick(&mut hardware_tick_ts); if drtiosat_tsc_loaded() { info!("TSC loaded from uplink"); - #[cfg(has_ad9154)] + /* TODO: #[cfg(has_jdcg)] { if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { error!("failed to align SYSREF at FPGA: {}", e); @@ -491,7 +497,7 @@ pub extern fn main() -> i32 { if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() { error!("failed to align SYSREF at DAC: {}", e); } - } + } */ for rep in repeaters.iter() { if let Err(e) = rep.sync_tsc() { error!("failed to sync TSC ({})", e); @@ -503,8 +509,8 @@ pub extern fn main() -> i32 { } } - #[cfg(has_ad9154)] - board_artiq::ad9154::jesd_reset(true); + #[cfg(has_jdcg)] + board_artiq::jdcg::jesd_reset(true); drtiosat_reset_phy(true); drtiosat_reset(true); diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 5c0be328d..350a4b74d 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -203,8 +203,11 @@ class Satellite(_SatelliteBase): platform.request("hmc7043_gpo")) self.csr_devices.append("hmc7043_gpo") self.config["HAS_HMC830_7043"] = None + self.config["HAS_AD9154"] = None + self.config["AD9154_COUNT"] = 2 self.config["CONVERTER_SPI_HMC830_CS"] = 0 self.config["CONVERTER_SPI_HMC7043_CS"] = 1 + self.config["CONVERTER_SPI_FIRST_AD9154_CS"] = 2 self.config["HMC830_REF"] = "150" # HMC workarounds From a421820a32d0ba2de94fea3e258aa45d883d4d6e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Oct 2019 21:42:45 +0800 Subject: [PATCH 1927/2457] sayma: initialize DACs over DRTIO --- artiq/firmware/libboard_artiq/ad9154.rs | 4 +- artiq/firmware/libboard_artiq/jdcg.rs | 12 ++-- .../firmware/libproto_artiq/drtioaux_proto.rs | 21 +++++++ artiq/firmware/satman/main.rs | 56 ++++++++++++++++++- artiq/firmware/satman/repeater.rs | 4 ++ 5 files changed, 88 insertions(+), 9 deletions(-) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 86de3dbee..479d62f41 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -350,11 +350,11 @@ pub fn setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { 0x1*ad9154_reg::LINK_EN | 0*ad9154_reg::LINK_PAGE | 0*ad9154_reg::LINK_MODE | 0*ad9154_reg::CHECKSUM_MODE); info!(" ...done"); + status(dacno); Ok(()) } -#[allow(dead_code)] -fn status(dacno: u8) { +pub fn status(dacno: u8) { spi_setup(dacno); info!("SERDES_PLL_LOCK: {}", (read(ad9154_reg::PLL_STATUS) & ad9154_reg::SERDES_PLL_LOCK_RB)); diff --git a/artiq/firmware/libboard_artiq/jdcg.rs b/artiq/firmware/libboard_artiq/jdcg.rs index b93d28336..dfb0d8632 100644 --- a/artiq/firmware/libboard_artiq/jdcg.rs +++ b/artiq/firmware/libboard_artiq/jdcg.rs @@ -2,35 +2,35 @@ use board_misoc::csr; pub fn jesd_reset(reset: bool) { unsafe { - csr::jesd_crg::jreset_write(if reset {1} else {0}); + csr::jesd_crg::jreset_write(if reset {1} else {0}); } } -fn jesd_enable(dacno: u8, en: bool) { +pub fn jesd_enable(dacno: u8, en: bool) { unsafe { (csr::JDCG[dacno as usize].jesd_control_enable_write)(if en {1} else {0}) } } -fn jesd_ready(dacno: u8) -> bool { +pub fn jesd_ready(dacno: u8) -> bool { unsafe { (csr::JDCG[dacno as usize].jesd_control_ready_read)() != 0 } } -fn jesd_prbs(dacno: u8, en: bool) { +pub fn jesd_prbs(dacno: u8, en: bool) { unsafe { (csr::JDCG[dacno as usize].jesd_control_prbs_config_write)(if en {0b01} else {0b00}) } } -fn jesd_stpl(dacno: u8, en: bool) { +pub fn jesd_stpl(dacno: u8, en: bool) { unsafe { (csr::JDCG[dacno as usize].jesd_control_stpl_enable_write)(if en {1} else {0}) } } -fn jesd_jsync(dacno: u8) -> bool { +pub fn jesd_jsync(dacno: u8) -> bool { unsafe { (csr::JDCG[dacno as usize].jesd_control_jsync_read)() != 0 } diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 64e279614..092e6fb4d 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -53,6 +53,9 @@ pub enum Packet { SpiReadRequest { destination: u8, busno: u8 }, SpiReadReply { succeeded: bool, data: u32 }, SpiBasicReply { succeeded: bool }, + + JdacSetupRequest { destination: u8, dacno: u8 }, + JdacBasicReply { succeeded: bool }, } impl Packet { @@ -178,6 +181,14 @@ impl Packet { succeeded: reader.read_bool()? }, + 0xa0 => Packet::JdacSetupRequest { + destination: reader.read_u8()?, + dacno: reader.read_u8()?, + }, + 0xa1 => Packet::JdacBasicReply { + succeeded: reader.read_bool()? + }, + ty => return Err(Error::UnknownPacket(ty)) }) } @@ -329,6 +340,16 @@ impl Packet { writer.write_u8(0x95)?; writer.write_bool(succeeded)?; }, + + Packet::JdacSetupRequest { destination, dacno } => { + writer.write_u8(0xa0)?; + writer.write_u8(destination)?; + writer.write_u8(dacno)?; + } + Packet::JdacBasicReply { succeeded } => { + writer.write_u8(0xa1)?; + writer.write_bool(succeeded)?; + }, } Ok(()) } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index e9cc3c1ed..0434168bf 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -288,6 +288,22 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } } + drtioaux::Packet::JdacSetupRequest { destination: _destination, dacno: _dacno } => { + forward!(_routing_table, _destination, *_rank, _repeaters, &packet); + #[cfg(has_ad9154)] + let succeeded = { + #[cfg(rtio_frequency = "125.0")] + const LINERATE: u64 = 5_000_000_000; + #[cfg(rtio_frequency = "150.0")] + const LINERATE: u64 = 6_000_000_000; + board_artiq::ad9154::setup(_dacno, LINERATE).is_ok() + }; + #[cfg(not(has_ad9154))] + let succeeded = false; + drtioaux::send(0, + &drtioaux::Packet::JdacBasicReply { succeeded: succeeded }) + } + _ => { warn!("received unexpected aux packet"); Ok(()) @@ -400,6 +416,32 @@ const SI5324_SETTINGS: si5324::FrequencySettings crystal_ref: true }; +#[cfg(has_jdcg)] +fn init_jdcgs() { + for dacno in 0..csr::JDCG.len() { + let dacno = dacno as u8; + info!("DAC-{} initializing...", dacno); + board_artiq::jdcg::jesd_enable(dacno, false); + board_artiq::jdcg::jesd_prbs(dacno, false); + board_artiq::jdcg::jesd_stpl(dacno, false); + clock::spin_us(10000); + board_artiq::jdcg::jesd_enable(dacno, true); + if let Err(e) = drtioaux::send(1, &drtioaux::Packet::JdacSetupRequest { + destination: 0, + dacno: dacno + }) { + error!("aux packet error ({})", e); + } + match drtioaux::recv_timeout(1, Some(1000)) { + Ok(drtioaux::Packet::JdacBasicReply { succeeded }) => + if !succeeded { error!("DAC-{} initialization failed", dacno); }, + Ok(packet) => error!("received unexpected aux packet: {:?}", packet), + Err(e) => error!("aux packet error ({})", e), + } + info!(" ...done"); + } +} + #[no_mangle] pub extern fn main() -> i32 { clock::init(); @@ -473,19 +515,31 @@ pub extern fn main() -> i32 { * Si5324 is locked to the recovered clock. */ board_artiq::jdcg::jesd_reset(false); - // TODO: board_artiq::ad9154::init(); + if repeaters[0].is_up() { + init_jdcgs(); + } } drtioaux::reset(0); drtiosat_reset(false); drtiosat_reset_phy(false); + #[cfg(has_jdcg)] + let mut rep0_was_up = repeaters[0].is_up(); while drtiosat_link_rx_up() { drtiosat_process_errors(); process_aux_packets(&mut repeaters, &mut routing_table, &mut rank); for mut rep in repeaters.iter_mut() { rep.service(&routing_table, rank); } + #[cfg(has_jdcg)] + { + let rep0_is_up = repeaters[0].is_up(); + if rep0_is_up && !rep0_was_up { + init_jdcgs(); + } + rep0_was_up = rep0_is_up; + } hardware_tick(&mut hardware_tick_ts); if drtiosat_tsc_loaded() { info!("TSC loaded from uplink"); diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index f51d413aa..69a813d34 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -43,6 +43,10 @@ impl Repeater { } } + pub fn is_up(&self) -> bool { + self.state == RepeaterState::Up + } + pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8) { self.process_local_errors(); From 1bc7743e033089c3566fe18d62f779fff3cb8e0c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Oct 2019 21:50:29 +0800 Subject: [PATCH 1928/2457] sayma: fix hmc7043 output settings for v2 hardware --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 30 ++++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 2dbee9bef..194211612 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -149,22 +149,22 @@ pub mod hmc7043 { pub const SYSREF_DIV: u16 = 256; const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // must be <= 4MHz - // enabled, divider, output config + // enabled, divider, output config, is sysref const OUTPUT_CONFIG: [(bool, u16, u8, bool); 14] = [ - (true, DAC_CLK_DIV, 0x08, false), // 0: DAC2_CLK - (true, SYSREF_DIV, 0x08, true), // 1: DAC2_SYSREF - (true, DAC_CLK_DIV, 0x08, false), // 2: DAC1_CLK - (true, SYSREF_DIV, 0x08, true), // 3: DAC1_SYSREF - (false, 0, 0x08, false), // 4: ADC2_CLK - (false, 0, 0x08, true), // 5: ADC2_SYSREF - (false, 0, 0x08, false), // 6: GTP_CLK2 - (true, SYSREF_DIV, 0x10, true), // 7: FPGA_DAC_SYSREF, LVDS - (true, FPGA_CLK_DIV, 0x08, false), // 8: GTP_CLK1 - (false, 0, 0x10, true), // 9: AMC_MASTER_AUX_CLK - (true, FPGA_CLK_DIV, 0x10, true), // 10: RTM_MASTER_AUX_CLK, LVDS, used for DDMTD RTIO/SYSREF alignment - (false, 0, 0x10, true), // 11: FPGA_ADC_SYSREF - (false, 0, 0x08, false), // 12: ADC1_CLK - (false, 0, 0x08, true), // 13: ADC1_SYSREF + (true, DAC_CLK_DIV, 0x08, false), // 0: DAC1_CLK + (true, SYSREF_DIV, 0x08, true), // 1: DAC1_SYSREF + (true, DAC_CLK_DIV, 0x08, false), // 2: DAC0_CLK + (true, SYSREF_DIV, 0x08, true), // 3: DAC0_SYSREF + (false, 0, 0x10, true), // 4: AMC_FPGA_SYSREF0 + (false, 0, 0x10, true), // 5: AMC_FPGA_SYSREF1 + (false, 0, 0x10, false), // 6: unused + (true, SYSREF_DIV, 0x10, true), // 7: RTM_FPGA_SYSREF0 + (true, FPGA_CLK_DIV, 0x08, false), // 8: GTP_CLK0_IN + (false, 0, 0x10, false), // 9: unused + (false, 0, 0x10, false), // 10: unused + (false, 0, 0x10, false), // 11: unused / uFL + (false, 0, 0x10, false), // 12: unused + (false, SYSREF_DIV, 0x10, true), // 13: RTM_FPGA_SYSREF1 ]; fn spi_setup() { From 97a0dee3e83431a15b4585b0e5a3c2361047d815 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Oct 2019 22:26:31 +0800 Subject: [PATCH 1929/2457] jesd204: remove ibuf_disable We use the MOSFET to mute the HMC7043 noise on hardware v2 instead. --- artiq/gateware/jesd204_tools.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index a5151acf3..27a1ce6cc 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -20,7 +20,6 @@ class UltrascaleCRG(Module, AutoCSR): fabric_freq = int(125e6) def __init__(self, platform, use_rtio_clock=False): - self.ibuf_disable = CSRStorage(reset=1) self.jreset = CSRStorage(reset=1) self.refclk = Signal() self.clock_domains.cd_jesd = ClockDomain() @@ -29,7 +28,7 @@ class UltrascaleCRG(Module, AutoCSR): refclk_pads = platform.request("dac_refclk", 0) platform.add_period_constraint(refclk_pads.p, 1e9/self.refclk_freq) self.specials += [ - Instance("IBUFDS_GTE3", i_CEB=self.ibuf_disable.storage, p_REFCLK_HROW_CK_SEL=0b00, + Instance("IBUFDS_GTE3", i_CEB=0, p_REFCLK_HROW_CK_SEL=0b00, i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=self.refclk, o_ODIV2=refclk2), AsyncResetSynchronizer(self.cd_jesd, self.jreset.storage), From 90e3b83e8014ef45754c07cb42d58cd13787a187 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Oct 2019 22:48:55 +0800 Subject: [PATCH 1930/2457] hmc7043: turn on AMC_FPGA_SYSREF1 Florent's JESD core won't work at all without. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 194211612..880a1d085 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -156,7 +156,7 @@ pub mod hmc7043 { (true, DAC_CLK_DIV, 0x08, false), // 2: DAC0_CLK (true, SYSREF_DIV, 0x08, true), // 3: DAC0_SYSREF (false, 0, 0x10, true), // 4: AMC_FPGA_SYSREF0 - (false, 0, 0x10, true), // 5: AMC_FPGA_SYSREF1 + (true, SYSREF_DIV, 0x10, true), // 5: AMC_FPGA_SYSREF1 (false, 0, 0x10, false), // 6: unused (true, SYSREF_DIV, 0x10, true), // 7: RTM_FPGA_SYSREF0 (true, FPGA_CLK_DIV, 0x08, false), // 8: GTP_CLK0_IN From ebd5d890f17ba3f6eead8d16bd1aefe1deadbc04 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 6 Oct 2019 23:10:08 +0800 Subject: [PATCH 1931/2457] satman: check for JESD ready --- artiq/firmware/satman/main.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 0434168bf..368e5d2b2 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -421,11 +421,20 @@ fn init_jdcgs() { for dacno in 0..csr::JDCG.len() { let dacno = dacno as u8; info!("DAC-{} initializing...", dacno); + board_artiq::jdcg::jesd_enable(dacno, false); board_artiq::jdcg::jesd_prbs(dacno, false); board_artiq::jdcg::jesd_stpl(dacno, false); clock::spin_us(10000); board_artiq::jdcg::jesd_enable(dacno, true); + let t = clock::get_ms(); + while !board_artiq::jdcg::jesd_ready(dacno) { + if clock::get_ms() > t + 200 { + error!("JESD ready timeout"); + break; + } + } + if let Err(e) = drtioaux::send(1, &drtioaux::Packet::JdacSetupRequest { destination: 0, dacno: dacno From 03007b896e720804a32679bc15fcd13b0091bea7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 7 Oct 2019 20:31:35 +0800 Subject: [PATCH 1932/2457] sayma_amc: sma -> mcx --- artiq/gateware/targets/sayma_amc.py | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index be74a43f6..adc305e5e 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -246,14 +246,14 @@ class Satellite(SatelliteBase): phy = ttl_simple.Output(platform.request("user_led", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - sma_io = platform.request("sma_io", 0) - self.comb += sma_io.direction.eq(1) - phy = ttl_serdes_ultrascale.Output(4, sma_io.level) + mcx_io = platform.request("mcx_io", 0) + self.comb += mcx_io.direction.eq(1) + phy = ttl_serdes_ultrascale.Output(4, mcx_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - sma_io = platform.request("sma_io", 1) - self.comb += sma_io.direction.eq(0) - phy = ttl_serdes_ultrascale.InOut(4, sma_io.level) + mcx_io = platform.request("mcx_io", 1) + self.comb += mcx_io.direction.eq(0) + phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) @@ -298,14 +298,14 @@ class SimpleSatellite(SatelliteBase): phy = ttl_simple.Output(platform.request("user_led", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - sma_io = platform.request("sma_io", 0) - self.comb += sma_io.direction.eq(1) - phy = ttl_serdes_ultrascale.Output(4, sma_io.level) + mcx_io = platform.request("mcx_io", 0) + self.comb += mcx_io.direction.eq(1) + phy = ttl_serdes_ultrascale.Output(4, mcx_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - sma_io = platform.request("sma_io", 1) - self.comb += sma_io.direction.eq(0) - phy = ttl_serdes_ultrascale.InOut(4, sma_io.level) + mcx_io = platform.request("mcx_io", 1) + self.comb += mcx_io.direction.eq(0) + phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) @@ -416,14 +416,14 @@ class Master(MiniSoC, AMPSoC): phy = ttl_simple.Output(platform.request("user_led", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - sma_io = platform.request("sma_io", 0) - self.comb += sma_io.direction.eq(1) - phy = ttl_serdes_ultrascale.Output(4, sma_io.level) + mcx_io = platform.request("mcx_io", 0) + self.comb += mcx_io.direction.eq(1) + phy = ttl_serdes_ultrascale.Output(4, mcx_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - sma_io = platform.request("sma_io", 1) - self.comb += sma_io.direction.eq(0) - phy = ttl_serdes_ultrascale.InOut(4, sma_io.level) + mcx_io = platform.request("mcx_io", 1) + self.comb += mcx_io.direction.eq(0) + phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From 4b3baf4825ea3ae230d47664b0f56c8c2d2b5b00 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 8 Oct 2019 00:10:36 +0800 Subject: [PATCH 1933/2457] firmware: run PRBS and STPL JESD204 tests --- artiq/firmware/libboard_artiq/ad9154.rs | 1 - artiq/firmware/libboard_artiq/jdcg.rs | 37 ------- artiq/firmware/libboard_artiq/lib.rs | 2 - .../firmware/libproto_artiq/drtioaux_proto.rs | 8 +- artiq/firmware/satman/jdcg.rs | 98 +++++++++++++++++++ artiq/firmware/satman/main.rs | 55 +++-------- 6 files changed, 117 insertions(+), 84 deletions(-) delete mode 100644 artiq/firmware/libboard_artiq/jdcg.rs create mode 100644 artiq/firmware/satman/jdcg.rs diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 479d62f41..015fccb66 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -350,7 +350,6 @@ pub fn setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { 0x1*ad9154_reg::LINK_EN | 0*ad9154_reg::LINK_PAGE | 0*ad9154_reg::LINK_MODE | 0*ad9154_reg::CHECKSUM_MODE); info!(" ...done"); - status(dacno); Ok(()) } diff --git a/artiq/firmware/libboard_artiq/jdcg.rs b/artiq/firmware/libboard_artiq/jdcg.rs deleted file mode 100644 index dfb0d8632..000000000 --- a/artiq/firmware/libboard_artiq/jdcg.rs +++ /dev/null @@ -1,37 +0,0 @@ -use board_misoc::csr; - -pub fn jesd_reset(reset: bool) { - unsafe { - csr::jesd_crg::jreset_write(if reset {1} else {0}); - } -} - -pub fn jesd_enable(dacno: u8, en: bool) { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_enable_write)(if en {1} else {0}) - } -} - -pub fn jesd_ready(dacno: u8) -> bool { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_ready_read)() != 0 - } -} - -pub fn jesd_prbs(dacno: u8, en: bool) { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_prbs_config_write)(if en {0b01} else {0b00}) - } -} - -pub fn jesd_stpl(dacno: u8, en: bool) { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_stpl_enable_write)(if en {1} else {0}) - } -} - -pub fn jesd_jsync(dacno: u8) -> bool { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_jsync_read)() != 0 - } -} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 24594414f..9a1007588 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -42,8 +42,6 @@ mod ad9154_reg; pub mod ad9154; /* TODO: #[cfg(has_jdcg)] pub mod jesd204sync; */ -#[cfg(has_jdcg)] -pub mod jdcg; #[cfg(has_allaki_atts)] pub mod hmc542; diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 092e6fb4d..6b93d7167 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -54,7 +54,7 @@ pub enum Packet { SpiReadReply { succeeded: bool, data: u32 }, SpiBasicReply { succeeded: bool }, - JdacSetupRequest { destination: u8, dacno: u8 }, + JdacBasicRequest { destination: u8, dacno: u8, reqno: u8 }, JdacBasicReply { succeeded: bool }, } @@ -181,9 +181,10 @@ impl Packet { succeeded: reader.read_bool()? }, - 0xa0 => Packet::JdacSetupRequest { + 0xa0 => Packet::JdacBasicRequest { destination: reader.read_u8()?, dacno: reader.read_u8()?, + reqno: reader.read_u8()?, }, 0xa1 => Packet::JdacBasicReply { succeeded: reader.read_bool()? @@ -341,10 +342,11 @@ impl Packet { writer.write_bool(succeeded)?; }, - Packet::JdacSetupRequest { destination, dacno } => { + Packet::JdacBasicRequest { destination, dacno, reqno } => { writer.write_u8(0xa0)?; writer.write_u8(destination)?; writer.write_u8(dacno)?; + writer.write_u8(reqno)?; } Packet::JdacBasicReply { succeeded } => { writer.write_u8(0xa1)?; diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs new file mode 100644 index 000000000..278fcb775 --- /dev/null +++ b/artiq/firmware/satman/jdcg.rs @@ -0,0 +1,98 @@ +use board_misoc::{csr, clock}; +use board_artiq::drtioaux; + +pub fn jesd_reset(reset: bool) { + unsafe { + csr::jesd_crg::jreset_write(if reset {1} else {0}); + } +} + +fn jesd_enable(dacno: u8, en: bool) { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_enable_write)(if en {1} else {0}) + } + clock::spin_us(5000); +} + +fn jesd_ready(dacno: u8) -> bool { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_ready_read)() != 0 + } +} + +fn jesd_prbs(dacno: u8, en: bool) { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_prbs_config_write)(if en {0b01} else {0b00}) + } + clock::spin_us(5000); +} + +fn jesd_stpl(dacno: u8, en: bool) { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_stpl_enable_write)(if en {1} else {0}) + } + clock::spin_us(5000); +} + +fn jesd_jsync(dacno: u8) -> bool { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_jsync_read)() != 0 + } +} + +fn jdac_basic_request(dacno: u8, reqno: u8) { + if let Err(e) = drtioaux::send(1, &drtioaux::Packet::JdacBasicRequest { + destination: 0, + dacno: dacno, + reqno: reqno + }) { + error!("aux packet error ({})", e); + } + match drtioaux::recv_timeout(1, Some(1000)) { + Ok(drtioaux::Packet::JdacBasicReply { succeeded }) => + if !succeeded { + error!("JESD DAC basic request failed (dacno={}, reqno={})", dacno, reqno); + }, + Ok(packet) => error!("received unexpected aux packet: {:?}", packet), + Err(e) => error!("aux packet error ({})", e), + } +} + +pub fn init() { + for dacno in 0..csr::JDCG.len() { + let dacno = dacno as u8; + info!("DAC-{} initializing...", dacno); + + jesd_enable(dacno, true); + jesd_prbs(dacno, false); + jesd_stpl(dacno, false); + + jdac_basic_request(dacno, 0); + + jesd_prbs(dacno, true); + jdac_basic_request(dacno, 2); + jesd_prbs(dacno, false); + + jesd_stpl(dacno, true); + jdac_basic_request(dacno, 3); + jesd_stpl(dacno, false); + + jdac_basic_request(dacno, 0); + + let t = clock::get_ms(); + while !jesd_ready(dacno) { + if clock::get_ms() > t + 200 { + error!("JESD ready timeout"); + break; + } + } + clock::spin_us(5000); + jdac_basic_request(dacno, 1); + + if !jesd_jsync(dacno) { + error!("bad SYNC"); + } + + info!(" ...done"); + } +} diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 368e5d2b2..9c8e32c93 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -15,6 +15,8 @@ use board_artiq::drtio_routing; use board_artiq::hmc830_7043; mod repeater; +#[cfg(has_jdcg)] +mod jdcg; fn drtiosat_reset(reset: bool) { unsafe { @@ -288,7 +290,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } } - drtioaux::Packet::JdacSetupRequest { destination: _destination, dacno: _dacno } => { + drtioaux::Packet::JdacBasicRequest { destination: _destination, dacno: _dacno, reqno: _reqno } => { forward!(_routing_table, _destination, *_rank, _repeaters, &packet); #[cfg(has_ad9154)] let succeeded = { @@ -296,7 +298,13 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], const LINERATE: u64 = 5_000_000_000; #[cfg(rtio_frequency = "150.0")] const LINERATE: u64 = 6_000_000_000; - board_artiq::ad9154::setup(_dacno, LINERATE).is_ok() + match _reqno { + 0 => board_artiq::ad9154::setup(_dacno, LINERATE).is_ok(), + 1 => { board_artiq::ad9154::status(_dacno); true }, + 2 => board_artiq::ad9154::prbs(_dacno).is_ok(), + 3 => board_artiq::ad9154::stpl(_dacno, 4, 2).is_ok(), + _ => false + } }; #[cfg(not(has_ad9154))] let succeeded = false; @@ -416,41 +424,6 @@ const SI5324_SETTINGS: si5324::FrequencySettings crystal_ref: true }; -#[cfg(has_jdcg)] -fn init_jdcgs() { - for dacno in 0..csr::JDCG.len() { - let dacno = dacno as u8; - info!("DAC-{} initializing...", dacno); - - board_artiq::jdcg::jesd_enable(dacno, false); - board_artiq::jdcg::jesd_prbs(dacno, false); - board_artiq::jdcg::jesd_stpl(dacno, false); - clock::spin_us(10000); - board_artiq::jdcg::jesd_enable(dacno, true); - let t = clock::get_ms(); - while !board_artiq::jdcg::jesd_ready(dacno) { - if clock::get_ms() > t + 200 { - error!("JESD ready timeout"); - break; - } - } - - if let Err(e) = drtioaux::send(1, &drtioaux::Packet::JdacSetupRequest { - destination: 0, - dacno: dacno - }) { - error!("aux packet error ({})", e); - } - match drtioaux::recv_timeout(1, Some(1000)) { - Ok(drtioaux::Packet::JdacBasicReply { succeeded }) => - if !succeeded { error!("DAC-{} initialization failed", dacno); }, - Ok(packet) => error!("received unexpected aux packet: {:?}", packet), - Err(e) => error!("aux packet error ({})", e), - } - info!(" ...done"); - } -} - #[no_mangle] pub extern fn main() -> i32 { clock::init(); @@ -523,9 +496,9 @@ pub extern fn main() -> i32 { * To handle those cases, we simply keep the JESD204 core in reset unless the * Si5324 is locked to the recovered clock. */ - board_artiq::jdcg::jesd_reset(false); + jdcg::jesd_reset(false); if repeaters[0].is_up() { - init_jdcgs(); + jdcg::init(); } } @@ -545,7 +518,7 @@ pub extern fn main() -> i32 { { let rep0_is_up = repeaters[0].is_up(); if rep0_is_up && !rep0_was_up { - init_jdcgs(); + jdcg::init(); } rep0_was_up = rep0_is_up; } @@ -573,7 +546,7 @@ pub extern fn main() -> i32 { } #[cfg(has_jdcg)] - board_artiq::jdcg::jesd_reset(true); + jdcg::jesd_reset(true); drtiosat_reset_phy(true); drtiosat_reset(true); From 5ee81dc6438eaa173d94a48a205816755f49a403 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 8 Oct 2019 10:27:04 +0800 Subject: [PATCH 1934/2457] satman: define constants for JdacBasicRequest reqnos --- artiq/firmware/satman/jdac_requests.rs | 4 ++++ artiq/firmware/satman/jdcg.rs | 12 +++++++----- artiq/firmware/satman/main.rs | 10 ++++++---- 3 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 artiq/firmware/satman/jdac_requests.rs diff --git a/artiq/firmware/satman/jdac_requests.rs b/artiq/firmware/satman/jdac_requests.rs new file mode 100644 index 000000000..2ba120ebb --- /dev/null +++ b/artiq/firmware/satman/jdac_requests.rs @@ -0,0 +1,4 @@ +pub const INIT: u8 = 0x00; +pub const PRINT_STATUS: u8 = 0x01; +pub const PRBS: u8 = 0x02; +pub const STPL: u8 = 0x03; diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs index 278fcb775..f7bdd8f90 100644 --- a/artiq/firmware/satman/jdcg.rs +++ b/artiq/firmware/satman/jdcg.rs @@ -1,6 +1,8 @@ use board_misoc::{csr, clock}; use board_artiq::drtioaux; +use super::jdac_requests; + pub fn jesd_reset(reset: bool) { unsafe { csr::jesd_crg::jreset_write(if reset {1} else {0}); @@ -67,17 +69,17 @@ pub fn init() { jesd_prbs(dacno, false); jesd_stpl(dacno, false); - jdac_basic_request(dacno, 0); + jdac_basic_request(dacno, jdac_requests::INIT); jesd_prbs(dacno, true); - jdac_basic_request(dacno, 2); + jdac_basic_request(dacno, jdac_requests::PRBS); jesd_prbs(dacno, false); jesd_stpl(dacno, true); - jdac_basic_request(dacno, 3); + jdac_basic_request(dacno, jdac_requests::STPL); jesd_stpl(dacno, false); - jdac_basic_request(dacno, 0); + jdac_basic_request(dacno, jdac_requests::INIT); let t = clock::get_ms(); while !jesd_ready(dacno) { @@ -87,7 +89,7 @@ pub fn init() { } } clock::spin_us(5000); - jdac_basic_request(dacno, 1); + jdac_basic_request(dacno, jdac_requests::PRINT_STATUS); if !jesd_jsync(dacno) { error!("bad SYNC"); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 9c8e32c93..c08e1b605 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -17,6 +17,8 @@ use board_artiq::hmc830_7043; mod repeater; #[cfg(has_jdcg)] mod jdcg; +#[cfg(any(has_ad9154, has_jdcg))] +pub mod jdac_requests; fn drtiosat_reset(reset: bool) { unsafe { @@ -299,10 +301,10 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], #[cfg(rtio_frequency = "150.0")] const LINERATE: u64 = 6_000_000_000; match _reqno { - 0 => board_artiq::ad9154::setup(_dacno, LINERATE).is_ok(), - 1 => { board_artiq::ad9154::status(_dacno); true }, - 2 => board_artiq::ad9154::prbs(_dacno).is_ok(), - 3 => board_artiq::ad9154::stpl(_dacno, 4, 2).is_ok(), + jdac_requests::INIT => board_artiq::ad9154::setup(_dacno, LINERATE).is_ok(), + jdac_requests::PRINT_STATUS => { board_artiq::ad9154::status(_dacno); true }, + jdac_requests::PRBS => board_artiq::ad9154::prbs(_dacno).is_ok(), + jdac_requests::STPL => board_artiq::ad9154::stpl(_dacno, 4, 2).is_ok(), _ => false } }; From 4df2c5d1fbc88ca957e2e064501d8e22bd61b787 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 8 Oct 2019 12:30:47 +0800 Subject: [PATCH 1935/2457] sayma: prepare for SYSREF align We will try DDMTD on the AMC first, as this is simpler and perhaps will work on v2 after the power supply fixes. --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 4 +- artiq/firmware/satman/jdcg.rs | 203 +++++++++++-------- artiq/firmware/satman/main.rs | 34 ++-- artiq/gateware/targets/sayma_amc.py | 9 +- artiq/gateware/targets/sayma_rtm.py | 7 - 5 files changed, 139 insertions(+), 118 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 880a1d085..18cbb8794 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -155,8 +155,8 @@ pub mod hmc7043 { (true, SYSREF_DIV, 0x08, true), // 1: DAC1_SYSREF (true, DAC_CLK_DIV, 0x08, false), // 2: DAC0_CLK (true, SYSREF_DIV, 0x08, true), // 3: DAC0_SYSREF - (false, 0, 0x10, true), // 4: AMC_FPGA_SYSREF0 - (true, SYSREF_DIV, 0x10, true), // 5: AMC_FPGA_SYSREF1 + (true, SYSREF_DIV, 0x10, true), // 4: AMC_FPGA_SYSREF0 + (true, FPGA_CLK_DIV, 0x10, true), // 5: AMC_FPGA_SYSREF1 (false, 0, 0x10, false), // 6: unused (true, SYSREF_DIV, 0x10, true), // 7: RTM_FPGA_SYSREF0 (true, FPGA_CLK_DIV, 0x08, false), // 8: GTP_CLK0_IN diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs index f7bdd8f90..a4ae234db 100644 --- a/artiq/firmware/satman/jdcg.rs +++ b/artiq/firmware/satman/jdcg.rs @@ -1,100 +1,123 @@ -use board_misoc::{csr, clock}; -use board_artiq::drtioaux; +pub mod jesd { + use board_misoc::{csr, clock}; -use super::jdac_requests; - -pub fn jesd_reset(reset: bool) { - unsafe { - csr::jesd_crg::jreset_write(if reset {1} else {0}); + pub fn reset(reset: bool) { + unsafe { + csr::jesd_crg::jreset_write(if reset {1} else {0}); + } } -} -fn jesd_enable(dacno: u8, en: bool) { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_enable_write)(if en {1} else {0}) - } - clock::spin_us(5000); -} - -fn jesd_ready(dacno: u8) -> bool { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_ready_read)() != 0 - } -} - -fn jesd_prbs(dacno: u8, en: bool) { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_prbs_config_write)(if en {0b01} else {0b00}) - } - clock::spin_us(5000); -} - -fn jesd_stpl(dacno: u8, en: bool) { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_stpl_enable_write)(if en {1} else {0}) - } - clock::spin_us(5000); -} - -fn jesd_jsync(dacno: u8) -> bool { - unsafe { - (csr::JDCG[dacno as usize].jesd_control_jsync_read)() != 0 - } -} - -fn jdac_basic_request(dacno: u8, reqno: u8) { - if let Err(e) = drtioaux::send(1, &drtioaux::Packet::JdacBasicRequest { - destination: 0, - dacno: dacno, - reqno: reqno - }) { - error!("aux packet error ({})", e); - } - match drtioaux::recv_timeout(1, Some(1000)) { - Ok(drtioaux::Packet::JdacBasicReply { succeeded }) => - if !succeeded { - error!("JESD DAC basic request failed (dacno={}, reqno={})", dacno, reqno); - }, - Ok(packet) => error!("received unexpected aux packet: {:?}", packet), - Err(e) => error!("aux packet error ({})", e), - } -} - -pub fn init() { - for dacno in 0..csr::JDCG.len() { - let dacno = dacno as u8; - info!("DAC-{} initializing...", dacno); - - jesd_enable(dacno, true); - jesd_prbs(dacno, false); - jesd_stpl(dacno, false); - - jdac_basic_request(dacno, jdac_requests::INIT); - - jesd_prbs(dacno, true); - jdac_basic_request(dacno, jdac_requests::PRBS); - jesd_prbs(dacno, false); - - jesd_stpl(dacno, true); - jdac_basic_request(dacno, jdac_requests::STPL); - jesd_stpl(dacno, false); - - jdac_basic_request(dacno, jdac_requests::INIT); - - let t = clock::get_ms(); - while !jesd_ready(dacno) { - if clock::get_ms() > t + 200 { - error!("JESD ready timeout"); - break; - } + pub fn enable(dacno: u8, en: bool) { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_enable_write)(if en {1} else {0}) } clock::spin_us(5000); - jdac_basic_request(dacno, jdac_requests::PRINT_STATUS); + } - if !jesd_jsync(dacno) { - error!("bad SYNC"); + pub fn ready(dacno: u8) -> bool { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_ready_read)() != 0 } + } - info!(" ...done"); + pub fn prbs(dacno: u8, en: bool) { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_prbs_config_write)(if en {0b01} else {0b00}) + } + clock::spin_us(5000); + } + + pub fn stpl(dacno: u8, en: bool) { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_stpl_enable_write)(if en {1} else {0}) + } + clock::spin_us(5000); + } + + pub fn jsync(dacno: u8) -> bool { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_jsync_read)() != 0 + } + } +} + +pub mod jdac { + use board_misoc::{csr, clock}; + use board_artiq::drtioaux; + + use super::jesd; + use super::super::jdac_requests; + + pub fn basic_request(dacno: u8, reqno: u8) { + if let Err(e) = drtioaux::send(1, &drtioaux::Packet::JdacBasicRequest { + destination: 0, + dacno: dacno, + reqno: reqno + }) { + error!("aux packet error ({})", e); + } + match drtioaux::recv_timeout(1, Some(1000)) { + Ok(drtioaux::Packet::JdacBasicReply { succeeded }) => + if !succeeded { + error!("JESD DAC basic request failed (dacno={}, reqno={})", dacno, reqno); + }, + Ok(packet) => error!("received unexpected aux packet: {:?}", packet), + Err(e) => error!("aux packet error ({})", e), + } + } + + pub fn init() { + for dacno in 0..csr::JDCG.len() { + let dacno = dacno as u8; + info!("DAC-{} initializing...", dacno); + + jesd::enable(dacno, true); + clock::spin_us(10); + if !jesd::ready(dacno) { + error!("JESD core reported not ready"); + } + + basic_request(dacno, jdac_requests::INIT); + + jesd::prbs(dacno, true); + basic_request(dacno, jdac_requests::PRBS); + jesd::prbs(dacno, false); + + jesd::stpl(dacno, true); + basic_request(dacno, jdac_requests::STPL); + jesd::stpl(dacno, false); + + basic_request(dacno, jdac_requests::INIT); + clock::spin_us(5000); + + basic_request(dacno, jdac_requests::PRINT_STATUS); + + if !jesd::jsync(dacno) { + error!("JESD core reported bad SYNC"); + } + + info!(" ...done"); + } + } +} + +pub mod jesd204sync { + fn sysref_auto_rtio_align() -> Result<(), &'static str> { + info!("TODO: sysref_auto_rtio_align"); + Ok(()) + } + + fn sysref_auto_dac_align() -> Result<(), &'static str> { + info!("TODO: sysref_auto_dac_align"); + Ok(()) + } + + pub fn sysref_auto_align() { + if let Err(e) = sysref_auto_rtio_align() { + error!("failed to align SYSREF at FPGA: {}", e); + } + if let Err(e) = sysref_auto_dac_align() { + error!("failed to align SYSREF at DAC: {}", e); + } } } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index c08e1b605..9d09d6859 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -498,9 +498,9 @@ pub extern fn main() -> i32 { * To handle those cases, we simply keep the JESD204 core in reset unless the * Si5324 is locked to the recovered clock. */ - jdcg::jesd_reset(false); + jdcg::jesd::reset(false); if repeaters[0].is_up() { - jdcg::init(); + jdcg::jdac::init(); } } @@ -516,26 +516,15 @@ pub extern fn main() -> i32 { for mut rep in repeaters.iter_mut() { rep.service(&routing_table, rank); } - #[cfg(has_jdcg)] - { - let rep0_is_up = repeaters[0].is_up(); - if rep0_is_up && !rep0_was_up { - jdcg::init(); - } - rep0_was_up = rep0_is_up; - } hardware_tick(&mut hardware_tick_ts); if drtiosat_tsc_loaded() { info!("TSC loaded from uplink"); - /* TODO: #[cfg(has_jdcg)] + #[cfg(has_jdcg)] { - if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { - error!("failed to align SYSREF at FPGA: {}", e); + if rep0_was_up { + jdcg::jesd204sync::sysref_auto_align(); } - if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() { - error!("failed to align SYSREF at DAC: {}", e); - } - } */ + } for rep in repeaters.iter() { if let Err(e) = rep.sync_tsc() { error!("failed to sync TSC ({})", e); @@ -545,10 +534,19 @@ pub extern fn main() -> i32 { error!("aux packet error: {}", e); } } + #[cfg(has_jdcg)] + { + let rep0_is_up = repeaters[0].is_up(); + if rep0_is_up && !rep0_was_up { + jdcg::jdac::init(); + jdcg::jesd204sync::sysref_auto_align(); + } + rep0_was_up = rep0_is_up; + } } #[cfg(has_jdcg)] - jdcg::jesd_reset(true); + jdcg::jesd::reset(true); drtiosat_reset_phy(true); drtiosat_reset(true); diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index adc305e5e..82b53c817 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -58,6 +58,7 @@ class SatelliteBase(BaseSoC): l2_size=128*1024, **kwargs) add_identifier(self, suffix=identifier_suffix) + self.rtio_clk_freq = rtio_clk_freq platform = self.platform @@ -279,11 +280,17 @@ class Satellite(SatelliteBase): self.add_rtio(rtio_channels) self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( - platform.request("dac_sysref"), self.rtio_tsc.coarse_ts) + platform.request("amc_fpga_sysref", 0), self.rtio_tsc.coarse_ts) self.csr_devices.append("sysref_sampler") self.jdcg_0.jesd.core.register_jref(self.sysref_sampler.jref) self.jdcg_1.jesd.core.register_jref(self.sysref_sampler.jref) + # DDMTD + # https://github.com/sinara-hw/Sayma_RTM/issues/68 + sysref_pads = platform.request("amc_fpga_sysref", 1) + self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(sysref_pads, self.rtio_clk_freq) + self.csr_devices.append("sysref_ddmtd") + class SimpleSatellite(SatelliteBase): def __init__(self, **kwargs): diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 350a4b74d..02a3afe42 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -21,7 +21,6 @@ from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import * -from artiq.gateware import jesd204_tools from artiq.build_soc import add_identifier from artiq import __artiq_dir__ as artiq_dir @@ -216,12 +215,6 @@ class Satellite(_SatelliteBase): platform.request("hmc7043_out_en")) self.csr_devices.append("hmc7043_out_en") - # DDMTD - # https://github.com/sinara-hw/Sayma_RTM/issues/68 - sysref_pads = platform.request("rtm_fpga_sysref", 1) # use odd-numbered 7043 output - self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(sysref_pads, self.rtio_clk_freq) - self.csr_devices.append("sysref_ddmtd") - class SatmanSoCBuilder(Builder): def __init__(self, *args, **kwargs): From 314d9b5d063c466a91f106e0fce3b191834910d5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 8 Oct 2019 12:59:52 +0800 Subject: [PATCH 1936/2457] kasli: default to 125MHz frequency for DRTIO This is the consistent and most common option. Sayma will also eventually move to it. --- artiq/gateware/targets/kasli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 835f6c863..630108088 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -273,7 +273,7 @@ class MasterBase(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, rtio_clk_freq=150e6, enable_sata=False, **kwargs): + def __init__(self, rtio_clk_freq=125e6, enable_sata=False, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -435,7 +435,7 @@ class SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, rtio_clk_freq=150e6, enable_sata=False, **kwargs): + def __init__(self, rtio_clk_freq=125e6, enable_sata=False, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", From 3aade3b59ac5d0f0aafd0368ba1875caacb3fd53 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 10 Oct 2019 10:55:44 +0800 Subject: [PATCH 1937/2457] manual: now building for nixpkgs 19.09 --- doc/manual/installing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 2e53a0b0b..e76de4580 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -23,10 +23,10 @@ Once Nix is installed, add the M-Labs package channel with: :: $ nix-channel --add https://nixbld.m-labs.hk/channel/custom/artiq/full/artiq-full -Those channels track `nixpkgs 19.03 `_. You can check the latest status through the `Hydra interface `_. As the Nix package manager default installation uses the development version of nixpkgs, we need to tell it to switch to the release: :: +Those channels track `nixpkgs 19.09 `_. You can check the latest status through the `Hydra interface `_. As the Nix package manager default installation uses the development version of nixpkgs, we need to tell it to switch to the release: :: $ nix-channel --remove nixpkgs - $ nix-channel --add https://nixos.org/channels/nixos-19.03 nixpkgs + $ nix-channel --add https://nixos.org/channels/nixos-19.09 nixpkgs Finally, make all the channel changes effective: :: From 9c5ff4fc0454f75a0572d2defe9cc16e938fe2b1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 10 Oct 2019 11:29:48 +0800 Subject: [PATCH 1938/2457] manual: Nix bug 2709 fixed in Nix 2.3 --- doc/manual/installing.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index e76de4580..e75f447c5 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -41,9 +41,6 @@ Nix won't install packages without verifying their cryptographic signature. Add The easiest way to obtain ARTIQ is then to install it into the user environment with ``$ nix-env -iA artiq-full.artiq-env``. This provides a minimal installation of ARTIQ where the usual commands (``artiq_master``, ``artiq_dashboard``, ``artiq_run``, etc.) are available. -.. note:: - If you are getting the error message ``file 'artiq-full' was not found in the Nix search path``, you are probably encountering `this Nix bug `_. As a workaround, enter the command ``$ export NIX_PATH=~/.nix-defexpr/channels:$NIX_PATH`` and try again. - This installation is however quite limited, as Nix creates a dedicated Python environment for the ARTIQ commands alone. This means that other useful Python packages that you may want (pandas, matplotlib, ...) are not available to them, and this restriction also applies to the M-Labs packages containing board binaries, which means that ``artiq_flash`` will not automatically find them. Installing multiple packages and making them visible to the ARTIQ commands requires using the Nix language. Create a file ``my-artiq-env.nix`` with the following contents: From 371388ecbe28bec74a2775392e440180b6c5bf39 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 11 Oct 2019 17:43:32 +0100 Subject: [PATCH 1939/2457] doc: Re-fix ARTIQ type hint formatting (#714) This adapts the previous monkey patch for the changed location of the attribute rendering code in Sphinx 2.0. --- doc/manual/conf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/manual/conf.py b/doc/manual/conf.py index 2243cad21..3b52040ad 100644 --- a/doc/manual/conf.py +++ b/doc/manual/conf.py @@ -23,7 +23,8 @@ import sphinx_rtd_theme # Hack-patch Sphinx so that ARTIQ-Python types are correctly printed # See: https://github.com/m-labs/artiq/issues/741 from sphinx.ext import autodoc -autodoc.repr = str +from sphinx.util import inspect +autodoc.repr = inspect.repr = str # we cannot use autodoc_mock_imports (does not help with argparse) From c64c8b4ddc40063acc2534b628815417061fb5b3 Mon Sep 17 00:00:00 2001 From: Tim Ballance Date: Sat, 12 Oct 2019 10:04:01 +0800 Subject: [PATCH 1940/2457] manual: RTIO sequence error notes (#1311) --- doc/manual/getting_started_core.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/manual/getting_started_core.rst b/doc/manual/getting_started_core.rst index e139f4afc..a17e0633e 100644 --- a/doc/manual/getting_started_core.rst +++ b/doc/manual/getting_started_core.rst @@ -174,6 +174,12 @@ Within a parallel block, some statements can be made sequential again using a `` self.ttl1.pulse(4*us) delay(4*us) +Particular care needs to be taken when working with ``parallel`` blocks in cases where a large number of RTIO events are generated as it possible to create sequencing errors (`RTIO sequence error`). Sequence errors do not halt execution of the kernel for performance reasons and instead are reported in the core log. If the ``aqctl_corelog`` process has been started with ``artiq_ctlmgr``, then these errors will be posted to the master log. However, if an experiment is executed through ``artiq_run``, these errors will not be visible outside of the core log. + +A sequence error is caused when the scalable event dispatcher (SED) cannot queue an RTIO event due to its timestamp being the same as or earlier than another event in its queue. By default, the SED has 8 lanes which allows ``parallel`` events to work without sequence errors in most cases, however if many (>8) events are queued with conflicting timestamps this error can surface. + +These errors can usually be overcome by reordering the generation of the events. Alternatively, the number of SED lanes can be increased in the gateware. + .. _rtio-analyzer-example: RTIO analyzer From 6cf06fba7ba4f95719ae15ab971c09f400a68a00 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 16 Oct 2019 16:16:34 +0800 Subject: [PATCH 1941/2457] examples: use default IP addresses for boards --- artiq/examples/kasli/device_db.py | 2 +- artiq/examples/kasli_drtioswitching/device_db.py | 2 +- artiq/examples/kasli_sawgmaster/device_db.py | 2 +- artiq/examples/sayma_master/device_db.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/examples/kasli/device_db.py b/artiq/examples/kasli/device_db.py index 83f53640f..4b20c7a28 100644 --- a/artiq/examples/kasli/device_db.py +++ b/artiq/examples/kasli/device_db.py @@ -1,6 +1,6 @@ # Tester device database -core_addr = "kasli-1.lab.m-labs.hk" +core_addr = "192.168.1.70" device_db = { "core": { diff --git a/artiq/examples/kasli_drtioswitching/device_db.py b/artiq/examples/kasli_drtioswitching/device_db.py index f04ee1869..433eaf7bc 100644 --- a/artiq/examples/kasli_drtioswitching/device_db.py +++ b/artiq/examples/kasli_drtioswitching/device_db.py @@ -1,4 +1,4 @@ -core_addr = "kasli-1.lab.m-labs.hk" +core_addr = "192.168.1.70" device_db = { "core": { diff --git a/artiq/examples/kasli_sawgmaster/device_db.py b/artiq/examples/kasli_sawgmaster/device_db.py index 70fa47ab1..68fa62e0a 100644 --- a/artiq/examples/kasli_sawgmaster/device_db.py +++ b/artiq/examples/kasli_sawgmaster/device_db.py @@ -1,4 +1,4 @@ -core_addr = "kasli-1.lab.m-labs.hk" +core_addr = "192.168.1.70" device_db = { "core": { diff --git a/artiq/examples/sayma_master/device_db.py b/artiq/examples/sayma_master/device_db.py index 38e78821e..e3a4e00fe 100644 --- a/artiq/examples/sayma_master/device_db.py +++ b/artiq/examples/sayma_master/device_db.py @@ -1,4 +1,4 @@ -core_addr = "sayma-1.lab.m-labs.hk" +core_addr = "192.168.1.60" device_db = { "core": { From 21a1c6de3ff78f56a6034c9d934f3f29aa117c54 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 16 Oct 2019 17:53:40 +0800 Subject: [PATCH 1942/2457] sayma: use SFP0 for DRTIO master --- artiq/gateware/targets/sayma_amc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 82b53c817..44300653d 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -361,10 +361,10 @@ class Master(MiniSoC, AMPSoC): self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - self.comb += platform.request("sfp_tx_disable", 1).eq(0) + self.comb += platform.request("sfp_tx_disable", 0).eq(0) self.submodules.drtio_transceiver = gth_ultrascale.GTH( clock_pads=platform.request("cdr_clk_clean", 0), - data_pads=[platform.request("sfp", 1)] + + data_pads=[platform.request("sfp", 0)] + # 6 and not 8 to work around Vivado bug (Xilinx CR 1020646) [platform.request("rtm_gth", i) for i in range(6)], sys_clk_freq=self.clk_freq, From 40d64fc782c2d4bf011afda7e81e7f0c0886293a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 16 Oct 2019 17:54:39 +0800 Subject: [PATCH 1943/2457] sayma: remove standalone examples (no longer supported) --- artiq/examples/sayma_standalone/device_db.py | 125 --------------- .../sayma_standalone/repository/blink_led.py | 16 -- .../sayma_standalone/repository/demo.py | 48 ------ .../sayma_standalone/repository/demo_2tone.py | 62 -------- .../sayma_standalone/repository/sines.py | 22 --- .../repository/test_ad9154_status.py | 145 ------------------ 6 files changed, 418 deletions(-) delete mode 100644 artiq/examples/sayma_standalone/device_db.py delete mode 100644 artiq/examples/sayma_standalone/repository/blink_led.py delete mode 100644 artiq/examples/sayma_standalone/repository/demo.py delete mode 100644 artiq/examples/sayma_standalone/repository/demo_2tone.py delete mode 100644 artiq/examples/sayma_standalone/repository/sines.py delete mode 100644 artiq/examples/sayma_standalone/repository/test_ad9154_status.py diff --git a/artiq/examples/sayma_standalone/device_db.py b/artiq/examples/sayma_standalone/device_db.py deleted file mode 100644 index 303fdce7e..000000000 --- a/artiq/examples/sayma_standalone/device_db.py +++ /dev/null @@ -1,125 +0,0 @@ -core_addr = "sayma-1.lab.m-labs.hk" - -device_db = { - "core": { - "type": "local", - "module": "artiq.coredevice.core", - "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1/150e6, "ref_multiplier": 1} - }, - "core_log": { - "type": "controller", - "host": "::1", - "port": 1068, - "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr - }, - "core_cache": { - "type": "local", - "module": "artiq.coredevice.cache", - "class": "CoreCache" - }, - - "converter_spi": { - "type": "local", - "module": "artiq.coredevice.spi2", - "class": "NRTSPIMaster", - }, - "ad9154_spi0": { - "type": "local", - "module": "artiq.coredevice.ad9154_spi", - "class": "AD9154", - "arguments": {"spi_device": "converter_spi", "chip_select": 2} - }, - "ad9154_spi1": { - "type": "local", - "module": "artiq.coredevice.ad9154_spi", - "class": "AD9154", - "arguments": {"spi_device": "converter_spi", "chip_select": 3} - }, - - "led0": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 0} - }, - "led1": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 1} - }, - "led1": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 2} - }, - "led1": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 3} - }, - "ttl_sma_out": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 4} - }, - "ttl_sma_in": { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 5} - }, - - "sawg0": { - "type": "local", - "module": "artiq.coredevice.sawg", - "class": "SAWG", - "arguments": {"channel_base": 6, "parallelism": 4} - }, - "sawg1": { - "type": "local", - "module": "artiq.coredevice.sawg", - "class": "SAWG", - "arguments": {"channel_base": 16, "parallelism": 4} - }, - "sawg2": { - "type": "local", - "module": "artiq.coredevice.sawg", - "class": "SAWG", - "arguments": {"channel_base": 26, "parallelism": 4} - }, - "sawg3": { - "type": "local", - "module": "artiq.coredevice.sawg", - "class": "SAWG", - "arguments": {"channel_base": 36, "parallelism": 4} - }, - "sawg4": { - "type": "local", - "module": "artiq.coredevice.sawg", - "class": "SAWG", - "arguments": {"channel_base": 46, "parallelism": 4} - }, - "sawg5": { - "type": "local", - "module": "artiq.coredevice.sawg", - "class": "SAWG", - "arguments": {"channel_base": 56, "parallelism": 4} - }, - "sawg6": { - "type": "local", - "module": "artiq.coredevice.sawg", - "class": "SAWG", - "arguments": {"channel_base": 66, "parallelism": 4} - }, - "sawg7": { - "type": "local", - "module": "artiq.coredevice.sawg", - "class": "SAWG", - "arguments": {"channel_base": 76, "parallelism": 4} - }, -} diff --git a/artiq/examples/sayma_standalone/repository/blink_led.py b/artiq/examples/sayma_standalone/repository/blink_led.py deleted file mode 100644 index d0fc99cb8..000000000 --- a/artiq/examples/sayma_standalone/repository/blink_led.py +++ /dev/null @@ -1,16 +0,0 @@ -from artiq.experiment import * - - -class BlinkSaymaLED(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("led0") - - @kernel - def run(self): - self.core.reset() - while True: - for _ in range(3): - self.led0.pulse(100*ms) - delay(100*ms) - delay(500*ms) diff --git a/artiq/examples/sayma_standalone/repository/demo.py b/artiq/examples/sayma_standalone/repository/demo.py deleted file mode 100644 index f1d43fd4e..000000000 --- a/artiq/examples/sayma_standalone/repository/demo.py +++ /dev/null @@ -1,48 +0,0 @@ -from artiq.experiment import * - - -class SAWGTest(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("ttl_sma_out") - - self.setattr_device("sawg0") - self.setattr_device("sawg1") - self.setattr_device("sawg2") - self.setattr_device("sawg3") - - @kernel - def run(self): - self.core.reset() - - while True: - self.sawg0.amplitude1.set(0.) - self.sawg0.frequency0.set(0*MHz) - self.sawg1.amplitude1.set(0.) - self.sawg1.frequency0.set(0*MHz) - delay(20*ms) - - self.sawg0.amplitude1.set(.4) - self.sawg0.frequency0.set(10*MHz) - self.sawg0.phase0.set(0.) - self.sawg1.amplitude1.set(.4) - self.sawg1.frequency0.set(10*MHz) - self.sawg1.phase0.set(0.) - self.ttl_sma_out.pulse(200*ns) - self.sawg1.amplitude1.set(.1) - delay(200*ns) - self.sawg1.amplitude1.set(-.4) - self.ttl_sma_out.pulse(200*ns) - self.sawg1.amplitude1.set(.4) - delay(200*ns) - self.sawg1.phase0.set(.25) - self.ttl_sma_out.pulse(200*ns) - self.sawg1.phase0.set(.5) - delay(200*ns) - self.sawg0.phase0.set(.5) - self.ttl_sma_out.pulse(200*ns) - self.sawg1.frequency0.set(30*MHz) - delay(200*ns) - self.sawg1.frequency0.set(10*MHz) - self.sawg1.phase0.set(0.) - self.ttl_sma_out.pulse(200*ns) diff --git a/artiq/examples/sayma_standalone/repository/demo_2tone.py b/artiq/examples/sayma_standalone/repository/demo_2tone.py deleted file mode 100644 index 756b25c33..000000000 --- a/artiq/examples/sayma_standalone/repository/demo_2tone.py +++ /dev/null @@ -1,62 +0,0 @@ -from artiq.experiment import * - - -class SAWGTestTwoTone(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("led0") - self.setattr_device("ttl_sma_out") - - self.setattr_device("sawg0") - self.setattr_device("sawg1") - self.setattr_device("sawg2") - self.setattr_device("sawg3") - - @kernel - def run(self): - self.core.reset() - delay(1*ms) - - self.sawg0.reset() - self.sawg1.reset() - self.sawg2.reset() - self.sawg3.reset() - - self.sawg0.config.set_clr(1, 1, 1) - delay(10*us) - self.sawg0.config.set_out_max(1.) - delay(10*us) - self.sawg0.config.set_out_min(-1.) - delay(10*us) - - while True: - t_up = t_hold = t_down = 800*ns - a1 = .3 - a2 = .4 - order = 3 - - delay(20*ms) - self.led0.on() - self.ttl_sma_out.on() - self.sawg0.frequency0.set(10*MHz) - self.sawg0.phase0.set(0.) - self.sawg0.frequency1.set(1*MHz) - self.sawg0.phase1.set(0.) - self.sawg0.frequency2.set(9*MHz) - self.sawg0.phase2.set(0.) - with parallel: - self.sawg0.amplitude1.smooth(.0, a1, t_up, order) - self.sawg0.amplitude2.smooth(.0, a2, t_up, order) - self.sawg0.amplitude1.set(a1) - self.sawg0.amplitude2.set(a2) - delay(t_hold) - with parallel: - self.sawg0.amplitude1.smooth(a1, .0, t_down, order) - self.sawg0.amplitude2.smooth(a2, .0, t_down, order) - self.sawg0.amplitude1.set(.0) - self.sawg0.amplitude2.set(.0) - - self.sawg1.amplitude1.set(.0) - self.sawg1.amplitude2.set(.0) - self.ttl_sma_out.off() - self.led0.off() diff --git a/artiq/examples/sayma_standalone/repository/sines.py b/artiq/examples/sayma_standalone/repository/sines.py deleted file mode 100644 index 7207ba7ec..000000000 --- a/artiq/examples/sayma_standalone/repository/sines.py +++ /dev/null @@ -1,22 +0,0 @@ -from artiq.experiment import * - - -class SAWGTest(EnvExperiment): - def build(self): - self.setattr_device("core") - self.setattr_device("ttl_sma_out") - self.sawgs = [self.get_device("sawg"+str(i)) for i in range(8)] - - @kernel - def run(self): - self.core.reset() - - for sawg in self.sawgs: - delay(1*ms) - sawg.amplitude1.set(.4) - # Do not use a sub-multiple of oscilloscope sample rates. - sawg.frequency0.set(9*MHz) - - while True: - delay(0.5*ms) - self.ttl_sma_out.pulse(0.5*ms) diff --git a/artiq/examples/sayma_standalone/repository/test_ad9154_status.py b/artiq/examples/sayma_standalone/repository/test_ad9154_status.py deleted file mode 100644 index fccebd615..000000000 --- a/artiq/examples/sayma_standalone/repository/test_ad9154_status.py +++ /dev/null @@ -1,145 +0,0 @@ -from artiq.coredevice.ad9154_reg import * -from artiq.experiment import * - - -class Test(EnvExperiment): - def build(self): - self.setattr_device("core") - self.ad9154_spi = self.get_device("ad9154_spi0") - - @kernel - def run(self): - self.ad9154_spi.setup_bus() - self.print_prodid() - self.print_status() - self.print_temp() - - def p(self, f, *a): - print(f % a) - - @kernel - def print_prodid(self): - self.p("PRODID: 0x%04x", (self.ad9154_spi.read(AD9154_PRODIDH) << 8) | - self.ad9154_spi.read(AD9154_PRODIDL)) - - @kernel - def print_temp(self): - self.ad9154_spi.write(AD9154_DIE_TEMP_CTRL0, AD9154_AUXADC_RESERVED_SET(0x10) | - AD9154_AUXADC_ENABLE_SET(1)) - self.ad9154_spi.write(AD9154_DIE_TEMP_UPDATE, 1) - self.p("temp_code %d", self.ad9154_spi.read(AD9154_DIE_TEMP0) | - (self.ad9154_spi.read(AD9154_DIE_TEMP1) << 8)) - self.ad9154_spi.write(AD9154_DIE_TEMP_CTRL0, AD9154_AUXADC_RESERVED_SET(0x10) | - AD9154_AUXADC_ENABLE_SET(0)) - - @kernel - def print_status(self): - x = self.ad9154_spi.read(AD9154_IRQ_STATUS0) - self.p("LANEFIFOERR: %d, SERPLLLOCK: %d, SERPLLLOST: %d, " - "DACPLLLOCK: %d, DACPLLLOST: %d", - AD9154_LANEFIFOERR_GET(x), AD9154_SERPLLLOCK_GET(x), - AD9154_SERPLLLOST_GET(x), AD9154_DACPLLLOCK_GET(x), - AD9154_DACPLLLOST_GET(x)) - x = self.ad9154_spi.read(AD9154_IRQ_STATUS1) - self.p("PRBS0: %d, PRBS1: %d, PRBS2: %d, PRBS3: %d", - AD9154_PRBS0_GET(x), AD9154_PRBS1_GET(x), - AD9154_PRBS2_GET(x), AD9154_PRBS3_GET(x)) - x = self.ad9154_spi.read(AD9154_IRQ_STATUS2) - self.p("SYNC_TRIP0: %d, SYNC_WLIM0: %d, SYNC_ROTATE0: %d, " - "SYNC_LOCK0: %d, NCO_ALIGN0: %d, BLNKDONE0: %d, " - "PDPERR0: %d", - AD9154_SYNC_TRIP0_GET(x), AD9154_SYNC_WLIM0_GET(x), - AD9154_SYNC_ROTATE0_GET(x), AD9154_SYNC_LOCK0_GET(x), - AD9154_NCO_ALIGN0_GET(x), AD9154_BLNKDONE0_GET(x), - AD9154_PDPERR0_GET(x)) - x = self.ad9154_spi.read(AD9154_IRQ_STATUS3) - self.p("SYNC_TRIP1: %d, SYNC_WLIM1: %d, SYNC_ROTATE1: %d, " - "SYNC_LOCK1: %d, NCO_ALIGN1: %d, BLNKDONE1: %d, " - "PDPERR1: %d", - AD9154_SYNC_TRIP1_GET(x), AD9154_SYNC_WLIM1_GET(x), - AD9154_SYNC_ROTATE1_GET(x), AD9154_SYNC_LOCK1_GET(x), - AD9154_NCO_ALIGN1_GET(x), AD9154_BLNKDONE1_GET(x), - AD9154_PDPERR1_GET(x)) - x = self.ad9154_spi.read(AD9154_JESD_CHECKS) - self.p("ERR_INTSUPP: %d, ERR_SUBCLASS: %d, ERR_KUNSUPP: %d, " - "ERR_JESDBAD: %d, ERR_WINLIMIT: %d, ERR_DLYOVER: %d", - AD9154_ERR_INTSUPP_GET(x), AD9154_ERR_SUBCLASS_GET(x), - AD9154_ERR_KUNSUPP_GET(x), AD9154_ERR_JESDBAD_GET(x), - AD9154_ERR_WINLIMIT_GET(x), AD9154_ERR_DLYOVER_GET(x)) - - x = self.ad9154_spi.read(AD9154_DACPLLSTATUS) - self.p("DACPLL_LOCK: %d, VCO_CAL_PROGRESS: %d, CP_CAL_VALID: %d, " - "CP_OVERRANGE_L: %d, CP_OVERRANGE_H: %d", - AD9154_DACPLL_LOCK_GET(x), AD9154_VCO_CAL_PROGRESS_GET(x), - AD9154_CP_CAL_VALID_GET(x), AD9154_CP_OVERRANGE_L_GET(x), - AD9154_CP_OVERRANGE_H_GET(x)) - - x = self.ad9154_spi.read(AD9154_PLL_STATUS) - self.p("PLL_LOCK_RB: %d, CURRENTS_READY_RB: %d, " - "VCO_CAL_IN_PROGRESS_RB: %d, PLL_CAL_VALID_RB: %d, " - "PLL_OVERRANGE_L_RB: %d, PLL_OVERRANGE_H_RB: %d", - AD9154_SERDES_PLL_LOCK_RB_GET(x), - AD9154_SERDES_CURRENTS_READY_RB_GET(x), - AD9154_SERDES_VCO_CAL_IN_PROGRESS_RB_GET(x), - AD9154_SERDES_PLL_CAL_VALID_RB_GET(x), - AD9154_SERDES_PLL_OVERRANGE_L_RB_GET(x), - AD9154_SERDES_PLL_OVERRANGE_H_RB_GET(x)) - - self.p("CODEGRPSYNC: 0x%02x", self.ad9154_spi.read(AD9154_CODEGRPSYNCFLG)) - self.p("FRAMESYNC: 0x%02x", self.ad9154_spi.read(AD9154_FRAMESYNCFLG)) - self.p("GOODCHECKSUM: 0x%02x", self.ad9154_spi.read(AD9154_GOODCHKSUMFLG)) - self.p("INITIALLANESYNC: 0x%02x", self.ad9154_spi.read(AD9154_INITLANESYNCFLG)) - - x = self.ad9154_spi.read(AD9154_SYNC_CURRERR_H) - self.p("SYNC_CURRERR: 0x%04x", self.ad9154_spi.read(AD9154_SYNC_CURRERR_L) | - (AD9154_CURRERROR_H_GET(x) << 8)) - self.p("SYNC_CURROVER: %d, SYNC_CURRUNDER: %d", - AD9154_CURROVER_GET(x), AD9154_CURRUNDER_GET(x)) - x = self.ad9154_spi.read(AD9154_SYNC_LASTERR_H) - self.p("SYNC_LASTERR: 0x%04x", self.ad9154_spi.read(AD9154_SYNC_LASTERR_L) | - (AD9154_LASTERROR_H_GET(x) << 8)) - self.p("SYNC_LASTOVER: %d, SYNC_LASTUNDER: %d", - AD9154_LASTOVER_GET(x), AD9154_LASTUNDER_GET(x)) - x = self.ad9154_spi.read(AD9154_SYNC_STATUS) - self.p("SYNC_TRIP: %d, SYNC_WLIM: %d, SYNC_ROTATE: %d, " - "SYNC_LOCK: %d, SYNC_BUSY: %d", - AD9154_SYNC_TRIP_GET(x), AD9154_SYNC_WLIM_GET(x), - AD9154_SYNC_ROTATE_GET(x), AD9154_SYNC_LOCK_GET(x), - AD9154_SYNC_BUSY_GET(x)) - - self.p("LANE_FIFO_FULL: 0x%02x", self.ad9154_spi.read(AD9154_FIFO_STATUS_REG_0)) - self.p("LANE_FIFO_EMPTY: 0x%02x", self.ad9154_spi.read(AD9154_FIFO_STATUS_REG_1)) - self.p("DID_REG: 0x%02x", self.ad9154_spi.read(AD9154_DID_REG)) - self.p("BID_REG: 0x%02x", self.ad9154_spi.read(AD9154_BID_REG)) - self.p("SCR_L_REG: 0x%02x", self.ad9154_spi.read(AD9154_SCR_L_REG)) - self.p("F_REG: 0x%02x", self.ad9154_spi.read(AD9154_F_REG)) - self.p("K_REG: 0x%02x", self.ad9154_spi.read(AD9154_K_REG)) - self.p("M_REG: 0x%02x", self.ad9154_spi.read(AD9154_M_REG)) - self.p("CS_N_REG: 0x%02x", self.ad9154_spi.read(AD9154_CS_N_REG)) - self.p("NP_REG: 0x%02x", self.ad9154_spi.read(AD9154_NP_REG)) - self.p("S_REG: 0x%02x", self.ad9154_spi.read(AD9154_S_REG)) - self.p("HD_CF_REG: 0x%02x", self.ad9154_spi.read(AD9154_HD_CF_REG)) - self.p("RES1_REG: 0x%02x", self.ad9154_spi.read(AD9154_RES1_REG)) - self.p("RES2_REG: 0x%02x", self.ad9154_spi.read(AD9154_RES2_REG)) - self.p("LIDx_REG: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", - self.ad9154_spi.read(AD9154_LID0_REG), self.ad9154_spi.read(AD9154_LID1_REG), - self.ad9154_spi.read(AD9154_LID2_REG), self.ad9154_spi.read(AD9154_LID3_REG), - self.ad9154_spi.read(AD9154_LID4_REG), self.ad9154_spi.read(AD9154_LID5_REG), - self.ad9154_spi.read(AD9154_LID6_REG), self.ad9154_spi.read(AD9154_LID7_REG)) - self.p("CHECKSUMx_REG: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", - self.ad9154_spi.read(AD9154_CHECKSUM0_REG), self.ad9154_spi.read(AD9154_CHECKSUM1_REG), - self.ad9154_spi.read(AD9154_CHECKSUM2_REG), self.ad9154_spi.read(AD9154_CHECKSUM3_REG), - self.ad9154_spi.read(AD9154_CHECKSUM4_REG), self.ad9154_spi.read(AD9154_CHECKSUM5_REG), - self.ad9154_spi.read(AD9154_CHECKSUM6_REG), self.ad9154_spi.read(AD9154_CHECKSUM7_REG)) - self.p("COMPSUMx_REG: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x", - self.ad9154_spi.read(AD9154_COMPSUM0_REG), self.ad9154_spi.read(AD9154_COMPSUM1_REG), - self.ad9154_spi.read(AD9154_COMPSUM2_REG), self.ad9154_spi.read(AD9154_COMPSUM3_REG), - self.ad9154_spi.read(AD9154_COMPSUM4_REG), self.ad9154_spi.read(AD9154_COMPSUM5_REG), - self.ad9154_spi.read(AD9154_COMPSUM6_REG), self.ad9154_spi.read(AD9154_COMPSUM7_REG)) - self.p("BADDISPARITY: 0x%02x", self.ad9154_spi.read(AD9154_BADDISPARITY)) - self.p("NITDISPARITY: 0x%02x", self.ad9154_spi.read(AD9154_NIT_W)) - self.p("UNEXPECTEDCONTROL: 0x%02x", self.ad9154_spi.read(AD9154_UNEXPECTEDCONTROL_W)) - self.p("DYN_LINK_LATENCY_0: 0x%02x", - self.ad9154_spi.read(AD9154_DYN_LINK_LATENCY_0)) - self.p("DYN_LINK_LATENCY_1: 0x%02x", - self.ad9154_spi.read(AD9154_DYN_LINK_LATENCY_1)) From bc060b7f01429dd0ed2e2866dd617fb3e9353c84 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 16 Oct 2019 18:18:11 +0800 Subject: [PATCH 1944/2457] style --- artiq/gateware/rtio/phy/ttl_serdes_generic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_generic.py b/artiq/gateware/rtio/phy/ttl_serdes_generic.py index 72d3175f3..e770052c6 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_generic.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_generic.py @@ -67,8 +67,8 @@ class InOut(Module): override_oe = Signal() self.overrides = [override_en, override_o, override_oe] - #: LSB of the input state (for edge detection; arbitrary choice, support for - #: short pulses will need a more involved solution). + # LSB of the input state (for edge detection; arbitrary choice, support for + # short pulses will need a more involved solution). self.input_state = Signal() # # # From 37d0a5dc19bde90c5521c13cc942a138f270fb8b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 16 Oct 2019 18:48:20 +0800 Subject: [PATCH 1945/2457] rtio/ttl: expose OE --- artiq/gateware/rtio/phy/ttl_serdes_generic.py | 8 ++++++-- artiq/gateware/rtio/phy/ttl_simple.py | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_generic.py b/artiq/gateware/rtio/phy/ttl_serdes_generic.py index e770052c6..5e03297fa 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_generic.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_generic.py @@ -67,6 +67,8 @@ class InOut(Module): override_oe = Signal() self.overrides = [override_en, override_o, override_oe] + # Output enable, for interfacing to external buffers. + self.oe = Signal() # LSB of the input state (for edge detection; arbitrary choice, support for # short pulses will need a more involved solution). self.input_state = Signal() @@ -82,15 +84,17 @@ class InOut(Module): override_en=override_en, override_o=override_o) oe_k = Signal() + self.oe.attr.add("no_retiming") self.sync.rio_phy += [ If(self.rtlink.o.stb & (self.rtlink.o.address == 1), oe_k.eq(self.rtlink.o.data[0])), If(override_en, - serdes.oe.eq(override_oe) + self.oe.eq(override_oe) ).Else( - serdes.oe.eq(oe_k) + self.oe.eq(oe_k) ) ] + self.comb += serdes.oe.eq(self.oe) # Input sensitivity = Signal(2) diff --git a/artiq/gateware/rtio/phy/ttl_simple.py b/artiq/gateware/rtio/phy/ttl_simple.py index aef84cb69..4484ce3af 100644 --- a/artiq/gateware/rtio/phy/ttl_simple.py +++ b/artiq/gateware/rtio/phy/ttl_simple.py @@ -90,6 +90,8 @@ class InOut(Module): self.overrides = [override_en, override_o, override_oe] self.probes = [] + # Output enable, for interfacing to external buffers. + self.oe = Signal() # Registered copy of the input state, in the rio_phy clock domain. self.input_state = Signal() @@ -101,6 +103,7 @@ class InOut(Module): o_k = Signal() oe_k = Signal() + self.oe.attr.add("no_retiming") self.sync.rio_phy += [ If(self.rtlink.o.stb, If(self.rtlink.o.address == 0, o_k.eq(self.rtlink.o.data[0])), @@ -108,12 +111,13 @@ class InOut(Module): ), If(override_en, ts.o.eq(override_o), - ts.oe.eq(override_oe) + self.oe.eq(override_oe) ).Else( ts.o.eq(o_k), - ts.oe.eq(oe_k) + self.oe.eq(oe_k) ) ] + self.comb += ts.oe.eq(self.oe) sample = Signal() self.sync.rio += [ sample.eq(0), From 8fa3c6460e12cffcb3f38ab734cd921288103400 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 16 Oct 2019 18:48:42 +0800 Subject: [PATCH 1946/2457] sayma_amc: set direction of external TTL buffer according to RTIO PHY OE --- artiq/gateware/targets/sayma_amc.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 44300653d..96e12faf3 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -248,13 +248,13 @@ class Satellite(SatelliteBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) mcx_io = platform.request("mcx_io", 0) - self.comb += mcx_io.direction.eq(1) - phy = ttl_serdes_ultrascale.Output(4, mcx_io.level) + phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) + self.comb += mcx_io.direction.eq(phy.oe) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) mcx_io = platform.request("mcx_io", 1) - self.comb += mcx_io.direction.eq(0) phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) + self.comb += mcx_io.direction.eq(phy.oe) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) @@ -306,13 +306,13 @@ class SimpleSatellite(SatelliteBase): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) mcx_io = platform.request("mcx_io", 0) - self.comb += mcx_io.direction.eq(1) - phy = ttl_serdes_ultrascale.Output(4, mcx_io.level) + phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) + self.comb += mcx_io.direction.eq(phy.oe) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) mcx_io = platform.request("mcx_io", 1) - self.comb += mcx_io.direction.eq(0) phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) + self.comb += mcx_io.direction.eq(phy.oe) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) @@ -424,13 +424,13 @@ class Master(MiniSoC, AMPSoC): self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) mcx_io = platform.request("mcx_io", 0) - self.comb += mcx_io.direction.eq(1) - phy = ttl_serdes_ultrascale.Output(4, mcx_io.level) + phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) + self.comb += mcx_io.direction.eq(phy.oe) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) mcx_io = platform.request("mcx_io", 1) - self.comb += mcx_io.direction.eq(0) phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) + self.comb += mcx_io.direction.eq(phy.oe) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From d42ff8114443ef9d0b30aa6f1934f6f294fb015e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 16 Oct 2019 18:49:25 +0800 Subject: [PATCH 1947/2457] examples/sayma_master: update device_db --- artiq/examples/sayma_master/device_db.py | 40 +++++++++++++++--------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/artiq/examples/sayma_master/device_db.py b/artiq/examples/sayma_master/device_db.py index e3a4e00fe..51eede704 100644 --- a/artiq/examples/sayma_master/device_db.py +++ b/artiq/examples/sayma_master/device_db.py @@ -23,44 +23,54 @@ device_db = { "module": "artiq.coredevice.dma", "class": "CoreDMA" }, +} - "fmcdio_dirctl_clk": { +for i in range(4): + device_db["led" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": i}, + } + + +for i in range(2): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": 4 + i}, + } + + +device_db.update( + fmcdio_dirctl_clk={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 6} }, - "fmcdio_dirctl_ser": { + fmcdio_dirctl_ser={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 7} }, - "fmcdio_dirctl_latch": { + fmcdio_dirctl_latch={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", "arguments": {"channel": 8} }, - "fmcdio_dirctl": { + fmcdio_dirctl={ "type": "local", "module": "artiq.coredevice.shiftreg", "class": "ShiftReg", "arguments": {"clk": "fmcdio_dirctl_clk", "ser": "fmcdio_dirctl_ser", "latch": "fmcdio_dirctl_latch"} - }, -} - - -for i in range(8): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLOut", - "arguments": {"channel": 9+i}, } - +) device_db.update( spi_urukul0={ From a8f85860c464422d3399c4c050b8ababb9fcf2f0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 17 Oct 2019 07:29:33 +0800 Subject: [PATCH 1948/2457] coreanalyzer: AD9914 fixes (#1376) --- artiq/coredevice/comm_analyzer.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/comm_analyzer.py b/artiq/coredevice/comm_analyzer.py index be5902724..1958a4d0c 100644 --- a/artiq/coredevice/comm_analyzer.py +++ b/artiq/coredevice/comm_analyzer.py @@ -462,7 +462,7 @@ def get_ref_period(devices): def get_dds_sysclk(devices): return get_single_device_argument(devices, "artiq.coredevice.ad9914", - ("ad9914",), "sysclk") + ("AD9914",), "sysclk") def create_channel_handlers(vcd_manager, devices, ref_period, @@ -485,8 +485,7 @@ def create_channel_handlers(vcd_manager, devices, ref_period, if dds_bus_channel in channel_handlers: dds_handler = channel_handlers[dds_bus_channel] else: - dds_handler = DDSHandler(vcd_manager, desc["class"], - dds_onehot_sel, dds_sysclk) + dds_handler = DDSHandler(vcd_manager, dds_onehot_sel, dds_sysclk) channel_handlers[dds_bus_channel] = dds_handler dds_handler.add_dds_channel(name, dds_channel) if (desc["module"] == "artiq.coredevice.spi2" and From 62b49882b9b35f1c8585a805e202fd8784de9876 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 17 Oct 2019 07:37:00 +0800 Subject: [PATCH 1949/2457] examples/kc705: fix dds_test --- artiq/examples/kc705_nist_clock/repository/dds_test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/examples/kc705_nist_clock/repository/dds_test.py b/artiq/examples/kc705_nist_clock/repository/dds_test.py index 5f93b2bc1..dceb10438 100644 --- a/artiq/examples/kc705_nist_clock/repository/dds_test.py +++ b/artiq/examples/kc705_nist_clock/repository/dds_test.py @@ -6,9 +6,9 @@ class DDSTest(EnvExperiment): def build(self): self.setattr_device("core") - self.setattr_device("dds0") - self.setattr_device("dds1") - self.setattr_device("dds2") + self.dds0 = self.get_device("ad9914dds0") + self.dds1 = self.get_device("ad9914dds1") + self.dds2 = self.get_device("ad9914dds2") self.setattr_device("ttl0") self.setattr_device("ttl1") self.setattr_device("ttl2") From 05e8f24c24fd5cd8e19727b8d9617873a81d5896 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 18 Oct 2019 23:28:47 +0800 Subject: [PATCH 1950/2457] sayma2: JESD204 synchronization --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 8 +- artiq/firmware/libboard_artiq/jesd204sync.rs | 451 --------------- artiq/firmware/libboard_artiq/lib.rs | 2 - .../firmware/libproto_artiq/drtioaux_proto.rs | 14 +- artiq/firmware/satman/jdac_requests.rs | 4 + artiq/firmware/satman/jdcg.rs | 519 +++++++++++++++++- artiq/firmware/satman/main.rs | 35 +- 7 files changed, 542 insertions(+), 491 deletions(-) delete mode 100644 artiq/firmware/libboard_artiq/jesd204sync.rs diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 18cbb8794..f318ed698 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -139,14 +139,12 @@ mod hmc830 { pub mod hmc7043 { use board_misoc::{csr, clock}; - pub const ANALOG_DELAY_RANGE: u8 = 24; - // Warning: dividers are not synchronized with HMC830 clock input! // Set DAC_CLK_DIV to 1 or 0 for deterministic phase. // (0 bypasses the divider and reduces noise) - pub const DAC_CLK_DIV: u16 = 0; - pub const FPGA_CLK_DIV: u16 = 16; - pub const SYSREF_DIV: u16 = 256; + const DAC_CLK_DIV: u16 = 0; + const FPGA_CLK_DIV: u16 = 16; // Keep in sync with jdcg.rs + const SYSREF_DIV: u16 = 256; // Keep in sync with jdcg.rs const HMC_SYSREF_DIV: u16 = SYSREF_DIV*8; // must be <= 4MHz // enabled, divider, output config, is sysref diff --git a/artiq/firmware/libboard_artiq/jesd204sync.rs b/artiq/firmware/libboard_artiq/jesd204sync.rs deleted file mode 100644 index 3d7924374..000000000 --- a/artiq/firmware/libboard_artiq/jesd204sync.rs +++ /dev/null @@ -1,451 +0,0 @@ -use board_misoc::{csr, clock, config}; - -use hmc830_7043::hmc7043; -use ad9154; - -fn average_2phases(a: i32, b:i32, modulo: i32) -> i32 { - let diff = ((a - b + modulo/2 + modulo) % modulo) - modulo/2; - return (modulo + b + diff/2) % modulo; -} - -fn average_phases(phases: &[i32], modulo: i32) -> i32 { - if phases.len() == 1 { - panic!("input array length must be a power of 2"); - } else if phases.len() == 2 { - average_2phases(phases[0], phases[1], modulo) - } else { - let cut = phases.len()/2; - average_2phases( - average_phases(&phases[..cut], modulo), - average_phases(&phases[cut..], modulo), - modulo) - } -} - -const RAW_DDMTD_N_SHIFT: i32 = 6; -const RAW_DDMTD_N: i32 = 1 << RAW_DDMTD_N_SHIFT; -const DDMTD_DITHER_BITS: i32 = 1; -const DDMTD_N_SHIFT: i32 = RAW_DDMTD_N_SHIFT + DDMTD_DITHER_BITS; -const DDMTD_N: i32 = 1 << DDMTD_N_SHIFT; - -fn init_ddmtd() -> Result<(), &'static str> { - unsafe { - csr::sysref_ddmtd::reset_write(1); - clock::spin_us(1); - csr::sysref_ddmtd::reset_write(0); - clock::spin_us(100); - if csr::sysref_ddmtd::locked_read() != 0 { - Ok(()) - } else { - Err("DDMTD helper PLL failed to lock") - } - } -} - -fn measure_ddmdt_phase_raw() -> i32 { - unsafe { csr::sysref_ddmtd::dt_read() as i32 } -} - -fn measure_ddmdt_phase() -> i32 { - const AVG_PRECISION_SHIFT: i32 = 6; - const AVG_PRECISION: i32 = 1 << AVG_PRECISION_SHIFT; - const AVG_MOD: i32 = 1 << (RAW_DDMTD_N_SHIFT + AVG_PRECISION_SHIFT + DDMTD_DITHER_BITS); - - let mut measurements = [0; AVG_PRECISION as usize]; - for i in 0..AVG_PRECISION { - measurements[i as usize] = measure_ddmdt_phase_raw() << (AVG_PRECISION_SHIFT + DDMTD_DITHER_BITS); - clock::spin_us(10); - } - average_phases(&measurements, AVG_MOD) >> AVG_PRECISION_SHIFT -} - -fn test_ddmtd_stability(raw: bool, tolerance: i32) -> Result<(), &'static str> { - info!("testing DDMTD stability (raw={}, tolerance={})...", raw, tolerance); - - let modulo = if raw { RAW_DDMTD_N } else { DDMTD_N }; - let measurement = if raw { measure_ddmdt_phase_raw } else { measure_ddmdt_phase }; - let ntests = if raw { 15000 } else { 150 }; - - let mut max_pkpk = 0; - for _ in 0..32 { - // If we are near the edges, wraparound can throw off the simple min/max computation. - // In this case, add an offset to get near the center. - let quadrant = measure_ddmdt_phase(); - let center_offset = - if quadrant < DDMTD_N/4 || quadrant > 3*DDMTD_N/4 { - modulo/2 - } else { - 0 - }; - - let mut min = modulo; - let mut max = 0; - for _ in 0..ntests { - let m = (measurement() + center_offset) % modulo; - if m < min { - min = m; - } - if m > max { - max = m; - } - } - let pkpk = max - min; - if pkpk > max_pkpk { - max_pkpk = pkpk; - } - if pkpk > tolerance { - error!(" ...excessive peak-peak jitter: {} (min={} max={} center_offset={})", pkpk, - min, max, center_offset); - return Err("excessive DDMTD peak-peak jitter"); - } - hmc7043::sysref_slip(); - } - - info!(" ...passed, peak-peak jitter: {}", max_pkpk); - Ok(()) -} - -fn test_slip_ddmtd() -> Result<(), &'static str> { - // expected_step = (RTIO clock frequency)*(DDMTD N)/(HMC7043 CLKIN frequency) - let expected_step = 8; - let tolerance = 1; - - info!("testing HMC7043 SYSREF slip against DDMTD..."); - let mut old_phase = measure_ddmdt_phase(); - for _ in 0..1024 { - hmc7043::sysref_slip(); - let phase = measure_ddmdt_phase(); - let step = (DDMTD_N + old_phase - phase) % DDMTD_N; - if (step - expected_step).abs() > tolerance { - error!(" ...got unexpected step: {} ({} -> {})", step, old_phase, phase); - return Err("HMC7043 SYSREF slip produced unexpected DDMTD step"); - } - old_phase = phase; - } - info!(" ...passed"); - Ok(()) -} - -fn sysref_sh_error() -> bool { - unsafe { - csr::sysref_sampler::sh_error_reset_write(1); - clock::spin_us(1); - csr::sysref_sampler::sh_error_reset_write(0); - clock::spin_us(10); - csr::sysref_sampler::sh_error_read() != 0 - } -} - -const SYSREF_SH_PRECISION_SHIFT: i32 = 5; -const SYSREF_SH_PRECISION: i32 = 1 << SYSREF_SH_PRECISION_SHIFT; -const SYSREF_SH_MOD: i32 = 1 << (DDMTD_N_SHIFT + SYSREF_SH_PRECISION_SHIFT); - -#[derive(Default)] -struct SysrefShLimits { - rising_phases: [i32; SYSREF_SH_PRECISION as usize], - falling_phases: [i32; SYSREF_SH_PRECISION as usize], -} - -fn measure_sysref_sh_limits() -> Result { - let mut ret = SysrefShLimits::default(); - let mut nslips = 0; - let mut rising_n = 0; - let mut falling_n = 0; - - let mut previous = sysref_sh_error(); - while rising_n < SYSREF_SH_PRECISION || falling_n < SYSREF_SH_PRECISION { - hmc7043::sysref_slip(); - nslips += 1; - if nslips > 1024 { - return Err("too many slips and not enough SYSREF S/H error transitions"); - } - - let current = sysref_sh_error(); - let phase = measure_ddmdt_phase(); - if current && !previous && rising_n < SYSREF_SH_PRECISION { - ret.rising_phases[rising_n as usize] = phase << SYSREF_SH_PRECISION_SHIFT; - rising_n += 1; - } - if !current && previous && falling_n < SYSREF_SH_PRECISION { - ret.falling_phases[falling_n as usize] = phase << SYSREF_SH_PRECISION_SHIFT; - falling_n += 1; - } - previous = current; - } - Ok(ret) -} - -fn max_phase_deviation(average: i32, phases: &[i32]) -> i32 { - let mut ret = 0; - for phase in phases.iter() { - let deviation = (phase - average + DDMTD_N) % DDMTD_N; - if deviation > ret { - ret = deviation; - } - } - return ret; -} - -fn reach_sysref_ddmtd_target(target: i32, tolerance: i32) -> Result { - for _ in 0..1024 { - let delta = (measure_ddmdt_phase() - target + DDMTD_N) % DDMTD_N; - if delta <= tolerance { - return Ok(delta) - } - hmc7043::sysref_slip(); - } - Err("failed to reach SYSREF DDMTD phase target") -} - -fn calibrate_sysref_target(rising_average: i32, falling_average: i32) -> Result { - info!("calibrating SYSREF DDMTD target phase..."); - let coarse_target = - if rising_average < falling_average { - (rising_average + falling_average)/2 - } else { - ((falling_average - (DDMTD_N - rising_average))/2 + DDMTD_N) % DDMTD_N - }; - info!(" SYSREF calibration coarse target: {}", coarse_target); - reach_sysref_ddmtd_target(coarse_target, 8)?; - let target = measure_ddmdt_phase(); - info!(" ...done, target={}", target); - Ok(target) -} - -fn sysref_get_tsc_phase_raw() -> Result { - if sysref_sh_error() { - return Err("SYSREF failed S/H timing"); - } - let ret = unsafe { csr::sysref_sampler::sysref_phase_read() }; - Ok(ret) -} - -// Note: the code below assumes RTIO/SYSREF frequency ratio is a power of 2 - -fn sysref_get_tsc_phase() -> Result { - let mask = (hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV - 1) as u8; - Ok((sysref_get_tsc_phase_raw()? & mask) as i32) -} - -pub fn test_sysref_frequency() -> Result<(), &'static str> { - info!("testing SYSREF frequency against raw TSC phase bit toggles..."); - - let mut all_toggles = 0; - let initial_phase = sysref_get_tsc_phase_raw()?; - for _ in 0..20000 { - clock::spin_us(1); - all_toggles |= sysref_get_tsc_phase_raw()? ^ initial_phase; - } - - let ratio = (hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV) as u8; - let expected_toggles = 0xff ^ (ratio - 1); - if all_toggles == expected_toggles { - info!(" ...done (0x{:02x})", all_toggles); - Ok(()) - } else { - error!(" ...unexpected toggles: got 0x{:02x}, expected 0x{:02x}", - all_toggles, expected_toggles); - Err("unexpected toggles") - } -} - -fn sysref_slip_rtio_cycle() { - for _ in 0..hmc7043::FPGA_CLK_DIV { - hmc7043::sysref_slip(); - } -} - -pub fn test_slip_tsc() -> Result<(), &'static str> { - info!("testing HMC7043 SYSREF slip against TSC phase..."); - let initial_phase = sysref_get_tsc_phase()?; - let modulo = (hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV) as i32; - for i in 0..128 { - sysref_slip_rtio_cycle(); - let expected_phase = (initial_phase + i + 1) % modulo; - let phase = sysref_get_tsc_phase()?; - if phase != expected_phase { - error!(" ...unexpected TSC phase: got {}, expected {} ", phase, expected_phase); - return Err("HMC7043 SYSREF slip produced unexpected TSC phase"); - } - } - info!(" ...done"); - Ok(()) -} - -pub fn sysref_rtio_align() -> Result<(), &'static str> { - info!("aligning SYSREF with RTIO TSC..."); - let mut nslips = 0; - loop { - sysref_slip_rtio_cycle(); - if sysref_get_tsc_phase()? == 0 { - info!(" ...done"); - return Ok(()) - } - - nslips += 1; - if nslips > hmc7043::SYSREF_DIV/hmc7043::FPGA_CLK_DIV { - return Err("failed to find SYSREF transition aligned with RTIO TSC"); - } - } -} - -pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { - init_ddmtd()?; - test_ddmtd_stability(true, 4)?; - test_ddmtd_stability(false, 1)?; - test_slip_ddmtd()?; - - info!("determining SYSREF S/H limits..."); - let sysref_sh_limits = measure_sysref_sh_limits()?; - let rising_average = average_phases(&sysref_sh_limits.rising_phases, SYSREF_SH_MOD); - let falling_average = average_phases(&sysref_sh_limits.falling_phases, SYSREF_SH_MOD); - let rising_max_deviation = max_phase_deviation(rising_average, &sysref_sh_limits.rising_phases); - let falling_max_deviation = max_phase_deviation(falling_average, &sysref_sh_limits.falling_phases); - - let rising_average = rising_average >> SYSREF_SH_PRECISION_SHIFT; - let falling_average = falling_average >> SYSREF_SH_PRECISION_SHIFT; - let rising_max_deviation = rising_max_deviation >> SYSREF_SH_PRECISION_SHIFT; - let falling_max_deviation = falling_max_deviation >> SYSREF_SH_PRECISION_SHIFT; - - info!(" SYSREF S/H average limits (DDMTD phases): {} {}", rising_average, falling_average); - info!(" SYSREF S/H maximum limit deviation: {} {}", rising_max_deviation, falling_max_deviation); - if rising_max_deviation > 8 || falling_max_deviation > 8 { - return Err("excessive SYSREF S/H limit deviation"); - } - info!(" ...done"); - - let entry = config::read_str("sysref_ddmtd_phase_fpga", |r| r.map(|s| s.parse())); - let target_phase = match entry { - Ok(Ok(phase)) => { - info!("using FPGA SYSREF DDMTD phase target from config: {}", phase); - phase - } - _ => { - let phase = calibrate_sysref_target(rising_average, falling_average)?; - if let Err(e) = config::write_int("sysref_ddmtd_phase_fpga", phase as u32) { - error!("failed to update FPGA SYSREF DDMTD phase target in config: {}", e); - } - phase - } - }; - - info!("aligning SYSREF with RTIO clock..."); - let delta = reach_sysref_ddmtd_target(target_phase, 3)?; - if sysref_sh_error() { - return Err("SYSREF does not meet S/H timing at DDMTD phase target"); - } - info!(" ...done, delta={}", delta); - - test_sysref_frequency()?; - test_slip_tsc()?; - sysref_rtio_align()?; - - Ok(()) -} - -fn sysref_cal_dac(dacno: u8) -> Result { - info!("calibrating SYSREF delay at DAC-{}...", dacno); - - // Allocate for more than expected as jitter may create spurious entries. - let mut limits_buf = [0; 8]; - let mut n_limits = 0; - - limits_buf[n_limits] = -1; - n_limits += 1; - - // avoid spurious rotation at delay=0 - hmc7043::sysref_delay_dac(dacno, 0); - ad9154::dac_sync(dacno)?; - - for scan_delay in 0..hmc7043::ANALOG_DELAY_RANGE { - hmc7043::sysref_delay_dac(dacno, scan_delay); - if ad9154::dac_sync(dacno)? { - limits_buf[n_limits] = scan_delay as i16; - n_limits += 1; - if n_limits >= limits_buf.len() - 1 { - break; - } - } - } - - limits_buf[n_limits] = hmc7043::ANALOG_DELAY_RANGE as i16; - n_limits += 1; - - info!(" using limits: {:?}", &limits_buf[..n_limits]); - - let mut delay = 0; - let mut best_margin = 0; - - for i in 0..(n_limits-1) { - let margin = limits_buf[i+1] - limits_buf[i]; - if margin > best_margin { - best_margin = margin; - delay = ((limits_buf[i+1] + limits_buf[i])/2) as u8; - } - } - - info!(" ...done, delay={}", delay); - Ok(delay) -} - -fn sysref_dac_align(dacno: u8, delay: u8) -> Result<(), &'static str> { - let tolerance = 5; - - info!("verifying SYSREF margins at DAC-{}...", dacno); - - // avoid spurious rotation at delay=0 - hmc7043::sysref_delay_dac(dacno, 0); - ad9154::dac_sync(dacno)?; - - let mut rotation_seen = false; - for scan_delay in 0..hmc7043::ANALOG_DELAY_RANGE { - hmc7043::sysref_delay_dac(dacno, scan_delay); - if ad9154::dac_sync(dacno)? { - rotation_seen = true; - let distance = (scan_delay as i16 - delay as i16).abs(); - if distance < tolerance { - error!(" rotation at delay={} is {} delay steps from target (FAIL)", scan_delay, distance); - return Err("insufficient SYSREF margin at DAC"); - } else { - info!(" rotation at delay={} is {} delay steps from target (PASS)", scan_delay, distance); - } - } - } - - if !rotation_seen { - return Err("no rotation seen when scanning DAC SYSREF delay"); - } - - info!(" ...done"); - - // We tested that the value is correct - now use it - hmc7043::sysref_delay_dac(dacno, delay); - ad9154::dac_sync(dacno)?; - - Ok(()) -} - -pub fn sysref_auto_dac_align() -> Result<(), &'static str> { - // We assume that DAC SYSREF traces are length-matched so only one delay - // value is needed, and we use DAC-0 as calibration reference. - - let entry = config::read_str("sysref_7043_delay_dac", |r| r.map(|s| s.parse())); - let delay = match entry { - Ok(Ok(delay)) => { - info!("using DAC SYSREF delay from config: {}", delay); - delay - }, - _ => { - let delay = sysref_cal_dac(0)?; - if let Err(e) = config::write_int("sysref_7043_delay_dac", delay as u32) { - error!("failed to update DAC SYSREF delay in config: {}", e); - } - delay - } - }; - - for dacno in 0..csr::AD9154.len() { - sysref_dac_align(dacno as u8, delay)?; - } - Ok(()) -} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 9a1007588..ce0757427 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -40,8 +40,6 @@ pub mod hmc830_7043; mod ad9154_reg; #[cfg(has_ad9154)] pub mod ad9154; -/* TODO: #[cfg(has_jdcg)] -pub mod jesd204sync; */ #[cfg(has_allaki_atts)] pub mod hmc542; diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 6b93d7167..bd4875655 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -54,8 +54,8 @@ pub enum Packet { SpiReadReply { succeeded: bool, data: u32 }, SpiBasicReply { succeeded: bool }, - JdacBasicRequest { destination: u8, dacno: u8, reqno: u8 }, - JdacBasicReply { succeeded: bool }, + JdacBasicRequest { destination: u8, dacno: u8, reqno: u8, param: u8 }, + JdacBasicReply { succeeded: bool, retval: u8 }, } impl Packet { @@ -185,9 +185,11 @@ impl Packet { destination: reader.read_u8()?, dacno: reader.read_u8()?, reqno: reader.read_u8()?, + param: reader.read_u8()?, }, 0xa1 => Packet::JdacBasicReply { - succeeded: reader.read_bool()? + succeeded: reader.read_bool()?, + retval: reader.read_u8()? }, ty => return Err(Error::UnknownPacket(ty)) @@ -342,15 +344,17 @@ impl Packet { writer.write_bool(succeeded)?; }, - Packet::JdacBasicRequest { destination, dacno, reqno } => { + Packet::JdacBasicRequest { destination, dacno, reqno, param } => { writer.write_u8(0xa0)?; writer.write_u8(destination)?; writer.write_u8(dacno)?; writer.write_u8(reqno)?; + writer.write_u8(param)?; } - Packet::JdacBasicReply { succeeded } => { + Packet::JdacBasicReply { succeeded, retval } => { writer.write_u8(0xa1)?; writer.write_bool(succeeded)?; + writer.write_u8(retval)?; }, } Ok(()) diff --git a/artiq/firmware/satman/jdac_requests.rs b/artiq/firmware/satman/jdac_requests.rs index 2ba120ebb..0df8335bd 100644 --- a/artiq/firmware/satman/jdac_requests.rs +++ b/artiq/firmware/satman/jdac_requests.rs @@ -2,3 +2,7 @@ pub const INIT: u8 = 0x00; pub const PRINT_STATUS: u8 = 0x01; pub const PRBS: u8 = 0x02; pub const STPL: u8 = 0x03; + +pub const SYSREF_DELAY_DAC: u8 = 0x10; +pub const SYSREF_SLIP: u8 = 0x11; +pub const SYNC: u8 = 0x12; diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs index a4ae234db..38e5bf866 100644 --- a/artiq/firmware/satman/jdcg.rs +++ b/artiq/firmware/satman/jdcg.rs @@ -48,25 +48,37 @@ pub mod jdac { use super::jesd; use super::super::jdac_requests; - pub fn basic_request(dacno: u8, reqno: u8) { + pub fn basic_request(dacno: u8, reqno: u8, param: u8) -> Result { if let Err(e) = drtioaux::send(1, &drtioaux::Packet::JdacBasicRequest { destination: 0, dacno: dacno, - reqno: reqno + reqno: reqno, + param: param }) { error!("aux packet error ({})", e); + return Err("aux packet error while sending for JESD DAC basic request"); } match drtioaux::recv_timeout(1, Some(1000)) { - Ok(drtioaux::Packet::JdacBasicReply { succeeded }) => - if !succeeded { + Ok(drtioaux::Packet::JdacBasicReply { succeeded, retval }) => { + if succeeded { + Ok(retval) + } else { error!("JESD DAC basic request failed (dacno={}, reqno={})", dacno, reqno); - }, - Ok(packet) => error!("received unexpected aux packet: {:?}", packet), - Err(e) => error!("aux packet error ({})", e), + Err("remote error status to JESD DAC basic request") + } + }, + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); + Err("unexpected aux packet in reply to JESD DAC basic request") + }, + Err(e) => { + error!("aux packet error ({})", e); + Err("aux packet error while waiting for JESD DAC basic reply") + } } } - pub fn init() { + pub fn init() -> Result<(), &'static str> { for dacno in 0..csr::JDCG.len() { let dacno = dacno as u8; info!("DAC-{} initializing...", dacno); @@ -75,40 +87,513 @@ pub mod jdac { clock::spin_us(10); if !jesd::ready(dacno) { error!("JESD core reported not ready"); + return Err("JESD core reported not ready"); } - basic_request(dacno, jdac_requests::INIT); + basic_request(dacno, jdac_requests::INIT, 0)?; jesd::prbs(dacno, true); - basic_request(dacno, jdac_requests::PRBS); + basic_request(dacno, jdac_requests::PRBS, 0)?; jesd::prbs(dacno, false); jesd::stpl(dacno, true); - basic_request(dacno, jdac_requests::STPL); + basic_request(dacno, jdac_requests::STPL, 0)?; jesd::stpl(dacno, false); - basic_request(dacno, jdac_requests::INIT); + basic_request(dacno, jdac_requests::INIT, 0)?; clock::spin_us(5000); - basic_request(dacno, jdac_requests::PRINT_STATUS); + basic_request(dacno, jdac_requests::PRINT_STATUS, 0)?; if !jesd::jsync(dacno) { error!("JESD core reported bad SYNC"); + return Err("JESD core reported bad SYNC"); } info!(" ...done"); } + Ok(()) } } pub mod jesd204sync { - fn sysref_auto_rtio_align() -> Result<(), &'static str> { - info!("TODO: sysref_auto_rtio_align"); + use board_misoc::{csr, clock, config}; + + use super::jdac; + use super::super::jdac_requests; + + const HMC7043_ANALOG_DELAY_RANGE: u8 = 24; + + const FPGA_CLK_DIV: u16 = 16; // Keep in sync with hmc830_7043.rs + const SYSREF_DIV: u16 = 256; // Keep in sync with hmc830_7043.rs + + fn hmc7043_sysref_delay_dac(dacno: u8, phase_offset: u8) -> Result<(), &'static str> { + match jdac::basic_request(dacno, jdac_requests::SYSREF_DELAY_DAC, phase_offset) { + Ok(_) => Ok(()), + Err(e) => Err(e) + } + } + + + fn hmc7043_sysref_slip() -> Result<(), &'static str> { + match jdac::basic_request(0, jdac_requests::SYSREF_SLIP, 0) { + Ok(_) => Ok(()), + Err(e) => Err(e) + } + } + + fn ad9154_sync(dacno: u8) -> Result { + match jdac::basic_request(dacno, jdac_requests::SYNC, 0) { + Ok(0) => Ok(false), + Ok(_) => Ok(true), + Err(e) => Err(e) + } + } + + fn average_2phases(a: i32, b: i32, modulo: i32) -> i32 { + let diff = ((a - b + modulo/2 + modulo) % modulo) - modulo/2; + return (modulo + b + diff/2) % modulo; + } + + fn average_phases(phases: &[i32], modulo: i32) -> i32 { + if phases.len() == 1 { + panic!("input array length must be a power of 2"); + } else if phases.len() == 2 { + average_2phases(phases[0], phases[1], modulo) + } else { + let cut = phases.len()/2; + average_2phases( + average_phases(&phases[..cut], modulo), + average_phases(&phases[cut..], modulo), + modulo) + } + } + + const RAW_DDMTD_N_SHIFT: i32 = 6; + const RAW_DDMTD_N: i32 = 1 << RAW_DDMTD_N_SHIFT; + const DDMTD_DITHER_BITS: i32 = 1; + const DDMTD_N_SHIFT: i32 = RAW_DDMTD_N_SHIFT + DDMTD_DITHER_BITS; + const DDMTD_N: i32 = 1 << DDMTD_N_SHIFT; + + fn init_ddmtd() -> Result<(), &'static str> { + unsafe { + csr::sysref_ddmtd::reset_write(1); + clock::spin_us(1); + csr::sysref_ddmtd::reset_write(0); + clock::spin_us(100); + if csr::sysref_ddmtd::locked_read() != 0 { + Ok(()) + } else { + Err("DDMTD helper PLL failed to lock") + } + } + } + + fn measure_ddmdt_phase_raw() -> i32 { + unsafe { csr::sysref_ddmtd::dt_read() as i32 } + } + + fn measure_ddmdt_phase() -> i32 { + const AVG_PRECISION_SHIFT: i32 = 6; + const AVG_PRECISION: i32 = 1 << AVG_PRECISION_SHIFT; + const AVG_MOD: i32 = 1 << (RAW_DDMTD_N_SHIFT + AVG_PRECISION_SHIFT + DDMTD_DITHER_BITS); + + let mut measurements = [0; AVG_PRECISION as usize]; + for i in 0..AVG_PRECISION { + measurements[i as usize] = measure_ddmdt_phase_raw() << (AVG_PRECISION_SHIFT + DDMTD_DITHER_BITS); + clock::spin_us(10); + } + average_phases(&measurements, AVG_MOD) >> AVG_PRECISION_SHIFT + } + + fn test_ddmtd_stability(raw: bool, tolerance: i32) -> Result<(), &'static str> { + info!("testing DDMTD stability (raw={}, tolerance={})...", raw, tolerance); + + let modulo = if raw { RAW_DDMTD_N } else { DDMTD_N }; + let measurement = if raw { measure_ddmdt_phase_raw } else { measure_ddmdt_phase }; + let ntests = if raw { 15000 } else { 150 }; + + let mut max_pkpk = 0; + for _ in 0..32 { + // If we are near the edges, wraparound can throw off the simple min/max computation. + // In this case, add an offset to get near the center. + let quadrant = measure_ddmdt_phase(); + let center_offset = + if quadrant < DDMTD_N/4 || quadrant > 3*DDMTD_N/4 { + modulo/2 + } else { + 0 + }; + + let mut min = modulo; + let mut max = 0; + for _ in 0..ntests { + let m = (measurement() + center_offset) % modulo; + if m < min { + min = m; + } + if m > max { + max = m; + } + } + let pkpk = max - min; + if pkpk > max_pkpk { + max_pkpk = pkpk; + } + if pkpk > tolerance { + error!(" ...excessive peak-peak jitter: {} (min={} max={} center_offset={})", pkpk, + min, max, center_offset); + return Err("excessive DDMTD peak-peak jitter"); + } + hmc7043_sysref_slip(); + } + + info!(" ...passed, peak-peak jitter: {}", max_pkpk); Ok(()) } - fn sysref_auto_dac_align() -> Result<(), &'static str> { - info!("TODO: sysref_auto_dac_align"); + fn test_slip_ddmtd() -> Result<(), &'static str> { + // expected_step = (RTIO clock frequency)*(DDMTD N)/(HMC7043 CLKIN frequency) + let expected_step = 8; + let tolerance = 1; + + info!("testing HMC7043 SYSREF slip against DDMTD..."); + let mut old_phase = measure_ddmdt_phase(); + for _ in 0..1024 { + hmc7043_sysref_slip(); + let phase = measure_ddmdt_phase(); + let step = (DDMTD_N + old_phase - phase) % DDMTD_N; + if (step - expected_step).abs() > tolerance { + error!(" ...got unexpected step: {} ({} -> {})", step, old_phase, phase); + return Err("HMC7043 SYSREF slip produced unexpected DDMTD step"); + } + old_phase = phase; + } + info!(" ...passed"); + Ok(()) + } + + fn sysref_sh_error() -> bool { + unsafe { + csr::sysref_sampler::sh_error_reset_write(1); + clock::spin_us(1); + csr::sysref_sampler::sh_error_reset_write(0); + clock::spin_us(10); + csr::sysref_sampler::sh_error_read() != 0 + } + } + + const SYSREF_SH_PRECISION_SHIFT: i32 = 5; + const SYSREF_SH_PRECISION: i32 = 1 << SYSREF_SH_PRECISION_SHIFT; + const SYSREF_SH_MOD: i32 = 1 << (DDMTD_N_SHIFT + SYSREF_SH_PRECISION_SHIFT); + + #[derive(Default)] + struct SysrefShLimits { + rising_phases: [i32; SYSREF_SH_PRECISION as usize], + falling_phases: [i32; SYSREF_SH_PRECISION as usize], + } + + fn measure_sysref_sh_limits() -> Result { + let mut ret = SysrefShLimits::default(); + let mut nslips = 0; + let mut rising_n = 0; + let mut falling_n = 0; + + let mut previous = sysref_sh_error(); + while rising_n < SYSREF_SH_PRECISION || falling_n < SYSREF_SH_PRECISION { + hmc7043_sysref_slip(); + nslips += 1; + if nslips > 1024 { + return Err("too many slips and not enough SYSREF S/H error transitions"); + } + + let current = sysref_sh_error(); + let phase = measure_ddmdt_phase(); + if current && !previous && rising_n < SYSREF_SH_PRECISION { + ret.rising_phases[rising_n as usize] = phase << SYSREF_SH_PRECISION_SHIFT; + rising_n += 1; + } + if !current && previous && falling_n < SYSREF_SH_PRECISION { + ret.falling_phases[falling_n as usize] = phase << SYSREF_SH_PRECISION_SHIFT; + falling_n += 1; + } + previous = current; + } + Ok(ret) + } + + fn max_phase_deviation(average: i32, phases: &[i32]) -> i32 { + let mut ret = 0; + for phase in phases.iter() { + let deviation = (phase - average + DDMTD_N) % DDMTD_N; + if deviation > ret { + ret = deviation; + } + } + return ret; + } + + fn reach_sysref_ddmtd_target(target: i32, tolerance: i32) -> Result { + for _ in 0..1024 { + let delta = (measure_ddmdt_phase() - target + DDMTD_N) % DDMTD_N; + if delta <= tolerance { + return Ok(delta) + } + hmc7043_sysref_slip(); + } + Err("failed to reach SYSREF DDMTD phase target") + } + + fn calibrate_sysref_target(rising_average: i32, falling_average: i32) -> Result { + info!("calibrating SYSREF DDMTD target phase..."); + let coarse_target = + if rising_average < falling_average { + (rising_average + falling_average)/2 + } else { + ((falling_average - (DDMTD_N - rising_average))/2 + DDMTD_N) % DDMTD_N + }; + info!(" SYSREF calibration coarse target: {}", coarse_target); + reach_sysref_ddmtd_target(coarse_target, 8)?; + let target = measure_ddmdt_phase(); + info!(" ...done, target={}", target); + Ok(target) + } + + fn sysref_get_tsc_phase_raw() -> Result { + if sysref_sh_error() { + return Err("SYSREF failed S/H timing"); + } + let ret = unsafe { csr::sysref_sampler::sysref_phase_read() }; + Ok(ret) + } + + // Note: the code below assumes RTIO/SYSREF frequency ratio is a power of 2 + + fn sysref_get_tsc_phase() -> Result { + let mask = (SYSREF_DIV/FPGA_CLK_DIV - 1) as u8; + Ok((sysref_get_tsc_phase_raw()? & mask) as i32) + } + + pub fn test_sysref_frequency() -> Result<(), &'static str> { + info!("testing SYSREF frequency against raw TSC phase bit toggles..."); + + let mut all_toggles = 0; + let initial_phase = sysref_get_tsc_phase_raw()?; + for _ in 0..20000 { + clock::spin_us(1); + all_toggles |= sysref_get_tsc_phase_raw()? ^ initial_phase; + } + + let ratio = (SYSREF_DIV/FPGA_CLK_DIV) as u8; + let expected_toggles = 0xff ^ (ratio - 1); + if all_toggles == expected_toggles { + info!(" ...done (0x{:02x})", all_toggles); + Ok(()) + } else { + error!(" ...unexpected toggles: got 0x{:02x}, expected 0x{:02x}", + all_toggles, expected_toggles); + Err("unexpected toggles") + } + } + + fn sysref_slip_rtio_cycle() { + for _ in 0..FPGA_CLK_DIV { + hmc7043_sysref_slip(); + } + } + + pub fn test_slip_tsc() -> Result<(), &'static str> { + info!("testing HMC7043 SYSREF slip against TSC phase..."); + let initial_phase = sysref_get_tsc_phase()?; + let modulo = (SYSREF_DIV/FPGA_CLK_DIV) as i32; + for i in 0..128 { + sysref_slip_rtio_cycle(); + let expected_phase = (initial_phase + i + 1) % modulo; + let phase = sysref_get_tsc_phase()?; + if phase != expected_phase { + error!(" ...unexpected TSC phase: got {}, expected {} ", phase, expected_phase); + return Err("HMC7043 SYSREF slip produced unexpected TSC phase"); + } + } + info!(" ...done"); + Ok(()) + } + + pub fn sysref_rtio_align() -> Result<(), &'static str> { + info!("aligning SYSREF with RTIO TSC..."); + let mut nslips = 0; + loop { + sysref_slip_rtio_cycle(); + if sysref_get_tsc_phase()? == 0 { + info!(" ...done"); + return Ok(()) + } + + nslips += 1; + if nslips > SYSREF_DIV/FPGA_CLK_DIV { + return Err("failed to find SYSREF transition aligned with RTIO TSC"); + } + } + } + + pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { + init_ddmtd()?; + test_ddmtd_stability(true, 4)?; + test_ddmtd_stability(false, 1)?; + test_slip_ddmtd()?; + + info!("determining SYSREF S/H limits..."); + let sysref_sh_limits = measure_sysref_sh_limits()?; + let rising_average = average_phases(&sysref_sh_limits.rising_phases, SYSREF_SH_MOD); + let falling_average = average_phases(&sysref_sh_limits.falling_phases, SYSREF_SH_MOD); + let rising_max_deviation = max_phase_deviation(rising_average, &sysref_sh_limits.rising_phases); + let falling_max_deviation = max_phase_deviation(falling_average, &sysref_sh_limits.falling_phases); + + let rising_average = rising_average >> SYSREF_SH_PRECISION_SHIFT; + let falling_average = falling_average >> SYSREF_SH_PRECISION_SHIFT; + let rising_max_deviation = rising_max_deviation >> SYSREF_SH_PRECISION_SHIFT; + let falling_max_deviation = falling_max_deviation >> SYSREF_SH_PRECISION_SHIFT; + + info!(" SYSREF S/H average limits (DDMTD phases): {} {}", rising_average, falling_average); + info!(" SYSREF S/H maximum limit deviation: {} {}", rising_max_deviation, falling_max_deviation); + if rising_max_deviation > 8 || falling_max_deviation > 8 { + return Err("excessive SYSREF S/H limit deviation"); + } + info!(" ...done"); + + let entry = config::read_str("sysref_ddmtd_phase_fpga", |r| r.map(|s| s.parse())); + let target_phase = match entry { + Ok(Ok(phase)) => { + info!("using FPGA SYSREF DDMTD phase target from config: {}", phase); + phase + } + _ => { + let phase = calibrate_sysref_target(rising_average, falling_average)?; + if let Err(e) = config::write_int("sysref_ddmtd_phase_fpga", phase as u32) { + error!("failed to update FPGA SYSREF DDMTD phase target in config: {}", e); + } + phase + } + }; + + info!("aligning SYSREF with RTIO clock..."); + let delta = reach_sysref_ddmtd_target(target_phase, 3)?; + if sysref_sh_error() { + return Err("SYSREF does not meet S/H timing at DDMTD phase target"); + } + info!(" ...done, delta={}", delta); + + test_sysref_frequency()?; + test_slip_tsc()?; + sysref_rtio_align()?; + + Ok(()) + } + + fn sysref_cal_dac(dacno: u8) -> Result { + info!("calibrating SYSREF delay at DAC-{}...", dacno); + + // Allocate for more than expected as jitter may create spurious entries. + let mut limits_buf = [0; 8]; + let mut n_limits = 0; + + limits_buf[n_limits] = -1; + n_limits += 1; + + // avoid spurious rotation at delay=0 + hmc7043_sysref_delay_dac(dacno, 0); + ad9154_sync(dacno)?; + + for scan_delay in 0..HMC7043_ANALOG_DELAY_RANGE { + hmc7043_sysref_delay_dac(dacno, scan_delay); + if ad9154_sync(dacno)? { + limits_buf[n_limits] = scan_delay as i16; + n_limits += 1; + if n_limits >= limits_buf.len() - 1 { + break; + } + } + } + + limits_buf[n_limits] = HMC7043_ANALOG_DELAY_RANGE as i16; + n_limits += 1; + + info!(" using limits: {:?}", &limits_buf[..n_limits]); + + let mut delay = 0; + let mut best_margin = 0; + + for i in 0..(n_limits-1) { + let margin = limits_buf[i+1] - limits_buf[i]; + if margin > best_margin { + best_margin = margin; + delay = ((limits_buf[i+1] + limits_buf[i])/2) as u8; + } + } + + info!(" ...done, delay={}", delay); + Ok(delay) + } + + fn sysref_dac_align(dacno: u8, delay: u8) -> Result<(), &'static str> { + let tolerance = 5; + + info!("verifying SYSREF margins at DAC-{}...", dacno); + + // avoid spurious rotation at delay=0 + hmc7043_sysref_delay_dac(dacno, 0); + ad9154_sync(dacno)?; + + let mut rotation_seen = false; + for scan_delay in 0..HMC7043_ANALOG_DELAY_RANGE { + hmc7043_sysref_delay_dac(dacno, scan_delay); + if ad9154_sync(dacno)? { + rotation_seen = true; + let distance = (scan_delay as i16 - delay as i16).abs(); + if distance < tolerance { + error!(" rotation at delay={} is {} delay steps from target (FAIL)", scan_delay, distance); + return Err("insufficient SYSREF margin at DAC"); + } else { + info!(" rotation at delay={} is {} delay steps from target (PASS)", scan_delay, distance); + } + } + } + + if !rotation_seen { + return Err("no rotation seen when scanning DAC SYSREF delay"); + } + + info!(" ...done"); + + // We tested that the value is correct - now use it + hmc7043_sysref_delay_dac(dacno, delay); + ad9154_sync(dacno)?; + + Ok(()) + } + + pub fn sysref_auto_dac_align() -> Result<(), &'static str> { + // We assume that DAC SYSREF traces are length-matched so only one delay + // value is needed, and we use DAC-0 as calibration reference. + + let entry = config::read_str("sysref_7043_delay_dac", |r| r.map(|s| s.parse())); + let delay = match entry { + Ok(Ok(delay)) => { + info!("using DAC SYSREF delay from config: {}", delay); + delay + }, + _ => { + let delay = sysref_cal_dac(0)?; + if let Err(e) = config::write_int("sysref_7043_delay_dac", delay as u32) { + error!("failed to update DAC SYSREF delay in config: {}", e); + } + delay + } + }; + + for dacno in 0..csr::JDCG.len() { + sysref_dac_align(dacno as u8, delay)?; + } Ok(()) } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 9d09d6859..ce0d92ae4 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -292,26 +292,39 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], } } - drtioaux::Packet::JdacBasicRequest { destination: _destination, dacno: _dacno, reqno: _reqno } => { + drtioaux::Packet::JdacBasicRequest { destination: _destination, dacno: _dacno, + reqno: _reqno, param: _param } => { forward!(_routing_table, _destination, *_rank, _repeaters, &packet); #[cfg(has_ad9154)] - let succeeded = { + let (succeeded, retval) = { #[cfg(rtio_frequency = "125.0")] const LINERATE: u64 = 5_000_000_000; #[cfg(rtio_frequency = "150.0")] const LINERATE: u64 = 6_000_000_000; match _reqno { - jdac_requests::INIT => board_artiq::ad9154::setup(_dacno, LINERATE).is_ok(), - jdac_requests::PRINT_STATUS => { board_artiq::ad9154::status(_dacno); true }, - jdac_requests::PRBS => board_artiq::ad9154::prbs(_dacno).is_ok(), - jdac_requests::STPL => board_artiq::ad9154::stpl(_dacno, 4, 2).is_ok(), - _ => false + jdac_requests::INIT => (board_artiq::ad9154::setup(_dacno, LINERATE).is_ok(), 0), + jdac_requests::PRINT_STATUS => { board_artiq::ad9154::status(_dacno); (true, 0) }, + jdac_requests::PRBS => (board_artiq::ad9154::prbs(_dacno).is_ok(), 0), + jdac_requests::STPL => (board_artiq::ad9154::stpl(_dacno, 4, 2).is_ok(), 0), + jdac_requests::SYSREF_DELAY_DAC => { board_artiq::hmc830_7043::hmc7043::sysref_delay_dac(_dacno, _param); (true, 0) }, + jdac_requests::SYSREF_SLIP => { board_artiq::hmc830_7043::hmc7043::sysref_slip(); (true, 0) }, + jdac_requests::SYNC => { + match board_artiq::ad9154::sync(_dacno) { + Ok(false) => (true, 0), + Ok(true) => (true, 1), + Err(e) => { + error!("DAC sync failed: {}", e); + (false, 0) + } + } + } + _ => (false, 0) } }; #[cfg(not(has_ad9154))] - let succeeded = false; + let (succeeded, retval) = (false, 0); drtioaux::send(0, - &drtioaux::Packet::JdacBasicReply { succeeded: succeeded }) + &drtioaux::Packet::JdacBasicReply { succeeded: succeeded, retval: retval }) } _ => { @@ -500,7 +513,7 @@ pub extern fn main() -> i32 { */ jdcg::jesd::reset(false); if repeaters[0].is_up() { - jdcg::jdac::init(); + let _ = jdcg::jdac::init(); } } @@ -538,7 +551,7 @@ pub extern fn main() -> i32 { { let rep0_is_up = repeaters[0].is_up(); if rep0_is_up && !rep0_was_up { - jdcg::jdac::init(); + let _ = jdcg::jdac::init(); jdcg::jesd204sync::sysref_auto_align(); } rep0_was_up = rep0_is_up; From 6d5dcb42110c216cc37148df3a131621cbc393e4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 19 Oct 2019 17:14:11 +0800 Subject: [PATCH 1951/2457] runtime: enable IPv6. Closes #349 --- artiq/firmware/runtime/Cargo.toml | 2 +- artiq/firmware/runtime/main.rs | 47 ++++++++++++++++++++++++++----- doc/manual/installing.rst | 2 ++ 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 4c187b1ff..c2404fc4c 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -27,7 +27,7 @@ board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp logger_artiq = { path = "../liblogger_artiq" } board_artiq = { path = "../libboard_artiq" } proto_artiq = { path = "../libproto_artiq", features = ["log", "alloc"] } -smoltcp = { version = "0.5.0", default-features = false, features = ["rust-1_28", "alloc", "log", "proto-ipv4", "socket-tcp"] } +smoltcp = { version = "0.5.0", default-features = false, features = ["rust-1_28", "alloc", "log", "proto-ipv4", "proto-ipv6", "socket-tcp"] } [dependencies.fringe] git = "https://github.com/m-labs/libfringe" diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 82f691a35..6e37f42e1 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -170,7 +170,7 @@ fn startup() { match config::read_str("ip", |r| r.map(|s| s.parse())) { Ok(Ok(addr)) => { protocol_addr = addr; - info!("using IP address {}", protocol_addr); + info!("using IPv4 address {}", protocol_addr); } _ => { #[cfg(soc_platform = "kasli")] @@ -189,9 +189,23 @@ fn startup() { { protocol_addr = IpAddress::v4(192, 168, 1, 50); } - info!("using default IP address {}", protocol_addr); + info!("using default IPv4 address {}", protocol_addr); } } + let protocol_addr6_ll = IpAddress::v6( + 0xfe80, 0x0000, 0x0000, 0x0000, + (((hardware_addr.0[0] ^ 0x02) as u16) << 8) | (hardware_addr.0[1] as u16), + ((hardware_addr.0[2] as u16) << 8) | 0x00ff, + 0xfe00 | (hardware_addr.0[3] as u16), + ((hardware_addr.0[4] as u16) << 8) | (hardware_addr.0[5] as u16)); + info!("using IPv6 link-local address {}", protocol_addr6_ll); + let protocol_addr6 = match config::read_str("ip6", |r| r.map(|s| s.parse())) { + Ok(Ok(addr)) => { + info!("using IPv6 configured address {}", addr); + Some(addr) + } + _ => None + }; let mut net_device = unsafe { ethmac::EthernetDevice::new() }; net_device.reset_phy_if_any(); @@ -218,12 +232,31 @@ fn startup() { let neighbor_cache = smoltcp::iface::NeighborCache::new(alloc::btree_map::BTreeMap::new()); - let mut interface = - smoltcp::iface::EthernetInterfaceBuilder::new(net_device) - .neighbor_cache(neighbor_cache) + let mut interface = match protocol_addr6 { + Some(addr) => { + let ip_addrs = [ + IpCidr::new(protocol_addr, 0), + IpCidr::new(protocol_addr6_ll, 0), + IpCidr::new(addr, 0) + ]; + smoltcp::iface::EthernetInterfaceBuilder::new(net_device) .ethernet_addr(hardware_addr) - .ip_addrs([IpCidr::new(protocol_addr, 0)]) - .finalize(); + .ip_addrs(ip_addrs) + .neighbor_cache(neighbor_cache) + .finalize() + } + None => { + let ip_addrs = [ + IpCidr::new(protocol_addr, 0), + IpCidr::new(protocol_addr6_ll, 0) + ]; + smoltcp::iface::EthernetInterfaceBuilder::new(net_device) + .ethernet_addr(hardware_addr) + .ip_addrs(ip_addrs) + .neighbor_cache(neighbor_cache) + .finalize() + } + }; #[cfg(has_drtio)] let drtio_routing_table = urc::Urc::new(RefCell::new( diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index e75f447c5..5ce4f1259 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -240,6 +240,8 @@ In other cases, install OpenOCD as before, and flash the IP and MAC addresses di Check that you can ping the device. If ping fails, check that the Ethernet link LED is ON - on Kasli, it is the LED next to the SFP0 connector. As a next step, look at the messages emitted on the UART during boot. Use a program such as flterm or PuTTY to connect to the device's serial port at 115200bps 8-N-1 and reboot the device. On Kasli, the serial port is on FTDI channel 2 with v1.1 hardware (with channel 0 being JTAG) and on FTDI channel 1 with v1.0 hardware. +If you want to use IPv6, the device also has a link-local address that corresponds to its EUI-64, and an additional arbitrary IPv6 address can be defined by using the ``ip6`` configuration key. All IPv4 and IPv6 addresses can be used at the same time. + Miscellaneous configuration of the core device ---------------------------------------------- From d26d80410e2bd963c3b83524e7ae9d4d7120bf63 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 19 Oct 2019 17:56:35 +0800 Subject: [PATCH 1952/2457] runtime: refactor network settings --- artiq/firmware/runtime/main.rs | 102 +++-------------------- artiq/firmware/runtime/net_settings.rs | 110 +++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 91 deletions(-) create mode 100644 artiq/firmware/runtime/net_settings.rs diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 6e37f42e1..8d39f4001 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -28,7 +28,7 @@ extern crate proto_artiq; use core::cell::RefCell; use core::convert::TryFrom; -use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; +use smoltcp::wire::IpCidr; use board_misoc::{csr, irq, ident, clock, boot, config}; #[cfg(has_ethmac)] @@ -41,6 +41,8 @@ use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_pro #[cfg(has_rtio_analyzer)] use proto_artiq::analyzer_proto; +mod net_settings; + mod rtio_clocking; mod rtio_mgt; @@ -124,89 +126,6 @@ fn startup() { sayma_hw_init(); rtio_clocking::init(); - let hardware_addr; - match config::read_str("mac", |r| r.map(|s| s.parse())) { - Ok(Ok(addr)) => { - hardware_addr = addr; - info!("using MAC address {}", hardware_addr); - } - _ => { - #[cfg(soc_platform = "kasli")] - { - let eeprom = board_artiq::i2c_eeprom::EEPROM::kasli_eeprom(); - hardware_addr = - eeprom.read_eui48() - .map(|addr_buf| { - let hardware_addr = EthernetAddress(addr_buf); - info!("using MAC address {} from EEPROM", hardware_addr); - hardware_addr - }) - .unwrap_or_else(|e| { - error!("failed to read MAC address from EEPROM: {}", e); - let hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x21]); - warn!("using default MAC address {}; consider changing it", hardware_addr); - hardware_addr - }); - } - #[cfg(soc_platform = "sayma_amc")] - { - hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x11]); - warn!("using default MAC address {}; consider changing it", hardware_addr); - } - #[cfg(soc_platform = "metlino")] - { - hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x19]); - warn!("using default MAC address {}; consider changing it", hardware_addr); - } - #[cfg(soc_platform = "kc705")] - { - hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); - warn!("using default MAC address {}; consider changing it", hardware_addr); - } - } - } - - let protocol_addr; - match config::read_str("ip", |r| r.map(|s| s.parse())) { - Ok(Ok(addr)) => { - protocol_addr = addr; - info!("using IPv4 address {}", protocol_addr); - } - _ => { - #[cfg(soc_platform = "kasli")] - { - protocol_addr = IpAddress::v4(192, 168, 1, 70); - } - #[cfg(soc_platform = "sayma_amc")] - { - protocol_addr = IpAddress::v4(192, 168, 1, 60); - } - #[cfg(soc_platform = "metlino")] - { - protocol_addr = IpAddress::v4(192, 168, 1, 65); - } - #[cfg(soc_platform = "kc705")] - { - protocol_addr = IpAddress::v4(192, 168, 1, 50); - } - info!("using default IPv4 address {}", protocol_addr); - } - } - let protocol_addr6_ll = IpAddress::v6( - 0xfe80, 0x0000, 0x0000, 0x0000, - (((hardware_addr.0[0] ^ 0x02) as u16) << 8) | (hardware_addr.0[1] as u16), - ((hardware_addr.0[2] as u16) << 8) | 0x00ff, - 0xfe00 | (hardware_addr.0[3] as u16), - ((hardware_addr.0[4] as u16) << 8) | (hardware_addr.0[5] as u16)); - info!("using IPv6 link-local address {}", protocol_addr6_ll); - let protocol_addr6 = match config::read_str("ip6", |r| r.map(|s| s.parse())) { - Ok(Ok(addr)) => { - info!("using IPv6 configured address {}", addr); - Some(addr) - } - _ => None - }; - let mut net_device = unsafe { ethmac::EthernetDevice::new() }; net_device.reset_phy_if_any(); @@ -232,26 +151,27 @@ fn startup() { let neighbor_cache = smoltcp::iface::NeighborCache::new(alloc::btree_map::BTreeMap::new()); - let mut interface = match protocol_addr6 { + let net_addresses = net_settings::get_adresses(); + let mut interface = match net_addresses.ipv6_addr { Some(addr) => { let ip_addrs = [ - IpCidr::new(protocol_addr, 0), - IpCidr::new(protocol_addr6_ll, 0), + IpCidr::new(net_addresses.ipv4_addr, 0), + IpCidr::new(net_addresses.ipv6_ll_addr, 0), IpCidr::new(addr, 0) ]; smoltcp::iface::EthernetInterfaceBuilder::new(net_device) - .ethernet_addr(hardware_addr) + .ethernet_addr(net_addresses.hardware_addr) .ip_addrs(ip_addrs) .neighbor_cache(neighbor_cache) .finalize() } None => { let ip_addrs = [ - IpCidr::new(protocol_addr, 0), - IpCidr::new(protocol_addr6_ll, 0) + IpCidr::new(net_addresses.ipv4_addr, 0), + IpCidr::new(net_addresses.ipv6_ll_addr, 0) ]; smoltcp::iface::EthernetInterfaceBuilder::new(net_device) - .ethernet_addr(hardware_addr) + .ethernet_addr(net_addresses.hardware_addr) .ip_addrs(ip_addrs) .neighbor_cache(neighbor_cache) .finalize() diff --git a/artiq/firmware/runtime/net_settings.rs b/artiq/firmware/runtime/net_settings.rs new file mode 100644 index 000000000..d208479d5 --- /dev/null +++ b/artiq/firmware/runtime/net_settings.rs @@ -0,0 +1,110 @@ +use smoltcp::wire::{EthernetAddress, IpAddress}; + +use board_misoc::config; +#[cfg(soc_platform = "kasli")] +use board_artiq::i2c_eeprom; + + +pub struct NetAddresses { + pub hardware_addr: EthernetAddress, + pub ipv4_addr: IpAddress, + pub ipv6_ll_addr: IpAddress, + pub ipv6_addr: Option +} + +pub fn get_adresses() -> NetAddresses { + let hardware_addr; + match config::read_str("mac", |r| r.map(|s| s.parse())) { + Ok(Ok(addr)) => { + hardware_addr = addr; + info!("using MAC address {}", hardware_addr); + } + _ => { + #[cfg(soc_platform = "kasli")] + { + let eeprom = i2c_eeprom::EEPROM::kasli_eeprom(); + hardware_addr = + eeprom.read_eui48() + .map(|addr_buf| { + let hardware_addr = EthernetAddress(addr_buf); + info!("using MAC address {} from EEPROM", hardware_addr); + hardware_addr + }) + .unwrap_or_else(|e| { + error!("failed to read MAC address from EEPROM: {}", e); + let hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x21]); + warn!("using default MAC address {}; consider changing it", hardware_addr); + hardware_addr + }); + } + #[cfg(soc_platform = "sayma_amc")] + { + hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x11]); + warn!("using default MAC address {}; consider changing it", hardware_addr); + } + #[cfg(soc_platform = "metlino")] + { + hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x19]); + warn!("using default MAC address {}; consider changing it", hardware_addr); + } + #[cfg(soc_platform = "kc705")] + { + hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); + warn!("using default MAC address {}; consider changing it", hardware_addr); + } + } + } + + let ipv4_addr; + match config::read_str("ip", |r| r.map(|s| s.parse())) { + Ok(Ok(addr)) => { + ipv4_addr = addr; + info!("using IPv4 address {}", ipv4_addr); + } + _ => { + #[cfg(soc_platform = "kasli")] + { + ipv4_addr = IpAddress::v4(192, 168, 1, 70); + } + #[cfg(soc_platform = "sayma_amc")] + { + ipv4_addr = IpAddress::v4(192, 168, 1, 60); + } + #[cfg(soc_platform = "metlino")] + { + ipv4_addr = IpAddress::v4(192, 168, 1, 65); + } + #[cfg(soc_platform = "kc705")] + { + ipv4_addr = IpAddress::v4(192, 168, 1, 50); + } + info!("using default IPv4 address {}", ipv4_addr); + } + } + + let ipv6_ll_addr = IpAddress::v6( + 0xfe80, 0x0000, 0x0000, 0x0000, + (((hardware_addr.0[0] ^ 0x02) as u16) << 8) | (hardware_addr.0[1] as u16), + ((hardware_addr.0[2] as u16) << 8) | 0x00ff, + 0xfe00 | (hardware_addr.0[3] as u16), + ((hardware_addr.0[4] as u16) << 8) | (hardware_addr.0[5] as u16)); + info!("using IPv6 link-local address {}", ipv6_ll_addr); + + let ipv6_addr = match config::read_str("ip6", |r| r.map(|s| s.parse())) { + Ok(Ok(addr)) => { + info!("using IPv6 configured address {}", addr); + Some(addr) + }, + _ => { + info!("no IPv6 configured address"); + None + } + }; + + NetAddresses { + hardware_addr: hardware_addr, + ipv4_addr: ipv4_addr, + ipv6_ll_addr: ipv6_ll_addr, + ipv6_addr: ipv6_addr + } +} From 1c5e7490361c6506f078c81ae77d225fc4fb0c72 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Oct 2019 12:53:54 +0800 Subject: [PATCH 1953/2457] satman: remove compilation warning without JESD DACs --- artiq/firmware/satman/repeater.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/satman/repeater.rs b/artiq/firmware/satman/repeater.rs index 69a813d34..9969d5099 100644 --- a/artiq/firmware/satman/repeater.rs +++ b/artiq/firmware/satman/repeater.rs @@ -43,6 +43,7 @@ impl Repeater { } } + #[allow(dead_code)] pub fn is_up(&self) -> bool { self.state == RepeaterState::Up } From 8f76a3218e48ffc70b6da31f73c941076ebe0d6f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Oct 2019 12:58:52 +0800 Subject: [PATCH 1954/2457] firmware: move i2c to libboard_misoc, enable IPv6 in bootloader, share network settings --- artiq/firmware/bootloader/Cargo.toml | 2 +- artiq/firmware/bootloader/main.rs | 45 ++++++----- artiq/firmware/libboard_artiq/lib.rs | 5 -- artiq/firmware/libboard_artiq/pca9548.rs | 13 ---- artiq/firmware/libboard_artiq/si5324.rs | 14 ++-- .../{libboard_artiq => libboard_misoc}/i2c.rs | 24 ++++-- .../i2c_eeprom.rs | 5 +- artiq/firmware/libboard_misoc/lib.rs | 5 ++ .../net_settings.rs | 74 +++++++------------ artiq/firmware/runtime/kern_hwreq.rs | 2 +- artiq/firmware/runtime/main.rs | 7 +- artiq/firmware/satman/main.rs | 6 +- 12 files changed, 93 insertions(+), 109 deletions(-) delete mode 100644 artiq/firmware/libboard_artiq/pca9548.rs rename artiq/firmware/{libboard_artiq => libboard_misoc}/i2c.rs (89%) rename artiq/firmware/{libboard_artiq => libboard_misoc}/i2c_eeprom.rs (91%) rename artiq/firmware/{runtime => libboard_misoc}/net_settings.rs (51%) diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml index 2a43b72f5..aed6df31b 100644 --- a/artiq/firmware/bootloader/Cargo.toml +++ b/artiq/firmware/bootloader/Cargo.toml @@ -16,4 +16,4 @@ build_misoc = { path = "../libbuild_misoc" } byteorder = { version = "1.0", default-features = false } crc = { version = "1.7", default-features = false } board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp"] } -smoltcp = { version = "0.5.0", default-features = false, features = ["proto-ipv4", "socket-tcp"] } +smoltcp = { version = "0.5.0", default-features = false, features = ["proto-ipv4", "proto-ipv6", "socket-tcp"] } diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index fc084d5e4..545e3a73c 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -12,7 +12,7 @@ use crc::crc32; use byteorder::{ByteOrder, BigEndian}; use board_misoc::{ident, cache, sdram, boot, mem as board_mem}; #[cfg(has_ethmac)] -use board_misoc::{clock, config, ethmac}; +use board_misoc::{clock, config, ethmac, net_settings}; use board_misoc::uart_console::Console; fn check_integrity() -> bool { @@ -155,18 +155,6 @@ fn network_boot() { println!("Initializing network..."); - let eth_addr = match config::read_str("mac", |r| r.map(|s| s.parse())) { - Ok(Ok(addr)) => addr, - _ => EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]) - }; - - let ip_addr = match config::read_str("ip", |r| r.map(|s| s.parse())) { - Ok(Ok(addr)) => addr, - _ => IpAddress::v4(192, 168, 1, 50) - }; - - println!("Using MAC address {} and IP address {}", eth_addr, ip_addr); - let mut net_device = unsafe { ethmac::EthernetDevice::new() }; net_device.reset_phy_if_any(); @@ -174,12 +162,33 @@ fn network_boot() { let neighbor_cache = smoltcp::iface::NeighborCache::new(&mut neighbor_map[..]); let mut ip_addrs = [IpCidr::new(ip_addr, 0)]; - let mut interface = - smoltcp::iface::EthernetInterfaceBuilder::new(net_device) + let net_addresses = net_settings::get_adresses(); + println!("network addresses: {}", net_addresses); + let mut interface = match net_addresses.ipv6_addr { + Some(addr) => { + let ip_addrs = [ + IpCidr::new(net_addresses.ipv4_addr, 0), + IpCidr::new(net_addresses.ipv6_ll_addr, 0), + IpCidr::new(addr, 0) + ]; + smoltcp::iface::EthernetInterfaceBuilder::new(net_device) + .ethernet_addr(net_addresses.hardware_addr) + .ip_addrs(ip_addrs) .neighbor_cache(neighbor_cache) - .ethernet_addr(eth_addr) - .ip_addrs(&mut ip_addrs[..]) - .finalize(); + .finalize() + } + None => { + let ip_addrs = [ + IpCidr::new(net_addresses.ipv4_addr, 0), + IpCidr::new(net_addresses.ipv6_ll_addr, 0) + ]; + smoltcp::iface::EthernetInterfaceBuilder::new(net_device) + .ethernet_addr(net_addresses.hardware_addr) + .ip_addrs(ip_addrs) + .neighbor_cache(neighbor_cache) + .finalize() + } + }; let mut socket_set_storage = []; let mut sockets = diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index ce0757427..9a4e727b2 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -17,7 +17,6 @@ extern crate proto_artiq; pub mod pcr; -pub mod i2c; pub mod spi; #[cfg(has_kernel_cpu)] @@ -25,12 +24,8 @@ pub mod mailbox; #[cfg(has_kernel_cpu)] pub mod rpc_queue; -#[cfg(any(soc_platform = "kasli", has_si5324))] -mod pca9548; #[cfg(has_si5324)] pub mod si5324; -#[cfg(soc_platform = "kasli")] -pub mod i2c_eeprom; #[cfg(has_slave_fpga_cfg)] pub mod slave_fpga; diff --git a/artiq/firmware/libboard_artiq/pca9548.rs b/artiq/firmware/libboard_artiq/pca9548.rs deleted file mode 100644 index a69d72ed7..000000000 --- a/artiq/firmware/libboard_artiq/pca9548.rs +++ /dev/null @@ -1,13 +0,0 @@ -use i2c; - -pub fn select(busno: u8, address: u8, channels: u8) -> Result<(), &'static str> { - i2c::start(busno).unwrap(); - if !i2c::write(busno, address << 1)? { - return Err("PCA9548 failed to ack write address") - } - if !i2c::write(busno, channels)? { - return Err("PCA9548 failed to ack control word") - } - i2c::stop(busno).unwrap(); - Ok(()) -} diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index d02bec693..68005131f 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -1,9 +1,7 @@ use core::result; -use board_misoc::clock; +use board_misoc::{clock, i2c}; #[cfg(not(si5324_soft_reset))] use board_misoc::csr; -use i2c; -use pca9548; type Result = result::Result; @@ -181,15 +179,15 @@ fn init() -> Result<()> { #[cfg(soc_platform = "kasli")] { - pca9548::select(BUSNO, 0x70, 0)?; - pca9548::select(BUSNO, 0x71, 1 << 3)?; + i2c::pca9548_select(BUSNO, 0x70, 0)?; + i2c::pca9548_select(BUSNO, 0x71, 1 << 3)?; } #[cfg(soc_platform = "sayma_amc")] - pca9548::select(BUSNO, 0x70, 1 << 4)?; + i2c::pca9548_select(BUSNO, 0x70, 1 << 4)?; #[cfg(soc_platform = "sayma_rtm")] - pca9548::select(BUSNO, 0x77, 1 << 5)?; + i2c::pca9548_select(BUSNO, 0x77, 1 << 5)?; #[cfg(soc_platform = "kc705")] - pca9548::select(BUSNO, 0x74, 1 << 7)?; + i2c::pca9548_select(BUSNO, 0x74, 1 << 7)?; if ident()? != 0x0182 { return Err("Si5324 does not have expected product number"); diff --git a/artiq/firmware/libboard_artiq/i2c.rs b/artiq/firmware/libboard_misoc/i2c.rs similarity index 89% rename from artiq/firmware/libboard_artiq/i2c.rs rename to artiq/firmware/libboard_misoc/i2c.rs index d13dc32ce..b816c4921 100644 --- a/artiq/firmware/libboard_artiq/i2c.rs +++ b/artiq/firmware/libboard_misoc/i2c.rs @@ -1,6 +1,6 @@ #[cfg(has_i2c)] mod imp { - use board_misoc::{csr, clock}; + use super::super::{csr, clock}; const INVALID_BUS: &'static str = "Invalid I2C bus"; @@ -46,7 +46,7 @@ mod imp { } } - pub fn init() { + pub fn init() -> Result<(), &'static str> { for busno in 0..csr::CONFIG_I2C_BUS_COUNT { let busno = busno as u8; // Set SCL as output, and high level @@ -61,8 +61,6 @@ mod imp { half_period(); half_period(); if !sda_i(busno) { - warn!("SDA is stuck low on bus #{}, trying to unstuck", busno); - // Try toggling SCL a few times for _bit in 0..8 { scl_o(busno, false); @@ -73,9 +71,10 @@ mod imp { } if !sda_i(busno) { - error!("SDA is stuck low on bus #{} and doesn't get unstuck", busno); + return Err("SDA is stuck low and doesn't get unstuck"); } } + Ok(()) } pub fn start(busno: u8) -> Result<(), &'static str> { @@ -178,17 +177,30 @@ mod imp { Ok(data) } + + pub fn pca9548_select(busno: u8, address: u8, channels: u8) -> Result<(), &'static str> { + start(busno)?; + if !write(busno, address << 1)? { + return Err("PCA9548 failed to ack write address") + } + if !write(busno, channels)? { + return Err("PCA9548 failed to ack control word") + } + stop(busno)?; + Ok(()) + } } #[cfg(not(has_i2c))] mod imp { const NO_I2C: &'static str = "No I2C support on this platform"; - pub fn init() {} + pub fn init() { Err(NO_I2C) } pub fn start(_busno: u8) -> Result<(), &'static str> { Err(NO_I2C) } pub fn restart(_busno: u8) -> Result<(), &'static str> { Err(NO_I2C) } pub fn stop(_busno: u8) -> Result<(), &'static str> { Err(NO_I2C) } pub fn write(_busno: u8, _data: u8) -> Result { Err(NO_I2C) } pub fn read(_busno: u8, _ack: bool) -> Result { Err(NO_I2C) } + pub fn pca9548_select(busno: u8, address: u8, channels: u8) -> Result<(), &'static str> { Err(NO_I2C) } } pub use self::imp::*; diff --git a/artiq/firmware/libboard_artiq/i2c_eeprom.rs b/artiq/firmware/libboard_misoc/i2c_eeprom.rs similarity index 91% rename from artiq/firmware/libboard_artiq/i2c_eeprom.rs rename to artiq/firmware/libboard_misoc/i2c_eeprom.rs index e5f6cb9b3..0a15f7535 100644 --- a/artiq/firmware/libboard_artiq/i2c_eeprom.rs +++ b/artiq/firmware/libboard_misoc/i2c_eeprom.rs @@ -1,5 +1,4 @@ use i2c; -use pca9548; #[cfg(soc_platform = "kasli")] const I2C_SWITCH0: u8 = 0x70; @@ -25,8 +24,8 @@ impl EEPROM { fn select(&self) -> Result<(), &'static str> { let mask: u16 = 1 << self.port; - pca9548::select(self.busno, I2C_SWITCH0, mask as u8)?; - pca9548::select(self.busno, I2C_SWITCH1, (mask >> 8) as u8)?; + i2c::pca9548_select(self.busno, I2C_SWITCH0, mask as u8)?; + i2c::pca9548_select(self.busno, I2C_SWITCH1, (mask >> 8) as u8)?; Ok(()) } diff --git a/artiq/firmware/libboard_misoc/lib.rs b/artiq/firmware/libboard_misoc/lib.rs index 1b1b597d9..b49a69446 100644 --- a/artiq/firmware/libboard_misoc/lib.rs +++ b/artiq/firmware/libboard_misoc/lib.rs @@ -32,3 +32,8 @@ pub mod uart_console; pub mod uart_logger; #[cfg(all(has_ethmac, feature = "smoltcp"))] pub mod ethmac; +pub mod i2c; +#[cfg(soc_platform = "kasli")] +pub mod i2c_eeprom; +#[cfg(all(has_ethmac, feature = "smoltcp"))] +pub mod net_settings; diff --git a/artiq/firmware/runtime/net_settings.rs b/artiq/firmware/libboard_misoc/net_settings.rs similarity index 51% rename from artiq/firmware/runtime/net_settings.rs rename to artiq/firmware/libboard_misoc/net_settings.rs index d208479d5..3636c6924 100644 --- a/artiq/firmware/runtime/net_settings.rs +++ b/artiq/firmware/libboard_misoc/net_settings.rs @@ -1,8 +1,10 @@ +use core::fmt; + use smoltcp::wire::{EthernetAddress, IpAddress}; -use board_misoc::config; +use config; #[cfg(soc_platform = "kasli")] -use board_artiq::i2c_eeprom; +use i2c_eeprom; pub struct NetAddresses { @@ -12,13 +14,22 @@ pub struct NetAddresses { pub ipv6_addr: Option } +impl fmt::Display for NetAddresses { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "MAC:{} IPv4:{} IPv6-LL:{} IPv6:", + self.hardware_addr, self.ipv4_addr, self.ipv6_ll_addr)?; + match self.ipv6_addr { + Some(addr) => write!(f, "{}", addr)?, + None => write!(f, "no configured address")? + } + Ok(()) + } +} + pub fn get_adresses() -> NetAddresses { let hardware_addr; match config::read_str("mac", |r| r.map(|s| s.parse())) { - Ok(Ok(addr)) => { - hardware_addr = addr; - info!("using MAC address {}", hardware_addr); - } + Ok(Ok(addr)) => hardware_addr = addr, _ => { #[cfg(soc_platform = "kasli")] { @@ -27,58 +38,34 @@ pub fn get_adresses() -> NetAddresses { eeprom.read_eui48() .map(|addr_buf| { let hardware_addr = EthernetAddress(addr_buf); - info!("using MAC address {} from EEPROM", hardware_addr); hardware_addr }) .unwrap_or_else(|e| { - error!("failed to read MAC address from EEPROM: {}", e); let hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x21]); - warn!("using default MAC address {}; consider changing it", hardware_addr); hardware_addr }); } #[cfg(soc_platform = "sayma_amc")] - { - hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x11]); - warn!("using default MAC address {}; consider changing it", hardware_addr); - } + { hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x11]); } #[cfg(soc_platform = "metlino")] - { - hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x19]); - warn!("using default MAC address {}; consider changing it", hardware_addr); - } + { hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x19]); } #[cfg(soc_platform = "kc705")] - { - hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); - warn!("using default MAC address {}; consider changing it", hardware_addr); - } + { hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); } } } let ipv4_addr; match config::read_str("ip", |r| r.map(|s| s.parse())) { - Ok(Ok(addr)) => { - ipv4_addr = addr; - info!("using IPv4 address {}", ipv4_addr); - } + Ok(Ok(addr)) => ipv4_addr = addr, _ => { #[cfg(soc_platform = "kasli")] - { - ipv4_addr = IpAddress::v4(192, 168, 1, 70); - } + { ipv4_addr = IpAddress::v4(192, 168, 1, 70); } #[cfg(soc_platform = "sayma_amc")] - { - ipv4_addr = IpAddress::v4(192, 168, 1, 60); - } + { ipv4_addr = IpAddress::v4(192, 168, 1, 60); } #[cfg(soc_platform = "metlino")] - { - ipv4_addr = IpAddress::v4(192, 168, 1, 65); - } + { ipv4_addr = IpAddress::v4(192, 168, 1, 65); } #[cfg(soc_platform = "kc705")] - { - ipv4_addr = IpAddress::v4(192, 168, 1, 50); - } - info!("using default IPv4 address {}", ipv4_addr); + { ipv4_addr = IpAddress::v4(192, 168, 1, 50); } } } @@ -88,17 +75,10 @@ pub fn get_adresses() -> NetAddresses { ((hardware_addr.0[2] as u16) << 8) | 0x00ff, 0xfe00 | (hardware_addr.0[3] as u16), ((hardware_addr.0[4] as u16) << 8) | (hardware_addr.0[5] as u16)); - info!("using IPv6 link-local address {}", ipv6_ll_addr); let ipv6_addr = match config::read_str("ip6", |r| r.map(|s| s.parse())) { - Ok(Ok(addr)) => { - info!("using IPv6 configured address {}", addr); - Some(addr) - }, - _ => { - info!("no IPv6 configured address"); - None - } + Ok(Ok(addr)) => Some(addr), + _ => None }; NetAddresses { diff --git a/artiq/firmware/runtime/kern_hwreq.rs b/artiq/firmware/runtime/kern_hwreq.rs index d039d7ce2..53e0daa8a 100644 --- a/artiq/firmware/runtime/kern_hwreq.rs +++ b/artiq/firmware/runtime/kern_hwreq.rs @@ -4,8 +4,8 @@ use sched::{Io, Mutex, Error as SchedError}; use session::{kern_acknowledge, kern_send, Error}; use rtio_mgt; use urc::Urc; +use board_misoc::i2c as local_i2c; use board_artiq::drtio_routing; -use board_artiq::i2c as local_i2c; use board_artiq::spi as local_spi; #[cfg(has_drtio)] diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 8d39f4001..0f24877d8 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -30,7 +30,7 @@ use core::cell::RefCell; use core::convert::TryFrom; use smoltcp::wire::IpCidr; -use board_misoc::{csr, irq, ident, clock, boot, config}; +use board_misoc::{csr, irq, ident, clock, boot, config, net_settings}; #[cfg(has_ethmac)] use board_misoc::ethmac; #[cfg(has_drtio)] @@ -41,8 +41,6 @@ use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_pro #[cfg(has_rtio_analyzer)] use proto_artiq::analyzer_proto; -mod net_settings; - mod rtio_clocking; mod rtio_mgt; @@ -122,7 +120,7 @@ fn startup() { setup_log_levels(); #[cfg(has_i2c)] - board_artiq::i2c::init(); + board_misoc::i2c::init().expect("I2C initialization failed"); sayma_hw_init(); rtio_clocking::init(); @@ -152,6 +150,7 @@ fn startup() { let neighbor_cache = smoltcp::iface::NeighborCache::new(alloc::btree_map::BTreeMap::new()); let net_addresses = net_settings::get_adresses(); + info!("network addresses: {}", net_addresses); let mut interface = match net_addresses.ipv6_addr { Some(addr) => { let ip_addrs = [ diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index ce0d92ae4..98cc844c9 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -8,8 +8,8 @@ extern crate board_misoc; extern crate board_artiq; use core::convert::TryFrom; -use board_misoc::{csr, irq, ident, clock, uart_logger}; -use board_artiq::{i2c, spi, si5324, drtioaux}; +use board_misoc::{csr, irq, ident, clock, uart_logger, i2c}; +use board_artiq::{spi, si5324, drtioaux}; use board_artiq::drtio_routing; #[cfg(has_hmc830_7043)] use board_artiq::hmc830_7043; @@ -451,7 +451,7 @@ pub extern fn main() -> i32 { #[cfg(has_slave_fpga_cfg)] board_artiq::slave_fpga::load().expect("cannot load RTM FPGA gateware"); - i2c::init(); + i2c::init().expect("I2C initialization failed"); si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324"); unsafe { csr::drtio_transceiver::stable_clkin_write(1); From 818d6b2f5abb5cd7fa9f56d8692013076c83a19e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Oct 2019 13:28:17 +0800 Subject: [PATCH 1955/2457] bootloader: fix compilation problems --- artiq/firmware/bootloader/main.rs | 27 ++++++++----------- artiq/firmware/libboard_misoc/net_settings.rs | 10 ++----- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 545e3a73c..f44f0b757 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -12,7 +12,7 @@ use crc::crc32; use byteorder::{ByteOrder, BigEndian}; use board_misoc::{ident, cache, sdram, boot, mem as board_mem}; #[cfg(has_ethmac)] -use board_misoc::{clock, config, ethmac, net_settings}; +use board_misoc::{clock, ethmac, net_settings}; use board_misoc::uart_console::Console; fn check_integrity() -> bool { @@ -151,7 +151,7 @@ fn flash_boot() { #[cfg(has_ethmac)] fn network_boot() { - use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; + use smoltcp::wire::IpCidr; println!("Initializing network..."); @@ -161,33 +161,28 @@ fn network_boot() { let mut neighbor_map = [None; 2]; let neighbor_cache = smoltcp::iface::NeighborCache::new(&mut neighbor_map[..]); - let mut ip_addrs = [IpCidr::new(ip_addr, 0)]; let net_addresses = net_settings::get_adresses(); println!("network addresses: {}", net_addresses); + let mut ip_addrs = [ + IpCidr::new(net_addresses.ipv4_addr, 0), + IpCidr::new(net_addresses.ipv6_ll_addr, 0), + IpCidr::new(net_addresses.ipv6_ll_addr, 0) + ]; let mut interface = match net_addresses.ipv6_addr { Some(addr) => { - let ip_addrs = [ - IpCidr::new(net_addresses.ipv4_addr, 0), - IpCidr::new(net_addresses.ipv6_ll_addr, 0), - IpCidr::new(addr, 0) - ]; + ip_addrs[2] = IpCidr::new(addr, 0); smoltcp::iface::EthernetInterfaceBuilder::new(net_device) .ethernet_addr(net_addresses.hardware_addr) - .ip_addrs(ip_addrs) + .ip_addrs(&mut ip_addrs[..]) .neighbor_cache(neighbor_cache) .finalize() } - None => { - let ip_addrs = [ - IpCidr::new(net_addresses.ipv4_addr, 0), - IpCidr::new(net_addresses.ipv6_ll_addr, 0) - ]; + None => smoltcp::iface::EthernetInterfaceBuilder::new(net_device) .ethernet_addr(net_addresses.hardware_addr) - .ip_addrs(ip_addrs) + .ip_addrs(&mut ip_addrs[..2]) .neighbor_cache(neighbor_cache) .finalize() - } }; let mut socket_set_storage = []; diff --git a/artiq/firmware/libboard_misoc/net_settings.rs b/artiq/firmware/libboard_misoc/net_settings.rs index 3636c6924..1ab25b4e6 100644 --- a/artiq/firmware/libboard_misoc/net_settings.rs +++ b/artiq/firmware/libboard_misoc/net_settings.rs @@ -36,14 +36,8 @@ pub fn get_adresses() -> NetAddresses { let eeprom = i2c_eeprom::EEPROM::kasli_eeprom(); hardware_addr = eeprom.read_eui48() - .map(|addr_buf| { - let hardware_addr = EthernetAddress(addr_buf); - hardware_addr - }) - .unwrap_or_else(|e| { - let hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x21]); - hardware_addr - }); + .map(|addr_buf| EthernetAddress(addr_buf)) + .unwrap_or_else(|_e| EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x21])); } #[cfg(soc_platform = "sayma_amc")] { hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x11]); } From 47a83c71f153afa96a9b335d31ab3b186f5627f1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Oct 2019 14:00:14 +0800 Subject: [PATCH 1956/2457] firmware: more readable network addresses message --- artiq/firmware/libboard_misoc/net_settings.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_misoc/net_settings.rs b/artiq/firmware/libboard_misoc/net_settings.rs index 1ab25b4e6..f58eae13f 100644 --- a/artiq/firmware/libboard_misoc/net_settings.rs +++ b/artiq/firmware/libboard_misoc/net_settings.rs @@ -16,7 +16,7 @@ pub struct NetAddresses { impl fmt::Display for NetAddresses { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "MAC:{} IPv4:{} IPv6-LL:{} IPv6:", + write!(f, "MAC={} IPv4={} IPv6-LL={} IPv6=", self.hardware_addr, self.ipv4_addr, self.ipv6_ll_addr)?; match self.ipv6_addr { Some(addr) => write!(f, "{}", addr)?, From f2f7170d20709c77b2521f27fe8141dda86df006 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 21 Oct 2019 22:56:08 +0800 Subject: [PATCH 1957/2457] hmc7043: use recommend I/O standards https://github.com/sinara-hw/Sayma_RTM/issues/116#issuecomment-544187952 --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index f318ed698..a3e2cf337 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -150,9 +150,9 @@ pub mod hmc7043 { // enabled, divider, output config, is sysref const OUTPUT_CONFIG: [(bool, u16, u8, bool); 14] = [ (true, DAC_CLK_DIV, 0x08, false), // 0: DAC1_CLK - (true, SYSREF_DIV, 0x08, true), // 1: DAC1_SYSREF + (true, SYSREF_DIV, 0x00, true), // 1: DAC1_SYSREF (true, DAC_CLK_DIV, 0x08, false), // 2: DAC0_CLK - (true, SYSREF_DIV, 0x08, true), // 3: DAC0_SYSREF + (true, SYSREF_DIV, 0x00, true), // 3: DAC0_SYSREF (true, SYSREF_DIV, 0x10, true), // 4: AMC_FPGA_SYSREF0 (true, FPGA_CLK_DIV, 0x10, true), // 5: AMC_FPGA_SYSREF1 (false, 0, 0x10, false), // 6: unused @@ -160,7 +160,7 @@ pub mod hmc7043 { (true, FPGA_CLK_DIV, 0x08, false), // 8: GTP_CLK0_IN (false, 0, 0x10, false), // 9: unused (false, 0, 0x10, false), // 10: unused - (false, 0, 0x10, false), // 11: unused / uFL + (false, 0, 0x08, false), // 11: unused / uFL (false, 0, 0x10, false), // 12: unused (false, SYSREF_DIV, 0x10, true), // 13: RTM_FPGA_SYSREF1 ]; From 5d7f22ffa41cd749a5bbb7d2ffd4961e9f1b1e78 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 11 Oct 2019 13:45:03 +0100 Subject: [PATCH 1958/2457] compiler: Remove provision for unused four-parameter llptr_to_var() form [nfc] `var_type` was presumably intended to convert to a target type, but wasn't actually acted on in the function body (nor was it used anywhere in the codebase). --- artiq/compiler/transforms/llvm_ir_generator.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 3fc6d719e..0a8e95f79 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -719,9 +719,8 @@ class LLVMIRGenerator: self.llbuilder.store(lloperand, llfieldptr) return llalloc - def llptr_to_var(self, llenv, env_ty, var_name, var_type=None): - if var_name in env_ty.params and (var_type is None or - env_ty.params[var_name] == var_type): + def llptr_to_var(self, llenv, env_ty, var_name): + if var_name in env_ty.params: var_index = list(env_ty.params.keys()).index(var_name) return self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(var_index)], inbounds=True) From 611bcc4db4ed604a32d9678623617cd50e968cbf Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 27 Oct 2019 20:42:48 +0000 Subject: [PATCH 1959/2457] compiler: Cache expensive target data layout queries On one typical experiment, this shaves about 3 seconds (~25%) off the overall kernel compilation time. GitHub: Closes #1370. --- .../compiler/transforms/llvm_ir_generator.py | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 0a8e95f79..ca302412d 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -124,6 +124,35 @@ class DebugInfoEmitter: "scope": scope }) + +class ABILayoutInfo: + """Caches DataLayout size/alignment lookup results. + + llvmlite's Type.get_abi_{size, alignment}() are implemented in a very + inefficient way, in particular _get_ll_pointer_type() used to construct the + corresponding llvm::Type is. We thus cache the results, optionally directly + using the compiler type as a key. + + (This is a separate class for use with @memoize.) + """ + + def __init__(self, lldatalayout, llcontext, llty_of_type): + self.cache = {} + self.lldatalayout = lldatalayout + self.llcontext = llcontext + self.llty_of_type = llty_of_type + + @memoize + def get_size_align(self, llty): + lowered = llty._get_ll_pointer_type(self.lldatalayout, self.llcontext) + return (self.lldatalayout.get_pointee_abi_size(lowered), + self.lldatalayout.get_pointee_abi_alignment(lowered)) + + @memoize + def get_size_align_for_type(self, typ): + return self.get_size_align(self.llty_of_type(typ)) + + class LLVMIRGenerator: def __init__(self, engine, module_name, target, embedding_map): self.engine = engine @@ -134,6 +163,8 @@ class LLVMIRGenerator: self.llmodule.triple = target.triple self.llmodule.data_layout = target.data_layout self.lldatalayout = llvm.create_target_data(self.llmodule.data_layout) + self.abi_layout_info = ABILayoutInfo(self.lldatalayout, self.llcontext, + self.llty_of_type) self.function_flags = None self.llfunction = None self.llmap = {} @@ -547,11 +578,8 @@ class LLVMIRGenerator: offset = 0 llrpcattrs = [] for attr in typ.attributes: - attrtyp = typ.attributes[attr] - size = self.llty_of_type(attrtyp). \ - get_abi_size(self.lldatalayout, context=self.llcontext) - alignment = self.llty_of_type(attrtyp). \ - get_abi_alignment(self.lldatalayout, context=self.llcontext) + attrtyp = typ.attributes[attr] + size, alignment = self.abi_layout_info.get_size_align_for_type(attrtyp) if offset % alignment != 0: offset += alignment - (offset % alignment) @@ -735,7 +763,7 @@ class LLVMIRGenerator: def mark_dereferenceable(self, load): assert isinstance(load, ll.LoadInstr) and isinstance(load.type, ll.PointerType) - pointee_size = load.type.pointee.get_abi_size(self.lldatalayout, context=self.llcontext) + pointee_size, _ = self.abi_layout_info.get_size_align(load.type.pointee) metadata = self.llmodule.add_metadata([ll.Constant(lli64, pointee_size)]) load.set_metadata('dereferenceable', metadata) From 1f15e550212d5456e7f672bd65b43e71295fb618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 28 Oct 2019 15:35:44 +0100 Subject: [PATCH 1960/2457] comm_analyzer: don't assume every message has data close #1377 --- artiq/coredevice/comm_analyzer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/comm_analyzer.py b/artiq/coredevice/comm_analyzer.py index 1958a4d0c..45766f340 100644 --- a/artiq/coredevice/comm_analyzer.py +++ b/artiq/coredevice/comm_analyzer.py @@ -360,8 +360,8 @@ class SPIMaster2Handler(WishboneHandler): def process_message(self, message): self.stb.set_value("1") self.stb.set_value("0") - data = message.data if isinstance(message, OutputMessage): + data = message.data address = message.address if address == 1: logger.debug("SPI config @%d data=0x%08x", From 462cf5967e0cb2c2816533bcbd5bd9da6fa0c480 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 30 Oct 2019 21:23:42 +0800 Subject: [PATCH 1961/2457] bootloader: add netboot support --- artiq/firmware/bootloader/bootloader.ld | 2 +- artiq/firmware/bootloader/main.rs | 174 +++++++++++++++++++++++- artiq/gateware/targets/kasli.py | 1 + artiq/gateware/targets/kc705.py | 1 + 4 files changed, 172 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/bootloader/bootloader.ld b/artiq/firmware/bootloader/bootloader.ld index d4976d534..3ce00544f 100644 --- a/artiq/firmware/bootloader/bootloader.ld +++ b/artiq/firmware/bootloader/bootloader.ld @@ -46,7 +46,7 @@ SECTIONS .stack : { /* Ensure we have a certain amount of space available for stack. */ - . = ORIGIN(sram) + LENGTH(sram) - 0x800; + . = ORIGIN(sram) + LENGTH(sram) - 0x1a00; . = ORIGIN(sram) + LENGTH(sram) - 4; _fstack = .; } > sram diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index f44f0b757..ea338c142 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -149,6 +149,126 @@ fn flash_boot() { } } +#[cfg(has_ethmac)] +enum NetConnState { + WaitCommand, + FirmwareLength(usize, u8), + FirmwareDownload(usize, usize), + WaitO, + WaitK +} + +#[cfg(has_ethmac)] +struct NetConn { + state: NetConnState, + firmware_downloaded: bool +} + +impl NetConn { + pub fn new() -> NetConn { + NetConn { + state: NetConnState::WaitCommand, + firmware_downloaded: false + } + } + + pub fn reset(&mut self) { + self.state = NetConnState::WaitCommand; + self.firmware_downloaded = false; + } + + // buf must contain at least one byte + // this function must consume at least one byte + fn input_partial(&mut self, buf: &[u8], mut boot_callback: impl FnMut()) -> Result { + match self.state { + NetConnState::WaitCommand => { + match buf[0] { + b'F' => { + println!("Received firmware load command"); + self.state = NetConnState::FirmwareLength(0, 0); + Ok(1) + }, + b'B' => { + if self.firmware_downloaded { + println!("Received boot command"); + boot_callback(); + self.state = NetConnState::WaitCommand; + Ok(1) + } else { + println!("Received boot command, but no firmware downloaded"); + Err(()) + } + }, + _ => { + println!("Received unknown netboot command: 0x{:02x}", buf[0]); + Err(()) + } + } + }, + NetConnState::FirmwareLength(firmware_length, recv_bytes) => { + let firmware_length = (firmware_length << 8) | (buf[0] as usize); + let recv_bytes = recv_bytes + 1; + if recv_bytes == 4 { + self.state = NetConnState::FirmwareDownload(firmware_length, 0); + } else { + self.state = NetConnState::FirmwareLength(firmware_length, recv_bytes); + } + Ok(1) + }, + NetConnState::FirmwareDownload(firmware_length, recv_bytes) => { + let max_length = firmware_length - recv_bytes; + let buf = if buf.len() > max_length { + &buf[..max_length] + } else { + &buf[..] + }; + let length = buf.len(); + + let firmware_in_sdram = unsafe { slice::from_raw_parts_mut((board_mem::MAIN_RAM_BASE + recv_bytes) as *mut u8, length) }; + firmware_in_sdram.copy_from_slice(buf); + + let recv_bytes = recv_bytes + length; + if recv_bytes == firmware_length { + self.state = NetConnState::WaitO; + Ok(length) + } else { + self.state = NetConnState::FirmwareDownload(firmware_length, recv_bytes); + Ok(length) + } + }, + NetConnState::WaitO => { + if buf[0] == b'O' { + self.state = NetConnState::WaitK; + Ok(1) + } else { + println!("End-of-firmware confirmation failed"); + Err(()) + } + }, + NetConnState::WaitK => { + if buf[0] == b'K' { + println!("Firmware successfully downloaded"); + self.state = NetConnState::WaitCommand; + self.firmware_downloaded = true; + Ok(1) + } else { + println!("End-of-firmware confirmation failed"); + Err(()) + } + } + } + } + + fn input(&mut self, buf: &[u8], mut boot_callback: impl FnMut()) -> Result<(), ()> { + let mut remaining = &buf[..]; + while !remaining.is_empty() { + let read_cnt = self.input_partial(remaining, &mut boot_callback)?; + remaining = &remaining[read_cnt..]; + } + Ok(()) + } +} + #[cfg(has_ethmac)] fn network_boot() { use smoltcp::wire::IpCidr; @@ -162,7 +282,7 @@ fn network_boot() { let neighbor_cache = smoltcp::iface::NeighborCache::new(&mut neighbor_map[..]); let net_addresses = net_settings::get_adresses(); - println!("network addresses: {}", net_addresses); + println!("Network addresses: {}", net_addresses); let mut ip_addrs = [ IpCidr::new(net_addresses.ipv4_addr, 0), IpCidr::new(net_addresses.ipv6_ll_addr, 0), @@ -185,15 +305,56 @@ fn network_boot() { .finalize() }; - let mut socket_set_storage = []; + let mut rx_storage = [0; 4096]; + let mut tx_storage = [0; 128]; + + let mut socket_set_entries: [_; 1] = Default::default(); let mut sockets = - smoltcp::socket::SocketSet::new(&mut socket_set_storage[..]); + smoltcp::socket::SocketSet::new(&mut socket_set_entries[..]); + + let tcp_rx_buffer = smoltcp::socket::TcpSocketBuffer::new(&mut rx_storage[..]); + let tcp_tx_buffer = smoltcp::socket::TcpSocketBuffer::new(&mut tx_storage[..]); + let tcp_socket = smoltcp::socket::TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer); + let tcp_handle = sockets.add(tcp_socket); + + let mut net_conn = NetConn::new(); + let mut boot_time = None; println!("Waiting for connections..."); loop { - let timestamp = smoltcp::time::Instant::from_millis(clock::get_ms() as i64); - match interface.poll(&mut sockets, timestamp) { + let timestamp = clock::get_ms() as i64; + { + let socket = &mut *sockets.get::(tcp_handle); + + match boot_time { + None => { + if !socket.is_open() { + socket.listen(4269).unwrap() // 0x10ad + } + + if socket.may_recv() { + if socket.recv(|data| { + (data.len(), net_conn.input(data, || { boot_time = Some(timestamp + 20); }).is_err()) + }).unwrap() { + net_conn.reset(); + socket.close(); + } + } else if socket.may_send() { + net_conn.reset(); + socket.close(); + } + }, + Some(boot_time) => { + if timestamp > boot_time { + println!("Starting firmware."); + unsafe { boot::jump(board_mem::MAIN_RAM_BASE) } + } + } + } + } + + match interface.poll(&mut sockets, smoltcp::time::Instant::from_millis(timestamp)) { Ok(_) => (), Err(smoltcp::Error::Unrecognized) => (), Err(err) => println!("Network error: {}", err) @@ -214,6 +375,8 @@ pub extern fn main() -> i32 { println!("Copyright (c) 2017-2019 M-Labs Limited"); println!(""); + clock::init(); + if startup() { println!(""); flash_boot(); @@ -223,6 +386,7 @@ pub extern fn main() -> i32 { println!("Halting."); } + println!("No boot medium."); loop {} } diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 630108088..0055c607f 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -100,6 +100,7 @@ class StandaloneBase(MiniSoC, AMPSoC): cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, + integrated_sram_size=8192, ethmac_nrxslots=4, ethmac_ntxslots=4, **kwargs) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index d2e2ca0c3..b586edda4 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -124,6 +124,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, + integrated_sram_size=8192, ethmac_nrxslots=4, ethmac_ntxslots=4, **kwargs) From 88dbff46f4f1a6b487384e97ee46608d84019a68 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 30 Oct 2019 21:24:51 +0800 Subject: [PATCH 1962/2457] add netboot tool --- artiq/frontend/artiq_netboot.py | 38 +++++++++++++++++++++++++++++++++ setup.py | 1 + 2 files changed, 39 insertions(+) create mode 100755 artiq/frontend/artiq_netboot.py diff --git a/artiq/frontend/artiq_netboot.py b/artiq/frontend/artiq_netboot.py new file mode 100755 index 000000000..ef36ad743 --- /dev/null +++ b/artiq/frontend/artiq_netboot.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 + +import argparse +import socket +import struct +import os +import time + +def main(): + parser = argparse.ArgumentParser(description="ARTIQ netboot tool") + parser.add_argument("hostname", metavar="HOSTNAME", + help="hostname of the target board") + parser.add_argument("-f", "--firmware", nargs=1, + help="firmware to load") + parser.add_argument("-b", "--boot", action="store_true", + help="boot the device") + args = parser.parse_args() + + sock = socket.create_connection((args.hostname, 4269)) + try: + if args.firmware is not None: + with open(args.firmware[0], "rb") as input_file: + sock.sendall(b"F") + sock.sendall(struct.pack(">I", os.fstat(input_file.fileno()).st_size)) + while True: + data = input_file.read(4096) + if not data: + break + sock.sendall(data) + sock.sendall(b"OK") + if args.boot: + sock.sendall(b"B") + finally: + sock.close() + + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index 7137bce4f..da895fa89 100755 --- a/setup.py +++ b/setup.py @@ -25,6 +25,7 @@ console_scripts = [ "artiq_coremgmt = artiq.frontend.artiq_coremgmt:main", "artiq_ctlmgr = artiq.frontend.artiq_ctlmgr:main", "artiq_ddb_template = artiq.frontend.artiq_ddb_template:main", + "artiq_netboot = artiq.frontend.artiq_netboot:main", "artiq_devtool = artiq.frontend.artiq_devtool:main", "artiq_influxdb = artiq.frontend.artiq_influxdb:main", "artiq_influxdb_schedule = artiq.frontend.artiq_influxdb_schedule:main", From c96de7454d55b07dbcd0fb8240b20cf22cf3d622 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 30 Oct 2019 21:26:26 +0800 Subject: [PATCH 1963/2457] remove artiq_devtool --- DEVELOPER_NOTES.rst | 26 --- RELEASE_NOTES.rst | 1 + artiq/frontend/artiq_devtool.py | 283 -------------------------------- setup.py | 1 - 4 files changed, 1 insertion(+), 310 deletions(-) delete mode 100755 artiq/frontend/artiq_devtool.py diff --git a/DEVELOPER_NOTES.rst b/DEVELOPER_NOTES.rst index 318415c39..634ee2471 100644 --- a/DEVELOPER_NOTES.rst +++ b/DEVELOPER_NOTES.rst @@ -36,32 +36,6 @@ The board lock file also contains the openocd commands for selecting the corresp artiq_flash -I "$(cat /var/lib/artiq/boards/sayma-1)" -Using developer tools -===================== - -ARTIQ ships with an ``artiq_devtool`` binary, which automates common actions arising when developing the board gateware and firmware on a machine other than the one to which the board is connected. - -.. argparse:: - :ref: artiq.frontend.artiq_devtool.get_argparser - :prog: artiq_devtool - -To build and flash the firmware for ``sayma_amc_standalone`` target: -:: - artiq_devtool -t sayma_amc_standalone build flash+log - -To build the same target, flash it to the 3rd connected board, and forward the core device ports (1380, 1381, ...) as well as logs on the serial port: -:: - artiq_devtool -t sayma_amc_standalone -b sayma-3 build flash connect - -While the previous command is running, to build a new firmware and hotswap it, i.e. run without reflashing the board: -:: - artiq_devtool -t sayma_amc_standalone build hotswap - -While the previous command is running, to reset a board, e.g. if it became unresponsive: -:: - artiq_devtool -t sayma_amc_standalone reset - - Deleting git branches ===================== diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 82fd78832..a57645d9e 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -33,6 +33,7 @@ ARTIQ-5 from EEPROM if `mac` is absent from the flash config. * The ``-e/--experiment`` switch of ``artiq_run`` and ``artiq_compile`` has been renamed ``-c/--class-name``. +* ``artiq_devtool`` has been removed. ARTIQ-4 diff --git a/artiq/frontend/artiq_devtool.py b/artiq/frontend/artiq_devtool.py deleted file mode 100755 index e23f766fe..000000000 --- a/artiq/frontend/artiq_devtool.py +++ /dev/null @@ -1,283 +0,0 @@ -#!/usr/bin/env python3 - -# This script makes the following assumptions: -# * miniconda is installed remotely at ~/miniconda -# * misoc and artiq are installed remotely via conda - -import sys -import argparse -import logging -import subprocess -import socket -import select -import threading -import os -import shutil -import re -import shlex - -from artiq.tools import add_common_args, init_logger -from artiq.remoting import SSHClient -from artiq.coredevice.comm_mgmt import CommMgmt - -logger = logging.getLogger(__name__) - - -def get_argparser(): - parser = argparse.ArgumentParser( - description="ARTIQ core device development tool", - formatter_class=argparse.ArgumentDefaultsHelpFormatter) - - add_common_args(parser) - - parser.add_argument("-t", "--target", metavar="TARGET", - type=str, default="kasli", - help="target to build, one of: " - "kc705 kasli sayma") - parser.add_argument("-V", "--variant", metavar="VARIANT", - type=str, default=None, - help="variant to build, dependent on the target") - parser.add_argument("-g", "--gateware", - default=False, action="store_true", - help="build/flash gateware, not just software") - parser.add_argument("--args", metavar="ARGS", - type=shlex.split, default=[], - help="extra arguments for gateware/firmware build") - - parser.add_argument("-H", "--host", - type=str, default="lab.m-labs.hk", - help="SSH host where the development board is located") - parser.add_argument("-J", "--jump", - type=str, default=None, - help="SSH host to jump through") - parser.add_argument("-b", "--board", - type=str, default="{board_type}-1", - help="board to connect to on the development SSH host") - parser.add_argument("-B", "--board-file", - type=str, default="/var/lib/artiq/boards/{board}", - help="the board file containing the openocd initialization commands; " - "it is also used as the lock file") - parser.add_argument("-s", "--serial", - type=str, default="/dev/ttyUSB_{board}", - help="TTY device corresponding to the development board") - parser.add_argument("-d", "--device", - type=str, default="{board}", - help="address or domain corresponding to the development board") - parser.add_argument("-w", "--wait", action="store_true", - help="wait for the board to unlock instead of aborting the actions") - - parser.add_argument("actions", metavar="ACTION", - type=str, default=[], nargs="+", - help="actions to perform, sequence of: " - "build clean reset flash flash+log load connect hotswap") - - return parser - - -def main(): - args = get_argparser().parse_args() - init_logger(args) - if args.verbose == args.quiet == 0: - logging.getLogger().setLevel(logging.INFO) - - def build_dir(*path, target=args.target): - return os.path.join("/tmp/", "artiq_" + target, *path) - - if args.target == "kc705": - board_type, firmware = "kc705", "runtime" - variant = "nist_clock" if args.variant is None else args.variant - elif args.target == "sayma": - board_type, firmware = "sayma", "runtime" - variant = "standalone" if args.variant is None else args.variant - elif args.target == "kasli": - board_type, firmware = "kasli", "runtime" - variant = "tester" if args.variant is None else args.variant - else: - raise NotImplementedError("unknown target {}".format(args.target)) - - board = args.board.format(board_type=board_type) - board_file = args.board_file.format(board=board) - device = args.device.format(board=board, host=args.host) - serial = args.serial.format(board=board) - - client = SSHClient(args.host, args.jump) - - flock_acquired = False - flock_file = None # GC root - def lock(): - nonlocal flock_acquired - nonlocal flock_file - - if not flock_acquired: - fuser_args = ["fuser", "-u", board_file] - fuser = client.spawn_command(fuser_args) - fuser_file = fuser.makefile('r') - fuser_match = re.search(r"\((.+?)\)", fuser_file.readline()) - if fuser_match and fuser_match.group(1) == os.getenv("USER"): - logger.info("Lock already acquired by {}".format(os.getenv("USER"))) - flock_acquired = True - return - - logger.info("Acquiring device lock") - flock_args = ["flock"] - if not args.wait: - flock_args.append("--nonblock") - flock_args += ["--verbose", board_file] - flock_args += ["sleep", "86400"] - - flock = client.spawn_command(flock_args, get_pty=True) - flock_file = flock.makefile('r') - while not flock_acquired: - line = flock_file.readline() - if not line: - break - logger.debug(line.rstrip()) - if line.startswith("flock: executing"): - flock_acquired = True - elif line.startswith("flock: failed"): - logger.error("Failed to get lock") - sys.exit(1) - - def command(*args, on_failure="Command failed"): - logger.debug("Running {}".format(" ".join([shlex.quote(arg) for arg in args]))) - try: - subprocess.check_call(args) - except subprocess.CalledProcessError: - logger.error(on_failure) - sys.exit(1) - - def build(target, *extra_args, output_dir=build_dir(), variant=variant): - build_args = ["python3", "-m", "artiq.gateware.targets." + target, *extra_args] - if not args.gateware: - build_args.append("--no-compile-gateware") - if variant: - build_args += ["--variant", variant] - build_args += ["--output-dir", output_dir] - command(*build_args, on_failure="Build failed") - - def flash(*steps): - lock() - - flash_args = ["artiq_flash"] - for _ in range(args.verbose): - flash_args.append("-v") - flash_args += ["-H", args.host] - if args.jump: - flash_args += ["-J", args.jump] - flash_args += ["-t", board_type] - flash_args += ["-V", variant] - flash_args += ["-I", "source {}".format(board_file)] - flash_args += ["--srcbuild", build_dir()] - flash_args += steps - command(*flash_args, on_failure="Flashing failed") - - for action in args.actions: - if action == "build": - logger.info("Building target") - if args.target == "sayma": - build("sayma_rtm", output_dir=build_dir("rtm_gateware"), variant=None) - build("sayma_amc", "--rtm-csr-csv", build_dir("rtm_gateware", "rtm_csr.csv")) - else: - build(args.target) - - elif action == "clean": - logger.info("Cleaning build directory") - shutil.rmtree(build_dir(), ignore_errors=True) - - elif action == "reset": - logger.info("Resetting device") - flash("start") - - elif action == "flash": - gateware = ["gateware"] if args.gateware else [] - - logger.info("Flashing and booting") - flash(*gateware, "bootloader", "firmware", "start") - - elif action == "flash+log": - gateware = ["gateware"] if args.gateware else [] - - logger.info("Flashing") - flash(*gateware, "bootloader", "firmware") - - flterm = client.spawn_command(["flterm", serial, "--output-only"]) - logger.info("Booting") - flash("start") - client.drain(flterm) - - elif action == "load": - logger.info("Loading gateware") - flash("load") - - elif action == "connect": - lock() - - transport = client.get_transport() - transport.set_keepalive(30) - - def forwarder(local_stream, remote_stream): - try: - while True: - r, _, _ = select.select([local_stream, remote_stream], [], []) - if local_stream in r: - data = local_stream.recv(65535) - if data == b"": - break - remote_stream.sendall(data) - if remote_stream in r: - data = remote_stream.recv(65535) - if data == b"": - break - local_stream.sendall(data) - except Exception as err: - logger.error("Cannot forward on port %s: %s", port, repr(err)) - local_stream.close() - remote_stream.close() - - def listener(port): - listener = socket.socket() - listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - listener.bind(('localhost', port)) - listener.listen(8) - while True: - local_stream, peer_addr = listener.accept() - logger.info("Accepting %s:%s and opening SSH channel to %s:%s", - *peer_addr, device, port) - try: - remote_stream = \ - transport.open_channel('direct-tcpip', (device, port), peer_addr) - except Exception: - logger.exception("Cannot open channel on port %s", port) - continue - - thread = threading.Thread(target=forwarder, args=(local_stream, remote_stream), - name="forward-{}".format(port), daemon=True) - thread.start() - - ports = [1380, 1381, 1382, 1383] - for port in ports: - thread = threading.Thread(target=listener, args=(port,), - name="listen-{}".format(port), daemon=True) - thread.start() - - logger.info("Forwarding ports {} to core device and logs from core device" - .format(", ".join(map(str, ports)))) - client.run_command(["flterm", serial, "--output-only"]) - - elif action == "hotswap": - lock() - - logger.info("Hotswapping firmware") - firmware = build_dir(variant, "software", firmware, firmware + ".bin") - - mgmt = CommMgmt(device) - mgmt.open(ssh_transport=client.get_transport()) - with open(firmware, "rb") as f: - mgmt.hotswap(f.read()) - - else: - logger.error("Unknown action {}".format(action)) - sys.exit(1) - -if __name__ == "__main__": - main() diff --git a/setup.py b/setup.py index da895fa89..a2b470e0a 100755 --- a/setup.py +++ b/setup.py @@ -26,7 +26,6 @@ console_scripts = [ "artiq_ctlmgr = artiq.frontend.artiq_ctlmgr:main", "artiq_ddb_template = artiq.frontend.artiq_ddb_template:main", "artiq_netboot = artiq.frontend.artiq_netboot:main", - "artiq_devtool = artiq.frontend.artiq_devtool:main", "artiq_influxdb = artiq.frontend.artiq_influxdb:main", "artiq_influxdb_schedule = artiq.frontend.artiq_influxdb_schedule:main", "artiq_master = artiq.frontend.artiq_master:main", From 3042476230871cf464d663fae92cb3bf4637c7c3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 30 Oct 2019 21:29:33 +0800 Subject: [PATCH 1964/2457] artiq_netboot: remove unnecessary import --- artiq/frontend/artiq_netboot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/frontend/artiq_netboot.py b/artiq/frontend/artiq_netboot.py index ef36ad743..9adcc294a 100755 --- a/artiq/frontend/artiq_netboot.py +++ b/artiq/frontend/artiq_netboot.py @@ -4,7 +4,6 @@ import argparse import socket import struct import os -import time def main(): parser = argparse.ArgumentParser(description="ARTIQ netboot tool") From dc71039934dd2741ee87593822c50e5400e12d24 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 30 Oct 2019 21:36:00 +0800 Subject: [PATCH 1965/2457] sayma, metlino: increase integrated_sram_size on Ethernet-enabled variants --- artiq/gateware/targets/metlino.py | 1 + artiq/gateware/targets/sayma_amc.py | 1 + 2 files changed, 2 insertions(+) diff --git a/artiq/gateware/targets/metlino.py b/artiq/gateware/targets/metlino.py index 126565ef2..999bfaaf6 100755 --- a/artiq/gateware/targets/metlino.py +++ b/artiq/gateware/targets/metlino.py @@ -43,6 +43,7 @@ class Master(MiniSoC, AMPSoC): cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, + integrated_sram_size=8192, ethmac_nrxslots=4, ethmac_ntxslots=4, **kwargs) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 96e12faf3..b3533081e 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -340,6 +340,7 @@ class Master(MiniSoC, AMPSoC): cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, + integrated_sram_size=8192, ethmac_nrxslots=4, ethmac_ntxslots=4, **kwargs) From 228e44a059ef46fd8924a7393bfb687ff28013fa Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 30 Oct 2019 21:39:00 +0800 Subject: [PATCH 1966/2457] sayma: enable Ethernet on DRTIO satellite variant So that netboot can be used in bootloader. --- artiq/gateware/targets/sayma_amc.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index b3533081e..3694068fb 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -45,17 +45,20 @@ class RTMUARTForward(Module): ] -class SatelliteBase(BaseSoC): +class SatelliteBase(MiniSoC): mem_map = { "drtioaux": 0x14000000, } - mem_map.update(BaseSoC.mem_map) + mem_map.update(MiniSoC.mem_map) def __init__(self, rtio_clk_freq=125e6, identifier_suffix="", **kwargs): - BaseSoC.__init__(self, + MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, + integrated_sram_size=8192, + ethmac_nrxslots=4, + ethmac_ntxslots=4, **kwargs) add_identifier(self, suffix=identifier_suffix) self.rtio_clk_freq = rtio_clk_freq From bc050fdeec9fb0c5cd98fa7a74fd7abc35d1124e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 30 Oct 2019 21:46:06 +0800 Subject: [PATCH 1967/2457] bootloader: treat zero-length firmware in flash as no firmware --- artiq/firmware/bootloader/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index ea338c142..2c7e8a959 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -120,7 +120,7 @@ fn flash_boot() { let length = BigEndian::read_u32(&header[0..]) as usize; let expected_crc = BigEndian::read_u32(&header[4..]); - if length == 0xffffffff { + if length == 0 || length == 0xffffffff { println!("No firmware present"); return } else if length > 4 * 1024 * 1024 { From 9a35a2ed81b8ff6d8c95b703c1aebe3d27903aff Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 30 Oct 2019 22:02:16 +0800 Subject: [PATCH 1968/2457] test_frontends: update --- artiq/test/test_frontends.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/test_frontends.py b/artiq/test/test_frontends.py index c80228294..243f42ac3 100644 --- a/artiq/test/test_frontends.py +++ b/artiq/test/test_frontends.py @@ -14,7 +14,7 @@ class TestFrontends(unittest.TestCase): ], "artiq": [ "client", "compile", "coreanalyzer", "coremgmt", "ctlmgr", - "devtool", "flash", "influxdb", "master", "mkfs", "route", + "netboot", "flash", "influxdb", "master", "mkfs", "route", "rpctool", "rtiomon", "run", "session" ] } From 389a8f587a459a1e2f26f3c4fd349b61cc6b6793 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 31 Oct 2019 11:50:53 +0800 Subject: [PATCH 1969/2457] slave_fpga: modularize --- artiq/firmware/libboard_artiq/slave_fpga.rs | 49 ++++++++++++++------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/artiq/firmware/libboard_artiq/slave_fpga.rs b/artiq/firmware/libboard_artiq/slave_fpga.rs index a400af440..6a56e527a 100644 --- a/artiq/firmware/libboard_artiq/slave_fpga.rs +++ b/artiq/firmware/libboard_artiq/slave_fpga.rs @@ -24,21 +24,7 @@ unsafe fn shift_u8(data: u8) { } } -pub fn load() -> Result<(), &'static str> { - info!("Loading slave FPGA gateware..."); - - let header = unsafe { slice::from_raw_parts(GATEWARE, 8) }; - - let magic = BigEndian::read_u32(&header[0..]); - let length = BigEndian::read_u32(&header[4..]) as usize; - info!(" magic: 0x{:08x}, length: 0x{:08x}", magic, length); - if magic != 0x5352544d { // "SRTM", see sayma_rtm target as well - return Err("Bad magic"); - } - if length > 0x220000 { - return Err("Too large (corrupted?)"); - } - +pub fn prepare() -> Result<(), &'static str> { unsafe { if csr::slave_fpga_cfg::in_read() & DONE_BIT != 0 { info!(" DONE before loading"); @@ -61,14 +47,24 @@ pub fn load() -> Result<(), &'static str> { if csr::slave_fpga_cfg::in_read() & DONE_BIT != 0 { return Err("DONE high despite PROGRAM"); } + } + Ok(()) +} - for i in slice::from_raw_parts(GATEWARE.offset(8), length) { +pub fn input(data: &[u8]) -> Result<(), &'static str> { + unsafe { + for i in data { shift_u8(*i); if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { return Err("INIT asserted during load"); } } + } + Ok(()) +} +pub fn complete() -> Result<(), &'static str> { + unsafe { let t = clock::get_ms(); while csr::slave_fpga_cfg::in_read() & DONE_BIT == 0 { if clock::get_ms() > t + 100 { @@ -80,6 +76,27 @@ pub fn load() -> Result<(), &'static str> { csr::slave_fpga_cfg::out_write(PROGRAM_B_BIT); csr::slave_fpga_cfg::oe_write(PROGRAM_B_BIT); } + Ok(()) +} + +pub fn load() -> Result<(), &'static str> { + info!("Loading slave FPGA gateware..."); + + let header = unsafe { slice::from_raw_parts(GATEWARE, 8) }; + + let magic = BigEndian::read_u32(&header[0..]); + let length = BigEndian::read_u32(&header[4..]) as usize; + info!(" magic: 0x{:08x}, length: 0x{:08x}", magic, length); + if magic != 0x5352544d { // "SRTM", see sayma_rtm target as well + return Err("Bad magic"); + } + if length > 0x220000 { + return Err("Too large (corrupted?)"); + } + + prepare()?; + input(unsafe { slice::from_raw_parts(GATEWARE.offset(8), length) })?; + complete()?; info!(" ...done"); Ok(()) From a78e493b728174b77bbf751e3d474fa60cbcec8a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 31 Oct 2019 12:42:09 +0800 Subject: [PATCH 1970/2457] firmware: load slave FPGA in bootloader --- artiq/firmware/bootloader/main.rs | 41 +++++++++++++++++++ artiq/firmware/libboard_artiq/lib.rs | 2 - artiq/firmware/libboard_misoc/lib.rs | 4 ++ .../slave_fpga.rs | 33 ++------------- artiq/firmware/runtime/main.rs | 3 -- artiq/firmware/satman/main.rs | 3 -- 6 files changed, 48 insertions(+), 38 deletions(-) rename artiq/firmware/{libboard_artiq => libboard_misoc}/slave_fpga.rs (71%) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 2c7e8a959..84fde93ac 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -11,6 +11,8 @@ use core::{ptr, slice}; use crc::crc32; use byteorder::{ByteOrder, BigEndian}; use board_misoc::{ident, cache, sdram, boot, mem as board_mem}; +#[cfg(has_slave_fpga_cfg)] +use board_misoc::slave_fpga; #[cfg(has_ethmac)] use board_misoc::{clock, ethmac, net_settings}; use board_misoc::uart_console::Console; @@ -110,6 +112,43 @@ fn startup() -> bool { true } +#[cfg(has_slave_fpga_cfg)] +fn load_slave_fpga() { + println!("Loading slave FPGA gateware..."); + + const GATEWARE: *mut u8 = board_misoc::csr::CONFIG_SLAVE_FPGA_GATEWARE as *mut u8; + + let header = unsafe { slice::from_raw_parts(GATEWARE, 8) }; + let magic = BigEndian::read_u32(&header[0..]); + let length = BigEndian::read_u32(&header[4..]) as usize; + println!(" magic: 0x{:08x}, length: 0x{:08x}", magic, length); + if magic != 0x5352544d { + println!(" ...Error: bad magic"); + return + } + if length > 0x220000 { + println!(" ...Error: too long (corrupted?)"); + return + } + let payload = unsafe { slice::from_raw_parts(GATEWARE.offset(8), length) }; + + if let Err(e) = slave_fpga::prepare() { + println!(" ...Error during preparation: {}", e); + return + } + if let Err(e) = slave_fpga::input(payload) { + println!(" ...Error during loading: {}", e); + return + } + if let Err(e) = slave_fpga::complete() { + println!(" ...Error during completion: {}", e); + return + } + + println!(" ...done"); +} + + fn flash_boot() { const FIRMWARE: *mut u8 = board_mem::FLASH_BOOT_ADDRESS as *mut u8; const MAIN_RAM: *mut u8 = board_mem::MAIN_RAM_BASE as *mut u8; @@ -379,6 +418,8 @@ pub extern fn main() -> i32 { if startup() { println!(""); + #[cfg(has_slave_fpga_cfg)] + load_slave_fpga(); flash_boot(); #[cfg(has_ethmac)] network_boot(); diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 9a4e727b2..b9666732d 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -27,8 +27,6 @@ pub mod rpc_queue; #[cfg(has_si5324)] pub mod si5324; -#[cfg(has_slave_fpga_cfg)] -pub mod slave_fpga; #[cfg(has_hmc830_7043)] pub mod hmc830_7043; #[cfg(has_ad9154)] diff --git a/artiq/firmware/libboard_misoc/lib.rs b/artiq/firmware/libboard_misoc/lib.rs index b49a69446..8abddf898 100644 --- a/artiq/firmware/libboard_misoc/lib.rs +++ b/artiq/firmware/libboard_misoc/lib.rs @@ -27,8 +27,10 @@ pub mod uart; pub mod spiflash; pub mod config; #[cfg(feature = "uart_console")] +#[macro_use] pub mod uart_console; #[cfg(all(feature = "uart_console", feature = "log"))] +#[macro_use] pub mod uart_logger; #[cfg(all(has_ethmac, feature = "smoltcp"))] pub mod ethmac; @@ -37,3 +39,5 @@ pub mod i2c; pub mod i2c_eeprom; #[cfg(all(has_ethmac, feature = "smoltcp"))] pub mod net_settings; +#[cfg(has_slave_fpga_cfg)] +pub mod slave_fpga; diff --git a/artiq/firmware/libboard_artiq/slave_fpga.rs b/artiq/firmware/libboard_misoc/slave_fpga.rs similarity index 71% rename from artiq/firmware/libboard_artiq/slave_fpga.rs rename to artiq/firmware/libboard_misoc/slave_fpga.rs index 6a56e527a..40c6795e0 100644 --- a/artiq/firmware/libboard_artiq/slave_fpga.rs +++ b/artiq/firmware/libboard_misoc/slave_fpga.rs @@ -1,6 +1,4 @@ -use board_misoc::{csr, clock}; -use core::slice; -use byteorder::{ByteOrder, BigEndian}; +use super::{csr, clock}; const CCLK_BIT: u8 = 1 << 0; const DIN_BIT: u8 = 1 << 1; @@ -8,8 +6,6 @@ const DONE_BIT: u8 = 1 << 2; const INIT_B_BIT: u8 = 1 << 3; const PROGRAM_B_BIT: u8 = 1 << 4; -const GATEWARE: *mut u8 = csr::CONFIG_SLAVE_FPGA_GATEWARE as *mut u8; - unsafe fn shift_u8(data: u8) { for i in 0..8 { let mut bits: u8 = PROGRAM_B_BIT; @@ -27,10 +23,10 @@ unsafe fn shift_u8(data: u8) { pub fn prepare() -> Result<(), &'static str> { unsafe { if csr::slave_fpga_cfg::in_read() & DONE_BIT != 0 { - info!(" DONE before loading"); + println!(" DONE before loading"); } if csr::slave_fpga_cfg::in_read() & INIT_B_BIT == 0 { - info!(" INIT asserted before loading"); + println!(" INIT asserted before loading"); } csr::slave_fpga_cfg::out_write(0); @@ -78,26 +74,3 @@ pub fn complete() -> Result<(), &'static str> { } Ok(()) } - -pub fn load() -> Result<(), &'static str> { - info!("Loading slave FPGA gateware..."); - - let header = unsafe { slice::from_raw_parts(GATEWARE, 8) }; - - let magic = BigEndian::read_u32(&header[0..]); - let length = BigEndian::read_u32(&header[4..]) as usize; - info!(" magic: 0x{:08x}, length: 0x{:08x}", magic, length); - if magic != 0x5352544d { // "SRTM", see sayma_rtm target as well - return Err("Bad magic"); - } - if length > 0x220000 { - return Err("Too large (corrupted?)"); - } - - prepare()?; - input(unsafe { slice::from_raw_parts(GATEWARE.offset(8), length) })?; - complete()?; - - info!(" ...done"); - Ok(()) -} diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 0f24877d8..d7f983090 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -89,9 +89,6 @@ fn setup_log_levels() { } fn sayma_hw_init() { - #[cfg(has_slave_fpga_cfg)] - board_artiq::slave_fpga::load().expect("cannot load RTM FPGA gateware"); - #[cfg(has_hmc830_7043)] /* must be the first SPI init because of HMC830 SPI mode selection */ board_artiq::hmc830_7043::init().expect("cannot initialize HMC830/7043"); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 98cc844c9..dc66038c7 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -448,9 +448,6 @@ pub extern fn main() -> i32 { info!("software ident {}", csr::CONFIG_IDENTIFIER_STR); info!("gateware ident {}", ident::read(&mut [0; 64])); - #[cfg(has_slave_fpga_cfg)] - board_artiq::slave_fpga::load().expect("cannot load RTM FPGA gateware"); - i2c::init().expect("I2C initialization failed"); si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324"); unsafe { From 42af76326f7ef7e85d935a8d677dc3f87b5fbea9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 1 Nov 2019 10:15:11 +0800 Subject: [PATCH 1971/2457] kasli: enlarge integrated CPU SRAM for DRTIO masters Required by the bootloader netboot support. --- artiq/gateware/targets/kasli.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 0055c607f..356497d6b 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -279,6 +279,7 @@ class MasterBase(MiniSoC, AMPSoC): cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, + integrated_sram_size=8192, ethmac_nrxslots=4, ethmac_ntxslots=4, **kwargs) From deadfead2a91010e663088f144472cb432c76fa0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 1 Nov 2019 10:17:12 +0800 Subject: [PATCH 1972/2457] bootloader: fix !has_ethmac --- artiq/firmware/bootloader/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 84fde93ac..59a29aa99 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -203,6 +203,7 @@ struct NetConn { firmware_downloaded: bool } +#[cfg(has_ethmac)] impl NetConn { pub fn new() -> NetConn { NetConn { @@ -414,6 +415,7 @@ pub extern fn main() -> i32 { println!("Copyright (c) 2017-2019 M-Labs Limited"); println!(""); + #[cfg(has_ethmac)] clock::init(); if startup() { From 5362f92b396affd292b031478b41854e52902358 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 1 Nov 2019 10:21:49 +0800 Subject: [PATCH 1973/2457] bootloader: disable minimum stack space check in linker script * The value varies greatly whether netboot is enabled or not. * There is no simple solution to detect has_ethmac in the linker script and set the value accordingly. * The space check is an imperfect solution that will be superseded by stack pointer limits. * Left commented out so we can re-enable it manually during development if stack corruption is suspected. --- artiq/firmware/bootloader/bootloader.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/bootloader/bootloader.ld b/artiq/firmware/bootloader/bootloader.ld index 3ce00544f..22aea8cb6 100644 --- a/artiq/firmware/bootloader/bootloader.ld +++ b/artiq/firmware/bootloader/bootloader.ld @@ -46,7 +46,7 @@ SECTIONS .stack : { /* Ensure we have a certain amount of space available for stack. */ - . = ORIGIN(sram) + LENGTH(sram) - 0x1a00; + /*. = ORIGIN(sram) + LENGTH(sram) - 0x1a00; */ . = ORIGIN(sram) + LENGTH(sram) - 4; _fstack = .; } > sram From 29b4d87943b42155ba7707ec98ae6576dfab1f86 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 1 Nov 2019 10:28:41 +0800 Subject: [PATCH 1974/2457] firmware: add cargosha256.nix --- artiq/firmware/cargosha256.nix | 1 + 1 file changed, 1 insertion(+) create mode 100644 artiq/firmware/cargosha256.nix diff --git a/artiq/firmware/cargosha256.nix b/artiq/firmware/cargosha256.nix new file mode 100644 index 000000000..c356e4291 --- /dev/null +++ b/artiq/firmware/cargosha256.nix @@ -0,0 +1 @@ +"1xzjn9i4rkd9124v2gbdplsgsvp1hlx7czdgc58n316vsnrkbr86" From 98854473ddd6296f00ecc013c074f4423d006eab Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 2 Nov 2019 12:12:32 +0800 Subject: [PATCH 1975/2457] sayma_amc: use all transceivers on master (#1230) --- artiq/gateware/targets/sayma_amc.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 3694068fb..95d2347b0 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -369,8 +369,7 @@ class Master(MiniSoC, AMPSoC): self.submodules.drtio_transceiver = gth_ultrascale.GTH( clock_pads=platform.request("cdr_clk_clean", 0), data_pads=[platform.request("sfp", 0)] + - # 6 and not 8 to work around Vivado bug (Xilinx CR 1020646) - [platform.request("rtm_gth", i) for i in range(6)], + [platform.request("rtm_gth", i) for i in range(8)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") From e2f9f59472f1ca7840f9fa562fba6cfa940f6f3c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Nov 2019 15:18:58 +0800 Subject: [PATCH 1976/2457] artiq_flash: fix flashing Sayma RTM from package --- artiq/frontend/artiq_flash.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index b7cd7fa42..81e0e6b2c 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -364,6 +364,11 @@ def main(): variant_dir = variant else: variant_dir = args.target + "-" + variant + if args.target == "sayma": + if args.srcbuild: + rtm_variant_dir = variant + else: + rtm_variant_dir = "sayma-rtm" if args.host is None: client = LocalClient() @@ -405,7 +410,7 @@ def main(): programmer.write_binary(*config["gateware"], gateware_bin) if args.target == "sayma" and variant != "master": rtm_gateware_bin = convert_gateware( - artifact_path("rtm", "gateware", "top.bit"), header=True) + artifact_path(rtm_variant_dir, "gateware", "top.bit"), header=True) programmer.write_binary(*config["rtm_gateware"], rtm_gateware_bin) elif action == "bootloader": @@ -425,7 +430,7 @@ def main(): elif action == "load": if args.target == "sayma": if variant != "simplesatellite" and variant != "master": - rtm_gateware_bit = artifact_path("rtm", "gateware", "top.bit") + rtm_gateware_bit = artifact_path(rtm_variant_dir, "gateware", "top.bit") programmer.load(rtm_gateware_bit, 0) gateware_bit = artifact_path(variant_dir, "gateware", "top.bit") programmer.load(gateware_bit, 1) From 9dc82bd7668adfc1f9e1ff29cc26f8fadaed6f09 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Nov 2019 15:31:08 +0800 Subject: [PATCH 1977/2457] bootloader: add no_flash_boot config option to force network boot --- artiq/firmware/bootloader/main.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 59a29aa99..3d2ae4fbd 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -14,7 +14,7 @@ use board_misoc::{ident, cache, sdram, boot, mem as board_mem}; #[cfg(has_slave_fpga_cfg)] use board_misoc::slave_fpga; #[cfg(has_ethmac)] -use board_misoc::{clock, ethmac, net_settings}; +use board_misoc::{clock, ethmac, config, net_settings}; use board_misoc::uart_console::Console; fn check_integrity() -> bool { @@ -420,9 +420,13 @@ pub extern fn main() -> i32 { if startup() { println!(""); - #[cfg(has_slave_fpga_cfg)] - load_slave_fpga(); - flash_boot(); + if !config::read_str("no_flash_boot", |r| r == Ok("1")) { + #[cfg(has_slave_fpga_cfg)] + load_slave_fpga(); + flash_boot(); + } else { + println!("Flash booting has been disabled."); + } #[cfg(has_ethmac)] network_boot(); } else { From 307f39e9004939a09113ba3f88b11be797dc44b9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Nov 2019 15:46:07 +0800 Subject: [PATCH 1978/2457] remoting: fix multiuser access. Closes #1383 --- artiq/remoting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/remoting.py b/artiq/remoting.py index 2c5f8af31..24e53b53a 100644 --- a/artiq/remoting.py +++ b/artiq/remoting.py @@ -7,6 +7,7 @@ import shlex import subprocess import hashlib import random +import getpass __all__ = ["LocalClient", "SSHClient"] @@ -62,7 +63,7 @@ class SSHClient(Client): self.jump_host = jump_host self.ssh = None self.sftp = None - self._tmpr = "/tmp/artiq" + self._tmpr = "/tmp/artiq-" + getpass.getuser() self._tmpl = tempfile.TemporaryDirectory(prefix="artiq") self._cached = [] self._downloads = {} From b25a17fa370a061fd9638871263dd118dec09c43 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Nov 2019 16:28:49 +0800 Subject: [PATCH 1979/2457] netboot: support slave FPGA loading --- artiq/firmware/bootloader/main.rs | 97 +++++++++++++++++++-- artiq/firmware/libboard_misoc/slave_fpga.rs | 2 +- artiq/frontend/artiq_netboot.py | 31 +++++-- 3 files changed, 111 insertions(+), 19 deletions(-) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 3d2ae4fbd..facc2a72e 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -140,15 +140,14 @@ fn load_slave_fpga() { println!(" ...Error during loading: {}", e); return } - if let Err(e) = slave_fpga::complete() { - println!(" ...Error during completion: {}", e); + if let Err(e) = slave_fpga::startup() { + println!(" ...Error during startup: {}", e); return } println!(" ...done"); } - fn flash_boot() { const FIRMWARE: *mut u8 = board_mem::FLASH_BOOT_ADDRESS as *mut u8; const MAIN_RAM: *mut u8 = board_mem::MAIN_RAM_BASE as *mut u8; @@ -193,8 +192,16 @@ enum NetConnState { WaitCommand, FirmwareLength(usize, u8), FirmwareDownload(usize, usize), - WaitO, - WaitK + FirmwareWaitO, + FirmwareWaitK, + #[cfg(has_slave_fpga_cfg)] + GatewareLength(usize, u8), + #[cfg(has_slave_fpga_cfg)] + GatewareDownload(usize, usize), + #[cfg(has_slave_fpga_cfg)] + GatewareWaitO, + #[cfg(has_slave_fpga_cfg)] + GatewareWaitK } #[cfg(has_ethmac)] @@ -228,6 +235,12 @@ impl NetConn { self.state = NetConnState::FirmwareLength(0, 0); Ok(1) }, + #[cfg(has_slave_fpga_cfg)] + b'G' => { + println!("Received gateware load command"); + self.state = NetConnState::GatewareLength(0, 0); + Ok(1) + } b'B' => { if self.firmware_downloaded { println!("Received boot command"); @@ -245,6 +258,7 @@ impl NetConn { } } }, + NetConnState::FirmwareLength(firmware_length, recv_bytes) => { let firmware_length = (firmware_length << 8) | (buf[0] as usize); let recv_bytes = recv_bytes + 1; @@ -269,23 +283,23 @@ impl NetConn { let recv_bytes = recv_bytes + length; if recv_bytes == firmware_length { - self.state = NetConnState::WaitO; + self.state = NetConnState::FirmwareWaitO; Ok(length) } else { self.state = NetConnState::FirmwareDownload(firmware_length, recv_bytes); Ok(length) } }, - NetConnState::WaitO => { + NetConnState::FirmwareWaitO => { if buf[0] == b'O' { - self.state = NetConnState::WaitK; + self.state = NetConnState::FirmwareWaitK; Ok(1) } else { println!("End-of-firmware confirmation failed"); Err(()) } }, - NetConnState::WaitK => { + NetConnState::FirmwareWaitK => { if buf[0] == b'K' { println!("Firmware successfully downloaded"); self.state = NetConnState::WaitCommand; @@ -296,6 +310,71 @@ impl NetConn { Err(()) } } + + #[cfg(has_slave_fpga_cfg)] + NetConnState::GatewareLength(gateware_length, recv_bytes) => { + let gateware_length = (gateware_length << 8) | (buf[0] as usize); + let recv_bytes = recv_bytes + 1; + if recv_bytes == 4 { + if let Err(e) = slave_fpga::prepare() { + println!(" Error during slave FPGA preparation: {}", e); + return Err(()) + } + self.state = NetConnState::GatewareDownload(gateware_length, 0); + } else { + self.state = NetConnState::GatewareLength(gateware_length, recv_bytes); + } + Ok(1) + }, + #[cfg(has_slave_fpga_cfg)] + NetConnState::GatewareDownload(gateware_length, recv_bytes) => { + let max_length = gateware_length - recv_bytes; + let buf = if buf.len() > max_length { + &buf[..max_length] + } else { + &buf[..] + }; + let length = buf.len(); + + if let Err(e) = slave_fpga::input(buf) { + println!("Error during slave FPGA loading: {}", e); + return Err(()) + } + + let recv_bytes = recv_bytes + length; + if recv_bytes == gateware_length { + self.state = NetConnState::GatewareWaitO; + Ok(length) + } else { + self.state = NetConnState::GatewareDownload(gateware_length, recv_bytes); + Ok(length) + } + }, + #[cfg(has_slave_fpga_cfg)] + NetConnState::GatewareWaitO => { + if buf[0] == b'O' { + self.state = NetConnState::GatewareWaitK; + Ok(1) + } else { + println!("End-of-gateware confirmation failed"); + Err(()) + } + }, + #[cfg(has_slave_fpga_cfg)] + NetConnState::GatewareWaitK => { + if buf[0] == b'K' { + if let Err(e) = slave_fpga::startup() { + println!("Error during slave FPGA startup: {}", e); + return Err(()) + } + println!("Gateware successfully downloaded"); + self.state = NetConnState::WaitCommand; + Ok(1) + } else { + println!("End-of-gateware confirmation failed"); + Err(()) + } + } } } diff --git a/artiq/firmware/libboard_misoc/slave_fpga.rs b/artiq/firmware/libboard_misoc/slave_fpga.rs index 40c6795e0..bafe1d7fe 100644 --- a/artiq/firmware/libboard_misoc/slave_fpga.rs +++ b/artiq/firmware/libboard_misoc/slave_fpga.rs @@ -59,7 +59,7 @@ pub fn input(data: &[u8]) -> Result<(), &'static str> { Ok(()) } -pub fn complete() -> Result<(), &'static str> { +pub fn startup() -> Result<(), &'static str> { unsafe { let t = clock::get_ms(); while csr::slave_fpga_cfg::in_read() & DONE_BIT == 0 { diff --git a/artiq/frontend/artiq_netboot.py b/artiq/frontend/artiq_netboot.py index 9adcc294a..4f72b2c45 100755 --- a/artiq/frontend/artiq_netboot.py +++ b/artiq/frontend/artiq_netboot.py @@ -5,12 +5,29 @@ import socket import struct import os + +def send_file(sock, filename): + with open(filename, "rb") as input_file: + sock.sendall(struct.pack(">I", os.fstat(input_file.fileno()).st_size)) + while True: + data = input_file.read(4096) + if not data: + break + sock.sendall(data) + sock.sendall(b"OK") + + def main(): parser = argparse.ArgumentParser(description="ARTIQ netboot tool") parser.add_argument("hostname", metavar="HOSTNAME", help="hostname of the target board") parser.add_argument("-f", "--firmware", nargs=1, help="firmware to load") + # Note that on softcore systems, the main gateware cannot be replaced + # with -g. This option is used for loading the RTM FPGA from the AMC + # on Sayma, and the PL on Zynq. + parser.add_argument("-g", "--gateware", nargs=1, + help="gateware to load") parser.add_argument("-b", "--boot", action="store_true", help="boot the device") args = parser.parse_args() @@ -18,15 +35,11 @@ def main(): sock = socket.create_connection((args.hostname, 4269)) try: if args.firmware is not None: - with open(args.firmware[0], "rb") as input_file: - sock.sendall(b"F") - sock.sendall(struct.pack(">I", os.fstat(input_file.fileno()).st_size)) - while True: - data = input_file.read(4096) - if not data: - break - sock.sendall(data) - sock.sendall(b"OK") + sock.sendall(b"F") + send_file(sock, args.firmware[0]) + if args.gateware is not None: + sock.sendall(b"G") + send_file(sock, args.gateware[0]) if args.boot: sock.sendall(b"B") finally: From bc3b55b1a83f824612ae78a843b2b0925c33e495 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 29 Oct 2019 21:17:09 +0000 Subject: [PATCH 1980/2457] gateware/eem: Force IOB=TRUE on Urukul SYNC output Without this, the final register in the SYNC signal TTLClockGen isn't (always) placed in the I/O tile, leading to more jitter than necessary, and causing "double window" artefacts. See sinara-hw/Urukul#16 for more details. (Patch based on work by Weida Zhang, testing by various members of the community in Oxford and elsewhere.) --- artiq/gateware/eem.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index fad54969f..8a8ad40b8 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -87,7 +87,7 @@ class Urukul(_EEM): ), ] ttls = [(6, eem, "io_update"), - (7, eem, "dds_reset_sync_in")] + (7, eem, "dds_reset_sync_in", Misc("IOB=TRUE"))] if eem_aux is not None: ttls += [(0, eem_aux, "sync_clk"), (1, eem_aux, "sync_in"), @@ -97,12 +97,12 @@ class Urukul(_EEM): (5, eem_aux, "sw1"), (6, eem_aux, "sw2"), (7, eem_aux, "sw3")] - for i, j, sig in ttls: + for i, j, sig, *extra_args in ttls: ios.append( ("urukul{}_{}".format(eem, sig), 0, Subsignal("p", Pins(_eem_pin(j, i, "p"))), Subsignal("n", Pins(_eem_pin(j, i, "n"))), - IOStandard(iostandard) + IOStandard(iostandard), *extra_args )) return ios From 5279bc275af4924b610046a25b8d86191a77d1f2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 Nov 2019 18:56:10 +0800 Subject: [PATCH 1981/2457] urukul: rework EEPROM synchronization. Closes #1372 --- artiq/coredevice/ad9910.py | 99 +++++++++++-------- .../examples/kasli/repository/kasli_tester.py | 14 +-- 2 files changed, 64 insertions(+), 49 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 1065517df..170068dc8 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -1,5 +1,4 @@ from numpy import int32, int64 -import functools from artiq.language.core import ( kernel, delay, portable, delay_mu, now_mu, at_mu) @@ -62,6 +61,43 @@ RAM_MODE_CONT_BIDIR_RAMP = 3 RAM_MODE_CONT_RAMPUP = 4 +class SyncDataUser: + def __init__(self, core, sync_delay_seed, io_update_delay): + self.core = core + self.sync_delay_seed = sync_delay_seed + self.io_update_delay = io_update_delay + + @kernel + def init(self): + pass + + +class SyncDataEeprom: + def __init__(self, dmgr, core, eeprom_str): + self.core = core + + eeprom_device, eeprom_offset = eeprom_str.split(":") + self.eeprom_device = dmgr.get(eeprom_device) + self.eeprom_offset = int(eeprom_offset) + + self.sync_delay_seed = 0 + self.io_update_delay = 0 + + @kernel + def init(self): + word = self.eeprom_device.read_i32(self.eeprom_offset) >> 16 + sync_delay_seed = word >> 8 + if sync_delay_seed >= 0: + io_update_delay = word & 0xff + else: + io_update_delay = 0 + if io_update_delay == 0xff: # unprogrammed EEPROM + io_update_delay = 0 + # With Numpy, type(int32(-1) >> 1) == int64 + self.sync_delay_seed = int32(sync_delay_seed) + self.io_update_delay = int32(io_update_delay) + + class AD9910: """ AD9910 DDS channel on Urukul. @@ -88,15 +124,17 @@ class AD9910: and set this to the delay tap number returned (default: -1 to signal no synchronization and no tuning during :meth:`init`). Can be a string of the form "eeprom_device:byte_offset" to read the value - from a I2C EEPROM. + from a I2C EEPROM; in which case, `io_update_delay` must be set to the + same string value. :param io_update_delay: IO_UPDATE pulse alignment delay. To align IO_UPDATE to SYNC_CLK, run :meth:`tune_io_update_delay` and set this to the delay tap number returned. Can be a string of the form "eeprom_device:byte_offset" to read the value - from a I2C EEPROM. + from a I2C EEPROM; in which case, `sync_delay_seed` must be set to the + same string value. """ kernel_invariants = {"chip_select", "cpld", "core", "bus", - "ftw_per_hz", "io_update_delay", "sysclk_per_mu"} + "ftw_per_hz", "sysclk_per_mu"} def __init__(self, dmgr, chip_select, cpld_device, sw_device=None, pll_n=40, pll_cp=7, pll_vco=5, sync_delay_seed=-1, @@ -128,41 +166,14 @@ class AD9910: assert sysclk <= 1e9 self.ftw_per_hz = (1 << 32)/sysclk self.sysclk_per_mu = int(round(sysclk*self.core.ref_period)) + self.sysclk = sysclk - @functools.lru_cache(maxsize=2) - def get_eeprom_sync_data(eeprom_str): - device, offset = eeprom_str.split(":") - device = dmgr.get(device) - offset = int(offset) - - word = device.read_i32(offset) >> 16 - sync_delay_seed = word >> 8 - if sync_delay_seed >= 0: - io_update_delay = word & 0xff - else: - io_update_delay = 0 - if io_update_delay == 0xff: # unprogrammed EEPROM - io_update_delay = 0 - # With Numpy, type(int32(-1) >> 1) == int64 - return device, offset, int32(sync_delay_seed), int32(io_update_delay) - - if isinstance(sync_delay_seed, str): - self.sync_delay_seed_eeprom, self.sync_delay_seed_offset, sync_delay_seed, _ = \ - get_eeprom_sync_data(sync_delay_seed) + if isinstance(sync_delay_seed, str) or isinstance(io_update_delay, str): + if sync_delay_seed != io_update_delay: + raise ValueError("When using EEPROM, sync_delay_seed must be equal to io_update_delay") + self.sync_data = SyncDataEeprom(dmgr, self.core, sync_delay_seed) else: - self.sync_delay_seed_eeprom, self.sync_delay_seed_offset = None, None - if isinstance(io_update_delay, str): - self.io_update_delay_eeprom, self.io_update_delay_offset, _, io_update_delay = \ - get_eeprom_sync_data(io_update_delay) - else: - self.io_update_delay_eeprom, self.io_update_delay_offset = None, None - - if sync_delay_seed >= 0 and not self.cpld.sync_div: - raise ValueError("parent cpld does not drive SYNC") - self.sync_delay_seed = sync_delay_seed - if self.sync_delay_seed >= 0: - assert self.sysclk_per_mu == sysclk*self.core.ref_period - self.io_update_delay = io_update_delay + self.sync_data = SyncDataUser(self.core, sync_delay_seed, io_update_delay) self.phase_mode = PHASE_MODE_CONTINUOUS @@ -369,6 +380,14 @@ class AD9910: :param blind: Do not read back DDS identity and do not wait for lock. """ + self.sync_data.init() + if self.sync_data.sync_delay_seed >= 0 and not self.cpld.sync_div: + raise ValueError("parent cpld does not drive SYNC") + if self.sync_data.sync_delay_seed >= 0: + if self.sysclk_per_mu != self.sysclk*self.core.ref_period: + raise ValueError("incorrect clock ratio for synchronization") + delay(50*ms) # slack + # Set SPI mode self.set_cfr1() self.cpld.io_update.pulse(1*us) @@ -406,8 +425,8 @@ class AD9910: if i >= 100 - 1: raise ValueError("PLL lock timeout") delay(10*us) # slack - if self.sync_delay_seed >= 0: - self.tune_sync_delay(self.sync_delay_seed) + if self.sync_data.sync_delay_seed >= 0: + self.tune_sync_delay(self.sync_data.sync_delay_seed) delay(1*ms) @kernel @@ -468,7 +487,7 @@ class AD9910: pow_ += dt*ftw*self.sysclk_per_mu >> 16 self.write64(_AD9910_REG_PROFILE0 + profile, (asf << 16) | (pow_ & 0xffff), ftw) - delay_mu(int64(self.io_update_delay)) + delay_mu(int64(self.sync_data.io_update_delay)) self.cpld.io_update.pulse_mu(8) # assumes 8 mu > t_SYN_CCLK at_mu(now_mu() & ~7) # clear fine TSC again if phase_mode != PHASE_MODE_CONTINUOUS: diff --git a/artiq/examples/kasli/repository/kasli_tester.py b/artiq/examples/kasli/repository/kasli_tester.py index 4c4e14325..084022e5e 100644 --- a/artiq/examples/kasli/repository/kasli_tester.py +++ b/artiq/examples/kasli/repository/kasli_tester.py @@ -3,7 +3,7 @@ import os import select from artiq.experiment import * -from artiq.coredevice.ad9910 import AD9910 +from artiq.coredevice.ad9910 import AD9910, SyncDataEeprom if os.name == "nt": import msvcrt @@ -240,15 +240,11 @@ class KasliTester(EnvExperiment): print("Calibrating inter-device synchronization...") for channel_name, channel_dev in self.urukuls: if (not isinstance(channel_dev, AD9910) or - (channel_dev.sync_delay_seed_eeprom is None and channel_dev.io_update_delay_eeprom is None)): - print("{}\tno synchronization".format(channel_name)) - elif channel_dev.sync_delay_seed_eeprom is not channel_dev.io_update_delay_eeprom: - print("{}\tunsupported EEPROM configuration".format(channel_name)) - elif channel_dev.sync_delay_seed_offset != channel_dev.io_update_delay_offset: - print("{}\tunsupported EEPROM offsets".format(channel_name)) + not isinstance(channel_dev.sync_data, SyncDataEeprom)): + print("{}\tno EEPROM synchronization".format(channel_name)) else: - eeprom = channel_dev.sync_delay_seed_eeprom - offset = channel_dev.sync_delay_seed_offset + eeprom = channel_dev.sync_data.eeprom_device + offset = channel_dev.sync_data.eeprom_offset sync_delay_seed, io_update_delay = self.calibrate_urukul(channel_dev) print("{}\t{} {}".format(channel_name, sync_delay_seed, io_update_delay)) eeprom_word = (sync_delay_seed << 24) | (io_update_delay << 16) From 664490384350795a5b62ada96d368f05dfbd8349 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 6 Nov 2019 14:45:55 +0800 Subject: [PATCH 1982/2457] bootloader: fix imports --- artiq/firmware/bootloader/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index facc2a72e..52d5eefac 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -10,11 +10,11 @@ extern crate board_misoc; use core::{ptr, slice}; use crc::crc32; use byteorder::{ByteOrder, BigEndian}; -use board_misoc::{ident, cache, sdram, boot, mem as board_mem}; +use board_misoc::{ident, cache, sdram, config, boot, mem as board_mem}; #[cfg(has_slave_fpga_cfg)] use board_misoc::slave_fpga; #[cfg(has_ethmac)] -use board_misoc::{clock, ethmac, config, net_settings}; +use board_misoc::{clock, ethmac, net_settings}; use board_misoc::uart_console::Console; fn check_integrity() -> bool { From 3fd6962bd2b34707679e313b8502a8bd557b7dc1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 10 Nov 2019 15:55:17 +0800 Subject: [PATCH 1983/2457] use sipyco (#585) --- artiq/applets/simple.py | 6 +- artiq/browser/datasets.py | 3 +- artiq/browser/experiments.py | 3 +- artiq/browser/files.py | 3 +- artiq/dashboard/experiments.py | 3 +- artiq/dashboard/moninj.py | 3 +- artiq/examples/artiq_ipython_notebook.ipynb | 4 +- .../repository/remote_exec_demo.py | 3 +- artiq/examples/remote_exec_controller.py | 2 +- artiq/frontend/aqctl_corelog.py | 15 +- artiq/frontend/artiq_client.py | 16 +- artiq/frontend/artiq_compile.py | 6 +- artiq/frontend/artiq_coreanalyzer.py | 7 +- artiq/frontend/artiq_coremgmt.py | 7 +- artiq/frontend/artiq_ctlmgr.py | 15 +- artiq/frontend/artiq_dashboard.py | 11 +- artiq/frontend/artiq_flash.py | 7 +- artiq/frontend/artiq_influxdb.py | 24 +- artiq/frontend/artiq_influxdb_schedule.py | 21 +- artiq/frontend/artiq_master.py | 17 +- artiq/frontend/artiq_rpctool.py | 121 ---- artiq/frontend/artiq_run.py | 6 +- artiq/gui/applets.py | 7 +- artiq/gui/log.py | 2 +- artiq/gui/models.py | 2 +- artiq/gui/state.py | 4 +- artiq/language/environment.py | 3 +- artiq/master/ctlmgr.py | 10 +- artiq/master/databases.py | 6 +- artiq/master/experiments.py | 3 +- artiq/master/log.py | 2 +- artiq/master/scheduler.py | 6 +- artiq/master/worker.py | 7 +- artiq/master/worker_db.py | 4 +- artiq/master/worker_impl.py | 8 +- artiq/monkey_patches.py | 37 -- artiq/protocols/asyncio_server.py | 54 -- artiq/protocols/broadcast.py | 109 --- artiq/protocols/logging.py | 187 ------ artiq/protocols/packed_exceptions.py | 42 -- artiq/protocols/pc_rpc.py | 625 ------------------ artiq/protocols/pipe_ipc.py | 218 ------ artiq/protocols/pyon.py | 227 ------- artiq/protocols/remote_exec.py | 116 ---- artiq/protocols/sync_struct.py | 328 --------- artiq/test/hardware_testbench.py | 79 --- artiq/test/test_ctlmgr.py | 4 +- artiq/test/test_datasets.py | 3 +- artiq/test/test_fire_and_forget.py | 17 + artiq/test/test_frontends.py | 2 +- artiq/test/test_pc_rpc.py | 166 ----- artiq/test/test_pipe_ipc.py | 80 --- artiq/test/test_rpctool.py | 39 -- artiq/test/test_serialization.py | 56 -- artiq/test/test_sync_struct.py | 72 -- artiq/tools.py | 108 +-- doc/manual/developing_a_ndsp.rst | 38 +- doc/manual/environment.rst | 4 +- doc/manual/index.rst | 1 - doc/manual/protocols_reference.rst | 43 -- doc/manual/utilities.rst | 65 -- setup.py | 1 - 62 files changed, 188 insertions(+), 2900 deletions(-) delete mode 100755 artiq/frontend/artiq_rpctool.py delete mode 100644 artiq/monkey_patches.py delete mode 100644 artiq/protocols/asyncio_server.py delete mode 100644 artiq/protocols/broadcast.py delete mode 100644 artiq/protocols/logging.py delete mode 100644 artiq/protocols/packed_exceptions.py delete mode 100644 artiq/protocols/pc_rpc.py delete mode 100644 artiq/protocols/pipe_ipc.py delete mode 100644 artiq/protocols/pyon.py delete mode 100644 artiq/protocols/remote_exec.py delete mode 100644 artiq/protocols/sync_struct.py create mode 100644 artiq/test/test_fire_and_forget.py delete mode 100644 artiq/test/test_pc_rpc.py delete mode 100644 artiq/test/test_pipe_ipc.py delete mode 100644 artiq/test/test_rpctool.py delete mode 100644 artiq/test/test_serialization.py delete mode 100644 artiq/test/test_sync_struct.py delete mode 100644 doc/manual/protocols_reference.rst diff --git a/artiq/applets/simple.py b/artiq/applets/simple.py index c05d86384..71c2d34fd 100644 --- a/artiq/applets/simple.py +++ b/artiq/applets/simple.py @@ -6,9 +6,9 @@ import string from quamash import QEventLoop, QtWidgets, QtCore -from artiq.protocols.sync_struct import Subscriber, process_mod -from artiq.protocols import pyon -from artiq.protocols.pipe_ipc import AsyncioChildComm +from sipyco.sync_struct import Subscriber, process_mod +from sipyco import pyon +from sipyco.pipe_ipc import AsyncioChildComm logger = logging.getLogger(__name__) diff --git a/artiq/browser/datasets.py b/artiq/browser/datasets.py index 4f3e9e181..b66b18216 100644 --- a/artiq/browser/datasets.py +++ b/artiq/browser/datasets.py @@ -3,10 +3,11 @@ import asyncio from PyQt5 import QtCore, QtWidgets +from sipyco.pc_rpc import AsyncioClient as RPCClient + from artiq.tools import short_format from artiq.gui.tools import LayoutWidget, QRecursiveFilterProxyModel from artiq.gui.models import DictSyncTreeSepModel -from artiq.protocols.pc_rpc import AsyncioClient as RPCClient # reduced read-only version of artiq.dashboard.datasets diff --git a/artiq/browser/experiments.py b/artiq/browser/experiments.py index da501e038..6b580a7ed 100644 --- a/artiq/browser/experiments.py +++ b/artiq/browser/experiments.py @@ -7,10 +7,11 @@ from collections import OrderedDict from PyQt5 import QtCore, QtGui, QtWidgets import h5py +from sipyco import pyon + from artiq import __artiq_dir__ as artiq_dir from artiq.gui.tools import LayoutWidget, log_level_to_name, get_open_file_name from artiq.gui.entries import procdesc_to_entry -from artiq.protocols import pyon from artiq.master.worker import Worker, log_worker_exception logger = logging.getLogger(__name__) diff --git a/artiq/browser/files.py b/artiq/browser/files.py index 1dfbac28e..ea36777d2 100644 --- a/artiq/browser/files.py +++ b/artiq/browser/files.py @@ -5,7 +5,8 @@ from datetime import datetime import h5py from PyQt5 import QtCore, QtWidgets, QtGui -from artiq.protocols import pyon +from sipyco import pyon + logger = logging.getLogger(__name__) diff --git a/artiq/dashboard/experiments.py b/artiq/dashboard/experiments.py index 1b6637f39..57aaf6af6 100644 --- a/artiq/dashboard/experiments.py +++ b/artiq/dashboard/experiments.py @@ -7,9 +7,10 @@ from collections import OrderedDict from PyQt5 import QtCore, QtGui, QtWidgets import h5py +from sipyco import pyon + from artiq.gui.tools import LayoutWidget, log_level_to_name, get_open_file_name from artiq.gui.entries import procdesc_to_entry, ScanEntry -from artiq.protocols import pyon logger = logging.getLogger(__name__) diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py index 5de911826..cea227cb0 100644 --- a/artiq/dashboard/moninj.py +++ b/artiq/dashboard/moninj.py @@ -4,7 +4,8 @@ from collections import namedtuple from PyQt5 import QtCore, QtWidgets, QtGui -from artiq.protocols.sync_struct import Subscriber +from sipyco.sync_struct import Subscriber + from artiq.coredevice.comm_moninj import * from artiq.gui.tools import LayoutWidget from artiq.gui.flowlayout import FlowLayout diff --git a/artiq/examples/artiq_ipython_notebook.ipynb b/artiq/examples/artiq_ipython_notebook.ipynb index 6bab291fe..50b0b0905 100644 --- a/artiq/examples/artiq_ipython_notebook.ipynb +++ b/artiq/examples/artiq_ipython_notebook.ipynb @@ -34,8 +34,8 @@ "import pandas as pd\n", "import h5py\n", "\n", - "from artiq.protocols.pc_rpc import (Client, AsyncioClient,\n", - " BestEffortClient, AutoTarget)\n", + "from sipyco.pc_rpc import (Client, AsyncioClient,\n", + " BestEffortClient, AutoTarget)\n", "from artiq.master.databases import DeviceDB\n", "from artiq.master.worker_db import DeviceManager" ] diff --git a/artiq/examples/no_hardware/repository/remote_exec_demo.py b/artiq/examples/no_hardware/repository/remote_exec_demo.py index c347d43be..f7998bd1d 100644 --- a/artiq/examples/no_hardware/repository/remote_exec_demo.py +++ b/artiq/examples/no_hardware/repository/remote_exec_demo.py @@ -1,8 +1,9 @@ import time import inspect +from sipyco.remote_exec import connect_global_rpc + from artiq.experiment import * -from artiq.protocols.remote_exec import connect_global_rpc import remote_exec_processing diff --git a/artiq/examples/remote_exec_controller.py b/artiq/examples/remote_exec_controller.py index 421202414..7c97a09c6 100755 --- a/artiq/examples/remote_exec_controller.py +++ b/artiq/examples/remote_exec_controller.py @@ -4,7 +4,7 @@ import numpy as np from numba import jit import logging -from artiq.protocols.remote_exec import simple_rexec_server_loop +from sipyco.remote_exec import simple_rexec_server_loop @jit(nopython=True) diff --git a/artiq/frontend/aqctl_corelog.py b/artiq/frontend/aqctl_corelog.py index a59998160..b0b396efd 100755 --- a/artiq/frontend/aqctl_corelog.py +++ b/artiq/frontend/aqctl_corelog.py @@ -6,17 +6,18 @@ import struct import logging import re -from artiq import tools -from artiq.protocols.pc_rpc import Server -from artiq.protocols.logging import log_with_name +from sipyco.pc_rpc import Server +from sipyco import common_args +from sipyco.logging_tools import log_with_name + from artiq.coredevice.comm_mgmt import Request, Reply def get_argparser(): parser = argparse.ArgumentParser( description="ARTIQ controller for core device logs") - tools.add_common_args(parser) - tools.simple_network_args(parser, 1068) + common_args.verbosity_args(parser) + common_args.simple_network_args(parser, 1068) parser.add_argument("--simulation", action="store_true", help="Simulation - does not connect to device") parser.add_argument("core_addr", metavar="CORE_ADDR", @@ -65,7 +66,7 @@ async def get_logs(host): def main(): args = get_argparser().parse_args() - tools.init_logger(args) + common_args.init_logger_from_args(args) loop = asyncio.get_event_loop() try: @@ -73,7 +74,7 @@ def main(): get_logs_sim(args.core_addr) if args.simulation else get_logs(args.core_addr)) try: server = Server({"corelog": PingTarget()}, None, True) - loop.run_until_complete(server.start(tools.bind_address_from_args(args), args.port)) + loop.run_until_complete(server.start(common_args.bind_address_from_args(args), args.port)) try: loop.run_until_complete(server.wait_terminate()) finally: diff --git a/artiq/frontend/artiq_client.py b/artiq/frontend/artiq_client.py index d0c7101f4..03b49d2dc 100755 --- a/artiq/frontend/artiq_client.py +++ b/artiq/frontend/artiq_client.py @@ -17,11 +17,13 @@ from dateutil.parser import parse as parse_date from prettytable import PrettyTable -from artiq.protocols.pc_rpc import Client -from artiq.protocols.sync_struct import Subscriber -from artiq.protocols.broadcast import Receiver -from artiq.protocols import pyon -from artiq.tools import short_format, add_common_args, parse_arguments +from sipyco.pc_rpc import Client +from sipyco.sync_struct import Subscriber +from sipyco.broadcast import Receiver +from sipyco import pyon + +from artiq.tools import short_format, parse_arguments +from artiq import __version__ as artiq_version def clear_screen(): @@ -39,6 +41,9 @@ def get_argparser(): parser.add_argument( "--port", default=None, type=int, help="TCP port to use to connect to the master") + parser.add_argument("--version", action="version", + version="ARTIQ v{}".format(artiq_version), + help="print the ARTIQ version number") subparsers = parser.add_subparsers(dest="action") subparsers.required = True @@ -64,7 +69,6 @@ def get_argparser(): "(defaults to head, ignored without -R)") parser_add.add_argument("-c", "--class-name", default=None, help="name of the class to run") - add_common_args(parser) parser_add.add_argument("file", metavar="FILE", help="file containing the experiment to run") parser_add.add_argument("arguments", metavar="ARGUMENTS", nargs="*", diff --git a/artiq/frontend/artiq_compile.py b/artiq/frontend/artiq_compile.py index cf7335474..2ebe0a657 100755 --- a/artiq/frontend/artiq_compile.py +++ b/artiq/frontend/artiq_compile.py @@ -2,6 +2,8 @@ import os, sys, logging, argparse +from sipyco import common_args + from artiq.master.databases import DeviceDB, DatasetDB from artiq.master.worker_db import DeviceManager, DatasetManager from artiq.language.environment import ProcessArgumentManager @@ -15,7 +17,7 @@ logger = logging.getLogger(__name__) def get_argparser(): parser = argparse.ArgumentParser(description="ARTIQ static compiler") - add_common_args(parser) + common_args.verbosity_args(parser) parser.add_argument("--device-db", default="device_db.py", help="device database file (default: '%(default)s')") parser.add_argument("--dataset-db", default="dataset_db.pyon", @@ -36,7 +38,7 @@ def get_argparser(): def main(): args = get_argparser().parse_args() - init_logger(args) + common_args.init_logger_from_args(args) device_mgr = DeviceManager(DeviceDB(args.device_db)) dataset_mgr = DatasetManager(DatasetDB(args.dataset_db)) diff --git a/artiq/frontend/artiq_coreanalyzer.py b/artiq/frontend/artiq_coreanalyzer.py index 2bd965004..96a058b4d 100755 --- a/artiq/frontend/artiq_coreanalyzer.py +++ b/artiq/frontend/artiq_coreanalyzer.py @@ -3,7 +3,8 @@ import argparse import sys -from artiq.tools import add_common_args, init_logger +from sipyco import common_args + from artiq.master.databases import DeviceDB from artiq.master.worker_db import DeviceManager from artiq.coredevice.comm_analyzer import (get_analyzer_dump, @@ -14,7 +15,7 @@ def get_argparser(): parser = argparse.ArgumentParser(description="ARTIQ core device " "RTIO analysis tool") - add_common_args(parser) + common_args.verbosity_args(parser) parser.add_argument("--device-db", default="device_db.py", help="device database file (default: '%(default)s')") @@ -37,7 +38,7 @@ def get_argparser(): def main(): args = get_argparser().parse_args() - init_logger(args) + common_args.init_logger_from_args(args) if (not args.print_decoded and args.write_vcd is None and args.write_dump is None): diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index 270e01cc4..5c7594cff 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -3,7 +3,8 @@ import argparse import struct -from artiq.tools import add_common_args, init_logger +from sipyco import common_args + from artiq.master.databases import DeviceDB from artiq.coredevice.comm_kernel import CommKernel from artiq.coredevice.comm_mgmt import CommMgmt @@ -14,7 +15,7 @@ def get_argparser(): parser = argparse.ArgumentParser(description="ARTIQ core device " "management tool") - add_common_args(parser) + common_args.verbosity_args(parser) parser.add_argument("--device-db", default="device_db.py", help="device database file (default: '%(default)s')") parser.add_argument("-D", "--device", default=None, @@ -134,7 +135,7 @@ def get_argparser(): def main(): args = get_argparser().parse_args() - init_logger(args) + common_args.init_logger_from_args(args) if args.device is None: core_addr = DeviceDB(args.device_db).get("core")["arguments"]["host"] diff --git a/artiq/frontend/artiq_ctlmgr.py b/artiq/frontend/artiq_ctlmgr.py index bfad03ad7..6612e8e9d 100755 --- a/artiq/frontend/artiq_ctlmgr.py +++ b/artiq/frontend/artiq_ctlmgr.py @@ -7,17 +7,18 @@ import os import logging import platform -from artiq.protocols.pc_rpc import Server -from artiq.protocols.logging import LogForwarder, SourceFilter -from artiq.tools import (simple_network_args, atexit_register_coroutine, - bind_address_from_args, add_common_args) +from sipyco.pc_rpc import Server +from sipyco.logging_tools import LogForwarder, SourceFilter +from sipyco import common_args + +from artiq.tools import atexit_register_coroutine from artiq.master.ctlmgr import ControllerManager def get_argparser(): parser = argparse.ArgumentParser(description="ARTIQ controller manager") - add_common_args(parser) + common_args.verbosity_args(parser) parser.add_argument( "-s", "--server", default="::1", @@ -31,7 +32,7 @@ def get_argparser(): parser.add_argument( "--retry-master", default=5.0, type=float, help="retry timer for reconnecting to master") - simple_network_args(parser, [("control", "control", 3249)]) + common_args.simple_network_args(parser, [("control", "control", 3249)]) return parser @@ -73,7 +74,7 @@ def main(): rpc_target = CtlMgrRPC() rpc_server = Server({"ctlmgr": rpc_target}, builtin_terminate=True) - loop.run_until_complete(rpc_server.start(bind_address_from_args(args), + loop.run_until_complete(rpc_server.start(common_args.bind_address_from_args(args), args.port_control)) atexit_register_coroutine(rpc_server.stop) diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index ee5f132b8..6af277019 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -9,11 +9,12 @@ import logging from PyQt5 import QtCore, QtGui, QtWidgets from quamash import QEventLoop +from sipyco.pc_rpc import AsyncioClient, Client +from sipyco.broadcast import Receiver +from sipyco import common_args + from artiq import __artiq_dir__ as artiq_dir, __version__ as artiq_version -from artiq.tools import (atexit_register_coroutine, add_common_args, - get_user_config_dir) -from artiq.protocols.pc_rpc import AsyncioClient, Client -from artiq.protocols.broadcast import Receiver +from artiq.tools import atexit_register_coroutine, get_user_config_dir from artiq.gui.models import ModelSubscriber from artiq.gui import state, log from artiq.dashboard import (experiments, shortcuts, explorer, @@ -37,7 +38,7 @@ def get_argparser(): parser.add_argument( "--db-file", default=None, help="database file for local GUI settings") - add_common_args(parser) + common_args.verbosity_args(parser) return parser diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 81e0e6b2c..f2dd3d727 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -10,8 +10,9 @@ import atexit from functools import partial from collections import defaultdict +from sipyco import common_args + from artiq import __artiq_dir__ as artiq_dir -from artiq.tools import add_common_args, init_logger from artiq.remoting import SSHClient, LocalClient from artiq.frontend.bit2bin import bit2bin @@ -41,7 +42,7 @@ Prerequisites: plugdev group: 'sudo adduser $USER plugdev' and re-login. """) - add_common_args(parser) + common_args.verbosity_args(parser) parser.add_argument("-n", "--dry-run", default=False, action="store_true", @@ -295,7 +296,7 @@ class ProgrammerMetlino(Programmer): def main(): args = get_argparser().parse_args() - init_logger(args) + common_args.init_logger_from_args(args) config = { "kasli": { diff --git a/artiq/frontend/artiq_influxdb.py b/artiq/frontend/artiq_influxdb.py index 0dbd740c5..2a1fd8720 100755 --- a/artiq/frontend/artiq_influxdb.py +++ b/artiq/frontend/artiq_influxdb.py @@ -11,13 +11,13 @@ import time import numpy as np import aiohttp -from artiq.tools import ( - simple_network_args, add_common_args, atexit_register_coroutine, - bind_address_from_args, init_logger, TaskObject -) -from artiq.protocols.sync_struct import Subscriber -from artiq.protocols.pc_rpc import Server -from artiq.protocols import pyon +from sipyco import common_args +from sipyco.asyncio_tools import TaskObject +from sipyco.sync_struct import Subscriber +from sipyco.pc_rpc import Server +from sipyco import pyon + +from artiq.tools import atexit_register_coroutine logger = logging.getLogger(__name__) @@ -62,8 +62,8 @@ def get_argparser(): help="file to load the patterns from (default: %(default)s). " "If the file is not found, no patterns are loaded " "(everything is logged).") - simple_network_args(parser, [("control", "control", 3248)]) - add_common_args(parser) + common_args.simple_network_args(parser, [("control", "control", 3248)]) + common_args.verbosity_args(parser) return parser @@ -201,7 +201,7 @@ class Filter: logger.info("no pattern file found, logging everything") self.patterns = [] - # Privatize so that it is not shown in artiq_rpctool list-methods. + # Privatize so that it is not shown in sipyco_rpctool list-methods. def _filter(self, k): take = "+" for pattern in self.patterns: @@ -222,7 +222,7 @@ class Filter: def main(): args = get_argparser().parse_args() - init_logger(args) + common_args.init_logger_from_args(args) loop = asyncio.get_event_loop() atexit.register(loop.close) @@ -235,7 +235,7 @@ def main(): filter = Filter(args.pattern_file) rpc_server = Server({"influxdb_filter": filter}, builtin_terminate=True) - loop.run_until_complete(rpc_server.start(bind_address_from_args(args), + loop.run_until_complete(rpc_server.start(common_args.bind_address_from_args(args), args.port_control)) atexit_register_coroutine(rpc_server.stop) diff --git a/artiq/frontend/artiq_influxdb_schedule.py b/artiq/frontend/artiq_influxdb_schedule.py index bf8f3a79a..23c391c87 100755 --- a/artiq/frontend/artiq_influxdb_schedule.py +++ b/artiq/frontend/artiq_influxdb_schedule.py @@ -9,12 +9,13 @@ import time import aiohttp import numpy as np -from artiq.protocols.sync_struct import Subscriber -from artiq.tools import (add_common_args, simple_network_args, TaskObject, - init_logger, atexit_register_coroutine, - bind_address_from_args) -from artiq.protocols.pc_rpc import Server -from artiq.protocols import pyon +from sipyco.sync_struct import Subscriber +from sipyco.pc_rpc import Server +from sipyco import pyon +from sipyco import common_args +from sipyco.asyncio_tools import TaskObject + +from artiq.tools import atexit_register_coroutine logger = logging.getLogger(__name__) @@ -53,8 +54,8 @@ def get_argparser(): "--database", default="db", help="database name to use") group.add_argument( "--table", default="schedule", help="table name to use") - simple_network_args(parser, [("control", "control", 3275)]) - add_common_args(parser) + common_args.simple_network_args(parser, [("control", "control", 3275)]) + common_args.verbosity_args(parser) return parser @@ -210,7 +211,7 @@ class Logger: def main(): args = get_argparser().parse_args() - init_logger(args) + common_args.init_logger_from_args(args) loop = asyncio.get_event_loop() atexit.register(loop.close) @@ -226,7 +227,7 @@ def main(): server = Logger() rpc_server = Server({"schedule_logger": server}, builtin_terminate=True) loop.run_until_complete(rpc_server.start( - bind_address_from_args(args), args.port_control)) + common_args.bind_address_from_args(args), args.port_control)) atexit_register_coroutine(rpc_server.stop) reader = MasterReader(args.server_master, args.port_master, diff --git a/artiq/frontend/artiq_master.py b/artiq/frontend/artiq_master.py index 4583ed6d4..373fd4da4 100755 --- a/artiq/frontend/artiq_master.py +++ b/artiq/frontend/artiq_master.py @@ -6,12 +6,13 @@ import atexit import os import logging -from artiq.tools import (simple_network_args, atexit_register_coroutine, - bind_address_from_args) -from artiq.protocols.pc_rpc import Server as RPCServer -from artiq.protocols.sync_struct import Publisher -from artiq.protocols.logging import Server as LoggingServer -from artiq.protocols.broadcast import Broadcaster +from sipyco.pc_rpc import Server as RPCServer +from sipyco.sync_struct import Publisher +from sipyco.logging_tools import Server as LoggingServer +from sipyco.broadcast import Broadcaster +from sipyco import common_args + +from artiq.tools import atexit_register_coroutine from artiq.master.log import log_args, init_log from artiq.master.databases import DeviceDB, DatasetDB from artiq.master.scheduler import Scheduler @@ -25,7 +26,7 @@ logger = logging.getLogger(__name__) def get_argparser(): parser = argparse.ArgumentParser(description="ARTIQ master") - simple_network_args(parser, [ + common_args.simple_network_args(parser, [ ("notify", "notifications", 3250), ("control", "control", 3251), ("logging", "remote logging", 1066), @@ -72,7 +73,7 @@ def main(): else: loop = asyncio.get_event_loop() atexit.register(loop.close) - bind = bind_address_from_args(args) + bind = common_args.bind_address_from_args(args) server_broadcast = Broadcaster() loop.run_until_complete(server_broadcast.start( diff --git a/artiq/frontend/artiq_rpctool.py b/artiq/frontend/artiq_rpctool.py deleted file mode 100755 index fb9844f29..000000000 --- a/artiq/frontend/artiq_rpctool.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import textwrap -import sys -import traceback -import numpy as np # Needed to use numpy in RPC call arguments on cmd line -import pprint -import inspect - -from artiq.protocols.pc_rpc import AutoTarget, Client - - -def get_argparser(): - parser = argparse.ArgumentParser( - description="ARTIQ RPC tool") - parser.add_argument("server", metavar="SERVER", - help="hostname or IP of the controller to connect to") - parser.add_argument("port", metavar="PORT", type=int, - help="TCP port to use to connect to the controller") - subparsers = parser.add_subparsers(dest="action") - subparsers.add_parser("list-targets", help="list existing targets") - parser_list_methods = subparsers.add_parser("list-methods", - help="list target's methods") - parser_list_methods.add_argument("-t", "--target", help="target name") - parser_call = subparsers.add_parser("call", help="call a target's method") - parser_call.add_argument("-t", "--target", help="target name") - parser_call.add_argument("method", metavar="METHOD", help="method name") - parser_call.add_argument("args", metavar="ARGS", nargs=argparse.REMAINDER, - help="arguments") - parser_interactive = subparsers.add_parser("interactive", - help="enter interactive mode " - "(default)") - parser_interactive.add_argument("-t", "--target", help="target name") - return parser - - -def list_targets(target_names, description): - print("Target(s): " + ", ".join(target_names)) - if description is not None: - print("Description: " + description) - - -def list_methods(remote): - doc = remote.get_rpc_method_list() - if doc["docstring"] is not None: - print(doc["docstring"]) - print() - for name, (argspec, docstring) in sorted(doc["methods"].items()): - print(name + inspect.formatargspec(**argspec)) - if docstring is not None: - print(textwrap.indent(docstring, " ")) - print() - - -def call_method(remote, method_name, args): - method = getattr(remote, method_name) - ret = method(*[eval(arg) for arg in args]) - if ret is not None: - pprint.pprint(ret) - - -def interactive(remote): - try: - import readline # This makes input() nicer - except ImportError: - print("Warning: readline not available. " - "Install it to add line editing capabilities.") - - while True: - try: - cmd = input("({}) ".format(remote.get_selected_target())) - except EOFError: - return - class RemoteDict: - def __getitem__(self, k): - if k == "np": - return np - else: - return getattr(remote, k) - try: - ret = eval(cmd, {}, RemoteDict()) - except Exception as e: - if hasattr(e, "parent_traceback"): - print("Remote exception:") - print(traceback.format_exception_only(type(e), e)[0].rstrip()) - for l in e.parent_traceback: - print(l.rstrip()) - else: - traceback.print_exc() - else: - if ret is not None: - pprint.pprint(ret) - - -def main(): - args = get_argparser().parse_args() - if not args.action: - args.target = None - - remote = Client(args.server, args.port, None) - targets, description = remote.get_rpc_id() - if args.action != "list-targets": - if not args.target: - remote.select_rpc_target(AutoTarget) - else: - remote.select_rpc_target(args.target) - - if args.action == "list-targets": - list_targets(targets, description) - elif args.action == "list-methods": - list_methods(remote) - elif args.action == "call": - call_method(remote, args.method, args.args) - elif args.action == "interactive" or not args.action: - interactive(remote) - else: - print("Unrecognized action: {}".format(args.action)) - -if __name__ == "__main__": - main() diff --git a/artiq/frontend/artiq_run.py b/artiq/frontend/artiq_run.py index 76954e56c..c235387c9 100755 --- a/artiq/frontend/artiq_run.py +++ b/artiq/frontend/artiq_run.py @@ -12,6 +12,8 @@ import h5py from llvmlite_artiq import binding as llvm +from sipyco import common_args + from artiq.language.environment import EnvExperiment, ProcessArgumentManager from artiq.language.types import TBool from artiq.master.databases import DeviceDB, DatasetDB @@ -126,7 +128,7 @@ def get_argparser(with_file=True): parser = argparse.ArgumentParser( description="Local experiment running tool") - add_common_args(parser) + common_args.verbosity_args(parser) parser.add_argument("--device-db", default="device_db.py", help="device database file (default: '%(default)s')") parser.add_argument("--dataset-db", default="dataset_db.pyon", @@ -184,7 +186,7 @@ def _build_experiment(device_mgr, dataset_mgr, args): def run(with_file=False): args = get_argparser(with_file).parse_args() - init_logger(args) + common_args.init_logger_from_args(args) device_mgr = DeviceManager(DeviceDB(args.device_db), virtual_devices={"scheduler": DummyScheduler(), diff --git a/artiq/gui/applets.py b/artiq/gui/applets.py index ebf735595..432fb458d 100644 --- a/artiq/gui/applets.py +++ b/artiq/gui/applets.py @@ -10,9 +10,10 @@ from itertools import count from PyQt5 import QtCore, QtGui, QtWidgets -from artiq.protocols.pipe_ipc import AsyncioParentComm -from artiq.protocols.logging import LogParser -from artiq.protocols import pyon +from sipyco.pipe_ipc import AsyncioParentComm +from sipyco.logging_tools import LogParser +from sipyco import pyon + from artiq.gui.tools import QDockWidgetCloseDetect, LayoutWidget diff --git a/artiq/gui/log.py b/artiq/gui/log.py index 2b5d7185f..9bf9d7efa 100644 --- a/artiq/gui/log.py +++ b/artiq/gui/log.py @@ -6,7 +6,7 @@ from functools import partial from PyQt5 import QtCore, QtGui, QtWidgets -from artiq.protocols.logging import SourceFilter +from sipyco.logging_tools import SourceFilter from artiq.gui.tools import (LayoutWidget, log_level_to_name, QDockWidgetCloseDetect) diff --git a/artiq/gui/models.py b/artiq/gui/models.py index 9b9551593..4d6f19c22 100644 --- a/artiq/gui/models.py +++ b/artiq/gui/models.py @@ -1,6 +1,6 @@ from PyQt5 import QtCore -from artiq.protocols.sync_struct import Subscriber, process_mod +from sipyco.sync_struct import Subscriber, process_mod class ModelManager: diff --git a/artiq/gui/state.py b/artiq/gui/state.py index fc19f7919..3a3f21be8 100644 --- a/artiq/gui/state.py +++ b/artiq/gui/state.py @@ -2,8 +2,8 @@ import asyncio from collections import OrderedDict import logging -from artiq.tools import TaskObject -from artiq.protocols import pyon +from sipyco.asyncio_tools import TaskObject +from sipyco import pyon logger = logging.getLogger(__name__) diff --git a/artiq/language/environment.py b/artiq/language/environment.py index 574cd8b16..766779177 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -2,7 +2,8 @@ import warnings from collections import OrderedDict from inspect import isclass -from artiq.protocols import pyon +from sipyco import pyon + from artiq.language import units from artiq.language.core import rpc diff --git a/artiq/master/ctlmgr.py b/artiq/master/ctlmgr.py index 93306df6d..075f08a41 100644 --- a/artiq/master/ctlmgr.py +++ b/artiq/master/ctlmgr.py @@ -5,10 +5,12 @@ import shlex import socket import os -from artiq.protocols.sync_struct import Subscriber -from artiq.protocols.pc_rpc import AsyncioClient -from artiq.protocols.logging import LogParser -from artiq.tools import Condition, TaskObject +from sipyco.sync_struct import Subscriber +from sipyco.pc_rpc import AsyncioClient +from sipyco.logging_tools import LogParser +from sipyco.asyncio_tools import TaskObject + +from artiq.tools import Condition logger = logging.getLogger(__name__) diff --git a/artiq/master/databases.py b/artiq/master/databases.py index c96deb9ab..0eb59bf0e 100644 --- a/artiq/master/databases.py +++ b/artiq/master/databases.py @@ -1,9 +1,9 @@ import asyncio import tokenize -from artiq.protocols.sync_struct import Notifier, process_mod, update_from_dict -from artiq.protocols import pyon -from artiq.tools import TaskObject +from sipyco.sync_struct import Notifier, process_mod, update_from_dict +from sipyco import pyon +from sipyco.asyncio_tools import TaskObject def device_db_from_file(filename): diff --git a/artiq/master/experiments.py b/artiq/master/experiments.py index 892d6d30a..b9a46d7ba 100644 --- a/artiq/master/experiments.py +++ b/artiq/master/experiments.py @@ -5,7 +5,8 @@ import shutil import time import logging -from artiq.protocols.sync_struct import Notifier, update_from_dict +from sipyco.sync_struct import Notifier, update_from_dict + from artiq.master.worker import (Worker, WorkerInternalException, log_worker_exception) from artiq.tools import get_windows_drives, exc_to_warning diff --git a/artiq/master/log.py b/artiq/master/log.py index d759d1309..945e44d86 100644 --- a/artiq/master/log.py +++ b/artiq/master/log.py @@ -1,7 +1,7 @@ import logging import logging.handlers -from artiq.protocols.logging import SourceFilter +from sipyco.logging_tools import SourceFilter class LogForwarder(logging.Handler): diff --git a/artiq/master/scheduler.py b/artiq/master/scheduler.py index 0f5d9c8c8..78d90564b 100644 --- a/artiq/master/scheduler.py +++ b/artiq/master/scheduler.py @@ -3,9 +3,11 @@ import logging from enum import Enum from time import time +from sipyco.sync_struct import Notifier +from sipyco.asyncio_tools import TaskObject + from artiq.master.worker import Worker, log_worker_exception -from artiq.tools import asyncio_wait_or_cancel, TaskObject, Condition -from artiq.protocols.sync_struct import Notifier +from artiq.tools import asyncio_wait_or_cancel, Condition logger = logging.getLogger(__name__) diff --git a/artiq/master/worker.py b/artiq/master/worker.py index 293d0f180..9480af8f4 100644 --- a/artiq/master/worker.py +++ b/artiq/master/worker.py @@ -5,9 +5,10 @@ import logging import subprocess import time -from artiq.protocols import pipe_ipc, pyon -from artiq.protocols.logging import LogParser -from artiq.protocols.packed_exceptions import current_exc_packed +from sipyco import pipe_ipc, pyon +from sipyco.logging_tools import LogParser +from sipyco.packed_exceptions import current_exc_packed + from artiq.tools import asyncio_wait_or_cancel diff --git a/artiq/master/worker_db.py b/artiq/master/worker_db.py index 3a3f7ef25..6d3799576 100644 --- a/artiq/master/worker_db.py +++ b/artiq/master/worker_db.py @@ -9,8 +9,8 @@ from collections import OrderedDict import importlib import logging -from artiq.protocols.sync_struct import Notifier -from artiq.protocols.pc_rpc import AutoTarget, Client, BestEffortClient +from sipyco.sync_struct import Notifier +from sipyco.pc_rpc import AutoTarget, Client, BestEffortClient logger = logging.getLogger(__name__) diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index 539b09b90..e53ea9376 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -15,10 +15,12 @@ from collections import OrderedDict import h5py +from sipyco import pipe_ipc, pyon +from sipyco.packed_exceptions import raise_packed_exc +from sipyco.logging_tools import multiline_log_config + import artiq -from artiq.protocols import pipe_ipc, pyon -from artiq.protocols.packed_exceptions import raise_packed_exc -from artiq.tools import multiline_log_config, file_import +from artiq.tools import file_import from artiq.master.worker_db import DeviceManager, DatasetManager, DummyDevice from artiq.language.environment import (is_experiment, TraceArgumentManager, ProcessArgumentManager) diff --git a/artiq/monkey_patches.py b/artiq/monkey_patches.py deleted file mode 100644 index f6c31ad48..000000000 --- a/artiq/monkey_patches.py +++ /dev/null @@ -1,37 +0,0 @@ -import sys -import socket - - -__all__ = [] - - -if sys.version_info[:3] >= (3, 5, 2) and sys.version_info[:3] <= (3, 6, 6): - import asyncio - - # See https://github.com/m-labs/artiq/issues/506 - def _ipaddr_info(host, port, family, type, proto): - return None - asyncio.base_events._ipaddr_info = _ipaddr_info - - # See https://github.com/m-labs/artiq/issues/1016 - @asyncio.coroutine - def sock_connect(self, sock, address): - """Connect to a remote socket at address. - - This method is a coroutine. - """ - if self._debug and sock.gettimeout() != 0: - raise ValueError("the socket must be non-blocking") - - if not hasattr(socket, 'AF_UNIX') or sock.family != socket.AF_UNIX: - socktype = sock.type & 0xf # WA https://bugs.python.org/issue21327 - resolved = asyncio.base_events._ensure_resolved( - address, family=sock.family, type=socktype, proto=sock.proto, loop=self) - if not resolved.done(): - yield from resolved - _, _, _, _, address = resolved.result()[0] - - fut = self.create_future() - self._sock_connect(fut, sock, address) - return (yield from fut) - asyncio.selector_events.BaseSelectorEventLoop.sock_connect = sock_connect diff --git a/artiq/protocols/asyncio_server.py b/artiq/protocols/asyncio_server.py deleted file mode 100644 index 4eef0374b..000000000 --- a/artiq/protocols/asyncio_server.py +++ /dev/null @@ -1,54 +0,0 @@ -import asyncio -from copy import copy - - -class AsyncioServer: - """Generic TCP server based on asyncio. - - Users of this class must derive from it and define the - :meth:`~artiq.protocols.asyncio_server.AsyncioServer._handle_connection_cr` - method/coroutine. - """ - def __init__(self): - self._client_tasks = set() - - async def start(self, host, port): - """Starts the server. - - The user must call :meth:`stop` - to free resources properly after this method completes successfully. - - This method is a *coroutine*. - - :param host: Bind address of the server (see ``asyncio.start_server`` - from the Python standard library). - :param port: TCP port to bind to. - """ - self.server = await asyncio.start_server(self._handle_connection, - host, port, - limit=4*1024*1024) - - async def stop(self): - """Stops the server.""" - wait_for = copy(self._client_tasks) - for task in self._client_tasks: - task.cancel() - for task in wait_for: - try: - await asyncio.wait_for(task, None) - except asyncio.CancelledError: - pass - self.server.close() - await self.server.wait_closed() - del self.server - - def _client_done(self, task): - self._client_tasks.remove(task) - - def _handle_connection(self, reader, writer): - task = asyncio.ensure_future(self._handle_connection_cr(reader, writer)) - self._client_tasks.add(task) - task.add_done_callback(self._client_done) - - async def _handle_connection_cr(self, reader, writer): - raise NotImplementedError diff --git a/artiq/protocols/broadcast.py b/artiq/protocols/broadcast.py deleted file mode 100644 index 354a1b560..000000000 --- a/artiq/protocols/broadcast.py +++ /dev/null @@ -1,109 +0,0 @@ -import asyncio - -from artiq.monkey_patches import * -from artiq.protocols import pyon -from artiq.protocols.asyncio_server import AsyncioServer - - -_init_string = b"ARTIQ broadcast\n" - - -class Receiver: - def __init__(self, name, notify_cb, disconnect_cb=None): - self.name = name - if not isinstance(notify_cb, list): - notify_cb = [notify_cb] - self.notify_cbs = notify_cb - self.disconnect_cb = disconnect_cb - - async def connect(self, host, port): - self.reader, self.writer = \ - await asyncio.open_connection(host, port, limit=100*1024*1024) - try: - self.writer.write(_init_string) - self.writer.write((self.name + "\n").encode()) - self.receive_task = asyncio.ensure_future(self._receive_cr()) - except: - self.writer.close() - del self.reader - del self.writer - raise - - async def close(self): - self.disconnect_cb = None - try: - self.receive_task.cancel() - try: - await asyncio.wait_for(self.receive_task, None) - except asyncio.CancelledError: - pass - finally: - self.writer.close() - del self.reader - del self.writer - - async def _receive_cr(self): - try: - target = None - while True: - line = await self.reader.readline() - if not line: - return - obj = pyon.decode(line.decode()) - - for notify_cb in self.notify_cbs: - notify_cb(obj) - finally: - if self.disconnect_cb is not None: - self.disconnect_cb() - - -class Broadcaster(AsyncioServer): - def __init__(self, queue_limit=1024): - AsyncioServer.__init__(self) - self._queue_limit = queue_limit - self._recipients = dict() - - async def _handle_connection_cr(self, reader, writer): - try: - line = await reader.readline() - if line != _init_string: - return - - line = await reader.readline() - if not line: - return - name = line.decode()[:-1] - - queue = asyncio.Queue(self._queue_limit) - if name in self._recipients: - self._recipients[name].add(queue) - else: - self._recipients[name] = {queue} - try: - while True: - line = await queue.get() - writer.write(line) - # raise exception on connection error - await writer.drain() - finally: - self._recipients[name].remove(queue) - if not self._recipients[name]: - del self._recipients[name] - except (ConnectionResetError, ConnectionAbortedError, BrokenPipeError): - # receivers disconnecting are a normal occurence - pass - finally: - writer.close() - - def broadcast(self, name, obj): - if name in self._recipients: - line = pyon.encode(obj) + "\n" - line = line.encode() - for recipient in self._recipients[name]: - try: - recipient.put_nowait(line) - except asyncio.QueueFull: - # do not log: log messages may be sent back to us - # as broadcasts, and cause infinite recursion. - pass diff --git a/artiq/protocols/logging.py b/artiq/protocols/logging.py deleted file mode 100644 index 542e8da35..000000000 --- a/artiq/protocols/logging.py +++ /dev/null @@ -1,187 +0,0 @@ -import asyncio -import logging -import re - -from artiq.monkey_patches import * -from artiq.protocols.asyncio_server import AsyncioServer -from artiq.tools import TaskObject, MultilineFormatter - - -logging.TRACE = 5 -logging.addLevelName(logging.TRACE, 'TRACE') - - -logger = logging.getLogger(__name__) -_fwd_logger = logging.getLogger("fwd") - - -def log_with_name(name, *args, **kwargs): - _fwd_logger.name = name - _fwd_logger.log(*args, **kwargs) - - -_name_to_level = { - "CRITICAL": logging.CRITICAL, - "ERROR": logging.ERROR, - "WARN": logging.WARNING, - "WARNING": logging.WARNING, - "INFO": logging.INFO, - "DEBUG": logging.DEBUG, - "TRACE": logging.TRACE, -} - - -def parse_log_message(msg): - lr = "|".join(_name_to_level.keys()) - m = re.fullmatch('('+lr+')(<\d+>)?:([^:]*):(.*)', msg) - if m is None: - return 0, logging.INFO, "print", msg - level = _name_to_level[m.group(1)] - if m.group(2): - multiline = int(m.group(2)[1:-1]) - 1 - else: - multiline = 0 - name = m.group(3) - message = m.group(4) - return multiline, level, name, message - - -class LogParser: - def __init__(self, source_cb): - self.source_cb = source_cb - self.multiline_count = 0 - self.multiline_level = None - self.multiline_name = None - self.multiline_message = None - - def line_input(self, msg): - if self.multiline_count: - self.multiline_message += "\n" + msg - self.multiline_count -= 1 - if not self.multiline_count: - log_with_name( - self.multiline_name, - self.multiline_level, - self.multiline_message, - extra={"source": self.source_cb()}) - self.multiline_level = None - self.multiline_name = None - self.multiline_message = None - else: - multiline, level, name, message = parse_log_message(msg) - if multiline: - self.multiline_count = multiline - self.multiline_level = level - self.multiline_name = name - self.multiline_message = message - else: - log_with_name(name, level, message, - extra={"source": self.source_cb()}) - - async def stream_task(self, stream): - while True: - try: - entry = (await stream.readline()) - if not entry: - break - self.line_input(entry.decode().rstrip("\r\n")) - except: - logger.debug("exception in log forwarding", exc_info=True) - break - logger.debug("stopped log forwarding of stream %s of %s", - stream, self.source_cb()) - - -_init_string = b"ARTIQ logging\n" - - -class Server(AsyncioServer): - """Remote logging TCP server. - - Log entries are in the format: - source:levelno:name:message - continuation... - ...continuation - """ - async def _handle_connection_cr(self, reader, writer): - try: - line = await reader.readline() - if line != _init_string: - return - - source = None - parser = LogParser(lambda: source) - - while True: - line = await reader.readline() - if not line: - break - try: - line = line.decode() - except: - return - line = line[:-1] - if parser.multiline_count: - parser.line_input(line) - else: - linesplit = line.split(":", maxsplit=1) - if len(linesplit) != 2: - logger.warning("received improperly formatted message, " - "dropping connection") - return - source, remainder = linesplit - parser.line_input(remainder) - except (ConnectionResetError, ConnectionAbortedError, BrokenPipeError): - # May happens on Windows when client disconnects - pass - finally: - writer.close() - - -class SourceFilter: - def __init__(self, local_level, local_source): - self.local_level = local_level - self.local_source = local_source - - def filter(self, record): - if not hasattr(record, "source"): - record.source = self.local_source - if record.source == self.local_source: - return record.levelno >= self.local_level - else: - # log messages that are forwarded from a source have already - # been filtered, and may have a level below the local level. - return True - - -class LogForwarder(logging.Handler, TaskObject): - def __init__(self, host, port, reconnect_timer=5.0, queue_size=1000, - **kwargs): - logging.Handler.__init__(self, **kwargs) - self.host = host - self.port = port - self.setFormatter(MultilineFormatter()) - self._queue = asyncio.Queue(queue_size) - self.reconnect_timer = reconnect_timer - - def emit(self, record): - self._queue.put_nowait(record.source + ":" + self.format(record)) - - async def _do(self): - reader = writer = None - while True: - try: - reader, writer = await asyncio.open_connection(self.host, - self.port) - writer.write(_init_string) - while True: - message = await self._queue.get() + "\n" - writer.write(message.encode()) - await writer.drain() - except asyncio.CancelledError: - return - except: - await asyncio.sleep(self.reconnect_timer) - finally: - if writer is not None: - writer.close() diff --git a/artiq/protocols/packed_exceptions.py b/artiq/protocols/packed_exceptions.py deleted file mode 100644 index 2c453bf80..000000000 --- a/artiq/protocols/packed_exceptions.py +++ /dev/null @@ -1,42 +0,0 @@ -import inspect -import builtins -import traceback -import sys - - -__all__ = ["GenericRemoteException", "current_exc_packed", "raise_packed_exc"] - - -class GenericRemoteException(Exception): - pass - - -builtin_exceptions = {v: k for k, v in builtins.__dict__.items() - if inspect.isclass(v) and issubclass(v, BaseException)} - - -def current_exc_packed(): - exc_class, exc, exc_tb = sys.exc_info() - if exc_class in builtin_exceptions: - return { - "class": builtin_exceptions[exc_class], - "message": str(exc), - "traceback": traceback.format_tb(exc_tb) - } - else: - message = traceback.format_exception_only(exc_class, exc)[0].rstrip() - return { - "class": "GenericRemoteException", - "message": message, - "traceback": traceback.format_tb(exc_tb) - } - - -def raise_packed_exc(pack): - if pack["class"] == "GenericRemoteException": - cls = GenericRemoteException - else: - cls = getattr(builtins, pack["class"]) - exc = cls(pack["message"]) - exc.parent_traceback = pack["traceback"] - raise exc diff --git a/artiq/protocols/pc_rpc.py b/artiq/protocols/pc_rpc.py deleted file mode 100644 index 5fa6f0820..000000000 --- a/artiq/protocols/pc_rpc.py +++ /dev/null @@ -1,625 +0,0 @@ -""" -This module provides a remote procedure call (RPC) mechanism over sockets -between conventional computers (PCs) running Python. It strives to be -transparent and uses :mod:`artiq.protocols.pyon` internally so that e.g. Numpy -arrays can be easily used. - -Note that the server operates on copies of objects provided by the client, -and modifications to mutable types are not written back. For example, if the -client passes a list as a parameter of an RPC method, and that method -``append()s`` an element to the list, the element is not appended to the -client's list. -""" - -import asyncio -import inspect -import logging -import socket -import threading -import time -from operator import itemgetter - -from artiq.monkey_patches import * -from artiq.protocols import pyon -from artiq.protocols.asyncio_server import AsyncioServer as _AsyncioServer -from artiq.protocols.packed_exceptions import * - -logger = logging.getLogger(__name__) - - -class AutoTarget: - """Use this as target value in clients for them to automatically connect - to the target exposed by the server. Servers must have only one target.""" - pass - - -class IncompatibleServer(Exception): - """Raised by the client when attempting to connect to a server that does - not have the expected target.""" - pass - - -_init_string = b"ARTIQ pc_rpc\n" - - -def _validate_target_name(target_name, target_names): - if target_name is AutoTarget: - if len(target_names) > 1: - raise ValueError("Server has multiple targets: " + - " ".join(sorted(target_names))) - else: - target_name = target_names[0] - elif target_name not in target_names: - raise IncompatibleServer( - "valid target name(s): " + " ".join(sorted(target_names))) - return target_name - - -class Client: - """This class proxies the methods available on the server so that they - can be used as if they were local methods. - - For example, if the server provides method ``foo``, and ``c`` is a local - :class:`.Client` object, then the method can be called as: :: - - result = c.foo(param1, param2) - - The parameters and the result are automatically transferred from the - server. - - Only methods are supported. Attributes must be accessed by providing and - using "get" and/or "set" methods on the server side. - - At object initialization, the connection to the remote server is - automatically attempted. The user must call :meth:`~artiq.protocols.pc_rpc.Client.close_rpc` to - free resources properly after initialization completes successfully. - - :param host: Identifier of the server. The string can represent a - hostname or a IPv4 or IPv6 address (see - ``socket.create_connection`` in the Python standard library). - :param port: TCP port to use. - :param target_name: Target name to select. ``IncompatibleServer`` is - raised if the target does not exist. - Use :class:`.AutoTarget` for automatic selection if the server has only one - target. - Use ``None`` to skip selecting a target. The list of targets can then - be retrieved using :meth:`~artiq.protocols.pc_rpc.Client.get_rpc_id` - and then one can be selected later using :meth:`~artiq.protocols.pc_rpc.Client.select_rpc_target`. - :param timeout: Socket operation timeout. Use ``None`` for blocking - (default), ``0`` for non-blocking, and a finite value to raise - ``socket.timeout`` if an operation does not complete within the - given time. See also ``socket.create_connection()`` and - ``socket.settimeout()`` in the Python standard library. A timeout - in the middle of a RPC can break subsequent RPCs (from the same - client). - """ - def __init__(self, host, port, target_name=AutoTarget, timeout=None): - self.__socket = socket.create_connection((host, port), timeout) - - try: - self.__socket.sendall(_init_string) - - server_identification = self.__recv() - self.__target_names = server_identification["targets"] - self.__description = server_identification["description"] - self.__selected_target = None - self.__valid_methods = set() - if target_name is not None: - self.select_rpc_target(target_name) - except: - self.__socket.close() - raise - - def select_rpc_target(self, target_name): - """Selects a RPC target by name. This function should be called - exactly once if the object was created with ``target_name=None``.""" - target_name = _validate_target_name(target_name, self.__target_names) - self.__socket.sendall((target_name + "\n").encode()) - self.__selected_target = target_name - self.__valid_methods = self.__recv() - - def get_selected_target(self): - """Returns the selected target, or ``None`` if no target has been - selected yet.""" - return self.__selected_target - - def get_rpc_id(self): - """Returns a tuple (target_names, description) containing the - identification information of the server.""" - return (self.__target_names, self.__description) - - def get_local_host(self): - """Returns the address of the local end of the connection.""" - return self.__socket.getsockname()[0] - - def close_rpc(self): - """Closes the connection to the RPC server. - - No further method calls should be done after this method is called. - """ - self.__socket.close() - - def __send(self, obj): - line = pyon.encode(obj) + "\n" - self.__socket.sendall(line.encode()) - - def __recv(self): - buf = self.__socket.recv(4096).decode() - while "\n" not in buf: - more = self.__socket.recv(4096) - if not more: - break - buf += more.decode() - return pyon.decode(buf) - - def __do_action(self, action): - self.__send(action) - - obj = self.__recv() - if obj["status"] == "ok": - return obj["ret"] - elif obj["status"] == "failed": - raise_packed_exc(obj["exception"]) - else: - raise ValueError - - def __do_rpc(self, name, args, kwargs): - obj = {"action": "call", "name": name, "args": args, "kwargs": kwargs} - return self.__do_action(obj) - - def get_rpc_method_list(self): - obj = {"action": "get_rpc_method_list"} - return self.__do_action(obj) - - def __getattr__(self, name): - if name not in self.__valid_methods: - raise AttributeError - def proxy(*args, **kwargs): - return self.__do_rpc(name, args, kwargs) - return proxy - - -class AsyncioClient: - """This class is similar to :class:`artiq.protocols.pc_rpc.Client`, but - uses ``asyncio`` instead of blocking calls. - - All RPC methods are coroutines. - - Concurrent access from different asyncio tasks is supported; all calls - use a single lock. - """ - def __init__(self): - self.__lock = asyncio.Lock() - self.__reader = None - self.__writer = None - self.__target_names = None - self.__description = None - - async def connect_rpc(self, host, port, target_name): - """Connects to the server. This cannot be done in __init__ because - this method is a coroutine. See :class:`artiq.protocols.pc_rpc.Client` for a description of the - parameters.""" - self.__reader, self.__writer = \ - await asyncio.open_connection(host, port, limit=100*1024*1024) - try: - self.__writer.write(_init_string) - server_identification = await self.__recv() - self.__target_names = server_identification["targets"] - self.__description = server_identification["description"] - self.__selected_target = None - self.__valid_methods = set() - if target_name is not None: - await self.select_rpc_target(target_name) - except: - self.close_rpc() - raise - - async def select_rpc_target(self, target_name): - """Selects a RPC target by name. This function should be called - exactly once if the connection was created with ``target_name=None``. - """ - target_name = _validate_target_name(target_name, self.__target_names) - self.__writer.write((target_name + "\n").encode()) - self.__selected_target = target_name - self.__valid_methods = await self.__recv() - - def get_selected_target(self): - """Returns the selected target, or ``None`` if no target has been - selected yet.""" - return self.__selected_target - - def get_local_host(self): - """Returns the address of the local end of the connection.""" - return self.__writer.get_extra_info("socket").getsockname()[0] - - def get_rpc_id(self): - """Returns a tuple (target_names, description) containing the - identification information of the server.""" - return (self.__target_names, self.__description) - - def close_rpc(self): - """Closes the connection to the RPC server. - - No further method calls should be done after this method is called. - """ - if self.__writer is not None: - self.__writer.close() - self.__reader = None - self.__writer = None - self.__target_names = None - self.__description = None - - def __send(self, obj): - line = pyon.encode(obj) + "\n" - self.__writer.write(line.encode()) - - async def __recv(self): - line = await self.__reader.readline() - return pyon.decode(line.decode()) - - async def __do_rpc(self, name, args, kwargs): - await self.__lock.acquire() - try: - obj = {"action": "call", "name": name, - "args": args, "kwargs": kwargs} - self.__send(obj) - - obj = await self.__recv() - if obj["status"] == "ok": - return obj["ret"] - elif obj["status"] == "failed": - raise_packed_exc(obj["exception"]) - else: - raise ValueError - finally: - self.__lock.release() - - def __getattr__(self, name): - if name not in self.__valid_methods: - raise AttributeError - async def proxy(*args, **kwargs): - res = await self.__do_rpc(name, args, kwargs) - return res - return proxy - - -class BestEffortClient: - """This class is similar to :class:`artiq.protocols.pc_rpc.Client`, but - network errors are suppressed and connections are retried in the - background. - - RPC calls that failed because of network errors return ``None``. Other RPC - calls are blocking and return the correct value. - - :param firstcon_timeout: Timeout to use during the first (blocking) - connection attempt at object initialization. - :param retry: Amount of time to wait between retries when reconnecting - in the background. - """ - def __init__(self, host, port, target_name, - firstcon_timeout=1.0, retry=5.0): - self.__host = host - self.__port = port - self.__target_name = target_name - self.__retry = retry - - self.__conretry_terminate = False - self.__socket = None - self.__valid_methods = set() - try: - self.__coninit(firstcon_timeout) - except: - logger.warning("first connection attempt to %s:%d[%s] failed, " - "retrying in the background", - self.__host, self.__port, self.__target_name, - exc_info=True) - self.__start_conretry() - else: - self.__conretry_thread = None - - def __coninit(self, timeout): - if timeout is None: - self.__socket = socket.create_connection( - (self.__host, self.__port)) - else: - self.__socket = socket.create_connection( - (self.__host, self.__port), timeout) - self.__socket.settimeout(None) - self.__socket.sendall(_init_string) - server_identification = self.__recv() - target_name = _validate_target_name(self.__target_name, - server_identification["targets"]) - self.__socket.sendall((target_name + "\n").encode()) - self.__valid_methods = self.__recv() - - def __start_conretry(self): - self.__conretry_thread = threading.Thread(target=self.__conretry) - self.__conretry_thread.start() - - def __conretry(self): - while True: - try: - self.__coninit(None) - except: - if self.__conretry_terminate: - break - time.sleep(self.__retry) - else: - break - if not self.__conretry_terminate: - logger.warning("connection to %s:%d[%s] established in " - "the background", - self.__host, self.__port, self.__target_name) - if self.__conretry_terminate and self.__socket is not None: - self.__socket.close() - # must be after __socket.close() to avoid race condition - self.__conretry_thread = None - - def close_rpc(self): - """Closes the connection to the RPC server. - - No further method calls should be done after this method is called. - """ - if self.__conretry_thread is None: - if self.__socket is not None: - self.__socket.close() - else: - # Let the thread complete I/O and then do the socket closing. - # Python fails to provide a way to cancel threads... - self.__conretry_terminate = True - - def __send(self, obj): - line = pyon.encode(obj) + "\n" - self.__socket.sendall(line.encode()) - - def __recv(self): - buf = self.__socket.recv(4096).decode() - while "\n" not in buf: - more = self.__socket.recv(4096) - if not more: - break - buf += more.decode() - return pyon.decode(buf) - - def __do_rpc(self, name, args, kwargs): - if self.__conretry_thread is not None: - return None - - obj = {"action": "call", "name": name, "args": args, "kwargs": kwargs} - try: - self.__send(obj) - obj = self.__recv() - except: - logger.warning("connection failed while attempting " - "RPC to %s:%d[%s], re-establishing connection " - "in the background", - self.__host, self.__port, self.__target_name) - self.__start_conretry() - return None - else: - if obj["status"] == "ok": - return obj["ret"] - elif obj["status"] == "failed": - raise_packed_exc(obj["exception"]) - else: - raise ValueError - - def __getattr__(self, name): - if name not in self.__valid_methods: - raise AttributeError - def proxy(*args, **kwargs): - return self.__do_rpc(name, args, kwargs) - return proxy - - def get_selected_target(self): - raise NotImplementedError - - def get_local_host(self): - raise NotImplementedError - - -def _format_arguments(arguments): - fmtargs = [] - for k, v in sorted(arguments.items(), key=itemgetter(0)): - fmtargs.append(k + "=" + repr(v)) - if fmtargs: - return ", ".join(fmtargs) - else: - return "" - - -class _PrettyPrintCall: - def __init__(self, obj): - self.obj = obj - - def __str__(self): - r = self.obj["name"] + "(" - args = ", ".join([repr(a) for a in self.obj["args"]]) - r += args - kwargs = _format_arguments(self.obj["kwargs"]) - if args and kwargs: - r += ", " - r += kwargs - r += ")" - return r - - -class Server(_AsyncioServer): - """This class creates a TCP server that handles requests coming from - *Client* objects (whether :class:`.Client`, :class:`.BestEffortClient`, - or :class:`.AsyncioClient`). - - The server is designed using ``asyncio`` so that it can easily support - multiple connections without the locking issues that arise in - multi-threaded applications. Multiple connection support is useful even in - simple cases: it allows new connections to be be accepted even when the - previous client failed to properly shut down its connection. - - If a target method is a coroutine, it is awaited and its return value - is sent to the RPC client. If ``allow_parallel`` is true, multiple - target coroutines may be executed in parallel (one per RPC client), - otherwise a lock ensures that the calls from several clients are executed - sequentially. - - :param targets: A dictionary of objects providing the RPC methods to be - exposed to the client. Keys are names identifying each object. - Clients select one of these objects using its name upon connection. - :param description: An optional human-readable string giving more - information about the server. - :param builtin_terminate: If set, the server provides a built-in - ``terminate`` method that unblocks any tasks waiting on - ``wait_terminate``. This is useful to handle server termination - requests from clients. - :param allow_parallel: Allow concurrent asyncio calls to the target's - methods. - """ - def __init__(self, targets, description=None, builtin_terminate=False, - allow_parallel=False): - _AsyncioServer.__init__(self) - self.targets = targets - self.description = description - self.builtin_terminate = builtin_terminate - if builtin_terminate: - self._terminate_request = asyncio.Event() - if allow_parallel: - self._noparallel = None - else: - self._noparallel = asyncio.Lock() - - @staticmethod - def _document_function(function): - """ - Turn a function into a tuple of its arguments and documentation. - - Allows remote inspection of what methods are available on a local device. - - Args: - function (Callable): a Python function to be documented. - - Returns: - Tuple[dict, str]: tuple of (argument specifications, - function documentation). - Any type annotations are converted to strings (for PYON serialization). - """ - argspec_dict = dict(inspect.getfullargspec(function)._asdict()) - # Fix issue #1186: PYON can't serialize type annotations. - if any(argspec_dict.get("annotations", {})): - argspec_dict["annotations"] = str(argspec_dict["annotations"]) - return argspec_dict, inspect.getdoc(function) - - async def _process_action(self, target, obj): - if self._noparallel is not None: - await self._noparallel.acquire() - try: - if obj["action"] == "get_rpc_method_list": - members = inspect.getmembers(target, inspect.ismethod) - doc = { - "docstring": inspect.getdoc(target), - "methods": {} - } - for name, method in members: - if name.startswith("_"): - continue - method = getattr(target, name) - doc["methods"][name] = self._document_function(method) - if self.builtin_terminate: - doc["methods"]["terminate"] = ( - { - "args": ["self"], - "defaults": None, - "varargs": None, - "varkw": None, - "kwonlyargs": [], - "kwonlydefaults": [], - }, - "Terminate the server.") - logger.debug("RPC docs for %s: %s", target, doc) - return {"status": "ok", "ret": doc} - elif obj["action"] == "call": - logger.debug("calling %s", _PrettyPrintCall(obj)) - if (self.builtin_terminate and obj["name"] == - "terminate"): - self._terminate_request.set() - return {"status": "ok", "ret": None} - else: - method = getattr(target, obj["name"]) - ret = method(*obj["args"], **obj["kwargs"]) - if inspect.iscoroutine(ret): - ret = await ret - return {"status": "ok", "ret": ret} - else: - raise ValueError("Unknown action: {}" - .format(obj["action"])) - except asyncio.CancelledError: - raise - except: - return { - "status": "failed", - "exception": current_exc_packed() - } - finally: - if self._noparallel is not None: - self._noparallel.release() - - async def _handle_connection_cr(self, reader, writer): - try: - line = await reader.readline() - if line != _init_string: - return - - obj = { - "targets": sorted(self.targets.keys()), - "description": self.description - } - line = pyon.encode(obj) + "\n" - writer.write(line.encode()) - line = await reader.readline() - if not line: - return - target_name = line.decode()[:-1] - try: - target = self.targets[target_name] - except KeyError: - return - - if callable(target): - target = target() - - valid_methods = inspect.getmembers(target, inspect.ismethod) - valid_methods = {m[0] for m in valid_methods} - if self.builtin_terminate: - valid_methods.add("terminate") - writer.write((pyon.encode(valid_methods) + "\n").encode()) - - while True: - line = await reader.readline() - if not line: - break - reply = await self._process_action(target, pyon.decode(line.decode())) - writer.write((pyon.encode(reply) + "\n").encode()) - except (ConnectionResetError, ConnectionAbortedError, BrokenPipeError): - # May happens on Windows when client disconnects - pass - finally: - writer.close() - - async def wait_terminate(self): - await self._terminate_request.wait() - - -def simple_server_loop(targets, host, port, description=None): - """Runs a server until an exception is raised (e.g. the user hits Ctrl-C) - or termination is requested by a client. - - See :class:`artiq.protocols.pc_rpc.Server` for a description of the parameters. - """ - loop = asyncio.get_event_loop() - try: - server = Server(targets, description, True) - loop.run_until_complete(server.start(host, port)) - try: - loop.run_until_complete(server.wait_terminate()) - finally: - loop.run_until_complete(server.stop()) - finally: - loop.close() diff --git a/artiq/protocols/pipe_ipc.py b/artiq/protocols/pipe_ipc.py deleted file mode 100644 index e81176c4e..000000000 --- a/artiq/protocols/pipe_ipc.py +++ /dev/null @@ -1,218 +0,0 @@ -import os -import asyncio -from asyncio.streams import FlowControlMixin - - -__all__ = ["AsyncioParentComm", "AsyncioChildComm", "ChildComm"] - - -class _BaseIO: - def write(self, data): - self.writer.write(data) - - async def drain(self): - await self.writer.drain() - - async def readline(self): - return await self.reader.readline() - - async def read(self, n): - return await self.reader.read(n) - - -if os.name != "nt": - async def _fds_to_asyncio(rfd, wfd, loop): - reader = asyncio.StreamReader(loop=loop, limit=100*1024*1024) - reader_protocol = asyncio.StreamReaderProtocol(reader, loop=loop) - rf = open(rfd, "rb", 0) - rt, _ = await loop.connect_read_pipe(lambda: reader_protocol, rf) - - wf = open(wfd, "wb", 0) - wt, _ = await loop.connect_write_pipe(FlowControlMixin, wf) - writer = asyncio.StreamWriter(wt, reader_protocol, None, loop) - - return rt, reader, writer - - - class AsyncioParentComm(_BaseIO): - def __init__(self): - self.c_rfd, self.p_wfd = os.pipe() - self.p_rfd, self.c_wfd = os.pipe() - - def get_address(self): - return "{},{}".format(self.c_rfd, self.c_wfd) - - async def _autoclose(self): - await self.process.wait() - self.reader_transport.close() - self.writer.close() - - async def create_subprocess(self, *args, **kwargs): - loop = asyncio.get_event_loop() - self.process = await asyncio.create_subprocess_exec( - *args, pass_fds={self.c_rfd, self.c_wfd}, **kwargs) - os.close(self.c_rfd) - os.close(self.c_wfd) - - self.reader_transport, self.reader, self.writer = \ - await _fds_to_asyncio(self.p_rfd, self.p_wfd, loop) - asyncio.ensure_future(self._autoclose()) - - - class AsyncioChildComm(_BaseIO): - def __init__(self, address): - self.address = address - - async def connect(self): - rfd, wfd = self.address.split(",", maxsplit=1) - self.reader_transport, self.reader, self.writer = \ - await _fds_to_asyncio(int(rfd), int(wfd), - asyncio.get_event_loop()) - - def close(self): - self.reader_transport.close() - self.writer.close() - - - class ChildComm: - def __init__(self, address): - rfd, wfd = address.split(",", maxsplit=1) - self.rf = open(int(rfd), "rb", 0) - self.wf = open(int(wfd), "wb", 0) - - def read(self, n): - return self.rf.read(n) - - def readline(self): - return self.rf.readline() - - def write(self, data): - return self.wf.write(data) - - def close(self): - self.rf.close() - self.wf.close() - - -else: # windows - import itertools - - - _pipe_count = itertools.count() - - - class AsyncioParentComm: - """Requires ProactorEventLoop""" - def __init__(self): - # We cannot use anonymous pipes on Windows, because we do not know - # in advance if the child process wants a handle open in overlapped - # mode or not. - self.address = "\\\\.\\pipe\\artiq-{}-{}".format(os.getpid(), - next(_pipe_count)) - self.ready = asyncio.Event() - self.write_buffer = b"" - - def get_address(self): - return self.address - - async def _autoclose(self): - await self.process.wait() - self.server[0].close() - del self.server - if self.ready.is_set(): - self.writer.close() - del self.reader - del self.writer - - async def create_subprocess(self, *args, **kwargs): - loop = asyncio.get_event_loop() - - def factory(): - reader = asyncio.StreamReader(loop=loop, limit=100*1024*1024) - protocol = asyncio.StreamReaderProtocol(reader, - self._child_connected, - loop=loop) - return protocol - self.server = await loop.start_serving_pipe( - factory, self.address) - - self.process = await asyncio.create_subprocess_exec( - *args, **kwargs) - asyncio.ensure_future(self._autoclose()) - - def _child_connected(self, reader, writer): - # HACK: We should shut down the pipe server here. - # However, self.server[0].close() is racy, and will cause an - # invalid handle error if loop.start_serving_pipe has not finished - # its work in the background. - # The bug manifests itself here frequently as the event loop is - # reopening the server as soon as a new client connects. - # There is still a race condition in the AsyncioParentComm - # creation/destruction, but it is unlikely to cause problems - # in most practical cases. - if self.ready.is_set(): - # A child already connected before. We should have shut down - # the server, but asyncio won't let us do that. - # Drop connections immediately instead. - writer.close() - return - self.reader = reader - self.writer = writer - if self.write_buffer: - self.writer.write(self.write_buffer) - self.write_buffer = b"" - self.ready.set() - - def write(self, data): - if self.ready.is_set(): - self.writer.write(data) - else: - self.write_buffer += data - - async def drain(self): - await self.ready.wait() - await self.writer.drain() - - async def readline(self): - await self.ready.wait() - return await self.reader.readline() - - async def read(self, n): - await self.ready.wait() - return await self.reader.read(n) - - - class AsyncioChildComm(_BaseIO): - """Requires ProactorEventLoop""" - def __init__(self, address): - self.address = address - - async def connect(self): - loop = asyncio.get_event_loop() - self.reader = asyncio.StreamReader(loop=loop, limit=100*1024*1024) - reader_protocol = asyncio.StreamReaderProtocol( - self.reader, loop=loop) - transport, _ = await loop.create_pipe_connection( - lambda: reader_protocol, self.address) - self.writer = asyncio.StreamWriter(transport, reader_protocol, - self.reader, loop) - - def close(self): - self.writer.close() - - - class ChildComm: - def __init__(self, address): - self.f = open(address, "a+b", 0) - - def read(self, n): - return self.f.read(n) - - def readline(self): - return self.f.readline() - - def write(self, data): - return self.f.write(data) - - def close(self): - self.f.close() diff --git a/artiq/protocols/pyon.py b/artiq/protocols/pyon.py deleted file mode 100644 index 2ad6755fd..000000000 --- a/artiq/protocols/pyon.py +++ /dev/null @@ -1,227 +0,0 @@ -""" -This module provides serialization and deserialization functions for Python -objects. Its main features are: - -* Human-readable format compatible with the Python syntax. -* Each object is serialized on a single line, with only ASCII characters. -* Supports all basic Python data structures: None, booleans, integers, - floats, complex numbers, strings, tuples, lists, dictionaries. -* Those data types are accurately reconstructed (unlike JSON where e.g. tuples - become lists, and dictionary keys are turned into strings). -* Supports Numpy arrays. - -The main rationale for this new custom serializer (instead of using JSON) is -that JSON does not support Numpy and more generally cannot be extended with -other data types while keeping a concise syntax. Here we can use the Python -function call syntax to express special data types. -""" - - -from operator import itemgetter -import base64 -from fractions import Fraction -from collections import OrderedDict -import os -import tempfile - -import numpy - - -_encode_map = { - type(None): "none", - bool: "bool", - int: "number", - float: "number", - complex: "number", - str: "str", - bytes: "bytes", - tuple: "tuple", - list: "list", - set: "set", - dict: "dict", - slice: "slice", - Fraction: "fraction", - OrderedDict: "ordereddict", - numpy.ndarray: "nparray" -} - -_numpy_scalar = { - "int8", "int16", "int32", "int64", - "uint8", "uint16", "uint32", "uint64", - "float16", "float32", "float64", - "complex64", "complex128", -} - - -for _t in _numpy_scalar: - _encode_map[getattr(numpy, _t)] = "npscalar" - - -_str_translation = { - ord("\""): "\\\"", - ord("\\"): "\\\\", - ord("\n"): "\\n", - ord("\r"): "\\r", -} - - -class _Encoder: - def __init__(self, pretty): - self.pretty = pretty - self.indent_level = 0 - - def indent(self): - return " "*self.indent_level - - def encode_none(self, x): - return "null" - - def encode_bool(self, x): - if x: - return "true" - else: - return "false" - - def encode_number(self, x): - return repr(x) - - def encode_str(self, x): - # Do not use repr() for JSON compatibility. - return "\"" + x.translate(_str_translation) + "\"" - - def encode_bytes(self, x): - return repr(x) - - def encode_tuple(self, x): - if len(x) == 1: - return "(" + self.encode(x[0]) + ", )" - else: - r = "(" - r += ", ".join([self.encode(item) for item in x]) - r += ")" - return r - - def encode_list(self, x): - r = "[" - r += ", ".join([self.encode(item) for item in x]) - r += "]" - return r - - def encode_set(self, x): - r = "{" - r += ", ".join([self.encode(item) for item in x]) - r += "}" - return r - - def encode_dict(self, x): - if self.pretty and all(k.__class__ == str for k in x.keys()): - items = lambda: sorted(x.items(), key=itemgetter(0)) - else: - items = x.items - - r = "{" - if not self.pretty or len(x) < 2: - r += ", ".join([self.encode(k) + ": " + self.encode(v) - for k, v in items()]) - else: - self.indent_level += 1 - r += "\n" - first = True - for k, v in items(): - if not first: - r += ",\n" - first = False - r += self.indent() + self.encode(k) + ": " + self.encode(v) - r += "\n" # no ',' - self.indent_level -= 1 - r += self.indent() - r += "}" - return r - - def encode_slice(self, x): - return repr(x) - - def encode_fraction(self, x): - return "Fraction({}, {})".format(self.encode(x.numerator), - self.encode(x.denominator)) - - def encode_ordereddict(self, x): - return "OrderedDict(" + self.encode(list(x.items())) + ")" - - def encode_nparray(self, x): - r = "nparray(" - r += self.encode(x.shape) + ", " - r += self.encode(x.dtype.str) + ", " - r += self.encode(base64.b64encode(x.data)) - r += ")" - return r - - def encode_npscalar(self, x): - r = "npscalar(" - r += self.encode(x.dtype.str) + ", " - r += self.encode(base64.b64encode(x.data)) - r += ")" - return r - - def encode(self, x): - ty = _encode_map.get(type(x), None) - if ty is None: - raise TypeError("`{!r}` ({}) is not PYON serializable" - .format(x, type(x))) - return getattr(self, "encode_" + ty)(x) - - -def encode(x, pretty=False): - """Serializes a Python object and returns the corresponding string in - Python syntax.""" - return _Encoder(pretty).encode(x) - - -def _nparray(shape, dtype, data): - a = numpy.frombuffer(base64.b64decode(data), dtype=dtype) - a = a.copy() - return a.reshape(shape) - - -def _npscalar(ty, data): - return numpy.frombuffer(base64.b64decode(data), dtype=ty)[0] - - -_eval_dict = { - "__builtins__": {}, - - "null": None, - "false": False, - "true": True, - "inf": numpy.inf, - "slice": slice, - "nan": numpy.nan, - - "Fraction": Fraction, - "OrderedDict": OrderedDict, - "nparray": _nparray, - "npscalar": _npscalar -} - - -def decode(s): - """Parses a string in the Python syntax, reconstructs the corresponding - object, and returns it.""" - return eval(s, _eval_dict, {}) - - -def store_file(filename, x): - """Encodes a Python object and writes it to the specified file.""" - contents = encode(x, True) - directory = os.path.abspath(os.path.dirname(filename)) - with tempfile.NamedTemporaryFile("w", dir=directory, delete=False) as f: - f.write(contents) - f.write("\n") - tmpname = f.name - os.replace(tmpname, filename) - - -def load_file(filename): - """Parses the specified file and returns the decoded Python object.""" - with open(filename, "r") as f: - return decode(f.read()) diff --git a/artiq/protocols/remote_exec.py b/artiq/protocols/remote_exec.py deleted file mode 100644 index ae9870c30..000000000 --- a/artiq/protocols/remote_exec.py +++ /dev/null @@ -1,116 +0,0 @@ -""" -This module provides facilities for experiment to execute code remotely on -controllers. - -The remotely executed code has direct access to the driver, so it can transfer -large amounts of data with it, and only exchange higher-level, processed data -with the experiment (and over the network). - -Controllers with support for remote execution contain an additional target -that gives RPC access to instances of :class:`.RemoteExecServer`. One such instance -is created per client (experiment) connection and manages one Python namespace -in which the experiment can execute arbitrary code by calling the methods of -:class:`.RemoteExecServer`. - -The namespaces are initialized with the following global values: - - * ``controller_driver`` - the driver instance of the controller. - * ``controller_initial_namespace`` - a controller-wide dictionary copied - when initializing a new namespace. - * all values from ``controller_initial_namespace``. - -Access to a controller with support for remote execution is done through an -additional device database entry of this form: :: - - "$REXEC_DEVICE_NAME": { - "type": "controller_aux_target", - "controller": "$CONTROLLER_DEVICE_NAME", - "target_name": "$TARGET_NAME_FOR_REXEC" - } - -Specifying ``target_name`` is mandatory in all device database entries for all -controllers with remote execution support. - -""" - -from functools import partial -import inspect - -from artiq.protocols.pc_rpc import simple_server_loop - - -__all__ = ["RemoteExecServer", "simple_rexec_server_loop", "connect_global_rpc"] - - -class RemoteExecServer: - """RPC target created at each connection by controllers with remote - execution support. Manages one Python namespace and provides RPCs - for code execution. - """ - def __init__(self, initial_namespace): - self.namespace = dict(initial_namespace) - # The module actually has to exist, otherwise it breaks e.g. Numba - self.namespace["__name__"] = "artiq.protocols.remote_exec" - - def add_code(self, code): - """Executes the specified code in the namespace. - - :param code: a string containing valid Python code - """ - exec(code, self.namespace) - - def call(self, function, *args, **kwargs): - """Calls a function in the namespace, passing it positional and - keyword arguments, and returns its value. - - :param function: a string containing the name of the function to - execute. - """ - return self.namespace[function](*args, **kwargs) - - -def simple_rexec_server_loop(target_name, target, host, port, - description=None): - """Runs a server with remote execution support, until an exception is - raised (e.g. the user hits Ctrl-C) or termination is requested by a client. - """ - initial_namespace = {"controller_driver": target} - initial_namespace["controller_initial_namespace"] = initial_namespace - targets = { - target_name: target, - target_name + "_rexec": lambda: RemoteExecServer(initial_namespace) - } - simple_server_loop(targets, host, port, description) - - -def connect_global_rpc(controller_rexec, host=None, port=3251, - target="master_dataset_db", name="dataset_db"): - """Creates a global RPC client in a controller that is used across - all remote execution connections. With the default parameters, it connects - to the dataset database (i.e. gives direct dataset access to experiment - code remotely executing in controllers). - - If a global object with the same name already exists, the function does - nothing. - - :param controller_rexec: the RPC client connected to the controller's - remote execution interface. - :param host: the host name to connect the RPC client to. Default is the - local end of the remote execution interface (typically, the ARTIQ - master). - :param port: TCP port to connect the RPC client to. - :param target: name of the RPC target. - :param name: name of the object to insert into the global namespace. - """ - if host is None: - host = controller_rexec.get_local_host() - code = """ -if "{name}" not in controller_initial_namespace: - import atexit - from artiq.protocols.pc_rpc import Client - - {name} = Client("{host}", {port}, "{target}") - atexit.register({name}.close_rpc) - controller_initial_namespace["{name}"] = {name} -""".format(host=host, port=port, target=target, name=name) - controller_rexec.add_code(code) diff --git a/artiq/protocols/sync_struct.py b/artiq/protocols/sync_struct.py deleted file mode 100644 index 02db70ffc..000000000 --- a/artiq/protocols/sync_struct.py +++ /dev/null @@ -1,328 +0,0 @@ -"""This module helps synchronizing a mutable Python structure owned and -modified by one process (the *publisher*) with copies of it (the -*subscribers*) in different processes and possibly different machines. - -Synchronization is achieved by sending a full copy of the structure to each -subscriber upon connection (*initialization*), followed by dictionaries -describing each modification made to the structure (*mods*, see -:class:`ModAction`). - -Structures must be PYON serializable and contain only lists, dicts, and -immutable types. Lists and dicts can be nested arbitrarily. -""" - -import asyncio -from enum import Enum, unique -from operator import getitem -from functools import partial - -from artiq.monkey_patches import * -from artiq.protocols import pyon -from artiq.protocols.asyncio_server import AsyncioServer - - -_protocol_banner = b"ARTIQ sync_struct\n" - - -@unique -class ModAction(Enum): - """Describes the type of incremental modification. - - `Mods` are represented by a dictionary ``m``. ``m["action"]`` describes - the type of modification, as per this enum, serialized as a string if - required. - - The path (member field) the change applies to is given in - ``m["path"]`` as a list; elements give successive levels of indexing. - (There is no ``path`` on initial initialization.) - - Details on the modification are stored in additional data fields specific - to each type. - - For example, this represents appending the value ``42`` to an array - ``data.counts[0]``: :: - - { - "action": "append", - "path": ["data", "counts", 0], - "x": 42 - } - """ - - #: A full copy of the data is sent in `struct`; no `path` given. - init = "init" - - #: Appends `x` to target list. - append = "append" - - #: Inserts `x` into target list at index `i`. - insert = "insert" - - #: Removes index `i` from target list. - pop = "pop" - - #: Sets target's `key` to `value`. - setitem = "setitem" - - #: Removes target's `key`. - delitem = "delitem" - - -# Handlers to apply a given mod to a target dict, invoked with (target, mod). -_mod_appliers = { - ModAction.append: lambda t, m: t.append(m["x"]), - ModAction.insert: lambda t, m: t.insert(m["i"], m["x"]), - ModAction.pop: lambda t, m: t.pop(m["i"]), - ModAction.setitem: lambda t, m: t.__setitem__(m["key"], m["value"]), - ModAction.delitem: lambda t, m: t.__delitem__(m["key"]) -} - - -def process_mod(target, mod): - """Apply a *mod* to the target, mutating it.""" - for key in mod["path"]: - target = getitem(target, key) - - _mod_appliers[ModAction(mod["action"])](target, mod) - - -class Subscriber: - """An asyncio-based client to connect to a ``Publisher``. - - :param notifier_name: Name of the notifier to subscribe to. - :param target_builder: A function called during initialization that takes - the object received from the publisher and returns the corresponding - local structure to use. Can be identity. - :param notify_cb: An optional function called every time a mod is received - from the publisher. The mod is passed as parameter. The function is - called after the mod has been processed. - A list of functions may also be used, and they will be called in turn. - :param disconnect_cb: An optional function called when disconnection - happens from external causes (i.e. not when ``close`` is called). - """ - def __init__(self, notifier_name, target_builder, notify_cb=None, - disconnect_cb=None): - self.notifier_name = notifier_name - self.target_builder = target_builder - if notify_cb is None: - notify_cb = [] - if not isinstance(notify_cb, list): - notify_cb = [notify_cb] - self.notify_cbs = notify_cb - self.disconnect_cb = disconnect_cb - - async def connect(self, host, port, before_receive_cb=None): - self.reader, self.writer = \ - await asyncio.open_connection(host, port, limit=100*1024*1024) - try: - if before_receive_cb is not None: - before_receive_cb() - self.writer.write(_protocol_banner) - self.writer.write((self.notifier_name + "\n").encode()) - self.receive_task = asyncio.ensure_future(self._receive_cr()) - except: - self.writer.close() - del self.reader - del self.writer - raise - - async def close(self): - self.disconnect_cb = None - try: - self.receive_task.cancel() - try: - await asyncio.wait_for(self.receive_task, None) - except asyncio.CancelledError: - pass - finally: - self.writer.close() - del self.reader - del self.writer - - async def _receive_cr(self): - try: - target = None - while True: - line = await self.reader.readline() - if not line: - return - mod = pyon.decode(line.decode()) - - if mod["action"] == "init": - target = self.target_builder(mod["struct"]) - else: - process_mod(target, mod) - - for notify_cb in self.notify_cbs: - notify_cb(mod) - except ConnectionError: - pass - finally: - if self.disconnect_cb is not None: - self.disconnect_cb() - - -class Notifier: - """Encapsulates a structure whose changes need to be published. - - All mutations to the structure must be made through the :class:`.Notifier`. - The original structure must only be accessed for reads. - - In addition to the list methods below, the :class:`.Notifier` supports the - index syntax for modification and deletion of elements. Modification of - nested structures can be also done using the index syntax, for example: - - >>> n = Notifier([]) - >>> n.append([]) - >>> n[0].append(42) - >>> n.raw_view - [[42]] - - This class does not perform any network I/O and is meant to be used with - e.g. the :class:`.Publisher` for this purpose. Only one publisher at most - can be associated with a :class:`.Notifier`. - - :param backing_struct: Structure to encapsulate. - """ - def __init__(self, backing_struct, root=None, path=[]): - #: The raw data encapsulated (read-only!). - self.raw_view = backing_struct - - if root is None: - self.root = self - self.publish = None - else: - self.root = root - self._backing_struct = backing_struct - self._path = path - - # Backing struct modification methods. - # All modifications must go through them! - - def append(self, x): - """Append to a list.""" - self._backing_struct.append(x) - if self.root.publish is not None: - self.root.publish({"action": ModAction.append.value, - "path": self._path, - "x": x}) - - def insert(self, i, x): - """Insert an element into a list.""" - self._backing_struct.insert(i, x) - if self.root.publish is not None: - self.root.publish({"action": ModAction.insert.value, - "path": self._path, - "i": i, "x": x}) - - def pop(self, i=-1): - """Pop an element from a list. The returned element is not - encapsulated in a :class:`.Notifier` and its mutations are no longer - tracked.""" - r = self._backing_struct.pop(i) - if self.root.publish is not None: - self.root.publish({"action": ModAction.pop.value, - "path": self._path, - "i": i}) - return r - - def __setitem__(self, key, value): - self._backing_struct.__setitem__(key, value) - if self.root.publish is not None: - self.root.publish({"action": ModAction.setitem.value, - "path": self._path, - "key": key, - "value": value}) - - def __delitem__(self, key): - self._backing_struct.__delitem__(key) - if self.root.publish is not None: - self.root.publish({"action": ModAction.delitem.value, - "path": self._path, - "key": key}) - - def __getitem__(self, key): - item = getitem(self._backing_struct, key) - return Notifier(item, self.root, self._path + [key]) - - -def update_from_dict(target, source): - """Updates notifier contents from given source dictionary. - - Only the necessary changes are performed; unchanged fields are not written. - (Currently, modifications are only performed at the top level. That is, - whenever there is a change to a child array/struct the entire member is - updated instead of choosing a more optimal set of mods.) - """ - curr = target.raw_view - - # Delete removed keys. - for k in list(curr.keys()): - if k not in source: - del target[k] - - # Insert/update changed data. - for k in source.keys(): - if k not in curr or curr[k] != source[k]: - target[k] = source[k] - - -class Publisher(AsyncioServer): - """A network server that publish changes to structures encapsulated in - a :class:`.Notifier`. - - :param notifiers: A dictionary containing the notifiers to associate with - the :class:`.Publisher`. The keys of the dictionary are the names of - the notifiers to be used with :class:`.Subscriber`. - """ - def __init__(self, notifiers): - AsyncioServer.__init__(self) - self.notifiers = notifiers - self._recipients = {k: set() for k in notifiers.keys()} - self._notifier_names = {id(v): k for k, v in notifiers.items()} - - for notifier in notifiers.values(): - notifier.publish = partial(self.publish, notifier) - - async def _handle_connection_cr(self, reader, writer): - try: - line = await reader.readline() - if line != _protocol_banner: - return - - line = await reader.readline() - if not line: - return - notifier_name = line.decode()[:-1] - - try: - notifier = self.notifiers[notifier_name] - except KeyError: - return - - obj = {"action": ModAction.init.value, "struct": notifier.raw_view} - line = pyon.encode(obj) + "\n" - writer.write(line.encode()) - - queue = asyncio.Queue() - self._recipients[notifier_name].add(queue) - try: - while True: - line = await queue.get() - writer.write(line) - # raise exception on connection error - await writer.drain() - finally: - self._recipients[notifier_name].remove(queue) - except (ConnectionError, TimeoutError): - # subscribers disconnecting are a normal occurrence - pass - finally: - writer.close() - - def publish(self, notifier, mod): - line = pyon.encode(mod) + "\n" - line = line.encode() - notifier_name = self._notifier_names[id(notifier)] - for recipient in self._recipients[notifier_name]: - recipient.put_nowait(line) diff --git a/artiq/test/hardware_testbench.py b/artiq/test/hardware_testbench.py index d13a2f68e..987a1cf6b 100644 --- a/artiq/test/hardware_testbench.py +++ b/artiq/test/hardware_testbench.py @@ -5,96 +5,17 @@ import os import sys import unittest import logging -import subprocess -import shlex -import time -import socket from artiq.master.databases import DeviceDB, DatasetDB from artiq.master.worker_db import DeviceManager, DatasetManager, DeviceError from artiq.coredevice.core import CompileError from artiq.frontend.artiq_run import DummyScheduler -from artiq.protocols.pc_rpc import AutoTarget, Client artiq_root = os.getenv("ARTIQ_ROOT") logger = logging.getLogger(__name__) -class GenericControllerCase(unittest.TestCase): - def get_device_db(self): - raise NotImplementedError - - def setUp(self): - self.device_db = self.get_device_db() - self.device_mgr = DeviceManager(self.device_db) - self.controllers = {} - - def tearDown(self): - self.device_mgr.close_devices() - for name in list(self.controllers): - self.stop_controller(name) - - def start_controller(self, name, sleep=1): - if name in self.controllers: - raise ValueError("controller `{}` already started".format(name)) - try: - entry = self.device_db.get(name) - except KeyError: - raise unittest.SkipTest( - "controller `{}` not found".format(name)) - entry["command"] = entry["command"].format( - name=name, bind=entry["host"], port=entry["port"]) - proc = subprocess.Popen(shlex.split(entry["command"])) - self.controllers[name] = entry, proc - time.sleep(sleep) - - def stop_controller(self, name, default_timeout=1): - desc, proc = self.controllers[name] - t = desc.get("term_timeout", default_timeout) - target_name = desc.get("target_name", None) - if target_name is None: - target_name = AutoTarget - try: - try: - client = Client(desc["host"], desc["port"], target_name, t) - try: - client.terminate() - finally: - client.close_rpc() - proc.wait(t) - return - except (socket.timeout, subprocess.TimeoutExpired): - logger.warning("Controller %s failed to exit on request", name) - try: - proc.terminate() - except ProcessLookupError: - pass - try: - proc.wait(t) - return - except subprocess.TimeoutExpired: - logger.warning("Controller %s failed to exit on terminate", - name) - try: - proc.kill() - except ProcessLookupError: - pass - try: - proc.wait(t) - return - except subprocess.TimeoutExpired: - logger.warning("Controller %s failed to die on kill", name) - finally: - del self.controllers[name] - - -@unittest.skipUnless(artiq_root, "no ARTIQ_ROOT") -class ControllerCase(GenericControllerCase): - def get_device_db(self): - return DeviceDB(os.path.join(artiq_root, "device_db.py")) - - @unittest.skipUnless(artiq_root, "no ARTIQ_ROOT") class ExperimentCase(unittest.TestCase): def setUp(self): diff --git a/artiq/test/test_ctlmgr.py b/artiq/test/test_ctlmgr.py index bc9031bce..728353033 100644 --- a/artiq/test/test_ctlmgr.py +++ b/artiq/test/test_ctlmgr.py @@ -4,10 +4,12 @@ import unittest import logging import asyncio +from sipyco.pc_rpc import AsyncioClient + from artiq.master.ctlmgr import Controllers -from artiq.protocols.pc_rpc import AsyncioClient from artiq.tools import expect_no_log_messages + logger = logging.getLogger(__name__) diff --git a/artiq/test/test_datasets.py b/artiq/test/test_datasets.py index 4ea48cc6e..871568a2a 100644 --- a/artiq/test/test_datasets.py +++ b/artiq/test/test_datasets.py @@ -3,9 +3,10 @@ import copy import unittest +from sipyco.sync_struct import process_mod + from artiq.experiment import EnvExperiment from artiq.master.worker_db import DatasetManager -from artiq.protocols.sync_struct import process_mod class MockDatasetDB: diff --git a/artiq/test/test_fire_and_forget.py b/artiq/test/test_fire_and_forget.py new file mode 100644 index 000000000..fb8e67555 --- /dev/null +++ b/artiq/test/test_fire_and_forget.py @@ -0,0 +1,17 @@ +import unittest + +from artiq.protocols import fire_and_forget + + +class FireAndForgetCase(unittest.TestCase): + def _set_ok(self): + self.ok = True + + def test_fire_and_forget(self): + self.ok = False + p = fire_and_forget.FFProxy(self) + p._set_ok() + with self.assertRaises(AttributeError): + p.non_existing_method + p.ff_join() + self.assertTrue(self.ok) diff --git a/artiq/test/test_frontends.py b/artiq/test/test_frontends.py index 243f42ac3..0d88fb328 100644 --- a/artiq/test/test_frontends.py +++ b/artiq/test/test_frontends.py @@ -15,7 +15,7 @@ class TestFrontends(unittest.TestCase): "artiq": [ "client", "compile", "coreanalyzer", "coremgmt", "ctlmgr", "netboot", "flash", "influxdb", "master", "mkfs", "route", - "rpctool", "rtiomon", "run", "session" + "rtiomon", "run", "session" ] } diff --git a/artiq/test/test_pc_rpc.py b/artiq/test/test_pc_rpc.py deleted file mode 100644 index 8b095fe9e..000000000 --- a/artiq/test/test_pc_rpc.py +++ /dev/null @@ -1,166 +0,0 @@ -import asyncio -import inspect -import subprocess -import sys -import time -import unittest - -import numpy as np - -from artiq.protocols import fire_and_forget, pc_rpc, pyon - -test_address = "::1" -test_port = 7777 -test_object = [5, 2.1, None, True, False, - {"a": 5, 2: np.linspace(0, 10, 1)}, - (4, 5), (10,), "ab\nx\"'"] - - -class RPCCase(unittest.TestCase): - def _run_server_and_test(self, test, *args): - # running this file outside of unittest starts the echo server - with subprocess.Popen([sys.executable, - sys.modules[__name__].__file__]) as proc: - try: - test(*args) - finally: - try: - proc.wait(timeout=1) - except subprocess.TimeoutExpired: - proc.kill() - raise - - def _blocking_echo(self, target): - for attempt in range(100): - time.sleep(.2) - try: - remote = pc_rpc.Client(test_address, test_port, - target) - except ConnectionRefusedError: - pass - else: - break - try: - test_object_back = remote.echo(test_object) - self.assertEqual(test_object, test_object_back) - test_object_back = remote.async_echo(test_object) - self.assertEqual(test_object, test_object_back) - with self.assertRaises(AttributeError): - remote.non_existing_method - remote.terminate() - finally: - remote.close_rpc() - - def test_blocking_echo(self): - self._run_server_and_test(self._blocking_echo, "test") - - def test_blocking_echo_autotarget(self): - self._run_server_and_test(self._blocking_echo, pc_rpc.AutoTarget) - - async def _asyncio_echo(self, target): - remote = pc_rpc.AsyncioClient() - for attempt in range(100): - await asyncio.sleep(.2) - try: - await remote.connect_rpc(test_address, test_port, target) - except ConnectionRefusedError: - pass - else: - break - try: - test_object_back = await remote.echo(test_object) - self.assertEqual(test_object, test_object_back) - test_object_back = await remote.async_echo(test_object) - self.assertEqual(test_object, test_object_back) - with self.assertRaises(AttributeError): - await remote.non_existing_method - await remote.terminate() - finally: - remote.close_rpc() - - def _loop_asyncio_echo(self, target): - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - try: - loop.run_until_complete(self._asyncio_echo(target)) - finally: - loop.close() - - def test_asyncio_echo(self): - self._run_server_and_test(self._loop_asyncio_echo, "test") - - def test_asyncio_echo_autotarget(self): - self._run_server_and_test(self._loop_asyncio_echo, pc_rpc.AutoTarget) - - def test_rpc_encode_function(self): - """Test that `pc_rpc` can encode a function properly. - - Used in `get_rpc_method_list` part of - :meth:`artiq.protocols.pc_rpc.Server._process_action` - """ - - def _annotated_function( - arg1: str, arg2: np.ndarray = np.array([1,]) - ) -> np.ndarray: - """Sample docstring.""" - return arg1 - - argspec_documented, docstring = pc_rpc.Server._document_function( - _annotated_function - ) - self.assertEqual(docstring, "Sample docstring.") - - # purposefully ignore how argspec["annotations"] is treated. - # allows option to change PYON later to encode annotations. - argspec_master = dict(inspect.getfullargspec(_annotated_function)._asdict()) - argspec_without_annotation = argspec_master.copy() - del argspec_without_annotation["annotations"] - # check if all items (excluding annotations) are same in both dictionaries - self.assertLessEqual( - argspec_without_annotation.items(), argspec_documented.items() - ) - self.assertDictEqual( - argspec_documented, pyon.decode(pyon.encode(argspec_documented)) - ) - - -class FireAndForgetCase(unittest.TestCase): - def _set_ok(self): - self.ok = True - - def test_fire_and_forget(self): - self.ok = False - p = fire_and_forget.FFProxy(self) - p._set_ok() - with self.assertRaises(AttributeError): - p.non_existing_method - p.ff_join() - self.assertTrue(self.ok) - - -class Echo: - def echo(self, x): - return x - - async def async_echo(self, x): - await asyncio.sleep(0.01) - return x - - -def run_server(): - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - try: - echo = Echo() - server = pc_rpc.Server({"test": echo}, builtin_terminate=True) - loop.run_until_complete(server.start(test_address, test_port)) - try: - loop.run_until_complete(server.wait_terminate()) - finally: - loop.run_until_complete(server.stop()) - finally: - loop.close() - - -if __name__ == "__main__": - run_server() diff --git a/artiq/test/test_pipe_ipc.py b/artiq/test/test_pipe_ipc.py deleted file mode 100644 index b066d4276..000000000 --- a/artiq/test/test_pipe_ipc.py +++ /dev/null @@ -1,80 +0,0 @@ -import unittest -import sys -import asyncio -import os - -from artiq.protocols import pipe_ipc - - -class IPCCase(unittest.TestCase): - def setUp(self): - if os.name == "nt": - self.loop = asyncio.ProactorEventLoop() - else: - self.loop = asyncio.new_event_loop() - asyncio.set_event_loop(self.loop) - - def tearDown(self): - self.loop.close() - - async def _coro_test(self, child_asyncio): - ipc = pipe_ipc.AsyncioParentComm() - await ipc.create_subprocess(sys.executable, - sys.modules[__name__].__file__, - str(child_asyncio), - ipc.get_address()) - for i in range(10): - ipc.write("{}\n".format(i).encode()) - await ipc.drain() - s = (await ipc.readline()).decode() - self.assertEqual(int(s), i+1) - ipc.write(b"-1\n") - await ipc.process.wait() - - def test_blocking(self): - self.loop.run_until_complete(self._coro_test(False)) - - def test_asyncio(self): - self.loop.run_until_complete(self._coro_test(True)) - - -def run_child_blocking(): - child_comm = pipe_ipc.ChildComm(sys.argv[2]) - while True: - x = int(child_comm.readline().decode()) - if x < 0: - break - child_comm.write((str(x+1) + "\n").encode()) - child_comm.close() - - -async def coro_child(): - child_comm = pipe_ipc.AsyncioChildComm(sys.argv[2]) - await child_comm.connect() - while True: - x = int((await child_comm.readline()).decode()) - if x < 0: - break - child_comm.write((str(x+1) + "\n").encode()) - await child_comm.drain() - child_comm.close() - - -def run_child_asyncio(): - if os.name == "nt": - loop = asyncio.ProactorEventLoop() - asyncio.set_event_loop(loop) - else: - loop = asyncio.get_event_loop() - loop.run_until_complete(coro_child()) - loop.close() - - -def run_child(): - if sys.argv[1] == "True": - run_child_asyncio() - else: - run_child_blocking() - -if __name__ == "__main__": - run_child() diff --git a/artiq/test/test_rpctool.py b/artiq/test/test_rpctool.py deleted file mode 100644 index fb74395bf..000000000 --- a/artiq/test/test_rpctool.py +++ /dev/null @@ -1,39 +0,0 @@ -import os -import sys -import asyncio -import unittest - -from artiq.protocols.pc_rpc import Server - - -class Target: - def output_value(self): - return 4125380 - - -class TestRPCTool(unittest.TestCase): - async def check_value(self): - proc = await asyncio.create_subprocess_exec( - sys.executable, "-m", "artiq.frontend.artiq_rpctool", "::1", "7777", "call", "output_value", - stdout = asyncio.subprocess.PIPE) - (value, err) = await proc.communicate() - self.assertEqual(value.decode('ascii').rstrip(), '4125380') - await proc.wait() - - async def do_test(self): - server = Server({"target": Target()}) - await server.start("::1", 7777) - await self.check_value() - await server.stop() - - def test_rpc(self): - if os.name == "nt": - loop = asyncio.ProactorEventLoop() - else: - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - try: - loop.run_until_complete(self.do_test()) - finally: - loop.close() - diff --git a/artiq/test/test_serialization.py b/artiq/test/test_serialization.py deleted file mode 100644 index 803e42cde..000000000 --- a/artiq/test/test_serialization.py +++ /dev/null @@ -1,56 +0,0 @@ -import unittest -import json -from fractions import Fraction - -import numpy as np - -from artiq.protocols import pyon - - -_pyon_test_object = { - (1, 2): [(3, 4.2), (2, )], - "slice": slice(3), - Fraction(3, 4): np.linspace(5, 10, 1), - "set": {"testing", "sets"}, - "a": np.int8(9), "b": np.int16(-98), "c": np.int32(42), "d": np.int64(-5), - "e": np.uint8(8), "f": np.uint16(5), "g": np.uint32(4), "h": np.uint64(9), - "x": np.float16(9.0), "y": np.float32(9.0), "z": np.float64(9.0), - 1j: 1-9j, - "q": np.complex128(1j), -} - - -class PYON(unittest.TestCase): - def test_encdec(self): - for enc in pyon.encode, lambda x: pyon.encode(x, True): - with self.subTest(enc=enc): - self.assertEqual(pyon.decode(enc(_pyon_test_object)), - _pyon_test_object) - # NaNs don't compare equal, so test separately. - assert np.isnan(pyon.decode(enc(np.nan))) - - def test_encdec_array(self): - orig = {k: (np.array(v), np.array([v])) - for k, v in _pyon_test_object.items() - if np.isscalar(v)} - for enc in pyon.encode, lambda x: pyon.encode(x, True): - result = pyon.decode(enc(orig)) - for k in orig: - with self.subTest(enc=enc, k=k, v=orig[k]): - np.testing.assert_equal(result[k], orig[k]) - - -_json_test_object = { - "a": "b", - "x": [1, 2, {}], - "foo\nbaz\\qux\"\r2": ["bar", 1.2, {"x": "y"}], - "bar": [True, False, None] -} - - -class JSONPYON(unittest.TestCase): - def test_encdec(self): - for enc in pyon.encode, lambda x: pyon.encode(x, True), json.dumps: - for dec in pyon.decode, json.loads: - self.assertEqual(dec(enc(_json_test_object)), - _json_test_object) diff --git a/artiq/test/test_sync_struct.py b/artiq/test/test_sync_struct.py deleted file mode 100644 index 2352508ac..000000000 --- a/artiq/test/test_sync_struct.py +++ /dev/null @@ -1,72 +0,0 @@ -import unittest -import asyncio -import numpy as np - -from artiq.protocols import sync_struct - -test_address = "::1" -test_port = 7777 - - -def write_test_data(test_dict): - test_values = [5, 2.1, None, True, False, - {"a": 5, 2: np.linspace(0, 10, 1)}, - (4, 5), (10,), "ab\nx\"'"] - for i in range(10): - test_dict[str(i)] = i - for key, value in enumerate(test_values): - test_dict[key] = value - test_dict[1.5] = 1.5 - test_dict["list"] = [] - test_dict["list"][:] = [34, 31] - test_dict["list"].append(42) - test_dict["list"].insert(1, 1) - test_dict[100] = 0 - test_dict[100] = 1 - test_dict[101] = 1 - test_dict.pop(101) - test_dict[102] = 1 - del test_dict[102] - test_dict["array"] = np.zeros(1) - test_dict["array"][0] = 10 - test_dict["finished"] = True - - -class SyncStructCase(unittest.TestCase): - def init_test_dict(self, init): - self.received_dict = init - return init - - def notify(self, mod): - if ((mod["action"] == "init" and "finished" in mod["struct"]) - or (mod["action"] == "setitem" and mod["key"] == "finished")): - self.receiving_done.set() - - def setUp(self): - self.loop = asyncio.new_event_loop() - asyncio.set_event_loop(self.loop) - - async def _do_test_recv(self): - self.receiving_done = asyncio.Event() - - test_dict = sync_struct.Notifier(dict()) - publisher = sync_struct.Publisher({"test": test_dict}) - await publisher.start(test_address, test_port) - - subscriber = sync_struct.Subscriber("test", self.init_test_dict, - self.notify) - await subscriber.connect(test_address, test_port) - - write_test_data(test_dict) - await self.receiving_done.wait() - - await subscriber.close() - await publisher.stop() - - self.assertEqual(self.received_dict, test_dict.raw_view) - - def test_recv(self): - self.loop.run_until_complete(self._do_test_recv()) - - def tearDown(self): - self.loop.close() diff --git a/artiq/tools.py b/artiq/tools.py index d7d20bae1..afeef8bc8 100644 --- a/artiq/tools.py +++ b/artiq/tools.py @@ -10,17 +10,18 @@ import sys import numpy as np +from sipyco import pyon + from artiq import __version__ as artiq_version from artiq.appdirs import user_config_dir from artiq.language.environment import is_experiment -from artiq.protocols import pyon + __all__ = ["parse_arguments", "elide", "short_format", "file_import", - "get_experiment", "add_common_args", "simple_network_args", + "get_experiment", "UnexpectedLogMessageError", "expect_no_log_messages", - "multiline_log_config", "init_logger", "bind_address_from_args", "atexit_register_coroutine", "exc_to_warning", - "asyncio_wait_or_cancel", "TaskObject", "Condition", + "asyncio_wait_or_cancel", "Condition", "get_windows_drives", "get_user_config_dir"] @@ -106,44 +107,6 @@ def get_experiment(module, class_name=None): return exps[0][1] -def add_common_args(parser): - """Add common utility arguments to the cmd parser. - - Arguments added: - * `-v`/`-q`: increase or decrease the default logging levels. - Repeat for higher levels. - * `--version`: print the ARTIQ version - """ - group = parser.add_argument_group("common") - group.add_argument("-v", "--verbose", default=0, action="count", - help="increase logging level") - group.add_argument("-q", "--quiet", default=0, action="count", - help="decrease logging level") - group.add_argument("--version", action="version", - version="ARTIQ v{}".format(artiq_version), - help="print the ARTIQ version number") - - -def simple_network_args(parser, default_port): - group = parser.add_argument_group("network server") - group.add_argument( - "--bind", default=[], action="append", - help="additional hostname or IP address to bind to; " - "use '*' to bind to all interfaces (default: %(default)s)") - group.add_argument( - "--no-localhost-bind", default=False, action="store_true", - help="do not implicitly also bind to localhost addresses") - if isinstance(default_port, int): - group.add_argument("-p", "--port", default=default_port, type=int, - help="TCP port to listen on (default: %(default)d)") - else: - for name, purpose, default in default_port: - h = ("TCP port for {} connections (default: {})" - .format(purpose, default)) - group.add_argument("--port-" + name, default=default, type=int, - help=h) - - class UnexpectedLogMessageError(Exception): pass @@ -174,42 +137,6 @@ def expect_no_log_messages(level, logger=None): logger.removeHandler(handler) -class MultilineFormatter(logging.Formatter): - def __init__(self): - logging.Formatter.__init__( - self, "%(levelname)s:%(name)s:%(message)s") - - def format(self, record): - r = logging.Formatter.format(self, record) - linebreaks = r.count("\n") - if linebreaks: - i = r.index(":") - r = r[:i] + "<" + str(linebreaks + 1) + ">" + r[i:] - return r - - -def multiline_log_config(level): - root_logger = logging.getLogger() - root_logger.setLevel(level) - handler = logging.StreamHandler() - handler.setFormatter(MultilineFormatter()) - root_logger.addHandler(handler) - - -def init_logger(args): - multiline_log_config( - level=logging.WARNING + args.quiet*10 - args.verbose*10) - - -def bind_address_from_args(args): - if "*" in args.bind: - return None - if args.no_localhost_bind: - return args.bind - else: - return ["127.0.0.1", "::1"] + args.bind - - def atexit_register_coroutine(coroutine, loop=None): if loop is None: loop = asyncio.get_event_loop() @@ -238,31 +165,6 @@ async def asyncio_wait_or_cancel(fs, **kwargs): return fs -class TaskObject: - def start(self): - async def log_exceptions(awaitable): - try: - return await awaitable() - except asyncio.CancelledError: - raise - except Exception: - logger.error("Unhandled exception in TaskObject task body", exc_info=True) - raise - - self.task = asyncio.ensure_future(log_exceptions(self._do)) - - async def stop(self): - self.task.cancel() - try: - await asyncio.wait_for(self.task, None) - except asyncio.CancelledError: - pass - del self.task - - async def _do(self): - raise NotImplementedError - - class Condition: def __init__(self, *, loop=None): if loop is not None: diff --git a/doc/manual/developing_a_ndsp.rst b/doc/manual/developing_a_ndsp.rst index 1d786ca97..18e3a995a 100644 --- a/doc/manual/developing_a_ndsp.rst +++ b/doc/manual/developing_a_ndsp.rst @@ -1,7 +1,7 @@ Developing a Network Device Support Package (NDSP) ================================================== -Most ARTIQ devices are interfaced through "controllers" that expose RPC interfaces to the network (based on :class:`artiq.protocols.pc_rpc`). The master never does direct I/O to the devices, but issues RPCs to the controllers when needed. As opposed to running everything on the master, this architecture has those main advantages: +Most ARTIQ devices are interfaced through "controllers" that expose RPC interfaces to the network (based on SiPyCo). The master never does direct I/O to the devices, but issues RPCs to the controllers when needed. As opposed to running everything on the master, this architecture has those main advantages: * Each driver can be run on a different machine, which alleviates cabling issues and OS compatibility problems. * Reduces the impact of driver crashes. @@ -15,13 +15,13 @@ A network device support package (NDSP) is composed of several parts: 1. The `driver`, which contains the Python API functions to be called over the network, and performs the I/O to the device. The top-level module of the driver is called ``artiq.devices.XXX.driver``. 2. The `controller`, which instantiates, initializes and terminates the driver, and sets up the RPC server. The controller is a front-end command-line tool to the user and is called ``artiq.frontend.aqctl_XXX``. A ``setup.py`` entry must also be created to install it. -3. An optional `client`, which connects to the controller and exposes the functions of the driver as a command-line interface. Clients are front-end tools (called ``artiq.frontend.aqcli_XXX``) that have ``setup.py`` entries. In most cases, a custom client is not needed and the generic ``artiq_rpctool`` utility can be used instead. Custom clients are only required when large amounts of data must be transferred over the network API, that would be unwieldy to pass as ``artiq_rpctool`` command-line parameters. +3. An optional `client`, which connects to the controller and exposes the functions of the driver as a command-line interface. Clients are front-end tools (called ``artiq.frontend.aqcli_XXX``) that have ``setup.py`` entries. In most cases, a custom client is not needed and the generic ``sipyco_rpctool`` utility can be used instead. Custom clients are only required when large amounts of data must be transferred over the network API, that would be unwieldy to pass as ``sipyco_rpctool`` command-line parameters. 4. An optional `mediator`, which is code executed on the client that supplements the network API. A mediator may contain kernels that control real-time signals such as TTL lines connected to the device. Simple devices use the network API directly and do not have a mediator. Mediator modules are called ``artiq.devices.XXX.mediator`` and their public classes are exported at the ``artiq.devices.XXX`` level (via ``__init__.py``) for direct import and use by the experiments. The driver and controller ------------------------- -A controller is a piece of software that receives commands from a client over the network (or the ``localhost`` interface), drives a device, and returns information about the device to the client. The mechanism used is remote procedure calls (RPCs) using :class:`artiq.protocols.pc_rpc`, which makes the network layers transparent for the driver's user. +A controller is a piece of software that receives commands from a client over the network (or the ``localhost`` interface), drives a device, and returns information about the device to the client. The mechanism used is remote procedure calls (RPCs) using ``sipyco.pc_rpc``, which makes the network layers transparent for the driver's user. The controller we will develop is for a "device" that is very easy to work with: the console from which the controller is run. The operation that the driver will implement is writing a message to that console. @@ -33,9 +33,9 @@ For using RPC, the functions that a driver provides must be the methods of a sin For a more complex driver, you would put this class definition into a separate Python module called ``driver``. -To turn it into a server, we use :class:`artiq.protocols.pc_rpc`. Import the function we will use: :: +To turn it into a server, we use ``sipyco.pc_rpc``. Import the function we will use: :: - from artiq.protocols.pc_rpc import simple_server_loop + from sipyco.pc_rpc import simple_server_loop and add a ``main`` function that is run when the program is executed: :: @@ -68,24 +68,24 @@ and verify that you can connect to the TCP port: :: :tip: Use the key combination Ctrl-AltGr-9 to get the ``telnet>`` prompt, and enter ``close`` to quit Telnet. Quit the controller with Ctrl-C. -Also verify that a target (service) named "hello" (as passed in the first argument to ``simple_server_loop``) exists using the ``artiq_rpctool`` program from the ARTIQ front-end tools: :: +Also verify that a target (service) named "hello" (as passed in the first argument to ``simple_server_loop``) exists using the ``sipyco_rpctool`` program from the ARTIQ front-end tools: :: - $ artiq_rpctool ::1 3249 list-targets + $ sipyco_rpctool ::1 3249 list-targets Target(s): hello The client ---------- -Clients are small command-line utilities that expose certain functionalities of the drivers. The ``artiq_rpctool`` utility contains a generic client that can be used in most cases, and developing a custom client is not required. Try these commands :: +Clients are small command-line utilities that expose certain functionalities of the drivers. The ``sipyco_rpctool`` utility contains a generic client that can be used in most cases, and developing a custom client is not required. Try these commands :: - $ artiq_rpctool ::1 3249 list-methods - $ artiq_rpctool ::1 3249 call message test + $ sipyco_rpctool ::1 3249 list-methods + $ sipyco_rpctool ::1 3249 call message test In case you are developing a NDSP that is complex enough to need a custom client, we will see how to develop one. Create a ``aqcli_hello.py`` file with the following contents: :: #!/usr/bin/env python3 - from artiq.protocols.pc_rpc import Client + from sipyco.pc_rpc import Client def main(): @@ -112,11 +112,11 @@ Command-line arguments Use the Python ``argparse`` module to make the bind address(es) and port configurable on the controller, and the server address, port and message configurable on the client. -We suggest naming the controller parameters ``--bind`` (which adds a bind address in addition to a default binding to localhost), ``--no-bind-localhost`` (which disables the default binding to localhost), and ``--port``, so that those parameters stay consistent across controllers. Use ``-s/--server`` and ``--port`` on the client. The ``artiq.tools.simple_network_args`` library function adds such arguments for the controller, and the ``artiq.tools.bind_address_from_args`` function processes them. +We suggest naming the controller parameters ``--bind`` (which adds a bind address in addition to a default binding to localhost), ``--no-bind-localhost`` (which disables the default binding to localhost), and ``--port``, so that those parameters stay consistent across controllers. Use ``-s/--server`` and ``--port`` on the client. The ``sipyco.common_args.simple_network_args`` library function adds such arguments for the controller, and the ``sipyco.common_args.bind_address_from_args`` function processes them. The controller's code would contain something similar to this: :: - from artiq.tools import simple_network_args + from sipyco.common_args import simple_network_args def get_argparser(): parser = argparse.ArgumentParser(description="Hello world controller") @@ -132,14 +132,14 @@ We suggest that you define a function ``get_argparser`` that returns the argumen Logging ------- -For the debug, information and warning messages, use the ``logging`` Python module and print the log on the standard error output (the default setting). The logging level is by default "WARNING", meaning that only warning messages and more critical messages will get printed (and no debug nor information messages). By calling :func:`artiq.tools.add_common_args` with the parser as argument, you add support for the ``--verbose`` (``-v``) and ``--quiet`` (``-q``) arguments in the parser. Each occurence of ``-v`` (resp. ``-q``) in the arguments will increase (resp. decrease) the log level of the logging module. For instance, if only one ``-v`` is present in the arguments, then more messages (info, warning and above) will get printed. If only one ``-q`` is present in the arguments, then only errors and critical messages will get printed. If ``-qq`` is present in the arguments, then only critical messages will get printed, but no debug/info/warning/error. +For the debug, information and warning messages, use the ``logging`` Python module and print the log on the standard error output (the default setting). The logging level is by default "WARNING", meaning that only warning messages and more critical messages will get printed (and no debug nor information messages). By calling ``sipyco.common_args.verbosity_args`` with the parser as argument, you add support for the ``--verbose`` (``-v``) and ``--quiet`` (``-q``) arguments in the parser. Each occurence of ``-v`` (resp. ``-q``) in the arguments will increase (resp. decrease) the log level of the logging module. For instance, if only one ``-v`` is present in the arguments, then more messages (info, warning and above) will get printed. If only one ``-q`` is present in the arguments, then only errors and critical messages will get printed. If ``-qq`` is present in the arguments, then only critical messages will get printed, but no debug/info/warning/error. The program below exemplifies how to use logging: :: import argparse import logging - from artiq.tools import add_common_args, init_logger + from sipyco.common_args import verbosity_args, init_logger_from_args # get a logger that prints the module name @@ -151,13 +151,13 @@ The program below exemplifies how to use logging: :: parser.add_argument("--someargument", help="some argument") # [...] - add_common_args(parser) # This adds the -q and -v handling + add_verbosity_args(parser) # This adds the -q and -v handling return parser def main(): args = get_argparser().parse_args() - init_logger(args) # This initializes logging system log level according to -v/-q args + init_logger_from_args(args) # This initializes logging system log level according to -v/-q args logger.debug("this is a debug message") logger.info("this is an info message") @@ -172,7 +172,7 @@ The program below exemplifies how to use logging: :: Remote execution support ------------------------ -If you wish to support remote execution in your controller, you may do so by simply replacing ``simple_server_loop`` with :class:`artiq.protocols.remote_exec.simple_rexec_server_loop`. +If you wish to support remote execution in your controller, you may do so by simply replacing ``simple_server_loop`` with :class:`sipyco.remote_exec.simple_rexec_server_loop`. General guidelines ------------------ @@ -184,5 +184,5 @@ General guidelines * Controllers must be able to operate in "simulation" mode, where they behave properly even if the associated hardware is not connected. For example, they can print the data to the console instead of sending it to the device, or dump it into a file. * The simulation mode is entered whenever the ``--simulation`` option is specified. * Keep command line parameters consistent across clients/controllers. When adding new command line options, look for a client/controller that does a similar thing and follow its use of ``argparse``. If the original client/controller could use ``argparse`` in a better way, improve it. -* Use docstrings for all public methods of the driver (note that those will be retrieved by ``artiq_rpctool``). +* Use docstrings for all public methods of the driver (note that those will be retrieved by ``sipyco_rpctool``). * Choose a free default TCP port and add it to the default port list in this manual. diff --git a/doc/manual/environment.rst b/doc/manual/environment.rst index 5a2df7a89..cf2cf7308 100644 --- a/doc/manual/environment.rst +++ b/doc/manual/environment.rst @@ -22,9 +22,9 @@ Local device entries are dictionaries that contain a ``type`` field set to ``loc Controllers +++++++++++ -Controller entries are dictionaries whose ``type`` field is set to ``controller``. When an experiment requests such a device, a RPC client (see :class:`artiq.protocols.pc_rpc`) is created and connected to the appropriate controller. Controller entries are also used by controller managers to determine what controllers to run. +Controller entries are dictionaries whose ``type`` field is set to ``controller``. When an experiment requests such a device, a RPC client (see ``sipyco.pc_rpc``) is created and connected to the appropriate controller. Controller entries are also used by controller managers to determine what controllers to run. -The ``best_effort`` field is a boolean that determines whether to use :class:`artiq.protocols.pc_rpc.Client` or :class:`artiq.protocols.pc_rpc.BestEffortClient`. The ``host`` and ``port`` fields configure the TCP connection. The ``target`` field contains the name of the RPC target to use (you may use ``artiq_rpctool`` on a controller to list its targets). Controller managers run the ``command`` field in a shell to launch the controller, after replacing ``{port}`` and ``{bind}`` by respectively the TCP port the controller should listen to (matches the ``port`` field) and an appropriate bind address for the controller's listening socket. +The ``best_effort`` field is a boolean that determines whether to use ``sipyco.pc_rpc.Client`` or ``sipyco.pc_rpc.BestEffortClient``. The ``host`` and ``port`` fields configure the TCP connection. The ``target`` field contains the name of the RPC target to use (you may use ``sipyco_rpctool`` on a controller to list its targets). Controller managers run the ``command`` field in a shell to launch the controller, after replacing ``{port}`` and ``{bind}`` by respectively the TCP port the controller should listen to (matches the ``port`` field) and an appropriate bind address for the controller's listening socket. Aliases +++++++ diff --git a/doc/manual/index.rst b/doc/manual/index.rst index 3465bc0ac..c7ecde30f 100644 --- a/doc/manual/index.rst +++ b/doc/manual/index.rst @@ -20,7 +20,6 @@ Contents: drtio core_language_reference core_drivers_reference - protocols_reference list_of_ndsps developing_a_ndsp utilities diff --git a/doc/manual/protocols_reference.rst b/doc/manual/protocols_reference.rst deleted file mode 100644 index 247d834b7..000000000 --- a/doc/manual/protocols_reference.rst +++ /dev/null @@ -1,43 +0,0 @@ -Protocols reference -=================== - -:mod:`artiq.protocols.asyncio_server` module --------------------------------------------- - -.. automodule:: artiq.protocols.asyncio_server - :members: - - -:mod:`artiq.protocols.pyon` module ----------------------------------- - -.. automodule:: artiq.protocols.pyon - :members: - - -:mod:`artiq.protocols.pc_rpc` module ------------------------------------- - -.. automodule:: artiq.protocols.pc_rpc - :members: - - -:mod:`artiq.protocols.fire_and_forget` module ---------------------------------------------- - -.. automodule:: artiq.protocols.fire_and_forget - :members: - - -:mod:`artiq.protocols.sync_struct` module ------------------------------------------ - -.. automodule:: artiq.protocols.sync_struct - :members: - - -:mod:`artiq.protocols.remote_exec` module ------------------------------------------ - -.. automodule:: artiq.protocols.remote_exec - :members: diff --git a/doc/manual/utilities.rst b/doc/manual/utilities.rst index abac93f95..4946fea2a 100644 --- a/doc/manual/utilities.rst +++ b/doc/manual/utilities.rst @@ -12,71 +12,6 @@ Local running tool :ref: artiq.frontend.artiq_run.get_argparser :prog: artiq_run -Remote Procedure Call tool --------------------------- - -.. argparse:: - :ref: artiq.frontend.artiq_rpctool.get_argparser - :prog: artiq_rpctool - -This tool is the preferred way of handling simple ARTIQ controllers. -Instead of writing a client for very simple cases you can just use this tool -in order to call remote functions of an ARTIQ controller. - -* Listing existing targets - - The ``list-targets`` sub-command will print to standard output the - target list of the remote server:: - - $ artiq_rpctool hostname port list-targets - -* Listing callable functions - - The ``list-methods`` sub-command will print to standard output a sorted - list of the functions you can call on the remote server's target. - - The list will contain function names, signatures (arguments) and - docstrings. - - If the server has only one target, you can do:: - - $ artiq_rpctool hostname port list-methods - - Otherwise you need to specify the target, using the ``-t target`` - option:: - - $ artiq_rpctool hostname port list-methods -t target_name - -* Remotely calling a function - - The ``call`` sub-command will call a function on the specified remote - server's target, passing the specified arguments. - Like with the previous sub-command, you only need to provide the target - name (with ``-t target``) if the server hosts several targets. - - The following example will call the ``set_attenuation`` method of the - Lda controller with the argument ``5``:: - - $ artiq_rpctool ::1 3253 call -t lda set_attenuation 5 - - In general, to call a function named ``f`` with N arguments named - respectively ``x1, x2, ..., xN`` you can do:: - - $ artiq_rpctool hostname port call -t target f x1 x2 ... xN - - You can use Python syntax to compute arguments as they will be passed - to the ``eval()`` primitive. The numpy package is available in the namespace - as ``np``. Beware to use quotes to separate arguments which use spaces:: - - $ artiq_rpctool hostname port call -t target f '3 * 4 + 2' True '[1, 2]' - $ artiq_rpctool ::1 3256 call load_sample_values 'np.array([1.0, 2.0], dtype=float)' - - If the called function has a return value, it will get printed to - the standard output if the value is not None like in the standard - python interactive console:: - - $ artiq_rpctool ::1 3253 call get_attenuation - 5.0 dB Static compiler --------------- diff --git a/setup.py b/setup.py index a2b470e0a..fae2b91ae 100755 --- a/setup.py +++ b/setup.py @@ -33,7 +33,6 @@ console_scripts = [ "artiq_rtiomon = artiq.frontend.artiq_rtiomon:main", "artiq_session = artiq.frontend.artiq_session:main", "artiq_route = artiq.frontend.artiq_route:main", - "artiq_rpctool = artiq.frontend.artiq_rpctool:main", "artiq_run = artiq.frontend.artiq_run:main", "artiq_flash = artiq.frontend.artiq_flash:main", From e65303cfe9d94be0d1ab932160ace76bebdcbcee Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 11 Nov 2019 12:24:50 +0800 Subject: [PATCH 1984/2457] RELEASE_NOTES: sipyco --- RELEASE_NOTES.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index a57645d9e..5561efdfc 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -34,6 +34,8 @@ ARTIQ-5 * The ``-e/--experiment`` switch of ``artiq_run`` and ``artiq_compile`` has been renamed ``-c/--class-name``. * ``artiq_devtool`` has been removed. +* Much of ``artiq.protocols`` has been moved to a separate package ``sipyco``. + ``artiq_rpctool`` has been renamed to ``sipyco_rpctool``. ARTIQ-4 From fd7081830c6fe3811fc85ca1ffb495a5604bf621 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 12 Nov 2019 19:43:04 +0800 Subject: [PATCH 1985/2457] remove fire_and_forget (moved to sipyco) --- artiq/protocols/__init__.py | 0 artiq/protocols/fire_and_forget.py | 51 ------------------------------ artiq/test/test_fire_and_forget.py | 17 ---------- 3 files changed, 68 deletions(-) delete mode 100644 artiq/protocols/__init__.py delete mode 100644 artiq/protocols/fire_and_forget.py delete mode 100644 artiq/test/test_fire_and_forget.py diff --git a/artiq/protocols/__init__.py b/artiq/protocols/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/artiq/protocols/fire_and_forget.py b/artiq/protocols/fire_and_forget.py deleted file mode 100644 index 61b2a4aa2..000000000 --- a/artiq/protocols/fire_and_forget.py +++ /dev/null @@ -1,51 +0,0 @@ -import threading -import logging -import inspect - - -logger = logging.getLogger(__name__) - - -class FFProxy: - """Proxies a target object and runs its methods in the background. - - All method calls to this object are forwarded to the target and executed - in a background thread. Method calls return immediately. Exceptions from - the target method are turned into warnings. At most one method from the - target object may be executed in the background; if a new call is - submitted while the previous one is still executing, a warning is printed - and the new call is dropped. - - This feature is typically used to wrap slow and non-critical RPCs in - experiments. - """ - def __init__(self, target): - self.target = target - - valid_methods = inspect.getmembers(target, inspect.ismethod) - self._valid_methods = {m[0] for m in valid_methods} - self._thread = None - - def ff_join(self): - """Waits until any background method finishes its execution.""" - if self._thread is not None: - self._thread.join() - - def __getattr__(self, k): - if k not in self._valid_methods: - raise AttributeError - def run_in_thread(*args, **kwargs): - if self._thread is not None and self._thread.is_alive(): - logger.warning("skipping fire-and-forget call to %r.%s as " - "previous call did not complete", - self.target, k) - return - def thread_body(): - try: - getattr(self.target, k)(*args, **kwargs) - except: - logger.warning("fire-and-forget call to %r.%s raised an " - "exception:", self.target, k, exc_info=True) - self._thread = threading.Thread(target=thread_body) - self._thread.start() - return run_in_thread diff --git a/artiq/test/test_fire_and_forget.py b/artiq/test/test_fire_and_forget.py deleted file mode 100644 index fb8e67555..000000000 --- a/artiq/test/test_fire_and_forget.py +++ /dev/null @@ -1,17 +0,0 @@ -import unittest - -from artiq.protocols import fire_and_forget - - -class FireAndForgetCase(unittest.TestCase): - def _set_ok(self): - self.ok = True - - def test_fire_and_forget(self): - self.ok = False - p = fire_and_forget.FFProxy(self) - p._set_ok() - with self.assertRaises(AttributeError): - p.non_existing_method - p.ff_join() - self.assertTrue(self.ok) From 61ca46ec3fe8db0cc1bf1c641264252150fd7d67 Mon Sep 17 00:00:00 2001 From: Garrett Date: Tue, 5 Nov 2019 14:54:20 -0600 Subject: [PATCH 1986/2457] updated adoo10.py for RAM mode frequency control --- artiq/coredevice/ad9910.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 170068dc8..5ffe93110 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -345,7 +345,8 @@ class AD9910: @kernel def set_cfr1(self, power_down=0b0000, phase_autoclear=0, drg_load_lrr=0, drg_autoclear=0, - internal_profile=0, ram_destination=0, ram_enable=0): + internal_profile=0, ram_destination=0, ram_enable=0, + manual_osk_external=0, osk_enable=0, select_auto_osk=0): """Set CFR1. See the AD9910 datasheet for parameter meanings. This method does not pulse IO_UPDATE. @@ -363,10 +364,13 @@ class AD9910: self.write32(_AD9910_REG_CFR1, (ram_enable << 31) | (ram_destination << 29) | + (manual_osk_external << 23) | (internal_profile << 17) | (drg_load_lrr << 15) | (drg_autoclear << 14) | (phase_autoclear << 13) | + (osk_enable << 9) | + (select_auto_osk << 8) | (power_down << 4) | 2) # SDIO input only, MSB first @@ -526,7 +530,7 @@ class AD9910: @kernel def set_asf(self, asf): - self.write32(_AD9910_REG_ASF, asf) + self.write32(_AD9910_REG_ASF, asf<<2) @kernel def set_pow(self, pow_): From 6d34eb3bb00c6cc774b383c36c480be1f6906ab8 Mon Sep 17 00:00:00 2001 From: Garrett Date: Mon, 11 Nov 2019 14:40:16 -0600 Subject: [PATCH 1987/2457] updated docstrings for set_cfr1() in ad9910.py --- artiq/coredevice/ad9910.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 5ffe93110..0168568fe 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -360,6 +360,9 @@ class AD9910: (:const:`RAM_DEST_FTW`, :const:`RAM_DEST_POW`, :const:`RAM_DEST_ASF`, :const:`RAM_DEST_POWASF`). :param ram_enable: RAM mode enable. + :param manual_osk_external: Enable OSK pin control in manual OSK mode. + :param osk_enable: Enable OSK mode. + :param select_auto_osk: Select manual or automatic OSK mode """ self.write32(_AD9910_REG_CFR1, (ram_enable << 31) | @@ -630,6 +633,10 @@ class AD9910: @kernel def set_frequency(self, frequency): + """Set the value stored to the AD9910's FTW register + + :param frequency: frequency to be stored, in Hz + """ return self.set_ftw(self.frequency_to_ftw(frequency)) @kernel From 4ad3651022da0dca04bf5b67ba860fa1dde56680 Mon Sep 17 00:00:00 2001 From: Garrett Date: Mon, 11 Nov 2019 14:42:34 -0600 Subject: [PATCH 1988/2457] fixed typo in ad9910.py --- artiq/coredevice/ad9910.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 0168568fe..d1d86403e 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -362,7 +362,7 @@ class AD9910: :param ram_enable: RAM mode enable. :param manual_osk_external: Enable OSK pin control in manual OSK mode. :param osk_enable: Enable OSK mode. - :param select_auto_osk: Select manual or automatic OSK mode + :param select_auto_osk: Select manual or automatic OSK mode. """ self.write32(_AD9910_REG_CFR1, (ram_enable << 31) | From 3a19ba7e62b7f4b8e4bdf1ed70a6c57398b361f3 Mon Sep 17 00:00:00 2001 From: Garrett Date: Mon, 11 Nov 2019 15:50:40 -0600 Subject: [PATCH 1989/2457] added docstrings to ad9910.py --- artiq/coredevice/ad9910.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index d1d86403e..baa77b50d 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -529,14 +529,26 @@ class AD9910: @kernel def set_ftw(self, ftw): + """Set the value stored to the AD9910's frequency tuning word (FTW) register. + + :param ftw: Frequency tuning word to be stored, range: 0 to 0xffffffff. + """ self.write32(_AD9910_REG_FTW, ftw) @kernel def set_asf(self, asf): + """Set the value stored to the AD9910's amplitude scale factor (ASF) register. + + :param asf: Amplitude scale factor to be stored, range: 0 to 0x3ffe. + """ self.write32(_AD9910_REG_ASF, asf<<2) @kernel def set_pow(self, pow_): + """Set the value stored to the AD9910's phase offset word (POW) register. + + :param pow_: Phase offset word to be stored, range: 0 to 0xffff. + """ self.write32(_AD9910_REG_POW, pow_) @portable(flags={"fast-math"}) @@ -633,18 +645,26 @@ class AD9910: @kernel def set_frequency(self, frequency): - """Set the value stored to the AD9910's FTW register + """Set the value stored to the AD9910's frequency tuning word (FTW) register. - :param frequency: frequency to be stored, in Hz + :param frequency: frequency to be stored, in Hz. """ return self.set_ftw(self.frequency_to_ftw(frequency)) @kernel def set_amplitude(self, amplitude): + """Set the value stored to the AD9910's amplitude scale factor (ASF) register. + + :param amplitude: amplitude to be stored, in units of full scale. + """ return self.set_asf(self.amplitude_to_asf(amplitude)) @kernel def set_phase(self, turns): + """Set the value stored to the AD9910's phase offset word (POW) register. + + :param turns: phase offset to be stored, in turns. + """ return self.set_pow(self.turns_to_pow(turns)) @kernel From f8a7e278b84dcc18fb29749de7fa1d2839d3d6e0 Mon Sep 17 00:00:00 2001 From: Garrett Date: Tue, 12 Nov 2019 11:03:00 -0600 Subject: [PATCH 1990/2457] removed OSK-related changes in AD9910, to be included in a separate branch. --- artiq/coredevice/ad9910.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index baa77b50d..a93242455 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -345,8 +345,7 @@ class AD9910: @kernel def set_cfr1(self, power_down=0b0000, phase_autoclear=0, drg_load_lrr=0, drg_autoclear=0, - internal_profile=0, ram_destination=0, ram_enable=0, - manual_osk_external=0, osk_enable=0, select_auto_osk=0): + internal_profile=0, ram_destination=0, ram_enable=0): """Set CFR1. See the AD9910 datasheet for parameter meanings. This method does not pulse IO_UPDATE. @@ -360,20 +359,14 @@ class AD9910: (:const:`RAM_DEST_FTW`, :const:`RAM_DEST_POW`, :const:`RAM_DEST_ASF`, :const:`RAM_DEST_POWASF`). :param ram_enable: RAM mode enable. - :param manual_osk_external: Enable OSK pin control in manual OSK mode. - :param osk_enable: Enable OSK mode. - :param select_auto_osk: Select manual or automatic OSK mode. """ self.write32(_AD9910_REG_CFR1, (ram_enable << 31) | (ram_destination << 29) | - (manual_osk_external << 23) | (internal_profile << 17) | (drg_load_lrr << 15) | (drg_autoclear << 14) | (phase_autoclear << 13) | - (osk_enable << 9) | - (select_auto_osk << 8) | (power_down << 4) | 2) # SDIO input only, MSB first From 4416378d21d9f265ce235ebf0f495b361af3e2ab Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Nov 2019 11:42:31 +0800 Subject: [PATCH 1991/2457] frontend: add --version to common tools --- artiq/frontend/artiq_browser.py | 4 ++++ artiq/frontend/artiq_compile.py | 4 ++++ artiq/frontend/artiq_coremgmt.py | 4 ++++ artiq/frontend/artiq_dashboard.py | 4 ++++ artiq/frontend/artiq_ddb_template.py | 5 +++++ artiq/frontend/artiq_flash.py | 5 +++++ artiq/frontend/artiq_master.py | 4 ++++ artiq/frontend/artiq_run.py | 4 ++++ artiq/frontend/artiq_session.py | 5 ++++- 9 files changed, 38 insertions(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index da5bead60..e002cac83 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -9,6 +9,7 @@ import logging from PyQt5 import QtCore, QtGui, QtWidgets from quamash import QEventLoop +from artiq import __version__ as artiq_version from artiq import __artiq_dir__ as artiq_dir from artiq.tools import (add_common_args, atexit_register_coroutine, get_user_config_dir) @@ -21,6 +22,9 @@ logger = logging.getLogger(__name__) def get_argparser(): parser = argparse.ArgumentParser(description="ARTIQ Browser") + parser.add_argument("--version", action="version", + version="ARTIQ v{}".format(artiq_version), + help="print the ARTIQ version number") parser.add_argument("--db-file", default=None, help="database file for local browser settings " "(default: %(default)s)") diff --git a/artiq/frontend/artiq_compile.py b/artiq/frontend/artiq_compile.py index 2ebe0a657..1609971e0 100755 --- a/artiq/frontend/artiq_compile.py +++ b/artiq/frontend/artiq_compile.py @@ -4,6 +4,7 @@ import os, sys, logging, argparse from sipyco import common_args +from artiq import __version__ as artiq_version from artiq.master.databases import DeviceDB, DatasetDB from artiq.master.worker_db import DeviceManager, DatasetManager from artiq.language.environment import ProcessArgumentManager @@ -16,6 +17,9 @@ logger = logging.getLogger(__name__) def get_argparser(): parser = argparse.ArgumentParser(description="ARTIQ static compiler") + parser.add_argument("--version", action="version", + version="ARTIQ v{}".format(artiq_version), + help="print the ARTIQ version number") common_args.verbosity_args(parser) parser.add_argument("--device-db", default="device_db.py", diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index 5c7594cff..db420c971 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -5,6 +5,7 @@ import struct from sipyco import common_args +from artiq import __version__ as artiq_version from artiq.master.databases import DeviceDB from artiq.coredevice.comm_kernel import CommKernel from artiq.coredevice.comm_mgmt import CommMgmt @@ -14,6 +15,9 @@ from artiq.coredevice.profiler import CallgrindWriter def get_argparser(): parser = argparse.ArgumentParser(description="ARTIQ core device " "management tool") + parser.add_argument("--version", action="version", + version="ARTIQ v{}".format(artiq_version), + help="print the ARTIQ version number") common_args.verbosity_args(parser) parser.add_argument("--device-db", default="device_db.py", diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index 6af277019..d954b0190 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -13,6 +13,7 @@ from sipyco.pc_rpc import AsyncioClient, Client from sipyco.broadcast import Receiver from sipyco import common_args +from artiq import __version__ as artiq_version from artiq import __artiq_dir__ as artiq_dir, __version__ as artiq_version from artiq.tools import atexit_register_coroutine, get_user_config_dir from artiq.gui.models import ModelSubscriber @@ -23,6 +24,9 @@ from artiq.dashboard import (experiments, shortcuts, explorer, def get_argparser(): parser = argparse.ArgumentParser(description="ARTIQ Dashboard") + parser.add_argument("--version", action="version", + version="ARTIQ v{}".format(artiq_version), + help="print the ARTIQ version number") parser.add_argument( "-s", "--server", default="::1", help="hostname or IP of the master to connect to") diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 48fda75a6..b561e69d9 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -7,6 +7,8 @@ import textwrap from collections import defaultdict from itertools import count +from artiq import __version__ as artiq_version + def process_header(output, description): if description["target"] != "kasli": @@ -473,6 +475,9 @@ def process(output, master_description, satellites): def main(): parser = argparse.ArgumentParser( description="ARTIQ device database template builder") + parser.add_argument("--version", action="version", + version="ARTIQ v{}".format(artiq_version), + help="print the ARTIQ version number") parser.add_argument("master_description", metavar="MASTER_DESCRIPTION", help="JSON system description file for the standalone or master node") parser.add_argument("-o", "--output", diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index f2dd3d727..495a3bd00 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -12,6 +12,7 @@ from collections import defaultdict from sipyco import common_args +from artiq import __version__ as artiq_version from artiq import __artiq_dir__ as artiq_dir from artiq.remoting import SSHClient, LocalClient from artiq.frontend.bit2bin import bit2bin @@ -42,6 +43,10 @@ Prerequisites: plugdev group: 'sudo adduser $USER plugdev' and re-login. """) + parser.add_argument("--version", action="version", + version="ARTIQ v{}".format(artiq_version), + help="print the ARTIQ version number") + common_args.verbosity_args(parser) parser.add_argument("-n", "--dry-run", diff --git a/artiq/frontend/artiq_master.py b/artiq/frontend/artiq_master.py index 373fd4da4..ff9014b50 100755 --- a/artiq/frontend/artiq_master.py +++ b/artiq/frontend/artiq_master.py @@ -12,6 +12,7 @@ from sipyco.logging_tools import Server as LoggingServer from sipyco.broadcast import Broadcaster from sipyco import common_args +from artiq import __version__ as artiq_version from artiq.tools import atexit_register_coroutine from artiq.master.log import log_args, init_log from artiq.master.databases import DeviceDB, DatasetDB @@ -25,6 +26,9 @@ logger = logging.getLogger(__name__) def get_argparser(): parser = argparse.ArgumentParser(description="ARTIQ master") + parser.add_argument("--version", action="version", + version="ARTIQ v{}".format(artiq_version), + help="print the ARTIQ version number") common_args.simple_network_args(parser, [ ("notify", "notifications", 3250), diff --git a/artiq/frontend/artiq_run.py b/artiq/frontend/artiq_run.py index c235387c9..4e6f2b7a3 100755 --- a/artiq/frontend/artiq_run.py +++ b/artiq/frontend/artiq_run.py @@ -14,6 +14,7 @@ from llvmlite_artiq import binding as llvm from sipyco import common_args +from artiq import __version__ as artiq_version from artiq.language.environment import EnvExperiment, ProcessArgumentManager from artiq.language.types import TBool from artiq.master.databases import DeviceDB, DatasetDB @@ -127,6 +128,9 @@ class DummyCCB: def get_argparser(with_file=True): parser = argparse.ArgumentParser( description="Local experiment running tool") + parser.add_argument("--version", action="version", + version="ARTIQ v{}".format(artiq_version), + help="print the ARTIQ version number") common_args.verbosity_args(parser) parser.add_argument("--device-db", default="device_db.py", diff --git a/artiq/frontend/artiq_session.py b/artiq/frontend/artiq_session.py index b04a83008..be9fa4ae1 100755 --- a/artiq/frontend/artiq_session.py +++ b/artiq/frontend/artiq_session.py @@ -3,7 +3,7 @@ import argparse import sys import subprocess - +from artiq import __version__ as artiq_version def get_argparser(): @@ -11,6 +11,9 @@ def get_argparser(): description="ARTIQ session manager. " "Automatically runs the master, dashboard and " "local controller manager on the current machine.") + parser.add_argument("--version", action="version", + version="ARTIQ v{}".format(artiq_version), + help="print the ARTIQ version number") parser.add_argument("-m", action="append", default=[], help="add argument to the master command line") parser.add_argument("-d", action="append", default=[], From 3f10363b014340a0d5f41e029e7bba3c4d6ae66d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Nov 2019 12:07:16 +0800 Subject: [PATCH 1992/2457] install-with-conda: explain board packages further --- install-with-conda.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/install-with-conda.py b/install-with-conda.py index 571d705a1..2eab13866 100644 --- a/install-with-conda.py +++ b/install-with-conda.py @@ -9,8 +9,12 @@ CONDA_ENV_NAME = "artiq" # The conda packages to download and install. CONDA_PACKAGES = [ "artiq", + # Only install board packages if you plan to reflash the board. + # The two lines below are just examples and probably not what you want. + # Select the packages that correspond to your board, or remove them + # if you do not intend to reflash the board. "artiq-board-kc705-nist_clock", - "artiq-board-kasli-mitll" + "artiq-board-kasli-wipm" ] # Set to False if you have already set up conda channels ADD_CHANNELS = True From 7a92f443c21e00b03f5fa3968d74f316a250d96f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Nov 2019 12:22:59 +0800 Subject: [PATCH 1993/2457] doc: fix heading --- doc/manual/management_system.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/management_system.rst b/doc/manual/management_system.rst index 8976c0fb0..ebebe1b57 100644 --- a/doc/manual/management_system.rst +++ b/doc/manual/management_system.rst @@ -189,7 +189,7 @@ artiq_dashboard artiq_session ---------------- +------------- .. argparse:: :ref: artiq.frontend.artiq_session.get_argparser From 4707aef45cbbb560bb874165e2f721093510d7e9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Nov 2019 15:21:51 +0800 Subject: [PATCH 1994/2457] split out artiq-comtools --- artiq/frontend/artiq_browser.py | 5 +- artiq/frontend/artiq_ctlmgr.py | 85 ------- artiq/frontend/artiq_dashboard.py | 3 +- artiq/frontend/artiq_influxdb.py | 251 -------------------- artiq/frontend/artiq_influxdb_schedule.py | 242 -------------------- artiq/frontend/artiq_master.py | 2 +- artiq/frontend/artiq_session.py | 6 +- artiq/master/ctlmgr.py | 265 ---------------------- artiq/master/scheduler.py | 4 +- artiq/test/test_ctlmgr.py | 85 ------- artiq/test/test_frontends.py | 4 +- artiq/tools.py | 66 +----- doc/manual/conf.py | 2 +- doc/manual/installing.rst | 1 + doc/manual/management_system.rst | 12 +- doc/manual/utilities.rst | 14 -- install-with-conda.py | 1 + setup.py | 6 +- 18 files changed, 20 insertions(+), 1034 deletions(-) delete mode 100755 artiq/frontend/artiq_ctlmgr.py delete mode 100755 artiq/frontend/artiq_influxdb.py delete mode 100755 artiq/frontend/artiq_influxdb_schedule.py delete mode 100644 artiq/master/ctlmgr.py delete mode 100644 artiq/test/test_ctlmgr.py diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index e002cac83..4faa8fa47 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -9,10 +9,11 @@ import logging from PyQt5 import QtCore, QtGui, QtWidgets from quamash import QEventLoop +from sipyco.asyncio_tools import atexit_register_coroutine + from artiq import __version__ as artiq_version from artiq import __artiq_dir__ as artiq_dir -from artiq.tools import (add_common_args, atexit_register_coroutine, - get_user_config_dir) +from artiq.tools import add_common_args, get_user_config_dir from artiq.gui import state, applets, models, log from artiq.browser import datasets, files, experiments diff --git a/artiq/frontend/artiq_ctlmgr.py b/artiq/frontend/artiq_ctlmgr.py deleted file mode 100755 index 6612e8e9d..000000000 --- a/artiq/frontend/artiq_ctlmgr.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python3 - -import asyncio -import atexit -import argparse -import os -import logging -import platform - -from sipyco.pc_rpc import Server -from sipyco.logging_tools import LogForwarder, SourceFilter -from sipyco import common_args - -from artiq.tools import atexit_register_coroutine -from artiq.master.ctlmgr import ControllerManager - - -def get_argparser(): - parser = argparse.ArgumentParser(description="ARTIQ controller manager") - - common_args.verbosity_args(parser) - - parser.add_argument( - "-s", "--server", default="::1", - help="hostname or IP of the master to connect to") - parser.add_argument( - "--port-notify", default=3250, type=int, - help="TCP port to connect to for notifications") - parser.add_argument( - "--port-logging", default=1066, type=int, - help="TCP port to connect to for logging") - parser.add_argument( - "--retry-master", default=5.0, type=float, - help="retry timer for reconnecting to master") - common_args.simple_network_args(parser, [("control", "control", 3249)]) - return parser - - -def main(): - args = get_argparser().parse_args() - - root_logger = logging.getLogger() - root_logger.setLevel(logging.NOTSET) - source_adder = SourceFilter(logging.WARNING + - args.quiet*10 - args.verbose*10, - "ctlmgr({})".format(platform.node())) - console_handler = logging.StreamHandler() - console_handler.setFormatter(logging.Formatter( - "%(levelname)s:%(source)s:%(name)s:%(message)s")) - console_handler.addFilter(source_adder) - root_logger.addHandler(console_handler) - - if os.name == "nt": - loop = asyncio.ProactorEventLoop() - asyncio.set_event_loop(loop) - else: - loop = asyncio.get_event_loop() - atexit.register(loop.close) - - logfwd = LogForwarder(args.server, args.port_logging, - args.retry_master) - logfwd.addFilter(source_adder) - root_logger.addHandler(logfwd) - logfwd.start() - atexit_register_coroutine(logfwd.stop) - - ctlmgr = ControllerManager(args.server, args.port_notify, - args.retry_master) - ctlmgr.start() - atexit_register_coroutine(ctlmgr.stop) - - class CtlMgrRPC: - retry_now = ctlmgr.retry_now - - rpc_target = CtlMgrRPC() - rpc_server = Server({"ctlmgr": rpc_target}, builtin_terminate=True) - loop.run_until_complete(rpc_server.start(common_args.bind_address_from_args(args), - args.port_control)) - atexit_register_coroutine(rpc_server.stop) - - loop.run_until_complete(rpc_server.wait_terminate()) - - -if __name__ == "__main__": - main() diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index d954b0190..ba0b9fd05 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -12,10 +12,11 @@ from quamash import QEventLoop from sipyco.pc_rpc import AsyncioClient, Client from sipyco.broadcast import Receiver from sipyco import common_args +from sipyco.asyncio_tools import atexit_register_coroutine from artiq import __version__ as artiq_version from artiq import __artiq_dir__ as artiq_dir, __version__ as artiq_version -from artiq.tools import atexit_register_coroutine, get_user_config_dir +from artiq.tools import get_user_config_dir from artiq.gui.models import ModelSubscriber from artiq.gui import state, log from artiq.dashboard import (experiments, shortcuts, explorer, diff --git a/artiq/frontend/artiq_influxdb.py b/artiq/frontend/artiq_influxdb.py deleted file mode 100755 index 2a1fd8720..000000000 --- a/artiq/frontend/artiq_influxdb.py +++ /dev/null @@ -1,251 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import logging -import asyncio -import atexit -import fnmatch -from functools import partial -import time - -import numpy as np -import aiohttp - -from sipyco import common_args -from sipyco.asyncio_tools import TaskObject -from sipyco.sync_struct import Subscriber -from sipyco.pc_rpc import Server -from sipyco import pyon - -from artiq.tools import atexit_register_coroutine - - -logger = logging.getLogger(__name__) - - -def get_argparser(): - parser = argparse.ArgumentParser( - description="ARTIQ data to InfluxDB bridge", - epilog="Pattern matching works as follows. " - "The default action on a key (dataset name) is to log it. " - "Then the patterns are traversed in order and glob-matched " - "with the key. " - "Optional + and - pattern prefixes specify to either ignore or " - "log keys matching the rest of the pattern. " - "Default (in the absence of prefix) is to ignore. Last matched " - "pattern takes precedence.") - master_group = parser.add_argument_group("master") - master_group.add_argument( - "--server-master", default="::1", - help="hostname or IP of the master to connect to") - master_group.add_argument( - "--port-master", default=3250, type=int, - help="TCP port to use to connect to the master (default: %(default)s") - master_group.add_argument( - "--retry-master", default=5.0, type=float, - help="retry timer for reconnecting to master") - database_group = parser.add_argument_group("database") - database_group.add_argument( - "--baseurl-db", default="http://localhost:8086", - help="base URL to access InfluxDB (default: %(default)s)") - database_group.add_argument( - "--user-db", default="", help="InfluxDB username") - database_group.add_argument( - "--password-db", default="", help="InfluxDB password") - database_group.add_argument( - "--database", default="db", help="database name to use") - database_group.add_argument( - "--table", default="lab", help="table name to use") - filter_group = parser.add_argument_group("filter") - filter_group.add_argument( - "--pattern-file", default="influxdb_patterns.cfg", - help="file to load the patterns from (default: %(default)s). " - "If the file is not found, no patterns are loaded " - "(everything is logged).") - common_args.simple_network_args(parser, [("control", "control", 3248)]) - common_args.verbosity_args(parser) - return parser - - -def format_influxdb(v): - if np.issubdtype(type(v), np.bool_): - return "bool={}".format(v) - if np.issubdtype(type(v), np.integer): - return "int={}i".format(v) - if np.issubdtype(type(v), np.floating): - return "float={}".format(v) - if np.issubdtype(type(v), np.str_): - return "str=\"{}\"".format(v.replace('"', '\\"')) - return "pyon=\"{}\"".format(pyon.encode(v).replace('"', '\\"')) - - -class DBWriter(TaskObject): - def __init__(self, base_url, user, password, database, table): - self.base_url = base_url - self.user = user - self.password = password - self.database = database - self.table = table - - self._queue = asyncio.Queue(100) - - def update(self, k, v): - try: - self._queue.put_nowait((k, v, time.time())) - except asyncio.QueueFull: - logger.warning("failed to update dataset '%s': " - "too many pending updates", k) - - async def _do(self): - async with aiohttp.ClientSession() as session: - while True: - k, v, t = await self._queue.get() - url = self.base_url + "/write" - params = {"u": self.user, "p": self.password, - "db": self.database, "precision": "ms"} - data = "{},dataset={} {} {}".format( - self.table, k, format_influxdb(v), round(t*1e3)) - try: - response = await session.post(url, params=params, - data=data) - except Exception: - logger.warning("got exception trying to update '%s'", - k, exc_info=True) - else: - if response.status not in (200, 204): - content = (await response.content.read()).decode() \ - .strip() - logger.warning("got HTTP status %d " - "trying to update '%s': %s", - response.status, k, content) - response.close() - - -class _Mock: - def __setitem__(self, k, v): - pass - - def __getitem__(self, k): - return self - - def __delitem__(self, k): - pass - - def append(self, v): - pass - - -class Datasets: - def __init__(self, filter_function, writer, init): - self.filter_function = filter_function - self.writer = writer - - def __setitem__(self, k, v): - if self.filter_function(k): - self.writer.update(k, v[1]) - - # ignore mutations - def __getitem__(self, k): - return _Mock() - - # ignore deletions - def __delitem__(self, k): - pass - - -class MasterReader(TaskObject): - def __init__(self, server, port, retry, filter_function, writer): - self.server = server - self.port = port - self.retry = retry - - self.filter_function = filter_function - self.writer = writer - - async def _do(self): - subscriber = Subscriber( - "datasets", - partial(Datasets, self.filter_function, self.writer)) - while True: - try: - await subscriber.connect(self.server, self.port) - try: - await asyncio.wait_for(subscriber.receive_task, None) - finally: - await subscriber.close() - except (ConnectionAbortedError, ConnectionError, - ConnectionRefusedError, ConnectionResetError) as e: - logger.warning("Connection to master failed (%s: %s)", - e.__class__.__name__, str(e)) - else: - logger.warning("Connection to master lost") - logger.warning("Retrying in %.1f seconds", self.retry) - await asyncio.sleep(self.retry) - - -class Filter: - def __init__(self, pattern_file): - self.pattern_file = pattern_file - self.scan_patterns() - - def scan_patterns(self): - """(Re)load the patterns file.""" - try: - with open(self.pattern_file, "r") as f: - self.patterns = [] - for line in f: - line = line.rstrip() - if line: - self.patterns.append(line) - except FileNotFoundError: - logger.info("no pattern file found, logging everything") - self.patterns = [] - - # Privatize so that it is not shown in sipyco_rpctool list-methods. - def _filter(self, k): - take = "+" - for pattern in self.patterns: - sign = "-" - if pattern[0] in "+-": - sign, pattern = pattern[0], pattern[1:] - if fnmatch.fnmatchcase(k, pattern): - take = sign - return take == "+" - - def get_patterns(self): - """Show existing patterns.""" - return self.patterns - - def ping(self): - return True - - -def main(): - args = get_argparser().parse_args() - common_args.init_logger_from_args(args) - - loop = asyncio.get_event_loop() - atexit.register(loop.close) - - writer = DBWriter(args.baseurl_db, - args.user_db, args.password_db, - args.database, args.table) - writer.start() - atexit_register_coroutine(writer.stop) - - filter = Filter(args.pattern_file) - rpc_server = Server({"influxdb_filter": filter}, builtin_terminate=True) - loop.run_until_complete(rpc_server.start(common_args.bind_address_from_args(args), - args.port_control)) - atexit_register_coroutine(rpc_server.stop) - - reader = MasterReader(args.server_master, args.port_master, - args.retry_master, filter._filter, writer) - reader.start() - atexit_register_coroutine(reader.stop) - - loop.run_until_complete(rpc_server.wait_terminate()) - - -if __name__ == "__main__": - main() diff --git a/artiq/frontend/artiq_influxdb_schedule.py b/artiq/frontend/artiq_influxdb_schedule.py deleted file mode 100755 index 23c391c87..000000000 --- a/artiq/frontend/artiq_influxdb_schedule.py +++ /dev/null @@ -1,242 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import logging -import asyncio -import atexit -import time - -import aiohttp -import numpy as np - -from sipyco.sync_struct import Subscriber -from sipyco.pc_rpc import Server -from sipyco import pyon -from sipyco import common_args -from sipyco.asyncio_tools import TaskObject - -from artiq.tools import atexit_register_coroutine - - -logger = logging.getLogger(__name__) - - -def get_argparser(): - parser = argparse.ArgumentParser( - description="ARTIQ schedule InfluxDB logger bridge", - epilog="Listens to schedule updates on the master experiment schedule " - "and submits schedule additions and removals to the InfluxDB " - "database. Other schedule changes, such as transitions between " - "pipeline states (prepare, prepare_done, running, etc.) are " - "ignored. Typical high cardinality metadata is logged as " - "fields while low cardinality data is logged as tags. " - "The initially obtained complete state is logged as a 'clear' " - "entry followed by the addition of all entries.") - group = parser.add_argument_group("master") - group.add_argument( - "--server-master", default="::1", - help="hostname or IP of the master to connect to") - group.add_argument( - "--port-master", default=3250, type=int, - help="TCP port to use to connect to the master") - group.add_argument( - "--retry-master", default=5.0, type=float, - help="retry timer for reconnecting to master") - group = parser.add_argument_group("database") - group.add_argument( - "--baseurl-db", default="http://localhost:8086", - help="base URL to access InfluxDB (default: %(default)s)") - group.add_argument( - "--user-db", default="", help="InfluxDB username") - group.add_argument( - "--password-db", default="", help="InfluxDB password") - group.add_argument( - "--database", default="db", help="database name to use") - group.add_argument( - "--table", default="schedule", help="table name to use") - common_args.simple_network_args(parser, [("control", "control", 3275)]) - common_args.verbosity_args(parser) - return parser - - -def format_influxdb(v, tag=True): - if np.issubdtype(type(v), np.bool_): - return "{}".format(v) - if np.issubdtype(type(v), np.integer): - return "{}i".format(v) - if np.issubdtype(type(v), np.floating): - return "{}".format(v) - if not np.issubdtype(type(v), np.str_): - v = pyon.encode(v) - if tag: - for i in ",= ": - v = v.replace(i, "\\" + i) - return v - else: - return "\"{}\"".format(v.replace('"', '\\"')) - - -class DBWriter(TaskObject): - def __init__(self, base_url, user, password, database, table): - self.base_url = base_url - self.user = user - self.password = password - self.database = database - self.table = table - - self._queue = asyncio.Queue(100) - - def update(self, fields, tags): - try: - self._queue.put_nowait((fields, tags, time.time())) - except asyncio.QueueFull: - logger.warning("failed to update schedule: " - "too many pending updates") - - async def _do(self): - async with aiohttp.ClientSession() as session: - while True: - fields, tags, timestamp = await self._queue.get() - url = self.base_url + "/write" - params = {"u": self.user, "p": self.password, - "db": self.database, "precision": "ms"} - tags = ",".join("{}={}".format( - k, format_influxdb(v, tag=True)) - for (k, v) in tags.items()) - fields = ",".join("{}={}".format( - k, format_influxdb(v, tag=False)) - for (k, v) in fields.items()) - data = "{},{} {} {}".format( - self.table, tags, fields, round(timestamp*1e3)) - try: - response = await session.post( - url, params=params, data=data) - except: - logger.warning("got exception trying to update schedule", - exc_info=True) - else: - if response.status not in (200, 204): - content = ( - await response.content.read()).decode().strip() - logger.warning("got HTTP status %d " - "trying to update schedule: %s", - response.status, content) - response.close() - - -class Log(dict): - def __init__(self, writer): - self.writer = writer - - def init(self, x): - self.clear() - self.update(x) - self.writer.update({"rid": -1}, {"status": "clear"}) - for k, v in self.items(): - self.notify_cb(dict(action="setitem", key=k, value=v)) - return self - - def notify_cb(self, mod): - if not mod.get("path"): - if mod["action"] == "setitem": - rid = mod["key"] - v = mod["value"] - logger.debug("added: %s: %s", rid, v) - self.writer.update( - fields={ - "rid": rid, - "log_level": v["expid"]["log_level"], - "priority": v["priority"], - "due_date": v["due_date"] or -1., - "arguments": v["expid"].get("arguments", {}), - "repo_rev": v["expid"]["repo_rev"], - "flush": v["flush"], - }, - tags={ - "status": "add", - "class_name": v["expid"]["class_name"], - "file": v["expid"]["file"], - "pipeline": v["pipeline"], - }) - elif mod["action"] == "delitem": - rid = mod["key"] - logger.debug("removed: %s", rid) - self.writer.update({"rid": rid}, {"status": "remove"}) - elif (mod["action"] == "setitem" and mod["key"] == "status" - and mod["value"] == "running"): - rid = mod["path"][0] - logger.debug("run: %s", rid) - - def disconnect_cb(self): - logger.warn("disconnect") - - -class MasterReader(TaskObject): - def __init__(self, server, port, retry, writer): - self.server = server - self.port = port - self.retry = retry - - self.writer = writer - - async def _do(self): - subscriber = Subscriber( - "schedule", - target_builder=self.writer.init, - notify_cb=self.writer.notify_cb, - disconnect_cb=self.writer.disconnect_cb) - while True: - try: - await subscriber.connect(self.server, self.port) - try: - await asyncio.wait_for(subscriber.receive_task, None) - finally: - await subscriber.close() - except (ConnectionAbortedError, ConnectionError, - ConnectionRefusedError, ConnectionResetError) as e: - logger.warning("Connection to master failed (%s: %s)", - e.__class__.__name__, str(e)) - except Exception as e: - logger.exception(e) - else: - logger.warning("Connection to master lost") - logger.warning("Retrying in %.1f seconds", self.retry) - await asyncio.sleep(self.retry) - - -class Logger: - def ping(self): - return True - - -def main(): - args = get_argparser().parse_args() - common_args.init_logger_from_args(args) - - loop = asyncio.get_event_loop() - atexit.register(loop.close) - - writer = DBWriter(args.baseurl_db, - args.user_db, args.password_db, - args.database, args.table) - writer.start() - atexit_register_coroutine(writer.stop) - - log = Log(writer) - - server = Logger() - rpc_server = Server({"schedule_logger": server}, builtin_terminate=True) - loop.run_until_complete(rpc_server.start( - common_args.bind_address_from_args(args), args.port_control)) - atexit_register_coroutine(rpc_server.stop) - - reader = MasterReader(args.server_master, args.port_master, - args.retry_master, log) - reader.start() - atexit_register_coroutine(reader.stop) - - loop.run_until_complete(rpc_server.wait_terminate()) - - -if __name__ == "__main__": - main() diff --git a/artiq/frontend/artiq_master.py b/artiq/frontend/artiq_master.py index ff9014b50..1a5073692 100755 --- a/artiq/frontend/artiq_master.py +++ b/artiq/frontend/artiq_master.py @@ -11,9 +11,9 @@ from sipyco.sync_struct import Publisher from sipyco.logging_tools import Server as LoggingServer from sipyco.broadcast import Broadcaster from sipyco import common_args +from sipyco.asyncio_tools import atexit_register_coroutine from artiq import __version__ as artiq_version -from artiq.tools import atexit_register_coroutine from artiq.master.log import log_args, init_log from artiq.master.databases import DeviceDB, DatasetDB from artiq.master.scheduler import Scheduler diff --git a/artiq/frontend/artiq_session.py b/artiq/frontend/artiq_session.py index be9fa4ae1..3a500c90f 100755 --- a/artiq/frontend/artiq_session.py +++ b/artiq/frontend/artiq_session.py @@ -10,7 +10,9 @@ def get_argparser(): parser = argparse.ArgumentParser( description="ARTIQ session manager. " "Automatically runs the master, dashboard and " - "local controller manager on the current machine.") + "local controller manager on the current machine. " + "The latter requires the artiq-comtools package to " + "be installed.") parser.add_argument("--version", action="version", version="ARTIQ v{}".format(artiq_version), help="print the ARTIQ version number") @@ -28,7 +30,7 @@ def main(): master_cmd = [sys.executable, "-u", "-m", "artiq.frontend.artiq_master"] dashboard_cmd = [sys.executable, "-m", "artiq.frontend.artiq_dashboard"] - ctlmgr_cmd = [sys.executable, "-m", "artiq.frontend.artiq_ctlmgr"] + ctlmgr_cmd = [sys.executable, "-m", "artiq_comtools.artiq_ctlmgr"] master_cmd += args.m dashboard_cmd += args.d ctlmgr_cmd += args.c diff --git a/artiq/master/ctlmgr.py b/artiq/master/ctlmgr.py deleted file mode 100644 index 075f08a41..000000000 --- a/artiq/master/ctlmgr.py +++ /dev/null @@ -1,265 +0,0 @@ -import asyncio -import logging -import subprocess -import shlex -import socket -import os - -from sipyco.sync_struct import Subscriber -from sipyco.pc_rpc import AsyncioClient -from sipyco.logging_tools import LogParser -from sipyco.asyncio_tools import TaskObject - -from artiq.tools import Condition - - -logger = logging.getLogger(__name__) - - -class Controller: - def __init__(self, name, ddb_entry): - self.name = name - self.command = ddb_entry["command"] - self.retry_timer = ddb_entry.get("retry_timer", 5) - self.retry_timer_backoff = ddb_entry.get("retry_timer_backoff", 1.1) - - self.host = ddb_entry["host"] - self.port = ddb_entry["port"] - self.ping_timer = ddb_entry.get("ping_timer", 30) - self.ping_timeout = ddb_entry.get("ping_timeout", 30) - self.term_timeout = ddb_entry.get("term_timeout", 30) - - self.retry_timer_cur = self.retry_timer - self.retry_now = Condition() - self.process = None - self.launch_task = asyncio.ensure_future(self.launcher()) - - async def end(self): - self.launch_task.cancel() - await asyncio.wait_for(self.launch_task, None) - - async def call(self, method, *args, **kwargs): - remote = AsyncioClient() - await remote.connect_rpc(self.host, self.port, None) - try: - targets, _ = remote.get_rpc_id() - await remote.select_rpc_target(targets[0]) - r = await getattr(remote, method)(*args, **kwargs) - finally: - remote.close_rpc() - return r - - async def _ping(self): - try: - ok = await asyncio.wait_for(self.call("ping"), - self.ping_timeout) - if ok: - self.retry_timer_cur = self.retry_timer - return ok - except: - return False - - async def _wait_and_ping(self): - while True: - try: - await asyncio.wait_for(self.process.wait(), - self.ping_timer) - except asyncio.TimeoutError: - logger.debug("pinging controller %s", self.name) - ok = await self._ping() - if not ok: - logger.warning("Controller %s ping failed", self.name) - await self._terminate() - return - else: - break - - def _get_log_source(self): - return "controller({})".format(self.name) - - async def launcher(self): - try: - while True: - logger.info("Starting controller %s with command: %s", - self.name, self.command) - try: - env = os.environ.copy() - env["PYTHONUNBUFFERED"] = "1" - self.process = await asyncio.create_subprocess_exec( - *shlex.split(self.command), - stdout=subprocess.PIPE, stderr=subprocess.PIPE, - env=env, start_new_session=True) - asyncio.ensure_future( - LogParser(self._get_log_source).stream_task( - self.process.stdout)) - asyncio.ensure_future( - LogParser(self._get_log_source).stream_task( - self.process.stderr)) - await self._wait_and_ping() - except FileNotFoundError: - logger.warning("Controller %s failed to start", self.name) - else: - logger.warning("Controller %s exited", self.name) - logger.warning("Restarting in %.1f seconds", - self.retry_timer_cur) - try: - await asyncio.wait_for(self.retry_now.wait(), - self.retry_timer_cur) - except asyncio.TimeoutError: - pass - self.retry_timer_cur *= self.retry_timer_backoff - except asyncio.CancelledError: - await self._terminate() - - async def _terminate(self): - if self.process is None or self.process.returncode is not None: - logger.info("Controller %s already terminated", self.name) - return - logger.debug("Terminating controller %s", self.name) - try: - await asyncio.wait_for(self.call("terminate"), self.term_timeout) - await asyncio.wait_for(self.process.wait(), self.term_timeout) - logger.info("Controller %s terminated", self.name) - return - except: - logger.warning("Controller %s did not exit on request, " - "ending the process", self.name) - if os.name != "nt": - try: - self.process.terminate() - except ProcessLookupError: - pass - try: - await asyncio.wait_for(self.process.wait(), self.term_timeout) - logger.info("Controller process %s terminated", self.name) - return - except asyncio.TimeoutError: - logger.warning("Controller process %s did not terminate, " - "killing", self.name) - try: - self.process.kill() - except ProcessLookupError: - pass - try: - await asyncio.wait_for(self.process.wait(), self.term_timeout) - logger.info("Controller process %s killed", self.name) - return - except asyncio.TimeoutError: - logger.warning("Controller process %s failed to die", self.name) - - -def get_ip_addresses(host): - try: - addrinfo = socket.getaddrinfo(host, None) - except: - return set() - return {info[4][0] for info in addrinfo} - - -class Controllers: - def __init__(self): - self.host_filter = None - self.active_or_queued = set() - self.queue = asyncio.Queue() - self.active = dict() - self.process_task = asyncio.ensure_future(self._process()) - - async def _process(self): - while True: - action, param = await self.queue.get() - if action == "set": - k, ddb_entry = param - if k in self.active: - await self.active[k].end() - self.active[k] = Controller(k, ddb_entry) - elif action == "del": - await self.active[param].end() - del self.active[param] - self.queue.task_done() - if action not in ("set", "del"): - raise ValueError - - def __setitem__(self, k, v): - try: - if (isinstance(v, dict) and v["type"] == "controller" and - self.host_filter in get_ip_addresses(v["host"]) and - "command" in v): - v["command"] = v["command"].format(name=k, - bind=self.host_filter, - port=v["port"]) - self.queue.put_nowait(("set", (k, v))) - self.active_or_queued.add(k) - except: - logger.error("Failed to process device database entry %s", k, - exc_info=True) - - def __delitem__(self, k): - if k in self.active_or_queued: - self.queue.put_nowait(("del", k)) - self.active_or_queued.remove(k) - - def delete_all(self): - for name in set(self.active_or_queued): - del self[name] - - async def shutdown(self): - self.process_task.cancel() - for c in self.active.values(): - await c.end() - - -class ControllerDB: - def __init__(self): - self.current_controllers = Controllers() - - def set_host_filter(self, host_filter): - self.current_controllers.host_filter = host_filter - - def sync_struct_init(self, init): - if self.current_controllers is not None: - self.current_controllers.delete_all() - for k, v in init.items(): - self.current_controllers[k] = v - return self.current_controllers - - -class ControllerManager(TaskObject): - def __init__(self, server, port, retry_master): - self.server = server - self.port = port - self.retry_master = retry_master - self.controller_db = ControllerDB() - - async def _do(self): - try: - subscriber = Subscriber("devices", - self.controller_db.sync_struct_init) - while True: - try: - def set_host_filter(): - s = subscriber.writer.get_extra_info("socket") - localhost = s.getsockname()[0] - self.controller_db.set_host_filter(localhost) - await subscriber.connect(self.server, self.port, - set_host_filter) - try: - await asyncio.wait_for(subscriber.receive_task, None) - finally: - await subscriber.close() - except (ConnectionAbortedError, ConnectionError, - ConnectionRefusedError, ConnectionResetError) as e: - logger.warning("Connection to master failed (%s: %s)", - e.__class__.__name__, str(e)) - else: - logger.warning("Connection to master lost") - logger.warning("Retrying in %.1f seconds", self.retry_master) - await asyncio.sleep(self.retry_master) - except asyncio.CancelledError: - pass - finally: - await self.controller_db.current_controllers.shutdown() - - def retry_now(self, k): - """If a controller is disabled and pending retry, perform that retry - now.""" - self.controller_db.current_controllers.active[k].retry_now.notify() diff --git a/artiq/master/scheduler.py b/artiq/master/scheduler.py index 78d90564b..a1c16715f 100644 --- a/artiq/master/scheduler.py +++ b/artiq/master/scheduler.py @@ -4,10 +4,10 @@ from enum import Enum from time import time from sipyco.sync_struct import Notifier -from sipyco.asyncio_tools import TaskObject +from sipyco.asyncio_tools import TaskObject, Condition from artiq.master.worker import Worker, log_worker_exception -from artiq.tools import asyncio_wait_or_cancel, Condition +from artiq.tools import asyncio_wait_or_cancel logger = logging.getLogger(__name__) diff --git a/artiq/test/test_ctlmgr.py b/artiq/test/test_ctlmgr.py deleted file mode 100644 index 728353033..000000000 --- a/artiq/test/test_ctlmgr.py +++ /dev/null @@ -1,85 +0,0 @@ -import os -import sys -import unittest -import logging -import asyncio - -from sipyco.pc_rpc import AsyncioClient - -from artiq.master.ctlmgr import Controllers -from artiq.tools import expect_no_log_messages - - -logger = logging.getLogger(__name__) - - -class ControllerCase(unittest.TestCase): - def setUp(self): - if os.name == "nt": - self.loop = asyncio.ProactorEventLoop() - else: - self.loop = asyncio.new_event_loop() - asyncio.set_event_loop(self.loop) - self.addCleanup(self.loop.close) - - self.controllers = Controllers() - self.controllers.host_filter = "::1" - self.addCleanup( - self.loop.run_until_complete, self.controllers.shutdown()) - - async def start(self, name, entry): - self.controllers[name] = entry - await self.controllers.queue.join() - await self.wait_for_ping(entry["host"], entry["port"]) - - async def get_client(self, host, port): - remote = AsyncioClient() - await remote.connect_rpc(host, port, None) - targets, _ = remote.get_rpc_id() - await remote.select_rpc_target(targets[0]) - self.addCleanup(remote.close_rpc) - return remote - - async def wait_for_ping(self, host, port, retries=5, timeout=2): - dt = timeout/retries - while timeout > 0: - try: - remote = await self.get_client(host, port) - ok = await asyncio.wait_for(remote.ping(), dt) - if not ok: - raise ValueError("unexcepted ping() response from " - "controller: `{}`".format(ok)) - return ok - except asyncio.TimeoutError: - timeout -= dt - except (ConnectionAbortedError, ConnectionError, - ConnectionRefusedError, ConnectionResetError): - await asyncio.sleep(dt) - timeout -= dt - raise asyncio.TimeoutError - - def test_start_ping_stop_controller(self): - entry = { - "type": "controller", - "host": "::1", - "port": 1068, - "command": (sys.executable.replace("\\", "\\\\") - + " -m artiq.frontend.aqctl_corelog " - + "-p {port} --simulation foo") - } - async def test(): - await self.start("corelog", entry) - remote = await self.get_client(entry["host"], entry["port"]) - await remote.ping() - - self.loop.run_until_complete(test()) - - def test_no_command_controller(self): - entry = { - "type": "controller", - "host": "::1", - "port": 1068 - } - with expect_no_log_messages(logging.ERROR): - self.controllers["corelog"] = entry - self.assertTrue(self.controllers.queue.empty()) diff --git a/artiq/test/test_frontends.py b/artiq/test/test_frontends.py index 0d88fb328..9bafbff4a 100644 --- a/artiq/test/test_frontends.py +++ b/artiq/test/test_frontends.py @@ -13,8 +13,8 @@ class TestFrontends(unittest.TestCase): "corelog" ], "artiq": [ - "client", "compile", "coreanalyzer", "coremgmt", "ctlmgr", - "netboot", "flash", "influxdb", "master", "mkfs", "route", + "client", "compile", "coreanalyzer", "coremgmt", + "netboot", "flash", "master", "mkfs", "route", "rtiomon", "run", "session" ] } diff --git a/artiq/tools.py b/artiq/tools.py index afeef8bc8..23095f251 100644 --- a/artiq/tools.py +++ b/artiq/tools.py @@ -1,7 +1,4 @@ import asyncio -import atexit -import collections -import contextlib import importlib.machinery import logging import os @@ -19,9 +16,7 @@ from artiq.language.environment import is_experiment __all__ = ["parse_arguments", "elide", "short_format", "file_import", "get_experiment", - "UnexpectedLogMessageError", "expect_no_log_messages", - "atexit_register_coroutine", "exc_to_warning", - "asyncio_wait_or_cancel", "Condition", + "exc_to_warning", "asyncio_wait_or_cancel", "get_windows_drives", "get_user_config_dir"] @@ -107,42 +102,6 @@ def get_experiment(module, class_name=None): return exps[0][1] -class UnexpectedLogMessageError(Exception): - pass - - -class FailingLogHandler(logging.Handler): - def emit(self, record): - raise UnexpectedLogMessageError("Unexpected log message: '{}'".format( - record.getMessage())) - - -@contextlib.contextmanager -def expect_no_log_messages(level, logger=None): - """Raise an UnexpectedLogMessageError if a log message of the given level - (or above) is emitted while the context is active. - - Example: :: - - with expect_no_log_messages(logging.ERROR): - do_stuff_that_should_not_log_errors() - """ - if logger is None: - logger = logging.getLogger() - handler = FailingLogHandler(level) - logger.addHandler(handler) - try: - yield - finally: - logger.removeHandler(handler) - - -def atexit_register_coroutine(coroutine, loop=None): - if loop is None: - loop = asyncio.get_event_loop() - atexit.register(lambda: loop.run_until_complete(coroutine())) - - async def exc_to_warning(coro): try: await coro @@ -165,29 +124,6 @@ async def asyncio_wait_or_cancel(fs, **kwargs): return fs -class Condition: - def __init__(self, *, loop=None): - if loop is not None: - self._loop = loop - else: - self._loop = asyncio.get_event_loop() - self._waiters = collections.deque() - - async def wait(self): - """Wait until notified.""" - fut = asyncio.Future(loop=self._loop) - self._waiters.append(fut) - try: - await fut - finally: - self._waiters.remove(fut) - - def notify(self): - for fut in self._waiters: - if not fut.done(): - fut.set_result(False) - - def get_windows_drives(): from ctypes import windll diff --git a/doc/manual/conf.py b/doc/manual/conf.py index 3b52040ad..6f9b76777 100644 --- a/doc/manual/conf.py +++ b/doc/manual/conf.py @@ -35,7 +35,7 @@ mock_modules = ["artiq.gui.waitingspinnerwidget", "quamash", "pyqtgraph", "matplotlib", "numpy", "dateutil", "dateutil.parser", "prettytable", "PyQt5", "h5py", "serial", "scipy", "scipy.interpolate", - "llvmlite_artiq", "Levenshtein", "aiohttp", "pythonparser"] + "llvmlite_artiq", "Levenshtein", "pythonparser"] for module in mock_modules: sys.modules[module] = Mock() diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 5ce4f1259..33cd8498c 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -58,6 +58,7 @@ Installing multiple packages and making them visible to the ARTIQ commands requi (pkgs.python3.withPackages(ps: [ # List desired Python packages here. artiq-full.artiq + artiq-full.artiq-comtools # The board packages are also "Python" packages. You only need a board # package if you intend to reflash that board (those packages contain # only board firmware). diff --git a/doc/manual/management_system.rst b/doc/manual/management_system.rst index ebebe1b57..aafbb0361 100644 --- a/doc/manual/management_system.rst +++ b/doc/manual/management_system.rst @@ -16,7 +16,7 @@ The master is a headless component, and one or several clients (command-line or Controller manager ------------------ -:ref:`Controller managers ` are responsible for running and stopping controllers on a machine. There is one controller manager per network node that runs controllers. +Controller managers (started using the ``artiq_ctlmgr`` command that is part of the ``artiq-comtools`` package) are responsible for running and stopping controllers on a machine. There is one controller manager per network node that runs controllers. A controller manager connects to the master and uses the device database to determine what controllers need to be run. Changes in the device database are tracked by the manager and controllers are started and stopped accordingly. @@ -158,16 +158,6 @@ artiq_master :prog: artiq_master -.. _frontend-artiq-ctlmgr: - -artiq_ctlmgr ------------- - -.. argparse:: - :ref: artiq.frontend.artiq_ctlmgr.get_argparser - :prog: artiq_ctlmgr - - .. _frontend-artiq-client: artiq_client diff --git a/doc/manual/utilities.rst b/doc/manual/utilities.rst index 4946fea2a..9e056e55e 100644 --- a/doc/manual/utilities.rst +++ b/doc/manual/utilities.rst @@ -131,17 +131,3 @@ DRTIO routing table manipulation tool .. argparse:: :ref: artiq.frontend.artiq_route.get_argparser :prog: artiq_route - -Data to InfluxDB bridge ------------------------ - -.. argparse:: - :ref: artiq.frontend.artiq_influxdb.get_argparser - :prog: artiq_influxdb - -Schedule to InfluxDB logging bridge ------------------------------------ - -.. argparse:: - :ref: artiq.frontend.artiq_influxdb_schedule.get_argparser - :prog: artiq_influxdb_schedule diff --git a/install-with-conda.py b/install-with-conda.py index 2eab13866..fb09ad3ab 100644 --- a/install-with-conda.py +++ b/install-with-conda.py @@ -9,6 +9,7 @@ CONDA_ENV_NAME = "artiq" # The conda packages to download and install. CONDA_PACKAGES = [ "artiq", + "artiq-comtools", # Only install board packages if you plan to reflash the board. # The two lines below are just examples and probably not what you want. # Select the packages that correspond to your board, or remove them diff --git a/setup.py b/setup.py index fae2b91ae..3e0e722ad 100755 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ if sys.version_info[:3] < (3, 5, 3): requirements = [ "numpy", "scipy", "python-dateutil", "prettytable", "h5py", - "quamash", "pyqtgraph", "pygit2", "aiohttp", + "quamash", "pyqtgraph", "pygit2", "llvmlite_artiq", "pythonparser", "python-Levenshtein", ] @@ -23,11 +23,8 @@ console_scripts = [ "artiq_compile = artiq.frontend.artiq_compile:main", "artiq_coreanalyzer = artiq.frontend.artiq_coreanalyzer:main", "artiq_coremgmt = artiq.frontend.artiq_coremgmt:main", - "artiq_ctlmgr = artiq.frontend.artiq_ctlmgr:main", "artiq_ddb_template = artiq.frontend.artiq_ddb_template:main", "artiq_netboot = artiq.frontend.artiq_netboot:main", - "artiq_influxdb = artiq.frontend.artiq_influxdb:main", - "artiq_influxdb_schedule = artiq.frontend.artiq_influxdb_schedule:main", "artiq_master = artiq.frontend.artiq_master:main", "artiq_mkfs = artiq.frontend.artiq_mkfs:main", "artiq_rtiomon = artiq.frontend.artiq_rtiomon:main", @@ -35,7 +32,6 @@ console_scripts = [ "artiq_route = artiq.frontend.artiq_route:main", "artiq_run = artiq.frontend.artiq_run:main", "artiq_flash = artiq.frontend.artiq_flash:main", - "aqctl_corelog = artiq.frontend.aqctl_corelog:main", ] From db13747279e92d645b2f07753e886ed29e3c7e6a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Nov 2019 16:22:45 +0800 Subject: [PATCH 1995/2457] fix device_db alias corner case bugs. Closes #1140 --- artiq/examples/artiq_ipython_notebook.ipynb | 4 +- artiq/frontend/artiq_coremgmt.py | 3 +- artiq/master/databases.py | 8 +++- artiq/master/worker_db.py | 44 ++++++++++----------- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/artiq/examples/artiq_ipython_notebook.ipynb b/artiq/examples/artiq_ipython_notebook.ipynb index 50b0b0905..7964cd5a4 100644 --- a/artiq/examples/artiq_ipython_notebook.ipynb +++ b/artiq/examples/artiq_ipython_notebook.ipynb @@ -72,8 +72,8 @@ "assert lda.get_attenuation() == 42\n", "\n", "# ... or we can wire it up ourselves if you know where it is\n", - "assert ddb.get(\"lda\")[\"host\"] == \"::1\"\n", - "assert ddb.get(\"lda\")[\"port\"] == 3253\n", + "assert ddb.get(\"lda\", resolve_alias=True)[\"host\"] == \"::1\"\n", + "assert ddb.get(\"lda\", resolve_alias=True)[\"port\"] == 3253\n", "\n", "# there are different Client types tailored to different use cases:\n", "\n", diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index db420c971..542e12925 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -142,7 +142,8 @@ def main(): common_args.init_logger_from_args(args) if args.device is None: - core_addr = DeviceDB(args.device_db).get("core")["arguments"]["host"] + ddb = DeviceDB(args.device_db) + core_addr = ddb.get("core", resolve_alias=True)["arguments"]["host"] else: core_addr = args.device mgmt = CommMgmt(core_addr) diff --git a/artiq/master/databases.py b/artiq/master/databases.py index 0eb59bf0e..977cfae44 100644 --- a/artiq/master/databases.py +++ b/artiq/master/databases.py @@ -25,8 +25,12 @@ class DeviceDB: def get_device_db(self): return self.data.raw_view - def get(self, key): - return self.data.raw_view[key] + def get(self, key, resolve_alias=False): + desc = self.data.raw_view[key] + if resolve_alias: + while isinstance(desc, str): + desc = self.data.raw_view[desc] + return desc class DatasetDB(TaskObject): diff --git a/artiq/master/worker_db.py b/artiq/master/worker_db.py index 6d3799576..172846145 100644 --- a/artiq/master/worker_db.py +++ b/artiq/master/worker_db.py @@ -5,7 +5,6 @@ standalone command line tools). """ from operator import setitem -from collections import OrderedDict import importlib import logging @@ -60,44 +59,43 @@ class DeviceManager: def __init__(self, ddb, virtual_devices=dict()): self.ddb = ddb self.virtual_devices = virtual_devices - self.active_devices = OrderedDict() + self.active_devices = [] def get_device_db(self): """Returns the full contents of the device database.""" return self.ddb.get_device_db() def get_desc(self, name): - desc = self.ddb.get(name) - while isinstance(desc, str): - # alias - desc = self.ddb.get(desc) - return desc + return self.ddb.get(name, resolve_alias=True) def get(self, name): """Get the device driver or controller client corresponding to a device database entry.""" if name in self.virtual_devices: return self.virtual_devices[name] - if name in self.active_devices: - return self.active_devices[name] - else: - try: - desc = self.get_desc(name) - except Exception as e: - raise DeviceError("Failed to get description of device '{}'" - .format(name)) from e - try: - dev = _create_device(desc, self) - except Exception as e: - raise DeviceError("Failed to create device '{}'" - .format(name)) from e - self.active_devices[name] = dev - return dev + + try: + desc = self.get_desc(name) + except Exception as e: + raise DeviceError("Failed to get description of device '{}'" + .format(name)) from e + + for existing_desc, existing_dev in self.active_devices: + if desc == existing_desc: + return existing_dev + + try: + dev = _create_device(desc, self) + except Exception as e: + raise DeviceError("Failed to create device '{}'" + .format(name)) from e + self.active_devices.append((desc, dev)) + return dev def close_devices(self): """Closes all active devices, in the opposite order as they were requested.""" - for dev in reversed(list(self.active_devices.values())): + for _desc, dev in reversed(self.active_devices): try: if isinstance(dev, (Client, BestEffortClient)): dev.close_rpc() From 29d84f5655ca3025dc46e58366e0e29abc503508 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Nov 2019 16:56:03 +0800 Subject: [PATCH 1996/2457] add beta version marker --- BETA | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 BETA diff --git a/BETA b/BETA new file mode 100644 index 000000000..e69de29bb From 6bb931a17b282470c145bf0e1ceb8a6ec0bce043 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Nov 2019 17:04:46 +0800 Subject: [PATCH 1997/2457] manual: point to beta Nix channel --- doc/manual/installing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 33cd8498c..3c1f51f68 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -21,7 +21,7 @@ First, install the Nix package manager. Some distributions provide a package for Once Nix is installed, add the M-Labs package channel with: :: - $ nix-channel --add https://nixbld.m-labs.hk/channel/custom/artiq/full/artiq-full + $ nix-channel --add https://nixbld.m-labs.hk/channel/custom/artiq/full-beta/artiq-full Those channels track `nixpkgs 19.09 `_. You can check the latest status through the `Hydra interface `_. As the Nix package manager default installation uses the development version of nixpkgs, we need to tell it to switch to the release: :: From 9b6b683d87b314ec304951a619a3236b1e4fe871 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Nov 2019 17:16:50 +0800 Subject: [PATCH 1998/2457] update MAJOR_VERSION --- MAJOR_VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAJOR_VERSION b/MAJOR_VERSION index 7ed6ff82d..1e8b31496 100644 --- a/MAJOR_VERSION +++ b/MAJOR_VERSION @@ -1 +1 @@ -5 +6 From 310a627e162de782fd31aef842e41f0989a4bde3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 14 Nov 2019 23:52:57 +0800 Subject: [PATCH 1999/2457] doc: mention toptica-lasersdk-artiq conda package --- doc/manual/list_of_ndsps.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/list_of_ndsps.rst b/doc/manual/list_of_ndsps.rst index 37d5993b8..a8c4c06b3 100644 --- a/doc/manual/list_of_ndsps.rst +++ b/doc/manual/list_of_ndsps.rst @@ -22,7 +22,7 @@ The following network device support packages are available for ARTIQ. This list +---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ | Anel HUT2 power distribution | ``hut2`` | ``hut2`` | `HTML `_ | +---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ -| TOPTICA lasers | ``toptica-lasersdk-artiq`` | See anaconda.org | Not available | +| TOPTICA lasers | ``toptica-lasersdk-artiq`` | ``toptica-lasersdk-artiq`` | Not available | +---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ | HighFinesse wavemeters | ``highfinesse-net`` | ``highfinesse-net`` | `HTML `_ | +---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ From eefc6ae80d275fbfe0b4ef326401e4f2c08a3153 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 15 Nov 2019 13:07:16 +0800 Subject: [PATCH 2000/2457] update release notes --- RELEASE_NOTES.rst | 51 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 5561efdfc..4e5a81792 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -6,25 +6,60 @@ Release notes ARTIQ-5 ------- -* The :class:`~artiq.coredevice.ad9910.AD9910` and - :class:`~artiq.coredevice.ad9914.AD9914` phase reference timestamp parameters - have been renamed to ``ref_time_mu`` for consistency, as they are in machine - units. -* :func:`~artiq.tools.verbosity_args` has been renamed to - :func:`~artiq.tools.add_common_args`, and now adds a ``--version`` flag. +Highlights: + +* Performance improvements: + - Faster RTIO event submission (1.5x improvement in pulse rate test) + See: https://github.com/m-labs/artiq/issues/636 + - Faster compilation times (3 seconds saved on kernel compilation time on a typical + medium-size experiment) + See: https://github.com/m-labs/artiq/commit/611bcc4db4ed604a32d9678623617cd50e968cbf +* Improved packaging and build system: + - new continuous integration/delivery infrastructure based on Nix and Hydra, + providing reproducibility, speed and independence. + - rolling release process (https://github.com/m-labs/artiq/issues/1326). + - firmware, gateware and device database templates are automatically built for all + supported Kasli variants. + - new JSON description format for generic Kasli systems. + - Nix packages are now supported. + - many Conda problems worked around. + - controllers are now out-of-tree. + - split packages that enable lightweight applications that communicate with ARTIQ, + e.g. controllers running on non-x86 single-board computers. +* Improved Urukul support: + - AD9910 RAM mode. + - Configurable refclk divider and PLL bypass. + - More reliable phase synchronization at high sample rates. + - Synchronization calibration data can be read from EEPROM. * A gateware-level input edge counter has been added, which offers higher throughput and increased flexibility over the usual TTL input PHYs where edge timestamps are not required. See :mod:`artiq.coredevice.edge_counter` for the core device driver and :mod:`artiq.gateware.rtio.phy.edge_counter`/ :meth:`artiq.gateware.eem.DIO.add_std` for the gateware components. +* With DRTIO, Siphaser uses a better calibration mechanism. + See: https://github.com/m-labs/artiq/commit/cc58318500ecfa537abf24127f2c22e8fe66e0f8 +* Schedule updates can be sent to influxdb (artiq_influxdb_schedule). +* Experiments can now programatically set their default pipeline, priority, and flush flag. * List datasets can now be efficiently appended to from experiments using :meth:`artiq.language.environment.HasEnvironment.append_to_dataset`. +* The core device now supports IPv6. +* To make development easier, the bootloader can receive firmware and secondary FPGA + gateware from the network. +* Python 3.7 compatibility (Nix and source builds only, no Conda). +* Various other bugs from 4.0 fixed. +* Preliminary Sayma v2 and Metlino hardware support. + +Breaking changes: + +* The :class:`~artiq.coredevice.ad9910.AD9910` and + :class:`~artiq.coredevice.ad9914.AD9914` phase reference timestamp parameters + have been renamed to ``ref_time_mu`` for consistency, as they are in machine + units. * The controller manager now ignores device database entries without the - ``"command"`` key set to facilitate sharing of devices between multiple + ``command`` key set to facilitate sharing of devices between multiple masters. * The meaning of the ``-d/--dir`` and ``--srcbuild`` options of ``artiq_flash`` has changed. -* Experiments can now programatically set their default pipeline, priority, and flush flag. * Controllers for third-party devices are now out-of-tree. * ``aqctl_corelog`` now filters log messages below the ``WARNING`` level by default. This behavior can be changed using the ``-v`` and ``-q`` options like the other From 3adc799785e41248fe208aad08bc833126df9722 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 15 Nov 2019 13:49:09 +0800 Subject: [PATCH 2001/2457] update GUI background --- artiq/gui/logo_ver.svg | 75 +++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/artiq/gui/logo_ver.svg b/artiq/gui/logo_ver.svg index 43a4dcd3b..f45f67897 100644 --- a/artiq/gui/logo_ver.svg +++ b/artiq/gui/logo_ver.svg @@ -18,7 +18,7 @@ enable-background="new 0 0 800 800" xml:space="preserve" id="svg2" - inkscape:version="0.92.3 (2405546, 2018-03-11)" + inkscape:version="0.92.4 (5da689c313, 2019-01-14)" sodipodi:docname="logo_ver.svg">image/svg+xml \ No newline at end of file + aria-label="6" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:96px;line-height:25px;font-family:'Droid Sans Thai';-inkscape-font-specification:'Droid Sans Thai, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:0;stroke:none" + id="text843"> + \ No newline at end of file From 57979da59a73f321ed78b5d0509dbfae3fe36cbf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 15 Nov 2019 13:49:54 +0800 Subject: [PATCH 2002/2457] RELEASE_NOTES: add ARTIQ-6 section --- RELEASE_NOTES.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 4e5a81792..c68dfb4d6 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -3,6 +3,14 @@ Release notes ============= +ARTIQ-6 +------- + +Highlights: + +Breaking changes: + + ARTIQ-5 ------- From cf6a7f243f477ef6425978c8936433e38bd127a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Fri, 15 Nov 2019 15:56:17 +0800 Subject: [PATCH 2003/2457] RELEASE_NOTES: fix rst formatting --- RELEASE_NOTES.rst | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index c68dfb4d6..58ec454b7 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -17,28 +17,28 @@ ARTIQ-5 Highlights: * Performance improvements: - - Faster RTIO event submission (1.5x improvement in pulse rate test) - See: https://github.com/m-labs/artiq/issues/636 - - Faster compilation times (3 seconds saved on kernel compilation time on a typical - medium-size experiment) - See: https://github.com/m-labs/artiq/commit/611bcc4db4ed604a32d9678623617cd50e968cbf + - Faster RTIO event submission (1.5x improvement in pulse rate test) + See: https://github.com/m-labs/artiq/issues/636 + - Faster compilation times (3 seconds saved on kernel compilation time on a typical + medium-size experiment) + See: https://github.com/m-labs/artiq/commit/611bcc4db4ed604a32d9678623617cd50e968cbf * Improved packaging and build system: - - new continuous integration/delivery infrastructure based on Nix and Hydra, - providing reproducibility, speed and independence. - - rolling release process (https://github.com/m-labs/artiq/issues/1326). - - firmware, gateware and device database templates are automatically built for all - supported Kasli variants. - - new JSON description format for generic Kasli systems. - - Nix packages are now supported. - - many Conda problems worked around. - - controllers are now out-of-tree. - - split packages that enable lightweight applications that communicate with ARTIQ, - e.g. controllers running on non-x86 single-board computers. + - new continuous integration/delivery infrastructure based on Nix and Hydra, + providing reproducibility, speed and independence. + - rolling release process (https://github.com/m-labs/artiq/issues/1326). + - firmware, gateware and device database templates are automatically built for all + supported Kasli variants. + - new JSON description format for generic Kasli systems. + - Nix packages are now supported. + - many Conda problems worked around. + - controllers are now out-of-tree. + - split packages that enable lightweight applications that communicate with ARTIQ, + e.g. controllers running on non-x86 single-board computers. * Improved Urukul support: - - AD9910 RAM mode. - - Configurable refclk divider and PLL bypass. - - More reliable phase synchronization at high sample rates. - - Synchronization calibration data can be read from EEPROM. + - AD9910 RAM mode. + - Configurable refclk divider and PLL bypass. + - More reliable phase synchronization at high sample rates. + - Synchronization calibration data can be read from EEPROM. * A gateware-level input edge counter has been added, which offers higher throughput and increased flexibility over the usual TTL input PHYs where edge timestamps are not required. See :mod:`artiq.coredevice.edge_counter` for From b7292f01955c92036344abb7e205a59346ed2078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Fri, 15 Nov 2019 15:59:24 +0800 Subject: [PATCH 2004/2457] RELEASE_NOTES: fix rst formatting further --- RELEASE_NOTES.rst | 52 +++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 58ec454b7..c6ff3f579 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -17,39 +17,39 @@ ARTIQ-5 Highlights: * Performance improvements: - - Faster RTIO event submission (1.5x improvement in pulse rate test) - See: https://github.com/m-labs/artiq/issues/636 - - Faster compilation times (3 seconds saved on kernel compilation time on a typical - medium-size experiment) - See: https://github.com/m-labs/artiq/commit/611bcc4db4ed604a32d9678623617cd50e968cbf + - Faster RTIO event submission (1.5x improvement in pulse rate test) + See: https://github.com/m-labs/artiq/issues/636 + - Faster compilation times (3 seconds saved on kernel compilation time on a typical + medium-size experiment) + See: https://github.com/m-labs/artiq/commit/611bcc4db4ed604a32d9678623617cd50e968cbf * Improved packaging and build system: - - new continuous integration/delivery infrastructure based on Nix and Hydra, - providing reproducibility, speed and independence. - - rolling release process (https://github.com/m-labs/artiq/issues/1326). - - firmware, gateware and device database templates are automatically built for all - supported Kasli variants. - - new JSON description format for generic Kasli systems. - - Nix packages are now supported. - - many Conda problems worked around. - - controllers are now out-of-tree. - - split packages that enable lightweight applications that communicate with ARTIQ, - e.g. controllers running on non-x86 single-board computers. + - new continuous integration/delivery infrastructure based on Nix and Hydra, + providing reproducibility, speed and independence. + - rolling release process (https://github.com/m-labs/artiq/issues/1326). + - firmware, gateware and device database templates are automatically built for all + supported Kasli variants. + - new JSON description format for generic Kasli systems. + - Nix packages are now supported. + - many Conda problems worked around. + - controllers are now out-of-tree. + - split packages that enable lightweight applications that communicate with ARTIQ, + e.g. controllers running on non-x86 single-board computers. * Improved Urukul support: - - AD9910 RAM mode. - - Configurable refclk divider and PLL bypass. - - More reliable phase synchronization at high sample rates. - - Synchronization calibration data can be read from EEPROM. + - AD9910 RAM mode. + - Configurable refclk divider and PLL bypass. + - More reliable phase synchronization at high sample rates. + - Synchronization calibration data can be read from EEPROM. * A gateware-level input edge counter has been added, which offers higher throughput and increased flexibility over the usual TTL input PHYs where - edge timestamps are not required. See :mod:`artiq.coredevice.edge_counter` for - the core device driver and :mod:`artiq.gateware.rtio.phy.edge_counter`/ - :meth:`artiq.gateware.eem.DIO.add_std` for the gateware components. + edge timestamps are not required. See `artiq.coredevice.edge_counter` for + the core device driver and `artiq.gateware.rtio.phy.edge_counter`/ + `artiq.gateware.eem.DIO.add_std` for the gateware components. * With DRTIO, Siphaser uses a better calibration mechanism. See: https://github.com/m-labs/artiq/commit/cc58318500ecfa537abf24127f2c22e8fe66e0f8 * Schedule updates can be sent to influxdb (artiq_influxdb_schedule). * Experiments can now programatically set their default pipeline, priority, and flush flag. * List datasets can now be efficiently appended to from experiments using - :meth:`artiq.language.environment.HasEnvironment.append_to_dataset`. + `artiq.language.environment.HasEnvironment.append_to_dataset`. * The core device now supports IPv6. * To make development easier, the bootloader can receive firmware and secondary FPGA gateware from the network. @@ -59,8 +59,8 @@ Highlights: Breaking changes: -* The :class:`~artiq.coredevice.ad9910.AD9910` and - :class:`~artiq.coredevice.ad9914.AD9914` phase reference timestamp parameters +* The `artiq.coredevice.ad9910.AD9910` and + `artiq.coredevice.ad9914.AD9914` phase reference timestamp parameters have been renamed to ``ref_time_mu`` for consistency, as they are in machine units. * The controller manager now ignores device database entries without the From ac8a5b60c0099052db142e31469e45402bfa9c09 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 18 Nov 2019 08:37:44 +0800 Subject: [PATCH 2005/2457] doc: add sipyco to mock modules --- doc/manual/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/conf.py b/doc/manual/conf.py index 6f9b76777..a02b2c9f8 100644 --- a/doc/manual/conf.py +++ b/doc/manual/conf.py @@ -35,7 +35,7 @@ mock_modules = ["artiq.gui.waitingspinnerwidget", "quamash", "pyqtgraph", "matplotlib", "numpy", "dateutil", "dateutil.parser", "prettytable", "PyQt5", "h5py", "serial", "scipy", "scipy.interpolate", - "llvmlite_artiq", "Levenshtein", "pythonparser"] + "llvmlite_artiq", "Levenshtein", "pythonparser", "sipyco"] for module in mock_modules: sys.modules[module] = Mock() From 9f459f37dc05cd912513ee6183e58c97738a9284 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 18 Nov 2019 13:03:37 +0800 Subject: [PATCH 2006/2457] doc: NDSP URLs, mention contributions can be added to list Closes #1389 --- doc/manual/developing_a_ndsp.rst | 5 ++++ doc/manual/list_of_ndsps.rst | 50 +++++++++++++++----------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/doc/manual/developing_a_ndsp.rst b/doc/manual/developing_a_ndsp.rst index 18e3a995a..be8809c58 100644 --- a/doc/manual/developing_a_ndsp.rst +++ b/doc/manual/developing_a_ndsp.rst @@ -186,3 +186,8 @@ General guidelines * Keep command line parameters consistent across clients/controllers. When adding new command line options, look for a client/controller that does a similar thing and follow its use of ``argparse``. If the original client/controller could use ``argparse`` in a better way, improve it. * Use docstrings for all public methods of the driver (note that those will be retrieved by ``sipyco_rpctool``). * Choose a free default TCP port and add it to the default port list in this manual. + +Hosting your code +----------------- + +We suggest that you create a Git repository for your code, and publish it on https://git.m-labs.hk/, GitLab, GitHub, or a similar website of your choosing. Then send us a message or pull request for your NDSP to be added to the list in this manual. diff --git a/doc/manual/list_of_ndsps.rst b/doc/manual/list_of_ndsps.rst index a8c4c06b3..74237b22a 100644 --- a/doc/manual/list_of_ndsps.rst +++ b/doc/manual/list_of_ndsps.rst @@ -1,30 +1,28 @@ List of available NDSPs ======================= -The following network device support packages are available for ARTIQ. This list is non-exhaustive. +The following network device support packages are available for ARTIQ. If you would like to add yours to this list, just send us an email or a pull request. -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ -| Equipment | Nix package | Conda package | Documentation | -+=================================+===================================+==================================+=====================================================================================================+ -| PDQ2 | Not available | Not available | `HTML `_ | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ -| Lab Brick Digital Attenuator | ``lda`` | ``lda`` | `HTML `_ | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ -| Novatech 409B | ``novatech409b`` | ``novatech409b`` | `HTML `_ | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ -| Thorlabs T-Cubes | ``thorlabs_tcube`` | ``thorlabs_tcube`` | `HTML `_ | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ -| Korad KA3005P | ``korad_ka3005p`` | ``korad_ka3005p`` | `HTML `_ | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ -| Newfocus 8742 | ``newfocus8742`` | ``newfocus8742`` | `HTML `_ | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ -| Princeton Instruments PICam | Not available | Not available | Not available | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ -| Anel HUT2 power distribution | ``hut2`` | ``hut2`` | `HTML `_ | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ -| TOPTICA lasers | ``toptica-lasersdk-artiq`` | ``toptica-lasersdk-artiq`` | Not available | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ -| HighFinesse wavemeters | ``highfinesse-net`` | ``highfinesse-net`` | `HTML `_ | -+---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+ - -For PDQ2 see https://github.com/m-labs/pdq. For PICam see https://github.com/quartiq/picam. ++---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+----------------------------------------------+ +| Equipment | Nix package | Conda package | Documentation | URL | ++=================================+===================================+==================================+=====================================================================================================+==============================================+ +| PDQ2 | Not available | Not available | `HTML `_ | https://github.com/m-labs/pdq | ++---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+----------------------------------------------+ +| Lab Brick Digital Attenuator | ``lda`` | ``lda`` | `HTML `_ | https://github.com/m-labs/lda | ++---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+----------------------------------------------+ +| Novatech 409B | ``novatech409b`` | ``novatech409b`` | `HTML `_ | https://github.com/m-labs/novatech409b | ++---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+----------------------------------------------+ +| Thorlabs T-Cubes | ``thorlabs_tcube`` | ``thorlabs_tcube`` | `HTML `_ | https://github.com/m-labs/thorlabs_tcube | ++---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+----------------------------------------------+ +| Korad KA3005P | ``korad_ka3005p`` | ``korad_ka3005p`` | `HTML `_ | https://github.com/m-labs/korad_ka3005p | ++---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+----------------------------------------------+ +| Newfocus 8742 | ``newfocus8742`` | ``newfocus8742`` | `HTML `_ | https://github.com/quartiq/newfocus8742 | ++---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+----------------------------------------------+ +| Princeton Instruments PICam | Not available | Not available | Not available | https://github.com/quartiq/picam | ++---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+----------------------------------------------+ +| Anel HUT2 power distribution | ``hut2`` | ``hut2`` | `HTML `_ | https://github.com/quartiq/hut2 | ++---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+----------------------------------------------+ +| TOPTICA lasers | ``toptica-lasersdk-artiq`` | ``toptica-lasersdk-artiq`` | Not available | https://github.com/quartiq/lasersdk-artiq | ++---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+----------------------------------------------+ +| HighFinesse wavemeters | ``highfinesse-net`` | ``highfinesse-net`` | `HTML `_ | https://github.com/quartiq/highfinesse-net | ++---------------------------------+-----------------------------------+----------------------------------+-----------------------------------------------------------------------------------------------------+----------------------------------------------+ From f330e285fb584c00ead3b47c9ee93b8b728f746a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 18 Nov 2019 15:26:51 +0800 Subject: [PATCH 2007/2457] DEVELOPER_NOTES: update board lockfile info --- DEVELOPER_NOTES.rst | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/DEVELOPER_NOTES.rst b/DEVELOPER_NOTES.rst index 634ee2471..8c141fbf9 100644 --- a/DEVELOPER_NOTES.rst +++ b/DEVELOPER_NOTES.rst @@ -1,39 +1,17 @@ Sharing development boards ========================== -To avoid conflicts for development boards on the server, while using a board you must hold the corresponding lock file present in ``/var/lib/artiq/boards``. Holding the lock file grants you exclusive access to the board. +To avoid conflicts for development boards on the server, while using a board you must hold the corresponding lock file present in the ``/tmp`` folder of the machine to which the board is connected. Holding the lock file grants you exclusive access to the board. -To lock the KC705 for 30 minutes or until Ctrl-C is pressed: +For example, to lock the KC705 until ENTER is pressed: :: - flock --verbose /var/lib/artiq/boards/kc705-1 sleep 1800 - -Check that the command acquires the lock, i.e. prints something such as: -:: - flock: getting lock took 0.000003 seconds - flock: executing sleep - -To lock the KC705 for the duration of the execution of a shell: -:: - flock /var/lib/artiq/boards/kc705-1 bash - -You may also use this script: -:: - #!/bin/bash - exec flock /var/lib/artiq/boards/$1 bash --rcfile <(cat ~/.bashrc; echo PS1=\"[$1\ lock]\ \$PS1\") + ssh rpi-1.m-labs.hk "flock /tmp/board_lock-kc705-1 -c 'echo locked; read; echo unlocked'" If the board is already locked by another user, the ``flock`` commands above will wait for the lock to be released. -To determine which user is locking a board, use: +To determine which user is locking a board, use a command such as: :: - fuser -v /var/lib/artiq/boards/kc705-1 - - -Selecting a development board with artiq_flash -============================================== - -The board lock file also contains the openocd commands for selecting the corresponding developer board: -:: - artiq_flash -I "$(cat /var/lib/artiq/boards/sayma-1)" + ssh rpi-1.m-labs.hk "fuser -v /tmp/board_lock-kc705-1" Deleting git branches From f73e2a3d30b9243bb636038031216a65487ddc73 Mon Sep 17 00:00:00 2001 From: Fabian Schmid Date: Sun, 17 Nov 2019 16:51:26 +0100 Subject: [PATCH 2008/2457] doc: clarify urukul attenuator behavior Closes #1386 Signed-off-by: Fabian Schmid --- artiq/coredevice/ad9910.py | 4 ++++ artiq/coredevice/ad9912.py | 4 ++++ artiq/coredevice/urukul.py | 9 ++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index a93242455..9982dbf06 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -684,6 +684,8 @@ class AD9910: def set_att_mu(self, att): """Set digital step attenuator in machine units. + This method will write the attenuator settings of all four channels. + .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att_mu` :param att: Attenuation setting, 8 bit digital. @@ -694,6 +696,8 @@ class AD9910: def set_att(self, att): """Set digital step attenuator in SI units. + This method will write the attenuator settings of all four channels. + .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att` :param att: Attenuation in dB. diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index adcfcb4dc..9e1005932 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -113,6 +113,8 @@ class AD9912: def set_att_mu(self, att): """Set digital step attenuator in machine units. + This method will write the attenuator settings of all four channels. + .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att_mu` :param att: Attenuation setting, 8 bit digital. @@ -123,6 +125,8 @@ class AD9912: def set_att(self, att): """Set digital step attenuator in SI units. + This method will write the attenuator settings of all four channels. + .. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att` :param att: Attenuation in dB. Higher values mean more attenuation. diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index cf84bd94f..2cad18188 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -288,7 +288,8 @@ class CPLD: def set_att_mu(self, channel, att): """Set digital step attenuator in machine units. - This method will write the attenuator settings of all four channels. + This method will also write the attenuator settings of the three other channels. Use + :meth:`get_att_mu` to retrieve the hardware state set in previous experiments. :param channel: Attenuator channel (0-3). :param att: Digital attenuation setting: @@ -315,6 +316,10 @@ class CPLD: def set_att(self, channel, att): """Set digital step attenuator in SI units. + This method will write the attenuator settings of all four channels. + + .. seealso:: :meth:`set_att_mu` + :param channel: Attenuator channel (0-3). :param att: Attenuation setting in dB. Higher value is more attenuation. Minimum attenuation is 0*dB, maximum attenuation is @@ -326,6 +331,8 @@ class CPLD: def get_att_mu(self): """Return the digital step attenuator settings in machine units. + The result is stored and will be used in future calls of :meth:`set_att_mu`. + :return: 32 bit attenuator settings """ self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT, 32, From 56d4b70e01067befddbcd57c5eae07f1f32c6c57 Mon Sep 17 00:00:00 2001 From: gthickman Date: Mon, 18 Nov 2019 08:57:27 -0600 Subject: [PATCH 2009/2457] ad9910 osk (#1387) * updated adoo10.py for RAM mode frequency control * updated docstrings for set_cfr1() in ad9910.py * fixed typo in ad9910.py * added docstrings to ad9910.py * removed OSK-related changes in AD9910, to be included in a separate branch. * updated AD9910 set_cfr1 for control of OSK mode parameters * updated AD9910 set_cfr1() for control of OSK mode parameters. --- artiq/coredevice/ad9910.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 9982dbf06..a28d87d0a 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -345,7 +345,8 @@ class AD9910: @kernel def set_cfr1(self, power_down=0b0000, phase_autoclear=0, drg_load_lrr=0, drg_autoclear=0, - internal_profile=0, ram_destination=0, ram_enable=0): + internal_profile=0, ram_destination=0, ram_enable=0, + manual_osk_external=0, osk_enable=0, select_auto_osk=0): """Set CFR1. See the AD9910 datasheet for parameter meanings. This method does not pulse IO_UPDATE. @@ -359,14 +360,20 @@ class AD9910: (:const:`RAM_DEST_FTW`, :const:`RAM_DEST_POW`, :const:`RAM_DEST_ASF`, :const:`RAM_DEST_POWASF`). :param ram_enable: RAM mode enable. + :param manual_osk_external: Enable OSK pin control in manual OSK mode. + :param osk_enable: Enable OSK mode. + :param select_auto_osk: Select manual or automatic OSK mode. """ self.write32(_AD9910_REG_CFR1, (ram_enable << 31) | (ram_destination << 29) | + (manual_osk_external << 23) | (internal_profile << 17) | (drg_load_lrr << 15) | (drg_autoclear << 14) | (phase_autoclear << 13) | + (osk_enable << 9) | + (select_auto_osk << 8) | (power_down << 4) | 2) # SDIO input only, MSB first From c5dbab19293529c87945530e098f1624029dc3d1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Nov 2019 14:43:08 +0800 Subject: [PATCH 2010/2457] gateware: move wrpll to drtio --- artiq/gateware/{ => drtio}/wrpll/__init__.py | 0 artiq/gateware/{ => drtio}/wrpll/filters.py | 0 artiq/gateware/{ => drtio}/wrpll/si549.py | 0 artiq/gateware/{ => drtio}/wrpll/thls.py | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename artiq/gateware/{ => drtio}/wrpll/__init__.py (100%) rename artiq/gateware/{ => drtio}/wrpll/filters.py (100%) rename artiq/gateware/{ => drtio}/wrpll/si549.py (100%) rename artiq/gateware/{ => drtio}/wrpll/thls.py (100%) diff --git a/artiq/gateware/wrpll/__init__.py b/artiq/gateware/drtio/wrpll/__init__.py similarity index 100% rename from artiq/gateware/wrpll/__init__.py rename to artiq/gateware/drtio/wrpll/__init__.py diff --git a/artiq/gateware/wrpll/filters.py b/artiq/gateware/drtio/wrpll/filters.py similarity index 100% rename from artiq/gateware/wrpll/filters.py rename to artiq/gateware/drtio/wrpll/filters.py diff --git a/artiq/gateware/wrpll/si549.py b/artiq/gateware/drtio/wrpll/si549.py similarity index 100% rename from artiq/gateware/wrpll/si549.py rename to artiq/gateware/drtio/wrpll/si549.py diff --git a/artiq/gateware/wrpll/thls.py b/artiq/gateware/drtio/wrpll/thls.py similarity index 100% rename from artiq/gateware/wrpll/thls.py rename to artiq/gateware/drtio/wrpll/thls.py From fa41c946ea7cce06167bde3bc5f9d88678d6eb09 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Nov 2019 17:04:24 +0800 Subject: [PATCH 2011/2457] wrpll: si549 fixes --- artiq/gateware/drtio/wrpll/si549.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/si549.py b/artiq/gateware/drtio/wrpll/si549.py index 652e3f0b5..a0f2c985a 100644 --- a/artiq/gateware/drtio/wrpll/si549.py +++ b/artiq/gateware/drtio/wrpll/si549.py @@ -170,7 +170,7 @@ class ADPLLProgrammer(Module): self.submodules += master self.comb += [ - master.cg.load.eq(self.i2c_divider.storage), + master.cg.load.eq(self.i2c_divider), self.scl.eq(master.scl), master.sda_i.eq(self.sda_i), self.sda_o.eq(master.sda_o) @@ -184,7 +184,7 @@ class Si549(Module, AutoCSR): self.gpio_out = CSRStorage(2) self.gpio_oe = CSRStorage(2) - self.i2c_divider = CSRStorage(16) + self.i2c_divider = CSRStorage(16, reset=2500) self.i2c_address = CSRStorage(7) self.errors = CSR(2) @@ -205,7 +205,7 @@ class Si549(Module, AutoCSR): ] self.comb += [ programmer.adpll.eq(self.adpll), - programmer.adpll_stb.eq(self.adpll_stb) + programmer.stb.eq(self.adpll_stb) ] self.gpio_enable.storage.attr.add("no_retiming") From fe0c324b385ad1a10dc1a9aa6189bfd3ca2da04a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Nov 2019 17:37:09 +0800 Subject: [PATCH 2012/2457] sayma: integrate si549 core --- artiq/gateware/drtio/wrpll/__init__.py | 1 + artiq/gateware/drtio/wrpll/core.py | 10 ++++++++++ artiq/gateware/targets/sayma_amc.py | 20 +++++++++++++++++--- 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 artiq/gateware/drtio/wrpll/core.py diff --git a/artiq/gateware/drtio/wrpll/__init__.py b/artiq/gateware/drtio/wrpll/__init__.py index e69de29bb..d004bc955 100644 --- a/artiq/gateware/drtio/wrpll/__init__.py +++ b/artiq/gateware/drtio/wrpll/__init__.py @@ -0,0 +1 @@ +from artiq.gateware.drtio.wrpll.core import WRPLL diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py new file mode 100644 index 000000000..77c11fb3b --- /dev/null +++ b/artiq/gateware/drtio/wrpll/core.py @@ -0,0 +1,10 @@ +from migen import * +from misoc.interconnect.csr import * + +from artiq.gateware.drtio.wrpll.si549 import Si549 + + +class WRPLL(Module, AutoCSR): + def __init__(self, main_dcxo_i2c, helper_dxco_i2c): + self.submodules.main_dcxo = Si549(main_dcxo_i2c) + self.submodules.helper_dcxo = Si549(helper_dxco_i2c) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 95d2347b0..76cc455af 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -19,6 +19,7 @@ from artiq.gateware import jesd204_tools from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_ultrascale, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale from artiq.gateware.drtio.siphaser import SiPhaser7Series +from artiq.gateware.drtio.wrpll import WRPLL from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import * from artiq.build_soc import * @@ -51,7 +52,7 @@ class SatelliteBase(MiniSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, rtio_clk_freq=125e6, identifier_suffix="", **kwargs): + def __init__(self, rtio_clk_freq=125e6, identifier_suffix="", *, with_wrpll, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -141,6 +142,17 @@ class SatelliteBase(MiniSoC): self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None + if with_wrpll: + # TODO: check OE polarity (depends on what was installed on the boards) + self.comb += [ + platform.request("ddmtd_main_dcxo_oe").eq(1), + platform.request("ddmtd_helper_dcxo_oe").eq(1) + ] + self.submodules.wrpll = WRPLL( + main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), + helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c")) + self.csr_devices.append("wrpll") + rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] platform.add_period_constraint(gth.txoutclk, rtio_clk_period/2) @@ -492,13 +504,15 @@ def main(): default=False, action="store_true", help="Remove SAWG RTIO channels feeding the JESD links (speeds up " "compilation time). Replaces them with fixed pattern generators.") + parser.add_argument("--with-wrpll", default=False, action="store_true") args = parser.parse_args() variant = args.variant.lower() if variant == "satellite": - soc = Satellite(with_sawg=not args.without_sawg, **soc_sayma_amc_argdict(args)) + soc = Satellite(with_sawg=not args.without_sawg, with_wrpll=args.with_wrpll, + **soc_sayma_amc_argdict(args)) elif variant == "simplesatellite": - soc = SimpleSatellite(**soc_sayma_amc_argdict(args)) + soc = SimpleSatellite(with_wrpll=args.with_wrpll, **soc_sayma_amc_argdict(args)) elif variant == "master": soc = Master(**soc_sayma_amc_argdict(args)) else: From ae50da09c43869acf2be9df25b14e97ee40d77f1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Nov 2019 19:15:50 +0800 Subject: [PATCH 2013/2457] drtio/gth_ultrascale: support OBUFDS_GTE3 --- artiq/gateware/drtio/transceiver/gth_ultrascale.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index e0d81bd5c..aefea7652 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -37,6 +37,8 @@ class GTHSingle(Module): self.rx_ready = Signal() # transceiver direct clock outputs + # for OBUFDS_GTE3 + self.rxrecclkout = Signal() # useful to specify clock constraints in a way palatable to Vivado self.txoutclk = Signal() self.rxoutclk = Signal() @@ -521,6 +523,7 @@ class GTHSingle(Module): i_RXSYSCLKSEL=0b00, i_RXOUTCLKSEL=0b010, i_RXPLLCLKSEL=0b00, + o_RXRECCLKOUT=self.rxrecclkout, o_RXOUTCLK=self.rxoutclk, i_RXUSRCLK=ClockSignal("rtio_rx"), i_RXUSRCLK2=ClockSignal("rtio_rx"), @@ -633,7 +636,7 @@ class GTHTXPhaseAlignement(Module): class GTH(Module, TransceiverInterface): - def __init__(self, clock_pads, data_pads, sys_clk_freq, rtio_clk_freq, rtiox_mul=2, dw=20, master=0): + def __init__(self, clock_pads, data_pads, sys_clk_freq, rtio_clk_freq, rtiox_mul=2, dw=20, master=0, clock_recout_pads=None): self.nchannels = nchannels = len(data_pads) self.gths = [] @@ -689,3 +692,9 @@ class GTH(Module, TransceiverInterface): getattr(self, "cd_rtio_rx" + str(i)).clk.eq(self.gths[i].cd_rtio_rx.clk), getattr(self, "cd_rtio_rx" + str(i)).rst.eq(self.gths[i].cd_rtio_rx.rst) ] + + if clock_recout_pads is not None: + self.specials += Instance("OBUFDS_GTE3", + i_I=self.gths[0].rxrecclkout, + i_CEB=0, + o_O=clock_recout_pads.p, o_OB=clock_recout_pads.n) From c536f6c4df2e80a9a8400b12362bed5a4306d406 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 20 Nov 2019 19:16:04 +0800 Subject: [PATCH 2014/2457] sayma_amc: output ddmtd_rec_clk --- artiq/gateware/targets/sayma_amc.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 76cc455af..cfd2434f5 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -66,6 +66,10 @@ class SatelliteBase(MiniSoC): platform = self.platform + if with_wrpll: + clock_recout_pads = platform.request("ddmtd_rec_clk") + else: + clock_recout_pads = None # Use SFP0 to connect to master (Kasli) self.comb += platform.request("sfp_tx_disable", 0).eq(0) drtio_data_pads = [ @@ -76,7 +80,8 @@ class SatelliteBase(MiniSoC): clock_pads=platform.request("cdr_clk_clean"), data_pads=drtio_data_pads, sys_clk_freq=self.clk_freq, - rtio_clk_freq=rtio_clk_freq) + rtio_clk_freq=rtio_clk_freq, + clock_recout_pads=clock_recout_pads) self.csr_devices.append("drtio_transceiver") self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) From e0687b77f53ae72b4e39bacc41e7bab75eb9813c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 22 Nov 2019 14:02:13 +0000 Subject: [PATCH 2015/2457] si5324: 10 MHz ext_ref_frequency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * close #1254 * tested on innsbruck2 kasli variant * sponsored by Uni Innsbruck/AQT Signed-off-by: Robert Jördens --- artiq/firmware/runtime/rtio_clocking.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index 3277a2794..99a47fe3f 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -67,6 +67,19 @@ pub mod crg { #[cfg(si5324_as_synthesizer)] fn setup_si5324_as_synthesizer() { + // 125 MHz output from 10 MHz CLKIN2, 504 Hz BW + #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "10.0"))] + const SI5324_SETTINGS: si5324::FrequencySettings + = si5324::FrequencySettings { + n1_hs : 10, + nc1_ls : 4, + n2_hs : 10, + n2_ls : 300, + n31 : 75, + n32 : 6, + bwsel : 4, + crystal_ref: false + }; // 125MHz output, from 100MHz CLKIN2 reference, 586 Hz loop bandwidth #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "100.0"))] const SI5324_SETTINGS: si5324::FrequencySettings From 449d2c4f08aeb9398321a82b3f138f7049b1f3f4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 27 Nov 2019 21:04:28 +0800 Subject: [PATCH 2016/2457] libboard_misoc: fix !has_i2c --- artiq/firmware/libboard_misoc/i2c.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_misoc/i2c.rs b/artiq/firmware/libboard_misoc/i2c.rs index b816c4921..acade0c24 100644 --- a/artiq/firmware/libboard_misoc/i2c.rs +++ b/artiq/firmware/libboard_misoc/i2c.rs @@ -194,13 +194,13 @@ mod imp { #[cfg(not(has_i2c))] mod imp { const NO_I2C: &'static str = "No I2C support on this platform"; - pub fn init() { Err(NO_I2C) } + pub fn init() -> Result<(), &'static str> { Err(NO_I2C) } pub fn start(_busno: u8) -> Result<(), &'static str> { Err(NO_I2C) } pub fn restart(_busno: u8) -> Result<(), &'static str> { Err(NO_I2C) } pub fn stop(_busno: u8) -> Result<(), &'static str> { Err(NO_I2C) } pub fn write(_busno: u8, _data: u8) -> Result { Err(NO_I2C) } pub fn read(_busno: u8, _ack: bool) -> Result { Err(NO_I2C) } - pub fn pca9548_select(busno: u8, address: u8, channels: u8) -> Result<(), &'static str> { Err(NO_I2C) } + pub fn pca9548_select(_busno: u8, _address: u8, _channels: u8) -> Result<(), &'static str> { Err(NO_I2C) } } pub use self::imp::*; From 4832bfb08c35806a3b456f827d1876ae8afe97ca Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 27 Nov 2019 21:21:00 +0800 Subject: [PATCH 2017/2457] wrpll: i2c functions, select_recovered_clock placeholder --- artiq/firmware/libboard_artiq/lib.rs | 2 + artiq/firmware/libboard_artiq/wrpll.rs | 190 +++++++++++++++++++++++++ artiq/firmware/satman/main.rs | 33 +++-- artiq/gateware/targets/sayma_amc.py | 35 ++--- 4 files changed, 235 insertions(+), 25 deletions(-) create mode 100644 artiq/firmware/libboard_artiq/wrpll.rs diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index b9666732d..0826ceac3 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -26,6 +26,8 @@ pub mod rpc_queue; #[cfg(has_si5324)] pub mod si5324; +#[cfg(has_wrpll)] +pub mod wrpll; #[cfg(has_hmc830_7043)] pub mod hmc830_7043; diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs new file mode 100644 index 000000000..dc97d041a --- /dev/null +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -0,0 +1,190 @@ +mod i2c { + use board_misoc::{csr, clock}; + + #[derive(Debug, Clone, Copy)] + pub enum Dcxo { + Main, + Helper + } + + fn half_period() { clock::spin_us(100) } + const SDA_MASK: u8 = 2; + const SCL_MASK: u8 = 1; + + fn sda_i(dcxo: Dcxo) -> bool { + let reg = match dcxo { + Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_in_read() }, + Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_in_read() }, + }; + reg & SDA_MASK != 0 + } + + fn sda_oe(dcxo: Dcxo, oe: bool) { + let reg = match dcxo { + Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_oe_read() }, + Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_oe_read() }, + }; + let reg = if oe { reg | SDA_MASK } else { reg & !SDA_MASK }; + match dcxo { + Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_oe_write(reg) }, + Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_oe_write(reg) } + } + } + + fn sda_o(dcxo: Dcxo, o: bool) { + let reg = match dcxo { + Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_out_read() }, + Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_out_read() }, + }; + let reg = if o { reg | SDA_MASK } else { reg & !SDA_MASK }; + match dcxo { + Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_out_write(reg) }, + Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_out_write(reg) } + } + } + + fn scl_oe(dcxo: Dcxo, oe: bool) { + let reg = match dcxo { + Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_oe_read() }, + Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_oe_read() }, + }; + let reg = if oe { reg | SCL_MASK } else { reg & !SCL_MASK }; + match dcxo { + Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_oe_write(reg) }, + Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_oe_write(reg) } + } + } + + fn scl_o(dcxo: Dcxo, o: bool) { + let reg = match dcxo { + Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_out_read() }, + Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_out_read() }, + }; + let reg = if o { reg | SCL_MASK } else { reg & !SCL_MASK }; + match dcxo { + Dcxo::Main => unsafe { csr::wrpll::main_dcxo_gpio_out_write(reg) }, + Dcxo::Helper => unsafe { csr::wrpll::helper_dcxo_gpio_out_write(reg) } + } + } + + pub fn init(dcxo: Dcxo) -> Result<(), &'static str> { + // Set SCL as output, and high level + scl_o(dcxo, true); + scl_oe(dcxo, true); + // Prepare a zero level on SDA so that sda_oe pulls it down + sda_o(dcxo, false); + // Release SDA + sda_oe(dcxo, false); + + // Check the I2C bus is ready + half_period(); + half_period(); + if !sda_i(dcxo) { + // Try toggling SCL a few times + for _bit in 0..8 { + scl_o(dcxo, false); + half_period(); + scl_o(dcxo, true); + half_period(); + } + } + + if !sda_i(dcxo) { + return Err("SDA is stuck low and doesn't get unstuck"); + } + Ok(()) + } + + pub fn start(dcxo: Dcxo) { + // Set SCL high then SDA low + scl_o(dcxo, true); + half_period(); + sda_oe(dcxo, true); + half_period(); + } + + pub fn restart(dcxo: Dcxo) { + // Set SCL low then SDA high */ + scl_o(dcxo, false); + half_period(); + sda_oe(dcxo, false); + half_period(); + // Do a regular start + start(dcxo); + } + + pub fn stop(dcxo: Dcxo) { + // First, make sure SCL is low, so that the target releases the SDA line + scl_o(dcxo, false); + half_period(); + // Set SCL high then SDA high + sda_oe(dcxo, true); + scl_o(dcxo, true); + half_period(); + sda_oe(dcxo, false); + half_period(); + } + + pub fn write(dcxo: Dcxo, data: u8) -> bool { + // MSB first + for bit in (0..8).rev() { + // Set SCL low and set our bit on SDA + scl_o(dcxo, false); + sda_oe(dcxo, data & (1 << bit) == 0); + half_period(); + // Set SCL high ; data is shifted on the rising edge of SCL + scl_o(dcxo, true); + half_period(); + } + // Check ack + // Set SCL low, then release SDA so that the I2C target can respond + scl_o(dcxo, false); + half_period(); + sda_oe(dcxo, false); + // Set SCL high and check for ack + scl_o(dcxo, true); + half_period(); + // returns true if acked (I2C target pulled SDA low) + !sda_i(dcxo) + } + + pub fn read(dcxo: Dcxo, ack: bool) -> u8 { + // Set SCL low first, otherwise setting SDA as input may cause a transition + // on SDA with SCL high which will be interpreted as START/STOP condition. + scl_o(dcxo, false); + half_period(); // make sure SCL has settled low + sda_oe(dcxo, false); + + let mut data: u8 = 0; + + // MSB first + for bit in (0..8).rev() { + scl_o(dcxo, false); + half_period(); + // Set SCL high and shift data + scl_o(dcxo, true); + half_period(); + if sda_i(dcxo) { data |= 1 << bit } + } + // Send ack + // Set SCL low and pull SDA low when acking + scl_o(dcxo, false); + if ack { sda_oe(dcxo, true) } + half_period(); + // then set SCL high + scl_o(dcxo, true); + half_period(); + + data + } +} + +pub fn init() { + info!("initializing..."); + i2c::init(i2c::Dcxo::Main); + i2c::init(i2c::Dcxo::Helper); +} + +pub fn select_recovered_clock(rc: bool) { + info!("select_recovered_clock: {}", rc); +} diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index dc66038c7..fb738f057 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -9,7 +9,11 @@ extern crate board_artiq; use core::convert::TryFrom; use board_misoc::{csr, irq, ident, clock, uart_logger, i2c}; -use board_artiq::{spi, si5324, drtioaux}; +#[cfg(has_si5324)] +use board_artiq::si5324; +#[cfg(has_wrpll)] +use board_artiq::wrpll; +use board_artiq::{spi, drtioaux}; use board_artiq::drtio_routing; #[cfg(has_hmc830_7043)] use board_artiq::hmc830_7043; @@ -413,7 +417,7 @@ fn hardware_tick(ts: &mut u64) { } } -#[cfg(rtio_frequency = "150.0")] +#[cfg(all(has_si5324, rtio_frequency = "150.0"))] const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings { n1_hs : 6, @@ -426,7 +430,7 @@ const SI5324_SETTINGS: si5324::FrequencySettings crystal_ref: true }; -#[cfg(rtio_frequency = "125.0")] +#[cfg(all(has_si5324, rtio_frequency = "125.0"))] const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings { n1_hs : 5, @@ -448,8 +452,13 @@ pub extern fn main() -> i32 { info!("software ident {}", csr::CONFIG_IDENTIFIER_STR); info!("gateware ident {}", ident::read(&mut [0; 64])); - i2c::init().expect("I2C initialization failed"); - si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324"); + #[cfg(has_si5324)] + { + i2c::init().expect("I2C initialization failed"); + si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324"); + } + #[cfg(has_wrpll)] + wrpll::init(); unsafe { csr::drtio_transceiver::stable_clkin_write(1); } @@ -490,8 +499,13 @@ pub extern fn main() -> i32 { } info!("uplink is up, switching to recovered clock"); - si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); - si5324::siphaser::calibrate_skew().expect("failed to calibrate skew"); + #[cfg(has_si5324)] + { + si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks"); + si5324::siphaser::calibrate_skew().expect("failed to calibrate skew"); + } + #[cfg(has_wrpll)] + wrpll::select_recovered_clock(true); #[cfg(has_jdcg)] { @@ -561,8 +575,11 @@ pub extern fn main() -> i32 { drtiosat_reset_phy(true); drtiosat_reset(true); drtiosat_tsc_loaded(); - info!("uplink is down, switching to local crystal clock"); + info!("uplink is down, switching to local oscillator clock"); + #[cfg(has_si5324)] si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks"); + #[cfg(has_wrpll)] + wrpll::select_recovered_clock(false); } } diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index cfd2434f5..dc5d37a6a 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -130,26 +130,10 @@ class SatelliteBase(MiniSoC): self.add_csr_group("drtiorep", drtiorep_csr_group) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - self.comb += platform.request("filtered_clk_sel").eq(1) - self.submodules.siphaser = SiPhaser7Series( - si5324_clkin=platform.request("si5324_clkin"), - rx_synchronizer=self.rx_synchronizer, - ultrascale=True, - rtio_clk_freq=rtio_clk_freq) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) - self.csr_devices.append("siphaser") - self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) - self.csr_devices.append("si5324_rst_n") - i2c = self.platform.request("i2c") - self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) - self.csr_devices.append("i2c") - self.config["I2C_BUS_COUNT"] = 1 - self.config["HAS_SI5324"] = None - if with_wrpll: # TODO: check OE polarity (depends on what was installed on the boards) self.comb += [ + platform.request("filtered_clk_sel").eq(0), platform.request("ddmtd_main_dcxo_oe").eq(1), platform.request("ddmtd_helper_dcxo_oe").eq(1) ] @@ -157,6 +141,23 @@ class SatelliteBase(MiniSoC): main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c")) self.csr_devices.append("wrpll") + else: + self.comb += platform.request("filtered_clk_sel").eq(1) + self.submodules.siphaser = SiPhaser7Series( + si5324_clkin=platform.request("si5324_clkin"), + rx_synchronizer=self.rx_synchronizer, + ultrascale=True, + rtio_clk_freq=rtio_clk_freq) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) + self.csr_devices.append("siphaser") + self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) + self.csr_devices.append("si5324_rst_n") + i2c = self.platform.request("i2c") + self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) + self.csr_devices.append("i2c") + self.config["I2C_BUS_COUNT"] = 1 + self.config["HAS_SI5324"] = None rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] From bcd2383c9d6a4e5521328caa2e76802d8e1f33f6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 27 Nov 2019 22:58:08 +0800 Subject: [PATCH 2018/2457] wrpll: si549 initialization --- artiq/firmware/libboard_artiq/wrpll.rs | 92 +++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index dc97d041a..01a3e89d5 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -179,10 +179,98 @@ mod i2c { } } +mod si549 { + use board_misoc::clock; + use super::i2c; + + const ADDRESS: u8 = 0x55; + + pub fn write(dcxo: i2c::Dcxo, reg: u8, val: u8) -> Result<(), &'static str> { + i2c::start(dcxo); + if !i2c::write(dcxo, ADDRESS << 1) { + return Err("Si549 failed to ack write address") + } + if !i2c::write(dcxo, reg) { + return Err("Si549 failed to ack register") + } + if !i2c::write(dcxo, val) { + return Err("Si549 failed to ack value") + } + i2c::stop(dcxo); + Ok(()) + } + + pub fn write_no_ack_value(dcxo: i2c::Dcxo, reg: u8, val: u8) -> Result<(), &'static str> { + i2c::start(dcxo); + if !i2c::write(dcxo, ADDRESS << 1) { + return Err("Si549 failed to ack write address") + } + if !i2c::write(dcxo, reg) { + return Err("Si549 failed to ack register") + } + i2c::write(dcxo, val); + i2c::stop(dcxo); + Ok(()) + } + + pub fn read(dcxo: i2c::Dcxo, reg: u8) -> Result { + i2c::start(dcxo); + if !i2c::write(dcxo, ADDRESS << 1) { + return Err("Si549 failed to ack write address") + } + if !i2c::write(dcxo, reg) { + return Err("Si549 failed to ack register") + } + i2c::restart(dcxo); + if !i2c::write(dcxo, (ADDRESS << 1) | 1) { + return Err("Si549 failed to ack read address") + } + let val = i2c::read(dcxo, false); + i2c::stop(dcxo); + Ok(val) + } + + pub fn program(dcxo: i2c::Dcxo, hsdiv: u16, lsdiv: u8, fbdiv: u64) -> Result<(), &'static str> { + i2c::init(dcxo)?; + + write(dcxo, 255, 0x00)?; // PAGE + write_no_ack_value(dcxo, 7, 0x80)?; // RESET + clock::spin_us(50_000); // required? not specified in datasheet. + + write(dcxo, 255, 0x00)?; // PAGE + write(dcxo, 69, 0x00)?; // Disable FCAL override. Should bit 0 be 1? + write(dcxo, 17, 0x00)?; // Synchronously disable output + + // The Si549 has no ID register, so we check that it responds correctly + // by writing values to a RAM-like register and reading them back. + for test_value in 0..255 { + write(dcxo, 23, test_value)?; + let readback = read(dcxo, 23)?; + if readback != test_value { + return Err("Si549 detection failed"); + } + } + + write(dcxo, 23, hsdiv as u8)?; + write(dcxo, 24, (hsdiv >> 8) as u8 | (lsdiv << 4))?; + write(dcxo, 26, fbdiv as u8)?; + write(dcxo, 27, (fbdiv >> 8) as u8)?; + write(dcxo, 28, (fbdiv >> 16) as u8)?; + write(dcxo, 29, (fbdiv >> 24) as u8)?; + write(dcxo, 30, (fbdiv >> 32) as u8)?; + write(dcxo, 31, (fbdiv >> 40) as u8)?; + + write(dcxo, 7, 0x08)?; // Start FCAL + write(dcxo, 17, 0x01)?; // Synchronously enable output + + Ok(()) + } +} + pub fn init() { info!("initializing..."); - i2c::init(i2c::Dcxo::Main); - i2c::init(i2c::Dcxo::Helper); + si549::program(i2c::Dcxo::Main, 0x017, 2, 0x04b5badb98a).expect("cannot initialize main Si549"); + si549::program(i2c::Dcxo::Helper, 0x017, 2, 0x04b5c447213).expect("cannot initialize helper Si549"); } pub fn select_recovered_clock(rc: bool) { From 68cab5be8c6107b9121dafb51565a25b4f97a19a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Nov 2019 16:36:59 +0800 Subject: [PATCH 2019/2457] si549: cleanups --- artiq/firmware/libboard_artiq/wrpll.rs | 18 ++++++++++++++---- artiq/gateware/targets/sayma_amc.py | 1 - 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 01a3e89d5..125b47e69 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -234,11 +234,13 @@ mod si549 { i2c::init(dcxo)?; write(dcxo, 255, 0x00)?; // PAGE - write_no_ack_value(dcxo, 7, 0x80)?; // RESET + write_no_ack_value(dcxo, 7, 0x80)?; // RESET clock::spin_us(50_000); // required? not specified in datasheet. write(dcxo, 255, 0x00)?; // PAGE - write(dcxo, 69, 0x00)?; // Disable FCAL override. Should bit 0 be 1? + write(dcxo, 69, 0x00)?; // Disable FCAL override. + // Note: Value 0x00 from Table 5.6 is inconsistent with Table 5.7, + // which shows bit 0 as reserved and =1. write(dcxo, 17, 0x00)?; // Synchronously disable output // The Si549 has no ID register, so we check that it responds correctly @@ -269,8 +271,16 @@ mod si549 { pub fn init() { info!("initializing..."); - si549::program(i2c::Dcxo::Main, 0x017, 2, 0x04b5badb98a).expect("cannot initialize main Si549"); - si549::program(i2c::Dcxo::Helper, 0x017, 2, 0x04b5c447213).expect("cannot initialize helper Si549"); + + #[cfg(rtio_frequency = "125.0")] + let (m_hsdiv, m_lsdiv, m_fbdiv) = (0x017, 2, 0x04b5badb98a); + #[cfg(rtio_frequency = "125.0")] + let (h_hsdiv, h_lsdiv, h_fbdiv) = (0x017, 2, 0x04b5c447213); + + si549::program(i2c::Dcxo::Main, m_hsdiv, m_lsdiv, m_fbdiv) + .expect("cannot initialize main Si549"); + si549::program(i2c::Dcxo::Helper, h_hsdiv, h_lsdiv, h_fbdiv) + .expect("cannot initialize helper Si549"); } pub fn select_recovered_clock(rc: bool) { diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index dc5d37a6a..4e2341037 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -131,7 +131,6 @@ class SatelliteBase(MiniSoC): self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) if with_wrpll: - # TODO: check OE polarity (depends on what was installed on the boards) self.comb += [ platform.request("filtered_clk_sel").eq(0), platform.request("ddmtd_main_dcxo_oe").eq(1), From 4a03ca928d94156b0a075a465feed5f3cd1d9003 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Nov 2019 17:38:29 +0800 Subject: [PATCH 2020/2457] artiq_flash: sayma fixes --- artiq/frontend/artiq_flash.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 495a3bd00..516f0493d 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -372,7 +372,7 @@ def main(): variant_dir = args.target + "-" + variant if args.target == "sayma": if args.srcbuild: - rtm_variant_dir = variant + rtm_variant_dir = "rtm" else: rtm_variant_dir = "sayma-rtm" @@ -414,7 +414,7 @@ def main(): gateware_bin = convert_gateware( artifact_path(variant_dir, "gateware", "top.bit")) programmer.write_binary(*config["gateware"], gateware_bin) - if args.target == "sayma" and variant != "master": + if args.target == "sayma" and variant != "simplesatellite" and variant != "master": rtm_gateware_bin = convert_gateware( artifact_path(rtm_variant_dir, "gateware", "top.bit"), header=True) programmer.write_binary(*config["rtm_gateware"], From 354d82cfe3b912d31de163bdd556a250b1e930cd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Nov 2019 17:40:00 +0800 Subject: [PATCH 2021/2457] wrpll: drive helper clock domain --- artiq/firmware/libboard_artiq/wrpll.rs | 7 +++++++ artiq/gateware/drtio/wrpll/core.py | 13 ++++++++++++- artiq/gateware/targets/sayma_amc.py | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 125b47e69..0a075beff 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -1,3 +1,5 @@ +use board_misoc::{csr, clock}; + mod i2c { use board_misoc::{csr, clock}; @@ -272,6 +274,8 @@ mod si549 { pub fn init() { info!("initializing..."); + unsafe { csr::wrpll::helper_reset_write(1); } + #[cfg(rtio_frequency = "125.0")] let (m_hsdiv, m_lsdiv, m_fbdiv) = (0x017, 2, 0x04b5badb98a); #[cfg(rtio_frequency = "125.0")] @@ -281,6 +285,9 @@ pub fn init() { .expect("cannot initialize main Si549"); si549::program(i2c::Dcxo::Helper, h_hsdiv, h_lsdiv, h_fbdiv) .expect("cannot initialize helper Si549"); + + clock::spin_us(10_000); // Settling Time after FS Change + unsafe { csr::wrpll::helper_reset_write(0); } } pub fn select_recovered_clock(rc: bool) { diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 77c11fb3b..4c2a35a91 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -1,10 +1,21 @@ from migen import * +from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.interconnect.csr import * from artiq.gateware.drtio.wrpll.si549 import Si549 class WRPLL(Module, AutoCSR): - def __init__(self, main_dcxo_i2c, helper_dxco_i2c): + def __init__(self, helper_clk_pads, main_dcxo_i2c, helper_dxco_i2c): + self.helper_reset = CSRStorage(reset=1) + + self.clock_domains.cd_helper = ClockDomain() + self.helper_reset.storage.attr.add("no_retiming") + self.specials += [ + Instance("IBUFGDS", i_I=helper_clk_pads.p, i_IB=helper_clk_pads.n, + o_O=self.cd_helper.clk), + AsyncResetSynchronizer(self.cd_helper, self.helper_reset.storage) + ] + self.submodules.main_dcxo = Si549(main_dcxo_i2c) self.submodules.helper_dcxo = Si549(helper_dxco_i2c) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 4e2341037..8487fdf40 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -137,6 +137,7 @@ class SatelliteBase(MiniSoC): platform.request("ddmtd_helper_dcxo_oe").eq(1) ] self.submodules.wrpll = WRPLL( + helper_clk_pads=platform.request("ddmtd_helper_clk"), main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c")) self.csr_devices.append("wrpll") From 2e55e39ac7003bfbbae158cef333773841230498 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Nov 2019 17:40:25 +0800 Subject: [PATCH 2022/2457] wrpll: use spaces to indent --- artiq/gateware/drtio/wrpll/core.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 4c2a35a91..d4a4435a7 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -6,16 +6,16 @@ from artiq.gateware.drtio.wrpll.si549 import Si549 class WRPLL(Module, AutoCSR): - def __init__(self, helper_clk_pads, main_dcxo_i2c, helper_dxco_i2c): - self.helper_reset = CSRStorage(reset=1) + def __init__(self, helper_clk_pads, main_dcxo_i2c, helper_dxco_i2c): + self.helper_reset = CSRStorage(reset=1) - self.clock_domains.cd_helper = ClockDomain() - self.helper_reset.storage.attr.add("no_retiming") - self.specials += [ - Instance("IBUFGDS", i_I=helper_clk_pads.p, i_IB=helper_clk_pads.n, - o_O=self.cd_helper.clk), - AsyncResetSynchronizer(self.cd_helper, self.helper_reset.storage) - ] + self.clock_domains.cd_helper = ClockDomain() + self.helper_reset.storage.attr.add("no_retiming") + self.specials += [ + Instance("IBUFGDS", i_I=helper_clk_pads.p, i_IB=helper_clk_pads.n, + o_O=self.cd_helper.clk), + AsyncResetSynchronizer(self.cd_helper, self.helper_reset.storage) + ] - self.submodules.main_dcxo = Si549(main_dcxo_i2c) - self.submodules.helper_dcxo = Si549(helper_dxco_i2c) + self.submodules.main_dcxo = Si549(main_dcxo_i2c) + self.submodules.helper_dcxo = Si549(helper_dxco_i2c) From 87894102e504d8cd24f20dde1a1e619d851c42a2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Nov 2019 17:49:02 +0800 Subject: [PATCH 2023/2457] si549: use recommended i2c read sequence --- artiq/firmware/libboard_artiq/wrpll.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 0a075beff..d27b90767 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -105,16 +105,6 @@ mod i2c { half_period(); } - pub fn restart(dcxo: Dcxo) { - // Set SCL low then SDA high */ - scl_o(dcxo, false); - half_period(); - sda_oe(dcxo, false); - half_period(); - // Do a regular start - start(dcxo); - } - pub fn stop(dcxo: Dcxo) { // First, make sure SCL is low, so that the target releases the SDA line scl_o(dcxo, false); @@ -223,12 +213,15 @@ mod si549 { if !i2c::write(dcxo, reg) { return Err("Si549 failed to ack register") } - i2c::restart(dcxo); + i2c::stop(dcxo); + + i2c::start(dcxo); if !i2c::write(dcxo, (ADDRESS << 1) | 1) { return Err("Si549 failed to ack read address") } let val = i2c::read(dcxo, false); i2c::stop(dcxo); + Ok(val) } From 39d5ca11f45efe48f655cbec76d21b92bd46a176 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Nov 2019 22:03:26 +0800 Subject: [PATCH 2024/2457] si549: increase I2C frequency --- artiq/firmware/libboard_artiq/wrpll.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index d27b90767..40ae88e43 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -9,7 +9,7 @@ mod i2c { Helper } - fn half_period() { clock::spin_us(100) } + fn half_period() { clock::spin_us(10) } const SDA_MASK: u8 = 2; const SCL_MASK: u8 = 1; From eb271f383bf927b6621e2decb5ac4c8951abcc0a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 28 Nov 2019 22:03:50 +0800 Subject: [PATCH 2025/2457] wrpll: add DDMTD cores --- artiq/firmware/libboard_artiq/wrpll.rs | 9 ++++ artiq/gateware/drtio/wrpll/core.py | 6 ++- artiq/gateware/drtio/wrpll/ddmtd.py | 62 ++++++++++++++++++++++++++ artiq/gateware/targets/sayma_amc.py | 3 +- 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 artiq/gateware/drtio/wrpll/ddmtd.py diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 40ae88e43..84c34b67e 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -281,6 +281,15 @@ pub fn init() { clock::spin_us(10_000); // Settling Time after FS Change unsafe { csr::wrpll::helper_reset_write(0); } + + info!("DDMTD test:"); + for _ in 0..20 { + unsafe { + csr::wrpll::ddmtd_main_arm_write(1); + while csr::wrpll::ddmtd_main_arm_read() != 0 {} + info!("{}", csr::wrpll::ddmtd_main_tag_read()); + } + } } pub fn select_recovered_clock(rc: bool) { diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index d4a4435a7..ee2099648 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -3,10 +3,11 @@ from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.interconnect.csr import * from artiq.gateware.drtio.wrpll.si549 import Si549 +from artiq.gateware.drtio.wrpll.ddmtd import DDMTD class WRPLL(Module, AutoCSR): - def __init__(self, helper_clk_pads, main_dcxo_i2c, helper_dxco_i2c): + def __init__(self, helper_clk_pads, main_dcxo_i2c, helper_dxco_i2c, ddmtd_inputs, N=15): self.helper_reset = CSRStorage(reset=1) self.clock_domains.cd_helper = ClockDomain() @@ -19,3 +20,6 @@ class WRPLL(Module, AutoCSR): self.submodules.main_dcxo = Si549(main_dcxo_i2c) self.submodules.helper_dcxo = Si549(helper_dxco_i2c) + + self.submodules.ddmtd_helper = DDMTD(N, ddmtd_inputs.rec_clk) + self.submodules.ddmtd_main = DDMTD(N, ddmtd_inputs.main_xo) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py new file mode 100644 index 000000000..3708371b5 --- /dev/null +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -0,0 +1,62 @@ +from migen import * +from migen.genlib.cdc import PulseSynchronizer, MultiReg +from misoc.interconnect.csr import * + + +class DDMTDEdgeDetector(Module): + def __init__(self, i): + self.rising = Signal() + + history = Signal(4) + deglitched = Signal() + self.sync.helper += history.eq(Cat(history[1:], i)) + self.comb += deglitched.eq(i | history[0] | history[1] | history[2] | history[3]) + + deglitched_r = Signal() + self.sync.helper += [ + deglitched_r.eq(deglitched), + self.rising.eq(deglitched & ~deglitched_r) + ] + + +class DDMTD(Module, AutoCSR): + def __init__(self, N, i): + self.arm = CSR() + self.tag = CSRStatus(N) + + # in helper clock domain + self.h_tag = Signal(N) + self.h_tag_update = Signal() + + # # # + + ed = DDMTDEdgeDetector(i) + self.submodules += ed + + counter = Signal(N) + self.sync.helper += [ + counter.eq(counter + 1), + self.h_tag_update.eq(0), + If(ed.rising, + self.h_tag_update.eq(1), + self.h_tag.eq(counter) + ) + ] + + tag_update_ps = PulseSynchronizer("helper", "sys") + self.submodules += tag_update_ps + self.comb += tag_update_ps.i.eq(self.h_tag_update) + tag_update = Signal() + self.sync += tag_update.eq(tag_update_ps.o) + + tag = Signal(N) + self.h_tag.attr.add("no_retiming") + self.specials += MultiReg(self.h_tag, tag) + + self.sync += [ + If(self.arm.re & self.arm.r, self.arm.w.eq(1)), + If(tag_update, + If(self.arm.w, self.tag.status.eq(tag)), + self.arm.w.eq(0), + ) + ] diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 8487fdf40..6cb234f51 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -139,7 +139,8 @@ class SatelliteBase(MiniSoC): self.submodules.wrpll = WRPLL( helper_clk_pads=platform.request("ddmtd_helper_clk"), main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), - helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c")) + helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"), + ddmtd_inputs=platform.request("ddmtd_inputs")) self.csr_devices.append("wrpll") else: self.comb += platform.request("filtered_clk_sel").eq(1) From 86e1924493b6764944a363928e60fcaa2fa82fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 29 Nov 2019 18:46:27 +0000 Subject: [PATCH 2026/2457] kasli_generic: support external reference on masters --- artiq/gateware/targets/kasli_generic.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index c7e74064f..8824e8677 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -162,6 +162,10 @@ class GenericMaster(MasterBase): rtio_clk_freq=description.get("rtio_frequency", 125e6), enable_sata=description.get("enable_sata_drtio", False), **kwargs) + if "ext_ref_frequency" in description: + self.config["SI5324_EXT_REF"] = None + self.config["EXT_REF_FREQUENCY"] = "{:.1f}".format( + description["ext_ref_frequency"]/1e6) if hw_rev == "v1.0": # EEM clock fan-out from Si5324, not MMCX self.comb += self.platform.request("clk_sel").eq(1) From 56074cfffa54a689c98002a4cc26a73a7705a558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 19 Nov 2019 17:12:23 +0000 Subject: [PATCH 2027/2457] suservo: support operating with one urukul MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit implemented by wiring up the second Urukul to dummy pins Signed-off-by: Robert Jördens --- artiq/gateware/eem.py | 61 ++++++++++++------------- artiq/gateware/suservo/pads.py | 11 +++-- artiq/gateware/targets/kasli_generic.py | 10 ++-- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 8a8ad40b8..da11fa797 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -470,13 +470,15 @@ class Grabber(_EEM): class SUServo(_EEM): @staticmethod def io(*eems, iostandard="LVDS_25"): - assert len(eems) == 6 - return (Sampler.io(*eems[0:2], iostandard=iostandard) - + Urukul.io_qspi(*eems[2:4], iostandard=iostandard) - + Urukul.io_qspi(*eems[4:6], iostandard=iostandard)) + assert len(eems) in (4, 6) + io = (Sampler.io(*eems[0:2], iostandard=iostandard) + + Urukul.io_qspi(*eems[2:4], iostandard=iostandard)) + if len(eems) == 6: # two Urukuls + io += Urukul.io_qspi(*eems[4:6], iostandard=iostandard), + return io @classmethod - def add_std(cls, target, eems_sampler, eems_urukul0, eems_urukul1, + def add_std(cls, target, eems_sampler, eems_urukul, t_rtt=4, clk=1, shift=11, profile=5, iostandard="LVDS_25"): """Add a 8-channel Sampler-Urukul Servo @@ -496,15 +498,14 @@ class SUServo(_EEM): (default: 5) """ cls.add_extension( - target, *(eems_sampler + eems_urukul0 + eems_urukul1), + target, *(eems_sampler + sum(eems_urukul, [])), iostandard=iostandard) eem_sampler = "sampler{}".format(eems_sampler[0]) - eem_urukul0 = "urukul{}".format(eems_urukul0[0]) - eem_urukul1 = "urukul{}".format(eems_urukul1[0]) + eem_urukul = ["urukul{}".format(i[0]) for i in eems_urukul] sampler_pads = servo_pads.SamplerPads(target.platform, eem_sampler) urukul_pads = servo_pads.UrukulPads( - target.platform, eem_urukul0, eem_urukul1) + target.platform, *eem_urukul) target.submodules += sampler_pads, urukul_pads # timings in units of RTIO coarse period adc_p = servo.ADCParams(width=16, channels=8, lanes=4, t_cnvh=4, @@ -536,30 +537,24 @@ class SUServo(_EEM): target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - phy = spi2.SPIMaster( - target.platform.request("{}_spi_p".format(eem_urukul0)), - target.platform.request("{}_spi_n".format(eem_urukul0))) - target.submodules += phy - target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + for i in range(2): + if len(eem_urukul) > i: + spi_p, spi_n = ( + target.platform.request("{}_spi_p".format(eem_urukul[i])), + target.platform.request("{}_spi_n".format(eem_urukul[i]))) + else: # create a dummy bus + spi_p = Record([("clk", 1), ("cs_n", 1)]) # mosi, cs_n + spi_n = None - pads = target.platform.request("{}_dds_reset_sync_in".format(eem_urukul0)) - target.specials += DifferentialOutput(0, pads.p, pads.n) + phy = spi2.SPIMaster(spi_p, spi_n) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): - pads = target.platform.request("{}_{}".format(eem_urukul0, signal)) - target.specials += DifferentialOutput( - su.iir.ctrl[i].en_out, pads.p, pads.n) + for j, eem_urukuli in enumerate(eem_urukul): + pads = target.platform.request("{}_dds_reset_sync_in".format(eem_urukuli)) + target.specials += DifferentialOutput(0, pads.p, pads.n) - phy = spi2.SPIMaster( - target.platform.request("{}_spi_p".format(eem_urukul1)), - target.platform.request("{}_spi_n".format(eem_urukul1))) - target.submodules += phy - target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) - - pads = target.platform.request("{}_dds_reset_sync_in".format(eem_urukul1)) - target.specials += DifferentialOutput(0, pads.p, pads.n) - - for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): - pads = target.platform.request("{}_{}".format(eem_urukul1, signal)) - target.specials += DifferentialOutput( - su.iir.ctrl[i + 4].en_out, pads.p, pads.n) + for i, signal in enumerate("sw0 sw1 sw2 sw3".split()): + pads = target.platform.request("{}_{}".format(eem_urukuli, signal)) + target.specials += DifferentialOutput( + su.iir.ctrl[j*4 + i].en_out, pads.p, pads.n) diff --git a/artiq/gateware/suservo/pads.py b/artiq/gateware/suservo/pads.py index 5a9fdba75..0ab7d352f 100644 --- a/artiq/gateware/suservo/pads.py +++ b/artiq/gateware/suservo/pads.py @@ -58,12 +58,12 @@ class SamplerPads(Module): class UrukulPads(Module): - def __init__(self, platform, eem0, eem1): + def __init__(self, platform, *eems): spip, spin = [[ platform.request("{}_qspi_{}".format(eem, pol), 0) - for eem in (eem0, eem1)] for pol in "pn"] + for eem in eems] for pol in "pn"] ioup = [platform.request("{}_io_update".format(eem), 0) - for eem in (eem0, eem1)] + for eem in eems] self.cs_n = Signal() self.clk = Signal() self.io_update = Signal() @@ -71,12 +71,13 @@ class UrukulPads(Module): DifferentialOutput(~self.cs_n, spip[i].cs, spin[i].cs), DifferentialOutput(self.clk, spip[i].clk, spin[i].clk), DifferentialOutput(self.io_update, ioup[i].p, ioup[i].n)) - for i in range(2)] + for i in range(len(eems))] for i in range(8): mosi = Signal() setattr(self, "mosi{}".format(i), mosi) + for i in range(4*len(eems)): self.specials += [ - DifferentialOutput(mosi, + DifferentialOutput(getattr(self, "mosi{}".format(i)), getattr(spip[i // 4], "mosi{}".format(i % 4)), getattr(spin[i // 4], "mosi{}".format(i % 4))) ] diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index 8824e8677..fc6dba19d 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -64,13 +64,17 @@ def peripheral_sampler(module, peripheral): def peripheral_suservo(module, peripheral): if len(peripheral["sampler_ports"]) != 2: raise ValueError("wrong number of Sampler ports") + urukul_ports = [] if len(peripheral["urukul0_ports"]) != 2: raise ValueError("wrong number of Urukul #0 ports") - if len(peripheral["urukul1_ports"]) != 2: - raise ValueError("wrong number of Urukul #1 ports") + urukul_ports.append(peripheral["urukul0_ports"]) + if "urukul1_ports" in peripheral: + if len(peripheral["urukul1_ports"]) != 2: + raise ValueError("wrong number of Urukul #1 ports") + urukul_ports.append(peripheral["urukul1_ports"]) eem.SUServo.add_std(module, peripheral["sampler_ports"], - peripheral["urukul0_ports"], peripheral["urukul1_ports"]) + urukul_ports) def peripheral_zotino(module, peripheral): From 05c5fed07da8ac27352ea0a453156fcdf9dd9783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 3 Dec 2019 08:38:07 +0000 Subject: [PATCH 2028/2457] suservo: stray comma --- artiq/gateware/eem.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index da11fa797..b5e50c0ba 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -474,7 +474,7 @@ class SUServo(_EEM): io = (Sampler.io(*eems[0:2], iostandard=iostandard) + Urukul.io_qspi(*eems[2:4], iostandard=iostandard)) if len(eems) == 6: # two Urukuls - io += Urukul.io_qspi(*eems[4:6], iostandard=iostandard), + io += Urukul.io_qspi(*eems[4:6], iostandard=iostandard) return io @classmethod From 7098854b0f0bf8fb0120aa9c67ee8398efa8fa4a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 4 Dec 2019 19:05:56 +0800 Subject: [PATCH 2029/2457] wrpll: share DDMTD counter --- artiq/gateware/drtio/wrpll/core.py | 6 ++++-- artiq/gateware/drtio/wrpll/ddmtd.py | 18 ++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index ee2099648..81527ae58 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -21,5 +21,7 @@ class WRPLL(Module, AutoCSR): self.submodules.main_dcxo = Si549(main_dcxo_i2c) self.submodules.helper_dcxo = Si549(helper_dxco_i2c) - self.submodules.ddmtd_helper = DDMTD(N, ddmtd_inputs.rec_clk) - self.submodules.ddmtd_main = DDMTD(N, ddmtd_inputs.main_xo) + ddmtd_counter = Signal(N) + self.sync.helper += ddmtd_counter.eq(ddmtd_counter + 1) + self.submodules.ddmtd_helper = DDMTD(ddmtd_counter, ddmtd_inputs.rec_clk) + self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_inputs.main_xo) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index 3708371b5..d05d0445b 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -4,13 +4,13 @@ from misoc.interconnect.csr import * class DDMTDEdgeDetector(Module): - def __init__(self, i): + def __init__(self, input_signal): self.rising = Signal() history = Signal(4) deglitched = Signal() - self.sync.helper += history.eq(Cat(history[1:], i)) - self.comb += deglitched.eq(i | history[0] | history[1] | history[2] | history[3]) + self.sync.helper += history.eq(Cat(history[1:], input_signal)) + self.comb += deglitched.eq(input_signal | history[0] | history[1] | history[2] | history[3]) deglitched_r = Signal() self.sync.helper += [ @@ -20,22 +20,20 @@ class DDMTDEdgeDetector(Module): class DDMTD(Module, AutoCSR): - def __init__(self, N, i): + def __init__(self, counter, input_signal): self.arm = CSR() - self.tag = CSRStatus(N) + self.tag = CSRStatus(len(counter)) # in helper clock domain - self.h_tag = Signal(N) + self.h_tag = Signal(len(counter)) self.h_tag_update = Signal() # # # - ed = DDMTDEdgeDetector(i) + ed = DDMTDEdgeDetector(input_signal) self.submodules += ed - counter = Signal(N) self.sync.helper += [ - counter.eq(counter + 1), self.h_tag_update.eq(0), If(ed.rising, self.h_tag_update.eq(1), @@ -49,7 +47,7 @@ class DDMTD(Module, AutoCSR): tag_update = Signal() self.sync += tag_update.eq(tag_update_ps.o) - tag = Signal(N) + tag = Signal(len(counter)) self.h_tag.attr.add("no_retiming") self.specials += MultiReg(self.h_tag, tag) From 14e250c78f0306a9aac87ad9f9e6e6b1e8d60fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kulik?= Date: Fri, 6 Dec 2019 15:41:19 +0100 Subject: [PATCH 2030/2457] Enabled internal pullup for CML SYSREF outputs, otherwise there is no signal on them. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paweł Kulik --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index a3e2cf337..2c34f9f0d 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -150,9 +150,9 @@ pub mod hmc7043 { // enabled, divider, output config, is sysref const OUTPUT_CONFIG: [(bool, u16, u8, bool); 14] = [ (true, DAC_CLK_DIV, 0x08, false), // 0: DAC1_CLK - (true, SYSREF_DIV, 0x00, true), // 1: DAC1_SYSREF + (true, SYSREF_DIV, 0x01, true), // 1: DAC1_SYSREF (true, DAC_CLK_DIV, 0x08, false), // 2: DAC0_CLK - (true, SYSREF_DIV, 0x00, true), // 3: DAC0_SYSREF + (true, SYSREF_DIV, 0x01, true), // 3: DAC0_SYSREF (true, SYSREF_DIV, 0x10, true), // 4: AMC_FPGA_SYSREF0 (true, FPGA_CLK_DIV, 0x10, true), // 5: AMC_FPGA_SYSREF1 (false, 0, 0x10, false), // 6: unused From 3851a02a3a7b8b32e9ce5f0800a2acb66051b75d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kulik?= Date: Fri, 6 Dec 2019 15:37:50 +0100 Subject: [PATCH 2031/2457] Added option of flashing only RTM gateware. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paweł Kulik --- artiq/frontend/artiq_flash.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 516f0493d..7a59993da 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -26,6 +26,7 @@ def get_argparser(): Valid actions: * gateware: write gateware bitstream to flash + * rtm_gateware: write RTM board gateware bitstream to flash * bootloader: write bootloader to flash * storage: write storage image to flash * firmware: write firmware to flash @@ -340,7 +341,7 @@ def main(): bin_dir = os.path.join(artiq_dir, "board-support") needs_artifacts = any(action in args.action - for action in ["gateware", "bootloader", "firmware", "load"]) + for action in ["gateware", "bootloader", "firmware", "load", "rtm_gateware"]) variant = args.variant if needs_artifacts and variant is None: variants = [] @@ -419,6 +420,14 @@ def main(): artifact_path(rtm_variant_dir, "gateware", "top.bit"), header=True) programmer.write_binary(*config["rtm_gateware"], rtm_gateware_bin) + elif action == "rtm_gateware": + if args.target == "sayma" and variant != "simplesatellite" and variant != "master": + rtm_gateware_bin = convert_gateware( + artifact_path(rtm_variant_dir, "gateware", "top.bit"), header=True) + programmer.write_binary(*config["rtm_gateware"], + rtm_gateware_bin) + else: + raise ValueError("No RTM board for this board and variant.") elif action == "bootloader": bootloader_bin = artifact_path(variant_dir, "software", "bootloader", "bootloader.bin") programmer.write_binary(*config["bootloader"], bootloader_bin) From da9237de53ff5de0b56714abf39688af5fe95884 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 7 Dec 2019 18:18:57 +0800 Subject: [PATCH 2032/2457] wrpll: support differential DDMTD inputs --- artiq/gateware/drtio/wrpll/core.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 81527ae58..6465c004b 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -23,5 +23,19 @@ class WRPLL(Module, AutoCSR): ddmtd_counter = Signal(N) self.sync.helper += ddmtd_counter.eq(ddmtd_counter + 1) - self.submodules.ddmtd_helper = DDMTD(ddmtd_counter, ddmtd_inputs.rec_clk) - self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_inputs.main_xo) + if hasattr(ddmtd_inputs, "rec_clk"): + ddmtd_input_rec_clk = ddmtd_inputs.rec_clk + else: + ddmtd_input_rec_clk = Signal() + self.specials += Instance("IBUFDS", + i_I=ddmtd_inputs.rec_clk_p, i_IB=ddmtd_inputs.rec_clk_n, + o_O=ddmtd_input_rec_clk) + if hasattr(ddmtd_inputs, "main_xo"): + ddmtd_input_main_xo = ddmtd_inputs.main_xo + else: + ddmtd_input_main_xo = Signal() + self.specials += Instance("IBUFDS", + i_I=ddmtd_inputs.main_xo_p, i_IB=ddmtd_inputs.main_xo_n, + o_O=ddmtd_input_main_xo) + self.submodules.ddmtd_helper = DDMTD(ddmtd_counter, ddmtd_input_rec_clk) + self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_input_main_xo) From 57a5bea43ae301bba21b41f7bf88fcdfa125e489 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 8 Dec 2019 11:44:42 +0800 Subject: [PATCH 2033/2457] sayma_rtm: support setting RTIO frequency --- artiq/gateware/targets/sayma_rtm.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 02a3afe42..9e269a6c2 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -73,7 +73,7 @@ class _SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, rtio_clk_freq=150e6, **kwargs): + def __init__(self, rtio_clk_freq, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", **kwargs) @@ -207,7 +207,7 @@ class Satellite(_SatelliteBase): self.config["CONVERTER_SPI_HMC830_CS"] = 0 self.config["CONVERTER_SPI_HMC7043_CS"] = 1 self.config["CONVERTER_SPI_FIRST_AD9154_CS"] = 2 - self.config["HMC830_REF"] = "150" + self.config["HMC830_REF"] = str(int(self.rtio_clk_freq/1e6)) # HMC workarounds self.comb += platform.request("hmc830_pwr_en").eq(1) @@ -243,10 +243,13 @@ def main(): description="Sayma RTM gateware and firmware builder") builder_args(parser) soc_sayma_rtm_args(parser) + parser.add_argument("--rtio-clk-freq", + default=150, type=int, help="RTIO clock frequency in MHz") parser.set_defaults(output_dir=os.path.join("artiq_sayma", "rtm")) args = parser.parse_args() - soc = Satellite(**soc_sayma_rtm_argdict(args)) + soc = Satellite(rtio_clk_freq=1e6*args.rtio_clk_freq, + **soc_sayma_rtm_argdict(args)) builder = SatmanSoCBuilder(soc, **builder_argdict(args)) try: builder.build() From 883310d83ea645fd8254be11f5e527069b9e408d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 8 Dec 2019 14:26:05 +0800 Subject: [PATCH 2034/2457] sayma_rtm: si5324 -> cdrclkc --- artiq/gateware/targets/sayma_rtm.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 9e269a6c2..d7dc3d207 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -82,20 +82,20 @@ class _SatelliteBase(BaseSoC): platform = self.platform - disable_si5324_ibuf = Signal(reset=1) - disable_si5324_ibuf.attr.add("no_retiming") - si5324_clkout = platform.request("cdr_clk_clean") - si5324_clkout_buf = Signal() + disable_cdrclkc_ibuf = Signal(reset=1) + disable_cdrclkc_ibuf.attr.add("no_retiming") + cdrclkc_clkout = platform.request("cdr_clk_clean") + cdrclkc_clkout_buf = Signal() self.specials += Instance("IBUFDS_GTE2", - i_CEB=disable_si5324_ibuf, - i_I=si5324_clkout.p, i_IB=si5324_clkout.n, - o_O=si5324_clkout_buf) + i_CEB=disable_cdrclkc_ibuf, + i_I=cdrclkc_clkout.p, i_IB=cdrclkc_clkout.n, + o_O=cdrclkc_clkout_buf) qpll_drtio_settings = QPLLSettings( refclksel=0b001, fbdiv=4, fbdiv_45=5, refclk_div=1) - qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings) + qpll = QPLL(cdrclkc_clkout_buf, qpll_drtio_settings) self.submodules += qpll self.submodules.drtio_transceiver = gtp_7series.GTP( @@ -104,7 +104,7 @@ class _SatelliteBase(BaseSoC): sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") - self.sync += disable_si5324_ibuf.eq( + self.sync += disable_cdrclkc_ibuf.eq( ~self.drtio_transceiver.stable_clkin.storage) self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) From bcd061f141c481c8d077ecab9c8ba08feb754a2d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 8 Dec 2019 15:12:04 +0800 Subject: [PATCH 2035/2457] artiq_flash: RTM is a regular DRTIO satellite, can be used with all variants --- artiq/frontend/artiq_flash.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 7a59993da..6592270b0 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -421,13 +421,13 @@ def main(): programmer.write_binary(*config["rtm_gateware"], rtm_gateware_bin) elif action == "rtm_gateware": - if args.target == "sayma" and variant != "simplesatellite" and variant != "master": + if args.target == "sayma": rtm_gateware_bin = convert_gateware( artifact_path(rtm_variant_dir, "gateware", "top.bit"), header=True) programmer.write_binary(*config["rtm_gateware"], rtm_gateware_bin) else: - raise ValueError("No RTM board for this board and variant.") + raise ValueError("No RTM for this board") elif action == "bootloader": bootloader_bin = artifact_path(variant_dir, "software", "bootloader", "bootloader.bin") programmer.write_binary(*config["bootloader"], bootloader_bin) From f35f658bc544ff15ba1c31df89461ba92d4837b5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 8 Dec 2019 15:29:31 +0800 Subject: [PATCH 2036/2457] artiq_flash: rework RTM management --- artiq/frontend/artiq_flash.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 6592270b0..40679c492 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -71,8 +71,10 @@ Prerequisites: parser.add_argument("-d", "--dir", help="look for board binaries in this directory") parser.add_argument("--srcbuild", help="board binaries directory is laid out as a source build tree", default=False, action="store_true") + parser.add_argument("--force-rtm", help="force RTM actions on boards/variants that normally do not have a RTM", + default=False, action="store_true") parser.add_argument("action", metavar="ACTION", nargs="*", - default="gateware bootloader firmware start".split(), + default="gateware rtm_gateware bootloader firmware start".split(), help="actions to perform, default: %(default)s") return parser @@ -340,8 +342,9 @@ def main(): if bin_dir is None: bin_dir = os.path.join(artiq_dir, "board-support") - needs_artifacts = any(action in args.action - for action in ["gateware", "bootloader", "firmware", "load", "rtm_gateware"]) + needs_artifacts = any( + action in args.action + for action in ["gateware", "rtm_gateware", "bootloader", "firmware", "load", "rtm_load"]) variant = args.variant if needs_artifacts and variant is None: variants = [] @@ -415,19 +418,13 @@ def main(): gateware_bin = convert_gateware( artifact_path(variant_dir, "gateware", "top.bit")) programmer.write_binary(*config["gateware"], gateware_bin) - if args.target == "sayma" and variant != "simplesatellite" and variant != "master": - rtm_gateware_bin = convert_gateware( - artifact_path(rtm_variant_dir, "gateware", "top.bit"), header=True) - programmer.write_binary(*config["rtm_gateware"], - rtm_gateware_bin) elif action == "rtm_gateware": - if args.target == "sayma": + if args.force_rtm or ( + args.target == "sayma" and variant != "simplesatellite" and variant != "master"): rtm_gateware_bin = convert_gateware( artifact_path(rtm_variant_dir, "gateware", "top.bit"), header=True) programmer.write_binary(*config["rtm_gateware"], rtm_gateware_bin) - else: - raise ValueError("No RTM for this board") elif action == "bootloader": bootloader_bin = artifact_path(variant_dir, "software", "bootloader", "bootloader.bin") programmer.write_binary(*config["bootloader"], bootloader_bin) @@ -444,14 +441,16 @@ def main(): programmer.write_binary(*config["firmware"], firmware_fbi) elif action == "load": if args.target == "sayma": - if variant != "simplesatellite" and variant != "master": - rtm_gateware_bit = artifact_path(rtm_variant_dir, "gateware", "top.bit") - programmer.load(rtm_gateware_bit, 0) gateware_bit = artifact_path(variant_dir, "gateware", "top.bit") programmer.load(gateware_bit, 1) else: gateware_bit = artifact_path(variant_dir, "gateware", "top.bit") programmer.load(gateware_bit, 0) + elif action == "rtm_load": + if args.force_rtm or ( + args.target == "sayma" and variant != "simplesatellite" and variant != "master"): + rtm_gateware_bit = artifact_path(rtm_variant_dir, "gateware", "top.bit") + programmer.load(rtm_gateware_bit, 0) elif action == "start": programmer.start() elif action == "erase": From 46a776d06e86fa57f34b948fa7cadf5664f7087b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 8 Dec 2019 15:30:00 +0800 Subject: [PATCH 2037/2457] sayma: introduce WRPLL on RTM --- artiq/gateware/drtio/wrpll/__init__.py | 1 + artiq/gateware/drtio/wrpll/core.py | 18 +-------- artiq/gateware/drtio/wrpll/ddmtd.py | 41 ++++++++++++++++++++ artiq/gateware/targets/sayma_amc.py | 6 ++- artiq/gateware/targets/sayma_rtm.py | 53 +++++++++++++++++--------- 5 files changed, 84 insertions(+), 35 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/__init__.py b/artiq/gateware/drtio/wrpll/__init__.py index d004bc955..25e510f4c 100644 --- a/artiq/gateware/drtio/wrpll/__init__.py +++ b/artiq/gateware/drtio/wrpll/__init__.py @@ -1 +1,2 @@ from artiq.gateware.drtio.wrpll.core import WRPLL +from artiq.gateware.drtio.wrpll.ddmtd import DDMTDSamplerExtFF, DDMTDSamplerGTP diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 6465c004b..81527ae58 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -23,19 +23,5 @@ class WRPLL(Module, AutoCSR): ddmtd_counter = Signal(N) self.sync.helper += ddmtd_counter.eq(ddmtd_counter + 1) - if hasattr(ddmtd_inputs, "rec_clk"): - ddmtd_input_rec_clk = ddmtd_inputs.rec_clk - else: - ddmtd_input_rec_clk = Signal() - self.specials += Instance("IBUFDS", - i_I=ddmtd_inputs.rec_clk_p, i_IB=ddmtd_inputs.rec_clk_n, - o_O=ddmtd_input_rec_clk) - if hasattr(ddmtd_inputs, "main_xo"): - ddmtd_input_main_xo = ddmtd_inputs.main_xo - else: - ddmtd_input_main_xo = Signal() - self.specials += Instance("IBUFDS", - i_I=ddmtd_inputs.main_xo_p, i_IB=ddmtd_inputs.main_xo_n, - o_O=ddmtd_input_main_xo) - self.submodules.ddmtd_helper = DDMTD(ddmtd_counter, ddmtd_input_rec_clk) - self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_input_main_xo) + self.submodules.ddmtd_helper = DDMTD(ddmtd_counter, ddmtd_inputs.rec_clk) + self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_inputs.main_xo) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index d05d0445b..d5a35a70f 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -3,6 +3,47 @@ from migen.genlib.cdc import PulseSynchronizer, MultiReg from misoc.interconnect.csr import * +class DDMTDSamplerExtFF(Module): + def __init__(self, ddmtd_inputs): + # TODO: s/h timing at FPGA pads + if hasattr(ddmtd_inputs, "rec_clk"): + self.rec_clk = ddmtd_inputs.rec_clk + else: + self.rec_clk = Signal() + self.specials += Instance("IBUFDS", + i_I=ddmtd_inputs.rec_clk_p, i_IB=ddmtd_inputs.rec_clk_n, + o_O=self.rec_clk) + if hasattr(ddmtd_inputs, "main_xo"): + self.main_xo = ddmtd_inputs.main_xo + else: + self.main_xo = Signal() + self.specials += Instance("IBUFDS", + i_I=ddmtd_inputs.main_xo_p, i_IB=ddmtd_inputs.main_xo_n, + o_O=self.main_xo) + + +class DDMTDSamplerGTP(Module): + def __init__(self, gtp, main_xo_pads): + self.rec_clk = Signal() + self.main_xo = Signal() + + # Getting this signal from IBUFDS_GTE2 is problematic because: + # 1. the clock gets divided by 2 + # 2. the transceiver PLL craps out if an improper clock signal is applied, + # so we are disabling the buffer until the clock is stable. + # 3. UG482 says "The O and ODIV2 outputs are not phase matched to each other", + # which may or may not be a problem depending on what it actually means. + main_xo_se = Signal() + self.specials += Instance("IBUFDS", + i_I=main_xo_pads.p, i_IB=main_xo_pads.n, + o_O=main_xo_se) + + self.sync.helper += [ + self.rec_clk.eq(gtp.cd_rtio_rx0.clk), + self.main_xo.eq(main_xo_se) + ] + + class DDMTDEdgeDetector(Module): def __init__(self, input_signal): self.rising = Signal() diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 6cb234f51..d90142cbc 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -19,7 +19,7 @@ from artiq.gateware import jesd204_tools from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_ultrascale, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale from artiq.gateware.drtio.siphaser import SiPhaser7Series -from artiq.gateware.drtio.wrpll import WRPLL +from artiq.gateware.drtio.wrpll import WRPLL, DDMTDSamplerExtFF from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import * from artiq.build_soc import * @@ -136,11 +136,13 @@ class SatelliteBase(MiniSoC): platform.request("ddmtd_main_dcxo_oe").eq(1), platform.request("ddmtd_helper_dcxo_oe").eq(1) ] + self.submodules.wrpll_sampler = DDMTDSamplerExtFF( + platform.request("ddmtd_inputs")) self.submodules.wrpll = WRPLL( helper_clk_pads=platform.request("ddmtd_helper_clk"), main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"), - ddmtd_inputs=platform.request("ddmtd_inputs")) + ddmtd_inputs=self.wrpll_sampler) self.csr_devices.append("wrpll") else: self.comb += platform.request("filtered_clk_sel").eq(1) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index d7dc3d207..29ac40779 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -19,6 +19,7 @@ from artiq.gateware import rtio from artiq.gateware.rtio.phy import ttl_serdes_7series from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series +from artiq.gateware.drtio.wrpll import WRPLL, DDMTDSamplerGTP from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import * from artiq.build_soc import add_identifier @@ -73,7 +74,7 @@ class _SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, rtio_clk_freq, **kwargs): + def __init__(self, rtio_clk_freq, *, with_wrpll, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", **kwargs) @@ -132,21 +133,37 @@ class _SatelliteBase(BaseSoC): self.add_memory_group("drtioaux_mem", ["drtioaux0_mem"]) self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - self.comb += platform.request("filtered_clk_sel").eq(1) - self.submodules.siphaser = SiPhaser7Series( - si5324_clkin=platform.request("si5324_clkin"), - rx_synchronizer=self.rx_synchronizer, - ref_clk=self.crg.cd_sys.clk, ref_div2=True, - rtio_clk_freq=rtio_clk_freq) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) - self.csr_devices.append("siphaser") - i2c = self.platform.request("i2c") - self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) - self.csr_devices.append("i2c") - self.config["I2C_BUS_COUNT"] = 1 - self.config["HAS_SI5324"] = None - self.config["SI5324_SOFT_RESET"] = None + if with_wrpll: + self.comb += [ + platform.request("filtered_clk_sel").eq(0), + platform.request("ddmtd_main_dcxo_oe").eq(1), + platform.request("ddmtd_helper_dcxo_oe").eq(1) + ] + self.submodules.wrpll_sampler = DDMTDSamplerGTP( + self.drtio_transceiver, + platform.request("cdr_clk_clean_fabric")) + self.submodules.wrpll = WRPLL( + helper_clk_pads=platform.request("ddmtd_helper_clk"), + main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), + helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"), + ddmtd_inputs=self.wrpll_sampler) + self.csr_devices.append("wrpll") + else: + self.comb += platform.request("filtered_clk_sel").eq(1) + self.submodules.siphaser = SiPhaser7Series( + si5324_clkin=platform.request("si5324_clkin"), + rx_synchronizer=self.rx_synchronizer, + ref_clk=self.crg.cd_sys.clk, ref_div2=True, + rtio_clk_freq=rtio_clk_freq) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) + self.csr_devices.append("siphaser") + i2c = self.platform.request("i2c") + self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) + self.csr_devices.append("i2c") + self.config["I2C_BUS_COUNT"] = 1 + self.config["HAS_SI5324"] = None + self.config["SI5324_SOFT_RESET"] = None rtio_clk_period = 1e9/rtio_clk_freq gtp = self.drtio_transceiver.gtps[0] @@ -245,10 +262,12 @@ def main(): soc_sayma_rtm_args(parser) parser.add_argument("--rtio-clk-freq", default=150, type=int, help="RTIO clock frequency in MHz") + parser.add_argument("--with-wrpll", default=False, action="store_true") parser.set_defaults(output_dir=os.path.join("artiq_sayma", "rtm")) args = parser.parse_args() - soc = Satellite(rtio_clk_freq=1e6*args.rtio_clk_freq, + soc = Satellite( + rtio_clk_freq=1e6*args.rtio_clk_freq, with_wrpll=args.with_wrpll, **soc_sayma_rtm_argdict(args)) builder = SatmanSoCBuilder(soc, **builder_argdict(args)) try: From 0499f83580c6fb65117fb73f4360d0868929e37c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 8 Dec 2019 23:46:33 +0800 Subject: [PATCH 2038/2457] wrpll: helper clock sanity check --- artiq/firmware/libboard_artiq/wrpll.rs | 11 +++++++++ artiq/gateware/drtio/wrpll/core.py | 32 ++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 84c34b67e..3e554064c 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -264,6 +264,14 @@ mod si549 { } } +fn get_helper_frequency() -> u32 { + unsafe { csr::wrpll::helper_frequency_start_write(1); } + clock::spin_us(10_000); + unsafe { csr::wrpll::helper_frequency_stop_write(1); } + clock::spin_us(1); + unsafe { csr::wrpll::helper_frequency_counter_read() } +} + pub fn init() { info!("initializing..."); @@ -281,6 +289,9 @@ pub fn init() { clock::spin_us(10_000); // Settling Time after FS Change unsafe { csr::wrpll::helper_reset_write(0); } + clock::spin_us(1); + + info!("helper clock frequency: {}MHz", get_helper_frequency()/10000); info!("DDMTD test:"); for _ in 0..20 { diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 81527ae58..37467008a 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -1,11 +1,41 @@ from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.cdc import MultiReg, PulseSynchronizer from misoc.interconnect.csr import * from artiq.gateware.drtio.wrpll.si549 import Si549 from artiq.gateware.drtio.wrpll.ddmtd import DDMTD +class FrequencyCounter(Module, AutoCSR): + def __init__(self): + self.counter = CSRStatus(32) + self.start = CSR() + self.stop = CSR() + + ps_start = PulseSynchronizer("sys", "helper") + ps_stop = PulseSynchronizer("sys", "helper") + self.submodules += ps_start, ps_stop + + self.comb += [ + ps_start.i.eq(self.start.re & self.start.r), + ps_stop.i.eq(self.stop.re & self.stop.r) + ] + + counter = Signal(32) + self.specials += MultiReg(counter, self.counter.status) + + counting = Signal() + self.sync.helper += [ + If(counting, counter.eq(counter + 1)), + If(ps_start.o, + counter.eq(0), + counting.eq(1) + ), + If(ps_stop.o, counting.eq(0)) + ] + + class WRPLL(Module, AutoCSR): def __init__(self, helper_clk_pads, main_dcxo_i2c, helper_dxco_i2c, ddmtd_inputs, N=15): self.helper_reset = CSRStorage(reset=1) @@ -21,6 +51,8 @@ class WRPLL(Module, AutoCSR): self.submodules.main_dcxo = Si549(main_dcxo_i2c) self.submodules.helper_dcxo = Si549(helper_dxco_i2c) + self.submodules.helper_frequency = FrequencyCounter() + ddmtd_counter = Signal(N) self.sync.helper += ddmtd_counter.eq(ddmtd_counter + 1) self.submodules.ddmtd_helper = DDMTD(ddmtd_counter, ddmtd_inputs.rec_clk) From d43fe644f09904ff0a0c37f31d0e4192aa2943f2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Dec 2019 11:47:14 +0800 Subject: [PATCH 2039/2457] wrpll: stabilize DDMTDSamplerGTP --- artiq/gateware/drtio/wrpll/ddmtd.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index d5a35a70f..d5270de0d 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -27,20 +27,23 @@ class DDMTDSamplerGTP(Module): self.rec_clk = Signal() self.main_xo = Signal() - # Getting this signal from IBUFDS_GTE2 is problematic because: + # Getting the main XO signal from IBUFDS_GTE2 is problematic because: # 1. the clock gets divided by 2 # 2. the transceiver PLL craps out if an improper clock signal is applied, # so we are disabling the buffer until the clock is stable. # 3. UG482 says "The O and ODIV2 outputs are not phase matched to each other", # which may or may not be a problem depending on what it actually means. main_xo_se = Signal() - self.specials += Instance("IBUFDS", - i_I=main_xo_pads.p, i_IB=main_xo_pads.n, - o_O=main_xo_se) - - self.sync.helper += [ - self.rec_clk.eq(gtp.cd_rtio_rx0.clk), - self.main_xo.eq(main_xo_se) + self.specials += [ + Instance("IBUFDS", + i_I=main_xo_pads.p, i_IB=main_xo_pads.n, + o_O=main_xo_se), + Instance("FD", i_C=ClockSignal("helper"), + i_D=gtp.cd_rtio_rx0.clk, o_Q=self.rec_clk, + attr={("DONT_TOUCH", "TRUE")}), + Instance("FD", i_C=ClockSignal("helper"), + i_D=main_xo_se, o_Q=self.main_xo, + attr={("IOB", "TRUE")}), ] From 4148efd2eeea9da4aaca271d4603128529ab4838 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Dec 2019 11:47:29 +0800 Subject: [PATCH 2040/2457] wrpll: implement filters and connect to Si549 --- artiq/gateware/drtio/wrpll/core.py | 15 +++++++++++++-- artiq/gateware/drtio/wrpll/thls.py | 7 +++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 37467008a..35902d752 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -5,6 +5,7 @@ from misoc.interconnect.csr import * from artiq.gateware.drtio.wrpll.si549 import Si549 from artiq.gateware.drtio.wrpll.ddmtd import DDMTD +from artiq.gateware.drtio.wrpll import thls, filters class FrequencyCounter(Module, AutoCSR): @@ -48,12 +49,22 @@ class WRPLL(Module, AutoCSR): AsyncResetSynchronizer(self.cd_helper, self.helper_reset.storage) ] - self.submodules.main_dcxo = Si549(main_dcxo_i2c) self.submodules.helper_dcxo = Si549(helper_dxco_i2c) + self.submodules.main_dcxo = Si549(main_dcxo_i2c) - self.submodules.helper_frequency = FrequencyCounter() + self.submodules.helper_frequency = FrequencyCounter() # for diagnostics ddmtd_counter = Signal(N) self.sync.helper += ddmtd_counter.eq(ddmtd_counter + 1) self.submodules.ddmtd_helper = DDMTD(ddmtd_counter, ddmtd_inputs.rec_clk) self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_inputs.main_xo) + + helper_cd = ClockDomainsRenamer("helper") + self.submodules.filter_helper = helper_cd(thls.make(filters.helper, data_width=48)) + self.submodules.filter_main = helper_cd(thls.make(filters.main, data_width=48)) + self.comb += [ + self.helper_dcxo.adpll_stb.eq(self.filter_helper.output_stb), + self.helper_dcxo.adpll.eq(self.filter_helper.output), + self.main_dcxo.adpll_stb.eq(self.filter_main.output_stb), + self.main_dcxo.adpll.eq(self.filter_main.output) + ] diff --git a/artiq/gateware/drtio/wrpll/thls.py b/artiq/gateware/drtio/wrpll/thls.py index 3f5aa6425..6d2509c63 100644 --- a/artiq/gateware/drtio/wrpll/thls.py +++ b/artiq/gateware/drtio/wrpll/thls.py @@ -589,6 +589,13 @@ class ProcessorImpl(Module): ) +def make(function, **kwargs): + proc = Processor(**kwargs) + cp = compile(proc, simple_test) + cp.dimension_processor() + return proc.implement(cp.encode(), cp.data) + + a = 0 b = 0 c = 0 From 05e2e1899a6e12e0c705a29306339dae5046aa82 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Dec 2019 11:57:33 +0800 Subject: [PATCH 2041/2457] wrpll: update OBUFDS_GTE2 comment Seems O can fan out simultaneously to transceiver and fabric. Kasli is using ODIV2 for no particular reason. --- artiq/gateware/drtio/wrpll/ddmtd.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index d5270de0d..6068b4dec 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -27,12 +27,9 @@ class DDMTDSamplerGTP(Module): self.rec_clk = Signal() self.main_xo = Signal() - # Getting the main XO signal from IBUFDS_GTE2 is problematic because: - # 1. the clock gets divided by 2 - # 2. the transceiver PLL craps out if an improper clock signal is applied, + # Getting the main XO signal from IBUFDS_GTE2 is problematic because + # the transceiver PLL craps out if an improper clock signal is applied, # so we are disabling the buffer until the clock is stable. - # 3. UG482 says "The O and ODIV2 outputs are not phase matched to each other", - # which may or may not be a problem depending on what it actually means. main_xo_se = Signal() self.specials += [ Instance("IBUFDS", From 2b5213b0130b4a0639554cef46da3903560f63b1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Dec 2019 12:26:44 +0800 Subject: [PATCH 2042/2457] wrpll: constrain clocks --- artiq/gateware/targets/sayma_amc.py | 4 +++- artiq/gateware/targets/sayma_rtm.py | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index d90142cbc..e75c6d67a 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -129,6 +129,7 @@ class SatelliteBase(MiniSoC): self.add_memory_group("drtioaux_mem", drtioaux_memory_group) self.add_csr_group("drtiorep", drtiorep_csr_group) + rtio_clk_period = 1e9/rtio_clk_freq self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) if with_wrpll: self.comb += [ @@ -144,6 +145,8 @@ class SatelliteBase(MiniSoC): helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"), ddmtd_inputs=self.wrpll_sampler) self.csr_devices.append("wrpll") + platform.add_period_constraint(self.wrpll.cd_helper.clk, rtio_clk_period*0.99) + platform.add_false_path_constraints(self.crg.cd_sys.clk, self.wrpll.cd_helper.clk) else: self.comb += platform.request("filtered_clk_sel").eq(1) self.submodules.siphaser = SiPhaser7Series( @@ -162,7 +165,6 @@ class SatelliteBase(MiniSoC): self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None - rtio_clk_period = 1e9/rtio_clk_freq gth = self.drtio_transceiver.gths[0] platform.add_period_constraint(gth.txoutclk, rtio_clk_period/2) platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 29ac40779..0c67ce437 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -132,6 +132,8 @@ class _SatelliteBase(BaseSoC): self.add_csr_group("drtioaux", ["drtioaux0"]) self.add_memory_group("drtioaux_mem", ["drtioaux0_mem"]) + gtp = self.drtio_transceiver.gtps[0] + rtio_clk_period = 1e9/rtio_clk_freq self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) if with_wrpll: self.comb += [ @@ -148,6 +150,9 @@ class _SatelliteBase(BaseSoC): helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"), ddmtd_inputs=self.wrpll_sampler) self.csr_devices.append("wrpll") + platform.add_period_constraint(self.wrpll.cd_helper.clk, rtio_clk_period*0.99) + platform.add_false_path_constraints(self.crg.cd_sys.clk, self.wrpll.cd_helper.clk) + platform.add_false_path_constraints(self.wrpll.cd_helper.clk, gtp.rxoutclk) else: self.comb += platform.request("filtered_clk_sel").eq(1) self.submodules.siphaser = SiPhaser7Series( @@ -165,8 +170,6 @@ class _SatelliteBase(BaseSoC): self.config["HAS_SI5324"] = None self.config["SI5324_SOFT_RESET"] = None - rtio_clk_period = 1e9/rtio_clk_freq - gtp = self.drtio_transceiver.gtps[0] platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( From 439576f59d0cda819c704df00a6d61c1b688538a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Dec 2019 16:13:57 +0800 Subject: [PATCH 2043/2457] wrpll: fix Si549 initialization delays --- artiq/firmware/libboard_artiq/wrpll.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 3e554064c..530259656 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -230,7 +230,7 @@ mod si549 { write(dcxo, 255, 0x00)?; // PAGE write_no_ack_value(dcxo, 7, 0x80)?; // RESET - clock::spin_us(50_000); // required? not specified in datasheet. + clock::spin_us(100_000); // required? not specified in datasheet. write(dcxo, 255, 0x00)?; // PAGE write(dcxo, 69, 0x00)?; // Disable FCAL override. @@ -287,7 +287,9 @@ pub fn init() { si549::program(i2c::Dcxo::Helper, h_hsdiv, h_lsdiv, h_fbdiv) .expect("cannot initialize helper Si549"); - clock::spin_us(10_000); // Settling Time after FS Change + // Si549 Settling Time for Large Frequency Change. + // Datasheet said 10ms but it lied. + clock::spin_us(50_000); unsafe { csr::wrpll::helper_reset_write(0); } clock::spin_us(1); From 14e09582b6ea141624d3f50d85498d4590f55c7c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Dec 2019 16:20:08 +0800 Subject: [PATCH 2044/2457] wrpll: work around si549 not working when lsdiv=2 --- artiq/firmware/libboard_artiq/wrpll.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 530259656..826a643aa 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -278,9 +278,9 @@ pub fn init() { unsafe { csr::wrpll::helper_reset_write(1); } #[cfg(rtio_frequency = "125.0")] - let (m_hsdiv, m_lsdiv, m_fbdiv) = (0x017, 2, 0x04b5badb98a); + let (m_hsdiv, m_lsdiv, m_fbdiv) = (0x05c, 0, 0x04b5badb98a); #[cfg(rtio_frequency = "125.0")] - let (h_hsdiv, h_lsdiv, h_fbdiv) = (0x017, 2, 0x04b5c447213); + let (h_hsdiv, h_lsdiv, h_fbdiv) = (0x05c, 0, 0x04b5c447213); si549::program(i2c::Dcxo::Main, m_hsdiv, m_lsdiv, m_fbdiv) .expect("cannot initialize main Si549"); From f633c62e8d2df46659174c5f6672011a0e3b4400 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Dec 2019 17:22:58 +0800 Subject: [PATCH 2045/2457] wrpll: speed up si549 i2c access --- artiq/firmware/libboard_artiq/wrpll.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 826a643aa..22072f403 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -9,7 +9,7 @@ mod i2c { Helper } - fn half_period() { clock::spin_us(10) } + fn half_period() { clock::spin_us(1) } const SDA_MASK: u8 = 2; const SCL_MASK: u8 = 1; From 0d4eccc1a5f5a48d27c00c4011ea92e181eceb59 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Dec 2019 17:23:09 +0800 Subject: [PATCH 2046/2457] wrpll: improve debug output --- artiq/firmware/libboard_artiq/wrpll.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 22072f403..1a528afeb 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -272,6 +272,14 @@ fn get_helper_frequency() -> u32 { unsafe { csr::wrpll::helper_frequency_counter_read() } } +fn get_ddmtd_main_tag() -> u16 { + unsafe { + csr::wrpll::ddmtd_main_arm_write(1); + while csr::wrpll::ddmtd_main_arm_read() != 0 {} + csr::wrpll::ddmtd_main_tag_read() + } +} + pub fn init() { info!("initializing..."); @@ -286,23 +294,19 @@ pub fn init() { .expect("cannot initialize main Si549"); si549::program(i2c::Dcxo::Helper, h_hsdiv, h_lsdiv, h_fbdiv) .expect("cannot initialize helper Si549"); - // Si549 Settling Time for Large Frequency Change. // Datasheet said 10ms but it lied. clock::spin_us(50_000); + unsafe { csr::wrpll::helper_reset_write(0); } clock::spin_us(1); info!("helper clock frequency: {}MHz", get_helper_frequency()/10000); - - info!("DDMTD test:"); - for _ in 0..20 { - unsafe { - csr::wrpll::ddmtd_main_arm_write(1); - while csr::wrpll::ddmtd_main_arm_read() != 0 {} - info!("{}", csr::wrpll::ddmtd_main_tag_read()); - } + let mut tags = [0; 10]; + for i in 0..tags.len() { + tags[i] = get_ddmtd_main_tag(); } + info!("DDMTD main tags: {:?}", tags); } pub fn select_recovered_clock(rc: bool) { From 4919fb8765652852cd0802afa71596dd432c94dc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Dec 2019 17:39:22 +0800 Subject: [PATCH 2047/2457] wrpll: print DDMTD helper tags --- artiq/firmware/libboard_artiq/wrpll.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 1a528afeb..1f6f91775 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -280,6 +280,14 @@ fn get_ddmtd_main_tag() -> u16 { } } +fn get_ddmtd_helper_tag() -> u16 { + unsafe { + csr::wrpll::ddmtd_helper_arm_write(1); + while csr::wrpll::ddmtd_helper_arm_read() != 0 {} + csr::wrpll::ddmtd_helper_tag_read() + } +} + pub fn init() { info!("initializing..."); @@ -311,4 +319,11 @@ pub fn init() { pub fn select_recovered_clock(rc: bool) { info!("select_recovered_clock: {}", rc); + if rc { + let mut tags = [0; 10]; + for i in 0..tags.len() { + tags[i] = get_ddmtd_helper_tag(); + } + info!("DDMTD helper tags: {:?}", tags); + } } From f7a5df8d81ff369cfb7d52c4864f0a6e9097573c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Dec 2019 17:41:44 +0800 Subject: [PATCH 2048/2457] wrpll: add diagram from Weida --- doc/wrpll_diagram.png | Bin 0 -> 58653 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/wrpll_diagram.png diff --git a/doc/wrpll_diagram.png b/doc/wrpll_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..1085e0b15335dc913758370250c819caa810a42a GIT binary patch literal 58653 zcmdSBg;QKj^9BlpAi)V5+}+*X-66O`aCdii2*KSUSaA0Rf(C*ISsWI3xl7*f{eIuA zy8pnf8n)Q8b!Pg^^z?N1^Yn>QR+K{e@aY2t1O$?dw74n+1QZDTrw<1Mz7iai$pisG z3?U;fqV5TK+=Y~_Yo2-gieN;eOdkxCNczD}!^{VzS#JkpH$FaV=7_6F00;>vO^XQq zl~&xKaVA7>o+(A>am*R=Al*+&@G_1ClO~cW;|KjY5x24xI8@(D&TtZ}P0u9pp~-6O z)n$!}if3;pyHkNO#mv7f&-!PZVeMmgkB336OU_ZZy%uenY(Y?bS+4g7pPOUrd^9I& za$%@{T1ryye1%%QQD5*Fw`)8P3Zxbp4XDHYr2lxS@m_L@ZF7PY5}o*OD@TFK;&K>n zoDz)DX|(ty6|pp4iOO9}Tcci)T z96^i!9rvGqnq>k3K6XD5d?fxO&OeuVpvyb=h>fA(6CwVu%~L|sf|_}ljxqo58u<4e z)clLwkWl#lSI^2>;2sutJHKoFzb+?=frmpzr~Kb;6NT;2^DhjtF8d9V{%5pAVPx=d zJknqPov8mG2plBltok*P1T{+hyX92w1c#DzAoN?ypMj${?8a}jnEcXY?8Hw#{T+TDPV41-2h8v6q}wc-$v<3`=hC@K@Dksu9+I zrhc9Y@@4oJXtjPXB?E#1l;Uy9=Ovr-O1fDE0Lt+y3AB|2x*0Tp-|a zC&wo~`>lgdA;SD{8FZ1Jrm^8ge`R?ab#G`u{_UP}L#Xq71jdZ>y7vMyxJu{(48yMD zUUDeKUtOMk<&VwO>VHbbdcDnt@(1wpmrR@J{JjkU$_ZMZ@lJ|Vx>!~EARx;9%1b=S zos2zIfd~--4$)#9DeTX}h_$qmc;I)b9>{3~9D@`AD<>~hd(KhW5@wvpJ`g}{ia5CJ zpNYPQSN58kifH>gkO%aZh>*!T9J(Zhp5!L7F*Rmb-2_^jSPq;Kj_$`BsI4_)#Fz#m zj+Q?$l&I&(WUC4zSU%43Z!;UT1@4F`7gH`7thvGjsF6iNFwne63zwBwyleJZI!=q< z+>4sm5C$L6lsb-~StYQ`B6n)!#93tSop&({SZxG}^OnyU)UIt9j>nSiva$t^mpj}#Gbv>9uBF6Wf zP#UuB@=sE2?E7t7UqF!+NmIg3a~(^VrP*)Zl2m5jOrm@KwGVN!U=fRc(vN_@G4sHC ze*435U-F2mz@)7p-dV!NLa(g=R9jthnX&z{xT@~#I+(4z57_y%9ZZ$oO`*a?HTgA5 zM@3f}_3};s^6TN0y&S6VcdWnyQu0B1(53o#Wni7wdvo)nZhKa5>`&CTjM!I1t-a`+eqLT zF^zW+G6D)NUGPDRf({g<*%D(%6N!;>5UbiSug*&wZ2Uw9wj_kr+VxNu%jF~BgW`OE z=mqu7kj#^4+UlijJ}a|mL;U2wl&{wBz*1kQlW~h}AWeefv|r_xq^VYfiW4(htkrKl zZ9gjS%-|?lE}T+EbMu?QP~`+>&)P+QN@gc|EGLl=Qn+dA-F7Bn{;KMKH_R$12fJE8 zQcRzNa(=Qkil;tn z<|(A^e3(wJBMR(F7N(=HIo}#eLzmzoSH6Ybk;;|YM*Xffif8GHFH;X4&wEJCe&L|+ z;NVbCt&J>P)I&6EntX66NT^Pe@;|mH5PCQWtjtb>Xn#O_m>yY5d+hNCa@;jYL@KUlBzt$Av(torKBv@8WCcbiLKo%G#HYw4&OG)w)& za5L!O1On~t9~oQmhm-l*Z9k;l(j(+*Bn4h0)rO^yUv9E=w{43IWUV#$nC*tZ;Rum0 zOuOBPaR6BT^RHdHH1S1_utToKrhjO%GEAv!&hCU{Gbw$+dn7d^_a?e}@HV`Y{r9+! z6|NR4Lba5t4NJZDKH)5y^H+N&LnEKfS}57!n28rmc%rmHc+&Vx`@Y$_(J7?80F{3> zaZy9#rX-@lyrVmF996X8(xd_QS>fQ}@ZEylr3hEN zqCNf-`iP>9n&9->Lsvt6_On-~P`GeD?q)VGIw@0ZwiyMbVJ^mZ+zh|VzxMCV1dfRi zqlygTiDj4z!4E#7T}nL&fYq;ufKebKR#~2tZBf7+C2+E2>nFJQU5P-JWS}6@!jPrt8iA_unIEFL zLN15^cY6(vELfx4_PL-C6u!Nm@O~Q0PK!@A4vz`d}0M1U#^B(tc{&p>V|j3bcw^W*EaoB5IOm@ zH!gt{3U(K<%_g6SnT&^enn`0g)<91xuzT(wF+ob z_aiw(ed!xl;#GdQNxv>=!>fE)zmu>v+f|pW@hjaq!jYjTYlJo-7_(tZoWQ$bj)<8V zwlC81d0_2en8f&dXoNx|DhWS-^9g-UQKe!JfAFd)xPZpQ!Bv1dpeizv;OIEuZtlA} zL__shh6w-l@hdsZL%0jWA8$)>P%m>s?Lqr#QgC%0-N7jJZeh#dpT)e{RMNo)BMzy1 zCQ+=kTTG$yE?+Ht~H_hMk%#&((lz$BR+U?0<*uzdVQd=6jd2W?^A$YEJi$~}% zghs#XuH80)Sc<(6tzqyeyx00uxbZs~K4-^jaR>Q=M_DI-m&ITAPaYj=m?}TS3fTv7 zV{wR>d7-5~{j)gx)GvD^UzHP|uC6K5$Om(piSZ~B;+~br0-@h=XO0k>pfvfi)HFh5 zn<>^3S$-$7dAy*-O&W!$epyCEV3(O$HM1tvg*mn0ADujAlzzt>8KrMn6%VKc^H_Bj z*p)cG>uxd8^uh!%;R6?8RXRhLx{AJ$l%zN_4Ewc=?B<$vya~VeS&Pz~tHRh>_)gXc zMC<1CyX|r(Th+;iuWX;R_Y7Dg{(2@+fqlHWxam1^=9G=0AHBYPxlULhEkJ^4u>V8> zXEx(RmfwY9!UFWPM;@{I!d7MF1E^2UGQ(w@ow2YD03i(xZ(k)khn+4rBTNb0;+HDs zM88MCN~H_Grlf&1pN!;1Stt0^ugtsRS)1&uQp|cJ)-+<+R#+%q;;fdVn_A9Jf>`hNR}*sTJ)Wg4jcrtX8B2U!|(LK|8!*E`P7Jp5nnS;YIXcnKJ@+Yk%{X z^ZkrO-;3zsi&tKTC0QpJb~Iw%du&5Zk(U-}5y!U|xm_)2QgT5rA`^DWTDKsP3A;30 zd1Q>wbl2Vtrr(qnUdSY|Kq9hJ(|hi2DJ&a$mq2Gri;9EK8j-*b-0e|5dF+^O1Y}&d zX!)NHbDBMWHeZy(sOc2Co>yz#%k`Pw*r-dr*-j851V@szHzz9*lUZEbYtFCiMb+ZGOgV~}-tE5W07S@OrgVms&Y z3FE#rWPH&Vm2F8cnTwNTHC4fM_ojYd74=h3vIAf(wR9VvXu9#yw6MT$??(=Bx!I7q zCjWv__R(!oAGW^9(0Poa71aHhI%|*F3HEMme}9L(-3aKRCHfGCihM-GW@BxT(kqUd z|I3@Syiwt8uTn<@Qj0!({H-ifBIjaPuQhR;n=hMi@hj;G@M5tq`#6<51BLBt_K*ZL zGA2M5HURno0cpRRtUua!-&>d~OpVCVpNyw7s09>`Zg_6Tai28J;io zxVN&2tN$x^cocL!f4VS_mj`iAtG>{qult7%wtR`Y2fv)t{r(&tJ?lDHvq_i@A>-Ne)1~r#xLcC zP2`?8RaSixgUv*!)-y;YNSLraE61eKeQuJu$MOPgh8)(m8hTC~6h%zTb+%sciQ?6><3l?8Pk7psmz~loYUS+J!CZ;E~=Fv>9%a9XMo05fQ#$? zut6O#7wJ3~{Y;yAL=SbH=7&5kAcU#yUl|^Ym#CD*ARa)+lW=5-Z*_Es;HPIP-?3y0 zfY!?d+thsH9j_v^nO`tHsX>qbGk3FaJ$YhYpzpeudVC-?sNp3t?*PD3qam|Z+ip4% zAFi@4VI1(s1K!rxpK1`@?=S*+BsHUDk@h9}+NR!;GCi9Y<@J6LZhiSSw`P?LMF8V< zd+y%B%-h?0dS<2|IQaL6ip#+nYnrExGQyfm74@D+N}%8M;VdHBpsdn~1xQ`k?^-5emKX?UmO zdv=}SWV+FDEjSqboc9nU_WgOY@bJ!1CwyFREtVz% zpFej}<%XOjvA$Ez6~`$9SE=d_iEA~VbowoCfKHVQ`)|rc*bn{t=if|Et+4e>_ar2! z5iMPzM-N;k_x*EJCA0Q9Dk@ubJPwfQOx*8|IECVTTKH`k`fbpuzXdjQjzf)ffV%Mt z)f4texL{2DGJbfbO8q&94M?!eTh%cD${5l`<)#yFX(EpiHmN(0n^ir@>T5ORNsL94 zX`|@T4rMrlEy)M;?~UJM`nzAEW75oZo?3@4Uh;Yf`s^~AH6@%fa+LKOGF2byN~ma7 ziVBAkOZVFJ7!qxTIZwtHRPOt-4I_g2Wf_S1Dx=Yb&eF{9o~RTVnt8{yf`$1bj~|7x zsULz67{`5x37a~lSV2Tx>w}%NKz&Xv^w)ipn$yR1FBB#I3w+L(W0^=+n#Cc)hIduA zJA+01P<5SGFsCmI*z0%vY+H%`p%a+xnPi4|Sl~+mA0X^6^Z=HnsF4b>)Sl*aY1u5FI0yi8@!`yX!fR zWSm&q8&uHnG|Xq{c&}zU-AymxOL~O)Ppv;51*vw7U1*RSRY5HIQSSH@mJC(nWC~I} zSbl!RU+U_KGmpJrmc~J-(OK5k#qfpt;Tv_A%tzIzYDTM-owgSBhQ?%OG$p?9z6+?>x(G`6jKT!-F^ zF?HA)hW6;>U!VqXu)@ac6VGa^(H-v4@oXi37d>;giFHL1$0ARvgTt_dBzK^~gz*AvT1HvTk= znmSI<9p7e!{Nd+(AD5vbuM_lrG6>!mCD_rFq|ob1K;3*$hV@QfMoulf`ihZXpvX=Z z*w@rRp7-%GAv2e116I;p28IIAKs4P$hkmlJ<`J2EDq`4CYbKLLc9w-JA07juZ;r|sa(+Dp5}&`u@! zpCy)X0saaW(ZKAxX)Fjy$wq*;nl4{zw)_&gce^C&f$dbW6_pIN>0PCU)$On{edrzUjSjp4XMDjgqH60`%3b z^R57KPV#NF#)11`^-V5||3Z#zrE9$-NwCI)Uz4^p&?Qw7#NivBdft0QFdcj2-iRig zOUmH^m<+w9F0@Uub9aZKd>UEiZ9i{ilrUag$%C`$SpPBc>_~iTU72fm=ccWr!jbW5 z`(u7Thfd*7_*Sv~I8U@o*qOPx5{&C(4<-C(7UF5^PMV2$t=P{vKXA|*mNaDv#a#1COYI=P>&zvF^2@!@Vg;K}p@OcXe=cz>Ip1KdL;RaR- z#g|ta(X0RTV%ztdc}FF{mO}6Z-8r$m|R45_M?tfTejIGIewQ@t{u-M z%h((Cr=1-vFH9oh7)n*sTI>&!{Ecwkf`*|VQCF6=e1yU0{%fUU?Q+XUywH3oxuu1J zqlL2Dg>$|kXf_?<8D7^X9;pr;twHj~B=*SuRv=!l3$@s5{oFt-pA_EuBGaQZsz1nX zq^LJ!_*iQe)Q@W^;KZnrDXR3XNbKiIap0qRwRnkjOyOsF+a=NNlYrmGb-#7_T$B%$ zZSmHEtnbP>Y$g^*{H!PqJYNz_)5)MpiQM&u%rI99g8e*z8RURxx>rAF)- zW&gVEdqxCY8gAXv0XQr26g#K9fj@lPecF8+HIBH(XkJ89$hg>s&KJn{ZsxEF#Cyiy zB{=JkuB&sGSo(Yg$I(M<>!T ze2(Btr84RH-LC)KS_*JO|yR7SGrAk+U6T(y~}b zA)A>BZl8mZ^FzG4KWh%4NtzTPk=KF+U*Vz3EGNh)*iE7+;v@)O{8EGR;hRBnYcf_{H^}5@tQ+t4m+Q0Cf|pHuCcORuet&@=J*YlBd# z3y72@4)hTBn<>y#$P?Nm!LE-j;O?UZkqd_4%Z%yFQxYz!%~Q4MVSw5v0tfx>!&()} z_tM?4ydMzD_}}Ye)Na14D#fb~K1e2oPMu}Snz)kRUQ#90JU=@%i7eEQQvLSQm+WpR zX{y+ObG;JJW^jHVi3v!*He%{|VqN#CyCX&oGdsMO4AY-wwBp5my$QSge(JNlPWMo# z*44RYGpV!kt6vP|i9w;XjL+TA@)Nu^Jax}aFEP4;{@GoK)m+{JwO`-oWk&`jx*5c0 z$YzqVFJ*u|eXaEv>t?(Ar5{6#owmj*(H-jc#Wi_$#_B98sW)MJ&q$i05)PbR$Bn>K z-xQk94^b8(3x_2mX^nxu=rwekX5%NkH3e1}7=>Bb5a1Pddxurx@33wG7uWW%*8{bA zGFPslGyGo-rZcSPX!Jo%IrI!l4BD&9QK@}hB0!9G+-ZrGPJg>|9l$K3&P$IInY#`h zXMkzgvbob~y_D&A0H}X4;E5RPc_rs=#D|mkp^D+|=@Hb%!dGHQ^qOiMMBic+xA<-OeaSqx;a**RBJQQj_{u54BVzj>Ok=0Ijy zjQ2-icXR_I9=3t+`Ow{TgkUHpou=@r5S?3OKVx21Pr{3~--388^|26=zsSk44j}GQ z{NV@RZ%g8Mc$4efEeyN4Ln zB6>xw{{ofNt0(mtwkU?+xfrO-=;PcW~by$wJcE9B6eV>@s8NUJ;$)p zQNmgTjK6o5V7oqaFef6$^|?t3#`>Ef`UC0&gV(c({6qL+Tk9!F}duv?3xnp-D}RDTQhN zz2cn}&*;0Ha3q})2Ps^a}uX47zs|>`SV*^zyc9QwNPR-DbiDIUAk~rN@dJHoy>+gQ2mpROm!>>Xan-$zTWe= z%}{@B)2}N%eXgsim_E5JMi#P=JZ!Y_Rx|A4%Wc1&d6gBY-v-XV^gK0_dtDoR%{%bU z>$80YwgADQzI@mDFy4~*K;{#cT&8L~wt=6RA17n?^?K^l*q-=oG>?7jW_aq;5`owl zc3S6Sp8q;yM|D%wogG6}k!g98@BPI*fyXKf4E$1M;oRt6k4i$6r_iVa397X9a-bq- zQnY7MFjq3*3rt7_1hL$ghJaGvF8gbP>kUnFuMEBbFI%nS{$KU0I;rSt{`4p8U)B(M zn!c+KP`Y`e~ zJ_-tad}2^u@MftVD&-ROSnnUZA5X`1E3)P5TVr$;b+dS8-FX_c|E6QBp{;US&^O(> z(C_9tKo!(1=rQ`p0@bE%F^ULIcPTcsyxswvn@%eT*D3elK|ck>UNB}9Y75=2y1b!^ zj+c{MTCqu?;d*V(<{GA@TGf|sw9@venso*_Ew@vItOP`SXPl)aFW*}5*<|t!;HP;F z>)5nPQNW@YAN-Nv%y&~>eOb#p_@g|9;GrJf+nt;db(^rse*UdV@V zXCx99US1Qb>8Da{CieJUl|xTa>UrA;K^%pPrFp88%B+M=h8sp+*n7w zjh<=s8r0L@>hzU*J0tg+iyQ18YYdWhnagD41f3x3uzzH-*^>uUZt#?cvwSb$+M$0Kpz?}rPelej>6o&y}z*v06Ru3iP zC-eb*41XEyqb`2r&A*h4YsJ8Y`@_k6?cpI_dcIRamqFvq98U>c?3lKl@i|fbiumWl zF?@49Z@jw+s#M@=xmgTr_b$TT5^^b4p0I2{&yPELj@^3g&6l zXsnmKum2W9)cIuhPbysKv~7=2dcs|2mG<7m7`y7}J+@xHZ_T({W5sAB^WaOViH!?ye6BnNDk&9eV_#mlSE@0ym3InE=Od&u*~tSSz#1ar>QBOA*kj9nKYh`ki{)$rtzyGWOI9 z6ZWPn#-lVZVdKRN4;+1He?MBedts3(@z{tX+y79=fT?lH;H{J*z~Gp}TCEQQlN9|W ztD1x-uzOb#v4l$|9#;P>K|B%XgNPium;a!vi1(Tq%4dG#VhSi)0*O>4BWBDn6w(&M zYqcX8{JwORYSj|}l0-y%0UU6tQzutGCP=Q(W)yT#C=o;4ksX6ZzoAlznY(b~%bqC( zb*+$34(#fV0Ia9HA;s5lv1M)szAY4$V+3MKHt(DvZ-v;R-UgEVH@gQVy#Ga=a_8yvFyeGYGPCuoo4V#{I%p%iom2SNY_TKg~_^2BJDJG0@ zyJ}&i-sJ6+X&v%=?UHc7*i#RkbumWT1P+i!0Z*L5Xu$T3V&m&>9Qkw%nrD_K5HoKK zA9+BC-fsV!KV@0*M;#$bKxe2%E~njR6}LFeJ8(#V6TssLp_Tg_HPIei82TL*tYK?t z+~ud<6Ucwn?cGPz44kC`wU-@V0152obO<}&I0-D~3&8(5$D`ik)h9Y}bQ&efm@$3n zkZ6l3R~4_`%y%JXKeTMjhL$4TlZQPclT?0n>qCkx2{?tj1{34OtIrueqracFBHx}M zM#8ltY3x~bBi=s`-+_?C^*h#43T0q~JzS=DjuWtbPK9IN0o#;0qSTr|yj2DV> z`+(n{-cSblPf&%fQCZ{Q>;q&}H!Eo6H6A3`irewhi5;_-8~Qur$&>kt!uQcZD9pp3 zBhcqvo>mrw3^~@(`ITH1B2fTZ}0p`D7~ z%$zw(HTBa+w@4_0qgl+YH(Y&&pX-EGE%dbZc7@x5-Q)PT%Cwy%HVLEp7BUB@cw0mM?)C0M;`iga53Ry( z!kf7_MbBT6H~mQ`1?H?Nhd>YR>GhMvcXsOD=Z#y4lm+Z?vj>>LKv_=#Ssa-u)ie#sC_-o4E=0Nd&=m}$h1{uzgNcy=%x-r2h5Zo2RLjyoKK9` zQOniNNcn>iAKH=^uybb=J-`Uqs`A-ja2~OUp^LkqYAKaq`3;io=pOwx3mwk?&WfdN z!U{oi;NXmfP|I*Zf|BiZiwVUQksK}gIUUiSZCO+!#6ht%9%W{b`Yqz|(XgrI3Zy<8 z_J=_gPN^)hM@NkL!d8f{D6WG|b4AVOJ-!^Qfhi%Wq*^B^j#MSJR#4EC z;0q^Ku{t~4fXmV#%~4jp;31a5I#j@v%TfG02S7-JZRlISOeK-(29IgII`0SuC*6Os zTC*-*xKeH~R!D-GRVP2c9YDNMZ7H*bWdI$%2hvt_^{A1}!b0TsCr%>-W$tFc+Dcx` zZZJtxo)RkUdu0YdF7*{;*r49l5h-f7I$y4?GnB5CMMMBQ`VnH=$tA06_MrGUrYcc8 zF>K|%f=mA5D>$z}T~G8nTL0B&btVxhdk36h*eHB`Wfaz}J+(WQoXk7Q!s`YHQ54s| z#+FaXLp43ASmmjL9;lR4FBm^OdURhBnA0TwI%Bi^sm@n%IFP|argE%RtzBS{!Ju1u zVZNwA_~z43TR{)cRT?1E>Gv^|oq8@hsonrf2TtK~1(ehdk<$HiT035%1U#Gl&|Wqi zUik>wk4I_G_cxY%4BI~VT@-KsiVGY~ySpwtlN}`B<09?&VZ%{_W7DCwVIAf{I^g<7 z!1YS=SYkH;1LTRQnp~@nAr~W!c$NGQDW+hkRo1KL@wDSSO34?hKpAfH`!0)>R)Y1L zV9F@al>L^sjTfh$xmzD@lrGbUi;BwT}5&QaxEb6(N>LOtGnnCewum(#$s zi80i`B->8?7(rP53>}@^d3tWi3g}+t_O-E=GcY$?U>;>L0K8~dpD4PRS%!Jgj=O?S zk>xj(Uy2kBIOo6Ncbit@8q?4XhWIfbWU=;QB{WaAvhW2`sF=}lgJ9t?n^Vd-^6b%A2^8m14Fh%_+r}5`5-%;JXb%ax`c^87ri=KO1g@@iW z6QDMzYupF*I5~w+m5U1w^@8w$`t+v_I2x%ZviNp(cBnR;)Mw|OdToEyMH$W2BLaQL zWUt;aiq|58B&{XZxk?yEtA>ADYt+F2hrbN`YycG>j|Us8+_;T*=QO;ISbp>b*0d0i zbh$h%-8~;U6xl7vc!E>$w6&c_NJpA?uX_O-!G;9B^yKrF91Ae=;Tsq_uyAofZ&J^ws4*SXr)mC5^C*xvP54lZ z8CBU|FzdvsyoZuhjUb`I=pVB<34-t<{5PqAkqju?HjDlUAb-bC(bnsOf+KEXJyaV3Z0wZg26!dmV*+X&IzV+aw0l{5?Cns^}e!S6x}S^o#arIK>c;c ztvtpAUs^vsw_h57V7e@oeFQzaH5ee64=8T{)l>DI7$s#)c06x z?T{Re3%cu(TlI{>Hat9E?7{CPAsP*bqH7i$2YUwUd4YrbSVKniur-IK1taZoqWPbq zJ5Ldm=zNPhZMfql$sH3BWqsEuc;z_?#UeqE0=KJb=;H!)ClYT-^-nH#~d@sPI<4y7pBz=fhkYo&8#(x3Dbbkjdu%U7-`$JnCv#< z+&0z%PXpR@yTBwF+V)!Q)u9W6i2}M4o4PJ+C1i@|ihkB+ap6>n41@;HnWx2Iqwnt- zQ<8C{rhf(J;wxxjn7TZt%aaI9)#i?-cyr2f%zE|VyLIq;pWBCKt^8@6S46&oJgIRM z1C<%$OZ>=5Ge$EQE|JmX|C;l0j{iTv{j@Fq8sz=sNkGr>Z_}uj=a`z6)c%<_`2F#w zhwSDz*0CQ*Alv0oe&VY;x4+l5Ic@632N3R;0Rk!G3F4qnRK!a8K&3*@$y@>5w&Ysf z7JGTXlPAqZJEnnP%*9e_Bs>4xsgxV2x}N9%a8T&Cmgnb8W#4fR*?IOvRDV0^@#`qy z>IogpXwXwBLTka*LCu;v6fWtaPHi?ECFobC4O6EL6CXryATRi-RzV_O^oFg+H<1#e zJg}f2NQ~MERrlsoQl)(ocljMseR?E83~_~|-Sh%>wGEg$Ik%Dp^l{*!|HNJIeIB<1 zV9Q3|j-XmKR-QV!Mo4%p!tQ{%rU@iLqmdiVmnMtR8sYkxCUdc14RPlnDcGen{sx=0 zYlA?%Amo0cUwyK%&RopP{Qx-1j6c+LTUvN|(mfUZBLq`#ebti&RHpYc(MZr=s1!YA z$o3;e<}K$WT{MH~{fLh94$=$25JY0&x%nPg*={vMikYjUwM#MaXT8g3+`eEo`bqrr zCO8V5j^${BNvuYbQjQWCHYrybCKH&f@V9TLd)zMEB_^Esq(5PoE+A1Y4P{E1pL(m` z;Z9?CWl|jV7`;}%nY$tEI~&6@C@`YvRW@sY*dLwtGU_6nH30TyM7WWZWKsK7LXCe9n`83?cfTpKPq>+8UdGHnCU88I$xsh zySCywk+HK!_Bui$w5Wt@1K6;f@B3tg>>OoVTwx`3&PaGMg57mDC2cx@SR-@lNqAWx zJ8x0D&t&@d_aMnM;7==!o-)(AAtypgAQEJ=QL{GC4@}T7-Qc_Ft}1NZxJu)*`!=fZQ2pp^+j;c#y){p5t#eXS%!JC&it^gawjhB4B=-bRR_D@_+jR9)xMSQ zo#XWgnnqgnd$~6IVZF89+}cu|?IN#GD=rd!=Z{;B>OWF8V@$qpgvIA-UKPIcJL$qn z{sP9S<;H(LCuL&uBVcRTCeR2_*kP}Pf;KiwS0M4ThO=9P~qus+L=O+om zhbo*P@;R=@R9lZj+K=w!_%azo#0^PRysja55wbCC4;s>K(t#$oZFfoveRz^xkm&Te)Y2?~N(CN%g{jp6B zWDEB#V<~AT;}S*C5MRRAKDtOI?a?|`zJ%BfvY@m#8ZA@ z25aZnC)h39x^lY23m#5+ORpLAQrS+nvAAH1O@YQtd$G}aPWd$BrY+;N<3{J}MmCE` zcI-rwO<2)tY|-;R2DiJd`zc=BrTbPqzVAEwY%Cd}mUf$;Ma}h4(+Dd$vp;m|MQum@ zs7<$6>fTaWcK*|94KV)o_srdD27SUtP1x+BVbA7x>z7}wx$UqB&NUNBG}s@9(Jl*(l={+7-4QH^D0&az zB2kbqI?3gl@cF>^MpZiOv>*6YaXMDZYZhrd94_WmWPU}7G(~ybB}ez}4Lgt$N(lUZ zC(?*Z&%r=Jh3O&8$A>VlGUKsTomS&NXowCz71ZMf^$j}lV5fi;8d-^;H+$Zox_fIY znKQJq8`EG_H+(i6>)h# z8P~uroO(ODpTiLeT)I8LhnS$DA$2YDi?)LaUZ5xaYgvi*xssq;k#dtVRy7;cRtBM1 zJ{xokU+DTM+*5j(XbF;ZHHC>zQdnKpu>+KN)V0MkwmFI27v{jtZpbyrvL;Hl5)Qg% z_e?^qpHK_(#%`ntuBPkmW($qq8cxi}XXel(FZ1bNI2xQ~7vC?BL7AbYTiQ^m;%<0! zby{67&q0gHE|rbQ^C52Zm{mk$G+thFji(PpgVkqSNw{S+1KnS>rC*DSRN-`)s`pNS zA4}7EAbN~SYSmg52N7`(MhZtxty&Js99=ox!>_r6KAXlB-)(~ZX+X#jI*Rx5u$C*0 zG+>#^0;|g_c`!92lI(!nJzR;QbV)n z$~g1+g}F}6Cyv%GoLRPnkdud^1td5;A-#5{Wal9np?lPTSz-HqIkw5!+CeC$fVZRl zFeI=R?CI?cA=!`7usMN!)@i?;Du*!a_jp!>^8}VnAmacJ{DP~DyjCS-SeO$e9+t)%KbJ;i= z2lXuvkV)(ke!g4sA7msEgiqye+O=w>-QXI$Oto2xw4niYb{CQb)DU&dZ>*_fVeLN+ z0NYdeIiE@Ec6fa)=`fur3oxG#!s;mV9^~~WznJdpP>!4qDu!of1f@-l&Lrky*;2`E zZ>{3(4b`}JnZLzcMIWg(lfVw$_BMh8XJF)1$IQznxDXO;5li4DnBSZO%Q2h0Q7^@q zVjdo?JVxECO^7r;`OJqkK?8rTJ*I6dAPiXn+^roPzr8a4R^jx+0a zD8-{Pgb2x%U7%C1yNS-rVT&4=)Ii$wYzNBerpW~#X{FLHw>0%>4c`j;n1W0&?&}x? z5z->1P1zqJSE3uoM0UyYk_Juo$K(yWc~zy^A~Dc>h{@`wqo_~*!+(uIA#&nQyA|#I z>L3U9LX%wvkhsco)`!)+62wUp2{e@iuGLq5GABVFrU);1gV+S&sco1Qg;;@bbW)n` z^uVT3Ua&%^LIHEe zJ3DBpdH#U*DooY~lUS*r5*&2IKJR8Zgiq}a1iwd^H>B_a^Up=cn3|NElkHSB&EZDl zGD2f_!1x5S6SNr-f-tDd>8#O}Q2*^Y zV=5m<3LAN6*hTK}_=X9c4yUn}?%Ks>Vp5%5WI1g16RoN_wS7sUtWs|~ z+GuquYPg8JV926P^9EOIBO_olic3ksV&1B5*7N_DtF8YL)$rBkr*2?S9ev2)c!uX4 zzjQu2v~8LP8vQ1jL{J7&wm3XCg@LF{^hU|t`KrrQ#rwLl9QRLeMc^6%{6&l0*C7Z0 zRTy$*1nBa?#eRBrO(Og>55KQl9S_HiQ?wM_EiKqo*^W@)y34|s+Ky9RpaI$9g_V?^ zo%`u(1tBQ+3fj%sO0Ep$lvIC6NyLySOu4juCSDT87qRho^wk%y z7))5?GrAa?Jojo5BYsIQ930QnUgvUHuZ|w8Y8{G9GkB`sPcfJJCp+|4r?*9j30?by z&_zf&pzVA*$-O_fqoGK!q|W|uLkD)h>%#e273wI0&{oH}_x+eUSG7q>N9p*F0< zO~J(;6l~9iB;btVtv~>5Cq%)F8pucST!X zUjEYTbFB3aH6Pd&PU&=i0n|8A_z&nU$Z;83`D1+eO&N?#;0DoL@6qP)P!LHmuSu5X zf|0LGsCQrz#g*h>r};ury{EU}O}X{g@nnj}2hnVChbjwDizR<3QvL8oywJ$SP72k~ zgb1mi_Dy`bDpJUiGcM8-6Kax7ZSsC~IGnF&y;-(7^80^y`^uoKx-VWpq`MpGF6r*> zMmnUsy9K1BrMsoOK|n%Uy1ToZd(gN3AMU3+b7!6zoa6KCSbOza`**Mo`JrVfK{b~t z(D-rxU?vn%gW7@vZTrP4U@@Udh*2LdHVq-f-yJl4|*}JJ@84PE5iSA)+Sew7t0t)hbJX ziUU;3emPfRx>VyGAcU+TzBwxM=);qK9|-(7_7yThk|Lw~_f=L&$#+L=ai2lfYy!8m zntp=6FK2QIYo=V=!XvhHv&?BMnds;;`NZwZeQ zjuCe6-(`lTsF)^Ne8U1tPI$x7%#2}=n1UoGb|a6FW!s4Dm>#k9S}98LZTrC&rO%h? zs)rVO&F6NWutxft@z;DE_h`~_^>tjvWa!56d4x-N(wM`&!N#8gO{2HSGM^Yp!&=3) ztv2OrJ-tDTakH19#2)u}>MB)p`Z)0UL{N`*fA;SS{i1Gjg7YC;d8=N@Pa=RZE++Pv z^_(I29TgxX3n;zDmX`l-{i7d?bV_8Q@pc~p-asN!+cyE0T}Zf?C7M!+s;-(PDVml` zma|Mdp@_NJA*0+vOE+B3XeFSEuxXe%2q5EM$QuNN$v&i{)7*%^@0a;YO6d=VTCDN| znJIN}fx~LGV|*p#STrH95um)oU1NTmHihYfaoz_U#OpyiplGyt)ZsKfb78=g61t%= zblhQp*gUdhL;?PG5Y*UC8xqm>|B86ztB8}JcG>(Z_JI5g5WVUSWJ91i;~#ARAR|Bl zx`XvS@*%|kJVql1bjSbez(3qanUT3&4h6^zSGLUqKKx+^QbvQ{&?vN;wPxSvO}l}o z`KVc2Oa60!Q;7`2Y3+Ta5IXSJcNN6JMeKnJf;;}zR~-PSBWsIy)bkx4!p?y4-vBCq zcBAqNo-(yHJpGs1_{(@$0ek)_*7q97{QFVR0iKrrOfCCgl$tq!{z;Kh=&$ng&nK%H zc&eVnu0`_C^}yHb-PNyXA-MQ7f0>g%1O?21f_nwMZN1okCKCWNM%7QdsUBBtH?&yM z>U?fXz?2F7YcZ<=ovcsbA$a7#0ZtOXYH=2tlNa>jj#e#cUPHY<%fLzVEA8s*TZ<9M zMFuLMxx`o0uCn~^#9$V09d5hE5OJ9udib5v>6oEH@|sMQ)g#;xgOYO z)7+X4z<+s@r0r#ppk?g%@6x^i7MAyCfT__tyHR<<&V~xTppEEsCJ3rJtt(7i!d?af zpZGz~BROQxzo{4(0GN46rr{~<%}4q4&<}*%Ra}v(O$qo6?Vofi4$B=%t^V;A{J@96 zcQ0(VyJ-Ht%=!D+iar1*Zs}q%%k)2w8Bw#&|F7T0X)@xr4}S@7G;T47SeRKm#7>{h zie+0X!FIH(JUdB|-TNL}nDpx)oX7F5CYKw2YuFvq^y7zv5BGWDJ2d}F(?1dxoY2Yh z?dggQZ#Ml|t7ca7-Ol}B%hh>9Zqo&x_SF|%(o9<6<)uRXEw6(}fBL|Re`&^e1{|^c zBVHvWIz=Uxb%*#zus7BWbwEd_Hey{! zJDJY4Bj~t}2tV90|3V3mzZwf{JfdaiDeyTB_?O=;LO?cJXGXMTsxv;f47N4iZ(dgR z?s)r5bauwt_S^&59zEK7S-uJ^Dy;bo%^|E^ns_f;hOQs|~w{F58+A7C%a-PB-$}v!@0cfoCFJH6m&nzS{l~Wo+d8$zpytBt5AEc zDd?j2AN5VJE>yB;CI3c5_@g)!lmVQlisC(e(|=V1pd&hyK@wa|*@pfF>3UTTDX+@2 zpdc{)e;$LH0$WU=w54dZ#GfpoDIhgj^n`V|ink zxr~Az?%U{v)W}v}dU*Yd-Q^!j(fPI%l^^o3>nqe})+d8bhGWJLg0L+FKm1o^5*R6N zRRz9F?9U~wM7^<4EYZ=iJ}cFY|Bo(EkbYgsgjFSjG0NDY!8b+Y>hBmE)4<_bvUS<1 z6_saG{>%EWZJT4(CIJ+F!~g3dQ~`rvN{4Oz!-uc`0KN=FNvqKM7yoV?Af5s(V3>Mi z4gV3u-^>UIIN*)BfzAFCB>y&oXaIzmXH}lYe>5^MH2GJ6*`PB(*yR5{i{FRRivn0i zL&+*_c;qkmDx+P46xBMKZg=^e=?7&;;1`SEN`}Arh}! zjFj}VVUFaiz)MKz9H<$4>;ZwOx5QrX;RJEgiKaR6Lc*OeZXnC-`yQTXHrQ6jSMiUw zlE{JpV$}+NNqx*gqRO{4JEL7)%(We*1k|KPO!M?B0quInDsNG91s?9C$DF1;E=!xa zne009^2<(xdYFDAhW$BI@>crjqf;#bbd0 zPCk+;I?f7>+5Rfak@lJsumc9f@J^&Boi>h3`IbGl?cwyy5OO?p!G88jz1TO+y}-C{y{7swz#N3#x$8$7!Ilu| z#E-!&9v;bkX~Ytjg5d?9w(TiwK3woj>;4LBHy(J;^>IZGJ3s@7EC5-}5_`1}U%$R0 zQ35V@=X{+dzLW|dXWa{({>t(otjm|%s}Xu0-g8=vx*=D}u8)9ST8I7&i!nwv9&V*m zX?1SOAo%csJ^Lk_o;HCCGeWfx#uL?hyudZ{A?A3>vp2B8e#&RzwhsNNXUpNyC)#l#OuDhFJp06C6>B`y&^Y^ba8BDwFQlA1QjH_mm@e8fA`I~;xKHe3 zm1It>?L!6qV}UR7^XVeK+e_!OVX2%(ll3@*kR!8H3s$nBwRFmz`6p^$S<{S2TXHK( ztFQms^Virn15>_TCR|H~7_6eWk;xZ|sDbL&HL;8R{EqjttXaF(il1m0j0MHjV72+#i8#a;KDD~>L z&uG4G<8$&pqco{!#|sQ|YOLfwYs|L92_BqMCQ!ndc%*05wReJZUH4aMl7rinwvpO?Q__k}C`a4~hdU=1!%V_7 zajqKPld;!*+CkMtvexO~b>=SJN8M=dyNj>x9+ZwpPUkl(8lR?r7IGM?^XlZdIu+w4 zUz9Af;r>S%pS?PywAD7Bf`f-xmjKkHOH#tu+rjtwds9TVl=&{|vTa7xaQaL(OKtEC znsHNgA}Nd_-#{vzhU;TDMC5tbMbfHI^_VU$OYsxj7Pc)pnH)(r#2o2v;=KQji~Uic z?7A$VD{Y9t!*k6^Io1#JY@pd2G392eCT= zwoeuXV1Hq=;`o6qnc(Q7^jSgy8E(BY!nsIGllAGPA4{gJ>^W~Nhe-MpXC}&KwkKMN zK}kS)o8y@1UhWcHUqcfqY{gkXkZqp0USlxfbPhKkift|td56Tz4!xm2-dmA85Yf!+ zv{t<)hn>X*7C7BWn`&w^O4H-Qia+!YyO2A+TPW=?}1gi&DNBUwm4STc(vib_QL{mv7o$KIhIsZj>OyoU!+(tosVSj zJ;I%B@bx`%vIy{Sh&l246hK2>y;LnKC28CN=8GDPsFK&J#(n_)igHKdfc)5~ylSZ-is^!~%4mBKy)}#3ZL1)#q~1*59yDCA_@K z)>geWmEB66uz>iG9+#gM=jBJFK-cds`ReAu3;B(kQ1iz8fo@PXZ;Jm93>7Kk-m5=- zX$uPWuS*43K1^U0G`z|gkLLfc;gLs zYE{~-HGUk~MHpdP1Hj=j>6$va{mze|O25mc4F|J+q_IaW8KNX@%~u@3!}A(0kSR~I zY9vpsUxQ=^)j{0oJoZ$D^E#+2CT95Kasg2Yx-V)YGL94o9YLdZv)zYIoC$_M=$1f} zAKjo%`F+hF*VxT!NYVO|(n+G-qLIfn zKlhJSRGFLAU@HacIBVa#58cm(va*)E=69B__=}7ArW{P^&oiT$Q&Z1fsxnr7R)5em zWL4FzK6h%gwbw^H7=UCF(XtHV7+5e`U`Qb}8=a{ht7>tn`g!;3j)i^3&7>R;l! zgSY51eWl?!FRMXyJ~5LU_>-xRxa?B;Xxm^5H8`aJDYJJwwXamn4U4bc>EM$J((@Pl)V3u%jloZ@C>SVa!9RF3GAgoWJb`2kJ{CY zhz{{^8RE+IhDzfu`XCET1<-)yrWJifgDv>#VTLc>6vm!F001c#%Pp&e3j5f(<#&kU zsc*+wUauXkV?UFMy2Z&Gyo6|URHMGC@9TkABC+;J!vJ~jV}8s};DOYT4tT3qCX>o= zW$EMP?ixjl{+pVP&=WR3=U2j*J-^|1?Z_4Cw{%1@wp)-0({HFu_f$vbfJzU+%X8W7 zC{2Ko&E1l0>gl;rq_rdgGikVAY2Z)Gk@wbnhI2`6t}l7tr4;9M28t;c@?2>jyyUo0 zhrmUO+p1dn(su1sD^9k=gK3HzE$w=w_!=Cg6DL2+n2t*Gl)}4yU8DfrHkjREztdu> zK4i0kaxo|_sYGq~=1yQ)VJ^B-o%caRQT_S|O*J9tmD5=Ls{y3!6dcIk;bffuYu;g( z=k1&3t*4n8+;2m#0T+4wH@EuaF?Q&QOscc5|RfSx&u50)}-}%LF=-lO0)JK1F}W6_9+WgW%Sa3 z`y#^!NI%6&nq$u^7b)QRJGL;|rP%0X2C8X?(Ojj}ED7vz7M#Ya@2Qzvbq(Il*~OGK z>fF_;kA&!)h%{9MWq@;RW_l8ow_ZR3naNGPuzJUz)_N5?V^JByzt6Ce2v|4-OdJbX zMcb|P;qqN4$Lg0|ghZ?f>S-qmwxVg$0O9Kpz21zGp3p>|wzOr|7*l#*7Zp8?#6PyR z*$ueLOiIK^;l@DlIML;{ws$=ASye-P$=XB~(?(X@Z{UZKJVR%zR)bVHLqj_y^HZ~l zy;w$?1h)r=R15>M*=4s!S)uxQ-B=vRj+eb-3@)lYYV-S}2VI}hv;``?f=REV^qb0K z$tP|*t7?r@KrvsxhP-W@$)^ON6Ya*Qj<-*_>TBujs@kE@yKzkS-E4T3kGBiX5o0e zsXgaq5HrlC01Y~?vF>lgG$fcGW$!B(P3(77^WwhC0hQE2ENq>&oL) zO&&cQYo#)O(_U3a`@T-Gct}+LT%wf?LZQ2ja@}MnTdvkb2+BryXV-dJ@8)^h z$xU#Wx^(fq(_23IC7fWT869ToqY5hqgHaG+4H3HdJc6M7X*)Cz6a|@ff_-E^oQ5kd z*TWx$usAV7NAaV>MYS(GC%QeJkXYM|UMb%s!Rq7zr+3bA^RMRPn?KFR7)=8i^bz1- zKr7a;ls6C5i^OXw^rYjdxnLK|2kpq{ZMa<^3fc5_MDNcpx_M;ohVd>nZ}(TzB4s1) zMlf_?O^%e-;_ObY$av!w{u%g2$IRPt4n*5=ZODP{ph( zu~N6$YA7R?ATneQ=n+!V=Y+?#lor1PjkoC9NlvO>zc#VZPRLo*pTjuK|($(!dF0wwA@2-*@=WpUwy&y_oINw+|NMx5wIcDU+kPPP>zEt^_V@jS_+$ky zWTiS--m5U#a3$^JcLPBM6X@g+*s2gmYPB?}+bMN)2)hE?XqyoBjD-&RTJ(e&sfeDgS?^a%5usn9CHB9@0{-5xk<1Ex%<$Gs

25xcf?lM z?!T*McD?Yd4?gWr(W_~@@V+3DuXh=Xy_-PRZ%9^L%2rYNKr=Q=?Ag#Tqek*eGe{+2 z#K(MYiFO7PBRgk&dyPiV%(ZiESNM$KSZp0Fm!4SUbNpw7?=baPIc4-fV8ZF2-i{cuDu`NYcIg0V zr4-{>MCh%XLox0sk=`jjHB*YH9)aOs%9rHNu+kw&d^WRGuV1_0_`>my@u|7=Y-nZ0 ze}`a5?0J%ELmw1z0E!W8!yhE>W<2MZc;m>-{F^{b61NPuMd^)^uX9Q*6)REKC$Ynu z>jZJ?5|@{^^f{=tI{sg1Mg@t(d%}J8sU)0&!bnpaz8}JnnQt2RCDDThZob!$Zuq_( z_XXzMUT4yGF5B$=u>`;HE-!?Hq*?41T!Klor)24c^tej1wu9ru5iXEPcRiO`?+!oF zFf&Er$Dq8xiV)a**J;C?+m0DTS;E*AZz5#lO?YVGJplnEG@YSo&W|uiXEn$5RNt~} zX0x@yx`bY4#)n2xeMS1X?{Dld#Zv=~k8vUaWnq4nBEj?Y7R_BqWwk-3v}A!dKToz< zN|lcd4pBeQVb6Zr-0~N!c`*sY-erBDHX97jj}2HI@VumSwAsTg%F4#fIkcY+e!AuH zQTez`#Jy+atv4X#Qir)LLg(Rx_SZ8f2Z=jMZb%9eJfbOF%(vmEaNjk%!~BHS1UsuOAGxX5 zJENSXR@1gRyRHL9RaMPTNSfNE@pF_?wkw8LwB)DzDcK9OX(IIup?h_a)w|F9;CV={ zBj(}8ox4AyIxq`BRrbH{msZ$N*gz41iL6&NbCZ0+`7otHB0%cnF*0SuOB>w>6~PH$ zXr9A3IBd4z-`(Baj<~i51_Xd9Jh^r}=+J66B8iHMe&urB|GI!N0y<|+PU)nqI5ibS z9aLJVmi;rkJ&|PW3%_TQv;y`wB$p(fgn=C$1oS&kIDQ<CLf*Pd8vsdu`S5J8W;A5#12Tk z_AN=ed*dSf@vz@qU+vP<363P{ly4fqhMXBPYTwZGmUHTl66Mb&KsSj`A+G07G z-+5W=dBIA8#1Cb)P!I3AgW zj7}7h?p5~hVv#@Nf`9(;e|){! zcK-#+{#PI7>g}y9ky=TG&91!d9=ii9Ks|6jkS1YTXENwG=6A|a>d9X#I5yQ(+pQ6K zcn3q@*@%qBUuiV(te`tnEP03=*OI-J&Bq-N%V)F&U2RqS+^)r(^hnIuh&jw?27@HZR2 zeQOkx_8wZvV*2{7sr3skTv=Z9^=z{DG|T)bYLV8j&kX5 z7>P-wF=*Lig}*oQ(S;k8MJ?je1CnF;YyA%VGss;%>Kww9VCl`K)WvBxVu;jMr#LGj+ON*SPTM53eH{oR;BtU2pBCyTqcC*rj)5EFb_esPc{&JI=(W@Za#N+#H z6s9{!)O3;(lIaK5_m7;0#RpNSz;=4*u%#>>NT=gb#r)9N(H{91kgD6ZDc$PH{-@n~AbQ_6~ zyeGh4#5~`B!0D=k>7=}DVs)gNK$@*IcoRj)Phf5$n$FA6dKz#EhFQ)SeQ8{nmq$w7 zamwf(-Q1T9uST+pUuFPO)=(kXd`{B30CT}~6J1|7gU=gqpR(p;nMHV!;zPR)S8DP3 zZXOD3u2{lxP_lgpg(sl7@5DkUWnWQ0F=)Gh2cjuC z{b@(Rm(&J$M}uhq6X#Bl>-ER^($!GzBRZ_&3*OHR*f))m!Ojm8I}5S1)@18qsc1%5 zjh6#Z*Vh@}`9Df4CqPj7uro_!S4{}XqxK^{yO4-v zp$XJ3LsmC5b3G!x?DOumD){=zV`CWx{I#k5+IsJ8suu|Jv{Z(eb9s-sGn#8&ClA%Y@bDhC%B#b z47$NhqR|pN>bmexV!0CCLrJ`wJBw`+bGA&FG&XwW2V5J{hz(3&Vo2{MZ0@Fz_o4^K zy|AL$;==FwIHj9%%fKS*A&|;$e4(DSu}6!OG*&|HZBR+UR&4x>TL`>IB6g=UG^fJ- zJ$vdbXFP&f(Ih>W%GFPoLyRyn=B+0&%D~|?9aJRv!^2|^_@t*#&zIBeS zjT5CSabH?Kz6&d)LNiDJOp5{gr(tL$(0L>`zzy`ndmf&8BK1HhW(OIh$=GA1s#N?G z`qsl+M{2#^?p`OkhrewkN;LsPW00ULFBH{#UC{d+rX#FohtF={$>YX$Z0c;~Ys?<@ z+#(s$!CR`0!V?+4Dg@9`hDRtQMO&WtpUo%^iIt>ku{E*bcl%|;Ed=nrpbK+KO5u5- z*;qb)wh!t)tQT)*-bh6VH6uWf$Ux>;YXk@~qn2eq5uj zzrRV7e|{I9nRU~K7;`$#-RLm^F4J+w)%5(GEREwLLxrH?KBknPBJ$*g|3NW55rphi zPc)UU_O*wJ4#3%bVrpaj9SJ_@1Z)DOBt~l`q@4Om9ef@n`Ns8T1Ch{s zKdu&ap!Q`tIRd^@6_sL@@I)r*ILL7D(RtT*Bx}GxmFFgiyT(?Z~?7OMN85jvmeAvwvD@>M-Q!v*Af#z&4jF}a^-S1-Z zQJ477zqko{mh#~`!z=LFMV7TRHBS%pUNpmA=&z$U-^blZv~ydff`Xf|dL!x+yJ9tP zkTqggkxHUdC2oO;1}mh5PD-aL)!ip%IdgcZNxfW7FSuRp9&otb7QN@LxCkM9LKn7e z4Q249S}K**vColbHiAb(k>6l^TrT^q zw!~}e@P#bKHD8CbbjxRKJfFoqZ7=9BBQG_-nZNal{&KTGmwoOF-k!2rjrX4N&zRCL z(=n+IrL{tG*0uiX@dqfnR$c?IP*XE-S(edhgF$Ep+nD>Ji(q-uP-VkNxP4Yj z(pkmdbO~xB^K1$P@96rYt37)J?Gu>Gm|d&1xDUE<6gvL+;SN=G5Ab{Pvg`c(<^dvO z1J!-ibtEY~4t>^H9Y4!&A`I?#+mf^Rub2|AD)O{3MQX8ks5$QxrC>Lfc8?%ot}q9t zlqVZ)#HEes-+%J`{<-JIc+>y`c>2=Ji<@!!!S6#S6Ag^B%bvoPX!H#n z%oh^+l6EtTy}96D5YWozz|!)jp} z-$3|CbhR%=vK4|`M;NF$H1lIKDUi}0m}wE@t_%Uiw;&`PkKSHSpUzb)5Q(>B}!LYaCdp!w(KXh-Jc||zN zT%UXS9vYgfVKPlstXfMezt}*JjHxS|$-bp%NR}+sL`KR7R<$9egT(Tsn6gV|&bTET zPDzHNz%gujY;_(Q(q~_cEg<+R&wXMfuok=4NfH)K8Pn;Q+Y=H_l}aBsOfw+;l@dN) zSZS-{C*lpwm<^BMNu*Tz&2IpoI(Gj`r5I?6Ce2W5+sTuk!cWHi2)^69v#aQ>u7FH& z{;N>c8(H0hD5v?L{62!RM619wa-fBtXYn<hK}pnY(tQ?T9TqC|AKP$U(COu6bRWxt$D8Xto zjY&KTXhn~X-$#E`*GkpCt`@Yo-aE6l2Cs)qp1Tq%8UMwSu5ge_9r*1 zLNjKxbtR%~3pg|sTPNZCW?vrdUo)`dqx{;A$Gf{!j$p=VILJT@TwnFATt zUFm9=>^Q*rFE=7^tkq2qGiB6&VN+XdAHT7vbWtyd2Lrv4j@@M=X{mK9MfKjO zds=LJh^QB zw^*9b=tCMOL_FJ>3@N{N2zHwy#xI>T;mdgL@oLd@^SOol_{qJ_M4b`%Vh6Lin6*gC z8w~hXv3@Xox1HM~!EuvIuRaodbh3GwyanvN>lprf_VzP)CzmkXQDLL2y03PcwxXPxw^H#0SSm0Wlb=vxstQuWVPD*?$!&Uyc>GV>dJ}zc_pWX>rUC) zA{*ZKY030U^IH>`{5SQR1i1}^K6~F8eL4=1og1>sL&tosd^n4x6ktBdCGoX`OBsq( zjXmLON~WNpbd=kp65Q(n_Lh96ZDFIYhkhPKHaEAzno_JmlbtIaKfwO6=;?4VSjFZ^KUAP{Ss&_ivYZ1t z(<4B>KsQ$cGrANi`IPVd2V@IY8WC>2cwMKjZK^>6 zxJX~$#WoePiLwzee4XSpRaBg~pFr+!HIyR5E;1jf!K}!1{kYjWmwxPro(DFU&!d|} zKX=nQl6~P0rDiC%|KO(gWHbiNXBhC$q_fsJG9q>Wz;}OLYQQ)fEqTsq0-8CAF)2&Mpin zz8mn$Ue~HWn$-Fy3MWN@<`=k!;9SQ9iuKA#776mzE@RC^bc{*GTM4?Y`wuAtIu@B@ zqTY1uch!;e^{_abP$CbtD>1xVhPPokzDV}UgyTvT^{Ews;#oyS{Zq-`#UYY9rPTyC zy@7YKYSa(C&v}rWTy3azipF3sYyJ#@xSNc12TB8vwb8I zuwluek(HK)r6j2kT9wb>p}OlsEiS}59>;>2AY5-fKSm_7i6#OskhFPU-;CNXnMpn> zeI8`nyWU(z$?pE34)Nao+&%g_kj+O-D8f0+PB=8DAA=7IRLl=Zgkyp7f&&+6!HEwM zLWJ*?+1P(&gldo;e|i(=+E(a)V1xuZ2fT2BXuLt^I*8w{2wW6G+tv^XEt*QFadpH7 z2QJii3uwK~#=n5+fPuNf>d*e-GI%Z(nzNgN_}BQrA3GAj=G)LVqOn4miI^f;%|uXcy(~l;8hCdI=>L2!La0D-M-OrI1pk(Bwe?+otS3L0aULW$Bic9{w zeJyp~iU6DNT6WEF#v}TY!3AG&a=^&4QQ_;DAW|S|5Y}YV;~d=o)KR8Q=aMkEl^=fk zrj%PgUvt%yhQ?XP1~%I-k1^aWx}eCenw;z&fPbrt6+c`m_E3%Yhj~FrkQktVENc?? z@Wn@PxObW|#FEaY^hnP-PWZN^;}`yBN&iM+fEJ5O4jGIj zSTkwn2Rpnt{t+N;APPX|6=Cac4OL$B ztvM71X+1!-Hv5Jy0R|TuPJp?@N$!X2Nct9Mbba#)9t@# zY=(-r#qI28e6kiPaHdZ@A|I#y##=Ob(lu`+9b-2C2{a)Q^ufa^De;}@Px?DiB0$xW z>b%*lGbZY*?<@A?rjAP($vFm%nB1a)_xkS??{a`C2oxIvBhN(M{dNgoBu6b2f~O)W z`D-ESP^#2ZLdKfkQ0nSNtsj<|otY_ry#1|rUh7=13gMEtlka5Q^TcrFyi2yydO+x` z%e)ie%E{Q!_J9y*iD8B$a)H;2ZakQWM9{JnX07Z*Q>h$zrADE|Fa9G0=R|pKqb? z!9s4H-#ZOzpaNS44+4piA@01p6T{FCz#+Cu2QVrEHu|E)@!Tn7@Dapkw|SStGQG|v z_qIL_Jh-hu6Y&2);_zP<%<9~-Ea&AVKE&NNZ)mav97r-)?4JoKe-}X%SF1U>Lln&I zQN2V{{*)2_GASY?0AmqEy3$cwld~t0XjCoZlNA^};owoGM+dyy{`K1%Gx?f;>A%!6 z7T<=`HZoj15j&LfmeBb5=`My2DH z9M$26N#&nBSd2)-<_AAwVuRpYYsJ*qMIC4g#cP`))a9tcK<~jC$uHqiPhhGo{&+qA zS2oxs8MBcT2*}sb^V1TG1nTUH!u>E2Bm#*u#v{$EHGKIeoz?d~a~x#rG%ebc%~ME9mCl5Rw{Jg8FI=ft~cRQ0m= zv?)h+nSJ&A$~9|PbP@EjA;;a9eqX)0Lpo3GgJM+&b{QXIxtX%=HxNmJNV9C69*8T| zTIBH^VL`wspp)M6P=iw*wZ=?dNyaH)St?3s&jZ~o00pTPWGYFW04jmY+hiERUl z>+w}xjPqxMf56Zjf_T&gOP2-I5rY=A!V#7ZXyR|=%ekGh^8DqAH?4P)!=Q3|sZ^Slbi!ZWti( zR}DZZ7VkR`W25m%8~2+i@xSNm4dLbR=IZW|Wo;Sm87|un{Vk}BFyIjE2Gc{V9IN^3 zCf|59f(AcUK$L%W0Ovb?p?khRcdIe+g*g!Hwt$gWME%%<-P6@CVn@zXq}Jnn0w_$D3fG-Xh&^2_LR zcL!u?@Ix`s!SWEwd?HDw*T}{uOjBCGdz>UP?|XA0*6O~gx|rfT+PHuU^X6-72$<+} z*Khl#O)?g0teluL5G05(O|W>Z8F^A9>F*w1irlXoxm^D~4@y-V&lh|$Z>etL`QQc1 zcOz#OjMY4Py;vk+kJvn#x*Hzr=jIZK1nu`f`f?T4-^&V%pc6v$V*`3? zY*d-p31f^i@!dhp87lcPj7p5%G}%#%zBbyzYILpM<45r4$7O~NPUt1m<-SZ*@+h3p z(gIn+x~NX{etIVV8`ySn+BlcD=;S9bD1TdcC>&6Se8~m^`zPh*M7Q? z$FZ0G)I7)NKGS5bJ^W|)`bhp=vKm(DQPXQjlv(t(O;=2&E1SjrJhfpO9$O|~a-Yz6HvL$m{Z-s|{?Zg6S0cMR+Mv6)eO!Bcs;j;9wC83H~& z?ICpIc2yq-P=?z1AtjscCVr^&_UTwZIIH_$@Y9|@1t=*g1pu|kb)Y**$rbT7MK^ex z=eYv(CcFRvGghhc(w@erp$a*$WA4D1E9T7iUNTp`t=Vwq#T|vP^@7btkzJ&pHSPwg z3E2wbx8N&=cMkaA^~(jtI_4Ykissvwx1KBq*(?x5XvF5YcvRWkZZ#~1TDCv)P?D00 zCS~)_7nP8oRYeIG?TFJXUKZ}~F`u1_EXFz2j2iH}n?fbC`yePk_1~$iTLB#_&?JV6 z49sNK|A(u0j;?e2zK6pGZLG#N8{2AZtFh5Eb{e~}ZQE>YHMVX0ebRgH=l31&KN%Ux z$vJuU-b-`Mxi;s>n|$C#J4!PN?;`o2-D=JYeD%xUWB*>pS(>(az)cn864*(=j!+0R z=}*@xb#kf}7qC8R)@zz=+mjGxMmcL3bvW<4Oh`QU&UvAIB@@k~6<%+kdm;bh;lP`} z=B%wWMu-&-lzG{sn!nsT&ggL_S^0EaBI~*OZvV0KG3Z>idINlKLP955ffW$Z!&bN) zW#=I3v)ZJ(G8F7xkqj=syJP(tQNoKM3GQB(w_|YGzFot9Tb08&=a8#0v3n$dIabz# z&{oa&3?9)1wB>m}5L_YteU2V#Fvww5xAIncFpVR?XuGd6qwdEmPW#ZlE+83v_Y%Up z#Cin1&LO1lBAzbD)BaL}i(XNhA(7Usi$~&s^@zL-J85kfNg7!ZhBmLR9_)4L^8|jx z9x%13g@PRGqPgy?Y80Bly)kPoAn5B`Hq{l}=3O$inb%!XL4>)SB>v3vR!!14hBO;G z=;pVA$Qt-wg!&{3@=KgDd;j{jGfrk>9$xgd@7Bn?yRQ7(FVqbi zlI~m2{;i;ZnuFjLaX>0CG%(WD5jCgvpVqXYt0{Hu5>NToM)t%hKQ^+S#xjV#YMh^a zORrzwvg@@=l%2OBsjGFln7syz`BI4o>>GCZz#$V3Uaq0fihoNdD;%i`i0rP@wr z6H~d6?ts>Q#KAI|u0343nleki!KGeRWT!Lta8)GLI0GZ1E%Hg6Asmtmid5Z6;rB;_ zyO+1<}Hn|XW+0H z0hp}0Ni-DS=T~^oqT%tU50AP$4SydBbwsXyS?Zxa`{HKdqW^Ec5XN6hOz>Eq^4?%V z!(w_qwc~NXjTp zFV1fessr-%yIDi$pTy9|IKK_!KYOgdw~=`J8X_FO7mttH8rei>8-k}`R&ki#MlksXB0EzIjAv_nOuzwq*;X2BmWkqW(U$6)(Bfk94Mrspt^yd0NI+ z%7ZI4BO{S36yLB4(7!0SLCtATajdQ9&@EJuH!9<=8w?1D^FK|XS%fIb60&G@{=GD( zmDKtq82G<(|Gl0M5`(~!7B@vDlOZI;wcezw%LO>0-$aFUu#k}<)W5S3u_g7v);ho- zdBdt^^Rh{Yyp;Q;_~jA<)E@9H7@;2fUn|C&52s?!%Yl_+vA#W&2;WvR7w2VYfbvx3 zhch$Bkp(A@`GJ1tE28m2APBpWR0_j-bT(%lohmWLZ(r~4UI)CKZ``LTlaAoy{p(~S z3VrA7in?A~K{2X^aAA~=is>AY55eOkFi@9T0C%=3Cd0}_?ylza8-(uPs!R_Wl(ISk zXdK3Zgbt0(pRU4g)1%XIM8|1`H?JeUEagSWsMBj-Ccq)!>M*Vn_glcl+&Q;h$uphN z#3q1^as~hR*ng^RIy5F2At%!N|F8wLB2^gQ$8v!aYX=_PNLsMJoxRqk_s*V3cE4oY zo1@TpVAM{{T)aQd5}rxl_(`EuKIRj)m@sLjNwjOgQ4`HtzFq@T(rlAj-*}C4PUAl) zCQwsv^N`tCSV~iM8-6I22E)Yv-Q0|#rfHxe{R6s;%X@QYhhl6s1f5SfAE1IJqhFY} z!1ma+N(mY*iN@kjxfM-Wv%R{1PD{RJ*FWp*!wKDE{HMcpNUF-5JpAub{^A4j)Y{); z6?XAeD&^Hn5%taBSMefB0eww!){$WhQtsi8mZm4tKBGDj zV4)@`y5SgLj4*XbFnMk#4yLu(9=xqT9*PnBzh0t$G90OLrh{VZswe%}3&mo2Q=e|} z*{6_yeSb1X{#(J~z;uCZNeR(zbItTp9phsy8?$D0Gp;H3 z`(KC=FvY!s&gzQXTC&}`LoiXh;FP8J^?%y4U#O*kl$N;~@E3IiovKba`s}kWsCRq3 z0E{mTyvERuAD&%xTJu0Maa32w1R6F)K{eE|A85528DbBKR4`)hg4$Rt6QRK97~!ui zDFx(l%Q{1m(+cbGxb#!WIeH>B9v5Zouw~#*~n~q!IyE#{#h9XZCSbSkK|~3^ifkkLRg{W96NqE6i?i zXIaY8q^u~*aX&(En#X5TE`6%04gTXM{Nl(r9@s#Y!Sc8jwDKuza6AwCa{}f+xSgOk z09YV;4^Z`e03}-B7!bSwJBz!Hs4p8(XBTr!k{`*6n-nTDy-~|j#qzJIeWcT}xBG;Y ziNWa9D8$67pIau?82P%mlK<$+yR6_!y0sOA^&Ad-LJ<1@KEa3I_ouJ<2fNm5HOSK! zS4iu@X7Zrbjf3xpe<(+in4rjI(?5-ae49N4Zj8=z>W9^ ziL6&2Iq*7&l=fa2%-5PtS2~^PNTqSIc#`3QGOgTrrT5S>Rok{a;ENfJF71tN`P|TV zUOK5ytrfKt)17B-rn2JYeDM7Mz&e<$0&1JC^49;=WHji1|~Kh5I{ZlXF>X9!P|MUE8XvYghd z-x5X!hgcnY;`zG&tpfjDfKGN`0X$M|KoIy`A%ffs&KPo>oI!}kI%b#V2($^$Tgn*l zHBZbNZULj@pt*^wcBS&Lc&t(rITf=ZwD>X>8M{G5Ip3dBQ*jV!5PtD2nm=g?K(q^zW+S=-zJMs5I=xu3on0QC0d3? z{qsw56c6<*G4yYk(rXkm{HMhDcXR#lK*`Rs`eRulNWuP-;uxe0k7v;sN}*s!%Pp{a z&rT7Wu5v)^-=aO)CjH;f84v*0nRrj9lC+B;iW{nT!9uS*De@O*uagJ#k<`0728nnO zL?pXNdL;rbn*IsVH4-!_pM<~U42XFed}vQv&AwmEj~`P#ozy~(cpQmE@5HC4qd7jf z{#X;F^qB?PAKC8cIc$8h89RXX#OF2pW?)>^Gcw!ZgQe5|j;k>UsD|_!c;WzVA8k6o zfk%>zR{Eu{4lnolYhIFgoA7qs<4}q&+N3xiUwb|}6as!P&=A2t$d738*c(erur+tv zSg>pGhl7R(9dftOxpr_Ty}DgT?GdkVc8*T~0AOIivi{}vpuE!@K=6(L%1r&qY!P`A zE^Hj!cMFJk>QQ+V=64K~7mKrV8tf0)0JXGLg(mg#fSiP;EibOs0|;uwf0_rr909E& zfC5O!|C6)Ia!7&M>?S**lj1=z$HG3e=v_3PXI%nPs0ZYDhmVOlmc(_h{u%~o8vKNiWu%D;Tpb~hXoOk&ZPD5(iF5u5a zaII-Nc*`(-+{nK;juKAbwW#m@J)}W8@2IBh8Ls9SU`88)db15*7`4t6-QHOdG`u2$ z6NPs(;txcbtFgGggzAw07(Tx+aVPZ|l84(o`(H3r7$P?AKChGYk*E?kZcv}=-6Ilc zAhO%-wwZp3I|*X|OjT?i?wfr!ijO2lz(pT^UE5)fy{Kg!6j)1{3&Fl6LquXsnJ zZAUd^8e46Nng4&SNc^`}e3;2{lDp8NHh*>#7Rtc%kDD` z7h~AI-)mZZ26V3GhHGvd+h+R(_@U$9_vJ$@!-W^I5i)xCtd}B3#okaC z`T|Cpwf@|3tlP4$o0jnBlz|E#z2N_YRmb7!d*C0oNJl}tw?O8fx?WGR!$Xzw)D>fZ z=XJcQ6P^e!7mWZoG|hXLfad!$eK}H;D*1_X!I_IY=l3rWl>@&Qf6A!BX@sYni9A-q zK@tIL3;3z<)eXj6kp03exU}j|Nb*fqEq_E;3h7oLuIu9nd&P9^f~u$y0AbFuy~+m} zy6*O$ou&P(-}KVCW%DR&_khs;i-na|Vlv28C`(%T9?F#enRgfz46SQZc(K8;gYZQ@ zDWasJk;s=8KF2KS!1m%?9w8>AxSaKxWPT#**Fjd?Kyv2XaHQH6V@`s5;{i&?=ROKio&I!OUk23PPGpX zjk2n`BF-b@u|-atA+^s#G4J#TI?9#`_Kb<-!iH}S*Ev1oHB!1^yZXI^piGer8KO%- z-zkC0Xshyy6u4k*RO=^rxnmx`M+PX~l~Ev(#dE31V)$JI+Tcr}j3j@ZJtvx#=-0aW z3NR~pE?5>qN@00_7}^7E(_txo4MCRgM^6(wI>mFxB5|+cPrb6D&*h!Ep7zMigXZ-NXkArUbFEe}WU95~Q z2MsuVg_lT}9x2>@;0(MC<@JPVQF zfP6%8*Z_;MIx=&Q1f;E9$D^;<*YfI1{I0wEfSCBSKZ4L5O~JBNc$E4BqY%mJWe0w6 z{>1?WIDd3!vN4e$xSodc_|QjJVY2*EI|nCJEoRuKPURnBn!E>t~0Z`)F6q z$+3SVAg(paTd6^Fe(LVnNblo0G*7e0`Odl0EtkfyNBDdaBMWCr#)i>*;_tqAHL>1& zJEMKPCposF0_aM=1y0{-cf1v3aGsaUJyo8bBrK<~NC+Pf`1j4({fA7FGFn@4QRDYI zsCpPHZ7tp5cGWz2@loM^J4j`K{OpYX`P{?nH)B0$p42LwcMs98An$wP{o3)S-$ySw zFnT_i99%MA+h>s5@VNc0L7-fNzYHa*?cnP(xz?$un_2v^MUK~O_gAc7TVGE4sgo(y ze5tamd0nmQ!GKn<>Wrew{bb6Z-MzdA5bC75V6jLwN%+#c(SdeX?%3Dp(lNIk%51m1 z1=YRueJU7rA>@&dvIK4Uiq01?aZZ0|MDBj`(A{N3!Et;DA=8fYOMK4Py%} zF;b7j13=J@PDy=zx+k}vVlY=ilPA8(FUJN{mY+h*&L&Q_4kRYj6=W@LIS=jYN~iyT zG{;yD?j!!m{#l`t7G#67kF^kcVb8y}_(F zo_yG&a=|Bf8vBvcfKP!FhcC^gfo1=Tuv7st_-uHfdvn%P$*iOW^}DNZYHN#_uZIHi}CdN^$0(2r5)tV5>x42(q(t;%!}}Ux3g_FCIJVyiJ(j7 zv6@azD!gv1%Mqg{T2LOF=whv`e$+4;p`FlW_eam ztmr0wdcvqCxhxmk1ee1A&nB9T4{rV2WLhB1@927OGYwSb&#hZ7(ULK%)Miz%AjDtO zu`6d)nD8-%Ua!H@bsRHtyV{VwD;bs|ai&QwRArMvymD{&B)onGX1KrtNe+vt-F@$I z2hZl*3b`Eh^9EvJ`{dBsmqbI%nm_YgDVT{lSGLgDdX zyB0}!jR(%C7~^e7#HaZU;4QCbCwS+XQfbrmQqP@GUw?keM%L60&O{jtD?VIs&`;u= z8f6eklUMPYx%AQPzpA0(N#G^8vXm7xl7>lM+}>*dn%9Q2e#SM`d+fZQrp%(npTX5D z`Jy1H`sWCr%7-_Ir1#6$jze%1O`SwT?E<2uEa*ftez!XaAm5O7`mwSf`-_)VgONEE ziWlFNz;^l#qmUx6J=%oIF}=0Rw}B*pMw9J5qEDjPGYpL zuu()Uhn&Vr?#wlhw;78~g0&=QCF6^o{!0mEj6{G8WqDPNDd z3z9LcM-x(El9YXKNNCW6r@(nq`_*j{xMAaemGsd8gF*#U#IJHJ#!ZRm3ReR*)Nkg> z7|p3y6^Gw5CBQ#6h5QG39hZ{JGWu6?;Y<~`&3Bus6JBgev`)6u^g|aS>0OqK`c)WU zfF1-oVQ@h%L8JzhV%w zSWetdlsjCu8I<724m4+j`LKpq@lB2& z+s{J(_if2%lwaU4u4h&7&LSlSd@2T^;Y?lYO6OHtZ{^dQ#myU+iMj#W^mAq65$eFCnL+o1r*|bm#~c^=X0mX z!d;g$0|Mw_&GSue3WN9T=`Z(Gvxo%9ZwQ#D=uKW#K z`VzdkL|2i^Vnykrtfd`J(Xx`eTYT3g$2?xDeb=Ym9o9ht_y(ZONu&_3VM||=d zgPag2*RbZtiB;R4Dz*6?TSNnV`M1B-Y2U6LfIRUNfN2}Y7JePu)}Qnt z)*OU}2mso5y!(;w{Je8f@4*%}GOfS;27W(+OyJ4|gC*iX&TvHPg-`zwEPSejyjP5U ze>Vf7%2+d61h^M-$dgL(g=HGkJJav8n%ov&b2|tTT%xnJzbk!=96!I_8vVAxow*Ij zq(=}xmo0_8y`EauYQ$VRrX186nZbO={kM8aB>>=!eeAT*5ZKHn<=)jL&56X6P_4Mt z*ALju)KpPR^VviDv7ur^D*VCcSNB1@Fc|F3?JyAW9^Wnh<%hg+bOWE&Q zCQe{&KeIvA2W)pgqF8vuL)~RRM9Burv!rv`Ba*|HUe11LgsI_17NJaW!vD<~$>HLJ zTZ1LU%GnX{$5iYKW+mVDFGP!YkAY!#UB*9TcXkm5>ypLv9y&km-)p-b9^h<>T|wt2 z@eDe9Q76lPvQL&MQpiXSp|XI)da1gDWUY<2_Ltrg6UyV*PJlIg(;l|`gj2sUwH6@6 z{NW|4NJl&uU!%$zDEeUuqsA{IGo3uL#}Mc!vGA$pNtIEso!8q|dwa0q-p-Kjual0UGA*Gc}Z`mM9? z|AE^T6&ScIl;UgOL@SPt2Jk8>a6}E4QLf)eSr|O5N3{S>kPkqu8GI@{Z6n9DsVEc8 zuY)b3N_&~AZc#6%rx6s%k?vMqtwG6K4{$i<4G)a0bsHNVP<~+TEz=`rEVCzkf-w1Z zB9P~aFpH-dA{>cEt6npQP~(Gd&;N(V`xj?~t?gkr8#vj8@G?-pcj&EMa|5^^#V@bs z2x~AtKZnS=?8Nl8pC!K(0oVje@!PcXZ5a2`_9YQd%XPJBkYA`Z+t3xCHyq)}hvS4= z?4-oYsbg1|Tdi<%-{gIB$;oH0xe10GbS%Lm_)KRPj*yy$Y@>!uIoBjAfs#OMR8l__ zo!GDeXsV+9D@pTzhb-tpY$5{QET`>&j&U_2z7G}^tr)F7r{0zCR<(doU~#})koeZ^ zX{e-yG@*;CtUW`a!S8nQqG}rt)<>qE;XKgUkACbt7V-%iyQIKfzboGk+^(w#7>e{MDA0P-%v6#b6u0R$p^>! zP4A5R2T{Y;{H-lXbGgUX59_e+9Ue9acBSpYGv{|5DnnjUl;#=~eKL`iUYVF~LM73f zwSaFK+KaMaS^#eCqjgHt2Wbic_9-5%^m|I=fHxFyp^mxF+T~cT9=QACYw~a5!t6K+ z&%uzhbY&7oS@-MAdV$R)QpZ*=LY>?uLY0Hm#0DTw8( zvOzom$IoLm<1ilVY384zrTyE5g5)(%_XVrtxvn2OX6@TxAg{vnzG6OP^0g5bW97Tf zzA!h*T0NwP7Q_^C^=w3lgx{KrX>Q$Ha%I1!MCaaC{ClKbk%Geer7Ipop&giT|b7$^Y7*N!qyDtU@ zjBJUd z@fzkg4<=sV8`r5%ip+}~G36I*V(WULhGOtgsJHE%XMjVGCi6tN&BIUd`er~J%K;FF_L-rVdvk$ zOS4B2J_z`~S)4!I@fEkS+x#v)^sI&F(w5o>^pESSVrKqrC{6Ww_ZoGj5$-!qYRhkH zhw#~x{CAZGZs5Ld$|u5QH_-5UbjW4aJAVnHUj-!&e{?o~#8tSYevthAVG!3eL2^DQ zOj3?tr z7RGP7fdUl=4x?Rz?#jJl8v$GoeGGTHpVf0t1xMDJ-Zazn7duaE>&4?n_vm=aC7e?M z^^6VUE%XZ0!SS^Ex$t`kH4f#|4e=_Y5t%LpPPx!0@=YoqL5Yrp9}mVc>dZ z*x#MYbN+=WD)9)Qhm1U>Ya>*qLTfKfA@ulMT zg!NV>(c{Df7#m{{-WnO)o(tPgaSfxJIb^$=UhrMN^Js(>KS=O3PZ21=}h&bQ5 zr@Pe6@kyb2NWNtk#=;sxO*&EeoG=06R5=AO(3lAR?1l7onvCA!wX+%7Yx&Jf03scM z2cic%b`$NZ7rkfpsqnnfvb@n>#q4IAB`KlbvKm?Y%NrA#!a)?JI@ z*~%Yfr1E}zI%&$WqW+FPc5z)tK9?i}+kWW@VTTvI%}LxE3nFUx;~1F5F=Lf8QJ~WM zo@XGkz4r^2m(90;Qb*S7tgQ+K)t^jBOkf4Clx1?LQIQxRE@EDMC3l&mUpcU+xsLNn zymNkIp#T0z9f}R#MwXk!B||(m(&`4_r&~60D<1_-Ad&8=hLPQe&AXk7;}3#G)Z2z` zL|m=Its7GV!Ym&`6@BKI*!@-wUNeEDDT43i)X~3(d__Ij>9L_1n^}S~{$#$OIH4VR z76^g#2bpnBM!g;lEZ#2^tB+x`g;pd_t=$&UZee>J0 zK!9OtX&Ket~5jy)`ow%>eI3HAn=qWcort!F;erxWh9zjS`od(& zWWtPx?|F^%>fDNf`f+6q7<~X^u^F!<&TS;|GUw&;`MuYY2Mjg-$S&EzRho8O;;^T) zQnfcS)Rn*Yrs)*-GUw)*v!u%Gy(@P0Y0l0&I}f_5%M9l#7L`MNTCJsBe9%AEd3z)I z%aIX~oT&-v^@gCayI$`X7C3y_ks)}1kByC8ukHvxU0dn!;DEXpWZVThuI4S`UBFcV zUkpTlysAKf@e4=Y@zu8mrP{cosCvFO^IP6U^LRWmd)_XA7d}7k4|4IWcWb^5TYSpP z1}cltD)o?Yy7;(TM@cZL@Uapto6|MAjm{(ly;ny#x{k0*JSeYEX&v6DcYMAN!Q{TGo5xKqSH`uqwG1x!EYYA8 zjR(U{>&Yn{i2MjPlaaD%zp)c|yJ*$#oY_98P2Y6|-dhOT>WCoQiDBcwOH4y#uK2bF zc!nEFgJJk_7CTWw4&6#7y;9+TxPHN(`_4(UM z+};Z$n^Lrc&|g?s!1Ph^@6TPIH*>ZOhAaD*kAF&X%3LDoCWUf0-)P7Ekp)b6k@8>) z&;v1`mfIc7;q|c%V-OPx=mclk|2jCk_&M|14KLGnqJkIO(eaxKXQgXN=-M#W%0GbQ`Z`_Zb1MGyO6Y4* z?h!!2`5@kaiJj&E{<-L&UwpNkjd8Q5HQ4_9T-LrMXi=*B(X)ApQC3hTSvL zbcqo!zqK<(+ekf9^9|qY3noi#De%Oq@9o4tPP_o8?#XQ(lY#!v&r0BtxuF5-94??= z2Q?YTj2y*-mkg>^40EYAaYx|jrmCkbX+kYVVsIkX=0wE#_9R&_JlXZyjHihrV0n_3y8?Z?ZPIZp%LkYXMA37Yff@zIrKXUf(-~|FyJ$CG- zqmz=iQ%nBQtp6l23fC@(RQ-^Kxqa+M<8K zZ1_I7k9rQok?kAgb6GCzWe#lsQTLIlRnX!q>LJrd%xQO70#XOgN~4774($b!R-~Qw z7EFt@_z;{5H`7vT$-fv>ra!>BvB=WTq^m3bs4c@$MWc%3YJ0ScoACY5mQS#m=Nn>P4!_KGSH=p(YXmpvSgZw&L@G&0pL~kN-sGpJdAA9l+Z$;$I=t@v?mtx?uD(TCj1&1U!uyX@=7z z+u{sj09ca;jsIWXRjVtFku$A!1l+gJR;|jO=X-POwq*TJBXxs`3}zvQQ-No9dfQVj z>w*a7$=hiJQsbu)$$6&PJYcU1%oB65$4v|=3X@Cdn{Fxpkr2*S2_z>CXJvcat7Oje zpit+4NXoASq$E7W)~efB7M}M2HbW!flBYy$n&MPC~>pC1q|0L^8D zUyH^Wq!i)B3whxAELXt_u3xmy8nM@X&gs09u{(^kX6;wLBHl$0sfG#$=Ac%u+nNld z5<#_iRsH@@8bAh>$)70w-cR>CQlr#qW(bQBv(TP?cpkmms;8&#F38Y{J>4M1a?P~l!BLU% z6H!bpj+oQGX!VX063FGpOrkE6zljK#0KonrFs&-30~0=Vv~ht)B_%;ekkBzSgk(qF zOaF01%YHjVCzS8;l2X!&Oe){s8;Tc;O!?5f&AeU)*SJZh96-GghN z9(Q=~*5%QEqa$bprgM-dP;~x=EJ`my>=4rGJbNZdulNKZe^a--J(Q z2$O~jS#!jY$y`(N)rW8HiVzNtC6Z1Y2$wl)^1mgky&^l;k<$I}r3 zt^55^TllW#zdW%Zn0E(8W=$;Xiv&#zCaSVHLyUZ|I(^Bl<9wj{E)FizZAC+Pn+6XU zY!uv7Ro2j=zBv5S_o`vgJJWPY+g$B8LuZoMg{lZ+iF#?f%4}#D=+I*)@9BCjBGqn3 zMn>AdJJ(_d8VB{B$0P~^LMDUD`pewUKI@2TYK@)e5-qFH!t)tw%A`$;5H%s?0Iffm zTpP(L>|n@=H^kaTb{xMC3Fd3?7MN2INho^^cQ3aLf9s6ihpb^A1Qq+p0Xn_Bxif-_E0L=YGd>3tN^W1GpbcV*>*`>wF#6a%E-Ep*d7Q*^gLO zapK066SN;(T#OR+K@_#jD)@{bHPju@4Rhm+jq)^#RJUhX&2>X_Uq;qL7X`QEQob>Q z&ytydp)u+~A05i*S%s?`jUs9|f%Fa!%cr)X(dz5t#*t{FzvHz;I#zSu0VTIQThDK@ zZ*PQ;(Zp|jSYsyQTW=0G9Ut*@qq6U24`H-ILd{5cVW)P+vql&FKwy zzbR;<;`DQA(2R=W-x{#W7X=9)+fKmZme|L{5FtAgSliW7QUVz*qq<#P_3c~M+AhAn zWt*SSmiJliLzh+fcMcys6z|JEeI>w06M{t{tEhcX2@ICNU3R3ys7oaZP9$y#|JbBN zpfSCmgo=}%&_Nf-N2BEE0nNvnc_C_&e7IKmSnOu=!@#llsczbVT{E|o3p#uGN`vtfm;d_`H!a*F&91c zGM0%6kr6i*QR+o-tDBkwCCbE$VF{m9{lGwpCyn3pV#@Bb@`t_n@NFw@;Y=GRs%|O4EY&2|h+58TCel5fp)xaKWg2r6_P*L%hc^SW; zB-b&l8+~m~87Zh4%nakxKK*}OfB~0BhFjVsn%ir6bSB6{!>5?%--`a9e6SA7Urd%S z{g=*V)~+%?1sob&hTm=UZ9~n>=*-QGmwGq-@KyB~pwcqL*6yc_h z^O^QN+)W~S zj-LeJOam7sW_4^}HC*qaTQP`T6q)J>d^+fw;)9c9S0FdnH|&-0y(umx^jr$Nuv= z5W@XSvAe(Sp(+qr(paI$xc*gP3~!-``N_%RcE!`j00Qw`1L)zkq8IQ&>=H)>nHhT& z1pkU{6ZIrPR^Xm5@i=g%%#6QLcs4Xoi9`}9C0DXHZ_;cMVN0-e_3mD`U!Nr~uW~REan#_v-DDj+k*xaX+FdKOJb9z~SWn9&C zeD2m_LSvlg3F=Tmz}=jzy;|TI_5_pn*Fo_OfsNRh%Vn)eb!YpMaogqWkJtPGn6!p5 z6+>;dg!((F!+Q0QZYWR)Dk8ntrT1^#$q<7M)y^`Lh2SJ;0uhQE=8k8-EIHN}dl{>l zSC$nZ?DhypmpYsuaHnD6oz2AUj@0}tdvZmyJgtuZtcg&LuCdCrL^i|E>wAa%Df>nU z4PVKP{bpY@f8tk+9pq9!lTXW63A!}QvWma{gXgE$-KTZDf`{<@X4060m(4NckEvdULI+Pt>YH0 zqX1O0zDEO0|!N zX62aDWIq{Q%v8_?yqEVJa9+5A)&O+_0QV#anOkYCKJ@JMhVq&l&>V;yK)h~_-zpic zTSF8-tkt@RzeaF9H;7mrcve%ufI=Wrgo6O%RU;%5=x!WmwX5+|Mm_XqvRt%8L3|it zj$MDhg#R`wZY~csYDj9v^W=;K0kcQc+x37~GrXzjG<@4K*P4xefW@83Eo&;cHJ-v7 zaIuTyDf_a=tBHg|35dSQy!U>-uYsJF_j+3+LXk3op6^+FLN`_lt4+MLJ6su0 zVZ0K7XTIjf++D$ROaF%-R15U>Hfr>_XDw|``m;89Wnfsz|E(np8L((r*b~i1V}Im( zb(XWT4&Yf9I6K<*AWw8|TLbbrYx^BnaIDXQNy~H3MqB-rm-IRLN)ilrP=_f0+m3Y~ z;IZ)t6h$y0%VqaB`@EB{iq-NQu<4Hu9R?w`XQiI2$&6@|>{{6>80ZMR`IFwCV_1b( zV^@O$4_LNBPf*{xLwq4uhL1icJjNWOCFWiaHRf8kjqtLgn`G6%zLiW z$9+U>Reb=N^|(@ntbLgB>$@T-KRV2V(`Xn)a2Hyk$Hkq%|m`iY5w! zY%I6UwY-&rkY{O}#Zc8l5-a^qz$O=fw2a0oCR8KwXU0P~>(#}J*3doa8&B)T2^w=q zebBQ%R$hrHt)ycXNsk|4jV{_wqu;N;ku%S7LqX`suU0vHnj)3FUbAU4vhq+bVwJNw zffXj!EnXR$WCGruqVoHW1Pe1WsuXp9ugIOd+}ZQt=y%i;wO#vhp1njBNf-#=!sld% zrG%dEiObqXj5wMOhOP=?j2M<;)_055uFj3ur=+g-n=N>=;>v&RqmIV*rFo&Nt7UxE zCVe)?3voh-mb$H^R>qvjxgy3VKjr=8XS{EU6P?E99@!Kt1Y%-dXI(}|QH=rHbq2jD#i&!%KdPC* zEb^pXZqlEK)BbL=Cg9L&EO&BdR$w$D`EfrsLhj4>c;Lp2wj4p6UFC1}4Z$R`6|$<+ zGng~e>uSvALftwZ`E1)AYHU7jadO8w51SjzrYMddP}=LhNo%r=)CqeoiNGWAcY=dD zrd)s|Q6W;~cx&38qAw>@nX#xcKef&+N6ktGvhFw8WK5*b)W6>Ll*SCc_SZ@3&OB^m ztCWRC`qe$`U?<1^F{G1PnLzuB(LW+djclVolQfMr|9LjCO-l3P-PRuQIsO|GdKJT39A<`~(lu{Z z*HuSI5m%*??_nqkb*W-yrNE)sq@-RlIkho=H1b3S;%;Vwd@+b04kmHMIDWO|>s|S) zAlywzIe{ELSm>#x(l!%zHD?O!s(pot(Wape7)?qN1~!|r&U$tFN~}8P)gR0TbSveh zv0*HC(kdxqcPVqPZNjo8XD#wFHyiVPBYRpVp>-9aga7<9;8-EfbV3z%gCRz$lfJH` z%edn%?CKofPDE@oCfRd7Y+}`w>SUc8VE-`M%x88``I#`na`%0}=dZheKS~nbMoe+h z1v+Pt^*p63vZ=F0QOuQB-*CUsI+M`w*sH|&z-TW&RMxroJq5@UgF(9=-w|s(w?~5g zeT#LX&XJanh=X+`l|ve2C`V2CqqHT+xHYrC5zJJ_?M~pW%JRmhFd&L0)_Ek8fAr%z zDJ!R#(Y*Uv7{ED66e^ndLm&?u(&G|$RLpgk@;DD@$9UWHO_jM8LG`Tq@)m$9I_|ZasrJA7VmV&CXxmdJ^ zAW^02z}0lJU(~j+SFgaXl?fOU4Pw+1;Fhd`=y+sYct8QBOi|e^v{%4Y8i29f;iaQp z4fPtV*Z!qe*Pt7BmNjdZ-oF0(98|Rv!4OY_(GKEYlk%zlSZSGm+@l1<+8reER#LVr z(Us$dtz^t=DUBE`A+fTAA4Uzm&uBo5X#XJ>7`+sptcyI7;#7utkCEp?j(ms5%5+(8 zfAyQ5_n-ZDrUh1iZu3td2pB2yd@=EKOtAJ(sbG`lnfnoW|Its6@3ChMxXh3##oG6I zukO@hm%VD-%MpCU9zkKm60@0>Y1rC$J@8L%Ox9P@dZH6K$ypai%2Zk@ASp!O?Oy@5 zi4Ta}bK`2$iV)^9og>i&CUY6=?U}DtIK~3*AKR0F*GY+k0;#Fyn?KHm_@mqR>2Uz=>t<0{dlQEq)-E2eJB0=o46QyQGh$k&>*< zw#0QhajFEa0-1X{ZXExI#$rlw5K19$*ws;S_nV4^=D@ZLQ_<2x#9uS<)`fJ|o2eic zYB8pbS`a*MPS-FtmSXRE!{_~&l@Fvo` zR`D++gnttyLVKsh3u4}?kIz6r5|O`i4cM_) zJbVo{1fSb}$NdHJ<{IOrJ^8RL+9rV(15souay_>u#T_hxQF|nYmeF&dlz~9B#UOBY zVj~i(gW*P=o=}U?e`%@XQE2X?*L}2qSsH|jOE#ldy1aSg&TYu=upmuJx@SpwTjbnz zz2RJLG7X;PohaZsZItBm+_JeD-WH0}lI7l#hYu8dt8aXdYy?q=1kQWpS!9sN!(>2; zb!j{JcvsWlDLc&9uFTiESmCsqPN#O-R>E6>;J%MgR@*0XCcC%c>YI&)i-m=u?$dJM zsEO*#EZQaM>*ZgnNB{ENT8=|Sxidi|yG^qp1|Ab<668`gc0$%Ie zpWb!!4L2V~%QzW51l=rchH7s?8%{2)7gGi^Og&B?w4P#NH_x7OY{qU>E;BGEYAo<& zPV=n6T&^y2`yHIA5_VI8vpe;Szb^??wzHP1$xBdUNPm+7wMLMxr{8dtpr8=Dl(y#g zjgEoGPZc&3r)g8`)WPbfKdMY*Ec9{~x;r>|mxQ>O8QjY`u_USg{&BIyd*T-m+D9ZO z3AXp+vKL4isaj-@1iuxzb=Jr3=EL7k+h6l*6`8@n+oT(e>j%BXm6q1w^5i(LgZ8M)3&L4e2y}C^IFcZN`{zVOQWj`!ImHk z&Gi^aP$IE{$RhMp9&GRu{zT?*vIo#H50JPm-F!X6Qqy8NO&Z_{~3fs9lp} zm>J*#Rl;b+AwO*mYG0dbru40-jD-QEg;@5X;GHd-3crH1z-%37hJ_f@ylUm0mF1V2 zJKuWY`B1Eku5aKa@6R2d8MFJQB0m2Vp&$QZVrT^!NW!1dUmZ?Jec@(B0fTNP+)$lW zMwqjynw6$oLvY?$+hXA7e7?j-X7@q*F9R)ZTF3CLWocO|i|-b+NV2pFa#=@xWzLwo!fg9V%>VK&m0am3pPncA)vHO|;~ z{O#xT=ODJx88u6J%vh<@yBv9sd4Pa0gtomSe>5J=i1mGjFqg2$rJsFq$7ILL}|aY@8JD#T)L{ zAUdgQJ%Y*_gVEmal!{ju6`Ndtt4~y$QCBfall=|^HNmC7Xe-eBawVq_~gwRw8K9nZf=>oUZ*mxlA%X$$eh_!9HC%9*dNF`rsq*yF33 zi7qCSz%+q9ofRE@BMb}%ceC?LejACXl#W=D4t(SnDmhtsg6#27Mpj%djdiyLukr#k zu3)dn@=%f+Z(`55tht{ZXxF4=fE4AAE!r|;X_;UjSDu}PbdT9X}lf02dxegt$AmzS_Z^= zQvwWvIlxTc;|2-rrX=@(P{{)MI%86Wj0EU~>tE2Gfb%Aki;TLMPsfVz2!o|8aGd!s ztFUf0@+NL%@cR4V#ayJ}L?qi`4=;cYNgl*aGYfX!@JXm+y57@g=QOyXlYo~;I&0K} z-*%1p4X+Hm1l{j@e)f9!mHoUAKo-Oa^Ds*rQ|4Dn$?Y&MR;rzEs0!Tja_MXK^K3U! z%h8GS|S|2%q8TPkRX6Ol#CDsKCQJf zB~ss}4z_5K(_fI8c-TJp#z(l?c|z@!V#*7%AIp|p{JA?Z+Vge`iT3Xr@A*;Xwp0ZS zqPk|9PoAq7dOkopzL~53yxh*HB~Q9=xlils$CJ=MedR8$=<^&xetG|(ld=0Tv**<8 z70Yr5a)D*d7=X*I8Z{Ly-Uxxv0ASDru( z0b$~58m8a2{v#$D>DdZG1Q;yd`x<7_yPq9_(}dFDzQkj(`oSP%9Zw@m`gLwsnCT6r z$2^^}1y{&`VT-d&rq%*~ydvnSC=3j{WqtJGA1B_n@(yFJS;wPhmS2q!)xYBI9l~13 z3!6*m@PhhYROdV)d1ki9&+?)Swt_D?=h>MV3$G%>r`Zv!9J*Q$8Br9;3qD8*VRmBT zsIlakLdKoK2Ob_!5x=~-r4PshbT#!EY$#a!08?#}`35jf{?Iy~PG|h#Sh6xnz+9F4 z76j7Fyz)|at}HUH<2y<6!;E)k%62YSMep$IE?}Iq54Qb09hx_%H$C@-Vf?8s9>(I_ zGQUe`Scx)^l~pe+DA6WY@i(jQ+zt0+^%)k(mpfMu&37lHsy<03 zim9ImA39};6`fkbSdaSoP6=~_k6k0r!!3mTjfmByTGstvxn&(|q%zrZF-?tcXO(A0 zo{tb&nXoc{9k>|_$3<$sEqbk>nLd+5pS@%{R5`~LXxq&`Wd>>XPqv7Fn$th?weA1v zG`BTxu9vjI+qrE+ptRadpA6iqdG}5tfety*IF5hR9Q#TRTQz8KLI-hQEW1*=#SNDK zQ=!R;RNH-ep?i_BzwT8IwOha)zZ%2_xe@Ce(~*4Ri_~ zdzYQTM9YONi!D5#7EhjR9xVci9wBmSzgs4K$G(Ipn4Y~{%{k07?7picg-iuMpZj$1I-dN9j=8zI_ zkAlA7ewj%PW#EIBp_!%6)Xc`L)6$P0*jLkj2r&6_YF15D?XXU4e{w|9wJ2YFh6QbS ze^_n8@irpX`*0uH;S-BhnF~)ux`g1db~v!H+D!BSq&UzLC3X`AYp-aLdgv`QkZW&c z6iBtfm;^$nM-Mh~gN#(6=@t5cPohva+0@tUTUOhKF1ZZNf$s^v5ib=0cS5Xf-+k}Y znvnFMemO&GVxEmM$__S(EB;`@mGL9u9O#8_rZmsmvCnR7FWkH&aKbT|g+GB~I!-4` zT=^$WZL?Ouiril^yqayyRf_cS@w0@8UT~Noa&Al{nNzhhSFdmz!tbRejuDh)maFh7 zHC=sM|1`hLYzf1LW{b*!EhOLx;u!Um2w1D73AX>hplC2R3=YSv{~q(E;*dToEcc58 zoG|KKgEP7@2#aHK3qA4!q}ej=mwhhZSn$C*PYHTGO78tpb+bltLs=ug5?=?%{#~d0 z2Sy2W6$PT4G+eQsdVAQ=R7Ce1z>XfLwlz*l_%}0**ty|lqZ>Td>h)`#Z7*XCpi@Q$ zp@%1BqLrK3#(h$8i*eVG(Y8R?id3VDLBwLwAEo|1A6)tg>n?I#L%2Jvj;p?L#Z5*J zCOOMnpZf|rv{CMY|1=7k_SJM{g>z+-EV&_cHSx%o!N;>pVwJkBrKG8`H3E&veSBTe z+Qxz*zX=~l0t4#-1Eb4MaL2ov*g4Ko2c#l@x=avXv$`H|7Y$t@r&qi)lAxZY)$s3r zuf}-jIOwwDDF8NuW>Pt(LAgA9>1EDxB@YHWfq&zAMu|5+c&=)aPAoMew#`;!D}q$A zrB5jHJh}5eHh2uLsRzQfedlnr0OL zj&V69vEQ8R2L_UsR8cMvO@A0BG_(*P(NP^v!5EGtv3VeN=JkH;Gw)vXSMdQ$m8Y1% zhXXpG;x4DDE-&X$Isg(7x)=^D$v#2r9Z7*BGMbC?4|G@$&;aBGoCB63?y`o%4GqI9eVuFOyH4;Q1!+9T9e|1yy7)8@HNZn^7c3hC zmj0(;0ayhJ(2z?1tI$Jl4++TwvPGc6X?dn2)C2`8WvIaIqx=#B@Jrs4u)3rC0t~U{ z-L;tym87AoI?`f$=TQ Date: Mon, 9 Dec 2019 18:13:22 +0800 Subject: [PATCH 2049/2457] gth_ultrascale: make OBUFDS_GTE3 work https://www.xilinx.com/support/answers/67919.html --- artiq/gateware/drtio/transceiver/gth_ultrascale.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index aefea7652..ea7f908f5 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -695,6 +695,8 @@ class GTH(Module, TransceiverInterface): if clock_recout_pads is not None: self.specials += Instance("OBUFDS_GTE3", + p_REFCLK_EN_TX_PATH=0b1, + p_REFCLK_ICNTL_TX=0b00111, i_I=self.gths[0].rxrecclkout, i_CEB=0, o_O=clock_recout_pads.p, o_OB=clock_recout_pads.n) From 150a02117cd619570b7a69fd95daf46e42f86262 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Dec 2019 19:47:50 +0800 Subject: [PATCH 2050/2457] sayma_rtm: drive clk_src_ext_sel --- artiq/gateware/targets/sayma_rtm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 0c67ce437..018a4868d 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -205,6 +205,8 @@ class Satellite(_SatelliteBase): self.add_rtio(rtio_channels) + self.comb += platform.request("clk_src_ext_sel").eq(0) + # HMC clock chip and DAC control self.comb += [ platform.request("ad9154_rst_n", 0).eq(1), From 13486f3acfce35d88cf73c116c52fa2077fe0450 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Dec 2019 19:49:34 +0800 Subject: [PATCH 2051/2457] wrpll: swap helper/main si549 frequencies --- artiq/firmware/libboard_artiq/wrpll.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 1f6f91775..5030b1f42 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -293,10 +293,10 @@ pub fn init() { unsafe { csr::wrpll::helper_reset_write(1); } - #[cfg(rtio_frequency = "125.0")] - let (m_hsdiv, m_lsdiv, m_fbdiv) = (0x05c, 0, 0x04b5badb98a); #[cfg(rtio_frequency = "125.0")] let (h_hsdiv, h_lsdiv, h_fbdiv) = (0x05c, 0, 0x04b5c447213); + #[cfg(rtio_frequency = "125.0")] + let (m_hsdiv, m_lsdiv, m_fbdiv) = (0x05c, 0, 0x04b5badb98a); si549::program(i2c::Dcxo::Main, m_hsdiv, m_lsdiv, m_fbdiv) .expect("cannot initialize main Si549"); From 6f52540569e80aa58145c55b1891e1a3bf7dbbae Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Dec 2019 20:13:55 +0800 Subject: [PATCH 2052/2457] wrpll: fix previous commit --- artiq/firmware/libboard_artiq/wrpll.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 5030b1f42..2261cb262 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -294,9 +294,9 @@ pub fn init() { unsafe { csr::wrpll::helper_reset_write(1); } #[cfg(rtio_frequency = "125.0")] - let (h_hsdiv, h_lsdiv, h_fbdiv) = (0x05c, 0, 0x04b5c447213); + let (h_hsdiv, h_lsdiv, h_fbdiv) = (0x05c, 0, 0x04b5badb98a); #[cfg(rtio_frequency = "125.0")] - let (m_hsdiv, m_lsdiv, m_fbdiv) = (0x05c, 0, 0x04b5badb98a); + let (m_hsdiv, m_lsdiv, m_fbdiv) = (0x05c, 0, 0x04b5c447213); si549::program(i2c::Dcxo::Main, m_hsdiv, m_lsdiv, m_fbdiv) .expect("cannot initialize main Si549"); From 52112d54f9c052159b88b78dc6bd712abd4f062c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 10 Dec 2019 10:30:06 +0800 Subject: [PATCH 2053/2457] kasli_generic: expose peripheral_processors dictionary. Closes #1403 --- artiq/gateware/targets/kasli_generic.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index fc6dba19d..f500d2946 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -99,16 +99,18 @@ def peripheral_grabber(module, peripheral): eem.Grabber.add_std(module, port, port_aux, port_aux2) +peripheral_processors = { + "dio": peripheral_dio, + "urukul": peripheral_urukul, + "novogorny": peripheral_novogorny, + "sampler": peripheral_sampler, + "suservo": peripheral_suservo, + "zotino": peripheral_zotino, + "grabber": peripheral_grabber, +} + + def add_peripherals(module, peripherals): - peripheral_processors = { - "dio": peripheral_dio, - "urukul": peripheral_urukul, - "novogorny": peripheral_novogorny, - "sampler": peripheral_sampler, - "suservo": peripheral_suservo, - "zotino": peripheral_zotino, - "grabber": peripheral_grabber, - } for peripheral in peripherals: peripheral_processors[peripheral["type"]](module, peripheral) From ac09f3a5dafb1bc11a765d4c4d0333a425b4dac7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 11 Dec 2019 16:18:56 +0800 Subject: [PATCH 2054/2457] artiq_browser: fix command line argument handling. Closes #1404 --- artiq/frontend/artiq_browser.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index 4faa8fa47..6d499e558 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -10,10 +10,11 @@ from PyQt5 import QtCore, QtGui, QtWidgets from quamash import QEventLoop from sipyco.asyncio_tools import atexit_register_coroutine +from sipyco import common_args from artiq import __version__ as artiq_version from artiq import __artiq_dir__ as artiq_dir -from artiq.tools import add_common_args, get_user_config_dir +from artiq.tools import get_user_config_dir from artiq.gui import state, applets, models, log from artiq.browser import datasets, files, experiments @@ -41,7 +42,7 @@ def get_argparser(): help="TCP port to use to connect to the master") parser.add_argument("select", metavar="SELECT", nargs="?", help="directory to browse or file to load") - add_common_args(parser) + common_args.verbosity_args(parser) return parser From 8d13aeb96c1f0a63c528bbb08e576626a4c57170 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Dec 2019 10:34:44 +0800 Subject: [PATCH 2055/2457] test: run test_help for browser and dashboard --- artiq/test/test_frontends.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/test/test_frontends.py b/artiq/test/test_frontends.py index 9bafbff4a..c433fca71 100644 --- a/artiq/test/test_frontends.py +++ b/artiq/test/test_frontends.py @@ -7,7 +7,6 @@ import unittest class TestFrontends(unittest.TestCase): def test_help(self): """Test --help as a simple smoke test against catastrophic breakage.""" - # Skip tests for GUI programs on headless CI environments. commands = { "aqctl": [ "corelog" @@ -15,7 +14,7 @@ class TestFrontends(unittest.TestCase): "artiq": [ "client", "compile", "coreanalyzer", "coremgmt", "netboot", "flash", "master", "mkfs", "route", - "rtiomon", "run", "session" + "rtiomon", "run", "session", "browser", "dashboard" ] } From 5fefdcc324648842663465ede333d9cb053af14a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 15 Dec 2019 10:41:58 +0800 Subject: [PATCH 2056/2457] manual: clarify XY applet setup example --- doc/manual/getting_started_mgmt.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/getting_started_mgmt.rst b/doc/manual/getting_started_mgmt.rst index e667abe02..953a7fbd9 100644 --- a/doc/manual/getting_started_mgmt.rst +++ b/doc/manual/getting_started_mgmt.rst @@ -157,7 +157,7 @@ Plotting in the ARTIQ dashboard is achieved by programs called "applets". Applet Applets are configured through their command line to select parameters such as the names of the datasets to plot. The list of command-line options can be retrieved using the ``-h`` option; for example you can run ``python3 -m artiq.applets.plot_xy -h`` in a terminal. -In our case, create a new applet from the XY template by right-clicking on the applet list, and edit the applet command line so that it retrieves the ``parabola`` dataset. Run the experiment again, and observe how the points are added one by one to the plot. +In our case, create a new applet from the XY template by right-clicking on the applet list, and edit the applet command line so that it retrieves the ``parabola`` dataset (the command line should now be ``${artiq_applet}plot_xy parabola``). Run the experiment again, and observe how the points are added one by one to the plot. After the experiment has finished executing, the results are written to a HDF5 file that resides in ``~/artiq-master/results//``. Open that file with HDFView or h5dump, and observe the data we just generated as well as the Git commit ID of the experiment (a hexadecimal hash such as ``947acb1f90ae1b8862efb489a9cc29f7d4e0c645`` that represents the data at a particular time in the Git repository). The list of Git commit IDs can be found using the ``git log`` command in ``~/artiq-work``. From 0279a60a550945197f723fb91bd2b1f09dd1d0d3 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 17 Dec 2019 13:28:38 +0000 Subject: [PATCH 2057/2457] examples: Add README This will be displayed by GitHub below the directory listing, and was inspired by observing new users disregard the examples/ tree entirely (even though the experiments and device DBs within would have cleared up their getting-started confusion) due to the perceived complexity wall induced by the wealth of subdirectories. --- artiq/examples/README.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 artiq/examples/README.rst diff --git a/artiq/examples/README.rst b/artiq/examples/README.rst new file mode 100644 index 000000000..4a37fd15c --- /dev/null +++ b/artiq/examples/README.rst @@ -0,0 +1,11 @@ +ARTIQ experiment examples +========================= + +This directory contains several sample ARTIQ master configurations +and associated experiments that illustrate basic usage of various +hardware and software features. + +New users might want to peruse the ``no_hardware`` directory to +explore the argument/dataset machinery without needing access to +hardware, and the ``kc705_nist_clock`` directory for inspiration +on how to coordinate between host and FPGA core device code. From d3508b014f9d6306d7ac150a764e820d0162d082 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 17 Dec 2019 19:59:59 +0000 Subject: [PATCH 2058/2457] firmware: Add whitespace between panic handler location and message --- artiq/firmware/ksupport/lib.rs | 2 +- artiq/firmware/runtime/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index 74ab757ef..c6e747fdb 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -58,7 +58,7 @@ pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! { send(&Log(format_args!("panic at unknown location"))); } if let Some(message) = info.message() { - send(&Log(format_args!("{}\n", message))); + send(&Log(format_args!(": {}\n", message))); } else { send(&Log(format_args!("\n"))); } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index d7f983090..d79c7b254 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -309,7 +309,7 @@ pub fn panic_impl(info: &core::panic::PanicInfo) -> ! { print!("panic at unknown location"); } if let Some(message) = info.message() { - println!("{}", message); + println!(": {}", message); } else { println!(""); } From 6ee15fbcaef5e27a39f58eee92d5d7e537276d6d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 18 Dec 2019 10:33:29 +0800 Subject: [PATCH 2059/2457] sayma_rtm: basemod RF switches --- artiq/gateware/targets/sayma_rtm.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 018a4868d..e78dcd216 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -196,12 +196,14 @@ class Satellite(_SatelliteBase): platform = self.platform rtio_channels = [] - phy = ttl_serdes_7series.Output_8X(platform.request("allaki0_rfsw0")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - phy = ttl_serdes_7series.Output_8X(platform.request("allaki0_rfsw1")) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) + for i in range(4): + phy = ttl_serdes_7series.Output_8X(platform.request("basemod0_rfsw", i)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + for i in range(4): + phy = ttl_serdes_7series.Output_8X(platform.request("basemod1_rfsw", i)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) self.add_rtio(rtio_channels) From fb2b634c4a90c49bf696ccca050b84051ece62f3 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 17 Dec 2019 19:10:33 +0000 Subject: [PATCH 2060/2457] compiler, language: Implement @kernel_from_string With support for polymorphism (or type erasure on pointers to member functions) being absent in the ARTIQ compiler, code generation is vital to be able to implement abstractions that work with user-provided lists/trees of objects with uniform interfaces (e.g. a common base class, or duck typing), but different concrete types. @kernel_from_string has been in production use for exactly this use case in Oxford for the better part of a year now (various places in ndscan). GitHub: Fixes #1089. --- artiq/compiler/embedding.py | 24 +++++++++++--- artiq/language/core.py | 55 +++++++++++++++++++++++++++++++- artiq/test/lit/embedding/eval.py | 18 +++++++++++ 3 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 artiq/test/lit/embedding/eval.py diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index 2b5c9a416..fb0a8be39 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -765,6 +765,9 @@ class Stitcher: if hasattr(function, 'artiq_embedded') and function.artiq_embedded.function: function = function.artiq_embedded.function + if isinstance(function, str): + return source.Range(source.Buffer(function, ""), 0, 0) + filename = function.__code__.co_filename line = function.__code__.co_firstlineno name = function.__code__.co_name @@ -848,10 +851,20 @@ class Stitcher: # Extract function source. embedded_function = host_function.artiq_embedded.function - source_code = inspect.getsource(embedded_function) - filename = embedded_function.__code__.co_filename - module_name = embedded_function.__globals__['__name__'] - first_line = embedded_function.__code__.co_firstlineno + if isinstance(embedded_function, str): + # This is a function to be eval'd from the given source code in string form. + # Mangle the host function's id() into the fully qualified name to make sure + # there are no collisions. + source_code = embedded_function + embedded_function = host_function + filename = "" + module_name = "__eval_{}".format(id(host_function)) + first_line = 1 + else: + source_code = inspect.getsource(embedded_function) + filename = embedded_function.__code__.co_filename + module_name = embedded_function.__globals__['__name__'] + first_line = embedded_function.__code__.co_firstlineno # Extract function annotation. signature = inspect.signature(embedded_function) @@ -937,6 +950,9 @@ class Stitcher: return function_node def _extract_annot(self, function, annot, kind, call_loc, fn_kind): + if annot is None: + annot = builtins.TNone() + if not isinstance(annot, types.Type): diag = diagnostic.Diagnostic("error", "type annotation for {kind}, '{annot}', is not an ARTIQ type", diff --git a/artiq/language/core.py b/artiq/language/core.py index fe1a7e814..5560398dd 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -8,7 +8,7 @@ import numpy __all__ = ["kernel", "portable", "rpc", "syscall", "host_only", - "set_time_manager", "set_watchdog_factory", + "kernel_from_string", "set_time_manager", "set_watchdog_factory", "TerminationRequested"] # global namespace for kernels @@ -140,6 +140,59 @@ def host_only(function): return function +def kernel_from_string(parameters, body_code, decorator=kernel): + """Build a kernel function from the supplied source code in string form, + similar to ``exec()``/``eval()``. + + Operating on pieces of source code as strings is a very brittle form of + metaprogramming; kernels generated like this are hard to debug, and + inconvenient to write. Nevertheless, this can sometimes be useful to work + around restrictions in ARTIQ Python. In that instance, care should be taken + to keep string-generated code to a minimum and cleanly separate it from + surrounding code. + + The resulting function declaration is also evaluated using ``exec()`` for + use from host Python code. To encourage a modicum of code hygiene, no + global symbols are available by default; any objects accessed by the + function body must be passed in explicitly as parameters. + + :param parameters: A list of parameter names the generated functions + accepts. Each entry can either be a string or a tuple of two strings; + if the latter, the second element specifies the type annotation. + :param body_code: The code for the function body, in string form. + ``return`` statements can be used to return values, as usual. + :param decorator: One of ``kernel`` or ``portable`` (optionally with + parameters) to specify how the function will be executed. + + :return: The function generated from the arguments. + """ + + # Build complete function declaration. + decl = "def kernel_from_string_fn(" + for p in parameters: + type_annotation = "" + if isinstance(p, tuple): + name, typ = p + type_annotation = ": " + typ + else: + name = p + decl += name + type_annotation + "," + decl += "):\n" + decl += "\n".join(" " + line for line in body_code.split("\n")) + + # Evaluate to get host-side function declaration. + context = {} + try: + exec(decl, context) + except SyntaxError: + raise SyntaxError("Error parsing kernel function: '{}'".format(decl)) + fn = decorator(context["kernel_from_string_fn"]) + + # Save source code for the compiler to pick up later. + fn.artiq_embedded = fn.artiq_embedded._replace(function=decl) + return fn + + class _DummyTimeManager: def _not_implemented(self, *args, **kwargs): raise NotImplementedError( diff --git a/artiq/test/lit/embedding/eval.py b/artiq/test/lit/embedding/eval.py new file mode 100644 index 000000000..d2f91cbf9 --- /dev/null +++ b/artiq/test/lit/embedding/eval.py @@ -0,0 +1,18 @@ +# RUN: %python -m artiq.compiler.testbench.embedding %s + +from artiq.language.core import * + + +def make_incrementer(increment): + return kernel_from_string(["a"], "return a + {}".format(increment), + portable) + + +foo = make_incrementer(1) +bar = make_incrementer(2) + + +@kernel +def entrypoint(): + assert foo(4) == 5 + assert bar(4) == 6 From 594ff45750cc9f0e5a72e0b793079b8fd75c3631 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 18 Dec 2019 13:23:40 +0000 Subject: [PATCH 2061/2457] compiler: Revert support for `None` as `TNone` This was mistakenly included in fb2b634c4a9, and broke the test case verifying that using None as an ARTIQ type annotation in fact generates an error message. --- artiq/compiler/embedding.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index fb0a8be39..2b10673bd 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -950,9 +950,6 @@ class Stitcher: return function_node def _extract_annot(self, function, annot, kind, call_loc, fn_kind): - if annot is None: - annot = builtins.TNone() - if not isinstance(annot, types.Type): diag = diagnostic.Diagnostic("error", "type annotation for {kind}, '{annot}', is not an ARTIQ type", From 8f518c6b055526106dd578d3d8c61d31c9a9d905 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 30 Jun 2018 19:51:58 +0100 Subject: [PATCH 2062/2457] compiler: Allow `None` in type hints Similar to how Python itself interprets None as type(None), make it translate to TNone in ARTIQ compiler type hints. --- artiq/compiler/embedding.py | 3 +++ artiq/test/lit/embedding/annotation.py | 5 +++++ artiq/test/lit/embedding/error_specialized_annot.py | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index 2b10673bd..fb0a8be39 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -950,6 +950,9 @@ class Stitcher: return function_node def _extract_annot(self, function, annot, kind, call_loc, fn_kind): + if annot is None: + annot = builtins.TNone() + if not isinstance(annot, types.Type): diag = diagnostic.Diagnostic("error", "type annotation for {kind}, '{annot}', is not an ARTIQ type", diff --git a/artiq/test/lit/embedding/annotation.py b/artiq/test/lit/embedding/annotation.py index 7e9c05d9f..21ae25332 100644 --- a/artiq/test/lit/embedding/annotation.py +++ b/artiq/test/lit/embedding/annotation.py @@ -11,7 +11,12 @@ def foo(x: TInt64, y: TInt64 = 1) -> TInt64: print(x+y) return x+y +@kernel +def bar(x: TInt64) -> None: + print(x) + @kernel def entrypoint(): print(foo(0, 2)) print(foo(1, 3)) + bar(3) diff --git a/artiq/test/lit/embedding/error_specialized_annot.py b/artiq/test/lit/embedding/error_specialized_annot.py index c474f235b..2f5955043 100644 --- a/artiq/test/lit/embedding/error_specialized_annot.py +++ b/artiq/test/lit/embedding/error_specialized_annot.py @@ -4,9 +4,9 @@ from artiq.experiment import * class c(): -# CHECK-L: ${LINE:+2}: error: type annotation for argument 'x', 'None', is not an ARTIQ type +# CHECK-L: ${LINE:+2}: error: type annotation for argument 'x', '', is not an ARTIQ type @kernel - def hello(self, x: None): + def hello(self, x: float): pass @kernel From 1c9cbe628525b5dbd39b025c15c9a1f416b3e78b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 20 Dec 2019 15:23:15 +0800 Subject: [PATCH 2063/2457] sayma_rtm: add basemod attenuators on RTIO --- artiq/gateware/targets/sayma_rtm.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index e78dcd216..8946ddea1 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -16,7 +16,7 @@ from misoc.targets.sayma_rtm import BaseSoC, soc_sayma_rtm_args, soc_sayma_rtm_a from misoc.integration.builder import Builder, builder_args, builder_argdict from artiq.gateware import rtio -from artiq.gateware.rtio.phy import ttl_serdes_7series +from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series from artiq.gateware.drtio.wrpll import WRPLL, DDMTDSamplerGTP @@ -196,12 +196,23 @@ class Satellite(_SatelliteBase): platform = self.platform rtio_channels = [] - for i in range(4): - phy = ttl_serdes_7series.Output_8X(platform.request("basemod0_rfsw", i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - for i in range(4): - phy = ttl_serdes_7series.Output_8X(platform.request("basemod1_rfsw", i)) + for bm in range(2): + print("BaseMod{} RF switches starting at RTIO channel 0x{:06x}" + .format(bm, len(rtio_channels))) + for i in range(4): + phy = ttl_serdes_7series.Output_8X(platform.request("basemod{}_rfsw".format(bm), i)) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + print("BaseMod{} attenuator starting at RTIO channel 0x{:06x}" + .format(bm, len(rtio_channels))) + basemod_att = platform.request("basemod{}_att".format(bm)) + for name in "rst_n clk mosi le".split(): + signal = getattr(basemod_att, name) + for i in range(len(signal)): + phy = ttl_simple.Output(signal[i]) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + phy = ttl_simple.InOut(basemod_att.miso) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From c5137eeb623f5c2fa7c1a4e9dc15f2b62e74c6e4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 20 Dec 2019 15:25:12 +0800 Subject: [PATCH 2064/2457] firmware: remove legacy hmc542 code --- artiq/firmware/libboard_artiq/hmc542.rs | 60 ------------------------- artiq/firmware/libboard_artiq/lib.rs | 2 - artiq/firmware/runtime/main.rs | 2 - artiq/firmware/satman/main.rs | 2 - 4 files changed, 66 deletions(-) delete mode 100644 artiq/firmware/libboard_artiq/hmc542.rs diff --git a/artiq/firmware/libboard_artiq/hmc542.rs b/artiq/firmware/libboard_artiq/hmc542.rs deleted file mode 100644 index fed25a78e..000000000 --- a/artiq/firmware/libboard_artiq/hmc542.rs +++ /dev/null @@ -1,60 +0,0 @@ -use board_misoc::{csr, clock}; - -const PIN_LE: u32 = 1 << 0; -const PIN_SIN: u32 = 1 << 1; -const PIN_CLK: u32 = 1 << 2; -const PIN_RST_N: u32 = 1 << 3; -const PIN_RST: u32 = PIN_RST_N; - -const CARDS: usize = 4; -const CHANNELS: usize = 2; - -fn set_pins(card_index: usize, chan_index: usize, pins: u32) { - let pins = pins ^ PIN_RST_N; - let shift = (card_index * 2 + chan_index)*4; - unsafe { - let state = csr::allaki_atts::out_read(); - let state = state & !(0xf << shift); - let state = state | (pins << shift); - csr::allaki_atts::out_write(state); - } - clock::spin_us(100); -} - -/// Attenuation is in units of 0.5 dB, from 0 dB (0) to 31.5 dB (63). -pub fn program(card_index: usize, chan_index: usize, atten: u8) { - assert!(card_index < 4 && chan_index < 2); - - info!("card {} channel {} set to {}{} dB", - card_index, chan_index, - atten / 2, if atten % 2 != 0 { ".5" } else { "" }); - - // 0b111111 = 0dB - // 0b111110 = 0.5dB - // 0b111101 = 1dB - // 0b111100 = 1.5dB - // ... - // 0b011111 = 16dB - // ... - // 0b000000 = 31.5dB - let atten = !atten << 2; - - let set_pins = |pins| set_pins(card_index, chan_index, pins); - set_pins(PIN_RST); - set_pins(0); - for n in (0..8).rev() { - let sin = if atten & 1 << n != 0 { PIN_SIN } else { 0 }; - set_pins(sin); - set_pins(sin | PIN_CLK); - } - set_pins(PIN_LE); -} - -/// See `program`. -pub fn program_all(atten: u8) { - for card in 0..CARDS { - for chan in 0..CHANNELS { - program(card, chan, atten) - } - } -} diff --git a/artiq/firmware/libboard_artiq/lib.rs b/artiq/firmware/libboard_artiq/lib.rs index 0826ceac3..448b10f9e 100644 --- a/artiq/firmware/libboard_artiq/lib.rs +++ b/artiq/firmware/libboard_artiq/lib.rs @@ -35,8 +35,6 @@ pub mod hmc830_7043; mod ad9154_reg; #[cfg(has_ad9154)] pub mod ad9154; -#[cfg(has_allaki_atts)] -pub mod hmc542; #[cfg(has_grabber)] pub mod grabber; diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index d79c7b254..9cc34edc6 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -103,8 +103,6 @@ fn sayma_hw_init() { error!("failed to align SYSREF at DAC: {}", e); } } - #[cfg(has_allaki_atts)] - board_artiq::hmc542::program_all(8/*=4dB*/); } fn startup() { diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index fb738f057..5225eba1b 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -474,8 +474,6 @@ pub extern fn main() -> i32 { board_artiq::ad9154::reset_and_detect(dacno as u8).expect("AD9154 DAC not detected"); } } - #[cfg(has_allaki_atts)] - board_artiq::hmc542::program_all(8/*=4dB*/); #[cfg(has_drtio_routing)] let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()]; From b7f16231978a498f0633732146356a826d272162 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 20 Dec 2019 18:58:31 +0800 Subject: [PATCH 2065/2457] sayma_rtm: connect attenuator shift registers in series --- artiq/gateware/targets/sayma_rtm.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 8946ddea1..fee4ab27b 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -203,16 +203,22 @@ class Satellite(_SatelliteBase): phy = ttl_serdes_7series.Output_8X(platform.request("basemod{}_rfsw".format(bm), i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) + print("BaseMod{} attenuator starting at RTIO channel 0x{:06x}" .format(bm, len(rtio_channels))) basemod_att = platform.request("basemod{}_att".format(bm)) - for name in "rst_n clk mosi le".split(): + for name in "rst_n clk le".split(): signal = getattr(basemod_att, name) for i in range(len(signal)): phy = ttl_simple.Output(signal[i]) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) - phy = ttl_simple.InOut(basemod_att.miso) + phy = ttl_simple.Output(basemod_att.mosi[0]) + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + for i in range(3): + self.comb += basemod_att.mosi[i+1].eq(basemod_att.miso[i]) + phy = ttl_simple.InOut(basemod_att.miso[3]) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From cab8c8249e60cb5f55258dfe99de5d386d374272 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 20 Dec 2019 18:58:50 +0800 Subject: [PATCH 2066/2457] coredevice/shiftreg: add get method --- artiq/coredevice/shiftreg.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/shiftreg.py b/artiq/coredevice/shiftreg.py index a71d6e217..cf7b9466c 100644 --- a/artiq/coredevice/shiftreg.py +++ b/artiq/coredevice/shiftreg.py @@ -6,13 +6,15 @@ class ShiftReg: """Driver for shift registers/latch combos connected to TTLs""" kernel_invariants = {"dt", "n"} - def __init__(self, dmgr, clk, ser, latch, n=32, dt=10*us): + def __init__(self, dmgr, clk, ser, latch, n=32, dt=10*us, ser_in=None): self.core = dmgr.get("core") self.clk = dmgr.get(clk) self.ser = dmgr.get(ser) self.latch = dmgr.get(latch) self.n = n self.dt = dt + if ser_in is not None: + self.ser_in = dmgr.get(ser_in) @kernel def set(self, data): @@ -34,3 +36,18 @@ class ShiftReg: delay(self.dt) self.latch.off() delay(self.dt) + + @kernel + def get(self): + delay(-2*(self.n + 1)*self.dt) + data = 0 + for i in range(self.n): + data <<= 1 + if self.ser_in.sample_input(): + data |= 1 + delay(self.dt) + self.clk.on() + delay(self.dt) + self.clk.off() + delay(self.dt) + return data From c3030f4ffb9a8ce48fc7f94c6975211843c5181a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 20 Dec 2019 19:59:15 +0800 Subject: [PATCH 2067/2457] kasli_sawgmaster: update device_db for BaseMod --- artiq/examples/kasli_sawgmaster/device_db.py | 99 +++++++++++++++++--- 1 file changed, 85 insertions(+), 14 deletions(-) diff --git a/artiq/examples/kasli_sawgmaster/device_db.py b/artiq/examples/kasli_sawgmaster/device_db.py index 68fa62e0a..781db5b56 100644 --- a/artiq/examples/kasli_sawgmaster/device_db.py +++ b/artiq/examples/kasli_sawgmaster/device_db.py @@ -97,18 +97,89 @@ for i in range(4): } } -for i in range(8): - device_db["sawg" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.sawg", - "class": "SAWG", - "arguments": {"channel_base": i*10+0x010006, "parallelism": 4} - } +""" +artiq_route routing.bin init +artiq_route routing.bin set 0 0 +artiq_route routing.bin set 1 1 0 +artiq_route routing.bin set 2 1 1 0 +artiq_route routing.bin set 3 2 0 +artiq_route routing.bin set 4 2 1 0 +artiq_coremgmt -D kasli config write -f routing_table routing.bin +""" + +for sayma in range(2): + amc_base = 0x010000 + sayma*0x020000 + rtm_base = 0x020000 + sayma*0x020000 + for i in range(4): + device_db["led" + str(4*sayma+i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": amc_base + i} + } + for i in range(2): + device_db["ttl_mcx" + str(2*sayma+i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": amc_base + 4 + i} + } + for i in range(8): + device_db["sawg" + str(8*sayma+i)] = { + "type": "local", + "module": "artiq.coredevice.sawg", + "class": "SAWG", + "arguments": {"channel_base": amc_base + 6 + i*10, "parallelism": 4} + } + for basemod in range(2): + for i in range(4): + device_db["sawg_sw" + str(8*sayma+4*basemod+i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": rtm_base + basemod*9 + i} + } + att_idx = 2*sayma + basemod + device_db["basemod_att_rst_n"+str(att_idx)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": rtm_base + basemod*9 + 4} + } + device_db["basemod_att_clk"+str(att_idx)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": rtm_base + basemod*9 + 5} + } + device_db["basemod_att_le"+str(att_idx)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": rtm_base + basemod*9 + 6} + } + device_db["basemod_att_mosi"+str(att_idx)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": rtm_base + basemod*9 + 7} + } + device_db["basemod_att_miso"+str(att_idx)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLInOut", + "arguments": {"channel": rtm_base + basemod*9 + 8} + } + device_db["basemod_att"+str(att_idx)] = { + "type": "local", + "module": "artiq.coredevice.basemod_att", + "class": "BaseModAtt", + "arguments": { + "rst_n": "basemod_att_rst_n"+str(att_idx), + "clk": "basemod_att_clk"+str(att_idx), + "le": "basemod_att_le"+str(att_idx), + "mosi": "basemod_att_mosi"+str(att_idx), + "miso": "basemod_att_miso"+str(att_idx), + } + } -for i in range(8): - device_db["sawg" + str(8+i)] = { - "type": "local", - "module": "artiq.coredevice.sawg", - "class": "SAWG", - "arguments": {"channel_base": i*10+0x020006, "parallelism": 4} - } From 8759c8d360e5e8158fda0edcebf55be3ba264b12 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 21 Dec 2019 14:17:22 +0800 Subject: [PATCH 2068/2457] shiftreg: fix get method --- artiq/coredevice/shiftreg.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/shiftreg.py b/artiq/coredevice/shiftreg.py index cf7b9466c..79000eba3 100644 --- a/artiq/coredevice/shiftreg.py +++ b/artiq/coredevice/shiftreg.py @@ -43,7 +43,8 @@ class ShiftReg: data = 0 for i in range(self.n): data <<= 1 - if self.ser_in.sample_input(): + self.ser_in.sample_input() + if self.ser_in.sample_get(): data |= 1 delay(self.dt) self.clk.on() From 106d25b32a24bd41994f31c1e7ab9eb02e58ff37 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 21 Dec 2019 14:17:52 +0800 Subject: [PATCH 2069/2457] kasli_sawgmaster: fix drtio_is_up --- artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py | 2 +- .../examples/kasli_sawgmaster/repository/sines_urukul_sayma.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py index fab0c3693..3a8204941 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_2sayma.py @@ -8,7 +8,7 @@ class Sines2Sayma(EnvExperiment): @kernel def drtio_is_up(self): - for i in range(3): + for i in range(5): if not self.core.get_rtio_destination_status(i): return False return True diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py index af43db1c1..b0a8f466c 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py @@ -23,7 +23,7 @@ class SinesUrukulSayma(EnvExperiment): @kernel def drtio_is_up(self): - for i in range(2): + for i in range(3): if not self.core.get_rtio_destination_status(i): return False return True From d4e039cede435feb0c84326e5e2d5f30756eb1f2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 21 Dec 2019 14:18:10 +0800 Subject: [PATCH 2070/2457] basemod: add coredevice driver --- artiq/coredevice/basemod_att.py | 45 +++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 artiq/coredevice/basemod_att.py diff --git a/artiq/coredevice/basemod_att.py b/artiq/coredevice/basemod_att.py new file mode 100644 index 000000000..d68e9b7a9 --- /dev/null +++ b/artiq/coredevice/basemod_att.py @@ -0,0 +1,45 @@ +from artiq.language.core import kernel, delay +from artiq.language.units import us, ms +from artiq.coredevice.shiftreg import ShiftReg + + +class BaseModAtt: + def __init__(self, dmgr, rst_n, clk, le, mosi, miso): + self.rst_n = dmgr.get(rst_n) + self.shift_reg = ShiftReg(dmgr, + clk=clk, ser=mosi, latch=le, ser_in=miso, n=8*4) + + @kernel + def reset(self): + # HMC's incompetence in digital design an interfaces means that + # the HMC542 needs a level low on RST_N and then a rising edge + # on Latch Enable. Their "latch" isn't a latch but a DFF. + # Of course, it also powers up with a random attenuation, and + # that cannot be fixed with simple pull-ups/pull-downs. + self.rst_n.off() + self.shift_reg.latch.off() + delay(1*us) + self.shift_reg.latch.on() + delay(1*us) + self.shift_reg.latch.off() + self.rst_n.on() + delay(1*us) + + @kernel + def set_mu(self, att0, att1, att2, att3): + word = ( + (att0 << 2) | + (att1 << 10) | + (att2 << 18) | + (att3 << 26) + ) + self.shift_reg.set(word) + + @kernel + def get_mu(self): + word = self.shift_reg.get() + att0 = (word >> 2) & 0x3f + att1 = (word >> 10) & 0x3f + att2 = (word >> 18) & 0x3f + att3 = (word >> 26) & 0x3f + return att0, att1, att2, att3 From b2480f0edc5e6e6baa1dd92236321484c29099c1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 21 Dec 2019 14:18:28 +0800 Subject: [PATCH 2071/2457] artiq_flash: update actions documentation --- artiq/frontend/artiq_flash.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 40679c492..7dcd9b651 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -25,12 +25,13 @@ def get_argparser(): epilog="""\ Valid actions: - * gateware: write gateware bitstream to flash - * rtm_gateware: write RTM board gateware bitstream to flash + * gateware: write main gateware bitstream to flash + * rtm_gateware: write RTM gateware bitstream to flash * bootloader: write bootloader to flash * storage: write storage image to flash * firmware: write firmware to flash - * load: load gateware bitstream into device (volatile but fast) + * load: load main gateware bitstream into device (volatile but fast) + * rtm_load: load RTM gateware bitstream into device * erase: erase flash memory * start: trigger the target to (re)load its gateware bitstream from flash From fb2076a026ceb4b938ce313bcd25024ccb23dcea Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 21 Dec 2019 14:56:41 +0800 Subject: [PATCH 2072/2457] basemod_att: add dB functions, document --- artiq/coredevice/basemod_att.py | 27 ++++++++++++++++++++++++++- doc/manual/core_drivers_reference.rst | 7 +++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/artiq/coredevice/basemod_att.py b/artiq/coredevice/basemod_att.py index d68e9b7a9..a46625c28 100644 --- a/artiq/coredevice/basemod_att.py +++ b/artiq/coredevice/basemod_att.py @@ -11,7 +11,7 @@ class BaseModAtt: @kernel def reset(self): - # HMC's incompetence in digital design an interfaces means that + # HMC's incompetence in digital design and interfaces means that # the HMC542 needs a level low on RST_N and then a rising edge # on Latch Enable. Their "latch" isn't a latch but a DFF. # Of course, it also powers up with a random attenuation, and @@ -27,6 +27,11 @@ class BaseModAtt: @kernel def set_mu(self, att0, att1, att2, att3): + """ + Sets the four attenuators on BaseMod. + The values are in half decibels, between 0 (no attenuation) + and 63 (31.5dB attenuation). + """ word = ( (att0 << 2) | (att1 << 10) | @@ -37,9 +42,29 @@ class BaseModAtt: @kernel def get_mu(self): + """ + Retrieves the current settings of the four attenuators on BaseMod. + """ word = self.shift_reg.get() att0 = (word >> 2) & 0x3f att1 = (word >> 10) & 0x3f att2 = (word >> 18) & 0x3f att3 = (word >> 26) & 0x3f return att0, att1, att2, att3 + + @kernel + def set(self, att0, att1, att2, att3): + """ + Sets the four attenuators on BaseMod. + The values are in decibels. + """ + self.set_mu(round(att0*2.0), round(att1*2.0), round(att2*2.0), round(att3*2.0)) + + @kernel + def get(self): + """ + Retrieves the current settings of the four attenuators on BaseMod. + The values are in decibels. + """ + att0, att1, att2, att3 = self.get_mu() + return 0.5*att0, 0.5*att1, 0.5*att2, 0.5*att3 diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index fd6f36fca..bcdcd1a00 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -112,6 +112,13 @@ RF generation drivers :members: +:mod:`artiq.coredevice.basemod_att` module +++++++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.basemod_att + :members: + + DAC/ADC drivers --------------- From af31c6ea21d3a2ff7db6fb218ade1a6ad6ff40a0 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 22 Dec 2019 05:46:41 +0000 Subject: [PATCH 2073/2457] coredevice: Don't use `is` to compare with integer literal This works on CPython, but is not guaranteed to do so, and produces a warning since 3.8 (see https://bugs.python.org/issue34850). --- artiq/coredevice/comm_kernel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index f9bd5c8b9..268d672cb 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -408,7 +408,7 @@ class CommKernel: args, kwargs = self._receive_rpc_args(embedding_map) return_tags = self._read_bytes() - if service_id is 0: + if service_id == 0: service = lambda obj, attr, value: setattr(obj, attr, value) else: service = embedding_map.retrieve_object(service_id) From e8b9fcf0bbc50e2c211c93d191e9ee007e1f3cad Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 23 Dec 2019 00:50:03 +0000 Subject: [PATCH 2074/2457] doc/manual/developing: Clarify Nix PYTHONPATH usage PYTHONPATH should still contain all the other directories (obvious once you've made that mistake once, of course). --- doc/manual/developing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/developing.rst b/doc/manual/developing.rst index a147a25eb..7dcde3822 100644 --- a/doc/manual/developing.rst +++ b/doc/manual/developing.rst @@ -22,4 +22,4 @@ ARTIQ itself does not depend on Nix, and it is also possible to compile everythi * If you are modifying a dependency of ARTIQ, in addition to updating the relevant part of ``nix-scripts``, rebuild and upload the corresponding Conda packages manually, and update their version numbers in ``conda-artiq.nix``. For Conda, only the main ARTIQ package and the board packages are handled automatically on Hydra. .. warning:: - Nix will make a read-only copy of the ARTIQ source to use in the shell environment. Therefore, any modifications that you make to the source after the shell is started will not be taken into account. A solution applicable to ARTIQ (and several other Python packages such as Migen and MiSoC) is to set the ``PYTHONPATH`` environment variable in the shell to the root of the ARTIQ source. If you want this to be done by default, edit ``profile`` in ``artiq-dev.nix``. + Nix will make a read-only copy of the ARTIQ source to use in the shell environment. Therefore, any modifications that you make to the source after the shell is started will not be taken into account. A solution applicable to ARTIQ (and several other Python packages such as Migen and MiSoC) is to prepend the ARTIQ source directory to the ``PYTHONPATH`` environment variable after entering the shell. If you want this to be done by default, edit ``profile`` in ``artiq-dev.nix``. From b5e1bd3fa2169fe88d4d0cdd4eedeb95fa41fa7f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 23 Dec 2019 19:53:49 +0800 Subject: [PATCH 2075/2457] coredevice: simplify/cleanup network connection code This removes: * host-side keepalive, which turns out not to be required * custom connection timeout (the default is OK) * SSH tunneling support (doesn't seem to be actually used anywhere) --- artiq/coredevice/comm.py | 37 --------------------------------- artiq/coredevice/comm_kernel.py | 7 ++++--- artiq/coredevice/comm_mgmt.py | 7 +++---- 3 files changed, 7 insertions(+), 44 deletions(-) delete mode 100644 artiq/coredevice/comm.py diff --git a/artiq/coredevice/comm.py b/artiq/coredevice/comm.py deleted file mode 100644 index 19a104e54..000000000 --- a/artiq/coredevice/comm.py +++ /dev/null @@ -1,37 +0,0 @@ -import sys -import socket -import logging - - -logger = logging.getLogger(__name__) - - -def set_keepalive(sock, after_idle, interval, max_fails): - if sys.platform.startswith("linux"): - sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, after_idle) - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, interval) - sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, max_fails) - elif sys.platform.startswith("win") or sys.platform.startswith("cygwin"): - # setting max_fails is not supported, typically ends up being 5 or 10 - # depending on Windows version - sock.ioctl(socket.SIO_KEEPALIVE_VALS, - (1, after_idle*1000, interval*1000)) - else: - logger.warning("TCP keepalive not supported on platform '%s', ignored", - sys.platform) - - -def initialize_connection(host, port, ssh_transport=None): - if ssh_transport is None: - sock = socket.create_connection((host, port), 5.0) - sock.settimeout(None) - set_keepalive(sock, 3, 2, 3) - logger.debug("connected to %s:%d", host, port) - else: - sock = ssh_transport.open_channel("direct-tcpip", (host, port), - ("localhost", 9999), timeout=5.0) - ssh_transport.set_keepalive(2) - logger.debug("connected to %s:%d via SSH transport to %s:%d", - host, port, *ssh_transport.getpeername()) - return sock diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 268d672cb..a4782318c 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -2,12 +2,12 @@ import struct import logging import traceback import numpy +import socket from enum import Enum from fractions import Fraction from collections import namedtuple from artiq.coredevice import exceptions -from artiq.coredevice.comm import initialize_connection from artiq import __version__ as software_version @@ -78,10 +78,11 @@ class CommKernel: self.host = host self.port = port - def open(self, **kwargs): + def open(self): if hasattr(self, "socket"): return - self.socket = initialize_connection(self.host, self.port, **kwargs) + self.socket = socket.create_connection((self.host, self.port)) + logger.debug("connected to %s:%d", self.host, self.port) self.socket.sendall(b"ARTIQ coredev\n") def close(self): diff --git a/artiq/coredevice/comm_mgmt.py b/artiq/coredevice/comm_mgmt.py index 5b078b8da..6468499e0 100644 --- a/artiq/coredevice/comm_mgmt.py +++ b/artiq/coredevice/comm_mgmt.py @@ -3,8 +3,6 @@ import logging import socket import struct -from artiq.coredevice.comm import initialize_connection - logger = logging.getLogger(__name__) @@ -59,10 +57,11 @@ class CommMgmt: self.host = host self.port = port - def open(self, **kwargs): + def open(self): if hasattr(self, "socket"): return - self.socket = initialize_connection(self.host, self.port, **kwargs) + self.socket = socket.create_connection((self.host, self.port)) + logger.debug("connected to %s:%d", self.host, self.port) self.socket.sendall(b"ARTIQ management\n") def close(self): From dfad27125ed5f838df2c2ce596534ff55e2645e5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 23 Dec 2019 19:58:10 +0800 Subject: [PATCH 2076/2457] runtime: relax/fix TCP keepalive settings (#1125) --- artiq/firmware/runtime/session.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index f5c76cf35..4a14f3fb6 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -629,7 +629,7 @@ pub fn thread(io: Io, aux_mutex: &Mutex, loop { if listener.can_accept() { let mut stream = listener.accept().expect("session: cannot accept"); - stream.set_timeout(Some(1000)); + stream.set_timeout(Some(2250)); stream.set_keep_alive(Some(500)); match host::read_magic(&mut stream) { From 9e15ff7e6a71a95806b7722112150ba8ef7b44b6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 30 Dec 2019 16:56:06 +0800 Subject: [PATCH 2077/2457] wrpll: improve DDMTD deglitcher --- artiq/gateware/drtio/wrpll/ddmtd.py | 34 ++++++++++++++++------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index 6068b4dec..f46df4463 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -44,19 +44,23 @@ class DDMTDSamplerGTP(Module): ] -class DDMTDEdgeDetector(Module): - def __init__(self, input_signal): - self.rising = Signal() +class DDMTDDeglitcherFirstEdge(Module): + def __init__(self, input_signal, blind_period=128): + self.detect = Signal() + self.tag_correction = 0 - history = Signal(4) - deglitched = Signal() - self.sync.helper += history.eq(Cat(history[1:], input_signal)) - self.comb += deglitched.eq(input_signal | history[0] | history[1] | history[2] | history[3]) - - deglitched_r = Signal() + rising = Signal() + input_signal_r = Signal() self.sync.helper += [ - deglitched_r.eq(deglitched), - self.rising.eq(deglitched & ~deglitched_r) + input_signal_r.eq(input_signal), + rising.eq(input_signal & ~input_signal_r) + ] + + blind_counter = Signal(max=blind_period) + self.sync.helper += [ + If(blind_counter != 0, blind_counter.eq(blind_counter - 1)), + If(rising, blind_counter.eq(blind_period - 1)), + self.detect.eq(rising & (blind_counter == 0)) ] @@ -71,14 +75,14 @@ class DDMTD(Module, AutoCSR): # # # - ed = DDMTDEdgeDetector(input_signal) - self.submodules += ed + deglitcher = DDMTDDeglitcherFirstEdge(input_signal) + self.submodules += deglitcher self.sync.helper += [ self.h_tag_update.eq(0), - If(ed.rising, + If(deglitcher.detect, self.h_tag_update.eq(1), - self.h_tag.eq(counter) + self.h_tag.eq(counter + deglitcher.tag_correction) ) ] From f57f235dca4cd2796ad9e57ef0930848279d86d0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 30 Dec 2019 19:47:57 +0800 Subject: [PATCH 2078/2457] wrpll: new frequency meter As per Mattermost discussion with Tom. --- artiq/firmware/libboard_artiq/wrpll.rs | 28 +++++++++---- artiq/gateware/drtio/wrpll/core.py | 58 ++++++++++++++++---------- 2 files changed, 56 insertions(+), 30 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 2261cb262..8c35c0cb8 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -264,12 +264,25 @@ mod si549 { } } -fn get_helper_frequency() -> u32 { - unsafe { csr::wrpll::helper_frequency_start_write(1); } - clock::spin_us(10_000); - unsafe { csr::wrpll::helper_frequency_stop_write(1); } - clock::spin_us(1); - unsafe { csr::wrpll::helper_frequency_counter_read() } +fn get_frequencies() -> (u32, u32, u32) { + unsafe { + csr::wrpll::frequency_counter_update_en_write(1); + clock::spin_us(200_000); // wait for at least one update + csr::wrpll::frequency_counter_update_en_write(0); + clock::spin_us(1); + let helper = csr::wrpll::frequency_counter_counter_helper_read(); + let main = csr::wrpll::frequency_counter_counter_rtio_read(); + let cdr = csr::wrpll::frequency_counter_counter_rtio_rx0_read(); + (helper, main, cdr) + } +} + +fn log_frequencies() { + let (f_helper, f_main, f_cdr) = get_frequencies(); + let conv_khz = |f| 4*(f as u64)*(csr::CONFIG_CLOCK_FREQUENCY as u64)/(1000*(1 << 23)); + info!("helper clock frequency: {}kHz ({})", conv_khz(f_helper), f_helper); + info!("main clock frequency: {}kHz ({})", conv_khz(f_main), f_main); + info!("CDR clock frequency: {}kHz ({})", conv_khz(f_cdr), f_cdr); } fn get_ddmtd_main_tag() -> u16 { @@ -309,7 +322,7 @@ pub fn init() { unsafe { csr::wrpll::helper_reset_write(0); } clock::spin_us(1); - info!("helper clock frequency: {}MHz", get_helper_frequency()/10000); + log_frequencies(); let mut tags = [0; 10]; for i in 0..tags.len() { tags[i] = get_ddmtd_main_tag(); @@ -319,6 +332,7 @@ pub fn init() { pub fn select_recovered_clock(rc: bool) { info!("select_recovered_clock: {}", rc); + log_frequencies(); if rc { let mut tags = [0; 10]; for i in 0..tags.len() { diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 35902d752..a37aa1a4b 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -9,32 +9,43 @@ from artiq.gateware.drtio.wrpll import thls, filters class FrequencyCounter(Module, AutoCSR): - def __init__(self): - self.counter = CSRStatus(32) - self.start = CSR() - self.stop = CSR() + def __init__(self, timer_width=23, counter_width=23, domains=["helper", "rtio", "rtio_rx0"]): + for domain in domains: + name = "counter_" + domain + counter = CSRStatus(counter_width, name=name) + setattr(self, name, counter) + self.update_en = CSRStorage() - ps_start = PulseSynchronizer("sys", "helper") - ps_stop = PulseSynchronizer("sys", "helper") - self.submodules += ps_start, ps_stop + timer = Signal(timer_width) + timer_tick = Signal() + self.sync += Cat(timer, timer_tick).eq(timer + 1) - self.comb += [ - ps_start.i.eq(self.start.re & self.start.r), - ps_stop.i.eq(self.stop.re & self.stop.r) - ] + for domain in domains: + sync_domain = getattr(self.sync, domain) + divider = Signal(2) + sync_domain += divider.eq(divider + 1) - counter = Signal(32) - self.specials += MultiReg(counter, self.counter.status) + divided = Signal() + divided.attr.add("no_retiming") + sync_domain += divided.eq(divider[-1]) + divided_sys = Signal() + self.specials += MultiReg(divided, divided_sys) - counting = Signal() - self.sync.helper += [ - If(counting, counter.eq(counter + 1)), - If(ps_start.o, - counter.eq(0), - counting.eq(1) - ), - If(ps_stop.o, counting.eq(0)) - ] + divided_sys_r = Signal() + divided_tick = Signal() + self.sync += divided_sys_r.eq(divided_sys) + self.comb += divided_tick.eq(divided_sys & ~divided_sys_r) + + counter = Signal(counter_width) + counter_csr = getattr(self, "counter_" + domain) + self.sync += [ + If(timer_tick, + If(self.update_en.storage, counter_csr.status.eq(counter)), + counter.eq(0), + ).Else( + If(divided_tick, counter.eq(counter + 1)) + ) + ] class WRPLL(Module, AutoCSR): @@ -52,7 +63,8 @@ class WRPLL(Module, AutoCSR): self.submodules.helper_dcxo = Si549(helper_dxco_i2c) self.submodules.main_dcxo = Si549(main_dcxo_i2c) - self.submodules.helper_frequency = FrequencyCounter() # for diagnostics + # for diagnostics and PLL initialization + self.submodules.frequency_counter = FrequencyCounter() ddmtd_counter = Signal(N) self.sync.helper += ddmtd_counter.eq(ddmtd_counter + 1) From 642a305c6a9c5e6f9bcd5ff631ab79d092660adf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 30 Dec 2019 20:01:06 +0800 Subject: [PATCH 2079/2457] wrpll: remove unnecessary delay Counting now happens in the sys domain with no CDC between counter and CPU. --- artiq/firmware/libboard_artiq/wrpll.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 8c35c0cb8..29910723d 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -269,7 +269,6 @@ fn get_frequencies() -> (u32, u32, u32) { csr::wrpll::frequency_counter_update_en_write(1); clock::spin_us(200_000); // wait for at least one update csr::wrpll::frequency_counter_update_en_write(0); - clock::spin_us(1); let helper = csr::wrpll::frequency_counter_counter_helper_read(); let main = csr::wrpll::frequency_counter_counter_rtio_read(); let cdr = csr::wrpll::frequency_counter_counter_rtio_rx0_read(); From 5c6e3949280c81b65b7b709bcbdbc3f70a192448 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 30 Dec 2019 22:17:44 +0800 Subject: [PATCH 2080/2457] ddmtd: add collector --- artiq/gateware/drtio/wrpll/core.py | 21 ++++++++++++++++++++- artiq/gateware/drtio/wrpll/ddmtd.py | 20 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index a37aa1a4b..dc026f3b9 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -4,7 +4,7 @@ from migen.genlib.cdc import MultiReg, PulseSynchronizer from misoc.interconnect.csr import * from artiq.gateware.drtio.wrpll.si549 import Si549 -from artiq.gateware.drtio.wrpll.ddmtd import DDMTD +from artiq.gateware.drtio.wrpll.ddmtd import DDMTD, Collector from artiq.gateware.drtio.wrpll import thls, filters @@ -72,8 +72,27 @@ class WRPLL(Module, AutoCSR): self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_inputs.main_xo) helper_cd = ClockDomainsRenamer("helper") + self.submodules.collector = helper_cd(Collector(N)) self.submodules.filter_helper = helper_cd(thls.make(filters.helper, data_width=48)) self.submodules.filter_main = helper_cd(thls.make(filters.main, data_width=48)) + + self.comb += [ + self.collector.tag_helper.eq(self.ddmtd_helper.h_tag), + self.collector.tag_helper_update.eq(self.ddmtd_helper.h_tag_update), + self.collector.tag_main.eq(self.ddmtd_main.h_tag), + self.collector.tag_main_update.eq(self.ddmtd_main.h_tag_update) + ] + + # compensate the 1 cycle latency of the collector + self.sync.helper += [ + self.filter_helper.input.eq(self.ddmtd_helper.h_tag), + self.filter_helper.input_stb.eq(self.ddmtd_helper.h_tag_update) + ] + self.comb += [ + self.filter_main.input.eq(self.collector.output), + self.filter_main.input_stb.eq(self.collector.output_update) + ] + self.comb += [ self.helper_dcxo.adpll_stb.eq(self.filter_helper.output_stb), self.helper_dcxo.adpll.eq(self.filter_helper.output), diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index f46df4463..2fe7f7e64 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -103,3 +103,23 @@ class DDMTD(Module, AutoCSR): self.arm.w.eq(0), ) ] + + +class Collector(Module): + def __init__(self, N): + self.tag_helper = Signal(N) + self.tag_helper_update = Signal() + self.tag_main = Signal(N) + self.tag_main_update = Signal() + + self.output = Signal(N) + self.output_update = Signal(N) + + # # # + + last_tag_main = Signal(N) + self.sync += [ + If(self.tag_main_update, last_tag_main.eq(self.tag_main)), + self.output_update.eq(self.tag_helper_update), + self.output.eq(last_tag_main - self.tag_helper) + ] From a666766f382a5c3303daa46fb0c7a7c02c38f0b5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 30 Dec 2019 22:19:42 +0800 Subject: [PATCH 2081/2457] wrpll: add ADPLL offset registers --- artiq/gateware/drtio/wrpll/core.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index dc026f3b9..ad2dd4e3c 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -51,6 +51,8 @@ class FrequencyCounter(Module, AutoCSR): class WRPLL(Module, AutoCSR): def __init__(self, helper_clk_pads, main_dcxo_i2c, helper_dxco_i2c, ddmtd_inputs, N=15): self.helper_reset = CSRStorage(reset=1) + self.adpll_offset_helper = CSRStorage(24) + self.adpll_offset_main = CSRStorage(24) self.clock_domains.cd_helper = ClockDomain() self.helper_reset.storage.attr.add("no_retiming") @@ -93,9 +95,9 @@ class WRPLL(Module, AutoCSR): self.filter_main.input_stb.eq(self.collector.output_update) ] - self.comb += [ + self.sync.helper += [ self.helper_dcxo.adpll_stb.eq(self.filter_helper.output_stb), - self.helper_dcxo.adpll.eq(self.filter_helper.output), + self.helper_dcxo.adpll.eq(self.filter_helper.output + self.adpll_offset_helper.storage), self.main_dcxo.adpll_stb.eq(self.filter_main.output_stb), - self.main_dcxo.adpll.eq(self.filter_main.output) + self.main_dcxo.adpll.eq(self.filter_main.output + self.adpll_offset_main.storage) ] From 1e864b7e2d6f794d22fa160e2fd12b9478ed179f Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 30 Dec 2019 20:02:22 +0000 Subject: [PATCH 2082/2457] coredevice/suservo: Add separate methods for setting only the IIR offset --- artiq/coredevice/suservo.py | 44 ++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index 8855fd2ef..b3d27c870 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -294,7 +294,7 @@ class Channel: base = (self.servo_channel << 8) | (profile << 3) self.servo.write(base + 0, ftw >> 16) self.servo.write(base + 6, (ftw & 0xffff)) - self.servo.write(base + 4, offs) + self.set_dds_offset_mu(profile, offs) self.servo.write(base + 2, pow_) @kernel @@ -307,10 +307,8 @@ class Channel: :param profile: Profile number (0-31) :param frequency: DDS frequency in Hz - :param offset: IIR offset (negative setpoint) in units of full scale. - For positive ADC voltages as setpoints, this should be negative. - Due to rounding and representation as two's complement, - ``offset=1`` can not be represented while ``offset=-1`` can. + :param offset: IIR offset (negative setpoint) in units of full scale, + see :meth:`dds_offset_to_mu` :param phase: DDS phase in turns """ if self.servo_channel < 4: @@ -319,9 +317,43 @@ class Channel: dds = self.servo.dds1 ftw = dds.frequency_to_ftw(frequency) pow_ = dds.turns_to_pow(phase) - offs = int(round(offset*(1 << COEFF_WIDTH - 1))) + offs = self.dds_offset_to_mu(offset) self.set_dds_mu(profile, ftw, offs, pow_) + @kernel + def set_dds_offset_mu(self, profile, offs): + """Set only IIR offset in DDS coefficient profile. + + See :meth:`set_dds_mu` for setting the complete DDS profile. + + :param profile: Profile number (0-31) + :param offs: IIR offset (17 bit signed) + """ + base = (self.servo_channel << 8) | (profile << 3) + self.servo.write(base + 4, offs) + + @kernel + def set_dds_offset(self, profile, offset): + """Set only IIR offset in DDS coefficient profile. + + See :meth:`set_dds` for setting the complete DDS profile. + + :param profile: Profile number (0-31) + :param offset: IIR offset (negative setpoint) in units of full scale + """ + self.set_dds_offset_mu(profile, self.dds_offset_to_mu(offset)) + + @portable + def dds_offset_to_mu(self, offset): + """Convert IIR offset (negative setpoint) from units of full scale to + machine units (see :meth:`set_dds_mu`, :meth:`set_dds_offset_mu`). + + For positive ADC voltages as setpoints, this should be negative. Due to + rounding and representation as two's complement, ``offset=1`` can not + be represented while ``offset=-1`` can. + """ + return int(round(offset * (1 << COEFF_WIDTH - 1))) + @kernel def set_iir_mu(self, profile, adc, a1, b0, b1, dly=0): """Set profile IIR coefficients in machine units. From bb04b082a7fddd654f067dad7749386ba7f6bb24 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 31 Dec 2019 11:36:26 +0800 Subject: [PATCH 2083/2457] wrpll: clarify comment --- artiq/firmware/libboard_artiq/wrpll.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 29910723d..b42166670 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -267,7 +267,8 @@ mod si549 { fn get_frequencies() -> (u32, u32, u32) { unsafe { csr::wrpll::frequency_counter_update_en_write(1); - clock::spin_us(200_000); // wait for at least one update + // wait for at least one full update cycle (> 2 timer periods) + clock::spin_us(200_000); csr::wrpll::frequency_counter_update_en_write(0); let helper = csr::wrpll::frequency_counter_counter_helper_read(); let main = csr::wrpll::frequency_counter_counter_rtio_read(); From 3f32d78c0efc9b4067baead3f93d995d2c70d1e4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 31 Dec 2019 12:12:03 +0800 Subject: [PATCH 2084/2457] wrpll: simple ADPLL test --- artiq/firmware/libboard_artiq/wrpll.rs | 18 ++++++++++++++++++ artiq/firmware/satman/main.rs | 2 ++ 2 files changed, 20 insertions(+) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index b42166670..bf935f36a 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -262,6 +262,13 @@ mod si549 { Ok(()) } + + pub fn adpll(dcxo: i2c::Dcxo, adpll: i32) -> Result<(), &'static str> { + write(dcxo, 231, adpll as u8)?; + write(dcxo, 232, (adpll >> 8) as u8)?; + write(dcxo, 233, (adpll >> 16) as u8)?; + Ok(()) + } } fn get_frequencies() -> (u32, u32, u32) { @@ -321,8 +328,19 @@ pub fn init() { unsafe { csr::wrpll::helper_reset_write(0); } clock::spin_us(1); +} +pub fn diagnostics() { log_frequencies(); + + info!("ADPLL test:"); + // +/-10ppm + si549::adpll(i2c::Dcxo::Helper, -85911).expect("ADPLL write failed"); + si549::adpll(i2c::Dcxo::Main, 85911).expect("ADPLL write failed"); + log_frequencies(); + si549::adpll(i2c::Dcxo::Helper, 0).expect("ADPLL write failed"); + si549::adpll(i2c::Dcxo::Main, 0).expect("ADPLL write failed"); + let mut tags = [0; 10]; for i in 0..tags.len() { tags[i] = get_ddmtd_main_tag(); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 5225eba1b..3b5096fd8 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -463,6 +463,8 @@ pub extern fn main() -> i32 { csr::drtio_transceiver::stable_clkin_write(1); } clock::spin_us(1500); // wait for CPLL/QPLL lock + #[cfg(has_wrpll)] + wrpll::diagnostics(); init_rtio_crg(); #[cfg(has_hmc830_7043)] From eebae01503add4324a098e73ca5d0f764e4118a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 31 Dec 2019 13:00:26 +0100 Subject: [PATCH 2085/2457] artiq_client: add back quiet-verbose args for submission close #1416 regression introduced in 3fd6962 --- artiq/frontend/artiq_client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_client.py b/artiq/frontend/artiq_client.py index 03b49d2dc..7194a4e45 100755 --- a/artiq/frontend/artiq_client.py +++ b/artiq/frontend/artiq_client.py @@ -20,7 +20,7 @@ from prettytable import PrettyTable from sipyco.pc_rpc import Client from sipyco.sync_struct import Subscriber from sipyco.broadcast import Receiver -from sipyco import pyon +from sipyco import common_args, pyon from artiq.tools import short_format, parse_arguments from artiq import __version__ as artiq_version @@ -122,6 +122,7 @@ def get_argparser(): "ls", help="list a directory on the master") parser_ls.add_argument("directory", default="", nargs="?") + common_args.verbosity_args(parser) return parser From 2c34f0214ba9f6c62f7f5433da46232b360b3147 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 23 Dec 2019 01:27:18 +0000 Subject: [PATCH 2086/2457] compiler: Short-circuit Type.unify() with identical other type This considerably improves performance; ~15% in terms of total artiq_run-to-kernel-compiled duration in one test case. --- artiq/compiler/types.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/artiq/compiler/types.py b/artiq/compiler/types.py index a8a2e5703..1f2a62a05 100644 --- a/artiq/compiler/types.py +++ b/artiq/compiler/types.py @@ -81,6 +81,8 @@ class TVar(Type): return root def unify(self, other): + if other is self: + return other = other.find() if self.parent is self: @@ -124,6 +126,8 @@ class TMono(Type): return self def unify(self, other): + if other is self: + return if isinstance(other, TMono) and self.name == other.name: assert self.params.keys() == other.params.keys() for param in self.params: @@ -171,6 +175,8 @@ class TTuple(Type): return self def unify(self, other): + if other is self: + return if isinstance(other, TTuple) and len(self.elts) == len(other.elts): for selfelt, otherelt in zip(self.elts, other.elts): selfelt.unify(otherelt) @@ -237,6 +243,8 @@ class TFunction(Type): return self def unify(self, other): + if other is self: + return if isinstance(other, TFunction) and \ self.args.keys() == other.args.keys() and \ self.optargs.keys() == other.optargs.keys(): @@ -296,6 +304,8 @@ class TCFunction(TFunction): self.flags = flags def unify(self, other): + if other is self: + return if isinstance(other, TCFunction) and \ self.name == other.name: super().unify(other) @@ -324,6 +334,8 @@ class TRPC(Type): return self def unify(self, other): + if other is self: + return if isinstance(other, TRPC) and \ self.service == other.service and \ self.is_async == other.is_async: @@ -366,6 +378,8 @@ class TBuiltin(Type): return self def unify(self, other): + if other is self: + return if self != other: raise UnificationError(self, other) @@ -471,6 +485,8 @@ class TValue(Type): return self def unify(self, other): + if other is self: + return if isinstance(other, TVar): other.unify(self) elif self != other: From d8c81d6d05ad0606dac69193c6db6cfa2f7094af Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 23 Dec 2019 01:29:13 +0000 Subject: [PATCH 2087/2457] compiler: Other types microoptimisations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Interestingly enough, these actually seem to give a measurable speedup (if small – about 1% improvement out of 6s whole-program compile-time in one particular test case). The previous implementation of is_mono() had also interesting behaviour if `name` wasn't given; it would test only for the presence of any keys specified via keyword arguments, disregarding their values. Looking at uses across the current ARTIQ codebase, I could neither find a case where this would have actually been triggered, nor any rationale for it. With the short-circuited implementation from this commit, is_mono() now checks name/all of params against any specified conditions. --- artiq/compiler/types.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/artiq/compiler/types.py b/artiq/compiler/types.py index 1f2a62a05..5299822c3 100644 --- a/artiq/compiler/types.py +++ b/artiq/compiler/types.py @@ -73,7 +73,7 @@ class TVar(Type): # path compression iter = self while iter.__class__ == TVar: - if iter is iter.parent: + if iter is root: break else: iter, iter.parent = iter.parent, root @@ -577,13 +577,15 @@ def is_mono(typ, name=None, **params): if not isinstance(typ, TMono): return False - params_match = True + if name is not None and typ.name != name: + return False + for param in params: if param not in typ.params: return False - params_match = params_match and \ - typ.params[param].find() == params[param].find() - return name is None or (typ.name == name and params_match) + if typ.params[param].find() != params[param].find(): + return False + return True def is_polymorphic(typ): return typ.fold(False, lambda accum, typ: accum or is_var(typ)) From 583a18dd5f2aa6319fd030dcdd8add6bc4e60c4d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 10 Jan 2020 14:33:02 +0800 Subject: [PATCH 2088/2457] firmware: expose fmod to kernels. Closes #1417 --- artiq/firmware/ksupport/api.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 00c0f23e6..6d14891a7 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -70,6 +70,7 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(sqrt), api!(round), api!(floor), + api!(fmod), /* exceptions */ api!(_Unwind_Resume = ::unwind::_Unwind_Resume), From 9dd011f4ad8cd5e7217766bdf9a2e99cd17dc92e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 13 Jan 2020 17:28:27 +0800 Subject: [PATCH 2089/2457] firmware: remove bitrotten Sayma code --- artiq/firmware/runtime/main.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 9cc34edc6..02e3fa61a 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -88,23 +88,6 @@ fn setup_log_levels() { } } -fn sayma_hw_init() { - #[cfg(has_hmc830_7043)] - /* must be the first SPI init because of HMC830 SPI mode selection */ - board_artiq::hmc830_7043::init().expect("cannot initialize HMC830/7043"); - #[cfg(has_ad9154)] - { - board_artiq::ad9154::jesd_reset(false); - board_artiq::ad9154::init(); - if let Err(e) = board_artiq::jesd204sync::sysref_auto_rtio_align() { - error!("failed to align SYSREF at FPGA: {}", e); - } - if let Err(e) = board_artiq::jesd204sync::sysref_auto_dac_align() { - error!("failed to align SYSREF at DAC: {}", e); - } - } -} - fn startup() { irq::set_mask(0); irq::set_ie(true); @@ -116,7 +99,6 @@ fn startup() { setup_log_levels(); #[cfg(has_i2c)] board_misoc::i2c::init().expect("I2C initialization failed"); - sayma_hw_init(); rtio_clocking::init(); let mut net_device = unsafe { ethmac::EthernetDevice::new() }; From 8edbc33d0e8024fce685be7410ee6b6e5502ce19 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 13 Jan 2020 19:29:10 +0800 Subject: [PATCH 2090/2457] wrpll: calculate initial ADPLL offsets --- artiq/firmware/libboard_artiq/wrpll.rs | 77 ++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index bf935f36a..dacb7fc03 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -284,12 +284,13 @@ fn get_frequencies() -> (u32, u32, u32) { } } -fn log_frequencies() { +fn log_frequencies() -> (u32, u32, u32) { let (f_helper, f_main, f_cdr) = get_frequencies(); let conv_khz = |f| 4*(f as u64)*(csr::CONFIG_CLOCK_FREQUENCY as u64)/(1000*(1 << 23)); info!("helper clock frequency: {}kHz ({})", conv_khz(f_helper), f_helper); info!("main clock frequency: {}kHz ({})", conv_khz(f_main), f_main); info!("CDR clock frequency: {}kHz ({})", conv_khz(f_cdr), f_cdr); + (f_helper, f_main, f_cdr) } fn get_ddmtd_main_tag() -> u16 { @@ -348,14 +349,82 @@ pub fn diagnostics() { info!("DDMTD main tags: {:?}", tags); } -pub fn select_recovered_clock(rc: bool) { - info!("select_recovered_clock: {}", rc); - log_frequencies(); +fn trim_dcxos(f_helper: u32, f_main: u32, f_cdr: u32) -> Result<(i32, i32), &'static str> { + const DCXO_STEP: i64 = (1.0e6/0.0001164) as i64; + const ADPLL_MAX: i64 = (950.0/0.0001164) as i64; + + const TIMER_WIDTH: u32 = 23; + const COUNTER_DIV: u32 = 2; + + const F_SYS: f64 = 125.0e6; + const F_MAIN: f64 = 125.0e6; + const F_HELPER: f64 = F_MAIN * ((1 << 15) as f64)/((1<<15) as f64 + 1.0); + + const SYS_COUNTS: i64 = (1 << (TIMER_WIDTH - COUNTER_DIV)) as i64; + const EXP_MAIN_COUNTS: i64 = ((SYS_COUNTS as f64) * (F_MAIN/F_SYS)) as i64; + const EXP_HELPER_COUNTS: i64 = ((SYS_COUNTS as f64) * (F_HELPER/F_SYS)) as i64; + + info!("after {} sys counts", SYS_COUNTS); + info!("expect {} main/CDR counts", EXP_MAIN_COUNTS); + info!("expect {} helper counts", EXP_HELPER_COUNTS); + + // calibrate the SYS clock to the CDR clock and correct the measured counts + // assume frequency errors are small so we can make an additive correction + // positive error means sys clock is too fast + let sys_err: i64 = EXP_MAIN_COUNTS - (f_cdr as i64); + let main_err: i64 = EXP_MAIN_COUNTS - (f_main as i64) - sys_err; + let helper_err: i64 = EXP_HELPER_COUNTS - (f_helper as i64) - sys_err; + + info!("sys count err {}", sys_err); + info!("main counts err {}", main_err); + info!("helper counts err {}", helper_err); + + // calculate required adjustment to the ADPLL register see + // https://www.silabs.com/documents/public/data-sheets/si549-datasheet.pdf + // section 5.6 + let helper_adpll: i64 = helper_err*DCXO_STEP/EXP_HELPER_COUNTS; + let main_adpll: i64 = main_err*DCXO_STEP/EXP_MAIN_COUNTS; + if helper_adpll.abs() > ADPLL_MAX { + return Err("helper DCXO offset too large"); + } + if main_adpll.abs() > ADPLL_MAX { + return Err("main DCXO offset too large"); + } + + Ok((helper_adpll as i32, main_adpll as i32)) +} + +fn select_recovered_clock_int(rc: bool) -> Result<(), &'static str> { + let (f_helper, f_main, f_cdr) = log_frequencies(); if rc { + let (helper_adpll, main_adpll) = trim_dcxos(f_helper, f_main, f_cdr)?; + si549::adpll(i2c::Dcxo::Helper, helper_adpll).expect("ADPLL write failed"); + si549::adpll(i2c::Dcxo::Main, main_adpll).expect("ADPLL write failed"); + unsafe { + csr::wrpll::adpll_offset_helper_write(helper_adpll as u32); + csr::wrpll::adpll_offset_main_write(main_adpll as u32); + } + let mut tags = [0; 10]; for i in 0..tags.len() { tags[i] = get_ddmtd_helper_tag(); } info!("DDMTD helper tags: {:?}", tags); + } else { + si549::adpll(i2c::Dcxo::Helper, 0).expect("ADPLL write failed"); + si549::adpll(i2c::Dcxo::Main, 0).expect("ADPLL write failed"); + } + Ok(()) +} + +pub fn select_recovered_clock(rc: bool) { + if rc { + info!("switching to recovered clock"); + } else { + info!("switching to local XO clock"); + } + match select_recovered_clock_int(rc) { + Ok(()) => info!("clock transition completed"), + Err(e) => error!("clock transition failed: {}", e) } } From e87d864063c31cec2af63d05c42872544da015bd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 13 Jan 2020 19:32:30 +0800 Subject: [PATCH 2091/2457] wrpll: print ADPLL offsets --- artiq/firmware/libboard_artiq/wrpll.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index dacb7fc03..bb24d8f16 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -391,6 +391,7 @@ fn trim_dcxos(f_helper: u32, f_main: u32, f_cdr: u32) -> Result<(i32, i32), &'st return Err("main DCXO offset too large"); } + info!("ADPLL offsets: helper={} main={}", helper_adpll, main_adpll); Ok((helper_adpll as i32, main_adpll as i32)) } From 9d7196bdb704aba04adaf168588064fdfae879fc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 13 Jan 2020 19:33:44 +0800 Subject: [PATCH 2092/2457] update copyright year --- README.rst | 2 +- artiq/firmware/bootloader/main.rs | 2 +- doc/manual/conf.py | 2 +- doc/manual/introduction.rst | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 7357f34bd..6e3bcbd70 100644 --- a/README.rst +++ b/README.rst @@ -29,7 +29,7 @@ Website: https://m-labs.hk/artiq License ======= -Copyright (C) 2014-2019 M-Labs Limited. +Copyright (C) 2014-2020 M-Labs Limited. ARTIQ is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 52d5eefac..39cf81c40 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -491,7 +491,7 @@ pub extern fn main() -> i32 { println!(r"|_| |_|_|____/ \___/ \____|"); println!(""); println!("MiSoC Bootloader"); - println!("Copyright (c) 2017-2019 M-Labs Limited"); + println!("Copyright (c) 2017-2020 M-Labs Limited"); println!(""); #[cfg(has_ethmac)] diff --git a/doc/manual/conf.py b/doc/manual/conf.py index a02b2c9f8..266426c78 100644 --- a/doc/manual/conf.py +++ b/doc/manual/conf.py @@ -89,7 +89,7 @@ master_doc = 'index' # General information about the project. project = 'ARTIQ' -copyright = '2014-2019, M-Labs Limited' +copyright = '2014-2020, M-Labs Limited' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/doc/manual/introduction.rst b/doc/manual/introduction.rst index 3f0603445..6336ba4ee 100644 --- a/doc/manual/introduction.rst +++ b/doc/manual/introduction.rst @@ -27,4 +27,4 @@ Website: https://m-labs.hk/artiq `Cite ARTIQ `_ as ``Bourdeauducq, Sébastien et al. (2016). ARTIQ 1.0. Zenodo. 10.5281/zenodo.51303``. -Copyright (C) 2014-2019 M-Labs Limited. Licensed under GNU LGPL version 3+. +Copyright (C) 2014-2020 M-Labs Limited. Licensed under GNU LGPL version 3+. From d685619bcd7cdcd09ed3556ee5e155e753054319 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 13 Jan 2020 20:42:41 +0800 Subject: [PATCH 2093/2457] wrpll: collector code modifications from Weida --- artiq/gateware/drtio/wrpll/ddmtd.py | 38 ++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index 2fe7f7e64..978706961 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -1,5 +1,6 @@ from migen import * from migen.genlib.cdc import PulseSynchronizer, MultiReg +from migen.genlib.fsm import FSM from misoc.interconnect.csr import * @@ -117,9 +118,38 @@ class Collector(Module): # # # - last_tag_main = Signal(N) + fsm = FSM() + self.submodules += fsm + + tag_collector = Signal(N) + fsm.act("IDLE", + If(self.tag_main_update & self.tag_helper_update, + NextValue(tag_collector, 0), + NextState("IDLE") + ).Elif(self.tag_main_update, + NextValue(tag_collector, self.tag_main), + NextState("WAITHELPER") + ).Elif(self.tag_helper_update, + NextValue(tag_collector, -self.tag_helper), + NextState("WAITMAIN") + ) + ) + fsm.act("WAITHELPER", + If(self.tag_helper_update, + NextValue(tag_collector, tag_collector - self.tag_helper), + NextState("IDLE") + ) + ) + fsm.act("WAITMAIN", + If(self.tag_main_update, + NextValue(tag_collector, tag_collector + self.tag_main), + NextState("IDLE") + ) + ) self.sync += [ - If(self.tag_main_update, last_tag_main.eq(self.tag_main)), - self.output_update.eq(self.tag_helper_update), - self.output.eq(last_tag_main - self.tag_helper) + self.output_update.eq(0), + If(self.tag_helper_update, + self.output_update.eq(1), + self.output.eq(tag_collector) + ) ] From ea3bce6fe34a4258cea834796272ccf60de0a7df Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 13 Jan 2020 20:43:34 +0800 Subject: [PATCH 2094/2457] wrpll: wait for settling time after setting ADPLL --- artiq/firmware/libboard_artiq/wrpll.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index bb24d8f16..fbf133d4b 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -267,6 +267,7 @@ mod si549 { write(dcxo, 231, adpll as u8)?; write(dcxo, 232, (adpll >> 8) as u8)?; write(dcxo, 233, (adpll >> 16) as u8)?; + clock::spin_us(100); Ok(()) } } From e7ef23d30c4e1605efe0254749d08b21e351c47b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 13 Jan 2020 20:44:15 +0800 Subject: [PATCH 2095/2457] wrpll: use CONFIG_CLOCK_FREQUENCY and rtio_frequency in trim_dcxos --- artiq/firmware/libboard_artiq/wrpll.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index fbf133d4b..ed0f27ba6 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -357,7 +357,8 @@ fn trim_dcxos(f_helper: u32, f_main: u32, f_cdr: u32) -> Result<(i32, i32), &'st const TIMER_WIDTH: u32 = 23; const COUNTER_DIV: u32 = 2; - const F_SYS: f64 = 125.0e6; + const F_SYS: f64 = csr::CONFIG_CLOCK_FREQUENCY as f64; + #[cfg(rtio_frequency = "125.0")] const F_MAIN: f64 = 125.0e6; const F_HELPER: f64 = F_MAIN * ((1 << 15) as f64)/((1<<15) as f64 + 1.0); From d5895b8999d6b6bc7ab1a233e23b61ebae8635be Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 13 Jan 2020 20:46:36 +0800 Subject: [PATCH 2096/2457] wrpll: adpll -> set_adpll --- artiq/firmware/libboard_artiq/wrpll.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index ed0f27ba6..c1343df20 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -263,7 +263,7 @@ mod si549 { Ok(()) } - pub fn adpll(dcxo: i2c::Dcxo, adpll: i32) -> Result<(), &'static str> { + pub fn set_adpll(dcxo: i2c::Dcxo, adpll: i32) -> Result<(), &'static str> { write(dcxo, 231, adpll as u8)?; write(dcxo, 232, (adpll >> 8) as u8)?; write(dcxo, 233, (adpll >> 16) as u8)?; @@ -337,11 +337,11 @@ pub fn diagnostics() { info!("ADPLL test:"); // +/-10ppm - si549::adpll(i2c::Dcxo::Helper, -85911).expect("ADPLL write failed"); - si549::adpll(i2c::Dcxo::Main, 85911).expect("ADPLL write failed"); + si549::set_adpll(i2c::Dcxo::Helper, -85911).expect("ADPLL write failed"); + si549::set_adpll(i2c::Dcxo::Main, 85911).expect("ADPLL write failed"); log_frequencies(); - si549::adpll(i2c::Dcxo::Helper, 0).expect("ADPLL write failed"); - si549::adpll(i2c::Dcxo::Main, 0).expect("ADPLL write failed"); + si549::set_adpll(i2c::Dcxo::Helper, 0).expect("ADPLL write failed"); + si549::set_adpll(i2c::Dcxo::Main, 0).expect("ADPLL write failed"); let mut tags = [0; 10]; for i in 0..tags.len() { @@ -401,8 +401,8 @@ fn select_recovered_clock_int(rc: bool) -> Result<(), &'static str> { let (f_helper, f_main, f_cdr) = log_frequencies(); if rc { let (helper_adpll, main_adpll) = trim_dcxos(f_helper, f_main, f_cdr)?; - si549::adpll(i2c::Dcxo::Helper, helper_adpll).expect("ADPLL write failed"); - si549::adpll(i2c::Dcxo::Main, main_adpll).expect("ADPLL write failed"); + si549::set_adpll(i2c::Dcxo::Helper, helper_adpll).expect("ADPLL write failed"); + si549::set_adpll(i2c::Dcxo::Main, main_adpll).expect("ADPLL write failed"); unsafe { csr::wrpll::adpll_offset_helper_write(helper_adpll as u32); csr::wrpll::adpll_offset_main_write(main_adpll as u32); @@ -414,8 +414,8 @@ fn select_recovered_clock_int(rc: bool) -> Result<(), &'static str> { } info!("DDMTD helper tags: {:?}", tags); } else { - si549::adpll(i2c::Dcxo::Helper, 0).expect("ADPLL write failed"); - si549::adpll(i2c::Dcxo::Main, 0).expect("ADPLL write failed"); + si549::set_adpll(i2c::Dcxo::Helper, 0).expect("ADPLL write failed"); + si549::set_adpll(i2c::Dcxo::Main, 0).expect("ADPLL write failed"); } Ok(()) } From 8ec0f2e717c0d142ede817d6d8f8c906e1fc49a8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 13 Jan 2020 22:30:11 +0800 Subject: [PATCH 2097/2457] wrpll: implement ADPLLProgrammer --- artiq/gateware/drtio/wrpll/si549.py | 117 +++++++++++++++++++--------- 1 file changed, 81 insertions(+), 36 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/si549.py b/artiq/gateware/drtio/wrpll/si549.py index a0f2c985a..476786c64 100644 --- a/artiq/gateware/drtio/wrpll/si549.py +++ b/artiq/gateware/drtio/wrpll/si549.py @@ -30,18 +30,17 @@ class I2CMasterMachine(Module): self.sda_i = Signal() self.submodules.cg = CEInserter()(I2CClockGen(clock_width)) - self.idle = Signal() self.start = Signal() self.stop = Signal() self.write = Signal() - self.read = Signal() self.ack = Signal() self.data = Signal(8) + self.idle = Signal() ### - busy = Signal() bits = Signal(4) + data = Signal(8) fsm = CEInserter()(FSM("IDLE")) self.submodules += fsm @@ -55,10 +54,8 @@ class I2CMasterMachine(Module): NextState("STOP0"), ).Elif(self.write, NextValue(bits, 8), - NextState("WRITE0"), - ).Elif(self.read, - NextValue(bits, 8), - NextState("READ0"), + NextValue(data, self.data), + NextState("WRITE0") ) ) @@ -93,13 +90,13 @@ class I2CMasterMachine(Module): NextValue(self.sda_o, 1), NextState("READACK0"), ).Else( - NextValue(self.sda_o, self.data[7]), + NextValue(self.sda_o, data[7]), NextState("WRITE1"), ) ) fsm.act("WRITE1", NextValue(self.scl, 1), - NextValue(self.data[1:], self.data[:-1]), + NextValue(data[1:], data[:-1]), NextValue(bits, bits - 1), NextState("WRITE0"), ) @@ -112,35 +109,9 @@ class I2CMasterMachine(Module): NextState("IDLE") ) - fsm.act("READ0", - NextValue(self.scl, 0), - NextState("READ1"), - ) - fsm.act("READ1", - NextValue(self.data[0], self.sda_i), - NextValue(self.scl, 0), - If(bits == 0, - NextValue(self.sda_o, ~self.ack), - NextState("WRITEACK0"), - ).Else( - NextValue(self.sda_o, 1), - NextState("READ2"), - ) - ) - fsm.act("READ2", - NextValue(self.scl, 1), - NextValue(self.data[:-1], self.data[1:]), - NextValue(bits, bits - 1), - NextState("READ1"), - ) - fsm.act("WRITEACK0", - NextValue(self.scl, 1), - NextState("IDLE"), - ) - run = Signal() self.comb += [ - run.eq(self.start | self.stop | self.write | self.read), + run.eq(self.start | self.stop | self.write), self.idle.eq(~run & fsm.ongoing("IDLE")), self.cg.ce.eq(~self.idle), fsm.ce.eq(run | self.cg.clk2x), @@ -176,6 +147,80 @@ class ADPLLProgrammer(Module): self.sda_o.eq(master.sda_o) ] + fsm = FSM() + self.submodules += fsm + + adpll = Signal.like(self.adpll) + + fsm.act("IDLE", + If(self.stb, + NextValue(adpll, self.adpll), + NextState("START") + ) + ) + fsm.act("START", + master.start.eq(1), + If(master.idle, NextState("DEVADDRESS")) + ) + fsm.act("DEVADDRESS", + master.data.eq(self.i2c_address << 1), + master.write.eq(1), + If(master.idle, NextState("REGADRESS")) + ) + fsm.act("REGADRESS", + master.data.eq(231), + master.write.eq(1), + If(master.idle, + If(master.ack, + NextState("DATA0") + ).Else( + self.nack.eq(1), + NextState("STOP") + ) + ) + ) + fsm.act("DATA0", + master.data.eq(adpll[0:8]), + master.write.eq(1), + If(master.idle, + If(master.ack, + NextState("DATA1") + ).Else( + self.nack.eq(1), + NextState("STOP") + ) + ) + ) + fsm.act("DATA1", + master.data.eq(adpll[8:16]), + master.write.eq(1), + If(master.idle, + If(master.ack, + NextState("DATA2") + ).Else( + self.nack.eq(1), + NextState("STOP") + ) + ) + ) + fsm.act("DATA2", + master.data.eq(adpll[16:24]), + master.write.eq(1), + If(master.idle, + If(~master.ack, self.nack.eq(1)), + NextState("STOP") + ) + ) + fsm.act("STOP", + master.stop.eq(1), + If(master.idle, + If(~master.ack, self.nack.eq(1)), + NextState("IDLE") + ) + ) + + self.comb += self.busy.eq(~fsm.ongoing("IDLE")) + class Si549(Module, AutoCSR): def __init__(self, pads): From 3242e9ec6c254c463c2a418ae409bea46eea6774 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 13 Jan 2020 22:31:57 +0800 Subject: [PATCH 2098/2457] wrpll: loop test --- artiq/firmware/libboard_artiq/wrpll.rs | 39 +++++++++++++++++++++++++- artiq/gateware/drtio/wrpll/core.py | 20 ++++++++----- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index c1343df20..5df8eef1e 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -175,7 +175,7 @@ mod si549 { use board_misoc::clock; use super::i2c; - const ADDRESS: u8 = 0x55; + pub const ADDRESS: u8 = 0x55; pub fn write(dcxo: i2c::Dcxo, reg: u8, val: u8) -> Result<(), &'static str> { i2c::start(dcxo); @@ -270,6 +270,13 @@ mod si549 { clock::spin_us(100); Ok(()) } + + pub fn get_adpll(dcxo: i2c::Dcxo) -> Result { + let b1 = read(dcxo, 231)? as i32; + let b2 = read(dcxo, 232)? as i32; + let b3 = read(dcxo, 233)? as i8 as i32; + Ok(b3 << 16 | b2 << 8 | b1) + } } fn get_frequencies() -> (u32, u32, u32) { @@ -315,6 +322,11 @@ pub fn init() { unsafe { csr::wrpll::helper_reset_write(1); } + unsafe { + csr::wrpll::helper_dcxo_i2c_address_write(si549::ADDRESS); + csr::wrpll::main_dcxo_i2c_address_write(si549::ADDRESS); + } + #[cfg(rtio_frequency = "125.0")] let (h_hsdiv, h_lsdiv, h_fbdiv) = (0x05c, 0, 0x04b5badb98a); #[cfg(rtio_frequency = "125.0")] @@ -403,16 +415,41 @@ fn select_recovered_clock_int(rc: bool) -> Result<(), &'static str> { let (helper_adpll, main_adpll) = trim_dcxos(f_helper, f_main, f_cdr)?; si549::set_adpll(i2c::Dcxo::Helper, helper_adpll).expect("ADPLL write failed"); si549::set_adpll(i2c::Dcxo::Main, main_adpll).expect("ADPLL write failed"); + unsafe { csr::wrpll::adpll_offset_helper_write(helper_adpll as u32); csr::wrpll::adpll_offset_main_write(main_adpll as u32); + csr::wrpll::helper_dcxo_gpio_enable_write(0); + csr::wrpll::main_dcxo_gpio_enable_write(0); + csr::wrpll::helper_dcxo_errors_write(0xff); + csr::wrpll::main_dcxo_errors_write(0xff); + csr::wrpll::filter_reset_write(0); } + clock::spin_us(100_000); + let mut tags = [0; 10]; for i in 0..tags.len() { tags[i] = get_ddmtd_helper_tag(); } info!("DDMTD helper tags: {:?}", tags); + + unsafe { + csr::wrpll::filter_reset_write(1); + } + clock::spin_us(50_000); + unsafe { + csr::wrpll::helper_dcxo_gpio_enable_write(1); + csr::wrpll::main_dcxo_gpio_enable_write(1); + } + unsafe { + info!("error {} {}", + csr::wrpll::helper_dcxo_errors_read(), + csr::wrpll::main_dcxo_errors_read()); + } + info!("new ADPLL: {} {}", + si549::get_adpll(i2c::Dcxo::Helper)?, + si549::get_adpll(i2c::Dcxo::Main)?); } else { si549::set_adpll(i2c::Dcxo::Helper, 0).expect("ADPLL write failed"); si549::set_adpll(i2c::Dcxo::Main, 0).expect("ADPLL write failed"); diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index ad2dd4e3c..a8d374ca8 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -51,15 +51,21 @@ class FrequencyCounter(Module, AutoCSR): class WRPLL(Module, AutoCSR): def __init__(self, helper_clk_pads, main_dcxo_i2c, helper_dxco_i2c, ddmtd_inputs, N=15): self.helper_reset = CSRStorage(reset=1) + self.filter_reset = CSRStorage(reset=1) self.adpll_offset_helper = CSRStorage(24) self.adpll_offset_main = CSRStorage(24) self.clock_domains.cd_helper = ClockDomain() + self.clock_domains.cd_filter = ClockDomain() self.helper_reset.storage.attr.add("no_retiming") + self.filter_reset.storage.attr.add("no_retiming") + self.specials += Instance("IBUFGDS", + i_I=helper_clk_pads.p, i_IB=helper_clk_pads.n, + o_O=self.cd_helper.clk) + self.comb += self.cd_filter.clk.eq(self.cd_helper.clk) self.specials += [ - Instance("IBUFGDS", i_I=helper_clk_pads.p, i_IB=helper_clk_pads.n, - o_O=self.cd_helper.clk), - AsyncResetSynchronizer(self.cd_helper, self.helper_reset.storage) + AsyncResetSynchronizer(self.cd_helper, self.helper_reset.storage), + AsyncResetSynchronizer(self.cd_filter, self.filter_reset.storage) ] self.submodules.helper_dcxo = Si549(helper_dxco_i2c) @@ -73,10 +79,10 @@ class WRPLL(Module, AutoCSR): self.submodules.ddmtd_helper = DDMTD(ddmtd_counter, ddmtd_inputs.rec_clk) self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_inputs.main_xo) - helper_cd = ClockDomainsRenamer("helper") - self.submodules.collector = helper_cd(Collector(N)) - self.submodules.filter_helper = helper_cd(thls.make(filters.helper, data_width=48)) - self.submodules.filter_main = helper_cd(thls.make(filters.main, data_width=48)) + filter_cd = ClockDomainsRenamer("filter") + self.submodules.collector = filter_cd(Collector(N)) + self.submodules.filter_helper = filter_cd(thls.make(filters.helper, data_width=48)) + self.submodules.filter_main = filter_cd(thls.make(filters.main, data_width=48)) self.comb += [ self.collector.tag_helper.eq(self.ddmtd_helper.h_tag), From 105dd60c788779aa68e4b438c5da019db1dcd115 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 14 Jan 2020 16:52:25 +0800 Subject: [PATCH 2099/2457] wrpll: ADPLLProgrammer mini test bench and fixes --- artiq/gateware/drtio/wrpll/si549.py | 46 ++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/si549.py b/artiq/gateware/drtio/wrpll/si549.py index 476786c64..376225d2b 100644 --- a/artiq/gateware/drtio/wrpll/si549.py +++ b/artiq/gateware/drtio/wrpll/si549.py @@ -35,7 +35,7 @@ class I2CMasterMachine(Module): self.write = Signal() self.ack = Signal() self.data = Signal(8) - self.idle = Signal() + self.ready = Signal() ### @@ -46,6 +46,7 @@ class I2CMasterMachine(Module): self.submodules += fsm fsm.act("IDLE", + self.ready.eq(1), If(self.start, NextState("START0"), ).Elif(self.stop & self.start, @@ -110,10 +111,11 @@ class I2CMasterMachine(Module): ) run = Signal() + idle = Signal() self.comb += [ run.eq(self.start | self.stop | self.write), - self.idle.eq(~run & fsm.ongoing("IDLE")), - self.cg.ce.eq(~self.idle), + idle.eq(~run & fsm.ongoing("IDLE")), + self.cg.ce.eq(~idle), fsm.ce.eq(run | self.cg.clk2x), ] @@ -160,17 +162,17 @@ class ADPLLProgrammer(Module): ) fsm.act("START", master.start.eq(1), - If(master.idle, NextState("DEVADDRESS")) + If(master.ready, NextState("DEVADDRESS")) ) fsm.act("DEVADDRESS", master.data.eq(self.i2c_address << 1), master.write.eq(1), - If(master.idle, NextState("REGADRESS")) + If(master.ready, NextState("REGADRESS")) ) fsm.act("REGADRESS", master.data.eq(231), master.write.eq(1), - If(master.idle, + If(master.ready, If(master.ack, NextState("DATA0") ).Else( @@ -182,7 +184,7 @@ class ADPLLProgrammer(Module): fsm.act("DATA0", master.data.eq(adpll[0:8]), master.write.eq(1), - If(master.idle, + If(master.ready, If(master.ack, NextState("DATA1") ).Else( @@ -194,7 +196,7 @@ class ADPLLProgrammer(Module): fsm.act("DATA1", master.data.eq(adpll[8:16]), master.write.eq(1), - If(master.idle, + If(master.ready, If(master.ack, NextState("DATA2") ).Else( @@ -206,14 +208,14 @@ class ADPLLProgrammer(Module): fsm.act("DATA2", master.data.eq(adpll[16:24]), master.write.eq(1), - If(master.idle, + If(master.ready, If(~master.ack, self.nack.eq(1)), NextState("STOP") ) ) fsm.act("STOP", master.stop.eq(1), - If(master.idle, + If(master.ready, If(~master.ack, self.nack.eq(1)), NextState("IDLE") ) @@ -222,6 +224,26 @@ class ADPLLProgrammer(Module): self.comb += self.busy.eq(~fsm.ongoing("IDLE")) +def simulate_programmer(): + from migen.sim.core import run_simulation + + dut = ADPLLProgrammer() + + def generator(): + yield dut.i2c_divider.eq(4) + yield dut.i2c_address.eq(0x55) + yield + yield dut.adpll.eq(0x123456) + yield dut.stb.eq(1) + yield + yield dut.stb.eq(0) + yield + while (yield dut.busy): + yield + + run_simulation(dut, generator(), vcd_name="tb.vcd") + + class Si549(Module, AutoCSR): def __init__(self, pads): self.gpio_enable = CSRStorage(reset=1) @@ -308,3 +330,7 @@ class Si549(Module, AutoCSR): If(self.errors.re & self.errors.r[n], self.errors.w[n].eq(0)), If(trig, self.errors.w[n].eq(1)) ] + + +if __name__ == "__main__": + simulate_programmer() From 50302d57c0bf713a36dcdeff566f7dd8c5cf3b9d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 14 Jan 2020 20:03:46 +0800 Subject: [PATCH 2100/2457] wrpll: more careful I2C timing --- artiq/gateware/drtio/wrpll/si549.py | 38 ++++++++++++++++------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/si549.py b/artiq/gateware/drtio/wrpll/si549.py index 376225d2b..f4427a9bc 100644 --- a/artiq/gateware/drtio/wrpll/si549.py +++ b/artiq/gateware/drtio/wrpll/si549.py @@ -49,8 +49,6 @@ class I2CMasterMachine(Module): self.ready.eq(1), If(self.start, NextState("START0"), - ).Elif(self.stop & self.start, - NextState("RESTART0"), ).Elif(self.stop, NextState("STOP0"), ).Elif(self.write, @@ -62,40 +60,44 @@ class I2CMasterMachine(Module): fsm.act("START0", NextValue(self.scl, 1), - NextState("START1")) + NextState("START1") + ) fsm.act("START1", NextValue(self.sda_o, 0), - NextState("IDLE")) - - fsm.act("RESTART0", - NextValue(self.scl, 0), - NextState("RESTART1")) - fsm.act("RESTART1", - NextValue(self.sda_o, 1), - NextState("START0")) + NextState("IDLE") + ) fsm.act("STOP0", NextValue(self.scl, 0), - NextState("STOP1")) + NextState("STOP1") + ) fsm.act("STOP1", - NextValue(self.scl, 1), NextValue(self.sda_o, 0), - NextState("STOP2")) + NextState("STOP2") + ) fsm.act("STOP2", + NextValue(self.scl, 1), + NextState("STOP3") + ) + fsm.act("STOP3", NextValue(self.sda_o, 1), - NextState("IDLE")) + NextState("IDLE") + ) fsm.act("WRITE0", NextValue(self.scl, 0), + NextState("WRITE1") + ) + fsm.act("WRITE1", If(bits == 0, NextValue(self.sda_o, 1), NextState("READACK0"), ).Else( NextValue(self.sda_o, data[7]), - NextState("WRITE1"), + NextState("WRITE2"), ) ) - fsm.act("WRITE1", + fsm.act("WRITE2", NextValue(self.scl, 1), NextValue(data[1:], data[:-1]), NextValue(bits, bits - 1), @@ -240,6 +242,8 @@ def simulate_programmer(): yield while (yield dut.busy): yield + for _ in range(20): + yield run_simulation(dut, generator(), vcd_name="tb.vcd") From 6c948c7726ca550249c0a77f2975337cfab80621 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 16 Jan 2020 08:59:52 +0800 Subject: [PATCH 2101/2457] sayma: RF switch control is active-low on Basemod, invert --- artiq/gateware/rtio/phy/ttl_serdes_7series.py | 11 ++++++----- artiq/gateware/targets/sayma_rtm.py | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_7series.py b/artiq/gateware/rtio/phy/ttl_serdes_7series.py index 730aea35b..8189258d6 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_7series.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_7series.py @@ -4,7 +4,7 @@ from artiq.gateware.rtio.phy import ttl_serdes_generic class _OSERDESE2_8X(Module): - def __init__(self, pad, pad_n=None): + def __init__(self, pad, pad_n=None, invert=False): self.o = Signal(8) self.t_in = Signal() self.t_out = Signal() @@ -16,12 +16,13 @@ class _OSERDESE2_8X(Module): self.specials += Instance("OSERDESE2", p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, + p_INIT_OQ=0b11111111 if invert else 0b00000000, o_OQ=pad_o, o_TQ=self.t_out, i_RST=ResetSignal("rio_phy"), i_CLK=ClockSignal("rtiox4"), i_CLKDIV=ClockSignal("rio_phy"), - i_D1=o[0], i_D2=o[1], i_D3=o[2], i_D4=o[3], - i_D5=o[4], i_D6=o[5], i_D7=o[6], i_D8=o[7], + i_D1=o[0] ^ invert, i_D2=o[1] ^ invert, i_D3=o[2] ^ invert, i_D4=o[3] ^ invert, + i_D5=o[4] ^ invert, i_D6=o[5] ^ invert, i_D7=o[6] ^ invert, i_D8=o[7] ^ invert, i_TCE=1, i_OCE=1, i_T1=self.t_in) if pad_n is None: @@ -106,8 +107,8 @@ class _IOSERDESE2_8X(Module): class Output_8X(ttl_serdes_generic.Output): - def __init__(self, pad, pad_n=None): - serdes = _OSERDESE2_8X(pad, pad_n) + def __init__(self, pad, pad_n=None, invert=False): + serdes = _OSERDESE2_8X(pad, pad_n, invert=invert) self.submodules += serdes ttl_serdes_generic.Output.__init__(self, serdes) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index fee4ab27b..9864563d1 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -200,7 +200,8 @@ class Satellite(_SatelliteBase): print("BaseMod{} RF switches starting at RTIO channel 0x{:06x}" .format(bm, len(rtio_channels))) for i in range(4): - phy = ttl_serdes_7series.Output_8X(platform.request("basemod{}_rfsw".format(bm), i)) + phy = ttl_serdes_7series.Output_8X(platform.request("basemod{}_rfsw".format(bm), i), + invert=True) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From 833f428391796b861bbb8e8784baa4c405a98fb1 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 16 Jan 2020 09:10:32 +0800 Subject: [PATCH 2102/2457] sayma: fix hmc542 to/from mu --- artiq/coredevice/basemod_att.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/basemod_att.py b/artiq/coredevice/basemod_att.py index a46625c28..4f372c33b 100644 --- a/artiq/coredevice/basemod_att.py +++ b/artiq/coredevice/basemod_att.py @@ -3,6 +3,15 @@ from artiq.language.units import us, ms from artiq.coredevice.shiftreg import ShiftReg +@portable +def to_mu(att): + return round(att*2.0) ^ 0x3f + +@portable +def from_mu(att_mu): + return 0.5*(att_mu ^ 0x3f) + + class BaseModAtt: def __init__(self, dmgr, rst_n, clk, le, mosi, miso): self.rst_n = dmgr.get(rst_n) @@ -58,7 +67,7 @@ class BaseModAtt: Sets the four attenuators on BaseMod. The values are in decibels. """ - self.set_mu(round(att0*2.0), round(att1*2.0), round(att2*2.0), round(att3*2.0)) + self.set_mu(to_mu(att0), to_mu(att1), to_mu(att2), to_mu(att3)) @kernel def get(self): @@ -67,4 +76,4 @@ class BaseModAtt: The values are in decibels. """ att0, att1, att2, att3 = self.get_mu() - return 0.5*att0, 0.5*att1, 0.5*att2, 0.5*att3 + return from_mu(att0), from_mu(att1), from_mu(att2), from_mu(att3) From 344f8bd12ac59ed89fe292846076434ff593c390 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 18 Jan 2020 09:42:58 +0800 Subject: [PATCH 2103/2457] wrpll: collector patch from Weida --- artiq/gateware/drtio/wrpll/ddmtd.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index 978706961..06bc33902 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -113,19 +113,19 @@ class Collector(Module): self.tag_main = Signal(N) self.tag_main_update = Signal() - self.output = Signal(N) + self.output = Signal((N, True)) self.output_update = Signal(N) # # # - fsm = FSM() + fsm = FSM(reset_state="IDLE") self.submodules += fsm tag_collector = Signal(N) fsm.act("IDLE", If(self.tag_main_update & self.tag_helper_update, NextValue(tag_collector, 0), - NextState("IDLE") + NextState("UPDATE") ).Elif(self.tag_main_update, NextValue(tag_collector, self.tag_main), NextState("WAITHELPER") @@ -137,19 +137,22 @@ class Collector(Module): fsm.act("WAITHELPER", If(self.tag_helper_update, NextValue(tag_collector, tag_collector - self.tag_helper), - NextState("IDLE") + NextState("UPDATE") ) ) fsm.act("WAITMAIN", If(self.tag_main_update, NextValue(tag_collector, tag_collector + self.tag_main), - NextState("IDLE") + NextState("UPDATE") ) ) + fsm.act("UPDATE", + NextValue(self.output, tag_collector), + NextState("IDLE") + ) self.sync += [ self.output_update.eq(0), If(self.tag_helper_update, - self.output_update.eq(1), - self.output.eq(tag_collector) + self.output_update.eq(1) ) ] From 6c3e71a83a23a34439628d2254ca5908938529c7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 18 Jan 2020 09:43:43 +0800 Subject: [PATCH 2104/2457] wrpll: cleanup --- artiq/gateware/drtio/wrpll/ddmtd.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index 06bc33902..a578a3824 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -150,9 +150,4 @@ class Collector(Module): NextValue(self.output, tag_collector), NextState("IDLE") ) - self.sync += [ - self.output_update.eq(0), - If(self.tag_helper_update, - self.output_update.eq(1) - ) - ] + self.sync += self.output_update.eq(self.tag_helper_update) From 45efee724ef3bf20e386d45d8004b9c5faebf48d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 20 Jan 2020 12:47:31 +0800 Subject: [PATCH 2105/2457] sayma: add JESD204 PHY done diagnostics --- artiq/firmware/satman/jdcg.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs index 38e5bf866..929c6a121 100644 --- a/artiq/firmware/satman/jdcg.rs +++ b/artiq/firmware/satman/jdcg.rs @@ -11,7 +11,12 @@ pub mod jesd { unsafe { (csr::JDCG[dacno as usize].jesd_control_enable_write)(if en {1} else {0}) } - clock::spin_us(5000); + } + + pub fn phy_done(dacno: u8) -> bool { + unsafe { + (csr::JDCG[dacno as usize].jesd_control_phy_done_read)() != 0 + } } pub fn ready(dacno: u8) -> bool { @@ -84,7 +89,11 @@ pub mod jdac { info!("DAC-{} initializing...", dacno); jesd::enable(dacno, true); - clock::spin_us(10); + clock::spin_us(10_000); + if !jesd::phy_done(dacno) { + error!("JESD core PHY not done"); + return Err("JESD core PHY not done"); + } if !jesd::ready(dacno) { error!("JESD core reported not ready"); return Err("JESD core reported not ready"); From 5c299de3b4460dc9ed8a065fb1f48384361f3a75 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 20 Jan 2020 18:21:29 +0800 Subject: [PATCH 2106/2457] sayma: print DAC status on JESD not ready error --- artiq/firmware/satman/jdcg.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs index 929c6a121..340b59ce0 100644 --- a/artiq/firmware/satman/jdcg.rs +++ b/artiq/firmware/satman/jdcg.rs @@ -95,7 +95,8 @@ pub mod jdac { return Err("JESD core PHY not done"); } if !jesd::ready(dacno) { - error!("JESD core reported not ready"); + error!("JESD core reported not ready, sending status print request"); + basic_request(dacno, jdac_requests::PRINT_STATUS, 0)?; return Err("JESD core reported not ready"); } From ec03767dcf2f82c366a6f3dd6bb8f37b636d193c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 20 Jan 2020 18:22:06 +0800 Subject: [PATCH 2107/2457] sayma: improve DAC status report --- artiq/firmware/libboard_artiq/ad9154.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/firmware/libboard_artiq/ad9154.rs b/artiq/firmware/libboard_artiq/ad9154.rs index 015fccb66..de32ff2e2 100644 --- a/artiq/firmware/libboard_artiq/ad9154.rs +++ b/artiq/firmware/libboard_artiq/ad9154.rs @@ -355,6 +355,8 @@ pub fn setup(dacno: u8, linerate: u64) -> Result<(), &'static str> { pub fn status(dacno: u8) { spi_setup(dacno); + info!("Printing status of AD9154-{}", dacno); + info!("PRODID: 0x{:04x}", (read(ad9154_reg::PRODIDH) as u16) << 8 | (read(ad9154_reg::PRODIDL) as u16)); info!("SERDES_PLL_LOCK: {}", (read(ad9154_reg::PLL_STATUS) & ad9154_reg::SERDES_PLL_LOCK_RB)); info!(""); From 01a6e77d89dfe430d7f241eb58f8537b5f57777d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sun, 16 Jun 2019 17:17:42 +0000 Subject: [PATCH 2108/2457] mirny: add MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * This targets unrelease CPLD gateware (https://github.com/quartiq/mirny/issues/1) * includes initial coredevice driver, eem shims, and kasli_generic tooling * addresses the ARTIQ side of #1130 * Register abstraction to be written Signed-off-by: Robert Jördens --- artiq/coredevice/adf5355.py | 68 +++++++++++++++++++++++++ artiq/coredevice/mirny.py | 66 ++++++++++++++++++++++++ artiq/gateware/eem.py | 45 ++++++++++++++++ artiq/gateware/targets/kasli_generic.py | 8 +++ 4 files changed, 187 insertions(+) create mode 100644 artiq/coredevice/adf5355.py create mode 100644 artiq/coredevice/mirny.py diff --git a/artiq/coredevice/adf5355.py b/artiq/coredevice/adf5355.py new file mode 100644 index 000000000..26c71db69 --- /dev/null +++ b/artiq/coredevice/adf5355.py @@ -0,0 +1,68 @@ +""""RTIO driver for the Analog Devices ADF[45]35[56] family of GHz PLLs +on Mirny-style prefixed SPI buses +""" + +# https://github.com/analogdevicesinc/linux/blob/master/Documentation/devicetree/bindings/iio/frequency/adf5355.txt +# https://github.com/analogdevicesinc/linux/blob/master/drivers/iio/frequency/adf5355.c +# https://www.analog.com/media/en/technical-documentation/data-sheets/ADF5356.pdf +# https://www.analog.com/media/en/technical-documentation/data-sheets/ADF5355.pdf +# https://www.analog.com/media/en/technical-documentation/user-guides/EV-ADF5356SD1Z-UG-1087.pdf + + +from numpy import int32 + +from artiq.language.core import (kernel, portable, delay_mu, delay, now_mu, + at_mu) +from artiq.language.units import ns, us +from artiq.coredevice import spi2 as spi, mirny + +SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | + 0*spi.SPI_INPUT | 1*spi.SPI_CS_POLARITY | + 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | + 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) + + +class ADF5355: + """Analog Devices AD[45]35[56] family of GHz PLLs. + + :param cpld_device: Mirny CPLD device name + :param sw_device: Mirny RF switch device name + :param channel: Mirny RF channel index + :param core_device: Core device name (default: "core") + """ + kernel_invariants = {"cpld", "sw", "channel", "core"} + + def __init__(self, dmgr, cpld_device, sw_device, channel, + core="core"): + self.cpld = dmgr.get(cpld_device) + self.sw = dmgr.get(sw_device) + self.channel = channel + self.core = dmgr.get(core) + + @kernel + def set_att_mu(self, att): + """Set digital step attenuator in machine units. + + :param att: Attenuation setting, 8 bit digital. + """ + self.cpld.set_att_mu(self.channel, att) + + @kernel + def write(self, data): + self.cpld.write_ext(self.channel | 4, 32, data) + + @kernel + def read_muxout(self): + return bool(self.cpld.read_reg(0) & (1 << (self.channel + 8))) + + @kernel + def init(self): + self.write((1 << 27) | 4) + if not self.read_muxout(): + raise ValueError("MUXOUT not high") + delay(100*us) + self.write((2 << 27) | 4) + if self.read_muxout(): + raise ValueError("MUXOUT not low") + delay(100*us) + self.write((6 << 27) | 4) diff --git a/artiq/coredevice/mirny.py b/artiq/coredevice/mirny.py new file mode 100644 index 000000000..f0605eed2 --- /dev/null +++ b/artiq/coredevice/mirny.py @@ -0,0 +1,66 @@ +from artiq.language.core import kernel, delay +from artiq.language.units import us + +from numpy import int32 + +from artiq.coredevice import spi2 as spi + + +SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | + 0*spi.SPI_INPUT | 1*spi.SPI_CS_POLARITY | + 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | + 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) + +# SPI clock write and read dividers +SPIT_WR = 4 +SPIT_RD = 16 + +SPI_CS = 1 + +class Mirny: + WE = 1 << 24 + kernel_invariants = {"bus", "core", "WE"} + + def __init__(self, dmgr, spi_device, core_device="core"): + self.core = dmgr.get(core_device) + self.bus = dmgr.get(spi_device) + + @kernel + def read_reg(self, addr): + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, 24, + SPIT_RD, SPI_CS) + self.bus.write((addr << 25)) + return self.bus.read() & int32(0xffff) + + @kernel + def write_reg(self, addr, data): + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 24, SPIT_WR, SPI_CS) + self.bus.write((addr << 25) | self.WE | ((data & 0xffff) << 8)) + + @kernel + def init(self): + reg0 = self.read_reg(0) + if reg0 & 0b11 != 0b11: + raise ValueError("Mirny HW_REV mismatch") + if (reg0 >> 2) & 0b11 != 0b00: + raise ValueError("Mirny PROTO_REV mismatch") + delay(100*us) # slack + + @kernel + def set_att_mu(self, channel, att): + """Set digital step attenuator in machine units. + + :param att: Attenuation setting, 8 bit digital. + """ + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 16, SPIT_WR, SPI_CS) + self.bus.write(((channel | 8) << 25) | (att << 16)) + + @kernel + def write_ext(self, addr, length, data): + self.bus.set_config_mu(SPI_CONFIG, 8, SPIT_WR, SPI_CS) + self.bus.write(addr << 25) + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, length, + SPIT_WR, SPI_CS) + if length < 32: + data <<= 32 - length + self.bus.write(data) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index b5e50c0ba..84f4526ce 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -558,3 +558,48 @@ class SUServo(_EEM): pads = target.platform.request("{}_{}".format(eem_urukuli, signal)) target.specials += DifferentialOutput( su.iir.ctrl[j*4 + i].en_out, pads.p, pads.n) + + +class Mirny(_EEM): + @staticmethod + def io(eem, iostandard="LVDS_25"): + ios = [ + ("mirny{}_spi_p".format(eem), 0, + Subsignal("clk", Pins(_eem_pin(eem, 0, "p"))), + Subsignal("mosi", Pins(_eem_pin(eem, 1, "p"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "p"))), + Subsignal("cs_n", Pins(_eem_pin(eem, 3, "p"))), + IOStandard(iostandard), + ), + ("mirny{}_spi_n".format(eem), 0, + Subsignal("clk", Pins(_eem_pin(eem, 0, "n"))), + Subsignal("mosi", Pins(_eem_pin(eem, 1, "n"))), + Subsignal("miso", Pins(_eem_pin(eem, 2, "n"))), + Subsignal("cs_n", Pins(_eem_pin(eem, 3, "n"))), + IOStandard(iostandard), + ), + ] + for i in range(4): + ios.append( + ("mirny{}_io{}".format(eem, i), 0, + Subsignal("p", Pins(_eem_pin(eem, 4 + i, "p"))), + Subsignal("n", Pins(_eem_pin(eem, 4 + i, "n"))), + IOStandard(iostandard) + )) + return ios + + @classmethod + def add_std(cls, target, eem, ttl_out_cls, iostandard="LVDS_25"): + cls.add_extension(target, eem, iostandard=iostandard) + + phy = spi2.SPIMaster( + target.platform.request("mirny{}_spi_p".format(eem)), + target.platform.request("mirny{}_spi_n".format(eem))) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + for i in range(4): + pads = target.platform.request("mirny{}_io{}".format(eem, i)) + phy = ttl_out_cls(pads.p, pads.n) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy)) diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index f500d2946..2f593459a 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -99,6 +99,13 @@ def peripheral_grabber(module, peripheral): eem.Grabber.add_std(module, port, port_aux, port_aux2) +def peripheral_mirny(module, peripheral): + if len(peripheral["ports"]) != 1: + raise ValueError("wrong number of ports") + eem.Mirny.add_std(module, peripheral["ports"][0], + ttl_serdes_7series.Output_8X) + + peripheral_processors = { "dio": peripheral_dio, "urukul": peripheral_urukul, @@ -107,6 +114,7 @@ peripheral_processors = { "suservo": peripheral_suservo, "zotino": peripheral_zotino, "grabber": peripheral_grabber, + "mirny": peripheral_mirny, } From da531404e84f52b7fb0dd214cbe4cffbb259b69d Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Fri, 20 Dec 2019 12:26:03 +0100 Subject: [PATCH 2109/2457] artiq_ddb_template: add Mirny support Signed-off-by: Etienne Wodey --- artiq/frontend/artiq_ddb_template.py | 51 ++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index b561e69d9..114cd2d79 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -228,6 +228,57 @@ class PeripheralManager: raise ValueError return next(channel) + def process_mirny(self, rtio_offset, peripheral): + mirny_name = self.get_name("mirny") + channel = count(0) + self.gen(""" + device_db["spi_{name}"]={{ + "type": "local", + "module": "artiq.coredevice.spi2", + "class": "SPIMaster", + "arguments": {{"channel": 0x{channel:06x}}} + }}""", + name=mirny_name, + channel=rtio_offset+next(channel)) + + for i in range(4): + self.gen(""" + device_db["ttl_{name}_sw{mchn}"] = {{ + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {{"channel": 0x{ttl_channel:06x}}} + }}""", + name=mirny_name, + mchn=i, + ttl_channel=rtio_offset+next(channel)) + + for i in range(4): + self.gen(""" + device_db["{name}_ch{mchn}"] = {{ + "type": "local", + "module": "artiq.coredevice.adf5355", + "class": "ADF5355", + "arguments": {{ + "channel": {mchn}, + "sw_device": "ttl_{name}_sw{mchn}", + "cpld_device": "{name}_cpld", + }} + }}""", + name=mirny_name, + mchn=i) + + self.gen(""" + device_db["{name}_cpld"] = {{ + "type": "local", + "module": "artiq.coredevice.mirny", + "class": "Mirny", + "arguments": {{"spi_device": "spi_{name}"}}, + }}""", + name=mirny_name) + + return next(channel) + def process_novogorny(self, rtio_offset, peripheral): self.gen(""" device_db["spi_{name}_adc"] = {{ From 9368c26d1c37d10215e6972aa6652aa562067d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 20 Jan 2020 13:07:20 +0100 Subject: [PATCH 2110/2457] mirny: add to manual --- artiq/coredevice/adf5355.py | 4 ++-- artiq/coredevice/mirny.py | 21 ++++++++++++++++++--- doc/manual/core_drivers_reference.rst | 12 ++++++++++++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/adf5355.py b/artiq/coredevice/adf5355.py index 26c71db69..59c3531ff 100644 --- a/artiq/coredevice/adf5355.py +++ b/artiq/coredevice/adf5355.py @@ -1,5 +1,5 @@ -""""RTIO driver for the Analog Devices ADF[45]35[56] family of GHz PLLs -on Mirny-style prefixed SPI buses +"""RTIO driver for the Analog Devices ADF[45]35[56] family of GHz PLLs +on Mirny-style prefixed SPI buses. """ # https://github.com/analogdevicesinc/linux/blob/master/Documentation/devicetree/bindings/iio/frequency/adf5355.txt diff --git a/artiq/coredevice/mirny.py b/artiq/coredevice/mirny.py index f0605eed2..813e72bcb 100644 --- a/artiq/coredevice/mirny.py +++ b/artiq/coredevice/mirny.py @@ -1,3 +1,6 @@ +"""RTIO driver for Mirny (4 channel GHz PLLs) +""" + from artiq.language.core import kernel, delay from artiq.language.units import us @@ -17,9 +20,16 @@ SPIT_RD = 16 SPI_CS = 1 +WE = 1 << 24 + + class Mirny: - WE = 1 << 24 - kernel_invariants = {"bus", "core", "WE"} + """Mirny PLL-based RF generator. + + :param spi_device: SPI bus device + :param core_device: Core device name (default: "core") + """ + kernel_invariants = {"bus", "core"} def __init__(self, dmgr, spi_device, core_device="core"): self.core = dmgr.get(core_device) @@ -27,6 +37,7 @@ class Mirny: @kernel def read_reg(self, addr): + """Read a register""" self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, 24, SPIT_RD, SPI_CS) self.bus.write((addr << 25)) @@ -34,11 +45,14 @@ class Mirny: @kernel def write_reg(self, addr, data): + """Write a register""" self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 24, SPIT_WR, SPI_CS) - self.bus.write((addr << 25) | self.WE | ((data & 0xffff) << 8)) + self.bus.write((addr << 25) | WE | ((data & 0xffff) << 8)) @kernel def init(self): + """Initialize Mirny by reading the status register and verifying + compatible hardware and protocol revisions""" reg0 = self.read_reg(0) if reg0 & 0b11 != 0b11: raise ValueError("Mirny HW_REV mismatch") @@ -57,6 +71,7 @@ class Mirny: @kernel def write_ext(self, addr, length, data): + """Perform SPI write to a prefixed address""" self.bus.set_config_mu(SPI_CONFIG, 8, SPIT_WR, SPI_CS) self.bus.write(addr << 25) self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, length, diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index bcdcd1a00..17e4909c9 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -99,6 +99,18 @@ RF generation drivers .. automodule:: artiq.coredevice.ad9914 :members: +:mod:`artiq.coredevice.mirny` module ++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.mirny + :members: + +:mod:`artiq.coredevice.adf5355` module ++++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.adf5355 + :members: + :mod:`artiq.coredevice.spline` module +++++++++++++++++++++++++++++++++++++ From 7ab0282234504e2576bbb67e3d6ff99680f2febc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 20 Jan 2020 13:09:13 +0100 Subject: [PATCH 2111/2457] adf5355: style --- artiq/coredevice/adf5355.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/artiq/coredevice/adf5355.py b/artiq/coredevice/adf5355.py index 59c3531ff..a23df6701 100644 --- a/artiq/coredevice/adf5355.py +++ b/artiq/coredevice/adf5355.py @@ -9,12 +9,9 @@ on Mirny-style prefixed SPI buses. # https://www.analog.com/media/en/technical-documentation/user-guides/EV-ADF5356SD1Z-UG-1087.pdf -from numpy import int32 - -from artiq.language.core import (kernel, portable, delay_mu, delay, now_mu, - at_mu) -from artiq.language.units import ns, us -from artiq.coredevice import spi2 as spi, mirny +from artiq.language.core import kernel, delay +from artiq.language.units import us +from artiq.coredevice import spi2 as spi SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | 0*spi.SPI_INPUT | 1*spi.SPI_CS_POLARITY | From 6b428ef3be5f9e75a442744d3e5b6db22d9c29e4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 20 Jan 2020 20:12:13 +0800 Subject: [PATCH 2112/2457] sayma: initialize DAC before testing jesd::ready --- artiq/firmware/satman/jdcg.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs index 340b59ce0..1237e493a 100644 --- a/artiq/firmware/satman/jdcg.rs +++ b/artiq/firmware/satman/jdcg.rs @@ -94,14 +94,16 @@ pub mod jdac { error!("JESD core PHY not done"); return Err("JESD core PHY not done"); } + + basic_request(dacno, jdac_requests::INIT, 0)?; + + // JESD ready depends on JSYNC being valid, so DAC init needs to happen first if !jesd::ready(dacno) { - error!("JESD core reported not ready, sending status print request"); + error!("JESD core reported not ready, sending DAC status print request"); basic_request(dacno, jdac_requests::PRINT_STATUS, 0)?; return Err("JESD core reported not ready"); } - basic_request(dacno, jdac_requests::INIT, 0)?; - jesd::prbs(dacno, true); basic_request(dacno, jdac_requests::PRBS, 0)?; jesd::prbs(dacno, false); From 62a52cb086ac485db422736c59522fd54d9e936a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 20 Jan 2020 20:13:32 +0800 Subject: [PATCH 2113/2457] sayma: do not pollute the log with DAC status on success --- artiq/firmware/satman/jdcg.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs index 1237e493a..ed214f4f4 100644 --- a/artiq/firmware/satman/jdcg.rs +++ b/artiq/firmware/satman/jdcg.rs @@ -115,8 +115,6 @@ pub mod jdac { basic_request(dacno, jdac_requests::INIT, 0)?; clock::spin_us(5000); - basic_request(dacno, jdac_requests::PRINT_STATUS, 0)?; - if !jesd::jsync(dacno) { error!("JESD core reported bad SYNC"); return Err("JESD core reported bad SYNC"); From e427aaaa66a59842aa835fb8316d9205d0455f87 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 20 Jan 2020 20:07:35 +0800 Subject: [PATCH 2114/2457] basemod_att: fix imports --- artiq/coredevice/basemod_att.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/basemod_att.py b/artiq/coredevice/basemod_att.py index 4f372c33b..5015324ff 100644 --- a/artiq/coredevice/basemod_att.py +++ b/artiq/coredevice/basemod_att.py @@ -1,4 +1,4 @@ -from artiq.language.core import kernel, delay +from artiq.language.core import kernel, portable, delay from artiq.language.units import us, ms from artiq.coredevice.shiftreg import ShiftReg From 8f9948a1fffca79640e88aec3da58036311da7e7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 20 Jan 2020 20:10:24 +0800 Subject: [PATCH 2115/2457] kasli_sawgmaster: add basemod programming example --- .../kasli_sawgmaster/repository/basemod.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 artiq/examples/kasli_sawgmaster/repository/basemod.py diff --git a/artiq/examples/kasli_sawgmaster/repository/basemod.py b/artiq/examples/kasli_sawgmaster/repository/basemod.py new file mode 100644 index 000000000..5b996962b --- /dev/null +++ b/artiq/examples/kasli_sawgmaster/repository/basemod.py @@ -0,0 +1,25 @@ +from artiq.experiment import * + + +class BaseMod(EnvExperiment): + def build(self): + self.setattr_device("core") + self.basemods = [self.get_device("basemod_att0"), self.get_device("basemod_att1")] + self.rfsws = [self.get_device("sawg_sw"+str(i)) for i in range(8)] + + @kernel + def run(self): + self.core.reset() + for basemod in self.basemods: + self.core.break_realtime() + delay(10*ms) + basemod.reset() + delay(10*ms) + basemod.set(0.0, 0.0, 0.0, 0.0) + delay(10*ms) + print(basemod.get_mu()) + + self.core.break_realtime() + for rfws in self.rfsws: + rfws.on() + delay(1*ms) From 2c4e5bfee46b0e49eb6310f682db91fd77709814 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 16 Sep 2019 17:28:36 +0000 Subject: [PATCH 2116/2457] fastino: add [WIP] --- artiq/coredevice/fastino.py | 124 +++++++++++++++ artiq/frontend/artiq_ddb_template.py | 12 ++ artiq/gateware/eem.py | 24 ++- artiq/gateware/rtio/phy/fastino.py | 199 ++++++++++++++++++++++++ artiq/gateware/targets/kasli_generic.py | 7 + doc/manual/core_drivers_reference.rst | 6 + 6 files changed, 371 insertions(+), 1 deletion(-) create mode 100644 artiq/coredevice/fastino.py create mode 100644 artiq/gateware/rtio/phy/fastino.py diff --git a/artiq/coredevice/fastino.py b/artiq/coredevice/fastino.py new file mode 100644 index 000000000..30c6bca54 --- /dev/null +++ b/artiq/coredevice/fastino.py @@ -0,0 +1,124 @@ +"""RTIO driver for the Fastino 32channel, 16 bit, 2.5 MS/s per channel, +streaming DAC. + +TODO: Example, describe update/hold +""" + +from artiq.language.core import kernel, portable +from artiq.coredevice.rtio import rtio_output, rtio_input_data +from artiq.language.units import us + + +class Fastino: + """Fastino 32-channel, 16-bit, 2.5 MS/s per channel streaming DAC + + :param channel: RTIO channel number + :param core_device: Core device name (default: "core") + """ + + kernel_invariants = {"core", "channel"} + + def __init__(self, dmgr, channel, core_device="core"): + self.channel = channel << 8 + self.core = dmgr.get(core_device) + + @kernel + def init(self): + """Initialize the device. + + This clears reset, unsets DAC_CLR, enables AFE_PWR, + clears error counters, then enables error counting + """ + self.set_cfg(0x8) + delay(1*us) + self.set_cfg(0x0) + delay(1*us) + + @kernel + def write(self, addr, data): + """Write data to a Fastino register. + + :param addr: Address to write to. + :param data: Data to write. + """ + rtio_output(self.channel | addr, data) + + @kernel + def read(self, addr): + """Read from Fastino register. + + TODO: untested + + :param addr: Address to read from. + :return: The data read. + """ + rtio_output(self.channel | addr | 0x80) + return rtio_input_data(self.channel >> 8) + + @kernel + def set_dac_mu(self, dac, data): + """Write DAC data in machine units. + + :param dac: DAC channel to write to (0-31). + :param data: DAC word to write, 16 bit unsigned integer, in machine + units. + """ + self.write(dac, data) + + @portable + def voltage_to_mu(self, voltage): + """Convert SI Volts to DAC machine units. + + :param voltage: Voltage in SI Volts. + :return: DAC data word in machine units, 16 bit integer. + """ + return int(round((0x8000/10.)*voltage)) + 0x8000 + + @kernel + def set_dac(self, dac, voltage): + """Set DAC data to given voltage. + + :param dac: DAC channel (0-31). + :param voltage: Desired output voltage. + """ + self.write(dac, self.voltage_to_mu(voltage)) + + @kernel + def update(self, update): + """Schedule channels for update. + + :param update: Bit mask of channels to update (32 bit). + """ + self.write(0x20, update) + + @kernel + def set_hold(self, hold): + """Set channels to manual update. + + :param hold: Bit mask of channels to hold (32 bit). + """ + self.write(0x21, hold) + + @kernel + def set_cfg(self, reset=0, afe_power_down=0, dac_clr=0, clr_err=0): + """Set configuration bits. + + :param reset: Reset SPI PLL and SPI clock domain. + :param afe_power_down: Disable AFE power. + :param dac_clr: Assert all 32 DAC_CLR signals setting all DACs to + mid-scale (0 V). + :param clr_err: Clear error counters and PLL reset indicator. + This clears the sticky red error LED. Must be cleared to enable + error counting. + """ + self.write(0x22, (reset << 0) | (afe_pwr_disable << 1) | + (dac_clr << 2) | (clr_err << 3)) + + @kernel + def set_leds(self, leds): + """Set the green user-defined LEDs + + :param leds: LED status, 8 bit integer each bit corresponding to one + green LED. + """ + self.write(0x23, leds) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 114cd2d79..57bddf32c 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -473,6 +473,18 @@ class PeripheralManager: channel=rtio_offset) return 2 + def process_fastino(self, rtio_offset, peripheral): + self.gen(""" + device_db["{name}"] = {{ + "type": "local", + "module": "artiq.coredevice.fastino", + "class": "Fastino", + "arguments": {{"channel": 0x{channel:06x}}} + }}""", + name=self.get_name("fastino"), + channel=rtio_offset) + return 1 + def process(self, rtio_offset, peripheral): processor = getattr(self, "process_"+str(peripheral["type"])) return processor(rtio_offset, peripheral) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 84f4526ce..0c8bb2372 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -5,7 +5,7 @@ from migen.genlib.io import DifferentialOutput from artiq.gateware import rtio from artiq.gateware.rtio.phy import spi2, ad53xx_monitor, grabber from artiq.gateware.suservo import servo, pads as servo_pads -from artiq.gateware.rtio.phy import servo as rtservo +from artiq.gateware.rtio.phy import servo as rtservo, fastino def _eem_signal(i): @@ -603,3 +603,25 @@ class Mirny(_EEM): phy = ttl_out_cls(pads.p, pads.n) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy)) + + +class Fastino(_EEM): + @staticmethod + def io(eem, iostandard="LVDS_25"): + return [ + ("fastino{}_ser_{}".format(eem, pol), 0, + Subsignal("clk", Pins(_eem_pin(eem, 0, pol))), + Subsignal("mosi", Pins(*(_eem_pin(eem, i, pol) + for i in range(1, 7)))), + Subsignal("miso", Pins(_eem_pin(eem, 7, pol))), + IOStandard(iostandard), + ) for pol in "pn"] + + @classmethod + def add_std(cls, target, eem, iostandard="LVDS_25"): + cls.add_extension(target, eem, iostandard=iostandard) + + phy = fastino.Fastino(target.platform.request("fastino{}_ser_p".format(eem)), + target.platform.request("fastino{}_ser_n".format(eem))) + target.submodules += phy + target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) diff --git a/artiq/gateware/rtio/phy/fastino.py b/artiq/gateware/rtio/phy/fastino.py new file mode 100644 index 000000000..4c95568f3 --- /dev/null +++ b/artiq/gateware/rtio/phy/fastino.py @@ -0,0 +1,199 @@ +from migen import * +from migen.genlib.cdc import MultiReg +from migen.genlib.io import DifferentialOutput, DifferentialInput, DDROutput +from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine + +from artiq.gateware.rtio import rtlink + + +class SerDes(Module): + def transpose(self, i, n): + # i is n,m c-contiguous + # o is m,n c-contiguous + m = len(i)//n + assert n*m == len(i) + + def __init__(self, pins, pins_n): + n_bits = 16 # bits per dac data word + n_channels = 32 # channels per fastino + n_div = 7 # bits per lane and word + assert n_div == 7 + n_frame = 14 # word per frame + n_lanes = len(pins.mosi) # number of data lanes + n_checksum = 12 # checksum bits + n_addr = 4 # readback address bits + n_word = n_lanes*n_div + n_body = n_word*n_frame - (n_frame//2 + 1) - n_checksum + + # dac data words + self.dacs = [Signal(n_bits) for i in range(n_channels)] + # dac update enable + self.enable = Signal(n_channels) + # configuration word + self.cfg = Signal(20) + # readback data + self.dat_r = Signal(n_frame//2*(1 << n_addr)) + # data load synchronization event + self.stb = Signal() + + # # # + + # crc-12 telco + self.submodules.crc = LiteEthMACCRCEngine( + data_width=2*n_lanes, width=n_checksum, polynom=0x80f) + + addr = Signal(4) + body_ = Cat(self.cfg, addr, self.enable, self.dacs) + assert len(body_) == n_body + body = Signal(n_body) + self.comb += body.eq(body_) + + words_ = [] + j = 0 + for i in range(n_frame): # iterate over words + if i == 0: # data and checksum + k = n_word - n_checksum + elif i == 1: # marker + words_.append(C(1)) + k = n_word - 1 + elif i < n_frame//2 + 2: # marker + words_.append(C(0)) + k = n_word - 1 + else: # full word + k = n_word + # append corresponding frame body bits + words_.append(body[j:j + k]) + j += k + words_ = Cat(words_) + assert len(words_) == n_frame*n_word - n_checksum + words = Signal(len(words_)) + self.comb += words.eq(words_) + + clk = Signal(n_div, reset=0b1100011) + clk_stb = Signal() + i_frame = Signal(max=n_div*n_frame//2) # DDR + frame_stb = Signal() + sr = [Signal(n_frame*n_div - n_checksum//n_lanes, reset_less=True) + for i in range(n_lanes)] + assert len(Cat(sr)) == len(words) + # DDR bits for each register + ddr_data = Cat([sri[-2] for sri in sr], [sri[-1] for sri in sr]) + self.comb += [ + # assert one cycle ahead + clk_stb.eq(~clk[0] & clk[-1]), + # double period because of DDR + frame_stb.eq(i_frame == n_div*n_frame//2 - 1), + + # LiteETHMACCRCEngine takes data LSB first + self.crc.data[::-1].eq(ddr_data), + self.stb.eq(frame_stb & clk_stb), + ] + miso = Signal() + miso_sr = Signal(n_frame, reset_less=True) + self.sync.rio_phy += [ + # shift 7 bit clock pattern by two bits each DDR cycle + clk.eq(Cat(clk[-2:], clk)), + [sri[2:].eq(sri) for sri in sr], + self.crc.last.eq(self.crc.next), + If(clk[:2] == 0, # TODO: tweak MISO sampling + miso_sr.eq(Cat(miso, miso_sr)), + ), + If(~frame_stb, + i_frame.eq(i_frame + 1), + ), + If(frame_stb & clk_stb, + i_frame.eq(0), + self.crc.last.eq(0), + # transpose, load + Cat(sr).eq(Cat(words[mm::n_lanes] for mm in range(n_lanes))), + Array([self.dat_r[i*n_frame//2:(i + 1)*n_frame//2] + for i in range(1 << len(addr))])[addr].eq(miso_sr), + addr.eq(addr + 1), + ), + If(i_frame == n_div*n_frame//2 - 2, + # inject crc + ddr_data.eq(self.crc.next), + ), + ] + + clk_ddr = Signal() + miso0 = Signal() + self.specials += [ + DDROutput(clk[-1], clk[-2], clk_ddr, ClockSignal("rio_phy")), + DifferentialOutput(clk_ddr, pins.clk, pins_n.clk), + DifferentialInput(pins.miso, pins_n.miso, miso0), + MultiReg(miso0, miso, "rio_phy"), + ] + for sri, ddr, mp, mn in zip( + sr, Signal(n_lanes), pins.mosi, pins_n.mosi): + self.specials += [ + DDROutput(sri[-1], sri[-2], ddr, ClockSignal("rio_phy")), + DifferentialOutput(ddr, mp, mn), + ] + + +class Fastino(Module): + def __init__(self, pins, pins_n): + self.rtlink = rtlink.Interface( + rtlink.OInterface(data_width=32, address_width=8, + enable_replace=False), + rtlink.IInterface(data_width=32)) + + self.submodules.serializer = SerDes(pins, pins_n) + + # Support staging DAC data (in `dacs`) by writing to the + # 32 DAC RTIO addresses, if a channel is not "held" by its + # bit in `hold` the next frame will contain the update. + # For the DACs held, the update is triggered by setting the + # corresponding bit in `update`. Update is self-clearing. + # This enables atomic DAC updates synchronized to a frame edge. + # + # This RTIO layout enables narrow RTIO words (32 bit + # compared to 512), efficient few-channel updates, + # least amount of DAC state tracking in kernels, + # at the cost of more DMA and RTIO data ((n*(32+32+64) vs + # 32+32*16+64)) + + hold = Signal.like(self.serializer.enable) + + # TODO: stb, timestamp + read_regs = Array([ + self.serializer.dat_r[i*7:(i + 1)*7] + for i in range(1 << 4) + ]) + + cases = { + # update + 0x20: self.serializer.enable.eq(self.serializer.enable | self.rtlink.o.data), + # hold + 0x21: hold.eq(self.rtlink.o.data), + # cfg + 0x22: self.serializer.cfg[:4].eq(self.rtlink.o.data), + # leds + 0x23: self.serializer.cfg[4:12].eq(self.rtlink.o.data), + # reserved + 0x24: self.serializer.cfg[12:].eq(self.rtlink.o.data), + } + for i in range(len(self.serializer.dacs)): + cases[i] = [ + self.serializer.dacs[i].eq(self.rtlink.o.data), + If(~hold[i], + self.serializer.enable[i].eq(1), + ) + ] + + self.sync.rio_phy += [ + If(self.serializer.stb, + self.serializer.enable.eq(0), + ), + If(self.rtlink.o.stb & ~self.rtlink.o.address[-1], + Case(self.rtlink.o.address[:-1], cases), + ), + ] + + self.sync.rtio += [ + self.rtlink.i.stb.eq(self.rtlink.o.stb & + self.rtlink.o.address[-1]), + self.rtlink.i.data.eq( + read_regs[self.rtlink.o.address[:-1]]), + ] diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index 2f593459a..477fecf16 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -105,6 +105,12 @@ def peripheral_mirny(module, peripheral): eem.Mirny.add_std(module, peripheral["ports"][0], ttl_serdes_7series.Output_8X) + +def peripheral_fastino(module, peripheral): + if len(peripheral["ports"]) != 1: + raise ValueError("wrong number of ports") + eem.Fastino.add_std(module, peripheral["ports"][0]) + peripheral_processors = { "dio": peripheral_dio, @@ -115,6 +121,7 @@ peripheral_processors = { "zotino": peripheral_zotino, "grabber": peripheral_grabber, "mirny": peripheral_mirny, + "fastino": peripheral_fastino, } diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 17e4909c9..b0026b6ac 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -158,6 +158,12 @@ DAC/ADC drivers .. automodule:: artiq.coredevice.novogorny :members: +:mod:`artiq.coredevice.fastino` module +++++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.fastino + :members: + Miscellaneous ------------- From c45a872cbadf193ce783efcb2d72b3b1bae7f54c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 16 Jan 2020 13:39:52 +0000 Subject: [PATCH 2117/2457] fastino: fix init, set_cfg --- artiq/coredevice/fastino.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/fastino.py b/artiq/coredevice/fastino.py index 30c6bca54..a84a947e9 100644 --- a/artiq/coredevice/fastino.py +++ b/artiq/coredevice/fastino.py @@ -29,9 +29,9 @@ class Fastino: This clears reset, unsets DAC_CLR, enables AFE_PWR, clears error counters, then enables error counting """ - self.set_cfg(0x8) + self.set_cfg(reset=0, afe_power_down=0, dac_clr=0, clr_err=1) delay(1*us) - self.set_cfg(0x0) + self.set_cfg(reset=0, afe_power_down=0, dac_clr=0, clr_err=0) delay(1*us) @kernel @@ -111,7 +111,7 @@ class Fastino: This clears the sticky red error LED. Must be cleared to enable error counting. """ - self.write(0x22, (reset << 0) | (afe_pwr_disable << 1) | + self.write(0x22, (reset << 0) | (afe_power_down << 1) | (dac_clr << 2) | (clr_err << 3)) @kernel From 248230a89ebb76998d1e4b048238a92f53c4ab8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 20 Jan 2020 13:22:22 +0100 Subject: [PATCH 2118/2457] fastino: style --- artiq/coredevice/fastino.py | 4 ++-- artiq/gateware/targets/kasli_generic.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/fastino.py b/artiq/coredevice/fastino.py index a84a947e9..baa01529f 100644 --- a/artiq/coredevice/fastino.py +++ b/artiq/coredevice/fastino.py @@ -4,7 +4,7 @@ streaming DAC. TODO: Example, describe update/hold """ -from artiq.language.core import kernel, portable +from artiq.language.core import kernel, portable, delay from artiq.coredevice.rtio import rtio_output, rtio_input_data from artiq.language.units import us @@ -112,7 +112,7 @@ class Fastino: error counting. """ self.write(0x22, (reset << 0) | (afe_power_down << 1) | - (dac_clr << 2) | (clr_err << 3)) + (dac_clr << 2) | (clr_err << 3)) @kernel def set_leds(self, leds): diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index 477fecf16..a3e03ef7b 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -105,7 +105,7 @@ def peripheral_mirny(module, peripheral): eem.Mirny.add_std(module, peripheral["ports"][0], ttl_serdes_7series.Output_8X) - + def peripheral_fastino(module, peripheral): if len(peripheral["ports"]) != 1: raise ValueError("wrong number of ports") From 82cdb7f933bf4d70602493cdeb11623eea3d75fc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 20 Jan 2020 20:15:27 +0800 Subject: [PATCH 2119/2457] typo --- artiq/examples/kasli_sawgmaster/repository/basemod.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/examples/kasli_sawgmaster/repository/basemod.py b/artiq/examples/kasli_sawgmaster/repository/basemod.py index 5b996962b..3ca9a1c86 100644 --- a/artiq/examples/kasli_sawgmaster/repository/basemod.py +++ b/artiq/examples/kasli_sawgmaster/repository/basemod.py @@ -20,6 +20,6 @@ class BaseMod(EnvExperiment): print(basemod.get_mu()) self.core.break_realtime() - for rfws in self.rfsws: - rfws.on() + for rfsw in self.rfsws: + rfsw.on() delay(1*ms) From bfcbffcd8debe3be98acc25500e53da7828b7df0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 21 Jan 2020 13:58:23 +0800 Subject: [PATCH 2120/2457] update smoltcp This disables the 'log' features which does not compile, and may break net_trace. To be investigated later. --- artiq/firmware/Cargo.lock | 20 +++++--------------- artiq/firmware/bootloader/Cargo.toml | 2 +- artiq/firmware/cargosha256.nix | 2 +- artiq/firmware/libboard_misoc/Cargo.toml | 2 +- artiq/firmware/libboard_misoc/ethmac.rs | 6 +++--- artiq/firmware/runtime/Cargo.toml | 2 +- 6 files changed, 12 insertions(+), 22 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index caf0d005f..2874347c8 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -33,7 +33,7 @@ dependencies = [ "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -44,7 +44,7 @@ dependencies = [ "build_misoc 0.0.0", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -146,14 +146,6 @@ name = "libc" version = "0.2.40" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "log" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "log" version = "0.4.1" @@ -218,7 +210,7 @@ dependencies = [ "logger_artiq 0.0.0", "managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "proto_artiq 0.0.0", - "smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "unwind_backtrace 0.0.0", ] @@ -234,12 +226,11 @@ dependencies = [ [[package]] name = "smoltcp" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -291,12 +282,11 @@ version = "0.0.0" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" "checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=b8a6d8f)" = "" "checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" -"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum log_buffer 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f033173c9486b7fe97a79c895c0a3483ae395ab6744c985d10078950e2492419" "checksum managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba6713e624266d7600e9feae51b1926c6a6a6bebb18ec5a8e11a5f1d5661baba" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fef582369edb298c6c41319a544ca9c4e83622f226055ccfcb35974fbb55ed34" +"checksum smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0fe46639fd2ec79eadf8fe719f237a7a0bd4dac5d957f1ca5bbdbc1c3c39e53a" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" diff --git a/artiq/firmware/bootloader/Cargo.toml b/artiq/firmware/bootloader/Cargo.toml index aed6df31b..e89902308 100644 --- a/artiq/firmware/bootloader/Cargo.toml +++ b/artiq/firmware/bootloader/Cargo.toml @@ -16,4 +16,4 @@ build_misoc = { path = "../libbuild_misoc" } byteorder = { version = "1.0", default-features = false } crc = { version = "1.7", default-features = false } board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp"] } -smoltcp = { version = "0.5.0", default-features = false, features = ["proto-ipv4", "proto-ipv6", "socket-tcp"] } +smoltcp = { version = "0.6.0", default-features = false, features = ["ethernet", "proto-ipv4", "proto-ipv6", "socket-tcp"] } diff --git a/artiq/firmware/cargosha256.nix b/artiq/firmware/cargosha256.nix index c356e4291..2bf5725cf 100644 --- a/artiq/firmware/cargosha256.nix +++ b/artiq/firmware/cargosha256.nix @@ -1 +1 @@ -"1xzjn9i4rkd9124v2gbdplsgsvp1hlx7czdgc58n316vsnrkbr86" +"0ml6j4sxqrayqk25xkrikwg713mahfqa60nrx1jhrj8c2h3p07yk" diff --git a/artiq/firmware/libboard_misoc/Cargo.toml b/artiq/firmware/libboard_misoc/Cargo.toml index 8847d0a0d..81ebf979f 100644 --- a/artiq/firmware/libboard_misoc/Cargo.toml +++ b/artiq/firmware/libboard_misoc/Cargo.toml @@ -15,7 +15,7 @@ build_misoc = { path = "../libbuild_misoc" } [dependencies] byteorder = { version = "1.0", default-features = false } log = { version = "0.4", default-features = false, optional = true } -smoltcp = { version = "0.5.0", default-features = false, optional = true } +smoltcp = { version = "0.6.0", default-features = false, optional = true } [features] uart_console = [] diff --git a/artiq/firmware/libboard_misoc/ethmac.rs b/artiq/firmware/libboard_misoc/ethmac.rs index 263f8122d..ff585a010 100644 --- a/artiq/firmware/libboard_misoc/ethmac.rs +++ b/artiq/firmware/libboard_misoc/ethmac.rs @@ -30,7 +30,7 @@ fn next_tx_slot() -> Option { } } -fn rx_buffer(slot: usize) -> *const u8 { +fn rx_buffer(slot: usize) -> *mut u8 { debug_assert!(slot < RX_SLOTS); (ETHMAC_BASE + SLOT_SIZE * slot) as _ } @@ -97,11 +97,11 @@ pub struct EthernetRxSlot(usize); impl phy::RxToken for EthernetRxSlot { fn consume(self, _timestamp: Instant, f: F) -> Result - where F: FnOnce(&[u8]) -> Result + where F: FnOnce(&mut [u8]) -> Result { unsafe { let length = csr::ethmac::sram_writer_length_read() as usize; - let result = f(slice::from_raw_parts(rx_buffer(self.0), length)); + let result = f(slice::from_raw_parts_mut(rx_buffer(self.0), length)); csr::ethmac::sram_writer_ev_pending_write(1); result } diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index c2404fc4c..bbb9877bb 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -27,7 +27,7 @@ board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp logger_artiq = { path = "../liblogger_artiq" } board_artiq = { path = "../libboard_artiq" } proto_artiq = { path = "../libproto_artiq", features = ["log", "alloc"] } -smoltcp = { version = "0.5.0", default-features = false, features = ["rust-1_28", "alloc", "log", "proto-ipv4", "proto-ipv6", "socket-tcp"] } +smoltcp = { version = "0.6.0", default-features = false, features = ["rust-1_28", "alloc", "ethernet", "proto-ipv4", "proto-ipv6", "socket-tcp"] } [dependencies.fringe] git = "https://github.com/m-labs/libfringe" From f4d8f77268f7ab7c5f02f8c9116cadd37d990fcb Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 21 Jan 2020 16:13:04 +0800 Subject: [PATCH 2121/2457] turn kasli_tester into a frontend tool --- .../artiq_sinara_tester.py} | 29 ++++++++++++++----- setup.py | 1 + 2 files changed, 23 insertions(+), 7 deletions(-) rename artiq/{examples/kasli/repository/kasli_tester.py => frontend/artiq_sinara_tester.py} (96%) mode change 100644 => 100755 diff --git a/artiq/examples/kasli/repository/kasli_tester.py b/artiq/frontend/artiq_sinara_tester.py old mode 100644 new mode 100755 similarity index 96% rename from artiq/examples/kasli/repository/kasli_tester.py rename to artiq/frontend/artiq_sinara_tester.py index 084022e5e..da702faee --- a/artiq/examples/kasli/repository/kasli_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -1,9 +1,14 @@ +#!/usr/bin/env python3 + import sys import os import select from artiq.experiment import * from artiq.coredevice.ad9910 import AD9910, SyncDataEeprom +from artiq.master.databases import DeviceDB +from artiq.master.worker_db import DeviceManager + if os.name == "nt": import msvcrt @@ -34,13 +39,8 @@ def is_enter_pressed() -> TBool: return False -class KasliTester(EnvExperiment): +class SinaraTester(EnvExperiment): def build(self): - # hack to detect artiq_run - if self.get_device("scheduler").__class__.__name__ != "DummyScheduler": - raise NotImplementedError( - "must be run with artiq_run to support keyboard interaction") - self.setattr_device("core") self.leds = dict() @@ -365,7 +365,7 @@ class KasliTester(EnvExperiment): self.grabber_capture(card_dev, rois) def run(self): - print("****** Kasli system tester ******") + print("****** Sinara system tester ******") print("") self.core.reset() if self.leds: @@ -382,3 +382,18 @@ class KasliTester(EnvExperiment): self.test_zotinos() if self.grabbers: self.test_grabbers() + + +def main(): + device_mgr = DeviceManager(DeviceDB("device_db.pyon")) + try: + experiment = SinaraTester((device_mgr, None, None, None)) + experiment.prepare() + experiment.run() + experiment.analyze() + finally: + device_mgr.close_devices() + + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index 3e0e722ad..44022073d 100755 --- a/setup.py +++ b/setup.py @@ -28,6 +28,7 @@ console_scripts = [ "artiq_master = artiq.frontend.artiq_master:main", "artiq_mkfs = artiq.frontend.artiq_mkfs:main", "artiq_rtiomon = artiq.frontend.artiq_rtiomon:main", + "artiq_sinara_tester = artiq.frontend.artiq_sinara_tester:main", "artiq_session = artiq.frontend.artiq_session:main", "artiq_route = artiq.frontend.artiq_route:main", "artiq_run = artiq.frontend.artiq_run:main", From dee16edb78a32bacf13c1fccaafb4eda7a16342e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 22 Jan 2020 19:16:26 +0800 Subject: [PATCH 2122/2457] wrpll: DDMTD sampler double latching --- artiq/gateware/drtio/wrpll/ddmtd.py | 39 +++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index a578a3824..4b4f30324 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -6,21 +6,34 @@ from misoc.interconnect.csr import * class DDMTDSamplerExtFF(Module): def __init__(self, ddmtd_inputs): + self.rec_clk = Signal() + self.main_xo = Signal() + + # # # + # TODO: s/h timing at FPGA pads if hasattr(ddmtd_inputs, "rec_clk"): - self.rec_clk = ddmtd_inputs.rec_clk + rec_clk_1 = ddmtd_inputs.rec_clk else: - self.rec_clk = Signal() + rec_clk_1 = Signal() self.specials += Instance("IBUFDS", i_I=ddmtd_inputs.rec_clk_p, i_IB=ddmtd_inputs.rec_clk_n, - o_O=self.rec_clk) + o_O=rec_clk_1) if hasattr(ddmtd_inputs, "main_xo"): - self.main_xo = ddmtd_inputs.main_xo + main_xo_1 = ddmtd_inputs.main_xo else: - self.main_xo = Signal() + main_xo_1 = Signal() self.specials += Instance("IBUFDS", i_I=ddmtd_inputs.main_xo_p, i_IB=ddmtd_inputs.main_xo_n, - o_O=self.main_xo) + o_O=main_xo_1) + self.specials += [ + Instance("FD", i_C=ClockSignal("helper"), + i_D=rec_clk_1, o_Q=self.rec_clk, + attr={("IOB", "TRUE")}), + Instance("FD", i_C=ClockSignal("helper"), + i_D=main_xo_1, o_Q=self.main_xo, + attr={("IOB", "TRUE")}), + ] class DDMTDSamplerGTP(Module): @@ -28,20 +41,30 @@ class DDMTDSamplerGTP(Module): self.rec_clk = Signal() self.main_xo = Signal() + # # # + # Getting the main XO signal from IBUFDS_GTE2 is problematic because # the transceiver PLL craps out if an improper clock signal is applied, # so we are disabling the buffer until the clock is stable. main_xo_se = Signal() + rec_clk_1 = Signal() + main_xo_1 = Signal() self.specials += [ Instance("IBUFDS", i_I=main_xo_pads.p, i_IB=main_xo_pads.n, o_O=main_xo_se), Instance("FD", i_C=ClockSignal("helper"), - i_D=gtp.cd_rtio_rx0.clk, o_Q=self.rec_clk, + i_D=gtp.cd_rtio_rx0.clk, o_Q=rec_clk_1, attr={("DONT_TOUCH", "TRUE")}), Instance("FD", i_C=ClockSignal("helper"), - i_D=main_xo_se, o_Q=self.main_xo, + i_D=rec_clk_1, o_Q=self.rec_clk, + attr={("DONT_TOUCH", "TRUE")}), + Instance("FD", i_C=ClockSignal("helper"), + i_D=main_xo_se, o_Q=main_xo_1, attr={("IOB", "TRUE")}), + Instance("FD", i_C=ClockSignal("helper"), + i_D=main_xo_1, o_Q=self.main_xo, + attr={("DONT_TOUCH", "TRUE")}), ] From dfa033eb872bc4112f5f1f401c9f33926184db3c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 24 Jan 2020 10:31:52 +0800 Subject: [PATCH 2123/2457] wrpll: new collector from Weida/Tom --- artiq/gateware/drtio/wrpll/core.py | 5 ++++- artiq/gateware/drtio/wrpll/ddmtd.py | 30 +++++++++++++++++++++-------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index a8d374ca8..793219043 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -79,6 +79,9 @@ class WRPLL(Module, AutoCSR): self.submodules.ddmtd_helper = DDMTD(ddmtd_counter, ddmtd_inputs.rec_clk) self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_inputs.main_xo) + collector_update = Signal() + self.sync.helper += collector_update.eq(ddmtd_counter == (2**N - 1)) + filter_cd = ClockDomainsRenamer("filter") self.submodules.collector = filter_cd(Collector(N)) self.submodules.filter_helper = filter_cd(thls.make(filters.helper, data_width=48)) @@ -98,7 +101,7 @@ class WRPLL(Module, AutoCSR): ] self.comb += [ self.filter_main.input.eq(self.collector.output), - self.filter_main.input_stb.eq(self.collector.output_update) + self.filter_main.input_stb.eq(collector_update) ] self.sync.helper += [ diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index 4b4f30324..58002779d 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -131,20 +131,19 @@ class DDMTD(Module, AutoCSR): class Collector(Module): def __init__(self, N): - self.tag_helper = Signal(N) + self.tag_helper = Signal((N, True)) self.tag_helper_update = Signal() - self.tag_main = Signal(N) + self.tag_main = Signal((N, True)) self.tag_main_update = Signal() - self.output = Signal((N, True)) - self.output_update = Signal(N) + self.output = Signal((N + 1, True)) # # # fsm = FSM(reset_state="IDLE") self.submodules += fsm - tag_collector = Signal(N) + tag_collector = Signal((N + 1, True)) fsm.act("IDLE", If(self.tag_main_update & self.tag_helper_update, NextValue(tag_collector, 0), @@ -160,17 +159,32 @@ class Collector(Module): fsm.act("WAITHELPER", If(self.tag_helper_update, NextValue(tag_collector, tag_collector - self.tag_helper), - NextState("UPDATE") + NextState("LEADCHECK") ) ) fsm.act("WAITMAIN", If(self.tag_main_update, NextValue(tag_collector, tag_collector + self.tag_main), - NextState("UPDATE") + NextState("LAGCHECK") ) ) + # To compensate DDMTD counter roll-over when main is ahead of roll-over + # and helper is after roll-over + fsm.act("LEADCHECK", + If(tag_collector > 0, + NextValue(tag_collector, tag_collector - (2**N - 1)) + ), + NextState("UPDATE") + ) + # To compensate DDMTD counter roll-over when helper is ahead of roll-over + # and main is after roll-over + fsm.act("LAGCHECK", + If(tag_collector < 0, + NextValue(tag_collector, tag_collector + (2**N - 1)) + ), + NextState("UPDATE") + ) fsm.act("UPDATE", NextValue(self.output, tag_collector), NextState("IDLE") ) - self.sync += self.output_update.eq(self.tag_helper_update) From 5f8e20b1a1a28bae3f110180139f8bbd4652c83a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 31 Jan 2020 10:26:58 +0800 Subject: [PATCH 2124/2457] artiq_sinara_tester: fix device_db filename --- artiq/frontend/artiq_sinara_tester.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index da702faee..fdf34c8a9 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -385,7 +385,7 @@ class SinaraTester(EnvExperiment): def main(): - device_mgr = DeviceManager(DeviceDB("device_db.pyon")) + device_mgr = DeviceManager(DeviceDB("device_db.py")) try: experiment = SinaraTester((device_mgr, None, None, None)) experiment.prepare() From ffb24e9fffe0e4325c74345e6bb8babdcb938c35 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 3 Feb 2020 18:07:26 +0800 Subject: [PATCH 2125/2457] artiq_flash: use correct proxy bitstream for Metlino --- artiq/frontend/artiq_flash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 7dcd9b651..50e63c042 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -297,7 +297,7 @@ class ProgrammerMetlino(Programmer): add_commands(self._script, "echo \"AMC FPGA XADC:\"", "xadc_report xcu.tap") def load_proxy(self): - self.load(find_proxy_bitfile("bscan_spi_xcku040-sayma.bit"), pld=0) + self.load(find_proxy_bitfile("bscan_spi_xcku040.bit"), pld=0) def start(self): add_commands(self._script, "xcu_program xcu.tap") From bf9f4e380a31143f762cd2b184d89e5b76168958 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 3 Feb 2020 18:07:59 +0800 Subject: [PATCH 2126/2457] si5324: program I2C mux on Metlino --- artiq/firmware/libboard_artiq/si5324.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/firmware/libboard_artiq/si5324.rs b/artiq/firmware/libboard_artiq/si5324.rs index 68005131f..f5e816f14 100644 --- a/artiq/firmware/libboard_artiq/si5324.rs +++ b/artiq/firmware/libboard_artiq/si5324.rs @@ -186,6 +186,8 @@ fn init() -> Result<()> { i2c::pca9548_select(BUSNO, 0x70, 1 << 4)?; #[cfg(soc_platform = "sayma_rtm")] i2c::pca9548_select(BUSNO, 0x77, 1 << 5)?; + #[cfg(soc_platform = "metlino")] + i2c::pca9548_select(BUSNO, 0x70, 1 << 4)?; #[cfg(soc_platform = "kc705")] i2c::pca9548_select(BUSNO, 0x74, 1 << 7)?; From c7de1f2e6bd24abcb5e393f2bf8f706a3da06b5d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Feb 2020 00:06:34 +0800 Subject: [PATCH 2127/2457] metlino: drive clock muxes --- artiq/gateware/targets/metlino.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/gateware/targets/metlino.py b/artiq/gateware/targets/metlino.py index 999bfaaf6..65e3c2f0c 100755 --- a/artiq/gateware/targets/metlino.py +++ b/artiq/gateware/targets/metlino.py @@ -53,6 +53,8 @@ class Master(MiniSoC, AMPSoC): platform = self.platform rtio_clk_freq = 150e6 + self.comb += platform.request("input_clk_sel").eq(1) + self.comb += platform.request("filtered_clk_sel").eq(1) self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) self.csr_devices.append("si5324_rst_n") i2c = self.platform.request("i2c") From 52ec8490085318620c612dd6abfaed318336394c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 5 Feb 2020 19:04:01 +0800 Subject: [PATCH 2128/2457] sayma: fix sysref_delay_dac --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index 2c34f9f0d..d5f418a5e 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -373,9 +373,9 @@ pub mod hmc7043 { pub fn sysref_delay_dac(dacno: u8, phase_offset: u8) { spi_setup(); if dacno == 0 { - write(0x00d5, phase_offset); - } else if dacno == 1 { write(0x00e9, phase_offset); + } else if dacno == 1 { + write(0x00d5, phase_offset); } else { unimplemented!(); } From 6d26def3ce6c89f33d6affec58e658c87a09d67d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 6 Feb 2020 22:28:49 +0800 Subject: [PATCH 2129/2457] sayma: drive filtered_clk_sel on master variant --- artiq/gateware/targets/sayma_amc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index e75c6d67a..18e6f70e0 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -388,6 +388,7 @@ class Master(MiniSoC, AMPSoC): self.config["SI5324_AS_SYNTHESIZER"] = None self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) + self.comb += platform.request("filtered_clk_sel").eq(1) self.comb += platform.request("sfp_tx_disable", 0).eq(0) self.submodules.drtio_transceiver = gth_ultrascale.GTH( clock_pads=platform.request("cdr_clk_clean", 0), From 2a909839ff2e84002307a3f4014442f6d03a12ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20K?= Date: Wed, 19 Feb 2020 12:44:11 +0100 Subject: [PATCH 2130/2457] artiq_flash: added option of specifying another username when connecting through SSH. (#1429) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paweł Kulik --- artiq/remoting.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/artiq/remoting.py b/artiq/remoting.py index 24e53b53a..41ca35928 100644 --- a/artiq/remoting.py +++ b/artiq/remoting.py @@ -59,7 +59,11 @@ class LocalClient(Client): class SSHClient(Client): def __init__(self, host, jump_host=None): - self.host = host + if "@" in host: + self.username, self.host = host.split("@") + else: + self.host = host + self.username = None self.jump_host = jump_host self.ssh = None self.sftp = None @@ -83,7 +87,7 @@ class SSHClient(Client): self.ssh = paramiko.SSHClient() self.ssh.load_system_host_keys() self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - self.ssh.connect(self.host, sock=proxy) + self.ssh.connect(self.host, username=self.username, sock=proxy) logger.debug("Connecting to {}".format(self.host)) return self.ssh From 8451e58fbef81c9b1f2bb41dbdda33e0595a7947 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 27 Feb 2020 02:11:12 +0800 Subject: [PATCH 2131/2457] ad9912: fix ftw width docstring --- artiq/coredevice/ad9912.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 9e1005932..32854ef6e 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -140,7 +140,7 @@ class AD9912: After the SPI transfer, the shared IO update pin is pulsed to activate the data. - :param ftw: Frequency tuning word: 32 bit unsigned. + :param ftw: Frequency tuning word: 48 bit unsigned. :param pow: Phase tuning word: 16 bit unsigned. """ # streaming transfer of FTW and POW From 8dbf30b23ec2c15a5972e457b6e9fc01db061b94 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 2 Mar 2020 18:42:01 +0800 Subject: [PATCH 2132/2457] manual: mention integrated Kasli JTAG --- doc/manual/installing.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 3c1f51f68..95235a275 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -215,6 +215,8 @@ Then, you can write the flash: $ artiq_flash -V [your system variant] +The JTAG adapter is integrated into the Kasli board; for flashing (and debugging) you simply need to connect your computer to the micro-USB connector on the Kasli front panel. + * For the KC705 board:: $ artiq_flash -t kc705 -V [nist_clock/nist_qc2] From e803830b3b3cc791fd98425ac30a4efb1c210485 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 5 Mar 2020 16:13:40 +0000 Subject: [PATCH 2133/2457] fastino: support wide RTIO interface and channel groups --- artiq/coredevice/fastino.py | 55 +++++++++++++++++++++++++++--- artiq/gateware/eem.py | 3 +- artiq/gateware/rtio/phy/fastino.py | 32 +++++++++++------ 3 files changed, 74 insertions(+), 16 deletions(-) diff --git a/artiq/coredevice/fastino.py b/artiq/coredevice/fastino.py index baa01529f..32306388a 100644 --- a/artiq/coredevice/fastino.py +++ b/artiq/coredevice/fastino.py @@ -5,8 +5,9 @@ TODO: Example, describe update/hold """ from artiq.language.core import kernel, portable, delay -from artiq.coredevice.rtio import rtio_output, rtio_input_data +from artiq.coredevice.rtio import rtio_output, rtio_output_wide, rtio_input_data from artiq.language.units import us +from artiq.language.types import TInt32, TList, TFloat class Fastino: @@ -14,13 +15,19 @@ class Fastino: :param channel: RTIO channel number :param core_device: Core device name (default: "core") + :param log2_width: Width of DAC channel group (power of two, + see the RTIO PHY for details). If zero, the + :meth:`set_dac`/:meth:`set_dac_mu` interface must be used. + If non-zero, the :meth:`set_group`/:meth:`set_group_mu` + interface must be used. Value must match the corresponding value + in the RTIO PHY. """ + kernel_invariants = {"core", "channel", "width"} - kernel_invariants = {"core", "channel"} - - def __init__(self, dmgr, channel, core_device="core"): + def __init__(self, dmgr, channel, core_device="core", log2_width=0): self.channel = channel << 8 self.core = dmgr.get(core_device) + self.width = 1 << log2_width @kernel def init(self): @@ -65,6 +72,21 @@ class Fastino: """ self.write(dac, data) + @kernel + def set_group_mu(self, dac: TInt32, data: TList(TInt32)): + """Write a group of DAC channels in machine units. + + :param dac: First channel in DAC channel group (0-31). The `log2_width` + LSBs must be zero. + :param data: List of DAC data pairs (2x16 bit unsigned) to write, + in machine units. Data exceeding group size is ignored. + If the list length is less than group size, the remaining + DAC channels within the group are cleared to 0 (machine units). + """ + if dac & (self.width - 1): + raise ValueError("Group index LSBs must be zero") + rtio_output_wide(self.channel | dac, data) + @portable def voltage_to_mu(self, voltage): """Convert SI Volts to DAC machine units. @@ -74,6 +96,20 @@ class Fastino: """ return int(round((0x8000/10.)*voltage)) + 0x8000 + @portable + def voltage_group_to_mu(self, voltage, data): + """Convert SI Volts to packed DAC channel group machine units. + + :param voltage: List of SI Volt voltages. + :param data: List of DAC channel data pairs to write to. + Half the length of `voltage`. + """ + for i in range(len(voltage)): + v = self.voltage_to_mu(voltage[i]) + if i & 1: + v = data[i // 2] | (v << 16) + data[i // 2] = v + @kernel def set_dac(self, dac, voltage): """Set DAC data to given voltage. @@ -83,6 +119,17 @@ class Fastino: """ self.write(dac, self.voltage_to_mu(voltage)) + @kernel + def set_group(self, dac, voltage): + """Set DAC group data to given voltage. + + :param dac: DAC channel (0-31). + :param voltage: Desired output voltage. + """ + data = [int32(0)] * (len(voltage) // 2) + self.voltage_group_to_mu(voltage, data) + self.set_group_mu(dac, data) + @kernel def update(self, update): """Schedule channels for update. diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 0c8bb2372..fba2c1b5a 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -622,6 +622,7 @@ class Fastino(_EEM): cls.add_extension(target, eem, iostandard=iostandard) phy = fastino.Fastino(target.platform.request("fastino{}_ser_p".format(eem)), - target.platform.request("fastino{}_ser_n".format(eem))) + target.platform.request("fastino{}_ser_n".format(eem)), + log2_width=0) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) diff --git a/artiq/gateware/rtio/phy/fastino.py b/artiq/gateware/rtio/phy/fastino.py index 4c95568f3..14d9d9cf1 100644 --- a/artiq/gateware/rtio/phy/fastino.py +++ b/artiq/gateware/rtio/phy/fastino.py @@ -133,26 +133,36 @@ class SerDes(Module): class Fastino(Module): - def __init__(self, pins, pins_n): + def __init__(self, pins, pins_n, log2_width=0): + width = 1 << log2_width self.rtlink = rtlink.Interface( - rtlink.OInterface(data_width=32, address_width=8, + rtlink.OInterface(data_width=max(16*width, 32), + address_width=8, enable_replace=False), rtlink.IInterface(data_width=32)) self.submodules.serializer = SerDes(pins, pins_n) # Support staging DAC data (in `dacs`) by writing to the - # 32 DAC RTIO addresses, if a channel is not "held" by its + # DAC RTIO addresses, if a channel is not "held" by its # bit in `hold` the next frame will contain the update. # For the DACs held, the update is triggered by setting the # corresponding bit in `update`. Update is self-clearing. # This enables atomic DAC updates synchronized to a frame edge. # - # This RTIO layout enables narrow RTIO words (32 bit - # compared to 512), efficient few-channel updates, - # least amount of DAC state tracking in kernels, + # The `log2_width=0` RTIO layout uses one DAC channel per RTIO address + # and a dense RTIO address space. The RTIO words are narrow. + # (32 bit compared to 512) and few-channel updates are efficient. + # There is the least amount of DAC state tracking in kernels, # at the cost of more DMA and RTIO data ((n*(32+32+64) vs # 32+32*16+64)) + # + # Other `log2_width` (up to `log2_width=5) settings pack multiple + # (in powers of two) DAC channels into one group and + # into one RTIO write. + # The RTIO data width increases accordingly. The `log2_width` + # LSBs of the RTIO address for a DAC channel write must be zero and the + # address space is sparse. hold = Signal.like(self.serializer.enable) @@ -174,12 +184,12 @@ class Fastino(Module): # reserved 0x24: self.serializer.cfg[12:].eq(self.rtlink.o.data), } - for i in range(len(self.serializer.dacs)): + for i in range(0, len(self.serializer.dacs), width): cases[i] = [ - self.serializer.dacs[i].eq(self.rtlink.o.data), - If(~hold[i], - self.serializer.enable[i].eq(1), - ) + Cat(self.serializer.dacs[i:i + width]).eq(self.rtlink.o.data), + [If(~hold[i + j], + self.serializer.enable[i + j].eq(1), + ) for j in range(width)] ] self.sync.rio_phy += [ From 380de177e7204d5b3ed665572c81b81ed635a742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 5 Mar 2020 17:55:27 +0000 Subject: [PATCH 2134/2457] rtio: fix wide output after RTIO refactoring fixes 3d0c3cc1cf84a1b6688afa4b41ba0c7789717915 --- artiq/firmware/ksupport/rtio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index fc64f554b..5ce17850f 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -91,7 +91,7 @@ mod imp { unsafe { csr::rtio::target_write(target as u32); // writing target clears o_data - for i in 0..data.len() { + for i in (0..data.len()).rev() { rtio_o_data_write(i, data[i] as _) } let status = csr::rtio::o_status_read(); From 9e66dd70757a7fe9881a4bdd837fa382d59bdabf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Mar 2020 22:23:08 +0800 Subject: [PATCH 2135/2457] soc: reprogrammable identifier --- artiq/build_soc.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/artiq/build_soc.py b/artiq/build_soc.py index 7c1f49e8d..483860d62 100644 --- a/artiq/build_soc.py +++ b/artiq/build_soc.py @@ -1,7 +1,8 @@ import os import subprocess -from misoc.cores import identifier +from migen import * +from misoc.interconnect.csr import * from misoc.integration.builder import * from artiq.gateware.amp import AMPSoC @@ -22,11 +23,39 @@ def get_identifier_string(soc, suffix="", add_class_name=True): return r +class ReprogrammableIdentifier(Module, AutoCSR): + def __init__(self, ident): + self.address = CSRStorage(8) + self.data = CSRStatus(8) + + contents = list(ident.encode()) + l = len(contents) + if l > 255: + raise ValueError("Identifier string must be 255 characters or less") + contents.insert(0, l) + + init_params = {i: 0 for i in range(0x40)} + for i, c in enumerate(contents): + # 0x38 was determined empirically. Another Xilinx mystery. + row = 0x38 + i//32 + col = 8*(i % 32) + init_params[row] |= c << col + init_params = {"p_INIT_{:02X}".format(k): v for k, v in init_params.items()} + + self.specials += Instance("RAMB18E1", name="identifier_str", + i_ADDRARDADDR=Cat(C(0, 3), self.address.storage), + i_CLKARDCLK=ClockSignal(), + o_DOADO=self.data.status, + i_ENARDEN=1, + p_READ_WIDTH_A=9, + **init_params) + + def add_identifier(soc, *args, **kwargs): if hasattr(soc, "identifier"): raise ValueError identifier_str = get_identifier_string(soc, *args, **kwargs) - soc.submodules.identifier = identifier.Identifier(identifier_str) + soc.submodules.identifier = ReprogrammableIdentifier(identifier_str) soc.config["IDENTIFIER_STR"] = identifier_str From 4a8d361acebf1e6b45e9fe35201315798b02d2f3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 12 Mar 2020 23:09:13 +0800 Subject: [PATCH 2136/2457] soc: optimize programmable identifier --- artiq/build_soc.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/artiq/build_soc.py b/artiq/build_soc.py index 483860d62..c5487d8d7 100644 --- a/artiq/build_soc.py +++ b/artiq/build_soc.py @@ -34,21 +34,14 @@ class ReprogrammableIdentifier(Module, AutoCSR): raise ValueError("Identifier string must be 255 characters or less") contents.insert(0, l) - init_params = {i: 0 for i in range(0x40)} - for i, c in enumerate(contents): - # 0x38 was determined empirically. Another Xilinx mystery. - row = 0x38 + i//32 - col = 8*(i % 32) - init_params[row] |= c << col - init_params = {"p_INIT_{:02X}".format(k): v for k, v in init_params.items()} - - self.specials += Instance("RAMB18E1", name="identifier_str", - i_ADDRARDADDR=Cat(C(0, 3), self.address.storage), - i_CLKARDCLK=ClockSignal(), - o_DOADO=self.data.status, - i_ENARDEN=1, - p_READ_WIDTH_A=9, - **init_params) + for i in range(8): + self.specials += Instance("ROM256X1", name="identifier_str"+str(i), + i_A0=self.address.storage[0], i_A1=self.address.storage[1], + i_A2=self.address.storage[2], i_A3=self.address.storage[3], + i_A4=self.address.storage[4], i_A5=self.address.storage[5], + i_A6=self.address.storage[6], i_A7=self.address.storage[7], + o_O=self.data.status[i], + p_INIT=sum(1 << j if c & (1 << i) else 0 for j, c in enumerate(contents))) def add_identifier(soc, *args, **kwargs): From 9294efabc0f39d39646b52954b414077e6ddccb2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 14 Mar 2020 12:19:43 +0800 Subject: [PATCH 2137/2457] manual: Kasli can get MAC address from EEPROM --- doc/manual/installing.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 95235a275..c503a3ec7 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -230,17 +230,19 @@ For Kasli, insert a SFP/RJ45 transceiver (normally included with purchases from You can also insert other types of SFP transceivers into Kasli if you wish to use it directly in e.g. an optical fiber Ethernet network. -If you purchased a device from M-Labs, it already comes with a valid MAC address and an IP address, usually ``192.168.1.75``. Once you can reach this IP, it can be changed with: :: +If you purchased a Kasli device from M-Labs, it usually comes with the IP address ``192.168.1.75``. Once you can reach this IP, it can be changed with: :: $ artiq_coremgmt -D 192.168.1.75 config write -s ip [new IP] and then reboot the device (with ``artiq_flash start`` or a power cycle). -In other cases, install OpenOCD as before, and flash the IP and MAC addresses directly: :: +In other cases, install OpenOCD as before, and flash the IP (and, if necessary, MAC) addresses directly: :: $ artiq_mkfs flash_storage.img -s mac xx:xx:xx:xx:xx:xx -s ip xx.xx.xx.xx $ artiq_flash -t [board] -V [variant] -f flash_storage.img storage start +For Kasli devices, flashing a MAC address is not necessary as they can obtain it from their EEPROM. + Check that you can ping the device. If ping fails, check that the Ethernet link LED is ON - on Kasli, it is the LED next to the SFP0 connector. As a next step, look at the messages emitted on the UART during boot. Use a program such as flterm or PuTTY to connect to the device's serial port at 115200bps 8-N-1 and reboot the device. On Kasli, the serial port is on FTDI channel 2 with v1.1 hardware (with channel 0 being JTAG) and on FTDI channel 1 with v1.0 hardware. If you want to use IPv6, the device also has a link-local address that corresponds to its EUI-64, and an additional arbitrary IPv6 address can be defined by using the ``ip6`` configuration key. All IPv4 and IPv6 addresses can be used at the same time. From 371d9233859f99a509ad74ff2a3153827e1f366a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 4 Apr 2020 13:05:46 +0800 Subject: [PATCH 2138/2457] manual: nixpkgs 20.03 --- doc/manual/installing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index c503a3ec7..302592f1f 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -23,10 +23,10 @@ Once Nix is installed, add the M-Labs package channel with: :: $ nix-channel --add https://nixbld.m-labs.hk/channel/custom/artiq/full-beta/artiq-full -Those channels track `nixpkgs 19.09 `_. You can check the latest status through the `Hydra interface `_. As the Nix package manager default installation uses the development version of nixpkgs, we need to tell it to switch to the release: :: +Those channels track `nixpkgs 20.03 `_. You can check the latest status through the `Hydra interface `_. As the Nix package manager default installation uses the development version of nixpkgs, we need to tell it to switch to the release: :: $ nix-channel --remove nixpkgs - $ nix-channel --add https://nixos.org/channels/nixos-19.09 nixpkgs + $ nix-channel --add https://nixos.org/channels/nixos-20.03 nixpkgs Finally, make all the channel changes effective: :: From 9b03a365edcbb6223bf32ca54c9f6c4b0266710e Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Fri, 3 Apr 2020 16:15:47 +0200 Subject: [PATCH 2139/2457] language/environment: cast argument processor default values early Fixes #1434. Also add unit tests for some argument processors. Signed-off-by: Etienne Wodey --- artiq/language/environment.py | 32 +++++++------- artiq/test/test_arguments.py | 79 +++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 14 deletions(-) create mode 100644 artiq/test/test_arguments.py diff --git a/artiq/language/environment.py b/artiq/language/environment.py index 766779177..eff9fc3f1 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -32,7 +32,7 @@ class _SimpleArgProcessor: if isinstance(default, list): raise NotImplementedError if default is not NoDefault: - self.default_value = default + self.default_value = self.process(default) def default(self): if not hasattr(self, "default_value"): @@ -54,6 +54,7 @@ class PYONValue(_SimpleArgProcessor): def __init__(self, default=NoDefault): # Override the _SimpleArgProcessor init, as list defaults are valid # PYON values + # default stays decoded if default is not NoDefault: self.default_value = default @@ -69,7 +70,13 @@ class PYONValue(_SimpleArgProcessor): class BooleanValue(_SimpleArgProcessor): """A boolean argument.""" - pass + def process(self, x): + if x is True: + return True + elif x is False: + return False + else: + raise ValueError("Invalid BooleanValue value") class EnumerationValue(_SimpleArgProcessor): @@ -80,15 +87,20 @@ class EnumerationValue(_SimpleArgProcessor): argument. """ def __init__(self, choices, default=NoDefault): - _SimpleArgProcessor.__init__(self, default) - assert default is NoDefault or default in choices self.choices = choices + super().__init__(default) + + def process(self, x): + if x not in self.choices: + raise ValueError("Invalid EnumerationValue value") + return x def describe(self): d = _SimpleArgProcessor.describe(self) d["choices"] = self.choices return d + class NumberValue(_SimpleArgProcessor): """An argument that can take a numerical value. @@ -132,8 +144,6 @@ class NumberValue(_SimpleArgProcessor): "the scale manually".format(unit)) if step is None: step = scale/10.0 - if default is not NoDefault: - self.default_value = default self.unit = unit self.scale = scale self.step = step @@ -141,19 +151,13 @@ class NumberValue(_SimpleArgProcessor): self.max = max self.ndecimals = ndecimals + super().__init__(default) + def _is_int(self): return (self.ndecimals == 0 and int(self.step) == self.step and self.scale == 1) - def default(self): - if not hasattr(self, "default_value"): - raise DefaultMissing - if self._is_int(): - return int(self.default_value) - else: - return float(self.default_value) - def process(self, x): if self._is_int(): return int(x) diff --git a/artiq/test/test_arguments.py b/artiq/test/test_arguments.py new file mode 100644 index 000000000..884c8982f --- /dev/null +++ b/artiq/test/test_arguments.py @@ -0,0 +1,79 @@ +import unittest +import numbers + + +from artiq.language.environment import BooleanValue, EnumerationValue, \ + NumberValue, DefaultMissing + + +class NumberValueCase(unittest.TestCase): + def setUp(self): + self.default_value = NumberValue() + self.int_value = NumberValue(42, step=1, ndecimals=0) + self.float_value = NumberValue(42) + + def test_invalid_default(self): + with self.assertRaises(ValueError): + _ = NumberValue("invalid") + + with self.assertRaises(TypeError): + _ = NumberValue(1.+1j) + + def test_no_default(self): + with self.assertRaises(DefaultMissing): + self.default_value.default() + + def test_integer_default(self): + self.assertIsInstance(self.int_value.default(), numbers.Integral) + + def test_default_to_float(self): + self.assertIsInstance(self.float_value.default(), numbers.Real) + self.assertNotIsInstance(self.float_value.default(), numbers.Integral) + + def test_invalid_unit(self): + with self.assertRaises(KeyError): + _ = NumberValue(unit="invalid") + + def test_default_scale(self): + self.assertEqual(self.default_value.scale, 1.) + + +class BooleanValueCase(unittest.TestCase): + def setUp(self): + self.default_value = BooleanValue() + self.true_value = BooleanValue(True) + self.false_value = BooleanValue(False) + + def test_default(self): + self.assertIs(self.true_value.default(), True) + self.assertIs(self.false_value.default(), False) + + def test_no_default(self): + with self.assertRaises(DefaultMissing): + self.default_value.default() + + def test_invalid_default(self): + with self.assertRaises(ValueError): + _ = BooleanValue(1) + + with self.assertRaises(ValueError): + _ = BooleanValue("abc") + + +class EnumerationValueCase(unittest.TestCase): + def setUp(self): + self.default_value = EnumerationValue(["abc"]) + + def test_no_default(self): + with self.assertRaises(DefaultMissing): + self.default_value.default() + + def test_invalid_default(self): + with self.assertRaises(ValueError): + _ = EnumerationValue("abc", "d") + + def test_valid_default(self): + try: + _ = EnumerationValue("abc", "a") + except ValueError: + self.fail("Unexpected ValueError") From 90d08988b26017608959fcb8d65fdca57db4d6e8 Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Fri, 3 Apr 2020 18:19:46 +0200 Subject: [PATCH 2140/2457] language/environment: BooleanValue: fix type detection Signed-off-by: Etienne Wodey --- artiq/language/environment.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/artiq/language/environment.py b/artiq/language/environment.py index eff9fc3f1..fddae667f 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -54,7 +54,6 @@ class PYONValue(_SimpleArgProcessor): def __init__(self, default=NoDefault): # Override the _SimpleArgProcessor init, as list defaults are valid # PYON values - # default stays decoded if default is not NoDefault: self.default_value = default @@ -71,12 +70,9 @@ class PYONValue(_SimpleArgProcessor): class BooleanValue(_SimpleArgProcessor): """A boolean argument.""" def process(self, x): - if x is True: - return True - elif x is False: - return False - else: + if type(x) != bool: raise ValueError("Invalid BooleanValue value") + return x class EnumerationValue(_SimpleArgProcessor): From 8f608fa2fabcf2616ae8370a588bb6977e4036b3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 5 Apr 2020 16:51:40 +0800 Subject: [PATCH 2141/2457] examples/sines_urukul_sayma: adapt for sayma v2, use 1 DAC only --- artiq/examples/kasli_sawgmaster/device_db.py | 20 +++++------------ .../repository/sines_urukul_sayma.py | 22 +++++++++++++++---- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/artiq/examples/kasli_sawgmaster/device_db.py b/artiq/examples/kasli_sawgmaster/device_db.py index 781db5b56..4cba2bbd2 100644 --- a/artiq/examples/kasli_sawgmaster/device_db.py +++ b/artiq/examples/kasli_sawgmaster/device_db.py @@ -25,50 +25,42 @@ device_db = { }, } -for i in range(8): - device_db["ttl" + str(i)] = { - "type": "local", - "module": "artiq.coredevice.ttl", - "class": "TTLInOut" if i < 4 else "TTLOut", - "arguments": {"channel": 1+i}, - } - device_db.update( spi_urukul0={ "type": "local", "module": "artiq.coredevice.spi2", "class": "SPIMaster", - "arguments": {"channel": 9} + "arguments": {"channel": 0} }, ttl_urukul0_io_update={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 10} + "arguments": {"channel": 1} }, ttl_urukul0_sw0={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 11} + "arguments": {"channel": 2} }, ttl_urukul0_sw1={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 12} + "arguments": {"channel": 3} }, ttl_urukul0_sw2={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 13} + "arguments": {"channel": 4} }, ttl_urukul0_sw3={ "type": "local", "module": "artiq.coredevice.ttl", "class": "TTLOut", - "arguments": {"channel": 14} + "arguments": {"channel": 5} }, urukul0_cpld={ "type": "local", diff --git a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py index b0a8f466c..dfd8e46c9 100644 --- a/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py +++ b/artiq/examples/kasli_sawgmaster/repository/sines_urukul_sayma.py @@ -8,9 +8,6 @@ class SinesUrukulSayma(EnvExperiment): # Urukul clock output syntonized to the RTIO clock. # Can be used as HMC830 reference on Sayma RTM. - # The clock output on Sayma AMC cannot be used, as it is derived from - # another Si5324 output than the GTH, and the two Si5324 output dividers - # are not synchronized with each other. # When using this reference, Sayma must be recalibrated every time Urukul # is rebooted, as Urukul is not synchronized to the Kasli. self.urukul_hmc_ref = self.get_device("urukul0_ch3") @@ -19,8 +16,16 @@ class SinesUrukulSayma(EnvExperiment): # When testing sync, do not reboot Urukul, as it is not # synchronized to the Kasli. self.urukul_meas = [self.get_device("urukul0_ch" + str(i)) for i in range(3)] - self.sawgs = [self.get_device("sawg"+str(i)) for i in range(8)] + # The same waveform is output on all first 4 SAWG channels (first DAC). + self.sawgs = [self.get_device("sawg"+str(i)) for i in range(4)] + self.basemod = self.get_device("basemod_att0") + self.rfsws = [self.get_device("sawg_sw"+str(i)) for i in range(4)] + + # DRTIO destinations: + # 0: local + # 1: Sayma AMC + # 2: Sayma RTM @kernel def drtio_is_up(self): for i in range(3): @@ -61,6 +66,15 @@ class SinesUrukulSayma(EnvExperiment): self.core.reset() + delay(10*ms) + self.basemod.reset() + delay(10*ms) + self.basemod.set(3.0, 3.0, 3.0, 3.0) + delay(10*ms) + for rfsw in self.rfsws: + delay(1*ms) + rfsw.on() + for sawg in self.sawgs: delay(1*ms) sawg.reset() From ffd3172e023912867fa3fd6fa64672ecd677fc56 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Apr 2020 00:00:38 +0800 Subject: [PATCH 2142/2457] sayma: move SYSREF DDMTD to RTM (#795) --- artiq/firmware/libboard_artiq/hmc830_7043.rs | 6 +- artiq/firmware/satman/jdac_common.rs | 74 +++++++++++++ artiq/firmware/satman/jdac_requests.rs | 8 -- artiq/firmware/satman/jdcg.rs | 110 ++++++------------- artiq/firmware/satman/main.rs | 21 ++-- artiq/gateware/targets/sayma_amc.py | 6 - artiq/gateware/targets/sayma_rtm.py | 10 ++ 7 files changed, 130 insertions(+), 105 deletions(-) create mode 100644 artiq/firmware/satman/jdac_common.rs delete mode 100644 artiq/firmware/satman/jdac_requests.rs diff --git a/artiq/firmware/libboard_artiq/hmc830_7043.rs b/artiq/firmware/libboard_artiq/hmc830_7043.rs index d5f418a5e..adf753141 100644 --- a/artiq/firmware/libboard_artiq/hmc830_7043.rs +++ b/artiq/firmware/libboard_artiq/hmc830_7043.rs @@ -154,15 +154,15 @@ pub mod hmc7043 { (true, DAC_CLK_DIV, 0x08, false), // 2: DAC0_CLK (true, SYSREF_DIV, 0x01, true), // 3: DAC0_SYSREF (true, SYSREF_DIV, 0x10, true), // 4: AMC_FPGA_SYSREF0 - (true, FPGA_CLK_DIV, 0x10, true), // 5: AMC_FPGA_SYSREF1 + (false, FPGA_CLK_DIV, 0x10, true), // 5: AMC_FPGA_SYSREF1 (false, 0, 0x10, false), // 6: unused - (true, SYSREF_DIV, 0x10, true), // 7: RTM_FPGA_SYSREF0 + (true, FPGA_CLK_DIV, 0x10, true), // 7: RTM_FPGA_SYSREF0 (true, FPGA_CLK_DIV, 0x08, false), // 8: GTP_CLK0_IN (false, 0, 0x10, false), // 9: unused (false, 0, 0x10, false), // 10: unused (false, 0, 0x08, false), // 11: unused / uFL (false, 0, 0x10, false), // 12: unused - (false, SYSREF_DIV, 0x10, true), // 13: RTM_FPGA_SYSREF1 + (false, FPGA_CLK_DIV, 0x10, true), // 13: RTM_FPGA_SYSREF1 ]; fn spi_setup() { diff --git a/artiq/firmware/satman/jdac_common.rs b/artiq/firmware/satman/jdac_common.rs new file mode 100644 index 000000000..3c185516f --- /dev/null +++ b/artiq/firmware/satman/jdac_common.rs @@ -0,0 +1,74 @@ +pub const INIT: u8 = 0x00; +pub const PRINT_STATUS: u8 = 0x01; +pub const PRBS: u8 = 0x02; +pub const STPL: u8 = 0x03; + +pub const SYSREF_DELAY_DAC: u8 = 0x10; +pub const SYSREF_SLIP: u8 = 0x11; +pub const SYNC: u8 = 0x12; + +pub const DDMTD_SYSREF_RAW: u8 = 0x20; +pub const DDMTD_SYSREF: u8 = 0x21; + + +fn average_2phases(a: i32, b: i32, modulo: i32) -> i32 { + let diff = ((a - b + modulo/2 + modulo) % modulo) - modulo/2; + return (modulo + b + diff/2) % modulo; +} + +pub fn average_phases(phases: &[i32], modulo: i32) -> i32 { + if phases.len() == 1 { + panic!("input array length must be a power of 2"); + } else if phases.len() == 2 { + average_2phases(phases[0], phases[1], modulo) + } else { + let cut = phases.len()/2; + average_2phases( + average_phases(&phases[..cut], modulo), + average_phases(&phases[cut..], modulo), + modulo) + } +} + +pub const RAW_DDMTD_N_SHIFT: i32 = 6; +pub const RAW_DDMTD_N: i32 = 1 << RAW_DDMTD_N_SHIFT; +pub const DDMTD_DITHER_BITS: i32 = 1; +pub const DDMTD_N_SHIFT: i32 = RAW_DDMTD_N_SHIFT + DDMTD_DITHER_BITS; +pub const DDMTD_N: i32 = 1 << DDMTD_N_SHIFT; + +#[cfg(has_ad9154)] +use board_misoc::{clock, csr}; + +#[cfg(has_ad9154)] +pub fn init_ddmtd() -> Result<(), &'static str> { + unsafe { + csr::sysref_ddmtd::reset_write(1); + clock::spin_us(1); + csr::sysref_ddmtd::reset_write(0); + clock::spin_us(100); + if csr::sysref_ddmtd::locked_read() != 0 { + Ok(()) + } else { + Err("DDMTD helper PLL failed to lock") + } + } +} + +#[cfg(has_ad9154)] +pub fn measure_ddmdt_phase_raw() -> i32 { + unsafe { csr::sysref_ddmtd::dt_read() as i32 } +} + +#[cfg(has_ad9154)] +pub fn measure_ddmdt_phase() -> i32 { + const AVG_PRECISION_SHIFT: i32 = 6; + const AVG_PRECISION: i32 = 1 << AVG_PRECISION_SHIFT; + const AVG_MOD: i32 = 1 << (RAW_DDMTD_N_SHIFT + AVG_PRECISION_SHIFT + DDMTD_DITHER_BITS); + + let mut measurements = [0; AVG_PRECISION as usize]; + for i in 0..AVG_PRECISION { + measurements[i as usize] = measure_ddmdt_phase_raw() << (AVG_PRECISION_SHIFT + DDMTD_DITHER_BITS); + clock::spin_us(10); + } + average_phases(&measurements, AVG_MOD) >> AVG_PRECISION_SHIFT +} diff --git a/artiq/firmware/satman/jdac_requests.rs b/artiq/firmware/satman/jdac_requests.rs deleted file mode 100644 index 0df8335bd..000000000 --- a/artiq/firmware/satman/jdac_requests.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub const INIT: u8 = 0x00; -pub const PRINT_STATUS: u8 = 0x01; -pub const PRBS: u8 = 0x02; -pub const STPL: u8 = 0x03; - -pub const SYSREF_DELAY_DAC: u8 = 0x10; -pub const SYSREF_SLIP: u8 = 0x11; -pub const SYNC: u8 = 0x12; diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs index ed214f4f4..4f8736fe7 100644 --- a/artiq/firmware/satman/jdcg.rs +++ b/artiq/firmware/satman/jdcg.rs @@ -51,7 +51,7 @@ pub mod jdac { use board_artiq::drtioaux; use super::jesd; - use super::super::jdac_requests; + use super::super::jdac_common; pub fn basic_request(dacno: u8, reqno: u8, param: u8) -> Result { if let Err(e) = drtioaux::send(1, &drtioaux::Packet::JdacBasicRequest { @@ -95,24 +95,24 @@ pub mod jdac { return Err("JESD core PHY not done"); } - basic_request(dacno, jdac_requests::INIT, 0)?; + basic_request(dacno, jdac_common::INIT, 0)?; // JESD ready depends on JSYNC being valid, so DAC init needs to happen first if !jesd::ready(dacno) { error!("JESD core reported not ready, sending DAC status print request"); - basic_request(dacno, jdac_requests::PRINT_STATUS, 0)?; + basic_request(dacno, jdac_common::PRINT_STATUS, 0)?; return Err("JESD core reported not ready"); } jesd::prbs(dacno, true); - basic_request(dacno, jdac_requests::PRBS, 0)?; + basic_request(dacno, jdac_common::PRBS, 0)?; jesd::prbs(dacno, false); jesd::stpl(dacno, true); - basic_request(dacno, jdac_requests::STPL, 0)?; + basic_request(dacno, jdac_common::STPL, 0)?; jesd::stpl(dacno, false); - basic_request(dacno, jdac_requests::INIT, 0)?; + basic_request(dacno, jdac_common::INIT, 0)?; clock::spin_us(5000); if !jesd::jsync(dacno) { @@ -130,7 +130,7 @@ pub mod jesd204sync { use board_misoc::{csr, clock, config}; use super::jdac; - use super::super::jdac_requests; + use super::super::jdac_common; const HMC7043_ANALOG_DELAY_RANGE: u8 = 24; @@ -138,7 +138,7 @@ pub mod jesd204sync { const SYSREF_DIV: u16 = 256; // Keep in sync with hmc830_7043.rs fn hmc7043_sysref_delay_dac(dacno: u8, phase_offset: u8) -> Result<(), &'static str> { - match jdac::basic_request(dacno, jdac_requests::SYSREF_DELAY_DAC, phase_offset) { + match jdac::basic_request(dacno, jdac_common::SYSREF_DELAY_DAC, phase_offset) { Ok(_) => Ok(()), Err(e) => Err(e) } @@ -146,90 +146,43 @@ pub mod jesd204sync { fn hmc7043_sysref_slip() -> Result<(), &'static str> { - match jdac::basic_request(0, jdac_requests::SYSREF_SLIP, 0) { + match jdac::basic_request(0, jdac_common::SYSREF_SLIP, 0) { Ok(_) => Ok(()), Err(e) => Err(e) } } fn ad9154_sync(dacno: u8) -> Result { - match jdac::basic_request(dacno, jdac_requests::SYNC, 0) { + match jdac::basic_request(dacno, jdac_common::SYNC, 0) { Ok(0) => Ok(false), Ok(_) => Ok(true), Err(e) => Err(e) } } - fn average_2phases(a: i32, b: i32, modulo: i32) -> i32 { - let diff = ((a - b + modulo/2 + modulo) % modulo) - modulo/2; - return (modulo + b + diff/2) % modulo; + + fn measure_ddmdt_phase_raw() -> Result { + Ok(jdac::basic_request(0, jdac_common::DDMTD_SYSREF_RAW, 0)? as i32) } - fn average_phases(phases: &[i32], modulo: i32) -> i32 { - if phases.len() == 1 { - panic!("input array length must be a power of 2"); - } else if phases.len() == 2 { - average_2phases(phases[0], phases[1], modulo) - } else { - let cut = phases.len()/2; - average_2phases( - average_phases(&phases[..cut], modulo), - average_phases(&phases[cut..], modulo), - modulo) - } - } - - const RAW_DDMTD_N_SHIFT: i32 = 6; - const RAW_DDMTD_N: i32 = 1 << RAW_DDMTD_N_SHIFT; - const DDMTD_DITHER_BITS: i32 = 1; - const DDMTD_N_SHIFT: i32 = RAW_DDMTD_N_SHIFT + DDMTD_DITHER_BITS; - const DDMTD_N: i32 = 1 << DDMTD_N_SHIFT; - - fn init_ddmtd() -> Result<(), &'static str> { - unsafe { - csr::sysref_ddmtd::reset_write(1); - clock::spin_us(1); - csr::sysref_ddmtd::reset_write(0); - clock::spin_us(100); - if csr::sysref_ddmtd::locked_read() != 0 { - Ok(()) - } else { - Err("DDMTD helper PLL failed to lock") - } - } - } - - fn measure_ddmdt_phase_raw() -> i32 { - unsafe { csr::sysref_ddmtd::dt_read() as i32 } - } - - fn measure_ddmdt_phase() -> i32 { - const AVG_PRECISION_SHIFT: i32 = 6; - const AVG_PRECISION: i32 = 1 << AVG_PRECISION_SHIFT; - const AVG_MOD: i32 = 1 << (RAW_DDMTD_N_SHIFT + AVG_PRECISION_SHIFT + DDMTD_DITHER_BITS); - - let mut measurements = [0; AVG_PRECISION as usize]; - for i in 0..AVG_PRECISION { - measurements[i as usize] = measure_ddmdt_phase_raw() << (AVG_PRECISION_SHIFT + DDMTD_DITHER_BITS); - clock::spin_us(10); - } - average_phases(&measurements, AVG_MOD) >> AVG_PRECISION_SHIFT + fn measure_ddmdt_phase() -> Result { + Ok(jdac::basic_request(0, jdac_common::DDMTD_SYSREF, 0)? as i32) } fn test_ddmtd_stability(raw: bool, tolerance: i32) -> Result<(), &'static str> { info!("testing DDMTD stability (raw={}, tolerance={})...", raw, tolerance); - let modulo = if raw { RAW_DDMTD_N } else { DDMTD_N }; + let modulo = if raw { jdac_common::RAW_DDMTD_N } else { jdac_common::DDMTD_N }; let measurement = if raw { measure_ddmdt_phase_raw } else { measure_ddmdt_phase }; - let ntests = if raw { 15000 } else { 150 }; + let ntests = if raw { 150 } else { 15 }; let mut max_pkpk = 0; for _ in 0..32 { // If we are near the edges, wraparound can throw off the simple min/max computation. // In this case, add an offset to get near the center. - let quadrant = measure_ddmdt_phase(); + let quadrant = measure_ddmdt_phase()?; let center_offset = - if quadrant < DDMTD_N/4 || quadrant > 3*DDMTD_N/4 { + if quadrant < jdac_common::DDMTD_N/4 || quadrant > 3*jdac_common::DDMTD_N/4 { modulo/2 } else { 0 @@ -238,7 +191,7 @@ pub mod jesd204sync { let mut min = modulo; let mut max = 0; for _ in 0..ntests { - let m = (measurement() + center_offset) % modulo; + let m = (measurement()? + center_offset) % modulo; if m < min { min = m; } @@ -268,11 +221,11 @@ pub mod jesd204sync { let tolerance = 1; info!("testing HMC7043 SYSREF slip against DDMTD..."); - let mut old_phase = measure_ddmdt_phase(); + let mut old_phase = measure_ddmdt_phase()?; for _ in 0..1024 { hmc7043_sysref_slip(); - let phase = measure_ddmdt_phase(); - let step = (DDMTD_N + old_phase - phase) % DDMTD_N; + let phase = measure_ddmdt_phase()?; + let step = (jdac_common::DDMTD_N + old_phase - phase) % jdac_common::DDMTD_N; if (step - expected_step).abs() > tolerance { error!(" ...got unexpected step: {} ({} -> {})", step, old_phase, phase); return Err("HMC7043 SYSREF slip produced unexpected DDMTD step"); @@ -295,7 +248,7 @@ pub mod jesd204sync { const SYSREF_SH_PRECISION_SHIFT: i32 = 5; const SYSREF_SH_PRECISION: i32 = 1 << SYSREF_SH_PRECISION_SHIFT; - const SYSREF_SH_MOD: i32 = 1 << (DDMTD_N_SHIFT + SYSREF_SH_PRECISION_SHIFT); + const SYSREF_SH_MOD: i32 = 1 << (jdac_common::DDMTD_N_SHIFT + SYSREF_SH_PRECISION_SHIFT); #[derive(Default)] struct SysrefShLimits { @@ -318,7 +271,7 @@ pub mod jesd204sync { } let current = sysref_sh_error(); - let phase = measure_ddmdt_phase(); + let phase = measure_ddmdt_phase()?; if current && !previous && rising_n < SYSREF_SH_PRECISION { ret.rising_phases[rising_n as usize] = phase << SYSREF_SH_PRECISION_SHIFT; rising_n += 1; @@ -335,7 +288,7 @@ pub mod jesd204sync { fn max_phase_deviation(average: i32, phases: &[i32]) -> i32 { let mut ret = 0; for phase in phases.iter() { - let deviation = (phase - average + DDMTD_N) % DDMTD_N; + let deviation = (phase - average + jdac_common::DDMTD_N) % jdac_common::DDMTD_N; if deviation > ret { ret = deviation; } @@ -345,7 +298,7 @@ pub mod jesd204sync { fn reach_sysref_ddmtd_target(target: i32, tolerance: i32) -> Result { for _ in 0..1024 { - let delta = (measure_ddmdt_phase() - target + DDMTD_N) % DDMTD_N; + let delta = (measure_ddmdt_phase()? - target + jdac_common::DDMTD_N) % jdac_common::DDMTD_N; if delta <= tolerance { return Ok(delta) } @@ -360,11 +313,11 @@ pub mod jesd204sync { if rising_average < falling_average { (rising_average + falling_average)/2 } else { - ((falling_average - (DDMTD_N - rising_average))/2 + DDMTD_N) % DDMTD_N + ((falling_average - (jdac_common::DDMTD_N - rising_average))/2 + jdac_common::DDMTD_N) % jdac_common::DDMTD_N }; info!(" SYSREF calibration coarse target: {}", coarse_target); reach_sysref_ddmtd_target(coarse_target, 8)?; - let target = measure_ddmdt_phase(); + let target = measure_ddmdt_phase()?; info!(" ...done, target={}", target); Ok(target) } @@ -447,15 +400,14 @@ pub mod jesd204sync { } pub fn sysref_auto_rtio_align() -> Result<(), &'static str> { - init_ddmtd()?; test_ddmtd_stability(true, 4)?; test_ddmtd_stability(false, 1)?; test_slip_ddmtd()?; info!("determining SYSREF S/H limits..."); let sysref_sh_limits = measure_sysref_sh_limits()?; - let rising_average = average_phases(&sysref_sh_limits.rising_phases, SYSREF_SH_MOD); - let falling_average = average_phases(&sysref_sh_limits.falling_phases, SYSREF_SH_MOD); + let rising_average = jdac_common::average_phases(&sysref_sh_limits.rising_phases, SYSREF_SH_MOD); + let falling_average = jdac_common::average_phases(&sysref_sh_limits.falling_phases, SYSREF_SH_MOD); let rising_max_deviation = max_phase_deviation(rising_average, &sysref_sh_limits.rising_phases); let falling_max_deviation = max_phase_deviation(falling_average, &sysref_sh_limits.falling_phases); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 3b5096fd8..12d80c2d0 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -22,7 +22,7 @@ mod repeater; #[cfg(has_jdcg)] mod jdcg; #[cfg(any(has_ad9154, has_jdcg))] -pub mod jdac_requests; +pub mod jdac_common; fn drtiosat_reset(reset: bool) { unsafe { @@ -306,13 +306,13 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], #[cfg(rtio_frequency = "150.0")] const LINERATE: u64 = 6_000_000_000; match _reqno { - jdac_requests::INIT => (board_artiq::ad9154::setup(_dacno, LINERATE).is_ok(), 0), - jdac_requests::PRINT_STATUS => { board_artiq::ad9154::status(_dacno); (true, 0) }, - jdac_requests::PRBS => (board_artiq::ad9154::prbs(_dacno).is_ok(), 0), - jdac_requests::STPL => (board_artiq::ad9154::stpl(_dacno, 4, 2).is_ok(), 0), - jdac_requests::SYSREF_DELAY_DAC => { board_artiq::hmc830_7043::hmc7043::sysref_delay_dac(_dacno, _param); (true, 0) }, - jdac_requests::SYSREF_SLIP => { board_artiq::hmc830_7043::hmc7043::sysref_slip(); (true, 0) }, - jdac_requests::SYNC => { + jdac_common::INIT => (board_artiq::ad9154::setup(_dacno, LINERATE).is_ok(), 0), + jdac_common::PRINT_STATUS => { board_artiq::ad9154::status(_dacno); (true, 0) }, + jdac_common::PRBS => (board_artiq::ad9154::prbs(_dacno).is_ok(), 0), + jdac_common::STPL => (board_artiq::ad9154::stpl(_dacno, 4, 2).is_ok(), 0), + jdac_common::SYSREF_DELAY_DAC => { board_artiq::hmc830_7043::hmc7043::sysref_delay_dac(_dacno, _param); (true, 0) }, + jdac_common::SYSREF_SLIP => { board_artiq::hmc830_7043::hmc7043::sysref_slip(); (true, 0) }, + jdac_common::SYNC => { match board_artiq::ad9154::sync(_dacno) { Ok(false) => (true, 0), Ok(true) => (true, 1), @@ -321,7 +321,9 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater], (false, 0) } } - } + }, + jdac_common::DDMTD_SYSREF_RAW => (true, jdac_common::measure_ddmdt_phase_raw() as u8), + jdac_common::DDMTD_SYSREF => (true, jdac_common::measure_ddmdt_phase() as u8), _ => (false, 0) } }; @@ -472,6 +474,7 @@ pub extern fn main() -> i32 { hmc830_7043::init().expect("cannot initialize HMC830/7043"); #[cfg(has_ad9154)] { + jdac_common::init_ddmtd().expect("failed to initialize SYSREF DDMTD core"); for dacno in 0..csr::CONFIG_AD9154_COUNT { board_artiq::ad9154::reset_and_detect(dacno as u8).expect("AD9154 DAC not detected"); } diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 18e6f70e0..a676c9219 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -311,12 +311,6 @@ class Satellite(SatelliteBase): self.jdcg_0.jesd.core.register_jref(self.sysref_sampler.jref) self.jdcg_1.jesd.core.register_jref(self.sysref_sampler.jref) - # DDMTD - # https://github.com/sinara-hw/Sayma_RTM/issues/68 - sysref_pads = platform.request("amc_fpga_sysref", 1) - self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(sysref_pads, self.rtio_clk_freq) - self.csr_devices.append("sysref_ddmtd") - class SimpleSatellite(SatelliteBase): def __init__(self, **kwargs): diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 9864563d1..777495aa6 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -16,6 +16,7 @@ from misoc.targets.sayma_rtm import BaseSoC, soc_sayma_rtm_args, soc_sayma_rtm_a from misoc.integration.builder import Builder, builder_args, builder_argdict from artiq.gateware import rtio +from artiq.gateware import jesd204_tools from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series @@ -257,6 +258,15 @@ class Satellite(_SatelliteBase): platform.request("hmc7043_out_en")) self.csr_devices.append("hmc7043_out_en") + # DDMTD + sysref_pads = platform.request("rtm_fpga_sysref", 0) + self.submodules.sysref_ddmtd = jesd204_tools.DDMTD(sysref_pads, self.rtio_clk_freq) + self.csr_devices.append("sysref_ddmtd") + platform.add_false_path_constraints( + self.sysref_ddmtd.cd_helper.clk, self.drtio_transceiver.gtps[0].txoutclk) + platform.add_false_path_constraints( + self.sysref_ddmtd.cd_helper.clk, self.crg.cd_sys.clk) + class SatmanSoCBuilder(Builder): def __init__(self, *args, **kwargs): From facc0357d89f6c3c48ac4eb4f7c0767a82f4d570 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Apr 2020 22:33:15 +0800 Subject: [PATCH 2143/2457] drtio: make sure receive buffer is drained after ping reply --- artiq/firmware/runtime/rtio_mgt.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 10ac429c6..825900b78 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -68,7 +68,17 @@ pub mod drtio { } let reply = aux_transact(io, aux_mutex, linkno, &drtioaux::Packet::EchoRequest); match reply { - Ok(drtioaux::Packet::EchoReply) => return count, + Ok(drtioaux::Packet::EchoReply) => { + // make sure receive buffer is drained + let max_time = clock::get_ms() + 200; + loop { + if clock::get_ms() > max_time { + return count; + } + let _ = drtioaux::recv(linkno); + io.relinquish().unwrap(); + } + } _ => {} } io.relinquish().unwrap(); From 61d4614b611014513a5891c8fb1e994f5a71a973 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Apr 2020 22:34:05 +0800 Subject: [PATCH 2144/2457] sayma: fix/cleanup DRTIO-DAC sync interaction --- artiq/firmware/runtime/rtio_clocking.rs | 6 +- artiq/firmware/satman/jdcg.rs | 9 ++- artiq/firmware/satman/main.rs | 65 +++++++++++-------- artiq/gateware/drtio/core.py | 1 + .../drtio/transceiver/gth_ultrascale.py | 6 +- .../gateware/drtio/transceiver/gtp_7series.py | 10 ++- 6 files changed, 63 insertions(+), 34 deletions(-) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index 99a47fe3f..9a36326f4 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -2,7 +2,7 @@ use board_misoc::config; #[cfg(si5324_as_synthesizer)] use board_artiq::si5324; #[cfg(has_drtio)] -use board_misoc::csr; +use board_misoc::{csr, clock}; #[derive(Debug)] pub enum RtioClock { @@ -161,6 +161,10 @@ pub fn init() { unsafe { csr::drtio_transceiver::stable_clkin_write(1); } + clock::spin_us(1500); // wait for CPLL/QPLL lock + unsafe { + csr::drtio_transceiver::txenable_write(0xffffffffu32 as _); + } #[cfg(has_rtio_crg)] { diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs index 4f8736fe7..a497ce505 100644 --- a/artiq/firmware/satman/jdcg.rs +++ b/artiq/firmware/satman/jdcg.rs @@ -160,7 +160,6 @@ pub mod jesd204sync { } } - fn measure_ddmdt_phase_raw() -> Result { Ok(jdac::basic_request(0, jdac_common::DDMTD_SYSREF_RAW, 0)? as i32) } @@ -567,4 +566,12 @@ pub mod jesd204sync { error!("failed to align SYSREF at DAC: {}", e); } } + + pub fn resync_dacs() -> Result<(), &'static str> { + info!("resychronizing DACs"); + for dacno in 0..csr::JDCG.len() { + ad9154_sync(dacno as u8)?; + } + Ok(()) + } } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 12d80c2d0..8a07db183 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -465,6 +465,10 @@ pub extern fn main() -> i32 { csr::drtio_transceiver::stable_clkin_write(1); } clock::spin_us(1500); // wait for CPLL/QPLL lock + #[cfg(not(has_jdcg))] + unsafe { + csr::drtio_transceiver::txenable_write(0xffffffffu32 as _); + } #[cfg(has_wrpll)] wrpll::diagnostics(); init_rtio_crg(); @@ -493,6 +497,11 @@ pub extern fn main() -> i32 { let mut hardware_tick_ts = 0; loop { + #[cfg(has_jdcg)] + unsafe { + // Hide from uplink until RTM is ready + csr::drtio_transceiver::txenable_write(0xfffffffeu32 as _); + } while !drtiosat_link_rx_up() { drtiosat_process_errors(); for mut rep in repeaters.iter_mut() { @@ -510,33 +519,12 @@ pub extern fn main() -> i32 { #[cfg(has_wrpll)] wrpll::select_recovered_clock(true); - #[cfg(has_jdcg)] - { - /* - * One side of the JESD204 elastic buffer is clocked by the Si5324, the other - * by the RTM. - * The elastic buffer can operate only when those two clocks are derived from - * the same oscillator. - * This is the case when either of those conditions is true: - * (1) The DRTIO master and the RTM are clocked directly from a common external - * source, *and* the Si5324 has locked to the recovered clock. - * This clocking scheme provides less noise and phase drift at the DACs. - * (2) The RTM clock is connected to the Si5324 output. - * To handle those cases, we simply keep the JESD204 core in reset unless the - * Si5324 is locked to the recovered clock. - */ - jdcg::jesd::reset(false); - if repeaters[0].is_up() { - let _ = jdcg::jdac::init(); - } - } - drtioaux::reset(0); drtiosat_reset(false); drtiosat_reset_phy(false); #[cfg(has_jdcg)] - let mut rep0_was_up = repeaters[0].is_up(); + let mut was_up = false; while drtiosat_link_rx_up() { drtiosat_process_errors(); process_aux_packets(&mut repeaters, &mut routing_table, &mut rank); @@ -548,8 +536,14 @@ pub extern fn main() -> i32 { info!("TSC loaded from uplink"); #[cfg(has_jdcg)] { - if rep0_was_up { - jdcg::jesd204sync::sysref_auto_align(); + // We assume that the RTM on repeater0 is up. + // Uplink should not send a TSC load command unless the link is + // up, and we are hiding when the RTM is down. + if let Err(e) = jdcg::jesd204sync::sysref_rtio_align() { + error!("failed to align SYSREF with TSC ({})", e); + } + if let Err(e) = jdcg::jesd204sync::resync_dacs() { + error!("DAC resync failed after SYSREF/TSC realignment ({})", e); } } for rep in repeaters.iter() { @@ -563,12 +557,29 @@ pub extern fn main() -> i32 { } #[cfg(has_jdcg)] { - let rep0_is_up = repeaters[0].is_up(); - if rep0_is_up && !rep0_was_up { + let is_up = repeaters[0].is_up(); + if is_up && !was_up { + /* + * One side of the JESD204 elastic buffer is clocked by the jitter filter + * (Si5324 or WRPLL), the other by the RTM. + * The elastic buffer can operate only when those two clocks are derived from + * the same oscillator. + * This is the case when either of those conditions is true: + * (1) The DRTIO master and the RTM are clocked directly from a common external + * source, *and* the jitter filter has locked to the recovered clock. + * This clocking scheme may provide less noise and phase drift at the DACs. + * (2) The RTM clock is connected to the jitter filter output. + * To handle those cases, we simply keep the JESD204 core in reset unless the + * jitter filter is locked to the recovered clock. + */ + jdcg::jesd::reset(false); let _ = jdcg::jdac::init(); jdcg::jesd204sync::sysref_auto_align(); + unsafe { + csr::drtio_transceiver::txenable_write(0xffffffffu32 as _); // unhide + } } - rep0_was_up = rep0_is_up; + was_up = is_up; } } diff --git a/artiq/gateware/drtio/core.py b/artiq/gateware/drtio/core.py index 55176b1ce..6311456e4 100644 --- a/artiq/gateware/drtio/core.py +++ b/artiq/gateware/drtio/core.py @@ -30,6 +30,7 @@ class ChannelInterface: class TransceiverInterface(AutoCSR): def __init__(self, channel_interfaces): self.stable_clkin = CSRStorage() + self.txenable = CSRStorage(len(channel_interfaces)) self.clock_domains.cd_rtio = ClockDomain() for i in range(len(channel_interfaces)): name = "rtio_rx" + str(i) diff --git a/artiq/gateware/drtio/transceiver/gth_ultrascale.py b/artiq/gateware/drtio/transceiver/gth_ultrascale.py index ea7f908f5..ddc88037a 100644 --- a/artiq/gateware/drtio/transceiver/gth_ultrascale.py +++ b/artiq/gateware/drtio/transceiver/gth_ultrascale.py @@ -29,6 +29,7 @@ class GTHSingle(Module): # # # + self.txenable = Signal() nwords = dw//10 self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( Encoder(nwords, True)) @@ -467,7 +468,6 @@ class GTHSingle(Module): i_GTREFCLK0=refclk, # TX clock - o_TXOUTCLK=self.txoutclk, i_TXSYSCLKSEL=0b00, i_TXPLLCLKSEL=0b00, @@ -487,7 +487,7 @@ class GTHSingle(Module): o_TXSYNCOUT=self.txsyncout, # TX data - + i_TXINHIBIT=~self.txenable, i_TXCTRL0=Cat(*[txdata[10*i+8] for i in range(nwords)]), i_TXCTRL1=Cat(*[txdata[10*i+9] for i in range(nwords)]), i_TXDATA=Cat(*[txdata[10*i:10*i+8] for i in range(nwords)]), @@ -675,6 +675,8 @@ class GTH(Module, TransceiverInterface): self.submodules.tx_phase_alignment = GTHTXPhaseAlignement(self.gths) TransceiverInterface.__init__(self, channel_interfaces) + for n, gth in enumerate(self.gths): + self.comb += gth.txenable.eq(self.txenable.storage[n]) self.clock_domains.cd_rtiox = ClockDomain(reset_less=True) if create_buf: # GTH PLLs recover on their own from an interrupted clock input, diff --git a/artiq/gateware/drtio/transceiver/gtp_7series.py b/artiq/gateware/drtio/transceiver/gtp_7series.py index 98360ca2d..5da42b22b 100644 --- a/artiq/gateware/drtio/transceiver/gtp_7series.py +++ b/artiq/gateware/drtio/transceiver/gtp_7series.py @@ -19,6 +19,7 @@ class GTPSingle(Module): # # # self.stable_clkin = Signal() + self.txenable = Signal() self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( Encoder(2, True)) self.submodules.decoders = decoders = [ClockDomainsRenamer("rtio_rx")( @@ -611,7 +612,7 @@ class GTPSingle(Module): i_TXDEEMPH =0, i_TXDIFFCTRL =0b1000, i_TXDIFFPD =0, - i_TXINHIBIT =0, + i_TXINHIBIT =~self.txenable, i_TXMAINCURSOR =0b0000000, i_TXPISOPD =0, # Transmit Ports - TX Fabric Clock Output Control Ports @@ -747,8 +748,11 @@ class GTP(Module, TransceiverInterface): self.submodules.tx_phase_alignment = GTPTXPhaseAlignement(self.gtps) TransceiverInterface.__init__(self, channel_interfaces) - for gtp in self.gtps: - self.comb += gtp.stable_clkin.eq(self.stable_clkin.storage) + for n, gtp in enumerate(self.gtps): + self.comb += [ + gtp.stable_clkin.eq(self.stable_clkin.storage), + gtp.txenable.eq(self.txenable.storage[n]) + ] self.comb += [ self.cd_rtio.clk.eq(self.gtps[master].cd_rtio_tx.clk), From 4d601c2102afab368ed2cd99080efd0aa9d5cc69 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Apr 2020 22:36:03 +0800 Subject: [PATCH 2145/2457] sayma: improve DAC sync messaging --- artiq/firmware/satman/jdcg.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs index a497ce505..ee61aecbc 100644 --- a/artiq/firmware/satman/jdcg.rs +++ b/artiq/firmware/satman/jdcg.rs @@ -527,6 +527,7 @@ pub mod jesd204sync { info!(" ...done"); // We tested that the value is correct - now use it + info!("sychronizing DAC-{}", dacno); hmc7043_sysref_delay_dac(dacno, delay); ad9154_sync(dacno)?; From 3c823a483afb7bde958519ce3f71b973d908dc4a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 6 Apr 2020 22:36:43 +0800 Subject: [PATCH 2146/2457] sayma: improve DAC sync messaging (again) --- artiq/firmware/satman/jdcg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs index ee61aecbc..98d546a79 100644 --- a/artiq/firmware/satman/jdcg.rs +++ b/artiq/firmware/satman/jdcg.rs @@ -569,8 +569,8 @@ pub mod jesd204sync { } pub fn resync_dacs() -> Result<(), &'static str> { - info!("resychronizing DACs"); for dacno in 0..csr::JDCG.len() { + info!("resychronizing DAC-{}", dacno); ad9154_sync(dacno as u8)?; } Ok(()) From 0f4be22274ff4c558e8599916abd319f386fae77 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 7 Apr 2020 21:17:04 +0800 Subject: [PATCH 2147/2457] sayma: add simple sychronized DDS for testing --- artiq/gateware/targets/sayma_amc.py | 78 +++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 15 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index a676c9219..e469f722f 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -190,20 +190,19 @@ class SatelliteBase(MiniSoC): # JESD204 DAC Channel Group -class JDCG(Module, AutoCSR): +class JDCGSAWG(Module, AutoCSR): def __init__(self, platform, sys_crg, jesd_crg, dac): self.submodules.jesd = jesd204_tools.UltrascaleTX( platform, sys_crg, jesd_crg, dac) - self.sawgs = [sawg.Channel(width=16, parallelism=4) for i in range(4)] - self.submodules += self.sawgs + self.submodules.sawgs = [sawg.Channel(width=16, parallelism=4) for i in range(4)] for conv, ch in zip(self.jesd.core.sink.flatten(), self.sawgs): assert len(Cat(ch.o)) == len(conv) self.sync.jesd += conv.eq(Cat(ch.o)) -class JDCGNoSAWG(Module, AutoCSR): +class JDCGPattern(Module, AutoCSR): def __init__(self, platform, sys_crg, jesd_crg, dac): self.submodules.jesd = jesd204_tools.UltrascaleTX( platform, sys_crg, jesd_crg, dac) @@ -243,13 +242,56 @@ class JDCGNoSAWG(Module, AutoCSR): ] +class JDCGSyncDDS(Module, AutoCSR): + def __init__(self, platform, sys_crg, jesd_crg, dac): + self.submodules.jesd = jesd204_tools.UltrascaleTX( + platform, sys_crg, jesd_crg, dac) + self.coarse_ts = Signal(32) + + self.sawgs = [] + + ftw = round(2**len(self.coarse_ts)*9e6/150e6) + parallelism = 4 + + mul_1 = Signal.like(self.coarse_ts) + mul_2 = Signal.like(self.coarse_ts) + mul_3 = Signal.like(self.coarse_ts) + self.sync.rtio += [ + mul_1.eq(self.coarse_ts*ftw), + mul_2.eq(mul_1), + mul_3.eq(mul_2) + ] + + phases = [Signal.like(self.coarse_ts) for i in range(parallelism)] + self.sync.rtio += [phases[i].eq(mul_3 + i*ftw//parallelism) + for i in range(parallelism)] + + resolution = 10 + steps = 2**resolution + from math import pi, cos + data = [(2**16 + round(cos(i/steps*2*pi)*((1 << 15) - 1))) & 0xffff + for i in range(steps)] + samples = [Signal(16) for i in range(4)] + for phase, sample in zip(phases, samples): + table = Memory(16, steps, init=data) + table_port = table.get_port(clock_domain="rtio") + self.specials += table, table_port + self.comb += [ + table_port.adr.eq(phase >> (len(self.coarse_ts) - resolution)), + sample.eq(table_port.dat_r) + ] + + self.sync.rtio += [sink.eq(Cat(samples)) + for sink in self.jesd.core.sink.flatten()] + + class Satellite(SatelliteBase): """ DRTIO satellite with local DAC/SAWG channels. """ - def __init__(self, with_sawg, **kwargs): + def __init__(self, jdcg_type, **kwargs): SatelliteBase.__init__(self, 150e6, - identifier_suffix=".without-sawg" if not with_sawg else "", + identifier_suffix="." + jdcg_type, **kwargs) platform = self.platform @@ -286,10 +328,11 @@ class Satellite(SatelliteBase): self.submodules.jesd_crg = jesd204_tools.UltrascaleCRG( platform, use_rtio_clock=True) - if with_sawg: - cls = JDCG - else: - cls = JDCGNoSAWG + cls = { + "sawg": JDCGSAWG, + "pattern": JDCGPattern, + "syncdds": JDCGSyncDDS + }[jdcg_type] self.submodules.jdcg_0 = cls(platform, self.crg, self.jesd_crg, 0) self.submodules.jdcg_1 = cls(platform, self.crg, self.jesd_crg, 1) self.csr_devices.append("jesd_crg") @@ -310,6 +353,11 @@ class Satellite(SatelliteBase): self.csr_devices.append("sysref_sampler") self.jdcg_0.jesd.core.register_jref(self.sysref_sampler.jref) self.jdcg_1.jesd.core.register_jref(self.sysref_sampler.jref) + if jdcg_type == "syncdds": + self.comb += [ + self.jdcg_0.coarse_ts.eq(self.rtio_tsc.coarse_ts), + self.jdcg_1.coarse_ts.eq(self.rtio_tsc.coarse_ts), + ] class SimpleSatellite(SatelliteBase): @@ -506,16 +554,16 @@ def main(): parser.add_argument("--rtm-csr-csv", default=os.path.join("artiq_sayma", "rtm_gateware", "rtm_csr.csv"), help="CSV file listing remote CSRs on RTM (default: %(default)s)") - parser.add_argument("--without-sawg", - default=False, action="store_true", - help="Remove SAWG RTIO channels feeding the JESD links (speeds up " - "compilation time). Replaces them with fixed pattern generators.") + parser.add_argument("--jdcg-type", + default="sawg", + help="Change type of signal generator. This is used exclusively for " + "development and debugging.") parser.add_argument("--with-wrpll", default=False, action="store_true") args = parser.parse_args() variant = args.variant.lower() if variant == "satellite": - soc = Satellite(with_sawg=not args.without_sawg, with_wrpll=args.with_wrpll, + soc = Satellite(jdcg_type=args.jdcg_type, with_wrpll=args.with_wrpll, **soc_sayma_amc_argdict(args)) elif variant == "simplesatellite": soc = SimpleSatellite(with_wrpll=args.with_wrpll, **soc_sayma_amc_argdict(args)) From ec7b2bea12e505a6ffe9c713422c96d55266ca78 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 8 Apr 2020 15:00:33 +0800 Subject: [PATCH 2148/2457] sayma: round FTW like Urukul in JDCGSyncDDS --- artiq/gateware/targets/sayma_amc.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index e469f722f..decc61640 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -250,21 +250,20 @@ class JDCGSyncDDS(Module, AutoCSR): self.sawgs = [] - ftw = round(2**len(self.coarse_ts)*9e6/150e6) + ftw = round(2**len(self.coarse_ts)*9e6/600e6) parallelism = 4 mul_1 = Signal.like(self.coarse_ts) mul_2 = Signal.like(self.coarse_ts) mul_3 = Signal.like(self.coarse_ts) self.sync.rtio += [ - mul_1.eq(self.coarse_ts*ftw), + mul_1.eq(self.coarse_ts*ftw*parallelism), mul_2.eq(mul_1), mul_3.eq(mul_2) ] phases = [Signal.like(self.coarse_ts) for i in range(parallelism)] - self.sync.rtio += [phases[i].eq(mul_3 + i*ftw//parallelism) - for i in range(parallelism)] + self.sync.rtio += [phases[i].eq(mul_3 + i*ftw) for i in range(parallelism)] resolution = 10 steps = 2**resolution From fb0ade77a90b0731d4e57d1e3bf771010c9e6327 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 10 Apr 2020 17:23:17 +0800 Subject: [PATCH 2149/2457] firmware: fix non-DRTIO build --- artiq/firmware/runtime/rtio_clocking.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index 9a36326f4..0a41ab8d0 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -158,12 +158,14 @@ pub fn init() { } #[cfg(has_drtio)] - unsafe { - csr::drtio_transceiver::stable_clkin_write(1); - } - clock::spin_us(1500); // wait for CPLL/QPLL lock - unsafe { - csr::drtio_transceiver::txenable_write(0xffffffffu32 as _); + { + unsafe { + csr::drtio_transceiver::stable_clkin_write(1); + } + clock::spin_us(1500); // wait for CPLL/QPLL lock + unsafe { + csr::drtio_transceiver::txenable_write(0xffffffffu32 as _); + } } #[cfg(has_rtio_crg)] From 9dc24f255e95b38c9a85e866397620e19f7a6c24 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 12 Apr 2020 15:06:46 +0800 Subject: [PATCH 2150/2457] comm_kernel: remove dead code --- artiq/coredevice/comm_kernel.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index a4782318c..e74dcb7b9 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -207,10 +207,6 @@ class CommKernel: # # Exported APIs # - - def reset_session(self): - self.write(struct.pack(">ll", 0x5a5a5a5a, 0)) - def check_system_info(self): self._write_empty(Request.SystemInfo) From de57039e6e001f19f3904ac1f360ee2e7ef76f5d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 12 Apr 2020 16:02:36 +0800 Subject: [PATCH 2151/2457] comm_kernel: cleanup --- artiq/coredevice/comm_kernel.py | 52 ++++++++++++++++----------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index e74dcb7b9..e17bb3298 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -92,7 +92,11 @@ class CommKernel: del self.socket logger.debug("disconnected") - def read(self, length): + # + # Reader interface + # + + def _read(self, length): r = bytes() while len(r) < length: rn = self.socket.recv(min(8192, length - len(r))) @@ -101,27 +105,20 @@ class CommKernel: r += rn return r - def write(self, data): - self.socket.sendall(data) - - # - # Reader interface - # - def _read_header(self): self.open() # Wait for a synchronization sequence, 5a 5a 5a 5a. sync_count = 0 while sync_count < 4: - (sync_byte, ) = struct.unpack("B", self.read(1)) + (sync_byte, ) = struct.unpack("B", self._read(1)) if sync_byte == 0x5a: sync_count += 1 else: sync_count = 0 # Read message header. - (raw_type, ) = struct.unpack("B", self.read(1)) + (raw_type, ) = struct.unpack("B", self._read(1)) self._read_type = Reply(raw_type) logger.debug("receiving message: type=%r", @@ -136,30 +133,27 @@ class CommKernel: self._read_header() self._read_expect(ty) - def _read_chunk(self, length): - return self.read(length) - def _read_int8(self): - (value, ) = struct.unpack("B", self._read_chunk(1)) + (value, ) = struct.unpack("B", self._read(1)) return value def _read_int32(self): - (value, ) = struct.unpack(">l", self._read_chunk(4)) + (value, ) = struct.unpack(">l", self._read(4)) return value def _read_int64(self): - (value, ) = struct.unpack(">q", self._read_chunk(8)) + (value, ) = struct.unpack(">q", self._read(8)) return value def _read_float64(self): - (value, ) = struct.unpack(">d", self._read_chunk(8)) + (value, ) = struct.unpack(">d", self._read(8)) return value def _read_bool(self): return True if self._read_int8() else False def _read_bytes(self): - return self._read_chunk(self._read_int32()) + return self._read(self._read_int32()) def _read_string(self): return self._read_bytes().decode("utf-8") @@ -168,38 +162,41 @@ class CommKernel: # Writer interface # + def _write(self, data): + self.socket.sendall(data) + def _write_header(self, ty): self.open() logger.debug("sending message: type=%r", ty) # Write synchronization sequence and header. - self.write(struct.pack(">lB", 0x5a5a5a5a, ty.value)) + self._write(struct.pack(">lB", 0x5a5a5a5a, ty.value)) def _write_empty(self, ty): self._write_header(ty) def _write_chunk(self, chunk): - self.write(chunk) + self._write(chunk) def _write_int8(self, value): - self.write(struct.pack("B", value)) + self._write(struct.pack("B", value)) def _write_int32(self, value): - self.write(struct.pack(">l", value)) + self._write(struct.pack(">l", value)) def _write_int64(self, value): - self.write(struct.pack(">q", value)) + self._write(struct.pack(">q", value)) def _write_float64(self, value): - self.write(struct.pack(">d", value)) + self._write(struct.pack(">d", value)) def _write_bool(self, value): - self.write(struct.pack("B", value)) + self._write(struct.pack("B", value)) def _write_bytes(self, value): self._write_int32(len(value)) - self.write(value) + self._write(value) def _write_string(self, value): self._write_bytes(value.encode("utf-8")) @@ -207,12 +204,13 @@ class CommKernel: # # Exported APIs # + def check_system_info(self): self._write_empty(Request.SystemInfo) self._read_header() self._read_expect(Reply.SystemInfo) - runtime_id = self._read_chunk(4) + runtime_id = self._read(4) if runtime_id != b"AROR": raise UnsupportedDevice("Unsupported runtime ID: {}" .format(runtime_id)) From e8b73876ab60e202bec0a2e5119bd7b740d0c78d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 12 Apr 2020 17:25:14 +0800 Subject: [PATCH 2152/2457] comm_kernel: add Zynq runtime identifier --- artiq/coredevice/comm_kernel.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index e17bb3298..d3a73c20e 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -211,21 +211,23 @@ class CommKernel: self._read_header() self._read_expect(Reply.SystemInfo) runtime_id = self._read(4) - if runtime_id != b"AROR": + if runtime_id == b"AROR": + gateware_version = self._read_string().split(";")[0] + if gateware_version != software_version and not self.warned_of_mismatch: + logger.warning("Mismatch between gateware (%s) " + "and software (%s) versions", + gateware_version, software_version) + CommKernel.warned_of_mismatch = True + + finished_cleanly = self._read_bool() + if not finished_cleanly: + logger.warning("Previous kernel did not cleanly finish") + elif runtime_id == b"ARZQ": + pass + else: raise UnsupportedDevice("Unsupported runtime ID: {}" .format(runtime_id)) - gateware_version = self._read_string().split(";")[0] - if gateware_version != software_version and not self.warned_of_mismatch: - logger.warning("Mismatch between gateware (%s) " - "and software (%s) versions", - gateware_version, software_version) - CommKernel.warned_of_mismatch = True - - finished_cleanly = self._read_bool() - if not finished_cleanly: - logger.warning("Previous kernel did not cleanly finish") - def load(self, kernel_library): self._write_header(Request.LoadKernel) self._write_bytes(kernel_library) From ea79ba4622859e72556e1efa161aa700a35f479a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sat, 29 Feb 2020 18:19:27 +0100 Subject: [PATCH 2153/2457] ttl_serdes: detect edges on short pulses Edges on pulses shorter than the RTIO period were missed because the reference sample and the last sample of the serdes word are the same. This change enables detection of edges on pulses as short as the serdes UI (and shorter as long as the pulse still hits a serdes sample aperture). In any RTIO period, only the leading event corresponding to the first edge with slope according to sensitivity is registerd. If the channel is sensitive to both rising and falling edges and if the pulse is contained within an RTIO period, or if it is sensitive only to one edge slope and there are multiple pulses in an RTIO period, only the leading event is seen. Thus this possibility of lost events is still there. Only the conditions under which loss occurs are reduced. In testing with the kasli-ptb6 variant, this also improves resource usage (a couple hundred LUT) and timing (0.1 ns WNS). --- RELEASE_NOTES.rst | 4 ++++ artiq/gateware/rtio/phy/ttl_serdes_generic.py | 21 ++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index c6ff3f579..79683c13a 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -8,6 +8,10 @@ ARTIQ-6 Highlights: +* Performance improvements: + - #1432: SERDES TTL inputs can now detect edges on pulses that are shorter + than the RTIO period + Breaking changes: diff --git a/artiq/gateware/rtio/phy/ttl_serdes_generic.py b/artiq/gateware/rtio/phy/ttl_serdes_generic.py index 5e03297fa..5c8456d93 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_generic.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_generic.py @@ -7,7 +7,7 @@ from artiq.gateware.rtio import rtlink def _mk_edges(w, direction): l = [(1 << i) - 1 for i in range(w)] if direction == "rising": - l = [2**w - 1 ^ x for x in l] + l = [((1 << w) - 1) ^ x for x in l] elif direction == "falling": pass else: @@ -69,8 +69,8 @@ class InOut(Module): # Output enable, for interfacing to external buffers. self.oe = Signal() - # LSB of the input state (for edge detection; arbitrary choice, support for - # short pulses will need a more involved solution). + # input state exposed for edge_counter: latest serdes sample + # support for short pulses will need a more involved solution self.input_state = Signal() # # # @@ -112,15 +112,16 @@ class InOut(Module): i_d = Signal() self.sync.rio_phy += [ i_d.eq(i), - self.rtlink.i.stb.eq( - sample | - (sensitivity[0] & ( i & ~i_d)) | - (sensitivity[1] & (~i & i_d)) - ), self.rtlink.i.data.eq(i), ] pe = PriorityEncoder(serdes_width) self.submodules += pe - self.comb += pe.i.eq(serdes.i ^ Replicate(i_d, serdes_width)) - self.sync.rio_phy += self.rtlink.i.fine_ts.eq(pe.o) + self.comb += pe.i.eq( + (serdes.i ^ Cat(i_d, serdes.i)) & ( + (serdes.i & Replicate(sensitivity[0], serdes_width)) | + (~serdes.i & Replicate(sensitivity[1], serdes_width)))) + self.sync.rio_phy += [ + self.rtlink.i.fine_ts.eq(pe.o), + self.rtlink.i.stb.eq(sample | ~pe.n), + ] From 77e6fdb7a7fe439dcda36adbbe64f4c5cd304b88 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 14 Apr 2020 18:22:06 +0800 Subject: [PATCH 2154/2457] artiq_flash: cleanup Sayma RTM management, support flashing AMC with RTM disconnected --- artiq/frontend/artiq_flash.py | 44 ++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index 50e63c042..6e7319a1c 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -72,11 +72,11 @@ Prerequisites: parser.add_argument("-d", "--dir", help="look for board binaries in this directory") parser.add_argument("--srcbuild", help="board binaries directory is laid out as a source build tree", default=False, action="store_true") - parser.add_argument("--force-rtm", help="force RTM actions on boards/variants that normally do not have a RTM", + parser.add_argument("--no-rtm-jtag", help="do not attempt JTAG to the RTM", default=False, action="store_true") parser.add_argument("action", metavar="ACTION", nargs="*", - default="gateware rtm_gateware bootloader firmware start".split(), - help="actions to perform, default: %(default)s") + default=[], + help="actions to perform, default: flash everything") return parser @@ -233,7 +233,7 @@ class ProgrammerXC7(Programmer): "xc7_program xc7.tap") -class ProgrammerSayma(Programmer): +class ProgrammerAMCRTM(Programmer): _sector_size = 0x10000 def __init__(self, client, preinit_script): @@ -270,7 +270,7 @@ class ProgrammerSayma(Programmer): add_commands(self._script, "xcu_program xcu.tap") -class ProgrammerMetlino(Programmer): +class ProgrammerAMC(Programmer): _sector_size = 0x10000 def __init__(self, client, preinit_script): @@ -316,7 +316,7 @@ def main(): "firmware": ("spi0", 0x450000), }, "sayma": { - "programmer": ProgrammerSayma, + "programmer": ProgrammerAMCRTM, "gateware": ("spi0", 0x000000), "bootloader": ("spi1", 0x000000), "storage": ("spi1", 0x040000), @@ -324,7 +324,7 @@ def main(): "rtm_gateware": ("spi1", 0x200000), }, "metlino": { - "programmer": ProgrammerMetlino, + "programmer": ProgrammerAMC, "gateware": ("spi0", 0x000000), "bootloader": ("spi1", 0x000000), "storage": ("spi1", 0x040000), @@ -343,7 +343,7 @@ def main(): if bin_dir is None: bin_dir = os.path.join(artiq_dir, "board-support") - needs_artifacts = any( + needs_artifacts = not args.action or any( action in args.action for action in ["gateware", "rtm_gateware", "bootloader", "firmware", "load", "rtm_load"]) variant = args.variant @@ -381,12 +381,22 @@ def main(): else: rtm_variant_dir = "sayma-rtm" + if not args.action: + if args.target == "sayma" and variant != "simplesatellite" and variant != "master": + args.action = "gateware rtm_gateware bootloader firmware start".split() + else: + args.action = "gateware bootloader firmware start".split() + if args.host is None: client = LocalClient() else: client = SSHClient(args.host, args.jump) - programmer = config["programmer"](client, preinit_script=args.preinit_command) + if args.target == "sayma" and args.no_rtm_jtag: + programmer_cls = ProgrammerAMC + else: + programmer_cls = config["programmer"] + programmer = programmer_cls(client, preinit_script=args.preinit_command) def artifact_path(this_variant_dir, *path_filename): if args.srcbuild: @@ -420,12 +430,10 @@ def main(): artifact_path(variant_dir, "gateware", "top.bit")) programmer.write_binary(*config["gateware"], gateware_bin) elif action == "rtm_gateware": - if args.force_rtm or ( - args.target == "sayma" and variant != "simplesatellite" and variant != "master"): - rtm_gateware_bin = convert_gateware( - artifact_path(rtm_variant_dir, "gateware", "top.bit"), header=True) - programmer.write_binary(*config["rtm_gateware"], - rtm_gateware_bin) + rtm_gateware_bin = convert_gateware( + artifact_path(rtm_variant_dir, "gateware", "top.bit"), header=True) + programmer.write_binary(*config["rtm_gateware"], + rtm_gateware_bin) elif action == "bootloader": bootloader_bin = artifact_path(variant_dir, "software", "bootloader", "bootloader.bin") programmer.write_binary(*config["bootloader"], bootloader_bin) @@ -448,10 +456,8 @@ def main(): gateware_bit = artifact_path(variant_dir, "gateware", "top.bit") programmer.load(gateware_bit, 0) elif action == "rtm_load": - if args.force_rtm or ( - args.target == "sayma" and variant != "simplesatellite" and variant != "master"): - rtm_gateware_bit = artifact_path(rtm_variant_dir, "gateware", "top.bit") - programmer.load(rtm_gateware_bit, 0) + rtm_gateware_bit = artifact_path(rtm_variant_dir, "gateware", "top.bit") + programmer.load(rtm_gateware_bit, 0) elif action == "start": programmer.start() elif action == "erase": From 9bc43b2dbfb3c0b2ab68e14237dbbc1dc51bcb56 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 23 Apr 2020 23:00:36 +0800 Subject: [PATCH 2155/2457] kasli: support EEPROM on v2 --- artiq/firmware/libboard_misoc/i2c_eeprom.rs | 11 ++++++++++- artiq/firmware/libboard_misoc/net_settings.rs | 5 ++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_misoc/i2c_eeprom.rs b/artiq/firmware/libboard_misoc/i2c_eeprom.rs index 0a15f7535..be06a55b4 100644 --- a/artiq/firmware/libboard_misoc/i2c_eeprom.rs +++ b/artiq/firmware/libboard_misoc/i2c_eeprom.rs @@ -13,7 +13,7 @@ pub struct EEPROM { } impl EEPROM { - pub fn kasli_eeprom() -> Self { + pub fn kasli1_eeprom() -> Self { EEPROM { busno: 0, /// Same port as Si5324 @@ -22,6 +22,15 @@ impl EEPROM { } } + pub fn kasli2_eeprom() -> Self { + EEPROM { + busno: 0, + /// SHARED I2C bus + port: 11, + address: 0xae, + } + } + fn select(&self) -> Result<(), &'static str> { let mask: u16 = 1 << self.port; i2c::pca9548_select(self.busno, I2C_SWITCH0, mask as u8)?; diff --git a/artiq/firmware/libboard_misoc/net_settings.rs b/artiq/firmware/libboard_misoc/net_settings.rs index f58eae13f..b553b5120 100644 --- a/artiq/firmware/libboard_misoc/net_settings.rs +++ b/artiq/firmware/libboard_misoc/net_settings.rs @@ -33,7 +33,10 @@ pub fn get_adresses() -> NetAddresses { _ => { #[cfg(soc_platform = "kasli")] { - let eeprom = i2c_eeprom::EEPROM::kasli_eeprom(); + #[cfg(any(hw_rev = "v1.0", hw_rev = "v1.1"))] + let eeprom = i2c_eeprom::EEPROM::kasli1_eeprom(); + #[cfg(hw_rev = "v2.0")] + let eeprom = i2c_eeprom::EEPROM::kasli2_eeprom(); hardware_addr = eeprom.read_eui48() .map(|addr_buf| EthernetAddress(addr_buf)) From d19f28fa84b00f31a5cf12488a121557a3ef224c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 23 Apr 2020 23:02:18 +0800 Subject: [PATCH 2156/2457] kasli: v2 clocking WIP, remove SFP LEDs from RTIO --- artiq/gateware/targets/kasli.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 356497d6b..07ebf430b 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -32,7 +32,10 @@ class _RTIOCRG(Module, AutoCSR): self.clock_domains.cd_rtio = ClockDomain() self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) - clk_synth = platform.request("si5324_clkout_fabric") + if platform.hw_rev == "v2.0": + clk_synth = platform.request("cdr_clk_clean_fabric") + else: + clk_synth = platform.request("si5324_clkout_fabric") clk_synth_se = Signal() platform.add_period_constraint(clk_synth.p, 8.0) self.specials += [ @@ -174,11 +177,12 @@ class Tester(StandaloneBase): eem.Sampler.add_std(self, 3, 2, ttl_serdes_7series.Output_8X) eem.Zotino.add_std(self, 4, ttl_serdes_7series.Output_8X) - for i in (1, 2): - sfp_ctl = self.platform.request("sfp_ctl", i) - phy = ttl_simple.Output(sfp_ctl.led) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) + if hw_rev in ("v1.0", "v1.1"): + for i in (1, 2): + sfp_ctl = self.platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) From 251a0101a66caf82a1a7f74c968bb7fbd6daecb2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 26 Apr 2020 12:38:43 +0800 Subject: [PATCH 2157/2457] compiler: support disabling now-pinning --- artiq/compiler/targets.py | 6 +- .../compiler/transforms/llvm_ir_generator.py | 67 ++++++++++++------- 2 files changed, 48 insertions(+), 25 deletions(-) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index 1519a8df9..c5b282c4c 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -78,13 +78,15 @@ class Target: :var little_endian: (boolean) Whether the code will be executed on a little-endian machine. This cannot be always determined from data_layout due to JIT. + :var now_pinning: (boolean) + Whether the target implements the now-pinning RTIO optimization. """ triple = "unknown" data_layout = "" features = [] print_function = "printf" little_endian = False - + now_pinning = True def __init__(self): self.llcontext = ll.Context() @@ -254,6 +256,7 @@ class OR1KTarget(Target): features = ["mul", "div", "ffl1", "cmov", "addc"] print_function = "core_log" little_endian = False + now_pinning = True class CortexA9Target(Target): triple = "armv7-unknown-linux-gnueabihf" @@ -261,3 +264,4 @@ class CortexA9Target(Target): features = ["dsp", "fp16", "neon", "vfp3"] print_function = "core_log" little_endian = True + now_pinning = False diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index ca302412d..b63cb881f 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -380,8 +380,19 @@ class LLVMIRGenerator: llty = ll.FunctionType(llvoid, [lli32, llsliceptr, llptrptr]) elif name == "rpc_recv": llty = ll.FunctionType(lli32, [llptr]) + + # with now-pinning elif name == "now": llty = lli64 + + # without now-pinning + elif name == "now_mu": + llty = ll.FunctionType(lli64, []) + elif name == "at_mu": + llty = ll.FunctionType(llvoid, [lli64]) + elif name == "delay_mu": + llty = ll.FunctionType(llvoid, [lli64]) + elif name == "watchdog_set": llty = ll.FunctionType(lli32, [lli64]) elif name == "watchdog_clear": @@ -1174,35 +1185,43 @@ class LLVMIRGenerator: # This is an identity cast at LLVM IR level. return self.map(insn.operands[0]) elif insn.op == "now_mu": - llnow = self.llbuilder.load(self.llbuiltin("now"), name=insn.name) - return llnow + if self.target.now_pinning: + return self.llbuilder.load(self.llbuiltin("now"), name=insn.name) + else: + return self.llbuilder.call(self.llbuiltin("now_mu"), []) elif insn.op == "at_mu": time, = insn.operands lltime = self.map(time) - lltime_hi = self.llbuilder.trunc(self.llbuilder.lshr(lltime, ll.Constant(lli64, 32)), lli32) - lltime_lo = self.llbuilder.trunc(lltime, lli32) - llnow_hiptr = self.llbuilder.bitcast(self.llbuiltin("now"), lli32.as_pointer()) - llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) - if self.target.little_endian: - lltime_hi, lltime_lo = lltime_lo, lltime_hi - llstore_hi = self.llbuilder.store_atomic(lltime_hi, llnow_hiptr, ordering="seq_cst", align=4) - llstore_lo = self.llbuilder.store_atomic(lltime_lo, llnow_loptr, ordering="seq_cst", align=4) - return llstore_lo + if self.target.now_pinning: + lltime_hi = self.llbuilder.trunc(self.llbuilder.lshr(lltime, ll.Constant(lli64, 32)), lli32) + lltime_lo = self.llbuilder.trunc(lltime, lli32) + llnow_hiptr = self.llbuilder.bitcast(self.llbuiltin("now"), lli32.as_pointer()) + llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) + if self.target.little_endian: + lltime_hi, lltime_lo = lltime_lo, lltime_hi + llstore_hi = self.llbuilder.store_atomic(lltime_hi, llnow_hiptr, ordering="seq_cst", align=4) + llstore_lo = self.llbuilder.store_atomic(lltime_lo, llnow_loptr, ordering="seq_cst", align=4) + return llstore_lo + else: + return self.llbuilder.call(self.llbuiltin("at_mu"), [lltime]) elif insn.op == "delay_mu": interval, = insn.operands - llnowptr = self.llbuiltin("now") - llnow = self.llbuilder.load(llnowptr, name="now.old") - lladjusted = self.llbuilder.add(llnow, self.map(interval), name="now.new") - - lladjusted_hi = self.llbuilder.trunc(self.llbuilder.lshr(lladjusted, ll.Constant(lli64, 32)), lli32) - lladjusted_lo = self.llbuilder.trunc(lladjusted, lli32) - llnow_hiptr = self.llbuilder.bitcast(llnowptr, lli32.as_pointer()) - llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) - if self.target.little_endian: - lladjusted_hi, lladjusted_lo = lladjusted_lo, lladjusted_hi - llstore_hi = self.llbuilder.store_atomic(lladjusted_hi, llnow_hiptr, ordering="seq_cst", align=4) - llstore_lo = self.llbuilder.store_atomic(lladjusted_lo, llnow_loptr, ordering="seq_cst", align=4) - return llstore_lo + llinterval = self.map(interval) + if self.target.now_pinning: + llnowptr = self.llbuiltin("now") + llnow = self.llbuilder.load(llnowptr, name="now.old") + lladjusted = self.llbuilder.add(llnow, llinterval, name="now.new") + lladjusted_hi = self.llbuilder.trunc(self.llbuilder.lshr(lladjusted, ll.Constant(lli64, 32)), lli32) + lladjusted_lo = self.llbuilder.trunc(lladjusted, lli32) + llnow_hiptr = self.llbuilder.bitcast(llnowptr, lli32.as_pointer()) + llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)]) + if self.target.little_endian: + lladjusted_hi, lladjusted_lo = lladjusted_lo, lladjusted_hi + llstore_hi = self.llbuilder.store_atomic(lladjusted_hi, llnow_hiptr, ordering="seq_cst", align=4) + llstore_lo = self.llbuilder.store_atomic(lladjusted_lo, llnow_loptr, ordering="seq_cst", align=4) + return llstore_lo + else: + return self.llbuilder.call(self.llbuiltin("delay_mu"), [llinterval]) elif insn.op == "watchdog_set": interval, = insn.operands return self.llbuilder.call(self.llbuiltin("watchdog_set"), [self.map(interval)]) From 3a7819704a82ff2ace83d15c6bd4cbff27540806 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 26 Apr 2020 16:04:32 +0800 Subject: [PATCH 2158/2457] rtio: support direct 64-bit now CSR in KernelInitiator --- artiq/gateware/rtio/cri.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 0c135a5b4..0de13b8d1 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -60,11 +60,14 @@ class Interface(Record): class KernelInitiator(Module, AutoCSR): - def __init__(self, tsc, cri=None): + def __init__(self, tsc, cri=None, now64=False): self.target = CSRStorage(32) - # not using CSRStorage atomic_write feature here to make storage reset_less - self.now_hi = CSR(32) - self.now_lo = CSR(32) + if now64: + self.now = CSRStorage(64) + else: + # not using CSRStorage atomic_write feature here to make storage reset_less + self.now_hi = CSR(32) + self.now_lo = CSR(32) # Writing target clears o_data. This implements automatic # zero-extension of output event data by the gateware. When staging an @@ -87,16 +90,19 @@ class KernelInitiator(Module, AutoCSR): # # # - now_hi_backing = Signal(32) - now = Signal(64, reset_less=True) - self.sync += [ - If(self.now_hi.re, now_hi_backing.eq(self.now_hi.r)), - If(self.now_lo.re, now.eq(Cat(self.now_lo.r, now_hi_backing))) - ] - self.comb += [ - self.now_hi.w.eq(now[32:]), - self.now_lo.w.eq(now[:32]) - ] + if now64: + now = self.now.storage + else: + now = Signal(64, reset_less=True) + now_hi_backing = Signal(32) + self.sync += [ + If(self.now_hi.re, now_hi_backing.eq(self.now_hi.r)), + If(self.now_lo.re, now.eq(Cat(self.now_lo.r, now_hi_backing))) + ] + self.comb += [ + self.now_hi.w.eq(now[32:]), + self.now_lo.w.eq(now[:32]) + ] self.comb += [ self.cri.cmd.eq(commands["nop"]), From 4228e0205cc64e16fd0455cddc9b87c312f6378c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 28 Apr 2020 15:00:24 +0800 Subject: [PATCH 2159/2457] compiler: link with lld on ARM (#733) --- artiq/compiler/targets.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index c5b282c4c..a9e5382be 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -68,6 +68,8 @@ class Target: :var triple: (string) LLVM target triple, e.g. ``"or1k"`` + :var linker: (string) + Linker to run. :var data_layout: (string) LLVM target data layout, e.g. ``"E-m:e-p:32:32-i64:32-f64:32-v64:32-v128:32-a:0:32-n32"`` :var features: (list of string) @@ -84,6 +86,7 @@ class Target: triple = "unknown" data_layout = "" features = [] + linker = "lld" print_function = "printf" little_endian = False now_pinning = True @@ -176,7 +179,7 @@ class Target: def link(self, objects): """Link the relocatable objects into a shared library for this target.""" - with RunTool([self.triple + "-ld", "-shared", "--eh-frame-hdr"] + + with RunTool([self.linker, "-shared", "--eh-frame-hdr"] + ["{{obj{}}}".format(index) for index in range(len(objects))] + ["-o", "{output}"], output=None, @@ -254,6 +257,7 @@ class OR1KTarget(Target): data_layout = "E-m:e-p:32:32-i8:8:8-i16:16:16-i64:32:32-" \ "f64:32:32-v64:32:32-v128:32:32-a0:0:32-n32" features = ["mul", "div", "ffl1", "cmov", "addc"] + linker = "or1k-linux-ld" print_function = "core_log" little_endian = False now_pinning = True @@ -262,6 +266,7 @@ class CortexA9Target(Target): triple = "armv7-unknown-linux-gnueabihf" data_layout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" features = ["dsp", "fp16", "neon", "vfp3"] + linker = "lld" print_function = "core_log" little_endian = True now_pinning = False From 140a26ad7eb7ce7bf0546510087d62b54fea29cd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 28 Apr 2020 16:07:26 +0800 Subject: [PATCH 2160/2457] compiler: ld -> ld.lld --- artiq/compiler/targets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index a9e5382be..308b15f59 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -266,7 +266,7 @@ class CortexA9Target(Target): triple = "armv7-unknown-linux-gnueabihf" data_layout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" features = ["dsp", "fp16", "neon", "vfp3"] - linker = "lld" + linker = "ld.lld" print_function = "core_log" little_endian = True now_pinning = False From 7e400a78f4fc4add4ce54566f053f737c313b46c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 28 Apr 2020 16:07:49 +0800 Subject: [PATCH 2161/2457] kasli: compile tester for hw 2.0 by default --- artiq/gateware/targets/kasli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 07ebf430b..0957fcfe4 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -158,7 +158,7 @@ class Tester(StandaloneBase): """ def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: - hw_rev = "v1.1" + hw_rev = "v2.0" StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None From 85e92ae28cd2de8d68ba15990a33aea1a62a516f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 28 Apr 2020 16:21:50 +0800 Subject: [PATCH 2162/2457] compiler: use more LLVM tools on ARM (#733) --- artiq/compiler/targets.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index 308b15f59..e44024177 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -68,8 +68,6 @@ class Target: :var triple: (string) LLVM target triple, e.g. ``"or1k"`` - :var linker: (string) - Linker to run. :var data_layout: (string) LLVM target data layout, e.g. ``"E-m:e-p:32:32-i64:32-f64:32-v64:32-v128:32-a:0:32-n32"`` :var features: (list of string) @@ -86,11 +84,15 @@ class Target: triple = "unknown" data_layout = "" features = [] - linker = "lld" print_function = "printf" little_endian = False now_pinning = True + tool_ld = "ld.lld" + tool_strip = "llvm-strip" + tool_addr2line = "llvm-addr2line" + tool_cxxfilt = "llvm-cxxfilt" + def __init__(self): self.llcontext = ll.Context() @@ -179,7 +181,7 @@ class Target: def link(self, objects): """Link the relocatable objects into a shared library for this target.""" - with RunTool([self.linker, "-shared", "--eh-frame-hdr"] + + with RunTool([self.tool_ld, "-shared", "--eh-frame-hdr"] + ["{{obj{}}}".format(index) for index in range(len(objects))] + ["-o", "{output}"], output=None, @@ -196,7 +198,7 @@ class Target: return self.link([self.assemble(self.compile(module)) for module in modules]) def strip(self, library): - with RunTool([self.triple + "-strip", "--strip-debug", "{library}", "-o", "{output}"], + with RunTool([self.tool_strip, "--strip-debug", "{library}", "-o", "{output}"], library=library, output=None) \ as results: return results["output"].read() @@ -210,7 +212,7 @@ class Target: # inside the call instruction (or its delay slot), since that's what # the backtrace entry should point at. offset_addresses = [hex(addr - 1) for addr in addresses] - with RunTool([self.triple + "-addr2line", "--addresses", "--functions", "--inlines", + with RunTool([self.tool_addr2line, "--addresses", "--functions", "--inlines", "--demangle", "--exe={library}"] + offset_addresses, library=library) \ as results: @@ -241,7 +243,7 @@ class Target: return backtrace def demangle(self, names): - with RunTool([self.triple + "-c++filt"] + names) as results: + with RunTool([self.tool_cxxfilt] + names) as results: return results["__stdout__"].read().rstrip().split("\n") class NativeTarget(Target): @@ -257,16 +259,19 @@ class OR1KTarget(Target): data_layout = "E-m:e-p:32:32-i8:8:8-i16:16:16-i64:32:32-" \ "f64:32:32-v64:32:32-v128:32:32-a0:0:32-n32" features = ["mul", "div", "ffl1", "cmov", "addc"] - linker = "or1k-linux-ld" print_function = "core_log" little_endian = False now_pinning = True + tool_ld = "or1k-linux-ld" + tool_strip = "or1k-linux-strip" + tool_addr2line = "or1k-linux-addr2line" + tool_cxxfilt = "or1k-linux-c++filt" + class CortexA9Target(Target): triple = "armv7-unknown-linux-gnueabihf" data_layout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" features = ["dsp", "fp16", "neon", "vfp3"] - linker = "ld.lld" print_function = "core_log" little_endian = True now_pinning = False From ef4e5bc69b59fcefda1ba2bbe7c49b049c29f287 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 May 2020 21:29:29 +0800 Subject: [PATCH 2163/2457] firmware: Kasli I2C EEPROM cleanup --- artiq/firmware/libboard_misoc/i2c_eeprom.rs | 17 +++++++---------- artiq/firmware/libboard_misoc/net_settings.rs | 5 +---- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/artiq/firmware/libboard_misoc/i2c_eeprom.rs b/artiq/firmware/libboard_misoc/i2c_eeprom.rs index be06a55b4..6f2dee15e 100644 --- a/artiq/firmware/libboard_misoc/i2c_eeprom.rs +++ b/artiq/firmware/libboard_misoc/i2c_eeprom.rs @@ -1,10 +1,5 @@ use i2c; -#[cfg(soc_platform = "kasli")] -const I2C_SWITCH0: u8 = 0x70; -#[cfg(soc_platform = "kasli")] -const I2C_SWITCH1: u8 = 0x71; - /// [Hardware manual](http://ww1.microchip.com/downloads/en/DeviceDoc/24AA02E48-24AA025E48-24AA02E64-24AA025E64-Data-Sheet-20002124H.pdf) pub struct EEPROM { busno: u8, @@ -13,7 +8,8 @@ pub struct EEPROM { } impl EEPROM { - pub fn kasli1_eeprom() -> Self { + #[cfg(all(soc_platform = "kasli", any(hw_rev = "v1.0", hw_rev = "v1.1")))] + pub fn new() -> Self { EEPROM { busno: 0, /// Same port as Si5324 @@ -22,7 +18,8 @@ impl EEPROM { } } - pub fn kasli2_eeprom() -> Self { + #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] + pub fn new() -> Self { EEPROM { busno: 0, /// SHARED I2C bus @@ -31,11 +28,11 @@ impl EEPROM { } } + #[cfg(soc_platform = "kasli")] fn select(&self) -> Result<(), &'static str> { let mask: u16 = 1 << self.port; - i2c::pca9548_select(self.busno, I2C_SWITCH0, mask as u8)?; - i2c::pca9548_select(self.busno, I2C_SWITCH1, (mask >> 8) as u8)?; - + i2c::pca9548_select(self.busno, 0x70, mask as u8)?; + i2c::pca9548_select(self.busno, 0x71, (mask >> 8) as u8)?; Ok(()) } diff --git a/artiq/firmware/libboard_misoc/net_settings.rs b/artiq/firmware/libboard_misoc/net_settings.rs index b553b5120..2663be5db 100644 --- a/artiq/firmware/libboard_misoc/net_settings.rs +++ b/artiq/firmware/libboard_misoc/net_settings.rs @@ -33,10 +33,7 @@ pub fn get_adresses() -> NetAddresses { _ => { #[cfg(soc_platform = "kasli")] { - #[cfg(any(hw_rev = "v1.0", hw_rev = "v1.1"))] - let eeprom = i2c_eeprom::EEPROM::kasli1_eeprom(); - #[cfg(hw_rev = "v2.0")] - let eeprom = i2c_eeprom::EEPROM::kasli2_eeprom(); + let eeprom = i2c_eeprom::EEPROM::new(); hardware_addr = eeprom.read_eui48() .map(|addr_buf| EthernetAddress(addr_buf)) From 4982fde8986be01dc0c1d50bf9ee963e989eb5f8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 5 May 2020 21:38:17 +0800 Subject: [PATCH 2164/2457] firmware: I2C I/O expander support --- artiq/firmware/libboard_misoc/io_expander.rs | 101 +++++++++++++++++++ artiq/firmware/libboard_misoc/lib.rs | 2 + artiq/firmware/runtime/main.rs | 15 +++ artiq/firmware/satman/main.rs | 26 ++++- 4 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 artiq/firmware/libboard_misoc/io_expander.rs diff --git a/artiq/firmware/libboard_misoc/io_expander.rs b/artiq/firmware/libboard_misoc/io_expander.rs new file mode 100644 index 000000000..0ff278a5e --- /dev/null +++ b/artiq/firmware/libboard_misoc/io_expander.rs @@ -0,0 +1,101 @@ +use i2c; + +pub struct IoExpander { + busno: u8, + port: u8, + address: u8, + virtual_led_mapping: &'static [(u8, u8, u8)], + out_current: [u8; 2], + out_target: [u8; 2], +} + +impl IoExpander { + #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] + pub fn new(index: u8) -> Self { + const VIRTUAL_LED_MAPPING0: [(u8, u8, u8); 2] = [(0, 0, 6), (1, 1, 6)]; + const VIRTUAL_LED_MAPPING1: [(u8, u8, u8); 2] = [(2, 0, 6), (3, 1, 6)]; + // Both expanders on SHARED I2C bus + match index { + 0 => IoExpander { + busno: 0, + port: 11, + address: 0x40, + virtual_led_mapping: &VIRTUAL_LED_MAPPING0, + out_current: [0; 2], + out_target: [0; 2], + }, + 1 => IoExpander { + busno: 0, + port: 11, + address: 0x42, + virtual_led_mapping: &VIRTUAL_LED_MAPPING1, + out_current: [0; 2], + out_target: [0; 2], + }, + _ => panic!("incorrect I/O expander index"), + } + } + + #[cfg(soc_platform = "kasli")] + fn select(&self) -> Result<(), &'static str> { + let mask: u16 = 1 << self.port; + i2c::pca9548_select(self.busno, 0x70, mask as u8)?; + i2c::pca9548_select(self.busno, 0x71, (mask >> 8) as u8)?; + Ok(()) + } + + fn write(&self, addr: u8, value: u8) -> Result<(), &'static str> { + i2c::start(self.busno)?; + i2c::write(self.busno, self.address)?; + i2c::write(self.busno, addr)?; + i2c::write(self.busno, value)?; + i2c::stop(self.busno)?; + Ok(()) + } + + pub fn init(&mut self) -> Result<(), &'static str> { + self.select()?; + + let mut iodir = [0xffu8; 2]; + for (_led, port, bit) in self.virtual_led_mapping.iter() { + iodir[*port as usize] &= !(1 << *bit); + } + self.write(0x00, iodir[0])?; + self.write(0x01, iodir[1])?; + + self.out_current[0] = 0x00; + self.write(0x12, 0x00)?; + self.out_current[1] = 0x00; + self.write(0x13, 0x00)?; + Ok(()) + } + + pub fn set(&mut self, port: u8, bit: u8, high: bool) { + if high { + self.out_target[port as usize] |= 1 << bit; + } else { + self.out_target[port as usize] &= !(1 << bit); + } + } + + pub fn service(&mut self) -> Result<(), &'static str> { + for (led, port, bit) in self.virtual_led_mapping.iter() { + // TODO: get level from gateware + self.set(*port, *bit, false); + } + + if self.out_target != self.out_current { + self.select()?; + if self.out_target[0] != self.out_current[0] { + self.write(0x12, self.out_target[0])?; + self.out_current[0] = self.out_target[0]; + } + if self.out_target[1] != self.out_current[1] { + self.write(0x13, self.out_target[1])?; + self.out_current[1] = self.out_target[1]; + } + } + + Ok(()) + } +} diff --git a/artiq/firmware/libboard_misoc/lib.rs b/artiq/firmware/libboard_misoc/lib.rs index 8abddf898..5e8a92972 100644 --- a/artiq/firmware/libboard_misoc/lib.rs +++ b/artiq/firmware/libboard_misoc/lib.rs @@ -37,6 +37,8 @@ pub mod ethmac; pub mod i2c; #[cfg(soc_platform = "kasli")] pub mod i2c_eeprom; +#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] +pub mod io_expander; #[cfg(all(has_ethmac, feature = "smoltcp"))] pub mod net_settings; #[cfg(has_slave_fpga_cfg)] diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 02e3fa61a..3fc931032 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -99,6 +99,15 @@ fn startup() { setup_log_levels(); #[cfg(has_i2c)] board_misoc::i2c::init().expect("I2C initialization failed"); + #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] + let (mut io_expander0, mut io_expander1); + #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] + { + io_expander0 = board_misoc::io_expander::IoExpander::new(0); + io_expander1 = board_misoc::io_expander::IoExpander::new(1); + io_expander0.init().expect("I2C I/O expander #0 initialization failed"); + io_expander1.init().expect("I2C I/O expander #1 initialization failed"); + } rtio_clocking::init(); let mut net_device = unsafe { ethmac::EthernetDevice::new() }; @@ -210,6 +219,12 @@ fn startup() { if let Some(_net_stats_diff) = net_stats.update() { debug!("ethernet mac:{}", ethmac::EthernetStatistics::new()); } + + #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] + { + io_expander0.service().expect("I2C I/O expander #0 service failed"); + io_expander1.service().expect("I2C I/O expander #1 service failed"); + } } } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 8a07db183..c3a9b05d9 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -454,13 +454,23 @@ pub extern fn main() -> i32 { info!("software ident {}", csr::CONFIG_IDENTIFIER_STR); info!("gateware ident {}", ident::read(&mut [0; 64])); - #[cfg(has_si5324)] + #[cfg(has_i2c)] + i2c::init().expect("I2C initialization failed"); + #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] + let (mut io_expander0, mut io_expander1); + #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] { - i2c::init().expect("I2C initialization failed"); - si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324"); + io_expander0 = board_misoc::io_expander::IoExpander::new(0); + io_expander1 = board_misoc::io_expander::IoExpander::new(1); + io_expander0.init().expect("I2C I/O expander #0 initialization failed"); + io_expander1.init().expect("I2C I/O expander #1 initialization failed"); } + + #[cfg(has_si5324)] + si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324"); #[cfg(has_wrpll)] wrpll::init(); + unsafe { csr::drtio_transceiver::stable_clkin_write(1); } @@ -507,6 +517,11 @@ pub extern fn main() -> i32 { for mut rep in repeaters.iter_mut() { rep.service(&routing_table, rank); } + #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] + { + io_expander0.service().expect("I2C I/O expander #0 service failed"); + io_expander1.service().expect("I2C I/O expander #1 service failed"); + } hardware_tick(&mut hardware_tick_ts); } @@ -531,6 +546,11 @@ pub extern fn main() -> i32 { for mut rep in repeaters.iter_mut() { rep.service(&routing_table, rank); } + #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] + { + io_expander0.service().expect("I2C I/O expander #0 service failed"); + io_expander1.service().expect("I2C I/O expander #1 service failed"); + } hardware_tick(&mut hardware_tick_ts); if drtiosat_tsc_loaded() { info!("TSC loaded from uplink"); From b83afedf43c405917d1f3b1639d317c4aad4540f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 7 May 2020 19:06:10 +0800 Subject: [PATCH 2165/2457] kasli: light up ERROR LED on panic --- artiq/firmware/bootloader/main.rs | 5 +++++ artiq/firmware/runtime/main.rs | 5 +++++ artiq/firmware/satman/main.rs | 5 +++++ artiq/gateware/targets/kasli.py | 7 ++++--- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/bootloader/main.rs b/artiq/firmware/bootloader/main.rs index 39cf81c40..c698dee78 100644 --- a/artiq/firmware/bootloader/main.rs +++ b/artiq/firmware/bootloader/main.rs @@ -530,6 +530,11 @@ pub extern fn abort() { #[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647} #[panic_implementation] pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! { + #[cfg(has_error_led)] + unsafe { + board_misoc::csr::error_led::out_write(1); + } + if let Some(location) = info.location() { print!("panic at {}:{}:{}", location.file(), location.line(), location.column()); } else { diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 3fc931032..b40c0d097 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -298,6 +298,11 @@ pub fn oom(layout: core::alloc::Layout) -> ! { pub fn panic_impl(info: &core::panic::PanicInfo) -> ! { irq::set_ie(false); + #[cfg(has_error_led)] + unsafe { + csr::error_led::out_write(1); + } + if let Some(location) = info.location() { print!("panic at {}:{}:{}", location.file(), location.line(), location.column()); } else { diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index c3a9b05d9..cb10671c6 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -648,6 +648,11 @@ pub extern fn abort() { #[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647} #[panic_implementation] pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! { + #[cfg(has_error_led)] + unsafe { + csr::error_led::out_write(1); + } + if let Some(location) = info.location() { print!("panic at {}:{}:{}", location.file(), location.line(), location.column()); } else { diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 0957fcfe4..d9e09c783 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -110,9 +110,10 @@ class StandaloneBase(MiniSoC, AMPSoC): AMPSoC.__init__(self) add_identifier(self) - self.submodules.leds = gpio.GPIOOut(Cat( - self.platform.request("user_led", 0))) - self.csr_devices.append("leds") + if self.platform.hw_rev == "v2.0": + self.submodules.error_led = gpio.GPIOOut(Cat( + self.platform.request("error_led"))) + self.csr_devices.append("error_led") i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) From 35f1814235a35b293d1090388d5f5d9f3b818c35 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 7 May 2020 19:07:43 +0800 Subject: [PATCH 2166/2457] kasli: implement virtual LEDs --- artiq/firmware/libboard_misoc/io_expander.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_misoc/io_expander.rs b/artiq/firmware/libboard_misoc/io_expander.rs index 0ff278a5e..136a38856 100644 --- a/artiq/firmware/libboard_misoc/io_expander.rs +++ b/artiq/firmware/libboard_misoc/io_expander.rs @@ -1,4 +1,5 @@ use i2c; +use csr; pub struct IoExpander { busno: u8, @@ -80,8 +81,10 @@ impl IoExpander { pub fn service(&mut self) -> Result<(), &'static str> { for (led, port, bit) in self.virtual_led_mapping.iter() { - // TODO: get level from gateware - self.set(*port, *bit, false); + let level = unsafe { + (csr::virtual_leds::status_read() >> led) & 1 + }; + self.set(*port, *bit, level != 0); } if self.out_target != self.out_current { From 1f2182d4c76f7a0b7e1f83d7ba01bbd5ed955915 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 7 May 2020 19:15:03 +0800 Subject: [PATCH 2167/2457] kasli: default to hardware v2 --- artiq/gateware/targets/kasli.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index d9e09c783..cbc2a74c7 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -197,7 +197,7 @@ class SUServo(StandaloneBase): """ def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: - hw_rev = "v1.1" + hw_rev = "v2.0" StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) self.config["SI5324_AS_SYNTHESIZER"] = None @@ -588,7 +588,7 @@ class SatelliteBase(BaseSoC): class Master(MasterBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: - hw_rev = "v1.1" + hw_rev = "v2.0" MasterBase.__init__(self, hw_rev=hw_rev, **kwargs) self.rtio_channels = [] @@ -611,7 +611,7 @@ class Master(MasterBase): class Satellite(SatelliteBase): def __init__(self, hw_rev=None, **kwargs): if hw_rev is None: - hw_rev = "v1.1" + hw_rev = "v2.0" SatelliteBase.__init__(self, hw_rev=hw_rev, **kwargs) self.rtio_channels = [] From 60e5f1c18e245cf2937538c694cfb759d9656516 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 7 May 2020 20:09:43 +0800 Subject: [PATCH 2168/2457] kasli: DRTIO support for Kasli 2 --- artiq/gateware/targets/kasli.py | 75 +++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index cbc2a74c7..fe2d5a65c 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -306,9 +306,12 @@ class MasterBase(MiniSoC, AMPSoC): if enable_sata: drtio_data_pads.append(platform.request("sata")) drtio_data_pads += [platform.request("sfp", i) for i in range(1, 3)] + if self.platform.hw_rev == "v2.0": + drtio_data_pads.append(platform.request("sfp", 3)) - sfp_ctls = [platform.request("sfp_ctl", i) for i in range(1, 3)] - self.comb += [sc.tx_disable.eq(0) for sc in sfp_ctls] + if self.platform.hw_rev in ("v1.0", "v1.1"): + sfp_ctls = [platform.request("sfp_ctl", i) for i in range(1, 3)] + self.comb += [sc.tx_disable.eq(0) for sc in sfp_ctls] self.submodules.drtio_transceiver = gtp_7series.GTP( qpll_channel=self.drtio_qpll_channel, @@ -316,15 +319,19 @@ class MasterBase(MiniSoC, AMPSoC): sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") - self.sync += self.disable_si5324_ibuf.eq( + self.sync += self.disable_cdr_clk_ibuf.eq( ~self.drtio_transceiver.stable_clkin.storage) if enable_sata: sfp_channels = self.drtio_transceiver.channels[1:] else: sfp_channels = self.drtio_transceiver.channels - self.comb += [sfp_ctl.led.eq(channel.rx_ready) - for sfp_ctl, channel in zip(sfp_ctls, sfp_channels)] + if self.platform.hw_rev in ("v1.0", "v1.1"): + self.comb += [sfp_ctl.led.eq(channel.rx_ready) + for sfp_ctl, channel in zip(sfp_ctls, sfp_channels)] + if self.platform.hw_rev == "v2.0": + self.comb += [self.virtual_leds.get(i + 1).eq(channel.rx_ready) + for i, channel in enumerate(sfp_channels)] self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) @@ -408,14 +415,17 @@ class MasterBase(MiniSoC, AMPSoC): def create_qpll(self): # The GTP acts up if you send any glitch to its # clock input, even while the PLL is held in reset. - self.disable_si5324_ibuf = Signal(reset=1) - self.disable_si5324_ibuf.attr.add("no_retiming") - si5324_clkout = self.platform.request("si5324_clkout") - si5324_clkout_buf = Signal() + self.disable_cdr_clk_ibuf = Signal(reset=1) + self.disable_cdr_clk_ibuf.attr.add("no_retiming") + if self.platform.hw_rev == "v2.0": + cdr_clk_clean = self.platform.request("cdr_clk_clean") + else: + cdr_clk_clean = self.platform.request("si5324_clkout") + cdr_clk_clean_buf = Signal() self.specials += Instance("IBUFDS_GTE2", - i_CEB=self.disable_si5324_ibuf, - i_I=si5324_clkout.p, i_IB=si5324_clkout.n, - o_O=si5324_clkout_buf) + i_CEB=self.disable_cdr_clk_ibuf, + i_I=cdr_clk_clean.p, i_IB=cdr_clk_clean.n, + o_O=cdr_clk_clean_buf) # Note precisely the rules Xilinx made up: # refclksel=0b001 GTREFCLK0 selected # refclksel=0b010 GTREFCLK1 selected @@ -430,7 +440,7 @@ class MasterBase(MiniSoC, AMPSoC): fbdiv=4, fbdiv_45=5, refclk_div=1) - qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings, + qpll = QPLL(cdr_clk_clean_buf, qpll_drtio_settings, self.crg.clk125_buf, qpll_eth_settings) self.submodules += qpll self.drtio_qpll_channel, self.ethphy_qpll_channel = qpll.channels @@ -452,44 +462,54 @@ class SatelliteBase(BaseSoC): platform = self.platform - disable_si5324_ibuf = Signal(reset=1) - disable_si5324_ibuf.attr.add("no_retiming") - si5324_clkout = platform.request("si5324_clkout") - si5324_clkout_buf = Signal() + disable_cdr_clk_ibuf = Signal(reset=1) + disable_cdr_clk_ibuf.attr.add("no_retiming") + if self.platform.hw_rev == "v2.0": + cdr_clk_clean = self.platform.request("cdr_clk_clean") + else: + cdr_clk_clean = self.platform.request("si5324_clkout") + cdr_clk_clean_buf = Signal() self.specials += Instance("IBUFDS_GTE2", - i_CEB=disable_si5324_ibuf, - i_I=si5324_clkout.p, i_IB=si5324_clkout.n, - o_O=si5324_clkout_buf) + i_CEB=disable_cdr_clk_ibuf, + i_I=cdr_clk_clean.p, i_IB=cdr_clk_clean.n, + o_O=cdr_clk_clean_buf) qpll_drtio_settings = QPLLSettings( refclksel=0b001, fbdiv=4, fbdiv_45=5, refclk_div=1) - qpll = QPLL(si5324_clkout_buf, qpll_drtio_settings) + qpll = QPLL(cdr_clk_clean_buf, qpll_drtio_settings) self.submodules += qpll drtio_data_pads = [] if enable_sata: drtio_data_pads.append(platform.request("sata")) drtio_data_pads += [platform.request("sfp", i) for i in range(3)] + if self.platform.hw_rev == "v2.0": + drtio_data_pads.append(platform.request("sfp", 3)) - sfp_ctls = [platform.request("sfp_ctl", i) for i in range(3)] - self.comb += [sc.tx_disable.eq(0) for sc in sfp_ctls] + if self.platform.hw_rev in ("v1.0", "v1.1"): + sfp_ctls = [platform.request("sfp_ctl", i) for i in range(3)] + self.comb += [sc.tx_disable.eq(0) for sc in sfp_ctls] self.submodules.drtio_transceiver = gtp_7series.GTP( qpll_channel=qpll.channels[0], data_pads=drtio_data_pads, sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") - self.sync += disable_si5324_ibuf.eq( + self.sync += disable_cdr_clk_ibuf.eq( ~self.drtio_transceiver.stable_clkin.storage) if enable_sata: sfp_channels = self.drtio_transceiver.channels[1:] else: sfp_channels = self.drtio_transceiver.channels - self.comb += [sfp_ctl.led.eq(channel.rx_ready) - for sfp_ctl, channel in zip(sfp_ctls, sfp_channels)] + if self.platform.hw_rev in ("v1.0", "v1.1"): + self.comb += [sfp_ctl.led.eq(channel.rx_ready) + for sfp_ctl, channel in zip(sfp_ctls, sfp_channels)] + if self.platform.hw_rev == "v2.0": + self.comb += [self.virtual_leds.get(i).eq(channel.rx_ready) + for i, channel in enumerate(sfp_channels)] self.submodules.rtio_tsc = rtio.TSC("sync", glbl_fine_ts_width=3) @@ -538,7 +558,8 @@ class SatelliteBase(BaseSoC): self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) self.submodules.siphaser = SiPhaser7Series( - si5324_clkin=platform.request("si5324_clkin"), + si5324_clkin=platform.request("cdr_clk") if platform.hw_rev == "v2.0" + else platform.request("si5324_clkin"), rx_synchronizer=self.rx_synchronizer, ref_clk=self.crg.clk125_div2, ref_div2=True, rtio_clk_freq=rtio_clk_freq) From 4e9a529e5ac19af78d393fd80f34773756c9e30d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 7 May 2020 21:34:02 +0800 Subject: [PATCH 2169/2457] kasli: integrate WRPLL --- artiq/firmware/libboard_artiq/wrpll.rs | 3 ++ artiq/firmware/libboard_misoc/io_expander.rs | 21 +++++++-- artiq/firmware/satman/main.rs | 11 +++++ artiq/gateware/targets/kasli.py | 48 ++++++++++++++------ 4 files changed, 65 insertions(+), 18 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 5df8eef1e..123e70c47 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -175,7 +175,10 @@ mod si549 { use board_misoc::clock; use super::i2c; + #[cfg(any(soc_platform = "metlino", soc_platform = "sayma_amc", soc_platform = "sayma_rtm"))] pub const ADDRESS: u8 = 0x55; + #[cfg(soc_platform = "kasli")] + pub const ADDRESS: u8 = 0x67; pub fn write(dcxo: i2c::Dcxo, reg: u8, val: u8) -> Result<(), &'static str> { i2c::start(dcxo); diff --git a/artiq/firmware/libboard_misoc/io_expander.rs b/artiq/firmware/libboard_misoc/io_expander.rs index 136a38856..d2d2acd2f 100644 --- a/artiq/firmware/libboard_misoc/io_expander.rs +++ b/artiq/firmware/libboard_misoc/io_expander.rs @@ -6,6 +6,7 @@ pub struct IoExpander { port: u8, address: u8, virtual_led_mapping: &'static [(u8, u8, u8)], + iodir: [u8; 2], out_current: [u8; 2], out_target: [u8; 2], } @@ -22,6 +23,7 @@ impl IoExpander { port: 11, address: 0x40, virtual_led_mapping: &VIRTUAL_LED_MAPPING0, + iodir: [0xff; 2], out_current: [0; 2], out_target: [0; 2], }, @@ -30,6 +32,7 @@ impl IoExpander { port: 11, address: 0x42, virtual_led_mapping: &VIRTUAL_LED_MAPPING1, + iodir: [0xff; 2], out_current: [0; 2], out_target: [0; 2], }, @@ -54,15 +57,19 @@ impl IoExpander { Ok(()) } + fn update_iodir(&self) -> Result<(), &'static str> { + self.write(0x00, self.iodir[0])?; + self.write(0x01, self.iodir[1])?; + Ok(()) + } + pub fn init(&mut self) -> Result<(), &'static str> { self.select()?; - let mut iodir = [0xffu8; 2]; for (_led, port, bit) in self.virtual_led_mapping.iter() { - iodir[*port as usize] &= !(1 << *bit); + self.iodir[*port as usize] &= !(1 << *bit); } - self.write(0x00, iodir[0])?; - self.write(0x01, iodir[1])?; + self.update_iodir()?; self.out_current[0] = 0x00; self.write(0x12, 0x00)?; @@ -71,6 +78,12 @@ impl IoExpander { Ok(()) } + pub fn set_oe(&mut self, port: u8, outputs: u8) -> Result<(), &'static str> { + self.iodir[port as usize] &= !outputs; + self.update_iodir()?; + Ok(()) + } + pub fn set(&mut self, port: u8, bit: u8, high: bool) { if high { self.out_target[port as usize] |= 1 << bit; diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index cb10671c6..9e2144370 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -464,6 +464,17 @@ pub extern fn main() -> i32 { io_expander1 = board_misoc::io_expander::IoExpander::new(1); io_expander0.init().expect("I2C I/O expander #0 initialization failed"); io_expander1.init().expect("I2C I/O expander #1 initialization failed"); + #[cfg(has_wrpll)] + { + io_expander0.set_oe(1, 1 << 7).unwrap(); + io_expander0.set(1, 7, true); + io_expander0.service().unwrap(); + io_expander1.set_oe(0, 1 << 7).unwrap(); + io_expander1.set_oe(1, 1 << 7).unwrap(); + io_expander1.set(0, 7, true); + io_expander1.set(1, 7, true); + io_expander1.service().unwrap(); + } } #[cfg(has_si5324)] diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index fe2d5a65c..73162c65b 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -20,6 +20,7 @@ from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, edge_counter from artiq.gateware import eem from artiq.gateware.drtio.transceiver import gtp_7series from artiq.gateware.drtio.siphaser import SiPhaser7Series +from artiq.gateware.drtio.wrpll import WRPLL, DDMTDSamplerGTP from artiq.gateware.drtio.rx_synchronizer import XilinxRXSynchronizer from artiq.gateware.drtio import * from artiq.build_soc import * @@ -452,7 +453,7 @@ class SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, rtio_clk_freq=125e6, enable_sata=False, **kwargs): + def __init__(self, rtio_clk_freq=125e6, enable_sata=False, *, with_wrpll=False, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -556,24 +557,38 @@ class SatelliteBase(BaseSoC): self.add_memory_group("drtioaux_mem", drtioaux_memory_group) self.add_csr_group("drtiorep", drtiorep_csr_group) - self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - self.submodules.siphaser = SiPhaser7Series( - si5324_clkin=platform.request("cdr_clk") if platform.hw_rev == "v2.0" - else platform.request("si5324_clkin"), - rx_synchronizer=self.rx_synchronizer, - ref_clk=self.crg.clk125_div2, ref_div2=True, - rtio_clk_freq=rtio_clk_freq) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) - self.csr_devices.append("siphaser") i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) self.csr_devices.append("i2c") self.config["I2C_BUS_COUNT"] = 1 - self.config["HAS_SI5324"] = None - self.config["SI5324_SOFT_RESET"] = None rtio_clk_period = 1e9/rtio_clk_freq + self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) + if with_wrpll: + self.submodules.wrpll_sampler = DDMTDSamplerGTP( + self.drtio_transceiver, + platform.request("cdr_clk_clean_fabric")) + self.submodules.wrpll = WRPLL( + helper_clk_pads=platform.request("ddmtd_helper_clk"), + main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), + helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"), + ddmtd_inputs=self.wrpll_sampler) + self.csr_devices.append("wrpll") + platform.add_period_constraint(self.wrpll.cd_helper.clk, rtio_clk_period*0.99) + platform.add_false_path_constraints(self.crg.cd_sys.clk, self.wrpll.cd_helper.clk) + else: + self.submodules.siphaser = SiPhaser7Series( + si5324_clkin=platform.request("cdr_clk") if platform.hw_rev == "v2.0" + else platform.request("si5324_clkin"), + rx_synchronizer=self.rx_synchronizer, + ref_clk=self.crg.clk125_div2, ref_div2=True, + rtio_clk_freq=rtio_clk_freq) + platform.add_false_path_constraints( + self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) + self.csr_devices.append("siphaser") + self.config["HAS_SI5324"] = None + self.config["SI5324_SOFT_RESET"] = None + gtp = self.drtio_transceiver.gtps[0] platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) @@ -658,15 +673,20 @@ def main(): parser.add_argument("-V", "--variant", default="tester", help="variant: {} (default: %(default)s)".format( "/".join(sorted(VARIANTS.keys())))) + parser.add_argument("--with-wrpll", default=False, action="store_true") args = parser.parse_args() + argdict = dict() + if args.with_wrpll: + argdict["with_wrpll"] = True + variant = args.variant.lower() try: cls = VARIANTS[variant] except KeyError: raise SystemExit("Invalid variant (-V/--variant)") - soc = cls(**soc_kasli_argdict(args)) + soc = cls(**soc_kasli_argdict(args), **argdict) build_artiq_soc(soc, builder_argdict(args)) From b3b6cb8efe98e0656322d6c1769585ef117c3f82 Mon Sep 17 00:00:00 2001 From: Marius Weber Date: Fri, 8 May 2020 18:23:43 +0100 Subject: [PATCH 2170/2457] ad53xx improvements (#1445) * ad53xx: voltage_to_mu() validation & documentation (closes #1443, #1444) The voltage input (float) is checked for validity. If we need more speed, we may want to check the DAC-code for over/underflow instead. Signed-off-by: Marius Weber * ad53xx documentation: voltage_to_mu is only valid for 16-bit DACs Signed-off-by: Marius Weber * AD53xx: add voltage_to_mu method (closes #1341) Signed-off-by: Marius Weber * ad53xx: improve voltage_to_mu performance Interger comparison is faster than floating point math. Signed-off-by: Marius Weber * AD53xx: voltage_to_mu method now uses attribute values Signed-off-by: Marius Weber * Fixup RELEASE_NOTES.rst Signed-off-by: Marius Weber * ad53xx: documentation improvements voltage_to_mu return value 14-bit DAC support Signed-off-by: Marius Weber --- RELEASE_NOTES.rst | 1 + artiq/coredevice/ad53xx.py | 29 ++++++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 79683c13a..e1a847bce 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -11,6 +11,7 @@ Highlights: * Performance improvements: - #1432: SERDES TTL inputs can now detect edges on pulses that are shorter than the RTIO period +* Zotino now exposes `voltage_to_mu()` Breaking changes: diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index c19239583..c4ff6d3aa 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -80,21 +80,30 @@ def ad53xx_cmd_read_ch(channel, op): return AD53XX_CMD_SPECIAL | AD53XX_SPECIAL_READ | (op + (channel << 7)) +# maintain function definition for backward compatibility @portable def voltage_to_mu(voltage, offset_dacs=0x2000, vref=5.): - """Returns the DAC register value required to produce a given output + """Returns the 16-bit DAC register value required to produce a given output voltage, assuming offset and gain errors have been trimmed out. + The 16-bit register value may also be used with 14-bit DACs. The additional + bits are disregarded by 14-bit DACs. + Also used to return offset register value required to produce a given voltage when the DAC register is set to mid-scale. An offset of V can be used to trim out a DAC offset error of -V. - :param voltage: Voltage + :param voltage: Voltage in SI units. + Valid voltages are: [-2*vref, + 2*vref - 1 LSB] + voltage offset. :param offset_dacs: Register value for the two offset DACs (default: 0x2000) :param vref: DAC reference voltage (default: 5.) + :return: The 16-bit DAC register value """ - return int(round(0x10000*(voltage/(4.*vref)) + offset_dacs*0x4)) + code = int(round((1 << 16) * (voltage / (4. * vref)) + offset_dacs * 0x4)) + if code < 0x0 or code > 0xffff: + raise ValueError("Invalid DAC voltage!") + return code class _DummyTTL: @@ -366,3 +375,17 @@ class AD53xx: self.core.break_realtime() self.write_offset_mu(channel, 0x8000-offset_err) self.write_gain_mu(channel, 0xffff-gain_err) + + @portable + def voltage_to_mu(self, voltage): + """Returns the 16-bit DAC register value required to produce a given + output voltage, assuming offset and gain errors have been trimmed out. + + The 16-bit register value may also be used with 14-bit DACs. The + additional bits are disregarded by 14-bit DACs. + + :param voltage: Voltage in SI units. + Valid voltages are: [-2*vref, + 2*vref - 1 LSB] + voltage offset. + :return: The 16-bit DAC register value + """ + return voltage_to_mu(voltage, self.offset_dacs, self.vref) From 2538840756ee76ee49a72dc714361f25be2170ff Mon Sep 17 00:00:00 2001 From: Marius Weber Date: Sun, 17 May 2020 14:09:11 +0100 Subject: [PATCH 2171/2457] Coredevice Input Validation (#1447) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Input validation and masking of SI -> mu conversions (close #1446) Signed-off-by: Marius Weber * Update RELEASE_NOTES Signed-off-by: Marius Weber Co-authored-by: Robert Jördens --- RELEASE_NOTES.rst | 1 + artiq/coredevice/ad9910.py | 15 +++++++++------ artiq/coredevice/ad9912.py | 8 ++++---- artiq/coredevice/ad9914.py | 23 ++++++++++++++--------- artiq/coredevice/suservo.py | 2 ++ artiq/coredevice/urukul.py | 7 +++++-- 6 files changed, 35 insertions(+), 21 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index e1a847bce..da4d0b272 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -11,6 +11,7 @@ Highlights: * Performance improvements: - #1432: SERDES TTL inputs can now detect edges on pulses that are shorter than the RTIO period +* Coredevice SI to mu conversions now always return valid codes, or raise a `ValueError`. * Zotino now exposes `voltage_to_mu()` Breaking changes: diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index a28d87d0a..4f8f99569 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -553,7 +553,7 @@ class AD9910: @portable(flags={"fast-math"}) def frequency_to_ftw(self, frequency): - """Return the frequency tuning word corresponding to the given + """Return the 32-bit frequency tuning word corresponding to the given frequency. """ return int32(round(self.ftw_per_hz*frequency)) @@ -567,9 +567,9 @@ class AD9910: @portable(flags={"fast-math"}) def turns_to_pow(self, turns): - """Return the phase offset word corresponding to the given phase + """Return the 16-bit phase offset word corresponding to the given phase in turns.""" - return int32(round(turns*0x10000)) + return int32(round(turns*0x10000)) & 0xffff @portable(flags={"fast-math"}) def pow_to_turns(self, pow_): @@ -579,9 +579,12 @@ class AD9910: @portable(flags={"fast-math"}) def amplitude_to_asf(self, amplitude): - """Return amplitude scale factor corresponding to given fractional - amplitude.""" - return int32(round(amplitude*0x3ffe)) + """Return 14-bit amplitude scale factor corresponding to given + fractional amplitude.""" + code = int32(round(amplitude * 0x3ffe)) + if code < 0 or code > (1 << 14) - 1: + raise ValueError("Invalid AD9910 fractional amplitude!") + return code @portable(flags={"fast-math"}) def asf_to_amplitude(self, asf): diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index 32854ef6e..e21477308 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -157,10 +157,10 @@ class AD9912: @portable(flags={"fast-math"}) def frequency_to_ftw(self, frequency): - """Returns the frequency tuning word corresponding to the given + """Returns the 48-bit frequency tuning word corresponding to the given frequency. """ - return int64(round(self.ftw_per_hz*frequency)) + return int64(round(self.ftw_per_hz*frequency)) & ((int64(1) << 48) - 1) @portable(flags={"fast-math"}) def ftw_to_frequency(self, ftw): @@ -171,10 +171,10 @@ class AD9912: @portable(flags={"fast-math"}) def turns_to_pow(self, phase): - """Returns the phase offset word corresponding to the given + """Returns the 16-bit phase offset word corresponding to the given phase. """ - return int32(round((1 << 14)*phase)) + return int32(round((1 << 14)*phase)) & 0xffff @kernel def set(self, frequency, phase=0.0): diff --git a/artiq/coredevice/ad9914.py b/artiq/coredevice/ad9914.py index 647ce58f1..ce7e3b1a2 100644 --- a/artiq/coredevice/ad9914.py +++ b/artiq/coredevice/ad9914.py @@ -236,10 +236,10 @@ class AD9914: @portable(flags={"fast-math"}) def frequency_to_ftw(self, frequency): - """Returns the frequency tuning word corresponding to the given + """Returns the 32-bit frequency tuning word corresponding to the given frequency. """ - return round(float(int64(2)**32*frequency/self.sysclk)) + return int32(round(float(int64(2)**32*frequency/self.sysclk))) @portable(flags={"fast-math"}) def ftw_to_frequency(self, ftw): @@ -250,9 +250,9 @@ class AD9914: @portable(flags={"fast-math"}) def turns_to_pow(self, turns): - """Returns the phase offset word corresponding to the given phase - in turns.""" - return round(float(turns*2**16)) + """Returns the 16-bit phase offset word corresponding to the given + phase in turns.""" + return round(float(turns*2**16)) & 0xffff @portable(flags={"fast-math"}) def pow_to_turns(self, pow): @@ -262,8 +262,12 @@ class AD9914: @portable(flags={"fast-math"}) def amplitude_to_asf(self, amplitude): - """Returns amplitude scale factor corresponding to given amplitude.""" - return round(float(amplitude*0x0fff)) + """Returns 12-bit amplitude scale factor corresponding to given + amplitude.""" + code = round(float(amplitude * 0x0fff)) + if code < 0 or code > 0xfff: + raise ValueError("Invalid AD9914 amplitude!") + return code @portable(flags={"fast-math"}) def asf_to_amplitude(self, asf): @@ -314,10 +318,11 @@ class AD9914: @portable(flags={"fast-math"}) def frequency_to_xftw(self, frequency): - """Returns the frequency tuning word corresponding to the given + """Returns the 63-bit frequency tuning word corresponding to the given frequency (extended resolution mode). """ - return int64(round(2.0*float(int64(2)**62)*frequency/self.sysclk)) + return int64(round(2.0*float(int64(2)**62)*frequency/self.sysclk)) & ( + (int64(1) << 63) - 1) @portable(flags={"fast-math"}) def xftw_to_frequency(self, xftw): diff --git a/artiq/coredevice/suservo.py b/artiq/coredevice/suservo.py index b3d27c870..932adf35b 100644 --- a/artiq/coredevice/suservo.py +++ b/artiq/coredevice/suservo.py @@ -558,5 +558,7 @@ class Channel: :param y: IIR state in units of full scale """ y_mu = int(round(y * Y_FULL_SCALE_MU)) + if y_mu < 0 or y_mu > (1 << 17) - 1: + raise ValueError("Invalid SUServo y-value!") self.set_y_mu(profile, y_mu) return y_mu diff --git a/artiq/coredevice/urukul.py b/artiq/coredevice/urukul.py index 2cad18188..cbc3edbfc 100644 --- a/artiq/coredevice/urukul.py +++ b/artiq/coredevice/urukul.py @@ -292,7 +292,7 @@ class CPLD: :meth:`get_att_mu` to retrieve the hardware state set in previous experiments. :param channel: Attenuator channel (0-3). - :param att: Digital attenuation setting: + :param att: 8-bit digital attenuation setting: 255 minimum attenuation, 0 maximum attenuation (31.5 dB) """ a = self.att_reg & ~(0xff << (channel * 8)) @@ -325,7 +325,10 @@ class CPLD: attenuation. Minimum attenuation is 0*dB, maximum attenuation is 31.5*dB. """ - self.set_att_mu(channel, 255 - int32(round(att*8))) + code = 255 - int32(round(att*8)) + if code < 0 or code > 255: + raise ValueError("Invalid urukul.CPLD attenuation!") + self.set_att_mu(channel, code) @kernel def get_att_mu(self): From 8858ba8095826f1c46d5eeb9e193f56597b58f63 Mon Sep 17 00:00:00 2001 From: Charles Baynham Date: Sun, 24 May 2020 12:31:38 +0100 Subject: [PATCH 2172/2457] dashboard: Restart applets if required Restart applets that are already running if a ccb call updates their spec Signed-off-by: Charles Baynham --- artiq/dashboard/applets_ccb.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/artiq/dashboard/applets_ccb.py b/artiq/dashboard/applets_ccb.py index 1337a5363..30fa23db6 100644 --- a/artiq/dashboard/applets_ccb.py +++ b/artiq/dashboard/applets_ccb.py @@ -1,3 +1,4 @@ +import asyncio import logging from PyQt5 import QtCore, QtWidgets @@ -149,15 +150,16 @@ class AppletsCCBDock(applets.AppletsDock): corresponds to a single group. If ``group`` is ``None`` or an empty list, it corresponds to the root. - ``command`` gives the command line used to run the applet, as if it - was started from a shell. The dashboard substitutes variables such as - ``$python`` that gives the complete file name of the Python - interpreter running the dashboard. + ``command`` gives the command line used to run the applet, as if it was + started from a shell. The dashboard substitutes variables such as + ``$python`` that gives the complete file name of the Python interpreter + running the dashboard. If the name already exists (after following any specified groups), the command or code of the existing applet with that name is replaced, and - the applet is shown at its previous position. If not, a new applet - entry is created and the applet is shown at any position on the screen. + the applet is restarted and shown at its previous position. If not, a + new applet entry is created and the applet is shown at any position on + the screen. If the group(s) do not exist, they are created. @@ -181,9 +183,17 @@ class AppletsCCBDock(applets.AppletsDock): else: spec = {"ty": "code", "code": code, "command": command} if applet is None: + logger.debug('Applet {} does not exist: creating'.format(name)) applet = self.new(name=name, spec=spec, parent=parent) else: - self.set_spec(applet, spec) + if spec != self.get_spec(applet): + logger.debug('Applet {} already exists: updating existing spec'.format(name)) + self.set_spec(applet, spec) + if applet.applet_dock: + asyncio.ensure_future(applet.applet_dock.restart()) + else: + logger.debug('Applet {} already exists and no update required'.format(name)) + if ccbp == "enable": applet.setCheckState(0, QtCore.Qt.Checked) From 692c4668381adcce9795abdc73cff9138c077839 Mon Sep 17 00:00:00 2001 From: Charles Baynham Date: Tue, 26 May 2020 10:50:03 +0100 Subject: [PATCH 2173/2457] Use logger formatting --- artiq/dashboard/applets_ccb.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/dashboard/applets_ccb.py b/artiq/dashboard/applets_ccb.py index 30fa23db6..73e2f23fb 100644 --- a/artiq/dashboard/applets_ccb.py +++ b/artiq/dashboard/applets_ccb.py @@ -183,16 +183,16 @@ class AppletsCCBDock(applets.AppletsDock): else: spec = {"ty": "code", "code": code, "command": command} if applet is None: - logger.debug('Applet {} does not exist: creating'.format(name)) + logger.debug("Applet %s does not exist: creating", name) applet = self.new(name=name, spec=spec, parent=parent) else: if spec != self.get_spec(applet): - logger.debug('Applet {} already exists: updating existing spec'.format(name)) + logger.debug("Applet %s already exists: updating existing spec", name) self.set_spec(applet, spec) if applet.applet_dock: asyncio.ensure_future(applet.applet_dock.restart()) else: - logger.debug('Applet {} already exists and no update required'.format(name)) + logger.debug("Applet %s already exists and no update required", name) if ccbp == "enable": applet.setCheckState(0, QtCore.Qt.Checked) From 5db2afc7a77ff7e47cbc765c7a4590cecc749f64 Mon Sep 17 00:00:00 2001 From: Charles Baynham Date: Tue, 26 May 2020 10:51:27 +0100 Subject: [PATCH 2174/2457] dashboard: Release notes for #1453 --- RELEASE_NOTES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index da4d0b272..50fb0ec7f 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -13,6 +13,7 @@ Highlights: than the RTIO period * Coredevice SI to mu conversions now always return valid codes, or raise a `ValueError`. * Zotino now exposes `voltage_to_mu()` +* Applets now restart if they are running and a ccb call changes their spec Breaking changes: From 8b939b7cb31645fd835155fe3739636ec7d76201 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 29 May 2020 14:40:49 +0800 Subject: [PATCH 2175/2457] sayma_amc: remove Master (obsoleted by Metlino) --- artiq/gateware/targets/sayma_amc.py | 161 +--------------------------- 1 file changed, 1 insertion(+), 160 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index decc61640..b07d4e377 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -12,8 +12,6 @@ from misoc.interconnect.csr import * from misoc.targets.sayma_amc import * from artiq.gateware.amp import AMPSoC -from artiq.gateware import eem -from artiq.gateware import fmcdio_vhdci_eem from artiq.gateware import rtio from artiq.gateware import jesd204_tools from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_ultrascale, sawg @@ -386,161 +384,6 @@ class SimpleSatellite(SatelliteBase): self.add_rtio(rtio_channels) -class Master(MiniSoC, AMPSoC): - """ - DRTIO master with 2 SFP ports plus 8 lanes on RTM. - Use passive RTM adapter to connect to satellites. - Due to GTH clock routing restrictions, it is not possible - to use more RTM lanes without additional hardware. - """ - mem_map = { - "cri_con": 0x10000000, - "rtio": 0x11000000, - "rtio_dma": 0x12000000, - "drtioaux": 0x14000000, - "mailbox": 0x70000000 - } - mem_map.update(MiniSoC.mem_map) - - def __init__(self, **kwargs): - MiniSoC.__init__(self, - cpu_type="or1k", - sdram_controller_type="minicon", - l2_size=128*1024, - integrated_sram_size=8192, - ethmac_nrxslots=4, - ethmac_ntxslots=4, - **kwargs) - AMPSoC.__init__(self) - add_identifier(self) - - platform = self.platform - rtio_clk_freq = 150e6 - - self.submodules += RTMUARTForward(platform) - - self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) - self.csr_devices.append("si5324_rst_n") - i2c = self.platform.request("i2c") - self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) - self.csr_devices.append("i2c") - self.config["I2C_BUS_COUNT"] = 1 - self.config["HAS_SI5324"] = None - self.config["SI5324_AS_SYNTHESIZER"] = None - self.config["RTIO_FREQUENCY"] = str(rtio_clk_freq/1e6) - - self.comb += platform.request("filtered_clk_sel").eq(1) - self.comb += platform.request("sfp_tx_disable", 0).eq(0) - self.submodules.drtio_transceiver = gth_ultrascale.GTH( - clock_pads=platform.request("cdr_clk_clean", 0), - data_pads=[platform.request("sfp", 0)] + - [platform.request("rtm_gth", i) for i in range(8)], - sys_clk_freq=self.clk_freq, - rtio_clk_freq=rtio_clk_freq) - self.csr_devices.append("drtio_transceiver") - - self.submodules.rtio_tsc = rtio.TSC("async", glbl_fine_ts_width=3) - - drtio_csr_group = [] - drtioaux_csr_group = [] - drtioaux_memory_group = [] - drtio_cri = [] - for i in range(len(self.drtio_transceiver.channels)): - core_name = "drtio" + str(i) - coreaux_name = "drtioaux" + str(i) - memory_name = "drtioaux" + str(i) + "_mem" - drtio_csr_group.append(core_name) - drtioaux_csr_group.append(coreaux_name) - drtioaux_memory_group.append(memory_name) - - cdr = ClockDomainsRenamer({"rtio_rx": "rtio_rx" + str(i)}) - - core = cdr(DRTIOMaster(self.rtio_tsc, self.drtio_transceiver.channels[i])) - setattr(self.submodules, core_name, core) - drtio_cri.append(core.cri) - self.csr_devices.append(core_name) - - coreaux = cdr(DRTIOAuxController(core.link_layer)) - setattr(self.submodules, coreaux_name, coreaux) - self.csr_devices.append(coreaux_name) - - memory_address = self.mem_map["drtioaux"] + 0x800*i - self.add_wb_slave(memory_address, 0x800, - coreaux.bus) - self.add_memory_region(memory_name, memory_address | self.shadow_base, 0x800) - self.config["HAS_DRTIO"] = None - self.config["HAS_DRTIO_ROUTING"] = None - self.add_csr_group("drtio", drtio_csr_group) - self.add_csr_group("drtioaux", drtioaux_csr_group) - self.add_memory_group("drtioaux_mem", drtioaux_memory_group) - - rtio_clk_period = 1e9/rtio_clk_freq - gth0 = self.drtio_transceiver.gths[0] - platform.add_period_constraint(gth0.txoutclk, rtio_clk_period/2) - platform.add_period_constraint(gth0.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, - gth0.txoutclk, gth0.rxoutclk) - for gth in self.drtio_transceiver.gths[1:]: - platform.add_period_constraint(gth.rxoutclk, rtio_clk_period) - platform.add_false_path_constraints( - self.crg.cd_sys.clk, gth0.txoutclk, gth.rxoutclk) - - self.rtio_channels = rtio_channels = [] - for i in range(4): - phy = ttl_simple.Output(platform.request("user_led", i)) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - mcx_io = platform.request("mcx_io", 0) - phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) - self.comb += mcx_io.direction.eq(phy.oe) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - mcx_io = platform.request("mcx_io", 1) - phy = ttl_serdes_ultrascale.InOut(4, mcx_io.level) - self.comb += mcx_io.direction.eq(phy.oe) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - - platform.add_extension(fmcdio_vhdci_eem.io) - platform.add_connectors(fmcdio_vhdci_eem.connectors) - fmcdio_dirctl = platform.request("fmcdio_dirctl") - for s in fmcdio_dirctl.clk, fmcdio_dirctl.ser, fmcdio_dirctl.latch: - phy = ttl_simple.Output(s) - self.submodules += phy - rtio_channels.append(rtio.Channel.from_phy(phy)) - eem.DIO.add_std(self, 2, ttl_simple.Output, ttl_simple.Output, - iostandard="LVDS") - eem.Urukul.add_std(self, 0, 1, ttl_simple.Output, - iostandard="LVDS") - eem.Zotino.add_std(self, 3, ttl_simple.Output, - iostandard="LVDS") - workaround_us_lvds_tristate(platform) - - self.config["HAS_RTIO_LOG"] = None - self.config["RTIO_LOG_CHANNEL"] = len(rtio_channels) - rtio_channels.append(rtio.LogChannel()) - - self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) - self.csr_devices.append("rtio_moninj") - - self.submodules.rtio_core = rtio.Core(self.rtio_tsc, rtio_channels) - self.csr_devices.append("rtio_core") - - self.submodules.rtio = rtio.KernelInitiator(self.rtio_tsc) - self.submodules.rtio_dma = ClockDomainsRenamer("sys_kernel")( - rtio.DMA(self.get_native_sdram_if())) - self.register_kernel_cpu_csrdevice("rtio") - self.register_kernel_cpu_csrdevice("rtio_dma") - self.submodules.cri_con = rtio.CRIInterconnectShared( - [self.rtio.cri, self.rtio_dma.cri], - [self.rtio_core.cri] + drtio_cri, - enable_routing=True) - self.register_kernel_cpu_csrdevice("cri_con") - self.submodules.routing_table = rtio.RoutingTableAccess(self.cri_con) - self.csr_devices.append("routing_table") - - def main(): parser = argparse.ArgumentParser( description="Sayma AMC gateware and firmware builder") @@ -548,7 +391,7 @@ def main(): soc_sayma_amc_args(parser) parser.set_defaults(output_dir="artiq_sayma") parser.add_argument("-V", "--variant", default="satellite", - help="variant: satellite/simplesatellite/master " + help="variant: satellite/simplesatellite " "(default: %(default)s)") parser.add_argument("--rtm-csr-csv", default=os.path.join("artiq_sayma", "rtm_gateware", "rtm_csr.csv"), @@ -566,8 +409,6 @@ def main(): **soc_sayma_amc_argdict(args)) elif variant == "simplesatellite": soc = SimpleSatellite(with_wrpll=args.with_wrpll, **soc_sayma_amc_argdict(args)) - elif variant == "master": - soc = Master(**soc_sayma_amc_argdict(args)) else: raise SystemExit("Invalid variant (-V/--variant)") From d8b5bcf019cb3d44cb16551ed89101e2fe2df75d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 29 May 2020 14:58:49 +0800 Subject: [PATCH 2176/2457] sayma_amc: support uTCA backplane for DRTIO --- artiq/gateware/targets/sayma_amc.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index b07d4e377..c2cb435f1 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -50,7 +50,7 @@ class SatelliteBase(MiniSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, rtio_clk_freq=125e6, identifier_suffix="", *, with_wrpll, **kwargs): + def __init__(self, rtio_clk_freq=125e6, identifier_suffix="", with_sfp=False, *, with_wrpll, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -68,15 +68,15 @@ class SatelliteBase(MiniSoC): clock_recout_pads = platform.request("ddmtd_rec_clk") else: clock_recout_pads = None - # Use SFP0 to connect to master (Kasli) - self.comb += platform.request("sfp_tx_disable", 0).eq(0) - drtio_data_pads = [ - platform.request("sfp", 0), - platform.request("rtm_amc_link") - ] + if with_sfp: + # Use SFP0 to connect to master (Kasli) + self.comb += platform.request("sfp_tx_disable", 0).eq(0) + drtio_uplink = platform.request("sfp", 0) + else: + drtio_uplink = platform.request("fat_pipe", 0) self.submodules.drtio_transceiver = gth_ultrascale.GTH( clock_pads=platform.request("cdr_clk_clean"), - data_pads=drtio_data_pads, + data_pads=[drtio_uplink, platform.request("rtm_amc_link")], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq, clock_recout_pads=clock_recout_pads) @@ -393,6 +393,8 @@ def main(): parser.add_argument("-V", "--variant", default="satellite", help="variant: satellite/simplesatellite " "(default: %(default)s)") + parser.add_argument("--sfp", default=False, + help="use SFP port for DRTIO instead of uTCA backplane") parser.add_argument("--rtm-csr-csv", default=os.path.join("artiq_sayma", "rtm_gateware", "rtm_csr.csv"), help="CSV file listing remote CSRs on RTM (default: %(default)s)") @@ -405,10 +407,10 @@ def main(): variant = args.variant.lower() if variant == "satellite": - soc = Satellite(jdcg_type=args.jdcg_type, with_wrpll=args.with_wrpll, + soc = Satellite(with_sfp=args.sfp, jdcg_type=args.jdcg_type, with_wrpll=args.with_wrpll, **soc_sayma_amc_argdict(args)) elif variant == "simplesatellite": - soc = SimpleSatellite(with_wrpll=args.with_wrpll, **soc_sayma_amc_argdict(args)) + soc = SimpleSatellite(with_sfp=args.sfp, with_wrpll=args.with_wrpll, **soc_sayma_amc_argdict(args)) else: raise SystemExit("Invalid variant (-V/--variant)") From 02900d79d03dd7bd936e71810a468c00f16ce975 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 29 May 2020 15:21:07 +0800 Subject: [PATCH 2177/2457] firmware: fix typos --- artiq/firmware/satman/jdcg.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs index 98d546a79..c581791a3 100644 --- a/artiq/firmware/satman/jdcg.rs +++ b/artiq/firmware/satman/jdcg.rs @@ -527,7 +527,7 @@ pub mod jesd204sync { info!(" ...done"); // We tested that the value is correct - now use it - info!("sychronizing DAC-{}", dacno); + info!("synchronizing DAC-{}", dacno); hmc7043_sysref_delay_dac(dacno, delay); ad9154_sync(dacno)?; @@ -570,7 +570,7 @@ pub mod jesd204sync { pub fn resync_dacs() -> Result<(), &'static str> { for dacno in 0..csr::JDCG.len() { - info!("resychronizing DAC-{}", dacno); + info!("resynchronizing DAC-{}", dacno); ad9154_sync(dacno as u8)?; } Ok(()) From d5c1eaa16ebaff548acfb274c9da9291c9710366 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 29 May 2020 15:37:23 +0800 Subject: [PATCH 2178/2457] runtime: remove stack alignment requirement I suppose this was for TMPU, but was never finished. --- artiq/firmware/runtime/runtime.ld | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/runtime.ld b/artiq/firmware/runtime/runtime.ld index 67841f91e..a0a884dd2 100644 --- a/artiq/firmware/runtime/runtime.ld +++ b/artiq/firmware/runtime/runtime.ld @@ -65,7 +65,7 @@ SECTIONS _ebss = .; } > runtime - .stack ALIGN(0x1000) : + .stack : { . += 0x4000; _fstack = . - 4; From bd9eec15c003ddd2ca4ef6a3139e426321690da7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 29 May 2020 15:59:16 +0800 Subject: [PATCH 2179/2457] metlino: increase number of DRTIO links Seems OK with Vivado 2019.2. --- artiq/gateware/targets/metlino.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/gateware/targets/metlino.py b/artiq/gateware/targets/metlino.py index 65e3c2f0c..b9746848a 100755 --- a/artiq/gateware/targets/metlino.py +++ b/artiq/gateware/targets/metlino.py @@ -67,8 +67,7 @@ class Master(MiniSoC, AMPSoC): self.submodules.drtio_transceiver = gth_ultrascale.GTH( clock_pads=platform.request("cdr_clk_clean", 0), - # use only a few channels to work around Vivado bug - data_pads=[platform.request("mch_fabric_d", i) for i in range(3)], + data_pads=[platform.request("mch_fabric_d", i) for i in range(11)], sys_clk_freq=self.clk_freq, rtio_clk_freq=rtio_clk_freq) self.csr_devices.append("drtio_transceiver") From cb76f9da896d3a7db04eb3ca8f314a8aa18b3113 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 29 May 2020 15:59:44 +0800 Subject: [PATCH 2180/2457] metlino: fix CSR collisions Closes #1425 --- artiq/gateware/targets/metlino.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/gateware/targets/metlino.py b/artiq/gateware/targets/metlino.py index b9746848a..d1013653c 100755 --- a/artiq/gateware/targets/metlino.py +++ b/artiq/gateware/targets/metlino.py @@ -46,6 +46,7 @@ class Master(MiniSoC, AMPSoC): integrated_sram_size=8192, ethmac_nrxslots=4, ethmac_ntxslots=4, + csr_address_width=15, **kwargs) AMPSoC.__init__(self) add_identifier(self) From 9822b88d9b0a5ee33caad8b9b5461d472ac7acb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 29 May 2020 11:13:26 +0200 Subject: [PATCH 2181/2457] ad9910: fix asf range (#1450) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ad9910: fix asf range The ASF is a 14-bit word. The highest possible value is 0x3fff, not 0x3ffe. `int(round(1.0 * 0x3fff)) == 0x3fff`. I don't remember and understand why this was 0x3ffe since the beginning. 0x3fff was already used as a default in `set_mu()` Signed-off-by: Robert Jördens * RELEASE_NOTES: ad9910 asf scale change Co-authored-by: David Nadlinger --- RELEASE_NOTES.rst | 2 ++ artiq/coredevice/ad9910.py | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 50fb0ec7f..503a6c675 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -13,6 +13,8 @@ Highlights: than the RTIO period * Coredevice SI to mu conversions now always return valid codes, or raise a `ValueError`. * Zotino now exposes `voltage_to_mu()` +* `ad9910`: The maximum amplitude scale factor is now `0x3fff` (was `0x3ffe` + before). * Applets now restart if they are running and a ccb call changes their spec Breaking changes: diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index 4f8f99569..cc6316791 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -539,9 +539,9 @@ class AD9910: def set_asf(self, asf): """Set the value stored to the AD9910's amplitude scale factor (ASF) register. - :param asf: Amplitude scale factor to be stored, range: 0 to 0x3ffe. + :param asf: Amplitude scale factor to be stored, range: 0 to 0x3fff. """ - self.write32(_AD9910_REG_ASF, asf<<2) + self.write32(_AD9910_REG_ASF, asf << 2) @kernel def set_pow(self, pow_): @@ -581,8 +581,8 @@ class AD9910: def amplitude_to_asf(self, amplitude): """Return 14-bit amplitude scale factor corresponding to given fractional amplitude.""" - code = int32(round(amplitude * 0x3ffe)) - if code < 0 or code > (1 << 14) - 1: + code = int32(round(amplitude * 0x3fff)) + if code < 0 or code > 0x3fff: raise ValueError("Invalid AD9910 fractional amplitude!") return code @@ -590,7 +590,7 @@ class AD9910: def asf_to_amplitude(self, asf): """Return amplitude as a fraction of full scale corresponding to given amplitude scale factor.""" - return asf / float(0x3ffe) + return asf / float(0x3fff) @portable(flags={"fast-math"}) def frequency_to_ram(self, frequency, ram): From a18d2468e98672a8ae9e647affc70c1624a7606a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 10 Jun 2020 17:15:24 +0800 Subject: [PATCH 2182/2457] test: do not build libartiq_support in lit.cfg --- artiq/test/lit/lit.cfg | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/artiq/test/lit/lit.cfg b/artiq/test/lit/lit.cfg index 10497bdd0..693383297 100644 --- a/artiq/test/lit/lit.cfg +++ b/artiq/test/lit/lit.cfg @@ -2,7 +2,6 @@ import os import sys -import subprocess import lit.util import lit.formats @@ -27,16 +26,7 @@ not_ = "{} {}".format(sys.executable, os.path.join(root, "lit", "not.py")) config.substitutions.append( ("%not", not_) ) if os.name == "posix": - support_lib = os.getenv("LIBARTIQ_SUPPORT") - if not support_lib: - support_build = os.path.join(root, "libartiq_support") - if subprocess.call(["rustc", os.path.join(support_build, "lib.rs"), - "--out-dir", support_build, - "-Cpanic=unwind", "-g"]) != 0: - lit_config.fatal("Unable to build JIT support library") - - support_lib = os.path.join(support_build, "libartiq_support.so") - config.environment["LIBARTIQ_SUPPORT"] = support_lib + config.environment["LIBARTIQ_SUPPORT"] = os.getenv("LIBARTIQ_SUPPORT") config.environment["RUST_BACKTRACE"] = "1" config.available_features.add("exceptions") From 6156bd408874c114f7b5174b0a77ac75c1e0bd54 Mon Sep 17 00:00:00 2001 From: Harry Ho Date: Thu, 11 Jun 2020 13:44:40 +0800 Subject: [PATCH 2183/2457] fastino: add tests using DACs and USER LEDs --- artiq/frontend/artiq_sinara_tester.py | 45 +++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index fdf34c8a9..e0ffe757d 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -50,6 +50,7 @@ class SinaraTester(EnvExperiment): self.urukuls = dict() self.samplers = dict() self.zotinos = dict() + self.fastinos = dict() self.grabbers = dict() ddb = self.get_device_db() @@ -74,6 +75,8 @@ class SinaraTester(EnvExperiment): self.samplers[name] = self.get_device(name) elif (module, cls) == ("artiq.coredevice.zotino", "Zotino"): self.zotinos[name] = self.get_device(name) + elif (module, cls) == ("artiq.coredevice.fastino", "Fastino"): + self.fastinos[name] = self.get_device(name) elif (module, cls) == ("artiq.coredevice.grabber", "Grabber"): self.grabbers[name] = self.get_device(name) @@ -107,6 +110,7 @@ class SinaraTester(EnvExperiment): self.urukuls = sorted(self.urukuls.items(), key=lambda x: (x[1].cpld.bus.channel, x[1].chip_select)) self.samplers = sorted(self.samplers.items(), key=lambda x: x[1].cnv.channel) self.zotinos = sorted(self.zotinos.items(), key=lambda x: x[1].bus.channel) + self.fastinos = sorted(self.fastinos.items(), key=lambda x: x[1].channel) self.grabbers = sorted(self.grabbers.items(), key=lambda x: x[1].channel_base) @kernel @@ -330,6 +334,45 @@ class SinaraTester(EnvExperiment): print("Press ENTER when done.") input() + @kernel + def set_fastino_voltages(self, fastino, voltages): + self.core.break_realtime() + fastino.init() + delay(200*us) + i = 0 + for voltage in voltages: + fastino.set_dac(i, voltage) + delay(100*us) + i += 1 + + @kernel + def fastinos_led_wave(self, fastinos): + while not is_enter_pressed(): + self.core.break_realtime() + # do not fill the FIFOs too much to avoid long response times + t = now_mu() - self.core.seconds_to_mu(0.2) + while self.core.get_rtio_counter_mu() < t: + pass + for fastino in fastinos: + for i in range(8): + fastino.set_leds(1 << i) + delay(100*ms) + fastino.set_leds(0) + delay(100*ms) + + def test_fastinos(self): + print("*** Testing Fastino DACs and USER LEDs.") + print("Voltages:") + for card_n, (card_name, card_dev) in enumerate(self.fastinos): + voltages = [(-1)**i*(2.*card_n + .1*(i//2 + 1)) for i in range(32)] + print(card_name, " ".join(["{:.1f}".format(x) for x in voltages])) + self.set_fastino_voltages(card_dev, voltages) + print("Press ENTER when done.") + # Test switching on/off USR_LEDs at the same time + self.fastinos_led_wave( + [card_dev for _, (__, card_dev) in enumerate(self.fastinos)] + ) + @kernel def grabber_capture(self, card_dev, rois): self.core.break_realtime() @@ -380,6 +423,8 @@ class SinaraTester(EnvExperiment): self.test_samplers() if self.zotinos: self.test_zotinos() + if self.fastinos: + self.test_fastinos() if self.grabbers: self.test_grabbers() From 1a17d0c869f31163d42b79f9f206c2f5cbcadddd Mon Sep 17 00:00:00 2001 From: Harry Ho Date: Thu, 11 Jun 2020 15:48:21 +0800 Subject: [PATCH 2184/2457] zotino: add USER LED test --- artiq/frontend/artiq_sinara_tester.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index e0ffe757d..5aed406e4 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -324,15 +324,33 @@ class SinaraTester(EnvExperiment): i += 1 zotino.load() + @kernel + def zotinos_led_wave(self, zotinos): + while not is_enter_pressed(): + self.core.break_realtime() + # do not fill the FIFOs too much to avoid long response times + t = now_mu() - self.core.seconds_to_mu(0.2) + while self.core.get_rtio_counter_mu() < t: + pass + for zotino in zotinos: + for i in range(8): + zotino.set_leds(1 << i) + delay(100*ms) + zotino.set_leds(0) + delay(100*ms) + def test_zotinos(self): - print("*** Testing Zotino DACs.") + print("*** Testing Zotino DACs and USER LEDs.") print("Voltages:") for card_n, (card_name, card_dev) in enumerate(self.zotinos): voltages = [(-1)**i*(2.*card_n + .1*(i//2 + 1)) for i in range(32)] print(card_name, " ".join(["{:.1f}".format(x) for x in voltages])) self.set_zotino_voltages(card_dev, voltages) print("Press ENTER when done.") - input() + # Test switching on/off USR_LEDs at the same time + self.zotinos_led_wave( + [card_dev for _, (__, card_dev) in enumerate(self.zotinos)] + ) @kernel def set_fastino_voltages(self, fastino, voltages): From ce7e92a75e87db90639a56fcfc6f1610e4cddf0d Mon Sep 17 00:00:00 2001 From: charlesbaynham Date: Mon, 15 Jun 2020 17:43:34 +0100 Subject: [PATCH 2185/2457] docs: Add docs for RTIO SED sequencing (#1461) Signed-off-by: Charles Baynham --- doc/manual/rtio.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/manual/rtio.rst b/doc/manual/rtio.rst index beb57a5e1..67c8bdcaf 100644 --- a/doc/manual/rtio.rst +++ b/doc/manual/rtio.rst @@ -123,7 +123,7 @@ Sequence errors --------------- A sequence error happens when the sequence of coarse timestamps cannot be supported by the gateware. For example, there may have been too many timeline rewinds. -Internally, the gateware stores output events in an array of FIFO buffers (the "lanes") and the timestamps in each lane much be strictly increasing. The gateware selects a different lane when an event with a decreasing or equal timestamp is submitted. A sequence error occurs when no appropriate lane can be found. +Internally, the gateware stores output events in an array of FIFO buffers (the "lanes") and the timestamps in each lane must be strictly increasing. If an event with a decreasing or equal timestamp is submitted, the gateware selects the next lane, wrapping around if the final lane is reached. If this lane also contains an event with a timestamp beyond the one being submitted then a sequence error occurs. See `this issue `_ for a real-life example of how this works. Notes: @@ -131,6 +131,7 @@ Notes: * Configuring the gateware with more lanes for the RTIO core reduces the frequency of sequence errors. * The number of lanes is a hard limit on the number of simultaneous RTIO output events. * Whether a particular sequence of timestamps causes a sequence error or not is fully deterministic (starting from a known RTIO state, e.g. after a reset). Adding a constant offset to the whole sequence does not affect the result. +* Zero-duration methods (such as :meth:`artiq.coredevice.ttl.TTLOut.on()`) do not advance the timeline and so will consume additional lanes if they are scheduled simultaneously. Adding a tiny delay will prevent this (e.g. ``delay_mu(self.core.ref_multiplier)``, at least one coarse rtio cycle). The offending event is discarded and the RTIO core keeps operating. From 2429a266f63367655e7a76e31f297bb5582209a0 Mon Sep 17 00:00:00 2001 From: charlesbaynham Date: Tue, 16 Jun 2020 19:17:22 +0100 Subject: [PATCH 2186/2457] ad9912: Fix typing problem on ad9912 (#1466) Closes #1463 FTW and phase word were ambiguously typed, resulting in failure to compile --- artiq/coredevice/ad9912.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ad9912.py b/artiq/coredevice/ad9912.py index e21477308..fa88f2003 100644 --- a/artiq/coredevice/ad9912.py +++ b/artiq/coredevice/ad9912.py @@ -1,5 +1,6 @@ from numpy import int32, int64 +from artiq.language.types import TInt32, TInt64 from artiq.language.core import kernel, delay, portable from artiq.language.units import ms, us, ns from artiq.coredevice.ad9912_reg import * @@ -156,7 +157,7 @@ class AD9912: self.cpld.io_update.pulse(10*ns) @portable(flags={"fast-math"}) - def frequency_to_ftw(self, frequency): + def frequency_to_ftw(self, frequency) -> TInt64: """Returns the 48-bit frequency tuning word corresponding to the given frequency. """ @@ -170,7 +171,7 @@ class AD9912: return ftw/self.ftw_per_hz @portable(flags={"fast-math"}) - def turns_to_pow(self, phase): + def turns_to_pow(self, phase) -> TInt32: """Returns the 16-bit phase offset word corresponding to the given phase. """ From d87042597a8b44fd29beeec951a8c5a77c868791 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 15 Jun 2020 00:23:48 +0100 Subject: [PATCH 2187/2457] master/worker_impl: Factor out "completed" message sending [nfc] Just reduces the visual complexity/potential for typos a bit, and we already have put_exception_report(). --- artiq/master/worker_impl.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index e53ea9376..5ee78eb35 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -213,6 +213,11 @@ def setup_diagnostics(experiment_file, repository_path): artiq.coredevice.core._DiagnosticEngine.render_diagnostic = \ render_diagnostic + +def put_completed(): + put_object({"action": "completed"}) + + def put_exception_report(): _, exc, _ = sys.exc_info() # When we get CompileError, a more suitable diagnostic has already @@ -281,14 +286,14 @@ def main(): os.chdir(dirname) argument_mgr = ProcessArgumentManager(expid["arguments"]) exp_inst = exp((device_mgr, dataset_mgr, argument_mgr, {})) - put_object({"action": "completed"}) + put_completed() elif action == "prepare": exp_inst.prepare() - put_object({"action": "completed"}) + put_completed() elif action == "run": run_time = time.time() exp_inst.run() - put_object({"action": "completed"}) + put_completed() elif action == "analyze": try: exp_inst.analyze() @@ -297,7 +302,7 @@ def main(): # write results afterwards put_exception_report() else: - put_object({"action": "completed"}) + put_completed() elif action == "write_results": filename = "{:09}-{}.h5".format(rid, exp.__name__) with h5py.File(filename, "w") as f: @@ -307,10 +312,10 @@ def main(): f["start_time"] = start_time f["run_time"] = run_time f["expid"] = pyon.encode(expid) - put_object({"action": "completed"}) + put_completed() elif action == "examine": examine(ExamineDeviceMgr, ExamineDatasetMgr, obj["file"]) - put_object({"action": "completed"}) + put_completed() elif action == "terminate": break except: From 7955b63b002011497b05f715bb0c7eec4ba01a65 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 15 Jun 2020 00:37:07 +0100 Subject: [PATCH 2188/2457] master: Always write results to HDF5 once run stage is reached MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, a significant risk of losing experimental results would be associated with long-running experiments, as any stray exceptions while run()ing the experiment – for instance, due to infrequent network glitches or hardware reliability issue – would cause no HDF5 file to be written. This was especially troublesome as long experiments would suffer from a higher probability of unanticipated failures, while at the same time being more costly to re-take in terms of wall-clock time. Unanticipated uncaught exceptions like that were enough of an issue that several Oxford codebases had come up with their own half-baked mitigation strategies, from swallowing all exceptions in run() by convention, to always broadcasting all results to uniquely named datasets such that the partial results could be recovered and written to HDF5 by manually run recovery experiments. This commit addresses the problem at its source, changing the worker behaviour such that an HDF5 file is always written as soon as run() starts. --- RELEASE_NOTES.rst | 1 + artiq/master/scheduler.py | 10 ++-------- artiq/master/worker.py | 4 ---- artiq/master/worker_impl.py | 35 +++++++++++++++++++---------------- 4 files changed, 22 insertions(+), 28 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 503a6c675..bb287f4a5 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -16,6 +16,7 @@ Highlights: * `ad9910`: The maximum amplitude scale factor is now `0x3fff` (was `0x3ffe` before). * Applets now restart if they are running and a ccb call changes their spec +* Experiment results are now always saved to HDF5, even if run() fails. Breaking changes: diff --git a/artiq/master/scheduler.py b/artiq/master/scheduler.py index a1c16715f..7da7c401d 100644 --- a/artiq/master/scheduler.py +++ b/artiq/master/scheduler.py @@ -115,7 +115,6 @@ class Run: run = _mk_worker_method("run") resume = _mk_worker_method("resume") analyze = _mk_worker_method("analyze") - write_results = _mk_worker_method("write_results") class RunPool: @@ -309,13 +308,8 @@ class AnalyzeStage(TaskObject): try: await run.analyze() except: - logger.error("got worker exception in analyze stage of RID %d." - " Results will still be saved.", run.rid) - log_worker_exception() - try: - await run.write_results() - except: - logger.error("failed to write results of RID %d.", run.rid) + logger.error("got worker exception in analyze stage of RID %d.", + run.rid) log_worker_exception() self.delete_cb(run.rid) diff --git a/artiq/master/worker.py b/artiq/master/worker.py index 9480af8f4..36d5a202f 100644 --- a/artiq/master/worker.py +++ b/artiq/master/worker.py @@ -293,10 +293,6 @@ class Worker: async def analyze(self): await self._worker_action({"action": "analyze"}) - async def write_results(self, timeout=15.0): - await self._worker_action({"action": "write_results"}, - timeout) - async def examine(self, rid, file, timeout=20.0): self.rid = rid self.filename = os.path.basename(file) diff --git a/artiq/master/worker_impl.py b/artiq/master/worker_impl.py index 5ee78eb35..784e4297a 100644 --- a/artiq/master/worker_impl.py +++ b/artiq/master/worker_impl.py @@ -252,6 +252,16 @@ def main(): exp_inst = None repository_path = None + def write_results(): + filename = "{:09}-{}.h5".format(rid, exp.__name__) + with h5py.File(filename, "w") as f: + dataset_mgr.write_hdf5(f) + f["artiq_version"] = artiq_version + f["rid"] = rid + f["start_time"] = start_time + f["run_time"] = run_time + f["expid"] = pyon.encode(expid) + device_mgr = DeviceManager(ParentDeviceDB, virtual_devices={"scheduler": Scheduler(), "ccb": CCB()}) @@ -292,27 +302,20 @@ def main(): put_completed() elif action == "run": run_time = time.time() - exp_inst.run() + try: + exp_inst.run() + except: + # Only write results in run() on failure; on success wait + # for end of analyze stage. + write_results() + raise put_completed() elif action == "analyze": try: exp_inst.analyze() - except: - # make analyze failure non-fatal, as we may still want to - # write results afterwards - put_exception_report() - else: put_completed() - elif action == "write_results": - filename = "{:09}-{}.h5".format(rid, exp.__name__) - with h5py.File(filename, "w") as f: - dataset_mgr.write_hdf5(f) - f["artiq_version"] = artiq_version - f["rid"] = rid - f["start_time"] = start_time - f["run_time"] = run_time - f["expid"] = pyon.encode(expid) - put_completed() + finally: + write_results() elif action == "examine": examine(ExamineDeviceMgr, ExamineDatasetMgr, obj["file"]) put_completed() From 966ed5d0135cd32f7f4cdbba049cc28a394c6884 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 19 Jun 2020 05:16:08 +0100 Subject: [PATCH 2189/2457] master/scheduler: Fix priority/due date precedence order when waiting to prepare MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See test case – previously, the highest-priority pending run would be used to calculate the timeout, rather than the earliest one. This probably managed to go undetected for that long as any unrelated changes to the pipeline (e.g. new submissions, or experiments pausing) would also cause _get_run() to be re-evaluated. --- artiq/master/scheduler.py | 70 +++++++-------- artiq/test/test_scheduler.py | 168 ++++++++++++++++++++++++++++++++++- 2 files changed, 200 insertions(+), 38 deletions(-) diff --git a/artiq/master/scheduler.py b/artiq/master/scheduler.py index 7da7c401d..d978fa2f9 100644 --- a/artiq/master/scheduler.py +++ b/artiq/master/scheduler.py @@ -87,17 +87,12 @@ class Run: self._notifier[self.rid]["status"] = self._status.name self._state_changed.notify() - # The run with the largest priority_key is to be scheduled first - def priority_key(self, now=None): - if self.due_date is None: - due_date_k = 0 - else: - due_date_k = -self.due_date - if now is not None and self.due_date is not None: - runnable = int(now > self.due_date) - else: - runnable = 1 - return (runnable, self.priority, due_date_k, -self.rid) + def priority_key(self): + """Return a comparable value that defines a run priority order. + + Applies only to runs the due date of which has already elapsed. + """ + return (self.priority, -(self.due_date or 0), -self.rid) async def close(self): # called through pool @@ -161,36 +156,37 @@ class PrepareStage(TaskObject): self.delete_cb = delete_cb def _get_run(self): - """If a run should get prepared now, return it. - Otherwise, return a float representing the time before the next timed - run becomes due, or None if there is no such run.""" + """If a run should get prepared now, return it. Otherwise, return a + float giving the time until the next check, or None if no time-based + check is required. + + The latter can be the case if there are no due-date runs, or none + of them are going to become next-in-line before further pool state + changes (which will also cause a re-evaluation). + """ + pending_runs = list( + filter(lambda r: r.status == RunStatus.pending, + self.pool.runs.values())) + now = time() - pending_runs = filter(lambda r: r.status == RunStatus.pending, - self.pool.runs.values()) - try: - candidate = max(pending_runs, key=lambda r: r.priority_key(now)) - except ValueError: - # pending_runs is an empty sequence - return None + def is_runnable(r): + return (r.due_date or 0) < now - prepared_runs = filter(lambda r: r.status == RunStatus.prepare_done, - self.pool.runs.values()) - try: - top_prepared_run = max(prepared_runs, - key=lambda r: r.priority_key()) - except ValueError: - # there are no existing prepared runs - go ahead with - pass - else: - # prepare (as well) only if it has higher priority than - # the highest priority prepared run - if top_prepared_run.priority_key() >= candidate.priority_key(): - return None + prepared_max = max((r.priority_key() for r in self.pool.runs.values() + if r.status == RunStatus.prepare_done), + default=None) + def takes_precedence(r): + return prepared_max is None or r.priority_key() > prepared_max - if candidate.due_date is None or candidate.due_date < now: + candidate = max(filter(is_runnable, pending_runs), + key=lambda r: r.priority_key(), + default=None) + if candidate is not None and takes_precedence(candidate): return candidate - else: - return candidate.due_date - now + + return min((r.due_date - now for r in pending_runs + if (not is_runnable(r) and takes_precedence(r))), + default=None) async def _do(self): while True: diff --git a/artiq/test/test_scheduler.py b/artiq/test/test_scheduler.py index e9cc3ceee..ad4f243bd 100644 --- a/artiq/test/test_scheduler.py +++ b/artiq/test/test_scheduler.py @@ -28,7 +28,18 @@ class BackgroundExperiment(EnvExperiment): sleep(0.2) except TerminationRequested: self.set_dataset("termination_ok", True, - broadcast=True, save=False) + broadcast=True, archive=False) + + +class CheckPauseBackgroundExperiment(EnvExperiment): + def build(self): + self.setattr_device("scheduler") + + def run(self): + while True: + while not self.scheduler.check_pause(): + sleep(0.2) + self.scheduler.pause() def _get_expid(name): @@ -117,6 +128,161 @@ class SchedulerCase(unittest.TestCase): scheduler.notifier.publish = None loop.run_until_complete(scheduler.stop()) + def test_pending_priority(self): + """Check due dates take precedence over priorities when waiting to + prepare.""" + loop = self.loop + handlers = {} + scheduler = Scheduler(_RIDCounter(0), handlers, None) + handlers["scheduler_check_pause"] = scheduler.check_pause + + expid_empty = _get_expid("EmptyExperiment") + + expid_bg = _get_expid("CheckPauseBackgroundExperiment") + # Suppress the SystemExit backtrace when worker process is killed. + expid_bg["log_level"] = logging.CRITICAL + + high_priority = 3 + middle_priority = 2 + low_priority = 1 + late = time() + 100000 + early = time() + 1 + + expect = [ + { + "path": [], + "action": "setitem", + "value": { + "repo_msg": None, + "priority": low_priority, + "pipeline": "main", + "due_date": None, + "status": "pending", + "expid": expid_bg, + "flush": False + }, + "key": 0 + }, + { + "path": [], + "action": "setitem", + "value": { + "repo_msg": None, + "priority": high_priority, + "pipeline": "main", + "due_date": late, + "status": "pending", + "expid": expid_empty, + "flush": False + }, + "key": 1 + }, + { + "path": [], + "action": "setitem", + "value": { + "repo_msg": None, + "priority": middle_priority, + "pipeline": "main", + "due_date": early, + "status": "pending", + "expid": expid_empty, + "flush": False + }, + "key": 2 + }, + { + "path": [0], + "action": "setitem", + "value": "preparing", + "key": "status" + }, + { + "path": [0], + "action": "setitem", + "value": "prepare_done", + "key": "status" + }, + { + "path": [0], + "action": "setitem", + "value": "running", + "key": "status" + }, + { + "path": [2], + "action": "setitem", + "value": "preparing", + "key": "status" + }, + { + "path": [2], + "action": "setitem", + "value": "prepare_done", + "key": "status" + }, + { + "path": [0], + "action": "setitem", + "value": "paused", + "key": "status" + }, + { + "path": [2], + "action": "setitem", + "value": "running", + "key": "status" + }, + { + "path": [2], + "action": "setitem", + "value": "run_done", + "key": "status" + }, + { + "path": [0], + "action": "setitem", + "value": "running", + "key": "status" + }, + { + "path": [2], + "action": "setitem", + "value": "analyzing", + "key": "status" + }, + { + "path": [2], + "action": "setitem", + "value": "deleting", + "key": "status" + }, + { + "path": [], + "action": "delitem", + "key": 2 + }, + ] + done = asyncio.Event() + expect_idx = 0 + def notify(mod): + nonlocal expect_idx + self.assertEqual(mod, expect[expect_idx]) + expect_idx += 1 + if expect_idx >= len(expect): + done.set() + scheduler.notifier.publish = notify + + scheduler.start() + + scheduler.submit("main", expid_bg, low_priority) + scheduler.submit("main", expid_empty, high_priority, late) + scheduler.submit("main", expid_empty, middle_priority, early) + + loop.run_until_complete(done.wait()) + scheduler.notifier.publish = None + loop.run_until_complete(scheduler.stop()) + def test_pause(self): loop = self.loop From 4ad46e0e409a3ba057b2c377b01eb772c50db84e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 20 Jun 2020 19:26:31 +0800 Subject: [PATCH 2190/2457] update Conda installation method --- doc/manual/installing.rst | 16 +++++++------- install-with-conda.py | 46 --------------------------------------- 2 files changed, 8 insertions(+), 54 deletions(-) delete mode 100644 install-with-conda.py diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 302592f1f..3eb864cc9 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -101,17 +101,17 @@ After installing either Anaconda or Miniconda, open a new terminal (also known a Executing just ``conda`` should print the help of the ``conda`` command. If your shell does not find the ``conda`` command, make sure that the Conda binaries are in your ``$PATH``. If ``$ echo $PATH`` does not show the Conda directories, add them: execute ``$ export PATH=$HOME/miniconda3/bin:$PATH`` if you installed Conda into ``~/miniconda3``. -Download the `ARTIQ installer script `_ and edit its beginning to define the Conda environment name (you can leave the default environment name if you are just getting started) and select the desired ARTIQ packages. Non-ARTIQ packages should be installed manually later. +Controllers for third-party devices (e.g. Thorlabs TCube, Lab Brick Digital Attenuator, etc.) that are not shipped with ARTIQ can also be installed with this script. Browse `Hydra `_ or see the list of NDSPs in this manual to find the names of the corresponding packages, and list them at the beginning of the script. + +Set up the Conda channel and install ARTIQ into a new Conda environment: :: + + $ conda config --prepend channels https://conda.m-labs.hk/artiq-beta + $ conda config --append channels conda-forge + $ conda install -n artiq artiq .. note:: If you do not need to flash boards, the ``artiq`` package is sufficient. The packages named ``artiq-board-*`` contain only firmware for the FPGA board and are never necessary for using an ARTIQ system without reflashing it. -Controllers for third-party devices (e.g. Thorlabs TCube, Lab Brick Digital Attenuator, etc.) that are not shipped with ARTIQ can also be installed with this script. Browse `Hydra `_ or see the list of NDSPs in this manual to find the names of the corresponding packages, and list them at the beginning of the script. - -Make sure the base Conda environment is activated and then run the installer script: :: - - $ conda activate base - $ python install-with-conda.py After the installation, activate the newly created environment by name. :: @@ -137,7 +137,7 @@ Upgrading ARTIQ (with Conda) When upgrading ARTIQ or when testing different versions it is recommended that new Conda environments are created instead of upgrading the packages in existing environments. Keep previous environments around until you are certain that they are not needed anymore and a new environment is known to work correctly. -To install the latest version, just select a different environment name and run the installer script again. +To install the latest version, just select a different environment name and run the installation command again. Switching between Conda environments using commands such as ``$ conda deactivate artiq-6`` and ``$ conda activate artiq-5`` is the recommended way to roll back to previous versions of ARTIQ. diff --git a/install-with-conda.py b/install-with-conda.py deleted file mode 100644 index fb09ad3ab..000000000 --- a/install-with-conda.py +++ /dev/null @@ -1,46 +0,0 @@ -# This script installs ARTIQ using the conda packages built by the new Nix/Hydra system. -# It needs to be run in the root (base) conda environment with "python install-with-conda.py" -# It supports Linux and Windows, but Linux users should consider using the higher-quality -# Nix package manager instead of Conda. - -# EDIT THIS: -# The name of the conda environment to create -CONDA_ENV_NAME = "artiq" -# The conda packages to download and install. -CONDA_PACKAGES = [ - "artiq", - "artiq-comtools", - # Only install board packages if you plan to reflash the board. - # The two lines below are just examples and probably not what you want. - # Select the packages that correspond to your board, or remove them - # if you do not intend to reflash the board. - "artiq-board-kc705-nist_clock", - "artiq-board-kasli-wipm" -] -# Set to False if you have already set up conda channels -ADD_CHANNELS = True - -# PROXY: If you are behind a web proxy, configure it in your .condarc (as per -# the conda manual). - -# You should not need to modify the rest of the script below. - -import os - -def run(command): - r = os.system(command) - if r != 0: - raise SystemExit("command '{}' returned non-zero exit status: {}".format(command, r)) - -if ADD_CHANNELS: - run("conda config --prepend channels m-labs") - run("conda config --prepend channels https://conda.m-labs.hk/artiq-beta") - run("conda config --append channels conda-forge") - -# Creating the environment first with python 3.5 hits fewer bugs in conda's broken dependency solver. -run("conda create -y -n {CONDA_ENV_NAME} python=3.5".format(CONDA_ENV_NAME=CONDA_ENV_NAME)) -for package in CONDA_PACKAGES: - # Do not activate the environment yet - otherwise "conda install" may not find the SSL module anymore on Windows. - # Installing into the environment from the outside works around this conda bug. - run("conda install -y -n {CONDA_ENV_NAME} -c https://conda.m-labs.hk/artiq-beta {package}" - .format(CONDA_ENV_NAME=CONDA_ENV_NAME, package=package)) From 91c93e1ad89d4bea03b5c61999e71d3f3784dc84 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 20 Jun 2020 19:32:13 +0800 Subject: [PATCH 2191/2457] manual: add note about additional packages --- doc/manual/installing.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 3eb864cc9..dc5cd6b87 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -110,8 +110,7 @@ Set up the Conda channel and install ARTIQ into a new Conda environment: :: $ conda install -n artiq artiq .. note:: - If you do not need to flash boards, the ``artiq`` package is sufficient. The packages named ``artiq-board-*`` contain only firmware for the FPGA board and are never necessary for using an ARTIQ system without reflashing it. - + If you do not need to flash boards, the ``artiq`` package is sufficient. The packages named ``artiq-board-*`` contain only firmware for the FPGA board and are never necessary for using an ARTIQ system without reflashing it. Controllers for third-party devices (e.g. Thorlabs TCube, Lab Brick Digital Attenuator, etc.) that are not shipped with ARTIQ can also be installed with this script. Browse `Hydra `_ or see the list of NDSPs in this manual to find the names of the corresponding packages. After the installation, activate the newly created environment by name. :: From f36692638c41d549519507fbf9dc875cbd8482ae Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 25 Jun 2020 16:38:27 +0100 Subject: [PATCH 2192/2457] dashboard: Add "Quick Open" dialog for experiments on global shortcut This is similar to functionality in Sublime Text, VS Code, etc. --- RELEASE_NOTES.rst | 6 +- artiq/dashboard/experiments.py | 75 ++++++++- artiq/gui/fuzzy_select.py | 272 +++++++++++++++++++++++++++++++++ 3 files changed, 351 insertions(+), 2 deletions(-) create mode 100644 artiq/gui/fuzzy_select.py diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index bb287f4a5..bdc55724d 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -15,7 +15,11 @@ Highlights: * Zotino now exposes `voltage_to_mu()` * `ad9910`: The maximum amplitude scale factor is now `0x3fff` (was `0x3ffe` before). -* Applets now restart if they are running and a ccb call changes their spec +* Dashboard: + - Applets now restart if they are running and a ccb call changes their spec + - A "Quick Open" dialog to open experiments by typing part of their name can + be brought up Ctrl-P (Ctrl+Return to immediately submit the selected entry + with the default arguments). * Experiment results are now always saved to HDF5, even if run() fails. Breaking changes: diff --git a/artiq/dashboard/experiments.py b/artiq/dashboard/experiments.py index 57aaf6af6..d4a7d788a 100644 --- a/artiq/dashboard/experiments.py +++ b/artiq/dashboard/experiments.py @@ -9,8 +9,9 @@ import h5py from sipyco import pyon -from artiq.gui.tools import LayoutWidget, log_level_to_name, get_open_file_name from artiq.gui.entries import procdesc_to_entry, ScanEntry +from artiq.gui.fuzzy_select import FuzzySelectWidget +from artiq.gui.tools import LayoutWidget, log_level_to_name, get_open_file_name logger = logging.getLogger(__name__) @@ -488,6 +489,60 @@ class _ExperimentDock(QtWidgets.QMdiSubWindow): self.hdf5_load_directory = state["hdf5_load_directory"] +class _QuickOpenDialog(QtWidgets.QDialog): + """Modal dialog for opening/submitting experiments from a + FuzzySelectWidget.""" + closed = QtCore.pyqtSignal() + + def __init__(self, manager): + super().__init__(manager.main_window) + self.setModal(True) + + self.manager = manager + + self.setWindowTitle("Quick open…") + + layout = QtWidgets.QGridLayout(self) + layout.setSpacing(0) + layout.setContentsMargins(0, 0, 0, 0) + self.setLayout(layout) + + # Find matching experiment names. Open experiments are preferred to + # matches from the repository to ease quick window switching. + open_exps = list(self.manager.open_experiments.keys()) + repo_exps = set("repo:" + k + for k in self.manager.explist.keys()) - set(open_exps) + choices = [(o, 100) for o in open_exps] + [(r, 0) for r in repo_exps] + + self.select_widget = FuzzySelectWidget(choices) + layout.addWidget(self.select_widget) + self.select_widget.aborted.connect(self.close) + self.select_widget.finished.connect(self._open_experiment) + + font_metrics = QtGui.QFontMetrics(self.select_widget.line_edit.font()) + self.select_widget.setMinimumWidth(font_metrics.averageCharWidth() * 70) + + def done(self, r): + if self.select_widget: + self.select_widget.abort() + self.closed.emit() + QtWidgets.QDialog.done(self, r) + + def _open_experiment(self, exp_name, modifiers): + if modifiers & QtCore.Qt.ControlModifier: + try: + self.manager.submit(exp_name) + except: + # Not all open_experiments necessarily still exist in the explist + # (e.g. if the repository has been re-scanned since). + logger.warning("failed to submit experiment '%s'", + exp_name, + exc_info=True) + else: + self.manager.open_experiment(exp_name) + self.close() + + class ExperimentManager: def __init__(self, main_window, explist_sub, schedule_sub, @@ -508,6 +563,13 @@ class ExperimentManager: self.open_experiments = dict() + self.is_quick_open_shown = False + quick_open_shortcut = QtWidgets.QShortcut( + QtCore.Qt.CTRL + QtCore.Qt.Key_P, + main_window) + quick_open_shortcut.setContext(QtCore.Qt.ApplicationShortcut) + quick_open_shortcut.activated.connect(self.show_quick_open) + def set_explist_model(self, model): self.explist = model.backing_store @@ -708,3 +770,14 @@ class ExperimentManager: self.submission_arguments = state["arguments"] for expurl in state["open_docks"]: self.open_experiment(expurl) + + def show_quick_open(self): + if self.is_quick_open_shown: + return + + self.is_quick_open_shown = True + dialog = _QuickOpenDialog(self) + def closed(): + self.is_quick_open_shown = False + dialog.closed.connect(closed) + dialog.show() diff --git a/artiq/gui/fuzzy_select.py b/artiq/gui/fuzzy_select.py new file mode 100644 index 000000000..abbe31dae --- /dev/null +++ b/artiq/gui/fuzzy_select.py @@ -0,0 +1,272 @@ +import re + +from functools import partial +from typing import List, Tuple +from PyQt5 import QtCore, QtWidgets + +from artiq.gui.tools import LayoutWidget + + +class FuzzySelectWidget(LayoutWidget): + """Widget to select from a list of pre-defined choices by typing in a + substring match (cf. Ctrl+P "Quick Open"/"Goto anything" functions in + editors/IDEs). + """ + + #: Raised when the selection process is aborted by the user (Esc, loss of + #: focus, etc.). + aborted = QtCore.pyqtSignal() + + #: Raised when an entry has been selected, giving the label of the user + #: choice and any additional QEvent.modifiers() (e.g. Ctrl key pressed). + finished = QtCore.pyqtSignal(str, int) + + def __init__(self, + choices: List[Tuple[str, int]] = [], + entry_count_limit: int = 10, + *args): + """ + :param choices: The choices the user can select from, given as tuples + of labels to display and an additional weight added to the + fuzzy-matching score. + :param entry_count_limit: Maximum number of entries to show. + """ + super().__init__(*args) + self.choices = choices + self.entry_count_limit = entry_count_limit + assert entry_count_limit >= 2, ("Need to allow at least two entries " + + "to show the ' not shown' hint") + + self.line_edit = QtWidgets.QLineEdit(self) + self.layout.addWidget(self.line_edit) + + line_edit_focus_filter = _FocusEventFilter(self.line_edit) + line_edit_focus_filter.focus_gained.connect(self._activate) + line_edit_focus_filter.focus_lost.connect(self._line_edit_focus_lost) + self.line_edit.installEventFilter(line_edit_focus_filter) + self.line_edit.textChanged.connect(self._update_menu) + + escape_filter = _EscapeKeyFilter(self) + escape_filter.escape_pressed.connect(self.abort) + self.line_edit.installEventFilter(escape_filter) + + self.menu = None + + self.update_when_text_changed = True + self.menu_typing_filter = None + self.line_edit_up_down_filter = None + self.abort_when_menu_hidden = False + self.abort_when_line_edit_unfocussed = True + + def set_choices(self, choices: List[Tuple[str, int]]) -> None: + """Update the list of choices available to the user.""" + self.choices = choices + if self.menu: + self._update_menu() + + def _activate(self): + self.update_when_text_changed = True + if not self.menu: + # Show menu after initial layout is complete. + QtCore.QTimer.singleShot(0, self._update_menu) + + def _ensure_menu(self): + if self.menu: + return + + self.menu = QtWidgets.QMenu(self) + + # Display menu with search results beneath line edit. + menu_pos = self.line_edit.mapToGlobal(self.line_edit.pos()) + menu_pos.setY(menu_pos.y() + self.line_edit.height()) + + self.menu.popup(menu_pos) + self.menu.aboutToHide.connect(self._menu_hidden) + + def _menu_hidden(self): + if self.abort_when_menu_hidden: + self.abort_when_menu_hidden = False + self.abort() + + def _line_edit_focus_lost(self): + if self.abort_when_line_edit_unfocussed: + self.abort() + + def _update_menu(self): + if not self.update_when_text_changed: + return + + filtered_choices = self._filter_choices() + + if not filtered_choices: + # No matches, don't display menu at all. + if self.menu: + self.abort_when_menu_hidden = False + self.menu.close() + self.menu = None + self.abort_when_line_edit_unfocussed = True + self.line_edit.setFocus() + return + + # Truncate the list, leaving room for the " not shown" entry. + num_omitted = 0 + if len(filtered_choices) > self.entry_count_limit: + num_omitted = len(filtered_choices) - (self.entry_count_limit - 1) + filtered_choices = filtered_choices[:self.entry_count_limit - 1] + + # We are going to end up with a menu shown and the line edit losing + # focus. + self.abort_when_line_edit_unfocussed = False + + if self.menu: + # Hide menu temporarily to avoid re-layouting on every added item. + self.abort_when_menu_hidden = False + self.menu.hide() + self.menu.clear() + + self._ensure_menu() + + first_action = None + last_action = None + for choice in filtered_choices: + action = QtWidgets.QAction(choice, self.menu) + action.triggered.connect(partial(self._finish, action, choice)) + action.modifiers = 0 + self.menu.addAction(action) + if not first_action: + first_action = action + last_action = action + + if num_omitted > 0: + action = QtWidgets.QAction("<{} not shown>".format(num_omitted), + self.menu) + action.setEnabled(False) + self.menu.addAction(action) + + if self.menu_typing_filter: + self.menu.removeEventFilter(self.menu_typing_filter) + self.menu_typing_filter = _NonUpDownKeyFilter(self.menu, + self.line_edit) + self.menu.installEventFilter(self.menu_typing_filter) + + if self.line_edit_up_down_filter: + self.line_edit.removeEventFilter(self.line_edit_up_down_filter) + self.line_edit_up_down_filter = _UpDownKeyFilter( + self.line_edit, self.menu, first_action, last_action) + self.line_edit.installEventFilter(self.line_edit_up_down_filter) + + self.abort_when_menu_hidden = True + self.menu.show() + if first_action: + self.menu.setActiveAction(first_action) + self.menu.setFocus() + else: + self.line_edit.setFocus() + + def _filter_choices(self): + """Return a filtered and ranked list of choices based on the current + user input. + + For a choice not to be filtered out, it needs to contain the entered + characters in order. Entries are further sorted by the length of the + match (i.e. preferring matches where the entered string occurrs + without interruptions), then the position of the match, and finally + lexicographically. + """ + # TODO: More SublimeText-like heuristics taking capital letters and + # punctuation into account. Also, requiring the matches to be in order + # seems to be a bit annoying in practice. + text = self.line_edit.text() + suggestions = [] + # `re` seems to be the fastest way of matching this in CPython, even + # with all the wildcards. + pat = '.*?'.join(map(re.escape, text.lower())) + regex = re.compile(pat) + for label, weight in self.choices: + r = regex.search(label.lower()) + if r: + suggestions.append((len(r.group()) - weight, r.start(), label)) + return [x for _, _, x in sorted(suggestions)] + + def _close(self): + if self.menu: + self.menu.close() + self.menu = None + self.update_when_text_changed = False + self.line_edit.clear() + + def abort(self): + self._close() + self.aborted.emit() + + def _finish(self, action, name): + self._close() + self.finished.emit(name, action.modifiers) + + +class _FocusEventFilter(QtCore.QObject): + """Emits signals when focus is gained/lost.""" + focus_gained = QtCore.pyqtSignal() + focus_lost = QtCore.pyqtSignal() + + def eventFilter(self, obj, event): + if event.type() == QtCore.QEvent.FocusIn: + self.focus_gained.emit() + elif event.type() == QtCore.QEvent.FocusOut: + self.focus_lost.emit() + return False + + +class _EscapeKeyFilter(QtCore.QObject): + """Emits a signal if the Escape key is pressed.""" + escape_pressed = QtCore.pyqtSignal() + + def eventFilter(self, obj, event): + if event.type() == QtCore.QEvent.KeyPress: + if event.key() == QtCore.Qt.Key_Escape: + self.escape_pressed.emit() + return False + + +class _UpDownKeyFilter(QtCore.QObject): + """Handles focussing the menu when pressing up/down in the line edit.""" + def __init__(self, parent, menu, first_item, last_item): + super().__init__(parent) + self.menu = menu + self.first_item = first_item + self.last_item = last_item + + def eventFilter(self, obj, event): + if event.type() == QtCore.QEvent.KeyPress: + if event.key() == QtCore.Qt.Key_Down: + self.menu.setActiveAction(self.first_item) + self.menu.setFocus() + return True + + if event.key() == QtCore.Qt.Key_Up: + self.menu.setActiveAction(self.last_item) + self.menu.setFocus() + return True + return False + + +class _NonUpDownKeyFilter(QtCore.QObject): + """Forwards input while the menu is focussed to the line edit.""" + def __init__(self, parent, target): + super().__init__(parent) + self.target = target + + def eventFilter(self, obj, event): + if event.type() == QtCore.QEvent.KeyPress: + k = event.key() + if k in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter): + action = obj.activeAction() + if action is not None: + action.modifiers = event.modifiers() + return False + if (k != QtCore.Qt.Key_Down and k != QtCore.Qt.Key_Up + and k != QtCore.Qt.Key_Enter + and k != QtCore.Qt.Key_Return): + QtWidgets.QApplication.sendEvent(self.target, event) + return True + return False From 89c53c35e8b3925bc91e0b75165c7963515f5def Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 26 Jun 2020 10:12:03 +0800 Subject: [PATCH 2193/2457] dashboard: style --- artiq/dashboard/experiments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/dashboard/experiments.py b/artiq/dashboard/experiments.py index d4a7d788a..6095a3466 100644 --- a/artiq/dashboard/experiments.py +++ b/artiq/dashboard/experiments.py @@ -500,7 +500,7 @@ class _QuickOpenDialog(QtWidgets.QDialog): self.manager = manager - self.setWindowTitle("Quick open…") + self.setWindowTitle("Quick open...") layout = QtWidgets.QGridLayout(self) layout.setSpacing(0) From fb6a8899f4c5d894ad8aace7ec7a446e24bbe70a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 26 Jun 2020 10:47:55 +0800 Subject: [PATCH 2194/2457] manual: use conda env creation command --- doc/manual/installing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index dc5cd6b87..223311c8c 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -107,7 +107,7 @@ Set up the Conda channel and install ARTIQ into a new Conda environment: :: $ conda config --prepend channels https://conda.m-labs.hk/artiq-beta $ conda config --append channels conda-forge - $ conda install -n artiq artiq + $ conda create -n artiq artiq .. note:: If you do not need to flash boards, the ``artiq`` package is sufficient. The packages named ``artiq-board-*`` contain only firmware for the FPGA board and are never necessary for using an ARTIQ system without reflashing it. Controllers for third-party devices (e.g. Thorlabs TCube, Lab Brick Digital Attenuator, etc.) that are not shipped with ARTIQ can also be installed with this script. Browse `Hydra `_ or see the list of NDSPs in this manual to find the names of the corresponding packages. From 5d58a195c002cb5bad293c77e5545f119066d7bf Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 26 Jun 2020 10:49:31 +0800 Subject: [PATCH 2195/2457] manual: clarify board package installation --- doc/manual/installing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 223311c8c..1c9f30eea 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -110,7 +110,7 @@ Set up the Conda channel and install ARTIQ into a new Conda environment: :: $ conda create -n artiq artiq .. note:: - If you do not need to flash boards, the ``artiq`` package is sufficient. The packages named ``artiq-board-*`` contain only firmware for the FPGA board and are never necessary for using an ARTIQ system without reflashing it. Controllers for third-party devices (e.g. Thorlabs TCube, Lab Brick Digital Attenuator, etc.) that are not shipped with ARTIQ can also be installed with this script. Browse `Hydra `_ or see the list of NDSPs in this manual to find the names of the corresponding packages. + If you do not need to flash boards, the ``artiq`` package is sufficient. The packages named ``artiq-board-*`` contain only firmware for the FPGA board, and you should not install them unless you are reflashing an FPGA board. Controllers for third-party devices (e.g. Thorlabs TCube, Lab Brick Digital Attenuator, etc.) that are not shipped with ARTIQ can also be installed with this script. Browse `Hydra `_ or see the list of NDSPs in this manual to find the names of the corresponding packages. After the installation, activate the newly created environment by name. :: From 906256cc02b5142e1ef6993c14d15af06d9e998a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 26 Jun 2020 10:50:11 +0800 Subject: [PATCH 2196/2457] manual: remove reference to conda install script --- doc/manual/installing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 1c9f30eea..a812e82cf 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -110,7 +110,7 @@ Set up the Conda channel and install ARTIQ into a new Conda environment: :: $ conda create -n artiq artiq .. note:: - If you do not need to flash boards, the ``artiq`` package is sufficient. The packages named ``artiq-board-*`` contain only firmware for the FPGA board, and you should not install them unless you are reflashing an FPGA board. Controllers for third-party devices (e.g. Thorlabs TCube, Lab Brick Digital Attenuator, etc.) that are not shipped with ARTIQ can also be installed with this script. Browse `Hydra `_ or see the list of NDSPs in this manual to find the names of the corresponding packages. + If you do not need to flash boards, the ``artiq`` package is sufficient. The packages named ``artiq-board-*`` contain only firmware for the FPGA board, and you should not install them unless you are reflashing an FPGA board. Controllers for third-party devices (e.g. Thorlabs TCube, Lab Brick Digital Attenuator, etc.) that are not shipped with ARTIQ can also be installed with Conda. Browse `Hydra `_ or see the list of NDSPs in this manual to find the names of the corresponding packages. After the installation, activate the newly created environment by name. :: From 95807234d9b49b1609c6da714906de778a2bd3e9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 28 Jun 2020 17:32:28 +0800 Subject: [PATCH 2197/2457] compiler: use binutils for ARM This is mostly due to Windoze, where installing anything is a PITA and the LLVM tools won't be available soon. --- artiq/compiler/targets.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index e44024177..9b985c32e 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -275,3 +275,8 @@ class CortexA9Target(Target): print_function = "core_log" little_endian = True now_pinning = False + + tool_ld = "armv7-unknown-linux-gnueabihf-ld" + tool_strip = "armv7-unknown-linux-gnueabihf-strip" + tool_addr2line = "armv7-unknown-linux-gnueabihf-addr2line" + tool_cxxfilt = "armv7-unknown-linux-gnueabihf-c++filt" From 3f0cf6e683b94ce1fb18beb2b1a8bc5cf8cb0f9d Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 30 Jun 2020 21:44:36 +0100 Subject: [PATCH 2198/2457] runtime: Stop kernel CPU before restarting comms CPU on panic Before, the system would enter a boot loop when a panic occurred while the kernel CPU was active (and panic_reset == 1), as kernel::start() for the startup kernel would panic. --- RELEASE_NOTES.rst | 2 ++ artiq/firmware/runtime/main.rs | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index bdc55724d..3a9a6d21a 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -21,6 +21,8 @@ Highlights: be brought up Ctrl-P (Ctrl+Return to immediately submit the selected entry with the default arguments). * Experiment results are now always saved to HDF5, even if run() fails. +* Core device: ``panic_reset 1`` now correctly resets the kernel CPU as well if + communication CPU panic occurs. Breaking changes: diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index b40c0d097..fda9d37ba 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -323,7 +323,10 @@ pub fn panic_impl(info: &core::panic::PanicInfo) -> ! { if config::read_str("panic_reset", |r| r == Ok("1")) { println!("restarting..."); - unsafe { boot::reset() } + unsafe { + kernel::stop(); + boot::reset(); + } } else { println!("halting."); println!("use `artiq_coremgmt config write -s panic_reset 1` to restart instead"); From f265976df62ec5bc358de68f8808ade96198ae15 Mon Sep 17 00:00:00 2001 From: Donald Sebastian Leung Date: Fri, 3 Jul 2020 15:55:11 +0800 Subject: [PATCH 2199/2457] i2c: duplicate TCA9548 control byte --- artiq/firmware/libboard_misoc/i2c.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/libboard_misoc/i2c.rs b/artiq/firmware/libboard_misoc/i2c.rs index acade0c24..9e62a97ff 100644 --- a/artiq/firmware/libboard_misoc/i2c.rs +++ b/artiq/firmware/libboard_misoc/i2c.rs @@ -183,8 +183,11 @@ mod imp { if !write(busno, address << 1)? { return Err("PCA9548 failed to ack write address") } - if !write(busno, channels)? { - return Err("PCA9548 failed to ack control word") + // Duplicate control byte: one for SCL, one for SDA + for _ in 0..2 { + if !write(busno, channels)? { + return Err("PCA9548 failed to ack control word") + } } stop(busno)?; Ok(()) From 13501115f6b9c6916d030edcfe99e76afea4e2e6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 7 Jul 2020 17:27:43 +0800 Subject: [PATCH 2200/2457] test: remove watchdog test (#1458) --- artiq/test/coredevice/test_rtio.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 1e7693cf5..c6f42366a 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -170,17 +170,6 @@ class PulseRateAD9914DDS(EnvExperiment): return -class Watchdog(EnvExperiment): - def build(self): - self.setattr_device("core") - - @kernel - def run(self): - with watchdog(50*ms): - while True: - pass - - class LoopbackCount(EnvExperiment): def build(self, npulses): self.setattr_device("core") @@ -522,11 +511,6 @@ class CoredeviceTest(ExperimentCase): def test_address_collision(self): self.execute_and_test_in_log(AddressCollision, "RTIO collision") - def test_watchdog(self): - # watchdog only works on the device - with self.assertRaises(exceptions.WatchdogExpired): - self.execute(Watchdog) - def test_time_keeps_running(self): self.execute(TimeKeepsRunning) t1 = self.dataset_mgr.get("time_at_start") From 85b5a04acf3b6a7b78d92cbdcd8bf8a369cada27 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 7 Jul 2020 17:28:15 +0800 Subject: [PATCH 2201/2457] test: print transfer rates in MiB/s --- artiq/test/coredevice/test_performance.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index a376bf73f..e5ccd7a98 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -52,19 +52,19 @@ class TransferTest(ExperimentCase): def test_host_to_device(self): exp = self.create(_Transfer) host_to_device_rate = exp.host_to_device() - print(host_to_device_rate, "B/s") + print(host_to_device_rate/(1024*1024), "MiB/s") self.assertGreater(host_to_device_rate, 2.0e6) def test_device_to_host(self): exp = self.create(_Transfer) device_to_host_rate = exp.device_to_host() - print(device_to_host_rate, "B/s") + print(device_to_host_rate/(1024*1024), "MiB/s") self.assertGreater(device_to_host_rate, 2.3e6) def test_device_to_host_array(self): exp = self.create(_Transfer) rate = exp.device_to_host_array() - print(rate, "B/s") + print(rate/(1024*1024), "MiB/s") self.assertGreater(rate, .15e6) From 2d1f1fff7fa9ab6d525f9089135c5282b3a707b6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 8 Jul 2020 18:14:44 +0800 Subject: [PATCH 2202/2457] kasli_generic: do not attempt to use SFP LED for RTIO on 2.0+ --- artiq/gateware/targets/kasli_generic.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index a3e03ef7b..bae599ed9 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -153,12 +153,13 @@ class GenericStandalone(StandaloneBase): self.rtio_channels = [] add_peripherals(self, description["peripherals"]) - for i in (1, 2): - print("SFP LED at RTIO channel 0x{:06x}".format(len(self.rtio_channels))) - sfp_ctl = self.platform.request("sfp_ctl", i) - phy = ttl_simple.Output(sfp_ctl.led) - self.submodules += phy - self.rtio_channels.append(rtio.Channel.from_phy(phy)) + if hw_rev in ("v1.0", "v1.1"): + for i in (1, 2): + print("SFP LED at RTIO channel 0x{:06x}".format(len(self.rtio_channels))) + sfp_ctl = self.platform.request("sfp_ctl", i) + phy = ttl_simple.Output(sfp_ctl.led) + self.submodules += phy + self.rtio_channels.append(rtio.Channel.from_phy(phy)) self.config["HAS_RTIO_LOG"] = None self.config["RTIO_LOG_CHANNEL"] = len(self.rtio_channels) From f273a9aaccefdfed7068e7e43f5ecec01355d36e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 8 Jul 2020 18:15:36 +0800 Subject: [PATCH 2203/2457] artiq_ddb_template: remove SFP LEDs on hw 2.0+ --- artiq/frontend/artiq_ddb_template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 57bddf32c..052673e03 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -520,7 +520,7 @@ def process(output, master_description, satellites): for peripheral in master_description["peripherals"]: n_channels = pm.process(rtio_offset, peripheral) rtio_offset += n_channels - if base == "standalone": + if base == "standalone" and master_description["hw_rev"] in ("v1.0", "v1.1"): n_channels = pm.add_sfp_leds(rtio_offset) rtio_offset += n_channels From 8719bab7260c6bf63e50c8935dda7e1ceed83d2e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 8 Jul 2020 19:02:02 +0800 Subject: [PATCH 2204/2457] Revert "i2c: duplicate TCA9548 control byte" This reverts commit f265976df62ec5bc358de68f8808ade96198ae15. --- artiq/firmware/libboard_misoc/i2c.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/libboard_misoc/i2c.rs b/artiq/firmware/libboard_misoc/i2c.rs index 9e62a97ff..acade0c24 100644 --- a/artiq/firmware/libboard_misoc/i2c.rs +++ b/artiq/firmware/libboard_misoc/i2c.rs @@ -183,11 +183,8 @@ mod imp { if !write(busno, address << 1)? { return Err("PCA9548 failed to ack write address") } - // Duplicate control byte: one for SCL, one for SDA - for _ in 0..2 { - if !write(busno, channels)? { - return Err("PCA9548 failed to ack control word") - } + if !write(busno, channels)? { + return Err("PCA9548 failed to ack control word") } stop(busno)?; Ok(()) From 901be75ba4c08f3392ecc9398b0ebcead2bfc78c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 11 Jul 2020 09:51:01 +0800 Subject: [PATCH 2205/2457] sayma_rtm: fix Si5324 reset Closes #1483 --- artiq/gateware/targets/sayma_rtm.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 777495aa6..bdef1fa09 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -164,12 +164,13 @@ class _SatelliteBase(BaseSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, self.siphaser.mmcm_freerun_output) self.csr_devices.append("siphaser") + self.submodules.si5324_rst_n = gpio.GPIOOut(platform.request("si5324").rst_n) + self.csr_devices.append("si5324_rst_n") i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) self.csr_devices.append("i2c") self.config["I2C_BUS_COUNT"] = 1 self.config["HAS_SI5324"] = None - self.config["SI5324_SOFT_RESET"] = None platform.add_period_constraint(gtp.txoutclk, rtio_clk_period) platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) From f2e0d2733422ebc2dd5c8d7817d16847d8bef8d2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 12 Jul 2020 10:13:18 +0800 Subject: [PATCH 2206/2457] rtio/dma: remove dead/broken code --- artiq/gateware/rtio/dma.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/artiq/gateware/rtio/dma.py b/artiq/gateware/rtio/dma.py index 03f479e03..dd1e23f55 100644 --- a/artiq/gateware/rtio/dma.py +++ b/artiq/gateware/rtio/dma.py @@ -12,9 +12,7 @@ def _reverse_bytes(s, g): class WishboneReader(Module): - def __init__(self, bus=None): - if bus is None: - bus = wishbone.Interface + def __init__(self): self.bus = bus aw = len(bus.adr) From 4340a5cfc1b311eab438024045cd31d7659ce38a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 12 Jul 2020 10:14:22 +0800 Subject: [PATCH 2207/2457] rtio/dma: fix previous commit --- artiq/gateware/rtio/dma.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/dma.py b/artiq/gateware/rtio/dma.py index dd1e23f55..20d558672 100644 --- a/artiq/gateware/rtio/dma.py +++ b/artiq/gateware/rtio/dma.py @@ -12,7 +12,7 @@ def _reverse_bytes(s, g): class WishboneReader(Module): - def __init__(self): + def __init__(self, bus): self.bus = bus aw = len(bus.adr) From e31ee1f0b3f268a3fa8eb8858625b36c3e643e4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 14 Jul 2020 17:33:32 +0000 Subject: [PATCH 2208/2457] firmware/i2c: rewrite I2C implementation * Never drive SDL or SDA high. They are specified to be open collector/drain and pulled up by resistive pullups. Driving high fails miserably in a multi-master topology (e.g. with a USB I2C interface). It would only ever be implemented to speed up the bus actively but that's tricky and completely unnecessary here. * Make the handover states between the I2C protocol phases (start, stop, restart, write, read) well defined. Add comments stressing those pre/postconditions. * Add checks for SDA arbitration failures and stuck SCL. * Remove wrong, misleading or redundant comments. --- artiq/firmware/libboard_misoc/i2c.rs | 100 +++++++++++++++------------ 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/artiq/firmware/libboard_misoc/i2c.rs b/artiq/firmware/libboard_misoc/i2c.rs index acade0c24..19ff3195a 100644 --- a/artiq/firmware/libboard_misoc/i2c.rs +++ b/artiq/firmware/libboard_misoc/i2c.rs @@ -14,6 +14,12 @@ mod imp { } } + fn scl_i(busno: u8) -> bool { + unsafe { + csr::i2c::in_read() & scl_bit(busno) != 0 + } + } + fn sda_oe(busno: u8, oe: bool) { unsafe { let reg = csr::i2c::oe_read(); @@ -49,13 +55,10 @@ mod imp { pub fn init() -> Result<(), &'static str> { for busno in 0..csr::CONFIG_I2C_BUS_COUNT { let busno = busno as u8; - // Set SCL as output, and high level - scl_o(busno, true); - scl_oe(busno, true); - // Prepare a zero level on SDA so that sda_oe pulls it down - sda_o(busno, false); - // Release SDA + scl_oe(busno, false); sda_oe(busno, false); + scl_o(busno, false); + sda_o(busno, false); // Check the I2C bus is ready half_period(); @@ -63,9 +66,9 @@ mod imp { if !sda_i(busno) { // Try toggling SCL a few times for _bit in 0..8 { - scl_o(busno, false); + scl_oe(busno, true); half_period(); - scl_o(busno, true); + scl_oe(busno, false); half_period(); } } @@ -73,6 +76,10 @@ mod imp { if !sda_i(busno) { return Err("SDA is stuck low and doesn't get unstuck"); } + if !scl_i(busno) { + return Err("SCL is stuck low and doesn't get unstuck"); + } + // postcondition: SCL and SDA high } Ok(()) } @@ -81,11 +88,17 @@ mod imp { if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { return Err(INVALID_BUS) } - // Set SCL high then SDA low - scl_o(busno, true); - half_period(); + // precondition: SCL and SDA high + if !scl_i(busno) { + return Err("SCL is stuck low and doesn't get unstuck"); + } + if !sda_i(busno) { + return Err("SDA arbitration lost"); + } sda_oe(busno, true); half_period(); + scl_oe(busno, true); + // postcondition: SCL and SDA low Ok(()) } @@ -93,13 +106,13 @@ mod imp { if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { return Err(INVALID_BUS) } - // Set SCL low then SDA high */ - scl_o(busno, false); - half_period(); + // precondition SCL and SDA low sda_oe(busno, false); half_period(); - // Do a regular start + scl_oe(busno, false); + half_period(); start(busno)?; + // postcondition: SCL and SDA low Ok(()) } @@ -107,15 +120,16 @@ mod imp { if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { return Err(INVALID_BUS) } - // First, make sure SCL is low, so that the target releases the SDA line - scl_o(busno, false); + // precondition: SCL and SDA low half_period(); - // Set SCL high then SDA high - sda_oe(busno, true); - scl_o(busno, true); + scl_oe(busno, false); half_period(); sda_oe(busno, false); half_period(); + if !sda_i(busno) { + return Err("SDA arbitration lost"); + } + // postcondition: SCL and SDA high Ok(()) } @@ -123,57 +137,53 @@ mod imp { if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { return Err(INVALID_BUS) } + // precondition: SCL and SDA low // MSB first for bit in (0..8).rev() { - // Set SCL low and set our bit on SDA - scl_o(busno, false); sda_oe(busno, data & (1 << bit) == 0); half_period(); - // Set SCL high ; data is shifted on the rising edge of SCL - scl_o(busno, true); + scl_oe(busno, false); half_period(); + scl_oe(busno, true); } - // Check ack - // Set SCL low, then release SDA so that the I2C target can respond - scl_o(busno, false); - half_period(); sda_oe(busno, false); - // Set SCL high and check for ack - scl_o(busno, true); half_period(); - // returns true if acked (I2C target pulled SDA low) - Ok(!sda_i(busno)) + scl_oe(busno, false); + half_period(); + // Read ack/nack + let ack = !sda_i(busno); + scl_oe(busno, true); + sda_oe(busno, true); + // postcondition: SCL and SDA low + + Ok(ack) } pub fn read(busno: u8, ack: bool) -> Result { if busno as u32 >= csr::CONFIG_I2C_BUS_COUNT { return Err(INVALID_BUS) } - // Set SCL low first, otherwise setting SDA as input may cause a transition - // on SDA with SCL high which will be interpreted as START/STOP condition. - scl_o(busno, false); - half_period(); // make sure SCL has settled low + // precondition: SCL and SDA low sda_oe(busno, false); let mut data: u8 = 0; // MSB first for bit in (0..8).rev() { - scl_o(busno, false); half_period(); - // Set SCL high and shift data - scl_o(busno, true); + scl_oe(busno, false); half_period(); if sda_i(busno) { data |= 1 << bit } + scl_oe(busno, true); } - // Send ack - // Set SCL low and pull SDA low when acking - scl_o(busno, false); - if ack { sda_oe(busno, true) } + // Send ack/nack + sda_oe(busno, ack); half_period(); - // then set SCL high - scl_o(busno, true); + scl_oe(busno, false); half_period(); + scl_oe(busno, true); + sda_oe(busno, true); + // postcondition: SCL and SDA low Ok(data) } From f78d673079d5fa935d03f88fe650cf75c61b6c10 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 16 Jul 2020 15:11:17 +0800 Subject: [PATCH 2209/2457] firmware/rpc: added `#[repr(C)]` for structs. Previously the structs are in repr(Rust) which has no layout guarantee. --- artiq/firmware/libproto_artiq/rpc_proto.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/firmware/libproto_artiq/rpc_proto.rs b/artiq/firmware/libproto_artiq/rpc_proto.rs index c0bab177a..5e326689b 100644 --- a/artiq/firmware/libproto_artiq/rpc_proto.rs +++ b/artiq/firmware/libproto_artiq/rpc_proto.rs @@ -49,6 +49,7 @@ unsafe fn recv_value(reader: &mut R, tag: Tag, data: &mut *mut (), Ok(()) } Tag::List(it) | Tag::Array(it) => { + #[repr(C)]. struct List { elements: *mut (), length: u32 }; consume_value!(List, |ptr| { (*ptr).length = reader.read_u32()?; @@ -132,6 +133,7 @@ unsafe fn send_value(writer: &mut W, tag: Tag, data: &mut *const ()) Ok(()) } Tag::List(it) | Tag::Array(it) => { + #[repr(C)]. struct List { elements: *const (), length: u32 }; consume_value!(List, |ptr| { writer.write_u32((*ptr).length)?; @@ -151,6 +153,7 @@ unsafe fn send_value(writer: &mut W, tag: Tag, data: &mut *const ()) Ok(()) } Tag::Keyword(it) => { + #[repr(C)]. struct Keyword<'a> { name: CSlice<'a, u8> }; consume_value!(Keyword, |ptr| { writer.write_string(str::from_utf8((*ptr).name.as_ref()).unwrap())?; @@ -162,6 +165,7 @@ unsafe fn send_value(writer: &mut W, tag: Tag, data: &mut *const ()) // to accurately advance data. } Tag::Object => { + #[repr(C)]. struct Object { id: u32 }; consume_value!(*const Object, |ptr| writer.write_u32((**ptr).id)) From eb28d7be3a455b9ecee38feac32aa0ffb5844f68 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 16 Jul 2020 15:15:47 +0800 Subject: [PATCH 2210/2457] firmware/rpc: fixed typo --- artiq/firmware/libproto_artiq/rpc_proto.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/firmware/libproto_artiq/rpc_proto.rs b/artiq/firmware/libproto_artiq/rpc_proto.rs index 5e326689b..750f3f467 100644 --- a/artiq/firmware/libproto_artiq/rpc_proto.rs +++ b/artiq/firmware/libproto_artiq/rpc_proto.rs @@ -49,7 +49,7 @@ unsafe fn recv_value(reader: &mut R, tag: Tag, data: &mut *mut (), Ok(()) } Tag::List(it) | Tag::Array(it) => { - #[repr(C)]. + #[repr(C)] struct List { elements: *mut (), length: u32 }; consume_value!(List, |ptr| { (*ptr).length = reader.read_u32()?; @@ -133,7 +133,7 @@ unsafe fn send_value(writer: &mut W, tag: Tag, data: &mut *const ()) Ok(()) } Tag::List(it) | Tag::Array(it) => { - #[repr(C)]. + #[repr(C)] struct List { elements: *const (), length: u32 }; consume_value!(List, |ptr| { writer.write_u32((*ptr).length)?; @@ -153,7 +153,7 @@ unsafe fn send_value(writer: &mut W, tag: Tag, data: &mut *const ()) Ok(()) } Tag::Keyword(it) => { - #[repr(C)]. + #[repr(C)] struct Keyword<'a> { name: CSlice<'a, u8> }; consume_value!(Keyword, |ptr| { writer.write_string(str::from_utf8((*ptr).name.as_ref()).unwrap())?; @@ -165,7 +165,7 @@ unsafe fn send_value(writer: &mut W, tag: Tag, data: &mut *const ()) // to accurately advance data. } Tag::Object => { - #[repr(C)]. + #[repr(C)] struct Object { id: u32 }; consume_value!(*const Object, |ptr| writer.write_u32((**ptr).id)) From 8510bf4e558d7b4cca64ab0315f99dcd598651c4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 16 Jul 2020 19:28:58 +0800 Subject: [PATCH 2211/2457] test_analyzer: configure loop_out as output --- artiq/test/coredevice/test_analyzer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/test/coredevice/test_analyzer.py b/artiq/test/coredevice/test_analyzer.py index 335c941c3..cf8a64540 100644 --- a/artiq/test/coredevice/test_analyzer.py +++ b/artiq/test/coredevice/test_analyzer.py @@ -15,6 +15,8 @@ class CreateTTLPulse(EnvExperiment): def initialize_io(self): self.core.reset() self.loop_in.input() + self.loop_out.output() + delay(1*us) self.loop_out.off() @kernel From 553a49e194013ce4f3e5f650067e0e9036d8f68f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 19 Jul 2020 17:59:43 +0800 Subject: [PATCH 2212/2457] test_moninj: set loop_out as output --- artiq/test/coredevice/test_moninj.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/test/coredevice/test_moninj.py b/artiq/test/coredevice/test_moninj.py index 3d9481ae0..83786a8a1 100644 --- a/artiq/test/coredevice/test_moninj.py +++ b/artiq/test/coredevice/test_moninj.py @@ -38,6 +38,7 @@ class MonInjTest(ExperimentCase): moninj_comm.monitor_injection(True, loop_out_channel, TTLOverride.level.en.value) loop.run_until_complete(asyncio.sleep(0.5)) moninj_comm.inject(loop_out_channel, TTLOverride.level.value, 0) + moninj_comm.inject(loop_out_channel, TTLOverride.level.oe.value, 1) moninj_comm.inject(loop_out_channel, TTLOverride.level.en.value, 1) loop.run_until_complete(asyncio.sleep(0.5)) moninj_comm.get_injection_status(loop_out_channel, TTLOverride.en.value) From 2a2f5c4d58c5146479e52359943c0c9b5bd15548 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 20 Jul 2020 19:39:19 +0800 Subject: [PATCH 2213/2457] comm_analyzer: make header error flag more general --- artiq/coredevice/comm_analyzer.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/comm_analyzer.py b/artiq/coredevice/comm_analyzer.py index 45766f340..dd58acb68 100644 --- a/artiq/coredevice/comm_analyzer.py +++ b/artiq/coredevice/comm_analyzer.py @@ -92,16 +92,16 @@ DecodedDump = namedtuple( def decode_dump(data): parts = struct.unpack(">IQbbb", data[:15]) (sent_bytes, total_byte_count, - overflow_occured, log_channel, dds_onehot_sel) = parts + error_occured, log_channel, dds_onehot_sel) = parts expected_len = sent_bytes + 15 if expected_len != len(data): raise ValueError("analyzer dump has incorrect length " "(got {}, expected {})".format( len(data), expected_len)) - if overflow_occured: - logger.warning("analyzer FIFO overflow occured, " - "some messages have been lost") + if error_occured: + logger.warning("error occured within the analyzer, " + "data may be corrupted") if total_byte_count > sent_bytes: logger.info("analyzer ring buffer has wrapped %d times", total_byte_count//sent_bytes) From 57e759a1edfd7ae6b1d5368c542f6a68809d8799 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 25 Jul 2020 02:09:13 +0100 Subject: [PATCH 2214/2457] compiler: Consistently use llunit through llvm_ir_generator [nfc] --- artiq/compiler/transforms/llvm_ir_generator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index b63cb881f..58177138b 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -209,7 +209,7 @@ class LLVMIRGenerator: if for_return: return llvoid else: - return ll.LiteralStructType([]) + return llunit elif types._is_pointer(typ): return llptr elif types.is_function(typ): @@ -239,7 +239,7 @@ class LLVMIRGenerator: if for_return: return llvoid else: - return ll.LiteralStructType([]) + return llunit elif builtins.is_bool(typ): return lli1 elif builtins.is_int(typ): @@ -1376,7 +1376,7 @@ class LLVMIRGenerator: name="rpc.args") for index, arg in enumerate(args): if builtins.is_none(arg.type): - llargslot = self.llbuilder.alloca(ll.LiteralStructType([]), + llargslot = self.llbuilder.alloca(llunit, name="rpc.arg{}".format(index)) else: llarg = self.map(arg) From 1c72585c1b56d969827176e1fc370c214f5fb35e Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 25 Jul 2020 02:18:10 +0100 Subject: [PATCH 2215/2457] compiler: Handle None-returning function calls used as values GitHub: Fixes #1493. --- artiq/compiler/transforms/llvm_ir_generator.py | 5 +++++ artiq/test/lit/codegen/none_retval.py | 11 +++++++++++ 2 files changed, 16 insertions(+) create mode 100644 artiq/test/lit/codegen/none_retval.py diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 58177138b..84dcac2dd 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -1481,6 +1481,11 @@ class LLVMIRGenerator: else: llcall = llresult = self.llbuilder.call(llfun, llargs, name=insn.name) + if isinstance(llresult.type, ll.VoidType): + # We have NoneType-returning functions return void, but None is + # {} elsewhere. + llresult = ll.Constant(llunit, []) + # Never add TBAA nowrite metadata to a functon with sret! # This leads to miscompilations. if types.is_c_function(functiontyp) and 'nowrite' in functiontyp.flags: diff --git a/artiq/test/lit/codegen/none_retval.py b/artiq/test/lit/codegen/none_retval.py new file mode 100644 index 000000000..ed2c9eb25 --- /dev/null +++ b/artiq/test/lit/codegen/none_retval.py @@ -0,0 +1,11 @@ +# RUN: %python -m artiq.compiler.testbench.llvmgen %s + +def make_none(): + return None + +def take_arg(arg): + pass + +def run(): + retval = make_none() + take_arg(retval) From 9b44ec7bc64d69f97670d58507d1016201322ae6 Mon Sep 17 00:00:00 2001 From: Charles Baynham Date: Thu, 23 Jul 2020 11:49:21 +0100 Subject: [PATCH 2216/2457] parameters: Allow forcing a NumberValue to return a float Signed-off-by: Charles Baynham --- RELEASE_NOTES.rst | 1 + artiq/language/environment.py | 36 +++++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 3a9a6d21a..7b9899d71 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -23,6 +23,7 @@ Highlights: * Experiment results are now always saved to HDF5, even if run() fails. * Core device: ``panic_reset 1`` now correctly resets the kernel CPU as well if communication CPU panic occurs. +* NumberValue accepts a ``type`` parameter specifying the output as ``int`` or ``float`` Breaking changes: diff --git a/artiq/language/environment.py b/artiq/language/environment.py index fddae667f..f7aab5502 100644 --- a/artiq/language/environment.py +++ b/artiq/language/environment.py @@ -100,10 +100,9 @@ class EnumerationValue(_SimpleArgProcessor): class NumberValue(_SimpleArgProcessor): """An argument that can take a numerical value. - If ndecimals = 0, scale = 1 and step is integer, then it returns - an integer value. Otherwise, it returns a floating point value. - The simplest way to represent an integer argument is - ``NumberValue(step=1, ndecimals=0)``. + If ``type=="auto"``, the result will be a ``float`` unless + ndecimals = 0, scale = 1 and step is an integer. Setting ``type`` to + ``int`` will also result in an error unless these conditions are met. When ``scale`` is not specified, and the unit is a common one (i.e. defined in ``artiq.language.units``), then the scale is obtained from @@ -126,9 +125,13 @@ class NumberValue(_SimpleArgProcessor): :param min: The minimum value of the argument. :param max: The maximum value of the argument. :param ndecimals: The number of decimals a UI should use. + :param type: Type of this number. Accepts ``"float"``, ``"int"`` or + ``"auto"``. Defaults to ``"auto"``. """ + valid_types = ["auto", "float", "int"] + def __init__(self, default=NoDefault, unit="", scale=None, - step=None, min=None, max=None, ndecimals=2): + step=None, min=None, max=None, ndecimals=2, type="auto"): if scale is None: if unit == "": scale = 1.0 @@ -146,14 +149,34 @@ class NumberValue(_SimpleArgProcessor): self.min = min self.max = max self.ndecimals = ndecimals + self.type = type + + if self.type not in NumberValue.valid_types: + raise TypeError("type must be 'float', 'int' or 'auto'") + + if self.type == "int" and not self._is_int_compatible(): + raise ValueError(("Value marked as integer but settings are " + "not compatible. Please set ndecimals = 0, " + "scale = 1 and step to an integer")) super().__init__(default) - def _is_int(self): + def _is_int_compatible(self): + ''' + Are the settings other than `type` compatible with this being + an integer? + ''' return (self.ndecimals == 0 and int(self.step) == self.step and self.scale == 1) + def _is_int(self): + ''' + Will this argument return an integer? + ''' + return (self.type == "int" + or (self.type == "auto" and self._is_int_compatible())) + def process(self, x): if self._is_int(): return int(x) @@ -170,6 +193,7 @@ class NumberValue(_SimpleArgProcessor): d["min"] = self.min d["max"] = self.max d["ndecimals"] = self.ndecimals + d["type"] = self.type return d From 8dd9a6d02443e912b9be37c9b9c18dbc47da2739 Mon Sep 17 00:00:00 2001 From: cw-mlabs <68726632+cw-mlabs@users.noreply.github.com> Date: Mon, 27 Jul 2020 12:57:29 +0800 Subject: [PATCH 2217/2457] wrpll: fix scl signal --- artiq/gateware/drtio/wrpll/si549.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/si549.py b/artiq/gateware/drtio/wrpll/si549.py index f4427a9bc..57e009a4c 100644 --- a/artiq/gateware/drtio/wrpll/si549.py +++ b/artiq/gateware/drtio/wrpll/si549.py @@ -296,8 +296,8 @@ class Si549(Module, AutoCSR): ts_scl.o.eq(self.gpio_out.storage[0]), ts_scl.oe.eq(self.gpio_oe.storage[0]) ).Else( - ts_scl.o.eq(programmer.scl), - ts_scl.oe.eq(1) + ts_scl.o.eq(0), + ts_scl.oe.eq(~programmer.scl) ) ] From e4b16428f58f7504dec658dbe53d40227ace67a3 Mon Sep 17 00:00:00 2001 From: cw-mlabs <68726632+cw-mlabs@users.noreply.github.com> Date: Mon, 27 Jul 2020 12:55:50 +0800 Subject: [PATCH 2218/2457] wrpll: fix run signal --- artiq/gateware/drtio/wrpll/si549.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/wrpll/si549.py b/artiq/gateware/drtio/wrpll/si549.py index 57e009a4c..6f840854c 100644 --- a/artiq/gateware/drtio/wrpll/si549.py +++ b/artiq/gateware/drtio/wrpll/si549.py @@ -115,7 +115,7 @@ class I2CMasterMachine(Module): run = Signal() idle = Signal() self.comb += [ - run.eq(self.start | self.stop | self.write), + run.eq((self.start | self.stop | self.write) & self.ready), idle.eq(~run & fsm.ongoing("IDLE")), self.cg.ce.eq(~idle), fsm.ce.eq(run | self.cg.clk2x), From f8d15069227298492ce539d793cfedfd8a80874c Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 28 Jul 2020 00:33:28 +0100 Subject: [PATCH 2219/2457] compiler: Fix lifetime tracking for function call return values GitHub: Fixes #1497. --- artiq/compiler/validators/escape.py | 2 +- artiq/test/lit/escape/error_call.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 artiq/test/lit/escape/error_call.py diff --git a/artiq/compiler/validators/escape.py b/artiq/compiler/validators/escape.py index 000c3ee5b..5aae58e51 100644 --- a/artiq/compiler/validators/escape.py +++ b/artiq/compiler/validators/escape.py @@ -103,7 +103,7 @@ class RegionOf(algorithm.Visitor): # The cache is borrow checked dynamically return Global() else: - self.visit_sometimes_allocating(node) + return self.visit_sometimes_allocating(node) # Value lives as long as the object/container, if it's mutable, # or else forever diff --git a/artiq/test/lit/escape/error_call.py b/artiq/test/lit/escape/error_call.py new file mode 100644 index 000000000..8bbc7992f --- /dev/null +++ b/artiq/test/lit/escape/error_call.py @@ -0,0 +1,14 @@ +# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t +# RUN: OutputCheck %s --file-to-check=%t + +from artiq.experiment import * + +@kernel +def leak(a): + return a + +@kernel +def entrypoint(): + # CHECK-L: ${LINE:+2}: error: cannot return an allocated value that does not live forever + # CHECK-L: ${LINE:+1}: note: ... to this point + return leak([1, 2, 3]) From cf19c9512dd41831bb5643025b9f3349c0828d83 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 28 Jul 2020 00:54:20 +0100 Subject: [PATCH 2220/2457] RELEASE_NOTES: Add entry for compiler lifetime tracking fix I contemplated putting this in the "Breaking changes" section, as it might break user code that has avoided being hit by memory corruption from the use-after free by chance (even though it was always an accepts-illegal bug). --- RELEASE_NOTES.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 7b9899d71..d1f88b15f 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -24,6 +24,9 @@ Highlights: * Core device: ``panic_reset 1`` now correctly resets the kernel CPU as well if communication CPU panic occurs. * NumberValue accepts a ``type`` parameter specifying the output as ``int`` or ``float`` +* In kernels, lifetime of allocated values (e.g. lists) is now correctly tracked across + function calls (see #1497, #1394). Previous versions (since ARTIQ 1.0) would accept + illegal code that would result in silent memory corruption at runtime. Breaking changes: From 5fd0d0bbb609445cb72451e07edc9d073a345b47 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 28 Jul 2020 12:08:47 +0800 Subject: [PATCH 2221/2457] gui: work around quamash bug with python 3.8 --- artiq/frontend/artiq_browser.py | 4 ++++ artiq/frontend/artiq_dashboard.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index 6d499e558..9e514fba0 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -5,6 +5,7 @@ import asyncio import atexit import os import logging +import sys from PyQt5 import QtCore, QtGui, QtWidgets from quamash import QEventLoop @@ -143,6 +144,9 @@ def main(): app = QtWidgets.QApplication(["ARTIQ Browser"]) loop = QEventLoop(app) asyncio.set_event_loop(loop) + # https://github.com/harvimt/quamash/issues/123 + if sys.version_info >= (3, 8): + asyncio.events._set_running_loop(loop) atexit.register(loop.close) datasets_sub = models.LocalModelManager(datasets.Model) diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index ba0b9fd05..ace7e4eb2 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -5,6 +5,7 @@ import asyncio import atexit import os import logging +import sys from PyQt5 import QtCore, QtGui, QtWidgets from quamash import QEventLoop @@ -104,6 +105,9 @@ def main(): app = QtWidgets.QApplication(["ARTIQ Dashboard"]) loop = QEventLoop(app) asyncio.set_event_loop(loop) + # https://github.com/harvimt/quamash/issues/123 + if sys.version_info >= (3, 8): + asyncio.events._set_running_loop(loop) atexit.register(loop.close) smgr = state.StateManager(args.db_file) From 455e4859b72d3eeea7e5a02beadc31de39080e0e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 30 Jul 2020 00:54:07 +0800 Subject: [PATCH 2222/2457] simplify versioneer Original version is very complex and still has a number of problems. --- .gitattributes | 1 - artiq/__init__.py | 10 +- artiq/_version.py | 531 +------------ setup.cfg | 7 - versioneer.py | 1820 +-------------------------------------------- 5 files changed, 40 insertions(+), 2329 deletions(-) delete mode 100644 .gitattributes delete mode 100644 setup.cfg diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index d9794962b..000000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -artiq/_version.py export-subst diff --git a/artiq/__init__.py b/artiq/__init__.py index 4536d3b00..cbb01c9e5 100644 --- a/artiq/__init__.py +++ b/artiq/__init__.py @@ -1,11 +1,7 @@ -from ._version import get_versions -__version__ = get_versions()['version'] -del get_versions +from ._version import get_version +__version__ = get_version() +del get_version import os __artiq_dir__ = os.path.dirname(os.path.abspath(__file__)) del os - -from ._version import get_versions -__version__ = get_versions()['version'] -del get_versions diff --git a/artiq/_version.py b/artiq/_version.py index 8f9af10f8..b3c3d5be4 100644 --- a/artiq/_version.py +++ b/artiq/_version.py @@ -1,526 +1,13 @@ - -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (built by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. - -# This file is released into the public domain. Generated by -# versioneer-0.18 (https://github.com/warner/python-versioneer) - -"""Git implementation of _version.py.""" - -import errno import os -import re -import subprocess -import sys - - -def get_keywords(): - """Get the keywords needed to look up the version information.""" - # these strings will be replaced by git during git-archive. - # setup.py/versioneer.py will grep for the variable names, so they must - # each be defined on a line of their own. _version.py will just call - # get_keywords(). - git_refnames = "$Format:%d$" - git_full = "$Format:%H$" - git_date = "$Format:%ci$" - keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} - return keywords - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_config(): - """Create, populate and return the VersioneerConfig() object.""" - # these strings are filled in when 'setup.py versioneer' creates - # _version.py - cfg = VersioneerConfig() - cfg.VCS = "git" - cfg.style = "pep440" - cfg.tag_prefix = "" - cfg.parentdir_prefix = "artiq-" - cfg.versionfile_source = "artiq/_version.py" - cfg.verbose = False - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -LONG_VERSION_PY = {} -HANDLERS = {} - - -def register_vcs_handler(vcs, method): # decorator - """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - p = None - for c in commands: - try: - dispcmd = str([c] + args) - # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) - break - except EnvironmentError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %s" % dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %s" % (commands,)) - return None, None - stdout = p.communicate()[0].strip() - if sys.version_info[0] >= 3: - stdout = stdout.decode() - if p.returncode != 0: - if verbose: - print("unable to run %s (error)" % dispcmd) - print("stdout was %s" % stdout) - return None, p.returncode - return stdout, p.returncode - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for i in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} - else: - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - f = open(versionfile_abs, "r") - for line in f.readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - f.close() - except EnvironmentError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if not keywords: - raise NotThisMethod("no keywords at all, weird") - date = keywords.get("date") - if date is not None: - # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = set([r.strip() for r in refnames.strip("()").split(",")]) - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) - if verbose: - print("discarding '%s', no digits" % ",".join(refs - tags)) - if verbose: - print("likely tags: %s" % ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - if verbose: - print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) - if rc != 0: - if verbose: - print("Directory %s not under git control" % root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", "--abbrev=8", - "--match", "%s*" % tag_prefix], - cwd=root) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:8] # maybe improved later - pieces["error"] = None - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) - if not mo: - # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%s' doesn't start with prefix '%s'" - print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) - pieces["distance"] = int(count_out) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def plus_or_dot(pieces): - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_pre(pieces): - """TAG[.post.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post.devDISTANCE - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += ".post.dev%d" % pieces["distance"] - else: - # exception #1 - rendered = "0.post.dev%d" % pieces["distance"] - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%s" % pieces["short"] - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%s" % pieces["short"] - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Eexceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%s'" % style) - - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} - - -def get_versions(): - """Get version information or return default if unable to do so.""" - # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have - # __file__, we can work backwards from there to the root. Some - # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which - # case we can only use expanded keywords. +def get_version(): override = os.getenv("VERSIONEER_OVERRIDE") if override: - return {"version": override, "full-revisionid": None, - "dirty": None, - "error": None, "date": None} - - cfg = get_config() - verbose = cfg.verbose - - try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) - except NotThisMethod: - pass - - try: - root = os.path.realpath(__file__) - # versionfile_source is the relative path from the top of the source - # tree (where the .git directory might live) to this file. Invert - # this to find the root from __file__. - for i in cfg.versionfile_source.split('/'): - root = os.path.dirname(root) - except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} - - try: - pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) - return render(pieces, cfg.style) - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - except NotThisMethod: - pass - - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} + return override + srcroot = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir) + with open(os.path.join(srcroot, "MAJOR_VERSION"), "r") as f: + version = f.read().strip() + version += ".unknown" + if os.path.exists(os.path.join(srcroot, "BETA")): + version += ".beta" + return version diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index c8d846cbf..000000000 --- a/setup.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[versioneer] -VCS = git -style = pep440 -versionfile_source = artiq/_version.py -versionfile_build = artiq/_version.py -tag_prefix = -parentdir_prefix = artiq- diff --git a/versioneer.py b/versioneer.py index 0539490d3..93f1c661d 100644 --- a/versioneer.py +++ b/versioneer.py @@ -1,1555 +1,32 @@ - -# Version: 0.18 - -"""The Versioneer - like a rocketeer, but for versions. - -The Versioneer -============== - -* like a rocketeer, but for versions! -* https://github.com/warner/python-versioneer -* Brian Warner -* License: Public Domain -* Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6, and pypy -* [![Latest Version] -(https://pypip.in/version/versioneer/badge.svg?style=flat) -](https://pypi.python.org/pypi/versioneer/) -* [![Build Status] -(https://travis-ci.org/warner/python-versioneer.png?branch=master) -](https://travis-ci.org/warner/python-versioneer) - -This is a tool for managing a recorded version number in distutils-based -python projects. The goal is to remove the tedious and error-prone "update -the embedded version string" step from your release process. Making a new -release should be as easy as recording a new tag in your version-control -system, and maybe making new tarballs. - - -## Quick Install - -* `pip install versioneer` to somewhere to your $PATH -* add a `[versioneer]` section to your setup.cfg (see below) -* run `versioneer install` in your source tree, commit the results - -## Version Identifiers - -Source trees come from a variety of places: - -* a version-control system checkout (mostly used by developers) -* a nightly tarball, produced by build automation -* a snapshot tarball, produced by a web-based VCS browser, like github's - "tarball from tag" feature -* a release tarball, produced by "setup.py sdist", distributed through PyPI - -Within each source tree, the version identifier (either a string or a number, -this tool is format-agnostic) can come from a variety of places: - -* ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows - about recent "tags" and an absolute revision-id -* the name of the directory into which the tarball was unpacked -* an expanded VCS keyword ($Id$, etc) -* a `_version.py` created by some earlier build step - -For released software, the version identifier is closely related to a VCS -tag. Some projects use tag names that include more than just the version -string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool -needs to strip the tag prefix to extract the version identifier. For -unreleased software (between tags), the version identifier should provide -enough information to help developers recreate the same tree, while also -giving them an idea of roughly how old the tree is (after version 1.2, before -version 1.3). Many VCS systems can report a description that captures this, -for example `git describe --tags --dirty --always` reports things like -"0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the -0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has -uncommitted changes. - -The version identifier is used for multiple purposes: - -* to allow the module to self-identify its version: `myproject.__version__` -* to choose a name and prefix for a 'setup.py sdist' tarball - -## Theory of Operation - -Versioneer works by adding a special `_version.py` file into your source -tree, where your `__init__.py` can import it. This `_version.py` knows how to -dynamically ask the VCS tool for version information at import time. - -`_version.py` also contains `$Revision$` markers, and the installation -process marks `_version.py` to have this marker rewritten with a tag name -during the `git archive` command. As a result, generated tarballs will -contain enough information to get the proper version. - -To allow `setup.py` to compute a version too, a `versioneer.py` is added to -the top level of your source tree, next to `setup.py` and the `setup.cfg` -that configures it. This overrides several distutils/setuptools commands to -compute the version when invoked, and changes `setup.py build` and `setup.py -sdist` to replace `_version.py` with a small static file that contains just -the generated version data. - -## Installation - -See [INSTALL.md](./INSTALL.md) for detailed installation instructions. - -## Version-String Flavors - -Code which uses Versioneer can learn about its version string at runtime by -importing `_version` from your main `__init__.py` file and running the -`get_versions()` function. From the "outside" (e.g. in `setup.py`), you can -import the top-level `versioneer.py` and run `get_versions()`. - -Both functions return a dictionary with different flavors of version -information: - -* `['version']`: A condensed version string, rendered using the selected - style. This is the most commonly used value for the project's version - string. The default "pep440" style yields strings like `0.11`, - `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section - below for alternative styles. - -* `['full-revisionid']`: detailed revision identifier. For Git, this is the - full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac". - -* `['date']`: Date and time of the latest `HEAD` commit. For Git, it is the - commit date in ISO 8601 format. This will be None if the date is not - available. - -* `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that - this is only accurate if run in a VCS checkout, otherwise it is likely to - be False or None - -* `['error']`: if the version string could not be computed, this will be set - to a string describing the problem, otherwise it will be None. It may be - useful to throw an exception in setup.py if this is set, to avoid e.g. - creating tarballs with a version string of "unknown". - -Some variants are more useful than others. Including `full-revisionid` in a -bug report should allow developers to reconstruct the exact code being tested -(or indicate the presence of local changes that should be shared with the -developers). `version` is suitable for display in an "about" box or a CLI -`--version` output: it can be easily compared against release notes and lists -of bugs fixed in various releases. - -The installer adds the following text to your `__init__.py` to place a basic -version in `YOURPROJECT.__version__`: - - from ._version import get_versions - __version__ = get_versions()['version'] - del get_versions - -## Styles - -The setup.cfg `style=` configuration controls how the VCS information is -rendered into a version string. - -The default style, "pep440", produces a PEP440-compliant string, equal to the -un-prefixed tag name for actual releases, and containing an additional "local -version" section with more detail for in-between builds. For Git, this is -TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags ---dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the -tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and -that this commit is two revisions ("+2") beyond the "0.11" tag. For released -software (exactly equal to a known tag), the identifier will only contain the -stripped tag, e.g. "0.11". - -Other styles are available. See [details.md](details.md) in the Versioneer -source tree for descriptions. - -## Debugging - -Versioneer tries to avoid fatal errors: if something goes wrong, it will tend -to return a version of "0+unknown". To investigate the problem, run `setup.py -version`, which will run the version-lookup code in a verbose mode, and will -display the full contents of `get_versions()` (including the `error` string, -which may help identify what went wrong). - -## Known Limitations - -Some situations are known to cause problems for Versioneer. This details the -most significant ones. More can be found on Github -[issues page](https://github.com/warner/python-versioneer/issues). - -### Subprojects - -Versioneer has limited support for source trees in which `setup.py` is not in -the root directory (e.g. `setup.py` and `.git/` are *not* siblings). The are -two common reasons why `setup.py` might not be in the root: - -* Source trees which contain multiple subprojects, such as - [Buildbot](https://github.com/buildbot/buildbot), which contains both - "master" and "slave" subprojects, each with their own `setup.py`, - `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI - distributions (and upload multiple independently-installable tarballs). -* Source trees whose main purpose is to contain a C library, but which also - provide bindings to Python (and perhaps other langauges) in subdirectories. - -Versioneer will look for `.git` in parent directories, and most operations -should get the right version string. However `pip` and `setuptools` have bugs -and implementation details which frequently cause `pip install .` from a -subproject directory to fail to find a correct version string (so it usually -defaults to `0+unknown`). - -`pip install --editable .` should work correctly. `setup.py install` might -work too. - -Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in -some later version. - -[Bug #38](https://github.com/warner/python-versioneer/issues/38) is tracking -this issue. The discussion in -[PR #61](https://github.com/warner/python-versioneer/pull/61) describes the -issue from the Versioneer side in more detail. -[pip PR#3176](https://github.com/pypa/pip/pull/3176) and -[pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve -pip to let Versioneer work correctly. - -Versioneer-0.16 and earlier only looked for a `.git` directory next to the -`setup.cfg`, so subprojects were completely unsupported with those releases. - -### Editable installs with setuptools <= 18.5 - -`setup.py develop` and `pip install --editable .` allow you to install a -project into a virtualenv once, then continue editing the source code (and -test) without re-installing after every change. - -"Entry-point scripts" (`setup(entry_points={"console_scripts": ..})`) are a -convenient way to specify executable scripts that should be installed along -with the python package. - -These both work as expected when using modern setuptools. When using -setuptools-18.5 or earlier, however, certain operations will cause -`pkg_resources.DistributionNotFound` errors when running the entrypoint -script, which must be resolved by re-installing the package. This happens -when the install happens with one version, then the egg_info data is -regenerated while a different version is checked out. Many setup.py commands -cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into -a different virtualenv), so this can be surprising. - -[Bug #83](https://github.com/warner/python-versioneer/issues/83) describes -this one, but upgrading to a newer version of setuptools should probably -resolve it. - -### Unicode version strings - -While Versioneer works (and is continually tested) with both Python 2 and -Python 3, it is not entirely consistent with bytes-vs-unicode distinctions. -Newer releases probably generate unicode version strings on py2. It's not -clear that this is wrong, but it may be surprising for applications when then -write these strings to a network connection or include them in bytes-oriented -APIs like cryptographic checksums. - -[Bug #71](https://github.com/warner/python-versioneer/issues/71) investigates -this question. - - -## Updating Versioneer - -To upgrade your project to a new release of Versioneer, do the following: - -* install the new Versioneer (`pip install -U versioneer` or equivalent) -* edit `setup.cfg`, if necessary, to include any new configuration settings - indicated by the release notes. See [UPGRADING](./UPGRADING.md) for details. -* re-run `versioneer install` in your source tree, to replace - `SRC/_version.py` -* commit any changed files - -## Future Directions - -This tool is designed to make it easily extended to other version-control -systems: all VCS-specific components are in separate directories like -src/git/ . The top-level `versioneer.py` script is assembled from these -components by running make-versioneer.py . In the future, make-versioneer.py -will take a VCS name as an argument, and will construct a version of -`versioneer.py` that is specific to the given VCS. It might also take the -configuration arguments that are currently provided manually during -installation by editing setup.py . Alternatively, it might go the other -direction and include code from all supported VCS systems, reducing the -number of intermediate scripts. - - -## License - -To make Versioneer easier to embed, all its code is dedicated to the public -domain. The `_version.py` that it creates is also in the public domain. -Specifically, both are released under the Creative Commons "Public Domain -Dedication" license (CC0-1.0), as described in -https://creativecommons.org/publicdomain/zero/1.0/ . - -""" - -from __future__ import print_function -try: - import configparser -except ImportError: - import ConfigParser as configparser -import errno -import json import os -import re -import subprocess import sys - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_root(): - """Get the project root directory. - - We require that all commands are run from the project root, i.e. the - directory that contains setup.py, setup.cfg, and versioneer.py . - """ - root = os.path.realpath(os.path.abspath(os.getcwd())) - setup_py = os.path.join(root, "setup.py") - versioneer_py = os.path.join(root, "versioneer.py") - if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - # allow 'python path/to/setup.py COMMAND' - root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) - setup_py = os.path.join(root, "setup.py") - versioneer_py = os.path.join(root, "versioneer.py") - if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - err = ("Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND').") - raise VersioneerBadRootError(err) - try: - # Certain runtime workflows (setup.py install/develop in a setuptools - # tree) execute all dependencies in a single python process, so - # "versioneer" may be imported multiple times, and python's shared - # module-import table will cache the first one. So we can't use - # os.path.dirname(__file__), as that will find whichever - # versioneer.py was first imported, even in later projects. - me = os.path.realpath(os.path.abspath(__file__)) - me_dir = os.path.normcase(os.path.splitext(me)[0]) - vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) - if me_dir != vsr_dir: - print("Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(me), versioneer_py)) - except NameError: - pass - return root - - -def get_config_from_root(root): - """Read the project setup.cfg file to determine Versioneer config.""" - # This might raise EnvironmentError (if setup.cfg is missing), or - # configparser.NoSectionError (if it lacks a [versioneer] section), or - # configparser.NoOptionError (if it lacks "VCS="). See the docstring at - # the top of versioneer.py for instructions on writing your setup.cfg . - setup_cfg = os.path.join(root, "setup.cfg") - parser = configparser.SafeConfigParser() - with open(setup_cfg, "r") as f: - parser.readfp(f) - VCS = parser.get("versioneer", "VCS") # mandatory - - def get(parser, name): - if parser.has_option("versioneer", name): - return parser.get("versioneer", name) - return None - cfg = VersioneerConfig() - cfg.VCS = VCS - cfg.style = get(parser, "style") or "" - cfg.versionfile_source = get(parser, "versionfile_source") - cfg.versionfile_build = get(parser, "versionfile_build") - cfg.tag_prefix = get(parser, "tag_prefix") - if cfg.tag_prefix in ("''", '""'): - cfg.tag_prefix = "" - cfg.parentdir_prefix = get(parser, "parentdir_prefix") - cfg.verbose = get(parser, "verbose") - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -# these dictionaries contain VCS-specific tools -LONG_VERSION_PY = {} -HANDLERS = {} - - -def register_vcs_handler(vcs, method): # decorator - """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - p = None - for c in commands: - try: - dispcmd = str([c] + args) - # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) - break - except EnvironmentError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %s" % dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %s" % (commands,)) - return None, None - stdout = p.communicate()[0].strip() - if sys.version_info[0] >= 3: - stdout = stdout.decode() - if p.returncode != 0: - if verbose: - print("unable to run %s (error)" % dispcmd) - print("stdout was %s" % stdout) - return None, p.returncode - return stdout, p.returncode - - -LONG_VERSION_PY['git'] = ''' -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (built by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. - -# This file is released into the public domain. Generated by -# versioneer-0.18 (https://github.com/warner/python-versioneer) - -"""Git implementation of _version.py.""" - -import errno -import os -import re -import subprocess -import sys - - -def get_keywords(): - """Get the keywords needed to look up the version information.""" - # these strings will be replaced by git during git-archive. - # setup.py/versioneer.py will grep for the variable names, so they must - # each be defined on a line of their own. _version.py will just call - # get_keywords(). - git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" - git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" - git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s" - keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} - return keywords - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_config(): - """Create, populate and return the VersioneerConfig() object.""" - # these strings are filled in when 'setup.py versioneer' creates - # _version.py - cfg = VersioneerConfig() - cfg.VCS = "git" - cfg.style = "%(STYLE)s" - cfg.tag_prefix = "%(TAG_PREFIX)s" - cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s" - cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s" - cfg.verbose = False - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -LONG_VERSION_PY = {} -HANDLERS = {} - - -def register_vcs_handler(vcs, method): # decorator - """Decorator to mark a method as the handler for a particular VCS.""" - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - p = None - for c in commands: - try: - dispcmd = str([c] + args) - # remember shell=False, so use git.cmd on windows, not just git - p = subprocess.Popen([c] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None)) - break - except EnvironmentError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %%s" %% dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %%s" %% (commands,)) - return None, None - stdout = p.communicate()[0].strip() - if sys.version_info[0] >= 3: - stdout = stdout.decode() - if p.returncode != 0: - if verbose: - print("unable to run %%s (error)" %% dispcmd) - print("stdout was %%s" %% stdout) - return None, p.returncode - return stdout, p.returncode - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for i in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} - else: - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print("Tried directories %%s but none started with prefix %%s" %% - (str(rootdirs), parentdir_prefix)) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - f = open(versionfile_abs, "r") - for line in f.readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - f.close() - except EnvironmentError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if not keywords: - raise NotThisMethod("no keywords at all, weird") - date = keywords.get("date") - if date is not None: - # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = set([r.strip() for r in refnames.strip("()").split(",")]) - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %%d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) - if verbose: - print("discarding '%%s', no digits" %% ",".join(refs - tags)) - if verbose: - print("likely tags: %%s" %% ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - if verbose: - print("picking %%s" %% r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) - if rc != 0: - if verbose: - print("Directory %%s not under git control" %% root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", - "--match", "%%s*" %% tag_prefix], - cwd=root) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) - if not mo: - # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%%s'" - %% describe_out) - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%%s' doesn't start with prefix '%%s'" - print(fmt %% (full_tag, tag_prefix)) - pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'" - %% (full_tag, tag_prefix)) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) - pieces["distance"] = int(count_out) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%%ci", "HEAD"], - cwd=root)[0].strip() - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def plus_or_dot(pieces): - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_pre(pieces): - """TAG[.post.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post.devDISTANCE - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += ".post.dev%%d" %% pieces["distance"] - else: - # exception #1 - rendered = "0.post.dev%%d" %% pieces["distance"] - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%%s" %% pieces["short"] - else: - # exception #1 - rendered = "0.post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%%s" %% pieces["short"] - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Eexceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%%s'" %% style) - - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} - - -def get_versions(): - """Get version information or return default if unable to do so.""" - # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have - # __file__, we can work backwards from there to the root. Some - # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which - # case we can only use expanded keywords. - - override = os.getenv("VERSIONEER_OVERRIDE") - if override: - return {"version": override, "full-revisionid": None, - "dirty": None, - "error": None, "date": None} - - cfg = get_config() - verbose = cfg.verbose - - try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) - except NotThisMethod: - pass - - try: - root = os.path.realpath(__file__) - # versionfile_source is the relative path from the top of the source - # tree (where the .git directory might live) to this file. Invert - # this to find the root from __file__. - for i in cfg.versionfile_source.split('/'): - root = os.path.dirname(root) - except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} - - try: - pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) - return render(pieces, cfg.style) - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - except NotThisMethod: - pass - - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} -''' - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - f = open(versionfile_abs, "r") - for line in f.readlines(): - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - f.close() - except EnvironmentError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if not keywords: - raise NotThisMethod("no keywords at all, weird") - date = keywords.get("date") - if date is not None: - # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = set([r.strip() for r in refnames.strip("()").split(",")]) - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = set([r for r in refs if re.search(r'\d', r)]) - if verbose: - print("discarding '%s', no digits" % ",".join(refs - tags)) - if verbose: - print("likely tags: %s" % ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - if verbose: - print("picking %s" % r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) - if rc != 0: - if verbose: - print("Directory %s not under git control" % root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", "--abbrev=8", - "--match", "%s*" % tag_prefix], - cwd=root) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:8] # maybe improved later - pieces["error"] = None - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) - if not mo: - # unparseable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%s'" - % describe_out) - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%s' doesn't start with prefix '%s'" - print(fmt % (full_tag, tag_prefix)) - pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" - % (full_tag, tag_prefix)) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], - cwd=root) - pieces["distance"] = int(count_out) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], - cwd=root)[0].strip() - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def do_vcs_install(manifest_in, versionfile_source, ipy): - """Git-specific installation logic for Versioneer. - - For Git, this means creating/changing .gitattributes to mark _version.py - for export-subst keyword substitution. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - files = [manifest_in, versionfile_source] - if ipy: - files.append(ipy) - try: - me = __file__ - if me.endswith(".pyc") or me.endswith(".pyo"): - me = os.path.splitext(me)[0] + ".py" - versioneer_file = os.path.relpath(me) - except NameError: - versioneer_file = "versioneer.py" - files.append(versioneer_file) - present = False - try: - f = open(".gitattributes", "r") - for line in f.readlines(): - if line.strip().startswith(versionfile_source): - if "export-subst" in line.strip().split()[1:]: - present = True - f.close() - except EnvironmentError: - pass - if not present: - f = open(".gitattributes", "a+") - f.write("%s export-subst\n" % versionfile_source) - f.close() - files.append(".gitattributes") - run_command(GITS, ["add", "--"] + files) - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for i in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} - else: - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print("Tried directories %s but none started with prefix %s" % - (str(rootdirs), parentdir_prefix)) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -SHORT_VERSION_PY = """ -# This file was generated by 'versioneer.py' (0.18) from -# revision-control system data, or from the parent directory name of an -# unpacked source archive. Distribution tarballs contain a pre-generated copy -# of this file. - -import json - -version_json = ''' -%s -''' # END VERSION_JSON - - -def get_versions(): - return json.loads(version_json) +VERSION_FILE = """ +def get_version(): + return "{version}" """ - -def versions_from_file(filename): - """Try to determine the version from _version.py if present.""" - try: - with open(filename) as f: - contents = f.read() - except EnvironmentError: - raise NotThisMethod("unable to read _version.py") - mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) - if not mo: - mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", - contents, re.M | re.S) - if not mo: - raise NotThisMethod("no version_json in _version.py") - return json.loads(mo.group(1)) - - -def write_to_version_file(filename, versions): - """Write the given version number to the given _version.py file.""" - os.unlink(filename) - contents = json.dumps(versions, sort_keys=True, - indent=1, separators=(",", ": ")) - with open(filename, "w") as f: - f.write(SHORT_VERSION_PY % contents) - - print("set %s to '%s'" % (filename, versions["version"])) - - -def plus_or_dot(pieces): - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_pre(pieces): - """TAG[.post.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post.devDISTANCE - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += ".post.dev%d" % pieces["distance"] - else: - # exception #1 - rendered = "0.post.dev%d" % pieces["distance"] - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%s" % pieces["short"] - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%s" % pieces["short"] - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Eexceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%s'" % style) - - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} - - -class VersioneerBadRootError(Exception): - """The project root directory is unknown or missing key files.""" - - -def get_versions(verbose=False): - """Get the project version from whatever source is available. - - Returns dict with two keys: 'version' and 'full'. - """ - override = os.getenv("VERSIONEER_OVERRIDE") - if override: - return {"version": override, "full-revisionid": None, - "dirty": None, - "error": None, "date": None} - - if "versioneer" in sys.modules: - # see the discussion in cmdclass.py:get_cmdclass() - del sys.modules["versioneer"] - - root = get_root() - cfg = get_config_from_root(root) - - assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg" - handlers = HANDLERS.get(cfg.VCS) - assert handlers, "unrecognized VCS '%s'" % cfg.VCS - verbose = verbose or cfg.verbose - assert cfg.versionfile_source is not None, \ - "please set versioneer.versionfile_source" - assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" - - versionfile_abs = os.path.join(root, cfg.versionfile_source) - - # extract version from first of: _version.py, VCS command (e.g. 'git - # describe'), parentdir. This is meant to work for developers using a - # source checkout, for users of a tarball created by 'setup.py sdist', - # and for users of a tarball/zipball created by 'git archive' or github's - # download-from-tag feature or the equivalent in other VCSes. - - get_keywords_f = handlers.get("get_keywords") - from_keywords_f = handlers.get("keywords") - if get_keywords_f and from_keywords_f: - try: - keywords = get_keywords_f(versionfile_abs) - ver = from_keywords_f(keywords, cfg.tag_prefix, verbose) - if verbose: - print("got version from expanded keyword %s" % ver) - return ver - except NotThisMethod: - pass - - try: - ver = versions_from_file(versionfile_abs) - if verbose: - print("got version from file %s %s" % (versionfile_abs, ver)) - return ver - except NotThisMethod: - pass - - from_vcs_f = handlers.get("pieces_from_vcs") - if from_vcs_f: - try: - pieces = from_vcs_f(cfg.tag_prefix, root, verbose) - ver = render(pieces, cfg.style) - if verbose: - print("got version from VCS %s" % ver) - return ver - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - if verbose: - print("got version from parentdir %s" % ver) - return ver - except NotThisMethod: - pass - - if verbose: - print("unable to compute version") - - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, "error": "unable to compute version", - "date": None} - - def get_version(): - """Get the short version string for this project.""" - return get_versions()["version"] + override = os.getenv("VERSIONEER_OVERRIDE") + if override: + return override + srcroot = os.path.dirname(os.path.abspath(__file__)) + with open(os.path.join(srcroot, "MAJOR_VERSION"), "r") as f: + version = f.read().strip() + version += ".unknown" + if os.path.exists(os.path.join(srcroot, "BETA")): + version += ".beta" + return version + +def write_to_version_file(filename, version): + os.unlink(filename) + with open(filename, "w") as f: + f.write(VERSION_FILE.format(version=version)) def get_cmdclass(): - """Get the custom setuptools/distutils subclasses used by Versioneer.""" - if "versioneer" in sys.modules: - del sys.modules["versioneer"] - # this fixes the "python setup.py develop" case (also 'install' and - # 'easy_install .'), in which subdependencies of the main project are - # built (using setup.py bdist_egg) in the same python process. Assume - # a main project A and a dependency B, which use different versions - # of Versioneer. A's setup.py imports A's Versioneer, leaving it in - # sys.modules by the time B's setup.py is executed, causing B to run - # with the wrong versioneer. Setuptools wraps the sub-dep builds in a - # sandbox that restores sys.modules to it's pre-build state, so the - # parent is protected against the child's "import versioneer". By - # removing ourselves from sys.modules here, before the child build - # happens, we protect the child from the parent's versioneer too. - # Also see https://github.com/warner/python-versioneer/issues/52 - cmds = {} - # we add "version" to both distutils and setuptools - from distutils.core import Command - - class cmd_version(Command): - description = "report generated version string" - user_options = [] - boolean_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - vers = get_versions(verbose=True) - print("Version: %s" % vers["version"]) - print(" full-revisionid: %s" % vers.get("full-revisionid")) - print(" dirty: %s" % vers.get("dirty")) - print(" date: %s" % vers.get("date")) - if vers["error"]: - print(" error: %s" % vers["error"]) - cmds["version"] = cmd_version - - # we override "build_py" in both distutils and setuptools - # - # most invocation pathways end up running build_py: - # distutils/build -> build_py - # distutils/install -> distutils/build ->.. - # setuptools/bdist_wheel -> distutils/install ->.. - # setuptools/bdist_egg -> distutils/install_lib -> build_py - # setuptools/install -> bdist_egg ->.. - # setuptools/develop -> ? - # pip install: - # copies source tree to a tempdir before running egg_info/etc - # if .git isn't copied too, 'git describe' will fail - # then does setup.py bdist_wheel, or sometimes setup.py install - # setup.py egg_info -> ? - # we override different "build_py" commands for both environments if "setuptools" in sys.modules: from setuptools.command.build_py import build_py as _build_py @@ -1558,78 +35,14 @@ def get_cmdclass(): class cmd_build_py(_build_py): def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() + version = get_version() _build_py.run(self) - # now locate _version.py in the new build/ directory and replace - # it with an updated value - if cfg.versionfile_build: - target_versionfile = os.path.join(self.build_lib, - cfg.versionfile_build) - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) + target_versionfile = os.path.join(self.build_lib, + "artiq", "_version.py") + print("UPDATING %s" % target_versionfile) + write_to_version_file(target_versionfile, version) cmds["build_py"] = cmd_build_py - if "cx_Freeze" in sys.modules: # cx_freeze enabled? - from cx_Freeze.dist import build_exe as _build_exe - # nczeczulin reports that py2exe won't like the pep440-style string - # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. - # setup(console=[{ - # "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION - # "product_version": versioneer.get_version(), - # ... - - class cmd_build_exe(_build_exe): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - target_versionfile = cfg.versionfile_source - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - _build_exe.run(self) - os.unlink(target_versionfile) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - cmds["build_exe"] = cmd_build_exe - del cmds["build_py"] - - if 'py2exe' in sys.modules: # py2exe enabled? - try: - from py2exe.distutils_buildexe import py2exe as _py2exe # py3 - except ImportError: - from py2exe.build_exe import py2exe as _py2exe # py2 - - class cmd_py2exe(_py2exe): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - target_versionfile = cfg.versionfile_source - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - _py2exe.run(self) - os.unlink(target_versionfile) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % - {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments if "setuptools" in sys.modules: @@ -1639,196 +52,19 @@ def get_cmdclass(): class cmd_sdist(_sdist): def run(self): - versions = get_versions() - self._versioneer_generated_versions = versions + version = get_version() + self._versioneer_generated_version = version # unless we update this, the command will keep using the old # version - self.distribution.metadata.version = versions["version"] + self.distribution.metadata.version = version return _sdist.run(self) def make_release_tree(self, base_dir, files): - root = get_root() - cfg = get_config_from_root(root) _sdist.make_release_tree(self, base_dir, files) - # now locate _version.py in the new base_dir directory - # (remembering that it may be a hardlink) and replace it with an - # updated value - target_versionfile = os.path.join(base_dir, cfg.versionfile_source) + target_versionfile = os.path.join(base_dir, "artiq", "_version.py") print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, - self._versioneer_generated_versions) + self._versioneer_generated_version) cmds["sdist"] = cmd_sdist return cmds - - -CONFIG_ERROR = """ -setup.cfg is missing the necessary Versioneer configuration. You need -a section like: - - [versioneer] - VCS = git - style = pep440 - versionfile_source = src/myproject/_version.py - versionfile_build = myproject/_version.py - tag_prefix = - parentdir_prefix = myproject- - -You will also need to edit your setup.py to use the results: - - import versioneer - setup(version=versioneer.get_version(), - cmdclass=versioneer.get_cmdclass(), ...) - -Please read the docstring in ./versioneer.py for configuration instructions, -edit setup.cfg, and re-run the installer or 'python versioneer.py setup'. -""" - -SAMPLE_CONFIG = """ -# See the docstring in versioneer.py for instructions. Note that you must -# re-run 'versioneer.py setup' after changing this section, and commit the -# resulting files. - -[versioneer] -#VCS = git -#style = pep440 -#versionfile_source = -#versionfile_build = -#tag_prefix = -#parentdir_prefix = - -""" - -INIT_PY_SNIPPET = """ -from ._version import get_versions -__version__ = get_versions()['version'] -del get_versions -""" - - -def do_setup(): - """Main VCS-independent setup function for installing Versioneer.""" - root = get_root() - try: - cfg = get_config_from_root(root) - except (EnvironmentError, configparser.NoSectionError, - configparser.NoOptionError) as e: - if isinstance(e, (EnvironmentError, configparser.NoSectionError)): - print("Adding sample versioneer config to setup.cfg", - file=sys.stderr) - with open(os.path.join(root, "setup.cfg"), "a") as f: - f.write(SAMPLE_CONFIG) - print(CONFIG_ERROR, file=sys.stderr) - return 1 - - print(" creating %s" % cfg.versionfile_source) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write(LONG % {"DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - }) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), - "__init__.py") - if os.path.exists(ipy): - try: - with open(ipy, "r") as f: - old = f.read() - except EnvironmentError: - old = "" - if INIT_PY_SNIPPET not in old: - print(" appending to %s" % ipy) - with open(ipy, "a") as f: - f.write(INIT_PY_SNIPPET) - else: - print(" %s unmodified" % ipy) - else: - print(" %s doesn't exist, ok" % ipy) - ipy = None - - # Make sure both the top-level "versioneer.py" and versionfile_source - # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so - # they'll be copied into source distributions. Pip won't be able to - # install the package without this. - manifest_in = os.path.join(root, "MANIFEST.in") - simple_includes = set() - try: - with open(manifest_in, "r") as f: - for line in f: - if line.startswith("include "): - for include in line.split()[1:]: - simple_includes.add(include) - except EnvironmentError: - pass - # That doesn't cover everything MANIFEST.in can do - # (http://docs.python.org/2/distutils/sourcedist.html#commands), so - # it might give some false negatives. Appending redundant 'include' - # lines is safe, though. - if "versioneer.py" not in simple_includes: - print(" appending 'versioneer.py' to MANIFEST.in") - with open(manifest_in, "a") as f: - f.write("include versioneer.py\n") - else: - print(" 'versioneer.py' already in MANIFEST.in") - if cfg.versionfile_source not in simple_includes: - print(" appending versionfile_source ('%s') to MANIFEST.in" % - cfg.versionfile_source) - with open(manifest_in, "a") as f: - f.write("include %s\n" % cfg.versionfile_source) - else: - print(" versionfile_source already in MANIFEST.in") - - # Make VCS-specific changes. For git, this means creating/changing - # .gitattributes to mark _version.py for export-subst keyword - # substitution. - do_vcs_install(manifest_in, cfg.versionfile_source, ipy) - return 0 - - -def scan_setup_py(): - """Validate the contents of setup.py against Versioneer's expectations.""" - found = set() - setters = False - errors = 0 - with open("setup.py", "r") as f: - for line in f.readlines(): - if "import versioneer" in line: - found.add("import") - if "versioneer.get_cmdclass()" in line: - found.add("cmdclass") - if "versioneer.get_version()" in line: - found.add("get_version") - if "versioneer.VCS" in line: - setters = True - if "versioneer.versionfile_source" in line: - setters = True - if len(found) != 3: - print("") - print("Your setup.py appears to be missing some important items") - print("(but I might be wrong). Please make sure it has something") - print("roughly like the following:") - print("") - print(" import versioneer") - print(" setup( version=versioneer.get_version(),") - print(" cmdclass=versioneer.get_cmdclass(), ...)") - print("") - errors += 1 - if setters: - print("You should remove lines like 'versioneer.VCS = ' and") - print("'versioneer.versionfile_source = ' . This configuration") - print("now lives in setup.cfg, and should be removed from setup.py") - print("") - errors += 1 - return errors - - -if __name__ == "__main__": - cmd = sys.argv[1] - if cmd == "setup": - errors = do_setup() - errors += scan_setup_py() - if errors: - sys.exit(1) From 709026d945e29cc410ef035f3ee1a9945b66751e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 30 Jul 2020 17:46:22 +0800 Subject: [PATCH 2223/2457] test: relax device_to_host_rate --- artiq/test/coredevice/test_performance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index e5ccd7a98..071c5d27c 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -59,7 +59,7 @@ class TransferTest(ExperimentCase): exp = self.create(_Transfer) device_to_host_rate = exp.device_to_host() print(device_to_host_rate/(1024*1024), "MiB/s") - self.assertGreater(device_to_host_rate, 2.3e6) + self.assertGreater(device_to_host_rate, 2.2e6) def test_device_to_host_array(self): exp = self.create(_Transfer) From ae999db8f6814c63eae563aca69276feb59d305d Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 30 Jul 2020 16:40:23 +0100 Subject: [PATCH 2224/2457] compiler: Revert function call lifetime tracking fix This reverts commits f8d15069227298492ce539d793cfedfd8a80874c and cf19c9512dd41831bb5643025b9f3349c0828d83. While the commit just fixes a clear typo in the implementation, it turns out the original algorithm isn't flexible enough to capture functions that transitively return references to long-lived data. For instance, while cache_get() is special-cased in the compiler to be recognised as returning a value of Global() lifetime, a function just forwarding to it (as seen in the embedding tests) isn't anymore. A separate issue is also that this makes implementing functions that take lists and return references to global data in user code impossible, which central parts of the Oxford codebase rely on. Just reverting for now to unblock master; a fix is easily designed, but needs testing. --- RELEASE_NOTES.rst | 3 --- artiq/compiler/validators/escape.py | 2 +- artiq/test/lit/escape/error_call.py | 14 -------------- 3 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 artiq/test/lit/escape/error_call.py diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index d1f88b15f..7b9899d71 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -24,9 +24,6 @@ Highlights: * Core device: ``panic_reset 1`` now correctly resets the kernel CPU as well if communication CPU panic occurs. * NumberValue accepts a ``type`` parameter specifying the output as ``int`` or ``float`` -* In kernels, lifetime of allocated values (e.g. lists) is now correctly tracked across - function calls (see #1497, #1394). Previous versions (since ARTIQ 1.0) would accept - illegal code that would result in silent memory corruption at runtime. Breaking changes: diff --git a/artiq/compiler/validators/escape.py b/artiq/compiler/validators/escape.py index 5aae58e51..000c3ee5b 100644 --- a/artiq/compiler/validators/escape.py +++ b/artiq/compiler/validators/escape.py @@ -103,7 +103,7 @@ class RegionOf(algorithm.Visitor): # The cache is borrow checked dynamically return Global() else: - return self.visit_sometimes_allocating(node) + self.visit_sometimes_allocating(node) # Value lives as long as the object/container, if it's mutable, # or else forever diff --git a/artiq/test/lit/escape/error_call.py b/artiq/test/lit/escape/error_call.py deleted file mode 100644 index 8bbc7992f..000000000 --- a/artiq/test/lit/escape/error_call.py +++ /dev/null @@ -1,14 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t -# RUN: OutputCheck %s --file-to-check=%t - -from artiq.experiment import * - -@kernel -def leak(a): - return a - -@kernel -def entrypoint(): - # CHECK-L: ${LINE:+2}: error: cannot return an allocated value that does not live forever - # CHECK-L: ${LINE:+1}: note: ... to this point - return leak([1, 2, 3]) From 9c9dc3d0efac1af8bc601c0f10fb44c5094a1dfc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 1 Aug 2020 10:35:21 +0800 Subject: [PATCH 2225/2457] manual: Kasli now supports 10/100 Ethernet --- doc/manual/installing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index a812e82cf..d4f702487 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -225,7 +225,7 @@ The JTAG adapter is integrated into the Kasli board; for flashing (and debugging Setting up the core device IP networking ---------------------------------------- -For Kasli, insert a SFP/RJ45 transceiver (normally included with purchases from M-Labs and QUARTIQ) into the SFP0 port and connect it to a gigabit Ethernet port in your network. It is necessary that the port be gigabit - 10/100 ports cannot be used. If you need to interface Kasli with 10/100 network equipment, connect them through a gigabit switch. +For Kasli, insert a SFP/RJ45 transceiver (normally included with purchases from M-Labs and QUARTIQ) into the SFP0 port and connect it to an Ethernet port in your network. If the port is 10Mbps or 100Mbps and not 1000Mbps, make sure that the SFP/RJ45 transceiver supports the lower rate. Many SFP/RJ45 transceivers only support the 1000Mbps rate. If you do not have a SFP/RJ45 transceiver that supports 10Mbps and 100Mbps rates, you may instead use a gigabit Ethernet switch in the middle to perform rate conversion. You can also insert other types of SFP transceivers into Kasli if you wish to use it directly in e.g. an optical fiber Ethernet network. From e3c5775584929f974870abfaf4f61e35de5c0513 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 6 Aug 2020 10:54:30 +0800 Subject: [PATCH 2226/2457] test: skip CacheTest.test_borrow on Zynq --- artiq/test/coredevice/test_cache.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/test/coredevice/test_cache.py b/artiq/test/coredevice/test_cache.py index 368515e0b..07452cf07 100644 --- a/artiq/test/coredevice/test_cache.py +++ b/artiq/test/coredevice/test_cache.py @@ -1,5 +1,6 @@ from artiq.experiment import * from artiq.coredevice.exceptions import CacheError +from artiq.compiler.targets import CortexA9Target from artiq.test.hardware_testbench import ExperimentCase @@ -40,6 +41,8 @@ class CacheTest(ExperimentCase): def test_borrow(self): exp = self.create(_Cache) + if exp.core.target_cls == CortexA9Target: + self.skipTest("Zynq port memory management does not need CacheError") exp.put("x4", [1, 2, 3]) with self.assertRaises(CacheError): exp.get_put("x4", []) From 3bfd372c20d43def2dbc538b35a81ea38703e77e Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 6 Aug 2020 16:07:28 +0800 Subject: [PATCH 2227/2457] compiler: linker discard local symbols. Fixes exception backtrace problem for ARM. --- artiq/compiler/targets.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index 9b985c32e..9ebc7907d 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -183,6 +183,7 @@ class Target: """Link the relocatable objects into a shared library for this target.""" with RunTool([self.tool_ld, "-shared", "--eh-frame-hdr"] + ["{{obj{}}}".format(index) for index in range(len(objects))] + + ["-x"] + ["-o", "{output}"], output=None, **{"obj{}".format(index): obj for index, obj in enumerate(objects)}) \ From 5f36e49f911bc8a714e8b2be45d92c42fe341714 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 6 Aug 2020 16:36:14 +0800 Subject: [PATCH 2228/2457] test_rtio: make DMA test generic wrt TTL channel --- artiq/test/coredevice/test_rtio.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index c6f42366a..96437d2a2 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -579,7 +579,7 @@ class _DMA(EnvExperiment): def build(self, trace_name="test_rtio"): self.setattr_device("core") self.setattr_device("core_dma") - self.setattr_device("ttl1") + self.setattr_device("ttl_out") self.trace_name = trace_name self.delta = np.int64(0) @@ -591,9 +591,9 @@ class _DMA(EnvExperiment): if not for_handle: delay(1*ms) delay(100*ns) - self.ttl1.on() + self.ttl_out.on() delay(100*ns) - self.ttl1.off() + self.ttl_out.off() @kernel def record_many(self, n): @@ -601,9 +601,9 @@ class _DMA(EnvExperiment): with self.core_dma.record(self.trace_name): for i in range(n//2): delay(100*ns) - self.ttl1.on() + self.ttl_out.on() delay(100*ns) - self.ttl1.off() + self.ttl_out.off() t2 = self.core.get_rtio_counter_mu() self.set_dataset("dma_record_time", self.core.mu_to_seconds(t2 - t1)) @@ -670,6 +670,7 @@ class DMATest(ExperimentCase): core_host = self.device_mgr.get_desc("core")["arguments"]["host"] exp = self.create(_DMA) + channel = exp.ttl_out.channel for use_handle in [False, True]: exp.record(use_handle) @@ -680,11 +681,11 @@ class DMATest(ExperimentCase): self.assertEqual(len(dump.messages), 3) self.assertIsInstance(dump.messages[-1], StoppedMessage) self.assertIsInstance(dump.messages[0], OutputMessage) - self.assertEqual(dump.messages[0].channel, 1) + self.assertEqual(dump.messages[0].channel, channel) self.assertEqual(dump.messages[0].address, 0) self.assertEqual(dump.messages[0].data, 1) self.assertIsInstance(dump.messages[1], OutputMessage) - self.assertEqual(dump.messages[1].channel, 1) + self.assertEqual(dump.messages[1].channel, channel) self.assertEqual(dump.messages[1].address, 0) self.assertEqual(dump.messages[1].data, 0) self.assertEqual(dump.messages[1].timestamp - From 504f72a02c03abf78f384857def7ae089405e36a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 6 Aug 2020 17:52:32 +0800 Subject: [PATCH 2229/2457] rtio: remove legacy i_overflow_reset CSR --- artiq/firmware/ksupport/rtio.rs | 3 --- artiq/gateware/rtio/cri.py | 1 - 2 files changed, 4 deletions(-) diff --git a/artiq/firmware/ksupport/rtio.rs b/artiq/firmware/ksupport/rtio.rs index 5ce17850f..a83a45ec1 100644 --- a/artiq/firmware/ksupport/rtio.rs +++ b/artiq/firmware/ksupport/rtio.rs @@ -112,7 +112,6 @@ mod imp { } if status & RTIO_I_STATUS_OVERFLOW != 0 { - csr::rtio::i_overflow_reset_write(1); raise!("RTIOOverflow", "RTIO input overflow on channel {0}", channel as i64, 0, 0); @@ -141,7 +140,6 @@ mod imp { } if status & RTIO_I_STATUS_OVERFLOW != 0 { - csr::rtio::i_overflow_reset_write(1); raise!("RTIOOverflow", "RTIO input overflow on channel {0}", channel as i64, 0, 0); @@ -167,7 +165,6 @@ mod imp { } if status & RTIO_I_STATUS_OVERFLOW != 0 { - csr::rtio::i_overflow_reset_write(1); raise!("RTIOOverflow", "RTIO input overflow on channel {0}", channel as i64, 0, 0); diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 0de13b8d1..c735b9e5f 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -79,7 +79,6 @@ class KernelInitiator(Module, AutoCSR): self.i_data = CSRStatus(32) self.i_timestamp = CSRStatus(64) self.i_status = CSRStatus(4) - self.i_overflow_reset = CSR() self.counter = CSRStatus(64) self.counter_update = CSR() From 1df62862cd6c32c6499740c6b05e8080b4aee518 Mon Sep 17 00:00:00 2001 From: pmldrmota <49479443+pmldrmota@users.noreply.github.com> Date: Fri, 7 Aug 2020 10:10:44 +0200 Subject: [PATCH 2230/2457] AD9910: Write correct number of bits to POW register (#1498) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * coredevice.ad9910: Add return type hints to conversion functions * coredevice.ad9910: Make set_pow write correct number of bits The AD9910 expects 16 bits. Thus, if writing 32 bits to the POW register, the chip would likely enter a locked-up state. * coredevice.ad9910: Correct data alignment in write_16 Co-authored-by: Robert Jördens * coredevice.ad9910: Add function to read from 16 bit registers Co-authored-by: drmota Co-authored-by: Robert Jördens --- artiq/coredevice/ad9910.py | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index cc6316791..fbe6bca41 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -3,6 +3,7 @@ from numpy import int32, int64 from artiq.language.core import ( kernel, delay, portable, delay_mu, now_mu, at_mu) from artiq.language.units import us, ms +from artiq.language.types import * from artiq.coredevice import spi2 as spi from artiq.coredevice import urukul @@ -222,6 +223,17 @@ class AD9910: """ self.phase_mode = phase_mode + @kernel + def write16(self, addr, data): + """Write to 16 bit register. + + :param addr: Register address + :param data: Data to be written + """ + self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 24, + urukul.SPIT_DDS_WR, self.chip_select) + self.bus.write((addr << 24) | (data << 8)) + @kernel def write32(self, addr, data): """Write to 32 bit register. @@ -236,6 +248,21 @@ class AD9910: urukul.SPIT_DDS_WR, self.chip_select) self.bus.write(data) + @kernel + def read16(self, addr): + """Read from 16 bit register. + + :param addr: Register address + """ + self.bus.set_config_mu(urukul.SPI_CONFIG, 8, + urukul.SPIT_DDS_WR, self.chip_select) + self.bus.write((addr | 0x80) << 24) + self.bus.set_config_mu( + urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, + 16, urukul.SPIT_DDS_RD, self.chip_select) + self.bus.write(0) + return self.bus.read() + @kernel def read32(self, addr): """Read from 32 bit register. @@ -549,10 +576,10 @@ class AD9910: :param pow_: Phase offset word to be stored, range: 0 to 0xffff. """ - self.write32(_AD9910_REG_POW, pow_) + self.write16(_AD9910_REG_POW, pow_) @portable(flags={"fast-math"}) - def frequency_to_ftw(self, frequency): + def frequency_to_ftw(self, frequency) -> TInt32: """Return the 32-bit frequency tuning word corresponding to the given frequency. """ @@ -566,7 +593,7 @@ class AD9910: return ftw / self.ftw_per_hz @portable(flags={"fast-math"}) - def turns_to_pow(self, turns): + def turns_to_pow(self, turns) -> TInt32: """Return the 16-bit phase offset word corresponding to the given phase in turns.""" return int32(round(turns*0x10000)) & 0xffff @@ -578,7 +605,7 @@ class AD9910: return pow_/0x10000 @portable(flags={"fast-math"}) - def amplitude_to_asf(self, amplitude): + def amplitude_to_asf(self, amplitude) -> TInt32: """Return 14-bit amplitude scale factor corresponding to given fractional amplitude.""" code = int32(round(amplitude * 0x3fff)) From 6ea836183d59f0cd00736a08fc220c7174b725d7 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 25 Jul 2020 18:05:59 +0100 Subject: [PATCH 2231/2457] test/lit: Move some list tests to appropriate module [nfc] --- artiq/test/lit/integration/array.py | 3 --- artiq/test/lit/integration/list.py | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/test/lit/integration/array.py b/artiq/test/lit/integration/array.py index 34463a799..aec874497 100644 --- a/artiq/test/lit/integration/array.py +++ b/artiq/test/lit/integration/array.py @@ -3,6 +3,3 @@ ary = array([1, 2, 3]) assert [x*x for x in ary] == [1, 4, 9] - -assert [1] + [2] == [1, 2] -assert [1] * 3 == [1, 1, 1] diff --git a/artiq/test/lit/integration/list.py b/artiq/test/lit/integration/list.py index 68ac2809e..97fad6a6c 100644 --- a/artiq/test/lit/integration/list.py +++ b/artiq/test/lit/integration/list.py @@ -14,3 +14,6 @@ assert [[0]] == [[0]] assert [[0]] != [[1]] assert [[[0]]] == [[[0]]] assert [[[0]]] != [[[1]]] + +assert [1] + [2] == [1, 2] +assert [1] * 3 == [1, 1, 1] From 56010c49fb2f4e1b2fc6e68cb9d9ed07658e78a2 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 25 Jul 2020 20:09:42 +0100 Subject: [PATCH 2232/2457] compiler/inferencer: Detect rectangular array()s Still needs support through all the rest of the compiler, and support for higher-dimensional arrays. Alternatively, we could always assume ndarrays of ndarrays are rectangular (i.e. ban array/list element types), and detect mismatch at runtime. This might turn out to be preferrable to be able to construct matrices from rows/columns. `array()` is disallowed for no particularly good reason but numpy API compatibility. --- artiq/compiler/transforms/inferencer.py | 30 ++++++++++++++++++++---- artiq/test/lit/inferencer/array.py | 13 ++++++++++ artiq/test/lit/inferencer/error_array.py | 5 ++++ 3 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 artiq/test/lit/inferencer/array.py create mode 100644 artiq/test/lit/inferencer/error_array.py diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 2f5d1800c..8a4c258d3 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -7,6 +7,21 @@ from pythonparser import algorithm, diagnostic, ast from .. import asttyped, types, builtins from .typedtree_printer import TypedtreePrinter + +def is_rectangular_2d_list(node): + if not isinstance(node, asttyped.ListT): + return False + num_elts = None + for e in node.elts: + if not isinstance(e, asttyped.ListT): + return False + if num_elts is None: + num_elts = len(e.elts) + elif num_elts != len(e.elts): + return False + return True + + class Inferencer(algorithm.Visitor): """ :class:`Inferencer` infers types by recursively applying the unification @@ -706,7 +721,6 @@ class Inferencer(algorithm.Visitor): node.loc, None) elif types.is_builtin(typ, "array"): valid_forms = lambda: [ - valid_form("array() -> array(elt='a)"), valid_form("array(x:'a) -> array(elt='b) where 'a is iterable") ] @@ -715,8 +729,10 @@ class Inferencer(algorithm.Visitor): else: assert False - if len(node.args) == 0 and len(node.keywords) == 0: - pass # [] + if (types.is_builtin(typ, "list") and len(node.args) == 0 and + len(node.keywords) == 0): + # Mimic numpy and don't allow array() (but []). + pass elif len(node.args) == 1 and len(node.keywords) == 0: arg, = node.args @@ -732,8 +748,14 @@ class Inferencer(algorithm.Visitor): {"typeb": printer.name(typeb)}, locb) ] + elt = arg.type.find().params["elt"] + if types.is_builtin(typ, "array") and builtins.is_listish(elt): + # KLUDGE: Support 2D arary creation if lexically specified + # as a rectangular array of lists. + if is_rectangular_2d_list(arg): + elt = elt.find().params["elt"] self._unify(node.type.find().params["elt"], - arg.type.find().params["elt"], + elt, node.loc, arg.loc, makenotes=makenotes) elif types.is_var(arg.type): pass # undetermined yet diff --git a/artiq/test/lit/inferencer/array.py b/artiq/test/lit/inferencer/array.py new file mode 100644 index 000000000..c4f215db8 --- /dev/null +++ b/artiq/test/lit/inferencer/array.py @@ -0,0 +1,13 @@ +# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +# CHECK-L: numpy.array(elt='a) +array([]) + +# CHECK-L: numpy.array(elt=numpy.int?) +array([1, 2, 3]) +# CHECK-L: numpy.array(elt=numpy.int?) +array([[1, 2, 3], [4, 5, 6]]) + +# CHECK-L: numpy.array(elt=list(elt=numpy.int?)) +array([[1, 2, 3], [4, 5]]) diff --git a/artiq/test/lit/inferencer/error_array.py b/artiq/test/lit/inferencer/error_array.py new file mode 100644 index 000000000..b1bd5cc5f --- /dev/null +++ b/artiq/test/lit/inferencer/error_array.py @@ -0,0 +1,5 @@ +# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +# CHECK-L: ${LINE:+1}: error: array cannot be invoked with the arguments () +a = array() From 575be2aeca88af00f69fe447b7a2fb1d1bcee8d4 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 25 Jul 2020 22:19:12 +0100 Subject: [PATCH 2233/2457] compiler: Basic support for creation of multidimensional arrays Breaks all uses of array(), as indexing is not yet implemented. --- artiq/compiler/builtins.py | 4 + .../compiler/transforms/artiq_ir_generator.py | 73 ++++++++++++++++++- .../compiler/transforms/llvm_ir_generator.py | 9 ++- artiq/test/lit/integration/array.py | 5 +- 4 files changed, 87 insertions(+), 4 deletions(-) diff --git a/artiq/compiler/builtins.py b/artiq/compiler/builtins.py index ce2e23e27..d881396a2 100644 --- a/artiq/compiler/builtins.py +++ b/artiq/compiler/builtins.py @@ -86,6 +86,10 @@ class TArray(types.TMono): if elt is None: elt = types.TVar() super().__init__("array", {"elt": elt}) + self.attributes = OrderedDict([ + ("shape", TList(TInt32())), + ("buffer", TList(elt)), + ]) def _array_printer(typ, printer, depth, max_depth): return "numpy.array(elt={})".format(printer.name(typ["elt"], depth, max_depth)) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 4e3c3394b..da593315f 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1637,7 +1637,7 @@ class ARTIQIRGenerator(algorithm.Visitor): return self.append(ir.Coerce(arg, node.type)) else: assert False - elif (types.is_builtin(typ, "list") or types.is_builtin(typ, "array") or + elif (types.is_builtin(typ, "list") or types.is_builtin(typ, "bytearray") or types.is_builtin(typ, "bytes")): if len(node.args) == 0 and len(node.keywords) == 0: length = ir.Constant(0, builtins.TInt32()) @@ -1660,6 +1660,77 @@ class ARTIQIRGenerator(algorithm.Visitor): return result else: assert False + elif types.is_builtin(typ, "array"): + if len(node.args) == 1 and len(node.keywords) == 0: + result_type = node.type.find() + arg = self.visit(node.args[0]) + + num_dims = 0 + result_elt = result_type["elt"].find() + inner_type = arg.type.find() + while True: + if inner_type == result_elt: + # TODO: What about types needing coercion (e.g. int32 to int64)? + break + assert builtins.is_iterable(inner_type) + num_dims += 1 + inner_type = builtins.get_iterable_elt(inner_type) + + # Derive shape from first element on each level (currently, type + # inference make sure arrays are always rectangular; in the future, we + # might want to insert a runtime check here). + # + # While we are at it, also total up overall number of elements + shape = self.append( + ir.Alloc([ir.Constant(num_dims, self._size_type)], + result_type.attributes["shape"])) + first_elt = arg + dim_idx = 0 + num_total_elts = None + while True: + length = self.iterable_len(first_elt) + self.append( + ir.SetElem(shape, ir.Constant(dim_idx, length.type), length)) + if num_total_elts is None: + num_total_elts = length + else: + num_total_elts = self.append( + ir.Arith(ast.Mult(loc=None), num_total_elts, length)) + + dim_idx += 1 + if dim_idx == num_dims: + break + first_elt = self.iterable_get(first_elt, + ir.Constant(0, length.type)) + + # Assign buffer from nested iterables. + buffer = self.append( + ir.Alloc([num_total_elts], result_type.attributes["buffer"])) + def body_gen(index): + # TODO: This is hilariously inefficient; we really want to emit a + # nested loop for the source and keep one running index for the + # target buffer. + indices = [] + mod_idx = index + for dim_idx in reversed(range(1, num_dims)): + dim_len = self.append(ir.GetElem(shape, ir.Constant(dim_idx, self._size_type))) + indices.append(self.append(ir.Arith(ast.Mod(loc=None), mod_idx, dim_len))) + mod_idx = self.append(ir.Arith(ast.FloorDiv(loc=None), mod_idx, dim_len)) + indices.append(mod_idx) + + elt = arg + for idx in reversed(indices): + elt = self.iterable_get(elt, idx) + self.append(ir.SetElem(buffer, index, elt)) + return self.append( + ir.Arith(ast.Add(loc=None), index, ir.Constant(1, length.type))) + self._make_loop( + ir.Constant(0, length.type), lambda index: self.append( + ir.Compare(ast.Lt(loc=None), index, num_total_elts)), body_gen) + + return self.append(ir.Alloc([shape, buffer], node.type)) + else: + assert False elif types.is_builtin(typ, "range"): elt_typ = builtins.get_iterable_elt(node.type) if len(node.args) == 1 and len(node.keywords) == 0: diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 84dcac2dd..3da6037a1 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -246,6 +246,10 @@ class LLVMIRGenerator: return ll.IntType(builtins.get_int_width(typ)) elif builtins.is_float(typ): return lldouble + elif builtins.is_array(typ): + llshapety = self.llty_of_type(typ.attributes["shape"]) + llbufferty = self.llty_of_type(typ.attributes["buffer"]) + return ll.LiteralStructType([llshapety, llbufferty]) elif builtins.is_listish(typ): lleltty = self.llty_of_type(builtins.get_iterable_elt(typ)) return ll.LiteralStructType([lleltty.as_pointer(), lli32]) @@ -733,7 +737,7 @@ class LLVMIRGenerator: name=insn.name) else: assert False - elif builtins.is_listish(insn.type): + elif builtins.is_listish(insn.type) and not builtins.is_array(insn.type): llsize = self.map(insn.operands[0]) lleltty = self.llty_of_type(builtins.get_iterable_elt(insn.type)) llalloc = self.llbuilder.alloca(lleltty, size=llsize) @@ -741,7 +745,8 @@ class LLVMIRGenerator: llvalue = self.llbuilder.insert_value(llvalue, llalloc, 0, name=insn.name) llvalue = self.llbuilder.insert_value(llvalue, llsize, 1) return llvalue - elif not builtins.is_allocated(insn.type) or ir.is_keyword(insn.type): + elif (not builtins.is_allocated(insn.type) or ir.is_keyword(insn.type) + or builtins.is_array(insn.type)): llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined) for index, elt in enumerate(insn.operands): llvalue = self.llbuilder.insert_value(llvalue, self.map(elt), index) diff --git a/artiq/test/lit/integration/array.py b/artiq/test/lit/integration/array.py index aec874497..3cb7fc58d 100644 --- a/artiq/test/lit/integration/array.py +++ b/artiq/test/lit/integration/array.py @@ -2,4 +2,7 @@ # REQUIRES: exceptions ary = array([1, 2, 3]) -assert [x*x for x in ary] == [1, 4, 9] +# FIXME: Implement ndarray indexing +# assert [x*x for x in ary] == [1, 4, 9] + +matrix = array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) From d882f8a3f031b337ad4008b4dfef48ea52cb258e Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 25 Jul 2020 22:34:52 +0100 Subject: [PATCH 2234/2457] compiler: Implement len() for ndarrays --- artiq/compiler/transforms/llvm_ir_generator.py | 4 ++++ artiq/test/lit/integration/array.py | 2 ++ 2 files changed, 6 insertions(+) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 3da6037a1..0ed3581fc 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -1170,6 +1170,10 @@ class LLVMIRGenerator: return get_outer(self.map(env), env.type) elif insn.op == "len": collection, = insn.operands + if builtins.is_array(collection.type): + # Return length of outermost dimension. + shape = self.llbuilder.extract_value(self.map(collection), 0) + return self.llbuilder.load(self.llbuilder.extract_value(shape, 0)) return self.llbuilder.extract_value(self.map(collection), 1) elif insn.op in ("printf", "rtio_log"): # We only get integers, floats, pointers and strings here. diff --git a/artiq/test/lit/integration/array.py b/artiq/test/lit/integration/array.py index 3cb7fc58d..c85ebaac1 100644 --- a/artiq/test/lit/integration/array.py +++ b/artiq/test/lit/integration/array.py @@ -2,7 +2,9 @@ # REQUIRES: exceptions ary = array([1, 2, 3]) +assert len(ary) == 3 # FIXME: Implement ndarray indexing # assert [x*x for x in ary] == [1, 4, 9] matrix = array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) +assert len(matrix) == 2 From 40f59561f26c4319bf9965b0376e50b6d0eaf1d3 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 25 Jul 2020 22:38:01 +0100 Subject: [PATCH 2235/2457] compiler: Add test for length of empty arrays [nfc] This makes sure we are actually emitting this as an 1D array (like NumPy does). --- artiq/test/lit/integration/array.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/artiq/test/lit/integration/array.py b/artiq/test/lit/integration/array.py index c85ebaac1..d8e8ab15c 100644 --- a/artiq/test/lit/integration/array.py +++ b/artiq/test/lit/integration/array.py @@ -6,5 +6,10 @@ assert len(ary) == 3 # FIXME: Implement ndarray indexing # assert [x*x for x in ary] == [1, 4, 9] +# Reassign to an existing value to disambiguate type of empty array. +empty_array = array([1]) +empty_array = array([]) +assert len(empty_array) == 0 + matrix = array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) assert len(matrix) == 2 From 632c5bc937463249d929c98ea69c73a1a67a7c7f Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 25 Jul 2020 22:58:42 +0100 Subject: [PATCH 2236/2457] compiler: Add ndarray .shape access --- artiq/compiler/transforms/llvm_ir_generator.py | 2 +- artiq/test/lit/integration/array.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 0ed3581fc..a8b85493d 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -881,7 +881,7 @@ class LLVMIRGenerator: if types.is_tuple(typ): return self.llbuilder.extract_value(self.map(insn.object()), attr, name=insn.name) - elif not builtins.is_allocated(typ): + elif builtins.is_array(typ) or not builtins.is_allocated(typ): return self.llbuilder.extract_value(self.map(insn.object()), self.attr_index(typ, attr), name=insn.name) diff --git a/artiq/test/lit/integration/array.py b/artiq/test/lit/integration/array.py index d8e8ab15c..3aa090603 100644 --- a/artiq/test/lit/integration/array.py +++ b/artiq/test/lit/integration/array.py @@ -3,6 +3,7 @@ ary = array([1, 2, 3]) assert len(ary) == 3 +assert ary.shape == [3] # FIXME: Implement ndarray indexing # assert [x*x for x in ary] == [1, 4, 9] @@ -10,6 +11,8 @@ assert len(ary) == 3 empty_array = array([1]) empty_array = array([]) assert len(empty_array) == 0 +assert empty_array.shape == [0] matrix = array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) assert len(matrix) == 2 +assert matrix.shape == [2, 3] From bc17bb4d1a28ae4f03efec91a576d34c57a1caf6 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 26 Jul 2020 01:07:03 +0100 Subject: [PATCH 2237/2457] compiler: Parametrize TArray in number of dimensions --- artiq/compiler/builtins.py | 15 +++- .../compiler/transforms/artiq_ir_generator.py | 60 ++++++------- artiq/compiler/transforms/inferencer.py | 86 ++++++++++++------- .../compiler/transforms/llvm_ir_generator.py | 2 +- artiq/compiler/validators/constness.py | 6 ++ artiq/test/lit/inferencer/error_array.py | 4 + artiq/test/lit/integration/array.py | 10 ++- 7 files changed, 107 insertions(+), 76 deletions(-) diff --git a/artiq/compiler/builtins.py b/artiq/compiler/builtins.py index d881396a2..ae7e61055 100644 --- a/artiq/compiler/builtins.py +++ b/artiq/compiler/builtins.py @@ -82,17 +82,24 @@ class TList(types.TMono): super().__init__("list", {"elt": elt}) class TArray(types.TMono): - def __init__(self, elt=None): + def __init__(self, elt=None, num_dims=types.TValue(1)): if elt is None: elt = types.TVar() - super().__init__("array", {"elt": elt}) + # For now, enforce number of dimensions to be known, as we'd otherwise + # need to implement custom unification logic for the type of `shape`. + # Default to 1 to keep compatibility with old user code from before + # multidimensional array support. + assert isinstance(num_dims.value, int), "Number of dimensions must be resolved" + + super().__init__("array", {"elt": elt, "num_dims": num_dims}) self.attributes = OrderedDict([ - ("shape", TList(TInt32())), + ("shape", types.TTuple([TInt32()] * num_dims.value)), ("buffer", TList(elt)), ]) def _array_printer(typ, printer, depth, max_depth): - return "numpy.array(elt={})".format(printer.name(typ["elt"], depth, max_depth)) + return "numpy.array(elt={}, num_dims={})".format( + printer.name(typ["elt"], depth, max_depth), typ["num_dims"].value) types.TypePrinter.custom_printers["array"] = _array_printer class TRange(types.TMono): diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index da593315f..730ea7f0a 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -7,6 +7,7 @@ semantics explicitly. """ from collections import OrderedDict, defaultdict +from functools import reduce from pythonparser import algorithm, diagnostic, ast from .. import types, builtins, asttyped, ir, iodelay @@ -1665,47 +1666,32 @@ class ARTIQIRGenerator(algorithm.Visitor): result_type = node.type.find() arg = self.visit(node.args[0]) - num_dims = 0 result_elt = result_type["elt"].find() - inner_type = arg.type.find() - while True: - if inner_type == result_elt: - # TODO: What about types needing coercion (e.g. int32 to int64)? - break - assert builtins.is_iterable(inner_type) - num_dims += 1 - inner_type = builtins.get_iterable_elt(inner_type) + num_dims = result_type["num_dims"].value # Derive shape from first element on each level (currently, type # inference make sure arrays are always rectangular; in the future, we # might want to insert a runtime check here). - # - # While we are at it, also total up overall number of elements - shape = self.append( - ir.Alloc([ir.Constant(num_dims, self._size_type)], - result_type.attributes["shape"])) - first_elt = arg - dim_idx = 0 - num_total_elts = None - while True: - length = self.iterable_len(first_elt) - self.append( - ir.SetElem(shape, ir.Constant(dim_idx, length.type), length)) - if num_total_elts is None: - num_total_elts = length + first_elt = None + lengths = [] + for dim_idx in range(num_dims): + if first_elt is None: + first_elt = arg else: - num_total_elts = self.append( - ir.Arith(ast.Mult(loc=None), num_total_elts, length)) + first_elt = self.iterable_get(first_elt, + ir.Constant(0, self._size_type)) + lengths.append(self.iterable_len(first_elt)) - dim_idx += 1 - if dim_idx == num_dims: - break - first_elt = self.iterable_get(first_elt, - ir.Constant(0, length.type)) + num_total_elts = reduce( + lambda l, r: self.append(ir.Arith(ast.Mult(loc=None), l, r)), + lengths[1:], lengths[0]) + + shape = self.append(ir.Alloc(lengths, result_type.attributes["shape"])) # Assign buffer from nested iterables. buffer = self.append( ir.Alloc([num_total_elts], result_type.attributes["buffer"])) + def body_gen(index): # TODO: This is hilariously inefficient; we really want to emit a # nested loop for the source and keep one running index for the @@ -1713,9 +1699,11 @@ class ARTIQIRGenerator(algorithm.Visitor): indices = [] mod_idx = index for dim_idx in reversed(range(1, num_dims)): - dim_len = self.append(ir.GetElem(shape, ir.Constant(dim_idx, self._size_type))) - indices.append(self.append(ir.Arith(ast.Mod(loc=None), mod_idx, dim_len))) - mod_idx = self.append(ir.Arith(ast.FloorDiv(loc=None), mod_idx, dim_len)) + dim_len = self.append(ir.GetAttr(shape, dim_idx)) + indices.append( + self.append(ir.Arith(ast.Mod(loc=None), mod_idx, dim_len))) + mod_idx = self.append( + ir.Arith(ast.FloorDiv(loc=None), mod_idx, dim_len)) indices.append(mod_idx) elt = arg @@ -1723,9 +1711,11 @@ class ARTIQIRGenerator(algorithm.Visitor): elt = self.iterable_get(elt, idx) self.append(ir.SetElem(buffer, index, elt)) return self.append( - ir.Arith(ast.Add(loc=None), index, ir.Constant(1, length.type))) + ir.Arith(ast.Add(loc=None), index, + ir.Constant(1, self._size_type))) + self._make_loop( - ir.Constant(0, length.type), lambda index: self.append( + ir.Constant(0, self._size_type), lambda index: self.append( ir.Compare(ast.Lt(loc=None), index, num_total_elts)), body_gen) return self.append(ir.Alloc([shape, buffer], node.type)) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 8a4c258d3..19ed2c85d 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -8,18 +8,28 @@ from .. import asttyped, types, builtins from .typedtree_printer import TypedtreePrinter -def is_rectangular_2d_list(node): - if not isinstance(node, asttyped.ListT): - return False +def match_rectangular_list(elts): num_elts = None - for e in node.elts: + elt_type = None + all_child_elts = [] + + for e in elts: + if elt_type is None: + elt_type = e.type.find() if not isinstance(e, asttyped.ListT): - return False + return elt_type, 0 if num_elts is None: num_elts = len(e.elts) elif num_elts != len(e.elts): - return False - return True + return elt_type, 0 + all_child_elts += e.elts + + if not all_child_elts: + # This ultimately turned out to be a list (of list, of ...) of empty lists. + return elt_type["elt"], 1 + + elt, num_dims = match_rectangular_list(all_child_elts) + return elt, num_dims + 1 class Inferencer(algorithm.Visitor): @@ -710,29 +720,45 @@ class Inferencer(algorithm.Visitor): "strings currently cannot be constructed", {}, node.loc) self.engine.process(diag) - elif types.is_builtin(typ, "list") or types.is_builtin(typ, "array"): - if types.is_builtin(typ, "list"): - valid_forms = lambda: [ - valid_form("list() -> list(elt='a)"), - valid_form("list(x:'a) -> list(elt='b) where 'a is iterable") - ] + elif types.is_builtin(typ, "array"): + valid_forms = lambda: [ + valid_form("array(x:'a) -> array(elt='b) where 'a is iterable") + ] - self._unify(node.type, builtins.TList(), - node.loc, None) - elif types.is_builtin(typ, "array"): - valid_forms = lambda: [ - valid_form("array(x:'a) -> array(elt='b) where 'a is iterable") - ] + if len(node.args) == 1 and len(node.keywords) == 0: + arg, = node.args - self._unify(node.type, builtins.TArray(), - node.loc, None) + if builtins.is_iterable(arg.type): + # KLUDGE: Support multidimensional arary creation if lexically + # specified as a rectangular array of lists. + elt, num_dims = match_rectangular_list([arg]) + self._unify(node.type, + builtins.TArray(elt, types.TValue(num_dims)), + node.loc, arg.loc) + elif types.is_var(arg.type): + pass # undetermined yet + else: + note = diagnostic.Diagnostic("note", + "this expression has type {type}", + {"type": types.TypePrinter().name(arg.type)}, + arg.loc) + diag = diagnostic.Diagnostic("error", + "the argument of {builtin}() must be of an iterable type", + {"builtin": typ.find().name}, + node.func.loc, notes=[note]) + self.engine.process(diag) else: - assert False + diagnose(valid_forms()) + elif types.is_builtin(typ, "list"): + valid_forms = lambda: [ + valid_form("list() -> list(elt='a)"), + valid_form("list(x:'a) -> list(elt='b) where 'a is iterable") + ] - if (types.is_builtin(typ, "list") and len(node.args) == 0 and - len(node.keywords) == 0): - # Mimic numpy and don't allow array() (but []). - pass + self._unify(node.type, builtins.TList(), node.loc, None) + + if len(node.args) == 0 and len(node.keywords) == 0: + pass # [] elif len(node.args) == 1 and len(node.keywords) == 0: arg, = node.args @@ -748,14 +774,8 @@ class Inferencer(algorithm.Visitor): {"typeb": printer.name(typeb)}, locb) ] - elt = arg.type.find().params["elt"] - if types.is_builtin(typ, "array") and builtins.is_listish(elt): - # KLUDGE: Support 2D arary creation if lexically specified - # as a rectangular array of lists. - if is_rectangular_2d_list(arg): - elt = elt.find().params["elt"] self._unify(node.type.find().params["elt"], - elt, + arg.type.find().params["elt"], node.loc, arg.loc, makenotes=makenotes) elif types.is_var(arg.type): pass # undetermined yet diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index a8b85493d..58615a43c 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -1173,7 +1173,7 @@ class LLVMIRGenerator: if builtins.is_array(collection.type): # Return length of outermost dimension. shape = self.llbuilder.extract_value(self.map(collection), 0) - return self.llbuilder.load(self.llbuilder.extract_value(shape, 0)) + return self.llbuilder.extract_value(shape, 0) return self.llbuilder.extract_value(self.map(collection), 1) elif insn.op in ("printf", "rtio_log"): # We only get integers, floats, pointers and strings here. diff --git a/artiq/compiler/validators/constness.py b/artiq/compiler/validators/constness.py index bfe228015..fb1123c49 100644 --- a/artiq/compiler/validators/constness.py +++ b/artiq/compiler/validators/constness.py @@ -50,3 +50,9 @@ class ConstnessValidator(algorithm.Visitor): node.loc) self.engine.process(diag) return + if builtins.is_array(typ): + diag = diagnostic.Diagnostic("error", + "array attributes cannot be assigned to", + {}, node.loc) + self.engine.process(diag) + return diff --git a/artiq/test/lit/inferencer/error_array.py b/artiq/test/lit/inferencer/error_array.py index b1bd5cc5f..787ae9294 100644 --- a/artiq/test/lit/inferencer/error_array.py +++ b/artiq/test/lit/inferencer/error_array.py @@ -3,3 +3,7 @@ # CHECK-L: ${LINE:+1}: error: array cannot be invoked with the arguments () a = array() + +b = array([1, 2, 3]) +# CHECK-L: ${LINE:+1}: error: array attributes cannot be assigned to +b.shape = (5, ) diff --git a/artiq/test/lit/integration/array.py b/artiq/test/lit/integration/array.py index 3aa090603..c02728334 100644 --- a/artiq/test/lit/integration/array.py +++ b/artiq/test/lit/integration/array.py @@ -3,7 +3,7 @@ ary = array([1, 2, 3]) assert len(ary) == 3 -assert ary.shape == [3] +assert ary.shape == (3,) # FIXME: Implement ndarray indexing # assert [x*x for x in ary] == [1, 4, 9] @@ -11,8 +11,12 @@ assert ary.shape == [3] empty_array = array([1]) empty_array = array([]) assert len(empty_array) == 0 -assert empty_array.shape == [0] +assert empty_array.shape == (0,) matrix = array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) assert len(matrix) == 2 -assert matrix.shape == [2, 3] +assert matrix.shape == (2, 3) + +three_tensor = array([[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]]) +assert len(three_tensor) == 1 +assert three_tensor.shape == (1, 2, 3) From c95a978ab64063ef26e6c168914b91d9071b167b Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 26 Jul 2020 01:33:52 +0100 Subject: [PATCH 2238/2457] compiler: Iteration for 1D ndarrays --- artiq/compiler/transforms/artiq_ir_generator.py | 9 ++++++++- artiq/compiler/transforms/inferencer.py | 8 ++++++++ artiq/test/lit/integration/array.py | 4 ++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 730ea7f0a..afd0da1a9 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -510,7 +510,14 @@ class ARTIQIRGenerator(algorithm.Visitor): def iterable_get(self, value, index): # Assuming the value is within bounds. - if builtins.is_listish(value.type): + if builtins.is_array(value.type): + # Scalar indexing into ndarray. + if value.type.find()["num_dims"].value > 1: + raise NotImplementedError + else: + buffer = self.append(ir.GetAttr(value, "buffer")) + return self.append(ir.GetElem(buffer, index)) + elif builtins.is_listish(value.type): return self.append(ir.GetElem(value, index)) elif builtins.is_range(value.type): start = self.append(ir.GetAttr(value, "start")) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 19ed2c85d..2838a9e14 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -208,6 +208,14 @@ class Inferencer(algorithm.Visitor): if builtins.is_bytes(collection.type) or builtins.is_bytearray(collection.type): self._unify(element.type, builtins.get_iterable_elt(collection.type), element.loc, None) + elif builtins.is_array(collection.type): + array_type = collection.type.find() + elem_dims = array_type["num_dims"].value - 1 + if elem_dims > 0: + elem_type = builtins.TArray(array_type["elt"], types.TValue(elem_dims)) + else: + elem_type = array_type["elt"] + self._unify(element.type, elem_type, element.loc, collection.loc) elif builtins.is_iterable(collection.type) and not builtins.is_str(collection.type): rhs_type = collection.type.find() rhs_wrapped_lhs_type = types.TMono(rhs_type.name, {"elt": element.type}) diff --git a/artiq/test/lit/integration/array.py b/artiq/test/lit/integration/array.py index c02728334..81763c29e 100644 --- a/artiq/test/lit/integration/array.py +++ b/artiq/test/lit/integration/array.py @@ -4,14 +4,14 @@ ary = array([1, 2, 3]) assert len(ary) == 3 assert ary.shape == (3,) -# FIXME: Implement ndarray indexing -# assert [x*x for x in ary] == [1, 4, 9] +assert [x * x for x in ary] == [1, 4, 9] # Reassign to an existing value to disambiguate type of empty array. empty_array = array([1]) empty_array = array([]) assert len(empty_array) == 0 assert empty_array.shape == (0,) +assert [x * x for x in empty_array] == [] matrix = array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) assert len(matrix) == 2 From 38c17622cce77a49c2387f1e8d5d2107e8d3be01 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 26 Jul 2020 02:46:05 +0100 Subject: [PATCH 2239/2457] compiler: Axis-wise iteration of ndarrays Matches NumPy. Slicing a TList reallocates, this doesn't; offsetting couldn't be handled in the IR without introducing new semantics (the Alloc kludge; could/should be made its own IR type). --- .../compiler/transforms/artiq_ir_generator.py | 19 +++++++++++++++++-- .../compiler/transforms/llvm_ir_generator.py | 18 ++++++++++++++++++ artiq/test/lit/integration/array.py | 9 +++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index afd0da1a9..8a1981279 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -512,8 +512,23 @@ class ARTIQIRGenerator(algorithm.Visitor): # Assuming the value is within bounds. if builtins.is_array(value.type): # Scalar indexing into ndarray. - if value.type.find()["num_dims"].value > 1: - raise NotImplementedError + num_dims = value.type.find()["num_dims"].value + if num_dims > 1: + old_shape = self.append(ir.GetAttr(value, "shape")) + lengths = [self.append(ir.GetAttr(old_shape, i)) for i in range(1, num_dims)] + new_shape = self.append(ir.Alloc(lengths, types.TTuple(old_shape.type.elts[1:]))) + + stride = reduce( + lambda l, r: self.append(ir.Arith(ast.Mult(loc=None), l, r)), + lengths[1:], lengths[0]) + offset = self.append(ir.Arith(ast.Mult(loc=None), stride, index)) + old_buffer = self.append(ir.GetAttr(value, "buffer")) + # KLUDGE: Represent offsetting by Alloc with two arguments. + new_buffer = self.append(ir.Alloc([old_buffer, offset], old_buffer.type)) + + result_type = builtins.TArray(value.type.find()["elt"], + types.TValue(num_dims - 1)) + return self.append(ir.Alloc([new_shape, new_buffer], result_type)) else: buffer = self.append(ir.GetAttr(value, "buffer")) return self.append(ir.GetElem(buffer, index)) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 58615a43c..b8e7e8457 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -738,6 +738,24 @@ class LLVMIRGenerator: else: assert False elif builtins.is_listish(insn.type) and not builtins.is_array(insn.type): + if builtins.is_listish(insn.operands[0].type): + # KLUDGE: Offsetting is represented as Alloc with base list in the first + # argument and offset in the second. Should probably move this to a + # seprate node type (or make it possible to construct lists from + # pointer/length). + llbase = self.map(insn.operands[0]) + lloldbase = self.llbuilder.extract_value(llbase, 0) + lloldsize = self.llbuilder.extract_value(llbase, 1) + + lloffset = self.map(insn.operands[1]) + llbase = self.llbuilder.gep(lloldbase, [lloffset], inbounds=True) + llsize = self.llbuilder.sub(lloldsize, lloffset) + + llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined) + llvalue = self.llbuilder.insert_value(llvalue, llbase, 0) + llvalue = self.llbuilder.insert_value(llvalue, llsize, 1) + return llvalue + llsize = self.map(insn.operands[0]) lleltty = self.llty_of_type(builtins.get_iterable_elt(insn.type)) llalloc = self.llbuilder.alloca(lleltty, size=llsize) diff --git a/artiq/test/lit/integration/array.py b/artiq/test/lit/integration/array.py index 81763c29e..1bca6304c 100644 --- a/artiq/test/lit/integration/array.py +++ b/artiq/test/lit/integration/array.py @@ -16,6 +16,15 @@ assert [x * x for x in empty_array] == [] matrix = array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) assert len(matrix) == 2 assert matrix.shape == (2, 3) +assert matrix[0][0] == 1.0 +assert matrix[0][1] == 2.0 +assert matrix[0][2] == 3.0 +assert matrix[1][0] == 4.0 +assert matrix[1][1] == 5.0 +assert matrix[1][2] == 6.0 +# FIXME: Need to decide on a solution for array comparisons — +# NumPy returns an array of bools! +# assert [x for x in matrix] == [array([1.0, 2.0, 3.0]), array([4.0, 5.0, 6.0])] three_tensor = array([[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]]) assert len(three_tensor) == 1 From cb1cadb46ac3bb1fbe3402e827f9a1ed9d8d8ed6 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 26 Jul 2020 02:51:00 +0100 Subject: [PATCH 2240/2457] compiler: Fix/test 1D array construction from generic iterables --- artiq/compiler/transforms/inferencer.py | 4 ++++ artiq/test/lit/integration/array.py | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 2838a9e14..1c9ea3e6c 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -740,6 +740,10 @@ class Inferencer(algorithm.Visitor): # KLUDGE: Support multidimensional arary creation if lexically # specified as a rectangular array of lists. elt, num_dims = match_rectangular_list([arg]) + if num_dims == 0: + # Not given as a list, so just default to 1 dimension. + elt = builtins.get_iterable_elt(arg.type) + num_dims = 1 self._unify(node.type, builtins.TArray(elt, types.TValue(num_dims)), node.loc, arg.loc) diff --git a/artiq/test/lit/integration/array.py b/artiq/test/lit/integration/array.py index 1bca6304c..aa4001fb6 100644 --- a/artiq/test/lit/integration/array.py +++ b/artiq/test/lit/integration/array.py @@ -13,6 +13,14 @@ assert len(empty_array) == 0 assert empty_array.shape == (0,) assert [x * x for x in empty_array] == [] +# Creating a list from a generic iterable always generates an 1D array, as we can't +# check for rectangularity at compile time. (This could be changed to *assume* +# rectangularity and insert runtime checks instead.) +list_of_lists = [[1, 2], [3, 4]] +array_of_lists = array(list_of_lists) +assert array_of_lists.shape == (2,) +assert [x for x in array_of_lists] == list_of_lists + matrix = array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) assert len(matrix) == 2 assert matrix.shape == (2, 3) From e82357d180582e3e392e7a009e70e361cdc49c68 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 27 Jul 2020 23:19:43 +0100 Subject: [PATCH 2241/2457] compiler: Fix inferencer tests after adding TArray.num_dims --- artiq/test/lit/inferencer/array.py | 8 ++++---- artiq/test/lit/inferencer/unify.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/test/lit/inferencer/array.py b/artiq/test/lit/inferencer/array.py index c4f215db8..f33040f92 100644 --- a/artiq/test/lit/inferencer/array.py +++ b/artiq/test/lit/inferencer/array.py @@ -1,13 +1,13 @@ # RUN: %python -m artiq.compiler.testbench.inferencer %s >%t # RUN: OutputCheck %s --file-to-check=%t -# CHECK-L: numpy.array(elt='a) +# CHECK-L: numpy.array(elt='a, num_dims=1) array([]) -# CHECK-L: numpy.array(elt=numpy.int?) +# CHECK-L: numpy.array(elt=numpy.int?, num_dims=1) array([1, 2, 3]) -# CHECK-L: numpy.array(elt=numpy.int?) +# CHECK-L: numpy.array(elt=numpy.int?, num_dims=2) array([[1, 2, 3], [4, 5, 6]]) -# CHECK-L: numpy.array(elt=list(elt=numpy.int?)) +# CHECK-L: numpy.array(elt=list(elt=numpy.int?), num_dims=1) array([[1, 2, 3], [4, 5]]) diff --git a/artiq/test/lit/inferencer/unify.py b/artiq/test/lit/inferencer/unify.py index e4fea57fe..8dcb1e423 100644 --- a/artiq/test/lit/inferencer/unify.py +++ b/artiq/test/lit/inferencer/unify.py @@ -64,7 +64,7 @@ kb = bytearray(b"x") # CHECK-L: kb:bytearray l = array([1]) -# CHECK-L: l:numpy.array(elt=numpy.int?) +# CHECK-L: l:numpy.array(elt=numpy.int?, num_dims=1) IndexError() # CHECK-L: IndexError:():IndexError From dea3c0c572fc47f301699eff5f8c4b4c5747fc9c Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 27 Jul 2020 23:21:23 +0100 Subject: [PATCH 2242/2457] compiler: Don't store redundant ndarray buffer length, match list layout This adds `elt` to _TPointer and the ir.Offset IR instruction, which is like GetElem but without the final load. --- artiq/compiler/builtins.py | 4 +- artiq/compiler/ir.py | 32 +++++++++++- .../compiler/transforms/artiq_ir_generator.py | 7 ++- .../transforms/dead_code_eliminator.py | 3 +- .../compiler/transforms/llvm_ir_generator.py | 52 ++++++++----------- artiq/compiler/types.py | 8 ++- 6 files changed, 66 insertions(+), 40 deletions(-) diff --git a/artiq/compiler/builtins.py b/artiq/compiler/builtins.py index ae7e61055..af0201765 100644 --- a/artiq/compiler/builtins.py +++ b/artiq/compiler/builtins.py @@ -93,8 +93,8 @@ class TArray(types.TMono): super().__init__("array", {"elt": elt, "num_dims": num_dims}) self.attributes = OrderedDict([ + ("buffer", types._TPointer(elt)), ("shape", types.TTuple([TInt32()] * num_dims.value)), - ("buffer", TList(elt)), ]) def _array_printer(typ, printer, depth, max_depth): @@ -317,7 +317,7 @@ def is_iterable(typ): def get_iterable_elt(typ): if is_str(typ) or is_bytes(typ) or is_bytearray(typ): return TInt(types.TValue(8)) - elif is_iterable(typ): + elif types._is_pointer(typ) or is_iterable(typ): return typ.find()["elt"].find() else: assert False diff --git a/artiq/compiler/ir.py b/artiq/compiler/ir.py index c20359962..a411c036f 100644 --- a/artiq/compiler/ir.py +++ b/artiq/compiler/ir.py @@ -738,6 +738,33 @@ class SetAttr(Instruction): def value(self): return self.operands[1] +class Offset(Instruction): + """ + An intruction that adds an offset to a pointer (indexes into a list). + + This is used to represent internally generated pointer arithmetic, and must + remain inside the same object (see :class:`GetElem` and LLVM's GetElementPtr). + """ + + """ + :param lst: (:class:`Value`) list + :param index: (:class:`Value`) index + """ + def __init__(self, base, offset, name=""): + assert isinstance(base, Value) + assert isinstance(offset, Value) + typ = types._TPointer(builtins.get_iterable_elt(base.type)) + super().__init__([base, offset], typ, name) + + def opcode(self): + return "offset" + + def base(self): + return self.operands[0] + + def index(self): + return self.operands[1] + class GetElem(Instruction): """ An intruction that loads an element from a list. @@ -755,7 +782,7 @@ class GetElem(Instruction): def opcode(self): return "getelem" - def list(self): + def base(self): return self.operands[0] def index(self): @@ -781,7 +808,7 @@ class SetElem(Instruction): def opcode(self): return "setelem" - def list(self): + def base(self): return self.operands[0] def index(self): @@ -840,6 +867,7 @@ class Arith(Instruction): def rhs(self): return self.operands[1] + class Compare(Instruction): """ A comparison operation on numbers. diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 8a1981279..c4d469cd7 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -523,12 +523,11 @@ class ARTIQIRGenerator(algorithm.Visitor): lengths[1:], lengths[0]) offset = self.append(ir.Arith(ast.Mult(loc=None), stride, index)) old_buffer = self.append(ir.GetAttr(value, "buffer")) - # KLUDGE: Represent offsetting by Alloc with two arguments. - new_buffer = self.append(ir.Alloc([old_buffer, offset], old_buffer.type)) + new_buffer = self.append(ir.Offset(old_buffer, offset)) result_type = builtins.TArray(value.type.find()["elt"], types.TValue(num_dims - 1)) - return self.append(ir.Alloc([new_shape, new_buffer], result_type)) + return self.append(ir.Alloc([new_buffer, new_shape], result_type)) else: buffer = self.append(ir.GetAttr(value, "buffer")) return self.append(ir.GetElem(buffer, index)) @@ -1740,7 +1739,7 @@ class ARTIQIRGenerator(algorithm.Visitor): ir.Constant(0, self._size_type), lambda index: self.append( ir.Compare(ast.Lt(loc=None), index, num_total_elts)), body_gen) - return self.append(ir.Alloc([shape, buffer], node.type)) + return self.append(ir.Alloc([buffer, shape], node.type)) else: assert False elif types.is_builtin(typ, "range"): diff --git a/artiq/compiler/transforms/dead_code_eliminator.py b/artiq/compiler/transforms/dead_code_eliminator.py index 2aceebeec..608a46d55 100644 --- a/artiq/compiler/transforms/dead_code_eliminator.py +++ b/artiq/compiler/transforms/dead_code_eliminator.py @@ -33,7 +33,8 @@ class DeadCodeEliminator: # it also has to run after the interleaver, but interleaver # doesn't like to work with IR before DCE. if isinstance(insn, (ir.Phi, ir.Alloc, ir.GetAttr, ir.GetElem, ir.Coerce, - ir.Arith, ir.Compare, ir.Select, ir.Quote, ir.Closure)) \ + ir.Arith, ir.Compare, ir.Select, ir.Quote, ir.Closure, + ir.Offset)) \ and not any(insn.uses): insn.erase() modified = True diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index b8e7e8457..dcc2cc03e 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -211,7 +211,7 @@ class LLVMIRGenerator: else: return llunit elif types._is_pointer(typ): - return llptr + return ll.PointerType(self.llty_of_type(typ["elt"])) elif types.is_function(typ): sretarg = [] llretty = self.llty_of_type(typ.ret, for_return=True) @@ -249,7 +249,7 @@ class LLVMIRGenerator: elif builtins.is_array(typ): llshapety = self.llty_of_type(typ.attributes["shape"]) llbufferty = self.llty_of_type(typ.attributes["buffer"]) - return ll.LiteralStructType([llshapety, llbufferty]) + return ll.LiteralStructType([llbufferty, llshapety]) elif builtins.is_listish(typ): lleltty = self.llty_of_type(builtins.get_iterable_elt(typ)) return ll.LiteralStructType([lleltty.as_pointer(), lli32]) @@ -737,28 +737,13 @@ class LLVMIRGenerator: name=insn.name) else: assert False - elif builtins.is_listish(insn.type) and not builtins.is_array(insn.type): - if builtins.is_listish(insn.operands[0].type): - # KLUDGE: Offsetting is represented as Alloc with base list in the first - # argument and offset in the second. Should probably move this to a - # seprate node type (or make it possible to construct lists from - # pointer/length). - llbase = self.map(insn.operands[0]) - lloldbase = self.llbuilder.extract_value(llbase, 0) - lloldsize = self.llbuilder.extract_value(llbase, 1) - - lloffset = self.map(insn.operands[1]) - llbase = self.llbuilder.gep(lloldbase, [lloffset], inbounds=True) - llsize = self.llbuilder.sub(lloldsize, lloffset) - - llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined) - llvalue = self.llbuilder.insert_value(llvalue, llbase, 0) - llvalue = self.llbuilder.insert_value(llvalue, llsize, 1) - return llvalue - + elif types._is_pointer(insn.type) or (builtins.is_listish(insn.type) + and not builtins.is_array(insn.type)): llsize = self.map(insn.operands[0]) lleltty = self.llty_of_type(builtins.get_iterable_elt(insn.type)) llalloc = self.llbuilder.alloca(lleltty, size=llsize) + if types._is_pointer(insn.type): + return llalloc llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined) llvalue = self.llbuilder.insert_value(llvalue, llalloc, 0, name=insn.name) llvalue = self.llbuilder.insert_value(llvalue, llsize, 1) @@ -962,20 +947,28 @@ class LLVMIRGenerator: inbounds=True, name=insn.name) return self.llbuilder.store(llvalue, llptr) - def process_GetElem(self, insn): - lst, idx = insn.list(), insn.index() - lllst, llidx = map(self.map, (lst, idx)) - llelts = self.llbuilder.extract_value(lllst, 0) + def process_Offset(self, insn): + base, idx = insn.base(), insn.index() + llelts, llidx = map(self.map, (base, idx)) + if not types._is_pointer(base.type): + # This is list-ish. + llelts = self.llbuilder.extract_value(llelts, 0) llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True) + return llelt + + def process_GetElem(self, insn): + llelt = self.process_Offset(insn) llvalue = self.llbuilder.load(llelt) if isinstance(llvalue.type, ll.PointerType): self.mark_dereferenceable(llvalue) return llvalue def process_SetElem(self, insn): - lst, idx = insn.list(), insn.index() - lllst, llidx = map(self.map, (lst, idx)) - llelts = self.llbuilder.extract_value(lllst, 0) + base, idx = insn.base(), insn.index() + llelts, llidx = map(self.map, (base, idx)) + if not types._is_pointer(base.type): + # This is list-ish. + llelts = self.llbuilder.extract_value(llelts, 0) llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True) return self.llbuilder.store(self.map(insn.value()), llelt) @@ -1190,7 +1183,8 @@ class LLVMIRGenerator: collection, = insn.operands if builtins.is_array(collection.type): # Return length of outermost dimension. - shape = self.llbuilder.extract_value(self.map(collection), 0) + shape = self.llbuilder.extract_value(self.map(collection), + self.attr_index(collection.type, "shape")) return self.llbuilder.extract_value(shape, 0) return self.llbuilder.extract_value(self.map(collection), 1) elif insn.op in ("printf", "rtio_log"): diff --git a/artiq/compiler/types.py b/artiq/compiler/types.py index 5299822c3..206f040fb 100644 --- a/artiq/compiler/types.py +++ b/artiq/compiler/types.py @@ -204,8 +204,10 @@ class TTuple(Type): return hash(tuple(self.elts)) class _TPointer(TMono): - def __init__(self): - super().__init__("pointer") + def __init__(self, elt=None): + if elt is None: + elt = TMono("int", {"width": 8}) # i8* + super().__init__("pointer", params={"elt": elt}) class TFunction(Type): """ @@ -735,6 +737,8 @@ class TypePrinter(object): else: return "%s(%s)" % (typ.name, ", ".join( ["%s=%s" % (k, self.name(typ.params[k], depth + 1)) for k in typ.params])) + elif isinstance(typ, _TPointer): + return "{}*".format(self.name(typ["elt"], depth + 1)) elif isinstance(typ, TTuple): if len(typ.elts) == 1: return "(%s,)" % self.name(typ.elts[0], depth + 1) From 504b8f014812167e217a23de5470b5025d58ed96 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 27 Jul 2020 23:34:37 +0100 Subject: [PATCH 2243/2457] language: Export TArray --- artiq/language/types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/language/types.py b/artiq/language/types.py index c767dd663..4a186788a 100644 --- a/artiq/language/types.py +++ b/artiq/language/types.py @@ -8,7 +8,7 @@ from artiq.compiler import types, builtins __all__ = ["TNone", "TTuple", "TBool", "TInt32", "TInt64", "TFloat", "TStr", "TBytes", "TByteArray", - "TList", "TRange32", "TRange64", + "TList", "TArray", "TRange32", "TRange64", "TVar"] TNone = builtins.TNone() @@ -21,6 +21,7 @@ TBytes = builtins.TBytes() TByteArray = builtins.TByteArray() TTuple = types.TTuple TList = builtins.TList +TArray = builtins.TArray TRange32 = builtins.TRange(builtins.TInt(types.TValue(32))) TRange64 = builtins.TRange(builtins.TInt(types.TValue(64))) TVar = types.TVar From a9a975e5d4aec6e88c2feff94d6cce80c46e72fa Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 27 Jul 2020 23:36:42 +0100 Subject: [PATCH 2244/2457] language: Allow instantating TArray using bare ints --- artiq/compiler/builtins.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/compiler/builtins.py b/artiq/compiler/builtins.py index af0201765..7edd97d9a 100644 --- a/artiq/compiler/builtins.py +++ b/artiq/compiler/builtins.py @@ -82,9 +82,12 @@ class TList(types.TMono): super().__init__("list", {"elt": elt}) class TArray(types.TMono): - def __init__(self, elt=None, num_dims=types.TValue(1)): + def __init__(self, elt=None, num_dims=1): if elt is None: elt = types.TVar() + if isinstance(num_dims, int): + # Make TArray more convenient to instantiate from (ARTIQ) user code. + num_dims = types.TValue(num_dims) # For now, enforce number of dimensions to be known, as we'd otherwise # need to implement custom unification logic for the type of `shape`. # Default to 1 to keep compatibility with old user code from before From ef57cad1a3b5c5e09d534ae65dfaf13de682ae84 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 28 Jul 2020 01:17:22 +0100 Subject: [PATCH 2245/2457] compiler: Test ndarray element assignment --- artiq/test/lit/integration/array.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/artiq/test/lit/integration/array.py b/artiq/test/lit/integration/array.py index aa4001fb6..05785889d 100644 --- a/artiq/test/lit/integration/array.py +++ b/artiq/test/lit/integration/array.py @@ -24,15 +24,24 @@ assert [x for x in array_of_lists] == list_of_lists matrix = array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) assert len(matrix) == 2 assert matrix.shape == (2, 3) +# FIXME: Need to decide on a solution for array comparisons — +# NumPy returns an array of bools! +# assert [x for x in matrix] == [array([1.0, 2.0, 3.0]), array([4.0, 5.0, 6.0])] assert matrix[0][0] == 1.0 assert matrix[0][1] == 2.0 assert matrix[0][2] == 3.0 assert matrix[1][0] == 4.0 assert matrix[1][1] == 5.0 assert matrix[1][2] == 6.0 -# FIXME: Need to decide on a solution for array comparisons — -# NumPy returns an array of bools! -# assert [x for x in matrix] == [array([1.0, 2.0, 3.0]), array([4.0, 5.0, 6.0])] + +matrix[0][0] = 7.0 +matrix[1][1] = 8.0 +assert matrix[0][0] == 7.0 +assert matrix[0][1] == 2.0 +assert matrix[0][2] == 3.0 +assert matrix[1][0] == 4.0 +assert matrix[1][1] == 8.0 +assert matrix[1][2] == 6.0 three_tensor = array([[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]]) assert len(three_tensor) == 1 From e77c7d1c39bf151830143a07161377eb9e7e4a96 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 28 Jul 2020 22:44:27 +0100 Subject: [PATCH 2246/2457] compiler: Add inferencer support for array operations --- artiq/compiler/transforms/inferencer.py | 60 +++++++++++++++++++- artiq/test/lit/inferencer/error_array_ops.py | 12 ++++ 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 artiq/test/lit/inferencer/error_array_ops.py diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 1c9ea3e6c..f2a0a79ee 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -313,6 +313,10 @@ class Inferencer(algorithm.Visitor): self.generic_visit(node) if builtins.is_numeric(node.type) and builtins.is_numeric(node.value.type): pass + elif (builtins.is_array(node.type) and builtins.is_array(node.value.type) + and builtins.is_numeric(node.type.find()["elt"]) + and builtins.is_numeric(node.value.type.find()["elt"])): + pass else: printer = types.TypePrinter() note = diagnostic.Diagnostic("note", @@ -338,7 +342,7 @@ class Inferencer(algorithm.Visitor): self.visit(node) return node - def _coerce_numeric(self, nodes, map_return=lambda typ: typ): + def _coerce_numeric(self, nodes, map_return=lambda typ: typ, map_node_type =lambda typ:typ): # See https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex. node_types = [] for node in nodes: @@ -354,6 +358,7 @@ class Inferencer(algorithm.Visitor): node_types.append(node.type) else: node_types.append(node.type) + node_types = [map_node_type(typ) for typ in node_types] if any(map(types.is_var, node_types)): # not enough info yet return elif not all(map(builtins.is_numeric, node_types)): @@ -386,7 +391,58 @@ class Inferencer(algorithm.Visitor): assert False def _coerce_binop(self, op, left, right): - if isinstance(op, (ast.BitAnd, ast.BitOr, ast.BitXor, + if builtins.is_array(left.type) or builtins.is_array(right.type): + # Operations on arrays are element-wise (possibly using broadcasting). + # TODO: Matrix multiplication (which aren't element-wise). + + # # TODO: Allow only for integer arrays. + # allowed_int_array_ops = (ast.BitAnd, ast.BitOr, ast.BitXor, ast.LShift, + # ast.RShift) + allowed_array_ops = (ast.Add, ast.Mult, ast.FloorDiv, ast.Mod, + ast.Pow, ast.Sub, ast.Div) + if not isinstance(op, allowed_array_ops): + diag = diagnostic.Diagnostic( + "error", "operator '{op}' not valid for array types", + {"op": op.loc.source()}, op.loc) + self.engine.process(diag) + return + + def num_dims(typ): + if builtins.is_array(typ): + # TODO: If number of dimensions is ever made a non-fixed parameter, + # need to acutally unify num_dims in _coerce_binop. + return typ.find()["num_dims"].value + return 0 + + # TODO: Broadcasting. + left_dims = num_dims(left.type) + right_dims = num_dims(right.type) + if left_dims != right_dims: + note1 = diagnostic.Diagnostic("note", "operand of dimension {num_dims}", + {"num_dims": left_dims}, left.loc) + note2 = diagnostic.Diagnostic("note", "operand of dimension {num_dims}", + {"num_dims": right_dims}, right.loc) + diag = diagnostic.Diagnostic( + "error", "dimensions of '{op}' array operands must match", + {"op": op.loc.source()}, op.loc, [left.loc, right.loc], [note1, note2]) + self.engine.process(diag) + return + + def map_node_type(typ): + if builtins.is_array(typ): + return typ.find()["elt"] + else: + # This is (if later valid) a single value broadcast across the array. + return typ + + def map_return(typ): + a = builtins.TArray(elt=typ, num_dims=left_dims) + return (a, a, a) + + return self._coerce_numeric((left, right), + map_return=map_return, + map_node_type=map_node_type) + elif isinstance(op, (ast.BitAnd, ast.BitOr, ast.BitXor, ast.LShift, ast.RShift)): # bitwise operators require integers for operand in (left, right): diff --git a/artiq/test/lit/inferencer/error_array_ops.py b/artiq/test/lit/inferencer/error_array_ops.py new file mode 100644 index 000000000..4f85290c1 --- /dev/null +++ b/artiq/test/lit/inferencer/error_array_ops.py @@ -0,0 +1,12 @@ +# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +a = array([[1, 2], [3, 4]]) +b = array([7, 8]) + +# NumPy supports implicit broadcasting over axes, which we don't (yet). +# Make sure there is a nice error message. +# CHECK-L: ${LINE:+3}: error: dimensions of '+' array operands must match +# CHECK-L: ${LINE:+2}: note: operand of dimension 2 +# CHECK-L: ${LINE:+1}: note: operand of dimension 1 +a + b From 9af6e5747d5ef9c481f76d29d3cc4d52c85afbbd Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 28 Jul 2020 23:45:37 +0100 Subject: [PATCH 2247/2457] compiler: Factor rpc_tag() out of llvm_ir_generator --- artiq/compiler/ir.py | 41 ++++++++++++++++ .../compiler/transforms/llvm_ir_generator.py | 49 ++----------------- artiq/coredevice/comm_kernel.py | 2 +- 3 files changed, 45 insertions(+), 47 deletions(-) diff --git a/artiq/compiler/ir.py b/artiq/compiler/ir.py index a411c036f..941b04d36 100644 --- a/artiq/compiler/ir.py +++ b/artiq/compiler/ir.py @@ -36,6 +36,47 @@ class TKeyword(types.TMono): def is_keyword(typ): return isinstance(typ, TKeyword) + +# See rpc_proto.rs and comm_kernel.py:_{send,receive}_rpc_value. +def rpc_tag(typ, error_handler): + typ = typ.find() + if types.is_tuple(typ): + assert len(typ.elts) < 256 + return b"t" + bytes([len(typ.elts)]) + \ + b"".join([rpc_tag(elt_type, error_handler) + for elt_type in typ.elts]) + elif builtins.is_none(typ): + return b"n" + elif builtins.is_bool(typ): + return b"b" + elif builtins.is_int(typ, types.TValue(32)): + return b"i" + elif builtins.is_int(typ, types.TValue(64)): + return b"I" + elif builtins.is_float(typ): + return b"f" + elif builtins.is_str(typ): + return b"s" + elif builtins.is_bytes(typ): + return b"B" + elif builtins.is_bytearray(typ): + return b"A" + elif builtins.is_list(typ): + return b"l" + rpc_tag(builtins.get_iterable_elt(typ), error_handler) + elif builtins.is_array(typ): + return b"a" + rpc_tag(builtins.get_iterable_elt(typ), error_handler) + elif builtins.is_range(typ): + return b"r" + rpc_tag(builtins.get_iterable_elt(typ), error_handler) + elif is_keyword(typ): + return b"k" + rpc_tag(typ.params["value"], error_handler) + elif types.is_function(typ) or types.is_method(typ) or types.is_rpc(typ): + raise ValueError("RPC tag for functional value") + elif '__objectid__' in typ.attributes: + return b"O" + else: + error_handler(typ) + + class Value: """ An SSA value that keeps track of its uses. diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index dcc2cc03e..70ef64785 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -570,7 +570,7 @@ class LLVMIRGenerator: if name == "__objectid__": rpctag = b"" else: - rpctag = b"Os" + self._rpc_tag(typ, error_handler=rpc_tag_error) + b":n" + rpctag = b"Os" + ir.rpc_tag(typ, error_handler=rpc_tag_error) + b":n" llrpcattrinit = ll.Constant(llrpcattrty, [ ll.Constant(lli32, offset), @@ -1310,49 +1310,6 @@ class LLVMIRGenerator: return llfun, list(llargs) - # See session.c:{send,receive}_rpc_value and comm_generic.py:_{send,receive}_rpc_value. - def _rpc_tag(self, typ, error_handler): - typ = typ.find() - if types.is_tuple(typ): - assert len(typ.elts) < 256 - return b"t" + bytes([len(typ.elts)]) + \ - b"".join([self._rpc_tag(elt_type, error_handler) - for elt_type in typ.elts]) - elif builtins.is_none(typ): - return b"n" - elif builtins.is_bool(typ): - return b"b" - elif builtins.is_int(typ, types.TValue(32)): - return b"i" - elif builtins.is_int(typ, types.TValue(64)): - return b"I" - elif builtins.is_float(typ): - return b"f" - elif builtins.is_str(typ): - return b"s" - elif builtins.is_bytes(typ): - return b"B" - elif builtins.is_bytearray(typ): - return b"A" - elif builtins.is_list(typ): - return b"l" + self._rpc_tag(builtins.get_iterable_elt(typ), - error_handler) - elif builtins.is_array(typ): - return b"a" + self._rpc_tag(builtins.get_iterable_elt(typ), - error_handler) - elif builtins.is_range(typ): - return b"r" + self._rpc_tag(builtins.get_iterable_elt(typ), - error_handler) - elif ir.is_keyword(typ): - return b"k" + self._rpc_tag(typ.params["value"], - error_handler) - elif types.is_function(typ) or types.is_method(typ) or types.is_rpc(typ): - raise ValueError("RPC tag for functional value") - elif '__objectid__' in typ.attributes: - return b"O" - else: - error_handler(typ) - def _build_rpc(self, fun_loc, fun_type, args, llnormalblock, llunwindblock): llservice = ll.Constant(lli32, fun_type.service) @@ -1370,7 +1327,7 @@ class LLVMIRGenerator: {"type": printer.name(arg.type)}, arg.loc) self.engine.process(diag) - tag += self._rpc_tag(arg.type, arg_error_handler) + tag += ir.rpc_tag(arg.type, arg_error_handler) tag += b":" def ret_error_handler(typ): @@ -1384,7 +1341,7 @@ class LLVMIRGenerator: {"type": printer.name(fun_type.ret)}, fun_loc) self.engine.process(diag) - tag += self._rpc_tag(fun_type.ret, ret_error_handler) + tag += ir.rpc_tag(fun_type.ret, ret_error_handler) lltag = self.llconst_of_const(ir.Constant(tag, builtins.TStr())) lltagptr = self.llbuilder.alloca(lltag.type) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index d3a73c20e..838bad042 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -244,7 +244,7 @@ class CommKernel: _rpc_sentinel = object() - # See session.c:{send,receive}_rpc_value and llvm_ir_generator.py:_rpc_tag. + # See rpc_proto.rs and compiler/ir.py:rpc_tag. def _receive_rpc_value(self, embedding_map): tag = chr(self._read_int8()) if tag == "\x00": From 48fb80017f84f6744fa73f9bcc187f38d6618f69 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 29 Jul 2020 01:28:55 +0100 Subject: [PATCH 2248/2457] compiler: Implement basic element-wise array operations --- .../compiler/transforms/artiq_ir_generator.py | 131 +++++++++++++++++- artiq/test/lit/integration/array_ops.py | 19 +++ 2 files changed, 145 insertions(+), 5 deletions(-) create mode 100644 artiq/test/lit/integration/array_ops.py diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index c4d469cd7..22482c8c0 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -83,6 +83,13 @@ class ARTIQIRGenerator(algorithm.Visitor): :ivar method_map: (map of :class:`ast.AttributeT` to :class:`ir.GetAttribute`) the map from method resolution nodes to instructions retrieving the called function inside a translated :class:`ast.CallT` node + + Finally, functions that implement array operations are instantiated on the fly as + necessary. They are kept track of in global dictionaries, with a mangled name + containing types and operations as key: + + :ivar array_binop_funcs: the map from mangled name to implementation of binary + operations between arrays """ _size_type = builtins.TInt32() @@ -111,6 +118,7 @@ class ARTIQIRGenerator(algorithm.Visitor): self.function_map = dict() self.variable_map = dict() self.method_map = defaultdict(lambda: []) + self.array_binop_funcs = dict() def annotate_calls(self, devirtualization): for var_node in devirtualization.variable_map: @@ -1337,8 +1345,124 @@ class ARTIQIRGenerator(algorithm.Visitor): name="{}.{}".format(_readable_name(value), node.type.name))) + def _get_total_array_len(self, shape): + lengths = [ + self.append(ir.GetAttr(shape, i)) for i in range(len(shape.type.elts)) + ] + return reduce(lambda l, r: self.append(ir.Arith(ast.Mult(loc=None), l, r)), + lengths[1:], lengths[0]) + + def _alloate_new_array(self, elt, shape): + total_length = self._get_total_array_len(shape) + buffer = self.append(ir.Alloc([total_length], types._TPointer(elt=elt))) + result_type = builtins.TArray(elt, types.TValue(len(shape.type.elts))) + return self.append(ir.Alloc([buffer, shape], result_type)) + + def _make_array_binop(self, name, op, result_type, lhs_type, rhs_type): + try: + result = ir.Argument(result_type, "result") + lhs = ir.Argument(lhs_type, "lhs") + rhs = ir.Argument(rhs_type, "rhs") + + # TODO: We'd like to use a "C function" here to be able to supply + # specialised implementations in a library in the future (and e.g. avoid + # passing around the context argument), but the code generator currently + # doesn't allow emitting them. + args = [result, lhs, rhs] + typ = types.TFunction(args=OrderedDict([(arg.name, arg.type) + for arg in args]), + optargs=OrderedDict(), + ret=builtins.TNone()) + env_args = [ir.EnvironmentArgument(self.current_env.type, "ARG.ENV")] + + # TODO: What to use for loc? + func = ir.Function(typ, name, env_args + args, loc=None) + func.is_internal = True + func.is_generated = True + self.functions.append(func) + old_func, self.current_function = self.current_function, func + + entry = self.add_block("entry") + old_block, self.current_block = self.current_block, entry + + old_final_branch, self.final_branch = self.final_branch, None + old_unwind, self.unwind_target = self.unwind_target, None + + shape = self.append(ir.GetAttr(lhs, "shape")) + rhs_shape = self.append(ir.GetAttr(rhs, "shape")) + self._make_check( + self.append(ir.Compare(ast.Eq(loc=None), shape, rhs_shape)), + lambda: self.alloc_exn( + builtins.TException("ValueError"), + ir.Constant("operands could not be broadcast together", + builtins.TStr()))) + # We assume result has correct shape; could just pass buffer pointer as well. + + result_buffer = self.append(ir.GetAttr(result, "buffer")) + lhs_buffer = self.append(ir.GetAttr(lhs, "buffer")) + rhs_buffer = self.append(ir.GetAttr(rhs, "buffer")) + num_total_elts = self._get_total_array_len(shape) + + def body_gen(index): + l = self.append(ir.GetElem(lhs_buffer, index)) + r = self.append(ir.GetElem(rhs_buffer, index)) + self.append( + ir.SetElem(result_buffer, index, self.append(ir.Arith(op, l, r)))) + return self.append( + ir.Arith(ast.Add(loc=None), index, ir.Constant(1, self._size_type))) + + self._make_loop( + ir.Constant(0, self._size_type), lambda index: self.append( + ir.Compare(ast.Lt(loc=None), index, num_total_elts)), body_gen) + + self.append(ir.Return(ir.Constant(None, builtins.TNone()))) + return func + finally: + self.current_function = old_func + self.current_block = old_block + self.final_branch = old_final_branch + self.unwind_target = old_unwind + + def _get_array_binop(self, op, result_type, lhs_type, rhs_type): + # Currently, we always have any type coercions resolved explicitly in the AST. + # In the future, this might no longer be true and the three types might all + # differ. + def name_error(typ): + assert False, "Internal compiler error: No RPC tag for {}".format(typ) + def mangle_name(typ): + typ = typ.find() + return ir.rpc_tag(typ["elt"], name_error).decode() +\ + str(typ["num_dims"].find().value) + name = "_array_{}_{}_{}_{}".format( + type(op).__name__, + *(map(mangle_name, (result_type, lhs_type, rhs_type)))) + if name not in self.array_binop_funcs: + self.array_binop_funcs[name] = self._make_array_binop( + name, op, result_type, lhs_type, rhs_type) + return self.array_binop_funcs[name] + def visit_BinOpT(self, node): - if builtins.is_numeric(node.type): + if builtins.is_array(node.type): + lhs = self.visit(node.left) + rhs = self.visit(node.right) + + # Array op implementation will check for matching shape. + # TODO: Broadcasts; select the widest shape. + # TODO: Detect and special-case matrix multiplication. + shape = self.append(ir.GetAttr(lhs, "shape")) + result = self._alloate_new_array(node.type.find()["elt"], shape) + + func = self._get_array_binop(node.op, node.type, node.left.type, node.right.type) + closure = self.append(ir.Closure(func, ir.Constant(None, ir.TEnvironment("arrayop", {})))) + params = [result, lhs, rhs] + if self.unwind_target is None: + insn = self.append(ir.Call(closure, params, {})) + else: + after_invoke = self.add_block("arrayop.invoke") + insn = self.append(ir.Invoke(func, params, {}, after_invoke, self.unwind_target)) + self.current_block = after_invoke + return result + elif builtins.is_numeric(node.type): lhs = self.visit(node.left) rhs = self.visit(node.right) if isinstance(node.op, (ast.LShift, ast.RShift)): @@ -1703,11 +1827,8 @@ class ARTIQIRGenerator(algorithm.Visitor): ir.Constant(0, self._size_type)) lengths.append(self.iterable_len(first_elt)) - num_total_elts = reduce( - lambda l, r: self.append(ir.Arith(ast.Mult(loc=None), l, r)), - lengths[1:], lengths[0]) - shape = self.append(ir.Alloc(lengths, result_type.attributes["shape"])) + num_total_elts = self._get_total_array_len(shape) # Assign buffer from nested iterables. buffer = self.append( diff --git a/artiq/test/lit/integration/array_ops.py b/artiq/test/lit/integration/array_ops.py new file mode 100644 index 000000000..72d2f0812 --- /dev/null +++ b/artiq/test/lit/integration/array_ops.py @@ -0,0 +1,19 @@ +# RUN: %python -m artiq.compiler.testbench.jit %s + +a = array([1, 2, 3]) +b = array([4, 5, 6]) + +c = a + b +assert c[0] == 5 +assert c[1] == 7 +assert c[2] == 9 + +c = a * b +assert c[0] == 4 +assert c[1] == 10 +assert c[2] == 18 + +c = b // a +assert c[0] == 4 +assert c[1] == 2 +assert c[2] == 2 From a7e855b3193bfcbf941e997831fac9591cceb09a Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 29 Jul 2020 23:15:07 +0100 Subject: [PATCH 2249/2457] compiler.types: Change invalid default value [nfc] This wasn't actually ever used, but was a dict instead of a set. --- artiq/compiler/types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/compiler/types.py b/artiq/compiler/types.py index 206f040fb..deeb8352b 100644 --- a/artiq/compiler/types.py +++ b/artiq/compiler/types.py @@ -296,7 +296,7 @@ class TCFunction(TFunction): attributes = OrderedDict() - def __init__(self, args, ret, name, flags={}): + def __init__(self, args, ret, name, flags=set()): assert isinstance(flags, set) for flag in flags: assert flag in {'nounwind', 'nowrite'} From 4d002c7934f0295afb9ff5118a3c10239a299737 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 29 Jul 2020 23:19:01 +0100 Subject: [PATCH 2250/2457] compiler: Explain use of rpc_tag() in array ops, formatting [nfc] --- artiq/compiler/transforms/artiq_ir_generator.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 22482c8c0..66b3d1f78 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1429,13 +1429,17 @@ class ARTIQIRGenerator(algorithm.Visitor): # differ. def name_error(typ): assert False, "Internal compiler error: No RPC tag for {}".format(typ) + def mangle_name(typ): typ = typ.find() - return ir.rpc_tag(typ["elt"], name_error).decode() +\ - str(typ["num_dims"].find().value) + # rpc_tag is used to turn element types into mangled names for no + # particularly good reason apart from not having to invent yet another + # string representation. + return (ir.rpc_tag(typ["elt"], name_error).decode() + + str(typ["num_dims"].find().value)) + name = "_array_{}_{}_{}_{}".format( - type(op).__name__, - *(map(mangle_name, (result_type, lhs_type, rhs_type)))) + type(op).__name__, *(map(mangle_name, (result_type, lhs_type, rhs_type)))) if name not in self.array_binop_funcs: self.array_binop_funcs[name] = self._make_array_binop( name, op, result_type, lhs_type, rhs_type) From 7bdd6785b7735b6fa867d21253c1623b9cb6ecef Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 29 Jul 2020 23:22:50 +0100 Subject: [PATCH 2251/2457] test/lit: Basic ndarray smoke tests for all binops --- artiq/test/lit/integration/array_ops.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/artiq/test/lit/integration/array_ops.py b/artiq/test/lit/integration/array_ops.py index 72d2f0812..cf511d0d8 100644 --- a/artiq/test/lit/integration/array_ops.py +++ b/artiq/test/lit/integration/array_ops.py @@ -8,6 +8,11 @@ assert c[0] == 5 assert c[1] == 7 assert c[2] == 9 +c = b - a +assert c[0] == 3 +assert c[1] == 3 +assert c[2] == 3 + c = a * b assert c[0] == 4 assert c[1] == 10 @@ -17,3 +22,19 @@ c = b // a assert c[0] == 4 assert c[1] == 2 assert c[2] == 2 + +c = a ** b +assert c[0] == 1 +assert c[1] == 32 +assert c[2] == 729 + +c = b % a +assert c[0] == 0 +assert c[1] == 1 +assert c[2] == 0 + +# FIXME: Implement array coercion. +# c = b / a +# assert c[0] == 4.0 +# assert c[1] == 2.5 +# assert c[2] == 2.0 From 0d8fbd4f19999c06bd46ffc63871db70e1f724eb Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 29 Jul 2020 23:25:29 +0100 Subject: [PATCH 2252/2457] test/lit: Add a test for matrix binary operations No reason to believe other operations won't work the same. (More exhaustive tests to follow using embedding for comparison against NumPy.) --- artiq/test/lit/integration/array_ops.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/artiq/test/lit/integration/array_ops.py b/artiq/test/lit/integration/array_ops.py index cf511d0d8..86014cc0c 100644 --- a/artiq/test/lit/integration/array_ops.py +++ b/artiq/test/lit/integration/array_ops.py @@ -38,3 +38,12 @@ assert c[2] == 0 # assert c[0] == 4.0 # assert c[1] == 2.5 # assert c[2] == 2.0 + + +d = array([[1, 2], [3, 4]]) +e = array([[5, 6], [7, 8]]) +f = d + e +assert f[0][0] == 6 +assert f[0][1] == 8 +assert f[1][0] == 10 +assert f[1][1] == 12 From 4426e4144f010ab70ae77dc08cfd29f94f90099d Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 30 Jul 2020 00:09:12 +0100 Subject: [PATCH 2253/2457] compiler: Implement unary plus/minus for arrays Implementation is needlessly generic to anticipate coercion/transcendental functions. --- .../compiler/transforms/artiq_ir_generator.py | 114 +++++++++++++++--- artiq/compiler/transforms/inferencer.py | 32 +++-- artiq/compiler/validators/escape.py | 2 +- .../{array_ops.py => array_binops.py} | 0 artiq/test/lit/integration/array_unaryops.py | 11 ++ 5 files changed, 132 insertions(+), 27 deletions(-) rename artiq/test/lit/integration/{array_ops.py => array_binops.py} (100%) create mode 100644 artiq/test/lit/integration/array_unaryops.py diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 66b3d1f78..055456e09 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -88,6 +88,8 @@ class ARTIQIRGenerator(algorithm.Visitor): necessary. They are kept track of in global dictionaries, with a mangled name containing types and operations as key: + :ivar array_unaryop_funcs: the map from mangled name to implementation of unary + operations for arrays :ivar array_binop_funcs: the map from mangled name to implementation of binary operations between arrays """ @@ -118,6 +120,7 @@ class ARTIQIRGenerator(algorithm.Visitor): self.function_map = dict() self.variable_map = dict() self.method_map = defaultdict(lambda: []) + self.array_unaryop_funcs = dict() self.array_binop_funcs = dict() def annotate_calls(self, devirtualization): @@ -1316,6 +1319,68 @@ class ARTIQIRGenerator(algorithm.Visitor): value_tail.append(ir.Branch(tail)) return phi + def _make_array_unaryop(self, name, make_op, result_type, arg_type): + try: + result = ir.Argument(result_type, "result") + arg = ir.Argument(arg_type, "arg") + + # TODO: We'd like to use a "C function" here to be able to supply + # specialised implementations in a library in the future (and e.g. avoid + # passing around the context argument), but the code generator currently + # doesn't allow emitting them. + args = [result, arg] + typ = types.TFunction(args=OrderedDict([(arg.name, arg.type) + for arg in args]), + optargs=OrderedDict(), + ret=builtins.TNone()) + env_args = [ir.EnvironmentArgument(self.current_env.type, "ARG.ENV")] + + # TODO: What to use for loc? + func = ir.Function(typ, name, env_args + args, loc=None) + func.is_internal = True + func.is_generated = True + self.functions.append(func) + old_func, self.current_function = self.current_function, func + + entry = self.add_block("entry") + old_block, self.current_block = self.current_block, entry + + old_final_branch, self.final_branch = self.final_branch, None + old_unwind, self.unwind_target = self.unwind_target, None + + shape = self.append(ir.GetAttr(arg, "shape")) + + result_buffer = self.append(ir.GetAttr(result, "buffer")) + arg_buffer = self.append(ir.GetAttr(arg, "buffer")) + num_total_elts = self._get_total_array_len(shape) + + def body_gen(index): + a = self.append(ir.GetElem(arg_buffer, index)) + self.append( + ir.SetElem(result_buffer, index, self.append(make_op(a)))) + return self.append( + ir.Arith(ast.Add(loc=None), index, ir.Constant(1, self._size_type))) + + self._make_loop( + ir.Constant(0, self._size_type), lambda index: self.append( + ir.Compare(ast.Lt(loc=None), index, num_total_elts)), body_gen) + + self.append(ir.Return(ir.Constant(None, builtins.TNone()))) + return func + finally: + self.current_function = old_func + self.current_block = old_block + self.final_branch = old_final_branch + self.unwind_target = old_unwind + + def _get_array_unaryop(self, name, make_op, result_type, arg_type): + name = "_array_{}_{}".format( + name, self._mangle_arrayop_types([result_type, arg_type])) + if name not in self.array_unaryop_funcs: + self.array_binop_funcs[name] = self._make_array_unaryop( + name, make_op, result_type, arg_type) + return self.array_binop_funcs[name] + def visit_UnaryOpT(self, node): if isinstance(node.op, ast.Not): cond = self.coerce_to_bool(self.visit(node.operand)) @@ -1327,9 +1392,18 @@ class ARTIQIRGenerator(algorithm.Visitor): return self.append(ir.Arith(ast.BitXor(loc=None), ir.Constant(-1, operand.type), operand)) elif isinstance(node.op, ast.USub): + def make_sub(val): + return ir.Arith(ast.Sub(loc=None), + ir.Constant(0, val.type), val) operand = self.visit(node.operand) - return self.append(ir.Arith(ast.Sub(loc=None), - ir.Constant(0, operand.type), operand)) + if builtins.is_array(operand.type): + shape = self.append(ir.GetAttr(operand, "shape")) + result = self._alloate_new_array(node.type.find()["elt"], shape) + func = self._get_array_unaryop("USub", make_sub, node.type, operand.type) + self._invoke_arrayop(func, [result, operand]) + return result + else: + return self.append(make_sub(operand)) elif isinstance(node.op, ast.UAdd): # No-op. return self.visit(node.operand) @@ -1423,10 +1497,7 @@ class ARTIQIRGenerator(algorithm.Visitor): self.final_branch = old_final_branch self.unwind_target = old_unwind - def _get_array_binop(self, op, result_type, lhs_type, rhs_type): - # Currently, we always have any type coercions resolved explicitly in the AST. - # In the future, this might no longer be true and the three types might all - # differ. + def _mangle_arrayop_types(self, types): def name_error(typ): assert False, "Internal compiler error: No RPC tag for {}".format(typ) @@ -1438,13 +1509,30 @@ class ARTIQIRGenerator(algorithm.Visitor): return (ir.rpc_tag(typ["elt"], name_error).decode() + str(typ["num_dims"].find().value)) - name = "_array_{}_{}_{}_{}".format( - type(op).__name__, *(map(mangle_name, (result_type, lhs_type, rhs_type)))) + return "_".join(mangle_name(t) for t in types) + + def _get_array_binop(self, op, result_type, lhs_type, rhs_type): + # Currently, we always have any type coercions resolved explicitly in the AST. + # In the future, this might no longer be true and the three types might all + # differ. + name = "_array_{}_{}".format( + type(op).__name__, + self._mangle_arrayop_types([result_type, lhs_type, rhs_type])) if name not in self.array_binop_funcs: self.array_binop_funcs[name] = self._make_array_binop( name, op, result_type, lhs_type, rhs_type) return self.array_binop_funcs[name] + def _invoke_arrayop(self, func, params): + closure = self.append( + ir.Closure(func, ir.Constant(None, ir.TEnvironment("arrayop", {})))) + if self.unwind_target is None: + self.append(ir.Call(closure, params, {})) + else: + after_invoke = self.add_block("arrayop.invoke") + self.append(ir.Invoke(func, params, {}, after_invoke, self.unwind_target)) + self.current_block = after_invoke + def visit_BinOpT(self, node): if builtins.is_array(node.type): lhs = self.visit(node.left) @@ -1457,14 +1545,8 @@ class ARTIQIRGenerator(algorithm.Visitor): result = self._alloate_new_array(node.type.find()["elt"], shape) func = self._get_array_binop(node.op, node.type, node.left.type, node.right.type) - closure = self.append(ir.Closure(func, ir.Constant(None, ir.TEnvironment("arrayop", {})))) - params = [result, lhs, rhs] - if self.unwind_target is None: - insn = self.append(ir.Call(closure, params, {})) - else: - after_invoke = self.add_block("arrayop.invoke") - insn = self.append(ir.Invoke(func, params, {}, after_invoke, self.unwind_target)) - self.current_block = after_invoke + self._invoke_arrayop(func, [result, lhs, rhs]) + return result elif builtins.is_numeric(node.type): lhs = self.visit(node.left) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index f2a0a79ee..010d4ec07 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -298,16 +298,27 @@ class Inferencer(algorithm.Visitor): node.operand.loc) self.engine.process(diag) else: # UAdd, USub + if types.is_var(operand_type): + return + if builtins.is_numeric(operand_type): - self._unify(node.type, operand_type, - node.loc, None) - elif not types.is_var(operand_type): - diag = diagnostic.Diagnostic("error", - "expected unary '{op}' operand to be of numeric type, not {type}", - {"op": node.op.loc.source(), - "type": types.TypePrinter().name(operand_type)}, - node.operand.loc) - self.engine.process(diag) + self._unify(node.type, operand_type, node.loc, None) + return + + if builtins.is_array(operand_type): + elt = operand_type.find()["elt"] + if builtins.is_numeric(elt): + self._unify(node.type, operand_type, node.loc, None) + return + if types.is_var(elt): + return + + diag = diagnostic.Diagnostic("error", + "expected unary '{op}' operand to be of numeric type, not {type}", + {"op": node.op.loc.source(), + "type": types.TypePrinter().name(operand_type)}, + node.operand.loc) + self.engine.process(diag) def visit_CoerceT(self, node): self.generic_visit(node) @@ -436,7 +447,8 @@ class Inferencer(algorithm.Visitor): return typ def map_return(typ): - a = builtins.TArray(elt=typ, num_dims=left_dims) + elt = builtins.TFloat() if isinstance(op, ast.Div) else typ + a = builtins.TArray(elt=elt, num_dims=left_dims) return (a, a, a) return self._coerce_numeric((left, right), diff --git a/artiq/compiler/validators/escape.py b/artiq/compiler/validators/escape.py index 000c3ee5b..125355b0c 100644 --- a/artiq/compiler/validators/escape.py +++ b/artiq/compiler/validators/escape.py @@ -156,7 +156,7 @@ class RegionOf(algorithm.Visitor): visit_NameConstantT = visit_immutable visit_NumT = visit_immutable visit_EllipsisT = visit_immutable - visit_UnaryOpT = visit_immutable + visit_UnaryOpT = visit_sometimes_allocating # possibly array op visit_CompareT = visit_immutable # Value lives forever diff --git a/artiq/test/lit/integration/array_ops.py b/artiq/test/lit/integration/array_binops.py similarity index 100% rename from artiq/test/lit/integration/array_ops.py rename to artiq/test/lit/integration/array_binops.py diff --git a/artiq/test/lit/integration/array_unaryops.py b/artiq/test/lit/integration/array_unaryops.py new file mode 100644 index 000000000..e55b6f733 --- /dev/null +++ b/artiq/test/lit/integration/array_unaryops.py @@ -0,0 +1,11 @@ +# RUN: %python -m artiq.compiler.testbench.jit %s + +a = array([1, 2]) + +b = +a +assert b[0] == 1 +assert b[1] == 2 + +b = -a +assert b[0] == -1 +assert b[1] == -2 From da255bee1bb4955c15304ac7785fe2a81225187a Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Thu, 30 Jul 2020 00:18:55 +0100 Subject: [PATCH 2254/2457] compiler: Implement element type coercion for arrays So far, this is not exposed to the user beyond implicit conversions. Note that all the implicit conversions, such as triggered by adding arrays of mismatching types, or dividing integer arrays, are currently emitted in a maximally inefficient way, where a temporary copy is first made for the type conversion. The conversions would more sensibly be implemented during the per-element operations to save on the extra copies, but the current behaviour fell out of the rest of the IR generator structure without extra changes. --- .../compiler/transforms/artiq_ir_generator.py | 18 +++++++++++++++--- artiq/test/lit/integration/array_binops.py | 13 ++++++++----- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 055456e09..9e3ccb6cc 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1415,9 +1415,21 @@ class ARTIQIRGenerator(algorithm.Visitor): if node.type.find() == value.type: return value else: - return self.append(ir.Coerce(value, node.type, - name="{}.{}".format(_readable_name(value), - node.type.name))) + if builtins.is_array(node.type): + result_elt = node.type.find()["elt"] + shape = self.append(ir.GetAttr(value, "shape")) + result = self._alloate_new_array(result_elt, shape) + func = self._get_array_unaryop("Coerce", + lambda v: ir.Coerce(v, result_elt), + node.type, value.type) + self._invoke_arrayop(func, [result, value]) + return result + else: + return self.append( + ir.Coerce(value, + node.type, + name="{}.{}".format(_readable_name(value), + node.type.name))) def _get_total_array_len(self, shape): lengths = [ diff --git a/artiq/test/lit/integration/array_binops.py b/artiq/test/lit/integration/array_binops.py index 86014cc0c..e60052277 100644 --- a/artiq/test/lit/integration/array_binops.py +++ b/artiq/test/lit/integration/array_binops.py @@ -33,12 +33,15 @@ assert c[0] == 0 assert c[1] == 1 assert c[2] == 0 -# FIXME: Implement array coercion. -# c = b / a -# assert c[0] == 4.0 -# assert c[1] == 2.5 -# assert c[2] == 2.0 +cf = b / a +assert cf[0] == 4.0 +assert cf[1] == 2.5 +assert cf[2] == 2.0 +cf2 = cf + a +assert cf2[0] == 5.0 +assert cf2[1] == 4.5 +assert cf2[2] == 5.0 d = array([[1, 2], [3, 4]]) e = array([[5, 6], [7, 8]]) From d37503f21dc6c3df7bf193fb12fce870d0c91136 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Aug 2020 13:42:24 +0100 Subject: [PATCH 2255/2457] compiler: T{C -> External}Function, clarify docs [nfc] --- artiq/compiler/builtins.py | 2 +- artiq/compiler/embedding.py | 6 ++-- .../compiler/transforms/artiq_ir_generator.py | 2 +- .../compiler/transforms/llvm_ir_generator.py | 14 ++++----- artiq/compiler/types.py | 31 +++++++++++++------ artiq/compiler/validators/escape.py | 2 +- 6 files changed, 34 insertions(+), 23 deletions(-) diff --git a/artiq/compiler/builtins.py b/artiq/compiler/builtins.py index 7edd97d9a..7a0aa6161 100644 --- a/artiq/compiler/builtins.py +++ b/artiq/compiler/builtins.py @@ -334,6 +334,6 @@ def is_allocated(typ): return not (is_none(typ) or is_bool(typ) or is_int(typ) or is_float(typ) or is_range(typ) or types._is_pointer(typ) or types.is_function(typ) or - types.is_c_function(typ) or types.is_rpc(typ) or + types.is_external_function(typ) or types.is_rpc(typ) or types.is_method(typ) or types.is_tuple(typ) or types.is_value(typ)) diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index fb0a8be39..bdac020bb 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -1001,9 +1001,9 @@ class Stitcher: self.engine.process(diag) ret_type = types.TVar() - function_type = types.TCFunction(arg_types, ret_type, - name=function.artiq_embedded.syscall, - flags=function.artiq_embedded.flags) + function_type = types.TExternalFunction(arg_types, ret_type, + name=function.artiq_embedded.syscall, + flags=function.artiq_embedded.flags) self.functions[function] = function_type return function_type diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 9e3ccb6cc..4241669e0 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -2137,7 +2137,7 @@ class ARTIQIRGenerator(algorithm.Visitor): assert None not in args if self.unwind_target is None or \ - types.is_c_function(callee.type) and "nounwind" in callee.type.flags: + types.is_external_function(callee.type) and "nounwind" in callee.type.flags: insn = self.append(ir.Call(func, args, arg_exprs)) else: after_invoke = self.add_block("invoke") diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 70ef64785..31384e578 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -205,7 +205,7 @@ class LLVMIRGenerator: typ = typ.find() if types.is_tuple(typ): return ll.LiteralStructType([self.llty_of_type(eltty) for eltty in typ.elts]) - elif types.is_rpc(typ) or types.is_c_function(typ): + elif types.is_rpc(typ) or types.is_external_function(typ): if for_return: return llvoid else: @@ -838,7 +838,7 @@ class LLVMIRGenerator: closure_type = typ.attributes[attr] assert types.is_constructor(typ) assert types.is_function(closure_type) or types.is_rpc(closure_type) - if types.is_c_function(closure_type) or types.is_rpc(closure_type): + if types.is_external_function(closure_type) or types.is_rpc(closure_type): return None llty = self.llty_of_type(typ.attributes[attr]) @@ -1443,7 +1443,7 @@ class LLVMIRGenerator: functiontyp, insn.arguments(), llnormalblock=None, llunwindblock=None) - elif types.is_c_function(functiontyp): + elif types.is_external_function(functiontyp): llfun, llargs = self._prepare_ffi_call(insn) else: llfun, llargs = self._prepare_closure_call(insn) @@ -1466,7 +1466,7 @@ class LLVMIRGenerator: # Never add TBAA nowrite metadata to a functon with sret! # This leads to miscompilations. - if types.is_c_function(functiontyp) and 'nowrite' in functiontyp.flags: + if types.is_external_function(functiontyp) and 'nowrite' in functiontyp.flags: llcall.set_metadata('tbaa', self.tbaa_nowrite_call) return llresult @@ -1480,7 +1480,7 @@ class LLVMIRGenerator: functiontyp, insn.arguments(), llnormalblock, llunwindblock) - elif types.is_c_function(functiontyp): + elif types.is_external_function(functiontyp): llfun, llargs = self._prepare_ffi_call(insn) else: llfun, llargs = self._prepare_closure_call(insn) @@ -1530,7 +1530,7 @@ class LLVMIRGenerator: attrvalue = getattr(value, attr) is_class_function = (types.is_constructor(typ) and types.is_function(typ.attributes[attr]) and - not types.is_c_function(typ.attributes[attr])) + not types.is_external_function(typ.attributes[attr])) if is_class_function: attrvalue = self.embedding_map.specialize_function(typ.instance, attrvalue) if not (types.is_instance(typ) and attr in typ.constant_attributes): @@ -1600,7 +1600,7 @@ class LLVMIRGenerator: llelts = [self._quote(v, t, lambda: path() + [str(i)]) for i, (v, t) in enumerate(zip(value, typ.elts))] return ll.Constant(llty, llelts) - elif types.is_rpc(typ) or types.is_c_function(typ) or types.is_builtin_function(typ): + elif types.is_rpc(typ) or types.is_external_function(typ) or types.is_builtin_function(typ): # RPC, C and builtin functions have no runtime representation. return ll.Constant(llty, ll.Undefined) elif types.is_function(typ): diff --git a/artiq/compiler/types.py b/artiq/compiler/types.py index deeb8352b..281b53577 100644 --- a/artiq/compiler/types.py +++ b/artiq/compiler/types.py @@ -283,12 +283,18 @@ class TFunction(Type): def __hash__(self): return hash((_freeze(self.args), _freeze(self.optargs), self.ret)) -class TCFunction(TFunction): +class TExternalFunction(TFunction): """ - A function type of a runtime-provided C function. + A type of an externally-provided function. - :ivar name: (str) C function name - :ivar flags: (set of str) C function flags. + This can be any function following the C ABI, such as provided by the + C/Rust runtime, or a compiler backend intrinsic. The mangled name to link + against is encoded as part of the type. + + :ivar name: (str) external symbol name. + This will be the symbol linked against (following any extra C name + mangling rules). + :ivar flags: (set of str) function flags. Flag ``nounwind`` means the function never raises an exception. Flag ``nowrite`` means the function never writes any memory that the ARTIQ Python code can observe. @@ -308,7 +314,7 @@ class TCFunction(TFunction): def unify(self, other): if other is self: return - if isinstance(other, TCFunction) and \ + if isinstance(other, TExternalFunction) and \ self.name == other.name: super().unify(other) elif isinstance(other, TVar): @@ -404,6 +410,11 @@ class TBuiltin(Type): class TBuiltinFunction(TBuiltin): """ A type of a builtin function. + + Builtin functions are treated specially throughout all stages of the + compilation process according to their name (e.g. calls may not actually + lower to a function call). See :class:`TExternalFunction` for externally + defined functions that are otherwise regular. """ class TConstructor(TBuiltin): @@ -609,12 +620,12 @@ def is_function(typ): def is_rpc(typ): return isinstance(typ.find(), TRPC) -def is_c_function(typ, name=None): +def is_external_function(typ, name=None): typ = typ.find() if name is None: - return isinstance(typ, TCFunction) + return isinstance(typ, TExternalFunction) else: - return isinstance(typ, TCFunction) and \ + return isinstance(typ, TExternalFunction) and \ typ.name == name def is_builtin(typ, name=None): @@ -744,7 +755,7 @@ class TypePrinter(object): return "(%s,)" % self.name(typ.elts[0], depth + 1) else: return "(%s)" % ", ".join([self.name(typ, depth + 1) for typ in typ.elts]) - elif isinstance(typ, (TFunction, TCFunction)): + elif isinstance(typ, (TFunction, TExternalFunction)): args = [] args += [ "%s:%s" % (arg, self.name(typ.args[arg], depth + 1)) for arg in typ.args] @@ -758,7 +769,7 @@ class TypePrinter(object): elif not (delay.is_fixed() and iodelay.is_zero(delay.duration)): signature += " " + self.name(delay, depth + 1) - if isinstance(typ, TCFunction): + if isinstance(typ, TExternalFunction): return "[ffi {}]{}".format(repr(typ.name), signature) elif isinstance(typ, TFunction): return signature diff --git a/artiq/compiler/validators/escape.py b/artiq/compiler/validators/escape.py index 125355b0c..c6ae59704 100644 --- a/artiq/compiler/validators/escape.py +++ b/artiq/compiler/validators/escape.py @@ -99,7 +99,7 @@ class RegionOf(algorithm.Visitor): visit_BinOpT = visit_sometimes_allocating def visit_CallT(self, node): - if types.is_c_function(node.func.type, "cache_get"): + if types.is_external_function(node.func.type, "cache_get"): # The cache is borrow checked dynamically return Global() else: From 4d484703205e33d85d9dd9ade4f1ddc15c0a5217 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Aug 2020 15:27:02 +0100 Subject: [PATCH 2256/2457] compiler: Support common numpy.* math functions Relies on the runtime to provide the necessary (libm-compatible) functions. The test is nifty, but a bit brittle; if this breaks in the future because of optimizer changes, do not hesitate to convert this into a more pedestrian test case. --- artiq/compiler/embedding.py | 11 ++++++-- artiq/compiler/math_fns.py | 42 ++++++++++++++++++++++++++++ artiq/test/lit/embedding/math_fns.py | 30 ++++++++++++++++++++ 3 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 artiq/compiler/math_fns.py create mode 100644 artiq/test/lit/embedding/math_fns.py diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index bdac020bb..ddacf947f 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -14,7 +14,7 @@ from pythonparser import lexer as source_lexer, parser as source_parser from Levenshtein import ratio as similarity, jaro_winkler from ..language import core as language_core -from . import types, builtins, asttyped, prelude +from . import types, builtins, asttyped, math_fns, prelude from .transforms import ASTTypedRewriter, Inferencer, IntMonomorphizer, TypedtreePrinter from .transforms.asttyped_rewriter import LocalExtractor @@ -246,7 +246,8 @@ class ASTSynthesizer: loc=begin_loc.join(end_loc)) elif inspect.isfunction(value) or inspect.ismethod(value) or \ isinstance(value, pytypes.BuiltinFunctionType) or \ - isinstance(value, SpecializedFunction): + isinstance(value, SpecializedFunction) or \ + isinstance(value, numpy.ufunc): if inspect.ismethod(value): quoted_self = self.quote(value.__self__) function_type = self.quote_function(value.__func__, self.expanded_from) @@ -1057,7 +1058,11 @@ class Stitcher: host_function = function if function in self.functions: - pass + return self.functions[function] + + math_type = math_fns.match(function) + if math_type is not None: + self.functions[function] = math_type elif not hasattr(host_function, "artiq_embedded") or \ (host_function.artiq_embedded.core_name is None and host_function.artiq_embedded.portable is False and diff --git a/artiq/compiler/math_fns.py b/artiq/compiler/math_fns.py new file mode 100644 index 000000000..83c1f82b4 --- /dev/null +++ b/artiq/compiler/math_fns.py @@ -0,0 +1,42 @@ +from collections import OrderedDict +import numpy +from . import builtins, types + +#: float -> float numpy.* math functions for which llvm.* intrinsics exist. +unary_fp_intrinsics = [(name, "llvm." + name + ".f64") for name in [ + "sin", + "cos", + "exp", + "exp2", + "log", + "log10", + "log2", + "fabs", + "floor", + "ceil", + "trunc", + "rint", +]] + +#: float -> float numpy.* math functions lowered to runtime calls. +unary_fp_runtime_calls = [ + ("tan", "tan"), + ("arcsin", "asin"), + ("arccos", "acos"), + ("arctan", "atan"), +] + + +def unary_fp_type(name): + return types.TExternalFunction(OrderedDict([("arg", builtins.TFloat())]), + builtins.TFloat(), name) + + +numpy_map = { + getattr(numpy, symbol): unary_fp_type(mangle) + for symbol, mangle in (unary_fp_intrinsics + unary_fp_runtime_calls) +} + + +def match(obj): + return numpy_map.get(obj, None) diff --git a/artiq/test/lit/embedding/math_fns.py b/artiq/test/lit/embedding/math_fns.py new file mode 100644 index 000000000..40ac18e42 --- /dev/null +++ b/artiq/test/lit/embedding/math_fns.py @@ -0,0 +1,30 @@ +# RUN: env ARTIQ_DUMP_LLVM=%t %python -m artiq.compiler.testbench.embedding %s +# RUN: OutputCheck %s --file-to-check=%t.ll + +from artiq.language.core import * +from artiq.language.types import * +import numpy + +@kernel +def entrypoint(): + # LLVM's constant folding for transcendental functions is good enough that + # we can do a basic smoke test by just making sure the module compiles and + # all assertions are statically eliminated. + + # CHECK-NOT: assert + assert numpy.sin(0.0) == 0.0 + assert numpy.cos(0.0) == 1.0 + assert numpy.exp(0.0) == 1.0 + assert numpy.exp2(1.0) == 2.0 + assert numpy.log(numpy.exp(1.0)) == 1.0 + assert numpy.log10(10.0) == 1.0 + assert numpy.log2(2.0) == 1.0 + assert numpy.fabs(-1.0) == 1.0 + assert numpy.floor(42.5) == 42.0 + assert numpy.ceil(42.5) == 43.0 + assert numpy.trunc(41.5) == 41.0 + assert numpy.rint(41.5) == 42.0 + assert numpy.tan(0.0) == 0.0 + assert numpy.arcsin(0.0) == 0.0 + assert numpy.arccos(1.0) == 0.0 + assert numpy.arctan(0.0) == 0.0 From 78afa2ea8ed6fa81eceed32c811f9582d48ee89e Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Aug 2020 17:52:15 +0100 Subject: [PATCH 2257/2457] compiler: Support MatMult in inferencer Still needs actual codegen support. --- artiq/compiler/transforms/inferencer.py | 65 ++++++++++++++++++++-- artiq/test/lit/inferencer/error_matmult.py | 11 ++++ artiq/test/lit/inferencer/matmult.py | 17 ++++++ 3 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 artiq/test/lit/inferencer/error_matmult.py create mode 100644 artiq/test/lit/inferencer/matmult.py diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 010d4ec07..7649682c2 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -402,11 +402,66 @@ class Inferencer(algorithm.Visitor): assert False def _coerce_binop(self, op, left, right): - if builtins.is_array(left.type) or builtins.is_array(right.type): - # Operations on arrays are element-wise (possibly using broadcasting). - # TODO: Matrix multiplication (which aren't element-wise). + if isinstance(op, ast.MatMult): + if types.is_var(left.type) or types.is_var(right.type): + return - # # TODO: Allow only for integer arrays. + def num_dims(operand): + if not builtins.is_array(operand.type): + diag = diagnostic.Diagnostic( + "error", + "expected matrix multiplication operand to be of array type, not {type}", + { + "op": op.loc.source(), + "type": types.TypePrinter().name(operand.type) + }, op.loc, [operand.loc]) + self.engine.process(diag) + return + num_dims = operand.type.find()["num_dims"].value + if num_dims not in (1, 2): + diag = diagnostic.Diagnostic( + "error", + "expected matrix multiplication operand to be 1- or 2-dimensional, not {type}", + { + "op": op.loc.source(), + "type": types.TypePrinter().name(operand.type) + }, op.loc, [operand.loc]) + self.engine.process(diag) + return + return num_dims + + left_dims = num_dims(left) + if not left_dims: + return + right_dims = num_dims(right) + if not right_dims: + return + + def map_node_type(typ): + return typ.find()["elt"] + + def map_return(typ): + if left_dims == 1: + if right_dims == 1: + result_dims = 0 + else: + result_dims = 1 + elif right_dims == 1: + result_dims = 1 + else: + result_dims = 2 + result = typ if result_dims == 0 else builtins.TArray( + typ, result_dims) + return (result, builtins.TArray(typ, left_dims), + builtins.TArray(typ, right_dims)) + + return self._coerce_numeric((left, right), + map_return=map_return, + map_node_type=map_node_type) + elif builtins.is_array(left.type) or builtins.is_array(right.type): + # Operations on arrays are element-wise (possibly using broadcasting). + + # TODO: Allow only for integer arrays. # allowed_int_array_ops = (ast.BitAnd, ast.BitOr, ast.BitXor, ast.LShift, # ast.RShift) allowed_array_ops = (ast.Add, ast.Mult, ast.FloorDiv, ast.Mod, @@ -553,7 +608,7 @@ class Inferencer(algorithm.Visitor): # division always returns a float return self._coerce_numeric((left, right), lambda typ: (builtins.TFloat(), builtins.TFloat(), builtins.TFloat())) - else: # MatMult + else: diag = diagnostic.Diagnostic("error", "operator '{op}' is not supported", {"op": op.loc.source()}, op.loc) diff --git a/artiq/test/lit/inferencer/error_matmult.py b/artiq/test/lit/inferencer/error_matmult.py new file mode 100644 index 000000000..2586aec31 --- /dev/null +++ b/artiq/test/lit/inferencer/error_matmult.py @@ -0,0 +1,11 @@ +# RUN: %python -m artiq.compiler.testbench.inferencer +diag %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +# CHECK-L: ${LINE:+1}: error: expected matrix multiplication operand to be of array type +1 @ 2 + +# CHECK-L: ${LINE:+1}: error: expected matrix multiplication operand to be of array type +[1] @ [2] + +# CHECK-L: ${LINE:+1}: error: expected matrix multiplication operand to be 1- or 2-dimensional +array([[[0]]]) @ array([[[1]]]) diff --git a/artiq/test/lit/inferencer/matmult.py b/artiq/test/lit/inferencer/matmult.py new file mode 100644 index 000000000..e8e982c57 --- /dev/null +++ b/artiq/test/lit/inferencer/matmult.py @@ -0,0 +1,17 @@ +# RUN: %python -m artiq.compiler.testbench.inferencer %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +vec = array([0, 1]) +mat = array([[0, 1], [2, 3]]) + +# CHECK-L: ):numpy.int? +vec @ vec + +# CHECK-L: ):numpy.array(elt=numpy.int?, num_dims=1) +vec @ mat + +# CHECK-L: ):numpy.array(elt=numpy.int?, num_dims=1) +mat @ vec + +# CHECK-L: ):numpy.array(elt=numpy.int?, num_dims=2) +mat @ mat From 0da4a61d995d8b88118584abcd104c835af18b69 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Aug 2020 20:25:07 +0100 Subject: [PATCH 2258/2457] compiler: Fix method name typo [nfc] --- artiq/compiler/transforms/artiq_ir_generator.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 4241669e0..81b4b5ce5 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1398,7 +1398,7 @@ class ARTIQIRGenerator(algorithm.Visitor): operand = self.visit(node.operand) if builtins.is_array(operand.type): shape = self.append(ir.GetAttr(operand, "shape")) - result = self._alloate_new_array(node.type.find()["elt"], shape) + result = self._allocate_new_array(node.type.find()["elt"], shape) func = self._get_array_unaryop("USub", make_sub, node.type, operand.type) self._invoke_arrayop(func, [result, operand]) return result @@ -1418,7 +1418,7 @@ class ARTIQIRGenerator(algorithm.Visitor): if builtins.is_array(node.type): result_elt = node.type.find()["elt"] shape = self.append(ir.GetAttr(value, "shape")) - result = self._alloate_new_array(result_elt, shape) + result = self._allocate_new_array(result_elt, shape) func = self._get_array_unaryop("Coerce", lambda v: ir.Coerce(v, result_elt), node.type, value.type) @@ -1438,7 +1438,7 @@ class ARTIQIRGenerator(algorithm.Visitor): return reduce(lambda l, r: self.append(ir.Arith(ast.Mult(loc=None), l, r)), lengths[1:], lengths[0]) - def _alloate_new_array(self, elt, shape): + def _allocate_new_array(self, elt, shape): total_length = self._get_total_array_len(shape) buffer = self.append(ir.Alloc([total_length], types._TPointer(elt=elt))) result_type = builtins.TArray(elt, types.TValue(len(shape.type.elts))) @@ -1554,7 +1554,7 @@ class ARTIQIRGenerator(algorithm.Visitor): # TODO: Broadcasts; select the widest shape. # TODO: Detect and special-case matrix multiplication. shape = self.append(ir.GetAttr(lhs, "shape")) - result = self._alloate_new_array(node.type.find()["elt"], shape) + result = self._allocate_new_array(node.type.find()["elt"], shape) func = self._get_array_binop(node.op, node.type, node.left.type, node.right.type) self._invoke_arrayop(func, [result, lhs, rhs]) From ef260adca85e4a27f858744ffa6e4c460ea1d4a3 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Aug 2020 20:26:20 +0100 Subject: [PATCH 2259/2457] compiler: Implement matrix multiplication LLVM will take care of optimising the loops. This was still unnecessarily painful; implementing generics and implementing this in ARTIQ Python looks very attractive right now. --- .../compiler/transforms/artiq_ir_generator.py | 228 +++++++++++++++--- artiq/test/lit/integration/array_matmult.py | 25 ++ 2 files changed, 218 insertions(+), 35 deletions(-) create mode 100644 artiq/test/lit/integration/array_matmult.py diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 81b4b5ce5..fa5912999 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -527,7 +527,7 @@ class ARTIQIRGenerator(algorithm.Visitor): if num_dims > 1: old_shape = self.append(ir.GetAttr(value, "shape")) lengths = [self.append(ir.GetAttr(old_shape, i)) for i in range(1, num_dims)] - new_shape = self.append(ir.Alloc(lengths, types.TTuple(old_shape.type.elts[1:]))) + new_shape = self._make_array_shape(lengths) stride = reduce( lambda l, r: self.append(ir.Arith(ast.Mult(loc=None), l, r)), @@ -1444,7 +1444,7 @@ class ARTIQIRGenerator(algorithm.Visitor): result_type = builtins.TArray(elt, types.TValue(len(shape.type.elts))) return self.append(ir.Alloc([buffer, shape], result_type)) - def _make_array_binop(self, name, op, result_type, lhs_type, rhs_type): + def _make_array_binop(self, name, result_type, lhs_type, rhs_type, body_gen): try: result = ir.Argument(result_type, "result") lhs = ir.Argument(lhs_type, "lhs") @@ -1461,8 +1461,8 @@ class ARTIQIRGenerator(algorithm.Visitor): ret=builtins.TNone()) env_args = [ir.EnvironmentArgument(self.current_env.type, "ARG.ENV")] - # TODO: What to use for loc? - func = ir.Function(typ, name, env_args + args, loc=None) + old_loc, self.current_loc = self.current_loc, None + func = ir.Function(typ, name, env_args + args) func.is_internal = True func.is_generated = True self.functions.append(func) @@ -1474,36 +1474,12 @@ class ARTIQIRGenerator(algorithm.Visitor): old_final_branch, self.final_branch = self.final_branch, None old_unwind, self.unwind_target = self.unwind_target, None - shape = self.append(ir.GetAttr(lhs, "shape")) - rhs_shape = self.append(ir.GetAttr(rhs, "shape")) - self._make_check( - self.append(ir.Compare(ast.Eq(loc=None), shape, rhs_shape)), - lambda: self.alloc_exn( - builtins.TException("ValueError"), - ir.Constant("operands could not be broadcast together", - builtins.TStr()))) - # We assume result has correct shape; could just pass buffer pointer as well. - - result_buffer = self.append(ir.GetAttr(result, "buffer")) - lhs_buffer = self.append(ir.GetAttr(lhs, "buffer")) - rhs_buffer = self.append(ir.GetAttr(rhs, "buffer")) - num_total_elts = self._get_total_array_len(shape) - - def body_gen(index): - l = self.append(ir.GetElem(lhs_buffer, index)) - r = self.append(ir.GetElem(rhs_buffer, index)) - self.append( - ir.SetElem(result_buffer, index, self.append(ir.Arith(op, l, r)))) - return self.append( - ir.Arith(ast.Add(loc=None), index, ir.Constant(1, self._size_type))) - - self._make_loop( - ir.Constant(0, self._size_type), lambda index: self.append( - ir.Compare(ast.Lt(loc=None), index, num_total_elts)), body_gen) + body_gen(result, lhs, rhs) self.append(ir.Return(ir.Constant(None, builtins.TNone()))) return func finally: + self.current_loc = old_loc self.current_function = old_func self.current_block = old_block self.final_branch = old_final_branch @@ -1518,8 +1494,9 @@ class ARTIQIRGenerator(algorithm.Visitor): # rpc_tag is used to turn element types into mangled names for no # particularly good reason apart from not having to invent yet another # string representation. - return (ir.rpc_tag(typ["elt"], name_error).decode() + - str(typ["num_dims"].find().value)) + if builtins.is_array(typ): + return mangle_name(typ["elt"]) + str(typ["num_dims"].find().value) + return ir.rpc_tag(typ, name_error).decode() return "_".join(mangle_name(t) for t in types) @@ -1531,8 +1508,41 @@ class ARTIQIRGenerator(algorithm.Visitor): type(op).__name__, self._mangle_arrayop_types([result_type, lhs_type, rhs_type])) if name not in self.array_binop_funcs: + + def body_gen(result, lhs, rhs): + # TODO: Move into caller for correct location information (or pass)? + shape = self.append(ir.GetAttr(lhs, "shape")) + rhs_shape = self.append(ir.GetAttr(rhs, "shape")) + self._make_check( + self.append(ir.Compare(ast.Eq(loc=None), shape, rhs_shape)), + lambda: self.alloc_exn( + builtins.TException("ValueError"), + ir.Constant("operands could not be broadcast together", + builtins.TStr()))) + # We assume result has correct shape; could just pass buffer pointer + # as well. + + result_buffer = self.append(ir.GetAttr(result, "buffer")) + lhs_buffer = self.append(ir.GetAttr(lhs, "buffer")) + rhs_buffer = self.append(ir.GetAttr(rhs, "buffer")) + num_total_elts = self._get_total_array_len(shape) + + def loop_gen(index): + l = self.append(ir.GetElem(lhs_buffer, index)) + r = self.append(ir.GetElem(rhs_buffer, index)) + self.append( + ir.SetElem(result_buffer, index, self.append(ir.Arith(op, l, + r)))) + return self.append( + ir.Arith(ast.Add(loc=None), index, + ir.Constant(1, self._size_type))) + + self._make_loop( + ir.Constant(0, self._size_type), lambda index: self.append( + ir.Compare(ast.Lt(loc=None), index, num_total_elts)), loop_gen) + self.array_binop_funcs[name] = self._make_array_binop( - name, op, result_type, lhs_type, rhs_type) + name, result_type, lhs_type, rhs_type, body_gen) return self.array_binop_funcs[name] def _invoke_arrayop(self, func, params): @@ -1545,14 +1555,162 @@ class ARTIQIRGenerator(algorithm.Visitor): self.append(ir.Invoke(func, params, {}, after_invoke, self.unwind_target)) self.current_block = after_invoke + def _get_array_offset(self, shape, indices): + last_stride = None + result = indices[0] + for dim, index in zip(shape[:-1], indices[1:]): + result = self.append(ir.Arith(ast.Mult(loc=None), result, dim)) + result = self.append(ir.Arith(ast.Add(loc=None), result, index)) + return result + + def _get_matmult(self, result_type, lhs_type, rhs_type): + name = "_array_MatMult_" + self._mangle_arrayop_types( + [result_type, lhs_type, rhs_type]) + if name not in self.array_binop_funcs: + + def body_gen(result, lhs, rhs): + assert builtins.is_array(result.type), \ + "vec @ vec should have been normalised into array result" + + # We assume result has correct shape; could just pass buffer pointer + # as well. + result_buffer = self.append(ir.GetAttr(result, "buffer")) + lhs_buffer = self.append(ir.GetAttr(lhs, "buffer")) + rhs_buffer = self.append(ir.GetAttr(rhs, "buffer")) + + num_rows, num_summands, _, num_cols = self._get_matmult_shapes(lhs, rhs) + + elt = result.type["elt"].find() + env_type = ir.TEnvironment("loop", {"$total": elt}) + env = self.append(ir.Alloc([], env_type)) + + def row_loop(row_idx): + lhs_base_offset = self.append( + ir.Arith(ast.Mult(loc=None), row_idx, num_summands)) + lhs_base = self.append(ir.Offset(lhs_buffer, lhs_base_offset)) + result_base_offset = self.append( + ir.Arith(ast.Mult(loc=None), row_idx, num_cols)) + result_base = self.append( + ir.Offset(result_buffer, result_base_offset)) + + def col_loop(col_idx): + rhs_base = self.append(ir.Offset(rhs_buffer, col_idx)) + + self.append( + ir.SetLocal(env, "$total", ir.Constant(elt.zero(), elt))) + + def sum_loop(sum_idx): + lhs_elem = self.append(ir.GetElem(lhs_base, sum_idx)) + rhs_offset = self.append( + ir.Arith(ast.Mult(loc=None), sum_idx, num_cols)) + rhs_elem = self.append(ir.GetElem(rhs_base, rhs_offset)) + product = self.append( + ir.Arith(ast.Mult(loc=None), lhs_elem, rhs_elem)) + prev_total = self.append(ir.GetLocal(env, "$total")) + total = self.append( + ir.Arith(ast.Add(loc=None), prev_total, product)) + self.append(ir.SetLocal(env, "$total", total)) + return self.append( + ir.Arith(ast.Add(loc=None), sum_idx, + ir.Constant(1, self._size_type))) + + self._make_loop( + ir.Constant(0, self._size_type), lambda index: self.append( + ir.Compare(ast.Lt(loc=None), index, num_summands)), + sum_loop) + + total = self.append(ir.GetLocal(env, "$total")) + self.append(ir.SetElem(result_base, col_idx, total)) + + return self.append( + ir.Arith(ast.Add(loc=None), col_idx, + ir.Constant(1, self._size_type))) + + self._make_loop( + ir.Constant(0, self._size_type), lambda index: self.append( + ir.Compare(ast.Lt(loc=None), index, num_cols)), col_loop) + return self.append( + ir.Arith(ast.Add(loc=None), row_idx, + ir.Constant(1, self._size_type))) + + self._make_loop( + ir.Constant(0, self._size_type), lambda index: self.append( + ir.Compare(ast.Lt(loc=None), index, num_rows)), row_loop) + + self.array_binop_funcs[name] = self._make_array_binop( + name, result_type, lhs_type, rhs_type, body_gen) + return self.array_binop_funcs[name] + + def _get_matmult_shapes(self, lhs, rhs): + lhs_shape = self.append(ir.GetAttr(lhs, "shape")) + if lhs.type["num_dims"].value == 1: + lhs_shape_outer = ir.Constant(1, self._size_type) + lhs_shape_inner = self.append(ir.GetAttr(lhs_shape, 0)) + else: + lhs_shape_outer = self.append(ir.GetAttr(lhs_shape, 0)) + lhs_shape_inner = self.append(ir.GetAttr(lhs_shape, 1)) + + rhs_shape = self.append(ir.GetAttr(rhs, "shape")) + if rhs.type["num_dims"].value == 1: + rhs_shape_inner = self.append(ir.GetAttr(rhs_shape, 0)) + rhs_shape_outer = ir.Constant(1, self._size_type) + else: + rhs_shape_inner = self.append(ir.GetAttr(rhs_shape, 0)) + rhs_shape_outer = self.append(ir.GetAttr(rhs_shape, 1)) + + return lhs_shape_outer, lhs_shape_inner, rhs_shape_inner, rhs_shape_outer + + def _make_array_shape(self, dims): + return self.append(ir.Alloc(dims, types.TTuple([self._size_type] * len(dims)))) + + def _emit_matmult(self, node, left, right): + # TODO: Also expose as numpy.dot. + lhs = self.visit(left) + rhs = self.visit(right) + + num_rows, lhs_inner, rhs_inner, num_cols = self._get_matmult_shapes(lhs, rhs) + self._make_check( + self.append(ir.Compare(ast.Eq(loc=None), lhs_inner, rhs_inner)), + lambda lhs_inner, rhs_inner: self.alloc_exn( + builtins.TException("ValueError"), + ir.Constant( + "inner dimensions for matrix multiplication do not match ({0} vs. {1})", + builtins.TStr()), lhs_inner, rhs_inner), + params=[lhs_inner, rhs_inner], + loc=node.loc) + result_shape = self._make_array_shape([num_rows, num_cols]) + + final_type = node.type.find() + if not builtins.is_array(final_type): + elt = node.type + result_dims = 0 + else: + elt = final_type["elt"] + result_dims = final_type["num_dims"].value + + result = self._allocate_new_array(elt, result_shape) + func = self._get_matmult(result.type, left.type, right.type) + self._invoke_arrayop(func, [result, lhs, rhs]) + + if result_dims == 2: + return result + result_buffer = self.append(ir.GetAttr(result, "buffer")) + if result_dims == 1: + shape = self._make_array_shape( + [num_cols if lhs.type["num_dims"].value == 1 else num_rows]) + return self.append(ir.Alloc([result_buffer, shape], node.type)) + return self.append(ir.GetElem(result_buffer, ir.Constant(0, self._size_type))) + + def visit_BinOpT(self, node): - if builtins.is_array(node.type): + if isinstance(node.op, ast.MatMult): + return self._emit_matmult(node, node.left, node.right) + elif builtins.is_array(node.type): lhs = self.visit(node.left) rhs = self.visit(node.right) # Array op implementation will check for matching shape. # TODO: Broadcasts; select the widest shape. - # TODO: Detect and special-case matrix multiplication. shape = self.append(ir.GetAttr(lhs, "shape")) result = self._allocate_new_array(node.type.find()["elt"], shape) diff --git a/artiq/test/lit/integration/array_matmult.py b/artiq/test/lit/integration/array_matmult.py new file mode 100644 index 000000000..7519c10ff --- /dev/null +++ b/artiq/test/lit/integration/array_matmult.py @@ -0,0 +1,25 @@ +# RUN: %python -m artiq.compiler.testbench.jit %s + +mat23 = array([[1, 2, 3], [4, 5, 6]]) +mat32 = array([[1, 2], [3, 4], [5, 6]]) +vec2 = array([1, 2]) +vec3 = array([1, 2, 3]) + +assert vec3 @ vec3 == 14 + +a = mat23 @ mat32 +assert a.shape == (2, 2) +assert a[0][0] == 22 +assert a[0][1] == 28 +assert a[1][0] == 49 +assert a[1][1] == 64 + +b = mat23 @ vec3 +assert b.shape == (2,) +assert b[0] == 14 +assert b[1] == 32 + +b = vec3 @ mat32 +assert b.shape == (2,) +assert b[0] == 22 +assert b[1] == 28 From 56a872ccc03061cc36ff125a66fd5e059c53fcb6 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Aug 2020 20:35:31 +0100 Subject: [PATCH 2260/2457] compiler: Insert array binop shape check in caller for location information --- .../compiler/transforms/artiq_ir_generator.py | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index fa5912999..a77969fc9 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1510,21 +1510,12 @@ class ARTIQIRGenerator(algorithm.Visitor): if name not in self.array_binop_funcs: def body_gen(result, lhs, rhs): - # TODO: Move into caller for correct location information (or pass)? - shape = self.append(ir.GetAttr(lhs, "shape")) - rhs_shape = self.append(ir.GetAttr(rhs, "shape")) - self._make_check( - self.append(ir.Compare(ast.Eq(loc=None), shape, rhs_shape)), - lambda: self.alloc_exn( - builtins.TException("ValueError"), - ir.Constant("operands could not be broadcast together", - builtins.TStr()))) - # We assume result has correct shape; could just pass buffer pointer - # as well. - + # At this point, shapes are assumed to match; could just pass buffer + # pointer for two of the three arrays as well. result_buffer = self.append(ir.GetAttr(result, "buffer")) lhs_buffer = self.append(ir.GetAttr(lhs, "buffer")) rhs_buffer = self.append(ir.GetAttr(rhs, "buffer")) + shape = self.append(ir.GetAttr(result, "shape")) num_total_elts = self._get_total_array_len(shape) def loop_gen(index): @@ -1709,9 +1700,15 @@ class ARTIQIRGenerator(algorithm.Visitor): lhs = self.visit(node.left) rhs = self.visit(node.right) - # Array op implementation will check for matching shape. - # TODO: Broadcasts; select the widest shape. shape = self.append(ir.GetAttr(lhs, "shape")) + # TODO: Broadcasts; select the widest shape. + rhs_shape = self.append(ir.GetAttr(rhs, "shape")) + self._make_check( + self.append(ir.Compare(ast.Eq(loc=None), shape, rhs_shape)), + lambda: self.alloc_exn( + builtins.TException("ValueError"), + ir.Constant("operands could not be broadcast together", + builtins.TStr()))) result = self._allocate_new_array(node.type.find()["elt"], shape) func = self._get_array_binop(node.op, node.type, node.left.type, node.right.type) From faea886c44201c31d8ba27a9ec2a83f6b17caf16 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Aug 2020 21:39:36 +0100 Subject: [PATCH 2261/2457] compiler: Implement array vs. scalar broadcasting --- .../compiler/transforms/artiq_ir_generator.py | 60 +++++++++++++------ artiq/compiler/transforms/inferencer.py | 19 +++--- artiq/test/lit/integration/array_broadcast.py | 55 +++++++++++++++++ 3 files changed, 107 insertions(+), 27 deletions(-) create mode 100644 artiq/test/lit/integration/array_broadcast.py diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index a77969fc9..e148ce184 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1513,17 +1513,30 @@ class ARTIQIRGenerator(algorithm.Visitor): # At this point, shapes are assumed to match; could just pass buffer # pointer for two of the three arrays as well. result_buffer = self.append(ir.GetAttr(result, "buffer")) - lhs_buffer = self.append(ir.GetAttr(lhs, "buffer")) - rhs_buffer = self.append(ir.GetAttr(rhs, "buffer")) shape = self.append(ir.GetAttr(result, "shape")) num_total_elts = self._get_total_array_len(shape) + if builtins.is_array(lhs.type): + lhs_buffer = self.append(ir.GetAttr(lhs, "buffer")) + def get_left(index): + return self.append(ir.GetElem(lhs_buffer, index)) + else: + def get_left(index): + return lhs + + if builtins.is_array(rhs.type): + rhs_buffer = self.append(ir.GetAttr(rhs, "buffer")) + def get_right(index): + return self.append(ir.GetElem(rhs_buffer, index)) + else: + def get_right(index): + return rhs + def loop_gen(index): - l = self.append(ir.GetElem(lhs_buffer, index)) - r = self.append(ir.GetElem(rhs_buffer, index)) - self.append( - ir.SetElem(result_buffer, index, self.append(ir.Arith(op, l, - r)))) + l = get_left(index) + r = get_right(index) + result = self.append(ir.Arith(op, l, r)) + self.append(ir.SetElem(result_buffer, index, result)) return self.append( ir.Arith(ast.Add(loc=None), index, ir.Constant(1, self._size_type))) @@ -1700,20 +1713,29 @@ class ARTIQIRGenerator(algorithm.Visitor): lhs = self.visit(node.left) rhs = self.visit(node.right) - shape = self.append(ir.GetAttr(lhs, "shape")) - # TODO: Broadcasts; select the widest shape. - rhs_shape = self.append(ir.GetAttr(rhs, "shape")) - self._make_check( - self.append(ir.Compare(ast.Eq(loc=None), shape, rhs_shape)), - lambda: self.alloc_exn( - builtins.TException("ValueError"), - ir.Constant("operands could not be broadcast together", - builtins.TStr()))) + # Broadcast scalars. + broadcast = False + array_arg = lhs + if not builtins.is_array(lhs.type): + broadcast = True + array_arg = rhs + elif not builtins.is_array(rhs.type): + broadcast = True + + shape = self.append(ir.GetAttr(array_arg, "shape")) + + if not broadcast: + rhs_shape = self.append(ir.GetAttr(rhs, "shape")) + self._make_check( + self.append(ir.Compare(ast.Eq(loc=None), shape, rhs_shape)), + lambda: self.alloc_exn( + builtins.TException("ValueError"), + ir.Constant("operands could not be broadcast together", + builtins.TStr()))) + result = self._allocate_new_array(node.type.find()["elt"], shape) - - func = self._get_array_binop(node.op, node.type, node.left.type, node.right.type) + func = self._get_array_binop(node.op, node.type, lhs.type, rhs.type) self._invoke_arrayop(func, [result, lhs, rhs]) - return result elif builtins.is_numeric(node.type): lhs = self.visit(node.left) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 7649682c2..445d64bce 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -480,10 +480,10 @@ class Inferencer(algorithm.Visitor): return typ.find()["num_dims"].value return 0 - # TODO: Broadcasting. left_dims = num_dims(left.type) right_dims = num_dims(right.type) - if left_dims != right_dims: + if left_dims != right_dims and left_dims != 0 and right_dims != 0: + # Mismatch (only scalar broadcast supported for now). note1 = diagnostic.Diagnostic("note", "operand of dimension {num_dims}", {"num_dims": left_dims}, left.loc) note2 = diagnostic.Diagnostic("note", "operand of dimension {num_dims}", @@ -495,16 +495,19 @@ class Inferencer(algorithm.Visitor): return def map_node_type(typ): - if builtins.is_array(typ): - return typ.find()["elt"] - else: - # This is (if later valid) a single value broadcast across the array. + if not builtins.is_array(typ): + # This is a single value broadcast across the array. return typ + return typ.find()["elt"] + # Figure out result type, handling broadcasts. + result_dims = left_dims if left_dims else right_dims def map_return(typ): elt = builtins.TFloat() if isinstance(op, ast.Div) else typ - a = builtins.TArray(elt=elt, num_dims=left_dims) - return (a, a, a) + result = builtins.TArray(elt=elt, num_dims=result_dims) + left = builtins.TArray(elt=elt, num_dims=left_dims) if left_dims else elt + right = builtins.TArray(elt=elt, num_dims=right_dims) if right_dims else elt + return (result, left, right) return self._coerce_numeric((left, right), map_return=map_return, diff --git a/artiq/test/lit/integration/array_broadcast.py b/artiq/test/lit/integration/array_broadcast.py new file mode 100644 index 000000000..d7cbc5998 --- /dev/null +++ b/artiq/test/lit/integration/array_broadcast.py @@ -0,0 +1,55 @@ +# RUN: %python -m artiq.compiler.testbench.jit %s + +a = array([1, 2, 3]) + +c = a + 1 +assert c[0] == 2 +assert c[1] == 3 +assert c[2] == 4 + +c = 1 - a +assert c[0] == 0 +assert c[1] == -1 +assert c[2] == -2 + +c = a * 1 +assert c[0] == 1 +assert c[1] == 2 +assert c[2] == 3 + +c = a // 2 +assert c[0] == 0 +assert c[1] == 1 +assert c[2] == 1 + +c = a ** 2 +assert c[0] == 1 +assert c[1] == 4 +assert c[2] == 9 + +c = 2 ** a +assert c[0] == 2 +assert c[1] == 4 +assert c[2] == 8 + +c = a % 2 +assert c[0] == 1 +assert c[1] == 0 +assert c[2] == 1 + +cf = a / 2 +assert cf[0] == 0.5 +assert cf[1] == 1.0 +assert cf[2] == 1.5 + +cf2 = 2 / array([1, 2, 4]) +assert cf2[0] == 2.0 +assert cf2[1] == 1.0 +assert cf2[2] == 0.5 + +d = array([[1, 2], [3, 4]]) +e = d + 1 +assert e[0][0] == 2 +assert e[0][1] == 3 +assert e[1][0] == 4 +assert e[1][1] == 5 From be7d78253f232350f03bfc83774e0109c2668696 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 2 Aug 2020 23:41:23 +0100 Subject: [PATCH 2262/2457] compiler: Implement 1D-/2D- array transpose Left generic transpose (shape order inversion) for now, as that would be less ugly if we implement forwarding to Python function bodies for array function implementations. Needs a runtime test case. --- artiq/compiler/math_fns.py | 5 +++ .../compiler/transforms/artiq_ir_generator.py | 45 +++++++++++++++++++ artiq/compiler/transforms/inferencer.py | 39 ++++++++++++++++ artiq/test/lit/embedding/array_transpose.py | 22 +++++++++ 4 files changed, 111 insertions(+) create mode 100644 artiq/test/lit/embedding/array_transpose.py diff --git a/artiq/compiler/math_fns.py b/artiq/compiler/math_fns.py index 83c1f82b4..4e67dfef0 100644 --- a/artiq/compiler/math_fns.py +++ b/artiq/compiler/math_fns.py @@ -26,6 +26,9 @@ unary_fp_runtime_calls = [ ("arctan", "atan"), ] +#: Array handling builtins (special treatment due to allocations). +numpy_builtins = ["transpose"] + def unary_fp_type(name): return types.TExternalFunction(OrderedDict([("arg", builtins.TFloat())]), @@ -36,6 +39,8 @@ numpy_map = { getattr(numpy, symbol): unary_fp_type(mangle) for symbol, mangle in (unary_fp_intrinsics + unary_fp_runtime_calls) } +for name in numpy_builtins: + numpy_map[getattr(numpy, name)] = types.TBuiltinFunction("numpy." + name) def match(obj): diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index e148ce184..ab162288d 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -2217,6 +2217,51 @@ class ARTIQIRGenerator(algorithm.Visitor): return result else: assert False + elif types.is_builtin(typ, "numpy.transpose"): + if len(node.args) == 1 and len(node.keywords) == 0: + arg, = map(self.visit, node.args) + + num_dims = arg.type.find()["num_dims"].value + if num_dims == 1: + # No-op as per NumPy semantics. + return arg + assert num_dims == 2 + arg_shape = self.append(ir.GetAttr(arg, "shape")) + dim0 = self.append(ir.GetAttr(arg_shape, 0)) + dim1 = self.append(ir.GetAttr(arg_shape, 1)) + shape = self._make_array_shape([dim1, dim0]) + result = self._allocate_new_array(node.type.find()["elt"], shape) + arg_buffer = self.append(ir.GetAttr(arg, "buffer")) + result_buffer = self.append(ir.GetAttr(result, "buffer")) + + def outer_gen(idx1): + arg_base = self.append(ir.Offset(arg_buffer, idx1)) + result_offset = self.append(ir.Arith(ast.Mult(loc=None), idx1, + dim0)) + result_base = self.append(ir.Offset(result_buffer, result_offset)) + + def inner_gen(idx0): + arg_offset = self.append( + ir.Arith(ast.Mult(loc=None), idx0, dim1)) + val = self.append(ir.GetElem(arg_base, arg_offset)) + self.append(ir.SetElem(result_base, idx0, val)) + return self.append( + ir.Arith(ast.Add(loc=None), idx0, ir.Constant(1, + idx0.type))) + + self._make_loop( + ir.Constant(0, self._size_type), lambda idx0: self.append( + ir.Compare(ast.Lt(loc=None), idx0, dim0)), inner_gen) + return self.append( + ir.Arith(ast.Add(loc=None), idx1, ir.Constant(1, idx1.type))) + + self._make_loop( + ir.Constant(0, self._size_type), + lambda idx1: self.append(ir.Compare(ast.Lt(loc=None), idx1, dim1)), + outer_gen) + return result + else: + assert False elif types.is_builtin(typ, "print"): self.polymorphic_print([self.visit(arg) for arg in node.args], separator=" ", suffix="\n") diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 445d64bce..d017af963 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -1074,6 +1074,45 @@ class Inferencer(algorithm.Visitor): arg1.loc, None) else: diagnose(valid_forms()) + elif types.is_builtin(typ, "numpy.transpose"): + valid_forms = lambda: [ + valid_form("transpose(x: array(elt='a, num_dims=1)) -> array(elt='a, num_dims=1)"), + valid_form("transpose(x: array(elt='a, num_dims=2)) -> array(elt='a, num_dims=2)") + ] + + if len(node.args) == 1 and len(node.keywords) == 0: + arg, = node.args + + if types.is_var(arg.type): + pass # undetermined yet + elif not builtins.is_array(arg.type): + note = diagnostic.Diagnostic( + "note", "this expression has type {type}", + {"type": types.TypePrinter().name(arg.type)}, arg.loc) + diag = diagnostic.Diagnostic( + "error", + "the argument of {builtin}() must be an array", + {"builtin": typ.find().name}, + node.func.loc, + notes=[note]) + self.engine.process(diag) + else: + num_dims = arg.type.find()["num_dims"].value + if num_dims not in (1, 2): + note = diagnostic.Diagnostic( + "note", "argument is {num_dims}-dimensional", + {"num_dims": num_dims}, arg.loc) + diag = diagnostic.Diagnostic( + "error", + "{builtin}() is currently only supported for up to " + "two-dimensional arrays", {"builtin": typ.find().name}, + node.func.loc, + notes=[note]) + self.engine.process(diag) + else: + self._unify(node.type, arg.type, node.loc, None) + else: + diagnose(valid_forms()) elif types.is_builtin(typ, "rtio_log"): valid_forms = lambda: [ valid_form("rtio_log(channel:str, args...) -> None"), diff --git a/artiq/test/lit/embedding/array_transpose.py b/artiq/test/lit/embedding/array_transpose.py new file mode 100644 index 000000000..2ab44bd7d --- /dev/null +++ b/artiq/test/lit/embedding/array_transpose.py @@ -0,0 +1,22 @@ +# RUN: %python -m artiq.compiler.testbench.embedding %s + +from artiq.language.core import * +from artiq.language.types import * +import numpy as np + +@kernel +def entrypoint(): + # FIXME: This needs to be a runtime test (but numpy.* integration is + # currently embedding-only). + a = np.array([1, 2, 3]) + b = np.transpose(a) + assert a.shape == b.shape + for i in range(len(a)): + assert a[i] == b[i] + + c = np.array([[1, 2, 3], [4, 5, 6]]) + d = np.transpose(c) + assert c.shape == d.shape + for i in range(2): + for j in range(3): + assert c[i][j] == d[j][i] From cc00ae95803b5382b5c14fbb3dd2c65104a52345 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 3 Aug 2020 01:29:39 +0100 Subject: [PATCH 2263/2457] compiler: Implement broadcasting of math functions --- artiq/compiler/math_fns.py | 4 +- .../compiler/transforms/artiq_ir_generator.py | 43 ++++++++++++++----- artiq/compiler/transforms/inferencer.py | 10 +++++ artiq/compiler/types.py | 15 ++++++- 4 files changed, 59 insertions(+), 13 deletions(-) diff --git a/artiq/compiler/math_fns.py b/artiq/compiler/math_fns.py index 4e67dfef0..5ae80ea4d 100644 --- a/artiq/compiler/math_fns.py +++ b/artiq/compiler/math_fns.py @@ -32,7 +32,9 @@ numpy_builtins = ["transpose"] def unary_fp_type(name): return types.TExternalFunction(OrderedDict([("arg", builtins.TFloat())]), - builtins.TFloat(), name) + builtins.TFloat(), + name, + broadcast_across_arrays=True) numpy_map = { diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index ab162288d..39731b709 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1335,8 +1335,8 @@ class ARTIQIRGenerator(algorithm.Visitor): ret=builtins.TNone()) env_args = [ir.EnvironmentArgument(self.current_env.type, "ARG.ENV")] - # TODO: What to use for loc? - func = ir.Function(typ, name, env_args + args, loc=None) + old_loc, self.current_loc = self.current_loc, None + func = ir.Function(typ, name, env_args + args) func.is_internal = True func.is_generated = True self.functions.append(func) @@ -1357,7 +1357,7 @@ class ARTIQIRGenerator(algorithm.Visitor): def body_gen(index): a = self.append(ir.GetElem(arg_buffer, index)) self.append( - ir.SetElem(result_buffer, index, self.append(make_op(a)))) + ir.SetElem(result_buffer, index, make_op(a))) return self.append( ir.Arith(ast.Add(loc=None), index, ir.Constant(1, self._size_type))) @@ -1368,6 +1368,7 @@ class ARTIQIRGenerator(algorithm.Visitor): self.append(ir.Return(ir.Constant(None, builtins.TNone()))) return func finally: + self.current_loc = old_loc self.current_function = old_func self.current_block = old_block self.final_branch = old_final_branch @@ -1393,8 +1394,8 @@ class ARTIQIRGenerator(algorithm.Visitor): ir.Constant(-1, operand.type), operand)) elif isinstance(node.op, ast.USub): def make_sub(val): - return ir.Arith(ast.Sub(loc=None), - ir.Constant(0, val.type), val) + return self.append(ir.Arith(ast.Sub(loc=None), + ir.Constant(0, val.type), val)) operand = self.visit(node.operand) if builtins.is_array(operand.type): shape = self.append(ir.GetAttr(operand, "shape")) @@ -1403,7 +1404,7 @@ class ARTIQIRGenerator(algorithm.Visitor): self._invoke_arrayop(func, [result, operand]) return result else: - return self.append(make_sub(operand)) + return make_sub(operand) elif isinstance(node.op, ast.UAdd): # No-op. return self.visit(node.operand) @@ -1419,9 +1420,9 @@ class ARTIQIRGenerator(algorithm.Visitor): result_elt = node.type.find()["elt"] shape = self.append(ir.GetAttr(value, "shape")) result = self._allocate_new_array(result_elt, shape) - func = self._get_array_unaryop("Coerce", - lambda v: ir.Coerce(v, result_elt), - node.type, value.type) + func = self._get_array_unaryop( + "Coerce", lambda v: self.append(ir.Coerce(v, result_elt)), + node.type, value.type) self._invoke_arrayop(func, [result, value]) return result else: @@ -2383,12 +2384,32 @@ class ARTIQIRGenerator(algorithm.Visitor): if types.is_builtin(node.func.type): insn = self.visit_builtin_call(node) + elif (types.is_broadcast_across_arrays(node.func.type) and len(args) >= 1 + and builtins.is_array(args[0].type)): + # The iodelay machinery set up in the surrounding code was + # deprecated/a relic from the past when array broadcasting support + # was added, so no attempt to keep the delay tracking intact is + # made. + assert len(args) == 1, "Broadcasting for multiple arguments not implemented" + + def make_call(val): + return self._user_call(ir.Constant(None, callee.type), [val], {}, + node.arg_exprs) + + shape = self.append(ir.GetAttr(args[0], "shape")) + result = self._allocate_new_array(node.type.find()["elt"], shape) + + # TODO: Generate more generically if non-externals are allowed. + name = node.func.type.find().name + func = self._get_array_unaryop(name, make_call, node.type, args[0].type) + self._invoke_arrayop(func, [result, args[0]]) + insn = result else: insn = self._user_call(callee, args, keywords, node.arg_exprs) - if isinstance(node.func, asttyped.AttributeT): attr_node = node.func - self.method_map[(attr_node.value.type.find(), attr_node.attr)].append(insn) + self.method_map[(attr_node.value.type.find(), + attr_node.attr)].append(insn) if node.iodelay is not None and not iodelay.is_const(node.iodelay, 0): after_delay = self.add_block("delay.tail") diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index d017af963..6b765c2c7 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -1232,6 +1232,16 @@ class Inferencer(algorithm.Visitor): self.engine.process(diag) return + # Array broadcasting for unary functions explicitly marked as such. + if len(node.args) == typ_arity == 1 and types.is_broadcast_across_arrays(typ): + arg_type = node.args[0].type.find() + if builtins.is_array(arg_type): + typ_arg, = typ_args.values() + self._unify(typ_arg, arg_type["elt"], node.args[0].loc, None) + self._unify(node.type, builtins.TArray(typ_ret, arg_type["num_dims"]), + node.loc, None) + return + for actualarg, (formalname, formaltyp) in \ zip(node.args, list(typ_args.items()) + list(typ_optargs.items())): self._unify(actualarg.type, formaltyp, diff --git a/artiq/compiler/types.py b/artiq/compiler/types.py index 281b53577..e7b68a3a4 100644 --- a/artiq/compiler/types.py +++ b/artiq/compiler/types.py @@ -298,11 +298,14 @@ class TExternalFunction(TFunction): Flag ``nounwind`` means the function never raises an exception. Flag ``nowrite`` means the function never writes any memory that the ARTIQ Python code can observe. + :ivar broadcast_across_arrays: (bool) + If True, the function is transparently applied element-wise when called + with TArray arguments. """ attributes = OrderedDict() - def __init__(self, args, ret, name, flags=set()): + def __init__(self, args, ret, name, flags=set(), broadcast_across_arrays=False): assert isinstance(flags, set) for flag in flags: assert flag in {'nounwind', 'nowrite'} @@ -310,6 +313,7 @@ class TExternalFunction(TFunction): self.name = name self.delay = TFixedDelay(iodelay.Const(0)) self.flags = flags + self.broadcast_across_arrays = broadcast_across_arrays def unify(self, other): if other is self: @@ -644,6 +648,15 @@ def is_builtin_function(typ, name=None): return isinstance(typ, TBuiltinFunction) and \ typ.name == name +def is_broadcast_across_arrays(typ): + # For now, broadcasting is only exposed to predefined external functions, and + # statically selected. Might be extended to user-defined functions if the design + # pans out. + typ = typ.find() + if not isinstance(typ, TExternalFunction): + return False + return typ.broadcast_across_arrays + def is_constructor(typ, name=None): typ = typ.find() if name is not None: From df8f1c5c5a8dceb78a915069f4a0620a90f4e7e1 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 3 Aug 2020 01:40:39 +0100 Subject: [PATCH 2264/2457] compiler: Annotate math functions nounwind/nowrite --- artiq/compiler/math_fns.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/compiler/math_fns.py b/artiq/compiler/math_fns.py index 5ae80ea4d..3dfb0c580 100644 --- a/artiq/compiler/math_fns.py +++ b/artiq/compiler/math_fns.py @@ -34,6 +34,8 @@ def unary_fp_type(name): return types.TExternalFunction(OrderedDict([("arg", builtins.TFloat())]), builtins.TFloat(), name, + # errno isn't observable from ARTIQ Python. + flags={"nounwind", "nowrite"}, broadcast_across_arrays=True) From 1c645d8857f27db72fa965b18d45b570aef99a71 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 8 Aug 2020 19:57:46 +0100 Subject: [PATCH 2265/2457] compiler: Unbreak quoting of 1D ndarrays Lists and arrays no longer have the same representation all the way through codegen, as used to be the case. This could/should be made more efficient later, eliding the temporary copies. --- artiq/compiler/embedding.py | 12 +--------- artiq/test/lit/embedding/arrays.py | 35 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 artiq/test/lit/embedding/arrays.py diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index ddacf947f..03be54a94 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -233,17 +233,7 @@ class ASTSynthesizer: begin_loc=begin_loc, end_loc=end_loc, loc=begin_loc.join(end_loc)) elif isinstance(value, numpy.ndarray): - begin_loc = self._add("numpy.array([") - elts = [] - for index, elt in enumerate(value): - elts.append(self.quote(elt)) - if index < len(value) - 1: - self._add(", ") - end_loc = self._add("])") - - return asttyped.ListT(elts=elts, ctx=None, type=builtins.TArray(), - begin_loc=begin_loc, end_loc=end_loc, - loc=begin_loc.join(end_loc)) + return self.call(numpy.array, [list(value)], {}) elif inspect.isfunction(value) or inspect.ismethod(value) or \ isinstance(value, pytypes.BuiltinFunctionType) or \ isinstance(value, SpecializedFunction) or \ diff --git a/artiq/test/lit/embedding/arrays.py b/artiq/test/lit/embedding/arrays.py new file mode 100644 index 000000000..3a2c226b9 --- /dev/null +++ b/artiq/test/lit/embedding/arrays.py @@ -0,0 +1,35 @@ +# RUN: %python -m artiq.compiler.testbench.embedding %s + +from artiq.language.core import * +from artiq.language.types import * +from numpy import array + +int_vec = array([1, 2, 3]) +float_vec = array([1.0, 2.0, 3.0]) +int_mat = array([[1, 2], [3, 4]]) +float_mat = array([[1.0, 2.0], [3.0, 4.0]]) + + +@kernel +def entrypoint(): + assert int_vec.shape == (3, ) + assert int_vec[0] == 1 + assert int_vec[1] == 2 + assert int_vec[2] == 3 + + assert float_vec.shape == (3, ) + assert float_vec[0] == 1.0 + assert float_vec[1] == 2.0 + assert float_vec[2] == 3.0 + + # assert int_mat.shape == (2, 2) + # assert int_mat[0][0] == 1 + # assert int_mat[0][1] == 2 + # assert int_mat[1][0] == 3 + # assert int_mat[1][1] == 4 + + # assert float_mat.shape == (2, 2) + # assert float_mat[0][0] == 1.0 + # assert float_mat[0][1] == 2.0 + # assert float_mat[1][0] == 3.0 + # assert float_mat[1][1] == 4.0 From 8eddb9194a5fbd29aee79992630e5b7fe3c3bea3 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 8 Aug 2020 21:08:47 +0100 Subject: [PATCH 2266/2457] test/lit: Add smoke test for math function broadcasting --- artiq/test/lit/embedding/array_math_fns.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 artiq/test/lit/embedding/array_math_fns.py diff --git a/artiq/test/lit/embedding/array_math_fns.py b/artiq/test/lit/embedding/array_math_fns.py new file mode 100644 index 000000000..2b298f2ef --- /dev/null +++ b/artiq/test/lit/embedding/array_math_fns.py @@ -0,0 +1,15 @@ +# RUN: %python -m artiq.compiler.testbench.embedding %s + +from artiq.language.core import * +import numpy as np + +@kernel +def entrypoint(): + # Just make sure everything compiles. + a = np.array([1.0, 2.0, 3.0]) + b = np.sin(a) + assert b.shape == a.shape + + c = np.array([1.0, 2.0, 3.0]) + d = np.arctan(c) + assert d.shape == c.shape From 5472e830f6a7fae2b3fcd8140870692bebf9a7f8 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 8 Aug 2020 20:35:04 +0100 Subject: [PATCH 2267/2457] compiler: Assume array()s are always rectangular --- .../compiler/transforms/artiq_ir_generator.py | 63 +++++++-------- artiq/compiler/transforms/inferencer.py | 77 ++++++++----------- artiq/test/lit/embedding/arrays.py | 21 ++--- artiq/test/lit/inferencer/array.py | 7 +- artiq/test/lit/integration/array.py | 9 +-- 5 files changed, 86 insertions(+), 91 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 39731b709..240dd4957 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1561,9 +1561,8 @@ class ARTIQIRGenerator(algorithm.Visitor): self.current_block = after_invoke def _get_array_offset(self, shape, indices): - last_stride = None result = indices[0] - for dim, index in zip(shape[:-1], indices[1:]): + for dim, index in zip(shape[1:], indices[1:]): result = self.append(ir.Arith(ast.Mult(loc=None), result, dim)) result = self.append(ir.Arith(ast.Add(loc=None), result, index)) return result @@ -2090,9 +2089,8 @@ class ARTIQIRGenerator(algorithm.Visitor): result_elt = result_type["elt"].find() num_dims = result_type["num_dims"].value - # Derive shape from first element on each level (currently, type - # inference make sure arrays are always rectangular; in the future, we - # might want to insert a runtime check here). + # Derive shape from first element on each level (and fail later if the + # array is in fact jagged). first_elt = None lengths = [] for dim_idx in range(num_dims): @@ -2110,32 +2108,37 @@ class ARTIQIRGenerator(algorithm.Visitor): buffer = self.append( ir.Alloc([num_total_elts], result_type.attributes["buffer"])) - def body_gen(index): - # TODO: This is hilariously inefficient; we really want to emit a - # nested loop for the source and keep one running index for the - # target buffer. - indices = [] - mod_idx = index - for dim_idx in reversed(range(1, num_dims)): - dim_len = self.append(ir.GetAttr(shape, dim_idx)) - indices.append( - self.append(ir.Arith(ast.Mod(loc=None), mod_idx, dim_len))) - mod_idx = self.append( - ir.Arith(ast.FloorDiv(loc=None), mod_idx, dim_len)) - indices.append(mod_idx) - - elt = arg - for idx in reversed(indices): - elt = self.iterable_get(elt, idx) - self.append(ir.SetElem(buffer, index, elt)) - return self.append( - ir.Arith(ast.Add(loc=None), index, - ir.Constant(1, self._size_type))) - - self._make_loop( - ir.Constant(0, self._size_type), lambda index: self.append( - ir.Compare(ast.Lt(loc=None), index, num_total_elts)), body_gen) + def assign_elems(outer_indices, indexed_arg): + if len(outer_indices) == num_dims: + dest_idx = self._get_array_offset(lengths, outer_indices) + self.append(ir.SetElem(buffer, dest_idx, indexed_arg)) + else: + this_level_len = self.iterable_len(indexed_arg) + dim_idx = len(outer_indices) + if dim_idx > 0: + # Check for rectangularity (outermost index is never jagged, + # by definition). + result_len = self.append(ir.GetAttr(shape, dim_idx)) + self._make_check( + self.append(ir.Compare(ast.Eq(loc=None), this_level_len, result_len)), + lambda a, b: self.alloc_exn( + builtins.TException("ValueError"), + ir.Constant( + "arrays must be rectangular (lengths were {0} vs. {1})", + builtins.TStr()), a, b), + params=[this_level_len, result_len], + loc=node.loc) + def body_gen(index): + elem = self.iterable_get(indexed_arg, index) + assign_elems(outer_indices + [index], elem) + return self.append( + ir.Arith(ast.Add(loc=None), index, + ir.Constant(1, self._size_type))) + self._make_loop( + ir.Constant(0, self._size_type), lambda index: self.append( + ir.Compare(ast.Lt(loc=None), index, this_level_len)), body_gen) + assign_elems([], arg) return self.append(ir.Alloc([buffer, shape], node.type)) else: assert False diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 6b765c2c7..ef982c3ce 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -8,30 +8,6 @@ from .. import asttyped, types, builtins from .typedtree_printer import TypedtreePrinter -def match_rectangular_list(elts): - num_elts = None - elt_type = None - all_child_elts = [] - - for e in elts: - if elt_type is None: - elt_type = e.type.find() - if not isinstance(e, asttyped.ListT): - return elt_type, 0 - if num_elts is None: - num_elts = len(e.elts) - elif num_elts != len(e.elts): - return elt_type, 0 - all_child_elts += e.elts - - if not all_child_elts: - # This ultimately turned out to be a list (of list, of ...) of empty lists. - return elt_type["elt"], 1 - - elt, num_dims = match_rectangular_list(all_child_elts) - return elt, num_dims + 1 - - class Inferencer(algorithm.Visitor): """ :class:`Inferencer` infers types by recursively applying the unification @@ -862,29 +838,42 @@ class Inferencer(algorithm.Visitor): if len(node.args) == 1 and len(node.keywords) == 0: arg, = node.args - if builtins.is_iterable(arg.type): - # KLUDGE: Support multidimensional arary creation if lexically - # specified as a rectangular array of lists. - elt, num_dims = match_rectangular_list([arg]) - if num_dims == 0: - # Not given as a list, so just default to 1 dimension. - elt = builtins.get_iterable_elt(arg.type) - num_dims = 1 - self._unify(node.type, - builtins.TArray(elt, types.TValue(num_dims)), - node.loc, arg.loc) - elif types.is_var(arg.type): - pass # undetermined yet - else: - note = diagnostic.Diagnostic("note", - "this expression has type {type}", - {"type": types.TypePrinter().name(arg.type)}, - arg.loc) - diag = diagnostic.Diagnostic("error", + # In the absence of any other information (there currently isn't a way + # to specify any), assume that all iterables are expandable into a + # (runtime-checked) rectangular array of the innermost element type. + elt = arg.type + num_dims = 0 + result_dims = (node.type.find()["num_dims"].value + if builtins.is_array(node.type) else -1) + while True: + if num_dims == result_dims: + # If we already know the number of dimensions of the result, + # stop so we can disambiguate the (innermost) element type of + # the argument if it is still unknown (e.g. empty array). + break + if types.is_var(elt): + return # undetermined yet + if not builtins.is_iterable(elt): + break + num_dims += 1 + elt = builtins.get_iterable_elt(elt) + + if num_dims == 0: + note = diagnostic.Diagnostic( + "note", "this expression has type {type}", + {"type": types.TypePrinter().name(arg.type)}, arg.loc) + diag = diagnostic.Diagnostic( + "error", "the argument of {builtin}() must be of an iterable type", {"builtin": typ.find().name}, - node.func.loc, notes=[note]) + node.func.loc, + notes=[note]) self.engine.process(diag) + return + + self._unify(node.type, + builtins.TArray(elt, types.TValue(num_dims)), + node.loc, arg.loc) else: diagnose(valid_forms()) elif types.is_builtin(typ, "list"): diff --git a/artiq/test/lit/embedding/arrays.py b/artiq/test/lit/embedding/arrays.py index 3a2c226b9..63d846585 100644 --- a/artiq/test/lit/embedding/arrays.py +++ b/artiq/test/lit/embedding/arrays.py @@ -12,6 +12,7 @@ float_mat = array([[1.0, 2.0], [3.0, 4.0]]) @kernel def entrypoint(): + # TODO: These need to be runtime tests! assert int_vec.shape == (3, ) assert int_vec[0] == 1 assert int_vec[1] == 2 @@ -22,14 +23,14 @@ def entrypoint(): assert float_vec[1] == 2.0 assert float_vec[2] == 3.0 - # assert int_mat.shape == (2, 2) - # assert int_mat[0][0] == 1 - # assert int_mat[0][1] == 2 - # assert int_mat[1][0] == 3 - # assert int_mat[1][1] == 4 + assert int_mat.shape == (2, 2) + assert int_mat[0][0] == 1 + assert int_mat[0][1] == 2 + assert int_mat[1][0] == 3 + assert int_mat[1][1] == 4 - # assert float_mat.shape == (2, 2) - # assert float_mat[0][0] == 1.0 - # assert float_mat[0][1] == 2.0 - # assert float_mat[1][0] == 3.0 - # assert float_mat[1][1] == 4.0 + assert float_mat.shape == (2, 2) + assert float_mat[0][0] == 1.0 + assert float_mat[0][1] == 2.0 + assert float_mat[1][0] == 3.0 + assert float_mat[1][1] == 4.0 diff --git a/artiq/test/lit/inferencer/array.py b/artiq/test/lit/inferencer/array.py index f33040f92..e3e00a254 100644 --- a/artiq/test/lit/inferencer/array.py +++ b/artiq/test/lit/inferencer/array.py @@ -1,7 +1,9 @@ # RUN: %python -m artiq.compiler.testbench.inferencer %s >%t # RUN: OutputCheck %s --file-to-check=%t -# CHECK-L: numpy.array(elt='a, num_dims=1) +# Nothing known, as there could be several more dimensions +# hidden from view by the array being empty. +# CHECK-L: ([]:list(elt='a)):'b array([]) # CHECK-L: numpy.array(elt=numpy.int?, num_dims=1) @@ -9,5 +11,6 @@ array([1, 2, 3]) # CHECK-L: numpy.array(elt=numpy.int?, num_dims=2) array([[1, 2, 3], [4, 5, 6]]) -# CHECK-L: numpy.array(elt=list(elt=numpy.int?), num_dims=1) +# Jagged arrays produce runtime failure: +# CHECK-L: numpy.array(elt=numpy.int?, num_dims=2) array([[1, 2, 3], [4, 5]]) diff --git a/artiq/test/lit/integration/array.py b/artiq/test/lit/integration/array.py index 05785889d..8f97c4002 100644 --- a/artiq/test/lit/integration/array.py +++ b/artiq/test/lit/integration/array.py @@ -13,13 +13,12 @@ assert len(empty_array) == 0 assert empty_array.shape == (0,) assert [x * x for x in empty_array] == [] -# Creating a list from a generic iterable always generates an 1D array, as we can't -# check for rectangularity at compile time. (This could be changed to *assume* -# rectangularity and insert runtime checks instead.) +# Creating arrays from generic iterables, rectangularity is assumed (and ensured +# with runtime checks). list_of_lists = [[1, 2], [3, 4]] array_of_lists = array(list_of_lists) -assert array_of_lists.shape == (2,) -assert [x for x in array_of_lists] == list_of_lists +assert array_of_lists.shape == (2, 2) +assert [[y for y in x] for x in array_of_lists] == list_of_lists matrix = array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) assert len(matrix) == 2 From 8783ba207214d52c67fa9c2236250b20319befdb Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 8 Aug 2020 22:34:46 +0100 Subject: [PATCH 2268/2457] compiler/firmware: RPCs for ndarrays --- artiq/compiler/ir.py | 3 +- artiq/coredevice/comm_kernel.py | 18 ++++++- artiq/firmware/libproto_artiq/rpc_proto.rs | 58 +++++++++++++++++++--- artiq/test/coredevice/test_embedding.py | 32 ++++++++++-- 4 files changed, 97 insertions(+), 14 deletions(-) diff --git a/artiq/compiler/ir.py b/artiq/compiler/ir.py index 941b04d36..3f984606f 100644 --- a/artiq/compiler/ir.py +++ b/artiq/compiler/ir.py @@ -64,7 +64,8 @@ def rpc_tag(typ, error_handler): elif builtins.is_list(typ): return b"l" + rpc_tag(builtins.get_iterable_elt(typ), error_handler) elif builtins.is_array(typ): - return b"a" + rpc_tag(builtins.get_iterable_elt(typ), error_handler) + num_dims = typ["num_dims"].value + return b"a" + bytes([num_dims]) + rpc_tag(typ["elt"], error_handler) elif builtins.is_range(typ): return b"r" + rpc_tag(builtins.get_iterable_elt(typ), error_handler) elif is_keyword(typ): diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 838bad042..41bddd553 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -276,8 +276,10 @@ class CommKernel: length = self._read_int32() return [self._receive_rpc_value(embedding_map) for _ in range(length)] elif tag == "a": - length = self._read_int32() - return numpy.array([self._receive_rpc_value(embedding_map) for _ in range(length)]) + num_dims = self._read_int8() + shape = tuple(self._read_int32() for _ in range(num_dims)) + elems = [self._receive_rpc_value(embedding_map) for _ in range(numpy.prod(shape))] + return numpy.array(elems).reshape(shape) elif tag == "r": start = self._receive_rpc_value(embedding_map) stop = self._receive_rpc_value(embedding_map) @@ -380,6 +382,18 @@ class CommKernel: tags_copy = bytearray(tags) self._send_rpc_value(tags_copy, elt, root, function) self._skip_rpc_value(tags) + elif tag == "a": + check(isinstance(value, numpy.ndarray), + lambda: "numpy.ndarray") + num_dims = tags.pop(0) + check(num_dims == len(value.shape), + lambda: "{}-dimensional numpy.ndarray".format(num_dims)) + for s in value.shape: + self._write_int32(s) + for elt in value.reshape((-1,), order="C"): + tags_copy = bytearray(tags) + self._send_rpc_value(tags_copy, elt, root, function) + self._skip_rpc_value(tags) elif tag == "r": check(isinstance(value, range), lambda: "range") diff --git a/artiq/firmware/libproto_artiq/rpc_proto.rs b/artiq/firmware/libproto_artiq/rpc_proto.rs index 750f3f467..b35e6b905 100644 --- a/artiq/firmware/libproto_artiq/rpc_proto.rs +++ b/artiq/firmware/libproto_artiq/rpc_proto.rs @@ -48,7 +48,7 @@ unsafe fn recv_value(reader: &mut R, tag: Tag, data: &mut *mut (), } Ok(()) } - Tag::List(it) | Tag::Array(it) => { + Tag::List(it) => { #[repr(C)] struct List { elements: *mut (), length: u32 }; consume_value!(List, |ptr| { @@ -64,6 +64,25 @@ unsafe fn recv_value(reader: &mut R, tag: Tag, data: &mut *mut (), Ok(()) }) } + Tag::Array(it, num_dims) => { + consume_value!(*mut (), |buffer| { + let mut total_len: u32 = 1; + for _ in 0..num_dims { + let len = reader.read_u32()?; + total_len *= len; + consume_value!(u32, |ptr| *ptr = len ) + } + + let elt_tag = it.clone().next().expect("truncated tag"); + *buffer = alloc(elt_tag.size() * total_len as usize)?; + + let mut data = *buffer; + for _ in 0..total_len { + recv_value(reader, elt_tag, &mut data, alloc)? + } + Ok(()) + }) + } Tag::Range(it) => { let tag = it.clone().next().expect("truncated tag"); recv_value(reader, tag, data, alloc)?; @@ -132,7 +151,7 @@ unsafe fn send_value(writer: &mut W, tag: Tag, data: &mut *const ()) } Ok(()) } - Tag::List(it) | Tag::Array(it) => { + Tag::List(it) => { #[repr(C)] struct List { elements: *const (), length: u32 }; consume_value!(List, |ptr| { @@ -145,6 +164,25 @@ unsafe fn send_value(writer: &mut W, tag: Tag, data: &mut *const ()) Ok(()) }) } + Tag::Array(it, num_dims) => { + writer.write_u8(num_dims)?; + consume_value!(*const(), |buffer| { + let elt_tag = it.clone().next().expect("truncated tag"); + + let mut total_len = 1; + for _ in 0..num_dims { + consume_value!(u32, |len| { + writer.write_u32(*len)?; + total_len *= *len; + }) + } + let mut data = *buffer; + for _ in 0..total_len as usize { + send_value(writer, elt_tag, &mut data)?; + } + Ok(()) + }) + } Tag::Range(it) => { let tag = it.clone().next().expect("truncated tag"); send_value(writer, tag, data)?; @@ -226,7 +264,7 @@ mod tag { ByteArray, Tuple(TagIterator<'a>, u8), List(TagIterator<'a>), - Array(TagIterator<'a>), + Array(TagIterator<'a>, u8), Range(TagIterator<'a>), Keyword(TagIterator<'a>), Object @@ -245,7 +283,7 @@ mod tag { Tag::ByteArray => b'A', Tag::Tuple(_, _) => b't', Tag::List(_) => b'l', - Tag::Array(_) => b'a', + Tag::Array(_, _) => b'a', Tag::Range(_) => b'r', Tag::Keyword(_) => b'k', Tag::Object => b'O', @@ -272,7 +310,7 @@ mod tag { size } Tag::List(_) => 8, - Tag::Array(_) => 8, + Tag::Array(_, num_dims) => 4 * (1 + num_dims as usize), Tag::Range(it) => { let tag = it.clone().next().expect("truncated tag"); tag.size() * 3 @@ -315,7 +353,11 @@ mod tag { Tag::Tuple(self.sub(count), count) } b'l' => Tag::List(self.sub(1)), - b'a' => Tag::Array(self.sub(1)), + b'a' => { + let count = self.data[0]; + self.data = &self.data[1..]; + Tag::Array(self.sub(1), count) + } b'r' => Tag::Range(self.sub(1)), b'k' => Tag::Keyword(self.sub(1)), b'O' => Tag::Object, @@ -370,10 +412,10 @@ mod tag { it.fmt(f)?; write!(f, ")")?; } - Tag::Array(it) => { + Tag::Array(it, num_dims) => { write!(f, "Array(")?; it.fmt(f)?; - write!(f, ")")?; + write!(f, ", {})", num_dims)?; } Tag::Range(it) => { write!(f, "Range(")?; diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 38e1a3d07..fbd47a1a4 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -22,6 +22,12 @@ class RoundtripTest(ExperimentCase): self.assertEqual(obj, objcopy) exp.roundtrip(obj, callback) + def assertArrayRoundtrip(self, obj): + exp = self.create(_Roundtrip) + def callback(objcopy): + numpy.testing.assert_array_equal(obj, objcopy) + exp.roundtrip(obj, callback) + def test_None(self): self.assertRoundtrip(None) @@ -48,9 +54,6 @@ class RoundtripTest(ExperimentCase): def test_list(self): self.assertRoundtrip([10]) - def test_array(self): - self.assertRoundtrip(numpy.array([10])) - def test_object(self): obj = object() self.assertRoundtrip(obj) @@ -64,6 +67,19 @@ class RoundtripTest(ExperimentCase): def test_list_mixed_tuple(self): self.assertRoundtrip([(0x12345678, [("foo", [0.0, 1.0], [0, 1])])]) + def test_array_1d(self): + self.assertArrayRoundtrip(numpy.array([1, 2, 3], dtype=numpy.int32)) + self.assertArrayRoundtrip(numpy.array([1.0, 2.0, 3.0])) + self.assertArrayRoundtrip(numpy.array(["a", "b", "c"])) + + def test_array_2d(self): + self.assertArrayRoundtrip(numpy.array([[1, 2], [3, 4]], dtype=numpy.int32)) + self.assertArrayRoundtrip(numpy.array([[1.0, 2.0], [3.0, 4.0]])) + self.assertArrayRoundtrip(numpy.array([["a", "b"], ["c", "d"]])) + + def test_array_jagged(self): + self.assertArrayRoundtrip(numpy.array([[1, 2], [3]])) + class _DefaultArg(EnvExperiment): def build(self): @@ -117,6 +133,12 @@ class _RPCTypes(EnvExperiment): def return_range(self) -> TRange32: return range(10) + def return_array(self) -> TArray(TInt32): + return numpy.array([1, 2]) + + def return_matrix(self) -> TArray(TInt32, 2): + return numpy.array([[1, 2], [3, 4]]) + def return_mismatch(self): return b"foo" @@ -132,6 +154,8 @@ class _RPCTypes(EnvExperiment): core_log(self.return_tuple()) core_log(self.return_list()) core_log(self.return_range()) + core_log(self.return_array()) + core_log(self.return_matrix()) def accept(self, value): pass @@ -150,6 +174,8 @@ class _RPCTypes(EnvExperiment): self.accept((2, 3)) self.accept([1, 2]) self.accept(range(10)) + self.accept(numpy.array([1, 2])) + self.accept(numpy.array([[1, 2], [3, 4]])) self.accept(self) @kernel From ad34df3de1e73926c8de0a3fbeaba5299ba34896 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 9 Aug 2020 02:43:37 +0100 Subject: [PATCH 2269/2457] compiler: Support numpy.float This would previously crash the compiler. --- artiq/compiler/embedding.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index 03be54a94..c327392f8 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -166,6 +166,10 @@ class ASTSynthesizer: typ = builtins.TBool() return asttyped.NameConstantT(value=value, type=typ, loc=self._add(repr(value))) + elif value is numpy.float: + typ = builtins.fn_float() + return asttyped.NameConstantT(value=None, type=typ, + loc=self._add("numpy.float")) elif value is numpy.int32: typ = builtins.fn_int32() return asttyped.NameConstantT(value=None, type=typ, From b00ba5ece11cf1c04306621d24523ece794a0c41 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 9 Aug 2020 02:44:54 +0100 Subject: [PATCH 2270/2457] =?UTF-8?q?compiler:=20Support=20explicit=20arra?= =?UTF-8?q?y(=E2=80=A6,=20dtype=3D=E2=80=A6)=20syntax?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compiler/transforms/artiq_ir_generator.py | 5 +-- artiq/compiler/transforms/inferencer.py | 33 +++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 240dd4957..9d5201800 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -2082,7 +2082,7 @@ class ARTIQIRGenerator(algorithm.Visitor): else: assert False elif types.is_builtin(typ, "array"): - if len(node.args) == 1 and len(node.keywords) == 0: + if len(node.args) == 1 and len(node.keywords) in (0, 1): result_type = node.type.find() arg = self.visit(node.args[0]) @@ -2111,7 +2111,8 @@ class ARTIQIRGenerator(algorithm.Visitor): def assign_elems(outer_indices, indexed_arg): if len(outer_indices) == num_dims: dest_idx = self._get_array_offset(lengths, outer_indices) - self.append(ir.SetElem(buffer, dest_idx, indexed_arg)) + coerced = self.append(ir.Coerce(indexed_arg, result_elt)) + self.append(ir.SetElem(buffer, dest_idx, coerced)) else: this_level_len = self.iterable_len(indexed_arg) dim_idx = len(outer_indices) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index ef982c3ce..8ac5fab15 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -832,10 +832,19 @@ class Inferencer(algorithm.Visitor): self.engine.process(diag) elif types.is_builtin(typ, "array"): valid_forms = lambda: [ - valid_form("array(x:'a) -> array(elt='b) where 'a is iterable") + valid_form("array(x:'a) -> array(elt='b) where 'a is iterable"), + valid_form("array(x:'a, dtype:'b) -> array(elt='b) where 'a is iterable") ] - if len(node.args) == 1 and len(node.keywords) == 0: + explicit_dtype = None + keywords_acceptable = False + if len(node.keywords) == 0: + keywords_acceptable = True + elif len(node.keywords) == 1: + if node.keywords[0].arg == "dtype": + keywords_acceptable = True + explicit_dtype = node.keywords[0].value + if len(node.args) == 1 and keywords_acceptable: arg, = node.args # In the absence of any other information (there currently isn't a way @@ -858,6 +867,26 @@ class Inferencer(algorithm.Visitor): num_dims += 1 elt = builtins.get_iterable_elt(elt) + if explicit_dtype is not None: + # TODO: Factor out type detection; support quoted type constructors + # (TList(TInt32), …)? + typ = explicit_dtype.type + if types.is_builtin(typ, "int32"): + elt = builtins.TInt32() + elif types.is_builtin(typ, "int64"): + elt = builtins.TInt64() + elif types.is_constructor(typ): + elt = typ.find().instance + else: + diag = diagnostic.Diagnostic( + "error", + "dtype argument of {builtin}() must be a valid constructor", + {"builtin": typ.find().name}, + node.func.loc, + notes=[note]) + self.engine.process(diag) + return + if num_dims == 0: note = diagnostic.Diagnostic( "note", "this expression has type {type}", From 33d931a5b7c457a627117a5e1bbf3c0603732c65 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 9 Aug 2020 03:28:36 +0100 Subject: [PATCH 2271/2457] compiler: Implement multi-dimensional indexing of arrays This generates rather more code than necessary, but has the advantage of automatically handling incomplete multi-dimensional subscripts which still leave arrays behind. --- .../compiler/transforms/artiq_ir_generator.py | 33 ++++++++++---- artiq/compiler/transforms/inferencer.py | 44 +++++++++++++++---- artiq/test/lit/inferencer/error_array.py | 4 ++ artiq/test/lit/integration/array.py | 28 ++++++------ 4 files changed, 77 insertions(+), 32 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 9d5201800..ac916f984 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1092,16 +1092,31 @@ class ARTIQIRGenerator(algorithm.Visitor): finally: self.current_assign = old_assign - length = self.iterable_len(value, index.type) - mapped_index = self._map_index(length, index, - loc=node.begin_loc) - if self.current_assign is None: - result = self.iterable_get(value, mapped_index) - result.set_name("{}.at.{}".format(value.name, _readable_name(index))) - return result + # For multi-dimensional indexes, just apply them sequentially. This + # works, as they are only supported for types where we do not + # immediately need to distinguish between the Get and Set cases + # (i.e. arrays, which are reference types). + if types.is_tuple(index.type): + num_idxs = len(index.type.find().elts) + indices = [ + self.append(ir.GetAttr(index, i)) for i in range(num_idxs) + ] else: - self.append(ir.SetElem(value, mapped_index, self.current_assign, - name="{}.at.{}".format(value.name, _readable_name(index)))) + indices = [index] + indexed = value + for i, idx in enumerate(indices): + length = self.iterable_len(indexed, idx.type) + mapped_index = self._map_index(length, idx, loc=node.begin_loc) + if self.current_assign is None or i < len(indices) - 1: + indexed = self.iterable_get(indexed, mapped_index) + indexed.set_name("{}.at.{}".format(indexed.name, + _readable_name(idx))) + else: + self.append(ir.SetElem(indexed, mapped_index, self.current_assign, + name="{}.at.{}".format(value.name, + _readable_name(index)))) + if self.current_assign is None: + return indexed else: # Slice length = self.iterable_len(value, node.slice.type) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 8ac5fab15..172dfb1fe 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -208,10 +208,9 @@ class Inferencer(algorithm.Visitor): self.generic_visit(node) value = node.value if types.is_tuple(value.type): - diag = diagnostic.Diagnostic("error", - "multi-dimensional slices are not supported", {}, - node.loc, []) - self.engine.process(diag) + for elt in value.type.find().elts: + self._unify(elt, builtins.TInt(), + value.loc, None) else: self._unify(value.type, builtins.TInt(), value.loc, None) @@ -237,12 +236,39 @@ class Inferencer(algorithm.Visitor): def visit_SubscriptT(self, node): self.generic_visit(node) if isinstance(node.slice, ast.Index): - self._unify_iterable(element=node, collection=node.value) + if types.is_tuple(node.slice.value.type): + if not builtins.is_array(node.value.type): + diag = diagnostic.Diagnostic( + "error", + "multi-dimensional slices only supported for arrays, not {type}", + {"type": types.TypePrinter().name(node.value.type)}, + node.loc, []) + self.engine.process(diag) + return + num_idxs = len(node.slice.value.type.find().elts) + array_type = node.value.type.find() + num_dims = array_type["num_dims"].value + remaining_dims = num_dims - num_idxs + if remaining_dims < 0: + diag = diagnostic.Diagnostic( + "error", + "too many indices for array of dimension {num_dims}", + {"num_dims": num_dims}, node.slice.loc, []) + self.engine.process(diag) + return + if remaining_dims == 0: + self._unify(node.type, array_type["elt"], node.loc, + node.value.loc) + else: + self._unify( + node.type, + builtins.TArray(array_type["elt"], remaining_dims)) + else: + self._unify_iterable(element=node, collection=node.value) elif isinstance(node.slice, ast.Slice): - self._unify(node.type, node.value.type, - node.loc, node.value.loc) - else: # ExtSlice - pass # error emitted above + self._unify(node.type, node.value.type, node.loc, node.value.loc) + else: # ExtSlice + pass # error emitted above def visit_IfExpT(self, node): self.generic_visit(node) diff --git a/artiq/test/lit/inferencer/error_array.py b/artiq/test/lit/inferencer/error_array.py index 787ae9294..5e79f99e6 100644 --- a/artiq/test/lit/inferencer/error_array.py +++ b/artiq/test/lit/inferencer/error_array.py @@ -5,5 +5,9 @@ a = array() b = array([1, 2, 3]) + +# CHECK-L: ${LINE:+1}: error: too many indices for array of dimension 1 +b[1, 2] + # CHECK-L: ${LINE:+1}: error: array attributes cannot be assigned to b.shape = (5, ) diff --git a/artiq/test/lit/integration/array.py b/artiq/test/lit/integration/array.py index 8f97c4002..039e76372 100644 --- a/artiq/test/lit/integration/array.py +++ b/artiq/test/lit/integration/array.py @@ -26,21 +26,21 @@ assert matrix.shape == (2, 3) # FIXME: Need to decide on a solution for array comparisons — # NumPy returns an array of bools! # assert [x for x in matrix] == [array([1.0, 2.0, 3.0]), array([4.0, 5.0, 6.0])] -assert matrix[0][0] == 1.0 -assert matrix[0][1] == 2.0 -assert matrix[0][2] == 3.0 -assert matrix[1][0] == 4.0 -assert matrix[1][1] == 5.0 -assert matrix[1][2] == 6.0 +assert matrix[0, 0] == 1.0 +assert matrix[0, 1] == 2.0 +assert matrix[0, 2] == 3.0 +assert matrix[1, 0] == 4.0 +assert matrix[1, 1] == 5.0 +assert matrix[1, 2] == 6.0 -matrix[0][0] = 7.0 -matrix[1][1] = 8.0 -assert matrix[0][0] == 7.0 -assert matrix[0][1] == 2.0 -assert matrix[0][2] == 3.0 -assert matrix[1][0] == 4.0 -assert matrix[1][1] == 8.0 -assert matrix[1][2] == 6.0 +matrix[0, 0] = 7.0 +matrix[1, 1] = 8.0 +assert matrix[0, 0] == 7.0 +assert matrix[0, 1] == 2.0 +assert matrix[0, 2] == 3.0 +assert matrix[1, 0] == 4.0 +assert matrix[1, 1] == 8.0 +assert matrix[1, 2] == 6.0 three_tensor = array([[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]]) assert len(three_tensor) == 1 From 8e262acd1e7e0167a60d2390d29868035260b54d Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 9 Aug 2020 17:03:56 +0100 Subject: [PATCH 2272/2457] compiler: Slight array op implementation cleanup [nfc] array_unaryop_funcs was never used; since the mangled names are unique, a single dictionary would be nicer for overrides anyway.s --- .../compiler/transforms/artiq_ir_generator.py | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index ac916f984..ac06f8717 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -88,10 +88,8 @@ class ARTIQIRGenerator(algorithm.Visitor): necessary. They are kept track of in global dictionaries, with a mangled name containing types and operations as key: - :ivar array_unaryop_funcs: the map from mangled name to implementation of unary - operations for arrays - :ivar array_binop_funcs: the map from mangled name to implementation of binary - operations between arrays + :ivar array_op_funcs: the map from mangled name to implementation of + operations on/between arrays """ _size_type = builtins.TInt32() @@ -120,8 +118,7 @@ class ARTIQIRGenerator(algorithm.Visitor): self.function_map = dict() self.variable_map = dict() self.method_map = defaultdict(lambda: []) - self.array_unaryop_funcs = dict() - self.array_binop_funcs = dict() + self.array_op_funcs = dict() def annotate_calls(self, devirtualization): for var_node in devirtualization.variable_map: @@ -1392,10 +1389,10 @@ class ARTIQIRGenerator(algorithm.Visitor): def _get_array_unaryop(self, name, make_op, result_type, arg_type): name = "_array_{}_{}".format( name, self._mangle_arrayop_types([result_type, arg_type])) - if name not in self.array_unaryop_funcs: - self.array_binop_funcs[name] = self._make_array_unaryop( + if name not in self.array_op_funcs: + self.array_op_funcs[name] = self._make_array_unaryop( name, make_op, result_type, arg_type) - return self.array_binop_funcs[name] + return self.array_op_funcs[name] def visit_UnaryOpT(self, node): if isinstance(node.op, ast.Not): @@ -1523,7 +1520,7 @@ class ARTIQIRGenerator(algorithm.Visitor): name = "_array_{}_{}".format( type(op).__name__, self._mangle_arrayop_types([result_type, lhs_type, rhs_type])) - if name not in self.array_binop_funcs: + if name not in self.array_op_funcs: def body_gen(result, lhs, rhs): # At this point, shapes are assumed to match; could just pass buffer @@ -1561,9 +1558,9 @@ class ARTIQIRGenerator(algorithm.Visitor): ir.Constant(0, self._size_type), lambda index: self.append( ir.Compare(ast.Lt(loc=None), index, num_total_elts)), loop_gen) - self.array_binop_funcs[name] = self._make_array_binop( + self.array_op_funcs[name] = self._make_array_binop( name, result_type, lhs_type, rhs_type, body_gen) - return self.array_binop_funcs[name] + return self.array_op_funcs[name] def _invoke_arrayop(self, func, params): closure = self.append( @@ -1585,7 +1582,7 @@ class ARTIQIRGenerator(algorithm.Visitor): def _get_matmult(self, result_type, lhs_type, rhs_type): name = "_array_MatMult_" + self._mangle_arrayop_types( [result_type, lhs_type, rhs_type]) - if name not in self.array_binop_funcs: + if name not in self.array_op_funcs: def body_gen(result, lhs, rhs): assert builtins.is_array(result.type), \ @@ -1656,9 +1653,9 @@ class ARTIQIRGenerator(algorithm.Visitor): ir.Constant(0, self._size_type), lambda index: self.append( ir.Compare(ast.Lt(loc=None), index, num_rows)), row_loop) - self.array_binop_funcs[name] = self._make_array_binop( + self.array_op_funcs[name] = self._make_array_binop( name, result_type, lhs_type, rhs_type, body_gen) - return self.array_binop_funcs[name] + return self.array_op_funcs[name] def _get_matmult_shapes(self, lhs, rhs): lhs_shape = self.append(ir.GetAttr(lhs, "shape")) From ae47d4c0eca5f6125b04e5aeb20ce2602d957f90 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 9 Aug 2020 17:45:20 +0100 Subject: [PATCH 2273/2457] test/coredevice: Add host/device consistency checks for NumPy math --- artiq/test/coredevice/test_numpy.py | 95 +++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 artiq/test/coredevice/test_numpy.py diff --git a/artiq/test/coredevice/test_numpy.py b/artiq/test/coredevice/test_numpy.py new file mode 100644 index 000000000..7cc906087 --- /dev/null +++ b/artiq/test/coredevice/test_numpy.py @@ -0,0 +1,95 @@ +from artiq.experiment import * +import numpy +from artiq.test.hardware_testbench import ExperimentCase +from artiq.compiler import math_fns + + +class _RunOnDevice(EnvExperiment): + def build(self): + self.setattr_device("core") + + @kernel + def run_on_kernel_unary(self, a, callback, numpy): + self.run(a, callback, numpy) + + @kernel + def run_on_kernel_binary(self, a, b, callback, numpy): + self.run(a, b, callback, numpy) + + +# Binary operations supported for scalars and arrays of any dimension, including +# broadcasting. +ELEM_WISE_BINOPS = ["+", "*", "//", "%", "**", "-", "/"] + + +class CompareHostDeviceTest(ExperimentCase): + def _test_binop(self, op, a, b): + exp = self.create(_RunOnDevice) + exp.run = kernel_from_string(["a", "b", "callback", "numpy"], + "callback(a " + op + "b)", + decorator=portable) + checked = False + + def with_host_result(host): + def with_both_results(device): + nonlocal checked + checked = True + self.assertTrue( + numpy.allclose(host, device), + "Discrepancy in binop test for '{}': Expexcted ({}, {}) -> {}, got {}" + .format(op, a, b, host, device)) + + exp.run_on_kernel_binary(a, b, with_both_results, numpy) + + exp.run(a, b, with_host_result, numpy) + self.assertTrue(checked, "Test did not run") + + def _test_unaryop(self, op, a): + exp = self.create(_RunOnDevice) + exp.run = kernel_from_string(["a", "callback", "numpy"], + "callback(" + op + ")", + decorator=portable) + checked = False + + def with_host_result(host): + def with_both_results(device): + nonlocal checked + checked = True + self.assertTrue( + numpy.allclose(host, device), + "Discrepancy in unaryop test for '{}': Expexcted {} -> {}, got {}" + .format(op, a, host, device)) + + exp.run_on_kernel_unary(a, with_both_results, numpy) + + exp.run(a, with_host_result, numpy) + self.assertTrue(checked, "Test did not run") + + def test_scalar_scalar_binops(self): + # Some arbitrarily chosen arguments of different types. Could be turned into + # randomised tests instead. + # TODO: Provoke overflows, division by zero, etc., and compare results. + args = [(typ(a), typ(b)) for a, b in [(0, 1), (3, 2), (11, 6)] + for typ in [numpy.int32, numpy.int64, numpy.float]] + for op in ELEM_WISE_BINOPS: + for arg in args: + self._test_binop(op, *arg) + + def test_scalar_matrix_binops(self): + for typ in [numpy.int32, numpy.int64, numpy.float]: + scalar = typ(3) + matrix = numpy.array([[4, 5, 6], [7, 8, 9]], dtype=typ) + for op in ELEM_WISE_BINOPS: + self._test_binop(op, scalar, matrix) + self._test_binop(op, matrix, scalar) + self._test_binop(op, matrix, matrix) + + def test_unary_math_fns(self): + names = [ + a for a, _ in math_fns.unary_fp_intrinsics + math_fns.unary_fp_runtime_calls + ] + for name in names: + op = "numpy.{}(a)".format(name) + print(op) + self._test_unaryop(op, 0.5) + self._test_unaryop(op, numpy.array([[0.3, 0.4], [0.5, 0.6]])) From a39bd69ca44806c5bef888ab90232e8bd77dfbe7 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 9 Aug 2020 19:27:54 +0100 Subject: [PATCH 2274/2457] compiler: Implement numpy.rint() using llvm.round() --- artiq/compiler/math_fns.py | 16 ++++++++++++++-- artiq/test/coredevice/test_numpy.py | 6 +++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/artiq/compiler/math_fns.py b/artiq/compiler/math_fns.py index 3dfb0c580..e29c3625b 100644 --- a/artiq/compiler/math_fns.py +++ b/artiq/compiler/math_fns.py @@ -15,8 +15,20 @@ unary_fp_intrinsics = [(name, "llvm." + name + ".f64") for name in [ "floor", "ceil", "trunc", - "rint", -]] +]] + [ + # numpy.rint() seems to (NumPy 1.19.0, Python 3.8.5, Linux x86_64) + # implement round-to-even, but unfortunately, rust-lang/libm only + # provides round(), which always rounds away from zero. + # + # As there is no equivalent of the latter in NumPy (nor any other + # basic rounding function), expose round() as numpy.rint anyway, + # even if the rounding modes don't match up, so there is some way + # to do rounding on the core device. (numpy.round() has entirely + # different semantics; it rounds to a configurable number of + # decimals.) + ("rint", "llvm.round.f64"), +] + #: float -> float numpy.* math functions lowered to runtime calls. unary_fp_runtime_calls = [ diff --git a/artiq/test/coredevice/test_numpy.py b/artiq/test/coredevice/test_numpy.py index 7cc906087..715aedaea 100644 --- a/artiq/test/coredevice/test_numpy.py +++ b/artiq/test/coredevice/test_numpy.py @@ -90,6 +90,6 @@ class CompareHostDeviceTest(ExperimentCase): ] for name in names: op = "numpy.{}(a)".format(name) - print(op) - self._test_unaryop(op, 0.5) - self._test_unaryop(op, numpy.array([[0.3, 0.4], [0.5, 0.6]])) + # Avoid 0.5, as numpy.rint's rounding mode currently doesn't match. + self._test_unaryop(op, 0.51) + self._test_unaryop(op, numpy.array([[0.3, 0.4], [0.51, 0.6]])) From d35f659d25ae9c0721f30df89dfe01c2148297a8 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 9 Aug 2020 20:03:34 +0100 Subject: [PATCH 2275/2457] compiler: Add additional math fns available from Rust libm --- artiq/compiler/math_fns.py | 9 +++++++++ artiq/test/coredevice/test_numpy.py | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/artiq/compiler/math_fns.py b/artiq/compiler/math_fns.py index e29c3625b..6b1890c1d 100644 --- a/artiq/compiler/math_fns.py +++ b/artiq/compiler/math_fns.py @@ -15,6 +15,7 @@ unary_fp_intrinsics = [(name, "llvm." + name + ".f64") for name in [ "floor", "ceil", "trunc", + "sqrt", ]] + [ # numpy.rint() seems to (NumPy 1.19.0, Python 3.8.5, Linux x86_64) # implement round-to-even, but unfortunately, rust-lang/libm only @@ -36,6 +37,14 @@ unary_fp_runtime_calls = [ ("arcsin", "asin"), ("arccos", "acos"), ("arctan", "atan"), + ("sinh", "sinh"), + ("cosh", "cosh"), + ("tanh", "tanh"), + ("arcsinh", "asinh"), + ("arccosh", "acosh"), + ("arctanh", "atanh"), + ("expm1", "expm1"), + ("cbrt", "cbrt"), ] #: Array handling builtins (special treatment due to allocations). diff --git a/artiq/test/coredevice/test_numpy.py b/artiq/test/coredevice/test_numpy.py index 715aedaea..6fb4ee3dd 100644 --- a/artiq/test/coredevice/test_numpy.py +++ b/artiq/test/coredevice/test_numpy.py @@ -35,7 +35,7 @@ class CompareHostDeviceTest(ExperimentCase): nonlocal checked checked = True self.assertTrue( - numpy.allclose(host, device), + numpy.allclose(host, device, equal_nan=True), "Discrepancy in binop test for '{}': Expexcted ({}, {}) -> {}, got {}" .format(op, a, b, host, device)) @@ -56,7 +56,7 @@ class CompareHostDeviceTest(ExperimentCase): nonlocal checked checked = True self.assertTrue( - numpy.allclose(host, device), + numpy.allclose(host, device, equal_nan=True), "Discrepancy in unaryop test for '{}': Expexcted {} -> {}, got {}" .format(op, a, host, device)) From 53d64d08a8d7360d24fed9716dcd71db7c1fd5c1 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 9 Aug 2020 23:14:56 +0100 Subject: [PATCH 2276/2457] compiler: Fix multi-dim slice error message test, tweak wording --- artiq/compiler/transforms/inferencer.py | 2 +- artiq/test/lit/inferencer/error_subscript.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 172dfb1fe..81a4c21ec 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -240,7 +240,7 @@ class Inferencer(algorithm.Visitor): if not builtins.is_array(node.value.type): diag = diagnostic.Diagnostic( "error", - "multi-dimensional slices only supported for arrays, not {type}", + "multi-dimensional indexing only supported for arrays, not {type}", {"type": types.TypePrinter().name(node.value.type)}, node.loc, []) self.engine.process(diag) diff --git a/artiq/test/lit/inferencer/error_subscript.py b/artiq/test/lit/inferencer/error_subscript.py index 0aadb3289..d8332ab09 100644 --- a/artiq/test/lit/inferencer/error_subscript.py +++ b/artiq/test/lit/inferencer/error_subscript.py @@ -3,7 +3,7 @@ x = [] -# CHECK-L: ${LINE:+1}: error: multi-dimensional slices are not supported +# CHECK-L: ${LINE:+1}: error: multi-dimensional indexing only supported for arrays x[1,2] # CHECK-L: ${LINE:+1}: error: multi-dimensional slices are not supported From 778f2cf905c0e3d8245a1c972e072402b0081a53 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 9 Aug 2020 23:30:25 +0100 Subject: [PATCH 2277/2457] compiler: Fix numpy.full, implement for >1D --- .../compiler/transforms/artiq_ir_generator.py | 38 ++++++++++++------- artiq/compiler/transforms/inferencer.py | 21 +++++++--- artiq/test/coredevice/test_embedding.py | 5 +++ 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index ac06f8717..5c5f00139 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1411,7 +1411,7 @@ class ARTIQIRGenerator(algorithm.Visitor): operand = self.visit(node.operand) if builtins.is_array(operand.type): shape = self.append(ir.GetAttr(operand, "shape")) - result = self._allocate_new_array(node.type.find()["elt"], shape) + result, _ = self._allocate_new_array(node.type.find()["elt"], shape) func = self._get_array_unaryop("USub", make_sub, node.type, operand.type) self._invoke_arrayop(func, [result, operand]) return result @@ -1431,7 +1431,7 @@ class ARTIQIRGenerator(algorithm.Visitor): if builtins.is_array(node.type): result_elt = node.type.find()["elt"] shape = self.append(ir.GetAttr(value, "shape")) - result = self._allocate_new_array(result_elt, shape) + result, _ = self._allocate_new_array(result_elt, shape) func = self._get_array_unaryop( "Coerce", lambda v: self.append(ir.Coerce(v, result_elt)), node.type, value.type) @@ -1455,7 +1455,7 @@ class ARTIQIRGenerator(algorithm.Visitor): total_length = self._get_total_array_len(shape) buffer = self.append(ir.Alloc([total_length], types._TPointer(elt=elt))) result_type = builtins.TArray(elt, types.TValue(len(shape.type.elts))) - return self.append(ir.Alloc([buffer, shape], result_type)) + return self.append(ir.Alloc([buffer, shape], result_type)), total_length def _make_array_binop(self, name, result_type, lhs_type, rhs_type, body_gen): try: @@ -1704,7 +1704,7 @@ class ARTIQIRGenerator(algorithm.Visitor): elt = final_type["elt"] result_dims = final_type["num_dims"].value - result = self._allocate_new_array(elt, result_shape) + result, _ = self._allocate_new_array(elt, result_shape) func = self._get_matmult(result.type, left.type, right.type) self._invoke_arrayop(func, [result, lhs, rhs]) @@ -1745,7 +1745,7 @@ class ARTIQIRGenerator(algorithm.Visitor): ir.Constant("operands could not be broadcast together", builtins.TStr()))) - result = self._allocate_new_array(node.type.find()["elt"], shape) + result, _ = self._allocate_new_array(node.type.find()["elt"], shape) func = self._get_array_binop(node.op, node.type, lhs.type, rhs.type) self._invoke_arrayop(func, [result, lhs, rhs]) return result @@ -2223,14 +2223,26 @@ class ARTIQIRGenerator(algorithm.Visitor): if len(node.args) == 2 and len(node.keywords) == 0: arg0, arg1 = map(self.visit, node.args) - result = self.append(ir.Alloc([arg0], node.type)) + num_dims = node.type.find()["num_dims"].value + if types.is_tuple(arg0.type): + lens = [self.append(ir.GetAttr(arg0, i)) for i in range(num_dims)] + else: + assert num_dims == 1 + lens = [arg0] + + shape = self._make_array_shape(lens) + result, total_len = self._allocate_new_array(node.type.find()["elt"], + shape) + def body_gen(index): self.append(ir.SetElem(result, index, arg1)) - return self.append(ir.Arith(ast.Add(loc=None), index, - ir.Constant(1, arg0.type))) - self._make_loop(ir.Constant(0, self._size_type), - lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, arg0)), - body_gen) + return self.append( + ir.Arith(ast.Add(loc=None), index, + ir.Constant(1, self._size_type))) + + self._make_loop( + ir.Constant(0, self._size_type), lambda index: self.append( + ir.Compare(ast.Lt(loc=None), index, total_len)), body_gen) return result else: assert False @@ -2247,7 +2259,7 @@ class ARTIQIRGenerator(algorithm.Visitor): dim0 = self.append(ir.GetAttr(arg_shape, 0)) dim1 = self.append(ir.GetAttr(arg_shape, 1)) shape = self._make_array_shape([dim1, dim0]) - result = self._allocate_new_array(node.type.find()["elt"], shape) + result, _ = self._allocate_new_array(node.type.find()["elt"], shape) arg_buffer = self.append(ir.GetAttr(arg, "buffer")) result_buffer = self.append(ir.GetAttr(result, "buffer")) @@ -2413,7 +2425,7 @@ class ARTIQIRGenerator(algorithm.Visitor): node.arg_exprs) shape = self.append(ir.GetAttr(args[0], "shape")) - result = self._allocate_new_array(node.type.find()["elt"], shape) + result, _ = self._allocate_new_array(node.type.find()["elt"], shape) # TODO: Generate more generically if non-externals are allowed. name = node.func.type.find().name diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 81a4c21ec..e5cbc561b 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -1103,17 +1103,26 @@ class Inferencer(algorithm.Visitor): diagnose(valid_forms()) elif types.is_builtin(typ, "make_array"): valid_forms = lambda: [ - valid_form("numpy.full(count:int32, value:'a) -> numpy.array(elt='a)") + valid_form("numpy.full(count:int32, value:'a) -> array(elt='a, num_dims=1)"), + valid_form("numpy.full(shape:(int32,)*'b, value:'a) -> array(elt='a, num_dims='b)"), ] - self._unify(node.type, builtins.TArray(), - node.loc, None) - if len(node.args) == 2 and len(node.keywords) == 0: arg0, arg1 = node.args - self._unify(arg0.type, builtins.TInt32(), - arg0.loc, None) + if types.is_var(arg0.type): + return # undetermined yet + elif types.is_tuple(arg0.type): + num_dims = len(arg0.type.find().elts) + self._unify(arg0.type, types.TTuple([builtins.TInt32()] * num_dims), + arg0.loc, None) + else: + num_dims = 1 + self._unify(arg0.type, builtins.TInt32(), + arg0.loc, None) + + self._unify(node.type, builtins.TArray(num_dims=num_dims), + node.loc, None) self._unify(arg1.type, node.type.find()["elt"], arg1.loc, None) else: diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index fbd47a1a4..a2c6cf823 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -244,6 +244,10 @@ class _RPCCalls(EnvExperiment): def numpy_full(self): return numpy.full(10, 20) + @kernel + def numpy_full_matrix(self): + return numpy.full((3, 2), 13) + @kernel def numpy_nan(self): return numpy.full(10, numpy.nan) @@ -277,6 +281,7 @@ class RPCCallsTest(ExperimentCase): self.assertEqual(exp.numpy_things(), (numpy.int32(10), numpy.int64(20), numpy.array([42,]))) self.assertTrue((exp.numpy_full() == numpy.full(10, 20)).all()) + self.assertTrue((exp.numpy_full_matrix() == numpy.full((3, 2), 13)).all()) self.assertTrue(numpy.isnan(exp.numpy_nan()).all()) exp.builtin() exp.async_in_try() From daf57969b21c1155a7d4d86a229922e131a201a8 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sun, 9 Aug 2020 23:34:30 +0100 Subject: [PATCH 2278/2457] compiler: Do not expand strings into TInt(8)s in array() --- artiq/compiler/transforms/inferencer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index e5cbc561b..e2be2c7df 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -888,7 +888,7 @@ class Inferencer(algorithm.Visitor): break if types.is_var(elt): return # undetermined yet - if not builtins.is_iterable(elt): + if not builtins.is_iterable(elt) or builtins.is_str(elt): break num_dims += 1 elt = builtins.get_iterable_elt(elt) From c6f0c4dca40d2be72f0b0624abcebdbaa4bbdda0 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 10 Aug 2020 00:22:13 +0100 Subject: [PATCH 2279/2457] test/coredevice: Ignore jagged 2D array embedding test for now --- artiq/test/coredevice/test_embedding.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index a2c6cf823..c32ba2c55 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -1,4 +1,5 @@ import numpy +import unittest from time import sleep from artiq.experiment import * @@ -77,6 +78,10 @@ class RoundtripTest(ExperimentCase): self.assertArrayRoundtrip(numpy.array([[1.0, 2.0], [3.0, 4.0]])) self.assertArrayRoundtrip(numpy.array([["a", "b"], ["c", "d"]])) + # FIXME: This should work, but currently passes as the argument is just + # synthesised as the same call to array(), instead of using the "type + # inference" result from the host NumPy implementation. + @unittest.expectedFailure def test_array_jagged(self): self.assertArrayRoundtrip(numpy.array([[1, 2], [3]])) From d8cd5023f6fb0927a6bcf6197342e6137a1a0262 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Aug 2020 13:36:06 +0800 Subject: [PATCH 2280/2457] runtime: expose more libm functions --- artiq/firmware/ksupport/api.rs | 42 ++++++++++++++++++- artiq/firmware/ksupport/glue.c | 2 +- artiq/firmware/ksupport/ksupport.ld | 4 +- artiq/firmware/libproto_artiq/kernel_proto.rs | 2 +- 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 6d14891a7..c07f9776b 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -67,10 +67,48 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(memcmp, extern { fn memcmp(a: *const u8, b: *mut u8, size: usize); }), /* libm */ - api!(sqrt), - api!(round), + // commented out functions are not available with the libm used here, but are available in NAR3. + api!(acos), + api!(acosh), + api!(asin), + api!(asinh), + api!(atan), + api!(atan2), + api!(atanh), + api!(cbrt), + api!(ceil), + api!(cos), + api!(cosh), + api!(erf), + api!(erfc), + api!(exp), + //api!(exp2), + //api!(exp10), + api!(expm1), + api!(fabs), api!(floor), + //api!(fma), api!(fmod), + api!(hypot), + api!(j0), + api!(j1), + api!(jn), + api!(lgamma), + api!(log), + //api!(log2), + api!(log10), + api!(pow), + api!(round), + api!(sin), + api!(sinh), + api!(sqrt), + api!(tan), + api!(tanh), + //api!(tgamma), + //api!(trunc), + api!(y0), + api!(y1), + api!(yn), /* exceptions */ api!(_Unwind_Resume = ::unwind::_Unwind_Resume), diff --git a/artiq/firmware/ksupport/glue.c b/artiq/firmware/ksupport/glue.c index c1155b732..7f87d5e3c 100644 --- a/artiq/firmware/ksupport/glue.c +++ b/artiq/firmware/ksupport/glue.c @@ -15,7 +15,7 @@ void send_to_core_log(struct slice str); void send_to_rtio_log(struct slice data); #define KERNELCPU_EXEC_ADDRESS 0x40800000 -#define KERNELCPU_PAYLOAD_ADDRESS 0x40840000 +#define KERNELCPU_PAYLOAD_ADDRESS 0x40860000 #define KERNELCPU_LAST_ADDRESS 0x4fffffff #define KSUPPORT_HEADER_SIZE 0x80 diff --git a/artiq/firmware/ksupport/ksupport.ld b/artiq/firmware/ksupport/ksupport.ld index 48b6978f2..bc6a97ab1 100644 --- a/artiq/firmware/ksupport/ksupport.ld +++ b/artiq/firmware/ksupport/ksupport.ld @@ -6,12 +6,12 @@ ENTRY(_reset_handler) * code/data/heap, then comes kernel memory. * Next 4M of main memory are reserved for * the background RPC queue. - * First 256K of kernel memory are for support code. + * First 384K of kernel memory are for support code. * Support code is loaded at ORIGIN-0x80 so that ELF headers * are also loaded. */ MEMORY { - ksupport (RWX) : ORIGIN = 0x40800000, LENGTH = 0x40000 + ksupport (RWX) : ORIGIN = 0x40800000, LENGTH = 0x60000 } /* Kernel stack is at the end of main RAM. */ diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index f7fef6eb0..a64f0f0b7 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -2,7 +2,7 @@ use core::fmt; use dyld; pub const KERNELCPU_EXEC_ADDRESS: usize = 0x40800000; -pub const KERNELCPU_PAYLOAD_ADDRESS: usize = 0x40840000; +pub const KERNELCPU_PAYLOAD_ADDRESS: usize = 0x40860000; pub const KERNELCPU_LAST_ADDRESS: usize = 0x4fffffff; pub const KSUPPORT_HEADER_SIZE: usize = 0x80; From 48008eaf5fc905a50b48daecba9393a12321c91a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 12 Aug 2020 15:01:13 +0800 Subject: [PATCH 2281/2457] test: omit unavailable math functions on OR1K --- artiq/test/coredevice/test_numpy.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/artiq/test/coredevice/test_numpy.py b/artiq/test/coredevice/test_numpy.py index 6fb4ee3dd..caaa2ce27 100644 --- a/artiq/test/coredevice/test_numpy.py +++ b/artiq/test/coredevice/test_numpy.py @@ -1,6 +1,7 @@ from artiq.experiment import * import numpy from artiq.test.hardware_testbench import ExperimentCase +from artiq.compiler.targets import CortexA9Target from artiq.compiler import math_fns @@ -88,6 +89,11 @@ class CompareHostDeviceTest(ExperimentCase): names = [ a for a, _ in math_fns.unary_fp_intrinsics + math_fns.unary_fp_runtime_calls ] + exp = self.create(_RunOnDevice) + if exp.core.target_cls != CortexA9Target: + names.remove("exp2") + names.remove("log2") + names.remove("trunc") for name in names: op = "numpy.{}(a)".format(name) # Avoid 0.5, as numpy.rint's rounding mode currently doesn't match. From b05cbcbc245125a770ae65f400dd39fe69e5a87f Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 13 Aug 2020 12:23:32 +0800 Subject: [PATCH 2282/2457] test: set uart log level to INFO for DMA tests --- artiq/test/coredevice/test_rtio.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 96437d2a2..e090ebf1b 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -652,6 +652,18 @@ class _DMA(EnvExperiment): class DMATest(ExperimentCase): + def setUp(self): + super().setUp() + # prevent DEBUG log messages causing delay for DMA + core_addr = self.device_mgr.get_desc("core")["arguments"]["host"] + self.mgmt = CommMgmt(core_addr) + self.mgmt.set_uart_log_level('INFO') + + def tearDown(self): + self.mgmt.set_uart_log_level('DEBUG') + self.mgmt.close() + super().tearDown() + def test_dma_storage(self): exp = self.create(_DMA) exp.record() From a46573e97a0707cad2a39d65fb21d8c8817490c9 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 13 Aug 2020 12:44:33 +0800 Subject: [PATCH 2283/2457] Revert "test: set uart log level to INFO for DMA tests" This reverts commit b05cbcbc245125a770ae65f400dd39fe69e5a87f. --- artiq/test/coredevice/test_rtio.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index e090ebf1b..96437d2a2 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -652,18 +652,6 @@ class _DMA(EnvExperiment): class DMATest(ExperimentCase): - def setUp(self): - super().setUp() - # prevent DEBUG log messages causing delay for DMA - core_addr = self.device_mgr.get_desc("core")["arguments"]["host"] - self.mgmt = CommMgmt(core_addr) - self.mgmt.set_uart_log_level('INFO') - - def tearDown(self): - self.mgmt.set_uart_log_level('DEBUG') - self.mgmt.close() - super().tearDown() - def test_dma_storage(self): exp = self.create(_DMA) exp.record() From 69718fca9085645886f01635e590114e21aeb863 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Fri, 14 Aug 2020 02:04:28 +0100 Subject: [PATCH 2284/2457] gui: Improve fuzzy-select heuristics Even though the code already used non-greedy wildcards before, it would not find the shortest match, as earlier match starts would still take precedence. This could possibly be sped up a bit in CPython by doing everything inside re using lookahead-assertion trickery, but the current code is already imperceptibly fast for hundreds of choices. --- artiq/gui/fuzzy_select.py | 42 +++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/artiq/gui/fuzzy_select.py b/artiq/gui/fuzzy_select.py index abbe31dae..50e95d5ea 100644 --- a/artiq/gui/fuzzy_select.py +++ b/artiq/gui/fuzzy_select.py @@ -32,7 +32,6 @@ class FuzzySelectWidget(LayoutWidget): :param entry_count_limit: Maximum number of entries to show. """ super().__init__(*args) - self.choices = choices self.entry_count_limit = entry_count_limit assert entry_count_limit >= 2, ("Need to allow at least two entries " + "to show the ' not shown' hint") @@ -58,9 +57,12 @@ class FuzzySelectWidget(LayoutWidget): self.abort_when_menu_hidden = False self.abort_when_line_edit_unfocussed = True + self.set_choices(choices) + def set_choices(self, choices: List[Tuple[str, int]]) -> None: """Update the list of choices available to the user.""" - self.choices = choices + # Keep sorted in the right order for when the query is empty. + self.choices = sorted(choices, key=lambda a: (a[1], a[0])) if self.menu: self._update_menu() @@ -173,19 +175,39 @@ class FuzzySelectWidget(LayoutWidget): without interruptions), then the position of the match, and finally lexicographically. """ + query = self.line_edit.text() + if not query: + return [label for label, _ in self.choices] + + # Find all "substring" matches of the given query in the labels, + # allowing any number of characters between each query character. + # Sort first by length of match (short matches preferred), to which the + # set weight is also applied, then by location (early in the label + # preferred), and at last alphabetically. + # TODO: More SublimeText-like heuristics taking capital letters and # punctuation into account. Also, requiring the matches to be in order # seems to be a bit annoying in practice. - text = self.line_edit.text() + + # `re` seems to be the fastest way of doing this in CPython, even with + # all the (non-greedy) wildcards. suggestions = [] - # `re` seems to be the fastest way of matching this in CPython, even - # with all the wildcards. - pat = '.*?'.join(map(re.escape, text.lower())) - regex = re.compile(pat) + pattern_str = ".*?".join(map(re.escape, query)) + pattern = re.compile(pattern_str, flags=re.IGNORECASE) for label, weight in self.choices: - r = regex.search(label.lower()) - if r: - suggestions.append((len(r.group()) - weight, r.start(), label)) + matches = [] + # Manually loop over shortest matches at each position; + # re.finditer() only returns non-overlapping matches. + pos = 0 + while True: + r = pattern.search(label, pos=pos) + if not r: + break + start, stop = r.span() + matches.append((stop - start - weight, start, label)) + pos = start + 1 + if matches: + suggestions.append(min(matches)) return [x for _, _, x in sorted(suggestions)] def _close(self): From 5f6aa02b61017d14f1bdaaec164231cff0cb0202 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 14 Aug 2020 13:14:45 +0800 Subject: [PATCH 2285/2457] gui: unbreak background --- artiq/gui/logo_ver.svg | 68 +++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/artiq/gui/logo_ver.svg b/artiq/gui/logo_ver.svg index f45f67897..6a6ece31b 100644 --- a/artiq/gui/logo_ver.svg +++ b/artiq/gui/logo_ver.svg @@ -32,8 +32,8 @@ guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" - inkscape:window-width="1920" - inkscape:window-height="1016" + inkscape:window-width="2560" + inkscape:window-height="1376" id="namedview544" showgrid="false" fit-margin-top="0" @@ -41,122 +41,122 @@ fit-margin-right="0" fit-margin-bottom="0" inkscape:zoom="1.18" - inkscape:cx="34.887294" - inkscape:cy="109.12724" + inkscape:cx="-304.09576" + inkscape:cy="102.34758" inkscape:window-x="0" - inkscape:window-y="0" + inkscape:window-y="27" inkscape:window-maximized="1" inkscape:current-layer="text3371" /> \ No newline at end of file From aa0154d8e29bdaba4d8c7759a24e57dbd3746018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 21 Aug 2020 11:31:26 +0000 Subject: [PATCH 2286/2457] phaser: initial --- artiq/gateware/eem.py | 31 +++++- artiq/gateware/rtio/phy/fastlink.py | 120 ++++++++++++++++++++++++ artiq/gateware/rtio/phy/phaser.py | 51 ++++++++++ artiq/gateware/targets/kasli_generic.py | 7 ++ 4 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 artiq/gateware/rtio/phy/fastlink.py create mode 100644 artiq/gateware/rtio/phy/phaser.py diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index fba2c1b5a..35cf36de1 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -5,7 +5,7 @@ from migen.genlib.io import DifferentialOutput from artiq.gateware import rtio from artiq.gateware.rtio.phy import spi2, ad53xx_monitor, grabber from artiq.gateware.suservo import servo, pads as servo_pads -from artiq.gateware.rtio.phy import servo as rtservo, fastino +from artiq.gateware.rtio.phy import servo as rtservo, fastino, phaser def _eem_signal(i): @@ -613,7 +613,8 @@ class Fastino(_EEM): Subsignal("clk", Pins(_eem_pin(eem, 0, pol))), Subsignal("mosi", Pins(*(_eem_pin(eem, i, pol) for i in range(1, 7)))), - Subsignal("miso", Pins(_eem_pin(eem, 7, pol))), + Subsignal("miso", Pins(_eem_pin(eem, 7, pol)), + Misc("DIFF_TERM=TRUE")), IOStandard(iostandard), ) for pol in "pn"] @@ -626,3 +627,29 @@ class Fastino(_EEM): log2_width=0) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) + + +class Phaser(_EEM): + @staticmethod + def io(eem, iostandard="LVDS_25"): + return [ + ("phaser{}_ser_{}".format(eem, pol), 0, + Subsignal("clk", Pins(_eem_pin(eem, 0, pol))), + Subsignal("mosi", Pins(*(_eem_pin(eem, i, pol) + for i in range(1, 7)))), + Subsignal("miso", Pins(_eem_pin(eem, 7, pol)), + Misc("DIFF_TERM=TRUE")), + IOStandard(iostandard), + ) for pol in "pn"] + + @classmethod + def add_std(cls, target, eem, iostandard="LVDS_25"): + cls.add_extension(target, eem, iostandard=iostandard) + + phy = phaser.Phaser(target.platform.request("phaser{}_ser_p".format(eem)), + target.platform.request("phaser{}_ser_n".format(eem))) + target.submodules += phy + target.rtio_channels.extend([ + rtio.Channel(phy.config, ififo_depth=4), + rtio.Channel(phy.data), + ]) diff --git a/artiq/gateware/rtio/phy/fastlink.py b/artiq/gateware/rtio/phy/fastlink.py new file mode 100644 index 000000000..4448ba9b1 --- /dev/null +++ b/artiq/gateware/rtio/phy/fastlink.py @@ -0,0 +1,120 @@ +from migen import * +from migen.genlib.cdc import MultiReg +from migen.genlib.io import DifferentialOutput, DifferentialInput, DDROutput +from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine + +from artiq.gateware.rtio import rtlink + + +class SerDes(Module): + # crc-12 telco: 0x80f + def __init__(self, pins, pins_n, t_clk=7, d_clk=0b1100011, + n_frame=14, n_crc=12, poly=0x80f): + """DDR fast link. + + * One word clock lane with `t_clk` period. + * Multiple data lanes at DDR speed. + * One return data lane at slower speed. + * n_frame//2 - 1 marker bits are used to provide framing. + + * `n_frame` words per frame + * `t_clk` bits per clk cycle with pattern `d_clk` + * `n_crc` CRC bits per frame + """ + n_lanes = len(pins.mosi) # number of data lanes + n_word = n_lanes*t_clk + n_body = n_word*n_frame - (n_frame//2 + 1) - n_crc + + # frame data + self.payload = Signal(n_body) + # readback data + self.readback = Signal(n_frame, reset_less=True) + # data load synchronization event + self.stb = Signal() + + # # # + + self.submodules.crc = LiteEthMACCRCEngine( + data_width=2*n_lanes, width=n_crc, polynom=poly) + + words_ = [] + j = 0 + for i in range(n_frame): # iterate over words + if i == 0: # data and checksum + k = n_word - n_crc + elif i == 1: # marker + words_.append(C(1)) + k = n_word - 1 + elif i < n_frame//2 + 2: # marker + words_.append(C(0)) + k = n_word - 1 + else: # full word + k = n_word + # append corresponding frame body bits + words_.append(self.payload[j:j + k]) + j += k + words_ = Cat(words_) + assert len(words_) == n_frame*n_word - n_crc + words = Signal(len(words_)) + self.comb += words.eq(words_) + + clk = Signal(t_clk, reset=d_clk) + clk_stb = Signal() + i_frame = Signal(max=t_clk*n_frame//2) # DDR + frame_stb = Signal() + # big shift register for clk and mosi + sr = [Signal(n_frame*t_clk - n_crc//n_lanes, reset_less=True) + for i in range(n_lanes)] + assert len(Cat(sr)) == len(words) + # DDR bits for each register + ddr_data = Cat([sri[-2] for sri in sr], [sri[-1] for sri in sr]) + self.comb += [ + # assert one cycle ahead + clk_stb.eq(~clk[0] & clk[-1]), + # double period because of DDR + frame_stb.eq(i_frame == t_clk*n_frame//2 - 1), + + # LiteETHMACCRCEngine takes data LSB first + self.crc.data[::-1].eq(ddr_data), + self.stb.eq(frame_stb & clk_stb), + ] + miso = Signal() + miso_sr = Signal(n_frame, reset_less=True) + self.sync.rio_phy += [ + # shift clock pattern by two bits each DDR cycle + clk.eq(Cat(clk[-2:], clk)), + [sri[2:].eq(sri) for sri in sr], + self.crc.last.eq(self.crc.next), + If(clk[:2] == 0, # TODO: tweak MISO sampling + miso_sr.eq(Cat(miso, miso_sr)), + ), + If(~frame_stb, + i_frame.eq(i_frame + 1), + ), + If(frame_stb & clk_stb, + i_frame.eq(0), + self.crc.last.eq(0), + # transpose, load + Cat(sr).eq(Cat(words[mm::n_lanes] for mm in range(n_lanes))), + self.readback.eq(miso_sr), + ), + If(i_frame == t_clk*n_frame//2 - 2, + # inject crc + ddr_data.eq(self.crc.next), + ), + ] + + clk_ddr = Signal() + miso0 = Signal() + self.specials += [ + DDROutput(clk[-1], clk[-2], clk_ddr, ClockSignal("rio_phy")), + DifferentialOutput(clk_ddr, pins.clk, pins_n.clk), + DifferentialInput(pins.miso, pins_n.miso, miso0), + MultiReg(miso0, miso, "rio_phy"), + ] + for sri, ddr, mp, mn in zip( + sr, Signal(n_lanes), pins.mosi, pins_n.mosi): + self.specials += [ + DDROutput(sri[-1], sri[-2], ddr, ClockSignal("rio_phy")), + DifferentialOutput(ddr, mp, mn), + ] diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py new file mode 100644 index 000000000..4dc2197ad --- /dev/null +++ b/artiq/gateware/rtio/phy/phaser.py @@ -0,0 +1,51 @@ +from migen import * + +from artiq.gateware.rtio import rtlink +from .fastlink import SerDes + + +class Phaser(Module): + def __init__(self, pins, pins_n): + self.config = rtlink.Interface( + rtlink.OInterface(data_width=8, address_width=8, + enable_replace=False), + rtlink.IInterface(data_width=8)) + self.data = rtlink.Interface( + rtlink.OInterface(data_width=32, address_width=8, + enable_replace=True)) + + self.submodules.serializer = SerDes( + pins, pins_n, t_clk=8, d_clk=0b00001111, + n_frame=10, n_crc=6, poly=0x2f) + + header = Record([ + ("we", 1), + ("addr", 7), + ("data", 8), + ("type", 4) + ]) + n_channels = 2 + n_samples = 8 + body = [[(Signal(14), Signal(14)) for i in range(n_channels)] + for j in range(n_samples)] + assert len(Cat(header.raw_bits(), body)) == \ + len(self.serializer.payload) + self.comb += self.serializer.payload.eq(Cat(header.raw_bits(), body)) + + self.sync.rio_phy += [ + If(self.serializer.stb, + header.we.eq(0), + ), + If(self.config.o.stb, + header.we.eq(~self.config.o.address[-1]), + header.addr.eq(self.config.o.address), + header.data.eq(self.config.o.data), + header.type.eq(0), # reserved + ), + ] + + self.sync.rtio += [ + self.config.i.stb.eq(self.config.o.stb & + self.config.o.address[-1]), + self.config.i.data.eq(self.serializer.readback), + ] diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index bae599ed9..a68951c43 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -112,6 +112,12 @@ def peripheral_fastino(module, peripheral): eem.Fastino.add_std(module, peripheral["ports"][0]) +def peripheral_phaser(module, peripheral): + if len(peripheral["ports"]) != 1: + raise ValueError("wrong number of ports") + eem.Phaser.add_std(module, peripheral["ports"][0]) + + peripheral_processors = { "dio": peripheral_dio, "urukul": peripheral_urukul, @@ -122,6 +128,7 @@ peripheral_processors = { "grabber": peripheral_grabber, "mirny": peripheral_mirny, "fastino": peripheral_fastino, + "phaser": peripheral_phaser, } From a34a647ec47237afa19fec6b350cea9a0cb13cde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 21 Aug 2020 15:21:36 +0000 Subject: [PATCH 2287/2457] phaser: refactor fastlink --- artiq/gateware/rtio/phy/fastlink.py | 80 ++++++++++++++++------------- artiq/gateware/rtio/phy/phaser.py | 11 ++-- 2 files changed, 52 insertions(+), 39 deletions(-) diff --git a/artiq/gateware/rtio/phy/fastlink.py b/artiq/gateware/rtio/phy/fastlink.py index 4448ba9b1..98602206e 100644 --- a/artiq/gateware/rtio/phy/fastlink.py +++ b/artiq/gateware/rtio/phy/fastlink.py @@ -8,7 +8,7 @@ from artiq.gateware.rtio import rtlink class SerDes(Module): # crc-12 telco: 0x80f - def __init__(self, pins, pins_n, t_clk=7, d_clk=0b1100011, + def __init__(self, n_data=8, t_clk=7, d_clk=0b1100011, n_frame=14, n_crc=12, poly=0x80f): """DDR fast link. @@ -21,9 +21,13 @@ class SerDes(Module): * `t_clk` bits per clk cycle with pattern `d_clk` * `n_crc` CRC bits per frame """ - n_lanes = len(pins.mosi) # number of data lanes + # pins + self.data = [Signal(2) for _ in range(n_data)] + n_lanes = n_data - 2 # number of data lanes n_word = n_lanes*t_clk + t_frame = t_clk*n_frame//2 n_body = n_word*n_frame - (n_frame//2 + 1) - n_crc + t_miso = 0 # miso sampling latency TODO # frame data self.payload = Signal(n_body) @@ -39,6 +43,7 @@ class SerDes(Module): words_ = [] j = 0 + # last, LSB to first, MSB for i in range(n_frame): # iterate over words if i == 0: # data and checksum k = n_word - n_crc @@ -59,62 +64,65 @@ class SerDes(Module): self.comb += words.eq(words_) clk = Signal(t_clk, reset=d_clk) - clk_stb = Signal() - i_frame = Signal(max=t_clk*n_frame//2) # DDR - frame_stb = Signal() + i = Signal(max=t_frame) # big shift register for clk and mosi - sr = [Signal(n_frame*t_clk - n_crc//n_lanes, reset_less=True) + sr = [Signal(t_frame*2 - n_crc//n_lanes, reset_less=True) for i in range(n_lanes)] assert len(Cat(sr)) == len(words) # DDR bits for each register ddr_data = Cat([sri[-2] for sri in sr], [sri[-1] for sri in sr]) self.comb += [ - # assert one cycle ahead - clk_stb.eq(~clk[0] & clk[-1]), - # double period because of DDR - frame_stb.eq(i_frame == t_clk*n_frame//2 - 1), - + self.stb.eq(i == t_frame - 1), # LiteETHMACCRCEngine takes data LSB first self.crc.data[::-1].eq(ddr_data), - self.stb.eq(frame_stb & clk_stb), ] miso = Signal() - miso_sr = Signal(n_frame, reset_less=True) + miso_sr = Signal(t_frame, reset_less=True) self.sync.rio_phy += [ - # shift clock pattern by two bits each DDR cycle + # shift everything by two bits clk.eq(Cat(clk[-2:], clk)), [sri[2:].eq(sri) for sri in sr], self.crc.last.eq(self.crc.next), - If(clk[:2] == 0, # TODO: tweak MISO sampling - miso_sr.eq(Cat(miso, miso_sr)), - ), - If(~frame_stb, - i_frame.eq(i_frame + 1), - ), - If(frame_stb & clk_stb, - i_frame.eq(0), + miso_sr.eq(Cat(miso, miso_sr)), + i.eq(i + 1), + If(self.stb, + i.eq(0), + clk.eq(clk.reset), self.crc.last.eq(0), # transpose, load Cat(sr).eq(Cat(words[mm::n_lanes] for mm in range(n_lanes))), - self.readback.eq(miso_sr), + self.readback.eq(Cat([miso_sr[int(round(t_miso + i*t_clk/2.))] + for i in range(n_frame)])), ), - If(i_frame == t_clk*n_frame//2 - 2, - # inject crc + If(i == t_frame - 2, + # inject crc for the last cycle ddr_data.eq(self.crc.next), ), ] - clk_ddr = Signal() - miso0 = Signal() - self.specials += [ - DDROutput(clk[-1], clk[-2], clk_ddr, ClockSignal("rio_phy")), - DifferentialOutput(clk_ddr, pins.clk, pins_n.clk), - DifferentialInput(pins.miso, pins_n.miso, miso0), - MultiReg(miso0, miso, "rio_phy"), + self.comb += [ + self.data[0].eq(clk[-2:]), + [di.eq(sri[-2:]) for di, sri in zip(self.data[1:-1], sr)], + miso.eq(self.data[-1]), ] - for sri, ddr, mp, mn in zip( - sr, Signal(n_lanes), pins.mosi, pins_n.mosi): + + +class SerInterface(Module): + def __init__(self, pins, pins_n): + n_data = 1 + len(pins.mosi) + 1 + self.data = [Signal(2) for _ in range(n_data)] + clk_ddr = Signal() + miso_reg = Signal() + self.specials += [ + DDROutput(self.data[0][-1], self.data[0][-2], + clk_ddr, ClockSignal("rio_phy")), + DifferentialOutput(clk_ddr, pins.clk, pins_n.clk), + DifferentialInput(pins.miso, pins_n.miso, miso_reg), + MultiReg(miso_reg, self.data[-1], "rio_phy"), + ] + for i in range(len(pins.mosi)): + ddr = Signal() self.specials += [ - DDROutput(sri[-1], sri[-2], ddr, ClockSignal("rio_phy")), - DifferentialOutput(ddr, mp, mn), + DDROutput(self.data[-1], self.data[-2], ddr, ClockSignal("rio_phy")), + DifferentialOutput(ddr, pins.mosi[i], pins_n.mosi[i]), ] diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index 4dc2197ad..679c2aa05 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -1,7 +1,7 @@ from migen import * from artiq.gateware.rtio import rtlink -from .fastlink import SerDes +from .fastlink import SerDes, SerInterface class Phaser(Module): @@ -15,8 +15,13 @@ class Phaser(Module): enable_replace=True)) self.submodules.serializer = SerDes( - pins, pins_n, t_clk=8, d_clk=0b00001111, - n_frame=10, n_crc=6, poly=0x2f) + n_data=8, t_clk=8, d_clk=0b00001111, + n_frame=10, n_crc=6, poly=0x2f) + self.submodules.intf = SerInterface(pins, pins_n) + self.comb += [ + Cat(self.intf.data[:-1]).eq(Cat(self.serializer.data[:-1])), + self.serializer.data[-1].eq(self.intf.data[-1]), + ] header = Record([ ("we", 1), From 3e99f1ce5a314af568502ca116f68d1a7528d987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sat, 22 Aug 2020 11:46:41 +0000 Subject: [PATCH 2288/2457] phaser: refactor link --- artiq/gateware/rtio/phy/fastlink.py | 93 ++++++++++++++--------------- artiq/gateware/rtio/phy/phaser.py | 7 ++- 2 files changed, 49 insertions(+), 51 deletions(-) diff --git a/artiq/gateware/rtio/phy/fastlink.py b/artiq/gateware/rtio/phy/fastlink.py index 98602206e..3f84bb6a8 100644 --- a/artiq/gateware/rtio/phy/fastlink.py +++ b/artiq/gateware/rtio/phy/fastlink.py @@ -1,6 +1,6 @@ from migen import * -from migen.genlib.cdc import MultiReg -from migen.genlib.io import DifferentialOutput, DifferentialInput, DDROutput +from migen.genlib.io import (DifferentialOutput, DifferentialInput, + DDROutput, DDRInput) from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine from artiq.gateware.rtio import rtlink @@ -17,16 +17,18 @@ class SerDes(Module): * One return data lane at slower speed. * n_frame//2 - 1 marker bits are used to provide framing. - * `n_frame` words per frame + * `n_data` lanes * `t_clk` bits per clk cycle with pattern `d_clk` - * `n_crc` CRC bits per frame + * `n_frame` words per frame + * `n_crc` CRC bits per frame for divisor poly `poly` """ # pins self.data = [Signal(2) for _ in range(n_data)] - n_lanes = n_data - 2 # number of data lanes - n_word = n_lanes*t_clk - t_frame = t_clk*n_frame//2 - n_body = n_word*n_frame - (n_frame//2 + 1) - n_crc + n_mosi = n_data - 2 # mosi lanes + n_word = n_mosi*t_clk # bits per word + t_frame = t_clk*n_frame # frame duration + n_marker = n_frame//2 + 1 + n_body = n_word*n_frame - n_marker - n_crc t_miso = 0 # miso sampling latency TODO # frame data @@ -39,11 +41,11 @@ class SerDes(Module): # # # self.submodules.crc = LiteEthMACCRCEngine( - data_width=2*n_lanes, width=n_crc, polynom=poly) + data_width=2*n_mosi, width=n_crc, polynom=poly) words_ = [] j = 0 - # last, LSB to first, MSB + # build from LSB to MSB because MSB first for i in range(n_frame): # iterate over words if i == 0: # data and checksum k = n_word - n_crc @@ -64,65 +66,60 @@ class SerDes(Module): self.comb += words.eq(words_) clk = Signal(t_clk, reset=d_clk) - i = Signal(max=t_frame) + i = Signal(max=t_frame//2) # big shift register for clk and mosi - sr = [Signal(t_frame*2 - n_crc//n_lanes, reset_less=True) - for i in range(n_lanes)] + sr = [Signal(t_frame - n_crc//n_mosi, reset_less=True) + for i in range(n_mosi)] assert len(Cat(sr)) == len(words) # DDR bits for each register - ddr_data = Cat([sri[-2] for sri in sr], [sri[-1] for sri in sr]) - self.comb += [ - self.stb.eq(i == t_frame - 1), - # LiteETHMACCRCEngine takes data LSB first - self.crc.data[::-1].eq(ddr_data), - ] - miso = Signal() + crc_data = [sri[-2] for sri in sr] + [sri[-1] for sri in sr] miso_sr = Signal(t_frame, reset_less=True) + miso_sr_next = Signal.like(miso_sr) + self.comb += [ + self.stb.eq(i == t_frame//2 - 1), + # LiteETHMACCRCEngine takes data LSB first + self.crc.data.eq(Cat(reversed(crc_data))), + miso_sr_next.eq(Cat(self.data[-1], miso_sr)), + [di.eq(sri[-2:]) for di, sri in zip(self.data, [clk] + sr)], + ] self.sync.rio_phy += [ # shift everything by two bits - clk.eq(Cat(clk[-2:], clk)), - [sri[2:].eq(sri) for sri in sr], + [sri.eq(Cat(sri[-2:], sri)) for sri in [clk] + sr], + miso_sr.eq(miso_sr_next), self.crc.last.eq(self.crc.next), - miso_sr.eq(Cat(miso, miso_sr)), i.eq(i + 1), If(self.stb, i.eq(0), clk.eq(clk.reset), self.crc.last.eq(0), # transpose, load - Cat(sr).eq(Cat(words[mm::n_lanes] for mm in range(n_lanes))), - self.readback.eq(Cat([miso_sr[int(round(t_miso + i*t_clk/2.))] - for i in range(n_frame)])), + [sri.eq(Cat(words[i::n_mosi])) for i, sri in enumerate(sr)], + # unload miso + self.readback.eq(Cat([miso_sr_next[t_miso + i*t_clk] + for i in range(n_frame)])), ), - If(i == t_frame - 2, + If(i == t_frame//2 - 2, # inject crc for the last cycle - ddr_data.eq(self.crc.next), + Cat(crc_data).eq(self.crc.next), ), ] - self.comb += [ - self.data[0].eq(clk[-2:]), - [di.eq(sri[-2:]) for di, sri in zip(self.data[1:-1], sr)], - miso.eq(self.data[-1]), - ] - class SerInterface(Module): def __init__(self, pins, pins_n): - n_data = 1 + len(pins.mosi) + 1 - self.data = [Signal(2) for _ in range(n_data)] - clk_ddr = Signal() - miso_reg = Signal() - self.specials += [ - DDROutput(self.data[0][-1], self.data[0][-2], - clk_ddr, ClockSignal("rio_phy")), - DifferentialOutput(clk_ddr, pins.clk, pins_n.clk), - DifferentialInput(pins.miso, pins_n.miso, miso_reg), - MultiReg(miso_reg, self.data[-1], "rio_phy"), - ] - for i in range(len(pins.mosi)): + self.data = [Signal(2) for _ in range(2 + len(pins.mosi))] + + for d, pp, pn in zip(self.data, + [pins.clk] + list(pins.mosi), + [pins_n.clk] + list(pins_n.mosi)): ddr = Signal() self.specials += [ - DDROutput(self.data[-1], self.data[-2], ddr, ClockSignal("rio_phy")), - DifferentialOutput(ddr, pins.mosi[i], pins_n.mosi[i]), + DDROutput(d[-1], d[-2], ddr, ClockSignal("rio_phy")), + DifferentialOutput(ddr, pp, pn), ] + ddr = Signal() + self.specials += [ + DifferentialInput(pins.miso, pins_n.miso, ddr), + DDRInput(ddr, self.data[-1][-1], self.data[-1][-2], + ClockSignal("rio_phy")), + ] diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index 679c2aa05..eb5cb26b2 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -9,7 +9,7 @@ class Phaser(Module): self.config = rtlink.Interface( rtlink.OInterface(data_width=8, address_width=8, enable_replace=False), - rtlink.IInterface(data_width=8)) + rtlink.IInterface(data_width=10)) self.data = rtlink.Interface( rtlink.OInterface(data_width=32, address_width=8, enable_replace=True)) @@ -31,8 +31,9 @@ class Phaser(Module): ]) n_channels = 2 n_samples = 8 - body = [[(Signal(14), Signal(14)) for i in range(n_channels)] - for j in range(n_samples)] + n_bits = 14 + body = [[(Signal(n_bits), Signal(n_bits)) + for i in range(n_channels)] for j in range(n_samples)] assert len(Cat(header.raw_bits(), body)) == \ len(self.serializer.payload) self.comb += self.serializer.payload.eq(Cat(header.raw_bits(), body)) From 7e584d0da108dc2efd408619204e014310e2bb47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sat, 22 Aug 2020 11:47:01 +0000 Subject: [PATCH 2289/2457] fastino: use fastlink --- artiq/gateware/rtio/phy/fastino.py | 180 ++++++----------------------- 1 file changed, 38 insertions(+), 142 deletions(-) diff --git a/artiq/gateware/rtio/phy/fastino.py b/artiq/gateware/rtio/phy/fastino.py index 14d9d9cf1..ba8a7b5c9 100644 --- a/artiq/gateware/rtio/phy/fastino.py +++ b/artiq/gateware/rtio/phy/fastino.py @@ -4,132 +4,7 @@ from migen.genlib.io import DifferentialOutput, DifferentialInput, DDROutput from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine from artiq.gateware.rtio import rtlink - - -class SerDes(Module): - def transpose(self, i, n): - # i is n,m c-contiguous - # o is m,n c-contiguous - m = len(i)//n - assert n*m == len(i) - - def __init__(self, pins, pins_n): - n_bits = 16 # bits per dac data word - n_channels = 32 # channels per fastino - n_div = 7 # bits per lane and word - assert n_div == 7 - n_frame = 14 # word per frame - n_lanes = len(pins.mosi) # number of data lanes - n_checksum = 12 # checksum bits - n_addr = 4 # readback address bits - n_word = n_lanes*n_div - n_body = n_word*n_frame - (n_frame//2 + 1) - n_checksum - - # dac data words - self.dacs = [Signal(n_bits) for i in range(n_channels)] - # dac update enable - self.enable = Signal(n_channels) - # configuration word - self.cfg = Signal(20) - # readback data - self.dat_r = Signal(n_frame//2*(1 << n_addr)) - # data load synchronization event - self.stb = Signal() - - # # # - - # crc-12 telco - self.submodules.crc = LiteEthMACCRCEngine( - data_width=2*n_lanes, width=n_checksum, polynom=0x80f) - - addr = Signal(4) - body_ = Cat(self.cfg, addr, self.enable, self.dacs) - assert len(body_) == n_body - body = Signal(n_body) - self.comb += body.eq(body_) - - words_ = [] - j = 0 - for i in range(n_frame): # iterate over words - if i == 0: # data and checksum - k = n_word - n_checksum - elif i == 1: # marker - words_.append(C(1)) - k = n_word - 1 - elif i < n_frame//2 + 2: # marker - words_.append(C(0)) - k = n_word - 1 - else: # full word - k = n_word - # append corresponding frame body bits - words_.append(body[j:j + k]) - j += k - words_ = Cat(words_) - assert len(words_) == n_frame*n_word - n_checksum - words = Signal(len(words_)) - self.comb += words.eq(words_) - - clk = Signal(n_div, reset=0b1100011) - clk_stb = Signal() - i_frame = Signal(max=n_div*n_frame//2) # DDR - frame_stb = Signal() - sr = [Signal(n_frame*n_div - n_checksum//n_lanes, reset_less=True) - for i in range(n_lanes)] - assert len(Cat(sr)) == len(words) - # DDR bits for each register - ddr_data = Cat([sri[-2] for sri in sr], [sri[-1] for sri in sr]) - self.comb += [ - # assert one cycle ahead - clk_stb.eq(~clk[0] & clk[-1]), - # double period because of DDR - frame_stb.eq(i_frame == n_div*n_frame//2 - 1), - - # LiteETHMACCRCEngine takes data LSB first - self.crc.data[::-1].eq(ddr_data), - self.stb.eq(frame_stb & clk_stb), - ] - miso = Signal() - miso_sr = Signal(n_frame, reset_less=True) - self.sync.rio_phy += [ - # shift 7 bit clock pattern by two bits each DDR cycle - clk.eq(Cat(clk[-2:], clk)), - [sri[2:].eq(sri) for sri in sr], - self.crc.last.eq(self.crc.next), - If(clk[:2] == 0, # TODO: tweak MISO sampling - miso_sr.eq(Cat(miso, miso_sr)), - ), - If(~frame_stb, - i_frame.eq(i_frame + 1), - ), - If(frame_stb & clk_stb, - i_frame.eq(0), - self.crc.last.eq(0), - # transpose, load - Cat(sr).eq(Cat(words[mm::n_lanes] for mm in range(n_lanes))), - Array([self.dat_r[i*n_frame//2:(i + 1)*n_frame//2] - for i in range(1 << len(addr))])[addr].eq(miso_sr), - addr.eq(addr + 1), - ), - If(i_frame == n_div*n_frame//2 - 2, - # inject crc - ddr_data.eq(self.crc.next), - ), - ] - - clk_ddr = Signal() - miso0 = Signal() - self.specials += [ - DDROutput(clk[-1], clk[-2], clk_ddr, ClockSignal("rio_phy")), - DifferentialOutput(clk_ddr, pins.clk, pins_n.clk), - DifferentialInput(pins.miso, pins_n.miso, miso0), - MultiReg(miso0, miso, "rio_phy"), - ] - for sri, ddr, mp, mn in zip( - sr, Signal(n_lanes), pins.mosi, pins_n.mosi): - self.specials += [ - DDROutput(sri[-1], sri[-2], ddr, ClockSignal("rio_phy")), - DifferentialOutput(ddr, mp, mn), - ] +from .fastlink import SerDes, SerInterface class Fastino(Module): @@ -139,9 +14,31 @@ class Fastino(Module): rtlink.OInterface(data_width=max(16*width, 32), address_width=8, enable_replace=False), - rtlink.IInterface(data_width=32)) + rtlink.IInterface(data_width=14)) - self.submodules.serializer = SerDes(pins, pins_n) + self.submodules.serializer = SerDes( + n_data=8, t_clk=7, d_clk=0b1100011, + n_frame=14, n_crc=12, poly=0x80f) + self.submodules.intf = SerInterface(pins, pins_n) + self.comb += [ + Cat(self.intf.data[:-1]).eq(Cat(self.serializer.data[:-1])), + self.serializer.data[-1].eq(self.intf.data[-1]), + ] + + # dac data words + dacs = [Signal(16) for i in range(32)] + header = Record([ + ("cfg", 4), + ("leds", 8), + ("reserved", 8), + ("addr", 4), + ("enable", len(dacs)), + ]) + body = Cat(header.raw_bits(), dacs) + assert len(body) == len(self.serializer.payload) + self.comb += self.serializer.payload.eq(body) + + # # # # Support staging DAC data (in `dacs`) by writing to the # DAC RTIO addresses, if a channel is not "held" by its @@ -164,37 +61,36 @@ class Fastino(Module): # LSBs of the RTIO address for a DAC channel write must be zero and the # address space is sparse. - hold = Signal.like(self.serializer.enable) + hold = Signal.like(header.enable) - # TODO: stb, timestamp - read_regs = Array([ - self.serializer.dat_r[i*7:(i + 1)*7] - for i in range(1 << 4) - ]) + read_regs = Array([Signal.like(self.serializer.readback) + for _ in range(1 << len(header.addr))]) cases = { # update - 0x20: self.serializer.enable.eq(self.serializer.enable | self.rtlink.o.data), + 0x20: header.enable.eq(header.enable | self.rtlink.o.data), # hold 0x21: hold.eq(self.rtlink.o.data), # cfg - 0x22: self.serializer.cfg[:4].eq(self.rtlink.o.data), + 0x22: header.cfg.eq(self.rtlink.o.data), # leds - 0x23: self.serializer.cfg[4:12].eq(self.rtlink.o.data), + 0x23: header.leds.eq(self.rtlink.o.data), # reserved - 0x24: self.serializer.cfg[12:].eq(self.rtlink.o.data), + 0x24: header.reserved.eq(self.rtlink.o.data), } - for i in range(0, len(self.serializer.dacs), width): + for i in range(0, len(dacs), width): cases[i] = [ - Cat(self.serializer.dacs[i:i + width]).eq(self.rtlink.o.data), + Cat(dacs[i:i + width]).eq(self.rtlink.o.data), [If(~hold[i + j], - self.serializer.enable[i + j].eq(1), + header.enable[i + j].eq(1), ) for j in range(width)] ] self.sync.rio_phy += [ If(self.serializer.stb, - self.serializer.enable.eq(0), + header.enable.eq(0), + read_regs[header.addr].eq(self.serializer.readback), + header.addr.eq(header.addr + 1), ), If(self.rtlink.o.stb & ~self.rtlink.o.address[-1], Case(self.rtlink.o.address[:-1], cases), From a27a03ab3cd45145d3b4d2db7ce8c2959f003e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sun, 23 Aug 2020 19:02:39 +0000 Subject: [PATCH 2290/2457] fastlink: fix crc vs data width --- artiq/gateware/rtio/phy/fastlink.py | 2 +- artiq/gateware/rtio/phy/phaser.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/phy/fastlink.py b/artiq/gateware/rtio/phy/fastlink.py index 3f84bb6a8..891df9b06 100644 --- a/artiq/gateware/rtio/phy/fastlink.py +++ b/artiq/gateware/rtio/phy/fastlink.py @@ -100,7 +100,7 @@ class SerDes(Module): ), If(i == t_frame//2 - 2, # inject crc for the last cycle - Cat(crc_data).eq(self.crc.next), + Cat(crc_data[-n_crc:]).eq(self.crc.next), ), ] diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index eb5cb26b2..3ca3c535e 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -46,7 +46,7 @@ class Phaser(Module): header.we.eq(~self.config.o.address[-1]), header.addr.eq(self.config.o.address), header.data.eq(self.config.o.data), - header.type.eq(0), # reserved + header.type.eq(1), # reserved ), ] From 63e4b9532552376a48bbd5b514feadf9c9410088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sun, 23 Aug 2020 19:41:13 +0000 Subject: [PATCH 2291/2457] fastlink: rework crc injection --- artiq/gateware/rtio/phy/fastlink.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/artiq/gateware/rtio/phy/fastlink.py b/artiq/gateware/rtio/phy/fastlink.py index 891df9b06..945075a27 100644 --- a/artiq/gateware/rtio/phy/fastlink.py +++ b/artiq/gateware/rtio/phy/fastlink.py @@ -23,7 +23,7 @@ class SerDes(Module): * `n_crc` CRC bits per frame for divisor poly `poly` """ # pins - self.data = [Signal(2) for _ in range(n_data)] + self.data = [Signal(2, reset_less=True) for _ in range(n_data)] n_mosi = n_data - 2 # mosi lanes n_word = n_mosi*t_clk # bits per word t_frame = t_clk*n_frame # frame duration @@ -48,6 +48,7 @@ class SerDes(Module): # build from LSB to MSB because MSB first for i in range(n_frame): # iterate over words if i == 0: # data and checksum + words_.append(C(0, n_crc)) k = n_word - n_crc elif i == 1: # marker words_.append(C(1)) @@ -61,30 +62,31 @@ class SerDes(Module): words_.append(self.payload[j:j + k]) j += k words_ = Cat(words_) - assert len(words_) == n_frame*n_word - n_crc + assert len(words_) == n_frame*n_word words = Signal(len(words_)) self.comb += words.eq(words_) clk = Signal(t_clk, reset=d_clk) i = Signal(max=t_frame//2) - # big shift register for clk and mosi - sr = [Signal(t_frame - n_crc//n_mosi, reset_less=True) - for i in range(n_mosi)] + # big shift register for mosi and + sr = [Signal(t_frame, reset_less=True) for i in range(n_mosi)] assert len(Cat(sr)) == len(words) - # DDR bits for each register - crc_data = [sri[-2] for sri in sr] + [sri[-1] for sri in sr] + sr_t = [sr[i % n_mosi][i//n_mosi] for i in range(len(words))] + data_t = ([d[0] for d in self.data[:-1]] + + [d[1] for d in self.data[:-1]]) miso_sr = Signal(t_frame, reset_less=True) miso_sr_next = Signal.like(miso_sr) self.comb += [ self.stb.eq(i == t_frame//2 - 1), # LiteETHMACCRCEngine takes data LSB first - self.crc.data.eq(Cat(reversed(crc_data))), + self.crc.data.eq(Cat(reversed(sr_t[-2*n_mosi:]))), miso_sr_next.eq(Cat(self.data[-1], miso_sr)), - [di.eq(sri[-2:]) for di, sri in zip(self.data, [clk] + sr)], ] self.sync.rio_phy += [ # shift everything by two bits - [sri.eq(Cat(sri[-2:], sri)) for sri in [clk] + sr], + [di.eq(sri[-2:]) for di, sri in zip(self.data, [clk] + sr)], + clk.eq(Cat(clk[-2:], clk)), + [sri.eq(Cat(C(0, 2), sri)) for sri in sr], miso_sr.eq(miso_sr_next), self.crc.last.eq(self.crc.next), i.eq(i + 1), @@ -97,10 +99,8 @@ class SerDes(Module): # unload miso self.readback.eq(Cat([miso_sr_next[t_miso + i*t_clk] for i in range(n_frame)])), - ), - If(i == t_frame//2 - 2, # inject crc for the last cycle - Cat(crc_data[-n_crc:]).eq(self.crc.next), + Cat(data_t[-n_crc:]).eq(self.crc.next), ), ] From eb350c3459a97c0276b2d0f138302ead5c098fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kulik?= Date: Mon, 24 Aug 2020 15:32:04 +0200 Subject: [PATCH 2292/2457] Drive SFP0 TX_DISABLE low during startup (as was in Kasli v1.1). Fixes Ethernet on SFP modules with pullup on this line. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Paweł Kulik --- artiq/firmware/runtime/main.rs | 3 +++ artiq/firmware/satman/main.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index fda9d37ba..73660b611 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -107,6 +107,9 @@ fn startup() { io_expander1 = board_misoc::io_expander::IoExpander::new(1); io_expander0.init().expect("I2C I/O expander #0 initialization failed"); io_expander1.init().expect("I2C I/O expander #1 initialization failed"); + io_expander0.set_oe(0, 1 << 1).unwrap(); + io_expander0.set(0, 1, false); + io_expander0.service().unwrap(); } rtio_clocking::init(); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 9e2144370..60f0f4c0a 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -475,6 +475,9 @@ pub extern fn main() -> i32 { io_expander1.set(1, 7, true); io_expander1.service().unwrap(); } + io_expander0.set_oe(0, 1 << 1).unwrap(); + io_expander0.set(0, 1, false); + io_expander0.service().unwrap(); } #[cfg(has_si5324)] From 11c9def5899d0d38cdce23675c05ca003162f59d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 24 Aug 2020 14:49:36 +0000 Subject: [PATCH 2293/2457] phaser: readback delay, test fastlink --- artiq/gateware/rtio/phy/fastlink.py | 6 ++-- artiq/gateware/rtio/phy/phaser.py | 15 ++++---- artiq/gateware/test/rtio/test_fastlink.py | 43 +++++++++++++++++++++++ 3 files changed, 54 insertions(+), 10 deletions(-) create mode 100644 artiq/gateware/test/rtio/test_fastlink.py diff --git a/artiq/gateware/rtio/phy/fastlink.py b/artiq/gateware/rtio/phy/fastlink.py index 945075a27..27f096a04 100644 --- a/artiq/gateware/rtio/phy/fastlink.py +++ b/artiq/gateware/rtio/phy/fastlink.py @@ -114,12 +114,14 @@ class SerInterface(Module): [pins_n.clk] + list(pins_n.mosi)): ddr = Signal() self.specials += [ - DDROutput(d[-1], d[-2], ddr, ClockSignal("rio_phy")), + # d1 closer to q, LSB first + DDROutput(d[1], d[0], ddr, ClockSignal("rio_phy")), DifferentialOutput(ddr, pp, pn), ] ddr = Signal() self.specials += [ DifferentialInput(pins.miso, pins_n.miso, ddr), - DDRInput(ddr, self.data[-1][-1], self.data[-1][-2], + # q1 closer to d, MSB first + DDRInput(ddr, self.data[-1][1], self.data[-1][0], ClockSignal("rio_phy")), ] diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index 3ca3c535e..f50ba111b 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -38,20 +38,19 @@ class Phaser(Module): len(self.serializer.payload) self.comb += self.serializer.payload.eq(Cat(header.raw_bits(), body)) - self.sync.rio_phy += [ + re_dly = Signal(3) # stage, send, respond + self.sync.rtio += [ + header.type.eq(1), # reserved If(self.serializer.stb, header.we.eq(0), + re_dly.eq(re_dly[1:]), ), If(self.config.o.stb, - header.we.eq(~self.config.o.address[-1]), + re_dly[-1].eq(~self.config.o.address[-1]), + header.we.eq(self.config.o.address[-1]), header.addr.eq(self.config.o.address), header.data.eq(self.config.o.data), - header.type.eq(1), # reserved ), - ] - - self.sync.rtio += [ - self.config.i.stb.eq(self.config.o.stb & - self.config.o.address[-1]), + self.config.i.stb.eq(re_dly[0] & self.serializer.stb), self.config.i.data.eq(self.serializer.readback), ] diff --git a/artiq/gateware/test/rtio/test_fastlink.py b/artiq/gateware/test/rtio/test_fastlink.py new file mode 100644 index 000000000..dd95120df --- /dev/null +++ b/artiq/gateware/test/rtio/test_fastlink.py @@ -0,0 +1,43 @@ +import unittest + +from migen import * +from artiq.gateware.rtio.phy.fastlink import * + + + +class TestPhaser(unittest.TestCase): + def setUp(self): + self.dut = SerDes(n_data=8, t_clk=8, d_clk=0b00001111, + n_frame=10, n_crc=6, poly=0x2f) + + def test_init(self): + pass + + def record_frame(self, frame): + clk = 0 + marker = 0 + state = "start" + while True: + clk = (clk << 2) & 0xff + clk |= (yield self.dut.data[0]) + if clk == 0x0f: + marker = (marker << 1) & 0x7f + marker |= (yield self.dut.data[1]) & 1 + if marker >> 1 == 0x01: + if state == "start": + state = "end" + elif state == "end": + break + yield + if state == "end": + data = yield from [(yield d) for d in self.dut.data] + frame.append(data) + + def test_frame(self): + frame = [] + run_simulation(self.dut, self.record_frame(frame), + clocks={n: 2 for n in ["sys", "rio", "rio_phy"]}) + self.assertEqual(len(frame), 8*10//2) + self.assertEqual([d[0] for d in frame], [0, 0, 3, 3] * 10) + self.assertEqual([d[1] & 1 for d in frame[4*4 - 1:10*4 - 1:4]], + [0, 0, 0, 0, 0, 1]) From bcefb06e194b62ba731c2bba7a0e5f7066e9c917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 24 Aug 2020 14:51:50 +0000 Subject: [PATCH 2294/2457] phaser: ddb template, split crc --- artiq/frontend/artiq_ddb_template.py | 12 +++++++++ artiq/gateware/rtio/phy/fastlink.py | 30 ++++++++++++++--------- artiq/gateware/test/rtio/test_fastlink.py | 16 ++++++------ 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 052673e03..86452c607 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -485,6 +485,18 @@ class PeripheralManager: channel=rtio_offset) return 1 + def process_phaser(self, rtio_offset, peripheral): + self.gen(""" + device_db["{name}"] = {{ + "type": "local", + "module": "artiq.coredevice.phaser", + "class": "Phaser", + "arguments": {{"channel": 0x{channel:06x}}} + }}""", + name=self.get_name("phaser"), + channel=rtio_offset) + return 2 + def process(self, rtio_offset, peripheral): processor = getattr(self, "process_"+str(peripheral["type"])) return processor(rtio_offset, peripheral) diff --git a/artiq/gateware/rtio/phy/fastlink.py b/artiq/gateware/rtio/phy/fastlink.py index 27f096a04..a7003c15e 100644 --- a/artiq/gateware/rtio/phy/fastlink.py +++ b/artiq/gateware/rtio/phy/fastlink.py @@ -30,6 +30,7 @@ class SerDes(Module): n_marker = n_frame//2 + 1 n_body = n_word*n_frame - n_marker - n_crc t_miso = 0 # miso sampling latency TODO + assert n_crc % n_mosi == 0 # frame data self.payload = Signal(n_body) @@ -40,8 +41,10 @@ class SerDes(Module): # # # - self.submodules.crc = LiteEthMACCRCEngine( - data_width=2*n_mosi, width=n_crc, polynom=poly) + self.submodules.crca = LiteEthMACCRCEngine( + data_width=n_mosi, width=n_crc, polynom=poly) + self.submodules.crcb = LiteEthMACCRCEngine( + data_width=n_mosi, width=n_crc, polynom=poly) words_ = [] j = 0 @@ -71,15 +74,17 @@ class SerDes(Module): # big shift register for mosi and sr = [Signal(t_frame, reset_less=True) for i in range(n_mosi)] assert len(Cat(sr)) == len(words) - sr_t = [sr[i % n_mosi][i//n_mosi] for i in range(len(words))] - data_t = ([d[0] for d in self.data[:-1]] + - [d[1] for d in self.data[:-1]]) + crc_insert = ([d[1] for d in self.data[:-1]] + + [d[0] for d in self.data[:-1]]) + crc_insert = Cat(crc_insert[-n_crc:]) miso_sr = Signal(t_frame, reset_less=True) miso_sr_next = Signal.like(miso_sr) self.comb += [ self.stb.eq(i == t_frame//2 - 1), # LiteETHMACCRCEngine takes data LSB first - self.crc.data.eq(Cat(reversed(sr_t[-2*n_mosi:]))), + self.crca.data.eq(Cat([sri[-1] for sri in sr[::-1]])), + self.crcb.data.eq(Cat([sri[-2] for sri in sr[::-1]])), + self.crcb.last.eq(self.crca.next), miso_sr_next.eq(Cat(self.data[-1], miso_sr)), ] self.sync.rio_phy += [ @@ -88,19 +93,20 @@ class SerDes(Module): clk.eq(Cat(clk[-2:], clk)), [sri.eq(Cat(C(0, 2), sri)) for sri in sr], miso_sr.eq(miso_sr_next), - self.crc.last.eq(self.crc.next), + self.crca.last.eq(self.crcb.next), i.eq(i + 1), If(self.stb, i.eq(0), clk.eq(clk.reset), - self.crc.last.eq(0), + self.crca.last.eq(0), # transpose, load [sri.eq(Cat(words[i::n_mosi])) for i, sri in enumerate(sr)], # unload miso self.readback.eq(Cat([miso_sr_next[t_miso + i*t_clk] for i in range(n_frame)])), # inject crc for the last cycle - Cat(data_t[-n_crc:]).eq(self.crc.next), + crc_insert.eq(self.crca.next if n_crc // n_mosi == 1 + else self.crcb.next), ), ] @@ -114,14 +120,14 @@ class SerInterface(Module): [pins_n.clk] + list(pins_n.mosi)): ddr = Signal() self.specials += [ - # d1 closer to q, LSB first + # d1 closer to q DDROutput(d[1], d[0], ddr, ClockSignal("rio_phy")), DifferentialOutput(ddr, pp, pn), ] ddr = Signal() self.specials += [ DifferentialInput(pins.miso, pins_n.miso, ddr), - # q1 closer to d, MSB first - DDRInput(ddr, self.data[-1][1], self.data[-1][0], + # q1 closer to d + DDRInput(ddr, self.data[-1][0], self.data[-1][1], ClockSignal("rio_phy")), ] diff --git a/artiq/gateware/test/rtio/test_fastlink.py b/artiq/gateware/test/rtio/test_fastlink.py index dd95120df..5b62c9aba 100644 --- a/artiq/gateware/test/rtio/test_fastlink.py +++ b/artiq/gateware/test/rtio/test_fastlink.py @@ -16,27 +16,27 @@ class TestPhaser(unittest.TestCase): def record_frame(self, frame): clk = 0 marker = 0 - state = "start" + stb = 0 while True: + if stb == 2: + frame.append((yield self.dut.data)) clk = (clk << 2) & 0xff clk |= (yield self.dut.data[0]) if clk == 0x0f: marker = (marker << 1) & 0x7f marker |= (yield self.dut.data[1]) & 1 if marker >> 1 == 0x01: - if state == "start": - state = "end" - elif state == "end": + stb += 1 + if stb >= 3: break yield - if state == "end": - data = yield from [(yield d) for d in self.dut.data] - frame.append(data) def test_frame(self): frame = [] + self.dut.comb += self.dut.payload.eq((1 << len(self.dut.payload)) - 1) run_simulation(self.dut, self.record_frame(frame), - clocks={n: 2 for n in ["sys", "rio", "rio_phy"]}) + clocks={n: 2 for n in ["sys", "rio", "rio_phy"]}, + vcd_name="fastlink.vcd") self.assertEqual(len(frame), 8*10//2) self.assertEqual([d[0] for d in frame], [0, 0, 3, 3] * 10) self.assertEqual([d[1] & 1 for d in frame[4*4 - 1:10*4 - 1:4]], From 20fcfd95e9b3aef2faecc19dad13851132419207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 24 Aug 2020 15:46:31 +0000 Subject: [PATCH 2295/2457] phaser: coredevice shim, readback fix --- artiq/coredevice/phaser.py | 45 ++++++++++++++++++++++++++++ artiq/frontend/artiq_ddb_template.py | 5 +++- artiq/gateware/rtio/phy/fastlink.py | 6 ++-- artiq/gateware/rtio/phy/phaser.py | 3 +- 4 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 artiq/coredevice/phaser.py diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py new file mode 100644 index 000000000..9ebd86d74 --- /dev/null +++ b/artiq/coredevice/phaser.py @@ -0,0 +1,45 @@ +from artiq.language.core import kernel, portable, delay +from artiq.coredevice.rtio import rtio_output, rtio_input_data +from artiq.language.units import us +from artiq.language.types import TInt32, TList, TFloat + + +PHASER_ADDR_BOARD_ID = 0x00 +PHASER_BOARD_ID = 19 + +class Phaser: + kernel_invariants = {"core", "channel_base"} + + def __init__(self, dmgr, channel_base, readback_delay=1, + core_device="core"): + self.channel_base = channel_base << 8 + self.core = dmgr.get(core_device) + self.readback_delay = readback_delay + + @kernel + def init(self): + board_id = self.read(PHASER_ADDR_BOARD_ID) + if board_id != PHASER_BOARD_ID: + raise ValueError("invalid board id") + + @kernel + def write(self, addr, data): + """Write data to a Fastino register. + + :param addr: Address to write to. + :param data: Data to write. + """ + rtio_output(self.channel_base | addr | 0x80, data) + + @kernel + def read(self, addr): + """Read from Fastino register. + + TODO: untested + + :param addr: Address to read from. + :return: The data read. + """ + rtio_output(self.channel_base | addr, 0) + response = rtio_input_data(self.channel_base >> 8) + return response >> self.readback_delay diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 86452c607..8a3122f9b 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -491,7 +491,10 @@ class PeripheralManager: "type": "local", "module": "artiq.coredevice.phaser", "class": "Phaser", - "arguments": {{"channel": 0x{channel:06x}}} + "arguments": {{ + "channel_base": 0x{channel:06x}, + "readback_delay": 1, + }} }}""", name=self.get_name("phaser"), channel=rtio_offset) diff --git a/artiq/gateware/rtio/phy/fastlink.py b/artiq/gateware/rtio/phy/fastlink.py index a7003c15e..0c361b901 100644 --- a/artiq/gateware/rtio/phy/fastlink.py +++ b/artiq/gateware/rtio/phy/fastlink.py @@ -86,6 +86,9 @@ class SerDes(Module): self.crcb.data.eq(Cat([sri[-2] for sri in sr[::-1]])), self.crcb.last.eq(self.crca.next), miso_sr_next.eq(Cat(self.data[-1], miso_sr)), + # unload miso + self.readback.eq(Cat([miso_sr_next[t_miso + i*t_clk] + for i in range(n_frame)])), ] self.sync.rio_phy += [ # shift everything by two bits @@ -101,9 +104,6 @@ class SerDes(Module): self.crca.last.eq(0), # transpose, load [sri.eq(Cat(words[i::n_mosi])) for i, sri in enumerate(sr)], - # unload miso - self.readback.eq(Cat([miso_sr_next[t_miso + i*t_clk] - for i in range(n_frame)])), # inject crc for the last cycle crc_insert.eq(self.crca.next if n_crc // n_mosi == 1 else self.crcb.next), diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index f50ba111b..19390f51d 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -32,8 +32,7 @@ class Phaser(Module): n_channels = 2 n_samples = 8 n_bits = 14 - body = [[(Signal(n_bits), Signal(n_bits)) - for i in range(n_channels)] for j in range(n_samples)] + body = [Signal(n_bits) for i in range(n_channels*n_samples*2)] assert len(Cat(header.raw_bits(), body)) == \ len(self.serializer.payload) self.comb += self.serializer.payload.eq(Cat(header.raw_bits(), body)) From cfddc1329410b135f480b0a40e8108e43da060d1 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Tue, 18 Aug 2020 16:29:28 +0800 Subject: [PATCH 2296/2457] test: fixed test_performance Added more tests and use normal rpc instead of async rpc. Async RPC does not represent the real throughput which is limited by the hardware and the network. Normal RPC which requires a response from the remote is closer to real usecases. --- artiq/test/coredevice/test_performance.py | 87 ++++++++++++++++++++--- 1 file changed, 79 insertions(+), 8 deletions(-) diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index 071c5d27c..c9ab98b01 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -1,6 +1,7 @@ import os import time import unittest +import numpy from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase @@ -15,13 +16,29 @@ class _Transfer(EnvExperiment): def source(self) -> TBytes: return self.data - @rpc(flags={"async"}) - def sink(self, data): - assert data == self.data + @rpc + def source_byte_list(self) -> TList(TBool): + return [True] * (1 << 15) - @rpc(flags={"async"}) + @rpc + def source_list(self) -> TList(TInt32): + return [123] * (1 << 15) + + @rpc + def source_array(self) -> TArray(TInt32): + return numpy.array([0] * (1 << 15), numpy.int32) + + @rpc + def sink(self, data): + pass + + @rpc + def sink_list(self, data): + pass + + @rpc def sink_array(self, data): - assert data == [0]*(1 << 15) + pass @kernel def host_to_device(self): @@ -30,6 +47,27 @@ class _Transfer(EnvExperiment): t1 = self.core.get_rtio_counter_mu() return len(data)/self.core.mu_to_seconds(t1-t0) + @kernel + def host_to_device_list(self): + t0 = self.core.get_rtio_counter_mu() + data = self.source_list() + t1 = self.core.get_rtio_counter_mu() + return 4 * len(data)/self.core.mu_to_seconds(t1-t0) + + @kernel + def host_to_device_array(self): + t0 = self.core.get_rtio_counter_mu() + data = self.source_array() + t1 = self.core.get_rtio_counter_mu() + return 4 * len(data)/self.core.mu_to_seconds(t1-t0) + + @kernel + def host_to_device_byte_list(self): + t0 = self.core.get_rtio_counter_mu() + data = self.source_byte_list() + t1 = self.core.get_rtio_counter_mu() + return len(data)/self.core.mu_to_seconds(t1-t0) + @kernel def device_to_host(self): t0 = self.core.get_rtio_counter_mu() @@ -38,14 +76,23 @@ class _Transfer(EnvExperiment): return len(self.data)/self.core.mu_to_seconds(t1-t0) @kernel - def device_to_host_array(self): + def device_to_host_list(self): #data = [[0]*8 for _ in range(1 << 12)] data = [0]*(1 << 15) t0 = self.core.get_rtio_counter_mu() + self.sink_list(data) + t1 = self.core.get_rtio_counter_mu() + return ((len(data)*4) / + self.core.mu_to_seconds(t1-t0)) + + @kernel + def device_to_host_array(self): + data = self.source_array() + t0 = self.core.get_rtio_counter_mu() self.sink_array(data) t1 = self.core.get_rtio_counter_mu() - return ((len(data)*4)/ - self.core.mu_to_seconds(t1-t0)) + return ((len(data)*4) / + self.core.mu_to_seconds(t1-t0)) class TransferTest(ExperimentCase): @@ -55,12 +102,36 @@ class TransferTest(ExperimentCase): print(host_to_device_rate/(1024*1024), "MiB/s") self.assertGreater(host_to_device_rate, 2.0e6) + def test_host_to_device_byte_list(self): + exp = self.create(_Transfer) + host_to_device_rate = exp.host_to_device_byte_list() + print(host_to_device_rate/(1024*1024), "MiB/s") + self.assertGreater(host_to_device_rate, 2.0e6) + + def test_host_to_device_list(self): + exp = self.create(_Transfer) + host_to_device_rate = exp.host_to_device_list() + print(host_to_device_rate/(1024*1024), "MiB/s") + self.assertGreater(host_to_device_rate, 2.0e6) + + def test_host_to_device_array(self): + exp = self.create(_Transfer) + host_to_device_rate = exp.host_to_device_array() + print(host_to_device_rate/(1024*1024), "MiB/s") + self.assertGreater(host_to_device_rate, 2.0e6) + def test_device_to_host(self): exp = self.create(_Transfer) device_to_host_rate = exp.device_to_host() print(device_to_host_rate/(1024*1024), "MiB/s") self.assertGreater(device_to_host_rate, 2.2e6) + def test_device_to_host_list(self): + exp = self.create(_Transfer) + rate = exp.device_to_host_list() + print(rate/(1024*1024), "MiB/s") + self.assertGreater(rate, .15e6) + def test_device_to_host_array(self): exp = self.create(_Transfer) rate = exp.device_to_host_array() From 7181ff66a6fd7b3aecddf752b6c3eff5fddf5a7d Mon Sep 17 00:00:00 2001 From: pca006132 Date: Tue, 18 Aug 2020 17:01:28 +0800 Subject: [PATCH 2297/2457] compiler: improved rpc performance for list and array 1. Removed duplicated tags before each elements. 2. Use numpy functions to speedup parsing. --- artiq/coredevice/comm_kernel.py | 228 ++++++++++++++++++++++---------- 1 file changed, 158 insertions(+), 70 deletions(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 41bddd553..b28f79272 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -43,9 +43,11 @@ class Reply(Enum): class UnsupportedDevice(Exception): pass + class LoadError(Exception): pass + class RPCReturnValueError(ValueError): pass @@ -53,6 +55,105 @@ class RPCReturnValueError(ValueError): RPCKeyword = namedtuple('RPCKeyword', ['name', 'value']) +def _receive_fraction(kernel, embedding_map): + numerator = kernel._read_int64() + denominator = kernel._read_int64() + return Fraction(numerator, denominator) + + +def _receive_list(kernel, embedding_map): + length = kernel._read_int32() + tag = chr(kernel._read_int8()) + if tag == "b": + buffer = kernel._read(length) + return numpy.ndarray((length, ), 'B', buffer).tolist() + elif tag == "i": + buffer = kernel._read(4 * length) + return numpy.ndarray((length, ), '>i4', buffer).tolist() + elif tag == "I": + buffer = kernel._read(8 * length) + return numpy.ndarray((length, ), '>i8', buffer).tolist() + elif tag == "f": + buffer = kernel._read(8 * length) + return numpy.ndarray((length, ), '>d', buffer).tolist() + else: + fn = receivers[tag] + elems = [] + for _ in range(length): + # discard tag, as our device would still send the tag for each + # non-primitive elements. + kernel._read_int8() + item = fn(kernel, embedding_map) + elems.append(item) + return elems + + +def _receive_array(kernel, embedding_map): + num_dims = kernel._read_int8() + shape = tuple(kernel._read_int32() for _ in range(num_dims)) + tag = chr(kernel._read_int8()) + fn = receivers[tag] + length = numpy.prod(shape) + if tag == "b": + buffer = kernel._read(length) + elems = numpy.ndarray((length, ), 'B', buffer) + elif tag == "i": + buffer = kernel._read(4 * length) + elems = numpy.ndarray((length, ), '>i4', buffer) + elif tag == "I": + buffer = kernel._read(8 * length) + elems = numpy.ndarray((length, ), '>i8', buffer) + elif tag == "f": + buffer = kernel._read(8 * length) + elems = numpy.ndarray((length, ), '>d', buffer) + else: + fn = receivers[tag] + elems = [] + for _ in range(numpy.prod(shape)): + # discard the tag + kernel._read_int8() + item = fn(kernel, embedding_map) + elems.append(item) + elems = numpy.array(elems) + return elems.reshape(shape) + + +def _receive_range(kernel, embedding_map): + start = kernel._receive_rpc_value(embedding_map) + stop = kernel._receive_rpc_value(embedding_map) + step = kernel._receive_rpc_value(embedding_map) + return range(start, stop, step) + + +def _receive_keyword(kernel, embedding_map): + name = kernel._read_string() + value = kernel._receive_rpc_value(embedding_map) + return RPCKeyword(name, value) + + +receivers = { + "\x00": lambda kernel, embedding_map: kernel._rpc_sentinel, + "t": lambda kernel, embedding_map: + tuple(kernel._receive_rpc_value(embedding_map) + for _ in range(kernel._read_int8())), + "n": lambda kernel, embedding_map: None, + "b": lambda kernel, embedding_map: bool(kernel._read_int8()), + "i": lambda kernel, embedding_map: numpy.int32(kernel._read_int32()), + "I": lambda kernel, embedding_map: numpy.int32(kernel._read_int64()), + "f": lambda kernel, embedding_map: kernel._read_float64(), + "s": lambda kernel, embedding_map: kernel._read_string(), + "B": lambda kernel, embedding_map: kernel._read_bytes(), + "A": lambda kernel, embedding_map: kernel._read_bytes(), + "O": lambda kernel, embedding_map: + embedding_map.retrieve_object(kernel._read_int32()), + "F": _receive_fraction, + "l": _receive_list, + "a": _receive_array, + "r": _receive_range, + "k": _receive_keyword +} + + class CommKernelDummy: def __init__(self): pass @@ -247,50 +348,8 @@ class CommKernel: # See rpc_proto.rs and compiler/ir.py:rpc_tag. def _receive_rpc_value(self, embedding_map): tag = chr(self._read_int8()) - if tag == "\x00": - return self._rpc_sentinel - elif tag == "t": - length = self._read_int8() - return tuple(self._receive_rpc_value(embedding_map) for _ in range(length)) - elif tag == "n": - return None - elif tag == "b": - return bool(self._read_int8()) - elif tag == "i": - return numpy.int32(self._read_int32()) - elif tag == "I": - return numpy.int64(self._read_int64()) - elif tag == "f": - return self._read_float64() - elif tag == "F": - numerator = self._read_int64() - denominator = self._read_int64() - return Fraction(numerator, denominator) - elif tag == "s": - return self._read_string() - elif tag == "B": - return self._read_bytes() - elif tag == "A": - return self._read_bytes() - elif tag == "l": - length = self._read_int32() - return [self._receive_rpc_value(embedding_map) for _ in range(length)] - elif tag == "a": - num_dims = self._read_int8() - shape = tuple(self._read_int32() for _ in range(num_dims)) - elems = [self._receive_rpc_value(embedding_map) for _ in range(numpy.prod(shape))] - return numpy.array(elems).reshape(shape) - elif tag == "r": - start = self._receive_rpc_value(embedding_map) - stop = self._receive_rpc_value(embedding_map) - step = self._receive_rpc_value(embedding_map) - return range(start, stop, step) - elif tag == "k": - name = self._read_string() - value = self._receive_rpc_value(embedding_map) - return RPCKeyword(name, value) - elif tag == "O": - return embedding_map.retrieve_object(self._read_int32()) + if tag in receivers: + return receivers.get(tag)(self, embedding_map) else: raise IOError("Unknown RPC value tag: {}".format(repr(tag))) @@ -357,8 +416,8 @@ class CommKernel: self._write_float64(value) elif tag == "F": check(isinstance(value, Fraction) and - (-2**63 < value.numerator < 2**63-1) and - (-2**63 < value.denominator < 2**63-1), + (-2**63 < value.numerator < 2**63-1) and + (-2**63 < value.denominator < 2**63-1), lambda: "64-bit Fraction") self._write_int64(value.numerator) self._write_int64(value.denominator) @@ -378,21 +437,47 @@ class CommKernel: check(isinstance(value, list), lambda: "list") self._write_int32(len(value)) - for elt in value: - tags_copy = bytearray(tags) - self._send_rpc_value(tags_copy, elt, root, function) + tag_element = chr(tags[0]) + if tag_element == "b": + self._write(bytes(value)) + elif tag_element == "i": + array = numpy.array(value, '>i4') + self._write(array.tobytes()) + elif tag_element == "I": + array = numpy.array(value, '>i8') + self._write(array.tobytes()) + elif tag_element == "f": + array = numpy.array(value, '>d') + self._write(array.tobytes()) + else: + for elt in value: + tags_copy = bytearray(tags) + self._send_rpc_value(tags_copy, elt, root, function) self._skip_rpc_value(tags) elif tag == "a": check(isinstance(value, numpy.ndarray), lambda: "numpy.ndarray") num_dims = tags.pop(0) check(num_dims == len(value.shape), - lambda: "{}-dimensional numpy.ndarray".format(num_dims)) + lambda: "{}-dimensional numpy.ndarray".format(num_dims)) for s in value.shape: self._write_int32(s) - for elt in value.reshape((-1,), order="C"): - tags_copy = bytearray(tags) - self._send_rpc_value(tags_copy, elt, root, function) + tag_element = chr(tags[0]) + if tag_element == "b": + self._write(value.reshape((-1,), order="C").tobytes()) + elif tag_element == "i": + array = value.reshape((-1,), order="C").astype('>i4') + self._write(array.tobytes()) + elif tag_element == "I": + array = value.reshape((-1,), order="C").astype('>i8') + self._write(array.tobytes()) + elif tag_element == "f": + array = value.reshape((-1,), order="C").astype('>d') + self._write(array.tobytes()) + else: + for elt in value.reshape((-1,), order="C"): + tags_copy = bytearray(tags) + self._send_rpc_value(tags_copy, elt, root, function) self._skip_rpc_value(tags) elif tag == "r": check(isinstance(value, range), @@ -414,15 +499,15 @@ class CommKernel: return msg def _serve_rpc(self, embedding_map): - is_async = self._read_bool() - service_id = self._read_int32() + is_async = self._read_bool() + service_id = self._read_int32() args, kwargs = self._receive_rpc_args(embedding_map) - return_tags = self._read_bytes() + return_tags = self._read_bytes() if service_id == 0: - service = lambda obj, attr, value: setattr(obj, attr, value) + def service(obj, attr, value): return setattr(obj, attr, value) else: - service = embedding_map.retrieve_object(service_id) + service = embedding_map.retrieve_object(service_id) logger.debug("rpc service: [%d]%r%s %r %r -> %s", service_id, service, (" (async)" if is_async else ""), args, kwargs, return_tags) @@ -432,15 +517,18 @@ class CommKernel: try: result = service(*args, **kwargs) - logger.debug("rpc service: %d %r %r = %r", service_id, args, kwargs, result) + logger.debug("rpc service: %d %r %r = %r", + service_id, args, kwargs, result) self._write_header(Request.RPCReply) self._write_bytes(return_tags) - self._send_rpc_value(bytearray(return_tags), result, result, service) + self._send_rpc_value(bytearray(return_tags), + result, result, service) except RPCReturnValueError as exn: raise except Exception as exn: - logger.debug("rpc service: %d %r %r ! %r", service_id, args, kwargs, exn) + logger.debug("rpc service: %d %r %r ! %r", + service_id, args, kwargs, exn) self._write_header(Request.RPCException) @@ -479,23 +567,23 @@ class CommKernel: assert False self._write_string(filename) self._write_int32(line) - self._write_int32(-1) # column not known + self._write_int32(-1) # column not known self._write_string(function) def _serve_exception(self, embedding_map, symbolizer, demangler): - name = self._read_string() - message = self._read_string() - params = [self._read_int64() for _ in range(3)] + name = self._read_string() + message = self._read_string() + params = [self._read_int64() for _ in range(3)] - filename = self._read_string() - line = self._read_int32() - column = self._read_int32() - function = self._read_string() + filename = self._read_string() + line = self._read_int32() + column = self._read_int32() + function = self._read_string() backtrace = [self._read_int32() for _ in range(self._read_int32())] traceback = list(reversed(symbolizer(backtrace))) + \ - [(filename, line, column, *demangler([function]), None)] + [(filename, line, column, *demangler([function]), None)] core_exn = exceptions.CoreException(name, message, params, traceback) if core_exn.id == 0: From aac2194759892b8f384be4bb606ba2f21251b7ba Mon Sep 17 00:00:00 2001 From: pca006132 Date: Wed, 26 Aug 2020 11:32:11 +0800 Subject: [PATCH 2298/2457] Ported rpc changes to or1k --- artiq/firmware/libproto_artiq/lib.rs | 1 + artiq/firmware/libproto_artiq/rpc_proto.rs | 105 +++++++++++++++++++-- 2 files changed, 97 insertions(+), 9 deletions(-) diff --git a/artiq/firmware/libproto_artiq/lib.rs b/artiq/firmware/libproto_artiq/lib.rs index d8cbfe607..66c04d5e6 100644 --- a/artiq/firmware/libproto_artiq/lib.rs +++ b/artiq/firmware/libproto_artiq/lib.rs @@ -11,6 +11,7 @@ extern crate cslice; #[macro_use] extern crate log; +extern crate byteorder; extern crate io; extern crate dyld; diff --git a/artiq/firmware/libproto_artiq/rpc_proto.rs b/artiq/firmware/libproto_artiq/rpc_proto.rs index b35e6b905..84296a62c 100644 --- a/artiq/firmware/libproto_artiq/rpc_proto.rs +++ b/artiq/firmware/libproto_artiq/rpc_proto.rs @@ -1,6 +1,7 @@ use core::str; +use core::slice; use cslice::{CSlice, CMutSlice}; - +use byteorder::{NetworkEndian, ByteOrder}; use io::{ProtoRead, Read, Write, ProtoWrite, Error}; use self::tag::{Tag, TagIterator, split_tag}; @@ -53,13 +54,34 @@ unsafe fn recv_value(reader: &mut R, tag: Tag, data: &mut *mut (), struct List { elements: *mut (), length: u32 }; consume_value!(List, |ptr| { (*ptr).length = reader.read_u32()?; + let length = (*ptr).length as usize; let tag = it.clone().next().expect("truncated tag"); (*ptr).elements = alloc(tag.size() * (*ptr).length as usize)?; let mut data = (*ptr).elements; - for _ in 0..(*ptr).length as usize { - recv_value(reader, tag, &mut data, alloc)? + match tag { + Tag::Bool => { + let dest = slice::from_raw_parts_mut(data as *mut u8, length); + reader.read_exact(dest)?; + }, + Tag::Int32 => { + let dest = slice::from_raw_parts_mut(data as *mut u8, length * 4); + reader.read_exact(dest)?; + let dest = slice::from_raw_parts_mut(data as *mut i32, length); + NetworkEndian::from_slice_i32(dest); + }, + Tag::Int64 | Tag::Float64 => { + let dest = slice::from_raw_parts_mut(data as *mut u8, length * 8); + reader.read_exact(dest)?; + let dest = slice::from_raw_parts_mut(data as *mut i64, length); + NetworkEndian::from_slice_i64(dest); + }, + _ => { + for _ in 0..length { + recv_value(reader, tag, &mut data, alloc)? + } + } } Ok(()) }) @@ -72,13 +94,34 @@ unsafe fn recv_value(reader: &mut R, tag: Tag, data: &mut *mut (), total_len *= len; consume_value!(u32, |ptr| *ptr = len ) } + let length = total_len as usize; let elt_tag = it.clone().next().expect("truncated tag"); *buffer = alloc(elt_tag.size() * total_len as usize)?; let mut data = *buffer; - for _ in 0..total_len { - recv_value(reader, elt_tag, &mut data, alloc)? + match elt_tag { + Tag::Bool => { + let dest = slice::from_raw_parts_mut(data as *mut u8, length); + reader.read_exact(dest)?; + }, + Tag::Int32 => { + let dest = slice::from_raw_parts_mut(data as *mut u8, length * 4); + reader.read_exact(dest)?; + let dest = slice::from_raw_parts_mut(data as *mut i32, length); + NetworkEndian::from_slice_i32(dest); + }, + Tag::Int64 | Tag::Float64 => { + let dest = slice::from_raw_parts_mut(data as *mut u8, length * 8); + reader.read_exact(dest)?; + let dest = slice::from_raw_parts_mut(data as *mut i64, length); + NetworkEndian::from_slice_i64(dest); + }, + _ => { + for _ in 0..length { + recv_value(reader, elt_tag, &mut data, alloc)? + } + } } Ok(()) }) @@ -155,11 +198,33 @@ unsafe fn send_value(writer: &mut W, tag: Tag, data: &mut *const ()) #[repr(C)] struct List { elements: *const (), length: u32 }; consume_value!(List, |ptr| { + let length = (*ptr).length as usize; writer.write_u32((*ptr).length)?; let tag = it.clone().next().expect("truncated tag"); let mut data = (*ptr).elements; - for _ in 0..(*ptr).length as usize { - send_value(writer, tag, &mut data)?; + writer.write_u8(tag.as_u8())?; + match tag { + Tag::Bool => { + let slice = slice::from_raw_parts(data as *const u8, length); + writer.write_all(slice)?; + }, + Tag::Int32 => { + let slice = slice::from_raw_parts(data as *const u32, length); + for v in slice.iter() { + writer.write_u32(*v)?; + } + }, + Tag::Int64 | Tag::Float64 => { + let slice = slice::from_raw_parts(data as *const u64, length); + for v in slice.iter() { + writer.write_u64(*v)?; + } + }, + _ => { + for _ in 0..length { + send_value(writer, tag, &mut data)?; + } + } } Ok(()) }) @@ -176,9 +241,31 @@ unsafe fn send_value(writer: &mut W, tag: Tag, data: &mut *const ()) total_len *= *len; }) } + let length = total_len as usize; let mut data = *buffer; - for _ in 0..total_len as usize { - send_value(writer, elt_tag, &mut data)?; + writer.write_u8(elt_tag.as_u8())?; + match elt_tag { + Tag::Bool => { + let slice = slice::from_raw_parts(data as *const u8, length); + writer.write_all(slice)?; + }, + Tag::Int32 => { + let slice = slice::from_raw_parts(data as *const u32, length); + for v in slice.iter() { + writer.write_u32(*v)?; + } + }, + Tag::Int64 | Tag::Float64 => { + let slice = slice::from_raw_parts(data as *const u64, length); + for v in slice.iter() { + writer.write_u64(*v)?; + } + }, + _ => { + for _ in 0..length { + send_value(writer, elt_tag, &mut data)?; + } + } } Ok(()) }) From 26bc5d24058c36c85dea6328ee4207fcbd5e6fc1 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Wed, 26 Aug 2020 12:12:33 +0800 Subject: [PATCH 2299/2457] Updated release notes --- RELEASE_NOTES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 7b9899d71..c6970f71d 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -11,6 +11,7 @@ Highlights: * Performance improvements: - #1432: SERDES TTL inputs can now detect edges on pulses that are shorter than the RTIO period + - Improved performance for kernel RPC involving list and array. * Coredevice SI to mu conversions now always return valid codes, or raise a `ValueError`. * Zotino now exposes `voltage_to_mu()` * `ad9910`: The maximum amplitude scale factor is now `0x3fff` (was `0x3ffe` From d1be1212ab939d1506de7d5dca303fcc06fabfd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 26 Aug 2020 15:10:50 +0000 Subject: [PATCH 2300/2457] phaser: coredevice shim, dds [wip] --- artiq/coredevice/phaser.py | 176 +++++++++++++++++++++++++-- artiq/frontend/artiq_ddb_template.py | 2 +- artiq/gateware/eem.py | 5 +- artiq/gateware/rtio/phy/phaser.py | 31 +++-- 4 files changed, 190 insertions(+), 24 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 9ebd86d74..bce26882d 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -1,39 +1,80 @@ -from artiq.language.core import kernel, portable, delay +import numpy as np + +from artiq.language.core import kernel, delay_mu, delay from artiq.coredevice.rtio import rtio_output, rtio_input_data -from artiq.language.units import us -from artiq.language.types import TInt32, TList, TFloat +from artiq.language.units import us, ns +from artiq.language.types import TInt32 -PHASER_ADDR_BOARD_ID = 0x00 PHASER_BOARD_ID = 19 +PHASER_ADDR_BOARD_ID = 0x00 +PHASER_ADDR_HW_REV = 0x01 +PHASER_ADDR_GW_REV = 0x02 +PHASER_ADDR_CFG = 0x03 +PHASER_ADDR_STA = 0x04 +PHASER_ADDR_CRC_ERR = 0x05 +PHASER_ADDR_LED = 0x06 +PHASER_ADDR_FAN = 0x07 +PHASER_ADDR_DUC_STB = 0x08 +PHASER_ADDR_ADC_CFG = 0x09 +PHASER_ADDR_SPI_CFG = 0x0a +PHASER_ADDR_SPI_DIV = 0x0b +PHASER_ADDR_SPI_SEL = 0x0c +PHASER_ADDR_SPI_DATW = 0x0d +PHASER_ADDR_SPI_DATR = 0x0e +# PHASER_ADDR_RESERVED0 = 0x0f +PHASER_ADDR_DUC0_CFG = 0x10 +# PHASER_ADDR_DUC0_RESERVED0 = 0x11 +PHASER_ADDR_DUC0_F = 0x12 +PHASER_ADDR_DUC0_P = 0x16 +PHASER_ADDR_DAC0_DATA = 0x18 +PHASER_ADDR_DAC0_TEST = 0x1c +PHASER_ADDR_DUC1_CFG = 0x20 +# PHASER_ADDR_DUC1_RESERVED0 = 0x21 +PHASER_ADDR_DUC1_F = 0x22 +PHASER_ADDR_DUC1_P = 0x26 +PHASER_ADDR_DAC1_DATA = 0x28 +PHASER_ADDR_DAC1_TEST = 0x2c + +PHASER_SEL_DAC = 1 << 0 +PHASER_SEL_TRF0 = 1 << 1 +PHASER_SEL_TRF1 = 1 << 2 +PHASER_SEL_ATT0 = 1 << 3 +PHASER_SEL_ATT1 = 1 << 4 + class Phaser: - kernel_invariants = {"core", "channel_base"} + kernel_invariants = {"core", "channel_base", "t_frame"} - def __init__(self, dmgr, channel_base, readback_delay=1, + def __init__(self, dmgr, channel_base, miso_delay=1, core_device="core"): self.channel_base = channel_base << 8 self.core = dmgr.get(core_device) - self.readback_delay = readback_delay + self.miso_delay = miso_delay + # frame duration in mu (10 words, 8 clock cycles each 4 ns) + # self.core.seconds_to_mu(10*8*4*ns) # unfortunately 319 + self.t_frame = 10*8*4 @kernel def init(self): board_id = self.read(PHASER_ADDR_BOARD_ID) if board_id != PHASER_BOARD_ID: raise ValueError("invalid board id") + delay(20*us) @kernel def write(self, addr, data): - """Write data to a Fastino register. + """Write data to a Phaser FPGA register. :param addr: Address to write to. :param data: Data to write. """ rtio_output(self.channel_base | addr | 0x80, data) + delay_mu(int64(self.t_frame)) @kernel def read(self, addr): - """Read from Fastino register. + """Read from Phaser FPGA register. TODO: untested @@ -42,4 +83,119 @@ class Phaser: """ rtio_output(self.channel_base | addr, 0) response = rtio_input_data(self.channel_base >> 8) - return response >> self.readback_delay + return response >> self.miso_delay + + @kernel + def set_leds(self, leds): + self.write(PHASER_ADDR_LED, leds) + + @kernel + def set_fan(self, duty): + self.write(PHASER_ADDR_FAN, duty) + + @kernel + def set_cfg(self, clk_sel=0, dac_resetb=1, dac_sleep=0, dac_txena=1, + trf0_ps=0, trf1_ps=0, att0_rstn=1, att1_rstn=1): + self.write(PHASER_ADDR_CFG, + (clk_sel << 0) | (dac_resetb << 1) | (dac_sleep << 2) | + (dac_txena << 3) | (trf0_ps << 4) | (trf1_ps << 5) | + (att0_rstn << 6) | (att1_rstn << 7)) + + @kernel + def get_sta(self): + return self.read(PHASER_ADDR_STA) + + @kernel + def get_crc_err(self): + return self.read(PHASER_ADDR_CRC_ERR) + + @kernel + def get_dac_data(self, ch) -> TInt32: + data = 0 + for addr in range(4): + data <<= 8 + data |= self.read(PHASER_ADDR_DAC0_DATA + (ch << 4) + addr) + delay(20*us) # slack + return data + + @kernel + def set_dac_test(self, ch, data: TInt32): + for addr in range(4): + byte = (data >> 24) & 0xff + self.write(PHASER_ADDR_DAC0_TEST + (ch << 4) + addr, byte) + data <<= 8 + return data + + @kernel + def set_duc_cfg(self, ch, clr=0, clr_once=0, select=0): + self.write(PHASER_ADDR_DUC0_CFG + (ch << 4), + (clr << 0) | (clr_once << 1) | (select << 2)) + + @kernel + def spi_cfg(self, select, div, end, clk_phase=0, clk_polarity=0, + half_duplex=0, lsb_first=0, offline=0): + self.write(PHASER_ADDR_SPI_SEL, select) + self.write(PHASER_ADDR_SPI_DIV, div) + self.write(PHASER_ADDR_SPI_CFG, + (offline << 0) | (end << 1) | (clk_phase << 2) | + (clk_polarity << 3) | (half_duplex << 4) | + (lsb_first << 5)) + + @kernel + def spi_write(self, data): + self.write(PHASER_ADDR_SPI_DATW, data) + + @kernel + def spi_read(self): + return self.read(PHASER_ADDR_SPI_DATR) + + @kernel + def dac_write(self, addr, data): + div = 30 # 100 ns min period + t_xfer = self.core.seconds_to_mu((8 + 1)*(div + 2)*4*ns) + self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=0) + self.spi_write(addr) + delay_mu(t_xfer) + self.spi_write(data >> 8) + delay_mu(t_xfer) + self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=1) + self.spi_write(data & 0xff) + delay_mu(t_xfer) + + @kernel + def dac_read(self, addr, div=30) -> TInt32: + t_xfer = self.core.seconds_to_mu((8 + 1)*(div + 2)*4*ns) + self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=0) + self.spi_write(addr | 0x80) + delay_mu(t_xfer) + self.spi_write(0) + delay_mu(t_xfer) + data = self.spi_read() << 8 + delay(10*us) # slack + self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=1) + self.spi_write(0) + delay_mu(t_xfer) + data |= self.spi_read() + return data + + @kernel + def att_write(self, ch, data): + div = 30 # 30 ns min period + t_xfer = self.core.seconds_to_mu((8 + 1)*(div + 2)*4*ns) + self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=1) + self.spi_write(data) + delay_mu(t_xfer) + + @kernel + def att_read(self, ch) -> TInt32: + div = 30 + t_xfer = self.core.seconds_to_mu((8 + 1)*(div + 2)*4*ns) + self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=0) + self.spi_write(0) + delay_mu(t_xfer) + data = self.spi_read() + delay(10*us) + self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=1) + self.spi_write(data) + delay_mu(t_xfer) + return data diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 8a3122f9b..3f208c4a7 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -493,7 +493,7 @@ class PeripheralManager: "class": "Phaser", "arguments": {{ "channel_base": 0x{channel:06x}, - "readback_delay": 1, + "miso_delay": 1, }} }}""", name=self.get_name("phaser"), diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 35cf36de1..74ff6647f 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -650,6 +650,7 @@ class Phaser(_EEM): target.platform.request("phaser{}_ser_n".format(eem))) target.submodules += phy target.rtio_channels.extend([ - rtio.Channel(phy.config, ififo_depth=4), - rtio.Channel(phy.data), + rtio.Channel.from_phy(phy, ififo_depth=4), + rtio.Channel.from_phy(phy.dds0), + rtio.Channel.from_phy(phy.dds1), ]) diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index 19390f51d..3d14e6084 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -1,18 +1,27 @@ from migen import * +from misoc.cores.duc import MultiDDS from artiq.gateware.rtio import rtlink from .fastlink import SerDes, SerInterface +class DDSChannel(Module): + def __init__(self): + self.rtlink = rtlink.Interface( + rtlink.OInterface(data_width=32, address_width=4, + enable_replace=True)) + self.submodules.dds = MultiDDS(n=5, fwidth=32, xwidth=16) + + class Phaser(Module): def __init__(self, pins, pins_n): - self.config = rtlink.Interface( + self.rtlink = rtlink.Interface( rtlink.OInterface(data_width=8, address_width=8, enable_replace=False), rtlink.IInterface(data_width=10)) - self.data = rtlink.Interface( - rtlink.OInterface(data_width=32, address_width=8, - enable_replace=True)) + + self.submodules.dds0 = DDSChannel() + self.submodules.dds1 = DDSChannel() self.submodules.serializer = SerDes( n_data=8, t_clk=8, d_clk=0b00001111, @@ -44,12 +53,12 @@ class Phaser(Module): header.we.eq(0), re_dly.eq(re_dly[1:]), ), - If(self.config.o.stb, - re_dly[-1].eq(~self.config.o.address[-1]), - header.we.eq(self.config.o.address[-1]), - header.addr.eq(self.config.o.address), - header.data.eq(self.config.o.data), + If(self.rtlink.o.stb, + re_dly[-1].eq(~self.rtlink.o.address[-1]), + header.we.eq(self.rtlink.o.address[-1]), + header.addr.eq(self.rtlink.o.address), + header.data.eq(self.rtlink.o.data), ), - self.config.i.stb.eq(re_dly[0] & self.serializer.stb), - self.config.i.data.eq(self.serializer.readback), + self.rtlink.i.stb.eq(re_dly[0] & self.serializer.stb), + self.rtlink.i.data.eq(self.serializer.readback), ] From e5e239224070aa3285e3b6972333c049e97f925d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 26 Aug 2020 17:12:41 +0000 Subject: [PATCH 2301/2457] phaser: wire up multidds --- artiq/coredevice/phaser.py | 19 ++++++++++--- artiq/gateware/eem.py | 7 +++-- artiq/gateware/rtio/phy/phaser.py | 47 ++++++++++++++++++++++++------- 3 files changed, 56 insertions(+), 17 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index bce26882d..7b5918232 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -48,7 +48,7 @@ class Phaser: def __init__(self, dmgr, channel_base, miso_delay=1, core_device="core"): - self.channel_base = channel_base << 8 + self.channel_base = channel_base self.core = dmgr.get(core_device) self.miso_delay = miso_delay # frame duration in mu (10 words, 8 clock cycles each 4 ns) @@ -69,7 +69,7 @@ class Phaser: :param addr: Address to write to. :param data: Data to write. """ - rtio_output(self.channel_base | addr | 0x80, data) + rtio_output((self.channel_base << 8) | addr | 0x80, data) delay_mu(int64(self.t_frame)) @kernel @@ -81,8 +81,8 @@ class Phaser: :param addr: Address to read from. :return: The data read. """ - rtio_output(self.channel_base | addr, 0) - response = rtio_input_data(self.channel_base >> 8) + rtio_output((self.channel_base << 8) | addr, 0) + response = rtio_input_data(self.channel_base) return response >> self.miso_delay @kernel @@ -199,3 +199,14 @@ class Phaser: self.spi_write(data) delay_mu(t_xfer) return data + + @kernel + def set_frequency_mu(self, ch, osc, ftw): + addr = ((self.channel_base + 1 + ch) << 8) | (osc << 1) + rtio_output(addr, ftw) + + @kernel + def set_amplitude_phase_mu(self, ch, osc, asf=0x7fff, pow=0, clr=0): + addr = ((self.channel_base + 1 + ch) << 8) | (osc << 1) | 1 + data = (asf & 0x7fff) | (clr << 15) | (pow << 16) + rtio_output(addr, data) diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 74ff6647f..447dd1fe6 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -646,11 +646,12 @@ class Phaser(_EEM): def add_std(cls, target, eem, iostandard="LVDS_25"): cls.add_extension(target, eem, iostandard=iostandard) - phy = phaser.Phaser(target.platform.request("phaser{}_ser_p".format(eem)), + phy = phaser.Phaser( + target.platform.request("phaser{}_ser_p".format(eem)), target.platform.request("phaser{}_ser_n".format(eem))) target.submodules += phy target.rtio_channels.extend([ rtio.Channel.from_phy(phy, ififo_depth=4), - rtio.Channel.from_phy(phy.dds0), - rtio.Channel.from_phy(phy.dds1), + rtio.Channel.from_phy(phy.ch0), + rtio.Channel.from_phy(phy.ch1), ]) diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index 3d14e6084..f78b24ee1 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -6,22 +6,48 @@ from .fastlink import SerDes, SerInterface class DDSChannel(Module): - def __init__(self): + def __init__(self, use_lut=None): self.rtlink = rtlink.Interface( rtlink.OInterface(data_width=32, address_width=4, - enable_replace=True)) - self.submodules.dds = MultiDDS(n=5, fwidth=32, xwidth=16) + enable_replace=True)) + to_rio_phy = ClockDomainsRenamer("rio_phy") + self.submodules.dds = to_rio_phy(MultiDDS( + n=5, fwidth=32, xwidth=16, z=19, zl=10, use_lut=use_lut)) + # TODO: latency + self.comb += self.dds.stb.eq(1) + regs = [] + for i in self.dds.i: + regs.extend([i.f, Cat(i.a, i.clr, i.p)]) + self.sync.rio_phy += [ + If(self.rtlink.o.stb, + Array(regs)[self.rtlink.o.address].eq(self.rtlink.o.data) + ) + ] class Phaser(Module): def __init__(self, pins, pins_n): self.rtlink = rtlink.Interface( rtlink.OInterface(data_width=8, address_width=8, - enable_replace=False), + enable_replace=False), rtlink.IInterface(data_width=10)) - self.submodules.dds0 = DDSChannel() - self.submodules.dds1 = DDSChannel() + self.submodules.ch0 = DDSChannel() + self.submodules.ch1 = DDSChannel(use_lut=self.ch0.dds.mod.cs.lut) + n_channels = 2 + n_samples = 8 + n_bits = 14 + body = [Signal(n_channels*2*n_bits, reset_less=True) + for i in range(n_samples)] + i_sample = Signal(max=n_samples) + self.sync.rio_phy += [ + If(self.ch0.dds.valid, # & self.ch1.dds.valid, + Array(body)[i_sample].eq(Cat( + self.ch0.dds.o.q[2:], self.ch0.dds.o.i[2:], + self.ch1.dds.o.q[2:], self.ch1.dds.o.i[2:])), + i_sample.eq(i_sample + 1), + ), + ] self.submodules.serializer = SerDes( n_data=8, t_clk=8, d_clk=0b00001111, @@ -31,6 +57,11 @@ class Phaser(Module): Cat(self.intf.data[:-1]).eq(Cat(self.serializer.data[:-1])), self.serializer.data[-1].eq(self.intf.data[-1]), ] + self.sync.rio_phy += [ + If(self.serializer.stb, + i_sample.eq(0), + ), + ] header = Record([ ("we", 1), @@ -38,10 +69,6 @@ class Phaser(Module): ("data", 8), ("type", 4) ]) - n_channels = 2 - n_samples = 8 - n_bits = 14 - body = [Signal(n_bits) for i in range(n_channels*n_samples*2)] assert len(Cat(header.raw_bits(), body)) == \ len(self.serializer.payload) self.comb += self.serializer.payload.eq(Cat(header.raw_bits(), body)) From c10ac2c92af72fbf4cf413aba1b68a5b51566f3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 27 Aug 2020 14:26:09 +0000 Subject: [PATCH 2302/2457] phaser: add trf, duc, interfaces, redo body assembly, use more natrual iq ordering (i lsb) --- artiq/coredevice/phaser.py | 116 ++++++++++++++++++++++++------ artiq/gateware/rtio/phy/phaser.py | 17 ++--- 2 files changed, 101 insertions(+), 32 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 7b5918232..d38bb4f71 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -42,6 +42,13 @@ PHASER_SEL_TRF1 = 1 << 2 PHASER_SEL_ATT0 = 1 << 3 PHASER_SEL_ATT1 = 1 << 4 +PHASER_STA_DAC_ALARM = 1 << 0 +PHASER_STA_TRF0_LD = 1 << 1 +PHASER_STA_TRF1_LD = 1 << 2 +PHASER_STA_TERM0 = 1 << 3 +PHASER_STA_TERM1 = 1 << 4 +PHASER_STA_SPI_IDLE = 1 << 5 + class Phaser: kernel_invariants = {"core", "channel_base", "t_frame"} @@ -57,23 +64,23 @@ class Phaser: @kernel def init(self): - board_id = self.read(PHASER_ADDR_BOARD_ID) + board_id = self.read8(PHASER_ADDR_BOARD_ID) if board_id != PHASER_BOARD_ID: raise ValueError("invalid board id") delay(20*us) @kernel - def write(self, addr, data): + def write8(self, addr, data): """Write data to a Phaser FPGA register. :param addr: Address to write to. :param data: Data to write. """ - rtio_output((self.channel_base << 8) | addr | 0x80, data) + rtio_output((self.channel_base << 8) | (addr & 0x7f) | 0x80, data) delay_mu(int64(self.t_frame)) @kernel - def read(self, addr): + def read8(self, addr) -> TInt32: """Read from Phaser FPGA register. TODO: untested @@ -81,40 +88,65 @@ class Phaser: :param addr: Address to read from. :return: The data read. """ - rtio_output((self.channel_base << 8) | addr, 0) + rtio_output((self.channel_base << 8) | (addr & 0x7f), 0) response = rtio_input_data(self.channel_base) return response >> self.miso_delay + @kernel + def write32(self, addr, data: TInt32): + for offset in range(4): + byte = data >> 24 + self.write8(addr + offset, byte) + data <<= 8 + + @kernel + def read32(self, addr) -> TInt32: + data = 0 + for offset in range(4): + data <<= 8 + data |= self.read8(addr + offset) + delay(20*us) # slack + return data + + @kernel + def write16(self, addr, data: TInt32): + self.write8(addr, data >> 8) + self.write8(addr + 1, data) + + @kernel + def read16(self, addr) -> TInt32: + return (self.read8(addr) << 8) | self.read8(addr) + @kernel def set_leds(self, leds): - self.write(PHASER_ADDR_LED, leds) + self.write8(PHASER_ADDR_LED, leds) @kernel def set_fan(self, duty): - self.write(PHASER_ADDR_FAN, duty) + self.write8(PHASER_ADDR_FAN, duty) @kernel def set_cfg(self, clk_sel=0, dac_resetb=1, dac_sleep=0, dac_txena=1, trf0_ps=0, trf1_ps=0, att0_rstn=1, att1_rstn=1): - self.write(PHASER_ADDR_CFG, + self.write8(PHASER_ADDR_CFG, (clk_sel << 0) | (dac_resetb << 1) | (dac_sleep << 2) | (dac_txena << 3) | (trf0_ps << 4) | (trf1_ps << 5) | (att0_rstn << 6) | (att1_rstn << 7)) @kernel def get_sta(self): - return self.read(PHASER_ADDR_STA) + return self.read8(PHASER_ADDR_STA) @kernel def get_crc_err(self): - return self.read(PHASER_ADDR_CRC_ERR) + return self.read8(PHASER_ADDR_CRC_ERR) @kernel def get_dac_data(self, ch) -> TInt32: data = 0 for addr in range(4): data <<= 8 - data |= self.read(PHASER_ADDR_DAC0_DATA + (ch << 4) + addr) + data |= self.read8(PHASER_ADDR_DAC0_DATA + (ch << 4) + addr) delay(20*us) # slack return data @@ -122,32 +154,43 @@ class Phaser: def set_dac_test(self, ch, data: TInt32): for addr in range(4): byte = (data >> 24) & 0xff - self.write(PHASER_ADDR_DAC0_TEST + (ch << 4) + addr, byte) + self.write8(PHASER_ADDR_DAC0_TEST + (ch << 4) + addr, byte) data <<= 8 - return data @kernel def set_duc_cfg(self, ch, clr=0, clr_once=0, select=0): - self.write(PHASER_ADDR_DUC0_CFG + (ch << 4), + self.write8(PHASER_ADDR_DUC0_CFG + (ch << 4), (clr << 0) | (clr_once << 1) | (select << 2)) + @kernel + def set_duc_frequency_mu(self, ch, ftw): + self.write32(PHASER_ADDR_DUC0_F + (ch << 4), ftw) + + @kernel + def set_duc_phase_mu(self, ch, pow): + self.write16(PHASER_ADDR_DUC0_P + (ch << 4), pow) + + @kernel + def duc_stb(self): + self.write8(PHASER_ADDR_DUC_STB, 0) + @kernel def spi_cfg(self, select, div, end, clk_phase=0, clk_polarity=0, half_duplex=0, lsb_first=0, offline=0): - self.write(PHASER_ADDR_SPI_SEL, select) - self.write(PHASER_ADDR_SPI_DIV, div) - self.write(PHASER_ADDR_SPI_CFG, + self.write8(PHASER_ADDR_SPI_SEL, select) + self.write8(PHASER_ADDR_SPI_DIV, div) + self.write8(PHASER_ADDR_SPI_CFG, (offline << 0) | (end << 1) | (clk_phase << 2) | (clk_polarity << 3) | (half_duplex << 4) | (lsb_first << 5)) @kernel def spi_write(self, data): - self.write(PHASER_ADDR_SPI_DATW, data) + self.write8(PHASER_ADDR_SPI_DATW, data) @kernel def spi_read(self): - return self.read(PHASER_ADDR_SPI_DATR) + return self.read8(PHASER_ADDR_SPI_DATR) @kernel def dac_write(self, addr, data): @@ -194,12 +237,45 @@ class Phaser: self.spi_write(0) delay_mu(t_xfer) data = self.spi_read() - delay(10*us) + delay(10*us) # slack self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=1) self.spi_write(data) delay_mu(t_xfer) return data + @kernel + def trf_write(self, ch, data, readback=False): + div = 30 # 50 ns min period + t_xfer = self.core.seconds_to_mu((8 + 1)*(div + 2)*4*ns) + read = 0 + if readback: + clk_phase = 1 + else: + clk_phase = 0 + end = 0 + for i in range(4): + if i == 0 or i == 3: + if i == 3: + end = 1 + self.spi_cfg(select=PHASER_SEL_TRF0 << ch, div=div, + lsb_first=1, clk_phase=clk_phase, end=end) + self.spi_write(data & 0xff) + data >>= 8 + delay_mu(t_xfer) + if readback: + read >>= 8 + read |= self.spi_read() << 24 + delay(10*us) # slack + return read + + @kernel + def trf_read(self, ch, addr, cnt_mux_sel=0) -> TInt32: + self.trf_write(ch, 0x80000008 | (addr << 28) | (cnt_mux_sel << 27)) + # single clk pulse to start readback + self.spi_cfg(select=PHASER_SEL_TRF0 << ch, div=30, end=1, clk_polarity=1) + self.spi_cfg(select=PHASER_SEL_TRF0 << ch, div=30, end=1, clk_polarity=0) + return self.trf_write(ch, 0x00000008, readback=True) + @kernel def set_frequency_mu(self, ch, osc, ftw): addr = ((self.channel_base + 1 + ch) << 8) | (osc << 1) diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index f78b24ee1..1ae6862a6 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -37,15 +37,13 @@ class Phaser(Module): n_channels = 2 n_samples = 8 n_bits = 14 - body = [Signal(n_channels*2*n_bits, reset_less=True) - for i in range(n_samples)] - i_sample = Signal(max=n_samples) + body = Signal(n_samples*n_channels*2*n_bits, reset_less=True) self.sync.rio_phy += [ If(self.ch0.dds.valid, # & self.ch1.dds.valid, - Array(body)[i_sample].eq(Cat( - self.ch0.dds.o.q[2:], self.ch0.dds.o.i[2:], - self.ch1.dds.o.q[2:], self.ch1.dds.o.i[2:])), - i_sample.eq(i_sample + 1), + # recent sample, ch0, i first + Cat(body).eq(Cat(self.ch0.dds.o.i[2:], self.ch0.dds.o.q[2:], + self.ch1.dds.o.i[2:], self.ch1.dds.o.q[2:], + body)), ), ] @@ -57,11 +55,6 @@ class Phaser(Module): Cat(self.intf.data[:-1]).eq(Cat(self.serializer.data[:-1])), self.serializer.data[-1].eq(self.intf.data[-1]), ] - self.sync.rio_phy += [ - If(self.serializer.stb, - i_sample.eq(0), - ), - ] header = Record([ ("we", 1), From 96fc248d7ccb29cca5bf66824675c4837fafc12e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 27 Aug 2020 14:28:19 +0000 Subject: [PATCH 2303/2457] phaser: synchronize multidds to frame --- artiq/gateware/rtio/phy/phaser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index 1ae6862a6..5109d033c 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -13,8 +13,6 @@ class DDSChannel(Module): to_rio_phy = ClockDomainsRenamer("rio_phy") self.submodules.dds = to_rio_phy(MultiDDS( n=5, fwidth=32, xwidth=16, z=19, zl=10, use_lut=use_lut)) - # TODO: latency - self.comb += self.dds.stb.eq(1) regs = [] for i in self.dds.i: regs.extend([i.f, Cat(i.a, i.clr, i.p)]) @@ -70,6 +68,8 @@ class Phaser(Module): self.sync.rtio += [ header.type.eq(1), # reserved If(self.serializer.stb, + self.ch0.dds.stb.eq(1), # synchronize + self.ch1.dds.stb.eq(1), # synchronize header.we.eq(0), re_dly.eq(re_dly[1:]), ), From 68bfa04abbfee0480861a1a56cf5ca03e4882cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 27 Aug 2020 15:31:42 +0000 Subject: [PATCH 2304/2457] phaser: trf readback strobe spi changes --- artiq/coredevice/phaser.py | 42 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index d38bb4f71..2376f190f 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -18,7 +18,7 @@ PHASER_ADDR_FAN = 0x07 PHASER_ADDR_DUC_STB = 0x08 PHASER_ADDR_ADC_CFG = 0x09 PHASER_ADDR_SPI_CFG = 0x0a -PHASER_ADDR_SPI_DIV = 0x0b +PHASER_ADDR_SPI_DIVLEN = 0x0b PHASER_ADDR_SPI_SEL = 0x0c PHASER_ADDR_SPI_DATW = 0x0d PHASER_ADDR_SPI_DATR = 0x0e @@ -153,7 +153,7 @@ class Phaser: @kernel def set_dac_test(self, ch, data: TInt32): for addr in range(4): - byte = (data >> 24) & 0xff + byte = data >> 24 self.write8(PHASER_ADDR_DAC0_TEST + (ch << 4) + addr, byte) data <<= 8 @@ -176,9 +176,9 @@ class Phaser: @kernel def spi_cfg(self, select, div, end, clk_phase=0, clk_polarity=0, - half_duplex=0, lsb_first=0, offline=0): + half_duplex=0, lsb_first=0, offline=0, length=8): self.write8(PHASER_ADDR_SPI_SEL, select) - self.write8(PHASER_ADDR_SPI_DIV, div) + self.write8(PHASER_ADDR_SPI_DIVLEN, (div - 2 >> 3) | (length - 1 << 5)) self.write8(PHASER_ADDR_SPI_CFG, (offline << 0) | (end << 1) | (clk_phase << 2) | (clk_polarity << 3) | (half_duplex << 4) | @@ -194,20 +194,20 @@ class Phaser: @kernel def dac_write(self, addr, data): - div = 30 # 100 ns min period - t_xfer = self.core.seconds_to_mu((8 + 1)*(div + 2)*4*ns) + div = 32 # 100 ns min period + t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=0) self.spi_write(addr) delay_mu(t_xfer) self.spi_write(data >> 8) delay_mu(t_xfer) self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=1) - self.spi_write(data & 0xff) + self.spi_write(data) delay_mu(t_xfer) @kernel - def dac_read(self, addr, div=30) -> TInt32: - t_xfer = self.core.seconds_to_mu((8 + 1)*(div + 2)*4*ns) + def dac_read(self, addr, div=32) -> TInt32: + t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=0) self.spi_write(addr | 0x80) delay_mu(t_xfer) @@ -223,16 +223,16 @@ class Phaser: @kernel def att_write(self, ch, data): - div = 30 # 30 ns min period - t_xfer = self.core.seconds_to_mu((8 + 1)*(div + 2)*4*ns) + div = 32 # 30 ns min period + t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=1) self.spi_write(data) delay_mu(t_xfer) @kernel def att_read(self, ch) -> TInt32: - div = 30 - t_xfer = self.core.seconds_to_mu((8 + 1)*(div + 2)*4*ns) + div = 32 + t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=0) self.spi_write(0) delay_mu(t_xfer) @@ -245,21 +245,20 @@ class Phaser: @kernel def trf_write(self, ch, data, readback=False): - div = 30 # 50 ns min period - t_xfer = self.core.seconds_to_mu((8 + 1)*(div + 2)*4*ns) + div = 32 # 50 ns min period + t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) read = 0 + end = 0 + clk_phase = 0 if readback: clk_phase = 1 - else: - clk_phase = 0 - end = 0 for i in range(4): if i == 0 or i == 3: if i == 3: end = 1 self.spi_cfg(select=PHASER_SEL_TRF0 << ch, div=div, lsb_first=1, clk_phase=clk_phase, end=end) - self.spi_write(data & 0xff) + self.spi_write(data) data >>= 8 delay_mu(t_xfer) if readback: @@ -272,8 +271,9 @@ class Phaser: def trf_read(self, ch, addr, cnt_mux_sel=0) -> TInt32: self.trf_write(ch, 0x80000008 | (addr << 28) | (cnt_mux_sel << 27)) # single clk pulse to start readback - self.spi_cfg(select=PHASER_SEL_TRF0 << ch, div=30, end=1, clk_polarity=1) - self.spi_cfg(select=PHASER_SEL_TRF0 << ch, div=30, end=1, clk_polarity=0) + self.spi_cfg(select=0, div=32, end=1, length=1) + self.spi_write(0) + delay((1 + 1)*32*4*ns) return self.trf_write(ch, 0x00000008, readback=True) @kernel From 7cf974a6a7e645ce0a3e58d55a369092646bd7f5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 28 Aug 2020 12:25:23 +0800 Subject: [PATCH 2305/2457] comm_kernel: fix typo --- artiq/coredevice/comm_kernel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index b28f79272..d5096cb69 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -139,7 +139,7 @@ receivers = { "n": lambda kernel, embedding_map: None, "b": lambda kernel, embedding_map: bool(kernel._read_int8()), "i": lambda kernel, embedding_map: numpy.int32(kernel._read_int32()), - "I": lambda kernel, embedding_map: numpy.int32(kernel._read_int64()), + "I": lambda kernel, embedding_map: numpy.int64(kernel._read_int64()), "f": lambda kernel, embedding_map: kernel._read_float64(), "s": lambda kernel, embedding_map: kernel._read_string(), "B": lambda kernel, embedding_map: kernel._read_bytes(), From 69f0699ebd8db2232a705f61a5655f99fba96edc Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 27 Aug 2020 13:06:09 +0800 Subject: [PATCH 2306/2457] test: improved test_performance 1. Added tests for small payload. 2. Added statistics. --- artiq/test/coredevice/test_performance.py | 310 +++++++++++++++------- 1 file changed, 220 insertions(+), 90 deletions(-) diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index c9ab98b01..3ca1f86ba 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -6,138 +6,268 @@ import numpy from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase +# large: 1MB payload +# small: 1KB payload +bytes_large = b"\x00" * (1 << 20) +bytes_small = b"\x00" * (1 << 10) + +list_large = [123] * (1 << 18) +list_small = [123] * (1 << 8) + +array_large = numpy.array(list_large, numpy.int32) +array_small = numpy.array(list_small, numpy.int32) + +byte_list_large = [True] * (1 << 20) +byte_list_small = [True] * (1 << 10) + +received_bytes = 0 +time_start = 0 +time_end = 0 class _Transfer(EnvExperiment): def build(self): self.setattr_device("core") - self.data = b"\x00"*(10**6) + self.count = 10 + self.h2d = [0.0] * self.count + self.d2h = [0.0] * self.count @rpc - def source(self) -> TBytes: - return self.data + def get_bytes(self, large: TBool) -> TBytes: + if large: + return bytes_large + else: + return bytes_small @rpc - def source_byte_list(self) -> TList(TBool): - return [True] * (1 << 15) + def get_list(self, large: TBool) -> TList(TInt32): + if large: + return list_large + else: + return list_small @rpc - def source_list(self) -> TList(TInt32): - return [123] * (1 << 15) + def get_byte_list(self, large: TBool) -> TList(TBool): + if large: + return byte_list_large + else: + return byte_list_small @rpc - def source_array(self) -> TArray(TInt32): - return numpy.array([0] * (1 << 15), numpy.int32) + def get_array(self, large: TBool) -> TArray(TInt32): + if large: + return array_large + else: + return array_small + + @rpc + def get_string_list(self) -> TList(TStr): + return string_list @rpc def sink(self, data): pass - @rpc - def sink_list(self, data): - pass + @rpc(flags={"async"}) + def sink_async(self, data): + global received_bytes, time_start, time_end + if received_bytes == 0: + time_start = time.time() + received_bytes += len(data) + if received_bytes == (1024 ** 2)*128: + time_end = time.time() @rpc - def sink_array(self, data): - pass + def get_async_throughput(self) -> TFloat: + return 128.0 / (time_end - time_start) @kernel - def host_to_device(self): - t0 = self.core.get_rtio_counter_mu() - data = self.source() - t1 = self.core.get_rtio_counter_mu() - return len(data)/self.core.mu_to_seconds(t1-t0) + def test_bytes(self, large): + def inner(): + t0 = self.core.get_rtio_counter_mu() + data = self.get_bytes(large) + t1 = self.core.get_rtio_counter_mu() + self.sink(data) + t2 = self.core.get_rtio_counter_mu() + self.h2d[i] = self.core.mu_to_seconds(t1 - t0) + self.d2h[i] = self.core.mu_to_seconds(t2 - t1) + + for i in range(self.count): + inner() + return (self.h2d, self.d2h) @kernel - def host_to_device_list(self): - t0 = self.core.get_rtio_counter_mu() - data = self.source_list() - t1 = self.core.get_rtio_counter_mu() - return 4 * len(data)/self.core.mu_to_seconds(t1-t0) + def test_byte_list(self, large): + def inner(): + t0 = self.core.get_rtio_counter_mu() + data = self.get_byte_list(large) + t1 = self.core.get_rtio_counter_mu() + self.sink(data) + t2 = self.core.get_rtio_counter_mu() + self.h2d[i] = self.core.mu_to_seconds(t1 - t0) + self.d2h[i] = self.core.mu_to_seconds(t2 - t1) + + for i in range(self.count): + inner() + return (self.h2d, self.d2h) @kernel - def host_to_device_array(self): - t0 = self.core.get_rtio_counter_mu() - data = self.source_array() - t1 = self.core.get_rtio_counter_mu() - return 4 * len(data)/self.core.mu_to_seconds(t1-t0) + def test_list(self, large): + def inner(): + t0 = self.core.get_rtio_counter_mu() + data = self.get_list(large) + t1 = self.core.get_rtio_counter_mu() + self.sink(data) + t2 = self.core.get_rtio_counter_mu() + self.h2d[i] = self.core.mu_to_seconds(t1 - t0) + self.d2h[i] = self.core.mu_to_seconds(t2 - t1) + + for i in range(self.count): + inner() + return (self.h2d, self.d2h) @kernel - def host_to_device_byte_list(self): - t0 = self.core.get_rtio_counter_mu() - data = self.source_byte_list() - t1 = self.core.get_rtio_counter_mu() - return len(data)/self.core.mu_to_seconds(t1-t0) + def test_array(self, large): + def inner(): + t0 = self.core.get_rtio_counter_mu() + data = self.get_array(large) + t1 = self.core.get_rtio_counter_mu() + self.sink(data) + t2 = self.core.get_rtio_counter_mu() + self.h2d[i] = self.core.mu_to_seconds(t1 - t0) + self.d2h[i] = self.core.mu_to_seconds(t2 - t1) + + for i in range(self.count): + inner() + return (self.h2d, self.d2h) @kernel - def device_to_host(self): - t0 = self.core.get_rtio_counter_mu() - self.sink(self.data) - t1 = self.core.get_rtio_counter_mu() - return len(self.data)/self.core.mu_to_seconds(t1-t0) - - @kernel - def device_to_host_list(self): - #data = [[0]*8 for _ in range(1 << 12)] - data = [0]*(1 << 15) - t0 = self.core.get_rtio_counter_mu() - self.sink_list(data) - t1 = self.core.get_rtio_counter_mu() - return ((len(data)*4) / - self.core.mu_to_seconds(t1-t0)) - - @kernel - def device_to_host_array(self): - data = self.source_array() - t0 = self.core.get_rtio_counter_mu() - self.sink_array(data) - t1 = self.core.get_rtio_counter_mu() - return ((len(data)*4) / - self.core.mu_to_seconds(t1-t0)) - + def test_async(self): + data = self.get_bytes(True) + for _ in range(128): + self.sink_async(data) + return self.get_async_throughput() class TransferTest(ExperimentCase): - def test_host_to_device(self): - exp = self.create(_Transfer) - host_to_device_rate = exp.host_to_device() - print(host_to_device_rate/(1024*1024), "MiB/s") - self.assertGreater(host_to_device_rate, 2.0e6) + @classmethod + def setUpClass(self): + self.results = [] - def test_host_to_device_byte_list(self): - exp = self.create(_Transfer) - host_to_device_rate = exp.host_to_device_byte_list() - print(host_to_device_rate/(1024*1024), "MiB/s") - self.assertGreater(host_to_device_rate, 2.0e6) + @classmethod + def tearDownClass(self): + if len(self.results) == 0: + return + max_length = max(max(len(row[0]) for row in self.results), len("Test")) - def test_host_to_device_list(self): - exp = self.create(_Transfer) - host_to_device_rate = exp.host_to_device_list() - print(host_to_device_rate/(1024*1024), "MiB/s") - self.assertGreater(host_to_device_rate, 2.0e6) + def pad(name): + nonlocal max_length + return name + " " * (max_length - len(name)) + print() + print("| {} | Mean (MiB/s) | std (MiB/s) |".format(pad("Test"))) + print("| {} | ------------ | ------------ |".format("-" * max_length)) + for v in self.results: + print("| {} | {:>12.2f} | {:>12.2f} |".format( + pad(v[0]), v[1], v[2])) - def test_host_to_device_array(self): + def test_bytes_large(self): exp = self.create(_Transfer) - host_to_device_rate = exp.host_to_device_array() - print(host_to_device_rate/(1024*1024), "MiB/s") - self.assertGreater(host_to_device_rate, 2.0e6) + results = exp.test_bytes(True) + host_to_device = (1 << 20) / numpy.array(results[0], numpy.float64) + device_to_host = (1 << 20) / numpy.array(results[1], numpy.float64) + host_to_device /= 1024*1024 + device_to_host /= 1024*1024 + self.results.append(["Bytes (1MB) H2D", host_to_device.mean(), + host_to_device.std()]) + self.results.append(["Bytes (1MB) D2H", device_to_host.mean(), + device_to_host.std()]) - def test_device_to_host(self): + def test_bytes_small(self): exp = self.create(_Transfer) - device_to_host_rate = exp.device_to_host() - print(device_to_host_rate/(1024*1024), "MiB/s") - self.assertGreater(device_to_host_rate, 2.2e6) + results = exp.test_bytes(False) + host_to_device = (1 << 10) / numpy.array(results[0], numpy.float64) + device_to_host = (1 << 10) / numpy.array(results[1], numpy.float64) + host_to_device /= 1024*1024 + device_to_host /= 1024*1024 + self.results.append(["Bytes (1KB) H2D", host_to_device.mean(), + host_to_device.std()]) + self.results.append(["Bytes (1KB) D2H", device_to_host.mean(), + device_to_host.std()]) - def test_device_to_host_list(self): + def test_byte_list_large(self): exp = self.create(_Transfer) - rate = exp.device_to_host_list() - print(rate/(1024*1024), "MiB/s") - self.assertGreater(rate, .15e6) + results = exp.test_byte_list(True) + host_to_device = (1 << 20) / numpy.array(results[0], numpy.float64) + device_to_host = (1 << 20) / numpy.array(results[1], numpy.float64) + host_to_device /= 1024*1024 + device_to_host /= 1024*1024 + self.results.append(["Bytes List (1MB) H2D", host_to_device.mean(), + host_to_device.std()]) + self.results.append(["Bytes List (1MB) D2H", device_to_host.mean(), + device_to_host.std()]) - def test_device_to_host_array(self): + def test_byte_list_small(self): exp = self.create(_Transfer) - rate = exp.device_to_host_array() - print(rate/(1024*1024), "MiB/s") - self.assertGreater(rate, .15e6) + results = exp.test_byte_list(False) + host_to_device = (1 << 10) / numpy.array(results[0], numpy.float64) + device_to_host = (1 << 10) / numpy.array(results[1], numpy.float64) + host_to_device /= 1024*1024 + device_to_host /= 1024*1024 + self.results.append(["Bytes List (1KB) H2D", host_to_device.mean(), + host_to_device.std()]) + self.results.append(["Bytes List (1KB) D2H", device_to_host.mean(), + device_to_host.std()]) + def test_list_large(self): + exp = self.create(_Transfer) + results = exp.test_list(True) + host_to_device = (1 << 20) / numpy.array(results[0], numpy.float64) + device_to_host = (1 << 20) / numpy.array(results[1], numpy.float64) + host_to_device /= 1024*1024 + device_to_host /= 1024*1024 + self.results.append(["I32 List (1MB) H2D", host_to_device.mean(), + host_to_device.std()]) + self.results.append(["I32 List (1MB) D2H", device_to_host.mean(), + device_to_host.std()]) + + def test_list_small(self): + exp = self.create(_Transfer) + results = exp.test_list(False) + host_to_device = (1 << 10) / numpy.array(results[0], numpy.float64) + device_to_host = (1 << 10) / numpy.array(results[1], numpy.float64) + host_to_device /= 1024*1024 + device_to_host /= 1024*1024 + self.results.append(["I32 List (1KB) H2D", host_to_device.mean(), + host_to_device.std()]) + self.results.append(["I32 List (1KB) D2H", device_to_host.mean(), + device_to_host.std()]) + + def test_array_large(self): + exp = self.create(_Transfer) + results = exp.test_array(True) + host_to_device = (1 << 20) / numpy.array(results[0], numpy.float64) + device_to_host = (1 << 20) / numpy.array(results[1], numpy.float64) + host_to_device /= 1024*1024 + device_to_host /= 1024*1024 + self.results.append(["I32 Array (1MB) H2D", host_to_device.mean(), + host_to_device.std()]) + self.results.append(["I32 Array (1MB) D2H", device_to_host.mean(), + device_to_host.std()]) + + def test_array_small(self): + exp = self.create(_Transfer) + results = exp.test_array(False) + host_to_device = (1 << 10) / numpy.array(results[0], numpy.float64) + device_to_host = (1 << 10) / numpy.array(results[1], numpy.float64) + host_to_device /= 1024*1024 + device_to_host /= 1024*1024 + self.results.append(["I32 Array (1KB) H2D", host_to_device.mean(), + host_to_device.std()]) + self.results.append(["I32 Array (1KB) D2H", device_to_host.mean(), + device_to_host.std()]) + + def test_async_throughput(self): + exp = self.create(_Transfer) + results = exp.test_async() + print("Async throughput: {:>6.2f}MiB/s".format(results)) class _KernelOverhead(EnvExperiment): def build(self): From b2572003acfef50b32aa00cd17388f00fed5f87a Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 27 Aug 2020 11:27:40 +0800 Subject: [PATCH 2307/2457] RPC: optimization by caching This reduced the calls needed for socket send/recv. --- artiq/coredevice/comm_kernel.py | 87 +++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 31 deletions(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index d5096cb69..babf035b3 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -66,16 +66,16 @@ def _receive_list(kernel, embedding_map): tag = chr(kernel._read_int8()) if tag == "b": buffer = kernel._read(length) - return numpy.ndarray((length, ), 'B', buffer).tolist() + return list(buffer) elif tag == "i": buffer = kernel._read(4 * length) - return numpy.ndarray((length, ), '>i4', buffer).tolist() + return list(struct.unpack(">%sl" % length, buffer)) elif tag == "I": buffer = kernel._read(8 * length) - return numpy.ndarray((length, ), '>i8', buffer).tolist() + return list(struct.unpack(">%sq" % length, buffer)) elif tag == "f": buffer = kernel._read(8 * length) - return numpy.ndarray((length, ), '>d', buffer).tolist() + return list(struct.unpack(">%sd" % length, buffer)) else: fn = receivers[tag] elems = [] @@ -178,6 +178,17 @@ class CommKernel: self._read_type = None self.host = host self.port = port + self.read_buffer = bytearray() + self.write_buffer = bytearray() + + self.unpack_int32 = struct.Struct(">l").unpack + self.unpack_int64 = struct.Struct(">q").unpack + self.unpack_float64 = struct.Struct(">d").unpack + + self.pack_header = struct.Struct(">lB").pack + self.pack_int32 = struct.Struct(">l").pack + self.pack_int64 = struct.Struct(">q").pack + self.pack_float64 = struct.Struct(">d").pack def open(self): if hasattr(self, "socket"): @@ -198,13 +209,18 @@ class CommKernel: # def _read(self, length): - r = bytes() - while len(r) < length: - rn = self.socket.recv(min(8192, length - len(r))) - if not rn: - raise ConnectionResetError("Connection closed") - r += rn - return r + # cache the reads to avoid frequent call to recv + while len(self.read_buffer) < length: + # the number is just the maximum amount + # when there is not much data, it would return earlier + diff = length - len(self.read_buffer) + flag = 0 + if diff > 8192: + flag |= socket.MSG_WAITALL + self.read_buffer += self.socket.recv(8192, flag) + result = self.read_buffer[:length] + self.read_buffer = self.read_buffer[length:] + return result def _read_header(self): self.open() @@ -212,14 +228,14 @@ class CommKernel: # Wait for a synchronization sequence, 5a 5a 5a 5a. sync_count = 0 while sync_count < 4: - (sync_byte, ) = struct.unpack("B", self._read(1)) + sync_byte = self._read(1)[0] if sync_byte == 0x5a: sync_count += 1 else: sync_count = 0 # Read message header. - (raw_type, ) = struct.unpack("B", self._read(1)) + raw_type = self._read(1)[0] self._read_type = Reply(raw_type) logger.debug("receiving message: type=%r", @@ -235,19 +251,18 @@ class CommKernel: self._read_expect(ty) def _read_int8(self): - (value, ) = struct.unpack("B", self._read(1)) - return value + return self._read(1)[0] def _read_int32(self): - (value, ) = struct.unpack(">l", self._read(4)) + (value, ) = self.unpack_int32(self._read(4)) return value def _read_int64(self): - (value, ) = struct.unpack(">q", self._read(8)) + (value, ) = self.unpack_int64(self._read(8)) return value def _read_float64(self): - (value, ) = struct.unpack(">d", self._read(8)) + (value, ) = self.unpack_float64(self._read(8)) return value def _read_bool(self): @@ -264,7 +279,15 @@ class CommKernel: # def _write(self, data): - self.socket.sendall(data) + self.write_buffer += data + # if the buffer is already pretty large, send it + # the block size is arbitrary, tuning it may improve performance + if len(self.write_buffer) > 4096: + self._flush() + + def _flush(self): + self.socket.sendall(self.write_buffer) + self.write_buffer.clear() def _write_header(self, ty): self.open() @@ -272,7 +295,7 @@ class CommKernel: logger.debug("sending message: type=%r", ty) # Write synchronization sequence and header. - self._write(struct.pack(">lB", 0x5a5a5a5a, ty.value)) + self._write(self.pack_header(0x5a5a5a5a, ty.value)) def _write_empty(self, ty): self._write_header(ty) @@ -281,19 +304,19 @@ class CommKernel: self._write(chunk) def _write_int8(self, value): - self._write(struct.pack("B", value)) + self._write(value) def _write_int32(self, value): - self._write(struct.pack(">l", value)) + self._write(self.pack_int32(value)) def _write_int64(self, value): - self._write(struct.pack(">q", value)) + self._write(self.pack_int64(value)) def _write_float64(self, value): - self._write(struct.pack(">d", value)) + self._write(self.pack_float64(value)) def _write_bool(self, value): - self._write(struct.pack("B", value)) + self._write(1 if value == True else 0) def _write_bytes(self, value): self._write_int32(len(value)) @@ -308,6 +331,7 @@ class CommKernel: def check_system_info(self): self._write_empty(Request.SystemInfo) + self._flush() self._read_header() self._read_expect(Reply.SystemInfo) @@ -332,6 +356,7 @@ class CommKernel: def load(self, kernel_library): self._write_header(Request.LoadKernel) self._write_bytes(kernel_library) + self._flush() self._read_header() if self._read_type == Reply.LoadFailed: @@ -341,6 +366,7 @@ class CommKernel: def run(self): self._write_empty(Request.RunKernel) + self._flush() logger.debug("running kernel") _rpc_sentinel = object() @@ -441,14 +467,11 @@ class CommKernel: if tag_element == "b": self._write(bytes(value)) elif tag_element == "i": - array = numpy.array(value, '>i4') - self._write(array.tobytes()) + self._write(struct.pack(">%sl" % len(value), *value)) elif tag_element == "I": - array = numpy.array(value, '>i8') - self._write(array.tobytes()) + self._write(struct.pack(">%sq" % len(value), *value)) elif tag_element == "f": - array = numpy.array(value, '>d') - self._write(array.tobytes()) + self._write(struct.pack(">%sd" % len(value), *value)) else: for elt in value: tags_copy = bytearray(tags) @@ -524,6 +547,7 @@ class CommKernel: self._write_bytes(return_tags) self._send_rpc_value(bytearray(return_tags), result, result, service) + self._flush() except RPCReturnValueError as exn: raise except Exception as exn: @@ -569,6 +593,7 @@ class CommKernel: self._write_int32(line) self._write_int32(-1) # column not known self._write_string(function) + self._flush() def _serve_exception(self, embedding_map, symbolizer, demangler): name = self._read_string() From 272dc5d36a5a6a4789001f2ad166b122c3984e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 28 Aug 2020 16:36:44 +0000 Subject: [PATCH 2308/2457] phaser: documentation --- artiq/coredevice/phaser.py | 223 +++++++++++++++++++++++--- artiq/gateware/rtio/phy/phaser.py | 5 +- doc/manual/core_drivers_reference.rst | 5 + 3 files changed, 208 insertions(+), 25 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 2376f190f..7eff5b51d 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -1,5 +1,3 @@ -import numpy as np - from artiq.language.core import kernel, delay_mu, delay from artiq.coredevice.rtio import rtio_output, rtio_input_data from artiq.language.units import us, ns @@ -49,44 +47,86 @@ PHASER_STA_TERM0 = 1 << 3 PHASER_STA_TERM1 = 1 << 4 PHASER_STA_SPI_IDLE = 1 << 5 +PHASER_DAC_SEL_DUC = 0 +PHASER_DAC_SEL_TEST = 1 + class Phaser: - kernel_invariants = {"core", "channel_base", "t_frame"} + """Phaser 4-channel, 16-bit, 1 GS/s DAC coredevice driver. - def __init__(self, dmgr, channel_base, miso_delay=1, - core_device="core"): + Phaser contains a 4 channel, 1 GS/s DAC chip with integrated upconversion, + quadrature modulation compensation and interpolation features. + + The coredevice produces 2 IQ data streams with 25 MS/s 14 bit. Each + data stream supports 5 independent numerically controlled oscillators (NCOs) + added together for each channel. Together with a data clock, framing + marker, a checksum and metadata for register access the data is sent in + groups of 8 samples over 1.5 Gb/s FastLink via a single EEM connector. + + On Phaser the data streams are buffered and interpolated from 25 MS/s to 500 + MS/s 16 bit followed by a 500 MS/s digital upconverter in the FPGA. + + The four 16 bit 500 MS/s DAC data streams are sent via a 32 bit parallel + LVDS bus operating at 1 Gb/s per pin pair and processed in the DAC. + + The four analog DAC outputs are passed through anti-aliasing filters and In + the baseband variant, the even channels feed 31.5 dB range and are + available on the front panel. The odd outputs are available on MMCX + connectors on board. + + In the upconverter variant, each of the two IQ (in-phase and quadrature) + output pairs feeds a one quadrature upconverter with integrated PLL/VCO. + The output from the upconverter passes through the step attenuator and is + available at the front panel. + + The DAC, the TRF upconverters and the two attenuators are configured + through a shared SPI bus that is accessed and controlled via FPGA + registers. + + :param channel: Base RTIO channel number + :param core_device: Core device name (default: "core") + :param miso_delay: Fastlink MISO signal delay to account for cable + and buffer round trip. This might be automated later. + """ + kernel_invariants = {"core", "channel_base", "t_frame", "miso_delay"} + + def __init__(self, dmgr, channel_base, miso_delay=1, core_device="core"): self.channel_base = channel_base self.core = dmgr.get(core_device) self.miso_delay = miso_delay # frame duration in mu (10 words, 8 clock cycles each 4 ns) - # self.core.seconds_to_mu(10*8*4*ns) # unfortunately 319 + # self.core.seconds_to_mu(10*8*4*ns) # unfortunately this returns 319 + assert self.core.ref_period == 1*ns self.t_frame = 10*8*4 @kernel def init(self): + """Initialize the board. + + Verifies board presence by reading the board ID register. + Does not alter any state. + """ board_id = self.read8(PHASER_ADDR_BOARD_ID) if board_id != PHASER_BOARD_ID: raise ValueError("invalid board id") - delay(20*us) + delay(20*us) # slack @kernel def write8(self, addr, data): - """Write data to a Phaser FPGA register. + """Write data to FPGA register. - :param addr: Address to write to. - :param data: Data to write. + :param addr: Address to write to (7 bit) + :param data: Data to write (8 bit) """ rtio_output((self.channel_base << 8) | (addr & 0x7f) | 0x80, data) delay_mu(int64(self.t_frame)) @kernel def read8(self, addr) -> TInt32: - """Read from Phaser FPGA register. + """Read from FPGA register. - TODO: untested - - :param addr: Address to read from. - :return: The data read. + :param addr: Address to read from (7 bit) + :return: Data read (8 bit) """ rtio_output((self.channel_base << 8) | (addr & 0x7f), 0) response = rtio_input_data(self.channel_base) @@ -94,6 +134,7 @@ class Phaser: @kernel def write32(self, addr, data: TInt32): + """Write 32 bit to a sequence of FPGA registers.""" for offset in range(4): byte = data >> 24 self.write8(addr + offset, byte) @@ -101,6 +142,7 @@ class Phaser: @kernel def read32(self, addr) -> TInt32: + """Read 32 bit from a sequence of FPGA registers.""" data = 0 for offset in range(4): data <<= 8 @@ -110,39 +152,80 @@ class Phaser: @kernel def write16(self, addr, data: TInt32): + """Write 16 bit to a sequence of FPGA registers.""" self.write8(addr, data >> 8) self.write8(addr + 1, data) @kernel def read16(self, addr) -> TInt32: + """Read 16 bit from a sequence of FPGA registers.""" return (self.read8(addr) << 8) | self.read8(addr) @kernel def set_leds(self, leds): + """Set the front panel LEDs. + + :param leds: LED settings (6 bit) + """ self.write8(PHASER_ADDR_LED, leds) @kernel def set_fan(self, duty): + """Set the fan duty cycle. + + :param duty: Duty cycle (8 bit) + """ self.write8(PHASER_ADDR_FAN, duty) @kernel def set_cfg(self, clk_sel=0, dac_resetb=1, dac_sleep=0, dac_txena=1, trf0_ps=0, trf1_ps=0, att0_rstn=1, att1_rstn=1): + """Set the configuration register. + + :param clk_sel: Select the external SMA clock input + :param dac_resetb: Active low DAC reset pin + :param dac_sleep: DAC sleep pin + :param dac_txena: Enable DAC transmission pin + :param trf0_ps: TRF0 upconverter power save + :param trf1_ps: TRF1 upconverter power save + :param att0_rstn: Active low attenuator 0 reset + :param att1_rstn: Active low attenuator 1 reset + """ self.write8(PHASER_ADDR_CFG, - (clk_sel << 0) | (dac_resetb << 1) | (dac_sleep << 2) | - (dac_txena << 3) | (trf0_ps << 4) | (trf1_ps << 5) | - (att0_rstn << 6) | (att1_rstn << 7)) + (clk_sel << 0) | (dac_resetb << 1) | (dac_sleep << 2) | + (dac_txena << 3) | (trf0_ps << 4) | (trf1_ps << 5) | + (att0_rstn << 6) | (att1_rstn << 7)) @kernel def get_sta(self): + """Get the status register value. + + Bit flags are: + + * `PHASER_STA_DAC_ALARM`: DAC alarm pin + * `PHASER_STA_TRF0_LD`: TRF0 lock detect pin + * `PHASER_STA_TRF1_LD`: TRF1 lock detect pin + * `PHASER_STA_TERM0`: ADC channel 0 termination indicator + * `PHASER_STA_TERM1`: ADC channel 1 termination indicator + * `PHASER_STA_SPI_IDLE`: SPI machine is idle and data registers can be + read/written + + :return: Status register + """ return self.read8(PHASER_ADDR_STA) @kernel def get_crc_err(self): + """Get the frame CRC error counter.""" return self.read8(PHASER_ADDR_CRC_ERR) @kernel def get_dac_data(self, ch) -> TInt32: + """Get a sample of the current DAC data. + + :param ch: DAC channel pair (0 or 1) + :return: DAC data as 32 bit IQ + """ data = 0 for addr in range(4): data <<= 8 @@ -152,6 +235,11 @@ class Phaser: @kernel def set_dac_test(self, ch, data: TInt32): + """Set the DAC test data. + + :param ch: DAC channel pair (0 or 1) + :param data: 32 bit IQ test data + """ for addr in range(4): byte = data >> 24 self.write8(PHASER_ADDR_DAC0_TEST + (ch << 4) + addr, byte) @@ -159,41 +247,84 @@ class Phaser: @kernel def set_duc_cfg(self, ch, clr=0, clr_once=0, select=0): + """Set the digital upconverter and interpolator configuration. + + :param ch: DAC channel pair (0 or 1) + :param clr: Keep the phase accumulator cleared + :param clr_once: Clear the phase accumulator for one cycle + :param select: Select the data to send to the DAC (0: DUC data, 1: test + data) + """ self.write8(PHASER_ADDR_DUC0_CFG + (ch << 4), - (clr << 0) | (clr_once << 1) | (select << 2)) + (clr << 0) | (clr_once << 1) | (select << 2)) @kernel def set_duc_frequency_mu(self, ch, ftw): + """Set the DUC frequency. + + :param ch: DAC channel pair (0 or 1) + :param ftw: DUC frequency tuning word + """ self.write32(PHASER_ADDR_DUC0_F + (ch << 4), ftw) @kernel def set_duc_phase_mu(self, ch, pow): + """Set the DUC phase offset + + :param ch: DAC channel pair (0 or 1) + :param pow: DUC phase offset word + """ self.write16(PHASER_ADDR_DUC0_P + (ch << 4), pow) @kernel def duc_stb(self): + """Strobe the DUC configuration register update. + + Transfer staging to active registers. + This affects both DUC channels. + """ self.write8(PHASER_ADDR_DUC_STB, 0) @kernel def spi_cfg(self, select, div, end, clk_phase=0, clk_polarity=0, half_duplex=0, lsb_first=0, offline=0, length=8): + """Set the SPI machine configuration + + :param select: Chip selects to assert (DAC, TRF0, TRF1, ATT0, ATT1) + :param div: SPI clock divider relative to 250 MHz fabric clock + :param end: Whether to end the SPI transaction and deassert chip select + :param clk_phase: SPI clock phase (sample on first or second edge) + :param clk_polarity: SPI clock polarity (idle low or high) + :param half_duplex: Read MISO data from MOSI wire + :param lsb_first: Transfer the least significant bit first + :param offline: Put the SPI interfaces offline and don't drive voltages + :param length: SPI transfer length (1 to 8 bits) + """ self.write8(PHASER_ADDR_SPI_SEL, select) self.write8(PHASER_ADDR_SPI_DIVLEN, (div - 2 >> 3) | (length - 1 << 5)) self.write8(PHASER_ADDR_SPI_CFG, - (offline << 0) | (end << 1) | (clk_phase << 2) | - (clk_polarity << 3) | (half_duplex << 4) | - (lsb_first << 5)) + (offline << 0) | (end << 1) | (clk_phase << 2) | + (clk_polarity << 3) | (half_duplex << 4) | + (lsb_first << 5)) @kernel def spi_write(self, data): + """Write 8 bits into the SPI data register and start/continue the + transaction.""" self.write8(PHASER_ADDR_SPI_DATW, data) @kernel def spi_read(self): + """Read from the SPI input data register.""" return self.read8(PHASER_ADDR_SPI_DATR) @kernel def dac_write(self, addr, data): + """Write 16 bit to a DAC register. + + :param addr: Register address + :param data: Register data to write + """ div = 32 # 100 ns min period t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=0) @@ -207,6 +338,12 @@ class Phaser: @kernel def dac_read(self, addr, div=32) -> TInt32: + """Read from a DAC register. + + :param addr: Register address to read from + :param div: SPI clock divider. Needs to be at least 250 to read the + temperature register. + """ t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=0) self.spi_write(addr | 0x80) @@ -223,6 +360,11 @@ class Phaser: @kernel def att_write(self, ch, data): + """Set channel attenuation. + + :param ch: RF channel (0 or 1) + :param data: Attenuator data + """ div = 32 # 30 ns min period t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=1) @@ -231,6 +373,13 @@ class Phaser: @kernel def att_read(self, ch) -> TInt32: + """Read current attenuation. + + The current attenuation value is read without side effects. + + :param ch: RF channel (0 or 1) + :return: Current attenuation + """ div = 32 t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=0) @@ -245,6 +394,12 @@ class Phaser: @kernel def trf_write(self, ch, data, readback=False): + """Write 32 bits to a TRF upconverter. + + :param ch: RF channel (0 or 1) + :param data: Register data (32 bit) + :param readback: Whether to return the read back MISO data + """ div = 32 # 50 ns min period t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) read = 0 @@ -269,8 +424,16 @@ class Phaser: @kernel def trf_read(self, ch, addr, cnt_mux_sel=0) -> TInt32: + """TRF upconverter register read. + + :param ch: RF channel (0 or 1) + :param addr: Register address to read + :param cnt_mux_sel: Report VCO counter min frequency + or max frequency + :return: Register data (32 bit) + """ self.trf_write(ch, 0x80000008 | (addr << 28) | (cnt_mux_sel << 27)) - # single clk pulse to start readback + # single clk pulse with ~LE to start readback self.spi_cfg(select=0, div=32, end=1, length=1) self.spi_write(0) delay((1 + 1)*32*4*ns) @@ -278,11 +441,25 @@ class Phaser: @kernel def set_frequency_mu(self, ch, osc, ftw): + """Set Phaser MultiDDS frequency tuning word. + + :param ch: RF channel (0 or 1) + :param osc: Oscillator number (0 to 4) + :param ftw: Frequency tuning word (32 bit) + """ addr = ((self.channel_base + 1 + ch) << 8) | (osc << 1) rtio_output(addr, ftw) @kernel def set_amplitude_phase_mu(self, ch, osc, asf=0x7fff, pow=0, clr=0): + """Set Phaser MultiDDS amplitude, phase offset and accumulator clear. + + :param ch: RF channel (0 or 1) + :param osc: Oscillator number (0 to 4) + :param asf: Amplitude (15 bit) + :param pow: Phase offset word (16 bit) + :param clr: Clear the phase accumulator (persistent) + """ addr = ((self.channel_base + 1 + ch) << 8) | (osc << 1) | 1 data = (asf & 0x7fff) | (clr << 15) | (pow << 16) rtio_output(addr, data) diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index 5109d033c..cc6ffa1e5 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -30,6 +30,7 @@ class Phaser(Module): enable_replace=False), rtlink.IInterface(data_width=10)) + # share a CosSinGen LUT between the two channels self.submodules.ch0 = DDSChannel() self.submodules.ch1 = DDSChannel(use_lut=self.ch0.dds.mod.cs.lut) n_channels = 2 @@ -38,7 +39,7 @@ class Phaser(Module): body = Signal(n_samples*n_channels*2*n_bits, reset_less=True) self.sync.rio_phy += [ If(self.ch0.dds.valid, # & self.ch1.dds.valid, - # recent sample, ch0, i first + # recent:ch0:i as low order in body Cat(body).eq(Cat(self.ch0.dds.o.i[2:], self.ch0.dds.o.q[2:], self.ch1.dds.o.i[2:], self.ch1.dds.o.q[2:], body)), @@ -66,7 +67,7 @@ class Phaser(Module): re_dly = Signal(3) # stage, send, respond self.sync.rtio += [ - header.type.eq(1), # reserved + header.type.eq(1), # body type is baseband data If(self.serializer.stb, self.ch0.dds.stb.eq(1), # synchronize self.ch1.dds.stb.eq(1), # synchronize diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index b0026b6ac..baa1b59e4 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -130,6 +130,11 @@ RF generation drivers .. automodule:: artiq.coredevice.basemod_att :members: +:mod:`artiq.coredevice.phaser` module ++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.phaser + :members: DAC/ADC drivers --------------- From 45ae6202c001d1d6719e23217faa258c5e72af42 Mon Sep 17 00:00:00 2001 From: Stephan Maka Date: Thu, 27 Aug 2020 23:56:57 +0200 Subject: [PATCH 2309/2457] build_soc: add identifier_str override option Signed-off-by: Stephan Maka --- RELEASE_NOTES.rst | 2 ++ artiq/build_soc.py | 6 ++++-- artiq/gateware/targets/kasli.py | 15 +++++++++------ artiq/gateware/targets/kasli_generic.py | 4 +++- artiq/gateware/targets/kc705.py | 8 +++++--- artiq/gateware/targets/metlino.py | 8 +++++--- artiq/gateware/targets/sayma_amc.py | 20 +++++++++++++++----- artiq/gateware/targets/sayma_rtm.py | 10 +++++++--- 8 files changed, 50 insertions(+), 23 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index c6970f71d..e38441707 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -25,6 +25,8 @@ Highlights: * Core device: ``panic_reset 1`` now correctly resets the kernel CPU as well if communication CPU panic occurs. * NumberValue accepts a ``type`` parameter specifying the output as ``int`` or ``float`` +* A parameter `--identifier-str` has been added to many targets to aid + with reproducible builds. Breaking changes: diff --git a/artiq/build_soc.py b/artiq/build_soc.py index c5487d8d7..2770c2ff3 100644 --- a/artiq/build_soc.py +++ b/artiq/build_soc.py @@ -44,10 +44,12 @@ class ReprogrammableIdentifier(Module, AutoCSR): p_INIT=sum(1 << j if c & (1 << i) else 0 for j, c in enumerate(contents))) -def add_identifier(soc, *args, **kwargs): +def add_identifier(soc, *args, identifier_str=None, **kwargs): if hasattr(soc, "identifier"): raise ValueError - identifier_str = get_identifier_string(soc, *args, **kwargs) + if identifier_str is None: + # not overridden with --identifier-str + identifier_str = get_identifier_string(soc, *args, **kwargs) soc.submodules.identifier = ReprogrammableIdentifier(identifier_str) soc.config["IDENTIFIER_STR"] = identifier_str diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 73162c65b..902f00047 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -99,7 +99,7 @@ class StandaloneBase(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, **kwargs): + def __init__(self, identifier_str=None, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -109,7 +109,7 @@ class StandaloneBase(MiniSoC, AMPSoC): ethmac_ntxslots=4, **kwargs) AMPSoC.__init__(self) - add_identifier(self) + add_identifier(self, identifier_str=identifier_str) if self.platform.hw_rev == "v2.0": self.submodules.error_led = gpio.GPIOOut(Cat( @@ -280,7 +280,7 @@ class MasterBase(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, rtio_clk_freq=125e6, enable_sata=False, **kwargs): + def __init__(self, rtio_clk_freq=125e6, enable_sata=False, identifier_str=None, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -290,7 +290,7 @@ class MasterBase(MiniSoC, AMPSoC): ethmac_ntxslots=4, **kwargs) AMPSoC.__init__(self) - add_identifier(self) + add_identifier(self, identifier_str=identifier_str) platform = self.platform @@ -453,13 +453,13 @@ class SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, rtio_clk_freq=125e6, enable_sata=False, *, with_wrpll=False, **kwargs): + def __init__(self, rtio_clk_freq=125e6, enable_sata=False, *, with_wrpll=False, identifier_str=None, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, **kwargs) - add_identifier(self) + add_identifier(self, identifier_str=identifier_str) platform = self.platform @@ -674,11 +674,14 @@ def main(): help="variant: {} (default: %(default)s)".format( "/".join(sorted(VARIANTS.keys())))) parser.add_argument("--with-wrpll", default=False, action="store_true") + parser.add_argument("--identifier-str", default=None, + help="Override ROM identifier") args = parser.parse_args() argdict = dict() if args.with_wrpll: argdict["with_wrpll"] = True + argdict["identifier_str"] = args.identifier_str variant = args.variant.lower() try: diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index bae599ed9..7109fc150 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -252,6 +252,8 @@ def main(): parser.set_defaults(output_dir="artiq_kasli") parser.add_argument("description", metavar="DESCRIPTION", help="JSON system description file") + parser.add_argument("--identifier-str", default=None, + help="Override ROM identifier") args = parser.parse_args() with open(args.description, "r") as f: @@ -269,7 +271,7 @@ def main(): else: raise ValueError("Invalid base") - soc = cls(description, **soc_kasli_argdict(args)) + soc = cls(description, identifier_str=args.identifier_str, **soc_kasli_argdict(args)) args.variant = description["variant"] build_artiq_soc(soc, builder_argdict(args)) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index b586edda4..aa9fe96b7 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -119,7 +119,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, **kwargs): + def __init__(self, identifier_str=None, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -129,7 +129,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): ethmac_ntxslots=4, **kwargs) AMPSoC.__init__(self) - add_identifier(self) + add_identifier(self, identifier_str=identifier_str) if isinstance(self.platform.toolchain, XilinxVivadoToolchain): self.platform.toolchain.bitstream_commands.extend([ @@ -416,6 +416,8 @@ def main(): help="variant: " "nist_clock/nist_qc2/sma_spi " "(default: %(default)s)") + parser.add_argument("--identifier-str", default=None, + help="Override ROM identifier") args = parser.parse_args() variant = args.variant.lower() @@ -424,7 +426,7 @@ def main(): except KeyError: raise SystemExit("Invalid variant (-V/--variant)") - soc = cls(**soc_kc705_argdict(args)) + soc = cls(identifier_str=args.identifier_str, **soc_kc705_argdict(args)) build_artiq_soc(soc, builder_argdict(args)) diff --git a/artiq/gateware/targets/metlino.py b/artiq/gateware/targets/metlino.py index d1013653c..9c255f79d 100755 --- a/artiq/gateware/targets/metlino.py +++ b/artiq/gateware/targets/metlino.py @@ -38,7 +38,7 @@ class Master(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, **kwargs): + def __init__(self, identifier_str=None, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -49,7 +49,7 @@ class Master(MiniSoC, AMPSoC): csr_address_width=15, **kwargs) AMPSoC.__init__(self) - add_identifier(self) + add_identifier(self, identifier_str=identifier_str) platform = self.platform rtio_clk_freq = 150e6 @@ -164,9 +164,11 @@ def main(): builder_args(parser) soc_sdram_args(parser) parser.set_defaults(output_dir="artiq_metlino") + parser.add_argument("--identifier-str", default=None, + help="Override ROM identifier") args = parser.parse_args() args.variant = "master" - soc = Master(**soc_sdram_argdict(args)) + soc = Master(identifier_str=args.identifier_str, **soc_sdram_argdict(args)) build_artiq_soc(soc, builder_argdict(args)) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index c2cb435f1..90e486e2f 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -50,7 +50,7 @@ class SatelliteBase(MiniSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, rtio_clk_freq=125e6, identifier_suffix="", with_sfp=False, *, with_wrpll, **kwargs): + def __init__(self, rtio_clk_freq=125e6, identifier_suffix="", identifier_str=None, with_sfp=False, *, with_wrpll, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -59,7 +59,7 @@ class SatelliteBase(MiniSoC): ethmac_nrxslots=4, ethmac_ntxslots=4, **kwargs) - add_identifier(self, suffix=identifier_suffix) + add_identifier(self, suffix=identifier_suffix, identifier_str=identifier_str) self.rtio_clk_freq = rtio_clk_freq platform = self.platform @@ -403,14 +403,24 @@ def main(): help="Change type of signal generator. This is used exclusively for " "development and debugging.") parser.add_argument("--with-wrpll", default=False, action="store_true") + parser.add_argument("--identifier-str", default=None, + help="Override ROM identifier") args = parser.parse_args() variant = args.variant.lower() if variant == "satellite": - soc = Satellite(with_sfp=args.sfp, jdcg_type=args.jdcg_type, with_wrpll=args.with_wrpll, - **soc_sayma_amc_argdict(args)) + soc = Satellite( + with_sfp=args.sfp, + jdcg_type=args.jdcg_type, + with_wrpll=args.with_wrpll, + identifier_str=args.identifier_str, + **soc_sayma_amc_argdict(args)) elif variant == "simplesatellite": - soc = SimpleSatellite(with_sfp=args.sfp, with_wrpll=args.with_wrpll, **soc_sayma_amc_argdict(args)) + soc = SimpleSatellite( + with_sfp=args.sfp, + with_wrpll=args.with_wrpll, + identifier_str=args.identifier_str, + **soc_sayma_amc_argdict(args)) else: raise SystemExit("Invalid variant (-V/--variant)") diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index bdef1fa09..0a670e04e 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -75,11 +75,11 @@ class _SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, rtio_clk_freq, *, with_wrpll, **kwargs): + def __init__(self, rtio_clk_freq, *, with_wrpll, identifier_str, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", **kwargs) - add_identifier(self) + add_identifier(self, identifier_str=identifier_str) self.rtio_clk_freq = rtio_clk_freq platform = self.platform @@ -299,11 +299,15 @@ def main(): parser.add_argument("--rtio-clk-freq", default=150, type=int, help="RTIO clock frequency in MHz") parser.add_argument("--with-wrpll", default=False, action="store_true") + parser.add_argument("--identifier-str", default=None, + help="Override ROM identifier") parser.set_defaults(output_dir=os.path.join("artiq_sayma", "rtm")) args = parser.parse_args() soc = Satellite( - rtio_clk_freq=1e6*args.rtio_clk_freq, with_wrpll=args.with_wrpll, + rtio_clk_freq=1e6*args.rtio_clk_freq, + with_wrpll=args.with_wrpll, + identifier_str=args.identifier_str, **soc_sayma_rtm_argdict(args)) builder = SatmanSoCBuilder(soc, **builder_argdict(args)) try: From 1ad9deaf910dd828321b3eedc8639f44569103b4 Mon Sep 17 00:00:00 2001 From: Harry Ho Date: Mon, 31 Aug 2020 13:55:19 +0800 Subject: [PATCH 2310/2457] fmcdio_vhdci_eem: fix pin naming --- artiq/gateware/fmcdio_vhdci_eem.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/fmcdio_vhdci_eem.py b/artiq/gateware/fmcdio_vhdci_eem.py index c1ab62864..0296efe8e 100644 --- a/artiq/gateware/fmcdio_vhdci_eem.py +++ b/artiq/gateware/fmcdio_vhdci_eem.py @@ -19,8 +19,9 @@ def _get_connectors(): for j, pair in enumerate(eem_fmc_connections[i]): for pn in "n", "p": cc = "cc_" if j == 0 else "" + lpc_cc = "CC_" if eem_fmc_connections[i][j] in (0, 1, 17, 18) else "" connections["d{}_{}{}".format(j, cc, pn)] = \ - "LPC:LA{:02d}_{}{}".format(pair, cc.upper(), pn.upper()) + "LPC:LA{:02d}_{}{}".format(pair, lpc_cc, pn.upper()) connectors.append(("eem{}".format(i), connections)) return connectors From dfbf3311cb112dcccba3c55c5b4c8c596359f24f Mon Sep 17 00:00:00 2001 From: Harry Ho Date: Mon, 31 Aug 2020 15:26:39 +0800 Subject: [PATCH 2311/2457] sayma_amc: add support for 4x DIO output channels via FMC --- artiq/gateware/targets/sayma_amc.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 90e486e2f..34eb6a606 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -12,8 +12,10 @@ from misoc.interconnect.csr import * from misoc.targets.sayma_amc import * from artiq.gateware.amp import AMPSoC +from artiq.gateware import eem from artiq.gateware import rtio from artiq.gateware import jesd204_tools +from artiq.gateware import fmcdio_vhdci_eem from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_ultrascale, sawg from artiq.gateware.drtio.transceiver import gth_ultrascale from artiq.gateware.drtio.siphaser import SiPhaser7Series @@ -284,7 +286,7 @@ class JDCGSyncDDS(Module, AutoCSR): class Satellite(SatelliteBase): """ - DRTIO satellite with local DAC/SAWG channels. + DRTIO satellite with local DAC/SAWG channels, as well as TTL channels via FMC and VHDCI carrier. """ def __init__(self, jdcg_type, **kwargs): SatelliteBase.__init__(self, 150e6, @@ -307,7 +309,7 @@ class Satellite(SatelliteBase): self.csr_devices.append("slave_fpga_cfg") self.config["SLAVE_FPGA_GATEWARE"] = 0x200000 - rtio_channels = [] + self.rtio_channels = rtio_channels = [] for i in range(4): phy = ttl_simple.Output(platform.request("user_led", i)) self.submodules += phy @@ -343,6 +345,27 @@ class Satellite(SatelliteBase): self.jdcg_1.sawgs for phy in sawg.phys) + # FMC-VHDCI-EEM DIOs x 2 (all OUTPUTs) + platform.add_connectors(fmcdio_vhdci_eem.connectors) + eem.DIO.add_std(self, 0, + ttl_simple.Output, ttl_simple.Output, iostandard="LVDS") + eem.DIO.add_std(self, 1, + ttl_simple.Output, ttl_simple.Output, iostandard="LVDS") + # FMC-DIO-32ch-LVDS-a Direction Control Pins (via shift register) as TTLs x 3 + platform.add_extension(fmcdio_vhdci_eem.io) + print("fmcdio_vhdci_eem.[CLK, SER, LATCH] starting at RTIO channel 0x{:06x}" + .format(len(rtio_channels))) + fmcdio_dirctl = platform.request("fmcdio_dirctl", 0) + fmcdio_dirctl_phys = [ + ttl_simple.Output(fmcdio_dirctl.clk), + ttl_simple.Output(fmcdio_dirctl.ser), + ttl_simple.Output(fmcdio_dirctl.latch) + ] + for phy in fmcdio_dirctl_phys: + self.submodules += phy + rtio_channels.append(rtio.Channel.from_phy(phy)) + workaround_us_lvds_tristate(platform) + self.add_rtio(rtio_channels) self.submodules.sysref_sampler = jesd204_tools.SysrefSampler( From 3d8413581010c53b89696ad961f12ad299815365 Mon Sep 17 00:00:00 2001 From: Harry Ho Date: Mon, 31 Aug 2020 12:40:41 +0800 Subject: [PATCH 2312/2457] examples: add Metlino master, Sayma satellite with TTLOuts via FMC --- artiq/examples/metlino_sayma_ttl/device_db.py | 95 +++++++++++++ .../metlino_sayma_ttl/repository/demo.py | 134 ++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 artiq/examples/metlino_sayma_ttl/device_db.py create mode 100644 artiq/examples/metlino_sayma_ttl/repository/demo.py diff --git a/artiq/examples/metlino_sayma_ttl/device_db.py b/artiq/examples/metlino_sayma_ttl/device_db.py new file mode 100644 index 000000000..d60addb5e --- /dev/null +++ b/artiq/examples/metlino_sayma_ttl/device_db.py @@ -0,0 +1,95 @@ +core_addr = "192.168.1.65" + +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": core_addr, "ref_period": 1/(8*125e6)} + }, + "core_log": { + "type": "controller", + "host": "::1", + "port": 1068, + "command": "aqctl_corelog -p {port} --bind {bind} " + core_addr + }, + "core_cache": { + "type": "local", + "module": "artiq.coredevice.cache", + "class": "CoreCache" + }, + "core_dma": { + "type": "local", + "module": "artiq.coredevice.dma", + "class": "CoreDMA" + } +} + +# master peripherals +for i in range(4): + device_db["led" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": i}, +} + +# DEST#1 peripherals +amc_base = 0x070000 +rtm_base = 0x020000 + +for i in range(4): + device_db["led" + str(4+i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": amc_base + i}, + } + +#DIO (EEM0) starting at RTIO channel 0x000056 +for i in range(8): + device_db["ttl" + str(i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": amc_base + 0x000056 + i}, + } + +#DIO (EEM1) starting at RTIO channel 0x00005e +for i in range(8): + device_db["ttl" + str(8+i)] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": amc_base + 0x00005e + i}, + } + +device_db["fmcdio_dirctl_clk"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": amc_base + 0x000066} +} + +device_db["fmcdio_dirctl_ser"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": amc_base + 0x000067} +} + +device_db["fmcdio_dirctl_latch"] = { + "type": "local", + "module": "artiq.coredevice.ttl", + "class": "TTLOut", + "arguments": {"channel": amc_base + 0x000068} +} + +device_db["fmcdio_dirctl"] = { + "type": "local", + "module": "artiq.coredevice.shiftreg", + "class": "ShiftReg", + "arguments": {"clk": "fmcdio_dirctl_clk", + "ser": "fmcdio_dirctl_ser", + "latch": "fmcdio_dirctl_latch"} +} diff --git a/artiq/examples/metlino_sayma_ttl/repository/demo.py b/artiq/examples/metlino_sayma_ttl/repository/demo.py new file mode 100644 index 000000000..bfc19255a --- /dev/null +++ b/artiq/examples/metlino_sayma_ttl/repository/demo.py @@ -0,0 +1,134 @@ +import sys +import os +import select + +from artiq.experiment import * +from artiq.coredevice.fmcdio_vhdci_eem import * + + +def chunker(seq, size): + res = [] + for el in seq: + res.append(el) + if len(res) == size: + yield res + res = [] + if res: + yield res + + +def is_enter_pressed() -> TBool: + if os.name == "nt": + if msvcrt.kbhit() and msvcrt.getch() == b"\r": + return True + else: + return False + else: + if select.select([sys.stdin, ], [], [], 0.0)[0]: + sys.stdin.read(1) + return True + else: + return False + + +class Demo(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("fmcdio_dirctl") + + self.leds = dict() + self.ttl_outs = dict() + + ddb = self.get_device_db() + for name, desc in ddb.items(): + if isinstance(desc, dict) and desc["type"] == "local": + module, cls = desc["module"], desc["class"] + if (module, cls) == ("artiq.coredevice.ttl", "TTLOut"): + dev = self.get_device(name) + if "led" in name: # guess + self.leds[name] = dev + elif "ttl" in name: # to exclude fmcdio_dirctl + self.ttl_outs[name] = dev + + self.leds = sorted(self.leds.items(), key=lambda x: x[1].channel) + self.ttl_outs = sorted(self.ttl_outs.items(), key=lambda x: x[1].channel) + + self.dirctl_word = ( + shiftreg_bits(0, dio_bank0_out_pins | dio_bank1_out_pins) | + shiftreg_bits(1, dio_bank0_out_pins | dio_bank1_out_pins) + ) + + @kernel + def drtio_is_up(self, drtio_index): + if not self.core.get_rtio_destination_status(drtio_index): + return False + print("DRTIO #", drtio_index, "is ready\n") + return True + + @kernel + def test_led(self, led): + while not is_enter_pressed(): + self.core.break_realtime() + # do not fill the FIFOs too much to avoid long response times + t = now_mu() - self.core.seconds_to_mu(0.2) + while self.core.get_rtio_counter_mu() < t: + pass + for i in range(3): + led.pulse(100*ms) + delay(100*ms) + + @kernel + def test_leds(self): + print("*** Testing LEDs.") + print("Check for blinking. Press ENTER when done.") + + for i in range(len(self.leds)): + led = self.leds[i:i+1] + print("Testing LED:", i) + self.test_led([dev for _, dev in led][0]) + + @kernel + def test_ttl_out_chunk(self, ttl_chunk): + while not is_enter_pressed(): + self.core.break_realtime() + for _ in range(50000): + i = 0 + for ttl in ttl_chunk: + i += 1 + for _ in range(i): + ttl.pulse(1*us) + delay(1*us) + delay(10*us) + + @kernel + def test_ttl_outs(self): + print("*** Testing TTL outputs.") + print("Outputs are tested in groups of 4. Touch each TTL connector") + print("with the oscilloscope probe tip, and check that the number of") + print("pulses corresponds to its number in the group.") + print("Press ENTER when done.") + + # for ttl_chunk in chunker(self.ttl_outs, 4): + for i in range(len(self.ttl_outs) // 4): + chunk_start, chunk_end = i*4, (i+1)*4 + ttl_chunk = self.ttl_outs[chunk_start:chunk_end] + print("Testing TTL outputs:", chunk_start, chunk_start+1, chunk_start+2, chunk_start+3) + self.test_ttl_out_chunk([dev for _, dev in ttl_chunk]) + + @kernel + def run(self): + self.core.reset() + delay(10*ms) + print("*** Waiting for DRTIO ready...") + drtio_indices = [7] + for i in drtio_indices: + while not self.drtio_is_up(i): + pass + + self.fmcdio_dirctl.set(self.dirctl_word) + delay(10*ms) + + if self.leds: + self.test_leds() + if self.ttl_outs: + self.test_ttl_outs() From 91df3d729001156ef45bf98824d37665174577e0 Mon Sep 17 00:00:00 2001 From: Stephan Maka Date: Mon, 31 Aug 2020 21:44:27 +0200 Subject: [PATCH 2313/2457] build_soc: override identifier_str only for gateware --- artiq/build_soc.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/artiq/build_soc.py b/artiq/build_soc.py index 2770c2ff3..e49d1b862 100644 --- a/artiq/build_soc.py +++ b/artiq/build_soc.py @@ -47,12 +47,11 @@ class ReprogrammableIdentifier(Module, AutoCSR): def add_identifier(soc, *args, identifier_str=None, **kwargs): if hasattr(soc, "identifier"): raise ValueError - if identifier_str is None: - # not overridden with --identifier-str - identifier_str = get_identifier_string(soc, *args, **kwargs) - soc.submodules.identifier = ReprogrammableIdentifier(identifier_str) - soc.config["IDENTIFIER_STR"] = identifier_str + software_identifier_str = get_identifier_string(soc, *args, **kwargs) + gateware_identifier_str = identifier_str or software_identifier_str + soc.submodules.identifier = ReprogrammableIdentifier(gateware_identifier_str) + soc.config["IDENTIFIER_STR"] = software_identifier_str def build_artiq_soc(soc, argdict): From f294d039b3eb0cdfebc28a9ac8d89252b0fecaa8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Sep 2020 16:47:04 +0800 Subject: [PATCH 2314/2457] test: skip NonexistentI2CBus if I2C is not supported --- artiq/test/coredevice/test_i2c.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/test/coredevice/test_i2c.py b/artiq/test/coredevice/test_i2c.py index b3d03c107..e5424efc6 100644 --- a/artiq/test/coredevice/test_i2c.py +++ b/artiq/test/coredevice/test_i2c.py @@ -24,6 +24,7 @@ class I2CSwitch(EnvExperiment): class NonexistentI2CBus(EnvExperiment): def build(self): self.setattr_device("core") + self.setattr_device("i2c_switch") # HACK: only run this test on boards with I2C self.broken_switch = PCA9548(self._HasEnvironment__device_mgr, 255) @kernel From 8d5dc0ad2af5ca4676c550522387ebf043ef606c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Sep 2020 17:08:26 +0800 Subject: [PATCH 2315/2457] test: relax test_pulse_rate on Zynq --- artiq/test/coredevice/test_rtio.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 96437d2a2..137abc734 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -12,6 +12,7 @@ from artiq.coredevice import exceptions from artiq.coredevice.comm_mgmt import CommMgmt from artiq.coredevice.comm_analyzer import (StoppedMessage, OutputMessage, InputMessage, decode_dump, get_analyzer_dump) +from artiq.compiler.targets import CortexA9Target artiq_low_latency = os.getenv("ARTIQ_LOW_LATENCY") @@ -460,11 +461,15 @@ class CoredeviceTest(ExperimentCase): def test_pulse_rate(self): """Minimum interval for sustained TTL output switching""" - self.execute(PulseRate) + exp = self.execute(PulseRate) rate = self.dataset_mgr.get("pulse_rate") print(rate) self.assertGreater(rate, 100*ns) - self.assertLess(rate, 480*ns) + if exp.core.target_cls == CortexA9Target: + # Crappy AXI PS/PL interface from Xilinx is slow. + self.assertLess(rate, 810*ns) + else: + self.assertLess(rate, 480*ns) def test_pulse_rate_ad9914_dds(self): """Minimum interval for sustained AD9914 DDS frequency switching""" From f0289d49ab1c7686e10c8390d0d28af7125abe59 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Sep 2020 17:49:40 +0800 Subject: [PATCH 2316/2457] test: temporarily disable test_async_throughput https://git.m-labs.hk/M-Labs/artiq-zynq/issues/104 --- artiq/test/coredevice/test_performance.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index 3ca1f86ba..4d7545c67 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -264,10 +264,10 @@ class TransferTest(ExperimentCase): self.results.append(["I32 Array (1KB) D2H", device_to_host.mean(), device_to_host.std()]) - def test_async_throughput(self): - exp = self.create(_Transfer) - results = exp.test_async() - print("Async throughput: {:>6.2f}MiB/s".format(results)) + #def test_async_throughput(self): + # exp = self.create(_Transfer) + # results = exp.test_async() + # print("Async throughput: {:>6.2f}MiB/s".format(results)) class _KernelOverhead(EnvExperiment): def build(self): From 4398a2d5fa4dff9da412945c4f42d7fa429f752e Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 1 Sep 2020 17:50:09 +0800 Subject: [PATCH 2317/2457] test: relax loopback gate timing --- artiq/test/coredevice/test_rtio.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 137abc734..de7318d27 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -231,17 +231,18 @@ class LoopbackGateTiming(EnvExperiment): # With the exact delay known, make sure tight gate timings work. # In the most common configuration, 24 mu == 24 ns == 3 coarse periods, # which should be plenty of slack. + # FIXME: ZC706 with NIST_QC2 needs 48ns - hw problem? delay_mu(10000) gate_start_mu = now_mu() - self.loop_in.gate_both_mu(24) + self.loop_in.gate_both_mu(48) # XXX gate_end_mu = now_mu() # gateware latency offset between gate and input lat_offset = 11*8 out_mu = gate_start_mu - loop_delay_mu + lat_offset at_mu(out_mu) - self.loop_out.pulse_mu(24) + self.loop_out.pulse_mu(48) # XXX in_mu = self.loop_in.timestamp_mu(gate_end_mu) print("timings: ", gate_start_mu, in_mu - lat_offset, gate_end_mu) From 002a71dd8dd9fe77d9f103288c55f988f3ad5d2c Mon Sep 17 00:00:00 2001 From: Stephan Maka Date: Tue, 1 Sep 2020 17:48:43 +0200 Subject: [PATCH 2318/2457] build_soc: rename identifier_str to gateware_identifier_str --- artiq/build_soc.py | 13 +++++++------ artiq/gateware/targets/kasli.py | 16 ++++++++-------- artiq/gateware/targets/kasli_generic.py | 4 ++-- artiq/gateware/targets/kc705.py | 8 ++++---- artiq/gateware/targets/metlino.py | 8 ++++---- artiq/gateware/targets/sayma_amc.py | 10 +++++----- artiq/gateware/targets/sayma_rtm.py | 8 ++++---- 7 files changed, 34 insertions(+), 33 deletions(-) diff --git a/artiq/build_soc.py b/artiq/build_soc.py index e49d1b862..ddce92fb1 100644 --- a/artiq/build_soc.py +++ b/artiq/build_soc.py @@ -44,14 +44,15 @@ class ReprogrammableIdentifier(Module, AutoCSR): p_INIT=sum(1 << j if c & (1 << i) else 0 for j, c in enumerate(contents))) -def add_identifier(soc, *args, identifier_str=None, **kwargs): +def add_identifier(soc, *args, gateware_identifier_str=None, **kwargs): if hasattr(soc, "identifier"): raise ValueError - software_identifier_str = get_identifier_string(soc, *args, **kwargs) - gateware_identifier_str = identifier_str or software_identifier_str - - soc.submodules.identifier = ReprogrammableIdentifier(gateware_identifier_str) - soc.config["IDENTIFIER_STR"] = software_identifier_str + if gateware_identifier_str is None: + # not overridden with --identifier-str + raise ValueError("gateware_identifier_str not overridden") + identifier_str = get_identifier_string(soc, *args, **kwargs) + soc.submodules.identifier = ReprogrammableIdentifier(gateware_identifier_str or identifier_str) + soc.config["IDENTIFIER_STR"] = identifier_str def build_artiq_soc(soc, argdict): diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 902f00047..96a4df558 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -99,7 +99,7 @@ class StandaloneBase(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, identifier_str=None, **kwargs): + def __init__(self, gateware_identifier_str=None, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -109,7 +109,7 @@ class StandaloneBase(MiniSoC, AMPSoC): ethmac_ntxslots=4, **kwargs) AMPSoC.__init__(self) - add_identifier(self, identifier_str=identifier_str) + add_identifier(self, gateware_identifier_str=gateware_identifier_str) if self.platform.hw_rev == "v2.0": self.submodules.error_led = gpio.GPIOOut(Cat( @@ -280,7 +280,7 @@ class MasterBase(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, rtio_clk_freq=125e6, enable_sata=False, identifier_str=None, **kwargs): + def __init__(self, rtio_clk_freq=125e6, enable_sata=False, gateware_identifier_str=None, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -290,7 +290,7 @@ class MasterBase(MiniSoC, AMPSoC): ethmac_ntxslots=4, **kwargs) AMPSoC.__init__(self) - add_identifier(self, identifier_str=identifier_str) + add_identifier(self, gateware_identifier_str=gateware_identifier_str) platform = self.platform @@ -453,13 +453,13 @@ class SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, rtio_clk_freq=125e6, enable_sata=False, *, with_wrpll=False, identifier_str=None, **kwargs): + def __init__(self, rtio_clk_freq=125e6, enable_sata=False, *, with_wrpll=False, gateware_identifier_str=None, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", l2_size=128*1024, **kwargs) - add_identifier(self, identifier_str=identifier_str) + add_identifier(self, gateware_identifier_str=gateware_identifier_str) platform = self.platform @@ -674,14 +674,14 @@ def main(): help="variant: {} (default: %(default)s)".format( "/".join(sorted(VARIANTS.keys())))) parser.add_argument("--with-wrpll", default=False, action="store_true") - parser.add_argument("--identifier-str", default=None, + parser.add_argument("--gateware-identifier-str", default=None, help="Override ROM identifier") args = parser.parse_args() argdict = dict() if args.with_wrpll: argdict["with_wrpll"] = True - argdict["identifier_str"] = args.identifier_str + argdict["gateware_identifier_str"] = args.gateware_identifier_str variant = args.variant.lower() try: diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index 7109fc150..939f60716 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -252,7 +252,7 @@ def main(): parser.set_defaults(output_dir="artiq_kasli") parser.add_argument("description", metavar="DESCRIPTION", help="JSON system description file") - parser.add_argument("--identifier-str", default=None, + parser.add_argument("--gateware-identifier-str", default=None, help="Override ROM identifier") args = parser.parse_args() @@ -271,7 +271,7 @@ def main(): else: raise ValueError("Invalid base") - soc = cls(description, identifier_str=args.identifier_str, **soc_kasli_argdict(args)) + soc = cls(description, gateware_identifier_str=args.gateware_identifier_str, **soc_kasli_argdict(args)) args.variant = description["variant"] build_artiq_soc(soc, builder_argdict(args)) diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index aa9fe96b7..1481fd351 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -119,7 +119,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, identifier_str=None, **kwargs): + def __init__(self, gateware_identifier_str=None, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -129,7 +129,7 @@ class _StandaloneBase(MiniSoC, AMPSoC): ethmac_ntxslots=4, **kwargs) AMPSoC.__init__(self) - add_identifier(self, identifier_str=identifier_str) + add_identifier(self, gateware_identifier_str=gateware_identifier_str) if isinstance(self.platform.toolchain, XilinxVivadoToolchain): self.platform.toolchain.bitstream_commands.extend([ @@ -416,7 +416,7 @@ def main(): help="variant: " "nist_clock/nist_qc2/sma_spi " "(default: %(default)s)") - parser.add_argument("--identifier-str", default=None, + parser.add_argument("--gateware-identifier-str", default=None, help="Override ROM identifier") args = parser.parse_args() @@ -426,7 +426,7 @@ def main(): except KeyError: raise SystemExit("Invalid variant (-V/--variant)") - soc = cls(identifier_str=args.identifier_str, **soc_kc705_argdict(args)) + soc = cls(gateware_identifier_str=args.gateware_identifier_str, **soc_kc705_argdict(args)) build_artiq_soc(soc, builder_argdict(args)) diff --git a/artiq/gateware/targets/metlino.py b/artiq/gateware/targets/metlino.py index 9c255f79d..2139278ef 100755 --- a/artiq/gateware/targets/metlino.py +++ b/artiq/gateware/targets/metlino.py @@ -38,7 +38,7 @@ class Master(MiniSoC, AMPSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, identifier_str=None, **kwargs): + def __init__(self, gateware_identifier_str=None, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -49,7 +49,7 @@ class Master(MiniSoC, AMPSoC): csr_address_width=15, **kwargs) AMPSoC.__init__(self) - add_identifier(self, identifier_str=identifier_str) + add_identifier(self, gateware_identifier_str=gateware_identifier_str) platform = self.platform rtio_clk_freq = 150e6 @@ -164,11 +164,11 @@ def main(): builder_args(parser) soc_sdram_args(parser) parser.set_defaults(output_dir="artiq_metlino") - parser.add_argument("--identifier-str", default=None, + parser.add_argument("--gateware-identifier-str", default=None, help="Override ROM identifier") args = parser.parse_args() args.variant = "master" - soc = Master(identifier_str=args.identifier_str, **soc_sdram_argdict(args)) + soc = Master(gateware_identifier_str=args.gateware_identifier_str, **soc_sdram_argdict(args)) build_artiq_soc(soc, builder_argdict(args)) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 34eb6a606..7f8a8a5b8 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -52,7 +52,7 @@ class SatelliteBase(MiniSoC): } mem_map.update(MiniSoC.mem_map) - def __init__(self, rtio_clk_freq=125e6, identifier_suffix="", identifier_str=None, with_sfp=False, *, with_wrpll, **kwargs): + def __init__(self, rtio_clk_freq=125e6, identifier_suffix="", gateware_identifier_str=None, with_sfp=False, *, with_wrpll, **kwargs): MiniSoC.__init__(self, cpu_type="or1k", sdram_controller_type="minicon", @@ -61,7 +61,7 @@ class SatelliteBase(MiniSoC): ethmac_nrxslots=4, ethmac_ntxslots=4, **kwargs) - add_identifier(self, suffix=identifier_suffix, identifier_str=identifier_str) + add_identifier(self, suffix=identifier_suffix, gateware_identifier_str=gateware_identifier_str) self.rtio_clk_freq = rtio_clk_freq platform = self.platform @@ -426,7 +426,7 @@ def main(): help="Change type of signal generator. This is used exclusively for " "development and debugging.") parser.add_argument("--with-wrpll", default=False, action="store_true") - parser.add_argument("--identifier-str", default=None, + parser.add_argument("--gateware-identifier-str", default=None, help="Override ROM identifier") args = parser.parse_args() @@ -436,13 +436,13 @@ def main(): with_sfp=args.sfp, jdcg_type=args.jdcg_type, with_wrpll=args.with_wrpll, - identifier_str=args.identifier_str, + gateware_identifier_str=args.gateware_identifier_str, **soc_sayma_amc_argdict(args)) elif variant == "simplesatellite": soc = SimpleSatellite( with_sfp=args.sfp, with_wrpll=args.with_wrpll, - identifier_str=args.identifier_str, + gateware_identifier_str=args.gateware_identifier_str, **soc_sayma_amc_argdict(args)) else: raise SystemExit("Invalid variant (-V/--variant)") diff --git a/artiq/gateware/targets/sayma_rtm.py b/artiq/gateware/targets/sayma_rtm.py index 0a670e04e..294a17823 100755 --- a/artiq/gateware/targets/sayma_rtm.py +++ b/artiq/gateware/targets/sayma_rtm.py @@ -75,11 +75,11 @@ class _SatelliteBase(BaseSoC): } mem_map.update(BaseSoC.mem_map) - def __init__(self, rtio_clk_freq, *, with_wrpll, identifier_str, **kwargs): + def __init__(self, rtio_clk_freq, *, with_wrpll, gateware_identifier_str, **kwargs): BaseSoC.__init__(self, cpu_type="or1k", **kwargs) - add_identifier(self, identifier_str=identifier_str) + add_identifier(self, gateware_identifier_str=gateware_identifier_str) self.rtio_clk_freq = rtio_clk_freq platform = self.platform @@ -299,7 +299,7 @@ def main(): parser.add_argument("--rtio-clk-freq", default=150, type=int, help="RTIO clock frequency in MHz") parser.add_argument("--with-wrpll", default=False, action="store_true") - parser.add_argument("--identifier-str", default=None, + parser.add_argument("--gateware-identifier-str", default=None, help="Override ROM identifier") parser.set_defaults(output_dir=os.path.join("artiq_sayma", "rtm")) args = parser.parse_args() @@ -307,7 +307,7 @@ def main(): soc = Satellite( rtio_clk_freq=1e6*args.rtio_clk_freq, with_wrpll=args.with_wrpll, - identifier_str=args.identifier_str, + gateware_identifier_str=args.gateware_identifier_str, **soc_sayma_rtm_argdict(args)) builder = SatmanSoCBuilder(soc, **builder_argdict(args)) try: From 47e88dfcbe925890fec49b83799cec1a52d2cbc4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 3 Sep 2020 14:19:55 +0800 Subject: [PATCH 2319/2457] Revert "test: temporarily disable test_async_throughput" This reverts commit f0289d49ab1c7686e10c8390d0d28af7125abe59. --- artiq/test/coredevice/test_performance.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/test/coredevice/test_performance.py b/artiq/test/coredevice/test_performance.py index 4d7545c67..3ca1f86ba 100644 --- a/artiq/test/coredevice/test_performance.py +++ b/artiq/test/coredevice/test_performance.py @@ -264,10 +264,10 @@ class TransferTest(ExperimentCase): self.results.append(["I32 Array (1KB) D2H", device_to_host.mean(), device_to_host.std()]) - #def test_async_throughput(self): - # exp = self.create(_Transfer) - # results = exp.test_async() - # print("Async throughput: {:>6.2f}MiB/s".format(results)) + def test_async_throughput(self): + exp = self.create(_Transfer) + results = exp.test_async() + print("Async throughput: {:>6.2f}MiB/s".format(results)) class _KernelOverhead(EnvExperiment): def build(self): From 458a411320afb98e71b5d583962f154946c83d38 Mon Sep 17 00:00:00 2001 From: Harry Ho Date: Thu, 3 Sep 2020 15:08:31 +0800 Subject: [PATCH 2320/2457] metlino_sayma_ttl: Fix RTIO frequency & demo code (#1516) --- artiq/examples/metlino_sayma_ttl/device_db.py | 2 +- .../metlino_sayma_ttl/repository/demo.py | 39 ++++++++----------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/artiq/examples/metlino_sayma_ttl/device_db.py b/artiq/examples/metlino_sayma_ttl/device_db.py index d60addb5e..c8c3acb8e 100644 --- a/artiq/examples/metlino_sayma_ttl/device_db.py +++ b/artiq/examples/metlino_sayma_ttl/device_db.py @@ -5,7 +5,7 @@ device_db = { "type": "local", "module": "artiq.coredevice.core", "class": "Core", - "arguments": {"host": core_addr, "ref_period": 1/(8*125e6)} + "arguments": {"host": core_addr, "ref_period": 1/(8*150e6)} }, "core_log": { "type": "controller", diff --git a/artiq/examples/metlino_sayma_ttl/repository/demo.py b/artiq/examples/metlino_sayma_ttl/repository/demo.py index bfc19255a..bb273ce2c 100644 --- a/artiq/examples/metlino_sayma_ttl/repository/demo.py +++ b/artiq/examples/metlino_sayma_ttl/repository/demo.py @@ -58,6 +58,17 @@ class Demo(EnvExperiment): shiftreg_bits(1, dio_bank0_out_pins | dio_bank1_out_pins) ) + @kernel + def init(self): + self.core.break_realtime() + print("*** Waiting for DRTIO ready...") + drtio_indices = [7] + for i in drtio_indices: + while not self.drtio_is_up(i): + pass + + self.fmcdio_dirctl.set(self.dirctl_word) + @kernel def drtio_is_up(self, drtio_index): if not self.core.get_rtio_destination_status(drtio_index): @@ -77,15 +88,13 @@ class Demo(EnvExperiment): led.pulse(100*ms) delay(100*ms) - @kernel def test_leds(self): print("*** Testing LEDs.") print("Check for blinking. Press ENTER when done.") - for i in range(len(self.leds)): - led = self.leds[i:i+1] - print("Testing LED:", i) - self.test_led([dev for _, dev in led][0]) + for led_name, led_dev in self.leds: + print("Testing LED: {}".format(led_name)) + self.test_led(led_dev) @kernel def test_ttl_out_chunk(self, ttl_chunk): @@ -100,7 +109,6 @@ class Demo(EnvExperiment): delay(1*us) delay(10*us) - @kernel def test_ttl_outs(self): print("*** Testing TTL outputs.") print("Outputs are tested in groups of 4. Touch each TTL connector") @@ -108,25 +116,12 @@ class Demo(EnvExperiment): print("pulses corresponds to its number in the group.") print("Press ENTER when done.") - # for ttl_chunk in chunker(self.ttl_outs, 4): - for i in range(len(self.ttl_outs) // 4): - chunk_start, chunk_end = i*4, (i+1)*4 - ttl_chunk = self.ttl_outs[chunk_start:chunk_end] - print("Testing TTL outputs:", chunk_start, chunk_start+1, chunk_start+2, chunk_start+3) - self.test_ttl_out_chunk([dev for _, dev in ttl_chunk]) + for ttl_chunk in chunker(self.ttl_outs, 4): + print("Testing TTL outputs: {}.".format(", ".join(name for name, dev in ttl_chunk))) + self.test_ttl_out_chunk([dev for name, dev in ttl_chunk]) - @kernel def run(self): self.core.reset() - delay(10*ms) - print("*** Waiting for DRTIO ready...") - drtio_indices = [7] - for i in drtio_indices: - while not self.drtio_is_up(i): - pass - - self.fmcdio_dirctl.set(self.dirctl_word) - delay(10*ms) if self.leds: self.test_leds() From 1b475bdac41f746d5c0657ca3b617cadb69ec1e6 Mon Sep 17 00:00:00 2001 From: Stephan Maka Date: Thu, 3 Sep 2020 14:21:36 +0200 Subject: [PATCH 2321/2457] build_soc: remove assertion that was used for test runs --- artiq/build_soc.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/artiq/build_soc.py b/artiq/build_soc.py index ddce92fb1..e3a1f3360 100644 --- a/artiq/build_soc.py +++ b/artiq/build_soc.py @@ -47,9 +47,6 @@ class ReprogrammableIdentifier(Module, AutoCSR): def add_identifier(soc, *args, gateware_identifier_str=None, **kwargs): if hasattr(soc, "identifier"): raise ValueError - if gateware_identifier_str is None: - # not overridden with --identifier-str - raise ValueError("gateware_identifier_str not overridden") identifier_str = get_identifier_string(soc, *args, **kwargs) soc.submodules.identifier = ReprogrammableIdentifier(gateware_identifier_str or identifier_str) soc.config["IDENTIFIER_STR"] = identifier_str From 56aa22caeb02328eb5403d0c076d3ce168a34e51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 3 Sep 2020 17:42:35 +0200 Subject: [PATCH 2322/2457] fastino: document/cleanup * added documentation on `update`/`hold` mechanism * mask machine unit values * cleanup coredevice driver close #1518 --- artiq/coredevice/fastino.py | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/artiq/coredevice/fastino.py b/artiq/coredevice/fastino.py index 32306388a..200d89018 100644 --- a/artiq/coredevice/fastino.py +++ b/artiq/coredevice/fastino.py @@ -1,25 +1,44 @@ """RTIO driver for the Fastino 32channel, 16 bit, 2.5 MS/s per channel, streaming DAC. - -TODO: Example, describe update/hold """ from artiq.language.core import kernel, portable, delay -from artiq.coredevice.rtio import rtio_output, rtio_output_wide, rtio_input_data +from artiq.coredevice.rtio import (rtio_output, rtio_output_wide, + rtio_input_data) from artiq.language.units import us -from artiq.language.types import TInt32, TList, TFloat +from artiq.language.types import TInt32, TList class Fastino: """Fastino 32-channel, 16-bit, 2.5 MS/s per channel streaming DAC + The RTIO PHY supports staging DAC data before transmitting them by writing + to the DAC RTIO addresses, if a channel is not "held" by setting its bit + using :meth:`set_hold`, the next frame will contain the update. For the + DACs held, the update is triggered explicitly by setting the corresponding + bit using :meth:`set_update`. Update is self-clearing. This enables atomic + DAC updates synchronized to a frame edge. + + The `log2_width=0` RTIO layout uses one DAC channel per RTIO address + and a dense RTIO address space. The RTIO words are narrow. + (32 bit compared to 512) and few-channel updates are efficient. + There is the least amount of DAC state tracking in kernels, + at the cost of more DMA and RTIO data. + + Other `log2_width` (up to `log2_width=5`) settings pack multiple + (in powers of two) DAC channels into one group and into one RTIO write. + The RTIO data width increases accordingly. The `log2_width` + LSBs of the RTIO address for a DAC channel write must be zero and the + address space is sparse. + + If `log2_width` is zero, the :meth:`set_dac`/:meth:`set_dac_mu` interface + must be used. If non-zero, the :meth:`set_group`/:meth:`set_group_mu` + interface must be used. + :param channel: RTIO channel number :param core_device: Core device name (default: "core") :param log2_width: Width of DAC channel group (power of two, - see the RTIO PHY for details). If zero, the - :meth:`set_dac`/:meth:`set_dac_mu` interface must be used. - If non-zero, the :meth:`set_group`/:meth:`set_group_mu` - interface must be used. Value must match the corresponding value + see the RTIO PHY for details). Value must match the corresponding value in the RTIO PHY. """ kernel_invariants = {"core", "channel", "width"} @@ -94,7 +113,7 @@ class Fastino: :param voltage: Voltage in SI Volts. :return: DAC data word in machine units, 16 bit integer. """ - return int(round((0x8000/10.)*voltage)) + 0x8000 + return (int(round((0x8000/10.)*voltage)) + 0x8000) & 0xffff @portable def voltage_group_to_mu(self, voltage, data): From 6195b1d3a0d74b5587d62be425d2c3175331d10e Mon Sep 17 00:00:00 2001 From: pca006132 Date: Fri, 4 Sep 2020 13:49:22 +0800 Subject: [PATCH 2323/2457] rpc: fixed _write_bool Closes #1519 --- artiq/coredevice/comm_kernel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index babf035b3..98211d592 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -316,7 +316,7 @@ class CommKernel: self._write(self.pack_float64(value)) def _write_bool(self, value): - self._write(1 if value == True else 0) + self._write(b'\x01' if value else b'\x00') def _write_bytes(self, value): self._write_int32(len(value)) @@ -425,7 +425,7 @@ class CommKernel: elif tag == "b": check(isinstance(value, bool), lambda: "bool") - self._write_int8(value) + self._write_bool(value) elif tag == "i": check(isinstance(value, (int, numpy.int32)) and (-2**31 < value < 2**31-1), From e69bb0aeb3c77c66649fae7228fe57a51f02f697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 7 Sep 2020 16:06:16 +0000 Subject: [PATCH 2324/2457] phaser: add comment about get_dac_data --- artiq/coredevice/phaser.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 7eff5b51d..fec71b1c9 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -223,6 +223,9 @@ class Phaser: def get_dac_data(self, ch) -> TInt32: """Get a sample of the current DAC data. + The data is split accross multiple registers and thus the data + is only valid if constant. + :param ch: DAC channel pair (0 or 1) :return: DAC data as 32 bit IQ """ From 8aaeaa604e49a32f24a77748e5bbd7dffcd3a9da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 7 Sep 2020 16:06:35 +0000 Subject: [PATCH 2325/2457] phaser: share_lut --- artiq/gateware/rtio/phy/phaser.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index cc6ffa1e5..f8fe99548 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -6,13 +6,13 @@ from .fastlink import SerDes, SerInterface class DDSChannel(Module): - def __init__(self, use_lut=None): + def __init__(self, share_lut=None): self.rtlink = rtlink.Interface( rtlink.OInterface(data_width=32, address_width=4, enable_replace=True)) to_rio_phy = ClockDomainsRenamer("rio_phy") self.submodules.dds = to_rio_phy(MultiDDS( - n=5, fwidth=32, xwidth=16, z=19, zl=10, use_lut=use_lut)) + n=5, fwidth=32, xwidth=16, z=19, zl=10, shae_lut=share_lut)) regs = [] for i in self.dds.i: regs.extend([i.f, Cat(i.a, i.clr, i.p)]) @@ -32,7 +32,7 @@ class Phaser(Module): # share a CosSinGen LUT between the two channels self.submodules.ch0 = DDSChannel() - self.submodules.ch1 = DDSChannel(use_lut=self.ch0.dds.mod.cs.lut) + self.submodules.ch1 = DDSChannel(share_lut=self.ch0.dds.mod.cs.lut) n_channels = 2 n_samples = 8 n_bits = 14 From 4e24700205f200447c1464bc4e094cf33864566c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 9 Sep 2020 16:52:52 +0000 Subject: [PATCH 2326/2457] phaser: spelling --- artiq/gateware/rtio/phy/phaser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index f8fe99548..46dfc8005 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -12,7 +12,7 @@ class DDSChannel(Module): enable_replace=True)) to_rio_phy = ClockDomainsRenamer("rio_phy") self.submodules.dds = to_rio_phy(MultiDDS( - n=5, fwidth=32, xwidth=16, z=19, zl=10, shae_lut=share_lut)) + n=5, fwidth=32, xwidth=16, z=19, zl=10, share_lut=share_lut)) regs = [] for i in self.dds.i: regs.extend([i.f, Cat(i.a, i.clr, i.p)]) From bff611a888366d3f4cffe2086a257ad4ea8f2ad9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 11 Sep 2020 11:21:45 +0800 Subject: [PATCH 2327/2457] test: relax test_dma_playback_time on Zynq --- artiq/test/coredevice/test_rtio.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index de7318d27..3313b5c14 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -627,11 +627,13 @@ class _DMA(EnvExperiment): self.delta = now_mu() - start @kernel - def playback_many(self, n): + def playback_many(self, n, add_delay=False): handle = self.core_dma.get_handle(self.trace_name) self.core.break_realtime() t1 = self.core.get_rtio_counter_mu() for i in range(n): + if add_delay: + delay(2*us) self.core_dma.playback_handle(handle) t2 = self.core.get_rtio_counter_mu() self.set_dataset("dma_playback_time", self.core.mu_to_seconds(t2 - t1)) @@ -724,13 +726,18 @@ class DMATest(ExperimentCase): self.device_mgr.get_desc("ad9914dds0") except KeyError: raise unittest.SkipTest("skipped on Kasli for now") + exp = self.create(_DMA) + is_zynq = exp.core.target_cls == CortexA9Target count = 20000 exp.record_many(40) - exp.playback_many(count) + exp.playback_many(count, is_zynq) dt = self.dataset_mgr.get("dma_playback_time") print("dt={}, dt/count={}".format(dt, dt/count)) - self.assertLess(dt/count, 4.5*us) + if is_zynq: + self.assertLess(dt/count, 6.2*us) + else: + self.assertLess(dt/count, 4.5*us) def test_dma_underflow(self): exp = self.create(_DMA) From fdd2d6f2fbd2b61e976254e0b63f10d343b988a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sat, 12 Sep 2020 11:02:37 +0000 Subject: [PATCH 2328/2457] phaser: SI methods --- artiq/coredevice/phaser.py | 84 +++++++++++++++++++++++++---- artiq/gateware/rtio/phy/fastlink.py | 1 + 2 files changed, 75 insertions(+), 10 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index fec71b1c9..877bdef21 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -270,6 +270,18 @@ class Phaser: """ self.write32(PHASER_ADDR_DUC0_F + (ch << 4), ftw) + @kernel + def set_duc_frequency(self, ch, frequency): + """Set the DUC frequency. + + :param ch: DAC channel pair (0 or 1) + :param frequency: DUC frequency in Hz + """ + if ch < 0 or ch > 1: + raise ValueError("invalid channel index") + ftw = int32(round(frequency*((1 << 32)/500e6))) + self.set_duc_frequency_mu(ch, ftw) + @kernel def set_duc_phase_mu(self, ch, pow): """Set the DUC phase offset @@ -279,6 +291,18 @@ class Phaser: """ self.write16(PHASER_ADDR_DUC0_P + (ch << 4), pow) + @kernel + def set_duc_phase(self, ch, phase): + """Set the DUC phase. + + :param ch: DAC channel pair (0 or 1) + :param phase: DUC phase in turns + """ + if ch < 0 or ch > 1: + raise ValueError("invalid channel index") + pow = int32(round(phase*(1 << 16))) & 0xffff + self.set_duc_phase_mu(ch, pow) + @kernel def duc_stb(self): """Strobe the DUC configuration register update. @@ -303,12 +327,16 @@ class Phaser: :param offline: Put the SPI interfaces offline and don't drive voltages :param length: SPI transfer length (1 to 8 bits) """ + if div < 2 or div > 257: + raise ValueError("invalid divider") + if length < 0 or length > 8: + raise ValueError("invalid length") self.write8(PHASER_ADDR_SPI_SEL, select) self.write8(PHASER_ADDR_SPI_DIVLEN, (div - 2 >> 3) | (length - 1 << 5)) self.write8(PHASER_ADDR_SPI_CFG, - (offline << 0) | (end << 1) | (clk_phase << 2) | - (clk_polarity << 3) | (half_duplex << 4) | - (lsb_first << 5)) + ((offline & 1) << 0) | ((end & 1) << 1) | + ((clk_phase & 1) << 2) | ((clk_polarity & 1) << 3) | + ((half_duplex & 1) << 4) | ((lsb_first & 1) << 5)) @kernel def spi_write(self, data): @@ -328,7 +356,7 @@ class Phaser: :param addr: Register address :param data: Register data to write """ - div = 32 # 100 ns min period + div = 34 # 100 ns min period t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=0) self.spi_write(addr) @@ -340,7 +368,7 @@ class Phaser: delay_mu(t_xfer) @kernel - def dac_read(self, addr, div=32) -> TInt32: + def dac_read(self, addr, div=34) -> TInt32: """Read from a DAC register. :param addr: Register address to read from @@ -368,7 +396,7 @@ class Phaser: :param ch: RF channel (0 or 1) :param data: Attenuator data """ - div = 32 # 30 ns min period + div = 34 # 30 ns min period t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=1) self.spi_write(data) @@ -383,7 +411,7 @@ class Phaser: :param ch: RF channel (0 or 1) :return: Current attenuation """ - div = 32 + div = 34 t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=0) self.spi_write(0) @@ -403,7 +431,7 @@ class Phaser: :param data: Register data (32 bit) :param readback: Whether to return the read back MISO data """ - div = 32 # 50 ns min period + div = 34 # 50 ns min period t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) read = 0 end = 0 @@ -437,7 +465,7 @@ class Phaser: """ self.trf_write(ch, 0x80000008 | (addr << 28) | (cnt_mux_sel << 27)) # single clk pulse with ~LE to start readback - self.spi_cfg(select=0, div=32, end=1, length=1) + self.spi_cfg(select=0, div=34, end=1, length=1) self.spi_write(0) delay((1 + 1)*32*4*ns) return self.trf_write(ch, 0x00000008, readback=True) @@ -453,6 +481,22 @@ class Phaser: addr = ((self.channel_base + 1 + ch) << 8) | (osc << 1) rtio_output(addr, ftw) + @kernel + def set_frequency(self, ch, osc, frequency): + """Set Phaser MultiDDS frequency. + + :param ch: RF channel (0 or 1) + :param osc: Oscillator number (0 to 4) + :param frequency: Frequency in Hz + """ + if ch < 0 or ch > 1: + raise ValueError("invalid channel index") + if osc < 0 or osc > 4: + raise ValueError("invalid oscillator index") + ftw = int32(round(frequency*((1 << 32)/125e6))) + self.set_frequency_mu(ch, osc, ftw) + + @kernel def set_amplitude_phase_mu(self, ch, osc, asf=0x7fff, pow=0, clr=0): """Set Phaser MultiDDS amplitude, phase offset and accumulator clear. @@ -464,5 +508,25 @@ class Phaser: :param clr: Clear the phase accumulator (persistent) """ addr = ((self.channel_base + 1 + ch) << 8) | (osc << 1) | 1 - data = (asf & 0x7fff) | (clr << 15) | (pow << 16) + data = (asf & 0x7fff) | ((clr & 1) << 15) | ((pow & 0xffff) << 16) rtio_output(addr, data) + + @kernel + def set_amplitude_phase(self, ch, osc, amplitude, phase=0., clr=0): + """Set Phaser MultiDDS amplitude and phase. + + :param ch: RF channel (0 or 1) + :param osc: Oscillator number (0 to 4) + :param amplitude: Amplitude in units of full scale + :param phase: Phase in turns + :param clr: Clear the phase accumulator (persistent) + """ + if ch < 0 or ch > 1: + raise ValueError("invalid channel index") + if osc < 0 or osc > 4: + raise ValueError("invalid oscillator index") + asf = int32(round(amplitude*0x7fff)) + if asf < 0 or asf > 0x7fff: + raise ValueError("invalid amplitude") + pow = int32(round(phase*(1 << 16))) + self.set_amplitude_phase_mu(ch, osc, asf, pow, clr) diff --git a/artiq/gateware/rtio/phy/fastlink.py b/artiq/gateware/rtio/phy/fastlink.py index 0c361b901..796b01642 100644 --- a/artiq/gateware/rtio/phy/fastlink.py +++ b/artiq/gateware/rtio/phy/fastlink.py @@ -87,6 +87,7 @@ class SerDes(Module): self.crcb.last.eq(self.crca.next), miso_sr_next.eq(Cat(self.data[-1], miso_sr)), # unload miso + # TODO: align to marker self.readback.eq(Cat([miso_sr_next[t_miso + i*t_clk] for i in range(n_frame)])), ] From e505dfed5bc868f8d6c79bc42df1f82f17a2a5c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sat, 12 Sep 2020 14:17:40 +0000 Subject: [PATCH 2329/2457] phaser: refactor coredevice driver --- artiq/coredevice/phaser.py | 322 +++++++++++++++++++------------------ 1 file changed, 165 insertions(+), 157 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 877bdef21..3d5fc3892 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -93,12 +93,15 @@ class Phaser: def __init__(self, dmgr, channel_base, miso_delay=1, core_device="core"): self.channel_base = channel_base self.core = dmgr.get(core_device) + # TODO: auto-align miso-delay in phy self.miso_delay = miso_delay # frame duration in mu (10 words, 8 clock cycles each 4 ns) # self.core.seconds_to_mu(10*8*4*ns) # unfortunately this returns 319 assert self.core.ref_period == 1*ns self.t_frame = 10*8*4 + self.channel = [PhaserChannel(self, ch) for ch in range(2)] + @kernel def init(self): """Initialize the board. @@ -150,17 +153,6 @@ class Phaser: delay(20*us) # slack return data - @kernel - def write16(self, addr, data: TInt32): - """Write 16 bit to a sequence of FPGA registers.""" - self.write8(addr, data >> 8) - self.write8(addr + 1, data) - - @kernel - def read16(self, addr) -> TInt32: - """Read 16 bit from a sequence of FPGA registers.""" - return (self.read8(addr) << 8) | self.read8(addr) - @kernel def set_leds(self, leds): """Set the front panel LEDs. @@ -169,19 +161,32 @@ class Phaser: """ self.write8(PHASER_ADDR_LED, leds) + @kernel + def set_fan_mu(self, pwm): + """Set the fan duty cycle. + + :param pwm: Duty cycle (8 bit) + """ + self.write8(PHASER_ADDR_FAN, pwm) + @kernel def set_fan(self, duty): """Set the fan duty cycle. - :param duty: Duty cycle (8 bit) + :param duty: Duty cycle (0. to 1.) """ - self.write8(PHASER_ADDR_FAN, duty) + pwm = int32(round(duty*255.)) + if pwm < 0 or pwm > 0xff: + raise ValueError("invalid duty cycle") + self.set_fan_mu(pwm) @kernel def set_cfg(self, clk_sel=0, dac_resetb=1, dac_sleep=0, dac_txena=1, trf0_ps=0, trf1_ps=0, att0_rstn=1, att1_rstn=1): """Set the configuration register. + Each flag is a single bit (0 or 1). + :param clk_sel: Select the external SMA clock input :param dac_resetb: Active low DAC reset pin :param dac_sleep: DAC sleep pin @@ -192,9 +197,10 @@ class Phaser: :param att1_rstn: Active low attenuator 1 reset """ self.write8(PHASER_ADDR_CFG, - (clk_sel << 0) | (dac_resetb << 1) | (dac_sleep << 2) | - (dac_txena << 3) | (trf0_ps << 4) | (trf1_ps << 5) | - (att0_rstn << 6) | (att1_rstn << 7)) + ((clk_sel & 1) << 0) | ((dac_resetb & 1) << 1) | + ((dac_sleep & 1) << 2) | ((dac_txena & 1) << 3) | + ((trf0_ps & 1) << 4) | ((trf1_ps & 1) << 5) | + ((att0_rstn & 1) << 6) | ((att1_rstn & 1) << 7)) @kernel def get_sta(self): @@ -216,93 +222,13 @@ class Phaser: @kernel def get_crc_err(self): - """Get the frame CRC error counter.""" + """Get the frame CRC error counter. + + :return: The number of frames with CRC mismatches sind the reset of the + device. Overflows at 256. + """ return self.read8(PHASER_ADDR_CRC_ERR) - @kernel - def get_dac_data(self, ch) -> TInt32: - """Get a sample of the current DAC data. - - The data is split accross multiple registers and thus the data - is only valid if constant. - - :param ch: DAC channel pair (0 or 1) - :return: DAC data as 32 bit IQ - """ - data = 0 - for addr in range(4): - data <<= 8 - data |= self.read8(PHASER_ADDR_DAC0_DATA + (ch << 4) + addr) - delay(20*us) # slack - return data - - @kernel - def set_dac_test(self, ch, data: TInt32): - """Set the DAC test data. - - :param ch: DAC channel pair (0 or 1) - :param data: 32 bit IQ test data - """ - for addr in range(4): - byte = data >> 24 - self.write8(PHASER_ADDR_DAC0_TEST + (ch << 4) + addr, byte) - data <<= 8 - - @kernel - def set_duc_cfg(self, ch, clr=0, clr_once=0, select=0): - """Set the digital upconverter and interpolator configuration. - - :param ch: DAC channel pair (0 or 1) - :param clr: Keep the phase accumulator cleared - :param clr_once: Clear the phase accumulator for one cycle - :param select: Select the data to send to the DAC (0: DUC data, 1: test - data) - """ - self.write8(PHASER_ADDR_DUC0_CFG + (ch << 4), - (clr << 0) | (clr_once << 1) | (select << 2)) - - @kernel - def set_duc_frequency_mu(self, ch, ftw): - """Set the DUC frequency. - - :param ch: DAC channel pair (0 or 1) - :param ftw: DUC frequency tuning word - """ - self.write32(PHASER_ADDR_DUC0_F + (ch << 4), ftw) - - @kernel - def set_duc_frequency(self, ch, frequency): - """Set the DUC frequency. - - :param ch: DAC channel pair (0 or 1) - :param frequency: DUC frequency in Hz - """ - if ch < 0 or ch > 1: - raise ValueError("invalid channel index") - ftw = int32(round(frequency*((1 << 32)/500e6))) - self.set_duc_frequency_mu(ch, ftw) - - @kernel - def set_duc_phase_mu(self, ch, pow): - """Set the DUC phase offset - - :param ch: DAC channel pair (0 or 1) - :param pow: DUC phase offset word - """ - self.write16(PHASER_ADDR_DUC0_P + (ch << 4), pow) - - @kernel - def set_duc_phase(self, ch, phase): - """Set the DUC phase. - - :param ch: DAC channel pair (0 or 1) - :param phase: DUC phase in turns - """ - if ch < 0 or ch > 1: - raise ValueError("invalid channel index") - pow = int32(round(phase*(1 << 16))) & 0xffff - self.set_duc_phase_mu(ch, pow) - @kernel def duc_stb(self): """Strobe the DUC configuration register update. @@ -389,50 +315,141 @@ class Phaser: data |= self.spi_read() return data + +class PhaserChannel: + """Phaser channel IQ pair""" + kernel_invariants = {"channel", "phaser"} + + def __init__(self, phaser, channel): + self.phaser = phaser + self.channel = channel + self.oscillator = [PhaserOscillator(self, osc) for osc in range(5)] + @kernel - def att_write(self, ch, data): + def get_dac_data(self) -> TInt32: + """Get a sample of the current DAC data. + + The data is split accross multiple registers and thus the data + is only valid if constant. + + :return: DAC data as 32 bit IQ. I in the 16 LSB, Q in the 16 MSB + """ + return self.phaser.read32(PHASER_ADDR_DAC0_DATA + (self.channel << 4)) + + @kernel + def set_dac_test(self, data: TInt32): + """Set the DAC test data. + + :param data: 32 bit IQ test data, I in the 16 LSB, Q in the 16 MSB + """ + self.phaser.write32(PHASER_ADDR_DAC0_TEST + (self.channel << 4), data) + + @kernel + def set_duc_cfg(self, clr=0, clr_once=0, select=0): + """Set the digital upconverter and interpolator configuration. + + :param clr: Keep the phase accumulator cleared + :param clr_once: Clear the phase accumulator for one cycle + :param select: Select the data to send to the DAC (0: DUC data, 1: test + data) + """ + if select < 0 or select > 3: + raise ValueError("invalid data select") + self.phaser.write8(PHASER_ADDR_DUC0_CFG + (self.channel << 4), + ((clr & 1) << 0) | ((clr_once & 1) << 1) | + ((select & 3) << 2)) + + @kernel + def set_duc_frequency_mu(self, ftw): + """Set the DUC frequency. + + :param ftw: DUC frequency tuning word + """ + self.phaser.write32(PHASER_ADDR_DUC0_F + (self.channel << 4), ftw) + + @kernel + def set_duc_frequency(self, frequency): + """Set the DUC frequency. + + :param frequency: DUC frequency in Hz + """ + ftw = int32(round(frequency*((1 << 32)/500e6))) + self.set_duc_frequency_mu(ftw) + + @kernel + def set_duc_phase_mu(self, pow): + """Set the DUC phase offset + + :param pow: DUC phase offset word + """ + addr = PHASER_ADDR_DUC0_P + (self.channel << 4) + self.phaser.write8(addr, pow >> 8) + self.phaser.write8(addr + 1, pow) + + @kernel + def set_duc_phase(self, phase): + """Set the DUC phase. + + :param phase: DUC phase in turns + """ + pow = int32(round(phase*(1 << 16))) + self.set_duc_phase_mu(pow) + + @kernel + def set_att_mu(self, data): """Set channel attenuation. - :param ch: RF channel (0 or 1) :param data: Attenuator data """ div = 34 # 30 ns min period - t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) - self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=1) - self.spi_write(data) + t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns) + self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.channel, div=div, + end=1) + self.phaser.spi_write(data) delay_mu(t_xfer) @kernel - def att_read(self, ch) -> TInt32: + def set_att(self, att): + """Set channel attenuation in SI units. + + :param att: Attenuation in dB + """ + data = 0xff - int32(round(att*8)) + if data < 0 or data > 0xff: + raise ValueError("invalid attenuation") + self.set_att_mu(data) + + @kernel + def get_att_mu(self) -> TInt32: """Read current attenuation. The current attenuation value is read without side effects. - :param ch: RF channel (0 or 1) :return: Current attenuation """ div = 34 - t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) - self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=0) - self.spi_write(0) + t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns) + self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.channel, div=div, + end=0) + self.phaser.spi_write(0) delay_mu(t_xfer) - data = self.spi_read() + data = self.phaser.spi_read() delay(10*us) # slack - self.spi_cfg(select=PHASER_SEL_ATT0 << ch, div=div, end=1) - self.spi_write(data) + self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.channel, div=div, + end=1) + self.phaser.spi_write(data) delay_mu(t_xfer) return data @kernel - def trf_write(self, ch, data, readback=False): + def trf_write(self, data, readback=False): """Write 32 bits to a TRF upconverter. - :param ch: RF channel (0 or 1) - :param data: Register data (32 bit) + :param data: Register data (32 bit) containing encoded address :param readback: Whether to return the read back MISO data """ div = 34 # 50 ns min period - t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) + t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns) read = 0 end = 0 clk_phase = 0 @@ -442,91 +459,82 @@ class Phaser: if i == 0 or i == 3: if i == 3: end = 1 - self.spi_cfg(select=PHASER_SEL_TRF0 << ch, div=div, - lsb_first=1, clk_phase=clk_phase, end=end) - self.spi_write(data) + self.phaser.spi_cfg(select=PHASER_SEL_TRF0 << self.channel, + div=div, lsb_first=1, clk_phase=clk_phase, + end=end) + self.phaser.spi_write(data) data >>= 8 delay_mu(t_xfer) if readback: read >>= 8 - read |= self.spi_read() << 24 + read |= self.phaser.spi_read() << 24 delay(10*us) # slack return read @kernel - def trf_read(self, ch, addr, cnt_mux_sel=0) -> TInt32: + def trf_read(self, addr, cnt_mux_sel=0) -> TInt32: """TRF upconverter register read. - :param ch: RF channel (0 or 1) - :param addr: Register address to read + :param addr: Register address to read (0 to 7) :param cnt_mux_sel: Report VCO counter min frequency or max frequency :return: Register data (32 bit) """ - self.trf_write(ch, 0x80000008 | (addr << 28) | (cnt_mux_sel << 27)) + self.trf_write(0x80000008 | (addr << 28) | (cnt_mux_sel << 27)) # single clk pulse with ~LE to start readback - self.spi_cfg(select=0, div=34, end=1, length=1) - self.spi_write(0) + self.phaser.spi_cfg(select=0, div=34, end=1, length=1) + self.phaser.spi_write(0) delay((1 + 1)*32*4*ns) - return self.trf_write(ch, 0x00000008, readback=True) + return self.trf_write(0x00000008, readback=True) + + +class PhaserOscillator: + """Phaser IQ channel oscillator""" + kernel_invariants = {"channel", "base_addr"} + + def __init__(self, channel, oscillator): + self.channel = channel + self.base_addr = ((self.channel.phaser.channel_base + 1 + + self.channel.channel) << 8) | (oscillator << 1) @kernel - def set_frequency_mu(self, ch, osc, ftw): + def set_frequency_mu(self, ftw): """Set Phaser MultiDDS frequency tuning word. - :param ch: RF channel (0 or 1) - :param osc: Oscillator number (0 to 4) :param ftw: Frequency tuning word (32 bit) """ - addr = ((self.channel_base + 1 + ch) << 8) | (osc << 1) - rtio_output(addr, ftw) + rtio_output(self.base_addr, ftw) @kernel - def set_frequency(self, ch, osc, frequency): + def set_frequency(self, frequency): """Set Phaser MultiDDS frequency. - :param ch: RF channel (0 or 1) - :param osc: Oscillator number (0 to 4) :param frequency: Frequency in Hz """ - if ch < 0 or ch > 1: - raise ValueError("invalid channel index") - if osc < 0 or osc > 4: - raise ValueError("invalid oscillator index") ftw = int32(round(frequency*((1 << 32)/125e6))) - self.set_frequency_mu(ch, osc, ftw) - + self.set_frequency_mu(ftw) @kernel - def set_amplitude_phase_mu(self, ch, osc, asf=0x7fff, pow=0, clr=0): + def set_amplitude_phase_mu(self, asf=0x7fff, pow=0, clr=0): """Set Phaser MultiDDS amplitude, phase offset and accumulator clear. - :param ch: RF channel (0 or 1) - :param osc: Oscillator number (0 to 4) :param asf: Amplitude (15 bit) :param pow: Phase offset word (16 bit) :param clr: Clear the phase accumulator (persistent) """ - addr = ((self.channel_base + 1 + ch) << 8) | (osc << 1) | 1 - data = (asf & 0x7fff) | ((clr & 1) << 15) | ((pow & 0xffff) << 16) - rtio_output(addr, data) + data = (asf & 0x7fff) | ((clr & 1) << 15) | (pow << 16) + rtio_output(self.base_addr | 1, data) @kernel - def set_amplitude_phase(self, ch, osc, amplitude, phase=0., clr=0): + def set_amplitude_phase(self, amplitude, phase=0., clr=0): """Set Phaser MultiDDS amplitude and phase. - :param ch: RF channel (0 or 1) - :param osc: Oscillator number (0 to 4) :param amplitude: Amplitude in units of full scale :param phase: Phase in turns :param clr: Clear the phase accumulator (persistent) """ - if ch < 0 or ch > 1: - raise ValueError("invalid channel index") - if osc < 0 or osc > 4: - raise ValueError("invalid oscillator index") asf = int32(round(amplitude*0x7fff)) if asf < 0 or asf > 0x7fff: raise ValueError("invalid amplitude") pow = int32(round(phase*(1 << 16))) - self.set_amplitude_phase_mu(ch, osc, asf, pow, clr) + self.set_amplitude_phase_mu(asf, pow, clr) From c3728678d615c87b43522de2dc15c3c57c322e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sat, 12 Sep 2020 17:19:10 +0000 Subject: [PATCH 2330/2457] phaser: document, elaborate comments, some fixes --- artiq/coredevice/phaser.py | 159 +++++++++++++++++++++++-------------- 1 file changed, 99 insertions(+), 60 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 3d5fc3892..f61f3edf4 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -1,6 +1,6 @@ from artiq.language.core import kernel, delay_mu, delay from artiq.coredevice.rtio import rtio_output, rtio_input_data -from artiq.language.units import us, ns +from artiq.language.units import us, ns, MHz from artiq.language.types import TInt32 @@ -57,36 +57,56 @@ class Phaser: Phaser contains a 4 channel, 1 GS/s DAC chip with integrated upconversion, quadrature modulation compensation and interpolation features. - The coredevice produces 2 IQ data streams with 25 MS/s 14 bit. Each - data stream supports 5 independent numerically controlled oscillators (NCOs) - added together for each channel. Together with a data clock, framing - marker, a checksum and metadata for register access the data is sent in - groups of 8 samples over 1.5 Gb/s FastLink via a single EEM connector. + The coredevice produces 2 IQ data streams with 25 MS/s and 14 bit per + quadrature. Each data stream supports 5 independent numerically controlled + IQ oscillators (NCOs, DDSs with 32 bit frequency, 16 bit phase, 15 bit + amplitude, and phase accumulator clear functionality) added together. + See :class:`PhaserChannel` and :class:`PhaserOscillator`. - On Phaser the data streams are buffered and interpolated from 25 MS/s to 500 - MS/s 16 bit followed by a 500 MS/s digital upconverter in the FPGA. + Together with a data clock, framing marker, a checksum and metadata for + register access the streams are sent in groups of 8 samples over 1.5 Gb/s + FastLink via a single EEM connector from coredevice to Phaser. + + On Phaser in the FPGA the data streams are buffered and interpolated + from 25 MS/s to 500 MS/s 16 bit followed by a 500 MS/s digital upconverter + with adjustable frequency and phase. The interpolation passband is 20 MHz + wide, passband ripple is less than 1e-3 amplitude, stopband attenuation + is better than 75 dB at offsets > 15 MHz and better than 90 dB at offsets + > 30 MHz. The four 16 bit 500 MS/s DAC data streams are sent via a 32 bit parallel - LVDS bus operating at 1 Gb/s per pin pair and processed in the DAC. + LVDS bus operating at 1 Gb/s per pin pair and processed in the DAC. On the + DAC 2x interpolation, sinx/x compensation, quadrature modulator compensation, + fine and coarse mixing as well as group delay capabilities are available. - The four analog DAC outputs are passed through anti-aliasing filters and In - the baseband variant, the even channels feed 31.5 dB range and are - available on the front panel. The odd outputs are available on MMCX - connectors on board. + The latency/group delay from the RTIO events setting + :class:`PhaserOscillator` or :class:`PhaserChannel` DUC parameters all they + way to the DAC outputs is deterministic. This enables deterministic + absolute phase with respect to other RTIO input and output events. + + The four analog DAC outputs are passed through anti-aliasing filters. + + In the baseband variant, the even/in-phase DAC channels feed 31.5 dB range + attenuators and are available on the front panel. The odd outputs are + available at MMCX connectors on board. In the upconverter variant, each of the two IQ (in-phase and quadrature) output pairs feeds a one quadrature upconverter with integrated PLL/VCO. - The output from the upconverter passes through the step attenuator and is - available at the front panel. + This analog quadrature upconverter supports offset tuning for carrier and + sideband suppression. The output from the upconverter passes through the + 31.5 dB range step attenuator and is available at the front panel. - The DAC, the TRF upconverters and the two attenuators are configured - through a shared SPI bus that is accessed and controlled via FPGA + The DAC, the analog quadrature upconverters and the two attenuators are + configured through a shared SPI bus that is accessed and controlled via FPGA registers. :param channel: Base RTIO channel number :param core_device: Core device name (default: "core") :param miso_delay: Fastlink MISO signal delay to account for cable and buffer round trip. This might be automated later. + + :attr:`channel`: List of two :class:`PhaserChannel` to access oscillators + and digital upconverter. """ kernel_invariants = {"core", "channel_base", "t_frame", "miso_delay"} @@ -176,7 +196,7 @@ class Phaser: :param duty: Duty cycle (0. to 1.) """ pwm = int32(round(duty*255.)) - if pwm < 0 or pwm > 0xff: + if pwm < 0 or pwm > 255: raise ValueError("invalid duty cycle") self.set_fan_mu(pwm) @@ -191,8 +211,8 @@ class Phaser: :param dac_resetb: Active low DAC reset pin :param dac_sleep: DAC sleep pin :param dac_txena: Enable DAC transmission pin - :param trf0_ps: TRF0 upconverter power save - :param trf1_ps: TRF1 upconverter power save + :param trf0_ps: Quadrature upconverter 0 power save + :param trf1_ps: Quadrature upconverter 1 power save :param att0_rstn: Active low attenuator 0 reset :param att1_rstn: Active low attenuator 1 reset """ @@ -209,8 +229,8 @@ class Phaser: Bit flags are: * `PHASER_STA_DAC_ALARM`: DAC alarm pin - * `PHASER_STA_TRF0_LD`: TRF0 lock detect pin - * `PHASER_STA_TRF1_LD`: TRF1 lock detect pin + * `PHASER_STA_TRF0_LD`: Quadrature upconverter 0 lock detect + * `PHASER_STA_TRF1_LD`: Quadrature upconverter 1 lock detect * `PHASER_STA_TERM0`: ADC channel 0 termination indicator * `PHASER_STA_TERM1`: ADC channel 1 termination indicator * `PHASER_STA_SPI_IDLE`: SPI machine is idle and data registers can be @@ -255,7 +275,7 @@ class Phaser: """ if div < 2 or div > 257: raise ValueError("invalid divider") - if length < 0 or length > 8: + if length < 1 or length > 8: raise ValueError("invalid length") self.write8(PHASER_ADDR_SPI_SEL, select) self.write8(PHASER_ADDR_SPI_DIVLEN, (div - 2 >> 3) | (length - 1 << 5)) @@ -298,8 +318,8 @@ class Phaser: """Read from a DAC register. :param addr: Register address to read from - :param div: SPI clock divider. Needs to be at least 250 to read the - temperature register. + :param div: SPI clock divider. Needs to be at least 250 (1 µs SPI + clock) to read the temperature register. """ t_xfer = self.core.seconds_to_mu((8 + 1)*div*4*ns) self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=0) @@ -308,7 +328,7 @@ class Phaser: self.spi_write(0) delay_mu(t_xfer) data = self.spi_read() << 8 - delay(10*us) # slack + delay(20*us) # slack self.spi_cfg(select=PHASER_SEL_DAC, div=div, end=1) self.spi_write(0) delay_mu(t_xfer) @@ -317,12 +337,27 @@ class Phaser: class PhaserChannel: - """Phaser channel IQ pair""" - kernel_invariants = {"channel", "phaser"} + """Phaser channel IQ pair. - def __init__(self, phaser, channel): + :attr:`oscillator`: List of five :class:`PhaserOscillator`. + + .. note:: The amplitude sum of the oscillators must be less than one to + avoid clipping or overflow. If any of the DDS or DUC frequencies are + non-zero, it is not sufficient to ensure that the sum in each + quadrature is within range. + + .. note:: The interpolation filter on Phaser has an intrinsic sinc-like + overshoot in its step response. That overshoot is an direct consequence + of its near-brick-wall frequency response. For large and wide-band + changes in oscillator parameters, the overshoot can lead to clipping + or overflow after the interpolation. Either band-limit any changes + in the oscillator parameters or back off the amplitude sufficiently. + """ + kernel_invariants = {"index", "phaser"} + + def __init__(self, phaser, index): self.phaser = phaser - self.channel = channel + self.index = index self.oscillator = [PhaserOscillator(self, osc) for osc in range(5)] @kernel @@ -334,7 +369,7 @@ class PhaserChannel: :return: DAC data as 32 bit IQ. I in the 16 LSB, Q in the 16 MSB """ - return self.phaser.read32(PHASER_ADDR_DAC0_DATA + (self.channel << 4)) + return self.phaser.read32(PHASER_ADDR_DAC0_DATA + (self.index << 4)) @kernel def set_dac_test(self, data: TInt32): @@ -342,20 +377,18 @@ class PhaserChannel: :param data: 32 bit IQ test data, I in the 16 LSB, Q in the 16 MSB """ - self.phaser.write32(PHASER_ADDR_DAC0_TEST + (self.channel << 4), data) + self.phaser.write32(PHASER_ADDR_DAC0_TEST + (self.index << 4), data) @kernel def set_duc_cfg(self, clr=0, clr_once=0, select=0): """Set the digital upconverter and interpolator configuration. - :param clr: Keep the phase accumulator cleared + :param clr: Keep the phase accumulator cleared (persistent) :param clr_once: Clear the phase accumulator for one cycle :param select: Select the data to send to the DAC (0: DUC data, 1: test - data) + data, other values: reserved) """ - if select < 0 or select > 3: - raise ValueError("invalid data select") - self.phaser.write8(PHASER_ADDR_DUC0_CFG + (self.channel << 4), + self.phaser.write8(PHASER_ADDR_DUC0_CFG + (self.index << 4), ((clr & 1) << 0) | ((clr_once & 1) << 1) | ((select & 3) << 2)) @@ -363,26 +396,27 @@ class PhaserChannel: def set_duc_frequency_mu(self, ftw): """Set the DUC frequency. - :param ftw: DUC frequency tuning word + :param ftw: DUC frequency tuning word (32 bit) """ - self.phaser.write32(PHASER_ADDR_DUC0_F + (self.channel << 4), ftw) + self.phaser.write32(PHASER_ADDR_DUC0_F + (self.index << 4), ftw) @kernel def set_duc_frequency(self, frequency): """Set the DUC frequency. - :param frequency: DUC frequency in Hz + :param frequency: DUC frequency in Hz (passband from -200 MHz to + 200 MHz, wrapping around at +- 250 MHz) """ - ftw = int32(round(frequency*((1 << 32)/500e6))) + ftw = int32(round(frequency*((1 << 32)/(500*MHz)))) self.set_duc_frequency_mu(ftw) @kernel def set_duc_phase_mu(self, pow): """Set the DUC phase offset - :param pow: DUC phase offset word + :param pow: DUC phase offset word (16 bit) """ - addr = PHASER_ADDR_DUC0_P + (self.channel << 4) + addr = PHASER_ADDR_DUC0_P + (self.index << 4) self.phaser.write8(addr, pow >> 8) self.phaser.write8(addr + 1, pow) @@ -403,7 +437,7 @@ class PhaserChannel: """ div = 34 # 30 ns min period t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns) - self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.channel, div=div, + self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.index, div=div, end=1) self.phaser.spi_write(data) delay_mu(t_xfer) @@ -425,17 +459,17 @@ class PhaserChannel: The current attenuation value is read without side effects. - :return: Current attenuation + :return: Current attenuation in machine units """ div = 34 t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns) - self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.channel, div=div, + self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.index, div=div, end=0) self.phaser.spi_write(0) delay_mu(t_xfer) data = self.phaser.spi_read() - delay(10*us) # slack - self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.channel, div=div, + delay(20*us) # slack + self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.index, div=div, end=1) self.phaser.spi_write(data) delay_mu(t_xfer) @@ -443,7 +477,7 @@ class PhaserChannel: @kernel def trf_write(self, data, readback=False): - """Write 32 bits to a TRF upconverter. + """Write 32 bits to upconverter. :param data: Register data (32 bit) containing encoded address :param readback: Whether to return the read back MISO data @@ -459,7 +493,7 @@ class PhaserChannel: if i == 0 or i == 3: if i == 3: end = 1 - self.phaser.spi_cfg(select=PHASER_SEL_TRF0 << self.channel, + self.phaser.spi_cfg(select=PHASER_SEL_TRF0 << self.index, div=div, lsb_first=1, clk_phase=clk_phase, end=end) self.phaser.spi_write(data) @@ -468,34 +502,38 @@ class PhaserChannel: if readback: read >>= 8 read |= self.phaser.spi_read() << 24 - delay(10*us) # slack + delay(20*us) # slack return read @kernel def trf_read(self, addr, cnt_mux_sel=0) -> TInt32: - """TRF upconverter register read. + """Quadrature upconverter register read. :param addr: Register address to read (0 to 7) - :param cnt_mux_sel: Report VCO counter min frequency - or max frequency + :param cnt_mux_sel: Report VCO counter min or max frequency :return: Register data (32 bit) """ self.trf_write(0x80000008 | (addr << 28) | (cnt_mux_sel << 27)) # single clk pulse with ~LE to start readback self.phaser.spi_cfg(select=0, div=34, end=1, length=1) self.phaser.spi_write(0) - delay((1 + 1)*32*4*ns) + delay((1 + 1)*34*4*ns) return self.trf_write(0x00000008, readback=True) class PhaserOscillator: - """Phaser IQ channel oscillator""" + """Phaser IQ channel oscillator (NCO/DDS). + + .. note:: Latencies between oscillators within a channel and between + oscillator paramters (amplitude and phase/frequency) are deterministic + (with respect to the 25 MS/s sample clock) but not matched. + """ kernel_invariants = {"channel", "base_addr"} - def __init__(self, channel, oscillator): + def __init__(self, channel, index): self.channel = channel self.base_addr = ((self.channel.phaser.channel_base + 1 + - self.channel.channel) << 8) | (oscillator << 1) + self.channel.index) << 8) | (index << 1) @kernel def set_frequency_mu(self, ftw): @@ -509,9 +547,10 @@ class PhaserOscillator: def set_frequency(self, frequency): """Set Phaser MultiDDS frequency. - :param frequency: Frequency in Hz + :param frequency: Frequency in Hz (passband from -10 MHz to 10 MHz, + wrapping around at +- 12.5 MHz) """ - ftw = int32(round(frequency*((1 << 32)/125e6))) + ftw = int32(round(frequency*((1 << 32)/(25*MHz)))) self.set_frequency_mu(ftw) @kernel From b619f657b92b3b59ef0a2d4e2f0a5c9c1f7afced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sat, 12 Sep 2020 19:59:49 +0200 Subject: [PATCH 2331/2457] phaser: doc tweaks --- artiq/coredevice/phaser.py | 39 ++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index f61f3edf4..98777bd25 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -76,8 +76,9 @@ class Phaser: The four 16 bit 500 MS/s DAC data streams are sent via a 32 bit parallel LVDS bus operating at 1 Gb/s per pin pair and processed in the DAC. On the - DAC 2x interpolation, sinx/x compensation, quadrature modulator compensation, - fine and coarse mixing as well as group delay capabilities are available. + DAC 2x interpolation, sinx/x compensation, quadrature modulator + compensation, fine and coarse mixing as well as group delay capabilities + are available. The latency/group delay from the RTIO events setting :class:`PhaserOscillator` or :class:`PhaserChannel` DUC parameters all they @@ -97,16 +98,19 @@ class Phaser: 31.5 dB range step attenuator and is available at the front panel. The DAC, the analog quadrature upconverters and the two attenuators are - configured through a shared SPI bus that is accessed and controlled via FPGA - registers. + configured through a shared SPI bus that is accessed and controlled via + FPGA registers. :param channel: Base RTIO channel number :param core_device: Core device name (default: "core") :param miso_delay: Fastlink MISO signal delay to account for cable and buffer round trip. This might be automated later. - :attr:`channel`: List of two :class:`PhaserChannel` to access oscillators - and digital upconverter. + Attributes: + + * :attr:`channel`: List of two :class:`PhaserChannel` + To access oscillators, digital upconverters, PLL/VCO analog + quadrature upconverters and attenuators. """ kernel_invariants = {"core", "channel_base", "t_frame", "miso_delay"} @@ -185,7 +189,7 @@ class Phaser: def set_fan_mu(self, pwm): """Set the fan duty cycle. - :param pwm: Duty cycle (8 bit) + :param pwm: Duty cycle in machine units (8 bit) """ self.write8(PHASER_ADDR_FAN, pwm) @@ -228,13 +232,13 @@ class Phaser: Bit flags are: - * `PHASER_STA_DAC_ALARM`: DAC alarm pin - * `PHASER_STA_TRF0_LD`: Quadrature upconverter 0 lock detect - * `PHASER_STA_TRF1_LD`: Quadrature upconverter 1 lock detect - * `PHASER_STA_TERM0`: ADC channel 0 termination indicator - * `PHASER_STA_TERM1`: ADC channel 1 termination indicator - * `PHASER_STA_SPI_IDLE`: SPI machine is idle and data registers can be - read/written + * :const:`PHASER_STA_DAC_ALARM`: DAC alarm pin + * :const:`PHASER_STA_TRF0_LD`: Quadrature upconverter 0 lock detect + * :const:`PHASER_STA_TRF1_LD`: Quadrature upconverter 1 lock detect + * :const:`PHASER_STA_TERM0`: ADC channel 0 termination indicator + * :const:`PHASER_STA_TERM1`: ADC channel 1 termination indicator + * :const:`PHASER_STA_SPI_IDLE`: SPI machine is idle and data registers + can be read/written :return: Status register """ @@ -339,7 +343,9 @@ class Phaser: class PhaserChannel: """Phaser channel IQ pair. - :attr:`oscillator`: List of five :class:`PhaserOscillator`. + Attributes: + + * :attr:`oscillator`: List of five :class:`PhaserOscillator`. .. note:: The amplitude sum of the oscillators must be less than one to avoid clipping or overflow. If any of the DDS or DUC frequencies are @@ -433,7 +439,7 @@ class PhaserChannel: def set_att_mu(self, data): """Set channel attenuation. - :param data: Attenuator data + :param data: Attenuator data in machine units (8 bit) """ div = 34 # 30 ns min period t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns) @@ -448,6 +454,7 @@ class PhaserChannel: :param att: Attenuation in dB """ + # 2 lsb are inactive, resulting in 8 LSB per dB data = 0xff - int32(round(att*8)) if data < 0 or data > 0xff: raise ValueError("invalid attenuation") From b449e7202b0a9dda9a2ef1847005cdc9a736970c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 14 Sep 2020 07:34:55 +0000 Subject: [PATCH 2332/2457] phaser: rework docs --- artiq/coredevice/phaser.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 98777bd25..7449ab19b 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -57,11 +57,11 @@ class Phaser: Phaser contains a 4 channel, 1 GS/s DAC chip with integrated upconversion, quadrature modulation compensation and interpolation features. - The coredevice produces 2 IQ data streams with 25 MS/s and 14 bit per - quadrature. Each data stream supports 5 independent numerically controlled - IQ oscillators (NCOs, DDSs with 32 bit frequency, 16 bit phase, 15 bit - amplitude, and phase accumulator clear functionality) added together. - See :class:`PhaserChannel` and :class:`PhaserOscillator`. + The coredevice produces 2 IQ (in-phase and quadrature) data streams with 25 + MS/s and 14 bit per quadrature. Each data stream supports 5 independent + numerically controlled IQ oscillators (NCOs, DDSs with 32 bit frequency, 16 + bit phase, 15 bit amplitude, and phase accumulator clear functionality) + added together. See :class:`PhaserChannel` and :class:`PhaserOscillator`. Together with a data clock, framing marker, a checksum and metadata for register access the streams are sent in groups of 8 samples over 1.5 Gb/s @@ -91,13 +91,13 @@ class Phaser: attenuators and are available on the front panel. The odd outputs are available at MMCX connectors on board. - In the upconverter variant, each of the two IQ (in-phase and quadrature) - output pairs feeds a one quadrature upconverter with integrated PLL/VCO. - This analog quadrature upconverter supports offset tuning for carrier and - sideband suppression. The output from the upconverter passes through the - 31.5 dB range step attenuator and is available at the front panel. + In the upconverter variant, each IQ output pair feeds a one quadrature + upconverter with integrated PLL/VCO. This analog quadrature upconverter + supports offset tuning for carrier and sideband suppression. The output + from the upconverter passes through the 31.5 dB range step attenuator and + is available at the front panel. - The DAC, the analog quadrature upconverters and the two attenuators are + The DAC, the analog quadrature upconverters and the attenuators are configured through a shared SPI bus that is accessed and controlled via FPGA registers. @@ -373,7 +373,8 @@ class PhaserChannel: The data is split accross multiple registers and thus the data is only valid if constant. - :return: DAC data as 32 bit IQ. I in the 16 LSB, Q in the 16 MSB + :return: DAC data as 32 bit IQ. I/DACA/DACC in the 16 LSB, + Q/DACB/DACD in the 16 MSB """ return self.phaser.read32(PHASER_ADDR_DAC0_DATA + (self.index << 4)) @@ -381,7 +382,8 @@ class PhaserChannel: def set_dac_test(self, data: TInt32): """Set the DAC test data. - :param data: 32 bit IQ test data, I in the 16 LSB, Q in the 16 MSB + :param data: 32 bit IQ test data, I/DACA/DACC in the 16 LSB, + Q/DACB/DACD in the 16 MSB """ self.phaser.write32(PHASER_ADDR_DAC0_TEST + (self.index << 4), data) From 3a79ef740b7af332df289bc17d23f4ec7c783f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 14 Sep 2020 08:31:54 +0000 Subject: [PATCH 2333/2457] phaser: work around integer size --- artiq/coredevice/phaser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 7449ab19b..ad7f6b028 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -415,7 +415,7 @@ class PhaserChannel: :param frequency: DUC frequency in Hz (passband from -200 MHz to 200 MHz, wrapping around at +- 250 MHz) """ - ftw = int32(round(frequency*((1 << 32)/(500*MHz)))) + ftw = int32(round(frequency*((1 << 31)/(250*MHz)))) self.set_duc_frequency_mu(ftw) @kernel @@ -559,7 +559,7 @@ class PhaserOscillator: :param frequency: Frequency in Hz (passband from -10 MHz to 10 MHz, wrapping around at +- 12.5 MHz) """ - ftw = int32(round(frequency*((1 << 32)/(25*MHz)))) + ftw = int32(round(frequency*((1 << 31)/(12.5*MHz)))) self.set_frequency_mu(ftw) @kernel From 07418258ae9c8b9f444e5843844a134bfc7929af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 14 Sep 2020 13:12:34 +0000 Subject: [PATCH 2334/2457] phaser: init [wip] --- artiq/coredevice/phaser.py | 123 ++++++++++++++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 8 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index ad7f6b028..ccdc10970 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -1,6 +1,6 @@ from artiq.language.core import kernel, delay_mu, delay from artiq.coredevice.rtio import rtio_output, rtio_input_data -from artiq.language.units import us, ns, MHz +from artiq.language.units import us, ns, ms, MHz, dB from artiq.language.types import TInt32 @@ -50,6 +50,8 @@ PHASER_STA_SPI_IDLE = 1 << 5 PHASER_DAC_SEL_DUC = 0 PHASER_DAC_SEL_TEST = 1 +PHASER_HW_REV_VARIANT = 1 << 4 + class Phaser: """Phaser 4-channel, 16-bit, 1 GS/s DAC coredevice driver. @@ -130,14 +132,73 @@ class Phaser: def init(self): """Initialize the board. - Verifies board presence by reading the board ID register. - Does not alter any state. + Verifies board and chip presence, resets components, performs communication + and configuration tests and establishes initial conditions. """ board_id = self.read8(PHASER_ADDR_BOARD_ID) if board_id != PHASER_BOARD_ID: raise ValueError("invalid board id") delay(20*us) # slack + # allow a few errors during startup and alignment + if self.get_crc_err() > 20: + raise ValueError("large number of CRC errors") + delay(.1*ms) # slack + + self.set_cfg(dac_resetb=0, att0_rstn=0, att1_rstn=0) + self.set_leds(0x00) + self.set_fan_mu(0) + self.set_cfg() # bring everything out of reset + delay(.1*ms) # slack + + # 4 wire SPI, sif4_enable + self.dac_write(0x02, 0x0082) + if self.dac_read(0x7f) != 0x5409: + raise ValueError("DAC version readback invalid") + delay(.1*ms) + if self.dac_read(0x00) != 0x049c: + raise ValueError("DAC config0 readback invalid") + delay(.1*ms) + + t = self.get_dac_temperature() + if t < 10 or t > 90: + raise ValueError("DAC temperature out of bounds") + delay(.1*ms) + + patterns = [ + [0xffff, 0xffff, 0x0000, 0x0000], # test channel + [0xaa55, 0x55aa, 0x55aa, 0xaa5a], # test iq + [0xaa55, 0xaa55, 0x55aa, 0x55aa], # test byte + [0x7a7a, 0xb6b6, 0xeaea, 0x4545], # ds pattern a + [0x1a1a, 0x1616, 0xaaaa, 0xc6c6], # ds pattern b + ] + delay(.5*ms) + for i in range(len(patterns)): + errors = self.dac_iotest(patterns[i]) + if errors: + raise ValueError("iotest error") + delay(.5*ms) + + hw_rev = self.read8(PHASER_ADDR_HW_REV) + has_upconverter = hw_rev & PHASER_HW_REV_VARIANT + delay(.1*ms) # slack + + for ch in range(2): + # test attenuator write and readback + self.channel[ch].set_att_mu(0x55) + if self.channel[ch].get_att_mu() != 0x55: + raise ValueError("attenuator test failed") + delay(.1*ms) + self.channel[ch].set_att(31.5*dB) + + # dac test data readback + dac_test = [0x10102020, 0x30304040] + self.channel[ch].set_duc_cfg(select=1) + self.channel[ch].set_dac_test(dac_test[ch]) + if self.channel[ch].get_dac_data() != dac_test[ch]: + raise ValueError("DAC test data readback failed") + delay(.1*ms) + @kernel def write8(self, addr, data): """Write data to FPGA register. @@ -201,7 +262,7 @@ class Phaser: """ pwm = int32(round(duty*255.)) if pwm < 0 or pwm > 255: - raise ValueError("invalid duty cycle") + raise ValueError("duty cycle out of bounds") self.set_fan_mu(pwm) @kernel @@ -278,9 +339,9 @@ class Phaser: :param length: SPI transfer length (1 to 8 bits) """ if div < 2 or div > 257: - raise ValueError("invalid divider") + raise ValueError("divider out of bounds") if length < 1 or length > 8: - raise ValueError("invalid length") + raise ValueError("length out of bounds") self.write8(PHASER_ADDR_SPI_SEL, select) self.write8(PHASER_ADDR_SPI_DIVLEN, (div - 2 >> 3) | (length - 1 << 5)) self.write8(PHASER_ADDR_SPI_CFG, @@ -339,6 +400,52 @@ class Phaser: data |= self.spi_read() return data + @kernel + def get_dac_temperature(self) -> TInt32: + """Read the DAC die temperature. + + :return: DAC temperature in degree Celsius + """ + return self.dac_read(0x06, div=257) >> 8 + + @kernel + def dac_iotest(self, pattern) -> TInt32: + """Performs a DAC IO test according to the datasheet. + + :param patterm: List of four int32 containing the pattern + :return: Bit error mask (16 bits) + """ + for addr in range(len(pattern)): + self.dac_write(0x25 + addr, pattern[addr]) + self.dac_write(0x29 + addr, pattern[addr]) + delay(.1*ms) + for ch in range(2): + self.channel[ch].set_duc_cfg(select=1) # test + # dac test data is i msb, q lsb + self.channel[ch].set_dac_test(pattern[2*ch] | (pattern[2*ch + 1] << 16)) + self.dac_write(0x01, 0x8000) # iotest_ena + errors = 0 + # A data delay of 3*50 ps heuristically matches FPGA+board+DAC skews. + # There is plenty of margin and no need to tune at runtime. + # Parity provides another level of safety. + for dly in [-3]: # range(-7, 8) + if dly < 0: + dly = -dly << 3 # data delay, else clock delay + self.dac_write(0x24, dly << 10) + self.dac_write(0x04, 0x0000) # clear iotest_result + delay(.2*ms) # let it rip + # no need to go through the alarm register, + # just read the error mask + # self.dac_write(0x05, 0x0000) # clear alarms + # alarm = self.dac_read(0x05) + # delay(.1*ms) # slack + # if alarm & 0x0080: # alarm_from_iotest + errors |= self.dac_read(0x04) + delay(.1*ms) # slack + self.dac_write(0x24, 0) # reset delays + # self.dac_write(0x01, 0x0000) # clear config + return errors + class PhaserChannel: """Phaser channel IQ pair. @@ -459,7 +566,7 @@ class PhaserChannel: # 2 lsb are inactive, resulting in 8 LSB per dB data = 0xff - int32(round(att*8)) if data < 0 or data > 0xff: - raise ValueError("invalid attenuation") + raise ValueError("attenuation out of bounds") self.set_att_mu(data) @kernel @@ -583,6 +690,6 @@ class PhaserOscillator: """ asf = int32(round(amplitude*0x7fff)) if asf < 0 or asf > 0x7fff: - raise ValueError("invalid amplitude") + raise ValueError("amplitude out of bounds") pow = int32(round(phase*(1 << 16))) self.set_amplitude_phase_mu(asf, pow, clr) From ff57813a9cfbdc03ff0fdbe9eae0e8a639e9c98b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 14 Sep 2020 13:12:44 +0000 Subject: [PATCH 2335/2457] phaser: init [wip] --- artiq/coredevice/phaser.py | 94 ++++++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 28 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index ccdc10970..5c3dfddc6 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -129,18 +129,20 @@ class Phaser: self.channel = [PhaserChannel(self, ch) for ch in range(2)] @kernel - def init(self): + def init(self, clk_sel=0): """Initialize the board. Verifies board and chip presence, resets components, performs communication and configuration tests and establishes initial conditions. + + :param clk_sel: Select the external SMA clock input (1 or 0) """ board_id = self.read8(PHASER_ADDR_BOARD_ID) if board_id != PHASER_BOARD_ID: raise ValueError("invalid board id") delay(20*us) # slack - # allow a few errors during startup and alignment + # allow a few errors during startup and alignment if self.get_crc_err() > 20: raise ValueError("large number of CRC errors") delay(.1*ms) # slack @@ -148,7 +150,7 @@ class Phaser: self.set_cfg(dac_resetb=0, att0_rstn=0, att1_rstn=0) self.set_leds(0x00) self.set_fan_mu(0) - self.set_cfg() # bring everything out of reset + self.set_cfg(clk_sel=clk_sel) # bring everything out of reset delay(.1*ms) # slack # 4 wire SPI, sif4_enable @@ -165,6 +167,43 @@ class Phaser: raise ValueError("DAC temperature out of bounds") delay(.1*ms) + delay(.5*ms) # slack + self.dac_write(0x00, 0x019c) # I=2, fifo, clkdiv_sync, qmc off + self.dac_write(0x01, 0x040e) # fifo alarms, parity + self.dac_write(0x02, 0x70a2) # clk alarms, sif4, nco off, mix, mix_gain, 2s + self.dac_write(0x03, 0x6000) # coarse dac 20.6 mA + self.dac_write(0x07, 0x40c1) # alarm mask + self.dac_write(0x09, 0x8000) # fifo_offset + self.dac_write(0x0d, 0x0000) # fmix, no cmix + self.dac_write(0x14, 0x5431) # fine nco ab + self.dac_write(0x15, 0x0323) # coarse nco ab + self.dac_write(0x16, 0x5431) # fine nco cd + self.dac_write(0x17, 0x0323) # coarse nco cd + self.dac_write(0x18, 0x2c60) # P=4, pll run, single cp, pll_ndivsync + self.dac_write(0x19, 0x8404) # M=8 N=1 + self.dac_write(0x1a, 0xfc00) # pll_vco=63 + delay(.2*ms) # slack + self.dac_write(0x1b, 0x0800) # int ref, fuse + self.dac_write(0x1e, 0x9999) # qmc sync from sif and reg + self.dac_write(0x1f, 0x9982) # mix sync, nco sync, istr is istr, sif_sync + self.dac_write(0x20, 0x2400) # fifo sync ISTR-OSTR + self.dac_write(0x22, 0x1be4) # reverse dacs for spectral inversion and layout + self.dac_write(0x24, 0x0000) # clk and data delays + + delay(1*ms) # lock pll + lvolt = self.dac_read(0x18) & 7 + delay(.1*ms) + if lvolt < 2 or lvolt > 5: + raise ValueError("DAC PLL tuning voltage out of bounds") + self.dac_write(0x20, 0x0000) # stop fifo sync + self.dac_write(0x05, 0x0000) # clear alarms + delay(1*ms) # run it + alarm = self.get_sta() & 1 + delay(.1*ms) + if alarm: + alarm = self.dac_read(0x05) + raise ValueError("DAC alarm") + patterns = [ [0xffff, 0xffff, 0x0000, 0x0000], # test channel [0xaa55, 0x55aa, 0x55aa, 0xaa5a], # test iq @@ -173,11 +212,18 @@ class Phaser: [0x1a1a, 0x1616, 0xaaaa, 0xc6c6], # ds pattern b ] delay(.5*ms) - for i in range(len(patterns)): - errors = self.dac_iotest(patterns[i]) - if errors: - raise ValueError("iotest error") - delay(.5*ms) + # A data delay of 3*50 ps heuristically matches FPGA+board+DAC skews. + # There is plenty of margin and no need to tune at runtime. + # Parity provides another level of safety. + for dly in [-3]: # range(-7, 8) + if dly < 0: + dly = -dly << 3 # data delay, else clock delay + self.dac_write(0x24, dly << 10) + for i in range(len(patterns)): + errors = self.dac_iotest(patterns[i]) + if errors: + raise ValueError("iotest error") + delay(.5*ms) hw_rev = self.read8(PHASER_ADDR_HW_REV) has_upconverter = hw_rev & PHASER_HW_REV_VARIANT @@ -424,26 +470,18 @@ class Phaser: # dac test data is i msb, q lsb self.channel[ch].set_dac_test(pattern[2*ch] | (pattern[2*ch + 1] << 16)) self.dac_write(0x01, 0x8000) # iotest_ena - errors = 0 - # A data delay of 3*50 ps heuristically matches FPGA+board+DAC skews. - # There is plenty of margin and no need to tune at runtime. - # Parity provides another level of safety. - for dly in [-3]: # range(-7, 8) - if dly < 0: - dly = -dly << 3 # data delay, else clock delay - self.dac_write(0x24, dly << 10) - self.dac_write(0x04, 0x0000) # clear iotest_result - delay(.2*ms) # let it rip - # no need to go through the alarm register, - # just read the error mask - # self.dac_write(0x05, 0x0000) # clear alarms - # alarm = self.dac_read(0x05) - # delay(.1*ms) # slack - # if alarm & 0x0080: # alarm_from_iotest - errors |= self.dac_read(0x04) - delay(.1*ms) # slack - self.dac_write(0x24, 0) # reset delays - # self.dac_write(0x01, 0x0000) # clear config + self.dac_write(0x04, 0x0000) # clear iotest_result + delay(.2*ms) # let it rip + # no need to go through the alarm register, + # just read the error mask + # self.dac_write(0x05, 0x0000) # clear alarms + # alarm = self.dac_read(0x05) + # delay(.1*ms) # slack + # if alarm & 0x0080: # alarm_from_iotest + errors = self.dac_read(0x04) + delay(.1*ms) # slack + self.dac_write(0x01, 0x0000) # clear config + self.dac_write(0x04, 0x0000) # clear iotest_result return errors From 9b58b712a6a65bd496f6c77506891091cd2685b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 15 Sep 2020 12:35:26 +0000 Subject: [PATCH 2336/2457] phaser: doc tweaks --- artiq/coredevice/phaser.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 5c3dfddc6..92e7fa0d9 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -77,10 +77,10 @@ class Phaser: > 30 MHz. The four 16 bit 500 MS/s DAC data streams are sent via a 32 bit parallel - LVDS bus operating at 1 Gb/s per pin pair and processed in the DAC. On the - DAC 2x interpolation, sinx/x compensation, quadrature modulator - compensation, fine and coarse mixing as well as group delay capabilities - are available. + LVDS bus operating at 1 Gb/s per pin pair and processed in the DAC (Texas + Instruments DAC34H84). On the DAC 2x interpolation, sinx/x compensation, + quadrature modulator compensation, fine and coarse mixing as well as group + delay capabilities are available. The latency/group delay from the RTIO events setting :class:`PhaserOscillator` or :class:`PhaserChannel` DUC parameters all they @@ -93,11 +93,12 @@ class Phaser: attenuators and are available on the front panel. The odd outputs are available at MMCX connectors on board. - In the upconverter variant, each IQ output pair feeds a one quadrature - upconverter with integrated PLL/VCO. This analog quadrature upconverter - supports offset tuning for carrier and sideband suppression. The output - from the upconverter passes through the 31.5 dB range step attenuator and - is available at the front panel. + In the upconverter variant, each IQ output pair feeds one quadrature + upconverter (Texas Instruments TRF372017) with integrated PLL/VCO. This + digitally configured analog quadrature upconverter supports offset tuning + for carrier and sideband suppression. The output from the upconverter + passes through the 31.5 dB range step attenuator and is available at the + front panel. The DAC, the analog quadrature upconverters and the attenuators are configured through a shared SPI bus that is accessed and controlled via @@ -461,8 +462,11 @@ class Phaser: :param patterm: List of four int32 containing the pattern :return: Bit error mask (16 bits) """ + if len(pattern) != 4: + raise ValueError("pattern length out of bounds") for addr in range(len(pattern)): self.dac_write(0x25 + addr, pattern[addr]) + # repeat the pattern twice self.dac_write(0x29 + addr, pattern[addr]) delay(.1*ms) for ch in range(2): @@ -534,7 +538,7 @@ class PhaserChannel: @kernel def set_duc_cfg(self, clr=0, clr_once=0, select=0): - """Set the digital upconverter and interpolator configuration. + """Set the digital upconverter (DUC) and interpolator configuration. :param clr: Keep the phase accumulator cleared (persistent) :param clr_once: Clear the phase accumulator for one cycle @@ -555,7 +559,7 @@ class PhaserChannel: @kernel def set_duc_frequency(self, frequency): - """Set the DUC frequency. + """Set the DUC frequency in SI units. :param frequency: DUC frequency in Hz (passband from -200 MHz to 200 MHz, wrapping around at +- 250 MHz) @@ -565,7 +569,7 @@ class PhaserChannel: @kernel def set_duc_phase_mu(self, pow): - """Set the DUC phase offset + """Set the DUC phase offset. :param pow: DUC phase offset word (16 bit) """ @@ -575,7 +579,7 @@ class PhaserChannel: @kernel def set_duc_phase(self, phase): - """Set the DUC phase. + """Set the DUC phase in SI units. :param phase: DUC phase in turns """ @@ -631,7 +635,7 @@ class PhaserChannel: @kernel def trf_write(self, data, readback=False): - """Write 32 bits to upconverter. + """Write 32 bits to quadrature upconverter register. :param data: Register data (32 bit) containing encoded address :param readback: Whether to return the read back MISO data From f3b0398720c513d57ee71126bff8a57f81a8a2cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 16 Sep 2020 09:19:15 +0000 Subject: [PATCH 2337/2457] phaser: n=2, m=16, sync_dly --- artiq/coredevice/phaser.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 92e7fa0d9..2e780ecf4 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -20,7 +20,7 @@ PHASER_ADDR_SPI_DIVLEN = 0x0b PHASER_ADDR_SPI_SEL = 0x0c PHASER_ADDR_SPI_DATW = 0x0d PHASER_ADDR_SPI_DATR = 0x0e -# PHASER_ADDR_RESERVED0 = 0x0f +PHASER_ADDR_SYNC_DLY = 0x0f PHASER_ADDR_DUC0_CFG = 0x10 # PHASER_ADDR_DUC0_RESERVED0 = 0x11 PHASER_ADDR_DUC0_F = 0x12 @@ -172,16 +172,17 @@ class Phaser: self.dac_write(0x00, 0x019c) # I=2, fifo, clkdiv_sync, qmc off self.dac_write(0x01, 0x040e) # fifo alarms, parity self.dac_write(0x02, 0x70a2) # clk alarms, sif4, nco off, mix, mix_gain, 2s - self.dac_write(0x03, 0x6000) # coarse dac 20.6 mA + self.dac_write(0x03, 0x4000) # coarse dac 20.6 mA self.dac_write(0x07, 0x40c1) # alarm mask - self.dac_write(0x09, 0x8000) # fifo_offset + self.dac_write(0x09, 0x4000) # fifo_offset + self.set_sync_dly(0) self.dac_write(0x0d, 0x0000) # fmix, no cmix self.dac_write(0x14, 0x5431) # fine nco ab self.dac_write(0x15, 0x0323) # coarse nco ab self.dac_write(0x16, 0x5431) # fine nco cd self.dac_write(0x17, 0x0323) # coarse nco cd self.dac_write(0x18, 0x2c60) # P=4, pll run, single cp, pll_ndivsync - self.dac_write(0x19, 0x8404) # M=8 N=1 + self.dac_write(0x19, 0x8814) # M=16 N=2 self.dac_write(0x1a, 0xfc00) # pll_vco=63 delay(.2*ms) # slack self.dac_write(0x1b, 0x0800) # int ref, fuse @@ -196,7 +197,7 @@ class Phaser: delay(.1*ms) if lvolt < 2 or lvolt > 5: raise ValueError("DAC PLL tuning voltage out of bounds") - self.dac_write(0x20, 0x0000) # stop fifo sync + # self.dac_write(0x20, 0x0000) # stop fifo sync self.dac_write(0x05, 0x0000) # clear alarms delay(1*ms) # run it alarm = self.get_sta() & 1 @@ -488,6 +489,16 @@ class Phaser: self.dac_write(0x04, 0x0000) # clear iotest_result return errors + @kernel + def set_sync_dly(self, dly): + """Set SYNC delay. + + :param dly: DAC SYNC delay setting (0 to 7) + """ + if dly < 0 or dly > 7: + raise ValueError("SYNC delay out of bounds") + self.write8(PHASER_ADDR_SYNC_DLY, dly) + class PhaserChannel: """Phaser channel IQ pair. From c18f515bf98dec24081691c702b9d53882219eb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 16 Sep 2020 11:49:46 +0000 Subject: [PATCH 2338/2457] phaser: rework rtio channels, sync_dly, init() --- artiq/coredevice/phaser.py | 64 +++++++++++++++++++------------ artiq/gateware/eem.py | 6 ++- artiq/gateware/rtio/phy/phaser.py | 22 ++++++----- 3 files changed, 57 insertions(+), 35 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 2e780ecf4..1251173de 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -21,12 +21,14 @@ PHASER_ADDR_SPI_SEL = 0x0c PHASER_ADDR_SPI_DATW = 0x0d PHASER_ADDR_SPI_DATR = 0x0e PHASER_ADDR_SYNC_DLY = 0x0f + PHASER_ADDR_DUC0_CFG = 0x10 # PHASER_ADDR_DUC0_RESERVED0 = 0x11 PHASER_ADDR_DUC0_F = 0x12 PHASER_ADDR_DUC0_P = 0x16 PHASER_ADDR_DAC0_DATA = 0x18 PHASER_ADDR_DAC0_TEST = 0x1c + PHASER_ADDR_DUC1_CFG = 0x20 # PHASER_ADDR_DUC1_RESERVED0 = 0x21 PHASER_ADDR_DUC1_F = 0x22 @@ -152,6 +154,7 @@ class Phaser: self.set_leds(0x00) self.set_fan_mu(0) self.set_cfg(clk_sel=clk_sel) # bring everything out of reset + self.set_sync_dly(4) # tune? delay(.1*ms) # slack # 4 wire SPI, sif4_enable @@ -175,7 +178,6 @@ class Phaser: self.dac_write(0x03, 0x4000) # coarse dac 20.6 mA self.dac_write(0x07, 0x40c1) # alarm mask self.dac_write(0x09, 0x4000) # fifo_offset - self.set_sync_dly(0) self.dac_write(0x0d, 0x0000) # fmix, no cmix self.dac_write(0x14, 0x5431) # fine nco ab self.dac_write(0x15, 0x0323) # coarse nco ab @@ -183,7 +185,7 @@ class Phaser: self.dac_write(0x17, 0x0323) # coarse nco cd self.dac_write(0x18, 0x2c60) # P=4, pll run, single cp, pll_ndivsync self.dac_write(0x19, 0x8814) # M=16 N=2 - self.dac_write(0x1a, 0xfc00) # pll_vco=63 + self.dac_write(0x1a, 0xfc00) # pll_vco=63, 4 GHz delay(.2*ms) # slack self.dac_write(0x1b, 0x0800) # int ref, fuse self.dac_write(0x1e, 0x9999) # qmc sync from sif and reg @@ -192,19 +194,20 @@ class Phaser: self.dac_write(0x22, 0x1be4) # reverse dacs for spectral inversion and layout self.dac_write(0x24, 0x0000) # clk and data delays + self.clear_dac_alarms() delay(1*ms) # lock pll lvolt = self.dac_read(0x18) & 7 delay(.1*ms) if lvolt < 2 or lvolt > 5: raise ValueError("DAC PLL tuning voltage out of bounds") # self.dac_write(0x20, 0x0000) # stop fifo sync - self.dac_write(0x05, 0x0000) # clear alarms - delay(1*ms) # run it - alarm = self.get_sta() & 1 - delay(.1*ms) - if alarm: - alarm = self.dac_read(0x05) + # alarm = self.get_sta() & 1 + # delay(.1*ms) + alarm = self.get_dac_alarms() + if alarm & ~0x0040: # ignore PLL alarms (see DS) + print(alarm) raise ValueError("DAC alarm") + delay(.5*ms) patterns = [ [0xffff, 0xffff, 0x0000, 0x0000], # test channel @@ -213,11 +216,10 @@ class Phaser: [0x7a7a, 0xb6b6, 0xeaea, 0x4545], # ds pattern a [0x1a1a, 0x1616, 0xaaaa, 0xc6c6], # ds pattern b ] - delay(.5*ms) - # A data delay of 3*50 ps heuristically matches FPGA+board+DAC skews. + # A data delay of 2*50 ps heuristically matches FPGA+board+DAC skews. # There is plenty of margin and no need to tune at runtime. # Parity provides another level of safety. - for dly in [-3]: # range(-7, 8) + for dly in [-2]: # range(-7, 8) if dly < 0: dly = -dly << 3 # data delay, else clock delay self.dac_write(0x24, dly << 10) @@ -226,6 +228,7 @@ class Phaser: if errors: raise ValueError("iotest error") delay(.5*ms) + self.clear_dac_alarms() hw_rev = self.read8(PHASER_ADDR_HW_REV) has_upconverter = hw_rev & PHASER_HW_REV_VARIANT @@ -362,6 +365,16 @@ class Phaser: """ return self.read8(PHASER_ADDR_CRC_ERR) + @kernel + def set_sync_dly(self, dly): + """Set SYNC delay. + + :param dly: DAC SYNC delay setting (0 to 7) + """ + if dly < 0 or dly > 7: + raise ValueError("SYNC delay out of bounds") + self.write8(PHASER_ADDR_SYNC_DLY, dly) + @kernel def duc_stb(self): """Strobe the DUC configuration register update. @@ -456,6 +469,19 @@ class Phaser: """ return self.dac_read(0x06, div=257) >> 8 + @kernel + def get_dac_alarms(self): + """Read the DAC alarm flags. + + :return: DAC alarm flags (see datasheet for bit meaning) + """ + return self.dac_read(0x05) + + @kernel + def clear_dac_alarms(self): + """Clear DAC alarm flags.""" + self.dac_write(0x05, 0x0000) + @kernel def dac_iotest(self, pattern) -> TInt32: """Performs a DAC IO test according to the datasheet. @@ -479,7 +505,7 @@ class Phaser: delay(.2*ms) # let it rip # no need to go through the alarm register, # just read the error mask - # self.dac_write(0x05, 0x0000) # clear alarms + # self.clear_dac_alarms() # alarm = self.dac_read(0x05) # delay(.1*ms) # slack # if alarm & 0x0080: # alarm_from_iotest @@ -489,16 +515,6 @@ class Phaser: self.dac_write(0x04, 0x0000) # clear iotest_result return errors - @kernel - def set_sync_dly(self, dly): - """Set SYNC delay. - - :param dly: DAC SYNC delay setting (0 to 7) - """ - if dly < 0 or dly > 7: - raise ValueError("SYNC delay out of bounds") - self.write8(PHASER_ADDR_SYNC_DLY, dly) - class PhaserChannel: """Phaser channel IQ pair. @@ -702,7 +718,7 @@ class PhaserOscillator: def __init__(self, channel, index): self.channel = channel self.base_addr = ((self.channel.phaser.channel_base + 1 + - self.channel.index) << 8) | (index << 1) + 2*self.channel.index) << 8) | index @kernel def set_frequency_mu(self, ftw): @@ -731,7 +747,7 @@ class PhaserOscillator: :param clr: Clear the phase accumulator (persistent) """ data = (asf & 0x7fff) | ((clr & 1) << 15) | (pow << 16) - rtio_output(self.base_addr | 1, data) + rtio_output(self.base_addr | (1 << 8), data) @kernel def set_amplitude_phase(self, amplitude, phase=0., clr=0): diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index 447dd1fe6..d6314e9be 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -652,6 +652,8 @@ class Phaser(_EEM): target.submodules += phy target.rtio_channels.extend([ rtio.Channel.from_phy(phy, ififo_depth=4), - rtio.Channel.from_phy(phy.ch0), - rtio.Channel.from_phy(phy.ch1), + rtio.Channel.from_phy(phy.ch0.frequency), + rtio.Channel.from_phy(phy.ch0.phase_amplitude), + rtio.Channel.from_phy(phy.ch1.frequency), + rtio.Channel.from_phy(phy.ch1.phase_amplitude), ]) diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index 46dfc8005..634d4f202 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -5,24 +5,28 @@ from artiq.gateware.rtio import rtlink from .fastlink import SerDes, SerInterface -class DDSChannel(Module): - def __init__(self, share_lut=None): +class Phy(Module): + def __init__(self, regs): self.rtlink = rtlink.Interface( rtlink.OInterface(data_width=32, address_width=4, enable_replace=True)) - to_rio_phy = ClockDomainsRenamer("rio_phy") - self.submodules.dds = to_rio_phy(MultiDDS( - n=5, fwidth=32, xwidth=16, z=19, zl=10, share_lut=share_lut)) - regs = [] - for i in self.dds.i: - regs.extend([i.f, Cat(i.a, i.clr, i.p)]) - self.sync.rio_phy += [ + self.sync.rtio += [ If(self.rtlink.o.stb, Array(regs)[self.rtlink.o.address].eq(self.rtlink.o.data) ) ] +class DDSChannel(Module): + def __init__(self, share_lut=None): + to_rio_phy = ClockDomainsRenamer("rio_phy") + self.submodules.dds = to_rio_phy(MultiDDS( + n=5, fwidth=32, xwidth=16, z=19, zl=10, share_lut=share_lut)) + self.submodules.frequency = Phy([i.f for i in self.dds.i]) + self.submodules.phase_amplitude = Phy( + [Cat(i.a, i.clr, i.p) for i in self.dds.i]) + + class Phaser(Module): def __init__(self, pins, pins_n): self.rtlink = rtlink.Interface( From 868a9a1f0c7d4340ca90c57a14a9719e14a57400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 16 Sep 2020 14:06:38 +0000 Subject: [PATCH 2339/2457] phaser: new multidds --- artiq/gateware/rtio/phy/phaser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/rtio/phy/phaser.py b/artiq/gateware/rtio/phy/phaser.py index 634d4f202..bb299ab0c 100644 --- a/artiq/gateware/rtio/phy/phaser.py +++ b/artiq/gateware/rtio/phy/phaser.py @@ -36,7 +36,7 @@ class Phaser(Module): # share a CosSinGen LUT between the two channels self.submodules.ch0 = DDSChannel() - self.submodules.ch1 = DDSChannel(share_lut=self.ch0.dds.mod.cs.lut) + self.submodules.ch1 = DDSChannel(share_lut=self.ch0.dds.cs.lut) n_channels = 2 n_samples = 8 n_bits = 14 From 29c940f4e378073399412f3cc58c5443280bc714 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 17 Sep 2020 16:53:43 +0800 Subject: [PATCH 2340/2457] kasli2: forward sma_clkin to si5324 --- artiq/gateware/targets/kasli.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 96a4df558..d1eb75252 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -79,6 +79,21 @@ class _RTIOCRG(Module, AutoCSR): ] +class SMAClkinForward(Module): + def __init__(self, platform): + sma_clkin = platform.request("sma_clkin") + sma_clkin_se = Signal() + sma_clkin_buffered = Signal() + cdr_clk_se = Signal() + cdr_clk = platform.request("cdr_clk") + self.specials += [ + Instance("IBUFDS", i_I=sma_clkin.p, i_IB=sma_clkin.n, o_O=sma_clkin_se), + Instance("BUFIO", i_I=sma_clkin_se, o_O=sma_clkin_buffered), + Instance("ODDR", i_C=sma_clkin_buffered, i_CE=1, i_D1=0, i_D2=1, o_Q=cdr_clk_se), + Instance("OBUFDS", i_I=cdr_clk_se, o_O=cdr_clk.p, o_OB=cdr_clk.n) + ] + + def fix_serdes_timing_path(platform): # ignore timing of path from OSERDESE2 through the pad to ISERDESE2 platform.add_platform_command( @@ -115,6 +130,7 @@ class StandaloneBase(MiniSoC, AMPSoC): self.submodules.error_led = gpio.GPIOOut(Cat( self.platform.request("error_led"))) self.csr_devices.append("error_led") + self.submodules += SMAClkinForward(self.platform) i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) @@ -294,6 +310,9 @@ class MasterBase(MiniSoC, AMPSoC): platform = self.platform + if platform.hw_rev == "v2.0": + self.submodules += SMAClkinForward(platform) + i2c = self.platform.request("i2c") self.submodules.i2c = gpio.GPIOTristate([i2c.scl, i2c.sda]) self.csr_devices.append("i2c") From b15e388b5f07e750d2522bbdc0e63789700d5414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 17 Sep 2020 14:13:10 +0000 Subject: [PATCH 2341/2457] ad53xx: distinguish errors --- artiq/coredevice/ad53xx.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index c4ff6d3aa..3445555d9 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -178,6 +178,8 @@ class AD53xx: self.write_offset_dacs_mu(self.offset_dacs) if not blind: ctrl = self.read_reg(channel=0, op=AD53XX_READ_CONTROL) + if ctrl == 0xffff: + raise ValueError("DAC not found") if ctrl & 0b10000: raise ValueError("DAC over temperature") delay(25*us) From f0959fb871b20e63fd06caf97fad03e8e1788624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 17 Sep 2020 14:13:58 +0000 Subject: [PATCH 2342/2457] phaser: iotest early, check_alarms --- artiq/coredevice/phaser.py | 94 ++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 1251173de..be50a649e 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -169,44 +169,6 @@ class Phaser: t = self.get_dac_temperature() if t < 10 or t > 90: raise ValueError("DAC temperature out of bounds") - delay(.1*ms) - - delay(.5*ms) # slack - self.dac_write(0x00, 0x019c) # I=2, fifo, clkdiv_sync, qmc off - self.dac_write(0x01, 0x040e) # fifo alarms, parity - self.dac_write(0x02, 0x70a2) # clk alarms, sif4, nco off, mix, mix_gain, 2s - self.dac_write(0x03, 0x4000) # coarse dac 20.6 mA - self.dac_write(0x07, 0x40c1) # alarm mask - self.dac_write(0x09, 0x4000) # fifo_offset - self.dac_write(0x0d, 0x0000) # fmix, no cmix - self.dac_write(0x14, 0x5431) # fine nco ab - self.dac_write(0x15, 0x0323) # coarse nco ab - self.dac_write(0x16, 0x5431) # fine nco cd - self.dac_write(0x17, 0x0323) # coarse nco cd - self.dac_write(0x18, 0x2c60) # P=4, pll run, single cp, pll_ndivsync - self.dac_write(0x19, 0x8814) # M=16 N=2 - self.dac_write(0x1a, 0xfc00) # pll_vco=63, 4 GHz - delay(.2*ms) # slack - self.dac_write(0x1b, 0x0800) # int ref, fuse - self.dac_write(0x1e, 0x9999) # qmc sync from sif and reg - self.dac_write(0x1f, 0x9982) # mix sync, nco sync, istr is istr, sif_sync - self.dac_write(0x20, 0x2400) # fifo sync ISTR-OSTR - self.dac_write(0x22, 0x1be4) # reverse dacs for spectral inversion and layout - self.dac_write(0x24, 0x0000) # clk and data delays - - self.clear_dac_alarms() - delay(1*ms) # lock pll - lvolt = self.dac_read(0x18) & 7 - delay(.1*ms) - if lvolt < 2 or lvolt > 5: - raise ValueError("DAC PLL tuning voltage out of bounds") - # self.dac_write(0x20, 0x0000) # stop fifo sync - # alarm = self.get_sta() & 1 - # delay(.1*ms) - alarm = self.get_dac_alarms() - if alarm & ~0x0040: # ignore PLL alarms (see DS) - print(alarm) - raise ValueError("DAC alarm") delay(.5*ms) patterns = [ @@ -228,6 +190,35 @@ class Phaser: if errors: raise ValueError("iotest error") delay(.5*ms) + + delay(.5*ms) # slack + self.dac_write(0x00, 0x019c) # I=2, fifo, clkdiv_sync, qmc off + self.dac_write(0x01, 0x040e) # fifo alarms, parity + self.dac_write(0x02, 0x70a2) # clk alarms, sif4, nco off, mix, mix_gain, 2s + self.dac_write(0x03, 0xa000) # coarse dac 20.6 mA + self.dac_write(0x07, 0x40c1) # alarm mask + self.dac_write(0x09, 0x4000) # fifo_offset + self.dac_write(0x0d, 0x0000) # fmix, no cmix + self.dac_write(0x14, 0x5431) # fine nco ab + self.dac_write(0x15, 0x0323) # coarse nco ab + self.dac_write(0x16, 0x5431) # fine nco cd + self.dac_write(0x17, 0x0323) # coarse nco cd + self.dac_write(0x18, 0x2c60) # P=4, pll run, single cp, pll_ndivsync + self.dac_write(0x19, 0x8814) # M=16 N=2 + self.dac_write(0x1a, 0xfc00) # pll_vco=63, 4 GHz + delay(.2*ms) # slack + self.dac_write(0x1b, 0x0800) # int ref, fuse + self.dac_write(0x1e, 0x9999) # qmc sync from sif and reg + self.dac_write(0x1f, 0x9982) # mix sync, nco sync, istr is istr, sif_sync + self.dac_write(0x20, 0x2400) # fifo sync ISTR-OSTR + self.dac_write(0x22, 0x1be4) # reverse dacs for spectral inversion and layout + self.dac_write(0x24, 0x0000) # clk and data delays + + delay(2*ms) # lock pll + lvolt = self.dac_read(0x18) & 7 + delay(.1*ms) + if lvolt < 2 or lvolt > 5: + raise ValueError("DAC PLL tuning voltage out of bounds") self.clear_dac_alarms() hw_rev = self.read8(PHASER_ADDR_HW_REV) @@ -236,8 +227,8 @@ class Phaser: for ch in range(2): # test attenuator write and readback - self.channel[ch].set_att_mu(0x55) - if self.channel[ch].get_att_mu() != 0x55: + self.channel[ch].set_att_mu(0x5a) + if self.channel[ch].get_att_mu() != 0x5a: raise ValueError("attenuator test failed") delay(.1*ms) self.channel[ch].set_att(31.5*dB) @@ -250,6 +241,19 @@ class Phaser: raise ValueError("DAC test data readback failed") delay(.1*ms) + # self.dac_write(0x20, 0x0000) # stop fifo sync + # alarm = self.get_sta() & 1 + # delay(.1*ms) + self.check_dac_alarms() + + @kernel + def check_dac_alarms(self): + alarm = self.get_dac_alarms() + delay(.1*ms) # slack + if alarm & ~0x0040: # ignore PLL alarms (see DS) + print(alarm) + raise ValueError("DAC alarm") + @kernel def write8(self, addr, data): """Write data to FPGA register. @@ -506,11 +510,13 @@ class Phaser: # no need to go through the alarm register, # just read the error mask # self.clear_dac_alarms() - # alarm = self.dac_read(0x05) - # delay(.1*ms) # slack - # if alarm & 0x0080: # alarm_from_iotest - errors = self.dac_read(0x04) + alarm = self.get_dac_alarms() delay(.1*ms) # slack + if alarm & 0x0080: # alarm_from_iotest + errors = self.dac_read(0x04) + delay(.1*ms) # slack + else: + errors = 0 self.dac_write(0x01, 0x0000) # clear config self.dac_write(0x04, 0x0000) # clear iotest_result return errors From d730851397356ed5a0d8087018026678212e93b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 21 Sep 2020 15:05:29 +0000 Subject: [PATCH 2343/2457] phaser: elaborate init sequence, more tests --- artiq/coredevice/phaser.py | 57 +++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index be50a649e..f28fbe69e 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -145,16 +145,17 @@ class Phaser: raise ValueError("invalid board id") delay(20*us) # slack - # allow a few errors during startup and alignment + # allow a few errors during startup and alignment since boot if self.get_crc_err() > 20: - raise ValueError("large number of CRC errors") + raise ValueError("large number of frame CRC errors") delay(.1*ms) # slack + # reset self.set_cfg(dac_resetb=0, att0_rstn=0, att1_rstn=0) self.set_leds(0x00) self.set_fan_mu(0) self.set_cfg(clk_sel=clk_sel) # bring everything out of reset - self.set_sync_dly(4) # tune? + self.set_sync_dly(4) # TODO: tune this? delay(.1*ms) # slack # 4 wire SPI, sif4_enable @@ -163,7 +164,7 @@ class Phaser: raise ValueError("DAC version readback invalid") delay(.1*ms) if self.dac_read(0x00) != 0x049c: - raise ValueError("DAC config0 readback invalid") + raise ValueError("DAC config0 reset readback invalid") delay(.1*ms) t = self.get_dac_temperature() @@ -178,8 +179,9 @@ class Phaser: [0x7a7a, 0xb6b6, 0xeaea, 0x4545], # ds pattern a [0x1a1a, 0x1616, 0xaaaa, 0xc6c6], # ds pattern b ] - # A data delay of 2*50 ps heuristically matches FPGA+board+DAC skews. - # There is plenty of margin and no need to tune at runtime. + # A data delay of 2*50 ps heuristically and reproducibly matches + # FPGA+board+DAC skews. There is plenty of margin (>= 250 ps + # either side) and no need to tune at runtime. # Parity provides another level of safety. for dly in [-2]: # range(-7, 8) if dly < 0: @@ -188,10 +190,9 @@ class Phaser: for i in range(len(patterns)): errors = self.dac_iotest(patterns[i]) if errors: - raise ValueError("iotest error") + raise ValueError("DAC iotest failure") delay(.5*ms) - delay(.5*ms) # slack self.dac_write(0x00, 0x019c) # I=2, fifo, clkdiv_sync, qmc off self.dac_write(0x01, 0x040e) # fifo alarms, parity self.dac_write(0x02, 0x70a2) # clk alarms, sif4, nco off, mix, mix_gain, 2s @@ -226,20 +227,33 @@ class Phaser: delay(.1*ms) # slack for ch in range(2): + channel = self.channel[ch] # test attenuator write and readback - self.channel[ch].set_att_mu(0x5a) - if self.channel[ch].get_att_mu() != 0x5a: + channel.set_att_mu(0x5a) + if channel.get_att_mu() != 0x5a: raise ValueError("attenuator test failed") delay(.1*ms) - self.channel[ch].set_att(31.5*dB) + channel.set_att(31.5*dB) - # dac test data readback - dac_test = [0x10102020, 0x30304040] - self.channel[ch].set_duc_cfg(select=1) - self.channel[ch].set_dac_test(dac_test[ch]) - if self.channel[ch].get_dac_data() != dac_test[ch]: - raise ValueError("DAC test data readback failed") + for i in range(len(channel.oscillator)): + oscillator = channel.oscillator[i] + if i == 0: + asf = 0x7fff + else: + asf = 0 + # pi/4 phase + oscillator.set_amplitude_phase_mu(asf=asf, pow=0x2000, clr=1) + delay_mu(8) + delay(1*us) # settle link, pipeline and impulse response + # test oscillator and DUC and their phase sign + channel.set_duc_phase_mu(0) + channel.set_duc_cfg(select=0, clr=1) + self.duc_stb() + data = channel.get_dac_data() delay(.1*ms) + if data != 0x4a124a12: + print(data) + raise ValueError("DUC+oscillator phase/amplitude test failed") # self.dac_write(0x20, 0x0000) # stop fifo sync # alarm = self.get_sta() & 1 @@ -501,9 +515,14 @@ class Phaser: self.dac_write(0x29 + addr, pattern[addr]) delay(.1*ms) for ch in range(2): - self.channel[ch].set_duc_cfg(select=1) # test + channel = self.channel[ch] + channel.set_duc_cfg(select=1) # test # dac test data is i msb, q lsb - self.channel[ch].set_dac_test(pattern[2*ch] | (pattern[2*ch + 1] << 16)) + data = pattern[2*ch] | (pattern[2*ch + 1] << 16) + channel.set_dac_test(data) + if channel.get_dac_data() != data: + raise ValueError("DAC test data readback failed") + delay(.1*ms) self.dac_write(0x01, 0x8000) # iotest_ena self.dac_write(0x04, 0x0000) # clear iotest_result delay(.2*ms) # let it rip From fdb2867757754ea36a4c220bafcc09d53acb139e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Mon, 21 Sep 2020 17:06:26 +0200 Subject: [PATCH 2344/2457] phaser: fewer iotest patterns --- artiq/coredevice/phaser.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index f28fbe69e..1c45ab783 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -173,11 +173,9 @@ class Phaser: delay(.5*ms) patterns = [ - [0xffff, 0xffff, 0x0000, 0x0000], # test channel - [0xaa55, 0x55aa, 0x55aa, 0xaa5a], # test iq - [0xaa55, 0xaa55, 0x55aa, 0x55aa], # test byte - [0x7a7a, 0xb6b6, 0xeaea, 0x4545], # ds pattern a - [0x1a1a, 0x1616, 0xaaaa, 0xc6c6], # ds pattern b + [0xf05a, 0x05af, 0x5af0, 0xaf05], # test channel/iq/byte/nibble + [0x7a7a, 0xb6b6, 0xeaea, 0x4545], # datasheet pattern a + [0x1a1a, 0x1616, 0xaaaa, 0xc6c6], # datasheet pattern b ] # A data delay of 2*50 ps heuristically and reproducibly matches # FPGA+board+DAC skews. There is plenty of margin (>= 250 ps From 3e036e365a5f362a7faf1becae8b781395d692d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 22 Sep 2020 09:52:49 +0000 Subject: [PATCH 2345/2457] phaser: nco, settings and init tweaks --- artiq/coredevice/phaser.py | 315 +++++++++++++++++++++++++++++++------ 1 file changed, 267 insertions(+), 48 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 1c45ab783..cb0dccad3 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -151,15 +151,17 @@ class Phaser: delay(.1*ms) # slack # reset - self.set_cfg(dac_resetb=0, att0_rstn=0, att1_rstn=0) + self.set_cfg(dac_resetb=0, att0_rstn=0, att1_rstn=0, dac_txena=0) self.set_leds(0x00) self.set_fan_mu(0) - self.set_cfg(clk_sel=clk_sel) # bring everything out of reset - self.set_sync_dly(4) # TODO: tune this? + self.set_cfg(clk_sel=clk_sel, dac_txena=0) # bring everything out of reset + # TODO: crossing dac_clk (125 MHz) edges with sync_dly (0-7 ns) + # should change the optimal fifo_offset + self.set_sync_dly(4) delay(.1*ms) # slack # 4 wire SPI, sif4_enable - self.dac_write(0x02, 0x0082) + self.dac_write(0x02, 0x0080) if self.dac_read(0x7f) != 0x5409: raise ValueError("DAC version readback invalid") delay(.1*ms) @@ -168,9 +170,9 @@ class Phaser: delay(.1*ms) t = self.get_dac_temperature() + delay(.5*ms) if t < 10 or t > 90: raise ValueError("DAC temperature out of bounds") - delay(.5*ms) patterns = [ [0xf05a, 0x05af, 0x5af0, 0xaf05], # test channel/iq/byte/nibble @@ -182,8 +184,8 @@ class Phaser: # either side) and no need to tune at runtime. # Parity provides another level of safety. for dly in [-2]: # range(-7, 8) - if dly < 0: - dly = -dly << 3 # data delay, else clock delay + if dly < 0: # use data delay, else use clock delay + dly = -dly << 3 self.dac_write(0x24, dly << 10) for i in range(len(patterns)): errors = self.dac_iotest(patterns[i]) @@ -191,38 +193,195 @@ class Phaser: raise ValueError("DAC iotest failure") delay(.5*ms) - self.dac_write(0x00, 0x019c) # I=2, fifo, clkdiv_sync, qmc off - self.dac_write(0x01, 0x040e) # fifo alarms, parity - self.dac_write(0x02, 0x70a2) # clk alarms, sif4, nco off, mix, mix_gain, 2s - self.dac_write(0x03, 0xa000) # coarse dac 20.6 mA - self.dac_write(0x07, 0x40c1) # alarm mask - self.dac_write(0x09, 0x4000) # fifo_offset - self.dac_write(0x0d, 0x0000) # fmix, no cmix - self.dac_write(0x14, 0x5431) # fine nco ab - self.dac_write(0x15, 0x0323) # coarse nco ab - self.dac_write(0x16, 0x5431) # fine nco cd - self.dac_write(0x17, 0x0323) # coarse nco cd - self.dac_write(0x18, 0x2c60) # P=4, pll run, single cp, pll_ndivsync - self.dac_write(0x19, 0x8814) # M=16 N=2 - self.dac_write(0x1a, 0xfc00) # pll_vco=63, 4 GHz - delay(.2*ms) # slack - self.dac_write(0x1b, 0x0800) # int ref, fuse - self.dac_write(0x1e, 0x9999) # qmc sync from sif and reg - self.dac_write(0x1f, 0x9982) # mix sync, nco sync, istr is istr, sif_sync - self.dac_write(0x20, 0x2400) # fifo sync ISTR-OSTR - self.dac_write(0x22, 0x1be4) # reverse dacs for spectral inversion and layout - self.dac_write(0x24, 0x0000) # clk and data delays + qmc_corr_ena = 0 # msb ab + qmc_offset_ena = 0 # msb ab + invsinc_ena = 0 # msb ab + + interpolation = 1 # 2x + fifo_ena = 1 + alarm_out_ena = 1 + alarm_out_pol = 1 + clkdiv_sync_ena = 1 + self.dac_write(0x00, + (qmc_offset_ena << 14) | (qmc_corr_ena << 12) | + (interpolation << 8) | (fifo_ena << 7) | + (alarm_out_ena << 4) | (alarm_out_pol << 3) | + (clkdiv_sync_ena << 2) | (invsinc_ena << 0)) + iotest_ena = 0 + cnt64_ena = 0 + oddeven_parity = 0 # even + single_parity_ena = 1 + dual_parity_ena = 0 + rev_interface = 0 + dac_complement = 0b0000 # msb A + alarm_fifo = 0b111 # msb 2-away + self.dac_write(0x01, + (iotest_ena << 15) | (cnt64_ena << 12) | + (oddeven_parity << 11) | (single_parity_ena << 10) | + (dual_parity_ena << 9) | (rev_interface << 8) | + (dac_complement << 4) | (alarm_fifo << 1)) + dacclkgone_ena = 1 + dataclkgone_ena = 1 + collisiongone_ena = 1 + sif4_ena = 1 + mixer_ena = 0 + mixer_gain = 1 + nco_ena = 0 + revbus = 0 + twos = 1 + self.dac_write(0x02, + (dacclkgone_ena << 14) | (dataclkgone_ena << 13) | + (collisiongone_ena << 12) | (sif4_ena << 7) | + (mixer_ena << 6) | (mixer_gain << 5) | + (nco_ena << 4) | (revbus << 3) | (twos << 1)) + coarse_dac = 0xa # 20.6 mA, 0-15 + sif_txenable = 0 + self.dac_write(0x03, (coarse_dac << 12) | (sif_txenable << 0)) + mask_alarm_from_zerochk = 0 + mask_alarm_fifo_collision = 0 + mask_alarm_fifo_1away = 0 + mask_alarm_fifo_2away = 0 + mask_alarm_dacclk_gone = 0 + mask_alarm_dataclk_gone = 0 + mask_alarm_output_gone = 0 + mask_alarm_from_iotest = 0 + mask_alarm_from_pll = 0 + mask_alarm_parity = 0b0000 # msb a + self.dac_write(0x07, + (mask_alarm_from_zerochk << 15) | (1 << 14) | + (mask_alarm_fifo_collision << 13) | (mask_alarm_fifo_1away << 12) | + (mask_alarm_fifo_2away << 11) | (mask_alarm_dacclk_gone << 10) | + (mask_alarm_dataclk_gone << 9) | (mask_alarm_output_gone << 8) | + (mask_alarm_from_iotest << 7) | (1 << 6) | + (mask_alarm_from_pll << 5) | (mask_alarm_parity << 1)) + qmc_offseta = 0 # 12b + self.dac_write(0x08, qmc_offseta) + fifo_offset = 2 # 0-7 + qmc_offsetb = 0 # 12b + self.dac_write(0x09, (fifo_offset << 13) | qmc_offsetb) + qmc_offsetc = 0 # 12b + self.dac_write(0x0a, qmc_offsetc) + qmc_offsetd = 0 # 12b + self.dac_write(0x0b, qmc_offsetd) + qmc_gaina = 0 # 11b + self.dac_write(0x0c, qmc_gaina) + cmix_fs8 = 0 + cmix_fs4 = 0 + cmix_fs2 = 0 + cmix_nfs4 = 0 + qmc_gainb = 0 # 11b + self.dac_write(0x0d, + (cmix_fs8 << 15) | (cmix_fs4 << 14) | (cmix_fs2 << 12) | + (cmix_nfs4 << 11) | qmc_gainb) + qmc_gainc = 0 # 11b + self.dac_write(0x0e, qmc_gainc) + output_delayab = 0b00 + output_delaycd = 0b00 + qmc_gaind = 0 # 11b + self.dac_write(0x0f, (output_delayab << 14) | (output_delaycd << 12) | + qmc_gaind) + qmc_phaseab = 0 # 12b + self.dac_write(0x10, qmc_phaseab) + qmc_phasecd = 0 # 12b + self.dac_write(0x11, qmc_phasecd) + pll_reset = 0 + pll_ndivsync_ena = 1 + pll_ena = 1 + pll_cp = 0b01 # single charge pump + pll_p = 0b100 # p=4 + self.dac_write(0x18, + (0b001 << 13) | (pll_reset << 12) | + (pll_ndivsync_ena << 11) | (pll_ena << 10) | + (pll_cp << 6) | (pll_p << 3)) + pll_m2 = 1 # x2 + pll_m = 8 # m = 8 + pll_n = 0b0001 # n = 2 + pll_vcotune = 0b01 + self.dac_write(0x19, + (pll_m2 << 15) | (pll_m << 8) | (pll_n << 4) | (pll_vcotune << 2)) + delay(.5*ms) # slack + pll_vco = 0x3f # 4 GHz + bias_sleep = 0 + tsense_sleep = 0 + pll_sleep = 0 + clkrecv_sleep = 0 + dac_sleep = 0b0000 # msb a + self.dac_write(0x1a, + (pll_vco << 10) | (bias_sleep << 7) | (tsense_sleep << 6) | + (pll_sleep << 5) | (clkrecv_sleep << 4) | (dac_sleep << 0)) + extref_ena = 0 + fuse_sleep = 1 + atest = 0b00000 # atest mode + self.dac_write(0x1b, + (extref_ena << 15) | (fuse_sleep << 11) | (atest << 0)) + syncsel_qmcoffsetab = 0b1001 # sif_sync and register write + syncsel_qmcoffsetcd = 0b1001 # sif_sync and register write + syncsel_qmccorrab = 0b1001 # sif_sync and register write + syncsel_qmccorrcd = 0b1001 # sif_sync and register write + self.dac_write(0x1e, + (syncsel_qmcoffsetab << 12) | (syncsel_qmcoffsetcd << 8) | + (syncsel_qmccorrab << 4) | (syncsel_qmccorrcd << 0)) + syncsel_mixerab = 0b1001 # sif_sync and register write + syncsel_mixercd = 0b1001 # sif_sync and register write + syncsel_nco = 0b1000 # sif_sync + syncsel_fifo_input = 0b10 # external lvds istr + sif_sync = 1 + self.dac_write(0x1e, + (syncsel_mixerab << 12) | (syncsel_mixercd << 8) | + (syncsel_nco << 4) | (syncsel_fifo_input << 2) | + (sif_sync << 1)) + syncsel_fifoin = 0b0010 # istr + syncsel_fifoout = 0b0100 # ostr + clkdiv_sync_sel = 0 # ostr + self.dac_write(0x20, + (syncsel_fifoin << 12) | (syncsel_fifoout << 8) | + (clkdiv_sync_sel << 0)) + path_a_sel = 0b00 + path_b_sel = 0b01 + path_c_sel = 0b10 + path_d_sel = 0b11 + # reverse dacs (DCBA) for spectral inversion and layout + dac_a_sel = 0b11 + dac_b_sel = 0b10 + dac_c_sel = 0b01 + dac_d_sel = 0b00 + self.dac_write(0x22, + (path_a_sel << 14) | (path_b_sel << 12) | + (path_c_sel << 10) | (path_d_sel << 8) | + (dac_a_sel << 6) | (dac_b_sel << 4) | + (dac_c_sel << 2) | (dac_d_sel << 0)) + dac_sleep_en = 0b1111 # msb a + clkrecv_sleep_en = 1 + pll_sleep_en = 1 + lvds_data_sleep_en = 1 + lvds_control_sleep_en = 1 + temp_sense_sleep_en = 1 + bias_sleep_en = 1 + self.dac_write(0x23, + (dac_sleep_en << 12) | (clkrecv_sleep_en << 11) | + (pll_sleep_en << 10) | (lvds_data_sleep_en << 9) | + (lvds_control_sleep_en << 8) | (temp_sense_sleep_en << 7) | + (1 << 6) | (bias_sleep_en << 5) | (0x1f << 0)) + # self.dac_write(0x24, 0x0000) # clk and data delays (tuned above) + ostrtodig_sel = 0 + ramp_ena = 0 + sifdac_ena = 0 + self.dac_write(0x2d, + (ostrtodig_sel << 14) | (ramp_ena << 13) | (0x002 << 1) | + (sifdac_ena << 0)) + grp_delaya = 0x00 + grp_delayb = 0x00 + self.dac_write(0x2e, (grp_delaya << 8) | (grp_delayb << 0)) + grp_delayc = 0x00 + grp_delayd = 0x00 + self.dac_write(0x2f, (grp_delayc << 8) | (grp_delayd << 0)) + sifdac = 0 + self.dac_write(0x30, sifdac) - delay(2*ms) # lock pll lvolt = self.dac_read(0x18) & 7 delay(.1*ms) if lvolt < 2 or lvolt > 5: raise ValueError("DAC PLL tuning voltage out of bounds") - self.clear_dac_alarms() - - hw_rev = self.read8(PHASER_ADDR_HW_REV) - has_upconverter = hw_rev & PHASER_HW_REV_VARIANT - delay(.1*ms) # slack for ch in range(2): channel = self.channel[ch] @@ -233,38 +392,43 @@ class Phaser: delay(.1*ms) channel.set_att(31.5*dB) + # test oscillators and DUC for i in range(len(channel.oscillator)): oscillator = channel.oscillator[i] + asf = 0 if i == 0: asf = 0x7fff - else: - asf = 0 - # pi/4 phase - oscillator.set_amplitude_phase_mu(asf=asf, pow=0x2000, clr=1) + # 6pi/4 phase + oscillator.set_amplitude_phase_mu(asf=asf, pow=0xc000, clr=1) delay_mu(8) - delay(1*us) # settle link, pipeline and impulse response - # test oscillator and DUC and their phase sign - channel.set_duc_phase_mu(0) + # 3pi/4 + channel.set_duc_phase_mu(0x6000) channel.set_duc_cfg(select=0, clr=1) self.duc_stb() + delay(.1*ms) # settle link, pipeline and impulse response data = channel.get_dac_data() delay(.1*ms) - if data != 0x4a124a12: + sqrt2 = 0x5a81 # 0x7fff/sqrt(2) + data_i = data & 0xffff + data_q = (data >> 16) & 0xffff + # allow ripple + if (data_i < sqrt2 - 30 or data_i > sqrt2 or + abs(data_i - data_q) > 2): print(data) raise ValueError("DUC+oscillator phase/amplitude test failed") # self.dac_write(0x20, 0x0000) # stop fifo sync # alarm = self.get_sta() & 1 # delay(.1*ms) + self.clear_dac_alarms() + delay(2*ms) # let it run a bit self.check_dac_alarms() - @kernel - def check_dac_alarms(self): - alarm = self.get_dac_alarms() + hw_rev = self.read8(PHASER_ADDR_HW_REV) + has_upconverter = hw_rev & PHASER_HW_REV_VARIANT delay(.1*ms) # slack - if alarm & ~0x0040: # ignore PLL alarms (see DS) - print(alarm) - raise ValueError("DAC alarm") + + self.set_cfg(clk_sel=clk_sel) # txena @kernel def write8(self, addr, data): @@ -493,6 +657,14 @@ class Phaser: """ return self.dac_read(0x05) + @kernel + def check_dac_alarms(self): + alarm = self.get_dac_alarms() + delay(.1*ms) # slack + if alarm & ~0x0040: # ignore PLL alarms (see DS) + print(alarm) + raise ValueError("DAC alarm") + @kernel def clear_dac_alarms(self): """Clear DAC alarm flags.""" @@ -542,6 +714,17 @@ class Phaser: class PhaserChannel: """Phaser channel IQ pair. + A Phaser channel contains: + + * multiple oscillators (in the coredevice phy), + * an interpolation chain and digital upconverter (DUC) on Phaser, + * several channel-specific settings in the DAC: + * quadrature modulation compensation QMC + * numerically controlled oscillator NCO or coarse mixer CMIX, + * the analog quadrature upconverter (in the Phaser-Upconverter hardware + variant), and + * a digitally controlled step attenuator. + Attributes: * :attr:`oscillator`: List of five :class:`PhaserOscillator`. @@ -636,6 +819,42 @@ class PhaserChannel: pow = int32(round(phase*(1 << 16))) self.set_duc_phase_mu(pow) + @kernel + def set_nco_frequency_mu(self, ftw): + """Set the NCO frequency. + + :param ftw: NCO frequency tuning word (32 bit) + """ + self.phaser.dac_write(0x15 + (self.index << 1), ftw >> 16) + self.phaser.dac_write(0x14 + (self.index << 1), ftw) + + @kernel + def set_nco_frequency(self, frequency): + """Set the NCO frequency in SI units. + + :param frequency: NCO frequency in Hz (passband from -400 MHz + to 400 MHz, wrapping around at +- 500 MHz) + """ + ftw = int32(round(frequency*((1 << 31)/(500*MHz)))) + self.set_nco_frequency_mu(ftw) + + @kernel + def set_nco_phase_mu(self, pow): + """Set the NCO phase offset. + + :param pow: NCO phase offset word (16 bit) + """ + self.phaser.dac_write(0x12 + self.index, pow) + + @kernel + def set_nco_phase(self, phase): + """Set the NCO phase in SI units. + + :param phase: NCO phase in turns + """ + pow = int32(round(phase*(1 << 16))) + self.set_duc_phase_mu(pow) + @kernel def set_att_mu(self, data): """Set channel attenuation. From fd5e22189890d482bb65f88b71d3505314aa858a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 22 Sep 2020 14:08:39 +0000 Subject: [PATCH 2346/2457] phaser: dac and trf register maps, init code --- artiq/coredevice/dac34h84.py | 262 ++++++++++++++++++++++++++++++ artiq/coredevice/phaser.py | 293 +++++++++------------------------- artiq/coredevice/trf372017.py | 133 +++++++++++++++ 3 files changed, 468 insertions(+), 220 deletions(-) create mode 100644 artiq/coredevice/dac34h84.py create mode 100644 artiq/coredevice/trf372017.py diff --git a/artiq/coredevice/dac34h84.py b/artiq/coredevice/dac34h84.py new file mode 100644 index 000000000..86e818c7e --- /dev/null +++ b/artiq/coredevice/dac34h84.py @@ -0,0 +1,262 @@ +class DAC34H84: + """DAC34H84 settings and register map. + + For possible values, documentation, and explanation, see the DAC datasheet + at https://www.ti.com/lit/pdf/slas751 + """ + qmc_corr_ena = 0 # msb ab + qmc_offset_ena = 0 # msb ab + invsinc_ena = 0 # msb ab + interpolation = 1 # 2x + fifo_ena = 1 + alarm_out_ena = 1 + alarm_out_pol = 1 + clkdiv_sync_ena = 1 + + iotest_ena = 0 + cnt64_ena = 0 + oddeven_parity = 0 # even + single_parity_ena = 1 + dual_parity_ena = 0 + rev_interface = 0 + dac_complement = 0b0000 # msb A + alarm_fifo = 0b111 # msb 2-away + + dacclkgone_ena = 1 + dataclkgone_ena = 1 + collisiongone_ena = 1 + sif4_ena = 1 + mixer_ena = 0 + mixer_gain = 1 + nco_ena = 0 + revbus = 0 + twos = 1 + + coarse_dac = 0xa # 20.6 mA, 0-15 + sif_txenable = 0 + + mask_alarm_from_zerochk = 0 + mask_alarm_fifo_collision = 0 + mask_alarm_fifo_1away = 0 + mask_alarm_fifo_2away = 0 + mask_alarm_dacclk_gone = 0 + mask_alarm_dataclk_gone = 0 + mask_alarm_output_gone = 0 + mask_alarm_from_iotest = 0 + mask_alarm_from_pll = 0 + mask_alarm_parity = 0b0000 # msb a + + qmc_offseta = 0 # 12b + fifo_offset = 2 # 0-7 + qmc_offsetb = 0 # 12b + + qmc_offsetc = 0 # 12b + + qmc_offsetd = 0 # 12b + + qmc_gaina = 0 # 11b + + cmix_fs8 = 0 + cmix_fs4 = 0 + cmix_fs2 = 0 + cmix_nfs4 = 0 + qmc_gainb = 0 # 11b + + qmc_gainc = 0 # 11b + + output_delayab = 0b00 + output_delaycd = 0b00 + qmc_gaind = 0 # 11b + + qmc_phaseab = 0 # 12b + + qmc_phasecd = 0 # 12b + + pll_reset = 0 + pll_ndivsync_ena = 1 + pll_ena = 1 + pll_cp = 0b01 # single charge pump + pll_p = 0b100 # p=4 + + pll_m2 = 1 # x2 + pll_m = 8 # m = 8 + pll_n = 0b0001 # n = 2 + pll_vcotune = 0b01 + + pll_vco = 0x3f # 4 GHz + bias_sleep = 0 + tsense_sleep = 0 + pll_sleep = 0 + clkrecv_sleep = 0 + dac_sleep = 0b0000 # msb a + + extref_ena = 0 + fuse_sleep = 1 + atest = 0b00000 # atest mode + + syncsel_qmcoffsetab = 0b1001 # sif_sync and register write + syncsel_qmcoffsetcd = 0b1001 # sif_sync and register write + syncsel_qmccorrab = 0b1001 # sif_sync and register write + syncsel_qmccorrcd = 0b1001 # sif_sync and register write + + syncsel_mixerab = 0b1001 # sif_sync and register write + syncsel_mixercd = 0b1001 # sif_sync and register write + syncsel_nco = 0b1000 # sif_sync + syncsel_fifo_input = 0b10 # external lvds istr + sif_sync = 1 + + syncsel_fifoin = 0b0010 # istr + syncsel_fifoout = 0b0100 # ostr + clkdiv_sync_sel = 0 # ostr + + path_a_sel = 0b00 + path_b_sel = 0b01 + path_c_sel = 0b10 + path_d_sel = 0b11 + # reverse dacs (DCBA) for spectral inversion and layout + dac_a_sel = 0b11 + dac_b_sel = 0b10 + dac_c_sel = 0b01 + dac_d_sel = 0b00 + + dac_sleep_en = 0b1111 # msb a + clkrecv_sleep_en = 1 + pll_sleep_en = 1 + lvds_data_sleep_en = 1 + lvds_control_sleep_en = 1 + temp_sense_sleep_en = 1 + bias_sleep_en = 1 + + data_dly = 2 + clk_dly = 0 + + ostrtodig_sel = 0 + ramp_ena = 0 + sifdac_ena = 0 + + grp_delaya = 0x00 + grp_delayb = 0x00 + + grp_delayc = 0x00 + grp_delayd = 0x00 + + sifdac = 0 + + def __init__(self, updates=None): + if updates is None: + return + for key, value in updates.items(): + if not hasattr(self, key): + raise KeyError("invalid setting", key) + setattr(self, key, value) + + def get_mmap(self): + mmap = [] + mmap.append( + (0x00 << 16) | + (self.qmc_offset_ena << 14) | (self.qmc_corr_ena << 12) | + (self.interpolation << 8) | (self.fifo_ena << 7) | + (self.alarm_out_ena << 4) | (self.alarm_out_pol << 3) | + (self.clkdiv_sync_ena << 2) | (self.invsinc_ena << 0)) + mmap.append( + (0x01 << 16) | + (self.iotest_ena << 15) | (self.cnt64_ena << 12) | + (self.oddeven_parity << 11) | (self.single_parity_ena << 10) | + (self.dual_parity_ena << 9) | (self.rev_interface << 8) | + (self.dac_complement << 4) | (self.alarm_fifo << 1)) + mmap.append( + (0x02 << 16) | + (self.dacclkgone_ena << 14) | (self.dataclkgone_ena << 13) | + (self.collisiongone_ena << 12) | (self.sif4_ena << 7) | + (self.mixer_ena << 6) | (self.mixer_gain << 5) | + (self.nco_ena << 4) | (self.revbus << 3) | (self.twos << 1)) + mmap.append((0x03 << 16) | (self.coarse_dac << 12) | (self.sif_txenable << 0)) + mmap.append( + (0x07 << 16) | + (self.mask_alarm_from_zerochk << 15) | (1 << 14) | + (self.mask_alarm_fifo_collision << 13) | + (self.mask_alarm_fifo_1away << 12) | + (self.mask_alarm_fifo_2away << 11) | + (self.mask_alarm_dacclk_gone << 10) | + (self.mask_alarm_dataclk_gone << 9) | + (self.mask_alarm_output_gone << 8) | + (self.mask_alarm_from_iotest << 7) | (1 << 6) | + (self.mask_alarm_from_pll << 5) | (self.mask_alarm_parity << 1)) + mmap.append( + (0x08 << 16) | (self.qmc_offseta << 0)) + mmap.append( + (0x09 << 16) | (self.fifo_offset << 13) | (self.qmc_offsetb << 0)) + mmap.append((0x0a << 16) | (self.qmc_offsetc << 0)) + mmap.append((0x0b << 16) | (self.qmc_offsetd << 0)) + mmap.append((0x0c << 16) | (self.qmc_gaina << 0)) + mmap.append( + (0x0d << 16) | + (self.cmix_fs8 << 15) | (self.cmix_fs4 << 14) | + (self.cmix_fs2 << 12) | (self.cmix_nfs4 << 11) | + (self.qmc_gainb << 0)) + mmap.append((0x0e << 16) | (self.qmc_gainc << 0)) + mmap.append( + (0x0f << 16) | + (self.output_delayab << 14) | (self.output_delaycd << 12) | + (self.qmc_gaind << 0)) + mmap.append((0x10 << 16) | (self.qmc_phaseab << 0)) + mmap.append((0x11 << 16) | (self.qmc_phasecd << 0)) + mmap.append( + (0x18 << 16) | + (0b001 << 13) | (self.pll_reset << 12) | + (self.pll_ndivsync_ena << 11) | (self.pll_ena << 10) | + (self.pll_cp << 6) | (self.pll_p << 3)) + mmap.append( + (0x19 << 16) | + (self.pll_m2 << 15) | (self.pll_m << 8) | (self.pll_n << 4) | + (self.pll_vcotune << 2)) + mmap.append( + (0x1a << 16) | + (self.pll_vco << 10) | (self.bias_sleep << 7) | + (self.tsense_sleep << 6) | + (self.pll_sleep << 5) | (self.clkrecv_sleep << 4) | + (self.dac_sleep << 0)) + mmap.append( + (0x1b << 16) | + (self.extref_ena << 15) | (self.fuse_sleep << 11) | + (self.atest << 0)) + mmap.append( + (0x1e << 16) | + (self.syncsel_qmcoffsetab << 12) | + (self.syncsel_qmcoffsetcd << 8) | + (self.syncsel_qmccorrab << 4) | + (self.syncsel_qmccorrcd << 0)) + mmap.append( + (0x1f << 16) | + (self.syncsel_mixerab << 12) | (self.syncsel_mixercd << 8) | + (self.syncsel_nco << 4) | (self.syncsel_fifo_input << 2) | + (self.sif_sync << 1)) + mmap.append( + (0x20 << 16) | + (self.syncsel_fifoin << 12) | (self.syncsel_fifoout << 8) | + (self.clkdiv_sync_sel << 0)) + mmap.append( + (0x22 << 16) | + (self.path_a_sel << 14) | (self.path_b_sel << 12) | + (self.path_c_sel << 10) | (self.path_d_sel << 8) | + (self.dac_a_sel << 6) | (self.dac_b_sel << 4) | + (self.dac_c_sel << 2) | (self.dac_d_sel << 0)) + mmap.append( + (0x23 << 16) | + (self.dac_sleep_en << 12) | (self.clkrecv_sleep_en << 11) | + (self.pll_sleep_en << 10) | (self.lvds_data_sleep_en << 9) | + (self.lvds_control_sleep_en << 8) | + (self.temp_sense_sleep_en << 7) | (1 << 6) | + (self.bias_sleep_en << 5) | (0x1f << 0)) + mmap.append( + (0x24 << 16) | (self.data_dly << 13) | (self.clk_dly << 10)) + mmap.append( + (0x2d << 16) | + (self.ostrtodig_sel << 14) | (self.ramp_ena << 13) | + (0x002 << 1) | (self.sifdac_ena << 0)) + mmap.append( + (0x2e << 16) | (self.grp_delaya << 8) | (self.grp_delayb << 0)) + mmap.append( + (0x2f << 16) | (self.grp_delayc << 8) | (self.grp_delayd << 0)) + mmap.append((0x30 << 16) | self.sifdac) + return mmap diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index cb0dccad3..36d9c4c21 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -2,6 +2,8 @@ from artiq.language.core import kernel, delay_mu, delay from artiq.coredevice.rtio import rtio_output, rtio_input_data from artiq.language.units import us, ns, ms, MHz, dB from artiq.language.types import TInt32 +from artiq.coredevice.dac34h84 import DAC34H84 +from artiq.coredevice.trf372017 import TRF372017 PHASER_BOARD_ID = 19 @@ -106,10 +108,22 @@ class Phaser: configured through a shared SPI bus that is accessed and controlled via FPGA registers. + .. note:: Various register settings of the DAC and the quadrature + upconverters are available to be modified through the `dac`, `trf0`, + `trf1` dictionaries. These can be set through the device database + (`device_db.py`). The settings are frozen during instantiation of the + class and applied during `init()`. See the :class:`DAC34H84` and + :class:`TRF372017` source for details. + :param channel: Base RTIO channel number :param core_device: Core device name (default: "core") :param miso_delay: Fastlink MISO signal delay to account for cable - and buffer round trip. This might be automated later. + and buffer round trip. Tuning this might be automated later. + :param dac: DAC34H84 DAC settings as a dictionary. + :param trf0: Channel 0 TRF372017 quadrature upconverter settings as a + dictionary. + :param trf1: Channel 1 TRF372017 quadrature upconverter settings as a + dictionary. Attributes: @@ -117,9 +131,11 @@ class Phaser: To access oscillators, digital upconverters, PLL/VCO analog quadrature upconverters and attenuators. """ - kernel_invariants = {"core", "channel_base", "t_frame", "miso_delay"} + kernel_invariants = {"core", "channel_base", "t_frame", "miso_delay", + "dac_mmap"} - def __init__(self, dmgr, channel_base, miso_delay=1, core_device="core"): + def __init__(self, dmgr, channel_base, miso_delay=1, core_device="core", + dac=None, trf0=None, trf1=None): self.channel_base = channel_base self.core = dmgr.get(core_device) # TODO: auto-align miso-delay in phy @@ -129,14 +145,18 @@ class Phaser: assert self.core.ref_period == 1*ns self.t_frame = 10*8*4 - self.channel = [PhaserChannel(self, ch) for ch in range(2)] + self.dac_mmap = DAC34H84(dac).get_mmap() + + self.channel = [PhaserChannel(self, ch, trf) + for ch, trf in enumerate([trf0, trf1])] @kernel def init(self, clk_sel=0): """Initialize the board. - Verifies board and chip presence, resets components, performs communication - and configuration tests and establishes initial conditions. + Verifies board and chip presence, resets components, performs + communication and configuration tests and establishes initial + conditions. :param clk_sel: Select the external SMA clock input (1 or 0) """ @@ -145,18 +165,28 @@ class Phaser: raise ValueError("invalid board id") delay(20*us) # slack + hw_rev = self.read8(PHASER_ADDR_HW_REV) + delay(.1*ms) # slack + has_upconverter = hw_rev & PHASER_HW_REV_VARIANT + + gw_rev = self.read8(PHASER_ADDR_GW_REV) + delay(.1*ms) # slack + # allow a few errors during startup and alignment since boot if self.get_crc_err() > 20: raise ValueError("large number of frame CRC errors") delay(.1*ms) # slack # reset - self.set_cfg(dac_resetb=0, att0_rstn=0, att1_rstn=0, dac_txena=0) + self.set_cfg(dac_resetb=0, dac_sleep=1, att0_rstn=0, att1_rstn=0, + dac_txena=0) self.set_leds(0x00) self.set_fan_mu(0) - self.set_cfg(clk_sel=clk_sel, dac_txena=0) # bring everything out of reset + # bring everything out of reset, keep tx off + self.set_cfg(clk_sel=clk_sel, dac_txena=0) + # TODO: crossing dac_clk (125 MHz) edges with sync_dly (0-7 ns) - # should change the optimal fifo_offset + # should change the optimal fifo_offset by 4 self.set_sync_dly(4) delay(.1*ms) # slack @@ -174,6 +204,10 @@ class Phaser: if t < 10 or t > 90: raise ValueError("DAC temperature out of bounds") + for data in self.dac_mmap: + self.dac_write(data >> 16, data) + delay(.1*ms) + patterns = [ [0xf05a, 0x05af, 0x5af0, 0xaf05], # test channel/iq/byte/nibble [0x7a7a, 0xb6b6, 0xeaea, 0x4545], # datasheet pattern a @@ -183,206 +217,25 @@ class Phaser: # FPGA+board+DAC skews. There is plenty of margin (>= 250 ps # either side) and no need to tune at runtime. # Parity provides another level of safety. - for dly in [-2]: # range(-7, 8) - if dly < 0: # use data delay, else use clock delay - dly = -dly << 3 - self.dac_write(0x24, dly << 10) - for i in range(len(patterns)): - errors = self.dac_iotest(patterns[i]) - if errors: - raise ValueError("DAC iotest failure") - delay(.5*ms) - - qmc_corr_ena = 0 # msb ab - qmc_offset_ena = 0 # msb ab - invsinc_ena = 0 # msb ab - - interpolation = 1 # 2x - fifo_ena = 1 - alarm_out_ena = 1 - alarm_out_pol = 1 - clkdiv_sync_ena = 1 - self.dac_write(0x00, - (qmc_offset_ena << 14) | (qmc_corr_ena << 12) | - (interpolation << 8) | (fifo_ena << 7) | - (alarm_out_ena << 4) | (alarm_out_pol << 3) | - (clkdiv_sync_ena << 2) | (invsinc_ena << 0)) - iotest_ena = 0 - cnt64_ena = 0 - oddeven_parity = 0 # even - single_parity_ena = 1 - dual_parity_ena = 0 - rev_interface = 0 - dac_complement = 0b0000 # msb A - alarm_fifo = 0b111 # msb 2-away - self.dac_write(0x01, - (iotest_ena << 15) | (cnt64_ena << 12) | - (oddeven_parity << 11) | (single_parity_ena << 10) | - (dual_parity_ena << 9) | (rev_interface << 8) | - (dac_complement << 4) | (alarm_fifo << 1)) - dacclkgone_ena = 1 - dataclkgone_ena = 1 - collisiongone_ena = 1 - sif4_ena = 1 - mixer_ena = 0 - mixer_gain = 1 - nco_ena = 0 - revbus = 0 - twos = 1 - self.dac_write(0x02, - (dacclkgone_ena << 14) | (dataclkgone_ena << 13) | - (collisiongone_ena << 12) | (sif4_ena << 7) | - (mixer_ena << 6) | (mixer_gain << 5) | - (nco_ena << 4) | (revbus << 3) | (twos << 1)) - coarse_dac = 0xa # 20.6 mA, 0-15 - sif_txenable = 0 - self.dac_write(0x03, (coarse_dac << 12) | (sif_txenable << 0)) - mask_alarm_from_zerochk = 0 - mask_alarm_fifo_collision = 0 - mask_alarm_fifo_1away = 0 - mask_alarm_fifo_2away = 0 - mask_alarm_dacclk_gone = 0 - mask_alarm_dataclk_gone = 0 - mask_alarm_output_gone = 0 - mask_alarm_from_iotest = 0 - mask_alarm_from_pll = 0 - mask_alarm_parity = 0b0000 # msb a - self.dac_write(0x07, - (mask_alarm_from_zerochk << 15) | (1 << 14) | - (mask_alarm_fifo_collision << 13) | (mask_alarm_fifo_1away << 12) | - (mask_alarm_fifo_2away << 11) | (mask_alarm_dacclk_gone << 10) | - (mask_alarm_dataclk_gone << 9) | (mask_alarm_output_gone << 8) | - (mask_alarm_from_iotest << 7) | (1 << 6) | - (mask_alarm_from_pll << 5) | (mask_alarm_parity << 1)) - qmc_offseta = 0 # 12b - self.dac_write(0x08, qmc_offseta) - fifo_offset = 2 # 0-7 - qmc_offsetb = 0 # 12b - self.dac_write(0x09, (fifo_offset << 13) | qmc_offsetb) - qmc_offsetc = 0 # 12b - self.dac_write(0x0a, qmc_offsetc) - qmc_offsetd = 0 # 12b - self.dac_write(0x0b, qmc_offsetd) - qmc_gaina = 0 # 11b - self.dac_write(0x0c, qmc_gaina) - cmix_fs8 = 0 - cmix_fs4 = 0 - cmix_fs2 = 0 - cmix_nfs4 = 0 - qmc_gainb = 0 # 11b - self.dac_write(0x0d, - (cmix_fs8 << 15) | (cmix_fs4 << 14) | (cmix_fs2 << 12) | - (cmix_nfs4 << 11) | qmc_gainb) - qmc_gainc = 0 # 11b - self.dac_write(0x0e, qmc_gainc) - output_delayab = 0b00 - output_delaycd = 0b00 - qmc_gaind = 0 # 11b - self.dac_write(0x0f, (output_delayab << 14) | (output_delaycd << 12) | - qmc_gaind) - qmc_phaseab = 0 # 12b - self.dac_write(0x10, qmc_phaseab) - qmc_phasecd = 0 # 12b - self.dac_write(0x11, qmc_phasecd) - pll_reset = 0 - pll_ndivsync_ena = 1 - pll_ena = 1 - pll_cp = 0b01 # single charge pump - pll_p = 0b100 # p=4 - self.dac_write(0x18, - (0b001 << 13) | (pll_reset << 12) | - (pll_ndivsync_ena << 11) | (pll_ena << 10) | - (pll_cp << 6) | (pll_p << 3)) - pll_m2 = 1 # x2 - pll_m = 8 # m = 8 - pll_n = 0b0001 # n = 2 - pll_vcotune = 0b01 - self.dac_write(0x19, - (pll_m2 << 15) | (pll_m << 8) | (pll_n << 4) | (pll_vcotune << 2)) - delay(.5*ms) # slack - pll_vco = 0x3f # 4 GHz - bias_sleep = 0 - tsense_sleep = 0 - pll_sleep = 0 - clkrecv_sleep = 0 - dac_sleep = 0b0000 # msb a - self.dac_write(0x1a, - (pll_vco << 10) | (bias_sleep << 7) | (tsense_sleep << 6) | - (pll_sleep << 5) | (clkrecv_sleep << 4) | (dac_sleep << 0)) - extref_ena = 0 - fuse_sleep = 1 - atest = 0b00000 # atest mode - self.dac_write(0x1b, - (extref_ena << 15) | (fuse_sleep << 11) | (atest << 0)) - syncsel_qmcoffsetab = 0b1001 # sif_sync and register write - syncsel_qmcoffsetcd = 0b1001 # sif_sync and register write - syncsel_qmccorrab = 0b1001 # sif_sync and register write - syncsel_qmccorrcd = 0b1001 # sif_sync and register write - self.dac_write(0x1e, - (syncsel_qmcoffsetab << 12) | (syncsel_qmcoffsetcd << 8) | - (syncsel_qmccorrab << 4) | (syncsel_qmccorrcd << 0)) - syncsel_mixerab = 0b1001 # sif_sync and register write - syncsel_mixercd = 0b1001 # sif_sync and register write - syncsel_nco = 0b1000 # sif_sync - syncsel_fifo_input = 0b10 # external lvds istr - sif_sync = 1 - self.dac_write(0x1e, - (syncsel_mixerab << 12) | (syncsel_mixercd << 8) | - (syncsel_nco << 4) | (syncsel_fifo_input << 2) | - (sif_sync << 1)) - syncsel_fifoin = 0b0010 # istr - syncsel_fifoout = 0b0100 # ostr - clkdiv_sync_sel = 0 # ostr - self.dac_write(0x20, - (syncsel_fifoin << 12) | (syncsel_fifoout << 8) | - (clkdiv_sync_sel << 0)) - path_a_sel = 0b00 - path_b_sel = 0b01 - path_c_sel = 0b10 - path_d_sel = 0b11 - # reverse dacs (DCBA) for spectral inversion and layout - dac_a_sel = 0b11 - dac_b_sel = 0b10 - dac_c_sel = 0b01 - dac_d_sel = 0b00 - self.dac_write(0x22, - (path_a_sel << 14) | (path_b_sel << 12) | - (path_c_sel << 10) | (path_d_sel << 8) | - (dac_a_sel << 6) | (dac_b_sel << 4) | - (dac_c_sel << 2) | (dac_d_sel << 0)) - dac_sleep_en = 0b1111 # msb a - clkrecv_sleep_en = 1 - pll_sleep_en = 1 - lvds_data_sleep_en = 1 - lvds_control_sleep_en = 1 - temp_sense_sleep_en = 1 - bias_sleep_en = 1 - self.dac_write(0x23, - (dac_sleep_en << 12) | (clkrecv_sleep_en << 11) | - (pll_sleep_en << 10) | (lvds_data_sleep_en << 9) | - (lvds_control_sleep_en << 8) | (temp_sense_sleep_en << 7) | - (1 << 6) | (bias_sleep_en << 5) | (0x1f << 0)) - # self.dac_write(0x24, 0x0000) # clk and data delays (tuned above) - ostrtodig_sel = 0 - ramp_ena = 0 - sifdac_ena = 0 - self.dac_write(0x2d, - (ostrtodig_sel << 14) | (ramp_ena << 13) | (0x002 << 1) | - (sifdac_ena << 0)) - grp_delaya = 0x00 - grp_delayb = 0x00 - self.dac_write(0x2e, (grp_delaya << 8) | (grp_delayb << 0)) - grp_delayc = 0x00 - grp_delayd = 0x00 - self.dac_write(0x2f, (grp_delayc << 8) | (grp_delayd << 0)) - sifdac = 0 - self.dac_write(0x30, sifdac) + for i in range(len(patterns)): + delay(.5*ms) + errors = self.dac_iotest(patterns[i]) + if errors: + raise ValueError("DAC iotest failure") + delay(10*ms) # let it settle lvolt = self.dac_read(0x18) & 7 delay(.1*ms) if lvolt < 2 or lvolt > 5: raise ValueError("DAC PLL tuning voltage out of bounds") + # self.dac_write(0x20, 0x0000) # stop fifo sync + # alarm = self.get_sta() & 1 + # delay(.1*ms) + self.clear_dac_alarms() + delay(2*ms) # let it run a bit + self.check_dac_alarms() + for ch in range(2): channel = self.channel[ch] # test attenuator write and readback @@ -400,7 +253,7 @@ class Phaser: asf = 0x7fff # 6pi/4 phase oscillator.set_amplitude_phase_mu(asf=asf, pow=0xc000, clr=1) - delay_mu(8) + delay(1*us) # 3pi/4 channel.set_duc_phase_mu(0x6000) channel.set_duc_cfg(select=0, clr=1) @@ -414,19 +267,17 @@ class Phaser: # allow ripple if (data_i < sqrt2 - 30 or data_i > sqrt2 or abs(data_i - data_q) > 2): - print(data) raise ValueError("DUC+oscillator phase/amplitude test failed") - # self.dac_write(0x20, 0x0000) # stop fifo sync - # alarm = self.get_sta() & 1 - # delay(.1*ms) - self.clear_dac_alarms() - delay(2*ms) # let it run a bit - self.check_dac_alarms() - - hw_rev = self.read8(PHASER_ADDR_HW_REV) - has_upconverter = hw_rev & PHASER_HW_REV_VARIANT - delay(.1*ms) # slack + if has_upconverter: + for data in channel.trf_mmap: + channel.trf_write(data) + delay(.1*ms) + delay(1*ms) # lock + lock_detect = self.get_sta() & (PHASER_STA_TRF0_LD << ch) + delay(.1*ms) + if not lock_detect: + raise ValueError("TRF quadrature upconverter lock failure") self.set_cfg(clk_sel=clk_sel) # txena @@ -662,7 +513,6 @@ class Phaser: alarm = self.get_dac_alarms() delay(.1*ms) # slack if alarm & ~0x0040: # ignore PLL alarms (see DS) - print(alarm) raise ValueError("DAC alarm") @kernel @@ -693,7 +543,9 @@ class Phaser: if channel.get_dac_data() != data: raise ValueError("DAC test data readback failed") delay(.1*ms) - self.dac_write(0x01, 0x8000) # iotest_ena + cfg = self.dac_read(0x01) + delay(.1*ms) + self.dac_write(0x01, cfg | 0x8000) # iotest_ena self.dac_write(0x04, 0x0000) # clear iotest_result delay(.2*ms) # let it rip # no need to go through the alarm register, @@ -706,7 +558,7 @@ class Phaser: delay(.1*ms) # slack else: errors = 0 - self.dac_write(0x01, 0x0000) # clear config + self.dac_write(0x01, cfg) # clear config self.dac_write(0x04, 0x0000) # clear iotest_result return errors @@ -741,11 +593,12 @@ class PhaserChannel: or overflow after the interpolation. Either band-limit any changes in the oscillator parameters or back off the amplitude sufficiently. """ - kernel_invariants = {"index", "phaser"} + kernel_invariants = {"index", "phaser", "trf_mmap"} - def __init__(self, phaser, index): + def __init__(self, phaser, index, trf): self.phaser = phaser self.index = index + self.trf_mmap = TRF372017(trf).get_mmap() self.oscillator = [PhaserOscillator(self, osc) for osc in range(5)] @kernel diff --git a/artiq/coredevice/trf372017.py b/artiq/coredevice/trf372017.py new file mode 100644 index 000000000..0dc1ac5dd --- /dev/null +++ b/artiq/coredevice/trf372017.py @@ -0,0 +1,133 @@ +class TRF372017: + """TRF372017 settings and register map. + + For possible values, documentation, and explanation, see the datasheet. + https://www.ti.com/lit/gpn/trf372017 + """ + rdiv = 21 # 13b + ref_inv = 0 + neg_vco = 1 + icp = 0 # 1.94 mA, 5b + icp_double = 0 + cal_clk_sel = 12 # /16, 4b + + ndiv = 420 # 16b + pll_div_sel = 0b01 # /1, 2b + prsc_sel = 1 # 8/9 + vco_sel = 2 # 2b + vcosel_mode = 0 + cal_acc = 0b00 # 2b + en_cal = 1 + + nfrac = 0 # 25b + + pwd_pll = 0 + pwd_cp = 0 + pwd_vco = 0 + pwd_vcomux = 0 + pwd_div124 = 0 + pwd_presc = 0 + pwd_out_buff = 1 + pwd_lo_div = 1 + pwd_tx_div = 0 + pwd_bb_vcm = 0 + pwd_dc_off = 0 + en_extvco = 0 + en_isource = 0 + ld_ana_prec = 0 # 2b + cp_tristate = 0 # 2b + speedup = 0 + ld_dig_prec = 0 + en_dith = 1 + mod_ord = 2 # 3rd order, 2b + dith_sel = 0 + del_sd_clk = 2 # 2b + en_frac = 0 + + vcobias_rtrim = 4 # 3b + pllbias_rtrim = 2 # 2b + vco_bias = 8 # 460 µA, 4b + vcobuf_bias = 2 # 2b + vcomux_bias = 3 # 2b + bufout_bias = 0 # 300 µA, 2b + vco_cal_ib = 0 # PTAT + vco_cal_ref = 2 # 1.04 V, 2b + vco_ampl_ctrl = 3 # 2b + vco_vb_ctrl = 0 # 1.2 V, 2b + en_ld_isource = 0 + + ioff = 0x80 # 8b + qoff = 0x80 # 8b + vref_sel = 4 # 0.85 V, 3b + tx_div_sel = 1 # div2, 2b + lo_div_sel = 3 # div8, 2b + tx_div_bias = 1 # 37.5 µA, 2b + lo_div_bias = 2 # 50 µA, 2b + + vco_trim = 0x20 # 6b + vco_test_mode = 0 + cal_bypass = 0 + mux_ctrl = 1 # lock detect, 3b + isource_sink = 0 + isource_trim = 4 # 3b + pd_tc = 0 # 2b + ib_vcm_sel = 0 # ptat + dcoffset_i = 2 # 150 µA, 2b + vco_bias_sel = 1 # spi + + def __init__(self, updates=None): + if updates is None: + return + for key, value in updates.items(): + if not hasattr(self, key): + raise KeyError("invalid setting", key) + setattr(self, key, value) + + def get_mmap(self): + mmap = [] + mmap.append( + 0x9 | + (self.rdiv << 5) | (self.ref_inv << 19) | (self.neg_vco << 20) | + (self.icp << 21) | (self.icp_double << 26) | + (self.cal_clk_sel << 27)) + mmap.append( + 0xa | + (self.ndiv << 5) | (self.pll_div_sel << 21) | (self.prsc_sel << 23) | + (self.vco_sel << 26) | (self.vcosel_mode << 28) | + (self.cal_acc << 29) | (self.en_cal << 31)) + mmap.append(0xb | (self.nfrac << 5)) + mmap.append( + 0xc | + (self.pwd_pll << 5) | (self.pwd_cp << 6) | (self.pwd_vco << 7) | + (self.pwd_vcomux << 8) | (self.pwd_div124 << 9) | + (self.pwd_presc << 10) | (self.pwd_out_buff << 12) | + (self.pwd_lo_div << 13) | (self.pwd_tx_div << 14) | + (self.pwd_bb_vcm << 15) | (self.pwd_dc_off << 16) | + (self.en_extvco << 17) | (self.en_isource << 18) | + (self.ld_ana_prec << 19) | (self.cp_tristate << 21) | + (self.speedup << 23) | (self.ld_dig_prec << 24) | + (self.en_dith << 25) | (self.mod_ord << 27) | + (self.dith_sel << 28) | (self.del_sd_clk << 29) | + (self.en_frac << 31)) + mmap.append( + 0xd | + (self.vcobias_rtrim << 5) | (self.pllbias_rtrim << 8) | + (self.vco_bias << 10) | (self.vcobuf_bias << 14) | + (self.vcomux_bias << 16) | (self.bufout_bias << 18) | + (1 << 21) | (self.vco_cal_ib << 22) | (self.vco_cal_ref << 23) | + (self.vco_ampl_ctrl << 26) | (self.vco_vb_ctrl << 28) | + (self.en_ld_isource << 31)) + mmap.append( + 0xe | + (self.ioff << 5) | (self.qoff << 13) | (self.vref_sel << 21) | + (self.tx_div_sel << 24) | (self.lo_div_sel << 26) | + (self.tx_div_bias << 28) | (self.lo_div_bias << 30)) + mmap.append( + 0xf | + (self.vco_trim << 7) | (self.vco_test_mode << 14) | + (self.cal_bypass << 15) | (self.mux_ctrl << 16) | + (self.isource_sink << 19) | (self.isource_trim << 20) | + (self.pd_tc << 23) | (self.ib_vcm_sel << 25) | + (1 << 28) | (self.dcoffset_i << 29) | + (self.vco_bias_sel << 31)) + return mmap From 5c76f5c31980bb996ddb99b9dc3c3fe825601305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 22 Sep 2020 14:36:49 +0000 Subject: [PATCH 2347/2457] tester: add phaser --- artiq/frontend/artiq_sinara_tester.py | 57 +++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index 5aed406e4..48b095729 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -51,6 +51,7 @@ class SinaraTester(EnvExperiment): self.samplers = dict() self.zotinos = dict() self.fastinos = dict() + self.phasers = dict() self.grabbers = dict() ddb = self.get_device_db() @@ -77,6 +78,8 @@ class SinaraTester(EnvExperiment): self.zotinos[name] = self.get_device(name) elif (module, cls) == ("artiq.coredevice.fastino", "Fastino"): self.fastinos[name] = self.get_device(name) + elif (module, cls) == ("artiq.coredevice.phaser", "Phaser"): + self.phasers[name] = self.get_device(name) elif (module, cls) == ("artiq.coredevice.grabber", "Grabber"): self.grabbers[name] = self.get_device(name) @@ -111,6 +114,7 @@ class SinaraTester(EnvExperiment): self.samplers = sorted(self.samplers.items(), key=lambda x: x[1].cnv.channel) self.zotinos = sorted(self.zotinos.items(), key=lambda x: x[1].bus.channel) self.fastinos = sorted(self.fastinos.items(), key=lambda x: x[1].channel) + self.phasers = sorted(self.phasers.items(), key=lambda x: x[1].channel_base) self.grabbers = sorted(self.grabbers.items(), key=lambda x: x[1].channel_base) @kernel @@ -391,6 +395,57 @@ class SinaraTester(EnvExperiment): [card_dev for _, (__, card_dev) in enumerate(self.fastinos)] ) + @kernel + def set_phaser_frequencies(self, phaser, duc, osc): + self.core.break_realtime() + phaser.init() + delay(1*ms) + phaser.channel[0].set_duc_frequency(duc) + phaser.channel[0].set_duc_cfg() + phaser.channel[0].set_att(6*dB) + phaser.channel[1].set_duc_frequency(-duc) + phaser.channel[1].set_duc_cfg() + phaser.channel[1].set_att(6*dB) + phaser.duc_stb() + delay(1*ms) + for i in range(len(osc)): + phaser.channel[0].oscillator[i].set_frequency(osc[i]) + phaser.channel[0].oscillator[i].set_amplitude_phase(.2) + phaser.channel[1].oscillator[i].set_frequency(-osc[i]) + phaser.channel[1].oscillator[i].set_amplitude_phase(.2) + delay(1*ms) + + @kernel + def phaser_led_wave(self, phasers): + while not is_enter_pressed(): + self.core.break_realtime() + # do not fill the FIFOs too much to avoid long response times + t = now_mu() - self.core.seconds_to_mu(.2) + while self.core.get_rtio_counter_mu() < t: + pass + for phaser in phasers: + for i in range(6): + phaser.set_leds(1 << i) + delay(100*ms) + phaser.set_leds(0) + delay(100*ms) + + def test_phasers(self): + print("*** Testing Phaser DACs and 6 USER LEDs.") + print("Frequencies:") + for card_n, (card_name, card_dev) in enumerate(self.phasers): + duc = (card_n + 1)*10*MHz + osc = [i*1*MHz for i in range(5)] + print(card_name, + " ".join(["{:.0f}+{:.0f}".format(duc/MHz, f/MHz) for f in osc]), + "MHz") + self.set_phaser_frequencies(card_dev, duc, osc) + print("Press ENTER when done.") + # Test switching on/off USR_LEDs at the same time + self.phaser_led_wave( + [card_dev for _, (__, card_dev) in enumerate(self.phasers)] + ) + @kernel def grabber_capture(self, card_dev, rois): self.core.break_realtime() @@ -443,6 +498,8 @@ class SinaraTester(EnvExperiment): self.test_zotinos() if self.fastinos: self.test_fastinos() + if self.phasers: + self.test_phasers() if self.grabbers: self.test_grabbers() From 85d16e3e5fdd1251be93076690de10c688753ef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 22 Sep 2020 15:27:38 +0000 Subject: [PATCH 2348/2457] phaser: tweaks --- artiq/coredevice/dac34h84.py | 2 +- artiq/coredevice/phaser.py | 17 +++++++++-------- artiq/coredevice/trf372017.py | 4 ++-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/artiq/coredevice/dac34h84.py b/artiq/coredevice/dac34h84.py index 86e818c7e..d288cd524 100644 --- a/artiq/coredevice/dac34h84.py +++ b/artiq/coredevice/dac34h84.py @@ -32,7 +32,7 @@ class DAC34H84: revbus = 0 twos = 1 - coarse_dac = 0xa # 20.6 mA, 0-15 + coarse_dac = 9 # 18.75 mA, 0-15 sif_txenable = 0 mask_alarm_from_zerochk = 0 diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 36d9c4c21..787e4990e 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -119,6 +119,7 @@ class Phaser: :param core_device: Core device name (default: "core") :param miso_delay: Fastlink MISO signal delay to account for cable and buffer round trip. Tuning this might be automated later. + :param clk_sel: Select the external SMA clock input (1 or 0) :param dac: DAC34H84 DAC settings as a dictionary. :param trf0: Channel 0 TRF372017 quadrature upconverter settings as a dictionary. @@ -134,8 +135,8 @@ class Phaser: kernel_invariants = {"core", "channel_base", "t_frame", "miso_delay", "dac_mmap"} - def __init__(self, dmgr, channel_base, miso_delay=1, core_device="core", - dac=None, trf0=None, trf1=None): + def __init__(self, dmgr, channel_base, miso_delay=1, clk_sel=0, + dac=None, trf0=None, trf1=None, core_device="core"): self.channel_base = channel_base self.core = dmgr.get(core_device) # TODO: auto-align miso-delay in phy @@ -144,6 +145,7 @@ class Phaser: # self.core.seconds_to_mu(10*8*4*ns) # unfortunately this returns 319 assert self.core.ref_period == 1*ns self.t_frame = 10*8*4 + self.clk_sel = clk_sel self.dac_mmap = DAC34H84(dac).get_mmap() @@ -151,14 +153,13 @@ class Phaser: for ch, trf in enumerate([trf0, trf1])] @kernel - def init(self, clk_sel=0): + def init(self): """Initialize the board. Verifies board and chip presence, resets components, performs communication and configuration tests and establishes initial conditions. - :param clk_sel: Select the external SMA clock input (1 or 0) """ board_id = self.read8(PHASER_ADDR_BOARD_ID) if board_id != PHASER_BOARD_ID: @@ -167,7 +168,7 @@ class Phaser: hw_rev = self.read8(PHASER_ADDR_HW_REV) delay(.1*ms) # slack - has_upconverter = hw_rev & PHASER_HW_REV_VARIANT + is_baseband = hw_rev & PHASER_HW_REV_VARIANT gw_rev = self.read8(PHASER_ADDR_GW_REV) delay(.1*ms) # slack @@ -183,7 +184,7 @@ class Phaser: self.set_leds(0x00) self.set_fan_mu(0) # bring everything out of reset, keep tx off - self.set_cfg(clk_sel=clk_sel, dac_txena=0) + self.set_cfg(clk_sel=self.clk_sel, dac_txena=0) # TODO: crossing dac_clk (125 MHz) edges with sync_dly (0-7 ns) # should change the optimal fifo_offset by 4 @@ -269,7 +270,7 @@ class Phaser: abs(data_i - data_q) > 2): raise ValueError("DUC+oscillator phase/amplitude test failed") - if has_upconverter: + if not is_baseband: for data in channel.trf_mmap: channel.trf_write(data) delay(.1*ms) @@ -279,7 +280,7 @@ class Phaser: if not lock_detect: raise ValueError("TRF quadrature upconverter lock failure") - self.set_cfg(clk_sel=clk_sel) # txena + self.set_cfg(clk_sel=self.clk_sel) # txena @kernel def write8(self, addr, data): diff --git a/artiq/coredevice/trf372017.py b/artiq/coredevice/trf372017.py index 0dc1ac5dd..053a8a5fc 100644 --- a/artiq/coredevice/trf372017.py +++ b/artiq/coredevice/trf372017.py @@ -12,7 +12,7 @@ class TRF372017: cal_clk_sel = 12 # /16, 4b ndiv = 420 # 16b - pll_div_sel = 0b01 # /1, 2b + pll_div_sel = 0 # /1, 2b prsc_sel = 1 # 8/9 vco_sel = 2 # 2b vcosel_mode = 0 @@ -106,7 +106,7 @@ class TRF372017: (self.en_extvco << 17) | (self.en_isource << 18) | (self.ld_ana_prec << 19) | (self.cp_tristate << 21) | (self.speedup << 23) | (self.ld_dig_prec << 24) | - (self.en_dith << 25) | (self.mod_ord << 27) | + (self.en_dith << 25) | (self.mod_ord << 26) | (self.dith_sel << 28) | (self.del_sd_clk << 29) | (self.en_frac << 31)) mmap.append( From ad096f294c841bef9f95c85422a02a773acb02c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 22 Sep 2020 15:35:19 +0000 Subject: [PATCH 2349/2457] phaser: add hitl test exercising the complete API --- artiq/test/coredevice/test_phaser.py | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 artiq/test/coredevice/test_phaser.py diff --git a/artiq/test/coredevice/test_phaser.py b/artiq/test/coredevice/test_phaser.py new file mode 100644 index 000000000..18aac6a57 --- /dev/null +++ b/artiq/test/coredevice/test_phaser.py @@ -0,0 +1,34 @@ +import unittest +from artiq.experiment import * +from artiq.test.hardware_testbench import ExperimentCase +from artiq.language.core import kernel, delay +from artiq.language.units import us + + +class PhaserExperiment(EnvExperiment): + def build(self): + self.setattr_device("core") + self.setattr_device("phaser0") + + @kernel + def run(self): + self.core.reset() + # The Phaser initialization performs a comprehensive test: + # * Fastlink bringup + # * Fastlink error counter + # * Board identification + # * Hardware identification + # * SPI write, readback, timing + # * Temperature readout + # * DAC identification, IOTEST, alarm sweep, PLL configuration, FIFO + # alignmend + # * DUC+Oscillator configuration, data end-to-end verification and + # readback + # * Attenuator write and readback + # * TRF bringup PLL locking + self.phaser0.init() + + +class PhaserTest(ExperimentCase): + def test(self): + self.execute(PhaserExperiment) From c55f2222dc1fed45dbeb4c7dfd8e186f1c196407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 22 Sep 2020 17:58:53 +0200 Subject: [PATCH 2350/2457] fastino: documentation and eem pass-through * Repeat information about matching log2_width a few times in the hope that people read it. #1518 * Pass through log2_width in kasli_generic json. close #1481 * Check DAC value range. #1518 --- artiq/coredevice/fastino.py | 22 ++++++++++++---------- artiq/gateware/eem.py | 4 ++-- artiq/gateware/targets/kasli_generic.py | 3 ++- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/artiq/coredevice/fastino.py b/artiq/coredevice/fastino.py index 200d89018..73fcfdf38 100644 --- a/artiq/coredevice/fastino.py +++ b/artiq/coredevice/fastino.py @@ -19,17 +19,17 @@ class Fastino: bit using :meth:`set_update`. Update is self-clearing. This enables atomic DAC updates synchronized to a frame edge. - The `log2_width=0` RTIO layout uses one DAC channel per RTIO address - and a dense RTIO address space. The RTIO words are narrow. - (32 bit compared to 512) and few-channel updates are efficient. - There is the least amount of DAC state tracking in kernels, - at the cost of more DMA and RTIO data. + The `log2_width=0` RTIO layout uses one DAC channel per RTIO address and a + dense RTIO address space. The RTIO words are narrow. (32 bit) and + few-channel updates are efficient. There is the least amount of DAC state + tracking in kernels, at the cost of more DMA and RTIO data. + The setting here and in the RTIO PHY (gateware) must match. Other `log2_width` (up to `log2_width=5`) settings pack multiple (in powers of two) DAC channels into one group and into one RTIO write. The RTIO data width increases accordingly. The `log2_width` LSBs of the RTIO address for a DAC channel write must be zero and the - address space is sparse. + address space is sparse. For `log2_width=5` the RTIO data is 512 bit wide. If `log2_width` is zero, the :meth:`set_dac`/:meth:`set_dac_mu` interface must be used. If non-zero, the :meth:`set_group`/:meth:`set_group_mu` @@ -37,9 +37,8 @@ class Fastino: :param channel: RTIO channel number :param core_device: Core device name (default: "core") - :param log2_width: Width of DAC channel group (power of two, - see the RTIO PHY for details). Value must match the corresponding value - in the RTIO PHY. + :param log2_width: Width of DAC channel group (logarithm base 2). + Value must match the corresponding value in the RTIO PHY (gateware). """ kernel_invariants = {"core", "channel", "width"} @@ -113,7 +112,10 @@ class Fastino: :param voltage: Voltage in SI Volts. :return: DAC data word in machine units, 16 bit integer. """ - return (int(round((0x8000/10.)*voltage)) + 0x8000) & 0xffff + data = int(round((0x8000/10.)*voltage)) + 0x8000 + if data < 0 or data > 0xffff: + raise ValueError("DAC voltage out of bounds") + return data @portable def voltage_group_to_mu(self, voltage, data): diff --git a/artiq/gateware/eem.py b/artiq/gateware/eem.py index fba2c1b5a..19fbe7ea8 100644 --- a/artiq/gateware/eem.py +++ b/artiq/gateware/eem.py @@ -618,11 +618,11 @@ class Fastino(_EEM): ) for pol in "pn"] @classmethod - def add_std(cls, target, eem, iostandard="LVDS_25"): + def add_std(cls, target, eem, log2_width, iostandard="LVDS_25"): cls.add_extension(target, eem, iostandard=iostandard) phy = fastino.Fastino(target.platform.request("fastino{}_ser_p".format(eem)), target.platform.request("fastino{}_ser_n".format(eem)), - log2_width=0) + log2_width=log2_width) target.submodules += phy target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4)) diff --git a/artiq/gateware/targets/kasli_generic.py b/artiq/gateware/targets/kasli_generic.py index 939f60716..2fcd299a1 100755 --- a/artiq/gateware/targets/kasli_generic.py +++ b/artiq/gateware/targets/kasli_generic.py @@ -109,7 +109,8 @@ def peripheral_mirny(module, peripheral): def peripheral_fastino(module, peripheral): if len(peripheral["ports"]) != 1: raise ValueError("wrong number of ports") - eem.Fastino.add_std(module, peripheral["ports"][0]) + eem.Fastino.add_std(module, peripheral["ports"][0], + peripheral.get("log2_width", 0)) peripheral_processors = { From ef65ee18bdd14bbf8c41f8aed401a4b0763c8069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 23 Sep 2020 08:35:56 +0000 Subject: [PATCH 2351/2457] dac34h84: unflip spectrum, clear nco --- artiq/coredevice/dac34h84.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/artiq/coredevice/dac34h84.py b/artiq/coredevice/dac34h84.py index d288cd524..6d40826b3 100644 --- a/artiq/coredevice/dac34h84.py +++ b/artiq/coredevice/dac34h84.py @@ -72,6 +72,13 @@ class DAC34H84: qmc_phasecd = 0 # 12b + phase_offsetab = 0 # 16b + phase_offsetcd = 0 # 16b + phase_addab_lsb = 0 # 16b + phase_addab_msb = 0 # 16b + phase_addcd_lsb = 0 # 16b + phase_addcd_msb = 0 # 16b + pll_reset = 0 pll_ndivsync_ena = 1 pll_ena = 1 @@ -109,15 +116,15 @@ class DAC34H84: syncsel_fifoout = 0b0100 # ostr clkdiv_sync_sel = 0 # ostr - path_a_sel = 0b00 - path_b_sel = 0b01 - path_c_sel = 0b10 - path_d_sel = 0b11 - # reverse dacs (DCBA) for spectral inversion and layout - dac_a_sel = 0b11 - dac_b_sel = 0b10 - dac_c_sel = 0b01 - dac_d_sel = 0b00 + path_a_sel = 0 + path_b_sel = 1 + path_c_sel = 2 + path_d_sel = 3 + # swap dac pairs (CDAB) for layout + dac_a_sel = 2 + dac_b_sel = 3 + dac_c_sel = 0 + dac_d_sel = 1 dac_sleep_en = 0b1111 # msb a clkrecv_sleep_en = 1 @@ -201,6 +208,12 @@ class DAC34H84: (self.qmc_gaind << 0)) mmap.append((0x10 << 16) | (self.qmc_phaseab << 0)) mmap.append((0x11 << 16) | (self.qmc_phasecd << 0)) + mmap.append((0x12 << 16) | (self.phase_offsetab << 0)) + mmap.append((0x13 << 16) | (self.phase_offsetcd << 0)) + mmap.append((0x14 << 16) | (self.phase_addab_lsb << 0)) + mmap.append((0x15 << 16) | (self.phase_addab_msb << 0)) + mmap.append((0x16 << 16) | (self.phase_addcd_lsb << 0)) + mmap.append((0x17 << 16) | (self.phase_addcd_msb << 0)) mmap.append( (0x18 << 16) | (0b001 << 13) | (self.pll_reset << 12) | From 03d5f985f8032c5ae076c6dad4f6d8801fc6d473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Wed, 23 Sep 2020 15:40:54 +0000 Subject: [PATCH 2352/2457] phaser: another artiq-python signed integer quirk --- artiq/coredevice/dac34h84.py | 9 +++++---- artiq/coredevice/phaser.py | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/artiq/coredevice/dac34h84.py b/artiq/coredevice/dac34h84.py index 6d40826b3..155096a1e 100644 --- a/artiq/coredevice/dac34h84.py +++ b/artiq/coredevice/dac34h84.py @@ -121,10 +121,11 @@ class DAC34H84: path_c_sel = 2 path_d_sel = 3 # swap dac pairs (CDAB) for layout - dac_a_sel = 2 - dac_b_sel = 3 - dac_c_sel = 0 - dac_d_sel = 1 + # swap I-Q dacs for spectral inversion + dac_a_sel = 3 + dac_b_sel = 2 + dac_c_sel = 1 + dac_d_sel = 0 dac_sleep_en = 0b1111 # msb a clkrecv_sleep_en = 1 diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 787e4990e..8acaf9010 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -651,7 +651,7 @@ class PhaserChannel: :param frequency: DUC frequency in Hz (passband from -200 MHz to 200 MHz, wrapping around at +- 250 MHz) """ - ftw = int32(round(frequency*((1 << 31)/(250*MHz)))) + ftw = int32(round(frequency*((1 << 30)/(125*MHz)))) self.set_duc_frequency_mu(ftw) @kernel @@ -689,7 +689,7 @@ class PhaserChannel: :param frequency: NCO frequency in Hz (passband from -400 MHz to 400 MHz, wrapping around at +- 500 MHz) """ - ftw = int32(round(frequency*((1 << 31)/(500*MHz)))) + ftw = int32(round(frequency*((1 << 30)/(250*MHz)))) self.set_nco_frequency_mu(ftw) @kernel @@ -831,7 +831,7 @@ class PhaserOscillator: :param frequency: Frequency in Hz (passband from -10 MHz to 10 MHz, wrapping around at +- 12.5 MHz) """ - ftw = int32(round(frequency*((1 << 31)/(12.5*MHz)))) + ftw = int32(round(frequency*((1 << 30)/(6.25*MHz)))) self.set_frequency_mu(ftw) @kernel From 6e6480ec211823b2ca57f4bbd56f8f43a6f97571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 24 Sep 2020 08:38:30 +0000 Subject: [PATCH 2353/2457] phaser: tweak slacks and errors, identify trf --- artiq/coredevice/phaser.py | 44 +++++++++++++++++++++-------------- artiq/coredevice/trf372017.py | 2 +- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 8acaf9010..56b09f13e 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -167,11 +167,11 @@ class Phaser: delay(20*us) # slack hw_rev = self.read8(PHASER_ADDR_HW_REV) - delay(.1*ms) # slack + delay(20*us) # slack is_baseband = hw_rev & PHASER_HW_REV_VARIANT gw_rev = self.read8(PHASER_ADDR_GW_REV) - delay(.1*ms) # slack + delay(20*us) # slack # allow a few errors during startup and alignment since boot if self.get_crc_err() > 20: @@ -185,11 +185,11 @@ class Phaser: self.set_fan_mu(0) # bring everything out of reset, keep tx off self.set_cfg(clk_sel=self.clk_sel, dac_txena=0) + delay(.1*ms) # slack # TODO: crossing dac_clk (125 MHz) edges with sync_dly (0-7 ns) # should change the optimal fifo_offset by 4 self.set_sync_dly(4) - delay(.1*ms) # slack # 4 wire SPI, sif4_enable self.dac_write(0x02, 0x0080) @@ -207,7 +207,7 @@ class Phaser: for data in self.dac_mmap: self.dac_write(data >> 16, data) - delay(.1*ms) + delay(20*us) patterns = [ [0xf05a, 0x05af, 0x5af0, 0xaf05], # test channel/iq/byte/nibble @@ -219,16 +219,16 @@ class Phaser: # either side) and no need to tune at runtime. # Parity provides another level of safety. for i in range(len(patterns)): - delay(.5*ms) + delay(.2*ms) errors = self.dac_iotest(patterns[i]) if errors: raise ValueError("DAC iotest failure") - delay(10*ms) # let it settle + delay(2*ms) # let it settle lvolt = self.dac_read(0x18) & 7 delay(.1*ms) if lvolt < 2 or lvolt > 5: - raise ValueError("DAC PLL tuning voltage out of bounds") + raise ValueError("DAC PLL lock failed, check clocking") # self.dac_write(0x20, 0x0000) # stop fifo sync # alarm = self.get_sta() & 1 @@ -270,15 +270,24 @@ class Phaser: abs(data_i - data_q) > 2): raise ValueError("DUC+oscillator phase/amplitude test failed") - if not is_baseband: - for data in channel.trf_mmap: - channel.trf_write(data) - delay(.1*ms) - delay(1*ms) # lock - lock_detect = self.get_sta() & (PHASER_STA_TRF0_LD << ch) - delay(.1*ms) - if not lock_detect: - raise ValueError("TRF quadrature upconverter lock failure") + if is_baseband: + continue + + if channel.trf_read(0) & 0x7f != 0x68: + raise ValueError("TRF identification failed") + delay(.1*ms) + + delay(.2*ms) + for data in channel.trf_mmap: + channel.trf_write(data) + + delay(2*ms) # lock + if not (self.get_sta() & (PHASER_STA_TRF0_LD << ch)): + raise ValueError("TRF lock failure") + delay(.1*ms) + if channel.trf_read(0) & 0x1000: + raise ValueError("TRF R_SAT_ERR") + delay(.1*ms) self.set_cfg(clk_sel=self.clk_sel) # txena @@ -799,7 +808,8 @@ class PhaserChannel: self.phaser.spi_cfg(select=0, div=34, end=1, length=1) self.phaser.spi_write(0) delay((1 + 1)*34*4*ns) - return self.trf_write(0x00000008, readback=True) + return self.trf_write(0x00000008 | (cnt_mux_sel << 27), + readback=True) class PhaserOscillator: diff --git a/artiq/coredevice/trf372017.py b/artiq/coredevice/trf372017.py index 053a8a5fc..40957db86 100644 --- a/artiq/coredevice/trf372017.py +++ b/artiq/coredevice/trf372017.py @@ -37,7 +37,7 @@ class TRF372017: ld_ana_prec = 0 # 2b cp_tristate = 0 # 2b speedup = 0 - ld_dig_prec = 0 + ld_dig_prec = 1 en_dith = 1 mod_ord = 2 # 3rd order, 2b dith_sel = 0 From a65239957f2152fd799301314190e937f006a712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 17 Sep 2020 14:13:10 +0000 Subject: [PATCH 2354/2457] ad53xx: distinguish errors --- artiq/coredevice/ad53xx.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/coredevice/ad53xx.py b/artiq/coredevice/ad53xx.py index c4ff6d3aa..3445555d9 100644 --- a/artiq/coredevice/ad53xx.py +++ b/artiq/coredevice/ad53xx.py @@ -178,6 +178,8 @@ class AD53xx: self.write_offset_dacs_mu(self.offset_dacs) if not blind: ctrl = self.read_reg(channel=0, op=AD53XX_READ_CONTROL) + if ctrl == 0xffff: + raise ValueError("DAC not found") if ctrl & 0b10000: raise ValueError("DAC over temperature") delay(25*us) From fec2f8b763d257e75bb863bb22b6b29327263245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Thu, 24 Sep 2020 10:59:22 +0000 Subject: [PATCH 2355/2457] phaser: increase slack for iotest --- artiq/coredevice/phaser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 56b09f13e..5dabc36a6 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -219,7 +219,7 @@ class Phaser: # either side) and no need to tune at runtime. # Parity provides another level of safety. for i in range(len(patterns)): - delay(.2*ms) + delay(.5*ms) errors = self.dac_iotest(patterns[i]) if errors: raise ValueError("DAC iotest failure") From 2fba3cfc78252d2b87d4e005099deee4d08c60dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Fri, 25 Sep 2020 20:54:59 +0000 Subject: [PATCH 2356/2457] phaser: debug init, systematic bring-up --- artiq/coredevice/phaser.py | 42 ++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 5dabc36a6..e42accb5a 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -153,13 +153,12 @@ class Phaser: for ch, trf in enumerate([trf0, trf1])] @kernel - def init(self): + def init(self, debug=False): """Initialize the board. Verifies board and chip presence, resets components, performs communication and configuration tests and establishes initial conditions. - """ board_id = self.read8(PHASER_ADDR_BOARD_ID) if board_id != PHASER_BOARD_ID: @@ -179,12 +178,15 @@ class Phaser: delay(.1*ms) # slack # reset - self.set_cfg(dac_resetb=0, dac_sleep=1, att0_rstn=0, att1_rstn=0, - dac_txena=0) + self.set_cfg(dac_resetb=0, dac_sleep=1, dac_txena=0, + trf0_ps=1, trf1_ps=1, + att0_rstn=0, att1_rstn=0) self.set_leds(0x00) self.set_fan_mu(0) - # bring everything out of reset, keep tx off - self.set_cfg(clk_sel=self.clk_sel, dac_txena=0) + # bring dac out of reset, keep tx off + self.set_cfg(clk_sel=self.clk_sel, dac_txena=0, + trf0_ps=1, trf1_ps=1, + att0_rstn=0, att1_rstn=0) delay(.1*ms) # slack # TODO: crossing dac_clk (125 MHz) edges with sync_dly (0-7 ns) @@ -235,7 +237,17 @@ class Phaser: # delay(.1*ms) self.clear_dac_alarms() delay(2*ms) # let it run a bit - self.check_dac_alarms() + alarms = self.get_dac_alarms() + delay(.1*ms) # slack + if alarms & ~0x0040: # ignore PLL alarms (see DS) + if debug: + print(alarms) + self.core.break_realtime() + else: + raise ValueError("DAC alarm") + + # power up trfs, release att reset + self.set_cfg(clk_sel=self.clk_sel, dac_txena=0) for ch in range(2): channel = self.channel[ch] @@ -244,7 +256,7 @@ class Phaser: if channel.get_att_mu() != 0x5a: raise ValueError("attenuator test failed") delay(.1*ms) - channel.set_att(31.5*dB) + channel.set_att_mu(0x00) # minimum attenuation # test oscillators and DUC for i in range(len(channel.oscillator)): @@ -289,7 +301,8 @@ class Phaser: raise ValueError("TRF R_SAT_ERR") delay(.1*ms) - self.set_cfg(clk_sel=self.clk_sel) # txena + # enable dac tx + self.set_cfg(clk_sel=self.clk_sel) @kernel def write8(self, addr, data): @@ -518,13 +531,6 @@ class Phaser: """ return self.dac_read(0x05) - @kernel - def check_dac_alarms(self): - alarm = self.get_dac_alarms() - delay(.1*ms) # slack - if alarm & ~0x0040: # ignore PLL alarms (see DS) - raise ValueError("DAC alarm") - @kernel def clear_dac_alarms(self): """Clear DAC alarm flags.""" @@ -561,9 +567,9 @@ class Phaser: # no need to go through the alarm register, # just read the error mask # self.clear_dac_alarms() - alarm = self.get_dac_alarms() + alarms = self.get_dac_alarms() delay(.1*ms) # slack - if alarm & 0x0080: # alarm_from_iotest + if alarms & 0x0080: # alarm_from_iotest errors = self.dac_read(0x04) delay(.1*ms) # slack else: From 569e5e56cd5cef6a4b26d5c1e2d2fd2677d3bb8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sat, 26 Sep 2020 20:37:16 +0000 Subject: [PATCH 2357/2457] phaser: autotune and fix fifo_offset --- artiq/coredevice/phaser.py | 61 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index e42accb5a..6ed6c4b3b 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -115,10 +115,20 @@ class Phaser: class and applied during `init()`. See the :class:`DAC34H84` and :class:`TRF372017` source for details. + .. note:: To establish deterministic latency between RTIO time base and DAC + output, the DAC FIFO read pointer value (`fifo_offset`) must be + fixed. If `tune_fifo_offset=True` (the default) a value with maximum + margin is determined automatically by `dac_tune_fifo_offset` each time + `init()` is called. This value should be used for the `fifo_offset` key + of the `dac` settings of Phaser in `device_db.py` and automatic + tuning should be disabled by `tune_fifo_offset=False`. + :param channel: Base RTIO channel number :param core_device: Core device name (default: "core") :param miso_delay: Fastlink MISO signal delay to account for cable and buffer round trip. Tuning this might be automated later. + :param tune_fifo_offset: Tune the DAC FIFO read pointer offset + (default=True) :param clk_sel: Select the external SMA clock input (1 or 0) :param dac: DAC34H84 DAC settings as a dictionary. :param trf0: Channel 0 TRF372017 quadrature upconverter settings as a @@ -135,8 +145,8 @@ class Phaser: kernel_invariants = {"core", "channel_base", "t_frame", "miso_delay", "dac_mmap"} - def __init__(self, dmgr, channel_base, miso_delay=1, clk_sel=0, - dac=None, trf0=None, trf1=None, core_device="core"): + def __init__(self, dmgr, channel_base, miso_delay=1, tune_fifo_offset=True, + clk_sel=0, dac=None, trf0=None, trf1=None, core_device="core"): self.channel_base = channel_base self.core = dmgr.get(core_device) # TODO: auto-align miso-delay in phy @@ -146,6 +156,7 @@ class Phaser: assert self.core.ref_period == 1*ns self.t_frame = 10*8*4 self.clk_sel = clk_sel + self.tune_fifo_offset = tune_fifo_offset self.dac_mmap = DAC34H84(dac).get_mmap() @@ -232,6 +243,9 @@ class Phaser: if lvolt < 2 or lvolt > 5: raise ValueError("DAC PLL lock failed, check clocking") + if self.tune_fifo_offset: + self.dac_tune_fifo_offset() + # self.dac_write(0x20, 0x0000) # stop fifo sync # alarm = self.get_sta() & 1 # delay(.1*ms) @@ -578,6 +592,49 @@ class Phaser: self.dac_write(0x04, 0x0000) # clear iotest_result return errors + @kernel + def dac_tune_fifo_offset(self): + """Scan through `fifo_offset` and configure midpoint setting. + + :return: Optimal `fifo_offset` setting with maximum margin to write + pointer. + """ + # expect two or three error free offsets: + # + # read offset 01234567 + # write pointer w + # distance 32101234 + # error free x xx + config9 = self.dac_read(0x09) + delay(.1*ms) + good = 0 + for o in range(8): + # set new fifo_offset + self.dac_write(0x09, (config9 & 0x1fff) | (o << 13)) + self.clear_dac_alarms() + delay(.1*ms) # run + alarms = self.get_dac_alarms() + delay(.1*ms) # slack + if (alarms >> 11) & 0x7 == 0: # any fifo alarm + good |= 1 << o + # if there are good offsets accross the wrap around + # offset for computations + if good & 0x81 == 0x81: + good = ((good << 4) & 0xf0) | (good >> 4) + offset = 4 + else: + offset = 0 + # calculate mean + sum = 0 + count = 0 + for o in range(8): + if good & (1 << o): + sum += o + count += 1 + best = ((sum // count) + offset) % 8 + self.dac_write(0x09, (config9 & 0x1fff) | (best << 13)) + return best + class PhaserChannel: """Phaser channel IQ pair. From 6c8bddcf8d251ec76a08baf478504e6be5fd9794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sat, 26 Sep 2020 21:13:00 +0000 Subject: [PATCH 2358/2457] phaser: tune sync_dly --- artiq/coredevice/phaser.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 6ed6c4b3b..9727fb92e 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -130,6 +130,7 @@ class Phaser: :param tune_fifo_offset: Tune the DAC FIFO read pointer offset (default=True) :param clk_sel: Select the external SMA clock input (1 or 0) + :param sync_dly: SYNC delay with respect to ISTR. :param dac: DAC34H84 DAC settings as a dictionary. :param trf0: Channel 0 TRF372017 quadrature upconverter settings as a dictionary. @@ -146,7 +147,8 @@ class Phaser: "dac_mmap"} def __init__(self, dmgr, channel_base, miso_delay=1, tune_fifo_offset=True, - clk_sel=0, dac=None, trf0=None, trf1=None, core_device="core"): + clk_sel=0, sync_dly=0, dac=None, trf0=None, trf1=None, + core_device="core"): self.channel_base = channel_base self.core = dmgr.get(core_device) # TODO: auto-align miso-delay in phy @@ -157,6 +159,7 @@ class Phaser: self.t_frame = 10*8*4 self.clk_sel = clk_sel self.tune_fifo_offset = tune_fifo_offset + self.sync_dly = sync_dly self.dac_mmap = DAC34H84(dac).get_mmap() @@ -200,9 +203,10 @@ class Phaser: att0_rstn=0, att1_rstn=0) delay(.1*ms) # slack - # TODO: crossing dac_clk (125 MHz) edges with sync_dly (0-7 ns) - # should change the optimal fifo_offset by 4 - self.set_sync_dly(4) + # TODO: crossing dac_clk (125 MHz) edges with sync_dly (2ns long, + # 0-14 ns delay in steps of 2ns) should change the optimal + # fifo_offset by 4 + self.set_sync_dly(self.sync_dly) # 4 wire SPI, sif4_enable self.dac_write(0x02, 0x0080) @@ -222,6 +226,11 @@ class Phaser: self.dac_write(data >> 16, data) delay(20*us) + # pll_ndivsync_ena disable + config18 = self.dac_read(0x18) + delay(.1*ms) + self.dac_write(0x18, config18 & ~0x0800) + patterns = [ [0xf05a, 0x05af, 0x5af0, 0xaf05], # test channel/iq/byte/nibble [0x7a7a, 0xb6b6, 0xeaea, 0x4545], # datasheet pattern a @@ -257,6 +266,7 @@ class Phaser: if debug: print(alarms) self.core.break_realtime() + # ignore alarms else: raise ValueError("DAC alarm") From c453c24fb06259e845fa49d8baa23934a1035ec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sat, 26 Sep 2020 21:16:08 +0000 Subject: [PATCH 2359/2457] phaser: tweak slacks --- artiq/coredevice/phaser.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 9727fb92e..32482d047 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -177,14 +177,14 @@ class Phaser: board_id = self.read8(PHASER_ADDR_BOARD_ID) if board_id != PHASER_BOARD_ID: raise ValueError("invalid board id") - delay(20*us) # slack + delay(.1*ms) # slack hw_rev = self.read8(PHASER_ADDR_HW_REV) - delay(20*us) # slack + delay(.1*ms) # slack is_baseband = hw_rev & PHASER_HW_REV_VARIANT gw_rev = self.read8(PHASER_ADDR_GW_REV) - delay(20*us) # slack + delay(.1*ms) # slack # allow a few errors during startup and alignment since boot if self.get_crc_err() > 20: @@ -218,13 +218,13 @@ class Phaser: delay(.1*ms) t = self.get_dac_temperature() - delay(.5*ms) + delay(.1*ms) if t < 10 or t > 90: raise ValueError("DAC temperature out of bounds") for data in self.dac_mmap: self.dac_write(data >> 16, data) - delay(20*us) + delay(40*us) # pll_ndivsync_ena disable config18 = self.dac_read(0x18) From eecd97ce4c1ea5e7196b4b95226e3f7227660435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sun, 27 Sep 2020 17:15:16 +0000 Subject: [PATCH 2360/2457] phaser: debug and comments --- artiq/coredevice/phaser.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index 32482d047..bcd83926c 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -203,9 +203,8 @@ class Phaser: att0_rstn=0, att1_rstn=0) delay(.1*ms) # slack - # TODO: crossing dac_clk (125 MHz) edges with sync_dly (2ns long, - # 0-14 ns delay in steps of 2ns) should change the optimal - # fifo_offset by 4 + # crossing dac_clk (reference) edges with sync_dly + # changes the optimal fifo_offset by 4 self.set_sync_dly(self.sync_dly) # 4 wire SPI, sif4_enable @@ -253,7 +252,10 @@ class Phaser: raise ValueError("DAC PLL lock failed, check clocking") if self.tune_fifo_offset: - self.dac_tune_fifo_offset() + fifo_offset = self.dac_tune_fifo_offset() + if debug: + print(fifo_offset) + self.core.break_realtime() # self.dac_write(0x20, 0x0000) # stop fifo sync # alarm = self.get_sta() & 1 From 9214e0f3e25dc8f0036970213acf90ee0cc56fb5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 2 Oct 2020 20:35:29 +0800 Subject: [PATCH 2361/2457] firmware: fix Si5324 CKIN selection on Kasli 2.0 https://github.com/sinara-hw/Kasli/issues/82#issuecomment-702129805 --- artiq/firmware/runtime/rtio_clocking.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index 0a41ab8d0..63a595358 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -145,15 +145,25 @@ fn setup_si5324_as_synthesizer() { bwsel : 3, crystal_ref: true }; - si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin2).expect("cannot initialize Si5324"); + #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0", not(si5324_ext_ref)))] + let si5324_ref_input = si5324::Input::Ckin2; + #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0", si5324_ext_ref))] + let si5324_ref_input = si5324::Input::Ckin1; + #[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] + let si5324_ref_input = si5324::Input::Ckin2; + si5324::setup(&SI5324_SETTINGS, si5324_ref_input).expect("cannot initialize Si5324"); } pub fn init() { #[cfg(si5324_as_synthesizer)] { + #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] + let si5324_ext_input = si5324::Input::Ckin1; + #[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] + let si5324_ext_input = si5324::Input::Ckin2; match get_rtio_clock_cfg() { RtioClock::Internal => setup_si5324_as_synthesizer(), - RtioClock::External => si5324::bypass(si5324::Input::Ckin2).expect("cannot bypass Si5324") + RtioClock::External => si5324::bypass(si5324_ext_input).expect("cannot bypass Si5324") } } From 88d346fa26fd29646ab28f678dda8e24c8d6ceaa Mon Sep 17 00:00:00 2001 From: pca006132 Date: Tue, 6 Oct 2020 15:19:45 +0800 Subject: [PATCH 2362/2457] fixes with statement with multiple items Closes #1478 --- artiq/compiler/transforms/artiq_ir_generator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 5c5f00139..d537908f5 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -883,8 +883,8 @@ class ARTIQIRGenerator(algorithm.Visitor): self.current_assign = None none = self.append(ir.Alloc([], builtins.TNone())) - cleanup.append(lambda: - self._user_call(exit_fn, [none, none, none], {})) + call = self._user_call(exit_fn, [none, none, none], {}) + cleanup.append(lambda: call) self._try_finally( body_gen=lambda: self.visit(node.body), From 02f46e8b796607bf9953412603142ebd20bf8afa Mon Sep 17 00:00:00 2001 From: pca006132 Date: Tue, 6 Oct 2020 14:55:02 +0800 Subject: [PATCH 2363/2457] Fixes none to bool coercion Fixes #1413 and #1414. --- artiq/compiler/transforms/artiq_ir_generator.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index d537908f5..dcfc8998f 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -417,6 +417,8 @@ class ARTIQIRGenerator(algorithm.Visitor): length = self.iterable_len(insn) return self.append(ir.Compare(ast.NotEq(loc=None), length, ir.Constant(0, length.type)), block=block) + elif builtins.is_none(insn.type): + return ir.Constant(False, builtins.TBool()) else: note = diagnostic.Diagnostic("note", "this expression has type {type}", From fe6115bcbbeb3caca596b904231851e24c18afb1 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Wed, 7 Oct 2020 18:59:35 +0800 Subject: [PATCH 2364/2457] compiler: fix incorrect with behavior --- artiq/compiler/transforms/artiq_ir_generator.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index dcfc8998f..1ce7c4005 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -885,8 +885,7 @@ class ARTIQIRGenerator(algorithm.Visitor): self.current_assign = None none = self.append(ir.Alloc([], builtins.TNone())) - call = self._user_call(exit_fn, [none, none, none], {}) - cleanup.append(lambda: call) + cleanup.append(lambda fn=exit_fn: self._user_call(fn, [none, none, none], {})) self._try_finally( body_gen=lambda: self.visit(node.body), From 6baf3b21989fcbef04719f6f4083fd3945f06eff Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Oct 2020 19:24:34 +0800 Subject: [PATCH 2365/2457] RELEASE_NOTES: fix indentation --- RELEASE_NOTES.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index e38441707..318759e30 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -9,9 +9,9 @@ ARTIQ-6 Highlights: * Performance improvements: - - #1432: SERDES TTL inputs can now detect edges on pulses that are shorter - than the RTIO period - - Improved performance for kernel RPC involving list and array. + - #1432: SERDES TTL inputs can now detect edges on pulses that are shorter + than the RTIO period + - Improved performance for kernel RPC involving list and array. * Coredevice SI to mu conversions now always return valid codes, or raise a `ValueError`. * Zotino now exposes `voltage_to_mu()` * `ad9910`: The maximum amplitude scale factor is now `0x3fff` (was `0x3ffe` From 66401aee9cf61967f4621662faf305764017acd2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Oct 2020 19:24:54 +0800 Subject: [PATCH 2366/2457] dashboard: cleanup import --- artiq/frontend/artiq_dashboard.py | 1 - 1 file changed, 1 deletion(-) diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index ace7e4eb2..66e79269c 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -15,7 +15,6 @@ from sipyco.broadcast import Receiver from sipyco import common_args from sipyco.asyncio_tools import atexit_register_coroutine -from artiq import __version__ as artiq_version from artiq import __artiq_dir__ as artiq_dir, __version__ as artiq_version from artiq.tools import get_user_config_dir from artiq.gui.models import ModelSubscriber From 1bfe977203c65dcaf1e1ba3849bca7655cbf3700 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 7 Oct 2020 19:25:26 +0800 Subject: [PATCH 2367/2457] manual: sphinx mock module whack-a-mole --- doc/manual/conf.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/manual/conf.py b/doc/manual/conf.py index 266426c78..13c1b7394 100644 --- a/doc/manual/conf.py +++ b/doc/manual/conf.py @@ -30,12 +30,19 @@ autodoc.repr = inspect.repr = str # we cannot use autodoc_mock_imports (does not help with argparse) mock_modules = ["artiq.gui.waitingspinnerwidget", "artiq.gui.flowlayout", + "artiq.gui.state", + "artiq.gui.log", + "artiq.gui.models", "artiq.compiler.module", "artiq.compiler.embedding", + "artiq.dashboard", "quamash", "pyqtgraph", "matplotlib", "numpy", "dateutil", "dateutil.parser", "prettytable", "PyQt5", "h5py", "serial", "scipy", "scipy.interpolate", - "llvmlite_artiq", "Levenshtein", "pythonparser", "sipyco"] + "llvmlite_artiq", "Levenshtein", "pythonparser", + "sipyco", "sipyco.pc_rpc", "sipyco.sync_struct", + "sipyco.asyncio_tools", "sipyco.logging_tools", + "sipyco.broadcast", "sipyco.packed_exceptions"] for module in mock_modules: sys.modules[module] = Mock() From 7c2519c912b95ebecab112e4da78489107dbbf0b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Oct 2020 09:18:46 +0800 Subject: [PATCH 2368/2457] manual: nixpkgs 20.09 --- doc/manual/installing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index d4f702487..c1184f168 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -23,10 +23,10 @@ Once Nix is installed, add the M-Labs package channel with: :: $ nix-channel --add https://nixbld.m-labs.hk/channel/custom/artiq/full-beta/artiq-full -Those channels track `nixpkgs 20.03 `_. You can check the latest status through the `Hydra interface `_. As the Nix package manager default installation uses the development version of nixpkgs, we need to tell it to switch to the release: :: +Those channels track `nixpkgs 20.09 `_. You can check the latest status through the `Hydra interface `_. As the Nix package manager default installation uses the development version of nixpkgs, we need to tell it to switch to the release: :: $ nix-channel --remove nixpkgs - $ nix-channel --add https://nixos.org/channels/nixos-20.03 nixpkgs + $ nix-channel --add https://nixos.org/channels/nixos-20.09 nixpkgs Finally, make all the channel changes effective: :: From ebb7ccbfd196c6191985f00c7caaab2c2a9be5bf Mon Sep 17 00:00:00 2001 From: hartytp Date: Mon, 5 Oct 2020 18:15:35 +0100 Subject: [PATCH 2369/2457] wrpll: document DDMTD collector and fix unwrapping --- artiq/gateware/drtio/wrpll/ddmtd.py | 193 ++++++++++++++++++++++------ 1 file changed, 156 insertions(+), 37 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index 58002779d..48ca5966f 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -130,61 +130,180 @@ class DDMTD(Module, AutoCSR): class Collector(Module): - def __init__(self, N): - self.tag_helper = Signal((N, True)) - self.tag_helper_update = Signal() - self.tag_main = Signal((N, True)) - self.tag_main_update = Signal() + """ Generates loop filter inputs from DDMTD outputs. - self.output = Signal((N + 1, True)) + When the WR PLL is locked, the following ideally (no noise etc) obtain: + - f_main = f_ref + - f_helper = f_ref * (2^N-1) / 2^N + - f_beat = f_ref - f_helper = f_ref / 2^N (cycle time is: dt=1/f_beat) + - the reference and main DCXO tags are equal each cycle + - the reference and main DCXO tags decrease by 1 each cycle (the tag + difference is f_helper*dt = f_helper/f_beat = (2^N-1) so we are 1 tag + away from a complete wrap around of the N-bit DDMTD counter) + + Since the main and reference tags cycle through all possible values when + locked, we need to unwrap the collector outputs to avoid glitches + (particularly noise around transitions). Currently we do this in hardware, + but we should consider extending the processor to allow us to do it + inside the filters at a later stage (at which point, the collector + essentially becomes a the trigger for the loop filters). + + The input to the main DCXO lock loop filter is the difference between the + reference and main tags after phase unwrapping. + + The input to the helper DCXO lock loop filter is the difference between the + current reference tag and the previous reference tag plus 1, after + phase unwrapping. + """ + def __init__(self, N): + self.ref_stb = Signal() + self.main_stb = Signal() + self.tag_ref = Signal(N) + self.tag_main = Signal(N) + + self.out_stb = Signal() + self.out_main = Signal((N+2, True)) + self.out_helper = Signal((N+2, True)) + self.out_tag_ref = Signal(N) + self.out_tag_main = Signal(N) + + tag_ref_r = Signal(N) + tag_main_r = Signal(N) + main_tag_diff = Signal((N+2, True)) + helper_tag_diff = Signal((N+2, True)) # # # fsm = FSM(reset_state="IDLE") self.submodules += fsm - tag_collector = Signal((N + 1, True)) fsm.act("IDLE", - If(self.tag_main_update & self.tag_helper_update, - NextValue(tag_collector, 0), - NextState("UPDATE") - ).Elif(self.tag_main_update, - NextValue(tag_collector, self.tag_main), - NextState("WAITHELPER") - ).Elif(self.tag_helper_update, - NextValue(tag_collector, -self.tag_helper), + NextValue(self.out_stb, 0), + If(self.ref_stb & self.main_stb, + NextValue(tag_ref_r, self.tag_ref), + NextValue(tag_main_r, self.tag_main), + NextState("DIFF") + ).Elif(self.ref_stb, + NextValue(tag_ref_r, self.tag_ref), NextState("WAITMAIN") + ).Elif(self.main_stb, + NextValue(tag_main_r, self.tag_main), + NextState("WAITREF") ) ) - fsm.act("WAITHELPER", - If(self.tag_helper_update, - NextValue(tag_collector, tag_collector - self.tag_helper), - NextState("LEADCHECK") + fsm.act("WAITREF", + If(self.ref_stb, + NextValue(tag_ref_r, self.tag_ref), + NextState("DIFF") ) ) fsm.act("WAITMAIN", - If(self.tag_main_update, - NextValue(tag_collector, tag_collector + self.tag_main), - NextState("LAGCHECK") + If(self.main_stb, + NextValue(tag_main_r, self.tag_main), + NextState("DIFF") ) ) - # To compensate DDMTD counter roll-over when main is ahead of roll-over - # and helper is after roll-over - fsm.act("LEADCHECK", - If(tag_collector > 0, - NextValue(tag_collector, tag_collector - (2**N - 1)) - ), - NextState("UPDATE") + fsm.act("DIFF", + NextValue(main_tag_diff, tag_main_r - tag_ref_r), + NextValue(helper_tag_diff, tag_ref_r - self.out_tag_ref + 1), + NextState("UNWRAP") ) - # To compensate DDMTD counter roll-over when helper is ahead of roll-over - # and main is after roll-over - fsm.act("LAGCHECK", - If(tag_collector < 0, - NextValue(tag_collector, tag_collector + (2**N - 1)) + fsm.act("UNWRAP", + If(main_tag_diff - self.out_main > 2**(N-1), + NextValue(main_tag_diff, main_tag_diff - 2**N) + ).Elif(self.out_main - main_tag_diff > 2**(N-1), + NextValue(main_tag_diff, main_tag_diff + 2**N) ), - NextState("UPDATE") + + If(helper_tag_diff - self.out_helper > 2**(N-1), + NextValue(helper_tag_diff, helper_tag_diff - 2**N) + ).Elif(self.out_helper - helper_tag_diff > 2**(N-1), + NextValue(helper_tag_diff, helper_tag_diff + 2**N) + ), + + NextState("OUTPUT") ) - fsm.act("UPDATE", - NextValue(self.output, tag_collector), + fsm.act("OUTPUT", + NextValue(self.out_tag_ref, tag_ref_r), + NextValue(self.out_tag_main, tag_main_r), + NextValue(self.out_main, main_tag_diff), + NextValue(self.out_helper, helper_tag_diff), + NextValue(self.out_stb, 1), NextState("IDLE") ) + + +def test_collector_main(): + + N = 2 + collector = Collector(N=N) + # check collector phase unwrapping + tags = [(0, 0, 0), + (0, 1, 1), + (2, 1, -1), + (3, 1, -2), + (0, 1, -3), + (1, 1, -4), + (2, 1, -5), + (3, 1, -6), + (3, 3, -4), + (0, 0, -4), + (0, 1, -3), + (0, 2, -2), + (0, 3, -1), + (0, 0, 0)] + for i in range(10): + tags.append((i % (2**N), (i+1) % (2**N), 1)) + + def generator(): + for tag_ref, tag_main, out in tags: + yield collector.tag_ref.eq(tag_ref) + yield collector.tag_main.eq(tag_main) + yield collector.main_stb.eq(1) + yield collector.ref_stb.eq(1) + + yield + + yield collector.main_stb.eq(0) + yield collector.ref_stb.eq(0) + + while not (yield collector.out_stb): + yield + + out_main = yield collector.out_main + assert out_main == out + + run_simulation(collector, generator()) + + +def test_collector_helper(): + + N = 3 + collector = Collector(N=N) + # check collector phase unwrapping + tags = [((2**N - 1 - tag) % (2**N), 0) for tag in range(20)] + tags += [((tags[-1][0] + 1 + tag) % (2**N), 2) for tag in range(20)] + tags += [((tags[-1][0] - 2 - 2*tag) % (2**N), -1) for tag in range(20)] + + def generator(): + for tag_ref, out in tags: + yield collector.tag_ref.eq(tag_ref) + yield collector.main_stb.eq(1) + yield collector.ref_stb.eq(1) + + yield + + yield collector.main_stb.eq(0) + yield collector.ref_stb.eq(0) + + while not (yield collector.out_stb): + yield + + out_helper = yield collector.out_helper + assert out_helper == out + + run_simulation(collector, generator()) + +if __name__ == "__main__": + test_collector_main() + test_collector_helper() From 17c952b8fb3e0736e9766388bb052288fbcc82e2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Oct 2020 15:00:49 +0800 Subject: [PATCH 2370/2457] wrpll: style --- artiq/gateware/drtio/wrpll/ddmtd.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index 48ca5966f..512638d8c 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -130,7 +130,7 @@ class DDMTD(Module, AutoCSR): class Collector(Module): - """ Generates loop filter inputs from DDMTD outputs. + """Generates loop filter inputs from DDMTD outputs. When the WR PLL is locked, the following ideally (no noise etc) obtain: - f_main = f_ref @@ -234,7 +234,6 @@ class Collector(Module): def test_collector_main(): - N = 2 collector = Collector(N=N) # check collector phase unwrapping @@ -277,7 +276,6 @@ def test_collector_main(): def test_collector_helper(): - N = 3 collector = Collector(N=N) # check collector phase unwrapping @@ -304,6 +302,7 @@ def test_collector_helper(): run_simulation(collector, generator()) + if __name__ == "__main__": test_collector_main() test_collector_helper() From e9ab434fa7824e8957943be764af6257b2dd6bb9 Mon Sep 17 00:00:00 2001 From: hartytp Date: Mon, 5 Oct 2020 20:59:27 +0100 Subject: [PATCH 2371/2457] wrpll.core: update for modified collector --- artiq/gateware/drtio/wrpll/core.py | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 793219043..e079d503d 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -76,32 +76,28 @@ class WRPLL(Module, AutoCSR): ddmtd_counter = Signal(N) self.sync.helper += ddmtd_counter.eq(ddmtd_counter + 1) - self.submodules.ddmtd_helper = DDMTD(ddmtd_counter, ddmtd_inputs.rec_clk) + self.submodules.ddmtd_ref = DDMTD(ddmtd_counter, ddmtd_inputs.rec_clk) self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_inputs.main_xo) - collector_update = Signal() - self.sync.helper += collector_update.eq(ddmtd_counter == (2**N - 1)) - filter_cd = ClockDomainsRenamer("filter") self.submodules.collector = filter_cd(Collector(N)) - self.submodules.filter_helper = filter_cd(thls.make(filters.helper, data_width=48)) - self.submodules.filter_main = filter_cd(thls.make(filters.main, data_width=48)) + self.submodules.filter_helper = filter_cd( + thls.make(filters.helper, data_width=48)) + self.submodules.filter_main = filter_cd( + thls.make(filters.main, data_width=48)) self.comb += [ - self.collector.tag_helper.eq(self.ddmtd_helper.h_tag), - self.collector.tag_helper_update.eq(self.ddmtd_helper.h_tag_update), + self.collector.tag_ref.eq(self.ddmtd_ref.h_tag), + self.collector.ref_stb.eq(self.ddmtd_ref.h_tag_update), self.collector.tag_main.eq(self.ddmtd_main.h_tag), - self.collector.tag_main_update.eq(self.ddmtd_main.h_tag_update) + self.collector.main_stb.eq(self.ddmtd_main.h_tag_update) ] - # compensate the 1 cycle latency of the collector - self.sync.helper += [ - self.filter_helper.input.eq(self.ddmtd_helper.h_tag), - self.filter_helper.input_stb.eq(self.ddmtd_helper.h_tag_update) - ] self.comb += [ - self.filter_main.input.eq(self.collector.output), - self.filter_main.input_stb.eq(collector_update) + self.filter_helper.input.eq(self.collector.out_helper), + self.filter_helper.input_stb.eq(self.collector.out_stb), + self.filter_main.input.eq(self.collector.out_main), + self.filter_main.input_stb.eq(self.collector.out_stb) ] self.sync.helper += [ From b44b8704525a188e0f4446aa22a1502a400dc00a Mon Sep 17 00:00:00 2001 From: hartytp Date: Mon, 5 Oct 2020 22:52:49 +0100 Subject: [PATCH 2372/2457] wrpll.filters: update to match Weida's MatLab simulations --- artiq/gateware/drtio/wrpll/filters.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/filters.py b/artiq/gateware/drtio/wrpll/filters.py index 58b664754..41fb06291 100644 --- a/artiq/gateware/drtio/wrpll/filters.py +++ b/artiq/gateware/drtio/wrpll/filters.py @@ -3,8 +3,7 @@ helper_xn2 = 0 helper_yn0 = 0 helper_yn1 = 0 helper_yn2 = 0 - -previous_helper_tag = 0 +helper_out = 0 main_xn1 = 0 main_xn2 = 0 @@ -13,31 +12,31 @@ main_yn1 = 0 main_yn2 = 0 -def helper(helper_tag): +def helper(tag_diff): global helper_xn1, helper_xn2, helper_yn0, \ - helper_yn1, helper_yn2, previous_helper_tag + helper_yn1, helper_yn2, helper_out - helper_xn0 = helper_tag - previous_helper_tag - 32768 + helper_xn0 = 0 - tag_diff # *(2**22) helper_yr = 4294967296 helper_yn2 = helper_yn1 helper_yn1 = helper_yn0 - helper_yn0 = ( - ((284885689*((217319150*helper_xn0 >> 44) + - (-17591968725107*helper_xn1 >> 44))) >> 44) + - (-35184372088832*helper_yn1 >> 44) - - (17592186044416*helper_yn2 >> 44)) + + helper_yn0 = (284885690 * (helper_xn0 + + (217319150 * helper_xn1 >> 44) + - (17591968725108 * helper_xn2 >> 44) + ) >> 44 + ) + (35184372088832*helper_yn1 >> 44) - helper_yn2 helper_xn2 = helper_xn1 helper_xn1 = helper_xn0 - previous_helper_tag = helper_tag - helper_yn0 = min(helper_yn0, helper_yr) helper_yn0 = max(helper_yn0, 0 - helper_yr) + helper_out = 268435456*helper_yn0 >> 44 - return helper_yn0 + return helper_out def main(main_xn0): From f6f6045f1a55bb9203ff332447657cccd9301d86 Mon Sep 17 00:00:00 2001 From: hartytp Date: Mon, 5 Oct 2020 22:55:20 +0100 Subject: [PATCH 2373/2457] wrpll.thls: fix make --- artiq/gateware/drtio/wrpll/thls.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/thls.py b/artiq/gateware/drtio/wrpll/thls.py index 6d2509c63..f977f2106 100644 --- a/artiq/gateware/drtio/wrpll/thls.py +++ b/artiq/gateware/drtio/wrpll/thls.py @@ -283,7 +283,7 @@ class Scheduler: # Instruction can be scheduled - self.remaining.remove(isn) + self.remaining.remove(isn) for inp, minp in zip(isn.inputs, mapped_inputs): can_free = inp < 0 and all(inp != rinp for risn in self.remaining for rinp in risn.inputs) @@ -354,7 +354,7 @@ def compile(processor, function): assert len(node.args.args) == 1 arg = node.args.args[0].arg body = node.body - + astcompiler = ASTCompiler() for node in body: if isinstance(node, ast.Global): @@ -591,7 +591,7 @@ class ProcessorImpl(Module): def make(function, **kwargs): proc = Processor(**kwargs) - cp = compile(proc, simple_test) + cp = compile(proc, function) cp.dimension_processor() return proc.implement(cp.encode(), cp.data) @@ -605,7 +605,7 @@ def foo(x): c = b b = a a = x - return 4748*a + 259*b - 155*c + return 4748*a + 259*b - 155*c def simple_test(x): From c9ae406ac6c3f7cc2a5a01a6a304fea8b791cd64 Mon Sep 17 00:00:00 2001 From: hartytp Date: Tue, 6 Oct 2020 12:07:28 +0100 Subject: [PATCH 2374/2457] wrpll: change the DDMTD helper frequency to match CERN, improve docs --- artiq/gateware/drtio/wrpll/ddmtd.py | 50 +++++++++++++++++------------ 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index 512638d8c..5466d84e0 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -132,28 +132,37 @@ class DDMTD(Module, AutoCSR): class Collector(Module): """Generates loop filter inputs from DDMTD outputs. - When the WR PLL is locked, the following ideally (no noise etc) obtain: - - f_main = f_ref - - f_helper = f_ref * (2^N-1) / 2^N - - f_beat = f_ref - f_helper = f_ref / 2^N (cycle time is: dt=1/f_beat) - - the reference and main DCXO tags are equal each cycle - - the reference and main DCXO tags decrease by 1 each cycle (the tag - difference is f_helper*dt = f_helper/f_beat = (2^N-1) so we are 1 tag - away from a complete wrap around of the N-bit DDMTD counter) - - Since the main and reference tags cycle through all possible values when - locked, we need to unwrap the collector outputs to avoid glitches - (particularly noise around transitions). Currently we do this in hardware, - but we should consider extending the processor to allow us to do it - inside the filters at a later stage (at which point, the collector - essentially becomes a the trigger for the loop filters). - The input to the main DCXO lock loop filter is the difference between the - reference and main tags after phase unwrapping. + reference and main tags after unwrapping (see below). The input to the helper DCXO lock loop filter is the difference between the - current reference tag and the previous reference tag plus 1, after - phase unwrapping. + current reference tag and the previous reference tag after unwrapping. + + When the WR PLL is locked, the following ideally (no noise/jitter) obtain: + - f_main = f_ref + - f_helper = f_ref * 2^N/(2^N+1) + - f_beat = f_ref - f_helper = f_ref / (2^N + 1) (cycle time is: dt=1/f_beat) + - the reference and main DCXO tags are equal to each other at every cycle + (the main DCXO lock drives this difference to 0) + - the reference and main DCXO tags both have the same value at each cycle + (the tag difference for each DDMTD is given by + f_helper*dt = f_helper/f_beat = 2^N, which causes the N-bit DDMTD counter + to wrap around and come back to its previous value) + + Note that we currently lock the frequency of the helper DCXO to the + reference clock, not it's phase. As a result, while the tag differences are + controlled, their absolute values are arbitrary. We could consider moving + the helper lock to a phase lock at some point in the future... + + Since the DDMTD counter is only N bits, it is possible for tag values to + wrap around. This will happen frequently if the locked tags happens to be + near the edges of the counter, so that jitter can easily cause a phase wrap. + But, it can also easily happen during lock acquisition or other transients. + To avoid glitches in the output, we unwrap the tag differences. Currently + we do this in hardware, but we should consider extending the processor to + allow us to do it inside the filters. Since the processor uses wider + signals, this would significantly extend the overall glitch-free + range of the PLL and may aid lock acquisition. """ def __init__(self, N): self.ref_stb = Signal() @@ -205,7 +214,7 @@ class Collector(Module): ) fsm.act("DIFF", NextValue(main_tag_diff, tag_main_r - tag_ref_r), - NextValue(helper_tag_diff, tag_ref_r - self.out_tag_ref + 1), + NextValue(helper_tag_diff, tag_ref_r - self.out_tag_ref), NextState("UNWRAP") ) fsm.act("UNWRAP", @@ -220,7 +229,6 @@ class Collector(Module): ).Elif(self.out_helper - helper_tag_diff > 2**(N-1), NextValue(helper_tag_diff, helper_tag_diff + 2**N) ), - NextState("OUTPUT") ) fsm.act("OUTPUT", From e5e648bde1349ba41f27bd9d8d4ce65cc78db4cd Mon Sep 17 00:00:00 2001 From: hartytp Date: Thu, 8 Oct 2020 15:16:07 +0800 Subject: [PATCH 2375/2457] wrpll: add bit shift for collector helper output --- artiq/gateware/drtio/wrpll/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index e079d503d..1edcc8915 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -94,7 +94,7 @@ class WRPLL(Module, AutoCSR): ] self.comb += [ - self.filter_helper.input.eq(self.collector.out_helper), + self.filter_helper.input.eq(self.collector.out_helper << 22), self.filter_helper.input_stb.eq(self.collector.out_stb), self.filter_main.input.eq(self.collector.out_main), self.filter_main.input_stb.eq(self.collector.out_stb) From f3cd0fc6756098fb99f954a8a8da46db9c35d0ab Mon Sep 17 00:00:00 2001 From: hartytp Date: Tue, 6 Oct 2020 15:33:18 +0100 Subject: [PATCH 2376/2457] wrpll.filters: the helper clipping threshold is currently way too low. Move clipping after the bitshift to increase a bit. TODO: think about this and pick a sensible threshold (and also think about integrator anti windup) --- artiq/gateware/drtio/wrpll/filters.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/filters.py b/artiq/gateware/drtio/wrpll/filters.py index 41fb06291..470f17bf3 100644 --- a/artiq/gateware/drtio/wrpll/filters.py +++ b/artiq/gateware/drtio/wrpll/filters.py @@ -32,9 +32,9 @@ def helper(tag_diff): helper_xn2 = helper_xn1 helper_xn1 = helper_xn0 - helper_yn0 = min(helper_yn0, helper_yr) - helper_yn0 = max(helper_yn0, 0 - helper_yr) helper_out = 268435456*helper_yn0 >> 44 + helper_out = min(helper_out, helper_yr) + helper_out = max(helper_out, 0 - helper_yr) return helper_out From 85bb64191715ada6fc6f4c8fe22a8cd5530637b9 Mon Sep 17 00:00:00 2001 From: hartytp Date: Tue, 6 Oct 2020 15:42:37 +0100 Subject: [PATCH 2377/2457] wrpll.ddmtd: fix first edge deglitcher The blind counter should be held in reset whenever the input is high, not just when there is a rising edge (otherwise the counter runs down during the main pulse and can then re-trigger on jitter from the falling edge) --- artiq/gateware/drtio/wrpll/ddmtd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index 5466d84e0..0ed3de69f 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -83,7 +83,7 @@ class DDMTDDeglitcherFirstEdge(Module): blind_counter = Signal(max=blind_period) self.sync.helper += [ If(blind_counter != 0, blind_counter.eq(blind_counter - 1)), - If(rising, blind_counter.eq(blind_period - 1)), + If(input_signal_r, blind_counter.eq(blind_period - 1)), self.detect.eq(rising & (blind_counter == 0)) ] From f2f942a8b4eb18a38a87c133181238aa2e91365d Mon Sep 17 00:00:00 2001 From: hartytp Date: Tue, 6 Oct 2020 15:59:05 +0100 Subject: [PATCH 2378/2457] wrpll.ddmtd: remove CSRs from DDMTD We will gather then from the collector output so we can get all tags on the same cycle --- artiq/gateware/drtio/wrpll/ddmtd.py | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index 0ed3de69f..7f13134de 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -88,10 +88,8 @@ class DDMTDDeglitcherFirstEdge(Module): ] -class DDMTD(Module, AutoCSR): +class DDMTD(Module): def __init__(self, counter, input_signal): - self.arm = CSR() - self.tag = CSRStatus(len(counter)) # in helper clock domain self.h_tag = Signal(len(counter)) @@ -110,24 +108,6 @@ class DDMTD(Module, AutoCSR): ) ] - tag_update_ps = PulseSynchronizer("helper", "sys") - self.submodules += tag_update_ps - self.comb += tag_update_ps.i.eq(self.h_tag_update) - tag_update = Signal() - self.sync += tag_update.eq(tag_update_ps.o) - - tag = Signal(len(counter)) - self.h_tag.attr.add("no_retiming") - self.specials += MultiReg(self.h_tag, tag) - - self.sync += [ - If(self.arm.re & self.arm.r, self.arm.w.eq(1)), - If(tag_update, - If(self.arm.w, self.tag.status.eq(tag)), - self.arm.w.eq(0), - ) - ] - class Collector(Module): """Generates loop filter inputs from DDMTD outputs. From 87911810d62cbc21a75451b4898f34e8ee979769 Mon Sep 17 00:00:00 2001 From: hartytp Date: Tue, 6 Oct 2020 16:29:11 +0100 Subject: [PATCH 2379/2457] wrpll.core: add CSRs to monitor the collector outputs --- artiq/gateware/drtio/wrpll/core.py | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 1edcc8915..4ce964a2a 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -8,6 +8,13 @@ from artiq.gateware.drtio.wrpll.ddmtd import DDMTD, Collector from artiq.gateware.drtio.wrpll import thls, filters +def _eq_sign_extend(t, s): + """Assign target signal `t` from source `s`, sign-extending `s` to the + full width. + """ + return t.eq(Cat(s, Replicate(s[-1], len(t) - len(s)))) + + class FrequencyCounter(Module, AutoCSR): def __init__(self, timer_width=23, counter_width=23, domains=["helper", "rtio", "rtio_rx0"]): for domain in domains: @@ -55,6 +62,12 @@ class WRPLL(Module, AutoCSR): self.adpll_offset_helper = CSRStorage(24) self.adpll_offset_main = CSRStorage(24) + self.tag_arm = CSR() + self.main_diff_tag = CSRStatus(32) + self.helper_diff_tag = CSRStatus(32) + self.ref_tag = CSRStatus(N) + self.main_tag = CSRStatus(N) + self.clock_domains.cd_helper = ClockDomain() self.clock_domains.cd_filter = ClockDomain() self.helper_reset.storage.attr.add("no_retiming") @@ -93,6 +106,34 @@ class WRPLL(Module, AutoCSR): self.collector.main_stb.eq(self.ddmtd_main.h_tag_update) ] + collector_stb_ps = PulseSynchronizer("helper", "sys") + self.submodules += collector_stb_ps + self.sync.helper += collector_stb_ps.i.eq(self.collector.out_stb) + collector_stb_sys = Signal() + self.sync += collector_stb_sys.eq(collector_stb_ps.o) + + main_diff_tag_sys = Signal((N+2, True)) + helper_diff_tag_sys = Signal((N+2, True)) + ref_tag_sys = Signal(N) + main_tag_sys = Signal(N) + self.specials += MultiReg(self.collector.out_main, main_diff_tag_sys) + self.specials += MultiReg(self.collector.out_helper, helper_diff_tag_sys) + self.specials += MultiReg(self.collector.tag_ref, ref_tag_sys) + self.specials += MultiReg(self.collector.tag_main, main_tag_sys) + + self.sync += [ + If(self.tag_arm.re & self.tag_arm.r, self.tag_arm.w.eq(1)), + If(collector_stb_sys, + self.tag_arm.w.eq(0), + If(self.tag_arm.w, + _eq_sign_extend(self.main_diff_tag.status, main_diff_tag_sys), + _eq_sign_extend(self.helper_diff_tag.status, helper_diff_tag_sys), + self.ref_tag.status.eq(ref_tag_sys), + self.main_tag.status.eq(main_tag_sys) + ) + ) + ] + self.comb += [ self.filter_helper.input.eq(self.collector.out_helper << 22), self.filter_helper.input_stb.eq(self.collector.out_stb), From 3fa5d0b963c6748fb68e2e4025ddd9bd2230ccba Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Oct 2020 15:28:16 +0800 Subject: [PATCH 2380/2457] wrpll: clean up sign extension --- artiq/gateware/drtio/wrpll/core.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 4ce964a2a..4aa57ce9c 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -8,13 +8,6 @@ from artiq.gateware.drtio.wrpll.ddmtd import DDMTD, Collector from artiq.gateware.drtio.wrpll import thls, filters -def _eq_sign_extend(t, s): - """Assign target signal `t` from source `s`, sign-extending `s` to the - full width. - """ - return t.eq(Cat(s, Replicate(s[-1], len(t) - len(s)))) - - class FrequencyCounter(Module, AutoCSR): def __init__(self, timer_width=23, counter_width=23, domains=["helper", "rtio", "rtio_rx0"]): for domain in domains: @@ -68,6 +61,13 @@ class WRPLL(Module, AutoCSR): self.ref_tag = CSRStatus(N) self.main_tag = CSRStatus(N) + main_diff_tag_32 = Signal((32, True)) + helper_diff_tag_32 = Signal((32, True)) + self.comb += [ + self.main_diff_tag.status.eq(main_diff_tag_32), + self.helper_diff_tag.status.eq(helper_diff_tag_32) + ] + self.clock_domains.cd_helper = ClockDomain() self.clock_domains.cd_filter = ClockDomain() self.helper_reset.storage.attr.add("no_retiming") @@ -126,8 +126,8 @@ class WRPLL(Module, AutoCSR): If(collector_stb_sys, self.tag_arm.w.eq(0), If(self.tag_arm.w, - _eq_sign_extend(self.main_diff_tag.status, main_diff_tag_sys), - _eq_sign_extend(self.helper_diff_tag.status, helper_diff_tag_sys), + main_diff_tag_32.eq(main_diff_tag_sys), + helper_diff_tag_32.eq(helper_diff_tag_sys), self.ref_tag.status.eq(ref_tag_sys), self.main_tag.status.eq(main_tag_sys) ) From 7d7be6e71140636482ca8611f4cf06044329e00b Mon Sep 17 00:00:00 2001 From: hartytp Date: Tue, 6 Oct 2020 16:32:16 +0100 Subject: [PATCH 2381/2457] wrpll.core: move collector into helper CD so we can get tags out while the filters are reset --- artiq/gateware/drtio/wrpll/core.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 4aa57ce9c..0d222768b 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -93,7 +93,8 @@ class WRPLL(Module, AutoCSR): self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_inputs.main_xo) filter_cd = ClockDomainsRenamer("filter") - self.submodules.collector = filter_cd(Collector(N)) + helper_cd = ClockDomainsRenamer("helper") + self.submodules.collector = helper_cd(Collector(N)) self.submodules.filter_helper = filter_cd( thls.make(filters.helper, data_width=48)) self.submodules.filter_main = filter_cd( From e6ff2ddc32ed74f3eaecc59eb54e61e8ec00cd72 Mon Sep 17 00:00:00 2001 From: hartytp Date: Tue, 6 Oct 2020 17:21:39 +0100 Subject: [PATCH 2382/2457] wrpll: add more diagnostics in firmware and adapt to recent gateware changes --- artiq/firmware/libboard_artiq/wrpll.rs | 132 ++++++++++++++++++------- 1 file changed, 96 insertions(+), 36 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index 123e70c47..e31b46ca2 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -266,6 +266,9 @@ mod si549 { Ok(()) } + // Si549 digital frequency trim ("all-digital PLL" register) + // ∆ f_out = adpll * 0.0001164e-6 (0.1164 ppb/lsb) + // max trim range is +- 950 ppm pub fn set_adpll(dcxo: i2c::Dcxo, adpll: i32) -> Result<(), &'static str> { write(dcxo, 231, adpll as u8)?; write(dcxo, 232, (adpll >> 8) as u8)?; @@ -282,6 +285,20 @@ mod si549 { } } +// to do: load from gateware config +const DDMTD_COUNTER_N: u32 = 15; +const DDMTD_COUNTER_M: u32 = (1 << DDMTD_COUNTER_N); +const F_SYS: f64 = csr::CONFIG_CLOCK_FREQUENCY as f64; + +const F_MAIN: f64 = 125.0e6; +const F_HELPER: f64 = F_MAIN * DDMTD_COUNTER_M as f64 / (DDMTD_COUNTER_M + 1) as f64; +const F_BEAT: f64 = F_MAIN - F_HELPER; +const TIME_STEP: f32 = 1./F_BEAT as f32; + +fn ddmtd_tag_to_s(mu: f32) -> f32 { + return (mu as f32)*TIME_STEP; +} + fn get_frequencies() -> (u32, u32, u32) { unsafe { csr::wrpll::frequency_counter_update_en_write(1); @@ -304,24 +321,58 @@ fn log_frequencies() -> (u32, u32, u32) { (f_helper, f_main, f_cdr) } -fn get_ddmtd_main_tag() -> u16 { +fn get_tags() -> (i32, i32, u16, u16) { unsafe { - csr::wrpll::ddmtd_main_arm_write(1); - while csr::wrpll::ddmtd_main_arm_read() != 0 {} - csr::wrpll::ddmtd_main_tag_read() + csr::wrpll::tag_arm_write(1); + while csr::wrpll::tag_arm_read() != 0 {} + + let main_diff = csr::wrpll::main_diff_tag_read() as i32; + let helper_diff = csr::wrpll::helper_diff_tag_read() as i32; + let ref_tag = csr::wrpll::ref_tag_read(); + let main_tag = csr::wrpll::main_tag_read(); + (main_diff, helper_diff, ref_tag, main_tag) } } -fn get_ddmtd_helper_tag() -> u16 { - unsafe { - csr::wrpll::ddmtd_helper_arm_write(1); - while csr::wrpll::ddmtd_helper_arm_read() != 0 {} - csr::wrpll::ddmtd_helper_tag_read() +fn print_tags() { + const NUM_TAGS: usize = 30; + let mut main_diffs = [0; NUM_TAGS]; // input to main loop filter + let mut helper_diffs = [0; NUM_TAGS]; // input to helper loop filter + let mut ref_tags = [0; NUM_TAGS]; + let mut main_tags = [0; NUM_TAGS]; + let mut jitter = [0 as f32; NUM_TAGS]; + + for i in 0..NUM_TAGS { + let (main_diff, helper_diff, ref_tag, main_tag) = get_tags(); + main_diffs[i] = main_diff; + helper_diffs[i] = helper_diff; + ref_tags[i] = ref_tag; + main_tags[i] = main_tag; } + info!("DDMTD ref tags: {:?}", ref_tags); + info!("DDMTD main tags: {:?}", main_tags); + info!("DDMTD main diffs: {:?}", main_diffs); + info!("DDMTD helper diffs: {:?}", helper_diffs); + + // look at the difference between the main DCXO and reference... + let t0 = main_diffs[0]; + main_diffs.iter_mut().for_each(|x| *x -= t0); + + // crude estimate of the max difference across our sample set (assumes no unwrapping issues...) + let delta = main_diffs[main_diffs.len()-1] as f32 / (main_diffs.len()-1) as f32; + info!("detla: {:?} tags", delta); + let delta_f: f32 = delta/DDMTD_COUNTER_M as f32 * F_BEAT as f32; + info!("MAIN <-> ref frequency difference: {:?} Hz ({:?} ppm)", delta_f, delta_f/F_HELPER as f32 * 1e6); + + jitter.iter_mut().enumerate().for_each(|(i, x)| *x = main_diffs[i] as f32 - delta*(i as f32)); + info!("jitter: {:?} tags", jitter); + + let var = jitter.iter().map(|x| x*x).fold(0 as f32, |acc, x| acc + x as f32) / NUM_TAGS as f32; + info!("variance: {:?} tags^2", var); } pub fn init() { - info!("initializing..."); + info!("initializing WR PLL..."); unsafe { csr::wrpll::helper_reset_write(1); } @@ -348,43 +399,29 @@ pub fn init() { } pub fn diagnostics() { + info!("WRPLL diagnostics..."); + info!("Untrimmed oscillator frequencies:"); log_frequencies(); - info!("ADPLL test:"); - // +/-10ppm - si549::set_adpll(i2c::Dcxo::Helper, -85911).expect("ADPLL write failed"); - si549::set_adpll(i2c::Dcxo::Main, 85911).expect("ADPLL write failed"); + info!("Increase helper DCXO frequency by +10ppm (1.25kHz):"); + si549::set_adpll(i2c::Dcxo::Helper, 85911).expect("ADPLL write failed"); + // to do: add check on frequency? log_frequencies(); - si549::set_adpll(i2c::Dcxo::Helper, 0).expect("ADPLL write failed"); - si549::set_adpll(i2c::Dcxo::Main, 0).expect("ADPLL write failed"); - - let mut tags = [0; 10]; - for i in 0..tags.len() { - tags[i] = get_ddmtd_main_tag(); - } - info!("DDMTD main tags: {:?}", tags); } fn trim_dcxos(f_helper: u32, f_main: u32, f_cdr: u32) -> Result<(i32, i32), &'static str> { + info!("Trimming oscillator frequencies..."); const DCXO_STEP: i64 = (1.0e6/0.0001164) as i64; const ADPLL_MAX: i64 = (950.0/0.0001164) as i64; const TIMER_WIDTH: u32 = 23; const COUNTER_DIV: u32 = 2; - const F_SYS: f64 = csr::CONFIG_CLOCK_FREQUENCY as f64; - #[cfg(rtio_frequency = "125.0")] - const F_MAIN: f64 = 125.0e6; - const F_HELPER: f64 = F_MAIN * ((1 << 15) as f64)/((1<<15) as f64 + 1.0); - + // how many counts we expect to measure const SYS_COUNTS: i64 = (1 << (TIMER_WIDTH - COUNTER_DIV)) as i64; const EXP_MAIN_COUNTS: i64 = ((SYS_COUNTS as f64) * (F_MAIN/F_SYS)) as i64; const EXP_HELPER_COUNTS: i64 = ((SYS_COUNTS as f64) * (F_HELPER/F_SYS)) as i64; - info!("after {} sys counts", SYS_COUNTS); - info!("expect {} main/CDR counts", EXP_MAIN_COUNTS); - info!("expect {} helper counts", EXP_HELPER_COUNTS); - // calibrate the SYS clock to the CDR clock and correct the measured counts // assume frequency errors are small so we can make an additive correction // positive error means sys clock is too fast @@ -412,13 +449,35 @@ fn trim_dcxos(f_helper: u32, f_main: u32, f_cdr: u32) -> Result<(i32, i32), &'st Ok((helper_adpll as i32, main_adpll as i32)) } +fn statistics(data: &[u16]) -> (f32, f32) { + let sum = data.iter().fold(0 as u32, |acc, x| acc + *x as u32); + let mean = sum as f32 / data.len() as f32; + + let squared_sum = data.iter().fold(0 as u32, |acc, x| acc + (*x as u32).pow(2)); + let variance = (squared_sum as f32 / data.len() as f32) - mean; + return (mean, variance) +} + fn select_recovered_clock_int(rc: bool) -> Result<(), &'static str> { + info!("Untrimmed oscillator frequencies:"); let (f_helper, f_main, f_cdr) = log_frequencies(); if rc { let (helper_adpll, main_adpll) = trim_dcxos(f_helper, f_main, f_cdr)?; + // to do: add assertion on max frequency shift here? si549::set_adpll(i2c::Dcxo::Helper, helper_adpll).expect("ADPLL write failed"); si549::set_adpll(i2c::Dcxo::Main, main_adpll).expect("ADPLL write failed"); + log_frequencies(); + clock::spin_us(100_000); // TO DO: remove/reduce! + print_tags(); + + info!("increasing main DCXO by 1ppm (125Hz):"); + si549::set_adpll(i2c::Dcxo::Main, main_adpll + 8591).expect("ADPLL write failed"); + clock::spin_us(100_000); + print_tags(); + + si549::set_adpll(i2c::Dcxo::Main, main_adpll).expect("ADPLL write failed"); + unsafe { csr::wrpll::adpll_offset_helper_write(helper_adpll as u32); csr::wrpll::adpll_offset_main_write(main_adpll as u32); @@ -431,11 +490,12 @@ fn select_recovered_clock_int(rc: bool) -> Result<(), &'static str> { clock::spin_us(100_000); - let mut tags = [0; 10]; - for i in 0..tags.len() { - tags[i] = get_ddmtd_helper_tag(); - } - info!("DDMTD helper tags: {:?}", tags); + print_tags(); +// let mut tags = [0; 10]; +// for i in 0..tags.len() { +// tags[i] = get_ddmtd_helper_tag(); +// } +// info!("DDMTD helper tags: {:?}", tags); unsafe { csr::wrpll::filter_reset_write(1); From d780faf4ac324311b5c4b00ad8f469bbb4fa77c4 Mon Sep 17 00:00:00 2001 From: hartytp Date: Wed, 7 Oct 2020 10:11:25 +0100 Subject: [PATCH 2383/2457] wrpll.si549: initialize the clock divider to a sensible value --- artiq/gateware/drtio/wrpll/si549.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/wrpll/si549.py b/artiq/gateware/drtio/wrpll/si549.py index 6f840854c..46ce0c138 100644 --- a/artiq/gateware/drtio/wrpll/si549.py +++ b/artiq/gateware/drtio/wrpll/si549.py @@ -255,7 +255,7 @@ class Si549(Module, AutoCSR): self.gpio_out = CSRStorage(2) self.gpio_oe = CSRStorage(2) - self.i2c_divider = CSRStorage(16, reset=2500) + self.i2c_divider = CSRStorage(16, reset=75) self.i2c_address = CSRStorage(7) self.errors = CSR(2) From cd8c2ce713f6af7324dda0822fe228dfdded10a8 Mon Sep 17 00:00:00 2001 From: hartytp Date: Thu, 8 Oct 2020 15:36:21 +0800 Subject: [PATCH 2384/2457] wrpll: add test to compare collector+filter against Matlab simulation --- artiq/gateware/drtio/wrpll/core.py | 87 ++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 0d222768b..63f1928eb 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -1,3 +1,5 @@ +import numpy as np + from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.cdc import MultiReg, PulseSynchronizer @@ -148,3 +150,88 @@ class WRPLL(Module, AutoCSR): self.main_dcxo.adpll_stb.eq(self.filter_main.output_stb), self.main_dcxo.adpll.eq(self.filter_main.output + self.adpll_offset_main.storage) ] + + +def helper_sim(N=15): + class WRPLL(Module): + def __init__(self, N): + self.tag_ref = Signal(N) + self.input_stb = Signal() + self.adpll = Signal((24, True)) + self.out_stb = Signal() + + # # # # + loop_filter = thls.make(filters.helper, data_width=48) + self.submodules.loop_filter = loop_filter + self.submodules.collector = collector = Collector(N) + + self.comb += [ + self.collector.tag_ref.eq(self.tag_ref), + self.collector.ref_stb.eq(self.input_stb), + self.collector.main_stb.eq(self.input_stb), + self.loop_filter.input.eq(self.collector.out_helper << 22), + self.loop_filter.input_stb.eq(self.collector.out_stb), + self.adpll.eq(self.loop_filter.output), + self.out_stb.eq(self.loop_filter.output_stb), + ] + pll = WRPLL(N=N) + + # check filter against output from MatLab model + initial_helper_out = -8000 + ref_tags = np.array([ + 24778, 16789, 8801, 814, 25596, 17612, 9628, 1646, + 26433, 18453, 10474, 2496, 27287, 19311, 11337, 3364, 28160, + 20190, 12221, 4253, 29054, 21088, 13124, 5161, 29966, 22005, + 14045, 6087, 30897, 22940, 14985, 7031, 31847, 23895, 15944, + 7995, 47, 24869, 16923, 8978, 1035, 25861, 17920, 9981, + 2042, 26873, 18937, 11002, 3069, 27904, 19973, 12042, 4113, + 28953, 21026, 13100, 5175, 30020, 22098, 14177, 6257, 31106, + 23189, 15273, 7358, 32212, 24300, 16388, 8478, 569, 25429, + 17522, 9617, 1712, 26577, 18675, 10774, 2875, 27745, 19848, + 11951, 4056, 28930, 21038, 13147, 5256, 30135, 22247, 14361, + 6475, 31359, 23476, 15595, 7714, 32603, 24725, 16847, 8971, + 1096 + ]) + adpll_sim = np.array([ + 8, 24, 41, 57, 74, 91, 107, 124, 140, 157, 173, + 190, 206, 223, 239, 256, 273, 289, 306, 322, 339, 355, + 372, 388, 405, 421, 438, 454, 471, 487, 504, 520, 537, + 553, 570, 586, 603, 619, 636, 652, 668, 685, 701, 718, + 734, 751, 767, 784, 800, 817, 833, 850, 866, 882, 899, + 915, 932, 948, 965, 981, 998, 1014, 1030, 1047, 1063, 1080, + 1096, 1112, 1129, 1145, 1162, 1178, 1194, 1211, 1227, 1244, 1260, + 1276, 1293, 1309, 1326, 1342, 1358, 1375, 1391, 1407, 1424, 1440, + 1457, 1473, 1489, 1506, 1522, 1538, 1555, 1571, 1587, 1604, 1620, + 1636]) + + def sim(): + yield pll.collector.out_helper.eq(initial_helper_out) + for ref_tag, adpll_matlab in zip(ref_tags, adpll_sim): + # feed collector + yield pll.tag_ref.eq(int(ref_tag)) + yield pll.input_stb.eq(1) + + yield + + yield pll.input_stb.eq(0) + + while not (yield pll.collector.out_stb): + yield + + tag_diff = yield pll.collector.out_helper + + while not (yield pll.loop_filter.output_stb): + yield + + adpll_migen = yield pll.adpll + print("ref tag diff: {}, migen sim adpll {}, matlab adpll {}" + .format(tag_diff, adpll_migen, adpll_matlab)) + + assert adpll_migen == adpll_matlab + yield + + run_simulation(pll, [sim()]) + + +if __name__ == "__main__": + helper_sim() From 6248970ef8a7f86328f4833d2f98421c3fe14363 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Oct 2020 15:40:15 +0800 Subject: [PATCH 2385/2457] wrpll: clean up matlab comparison test --- artiq/gateware/drtio/wrpll/core.py | 47 ++++++++++++++++-------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 63f1928eb..0c030c858 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -152,31 +152,34 @@ class WRPLL(Module, AutoCSR): ] -def helper_sim(N=15): - class WRPLL(Module): - def __init__(self, N): - self.tag_ref = Signal(N) - self.input_stb = Signal() - self.adpll = Signal((24, True)) - self.out_stb = Signal() +class HelperTB(Module): + def __init__(self, N): + self.tag_ref = Signal(N) + self.input_stb = Signal() + self.adpll = Signal((24, True)) + self.out_stb = Signal() - # # # # - loop_filter = thls.make(filters.helper, data_width=48) - self.submodules.loop_filter = loop_filter - self.submodules.collector = collector = Collector(N) + ### - self.comb += [ - self.collector.tag_ref.eq(self.tag_ref), - self.collector.ref_stb.eq(self.input_stb), - self.collector.main_stb.eq(self.input_stb), - self.loop_filter.input.eq(self.collector.out_helper << 22), - self.loop_filter.input_stb.eq(self.collector.out_stb), - self.adpll.eq(self.loop_filter.output), - self.out_stb.eq(self.loop_filter.output_stb), - ] - pll = WRPLL(N=N) + loop_filter = thls.make(filters.helper, data_width=48) + self.submodules.loop_filter = loop_filter + self.submodules.collector = collector = Collector(N) + + self.comb += [ + self.collector.tag_ref.eq(self.tag_ref), + self.collector.ref_stb.eq(self.input_stb), + self.collector.main_stb.eq(self.input_stb), + self.loop_filter.input.eq(self.collector.out_helper << 22), + self.loop_filter.input_stb.eq(self.collector.out_stb), + self.adpll.eq(self.loop_filter.output), + self.out_stb.eq(self.loop_filter.output_stb), + ] + + +# check filter against output from MatLab model +def helper_sim(): + pll = HelperTB(15) - # check filter against output from MatLab model initial_helper_out = -8000 ref_tags = np.array([ 24778, 16789, 8801, 814, 25596, 17612, 9628, 1646, From 96a5df0dc60e706b995c00455282d7ae858ab4d3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Oct 2020 16:19:44 +0800 Subject: [PATCH 2386/2457] kasli2: add false path constraint for wrpll helper clock --- artiq/gateware/targets/kasli.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index d1eb75252..9ea276c3a 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -614,6 +614,9 @@ class SatelliteBase(BaseSoC): platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.txoutclk, gtp.rxoutclk) + if with_wrpll: + platform.add_false_path_constraints( + self.wrpll.cd_helper.clk, gtp.rxoutclk) for gtp in self.drtio_transceiver.gtps[1:]: platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( From 7dfb4af682437a4ba6578010317a9de55af49ab5 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Oct 2020 16:31:10 +0800 Subject: [PATCH 2387/2457] kasli2: work around vivado clock constraint problem --- artiq/gateware/targets/kasli.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/targets/kasli.py b/artiq/gateware/targets/kasli.py index 9ea276c3a..91c6fb9a0 100755 --- a/artiq/gateware/targets/kasli.py +++ b/artiq/gateware/targets/kasli.py @@ -587,14 +587,19 @@ class SatelliteBase(BaseSoC): self.submodules.wrpll_sampler = DDMTDSamplerGTP( self.drtio_transceiver, platform.request("cdr_clk_clean_fabric")) + helper_clk_pads = platform.request("ddmtd_helper_clk") self.submodules.wrpll = WRPLL( - helper_clk_pads=platform.request("ddmtd_helper_clk"), + helper_clk_pads=helper_clk_pads, main_dcxo_i2c=platform.request("ddmtd_main_dcxo_i2c"), helper_dxco_i2c=platform.request("ddmtd_helper_dcxo_i2c"), ddmtd_inputs=self.wrpll_sampler) self.csr_devices.append("wrpll") - platform.add_period_constraint(self.wrpll.cd_helper.clk, rtio_clk_period*0.99) - platform.add_false_path_constraints(self.crg.cd_sys.clk, self.wrpll.cd_helper.clk) + # note: do not use self.wrpll.cd_helper.clk; otherwise, vivado craps out with: + # critical warning: create_clock attempting to set clock on an unknown port/pin + # command: "create_clock -period 7.920000 -waveform {0.000000 3.960000} -name + # helper_clk [get_xlnx_outside_genome_inst_pin 20 0] + platform.add_period_constraint(helper_clk_pads.p, rtio_clk_period*0.99) + platform.add_false_path_constraints(self.crg.cd_sys.clk, helper_clk_pads.p) else: self.submodules.siphaser = SiPhaser7Series( si5324_clkin=platform.request("cdr_clk") if platform.hw_rev == "v2.0" @@ -616,7 +621,7 @@ class SatelliteBase(BaseSoC): gtp.txoutclk, gtp.rxoutclk) if with_wrpll: platform.add_false_path_constraints( - self.wrpll.cd_helper.clk, gtp.rxoutclk) + helper_clk_pads.p, gtp.rxoutclk) for gtp in self.drtio_transceiver.gtps[1:]: platform.add_period_constraint(gtp.rxoutclk, rtio_clk_period) platform.add_false_path_constraints( From 07d43b6e5f4130fbbcab87423ec209b933dfe5d7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Oct 2020 17:51:27 +0800 Subject: [PATCH 2388/2457] wrpll: babysit Vivado DSP retiming Design now passes timing. --- artiq/gateware/drtio/wrpll/thls.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/thls.py b/artiq/gateware/drtio/wrpll/thls.py index f977f2106..b462d9078 100644 --- a/artiq/gateware/drtio/wrpll/thls.py +++ b/artiq/gateware/drtio/wrpll/thls.py @@ -403,10 +403,28 @@ class OpUnit(BaseUnit): def __init__(self, op, data_width, stages): BaseUnit.__init__(self, data_width) - o = op(self.i0, self.i1) - stb_o = self.stb_i - for i in range(stages): + if stages > 1: + # Vivado backward retiming for DSP does not work correctly if DSP inputs + # are not registered. + i0 = Signal.like(self.i0) + i1 = Signal.like(self.i1) + stb_i = Signal() + self.sync += [ + i0.eq(self.i0), + i1.eq(self.i1), + stb_i.eq(self.stb_i) + ] + output_stages = stages - 1 + else: + i0, i1, stb_i = self.i0, self.i1, self.stb_i + output_stages = stages + + o = op(i0, i1) + stb_o = stb_i + for i in range(output_stages): n_o = Signal(data_width) + if stages > 1: + n_o.attr.add(("retiming_backward", 1)) n_stb_o = Signal() self.sync += [ n_o.eq(o), From db62cf2abe49fd70b06bffc72b57d320e76f0510 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 8 Oct 2020 18:38:01 +0800 Subject: [PATCH 2389/2457] wrpll: convert tests to self-checking unittests --- artiq/gateware/drtio/wrpll/core.py | 90 -------------- artiq/gateware/drtio/wrpll/ddmtd.py | 75 ------------ artiq/gateware/drtio/wrpll/thls.py | 47 -------- artiq/gateware/test/wrpll/__init__.py | 0 artiq/gateware/test/wrpll/test_dsp.py | 159 +++++++++++++++++++++++++ artiq/gateware/test/wrpll/test_thls.py | 55 +++++++++ 6 files changed, 214 insertions(+), 212 deletions(-) create mode 100644 artiq/gateware/test/wrpll/__init__.py create mode 100644 artiq/gateware/test/wrpll/test_dsp.py create mode 100644 artiq/gateware/test/wrpll/test_thls.py diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 0c030c858..0d222768b 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -1,5 +1,3 @@ -import numpy as np - from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.cdc import MultiReg, PulseSynchronizer @@ -150,91 +148,3 @@ class WRPLL(Module, AutoCSR): self.main_dcxo.adpll_stb.eq(self.filter_main.output_stb), self.main_dcxo.adpll.eq(self.filter_main.output + self.adpll_offset_main.storage) ] - - -class HelperTB(Module): - def __init__(self, N): - self.tag_ref = Signal(N) - self.input_stb = Signal() - self.adpll = Signal((24, True)) - self.out_stb = Signal() - - ### - - loop_filter = thls.make(filters.helper, data_width=48) - self.submodules.loop_filter = loop_filter - self.submodules.collector = collector = Collector(N) - - self.comb += [ - self.collector.tag_ref.eq(self.tag_ref), - self.collector.ref_stb.eq(self.input_stb), - self.collector.main_stb.eq(self.input_stb), - self.loop_filter.input.eq(self.collector.out_helper << 22), - self.loop_filter.input_stb.eq(self.collector.out_stb), - self.adpll.eq(self.loop_filter.output), - self.out_stb.eq(self.loop_filter.output_stb), - ] - - -# check filter against output from MatLab model -def helper_sim(): - pll = HelperTB(15) - - initial_helper_out = -8000 - ref_tags = np.array([ - 24778, 16789, 8801, 814, 25596, 17612, 9628, 1646, - 26433, 18453, 10474, 2496, 27287, 19311, 11337, 3364, 28160, - 20190, 12221, 4253, 29054, 21088, 13124, 5161, 29966, 22005, - 14045, 6087, 30897, 22940, 14985, 7031, 31847, 23895, 15944, - 7995, 47, 24869, 16923, 8978, 1035, 25861, 17920, 9981, - 2042, 26873, 18937, 11002, 3069, 27904, 19973, 12042, 4113, - 28953, 21026, 13100, 5175, 30020, 22098, 14177, 6257, 31106, - 23189, 15273, 7358, 32212, 24300, 16388, 8478, 569, 25429, - 17522, 9617, 1712, 26577, 18675, 10774, 2875, 27745, 19848, - 11951, 4056, 28930, 21038, 13147, 5256, 30135, 22247, 14361, - 6475, 31359, 23476, 15595, 7714, 32603, 24725, 16847, 8971, - 1096 - ]) - adpll_sim = np.array([ - 8, 24, 41, 57, 74, 91, 107, 124, 140, 157, 173, - 190, 206, 223, 239, 256, 273, 289, 306, 322, 339, 355, - 372, 388, 405, 421, 438, 454, 471, 487, 504, 520, 537, - 553, 570, 586, 603, 619, 636, 652, 668, 685, 701, 718, - 734, 751, 767, 784, 800, 817, 833, 850, 866, 882, 899, - 915, 932, 948, 965, 981, 998, 1014, 1030, 1047, 1063, 1080, - 1096, 1112, 1129, 1145, 1162, 1178, 1194, 1211, 1227, 1244, 1260, - 1276, 1293, 1309, 1326, 1342, 1358, 1375, 1391, 1407, 1424, 1440, - 1457, 1473, 1489, 1506, 1522, 1538, 1555, 1571, 1587, 1604, 1620, - 1636]) - - def sim(): - yield pll.collector.out_helper.eq(initial_helper_out) - for ref_tag, adpll_matlab in zip(ref_tags, adpll_sim): - # feed collector - yield pll.tag_ref.eq(int(ref_tag)) - yield pll.input_stb.eq(1) - - yield - - yield pll.input_stb.eq(0) - - while not (yield pll.collector.out_stb): - yield - - tag_diff = yield pll.collector.out_helper - - while not (yield pll.loop_filter.output_stb): - yield - - adpll_migen = yield pll.adpll - print("ref tag diff: {}, migen sim adpll {}, matlab adpll {}" - .format(tag_diff, adpll_migen, adpll_matlab)) - - assert adpll_migen == adpll_matlab - yield - - run_simulation(pll, [sim()]) - - -if __name__ == "__main__": - helper_sim() diff --git a/artiq/gateware/drtio/wrpll/ddmtd.py b/artiq/gateware/drtio/wrpll/ddmtd.py index 7f13134de..ddeeac54e 100644 --- a/artiq/gateware/drtio/wrpll/ddmtd.py +++ b/artiq/gateware/drtio/wrpll/ddmtd.py @@ -219,78 +219,3 @@ class Collector(Module): NextValue(self.out_stb, 1), NextState("IDLE") ) - - -def test_collector_main(): - N = 2 - collector = Collector(N=N) - # check collector phase unwrapping - tags = [(0, 0, 0), - (0, 1, 1), - (2, 1, -1), - (3, 1, -2), - (0, 1, -3), - (1, 1, -4), - (2, 1, -5), - (3, 1, -6), - (3, 3, -4), - (0, 0, -4), - (0, 1, -3), - (0, 2, -2), - (0, 3, -1), - (0, 0, 0)] - for i in range(10): - tags.append((i % (2**N), (i+1) % (2**N), 1)) - - def generator(): - for tag_ref, tag_main, out in tags: - yield collector.tag_ref.eq(tag_ref) - yield collector.tag_main.eq(tag_main) - yield collector.main_stb.eq(1) - yield collector.ref_stb.eq(1) - - yield - - yield collector.main_stb.eq(0) - yield collector.ref_stb.eq(0) - - while not (yield collector.out_stb): - yield - - out_main = yield collector.out_main - assert out_main == out - - run_simulation(collector, generator()) - - -def test_collector_helper(): - N = 3 - collector = Collector(N=N) - # check collector phase unwrapping - tags = [((2**N - 1 - tag) % (2**N), 0) for tag in range(20)] - tags += [((tags[-1][0] + 1 + tag) % (2**N), 2) for tag in range(20)] - tags += [((tags[-1][0] - 2 - 2*tag) % (2**N), -1) for tag in range(20)] - - def generator(): - for tag_ref, out in tags: - yield collector.tag_ref.eq(tag_ref) - yield collector.main_stb.eq(1) - yield collector.ref_stb.eq(1) - - yield - - yield collector.main_stb.eq(0) - yield collector.ref_stb.eq(0) - - while not (yield collector.out_stb): - yield - - out_helper = yield collector.out_helper - assert out_helper == out - - run_simulation(collector, generator()) - - -if __name__ == "__main__": - test_collector_main() - test_collector_helper() diff --git a/artiq/gateware/drtio/wrpll/thls.py b/artiq/gateware/drtio/wrpll/thls.py index b462d9078..4216fb9fc 100644 --- a/artiq/gateware/drtio/wrpll/thls.py +++ b/artiq/gateware/drtio/wrpll/thls.py @@ -612,50 +612,3 @@ def make(function, **kwargs): cp = compile(proc, function) cp.dimension_processor() return proc.implement(cp.encode(), cp.data) - - -a = 0 -b = 0 -c = 0 - -def foo(x): - global a, b, c - c = b - b = a - a = x - return 4748*a + 259*b - 155*c - - -def simple_test(x): - global a - a = a + (x*4 >> 1) - return a - - -if __name__ == "__main__": - proc = Processor() - cp = compile(proc, simple_test) - cp.pretty_print() - cp.dimension_processor() - print(cp.encode()) - proc_impl = proc.implement(cp.encode(), cp.data) - - def send_values(values): - for value in values: - yield proc_impl.input.eq(value) - yield proc_impl.input_stb.eq(1) - yield - yield proc_impl.input.eq(0) - yield proc_impl.input_stb.eq(0) - yield - while (yield proc_impl.busy): - yield - @passive - def receive_values(callback): - while True: - while not (yield proc_impl.output_stb): - yield - callback((yield proc_impl.output)) - yield - - run_simulation(proc_impl, [send_values([42, 40, 10, 10]), receive_values(print)]) diff --git a/artiq/gateware/test/wrpll/__init__.py b/artiq/gateware/test/wrpll/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/artiq/gateware/test/wrpll/test_dsp.py b/artiq/gateware/test/wrpll/test_dsp.py new file mode 100644 index 000000000..eeb89a44e --- /dev/null +++ b/artiq/gateware/test/wrpll/test_dsp.py @@ -0,0 +1,159 @@ +import unittest + +import numpy as np + +from migen import * + +from artiq.gateware.drtio.wrpll.ddmtd import Collector +from artiq.gateware.drtio.wrpll import thls, filters + + +class HelperChainTB(Module): + def __init__(self, N): + self.tag_ref = Signal(N) + self.input_stb = Signal() + self.adpll = Signal((24, True)) + self.out_stb = Signal() + + ### + + self.submodules.collector = Collector(N) + self.submodules.loop_filter = thls.make(filters.helper, data_width=48) + + self.comb += [ + self.collector.tag_ref.eq(self.tag_ref), + self.collector.ref_stb.eq(self.input_stb), + self.collector.main_stb.eq(self.input_stb), + self.loop_filter.input.eq(self.collector.out_helper << 22), + self.loop_filter.input_stb.eq(self.collector.out_stb), + self.adpll.eq(self.loop_filter.output), + self.out_stb.eq(self.loop_filter.output_stb), + ] + + +class TestDSP(unittest.TestCase): + def test_main_collector(self): + N = 2 + collector = Collector(N=N) + # check collector phase unwrapping + tags = [(0, 0, 0), + (0, 1, 1), + (2, 1, -1), + (3, 1, -2), + (0, 1, -3), + (1, 1, -4), + (2, 1, -5), + (3, 1, -6), + (3, 3, -4), + (0, 0, -4), + (0, 1, -3), + (0, 2, -2), + (0, 3, -1), + (0, 0, 0)] + for i in range(10): + tags.append((i % (2**N), (i+1) % (2**N), 1)) + + def generator(): + for tag_ref, tag_main, out in tags: + yield collector.tag_ref.eq(tag_ref) + yield collector.tag_main.eq(tag_main) + yield collector.main_stb.eq(1) + yield collector.ref_stb.eq(1) + + yield + + yield collector.main_stb.eq(0) + yield collector.ref_stb.eq(0) + + while not (yield collector.out_stb): + yield + + out_main = yield collector.out_main + self.assertEqual(out_main, out) + + run_simulation(collector, generator()) + + @unittest.skip("FIXME") + def test_helper_collector(self): + N = 3 + collector = Collector(N=N) + # check collector phase unwrapping + tags = [((2**N - 1 - tag) % (2**N), 0) for tag in range(20)] + tags += [((tags[-1][0] + 1 + tag) % (2**N), 2) for tag in range(20)] + tags += [((tags[-1][0] - 2 - 2*tag) % (2**N), -1) for tag in range(20)] + + def generator(): + for tag_ref, out in tags: + yield collector.tag_ref.eq(tag_ref) + yield collector.main_stb.eq(1) + yield collector.ref_stb.eq(1) + + yield + + yield collector.main_stb.eq(0) + yield collector.ref_stb.eq(0) + + while not (yield collector.out_stb): + yield + + out_helper = yield collector.out_helper + self.assertEqual(out_helper, out) + + run_simulation(collector, generator()) + + # test helper collector + filter against output from MATLAB model + def test_helper_chain(self): + pll = HelperChainTB(15) + + initial_helper_out = -8000 + ref_tags = np.array([ + 24778, 16789, 8801, 814, 25596, 17612, 9628, 1646, + 26433, 18453, 10474, 2496, 27287, 19311, 11337, 3364, 28160, + 20190, 12221, 4253, 29054, 21088, 13124, 5161, 29966, 22005, + 14045, 6087, 30897, 22940, 14985, 7031, 31847, 23895, 15944, + 7995, 47, 24869, 16923, 8978, 1035, 25861, 17920, 9981, + 2042, 26873, 18937, 11002, 3069, 27904, 19973, 12042, 4113, + 28953, 21026, 13100, 5175, 30020, 22098, 14177, 6257, 31106, + 23189, 15273, 7358, 32212, 24300, 16388, 8478, 569, 25429, + 17522, 9617, 1712, 26577, 18675, 10774, 2875, 27745, 19848, + 11951, 4056, 28930, 21038, 13147, 5256, 30135, 22247, 14361, + 6475, 31359, 23476, 15595, 7714, 32603, 24725, 16847, 8971, + 1096 + ]) + adpll_sim = np.array([ + 8, 24, 41, 57, 74, 91, 107, 124, 140, 157, 173, + 190, 206, 223, 239, 256, 273, 289, 306, 322, 339, 355, + 372, 388, 405, 421, 438, 454, 471, 487, 504, 520, 537, + 553, 570, 586, 603, 619, 636, 652, 668, 685, 701, 718, + 734, 751, 767, 784, 800, 817, 833, 850, 866, 882, 899, + 915, 932, 948, 965, 981, 998, 1014, 1030, 1047, 1063, 1080, + 1096, 1112, 1129, 1145, 1162, 1178, 1194, 1211, 1227, 1244, 1260, + 1276, 1293, 1309, 1326, 1342, 1358, 1375, 1391, 1407, 1424, 1440, + 1457, 1473, 1489, 1506, 1522, 1538, 1555, 1571, 1587, 1604, 1620, + 1636]) + + def sim(): + yield pll.collector.out_helper.eq(initial_helper_out) + for ref_tag, adpll_matlab in zip(ref_tags, adpll_sim): + # feed collector + yield pll.tag_ref.eq(int(ref_tag)) + yield pll.input_stb.eq(1) + + yield + + yield pll.input_stb.eq(0) + + while not (yield pll.collector.out_stb): + yield + + tag_diff = yield pll.collector.out_helper + + while not (yield pll.loop_filter.output_stb): + yield + + adpll_migen = yield pll.adpll + self.assertEqual(adpll_migen, adpll_matlab) + + yield + + run_simulation(pll, [sim()]) diff --git a/artiq/gateware/test/wrpll/test_thls.py b/artiq/gateware/test/wrpll/test_thls.py new file mode 100644 index 000000000..c1013de30 --- /dev/null +++ b/artiq/gateware/test/wrpll/test_thls.py @@ -0,0 +1,55 @@ +import unittest + +from migen import * + +from artiq.gateware.drtio.wrpll import thls + + +a = 0 + +def simple_test(x): + global a + a = a + (x*4 >> 1) + return a + + +class TestTHLS(unittest.TestCase): + def test_thls(self): + global a + + proc = thls.Processor() + a = 0 + cp = thls.compile(proc, simple_test) + print("Program:") + cp.pretty_print() + cp.dimension_processor() + print("Encoded program:", cp.encode()) + proc_impl = proc.implement(cp.encode(), cp.data) + + def send_values(values): + for value in values: + yield proc_impl.input.eq(value) + yield proc_impl.input_stb.eq(1) + yield + yield proc_impl.input.eq(0) + yield proc_impl.input_stb.eq(0) + yield + while (yield proc_impl.busy): + yield + @passive + def receive_values(callback): + while True: + while not (yield proc_impl.output_stb): + yield + callback((yield proc_impl.output)) + yield + + send_list = [42, 40, 10, 10] + receive_list = [] + + run_simulation(proc_impl, [send_values(send_list), receive_values(receive_list.append)]) + print("Execution:", send_list, "->", receive_list) + + a = 0 + expected_list = [simple_test(x) for x in send_list] + self.assertEqual(receive_list, expected_list) From e9988f9d3b0abbe391b4513e801aeee709fbcb4a Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 8 Oct 2020 19:14:05 +0800 Subject: [PATCH 2390/2457] compiler: error message for custom operations Emit error messages for custom comparison and inclusion test, instead of compiler crashing. --- artiq/compiler/transforms/artiq_ir_generator.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 1ce7c4005..f5d66aa24 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1914,7 +1914,13 @@ class ARTIQIRGenerator(algorithm.Visitor): return result else: - assert False + loc = lhs.loc + loc.end = rhs.loc.end + diag = diagnostic.Diagnostic("error", + "Custom object comparison is not supported", + {}, + loc) + self.engine.process(diag) def polymorphic_compare_pair_inclusion(self, needle, haystack): if builtins.is_range(haystack.type): @@ -1958,7 +1964,13 @@ class ARTIQIRGenerator(algorithm.Visitor): result = phi else: - assert False + loc = needle.loc + loc.end = haystack.loc.end + diag = diagnostic.Diagnostic("error", + "Custom object inclusion test is not supported", + {}, + loc) + self.engine.process(diag) return result From d0d0a02fd008df626d95384c66adcda97df92306 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 8 Oct 2020 19:15:11 +0800 Subject: [PATCH 2391/2457] test: added lit test for new error messages --- artiq/test/lit/codegen/custom_comparison.py | 13 +++++++++++++ artiq/test/lit/codegen/custom_inclusion.py | 13 +++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 artiq/test/lit/codegen/custom_comparison.py create mode 100644 artiq/test/lit/codegen/custom_inclusion.py diff --git a/artiq/test/lit/codegen/custom_comparison.py b/artiq/test/lit/codegen/custom_comparison.py new file mode 100644 index 000000000..8a7a1d32b --- /dev/null +++ b/artiq/test/lit/codegen/custom_comparison.py @@ -0,0 +1,13 @@ +# RUN: %python -m artiq.compiler.testbench.signature +diag %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +class Foo: + def __init__(self): + pass + +a = Foo() +b = Foo() + +# CHECK-L: ${LINE:+1}: error: Custom object comparison is not supported +a > b + diff --git a/artiq/test/lit/codegen/custom_inclusion.py b/artiq/test/lit/codegen/custom_inclusion.py new file mode 100644 index 000000000..92cd1a772 --- /dev/null +++ b/artiq/test/lit/codegen/custom_inclusion.py @@ -0,0 +1,13 @@ +# RUN: %python -m artiq.compiler.testbench.signature +diag %s >%t +# RUN: OutputCheck %s --file-to-check=%t + +class Foo: + def __init__(self): + pass + +a = Foo() +b = Foo() + +# CHECK-L: ${LINE:+1}: error: Custom object inclusion test is not supported +a in b + From a058be2edec1801b58e2e761e317316f450cf72d Mon Sep 17 00:00:00 2001 From: hartytp Date: Thu, 8 Oct 2020 19:43:00 +0800 Subject: [PATCH 2392/2457] wrpll: fix test_helper_collector --- artiq/gateware/test/wrpll/test_dsp.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/test/wrpll/test_dsp.py b/artiq/gateware/test/wrpll/test_dsp.py index eeb89a44e..033e69853 100644 --- a/artiq/gateware/test/wrpll/test_dsp.py +++ b/artiq/gateware/test/wrpll/test_dsp.py @@ -73,14 +73,13 @@ class TestDSP(unittest.TestCase): run_simulation(collector, generator()) - @unittest.skip("FIXME") def test_helper_collector(self): N = 3 collector = Collector(N=N) # check collector phase unwrapping - tags = [((2**N - 1 - tag) % (2**N), 0) for tag in range(20)] - tags += [((tags[-1][0] + 1 + tag) % (2**N), 2) for tag in range(20)] - tags += [((tags[-1][0] - 2 - 2*tag) % (2**N), -1) for tag in range(20)] + tags = [((2**N - 1 - tag) % (2**N), -1) for tag in range(20)] + tags += [((tags[-1][0] + 1 + tag) % (2**N), 1) for tag in range(20)] + tags += [((tags[-1][0] - 2 - 2*tag) % (2**N), -2) for tag in range(20)] def generator(): for tag_ref, out in tags: From 35c61ce24d01a694f6b3fb6186da364cc34aeb1c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 12 Oct 2020 14:45:52 +0800 Subject: [PATCH 2393/2457] si5324: unify N31 settings when used as synthesizer Closes #1528 --- artiq/firmware/runtime/rtio_clocking.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index 63a595358..99fbb6fe1 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -67,7 +67,7 @@ pub mod crg { #[cfg(si5324_as_synthesizer)] fn setup_si5324_as_synthesizer() { - // 125 MHz output from 10 MHz CLKIN2, 504 Hz BW + // 125 MHz output from 10 MHz CLKINx reference, 504 Hz BW #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "10.0"))] const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings { @@ -75,12 +75,12 @@ fn setup_si5324_as_synthesizer() { nc1_ls : 4, n2_hs : 10, n2_ls : 300, - n31 : 75, + n31 : 6, n32 : 6, bwsel : 4, crystal_ref: false }; - // 125MHz output, from 100MHz CLKIN2 reference, 586 Hz loop bandwidth + // 125MHz output, from 100MHz CLKINx reference, 586 Hz loop bandwidth #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "100.0"))] const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings { @@ -88,12 +88,12 @@ fn setup_si5324_as_synthesizer() { nc1_ls : 4, n2_hs : 10, n2_ls : 260, - n31 : 65, + n31 : 52, n32 : 52, bwsel : 4, crystal_ref: false }; - // 125MHz output, from 125MHz CLKIN2 reference, 606 Hz loop bandwidth + // 125MHz output, from 125MHz CLKINx reference, 606 Hz loop bandwidth #[cfg(all(rtio_frequency = "125.0", si5324_ext_ref, ext_ref_frequency = "125.0"))] const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings { @@ -114,7 +114,7 @@ fn setup_si5324_as_synthesizer() { nc1_ls : 4, n2_hs : 10, n2_ls : 19972, - n31 : 4993, + n31 : 4565, n32 : 4565, bwsel : 4, crystal_ref: true @@ -127,7 +127,7 @@ fn setup_si5324_as_synthesizer() { nc1_ls : 4, n2_hs : 10, n2_ls : 33732, - n31 : 9370, + n31 : 7139, n32 : 7139, bwsel : 3, crystal_ref: true @@ -140,7 +140,7 @@ fn setup_si5324_as_synthesizer() { nc1_ls : 6, n2_hs : 10, n2_ls : 33732, - n31 : 9370, + n31 : 7139, n32 : 7139, bwsel : 3, crystal_ref: true From ac35548d0f66f83fd5d4b19df0a7bc5b0ea09843 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 14 Oct 2020 12:57:25 +0800 Subject: [PATCH 2394/2457] runtime: fix metlino si5324 init --- artiq/firmware/runtime/rtio_clocking.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index 99fbb6fe1..0f1aa78ab 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -151,6 +151,8 @@ fn setup_si5324_as_synthesizer() { let si5324_ref_input = si5324::Input::Ckin1; #[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] let si5324_ref_input = si5324::Input::Ckin2; + #[cfg(soc_platform = "metlino")] + let si5324_ref_input = si5324::Input::Ckin2; si5324::setup(&SI5324_SETTINGS, si5324_ref_input).expect("cannot initialize Si5324"); } From 57ee57e7ea6fd84e23084c28a66c26a3fc411705 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 14 Oct 2020 18:41:56 +0800 Subject: [PATCH 2395/2457] runtime: fix metlino si5324 init (2) --- artiq/firmware/runtime/rtio_clocking.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/firmware/runtime/rtio_clocking.rs b/artiq/firmware/runtime/rtio_clocking.rs index 0f1aa78ab..3b230bacc 100644 --- a/artiq/firmware/runtime/rtio_clocking.rs +++ b/artiq/firmware/runtime/rtio_clocking.rs @@ -163,6 +163,8 @@ pub fn init() { let si5324_ext_input = si5324::Input::Ckin1; #[cfg(all(soc_platform = "kasli", not(hw_rev = "v2.0")))] let si5324_ext_input = si5324::Input::Ckin2; + #[cfg(soc_platform = "metlino")] + let si5324_ext_input = si5324::Input::Ckin2; match get_rtio_clock_cfg() { RtioClock::Internal => setup_si5324_as_synthesizer(), RtioClock::External => si5324::bypass(si5324_ext_input).expect("cannot bypass Si5324") From e66d2a640801579307a6689b92df7f58958ab316 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Oct 2020 14:31:25 +0800 Subject: [PATCH 2396/2457] manual: clarify and expand nix-shell file --- doc/manual/installing.rst | 48 +++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index c1184f168..dbebb129f 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -48,8 +48,8 @@ Installing multiple packages and making them visible to the ARTIQ commands requi :: let - # Contains the NixOS package collection. ARTIQ depends on some of them, and - # you may also want certain packages from there. + # pkgs contains the NixOS package collection. ARTIQ depends on some of them, and + # you may want some additional packages from there. pkgs = import {}; artiq-full = import { inherit pkgs; }; in @@ -57,25 +57,39 @@ Installing multiple packages and making them visible to the ARTIQ commands requi buildInputs = [ (pkgs.python3.withPackages(ps: [ # List desired Python packages here. + + # You probably want these two. artiq-full.artiq artiq-full.artiq-comtools - # The board packages are also "Python" packages. You only need a board - # package if you intend to reflash that board (those packages contain - # only board firmware). - artiq-full.artiq-board-kc705-nist_clock - artiq-full.artiq-board-kasli-wipm - # from the NixOS package collection: - ps.paramiko # needed for flashing boards remotely (artiq_flash -H) - ps.pandas - ps.numpy - ps.scipy - ps.numba - (ps.matplotlib.override { enableQt = true; }) - ps.bokeh + + # You need a board support package if and only if you intend to flash + # a board (those packages contain only board firmware). + # The lines below are only examples, you need to select appropriate + # packages for your boards. + #artiq-full.artiq-board-kc705-nist_clock + #artiq-full.artiq-board-kasli-wipm + #ps.paramiko # needed if and only if flashing boards remotely (artiq_flash -H) + + # The NixOS package collection contains many other packages that you may find + # interesting for your research. Here are some examples: + #ps.pandas + #ps.numpy + #ps.scipy + #ps.numba + #(ps.matplotlib.override { enableQt = true; }) + #ps.bokeh + #ps.cirq + #ps.qiskit + #ps.qutip ])) + # List desired non-Python packages here - artiq-full.openocd # needed for flashing boards, also provides proxy bitstreams - pkgs.spyder + #artiq-full.openocd # needed if and only if flashing boards + # Other potentially interesting packages from the NixOS package collection: + #pkgs.gtkwave + #pkgs.spyder + #pkgs.R + #pkgs.julia ]; } From 7a5996ba79843d3c8ce8bf8d0c5fd11138eb37dc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Oct 2020 16:14:22 +0800 Subject: [PATCH 2397/2457] artiq_netboot: moved to git.m-labs.hk/M-Labs/artiq-netboot --- artiq/frontend/artiq_netboot.py | 50 --------------------------------- setup.py | 1 - 2 files changed, 51 deletions(-) delete mode 100755 artiq/frontend/artiq_netboot.py diff --git a/artiq/frontend/artiq_netboot.py b/artiq/frontend/artiq_netboot.py deleted file mode 100755 index 4f72b2c45..000000000 --- a/artiq/frontend/artiq_netboot.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import socket -import struct -import os - - -def send_file(sock, filename): - with open(filename, "rb") as input_file: - sock.sendall(struct.pack(">I", os.fstat(input_file.fileno()).st_size)) - while True: - data = input_file.read(4096) - if not data: - break - sock.sendall(data) - sock.sendall(b"OK") - - -def main(): - parser = argparse.ArgumentParser(description="ARTIQ netboot tool") - parser.add_argument("hostname", metavar="HOSTNAME", - help="hostname of the target board") - parser.add_argument("-f", "--firmware", nargs=1, - help="firmware to load") - # Note that on softcore systems, the main gateware cannot be replaced - # with -g. This option is used for loading the RTM FPGA from the AMC - # on Sayma, and the PL on Zynq. - parser.add_argument("-g", "--gateware", nargs=1, - help="gateware to load") - parser.add_argument("-b", "--boot", action="store_true", - help="boot the device") - args = parser.parse_args() - - sock = socket.create_connection((args.hostname, 4269)) - try: - if args.firmware is not None: - sock.sendall(b"F") - send_file(sock, args.firmware[0]) - if args.gateware is not None: - sock.sendall(b"G") - send_file(sock, args.gateware[0]) - if args.boot: - sock.sendall(b"B") - finally: - sock.close() - - -if __name__ == "__main__": - main() diff --git a/setup.py b/setup.py index 44022073d..95bbbe2ab 100755 --- a/setup.py +++ b/setup.py @@ -24,7 +24,6 @@ console_scripts = [ "artiq_coreanalyzer = artiq.frontend.artiq_coreanalyzer:main", "artiq_coremgmt = artiq.frontend.artiq_coremgmt:main", "artiq_ddb_template = artiq.frontend.artiq_ddb_template:main", - "artiq_netboot = artiq.frontend.artiq_netboot:main", "artiq_master = artiq.frontend.artiq_master:main", "artiq_mkfs = artiq.frontend.artiq_mkfs:main", "artiq_rtiomon = artiq.frontend.artiq_rtiomon:main", From 59703ad31d1ae120200e8c9d7944fbba84cca059 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Oct 2020 16:18:56 +0800 Subject: [PATCH 2398/2457] test: stop checking for artiq_netboot --- artiq/test/test_frontends.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/test_frontends.py b/artiq/test/test_frontends.py index c433fca71..a52d4a17c 100644 --- a/artiq/test/test_frontends.py +++ b/artiq/test/test_frontends.py @@ -13,7 +13,7 @@ class TestFrontends(unittest.TestCase): ], "artiq": [ "client", "compile", "coreanalyzer", "coremgmt", - "netboot", "flash", "master", "mkfs", "route", + "flash", "master", "mkfs", "route", "rtiomon", "run", "session", "browser", "dashboard" ] } From 4000adfb217e1adb18558f43166f3eec066fb17c Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Oct 2020 16:42:28 +0800 Subject: [PATCH 2399/2457] RELEASE_NOTES: update ARTIQ-6 section --- RELEASE_NOTES.rst | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 318759e30..48a98b202 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -8,13 +8,22 @@ ARTIQ-6 Highlights: +* New hardware support: + - Zynq SoC core devices, enabling kernels to run on 1 GHz CPU core with + a floating-point unit for faster computations. This currently requires an external + repository (https://git.m-labs.hk/m-labs/artiq-zynq) and only supports the ZC706. + - Mirny 4-channel wide-band PLL/VCO-based microwave frequency synthesiser + - Fastino 32-channel, 3MS/s per channel, 16-bit DAC EEM + - Kasli 2.0 +* Matrix math support on the core device. +* Trigonometric functions and miscellaneous math library support on the core device. * Performance improvements: - #1432: SERDES TTL inputs can now detect edges on pulses that are shorter than the RTIO period - Improved performance for kernel RPC involving list and array. -* Coredevice SI to mu conversions now always return valid codes, or raise a `ValueError`. -* Zotino now exposes `voltage_to_mu()` -* `ad9910`: The maximum amplitude scale factor is now `0x3fff` (was `0x3ffe` +* Coredevice SI to mu conversions now always return valid codes, or raise a ``ValueError``. +* Zotino now exposes ``voltage_to_mu()`` +* ``ad9910``: The maximum amplitude scale factor is now ``0x3fff`` (was ``0x3ffe`` before). * Dashboard: - Applets now restart if they are running and a ccb call changes their spec @@ -25,11 +34,16 @@ Highlights: * Core device: ``panic_reset 1`` now correctly resets the kernel CPU as well if communication CPU panic occurs. * NumberValue accepts a ``type`` parameter specifying the output as ``int`` or ``float`` -* A parameter `--identifier-str` has been added to many targets to aid +* A parameter ``--identifier-str`` has been added to many targets to aid with reproducible builds. +* Python 3.7 support in Conda packages. Breaking changes: +* ``artiq_netboot`` has been moved to its own repository at + https://git.m-labs.hk/m-labs/artiq-netboot +* Core device watchdogs have been removed. + ARTIQ-5 ------- From 4027735a6d3116c2020102f244b6a7cece44b9f4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Oct 2020 16:42:43 +0800 Subject: [PATCH 2400/2457] RELEASE_NOTES: fix formatting --- RELEASE_NOTES.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 48a98b202..6afe7697b 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -75,15 +75,15 @@ Highlights: - Synchronization calibration data can be read from EEPROM. * A gateware-level input edge counter has been added, which offers higher throughput and increased flexibility over the usual TTL input PHYs where - edge timestamps are not required. See `artiq.coredevice.edge_counter` for - the core device driver and `artiq.gateware.rtio.phy.edge_counter`/ - `artiq.gateware.eem.DIO.add_std` for the gateware components. + edge timestamps are not required. See ``martiq.coredevice.edge_counter`` for + the core device driver and ``artiq.gateware.rtio.phy.edge_counter``/ + ``artiq.gateware.eem.DIO.add_std`` for the gateware components. * With DRTIO, Siphaser uses a better calibration mechanism. See: https://github.com/m-labs/artiq/commit/cc58318500ecfa537abf24127f2c22e8fe66e0f8 * Schedule updates can be sent to influxdb (artiq_influxdb_schedule). * Experiments can now programatically set their default pipeline, priority, and flush flag. * List datasets can now be efficiently appended to from experiments using - `artiq.language.environment.HasEnvironment.append_to_dataset`. + ``artiq.language.environment.HasEnvironment.append_to_dataset``. * The core device now supports IPv6. * To make development easier, the bootloader can receive firmware and secondary FPGA gateware from the network. @@ -93,8 +93,8 @@ Highlights: Breaking changes: -* The `artiq.coredevice.ad9910.AD9910` and - `artiq.coredevice.ad9914.AD9914` phase reference timestamp parameters +* The ``artiq.coredevice.ad9910.AD9910`` and + ``artiq.coredevice.ad9914.AD9914`` phase reference timestamp parameters have been renamed to ``ref_time_mu`` for consistency, as they are in machine units. * The controller manager now ignores device database entries without the From 0a37a3dbf790aee4b455bb9674eae21da5e854f8 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Oct 2020 16:45:17 +0800 Subject: [PATCH 2401/2457] RELEASE_NOTES: fix formatting --- RELEASE_NOTES.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 6afe7697b..e87bd5929 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -9,12 +9,12 @@ ARTIQ-6 Highlights: * New hardware support: - - Zynq SoC core devices, enabling kernels to run on 1 GHz CPU core with - a floating-point unit for faster computations. This currently requires an external - repository (https://git.m-labs.hk/m-labs/artiq-zynq) and only supports the ZC706. - - Mirny 4-channel wide-band PLL/VCO-based microwave frequency synthesiser - - Fastino 32-channel, 3MS/s per channel, 16-bit DAC EEM - - Kasli 2.0 + - Zynq SoC core devices, enabling kernels to run on 1 GHz CPU core with a floating-point + unit for faster computations. This currently requires an external + repository (https://git.m-labs.hk/m-labs/artiq-zynq) and only supports the ZC706. + - Mirny 4-channel wide-band PLL/VCO-based microwave frequency synthesiser + - Fastino 32-channel, 3MS/s per channel, 16-bit DAC EEM + - Kasli 2.0 * Matrix math support on the core device. * Trigonometric functions and miscellaneous math library support on the core device. * Performance improvements: @@ -22,7 +22,7 @@ Highlights: than the RTIO period - Improved performance for kernel RPC involving list and array. * Coredevice SI to mu conversions now always return valid codes, or raise a ``ValueError``. -* Zotino now exposes ``voltage_to_mu()`` +* Zotino now exposes ``voltage_to_mu()`` * ``ad9910``: The maximum amplitude scale factor is now ``0x3fff`` (was ``0x3ffe`` before). * Dashboard: From ed90450d2c759d3444d4db6be1ac3c2225948434 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Oct 2020 16:48:28 +0800 Subject: [PATCH 2402/2457] README: mention Sinara in ARTIQ manifesto --- README.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 6e3bcbd70..da7e446c9 100644 --- a/README.rst +++ b/README.rst @@ -48,9 +48,10 @@ The ARTIQ manifesto =================== The free and open dissemination of methods and results is central to scientific progress. -The ARTIQ authors, contributors, and supporters consider the free and open exchange of scientific tools to be equally important and have chosen the licensing terms of ARTIQ accordingly. -ARTIQ, including its gateware, the firmware, and the ARTIQ tools and libraries are licensed as LGPLv3+. -This ensures that a user of ARTIQ obtains broad rights to use, redistribute, and modify it. + +The ARTIQ and Sinara authors, contributors, and supporters consider the free and open exchange of scientific tools to be equally important and have chosen the licensing terms of ARTIQ and Sinara accordingly. ARTIQ, including its gateware, the firmware, and the ARTIQ tools and libraries are licensed as LGPLv3+. The Sinara hardware designs are licensed under CERN OHL. +This ensures that a user of ARTIQ or Sinara hardware designs obtains broad rights to use, redistribute, study, and modify them. + The following statements are intended to clarify the interpretation and application of the licensing terms: * There is no requirement to distribute any unmodified, modified, or extended versions of ARTIQ. Only when distributing ARTIQ the source needs to be made available. From 24259523bb76afbd454c08eeb3995b8f8a518504 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Oct 2020 16:51:02 +0800 Subject: [PATCH 2403/2457] RELEASE_NOTES: link to issue consistently --- RELEASE_NOTES.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index e87bd5929..a786b4ff4 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -18,8 +18,8 @@ Highlights: * Matrix math support on the core device. * Trigonometric functions and miscellaneous math library support on the core device. * Performance improvements: - - #1432: SERDES TTL inputs can now detect edges on pulses that are shorter - than the RTIO period + - SERDES TTL inputs can now detect edges on pulses that are shorter + than the RTIO period (https://github.com/m-labs/artiq/issues/1432) - Improved performance for kernel RPC involving list and array. * Coredevice SI to mu conversions now always return valid codes, or raise a ``ValueError``. * Zotino now exposes ``voltage_to_mu()`` From 840364cf0ce1960672977b519f6d42b438484511 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Oct 2020 16:57:53 +0800 Subject: [PATCH 2404/2457] RELEASE_NOTES: fix typo --- RELEASE_NOTES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index a786b4ff4..62a87ef69 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -75,7 +75,7 @@ Highlights: - Synchronization calibration data can be read from EEPROM. * A gateware-level input edge counter has been added, which offers higher throughput and increased flexibility over the usual TTL input PHYs where - edge timestamps are not required. See ``martiq.coredevice.edge_counter`` for + edge timestamps are not required. See ``artiq.coredevice.edge_counter`` for the core device driver and ``artiq.gateware.rtio.phy.edge_counter``/ ``artiq.gateware.eem.DIO.add_std`` for the gateware components. * With DRTIO, Siphaser uses a better calibration mechanism. From 6af8655cc7658bb801a897e1198a570175f2de2f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Oct 2020 17:14:19 +0800 Subject: [PATCH 2405/2457] README: update --- README.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index da7e446c9..0d4859a3a 100644 --- a/README.rst +++ b/README.rst @@ -4,23 +4,23 @@ .. image:: https://raw.githubusercontent.com/m-labs/artiq/master/doc/logo/artiq.png :target: https://m-labs.hk/artiq -ARTIQ (Advanced Real-Time Infrastructure for Quantum physics) is the next-generation control system for quantum information experiments. -It is maintained and developed by `M-Labs `_ and the initial development was for and in partnership with the `Ion Storage Group at NIST `_. ARTIQ is free software and offered to the entire research community as a solution equally applicable to other challenging control tasks, including outside the field of ion trapping. Several other laboratories (e.g. at the University of Oxford, the Army Research Lab, and the University of Maryland) have later adopted ARTIQ as their control system and have contributed to it. +ARTIQ (Advanced Real-Time Infrastructure for Quantum physics) is a leading-edge control and data acquisition system for quantum information experiments. +It is maintained and developed by `M-Labs `_ and the initial development was for and in partnership with the `Ion Storage Group at NIST `_. ARTIQ is free software and offered to the entire research community as a solution equally applicable to other challenging control tasks, including outside the field of ion trapping. Many laboratories around the world have adopted ARTIQ as their control system, with over a hundred Sinara hardware crates deployed, and some have `contributed `_ to it. The system features a high-level programming language that helps describing complex experiments, which is compiled and executed on dedicated hardware with nanosecond timing resolution and sub-microsecond latency. It includes graphical user interfaces to parametrize and schedule experiments and to visualize and explore the results. ARTIQ uses FPGA hardware to perform its time-critical tasks. The `Sinara hardware `_, and in particular the Kasli FPGA carrier, is designed to work with ARTIQ. ARTIQ is designed to be portable to hardware platforms from different vendors and FPGA manufacturers. -Several different configurations of a `high-end FPGA evaluation kit `_ are also used and supported. FPGA platforms can be combined with any number of additional peripherals, either already accessible from ARTIQ or made accessible with little effort. +Several different configurations of a `FPGA evaluation kit `_ and of a `Zynq evaluation kit `_ are also used and supported. FPGA platforms can be combined with any number of additional peripherals, either already accessible from ARTIQ or made accessible with little effort. -ARTIQ and its dependencies are available in the form of Nix packages (for Linux) and Conda packages (for Windows and Linux). See `the manual `_ for installation instructions. +ARTIQ and its dependencies are available in the form of Nix packages (for Linux) and Conda packages (for Windows and Linux). See `the manual `_ for installation instructions. Packages containing pre-compiled binary images to be loaded onto the hardware platforms are supplied for each configuration. Like any open source software ARTIQ can equally be built and installed directly from `source `_. ARTIQ is supported by M-Labs and developed openly. -Components, features, fixes, improvements, and extensions are funded by and developed for the partnering research groups. +Components, features, fixes, improvements, and extensions are often `funded `_ by and developed for the partnering research groups. -Technologies employed include `Python `_, `Migen `_, `MiSoC `_/`mor1kx `_, `LLVM `_/`llvmlite `_, and `Qt5 `_. +Core technologies employed include `Python `_, `Migen `_, `Migen-AXI `_, `Rust `_, `MiSoC `_/`mor1kx `_, `LLVM `_/`llvmlite `_, and `Qt5 `_. Website: https://m-labs.hk/artiq From 90017da48445c43637b5c9b753f4cd77e4971e98 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Thu, 15 Oct 2020 18:38:00 +0800 Subject: [PATCH 2406/2457] firmware: remove obsolete watchdog code (#1458) --- artiq/firmware/ksupport/api.rs | 3 -- artiq/firmware/ksupport/lib.rs | 15 ------ artiq/firmware/libproto_artiq/kernel_proto.rs | 4 -- .../firmware/libproto_artiq/session_proto.rs | 4 -- artiq/firmware/runtime/main.rs | 1 - artiq/firmware/runtime/session.rs | 25 ---------- artiq/firmware/runtime/watchdog.rs | 49 ------------------- 7 files changed, 101 deletions(-) delete mode 100644 artiq/firmware/runtime/watchdog.rs diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index c07f9776b..89a6f638c 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -121,9 +121,6 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(now = csr::rtio::NOW_HI_ADDR as *const _), - api!(watchdog_set = ::watchdog_set), - api!(watchdog_clear = ::watchdog_clear), - api!(rpc_send = ::rpc_send), api!(rpc_send_async = ::rpc_send_async), api!(rpc_recv = ::rpc_recv), diff --git a/artiq/firmware/ksupport/lib.rs b/artiq/firmware/ksupport/lib.rs index c6e747fdb..5e42fd100 100644 --- a/artiq/firmware/ksupport/lib.rs +++ b/artiq/firmware/ksupport/lib.rs @@ -200,21 +200,6 @@ fn terminate(exception: &eh_artiq::Exception, backtrace: &mut [usize]) -> ! { loop {} } -#[unwind(allowed)] -extern fn watchdog_set(ms: i64) -> i32 { - if ms < 0 { - raise!("ValueError", "cannot set a watchdog with a negative timeout") - } - - send(&WatchdogSetRequest { ms: ms as u64 }); - recv!(&WatchdogSetReply { id } => id) as i32 -} - -#[unwind(aborts)] -extern fn watchdog_clear(id: i32) { - send(&WatchdogClear { id: id as usize }) -} - #[unwind(aborts)] extern fn cache_get(key: CSlice) -> CSlice<'static, i32> { send(&CacheGetRequest { diff --git a/artiq/firmware/libproto_artiq/kernel_proto.rs b/artiq/firmware/libproto_artiq/kernel_proto.rs index a64f0f0b7..3ca55426d 100644 --- a/artiq/firmware/libproto_artiq/kernel_proto.rs +++ b/artiq/firmware/libproto_artiq/kernel_proto.rs @@ -52,10 +52,6 @@ pub enum Message<'a> { }, RunAborted, - WatchdogSetRequest { ms: u64 }, - WatchdogSetReply { id: usize }, - WatchdogClear { id: usize }, - RpcSend { async: bool, service: u32, diff --git a/artiq/firmware/libproto_artiq/session_proto.rs b/artiq/firmware/libproto_artiq/session_proto.rs index cc0012da5..db353e874 100644 --- a/artiq/firmware/libproto_artiq/session_proto.rs +++ b/artiq/firmware/libproto_artiq/session_proto.rs @@ -105,7 +105,6 @@ pub enum Reply<'a> { RpcRequest { async: bool }, - WatchdogExpired, ClockFailure, } @@ -191,9 +190,6 @@ impl<'a> Reply<'a> { writer.write_u8(async as u8)?; }, - Reply::WatchdogExpired => { - writer.write_u8(14)?; - }, Reply::ClockFailure => { writer.write_u8(15)?; }, diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 73660b611..c64d0fc64 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -53,7 +53,6 @@ mod mgmt; mod profiler; mod kernel; mod kern_hwreq; -mod watchdog; mod session; #[cfg(any(has_rtio_moninj, has_drtio))] mod moninj; diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 4a14f3fb6..a05e18c2f 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -11,7 +11,6 @@ use rtio_clocking; use rtio_dma::Manager as DmaManager; use cache::Cache; use kern_hwreq; -use watchdog::WatchdogSet; use board_artiq::drtio_routing; use rpc_proto as rpc; @@ -28,10 +27,6 @@ pub enum Error { InvalidPointer(usize), #[fail(display = "RTIO clock failure")] ClockFailure, - #[fail(display = "watchdog {} expired", _0)] - WatchdogExpired(usize), - #[fail(display = "out of watchdogs")] - OutOfWatchdogs, #[fail(display = "protocol error: {}", _0)] Protocol(#[cause] host::Error), #[fail(display = "{}", _0)] @@ -91,7 +86,6 @@ enum KernelState { struct Session<'a> { congress: &'a mut Congress, kernel_state: KernelState, - watchdog_set: WatchdogSet, log_buffer: String } @@ -100,7 +94,6 @@ impl<'a> Session<'a> { Session { congress: congress, kernel_state: KernelState::Absent, - watchdog_set: WatchdogSet::new(), log_buffer: String::new() } } @@ -396,15 +389,6 @@ fn process_kern_message(io: &Io, aux_mutex: &Mutex, }) } - &kern::WatchdogSetRequest { ms } => { - let id = session.watchdog_set.set_ms(ms).map_err(|()| Error::OutOfWatchdogs)?; - kern_send(io, &kern::WatchdogSetReply { id: id }) - } - &kern::WatchdogClear { id } => { - session.watchdog_set.clear(id); - kern_acknowledge() - } - &kern::RpcSend { async, service, tag, data } => { match stream { None => unexpected!("unexpected RPC in flash kernel"), @@ -522,11 +506,6 @@ fn host_kernel_worker(io: &Io, aux_mutex: &Mutex, } if session.kernel_state == KernelState::Running { - if let Some(idx) = session.watchdog_set.expired() { - host_write(stream, host::Reply::WatchdogExpired)?; - return Err(Error::WatchdogExpired(idx)) - } - if !rtio_clocking::crg::check() { host_write(stream, host::Reply::ClockFailure)?; return Err(Error::ClockFailure) @@ -567,10 +546,6 @@ fn flash_kernel_worker(io: &Io, aux_mutex: &Mutex, } } - if let Some(idx) = session.watchdog_set.expired() { - return Err(Error::WatchdogExpired(idx)) - } - if !rtio_clocking::crg::check() { return Err(Error::ClockFailure) } diff --git a/artiq/firmware/runtime/watchdog.rs b/artiq/firmware/runtime/watchdog.rs deleted file mode 100644 index 202a1d1a0..000000000 --- a/artiq/firmware/runtime/watchdog.rs +++ /dev/null @@ -1,49 +0,0 @@ -use board_misoc::clock; - -#[derive(Debug, Clone, Copy)] -struct Watchdog { - active: bool, - threshold: u64 -} - -pub const MAX_WATCHDOGS: usize = 16; - -#[derive(Debug)] -pub struct WatchdogSet { - watchdogs: [Watchdog; MAX_WATCHDOGS] -} - -impl WatchdogSet { - pub fn new() -> WatchdogSet { - WatchdogSet { - watchdogs: [Watchdog { active: false, threshold: 0 }; MAX_WATCHDOGS] - } - } - - pub fn set_ms(&mut self, interval: u64) -> Result { - for (index, watchdog) in self.watchdogs.iter_mut().enumerate() { - if !watchdog.active { - watchdog.active = true; - watchdog.threshold = clock::get_ms() + interval; - return Ok(index) - } - } - - Err(()) - } - - pub fn clear(&mut self, index: usize) { - if index < MAX_WATCHDOGS { - self.watchdogs[index].active = false - } - } - - pub fn expired(&self) -> Option { - self.watchdogs - .iter() - .enumerate() - .filter(|(_, wd)| wd.active && clock::get_ms() > wd.threshold) - .min_by_key(|(_, wd)| wd.threshold) - .map_or(None, |(i, _)| Some(i)) - } -} From 3f076bf79bbc5abc18fef53d5b26288fea89fb78 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 16 Oct 2020 22:05:20 +0800 Subject: [PATCH 2407/2457] wrpll: fix mulshift --- artiq/gateware/drtio/wrpll/thls.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/gateware/drtio/wrpll/thls.py b/artiq/gateware/drtio/wrpll/thls.py index 4216fb9fc..279c56293 100644 --- a/artiq/gateware/drtio/wrpll/thls.py +++ b/artiq/gateware/drtio/wrpll/thls.py @@ -552,7 +552,8 @@ class ProcessorImpl(Module): if pd.multiplier_shifts: if len(pd.multiplier_shifts) != 1: raise NotImplementedError - multiplier = OpUnit(lambda a, b: a * b >> pd.multiplier_shifts[0], + # work around Migen's mishandling of Verilog's cretinous operator width rules + multiplier = OpUnit(lambda a, b: Cat(a, C(0, pd.data_width)) * Cat(b, C(0, pd.data_width)) >> pd.multiplier_shifts[0], pd.data_width, pd.multiplier_stages) else: multiplier = NopUnit(pd.data_width) From d185f1ac672f1bbd45746816160690588f6b6310 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 17 Oct 2020 00:32:02 +0800 Subject: [PATCH 2408/2457] wrpll: fix mulshift (2) --- artiq/gateware/drtio/wrpll/thls.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/drtio/wrpll/thls.py b/artiq/gateware/drtio/wrpll/thls.py index 279c56293..b11459692 100644 --- a/artiq/gateware/drtio/wrpll/thls.py +++ b/artiq/gateware/drtio/wrpll/thls.py @@ -400,8 +400,11 @@ class NopUnit(BaseUnit): class OpUnit(BaseUnit): - def __init__(self, op, data_width, stages): + def __init__(self, op, data_width, stages, op_data_width=None): BaseUnit.__init__(self, data_width) + # work around Migen's mishandling of Verilog's cretinous operator width rules + if op_data_width is None: + op_data_width = data_width if stages > 1: # Vivado backward retiming for DSP does not work correctly if DSP inputs @@ -419,10 +422,11 @@ class OpUnit(BaseUnit): i0, i1, stb_i = self.i0, self.i1, self.stb_i output_stages = stages - o = op(i0, i1) + o = Signal((op_data_width, True)) + self.comb += o.eq(op(i0, i1)) stb_o = stb_i for i in range(output_stages): - n_o = Signal(data_width) + n_o = Signal((data_width, True)) if stages > 1: n_o.attr.add(("retiming_backward", 1)) n_stb_o = Signal() @@ -552,9 +556,8 @@ class ProcessorImpl(Module): if pd.multiplier_shifts: if len(pd.multiplier_shifts) != 1: raise NotImplementedError - # work around Migen's mishandling of Verilog's cretinous operator width rules - multiplier = OpUnit(lambda a, b: Cat(a, C(0, pd.data_width)) * Cat(b, C(0, pd.data_width)) >> pd.multiplier_shifts[0], - pd.data_width, pd.multiplier_stages) + multiplier = OpUnit(lambda a, b: a * b >> pd.multiplier_shifts[0], + pd.data_width, pd.multiplier_stages, op_data_width=2*pd.data_width) else: multiplier = NopUnit(pd.data_width) minu = SelectUnit(operator.lt, pd.data_width) From 139385a57179165709e95b4ae36d4f97ef764fe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sun, 18 Oct 2020 17:11:09 +0000 Subject: [PATCH 2409/2457] fastlink: add fastino test --- artiq/gateware/test/rtio/test_fastlink.py | 49 +++++++++++++++++++++-- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/test/rtio/test_fastlink.py b/artiq/gateware/test/rtio/test_fastlink.py index 5b62c9aba..4304963d6 100644 --- a/artiq/gateware/test/rtio/test_fastlink.py +++ b/artiq/gateware/test/rtio/test_fastlink.py @@ -23,12 +23,13 @@ class TestPhaser(unittest.TestCase): clk = (clk << 2) & 0xff clk |= (yield self.dut.data[0]) if clk == 0x0f: - marker = (marker << 1) & 0x7f - marker |= (yield self.dut.data[1]) & 1 - if marker >> 1 == 0x01: + if marker == 0x01: stb += 1 if stb >= 3: break + # 10/2 + 1 marker bits + marker = (marker << 1) & 0x3f + marker |= (yield self.dut.data[1]) & 1 yield def test_frame(self): @@ -41,3 +42,45 @@ class TestPhaser(unittest.TestCase): self.assertEqual([d[0] for d in frame], [0, 0, 3, 3] * 10) self.assertEqual([d[1] & 1 for d in frame[4*4 - 1:10*4 - 1:4]], [0, 0, 0, 0, 0, 1]) + + +class TestFastino(unittest.TestCase): + def setUp(self): + self.dut = SerDes( + n_data=8, t_clk=7, d_clk=0b1100011, + n_frame=14, n_crc=12, poly=0x80f) + + def test_init(self): + pass + + def record_frame(self, frame): + clk = 0 + marker = 0 + stb = 0 + while True: + if stb == 2: + frame.append((yield self.dut.data)) + clk = (clk << 2) & 0xff + clk |= (yield self.dut.data[0]) + if clk in (0b11100011, 0b11000111): + if marker == 0x01: + stb += 1 + if stb >= 3: + break + # 14/2 + 1 marker bits + marker = (marker << 1) & 0xff + if clk & 0b100: + marker |= (yield self.dut.data[1]) >> 1 + else: + marker |= (yield self.dut.data[1]) & 1 + yield + + def test_frame(self): + frame = [] + self.dut.comb += self.dut.payload.eq((1 << len(self.dut.payload)) - 1) + run_simulation(self.dut, self.record_frame(frame), + clocks={n: 2 for n in ["sys", "rio", "rio_phy"]}, + vcd_name="fastlink.vcd") + self.assertEqual(len(frame), 7*14//2) + self.assertEqual([d[0] for d in frame], [3, 0, 1, 3, 2, 0, 3] * 7) + print(frame) From d98357051c5a57c93ca59956cf1c93308d7e37ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sun, 18 Oct 2020 18:01:41 +0000 Subject: [PATCH 2410/2457] add ref data --- artiq/gateware/test/rtio/test_fastlink.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/artiq/gateware/test/rtio/test_fastlink.py b/artiq/gateware/test/rtio/test_fastlink.py index 4304963d6..3733e8205 100644 --- a/artiq/gateware/test/rtio/test_fastlink.py +++ b/artiq/gateware/test/rtio/test_fastlink.py @@ -83,4 +83,8 @@ class TestFastino(unittest.TestCase): vcd_name="fastlink.vcd") self.assertEqual(len(frame), 7*14//2) self.assertEqual([d[0] for d in frame], [3, 0, 1, 3, 2, 0, 3] * 7) + self.assertEqual(ref, frame) print(frame) + + +ref = [[3, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [1, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [2, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [1, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [2, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [1, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [2, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [3, 2, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [1, 3, 3, 3, 3, 3, 3, 0], [3, 1, 3, 3, 3, 3, 3, 0], [2, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [3, 2, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [1, 3, 3, 3, 3, 3, 3, 0], [3, 1, 3, 3, 3, 3, 3, 0], [2, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [3, 2, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [1, 3, 3, 3, 3, 3, 3, 0], [3, 1, 3, 3, 3, 3, 3, 0], [2, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [3, 2, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [1, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [2, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [3, 3, 1, 1, 1, 2, 1, 0]] From 30d1acee9f7e8c642df3d9c1ba5b67e501b37b39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Sun, 18 Oct 2020 22:27:05 +0200 Subject: [PATCH 2411/2457] fastlink: fix fastino style link --- artiq/gateware/rtio/phy/fastlink.py | 9 ++++----- artiq/gateware/test/rtio/test_fastlink.py | 12 +++--------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/artiq/gateware/rtio/phy/fastlink.py b/artiq/gateware/rtio/phy/fastlink.py index 796b01642..1a9317f77 100644 --- a/artiq/gateware/rtio/phy/fastlink.py +++ b/artiq/gateware/rtio/phy/fastlink.py @@ -74,9 +74,8 @@ class SerDes(Module): # big shift register for mosi and sr = [Signal(t_frame, reset_less=True) for i in range(n_mosi)] assert len(Cat(sr)) == len(words) - crc_insert = ([d[1] for d in self.data[:-1]] + - [d[0] for d in self.data[:-1]]) - crc_insert = Cat(crc_insert[-n_crc:]) + crc_insert = Cat(([d[0] for d in self.data[1:-1]] + + [d[1] for d in self.data[1:-1]])[:n_crc]) miso_sr = Signal(t_frame, reset_less=True) miso_sr_next = Signal.like(miso_sr) self.comb += [ @@ -106,8 +105,8 @@ class SerDes(Module): # transpose, load [sri.eq(Cat(words[i::n_mosi])) for i, sri in enumerate(sr)], # inject crc for the last cycle - crc_insert.eq(self.crca.next if n_crc // n_mosi == 1 - else self.crcb.next), + crc_insert.eq(self.crca.next if n_crc // n_mosi <= 1 + else self.crca.last), ), ] diff --git a/artiq/gateware/test/rtio/test_fastlink.py b/artiq/gateware/test/rtio/test_fastlink.py index 3733e8205..df8840951 100644 --- a/artiq/gateware/test/rtio/test_fastlink.py +++ b/artiq/gateware/test/rtio/test_fastlink.py @@ -36,8 +36,7 @@ class TestPhaser(unittest.TestCase): frame = [] self.dut.comb += self.dut.payload.eq((1 << len(self.dut.payload)) - 1) run_simulation(self.dut, self.record_frame(frame), - clocks={n: 2 for n in ["sys", "rio", "rio_phy"]}, - vcd_name="fastlink.vcd") + clocks={n: 2 for n in ["sys", "rio", "rio_phy"]}) self.assertEqual(len(frame), 8*10//2) self.assertEqual([d[0] for d in frame], [0, 0, 3, 3] * 10) self.assertEqual([d[1] & 1 for d in frame[4*4 - 1:10*4 - 1:4]], @@ -79,12 +78,7 @@ class TestFastino(unittest.TestCase): frame = [] self.dut.comb += self.dut.payload.eq((1 << len(self.dut.payload)) - 1) run_simulation(self.dut, self.record_frame(frame), - clocks={n: 2 for n in ["sys", "rio", "rio_phy"]}, - vcd_name="fastlink.vcd") + clocks={n: 2 for n in ["sys", "rio", "rio_phy"]}) self.assertEqual(len(frame), 7*14//2) self.assertEqual([d[0] for d in frame], [3, 0, 1, 3, 2, 0, 3] * 7) - self.assertEqual(ref, frame) - print(frame) - - -ref = [[3, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [1, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [2, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [1, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [2, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [1, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [2, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [3, 2, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [1, 3, 3, 3, 3, 3, 3, 0], [3, 1, 3, 3, 3, 3, 3, 0], [2, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [3, 2, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [1, 3, 3, 3, 3, 3, 3, 0], [3, 1, 3, 3, 3, 3, 3, 0], [2, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [3, 2, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [1, 3, 3, 3, 3, 3, 3, 0], [3, 1, 3, 3, 3, 3, 3, 0], [2, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [3, 2, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [1, 3, 3, 3, 3, 3, 3, 0], [3, 3, 3, 3, 3, 3, 3, 0], [2, 3, 3, 3, 3, 3, 3, 0], [0, 3, 3, 3, 3, 3, 3, 0], [3, 3, 1, 1, 1, 2, 1, 0]] + self.assertEqual(frame[-1], [3, 3, 1, 1, 1, 2, 1, 0]) # crc12 From 94489f91833f1d6181563e7e9165d222ccfc6bfc Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 20 Oct 2020 01:28:01 +0200 Subject: [PATCH 2412/2457] compiler: Fix inference order issue in multi-dim. subscript This will be caught by the test for an imminent array quoting fix. --- artiq/compiler/transforms/inferencer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index e2be2c7df..ddbd0bf24 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -237,6 +237,8 @@ class Inferencer(algorithm.Visitor): self.generic_visit(node) if isinstance(node.slice, ast.Index): if types.is_tuple(node.slice.value.type): + if types.is_var(node.value.type): + return if not builtins.is_array(node.value.type): diag = diagnostic.Diagnostic( "error", From d161fd5d84d9b724eb27bb21dabcf41f61fd2c62 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 20 Oct 2020 01:29:51 +0200 Subject: [PATCH 2413/2457] compiler: Properly expand dimensions for array([]) with ndarray elements This matches host NumPy behaviour (and, in either case, was previously broken, as it still continued past the array element type). --- artiq/compiler/transforms/inferencer.py | 5 ++++- artiq/test/lit/integration/array.py | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index ddbd0bf24..ce0a269e1 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -892,7 +892,10 @@ class Inferencer(algorithm.Visitor): return # undetermined yet if not builtins.is_iterable(elt) or builtins.is_str(elt): break - num_dims += 1 + if builtins.is_array(elt): + num_dims += elt.find()["num_dims"].value + else: + num_dims += 1 elt = builtins.get_iterable_elt(elt) if explicit_dtype is not None: diff --git a/artiq/test/lit/integration/array.py b/artiq/test/lit/integration/array.py index 039e76372..512382cda 100644 --- a/artiq/test/lit/integration/array.py +++ b/artiq/test/lit/integration/array.py @@ -42,6 +42,9 @@ assert matrix[1, 0] == 4.0 assert matrix[1, 1] == 8.0 assert matrix[1, 2] == 6.0 +array_of_matrices = array([matrix, matrix]) +assert array_of_matrices.shape == (2, 2, 3) + three_tensor = array([[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]]) assert len(three_tensor) == 1 assert three_tensor.shape == (1, 2, 3) From d5f90f6c9faa1d52e5a1999db1a9eaf0b812d38b Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 20 Oct 2020 01:33:14 +0200 Subject: [PATCH 2414/2457] compiler: Fix quoting of multi-dimensional arrays GitHub: Fixes m-labs/artiq#1523. --- .../compiler/transforms/llvm_ir_generator.py | 33 +++++++++++------ artiq/test/coredevice/test_embedding.py | 37 +++++++++++++++++++ 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 31384e578..003de3c1a 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -1503,6 +1503,17 @@ class LLVMIRGenerator: return llcall + def _quote_listish_to_llglobal(self, value, elt_type, path, kind_name): + llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)]) + for i in range(len(value))] + lleltsary = ll.Constant(ll.ArrayType(self.llty_of_type(elt_type), len(llelts)), + list(llelts)) + name = self.llmodule.scope.deduplicate("quoted.{}".format(kind_name)) + llglobal = ll.GlobalVariable(self.llmodule, lleltsary.type, name) + llglobal.initializer = lleltsary + llglobal.linkage = "private" + return llglobal.bitcast(lleltsary.type.element.as_pointer()) + def _quote(self, value, typ, path): value_id = id(value) if value_id in self.llobject_map: @@ -1579,21 +1590,19 @@ class LLVMIRGenerator: llstr = self.llstr_of_str(as_bytes) llconst = ll.Constant(llty, [llstr, ll.Constant(lli32, len(as_bytes))]) return llconst + elif builtins.is_array(typ): + assert isinstance(value, numpy.ndarray), fail_msg + typ = typ.find() + assert len(value.shape) == typ["num_dims"].find().value + flattened = value.reshape((-1,)) + lleltsptr = self._quote_listish_to_llglobal(flattened, typ["elt"], path, "array") + llshape = ll.Constant.literal_struct([ll.Constant(lli32, s) for s in value.shape]) + return ll.Constant(llty, [lleltsptr, llshape]) elif builtins.is_listish(typ): assert isinstance(value, (list, numpy.ndarray)), fail_msg elt_type = builtins.get_iterable_elt(typ) - llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)]) - for i in range(len(value))] - lleltsary = ll.Constant(ll.ArrayType(self.llty_of_type(elt_type), len(llelts)), - list(llelts)) - - name = self.llmodule.scope.deduplicate("quoted.{}".format(typ.name)) - llglobal = ll.GlobalVariable(self.llmodule, lleltsary.type, name) - llglobal.initializer = lleltsary - llglobal.linkage = "private" - - lleltsptr = llglobal.bitcast(lleltsary.type.element.as_pointer()) - llconst = ll.Constant(llty, [lleltsptr, ll.Constant(lli32, len(llelts))]) + lleltsptr = self._quote_listish_to_llglobal(value, elt_type, path, typ.find().name) + llconst = ll.Constant(llty, [lleltsptr, ll.Constant(lli32, len(value))]) return llconst elif types.is_tuple(typ): assert isinstance(value, tuple), fail_msg diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index c32ba2c55..d944198c9 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -423,3 +423,40 @@ class ListTupleTest(ExperimentCase): def test_empty_list(self): self.create(_EmptyList).run() + + +class _ArrayQuoting(EnvExperiment): + def build(self): + self.setattr_device("core") + self.vec_i32 = np.array([0, 1], dtype=np.int32) + self.mat_i64 = np.array([[0, 1], [2, 3]], dtype=np.int64) + self.arr_f64 = np.array([[[0.0, 1.0], [2.0, 3.0]], + [[4.0, 5.0], [6.0, 7.0]]]) + self.strs = np.array(["foo", "bar"]) + + @kernel + def run(self): + assert self.vec_i32[0] == 0 + assert self.vec_i32[1] == 1 + + assert self.mat_i64[0, 0] == 0 + assert self.mat_i64[0, 1] == 1 + assert self.mat_i64[1, 0] == 2 + assert self.mat_i64[1, 1] == 3 + + assert self.arr_f64[0, 0, 0] == 0.0 + assert self.arr_f64[0, 0, 1] == 1.0 + assert self.arr_f64[0, 1, 0] == 2.0 + assert self.arr_f64[0, 1, 1] == 3.0 + assert self.arr_f64[1, 0, 0] == 4.0 + assert self.arr_f64[1, 0, 1] == 5.0 + assert self.arr_f64[1, 1, 0] == 6.0 + assert self.arr_f64[1, 1, 1] == 7.0 + + assert self.strs[0] == "foo" + assert self.strs[1] == "bar" + + +class ArrayQuotingTest(ExperimentCase): + def test_quoting(self): + self.create(_ArrayQuoting).run() From d672d2fc351150882afe881636cb09bd6d8ed3a8 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 20 Oct 2020 02:49:05 +0200 Subject: [PATCH 2415/2457] test/coredevice: Fixup NumPy references This fixes a copy/paste refactoring mistake from d5f90f6c9. --- artiq/test/coredevice/test_embedding.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index d944198c9..d3c362344 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -428,11 +428,11 @@ class ListTupleTest(ExperimentCase): class _ArrayQuoting(EnvExperiment): def build(self): self.setattr_device("core") - self.vec_i32 = np.array([0, 1], dtype=np.int32) - self.mat_i64 = np.array([[0, 1], [2, 3]], dtype=np.int64) - self.arr_f64 = np.array([[[0.0, 1.0], [2.0, 3.0]], - [[4.0, 5.0], [6.0, 7.0]]]) - self.strs = np.array(["foo", "bar"]) + self.vec_i32 = numpy.array([0, 1], dtype=numpy.int32) + self.mat_i64 = numpy.array([[0, 1], [2, 3]], dtype=numpy.int64) + self.arr_f64 = numpy.array([[[0.0, 1.0], [2.0, 3.0]], + [[4.0, 5.0], [6.0, 7.0]]]) + self.strs = numpy.array(["foo", "bar"]) @kernel def run(self): From ecef5661cebf90856ff9d51999fd4af07cbbe723 Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Thu, 29 Oct 2020 19:44:47 +0100 Subject: [PATCH 2416/2457] coredevice/phaser: fix typos in docstring Signed-off-by: Etienne Wodey --- artiq/coredevice/phaser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/phaser.py b/artiq/coredevice/phaser.py index bcd83926c..ab00d7f1a 100644 --- a/artiq/coredevice/phaser.py +++ b/artiq/coredevice/phaser.py @@ -87,7 +87,7 @@ class Phaser: delay capabilities are available. The latency/group delay from the RTIO events setting - :class:`PhaserOscillator` or :class:`PhaserChannel` DUC parameters all they + :class:`PhaserOscillator` or :class:`PhaserChannel` DUC parameters all the way to the DAC outputs is deterministic. This enables deterministic absolute phase with respect to other RTIO input and output events. @@ -672,7 +672,7 @@ class PhaserChannel: quadrature is within range. .. note:: The interpolation filter on Phaser has an intrinsic sinc-like - overshoot in its step response. That overshoot is an direct consequence + overshoot in its step response. That overshoot is a direct consequence of its near-brick-wall frequency response. For large and wide-band changes in oscillator parameters, the overshoot can lead to clipping or overflow after the interpolation. Either band-limit any changes From a97b4633cb7cbb47c619dd8f9bf6b1aa1f231b04 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Sat, 31 Oct 2020 19:06:00 +0100 Subject: [PATCH 2417/2457] compiler: Add math_fns module docstring [nfc] --- artiq/compiler/math_fns.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/artiq/compiler/math_fns.py b/artiq/compiler/math_fns.py index 6b1890c1d..8b1b38914 100644 --- a/artiq/compiler/math_fns.py +++ b/artiq/compiler/math_fns.py @@ -1,3 +1,9 @@ +r""" +The :mod:`math_fns` module lists math-related functions from NumPy recognized +by the ARTIQ compiler so host function objects can be :func:`match`\ ed to +the compiler type metadata describing their core device analogue. +""" + from collections import OrderedDict import numpy from . import builtins, types From ea95d914284816532282f84adc07c51578fad8d9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 9 Nov 2020 17:57:13 +0800 Subject: [PATCH 2418/2457] wrpll: separate collector reset --- artiq/firmware/libboard_artiq/wrpll.rs | 5 +++++ artiq/gateware/drtio/wrpll/core.py | 12 +++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/libboard_artiq/wrpll.rs b/artiq/firmware/libboard_artiq/wrpll.rs index e31b46ca2..4b0fa9754 100644 --- a/artiq/firmware/libboard_artiq/wrpll.rs +++ b/artiq/firmware/libboard_artiq/wrpll.rs @@ -485,6 +485,10 @@ fn select_recovered_clock_int(rc: bool) -> Result<(), &'static str> { csr::wrpll::main_dcxo_gpio_enable_write(0); csr::wrpll::helper_dcxo_errors_write(0xff); csr::wrpll::main_dcxo_errors_write(0xff); + csr::wrpll::collector_reset_write(0); + } + clock::spin_us(1_000); // wait for the collector to produce meaningful output + unsafe { csr::wrpll::filter_reset_write(0); } @@ -499,6 +503,7 @@ fn select_recovered_clock_int(rc: bool) -> Result<(), &'static str> { unsafe { csr::wrpll::filter_reset_write(1); + csr::wrpll::collector_reset_write(1); } clock::spin_us(50_000); unsafe { diff --git a/artiq/gateware/drtio/wrpll/core.py b/artiq/gateware/drtio/wrpll/core.py index 0d222768b..52bc91ab7 100644 --- a/artiq/gateware/drtio/wrpll/core.py +++ b/artiq/gateware/drtio/wrpll/core.py @@ -51,6 +51,7 @@ class FrequencyCounter(Module, AutoCSR): class WRPLL(Module, AutoCSR): def __init__(self, helper_clk_pads, main_dcxo_i2c, helper_dxco_i2c, ddmtd_inputs, N=15): self.helper_reset = CSRStorage(reset=1) + self.collector_reset = CSRStorage(reset=1) self.filter_reset = CSRStorage(reset=1) self.adpll_offset_helper = CSRStorage(24) self.adpll_offset_main = CSRStorage(24) @@ -69,15 +70,20 @@ class WRPLL(Module, AutoCSR): ] self.clock_domains.cd_helper = ClockDomain() + self.clock_domains.cd_collector = ClockDomain() self.clock_domains.cd_filter = ClockDomain() self.helper_reset.storage.attr.add("no_retiming") self.filter_reset.storage.attr.add("no_retiming") self.specials += Instance("IBUFGDS", i_I=helper_clk_pads.p, i_IB=helper_clk_pads.n, o_O=self.cd_helper.clk) - self.comb += self.cd_filter.clk.eq(self.cd_helper.clk) + self.comb += [ + self.cd_collector.clk.eq(self.cd_collector.clk), + self.cd_filter.clk.eq(self.cd_helper.clk), + ] self.specials += [ AsyncResetSynchronizer(self.cd_helper, self.helper_reset.storage), + AsyncResetSynchronizer(self.cd_collector, self.collector_reset.storage), AsyncResetSynchronizer(self.cd_filter, self.filter_reset.storage) ] @@ -92,9 +98,9 @@ class WRPLL(Module, AutoCSR): self.submodules.ddmtd_ref = DDMTD(ddmtd_counter, ddmtd_inputs.rec_clk) self.submodules.ddmtd_main = DDMTD(ddmtd_counter, ddmtd_inputs.main_xo) + collector_cd = ClockDomainsRenamer("collector") filter_cd = ClockDomainsRenamer("filter") - helper_cd = ClockDomainsRenamer("helper") - self.submodules.collector = helper_cd(Collector(N)) + self.submodules.collector = collector_cd(Collector(N)) self.submodules.filter_helper = filter_cd( thls.make(filters.helper, data_width=48)) self.submodules.filter_main = filter_cd( From f0ec987d23fb7ccd02a61b73201e4bb14d6baa57 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Mon, 9 Nov 2020 20:45:22 +0100 Subject: [PATCH 2419/2457] test/coredevice: Avoid NumPy deprecation warning Jagged arrays are no longer silently inferred as dtype=object, as per NEP-34. The compiler ndarray (re)implementation is unchanged, so the test still fails. --- artiq/test/coredevice/test_embedding.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index d3c362344..57c2a8fab 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -79,11 +79,11 @@ class RoundtripTest(ExperimentCase): self.assertArrayRoundtrip(numpy.array([["a", "b"], ["c", "d"]])) # FIXME: This should work, but currently passes as the argument is just - # synthesised as the same call to array(), instead of using the "type - # inference" result from the host NumPy implementation. + # synthesised as a call to array() without forwarding the dype form the host + # NumPy object. @unittest.expectedFailure def test_array_jagged(self): - self.assertArrayRoundtrip(numpy.array([[1, 2], [3]])) + self.assertArrayRoundtrip(numpy.array([[1, 2], [3]], dtype=object)) class _DefaultArg(EnvExperiment): From 4f311e74485d5c77d01395db63b3ea00eee12faf Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 4 Nov 2020 19:45:10 +0100 Subject: [PATCH 2420/2457] compiler: Raise exception on failed assert()s rather than panic This allows assert() to be used on Zynq, where abort() is not currently implemented for kernels. Furthermore, this is arguably the more natural implementation of assertions on all kernel targets (i.e. where embedding into host Python is used), as it matches host Python behavior, and the exception information actually makes it to the user rather than leading to a ConnectionClosed error. Since this does not implement printing of the subexpressions, I left the old print+abort implementation as default for the time being. The lit/integration/instance.py diff isn't just a spurious change; the exception-based assert implementation exposes a limitation in the existing closure lifetime tracking algorithm (which is not supposed to be what is tested there). GitHub: Fixes #1539. --- artiq/compiler/module.py | 11 ++- artiq/compiler/targets.py | 8 ++ .../compiler/transforms/artiq_ir_generator.py | 98 +++++++++++++++++-- artiq/coredevice/core.py | 3 +- artiq/coredevice/exceptions.py | 1 + artiq/test/coredevice/test_embedding.py | 37 +++++++ artiq/test/lit/integration/instance.py | 4 +- 7 files changed, 146 insertions(+), 16 deletions(-) diff --git a/artiq/compiler/module.py b/artiq/compiler/module.py index d43404b20..3cce61105 100644 --- a/artiq/compiler/module.py +++ b/artiq/compiler/module.py @@ -40,7 +40,8 @@ class Source: return cls(source.Buffer(f.read(), filename, 1), engine=engine) class Module: - def __init__(self, src, ref_period=1e-6, attribute_writeback=True, remarks=False): + def __init__(self, src, ref_period=1e-6, attribute_writeback=True, remarks=False, + raise_assertion_errors=False): self.attribute_writeback = attribute_writeback self.engine = src.engine self.embedding_map = src.embedding_map @@ -55,9 +56,11 @@ class Module: iodelay_estimator = transforms.IODelayEstimator(engine=self.engine, ref_period=ref_period) constness_validator = validators.ConstnessValidator(engine=self.engine) - artiq_ir_generator = transforms.ARTIQIRGenerator(engine=self.engine, - module_name=src.name, - ref_period=ref_period) + artiq_ir_generator = transforms.ARTIQIRGenerator( + engine=self.engine, + module_name=src.name, + ref_period=ref_period, + raise_assertion_errors=raise_assertion_errors) dead_code_eliminator = transforms.DeadCodeEliminator(engine=self.engine) local_access_validator = validators.LocalAccessValidator(engine=self.engine) local_demoter = transforms.LocalDemoter() diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index 9ebc7907d..427d9f07c 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -80,6 +80,9 @@ class Target: determined from data_layout due to JIT. :var now_pinning: (boolean) Whether the target implements the now-pinning RTIO optimization. + :var raise_assertion_errors: (bool) + Whether to raise an AssertionError on failed assertions or abort/panic + instead. """ triple = "unknown" data_layout = "" @@ -87,6 +90,7 @@ class Target: print_function = "printf" little_endian = False now_pinning = True + raise_assertion_errors = False tool_ld = "ld.lld" tool_strip = "llvm-strip" @@ -277,6 +281,10 @@ class CortexA9Target(Target): little_endian = True now_pinning = False + # Support for marshalling kernel CPU panics as RunAborted errors is not + # implemented in the ARTIQ Zynq runtime. + raise_assertion_errors = True + tool_ld = "armv7-unknown-linux-gnueabihf-ld" tool_strip = "armv7-unknown-linux-gnueabihf-strip" tool_addr2line = "armv7-unknown-linux-gnueabihf-addr2line" diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index f5d66aa24..075bf581d 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -94,11 +94,12 @@ class ARTIQIRGenerator(algorithm.Visitor): _size_type = builtins.TInt32() - def __init__(self, module_name, engine, ref_period): + def __init__(self, module_name, engine, ref_period, raise_assertion_errors): self.engine = engine self.functions = [] self.name = [module_name] if module_name != "" else [] self.ref_period = ir.Constant(ref_period, builtins.TFloat()) + self.raise_assertion_errors = raise_assertion_errors self.current_loc = None self.current_function = None self.current_class = None @@ -119,6 +120,7 @@ class ARTIQIRGenerator(algorithm.Visitor): self.variable_map = dict() self.method_map = defaultdict(lambda: []) self.array_op_funcs = dict() + self.raise_assert_func = None def annotate_calls(self, devirtualization): for var_node in devirtualization.variable_map: @@ -1017,19 +1019,30 @@ class ARTIQIRGenerator(algorithm.Visitor): cond_block = self.current_block self.current_block = body_block = self.add_block("check.body") - closure = self.append(ir.Closure(func, ir.Constant(None, ir.TEnvironment("check", {})))) + self._invoke_raising_func(func, params, "check") + + self.current_block = tail_block = self.add_block("check.tail") + cond_block.append(ir.BranchIf(cond, tail_block, body_block)) + + def _invoke_raising_func(self, func, params, block_name): + """Emit a call/invoke instruction as appropriate to terminte the current + basic block with a call to a helper function that always raises an + exception. + + (This is done for compiler-inserted checks and assertions to keep the + generated code tight for the normal case.) + """ + closure = self.append(ir.Closure(func, + ir.Constant(None, ir.TEnvironment("raise", {})))) if self.unwind_target is None: insn = self.append(ir.Call(closure, params, {})) else: - after_invoke = self.add_block("check.invoke") + after_invoke = self.add_block(block_name + ".invoke") insn = self.append(ir.Invoke(closure, params, {}, after_invoke, self.unwind_target)) self.current_block = after_invoke insn.is_cold = True self.append(ir.Unreachable()) - self.current_block = tail_block = self.add_block("check.tail") - cond_block.append(ir.BranchIf(cond, tail_block, body_block)) - def _map_index(self, length, index, one_past_the_end=False, loc=None): lt_0 = self.append(ir.Compare(ast.Lt(loc=None), index, ir.Constant(0, index.type))) @@ -2478,6 +2491,56 @@ class ARTIQIRGenerator(algorithm.Visitor): loc=node.loc) self.current_assert_subexprs.append((node, name)) + def _get_raise_assert_func(self): + """Emit the helper function that constructs AssertionErrors and raises + them, if it does not already exist in the current module. + + A separate function is used for code size reasons. (This could also be + compiled into a stand-alone support library instead.) + """ + if self.raise_assert_func: + return self.raise_assert_func + try: + msg = ir.Argument(builtins.TStr(), "msg") + file = ir.Argument(builtins.TStr(), "file") + line = ir.Argument(builtins.TInt32(), "line") + col = ir.Argument(builtins.TInt32(), "col") + function = ir.Argument(builtins.TStr(), "function") + + args = [msg, file, line, col, function] + typ = types.TFunction(args=OrderedDict([(arg.name, arg.type) + for arg in args]), + optargs=OrderedDict(), + ret=builtins.TNone()) + env = ir.TEnvironment(name="raise", vars={}) + env_arg = ir.EnvironmentArgument(env, "ARG.ENV") + func = ir.Function(typ, "_artiq_raise_assert", [env_arg] + args) + func.is_internal = True + func.is_cold = True + func.is_generated = True + self.functions.append(func) + old_func, self.current_function = self.current_function, func + + entry = self.add_block("entry") + old_block, self.current_block = self.current_block, entry + old_final_branch, self.final_branch = self.final_branch, None + old_unwind, self.unwind_target = self.unwind_target, None + + exn = self.alloc_exn(builtins.TException("AssertionError"), message=msg) + self.append(ir.SetAttr(exn, "__file__", file)) + self.append(ir.SetAttr(exn, "__line__", line)) + self.append(ir.SetAttr(exn, "__col__", col)) + self.append(ir.SetAttr(exn, "__func__", function)) + self.append(ir.Raise(exn)) + finally: + self.current_function = old_func + self.current_block = old_block + self.final_branch = old_final_branch + self.unwind_target = old_unwind + + self.raise_assert_func = func + return self.raise_assert_func + def visit_Assert(self, node): try: assert_suffix = ".assert@{}:{}".format(node.loc.line(), node.loc.column()) @@ -2502,6 +2565,26 @@ class ARTIQIRGenerator(algorithm.Visitor): if_failed = self.current_block = self.add_block("assert.fail") + if self.raise_assertion_errors: + self._raise_assertion_error(node) + else: + self._abort_after_assertion(node, assert_subexprs, assert_env) + + tail = self.current_block = self.add_block("assert.tail") + self.append(ir.BranchIf(cond, tail, if_failed), block=head) + + def _raise_assertion_error(self, node): + text = str(node.msg.s) if node.msg else "AssertionError" + msg = ir.Constant(text, builtins.TStr()) + loc_file = ir.Constant(node.loc.source_buffer.name, builtins.TStr()) + loc_line = ir.Constant(node.loc.line(), builtins.TInt32()) + loc_column = ir.Constant(node.loc.column(), builtins.TInt32()) + loc_function = ir.Constant(".".join(self.name), builtins.TStr()) + self._invoke_raising_func(self._get_raise_assert_func(), [ + msg, loc_file, loc_line, loc_column, loc_function + ], "assert.fail") + + def _abort_after_assertion(self, node, assert_subexprs, assert_env): if node.msg: explanation = node.msg.s else: @@ -2535,9 +2618,6 @@ class ARTIQIRGenerator(algorithm.Visitor): self.append(ir.Builtin("abort", [], builtins.TNone())) self.append(ir.Unreachable()) - tail = self.current_block = self.add_block("assert.tail") - self.append(ir.BranchIf(cond, tail, if_failed), block=head) - def polymorphic_print(self, values, separator, suffix="", as_repr=False, as_rtio=False): def printf(format_string, *args): format = ir.Constant(format_string, builtins.TStr()) diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index d150df596..87d6a854f 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -106,7 +106,8 @@ class Core: module = Module(stitcher, ref_period=self.ref_period, - attribute_writeback=attribute_writeback) + attribute_writeback=attribute_writeback, + raise_assertion_errors=self.target_cls.raise_assertion_errors) target = self.target_cls() library = target.compile_and_link([module]) diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index 0d84d49c0..8260739d2 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -11,6 +11,7 @@ ZeroDivisionError = builtins.ZeroDivisionError ValueError = builtins.ValueError IndexError = builtins.IndexError RuntimeError = builtins.RuntimeError +AssertionError = builtins.AssertionError class CoreException: diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 57c2a8fab..0d6da1cd4 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -460,3 +460,40 @@ class _ArrayQuoting(EnvExperiment): class ArrayQuotingTest(ExperimentCase): def test_quoting(self): self.create(_ArrayQuoting).run() + + +class _Assert(EnvExperiment): + def build(self): + self.setattr_device("core") + + def raises_assertion_errors(self): + return self.core.target_cls.raises_assertion_errors + + @kernel + def check(self, value): + assert value + + @kernel + def check_msg(self, value): + assert value, "foo" + + +class AssertTest(ExperimentCase): + def test_assert(self): + exp = self.create(_Assert) + + def check_fail(fn, msg): + if exp.raises_assertion_errors: + with self.assertRaises(AssertionError) as ctx: + fn() + self.assertEqual(str(ctx.exception), msg) + else: + # Without assertion exceptions, core device panics should still lead + # to a cleanly dropped connectionr rather than a hang/… + with self.assertRaises(ConnectionResetError): + fn() + + exp.check(True) + check_fail(lambda: exp.check(False), "AssertionError") + exp.check_msg(True) + check_fail(lambda: exp.check_msg(False), "foo") diff --git a/artiq/test/lit/integration/instance.py b/artiq/test/lit/integration/instance.py index bf255d88f..5acea8721 100644 --- a/artiq/test/lit/integration/instance.py +++ b/artiq/test/lit/integration/instance.py @@ -6,9 +6,9 @@ class c: i = c() -assert i.a == 1 - def f(): c = None assert i.a == 1 + +assert i.a == 1 f() From 211500089f59799054d52f3ebdfee87b594508e6 Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Thu, 8 Oct 2020 23:36:50 +0200 Subject: [PATCH 2421/2457] coredevice: mirny/adf5355: add basic high-level interface Signed-off-by: Etienne Wodey --- artiq/coredevice/adf5355.py | 483 ++++++++++++++++++++- artiq/coredevice/adf5355_reg.py | 742 ++++++++++++++++++++++++++++++++ artiq/coredevice/mirny.py | 71 ++- 3 files changed, 1256 insertions(+), 40 deletions(-) create mode 100644 artiq/coredevice/adf5355_reg.py diff --git a/artiq/coredevice/adf5355.py b/artiq/coredevice/adf5355.py index a23df6701..6bfd18da5 100644 --- a/artiq/coredevice/adf5355.py +++ b/artiq/coredevice/adf5355.py @@ -9,14 +9,39 @@ on Mirny-style prefixed SPI buses. # https://www.analog.com/media/en/technical-documentation/user-guides/EV-ADF5356SD1Z-UG-1087.pdf -from artiq.language.core import kernel, delay -from artiq.language.units import us +from artiq.language.core import kernel, portable, rpc, delay +from artiq.language.units import us, GHz, MHz +from artiq.language.types import TInt32, TInt64 from artiq.coredevice import spi2 as spi +from artiq.coredevice.adf5355_reg import * -SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | - 0*spi.SPI_INPUT | 1*spi.SPI_CS_POLARITY | - 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | - 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) +from fractions import Fraction +from numpy import int32, int64, floor, ceil + + +SPI_CONFIG = ( + 0 * spi.SPI_OFFLINE + | 0 * spi.SPI_END + | 0 * spi.SPI_INPUT + | 1 * spi.SPI_CS_POLARITY + | 0 * spi.SPI_CLK_POLARITY + | 0 * spi.SPI_CLK_PHASE + | 0 * spi.SPI_LSB_FIRST + | 0 * spi.SPI_HALF_DUPLEX +) + + +ADF5355_MIN_VCO_FREQ = int64(3.4 * GHz) +ADF5355_MAX_VCO_FREQ = int64(6.8 * GHz) +ADF5355_MAX_OUTA_FREQ = ADF5355_MAX_VCO_FREQ +ADF5355_MIN_OUTA_FREQ = ADF5355_MIN_VCO_FREQ / 64 +ADF5355_MAX_OUTB_FREQ = ADF5355_MAX_VCO_FREQ * 2 +ADF5355_MIN_OUTB_FREQ = ADF5355_MIN_VCO_FREQ * 2 + +ADF5355_MAX_FREQ_PFD = int32(125.0 * MHz) +ADF5355_MODULUS1 = int32(16777216) +ADF5355_MAX_MODULUS2 = int32(16383) # FIXME: ADF5356 has 28 bits MOD2 +ADF5355_MAX_R_CNT = int32(1023) class ADF5355: @@ -25,17 +50,57 @@ class ADF5355: :param cpld_device: Mirny CPLD device name :param sw_device: Mirny RF switch device name :param channel: Mirny RF channel index + :param ref_doubler: enable/disable reference clock doubler + :param ref_divider: enable/disable reference clock divide-by-2 :param core_device: Core device name (default: "core") """ - kernel_invariants = {"cpld", "sw", "channel", "core"} - def __init__(self, dmgr, cpld_device, sw_device, channel, - core="core"): + kernel_invariants = {"cpld", "sw", "channel", "core", "sysclk"} + + def __init__( + self, + dmgr, + cpld_device, + sw_device, + channel, + ref_doubler=False, + ref_divider=False, + core="core", + ): self.cpld = dmgr.get(cpld_device) self.sw = dmgr.get(sw_device) self.channel = channel self.core = dmgr.get(core) + self.ref_doubler = ref_doubler + self.ref_divider = ref_divider + self.sysclk = self.cpld.refclk + assert 10 <= self.sysclk / 1e6 <= 600 + + self._init_registers() + + @kernel + def init(self, blind=False): + """ + Initialize and configure the PLL. + + :param blind: Do not attempt to verify presence. + """ + if not blind: + # MUXOUT = VDD + self.write(ADF5355_REG4_MUXOUT(1) | 4) + delay(5000 * us) + if not self.read_muxout(): + raise ValueError("MUXOUT not high") + delay(1000 * us) + + # MUXOUT = DGND + self.write(ADF5355_REG4_MUXOUT(2) | 4) + delay(5000 * us) + if self.read_muxout(): + raise ValueError("MUXOUT not low") + delay(1000 * us) + @kernel def set_att_mu(self, att): """Set digital step attenuator in machine units. @@ -53,13 +118,393 @@ class ADF5355: return bool(self.cpld.read_reg(0) & (1 << (self.channel + 8))) @kernel - def init(self): - self.write((1 << 27) | 4) - if not self.read_muxout(): - raise ValueError("MUXOUT not high") - delay(100*us) - self.write((2 << 27) | 4) - if self.read_muxout(): - raise ValueError("MUXOUT not low") - delay(100*us) - self.write((6 << 27) | 4) + def set_frequency(self, f): + """ + Output given frequency on output A. + + :param f: 53.125 MHz <= f <= 6800 MHz + """ + freq = int64(round(f)) + + if freq > ADF5355_MAX_VCO_FREQ: + raise ValueError("Requested too high frequency") + + # select minimal output divider + rf_div_sel = 0 + while freq < ADF5355_MIN_VCO_FREQ: + freq <<= 1 + rf_div_sel += 1 + + if (1 << rf_div_sel) > 64: + raise ValueError("Requested too low frequency") + + # choose reference divider that maximizes PFD frequency + self.regs[4] = ADF5355_REG4_R_COUNTER_UPDATE( + self.regs[4], self._compute_reference_counter() + ) + f_pfd = self.f_pfd() + + # choose prescaler + if freq > int64(6e9): + self.regs[0] |= ADF5355_REG0_PRESCALER(1) # 8/9 + n_min, n_max = 75, 65535 + + # adjust reference divider to be able to match n_min constraint + while n_min * f_pfd > freq: + r = ADF5355_REG4_R_COUNTER_GET(self.regs[4]) + self.regs[4] = ADF5355_REG4_R_COUNTER_UPDATE(self.regs[4], r + 1) + f_pfd = self.f_pfd() + else: + self.regs[0] &= ~ADF5355_REG0_PRESCALER(1) # 4/5 + n_min, n_max = 23, 32767 + + # calculate PLL parameters + n, frac1, (frac2_msb, frac2_lsb), (mod2_msb, mod2_lsb) = calculate_pll( + freq, f_pfd + ) + + if not (n_min <= n <= n_max): + raise ValueError("Invalid INT value") + + # configure PLL + self.regs[0] = ADF5355_REG0_INT_VALUE_UPDATE(self.regs[0], n) + self.regs[1] = ADF5355_REG1_MAIN_FRAC_VALUE_UPDATE(self.regs[1], frac1) + self.regs[2] = ADF5355_REG2_AUX_FRAC_LSB_VALUE_UPDATE(self.regs[2], frac2_lsb) + self.regs[2] = ADF5355_REG2_AUX_MOD_LSB_VALUE_UPDATE(self.regs[2], mod2_lsb) + self.regs[13] = ADF5355_REG13_AUX_FRAC_MSB_VALUE_UPDATE( + self.regs[13], frac2_msb + ) + self.regs[13] = ADF5355_REG13_AUX_MOD_MSB_VALUE_UPDATE(self.regs[13], mod2_msb) + + self.regs[6] = ADF5355_REG6_RF_DIVIDER_SELECT_UPDATE(self.regs[6], rf_div_sel) + self.regs[6] = ADF5355_REG6_CP_BLEED_CURRENT_UPDATE( + self.regs[6], int32(floor(24 * f_pfd / (61.44 * MHz))) + ) + self.regs[9] = ADF5355_REG9_VCO_BAND_DIVISION_UPDATE( + self.regs[9], int32(ceil(f_pfd / 160e3)) + ) + + # commit + # TODO: frequency update sync + self.sync() + + @kernel + def sync(self): + """ + Write all registers to the device. Attempts to lock the PLL. + """ + f_pfd = self.f_pfd() + + if f_pfd <= 75.0 * MHz: + for i in range(13, 0, -1): + self.write(self.regs[i]) + delay(200 * us) + self.write(self.regs[0] | ADF5355_REG0_AUTOCAL(1)) + else: + # AUTOCAL AT HALF PFD FREQUENCY + + # calculate PLL at f_pfd/2 + n, frac1, (frac2_msb, frac2_lsb), (mod2_msb, mod2_lsb) = calculate_pll( + self.f_vco(), f_pfd >> 1 + ) + + self.write( + 13 + | ADF5355_REG13_AUX_FRAC_MSB_VALUE(frac2_msb) + | ADF5355_REG13_AUX_MOD_MSB_VALUE(mod2_msb) + ) + + for i in range(12, 4, -1): + self.write(self.regs[i]) + + self.write( + ADF5355_REG4_R_COUNTER_UPDATE(self.regs[4], 2 * self.ref_counter()) + ) + + self.write(self.regs[3]) + self.write( + 2 + | ADF5355_REG2_AUX_MOD_LSB_VALUE(mod2_lsb) + | ADF5355_REG2_AUX_FRAC_LSB_VALUE(frac2_lsb) + ) + self.write(1 | ADF5355_REG1_MAIN_FRAC_VALUE(frac1)) + + delay(200 * us) + self.write(ADF5355_REG0_INT_VALUE(n) | ADF5355_REG0_AUTOCAL(1)) + + # RELOCK AT WANTED PFD FREQUENCY + + for i in [4, 2, 1]: + self.write(self.regs[i]) + + # force-disable autocal + self.write(self.regs[0] & ~ADF5355_REG0_AUTOCAL(1)) + + @portable + def f_pfd(self) -> TInt64: + """ + Return the PFD frequency for the cached set of registers. + """ + r = ADF5355_REG4_R_COUNTER_GET(self.regs[4]) + d = ADF5355_REG4_R_DOUBLER_GET(self.regs[4]) + t = ADF5355_REG4_R_DIVIDER_GET(self.regs[4]) + return self._compute_pfd_frequency(r, d, t) + + @portable + def f_vco(self) -> TInt64: + """ + Return the VCO frequency for the cached set of registers. + """ + return int64( + self.f_pfd() + * ( + self.pll_n() + + (self.pll_frac1() + self.pll_frac2() / self.pll_mod2()) + / ADF5355_MODULUS1 + ) + ) + + @portable + def pll_n(self) -> TInt32: + """ + Return the PLL integer value (INT) for the cached set of registers. + """ + return ADF5355_REG0_INT_VALUE_GET(self.regs[0]) + + @portable + def pll_frac1(self) -> TInt32: + """ + Return the main fractional value (FRAC1) for the cached set of registers. + """ + return ADF5355_REG1_MAIN_FRAC_VALUE_GET(self.regs[1]) + + @portable + def pll_frac2(self) -> TInt32: + """ + Return the auxiliary fractional value (FRAC2) for the cached set of registers. + """ + return ( + ADF5355_REG13_AUX_FRAC_MSB_VALUE_GET(self.regs[13]) << 14 + ) | ADF5355_REG2_AUX_FRAC_LSB_VALUE_GET(self.regs[2]) + + @portable + def pll_mod2(self) -> TInt32: + """ + Return the auxiliary modulus value (MOD2) for the cached set of registers. + """ + return ( + ADF5355_REG13_AUX_MOD_MSB_VALUE_GET(self.regs[13]) << 14 + ) | ADF5355_REG2_AUX_MOD_LSB_VALUE_GET(self.regs[2]) + + @portable + def ref_counter(self) -> TInt32: + """ + Return the reference counter value (R) for the cached set of registers. + """ + return ADF5355_REG4_R_COUNTER_GET(self.regs[4]) + + @rpc + def info(self): + output_divider = 1 << ADF5355_REG6_RF_DIVIDER_SELECT_GET(self.regs[6]) + prescaler = ADF5355_REG0_PRESCALER_GET(self.regs[0]) + return { + # output + "f_outA": self.f_vco() / output_divider, + "f_outB": self.f_vco() * 2, + "output_divider": output_divider, + # PLL parameters + "f_vco": self.f_vco(), + "pll_n": self.pll_n(), + "pll_frac1": self.pll_frac1(), + "pll_frac2": self.pll_frac2(), + "pll_mod2": self.pll_mod2(), + "prescaler": "4/5" if prescaler == 0 else "8/9", + # reference / PFD + "sysclk": self.sysclk, + "ref_doubler": self.ref_doubler, + "ref_divider": self.ref_divider, + "ref_counter": self.ref_counter(), + "f_pfd": self.f_pfd(), + } + + @portable + def _init_registers(self): + """ + Initialize cached registers with sensible defaults. + """ + # fill with control bits + self.regs = [int32(i) for i in range(ADF5355_NUM_REGS)] + + # REG2 + # ==== + + # avoid divide-by-zero + self.regs[2] |= ADF5355_REG2_AUX_MOD_LSB_VALUE(1) + + # REG4 + # ==== + + # single-ended reference mode is recommended + # for references up to 250 MHz, even if the signal is differential + if self.sysclk <= 250 * MHz: + self.regs[4] |= ADF5355_REG4_REF_MODE(0) + else: + self.regs[4] |= ADF5355_REG4_REF_MODE(1) + + # phase detector polarity: positive + self.regs[4] |= ADF5355_REG4_PD_POLARITY(1) + + # charge pump current: 0.94 mA + self.regs[4] |= ADF5355_REG4_CURRENT_SETTING(2) + + # MUXOUT: digital lock detect + self.regs[4] |= ADF5355_REG4_MUX_LOGIC(1) # 3v3 logic + self.regs[4] |= ADF5355_REG4_MUXOUT(6) + + # setup reference path + if self.ref_doubler: + self.regs[4] |= ADF5355_REG4_R_DOUBLER(1) + + if self.ref_divider: + self.regs[4] |= ADF5355_REG4_R_DIVIDER(1) + + r = self._compute_reference_counter() + self.regs[4] |= ADF5355_REG4_R_COUNTER(r) + + # REG5 + # ==== + + # reserved values + self.regs[5] = int32(0x800025) + + # REG6 + # ==== + + # reserved values + self.regs[6] = int32(0x14000006) + + # enable negative bleed + self.regs[6] |= ADF5355_REG6_NEGATIVE_BLEED(1) + + # charge pump bleed current + # self.regs[6] |= ADF5355_REG6_CP_BLEED_CURRENT( + # int32(floor(24 * self.f_pfd / (61.44 * MHz))) + # ) + + # direct feedback from VCO to N counter + self.regs[6] |= ADF5355_REG6_FB_SELECT(1) + + # mute until the PLL is locked + self.regs[6] |= ADF5355_REG6_MUTE_TILL_LD(1) + + # enable output A + self.regs[6] |= ADF5355_REG6_RF_OUTPUT_A_ENABLE(1) + + # set output A power to max power, is adjusted by extra attenuator + self.regs[6] |= ADF5355_REG6_RF_OUTPUT_A_POWER(3) # +5 dBm + + # REG7 + # ==== + + # reserved values + self.regs[7] = int32(0x10000007) + + # sync load-enable to reference + self.regs[7] |= ADF5355_REG7_LE_SYNC(1) + + # frac-N lock-detect precision: 12 ns + self.regs[7] |= ADF5355_REG7_FRAC_N_LD_PRECISION(3) + + # REG8 + # ==== + + # reserved values + self.regs[8] = int32(0x102D0428) + + # REG9 + # ==== + + # default timeouts (from eval software) + self.regs[9] |= ( + ADF5355_REG9_SYNTH_LOCK_TIMEOUT(13) + | ADF5355_REG9_AUTOCAL_TIMEOUT(31) + | ADF5355_REG9_TIMEOUT(0x67) + ) + + # REG10 + # ===== + + # reserved values + self.regs[10] = int32(0xC0000A) + + # ADC defaults (from eval software) + self.regs[10] |= ( + ADF5355_REG10_ADC_ENABLE(1) + | ADF5355_REG10_ADC_CLK_DIV(256) + | ADF5355_REG10_ADC_CONV(1) + ) + + # REG11 + # ===== + + # reserved values + self.regs[11] = int32(0x61200B) + + # REG12 + # ===== + + # reserved values + self.regs[12] = int32(0x15FC) + + @portable + def _compute_pfd_frequency(self, r, d, t) -> TInt64: + """ + Calculate the PFD frequency from the given reference path parameters + """ + return int64(self.sysclk * ((1 + d) / (r * (1 + t)))) + + @portable + def _compute_reference_counter(self) -> TInt32: + """ + Determine the reference counter R that maximizes the PFD frequency + """ + d = ADF5355_REG4_R_DOUBLER_GET(self.regs[4]) + t = ADF5355_REG4_R_DIVIDER_GET(self.regs[4]) + r = 1 + while self._compute_pfd_frequency(r, d, t) > ADF5355_MAX_FREQ_PFD: + r += 1 + return int32(r) + + +@portable +def calculate_pll(f_vco: TInt64, f_pfd: TInt64): + """ + Calculate fractional-N PLL parameters such that + + f_vco = f_pfd * (n + (frac1 + frac2/mod2) / mod1) + + where + mod1 = 16777216 + mod2 = 16383 + """ + f_pfd = int64(f_pfd) + f_vco = int64(f_vco) + + # integral part + n = int32(f_vco / f_pfd) + r = f_vco / f_pfd - n + + # main fractional part + frac1 = int32(ADF5355_MODULUS1 * r) + r = r * ADF5355_MODULUS1 - frac1 + + # auxiliary fractional part + # FIXME: calculate optimal MOD2 + mod2 = ADF5355_MAX_MODULUS2 + frac2 = int32(r * mod2) + + # split frac2, mod2 + frac2_msb, frac2_lsb = (frac2 >> 14) & 0x3FFF, frac2 & 0x3FFF + mod2_msb, mod2_lsb = (mod2 >> 14) & 0x3FFF, mod2 & 0x3FFF + + return n, frac1, (frac2_msb, frac2_lsb), (mod2_msb, mod2_lsb) diff --git a/artiq/coredevice/adf5355_reg.py b/artiq/coredevice/adf5355_reg.py new file mode 100644 index 000000000..9eb0830df --- /dev/null +++ b/artiq/coredevice/adf5355_reg.py @@ -0,0 +1,742 @@ +# auto-generated, do not edit +from artiq.language.core import portable +from artiq.language.types import TInt32 +from numpy import int32 + + +@portable +def ADF5355_REG0_AUTOCAL_GET(reg: TInt32) -> TInt32: + return int32((reg >> 21) & 0x1) + + +@portable +def ADF5355_REG0_AUTOCAL(x: TInt32) -> TInt32: + return int32((x & 0x1) << 21) + + +@portable +def ADF5355_REG0_AUTOCAL_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 21)) | ((x & 0x1) << 21)) + + +@portable +def ADF5355_REG0_INT_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0xFFFF) + + +@portable +def ADF5355_REG0_INT_VALUE(x: TInt32) -> TInt32: + return int32((x & 0xFFFF) << 4) + + +@portable +def ADF5355_REG0_INT_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xFFFF << 4)) | ((x & 0xFFFF) << 4)) + + +@portable +def ADF5355_REG0_PRESCALER_GET(reg: TInt32) -> TInt32: + return int32((reg >> 20) & 0x1) + + +@portable +def ADF5355_REG0_PRESCALER(x: TInt32) -> TInt32: + return int32((x & 0x1) << 20) + + +@portable +def ADF5355_REG0_PRESCALER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 20)) | ((x & 0x1) << 20)) + + +@portable +def ADF5355_REG1_MAIN_FRAC_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0xFFFFFF) + + +@portable +def ADF5355_REG1_MAIN_FRAC_VALUE(x: TInt32) -> TInt32: + return int32((x & 0xFFFFFF) << 4) + + +@portable +def ADF5355_REG1_MAIN_FRAC_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xFFFFFF << 4)) | ((x & 0xFFFFFF) << 4)) + + +@portable +def ADF5355_REG2_AUX_FRAC_LSB_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 18) & 0x3FFF) + + +@portable +def ADF5355_REG2_AUX_FRAC_LSB_VALUE(x: TInt32) -> TInt32: + return int32((x & 0x3FFF) << 18) + + +@portable +def ADF5355_REG2_AUX_FRAC_LSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3FFF << 18)) | ((x & 0x3FFF) << 18)) + + +@portable +def ADF5355_REG2_AUX_MOD_LSB_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0x3FFF) + + +@portable +def ADF5355_REG2_AUX_MOD_LSB_VALUE(x: TInt32) -> TInt32: + return int32((x & 0x3FFF) << 4) + + +@portable +def ADF5355_REG2_AUX_MOD_LSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3FFF << 4)) | ((x & 0x3FFF) << 4)) + + +@portable +def ADF5355_REG3_PHASE_ADJUST_GET(reg: TInt32) -> TInt32: + return int32((reg >> 28) & 0x1) + + +@portable +def ADF5355_REG3_PHASE_ADJUST(x: TInt32) -> TInt32: + return int32((x & 0x1) << 28) + + +@portable +def ADF5355_REG3_PHASE_ADJUST_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 28)) | ((x & 0x1) << 28)) + + +@portable +def ADF5355_REG3_PHASE_RESYNC_GET(reg: TInt32) -> TInt32: + return int32((reg >> 29) & 0x1) + + +@portable +def ADF5355_REG3_PHASE_RESYNC(x: TInt32) -> TInt32: + return int32((x & 0x1) << 29) + + +@portable +def ADF5355_REG3_PHASE_RESYNC_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 29)) | ((x & 0x1) << 29)) + + +@portable +def ADF5355_REG3_PHASE_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0xFFFFFF) + + +@portable +def ADF5355_REG3_PHASE_VALUE(x: TInt32) -> TInt32: + return int32((x & 0xFFFFFF) << 4) + + +@portable +def ADF5355_REG3_PHASE_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xFFFFFF << 4)) | ((x & 0xFFFFFF) << 4)) + + +@portable +def ADF5355_REG3_SD_LOAD_RESET_GET(reg: TInt32) -> TInt32: + return int32((reg >> 30) & 0x1) + + +@portable +def ADF5355_REG3_SD_LOAD_RESET(x: TInt32) -> TInt32: + return int32((x & 0x1) << 30) + + +@portable +def ADF5355_REG3_SD_LOAD_RESET_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 30)) | ((x & 0x1) << 30)) + + +@portable +def ADF5355_REG4_COUNTER_RESET_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0x1) + + +@portable +def ADF5355_REG4_COUNTER_RESET(x: TInt32) -> TInt32: + return int32((x & 0x1) << 4) + + +@portable +def ADF5355_REG4_COUNTER_RESET_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 4)) | ((x & 0x1) << 4)) + + +@portable +def ADF5355_REG4_CP_THREE_STATE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 5) & 0x1) + + +@portable +def ADF5355_REG4_CP_THREE_STATE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 5) + + +@portable +def ADF5355_REG4_CP_THREE_STATE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 5)) | ((x & 0x1) << 5)) + + +@portable +def ADF5355_REG4_CURRENT_SETTING_GET(reg: TInt32) -> TInt32: + return int32((reg >> 10) & 0xF) + + +@portable +def ADF5355_REG4_CURRENT_SETTING(x: TInt32) -> TInt32: + return int32((x & 0xF) << 10) + + +@portable +def ADF5355_REG4_CURRENT_SETTING_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xF << 10)) | ((x & 0xF) << 10)) + + +@portable +def ADF5355_REG4_DOUBLE_BUFF_GET(reg: TInt32) -> TInt32: + return int32((reg >> 14) & 0x1) + + +@portable +def ADF5355_REG4_DOUBLE_BUFF(x: TInt32) -> TInt32: + return int32((x & 0x1) << 14) + + +@portable +def ADF5355_REG4_DOUBLE_BUFF_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 14)) | ((x & 0x1) << 14)) + + +@portable +def ADF5355_REG4_MUX_LOGIC_GET(reg: TInt32) -> TInt32: + return int32((reg >> 8) & 0x1) + + +@portable +def ADF5355_REG4_MUX_LOGIC(x: TInt32) -> TInt32: + return int32((x & 0x1) << 8) + + +@portable +def ADF5355_REG4_MUX_LOGIC_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 8)) | ((x & 0x1) << 8)) + + +@portable +def ADF5355_REG4_MUXOUT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 27) & 0x7) + + +@portable +def ADF5355_REG4_MUXOUT(x: TInt32) -> TInt32: + return int32((x & 0x7) << 27) + + +@portable +def ADF5355_REG4_MUXOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x7 << 27)) | ((x & 0x7) << 27)) + + +@portable +def ADF5355_REG4_PD_POLARITY_GET(reg: TInt32) -> TInt32: + return int32((reg >> 7) & 0x1) + + +@portable +def ADF5355_REG4_PD_POLARITY(x: TInt32) -> TInt32: + return int32((x & 0x1) << 7) + + +@portable +def ADF5355_REG4_PD_POLARITY_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 7)) | ((x & 0x1) << 7)) + + +@portable +def ADF5355_REG4_POWER_DOWN_GET(reg: TInt32) -> TInt32: + return int32((reg >> 6) & 0x1) + + +@portable +def ADF5355_REG4_POWER_DOWN(x: TInt32) -> TInt32: + return int32((x & 0x1) << 6) + + +@portable +def ADF5355_REG4_POWER_DOWN_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 6)) | ((x & 0x1) << 6)) + + +@portable +def ADF5355_REG4_R_COUNTER_GET(reg: TInt32) -> TInt32: + return int32((reg >> 15) & 0x3FF) + + +@portable +def ADF5355_REG4_R_COUNTER(x: TInt32) -> TInt32: + return int32((x & 0x3FF) << 15) + + +@portable +def ADF5355_REG4_R_COUNTER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3FF << 15)) | ((x & 0x3FF) << 15)) + + +@portable +def ADF5355_REG4_R_DIVIDER_GET(reg: TInt32) -> TInt32: + return int32((reg >> 25) & 0x1) + + +@portable +def ADF5355_REG4_R_DIVIDER(x: TInt32) -> TInt32: + return int32((x & 0x1) << 25) + + +@portable +def ADF5355_REG4_R_DIVIDER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 25)) | ((x & 0x1) << 25)) + + +@portable +def ADF5355_REG4_R_DOUBLER_GET(reg: TInt32) -> TInt32: + return int32((reg >> 26) & 0x1) + + +@portable +def ADF5355_REG4_R_DOUBLER(x: TInt32) -> TInt32: + return int32((x & 0x1) << 26) + + +@portable +def ADF5355_REG4_R_DOUBLER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 26)) | ((x & 0x1) << 26)) + + +@portable +def ADF5355_REG4_REF_MODE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 9) & 0x1) + + +@portable +def ADF5355_REG4_REF_MODE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 9) + + +@portable +def ADF5355_REG4_REF_MODE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 9)) | ((x & 0x1) << 9)) + + +@portable +def ADF5355_REG6_BLEED_POLARITY_GET(reg: TInt32) -> TInt32: + return int32((reg >> 31) & 0x1) + + +@portable +def ADF5355_REG6_BLEED_POLARITY(x: TInt32) -> TInt32: + return int32((x & 0x1) << 31) + + +@portable +def ADF5355_REG6_BLEED_POLARITY_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 31)) | ((x & 0x1) << 31)) + + +@portable +def ADF5355_REG6_CP_BLEED_CURRENT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 13) & 0xFF) + + +@portable +def ADF5355_REG6_CP_BLEED_CURRENT(x: TInt32) -> TInt32: + return int32((x & 0xFF) << 13) + + +@portable +def ADF5355_REG6_CP_BLEED_CURRENT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xFF << 13)) | ((x & 0xFF) << 13)) + + +@portable +def ADF5355_REG6_FB_SELECT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 24) & 0x1) + + +@portable +def ADF5355_REG6_FB_SELECT(x: TInt32) -> TInt32: + return int32((x & 0x1) << 24) + + +@portable +def ADF5355_REG6_FB_SELECT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 24)) | ((x & 0x1) << 24)) + + +@portable +def ADF5355_REG6_GATE_BLEED_GET(reg: TInt32) -> TInt32: + return int32((reg >> 30) & 0x1) + + +@portable +def ADF5355_REG6_GATE_BLEED(x: TInt32) -> TInt32: + return int32((x & 0x1) << 30) + + +@portable +def ADF5355_REG6_GATE_BLEED_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 30)) | ((x & 0x1) << 30)) + + +@portable +def ADF5355_REG6_MUTE_TILL_LD_GET(reg: TInt32) -> TInt32: + return int32((reg >> 11) & 0x1) + + +@portable +def ADF5355_REG6_MUTE_TILL_LD(x: TInt32) -> TInt32: + return int32((x & 0x1) << 11) + + +@portable +def ADF5355_REG6_MUTE_TILL_LD_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 11)) | ((x & 0x1) << 11)) + + +@portable +def ADF5355_REG6_NEGATIVE_BLEED_GET(reg: TInt32) -> TInt32: + return int32((reg >> 29) & 0x1) + + +@portable +def ADF5355_REG6_NEGATIVE_BLEED(x: TInt32) -> TInt32: + return int32((x & 0x1) << 29) + + +@portable +def ADF5355_REG6_NEGATIVE_BLEED_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 29)) | ((x & 0x1) << 29)) + + +@portable +def ADF5355_REG6_RF_DIVIDER_SELECT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 21) & 0x7) + + +@portable +def ADF5355_REG6_RF_DIVIDER_SELECT(x: TInt32) -> TInt32: + return int32((x & 0x7) << 21) + + +@portable +def ADF5355_REG6_RF_DIVIDER_SELECT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x7 << 21)) | ((x & 0x7) << 21)) + + +@portable +def ADF5355_REG6_RF_OUTPUT_A_ENABLE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 6) & 0x1) + + +@portable +def ADF5355_REG6_RF_OUTPUT_A_ENABLE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 6) + + +@portable +def ADF5355_REG6_RF_OUTPUT_A_ENABLE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 6)) | ((x & 0x1) << 6)) + + +@portable +def ADF5355_REG6_RF_OUTPUT_A_POWER_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0x3) + + +@portable +def ADF5355_REG6_RF_OUTPUT_A_POWER(x: TInt32) -> TInt32: + return int32((x & 0x3) << 4) + + +@portable +def ADF5355_REG6_RF_OUTPUT_A_POWER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3 << 4)) | ((x & 0x3) << 4)) + + +@portable +def ADF5355_REG6_RF_OUTPUT_B_ENABLE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 10) & 0x1) + + +@portable +def ADF5355_REG6_RF_OUTPUT_B_ENABLE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 10) + + +@portable +def ADF5355_REG6_RF_OUTPUT_B_ENABLE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 10)) | ((x & 0x1) << 10)) + + +@portable +def ADF5355_REG7_FRAC_N_LD_PRECISION_GET(reg: TInt32) -> TInt32: + return int32((reg >> 5) & 0x3) + + +@portable +def ADF5355_REG7_FRAC_N_LD_PRECISION(x: TInt32) -> TInt32: + return int32((x & 0x3) << 5) + + +@portable +def ADF5355_REG7_FRAC_N_LD_PRECISION_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3 << 5)) | ((x & 0x3) << 5)) + + +@portable +def ADF5355_REG7_LD_CYCLE_COUNT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 8) & 0x3) + + +@portable +def ADF5355_REG7_LD_CYCLE_COUNT(x: TInt32) -> TInt32: + return int32((x & 0x3) << 8) + + +@portable +def ADF5355_REG7_LD_CYCLE_COUNT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3 << 8)) | ((x & 0x3) << 8)) + + +@portable +def ADF5355_REG7_LD_MODE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0x1) + + +@portable +def ADF5355_REG7_LD_MODE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 4) + + +@portable +def ADF5355_REG7_LD_MODE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 4)) | ((x & 0x1) << 4)) + + +@portable +def ADF5355_REG7_LE_SEL_SYNC_EDGE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 27) & 0x1) + + +@portable +def ADF5355_REG7_LE_SEL_SYNC_EDGE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 27) + + +@portable +def ADF5355_REG7_LE_SEL_SYNC_EDGE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 27)) | ((x & 0x1) << 27)) + + +@portable +def ADF5355_REG7_LE_SYNC_GET(reg: TInt32) -> TInt32: + return int32((reg >> 25) & 0x1) + + +@portable +def ADF5355_REG7_LE_SYNC(x: TInt32) -> TInt32: + return int32((x & 0x1) << 25) + + +@portable +def ADF5355_REG7_LE_SYNC_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 25)) | ((x & 0x1) << 25)) + + +@portable +def ADF5355_REG7_LOL_MODE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 7) & 0x1) + + +@portable +def ADF5355_REG7_LOL_MODE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 7) + + +@portable +def ADF5355_REG7_LOL_MODE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 7)) | ((x & 0x1) << 7)) + + +@portable +def ADF5355_REG9_AUTOCAL_TIMEOUT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 9) & 0x1F) + + +@portable +def ADF5355_REG9_AUTOCAL_TIMEOUT(x: TInt32) -> TInt32: + return int32((x & 0x1F) << 9) + + +@portable +def ADF5355_REG9_AUTOCAL_TIMEOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1F << 9)) | ((x & 0x1F) << 9)) + + +@portable +def ADF5355_REG9_SYNTH_LOCK_TIMEOUT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0x1F) + + +@portable +def ADF5355_REG9_SYNTH_LOCK_TIMEOUT(x: TInt32) -> TInt32: + return int32((x & 0x1F) << 4) + + +@portable +def ADF5355_REG9_SYNTH_LOCK_TIMEOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1F << 4)) | ((x & 0x1F) << 4)) + + +@portable +def ADF5355_REG9_TIMEOUT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 14) & 0x3FF) + + +@portable +def ADF5355_REG9_TIMEOUT(x: TInt32) -> TInt32: + return int32((x & 0x3FF) << 14) + + +@portable +def ADF5355_REG9_TIMEOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3FF << 14)) | ((x & 0x3FF) << 14)) + + +@portable +def ADF5355_REG9_VCO_BAND_DIVISION_GET(reg: TInt32) -> TInt32: + return int32((reg >> 24) & 0xFF) + + +@portable +def ADF5355_REG9_VCO_BAND_DIVISION(x: TInt32) -> TInt32: + return int32((x & 0xFF) << 24) + + +@portable +def ADF5355_REG9_VCO_BAND_DIVISION_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xFF << 24)) | ((x & 0xFF) << 24)) + + +@portable +def ADF5355_REG10_ADC_CLK_DIV_GET(reg: TInt32) -> TInt32: + return int32((reg >> 6) & 0xFF) + + +@portable +def ADF5355_REG10_ADC_CLK_DIV(x: TInt32) -> TInt32: + return int32((x & 0xFF) << 6) + + +@portable +def ADF5355_REG10_ADC_CLK_DIV_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xFF << 6)) | ((x & 0xFF) << 6)) + + +@portable +def ADF5355_REG10_ADC_CONV_GET(reg: TInt32) -> TInt32: + return int32((reg >> 5) & 0x1) + + +@portable +def ADF5355_REG10_ADC_CONV(x: TInt32) -> TInt32: + return int32((x & 0x1) << 5) + + +@portable +def ADF5355_REG10_ADC_CONV_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 5)) | ((x & 0x1) << 5)) + + +@portable +def ADF5355_REG10_ADC_ENABLE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0x1) + + +@portable +def ADF5355_REG10_ADC_ENABLE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 4) + + +@portable +def ADF5355_REG10_ADC_ENABLE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 4)) | ((x & 0x1) << 4)) + + +@portable +def ADF5355_REG11_VCO_BAND_HOLD_GET(reg: TInt32) -> TInt32: + return int32((reg >> 24) & 0x1) + + +@portable +def ADF5355_REG11_VCO_BAND_HOLD(x: TInt32) -> TInt32: + return int32((x & 0x1) << 24) + + +@portable +def ADF5355_REG11_VCO_BAND_HOLD_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 24)) | ((x & 0x1) << 24)) + + +@portable +def ADF5355_REG12_PHASE_RESYNC_CLK_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 12) & 0xFFFFF) + + +@portable +def ADF5355_REG12_PHASE_RESYNC_CLK_VALUE(x: TInt32) -> TInt32: + return int32((x & 0xFFFFF) << 12) + + +@portable +def ADF5355_REG12_PHASE_RESYNC_CLK_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xFFFFF << 12)) | ((x & 0xFFFFF) << 12)) + + +@portable +def ADF5355_REG13_AUX_FRAC_MSB_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 18) & 0x3FFF) + + +@portable +def ADF5355_REG13_AUX_FRAC_MSB_VALUE(x: TInt32) -> TInt32: + return int32((x & 0x3FFF) << 18) + + +@portable +def ADF5355_REG13_AUX_FRAC_MSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3FFF << 18)) | ((x & 0x3FFF) << 18)) + + +@portable +def ADF5355_REG13_AUX_MOD_MSB_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0x3FFF) + + +@portable +def ADF5355_REG13_AUX_MOD_MSB_VALUE(x: TInt32) -> TInt32: + return int32((x & 0x3FFF) << 4) + + +@portable +def ADF5355_REG13_AUX_MOD_MSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3FFF << 4)) | ((x & 0x3FFF) << 4)) + + +ADF5355_NUM_REGS = 14 diff --git a/artiq/coredevice/mirny.py b/artiq/coredevice/mirny.py index 813e72bcb..2c533d4f8 100644 --- a/artiq/coredevice/mirny.py +++ b/artiq/coredevice/mirny.py @@ -9,10 +9,16 @@ from numpy import int32 from artiq.coredevice import spi2 as spi -SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END | - 0*spi.SPI_INPUT | 1*spi.SPI_CS_POLARITY | - 0*spi.SPI_CLK_POLARITY | 0*spi.SPI_CLK_PHASE | - 0*spi.SPI_LSB_FIRST | 0*spi.SPI_HALF_DUPLEX) +SPI_CONFIG = ( + 0 * spi.SPI_OFFLINE + | 0 * spi.SPI_END + | 0 * spi.SPI_INPUT + | 1 * spi.SPI_CS_POLARITY + | 0 * spi.SPI_CLK_POLARITY + | 0 * spi.SPI_CLK_PHASE + | 0 * spi.SPI_LSB_FIRST + | 0 * spi.SPI_HALF_DUPLEX +) # SPI clock write and read dividers SPIT_WR = 4 @@ -24,41 +30,65 @@ WE = 1 << 24 class Mirny: - """Mirny PLL-based RF generator. + """ + Mirny PLL-based RF generator. :param spi_device: SPI bus device + :param refclk: Reference clock (SMA, MMCX or on-board 100 MHz oscillator) + frequency in Hz + :param clk_sel: Reference clock selection. + valid options are: 0 - internal 100MHz XO; 1 - front-panel SMA; 2 - + internal MMCX :param core_device: Core device name (default: "core") """ + kernel_invariants = {"bus", "core"} - def __init__(self, dmgr, spi_device, core_device="core"): + def __init__(self, dmgr, spi_device, refclk=100e6, clk_sel=0, core_device="core"): self.core = dmgr.get(core_device) self.bus = dmgr.get(spi_device) + self.refclk = refclk + assert 10 <= self.refclk / 1e6 <= 600, "Invalid refclk" + + self.clk_sel = clk_sel & 0b11 + assert 0 <= self.clk_sel <= 3, "Invalid clk_sel" + + # TODO: support clk_div on v1.0 boards + @kernel def read_reg(self, addr): """Read a register""" - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, 24, - SPIT_RD, SPI_CS) + self.bus.set_config_mu( + SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, 24, SPIT_RD, SPI_CS + ) self.bus.write((addr << 25)) - return self.bus.read() & int32(0xffff) + return self.bus.read() & int32(0xFFFF) @kernel def write_reg(self, addr, data): """Write a register""" self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 24, SPIT_WR, SPI_CS) - self.bus.write((addr << 25) | WE | ((data & 0xffff) << 8)) + self.bus.write((addr << 25) | WE | ((data & 0xFFFF) << 8)) @kernel - def init(self): - """Initialize Mirny by reading the status register and verifying - compatible hardware and protocol revisions""" - reg0 = self.read_reg(0) - if reg0 & 0b11 != 0b11: - raise ValueError("Mirny HW_REV mismatch") - if (reg0 >> 2) & 0b11 != 0b00: - raise ValueError("Mirny PROTO_REV mismatch") - delay(100*us) # slack + def init(self, blind=False): + """ + Initialize and detect Mirny. + + :param blind: Do not attempt to verify presence and compatibility. + """ + if not blind: + reg0 = self.read_reg(0) + if reg0 & 0b11 != 0b11: + raise ValueError("Mirny HW_REV mismatch") + if (reg0 >> 2) & 0b11 != 0b00: + raise ValueError("Mirny PROTO_REV mismatch") + delay(100 * us) # slack + + # select clock source + self.write_reg(1, (self.clk_sel << 4)) + delay(1000 * us) @kernel def set_att_mu(self, channel, att): @@ -74,8 +104,7 @@ class Mirny: """Perform SPI write to a prefixed address""" self.bus.set_config_mu(SPI_CONFIG, 8, SPIT_WR, SPI_CS) self.bus.write(addr << 25) - self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, length, - SPIT_WR, SPI_CS) + self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, length, SPIT_WR, SPI_CS) if length < 32: data <<= 32 - length self.bus.write(data) From b856df7c358f06579eb314cf3522d62f5114ff11 Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Mon, 9 Nov 2020 14:50:32 +0100 Subject: [PATCH 2422/2457] coredevice: adf5355: cleanup, style --- artiq/coredevice/adf5355.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/artiq/coredevice/adf5355.py b/artiq/coredevice/adf5355.py index 6bfd18da5..03a4aa2f2 100644 --- a/artiq/coredevice/adf5355.py +++ b/artiq/coredevice/adf5355.py @@ -9,13 +9,12 @@ on Mirny-style prefixed SPI buses. # https://www.analog.com/media/en/technical-documentation/user-guides/EV-ADF5356SD1Z-UG-1087.pdf -from artiq.language.core import kernel, portable, rpc, delay +from artiq.language.core import kernel, portable, delay from artiq.language.units import us, GHz, MHz from artiq.language.types import TInt32, TInt64 from artiq.coredevice import spi2 as spi from artiq.coredevice.adf5355_reg import * -from fractions import Fraction from numpy import int32, int64, floor, ceil @@ -303,7 +302,6 @@ class ADF5355: """ return ADF5355_REG4_R_COUNTER_GET(self.regs[4]) - @rpc def info(self): output_divider = 1 << ADF5355_REG6_RF_DIVIDER_SELECT_GET(self.regs[6]) prescaler = ADF5355_REG0_PRESCALER_GET(self.regs[0]) From d433f6e86dd54036b9a315752a5bac50183acfc9 Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Mon, 9 Nov 2020 18:09:50 +0100 Subject: [PATCH 2423/2457] coredevice: adf5355: more general PLL parameters calculation Signed-off-by: Etienne Wodey --- artiq/coredevice/adf5355.py | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/artiq/coredevice/adf5355.py b/artiq/coredevice/adf5355.py index 03a4aa2f2..3f862c54b 100644 --- a/artiq/coredevice/adf5355.py +++ b/artiq/coredevice/adf5355.py @@ -474,6 +474,18 @@ class ADF5355: return int32(r) +@portable +def gcd(a, b): + while b: + a, b = b, a % b + return a + + +@portable +def split_msb_lsb_28b(v): + return int32((v >> 14) & 0x3FFF), int32(v & 0x3FFF) + + @portable def calculate_pll(f_vco: TInt64, f_pfd: TInt64): """ @@ -489,20 +501,21 @@ def calculate_pll(f_vco: TInt64, f_pfd: TInt64): f_vco = int64(f_vco) # integral part - n = int32(f_vco / f_pfd) - r = f_vco / f_pfd - n + n, r = int32(f_vco // f_pfd), f_vco % f_pfd # main fractional part - frac1 = int32(ADF5355_MODULUS1 * r) - r = r * ADF5355_MODULUS1 - frac1 + r *= ADF5355_MODULUS1 + frac1, frac2 = int32(r // f_pfd), r % f_pfd # auxiliary fractional part - # FIXME: calculate optimal MOD2 - mod2 = ADF5355_MAX_MODULUS2 - frac2 = int32(r * mod2) + mod2 = f_pfd - # split frac2, mod2 - frac2_msb, frac2_lsb = (frac2 >> 14) & 0x3FFF, frac2 & 0x3FFF - mod2_msb, mod2_lsb = (mod2 >> 14) & 0x3FFF, mod2 & 0x3FFF + while mod2 > ADF5355_MAX_MODULUS2: + mod2 >>= 1 + frac2 >>= 1 - return n, frac1, (frac2_msb, frac2_lsb), (mod2_msb, mod2_lsb) + gcd_div = gcd(frac2, mod2) + mod2 //= gcd_div + frac2 //= gcd_div + + return n, frac1, split_msb_lsb_28b(frac2), split_msb_lsb_28b(mod2) From b200465cce6b6ab2c119993a3046e1db8c7e44e8 Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Mon, 9 Nov 2020 18:26:17 +0100 Subject: [PATCH 2424/2457] coredevice: adf5355: rename to adf5356 Signed-off-by: Etienne Wodey --- artiq/coredevice/adf5355_reg.py | 742 -------------------- artiq/coredevice/{adf5355.py => adf5356.py} | 183 ++--- artiq/coredevice/adf5356_reg.py | 642 +++++++++++++++++ 3 files changed, 736 insertions(+), 831 deletions(-) delete mode 100644 artiq/coredevice/adf5355_reg.py rename artiq/coredevice/{adf5355.py => adf5356.py} (69%) create mode 100644 artiq/coredevice/adf5356_reg.py diff --git a/artiq/coredevice/adf5355_reg.py b/artiq/coredevice/adf5355_reg.py deleted file mode 100644 index 9eb0830df..000000000 --- a/artiq/coredevice/adf5355_reg.py +++ /dev/null @@ -1,742 +0,0 @@ -# auto-generated, do not edit -from artiq.language.core import portable -from artiq.language.types import TInt32 -from numpy import int32 - - -@portable -def ADF5355_REG0_AUTOCAL_GET(reg: TInt32) -> TInt32: - return int32((reg >> 21) & 0x1) - - -@portable -def ADF5355_REG0_AUTOCAL(x: TInt32) -> TInt32: - return int32((x & 0x1) << 21) - - -@portable -def ADF5355_REG0_AUTOCAL_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 21)) | ((x & 0x1) << 21)) - - -@portable -def ADF5355_REG0_INT_VALUE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 4) & 0xFFFF) - - -@portable -def ADF5355_REG0_INT_VALUE(x: TInt32) -> TInt32: - return int32((x & 0xFFFF) << 4) - - -@portable -def ADF5355_REG0_INT_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0xFFFF << 4)) | ((x & 0xFFFF) << 4)) - - -@portable -def ADF5355_REG0_PRESCALER_GET(reg: TInt32) -> TInt32: - return int32((reg >> 20) & 0x1) - - -@portable -def ADF5355_REG0_PRESCALER(x: TInt32) -> TInt32: - return int32((x & 0x1) << 20) - - -@portable -def ADF5355_REG0_PRESCALER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 20)) | ((x & 0x1) << 20)) - - -@portable -def ADF5355_REG1_MAIN_FRAC_VALUE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 4) & 0xFFFFFF) - - -@portable -def ADF5355_REG1_MAIN_FRAC_VALUE(x: TInt32) -> TInt32: - return int32((x & 0xFFFFFF) << 4) - - -@portable -def ADF5355_REG1_MAIN_FRAC_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0xFFFFFF << 4)) | ((x & 0xFFFFFF) << 4)) - - -@portable -def ADF5355_REG2_AUX_FRAC_LSB_VALUE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 18) & 0x3FFF) - - -@portable -def ADF5355_REG2_AUX_FRAC_LSB_VALUE(x: TInt32) -> TInt32: - return int32((x & 0x3FFF) << 18) - - -@portable -def ADF5355_REG2_AUX_FRAC_LSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x3FFF << 18)) | ((x & 0x3FFF) << 18)) - - -@portable -def ADF5355_REG2_AUX_MOD_LSB_VALUE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 4) & 0x3FFF) - - -@portable -def ADF5355_REG2_AUX_MOD_LSB_VALUE(x: TInt32) -> TInt32: - return int32((x & 0x3FFF) << 4) - - -@portable -def ADF5355_REG2_AUX_MOD_LSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x3FFF << 4)) | ((x & 0x3FFF) << 4)) - - -@portable -def ADF5355_REG3_PHASE_ADJUST_GET(reg: TInt32) -> TInt32: - return int32((reg >> 28) & 0x1) - - -@portable -def ADF5355_REG3_PHASE_ADJUST(x: TInt32) -> TInt32: - return int32((x & 0x1) << 28) - - -@portable -def ADF5355_REG3_PHASE_ADJUST_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 28)) | ((x & 0x1) << 28)) - - -@portable -def ADF5355_REG3_PHASE_RESYNC_GET(reg: TInt32) -> TInt32: - return int32((reg >> 29) & 0x1) - - -@portable -def ADF5355_REG3_PHASE_RESYNC(x: TInt32) -> TInt32: - return int32((x & 0x1) << 29) - - -@portable -def ADF5355_REG3_PHASE_RESYNC_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 29)) | ((x & 0x1) << 29)) - - -@portable -def ADF5355_REG3_PHASE_VALUE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 4) & 0xFFFFFF) - - -@portable -def ADF5355_REG3_PHASE_VALUE(x: TInt32) -> TInt32: - return int32((x & 0xFFFFFF) << 4) - - -@portable -def ADF5355_REG3_PHASE_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0xFFFFFF << 4)) | ((x & 0xFFFFFF) << 4)) - - -@portable -def ADF5355_REG3_SD_LOAD_RESET_GET(reg: TInt32) -> TInt32: - return int32((reg >> 30) & 0x1) - - -@portable -def ADF5355_REG3_SD_LOAD_RESET(x: TInt32) -> TInt32: - return int32((x & 0x1) << 30) - - -@portable -def ADF5355_REG3_SD_LOAD_RESET_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 30)) | ((x & 0x1) << 30)) - - -@portable -def ADF5355_REG4_COUNTER_RESET_GET(reg: TInt32) -> TInt32: - return int32((reg >> 4) & 0x1) - - -@portable -def ADF5355_REG4_COUNTER_RESET(x: TInt32) -> TInt32: - return int32((x & 0x1) << 4) - - -@portable -def ADF5355_REG4_COUNTER_RESET_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 4)) | ((x & 0x1) << 4)) - - -@portable -def ADF5355_REG4_CP_THREE_STATE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 5) & 0x1) - - -@portable -def ADF5355_REG4_CP_THREE_STATE(x: TInt32) -> TInt32: - return int32((x & 0x1) << 5) - - -@portable -def ADF5355_REG4_CP_THREE_STATE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 5)) | ((x & 0x1) << 5)) - - -@portable -def ADF5355_REG4_CURRENT_SETTING_GET(reg: TInt32) -> TInt32: - return int32((reg >> 10) & 0xF) - - -@portable -def ADF5355_REG4_CURRENT_SETTING(x: TInt32) -> TInt32: - return int32((x & 0xF) << 10) - - -@portable -def ADF5355_REG4_CURRENT_SETTING_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0xF << 10)) | ((x & 0xF) << 10)) - - -@portable -def ADF5355_REG4_DOUBLE_BUFF_GET(reg: TInt32) -> TInt32: - return int32((reg >> 14) & 0x1) - - -@portable -def ADF5355_REG4_DOUBLE_BUFF(x: TInt32) -> TInt32: - return int32((x & 0x1) << 14) - - -@portable -def ADF5355_REG4_DOUBLE_BUFF_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 14)) | ((x & 0x1) << 14)) - - -@portable -def ADF5355_REG4_MUX_LOGIC_GET(reg: TInt32) -> TInt32: - return int32((reg >> 8) & 0x1) - - -@portable -def ADF5355_REG4_MUX_LOGIC(x: TInt32) -> TInt32: - return int32((x & 0x1) << 8) - - -@portable -def ADF5355_REG4_MUX_LOGIC_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 8)) | ((x & 0x1) << 8)) - - -@portable -def ADF5355_REG4_MUXOUT_GET(reg: TInt32) -> TInt32: - return int32((reg >> 27) & 0x7) - - -@portable -def ADF5355_REG4_MUXOUT(x: TInt32) -> TInt32: - return int32((x & 0x7) << 27) - - -@portable -def ADF5355_REG4_MUXOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x7 << 27)) | ((x & 0x7) << 27)) - - -@portable -def ADF5355_REG4_PD_POLARITY_GET(reg: TInt32) -> TInt32: - return int32((reg >> 7) & 0x1) - - -@portable -def ADF5355_REG4_PD_POLARITY(x: TInt32) -> TInt32: - return int32((x & 0x1) << 7) - - -@portable -def ADF5355_REG4_PD_POLARITY_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 7)) | ((x & 0x1) << 7)) - - -@portable -def ADF5355_REG4_POWER_DOWN_GET(reg: TInt32) -> TInt32: - return int32((reg >> 6) & 0x1) - - -@portable -def ADF5355_REG4_POWER_DOWN(x: TInt32) -> TInt32: - return int32((x & 0x1) << 6) - - -@portable -def ADF5355_REG4_POWER_DOWN_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 6)) | ((x & 0x1) << 6)) - - -@portable -def ADF5355_REG4_R_COUNTER_GET(reg: TInt32) -> TInt32: - return int32((reg >> 15) & 0x3FF) - - -@portable -def ADF5355_REG4_R_COUNTER(x: TInt32) -> TInt32: - return int32((x & 0x3FF) << 15) - - -@portable -def ADF5355_REG4_R_COUNTER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x3FF << 15)) | ((x & 0x3FF) << 15)) - - -@portable -def ADF5355_REG4_R_DIVIDER_GET(reg: TInt32) -> TInt32: - return int32((reg >> 25) & 0x1) - - -@portable -def ADF5355_REG4_R_DIVIDER(x: TInt32) -> TInt32: - return int32((x & 0x1) << 25) - - -@portable -def ADF5355_REG4_R_DIVIDER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 25)) | ((x & 0x1) << 25)) - - -@portable -def ADF5355_REG4_R_DOUBLER_GET(reg: TInt32) -> TInt32: - return int32((reg >> 26) & 0x1) - - -@portable -def ADF5355_REG4_R_DOUBLER(x: TInt32) -> TInt32: - return int32((x & 0x1) << 26) - - -@portable -def ADF5355_REG4_R_DOUBLER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 26)) | ((x & 0x1) << 26)) - - -@portable -def ADF5355_REG4_REF_MODE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 9) & 0x1) - - -@portable -def ADF5355_REG4_REF_MODE(x: TInt32) -> TInt32: - return int32((x & 0x1) << 9) - - -@portable -def ADF5355_REG4_REF_MODE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 9)) | ((x & 0x1) << 9)) - - -@portable -def ADF5355_REG6_BLEED_POLARITY_GET(reg: TInt32) -> TInt32: - return int32((reg >> 31) & 0x1) - - -@portable -def ADF5355_REG6_BLEED_POLARITY(x: TInt32) -> TInt32: - return int32((x & 0x1) << 31) - - -@portable -def ADF5355_REG6_BLEED_POLARITY_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 31)) | ((x & 0x1) << 31)) - - -@portable -def ADF5355_REG6_CP_BLEED_CURRENT_GET(reg: TInt32) -> TInt32: - return int32((reg >> 13) & 0xFF) - - -@portable -def ADF5355_REG6_CP_BLEED_CURRENT(x: TInt32) -> TInt32: - return int32((x & 0xFF) << 13) - - -@portable -def ADF5355_REG6_CP_BLEED_CURRENT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0xFF << 13)) | ((x & 0xFF) << 13)) - - -@portable -def ADF5355_REG6_FB_SELECT_GET(reg: TInt32) -> TInt32: - return int32((reg >> 24) & 0x1) - - -@portable -def ADF5355_REG6_FB_SELECT(x: TInt32) -> TInt32: - return int32((x & 0x1) << 24) - - -@portable -def ADF5355_REG6_FB_SELECT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 24)) | ((x & 0x1) << 24)) - - -@portable -def ADF5355_REG6_GATE_BLEED_GET(reg: TInt32) -> TInt32: - return int32((reg >> 30) & 0x1) - - -@portable -def ADF5355_REG6_GATE_BLEED(x: TInt32) -> TInt32: - return int32((x & 0x1) << 30) - - -@portable -def ADF5355_REG6_GATE_BLEED_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 30)) | ((x & 0x1) << 30)) - - -@portable -def ADF5355_REG6_MUTE_TILL_LD_GET(reg: TInt32) -> TInt32: - return int32((reg >> 11) & 0x1) - - -@portable -def ADF5355_REG6_MUTE_TILL_LD(x: TInt32) -> TInt32: - return int32((x & 0x1) << 11) - - -@portable -def ADF5355_REG6_MUTE_TILL_LD_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 11)) | ((x & 0x1) << 11)) - - -@portable -def ADF5355_REG6_NEGATIVE_BLEED_GET(reg: TInt32) -> TInt32: - return int32((reg >> 29) & 0x1) - - -@portable -def ADF5355_REG6_NEGATIVE_BLEED(x: TInt32) -> TInt32: - return int32((x & 0x1) << 29) - - -@portable -def ADF5355_REG6_NEGATIVE_BLEED_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 29)) | ((x & 0x1) << 29)) - - -@portable -def ADF5355_REG6_RF_DIVIDER_SELECT_GET(reg: TInt32) -> TInt32: - return int32((reg >> 21) & 0x7) - - -@portable -def ADF5355_REG6_RF_DIVIDER_SELECT(x: TInt32) -> TInt32: - return int32((x & 0x7) << 21) - - -@portable -def ADF5355_REG6_RF_DIVIDER_SELECT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x7 << 21)) | ((x & 0x7) << 21)) - - -@portable -def ADF5355_REG6_RF_OUTPUT_A_ENABLE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 6) & 0x1) - - -@portable -def ADF5355_REG6_RF_OUTPUT_A_ENABLE(x: TInt32) -> TInt32: - return int32((x & 0x1) << 6) - - -@portable -def ADF5355_REG6_RF_OUTPUT_A_ENABLE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 6)) | ((x & 0x1) << 6)) - - -@portable -def ADF5355_REG6_RF_OUTPUT_A_POWER_GET(reg: TInt32) -> TInt32: - return int32((reg >> 4) & 0x3) - - -@portable -def ADF5355_REG6_RF_OUTPUT_A_POWER(x: TInt32) -> TInt32: - return int32((x & 0x3) << 4) - - -@portable -def ADF5355_REG6_RF_OUTPUT_A_POWER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x3 << 4)) | ((x & 0x3) << 4)) - - -@portable -def ADF5355_REG6_RF_OUTPUT_B_ENABLE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 10) & 0x1) - - -@portable -def ADF5355_REG6_RF_OUTPUT_B_ENABLE(x: TInt32) -> TInt32: - return int32((x & 0x1) << 10) - - -@portable -def ADF5355_REG6_RF_OUTPUT_B_ENABLE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 10)) | ((x & 0x1) << 10)) - - -@portable -def ADF5355_REG7_FRAC_N_LD_PRECISION_GET(reg: TInt32) -> TInt32: - return int32((reg >> 5) & 0x3) - - -@portable -def ADF5355_REG7_FRAC_N_LD_PRECISION(x: TInt32) -> TInt32: - return int32((x & 0x3) << 5) - - -@portable -def ADF5355_REG7_FRAC_N_LD_PRECISION_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x3 << 5)) | ((x & 0x3) << 5)) - - -@portable -def ADF5355_REG7_LD_CYCLE_COUNT_GET(reg: TInt32) -> TInt32: - return int32((reg >> 8) & 0x3) - - -@portable -def ADF5355_REG7_LD_CYCLE_COUNT(x: TInt32) -> TInt32: - return int32((x & 0x3) << 8) - - -@portable -def ADF5355_REG7_LD_CYCLE_COUNT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x3 << 8)) | ((x & 0x3) << 8)) - - -@portable -def ADF5355_REG7_LD_MODE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 4) & 0x1) - - -@portable -def ADF5355_REG7_LD_MODE(x: TInt32) -> TInt32: - return int32((x & 0x1) << 4) - - -@portable -def ADF5355_REG7_LD_MODE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 4)) | ((x & 0x1) << 4)) - - -@portable -def ADF5355_REG7_LE_SEL_SYNC_EDGE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 27) & 0x1) - - -@portable -def ADF5355_REG7_LE_SEL_SYNC_EDGE(x: TInt32) -> TInt32: - return int32((x & 0x1) << 27) - - -@portable -def ADF5355_REG7_LE_SEL_SYNC_EDGE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 27)) | ((x & 0x1) << 27)) - - -@portable -def ADF5355_REG7_LE_SYNC_GET(reg: TInt32) -> TInt32: - return int32((reg >> 25) & 0x1) - - -@portable -def ADF5355_REG7_LE_SYNC(x: TInt32) -> TInt32: - return int32((x & 0x1) << 25) - - -@portable -def ADF5355_REG7_LE_SYNC_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 25)) | ((x & 0x1) << 25)) - - -@portable -def ADF5355_REG7_LOL_MODE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 7) & 0x1) - - -@portable -def ADF5355_REG7_LOL_MODE(x: TInt32) -> TInt32: - return int32((x & 0x1) << 7) - - -@portable -def ADF5355_REG7_LOL_MODE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 7)) | ((x & 0x1) << 7)) - - -@portable -def ADF5355_REG9_AUTOCAL_TIMEOUT_GET(reg: TInt32) -> TInt32: - return int32((reg >> 9) & 0x1F) - - -@portable -def ADF5355_REG9_AUTOCAL_TIMEOUT(x: TInt32) -> TInt32: - return int32((x & 0x1F) << 9) - - -@portable -def ADF5355_REG9_AUTOCAL_TIMEOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1F << 9)) | ((x & 0x1F) << 9)) - - -@portable -def ADF5355_REG9_SYNTH_LOCK_TIMEOUT_GET(reg: TInt32) -> TInt32: - return int32((reg >> 4) & 0x1F) - - -@portable -def ADF5355_REG9_SYNTH_LOCK_TIMEOUT(x: TInt32) -> TInt32: - return int32((x & 0x1F) << 4) - - -@portable -def ADF5355_REG9_SYNTH_LOCK_TIMEOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1F << 4)) | ((x & 0x1F) << 4)) - - -@portable -def ADF5355_REG9_TIMEOUT_GET(reg: TInt32) -> TInt32: - return int32((reg >> 14) & 0x3FF) - - -@portable -def ADF5355_REG9_TIMEOUT(x: TInt32) -> TInt32: - return int32((x & 0x3FF) << 14) - - -@portable -def ADF5355_REG9_TIMEOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x3FF << 14)) | ((x & 0x3FF) << 14)) - - -@portable -def ADF5355_REG9_VCO_BAND_DIVISION_GET(reg: TInt32) -> TInt32: - return int32((reg >> 24) & 0xFF) - - -@portable -def ADF5355_REG9_VCO_BAND_DIVISION(x: TInt32) -> TInt32: - return int32((x & 0xFF) << 24) - - -@portable -def ADF5355_REG9_VCO_BAND_DIVISION_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0xFF << 24)) | ((x & 0xFF) << 24)) - - -@portable -def ADF5355_REG10_ADC_CLK_DIV_GET(reg: TInt32) -> TInt32: - return int32((reg >> 6) & 0xFF) - - -@portable -def ADF5355_REG10_ADC_CLK_DIV(x: TInt32) -> TInt32: - return int32((x & 0xFF) << 6) - - -@portable -def ADF5355_REG10_ADC_CLK_DIV_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0xFF << 6)) | ((x & 0xFF) << 6)) - - -@portable -def ADF5355_REG10_ADC_CONV_GET(reg: TInt32) -> TInt32: - return int32((reg >> 5) & 0x1) - - -@portable -def ADF5355_REG10_ADC_CONV(x: TInt32) -> TInt32: - return int32((x & 0x1) << 5) - - -@portable -def ADF5355_REG10_ADC_CONV_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 5)) | ((x & 0x1) << 5)) - - -@portable -def ADF5355_REG10_ADC_ENABLE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 4) & 0x1) - - -@portable -def ADF5355_REG10_ADC_ENABLE(x: TInt32) -> TInt32: - return int32((x & 0x1) << 4) - - -@portable -def ADF5355_REG10_ADC_ENABLE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 4)) | ((x & 0x1) << 4)) - - -@portable -def ADF5355_REG11_VCO_BAND_HOLD_GET(reg: TInt32) -> TInt32: - return int32((reg >> 24) & 0x1) - - -@portable -def ADF5355_REG11_VCO_BAND_HOLD(x: TInt32) -> TInt32: - return int32((x & 0x1) << 24) - - -@portable -def ADF5355_REG11_VCO_BAND_HOLD_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x1 << 24)) | ((x & 0x1) << 24)) - - -@portable -def ADF5355_REG12_PHASE_RESYNC_CLK_VALUE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 12) & 0xFFFFF) - - -@portable -def ADF5355_REG12_PHASE_RESYNC_CLK_VALUE(x: TInt32) -> TInt32: - return int32((x & 0xFFFFF) << 12) - - -@portable -def ADF5355_REG12_PHASE_RESYNC_CLK_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0xFFFFF << 12)) | ((x & 0xFFFFF) << 12)) - - -@portable -def ADF5355_REG13_AUX_FRAC_MSB_VALUE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 18) & 0x3FFF) - - -@portable -def ADF5355_REG13_AUX_FRAC_MSB_VALUE(x: TInt32) -> TInt32: - return int32((x & 0x3FFF) << 18) - - -@portable -def ADF5355_REG13_AUX_FRAC_MSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x3FFF << 18)) | ((x & 0x3FFF) << 18)) - - -@portable -def ADF5355_REG13_AUX_MOD_MSB_VALUE_GET(reg: TInt32) -> TInt32: - return int32((reg >> 4) & 0x3FFF) - - -@portable -def ADF5355_REG13_AUX_MOD_MSB_VALUE(x: TInt32) -> TInt32: - return int32((x & 0x3FFF) << 4) - - -@portable -def ADF5355_REG13_AUX_MOD_MSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: - return int32((reg & ~(0x3FFF << 4)) | ((x & 0x3FFF) << 4)) - - -ADF5355_NUM_REGS = 14 diff --git a/artiq/coredevice/adf5355.py b/artiq/coredevice/adf5356.py similarity index 69% rename from artiq/coredevice/adf5355.py rename to artiq/coredevice/adf5356.py index 3f862c54b..19ed29a60 100644 --- a/artiq/coredevice/adf5355.py +++ b/artiq/coredevice/adf5356.py @@ -4,16 +4,16 @@ on Mirny-style prefixed SPI buses. # https://github.com/analogdevicesinc/linux/blob/master/Documentation/devicetree/bindings/iio/frequency/adf5355.txt # https://github.com/analogdevicesinc/linux/blob/master/drivers/iio/frequency/adf5355.c -# https://www.analog.com/media/en/technical-documentation/data-sheets/ADF5356.pdf # https://www.analog.com/media/en/technical-documentation/data-sheets/ADF5355.pdf -# https://www.analog.com/media/en/technical-documentation/user-guides/EV-ADF5356SD1Z-UG-1087.pdf +# https://www.analog.com/media/en/technical-documentation/data-sheets/ADF5355.pdf +# https://www.analog.com/media/en/technical-documentation/user-guides/EV-ADF5355SD1Z-UG-1087.pdf from artiq.language.core import kernel, portable, delay from artiq.language.units import us, GHz, MHz from artiq.language.types import TInt32, TInt64 from artiq.coredevice import spi2 as spi -from artiq.coredevice.adf5355_reg import * +from artiq.coredevice.adf5356_reg import * from numpy import int32, int64, floor, ceil @@ -30,20 +30,20 @@ SPI_CONFIG = ( ) -ADF5355_MIN_VCO_FREQ = int64(3.4 * GHz) -ADF5355_MAX_VCO_FREQ = int64(6.8 * GHz) -ADF5355_MAX_OUTA_FREQ = ADF5355_MAX_VCO_FREQ -ADF5355_MIN_OUTA_FREQ = ADF5355_MIN_VCO_FREQ / 64 -ADF5355_MAX_OUTB_FREQ = ADF5355_MAX_VCO_FREQ * 2 -ADF5355_MIN_OUTB_FREQ = ADF5355_MIN_VCO_FREQ * 2 +ADF5356_MIN_VCO_FREQ = int64(3.4 * GHz) +ADF5356_MAX_VCO_FREQ = int64(6.8 * GHz) +ADF5356_MAX_OUTA_FREQ = ADF5356_MAX_VCO_FREQ +ADF5356_MIN_OUTA_FREQ = ADF5356_MIN_VCO_FREQ / 64 +ADF5356_MAX_OUTB_FREQ = ADF5356_MAX_VCO_FREQ * 2 +ADF5356_MIN_OUTB_FREQ = ADF5356_MIN_VCO_FREQ * 2 -ADF5355_MAX_FREQ_PFD = int32(125.0 * MHz) -ADF5355_MODULUS1 = int32(16777216) -ADF5355_MAX_MODULUS2 = int32(16383) # FIXME: ADF5356 has 28 bits MOD2 -ADF5355_MAX_R_CNT = int32(1023) +ADF5356_MAX_FREQ_PFD = int32(125.0 * MHz) +ADF5356_MODULUS1 = int32(1 << 24) +ADF5356_MAX_MODULUS2 = int32(1 << 28) # FIXME: ADF5356 has 28 bits MOD2 +ADF5356_MAX_R_CNT = int32(1023) -class ADF5355: +class ADF5356: """Analog Devices AD[45]35[56] family of GHz PLLs. :param cpld_device: Mirny CPLD device name @@ -87,14 +87,14 @@ class ADF5355: """ if not blind: # MUXOUT = VDD - self.write(ADF5355_REG4_MUXOUT(1) | 4) + self.write(ADF5356_REG4_MUXOUT(1) | 4) delay(5000 * us) if not self.read_muxout(): raise ValueError("MUXOUT not high") delay(1000 * us) # MUXOUT = DGND - self.write(ADF5355_REG4_MUXOUT(2) | 4) + self.write(ADF5356_REG4_MUXOUT(2) | 4) delay(5000 * us) if self.read_muxout(): raise ValueError("MUXOUT not low") @@ -125,12 +125,12 @@ class ADF5355: """ freq = int64(round(f)) - if freq > ADF5355_MAX_VCO_FREQ: + if freq > ADF5356_MAX_VCO_FREQ: raise ValueError("Requested too high frequency") # select minimal output divider rf_div_sel = 0 - while freq < ADF5355_MIN_VCO_FREQ: + while freq < ADF5356_MIN_VCO_FREQ: freq <<= 1 rf_div_sel += 1 @@ -138,23 +138,23 @@ class ADF5355: raise ValueError("Requested too low frequency") # choose reference divider that maximizes PFD frequency - self.regs[4] = ADF5355_REG4_R_COUNTER_UPDATE( + self.regs[4] = ADF5356_REG4_R_COUNTER_UPDATE( self.regs[4], self._compute_reference_counter() ) f_pfd = self.f_pfd() # choose prescaler if freq > int64(6e9): - self.regs[0] |= ADF5355_REG0_PRESCALER(1) # 8/9 + self.regs[0] |= ADF5356_REG0_PRESCALER(1) # 8/9 n_min, n_max = 75, 65535 # adjust reference divider to be able to match n_min constraint while n_min * f_pfd > freq: - r = ADF5355_REG4_R_COUNTER_GET(self.regs[4]) - self.regs[4] = ADF5355_REG4_R_COUNTER_UPDATE(self.regs[4], r + 1) + r = ADF5356_REG4_R_COUNTER_GET(self.regs[4]) + self.regs[4] = ADF5356_REG4_R_COUNTER_UPDATE(self.regs[4], r + 1) f_pfd = self.f_pfd() else: - self.regs[0] &= ~ADF5355_REG0_PRESCALER(1) # 4/5 + self.regs[0] &= ~ADF5356_REG0_PRESCALER(1) # 4/5 n_min, n_max = 23, 32767 # calculate PLL parameters @@ -166,25 +166,24 @@ class ADF5355: raise ValueError("Invalid INT value") # configure PLL - self.regs[0] = ADF5355_REG0_INT_VALUE_UPDATE(self.regs[0], n) - self.regs[1] = ADF5355_REG1_MAIN_FRAC_VALUE_UPDATE(self.regs[1], frac1) - self.regs[2] = ADF5355_REG2_AUX_FRAC_LSB_VALUE_UPDATE(self.regs[2], frac2_lsb) - self.regs[2] = ADF5355_REG2_AUX_MOD_LSB_VALUE_UPDATE(self.regs[2], mod2_lsb) - self.regs[13] = ADF5355_REG13_AUX_FRAC_MSB_VALUE_UPDATE( + self.regs[0] = ADF5356_REG0_INT_VALUE_UPDATE(self.regs[0], n) + self.regs[1] = ADF5356_REG1_MAIN_FRAC_VALUE_UPDATE(self.regs[1], frac1) + self.regs[2] = ADF5356_REG2_AUX_FRAC_LSB_VALUE_UPDATE(self.regs[2], frac2_lsb) + self.regs[2] = ADF5356_REG2_AUX_MOD_LSB_VALUE_UPDATE(self.regs[2], mod2_lsb) + self.regs[13] = ADF5356_REG13_AUX_FRAC_MSB_VALUE_UPDATE( self.regs[13], frac2_msb ) - self.regs[13] = ADF5355_REG13_AUX_MOD_MSB_VALUE_UPDATE(self.regs[13], mod2_msb) + self.regs[13] = ADF5356_REG13_AUX_MOD_MSB_VALUE_UPDATE(self.regs[13], mod2_msb) - self.regs[6] = ADF5355_REG6_RF_DIVIDER_SELECT_UPDATE(self.regs[6], rf_div_sel) - self.regs[6] = ADF5355_REG6_CP_BLEED_CURRENT_UPDATE( + self.regs[6] = ADF5356_REG6_RF_DIVIDER_SELECT_UPDATE(self.regs[6], rf_div_sel) + self.regs[6] = ADF5356_REG6_CP_BLEED_CURRENT_UPDATE( self.regs[6], int32(floor(24 * f_pfd / (61.44 * MHz))) ) - self.regs[9] = ADF5355_REG9_VCO_BAND_DIVISION_UPDATE( + self.regs[9] = ADF5356_REG9_VCO_BAND_DIVISION_UPDATE( self.regs[9], int32(ceil(f_pfd / 160e3)) ) # commit - # TODO: frequency update sync self.sync() @kernel @@ -198,7 +197,7 @@ class ADF5355: for i in range(13, 0, -1): self.write(self.regs[i]) delay(200 * us) - self.write(self.regs[0] | ADF5355_REG0_AUTOCAL(1)) + self.write(self.regs[0] | ADF5356_REG0_AUTOCAL(1)) else: # AUTOCAL AT HALF PFD FREQUENCY @@ -209,27 +208,27 @@ class ADF5355: self.write( 13 - | ADF5355_REG13_AUX_FRAC_MSB_VALUE(frac2_msb) - | ADF5355_REG13_AUX_MOD_MSB_VALUE(mod2_msb) + | ADF5356_REG13_AUX_FRAC_MSB_VALUE(frac2_msb) + | ADF5356_REG13_AUX_MOD_MSB_VALUE(mod2_msb) ) for i in range(12, 4, -1): self.write(self.regs[i]) self.write( - ADF5355_REG4_R_COUNTER_UPDATE(self.regs[4], 2 * self.ref_counter()) + ADF5356_REG4_R_COUNTER_UPDATE(self.regs[4], 2 * self.ref_counter()) ) self.write(self.regs[3]) self.write( 2 - | ADF5355_REG2_AUX_MOD_LSB_VALUE(mod2_lsb) - | ADF5355_REG2_AUX_FRAC_LSB_VALUE(frac2_lsb) + | ADF5356_REG2_AUX_MOD_LSB_VALUE(mod2_lsb) + | ADF5356_REG2_AUX_FRAC_LSB_VALUE(frac2_lsb) ) - self.write(1 | ADF5355_REG1_MAIN_FRAC_VALUE(frac1)) + self.write(1 | ADF5356_REG1_MAIN_FRAC_VALUE(frac1)) delay(200 * us) - self.write(ADF5355_REG0_INT_VALUE(n) | ADF5355_REG0_AUTOCAL(1)) + self.write(ADF5356_REG0_INT_VALUE(n) | ADF5356_REG0_AUTOCAL(1)) # RELOCK AT WANTED PFD FREQUENCY @@ -237,16 +236,16 @@ class ADF5355: self.write(self.regs[i]) # force-disable autocal - self.write(self.regs[0] & ~ADF5355_REG0_AUTOCAL(1)) + self.write(self.regs[0] & ~ADF5356_REG0_AUTOCAL(1)) @portable def f_pfd(self) -> TInt64: """ Return the PFD frequency for the cached set of registers. """ - r = ADF5355_REG4_R_COUNTER_GET(self.regs[4]) - d = ADF5355_REG4_R_DOUBLER_GET(self.regs[4]) - t = ADF5355_REG4_R_DIVIDER_GET(self.regs[4]) + r = ADF5356_REG4_R_COUNTER_GET(self.regs[4]) + d = ADF5356_REG4_R_DOUBLER_GET(self.regs[4]) + t = ADF5356_REG4_R_DIVIDER_GET(self.regs[4]) return self._compute_pfd_frequency(r, d, t) @portable @@ -259,7 +258,7 @@ class ADF5355: * ( self.pll_n() + (self.pll_frac1() + self.pll_frac2() / self.pll_mod2()) - / ADF5355_MODULUS1 + / ADF5356_MODULUS1 ) ) @@ -268,14 +267,14 @@ class ADF5355: """ Return the PLL integer value (INT) for the cached set of registers. """ - return ADF5355_REG0_INT_VALUE_GET(self.regs[0]) + return ADF5356_REG0_INT_VALUE_GET(self.regs[0]) @portable def pll_frac1(self) -> TInt32: """ Return the main fractional value (FRAC1) for the cached set of registers. """ - return ADF5355_REG1_MAIN_FRAC_VALUE_GET(self.regs[1]) + return ADF5356_REG1_MAIN_FRAC_VALUE_GET(self.regs[1]) @portable def pll_frac2(self) -> TInt32: @@ -283,8 +282,8 @@ class ADF5355: Return the auxiliary fractional value (FRAC2) for the cached set of registers. """ return ( - ADF5355_REG13_AUX_FRAC_MSB_VALUE_GET(self.regs[13]) << 14 - ) | ADF5355_REG2_AUX_FRAC_LSB_VALUE_GET(self.regs[2]) + ADF5356_REG13_AUX_FRAC_MSB_VALUE_GET(self.regs[13]) << 14 + ) | ADF5356_REG2_AUX_FRAC_LSB_VALUE_GET(self.regs[2]) @portable def pll_mod2(self) -> TInt32: @@ -292,24 +291,30 @@ class ADF5355: Return the auxiliary modulus value (MOD2) for the cached set of registers. """ return ( - ADF5355_REG13_AUX_MOD_MSB_VALUE_GET(self.regs[13]) << 14 - ) | ADF5355_REG2_AUX_MOD_LSB_VALUE_GET(self.regs[2]) + ADF5356_REG13_AUX_MOD_MSB_VALUE_GET(self.regs[13]) << 14 + ) | ADF5356_REG2_AUX_MOD_LSB_VALUE_GET(self.regs[2]) @portable def ref_counter(self) -> TInt32: """ Return the reference counter value (R) for the cached set of registers. """ - return ADF5355_REG4_R_COUNTER_GET(self.regs[4]) + return ADF5356_REG4_R_COUNTER_GET(self.regs[4]) + + @portable + def output_divider(self) -> TInt32: + """ + Return the value of the output A divider. + """ + return 1 << ADF5356_REG6_RF_DIVIDER_SELECT_GET(self.regs[6]) def info(self): - output_divider = 1 << ADF5355_REG6_RF_DIVIDER_SELECT_GET(self.regs[6]) - prescaler = ADF5355_REG0_PRESCALER_GET(self.regs[0]) + prescaler = ADF5356_REG0_PRESCALER_GET(self.regs[0]) return { # output - "f_outA": self.f_vco() / output_divider, + "f_outA": self.f_vco() / self.output_divider(), "f_outB": self.f_vco() * 2, - "output_divider": output_divider, + "output_divider": self.output_divider(), # PLL parameters "f_vco": self.f_vco(), "pll_n": self.pll_n(), @@ -331,13 +336,13 @@ class ADF5355: Initialize cached registers with sensible defaults. """ # fill with control bits - self.regs = [int32(i) for i in range(ADF5355_NUM_REGS)] + self.regs = [int32(i) for i in range(ADF5356_NUM_REGS)] # REG2 # ==== # avoid divide-by-zero - self.regs[2] |= ADF5355_REG2_AUX_MOD_LSB_VALUE(1) + self.regs[2] |= ADF5356_REG2_AUX_MOD_LSB_VALUE(1) # REG4 # ==== @@ -345,29 +350,29 @@ class ADF5355: # single-ended reference mode is recommended # for references up to 250 MHz, even if the signal is differential if self.sysclk <= 250 * MHz: - self.regs[4] |= ADF5355_REG4_REF_MODE(0) + self.regs[4] |= ADF5356_REG4_REF_MODE(0) else: - self.regs[4] |= ADF5355_REG4_REF_MODE(1) + self.regs[4] |= ADF5356_REG4_REF_MODE(1) # phase detector polarity: positive - self.regs[4] |= ADF5355_REG4_PD_POLARITY(1) + self.regs[4] |= ADF5356_REG4_PD_POLARITY(1) # charge pump current: 0.94 mA - self.regs[4] |= ADF5355_REG4_CURRENT_SETTING(2) + self.regs[4] |= ADF5356_REG4_CURRENT_SETTING(2) # MUXOUT: digital lock detect - self.regs[4] |= ADF5355_REG4_MUX_LOGIC(1) # 3v3 logic - self.regs[4] |= ADF5355_REG4_MUXOUT(6) + self.regs[4] |= ADF5356_REG4_MUX_LOGIC(1) # 3v3 logic + self.regs[4] |= ADF5356_REG4_MUXOUT(6) # setup reference path if self.ref_doubler: - self.regs[4] |= ADF5355_REG4_R_DOUBLER(1) + self.regs[4] |= ADF5356_REG4_R_DOUBLER(1) if self.ref_divider: - self.regs[4] |= ADF5355_REG4_R_DIVIDER(1) + self.regs[4] |= ADF5356_REG4_R_DIVIDER(1) r = self._compute_reference_counter() - self.regs[4] |= ADF5355_REG4_R_COUNTER(r) + self.regs[4] |= ADF5356_REG4_R_COUNTER(r) # REG5 # ==== @@ -382,24 +387,24 @@ class ADF5355: self.regs[6] = int32(0x14000006) # enable negative bleed - self.regs[6] |= ADF5355_REG6_NEGATIVE_BLEED(1) + self.regs[6] |= ADF5356_REG6_NEGATIVE_BLEED(1) # charge pump bleed current - # self.regs[6] |= ADF5355_REG6_CP_BLEED_CURRENT( + # self.regs[6] |= ADF5356_REG6_CP_BLEED_CURRENT( # int32(floor(24 * self.f_pfd / (61.44 * MHz))) # ) # direct feedback from VCO to N counter - self.regs[6] |= ADF5355_REG6_FB_SELECT(1) + self.regs[6] |= ADF5356_REG6_FB_SELECT(1) # mute until the PLL is locked - self.regs[6] |= ADF5355_REG6_MUTE_TILL_LD(1) + self.regs[6] |= ADF5356_REG6_MUTE_TILL_LD(1) # enable output A - self.regs[6] |= ADF5355_REG6_RF_OUTPUT_A_ENABLE(1) + self.regs[6] |= ADF5356_REG6_RF_OUTPUT_A_ENABLE(1) # set output A power to max power, is adjusted by extra attenuator - self.regs[6] |= ADF5355_REG6_RF_OUTPUT_A_POWER(3) # +5 dBm + self.regs[6] |= ADF5356_REG6_RF_OUTPUT_A_POWER(3) # +5 dBm # REG7 # ==== @@ -408,10 +413,10 @@ class ADF5355: self.regs[7] = int32(0x10000007) # sync load-enable to reference - self.regs[7] |= ADF5355_REG7_LE_SYNC(1) + self.regs[7] |= ADF5356_REG7_LE_SYNC(1) # frac-N lock-detect precision: 12 ns - self.regs[7] |= ADF5355_REG7_FRAC_N_LD_PRECISION(3) + self.regs[7] |= ADF5356_REG7_FRAC_N_LD_PRECISION(3) # REG8 # ==== @@ -424,9 +429,9 @@ class ADF5355: # default timeouts (from eval software) self.regs[9] |= ( - ADF5355_REG9_SYNTH_LOCK_TIMEOUT(13) - | ADF5355_REG9_AUTOCAL_TIMEOUT(31) - | ADF5355_REG9_TIMEOUT(0x67) + ADF5356_REG9_SYNTH_LOCK_TIMEOUT(13) + | ADF5356_REG9_AUTOCAL_TIMEOUT(31) + | ADF5356_REG9_TIMEOUT(0x67) ) # REG10 @@ -437,9 +442,9 @@ class ADF5355: # ADC defaults (from eval software) self.regs[10] |= ( - ADF5355_REG10_ADC_ENABLE(1) - | ADF5355_REG10_ADC_CLK_DIV(256) - | ADF5355_REG10_ADC_CONV(1) + ADF5356_REG10_ADC_ENABLE(1) + | ADF5356_REG10_ADC_CLK_DIV(256) + | ADF5356_REG10_ADC_CONV(1) ) # REG11 @@ -466,10 +471,10 @@ class ADF5355: """ Determine the reference counter R that maximizes the PFD frequency """ - d = ADF5355_REG4_R_DOUBLER_GET(self.regs[4]) - t = ADF5355_REG4_R_DIVIDER_GET(self.regs[4]) + d = ADF5356_REG4_R_DOUBLER_GET(self.regs[4]) + t = ADF5356_REG4_R_DIVIDER_GET(self.regs[4]) r = 1 - while self._compute_pfd_frequency(r, d, t) > ADF5355_MAX_FREQ_PFD: + while self._compute_pfd_frequency(r, d, t) > ADF5356_MAX_FREQ_PFD: r += 1 return int32(r) @@ -494,8 +499,8 @@ def calculate_pll(f_vco: TInt64, f_pfd: TInt64): f_vco = f_pfd * (n + (frac1 + frac2/mod2) / mod1) where - mod1 = 16777216 - mod2 = 16383 + mod1 = 2**24 + mod2 = 2**28 """ f_pfd = int64(f_pfd) f_vco = int64(f_vco) @@ -504,13 +509,13 @@ def calculate_pll(f_vco: TInt64, f_pfd: TInt64): n, r = int32(f_vco // f_pfd), f_vco % f_pfd # main fractional part - r *= ADF5355_MODULUS1 + r *= ADF5356_MODULUS1 frac1, frac2 = int32(r // f_pfd), r % f_pfd # auxiliary fractional part mod2 = f_pfd - while mod2 > ADF5355_MAX_MODULUS2: + while mod2 > ADF5356_MAX_MODULUS2: mod2 >>= 1 frac2 >>= 1 diff --git a/artiq/coredevice/adf5356_reg.py b/artiq/coredevice/adf5356_reg.py new file mode 100644 index 000000000..a61582d1a --- /dev/null +++ b/artiq/coredevice/adf5356_reg.py @@ -0,0 +1,642 @@ +# auto-generated, do not edit +from artiq.language.core import portable +from artiq.language.types import TInt32 +from numpy import int32 + +@portable +def ADF5356_REG0_AUTOCAL_GET(reg: TInt32) -> TInt32: + return int32((reg >> 21) & 0x1) + +@portable +def ADF5356_REG0_AUTOCAL(x: TInt32) -> TInt32: + return int32((x & 0x1) << 21) + +@portable +def ADF5356_REG0_AUTOCAL_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 21)) | ((x & 0x1) << 21)) + + +@portable +def ADF5356_REG0_INT_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0xffff) + +@portable +def ADF5356_REG0_INT_VALUE(x: TInt32) -> TInt32: + return int32((x & 0xffff) << 4) + +@portable +def ADF5356_REG0_INT_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xffff << 4)) | ((x & 0xffff) << 4)) + + +@portable +def ADF5356_REG0_PRESCALER_GET(reg: TInt32) -> TInt32: + return int32((reg >> 20) & 0x1) + +@portable +def ADF5356_REG0_PRESCALER(x: TInt32) -> TInt32: + return int32((x & 0x1) << 20) + +@portable +def ADF5356_REG0_PRESCALER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 20)) | ((x & 0x1) << 20)) + + +@portable +def ADF5356_REG1_MAIN_FRAC_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0xffffff) + +@portable +def ADF5356_REG1_MAIN_FRAC_VALUE(x: TInt32) -> TInt32: + return int32((x & 0xffffff) << 4) + +@portable +def ADF5356_REG1_MAIN_FRAC_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xffffff << 4)) | ((x & 0xffffff) << 4)) + + +@portable +def ADF5356_REG2_AUX_FRAC_LSB_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 18) & 0x3fff) + +@portable +def ADF5356_REG2_AUX_FRAC_LSB_VALUE(x: TInt32) -> TInt32: + return int32((x & 0x3fff) << 18) + +@portable +def ADF5356_REG2_AUX_FRAC_LSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3fff << 18)) | ((x & 0x3fff) << 18)) + + +@portable +def ADF5356_REG2_AUX_MOD_LSB_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0x3fff) + +@portable +def ADF5356_REG2_AUX_MOD_LSB_VALUE(x: TInt32) -> TInt32: + return int32((x & 0x3fff) << 4) + +@portable +def ADF5356_REG2_AUX_MOD_LSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3fff << 4)) | ((x & 0x3fff) << 4)) + + +@portable +def ADF5356_REG3_PHASE_ADJUST_GET(reg: TInt32) -> TInt32: + return int32((reg >> 28) & 0x1) + +@portable +def ADF5356_REG3_PHASE_ADJUST(x: TInt32) -> TInt32: + return int32((x & 0x1) << 28) + +@portable +def ADF5356_REG3_PHASE_ADJUST_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 28)) | ((x & 0x1) << 28)) + + +@portable +def ADF5356_REG3_PHASE_RESYNC_GET(reg: TInt32) -> TInt32: + return int32((reg >> 29) & 0x1) + +@portable +def ADF5356_REG3_PHASE_RESYNC(x: TInt32) -> TInt32: + return int32((x & 0x1) << 29) + +@portable +def ADF5356_REG3_PHASE_RESYNC_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 29)) | ((x & 0x1) << 29)) + + +@portable +def ADF5356_REG3_PHASE_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0xffffff) + +@portable +def ADF5356_REG3_PHASE_VALUE(x: TInt32) -> TInt32: + return int32((x & 0xffffff) << 4) + +@portable +def ADF5356_REG3_PHASE_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xffffff << 4)) | ((x & 0xffffff) << 4)) + + +@portable +def ADF5356_REG3_SD_LOAD_RESET_GET(reg: TInt32) -> TInt32: + return int32((reg >> 30) & 0x1) + +@portable +def ADF5356_REG3_SD_LOAD_RESET(x: TInt32) -> TInt32: + return int32((x & 0x1) << 30) + +@portable +def ADF5356_REG3_SD_LOAD_RESET_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 30)) | ((x & 0x1) << 30)) + + +@portable +def ADF5356_REG4_COUNTER_RESET_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0x1) + +@portable +def ADF5356_REG4_COUNTER_RESET(x: TInt32) -> TInt32: + return int32((x & 0x1) << 4) + +@portable +def ADF5356_REG4_COUNTER_RESET_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 4)) | ((x & 0x1) << 4)) + + +@portable +def ADF5356_REG4_CP_THREE_STATE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 5) & 0x1) + +@portable +def ADF5356_REG4_CP_THREE_STATE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 5) + +@portable +def ADF5356_REG4_CP_THREE_STATE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 5)) | ((x & 0x1) << 5)) + + +@portable +def ADF5356_REG4_CURRENT_SETTING_GET(reg: TInt32) -> TInt32: + return int32((reg >> 10) & 0xf) + +@portable +def ADF5356_REG4_CURRENT_SETTING(x: TInt32) -> TInt32: + return int32((x & 0xf) << 10) + +@portable +def ADF5356_REG4_CURRENT_SETTING_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xf << 10)) | ((x & 0xf) << 10)) + + +@portable +def ADF5356_REG4_DOUBLE_BUFF_GET(reg: TInt32) -> TInt32: + return int32((reg >> 14) & 0x1) + +@portable +def ADF5356_REG4_DOUBLE_BUFF(x: TInt32) -> TInt32: + return int32((x & 0x1) << 14) + +@portable +def ADF5356_REG4_DOUBLE_BUFF_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 14)) | ((x & 0x1) << 14)) + + +@portable +def ADF5356_REG4_MUX_LOGIC_GET(reg: TInt32) -> TInt32: + return int32((reg >> 8) & 0x1) + +@portable +def ADF5356_REG4_MUX_LOGIC(x: TInt32) -> TInt32: + return int32((x & 0x1) << 8) + +@portable +def ADF5356_REG4_MUX_LOGIC_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 8)) | ((x & 0x1) << 8)) + + +@portable +def ADF5356_REG4_MUXOUT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 27) & 0x7) + +@portable +def ADF5356_REG4_MUXOUT(x: TInt32) -> TInt32: + return int32((x & 0x7) << 27) + +@portable +def ADF5356_REG4_MUXOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x7 << 27)) | ((x & 0x7) << 27)) + + +@portable +def ADF5356_REG4_PD_POLARITY_GET(reg: TInt32) -> TInt32: + return int32((reg >> 7) & 0x1) + +@portable +def ADF5356_REG4_PD_POLARITY(x: TInt32) -> TInt32: + return int32((x & 0x1) << 7) + +@portable +def ADF5356_REG4_PD_POLARITY_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 7)) | ((x & 0x1) << 7)) + + +@portable +def ADF5356_REG4_POWER_DOWN_GET(reg: TInt32) -> TInt32: + return int32((reg >> 6) & 0x1) + +@portable +def ADF5356_REG4_POWER_DOWN(x: TInt32) -> TInt32: + return int32((x & 0x1) << 6) + +@portable +def ADF5356_REG4_POWER_DOWN_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 6)) | ((x & 0x1) << 6)) + + +@portable +def ADF5356_REG4_R_COUNTER_GET(reg: TInt32) -> TInt32: + return int32((reg >> 15) & 0x3ff) + +@portable +def ADF5356_REG4_R_COUNTER(x: TInt32) -> TInt32: + return int32((x & 0x3ff) << 15) + +@portable +def ADF5356_REG4_R_COUNTER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3ff << 15)) | ((x & 0x3ff) << 15)) + + +@portable +def ADF5356_REG4_R_DIVIDER_GET(reg: TInt32) -> TInt32: + return int32((reg >> 25) & 0x1) + +@portable +def ADF5356_REG4_R_DIVIDER(x: TInt32) -> TInt32: + return int32((x & 0x1) << 25) + +@portable +def ADF5356_REG4_R_DIVIDER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 25)) | ((x & 0x1) << 25)) + + +@portable +def ADF5356_REG4_R_DOUBLER_GET(reg: TInt32) -> TInt32: + return int32((reg >> 26) & 0x1) + +@portable +def ADF5356_REG4_R_DOUBLER(x: TInt32) -> TInt32: + return int32((x & 0x1) << 26) + +@portable +def ADF5356_REG4_R_DOUBLER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 26)) | ((x & 0x1) << 26)) + + +@portable +def ADF5356_REG4_REF_MODE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 9) & 0x1) + +@portable +def ADF5356_REG4_REF_MODE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 9) + +@portable +def ADF5356_REG4_REF_MODE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 9)) | ((x & 0x1) << 9)) + + +@portable +def ADF5356_REG6_BLEED_POLARITY_GET(reg: TInt32) -> TInt32: + return int32((reg >> 31) & 0x1) + +@portable +def ADF5356_REG6_BLEED_POLARITY(x: TInt32) -> TInt32: + return int32((x & 0x1) << 31) + +@portable +def ADF5356_REG6_BLEED_POLARITY_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 31)) | ((x & 0x1) << 31)) + + +@portable +def ADF5356_REG6_CP_BLEED_CURRENT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 13) & 0xff) + +@portable +def ADF5356_REG6_CP_BLEED_CURRENT(x: TInt32) -> TInt32: + return int32((x & 0xff) << 13) + +@portable +def ADF5356_REG6_CP_BLEED_CURRENT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xff << 13)) | ((x & 0xff) << 13)) + + +@portable +def ADF5356_REG6_FB_SELECT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 24) & 0x1) + +@portable +def ADF5356_REG6_FB_SELECT(x: TInt32) -> TInt32: + return int32((x & 0x1) << 24) + +@portable +def ADF5356_REG6_FB_SELECT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 24)) | ((x & 0x1) << 24)) + + +@portable +def ADF5356_REG6_GATE_BLEED_GET(reg: TInt32) -> TInt32: + return int32((reg >> 30) & 0x1) + +@portable +def ADF5356_REG6_GATE_BLEED(x: TInt32) -> TInt32: + return int32((x & 0x1) << 30) + +@portable +def ADF5356_REG6_GATE_BLEED_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 30)) | ((x & 0x1) << 30)) + + +@portable +def ADF5356_REG6_MUTE_TILL_LD_GET(reg: TInt32) -> TInt32: + return int32((reg >> 11) & 0x1) + +@portable +def ADF5356_REG6_MUTE_TILL_LD(x: TInt32) -> TInt32: + return int32((x & 0x1) << 11) + +@portable +def ADF5356_REG6_MUTE_TILL_LD_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 11)) | ((x & 0x1) << 11)) + + +@portable +def ADF5356_REG6_NEGATIVE_BLEED_GET(reg: TInt32) -> TInt32: + return int32((reg >> 29) & 0x1) + +@portable +def ADF5356_REG6_NEGATIVE_BLEED(x: TInt32) -> TInt32: + return int32((x & 0x1) << 29) + +@portable +def ADF5356_REG6_NEGATIVE_BLEED_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 29)) | ((x & 0x1) << 29)) + + +@portable +def ADF5356_REG6_RF_DIVIDER_SELECT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 21) & 0x7) + +@portable +def ADF5356_REG6_RF_DIVIDER_SELECT(x: TInt32) -> TInt32: + return int32((x & 0x7) << 21) + +@portable +def ADF5356_REG6_RF_DIVIDER_SELECT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x7 << 21)) | ((x & 0x7) << 21)) + + +@portable +def ADF5356_REG6_RF_OUTPUT_A_ENABLE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 6) & 0x1) + +@portable +def ADF5356_REG6_RF_OUTPUT_A_ENABLE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 6) + +@portable +def ADF5356_REG6_RF_OUTPUT_A_ENABLE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 6)) | ((x & 0x1) << 6)) + + +@portable +def ADF5356_REG6_RF_OUTPUT_A_POWER_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0x3) + +@portable +def ADF5356_REG6_RF_OUTPUT_A_POWER(x: TInt32) -> TInt32: + return int32((x & 0x3) << 4) + +@portable +def ADF5356_REG6_RF_OUTPUT_A_POWER_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3 << 4)) | ((x & 0x3) << 4)) + + +@portable +def ADF5356_REG6_RF_OUTPUT_B_ENABLE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 10) & 0x1) + +@portable +def ADF5356_REG6_RF_OUTPUT_B_ENABLE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 10) + +@portable +def ADF5356_REG6_RF_OUTPUT_B_ENABLE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 10)) | ((x & 0x1) << 10)) + + +@portable +def ADF5356_REG7_FRAC_N_LD_PRECISION_GET(reg: TInt32) -> TInt32: + return int32((reg >> 5) & 0x3) + +@portable +def ADF5356_REG7_FRAC_N_LD_PRECISION(x: TInt32) -> TInt32: + return int32((x & 0x3) << 5) + +@portable +def ADF5356_REG7_FRAC_N_LD_PRECISION_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3 << 5)) | ((x & 0x3) << 5)) + + +@portable +def ADF5356_REG7_LD_CYCLE_COUNT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 8) & 0x3) + +@portable +def ADF5356_REG7_LD_CYCLE_COUNT(x: TInt32) -> TInt32: + return int32((x & 0x3) << 8) + +@portable +def ADF5356_REG7_LD_CYCLE_COUNT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3 << 8)) | ((x & 0x3) << 8)) + + +@portable +def ADF5356_REG7_LD_MODE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0x1) + +@portable +def ADF5356_REG7_LD_MODE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 4) + +@portable +def ADF5356_REG7_LD_MODE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 4)) | ((x & 0x1) << 4)) + + +@portable +def ADF5356_REG7_LE_SEL_SYNC_EDGE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 27) & 0x1) + +@portable +def ADF5356_REG7_LE_SEL_SYNC_EDGE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 27) + +@portable +def ADF5356_REG7_LE_SEL_SYNC_EDGE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 27)) | ((x & 0x1) << 27)) + + +@portable +def ADF5356_REG7_LE_SYNC_GET(reg: TInt32) -> TInt32: + return int32((reg >> 25) & 0x1) + +@portable +def ADF5356_REG7_LE_SYNC(x: TInt32) -> TInt32: + return int32((x & 0x1) << 25) + +@portable +def ADF5356_REG7_LE_SYNC_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 25)) | ((x & 0x1) << 25)) + + +@portable +def ADF5356_REG7_LOL_MODE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 7) & 0x1) + +@portable +def ADF5356_REG7_LOL_MODE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 7) + +@portable +def ADF5356_REG7_LOL_MODE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 7)) | ((x & 0x1) << 7)) + + +@portable +def ADF5356_REG9_AUTOCAL_TIMEOUT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 9) & 0x1f) + +@portable +def ADF5356_REG9_AUTOCAL_TIMEOUT(x: TInt32) -> TInt32: + return int32((x & 0x1f) << 9) + +@portable +def ADF5356_REG9_AUTOCAL_TIMEOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1f << 9)) | ((x & 0x1f) << 9)) + + +@portable +def ADF5356_REG9_SYNTH_LOCK_TIMEOUT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0x1f) + +@portable +def ADF5356_REG9_SYNTH_LOCK_TIMEOUT(x: TInt32) -> TInt32: + return int32((x & 0x1f) << 4) + +@portable +def ADF5356_REG9_SYNTH_LOCK_TIMEOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1f << 4)) | ((x & 0x1f) << 4)) + + +@portable +def ADF5356_REG9_TIMEOUT_GET(reg: TInt32) -> TInt32: + return int32((reg >> 14) & 0x3ff) + +@portable +def ADF5356_REG9_TIMEOUT(x: TInt32) -> TInt32: + return int32((x & 0x3ff) << 14) + +@portable +def ADF5356_REG9_TIMEOUT_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3ff << 14)) | ((x & 0x3ff) << 14)) + + +@portable +def ADF5356_REG9_VCO_BAND_DIVISION_GET(reg: TInt32) -> TInt32: + return int32((reg >> 24) & 0xff) + +@portable +def ADF5356_REG9_VCO_BAND_DIVISION(x: TInt32) -> TInt32: + return int32((x & 0xff) << 24) + +@portable +def ADF5356_REG9_VCO_BAND_DIVISION_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xff << 24)) | ((x & 0xff) << 24)) + + +@portable +def ADF5356_REG10_ADC_CLK_DIV_GET(reg: TInt32) -> TInt32: + return int32((reg >> 6) & 0xff) + +@portable +def ADF5356_REG10_ADC_CLK_DIV(x: TInt32) -> TInt32: + return int32((x & 0xff) << 6) + +@portable +def ADF5356_REG10_ADC_CLK_DIV_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xff << 6)) | ((x & 0xff) << 6)) + + +@portable +def ADF5356_REG10_ADC_CONV_GET(reg: TInt32) -> TInt32: + return int32((reg >> 5) & 0x1) + +@portable +def ADF5356_REG10_ADC_CONV(x: TInt32) -> TInt32: + return int32((x & 0x1) << 5) + +@portable +def ADF5356_REG10_ADC_CONV_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 5)) | ((x & 0x1) << 5)) + + +@portable +def ADF5356_REG10_ADC_ENABLE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0x1) + +@portable +def ADF5356_REG10_ADC_ENABLE(x: TInt32) -> TInt32: + return int32((x & 0x1) << 4) + +@portable +def ADF5356_REG10_ADC_ENABLE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 4)) | ((x & 0x1) << 4)) + + +@portable +def ADF5356_REG11_VCO_BAND_HOLD_GET(reg: TInt32) -> TInt32: + return int32((reg >> 24) & 0x1) + +@portable +def ADF5356_REG11_VCO_BAND_HOLD(x: TInt32) -> TInt32: + return int32((x & 0x1) << 24) + +@portable +def ADF5356_REG11_VCO_BAND_HOLD_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x1 << 24)) | ((x & 0x1) << 24)) + + +@portable +def ADF5356_REG12_PHASE_RESYNC_CLK_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 12) & 0xfffff) + +@portable +def ADF5356_REG12_PHASE_RESYNC_CLK_VALUE(x: TInt32) -> TInt32: + return int32((x & 0xfffff) << 12) + +@portable +def ADF5356_REG12_PHASE_RESYNC_CLK_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0xfffff << 12)) | ((x & 0xfffff) << 12)) + + +@portable +def ADF5356_REG13_AUX_FRAC_MSB_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 18) & 0x3fff) + +@portable +def ADF5356_REG13_AUX_FRAC_MSB_VALUE(x: TInt32) -> TInt32: + return int32((x & 0x3fff) << 18) + +@portable +def ADF5356_REG13_AUX_FRAC_MSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3fff << 18)) | ((x & 0x3fff) << 18)) + + +@portable +def ADF5356_REG13_AUX_MOD_MSB_VALUE_GET(reg: TInt32) -> TInt32: + return int32((reg >> 4) & 0x3fff) + +@portable +def ADF5356_REG13_AUX_MOD_MSB_VALUE(x: TInt32) -> TInt32: + return int32((x & 0x3fff) << 4) + +@portable +def ADF5356_REG13_AUX_MOD_MSB_VALUE_UPDATE(reg: TInt32, x: TInt32) -> TInt32: + return int32((reg & ~(0x3fff << 4)) | ((x & 0x3fff) << 4)) + +ADF5356_NUM_REGS = 14 From 61dc2b8b648babcf3ff7665839e8cd475949e17c Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Mon, 9 Nov 2020 18:28:59 +0100 Subject: [PATCH 2425/2457] coredevice: adf5356: add some tests Signed-off-by: Etienne Wodey --- artiq/test/coredevice/test_adf5356.py | 146 ++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 artiq/test/coredevice/test_adf5356.py diff --git a/artiq/test/coredevice/test_adf5356.py b/artiq/test/coredevice/test_adf5356.py new file mode 100644 index 000000000..61637dbb8 --- /dev/null +++ b/artiq/test/coredevice/test_adf5356.py @@ -0,0 +1,146 @@ +import unittest +from artiq.experiment import * +from artiq.test.hardware_testbench import ExperimentCase +from artiq.coredevice.adf5356 import ( + calculate_pll, + split_msb_lsb_28b, + ADF5356_MODULUS1, + ADF5356_MAX_MODULUS2, +) + + +class ADF5356Exp(EnvExperiment): + def build(self, runner): + self.setattr_device("core") + self.dev = self.get_device("mirny0_ch0") + self.runner = runner + + def run(self): + getattr(self, self.runner)() + + @kernel + def instantiate(self): + pass + + @kernel + def init(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + + @kernel + def set_get_simple(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + self.dev.set_att_mu(0) + f = 300.123456 * MHz + self.dev.set_frequency(f) + self.set_dataset("freq_set", round(f / Hz)) + self.set_dataset( + "freq_get", round(self.dev.f_vco() / self.dev.output_divider() / Hz) + ) + + @kernel + def set_too_high_frequency(self): + self.dev.set_frequency(10 * GHz) + + @kernel + def set_too_low_frequency(self): + self.dev.set_frequency(1 * MHz) + + @kernel + def muxout_lock_detect(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + self.dev.set_att_mu(0) + f = 300.123 * MHz + self.dev.set_frequency(f) + delay(5 * ms) + self.set_dataset("muxout", self.dev.read_muxout()) + + +class TestCalculateParameters(unittest.TestCase): + def setUp(self): + self.f_pfd = 50 * MHz + self.mod1 = ADF5356_MODULUS1 + + def test_split_msb_lsb(self): + a = (0x123 << 14) | 0x3456 + msb, lsb = split_msb_lsb_28b(a) + + self.assertEqual(msb, 0x123) + self.assertEqual(lsb, 0x3456) + + def test_integer_pll(self): + p_n = 30 + n, frac1, frac2, mod2 = calculate_pll(p_n * self.f_pfd, self.f_pfd) + + self.assertEqual(p_n, n) + self.assertEqual(frac1, 0) + self.assertEqual(frac2, (0, 0)) + self.assertNotEqual(mod2, (0, 0)) + + def test_frac1_pll(self): + p_n = 30 + p_frac1 = 1 << 22 + n, frac1, frac2, mod2 = calculate_pll( + (p_n + p_frac1 / self.mod1) * self.f_pfd, self.f_pfd + ) + + self.assertEqual(p_n, n) + self.assertEqual(p_frac1, frac1) + self.assertEqual(frac2, (0, 0)) + self.assertNotEqual(mod2, (0, 0)) + + def test_frac_pll(self): + p_n = 30 + p_frac1 = 1 << 14 + p_frac2 = 1 << 24 + p_mod2 = 1 << 25 + n, frac1, frac2, mod2 = calculate_pll( + (p_n + (p_frac1 + p_frac2 / p_mod2) / self.mod1) * self.f_pfd, self.f_pfd + ) + + self.assertEqual(p_n, n) + self.assertEqual(p_frac1, frac1) + + frac2 = (frac2[0] << 14) | frac2[1] + mod2 = (mod2[0] << 14) | mod2[1] + + self.assertNotEqual(frac2, 0) + self.assertNotEqual(mod2, 0) + self.assertLessEqual(mod2, ADF5356_MAX_MODULUS2) + + self.assertEqual( + self.mod1 // (p_frac1 + p_frac2 // p_mod2), + self.mod1 // (frac1 + frac2 // mod2), + ) + + +class ADF5356Test(ExperimentCase): + def test_instantiate(self): + self.execute(ADF5356Exp, "instantiate") + + def test_init(self): + self.execute(ADF5356Exp, "init") + + def test_set_get_simple(self): + self.execute(ADF5356Exp, "set_get_simple") + f_set = self.dataset_mgr.get("freq_set") + f_get = self.dataset_mgr.get("freq_get") + self.assertEqual(f_set, f_get) + + def test_muxout_lock_detect(self): + self.execute(ADF5356Exp, "muxout_lock_detect") + muxout = self.dataset_mgr.get("muxout") + self.assertTrue(muxout) + + def test_set_too_high_frequency(self): + with self.assertRaises(ValueError): + self.execute(ADF5356Exp, "set_too_high_frequency") + + def test_set_too_low_frequency(self): + with self.assertRaises(ValueError): + self.execute(ADF5356Exp, "set_too_low_frequency") From 3844123c1381ef293f278a6f90ec2874f9fa1b39 Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Mon, 9 Nov 2020 19:19:16 +0100 Subject: [PATCH 2426/2457] coredevice: adf5356: add enable/disable and power setting for outA Signed-off-by: Etienne Wodey --- artiq/coredevice/adf5356.py | 37 ++++++++++++++++++++ artiq/test/coredevice/test_adf5356.py | 50 +++++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/artiq/coredevice/adf5356.py b/artiq/coredevice/adf5356.py index 19ed29a60..2c4da1751 100644 --- a/artiq/coredevice/adf5356.py +++ b/artiq/coredevice/adf5356.py @@ -116,6 +116,43 @@ class ADF5356: def read_muxout(self): return bool(self.cpld.read_reg(0) & (1 << (self.channel + 8))) + @kernel + def set_output_power_mu(self, n): + """ + Set the power level at output A of the PLL chip in machine units. + + This driver defaults to `n = 3` at init. + + :param n: output power setting, 0, 1, 2, or 3 (see ADF5356 datasheet, fig. 44). + """ + if n not in [0, 1, 2, 3]: + raise ValueError("invalid power setting") + self.regs[6] = ADF5356_REG6_RF_OUTPUT_A_POWER_UPDATE(self.regs[6], n) + self.sync() + + @portable + def output_power_mu(self): + """ + Return the power level at output A of the PLL chip in machine units. + """ + return ADF5356_REG6_RF_OUTPUT_A_POWER_GET(self.regs[6]) + + @kernel + def enable_output(self): + """ + Enable output A of the PLL chip. This is the default after init. + """ + self.regs[6] |= ADF5356_REG6_RF_OUTPUT_A_ENABLE(1) + self.sync() + + @kernel + def disable_output(self): + """ + Disable output A of the PLL chip. + """ + self.regs[6] &= ~ADF5356_REG6_RF_OUTPUT_A_ENABLE(1) + self.sync() + @kernel def set_frequency(self, f): """ diff --git a/artiq/test/coredevice/test_adf5356.py b/artiq/test/coredevice/test_adf5356.py index 61637dbb8..56f8c95a9 100644 --- a/artiq/test/coredevice/test_adf5356.py +++ b/artiq/test/coredevice/test_adf5356.py @@ -1,4 +1,6 @@ import unittest +import numpy as np + from artiq.experiment import * from artiq.test.hardware_testbench import ExperimentCase from artiq.coredevice.adf5356 import ( @@ -29,7 +31,7 @@ class ADF5356Exp(EnvExperiment): self.dev.init() @kernel - def set_get_simple(self): + def set_get_freq(self): self.core.break_realtime() self.dev.cpld.init() self.dev.init() @@ -60,6 +62,35 @@ class ADF5356Exp(EnvExperiment): delay(5 * ms) self.set_dataset("muxout", self.dev.read_muxout()) + @kernel + def set_get_output_power(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + self.dev.set_att_mu(0) + self.dev.set_frequency(100 * MHz) + self.set_dataset("get_power", np.full(4, np.nan)) + for n in range(4): + delay(10 * ms) + self.dev.set_output_power_mu(n) + m = self.dev.output_power_mu() + self.mutate_dataset("get_power", n, m) + + @kernel + def invalid_output_power_setting(self): + self.dev.set_output_power_mu(42) + + @kernel + def enable_disable_output(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + self.dev.set_att_mu(0) + self.dev.set_frequency(100 * MHz) + self.dev.disable_output() + delay(100 * us) + self.dev.enable_output() + class TestCalculateParameters(unittest.TestCase): def setUp(self): @@ -126,8 +157,8 @@ class ADF5356Test(ExperimentCase): def test_init(self): self.execute(ADF5356Exp, "init") - def test_set_get_simple(self): - self.execute(ADF5356Exp, "set_get_simple") + def test_set_get_freq(self): + self.execute(ADF5356Exp, "set_get_freq") f_set = self.dataset_mgr.get("freq_set") f_get = self.dataset_mgr.get("freq_get") self.assertEqual(f_set, f_get) @@ -144,3 +175,16 @@ class ADF5356Test(ExperimentCase): def test_set_too_low_frequency(self): with self.assertRaises(ValueError): self.execute(ADF5356Exp, "set_too_low_frequency") + + def test_set_get_output_power(self): + self.execute(ADF5356Exp, "set_get_output_power") + get_power = self.dataset_mgr.get("get_power") + for n in range(4): + self.assertEqual(n, get_power[n]) + + def test_invalid_output_power_setting(self): + with self.assertRaises(ValueError): + self.execute(ADF5356Exp, "invalid_output_power_setting") + + def test_enable_disable_output(self): + self.execute(ADF5356Exp, "enable_disable_output") From e8730a7e146de67a2015ec27f0a92ca70c18bfdf Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Mon, 9 Nov 2020 19:33:20 +0100 Subject: [PATCH 2427/2457] coredevice: adf5356: add test for failed PLL lock Signed-off-by: Etienne Wodey --- artiq/test/coredevice/test_adf5356.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/artiq/test/coredevice/test_adf5356.py b/artiq/test/coredevice/test_adf5356.py index 56f8c95a9..e98189c0f 100644 --- a/artiq/test/coredevice/test_adf5356.py +++ b/artiq/test/coredevice/test_adf5356.py @@ -62,6 +62,17 @@ class ADF5356Exp(EnvExperiment): delay(5 * ms) self.set_dataset("muxout", self.dev.read_muxout()) + @kernel + def muxout_lock_detect_no_lock(self): + self.core.break_realtime() + self.dev.cpld.init() + self.dev.init() + # set external SMA reference input + self.dev.cpld.write_reg(1, (1 << 4)) + self.dev.set_frequency(100 * MHz) + delay(5 * ms) + self.set_dataset("muxout", self.dev.read_muxout()) + @kernel def set_get_output_power(self): self.core.break_realtime() @@ -168,6 +179,11 @@ class ADF5356Test(ExperimentCase): muxout = self.dataset_mgr.get("muxout") self.assertTrue(muxout) + def test_muxout_lock_detect_no_lock(self): + self.execute(ADF5356Exp, "muxout_lock_detect_no_lock") + muxout = self.dataset_mgr.get("muxout") + self.assertFalse(muxout) + def test_set_too_high_frequency(self): with self.assertRaises(ValueError): self.execute(ADF5356Exp, "set_too_high_frequency") From dbcac62fd0ba5004c9892ae0639d2d2a931a6ee0 Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Mon, 9 Nov 2020 20:08:33 +0100 Subject: [PATCH 2428/2457] coredevice: adf5356: fix/adjust docs Signed-off-by: Etienne Wodey --- artiq/coredevice/adf5356.py | 22 ++++++++++++++-------- artiq/coredevice/mirny.py | 2 +- doc/manual/core_drivers_reference.rst | 4 ++-- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/artiq/coredevice/adf5356.py b/artiq/coredevice/adf5356.py index 2c4da1751..37505682f 100644 --- a/artiq/coredevice/adf5356.py +++ b/artiq/coredevice/adf5356.py @@ -32,11 +32,6 @@ SPI_CONFIG = ( ADF5356_MIN_VCO_FREQ = int64(3.4 * GHz) ADF5356_MAX_VCO_FREQ = int64(6.8 * GHz) -ADF5356_MAX_OUTA_FREQ = ADF5356_MAX_VCO_FREQ -ADF5356_MIN_OUTA_FREQ = ADF5356_MIN_VCO_FREQ / 64 -ADF5356_MAX_OUTB_FREQ = ADF5356_MAX_VCO_FREQ * 2 -ADF5356_MIN_OUTB_FREQ = ADF5356_MIN_VCO_FREQ * 2 - ADF5356_MAX_FREQ_PFD = int32(125.0 * MHz) ADF5356_MODULUS1 = int32(1 << 24) ADF5356_MAX_MODULUS2 = int32(1 << 28) # FIXME: ADF5356 has 28 bits MOD2 @@ -114,6 +109,11 @@ class ADF5356: @kernel def read_muxout(self): + """ + Read the state of the MUXOUT line. + + By default, this is configured to be the digital lock detection. + """ return bool(self.cpld.read_reg(0) & (1 << (self.channel + 8))) @kernel @@ -346,6 +346,9 @@ class ADF5356: return 1 << ADF5356_REG6_RF_DIVIDER_SELECT_GET(self.regs[6]) def info(self): + """ + Return a summary of high-level parameters as a dict. + """ prescaler = ADF5356_REG0_PRESCALER_GET(self.regs[0]) return { # output @@ -533,11 +536,14 @@ def calculate_pll(f_vco: TInt64, f_pfd: TInt64): """ Calculate fractional-N PLL parameters such that - f_vco = f_pfd * (n + (frac1 + frac2/mod2) / mod1) + ``f_vco`` = ``f_pfd`` * (``n`` + (``frac1`` + ``frac2``/``mod2``) / ``mod1``) where - mod1 = 2**24 - mod2 = 2**28 + ``mod1 = 2**24`` and ``mod2 <= 2**28`` + + :param f_vco: target VCO frequency + :param f_pfd: PFD frequency + :return: ``(n, frac1, (frac2_msb, frac2_lsb), (mod2_msb, mod2_lsb))`` """ f_pfd = int64(f_pfd) f_vco = int64(f_vco) diff --git a/artiq/coredevice/mirny.py b/artiq/coredevice/mirny.py index 2c533d4f8..9fdc18c0c 100644 --- a/artiq/coredevice/mirny.py +++ b/artiq/coredevice/mirny.py @@ -38,7 +38,7 @@ class Mirny: frequency in Hz :param clk_sel: Reference clock selection. valid options are: 0 - internal 100MHz XO; 1 - front-panel SMA; 2 - - internal MMCX + internal MMCX :param core_device: Core device name (default: "core") """ diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index baa1b59e4..0fc5a8e8f 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -105,10 +105,10 @@ RF generation drivers .. automodule:: artiq.coredevice.mirny :members: -:mod:`artiq.coredevice.adf5355` module +:mod:`artiq.coredevice.adf5356` module +++++++++++++++++++++++++++++++++++++++ -.. automodule:: artiq.coredevice.adf5355 +.. automodule:: artiq.coredevice.adf5356 :members: :mod:`artiq.coredevice.spline` module From d8a5a8f568e43135ef7ecf92dac318d2735b5573 Mon Sep 17 00:00:00 2001 From: Leon Riesebos Date: Mon, 19 Oct 2020 22:05:44 -0400 Subject: [PATCH 2429/2457] fixed value scaling issue for the center scan gui widget Signed-off-by: Leon Riesebos --- artiq/gui/entries.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gui/entries.py b/artiq/gui/entries.py index bfb4f405d..7e5e80916 100644 --- a/artiq/gui/entries.py +++ b/artiq/gui/entries.py @@ -301,7 +301,7 @@ class _CenterScan(LayoutWidget): apply_properties(center) center.setPrecision() center.setRelativeStep() - center.setValue(state["center"]) + center.setValue(state["center"]/scale) self.addWidget(center, 0, 1) self.addWidget(QtWidgets.QLabel("Center:"), 0, 0) @@ -311,7 +311,7 @@ class _CenterScan(LayoutWidget): span.setPrecision() span.setRelativeStep() span.setMinimum(0) - span.setValue(state["span"]) + span.setValue(state["span"]/scale) self.addWidget(span, 1, 1) self.addWidget(QtWidgets.QLabel("Span:"), 1, 0) @@ -321,7 +321,7 @@ class _CenterScan(LayoutWidget): step.setPrecision() step.setRelativeStep() step.setMinimum(0) - step.setValue(state["step"]) + step.setValue(state["step"]/scale) self.addWidget(step, 2, 1) self.addWidget(QtWidgets.QLabel("Step:"), 2, 0) From 292043a0a7b34222bf44aae10929b66120ff5796 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 10 Nov 2020 16:40:10 +0100 Subject: [PATCH 2430/2457] compiler: Raise AssertionErrors instead of abort()ing on all targets --- RELEASE_NOTES.rst | 6 +- artiq/compiler/module.py | 11 +-- artiq/compiler/targets.py | 8 -- .../compiler/transforms/artiq_ir_generator.py | 97 +------------------ artiq/coredevice/core.py | 3 +- artiq/test/coredevice/test_embedding.py | 15 +-- 6 files changed, 17 insertions(+), 123 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 62a87ef69..13ffd7094 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -15,8 +15,10 @@ Highlights: - Mirny 4-channel wide-band PLL/VCO-based microwave frequency synthesiser - Fastino 32-channel, 3MS/s per channel, 16-bit DAC EEM - Kasli 2.0 -* Matrix math support on the core device. -* Trigonometric functions and miscellaneous math library support on the core device. +* ARTIQ Python (core device kernels): + - Matrix math support on the core device. + - Trigonometric functions and miscellaneous math library support on the core device. + - Failed assertions now raise ``AssertionError``\ s instead of aborting kernel execution. * Performance improvements: - SERDES TTL inputs can now detect edges on pulses that are shorter than the RTIO period (https://github.com/m-labs/artiq/issues/1432) diff --git a/artiq/compiler/module.py b/artiq/compiler/module.py index 3cce61105..d43404b20 100644 --- a/artiq/compiler/module.py +++ b/artiq/compiler/module.py @@ -40,8 +40,7 @@ class Source: return cls(source.Buffer(f.read(), filename, 1), engine=engine) class Module: - def __init__(self, src, ref_period=1e-6, attribute_writeback=True, remarks=False, - raise_assertion_errors=False): + def __init__(self, src, ref_period=1e-6, attribute_writeback=True, remarks=False): self.attribute_writeback = attribute_writeback self.engine = src.engine self.embedding_map = src.embedding_map @@ -56,11 +55,9 @@ class Module: iodelay_estimator = transforms.IODelayEstimator(engine=self.engine, ref_period=ref_period) constness_validator = validators.ConstnessValidator(engine=self.engine) - artiq_ir_generator = transforms.ARTIQIRGenerator( - engine=self.engine, - module_name=src.name, - ref_period=ref_period, - raise_assertion_errors=raise_assertion_errors) + artiq_ir_generator = transforms.ARTIQIRGenerator(engine=self.engine, + module_name=src.name, + ref_period=ref_period) dead_code_eliminator = transforms.DeadCodeEliminator(engine=self.engine) local_access_validator = validators.LocalAccessValidator(engine=self.engine) local_demoter = transforms.LocalDemoter() diff --git a/artiq/compiler/targets.py b/artiq/compiler/targets.py index 427d9f07c..9ebc7907d 100644 --- a/artiq/compiler/targets.py +++ b/artiq/compiler/targets.py @@ -80,9 +80,6 @@ class Target: determined from data_layout due to JIT. :var now_pinning: (boolean) Whether the target implements the now-pinning RTIO optimization. - :var raise_assertion_errors: (bool) - Whether to raise an AssertionError on failed assertions or abort/panic - instead. """ triple = "unknown" data_layout = "" @@ -90,7 +87,6 @@ class Target: print_function = "printf" little_endian = False now_pinning = True - raise_assertion_errors = False tool_ld = "ld.lld" tool_strip = "llvm-strip" @@ -281,10 +277,6 @@ class CortexA9Target(Target): little_endian = True now_pinning = False - # Support for marshalling kernel CPU panics as RunAborted errors is not - # implemented in the ARTIQ Zynq runtime. - raise_assertion_errors = True - tool_ld = "armv7-unknown-linux-gnueabihf-ld" tool_strip = "armv7-unknown-linux-gnueabihf-strip" tool_addr2line = "armv7-unknown-linux-gnueabihf-addr2line" diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 075bf581d..9673eb89f 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -53,12 +53,6 @@ class ARTIQIRGenerator(algorithm.Visitor): a component of a composite right-hand side when visiting a composite left-hand side, such as, in ``x, y = z``, the 2nd tuple element when visting ``y`` - :ivar current_assert_env: (:class:`ir.Alloc` of type :class:`ir.TEnvironment`) - the environment where the individual components of current assert - statement are stored until display - :ivar current_assert_subexprs: (list of (:class:`ast.AST`, string)) - the mapping from components of current assert statement to the names - their values have in :ivar:`current_assert_env` :ivar break_target: (:class:`ir.BasicBlock` or None) the basic block to which ``break`` will transfer control :ivar continue_target: (:class:`ir.BasicBlock` or None) @@ -94,12 +88,11 @@ class ARTIQIRGenerator(algorithm.Visitor): _size_type = builtins.TInt32() - def __init__(self, module_name, engine, ref_period, raise_assertion_errors): + def __init__(self, module_name, engine, ref_period): self.engine = engine self.functions = [] self.name = [module_name] if module_name != "" else [] self.ref_period = ir.Constant(ref_period, builtins.TFloat()) - self.raise_assertion_errors = raise_assertion_errors self.current_loc = None self.current_function = None self.current_class = None @@ -109,8 +102,6 @@ class ARTIQIRGenerator(algorithm.Visitor): self.current_private_env = None self.current_args = None self.current_assign = None - self.current_assert_env = None - self.current_assert_subexprs = None self.break_target = None self.continue_target = None self.return_target = None @@ -1324,7 +1315,6 @@ class ARTIQIRGenerator(algorithm.Visitor): for value_node in node.values: value_head = self.current_block value = self.visit(value_node) - self.instrument_assert(value_node, value) value_tail = self.current_block blocks.append((value, value_head, value_tail)) @@ -2014,11 +2004,9 @@ class ARTIQIRGenerator(algorithm.Visitor): # of comparisons. blocks = [] lhs = self.visit(node.left) - self.instrument_assert(node.left, lhs) for op, rhs_node in zip(node.ops, node.comparators): result_head = self.current_block rhs = self.visit(rhs_node) - self.instrument_assert(rhs_node, rhs) result = self.polymorphic_compare_pair(op, lhs, rhs) result_tail = self.current_block @@ -2475,22 +2463,6 @@ class ARTIQIRGenerator(algorithm.Visitor): def visit_QuoteT(self, node): return self.append(ir.Quote(node.value, node.type)) - def instrument_assert(self, node, value): - if self.current_assert_env is not None: - if isinstance(value, ir.Constant): - return # don't display the values of constants - - if any([algorithm.compare(node, subexpr) - for (subexpr, name) in self.current_assert_subexprs]): - return # don't display the same subexpression twice - - name = self.current_assert_env.type.add("$subexpr", ir.TOption(node.type)) - value_opt = self.append(ir.Alloc([value], ir.TOption(node.type)), - loc=node.loc) - self.append(ir.SetLocal(self.current_assert_env, name, value_opt), - loc=node.loc) - self.current_assert_subexprs.append((node, name)) - def _get_raise_assert_func(self): """Emit the helper function that constructs AssertionErrors and raises them, if it does not already exist in the current module. @@ -2542,38 +2514,10 @@ class ARTIQIRGenerator(algorithm.Visitor): return self.raise_assert_func def visit_Assert(self, node): - try: - assert_suffix = ".assert@{}:{}".format(node.loc.line(), node.loc.column()) - assert_env_type = ir.TEnvironment(name=self.current_function.name + assert_suffix, - vars={}) - assert_env = self.current_assert_env = \ - self.append(ir.Alloc([], assert_env_type, name="assertenv")) - assert_subexprs = self.current_assert_subexprs = [] - init = self.current_block - - prehead = self.current_block = self.add_block("assert.prehead") - cond = self.visit(node.test) - head = self.current_block - finally: - self.current_assert_env = None - self.current_assert_subexprs = None - - for subexpr_node, subexpr_name in assert_subexprs: - empty = init.append(ir.Alloc([], ir.TOption(subexpr_node.type))) - init.append(ir.SetLocal(assert_env, subexpr_name, empty)) - init.append(ir.Branch(prehead)) + cond = self.visit(node.test) + head = self.current_block if_failed = self.current_block = self.add_block("assert.fail") - - if self.raise_assertion_errors: - self._raise_assertion_error(node) - else: - self._abort_after_assertion(node, assert_subexprs, assert_env) - - tail = self.current_block = self.add_block("assert.tail") - self.append(ir.BranchIf(cond, tail, if_failed), block=head) - - def _raise_assertion_error(self, node): text = str(node.msg.s) if node.msg else "AssertionError" msg = ir.Constant(text, builtins.TStr()) loc_file = ir.Constant(node.loc.source_buffer.name, builtins.TStr()) @@ -2584,39 +2528,8 @@ class ARTIQIRGenerator(algorithm.Visitor): msg, loc_file, loc_line, loc_column, loc_function ], "assert.fail") - def _abort_after_assertion(self, node, assert_subexprs, assert_env): - if node.msg: - explanation = node.msg.s - else: - explanation = node.loc.source() - self.append(ir.Builtin("printf", [ - ir.Constant("assertion failed at %.*s: %.*s\n\x00", builtins.TStr()), - ir.Constant(str(node.loc.begin()), builtins.TStr()), - ir.Constant(str(explanation), builtins.TStr()), - ], builtins.TNone())) - - for subexpr_node, subexpr_name in assert_subexprs: - subexpr_head = self.current_block - subexpr_value_opt = self.append(ir.GetLocal(assert_env, subexpr_name)) - subexpr_cond = self.append(ir.Builtin("is_some", [subexpr_value_opt], - builtins.TBool())) - - subexpr_body = self.current_block = self.add_block("assert.subexpr.body") - self.append(ir.Builtin("printf", [ - ir.Constant(" (%.*s) = \x00", builtins.TStr()), - ir.Constant(subexpr_node.loc.source(), builtins.TStr()) - ], builtins.TNone())) - subexpr_value = self.append(ir.Builtin("unwrap", [subexpr_value_opt], - subexpr_node.type)) - self.polymorphic_print([subexpr_value], separator="", suffix="\n") - subexpr_postbody = self.current_block - - subexpr_tail = self.current_block = self.add_block("assert.subexpr.tail") - self.append(ir.Branch(subexpr_tail), block=subexpr_postbody) - self.append(ir.BranchIf(subexpr_cond, subexpr_body, subexpr_tail), block=subexpr_head) - - self.append(ir.Builtin("abort", [], builtins.TNone())) - self.append(ir.Unreachable()) + tail = self.current_block = self.add_block("assert.tail") + self.append(ir.BranchIf(cond, tail, if_failed), block=head) def polymorphic_print(self, values, separator, suffix="", as_repr=False, as_rtio=False): def printf(format_string, *args): diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py index 87d6a854f..d150df596 100644 --- a/artiq/coredevice/core.py +++ b/artiq/coredevice/core.py @@ -106,8 +106,7 @@ class Core: module = Module(stitcher, ref_period=self.ref_period, - attribute_writeback=attribute_writeback, - raise_assertion_errors=self.target_cls.raise_assertion_errors) + attribute_writeback=attribute_writeback) target = self.target_cls() library = target.compile_and_link([module]) diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 0d6da1cd4..23d74fd7e 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -466,9 +466,6 @@ class _Assert(EnvExperiment): def build(self): self.setattr_device("core") - def raises_assertion_errors(self): - return self.core.target_cls.raises_assertion_errors - @kernel def check(self, value): assert value @@ -483,15 +480,9 @@ class AssertTest(ExperimentCase): exp = self.create(_Assert) def check_fail(fn, msg): - if exp.raises_assertion_errors: - with self.assertRaises(AssertionError) as ctx: - fn() - self.assertEqual(str(ctx.exception), msg) - else: - # Without assertion exceptions, core device panics should still lead - # to a cleanly dropped connectionr rather than a hang/… - with self.assertRaises(ConnectionResetError): - fn() + with self.assertRaises(AssertionError) as ctx: + fn() + self.assertEqual(str(ctx.exception), msg) exp.check(True) check_fail(lambda: exp.check(False), "AssertionError") From bc6fbecbdaebf6c61b777d97e687f1244fa113c4 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 10 Nov 2020 19:53:39 +0100 Subject: [PATCH 2431/2457] compiler, firmware: Do not expose abort() to kernels This was only exposed for the assert implementation, and does not exist on Zynq. --- artiq/compiler/transforms/llvm_ir_generator.py | 4 ---- artiq/firmware/ksupport/api.rs | 1 - 2 files changed, 5 deletions(-) diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 003de3c1a..8ee010cc7 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -374,8 +374,6 @@ class LLVMIRGenerator: llty = ll.FunctionType(llvoid, [self.llty_of_type(builtins.TException())]) elif name == "__artiq_reraise": llty = ll.FunctionType(llvoid, []) - elif name in "abort": - llty = ll.FunctionType(llvoid, []) elif name == "memcmp": llty = ll.FunctionType(lli32, [llptr, llptr, lli32]) elif name == "rpc_send": @@ -1143,8 +1141,6 @@ class LLVMIRGenerator: def process_Builtin(self, insn): if insn.op == "nop": return self.llbuilder.call(self.llbuiltin("llvm.donothing"), []) - if insn.op == "abort": - return self.llbuilder.call(self.llbuiltin("abort"), []) elif insn.op == "is_some": lloptarg = self.map(insn.operands[0]) return self.llbuilder.extract_value(lloptarg, 0, diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 89a6f638c..873dc6f71 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -63,7 +63,6 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(__powidf2), /* libc */ - api!(abort = ::abort), api!(memcmp, extern { fn memcmp(a: *const u8, b: *mut u8, size: usize); }), /* libm */ From fcf4763ae77d14587db3b3b236831145221364c9 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 10 Nov 2020 20:37:05 +0100 Subject: [PATCH 2432/2457] RELEASE_NOTES: Expand information on ndarrays --- RELEASE_NOTES.rst | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 13ffd7094..defab6744 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -16,9 +16,14 @@ Highlights: - Fastino 32-channel, 3MS/s per channel, 16-bit DAC EEM - Kasli 2.0 * ARTIQ Python (core device kernels): - - Matrix math support on the core device. - - Trigonometric functions and miscellaneous math library support on the core device. - - Failed assertions now raise ``AssertionError``\ s instead of aborting kernel execution. + - Multidimensional arrays are now available on the core device, using NumPy syntax. + Elementwise operations (e.g. ``+``, ``/``), matrix multiplication (``@``) and + multidimensional indexing are supported; slices and views are not yet. + - Trigonometric and other common math functions from NumPy are now available on the + core device (e.g. ``numpy.sin``), both for scalar arguments and implicitly + broadcast across multidimensional arrays. + - Failed assertions now raise ``AssertionError``\ s instead of aborting kernel + execution. * Performance improvements: - SERDES TTL inputs can now detect edges on pulses that are shorter than the RTIO period (https://github.com/m-labs/artiq/issues/1432) @@ -45,6 +50,10 @@ Breaking changes: * ``artiq_netboot`` has been moved to its own repository at https://git.m-labs.hk/m-labs/artiq-netboot * Core device watchdogs have been removed. +* The ARTIQ compiler now implements arrays following NumPy semantics, rather than as a + thin veneer around lists. Most prior use cases of NumPy arrays in kernels should work + unchanged with the new implementation, but the behavior might differ slightly in some + cases (for instance, non-rectangular arrays are not currently supported). ARTIQ-5 From d95e61956743d986970ad0f0e1d4cf4e3da86cf5 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Tue, 10 Nov 2020 22:24:04 +0100 Subject: [PATCH 2433/2457] =?UTF-8?q?compiler:=20Implement=20binary=20NumP?= =?UTF-8?q?y=20math=20functions=20(arctan2,=20=E2=80=A6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bulk of the diff is just factoring out the implementation for binary arithmetic implementations, to be reused for binary function calls. --- artiq/compiler/math_fns.py | 21 ++- .../compiler/transforms/artiq_ir_generator.py | 170 ++++++++++-------- artiq/compiler/transforms/inferencer.py | 114 +++++++----- artiq/firmware/ksupport/api.rs | 4 + artiq/test/coredevice/test_numpy.py | 25 ++- artiq/test/lit/embedding/array_math_fns.py | 11 ++ artiq/test/lit/embedding/math_fns.py | 1 + 7 files changed, 211 insertions(+), 135 deletions(-) diff --git a/artiq/compiler/math_fns.py b/artiq/compiler/math_fns.py index 8b1b38914..c54eac552 100644 --- a/artiq/compiler/math_fns.py +++ b/artiq/compiler/math_fns.py @@ -53,23 +53,36 @@ unary_fp_runtime_calls = [ ("cbrt", "cbrt"), ] +#: (float, float) -> float numpy.* math functions lowered to runtime calls. +binary_fp_runtime_calls = [ + ("arctan2", "atan2"), + ("copysign", "copysign"), + ("fmax", "fmax"), + ("fmin", "fmin"), + # ("ldexp", "ldexp"), # One argument is an int; would need a bit more plumbing. + ("hypot", "hypot"), + ("nextafter", "nextafter"), +] + #: Array handling builtins (special treatment due to allocations). numpy_builtins = ["transpose"] -def unary_fp_type(name): - return types.TExternalFunction(OrderedDict([("arg", builtins.TFloat())]), +def fp_runtime_type(name, arity): + args = [("arg{}".format(i), builtins.TFloat()) for i in range(arity)] + return types.TExternalFunction(OrderedDict(args), builtins.TFloat(), name, # errno isn't observable from ARTIQ Python. flags={"nounwind", "nowrite"}, broadcast_across_arrays=True) - numpy_map = { - getattr(numpy, symbol): unary_fp_type(mangle) + getattr(numpy, symbol): fp_runtime_type(mangle, arity=1) for symbol, mangle in (unary_fp_intrinsics + unary_fp_runtime_calls) } +for symbol, mangle in binary_fp_runtime_calls: + numpy_map[getattr(numpy, symbol)] = fp_runtime_type(mangle, arity=2) for name in numpy_builtins: numpy_map[getattr(numpy, name)] = types.TBuiltinFunction("numpy." + name) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 9673eb89f..14a45a0e4 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -1502,6 +1502,48 @@ class ARTIQIRGenerator(algorithm.Visitor): self.final_branch = old_final_branch self.unwind_target = old_unwind + def _make_array_elementwise_binop(self, name, result_type, lhs_type, + rhs_type, make_op): + def body_gen(result, lhs, rhs): + # At this point, shapes are assumed to match; could just pass buffer + # pointer for two of the three arrays as well. + result_buffer = self.append(ir.GetAttr(result, "buffer")) + shape = self.append(ir.GetAttr(result, "shape")) + num_total_elts = self._get_total_array_len(shape) + + if builtins.is_array(lhs.type): + lhs_buffer = self.append(ir.GetAttr(lhs, "buffer")) + def get_left(index): + return self.append(ir.GetElem(lhs_buffer, index)) + else: + def get_left(index): + return lhs + + if builtins.is_array(rhs.type): + rhs_buffer = self.append(ir.GetAttr(rhs, "buffer")) + def get_right(index): + return self.append(ir.GetElem(rhs_buffer, index)) + else: + def get_right(index): + return rhs + + def loop_gen(index): + l = get_left(index) + r = get_right(index) + result = make_op(l, r) + self.append(ir.SetElem(result_buffer, index, result)) + return self.append( + ir.Arith(ast.Add(loc=None), index, + ir.Constant(1, self._size_type))) + + self._make_loop( + ir.Constant(0, self._size_type), lambda index: self.append( + ir.Compare(ast.Lt(loc=None), index, num_total_elts)), + loop_gen) + + return self._make_array_binop(name, result_type, lhs_type, rhs_type, + body_gen) + def _mangle_arrayop_types(self, types): def name_error(typ): assert False, "Internal compiler error: No RPC tag for {}".format(typ) @@ -1517,53 +1559,16 @@ class ARTIQIRGenerator(algorithm.Visitor): return "_".join(mangle_name(t) for t in types) - def _get_array_binop(self, op, result_type, lhs_type, rhs_type): + def _get_array_elementwise_binop(self, name, make_op, result_type, lhs_type, rhs_type): # Currently, we always have any type coercions resolved explicitly in the AST. # In the future, this might no longer be true and the three types might all # differ. name = "_array_{}_{}".format( - type(op).__name__, + name, self._mangle_arrayop_types([result_type, lhs_type, rhs_type])) if name not in self.array_op_funcs: - - def body_gen(result, lhs, rhs): - # At this point, shapes are assumed to match; could just pass buffer - # pointer for two of the three arrays as well. - result_buffer = self.append(ir.GetAttr(result, "buffer")) - shape = self.append(ir.GetAttr(result, "shape")) - num_total_elts = self._get_total_array_len(shape) - - if builtins.is_array(lhs.type): - lhs_buffer = self.append(ir.GetAttr(lhs, "buffer")) - def get_left(index): - return self.append(ir.GetElem(lhs_buffer, index)) - else: - def get_left(index): - return lhs - - if builtins.is_array(rhs.type): - rhs_buffer = self.append(ir.GetAttr(rhs, "buffer")) - def get_right(index): - return self.append(ir.GetElem(rhs_buffer, index)) - else: - def get_right(index): - return rhs - - def loop_gen(index): - l = get_left(index) - r = get_right(index) - result = self.append(ir.Arith(op, l, r)) - self.append(ir.SetElem(result_buffer, index, result)) - return self.append( - ir.Arith(ast.Add(loc=None), index, - ir.Constant(1, self._size_type))) - - self._make_loop( - ir.Constant(0, self._size_type), lambda index: self.append( - ir.Compare(ast.Lt(loc=None), index, num_total_elts)), loop_gen) - - self.array_op_funcs[name] = self._make_array_binop( - name, result_type, lhs_type, rhs_type, body_gen) + self.array_op_funcs[name] = self._make_array_elementwise_binop( + name, result_type, lhs_type, rhs_type, make_op) return self.array_op_funcs[name] def _invoke_arrayop(self, func, params): @@ -1721,6 +1726,34 @@ class ARTIQIRGenerator(algorithm.Visitor): return self.append(ir.Alloc([result_buffer, shape], node.type)) return self.append(ir.GetElem(result_buffer, ir.Constant(0, self._size_type))) + def _broadcast_binop(self, name, make_op, result_type, lhs, rhs): + # Broadcast scalars (broadcasting higher dimensions is not yet allowed in the + # language). + broadcast = False + array_arg = lhs + if not builtins.is_array(lhs.type): + broadcast = True + array_arg = rhs + elif not builtins.is_array(rhs.type): + broadcast = True + + shape = self.append(ir.GetAttr(array_arg, "shape")) + + if not broadcast: + rhs_shape = self.append(ir.GetAttr(rhs, "shape")) + self._make_check( + self.append(ir.Compare(ast.Eq(loc=None), shape, rhs_shape)), + lambda: self.alloc_exn( + builtins.TException("ValueError"), + ir.Constant("operands could not be broadcast together", + builtins.TStr()))) + + elt = result_type.find()["elt"] + result, _ = self._allocate_new_array(elt, shape) + func = self._get_array_elementwise_binop(name, make_op, result_type, lhs.type, + rhs.type) + self._invoke_arrayop(func, [result, lhs, rhs]) + return result def visit_BinOpT(self, node): if isinstance(node.op, ast.MatMult): @@ -1728,31 +1761,10 @@ class ARTIQIRGenerator(algorithm.Visitor): elif builtins.is_array(node.type): lhs = self.visit(node.left) rhs = self.visit(node.right) - - # Broadcast scalars. - broadcast = False - array_arg = lhs - if not builtins.is_array(lhs.type): - broadcast = True - array_arg = rhs - elif not builtins.is_array(rhs.type): - broadcast = True - - shape = self.append(ir.GetAttr(array_arg, "shape")) - - if not broadcast: - rhs_shape = self.append(ir.GetAttr(rhs, "shape")) - self._make_check( - self.append(ir.Compare(ast.Eq(loc=None), shape, rhs_shape)), - lambda: self.alloc_exn( - builtins.TException("ValueError"), - ir.Constant("operands could not be broadcast together", - builtins.TStr()))) - - result, _ = self._allocate_new_array(node.type.find()["elt"], shape) - func = self._get_array_binop(node.op, node.type, lhs.type, rhs.type) - self._invoke_arrayop(func, [result, lhs, rhs]) - return result + name = type(node.op).__name__ + def make_op(l, r): + return self.append(ir.Arith(node.op, l, r)) + return self._broadcast_binop(name, make_op, node.type, lhs, rhs) elif builtins.is_numeric(node.type): lhs = self.visit(node.left) rhs = self.visit(node.right) @@ -2427,25 +2439,27 @@ class ARTIQIRGenerator(algorithm.Visitor): if types.is_builtin(node.func.type): insn = self.visit_builtin_call(node) elif (types.is_broadcast_across_arrays(node.func.type) and len(args) >= 1 - and builtins.is_array(args[0].type)): + and any(builtins.is_array(arg.type) for arg in args)): # The iodelay machinery set up in the surrounding code was # deprecated/a relic from the past when array broadcasting support # was added, so no attempt to keep the delay tracking intact is # made. - assert len(args) == 1, "Broadcasting for multiple arguments not implemented" - - def make_call(val): - return self._user_call(ir.Constant(None, callee.type), [val], {}, + def make_call(*args): + return self._user_call(ir.Constant(None, callee.type), args, {}, node.arg_exprs) - - shape = self.append(ir.GetAttr(args[0], "shape")) - result, _ = self._allocate_new_array(node.type.find()["elt"], shape) - # TODO: Generate more generically if non-externals are allowed. name = node.func.type.find().name - func = self._get_array_unaryop(name, make_call, node.type, args[0].type) - self._invoke_arrayop(func, [result, args[0]]) - insn = result + + if len(args) == 1: + shape = self.append(ir.GetAttr(args[0], "shape")) + result, _ = self._allocate_new_array(node.type.find()["elt"], shape) + func = self._get_array_unaryop(name, make_call, node.type, args[0].type) + self._invoke_arrayop(func, [result, args[0]]) + insn = result + elif len(args) == 2: + insn = self._broadcast_binop(name, make_call, node.type, *args) + else: + assert False, "Broadcasting for {} arguments not implemented".format(len) else: insn = self._user_call(callee, args, keywords, node.arg_exprs) if isinstance(node.func, asttyped.AttributeT): diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index ce0a269e1..0de455c8d 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -405,6 +405,47 @@ class Inferencer(algorithm.Visitor): else: assert False + def _coerce_binary_broadcast_op(self, left, right, map_return_elt, op_loc): + def num_dims(typ): + if builtins.is_array(typ): + # TODO: If number of dimensions is ever made a non-fixed parameter, + # need to acutally unify num_dims in _coerce_binop/…. + return typ.find()["num_dims"].value + return 0 + + left_dims = num_dims(left.type) + right_dims = num_dims(right.type) + if left_dims != right_dims and left_dims != 0 and right_dims != 0: + # Mismatch (only scalar broadcast supported for now). + note1 = diagnostic.Diagnostic("note", "operand of dimension {num_dims}", + {"num_dims": left_dims}, left.loc) + note2 = diagnostic.Diagnostic("note", "operand of dimension {num_dims}", + {"num_dims": right_dims}, right.loc) + diag = diagnostic.Diagnostic( + "error", "dimensions of '{op}' array operands must match", + {"op": op_loc.source()}, op_loc, [left.loc, right.loc], [note1, note2]) + self.engine.process(diag) + return + + def map_node_type(typ): + if not builtins.is_array(typ): + # This is a single value broadcast across the array. + return typ + return typ.find()["elt"] + + # Figure out result type, handling broadcasts. + result_dims = left_dims if left_dims else right_dims + def map_return(typ): + elt = map_return_elt(typ) + result = builtins.TArray(elt=elt, num_dims=result_dims) + left = builtins.TArray(elt=elt, num_dims=left_dims) if left_dims else elt + right = builtins.TArray(elt=elt, num_dims=right_dims) if right_dims else elt + return (result, left, right) + + return self._coerce_numeric((left, right), + map_return=map_return, + map_node_type=map_node_type) + def _coerce_binop(self, op, left, right): if isinstance(op, ast.MatMult): if types.is_var(left.type) or types.is_var(right.type): @@ -477,45 +518,11 @@ class Inferencer(algorithm.Visitor): self.engine.process(diag) return - def num_dims(typ): - if builtins.is_array(typ): - # TODO: If number of dimensions is ever made a non-fixed parameter, - # need to acutally unify num_dims in _coerce_binop. - return typ.find()["num_dims"].value - return 0 - - left_dims = num_dims(left.type) - right_dims = num_dims(right.type) - if left_dims != right_dims and left_dims != 0 and right_dims != 0: - # Mismatch (only scalar broadcast supported for now). - note1 = diagnostic.Diagnostic("note", "operand of dimension {num_dims}", - {"num_dims": left_dims}, left.loc) - note2 = diagnostic.Diagnostic("note", "operand of dimension {num_dims}", - {"num_dims": right_dims}, right.loc) - diag = diagnostic.Diagnostic( - "error", "dimensions of '{op}' array operands must match", - {"op": op.loc.source()}, op.loc, [left.loc, right.loc], [note1, note2]) - self.engine.process(diag) - return - - def map_node_type(typ): - if not builtins.is_array(typ): - # This is a single value broadcast across the array. - return typ - return typ.find()["elt"] - - # Figure out result type, handling broadcasts. - result_dims = left_dims if left_dims else right_dims - def map_return(typ): - elt = builtins.TFloat() if isinstance(op, ast.Div) else typ - result = builtins.TArray(elt=elt, num_dims=result_dims) - left = builtins.TArray(elt=elt, num_dims=left_dims) if left_dims else elt - right = builtins.TArray(elt=elt, num_dims=right_dims) if right_dims else elt - return (result, left, right) - - return self._coerce_numeric((left, right), - map_return=map_return, - map_node_type=map_node_type) + def map_result(typ): + if isinstance(op, ast.Div): + return builtins.TFloat() + return typ + return self._coerce_binary_broadcast_op(left, right, map_result, op.loc) elif isinstance(op, (ast.BitAnd, ast.BitOr, ast.BitXor, ast.LShift, ast.RShift)): # bitwise operators require integers @@ -1290,15 +1297,26 @@ class Inferencer(algorithm.Visitor): self.engine.process(diag) return - # Array broadcasting for unary functions explicitly marked as such. - if len(node.args) == typ_arity == 1 and types.is_broadcast_across_arrays(typ): - arg_type = node.args[0].type.find() - if builtins.is_array(arg_type): - typ_arg, = typ_args.values() - self._unify(typ_arg, arg_type["elt"], node.args[0].loc, None) - self._unify(node.type, builtins.TArray(typ_ret, arg_type["num_dims"]), - node.loc, None) - return + # Array broadcasting for functions explicitly marked as such. + if len(node.args) == typ_arity and types.is_broadcast_across_arrays(typ): + if typ_arity == 1: + arg_type = node.args[0].type.find() + if builtins.is_array(arg_type): + typ_arg, = typ_args.values() + self._unify(typ_arg, arg_type["elt"], node.args[0].loc, None) + self._unify(node.type, builtins.TArray(typ_ret, arg_type["num_dims"]), + node.loc, None) + return + elif typ_arity == 2: + if any(builtins.is_array(arg.type) for arg in node.args): + ret, arg0, arg1 = self._coerce_binary_broadcast_op( + node.args[0], node.args[1], lambda t: typ_ret, node.loc) + node.args[0] = self._coerce_one(arg0, node.args[0], + other_node=node.args[1]) + node.args[1] = self._coerce_one(arg1, node.args[1], + other_node=node.args[0]) + self._unify(node.type, ret, node.loc, None) + return for actualarg, (formalname, formaltyp) in \ zip(node.args, list(typ_args.items()) + list(typ_optargs.items())): diff --git a/artiq/firmware/ksupport/api.rs b/artiq/firmware/ksupport/api.rs index 873dc6f71..84e69dad5 100644 --- a/artiq/firmware/ksupport/api.rs +++ b/artiq/firmware/ksupport/api.rs @@ -76,6 +76,7 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(atanh), api!(cbrt), api!(ceil), + api!(copysign), api!(cos), api!(cosh), api!(erf), @@ -86,6 +87,8 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(expm1), api!(fabs), api!(floor), + // api!(fmax), + // api!(fmin), //api!(fma), api!(fmod), api!(hypot), @@ -96,6 +99,7 @@ static mut API: &'static [(&'static str, *const ())] = &[ api!(log), //api!(log2), api!(log10), + api!(nextafter), api!(pow), api!(round), api!(sin), diff --git a/artiq/test/coredevice/test_numpy.py b/artiq/test/coredevice/test_numpy.py index caaa2ce27..a3b7b5a00 100644 --- a/artiq/test/coredevice/test_numpy.py +++ b/artiq/test/coredevice/test_numpy.py @@ -27,7 +27,7 @@ class CompareHostDeviceTest(ExperimentCase): def _test_binop(self, op, a, b): exp = self.create(_RunOnDevice) exp.run = kernel_from_string(["a", "b", "callback", "numpy"], - "callback(a " + op + "b)", + "callback(" + op + ")", decorator=portable) checked = False @@ -74,16 +74,17 @@ class CompareHostDeviceTest(ExperimentCase): for typ in [numpy.int32, numpy.int64, numpy.float]] for op in ELEM_WISE_BINOPS: for arg in args: - self._test_binop(op, *arg) + self._test_binop("a" + op + "b", *arg) def test_scalar_matrix_binops(self): for typ in [numpy.int32, numpy.int64, numpy.float]: scalar = typ(3) matrix = numpy.array([[4, 5, 6], [7, 8, 9]], dtype=typ) for op in ELEM_WISE_BINOPS: - self._test_binop(op, scalar, matrix) - self._test_binop(op, matrix, scalar) - self._test_binop(op, matrix, matrix) + code = "a" + op + "b" + self._test_binop(code, scalar, matrix) + self._test_binop(code, matrix, scalar) + self._test_binop(code, matrix, matrix) def test_unary_math_fns(self): names = [ @@ -99,3 +100,17 @@ class CompareHostDeviceTest(ExperimentCase): # Avoid 0.5, as numpy.rint's rounding mode currently doesn't match. self._test_unaryop(op, 0.51) self._test_unaryop(op, numpy.array([[0.3, 0.4], [0.51, 0.6]])) + + def test_binary_math_fns(self): + names = [name for name, _ in math_fns.binary_fp_runtime_calls] + exp = self.create(_RunOnDevice) + if exp.core.target_cls != CortexA9Target: + names.remove("fmax") + names.remove("fmin") + for name in names: + code = "numpy.{}(a, b)".format(name) + # Avoid 0.5, as numpy.rint's rounding mode currently doesn't match. + self._test_binop(code, 1.0, 2.0) + self._test_binop(code, 1.0, numpy.array([2.0, 3.0])) + self._test_binop(code, numpy.array([1.0, 2.0]), 3.0) + self._test_binop(code, numpy.array([1.0, 2.0]), numpy.array([3.0, 4.0])) diff --git a/artiq/test/lit/embedding/array_math_fns.py b/artiq/test/lit/embedding/array_math_fns.py index 2b298f2ef..d23540b48 100644 --- a/artiq/test/lit/embedding/array_math_fns.py +++ b/artiq/test/lit/embedding/array_math_fns.py @@ -6,10 +6,21 @@ import numpy as np @kernel def entrypoint(): # Just make sure everything compiles. + + # LLVM intrinsic: a = np.array([1.0, 2.0, 3.0]) b = np.sin(a) assert b.shape == a.shape + # libm: c = np.array([1.0, 2.0, 3.0]) d = np.arctan(c) assert d.shape == c.shape + + # libm, binary: + e = np.array([1.0, 2.0, 3.0]) + f = np.array([4.0, 5.0, 6.0]) + g = np.arctan2(e, f) + # g = np.arctan2(e, 0.0) + # g = np.arctan2(0.0, f) + assert g.shape == e.shape diff --git a/artiq/test/lit/embedding/math_fns.py b/artiq/test/lit/embedding/math_fns.py index 40ac18e42..6f9416c8d 100644 --- a/artiq/test/lit/embedding/math_fns.py +++ b/artiq/test/lit/embedding/math_fns.py @@ -28,3 +28,4 @@ def entrypoint(): assert numpy.arcsin(0.0) == 0.0 assert numpy.arccos(1.0) == 0.0 assert numpy.arctan(0.0) == 0.0 + assert numpy.arctan2(0.0, 1.0) == 0.0 From a5dcd86fb8e33bd1e797496b5fa5457dd6f72527 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 11 Nov 2020 17:37:54 +0100 Subject: [PATCH 2434/2457] test/lit: Rename `array` to avoid conflict with standard library The old name created problems if a test dependency (e.g. NumPy/SciPy) ends up importing the system `array` module internally somewhere. --- artiq/test/lit/inferencer/{array.py => array_creation.py} | 0 artiq/test/lit/integration/{array.py => array_creation.py} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename artiq/test/lit/inferencer/{array.py => array_creation.py} (100%) rename artiq/test/lit/integration/{array.py => array_creation.py} (100%) diff --git a/artiq/test/lit/inferencer/array.py b/artiq/test/lit/inferencer/array_creation.py similarity index 100% rename from artiq/test/lit/inferencer/array.py rename to artiq/test/lit/inferencer/array_creation.py diff --git a/artiq/test/lit/integration/array.py b/artiq/test/lit/integration/array_creation.py similarity index 100% rename from artiq/test/lit/integration/array.py rename to artiq/test/lit/integration/array_creation.py From 9ff47bacab652c25af49e65c3e0cc4b399aedc78 Mon Sep 17 00:00:00 2001 From: David Nadlinger Date: Wed, 11 Nov 2020 16:35:33 +0100 Subject: [PATCH 2435/2457] =?UTF-8?q?compiler:=20Provide=20libm=20special?= =?UTF-8?q?=20functions=20(erf,=20Bessel=20functions,=20=E2=80=A6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests hard-depend on SciPy to make sure this is exercised during CI. --- artiq/compiler/math_fns.py | 61 ++++++++++++++++++++++++----- artiq/test/coredevice/test_numpy.py | 30 +++++++++----- 2 files changed, 71 insertions(+), 20 deletions(-) diff --git a/artiq/compiler/math_fns.py b/artiq/compiler/math_fns.py index c54eac552..35d23b534 100644 --- a/artiq/compiler/math_fns.py +++ b/artiq/compiler/math_fns.py @@ -8,6 +8,15 @@ from collections import OrderedDict import numpy from . import builtins, types +# Some special mathematical functions are exposed via their scipy.special +# equivalents. Since the rest of the ARTIQ core does not depend on SciPy, +# gracefully handle it not being present, making the functions simply not +# available. +try: + import scipy.special as scipy_special +except ImportError: + scipy_special = None + #: float -> float numpy.* math functions for which llvm.* intrinsics exist. unary_fp_intrinsics = [(name, "llvm." + name + ".f64") for name in [ "sin", @@ -36,6 +45,21 @@ unary_fp_intrinsics = [(name, "llvm." + name + ".f64") for name in [ ("rint", "llvm.round.f64"), ] +#: float -> float numpy.* math functions lowered to runtime calls. +unary_fp_runtime_calls = [ + ("tan", "tan"), + ("arcsin", "asin"), + ("arccos", "acos"), + ("arctan", "atan"), + ("sinh", "sinh"), + ("cosh", "cosh"), + ("tanh", "tanh"), + ("arcsinh", "asinh"), + ("arccosh", "acosh"), + ("arctanh", "atanh"), + ("expm1", "expm1"), + ("cbrt", "cbrt"), +] #: float -> float numpy.* math functions lowered to runtime calls. unary_fp_runtime_calls = [ @@ -53,6 +77,18 @@ unary_fp_runtime_calls = [ ("cbrt", "cbrt"), ] +scipy_special_unary_runtime_calls = [ + ("erf", "erf"), + ("erfc", "erfc"), + ("gamma", "tgamma"), + ("gammaln", "lgamma"), + ("j0", "j0"), + ("j1", "j1"), + ("y0", "y0"), + ("y1", "y1"), +] +# Not mapped: jv/yv, libm only supports integer orders. + #: (float, float) -> float numpy.* math functions lowered to runtime calls. binary_fp_runtime_calls = [ ("arctan2", "atan2"), @@ -70,22 +106,27 @@ numpy_builtins = ["transpose"] def fp_runtime_type(name, arity): args = [("arg{}".format(i), builtins.TFloat()) for i in range(arity)] - return types.TExternalFunction(OrderedDict(args), - builtins.TFloat(), - name, - # errno isn't observable from ARTIQ Python. - flags={"nounwind", "nowrite"}, - broadcast_across_arrays=True) + return types.TExternalFunction( + OrderedDict(args), + builtins.TFloat(), + name, + # errno isn't observable from ARTIQ Python. + flags={"nounwind", "nowrite"}, + broadcast_across_arrays=True) -numpy_map = { + +math_fn_map = { getattr(numpy, symbol): fp_runtime_type(mangle, arity=1) for symbol, mangle in (unary_fp_intrinsics + unary_fp_runtime_calls) } for symbol, mangle in binary_fp_runtime_calls: - numpy_map[getattr(numpy, symbol)] = fp_runtime_type(mangle, arity=2) + math_fn_map[getattr(numpy, symbol)] = fp_runtime_type(mangle, arity=2) for name in numpy_builtins: - numpy_map[getattr(numpy, name)] = types.TBuiltinFunction("numpy." + name) + math_fn_map[getattr(numpy, name)] = types.TBuiltinFunction("numpy." + name) +if scipy_special is not None: + for symbol, mangle in scipy_special_unary_runtime_calls: + math_fn_map[getattr(scipy_special, symbol)] = fp_runtime_type(mangle, arity=1) def match(obj): - return numpy_map.get(obj, None) + return math_fn_map.get(obj, None) diff --git a/artiq/test/coredevice/test_numpy.py b/artiq/test/coredevice/test_numpy.py index a3b7b5a00..a4b8897bd 100644 --- a/artiq/test/coredevice/test_numpy.py +++ b/artiq/test/coredevice/test_numpy.py @@ -1,5 +1,6 @@ from artiq.experiment import * import numpy +import scipy.special from artiq.test.hardware_testbench import ExperimentCase from artiq.compiler.targets import CortexA9Target from artiq.compiler import math_fns @@ -10,12 +11,12 @@ class _RunOnDevice(EnvExperiment): self.setattr_device("core") @kernel - def run_on_kernel_unary(self, a, callback, numpy): - self.run(a, callback, numpy) + def run_on_kernel_unary(self, a, callback, numpy, scipy): + self.run(a, callback, numpy, scipy) @kernel - def run_on_kernel_binary(self, a, b, callback, numpy): - self.run(a, b, callback, numpy) + def run_on_kernel_binary(self, a, b, callback, numpy, scipy): + self.run(a, b, callback, numpy, scipy) # Binary operations supported for scalars and arrays of any dimension, including @@ -26,7 +27,7 @@ ELEM_WISE_BINOPS = ["+", "*", "//", "%", "**", "-", "/"] class CompareHostDeviceTest(ExperimentCase): def _test_binop(self, op, a, b): exp = self.create(_RunOnDevice) - exp.run = kernel_from_string(["a", "b", "callback", "numpy"], + exp.run = kernel_from_string(["a", "b", "callback", "numpy", "scipy"], "callback(" + op + ")", decorator=portable) checked = False @@ -40,14 +41,14 @@ class CompareHostDeviceTest(ExperimentCase): "Discrepancy in binop test for '{}': Expexcted ({}, {}) -> {}, got {}" .format(op, a, b, host, device)) - exp.run_on_kernel_binary(a, b, with_both_results, numpy) + exp.run_on_kernel_binary(a, b, with_both_results, numpy, scipy) - exp.run(a, b, with_host_result, numpy) + exp.run(a, b, with_host_result, numpy, scipy) self.assertTrue(checked, "Test did not run") def _test_unaryop(self, op, a): exp = self.create(_RunOnDevice) - exp.run = kernel_from_string(["a", "callback", "numpy"], + exp.run = kernel_from_string(["a", "callback", "numpy", "scipy"], "callback(" + op + ")", decorator=portable) checked = False @@ -61,9 +62,9 @@ class CompareHostDeviceTest(ExperimentCase): "Discrepancy in unaryop test for '{}': Expexcted {} -> {}, got {}" .format(op, a, host, device)) - exp.run_on_kernel_unary(a, with_both_results, numpy) + exp.run_on_kernel_unary(a, with_both_results, numpy, scipy) - exp.run(a, with_host_result, numpy) + exp.run(a, with_host_result, numpy, scipy) self.assertTrue(checked, "Test did not run") def test_scalar_scalar_binops(self): @@ -101,6 +102,15 @@ class CompareHostDeviceTest(ExperimentCase): self._test_unaryop(op, 0.51) self._test_unaryop(op, numpy.array([[0.3, 0.4], [0.51, 0.6]])) + def test_unary_scipy_fns(self): + names = [name for name, _ in math_fns.scipy_special_unary_runtime_calls] + if self.create(_RunOnDevice).core.target_cls != CortexA9Target: + names.remove("gamma") + for name in names: + op = "scipy.special.{}(a)".format(name) + self._test_unaryop(op, 0.5) + self._test_unaryop(op, numpy.array([[0.3, 0.4], [0.5, 0.6]])) + def test_binary_math_fns(self): names = [name for name, _ in math_fns.binary_fp_runtime_calls] exp = self.create(_RunOnDevice) From 3e3883302001eaee5c46ff33726ef16b25537fb7 Mon Sep 17 00:00:00 2001 From: Marius Weber Date: Tue, 29 Sep 2020 01:24:39 +0100 Subject: [PATCH 2436/2457] ad9910: fix `turns_to_pow` return-type on host When run on the host, the `turns_to_pow` retrun-type is numpy.int64. Sensibly, the compiler does not attempt to convert `numpy.int64` to `int32`. Signed-off-by: Marius Weber --- artiq/coredevice/ad9910.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ad9910.py b/artiq/coredevice/ad9910.py index fbe6bca41..c1e828cf7 100644 --- a/artiq/coredevice/ad9910.py +++ b/artiq/coredevice/ad9910.py @@ -596,7 +596,7 @@ class AD9910: def turns_to_pow(self, turns) -> TInt32: """Return the 16-bit phase offset word corresponding to the given phase in turns.""" - return int32(round(turns*0x10000)) & 0xffff + return int32(round(turns*0x10000)) & int32(0xffff) @portable(flags={"fast-math"}) def pow_to_turns(self, pow_): From 0605267424fa2016ccc93addbe626e0fd2392ac8 Mon Sep 17 00:00:00 2001 From: SingularitySurfer Date: Thu, 19 Nov 2020 12:20:34 +0000 Subject: [PATCH 2437/2457] modified urukul instructions --- artiq/frontend/artiq_sinara_tester.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_sinara_tester.py b/artiq/frontend/artiq_sinara_tester.py index 48b095729..7c51e49f6 100755 --- a/artiq/frontend/artiq_sinara_tester.py +++ b/artiq/frontend/artiq_sinara_tester.py @@ -259,6 +259,8 @@ class SinaraTester(EnvExperiment): eeprom.write_i32(offset, eeprom_word) print("...done") + print("All urukul channels active.") + print("Check each channel amplitude (~1.6Vpp/8dbm at 50ohm) and frequency.") print("Frequencies:") for card_n, channels in enumerate(chunker(self.urukuls, 4)): for channel_n, (channel_name, channel_dev) in enumerate(channels): @@ -270,7 +272,8 @@ class SinaraTester(EnvExperiment): sw = [channel_dev for channel_name, channel_dev in self.urukuls if hasattr(channel_dev, "sw")] if sw: - print("Testing RF switch control. Press ENTER when done.") + print("Testing RF switch control. Check LEDs at urukul RF ports.") + print("Press ENTER when done.") for swi in sw: self.cfg_sw_off_urukul(swi) self.rf_switch_wave([swi.sw for swi in sw]) From 8e46c3c1fd8b9332da8e7ac995eaff376baa6ca9 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 22 Nov 2020 11:57:21 +0800 Subject: [PATCH 2438/2457] Revert "compiler: fix incorrect with behavior" This reverts commit fe6115bcbbeb3caca596b904231851e24c18afb1. --- artiq/compiler/transforms/artiq_ir_generator.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 14a45a0e4..068d75cdd 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -878,7 +878,8 @@ class ARTIQIRGenerator(algorithm.Visitor): self.current_assign = None none = self.append(ir.Alloc([], builtins.TNone())) - cleanup.append(lambda fn=exit_fn: self._user_call(fn, [none, none, none], {})) + call = self._user_call(exit_fn, [none, none, none], {}) + cleanup.append(lambda: call) self._try_finally( body_gen=lambda: self.visit(node.body), From eda4850f640d605bf50fbfc6e517f4501c377abd Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 22 Nov 2020 11:57:22 +0800 Subject: [PATCH 2439/2457] Revert "fixes with statement with multiple items" This reverts commit 88d346fa26fd29646ab28f678dda8e24c8d6ceaa. --- artiq/compiler/transforms/artiq_ir_generator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 068d75cdd..2a7f56d26 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -878,8 +878,8 @@ class ARTIQIRGenerator(algorithm.Visitor): self.current_assign = None none = self.append(ir.Alloc([], builtins.TNone())) - call = self._user_call(exit_fn, [none, none, none], {}) - cleanup.append(lambda: call) + cleanup.append(lambda: + self._user_call(exit_fn, [none, none, none], {})) self._try_finally( body_gen=lambda: self.visit(node.body), From d51d4e6ce084e1eafd53dbf02b1dfbeb314e2ceb Mon Sep 17 00:00:00 2001 From: Harry Ho Date: Thu, 26 Nov 2020 10:53:39 +0800 Subject: [PATCH 2440/2457] doc: fix missing instructions for bypassing Si5324 on Kasli --- doc/manual/installing.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index dbebb129f..e91163808 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -287,9 +287,9 @@ For DRTIO systems, the startup kernel should wait until the desired destinations If you are using DRTIO and the default routing table (for a star topology) is not suitable to your needs, prepare and load a different routing table. See :ref:`Using DRTIO `. -* Select the RTIO clock source (KC705 only) +* Select the RTIO clock source (KC705 and Kasli) -The KC705 may use either an external clock signal or its internal clock. The clock is selected at power-up. Use one of these commands: :: +The KC705 may use either an external clock signal or its internal clock. The clock is selected at power-up. For Kasli, setting the RTIO clock source to "external" would bypass the Si5324 synthesiser, requiring that an input clock be present. To select the source, use one of these commands: :: $ artiq_coremgmt config write -s rtio_clock i # internal clock (default) $ artiq_coremgmt config write -s rtio_clock e # external clock From cba631610c360f1ca3698cadb5045e769b553019 Mon Sep 17 00:00:00 2001 From: SingularitySurfer Date: Fri, 4 Dec 2020 14:40:59 +0000 Subject: [PATCH 2441/2457] fixed phaser number of rtio channels --- artiq/frontend/artiq_ddb_template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 3f208c4a7..1ea85b08a 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -498,7 +498,7 @@ class PeripheralManager: }}""", name=self.get_name("phaser"), channel=rtio_offset) - return 2 + return 6 def process(self, rtio_offset, peripheral): processor = getattr(self, "process_"+str(peripheral["type"])) From 9b4b550f760eacfb5c6609d8b60a787b11757347 Mon Sep 17 00:00:00 2001 From: SingularitySurfer Date: Fri, 4 Dec 2020 14:49:30 +0000 Subject: [PATCH 2442/2457] 5 is correct. --- artiq/frontend/artiq_ddb_template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 1ea85b08a..f40d2d60a 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -498,7 +498,7 @@ class PeripheralManager: }}""", name=self.get_name("phaser"), channel=rtio_offset) - return 6 + return 5 def process(self, rtio_offset, peripheral): processor = getattr(self, "process_"+str(peripheral["type"])) From 94271504dd174b41bfa76f4401af3987c403e957 Mon Sep 17 00:00:00 2001 From: Leon Riesebos Date: Wed, 2 Dec 2020 15:51:45 -0500 Subject: [PATCH 2443/2457] Added RuntimeError to prelude to make the name available in kernels closes #1477 Signed-off-by: Leon Riesebos --- artiq/compiler/prelude.py | 1 + 1 file changed, 1 insertion(+) diff --git a/artiq/compiler/prelude.py b/artiq/compiler/prelude.py index ee47168ac..9e1a3846d 100644 --- a/artiq/compiler/prelude.py +++ b/artiq/compiler/prelude.py @@ -25,6 +25,7 @@ def globals(): "IndexError": builtins.fn_IndexError(), "ValueError": builtins.fn_ValueError(), "ZeroDivisionError": builtins.fn_ZeroDivisionError(), + "RuntimeError": builtins.fn_RuntimeError(), # Built-in Python functions "len": builtins.fn_len(), From 3b2c225fc446dc1d0718732e74fe06001b796f53 Mon Sep 17 00:00:00 2001 From: Leon Riesebos Date: Wed, 2 Dec 2020 17:29:39 -0500 Subject: [PATCH 2444/2457] allow dashboard to close if no connection can be made to moninj Signed-off-by: Leon Riesebos --- artiq/dashboard/moninj.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py index cea227cb0..0233fd8d7 100644 --- a/artiq/dashboard/moninj.py +++ b/artiq/dashboard/moninj.py @@ -399,6 +399,9 @@ class _DeviceManager: self.disconnect_cb) try: await new_core_connection.connect(self.core_addr, 1383) + except asyncio.CancelledError: + logger.info("cancelled connection to core device moninj") + break except: logger.error("failed to connect to core device moninj", exc_info=True) await asyncio.sleep(10.) From ccdc741e73307e30240f2c78ba171889e4baff0f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 7 Dec 2020 18:02:36 +0800 Subject: [PATCH 2445/2457] sayma_amc: fix --sfp argument --- artiq/gateware/targets/sayma_amc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 7f8a8a5b8..59fa820f7 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -416,7 +416,7 @@ def main(): parser.add_argument("-V", "--variant", default="satellite", help="variant: satellite/simplesatellite " "(default: %(default)s)") - parser.add_argument("--sfp", default=False, + parser.add_argument("--sfp", default=False, action="store_true", help="use SFP port for DRTIO instead of uTCA backplane") parser.add_argument("--rtm-csr-csv", default=os.path.join("artiq_sayma", "rtm_gateware", "rtm_csr.csv"), From 072053c3b23108870a7bf66a50438d7717a04c6f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 8 Dec 2020 13:24:58 +0800 Subject: [PATCH 2446/2457] compiler: remove obsolete watchdog code (#1458) --- artiq/compiler/builtins.py | 3 -- artiq/compiler/prelude.py | 1 - .../compiler/transforms/artiq_ir_generator.py | 38 +++++++------------ artiq/compiler/transforms/inferencer.py | 7 +--- .../compiler/transforms/llvm_ir_generator.py | 11 ------ artiq/test/libartiq_support/lib.rs | 11 ------ .../test/lit/codegen/error_illegal_builtin.py | 5 --- artiq/test/lit/time/watchdog.py | 36 ------------------ 8 files changed, 14 insertions(+), 98 deletions(-) delete mode 100644 artiq/test/lit/codegen/error_illegal_builtin.py delete mode 100644 artiq/test/lit/time/watchdog.py diff --git a/artiq/compiler/builtins.py b/artiq/compiler/builtins.py index 7a0aa6161..b5662aec6 100644 --- a/artiq/compiler/builtins.py +++ b/artiq/compiler/builtins.py @@ -222,9 +222,6 @@ def obj_interleave(): def obj_sequential(): return types.TBuiltin("sequential") -def fn_watchdog(): - return types.TBuiltinFunction("watchdog") - def fn_delay(): return types.TBuiltinFunction("delay") diff --git a/artiq/compiler/prelude.py b/artiq/compiler/prelude.py index 9e1a3846d..13f319650 100644 --- a/artiq/compiler/prelude.py +++ b/artiq/compiler/prelude.py @@ -44,7 +44,6 @@ def globals(): "parallel": builtins.obj_parallel(), "interleave": builtins.obj_interleave(), "sequential": builtins.obj_sequential(), - "watchdog": builtins.fn_watchdog(), # ARTIQ time management functions "delay": builtins.fn_delay(), diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 2a7f56d26..afa75b61b 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -851,35 +851,23 @@ class ARTIQIRGenerator(algorithm.Visitor): cleanup = [] for item_node in node.items: + # user-defined context manager context_expr_node = item_node.context_expr optional_vars_node = item_node.optional_vars + context_mgr = self.visit(context_expr_node) + enter_fn = self.append(ir.GetAttr(context_mgr, '__enter__')) + exit_fn = self.append(ir.GetAttr(context_mgr, '__exit__')) - if isinstance(context_expr_node, asttyped.CallT) and \ - types.is_builtin(context_expr_node.func.type, "watchdog"): - timeout = self.visit(context_expr_node.args[0]) - timeout_ms = self.append(ir.Arith(ast.Mult(loc=None), timeout, - ir.Constant(1000, builtins.TFloat()))) - timeout_ms_int = self.append(ir.Coerce(timeout_ms, builtins.TInt64())) + try: + self.current_assign = self._user_call(enter_fn, [], {}) + if optional_vars_node is not None: + self.visit(optional_vars_node) + finally: + self.current_assign = None - watchdog_id = self.append(ir.Builtin("watchdog_set", [timeout_ms_int], - builtins.TInt32())) - cleanup.append(lambda: - self.append(ir.Builtin("watchdog_clear", [watchdog_id], builtins.TNone()))) - else: # user-defined context manager - context_mgr = self.visit(context_expr_node) - enter_fn = self.append(ir.GetAttr(context_mgr, '__enter__')) - exit_fn = self.append(ir.GetAttr(context_mgr, '__exit__')) - - try: - self.current_assign = self._user_call(enter_fn, [], {}) - if optional_vars_node is not None: - self.visit(optional_vars_node) - finally: - self.current_assign = None - - none = self.append(ir.Alloc([], builtins.TNone())) - cleanup.append(lambda: - self._user_call(exit_fn, [none, none, none], {})) + none = self.append(ir.Alloc([], builtins.TNone())) + cleanup.append(lambda: + self._user_call(exit_fn, [none, none, none], {})) self._try_finally( body_gen=lambda: self.visit(node.body), diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 0de455c8d..684c575de 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -1211,9 +1211,6 @@ class Inferencer(algorithm.Visitor): elif types.is_builtin(typ, "at_mu"): simple_form("at_mu(time_mu:numpy.int64) -> None", [builtins.TInt64()]) - elif types.is_builtin(typ, "watchdog"): - simple_form("watchdog(time:float) -> [builtin context manager]", - [builtins.TFloat()], builtins.TNone()) elif types.is_constructor(typ): # An user-defined class. self._unify(node.type, typ.find().instance, @@ -1458,9 +1455,7 @@ class Inferencer(algorithm.Visitor): typ = node.context_expr.type if (types.is_builtin(typ, "interleave") or types.is_builtin(typ, "sequential") or - types.is_builtin(typ, "parallel") or - (isinstance(node.context_expr, asttyped.CallT) and - types.is_builtin(node.context_expr.func.type, "watchdog"))): + types.is_builtin(typ, "parallel")): # builtin context managers if node.optional_vars is not None: self._unify(node.optional_vars.type, builtins.TNone(), diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 8ee010cc7..ce2530bf4 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -395,10 +395,6 @@ class LLVMIRGenerator: elif name == "delay_mu": llty = ll.FunctionType(llvoid, [lli64]) - elif name == "watchdog_set": - llty = ll.FunctionType(lli32, [lli64]) - elif name == "watchdog_clear": - llty = ll.FunctionType(llvoid, [lli32]) else: assert False @@ -407,7 +403,6 @@ class LLVMIRGenerator: if name in ("__artiq_raise", "__artiq_reraise", "llvm.trap"): llglobal.attributes.add("noreturn") if name in ("rtio_log", "rpc_send", "rpc_send_async", - "watchdog_set", "watchdog_clear", self.target.print_function): llglobal.attributes.add("nounwind") if name.find("__py_") == 0: @@ -1239,12 +1234,6 @@ class LLVMIRGenerator: return llstore_lo else: return self.llbuilder.call(self.llbuiltin("delay_mu"), [llinterval]) - elif insn.op == "watchdog_set": - interval, = insn.operands - return self.llbuilder.call(self.llbuiltin("watchdog_set"), [self.map(interval)]) - elif insn.op == "watchdog_clear": - id, = insn.operands - return self.llbuilder.call(self.llbuiltin("watchdog_clear"), [self.map(id)]) else: assert False diff --git a/artiq/test/libartiq_support/lib.rs b/artiq/test/libartiq_support/lib.rs index 51344b402..77e8f4160 100644 --- a/artiq/test/libartiq_support/lib.rs +++ b/artiq/test/libartiq_support/lib.rs @@ -76,14 +76,3 @@ fn terminate(exception: &eh_artiq::Exception, mut _backtrace: &mut [usize]) -> ! #[export_name = "now"] pub static mut NOW: i64 = 0; - -#[export_name = "watchdog_set"] -pub extern fn watchdog_set(ms: i64) -> i32 { - println!("watchdog_set {}", ms); - ms as i32 -} - -#[export_name = "watchdog_clear"] -pub extern fn watchdog_clear(id: i32) { - println!("watchdog_clear {}", id); -} diff --git a/artiq/test/lit/codegen/error_illegal_builtin.py b/artiq/test/lit/codegen/error_illegal_builtin.py deleted file mode 100644 index ae75ad9b7..000000000 --- a/artiq/test/lit/codegen/error_illegal_builtin.py +++ /dev/null @@ -1,5 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.signature +diag %s >%t -# RUN: OutputCheck %s --file-to-check=%t - -# CHECK-L: ${LINE:+1}: error: builtin function 'watchdog' cannot be used in this context -watchdog(1.0) diff --git a/artiq/test/lit/time/watchdog.py b/artiq/test/lit/time/watchdog.py deleted file mode 100644 index ccd3048bc..000000000 --- a/artiq/test/lit/time/watchdog.py +++ /dev/null @@ -1,36 +0,0 @@ -# RUN: %python -m artiq.compiler.testbench.jit %s >%t -# RUN: OutputCheck %s --file-to-check=%t -# REQUIRES: time - -def f(): - with watchdog(1.0): - pass - -def g(): - with watchdog(2.0): - raise Exception() - -def h(): - try: - g() - except: - pass - -def i(): - try: - with watchdog(3.0): - raise Exception() - except: - pass - -# CHECK-L: watchdog_set 1000 -# CHECK-L: watchdog_clear 1000 -f() - -# CHECK-L: watchdog_set 2000 -# CHECK-L: watchdog_clear 2000 -h() - -# CHECK-L: watchdog_set 3000 -# CHECK-L: watchdog_clear 3000 -i() From 1ce505c547eec422778a0964f4a4690fe5846bdc Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 8 Dec 2020 13:25:39 +0800 Subject: [PATCH 2447/2457] coredevice: remove obsolete watchdog code (#1458) --- artiq/coredevice/comm_kernel.py | 3 --- artiq/coredevice/exceptions.py | 4 ---- 2 files changed, 7 deletions(-) diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index 98211d592..5387b9d10 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -36,7 +36,6 @@ class Reply(Enum): RPCRequest = 10 - WatchdogExpired = 14 ClockFailure = 15 @@ -627,8 +626,6 @@ class CommKernel: self._serve_rpc(embedding_map) elif self._read_type == Reply.KernelException: self._serve_exception(embedding_map, symbolizer, demangler) - elif self._read_type == Reply.WatchdogExpired: - raise exceptions.WatchdogExpired elif self._read_type == Reply.ClockFailure: raise exceptions.ClockFailure else: diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index 8260739d2..cfa2ce85a 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -104,10 +104,6 @@ class DMAError(Exception): artiq_builtin = True -class WatchdogExpired(Exception): - """Raised when a watchdog expires.""" - - class ClockFailure(Exception): """Raised when RTIO PLL has lost lock.""" From 4b10273a2d7047d8ad3f4bba7fbdef0282e4bcd2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sat, 12 Dec 2020 21:50:11 +0800 Subject: [PATCH 2448/2457] gui: quamash -> qasync --- RELEASE_NOTES.rst | 1 + artiq/applets/simple.py | 6 +++--- artiq/frontend/artiq_browser.py | 5 +---- artiq/frontend/artiq_dashboard.py | 5 +---- doc/manual/conf.py | 2 +- setup.py | 2 +- 6 files changed, 8 insertions(+), 13 deletions(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index defab6744..4ab9f0537 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -54,6 +54,7 @@ Breaking changes: thin veneer around lists. Most prior use cases of NumPy arrays in kernels should work unchanged with the new implementation, but the behavior might differ slightly in some cases (for instance, non-rectangular arrays are not currently supported). +* ``quamash`` has been replaced with ``qasync``. ARTIQ-5 diff --git a/artiq/applets/simple.py b/artiq/applets/simple.py index 71c2d34fd..e5776310a 100644 --- a/artiq/applets/simple.py +++ b/artiq/applets/simple.py @@ -4,7 +4,7 @@ import asyncio import os import string -from quamash import QEventLoop, QtWidgets, QtCore +from qasync import QEventLoop, QtWidgets, QtCore from sipyco.sync_struct import Subscriber, process_mod from sipyco import pyon @@ -114,7 +114,7 @@ class SimpleApplet: self.datasets = {getattr(self.args, arg.replace("-", "_")) for arg in self.dataset_args} - def quamash_init(self): + def qasync_init(self): app = QtWidgets.QApplication([]) self.loop = QEventLoop(app) asyncio.set_event_loop(self.loop) @@ -212,7 +212,7 @@ class SimpleApplet: def run(self): self.args_init() - self.quamash_init() + self.qasync_init() try: self.ipc_init() try: diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index 9e514fba0..fc6d25fe2 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -8,7 +8,7 @@ import logging import sys from PyQt5 import QtCore, QtGui, QtWidgets -from quamash import QEventLoop +from qasync import QEventLoop from sipyco.asyncio_tools import atexit_register_coroutine from sipyco import common_args @@ -144,9 +144,6 @@ def main(): app = QtWidgets.QApplication(["ARTIQ Browser"]) loop = QEventLoop(app) asyncio.set_event_loop(loop) - # https://github.com/harvimt/quamash/issues/123 - if sys.version_info >= (3, 8): - asyncio.events._set_running_loop(loop) atexit.register(loop.close) datasets_sub = models.LocalModelManager(datasets.Model) diff --git a/artiq/frontend/artiq_dashboard.py b/artiq/frontend/artiq_dashboard.py index 66e79269c..bd9127f9d 100755 --- a/artiq/frontend/artiq_dashboard.py +++ b/artiq/frontend/artiq_dashboard.py @@ -8,7 +8,7 @@ import logging import sys from PyQt5 import QtCore, QtGui, QtWidgets -from quamash import QEventLoop +from qasync import QEventLoop from sipyco.pc_rpc import AsyncioClient, Client from sipyco.broadcast import Receiver @@ -104,9 +104,6 @@ def main(): app = QtWidgets.QApplication(["ARTIQ Dashboard"]) loop = QEventLoop(app) asyncio.set_event_loop(loop) - # https://github.com/harvimt/quamash/issues/123 - if sys.version_info >= (3, 8): - asyncio.events._set_running_loop(loop) atexit.register(loop.close) smgr = state.StateManager(args.db_file) diff --git a/doc/manual/conf.py b/doc/manual/conf.py index 13c1b7394..cb00b7afb 100644 --- a/doc/manual/conf.py +++ b/doc/manual/conf.py @@ -36,7 +36,7 @@ mock_modules = ["artiq.gui.waitingspinnerwidget", "artiq.compiler.module", "artiq.compiler.embedding", "artiq.dashboard", - "quamash", "pyqtgraph", "matplotlib", + "qasync", "pyqtgraph", "matplotlib", "numpy", "dateutil", "dateutil.parser", "prettytable", "PyQt5", "h5py", "serial", "scipy", "scipy.interpolate", "llvmlite_artiq", "Levenshtein", "pythonparser", diff --git a/setup.py b/setup.py index 95bbbe2ab..b8b5d7e1f 100755 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ if sys.version_info[:3] < (3, 5, 3): requirements = [ "numpy", "scipy", "python-dateutil", "prettytable", "h5py", - "quamash", "pyqtgraph", "pygit2", + "qasync", "pyqtgraph", "pygit2", "llvmlite_artiq", "pythonparser", "python-Levenshtein", ] From 33d39b261a8d56ec6ecfa45a84747d189bcee695 Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 14 Dec 2020 12:39:34 +0800 Subject: [PATCH 2449/2457] artiq_ddb_template: mirny_cpld: rename adf5355 to adf5356 Signed-off-by: occheung --- artiq/frontend/artiq_ddb_template.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index f40d2d60a..c8088753e 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -257,8 +257,8 @@ class PeripheralManager: self.gen(""" device_db["{name}_ch{mchn}"] = {{ "type": "local", - "module": "artiq.coredevice.adf5355", - "class": "ADF5355", + "module": "artiq.coredevice.adf5356", + "class": "ADF5356", "arguments": {{ "channel": {mchn}, "sw_device": "ttl_{name}_sw{mchn}", From 3f631c417d3b86c229e360b357a0e59c16dd6f2f Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 14 Dec 2020 12:42:40 +0800 Subject: [PATCH 2450/2457] artiq_ddb_template: mirny_cpld: add refclk, clk_sel args Signed-off-by: occheung --- artiq/frontend/artiq_ddb_template.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index c8088753e..8c19cacd3 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -273,9 +273,15 @@ class PeripheralManager: "type": "local", "module": "artiq.coredevice.mirny", "class": "Mirny", - "arguments": {{"spi_device": "spi_{name}"}}, + "arguments": {{ + "spi_device": "spi_{name}", + "refclk": {refclk}, + "clk_sel": {clk_sel} + }}, }}""", - name=mirny_name) + name=mirny_name, + refclk=peripheral.get("refclk", self.master_description.get("rtio_frequency", 125e6)), + clk_sel=peripheral["clk_sel"]) return next(channel) From 73271600a1fcccc40ff1365ddb8980dccf6b3053 Mon Sep 17 00:00:00 2001 From: Harry Ho Date: Thu, 10 Dec 2020 16:30:28 +0800 Subject: [PATCH 2451/2457] jdcg: STPL tests now perform after DAC initialization --- artiq/firmware/satman/jdcg.rs | 21 ++++++++++++++++----- artiq/firmware/satman/main.rs | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/satman/jdcg.rs b/artiq/firmware/satman/jdcg.rs index c581791a3..c8a34827b 100644 --- a/artiq/firmware/satman/jdcg.rs +++ b/artiq/firmware/satman/jdcg.rs @@ -108,10 +108,6 @@ pub mod jdac { basic_request(dacno, jdac_common::PRBS, 0)?; jesd::prbs(dacno, false); - jesd::stpl(dacno, true); - basic_request(dacno, jdac_common::STPL, 0)?; - jesd::stpl(dacno, false); - basic_request(dacno, jdac_common::INIT, 0)?; clock::spin_us(5000); @@ -120,7 +116,22 @@ pub mod jdac { return Err("JESD core reported bad SYNC"); } - info!(" ...done"); + info!(" ...done initializing"); + } + Ok(()) + } + + pub fn stpl() -> Result<(), &'static str> { + for dacno in 0..csr::JDCG.len() { + let dacno = dacno as u8; + + info!("Running STPL test on DAC-{}...", dacno); + + jesd::stpl(dacno, true); + basic_request(dacno, jdac_common::STPL, 0)?; + jesd::stpl(dacno, false); + + info!(" ...done STPL test"); } Ok(()) } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 60f0f4c0a..e8dfb3584 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -609,6 +609,7 @@ pub extern fn main() -> i32 { jdcg::jesd::reset(false); let _ = jdcg::jdac::init(); jdcg::jesd204sync::sysref_auto_align(); + jdcg::jdac::stpl(); unsafe { csr::drtio_transceiver::txenable_write(0xffffffffu32 as _); // unhide } From a017dafee6511e85dd7b95bd36b808c596b8503f Mon Sep 17 00:00:00 2001 From: occheung Date: Tue, 15 Dec 2020 10:38:56 +0800 Subject: [PATCH 2452/2457] ddb_template: mirny_cpld: add default value Signed-off-by: Oi Chee Cheung --- artiq/frontend/artiq_ddb_template.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 8c19cacd3..15d584fb1 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -280,8 +280,8 @@ class PeripheralManager: }}, }}""", name=mirny_name, - refclk=peripheral.get("refclk", self.master_description.get("rtio_frequency", 125e6)), - clk_sel=peripheral["clk_sel"]) + refclk=peripheral.get("refclk", 100e6), + clk_sel=peripheral.get("clk_sel", 0)) return next(channel) From 0a14cc585575cc3458d9c011ba9bfff538b94ff5 Mon Sep 17 00:00:00 2001 From: Aadit Rahul Kamat Date: Thu, 17 Dec 2020 11:48:14 +0800 Subject: [PATCH 2453/2457] Update link to Release Notes doc in PR template Signed-off-by: Aadit Rahul Kamat --- .github/pull_request_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 55e829cc4..0df6f0f36 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -38,7 +38,7 @@ Closes #XXX ### All Pull Requests - [x] Use correct spelling and grammar. -- [ ] Update [RELEASE_NOTES.md](../RELEASE_NOTES.md) if there are noteworthy changes, especially if there are changes to existing APIs. +- [ ] Update [RELEASE_NOTES.rst](../RELEASE_NOTES.rst) if there are noteworthy changes, especially if there are changes to existing APIs. - [ ] Close/update issues. - [ ] Check the copyright situation of your changes and sign off your patches (`git commit --signoff`, see [copyright](../CONTRIBUTING.rst#copyright-and-sign-off)). From 19f75f1cfda20a37110c69f836fec80edd5bfa8e Mon Sep 17 00:00:00 2001 From: Aadit Rahul Kamat Date: Thu, 17 Dec 2020 10:51:22 +0800 Subject: [PATCH 2454/2457] artiq_browser: update h5py api call Signed-off-by: Aadit Rahul Kamat --- artiq/browser/files.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/artiq/browser/files.py b/artiq/browser/files.py index ea36777d2..103ca28db 100644 --- a/artiq/browser/files.py +++ b/artiq/browser/files.py @@ -42,7 +42,7 @@ class ThumbnailIconProvider(QtWidgets.QFileIconProvider): except KeyError: return try: - img = QtGui.QImage.fromData(t.value) + img = QtGui.QImage.fromData(t[()]) except: logger.warning("unable to read thumbnail from %s", info.filePath(), exc_info=True) @@ -102,13 +102,13 @@ class Hdf5FileSystemModel(QtWidgets.QFileSystemModel): h5 = open_h5(info) if h5 is not None: try: - expid = pyon.decode(h5["expid"].value) - start_time = datetime.fromtimestamp(h5["start_time"].value) + expid = pyon.decode(h5["expid"][()]) + start_time = datetime.fromtimestamp(h5["start_time"][()]) v = ("artiq_version: {}\nrepo_rev: {}\nfile: {}\n" "class_name: {}\nrid: {}\nstart_time: {}").format( - h5["artiq_version"].value, expid["repo_rev"], + h5["artiq_version"][()], expid["repo_rev"], expid["file"], expid["class_name"], - h5["rid"].value, start_time) + h5["rid"][()], start_time) return v except: logger.warning("unable to read metadata from %s", @@ -174,14 +174,14 @@ class FilesDock(QtWidgets.QDockWidget): logger.debug("loading datasets from %s", info.filePath()) with f: try: - expid = pyon.decode(f["expid"].value) - start_time = datetime.fromtimestamp(f["start_time"].value) + expid = pyon.decode(f["expid"][()]) + start_time = datetime.fromtimestamp(f["start_time"][()]) v = { - "artiq_version": f["artiq_version"].value, + "artiq_version": f["artiq_version"][()], "repo_rev": expid["repo_rev"], "file": expid["file"], "class_name": expid["class_name"], - "rid": f["rid"].value, + "rid": f["rid"][()], "start_time": start_time, } self.metadata_changed.emit(v) @@ -190,13 +190,13 @@ class FilesDock(QtWidgets.QDockWidget): info.filePath(), exc_info=True) rd = dict() if "archive" in f: - rd = {k: (True, v.value) for k, v in f["archive"].items()} + rd = {k: (True, v[()]) for k, v in f["archive"].items()} if "datasets" in f: for k, v in f["datasets"].items(): if k in rd: logger.warning("dataset '%s' is both in archive and " "outputs", k) - rd[k] = (True, v.value) + rd[k] = (True, v[()]) if rd: self.datasets.init(rd) self.dataset_changed.emit(info.filePath()) From 8cd794e9f4e737357c0394a1d8ce1afc1b420868 Mon Sep 17 00:00:00 2001 From: Harry Ho Date: Wed, 16 Dec 2020 13:34:43 +0800 Subject: [PATCH 2455/2457] jesd204_tools: use new syntax from jesd204b core * requires jesd204b changes as in https://github.com/HarryMakes/jesd204b/tree/gth --- artiq/gateware/jesd204_tools.py | 102 +++++++++++++++++++++++++++----- 1 file changed, 88 insertions(+), 14 deletions(-) diff --git a/artiq/gateware/jesd204_tools.py b/artiq/gateware/jesd204_tools.py index 27a1ce6cc..d05d6432f 100644 --- a/artiq/gateware/jesd204_tools.py +++ b/artiq/gateware/jesd204_tools.py @@ -8,14 +8,19 @@ from misoc.interconnect.csr import * from jesd204b.common import (JESD204BTransportSettings, JESD204BPhysicalSettings, JESD204BSettings) -from jesd204b.phy.gth import GTHChannelPLL as JESD204BGTHChannelPLL +from jesd204b.phy.gth import (GTHChannelPLL as JESD204BGTHChannelPLL, + GTHQuadPLL as JESD204BGTHQuadPLL, + GTHTransmitter as JESD204BGTHTransmitter, + GTHInit as JESD204BGTHInit, + GTHTransmitterInterconnect as JESD204BGTHTransmitterInterconnect) from jesd204b.phy import JESD204BPhyTX from jesd204b.core import JESD204BCoreTX from jesd204b.core import JESD204BCoreTXControl class UltrascaleCRG(Module, AutoCSR): - linerate = int(6e9) + linerate = int(6e9) # linerate = 20*data_rate*4/8 = data_rate*10 + # data_rate = dac_rate/interp_factor refclk_freq = int(150e6) fabric_freq = int(125e6) @@ -45,27 +50,96 @@ PhyPads = namedtuple("PhyPads", "txp txn") class UltrascaleTX(Module, AutoCSR): - def __init__(self, platform, sys_crg, jesd_crg, dac): + def __init__(self, platform, sys_crg, jesd_crg, dac, pll_type="cpll", tx_half=False): + # Note: In general, the choice between channel and quad PLLs can be made based on the "nominal operating ranges", which are (see UG576, Ch.2): + # CPLL: 2.0 - 6.25 GHz + # QPLL0: 9.8 - 16.375 GHz + # QPLL1: 8.0 - 13.0 GHz + # However, the exact frequency and/or linerate range should be checked according to the model and speed grade from their corresponding datasheets. + pll_cls = { + "cpll": JESD204BGTHChannelPLL, + "qpll": JESD204BGTHQuadPLL + }[pll_type] ps = JESD204BPhysicalSettings(l=8, m=4, n=16, np=16) ts = JESD204BTransportSettings(f=2, s=2, k=16, cs=0) settings = JESD204BSettings(ps, ts, did=0x5a, bid=0x5) jesd_pads = platform.request("dac_jesd", dac) + plls = [] phys = [] for i in range(len(jesd_pads.txp)): - cpll = JESD204BGTHChannelPLL( - jesd_crg.refclk, jesd_crg.refclk_freq, jesd_crg.linerate) - self.submodules += cpll + pll = pll_cls( + jesd_crg.refclk, jesd_crg.refclk_freq, jesd_crg.linerate) + self.submodules += pll + plls.append(pll) + # QPLL quads + if pll_type == "qpll": + gthe3_common_cfgs = [] + for i in range(0, len(plls), 4): + # GTHE3_COMMON common signals + qpll_clk = Signal() + qpll_refclk = Signal() + qpll_reset = Signal() + qpll_lock = Signal() + # GTHE3_COMMON + self.specials += pll_cls.get_gthe3_common( + jesd_crg.refclk, jesd_crg.refclk_freq, jesd_crg.linerate, + qpll_clk, qpll_refclk, qpll_reset, qpll_lock) + gthe3_common_cfgs.append({ + "clk": qpll_clk, + "refclk": qpll_refclk, + "reset": qpll_reset, + "lock": qpll_lock + }) + # Per-channel PLL phys + for i, pll in enumerate(plls): + # PhyTX phy = JESD204BPhyTX( - cpll, PhyPads(jesd_pads.txp[i], jesd_pads.txn[i]), - jesd_crg.fabric_freq, transceiver="gth") - platform.add_period_constraint(phy.transmitter.cd_tx.clk, - 40*1e9/jesd_crg.linerate) - platform.add_false_path_constraints( - sys_crg.cd_sys.clk, - jesd_crg.cd_jesd.clk, - phy.transmitter.cd_tx.clk) + pll, jesd_crg.refclk, PhyPads(jesd_pads.txp[i], jesd_pads.txn[i]), + jesd_crg.fabric_freq, transceiver="gth", tx_half=tx_half) phys.append(phy) + if tx_half: + platform.add_period_constraint(phy.transmitter.cd_tx_half.clk, + 80*1e9/jesd_crg.linerate) + platform.add_false_path_constraints( + sys_crg.cd_sys.clk, + jesd_crg.cd_jesd.clk, + phy.transmitter.cd_tx_half.clk) + else: + platform.add_period_constraint(phy.transmitter.cd_tx.clk, + 40*1e9/jesd_crg.linerate) + platform.add_false_path_constraints( + sys_crg.cd_sys.clk, + jesd_crg.cd_jesd.clk, + phy.transmitter.cd_tx.clk) + # CHANNEL & init interconnects + for i, (pll, phy) in enumerate(zip(plls, phys)): + # CPLLs: 1 init per channel + if pll_type == "cpll": + phy_channel_cfg = {} + # Connect reset/lock to init + pll_reset = pll.reset + pll_lock = pll.lock + self.submodules += JESD204BGTHTransmitterInterconnect( + pll_reset, pll_lock, phy.transmitter, phy.transmitter.init) + # QPLL: 4 inits and 4 channels per quad + elif pll_type == "qpll": + # Connect clk/refclk to CHANNEL + phy_cfg = gthe3_common_cfgs[int(i//4)] + phy_channel_cfg = { + "qpll_clk": phy_cfg["clk"], + "qpll_refclk": phy_cfg["refclk"] + } + # Connect reset/lock to init + pll_reset = phy_cfg["reset"] + pll_lock = phy_cfg["lock"] + if i % 4 == 0: + self.submodules += JESD204BGTHTransmitterInterconnect( + pll_reset, pll_lock, phy.transmitter, + [phys[j].transmitter.init for j in range(i, min(len(phys), i+4))]) + # GTHE3_CHANNEL + self.specials += JESD204BGTHTransmitter.get_gthe3_channel( + pll, phy.transmitter, **phy_channel_cfg) self.submodules.core = JESD204BCoreTX( phys, settings, converter_data_width=64) From 43ecb3fea6b1580a7563613181c86df1a8ad614a Mon Sep 17 00:00:00 2001 From: Harry Ho Date: Tue, 15 Dec 2020 18:06:02 +0800 Subject: [PATCH 2456/2457] sayma: add comments about CPLL line rate on KU GTH --- artiq/gateware/targets/sayma_amc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/artiq/gateware/targets/sayma_amc.py b/artiq/gateware/targets/sayma_amc.py index 59fa820f7..4edfc72c7 100755 --- a/artiq/gateware/targets/sayma_amc.py +++ b/artiq/gateware/targets/sayma_amc.py @@ -192,6 +192,8 @@ class SatelliteBase(MiniSoC): # JESD204 DAC Channel Group class JDCGSAWG(Module, AutoCSR): def __init__(self, platform, sys_crg, jesd_crg, dac): + # Kintex Ultrascale GTH, speed grade -1C: + # CPLL linerate (D=1): 4.0 - 8.5 Gb/s self.submodules.jesd = jesd204_tools.UltrascaleTX( platform, sys_crg, jesd_crg, dac) From 43be383c8644a79623c82f28286f1b8f571e2f06 Mon Sep 17 00:00:00 2001 From: Chris Ballance Date: Mon, 21 Dec 2020 16:43:44 +0000 Subject: [PATCH 2457/2457] kasli v2.0: drive TX_DISABLE low on all SFPs (fixes #1570) This was the same problem as #1508 but on SFP1..3 --- artiq/firmware/runtime/main.rs | 9 +++++++++ artiq/firmware/satman/main.rs | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index c64d0fc64..91646cc5e 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -106,9 +106,18 @@ fn startup() { io_expander1 = board_misoc::io_expander::IoExpander::new(1); io_expander0.init().expect("I2C I/O expander #0 initialization failed"); io_expander1.init().expect("I2C I/O expander #1 initialization failed"); + + // Actively drive TX_DISABLE to false on SFP0..3 io_expander0.set_oe(0, 1 << 1).unwrap(); + io_expander0.set_oe(1, 1 << 1).unwrap(); + io_expander1.set_oe(0, 1 << 1).unwrap(); + io_expander1.set_oe(1, 1 << 1).unwrap(); io_expander0.set(0, 1, false); + io_expander0.set(1, 1, false); + io_expander1.set(0, 1, false); + io_expander1.set(1, 1, false); io_expander0.service().unwrap(); + io_expander1.service().unwrap(); } rtio_clocking::init(); diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index e8dfb3584..0b6d1cccb 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -475,9 +475,18 @@ pub extern fn main() -> i32 { io_expander1.set(1, 7, true); io_expander1.service().unwrap(); } + + // Actively drive TX_DISABLE to false on SFP0..3 io_expander0.set_oe(0, 1 << 1).unwrap(); + io_expander0.set_oe(1, 1 << 1).unwrap(); + io_expander1.set_oe(0, 1 << 1).unwrap(); + io_expander1.set_oe(1, 1 << 1).unwrap(); io_expander0.set(0, 1, false); + io_expander0.set(1, 1, false); + io_expander1.set(0, 1, false); + io_expander1.set(1, 1, false); io_expander0.service().unwrap(); + io_expander1.service().unwrap(); } #[cfg(has_si5324)]