Esempio n. 1
0
    def __init__(self, pll, pads, mode="master"):
        self.tx_k = Signal(4)
        self.tx_d = Signal(32)
        self.rx_k = Signal(4)
        self.rx_d = Signal(32)

        self.tx_idle = Signal()
        self.tx_comma = Signal()
        self.rx_idle = Signal()
        self.rx_comma = Signal()

        self.rx_bitslip_value = Signal(6)
        self.rx_delay_rst = Signal()
        self.rx_delay_inc = Signal()
        self.rx_delay_ce = Signal()

        # # #

        self.submodules.encoder = ClockDomainsRenamer("serwb_serdes")(Encoder(
            4, True))
        self.decoders = [
            ClockDomainsRenamer("serwb_serdes")(Decoder(True))
            for _ in range(4)
        ]
        self.submodules += self.decoders

        # clocking:

        # In master mode:
        # - linerate/10 pll refclk provided by user
        # - linerate/10 slave refclk generated on clk_pads
        # In Slave mode:
        # - linerate/10 pll refclk provided by clk_pads
        self.clock_domains.cd_serwb_serdes = ClockDomain()
        self.clock_domains.cd_serwb_serdes_5x = ClockDomain()
        self.clock_domains.cd_serwb_serdes_20x = ClockDomain(reset_less=True)
        self.comb += [
            self.cd_serwb_serdes.clk.eq(pll.serwb_serdes_clk),
            self.cd_serwb_serdes_5x.clk.eq(pll.serwb_serdes_5x_clk),
            self.cd_serwb_serdes_20x.clk.eq(pll.serwb_serdes_20x_clk)
        ]
        self.specials += AsyncResetSynchronizer(self.cd_serwb_serdes,
                                                ~pll.lock)
        self.comb += self.cd_serwb_serdes_5x.rst.eq(self.cd_serwb_serdes.rst)

        # control/status cdc
        tx_idle = Signal()
        tx_comma = Signal()
        rx_idle = Signal()
        rx_comma = Signal()
        rx_bitslip_value = Signal(6)
        self.specials += [
            MultiReg(self.tx_idle, tx_idle, "serwb_serdes"),
            MultiReg(self.tx_comma, tx_comma, "serwb_serdes"),
            MultiReg(rx_idle, self.rx_idle, "sys"),
            MultiReg(rx_comma, self.rx_comma, "sys")
        ]
        self.specials += MultiReg(self.rx_bitslip_value, rx_bitslip_value,
                                  "serwb_serdes"),

        # tx clock (linerate/10)
        if mode == "master":
            self.submodules.tx_clk_gearbox = Gearbox(40, "serwb_serdes", 8,
                                                     "serwb_serdes_5x")
            self.comb += self.tx_clk_gearbox.i.eq((0b1111100000 << 30)
                                                  | (0b1111100000 << 20)
                                                  | (0b1111100000 << 10)
                                                  | (0b1111100000 << 0))
            clk_o = Signal()
            self.specials += [
                Instance("OSERDESE2",
                         p_DATA_WIDTH=8,
                         p_TRISTATE_WIDTH=1,
                         p_DATA_RATE_OQ="DDR",
                         p_DATA_RATE_TQ="BUF",
                         p_SERDES_MODE="MASTER",
                         o_OQ=clk_o,
                         i_OCE=1,
                         i_RST=ResetSignal("serwb_serdes"),
                         i_CLK=ClockSignal("serwb_serdes_20x"),
                         i_CLKDIV=ClockSignal("serwb_serdes_5x"),
                         i_D1=self.tx_clk_gearbox.o[0],
                         i_D2=self.tx_clk_gearbox.o[1],
                         i_D3=self.tx_clk_gearbox.o[2],
                         i_D4=self.tx_clk_gearbox.o[3],
                         i_D5=self.tx_clk_gearbox.o[4],
                         i_D6=self.tx_clk_gearbox.o[5],
                         i_D7=self.tx_clk_gearbox.o[6],
                         i_D8=self.tx_clk_gearbox.o[7]),
                Instance("OBUFDS", i_I=clk_o, o_O=pads.clk_p, o_OB=pads.clk_n)
            ]

        # tx datapath
        # tx_data -> encoders -> gearbox -> serdes
        self.submodules.tx_gearbox = Gearbox(40, "serwb_serdes", 8,
                                             "serwb_serdes_5x")
        self.comb += [
            If(tx_comma, self.encoder.k[0].eq(1),
               self.encoder.d[0].eq(0xbc)).Else(
                   self.encoder.k[0].eq(self.tx_k[0]), self.encoder.k[1].eq(
                       self.tx_k[1]), self.encoder.k[2].eq(self.tx_k[2]),
                   self.encoder.k[3].eq(self.tx_k[3]),
                   self.encoder.d[0].eq(self.tx_d[0:8]),
                   self.encoder.d[1].eq(self.tx_d[8:16]),
                   self.encoder.d[2].eq(self.tx_d[16:24]),
                   self.encoder.d[3].eq(self.tx_d[24:32]))
        ]
        self.sync.serwb_serdes += \
            If(tx_idle,
                self.tx_gearbox.i.eq(0)
            ).Else(
                self.tx_gearbox.i.eq(Cat(*[self.encoder.output[i] for i in range(4)]))
            )

        serdes_o = Signal()
        self.specials += [
            Instance("OSERDESE2",
                     p_DATA_WIDTH=8,
                     p_TRISTATE_WIDTH=1,
                     p_DATA_RATE_OQ="DDR",
                     p_DATA_RATE_TQ="BUF",
                     p_SERDES_MODE="MASTER",
                     o_OQ=serdes_o,
                     i_OCE=1,
                     i_RST=ResetSignal("serwb_serdes"),
                     i_CLK=ClockSignal("serwb_serdes_20x"),
                     i_CLKDIV=ClockSignal("serwb_serdes_5x"),
                     i_D1=self.tx_gearbox.o[0],
                     i_D2=self.tx_gearbox.o[1],
                     i_D3=self.tx_gearbox.o[2],
                     i_D4=self.tx_gearbox.o[3],
                     i_D5=self.tx_gearbox.o[4],
                     i_D6=self.tx_gearbox.o[5],
                     i_D7=self.tx_gearbox.o[6],
                     i_D8=self.tx_gearbox.o[7]),
            Instance("OBUFDS", i_I=serdes_o, o_O=pads.tx_p, o_OB=pads.tx_n)
        ]

        # rx clock
        use_bufr = True
        if mode == "slave":
            clk_i = Signal()
            clk_i_bufg = Signal()
            self.specials += [
                Instance("IBUFDS", i_I=pads.clk_p, i_IB=pads.clk_n, o_O=clk_i)
            ]
            if use_bufr:
                clk_i_bufr = Signal()
                self.specials += [
                    Instance("BUFR", i_I=clk_i, o_O=clk_i_bufr),
                    Instance("BUFG", i_I=clk_i_bufr, o_O=clk_i_bufg)
                ]
            else:
                self.specials += Instance("BUFG", i_I=clk_i, o_O=clk_i_bufg)
            self.comb += pll.refclk.eq(clk_i_bufg)

        # rx datapath
        # serdes -> gearbox -> bitslip -> decoders -> rx_data
        self.submodules.rx_gearbox = Gearbox(8, "serwb_serdes_5x", 40,
                                             "serwb_serdes")
        self.submodules.rx_bitslip = ClockDomainsRenamer("serwb_serdes")(
            BitSlip(40))

        serdes_i_nodelay = Signal()
        self.specials += [
            Instance("IBUFDS_DIFF_OUT",
                     i_I=pads.rx_p,
                     i_IB=pads.rx_n,
                     o_O=serdes_i_nodelay)
        ]

        serdes_i_delayed = Signal()
        serdes_q = Signal(8)
        self.specials += [
            Instance("IDELAYE2",
                     p_DELAY_SRC="IDATAIN",
                     p_SIGNAL_PATTERN="DATA",
                     p_CINVCTRL_SEL="FALSE",
                     p_HIGH_PERFORMANCE_MODE="TRUE",
                     p_REFCLK_FREQUENCY=200.0,
                     p_PIPE_SEL="FALSE",
                     p_IDELAY_TYPE="VARIABLE",
                     p_IDELAY_VALUE=0,
                     i_C=ClockSignal(),
                     i_LD=self.rx_delay_rst,
                     i_CE=self.rx_delay_ce,
                     i_LDPIPEEN=0,
                     i_INC=self.rx_delay_inc,
                     i_IDATAIN=serdes_i_nodelay,
                     o_DATAOUT=serdes_i_delayed),
            Instance("ISERDESE2",
                     p_DATA_WIDTH=8,
                     p_DATA_RATE="DDR",
                     p_SERDES_MODE="MASTER",
                     p_INTERFACE_TYPE="NETWORKING",
                     p_NUM_CE=1,
                     p_IOBDELAY="IFD",
                     i_DDLY=serdes_i_delayed,
                     i_CE1=1,
                     i_RST=ResetSignal("serwb_serdes"),
                     i_CLK=ClockSignal("serwb_serdes_20x"),
                     i_CLKB=~ClockSignal("serwb_serdes_20x"),
                     i_CLKDIV=ClockSignal("serwb_serdes_5x"),
                     i_BITSLIP=0,
                     o_Q8=serdes_q[0],
                     o_Q7=serdes_q[1],
                     o_Q6=serdes_q[2],
                     o_Q5=serdes_q[3],
                     o_Q4=serdes_q[4],
                     o_Q3=serdes_q[5],
                     o_Q2=serdes_q[6],
                     o_Q1=serdes_q[7])
        ]

        self.comb += [
            self.rx_gearbox.i.eq(serdes_q),
            self.rx_bitslip.value.eq(rx_bitslip_value),
            self.rx_bitslip.i.eq(self.rx_gearbox.o),
            self.decoders[0].input.eq(self.rx_bitslip.o[0:10]),
            self.decoders[1].input.eq(self.rx_bitslip.o[10:20]),
            self.decoders[2].input.eq(self.rx_bitslip.o[20:30]),
            self.decoders[3].input.eq(self.rx_bitslip.o[30:40]),
            self.rx_k.eq(Cat(*[self.decoders[i].k for i in range(4)])),
            self.rx_d.eq(Cat(*[self.decoders[i].d for i in range(4)])),
            rx_idle.eq(self.rx_bitslip.o == 0),
            rx_comma.eq(
                ((self.decoders[0].d == 0xbc) & (self.decoders[0].k == 1))
                & ((self.decoders[1].d == 0x00) & (self.decoders[1].k == 0))
                & ((self.decoders[2].d == 0x00) & (self.decoders[2].k == 0))
                & ((self.decoders[3].d == 0x00) & (self.decoders[3].k == 0)))
        ]
