def __init__(self, clock_pads, data_pads, sys_clk_freq, rtio_clk_freq, dw=20, master=0): self.nchannels = nchannels = len(data_pads) self.gths = [] # # # refclk = Signal() self.specials += Instance("IBUFDS_GTE3", i_CEB=0, i_I=clock_pads.p, i_IB=clock_pads.n, o_O=refclk) rtio_tx_clk = Signal() channel_interfaces = [] for i in range(nchannels): if nchannels == 1: mode = "single" else: mode = "master" if i == master else "slave" gth = GTHSingle(refclk, data_pads[i], sys_clk_freq, rtio_clk_freq, dw, mode) if mode == "master": self.comb += rtio_tx_clk.eq(gth.cd_rtio_tx.clk) elif mode == "slave": self.comb += gth.cd_rtio_tx.clk.eq(rtio_tx_clk) self.gths.append(gth) setattr(self.submodules, "gth" + str(i), gth) channel_interface = ChannelInterface(gth.encoder, gth.decoders) self.comb += channel_interface.rx_ready.eq(gth.rx_ready) channel_interfaces.append(channel_interface) self.submodules.tx_phase_alignment = GTHTXPhaseAlignement(self.gths) TransceiverInterface.__init__(self, channel_interfaces) # GTH PLLs recover on their own from an interrupted clock input. # stable_clkin can be ignored. self.comb += [ self.cd_rtio.clk.eq(self.gths[master].cd_rtio_tx.clk), self.cd_rtio.rst.eq( reduce(or_, [gth.cd_rtio_tx.rst for gth in self.gths])) ] for i in range(nchannels): self.comb += [ getattr(self, "cd_rtio_rx" + str(i)).clk.eq( self.gths[i].cd_rtio_rx.clk), getattr(self, "cd_rtio_rx" + str(i)).rst.eq( self.gths[i].cd_rtio_rx.rst) ]
def __init__(self, clock_pads, data_pads, sys_clk_freq, rtio_clk_freq, rtiox_mul=2, dw=20, master=0): self.nchannels = nchannels = len(data_pads) self.gths = [] # # # create_buf = hasattr(clock_pads, "p") if create_buf: refclk = Signal() ibufds_ceb = Signal() self.specials += Instance("IBUFDS_GTE3", i_CEB=ibufds_ceb, i_I=clock_pads.p, i_IB=clock_pads.n, o_O=refclk) else: refclk = clock_pads rtio_tx_clk = Signal() channel_interfaces = [] for i in range(nchannels): if nchannels == 1: mode = "single" else: mode = "master" if i == master else "slave" gth = GTHSingle(refclk, data_pads[i], sys_clk_freq, rtio_clk_freq, rtiox_mul, dw, mode) if mode == "master": self.comb += rtio_tx_clk.eq(gth.cd_rtio_tx.clk) elif mode == "slave": self.comb += gth.cd_rtio_tx.clk.eq(rtio_tx_clk) self.gths.append(gth) setattr(self.submodules, "gth"+str(i), gth) channel_interface = ChannelInterface(gth.encoder, gth.decoders) self.comb += channel_interface.rx_ready.eq(gth.rx_ready) channel_interfaces.append(channel_interface) self.submodules.tx_phase_alignment = GTHTXPhaseAlignement(self.gths) TransceiverInterface.__init__(self, channel_interfaces) self.clock_domains.cd_rtiox = ClockDomain(reset_less=True) if create_buf: # GTH PLLs recover on their own from an interrupted clock input, # but be paranoid about HMC7043 noise. self.stable_clkin.storage.attr.add("no_retiming") self.comb += ibufds_ceb.eq(~self.stable_clkin.storage) self.comb += [ self.cd_rtio.clk.eq(self.gths[master].cd_rtio_tx.clk), self.cd_rtiox.clk.eq(self.gths[master].cd_rtiox_tx.clk), self.cd_rtio.rst.eq(reduce(or_, [gth.cd_rtio_tx.rst for gth in self.gths])) ] for i in range(nchannels): self.comb += [ getattr(self, "cd_rtio_rx" + str(i)).clk.eq(self.gths[i].cd_rtio_rx.clk), getattr(self, "cd_rtio_rx" + str(i)).rst.eq(self.gths[i].cd_rtio_rx.rst) ]
def __init__(self, qpll_channel, data_pads, sys_clk_freq, rtio_clk_freq, master=0): self.nchannels = nchannels = len(data_pads) self.gtps = [] # # # rtio_tx_clk = Signal() channel_interfaces = [] for i in range(nchannels): 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 n, gtp in enumerate(self.gtps): self.comb += [ gtp.stable_clkin.eq(self.stable_clkin.storage), gtp.txenable.eq(self.txenable.storage[n]) ] self.comb += [ self.cd_rtio.clk.eq(self.gtps[master].cd_rtio_tx.clk), self.cd_rtio.rst.eq( reduce(or_, [gtp.cd_rtio_tx.rst for gtp in self.gtps])) ] for i in range(nchannels): self.comb += [ getattr(self, "cd_rtio_rx" + str(i)).clk.eq( self.gtps[i].cd_rtio_rx.clk), getattr(self, "cd_rtio_rx" + str(i)).rst.eq( self.gtps[i].cd_rtio_rx.rst) ]
def __init__(self, clock_pads, data_pads, sys_clk_freq, rtio_clk_freq, dw=20, master=0): self.nchannels = nchannels = len(data_pads) self.gths = [] # # # refclk = Signal() self.specials += Instance("IBUFDS_GTE3", i_CEB=0, i_I=clock_pads.p, i_IB=clock_pads.n, o_O=refclk) rtio_tx_clk = Signal() channel_interfaces = [] for i in range(nchannels): mode = "master" if i == master else "slave" gth = GTHSingle(refclk, data_pads[i], sys_clk_freq, rtio_clk_freq, dw, mode) if mode == "master": self.comb += rtio_tx_clk.eq(gth.cd_rtio_tx.clk) else: self.comb += gth.cd_rtio_tx.clk.eq(rtio_tx_clk) self.gths.append(gth) setattr(self.submodules, "gth" + str(i), gth) channel_interface = ChannelInterface(gth.encoder, gth.decoders) self.comb += channel_interface.rx_ready.eq(gth.rx_ready) channel_interfaces.append(channel_interface) TransceiverInterface.__init__(self, channel_interfaces) self.comb += [ self.cd_rtio.clk.eq(self.gths[master].cd_rtio_tx.clk), self.cd_rtio.rst.eq( reduce(or_, [gth.cd_rtio_tx.rst for gth in self.gths])) ] for i in range(nchannels): self.comb += [ getattr(self, "cd_rtio_rx" + str(i)).clk.eq( self.gths[i].cd_rtio_rx.clk), getattr(self, "cd_rtio_rx" + str(i)).rst.eq( self.gths[i].cd_rtio_rx.rst) ]
def __init__(self, clock_pads, pads, sys_clk_freq, rtio_clk_freq=125e6, master=0): self.nchannels = nchannels = len(pads) self.gtxs = [] self.rtio_clk_freq = rtio_clk_freq # # # refclk = Signal() stable_clkin_n = Signal() self.specials += Instance("IBUFDS_GTE2", i_CEB=stable_clkin_n, i_I=clock_pads.p, i_IB=clock_pads.n, o_O=refclk, p_CLKCM_CFG="0b1", p_CLKRCV_TRST="0b1", p_CLKSWING_CFG="0b11") rtio_tx_clk = Signal() channel_interfaces = [] for i in range(nchannels): if nchannels == 1: mode = "single" else: mode = "master" if i == master else "slave" # Note: RX phase alignment is to be done on individual lanes, not multi-lane. gtx = GTX_20X(refclk, pads[i], sys_clk_freq, rtio_clk_freq=rtio_clk_freq, tx_mode=mode, rx_mode="single") # Fan-out (to slave) / Fan-in (from master) of the TXUSRCLK if mode == "slave": self.comb += gtx.cd_rtio_tx.clk.eq(rtio_tx_clk) else: self.comb += rtio_tx_clk.eq(gtx.cd_rtio_tx.clk) self.gtxs.append(gtx) setattr(self.submodules, "gtx" + str(i), gtx) channel_interface = ChannelInterface(gtx.encoder, gtx.decoders) self.comb += channel_interface.rx_ready.eq(gtx.rx_ready) channel_interfaces.append(channel_interface) self.submodules.tx_phase_alignment = GTXInitPhaseAlignment( [gtx.tx_init for gtx in self.gtxs]) TransceiverInterface.__init__(self, channel_interfaces) for n, gtx in enumerate(self.gtxs): self.comb += [ stable_clkin_n.eq(~self.stable_clkin.storage), gtx.txenable.eq(self.txenable.storage[n]) ] # Connect master's `rtio_tx` clock to `rtio` clock self.comb += [ self.cd_rtio.clk.eq(self.gtxs[master].cd_rtio_tx.clk), self.cd_rtio.rst.eq( reduce(or_, [gtx.cd_rtio_tx.rst for gtx in self.gtxs])) ] # Connect slave i's `rtio_rx` clock to `rtio_rxi` clock for i in range(nchannels): self.comb += [ getattr(self, "cd_rtio_rx" + str(i)).clk.eq( self.gtxs[i].cd_rtio_rx.clk), getattr(self, "cd_rtio_rx" + str(i)).rst.eq( self.gtxs[i].cd_rtio_rx.rst) ]
def __init__(self, clock_pads, tx_pads, rx_pads, sys_clk_freq, clock_div2=False): encoder = ClockDomainsRenamer("rtio")( Encoder(2, True)) self.submodules += encoder decoders = [ClockDomainsRenamer("rtio_rx0")( (Decoder(True))) for _ in range(2)] self.submodules += decoders TransceiverInterface.__init__(self, [ChannelInterface(encoder, decoders)]) # transceiver direct clock outputs # useful to specify clock constraints in a way palatable to Vivado self.txoutclk = Signal() self.rxoutclk = Signal() # # # refclk = Signal() if clock_div2: self.specials += Instance("IBUFDS_GTE2", i_CEB=0, i_I=clock_pads.p, i_IB=clock_pads.n, o_ODIV2=refclk ) else: self.specials += Instance("IBUFDS_GTE2", i_CEB=0, i_I=clock_pads.p, i_IB=clock_pads.n, o_O=refclk ) cplllock = Signal() # TX generates RTIO clock, init must be in system domain tx_init = GTXInit(sys_clk_freq, False) # RX receives restart commands from RTIO domain rx_init = ClockDomainsRenamer("rtio")( GTXInit(self.rtio_clk_freq, True)) self.submodules += tx_init, rx_init self.comb += tx_init.cplllock.eq(cplllock), \ rx_init.cplllock.eq(cplllock) txdata = Signal(20) rxdata = Signal(20) self.specials += \ Instance("GTXE2_CHANNEL", # PMA Attributes p_PMA_RSV=0x00018480, p_PMA_RSV2=0x2050, p_PMA_RSV3=0, p_PMA_RSV4=0, p_RX_BIAS_CFG=0b100, p_RX_CM_TRIM=0b010, p_RX_OS_CFG=0b10000000, p_RX_CLK25_DIV=5, p_TX_CLK25_DIV=5, # Power-Down Attributes p_PD_TRANS_TIME_FROM_P2=0x3c, p_PD_TRANS_TIME_NONE_P2=0x3c, p_PD_TRANS_TIME_TO_P2=0x64, # CPLL p_CPLL_CFG=0xBC07DC, p_CPLL_FBDIV=4, p_CPLL_FBDIV_45=5, p_CPLL_REFCLK_DIV=1, p_RXOUT_DIV=2, p_TXOUT_DIV=2, o_CPLLLOCK=cplllock, i_CPLLLOCKEN=1, i_CPLLREFCLKSEL=0b001, i_TSTIN=2**20-1, i_GTREFCLK0=refclk, # TX clock p_TXBUF_EN="FALSE", p_TX_XCLK_SEL="TXUSR", o_TXOUTCLK=self.txoutclk, i_TXSYSCLKSEL=0b00, i_TXOUTCLKSEL=0b11, # TX Startup/Reset i_GTTXRESET=tx_init.gtXxreset, o_TXRESETDONE=tx_init.Xxresetdone, i_TXDLYSRESET=tx_init.Xxdlysreset, o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone, o_TXPHALIGNDONE=tx_init.Xxphaligndone, i_TXUSERRDY=tx_init.Xxuserrdy, # TX data p_TX_DATA_WIDTH=20, p_TX_INT_DATAWIDTH=0, i_TXCHARDISPMODE=Cat(txdata[9], txdata[19]), i_TXCHARDISPVAL=Cat(txdata[8], txdata[18]), i_TXDATA=Cat(txdata[:8], txdata[10:18]), i_TXUSRCLK=ClockSignal("rtio"), i_TXUSRCLK2=ClockSignal("rtio"), # TX electrical i_TXBUFDIFFCTRL=0b100, i_TXDIFFCTRL=0b1000, # RX Startup/Reset i_GTRXRESET=rx_init.gtXxreset, o_RXRESETDONE=rx_init.Xxresetdone, i_RXDLYSRESET=rx_init.Xxdlysreset, o_RXDLYSRESETDONE=rx_init.Xxdlysresetdone, o_RXPHALIGNDONE=rx_init.Xxphaligndone, i_RXUSERRDY=rx_init.Xxuserrdy, # RX AFE p_RX_DFE_XYD_CFG=0, i_RXDFEXYDEN=1, i_RXDFEXYDHOLD=0, i_RXDFEXYDOVRDEN=0, i_RXLPMEN=0, # RX clock p_RXBUF_EN="FALSE", p_RX_XCLK_SEL="RXUSR", i_RXDDIEN=1, i_RXSYSCLKSEL=0b00, i_RXOUTCLKSEL=0b010, o_RXOUTCLK=self.rxoutclk, i_RXUSRCLK=ClockSignal("rtio_rx0"), i_RXUSRCLK2=ClockSignal("rtio_rx0"), p_RXCDR_CFG=0x03000023FF10100020, # RX Clock Correction Attributes p_CLK_CORRECT_USE="FALSE", p_CLK_COR_SEQ_1_1=0b0100000000, p_CLK_COR_SEQ_2_1=0b0100000000, p_CLK_COR_SEQ_1_ENABLE=0b1111, p_CLK_COR_SEQ_2_ENABLE=0b1111, # RX data p_RX_DATA_WIDTH=20, p_RX_INT_DATAWIDTH=0, o_RXDISPERR=Cat(rxdata[9], rxdata[19]), o_RXCHARISK=Cat(rxdata[8], rxdata[18]), o_RXDATA=Cat(rxdata[:8], rxdata[10:18]), # Pads i_GTXRXP=rx_pads.p, i_GTXRXN=rx_pads.n, o_GTXTXP=tx_pads.p, o_GTXTXN=tx_pads.n, ) tx_reset_deglitched = Signal() tx_reset_deglitched.attr.add("no_retiming") self.sync += tx_reset_deglitched.eq(~tx_init.done) self.specials += [ Instance("BUFG", i_I=self.txoutclk, o_O=self.cd_rtio.clk), AsyncResetSynchronizer(self.cd_rtio, tx_reset_deglitched) ] rx_reset_deglitched = Signal() rx_reset_deglitched.attr.add("no_retiming") self.sync.rtio += rx_reset_deglitched.eq(~rx_init.done) self.specials += [ Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rtio_rx0.clk), AsyncResetSynchronizer(self.cd_rtio_rx0, rx_reset_deglitched) ] chan = self.channels[0] self.comb += [ txdata.eq(Cat(chan.encoder.output[0], chan.encoder.output[1])), chan.decoders[0].input.eq(rxdata[:10]), chan.decoders[1].input.eq(rxdata[10:]) ] clock_aligner = ClockDomainsRenamer({"rtio_rx": "rtio_rx0"})( BruteforceClockAligner(0b0101111100, self.rtio_clk_freq)) self.submodules += clock_aligner self.comb += [ clock_aligner.rxdata.eq(rxdata), rx_init.restart.eq(clock_aligner.restart), chan.rx_ready.eq(clock_aligner.ready) ]