Beispiel #1
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.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)
            ]
Beispiel #2
0
    def __init__(self, clock_pads, data_pads, sys_clk_freq, rtio_clk_freq, rtiox_mul=2, dw=20, master=0):
        self.nchannels = nchannels = len(data_pads)
        self.gths = []

        # # #

        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)
            ]
Beispiel #3
0
    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)
            ]
Beispiel #4
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.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)
            ]
Beispiel #5
0
    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)
            ]
Beispiel #6
0
    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)
        ]