Esempio n. 2
0
    def __init__(self, pll, pads, mode="master"):
        self.tx_k = Signal(4)
        self.tx_d = Signal(32)
        self.rx_k = Signal(4)
        self.rx_d = Signal(32)

        self.tx_idle = Signal()
        self.tx_comma = Signal()
        self.rx_idle = Signal()
        self.rx_comma = Signal()

        self.rx_bitslip_value = Signal(6)
        self.rx_delay_rst = Signal()
        self.rx_delay_inc = Signal()
        self.rx_delay_ce = Signal()
        self.rx_delay_en_vtc = Signal()

        # # #

        self.submodules.encoder = ClockDomainsRenamer("serwb_serdes")(
            Encoder(4, True))
        self.decoders = [ClockDomainsRenamer("serwb_serdes")(
            Decoder(True)) for _ in range(4)]
        self.submodules += self.decoders

        # clocking:

        # In master mode:
        # - linerate/10 pll refclk provided by user
        # - linerate/10 slave refclk generated on clk_pads
        # In Slave mode:
        # - linerate/10 pll refclk provided by clk_pads
        self.clock_domains.cd_serwb_serdes = ClockDomain()
        self.clock_domains.cd_serwb_serdes_5x = ClockDomain()
        self.clock_domains.cd_serwb_serdes_20x = ClockDomain(reset_less=True)
        self.comb += [
            self.cd_serwb_serdes.clk.eq(pll.serwb_serdes_clk),
            self.cd_serwb_serdes_5x.clk.eq(pll.serwb_serdes_5x_clk),
            self.cd_serwb_serdes_20x.clk.eq(pll.serwb_serdes_20x_clk)
        ]
        self.specials += AsyncResetSynchronizer(self.cd_serwb_serdes, ~pll.lock)
        self.comb += self.cd_serwb_serdes_5x.rst.eq(self.cd_serwb_serdes.rst)

        # control/status cdc
        tx_idle = Signal()
        tx_comma = Signal()
        rx_idle = Signal()
        rx_comma = Signal()
        rx_bitslip_value = Signal(6)
        rx_delay_rst = Signal()
        rx_delay_inc = Signal()
        rx_delay_en_vtc = Signal()
        rx_delay_ce = Signal()
        self.specials += [
            MultiReg(self.tx_idle, tx_idle, "serwb_serdes"),
            MultiReg(self.tx_comma, tx_comma, "serwb_serdes"),
            MultiReg(rx_idle, self.rx_idle, "sys"),
            MultiReg(rx_comma, self.rx_comma, "sys"),
            MultiReg(self.rx_bitslip_value, rx_bitslip_value, "serwb_serdes"),
            MultiReg(self.rx_delay_inc, rx_delay_inc, "serwb_serdes_5x"),
            MultiReg(self.rx_delay_en_vtc, rx_delay_en_vtc, "serwb_serdes_5x")
        ]
        self.submodules.do_rx_delay_rst = PulseSynchronizer("sys", "serwb_serdes_5x")
        self.comb += [
            rx_delay_rst.eq(self.do_rx_delay_rst.o),
            self.do_rx_delay_rst.i.eq(self.rx_delay_rst)
        ]
        self.submodules.do_rx_delay_ce = PulseSynchronizer("sys", "serwb_serdes_5x")
        self.comb += [
            rx_delay_ce.eq(self.do_rx_delay_ce.o),
            self.do_rx_delay_ce.i.eq(self.rx_delay_ce)
        ]

        # tx clock (linerate/10)
        if mode == "master":
            self.submodules.tx_clk_gearbox = Gearbox(40, "serwb_serdes", 8, "serwb_serdes_5x")
            self.comb += self.tx_clk_gearbox.i.eq((0b1111100000 << 30) |
                                                  (0b1111100000 << 20) |
                                                  (0b1111100000 << 10) |
                                                  (0b1111100000 <<  0))
            clk_o = Signal()
            self.specials += [
                Instance("OSERDESE3",
                    p_DATA_WIDTH=8, p_INIT=0,
                    p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0,

                    o_OQ=clk_o,
                    i_RST=ResetSignal("serwb_serdes"),
                    i_CLK=ClockSignal("serwb_serdes_20x"), i_CLKDIV=ClockSignal("serwb_serdes_5x"),
                    i_D=self.tx_clk_gearbox.o
                ),
                Instance("OBUFDS",
                    i_I=clk_o,
                    o_O=pads.clk_p,
                    o_OB=pads.clk_n
                )
            ]

        # tx datapath
        # tx_data -> encoders -> gearbox -> serdes
        self.submodules.tx_gearbox = Gearbox(40, "serwb_serdes", 8, "serwb_serdes_5x")
        self.comb += [
            If(tx_comma,
                self.encoder.k[0].eq(1),
                self.encoder.d[0].eq(0xbc)
            ).Else(
                self.encoder.k[0].eq(self.tx_k[0]),
                self.encoder.k[1].eq(self.tx_k[1]),
                self.encoder.k[2].eq(self.tx_k[2]),
                self.encoder.k[3].eq(self.tx_k[3]),
                self.encoder.d[0].eq(self.tx_d[0:8]),
                self.encoder.d[1].eq(self.tx_d[8:16]),
                self.encoder.d[2].eq(self.tx_d[16:24]),
                self.encoder.d[3].eq(self.tx_d[24:32])
            )
        ]
        self.sync.serwb_serdes += \
            If(tx_idle,
                self.tx_gearbox.i.eq(0)
            ).Else(
                self.tx_gearbox.i.eq(Cat(*[self.encoder.output[i] for i in range(4)]))
            )

        serdes_o = Signal()
        self.specials += [
            Instance("OSERDESE3",
                p_DATA_WIDTH=8, p_INIT=0,
                p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0,

                o_OQ=serdes_o,
                i_RST=ResetSignal("serwb_serdes"),
                i_CLK=ClockSignal("serwb_serdes_20x"), i_CLKDIV=ClockSignal("serwb_serdes_5x"),
                i_D=self.tx_gearbox.o
            ),
            Instance("OBUFDS",
                i_I=serdes_o,
                o_O=pads.tx_p,
                o_OB=pads.tx_n
            )
        ]

        # rx clock
        use_bufr = True
        if mode == "slave":
            clk_i = Signal()
            clk_i_bufg = Signal()
            self.specials += [
                Instance("IBUFDS",
                    i_I=pads.clk_p,
                    i_IB=pads.clk_n,
                    o_O=clk_i
                )
            ]
            if use_bufr:
                clk_i_bufr = Signal()
                self.specials += [
                    Instance("BUFR", i_I=clk_i, o_O=clk_i_bufr),
                    Instance("BUFG", i_I=clk_i_bufr, o_O=clk_i_bufg)
                ]
            else:
                self.specials += Instance("BUFG", i_I=clk_i, o_O=clk_i_bufg)
            self.comb += pll.refclk.eq(clk_i_bufg)

        # rx datapath
        # serdes -> gearbox -> bitslip -> decoders -> rx_data
        self.submodules.rx_gearbox = Gearbox(8, "serwb_serdes_5x", 40, "serwb_serdes")
        self.submodules.rx_bitslip = ClockDomainsRenamer("serwb_serdes")(BitSlip(40))

        serdes_i_nodelay = Signal()
        self.specials += [
            Instance("IBUFDS_DIFF_OUT",
                i_I=pads.rx_p,
                i_IB=pads.rx_n,
                o_O=serdes_i_nodelay
            )
        ]

        serdes_i_delayed = Signal()
        serdes_q = Signal(8)
        self.specials += [
            Instance("IDELAYE3",
                p_CASCADE="NONE", p_UPDATE_MODE="ASYNC", p_REFCLK_FREQUENCY=200.0,
                p_IS_CLK_INVERTED=0, p_IS_RST_INVERTED=0,
                p_DELAY_FORMAT="COUNT", p_DELAY_SRC="IDATAIN",
                p_DELAY_TYPE="VARIABLE", p_DELAY_VALUE=0,

                i_CLK=ClockSignal("serwb_serdes_5x"),
                i_RST=rx_delay_rst, i_LOAD=0,
                i_INC=rx_delay_inc, i_EN_VTC=rx_delay_en_vtc,
                i_CE=rx_delay_ce,

                i_IDATAIN=serdes_i_nodelay, o_DATAOUT=serdes_i_delayed
            ),
            Instance("ISERDESE3",
                p_IS_CLK_INVERTED=0,
                p_IS_CLK_B_INVERTED=1,
                p_DATA_WIDTH=8,

                i_D=serdes_i_delayed,
                i_RST=ResetSignal("serwb_serdes"),
                i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0,
                i_CLK=ClockSignal("serwb_serdes_20x"),
                i_CLK_B=ClockSignal("serwb_serdes_20x"), # locally inverted
                i_CLKDIV=ClockSignal("serwb_serdes_5x"),
                o_Q=serdes_q
            )
        ]

        self.comb += [
            self.rx_gearbox.i.eq(serdes_q),
            self.rx_bitslip.value.eq(rx_bitslip_value),
            self.rx_bitslip.i.eq(self.rx_gearbox.o),
            self.decoders[0].input.eq(self.rx_bitslip.o[0:10]),
            self.decoders[1].input.eq(self.rx_bitslip.o[10:20]),
            self.decoders[2].input.eq(self.rx_bitslip.o[20:30]),
            self.decoders[3].input.eq(self.rx_bitslip.o[30:40]),
            self.rx_k.eq(Cat(*[self.decoders[i].k for i in range(4)])),
            self.rx_d.eq(Cat(*[self.decoders[i].d for i in range(4)])),
            rx_idle.eq(self.rx_bitslip.o == 0),
            rx_comma.eq(((self.decoders[0].d == 0xbc) & (self.decoders[0].k == 1)) &
                        ((self.decoders[1].d == 0x00) & (self.decoders[1].k == 0)) &
                        ((self.decoders[2].d == 0x00) & (self.decoders[2].k == 0)) &
                        ((self.decoders[3].d == 0x00) & (self.decoders[3].k == 0)))

        ]
    def __init__(self, pll, pads, mode="master"):
        self.tx_pattern = CSRStorage(20)
        self.tx_produce_square_wave = CSRStorage()
        self.tx_prbs_config = CSRStorage(2)

        self.rx_pattern = CSRStatus(20)
        self.rx_prbs_config = CSRStorage(2)
        self.rx_prbs_errors = CSRStatus(32)

        self.rx_bitslip_value = CSRStorage(5)
        self.rx_delay_rst = CSR()
        self.rx_delay_en_vtc = CSRStorage(reset=1)
        self.rx_delay_inc = CSRStorage()
        self.rx_delay_ce = CSR()
        self.rx_delay_m_cntvalueout = CSRStatus(9)
        self.rx_delay_s_cntvalueout = CSRStatus(9)

        # # #

        self.submodules.encoder = ClockDomainsRenamer("serdes")(Encoder(
            2, True))
        self.decoders = [
            ClockDomainsRenamer("serdes")(Decoder(True)) for _ in range(2)
        ]
        self.submodules += self.decoders

        # clocking
        # master mode:
        # - linerate/10 pll refclk provided externally
        # - linerate/10 clock generated on clk_pads
        # slave mode:
        # - linerate/10 pll refclk provided by clk_pads
        self.clock_domains.cd_serdes = ClockDomain()
        self.clock_domains.cd_serdes_10x = ClockDomain()
        self.clock_domains.cd_serdes_10x_90 = ClockDomain()
        self.clock_domains.cd_serdes_2p5x = ClockDomain()
        self.comb += [
            self.cd_serdes.clk.eq(pll.serdes_clk),
            self.cd_serdes_10x.clk.eq(pll.serdes_10x_clk),
            self.cd_serdes_10x_90.clk.eq(pll.serdes_10x_90_clk),
            self.cd_serdes_2p5x.clk.eq(pll.serdes_2p5x_clk)
        ]
        self.specials += [
            AsyncResetSynchronizer(self.cd_serdes, ~pll.lock),
            AsyncResetSynchronizer(self.cd_serdes_10x, ~pll.lock),
            AsyncResetSynchronizer(self.cd_serdes_10x_90, ~pll.lock),
            AsyncResetSynchronizer(self.cd_serdes_2p5x, ~pll.lock)
        ]

        # control/status cdc
        tx_pattern = Signal(20)
        tx_produce_square_wave = Signal()
        tx_prbs_config = Signal(2)

        rx_pattern = Signal(20)
        rx_prbs_config = Signal(2)
        rx_prbs_errors = Signal(32)

        rx_bitslip_value = Signal(5)
        rx_delay_rst = Signal()
        rx_delay_inc = Signal()
        rx_delay_en_vtc = Signal()
        rx_delay_ce = Signal()
        rx_delay_m_cntvalueout = Signal(9)
        rx_delay_s_cntvalueout = Signal(9)

        self.specials += [
            MultiReg(self.tx_pattern.storage, tx_pattern, "serdes"),
            MultiReg(self.tx_produce_square_wave.storage,
                     tx_produce_square_wave, "serdes"),
            MultiReg(self.tx_prbs_config.storage, tx_prbs_config, "serdes")
        ]

        self.specials += [
            MultiReg(rx_pattern, self.rx_pattern.status, "sys"),
            MultiReg(self.rx_prbs_config.storage, rx_prbs_config, "serdes"),
            MultiReg(rx_prbs_errors, self.rx_prbs_errors.status,
                     "sys")  # FIXME
        ]

        self.specials += [
            MultiReg(self.rx_bitslip_value.storage, rx_bitslip_value,
                     "serdes"),
            MultiReg(self.rx_delay_inc.storage, rx_delay_inc, "serdes_2p5x"),
            MultiReg(self.rx_delay_en_vtc.storage, rx_delay_en_vtc,
                     "serdes_2p5x")
        ]
        self.submodules.do_rx_delay_rst = PulseSynchronizer(
            "sys", "serdes_2p5x")
        self.comb += [
            rx_delay_rst.eq(self.do_rx_delay_rst.o),
            self.do_rx_delay_rst.i.eq(self.rx_delay_rst.re)
        ]
        self.submodules.do_rx_delay_ce = PulseSynchronizer(
            "sys", "serdes_2p5x")
        self.comb += [
            rx_delay_ce.eq(self.do_rx_delay_ce.o),
            self.do_rx_delay_ce.i.eq(self.rx_delay_ce.re)
        ]
        self.specials += [
            MultiReg(rx_delay_m_cntvalueout,
                     self.rx_delay_m_cntvalueout.status, "sys"),
            MultiReg(rx_delay_s_cntvalueout,
                     self.rx_delay_s_cntvalueout.status, "sys"),
        ]

        # tx clock (linerate/10)
        if mode == "master":
            self.submodules.tx_clk_gearbox = Gearbox(20, "serdes", 8,
                                                     "serdes_2p5x")
            self.comb += self.tx_clk_gearbox.i.eq(0b11111000001111100000)

            clk_o = Signal()
            self.specials += [
                Instance("OSERDESE3",
                         p_DATA_WIDTH=8,
                         p_INIT=0,
                         p_IS_CLK_INVERTED=0,
                         p_IS_CLKDIV_INVERTED=0,
                         p_IS_RST_INVERTED=0,
                         o_OQ=clk_o,
                         i_RST=ResetSignal("serdes_2p5x"),
                         i_CLK=ClockSignal("serdes_10x"),
                         i_CLKDIV=ClockSignal("serdes_2p5x"),
                         i_D=self.tx_clk_gearbox.o),
                Instance("OBUFDS", i_I=clk_o, o_O=pads.clk_p, o_OB=pads.clk_n)
            ]

        # tx data and prbs
        self.submodules.tx_prbs = ClockDomainsRenamer("serdes")(PRBSTX(
            20, True))
        self.comb += self.tx_prbs.config.eq(tx_prbs_config)
        self.submodules.tx_gearbox = Gearbox(20, "serdes", 8, "serdes_2p5x")
        self.sync.serdes += [
            self.tx_prbs.i.eq(Cat(*[self.encoder.output[i]
                                    for i in range(2)])),
            If(tx_pattern != 0, self.tx_gearbox.i.eq(tx_pattern)).Elif(
                tx_produce_square_wave,
                # square wave @ linerate/20 for scope observation
                self.tx_gearbox.i.eq(0b11111111110000000000)).Else(
                    self.tx_gearbox.i.eq(self.tx_prbs.o))
        ]

        serdes_o = Signal()
        self.specials += [
            Instance("OSERDESE3",
                     p_DATA_WIDTH=8,
                     p_INIT=0,
                     p_IS_CLK_INVERTED=0,
                     p_IS_CLKDIV_INVERTED=0,
                     p_IS_RST_INVERTED=0,
                     o_OQ=serdes_o,
                     i_RST=ResetSignal("serdes_2p5x"),
                     i_CLK=ClockSignal("serdes_10x"),
                     i_CLKDIV=ClockSignal("serdes_2p5x"),
                     i_D=self.tx_gearbox.o),
            Instance("OBUFDS", i_I=serdes_o, o_O=pads.tx_p, o_OB=pads.tx_n)
        ]

        # rx clock
        use_bufr = True
        if mode == "slave":
            clk_i = Signal()
            clk_i_bufg = Signal()
            self.specials += [
                Instance("IBUFDS", i_I=pads.clk_p, i_IB=pads.clk_n, o_O=clk_i)
            ]
            if use_bufr:
                clk_i_bufr = Signal()
                self.specials += [
                    Instance("BUFR", i_I=clk_i, o_O=clk_i_bufr),
                    Instance("BUFG", i_I=clk_i_bufr, o_O=clk_i_bufg),
                ]
            else:
                self.specials += Instance("BUFG", i_I=clk_i, o_O=clk_i_bufg),
            self.comb += pll.refclk.eq(clk_i_bufg)

        # rx
        self.submodules.rx_gearbox = Gearbox(8, "serdes_2p5x", 20, "serdes")
        self.submodules.rx_bitslip = ClockDomainsRenamer("serdes")(BitSlip(20))

        self.submodules.phase_detector = ClockDomainsRenamer("serdes_2p5x")(
            PhaseDetector())

        # use 2 serdes for phase detection: 1 master/ 1 slave
        serdes_m_i_nodelay = Signal()
        serdes_s_i_nodelay = Signal()
        self.specials += [
            Instance(
                "IBUFDS_DIFF_OUT",
                i_I=pads.rx_p,
                i_IB=pads.rx_n,
                o_O=serdes_m_i_nodelay,
                o_OB=serdes_s_i_nodelay,
            )
        ]

        serdes_m_i_delayed = Signal()
        serdes_m_q = Signal(8)
        self.specials += [
            Instance(
                "IDELAYE3",
                p_CASCADE="NONE",
                p_UPDATE_MODE="ASYNC",
                p_REFCLK_FREQUENCY=200.0,
                p_IS_CLK_INVERTED=0,
                p_IS_RST_INVERTED=0,
                # Note: can't use TIME mode since not reloading DELAY_VALUE on rst...
                p_DELAY_FORMAT="COUNT",
                p_DELAY_SRC="IDATAIN",
                p_DELAY_TYPE="VARIABLE",
                p_DELAY_VALUE=50,  # 1/4 bit period (ambient temp)
                i_CLK=ClockSignal("serdes_2p5x"),
                i_RST=rx_delay_rst,
                i_LOAD=0,
                i_INC=rx_delay_inc,
                i_EN_VTC=rx_delay_en_vtc,
                i_CE=rx_delay_ce,
                i_IDATAIN=serdes_m_i_nodelay,
                o_DATAOUT=serdes_m_i_delayed,
                o_CNTVALUEOUT=rx_delay_m_cntvalueout),
            Instance("ISERDESE3",
                     p_DATA_WIDTH=8,
                     i_D=serdes_m_i_delayed,
                     i_RST=ResetSignal("serdes_2p5x"),
                     i_FIFO_RD_CLK=0,
                     i_FIFO_RD_EN=0,
                     i_CLK=ClockSignal("serdes_10x"),
                     i_CLK_B=~ClockSignal("serdes_10x"),
                     i_CLKDIV=ClockSignal("serdes_2p5x"),
                     o_Q=serdes_m_q),
        ]
        self.comb += self.phase_detector.mdata.eq(serdes_m_q)

        serdes_s_i_delayed = Signal()
        serdes_s_q = Signal(8)
        self.specials += [
            Instance(
                "IDELAYE3",
                p_CASCADE="NONE",
                p_UPDATE_MODE="ASYNC",
                p_REFCLK_FREQUENCY=200.0,
                p_IS_CLK_INVERTED=0,
                p_IS_RST_INVERTED=0,
                # Note: can't use TIME mode since not reloading DELAY_VALUE on rst...
                p_DELAY_FORMAT="COUNT",
                p_DELAY_SRC="IDATAIN",
                p_DELAY_TYPE="VARIABLE",
                p_DELAY_VALUE=100,  # 1/2 bit period (ambient temp)
                i_CLK=ClockSignal("serdes_2p5x"),
                i_RST=rx_delay_rst,
                i_LOAD=0,
                i_INC=rx_delay_inc,
                i_EN_VTC=rx_delay_en_vtc,
                i_CE=rx_delay_ce,
                i_IDATAIN=serdes_s_i_nodelay,
                o_DATAOUT=serdes_s_i_delayed,
                o_CNTVALUEOUT=rx_delay_s_cntvalueout),
            Instance("ISERDESE3",
                     p_DATA_WIDTH=8,
                     i_D=serdes_s_i_delayed,
                     i_RST=ResetSignal("serdes_2p5x"),
                     i_FIFO_RD_CLK=0,
                     i_FIFO_RD_EN=0,
                     i_CLK=ClockSignal("serdes_10x"),
                     i_CLK_B=~ClockSignal("serdes_10x"),
                     i_CLKDIV=ClockSignal("serdes_2p5x"),
                     o_Q=serdes_s_q),
        ]
        self.comb += self.phase_detector.sdata.eq(~serdes_s_q)

        # rx data and prbs
        self.submodules.rx_prbs = ClockDomainsRenamer("serdes")(PRBSRX(
            20, True))
        self.comb += [
            self.rx_prbs.config.eq(rx_prbs_config),
            rx_prbs_errors.eq(self.rx_prbs.errors)
        ]
        self.comb += [
            self.rx_gearbox.i.eq(serdes_m_q),
            self.rx_bitslip.value.eq(rx_bitslip_value),
            self.rx_bitslip.i.eq(self.rx_gearbox.o),
            self.decoders[0].input.eq(self.rx_bitslip.o[:10]),
            self.decoders[1].input.eq(self.rx_bitslip.o[10:]),
            rx_pattern.eq(self.rx_bitslip.o),
            self.rx_prbs.i.eq(self.rx_bitslip.o)
        ]
