Example #1
0
    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)
        ]
Example #2
0
    def __init__(self, pll, pads, mode="master"):
        self.tx_k = Signal(4)
        self.tx_d = Signal(32)
        self.rx_k = Signal(4)
        self.rx_d = Signal(32)

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

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

        # # #

        self.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)))
        ]
Example #3
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)
Example #4
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()
        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)
Example #5
0
    def __init__(self, pll, pads, mode="master"):
        self.tx_k = Signal(4)
        self.tx_d = Signal(32)
        self.rx_k = Signal(4)
        self.rx_d = Signal(32)

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

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

        # # #

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

        # clocking:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        ]
Example #6
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)
        ]
Example #7
0
    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)
        ]
Example #8
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("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))
        ]
Example #9
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))
        ]
Example #10
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))
        ]
Example #11
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))
Example #12
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))