def __init__(self, pll, tx_pads, rx_pads, dual=0, channel=0, data_width=20, tx_polarity=0, rx_polarity=0): assert (data_width == 20) assert dual in [0, 1] assert channel in [0, 1] self.dual = dual self.channel = channel # TX controls self.tx_enable = Signal(reset=1) self.tx_ready = Signal() self.tx_inhibit = Signal() # FIXME self.tx_produce_square_wave = Signal() self.tx_produce_pattern = Signal() self.tx_pattern = Signal(data_width) self.tx_prbs_config = Signal(2) self.tx_idle = Signal() # RX controls self.rx_enable = Signal(reset=1) self.rx_ready = Signal() self.rx_align = Signal(reset=1) self.rx_prbs_config = Signal(2) self.rx_prbs_errors = Signal(32) self.rx_idle = Signal() # Loopback self.loopback = Signal( ) # FIXME: reconfigure lb_ctl to 0b0001 but does not seem enough # # # self.nwords = nwords = data_width // 10 self.submodules.encoder = ClockDomainsRenamer("tx")(Encoder( nwords, True)) self.submodules.decoders = [ ClockDomainsRenamer("rx")(Decoder(True)) for _ in range(nwords) ] # Transceiver direct clock outputs (useful to specify clock constraints) self.txoutclk = Signal() self.rxoutclk = Signal() self.tx_clk_freq = pll.config["linerate"] / data_width self.rx_clk_freq = pll.config["linerate"] / data_width # Internal signals ------------------------------------------------------------------------- rx_los = Signal() rx_lol = Signal() rx_lsm = Signal() rx_align = Signal() rx_data = Signal(20) rx_bus = Signal(24) tx_lol = Signal() tx_data = Signal(20) tx_bus = Signal(24) # Control/Status CDC ----------------------------------------------------------------------- tx_produce_square_wave = Signal() tx_produce_pattern = Signal() tx_pattern = Signal(20) tx_prbs_config = Signal(2) rx_prbs_config = Signal(2) rx_prbs_errors = Signal(32) self.specials += [ MultiReg(self.tx_produce_square_wave, tx_produce_square_wave, "tx"), MultiReg(self.tx_produce_pattern, tx_produce_pattern, "tx"), MultiReg(self.tx_pattern, tx_pattern, "tx"), MultiReg(self.tx_prbs_config, tx_prbs_config, "tx"), ] self.specials += [ MultiReg(self.rx_align, rx_align, "rx"), MultiReg(self.rx_prbs_config, rx_prbs_config, "rx"), MultiReg(rx_los, self.rx_idle, "sys"), MultiReg(rx_prbs_errors, self.rx_prbs_errors, "sys"), # FIXME ] # Clocking --------------------------------------------------------------------------------- self.clock_domains.cd_tx = ClockDomain() self.comb += self.cd_tx.clk.eq(self.txoutclk) self.specials += AsyncResetSynchronizer(self.cd_tx, ResetSignal("sys")) self.specials += MultiReg(~self.cd_tx.rst, self.tx_ready) self.clock_domains.cd_rx = ClockDomain() self.comb += self.cd_rx.clk.eq(self.rxoutclk) self.specials += AsyncResetSynchronizer(self.cd_rx, ResetSignal("sys")) self.specials += MultiReg(~self.cd_rx.rst, self.rx_ready) # DCU init --------------------------------------------------------------------------------- self.submodules.rx_init = rx_init = SerdesRXInit( tx_lol, rx_lol, rx_los, rx_lsm) # DCU instance ----------------------------------------------------------------------------- self.serdes_params = dict( # ECP5's DCU parameters/signals/instance have been documented by whitequark as part of # Yumewatari project: https://github.com/whitequark/Yumewatari # Copyright (C) 2018 [email protected] # DCU ---------------------------------------------------------------------------------- # DCU — power management p_D_MACROPDB="0b1", p_D_IB_PWDNB="0b1", # undocumented (required for RX) p_D_TXPLL_PWDNB="0b1", i_D_FFC_MACROPDB=1, # DCU — reset i_D_FFC_MACRO_RST=ResetSignal("sys"), i_D_FFC_DUAL_RST=ResetSignal("sys"), # DCU — clocking i_D_REFCLKI=pll.refclk, o_D_FFS_PLOL=tx_lol, p_D_REFCK_MODE={ 25: "0b100", 20: "0b000", 16: "0b010", 10: "0b001", 8: "0b011" }[pll.config["mult"]], p_D_TX_MAX_RATE="5.0", # 5.0 Gbps p_D_TX_VCO_CK_DIV={ 32: "0b111", 16: "0b110", 8: "0b101", 4: "0b100", 2: "0b010", 1: "0b000" }[1], # DIV/1 p_D_BITCLK_LOCAL_EN="0b1", # Use clock from local PLL # DCU — unknown p_D_CMUSETBIASI= "0b00", # begin undocumented (10BSER sample code used) p_D_CMUSETI4CPP="0d3", p_D_CMUSETI4CPZ="0d3", p_D_CMUSETI4VCO="0b00", p_D_CMUSETICP4P="0b01", p_D_CMUSETICP4Z="0b101", p_D_CMUSETINITVCT="0b00", p_D_CMUSETISCL4VCO="0b000", p_D_CMUSETP1GM="0b000", p_D_CMUSETP2AGM="0b000", p_D_CMUSETZGM="0b000", p_D_SETIRPOLY_AUX="0b01", p_D_SETICONST_AUX="0b01", p_D_SETIRPOLY_CH="0b01", p_D_SETICONST_CH="0b10", p_D_SETPLLRC="0d1", p_D_RG_EN="0b0", p_D_RG_SET="0b00", p_D_REQ_ISET="0b011", p_D_PD_ISET="0b11", # end undocumented # DCU — FIFOs p_D_LOW_MARK= "0d4", # Clock compensation FIFO low water mark (mean=8) p_D_HIGH_MARK= "0d12", # Clock compensation FIFO high water mark (mean=8) # CHX common --------------------------------------------------------------------------- # CHX — protocol p_CHX_PROTOCOL="10BSER", p_CHX_UC_MODE="0b1", p_CHX_ENC_BYPASS="******", # Bypass 8b10b encoder p_CHX_DEC_BYPASS="******", # Bypass 8b10b encoder # CHX receive -------------------------------------------------------------------------- # CHX RX — power management p_CHX_RPWDNB="0b1", i_CHX_FFC_RXPWDNB=1, # CHX RX — reset i_CHX_FFC_RRST=~self.rx_enable | rx_init.rrst, i_CHX_FFC_LANE_RX_RST=~self.rx_enable | rx_init.lane_rx_rst, # CHX RX — input i_CHX_HDINP=rx_pads.p, i_CHX_HDINN=rx_pads.n, p_CHX_REQ_EN="0b0", # Enable equalizer p_CHX_RX_RATE_SEL="0d10", # Equalizer pole position p_CHX_RTERM_RX={ "5k-ohms": "0b00000", "80-ohms": "0b00001", "75-ohms": "0b00100", "70-ohms": "0b00110", "60-ohms": "0b01011", "50-ohms": "0b10011", "46-ohms": "0b11001" }["50-ohms"], p_CHX_RXIN_CM="0b11", # CMFB (wizard value used) p_CHX_RXTERM_CM="0b11", # RX Input (wizard value used) # CHX RX — clocking i_CHX_RX_REFCLK=pll.refclk, o_CHX_FF_RX_PCLK=self.rxoutclk, i_CHX_FF_RXI_CLK=ClockSignal("rx"), p_CHX_CDR_MAX_RATE="5.0", # 5.0 Gbps p_CHX_RX_DCO_CK_DIV={ 32: "0b111", 16: "0b110", 8: "0b101", 4: "0b100", 2: "0b010", 1: "0b000" }[1], # DIV/1 p_CHX_RX_GEAR_MODE="0b1", # 1:2 gearbox p_CHX_FF_RX_H_CLK_EN="0b1", # enable DIV/2 output clock p_CHX_FF_RX_F_CLK_DIS="0b1", # disable DIV/1 output clock p_CHX_SEL_SD_RX_CLK="0b1", # FIFO driven by recovered clock p_CHX_AUTO_FACQ_EN="0b1", # undocumented (wizard value used) p_CHX_AUTO_CALIB_EN="0b1", # undocumented (wizard value used) p_CHX_PDEN_SEL="0b1", # phase detector disabled on LOS p_CHX_DCOATDCFG="0b00", # begin undocumented (sample code used) p_CHX_DCOATDDLY="0b00", p_CHX_DCOBYPSATD="0b1", p_CHX_DCOCALDIV="0b000", p_CHX_DCOCTLGI="0b011", p_CHX_DCODISBDAVOID="0b0", p_CHX_DCOFLTDAC="0b00", p_CHX_DCOFTNRG="0b001", p_CHX_DCOIOSTUNE="0b010", p_CHX_DCOITUNE="0b00", p_CHX_DCOITUNE4LSB="0b010", p_CHX_DCOIUPDNX2="0b1", p_CHX_DCONUOFLSB="0b100", p_CHX_DCOSCALEI="0b01", p_CHX_DCOSTARTVAL="0b010", p_CHX_DCOSTEP="0b11", # end undocumented # CHX RX — loss of signal o_CHX_FFS_RLOS=rx_los, p_CHX_RLOS_SEL="0b1", p_CHX_RX_LOS_EN="0b1", p_CHX_RX_LOS_LVL="0b100", # Lattice "TBD" (wizard value used) p_CHX_RX_LOS_CEQ="0b11", # Lattice "TBD" (wizard value used) # CHX RX — loss of lock o_CHX_FFS_RLOL=rx_lol, # CHx_RXLSM? CHx_RXWA? # CHX RX — link state machine i_CHX_FFC_SIGNAL_DETECT=rx_align, o_CHX_FFS_LS_SYNC_STATUS=rx_lsm, p_CHX_ENABLE_CG_ALIGN="0b1", p_CHX_UDF_COMMA_MASK="0x0ff", # compare the 8 lsbs p_CHX_UDF_COMMA_A="0b0000000011", # K28.1, K28.5 and K28.7 p_CHX_UDF_COMMA_B="0b0001111100", # K28.1, K28.5 and K28.7 p_CHX_CTC_BYPASS="******", # bypass CTC FIFO p_CHX_MIN_IPG_CNT="0b11", # minimum interpacket gap of 4 p_CHX_MATCH_2_ENABLE="0b0", # 2 character skip matching p_CHX_MATCH_4_ENABLE="0b0", # 4 character skip matching p_CHX_CC_MATCH_1="0x000", p_CHX_CC_MATCH_2="0x000", p_CHX_CC_MATCH_3="0x000", p_CHX_CC_MATCH_4="0x000", # CHX RX — data **{"o_CHX_FF_RX_D_%d" % n: rx_bus[n] for n in range(rx_bus.nbits)}, # CHX transmit ------------------------------------------------------------------------- # CHX TX — power management p_CHX_TPWDNB="0b1", i_CHX_FFC_TXPWDNB=1, # CHX TX — reset i_D_FFC_TRST=~self.tx_enable, i_CHX_FFC_LANE_TX_RST=~self.tx_enable, # CHX TX — output o_CHX_HDOUTP=tx_pads.p, o_CHX_HDOUTN=tx_pads.n, p_CHX_TXAMPLITUDE="0d1000", # 1000 mV p_CHX_RTERM_TX={ "5k-ohms": "0b00000", "80-ohms": "0b00001", "75-ohms": "0b00100", "70-ohms": "0b00110", "60-ohms": "0b01011", "50-ohms": "0b10011", "46-ohms": "0b11001" }["50-ohms"], p_CHX_TDRV_SLICE0_CUR="0b011", # 400 uA p_CHX_TDRV_SLICE0_SEL="0b01", # main data p_CHX_TDRV_SLICE1_CUR="0b000", # 100 uA p_CHX_TDRV_SLICE1_SEL="0b00", # power down p_CHX_TDRV_SLICE2_CUR="0b11", # 3200 uA p_CHX_TDRV_SLICE2_SEL="0b01", # main data p_CHX_TDRV_SLICE3_CUR="0b10", # 2400 uA p_CHX_TDRV_SLICE3_SEL="0b01", # main data p_CHX_TDRV_SLICE4_CUR="0b00", # 800 uA p_CHX_TDRV_SLICE4_SEL="0b00", # power down p_CHX_TDRV_SLICE5_CUR="0b00", # 800 uA p_CHX_TDRV_SLICE5_SEL="0b00", # power down # CHX TX — clocking o_CHX_FF_TX_PCLK=self.txoutclk, i_CHX_FF_TXI_CLK=ClockSignal("tx"), p_CHX_TX_GEAR_MODE="0b1", # 1:2 gearbox p_CHX_FF_TX_H_CLK_EN="0b1", # enable DIV/2 output clock p_CHX_FF_TX_F_CLK_DIS="0b1", # disable DIV/1 output clock # CHX TX — data **{"i_CHX_FF_TX_D_%d" % n: tx_bus[n] for n in range(tx_bus.nbits)}) # SCI Reconfiguration ---------------------------------------------------------------------- sci_reconfig = SerDesECP5SCIReconfig(self) self.submodules.sci_reconfig = sci_reconfig self.comb += sci_reconfig.loopback.eq(self.loopback) self.comb += sci_reconfig.tx_idle.eq(self.tx_idle) self.comb += sci_reconfig.rx_polarity.eq(rx_polarity) self.comb += sci_reconfig.tx_polarity.eq(tx_polarity) # TX Datapath and PRBS --------------------------------------------------------------------- self.submodules.tx_prbs = ClockDomainsRenamer("tx")(PRBSTX( data_width, True)) self.comb += self.tx_prbs.config.eq(tx_prbs_config) self.comb += [ self.tx_prbs.i.eq( Cat(*[self.encoder.output[i] for i in range(nwords)])), If( tx_produce_square_wave, # square wave @ linerate/data_width for scope observation tx_data.eq( Signal(data_width, reset=(1 << (data_width // 2)) - 1) )).Elif(tx_produce_pattern, tx_data.eq(tx_pattern)).Else( tx_data.eq(self.tx_prbs.o)), tx_bus[0:10].eq(tx_data[0:10]), tx_bus[12:22].eq(tx_data[10:20]), ] # RX Datapath and PRBS --------------------------------------------------------------------- self.submodules.rx_prbs = ClockDomainsRenamer("rx")(PRBSRX( data_width, True)) self.comb += [ self.rx_prbs.config.eq(rx_prbs_config), rx_prbs_errors.eq(self.rx_prbs.errors), rx_data[0:10].eq(rx_bus[0:10]), rx_data[10:20].eq(rx_bus[12:22]), ] for i in range(nwords): self.sync.rx += self.decoders[i].input.eq(rx_data[10 * i:10 * (i + 1)]) self.comb += self.rx_prbs.i.eq(rx_data)
def __init__(self, pll, tx_pads, rx_pads, sys_clk_freq, data_width=20, tx_buffer_enable=False, rx_buffer_enable=False, clock_aligner=True, clock_aligner_comma=0b0101111100, tx_polarity=0, rx_polarity=0): assert (data_width == 20) or (data_width == 40) # TX controls self.tx_enable = Signal() self.tx_ready = Signal() self.tx_inhibit = Signal() self.tx_produce_square_wave = Signal() self.tx_produce_pattern = Signal() self.tx_pattern = Signal(data_width) self.tx_prbs_config = Signal(2) # RX controls self.rx_enable = Signal() self.rx_ready = Signal() self.rx_align = Signal(reset=1) self.rx_prbs_config = Signal(2) self.rx_prbs_errors = Signal(32) # DRP self.drp = DRPInterface() # Loopback self.loopback = Signal(3) # # # use_cpll = isinstance(pll, GTHChannelPLL) use_qpll0 = isinstance(pll, GTHQuadPLL) and pll.config["qpll"] == "qpll0" use_qpll1 = isinstance(pll, GTHQuadPLL) and pll.config["qpll"] == "qpll1" self.nwords = nwords = data_width // 10 self.submodules.encoder = ClockDomainsRenamer("tx")(Encoder( nwords, True)) self.decoders = [ ClockDomainsRenamer("rx")(Decoder(True)) for _ in range(nwords) ] self.submodules += self.decoders # Transceiver direct clock outputs (useful to specify clock constraints) self.txoutclk = Signal() self.rxoutclk = Signal() self.tx_clk_freq = pll.config["linerate"] / data_width self.rx_clk_freq = pll.config["linerate"] / data_width # Control/Status CDC tx_produce_square_wave = Signal() tx_produce_pattern = Signal() tx_prbs_config = Signal(2) rx_prbs_config = Signal(2) rx_prbs_errors = Signal(32) self.specials += [ MultiReg(self.tx_produce_square_wave, tx_produce_square_wave, "tx"), MultiReg(self.tx_produce_pattern, tx_produce_pattern, "tx"), MultiReg(self.tx_prbs_config, tx_prbs_config, "tx"), ] self.specials += [ MultiReg(self.rx_prbs_config, rx_prbs_config, "rx"), MultiReg(rx_prbs_errors, self.rx_prbs_errors, "sys"), # FIXME ] # # # # TX init ---------------------------------------------------------------------------------- self.submodules.tx_init = tx_init = GTHTXInit(sys_clk_freq) self.comb += [ self.tx_ready.eq(tx_init.done), tx_init.restart.eq(~self.tx_enable) ] # RX init ---------------------------------------------------------------------------------- self.submodules.rx_init = rx_init = GTHRXInit(self.tx_clk_freq) self.comb += [ self.rx_ready.eq(rx_init.done), rx_init.restart.eq(~self.rx_enable) ] # PLL ---------------------------------------------------------------------------------- self.comb += [ tx_init.plllock.eq(pll.lock), rx_init.plllock.eq(pll.lock), pll.reset.eq(tx_init.pllreset) ] # DRP mux ---------------------------------------------------------------------------------- self.submodules.drp_mux = drp_mux = DRPMux() drp_mux.add_interface(self.drp) # GTHE3_CHANNEL instance ------------------------------------------------------------------- txdata = Signal(data_width) rxdata = Signal(data_width) rxphaligndone = Signal() self.gth_params = dict( p_ACJTAG_DEBUG_MODE=0b0, p_ACJTAG_MODE=0b0, p_ACJTAG_RESET=0b0, p_ADAPT_CFG0=0b1111100000000000, p_ADAPT_CFG1=0b0000000000000000, p_ALIGN_COMMA_DOUBLE="FALSE", p_ALIGN_COMMA_ENABLE=0b0000000000, p_ALIGN_COMMA_WORD=1, p_ALIGN_MCOMMA_DET="FALSE", p_ALIGN_MCOMMA_VALUE=0b1010000011, p_ALIGN_PCOMMA_DET="FALSE", p_ALIGN_PCOMMA_VALUE=0b0101111100, p_A_RXOSCALRESET=0b0, p_A_RXPROGDIVRESET=0b0, p_A_TXPROGDIVRESET=0b0, p_CBCC_DATA_SOURCE_SEL="ENCODED", p_CDR_SWAP_MODE_EN=0b0, p_CHAN_BOND_KEEP_ALIGN="FALSE", p_CHAN_BOND_MAX_SKEW=1, p_CHAN_BOND_SEQ_1_1=0b0000000000, p_CHAN_BOND_SEQ_1_2=0b0000000000, p_CHAN_BOND_SEQ_1_3=0b0000000000, p_CHAN_BOND_SEQ_1_4=0b0000000000, p_CHAN_BOND_SEQ_1_ENABLE=0b1111, p_CHAN_BOND_SEQ_2_1=0b0000000000, p_CHAN_BOND_SEQ_2_2=0b0000000000, p_CHAN_BOND_SEQ_2_3=0b0000000000, p_CHAN_BOND_SEQ_2_4=0b0000000000, p_CHAN_BOND_SEQ_2_ENABLE=0b1111, p_CHAN_BOND_SEQ_2_USE="FALSE", p_CHAN_BOND_SEQ_LEN=1, p_CLK_CORRECT_USE="FALSE", p_CLK_COR_KEEP_IDLE="FALSE", p_CLK_COR_MAX_LAT=12 if rx_buffer_enable else 20, p_CLK_COR_MIN_LAT=8 if rx_buffer_enable else 18, p_CLK_COR_PRECEDENCE="TRUE", p_CLK_COR_REPEAT_WAIT=0, p_CLK_COR_SEQ_1_1=0b0000000000, p_CLK_COR_SEQ_1_2=0b0000000000, p_CLK_COR_SEQ_1_3=0b0000000000, p_CLK_COR_SEQ_1_4=0b0000000000, p_CLK_COR_SEQ_1_ENABLE=0b1111, p_CLK_COR_SEQ_2_1=0b0000000000, p_CLK_COR_SEQ_2_2=0b0000000000, p_CLK_COR_SEQ_2_3=0b0000000000, p_CLK_COR_SEQ_2_4=0b0000000000, p_CLK_COR_SEQ_2_ENABLE=0b1111, p_CLK_COR_SEQ_2_USE="FALSE", p_CLK_COR_SEQ_LEN=1, p_CPLL_CFG0=0b0110011111111000, p_CPLL_CFG1=0b1010010010101100, p_CPLL_CFG2=0b0000000000000111, p_CPLL_CFG3=0b000000, p_CPLL_FBDIV=1 if (use_qpll0 | use_qpll1) else pll.config["n2"], p_CPLL_FBDIV_45=4 if (use_qpll0 | use_qpll1) else pll.config["n1"], p_CPLL_INIT_CFG0=0b0000001010110010, p_CPLL_INIT_CFG1=0b00000000, p_CPLL_LOCK_CFG=0b0000000111101000, p_CPLL_REFCLK_DIV=1 if (use_qpll0 | use_qpll1) else pll.config["m"], p_DDI_CTRL=0b00, p_DDI_REALIGN_WAIT=15, p_DEC_MCOMMA_DETECT="FALSE", p_DEC_PCOMMA_DETECT="FALSE", p_DEC_VALID_COMMA_ONLY="FALSE", p_DFE_D_X_REL_POS=0b0, p_DFE_VCM_COMP_EN=0b0, p_DMONITOR_CFG0=0b0000000000, p_DMONITOR_CFG1=0b00000000, p_ES_CLK_PHASE_SEL=0b0, p_ES_CONTROL=0b000000, p_ES_ERRDET_EN="FALSE", p_ES_EYE_SCAN_EN="FALSE", p_ES_HORZ_OFFSET=0b000000000000, p_ES_PMA_CFG=0b0000000000, p_ES_PRESCALE=0b00000, p_ES_QUALIFIER0=0b0000000000000000, p_ES_QUALIFIER1=0b0000000000000000, p_ES_QUALIFIER2=0b0000000000000000, p_ES_QUALIFIER3=0b0000000000000000, p_ES_QUALIFIER4=0b0000000000000000, p_ES_QUAL_MASK0=0b0000000000000000, p_ES_QUAL_MASK1=0b0000000000000000, p_ES_QUAL_MASK2=0b0000000000000000, p_ES_QUAL_MASK3=0b0000000000000000, p_ES_QUAL_MASK4=0b0000000000000000, p_ES_SDATA_MASK0=0b0000000000000000, p_ES_SDATA_MASK1=0b0000000000000000, p_ES_SDATA_MASK2=0b0000000000000000, p_ES_SDATA_MASK3=0b0000000000000000, p_ES_SDATA_MASK4=0b0000000000000000, p_EVODD_PHI_CFG=0b00000000000, p_EYE_SCAN_SWAP_EN=0b0, p_FTS_DESKEW_SEQ_ENABLE=0b1111, p_FTS_LANE_DESKEW_CFG=0b1111, p_FTS_LANE_DESKEW_EN="FALSE", p_GEARBOX_MODE=0b00000, p_GM_BIAS_SELECT=0b0, p_LOCAL_MASTER=0b1, p_OOBDIVCTL=0b00, p_OOB_PWRUP=0b0, p_PCI3_AUTO_REALIGN="OVR_1K_BLK", p_PCI3_PIPE_RX_ELECIDLE=0b0, p_PCI3_RX_ASYNC_EBUF_BYPASS=0b00, p_PCI3_RX_ELECIDLE_EI2_ENABLE=0b0, p_PCI3_RX_ELECIDLE_H2L_COUNT=0b000000, p_PCI3_RX_ELECIDLE_H2L_DISABLE=0b000, p_PCI3_RX_ELECIDLE_HI_COUNT=0b000000, p_PCI3_RX_ELECIDLE_LP4_DISABLE=0b0, p_PCI3_RX_FIFO_DISABLE=0b0, p_PCIE_BUFG_DIV_CTRL=0b0001000000000000, p_PCIE_RXPCS_CFG_GEN3=0b0000001010100100, p_PCIE_RXPMA_CFG=0b0000000000001010, p_PCIE_TXPCS_CFG_GEN3=0b0010010010100100, p_PCIE_TXPMA_CFG=0b0000000000001010, p_PCS_PCIE_EN="FALSE", p_PCS_RSVD0=0b0000000000000000, p_PCS_RSVD1=0b000, p_PD_TRANS_TIME_FROM_P2=0b000000111100, p_PD_TRANS_TIME_NONE_P2=0b00011001, p_PD_TRANS_TIME_TO_P2=0b01100100, p_PLL_SEL_MODE_GEN12=0b00, p_PLL_SEL_MODE_GEN3=0b11, p_PMA_RSV1=0b1111000000000000, p_PROCESS_PAR=0b010, p_RATE_SW_USE_DRP=0b1, p_RESET_POWERSAVE_DISABLE=0b0, ) self.gth_params.update( p_RXBUFRESET_TIME=0b00011, p_RXBUF_ADDR_MODE="FAST", p_RXBUF_EIDLE_HI_CNT=0b1000, p_RXBUF_EIDLE_LO_CNT=0b0000, p_RXBUF_EN="TRUE" if rx_buffer_enable else "FALSE", p_RXBUF_RESET_ON_CB_CHANGE="TRUE", p_RXBUF_RESET_ON_COMMAALIGN="FALSE", p_RXBUF_RESET_ON_EIDLE="FALSE", p_RXBUF_RESET_ON_RATE_CHANGE="TRUE", p_RXBUF_THRESH_OVFLW=57 if rx_buffer_enable else 0, p_RXBUF_THRESH_OVRD="TRUE" if rx_buffer_enable else "FALSE", p_RXBUF_THRESH_UNDFLW=3 if rx_buffer_enable else 0, p_RXCDRFREQRESET_TIME=0b00001, p_RXCDRPHRESET_TIME=0b00001, p_RXCDR_CFG0=0b0000000000000000, p_RXCDR_CFG0_GEN3=0b0000000000000000, p_RXCDR_CFG1=0b0000000000000000, p_RXCDR_CFG1_GEN3=0b0000000000000000, p_RXCDR_CFG2=0b0000011111010110, p_RXCDR_CFG2_GEN3=0b0000011111100110, p_RXCDR_CFG3=0b0000000000000000, p_RXCDR_CFG3_GEN3=0b0000000000000000, p_RXCDR_CFG4=0b0000000000000000, p_RXCDR_CFG4_GEN3=0b0000000000000000, p_RXCDR_CFG5=0b0000000000000000, p_RXCDR_CFG5_GEN3=0b0000000000000000, p_RXCDR_FR_RESET_ON_EIDLE=0b0, p_RXCDR_HOLD_DURING_EIDLE=0b0, p_RXCDR_LOCK_CFG0=0b0100010010000000, p_RXCDR_LOCK_CFG1=0b0101111111111111, p_RXCDR_LOCK_CFG2=0b0111011111000011, p_RXCDR_PH_RESET_ON_EIDLE=0b0, p_RXCFOK_CFG0=0b0100000000000000, p_RXCFOK_CFG1=0b0000000001100101, p_RXCFOK_CFG2=0b0000000000101110, p_RXDFELPMRESET_TIME=0b0001111, p_RXDFELPM_KL_CFG0=0b0000000000000000, p_RXDFELPM_KL_CFG1=0b0000000000000010, p_RXDFELPM_KL_CFG2=0b0000000000000000, p_RXDFE_CFG0=0b0000101000000000, p_RXDFE_CFG1=0b0000000000000000, p_RXDFE_GC_CFG0=0b0000000000000000, p_RXDFE_GC_CFG1=0b0111100001110000, p_RXDFE_GC_CFG2=0b0000000000000000, p_RXDFE_H2_CFG0=0b0000000000000000, p_RXDFE_H2_CFG1=0b0000000000000000, p_RXDFE_H3_CFG0=0b0100000000000000, p_RXDFE_H3_CFG1=0b0000000000000000, p_RXDFE_H4_CFG0=0b0010000000000000, p_RXDFE_H4_CFG1=0b0000000000000011, p_RXDFE_H5_CFG0=0b0010000000000000, p_RXDFE_H5_CFG1=0b0000000000000011, p_RXDFE_H6_CFG0=0b0010000000000000, p_RXDFE_H6_CFG1=0b0000000000000000, p_RXDFE_H7_CFG0=0b0010000000000000, p_RXDFE_H7_CFG1=0b0000000000000000, p_RXDFE_H8_CFG0=0b0010000000000000, p_RXDFE_H8_CFG1=0b0000000000000000, p_RXDFE_H9_CFG0=0b0010000000000000, p_RXDFE_H9_CFG1=0b0000000000000000, p_RXDFE_HA_CFG0=0b0010000000000000, p_RXDFE_HA_CFG1=0b0000000000000000, p_RXDFE_HB_CFG0=0b0010000000000000, p_RXDFE_HB_CFG1=0b0000000000000000, p_RXDFE_HC_CFG0=0b0000000000000000, p_RXDFE_HC_CFG1=0b0000000000000000, p_RXDFE_HD_CFG0=0b0000000000000000, p_RXDFE_HD_CFG1=0b0000000000000000, p_RXDFE_HE_CFG0=0b0000000000000000, p_RXDFE_HE_CFG1=0b0000000000000000, p_RXDFE_HF_CFG0=0b0000000000000000, p_RXDFE_HF_CFG1=0b0000000000000000, p_RXDFE_OS_CFG0=0b1000000000000000, p_RXDFE_OS_CFG1=0b0000000000000000, p_RXDFE_UT_CFG0=0b1000000000000000, p_RXDFE_UT_CFG1=0b0000000000000011, p_RXDFE_VP_CFG0=0b1010101000000000, p_RXDFE_VP_CFG1=0b0000000000110011, p_RXDLY_CFG=0b0000000000011111, p_RXDLY_LCFG=0b0000000000110000, p_RXELECIDLE_CFG="SIGCFG_4", p_RXGBOX_FIFO_INIT_RD_ADDR=4, p_RXGEARBOX_EN="FALSE", p_RXISCANRESET_TIME=0b00001, p_RXLPM_CFG=0b0000000000000000, p_RXLPM_GC_CFG=0b0001000000000000, p_RXLPM_KH_CFG0=0b0000000000000000, p_RXLPM_KH_CFG1=0b0000000000000010, p_RXLPM_OS_CFG0=0b1000000000000000, p_RXLPM_OS_CFG1=0b0000000000000010, p_RXOOB_CFG=0b000000110, p_RXOOB_CLK_CFG="PMA", p_RXOSCALRESET_TIME=0b00011, p_RXOUT_DIV=pll.config["d"], p_RXPCSRESET_TIME=0b00011, p_RXPHBEACON_CFG=0b0000000000000000, p_RXPHDLY_CFG=0b0010000000100000, p_RXPHSAMP_CFG=0b0010000100000000, p_RXPHSLIP_CFG=0b0110011000100010, p_RXPH_MONITOR_SEL=0b00000, p_RXPI_CFG0=0b00, p_RXPI_CFG1=0b00, p_RXPI_CFG2=0b00, p_RXPI_CFG3=0b00, p_RXPI_CFG4=0b1, p_RXPI_CFG5=0b1, p_RXPI_CFG6=0b000, p_RXPI_LPM=0b0, p_RXPI_VREFSEL=0b0, p_RXPMACLK_SEL="DATA", p_RXPMARESET_TIME=0b00011, p_RXPRBS_ERR_LOOPBACK=0b0, p_RXPRBS_LINKACQ_CNT=15, p_RXSLIDE_AUTO_WAIT=7, p_RXSLIDE_MODE="OFF", p_RXSYNC_MULTILANE=0b0, p_RXSYNC_OVRD=0b0, p_RXSYNC_SKIP_DA=0b0, p_RX_AFE_CM_EN=0b0, p_RX_BIAS_CFG0=0b0000101010110100, p_RX_BUFFER_CFG=0b000000, p_RX_CAPFF_SARC_ENB=0b0, p_RX_CLK25_DIV=5, p_RX_CLKMUX_EN=0b1, p_RX_CLK_SLIP_OVRD=0b00000, p_RX_CM_BUF_CFG=0b1010, p_RX_CM_BUF_PD=0b0, p_RX_CM_SEL=0b11, p_RX_CM_TRIM=0b1010, p_RX_CTLE3_LPF=0b00000001, p_RX_DATA_WIDTH=data_width, p_RX_DDI_SEL=0b000000, p_RX_DEFER_RESET_BUF_EN="TRUE", p_RX_DFELPM_CFG0=0b0110, p_RX_DFELPM_CFG1=0b1, p_RX_DFELPM_KLKH_AGC_STUP_EN=0b1, p_RX_DFE_AGC_CFG0=0b10, p_RX_DFE_AGC_CFG1=0b100, p_RX_DFE_KL_LPM_KH_CFG0=0b01, p_RX_DFE_KL_LPM_KH_CFG1=0b100, p_RX_DFE_KL_LPM_KL_CFG0=0b01, p_RX_DFE_KL_LPM_KL_CFG1=0b100, p_RX_DFE_LPM_HOLD_DURING_EIDLE=0b0, p_RX_DISPERR_SEQ_MATCH="TRUE", p_RX_DIVRESET_TIME=0b00001, p_RX_EN_HI_LR=0b0, p_RX_EYESCAN_VS_CODE=0b0000000, p_RX_EYESCAN_VS_NEG_DIR=0b0, p_RX_EYESCAN_VS_RANGE=0b00, p_RX_EYESCAN_VS_UT_SIGN=0b0, p_RX_FABINT_USRCLK_FLOP=0b0, p_RX_INT_DATAWIDTH=data_width == 40, p_RX_PMA_POWER_SAVE=0b0, p_RX_PROGDIV_CFG=0.0, p_RX_SAMPLE_PERIOD=0b111, p_RX_SIG_VALID_DLY=11, p_RX_SUM_DFETAPREP_EN=0b0, p_RX_SUM_IREF_TUNE=0b0000, p_RX_SUM_RES_CTRL=0b00, p_RX_SUM_VCMTUNE=0b0000, p_RX_SUM_VCM_OVWR=0b0, p_RX_SUM_VREF_TUNE=0b000, p_RX_TUNE_AFE_OS=0b10, p_RX_WIDEMODE_CDR=0b0, p_RX_XCLK_SEL="RXDES" if rx_buffer_enable else "RXUSR", p_SAS_MAX_COM=64, p_SAS_MIN_COM=36, p_SATA_BURST_SEQ_LEN=0b1110, p_SATA_CPLL_CFG="VCO_3000MHZ", p_SATA_MAX_BURST=8, p_SATA_MAX_INIT=21, p_SATA_MAX_WAKE=7, p_SATA_MIN_BURST=4, p_SATA_MIN_INIT=12, p_SATA_MIN_WAKE=4, p_SHOW_REALIGN_COMMA="TRUE", p_SIM_RECEIVER_DETECT_PASS="******", p_SIM_RESET_SPEEDUP="TRUE", p_SIM_TX_EIDLE_DRIVE_LEVEL=0b0, p_SIM_VERSION=2, p_TAPDLY_SET_TX=0b00, p_TEMPERATUR_PAR=0b0010, p_TERM_RCAL_CFG=0b100001000010000, p_TERM_RCAL_OVRD=0b000, p_TRANS_TIME_RATE=0b00001110, p_TST_RSV0=0b00000000, p_TST_RSV1=0b00000000, ) self.gth_params.update( p_TXBUF_EN="TRUE" if tx_buffer_enable else "FALSE", p_TXBUF_RESET_ON_RATE_CHANGE="TRUE", p_TXDLY_CFG=0b0000000000001001, p_TXDLY_LCFG=0b0000000001010000, p_TXDRVBIAS_N=0b1010, p_TXDRVBIAS_P=0b1010, p_TXFIFO_ADDR_CFG="LOW", p_TXGBOX_FIFO_INIT_RD_ADDR=4, p_TXGEARBOX_EN="FALSE", p_TXOUT_DIV=pll.config["d"], p_TXPCSRESET_TIME=0b00011, p_TXPHDLY_CFG0=0b0010000000100000, p_TXPHDLY_CFG1=0b0000000001110101, p_TXPH_CFG=0b0000100110000000, p_TXPH_MONITOR_SEL=0b00000, p_TXPI_CFG0=0b00, p_TXPI_CFG1=0b00, p_TXPI_CFG2=0b00, p_TXPI_CFG3=0b1, p_TXPI_CFG4=0b1, p_TXPI_CFG5=0b000, p_TXPI_GRAY_SEL=0b0, p_TXPI_INVSTROBE_SEL=0b0, p_TXPI_LPM=0b0, p_TXPI_PPMCLK_SEL="TXUSRCLK2", p_TXPI_PPM_CFG=0b00000000, p_TXPI_SYNFREQ_PPM=0b001, p_TXPI_VREFSEL=0b0, p_TXPMARESET_TIME=0b00011, p_TXSYNC_MULTILANE=0, p_TXSYNC_OVRD=0b0, p_TXSYNC_SKIP_DA=0b0, p_TX_CLK25_DIV=5, p_TX_CLKMUX_EN=0b1, p_TX_DATA_WIDTH=data_width, p_TX_DCD_CFG=0b000010, p_TX_DCD_EN=0b0, p_TX_DEEMPH0=0b000000, p_TX_DEEMPH1=0b000000, p_TX_DIVRESET_TIME=0b00001, p_TX_DRIVE_MODE="DIRECT", p_TX_EIDLE_ASSERT_DELAY=0b100, p_TX_EIDLE_DEASSERT_DELAY=0b011, p_TX_EML_PHI_TUNE=0b0, p_TX_FABINT_USRCLK_FLOP=0b0, p_TX_IDLE_DATA_ZERO=0b0, p_TX_INT_DATAWIDTH=data_width == 40, p_TX_LOOPBACK_DRIVE_HIZ="FALSE", p_TX_MAINCURSOR_SEL=0b0, p_TX_MARGIN_FULL_0=0b1001111, p_TX_MARGIN_FULL_1=0b1001110, p_TX_MARGIN_FULL_2=0b1001100, p_TX_MARGIN_FULL_3=0b1001010, p_TX_MARGIN_FULL_4=0b1001000, p_TX_MARGIN_LOW_0=0b1000110, p_TX_MARGIN_LOW_1=0b1000101, p_TX_MARGIN_LOW_2=0b1000011, p_TX_MARGIN_LOW_3=0b1000010, p_TX_MARGIN_LOW_4=0b1000000, p_TX_MODE_SEL=0b000, p_TX_PMADATA_OPT=0b0, p_TX_PMA_POWER_SAVE=0b0, p_TX_PROGCLK_SEL="PREPI", p_TX_PROGDIV_CFG=0.0, p_TX_QPI_STATUS_EN=0b0, p_TX_RXDETECT_CFG=0b00000000110010, p_TX_RXDETECT_REF=0b100, p_TX_SAMPLE_PERIOD=0b111, p_TX_SARC_LPBK_ENB=0b0, p_TX_XCLK_SEL="TXOUT" if tx_buffer_enable else "TXUSR", p_USE_PCS_CLK_PHASE_SEL=0b0, p_WB_MODE=0b00, ) self.gth_params.update( # Reset modes i_GTRESETSEL=0, i_RESETOVRD=0, # DRP i_DRPADDR=drp_mux.addr, i_DRPCLK=drp_mux.clk, i_DRPDI=drp_mux.di, o_DRPDO=drp_mux.do, i_DRPEN=drp_mux.en, o_DRPRDY=drp_mux.rdy, i_DRPWE=drp_mux.we, # CPLL i_CPLLRESET=0, i_CPLLPD=0 if (use_qpll0 | use_qpll1) else pll.reset, o_CPLLLOCK=Signal() if (use_qpll0 | use_qpll1) else pll.lock, i_CPLLLOCKEN=1, i_CPLLREFCLKSEL=0b001, i_TSTIN=2**20 - 1, i_GTREFCLK0=0 if (use_qpll0 | use_qpll1) else pll.refclk, # QPLL i_QPLL0CLK=0 if (use_cpll | use_qpll1) else pll.clk, i_QPLL0REFCLK=0 if (use_cpll | use_qpll1) else pll.refclk, i_QPLL1CLK=0 if (use_cpll | use_qpll0) else pll.clk, i_QPLL1REFCLK=0 if (use_cpll | use_qpll0) else pll.refclk, # TX clock o_TXOUTCLK=self.txoutclk, i_TXSYSCLKSEL=0b00 if use_cpll else 0b10 if use_qpll0 else 0b11, i_TXPLLCLKSEL=0b00 if use_cpll else 0b11 if use_qpll0 else 0b10, i_TXOUTCLKSEL=0b010 if tx_buffer_enable else 0b011, # 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, i_TXSYNCMODE=1, i_TXDLYBYPASS=1 if tx_buffer_enable else 0, i_TXPHDLYPD=1 if tx_buffer_enable else 0, # TX data i_TXCTRL0=Cat(*[txdata[10 * i + 8] for i in range(nwords)]), i_TXCTRL1=Cat(*[txdata[10 * i + 9] for i in range(nwords)]), i_TXDATA=Cat(*[txdata[10 * i:10 * i + 8] for i in range(nwords)]), i_TXUSRCLK=ClockSignal("tx"), i_TXUSRCLK2=ClockSignal("tx"), # TX electrical i_TXPD=0b00, i_TXBUFDIFFCTRL=0b000, i_TXDIFFCTRL=0b1100, i_TXINHIBIT=self.tx_inhibit, # Internal Loopback i_LOOPBACK=self.loopback, # RX Startup/Reset i_GTRXRESET=rx_init.gtXxreset, o_RXRESETDONE=rx_init.Xxresetdone, i_RXDLYSRESET=rx_init.Xxdlysreset, o_RXPHALIGNDONE=rxphaligndone, i_RXSYNCALLIN=rxphaligndone, i_RXUSERRDY=rx_init.Xxuserrdy, i_RXSYNCIN=0, i_RXSYNCMODE=1, o_RXSYNCDONE=rx_init.Xxsyncdone, i_RXDLYBYPASS=1 if rx_buffer_enable else 0, i_RXPHDLYPD=1 if rx_buffer_enable else 0, # RX AFE i_RXDFEAGCCTRL=1, i_RXDFEXYDEN=1, i_RXLPMEN=1, i_RXOSINTCFG=0xd, i_RXOSINTEN=1, # RX clock i_RXRATE=0, i_RXSYSCLKSEL=0b00, i_RXOUTCLKSEL=0b010, i_RXPLLCLKSEL=0b00, o_RXOUTCLK=self.rxoutclk, i_RXUSRCLK=ClockSignal("rx"), i_RXUSRCLK2=ClockSignal("rx"), # RX data o_RXCTRL0=Cat(*[rxdata[10 * i + 8] for i in range(nwords)]), o_RXCTRL1=Cat(*[rxdata[10 * i + 9] for i in range(nwords)]), o_RXDATA=Cat(*[rxdata[10 * i:10 * i + 8] for i in range(nwords)]), # RX electrical i_RXPD=0b00, i_RXELECIDLEMODE=0b11, # Polarity i_TXPOLARITY=tx_polarity, i_RXPOLARITY=rx_polarity, # Pads i_GTHRXP=rx_pads.p, i_GTHRXN=rx_pads.n, o_GTHTXP=tx_pads.p, o_GTHTXN=tx_pads.n) # TX clocking ------------------------------------------------------------------------------ tx_reset_deglitched = Signal() tx_reset_deglitched.attr.add("no_retiming") self.sync += tx_reset_deglitched.eq(~tx_init.done) self.clock_domains.cd_tx = ClockDomain() if not tx_buffer_enable: tx_bufg_div = pll.config["clkin"] / self.tx_clk_freq else: txoutclk_div = 1 assert tx_bufg_div == int(tx_bufg_div) self.specials += [ Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_tx.clk, i_DIV=int(tx_bufg_div) - 1), AsyncResetSynchronizer(self.cd_tx, tx_reset_deglitched) ] # RX clocking ------------------------------------------------------------------------------ rx_reset_deglitched = Signal() rx_reset_deglitched.attr.add("no_retiming") self.sync.tx += rx_reset_deglitched.eq(~rx_init.done) self.clock_domains.cd_rx = ClockDomain() self.specials += [ Instance("BUFG_GT", i_I=self.rxoutclk, o_O=self.cd_rx.clk), AsyncResetSynchronizer(self.cd_rx, rx_reset_deglitched) ] # TX Datapath and PRBS --------------------------------------------------------------------- self.submodules.tx_prbs = ClockDomainsRenamer("tx")(PRBSTX( data_width, True)) self.comb += self.tx_prbs.config.eq(tx_prbs_config) self.comb += [ self.tx_prbs.i.eq( Cat(*[self.encoder.output[i] for i in range(nwords)])), If( tx_produce_square_wave, # square wave @ linerate/data_width for scope observation txdata.eq( Signal(data_width, reset=(1 << (data_width // 2)) - 1) )).Elif(tx_produce_pattern, txdata.eq(self.tx_pattern)).Else( txdata.eq(self.tx_prbs.o)) ] # RX Datapath and PRBS --------------------------------------------------------------------- self.submodules.rx_prbs = ClockDomainsRenamer("rx")(PRBSRX( data_width, True)) self.comb += [ self.rx_prbs.config.eq(rx_prbs_config), rx_prbs_errors.eq(self.rx_prbs.errors) ] for i in range(nwords): self.comb += self.decoders[i].input.eq(rxdata[10 * i:10 * (i + 1)]) self.comb += self.rx_prbs.i.eq(rxdata) # Clock Aligner ---------------------------------------------------------------------------- if clock_aligner: clock_aligner = BruteforceClockAligner(clock_aligner_comma, self.tx_clk_freq) self.submodules.clock_aligner = clock_aligner ps_restart = PulseSynchronizer("tx", "sys") self.submodules += ps_restart self.comb += [ clock_aligner.rxdata.eq(rxdata), ps_restart.i.eq(clock_aligner.restart), rx_init.restart.eq((ps_restart.o & self.rx_align) | ~self.rx_enable), self.rx_ready.eq(clock_aligner.ready) ]
def __init__(self, pll, tx_pads, rx_pads, sys_clk_freq, data_width=20, tx_buffer_enable=False, rx_buffer_enable=False, clock_aligner=True, clock_aligner_comma=0b0101111100, tx_polarity=0, rx_polarity=0, pll_master=True): assert (data_width == 20) or (data_width == 40) # TX controls self.tx_enable = Signal(reset=1) self.tx_ready = Signal() self.tx_inhibit = Signal() self.tx_produce_square_wave = Signal() self.tx_produce_pattern = Signal() self.tx_pattern = Signal(data_width) self.tx_prbs_config = Signal(2) # RX controls self.rx_enable = Signal(reset=1) self.rx_ready = Signal() self.rx_align = Signal(reset=1) self.rx_prbs_config = Signal(2) self.rx_prbs_errors = Signal(32) # DRP self.drp = DRPInterface() # Loopback self.loopback = Signal(3) # # # self.nwords = nwords = data_width // 10 self.submodules.encoder = ClockDomainsRenamer("tx")(Encoder( nwords, True)) self.decoders = [ ClockDomainsRenamer("rx")(Decoder(True)) for _ in range(nwords) ] self.submodules += self.decoders # Transceiver direct clock outputs (useful to specify clock constraints) self.txoutclk = Signal() self.rxoutclk = Signal() self.tx_clk_freq = pll.config["linerate"] / data_width self.rx_clk_freq = pll.config["linerate"] / data_width # Control/Status CDC tx_produce_square_wave = Signal() tx_produce_pattern = Signal() tx_pattern = Signal(20) tx_prbs_config = Signal(2) rx_prbs_config = Signal(2) rx_prbs_errors = Signal(32) self.specials += [ MultiReg(self.tx_produce_square_wave, tx_produce_square_wave, "tx"), MultiReg(self.tx_produce_pattern, tx_produce_pattern, "tx"), MultiReg(self.tx_pattern, tx_pattern, "tx"), MultiReg(self.tx_prbs_config, tx_prbs_config, "tx"), ] self.specials += [ MultiReg(self.rx_prbs_config, rx_prbs_config, "rx"), MultiReg(rx_prbs_errors, self.rx_prbs_errors, "sys"), # FIXME ] # # # use_cpll = isinstance(pll, GTXChannelPLL) use_qpll = isinstance(pll, GTXQuadPLL) rxcdr_cfgs = { 1: 0x03000023ff10400020, 2: 0x03000023ff10200020, 4: 0x03000023ff10100020, 8: 0x03000023ff10080020, 16: 0x03000023ff10080020, } # TX init ---------------------------------------------------------------------------------- self.submodules.tx_init = tx_init = GTXTXInit( sys_clk_freq, buffer_enable=tx_buffer_enable) self.comb += [ self.tx_ready.eq(tx_init.done), tx_init.restart.eq(~self.tx_enable) ] # RX init ---------------------------------------------------------------------------------- self.submodules.rx_init = rx_init = GTXRXInit( sys_clk_freq, buffer_enable=rx_buffer_enable) self.comb += [ self.rx_ready.eq(rx_init.done), rx_init.restart.eq(~self.rx_enable) ] # PLL ---------------------------------------------------------------------------------- self.comb += [ tx_init.plllock.eq(pll.lock), rx_init.plllock.eq(pll.lock) ] if pll_master: self.comb += pll.reset.eq(tx_init.pllreset) # DRP mux ---------------------------------------------------------------------------------- self.submodules.drp_mux = drp_mux = DRPMux() drp_mux.add_interface(self.drp) # GTXE2_CHANNEL instance ------------------------------------------------------------------- txdata = Signal(data_width) rxdata = Signal(data_width) self.gtx_params = dict( # Simulation-Only Attributes p_SIM_RECEIVER_DETECT_PASS="******", p_SIM_TX_EIDLE_DRIVE_LEVEL="X", p_SIM_RESET_SPEEDUP="FALSE", p_SIM_CPLLREFCLK_SEL="FALSE", p_SIM_VERSION="4.0", # RX Byte and Word Alignment Attributes p_ALIGN_COMMA_DOUBLE="FALSE", p_ALIGN_COMMA_ENABLE=0b1111111111, p_ALIGN_COMMA_WORD=2 if data_width == 20 else 4, p_ALIGN_MCOMMA_DET="TRUE", p_ALIGN_MCOMMA_VALUE=0b1010000011, p_ALIGN_PCOMMA_DET="TRUE", p_ALIGN_PCOMMA_VALUE=0b0101111100, p_SHOW_REALIGN_COMMA="TRUE", p_RXSLIDE_AUTO_WAIT=7, p_RXSLIDE_MODE="OFF" if rx_buffer_enable else "PCS", p_RX_SIG_VALID_DLY=10, # RX 8B/10B Decoder Attributes p_RX_DISPERR_SEQ_MATCH="TRUE", p_DEC_MCOMMA_DETECT="TRUE", p_DEC_PCOMMA_DETECT="TRUE", p_DEC_VALID_COMMA_ONLY="TRUE", # RX Clock Correction Attributes p_CBCC_DATA_SOURCE_SEL="DECODED", p_CLK_COR_SEQ_2_USE="FALSE", p_CLK_COR_KEEP_IDLE="FALSE", p_CLK_COR_MAX_LAT=9 if data_width == 20 else 20, p_CLK_COR_MIN_LAT=7 if data_width == 20 else 16, p_CLK_COR_PRECEDENCE="TRUE", p_CLK_COR_REPEAT_WAIT=0, p_CLK_COR_SEQ_LEN=1, p_CLK_COR_SEQ_1_ENABLE=0b1111, p_CLK_COR_SEQ_1_1=0b0100000000, p_CLK_COR_SEQ_1_2=0b0000000000, p_CLK_COR_SEQ_1_3=0b0000000000, p_CLK_COR_SEQ_1_4=0b0000000000, p_CLK_CORRECT_USE="FALSE", p_CLK_COR_SEQ_2_ENABLE=0b1111, p_CLK_COR_SEQ_2_1=0b0100000000, p_CLK_COR_SEQ_2_2=0b0000000000, p_CLK_COR_SEQ_2_3=0b0000000000, p_CLK_COR_SEQ_2_4=0b0000000000, # RX Channel Bonding Attributes p_CHAN_BOND_KEEP_ALIGN="FALSE", p_CHAN_BOND_MAX_SKEW=1, p_CHAN_BOND_SEQ_LEN=1, p_CHAN_BOND_SEQ_1_1=0b0000000000, p_CHAN_BOND_SEQ_1_2=0b0000000000, p_CHAN_BOND_SEQ_1_3=0b0000000000, p_CHAN_BOND_SEQ_1_4=0b0000000000, p_CHAN_BOND_SEQ_1_ENABLE=0b1111, p_CHAN_BOND_SEQ_2_1=0b0000000000, p_CHAN_BOND_SEQ_2_2=0b0000000000, p_CHAN_BOND_SEQ_2_3=0b0000000000, p_CHAN_BOND_SEQ_2_4=0b0000000000, p_CHAN_BOND_SEQ_2_ENABLE=0b1111, p_CHAN_BOND_SEQ_2_USE="FALSE", p_FTS_DESKEW_SEQ_ENABLE=0b1111, p_FTS_LANE_DESKEW_CFG=0b1111, p_FTS_LANE_DESKEW_EN="FALSE", # RX Margin Analysis Attributes p_ES_CONTROL=0b000000, p_ES_ERRDET_EN="FALSE", p_ES_EYE_SCAN_EN="TRUE", p_ES_HORZ_OFFSET=0x000, p_ES_PMA_CFG=0b0000000000, p_ES_PRESCALE=0b00000, p_ES_QUALIFIER=0x00000000000000000000, p_ES_QUAL_MASK=0x00000000000000000000, p_ES_SDATA_MASK=0x00000000000000000000, p_ES_VERT_OFFSET=0b000000000, # FPGA RX Interface Attributes p_RX_DATA_WIDTH=data_width, # PMA Attributes p_OUTREFCLK_SEL_INV=0b11, p_PMA_RSV=0x001e7080, p_PMA_RSV2=0x2050, p_PMA_RSV3=0b00, p_PMA_RSV4=0x00000000, p_RX_BIAS_CFG=0b000000000100, p_DMONITOR_CFG=0x000A00, p_RX_CM_SEL=0b11, p_RX_CM_TRIM=0b010, p_RX_DEBUG_CFG=0b000000000000, p_RX_OS_CFG=0b0000010000000, p_TERM_RCAL_CFG=0b10000, p_TERM_RCAL_OVRD=0b0, p_TST_RSV=0x00000000, p_RX_CLK25_DIV=5, p_TX_CLK25_DIV=5, p_UCODEER_CLR=0b0, # PCI Express Attributes p_PCS_PCIE_EN="FALSE", # PCS Attributes p_PCS_RSVD_ATTR=0x000000000000, # RX Buffer Attributes p_RXBUF_ADDR_MODE="FAST", p_RXBUF_EIDLE_HI_CNT=0b1000, p_RXBUF_EIDLE_LO_CNT=0b0000, p_RXBUF_EN="TRUE" if rx_buffer_enable else "FALSE", p_RX_BUFFER_CFG=0b000000, p_RXBUF_RESET_ON_CB_CHANGE="TRUE", p_RXBUF_RESET_ON_COMMAALIGN="FALSE", p_RXBUF_RESET_ON_EIDLE="FALSE", p_RXBUF_RESET_ON_RATE_CHANGE="TRUE", p_RXBUFRESET_TIME=0b00001, p_RXBUF_THRESH_OVFLW=61, p_RXBUF_THRESH_OVRD="FALSE", p_RXBUF_THRESH_UNDFLW=4, p_RXDLY_CFG=0x001F, p_RXDLY_LCFG=0x030, p_RXDLY_TAP_CFG=0x0000, p_RXPH_CFG=0x000000, p_RXPHDLY_CFG=0x084020, p_RXPH_MONITOR_SEL=0b00000, p_RX_XCLK_SEL="RXREC" if rx_buffer_enable else "RXUSR", p_RX_DDI_SEL=0b000000, p_RX_DEFER_RESET_BUF_EN="TRUE", # CDR Attributes p_RXCDR_CFG=rxcdr_cfgs[pll.config["d"]], p_RXCDR_FR_RESET_ON_EIDLE=0b0, p_RXCDR_HOLD_DURING_EIDLE=0b0, p_RXCDR_PH_RESET_ON_EIDLE=0b0, p_RXCDR_LOCK_CFG=0b010101, # RX Initialization and Reset Attributes p_RXCDRFREQRESET_TIME=0b00001, p_RXCDRPHRESET_TIME=0b00001, p_RXISCANRESET_TIME=0b00001, p_RXPCSRESET_TIME=0b00001, p_RXPMARESET_TIME=0b00011, # RX OOB Signaling Attributes p_RXOOB_CFG=0b0000110, # RX Gearbox Attributes p_RXGEARBOX_EN="FALSE", p_GEARBOX_MODE=0b000, # PRBS Detection Attribute p_RXPRBS_ERR_LOOPBACK=0b0, # Power-Down Attributes p_PD_TRANS_TIME_FROM_P2=0x03c, p_PD_TRANS_TIME_NONE_P2=0x3c, p_PD_TRANS_TIME_TO_P2=0x64, # RX OOB Signaling Attributes p_SAS_MAX_COM=64, p_SAS_MIN_COM=36, p_SATA_BURST_SEQ_LEN=0b0101, p_SATA_BURST_VAL=0b100, p_SATA_EIDLE_VAL=0b100, p_SATA_MAX_BURST=8, p_SATA_MAX_INIT=21, p_SATA_MAX_WAKE=7, p_SATA_MIN_BURST=4, p_SATA_MIN_INIT=12, p_SATA_MIN_WAKE=4, # RX Fabric Clock Output Control Attributes p_TRANS_TIME_RATE=0x0E, # TX Buffer Attributes p_TXBUF_EN="TRUE" if tx_buffer_enable else "FALSE", p_TXBUF_RESET_ON_RATE_CHANGE="TRUE", p_TXDLY_CFG=0x001F, p_TXDLY_LCFG=0x030, p_TXDLY_TAP_CFG=0x0000, p_TXPH_CFG=0x0780, p_TXPHDLY_CFG=0x084020, p_TXPH_MONITOR_SEL=0b00000, p_TX_XCLK_SEL="TXOUT" if tx_buffer_enable else "TXUSR", # FPGA TX Interface Attributes p_TX_DATA_WIDTH=data_width, # TX Configurable Driver Attributes p_TX_DEEMPH0=0b00000, p_TX_DEEMPH1=0b00000, p_TX_EIDLE_ASSERT_DELAY=0b110, p_TX_EIDLE_DEASSERT_DELAY=0b100, p_TX_LOOPBACK_DRIVE_HIZ="FALSE", p_TX_MAINCURSOR_SEL=0b0, p_TX_DRIVE_MODE="DIRECT", p_TX_MARGIN_FULL_0=0b1001110, p_TX_MARGIN_FULL_1=0b1001001, p_TX_MARGIN_FULL_2=0b1000101, p_TX_MARGIN_FULL_3=0b1000010, p_TX_MARGIN_FULL_4=0b1000000, p_TX_MARGIN_LOW_0=0b1000110, p_TX_MARGIN_LOW_1=0b1000100, p_TX_MARGIN_LOW_2=0b1000010, p_TX_MARGIN_LOW_3=0b1000000, p_TX_MARGIN_LOW_4=0b1000000, # TX Gearbox Attributes p_TXGEARBOX_EN="FALSE", # TX Initialization and Reset Attributes p_TXPCSRESET_TIME=0b00001, p_TXPMARESET_TIME=0b00001, # TX Receiver Detection Attributes p_TX_RXDETECT_CFG=0x1832, p_TX_RXDETECT_REF=0b100, # CPLL Attributes p_CPLL_CFG=0xBC07DC, p_CPLL_FBDIV=1 if use_qpll else pll.config["n2"], p_CPLL_FBDIV_45=4 if use_qpll else pll.config["n1"], p_CPLL_INIT_CFG=0x00001E, p_CPLL_LOCK_CFG=0x01E8, p_CPLL_REFCLK_DIV=1 if use_qpll else pll.config["m"], p_RXOUT_DIV=pll.config["d"], p_TXOUT_DIV=pll.config["d"], p_SATA_CPLL_CFG="VCO_3000MHZ", # RX Initialization and Reset Attributes p_RXDFELPMRESET_TIME=0b0001111, # RX Equalizer Attributes p_RXLPM_HF_CFG=0b00000011110000, p_RXLPM_LF_CFG=0b00000011110000, p_RX_DFE_GAIN_CFG=0x020FEA, p_RX_DFE_H2_CFG=0b000000000000, p_RX_DFE_H3_CFG=0b000001000000, p_RX_DFE_H4_CFG=0b00011110000, p_RX_DFE_H5_CFG=0b00011100000, p_RX_DFE_KL_CFG=0b0000011111110, p_RX_DFE_LPM_CFG=0x0954, p_RX_DFE_LPM_HOLD_DURING_EIDLE=0b0, p_RX_DFE_UT_CFG=0b10001111000000000, p_RX_DFE_VP_CFG=0b00011111100000011, # Power-Down Attributes p_RX_CLKMUX_PD=0b1, p_TX_CLKMUX_PD=0b1, # FPGA RX Interface Attribute p_RX_INT_DATAWIDTH=data_width == 40, # FPGA TX Interface Attribute p_TX_INT_DATAWIDTH=data_width == 40, # TX Configurable Driver Attributes p_TX_QPI_STATUS_EN=0b0, # RX Equalizer Attributes p_RX_DFE_KL_CFG2=0x301148AC, p_RX_DFE_XYD_CFG=0b0000000000000, # TX Configurable Driver Attributes p_TX_PREDRIVER_MODE=0b0) self.gtx_params.update( # CPLL Ports #o_CPLLFBCLKLOST =, o_CPLLLOCK=Signal() if use_qpll else pll.lock, i_CPLLLOCKDETCLK=ClockSignal(), i_CPLLLOCKEN=1, i_CPLLPD=0, #o_CPLLREFCLKLOST = , i_CPLLREFCLKSEL=0b001, i_CPLLRESET=0 if use_qpll else pll.reset, i_GTRSVD=0b0000000000000000, i_PCSRSVDIN=0b0000000000000000, i_PCSRSVDIN2=0b00000, i_PMARSVDIN=0b00000, i_PMARSVDIN2=0b00000, i_TSTIN=0b11111111111111111111, #o_TSTOUT =, # Channel i_CLKRSVD=0b0000, # Channel - Clocking Ports i_GTGREFCLK=0, i_GTNORTHREFCLK0=0, i_GTNORTHREFCLK1=0, i_GTREFCLK0=0 if use_qpll else pll.refclk, i_GTREFCLK1=0, i_GTSOUTHREFCLK0=0, i_GTSOUTHREFCLK1=0, # Channel - DRP Ports i_DRPADDR=drp_mux.addr, i_DRPCLK=drp_mux.clk, i_DRPDI=drp_mux.di, o_DRPDO=drp_mux.do, i_DRPEN=drp_mux.en, o_DRPRDY=drp_mux.rdy, i_DRPWE=drp_mux.we, # Clocking Ports #o_GTREFCLKMONITOR =, i_QPLLCLK=0 if use_cpll else pll.clk, i_QPLLREFCLK=0 if use_cpll else pll.refclk, i_RXSYSCLKSEL=0b11 if use_qpll else 0b00, i_TXSYSCLKSEL=0b11 if use_qpll else 0b00, # Digital Monitor Ports #o_DMONITOROUT =, # FPGA TX Interface Datapath Configuration i_TX8B10BEN=0, # Loopback Ports i_LOOPBACK=self.loopback, # PCI Express Ports #o_PHYSTATUS =, i_RXRATE=0b000, #o_RXVALID =, # Power-Down Ports i_RXPD=Cat(rx_init.gtXxpd, rx_init.gtXxpd), i_TXPD=0b00, # RX 8B/10B Decoder Ports i_SETERRSTATUS=0, # RX Initialization and Reset Ports i_EYESCANRESET=0, i_RXUSERRDY=rx_init.Xxuserrdy, # RX Margin Analysis Ports #o_EYESCANDATAERROR =, i_EYESCANMODE=0, i_EYESCANTRIGGER=0, # Receive Ports - CDR Ports i_RXCDRFREQRESET=0, i_RXCDRHOLD=0, #o_RXCDRLOCK =, i_RXCDROVRDEN=0, i_RXCDRRESET=0, i_RXCDRRESETRSV=0, # Receive Ports - Clock Correction Ports #o_RXCLKCORCNT =, # Receive Ports - FPGA RX Interface Datapath Configuration i_RX8B10BEN=0, # Receive Ports - FPGA RX Interface Ports i_RXUSRCLK=ClockSignal("rx"), i_RXUSRCLK2=ClockSignal("rx"), # Receive Ports - FPGA RX interface Ports o_RXDATA=Cat(*[rxdata[10 * i:10 * i + 8] for i in range(nwords)]), # Receive Ports - Pattern Checker Ports #o_RXPRBSERR =, i_RXPRBSSEL=0b000, # Receive Ports - Pattern Checker ports i_RXPRBSCNTRESET=0, # Receive Ports - RX Equalizer Ports i_RXDFEXYDEN=1, i_RXDFEXYDHOLD=0, i_RXDFEXYDOVRDEN=0, # Receive Ports - RX 8B/10B Decoder Ports i_RXDISPERR=Cat(*[rxdata[10 * i + 9] for i in range(nwords)]), #o_RXNOTINTABLE =, # Receive Ports - RX AFE i_GTXRXP=rx_pads.p, i_GTXRXN=rx_pads.n, # Receive Ports - RX Buffer Bypass Ports i_RXBUFRESET=0, #o_RXBUFSTATUS =, i_RXDDIEN=0 if rx_buffer_enable else 1, i_RXDLYBYPASS=1 if rx_buffer_enable else 0, i_RXDLYEN=0, i_RXDLYOVRDEN=0, i_RXDLYSRESET=rx_init.Xxdlysreset, o_RXDLYSRESETDONE=rx_init.Xxdlysresetdone, i_RXPHALIGN=0, o_RXPHALIGNDONE=rx_init.Xxphaligndone, i_RXPHALIGNEN=0, i_RXPHDLYPD=0, i_RXPHDLYRESET=0, #o_RXPHMONITOR =, i_RXPHOVRDEN=0, #o_RXPHSLIPMONITOR =, #o_RXSTATUS =, # Receive Ports - RX Byte and Word Alignment Ports #o_RXBYTEISALIGNED =, #o_RXBYTEREALIGN =, #o_RXCOMMADET =, i_RXCOMMADETEN=1, i_RXMCOMMAALIGNEN=(~clock_aligner & self.rx_align & (rx_prbs_config == 0b00)) if rx_buffer_enable else 0, i_RXPCOMMAALIGNEN=(~clock_aligner & self.rx_align & (rx_prbs_config == 0b00)) if rx_buffer_enable else 0, # Receive Ports - RX Channel Bonding Ports #o_RXCHANBONDSEQ =, i_RXCHBONDEN=0, i_RXCHBONDLEVEL=0b000, i_RXCHBONDMASTER=0, #o_RXCHBONDO =, i_RXCHBONDSLAVE=0, # Receive Ports - RX Channel Bonding Ports #o_RXCHANISALIGNED =, #o_RXCHANREALIGN =, # Receive Ports - RX Equailizer Ports i_RXLPMHFHOLD=0, i_RXLPMHFOVRDEN=0, i_RXLPMLFHOLD=0, # Receive Ports - RX Equalizer Ports i_RXDFEAGCHOLD=0, i_RXDFEAGCOVRDEN=0, i_RXDFECM1EN=0, i_RXDFELFHOLD=0, i_RXDFELFOVRDEN=1, i_RXDFELPMRESET=0, i_RXDFETAP2HOLD=0, i_RXDFETAP2OVRDEN=0, i_RXDFETAP3HOLD=0, i_RXDFETAP3OVRDEN=0, i_RXDFETAP4HOLD=0, i_RXDFETAP4OVRDEN=0, i_RXDFETAP5HOLD=0, i_RXDFETAP5OVRDEN=0, i_RXDFEUTHOLD=0, i_RXDFEUTOVRDEN=0, i_RXDFEVPHOLD=0, i_RXDFEVPOVRDEN=0, i_RXDFEVSEN=0, i_RXLPMLFKLOVRDEN=0, #o_RXMONITOROUT = i_RXMONITORSEL=0, i_RXOSHOLD=0, i_RXOSOVRDEN=0, # Receive Ports - RX Fabric ClocK Output Control Ports #o_RXRATEDONE =, # Receive Ports - RX Fabric Output Control Ports o_RXOUTCLK=self.rxoutclk, #o_RXOUTCLKFABRIC =, #o_RXOUTCLKPCS =, i_RXOUTCLKSEL=0b010, # Receive Ports - RX Gearbox Ports #o_RXDATAVALID =, #o_RXHEADER =, #o_RXHEADERVALID =, #o_RXSTARTOFSEQ =, # Receive Ports - RX Gearbox Ports i_RXGEARBOXSLIP=0, # Receive Ports - RX Initialization and Reset Ports i_GTRXRESET=rx_init.gtXxreset, i_RXOOBRESET=0, i_RXPCSRESET=0, i_RXPMARESET=0, # Receive Ports - RX Margin Analysis ports i_RXLPMEN=0, # Receive Ports - RX OOB Signaling ports #o_RXCOMSASDET =, #o_RXCOMWAKEDET =, # Receive Ports - RX OOB Signaling ports #o_RXCOMINITDET =, # Receive Ports - RX OOB signalling Ports #o_RXELECIDLE =, i_RXELECIDLEMODE=0b11, # Receive Ports - RX Polarity Control Ports i_RXPOLARITY=rx_polarity, # Receive Ports - RX gearbox ports i_RXSLIDE=0, # Receive Ports - RX8B/10B Decoder Ports #o_RXCHARISCOMMA =, o_RXCHARISK=Cat(*[rxdata[10 * i + 8] for i in range(nwords)]), # Receive Ports - Rx Channel Bonding Ports i_RXCHBONDI=0b00000, # Receive Ports -RX Initialization and Reset Ports o_RXRESETDONE=rx_init.Xxresetdone, # Rx AFE Ports i_RXQPIEN=0, #o_RXQPISENN =, #o_RXQPISENP =, # TX Buffer Bypass Ports i_TXPHDLYTSTCLK=0, # TX Configurable Driver Ports i_TXPOSTCURSOR=0b00000, i_TXPOSTCURSORINV=0, i_TXPRECURSOR=0b00000, i_TXPRECURSORINV=0, i_TXQPIBIASEN=0, i_TXQPISTRONGPDOWN=0, i_TXQPIWEAKPUP=0, # TX Initialization and Reset Ports i_CFGRESET=0, i_GTTXRESET=tx_init.gtXxreset, #o_PCSRSVDOUT =, i_TXUSERRDY=tx_init.Xxuserrdy, # Transceiver Reset Mode Operation i_GTRESETSEL=0, i_RESETOVRD=0, # Transmit Ports - 8b10b Encoder Control Ports i_TXCHARDISPMODE=Cat(*[txdata[10 * i + 9] for i in range(nwords)]), i_TXCHARDISPVAL=Cat(*[txdata[10 * i + 8] for i in range(nwords)]), # Transmit Ports - FPGA TX Interface Ports i_TXUSRCLK=ClockSignal("tx"), i_TXUSRCLK2=ClockSignal("tx"), # Transmit Ports - PCI Express Ports i_TXELECIDLE=0, i_TXMARGIN=0b000, i_TXRATE=0b000, i_TXSWING=0, # Transmit Ports - Pattern Generator Ports i_TXPRBSFORCEERR=0, # Transmit Ports - TX Buffer Bypass Ports i_TXDLYBYPASS=1 if tx_buffer_enable else 0, i_TXDLYEN=0, i_TXDLYHOLD=0, i_TXDLYOVRDEN=0, i_TXDLYSRESET=tx_init.Xxdlysreset, o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone, i_TXDLYUPDOWN=0, i_TXPHALIGN=0, o_TXPHALIGNDONE=tx_init.Xxphaligndone, i_TXPHALIGNEN=0, i_TXPHDLYPD=0, i_TXPHDLYRESET=0, i_TXPHINIT=0, #o_TXPHINITDONE =, i_TXPHOVRDEN=0, # Transmit Ports - TX Buffer Ports #o_TXBUFSTATUS =, # Transmit Ports - TX Configurable Driver Ports i_TXBUFDIFFCTRL=0b100, i_TXDEEMPH=0, i_TXDIFFCTRL=0b1000, i_TXDIFFPD=0, i_TXINHIBIT=self.tx_inhibit, i_TXMAINCURSOR=0b0000000, i_TXPISOPD=0, # Transmit Ports - TX Data Path interface i_TXDATA=Cat(*[txdata[10 * i:10 * i + 8] for i in range(nwords)]), # Transmit Ports - TX Driver and OOB signaling o_GTXTXN=tx_pads.n, o_GTXTXP=tx_pads.p, # Transmit Ports - TX Fabric Clock Output Control Ports o_TXOUTCLK=self.txoutclk, #o_TXOUTCLKFABRIC =, #o_TXOUTCLKPCS =, i_TXOUTCLKSEL=0b010 if tx_buffer_enable else 0b011, #o_TXRATEDONE =, # Transmit Ports - TX Gearbox Ports i_TXCHARISK=0b00000000, #o_TXGEARBOXREADY =, i_TXHEADER=0b000, i_TXSEQUENCE=0b0000000, i_TXSTARTSEQ=0, # Transmit Ports - TX Initialization and Reset Ports i_TXPCSRESET=0, i_TXPMARESET=0, o_TXRESETDONE=tx_init.Xxresetdone, # Transmit Ports - TX OOB signaling Ports #o_TXCOMFINISH =, i_TXCOMINIT=0, i_TXCOMSAS=0, i_TXCOMWAKE=0, i_TXPDELECIDLEMODE=0, # Transmit Ports - TX Polarity Control Ports i_TXPOLARITY=tx_polarity, # Transmit Ports - TX Receiver Detection Ports i_TXDETECTRX=0, # Transmit Ports - TX8b/10b Encoder Ports i_TX8B10BBYPASS=0b00000000, # Transmit Ports - pattern Generator Ports i_TXPRBSSEL=0b000, # Tx Configurable Driver Ports #o_TXQPISENN =, #o_TXQPISENP =, ) # TX clocking ------------------------------------------------------------------------------ tx_reset_deglitched = Signal() tx_reset_deglitched.attr.add("no_retiming") self.sync += tx_reset_deglitched.eq(~tx_init.done) self.clock_domains.cd_tx = ClockDomain() txoutclk_bufg = Signal() self.specials += Instance("BUFG", i_I=self.txoutclk, o_O=txoutclk_bufg) if not tx_buffer_enable: txoutclk_div = pll.config["clkin"] / self.tx_clk_freq else: txoutclk_div = 1 # Use txoutclk_bufg when divider is 1 if txoutclk_div == 1: self.comb += self.cd_tx.clk.eq(txoutclk_bufg) self.specials += AsyncResetSynchronizer(self.cd_tx, tx_reset_deglitched) # Use a BUFR when integer divider (with BUFR_DIVIDE) elif txoutclk_div == int(txoutclk_div): txoutclk_bufr = Signal() self.specials += [ Instance("BUFR", i_I=txoutclk_bufg, o_O=txoutclk_bufr, i_CE=1, p_BUFR_DIVIDE=str(int(txoutclk_div))), Instance("BUFG", i_I=txoutclk_bufr, o_O=self.cd_tx.clk), AsyncResetSynchronizer(self.cd_tx, tx_reset_deglitched) ] # Use a PLL when non-integer divider else: txoutclk_pll = S7PLL() self.comb += txoutclk_pll.reset.eq(tx_reset_deglitched) self.submodules += txoutclk_pll txoutclk_pll.register_clkin(txoutclk_bufg, pll.config["clkin"]) txoutclk_pll.create_clkout(self.cd_tx, self.tx_clk_freq) # RX clocking ------------------------------------------------------------------------------ rx_reset_deglitched = Signal() rx_reset_deglitched.attr.add("no_retiming") self.sync.tx += rx_reset_deglitched.eq(~rx_init.done) self.clock_domains.cd_rx = ClockDomain() self.specials += [ Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rx.clk), AsyncResetSynchronizer(self.cd_rx, rx_reset_deglitched) ] # TX Datapath and PRBS --------------------------------------------------------------------- self.submodules.tx_prbs = ClockDomainsRenamer("tx")(PRBSTX( data_width, True)) self.comb += self.tx_prbs.config.eq(tx_prbs_config) self.comb += [ self.tx_prbs.i.eq( Cat(*[self.encoder.output[i] for i in range(nwords)])), If( tx_produce_square_wave, # square wave @ linerate/data_width for scope observation txdata.eq( Signal(data_width, reset=(1 << (data_width // 2)) - 1) )).Elif(tx_produce_pattern, txdata.eq(tx_pattern)).Else(txdata.eq(self.tx_prbs.o)) ] # RX Datapath and PRBS --------------------------------------------------------------------- self.submodules.rx_prbs = ClockDomainsRenamer("rx")(PRBSRX( data_width, True)) self.comb += [ self.rx_prbs.config.eq(rx_prbs_config), rx_prbs_errors.eq(self.rx_prbs.errors) ] for i in range(nwords): self.comb += self.decoders[i].input.eq(rxdata[10 * i:10 * (i + 1)]) self.comb += self.rx_prbs.i.eq(rxdata) # Clock Aligner ---------------------------------------------------------------------------- if clock_aligner: clock_aligner = BruteforceClockAligner(clock_aligner_comma, self.tx_clk_freq) self.submodules.clock_aligner = clock_aligner ps_restart = PulseSynchronizer("tx", "sys") self.submodules += ps_restart self.comb += [ clock_aligner.rxdata.eq(rxdata), ps_restart.i.eq(clock_aligner.restart), rx_init.restart.eq((ps_restart.o & self.rx_align) | ~self.rx_enable), self.rx_ready.eq(clock_aligner.ready) ]
def __init__(self, qpll, tx_pads, rx_pads, sys_clk_freq, data_width=20, tx_buffer_enable=False, rx_buffer_enable=False, clock_aligner=True, clock_aligner_comma=0b0101111100, tx_polarity=0, rx_polarity=0): assert (data_width == 20) # TX controls self.tx_enable = Signal() self.tx_ready = Signal() self.tx_inhibit = Signal() self.tx_produce_square_wave = Signal() self.tx_produce_pattern = Signal() self.tx_pattern = Signal(data_width) self.tx_prbs_config = Signal(2) # RX controls self.rx_enable = Signal() self.rx_ready = Signal() self.rx_align = Signal(reset=1) self.rx_prbs_config = Signal(2) self.rx_prbs_errors = Signal(32) # DRP self.drp = DRPInterface() # Loopback self.loopback = Signal(3) # # # self.nwords = nwords = data_width//10 self.submodules.encoder = ClockDomainsRenamer("tx")(Encoder(nwords, True)) self.decoders = [ClockDomainsRenamer("rx")(Decoder(True)) for _ in range(nwords)] self.submodules += self.decoders # Transceiver direct clock outputs (useful to specify clock constraints) self.txoutclk = Signal() self.rxoutclk = Signal() self.tx_clk_freq = qpll.config["linerate"]/data_width self.rx_clk_freq = qpll.config["linerate"]/data_width # Control/Status CDC tx_produce_square_wave = Signal() tx_produce_pattern = Signal() tx_prbs_config = Signal(2) rx_prbs_config = Signal(2) rx_prbs_errors = Signal(32) self.specials += [ MultiReg(self.tx_produce_square_wave, tx_produce_square_wave, "tx"), MultiReg(self.tx_produce_pattern, tx_produce_pattern, "tx"), MultiReg(self.tx_prbs_config, tx_prbs_config, "tx"), ] self.specials += [ MultiReg(self.rx_prbs_config, rx_prbs_config, "rx"), MultiReg(rx_prbs_errors, self.rx_prbs_errors, "sys"), # FIXME ] # # # assert qpll.config["linerate"] < 6.6e9 rxcdr_cfgs = { 1 : 0x0000107FE406001041010, 2 : 0x0000107FE206001041010, 4 : 0x0000107FE106001041010, 8 : 0x0000107FE086001041010, 16 : 0x0000107FE086001041010, } # TX init ---------------------------------------------------------------------------------- self.submodules.tx_init = tx_init = GTPTXInit(sys_clk_freq, buffer_enable=tx_buffer_enable) self.comb += [ self.tx_ready.eq(tx_init.done), tx_init.restart.eq(~self.tx_enable) ] # RX init ---------------------------------------------------------------------------------- self.submodules.rx_init = rx_init = GTPRXInit(sys_clk_freq, buffer_enable=rx_buffer_enable) self.comb += [ self.rx_ready.eq(rx_init.done), rx_init.restart.eq(~self.rx_enable) ] # PLL ---------------------------------------------------------------------------------- self.comb += [ tx_init.plllock.eq(qpll.lock), rx_init.plllock.eq(qpll.lock), qpll.reset.eq(tx_init.pllreset) ] # DRP mux ---------------------------------------------------------------------------------- self.submodules.drp_mux = drp_mux = DRPMux() drp_mux.add_interface(rx_init.drp) drp_mux.add_interface(self.drp) # GTPE2_CHANNEL instance ------------------------------------------------------------------- txdata = Signal(data_width) rxdata = Signal(data_width) rxphaligndone = Signal() self.gtp_params = dict( # Simulation-Only Attributes p_SIM_RECEIVER_DETECT_PASS = "******", p_SIM_TX_EIDLE_DRIVE_LEVEL = "X", p_SIM_RESET_SPEEDUP = "FALSE", p_SIM_VERSION = "2.0", # RX Byte and Word Alignment Attributes p_ALIGN_COMMA_DOUBLE = "FALSE", p_ALIGN_COMMA_ENABLE = 0b1111111111, p_ALIGN_COMMA_WORD = 2 if data_width == 20 else 4, p_ALIGN_MCOMMA_DET = "TRUE", p_ALIGN_MCOMMA_VALUE = 0b1010000011, p_ALIGN_PCOMMA_DET = "TRUE", p_ALIGN_PCOMMA_VALUE = 0b0101111100, p_SHOW_REALIGN_COMMA = "TRUE", p_RXSLIDE_AUTO_WAIT = 7, p_RXSLIDE_MODE = "OFF" if rx_buffer_enable else "PCS", p_RX_SIG_VALID_DLY = 10, # RX 8B/10B Decoder Attributes p_RX_DISPERR_SEQ_MATCH = "TRUE", p_DEC_MCOMMA_DETECT = "TRUE", p_DEC_PCOMMA_DETECT = "TRUE", p_DEC_VALID_COMMA_ONLY = "TRUE", # RX Clock Correction Attributes p_CBCC_DATA_SOURCE_SEL = "DECODED", p_CLK_COR_SEQ_2_USE = "FALSE", p_CLK_COR_KEEP_IDLE = "FALSE", p_CLK_COR_MAX_LAT = 10 if data_width == 20 else 19, p_CLK_COR_MIN_LAT = 8 if data_width == 20 else 15, p_CLK_COR_PRECEDENCE = "TRUE", p_CLK_COR_REPEAT_WAIT = 0, p_CLK_COR_SEQ_LEN = 1, p_CLK_COR_SEQ_1_ENABLE = 0b1111, p_CLK_COR_SEQ_1_1 = 0b0100000000, p_CLK_COR_SEQ_1_2 = 0b0000000000, p_CLK_COR_SEQ_1_3 = 0b0000000000, p_CLK_COR_SEQ_1_4 = 0b0000000000, p_CLK_CORRECT_USE = "FALSE", p_CLK_COR_SEQ_2_ENABLE = 0b1111, p_CLK_COR_SEQ_2_1 = 0b0100000000, p_CLK_COR_SEQ_2_2 = 0b0000000000, p_CLK_COR_SEQ_2_3 = 0b0000000000, p_CLK_COR_SEQ_2_4 = 0b0000000000, # RX Channel Bonding Attributes p_CHAN_BOND_KEEP_ALIGN = "FALSE", p_CHAN_BOND_MAX_SKEW = 1, p_CHAN_BOND_SEQ_LEN = 1, p_CHAN_BOND_SEQ_1_1 = 0b0000000000, p_CHAN_BOND_SEQ_1_2 = 0b0000000000, p_CHAN_BOND_SEQ_1_3 = 0b0000000000, p_CHAN_BOND_SEQ_1_4 = 0b0000000000, p_CHAN_BOND_SEQ_1_ENABLE = 0b1111, p_CHAN_BOND_SEQ_2_1 = 0b0000000000, p_CHAN_BOND_SEQ_2_2 = 0b0000000000, p_CHAN_BOND_SEQ_2_3 = 0b0000000000, p_CHAN_BOND_SEQ_2_4 = 0b0000000000, p_CHAN_BOND_SEQ_2_ENABLE = 0b1111, p_CHAN_BOND_SEQ_2_USE = "FALSE", p_FTS_DESKEW_SEQ_ENABLE = 0b1111, p_FTS_LANE_DESKEW_CFG = 0b1111, p_FTS_LANE_DESKEW_EN = "FALSE", # RX Margin Analysis Attributes p_ES_CONTROL = 0b000000, p_ES_ERRDET_EN = "FALSE", p_ES_EYE_SCAN_EN = "TRUE", p_ES_HORZ_OFFSET = 0x000, p_ES_PMA_CFG = 0b0000000000, p_ES_PRESCALE = 0b00000, p_ES_QUALIFIER = 0x00000000000000000000, p_ES_QUAL_MASK = 0x00000000000000000000, p_ES_SDATA_MASK = 0x00000000000000000000, p_ES_VERT_OFFSET = 0b000000000, # FPGA RX Interface Attributes p_RX_DATA_WIDTH = data_width, # PMA Attributes p_OUTREFCLK_SEL_INV = 0b11, p_PMA_RSV = 0x00000333, p_PMA_RSV2 = 0x00002040, p_PMA_RSV3 = 0b00, p_PMA_RSV4 = 0b0000, p_RX_BIAS_CFG = 0b0000111100110011, p_DMONITOR_CFG = 0x000A00, p_RX_CM_SEL = 0b01, p_RX_CM_TRIM = 0b0000, p_RX_DEBUG_CFG = 0b00000000000000, p_RX_OS_CFG = 0b0000010000000, p_TERM_RCAL_CFG = 0b100001000010000, p_TERM_RCAL_OVRD = 0b000, p_TST_RSV = 0x00000000, p_RX_CLK25_DIV = 5, p_TX_CLK25_DIV = 5, p_UCODEER_CLR = 0b0, # PCI Express Attributes p_PCS_PCIE_EN = "FALSE", # PCS Attributes p_PCS_RSVD_ATTR = 0x000000000000, # RX Buffer Attributes p_RXBUF_ADDR_MODE = "FAST", p_RXBUF_EIDLE_HI_CNT = 0b1000, p_RXBUF_EIDLE_LO_CNT = 0b0000, p_RXBUF_EN = "TRUE" if rx_buffer_enable else "FALSE", p_RX_BUFFER_CFG = 0b000000, p_RXBUF_RESET_ON_CB_CHANGE = "TRUE", p_RXBUF_RESET_ON_COMMAALIGN = "FALSE", p_RXBUF_RESET_ON_EIDLE = "FALSE", p_RXBUF_RESET_ON_RATE_CHANGE = "TRUE", p_RXBUFRESET_TIME = 0b00001, p_RXBUF_THRESH_OVFLW = 61, p_RXBUF_THRESH_OVRD = "FALSE", p_RXBUF_THRESH_UNDFLW = 4, p_RXDLY_CFG = 0x001F, p_RXDLY_LCFG = 0x030, p_RXDLY_TAP_CFG = 0x0000, p_RXPH_CFG = 0xC00002, p_RXPHDLY_CFG = 0x084020, p_RXPH_MONITOR_SEL = 0b00000, p_RX_XCLK_SEL = "RXREC" if rx_buffer_enable else "RXUSR", p_RX_DDI_SEL = 0b000000, p_RX_DEFER_RESET_BUF_EN = "TRUE", # CDR Attributes p_RXCDR_CFG = rxcdr_cfgs[qpll.config["d"]], p_RXCDR_FR_RESET_ON_EIDLE = 0b0, p_RXCDR_HOLD_DURING_EIDLE = 0b0, p_RXCDR_PH_RESET_ON_EIDLE = 0b0, p_RXCDR_LOCK_CFG = 0b001001, # RX Initialization and Reset Attributes p_RXCDRFREQRESET_TIME = 0b00001, p_RXCDRPHRESET_TIME = 0b00001, p_RXISCANRESET_TIME = 0b00001, p_RXPCSRESET_TIME = 0b00001, p_RXPMARESET_TIME = 0b00011, # RX OOB Signaling Attributes p_RXOOB_CFG = 0b0000110, # RX Gearbox Attributes p_RXGEARBOX_EN = "FALSE", p_GEARBOX_MODE = 0b000, # PRBS Detection Attribute p_RXPRBS_ERR_LOOPBACK = 0b0, # Power-Down Attributes p_PD_TRANS_TIME_FROM_P2 = 0x03c, p_PD_TRANS_TIME_NONE_P2 = 0x3c, p_PD_TRANS_TIME_TO_P2 = 0x64, # RX OOB Signaling Attributes p_SAS_MAX_COM = 64, p_SAS_MIN_COM = 36, p_SATA_BURST_SEQ_LEN = 0b0101, p_SATA_BURST_VAL = 0b100, p_SATA_EIDLE_VAL = 0b100, p_SATA_MAX_BURST = 8, p_SATA_MAX_INIT = 21, p_SATA_MAX_WAKE = 7, p_SATA_MIN_BURST = 4, p_SATA_MIN_INIT = 12, p_SATA_MIN_WAKE = 4, # RX Fabric Clock Output Control Attributes p_TRANS_TIME_RATE = 0x0E, # TX Buffer Attributes p_TXBUF_EN = "TRUE" if tx_buffer_enable else "FALSE", p_TXBUF_RESET_ON_RATE_CHANGE = "TRUE", p_TXDLY_CFG = 0x001F, p_TXDLY_LCFG = 0x030, p_TXDLY_TAP_CFG = 0x0000, p_TXPH_CFG = 0x0780, p_TXPHDLY_CFG = 0x084020, p_TXPH_MONITOR_SEL = 0b00000, p_TX_XCLK_SEL = "TXOUT" if tx_buffer_enable else "TXUSR", # FPGA TX Interface Attributes p_TX_DATA_WIDTH = data_width, # TX Configurable Driver Attributes p_TX_DEEMPH0 = 0b000000, p_TX_DEEMPH1 = 0b000000, p_TX_EIDLE_ASSERT_DELAY = 0b110, p_TX_EIDLE_DEASSERT_DELAY = 0b100, p_TX_LOOPBACK_DRIVE_HIZ = "FALSE", p_TX_MAINCURSOR_SEL = 0b0, p_TX_DRIVE_MODE = "DIRECT", p_TX_MARGIN_FULL_0 = 0b1001110, p_TX_MARGIN_FULL_1 = 0b1001001, p_TX_MARGIN_FULL_2 = 0b1000101, p_TX_MARGIN_FULL_3 = 0b1000010, p_TX_MARGIN_FULL_4 = 0b1000000, p_TX_MARGIN_LOW_0 = 0b1000110, p_TX_MARGIN_LOW_1 = 0b1000100, p_TX_MARGIN_LOW_2 = 0b1000010, p_TX_MARGIN_LOW_3 = 0b1000000, p_TX_MARGIN_LOW_4 = 0b1000000, # TX Gearbox Attributes p_TXGEARBOX_EN = "FALSE", # TX Initialization and Reset Attributes p_TXPCSRESET_TIME = 0b00001, p_TXPMARESET_TIME = 0b00001, # TX Receiver Detection Attributes p_TX_RXDETECT_CFG = 0x1832, p_TX_RXDETECT_REF = 0b100, # JTAG Attributes p_ACJTAG_DEBUG_MODE = 0b0, p_ACJTAG_MODE = 0b0, p_ACJTAG_RESET = 0b0, # CDR Attributes p_CFOK_CFG = 0x49000040E80, p_CFOK_CFG2 = 0b0100000, p_CFOK_CFG3 = 0b0100000, p_CFOK_CFG4 = 0b0, p_CFOK_CFG5 = 0x0, p_CFOK_CFG6 = 0b0000, p_RXOSCALRESET_TIME = 0b00011, p_RXOSCALRESET_TIMEOUT = 0b00000, # PMA Attributes p_CLK_COMMON_SWING = 0b0, p_RX_CLKMUX_EN = 0b1, p_TX_CLKMUX_EN = 0b1, p_ES_CLK_PHASE_SEL = 0b0, p_USE_PCS_CLK_PHASE_SEL = 0b0, p_PMA_RSV6 = 0b0, p_PMA_RSV7 = 0b0, # TX Configuration Driver Attributes p_TX_PREDRIVER_MODE = 0b0, p_PMA_RSV5 = 0b0, p_SATA_PLL_CFG = "VCO_3000MHZ", # RX Fabric Clock Output Control Attributes p_RXOUT_DIV = qpll.config["d"], # TX Fabric Clock Output Control Attributes p_TXOUT_DIV = qpll.config["d"], # RX Phase Interpolator Attributes p_RXPI_CFG0 = 0b000, p_RXPI_CFG1 = 0b1, p_RXPI_CFG2 = 0b1, # RX Equalizer Attributes p_ADAPT_CFG0 = 0x00000, p_RXLPMRESET_TIME = 0b0001111, p_RXLPM_BIAS_STARTUP_DISABLE = 0b0, p_RXLPM_CFG = 0b0110, p_RXLPM_CFG1 = 0b0, p_RXLPM_CM_CFG = 0b0, p_RXLPM_GC_CFG = 0b111100010, p_RXLPM_GC_CFG2 = 0b001, p_RXLPM_HF_CFG = 0b00001111110000, p_RXLPM_HF_CFG2 = 0b01010, p_RXLPM_HF_CFG3 = 0b0000, p_RXLPM_HOLD_DURING_EIDLE = 0b0, p_RXLPM_INCM_CFG = 0b0, p_RXLPM_IPCM_CFG = 0b1, p_RXLPM_LF_CFG = 0b000000001111110000, p_RXLPM_LF_CFG2 = 0b01010, p_RXLPM_OSINT_CFG = 0b100, # TX Phase Interpolator PPM Controller Attributes p_TXPI_CFG0 = 0b00, p_TXPI_CFG1 = 0b00, p_TXPI_CFG2 = 0b00, p_TXPI_CFG3 = 0b0, p_TXPI_CFG4 = 0b0, p_TXPI_CFG5 = 0b000, p_TXPI_GREY_SEL = 0b0, p_TXPI_INVSTROBE_SEL = 0b0, p_TXPI_PPMCLK_SEL = "TXUSRCLK2", p_TXPI_PPM_CFG = 0x00, p_TXPI_SYNFREQ_PPM = 0b001, # LOOPBACK Attributes p_LOOPBACK_CFG = 0b0, p_PMA_LOOPBACK_CFG = 0b0, # RX OOB Signalling Attributes p_RXOOB_CLK_CFG = "PMA", # TX OOB Signalling Attributes p_TXOOB_CFG = 0b0, # RX Buffer Attributes p_RXSYNC_MULTILANE = 0b0, p_RXSYNC_OVRD = 0b0, p_RXSYNC_SKIP_DA = 0b0, # TX Buffer Attributes p_TXSYNC_MULTILANE = 0b0, p_TXSYNC_OVRD = 0b1 if tx_buffer_enable else 0b0, p_TXSYNC_SKIP_DA = 0b0 ) self.gtp_params.update( # CPLL Ports i_GTRSVD = 0b0000000000000000, i_PCSRSVDIN = 0b0000000000000000, i_TSTIN = 0b11111111111111111111, # Channel - DRP Ports i_DRPADDR = drp_mux.addr, i_DRPCLK = drp_mux.clk, i_DRPDI = drp_mux.di, o_DRPDO = drp_mux.do, i_DRPEN = drp_mux.en, o_DRPRDY = drp_mux.rdy, i_DRPWE = drp_mux.we, # Clocking Ports i_RXSYSCLKSEL = 0b00 if qpll.channel == 0 else 0b11, i_TXSYSCLKSEL = 0b00 if qpll.channel == 0 else 0b11, # FPGA TX Interface Datapath Configuration i_TX8B10BEN = 0, # GTPE2_CHANNEL Clocking Ports i_PLL0CLK = qpll.clk if qpll.channel == 0 else 0, i_PLL0REFCLK = qpll.refclk if qpll.channel == 0 else 0, i_PLL1CLK = qpll.clk if qpll.channel == 1 else 0, i_PLL1REFCLK = qpll.refclk if qpll.channel == 1 else 0, # Loopback Ports i_LOOPBACK = self.loopback, # PCI Express Ports #o_PHYSTATUS =, i_RXRATE = 0, #o_RXVALID =, # PMA Reserved Ports i_PMARSVDIN3 = 0b0, i_PMARSVDIN4 = 0b0, # Power-Down Ports i_RXPD = Cat(rx_init.gtrxpd, rx_init.gtrxpd), i_TXPD = 0b00, # RX 8B/10B Decoder Ports i_SETERRSTATUS = 0, # RX Initialization and Reset Ports i_EYESCANRESET = 0, i_RXUSERRDY = rx_init.rxuserrdy, # RX Margin Analysis Ports #o_EYESCANDATAERROR =, i_EYESCANMODE = 0, i_EYESCANTRIGGER = 0, # Receive Ports i_CLKRSVD0 = 0, i_CLKRSVD1 = 0, i_DMONFIFORESET = 0, i_DMONITORCLK = 0, o_RXPMARESETDONE = rx_init.rxpmaresetdone, i_SIGVALIDCLK = 0, # Receive Ports - CDR Ports i_RXCDRFREQRESET = 0, i_RXCDRHOLD = 0, #o_RXCDRLOCK =, i_RXCDROVRDEN = 0, i_RXCDRRESET = 0, i_RXCDRRESETRSV = 0, i_RXOSCALRESET = 0, i_RXOSINTCFG = 0b0010, #o_RXOSINTDONE =, i_RXOSINTHOLD = 0, i_RXOSINTOVRDEN = 0, i_RXOSINTPD = 0, #o_RXOSINTSTARTED =, i_RXOSINTSTROBE = 0, #o_RXOSINTSTROBESTARTED =, i_RXOSINTTESTOVRDEN = 0, # Receive Ports - Clock Correction Ports #o_RXCLKCORCNT =, # Receive Ports - FPGA RX Interface Datapath Configuration i_RX8B10BEN = 0, # Receive Ports - FPGA RX Interface Ports o_RXDATA = Cat(*[rxdata[10*i:10*i+8] for i in range(nwords)]), i_RXUSRCLK = ClockSignal("rx"), i_RXUSRCLK2 = ClockSignal("rx"), # Receive Ports - Pattern Checker Ports #o_RXPRBSERR =, i_RXPRBSSEL = 0, # Receive Ports - Pattern Checker ports i_RXPRBSCNTRESET = 0, # Receive Ports - RX 8B/10B Decoder Ports #o_RXCHARISCOMMA =, o_RXCHARISK = Cat(*[rxdata[10*i+8] for i in range(nwords)]), o_RXDISPERR = Cat(*[rxdata[10*i+9] for i in range(nwords)]), #o_RXNOTINTABLE =, # Receive Ports - RX AFE Ports i_GTPRXN = rx_pads.n, i_GTPRXP = rx_pads.p, i_PMARSVDIN2 = 0b0, #o_PMARSVDOUT0 =, #o_PMARSVDOUT1 =, # Receive Ports - RX Buffer Bypass Ports i_RXBUFRESET = 0, #o_RXBUFSTATUS =, i_RXDDIEN = 0 if rx_buffer_enable else 1, i_RXDLYBYPASS = 1 if rx_buffer_enable else 0, i_RXDLYEN = 0, i_RXDLYOVRDEN = 0, i_RXDLYSRESET = rx_init.rxdlysreset, o_RXDLYSRESETDONE = rx_init.rxdlysresetdone, i_RXPHALIGN = 0, o_RXPHALIGNDONE = rxphaligndone, i_RXPHALIGNEN = 0, i_RXPHDLYPD = 0, i_RXPHDLYRESET = 0, #o_RXPHMONITOR =, i_RXPHOVRDEN = 0, #o_RXPHSLIPMONITOR =, #o_RXSTATUS =, i_RXSYNCALLIN = rxphaligndone, o_RXSYNCDONE = rx_init.rxsyncdone, i_RXSYNCIN = 0, i_RXSYNCMODE = 0 if rx_buffer_enable else 1, #o_RXSYNCOUT =, # Receive Ports - RX Byte and Word Alignment Ports #o_RXBYTEISALIGNED =, #o_RXBYTEREALIGN =, #o_RXCOMMADET =, i_RXCOMMADETEN = 1, i_RXMCOMMAALIGNEN = (~clock_aligner & self.rx_align & (rx_prbs_config == 0b00)) if rx_buffer_enable else 0, i_RXPCOMMAALIGNEN = (~clock_aligner & self.rx_align & (rx_prbs_config == 0b00)) if rx_buffer_enable else 0, i_RXSLIDE = 0, # Receive Ports - RX Channel Bonding Ports #o_RXCHANBONDSEQ =, i_RXCHBONDEN = 0, i_RXCHBONDI = 0b0000, i_RXCHBONDLEVEL = 0, i_RXCHBONDMASTER = 0, #o_RXCHBONDO =, i_RXCHBONDSLAVE = 0, # Receive Ports - RX Channel Bonding Ports #o_RXCHANISALIGNED =, #o_RXCHANREALIGN =, # Receive Ports - RX Decision Feedback Equalizer #o_DMONITOROUT =, i_RXADAPTSELTEST = 0, i_RXDFEXYDEN = 0, i_RXOSINTEN = 0b1, i_RXOSINTID0 = 0, i_RXOSINTNTRLEN = 0, #o_RXOSINTSTROBEDONE =, # Receive Ports - RX Driver,OOB signalling,Coupling and Eq.,CDR i_RXLPMLFOVRDEN = 0, i_RXLPMOSINTNTRLEN = 0, # Receive Ports - RX Equalizer Ports i_RXLPMHFHOLD = 0, i_RXLPMHFOVRDEN = 0, i_RXLPMLFHOLD = 0, i_RXOSHOLD = 0, i_RXOSOVRDEN = 0, # Receive Ports - RX Fabric ClocK Output Control Ports #o_RXRATEDONE =, # Receive Ports - RX Fabric Clock Output Control Ports i_RXRATEMODE = 0b0, # Receive Ports - RX Fabric Output Control Ports o_RXOUTCLK = self.rxoutclk, #o_RXOUTCLKFABRIC =, #o_RXOUTCLKPCS =, i_RXOUTCLKSEL = 0b010, # Receive Ports - RX Gearbox Ports #o_RXDATAVALID =, #o_RXHEADER =, #o_RXHEADERVALID =, #o_RXSTARTOFSEQ =, i_RXGEARBOXSLIP = 0, # Receive Ports - RX Initialization and Reset Ports i_GTRXRESET = rx_init.gtrxreset, i_RXLPMRESET = 0, i_RXOOBRESET = 0, i_RXPCSRESET = 0, i_RXPMARESET = 0, # Receive Ports - RX OOB Signaling ports #o_RXCOMSASDET =, #o_RXCOMWAKEDET =, #o_RXCOMINITDET =, #o_RXELECIDLE =, i_RXELECIDLEMODE = 0b11, # Receive Ports - RX Polarity Control Ports i_RXPOLARITY = rx_polarity, # Receive Ports -RX Initialization and Reset Ports o_RXRESETDONE = rx_init.rxresetdone, # TX Buffer Bypass Ports i_TXPHDLYTSTCLK = 0, # TX Configurable Driver Ports i_TXPOSTCURSOR = 0b00000, i_TXPOSTCURSORINV = 0, i_TXPRECURSOR = 0b00000, i_TXPRECURSORINV = 0, # TX Fabric Clock Output Control Ports i_TXRATEMODE = 0, # TX Initialization and Reset Ports i_CFGRESET = 0, i_GTTXRESET = tx_init.gttxreset, #o_PCSRSVDOUT =, i_TXUSERRDY = tx_init.txuserrdy, # TX Phase Interpolator PPM Controller Ports i_TXPIPPMEN = 0, i_TXPIPPMOVRDEN = 0, i_TXPIPPMPD = 0, i_TXPIPPMSEL = 1, i_TXPIPPMSTEPSIZE = 0, # Transceiver Reset Mode Operation i_GTRESETSEL = 0, i_RESETOVRD = 0, # Transmit Ports #o_TXPMARESETDONE =, # Transmit Ports - Configurable Driver Ports i_PMARSVDIN0 = 0b0, i_PMARSVDIN1 = 0b0, # Transmit Ports - FPGA TX Interface Ports i_TXDATA = Cat(*[txdata[10*i:10*i+8] for i in range(nwords)]), i_TXUSRCLK = ClockSignal("tx"), i_TXUSRCLK2 = ClockSignal("tx"), # Transmit Ports - PCI Express Ports i_TXELECIDLE = 0, i_TXMARGIN = 0, i_TXRATE = 0, i_TXSWING = 0, # Transmit Ports - Pattern Generator Ports i_TXPRBSFORCEERR = 0, # Transmit Ports - TX 8B/10B Encoder Ports i_TX8B10BBYPASS = 0, i_TXCHARDISPMODE = Cat(*[txdata[10*i+9] for i in range(nwords)]), i_TXCHARDISPVAL = Cat(*[txdata[10*i+8] for i in range(nwords)]), i_TXCHARISK = 0, # Transmit Ports - TX Buffer Bypass Ports i_TXDLYBYPASS = 1 if tx_buffer_enable else 0, i_TXDLYEN = tx_init.txdlyen, i_TXDLYHOLD = 0, i_TXDLYOVRDEN = 0, i_TXDLYSRESET = tx_init.txdlysreset, o_TXDLYSRESETDONE = tx_init.txdlysresetdone, i_TXDLYUPDOWN = 0, i_TXPHALIGN = tx_init.txphalign, o_TXPHALIGNDONE = tx_init.txphaligndone, i_TXPHALIGNEN = 0 if tx_buffer_enable else 1, i_TXPHDLYPD = 0, i_TXPHDLYRESET = 0, i_TXPHINIT = tx_init.txphinit, o_TXPHINITDONE = tx_init.txphinitdone, i_TXPHOVRDEN = 0, # Transmit Ports - TX Buffer Ports #o_TXBUFSTATUS =, # Transmit Ports - TX Buffer and Phase Alignment Ports i_TXSYNCALLIN = 0, #o_TXSYNCDONE =, #i_TXSYNCIN = 0, #i_TXSYNCMODE = 0, #o_TXSYNCOUT =, # Transmit Ports - TX Configurable Driver Ports o_GTPTXN = tx_pads.n, o_GTPTXP = tx_pads.p, i_TXBUFDIFFCTRL = 0b100, i_TXDEEMPH = 0, i_TXDIFFCTRL = 0b1000, i_TXDIFFPD = 0, i_TXINHIBIT = self.tx_inhibit, i_TXMAINCURSOR = 0b0000000, i_TXPISOPD = 0, # Transmit Ports - TX Fabric Clock Output Control Ports o_TXOUTCLK = self.txoutclk, #o_TXOUTCLKFABRIC =, #o_TXOUTCLKPCS =, i_TXOUTCLKSEL = 0b010 if tx_buffer_enable else 0b011, #o_TXRATEDONE =, # Transmit Ports - TX Gearbox Ports #o_TXGEARBOXREADY =, i_TXHEADER = 0, i_TXSEQUENCE = 0, i_TXSTARTSEQ = 0, # Transmit Ports - TX Initialization and Reset Ports i_TXPCSRESET = 0, i_TXPMARESET = 0, o_TXRESETDONE = tx_init.txresetdone, # Transmit Ports - TX OOB signalling Ports #o_TXCOMFINISH =, i_TXCOMINIT = 0, i_TXCOMSAS = 0, i_TXCOMWAKE = 0, i_TXPDELECIDLEMODE = 0, # Transmit Ports - TX Polarity Control Ports i_TXPOLARITY = tx_polarity, # Transmit Ports - TX Receiver Detection Ports i_TXDETECTRX = 0, # Transmit Ports - pattern Generator Ports i_TXPRBSSEL = 0, ) # TX clocking ------------------------------------------------------------------------------ tx_reset_deglitched = Signal() tx_reset_deglitched.attr.add("no_retiming") self.sync += tx_reset_deglitched.eq(~tx_init.done) self.clock_domains.cd_tx = ClockDomain() txoutclk_bufg = Signal() self.specials += Instance("BUFG", i_I=self.txoutclk, o_O=txoutclk_bufg) if not tx_buffer_enable: txoutclk_div = qpll.config["clkin"]/self.tx_clk_freq else: txoutclk_div = 1 # Use txoutclk_bufg when divider is 1 if txoutclk_div == 1: self.comb += self.cd_tx.clk.eq(txoutclk_bufg) self.specials += AsyncResetSynchronizer(self.cd_tx, tx_reset_deglitched) # Use a BUFR when integer divider (with BUFR_DIVIDE) elif txoutclk_div == int(txoutclk_div): txoutclk_bufr = Signal() self.specials += [ Instance("BUFR", i_I=txoutclk_bufg, o_O=txoutclk_bufr, i_CE=1, p_BUFR_DIVIDE=str(int(txoutclk_div))), Instance("BUFG", i_I=txoutclk_bufr, o_O=self.cd_tx.clk), AsyncResetSynchronizer(self.cd_tx, tx_reset_deglitched) ] # Use a PLL when non-integer divider else: txoutclk_pll = S7PLL() self.comb += txoutclk_pll.reset.eq(tx_reset_deglitched) self.submodules += txoutclk_pll txoutclk_pll.register_clkin(txoutclk_bufg, qpll.config["clkin"]) txoutclk_pll.create_clkout(self.cd_tx, self.tx_clk_freq) # RX clocking ------------------------------------------------------------------------------ rx_reset_deglitched = Signal() rx_reset_deglitched.attr.add("no_retiming") self.sync.tx += rx_reset_deglitched.eq(~rx_init.done) self.clock_domains.cd_rx = ClockDomain() self.specials += [ Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rx.clk), AsyncResetSynchronizer(self.cd_rx, rx_reset_deglitched) ] # TX Datapath and PRBS --------------------------------------------------------------------- self.submodules.tx_prbs = ClockDomainsRenamer("tx")(PRBSTX(data_width, True)) self.comb += self.tx_prbs.config.eq(tx_prbs_config) self.comb += [ self.tx_prbs.i.eq(Cat(*[self.encoder.output[i] for i in range(nwords)])), If(tx_produce_square_wave, # square wave @ linerate/data_width for scope observation txdata.eq(Signal(data_width, reset=(1<<(data_width//2))-1)) ).Elif(tx_produce_pattern, txdata.eq(self.tx_pattern) ).Else( txdata.eq(self.tx_prbs.o) ) ] # RX Datapath and PRBS --------------------------------------------------------------------- self.submodules.rx_prbs = ClockDomainsRenamer("rx")(PRBSRX(data_width, True)) self.comb += [ self.rx_prbs.config.eq(rx_prbs_config), rx_prbs_errors.eq(self.rx_prbs.errors) ] for i in range(nwords): self.comb += self.decoders[i].input.eq(rxdata[10*i:10*(i+1)]) self.comb += self.rx_prbs.i.eq(rxdata) # Clock Aligner ---------------------------------------------------------------------------- if clock_aligner: clock_aligner = BruteforceClockAligner(clock_aligner_comma, self.tx_clk_freq, check_period=10e-3) self.submodules.clock_aligner = clock_aligner ps_restart = PulseSynchronizer("tx", "sys") self.submodules += ps_restart self.comb += [ clock_aligner.rxdata.eq(rxdata), ps_restart.i.eq(clock_aligner.restart), rx_init.restart.eq((ps_restart.o & self.rx_align) | ~self.rx_enable), self.rx_ready.eq(clock_aligner.ready) ]