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))) ]
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) ]
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
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) ]