From d90dff4ef10182c69486dd8d92832585466c9b03 Mon Sep 17 00:00:00 2001 From: Yann Sionneau Date: Sun, 26 Jul 2015 17:40:18 +0800 Subject: [PATCH 01/38] rtio: add SERDES TTL (WIP) --- artiq/gateware/rtio/phy/ttl_serdes_7series.py | 58 ++++ artiq/gateware/rtio/phy/ttl_serdes_generic.py | 304 ++++++++++++++++++ 2 files changed, 362 insertions(+) create mode 100644 artiq/gateware/rtio/phy/ttl_serdes_7series.py create mode 100644 artiq/gateware/rtio/phy/ttl_serdes_generic.py diff --git a/artiq/gateware/rtio/phy/ttl_serdes_7series.py b/artiq/gateware/rtio/phy/ttl_serdes_7series.py new file mode 100644 index 000000000..57f3f4272 --- /dev/null +++ b/artiq/gateware/rtio/phy/ttl_serdes_7series.py @@ -0,0 +1,58 @@ +from migen.fhdl.std import * +from artiq.gateware.rtio.phy import ttl_serdes_generic + + +class OSerdese2(Module): + def __init__(self, pad): + self.o = o = Signal(8) + self.oe = oe = Signal() + self.t = t = Signal() + + self.specials += Instance("OSERDESE2", p_DATA_RATE_OQ="DDR", + p_DATA_RATE_TQ="DDR", p_DATA_WIDTH=8, + p_TRISTATE_WIDTH=1, o_OQ=pad, o_TQ=t, + 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=ResetSignal(), + i_T1=~oe) + + +class IOSerdese2(Module): + def __init__(self, pad): + ts = TSTriple() + self.o = o = Signal(8) + self.oe = oe = Signal() + self.i = i = Signal(8) + self.specials += ts.get_tristate(pad) + + 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=ts.i, i_CLK=ClockSignal("rtiox4"), + i_CE1=1, i_RST=ResetSignal(), + i_CLKDIV=ClockSignal("rio_phy")) + + oserdes = OSerdese2(ts.o) + self.submodules += oserdes + + self.comb += [ + ts.oe.eq(~oserdes.t), + oserdes.o.eq(o), + oserdes.oe.eq(oe) + ] + + +class Output(Module): + def __init__(self, pad): + serdes = OSerdese2(pad) + self.submodules += ttl_serdes_generic.Output(serdes, fine_ts_width=3) + + +class Inout(Module): + def __init__(self, pad): + serdes = IOSerdese2(pad) + self.submodules += ttl_serdes_generic.InOut(serdes, fine_ts_width=3) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_generic.py b/artiq/gateware/rtio/phy/ttl_serdes_generic.py new file mode 100644 index 000000000..56e17c7e1 --- /dev/null +++ b/artiq/gateware/rtio/phy/ttl_serdes_generic.py @@ -0,0 +1,304 @@ +from migen.fhdl.std import * +from artiq.gateware.rtio import rtlink +from migen.genlib.coding import PriorityEncoder + + +class Output(Module): + def __init__(self, serdes, fine_ts_width=0): + self.rtlink = rtlink.Interface(rtlink.OInterface(1, fine_ts_width= + fine_ts_width)) + + serdes_width = 2**fine_ts_width + o = Signal() + previous_o = Signal() + override_en = Signal() + override_o = Signal() + io_o = Signal() + self.overrides = [override_en, override_o] + + io = serdes + self.submodules += io + + if fine_ts_width > 0: + timestamp = Signal(fine_ts_width) + + # dout + edges = Array([0xff ^ ((1 << i) - 1) for i in range(serdes_width)]) + edge_out = Signal(serdes_width) + edge_out_n = Signal(serdes_width) + rise_out = Signal() + fall_out = Signal() + self.comb += [ + timestamp.eq(self.rtlink.o.fine_ts), + edge_out.eq(edges[timestamp]), + edge_out_n.eq(~edge_out), + rise_out.eq(~previous_o & o), + fall_out.eq(previous_o & ~o), + If(override_en, + io.o.eq(override_o) + ).Else( + If(rise_out, + io.o.eq(edge_out), + ).Elif(fall_out, + io.o.eq(edge_out_n), + ).Else( + io.o.eq(Replicate(o, serdes_width)), + ) + ) + ] + else: + self.comb += [ + If(override_en, + io_o.eq(override_o) + ).Else( + io_o.eq(o) + ) + ] + + self.comb += [ + io.o.eq(io_o), + ] + + self.sync.rio_phy += [ + If(self.rtlink.o.stb, + o.eq(self.rtlink.o.data), + ), + previous_o.eq(o), + ] + + +class Inout(Module): + def __init__(self, serdes, fine_ts_width=0): + self.rtlink = rtlink.Interface( + rtlink.OInterface(2, 2, fine_ts_width=fine_ts_width), + rtlink.IInterface(1, fine_ts_width=fine_ts_width)) + self.probes = [] + + serdes_width = 2**fine_ts_width + self.io = io = serdes + self.submodules += io + io_o = Signal(serdes_width) + io_i = Signal(serdes_width) + o = Signal() + rising = Signal() + falling = Signal() + i0 = Signal() + self.oe = oe = Signal() + override_en = Signal() + override_o = Signal() + override_oe = Signal() + self.sensitivity = Signal(2) + self.overrides = [override_en, override_o, override_oe] + previous_o = Signal() + + if fine_ts_width > 0: + + # Input + self.submodules.pe = pe = PriorityEncoder(serdes_width) + + self.sync.rio_phy += i0.eq(io_i[-1]) + + self.comb += [ + io_i.eq(io.i), + rising.eq(~i0 & io_i[-1]), + falling.eq(i0 & ~io_i[-1]), + pe.i.eq(io_i ^ Replicate(falling, serdes_width)), + self.rtlink.i.data.eq(io_i[-1]), + self.rtlink.i.fine_ts.eq(pe.o), + ] + + # Output + timestamp = Signal(fine_ts_width) + edges = Array([0xff ^ ((1 << i) - 1) for i in range(serdes_width)]) + edge_out = Signal(serdes_width) + edge_out_n = Signal(serdes_width) + rise_out = Signal() + fall_out = Signal() + + self.comb += [ + timestamp.eq(self.rtlink.o.fine_ts), + edge_out.eq(edges[timestamp]), + edge_out_n.eq(~edge_out), + rise_out.eq(~previous_o & o), + fall_out.eq(previous_o & ~o), + If(override_en, + io_o.eq(override_o), + ).Else( + If(rise_out, + io_o.eq(edge_out), + ).Elif(fall_out, + io_o.eq(edge_out_n), + ).Else( + io_o.eq(Replicate(o, serdes_width)), + ) + ) + ] + else: + self.comb += [ + io_i.eq(io.i), + rising.eq(~i0 & io_i), + falling.eq(i0 & ~io_i), + If(override_en, + io_o.eq(override_o) + ).Else( + io_o.eq(o), + ), + self.rtlink.i.data.eq(io_i), + ] + + self.comb += [ + io.oe.eq(oe), + io.o.eq(io_o), + self.rtlink.i.stb.eq( + (self.sensitivity[0] & rising) | + (self.sensitivity[1] & falling) + ), + ] + + self.sync.rio_phy += [ + If(self.rtlink.o.stb, + If(self.rtlink.o.address == 0, o.eq(self.rtlink.o.data[0])), + If(self.rtlink.o.address == 1, oe.eq(self.rtlink.o.data[0])), + ), + If(override_en, + oe.eq(override_oe) + ), + previous_o.eq(o), + ] + + self.sync.rio += [ + If(self.rtlink.o.stb & (self.rtlink.o.address == 2), + self.sensitivity.eq(self.rtlink.o.data) + ) + ] + +class FakeSerdes(Module): + def __init__(self): + self.o = o = Signal(8) + self.oe = oe = Signal(8) + + +class FakeIOSerdes(Module): + def __init__(self): + self.o = o = Signal(8) + self.oe = oe = Signal(8) + self.i = i = Signal(8) + + +class OutputTB(Module): + def __init__(self): + serdes = FakeSerdes() + self.o = RenameClockDomains(Output(serdes, fine_ts_width=3), + {"rio_phy": "sys"}) + self.submodules += self.o + + def gen_simulation(self, selfp): + + yield + selfp.o.rtlink.o.data = 1 + selfp.o.rtlink.o.fine_ts = 1 + selfp.o.rtlink.o.stb = 1 + yield + selfp.o.rtlink.o.stb = 0 + yield + selfp.o.rtlink.o.data = 0 + selfp.o.rtlink.o.fine_ts = 2 + selfp.o.rtlink.o.stb = 1 + yield + selfp.o.rtlink.o.data = 1 + selfp.o.rtlink.o.fine_ts = 7 + yield + + while True: + yield + + +class InoutTB(Module): + def __init__(self): + ioserdes = FakeIOSerdes() + self.io = RenameClockDomains(Inout(ioserdes, fine_ts_width=3), + {"rio_phy": "sys"}) + self.submodules += self.io + + def check_input(self, selfp, stb, fine_ts=None): + if stb != selfp.io.rtlink.i.stb: + print("KO rtlink.i.stb should be {} but is {}" + .format(stb, selfp.io.rtlink.i.stb)) + elif fine_ts is not None and fine_ts != selfp.io.rtlink.i.fine_ts: + print("KO rtlink.i.fine_ts should be {} but is {}" + .format(fine_ts, selfp.io.rtlink.i.fine_ts)) + else: + print("OK") + + def check_output(self, selfp, data): + if selfp.io.io.o != data: + print("KO io.o should be {} but is {}".format(data, selfp.io.io.o)) + else: + print("OK") + + def check_output_enable(self, selfp, oe): + if selfp.io.io.oe != oe: + print("KO io.oe should be {} but is {}".format(oe, selfp.io.io.oe)) + else: + print("OK") + + def gen_simulation(self, selfp): + selfp.io.sensitivity = 0b11 # rising + falling + self.check_output_enable(selfp, 0) + yield + selfp.io.io.i = 0b11111110 # rising edge at fine_ts = 1 + yield + self.check_input(selfp, stb=1, fine_ts=1) + selfp.io.io.i = 0b01111111 # falling edge at fine_ts = 7 + yield + self.check_input(selfp, stb=1, fine_ts=7) + selfp.io.io.i = 0b11000000 # rising edge at fine_ts = 6 + yield + self.check_input(selfp, stb=1, fine_ts=6) + selfp.io.sensitivity = 0b01 # rising + selfp.io.io.i = 0b00001111 # falling edge at fine_ts = 4 + yield + self.check_input(selfp, stb=0) # no strobe, sensitivity is rising edge + selfp.io.io.i = 0b11110000 # rising edge at fine_ts = 4 + yield + self.check_input(selfp, stb=1, fine_ts=4) + selfp.io.rtlink.o.address = 1 + selfp.io.rtlink.o.data = 1 + selfp.io.rtlink.o.stb = 1 # set Output Enable to 1 + yield + selfp.io.rtlink.o.address = 0 + selfp.io.rtlink.o.data = 1 + selfp.io.rtlink.o.fine_ts = 3 # rising edge at fine_ts = 3 + yield + self.check_output_enable(selfp, 1) + yield + selfp.io.rtlink.o.data = 0 + selfp.io.rtlink.o.fine_ts = 0 # falling edge at fine_ts = 0 + self.check_output(selfp, data=0b11111000) + yield + self.check_output(selfp, data=0xFF) # stays at 1 + yield + selfp.io.rtlink.o.data = 1 + selfp.io.rtlink.o.fine_ts = 7 + self.check_output(selfp, data=0) + yield + self.check_output(selfp, data=0) + yield + self.check_output(selfp, data=0b10000000) + while True: + yield + + +if __name__ == "__main__": + import sys + from migen.sim.generic import Simulator, TopLevel + from migen.sim import icarus + + if len(sys.argv) <= 1: + print("You should run this script with either InoutTB() or OutputTB() " + "arg") + sys.exit(1) + + with Simulator(eval(sys.argv[1]), TopLevel("top.vcd", clk_period=int(1/0.125)), + icarus.Runner(keep_files=False,)) as s: + s.run(200) From 940aa815dd31e048f73880d9fe9e7f7a52248c34 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Jul 2015 00:01:41 +0800 Subject: [PATCH 02/38] rtio/ttl_serdes: cleanup/rewrite --- artiq/gateware/rtio/phy/ttl_serdes_7series.py | 66 +-- artiq/gateware/rtio/phy/ttl_serdes_generic.py | 429 ++++++++---------- 2 files changed, 238 insertions(+), 257 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_7series.py b/artiq/gateware/rtio/phy/ttl_serdes_7series.py index 57f3f4272..ccb32ab5e 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_7series.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_7series.py @@ -1,58 +1,70 @@ from migen.fhdl.std import * + from artiq.gateware.rtio.phy import ttl_serdes_generic -class OSerdese2(Module): +class _OSERDESE2_8X(Module): def __init__(self, pad): - self.o = o = Signal(8) - self.oe = oe = Signal() - self.t = t = Signal() + self.o = Signal(8) + self.t_in = Signal() + self.t_out = Signal() + # # # + + o = self.o self.specials += Instance("OSERDESE2", p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="DDR", p_DATA_WIDTH=8, - p_TRISTATE_WIDTH=1, o_OQ=pad, o_TQ=t, + p_TRISTATE_WIDTH=1, + o_OQ=pad, o_TQ=self.t_out, 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=ResetSignal(), - i_T1=~oe) + i_TCE=1, i_OCE=1, i_RST=0, + i_T1=self.t_in) -class IOSerdese2(Module): +class _IOSERDESE2_8X(Module): def __init__(self, pad): - ts = TSTriple() - self.o = o = Signal(8) - self.oe = oe = Signal() - self.i = i = Signal(8) - self.specials += ts.get_tristate(pad) + self.o = Signal(8) + self.i = Signal(8) + self.oe = Signal() + # # # + + 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=ts.i, i_CLK=ClockSignal("rtiox4"), - i_CE1=1, i_RST=ResetSignal(), + i_D=pad_i, + i_CLK=ClockSignal("rtiox4"), + i_CLKB=~ClockSignal("rtiox4"), + i_CE1=1, i_RST=0, i_CLKDIV=ClockSignal("rio_phy")) - - oserdes = OSerdese2(ts.o) + oserdes = _OSERDESE2_8X(pad_o) self.submodules += oserdes - + self.specials += Instance("IOBUF", + i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, + io_IO=pad) self.comb += [ - ts.oe.eq(~oserdes.t), - oserdes.o.eq(o), - oserdes.oe.eq(oe) + oserdes.t_in.eq(~self.oe), + oserdes.o.eq(self.o) ] -class Output(Module): +class Output_8X(ttl_serdes_generic.Output): def __init__(self, pad): - serdes = OSerdese2(pad) - self.submodules += ttl_serdes_generic.Output(serdes, fine_ts_width=3) + serdes = _OSERDESE2_8X(pad) + self.submodules += serdes + ttl_serdes_generic.Output.__init__(self, serdes) -class Inout(Module): +class Inout_8X(ttl_serdes_generic.Inout): def __init__(self, pad): - serdes = IOSerdese2(pad) - self.submodules += ttl_serdes_generic.InOut(serdes, fine_ts_width=3) + serdes = _IOSERDESE2_8X(pad) + self.submodules += serdes + ttl_serdes_generic.Inout.__init__(self, serdes) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_generic.py b/artiq/gateware/rtio/phy/ttl_serdes_generic.py index 56e17c7e1..2ba010226 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_generic.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_generic.py @@ -1,304 +1,273 @@ from migen.fhdl.std import * -from artiq.gateware.rtio import rtlink from migen.genlib.coding import PriorityEncoder +from artiq.gateware.rtio import rtlink -class Output(Module): - def __init__(self, serdes, fine_ts_width=0): - self.rtlink = rtlink.Interface(rtlink.OInterface(1, fine_ts_width= - fine_ts_width)) - serdes_width = 2**fine_ts_width - o = Signal() - previous_o = Signal() - override_en = Signal() - override_o = Signal() - io_o = Signal() - self.overrides = [override_en, override_o] +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] + elif direction == "falling": + pass + else: + raise ValueError + return l - io = serdes - self.submodules += io - - if fine_ts_width > 0: - timestamp = Signal(fine_ts_width) - - # dout - edges = Array([0xff ^ ((1 << i) - 1) for i in range(serdes_width)]) - edge_out = Signal(serdes_width) - edge_out_n = Signal(serdes_width) - rise_out = Signal() - fall_out = Signal() - self.comb += [ - timestamp.eq(self.rtlink.o.fine_ts), - edge_out.eq(edges[timestamp]), - edge_out_n.eq(~edge_out), - rise_out.eq(~previous_o & o), - fall_out.eq(previous_o & ~o), - If(override_en, - io.o.eq(override_o) - ).Else( - If(rise_out, - io.o.eq(edge_out), - ).Elif(fall_out, - io.o.eq(edge_out_n), - ).Else( - io.o.eq(Replicate(o, serdes_width)), - ) - ) - ] - else: - self.comb += [ - If(override_en, - io_o.eq(override_o) - ).Else( - io_o.eq(o) - ) - ] - - self.comb += [ - io.o.eq(io_o), - ] +class _SerdesDriver(Module): + def __init__(self, serdes_o, stb, data, fine_ts, override_en, override_o): + previous_data = Signal() + serdes_width = flen(serdes_o) + edges = Array(_mk_edges(serdes_width, "rising")) + edges_n = Array(_mk_edges(serdes_width, "falling")) self.sync.rio_phy += [ - If(self.rtlink.o.stb, - o.eq(self.rtlink.o.data), - ), - previous_o.eq(o), - ] - - -class Inout(Module): - def __init__(self, serdes, fine_ts_width=0): - self.rtlink = rtlink.Interface( - rtlink.OInterface(2, 2, fine_ts_width=fine_ts_width), - rtlink.IInterface(1, fine_ts_width=fine_ts_width)) - self.probes = [] - - serdes_width = 2**fine_ts_width - self.io = io = serdes - self.submodules += io - io_o = Signal(serdes_width) - io_i = Signal(serdes_width) - o = Signal() - rising = Signal() - falling = Signal() - i0 = Signal() - self.oe = oe = Signal() - override_en = Signal() - override_o = Signal() - override_oe = Signal() - self.sensitivity = Signal(2) - self.overrides = [override_en, override_o, override_oe] - previous_o = Signal() - - if fine_ts_width > 0: - - # Input - self.submodules.pe = pe = PriorityEncoder(serdes_width) - - self.sync.rio_phy += i0.eq(io_i[-1]) - - self.comb += [ - io_i.eq(io.i), - rising.eq(~i0 & io_i[-1]), - falling.eq(i0 & ~io_i[-1]), - pe.i.eq(io_i ^ Replicate(falling, serdes_width)), - self.rtlink.i.data.eq(io_i[-1]), - self.rtlink.i.fine_ts.eq(pe.o), - ] - - # Output - timestamp = Signal(fine_ts_width) - edges = Array([0xff ^ ((1 << i) - 1) for i in range(serdes_width)]) - edge_out = Signal(serdes_width) - edge_out_n = Signal(serdes_width) - rise_out = Signal() - fall_out = Signal() - - self.comb += [ - timestamp.eq(self.rtlink.o.fine_ts), - edge_out.eq(edges[timestamp]), - edge_out_n.eq(~edge_out), - rise_out.eq(~previous_o & o), - fall_out.eq(previous_o & ~o), - If(override_en, - io_o.eq(override_o), - ).Else( - If(rise_out, - io_o.eq(edge_out), - ).Elif(fall_out, - io_o.eq(edge_out_n), - ).Else( - io_o.eq(Replicate(o, serdes_width)), - ) - ) - ] - else: - self.comb += [ - io_i.eq(io.i), - rising.eq(~i0 & io_i), - falling.eq(i0 & ~io_i), - If(override_en, - io_o.eq(override_o) - ).Else( - io_o.eq(o), - ), - self.rtlink.i.data.eq(io_i), - ] - - self.comb += [ - io.oe.eq(oe), - io.o.eq(io_o), - self.rtlink.i.stb.eq( - (self.sensitivity[0] & rising) | - (self.sensitivity[1] & falling) - ), - ] - - self.sync.rio_phy += [ - If(self.rtlink.o.stb, - If(self.rtlink.o.address == 0, o.eq(self.rtlink.o.data[0])), - If(self.rtlink.o.address == 1, oe.eq(self.rtlink.o.data[0])), - ), + If(stb, previous_data.eq(data)), If(override_en, - oe.eq(override_oe) - ), - previous_o.eq(o), - ] - - self.sync.rio += [ - If(self.rtlink.o.stb & (self.rtlink.o.address == 2), - self.sensitivity.eq(self.rtlink.o.data) + serdes_o.eq(Replicate(override_o, serdes_width)) + ).Else( + If(stb & ~previous_data & data, + serdes_o.eq(edges[fine_ts]), + ).Elif(stb & previous_data & ~data, + serdes_o.eq(edges_n[fine_ts]), + ).Else( + serdes_o.eq(Replicate(previous_data, serdes_width)), + ) ) ] -class FakeSerdes(Module): + +class Output(Module): + def __init__(self, serdes): + self.rtlink = rtlink.Interface( + rtlink.OInterface(1, fine_ts_width=log2_int(flen(serdes.o)))) + self.probes = [serdes.o[-1]] + override_en = Signal() + override_o = Signal() + self.overrides = [override_en, override_o] + + # # # + + self.submodules += _SerdesDriver( + serdes.o, + self.rtlink.o.stb, self.rtlink.o.data, self.rtlink.o.fine_ts, + override_en, override_o) + + +class Inout(Module): + def __init__(self, serdes): + serdes_width = flen(serdes.o) + assert flen(serdes.i) == serdes_width + self.rtlink = rtlink.Interface( + rtlink.OInterface(2, 2, fine_ts_width=log2_int(serdes_width)), + rtlink.IInterface(1, fine_ts_width=log2_int(serdes_width))) + self.probes = [serdes.i[-1], serdes.oe] + override_en = Signal() + override_o = Signal() + override_oe = Signal() + self.overrides = [override_en, override_o, override_oe] + + # # # + + # Output + self.submodules += _SerdesDriver( + serdes_o=serdes.o, + stb=self.rtlink.o.stb & (self.rtlink.o.address == 0), + data=self.rtlink.o.data[0], + fine_ts=self.rtlink.o.fine_ts, + override_en=override_en, override_o=override_o) + + oe_k = Signal() + 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) + ).Else( + serdes.oe.eq(oe_k) + ) + ] + + # Input + sensitivity = Signal(2) + self.sync.rio += If(self.rtlink.o.stb & (self.rtlink.o.address == 2), + sensitivity.eq(self.rtlink.o.data)) + + i = serdes.i[-1] + i_d = Signal() + self.sync.rio_phy += [ + i_d.eq(i), + self.rtlink.i.stb.eq( + (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) + + +class _FakeSerdes(Module): def __init__(self): - self.o = o = Signal(8) - self.oe = oe = Signal(8) + self.o = Signal(8) + self.i = Signal(8) + self.oe = Signal() -class FakeIOSerdes(Module): +class _OutputTB(Module): def __init__(self): - self.o = o = Signal(8) - self.oe = oe = Signal(8) - self.i = i = Signal(8) - - -class OutputTB(Module): - def __init__(self): - serdes = FakeSerdes() - self.o = RenameClockDomains(Output(serdes, fine_ts_width=3), - {"rio_phy": "sys"}) - self.submodules += self.o + 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.o.rtlink.o.data = 1 - selfp.o.rtlink.o.fine_ts = 1 - selfp.o.rtlink.o.stb = 1 + selfp.dut.rtlink.o.stb = 0 yield - selfp.o.rtlink.o.stb = 0 + selfp.dut.rtlink.o.data = 0 + selfp.dut.rtlink.o.fine_ts = 2 + selfp.dut.rtlink.o.stb = 1 yield - selfp.o.rtlink.o.data = 0 - selfp.o.rtlink.o.fine_ts = 2 - selfp.o.rtlink.o.stb = 1 yield - selfp.o.rtlink.o.data = 1 - selfp.o.rtlink.o.fine_ts = 7 - yield - - while True: + 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): +class _InoutTB(Module): def __init__(self): - ioserdes = FakeIOSerdes() - self.io = RenameClockDomains(Inout(ioserdes, fine_ts_width=3), - {"rio_phy": "sys"}) - self.submodules += self.io + 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.io.rtlink.i.stb: + if stb != selfp.dut.rtlink.i.stb: print("KO rtlink.i.stb should be {} but is {}" - .format(stb, selfp.io.rtlink.i.stb)) - elif fine_ts is not None and fine_ts != selfp.io.rtlink.i.fine_ts: + .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.io.rtlink.i.fine_ts)) + .format(fine_ts, selfp.dut.rtlink.i.fine_ts)) else: print("OK") def check_output(self, selfp, data): - if selfp.io.io.o != data: - print("KO io.o should be {} but is {}".format(data, selfp.io.io.o)) + 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.io.io.oe != oe: - print("KO io.oe should be {} but is {}".format(oe, selfp.io.io.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.io.sensitivity = 0b11 # rising + falling + 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.io.io.i = 0b11111110 # rising edge at fine_ts = 1 + + 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.io.io.i = 0b01111111 # falling edge at fine_ts = 7 + + 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.io.io.i = 0b11000000 # rising edge at fine_ts = 6 + + 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.io.sensitivity = 0b01 # rising - selfp.io.io.i = 0b00001111 # falling edge at fine_ts = 4 + + 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.io.io.i = 0b11110000 # rising edge at fine_ts = 4 + + selfp.serdes.i = 0b11110000 # rising edge at fine_ts = 4 yield self.check_input(selfp, stb=1, fine_ts=4) - selfp.io.rtlink.o.address = 1 - selfp.io.rtlink.o.data = 1 - selfp.io.rtlink.o.stb = 1 # set Output Enable to 1 + + 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 - selfp.io.rtlink.o.address = 0 - selfp.io.rtlink.o.data = 1 - selfp.io.rtlink.o.fine_ts = 3 # rising edge at fine_ts = 3 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 - selfp.io.rtlink.o.data = 0 - selfp.io.rtlink.o.fine_ts = 0 # falling edge at fine_ts = 0 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.io.rtlink.o.data = 1 - selfp.io.rtlink.o.fine_ts = 7 - self.check_output(selfp, data=0) + 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) - while True: - yield if __name__ == "__main__": import sys from migen.sim.generic import Simulator, TopLevel - from migen.sim import icarus - if len(sys.argv) <= 1: - print("You should run this script with either InoutTB() or OutputTB() " - "arg") + if len(sys.argv) != 2: + print("Incorrect command line") sys.exit(1) - with Simulator(eval(sys.argv[1]), TopLevel("top.vcd", clk_period=int(1/0.125)), - icarus.Runner(keep_files=False,)) as s: - s.run(200) + cls = { + "output": _OutputTB, + "inout": _InoutTB + }[sys.argv[1]] + + with Simulator(cls(), TopLevel("top.vcd", clk_period=int(1/0.125))) as s: + s.run() From f68d5cbd736ee161d47114e33902aad8e9fe9af0 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Jul 2015 01:52:47 +0800 Subject: [PATCH 03/38] rtio: forward rtio domain reset to rio and rio_phy domains --- artiq/gateware/rtio/core.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index b4fedcf88..38446604e 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -329,11 +329,15 @@ class RTIO(Module): self.cd_rsys.rst.eq(self.kcsrs.reset.storage) ] self.comb += self.cd_rio.clk.eq(ClockSignal("rtio")) - self.specials += AsyncResetSynchronizer(self.cd_rio, - self.kcsrs.reset.storage) + self.specials += AsyncResetSynchronizer( + self.cd_rio, + self.kcsrs.reset.storage | ResetSignal("rtio", + allow_resetless=True)) self.comb += self.cd_rio_phy.clk.eq(ClockSignal("rtio")) - self.specials += AsyncResetSynchronizer(self.cd_rio_phy, - self.kcsrs.reset_phy.storage) + self.specials += AsyncResetSynchronizer( + self.cd_rio_phy, + self.kcsrs.reset_phy.storage | ResetSignal("rtio", + allow_resetless=True)) # Managers self.submodules.counter = _RTIOCounter(full_ts_width - fine_ts_width) From d3f05e414aff3213e0be87ed1ddd7debcf2b4036 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Jul 2015 10:50:25 +0800 Subject: [PATCH 04/38] runtime: account for RTIO_FINE_TS_WIDTH in time buffers --- soc/runtime/bridge.c | 8 +++++--- soc/runtime/ksupport.c | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/soc/runtime/bridge.c b/soc/runtime/bridge.c index eb16587de..78083a16f 100644 --- a/soc/runtime/bridge.c +++ b/soc/runtime/bridge.c @@ -5,12 +5,14 @@ #include "dds.h" #include "bridge.h" +#define TIME_BUFFER (8000 << RTIO_FINE_TS_WIDTH) + static void dds_write(int addr, int data) { rtio_chan_sel_write(RTIO_DDS_CHANNEL); rtio_o_address_write(addr); rtio_o_data_write(data); - rtio_o_timestamp_write(rtio_get_counter() + 8000); + rtio_o_timestamp_write(rtio_get_counter() + TIME_BUFFER); rtio_o_we_write(1); } @@ -46,7 +48,7 @@ void bridge_main(void) struct msg_brg_ttl_out *msg; msg = (struct msg_brg_ttl_out *)umsg; - ttl_set_oe(rtio_get_counter() + 8000, msg->channel, msg->value); + ttl_set_oe(rtio_get_counter() + TIME_BUFFER, msg->channel, msg->value); mailbox_acknowledge(); break; } @@ -54,7 +56,7 @@ void bridge_main(void) struct msg_brg_ttl_out *msg; msg = (struct msg_brg_ttl_out *)umsg; - ttl_set_o(rtio_get_counter() + 8000, msg->channel, msg->value); + ttl_set_o(rtio_get_counter() + TIME_BUFFER, msg->channel, msg->value); mailbox_acknowledge(); break; } diff --git a/soc/runtime/ksupport.c b/soc/runtime/ksupport.c index 032fe88ec..eb7a784b7 100644 --- a/soc/runtime/ksupport.c +++ b/soc/runtime/ksupport.c @@ -79,7 +79,7 @@ long long int now_init(void) if(now < 0) { rtio_init(); - now = rtio_get_counter() + 125000; + now = rtio_get_counter() + (125000 << RTIO_FINE_TS_WIDTH); } return now; From 5b50f5fe05b63bc3bb2ea8a33d015c1ce628a462 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Jul 2015 10:50:50 +0800 Subject: [PATCH 05/38] rtio/ttl_serdes_7series: use recommended OSERDES T configuration --- artiq/gateware/rtio/phy/ttl_serdes_7series.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_7series.py b/artiq/gateware/rtio/phy/ttl_serdes_7series.py index ccb32ab5e..b2322b4f5 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_7series.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_7series.py @@ -12,9 +12,9 @@ class _OSERDESE2_8X(Module): # # # o = self.o - self.specials += Instance("OSERDESE2", p_DATA_RATE_OQ="DDR", - p_DATA_RATE_TQ="DDR", p_DATA_WIDTH=8, - p_TRISTATE_WIDTH=1, + 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_TQ=self.t_out, i_CLK=ClockSignal("rtiox4"), i_CLKDIV=ClockSignal("rio_phy"), From fe6a5c42dfac0d847540d27b6d9fa619263f1fe2 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Jul 2015 10:57:15 +0800 Subject: [PATCH 06/38] rtio: remove unused clk_freq argument --- artiq/gateware/rtio/core.py | 3 +-- soc/targets/artiq_kc705.py | 3 +-- soc/targets/artiq_pipistrello.py | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 38446604e..bb5b51efe 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -300,8 +300,7 @@ class _KernelCSRs(AutoCSR): class RTIO(Module): - def __init__(self, channels, clk_freq, full_ts_width=63, - guard_io_cycles=20): + def __init__(self, channels, full_ts_width=63, guard_io_cycles=20): data_width = max(rtlink.get_data_width(c.interface) for c in channels) address_width = max(rtlink.get_address_width(c.interface) diff --git a/soc/targets/artiq_kc705.py b/soc/targets/artiq_kc705.py index cfc9774f9..666cb8f05 100644 --- a/soc/targets/artiq_kc705.py +++ b/soc/targets/artiq_kc705.py @@ -58,8 +58,7 @@ class _NIST_QCx(MiniSoC, AMPSoC): def add_rtio(self, rtio_channels): self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.pll_sys) - self.submodules.rtio = rtio.RTIO(rtio_channels, - clk_freq=125000000) + self.submodules.rtio = rtio.RTIO(rtio_channels) self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width) self.add_constant("DDS_RTIO_CLK_RATIO", 8 >> self.rtio.fine_ts_width) self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index fd09ed373..e393edc36 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -128,8 +128,7 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd # RTIO core self.submodules.rtio_crg = _RTIOCRG(platform, self.clk_freq) - self.submodules.rtio = rtio.RTIO(rtio_channels, - clk_freq=125000000) + self.submodules.rtio = rtio.RTIO(rtio_channels) self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width) self.add_constant("DDS_RTIO_CLK_RATIO", 8 >> self.rtio.fine_ts_width) self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) From 3573fd02a6194c73831b5b80cb2ef15499b90d78 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Jul 2015 10:58:19 +0800 Subject: [PATCH 07/38] targets/kc705: add TIG constraints for ISE --- soc/targets/artiq_kc705.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/soc/targets/artiq_kc705.py b/soc/targets/artiq_kc705.py index 666cb8f05..41c050fb8 100644 --- a/soc/targets/artiq_kc705.py +++ b/soc/targets/artiq_kc705.py @@ -3,6 +3,7 @@ from migen.bank.description import * from migen.bank import wbgen from mibuild.generic_platform import * from mibuild.xilinx.vivado import XilinxVivadoToolchain +from mibuild.xilinx.ise import XilinxISEToolchain from misoclib.com import gpio from misoclib.soc import mem_decoder @@ -70,6 +71,13 @@ create_clock -name rio_clk -period 8.0 [get_nets {rio_clk}] set_false_path -from [get_clocks rsys_clk] -to [get_clocks rio_clk] set_false_path -from [get_clocks rio_clk] -to [get_clocks rsys_clk] """, rsys_clk=self.rtio.cd_rsys.clk, rio_clk=self.rtio.cd_rio.clk) + if isinstance(self.platform.toolchain, XilinxISEToolchain): + self.platform.add_platform_command(""" +NET "sys_clk" TNM_NET = "GRPrsys_clk"; +NET "{rio_clk}" TNM_NET = "GRPrio_clk"; +TIMESPEC "TSfix_cdc1" = FROM "GRPrsys_clk" TO "GRPrio_clk" TIG; +TIMESPEC "TSfix_cdc2" = FROM "GRPrio_clk" TO "GRPrsys_clk" TIG; +""", rio_clk=self.rtio_crg.cd_rtio.clk) rtio_csrs = self.rtio.get_csrs() self.submodules.rtiowb = wbgen.Bank(rtio_csrs) From 959b7a7b46d2362a6ebc2e8eaff54fcacceccb42 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Jul 2015 11:46:56 +0800 Subject: [PATCH 08/38] rtio: resetless -> reset_less --- 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 bb5b51efe..7e7344cfa 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -331,12 +331,12 @@ class RTIO(Module): self.specials += AsyncResetSynchronizer( self.cd_rio, self.kcsrs.reset.storage | ResetSignal("rtio", - allow_resetless=True)) + allow_reset_less=True)) self.comb += self.cd_rio_phy.clk.eq(ClockSignal("rtio")) self.specials += AsyncResetSynchronizer( self.cd_rio_phy, self.kcsrs.reset_phy.storage | ResetSignal("rtio", - allow_resetless=True)) + allow_reset_less=True)) # Managers self.submodules.counter = _RTIOCounter(full_ts_width - fine_ts_width) From b1d58bd4c89447a3552ec4f54f75397434187320 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Jul 2015 12:22:35 +0800 Subject: [PATCH 09/38] rtio: fix replace/sequence_error when fine_ts_width > 0 --- artiq/gateware/rtio/core.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py index 7e7344cfa..08c46188f 100644 --- a/artiq/gateware/rtio/core.py +++ b/artiq/gateware/rtio/core.py @@ -118,8 +118,10 @@ class _OutputManager(Module): sequence_error = Signal() nop = Signal() self.sync.rsys += [ - replace.eq(self.ev.timestamp == buf.timestamp[fine_ts_width:]), - sequence_error.eq(self.ev.timestamp < buf.timestamp[fine_ts_width:]) + replace.eq(self.ev.timestamp[fine_ts_width:] \ + == buf.timestamp[fine_ts_width:]), + sequence_error.eq(self.ev.timestamp[fine_ts_width:] \ + < buf.timestamp[fine_ts_width:]) ] if interface.suppress_nop: # disable NOP at reset: do not suppress a first write with all 0s From d7138b25f2410c5fc0c12d0c1d1a7774f9597033 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Jul 2015 12:22:56 +0800 Subject: [PATCH 10/38] examples/ddb: add device aliases for unittests --- examples/master/ddb.pyon | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/master/ddb.pyon b/examples/master/ddb.pyon index e853675c5..f7424636d 100644 --- a/examples/master/ddb.pyon +++ b/examples/master/ddb.pyon @@ -133,6 +133,9 @@ "command": "lda_controller -p {port} --bind {bind}" }, + "ttl_inout": "pmt0", + "ttl_out": "ttl0", + "pmt": "pmt0", "bd_dds": "dds0", "bd_sw": "ttl0", From fe57308e71412c73f24d4c92d775f494c6e5d13d Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Jul 2015 20:11:31 +0800 Subject: [PATCH 11/38] runtime: support for RTIO PLL --- soc/runtime/main.c | 4 ++++ soc/runtime/session.c | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/soc/runtime/main.c b/soc/runtime/main.c index 306f26b20..3a639b145 100644 --- a/soc/runtime/main.c +++ b/soc/runtime/main.c @@ -253,6 +253,10 @@ int main(void) puts("Press 't' to enter test mode..."); blink_led(); +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR + rtio_crg_pll_reset_write(0); +#endif + if(check_test_mode()) { puts("Entering test mode."); test_main(); diff --git a/soc/runtime/session.c b/soc/runtime/session.c index 9b3591e30..d0f896583 100644 --- a/soc/runtime/session.c +++ b/soc/runtime/session.c @@ -128,6 +128,22 @@ static int check_flash_storage_key_len(char *key, unsigned int key_len) return 1; } +static void switch_clock(int clk) +{ + int current_clk; + + current_clk = rtio_crg_clock_sel_read(); + if(clk == current_clk) + return; +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR + rtio_crg_pll_reset_write(1); +#endif + rtio_crg_clock_sel_write(clk); +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR + rtio_crg_pll_reset_write(0); +#endif +} + static int process_input(void) { switch(buffer_in[8]) { @@ -154,7 +170,7 @@ static int process_input(void) submit_output(9); break; } - rtio_crg_clock_sel_write(buffer_in[9]); + switch_clock(buffer_in[9]); buffer_out[8] = REMOTEMSG_TYPE_CLOCK_SWITCH_COMPLETED; submit_output(9); break; From 2a95e866aaad73a3c27420e6914c9c878a5d24af Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Jul 2015 20:12:17 +0800 Subject: [PATCH 12/38] kc705: use 8X SERDES RTIO PHY --- examples/master/ddb.pyon | 2 +- soc/targets/artiq_kc705.py | 53 +++++++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/examples/master/ddb.pyon b/examples/master/ddb.pyon index f7424636d..a1ce5680a 100644 --- a/examples/master/ddb.pyon +++ b/examples/master/ddb.pyon @@ -9,7 +9,7 @@ "type": "local", "module": "artiq.coredevice.core", "class": "Core", - "arguments": {} + "arguments": {"ref_period": 1e-9} }, "pmt0": { diff --git a/soc/targets/artiq_kc705.py b/soc/targets/artiq_kc705.py index 41c050fb8..66d75728b 100644 --- a/soc/targets/artiq_kc705.py +++ b/soc/targets/artiq_kc705.py @@ -1,4 +1,6 @@ from migen.fhdl.std import * +from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.cdc import MultiReg from migen.bank.description import * from migen.bank import wbgen from mibuild.generic_platform import * @@ -12,13 +14,16 @@ from targets.kc705 import MiniSoC from artiq.gateware.soc import AMPSoC from artiq.gateware import rtio, nist_qc1, nist_qc2 -from artiq.gateware.rtio.phy import ttl_simple, dds +from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, dds class _RTIOCRG(Module, AutoCSR): def __init__(self, platform, rtio_internal_clk): self._clock_sel = CSRStorage() - self.clock_domains.cd_rtio = ClockDomain(reset_less=True) + 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() user_sma_clock = platform.request("user_sma_clock") @@ -26,11 +31,34 @@ class _RTIOCRG(Module, AutoCSR): self.specials += Instance("IBUFDS", i_I=user_sma_clock.p, i_IB=user_sma_clock.n, o_O=rtio_external_clk) - self.specials += Instance("BUFGMUX", - i_I0=rtio_internal_clk, - i_I1=rtio_external_clk, - i_S=self._clock_sel.storage, - o_O=self.cd_rtio.clk) + + pll_locked = Signal() + rtio_clk = Signal() + rtiox4_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, + + p_CLKFBOUT_MULT=8, p_DIVCLK_DIVIDE=1, + i_CLKFBIN=self.cd_rtio.clk, + i_RST=self._pll_reset.storage, + + p_CLKOUT0_DIVIDE=8, p_CLKOUT0_PHASE=0.0, + o_CLKFBOUT=rtio_clk, + p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, + o_CLKOUT1=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 _NIST_QCx(MiniSoC, AMPSoC): @@ -58,9 +86,10 @@ class _NIST_QCx(MiniSoC, AMPSoC): platform.request("user_led", 1))) def add_rtio(self, rtio_channels): - self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.pll_sys) + self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk) self.submodules.rtio = rtio.RTIO(rtio_channels) self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width) + assert self.rtio.fine_ts_width <= 3 self.add_constant("DDS_RTIO_CLK_RATIO", 8 >> self.rtio.fine_ts_width) self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) @@ -99,11 +128,11 @@ class NIST_QC1(_NIST_QCx): rtio_channels = [] for i in range(2): - phy = ttl_simple.Inout(platform.request("pmt", i)) + phy = ttl_serdes_7series.Inout_8X(platform.request("pmt", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) for i in range(15): - phy = ttl_simple.Output(platform.request("ttl", i)) + phy = ttl_serdes_7series.Output_8X(platform.request("ttl", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) @@ -138,11 +167,11 @@ class NIST_QC2(_NIST_QCx): # TTL14 is for the clock generator continue if i % 4 == 3: - phy = ttl_simple.Inout(platform.request("ttl", i)) + phy = ttl_serdes_7series.Inout_8X(platform.request("ttl", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512)) else: - phy = ttl_simple.Output(platform.request("ttl", i)) + phy = ttl_serdes_7series.Output_8X(platform.request("ttl", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy)) From 256e99f0d78e43fa485dea336375b81180770030 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Jul 2015 20:31:37 +0800 Subject: [PATCH 13/38] kc705: crg cleanup --- soc/targets/artiq_kc705.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/soc/targets/artiq_kc705.py b/soc/targets/artiq_kc705.py index 66d75728b..4677ada33 100644 --- a/soc/targets/artiq_kc705.py +++ b/soc/targets/artiq_kc705.py @@ -49,10 +49,10 @@ class _RTIOCRG(Module, AutoCSR): i_CLKFBIN=self.cd_rtio.clk, i_RST=self._pll_reset.storage, - p_CLKOUT0_DIVIDE=8, p_CLKOUT0_PHASE=0.0, o_CLKFBOUT=rtio_clk, - p_CLKOUT1_DIVIDE=2, p_CLKOUT1_PHASE=0.0, - o_CLKOUT1=rtiox4_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), From 299bc1cb7e6569744ef51f3efa01bc07d204254a Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 27 Jul 2015 20:46:44 +0800 Subject: [PATCH 14/38] kc705: output divided-by-2 RTIO clock --- soc/targets/artiq_kc705.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/soc/targets/artiq_kc705.py b/soc/targets/artiq_kc705.py index 4677ada33..ffa61f76c 100644 --- a/soc/targets/artiq_kc705.py +++ b/soc/targets/artiq_kc705.py @@ -60,6 +60,10 @@ class _RTIOCRG(Module, AutoCSR): MultiReg(pll_locked, self._pll_locked.status) ] + # 62.5MHz when using internal RTIO clock + ext_clkout = platform.request("user_sma_gpio_p") + self.sync.rtio += ext_clkout.eq(~ext_clkout) + class _NIST_QCx(MiniSoC, AMPSoC): csr_map = { From 09d837e4baf2901152df6b85bd1b5b956ace0f54 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 28 Jul 2015 00:05:24 +0800 Subject: [PATCH 15/38] runtime: monitor RTIO clock status --- soc/runtime/clock.c | 10 ++++++++++ soc/runtime/clock.h | 1 + soc/runtime/session.c | 39 ++++++++++++++++++++++++++++++--------- 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/soc/runtime/clock.c b/soc/runtime/clock.c index 6b3946790..171fb6f30 100644 --- a/soc/runtime/clock.c +++ b/soc/runtime/clock.c @@ -26,6 +26,16 @@ long long int clock_get_ms(void) return clock_ms; } +void busywait_us(long long int us) +{ + long long int threshold; + + timer0_update_value_write(1); + threshold = timer0_value_read() - us*(long long int)identifier_frequency_read()/1000000LL; + while(timer0_value_read() > threshold) + timer0_update_value_write(1); +} + struct watchdog { int active; long long int threshold; diff --git a/soc/runtime/clock.h b/soc/runtime/clock.h index 70de5e5b7..4f4895443 100644 --- a/soc/runtime/clock.h +++ b/soc/runtime/clock.h @@ -3,6 +3,7 @@ void clock_init(void); long long int clock_get_ms(void); +void busywait_us(long long us); #define MAX_WATCHDOGS 16 diff --git a/soc/runtime/session.c b/soc/runtime/session.c index d0f896583..d3227a4d6 100644 --- a/soc/runtime/session.c +++ b/soc/runtime/session.c @@ -128,20 +128,30 @@ static int check_flash_storage_key_len(char *key, unsigned int key_len) return 1; } -static void switch_clock(int clk) +static int switch_clock(int clk) { int current_clk; current_clk = rtio_crg_clock_sel_read(); - if(clk == current_clk) - return; + if(clk == current_clk) { +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR + busywait_us(150); + if(!rtio_crg_pll_locked_read()) + return 0; +#endif + return 1; + } #ifdef CSR_RTIO_CRG_PLL_RESET_ADDR rtio_crg_pll_reset_write(1); #endif rtio_crg_clock_sel_write(clk); #ifdef CSR_RTIO_CRG_PLL_RESET_ADDR rtio_crg_pll_reset_write(0); + busywait_us(150); + if(!rtio_crg_pll_locked_read()) + return 0; #endif + return 1; } static int process_input(void) @@ -170,8 +180,10 @@ static int process_input(void) submit_output(9); break; } - switch_clock(buffer_in[9]); - buffer_out[8] = REMOTEMSG_TYPE_CLOCK_SWITCH_COMPLETED; + if(switch_clock(buffer_in[9])) + buffer_out[8] = REMOTEMSG_TYPE_CLOCK_SWITCH_COMPLETED; + else + buffer_out[8] = REMOTEMSG_TYPE_CLOCK_SWITCH_FAILED; submit_output(9); break; case REMOTEMSG_TYPE_LOAD_OBJECT: @@ -543,10 +555,19 @@ void session_poll(void **data, int *len) { int l; - if((user_kernel_state == USER_KERNEL_RUNNING) && watchdog_expired()) { - log("Watchdog expired"); - *len = -1; - return; + if(user_kernel_state == USER_KERNEL_RUNNING) { + if(watchdog_expired()) { + log("Watchdog expired"); + *len = -1; + return; + } +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR + if(!rtio_crg_pll_locked_read()) { + log("RTIO clock failure"); + *len = -1; + return; + } +#endif } l = get_out_packet_len(); From 7feaca7c7caa0a6376e55ce3b3e328fac9eece40 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 28 Jul 2015 00:19:07 +0800 Subject: [PATCH 16/38] runtime: allow selecting external clock at startup --- soc/runtime/Makefile | 2 +- soc/runtime/main.c | 6 ++-- soc/runtime/rtiocrg.c | 64 +++++++++++++++++++++++++++++++++++++++++++ soc/runtime/rtiocrg.h | 8 ++++++ soc/runtime/session.c | 33 ++-------------------- 5 files changed, 78 insertions(+), 35 deletions(-) create mode 100644 soc/runtime/rtiocrg.c create mode 100644 soc/runtime/rtiocrg.h diff --git a/soc/runtime/Makefile b/soc/runtime/Makefile index 241448f37..673235928 100644 --- a/soc/runtime/Makefile +++ b/soc/runtime/Makefile @@ -1,6 +1,6 @@ include $(MSCDIR)/software/common.mak -OBJECTS := isr.o flash_storage.o clock.o elf_loader.o services.o session.o log.o test_mode.o kloader.o bridge_ctl.o mailbox.o ksupport_data.o kserver.o moninj.o main.o +OBJECTS := isr.o flash_storage.o clock.o rtiocrg.o elf_loader.o services.o session.o log.o test_mode.o kloader.o bridge_ctl.o mailbox.o ksupport_data.o kserver.o moninj.o main.o OBJECTS_KSUPPORT := ksupport.o exception_jmp.o exceptions.o mailbox.o bridge.o rtio.o ttl.o dds.o CFLAGS += -Ilwip/src/include -Iliblwip diff --git a/soc/runtime/main.c b/soc/runtime/main.c index 3a639b145..74df38aea 100644 --- a/soc/runtime/main.c +++ b/soc/runtime/main.c @@ -24,6 +24,7 @@ #include "kloader.h" #include "flash_storage.h" #include "clock.h" +#include "rtiocrg.h" #include "test_mode.h" #include "kserver.h" #include "session.h" @@ -250,13 +251,10 @@ int main(void) puts("ARTIQ runtime built "__DATE__" "__TIME__"\n"); clock_init(); + rtiocrg_init(); puts("Press 't' to enter test mode..."); blink_led(); -#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR - rtio_crg_pll_reset_write(0); -#endif - if(check_test_mode()) { puts("Entering test mode."); test_main(); diff --git a/soc/runtime/rtiocrg.c b/soc/runtime/rtiocrg.c new file mode 100644 index 000000000..08cabd5b2 --- /dev/null +++ b/soc/runtime/rtiocrg.c @@ -0,0 +1,64 @@ +#include +#include + +#include "clock.h" +#include "flash_storage.h" +#include "rtiocrg.h" + +void rtiocrg_init(void) +{ + char b; + int clk; + +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR + rtio_crg_pll_reset_write(0); +#endif + b = 'i'; + clk = 0; + fs_read("startup_clock", &b, 1, NULL); + if(b == 'i') + printf("Startup RTIO clock: internal\n"); + else if(b == 'e') { + printf("Startup RTIO clock: external\n"); + clk = 1; + } else + printf("WARNING: unknown startup_clock entry in flash storage\n"); + + if(!rtiocrg_switch_clock(clk)) + printf("WARNING: startup RTIO clock failed\n"); +} + +int rtiocrg_check(void) +{ +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR + return rtio_crg_pll_locked_read(); +#else + return 1; +#endif +} + +int rtiocrg_switch_clock(int clk) +{ + int current_clk; + + current_clk = rtio_crg_clock_sel_read(); + if(clk == current_clk) { +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR + busywait_us(150); + if(!rtio_crg_pll_locked_read()) + return 0; +#endif + return 1; + } +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR + rtio_crg_pll_reset_write(1); +#endif + rtio_crg_clock_sel_write(clk); +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR + rtio_crg_pll_reset_write(0); + busywait_us(150); + if(!rtio_crg_pll_locked_read()) + return 0; +#endif + return 1; +} diff --git a/soc/runtime/rtiocrg.h b/soc/runtime/rtiocrg.h new file mode 100644 index 000000000..df498f617 --- /dev/null +++ b/soc/runtime/rtiocrg.h @@ -0,0 +1,8 @@ +#ifndef __RTIOCRG_H +#define __RTIOCRG_H + +void rtiocrg_init(void); +int rtiocrg_check(void); +int rtiocrg_switch_clock(int clk); + +#endif /* __RTIOCRG_H */ diff --git a/soc/runtime/session.c b/soc/runtime/session.c index d3227a4d6..c0908639c 100644 --- a/soc/runtime/session.c +++ b/soc/runtime/session.c @@ -12,6 +12,7 @@ #include "kloader.h" #include "exceptions.h" #include "flash_storage.h" +#include "rtiocrg.h" #include "session.h" #define BUFFER_IN_SIZE (1024*1024) @@ -128,32 +129,6 @@ static int check_flash_storage_key_len(char *key, unsigned int key_len) return 1; } -static int switch_clock(int clk) -{ - int current_clk; - - current_clk = rtio_crg_clock_sel_read(); - if(clk == current_clk) { -#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR - busywait_us(150); - if(!rtio_crg_pll_locked_read()) - return 0; -#endif - return 1; - } -#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR - rtio_crg_pll_reset_write(1); -#endif - rtio_crg_clock_sel_write(clk); -#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR - rtio_crg_pll_reset_write(0); - busywait_us(150); - if(!rtio_crg_pll_locked_read()) - return 0; -#endif - return 1; -} - static int process_input(void) { switch(buffer_in[8]) { @@ -180,7 +155,7 @@ static int process_input(void) submit_output(9); break; } - if(switch_clock(buffer_in[9])) + if(rtiocrg_switch_clock(buffer_in[9])) buffer_out[8] = REMOTEMSG_TYPE_CLOCK_SWITCH_COMPLETED; else buffer_out[8] = REMOTEMSG_TYPE_CLOCK_SWITCH_FAILED; @@ -561,13 +536,11 @@ void session_poll(void **data, int *len) *len = -1; return; } -#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR - if(!rtio_crg_pll_locked_read()) { + if(!rtiocrg_check()) { log("RTIO clock failure"); *len = -1; return; } -#endif } l = get_out_packet_len(); From 228f7c3d61d2c8ed310a1dcadb6ecd2ecb7c64f7 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 28 Jul 2015 00:38:20 +0800 Subject: [PATCH 17/38] manual: update xc3sprog download --- 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 ff74515ba..77ff98394 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -147,7 +147,7 @@ These steps are required to generate bitstream (``.bit``) files, build the MiSoC :: $ cd ~/artiq-dev - $ svn co https://xc3sprog.svn.sourceforge.net/svnroot/xc3sprog/trunk xc3sprog + $ svn co http://svn.code.sf.net/p/xc3sprog/code/trunk xc3sprog $ cd xc3sprog $ cmake . && make $ sudo make install From 0cd74533cac5e98cdd17c4bdab2cb825fed55cff Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 28 Jul 2015 00:38:38 +0800 Subject: [PATCH 18/38] runtime: more explicit message about startup clock failure --- soc/runtime/rtiocrg.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/soc/runtime/rtiocrg.c b/soc/runtime/rtiocrg.c index 08cabd5b2..255f2a308 100644 --- a/soc/runtime/rtiocrg.c +++ b/soc/runtime/rtiocrg.c @@ -24,8 +24,11 @@ void rtiocrg_init(void) } else printf("WARNING: unknown startup_clock entry in flash storage\n"); - if(!rtiocrg_switch_clock(clk)) + if(!rtiocrg_switch_clock(clk)) { printf("WARNING: startup RTIO clock failed\n"); + printf("WARNING: this may cause the system initialization to fail\n"); + printf("WARNING: fix clocking and reset the device\n"); + } } int rtiocrg_check(void) From eec4a2d2d2b471306688295e38c509f2e7d4304d Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 27 Jul 2015 21:10:04 +0300 Subject: [PATCH 19/38] Update buildsystem to track -fPIC and ranlib removal in MiSoC. --- soc/runtime/ksupport.ld | 4 ++-- soc/runtime/liblwip/Makefile | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/soc/runtime/ksupport.ld b/soc/runtime/ksupport.ld index 4126b4a7b..0aec5ca64 100644 --- a/soc/runtime/ksupport.ld +++ b/soc/runtime/ksupport.ld @@ -4,10 +4,10 @@ ENTRY(_start) INCLUDE generated/regions.ld /* First 4M of main memory are reserved for runtime code/data - * then comes kernel memory. First 16K of kernel memory are for support code. + * then comes kernel memory. First 32K of kernel memory are for support code. */ MEMORY { - ksupport : ORIGIN = 0x40400000, LENGTH = 0x4000 + ksupport : ORIGIN = 0x40400000, LENGTH = 0x8000 } /* On AMP systems, kernel stack is at the end of main RAM, diff --git a/soc/runtime/liblwip/Makefile b/soc/runtime/liblwip/Makefile index 5dc22bcf3..0aaabd954 100644 --- a/soc/runtime/liblwip/Makefile +++ b/soc/runtime/liblwip/Makefile @@ -53,4 +53,3 @@ clean: liblwip.a: $(LWIPOBJS) $(AR) clr liblwip.a $(LWIPOBJS) - $(RANLIB) liblwip.a From ae3a52c49c206df85bfc66f4ca2cb839a97c7a25 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 28 Jul 2015 02:12:14 +0800 Subject: [PATCH 20/38] runtime: fix KERNELCPU_PAYLOAD_ADDRESS --- soc/runtime/kloader.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soc/runtime/kloader.h b/soc/runtime/kloader.h index 098a740b7..ceefbc89d 100644 --- a/soc/runtime/kloader.h +++ b/soc/runtime/kloader.h @@ -2,7 +2,7 @@ #define __KLOADER_H #define KERNELCPU_EXEC_ADDRESS 0x40400000 -#define KERNELCPU_PAYLOAD_ADDRESS 0x40404000 +#define KERNELCPU_PAYLOAD_ADDRESS 0x40408000 extern long long int now; From 9ac5bc52d478db5049f881a26a3805411df21411 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 27 Jul 2015 21:01:15 -0600 Subject: [PATCH 21/38] rtio: add spartan6 serdes, 4x and 8x --- .../gateware/rtio/phy/ttl_serdes_spartan6.py | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 artiq/gateware/rtio/phy/ttl_serdes_spartan6.py diff --git a/artiq/gateware/rtio/phy/ttl_serdes_spartan6.py b/artiq/gateware/rtio/phy/ttl_serdes_spartan6.py new file mode 100644 index 000000000..89fddb2d0 --- /dev/null +++ b/artiq/gateware/rtio/phy/ttl_serdes_spartan6.py @@ -0,0 +1,155 @@ +from migen.fhdl.std import * + +from artiq.gateware.rtio.phy import ttl_serdes_generic + + +class _OSERDES2_8X(Module): + def __init__(self, pad, stb): + self.o = Signal(8) + self.t_in = Signal() + self.t_out = Signal() + + # # # + + cascade = Signal(4) + o = self.o + common = dict(p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR", + p_DATA_WIDTH=8, p_OUTPUT_MODE="SINGLE_ENDED", i_TRAIN=0, + i_CLK0=ClockSignal("rtiox8"), i_CLK1=0, + i_CLKDIV=ClockSignal("rio_phy"), + i_IOCE=stb, i_OCE=1, i_TCE=1, i_RST=0, + i_T4=self.t_in, i_T3=self.t_in, + i_T2=self.t_in, i_T1=self.t_in) + + self.specials += [ + Instance("OSERDES2", p_SERDES_MODE="MASTER", + i_D4=o[7], i_D3=o[6], i_D2=o[5], i_D1=o[4], + i_SHIFTIN1=1, i_SHIFTIN2=1, + i_SHIFTIN3=cascade[2], i_SHIFTIN4=cascade[3], + o_SHIFTOUT1=cascade[0], o_SHIFTOUT2=cascade[1], + o_OQ=pad, o_TQ=self.t_out, **common), + Instance("OSERDES2", p_SERDES_MODE="SLAVE", + i_D4=o[3], i_D3=o[2], i_D2=o[1], i_D1=o[0], + i_SHIFTIN1=cascade[0], i_SHIFTIN2=cascade[1], + i_SHIFTIN3=1, i_SHIFTIN4=1, + o_SHIFTOUT3=cascade[2], o_SHIFTOUT4=cascade[3], + **common), + ] + + +class _IOSERDES2_8X(Module): + def __init__(self, pad, stb): + self.o = Signal(8) + self.i = Signal(8) + self.oe = Signal() + + # # # + + pad_i = Signal() + pad_o = Signal() + cascade = Signal() + i = self.i + common = dict(p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", + p_DATA_WIDTH=8, p_INTERFACE_TYPE="RETIMED", + i_BITSLIP=0, i_CE0=1, i_IOCE=stb, + i_RST=0, i_CLK0=ClockSignal("rtiox8"), i_CLK1=0, + i_CLKDIV=ClockSignal("rio_phy")) + self.specials += [ + Instance("ISERDES2", p_SERDES_MODE="MASTER", + o_Q4=i[7], o_Q3=i[6], o_Q2=i[5], o_Q1=i[4], + o_SHIFTOUT=cascade, i_D=pad_i, i_SHIFTIN=0, + **common), + Instance("ISERDES2", p_SERDES_MODE="SLAVE", + o_Q4=i[3], o_Q3=i[2], o_Q2=i[1], o_Q1=i[0], + i_D=0, i_SHIFTIN=cascade, **common), + ] + + oserdes = _OSERDES2_8X(pad_o, stb) + self.submodules += oserdes + self.specials += Instance("IOBUF", + i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, + io_IO=pad) + self.comb += [ + oserdes.t_in.eq(~self.oe), + oserdes.o.eq(self.o), + ] + + +class Output_8X(ttl_serdes_generic.Output): + def __init__(self, pad, stb): + serdes = _OSERDES2_8X(pad, stb) + self.submodules += serdes + ttl_serdes_generic.Output.__init__(self, serdes) + + +class Inout_8X(ttl_serdes_generic.Inout): + def __init__(self, pad, stb): + serdes = _IOSERDES2_8X(pad, stb) + self.submodules += serdes + ttl_serdes_generic.Inout.__init__(self, serdes) + + +class _OSERDES2_4X(Module): + def __init__(self, pad, stb): + self.o = Signal(4) + self.t_in = Signal() + self.t_out = Signal() + + # # # + + o = self.o + self.specials += Instance("OSERDES2", p_SERDES_MODE="NONE", + p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR", + p_DATA_WIDTH=4, p_OUTPUT_MODE="SINGLE_ENDED", + i_TRAIN=0, i_CLK0=ClockSignal("rtiox4"), + i_CLK1=0, i_CLKDIV=ClockSignal("rio_phy"), + i_IOCE=stb, i_OCE=1, i_TCE=1, + i_RST=ResetSignal(), + i_T4=self.t_in, i_T3=self.t_in, + i_T2=self.t_in, i_T1=self.t_in, + i_D4=o[3], i_D3=o[2], i_D2=o[1], i_D1=o[0], + o_OQ=pad, o_TQ=self.t_out) + + +class _IOSERDES2_4X(Module): + def __init__(self, pad, stb): + self.o = Signal(4) + self.i = Signal(4) + self.oe = Signal() + + # # # + + pad_i = Signal() + pad_o = Signal() + i = self.i + self.specials += Instance("ISERDES2", p_SERDES_MODE="NONE", + p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", + p_DATA_WIDTH=4, p_INTERFACE_TYPE="RETIMED", + i_BITSLIP=0, i_CE0=1, i_IOCE=stb, + i_RST=0, i_CLK0=ClockSignal("rtiox4"), + i_CLK1=0, i_CLKDIV=ClockSignal("rio_phy"), + o_Q4=i[3], o_Q3=i[2], o_Q2=i[1], o_Q1=i[0], + i_D=pad_i, i_SHIFTIN=0) + oserdes = _OSERDES2_4X(pad_o, stb) + self.submodules += oserdes + self.specials += Instance("IOBUF", + i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out, + io_IO=pad) + self.comb += [ + oserdes.t_in.eq(~self.oe), + oserdes.o.eq(self.o), + ] + + +class Output_4X(ttl_serdes_generic.Output): + def __init__(self, pad, stb): + serdes = _OSERDES2_4X(pad, stb) + self.submodules += serdes + ttl_serdes_generic.Output.__init__(self, serdes) + + +class Inout_4X(ttl_serdes_generic.Inout): + def __init__(self, pad, stb): + serdes = _IOSERDES2_4X(pad, stb) + self.submodules += serdes + ttl_serdes_generic.Inout.__init__(self, serdes) From 8e92cc91f5bc535a519134a3128c286744bd01b2 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 27 Jul 2015 21:29:50 -0600 Subject: [PATCH 22/38] pipistrello: use 4x serdes for rtio ttl --- soc/targets/artiq_pipistrello.py | 109 ++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 32 deletions(-) diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index 0f80f66b3..ac0f1577a 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -3,6 +3,8 @@ from fractions import Fraction from migen.fhdl.std import * from migen.bank.description import * from migen.bank import wbgen +from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.cdc import MultiReg from misoclib.com import gpio from misoclib.soc import mem_decoder @@ -11,46 +13,84 @@ from targets.pipistrello import BaseSoC from artiq.gateware.soc import AMPSoC from artiq.gateware import rtio, nist_qc1 -from artiq.gateware.rtio.phy import ttl_simple, dds +from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_spartan6, dds class _RTIOCRG(Module, AutoCSR): def __init__(self, platform, clk_freq): self._clock_sel = CSRStorage() - self.clock_domains.cd_rtio = ClockDomain(reset_less=True) + self._pll_reset = CSRStorage(reset=1) + self._pll_locked = CSRStatus() - f = Fraction(125*1000*1000, clk_freq) + self.clock_domains.cd_rtio = ClockDomain() + self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) + self.clock_domains.cd_rtiox8 = ClockDomain(reset_less=True) + self.rtiox4_stb = Signal() + self.rtiox8_stb = Signal() + + rtio_f = 125*1000*1000 + f = Fraction(rtio_f, clk_freq) rtio_internal_clk = Signal() - self.specials += Instance("DCM_CLKGEN", - p_CLKFXDV_DIVIDE=2, - p_CLKFX_DIVIDE=f.denominator, - p_CLKFX_MD_MAX=float(f), - p_CLKFX_MULTIPLY=f.numerator, - p_CLKIN_PERIOD=1e9/clk_freq, - p_SPREAD_SPECTRUM="NONE", - p_STARTUP_WAIT="FALSE", - i_CLKIN=ClockSignal(), - o_CLKFX=rtio_internal_clk, - i_FREEZEDCM=0, - i_RST=ResetSignal()) - - rtio_external_clk = platform.request("pmt", 2) - # ISE infers constraints for the internal clock - # and propagates them through the BUFGMUX. Adding this: - # platform.add_period_constraint(rtio_external_clk, 8.0) - # seems to confuse it - self.specials += Instance("BUFGMUX", - i_I0=rtio_internal_clk, - i_I1=rtio_external_clk, - i_S=self._clock_sel.storage, - o_O=self.cd_rtio.clk) + rtio_external_clk = Signal() + pmt2 = platform.request("pmt", 2) + dcm_locked = Signal() + rtio_clk = Signal() + pll_locked = Signal() + pll = Signal(3) + pll_fb = Signal() + self.specials += [ + Instance("IBUFG", i_I=pmt2, o_O=rtio_external_clk), + Instance("DCM_CLKGEN", p_CLKFXDV_DIVIDE=2, + p_CLKFX_DIVIDE=f.denominator, p_CLKFX_MD_MAX=float(f), + p_CLKFX_MULTIPLY=f.numerator, p_CLKIN_PERIOD=1e9/clk_freq, + p_SPREAD_SPECTRUM="NONE", p_STARTUP_WAIT="FALSE", + i_CLKIN=ClockSignal(), o_CLKFX=rtio_internal_clk, + i_FREEZEDCM=0, i_RST=ResetSignal(), o_LOCKED=dcm_locked), + Instance("BUFGMUX", + i_I0=rtio_internal_clk, i_I1=rtio_external_clk, + i_S=self._clock_sel.storage, o_O=rtio_clk), + Instance("PLL_ADV", p_SIM_DEVICE="SPARTAN6", + p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL", + p_REF_JITTER=.01, p_CLK_FEEDBACK="CLKFBOUT", + i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0, + i_RST=self._pll_reset.storage | ~dcm_locked, i_REL=0, + p_DIVCLK_DIVIDE=1, p_CLKFBOUT_MULT=8, + p_CLKFBOUT_PHASE=0., i_CLKINSEL=1, + i_CLKIN1=rtio_clk, i_CLKIN2=0, + p_CLKIN1_PERIOD=1e9/rtio_f, p_CLKIN2_PERIOD=0., + i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_locked, + o_CLKOUT0=pll[0], p_CLKOUT0_DUTY_CYCLE=.5, + o_CLKOUT1=pll[1], p_CLKOUT1_DUTY_CYCLE=.5, + o_CLKOUT2=pll[2], p_CLKOUT2_DUTY_CYCLE=.5, + p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=1, + p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=2, + p_CLKOUT2_PHASE=0., p_CLKOUT2_DIVIDE=8), + Instance("BUFPLL", p_DIVIDE=8, + i_PLLIN=pll[0], i_GCLK=self.cd_rtio.clk, + i_LOCKED=pll_locked, o_IOCLK=self.cd_rtiox8.clk, + o_SERDESSTROBE=self.rtiox8_stb), + Instance("BUFPLL", p_DIVIDE=4, + i_PLLIN=pll[1], i_GCLK=self.cd_rtio.clk, + i_LOCKED=pll_locked, o_IOCLK=self.cd_rtiox4.clk, + o_SERDESSTROBE=self.rtiox4_stb), + Instance("BUFG", i_I=pll[2], o_O=self.cd_rtio.clk), + AsyncResetSynchronizer(self.cd_rtio, ~pll_locked), + MultiReg(pll_locked, self._pll_locked.status), + ] + # ISE infers correct period constraints for cd_rtio.clk from + # the internal clock. The first two TIGs target just the BUFGMUX. platform.add_platform_command(""" -NET "{int_clk}" TNM_NET = "GRPint_clk"; NET "sys_clk" TNM_NET = "GRPsys_clk"; -TIMESPEC "TSfix_ise1" = FROM "GRPint_clk" TO "GRPsys_clk" TIG; +NET "{ext_clk}" TNM_NET = "GRPext_clk"; +TIMESPEC "TSfix_ise1" = FROM "GRPsys_clk" TO "GRPext_clk" TIG; +NET "{int_clk}" TNM_NET = "GRPint_clk"; TIMESPEC "TSfix_ise2" = FROM "GRPsys_clk" TO "GRPint_clk" TIG; -""", int_clk=rtio_internal_clk) +NET "{rtio_clk}" TNM_NET = "GRPrtio_clk"; +TIMESPEC "TSfix_ise3" = FROM "GRPrtio_clk" TO "GRPsys_clk" TIG; +TIMESPEC "TSfix_ise4" = FROM "GRPsys_clk" TO "GRPrtio_clk" TIG; +""", ext_clk=rtio_external_clk, int_clk=rtio_internal_clk, + rtio_clk=self.cd_rtio.clk) class NIST_QC1(BaseSoC, AMPSoC): @@ -90,16 +130,22 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd platform.request("ttl_h_tx_en").eq(1) ] + self.submodules.rtio_crg = _RTIOCRG(platform, self.clk_freq) + # RTIO channels rtio_channels = [] + # pmt1 can run on a 8x serdes if pmt0 is not used for i in range(2): - phy = ttl_simple.Inout(platform.request("pmt", i)) + phy = ttl_serdes_spartan6.Inout_4X(platform.request("pmt", i), + self.rtio_crg.rtiox4_stb) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512, ofifo_depth=4)) + # ttl2 can run on a 8x serdes if xtrig is not used for i in range(15): - phy = ttl_simple.Output(platform.request("ttl", i)) + phy = ttl_serdes_spartan6.Output_4X(platform.request("ttl", i), + self.rtio_crg.rtiox4_stb) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=256)) @@ -127,7 +173,6 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd ififo_depth=4)) # RTIO core - self.submodules.rtio_crg = _RTIOCRG(platform, self.clk_freq) self.submodules.rtio = rtio.RTIO(rtio_channels) self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width) self.add_constant("DDS_RTIO_CLK_RATIO", 8 >> self.rtio.fine_ts_width) From e95b06e96d6bf4ff7d3a11da4104acf10be1d07b Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 27 Jul 2015 21:48:56 -0600 Subject: [PATCH 23/38] pipistrello: tie unused dds.p low --- soc/targets/artiq_pipistrello.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index ac0f1577a..969a1325c 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -166,7 +166,9 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels)) self.add_constant("DDS_CHANNEL_COUNT", 8) self.add_constant("DDS_AD9858") - phy = dds.AD9858(platform.request("dds"), 8) + dds_pins = platform.request("dds") + self.comb += dds_pins.p.eq(0) + phy = dds.AD9858(dds_pins, 8) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=512, From bdee914828c1c65126157376810bc533ca5d9173 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 27 Jul 2015 22:14:42 -0600 Subject: [PATCH 24/38] rtiocrg.c: pipistrello also has pll_reset --- soc/runtime/rtiocrg.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/soc/runtime/rtiocrg.c b/soc/runtime/rtiocrg.c index 255f2a308..aaafe95e9 100644 --- a/soc/runtime/rtiocrg.c +++ b/soc/runtime/rtiocrg.c @@ -10,9 +10,7 @@ void rtiocrg_init(void) char b; int clk; -#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR rtio_crg_pll_reset_write(0); -#endif b = 'i'; clk = 0; fs_read("startup_clock", &b, 1, NULL); @@ -33,11 +31,7 @@ void rtiocrg_init(void) int rtiocrg_check(void) { -#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR return rtio_crg_pll_locked_read(); -#else - return 1; -#endif } int rtiocrg_switch_clock(int clk) @@ -46,22 +40,16 @@ int rtiocrg_switch_clock(int clk) current_clk = rtio_crg_clock_sel_read(); if(clk == current_clk) { -#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR busywait_us(150); if(!rtio_crg_pll_locked_read()) return 0; -#endif return 1; } -#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR rtio_crg_pll_reset_write(1); -#endif rtio_crg_clock_sel_write(clk); -#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR rtio_crg_pll_reset_write(0); busywait_us(150); if(!rtio_crg_pll_locked_read()) return 0; -#endif return 1; } From f0a7078336472cd10b903a911933344b23e2aa0c Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 27 Jul 2015 22:18:45 -0600 Subject: [PATCH 25/38] Revert "rtiocrg.c: pipistrello also has pll_reset" This reverts commit bdee914828c1c65126157376810bc533ca5d9173. --- soc/runtime/rtiocrg.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/soc/runtime/rtiocrg.c b/soc/runtime/rtiocrg.c index aaafe95e9..255f2a308 100644 --- a/soc/runtime/rtiocrg.c +++ b/soc/runtime/rtiocrg.c @@ -10,7 +10,9 @@ void rtiocrg_init(void) char b; int clk; +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR rtio_crg_pll_reset_write(0); +#endif b = 'i'; clk = 0; fs_read("startup_clock", &b, 1, NULL); @@ -31,7 +33,11 @@ void rtiocrg_init(void) int rtiocrg_check(void) { +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR return rtio_crg_pll_locked_read(); +#else + return 1; +#endif } int rtiocrg_switch_clock(int clk) @@ -40,16 +46,22 @@ int rtiocrg_switch_clock(int clk) current_clk = rtio_crg_clock_sel_read(); if(clk == current_clk) { +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR busywait_us(150); if(!rtio_crg_pll_locked_read()) return 0; +#endif return 1; } +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR rtio_crg_pll_reset_write(1); +#endif rtio_crg_clock_sel_write(clk); +#ifdef CSR_RTIO_CRG_PLL_RESET_ADDR rtio_crg_pll_reset_write(0); busywait_us(150); if(!rtio_crg_pll_locked_read()) return 0; +#endif return 1; } From 1809a70f5c229593f3e0e0bdb0bee4b69baaefb8 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 27 Jul 2015 23:38:23 -0600 Subject: [PATCH 26/38] Revert "pipistrello: use 4x serdes for rtio ttl" This reverts commit 8e92cc91f5bc535a519134a3128c286744bd01b2. Broken. Will revisit. --- soc/targets/artiq_pipistrello.py | 109 +++++++++---------------------- 1 file changed, 32 insertions(+), 77 deletions(-) diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index 969a1325c..f170d6360 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -3,8 +3,6 @@ from fractions import Fraction from migen.fhdl.std import * from migen.bank.description import * from migen.bank import wbgen -from migen.genlib.resetsync import AsyncResetSynchronizer -from migen.genlib.cdc import MultiReg from misoclib.com import gpio from misoclib.soc import mem_decoder @@ -13,84 +11,46 @@ from targets.pipistrello import BaseSoC from artiq.gateware.soc import AMPSoC from artiq.gateware import rtio, nist_qc1 -from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_spartan6, dds +from artiq.gateware.rtio.phy import ttl_simple, dds class _RTIOCRG(Module, AutoCSR): def __init__(self, platform, clk_freq): self._clock_sel = CSRStorage() - self._pll_reset = CSRStorage(reset=1) - self._pll_locked = CSRStatus() + self.clock_domains.cd_rtio = ClockDomain(reset_less=True) - self.clock_domains.cd_rtio = ClockDomain() - self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) - self.clock_domains.cd_rtiox8 = ClockDomain(reset_less=True) - self.rtiox4_stb = Signal() - self.rtiox8_stb = Signal() - - rtio_f = 125*1000*1000 - f = Fraction(rtio_f, clk_freq) + f = Fraction(125*1000*1000, clk_freq) rtio_internal_clk = Signal() - rtio_external_clk = Signal() - pmt2 = platform.request("pmt", 2) - dcm_locked = Signal() - rtio_clk = Signal() - pll_locked = Signal() - pll = Signal(3) - pll_fb = Signal() - self.specials += [ - Instance("IBUFG", i_I=pmt2, o_O=rtio_external_clk), - Instance("DCM_CLKGEN", p_CLKFXDV_DIVIDE=2, - p_CLKFX_DIVIDE=f.denominator, p_CLKFX_MD_MAX=float(f), - p_CLKFX_MULTIPLY=f.numerator, p_CLKIN_PERIOD=1e9/clk_freq, - p_SPREAD_SPECTRUM="NONE", p_STARTUP_WAIT="FALSE", - i_CLKIN=ClockSignal(), o_CLKFX=rtio_internal_clk, - i_FREEZEDCM=0, i_RST=ResetSignal(), o_LOCKED=dcm_locked), - Instance("BUFGMUX", - i_I0=rtio_internal_clk, i_I1=rtio_external_clk, - i_S=self._clock_sel.storage, o_O=rtio_clk), - Instance("PLL_ADV", p_SIM_DEVICE="SPARTAN6", - p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL", - p_REF_JITTER=.01, p_CLK_FEEDBACK="CLKFBOUT", - i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0, - i_RST=self._pll_reset.storage | ~dcm_locked, i_REL=0, - p_DIVCLK_DIVIDE=1, p_CLKFBOUT_MULT=8, - p_CLKFBOUT_PHASE=0., i_CLKINSEL=1, - i_CLKIN1=rtio_clk, i_CLKIN2=0, - p_CLKIN1_PERIOD=1e9/rtio_f, p_CLKIN2_PERIOD=0., - i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_locked, - o_CLKOUT0=pll[0], p_CLKOUT0_DUTY_CYCLE=.5, - o_CLKOUT1=pll[1], p_CLKOUT1_DUTY_CYCLE=.5, - o_CLKOUT2=pll[2], p_CLKOUT2_DUTY_CYCLE=.5, - p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=1, - p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=2, - p_CLKOUT2_PHASE=0., p_CLKOUT2_DIVIDE=8), - Instance("BUFPLL", p_DIVIDE=8, - i_PLLIN=pll[0], i_GCLK=self.cd_rtio.clk, - i_LOCKED=pll_locked, o_IOCLK=self.cd_rtiox8.clk, - o_SERDESSTROBE=self.rtiox8_stb), - Instance("BUFPLL", p_DIVIDE=4, - i_PLLIN=pll[1], i_GCLK=self.cd_rtio.clk, - i_LOCKED=pll_locked, o_IOCLK=self.cd_rtiox4.clk, - o_SERDESSTROBE=self.rtiox4_stb), - Instance("BUFG", i_I=pll[2], o_O=self.cd_rtio.clk), - AsyncResetSynchronizer(self.cd_rtio, ~pll_locked), - MultiReg(pll_locked, self._pll_locked.status), - ] + self.specials += Instance("DCM_CLKGEN", + p_CLKFXDV_DIVIDE=2, + p_CLKFX_DIVIDE=f.denominator, + p_CLKFX_MD_MAX=float(f), + p_CLKFX_MULTIPLY=f.numerator, + p_CLKIN_PERIOD=1e9/clk_freq, + p_SPREAD_SPECTRUM="NONE", + p_STARTUP_WAIT="FALSE", + i_CLKIN=ClockSignal(), + o_CLKFX=rtio_internal_clk, + i_FREEZEDCM=0, + i_RST=ResetSignal()) + + rtio_external_clk = platform.request("pmt", 2) + # ISE infers constraints for the internal clock + # and propagates them through the BUFGMUX. Adding this: + # platform.add_period_constraint(rtio_external_clk, 8.0) + # seems to confuse it + self.specials += Instance("BUFGMUX", + i_I0=rtio_internal_clk, + i_I1=rtio_external_clk, + i_S=self._clock_sel.storage, + o_O=self.cd_rtio.clk) - # ISE infers correct period constraints for cd_rtio.clk from - # the internal clock. The first two TIGs target just the BUFGMUX. platform.add_platform_command(""" -NET "sys_clk" TNM_NET = "GRPsys_clk"; -NET "{ext_clk}" TNM_NET = "GRPext_clk"; -TIMESPEC "TSfix_ise1" = FROM "GRPsys_clk" TO "GRPext_clk" TIG; NET "{int_clk}" TNM_NET = "GRPint_clk"; +NET "sys_clk" TNM_NET = "GRPsys_clk"; +TIMESPEC "TSfix_ise1" = FROM "GRPint_clk" TO "GRPsys_clk" TIG; TIMESPEC "TSfix_ise2" = FROM "GRPsys_clk" TO "GRPint_clk" TIG; -NET "{rtio_clk}" TNM_NET = "GRPrtio_clk"; -TIMESPEC "TSfix_ise3" = FROM "GRPrtio_clk" TO "GRPsys_clk" TIG; -TIMESPEC "TSfix_ise4" = FROM "GRPsys_clk" TO "GRPrtio_clk" TIG; -""", ext_clk=rtio_external_clk, int_clk=rtio_internal_clk, - rtio_clk=self.cd_rtio.clk) +""", int_clk=rtio_internal_clk) class NIST_QC1(BaseSoC, AMPSoC): @@ -130,22 +90,16 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd platform.request("ttl_h_tx_en").eq(1) ] - self.submodules.rtio_crg = _RTIOCRG(platform, self.clk_freq) - # RTIO channels rtio_channels = [] - # pmt1 can run on a 8x serdes if pmt0 is not used for i in range(2): - phy = ttl_serdes_spartan6.Inout_4X(platform.request("pmt", i), - self.rtio_crg.rtiox4_stb) + phy = ttl_simple.Inout(platform.request("pmt", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512, ofifo_depth=4)) - # ttl2 can run on a 8x serdes if xtrig is not used for i in range(15): - phy = ttl_serdes_spartan6.Output_4X(platform.request("ttl", i), - self.rtio_crg.rtiox4_stb) + phy = ttl_simple.Output(platform.request("ttl", i)) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=256)) @@ -175,6 +129,7 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd ififo_depth=4)) # RTIO core + self.submodules.rtio_crg = _RTIOCRG(platform, self.clk_freq) self.submodules.rtio = rtio.RTIO(rtio_channels) self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width) self.add_constant("DDS_RTIO_CLK_RATIO", 8 >> self.rtio.fine_ts_width) From 8e391e2661918cbae43795a16e9523e3a9e245f6 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 28 Jul 2015 18:56:35 +0800 Subject: [PATCH 27/38] kc705: generate 10MHz clock on GPIO SMA For SynthNV and input tests. --- soc/targets/artiq_kc705.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/soc/targets/artiq_kc705.py b/soc/targets/artiq_kc705.py index ffa61f76c..a768e2f07 100644 --- a/soc/targets/artiq_kc705.py +++ b/soc/targets/artiq_kc705.py @@ -25,6 +25,12 @@ 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 + self.clock_domains.cd_ext_clkout = ClockDomain(reset_less=True) + ext_clkout = platform.request("user_sma_gpio_p") + 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) @@ -35,6 +41,7 @@ class _RTIOCRG(Module, AutoCSR): 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, @@ -45,6 +52,7 @@ class _RTIOCRG(Module, AutoCSR): # 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, @@ -52,18 +60,18 @@ class _RTIOCRG(Module, AutoCSR): o_CLKFBOUT=rtio_clk, p_CLKOUT0_DIVIDE=2, p_CLKOUT0_PHASE=0.0, - o_CLKOUT0=rtiox4_clk), + 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) ] - # 62.5MHz when using internal RTIO clock - ext_clkout = platform.request("user_sma_gpio_p") - self.sync.rtio += ext_clkout.eq(~ext_clkout) - class _NIST_QCx(MiniSoC, AMPSoC): csr_map = { From 9dfbf077433bc47da125a89cdfbaf90cd14adf17 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Mon, 27 Jul 2015 21:29:50 -0600 Subject: [PATCH 28/38] pipistrello: use 4x serdes for rtio ttl pipistrello: do not wait for lock on startup LCK_cycle:6 was added in 6a412f796e1 (mibuild). It waits for _all_ DCM and PLLs to lock (probably irrespective of STARTUP_WAIT). --- soc/targets/artiq_pipistrello.py | 110 ++++++++++++++++++++++--------- 1 file changed, 78 insertions(+), 32 deletions(-) diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index f170d6360..7c9049583 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -3,6 +3,8 @@ from fractions import Fraction from migen.fhdl.std import * from migen.bank.description import * from migen.bank import wbgen +from migen.genlib.resetsync import AsyncResetSynchronizer +from migen.genlib.cdc import MultiReg from misoclib.com import gpio from misoclib.soc import mem_decoder @@ -11,46 +13,84 @@ from targets.pipistrello import BaseSoC from artiq.gateware.soc import AMPSoC from artiq.gateware import rtio, nist_qc1 -from artiq.gateware.rtio.phy import ttl_simple, dds +from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_spartan6, dds class _RTIOCRG(Module, AutoCSR): def __init__(self, platform, clk_freq): self._clock_sel = CSRStorage() - self.clock_domains.cd_rtio = ClockDomain(reset_less=True) + self._pll_reset = CSRStorage(reset=1) + self._pll_locked = CSRStatus() - f = Fraction(125*1000*1000, clk_freq) + self.clock_domains.cd_rtio = ClockDomain() + self.clock_domains.cd_rtiox4 = ClockDomain(reset_less=True) + self.clock_domains.cd_rtiox8 = ClockDomain(reset_less=True) + self.rtiox4_stb = Signal() + self.rtiox8_stb = Signal() + + rtio_f = 125*1000*1000 + f = Fraction(rtio_f, clk_freq) rtio_internal_clk = Signal() - self.specials += Instance("DCM_CLKGEN", - p_CLKFXDV_DIVIDE=2, - p_CLKFX_DIVIDE=f.denominator, - p_CLKFX_MD_MAX=float(f), - p_CLKFX_MULTIPLY=f.numerator, - p_CLKIN_PERIOD=1e9/clk_freq, - p_SPREAD_SPECTRUM="NONE", - p_STARTUP_WAIT="FALSE", - i_CLKIN=ClockSignal(), - o_CLKFX=rtio_internal_clk, - i_FREEZEDCM=0, - i_RST=ResetSignal()) - - rtio_external_clk = platform.request("pmt", 2) - # ISE infers constraints for the internal clock - # and propagates them through the BUFGMUX. Adding this: - # platform.add_period_constraint(rtio_external_clk, 8.0) - # seems to confuse it - self.specials += Instance("BUFGMUX", - i_I0=rtio_internal_clk, - i_I1=rtio_external_clk, - i_S=self._clock_sel.storage, - o_O=self.cd_rtio.clk) + rtio_external_clk = Signal() + pmt2 = platform.request("pmt", 2) + dcm_locked = Signal() + rtio_clk = Signal() + pll_locked = Signal() + pll = Signal(3) + pll_fb = Signal() + self.specials += [ + Instance("IBUFG", i_I=pmt2, o_O=rtio_external_clk), + Instance("DCM_CLKGEN", p_CLKFXDV_DIVIDE=2, + p_CLKFX_DIVIDE=f.denominator, p_CLKFX_MD_MAX=float(f), + p_CLKFX_MULTIPLY=f.numerator, p_CLKIN_PERIOD=1e9/clk_freq, + p_SPREAD_SPECTRUM="NONE", p_STARTUP_WAIT="FALSE", + i_CLKIN=ClockSignal(), o_CLKFX=rtio_internal_clk, + i_FREEZEDCM=0, i_RST=ResetSignal(), o_LOCKED=dcm_locked), + Instance("BUFGMUX", + i_I0=rtio_internal_clk, i_I1=rtio_external_clk, + i_S=self._clock_sel.storage, o_O=rtio_clk), + Instance("PLL_ADV", p_SIM_DEVICE="SPARTAN6", + p_BANDWIDTH="OPTIMIZED", p_COMPENSATION="INTERNAL", + p_REF_JITTER=.01, p_CLK_FEEDBACK="CLKFBOUT", + i_DADDR=0, i_DCLK=0, i_DEN=0, i_DI=0, i_DWE=0, + i_RST=self._pll_reset.storage | ~dcm_locked, i_REL=0, + p_DIVCLK_DIVIDE=1, p_CLKFBOUT_MULT=8, + p_CLKFBOUT_PHASE=0., i_CLKINSEL=1, + i_CLKIN1=rtio_clk, i_CLKIN2=0, + p_CLKIN1_PERIOD=1e9/rtio_f, p_CLKIN2_PERIOD=0., + i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, o_LOCKED=pll_locked, + o_CLKOUT0=pll[0], p_CLKOUT0_DUTY_CYCLE=.5, + o_CLKOUT1=pll[1], p_CLKOUT1_DUTY_CYCLE=.5, + o_CLKOUT2=pll[2], p_CLKOUT2_DUTY_CYCLE=.5, + p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=1, + p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=2, + p_CLKOUT2_PHASE=0., p_CLKOUT2_DIVIDE=8), + Instance("BUFPLL", p_DIVIDE=8, + i_PLLIN=pll[0], i_GCLK=self.cd_rtio.clk, + i_LOCKED=pll_locked, o_IOCLK=self.cd_rtiox8.clk, + o_SERDESSTROBE=self.rtiox8_stb), + Instance("BUFPLL", p_DIVIDE=4, + i_PLLIN=pll[1], i_GCLK=self.cd_rtio.clk, + i_LOCKED=pll_locked, o_IOCLK=self.cd_rtiox4.clk, + o_SERDESSTROBE=self.rtiox4_stb), + Instance("BUFG", i_I=pll[2], o_O=self.cd_rtio.clk), + AsyncResetSynchronizer(self.cd_rtio, ~pll_locked), + MultiReg(pll_locked, self._pll_locked.status), + ] + # ISE infers correct period constraints for cd_rtio.clk from + # the internal clock. The first two TIGs target just the BUFGMUX. platform.add_platform_command(""" -NET "{int_clk}" TNM_NET = "GRPint_clk"; NET "sys_clk" TNM_NET = "GRPsys_clk"; -TIMESPEC "TSfix_ise1" = FROM "GRPint_clk" TO "GRPsys_clk" TIG; +NET "{ext_clk}" TNM_NET = "GRPext_clk"; +TIMESPEC "TSfix_ise1" = FROM "GRPsys_clk" TO "GRPext_clk" TIG; +NET "{int_clk}" TNM_NET = "GRPint_clk"; TIMESPEC "TSfix_ise2" = FROM "GRPsys_clk" TO "GRPint_clk" TIG; -""", int_clk=rtio_internal_clk) +NET "{rtio_clk}" TNM_NET = "GRPrtio_clk"; +TIMESPEC "TSfix_ise3" = FROM "GRPrtio_clk" TO "GRPsys_clk" TIG; +TIMESPEC "TSfix_ise4" = FROM "GRPsys_clk" TO "GRPrtio_clk" TIG; +""", ext_clk=rtio_external_clk, int_clk=rtio_internal_clk, + rtio_clk=self.cd_rtio.clk) class NIST_QC1(BaseSoC, AMPSoC): @@ -73,6 +113,7 @@ class NIST_QC1(BaseSoC, AMPSoC): sdram_controller_settings=MiniconSettings(l2_size=64*1024), with_timer=False, **kwargs) AMPSoC.__init__(self) + platform.toolchain.bitgen_opt = "-g Binary:Yes -w" platform.toolchain.ise_commands += """ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd {build_name}.pcf """ @@ -90,16 +131,22 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd platform.request("ttl_h_tx_en").eq(1) ] + self.submodules.rtio_crg = _RTIOCRG(platform, self.clk_freq) + # RTIO channels rtio_channels = [] + # pmt1 can run on a 8x serdes if pmt0 is not used for i in range(2): - phy = ttl_simple.Inout(platform.request("pmt", i)) + phy = ttl_serdes_spartan6.Inout_4X(platform.request("pmt", i), + self.rtio_crg.rtiox4_stb) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=512, ofifo_depth=4)) + # ttl2 can run on a 8x serdes if xtrig is not used for i in range(15): - phy = ttl_simple.Output(platform.request("ttl", i)) + phy = ttl_serdes_spartan6.Output_4X(platform.request("ttl", i), + self.rtio_crg.rtiox4_stb) self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=256)) @@ -129,7 +176,6 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd ififo_depth=4)) # RTIO core - self.submodules.rtio_crg = _RTIOCRG(platform, self.clk_freq) self.submodules.rtio = rtio.RTIO(rtio_channels) self.add_constant("RTIO_FINE_TS_WIDTH", self.rtio.fine_ts_width) self.add_constant("DDS_RTIO_CLK_RATIO", 8 >> self.rtio.fine_ts_width) From fb339d294ea9a58d9fcd319c5f8e094b56d3619d Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 28 Jul 2015 01:21:11 -0600 Subject: [PATCH 29/38] serdes_s6: no need to reset --- artiq/gateware/rtio/phy/ttl_serdes_spartan6.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/artiq/gateware/rtio/phy/ttl_serdes_spartan6.py b/artiq/gateware/rtio/phy/ttl_serdes_spartan6.py index 89fddb2d0..cf31449c1 100644 --- a/artiq/gateware/rtio/phy/ttl_serdes_spartan6.py +++ b/artiq/gateware/rtio/phy/ttl_serdes_spartan6.py @@ -103,8 +103,7 @@ class _OSERDES2_4X(Module): p_DATA_WIDTH=4, p_OUTPUT_MODE="SINGLE_ENDED", i_TRAIN=0, i_CLK0=ClockSignal("rtiox4"), i_CLK1=0, i_CLKDIV=ClockSignal("rio_phy"), - i_IOCE=stb, i_OCE=1, i_TCE=1, - i_RST=ResetSignal(), + i_IOCE=stb, i_OCE=1, i_TCE=1, i_RST=0, i_T4=self.t_in, i_T3=self.t_in, i_T2=self.t_in, i_T1=self.t_in, i_D4=o[3], i_D3=o[2], i_D2=o[1], i_D1=o[0], From 67715f0d2ee43beae98e7f58bd951f24b57d8eeb Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 28 Jul 2015 12:50:34 -0600 Subject: [PATCH 30/38] pipistrello: only put serdes on the lower ttls this setup is getting a bit power hungry. pmt0, 1 (rtio channels 0, 1): 4x in and out ttl0, 1 (rtio channels 2, 3): 4x out ttl2 (rtio channel 4): 8x out --- soc/targets/artiq_pipistrello.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/soc/targets/artiq_pipistrello.py b/soc/targets/artiq_pipistrello.py index 7c9049583..7a16cdcfe 100644 --- a/soc/targets/artiq_pipistrello.py +++ b/soc/targets/artiq_pipistrello.py @@ -145,8 +145,15 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd # ttl2 can run on a 8x serdes if xtrig is not used for i in range(15): - phy = ttl_serdes_spartan6.Output_4X(platform.request("ttl", i), - self.rtio_crg.rtiox4_stb) + if i in (0, 1): + phy = ttl_serdes_spartan6.Output_4X(platform.request("ttl", i), + self.rtio_crg.rtiox4_stb) + elif i in (2,): + phy = ttl_serdes_spartan6.Output_8X(platform.request("ttl", i), + self.rtio_crg.rtiox8_stb) + else: + phy = ttl_simple.Output(platform.request("ttl", i)) + self.submodules += phy rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=256)) From b179430f6bc9c5808ba53de632f80940afc2892c Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 28 Jul 2015 23:35:07 +0300 Subject: [PATCH 31/38] Specify correct llvmlite branch in installation instructions. --- doc/manual/installing.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/manual/installing.rst b/doc/manual/installing.rst index 77ff98394..5ade4cb7e 100644 --- a/doc/manual/installing.rst +++ b/doc/manual/installing.rst @@ -299,16 +299,14 @@ Installing the host-side software * Install the llvmlite Python bindings: :: $ cd ~/artiq-dev - $ git clone https://github.com/numba/llvmlite + $ git clone https://github.com/m-labs/llvmlite + $ git checkout backport-3.5 $ cd llvmlite $ patch -p1 < ~/artiq-dev/artiq/misc/llvmlite-add-all-targets.patch $ patch -p1 < ~/artiq-dev/artiq/misc/llvmlite-rename.patch $ patch -p1 < ~/artiq-dev/artiq/misc/llvmlite-build-as-debug-on-windows.patch $ LLVM_CONFIG=/usr/local/llvm-or1k/bin/llvm-config python3 setup.py install --user -.. note:: - llvmlite is in development and its API is not stable yet. Commit ID ``11a8303d02e3d6dd2d1e0e9065701795cd8a979f`` is known to work. - * Install ARTIQ: :: $ cd ~/artiq-dev From e95b66f114026593ad990b81f26f8d5a0e4ddb3d Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 28 Jul 2015 16:14:26 -0600 Subject: [PATCH 32/38] ttl: remove spurious _mu --- artiq/coredevice/ttl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 644e55ff6..078dc4bb2 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -177,7 +177,7 @@ class TTLInOut: self._set_sensitivity(0) @kernel - def gate_both_mu(self, duration): + def gate_both(self, duration): """Register both rising and falling edge events for the specified duration (in seconds).""" self._set_sensitivity(3) From 5f5227f01f9fbede73d9b0fb5954412623fc5f90 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 28 Jul 2015 16:16:49 -0600 Subject: [PATCH 33/38] ttl: add timestamp() --- artiq/coredevice/ttl.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 078dc4bb2..b2399786a 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -196,13 +196,23 @@ class TTLInOut: @kernel def timestamp_mu(self): - """Poll the RTIO input and returns an event timestamp, according to - the gating. + """Poll the RTIO input and returns an event timestamp (in machine + units), according to the gating. If the gate is permanently closed, returns a negative value. """ return syscall("ttl_get", self.channel, self.i_previous_timestamp) + @kernel + def timestamp(self): + """Poll the RTIO input and returns an event timestamp (in seconds), + according to the gating. + + If the gate is permanently closed, returns a negative value. + """ + return mu_to_seconds( + syscall("ttl_get", self.channel, self.i_previous_timestamp)) + class TTLClockGen: """RTIO TTL clock generator driver. From 2640a57af3e91ed357a8cb1d0f3bbd560f17de44 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 28 Jul 2015 16:17:23 -0600 Subject: [PATCH 34/38] test/coredevice: let output() settle longer --- artiq/test/coredevice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/test/coredevice.py b/artiq/test/coredevice.py index 95e8573b9..e4d9375ba 100644 --- a/artiq/test/coredevice.py +++ b/artiq/test/coredevice.py @@ -120,7 +120,7 @@ class LoopbackCount(EnvExperiment): @kernel def run(self): self.ttl_inout.output() - delay(1*us) + delay(5*us) with parallel: self.ttl_inout.gate_rising(10*us) with sequential: From 90368415a6f24b458fc0cbf54acf255d259388f3 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 29 Jul 2015 11:11:16 +0800 Subject: [PATCH 35/38] ttl: remove timestamp function The general idea is that functions that work with absolute timestamps exist only in machine units versions, to help prevent floating point losses of precision. Time differences should be computed in machine units and then converted, e.g. mu_to_seconds(t2-t1). This function would have had problems after ~50 days of running the device. --- artiq/coredevice/ttl.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index b2399786a..866e884e5 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -203,16 +203,6 @@ class TTLInOut: """ return syscall("ttl_get", self.channel, self.i_previous_timestamp) - @kernel - def timestamp(self): - """Poll the RTIO input and returns an event timestamp (in seconds), - according to the gating. - - If the gate is permanently closed, returns a negative value. - """ - return mu_to_seconds( - syscall("ttl_get", self.channel, self.i_previous_timestamp)) - class TTLClockGen: """RTIO TTL clock generator driver. From 278570faf693b1eba6002cca446d9e76663ccc30 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 28 Jul 2015 21:36:01 -0600 Subject: [PATCH 36/38] examples: add TDR toy example --- examples/master/repository/tdr.py | 75 +++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 examples/master/repository/tdr.py diff --git a/examples/master/repository/tdr.py b/examples/master/repository/tdr.py new file mode 100644 index 000000000..cca9647e4 --- /dev/null +++ b/examples/master/repository/tdr.py @@ -0,0 +1,75 @@ +from artiq import * + + +class PulseNotReceivedError(Exception): + pass + + +class TDR(EnvExperiment): + """Time domain reflectometer. + + From ttl2 an impedance matched pulse is send onto a coax + cable with an open end. pmt0 (very short stub, high impedance) also + listens on the transmission line near ttl2. + + When the forward propagating pulse passes pmt0, the voltage is half of the + logic voltage and does not register as a rising edge. Once the + rising edge is reflected at an open end (same sign) and passes by pmt0 on + its way back to ttl2, it is detected. Analogously, hysteresis leads to + detection of the falling edge once the reflection reaches pmt0 after + one round trip time. + + This works marginally and is just a proof of principle: it relies on + hysteresis at FPGA inputs around half voltage and good impedance steps, + as well as reasonably low loss cable. It does not work well for longer + cables (>100 ns RTT). The default drive strength of 12 mA and 3.3 V would + be ~300 Ω but it seems 40 Ω series impedance at the output matches + the hysteresis of the input. + + This is also equivalent to a loopback tester or a delay measurement. + """ + def build(self): + self.attr_device("core") + self.attr_device("pmt0") + self.attr_device("ttl2") + + def run(self): + n = 1000 # repetitions + latency = 50e-9 # calibrated latency without a transmission line + pulse = 1e-6 # pulse length, larger than rtt + try: + self.many(n, seconds_to_mu(pulse, self.core)) + except PulseNotReceivedError: + print("to few edges: cable too long or wiring bad") + else: + print(self.t) + t_rise = mu_to_seconds(self.t[0], self.core)/n - latency + t_fall = mu_to_seconds(self.t[1], self.core)/n - latency - pulse + print("round trip times:") + print("rising: {:5g} ns, falling {:5g} ns".format( + t_rise/1e-9, t_fall/1e-9)) + + def rep(self, t): + self.t = t + + @kernel + def many(self, n, p): + t = [0 for i in range(2)] + self.core.break_realtime() + for i in range(n): + self.one(t, p) + self.rep(t) + + @kernel + def one(self, t, p): + with parallel: + self.pmt0.gate_both_mu(2*p) + with sequential: + t0 = now_mu() + self.ttl2.pulse_mu(p) + for i in range(len(t)): + ti = self.pmt0.timestamp_mu() + if ti <= 0: + raise PulseNotReceivedError + t[i] += ti - t0 + self.pmt0.count() From ebbbdcf194b2935b4237118687c626ec93d33859 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Tue, 28 Jul 2015 23:30:26 -0600 Subject: [PATCH 37/38] examples/tdr: cleanup --- examples/master/repository/tdr.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/examples/master/repository/tdr.py b/examples/master/repository/tdr.py index cca9647e4..9a07d5753 100644 --- a/examples/master/repository/tdr.py +++ b/examples/master/repository/tdr.py @@ -49,27 +49,23 @@ class TDR(EnvExperiment): print("rising: {:5g} ns, falling {:5g} ns".format( t_rise/1e-9, t_fall/1e-9)) - def rep(self, t): - self.t = t - @kernel def many(self, n, p): t = [0 for i in range(2)] self.core.break_realtime() for i in range(n): self.one(t, p) - self.rep(t) + self.t = t @kernel def one(self, t, p): + t0 = now_mu() with parallel: self.pmt0.gate_both_mu(2*p) - with sequential: - t0 = now_mu() - self.ttl2.pulse_mu(p) + self.ttl2.pulse_mu(p) for i in range(len(t)): ti = self.pmt0.timestamp_mu() if ti <= 0: raise PulseNotReceivedError t[i] += ti - t0 - self.pmt0.count() + self.pmt0.count() # flush From c40ae9dbd3c8443543081e81266ba91d86cd6c18 Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 29 Jul 2015 12:40:30 +0300 Subject: [PATCH 38/38] MiSoC is not built with -fPIC anymore, remove support code for that. --- soc/runtime/ksupport.ld | 11 ----------- soc/runtime/linker.ld | 11 ----------- 2 files changed, 22 deletions(-) diff --git a/soc/runtime/ksupport.ld b/soc/runtime/ksupport.ld index 0aec5ca64..3cc585399 100644 --- a/soc/runtime/ksupport.ld +++ b/soc/runtime/ksupport.ld @@ -24,17 +24,6 @@ SECTIONS _etext = .; } > ksupport - .got : - { - _GLOBAL_OFFSET_TABLE_ = .; - *(.got) - } > ksupport - - .got.plt : - { - *(.got.plt) - } > ksupport - .rodata : { . = ALIGN(4); diff --git a/soc/runtime/linker.ld b/soc/runtime/linker.ld index d0c3a6558..4a4217f1e 100644 --- a/soc/runtime/linker.ld +++ b/soc/runtime/linker.ld @@ -26,17 +26,6 @@ SECTIONS _etext = .; } > runtime - .got : - { - _GLOBAL_OFFSET_TABLE_ = .; - *(.got) - } > runtime - - .got.plt : - { - *(.got.plt) - } > runtime - .rodata : { . = ALIGN(4);