def __init__(self, qpll_channel, pads, sys_clk_freq, rtio_clk_freq, mode): assert mode in ["single", "master", "slave"] self.mode = mode # # # self.stable_clkin = Signal() self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( Encoder(2, True)) self.submodules.decoders = decoders = [ ClockDomainsRenamer("rtio_rx")((Decoder(True))) for _ in range(2) ] self.rx_ready = Signal() # transceiver direct clock outputs # useful to specify clock constraints in a way palatable to Vivado self.txoutclk = Signal() self.rxoutclk = Signal() # # # # TX generates RTIO clock, init must be in system domain self.submodules.tx_init = tx_init = GTPTXInit(sys_clk_freq, mode) # RX receives restart commands from RTIO domain rx_init = ClockDomainsRenamer("rtio_tx")(GTPRXInit(rtio_clk_freq)) self.submodules += rx_init self.comb += [ tx_init.stable_clkin.eq(self.stable_clkin), qpll_channel.reset.eq(tx_init.pllreset), tx_init.plllock.eq(qpll_channel.lock) ] txdata = Signal(20) rxdata = Signal(20) rxphaligndone = Signal() 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=1, p_ALIGN_MCOMMA_DET="TRUE", p_ALIGN_MCOMMA_VALUE=0b1010000011, p_ALIGN_PCOMMA_DET="TRUE", p_ALIGN_PCOMMA_VALUE=0b0101111100, p_SHOW_REALIGN_COMMA="FALSE", p_RXSLIDE_AUTO_WAIT=7, p_RXSLIDE_MODE="PCS", p_RX_SIG_VALID_DLY=10, # RX 8B/10B Decoder Attributes p_RX_DISPERR_SEQ_MATCH="FALSE", p_DEC_MCOMMA_DETECT="TRUE", p_DEC_PCOMMA_DETECT="TRUE", p_DEC_VALID_COMMA_ONLY="FALSE", # RX Clock Correction Attributes p_CBCC_DATA_SOURCE_SEL="ENCODED", p_CLK_COR_SEQ_2_USE="FALSE", p_CLK_COR_KEEP_IDLE="FALSE", p_CLK_COR_MAX_LAT=9, p_CLK_COR_MIN_LAT=7, 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="FALSE", p_ES_HORZ_OFFSET=0x010, 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=20, # 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="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="RXUSR", p_RX_DDI_SEL=0b000000, p_RX_DEFER_RESET_BUF_EN="TRUE", # CDR Attributes p_RXCDR_CFG=0x0001107FE206021081010, 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="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="TXUSR", # FPGA TX Interface Attributes p_TX_DATA_WIDTH=20, # 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=2, # TX Fabric Clock Output Control Attributes p_TXOUT_DIV=2, # 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, p_TXSYNC_SKIP_DA=0b0) gtp_params.update( # CPLL Ports i_GTRSVD=0b0000000000000000, i_PCSRSVDIN=0b0000000000000000, i_TSTIN=0b11111111111111111111, # Channel - DRP Ports i_DRPADDR=rx_init.drpaddr, i_DRPCLK=ClockSignal("rtio_tx"), i_DRPDI=rx_init.drpdi, o_DRPDO=rx_init.drpdo, i_DRPEN=rx_init.drpen, o_DRPRDY=rx_init.drprdy, i_DRPWE=rx_init.drpwe, # FPGA TX Interface Datapath Configuration i_TX8B10BEN=0, # Loopback Ports i_LOOPBACK=0, # 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[:8], rxdata[10:18]), i_RXUSRCLK=ClockSignal("rtio_rx"), i_RXUSRCLK2=ClockSignal("rtio_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[8], rxdata[18]), o_RXDISPERR=Cat(rxdata[9], rxdata[19]), #o_RXNOTINTABLE =, # Receive Ports - RX AFE Ports i_GTPRXN=pads.rxn, i_GTPRXP=pads.rxp, i_PMARSVDIN2=0b0, #o_PMARSVDOUT0 =, #o_PMARSVDOUT1 =, # Receive Ports - RX Buffer Bypass Ports i_RXBUFRESET=0, #o_RXBUFSTATUS =, i_RXDDIEN=1, i_RXDLYBYPASS=0, i_RXDLYEN=1, 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=1, #o_RXSYNCOUT =, # Receive Ports - RX Byte and Word Alignment Ports #o_RXBYTEISALIGNED =, #o_RXBYTEREALIGN =, #o_RXCOMMADET =, i_RXCOMMADETEN=1, i_RXMCOMMAALIGNEN=0, i_RXPCOMMAALIGNEN=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=0, # 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=0, 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=0, 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[:8], txdata[10:18]), i_TXUSRCLK=ClockSignal("rtio_tx"), i_TXUSRCLK2=ClockSignal("rtio_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[9], txdata[19]), i_TXCHARDISPVAL=Cat(txdata[8], txdata[18]), i_TXCHARISK=0, # Transmit Ports - TX Buffer Bypass Ports i_TXDLYBYPASS=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=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=pads.txn, o_GTPTXP=pads.txp, i_TXBUFDIFFCTRL=0b100, i_TXDEEMPH=0, i_TXDIFFCTRL=0b1000, i_TXDIFFPD=0, i_TXINHIBIT=0, i_TXMAINCURSOR=0b0000000, i_TXPISOPD=0, # Transmit Ports - TX Fabric Clock Output Control Ports o_TXOUTCLK=self.txoutclk, #o_TXOUTCLKFABRIC =, #o_TXOUTCLKPCS =, i_TXOUTCLKSEL=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=0, # Transmit Ports - TX Receiver Detection Ports i_TXDETECTRX=0, # Transmit Ports - pattern Generator Ports i_TXPRBSSEL=0) if qpll_channel.index == 0: gtp_params.update( i_RXSYSCLKSEL=0b00, i_TXSYSCLKSEL=0b00, i_PLL0CLK=qpll_channel.clk, i_PLL0REFCLK=qpll_channel.refclk, i_PLL1CLK=0, i_PLL1REFCLK=0, ) elif qpll_channel.index == 1: gtp_params.update( i_RXSYSCLKSEL=0b11, i_TXSYSCLKSEL=0b11, i_PLL0CLK=0, i_PLL0REFCLK=0, i_PLL1CLK=qpll_channel.clk, i_PLL1REFCLK=qpll_channel.refclk, ) else: raise ValueError self.specials += Instance("GTPE2_CHANNEL", **gtp_params) # 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_rtio_tx = ClockDomain() if mode == "master" or mode == "single": self.specials += Instance("BUFG", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk) self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched) # rx clocking rx_reset_deglitched = Signal() rx_reset_deglitched.attr.add("no_retiming") self.sync.rtio_tx += rx_reset_deglitched.eq(~rx_init.done) self.clock_domains.cd_rtio_rx = ClockDomain() self.specials += [ Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rtio_rx.clk), AsyncResetSynchronizer(self.cd_rtio_rx, rx_reset_deglitched) ] # tx data self.comb += txdata.eq(Cat(*[encoder.output[i] for i in range(2)])) # rx data for i in range(2): self.comb += decoders[i].input.eq(rxdata[10 * i:10 * (i + 1)]) # clock alignment clock_aligner = BruteforceClockAligner(0b0101111100, rtio_clk_freq, check_period=12e-3) self.submodules += clock_aligner self.comb += [ clock_aligner.rxdata.eq(rxdata), rx_init.restart.eq(clock_aligner.restart), self.rx_ready.eq(clock_aligner.ready) ]
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, refclk, pads, sys_clk_freq, rtio_clk_freq, dw, mode): assert (dw == 20) or (dw == 40) assert mode in ["single", "master", "slave"] self.mode = mode # phase alignment self.txsyncallin = Signal() self.txphaligndone = Signal() self.txsyncallin = Signal() self.txsyncin = Signal() self.txsyncout = Signal() self.txdlysreset = Signal() # # # nwords = dw//10 self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( Encoder(nwords, True)) self.submodules.decoders = decoders = [ClockDomainsRenamer("rtio_rx")( (Decoder(True))) for _ in range(nwords)] self.rx_ready = Signal() # transceiver direct clock outputs # useful to specify clock constraints in a way palatable to Vivado self.txoutclk = Signal() self.rxoutclk = Signal() # # # # TX generates RTIO clock, init must be in system domain self.submodules.tx_init = tx_init = GTHInit(sys_clk_freq, False, mode) # RX receives restart commands from RTIO domain rx_init = ClockDomainsRenamer("rtio_tx")(GTHInit(rtio_clk_freq, True)) self.submodules += rx_init cpll_reset = Signal() cpll_lock = Signal() self.comb += [ cpll_reset.eq(tx_init.pllreset), tx_init.plllock.eq(cpll_lock), rx_init.plllock.eq(cpll_lock) ] txdata = Signal(dw) rxdata = Signal(dw) rxphaligndone = Signal() 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 =20, p_CLK_COR_MIN_LAT =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 =5, p_CPLL_FBDIV_45 =4, p_CPLL_INIT_CFG0 =0b0000001010110010, p_CPLL_INIT_CFG1 =0b00000000, p_CPLL_LOCK_CFG =0b0000000111101000, p_CPLL_REFCLK_DIV =1, 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, ) 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 ="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 =0, p_RXBUF_THRESH_OVRD ="FALSE", p_RXBUF_THRESH_UNDFLW =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 =2, 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 =6, 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 =dw, 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 =dw==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 ="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, ) gth_params.update( p_TXBUF_EN ="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 =2, 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 if mode == "single" else 1, p_TXSYNC_OVRD =0b0, p_TXSYNC_SKIP_DA =0b0, p_TX_CLK25_DIV =6, p_TX_CLKMUX_EN =0b1, p_TX_DATA_WIDTH =dw, 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 =dw==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 ="TXUSR", p_USE_PCS_CLK_PHASE_SEL =0b0, p_WB_MODE =0b00, ) gth_params.update( # Reset modes i_GTRESETSEL=0, i_RESETOVRD=0, i_CPLLRESET=0, i_CPLLPD=cpll_reset, o_CPLLLOCK=cpll_lock, i_CPLLLOCKEN=1, i_CPLLREFCLKSEL=0b001, i_TSTIN=2**20-1, i_GTREFCLK0=refclk, # TX clock o_TXOUTCLK=self.txoutclk, i_TXSYSCLKSEL=0b00, i_TXPLLCLKSEL=0b00, i_TXOUTCLKSEL=0b11, # TX Startup/Reset i_GTTXRESET=tx_init.gtXxreset, o_TXRESETDONE=tx_init.Xxresetdone, i_TXDLYSRESET=tx_init.Xxdlysreset if mode != "slave" else self.txdlysreset, o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone, o_TXPHALIGNDONE=tx_init.Xxphaligndone, i_TXUSERRDY=tx_init.Xxuserrdy, i_TXSYNCMODE=mode != "slave", i_TXSYNCALLIN=self.txsyncallin, i_TXSYNCIN=self.txsyncin, o_TXSYNCOUT=self.txsyncout, # 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("rtio_tx"), i_TXUSRCLK2=ClockSignal("rtio_tx"), # TX electrical i_TXPD=0b00, i_TXBUFDIFFCTRL=0b000, i_TXDIFFCTRL=0b1100, # 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, # RX AFE i_RXDFEAGCCTRL=1, i_RXDFEXYDEN=1, i_RXLPMEN=1, i_RXOSINTCFG=0xd, i_RXOSINTEN=1, # RX clock i_RXRATE=0, i_RXDLYBYPASS=0, i_RXSYSCLKSEL=0b00, i_RXOUTCLKSEL=0b010, i_RXPLLCLKSEL=0b00, o_RXOUTCLK=self.rxoutclk, i_RXUSRCLK=ClockSignal("rtio_rx"), i_RXUSRCLK2=ClockSignal("rtio_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=Replicate(rx_init.restart, 2), i_RXELECIDLEMODE=0b11, # Pads i_GTHRXP=pads.rxp, i_GTHRXN=pads.rxn, o_GTHTXP=pads.txp, o_GTHTXN=pads.txn ) self.specials += Instance("GTHE3_CHANNEL", **gth_params) self.comb += self.txphaligndone.eq(tx_init.Xxphaligndone) self.submodules += [ add_probe_async("drtio_gth", "cpll_lock", cpll_lock), add_probe_async("drtio_gth", "txuserrdy", tx_init.Xxuserrdy), add_probe_async("drtio_gth", "tx_init_done", tx_init.done), add_probe_async("drtio_gth", "rxuserrdy", rx_init.Xxuserrdy), add_probe_async("drtio_gth", "rx_init_done", rx_init.done), add_probe_buffer("drtio_gth", "txdata", txdata, clock_domain="rtio_tx"), add_probe_buffer("drtio_gth", "rxdata", rxdata, clock_domain="rtio_rx") ] # 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_rtio_tx = ClockDomain() if mode == "master" or mode == "single": self.specials += \ Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk, i_DIV=0) self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched) # rx clocking rx_reset_deglitched = Signal() rx_reset_deglitched.attr.add("no_retiming") self.sync.rtio_tx += rx_reset_deglitched.eq(~rx_init.done) self.clock_domains.cd_rtio_rx = ClockDomain() self.specials += [ Instance("BUFG_GT", i_I=self.rxoutclk, o_O=self.cd_rtio_rx.clk), AsyncResetSynchronizer(self.cd_rtio_rx, rx_reset_deglitched) ] # tx data self.comb += txdata.eq(Cat(*[encoder.output[i] for i in range(nwords)])) # rx data for i in range(nwords): self.comb += decoders[i].input.eq(rxdata[10*i:10*(i+1)]) # clock alignment clock_aligner = BruteforceClockAligner(0b0101111100, rtio_clk_freq) self.submodules += clock_aligner self.comb += [ clock_aligner.rxdata.eq(rxdata), rx_init.restart.eq(clock_aligner.restart), self.rx_ready.eq(clock_aligner.ready) ] self.submodules += add_probe_async("drtio_gth", "clock_aligner_ready", clock_aligner.ready)
def __init__(self, refclk, pads, sys_clk_freq, rtio_clk_freq, dw, mode): assert (dw == 20) or (dw == 40) assert mode in ["single", "master", "slave"] self.mode = mode # phase alignment self.txsyncallin = Signal() self.txphaligndone = Signal() self.txsyncallin = Signal() self.txsyncin = Signal() self.txsyncout = Signal() self.txdlysreset = Signal() # # # nwords = dw // 10 self.submodules.encoder = encoder = ClockDomainsRenamer("rtio_tx")( Encoder(nwords, True)) self.submodules.decoders = decoders = [ ClockDomainsRenamer("rtio_rx")((Decoder(True))) for _ in range(nwords) ] self.rx_ready = Signal() # transceiver direct clock outputs # useful to specify clock constraints in a way palatable to Vivado self.txoutclk = Signal() self.rxoutclk = Signal() # # # # TX generates RTIO clock, init must be in system domain self.submodules.tx_init = tx_init = GTHInit(sys_clk_freq, False, mode) # RX receives restart commands from RTIO domain rx_init = ClockDomainsRenamer("rtio_tx")(GTHInit(rtio_clk_freq, True)) self.submodules += rx_init cpll_reset = Signal() cpll_lock = Signal() self.comb += [ cpll_reset.eq(tx_init.pllreset), tx_init.plllock.eq(cpll_lock), rx_init.plllock.eq(cpll_lock) ] txdata = Signal(dw) rxdata = Signal(dw) rxphaligndone = Signal() self.specials += \ Instance("GTHE3_CHANNEL", # Reset modes i_GTRESETSEL=0, i_RESETOVRD=0, # PMA Attributes p_PMA_RSV1=0xf800, p_RX_BIAS_CFG0=0x0AB4, p_RX_CM_TRIM=0b1010, p_RX_CLK25_DIV=5, p_TX_CLK25_DIV=5, # Power-Down Attributes p_PD_TRANS_TIME_FROM_P2=0x3c, p_PD_TRANS_TIME_NONE_P2=0x19, p_PD_TRANS_TIME_TO_P2=0x64, # CPLL p_CPLL_CFG0=0x67f8, p_CPLL_CFG1=0xa4ac, p_CPLL_CFG2=0xf007, p_CPLL_CFG3=0x0000, p_CPLL_FBDIV=5, p_CPLL_FBDIV_45=4, p_CPLL_REFCLK_DIV=1, p_RXOUT_DIV=2, p_TXOUT_DIV=2, i_CPLLRESET=0, i_CPLLPD=cpll_reset, o_CPLLLOCK=cpll_lock, i_CPLLLOCKEN=1, i_CPLLREFCLKSEL=0b001, i_TSTIN=2**20-1, i_GTREFCLK0=refclk, # TX clock p_TXBUF_EN="FALSE", p_TX_XCLK_SEL="TXUSR", o_TXOUTCLK=self.txoutclk, i_TXSYSCLKSEL=0b00, i_TXPLLCLKSEL=0b00, i_TXOUTCLKSEL=0b11, # TX Startup/Reset i_GTTXRESET=tx_init.gtXxreset, o_TXRESETDONE=tx_init.Xxresetdone, i_TXDLYSRESET=tx_init.Xxdlysreset if mode != "slave" else self.txdlysreset, o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone, o_TXPHALIGNDONE=tx_init.Xxphaligndone, i_TXUSERRDY=tx_init.Xxuserrdy, i_TXSYNCMODE=mode != "slave", p_TXSYNC_MULTILANE=0 if mode == "single" else 1, p_TXSYNC_OVRD=0, i_TXSYNCALLIN=self.txsyncallin, i_TXSYNCIN=self.txsyncin, o_TXSYNCOUT=self.txsyncout, # TX data p_TX_DATA_WIDTH=dw, p_TX_INT_DATAWIDTH=dw == 40, 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("rtio_tx"), i_TXUSRCLK2=ClockSignal("rtio_tx"), # TX electrical i_TXPD=0b00, p_TX_CLKMUX_EN=1, i_TXBUFDIFFCTRL=0b000, i_TXDIFFCTRL=0b1100, # 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, # RX AFE i_RXDFEAGCCTRL=1, i_RXDFEXYDEN=1, i_RXLPMEN=1, i_RXOSINTCFG=0xd, i_RXOSINTEN=1, # RX clock i_RXRATE=0, i_RXDLYBYPASS=0, p_RXBUF_EN="FALSE", p_RX_XCLK_SEL="RXUSR", i_RXSYSCLKSEL=0b00, i_RXOUTCLKSEL=0b010, i_RXPLLCLKSEL=0b00, o_RXOUTCLK=self.rxoutclk, i_RXUSRCLK=ClockSignal("rtio_rx"), i_RXUSRCLK2=ClockSignal("rtio_rx"), # RX Clock Correction Attributes p_CLK_CORRECT_USE="FALSE", p_CLK_COR_SEQ_1_1=0b0100000000, p_CLK_COR_SEQ_2_1=0b0100000000, p_CLK_COR_SEQ_1_ENABLE=0b1111, p_CLK_COR_SEQ_2_ENABLE=0b1111, # RX data p_RX_DATA_WIDTH=dw, p_RX_INT_DATAWIDTH=dw == 40, 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, p_RX_CLKMUX_EN=1, i_RXELECIDLEMODE=0b11, # Pads i_GTHRXP=pads.rxp, i_GTHRXN=pads.rxn, o_GTHTXP=pads.txp, o_GTHTXN=pads.txn ) self.comb += self.txphaligndone.eq(tx_init.Xxphaligndone) self.submodules += [ add_probe_async("drtio_gth", "cpll_lock", cpll_lock), add_probe_async("drtio_gth", "txuserrdy", tx_init.Xxuserrdy), add_probe_async("drtio_gth", "tx_init_done", tx_init.done), add_probe_async("drtio_gth", "rxuserrdy", rx_init.Xxuserrdy), add_probe_async("drtio_gth", "rx_init_done", rx_init.done), add_probe_buffer("drtio_gth", "txdata", txdata, clock_domain="rtio_tx"), add_probe_buffer("drtio_gth", "rxdata", rxdata, clock_domain="rtio_rx") ] # 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_rtio_tx = ClockDomain() if mode == "master" or mode == "single": self.specials += \ Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk, i_DIV=0) self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched) # rx clocking rx_reset_deglitched = Signal() rx_reset_deglitched.attr.add("no_retiming") self.sync.rtio_tx += rx_reset_deglitched.eq(~rx_init.done) self.clock_domains.cd_rtio_rx = ClockDomain() self.specials += [ Instance("BUFG_GT", i_I=self.rxoutclk, o_O=self.cd_rtio_rx.clk), AsyncResetSynchronizer(self.cd_rtio_rx, rx_reset_deglitched) ] # tx data self.comb += txdata.eq(Cat(*[encoder.output[i] for i in range(nwords)])) # rx data for i in range(nwords): self.comb += decoders[i].input.eq(rxdata[10 * i:10 * (i + 1)]) # clock alignment clock_aligner = BruteforceClockAligner(0b0101111100, rtio_clk_freq) self.submodules += clock_aligner self.comb += [ clock_aligner.rxdata.eq(rxdata), rx_init.restart.eq(clock_aligner.restart), self.rx_ready.eq(clock_aligner.ready) ] self.submodules += add_probe_async("drtio_gth", "clock_aligner_ready", clock_aligner.ready)
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, refclk, pads, sys_clk_freq, rtio_clk_freq=125e6, tx_mode="single", rx_mode="single"): assert tx_mode in ["single", "master", "slave"] assert rx_mode in ["single", "master", "slave"] self.txenable = Signal() self.submodules.encoder = ClockDomainsRenamer("rtio_tx")(Encoder( 2, True)) self.submodules.decoders = [ ClockDomainsRenamer("rtio_rx")((Decoder(True))) for _ in range(2) ] self.rx_ready = Signal() # transceiver direct clock outputs # useful to specify clock constraints in a way palatable to Vivado self.txoutclk = Signal() self.rxoutclk = Signal() # # # cpllreset = Signal() cplllock = Signal() # TX generates RTIO clock, init must be in system domain self.submodules.tx_init = tx_init = GTXInit(sys_clk_freq, False, mode=tx_mode) # RX receives restart commands from RTIO domain self.submodules.rx_init = rx_init = ClockDomainsRenamer("rtio_tx")( GTXInit(rtio_clk_freq, True, mode=rx_mode)) self.comb += [ cpllreset.eq(tx_init.cpllreset), tx_init.cplllock.eq(cplllock), rx_init.cplllock.eq(cplllock) ] txdata = Signal(20) rxdata = Signal(20) # Note: the following parameters were set after consulting AR45360 self.specials += \ Instance("GTXE2_CHANNEL", # PMA Attributes p_PMA_RSV=0x00018480, p_PMA_RSV2=0x2050, # PMA_RSV2[5] = 0: Eye scan feature disabled p_PMA_RSV3=0, p_PMA_RSV4=1, # PMA_RSV[4],RX_CM_TRIM[2:0] = 0b1010: Common mode 800mV p_RX_BIAS_CFG=0b000000000100, p_RX_OS_CFG=0b0000010000000, p_RX_CLK25_DIV=5, p_TX_CLK25_DIV=5, # Power-Down Attributes p_PD_TRANS_TIME_FROM_P2=0x3c, p_PD_TRANS_TIME_NONE_P2=0x3c, p_PD_TRANS_TIME_TO_P2=0x64, # CPLL p_CPLL_CFG=0xBC07DC, p_CPLL_FBDIV=4, p_CPLL_FBDIV_45=5, p_CPLL_REFCLK_DIV=1, p_RXOUT_DIV=2, p_TXOUT_DIV=2, i_CPLLRESET=cpllreset, i_CPLLPD=cpllreset, o_CPLLLOCK=cplllock, i_CPLLLOCKEN=1, i_CPLLREFCLKSEL=0b001, i_TSTIN=2**20-1, i_GTREFCLK0=refclk, # TX clock p_TXBUF_EN="FALSE", p_TX_XCLK_SEL="TXUSR", o_TXOUTCLK=self.txoutclk, i_TXSYSCLKSEL=0b00, i_TXOUTCLKSEL=0b11, # TX Startup/Reset i_TXPHDLYRESET=0, i_TXDLYBYPASS=0, i_TXPHALIGNEN=1 if tx_mode != "single" else 0, i_GTTXRESET=tx_init.gtXxreset, o_TXRESETDONE=tx_init.Xxresetdone, i_TXDLYSRESET=tx_init.Xxdlysreset, o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone, i_TXPHINIT=tx_init.txphinit if tx_mode != "single" else 0, o_TXPHINITDONE=tx_init.txphinitdone if tx_mode != "single" else Signal(), i_TXPHALIGN=tx_init.Xxphalign if tx_mode != "single" else 0, i_TXDLYEN=tx_init.Xxdlyen if tx_mode != "single" else 0, o_TXPHALIGNDONE=tx_init.Xxphaligndone, i_TXUSERRDY=tx_init.Xxuserrdy, p_TXPMARESET_TIME=1, p_TXPCSRESET_TIME=1, i_TXINHIBIT=~self.txenable, # TX data p_TX_DATA_WIDTH=20, p_TX_INT_DATAWIDTH=0, i_TXCHARDISPMODE=Cat(txdata[9], txdata[19]), i_TXCHARDISPVAL=Cat(txdata[8], txdata[18]), i_TXDATA=Cat(txdata[:8], txdata[10:18]), i_TXUSRCLK=ClockSignal("rtio_tx"), i_TXUSRCLK2=ClockSignal("rtio_tx"), # TX electrical i_TXBUFDIFFCTRL=0b100, i_TXDIFFCTRL=0b1000, # RX Startup/Reset i_RXPHDLYRESET=0, i_RXDLYBYPASS=0, i_RXPHALIGNEN=1 if rx_mode != "single" else 0, i_GTRXRESET=rx_init.gtXxreset, o_RXRESETDONE=rx_init.Xxresetdone, i_RXDLYSRESET=rx_init.Xxdlysreset, o_RXDLYSRESETDONE=rx_init.Xxdlysresetdone, i_RXPHALIGN=rx_init.Xxphalign if rx_mode != "single" else 0, i_RXDLYEN=rx_init.Xxdlyen if rx_mode != "single" else 0, o_RXPHALIGNDONE=rx_init.Xxphaligndone, i_RXUSERRDY=rx_init.Xxuserrdy, p_RXPMARESET_TIME=1, p_RXPCSRESET_TIME=1, # RX AFE p_RX_DFE_XYD_CFG=0, p_RX_CM_SEL=0b11, # RX_CM_SEL = 0b11: Common mode is programmable p_RX_CM_TRIM=0b010, # PMA_RSV[4],RX_CM_TRIM[2:0] = 0b1010: Common mode 800mV i_RXDFEXYDEN=1, i_RXDFEXYDHOLD=0, i_RXDFEXYDOVRDEN=0, i_RXLPMEN=0, # RXLPMEN = 0: DFE mode is enabled p_RX_DFE_GAIN_CFG=0x0207EA, p_RX_DFE_VP_CFG=0b00011111100000011, p_RX_DFE_UT_CFG=0b10001000000000000, p_RX_DFE_KL_CFG=0b0000011111110, p_RX_DFE_KL_CFG2=0x3788140A, p_RX_DFE_H2_CFG=0b000110000000, p_RX_DFE_H3_CFG=0b000110000000, p_RX_DFE_H4_CFG=0b00011100000, p_RX_DFE_H5_CFG=0b00011100000, p_RX_DFE_LPM_CFG=0x0904, # RX_DFE_LPM_CFG = 0x0904: linerate <= 6.6Gb/s # = 0x0104: linerate > 6.6Gb/s # RX clock i_RXDDIEN=1, i_RXSYSCLKSEL=0b00, i_RXOUTCLKSEL=0b010, o_RXOUTCLK=self.rxoutclk, i_RXUSRCLK=ClockSignal("rtio_rx"), i_RXUSRCLK2=ClockSignal("rtio_rx"), # RX Clock Correction Attributes p_CLK_CORRECT_USE="FALSE", p_CLK_COR_SEQ_1_1=0b0100000000, p_CLK_COR_SEQ_2_1=0b0100000000, p_CLK_COR_SEQ_1_ENABLE=0b1111, p_CLK_COR_SEQ_2_ENABLE=0b1111, # RX data p_RX_DATA_WIDTH=20, p_RX_INT_DATAWIDTH=0, o_RXDISPERR=Cat(rxdata[9], rxdata[19]), o_RXCHARISK=Cat(rxdata[8], rxdata[18]), o_RXDATA=Cat(rxdata[:8], rxdata[10:18]), # RX Byte and Word Alignment Attributes p_ALIGN_COMMA_DOUBLE="FALSE", p_ALIGN_COMMA_ENABLE=0b1111111111, p_ALIGN_COMMA_WORD=1, p_ALIGN_MCOMMA_DET="TRUE", p_ALIGN_MCOMMA_VALUE=0b1010000011, p_ALIGN_PCOMMA_DET="TRUE", p_ALIGN_PCOMMA_VALUE=0b0101111100, p_SHOW_REALIGN_COMMA="FALSE", p_RXSLIDE_AUTO_WAIT=7, p_RXSLIDE_MODE="PCS", p_RX_SIG_VALID_DLY=10, # RX 8B/10B Decoder Attributes p_RX_DISPERR_SEQ_MATCH="FALSE", p_DEC_MCOMMA_DETECT="TRUE", p_DEC_PCOMMA_DETECT="TRUE", p_DEC_VALID_COMMA_ONLY="FALSE", # RX Buffer Attributes p_RXBUF_ADDR_MODE="FAST", p_RXBUF_EIDLE_HI_CNT=0b1000, p_RXBUF_EIDLE_LO_CNT=0b0000, p_RXBUF_EN="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", # RXBUF_RESET_ON_EIDLE = FALSE: OOB is disabled 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="RXUSR", p_RX_DDI_SEL=0b000000, p_RX_DEFER_RESET_BUF_EN="TRUE", # CDR Attributes p_RXCDR_CFG=0x03000023FF20400020, # DFE @ <= 6.6Gb/s, scrambled, CDR setting < +/- 200ppm # (See UG476 (v1.12.1), p.206) 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, # Pads i_GTXRXP=pads.rxp, i_GTXRXN=pads.rxn, o_GTXTXP=pads.txp, o_GTXTXN=pads.txn, # Other parameters p_PCS_RSVD_ATTR=( (tx_mode != "single") << 1 | # PCS_RSVD_ATTR[1] = 0: TX Single Lane Auto Mode # = 1: TX Manual Mode (rx_mode != "single") << 2 | # [2] = 0: RX Single Lane Auto Mode # = 1: RX Manual Mode 0 << 8 # [8] = 0: OOB is disabled ), i_RXELECIDLEMODE=0b11, # RXELECIDLEMODE = 0b11: OOB is disabled p_RX_DFE_LPM_HOLD_DURING_EIDLE=0b0, p_ES_EYE_SCAN_EN="TRUE", # Must be TRUE for GTX ) # 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_rtio_tx = ClockDomain() if tx_mode == "single" or tx_mode == "master": self.specials += Instance("BUFG", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk) self.specials += AsyncResetSynchronizer(self.cd_rtio_tx, tx_reset_deglitched) # RX clocking rx_reset_deglitched = Signal() rx_reset_deglitched.attr.add("no_retiming") self.sync.rtio += rx_reset_deglitched.eq(~rx_init.done) self.clock_domains.cd_rtio_rx = ClockDomain() if rx_mode == "single" or rx_mode == "master": self.specials += Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rtio_rx.clk), self.specials += AsyncResetSynchronizer(self.cd_rtio_rx, rx_reset_deglitched) self.comb += [ txdata.eq(Cat(self.encoder.output[0], self.encoder.output[1])), self.decoders[0].input.eq(rxdata[:10]), self.decoders[1].input.eq(rxdata[10:]) ] clock_aligner = BruteforceClockAligner(0b0101111100, rtio_clk_freq) self.submodules += clock_aligner self.comb += [ clock_aligner.rxdata.eq(rxdata), rx_init.restart.eq(clock_aligner.restart), self.rx_ready.eq(clock_aligner.ready) ]
def __init__(self, clock_pads, tx_pads, rx_pads, sys_clk_freq, clock_div2=False): self.submodules.encoder = ClockDomainsRenamer("rtio")(Encoder(2, True)) self.decoders = [ ClockDomainsRenamer("rtio_rx")(Decoder(True)) for _ in range(2) ] self.submodules += self.decoders self.rx_ready = Signal() # transceiver direct clock outputs # useful to specify clock constraints in a way palatable to Vivado self.txoutclk = Signal() self.rxoutclk = Signal() # # # refclk = Signal() if clock_div2: self.specials += Instance("IBUFDS_GTE2", i_CEB=0, i_I=clock_pads.p, i_IB=clock_pads.n, o_ODIV2=refclk) else: self.specials += Instance("IBUFDS_GTE2", i_CEB=0, i_I=clock_pads.p, i_IB=clock_pads.n, o_O=refclk) cplllock = Signal() # TX generates RTIO clock, init must be in system domain tx_init = GTXInit(sys_clk_freq, False) # RX receives restart commands from RTIO domain rx_init = ClockDomainsRenamer("rtio")(GTXInit(self.rtio_clk_freq, True)) self.submodules += tx_init, rx_init self.comb += tx_init.cplllock.eq(cplllock), \ rx_init.cplllock.eq(cplllock) txdata = Signal(20) rxdata = Signal(20) self.specials += \ Instance("GTXE2_CHANNEL", # PMA Attributes p_PMA_RSV=0x00018480, p_PMA_RSV2=0x2050, p_PMA_RSV3=0, p_PMA_RSV4=0, p_RX_BIAS_CFG=0b100, p_RX_CM_TRIM=0b010, p_RX_OS_CFG=0b10000000, p_RX_CLK25_DIV=5, p_TX_CLK25_DIV=5, # Power-Down Attributes p_PD_TRANS_TIME_FROM_P2=0x3c, p_PD_TRANS_TIME_NONE_P2=0x3c, p_PD_TRANS_TIME_TO_P2=0x64, # CPLL p_CPLL_CFG=0xBC07DC, p_CPLL_FBDIV=4, p_CPLL_FBDIV_45=5, p_CPLL_REFCLK_DIV=1, p_RXOUT_DIV=2, p_TXOUT_DIV=2, o_CPLLLOCK=cplllock, i_CPLLLOCKEN=1, i_CPLLREFCLKSEL=0b001, i_TSTIN=2**20-1, i_GTREFCLK0=refclk, # TX clock p_TXBUF_EN="FALSE", p_TX_XCLK_SEL="TXUSR", o_TXOUTCLK=self.txoutclk, i_TXSYSCLKSEL=0b00, i_TXOUTCLKSEL=0b11, # TX Startup/Reset i_GTTXRESET=tx_init.gtXxreset, o_TXRESETDONE=tx_init.Xxresetdone, i_TXDLYSRESET=tx_init.Xxdlysreset, o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone, o_TXPHALIGNDONE=tx_init.Xxphaligndone, i_TXUSERRDY=tx_init.Xxuserrdy, # TX data p_TX_DATA_WIDTH=20, p_TX_INT_DATAWIDTH=0, i_TXCHARDISPMODE=Cat(txdata[9], txdata[19]), i_TXCHARDISPVAL=Cat(txdata[8], txdata[18]), i_TXDATA=Cat(txdata[:8], txdata[10:18]), i_TXUSRCLK=ClockSignal("rtio"), i_TXUSRCLK2=ClockSignal("rtio"), # TX electrical i_TXBUFDIFFCTRL=0b100, i_TXDIFFCTRL=0b1000, # RX Startup/Reset i_GTRXRESET=rx_init.gtXxreset, o_RXRESETDONE=rx_init.Xxresetdone, i_RXDLYSRESET=rx_init.Xxdlysreset, o_RXDLYSRESETDONE=rx_init.Xxdlysresetdone, o_RXPHALIGNDONE=rx_init.Xxphaligndone, i_RXUSERRDY=rx_init.Xxuserrdy, # RX AFE p_RX_DFE_XYD_CFG=0, i_RXDFEXYDEN=1, i_RXDFEXYDHOLD=0, i_RXDFEXYDOVRDEN=0, i_RXLPMEN=0, # RX clock p_RXBUF_EN="FALSE", p_RX_XCLK_SEL="RXUSR", i_RXDDIEN=1, i_RXSYSCLKSEL=0b00, i_RXOUTCLKSEL=0b010, o_RXOUTCLK=self.rxoutclk, i_RXUSRCLK=ClockSignal("rtio_rx"), i_RXUSRCLK2=ClockSignal("rtio_rx"), p_RXCDR_CFG=0x03000023FF10100020, # RX Clock Correction Attributes p_CLK_CORRECT_USE="FALSE", p_CLK_COR_SEQ_1_1=0b0100000000, p_CLK_COR_SEQ_2_1=0b0100000000, p_CLK_COR_SEQ_1_ENABLE=0b1111, p_CLK_COR_SEQ_2_ENABLE=0b1111, # RX data p_RX_DATA_WIDTH=20, p_RX_INT_DATAWIDTH=0, o_RXDISPERR=Cat(rxdata[9], rxdata[19]), o_RXCHARISK=Cat(rxdata[8], rxdata[18]), o_RXDATA=Cat(rxdata[:8], rxdata[10:18]), # Pads i_GTXRXP=rx_pads.p, i_GTXRXN=rx_pads.n, o_GTXTXP=tx_pads.p, o_GTXTXN=tx_pads.n, ) tx_reset_deglitched = Signal() tx_reset_deglitched.attr.add("no_retiming") self.sync += tx_reset_deglitched.eq(~tx_init.done) self.clock_domains.cd_rtio = ClockDomain() self.specials += [ Instance("BUFG", i_I=self.txoutclk, o_O=self.cd_rtio.clk), AsyncResetSynchronizer(self.cd_rtio, tx_reset_deglitched) ] rx_reset_deglitched = Signal() rx_reset_deglitched.attr.add("no_retiming") self.sync.rtio += rx_reset_deglitched.eq(~rx_init.done) self.clock_domains.cd_rtio_rx = ClockDomain() self.specials += [ Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rtio_rx.clk), AsyncResetSynchronizer(self.cd_rtio_rx, rx_reset_deglitched) ] self.comb += [ txdata.eq(Cat(self.encoder.output[0], self.encoder.output[1])), self.decoders[0].input.eq(rxdata[:10]), self.decoders[1].input.eq(rxdata[10:]) ] clock_aligner = BruteforceClockAligner(0b0101111100, self.rtio_clk_freq) self.submodules += clock_aligner self.comb += [ clock_aligner.rxdata.eq(rxdata), rx_init.restart.eq(clock_aligner.restart), self.rx_ready.eq(clock_aligner.ready) ]
def __init__(self, pads, mode="master"): # Control self.delay_rst = Signal() self.delay_inc = Signal() self.bitslip_value = bitslip_value = Signal(6) # Status self.idle = idle = Signal() self.comma = comma = Signal() # Datapath self.ce = ce = Signal() self.k = k = Signal(4) self.d = d = Signal(32) # # # # Data input (DDR with sys4x) data_nodelay = Signal() data_delayed = Signal() data_deserialized = Signal(8) self.specials += [ DifferentialInput(pads.rx_p, pads.rx_n, data_nodelay), 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.delay_rst, i_CE=self.delay_inc, i_LDPIPEEN=0, i_INC=1, i_IDATAIN=data_nodelay, o_DATAOUT=data_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=data_delayed, i_CE1=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKB=~ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_BITSLIP=0, o_Q8=data_deserialized[0], o_Q7=data_deserialized[1], o_Q6=data_deserialized[2], o_Q5=data_deserialized[3], o_Q4=data_deserialized[4], o_Q3=data_deserialized[5], o_Q2=data_deserialized[6], o_Q1=data_deserialized[7]) ] # 8 --> 40 converter and bitslip converter = stream.Converter(8, 40) self.submodules += converter bitslip = CEInserter()(BitSlip(40)) self.submodules += bitslip self.comb += [ converter.sink.stb.eq(1), converter.source.ack.eq(1), # Enable pipeline when converter outputs the 40 bits ce.eq(converter.source.stb), # Connect input data to converter converter.sink.data.eq(data_deserialized), # Connect converter to bitslip bitslip.ce.eq(ce), bitslip.value.eq(bitslip_value), bitslip.i.eq(converter.source.data) ] # 8b10b decoder self.submodules.decoders = decoders = [ CEInserter()(Decoder(True)) for _ in range(4) ] self.comb += [decoders[i].ce.eq(ce) for i in range(4)] self.comb += [ # Connect bitslip to decoder decoders[0].input.eq(bitslip.o[0:10]), decoders[1].input.eq(bitslip.o[10:20]), decoders[2].input.eq(bitslip.o[20:30]), decoders[3].input.eq(bitslip.o[30:40]), # Connect decoder to output self.k.eq(Cat(*[decoders[i].k for i in range(4)])), self.d.eq(Cat(*[decoders[i].d for i in range(4)])), ] # Status idle_timer = WaitTimer(256) self.submodules += idle_timer self.comb += [ idle_timer.wait.eq(1), self.idle.eq(idle_timer.done & ((bitslip.o == 0) | (bitslip.o == (2**40 - 1)))), self.comma.eq((decoders[0].k == 1) & (decoders[0].d == K(28, 5)) & (decoders[1].k == 0) & (decoders[1].d == 0) & (decoders[2].k == 0) & (decoders[2].d == 0) & (decoders[3].k == 0) & (decoders[3].d == 0)) ]
def __init__(self, pads, mode="master"): # Control self.delay_rst = Signal() self.delay_inc = Signal() self.bitslip_value = bitslip_value = Signal(6) # Status self.idle = idle = Signal() self.comma = comma = Signal() # Datapath self.ce = ce = Signal() self.k = k = Signal(4) self.d = d = Signal(32) # # # # Data input (DDR with sys4x) data_nodelay = Signal() data_delayed = Signal() data_deserialized = Signal(8) self.specials += [ DifferentialInput(pads.rx_p, pads.rx_n, data_nodelay), 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("sys"), i_RST=self.delay_rst, i_LOAD=0, i_INC=1, i_EN_VTC=0, i_CE=self.delay_inc, i_IDATAIN=data_nodelay, o_DATAOUT=data_delayed ), Instance("ISERDESE3", p_IS_CLK_INVERTED=0, p_IS_CLK_B_INVERTED=1, p_DATA_WIDTH=8, i_D=data_delayed, i_RST=ResetSignal("sys"), i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0, i_CLK=ClockSignal("sys4x"), i_CLK_B=ClockSignal("sys4x"), # locally inverted i_CLKDIV=ClockSignal("sys"), o_Q=data_deserialized ) ] # 8 --> 40 converter and bitslip converter = stream.Converter(8, 40) self.submodules += converter bitslip = CEInserter()(BitSlip(40)) self.submodules += bitslip self.comb += [ converter.sink.stb.eq(1), converter.source.ack.eq(1), # Enable pipeline when converter outputs the 40 bits ce.eq(converter.source.stb), # Connect input data to converter converter.sink.data.eq(data_deserialized), # Connect converter to bitslip bitslip.ce.eq(ce), bitslip.value.eq(bitslip_value), bitslip.i.eq(converter.source.data) ] # 8b10b decoder self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] self.comb += [decoders[i].ce.eq(ce) for i in range(4)] self.comb += [ # Connect bitslip to decoder decoders[0].input.eq(bitslip.o[0:10]), decoders[1].input.eq(bitslip.o[10:20]), decoders[2].input.eq(bitslip.o[20:30]), decoders[3].input.eq(bitslip.o[30:40]), # Connect decoder to output self.k.eq(Cat(*[decoders[i].k for i in range(4)])), self.d.eq(Cat(*[decoders[i].d for i in range(4)])), ] # Status idle_timer = WaitTimer(256) self.submodules += idle_timer self.comb += [ idle_timer.wait.eq(1), self.idle.eq(idle_timer.done & ((bitslip.o == 0) | (bitslip.o == (2**40-1)))), self.comma.eq( (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & (decoders[1].k == 0) & (decoders[1].d == 0) & (decoders[2].k == 0) & (decoders[2].d == 0) & (decoders[3].k == 0) & (decoders[3].d == 0)) ]
def __init__(self, pads, mode="master"): # Control self.bitslip_value = bitslip_value = Signal(6) # Status self.idle = idle = Signal() self.comma = comma = Signal() # Datapath self.ce = ce = Signal() self.k = k = Signal(4) self.d = d = Signal(32) # # # # Input data (on rising edge of sys_clk) data = Signal() data_d = Signal() self.specials += DifferentialInput(pads.rx_p, pads.rx_n, data) self.sync += data_d.eq(data) # 1 --> 40 converter and bitslip converter = stream.Converter(1, 40) self.submodules += converter bitslip = CEInserter()(BitSlip(40)) self.submodules += bitslip self.comb += [ converter.sink.stb.eq(1), converter.source.ack.eq(1), # Enable pipeline when converter outputs the 40 bits ce.eq(converter.source.stb), # Connect input data to converter converter.sink.data.eq(data), # Connect converter to bitslip bitslip.ce.eq(ce), bitslip.value.eq(bitslip_value), bitslip.i.eq(converter.source.data) ] # 8b10b decoder self.submodules.decoders = decoders = [CEInserter()(Decoder(True)) for _ in range(4)] self.comb += [decoders[i].ce.eq(ce) for i in range(4)] self.comb += [ # Connect bitslip to decoder decoders[0].input.eq(bitslip.o[0:10]), decoders[1].input.eq(bitslip.o[10:20]), decoders[2].input.eq(bitslip.o[20:30]), decoders[3].input.eq(bitslip.o[30:40]), # Connect decoder to output self.k.eq(Cat(*[decoders[i].k for i in range(4)])), self.d.eq(Cat(*[decoders[i].d for i in range(4)])), ] # Status idle_timer = WaitTimer(256) self.submodules += idle_timer self.comb += [ idle_timer.wait.eq(1), self.idle.eq(idle_timer.done & ((bitslip.o == 0) | (bitslip.o == (2**40-1)))), self.comma.eq( (decoders[0].k == 1) & (decoders[0].d == K(28,5)) & (decoders[1].k == 0) & (decoders[1].d == 0) & (decoders[2].k == 0) & (decoders[2].d == 0) & (decoders[3].k == 0) & (decoders[3].d == 0)) ]
def __init__(self, pads, mode="master"): if mode == "slave": self.refclk = Signal() self.tx_ce = Signal() self.tx_k = Signal(4) self.tx_d = Signal(32) self.rx_ce = Signal() 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_en_vtc = Signal() # # # self.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) self.comb += encoder.ce.eq(self.tx_ce) self.submodules.decoders = decoders = [ CEInserter()(Decoder(True)) for _ in range(4) ] self.comb += [decoders[i].ce.eq(self.rx_ce) for i in range(4)] # clocking: # In master mode: # - linerate/10 refclk generated on clk_pads # In Slave mode: # - linerate/10 refclk provided by clk_pads # tx clock (linerate/10) if mode == "master": clk_converter = stream.Converter(40, 8) self.submodules += clk_converter self.comb += [ clk_converter.sink.stb.eq(1), clk_converter.sink.data.eq( Replicate(Signal(10, reset=0b1111100000), 4)), clk_converter.source.ack.eq(1) ] 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("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D=clk_converter.source.data), Instance("OBUFDS", i_I=clk_o, o_O=pads.clk_p, o_OB=pads.clk_n) ] # tx datapath # tx_data -> encoders -> converter -> serdes self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) self.comb += [ tx_converter.sink.stb.eq(1), self.tx_ce.eq(tx_converter.sink.ack), tx_converter.source.ack.eq(1), If(self.tx_idle, tx_converter.sink.data.eq(0)).Else( tx_converter.sink.data.eq( Cat(*[encoder.output[i] for i in range(4)]))), If( self.tx_comma, encoder.k[0].eq(1), encoder.d[0].eq(K(28, 5)), ).Else(encoder.k[0].eq(self.tx_k[0]), encoder.k[1].eq( self.tx_k[1]), encoder.k[2].eq(self.tx_k[2]), encoder.k[3].eq(self.tx_k[3]), encoder.d[0].eq(self.tx_d[0:8]), encoder.d[1].eq(self.tx_d[8:16]), encoder.d[2].eq(self.tx_d[16:24]), encoder.d[3].eq(self.tx_d[24:32])) ] 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("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D=tx_converter.source.data), 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 += self.refclk.eq(clk_i_bufg) # rx datapath # serdes -> converter -> bitslip -> decoders -> rx_data self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) self.comb += [ self.rx_ce.eq(rx_converter.source.stb), rx_converter.source.ack.eq(1) ] self.submodules.rx_bitslip = rx_bitslip = CEInserter()(BitSlip(40)) self.comb += rx_bitslip.ce.eq(self.rx_ce) 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("sys"), i_RST=self.rx_delay_rst, i_LOAD=0, i_INC=1, i_EN_VTC=self.rx_delay_en_vtc, i_CE=self.rx_delay_inc, 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("sys"), i_FIFO_RD_CLK=0, i_FIFO_RD_EN=0, i_CLK=ClockSignal("sys4x"), i_CLK_B=ClockSignal("sys4x"), # locally inverted i_CLKDIV=ClockSignal("sys"), o_Q=serdes_q) ] self.comb += [ rx_converter.sink.stb.eq(1), rx_converter.sink.data.eq(serdes_q), rx_bitslip.value.eq(self.rx_bitslip_value), rx_bitslip.i.eq(rx_converter.source.data), decoders[0].input.eq(rx_bitslip.o[0:10]), decoders[1].input.eq(rx_bitslip.o[10:20]), decoders[2].input.eq(rx_bitslip.o[20:30]), decoders[3].input.eq(rx_bitslip.o[30:40]), self.rx_k.eq(Cat(*[decoders[i].k for i in range(4)])), self.rx_d.eq(Cat(*[decoders[i].d for i in range(4)])), self.rx_comma.eq((decoders[0].k == 1) & (decoders[0].d == K(28, 5)) & (decoders[1].k == 0) & (decoders[1].d == 0) & (decoders[2].k == 0) & (decoders[2].d == 0) & (decoders[3].k == 0) & (decoders[3].d == 0)) ] idle_timer = WaitTimer(32) self.submodules += idle_timer self.comb += idle_timer.wait.eq(1) self.sync += self.rx_idle.eq(idle_timer.done & (rx_bitslip.o == 0))
def __init__(self, pads, mode="master"): if mode == "slave": self.refclk = Signal() self.tx_ce = Signal() self.tx_k = Signal(4) self.tx_d = Signal(32) self.rx_ce = Signal() 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.submodules.encoder = encoder = CEInserter()(Encoder(4, True)) self.comb += encoder.ce.eq(self.tx_ce) self.submodules.decoders = decoders = [ CEInserter()(Decoder(True)) for _ in range(4) ] self.comb += [decoders[i].ce.eq(self.rx_ce) for i in range(4)] # clocking: # In Master mode: # - linerate/10 refclk is generated on clk_pads # In Slave mode: # - linerate/10 refclk is provided by clk_pads # tx clock (linerate/10) if mode == "master": clk_converter = stream.Converter(40, 8) self.submodules += clk_converter self.comb += [ clk_converter.sink.stb.eq(1), clk_converter.sink.data.eq( Replicate(Signal(10, reset=0b1111100000), 4)), clk_converter.source.ack.eq(1) ] 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("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D1=clk_converter.source.data[0], i_D2=clk_converter.source.data[1], i_D3=clk_converter.source.data[2], i_D4=clk_converter.source.data[3], i_D5=clk_converter.source.data[4], i_D6=clk_converter.source.data[5], i_D7=clk_converter.source.data[6], i_D8=clk_converter.source.data[7]), Instance("OBUFDS", i_I=clk_o, o_O=pads.clk_p, o_OB=pads.clk_n) ] # tx datapath # tx_data -> encoders -> converter -> serdes self.submodules.tx_converter = tx_converter = stream.Converter(40, 8) self.comb += [ tx_converter.sink.stb.eq(1), self.tx_ce.eq(tx_converter.sink.ack), tx_converter.source.ack.eq(1), If(self.tx_idle, tx_converter.sink.data.eq(0)).Else( tx_converter.sink.data.eq( Cat(*[encoder.output[i] for i in range(4)]))), If( self.tx_comma, encoder.k[0].eq(1), encoder.d[0].eq(K(28, 5)), ).Else(encoder.k[0].eq(self.tx_k[0]), encoder.k[1].eq( self.tx_k[1]), encoder.k[2].eq(self.tx_k[2]), encoder.k[3].eq(self.tx_k[3]), encoder.d[0].eq(self.tx_d[0:8]), encoder.d[1].eq(self.tx_d[8:16]), encoder.d[2].eq(self.tx_d[16:24]), encoder.d[3].eq(self.tx_d[24:32])) ] 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("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D1=tx_converter.source.data[0], i_D2=tx_converter.source.data[1], i_D3=tx_converter.source.data[2], i_D4=tx_converter.source.data[3], i_D5=tx_converter.source.data[4], i_D6=tx_converter.source.data[5], i_D7=tx_converter.source.data[6], i_D8=tx_converter.source.data[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 += self.refclk.eq(clk_i_bufg) # rx datapath # serdes -> converter -> bitslip -> decoders -> rx_data self.submodules.rx_converter = rx_converter = stream.Converter(8, 40) self.comb += [ self.rx_ce.eq(rx_converter.source.stb), rx_converter.source.ack.eq(1) ] self.submodules.rx_bitslip = rx_bitslip = CEInserter()(BitSlip(40)) self.comb += rx_bitslip.ce.eq(self.rx_ce) 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_inc, i_LDPIPEEN=0, i_INC=1, 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("sys"), i_CLK=ClockSignal("sys4x"), i_CLKB=~ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), 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 += [ rx_converter.sink.stb.eq(1), rx_converter.sink.data.eq(serdes_q), rx_bitslip.value.eq(self.rx_bitslip_value), rx_bitslip.i.eq(rx_converter.source.data), decoders[0].input.eq(rx_bitslip.o[0:10]), decoders[1].input.eq(rx_bitslip.o[10:20]), decoders[2].input.eq(rx_bitslip.o[20:30]), decoders[3].input.eq(rx_bitslip.o[30:40]), self.rx_k.eq(Cat(*[decoders[i].k for i in range(4)])), self.rx_d.eq(Cat(*[decoders[i].d for i in range(4)])), self.rx_comma.eq((decoders[0].k == 1) & (decoders[0].d == K(28, 5)) & (decoders[1].k == 0) & (decoders[1].d == 0) & (decoders[2].k == 0) & (decoders[2].d == 0) & (decoders[3].k == 0) & (decoders[3].d == 0)) ] idle_timer = WaitTimer(32) self.submodules += idle_timer self.comb += idle_timer.wait.eq(1) self.sync += self.rx_idle.eq(idle_timer.done & (rx_bitslip.o == 0))