Esempio n. 4
0
 def __init__(self):
     self.submodules.gearbox_down = Gearbox(10, "user", 8, "gearbox")
     self.submodules.gearbox_up = Gearbox(8, "gearbox", 10, "user")
     self.comb += self.gearbox_up.i.eq(self.gearbox_down.o)
     self.i, self.o = self.gearbox_down.i, self.gearbox_up.o
Esempio n. 5
0
    def __init__(self, pad_p, pad_n, ntbits=8):
        self.d = Signal(10)

        self._dly_ctl = CSR(5)
        self._phase = CSRStatus(2)
        self._phase_reset = CSR()
        self._cntvalueout_m = CSRStatus(5)
        self._cntvalueout_s = CSRStatus(5)

        # # #

        # use 2 serdes for phase detection: master & slave
        serdes_m_i_nodelay = Signal()
        serdes_s_i_nodelay = Signal()
        self.specials += [
            Instance(
                "IBUFDS_DIFF_OUT",
                i_I=pad_p,
                i_IB=pad_n,
                o_O=serdes_m_i_nodelay,
                o_OB=serdes_s_i_nodelay,
            )
        ]

        delay_rst = Signal()
        delay_master_inc = Signal()
        delay_master_ce = Signal()
        delay_slave_inc = Signal()
        delay_slave_ce = Signal()

        # master serdes
        serdes_m_i_delayed = Signal()
        serdes_m_q = Signal(8)
        serdes_m_d = Signal(8)
        serdes_m_cntvalue = Signal(5)
        self.specials += [
            Instance("IDELAYE2",
                     p_DELAY_SRC="IDATAIN",
                     p_SIGNAL_PATTERN="DATA",
                     p_CINVCTRL_SEL="FALSE",
                     p_HIGH_PERFORMANCE_MODE="TRUE",
                     p_REFCLK_FREQUENCY=200.0,
                     p_PIPE_SEL="FALSE",
                     p_IDELAY_TYPE="VARIABLE",
                     p_IDELAY_VALUE=0,
                     i_C=ClockSignal("pix1p25x"),
                     i_LD=delay_rst,
                     i_CE=delay_master_ce,
                     i_LDPIPEEN=0,
                     i_INC=delay_master_inc,
                     i_IDATAIN=serdes_m_i_nodelay,
                     o_DATAOUT=serdes_m_i_delayed,
                     o_CNTVALUEOUT=serdes_m_cntvalue),
            Instance("ISERDESE2",
                     p_DATA_WIDTH=8,
                     p_DATA_RATE="DDR",
                     p_SERDES_MODE="MASTER",
                     p_INTERFACE_TYPE="NETWORKING",
                     p_NUM_CE=1,
                     p_IOBDELAY="IFD",
                     i_DDLY=serdes_m_i_delayed,
                     i_CE1=1,
                     i_RST=ResetSignal("pix1p25x"),
                     i_CLK=ClockSignal("pix5x"),
                     i_CLKB=~ClockSignal("pix5x"),
                     i_CLKDIV=ClockSignal("pix1p25x"),
                     i_BITSLIP=0,
                     o_Q8=serdes_m_q[0],
                     o_Q7=serdes_m_q[1],
                     o_Q6=serdes_m_q[2],
                     o_Q5=serdes_m_q[3],
                     o_Q4=serdes_m_q[4],
                     o_Q3=serdes_m_q[5],
                     o_Q2=serdes_m_q[6],
                     o_Q1=serdes_m_q[7]),
        ]

        # slave serdes
        # idelay_value must be preloaded with a 90° phase shift but we
        # do it dynamically by software to support all resolutions
        serdes_s_i_delayed = Signal()
        serdes_s_q = Signal(8)
        serdes_s_d = Signal(8)
        serdes_s_cntvalue = Signal(5)
        self.specials += [
            Instance("IDELAYE2",
                     p_DELAY_SRC="IDATAIN",
                     p_SIGNAL_PATTERN="DATA",
                     p_CINVCTRL_SEL="FALSE",
                     p_HIGH_PERFORMANCE_MODE="TRUE",
                     p_REFCLK_FREQUENCY=200.0,
                     p_PIPE_SEL="FALSE",
                     p_IDELAY_TYPE="VARIABLE",
                     p_IDELAY_VALUE=0,
                     i_C=ClockSignal("pix1p25x"),
                     i_LD=delay_rst,
                     i_CE=delay_slave_ce,
                     i_LDPIPEEN=0,
                     i_INC=delay_slave_inc,
                     i_IDATAIN=serdes_s_i_nodelay,
                     o_DATAOUT=serdes_s_i_delayed,
                     o_CNTVALUEOUT=serdes_s_cntvalue),
            Instance("ISERDESE2",
                     p_DATA_WIDTH=8,
                     p_DATA_RATE="DDR",
                     p_SERDES_MODE="MASTER",
                     p_INTERFACE_TYPE="NETWORKING",
                     p_NUM_CE=1,
                     p_IOBDELAY="IFD",
                     i_DDLY=serdes_s_i_delayed,
                     i_CE1=1,
                     i_RST=ResetSignal("pix1p25x"),
                     i_CLK=ClockSignal("pix5x"),
                     i_CLKB=~ClockSignal("pix5x"),
                     i_CLKDIV=ClockSignal("pix1p25x"),
                     i_BITSLIP=0,
                     o_Q8=serdes_s_q[0],
                     o_Q7=serdes_s_q[1],
                     o_Q6=serdes_s_q[2],
                     o_Q5=serdes_s_q[3],
                     o_Q4=serdes_s_q[4],
                     o_Q3=serdes_s_q[5],
                     o_Q2=serdes_s_q[6],
                     o_Q1=serdes_s_q[7]),
        ]

        # cntvalue sync
        self.submodules.sync_mcntvalue = BusSynchronizer(5, "pix1p25x", "sys")
        self.submodules.sync_scntvalue = BusSynchronizer(5, "pix1p25x", "sys")
        self.comb += [
            self.sync_mcntvalue.i.eq(serdes_m_cntvalue),
            self._cntvalueout_m.status.eq(self.sync_mcntvalue.o),
            self.sync_scntvalue.i.eq(serdes_s_cntvalue),
            self._cntvalueout_s.status.eq(self.sync_scntvalue.o),
        ]

        # polarity
        if hasattr(pad_p, "inverted"):
            self.comb += [
                serdes_m_d.eq(~serdes_m_q),
                serdes_s_d.eq(serdes_s_q)
            ]
        else:
            self.comb += [
                serdes_m_d.eq(serdes_m_q),
                serdes_s_d.eq(~serdes_s_q)
            ]

        # datapath
        self.submodules.gearbox = Gearbox(8, "pix1p25x", 10, "pix")
        self.comb += [self.gearbox.i.eq(serdes_m_d), self.d.eq(self.gearbox.o)]

        # phase detector
        self.submodules.phase_detector = ClockDomainsRenamer("pix1p25x")(
            S7PhaseDetector())
        self.comb += [
            self.phase_detector.mdata.eq(serdes_m_d),
            self.phase_detector.sdata.eq(serdes_s_d)
        ]

        # phase error accumulator
        lateness = Signal(ntbits, reset=2**(ntbits - 1))
        too_late = Signal()
        too_early = Signal()
        reset_lateness = Signal()
        self.comb += [
            too_late.eq(lateness == (2**ntbits - 1)),
            too_early.eq(lateness == 0)
        ]
        self.sync.pix1p25x += [
            If(reset_lateness, lateness.eq(2**(ntbits - 1))).Elif(
                ~too_late & ~too_early,
                If(self.phase_detector.dec, lateness.eq(lateness + 1)),
                If(self.phase_detector.inc, lateness.eq(lateness - 1)))
        ]

        # delay control
        self.submodules.do_delay_rst = PulseSynchronizer("sys", "pix1p25x")
        self.submodules.do_delay_master_inc = PulseSynchronizer(
            "sys", "pix1p25x")
        self.submodules.do_delay_master_dec = PulseSynchronizer(
            "sys", "pix1p25x")
        self.submodules.do_delay_slave_inc = PulseSynchronizer(
            "sys", "pix1p25x")
        self.submodules.do_delay_slave_dec = PulseSynchronizer(
            "sys", "pix1p25x")
        self.comb += [
            delay_rst.eq(self.do_delay_rst.o),
            delay_master_inc.eq(self.do_delay_master_inc.o),
            delay_master_ce.eq(self.do_delay_master_inc.o
                               | self.do_delay_master_dec.o),
            delay_slave_inc.eq(self.do_delay_slave_inc.o),
            delay_slave_ce.eq(self.do_delay_slave_inc.o
                              | self.do_delay_slave_dec.o)
        ]

        self.comb += [
            self.do_delay_rst.i.eq(self._dly_ctl.re & self._dly_ctl.r[0]),
            self.do_delay_master_inc.i.eq(self._dly_ctl.re
                                          & self._dly_ctl.r[1]),
            self.do_delay_master_dec.i.eq(self._dly_ctl.re
                                          & self._dly_ctl.r[2]),
            self.do_delay_slave_inc.i.eq(self._dly_ctl.re
                                         & self._dly_ctl.r[3]),
            self.do_delay_slave_dec.i.eq(self._dly_ctl.re & self._dly_ctl.r[4])
        ]

        # phase detector control
        self.specials += MultiReg(Cat(too_late, too_early), self._phase.status)
        self.submodules.do_reset_lateness = PulseSynchronizer(
            "sys", "pix1p25x")
        self.comb += [
            reset_lateness.eq(self.do_reset_lateness.o),
            self.do_reset_lateness.i.eq(self._phase_reset.re)
        ]
    def __init__(self, pll, pads, mode="master"):
        self.tx_pattern = CSRStorage(20)
        self.tx_produce_square_wave = CSRStorage()
        self.tx_prbs_config = CSRStorage(2)

        self.rx_pattern = CSRStatus(20)
        self.rx_prbs_config = CSRStorage(2)
        self.rx_prbs_errors = CSRStatus(32)

        self.rx_bitslip_value = CSRStorage(5)
        self.rx_delay_rst = CSR()
        self.rx_delay_inc = CSRStorage()
        self.rx_delay_ce = CSR()

        # # #

        self.submodules.encoder = ClockDomainsRenamer("serdes")(Encoder(
            2, True))
        self.decoders = [
            ClockDomainsRenamer("serdes")(Decoder(True)) for _ in range(2)
        ]
        self.submodules += self.decoders

        # clocking
        # master mode:
        # - linerate/10 pll refclk provided externally
        # - linerate/10 clock generated on clk_pads
        # slave mode:
        # - linerate/10 pll refclk provided by clk_pads
        self.clock_domains.cd_serdes = ClockDomain()
        self.clock_domains.cd_serdes_10x = ClockDomain()
        self.clock_domains.cd_serdes_2p5x = ClockDomain()
        self.comb += [
            self.cd_serdes.clk.eq(pll.serdes_clk),
            self.cd_serdes_10x.clk.eq(pll.serdes_10x_clk),
            self.cd_serdes_2p5x.clk.eq(pll.serdes_2p5x_clk)
        ]
        self.specials += [
            AsyncResetSynchronizer(self.cd_serdes, ~pll.lock),
            AsyncResetSynchronizer(self.cd_serdes_10x, ~pll.lock),
            AsyncResetSynchronizer(self.cd_serdes_2p5x, ~pll.lock)
        ]

        # control/status cdc
        tx_pattern = Signal(20)
        tx_produce_square_wave = Signal()
        tx_prbs_config = Signal(2)

        rx_pattern = Signal(20)
        rx_prbs_config = Signal(2)
        rx_prbs_errors = Signal(32)

        rx_bitslip_value = Signal(5)

        self.specials += [
            MultiReg(self.tx_pattern.storage, tx_pattern, "serdes"),
            MultiReg(self.tx_produce_square_wave.storage,
                     tx_produce_square_wave, "serdes"),
            MultiReg(self.tx_prbs_config.storage, tx_prbs_config, "serdes"),
        ]

        self.specials += [
            MultiReg(rx_pattern, self.rx_pattern.status, "sys"),
            MultiReg(self.rx_prbs_config.storage, rx_prbs_config, "serdes"),
            MultiReg(rx_prbs_errors, self.rx_prbs_errors.status,
                     "sys"),  # FIXME
        ]

        self.specials += MultiReg(self.rx_bitslip_value.storage,
                                  rx_bitslip_value, "serdes"),

        # tx clock (linerate/10)
        if mode == "master":
            self.submodules.tx_clk_gearbox = Gearbox(20, "serdes", 8,
                                                     "serdes_2p5x")
            self.comb += self.tx_clk_gearbox.i.eq(0b11111000001111100000)

            clk_o = Signal()
            self.specials += [
                Instance("OSERDESE2",
                         p_DATA_WIDTH=8,
                         p_TRISTATE_WIDTH=1,
                         p_DATA_RATE_OQ="DDR",
                         p_DATA_RATE_TQ="BUF",
                         p_SERDES_MODE="MASTER",
                         o_OQ=clk_o,
                         i_OCE=1,
                         i_RST=ResetSignal("serdes_2p5x"),
                         i_CLK=ClockSignal("serdes_10x"),
                         i_CLKDIV=ClockSignal("serdes_2p5x"),
                         i_D1=self.tx_clk_gearbox.o[0],
                         i_D2=self.tx_clk_gearbox.o[1],
                         i_D3=self.tx_clk_gearbox.o[2],
                         i_D4=self.tx_clk_gearbox.o[3],
                         i_D5=self.tx_clk_gearbox.o[4],
                         i_D6=self.tx_clk_gearbox.o[5],
                         i_D7=self.tx_clk_gearbox.o[6],
                         i_D8=self.tx_clk_gearbox.o[7]),
                Instance("OBUFDS", i_I=clk_o, o_O=pads.clk_p, o_OB=pads.clk_n)
            ]

        # tx data and prbs
        self.submodules.tx_prbs = ClockDomainsRenamer("serdes")(PRBSTX(
            20, True))
        self.comb += self.tx_prbs.config.eq(tx_prbs_config)
        self.submodules.tx_gearbox = Gearbox(20, "serdes", 8, "serdes_2p5x")
        self.sync.serdes += [
            self.tx_prbs.i.eq(Cat(*[self.encoder.output[i]
                                    for i in range(2)])),
            If(tx_pattern != 0, self.tx_gearbox.i.eq(tx_pattern)).Elif(
                tx_produce_square_wave,
                # square wave @ linerate/20 for scope observation
                self.tx_gearbox.i.eq(0b11111111110000000000)).Else(
                    self.tx_gearbox.i.eq(self.tx_prbs.o))
        ]

        serdes_o = Signal()
        self.specials += [
            Instance("OSERDESE2",
                     p_DATA_WIDTH=8,
                     p_TRISTATE_WIDTH=1,
                     p_DATA_RATE_OQ="DDR",
                     p_DATA_RATE_TQ="BUF",
                     p_SERDES_MODE="MASTER",
                     o_OQ=serdes_o,
                     i_OCE=1,
                     i_RST=ResetSignal("serdes_2p5x"),
                     i_CLK=ClockSignal("serdes_10x"),
                     i_CLKDIV=ClockSignal("serdes_2p5x"),
                     i_D1=self.tx_gearbox.o[0],
                     i_D2=self.tx_gearbox.o[1],
                     i_D3=self.tx_gearbox.o[2],
                     i_D4=self.tx_gearbox.o[3],
                     i_D5=self.tx_gearbox.o[4],
                     i_D6=self.tx_gearbox.o[5],
                     i_D7=self.tx_gearbox.o[6],
                     i_D8=self.tx_gearbox.o[7]),
            Instance("OBUFDS", i_I=serdes_o, o_O=pads.tx_p, o_OB=pads.tx_n)
        ]

        # rx clock
        use_bufr = False
        if mode == "slave":
            clk_i = Signal()

            clk_i_bufg = Signal()
            self.specials += [
                Instance("IBUFDS", i_I=pads.clk_p, i_IB=pads.clk_n, o_O=clk_i)
            ]
            if use_bufr:
                clk_i_bufr = Signal()
                self.specials += [
                    Instance("BUFR", i_I=clk_i, o_O=clk_i_bufr),
                    Instance("BUFG", i_I=clk_i_bufr, o_O=clk_i_bufg),
                ]
            else:
                self.specials += Instance("BUFG", i_I=clk_i, o_O=clk_i_bufg),
            self.comb += pll.refclk.eq(clk_i_bufg)

        # rx
        self.submodules.rx_gearbox = Gearbox(8, "serdes_2p5x", 20, "serdes")
        self.submodules.rx_bitslip = ClockDomainsRenamer("serdes")(BitSlip(20))

        self.submodules.phase_detector = ClockDomainsRenamer("serdes_2p5x")(
            PhaseDetector())

        # use 2 serdes for phase detection: 1 master/ 1 slave
        serdes_m_i_nodelay = Signal()
        serdes_s_i_nodelay = Signal()
        self.specials += [
            Instance(
                "IBUFDS_DIFF_OUT",
                i_I=pads.rx_p,
                i_IB=pads.rx_n,
                o_O=serdes_m_i_nodelay,
                o_OB=serdes_s_i_nodelay,
            )
        ]

        serdes_m_i_delayed = Signal()
        serdes_m_q = Signal(8)
        serdes_m_idelay_value = int(1 / (4 * pll.linerate) /
                                    78e-12)  # 1/4 bit period
        assert serdes_m_idelay_value < 32
        self.specials += [
            Instance("IDELAYE2",
                     p_DELAY_SRC="IDATAIN",
                     p_SIGNAL_PATTERN="DATA",
                     p_CINVCTRL_SEL="FALSE",
                     p_HIGH_PERFORMANCE_MODE="TRUE",
                     p_REFCLK_FREQUENCY=200.0,
                     p_PIPE_SEL="FALSE",
                     p_IDELAY_TYPE="VARIABLE",
                     p_IDELAY_VALUE=serdes_m_idelay_value,
                     i_C=ClockSignal(),
                     i_LD=self.rx_delay_rst.re,
                     i_CE=self.rx_delay_ce.re,
                     i_LDPIPEEN=0,
                     i_INC=self.rx_delay_inc.storage,
                     i_IDATAIN=serdes_m_i_nodelay,
                     o_DATAOUT=serdes_m_i_delayed),
            Instance("ISERDESE2",
                     p_DATA_WIDTH=8,
                     p_DATA_RATE="DDR",
                     p_SERDES_MODE="MASTER",
                     p_INTERFACE_TYPE="NETWORKING",
                     p_NUM_CE=1,
                     p_IOBDELAY="IFD",
                     i_DDLY=serdes_m_i_delayed,
                     i_CE1=1,
                     i_RST=ResetSignal("serdes_2p5x"),
                     i_CLK=ClockSignal("serdes_10x"),
                     i_CLKB=~ClockSignal("serdes_10x"),
                     i_CLKDIV=ClockSignal("serdes_2p5x"),
                     i_BITSLIP=0,
                     o_Q8=serdes_m_q[0],
                     o_Q7=serdes_m_q[1],
                     o_Q6=serdes_m_q[2],
                     o_Q5=serdes_m_q[3],
                     o_Q4=serdes_m_q[4],
                     o_Q3=serdes_m_q[5],
                     o_Q2=serdes_m_q[6],
                     o_Q1=serdes_m_q[7]),
        ]
        self.comb += self.phase_detector.mdata.eq(serdes_m_q)

        serdes_s_i_delayed = Signal()
        serdes_s_q = Signal(8)
        serdes_s_idelay_value = int(1 / (2 * pll.linerate) /
                                    78e-12)  # 1/2 bit period
        assert serdes_s_idelay_value < 32
        self.specials += [
            Instance("IDELAYE2",
                     p_DELAY_SRC="IDATAIN",
                     p_SIGNAL_PATTERN="DATA",
                     p_CINVCTRL_SEL="FALSE",
                     p_HIGH_PERFORMANCE_MODE="TRUE",
                     p_REFCLK_FREQUENCY=200.0,
                     p_PIPE_SEL="FALSE",
                     p_IDELAY_TYPE="VARIABLE",
                     p_IDELAY_VALUE=serdes_s_idelay_value,
                     i_C=ClockSignal(),
                     i_LD=self.rx_delay_rst.re,
                     i_CE=self.rx_delay_ce.re,
                     i_LDPIPEEN=0,
                     i_INC=self.rx_delay_inc.storage,
                     i_IDATAIN=serdes_s_i_nodelay,
                     o_DATAOUT=serdes_s_i_delayed),
            Instance("ISERDESE2",
                     p_DATA_WIDTH=8,
                     p_DATA_RATE="DDR",
                     p_SERDES_MODE="MASTER",
                     p_INTERFACE_TYPE="NETWORKING",
                     p_NUM_CE=1,
                     p_IOBDELAY="IFD",
                     i_DDLY=serdes_s_i_delayed,
                     i_CE1=1,
                     i_RST=ResetSignal("serdes_2p5x"),
                     i_CLK=ClockSignal("serdes_10x"),
                     i_CLKB=~ClockSignal("serdes_10x"),
                     i_CLKDIV=ClockSignal("serdes_2p5x"),
                     i_BITSLIP=0,
                     o_Q8=serdes_s_q[0],
                     o_Q7=serdes_s_q[1],
                     o_Q6=serdes_s_q[2],
                     o_Q5=serdes_s_q[3],
                     o_Q4=serdes_s_q[4],
                     o_Q3=serdes_s_q[5],
                     o_Q2=serdes_s_q[6],
                     o_Q1=serdes_s_q[7]),
        ]
        self.comb += self.phase_detector.sdata.eq(~serdes_s_q)

        # rx data and prbs
        self.submodules.rx_prbs = ClockDomainsRenamer("serdes")(PRBSRX(
            20, True))
        self.comb += [
            self.rx_prbs.config.eq(rx_prbs_config),
            rx_prbs_errors.eq(self.rx_prbs.errors)
        ]
        self.comb += [
            self.rx_gearbox.i.eq(serdes_m_q),
            self.rx_bitslip.value.eq(rx_bitslip_value),
            self.rx_bitslip.i.eq(self.rx_gearbox.o),
            rx_pattern.eq(self.rx_gearbox.o),
            self.decoders[0].input.eq(self.rx_bitslip.o[:10]),
            self.decoders[1].input.eq(self.rx_bitslip.o[10:]),
            self.rx_prbs.i.eq(self.rx_bitslip.o)
        ]