forked from M-Labs/artiq
drtio/transceiver/gtp: implement tx multi lane phase alignment sequence
This commit is contained in:
parent
e565d3fa59
commit
1f0d955ce4
|
@ -13,8 +13,10 @@ from artiq.gateware.drtio.transceiver.gtp_7series_init import *
|
|||
|
||||
class GTPSingle(Module):
|
||||
def __init__(self, qpll_channel, pads, sys_clk_freq, rtio_clk_freq, mode):
|
||||
if mode != "master":
|
||||
raise NotImplementedError
|
||||
assert mode in ["single", "master", "slave"]
|
||||
self.mode = mode
|
||||
|
||||
# # #
|
||||
|
||||
self.stable_clkin = Signal()
|
||||
self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")(
|
||||
|
@ -31,10 +33,10 @@ class GTPSingle(Module):
|
|||
# # #
|
||||
|
||||
# TX generates RTIO clock, init must be in system domain
|
||||
tx_init = GTPTXInit(sys_clk_freq)
|
||||
self.submodules.tx_init = tx_init = GTPTXInit(sys_clk_freq, mode)
|
||||
# RX receives restart commands from RTIO domain
|
||||
rx_init = ClockDomainsRenamer("rtio_tx")(GTPRXInit(rtio_clk_freq))
|
||||
self.submodules += tx_init, rx_init
|
||||
self.submodules += rx_init
|
||||
|
||||
self.comb += [
|
||||
tx_init.stable_clkin.eq(self.stable_clkin),
|
||||
|
@ -353,7 +355,7 @@ class GTPSingle(Module):
|
|||
|
||||
# TX Buffer Attributes
|
||||
p_TXSYNC_MULTILANE =0b0,
|
||||
p_TXSYNC_OVRD =0b0,
|
||||
p_TXSYNC_OVRD =0b1,
|
||||
p_TXSYNC_SKIP_DA =0b0
|
||||
)
|
||||
gtp_params.update(
|
||||
|
@ -438,7 +440,7 @@ class GTPSingle(Module):
|
|||
#o_RXNOTINTABLE =,
|
||||
# Receive Ports - RX AFE Ports
|
||||
i_GTPRXN =pads.rxn,
|
||||
i_GTPRXP =pads.rxp,
|
||||
i_GTPRXP =pads.rxp,
|
||||
i_PMARSVDIN2 =0b0,
|
||||
#o_PMARSVDOUT0 =,
|
||||
#o_PMARSVDOUT1 =,
|
||||
|
@ -667,7 +669,7 @@ class GTPSingle(Module):
|
|||
tx_reset_deglitched.attr.add("no_retiming")
|
||||
self.sync += tx_reset_deglitched.eq(~tx_init.done)
|
||||
self.clock_domains.cd_rtio_tx = ClockDomain()
|
||||
if mode == "master":
|
||||
if mode == "master" or mode == "single":
|
||||
self.specials += Instance("BUFG", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk)
|
||||
self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched)
|
||||
|
||||
|
@ -698,30 +700,52 @@ class GTPSingle(Module):
|
|||
]
|
||||
|
||||
|
||||
class GTPTXPhaseAlignement(Module):
|
||||
# TX Buffer Bypass in Single-Lane/Multi-Lane Auto Mode (ug482)
|
||||
def __init__(self, gtps):
|
||||
master_phaligndone = Signal()
|
||||
slaves_phaligndone = Signal(reset=1)
|
||||
# Specific to Slave transceivers
|
||||
for gtp in gtps:
|
||||
if gtp.mode == "slave":
|
||||
self.comb += gtp.tx_init.master_phaligndone.eq(master_phaligndone)
|
||||
slaves_phaligndone = slaves_phaligndone & gtp.tx_init.done
|
||||
# Specific to Master transceivers
|
||||
for gtp in gtps:
|
||||
if gtp.mode == "master":
|
||||
self.comb += [
|
||||
master_phaligndone.eq(gtp.tx_init.master_phaligndone),
|
||||
gtp.tx_init.slaves_phaligndone.eq(slaves_phaligndone)
|
||||
]
|
||||
|
||||
|
||||
class GTP(Module, TransceiverInterface):
|
||||
def __init__(self, qpll_channel, data_pads, sys_clk_freq, rtio_clk_freq, master=0):
|
||||
self.nchannels = nchannels = len(data_pads)
|
||||
self.gtps = []
|
||||
if nchannels > 1:
|
||||
raise NotImplementedError
|
||||
|
||||
# # #
|
||||
|
||||
rtio_tx_clk = Signal()
|
||||
channel_interfaces = []
|
||||
for i in range(nchannels):
|
||||
mode = "master" if i == master else "slave"
|
||||
gtp = GTPSingle(qpll_channel, data_pads[i], sys_clk_freq, rtio_clk_freq, mode)
|
||||
if mode == "master":
|
||||
self.comb += rtio_tx_clk.eq(gtp.cd_rtio_tx.clk)
|
||||
if nchannels == 1:
|
||||
mode = "single"
|
||||
else:
|
||||
mode = "master" if i == master else "slave"
|
||||
gtp = GTPSingle(qpll_channel, data_pads[i], sys_clk_freq, rtio_clk_freq, mode)
|
||||
if mode == "slave":
|
||||
self.comb += gtp.cd_rtio_tx.clk.eq(rtio_tx_clk)
|
||||
else:
|
||||
self.comb += rtio_tx_clk.eq(gtp.cd_rtio_tx.clk)
|
||||
self.gtps.append(gtp)
|
||||
setattr(self.submodules, "gtp"+str(i), gtp)
|
||||
channel_interface = ChannelInterface(gtp.encoder, gtp.decoders)
|
||||
self.comb += channel_interface.rx_ready.eq(gtp.rx_ready)
|
||||
channel_interfaces.append(channel_interface)
|
||||
|
||||
self.submodules.tx_phase_alignment = GTPTXPhaseAlignement(self.gtps)
|
||||
|
||||
TransceiverInterface.__init__(self, channel_interfaces)
|
||||
for gtp in self.gtps:
|
||||
self.comb += gtp.stable_clkin.eq(self.stable_clkin.storage)
|
||||
|
|
|
@ -9,7 +9,7 @@ __all__ = ["GTPTXInit", "GTPRXInit"]
|
|||
|
||||
|
||||
class GTPTXInit(Module):
|
||||
def __init__(self, sys_clk_freq):
|
||||
def __init__(self, sys_clk_freq, mode="single"):
|
||||
self.stable_clkin = Signal()
|
||||
self.done = Signal()
|
||||
self.restart = Signal()
|
||||
|
@ -29,6 +29,9 @@ class GTPTXInit(Module):
|
|||
self.txdlyen = Signal()
|
||||
self.txuserrdy = Signal()
|
||||
|
||||
self.master_phaligndone = Signal()
|
||||
self.slaves_phaligndone = Signal()
|
||||
|
||||
# # #
|
||||
|
||||
# Double-latch transceiver asynch outputs
|
||||
|
@ -106,6 +109,16 @@ class GTPTXInit(Module):
|
|||
txuserrdy.eq(1),
|
||||
txdlysreset.eq(1),
|
||||
If(txdlysresetdone,
|
||||
If(mode == "slave",
|
||||
NextState("WAIT_MASTER")
|
||||
).Else(
|
||||
NextState("PHALIGN")
|
||||
)
|
||||
)
|
||||
)
|
||||
startup_fsm.act("WAIT_MASTER",
|
||||
txuserrdy.eq(1),
|
||||
If(self.master_phaligndone,
|
||||
NextState("PHALIGN")
|
||||
)
|
||||
)
|
||||
|
@ -117,16 +130,39 @@ class GTPTXInit(Module):
|
|||
NextState("WAIT_FIRST_ALIGN_DONE")
|
||||
)
|
||||
)
|
||||
# Wait 2 rising edges of Xxphaligndone
|
||||
# (from UG482 in TX Buffer Bypass in Single-Lane Auto Mode)
|
||||
# Wait N rising edges of Xxphaligndone
|
||||
# N=2 for Single, 3 for Master, 1 for Slave
|
||||
# (from UGB482 in TX Buffer Bypass in Multi/Single-Lane Auto Mode)
|
||||
startup_fsm.act("WAIT_FIRST_ALIGN_DONE",
|
||||
txuserrdy.eq(1),
|
||||
txphalign.eq(1),
|
||||
If(txphaligndone_rising,
|
||||
NextState("WAIT_SECOND_ALIGN_DONE")
|
||||
If(mode == "slave",
|
||||
NextState("READY")
|
||||
).Else(
|
||||
NextState("WAIT_SECOND_ALIGN_DONE")
|
||||
)
|
||||
)
|
||||
)
|
||||
startup_fsm.act("WAIT_SECOND_ALIGN_DONE",
|
||||
txuserrdy.eq(1),
|
||||
txdlyen.eq(1),
|
||||
If(txphaligndone_rising,
|
||||
If(mode == "master",
|
||||
NextState("WAIT_SLAVES")
|
||||
).Else(
|
||||
NextState("READY")
|
||||
)
|
||||
)
|
||||
)
|
||||
startup_fsm.act("WAIT_SLAVES",
|
||||
txuserrdy.eq(1),
|
||||
self.master_phaligndone.eq(1),
|
||||
If(self.slaves_phaligndone,
|
||||
NextState("WAIT_THIRD_ALIGN_DONE")
|
||||
)
|
||||
)
|
||||
startup_fsm.act("WAIT_THIRD_ALIGN_DONE",
|
||||
txuserrdy.eq(1),
|
||||
txdlyen.eq(1),
|
||||
If(txphaligndone_rising,
|
||||
|
|
Loading…
Reference in New Issue