mirror of https://github.com/m-labs/artiq.git
drtio/transceiver/gth: implement tx multi lane phase alignment sequence
This commit is contained in:
parent
bc5e949bb4
commit
820c834251
|
@ -1,5 +1,5 @@
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from operator import or_
|
from operator import or_, and_
|
||||||
|
|
||||||
from migen import *
|
from migen import *
|
||||||
from migen.genlib.resetsync import AsyncResetSynchronizer
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
||||||
|
@ -16,7 +16,18 @@ from artiq.gateware.drtio.transceiver.gth_ultrascale_init import *
|
||||||
class GTHSingle(Module):
|
class GTHSingle(Module):
|
||||||
def __init__(self, refclk, pads, sys_clk_freq, rtio_clk_freq, dw, mode):
|
def __init__(self, refclk, pads, sys_clk_freq, rtio_clk_freq, dw, mode):
|
||||||
assert (dw == 20) or (dw == 40)
|
assert (dw == 20) or (dw == 40)
|
||||||
assert mode in ["master", "slave"]
|
assert mode in ["single", "master", "slave"]
|
||||||
|
self.mode = mode
|
||||||
|
|
||||||
|
# phase alignment
|
||||||
|
self.txsyncallin = Signal()
|
||||||
|
self.txphaligndone = Signal()
|
||||||
|
self.txsyncallin = Signal()
|
||||||
|
self.txsyncin = Signal()
|
||||||
|
self.txsyncout = Signal()
|
||||||
|
self.txdlysreset = Signal()
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
nwords = dw//10
|
nwords = dw//10
|
||||||
self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")(
|
self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")(
|
||||||
|
@ -96,11 +107,16 @@ class GTHSingle(Module):
|
||||||
# TX Startup/Reset
|
# TX Startup/Reset
|
||||||
i_GTTXRESET=tx_init.gtXxreset,
|
i_GTTXRESET=tx_init.gtXxreset,
|
||||||
o_TXRESETDONE=tx_init.Xxresetdone,
|
o_TXRESETDONE=tx_init.Xxresetdone,
|
||||||
i_TXDLYSRESET=tx_init.Xxdlysreset,
|
i_TXDLYSRESET=tx_init.Xxdlysreset if mode != "slave" else self.txdlysreset,
|
||||||
o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone,
|
o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone,
|
||||||
o_TXPHALIGNDONE=tx_init.Xxphaligndone,
|
o_TXPHALIGNDONE=tx_init.Xxphaligndone,
|
||||||
i_TXUSERRDY=tx_init.Xxuserrdy,
|
i_TXUSERRDY=tx_init.Xxuserrdy,
|
||||||
i_TXSYNCMODE=1,
|
i_TXSYNCMODE=mode != "slave",
|
||||||
|
p_TXSYNC_MULTILANE=0 if mode == "single" else 1,
|
||||||
|
p_TXSYNC_OVRD=0,
|
||||||
|
i_TXSYNCALLIN=self.txsyncallin,
|
||||||
|
i_TXSYNCIN=self.txsyncin,
|
||||||
|
o_TXSYNCOUT=self.txsyncout,
|
||||||
|
|
||||||
# TX data
|
# TX data
|
||||||
p_TX_DATA_WIDTH=dw,
|
p_TX_DATA_WIDTH=dw,
|
||||||
|
@ -172,6 +188,7 @@ class GTHSingle(Module):
|
||||||
o_GTHTXP=pads.txp,
|
o_GTHTXP=pads.txp,
|
||||||
o_GTHTXN=pads.txn
|
o_GTHTXN=pads.txn
|
||||||
)
|
)
|
||||||
|
self.comb += self.txphaligndone.eq(tx_init.Xxphaligndone)
|
||||||
|
|
||||||
self.submodules += [
|
self.submodules += [
|
||||||
add_probe_async("drtio_gth", "cpll_lock", cpll_lock),
|
add_probe_async("drtio_gth", "cpll_lock", cpll_lock),
|
||||||
|
@ -221,6 +238,44 @@ class GTHSingle(Module):
|
||||||
self.submodules += add_probe_async("drtio_gth", "clock_aligner_ready", clock_aligner.ready)
|
self.submodules += add_probe_async("drtio_gth", "clock_aligner_ready", clock_aligner.ready)
|
||||||
|
|
||||||
|
|
||||||
|
class GTHTXPhaseAlignement(Module):
|
||||||
|
# TX Buffer Bypass in Single-Lane/Multi-Lane Auto Mode (ug576)
|
||||||
|
def __init__(self, gths):
|
||||||
|
txsyncallin = Signal()
|
||||||
|
txsync = Signal()
|
||||||
|
txphaligndone = Signal(len(gths))
|
||||||
|
txdlysreset = Signal()
|
||||||
|
ready_for_align = Signal(len(gths))
|
||||||
|
all_ready_for_align = Signal()
|
||||||
|
|
||||||
|
for i, gth in enumerate(gths):
|
||||||
|
# Common to all transceivers
|
||||||
|
self.comb += [
|
||||||
|
ready_for_align[i].eq(1),
|
||||||
|
gth.txsyncin.eq(txsync),
|
||||||
|
gth.txsyncallin.eq(txsyncallin),
|
||||||
|
txphaligndone[i].eq(gth.txphaligndone)
|
||||||
|
]
|
||||||
|
# Specific to Master or Single transceivers
|
||||||
|
if gth.mode == "master" or gth.mode == "single":
|
||||||
|
self.comb += [
|
||||||
|
gth.tx_init.all_ready_for_align.eq(all_ready_for_align),
|
||||||
|
txsync.eq(gth.txsyncout),
|
||||||
|
txdlysreset.eq(gth.tx_init.Xxdlysreset)
|
||||||
|
]
|
||||||
|
# Specific to Slave transceivers
|
||||||
|
else:
|
||||||
|
self.comb += [
|
||||||
|
ready_for_align[i].eq(gth.tx_init.ready_for_align),
|
||||||
|
gth.txdlysreset.eq(txdlysreset),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.comb += [
|
||||||
|
txsyncallin.eq(reduce(and_, [txphaligndone[i] for i in range(len(gths))])),
|
||||||
|
all_ready_for_align.eq(reduce(and_, [ready_for_align[i] for i in range(len(gths))]))
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class GTH(Module, TransceiverInterface):
|
class GTH(Module, TransceiverInterface):
|
||||||
def __init__(self, clock_pads, data_pads, sys_clk_freq, rtio_clk_freq, dw=20, master=0):
|
def __init__(self, clock_pads, data_pads, sys_clk_freq, rtio_clk_freq, dw=20, master=0):
|
||||||
self.nchannels = nchannels = len(data_pads)
|
self.nchannels = nchannels = len(data_pads)
|
||||||
|
@ -238,18 +293,23 @@ class GTH(Module, TransceiverInterface):
|
||||||
rtio_tx_clk = Signal()
|
rtio_tx_clk = Signal()
|
||||||
channel_interfaces = []
|
channel_interfaces = []
|
||||||
for i in range(nchannels):
|
for i in range(nchannels):
|
||||||
mode = "master" if i == master else "slave"
|
if nchannels == 1:
|
||||||
gth = GTHSingle(refclk, data_pads[i], sys_clk_freq, rtio_clk_freq, dw, mode)
|
mode = "single"
|
||||||
if mode == "master":
|
|
||||||
self.comb += rtio_tx_clk.eq(gth.cd_rtio_tx.clk)
|
|
||||||
else:
|
else:
|
||||||
|
mode = "master" if i == master else "slave"
|
||||||
|
gth = GTHSingle(plls[i], tx_pads[i], rx_pads[i], sys_clk_freq, dw, mode)
|
||||||
|
if mode == "slave":
|
||||||
self.comb += gth.cd_rtio_tx.clk.eq(rtio_tx_clk)
|
self.comb += gth.cd_rtio_tx.clk.eq(rtio_tx_clk)
|
||||||
|
else:
|
||||||
|
self.comb += rtio_tx_clk.eq(gth.cd_rtio_tx.clk)
|
||||||
self.gths.append(gth)
|
self.gths.append(gth)
|
||||||
setattr(self.submodules, "gth"+str(i), gth)
|
setattr(self.submodules, "gth"+str(i), gth)
|
||||||
channel_interface = ChannelInterface(gth.encoder, gth.decoders)
|
channel_interface = ChannelInterface(gth.encoder, gth.decoders)
|
||||||
self.comb += channel_interface.rx_ready.eq(gth.rx_ready)
|
self.comb += channel_interface.rx_ready.eq(gth.rx_ready)
|
||||||
channel_interfaces.append(channel_interface)
|
channel_interfaces.append(channel_interface)
|
||||||
|
|
||||||
|
self.submodules.tx_phase_alignment = GTHTXPhaseAlignement(self.gths)
|
||||||
|
|
||||||
TransceiverInterface.__init__(self, channel_interfaces)
|
TransceiverInterface.__init__(self, channel_interfaces)
|
||||||
# GTH PLLs recover on their own from an interrupted clock input.
|
# GTH PLLs recover on their own from an interrupted clock input.
|
||||||
# stable_clkin can be ignored.
|
# stable_clkin can be ignored.
|
||||||
|
|
Loading…
Reference in New Issue