from functools import reduce from operator import or_, and_ from migen import * from migen.genlib.resetsync import AsyncResetSynchronizer from misoc.cores.code_8b10b import Encoder, Decoder from microscope import * from artiq.gateware.drtio.core import TransceiverInterface, ChannelInterface from artiq.gateware.drtio.transceiver.clock_aligner import BruteforceClockAligner from artiq.gateware.drtio.transceiver.gth_ultrascale_init import * class GTHSingle(Module): def __init__(self, refclk, pads, sys_clk_freq, rtio_clk_freq, rtiox_mul, 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() # # # self.txenable = 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 # for OBUFDS_GTE3 self.rxrecclkout = Signal() # 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 ="TRUE", 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 =dw/rtiox_mul, 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=0b101, # 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_TXINHIBIT=~self.txenable, 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_RXRECCLKOUT=self.rxrecclkout, 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() self.clock_domains.cd_rtiox_tx = ClockDomain() if mode == "master" or mode == "single": self.specials += [ Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_rtiox_tx.clk, i_DIV=0), Instance("BUFG_GT", i_I=self.txoutclk, o_O=self.cd_rtio_tx.clk, i_DIV=rtiox_mul-1) ] 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) class GTHTXPhaseAlignement(Module): # TX Buffer Bypass in Single-Lane/Multi-Lane Auto Mode (ug576) def __init__(self, gths): txsyncallin = Signal() txsync = Signal() txphaligndone = Signal(len(gths)) txdlysreset = Signal() ready_for_align = Signal(len(gths)) all_ready_for_align = Signal() for i, gth in enumerate(gths): # Common to all transceivers self.comb += [ ready_for_align[i].eq(1), gth.txsyncin.eq(txsync), gth.txsyncallin.eq(txsyncallin), txphaligndone[i].eq(gth.txphaligndone) ] # Specific to Master or Single transceivers if gth.mode == "master" or gth.mode == "single": self.comb += [ gth.tx_init.all_ready_for_align.eq(all_ready_for_align), txsync.eq(gth.txsyncout), txdlysreset.eq(gth.tx_init.Xxdlysreset) ] # Specific to Slave transceivers else: self.comb += [ ready_for_align[i].eq(gth.tx_init.ready_for_align), gth.txdlysreset.eq(txdlysreset), ] self.comb += [ txsyncallin.eq(reduce(and_, [txphaligndone[i] for i in range(len(gths))])), all_ready_for_align.eq(reduce(and_, [ready_for_align[i] for i in range(len(gths))])) ] class GTH(Module, TransceiverInterface): def __init__(self, clock_pads, data_pads, sys_clk_freq, rtio_clk_freq, rtiox_mul=2, dw=20, master=0, clock_recout_pads=None): self.nchannels = nchannels = len(data_pads) self.gths = [] # # # create_buf = hasattr(clock_pads, "p") if create_buf: refclk = Signal() ibufds_ceb = Signal() self.specials += Instance("IBUFDS_GTE3", i_CEB=ibufds_ceb, i_I=clock_pads.p, i_IB=clock_pads.n, o_O=refclk) else: refclk = clock_pads rtio_tx_clk = Signal() channel_interfaces = [] for i in range(nchannels): if nchannels == 1: mode = "single" else: mode = "master" if i == master else "slave" gth = GTHSingle(refclk, data_pads[i], sys_clk_freq, rtio_clk_freq, rtiox_mul, dw, mode) if mode == "master": self.comb += rtio_tx_clk.eq(gth.cd_rtio_tx.clk) elif mode == "slave": self.comb += gth.cd_rtio_tx.clk.eq(rtio_tx_clk) self.gths.append(gth) setattr(self.submodules, "gth"+str(i), gth) channel_interface = ChannelInterface(gth.encoder, gth.decoders) self.comb += channel_interface.rx_ready.eq(gth.rx_ready) channel_interfaces.append(channel_interface) self.submodules.tx_phase_alignment = GTHTXPhaseAlignement(self.gths) TransceiverInterface.__init__(self, channel_interfaces) for n, gth in enumerate(self.gths): self.comb += gth.txenable.eq(self.txenable.storage[n]) self.clock_domains.cd_rtiox = ClockDomain(reset_less=True) if create_buf: # GTH PLLs recover on their own from an interrupted clock input, # but be paranoid about HMC7043 noise. self.stable_clkin.storage.attr.add("no_retiming") self.comb += ibufds_ceb.eq(~self.stable_clkin.storage) self.comb += [ self.cd_rtio.clk.eq(self.gths[master].cd_rtio_tx.clk), self.cd_rtiox.clk.eq(self.gths[master].cd_rtiox_tx.clk), self.cd_rtio.rst.eq(reduce(or_, [gth.cd_rtio_tx.rst for gth in self.gths])) ] for i in range(nchannels): self.comb += [ getattr(self, "cd_rtio_rx" + str(i)).clk.eq(self.gths[i].cd_rtio_rx.clk), getattr(self, "cd_rtio_rx" + str(i)).rst.eq(self.gths[i].cd_rtio_rx.rst) ] if clock_recout_pads is not None: self.specials += Instance("OBUFDS_GTE3", p_REFCLK_EN_TX_PATH=0b1, p_REFCLK_ICNTL_TX=0b00111, i_I=self.gths[0].rxrecclkout, i_CEB=0, o_O=clock_recout_pads.p, o_OB=clock_recout_pads.n)