示例#1
0
    def __init__(self, si5324_clkin, si5324_clkout_fabric,
                 ref_clk=None, ref_div2=False):
        self.switch_clocks = CSRStorage()
        self.phase_shift = CSR()
        self.phase_shift_done = CSRStatus(reset=1)
        self.sample_result = CSRStatus()

        # 125MHz/62.5MHz reference clock to 150MHz. VCO @ 625MHz.
        # Used to provide a startup clock to the transceiver through the Si,
        # we do not use the crystal reference so that the PFD (f3) frequency
        # can be high.
        mmcm_freerun_fb = Signal()
        mmcm_freerun_output = Signal()
        self.specials += \
            Instance("MMCME2_BASE",
                p_CLKIN1_PERIOD=16.0 if ref_div2 else 8.0,
                i_CLKIN1=ClockSignal("sys") if ref_clk is None else ref_clk,
                i_RST=ResetSignal("sys") if ref_clk is None else 0,

                p_CLKFBOUT_MULT_F=12.0 if ref_div2 else 6.0,
                p_DIVCLK_DIVIDE=1,

                o_CLKFBOUT=mmcm_freerun_fb, i_CLKFBIN=mmcm_freerun_fb,

                p_CLKOUT0_DIVIDE_F=5.0, o_CLKOUT0=mmcm_freerun_output,
            )
        
        # 150MHz to 150MHz with controllable phase shift, VCO @ 1200MHz.
        # Inserted between CDR and output to Si, used to correct 
        # non-determinstic skew of Si5324.
        mmcm_ps_fb = Signal()
        mmcm_ps_output = Signal()
        mmcm_ps_psdone = Signal()
        self.specials += \
            Instance("MMCME2_ADV",
                p_CLKIN1_PERIOD=1e9/150e6,
                i_CLKIN1=ClockSignal("rtio_rx0"),
                i_RST=ResetSignal("rtio_rx0"),
                i_CLKINSEL=1,  # yes, 1=CLKIN1 0=CLKIN2

                p_CLKFBOUT_MULT_F=8.0,
                p_CLKOUT0_DIVIDE_F=8.0,
                p_DIVCLK_DIVIDE=1,

                o_CLKFBOUT=mmcm_ps_fb, i_CLKFBIN=mmcm_ps_fb,

                p_CLKOUT0_USE_FINE_PS="TRUE",
                o_CLKOUT0=mmcm_ps_output,

                i_PSCLK=ClockSignal(),
                i_PSEN=self.phase_shift.re,
                i_PSINCDEC=self.phase_shift.r,
                o_PSDONE=mmcm_ps_psdone,
            )
        self.sync += [
            If(self.phase_shift.re, self.phase_shift_done.status.eq(0)),
            If(mmcm_ps_psdone, self.phase_shift_done.status.eq(1))
        ]

        si5324_clkin_se = Signal()
        self.specials += [
            Instance("BUFGMUX",
                i_I0=mmcm_freerun_output,
                i_I1=mmcm_ps_output,
                i_S=self.switch_clocks.storage,
                o_O=si5324_clkin_se
            ),
            Instance("OBUFDS",
                i_I=si5324_clkin_se,
                o_O=si5324_clkin.p, o_OB=si5324_clkin.n
            )
        ]

        si5324_clkout_se = Signal()
        self.specials += \
            Instance("IBUFDS",
                p_DIFF_TERM="TRUE", p_IBUF_LOW_PWR="TRUE",
                i_I=si5324_clkout_fabric.p, i_IB=si5324_clkout_fabric.n,
                o_O=si5324_clkout_se),
        
        clkout_sample1 = Signal()  # IOB register
        self.sync.rtio_rx0 += clkout_sample1.eq(si5324_clkout_se)
        self.specials += MultiReg(clkout_sample1, self.sample_result.status)

        # expose MMCM outputs - used for clock constraints
        self.mmcm_freerun_output = mmcm_freerun_output
        self.mmcm_ps_output = mmcm_ps_output
示例#2
0
    def __init__(self, sys_clk_freq, rx):
        self.done = Signal()
        self.restart = Signal()

        # GTX signals
        self.plllock = Signal()
        self.pllreset = Signal()
        self.gtXxreset = Signal()
        self.Xxresetdone = Signal()
        self.Xxdlysreset = Signal()
        self.Xxdlysresetdone = Signal()
        self.Xxphaligndone = Signal()
        self.Xxuserrdy = Signal()

        # # #

        # Double-latch transceiver asynch outputs
        plllock = Signal()
        Xxresetdone = Signal()
        Xxdlysresetdone = Signal()
        Xxphaligndone = Signal()
        self.specials += [
            MultiReg(self.plllock, plllock),
            MultiReg(self.Xxresetdone, Xxresetdone),
            MultiReg(self.Xxdlysresetdone, Xxdlysresetdone),
            MultiReg(self.Xxphaligndone, Xxphaligndone)
        ]

        # Deglitch FSM outputs driving transceiver asynch inputs
        gtXxreset = Signal()
        Xxdlysreset = Signal()
        Xxuserrdy = Signal()
        self.sync += [
            self.gtXxreset.eq(gtXxreset),
            self.Xxdlysreset.eq(Xxdlysreset),
            self.Xxuserrdy.eq(Xxuserrdy)
        ]

        # After configuration, transceiver resets have to stay low for
        # at least 500ns (see AR43482)
        startup_cycles = ceil(500 * sys_clk_freq / 1000000000)
        startup_timer = WaitTimer(startup_cycles)
        self.submodules += startup_timer

        startup_fsm = ResetInserter()(FSM(reset_state="RESET_ALL"))
        self.submodules += startup_fsm

        ready_timer = WaitTimer(1 * sys_clk_freq // 1000)
        self.submodules += ready_timer
        self.comb += [
            ready_timer.wait.eq(~self.done & ~startup_fsm.reset),
            startup_fsm.reset.eq(self.restart | ready_timer.done)
        ]

        if rx:
            cdr_stable_timer = WaitTimer(1024)
            self.submodules += cdr_stable_timer

        Xxphaligndone_r = Signal(reset=1)
        Xxphaligndone_rising = Signal()
        self.sync += Xxphaligndone_r.eq(Xxphaligndone)
        self.comb += Xxphaligndone_rising.eq(Xxphaligndone & ~Xxphaligndone_r)

        startup_fsm.act("RESET_ALL", gtXxreset.eq(1), self.pllreset.eq(1),
                        startup_timer.wait.eq(1),
                        NextState("RELEASE_PLL_RESET"))
        startup_fsm.act(
            "RELEASE_PLL_RESET", gtXxreset.eq(1), startup_timer.wait.eq(1),
            If(plllock & startup_timer.done, NextState("RELEASE_GTX_RESET")))
        # Release GTX reset and wait for GTX resetdone
        # (from UG476, GTX is reset on falling edge
        # of gtXxreset)
        if rx:
            startup_fsm.act(
                "RELEASE_GTX_RESET", Xxuserrdy.eq(1),
                cdr_stable_timer.wait.eq(1),
                If(Xxresetdone & cdr_stable_timer.done, NextState("ALIGN")))
        else:
            startup_fsm.act("RELEASE_GTX_RESET", Xxuserrdy.eq(1),
                            If(Xxresetdone, NextState("ALIGN")))
        # Start delay alignment (pulse)
        startup_fsm.act("ALIGN", Xxuserrdy.eq(1), Xxdlysreset.eq(1),
                        NextState("WAIT_ALIGN"))
        # Wait for delay alignment
        startup_fsm.act(
            "WAIT_ALIGN", Xxuserrdy.eq(1),
            If(Xxdlysresetdone, NextState("WAIT_FIRST_ALIGN_DONE")))
        # Wait 2 rising edges of Xxphaligndone
        # (from UG476 in buffer bypass config)
        startup_fsm.act(
            "WAIT_FIRST_ALIGN_DONE", Xxuserrdy.eq(1),
            If(Xxphaligndone_rising, NextState("WAIT_SECOND_ALIGN_DONE")))
        startup_fsm.act("WAIT_SECOND_ALIGN_DONE", Xxuserrdy.eq(1),
                        If(Xxphaligndone_rising, NextState("READY")))
        startup_fsm.act("READY", Xxuserrdy.eq(1), self.done.eq(1))
示例#3
0
文件: spi.py 项目: minisparrow/litex
    def __init__(self, pads, data_width):
        if pads is None:
            pads = Record(self.pads_layout)
        if not hasattr(pads, "cs_n"):
            pads.cs_n = Signal()
        self.pads = pads
        self.data_width = data_width

        self.start = Signal()
        self.length = Signal(8)
        self.done = Signal()
        self.irq = Signal()
        self.mosi = Signal(data_width)
        self.miso = Signal(data_width)
        self.cs = Signal()
        self.loopback = Signal()

        # # #

        clk = Signal()
        cs = Signal()
        mosi = Signal()
        miso = Signal()

        # IOs <--> Internal (input resynchronization) ----------------------------------------------
        self.specials += [
            MultiReg(pads.clk, clk),
            MultiReg(~pads.cs_n, cs),
            MultiReg(pads.mosi, mosi),
        ]
        self.comb += pads.miso.eq(miso)

        # Clock detection --------------------------------------------------------------------------
        clk_d = Signal()
        clk_rise = Signal()
        clk_fall = Signal()
        self.sync += clk_d.eq(clk)
        self.comb += clk_rise.eq(clk & ~clk_d)
        self.comb += clk_fall.eq(~clk & clk_d)

        # Control FSM ------------------------------------------------------------------------------
        self.submodules.fsm = fsm = FSM(reset_state="IDLE")
        fsm.act(
            "IDLE",
            If(cs, self.start.eq(1), NextValue(self.length, 0),
               NextState("XFER")).Else(self.done.eq(1)))
        fsm.act("XFER", If(~cs, self.irq.eq(1), NextState("IDLE")),
                NextValue(self.length, self.length + clk_rise))

        # Master In Slave Out (MISO) generation (generated on spi_clk falling edge) ----------------
        miso_data = Signal(data_width)
        self.sync += \
            If(self.start,
                miso_data.eq(self.miso)
            ).Elif(cs & clk_fall,
                miso_data.eq(Cat(Signal(), miso_data[:-1]))
            )
        self.comb += \
            If(self.loopback,
                miso.eq(mosi)
            ).Else(
                miso.eq(miso_data[-1]),
            )

        # Master Out Slave In (MOSI) capture (captured on spi_clk rising edge) ---------------------
        self.sync += \
            If(cs & clk_rise,
                self.mosi.eq(Cat(mosi, self.mosi[:-1]))
            )
示例#4
0
    def __init__(self,
                 pll,
                 tx_pads,
                 rx_pads,
                 sys_clk_freq,
                 data_width=20,
                 tx_buffer_enable=False,
                 rx_buffer_enable=False,
                 clock_aligner=True,
                 tx_polarity=0,
                 rx_polarity=0):
        assert (data_width == 20) or (data_width == 40)

        # TX controls
        self.tx_restart = Signal()
        self.tx_disable = Signal()
        self.tx_produce_square_wave = Signal()
        self.tx_prbs_config = Signal(2)

        # RX controls
        self.rx_ready = Signal()
        self.rx_restart = Signal()
        self.rx_prbs_config = Signal(2)
        self.rx_prbs_errors = Signal(32)

        # DRP
        self.drp = DRPInterface()

        # Loopback
        self.loopback = Signal(3)

        # # #

        use_cpll = isinstance(pll, GTHChannelPLL)
        use_qpll0 = isinstance(pll,
                               GTHQuadPLL) and pll.config["qpll"] == "qpll0"
        use_qpll1 = isinstance(pll,
                               GTHQuadPLL) and pll.config["qpll"] == "qpll1"

        self.nwords = nwords = data_width // 10

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

        self.tx_ready = Signal()
        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()

        self.tx_clk_freq = pll.config["linerate"] / data_width
        self.rx_clk_freq = pll.config["linerate"] / data_width

        # control/status cdc
        tx_produce_square_wave = Signal()
        tx_prbs_config = Signal(2)

        rx_prbs_config = Signal(2)
        rx_prbs_errors = Signal(32)

        self.specials += [
            MultiReg(self.tx_produce_square_wave, tx_produce_square_wave,
                     "tx"),
            MultiReg(self.tx_prbs_config, tx_prbs_config, "tx"),
        ]

        self.specials += [
            MultiReg(self.rx_prbs_config, rx_prbs_config, "rx"),
            MultiReg(rx_prbs_errors, self.rx_prbs_errors, "sys"),  # FIXME
        ]

        # # #

        # TX generates TX clock, init must be in system domain
        self.submodules.tx_init = tx_init = GTHTXInit(sys_clk_freq)
        self.comb += tx_init.restart.eq(self.tx_restart)
        # RX receives restart commands from TX domain
        self.submodules.rx_init = rx_init = ClockDomainsRenamer("tx")(
            GTHRXInit(self.tx_clk_freq))
        self.comb += [
            tx_init.plllock.eq(pll.lock),
            rx_init.plllock.eq(pll.lock),
            pll.reset.eq(tx_init.pllreset)
        ]

        # DRP mux
        self.submodules.drp_mux = drp_mux = DRPMux()
        drp_mux.add_interface(self.drp)

        txdata = Signal(data_width)
        rxdata = Signal(data_width)

        rxphaligndone = Signal()
        self.gth_params = dict(
            p_ACJTAG_DEBUG_MODE=0b0,
            p_ACJTAG_MODE=0b0,
            p_ACJTAG_RESET=0b0,
            p_ADAPT_CFG0=0b1111100000000000,
            p_ADAPT_CFG1=0b0000000000000000,
            p_ALIGN_COMMA_DOUBLE="FALSE",
            p_ALIGN_COMMA_ENABLE=0b0000000000,
            p_ALIGN_COMMA_WORD=1,
            p_ALIGN_MCOMMA_DET="FALSE",
            p_ALIGN_MCOMMA_VALUE=0b1010000011,
            p_ALIGN_PCOMMA_DET="FALSE",
            p_ALIGN_PCOMMA_VALUE=0b0101111100,
            p_A_RXOSCALRESET=0b0,
            p_A_RXPROGDIVRESET=0b0,
            p_A_TXPROGDIVRESET=0b0,
            p_CBCC_DATA_SOURCE_SEL="ENCODED",
            p_CDR_SWAP_MODE_EN=0b0,
            p_CHAN_BOND_KEEP_ALIGN="FALSE",
            p_CHAN_BOND_MAX_SKEW=1,
            p_CHAN_BOND_SEQ_1_1=0b0000000000,
            p_CHAN_BOND_SEQ_1_2=0b0000000000,
            p_CHAN_BOND_SEQ_1_3=0b0000000000,
            p_CHAN_BOND_SEQ_1_4=0b0000000000,
            p_CHAN_BOND_SEQ_1_ENABLE=0b1111,
            p_CHAN_BOND_SEQ_2_1=0b0000000000,
            p_CHAN_BOND_SEQ_2_2=0b0000000000,
            p_CHAN_BOND_SEQ_2_3=0b0000000000,
            p_CHAN_BOND_SEQ_2_4=0b0000000000,
            p_CHAN_BOND_SEQ_2_ENABLE=0b1111,
            p_CHAN_BOND_SEQ_2_USE="FALSE",
            p_CHAN_BOND_SEQ_LEN=1,
            p_CLK_CORRECT_USE="FALSE",
            p_CLK_COR_KEEP_IDLE="FALSE",
            p_CLK_COR_MAX_LAT=12 if rx_buffer_enable else 20,
            p_CLK_COR_MIN_LAT=8 if rx_buffer_enable else 18,
            p_CLK_COR_PRECEDENCE="TRUE",
            p_CLK_COR_REPEAT_WAIT=0,
            p_CLK_COR_SEQ_1_1=0b0000000000,
            p_CLK_COR_SEQ_1_2=0b0000000000,
            p_CLK_COR_SEQ_1_3=0b0000000000,
            p_CLK_COR_SEQ_1_4=0b0000000000,
            p_CLK_COR_SEQ_1_ENABLE=0b1111,
            p_CLK_COR_SEQ_2_1=0b0000000000,
            p_CLK_COR_SEQ_2_2=0b0000000000,
            p_CLK_COR_SEQ_2_3=0b0000000000,
            p_CLK_COR_SEQ_2_4=0b0000000000,
            p_CLK_COR_SEQ_2_ENABLE=0b1111,
            p_CLK_COR_SEQ_2_USE="FALSE",
            p_CLK_COR_SEQ_LEN=1,
            p_CPLL_CFG0=0b0110011111111000,
            p_CPLL_CFG1=0b1010010010101100,
            p_CPLL_CFG2=0b0000000000000111,
            p_CPLL_CFG3=0b000000,
            p_CPLL_FBDIV=1 if (use_qpll0 | use_qpll1) else pll.config["n2"],
            p_CPLL_FBDIV_45=4 if (use_qpll0 | use_qpll1) else pll.config["n1"],
            p_CPLL_INIT_CFG0=0b0000001010110010,
            p_CPLL_INIT_CFG1=0b00000000,
            p_CPLL_LOCK_CFG=0b0000000111101000,
            p_CPLL_REFCLK_DIV=1 if
            (use_qpll0 | use_qpll1) else pll.config["m"],
            p_DDI_CTRL=0b00,
            p_DDI_REALIGN_WAIT=15,
            p_DEC_MCOMMA_DETECT="FALSE",
            p_DEC_PCOMMA_DETECT="FALSE",
            p_DEC_VALID_COMMA_ONLY="FALSE",
            p_DFE_D_X_REL_POS=0b0,
            p_DFE_VCM_COMP_EN=0b0,
            p_DMONITOR_CFG0=0b0000000000,
            p_DMONITOR_CFG1=0b00000000,
            p_ES_CLK_PHASE_SEL=0b0,
            p_ES_CONTROL=0b000000,
            p_ES_ERRDET_EN="FALSE",
            p_ES_EYE_SCAN_EN="FALSE",
            p_ES_HORZ_OFFSET=0b000000000000,
            p_ES_PMA_CFG=0b0000000000,
            p_ES_PRESCALE=0b00000,
            p_ES_QUALIFIER0=0b0000000000000000,
            p_ES_QUALIFIER1=0b0000000000000000,
            p_ES_QUALIFIER2=0b0000000000000000,
            p_ES_QUALIFIER3=0b0000000000000000,
            p_ES_QUALIFIER4=0b0000000000000000,
            p_ES_QUAL_MASK0=0b0000000000000000,
            p_ES_QUAL_MASK1=0b0000000000000000,
            p_ES_QUAL_MASK2=0b0000000000000000,
            p_ES_QUAL_MASK3=0b0000000000000000,
            p_ES_QUAL_MASK4=0b0000000000000000,
            p_ES_SDATA_MASK0=0b0000000000000000,
            p_ES_SDATA_MASK1=0b0000000000000000,
            p_ES_SDATA_MASK2=0b0000000000000000,
            p_ES_SDATA_MASK3=0b0000000000000000,
            p_ES_SDATA_MASK4=0b0000000000000000,
            p_EVODD_PHI_CFG=0b00000000000,
            p_EYE_SCAN_SWAP_EN=0b0,
            p_FTS_DESKEW_SEQ_ENABLE=0b1111,
            p_FTS_LANE_DESKEW_CFG=0b1111,
            p_FTS_LANE_DESKEW_EN="FALSE",
            p_GEARBOX_MODE=0b00000,
            p_GM_BIAS_SELECT=0b0,
            p_LOCAL_MASTER=0b1,
            p_OOBDIVCTL=0b00,
            p_OOB_PWRUP=0b0,
            p_PCI3_AUTO_REALIGN="OVR_1K_BLK",
            p_PCI3_PIPE_RX_ELECIDLE=0b0,
            p_PCI3_RX_ASYNC_EBUF_BYPASS=0b00,
            p_PCI3_RX_ELECIDLE_EI2_ENABLE=0b0,
            p_PCI3_RX_ELECIDLE_H2L_COUNT=0b000000,
            p_PCI3_RX_ELECIDLE_H2L_DISABLE=0b000,
            p_PCI3_RX_ELECIDLE_HI_COUNT=0b000000,
            p_PCI3_RX_ELECIDLE_LP4_DISABLE=0b0,
            p_PCI3_RX_FIFO_DISABLE=0b0,
            p_PCIE_BUFG_DIV_CTRL=0b0001000000000000,
            p_PCIE_RXPCS_CFG_GEN3=0b0000001010100100,
            p_PCIE_RXPMA_CFG=0b0000000000001010,
            p_PCIE_TXPCS_CFG_GEN3=0b0010010010100100,
            p_PCIE_TXPMA_CFG=0b0000000000001010,
            p_PCS_PCIE_EN="FALSE",
            p_PCS_RSVD0=0b0000000000000000,
            p_PCS_RSVD1=0b000,
            p_PD_TRANS_TIME_FROM_P2=0b000000111100,
            p_PD_TRANS_TIME_NONE_P2=0b00011001,
            p_PD_TRANS_TIME_TO_P2=0b01100100,
            p_PLL_SEL_MODE_GEN12=0b00,
            p_PLL_SEL_MODE_GEN3=0b11,
            p_PMA_RSV1=0b1111000000000000,
            p_PROCESS_PAR=0b010,
            p_RATE_SW_USE_DRP=0b1,
            p_RESET_POWERSAVE_DISABLE=0b0,
        )
        self.gth_params.update(
            p_RXBUFRESET_TIME=0b00011,
            p_RXBUF_ADDR_MODE="FAST",
            p_RXBUF_EIDLE_HI_CNT=0b1000,
            p_RXBUF_EIDLE_LO_CNT=0b0000,
            p_RXBUF_EN="TRUE" if rx_buffer_enable else "FALSE",
            p_RXBUF_RESET_ON_CB_CHANGE="TRUE",
            p_RXBUF_RESET_ON_COMMAALIGN="FALSE",
            p_RXBUF_RESET_ON_EIDLE="FALSE",
            p_RXBUF_RESET_ON_RATE_CHANGE="TRUE",
            p_RXBUF_THRESH_OVFLW=57 if rx_buffer_enable else 0,
            p_RXBUF_THRESH_OVRD="TRUE" if rx_buffer_enable else "FALSE",
            p_RXBUF_THRESH_UNDFLW=3 if rx_buffer_enable else 0,
            p_RXCDRFREQRESET_TIME=0b00001,
            p_RXCDRPHRESET_TIME=0b00001,
            p_RXCDR_CFG0=0b0000000000000000,
            p_RXCDR_CFG0_GEN3=0b0000000000000000,
            p_RXCDR_CFG1=0b0000000000000000,
            p_RXCDR_CFG1_GEN3=0b0000000000000000,
            p_RXCDR_CFG2=0b0000011111010110,
            p_RXCDR_CFG2_GEN3=0b0000011111100110,
            p_RXCDR_CFG3=0b0000000000000000,
            p_RXCDR_CFG3_GEN3=0b0000000000000000,
            p_RXCDR_CFG4=0b0000000000000000,
            p_RXCDR_CFG4_GEN3=0b0000000000000000,
            p_RXCDR_CFG5=0b0000000000000000,
            p_RXCDR_CFG5_GEN3=0b0000000000000000,
            p_RXCDR_FR_RESET_ON_EIDLE=0b0,
            p_RXCDR_HOLD_DURING_EIDLE=0b0,
            p_RXCDR_LOCK_CFG0=0b0100010010000000,
            p_RXCDR_LOCK_CFG1=0b0101111111111111,
            p_RXCDR_LOCK_CFG2=0b0111011111000011,
            p_RXCDR_PH_RESET_ON_EIDLE=0b0,
            p_RXCFOK_CFG0=0b0100000000000000,
            p_RXCFOK_CFG1=0b0000000001100101,
            p_RXCFOK_CFG2=0b0000000000101110,
            p_RXDFELPMRESET_TIME=0b0001111,
            p_RXDFELPM_KL_CFG0=0b0000000000000000,
            p_RXDFELPM_KL_CFG1=0b0000000000000010,
            p_RXDFELPM_KL_CFG2=0b0000000000000000,
            p_RXDFE_CFG0=0b0000101000000000,
            p_RXDFE_CFG1=0b0000000000000000,
            p_RXDFE_GC_CFG0=0b0000000000000000,
            p_RXDFE_GC_CFG1=0b0111100001110000,
            p_RXDFE_GC_CFG2=0b0000000000000000,
            p_RXDFE_H2_CFG0=0b0000000000000000,
            p_RXDFE_H2_CFG1=0b0000000000000000,
            p_RXDFE_H3_CFG0=0b0100000000000000,
            p_RXDFE_H3_CFG1=0b0000000000000000,
            p_RXDFE_H4_CFG0=0b0010000000000000,
            p_RXDFE_H4_CFG1=0b0000000000000011,
            p_RXDFE_H5_CFG0=0b0010000000000000,
            p_RXDFE_H5_CFG1=0b0000000000000011,
            p_RXDFE_H6_CFG0=0b0010000000000000,
            p_RXDFE_H6_CFG1=0b0000000000000000,
            p_RXDFE_H7_CFG0=0b0010000000000000,
            p_RXDFE_H7_CFG1=0b0000000000000000,
            p_RXDFE_H8_CFG0=0b0010000000000000,
            p_RXDFE_H8_CFG1=0b0000000000000000,
            p_RXDFE_H9_CFG0=0b0010000000000000,
            p_RXDFE_H9_CFG1=0b0000000000000000,
            p_RXDFE_HA_CFG0=0b0010000000000000,
            p_RXDFE_HA_CFG1=0b0000000000000000,
            p_RXDFE_HB_CFG0=0b0010000000000000,
            p_RXDFE_HB_CFG1=0b0000000000000000,
            p_RXDFE_HC_CFG0=0b0000000000000000,
            p_RXDFE_HC_CFG1=0b0000000000000000,
            p_RXDFE_HD_CFG0=0b0000000000000000,
            p_RXDFE_HD_CFG1=0b0000000000000000,
            p_RXDFE_HE_CFG0=0b0000000000000000,
            p_RXDFE_HE_CFG1=0b0000000000000000,
            p_RXDFE_HF_CFG0=0b0000000000000000,
            p_RXDFE_HF_CFG1=0b0000000000000000,
            p_RXDFE_OS_CFG0=0b1000000000000000,
            p_RXDFE_OS_CFG1=0b0000000000000000,
            p_RXDFE_UT_CFG0=0b1000000000000000,
            p_RXDFE_UT_CFG1=0b0000000000000011,
            p_RXDFE_VP_CFG0=0b1010101000000000,
            p_RXDFE_VP_CFG1=0b0000000000110011,
            p_RXDLY_CFG=0b0000000000011111,
            p_RXDLY_LCFG=0b0000000000110000,
            p_RXELECIDLE_CFG="SIGCFG_4",
            p_RXGBOX_FIFO_INIT_RD_ADDR=4,
            p_RXGEARBOX_EN="FALSE",
            p_RXISCANRESET_TIME=0b00001,
            p_RXLPM_CFG=0b0000000000000000,
            p_RXLPM_GC_CFG=0b0001000000000000,
            p_RXLPM_KH_CFG0=0b0000000000000000,
            p_RXLPM_KH_CFG1=0b0000000000000010,
            p_RXLPM_OS_CFG0=0b1000000000000000,
            p_RXLPM_OS_CFG1=0b0000000000000010,
            p_RXOOB_CFG=0b000000110,
            p_RXOOB_CLK_CFG="PMA",
            p_RXOSCALRESET_TIME=0b00011,
            p_RXOUT_DIV=pll.config["d"],
            p_RXPCSRESET_TIME=0b00011,
            p_RXPHBEACON_CFG=0b0000000000000000,
            p_RXPHDLY_CFG=0b0010000000100000,
            p_RXPHSAMP_CFG=0b0010000100000000,
            p_RXPHSLIP_CFG=0b0110011000100010,
            p_RXPH_MONITOR_SEL=0b00000,
            p_RXPI_CFG0=0b00,
            p_RXPI_CFG1=0b00,
            p_RXPI_CFG2=0b00,
            p_RXPI_CFG3=0b00,
            p_RXPI_CFG4=0b1,
            p_RXPI_CFG5=0b1,
            p_RXPI_CFG6=0b000,
            p_RXPI_LPM=0b0,
            p_RXPI_VREFSEL=0b0,
            p_RXPMACLK_SEL="DATA",
            p_RXPMARESET_TIME=0b00011,
            p_RXPRBS_ERR_LOOPBACK=0b0,
            p_RXPRBS_LINKACQ_CNT=15,
            p_RXSLIDE_AUTO_WAIT=7,
            p_RXSLIDE_MODE="OFF",
            p_RXSYNC_MULTILANE=0b0,
            p_RXSYNC_OVRD=0b0,
            p_RXSYNC_SKIP_DA=0b0,
            p_RX_AFE_CM_EN=0b0,
            p_RX_BIAS_CFG0=0b0000101010110100,
            p_RX_BUFFER_CFG=0b000000,
            p_RX_CAPFF_SARC_ENB=0b0,
            p_RX_CLK25_DIV=5,
            p_RX_CLKMUX_EN=0b1,
            p_RX_CLK_SLIP_OVRD=0b00000,
            p_RX_CM_BUF_CFG=0b1010,
            p_RX_CM_BUF_PD=0b0,
            p_RX_CM_SEL=0b11,
            p_RX_CM_TRIM=0b1010,
            p_RX_CTLE3_LPF=0b00000001,
            p_RX_DATA_WIDTH=data_width,
            p_RX_DDI_SEL=0b000000,
            p_RX_DEFER_RESET_BUF_EN="TRUE",
            p_RX_DFELPM_CFG0=0b0110,
            p_RX_DFELPM_CFG1=0b1,
            p_RX_DFELPM_KLKH_AGC_STUP_EN=0b1,
            p_RX_DFE_AGC_CFG0=0b10,
            p_RX_DFE_AGC_CFG1=0b100,
            p_RX_DFE_KL_LPM_KH_CFG0=0b01,
            p_RX_DFE_KL_LPM_KH_CFG1=0b100,
            p_RX_DFE_KL_LPM_KL_CFG0=0b01,
            p_RX_DFE_KL_LPM_KL_CFG1=0b100,
            p_RX_DFE_LPM_HOLD_DURING_EIDLE=0b0,
            p_RX_DISPERR_SEQ_MATCH="TRUE",
            p_RX_DIVRESET_TIME=0b00001,
            p_RX_EN_HI_LR=0b0,
            p_RX_EYESCAN_VS_CODE=0b0000000,
            p_RX_EYESCAN_VS_NEG_DIR=0b0,
            p_RX_EYESCAN_VS_RANGE=0b00,
            p_RX_EYESCAN_VS_UT_SIGN=0b0,
            p_RX_FABINT_USRCLK_FLOP=0b0,
            p_RX_INT_DATAWIDTH=data_width == 40,
            p_RX_PMA_POWER_SAVE=0b0,
            p_RX_PROGDIV_CFG=0.0,
            p_RX_SAMPLE_PERIOD=0b111,
            p_RX_SIG_VALID_DLY=11,
            p_RX_SUM_DFETAPREP_EN=0b0,
            p_RX_SUM_IREF_TUNE=0b0000,
            p_RX_SUM_RES_CTRL=0b00,
            p_RX_SUM_VCMTUNE=0b0000,
            p_RX_SUM_VCM_OVWR=0b0,
            p_RX_SUM_VREF_TUNE=0b000,
            p_RX_TUNE_AFE_OS=0b10,
            p_RX_WIDEMODE_CDR=0b0,
            p_RX_XCLK_SEL="RXDES" if rx_buffer_enable else "RXUSR",
            p_SAS_MAX_COM=64,
            p_SAS_MIN_COM=36,
            p_SATA_BURST_SEQ_LEN=0b1110,
            p_SATA_CPLL_CFG="VCO_3000MHZ",
            p_SATA_MAX_BURST=8,
            p_SATA_MAX_INIT=21,
            p_SATA_MAX_WAKE=7,
            p_SATA_MIN_BURST=4,
            p_SATA_MIN_INIT=12,
            p_SATA_MIN_WAKE=4,
            p_SHOW_REALIGN_COMMA="TRUE",
            p_SIM_RECEIVER_DETECT_PASS="******",
            p_SIM_RESET_SPEEDUP="TRUE",
            p_SIM_TX_EIDLE_DRIVE_LEVEL=0b0,
            p_SIM_VERSION=2,
            p_TAPDLY_SET_TX=0b00,
            p_TEMPERATUR_PAR=0b0010,
            p_TERM_RCAL_CFG=0b100001000010000,
            p_TERM_RCAL_OVRD=0b000,
            p_TRANS_TIME_RATE=0b00001110,
            p_TST_RSV0=0b00000000,
            p_TST_RSV1=0b00000000,
        )
        self.gth_params.update(
            p_TXBUF_EN="TRUE" if tx_buffer_enable else "FALSE",
            p_TXBUF_RESET_ON_RATE_CHANGE="TRUE",
            p_TXDLY_CFG=0b0000000000001001,
            p_TXDLY_LCFG=0b0000000001010000,
            p_TXDRVBIAS_N=0b1010,
            p_TXDRVBIAS_P=0b1010,
            p_TXFIFO_ADDR_CFG="LOW",
            p_TXGBOX_FIFO_INIT_RD_ADDR=4,
            p_TXGEARBOX_EN="FALSE",
            p_TXOUT_DIV=pll.config["d"],
            p_TXPCSRESET_TIME=0b00011,
            p_TXPHDLY_CFG0=0b0010000000100000,
            p_TXPHDLY_CFG1=0b0000000001110101,
            p_TXPH_CFG=0b0000100110000000,
            p_TXPH_MONITOR_SEL=0b00000,
            p_TXPI_CFG0=0b00,
            p_TXPI_CFG1=0b00,
            p_TXPI_CFG2=0b00,
            p_TXPI_CFG3=0b1,
            p_TXPI_CFG4=0b1,
            p_TXPI_CFG5=0b000,
            p_TXPI_GRAY_SEL=0b0,
            p_TXPI_INVSTROBE_SEL=0b0,
            p_TXPI_LPM=0b0,
            p_TXPI_PPMCLK_SEL="TXUSRCLK2",
            p_TXPI_PPM_CFG=0b00000000,
            p_TXPI_SYNFREQ_PPM=0b001,
            p_TXPI_VREFSEL=0b0,
            p_TXPMARESET_TIME=0b00011,
            p_TXSYNC_MULTILANE=0,
            p_TXSYNC_OVRD=0b0,
            p_TXSYNC_SKIP_DA=0b0,
            p_TX_CLK25_DIV=5,
            p_TX_CLKMUX_EN=0b1,
            p_TX_DATA_WIDTH=data_width,
            p_TX_DCD_CFG=0b000010,
            p_TX_DCD_EN=0b0,
            p_TX_DEEMPH0=0b000000,
            p_TX_DEEMPH1=0b000000,
            p_TX_DIVRESET_TIME=0b00001,
            p_TX_DRIVE_MODE="DIRECT",
            p_TX_EIDLE_ASSERT_DELAY=0b100,
            p_TX_EIDLE_DEASSERT_DELAY=0b011,
            p_TX_EML_PHI_TUNE=0b0,
            p_TX_FABINT_USRCLK_FLOP=0b0,
            p_TX_IDLE_DATA_ZERO=0b0,
            p_TX_INT_DATAWIDTH=data_width == 40,
            p_TX_LOOPBACK_DRIVE_HIZ="FALSE",
            p_TX_MAINCURSOR_SEL=0b0,
            p_TX_MARGIN_FULL_0=0b1001111,
            p_TX_MARGIN_FULL_1=0b1001110,
            p_TX_MARGIN_FULL_2=0b1001100,
            p_TX_MARGIN_FULL_3=0b1001010,
            p_TX_MARGIN_FULL_4=0b1001000,
            p_TX_MARGIN_LOW_0=0b1000110,
            p_TX_MARGIN_LOW_1=0b1000101,
            p_TX_MARGIN_LOW_2=0b1000011,
            p_TX_MARGIN_LOW_3=0b1000010,
            p_TX_MARGIN_LOW_4=0b1000000,
            p_TX_MODE_SEL=0b000,
            p_TX_PMADATA_OPT=0b0,
            p_TX_PMA_POWER_SAVE=0b0,
            p_TX_PROGCLK_SEL="PREPI",
            p_TX_PROGDIV_CFG=0.0,
            p_TX_QPI_STATUS_EN=0b0,
            p_TX_RXDETECT_CFG=0b00000000110010,
            p_TX_RXDETECT_REF=0b100,
            p_TX_SAMPLE_PERIOD=0b111,
            p_TX_SARC_LPBK_ENB=0b0,
            p_TX_XCLK_SEL="TXOUT" if tx_buffer_enable else "TXUSR",
            p_USE_PCS_CLK_PHASE_SEL=0b0,
            p_WB_MODE=0b00,
        )
        self.gth_params.update(
            # Reset modes
            i_GTRESETSEL=0,
            i_RESETOVRD=0,

            # DRP
            i_DRPADDR=drp_mux.addr,
            i_DRPCLK=drp_mux.clk,
            i_DRPDI=drp_mux.di,
            o_DRPDO=drp_mux.do,
            i_DRPEN=drp_mux.en,
            o_DRPRDY=drp_mux.rdy,
            i_DRPWE=drp_mux.we,

            # CPLL
            i_CPLLRESET=0,
            i_CPLLPD=0 if (use_qpll0 | use_qpll1) else pll.reset,
            o_CPLLLOCK=Signal() if (use_qpll0 | use_qpll1) else pll.lock,
            i_CPLLLOCKEN=1,
            i_CPLLREFCLKSEL=0b001,
            i_TSTIN=2**20 - 1,
            i_GTREFCLK0=0 if (use_qpll0 | use_qpll1) else pll.refclk,

            # QPLL
            i_QPLL0CLK=0 if (use_cpll | use_qpll1) else pll.clk,
            i_QPLL0REFCLK=0 if (use_cpll | use_qpll1) else pll.refclk,
            i_QPLL1CLK=0 if (use_cpll | use_qpll0) else pll.clk,
            i_QPLL1REFCLK=0 if (use_cpll | use_qpll0) else pll.refclk,

            # TX clock
            o_TXOUTCLK=self.txoutclk,
            i_TXSYSCLKSEL=0b00 if use_cpll else 0b10 if use_qpll0 else 0b11,
            i_TXPLLCLKSEL=0b00 if use_cpll else 0b11 if use_qpll0 else 0b10,
            i_TXOUTCLKSEL=0b010 if tx_buffer_enable else 0b011,

            # TX Startup/Reset
            i_GTTXRESET=tx_init.gtXxreset,
            o_TXRESETDONE=tx_init.Xxresetdone,
            i_TXDLYSRESET=tx_init.Xxdlysreset,
            o_TXDLYSRESETDONE=tx_init.Xxdlysresetdone,
            o_TXPHALIGNDONE=tx_init.Xxphaligndone,
            i_TXUSERRDY=tx_init.Xxuserrdy,
            i_TXSYNCMODE=1,
            i_TXDLYBYPASS=1 if tx_buffer_enable else 0,
            i_TXPHDLYPD=1 if tx_buffer_enable else 0,

            # TX data
            i_TXCTRL0=Cat(*[txdata[10 * i + 8] for i in range(nwords)]),
            i_TXCTRL1=Cat(*[txdata[10 * i + 9] for i in range(nwords)]),
            i_TXDATA=Cat(*[txdata[10 * i:10 * i + 8] for i in range(nwords)]),
            i_TXUSRCLK=ClockSignal("tx"),
            i_TXUSRCLK2=ClockSignal("tx"),

            # TX electrical
            i_TXPD=0b00,
            i_TXBUFDIFFCTRL=0b000,
            i_TXDIFFCTRL=0b1100,
            i_TXINHIBIT=self.tx_disable,

            # Internal Loopback
            i_LOOPBACK=self.loopback,

            # RX Startup/Reset
            i_GTRXRESET=rx_init.gtXxreset,
            o_RXRESETDONE=rx_init.Xxresetdone,
            i_RXDLYSRESET=rx_init.Xxdlysreset,
            o_RXPHALIGNDONE=rxphaligndone,
            i_RXSYNCALLIN=rxphaligndone,
            i_RXUSERRDY=rx_init.Xxuserrdy,
            i_RXSYNCIN=0,
            i_RXSYNCMODE=1,
            o_RXSYNCDONE=rx_init.Xxsyncdone,
            i_RXDLYBYPASS=1 if rx_buffer_enable else 0,
            i_RXPHDLYPD=1 if rx_buffer_enable else 0,

            # RX AFE
            i_RXDFEAGCCTRL=1,
            i_RXDFEXYDEN=1,
            i_RXLPMEN=1,
            i_RXOSINTCFG=0xd,
            i_RXOSINTEN=1,

            # RX clock
            i_RXRATE=0,
            i_RXSYSCLKSEL=0b00,
            i_RXOUTCLKSEL=0b010,
            i_RXPLLCLKSEL=0b00,
            o_RXOUTCLK=self.rxoutclk,
            i_RXUSRCLK=ClockSignal("rx"),
            i_RXUSRCLK2=ClockSignal("rx"),

            # RX data
            o_RXCTRL0=Cat(*[rxdata[10 * i + 8] for i in range(nwords)]),
            o_RXCTRL1=Cat(*[rxdata[10 * i + 9] for i in range(nwords)]),
            o_RXDATA=Cat(*[rxdata[10 * i:10 * i + 8] for i in range(nwords)]),

            # RX electrical
            i_RXPD=0b00,
            i_RXELECIDLEMODE=0b11,

            # Polarity
            i_TXPOLARITY=tx_polarity,
            i_RXPOLARITY=rx_polarity,

            # Pads
            i_GTHRXP=rx_pads.p,
            i_GTHRXN=rx_pads.n,
            o_GTHTXP=tx_pads.p,
            o_GTHTXN=tx_pads.n)

        # tx clocking
        tx_reset_deglitched = Signal()
        tx_reset_deglitched.attr.add("no_retiming")
        self.sync += tx_reset_deglitched.eq(~tx_init.done)
        self.clock_domains.cd_tx = ClockDomain()
        if not tx_buffer_enable:
            tx_bufg_div = pll.config["clkin"] / self.tx_clk_freq
        else:
            txoutclk_div = 1
        assert tx_bufg_div == int(tx_bufg_div)
        self.specials += [
            Instance("BUFG_GT",
                     i_I=self.txoutclk,
                     o_O=self.cd_tx.clk,
                     i_DIV=int(tx_bufg_div) - 1),
            AsyncResetSynchronizer(self.cd_tx, tx_reset_deglitched)
        ]

        # rx clocking
        rx_reset_deglitched = Signal()
        rx_reset_deglitched.attr.add("no_retiming")
        self.sync.tx += rx_reset_deglitched.eq(~rx_init.done)
        self.clock_domains.cd_rx = ClockDomain()
        self.specials += [
            Instance("BUFG_GT", i_I=self.rxoutclk, o_O=self.cd_rx.clk),
            AsyncResetSynchronizer(self.cd_rx, rx_reset_deglitched)
        ]

        # tx data and prbs
        self.submodules.tx_prbs = ClockDomainsRenamer("tx")(PRBSTX(
            data_width, True))
        self.comb += self.tx_prbs.config.eq(tx_prbs_config)
        self.comb += [
            self.tx_prbs.i.eq(
                Cat(*[self.encoder.output[i] for i in range(nwords)])),
            If(
                tx_produce_square_wave,
                # square wave @ linerate/data_width for scope observation
                txdata.eq(Signal(data_width, reset=1 << (data_width // 2) - 1)
                          )).Else(txdata.eq(self.tx_prbs.o))
        ]

        # rx data and prbs
        self.submodules.rx_prbs = ClockDomainsRenamer("rx")(PRBSRX(
            data_width, True))
        self.comb += [
            self.rx_prbs.config.eq(rx_prbs_config),
            rx_prbs_errors.eq(self.rx_prbs.errors)
        ]
        for i in range(nwords):
            self.comb += self.decoders[i].input.eq(rxdata[10 * i:10 * (i + 1)])
        self.comb += self.rx_prbs.i.eq(rxdata)

        # clock alignment
        if clock_aligner:
            clock_aligner = BruteforceClockAligner(0b0101111100,
                                                   self.tx_clk_freq)
            self.submodules += clock_aligner
            self.comb += [
                clock_aligner.rxdata.eq(rxdata),
                rx_init.restart.eq(clock_aligner.restart | self.rx_restart),
                self.rx_ready.eq(clock_aligner.ready)
            ]
        else:
            self.comb += self.rx_ready.eq(rx_init.done)
示例#5
0
    def __init__(self, default_video_timings="800x600@60Hz"):
        vt = video_timings[default_video_timings]
        # MMAP Control/Status Registers.
        self._enable = CSRStorage(reset=1)

        self._hres = CSRStorage(hbits, vt["h_active"])
        self._hsync_start = CSRStorage(hbits,
                                       vt["h_active"] + vt["h_sync_offset"])
        self._hsync_end = CSRStorage(
            hbits, vt["h_active"] + vt["h_sync_offset"] + vt["h_sync_width"])
        self._hscan = CSRStorage(hbits, vt["h_active"] + vt["h_blanking"])

        self._vres = CSRStorage(vbits, vt["v_active"])
        self._vsync_start = CSRStorage(vbits,
                                       vt["v_active"] + vt["v_sync_offset"])
        self._vsync_end = CSRStorage(
            vbits, vt["v_active"] + vt["v_sync_offset"] + vt["v_sync_width"])
        self._vscan = CSRStorage(vbits, vt["v_active"] + vt["v_blanking"])

        # Video Timing Source
        self.source = source = stream.Endpoint(video_timing_layout)

        # # #

        # Resynchronize Enable to Video clock domain.
        self.enable = enable = Signal()
        self.specials += MultiReg(self._enable.storage, enable)

        # Resynchronize Horizontal Timings to Video clock domain.
        self.hres = hres = Signal(hbits)
        self.hsync_start = hsync_start = Signal(hbits)
        self.hsync_end = hsync_end = Signal(hbits)
        self.hscan = hscan = Signal(hbits)
        self.specials += MultiReg(self._hres.storage, hres)
        self.specials += MultiReg(self._hsync_start.storage, hsync_start)
        self.specials += MultiReg(self._hsync_end.storage, hsync_end)
        self.specials += MultiReg(self._hscan.storage, hscan)

        # Resynchronize Vertical Timings to Video clock domain.
        self.vres = vres = Signal(vbits)
        self.vsync_start = vsync_start = Signal(vbits)
        self.vsync_end = vsync_end = Signal(vbits)
        self.vscan = vscan = Signal(vbits)
        self.specials += MultiReg(self._vres.storage, vres)
        self.specials += MultiReg(self._vsync_start.storage, vsync_start)
        self.specials += MultiReg(self._vsync_end.storage, vsync_end)
        self.specials += MultiReg(self._vscan.storage, vscan)

        # Generate timings.
        hactive = Signal()
        vactive = Signal()
        fsm = FSM(reset_state="IDLE")
        fsm = ResetInserter()(fsm)
        self.submodules.fsm = fsm
        self.comb += fsm.reset.eq(~enable)
        fsm.act("IDLE", NextValue(hactive, 0), NextValue(vactive, 0),
                NextValue(source.hres, hres), NextValue(source.vres, vres),
                NextValue(source.hcount, 0), NextValue(source.vcount, 0),
                NextState("RUN"))
        self.comb += source.de.eq(
            hactive & vactive)  # DE when both HActive and VActive.
        self.sync += source.first.eq((source.hcount == 0)
                                     & (source.vcount == 0)),
        self.sync += source.last.eq((source.hcount == hscan)
                                    & (source.vcount == vscan)),
        fsm.act(
            "RUN",
            source.valid.eq(1),
            If(
                source.ready,
                # Increment HCount.
                NextValue(source.hcount, source.hcount + 1),
                # Generate HActive / HSync.
                If(source.hcount == 0, NextValue(hactive,
                                                 1)),  # Start of HActive.
                If(source.hcount == hres, NextValue(hactive,
                                                    0)),  # End of HActive.
                If(source.hcount == hsync_start,
                   NextValue(source.hsync, 1)),  # Start of HSync.
                If(source.hcount == hsync_end, NextValue(source.hsync,
                                                         0)),  # End of HSync.
                # End of HScan.
                If(
                    source.hcount == hscan,
                    # Reset HCount.
                    NextValue(source.hcount, 0),
                    # Increment VCount.
                    NextValue(source.vcount, source.vcount + 1),
                    # Generate VActive / VSync.
                    If(source.vcount == 0, NextValue(vactive,
                                                     1)),  # Start of VActive.
                    If(source.vcount == vres, NextValue(vactive,
                                                        0)),  # End of HActive.
                    If(source.vcount == vsync_start,
                       NextValue(source.vsync, 1)),  # Start of VSync.
                    If(source.vcount == vsync_end,
                       NextValue(source.vsync, 0)),  # End of VSync.
                    # End of VScan.
                    If(
                        source.vcount == vscan,
                        # Reset VCount.
                        NextValue(source.vcount, 0),
                    ))))
示例#6
0
    def __init__(self, pads, out_fifo, in_fifo):
        di = Signal(4)
        self.comb += [
            pads.rs_t.oe.eq(1),
            pads.rw_t.oe.eq(1),
            pads.e_t.oe.eq(1),
            pads.d_t.oe.eq(~pads.rw_t.o),
        ]
        self.specials += [MultiReg(pads.d_t.i, di)]

        rx_setup_cyc = math.ceil(60e-9 * 30e6)
        e_pulse_cyc = math.ceil(500e-9 * 30e6)
        e_wait_cyc = math.ceil(700e-9 * 30e6)
        cmd_wait_cyc = math.ceil(1.52e-3 * 30e6)
        timer = Signal(
            max=max([rx_setup_cyc, e_pulse_cyc, e_wait_cyc, cmd_wait_cyc]))

        cmd = Signal(8)
        data = Signal(8)
        msb = Signal()

        self.submodules.fsm = FSM(reset_state="IDLE")
        self.fsm.act(
            "IDLE", NextValue(pads.e_t.o, 0),
            If(out_fifo.readable, out_fifo.re.eq(1),
               NextValue(cmd, out_fifo.dout), NextState("COMMAND")))
        self.fsm.act(
            "COMMAND", NextValue(msb, (cmd & XFER_BIT_HALF) == 0),
            NextValue(pads.rs_t.o, (cmd & XFER_BIT_DATA) != 0),
            NextValue(pads.rw_t.o, (cmd & XFER_BIT_READ) != 0),
            If(cmd & XFER_BIT_WAIT, NextValue(timer, cmd_wait_cyc),
               NextState("WAIT")).Elif(cmd & XFER_BIT_READ,
                                       NextValue(timer, rx_setup_cyc),
                                       NextState("READ-SETUP")).Elif(
                                           out_fifo.readable,
                                           out_fifo.re.eq(1),
                                           NextValue(data, out_fifo.dout),
                                           NextState("WRITE"),
                                       ))
        self.fsm.act(
            "WRITE",
            If(
                timer == 0, NextValue(pads.e_t.o, 1),
                If(msb,
                   NextValue(pads.d_t.o,
                             data[4:])).Else(NextValue(pads.d_t.o, data[:4])),
                NextValue(timer, e_pulse_cyc),
                NextState("WRITE-HOLD")).Else(NextValue(timer, timer - 1)))
        self.fsm.act(
            "WRITE-HOLD",
            If(timer == 0, NextValue(pads.e_t.o, 0), NextValue(msb, ~msb),
               NextValue(timer, e_wait_cyc),
               If(msb, NextState("WRITE")).Else(NextState("WAIT"))).Else(
                   NextValue(timer, timer - 1)))
        self.fsm.act(
            "READ-SETUP",
            If(timer == 0, NextValue(pads.e_t.o, 1),
               NextValue(timer, e_pulse_cyc),
               NextState("READ")).Else(NextValue(timer, timer - 1)))
        self.fsm.act(
            "READ",
            If(
                timer == 0,
                If(~(cmd & XFER_BIT_DATA) & msb & di[3],
                   # BF=1, wait until it goes low
                   ).Else(
                       NextValue(pads.e_t.o, 0), NextValue(msb, ~msb),
                       NextValue(timer, e_wait_cyc),
                       If(msb, NextValue(data[4:],
                                         di), NextState("READ-SETUP")).Else(
                                             NextValue(data[:4], di),
                                             NextState("READ-PROCESS")))).Else(
                                                 NextValue(timer, timer - 1)))
        self.fsm.act(
            "READ-PROCESS",
            If(
                cmd & XFER_BIT_DATA,
                If(in_fifo.writable, in_fifo.din.eq(data), in_fifo.we.eq(1),
                   NextState("WAIT"))).Else(
                       # done reading status register, ignore it and continue
                       NextState("WAIT")))
        self.fsm.act(
            "WAIT",
            If(
                timer == 0,
                NextState("IDLE"),
            ).Else(NextValue(timer, timer - 1)))
示例#7
0
    def __init__(self, input_pads, rtio_clk_freq=150e6):
        N = 64
        self.reset = CSRStorage(reset=1)
        self.locked = CSRStatus()
        self.dt = CSRStatus(N.bit_length())

        # # #

        self.clock_domains.cd_helper = ClockDomain(reset_less=True)
        helper_locked = Signal()
        helper_fb = Signal()
        helper_output = Signal()

        input_se = Signal()
        beat1 = Signal()
        beat2 = Signal()
        self.specials += [
            Instance("MMCME2_BASE",
                p_CLKIN1_PERIOD=1e9/rtio_clk_freq,
                i_CLKIN1=ClockSignal("rtio"),
                i_RST=self.reset.storage,
                o_LOCKED=helper_locked,

                # VCO at 1200MHz with 150MHz RTIO frequency
                p_CLKFBOUT_MULT_F=8.0,
                p_DIVCLK_DIVIDE=1,

                o_CLKFBOUT=helper_fb, i_CLKFBIN=helper_fb,

                # helper PLL ratio: 64/65 (N=64)
                p_CLKOUT0_DIVIDE_F=8.125,
                o_CLKOUT0=helper_output,
            ),
            MultiReg(helper_locked, self.locked.status),
            Instance("BUFG", i_I=helper_output, o_O=self.cd_helper.clk),
            Instance("IBUFDS", i_I=input_pads.p, i_IB=input_pads.n, o_O=input_se),
            Instance("FD", i_C=self.cd_helper.clk, i_D=input_se, o_Q=beat1, attr={("IOB", "TRUE")}),
            Instance("FD", i_C=self.cd_helper.clk, i_D=ClockSignal("rtio"), o_Q=beat2),
        ]

        ed1 = DDMTDEdgeDetector(beat1)
        ed2 = DDMTDEdgeDetector(beat2)
        self.submodules += ed1, ed2

        counting = Signal()
        counter = Signal(N.bit_length())
        result = Signal.like(counter)
        self.sync.helper += [
            If(counting,
                counter.eq(counter + 1)
            ).Else(
                result.eq(counter)
            ),

            If(ed1.rising, counting.eq(1), counter.eq(0)),
            If(ed2.rising, counting.eq(0))
        ]

        bsync = BusSynchronizer(len(result), "helper", "sys")
        self.submodules += bsync
        self.comb += [
            bsync.i.eq(result),
            self.dt.status.eq(bsync.o)
        ]
示例#8
0
    def __init__(self, pads, default=_default_edid):
        self._hpd_notif = CSRStatus()
        self._hpd_en = CSRStorage()
        mem_size = len(default)
        assert mem_size % 128 == 0
        self.specials.mem = Memory(8, mem_size, init=default)

        # # #

        # HPD
        if hasattr(pads, "hpd_notif"):
            if hasattr(getattr(pads, "hpd_notif"), "inverted"):
                hpd_notif_n = Signal()
                self.comb += hpd_notif_n.eq(~pads.hpd_notif)
                self.specials += MultiReg(hpd_notif_n, self._hpd_notif.status)
            else:
                self.specials += MultiReg(pads.hpd_notif,
                                          self._hpd_notif.status)
        else:
            self.comb += self._hpd_notif.status.eq(1)
        if hasattr(pads, "hpd_en"):
            self.comb += pads.hpd_en.eq(self._hpd_en.storage)

        # EDID
        scl_raw = Signal()
        sda_i = Signal()
        sda_raw = Signal()
        sda_drv = Signal()
        _sda_drv_reg = Signal()
        _sda_i_async = Signal()
        self.sync += _sda_drv_reg.eq(sda_drv)

        pad_scl = getattr(pads, "scl")
        if hasattr(pad_scl, "inverted"):
            self.specials += MultiReg(~pads.scl, scl_raw)
        else:
            self.specials += MultiReg(pads.scl, scl_raw)

        if hasattr(pads, "sda_pu") and hasattr(pads, "sda_pd"):
            pad_sda = getattr(pads, "sda")
            if hasattr(pad_sda, "inverted"):
                self.specials += MultiReg(~pads.sda, sda_raw)
            else:
                self.specials += MultiReg(pads.sda, sda_raw)

            self.comb += [
                pads.sda_pu.eq(0),
                pads.sda_pd.eq(_sda_drv_reg),
            ]
        else:
            self.specials += [
                Tristate(pads.sda, 0, _sda_drv_reg, _sda_i_async),
                MultiReg(_sda_i_async, sda_raw),
            ]

        # for debug
        self.scl = scl_raw
        self.sda_i = sda_i
        self.sda_o = Signal()
        self.comb += self.sda_o.eq(~_sda_drv_reg)
        self.sda_oe = _sda_drv_reg

        scl_i = Signal()
        samp_count = Signal(6)
        samp_carry = Signal()
        self.sync += [
            Cat(samp_count, samp_carry).eq(samp_count + 1),
            If(samp_carry, scl_i.eq(scl_raw), sda_i.eq(sda_raw))
        ]

        scl_r = Signal()
        sda_r = Signal()
        scl_rising = Signal()
        sda_rising = Signal()
        sda_falling = Signal()
        self.sync += [scl_r.eq(scl_i), sda_r.eq(sda_i)]
        self.comb += [
            scl_rising.eq(scl_i & ~scl_r),
            sda_rising.eq(sda_i & ~sda_r),
            sda_falling.eq(~sda_i & sda_r)
        ]

        start = Signal()
        self.comb += start.eq(scl_i & sda_falling)

        din = Signal(8)
        counter = Signal(max=9)
        self.sync += [
            If(start, counter.eq(0)),
            If(
                scl_rising,
                If(counter == 8,
                   counter.eq(0)).Else(counter.eq(counter + 1),
                                       din.eq(Cat(sda_i, din[:7]))))
        ]

        self.din = din
        self.counter = counter

        is_read = Signal()
        update_is_read = Signal()
        self.sync += If(update_is_read, is_read.eq(din[0]))

        offset_counter = Signal(max=mem_size)
        oc_load = Signal()
        oc_inc = Signal()
        self.sync += \
            If(oc_load,
                offset_counter.eq(din)
            ).Elif(oc_inc,
                offset_counter.eq(offset_counter + 1)
            )

        rdport = self.mem.get_port()
        self.specials += rdport
        self.comb += rdport.adr.eq(offset_counter)
        data_bit = Signal()

        zero_drv = Signal()
        data_drv = Signal()
        self.comb += \
            If(zero_drv,
                sda_drv.eq(1)
            ).Elif(data_drv,
                sda_drv.eq(~data_bit)
            )

        data_drv_en = Signal()
        data_drv_stop = Signal()
        self.sync += \
            If(data_drv_en,
                data_drv.eq(1)
            ).Elif(data_drv_stop,
                data_drv.eq(0)
            )
        self.sync += \
            If(data_drv_en,
                chooser(rdport.dat_r, counter, data_bit, 8, reverse=True)
            )

        self.submodules.fsm = fsm = FSM()

        fsm.act("WAIT_START")
        fsm.act(
            "RCV_ADDRESS",
            If(
                counter == 8,
                If(din[1:] == 0x50, update_is_read.eq(1),
                   NextState("ACK_ADDRESS0")).Else(NextState("WAIT_START"))))
        fsm.act("ACK_ADDRESS0", If(~scl_i, NextState("ACK_ADDRESS1")))
        fsm.act("ACK_ADDRESS1", zero_drv.eq(1),
                If(scl_i, NextState("ACK_ADDRESS2")))
        fsm.act(
            "ACK_ADDRESS2", zero_drv.eq(1),
            If(~scl_i,
               If(is_read, NextState("READ")).Else(NextState("RCV_OFFSET"))))

        fsm.act("RCV_OFFSET",
                If(counter == 8, oc_load.eq(1), NextState("ACK_OFFSET0")))
        fsm.act("ACK_OFFSET0", If(~scl_i, NextState("ACK_OFFSET1")))
        fsm.act("ACK_OFFSET1", zero_drv.eq(1),
                If(scl_i, NextState("ACK_OFFSET2")))
        fsm.act("ACK_OFFSET2", zero_drv.eq(1),
                If(~scl_i, NextState("RCV_ADDRESS")))

        fsm.act(
            "READ",
            If(
                ~scl_i,
                If(counter == 8, data_drv_stop.eq(1),
                   NextState("ACK_READ")).Else(data_drv_en.eq(1))))
        fsm.act(
            "ACK_READ",
            If(scl_rising, oc_inc.eq(1),
               If(sda_i, NextState("WAIT_START")).Else(NextState("READ"))))

        for state in fsm.actions.keys():
            fsm.act(state, If(start, NextState("RCV_ADDRESS")))
            if hasattr(pads, "hpd_en"):
                fsm.act(state,
                        If(~self._hpd_en.storage, NextState("WAIT_START")))
示例#9
0
    def __init__(self, pads):
        def io_bus(n):
            return Record([("oe", 1), ("i", n), ("o", n)])

        # # #
        self.clk_enable = Signal()
        self.cs = Signal()
        self.dq = io_bus(32)
        self.rwds = io_bus(4)

        ## IO Delay shifting
        self.dly_io = delayf_pins()
        self.dly_clk = delayf_pins()

        dq = self.add_tristate(
            pads.dq) if not hasattr(pads.dq, "oe") else pads.dq
        rwds = self.add_tristate(
            pads.rwds) if not hasattr(pads.rwds, "oe") else pads.rwds

        # Shift non DDR signals to match the FF's inside DDR modules.
        self.specials += MultiReg(self.cs, pads.cs_n, n=3)

        self.specials += MultiReg(self.rwds.oe, rwds.oe, n=3)
        self.specials += MultiReg(self.dq.oe, dq.oe, n=3)

        # mask off clock when no CS
        clk_en = Signal()
        self.comb += clk_en.eq(self.clk_enable & ~self.cs)

        #clk_out
        clkp = Signal()
        clkn = Signal()
        self.specials += [
            Instance("ODDRX2F",
                     i_D3=clk_en,
                     i_D2=0,
                     i_D1=clk_en,
                     i_D0=0,
                     i_SCLK=ClockSignal("hr_90"),
                     i_ECLK=ClockSignal("hr2x_90"),
                     i_RST=ResetSignal("hr"),
                     o_Q=clkp),
            Instance(
                "DELAYF",
                p_DEL_MODE="USER_DEFINED",
                p_DEL_VALUE=0,  # (25ps per tap)
                i_A=clkp,
                i_LOADN=self.dly_clk.loadn,
                i_MOVE=self.dly_clk.move,
                i_DIRECTION=self.dly_clk.direction,
                o_Z=pads.clk_p)
        ]

        self.specials += [
            Instance("ODDRX2F",
                     i_D3=~clk_en,
                     i_D2=1,
                     i_D1=~clk_en,
                     i_D0=1,
                     i_SCLK=ClockSignal("hr_90"),
                     i_ECLK=ClockSignal("hr2x_90"),
                     i_RST=ResetSignal("hr"),
                     o_Q=clkn),
            Instance(
                "DELAYF",
                p_DEL_MODE="USER_DEFINED",
                p_DEL_VALUE=0,  # (25ps per tap)
                i_A=clkn,
                i_LOADN=self.dly_clk.loadn,
                i_MOVE=self.dly_clk.move,
                i_DIRECTION=self.dly_clk.direction,
                o_Z=pads.clk_n)
        ]

        # DQ_out
        for i in range(8):
            self.specials += [
                Instance("ODDRX2F",
                         i_D3=self.dq.o[i],
                         i_D2=self.dq.o[8 + i],
                         i_D1=self.dq.o[16 + i],
                         i_D0=self.dq.o[24 + i],
                         i_SCLK=ClockSignal("hr"),
                         i_ECLK=ClockSignal("hr2x"),
                         i_RST=ResetSignal("hr"),
                         o_Q=dq.o[i])
            ]

        # DQ_in
        for i in range(8):
            dq_in = Signal()
            self.specials += [
                Instance("IDDRX2F",
                         i_D=dq_in,
                         i_SCLK=ClockSignal("hr"),
                         i_ECLK=ClockSignal("hr2x"),
                         i_RST=ResetSignal("hr"),
                         o_Q3=self.dq.i[i],
                         o_Q2=self.dq.i[i + 8],
                         o_Q1=self.dq.i[i + 16],
                         o_Q0=self.dq.i[i + 24]),
                Instance(
                    "DELAYF",
                    p_DEL_MODE="USER_DEFINED",
                    p_DEL_VALUE=0,  # (25ps per tap)
                    i_A=dq.i[i],
                    i_LOADN=self.dly_io.loadn,
                    i_MOVE=self.dly_io.move,
                    i_DIRECTION=self.dly_io.direction,
                    o_Z=dq_in)
            ]

        # RWDS_out
        self.specials += [
            Instance("ODDRX2F",
                     i_D3=self.rwds.o[0],
                     i_D2=self.rwds.o[1],
                     i_D1=self.rwds.o[2],
                     i_D0=self.rwds.o[3],
                     i_SCLK=ClockSignal("hr"),
                     i_ECLK=ClockSignal("hr2x"),
                     i_RST=ResetSignal("hr"),
                     o_Q=rwds.o)
        ]

        # RWDS_in
        rwds_in = Signal()
        self.specials += [
            Instance("IDDRX2F",
                     i_D=rwds_in,
                     i_SCLK=ClockSignal("hr"),
                     i_ECLK=ClockSignal("hr2x"),
                     i_RST=ResetSignal("hr"),
                     o_Q3=self.rwds.i[0],
                     o_Q2=self.rwds.i[1],
                     o_Q1=self.rwds.i[2],
                     o_Q0=self.rwds.i[3]),
            Instance(
                "DELAYF",
                p_DEL_MODE="USER_DEFINED",
                p_DEL_VALUE=0,  # (25ps per tap)
                i_A=rwds.i,
                i_LOADN=self.dly_io.loadn,
                i_MOVE=self.dly_io.move,
                i_DIRECTION=self.dly_io.direction,
                o_Z=rwds_in)
        ]
    def __init__(self, pll, pads, mode="master"):
        self.tx_pattern = CSRStorage(20)
        self.tx_produce_square_wave = CSRStorage()
        self.tx_prbs_config = CSRStorage(2)

        self.rx_pattern = CSRStatus(20)
        self.rx_prbs_config = CSRStorage(2)
        self.rx_prbs_errors = CSRStatus(32)

        self.rx_bitslip_value = CSRStorage(5)
        self.rx_delay_rst = CSR()
        self.rx_delay_inc = CSRStorage()
        self.rx_delay_ce = CSR()

        # # #

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

        # clocking
        # master mode:
        # - linerate/10 pll refclk provided externally
        # - linerate/10 clock generated on clk_pads
        # slave mode:
        # - linerate/10 pll refclk provided by clk_pads
        self.clock_domains.cd_serdes = ClockDomain()
        self.clock_domains.cd_serdes_10x = ClockDomain()
        self.clock_domains.cd_serdes_2p5x = ClockDomain()
        self.comb += [
            self.cd_serdes.clk.eq(pll.serdes_clk),
            self.cd_serdes_10x.clk.eq(pll.serdes_10x_clk),
            self.cd_serdes_2p5x.clk.eq(pll.serdes_2p5x_clk)
        ]
        self.specials += [
            AsyncResetSynchronizer(self.cd_serdes, ~pll.lock),
            AsyncResetSynchronizer(self.cd_serdes_10x, ~pll.lock),
            AsyncResetSynchronizer(self.cd_serdes_2p5x, ~pll.lock)
        ]

        # control/status cdc
        tx_pattern = Signal(20)
        tx_produce_square_wave = Signal()
        tx_prbs_config = Signal(2)

        rx_pattern = Signal(20)
        rx_prbs_config = Signal(2)
        rx_prbs_errors = Signal(32)

        rx_bitslip_value = Signal(5)

        self.specials += [
            MultiReg(self.tx_pattern.storage, tx_pattern, "serdes"),
            MultiReg(self.tx_produce_square_wave.storage,
                     tx_produce_square_wave, "serdes"),
            MultiReg(self.tx_prbs_config.storage, tx_prbs_config, "serdes"),
        ]

        self.specials += [
            MultiReg(rx_pattern, self.rx_pattern.status, "sys"),
            MultiReg(self.rx_prbs_config.storage, rx_prbs_config, "serdes"),
            MultiReg(rx_prbs_errors, self.rx_prbs_errors.status,
                     "sys"),  # FIXME
        ]

        self.specials += MultiReg(self.rx_bitslip_value.storage,
                                  rx_bitslip_value, "serdes"),

        # tx clock (linerate/10)
        if mode == "master":
            self.submodules.tx_clk_gearbox = Gearbox(20, "serdes", 8,
                                                     "serdes_2p5x")
            self.comb += self.tx_clk_gearbox.i.eq(0b11111000001111100000)

            clk_o = Signal()
            self.specials += [
                Instance("OSERDESE2",
                         p_DATA_WIDTH=8,
                         p_TRISTATE_WIDTH=1,
                         p_DATA_RATE_OQ="DDR",
                         p_DATA_RATE_TQ="BUF",
                         p_SERDES_MODE="MASTER",
                         o_OQ=clk_o,
                         i_OCE=1,
                         i_RST=ResetSignal("serdes_2p5x"),
                         i_CLK=ClockSignal("serdes_10x"),
                         i_CLKDIV=ClockSignal("serdes_2p5x"),
                         i_D1=self.tx_clk_gearbox.o[0],
                         i_D2=self.tx_clk_gearbox.o[1],
                         i_D3=self.tx_clk_gearbox.o[2],
                         i_D4=self.tx_clk_gearbox.o[3],
                         i_D5=self.tx_clk_gearbox.o[4],
                         i_D6=self.tx_clk_gearbox.o[5],
                         i_D7=self.tx_clk_gearbox.o[6],
                         i_D8=self.tx_clk_gearbox.o[7]),
                Instance("OBUFDS", i_I=clk_o, o_O=pads.clk_p, o_OB=pads.clk_n)
            ]

        # tx data and prbs
        self.submodules.tx_prbs = ClockDomainsRenamer("serdes")(PRBSTX(
            20, True))
        self.comb += self.tx_prbs.config.eq(tx_prbs_config)
        self.submodules.tx_gearbox = Gearbox(20, "serdes", 8, "serdes_2p5x")
        self.sync.serdes += [
            self.tx_prbs.i.eq(Cat(*[self.encoder.output[i]
                                    for i in range(2)])),
            If(tx_pattern != 0, self.tx_gearbox.i.eq(tx_pattern)).Elif(
                tx_produce_square_wave,
                # square wave @ linerate/20 for scope observation
                self.tx_gearbox.i.eq(0b11111111110000000000)).Else(
                    self.tx_gearbox.i.eq(self.tx_prbs.o))
        ]

        serdes_o = Signal()
        self.specials += [
            Instance("OSERDESE2",
                     p_DATA_WIDTH=8,
                     p_TRISTATE_WIDTH=1,
                     p_DATA_RATE_OQ="DDR",
                     p_DATA_RATE_TQ="BUF",
                     p_SERDES_MODE="MASTER",
                     o_OQ=serdes_o,
                     i_OCE=1,
                     i_RST=ResetSignal("serdes_2p5x"),
                     i_CLK=ClockSignal("serdes_10x"),
                     i_CLKDIV=ClockSignal("serdes_2p5x"),
                     i_D1=self.tx_gearbox.o[0],
                     i_D2=self.tx_gearbox.o[1],
                     i_D3=self.tx_gearbox.o[2],
                     i_D4=self.tx_gearbox.o[3],
                     i_D5=self.tx_gearbox.o[4],
                     i_D6=self.tx_gearbox.o[5],
                     i_D7=self.tx_gearbox.o[6],
                     i_D8=self.tx_gearbox.o[7]),
            Instance("OBUFDS", i_I=serdes_o, o_O=pads.tx_p, o_OB=pads.tx_n)
        ]

        # rx clock
        use_bufr = False
        if mode == "slave":
            clk_i = Signal()

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

        # rx
        self.submodules.rx_gearbox = Gearbox(8, "serdes_2p5x", 20, "serdes")
        self.submodules.rx_bitslip = ClockDomainsRenamer("serdes")(BitSlip(20))

        self.submodules.phase_detector = ClockDomainsRenamer("serdes_2p5x")(
            PhaseDetector())

        # use 2 serdes for phase detection: 1 master/ 1 slave
        serdes_m_i_nodelay = Signal()
        serdes_s_i_nodelay = Signal()
        self.specials += [
            Instance(
                "IBUFDS_DIFF_OUT",
                i_I=pads.rx_p,
                i_IB=pads.rx_n,
                o_O=serdes_m_i_nodelay,
                o_OB=serdes_s_i_nodelay,
            )
        ]

        serdes_m_i_delayed = Signal()
        serdes_m_q = Signal(8)
        serdes_m_idelay_value = int(1 / (4 * pll.linerate) /
                                    78e-12)  # 1/4 bit period
        assert serdes_m_idelay_value < 32
        self.specials += [
            Instance("IDELAYE2",
                     p_DELAY_SRC="IDATAIN",
                     p_SIGNAL_PATTERN="DATA",
                     p_CINVCTRL_SEL="FALSE",
                     p_HIGH_PERFORMANCE_MODE="TRUE",
                     p_REFCLK_FREQUENCY=200.0,
                     p_PIPE_SEL="FALSE",
                     p_IDELAY_TYPE="VARIABLE",
                     p_IDELAY_VALUE=serdes_m_idelay_value,
                     i_C=ClockSignal(),
                     i_LD=self.rx_delay_rst.re,
                     i_CE=self.rx_delay_ce.re,
                     i_LDPIPEEN=0,
                     i_INC=self.rx_delay_inc.storage,
                     i_IDATAIN=serdes_m_i_nodelay,
                     o_DATAOUT=serdes_m_i_delayed),
            Instance("ISERDESE2",
                     p_DATA_WIDTH=8,
                     p_DATA_RATE="DDR",
                     p_SERDES_MODE="MASTER",
                     p_INTERFACE_TYPE="NETWORKING",
                     p_NUM_CE=1,
                     p_IOBDELAY="IFD",
                     i_DDLY=serdes_m_i_delayed,
                     i_CE1=1,
                     i_RST=ResetSignal("serdes_2p5x"),
                     i_CLK=ClockSignal("serdes_10x"),
                     i_CLKB=~ClockSignal("serdes_10x"),
                     i_CLKDIV=ClockSignal("serdes_2p5x"),
                     i_BITSLIP=0,
                     o_Q8=serdes_m_q[0],
                     o_Q7=serdes_m_q[1],
                     o_Q6=serdes_m_q[2],
                     o_Q5=serdes_m_q[3],
                     o_Q4=serdes_m_q[4],
                     o_Q3=serdes_m_q[5],
                     o_Q2=serdes_m_q[6],
                     o_Q1=serdes_m_q[7]),
        ]
        self.comb += self.phase_detector.mdata.eq(serdes_m_q)

        serdes_s_i_delayed = Signal()
        serdes_s_q = Signal(8)
        serdes_s_idelay_value = int(1 / (2 * pll.linerate) /
                                    78e-12)  # 1/2 bit period
        assert serdes_s_idelay_value < 32
        self.specials += [
            Instance("IDELAYE2",
                     p_DELAY_SRC="IDATAIN",
                     p_SIGNAL_PATTERN="DATA",
                     p_CINVCTRL_SEL="FALSE",
                     p_HIGH_PERFORMANCE_MODE="TRUE",
                     p_REFCLK_FREQUENCY=200.0,
                     p_PIPE_SEL="FALSE",
                     p_IDELAY_TYPE="VARIABLE",
                     p_IDELAY_VALUE=serdes_s_idelay_value,
                     i_C=ClockSignal(),
                     i_LD=self.rx_delay_rst.re,
                     i_CE=self.rx_delay_ce.re,
                     i_LDPIPEEN=0,
                     i_INC=self.rx_delay_inc.storage,
                     i_IDATAIN=serdes_s_i_nodelay,
                     o_DATAOUT=serdes_s_i_delayed),
            Instance("ISERDESE2",
                     p_DATA_WIDTH=8,
                     p_DATA_RATE="DDR",
                     p_SERDES_MODE="MASTER",
                     p_INTERFACE_TYPE="NETWORKING",
                     p_NUM_CE=1,
                     p_IOBDELAY="IFD",
                     i_DDLY=serdes_s_i_delayed,
                     i_CE1=1,
                     i_RST=ResetSignal("serdes_2p5x"),
                     i_CLK=ClockSignal("serdes_10x"),
                     i_CLKB=~ClockSignal("serdes_10x"),
                     i_CLKDIV=ClockSignal("serdes_2p5x"),
                     i_BITSLIP=0,
                     o_Q8=serdes_s_q[0],
                     o_Q7=serdes_s_q[1],
                     o_Q6=serdes_s_q[2],
                     o_Q5=serdes_s_q[3],
                     o_Q4=serdes_s_q[4],
                     o_Q3=serdes_s_q[5],
                     o_Q2=serdes_s_q[6],
                     o_Q1=serdes_s_q[7]),
        ]
        self.comb += self.phase_detector.sdata.eq(~serdes_s_q)

        # rx data and prbs
        self.submodules.rx_prbs = ClockDomainsRenamer("serdes")(PRBSRX(
            20, True))
        self.comb += [
            self.rx_prbs.config.eq(rx_prbs_config),
            rx_prbs_errors.eq(self.rx_prbs.errors)
        ]
        self.comb += [
            self.rx_gearbox.i.eq(serdes_m_q),
            self.rx_bitslip.value.eq(rx_bitslip_value),
            self.rx_bitslip.i.eq(self.rx_gearbox.o),
            rx_pattern.eq(self.rx_gearbox.o),
            self.decoders[0].input.eq(self.rx_bitslip.o[:10]),
            self.decoders[1].input.eq(self.rx_bitslip.o[10:]),
            self.rx_prbs.i.eq(self.rx_bitslip.o)
        ]
示例#11
0
    def __init__(self, platform, pads, data_width=64, bar0_size=1*MB, cd="sys", pll1=None):
        self.sink = stream.Endpoint(phy_layout(data_width))
        self.source = stream.Endpoint(phy_layout(data_width))
        self.msi = stream.Endpoint(msi_layout())

        self._lnk_up = CSRStatus()
        self._msi_enable = CSRStatus()
        self._bus_master_enable = CSRStatus()
        self._max_request_size = CSRStatus(16)
        self._max_payload_size = CSRStatus(16)

        self.data_width = data_width

        self.id = Signal(16)
        self.bar0_size = bar0_size
        self.bar0_mask = get_bar_mask(bar0_size)
        self.max_request_size = Signal(16)
        self.max_payload_size = Signal(16)

        # # #

        # clocking
        pcie_clk = Signal()
        pcie_rst = Signal()
        pcie_refclk = Signal()
        self.specials += Instance("IBUFDS_GTE2",
            i_CEB=0,
            i_I=pads.clk_p,
            i_IB=pads.clk_n,
            o_O=pcie_refclk
        )
        pcie_refclk.attr.add("keep")
        platform.add_period_constraint(pcie_refclk, 10.0)

        self.clock_domains.cd_pcie = ClockDomain()
        self.clock_domains.cd_pcie_reset_less = ClockDomain(reset_less=True)
        self.cd_pcie.clk.attr.add("keep")
        platform.add_period_constraint(self.cd_pcie.clk, 8.0)

        pcie_refclk_present = Signal()
        pcie_refclk_timer = ClockDomainsRenamer("pcie_reset_less")(WaitTimer(1024))
        self.submodules += pcie_refclk_timer
        self.comb += [
            pcie_refclk_timer.wait.eq(1),
            pcie_refclk_present.eq(pcie_refclk_timer.done)
        ]

        self.comb += [
            self.cd_pcie.clk.eq(pcie_clk),
            self.cd_pcie.rst.eq(pcie_rst & pcie_refclk_present),
            self.cd_pcie_reset_less.clk.eq(pcie_clk),
        ]

        # tx cdc (fpga --> host)
        if cd == "pcie":
            s_axis_tx = self.sink
        else:
            tx_buffer = stream.Buffer(phy_layout(data_width))
            tx_buffer = ClockDomainsRenamer(cd)(tx_buffer)
            tx_cdc = stream.AsyncFIFO(phy_layout(data_width), 4)
            tx_cdc = ClockDomainsRenamer({"write": cd, "read": "pcie"})(tx_cdc)
            self.submodules += tx_buffer, tx_cdc
            self.comb += [
                self.sink.connect(tx_buffer.sink),
                tx_buffer.source.connect(tx_cdc.sink)
            ]
            s_axis_tx = tx_cdc.source

        # rx cdc (host --> fpga)
        if cd == "pcie":
            m_axis_rx = self.source
        else:
            rx_cdc = stream.AsyncFIFO(phy_layout(data_width), 4)
            rx_cdc = ClockDomainsRenamer({"write": "pcie", "read": cd})(rx_cdc)
            rx_buffer = stream.Buffer(phy_layout(data_width))
            rx_buffer = ClockDomainsRenamer(cd)(rx_buffer)
            self.submodules += rx_buffer, rx_cdc
            self.comb += [
                rx_cdc.source.connect(rx_buffer.sink),
                rx_buffer.source.connect(self.source)
            ]
            m_axis_rx = rx_cdc.sink

        # msi cdc (fpga --> host)
        if cd == "pcie":
            cfg_msi = self.msi
        else:
            msi_cdc = stream.AsyncFIFO(msi_layout(), 4)
            msi_cdc = ClockDomainsRenamer({"write": cd, "read": "pcie"})(msi_cdc)
            self.submodules += msi_cdc
            self.comb += self.msi.connect(msi_cdc.sink)
            cfg_msi = msi_cdc.source


        # config
        def convert_size(command, size):
            cases = {}
            value = 128
            for i in range(6):
                cases[i] = size.eq(value)
                value = value*2
            return Case(command, cases)

        lnk_up = Signal()
        msienable = Signal()
        bus_number = Signal(8)
        device_number = Signal(5)
        function_number = Signal(3)
        command = Signal(16)
        dcommand = Signal(16)
        self.sync.pcie += [
            convert_size(dcommand[12:15], self.max_request_size),
            convert_size(dcommand[5:8], self.max_payload_size),
            self.id.eq(Cat(function_number, device_number, bus_number))
        ]
        self.specials += [
            MultiReg(lnk_up, self._lnk_up.status),
            MultiReg(command[2], self._bus_master_enable.status),
            MultiReg(msienable, self._msi_enable.status),
            MultiReg(self.max_request_size, self._max_request_size.status),
            MultiReg(self.max_payload_size, self._max_payload_size.status)
        ]

        # hard ip
        self.specials += Instance("pcie_phy",
                p_C_DATA_WIDTH=data_width,
                p_C_PCIE_GT_DEVICE={
                    "xc7k": "GTX",
                    "xc7a": "GTP"}[platform.device[:4]],
                p_C_BAR0=get_bar_mask(bar0_size),

                i_sys_clk=pcie_refclk,
                i_sys_rst_n=1 if not hasattr(pads, "rst_n") else pads.rst_n,

                o_pci_exp_txp=pads.tx_p,
                o_pci_exp_txn=pads.tx_n,

                i_pci_exp_rxp=pads.rx_p,
                i_pci_exp_rxn=pads.rx_n,

                o_user_clk=pcie_clk,
                o_user_reset=pcie_rst,
                o_user_lnk_up=lnk_up,

                #o_tx_buf_av=,
                #o_tx_terr_drop=,
                #o_tx_cfg_req=,
                i_tx_cfg_gnt=1,

                i_s_axis_tx_tvalid=s_axis_tx.valid,
                i_s_axis_tx_tlast=s_axis_tx.last,
                o_s_axis_tx_tready=s_axis_tx.ready,
                i_s_axis_tx_tdata=s_axis_tx.dat,
                i_s_axis_tx_tkeep=s_axis_tx.be,
                i_s_axis_tx_tuser=0,

                i_rx_np_ok=1,
                i_rx_np_req=1,

                o_m_axis_rx_tvalid=m_axis_rx.valid,
                o_m_axis_rx_tlast=m_axis_rx.last,
                i_m_axis_rx_tready=m_axis_rx.ready,
                o_m_axis_rx_tdata=m_axis_rx.dat,
                o_m_axis_rx_tkeep=m_axis_rx.be,
                #o_m_axis_rx_tuser=,

                #o_cfg_to_turnoff=,
                o_cfg_bus_number=bus_number,
                o_cfg_device_number=device_number,
                o_cfg_function_number=function_number,
                o_cfg_command=command,
                o_cfg_dcommand=dcommand,
                o_cfg_interrupt_msienable=msienable,

                i_cfg_interrupt=cfg_msi.valid,
                o_cfg_interrupt_rdy=cfg_msi.ready,
                i_cfg_interrupt_di=cfg_msi.dat,

                p_QPLL_PLL1_FBDIV=4 if pll1 is None else pll1.config["n2"],
                p_QPLL_PLL1_FBDIV_45=4 if pll1 is None else pll1.config["n1"],
                p_QPLL_PLL1_REFCLK_DIV=1 if pll1 is None else pll1.config["m"],

                i_QPLL_GTGREFCLK1=0 if pll1 is None else pll1.gtgrefclk,
                i_QPLL_GTREFCLK1=0 if pll1 is None else pll1.gtrefclk,
                i_QPLL_PLL1LOCKEN=1,
                i_QPLL_PLL1PD=1 if pll1 is None else 0,
                i_QPLL_PLL1REFCLKSEL=0b001 if pll1 is None else pll1.refclksel,
                i_QPLL_PLL1RESET=1 if pll1 is None else pll1.reset,
                o_QPLL_PLL1LOCK=Signal() if pll1 is None else pll1.lock,
                o_QPLL_PLL1OUTCLK=Signal() if pll1 is None else pll1.clk,
                o_QPLL_PLL1OUTREFCLK=Signal() if pll1 is None else pll1.refclk
        )
        litepcie_phy_path = os.path.abspath(os.path.dirname(__file__))
        platform.add_source_dir(os.path.join(litepcie_phy_path, "xilinx", "7-series", "common"))
        platform.add_source(os.path.join(litepcie_phy_path, "xilinx", "7-series", "common", "xpm_cdc.sv"))
        if platform.device[:4] == "xc7k":
            platform.add_source_dir(os.path.join(litepcie_phy_path, "xilinx", "7-series", "kintex7"))
        elif platform.device[:4] == "xc7a":
            platform.add_source_dir(os.path.join(litepcie_phy_path, "xilinx", "7-series", "artix7"))
示例#12
0
    def __init__(self, pll, tx_pads, rx_pads, sys_clk_freq, data_width=20,
                 tx_buffer_enable=False, rx_buffer_enable=False,
                 clock_aligner=True, clock_aligner_comma=0b0101111100,
                 tx_polarity=0, rx_polarity=0,
                 pll_master=True):
        assert (data_width == 20) or (data_width == 40)

        # TX controls
        self.tx_enable              = Signal()
        self.tx_ready               = Signal()
        self.tx_inhibit             = Signal()
        self.tx_produce_square_wave = Signal()
        self.tx_produce_pattern     = Signal()
        self.tx_pattern             = Signal(data_width)
        self.tx_prbs_config         = Signal(2)

        # RX controls
        self.rx_enable      = Signal()
        self.rx_ready       = Signal()
        self.rx_align       = Signal(reset=1)
        self.rx_prbs_config = Signal(2)
        self.rx_prbs_errors = Signal(32)

        # DRP
        self.drp = DRPInterface()

        # Loopback
        self.loopback = Signal(3)

        # # #

        self.nwords = nwords = data_width//10

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

        # Transceiver direct clock outputs (useful to specify clock constraints)
        self.txoutclk = Signal()
        self.rxoutclk = Signal()

        self.tx_clk_freq = pll.config["linerate"]/data_width
        self.rx_clk_freq = pll.config["linerate"]/data_width

        # Control/Status CDC
        tx_produce_square_wave = Signal()
        tx_produce_pattern     = Signal()
        tx_prbs_config         = Signal(2)

        rx_prbs_config = Signal(2)
        rx_prbs_errors = Signal(32)

        self.specials += [
            MultiReg(self.tx_produce_square_wave, tx_produce_square_wave, "tx"),
            MultiReg(self.tx_produce_pattern, tx_produce_pattern, "tx"),
            MultiReg(self.tx_prbs_config, tx_prbs_config, "tx"),
        ]

        self.specials += [
            MultiReg(self.rx_prbs_config, rx_prbs_config, "rx"),
            MultiReg(rx_prbs_errors, self.rx_prbs_errors, "sys"), # FIXME
        ]

        # # #

        use_cpll = isinstance(pll, GTXChannelPLL)
        use_qpll = isinstance(pll, GTXQuadPLL)

        rxcdr_cfgs = {
            1 : 0x03000023ff10400020,
            2 : 0x03000023ff10200020,
            4 : 0x03000023ff10100020,
            8 : 0x03000023ff10080020,
           16 : 0x03000023ff10080020,
        }

        # TX init ----------------------------------------------------------------------------------
        self.submodules.tx_init = tx_init = GTXTXInit(sys_clk_freq, buffer_enable=tx_buffer_enable)
        self.comb += [
            self.tx_ready.eq(tx_init.done),
            tx_init.restart.eq(~self.tx_enable)
        ]

        # RX init ----------------------------------------------------------------------------------
        self.submodules.rx_init = rx_init = GTXRXInit(sys_clk_freq, buffer_enable=rx_buffer_enable)
        self.comb += [
            self.rx_ready.eq(rx_init.done),
            rx_init.restart.eq(~self.rx_enable)
        ]

        # PLL ----------------------------------------------------------------------------------
        self.comb += [
            tx_init.plllock.eq(pll.lock),
            rx_init.plllock.eq(pll.lock)
        ]
        if pll_master:
            self.comb += pll.reset.eq(tx_init.pllreset)

        # DRP mux ----------------------------------------------------------------------------------
        self.submodules.drp_mux = drp_mux = DRPMux()
        drp_mux.add_interface(self.drp)

        # GTXE2_CHANNEL instance -------------------------------------------------------------------
        txdata = Signal(data_width)
        rxdata = Signal(data_width)
        self.gtx_params = dict(
            # Simulation-Only Attributes
            p_SIM_RECEIVER_DETECT_PASS     = "******",
            p_SIM_TX_EIDLE_DRIVE_LEVEL     = "X",
            p_SIM_RESET_SPEEDUP            = "FALSE",
            p_SIM_CPLLREFCLK_SEL           = "FALSE",
            p_SIM_VERSION                  = "4.0",

            # RX Byte and Word Alignment Attributes
            p_ALIGN_COMMA_DOUBLE           = "FALSE",
            p_ALIGN_COMMA_ENABLE           = 0b1111111111,
            p_ALIGN_COMMA_WORD             = 2 if data_width == 20 else 4,
            p_ALIGN_MCOMMA_DET             = "TRUE",
            p_ALIGN_MCOMMA_VALUE           = 0b1010000011,
            p_ALIGN_PCOMMA_DET             = "TRUE",
            p_ALIGN_PCOMMA_VALUE           = 0b0101111100,
            p_SHOW_REALIGN_COMMA           = "TRUE",
            p_RXSLIDE_AUTO_WAIT            = 7,
            p_RXSLIDE_MODE                 = "OFF" if rx_buffer_enable else "PCS",
            p_RX_SIG_VALID_DLY             = 10,

            # RX 8B/10B Decoder Attributes
            p_RX_DISPERR_SEQ_MATCH         = "TRUE",
            p_DEC_MCOMMA_DETECT            = "TRUE",
            p_DEC_PCOMMA_DETECT            = "TRUE",
            p_DEC_VALID_COMMA_ONLY         = "TRUE",

            # RX Clock Correction Attributes
            p_CBCC_DATA_SOURCE_SEL         = "DECODED",
            p_CLK_COR_SEQ_2_USE            = "FALSE",
            p_CLK_COR_KEEP_IDLE            = "FALSE",
            p_CLK_COR_MAX_LAT              = 9 if data_width == 20 else 20,
            p_CLK_COR_MIN_LAT              = 7 if data_width == 20 else 16,
            p_CLK_COR_PRECEDENCE           = "TRUE",
            p_CLK_COR_REPEAT_WAIT          = 0,
            p_CLK_COR_SEQ_LEN              = 1,
            p_CLK_COR_SEQ_1_ENABLE         = 0b1111,
            p_CLK_COR_SEQ_1_1              = 0b0100000000,
            p_CLK_COR_SEQ_1_2              = 0b0000000000,
            p_CLK_COR_SEQ_1_3              = 0b0000000000,
            p_CLK_COR_SEQ_1_4              = 0b0000000000,
            p_CLK_CORRECT_USE              = "FALSE",
            p_CLK_COR_SEQ_2_ENABLE         = 0b1111,
            p_CLK_COR_SEQ_2_1              = 0b0100000000,
            p_CLK_COR_SEQ_2_2              = 0b0000000000,
            p_CLK_COR_SEQ_2_3              = 0b0000000000,
            p_CLK_COR_SEQ_2_4              = 0b0000000000,

            # RX Channel Bonding Attributes
            p_CHAN_BOND_KEEP_ALIGN         = "FALSE",
            p_CHAN_BOND_MAX_SKEW           = 1,
            p_CHAN_BOND_SEQ_LEN            = 1,
            p_CHAN_BOND_SEQ_1_1            = 0b0000000000,
            p_CHAN_BOND_SEQ_1_2            = 0b0000000000,
            p_CHAN_BOND_SEQ_1_3            = 0b0000000000,
            p_CHAN_BOND_SEQ_1_4            = 0b0000000000,
            p_CHAN_BOND_SEQ_1_ENABLE       = 0b1111,
            p_CHAN_BOND_SEQ_2_1            = 0b0000000000,
            p_CHAN_BOND_SEQ_2_2            = 0b0000000000,
            p_CHAN_BOND_SEQ_2_3            = 0b0000000000,
            p_CHAN_BOND_SEQ_2_4            = 0b0000000000,
            p_CHAN_BOND_SEQ_2_ENABLE       = 0b1111,
            p_CHAN_BOND_SEQ_2_USE          = "FALSE",
            p_FTS_DESKEW_SEQ_ENABLE        = 0b1111,
            p_FTS_LANE_DESKEW_CFG          = 0b1111,
            p_FTS_LANE_DESKEW_EN           = "FALSE",

            # RX Margin Analysis Attributes
            p_ES_CONTROL                   = 0b000000,
            p_ES_ERRDET_EN                 = "FALSE",
            p_ES_EYE_SCAN_EN               = "TRUE",
            p_ES_HORZ_OFFSET               = 0x000,
            p_ES_PMA_CFG                   = 0b0000000000,
            p_ES_PRESCALE                  = 0b00000,
            p_ES_QUALIFIER                 = 0x00000000000000000000,
            p_ES_QUAL_MASK                 = 0x00000000000000000000,
            p_ES_SDATA_MASK                = 0x00000000000000000000,
            p_ES_VERT_OFFSET               = 0b000000000,

            # FPGA RX Interface Attributes
            p_RX_DATA_WIDTH                = data_width,

            # PMA Attributes
            p_OUTREFCLK_SEL_INV            = 0b11,
            p_PMA_RSV                      = 0x001e7080,
            p_PMA_RSV2                     = 0x2050,
            p_PMA_RSV3                     = 0b00,
            p_PMA_RSV4                     = 0x00000000,
            p_RX_BIAS_CFG                  = 0b000000000100,
            p_DMONITOR_CFG                 = 0x000A00,
            p_RX_CM_SEL                    = 0b11,
            p_RX_CM_TRIM                   = 0b010,
            p_RX_DEBUG_CFG                 = 0b000000000000,
            p_RX_OS_CFG                    = 0b0000010000000,
            p_TERM_RCAL_CFG                = 0b10000,
            p_TERM_RCAL_OVRD               = 0b0,
            p_TST_RSV                      = 0x00000000,
            p_RX_CLK25_DIV                 = 5,
            p_TX_CLK25_DIV                 = 5,
            p_UCODEER_CLR                  = 0b0,

            # PCI Express Attributes
            p_PCS_PCIE_EN                  = "FALSE",

            # PCS Attributes
            p_PCS_RSVD_ATTR                = 0x000000000000,

            # RX Buffer Attributes
            p_RXBUF_ADDR_MODE              = "FAST",
            p_RXBUF_EIDLE_HI_CNT           = 0b1000,
            p_RXBUF_EIDLE_LO_CNT           = 0b0000,
            p_RXBUF_EN                     = "TRUE" if rx_buffer_enable else "FALSE",
            p_RX_BUFFER_CFG                = 0b000000,
            p_RXBUF_RESET_ON_CB_CHANGE     = "TRUE",
            p_RXBUF_RESET_ON_COMMAALIGN    = "FALSE",
            p_RXBUF_RESET_ON_EIDLE         = "FALSE",
            p_RXBUF_RESET_ON_RATE_CHANGE   = "TRUE",
            p_RXBUFRESET_TIME              = 0b00001,
            p_RXBUF_THRESH_OVFLW           = 61,
            p_RXBUF_THRESH_OVRD            = "FALSE",
            p_RXBUF_THRESH_UNDFLW          = 4,
            p_RXDLY_CFG                    = 0x001F,
            p_RXDLY_LCFG                   = 0x030,
            p_RXDLY_TAP_CFG                = 0x0000,
            p_RXPH_CFG                     = 0x000000,
            p_RXPHDLY_CFG                  = 0x084020,
            p_RXPH_MONITOR_SEL             = 0b00000,
            p_RX_XCLK_SEL                  = "RXREC" if rx_buffer_enable else "RXUSR",
            p_RX_DDI_SEL                   = 0b000000,
            p_RX_DEFER_RESET_BUF_EN        = "TRUE",

            # CDR Attributes
            p_RXCDR_CFG                    = rxcdr_cfgs[pll.config["d"]],
            p_RXCDR_FR_RESET_ON_EIDLE      = 0b0,
            p_RXCDR_HOLD_DURING_EIDLE      = 0b0,
            p_RXCDR_PH_RESET_ON_EIDLE      = 0b0,
            p_RXCDR_LOCK_CFG               = 0b010101,

            # RX Initialization and Reset Attributes
            p_RXCDRFREQRESET_TIME          = 0b00001,
            p_RXCDRPHRESET_TIME            = 0b00001,
            p_RXISCANRESET_TIME            = 0b00001,
            p_RXPCSRESET_TIME              = 0b00001,
            p_RXPMARESET_TIME              = 0b00011,

            # RX OOB Signaling Attributes
            p_RXOOB_CFG                    = 0b0000110,

            # RX Gearbox Attributes
            p_RXGEARBOX_EN                 = "FALSE",
            p_GEARBOX_MODE                 = 0b000,

            # PRBS Detection Attribute
            p_RXPRBS_ERR_LOOPBACK          = 0b0,

            # Power-Down Attributes
            p_PD_TRANS_TIME_FROM_P2        = 0x03c,
            p_PD_TRANS_TIME_NONE_P2        = 0x3c,
            p_PD_TRANS_TIME_TO_P2          = 0x64,

            # RX OOB Signaling Attributes
            p_SAS_MAX_COM                  = 64,
            p_SAS_MIN_COM                  = 36,
            p_SATA_BURST_SEQ_LEN           = 0b0101,
            p_SATA_BURST_VAL               = 0b100,
            p_SATA_EIDLE_VAL               = 0b100,
            p_SATA_MAX_BURST               = 8,
            p_SATA_MAX_INIT                = 21,
            p_SATA_MAX_WAKE                = 7,
            p_SATA_MIN_BURST               = 4,
            p_SATA_MIN_INIT                = 12,
            p_SATA_MIN_WAKE                = 4,

            # RX Fabric Clock Output Control Attributes
            p_TRANS_TIME_RATE              = 0x0E,

            # TX Buffer Attributes
            p_TXBUF_EN                     = "TRUE" if tx_buffer_enable else "FALSE",
            p_TXBUF_RESET_ON_RATE_CHANGE   = "TRUE",
            p_TXDLY_CFG                    = 0x001F,
            p_TXDLY_LCFG                   = 0x030,
            p_TXDLY_TAP_CFG                = 0x0000,
            p_TXPH_CFG                     = 0x0780,
            p_TXPHDLY_CFG                  = 0x084020,
            p_TXPH_MONITOR_SEL             = 0b00000,
            p_TX_XCLK_SEL                  = "TXOUT" if tx_buffer_enable else "TXUSR",

            # FPGA TX Interface Attributes
            p_TX_DATA_WIDTH                = data_width,

            # TX Configurable Driver Attributes
            p_TX_DEEMPH0                   = 0b00000,
            p_TX_DEEMPH1                   = 0b00000,
            p_TX_EIDLE_ASSERT_DELAY        = 0b110,
            p_TX_EIDLE_DEASSERT_DELAY      = 0b100,
            p_TX_LOOPBACK_DRIVE_HIZ        = "FALSE",
            p_TX_MAINCURSOR_SEL            = 0b0,
            p_TX_DRIVE_MODE                = "DIRECT",
            p_TX_MARGIN_FULL_0             = 0b1001110,
            p_TX_MARGIN_FULL_1             = 0b1001001,
            p_TX_MARGIN_FULL_2             = 0b1000101,
            p_TX_MARGIN_FULL_3             = 0b1000010,
            p_TX_MARGIN_FULL_4             = 0b1000000,
            p_TX_MARGIN_LOW_0              = 0b1000110,
            p_TX_MARGIN_LOW_1              = 0b1000100,
            p_TX_MARGIN_LOW_2              = 0b1000010,
            p_TX_MARGIN_LOW_3              = 0b1000000,
            p_TX_MARGIN_LOW_4              = 0b1000000,

            # TX Gearbox Attributes
            p_TXGEARBOX_EN                 = "FALSE",

            # TX Initialization and Reset Attributes
            p_TXPCSRESET_TIME              = 0b00001,
            p_TXPMARESET_TIME              = 0b00001,

            # TX Receiver Detection Attributes
            p_TX_RXDETECT_CFG              = 0x1832,
            p_TX_RXDETECT_REF              = 0b100,

            # CPLL Attributes
            p_CPLL_CFG                     = 0xBC07DC,
            p_CPLL_FBDIV                   = 1 if use_qpll else pll.config["n2"],
            p_CPLL_FBDIV_45                = 4 if use_qpll else pll.config["n1"],
            p_CPLL_INIT_CFG                = 0x00001E,
            p_CPLL_LOCK_CFG                = 0x01E8,
            p_CPLL_REFCLK_DIV              = 1 if use_qpll else pll.config["m"],
            p_RXOUT_DIV                    = pll.config["d"],
            p_TXOUT_DIV                    = pll.config["d"],
            p_SATA_CPLL_CFG                = "VCO_3000MHZ",

            # RX Initialization and Reset Attributes
            p_RXDFELPMRESET_TIME           = 0b0001111,

            # RX Equalizer Attributes
            p_RXLPM_HF_CFG                 = 0b00000011110000,
            p_RXLPM_LF_CFG                 = 0b00000011110000,
            p_RX_DFE_GAIN_CFG              = 0x020FEA,
            p_RX_DFE_H2_CFG                = 0b000000000000,
            p_RX_DFE_H3_CFG                = 0b000001000000,
            p_RX_DFE_H4_CFG                = 0b00011110000,
            p_RX_DFE_H5_CFG                = 0b00011100000,
            p_RX_DFE_KL_CFG                = 0b0000011111110,
            p_RX_DFE_LPM_CFG               = 0x0954,
            p_RX_DFE_LPM_HOLD_DURING_EIDLE = 0b0,
            p_RX_DFE_UT_CFG                = 0b10001111000000000,
            p_RX_DFE_VP_CFG                = 0b00011111100000011,

            # Power-Down Attributes
            p_RX_CLKMUX_PD                 = 0b1,
            p_TX_CLKMUX_PD                 = 0b1,

            # FPGA RX Interface Attribute
            p_RX_INT_DATAWIDTH             = data_width == 40,

            # FPGA TX Interface Attribute
            p_TX_INT_DATAWIDTH             = data_width == 40,

            # TX Configurable Driver Attributes
            p_TX_QPI_STATUS_EN             = 0b0,

            # RX Equalizer Attributes
            p_RX_DFE_KL_CFG2               = 0x301148AC,
            p_RX_DFE_XYD_CFG               = 0b0000000000000,

            # TX Configurable Driver Attributes
            p_TX_PREDRIVER_MODE            = 0b0
        )
        self.gtx_params.update(
            # CPLL Ports
            #o_CPLLFBCLKLOST    =,
            o_CPLLLOCK          = Signal() if use_qpll else pll.lock,
            i_CPLLLOCKDETCLK    = ClockSignal(),
            i_CPLLLOCKEN        = 1,
            i_CPLLPD            = 0,
            #o_CPLLREFCLKLOST   = ,
            i_CPLLREFCLKSEL     = 0b001,
            i_CPLLRESET         = 0 if use_qpll else pll.reset,
            i_GTRSVD            = 0b0000000000000000,
            i_PCSRSVDIN         = 0b0000000000000000,
            i_PCSRSVDIN2        = 0b00000,
            i_PMARSVDIN         = 0b00000,
            i_PMARSVDIN2        = 0b00000,
            i_TSTIN             = 0b11111111111111111111,
            #o_TSTOUT           =,

            # Channel
            i_CLKRSVD           = 0b0000,

            # Channel - Clocking Ports
            i_GTGREFCLK         = 0,
            i_GTNORTHREFCLK0    = 0,
            i_GTNORTHREFCLK1    = 0,
            i_GTREFCLK0         = 0 if use_qpll else pll.refclk,
            i_GTREFCLK1         = 0,
            i_GTSOUTHREFCLK0    = 0,
            i_GTSOUTHREFCLK1    = 0,

            # Channel - DRP Ports
            i_DRPADDR           = drp_mux.addr,
            i_DRPCLK            = drp_mux.clk,
            i_DRPDI             = drp_mux.di,
            o_DRPDO             = drp_mux.do,
            i_DRPEN             = drp_mux.en,
            o_DRPRDY            = drp_mux.rdy,
            i_DRPWE             = drp_mux.we,

            # Clocking Ports
            #o_GTREFCLKMONITOR  =,
            i_QPLLCLK           = 0 if use_cpll else pll.clk,
            i_QPLLREFCLK        = 0 if use_cpll else pll.refclk,
            i_RXSYSCLKSEL       = 0b11 if use_qpll else 0b00,
            i_TXSYSCLKSEL       = 0b11 if use_qpll else 0b00,

            # Digital Monitor Ports
            #o_DMONITOROUT      =,

            # FPGA TX Interface Datapath Configuration
            i_TX8B10BEN         = 0,

            # Loopback Ports
            i_LOOPBACK          = self.loopback,

            # PCI Express Ports
            #o_PHYSTATUS        =,
            i_RXRATE            = 0b000,
            #o_RXVALID          =,

            # Power-Down Ports
            i_RXPD              = Cat(rx_init.gtXxpd, rx_init.gtXxpd),
            i_TXPD              = 0b00,

            # RX 8B/10B Decoder Ports
            i_SETERRSTATUS      = 0,

            # RX Initialization and Reset Ports
            i_EYESCANRESET      = 0,
            i_RXUSERRDY         = rx_init.Xxuserrdy,

            # RX Margin Analysis Ports
            #o_EYESCANDATAERROR =,
            i_EYESCANMODE       = 0,
            i_EYESCANTRIGGER    = 0,

            # Receive Ports - CDR Ports
            i_RXCDRFREQRESET    = 0,
            i_RXCDRHOLD         = 0,
            #o_RXCDRLOCK        =,
            i_RXCDROVRDEN       = 0,
            i_RXCDRRESET        = 0,
            i_RXCDRRESETRSV     = 0,

            # Receive Ports - Clock Correction Ports
            #o_RXCLKCORCNT      =,

            # Receive Ports - FPGA RX Interface Datapath Configuration
            i_RX8B10BEN         = 0,

            # Receive Ports - FPGA RX Interface Ports
            i_RXUSRCLK          = ClockSignal("rx"),
            i_RXUSRCLK2         = ClockSignal("rx"),

            # Receive Ports - FPGA RX interface Ports
            o_RXDATA            = Cat(*[rxdata[10*i:10*i+8] for i in range(nwords)]),

            # Receive Ports - Pattern Checker Ports
            #o_RXPRBSERR        =,
            i_RXPRBSSEL         = 0b000,

            # Receive Ports - Pattern Checker ports
            i_RXPRBSCNTRESET    = 0,

            # Receive Ports - RX  Equalizer Ports
            i_RXDFEXYDEN        = 1,
            i_RXDFEXYDHOLD      = 0,
            i_RXDFEXYDOVRDEN    = 0,

            # Receive Ports - RX 8B/10B Decoder Ports
            i_RXDISPERR         = Cat(*[rxdata[10*i+9] for i in range(nwords)]),
            #o_RXNOTINTABLE     =,

            # Receive Ports - RX AFE
            i_GTXRXP            = rx_pads.p,
            i_GTXRXN            = rx_pads.n,

            # Receive Ports - RX Buffer Bypass Ports
            i_RXBUFRESET        = 0,
            #o_RXBUFSTATUS      =,
            i_RXDDIEN           = 0 if rx_buffer_enable else 1,
            i_RXDLYBYPASS       = 1 if rx_buffer_enable else 0,
            i_RXDLYEN           = 0,
            i_RXDLYOVRDEN       = 0,
            i_RXDLYSRESET       = rx_init.Xxdlysreset,
            o_RXDLYSRESETDONE   = rx_init.Xxdlysresetdone,
            i_RXPHALIGN         = 0,
            o_RXPHALIGNDONE     = rx_init.Xxphaligndone,
            i_RXPHALIGNEN       = 0,
            i_RXPHDLYPD         = 0,
            i_RXPHDLYRESET      = 0,
            #o_RXPHMONITOR      =,
            i_RXPHOVRDEN        = 0,
            #o_RXPHSLIPMONITOR  =,
            #o_RXSTATUS         =,

            # Receive Ports - RX Byte and Word Alignment Ports
            #o_RXBYTEISALIGNED  =,
            #o_RXBYTEREALIGN    =,
            #o_RXCOMMADET       =,
            i_RXCOMMADETEN      = 1,
            i_RXMCOMMAALIGNEN   = (~clock_aligner & self.rx_align & (rx_prbs_config == 0b00)) if rx_buffer_enable else 0,
            i_RXPCOMMAALIGNEN   = (~clock_aligner & self.rx_align & (rx_prbs_config == 0b00)) if rx_buffer_enable else 0,

            # Receive Ports - RX Channel Bonding Ports
            #o_RXCHANBONDSEQ    =,
            i_RXCHBONDEN        = 0,
            i_RXCHBONDLEVEL     = 0b000,
            i_RXCHBONDMASTER    = 0,
            #o_RXCHBONDO        =,
            i_RXCHBONDSLAVE     = 0,

            # Receive Ports - RX Channel Bonding Ports
            #o_RXCHANISALIGNED  =,
            #o_RXCHANREALIGN    =,

            # Receive Ports - RX Equailizer Ports
            i_RXLPMHFHOLD       = 0,
            i_RXLPMHFOVRDEN     = 0,
            i_RXLPMLFHOLD       = 0,

            # Receive Ports - RX Equalizer Ports
            i_RXDFEAGCHOLD      = 0,
            i_RXDFEAGCOVRDEN    = 0,
            i_RXDFECM1EN        = 0,
            i_RXDFELFHOLD       = 0,
            i_RXDFELFOVRDEN     = 1,
            i_RXDFELPMRESET     = 0,
            i_RXDFETAP2HOLD     = 0,
            i_RXDFETAP2OVRDEN   = 0,
            i_RXDFETAP3HOLD     = 0,
            i_RXDFETAP3OVRDEN   = 0,
            i_RXDFETAP4HOLD     = 0,
            i_RXDFETAP4OVRDEN   = 0,
            i_RXDFETAP5HOLD     = 0,
            i_RXDFETAP5OVRDEN   = 0,
            i_RXDFEUTHOLD       = 0,
            i_RXDFEUTOVRDEN     = 0,
            i_RXDFEVPHOLD       = 0,
            i_RXDFEVPOVRDEN     = 0,
            i_RXDFEVSEN         = 0,
            i_RXLPMLFKLOVRDEN   = 0,
            #o_RXMONITOROUT     =
            i_RXMONITORSEL      = 0,
            i_RXOSHOLD          = 0,
            i_RXOSOVRDEN        = 0,

            # Receive Ports - RX Fabric ClocK Output Control Ports
            #o_RXRATEDONE       =,

            # Receive Ports - RX Fabric Output Control Ports
            o_RXOUTCLK          = self.rxoutclk,
            #o_RXOUTCLKFABRIC   =,
            #o_RXOUTCLKPCS      =,
            i_RXOUTCLKSEL       = 0b010,

            # Receive Ports - RX Gearbox Ports
            #o_RXDATAVALID      =,
            #o_RXHEADER         =,
            #o_RXHEADERVALID    =,
            #o_RXSTARTOFSEQ     =,

            # Receive Ports - RX Gearbox Ports
            i_RXGEARBOXSLIP     = 0,

            # Receive Ports - RX Initialization and Reset Ports
            i_GTRXRESET         = rx_init.gtXxreset,
            i_RXOOBRESET        = 0,
            i_RXPCSRESET        = 0,
            i_RXPMARESET        = 0,

            # Receive Ports - RX Margin Analysis ports
            i_RXLPMEN           = 0,

            # Receive Ports - RX OOB Signaling ports
            #o_RXCOMSASDET      =,
            #o_RXCOMWAKEDET     =,

            # Receive Ports - RX OOB Signaling ports
            #o_RXCOMINITDET     =,

            # Receive Ports - RX OOB signalling Ports
            #o_RXELECIDLE       =,
            i_RXELECIDLEMODE    = 0b11,

            # Receive Ports - RX Polarity Control Ports
            i_RXPOLARITY        = rx_polarity,

            # Receive Ports - RX gearbox ports
            i_RXSLIDE           = 0,

            # Receive Ports - RX8B/10B Decoder Ports
            #o_RXCHARISCOMMA    =,
            o_RXCHARISK         = Cat(*[rxdata[10*i+8] for i in range(nwords)]),

            # Receive Ports - Rx Channel Bonding Ports
            i_RXCHBONDI         = 0b00000,

            # Receive Ports -RX Initialization and Reset Ports
            o_RXRESETDONE       = rx_init.Xxresetdone,

            # Rx AFE Ports
            i_RXQPIEN           = 0,
            #o_RXQPISENN        =,
            #o_RXQPISENP        =,

            # TX Buffer Bypass Ports
            i_TXPHDLYTSTCLK     = 0,

            # TX Configurable Driver Ports
            i_TXPOSTCURSOR      = 0b00000,
            i_TXPOSTCURSORINV   = 0,
            i_TXPRECURSOR       = 0b00000,
            i_TXPRECURSORINV    = 0,
            i_TXQPIBIASEN       = 0,
            i_TXQPISTRONGPDOWN  = 0,
            i_TXQPIWEAKPUP      = 0,

            # TX Initialization and Reset Ports
            i_CFGRESET          = 0,
            i_GTTXRESET         = tx_init.gtXxreset,
            #o_PCSRSVDOUT       =,
            i_TXUSERRDY         = tx_init.Xxuserrdy,

            # Transceiver Reset Mode Operation
            i_GTRESETSEL        = 0,
            i_RESETOVRD         = 0,

            # Transmit Ports - 8b10b Encoder Control Ports
            i_TXCHARDISPMODE    = Cat(*[txdata[10*i+9] for i in range(nwords)]),
            i_TXCHARDISPVAL     = Cat(*[txdata[10*i+8] for i in range(nwords)]),

            # Transmit Ports - FPGA TX Interface Ports
            i_TXUSRCLK          = ClockSignal("tx"),
            i_TXUSRCLK2         = ClockSignal("tx"),

            # Transmit Ports - PCI Express Ports
            i_TXELECIDLE        = 0,
            i_TXMARGIN          = 0b000,
            i_TXRATE            = 0b000,
            i_TXSWING           = 0,

            # Transmit Ports - Pattern Generator Ports
            i_TXPRBSFORCEERR    = 0,

            # Transmit Ports - TX Buffer Bypass Ports
            i_TXDLYBYPASS       = 1 if tx_buffer_enable else 0,
            i_TXDLYEN           = 0,
            i_TXDLYHOLD         = 0,
            i_TXDLYOVRDEN       = 0,
            i_TXDLYSRESET       = tx_init.Xxdlysreset,
            o_TXDLYSRESETDONE   = tx_init.Xxdlysresetdone,
            i_TXDLYUPDOWN       = 0,
            i_TXPHALIGN         = 0,
            o_TXPHALIGNDONE     = tx_init.Xxphaligndone,
            i_TXPHALIGNEN       = 0,
            i_TXPHDLYPD         = 0,
            i_TXPHDLYRESET      = 0,
            i_TXPHINIT          = 0,
            #o_TXPHINITDONE     =,
            i_TXPHOVRDEN        = 0,

            # Transmit Ports - TX Buffer Ports
            #o_TXBUFSTATUS      =,

            # Transmit Ports - TX Configurable Driver Ports
            i_TXBUFDIFFCTRL     = 0b100,
            i_TXDEEMPH          = 0,
            i_TXDIFFCTRL        = 0b1000,
            i_TXDIFFPD          = 0,
            i_TXINHIBIT         = self.tx_inhibit,
            i_TXMAINCURSOR      = 0b0000000,
            i_TXPISOPD          = 0,

            # Transmit Ports - TX Data Path interface
            i_TXDATA            = Cat(*[txdata[10*i:10*i+8] for i in range(nwords)]),

            # Transmit Ports - TX Driver and OOB signaling
            o_GTXTXN            = tx_pads.n,
            o_GTXTXP            = tx_pads.p,

            # Transmit Ports - TX Fabric Clock Output Control Ports
            o_TXOUTCLK          = self.txoutclk,
            #o_TXOUTCLKFABRIC   =,
            #o_TXOUTCLKPCS      =,
            i_TXOUTCLKSEL       = 0b010 if tx_buffer_enable else 0b011,
            #o_TXRATEDONE       =,

            # Transmit Ports - TX Gearbox Ports
            i_TXCHARISK         = 0b00000000,
            #o_TXGEARBOXREADY   =,
            i_TXHEADER          = 0b000,
            i_TXSEQUENCE        = 0b0000000,
            i_TXSTARTSEQ        = 0,

            # Transmit Ports - TX Initialization and Reset Ports
            i_TXPCSRESET        = 0,
            i_TXPMARESET        = 0,
            o_TXRESETDONE       = tx_init.Xxresetdone,

            # Transmit Ports - TX OOB signaling Ports
            #o_TXCOMFINISH      =,
            i_TXCOMINIT         = 0,
            i_TXCOMSAS          = 0,
            i_TXCOMWAKE         = 0,
            i_TXPDELECIDLEMODE  = 0,

            # Transmit Ports - TX Polarity Control Ports
            i_TXPOLARITY        = tx_polarity,

            # Transmit Ports - TX Receiver Detection Ports
            i_TXDETECTRX        = 0,

            # Transmit Ports - TX8b/10b Encoder Ports
            i_TX8B10BBYPASS     = 0b00000000,

            # Transmit Ports - pattern Generator Ports
            i_TXPRBSSEL         = 0b000,

            # Tx Configurable Driver  Ports
            #o_TXQPISENN        =,
            #o_TXQPISENP        =,
            )

        # TX clocking ------------------------------------------------------------------------------
        tx_reset_deglitched = Signal()
        tx_reset_deglitched.attr.add("no_retiming")
        self.sync += tx_reset_deglitched.eq(~tx_init.done)
        self.clock_domains.cd_tx = ClockDomain()

        txoutclk_bufg = Signal()
        self.specials += Instance("BUFG", i_I=self.txoutclk, o_O=txoutclk_bufg)

        if not tx_buffer_enable:
            txoutclk_div = pll.config["clkin"]/self.tx_clk_freq
        else:
            txoutclk_div = 1
        # Use txoutclk_bufg when divider is 1
        if txoutclk_div == 1:
            self.comb += self.cd_tx.clk.eq(txoutclk_bufg)
            self.specials += AsyncResetSynchronizer(self.cd_tx, tx_reset_deglitched)
        # Use a BUFR when integer divider (with BUFR_DIVIDE)
        elif txoutclk_div == int(txoutclk_div):
            txoutclk_bufr = Signal()
            self.specials += [
                Instance("BUFR", i_I=txoutclk_bufg, o_O=txoutclk_bufr,
                    i_CE=1, p_BUFR_DIVIDE=str(int(txoutclk_div))),
                Instance("BUFG", i_I=txoutclk_bufr, o_O=self.cd_tx.clk),
                AsyncResetSynchronizer(self.cd_tx, tx_reset_deglitched)
            ]
        # Use a PLL when non-integer divider
        else:
            txoutclk_pll = S7PLL()
            self.comb += txoutclk_pll.reset.eq(tx_reset_deglitched)
            self.submodules += txoutclk_pll
            txoutclk_pll.register_clkin(txoutclk_bufg, pll.config["clkin"])
            txoutclk_pll.create_clkout(self.cd_tx, self.tx_clk_freq)

        # RX clocking ------------------------------------------------------------------------------
        rx_reset_deglitched = Signal()
        rx_reset_deglitched.attr.add("no_retiming")
        self.sync.tx += rx_reset_deglitched.eq(~rx_init.done)
        self.clock_domains.cd_rx = ClockDomain()
        self.specials += [
            Instance("BUFG", i_I=self.rxoutclk, o_O=self.cd_rx.clk),
            AsyncResetSynchronizer(self.cd_rx, rx_reset_deglitched)
        ]

        # TX Datapath and PRBS ---------------------------------------------------------------------
        self.submodules.tx_prbs = ClockDomainsRenamer("tx")(PRBSTX(data_width, True))
        self.comb += self.tx_prbs.config.eq(tx_prbs_config)
        self.comb += [
            self.tx_prbs.i.eq(Cat(*[self.encoder.output[i] for i in range(nwords)])),
            If(tx_produce_square_wave,
                # square wave @ linerate/data_width for scope observation
                txdata.eq(Signal(data_width, reset=(1<<(data_width//2))-1))
            ).Elif(tx_produce_pattern,
                txdata.eq(self.tx_pattern)
            ).Else(
                txdata.eq(self.tx_prbs.o)
            )
        ]

        # RX Datapath and PRBS ---------------------------------------------------------------------
        self.submodules.rx_prbs = ClockDomainsRenamer("rx")(PRBSRX(data_width, True))
        self.comb += [
            self.rx_prbs.config.eq(rx_prbs_config),
            rx_prbs_errors.eq(self.rx_prbs.errors)
        ]
        for i in range(nwords):
            self.comb += self.decoders[i].input.eq(rxdata[10*i:10*(i+1)])
        self.comb += self.rx_prbs.i.eq(rxdata)

        # Clock Aligner ----------------------------------------------------------------------------
        if clock_aligner:
            clock_aligner = BruteforceClockAligner(clock_aligner_comma, self.tx_clk_freq)
            self.submodules.clock_aligner = clock_aligner
            ps_restart = PulseSynchronizer("tx", "sys")
            self.submodules += ps_restart
            self.comb += [
                clock_aligner.rxdata.eq(rxdata),
                ps_restart.i.eq(clock_aligner.restart),
                rx_init.restart.eq((ps_restart.o & self.rx_align) | ~self.rx_enable),
                self.rx_ready.eq(clock_aligner.ready)
            ]
    def __init__(self, platform, pads, data_width=64, bar0_size=1*MB, cd="sys"):
        # Streams ----------------------------------------------------------------------------------
        self.sink = stream.Endpoint(phy_layout(data_width))
        self.source = stream.Endpoint(phy_layout(data_width))
        self.msi = stream.Endpoint(msi_layout())

        # Registers --------------------------------------------------------------------------------
        self._lnk_up = CSRStatus()
        self._msi_enable = CSRStatus()
        self._bus_master_enable = CSRStatus()
        self._max_request_size = CSRStatus(16)
        self._max_payload_size = CSRStatus(16)

        # Parameters/Locals ------------------------------------------------------------------------
        self.platform = platform
        self.data_width = data_width

        self.id = Signal(16)
        self.bar0_size = bar0_size
        self.bar0_mask = get_bar_mask(bar0_size)
        self.max_request_size = Signal(16)
        self.max_payload_size = Signal(16)

        self.external_hard_ip = False

        # # #

        # Clocking ---------------------------------------------------------------------------------
        pcie_refclk = Signal()
        self.specials += Instance("IBUFDS_GTE2",
            i_CEB=0,
            i_I=pads.clk_p,
            i_IB=pads.clk_n,
            o_O=pcie_refclk
        )
        self.clock_domains.cd_pcie = ClockDomain()

        # TX CDC (FPGA --> HOST) -------------------------------------------------------------------
        if cd == "pcie":
            s_axis_tx = self.sink
        else:
            tx_buffer = stream.Buffer(phy_layout(data_width))
            tx_buffer = ClockDomainsRenamer(cd)(tx_buffer)
            tx_cdc = stream.AsyncFIFO(phy_layout(data_width), 4)
            tx_cdc = ClockDomainsRenamer({"write": cd, "read": "pcie"})(tx_cdc)
            self.submodules += tx_buffer, tx_cdc
            self.comb += [
                self.sink.connect(tx_buffer.sink),
                tx_buffer.source.connect(tx_cdc.sink)
            ]
            s_axis_tx = tx_cdc.source

        # RX CDC (HOST --> FPGA) -------------------------------------------------------------------
        if cd == "pcie":
            m_axis_rx = self.source
        else:
            rx_cdc = stream.AsyncFIFO(phy_layout(data_width), 4)
            rx_cdc = ClockDomainsRenamer({"write": "pcie", "read": cd})(rx_cdc)
            rx_buffer = stream.Buffer(phy_layout(data_width))
            rx_buffer = ClockDomainsRenamer(cd)(rx_buffer)
            self.submodules += rx_buffer, rx_cdc
            self.comb += [
                rx_cdc.source.connect(rx_buffer.sink),
                rx_buffer.source.connect(self.source)
            ]
            m_axis_rx = rx_cdc.sink

        # MSI CDC (FPGA --> HOST) ------------------------------------------------------------------
        if cd == "pcie":
            cfg_msi = self.msi
        else:
            msi_cdc = stream.AsyncFIFO(msi_layout(), 4)
            msi_cdc = ClockDomainsRenamer({"write": cd, "read": "pcie"})(msi_cdc)
            self.submodules += msi_cdc
            self.comb += self.msi.connect(msi_cdc.sink)
            cfg_msi = msi_cdc.source

        # Hard IP Configuration --------------------------------------------------------------------
        def convert_size(command, size):
            cases = {}
            value = 128
            for i in range(6):
                cases[i] = size.eq(value)
                value = value*2
            return Case(command, cases)

        lnk_up = Signal()
        msienable = Signal()
        bus_number = Signal(8)
        device_number = Signal(5)
        function_number = Signal(3)
        command = Signal(16)
        dcommand = Signal(16)
        self.sync.pcie += [
            convert_size(dcommand[12:15], self.max_request_size),
            convert_size(dcommand[5:8], self.max_payload_size),
            self.id.eq(Cat(function_number, device_number, bus_number))
        ]
        self.specials += [
            MultiReg(lnk_up, self._lnk_up.status),
            MultiReg(command[2], self._bus_master_enable.status),
            MultiReg(msienable, self._msi_enable.status),
            MultiReg(self.max_request_size, self._max_request_size.status),
            MultiReg(self.max_payload_size, self._max_payload_size.status)
        ]

        # Hard IP ----------------------------------------------------------------------------------
        m_axis_rx_tlast = Signal()
        m_axis_rx_tuser = Signal(32)
        self.pcie_phy_params = dict(
            p_C_DATA_WIDTH=data_width,
            p_C_PCIE_GT_DEVICE={
                "xc7k": "GTX",
                "xc7a": "GTP"}[platform.device[:4]],
            p_C_BAR0=get_bar_mask(bar0_size),

            i_sys_clk=pcie_refclk,
            i_sys_rst_n=1 if not hasattr(pads, "rst_n") else pads.rst_n,

            o_pci_exp_txp=pads.tx_p,
            o_pci_exp_txn=pads.tx_n,

            i_pci_exp_rxp=pads.rx_p,
            i_pci_exp_rxn=pads.rx_n,

            o_user_clk=ClockSignal("pcie"),
            o_user_reset=ResetSignal("pcie"),
            o_user_lnk_up=lnk_up,

            #o_tx_buf_av=,
            #o_tx_terr_drop=,
            #o_tx_cfg_req=,
            i_tx_cfg_gnt=1,

            i_s_axis_tx_tvalid=s_axis_tx.valid,
            i_s_axis_tx_tlast=s_axis_tx.last,
            o_s_axis_tx_tready=s_axis_tx.ready,
            i_s_axis_tx_tdata=s_axis_tx.dat,
            i_s_axis_tx_tkeep=s_axis_tx.be,
            i_s_axis_tx_tuser=0,

            i_rx_np_ok=1,
            i_rx_np_req=1,

            o_m_axis_rx_tvalid=m_axis_rx.valid,
            o_m_axis_rx_tlast=m_axis_rx_tlast,
            i_m_axis_rx_tready=m_axis_rx.ready,
            o_m_axis_rx_tdata=m_axis_rx.dat,
            o_m_axis_rx_tkeep=m_axis_rx.be,
            o_m_axis_rx_tuser=m_axis_rx_tuser,

            #o_cfg_to_turnoff=,
            o_cfg_bus_number=bus_number,
            o_cfg_device_number=device_number,
            o_cfg_function_number=function_number,
            o_cfg_command=command,
            o_cfg_dcommand=dcommand,
            o_cfg_interrupt_msienable=msienable,

            i_cfg_interrupt=cfg_msi.valid,
            o_cfg_interrupt_rdy=cfg_msi.ready,
            i_cfg_interrupt_di=cfg_msi.dat,

            i_QPLL_PLL1PD=1,
        )
        if data_width == 128:
            self.comb += m_axis_rx.last.eq(m_axis_rx_tuser[21])
        else:
            self.comb += m_axis_rx.last.eq(m_axis_rx_tlast)
示例#14
0
    def __init__(self, capture_depth, **kwargs):
        self.platform = Platform(**kwargs)
        self.platform.add_extension([
            ("tp0", 0, Pins("X3:5"), IOStandard("LVCMOS33")),
        ])

        self.clock_domains.cd_ref = ClockDomain()
        self.clock_domains.cd_rx = ClockDomain()
        self.clock_domains.cd_tx = ClockDomain()

        self.submodules.serdes = serdes = \
            LatticeECP5PCIeSERDES(self.platform.request("pcie_x1"))
        self.submodules.aligner = aligner = \
            ClockDomainsRenamer("rx")(PCIeSERDESAligner(serdes.lane))
        self.comb += [
            self.cd_ref.clk.eq(serdes.ref_clk),
            serdes.rx_clk_i.eq(serdes.rx_clk_o),
            self.cd_rx.clk.eq(serdes.rx_clk_i),
            serdes.tx_clk_i.eq(serdes.tx_clk_o),
            self.cd_tx.clk.eq(serdes.tx_clk_i),
        ]

        self.submodules.tx_phy = ClockDomainsRenamer("tx")(PCIePHYTX(aligner))
        self.comb += [
            self.aligner.rx_align.eq(1),
            self.tx_phy.ts.n_fts.eq(0xff),
            self.tx_phy.ts.rate.gen1.eq(1),
        ]

        with open("top.sdc", "w") as f:
            f.write("define_clock -name {n:serdes_ref_clk} -freq 100.000\n")
            f.write("define_clock -name {n:serdes_tx_clk_o} -freq 150.000\n")
            f.write("define_clock -name {n:serdes_rx_clk_o} -freq 150.000\n")
        self.platform.add_source("top.sdc")
        self.platform.add_platform_command(
            """FREQUENCY NET "serdes_ref_clk" 100 MHz;""")
        self.platform.add_platform_command(
            """FREQUENCY NET "serdes_rx_clk_o" 125 MHz;""")
        self.platform.add_platform_command(
            """FREQUENCY NET "serdes_tx_clk_o" 125 MHz;""")

        refclkcounter = Signal(32)
        self.sync.ref += refclkcounter.eq(refclkcounter + 1)
        rxclkcounter = Signal(32)
        self.sync.rx += rxclkcounter.eq(rxclkcounter + 1)
        txclkcounter = Signal(32)
        self.sync.tx += txclkcounter.eq(txclkcounter + 1)

        led_att1 = self.platform.request("user_led")
        led_att2 = self.platform.request("user_led")
        led_sta1 = self.platform.request("user_led")
        led_sta2 = self.platform.request("user_led")
        led_err1 = self.platform.request("user_led")
        led_err2 = self.platform.request("user_led")
        led_err3 = self.platform.request("user_led")
        led_err4 = self.platform.request("user_led")
        self.comb += [
            led_att1.eq(~(refclkcounter[25])),
            led_att2.eq(~(0)),
            led_sta1.eq(~(rxclkcounter[25])),
            led_sta2.eq(~(txclkcounter[25])),
            led_err1.eq(~(~serdes.lane.rx_present)),
            led_err2.eq(~(~serdes.lane.rx_locked)),
            led_err3.eq(~(~serdes.lane.rx_aligned)),
            led_err4.eq(~(0)),
        ]

        trigger_rx = Signal()
        trigger_ref = Signal()
        self.specials += MultiReg(trigger_ref, trigger_rx, odomain="rx")

        capture = Signal()
        self.submodules.symbols = symbols = ClockDomainsRenamer({
            "write": "rx",
            "read": "ref"
        })(AsyncFIFO(width=18, depth=capture_depth))
        self.comb += [
            symbols.din.eq(Cat(aligner.rx_symbol)),
            symbols.we.eq(capture)
        ]
        self.sync.rx += [
            If(trigger_rx, capture.eq(1)).Elif(~symbols.writable,
                                               capture.eq(0))
        ]

        uart_pads = Pads(self.platform.request("serial"))
        self.submodules += uart_pads
        self.submodules.uart = uart = ClockDomainsRenamer("ref")(UART(
            uart_pads, bit_cyc=uart_bit_cyc(100e6, 115200)[0]))

        self.comb += [uart.rx_ack.eq(uart.rx_rdy), trigger_ref.eq(uart.rx_rdy)]

        self.submodules.fsm = ClockDomainsRenamer("ref")(
            FSM(reset_state="WAIT"))
        self.fsm.act("WAIT", If(uart.rx_rdy, NextState("SYNC-1")))
        self.fsm.act(
            "SYNC-1",
            If(uart.tx_rdy, uart.tx_ack.eq(1), uart.tx_data.eq(0xff),
               NextState("SYNC-2")))
        self.fsm.act(
            "SYNC-2",
            If(uart.tx_rdy, uart.tx_ack.eq(1), uart.tx_data.eq(0xff),
               NextState("BYTE-0")))
        self.fsm.act(
            "BYTE-0",
            If(symbols.readable & uart.tx_rdy, uart.tx_ack.eq(1),
               uart.tx_data.eq(symbols.dout[16:]),
               NextState("BYTE-1")).Elif(~symbols.readable, NextState("WAIT")))
        self.fsm.act(
            "BYTE-1",
            If(symbols.readable & uart.tx_rdy, uart.tx_ack.eq(1),
               uart.tx_data.eq(symbols.dout[8:]), NextState("BYTE-2")))
        self.fsm.act(
            "BYTE-2",
            If(symbols.readable & uart.tx_rdy, uart.tx_ack.eq(1),
               uart.tx_data.eq(symbols.dout[0:]), symbols.re.eq(1),
               NextState("BYTE-0")))

        tp0 = self.platform.request("tp0")
示例#15
0
    def __init__(self, clkspertick, clkfreq, bits=64):
        self.clkspertick = int(clkfreq / clkspertick)

        self.intro = ModuleDoc("""TickTimer: A practical systick timer.

        TIMER0 in the system gives a high-resolution, sysclk-speed timer which overflows
        very quickly and requires OS overhead to convert it into a practically usable time source
        which counts off in systicks, instead of sysclks.

        The hardware parameter to the block is the divisor of sysclk, and sysclk. So if
        the divisor is 1000, then the increment for a tick is 1ms. If the divisor is 2000,
        the increment for a tick is 0.5ms. 
        
        Note to self: substantial area savings could be hand by being smarter about the
        synchronization between the always-on and the TickTimer domains. Right now about 1.8%
        of the chip is eaten up by ~1100 synchronization registers to cross the 64-bit values
        between the clock domains. Since the values move rarely, a slightly smarter method
        would be to create a lock-out around a read pulse and then create some false_path
        rules around the datapaths to keep the place/route from getting distracted by the
        cross-domain clocks.
        """)

        resolution_in_ms = 1000 * (self.clkspertick / clkfreq)
        self.note = ModuleDoc(
            title="Configuration",
            body=
            "This timer was configured with {} bits, which rolls over in {:.2f} years, with each bit giving {}ms resolution"
            .format(bits, (2**bits / (60 * 60 * 24 * 365)) *
                    (self.clkspertick / clkfreq), resolution_in_ms))

        prescaler = Signal(max=self.clkspertick, reset=self.clkspertick)
        timer = Signal(bits)

        # cross-process domain signals. Broken out to a different CSR so it can be on a different virtual memory page.
        self.pause = Signal()
        pause = Signal()
        self.specials += MultiReg(self.pause, pause, "always_on")

        self.load = Signal()
        self.submodules.load_xfer = BlindTransfer("sys", "always_on")
        self.comb += self.load_xfer.i.eq(self.load)

        self.paused = Signal()
        paused = Signal()
        self.specials += MultiReg(paused, self.paused)

        self.timer = Signal(bits)
        self.submodules.timer_sync = BusSynchronizer(bits, "always_on", "sys")
        self.comb += [
            self.timer_sync.i.eq(timer),
            self.timer.eq(self.timer_sync.o)
        ]
        self.resume_time = Signal(bits)
        self.submodules.resume_sync = BusSynchronizer(bits, "sys", "always_on")
        self.comb += [self.resume_sync.i.eq(self.resume_time)]

        self.control = CSRStorage(fields=[
            CSRField(
                "reset",
                description=
                "Write a `1` to this bit to reset the count to 0. This bit has priority over all other requests.",
                pulse=True),
        ])
        self.time = CSRStatus(bits,
                              name="time",
                              description="""Elapsed time in systicks""")
        self.comb += self.time.status.eq(self.timer_sync.o)

        self.submodules.reset_xfer = BlindTransfer("sys", "always_on")
        self.comb += [
            self.reset_xfer.i.eq(self.control.fields.reset),
        ]

        self.sync.always_on += [
            If(
                self.reset_xfer.o,
                timer.eq(0),
                prescaler.eq(self.clkspertick),
            ).Elif(
                self.load_xfer.o,
                prescaler.eq(self.clkspertick),
                timer.eq(self.resume_sync.o),
            ).Else(
                If(
                    prescaler == 0, prescaler.eq(self.clkspertick),
                    If(pause == 0, timer.eq(timer + 1),
                       paused.eq(0)).Else(timer.eq(timer), paused.eq(1))).Else(
                           prescaler.eq(prescaler - 1), ))
        ]

        self.msleep = ModuleDoc("""msleep extension
        
        The msleep extension is a Xous-specific add-on to aid the implementation of the msleep server.
        
        msleep fires an interrupt when the requested time is less than or equal to the current elapsed time in
        systicks. The interrupt remains active until a new target is set, or masked. 
        
        There is a slight slip in time (~200ns) from when the msleep timer is set before it can take effect.
        This is because it takes many CPU clock cycles to transfer this data into the always-on clock
        domain, which runs at a much slower rate than the CPU clock.
        """)
        self.msleep_target = CSRStorage(
            size=bits,
            description="Target time in {}ms ticks".format(resolution_in_ms))
        self.submodules.ev = EventManager()
        self.ev.alarm = EventSourceLevel()
        # sys-domain alarm is computed using sys-domain time view, so that the trigger condition
        # corresponds tightly to the setting of the target time
        alarm_trigger = Signal()
        self.comb += self.ev.alarm.trigger.eq(alarm_trigger)

        # always_on domain gets a delayed copy of msleep_target
        # thus its output may not match that of the sys-domain alarm
        # in particular, it takes time for msleep_target update to propagate through
        # the bus synchronizers; however, the "trigger" enable for the system is handled
        # in the sys-domain, and can be set *before* the bus synchronizers have passed the
        # data through. This causes the alarm to glitch prematurely.

        # if we seem to be errantly aborting WFI's that are entered shortly after
        # setting an msleep target, this race condition is likely the culprit.

        # the circuit below locks out alarms for the duration of time that it takes for
        # msleep_target to propagate to its target, and back again
        self.submodules.ping = BlindTransfer("sys", "always_on")
        self.comb += self.ping.i.eq(self.msleep_target.re)
        self.submodules.pong = BlindTransfer("always_on", "sys")
        self.comb += self.pong.i.eq(self.ping.o)
        lockout_alarm = Signal()
        self.comb += [
            If(lockout_alarm, alarm_trigger.eq(0)).Else(
                alarm_trigger.eq(
                    self.msleep_target.storage <= self.timer_sync.o))
        ]
        self.sync += [
            If(self.msleep_target.re, lockout_alarm.eq(1)).Elif(
                self.pong.o,
                lockout_alarm.eq(0)).Else(lockout_alarm.eq(lockout_alarm))
        ]

        # re-compute the alarm signal in the "always on" domain -- so that this can trigger even when the CPU clock is stopped
        alarm = Signal()
        self.submodules.target_xfer = BusSynchronizer(bits, "sys", "always_on")
        self.comb += self.target_xfer.i.eq(self.msleep_target.storage)
        self.sync.always_on += alarm.eq(self.target_xfer.o <= timer)

        self.alarm_always_on = Signal()
        self.comb += self.alarm_always_on.eq(alarm)
示例#16
0
    def __init__(self,
                 pads,
                 fifo_depth=256,
                 controller=False,
                 master=False,
                 concatenate_channels=True,
                 sample_width=16,
                 frame_format=I2S_FORMAT.I2S_LEFT_JUSTIFIED,
                 lrck_ref_freq=100e6,
                 lrck_freq=44100,
                 bits_per_channel=28):
        if master == True:
            print(
                "Master/slave terminology deprecated, please use controller/peripheral. Please see http://oshwa.org/a-resolution-to-redefine-spi-signal-names."
            )
            controller = True

        self.intro = ModuleDoc("""Intro

        I2S controller/peripheral creates a controller/peripheral audio interface instance depending on a configured controller variable. 
        Tx and Rx interfaces are inferred based upon the presence or absence of the respective pins in the "pads" argument.
        
        When device is configured as controller you can manipulate LRCK and SCLK signals using below variables.
        
        - lrck_ref_freq - is a reference signal that is required to achive desired LRCK and SCLK frequencies.
                         Have be the same as your sys_clk.
        - lrck_freq - this variable defines requested LRCK frequency. Mind you, that based on sys_clk frequency, 
                         configured value will be more or less acurate.
        - bits_per_channel - defines SCLK frequency. Mind you, that based on sys_clk frequency, 
                         the requested amount of bits per channel may vary from configured.
        
        When device is configured as peripheral I2S interface, sampling rate and framing is set by the
        programming of the audio CODEC chip. A peripheral configuration defers the
        generation of audio clocks to the CODEC, which has PLLs specialized to generate the correct
        frequencies for audio sampling rates.

        I2S core supports two formats: standard and left-justified.
        
        - Standard format requires a device to receive and send data with one bit offset for both channels. 
            Left channel begins with low signal on LRCK.
        - Left justified format requires from device to receive and send data without any bit offset for both channels.
            Left channel begins with high signal on LRCK.
    
        Sample width can be any of 1 to 32 bits.

        When sample_width is less than or equal to 16-bit and concatenate_channels is enabled,
        sending and reciving channels is performed atomically. eg. both samples are transfered from/to fifo in single operation.

        System Interface
        ----------------

        `fifo_depth` is the depth at which either a read interrupt is fired (guaranteeing at least
        `fifo_depth` stereo samples in the receive FIFO) or a write interrupt is fired (guaranteeing
        at least `fifo_depth` free space in the transmit FIFO). The maximum depth is 512.

        To receive audio data:

        - reset the Rx FIFO, to guarantee all pointers at zero
        - hook the Rx full interrupt with an interrupt handler (optional)
        - if the CODEC is not yet transmitting data, initiate data transmission
        - enable Rx FIFO to run
        - poll or wait for interrupt; upon interrupt, read `fifo_depth` words. Repeat.
        - to close the stream, simply clear the Rx FIFO enable bit. The next initiation should call a
          reset of the FIFO to ensure leftover previous data is cleared from the FIFO.

        To transmit audio data:

        - reset the Tx FIFO, to guarantee all pointers at zero
        - hook the Tx available interrupt with an interrupt handler (optional)
        - write 512 words of data into the Tx FIFO, filling it to the max
        - if the CODEC is not yet requesting data and unmuted, unmute and initiate reception
        - enable the Tx FIFO to run
        - poll or wait for interrupt; upon interrupt, write `fifo_depth` words. Repeat.
        - to close stream, mute the DAC and stop the request clock. Ideally, this can be completed
          before the FIFO is emptied, so there is no jarring pop or truncation of data
        - stop FIFO running. Next initiation should reset the FIFO to ensure leftover previous data
          in FIFO is cleared.

        CODEC Interface
        ---------------

        The interface assumes we have a sysclk domain running around 100MHz, and that our typical max
        audio rate is 44.1kHz * 24bits * 2channels = 2.1168MHz audio clock. Thus, the architecture
        treats the audio clock and data as asynchronous inputs that are MultiReg-syncd into the clock
        domain. Probably the slowest sysclk rate this might work with is around 20-25MHz (10x over
        sampling), but at 100MHz things will be quite comfortable.

        The upside of the fully asynchronous implementation is that we can leave the I/O unconstrained,
        giving the place/route more latitude to do its job.

        Here's the timing format targeted by this I2S interface:

            .. wavedrom::
                :caption: Timing format of the I2S interface

                { "signal" : [
                  { "name": "clk",         "wave": "n....|.......|......" },
                  { "name": "sync",        "wave": "1.0..|....1..|....0." },
                  { "name": "tx/rx",       "wave": ".====|==x.===|==x.=x", "data":
                  ["L15", "L14", "...", "L1", "L0", "R15", "R14", "...", "R1", "R0", "L15"] },
                ]}

        - Data is updated on the falling edge
        - Data is sampled on the rising edge
        - Words are MSB-to-LSB,  
        - Sync is an input or output based on configure mode,
        - Sync can be longer than the wordlen, extra bits are just ignored
        - Tx is data to the codec (SDI pin on LM49352)
        - Rx is data from the codec (SDO pin on LM49352)
        """)

        # One cache line is 8 32-bit words, need to always have enough space for one line or else
        # nothing works
        if fifo_depth > 504:
            fifo_depth = 504
            print(
                "I2S warning: fifo depth greater than 504 selected; truncating to 504"
            )
        if fifo_depth < 8:
            fifo_depth = 8
            print(
                "I2S warning: fifo depth less than 8 selected; truncating to 8"
            )
        if sample_width > 32:
            sample_width = 32
            print(
                "I2S warning: sample width greater than 32 bits. truncating to 32"
            )

        # Connect pins, synchronizers, and edge detectors
        if hasattr(pads, 'tx'):
            tx_pin = Signal()
            self.comb += pads.tx.eq(tx_pin)
        if hasattr(pads, 'rx'):
            rx_pin = Signal()
            self.specials += MultiReg(pads.rx, rx_pin)

        fifo_data_width = sample_width
        if concatenate_channels:
            if sample_width <= 16:
                fifo_data_width = sample_width * 2
            else:
                concatenate_channels = False
                print(
                    "I2S warning: sample width greater than 16 bits. your channels can't be glued"
                )

        sync_pin = Signal()
        self.specials += MultiReg(pads.sync, sync_pin)

        clk_pin = Signal()
        self.specials += MultiReg(pads.clk, clk_pin)
        clk_d = Signal()
        self.sync += clk_d.eq(clk_pin)
        rising_edge = Signal()
        falling_edge = Signal()
        self.comb += [
            rising_edge.eq(clk_pin & ~clk_d),
            falling_edge.eq(~clk_pin & clk_d)
        ]

        # Wishbone bus
        self.bus = bus = wishbone.Interface()
        rd_ack = Signal()
        wr_ack = Signal()
        self.comb += [
            If(
                bus.we,
                bus.ack.eq(wr_ack),
            ).Else(bus.ack.eq(rd_ack), )
        ]

        if controller == True:
            if bits_per_channel < sample_width and frame_format == I2S_FORMAT.I2S_STANDARD:
                bits_per_channel = sample_width + 1
                print(
                    "I2S warning: bits per channel can't be smaller than sample_width. Setting bits per channel to {}"
                    .format(sample_width + 1))
            # implementing LRCK signal
            lrck_period = int(lrck_ref_freq / (lrck_freq * 2))
            lrck_counter = Signal(16)
            self.sync += [
                If(
                    (lrck_counter == lrck_period),
                    lrck_counter.eq(0),
                    pads.sync.eq(~pads.sync),
                ).Else(lrck_counter.eq(lrck_counter + 1))
            ]
            # implementing SCLK signal
            sclk_period = int(lrck_period / (bits_per_channel * 2))
            sclk_counter = Signal(16)
            self.sync += [
                If(
                    (sclk_counter == sclk_period),
                    sclk_counter.eq(0),
                    pads.clk.eq(~pads.clk),
                ).Else(sclk_counter.eq(sclk_counter + 1))
            ]

        # Interrupts
        self.submodules.ev = EventManager()
        if hasattr(pads, 'rx'):
            self.ev.rx_ready = EventSourcePulse(
                description="Indicates FIFO is ready to read"
            )  # Rising edge triggered
            self.ev.rx_error = EventSourcePulse(
                description=
                "Indicates an Rx error has happened (over/underflow)")
        if hasattr(pads, 'tx'):
            self.ev.tx_ready = EventSourcePulse(
                description=
                "Indicates enough space available for next Tx quanta of {} words"
                .format(fifo_depth))
            self.ev.tx_error = EventSourcePulse(
                description="Indicates a Tx error has happened (over/underflow"
            )
        self.ev.finalize()

        # build the RX subsystem
        if hasattr(pads, 'rx'):
            rx_rd_d = Signal(fifo_data_width)
            rx_almostfull = Signal()
            rx_almostempty = Signal()
            rx_full = Signal()
            rx_empty = Signal()
            rx_rdcount = Signal(9)
            rx_rderr = Signal()
            rx_wrerr = Signal()
            rx_wrcount = Signal(9)
            rx_rden = Signal()
            rx_wr_d = Signal(fifo_data_width)
            rx_wren = Signal()

            self.rx_ctl = CSRStorage(
                description="Rx data path control",
                fields=[
                    CSRField("enable",
                             size=1,
                             description="Enable the receiving data"),
                    CSRField(
                        "reset",
                        size=1,
                        description=
                        "Writing `1` resets the FIFO. Reset happens regardless of enable state.",
                        pulse=1)
                ])
            self.rx_stat = CSRStatus(
                description="Rx data path status",
                fields=[
                    CSRField("overflow", size=1, description="Rx overflow"),
                    CSRField("underflow", size=1, description="Rx underflow"),
                    CSRField(
                        "dataready",
                        size=1,
                        description="{} words of data loaded and ready to read"
                        .format(fifo_depth)),
                    CSRField("empty",
                             size=1,
                             description="No data available in FIFO to read"
                             ),  # next flags probably never used
                    CSRField("wrcount", size=9, description="Write count"),
                    CSRField("rdcount", size=9, description="Read count"),
                    CSRField("fifo_depth",
                             size=9,
                             description="FIFO depth as synthesized"),
                    CSRField(
                        "concatenate_channels",
                        size=1,
                        reset=concatenate_channels,
                        description="Receive and send both channels atomically"
                    )
                ])
            self.rx_conf = CSRStatus(
                description="Rx configuration",
                fields=[
                    CSRField(
                        "format",
                        size=2,
                        reset=frame_format.value,
                        description=
                        "I2S sample format. {} is left-justified, {} is I2S standard"
                        .format(I2S_FORMAT.I2S_LEFT_JUSTIFIED,
                                I2S_FORMAT.I2S_STANDARD)),
                    CSRField("sample_width",
                             size=6,
                             reset=sample_width,
                             description="Single sample width"),
                    CSRField("lrck_freq",
                             size=24,
                             reset=lrck_freq,
                             description="Audio sampling rate frequency"),
                ])
            self.comb += self.rx_stat.fields.fifo_depth.eq(fifo_depth)

            rx_rst_cnt = Signal(3)
            rx_reset = Signal()
            self.sync += [
                If(
                    self.rx_ctl.fields.reset,
                    rx_rst_cnt.eq(5),  # 5 cycles reset required by design
                    rx_reset.eq(1)).Else(
                        If(rx_rst_cnt == 0,
                           rx_reset.eq(0)).Else(rx_rst_cnt.eq(rx_rst_cnt - 1),
                                                rx_reset.eq(1)))
            ]

            # At a width of 32 bits, an 18kiB fifo is 512 entries deep
            self.specials += Instance(
                "FIFO_SYNC_MACRO",
                p_DEVICE="7SERIES",
                p_FIFO_SIZE="18Kb",
                p_DATA_WIDTH=fifo_data_width,
                p_ALMOST_EMPTY_OFFSET=8,
                p_ALMOST_FULL_OFFSET=(512 - fifo_depth),
                p_DO_REG=0,
                i_CLK=ClockSignal(),
                i_RST=rx_reset,
                o_ALMOSTFULL=rx_almostfull,
                o_ALMOSTEMPTY=rx_almostempty,
                o_FULL=rx_full,
                o_EMPTY=rx_empty,
                i_WREN=rx_wren & ~rx_reset,
                i_DI=rx_wr_d,
                i_RDEN=rx_rden & ~rx_reset,
                o_DO=rx_rd_d,
                o_RDCOUNT=rx_rdcount,
                o_RDERR=rx_rderr,
                o_WRCOUNT=rx_wrcount,
                o_WRERR=rx_wrerr,
            )
            self.comb += [  # Wire up the status signals and interrupts
                self.rx_stat.fields.underflow.eq(rx_rderr),
                self.rx_stat.fields.dataready.eq(rx_almostfull),
                self.rx_stat.fields.wrcount.eq(rx_wrcount),
                self.rx_stat.fields.rdcount.eq(rx_rdcount),
                self.ev.rx_ready.trigger.eq(rx_almostfull),
                self.ev.rx_error.trigger.eq(rx_wrerr | rx_rderr),
            ]
            bus_read = Signal()
            bus_read_d = Signal()
            rd_ack_pipe = Signal()
            self.comb += bus_read.eq(bus.cyc & bus.stb & ~bus.we
                                     & (bus.cti == 0))
            self.sync += [  # This is the bus responder -- only works for uncached memory regions
                bus_read_d.eq(bus_read),
                If(
                    bus_read & ~bus_read_d,  # One response, one cycle
                    rd_ack_pipe.eq(1),
                    If(
                        ~rx_empty,
                        bus.dat_r.eq(rx_rd_d),
                        rx_rden.eq(1),
                    ).Else(
                        # Don't stall the bus indefinitely if we try to read from an empty fifo...just
                        # return garbage
                        bus.dat_r.eq(0xdeadbeef),
                        rx_rden.eq(0),
                    )).Else(
                        rx_rden.eq(0),
                        rd_ack_pipe.eq(0),
                    ),
                rd_ack.eq(rd_ack_pipe),
            ]
            rx_cnt_width = math.ceil(math.log(fifo_data_width, 2))
            rx_cnt = Signal(rx_cnt_width)
            rx_delay_cnt = Signal()
            rx_delay_val = 1 if frame_format == I2S_FORMAT.I2S_STANDARD else 0

            self.submodules.rxi2s = rxi2s = FSM(reset_state="IDLE")
            rxi2s.act(
                "IDLE",
                NextValue(rx_wr_d, 0),
                If(
                    self.rx_ctl.fields.enable,
                    # Wait_sync guarantees we start at the beginning of a left frame, and not in
                    # the middle
                    If(
                        rising_edge &
                        (~sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD
                         else sync_pin), NextState("WAIT_SYNC"),
                        NextValue(rx_delay_cnt, rx_delay_val)))),
            rxi2s.act(
                "WAIT_SYNC",
                If(
                    rising_edge & (~sync_pin if frame_format
                                   == I2S_FORMAT.I2S_STANDARD else sync_pin),
                    If(rx_delay_cnt > 0,
                       NextValue(rx_delay_cnt, rx_delay_cnt - 1),
                       NextState("WAIT_SYNC")).Else(
                           NextState("LEFT"),
                           NextValue(rx_delay_cnt, rx_delay_val),
                           NextValue(rx_cnt, sample_width))),
            )
            rxi2s.act(
                "LEFT",
                If(~self.rx_ctl.fields.enable, NextState("IDLE")).Else(
                    NextValue(rx_wr_d, Cat(rx_pin, rx_wr_d[:-1])),
                    NextValue(rx_cnt, rx_cnt - 1), NextState("LEFT_WAIT")))
            if concatenate_channels:
                rxi2s.act(
                    "LEFT_WAIT",
                    If(~self.rx_ctl.fields.enable, NextState("IDLE")).Else(
                        If(
                            rising_edge,
                            If((rx_cnt == 0),
                               If((sync_pin if frame_format
                                   == I2S_FORMAT.I2S_STANDARD else ~sync_pin),
                                  If(
                                      rx_delay_cnt == 0,
                                      NextValue(rx_cnt, sample_width),
                                      NextValue(rx_delay_cnt, rx_delay_val),
                                      NextState("RIGHT"),
                                  ).Else(
                                      NextValue(rx_delay_cnt,
                                                rx_delay_cnt - 1),
                                      NextState("LEFT_WAIT"))).Else(
                                          NextState("LEFT_WAIT"))).Elif(
                                              rx_cnt > 0, NextState("LEFT")))))
            else:
                rxi2s.act(
                    "LEFT_WAIT",
                    If(~self.rx_ctl.fields.enable, NextState("IDLE")).Else(
                        If(
                            rising_edge,
                            If(
                                (rx_cnt == 0),
                                If(
                                    (sync_pin
                                     if frame_format == I2S_FORMAT.I2S_STANDARD
                                     else ~sync_pin),
                                    If(
                                        rx_delay_cnt == 0,
                                        NextValue(rx_cnt, sample_width),
                                        NextValue(rx_delay_cnt, rx_delay_val),
                                        NextState("RIGHT"),
                                        rx_wren.eq(
                                            1
                                        )  # Pulse rx_wren to write the current data word
                                    ).Else(
                                        NextValue(rx_delay_cnt,
                                                  rx_delay_cnt - 1),
                                        NextState("LEFT_WAIT"))).Else(
                                            NextState("LEFT_WAIT"))).Elif(
                                                rx_cnt > 0,
                                                NextState("LEFT")))))

            rxi2s.act(
                "RIGHT",
                If(~self.rx_ctl.fields.enable, NextState("IDLE")).Else(
                    NextValue(rx_wr_d, Cat(rx_pin, rx_wr_d[:-1])),
                    NextValue(rx_cnt, rx_cnt - 1), NextState("RIGHT_WAIT")))
            rxi2s.act(
                "RIGHT_WAIT",
                If(~self.rx_ctl.fields.enable, NextState("IDLE")).Else(
                    If(
                        rising_edge,
                        If(
                            (rx_cnt == 0) &
                            (~sync_pin if frame_format
                             == I2S_FORMAT.I2S_STANDARD else sync_pin),
                            If(
                                rx_delay_cnt == 0,
                                NextValue(rx_cnt, sample_width),
                                NextValue(rx_delay_cnt, rx_delay_val),
                                NextState("LEFT"),
                                rx_wren.eq(
                                    1
                                )  # Pulse rx_wren to write the current data word
                            ).Else(NextValue(rx_delay_cnt, rx_delay_cnt - 1),
                                   NextState("RIGHT_WAIT"))).Elif(
                                       rx_cnt > 0, NextState("RIGHT")))))

        # Build the TX subsystem
        if hasattr(pads, 'tx'):
            tx_rd_d = Signal(fifo_data_width)
            tx_almostfull = Signal()
            tx_almostempty = Signal()
            tx_full = Signal()
            tx_empty = Signal()
            tx_rdcount = Signal(9)
            tx_rderr = Signal()
            tx_wrerr = Signal()
            tx_wrcount = Signal(9)
            tx_rden = Signal()
            tx_wr_d = Signal(fifo_data_width)
            tx_wren = Signal()

            self.tx_ctl = CSRStorage(
                description="Tx data path control",
                fields=[
                    CSRField("enable",
                             size=1,
                             description="Enable the transmission data"),
                    CSRField(
                        "reset",
                        size=1,
                        description=
                        "Writing `1` resets the FIFO. Reset happens regardless of enable state.",
                        pulse=1)
                ])
            self.tx_stat = CSRStatus(
                description="Tx data path status",
                fields=[
                    CSRField("overflow", size=1, description="Tx overflow"),
                    CSRField("underflow", size=1, description="Tx underflow"),
                    CSRField(
                        "free",
                        size=1,
                        description="At least {} words of space free".format(
                            fifo_depth)),
                    CSRField("almostfull",
                             size=1,
                             description="Less than 8 words space available"
                             ),  # the next few flags should be rarely used
                    CSRField("full",
                             size=1,
                             description="FIFO is full or overfull"),
                    CSRField("empty", size=1, description="FIFO is empty"),
                    CSRField("wrcount", size=9, description="Tx write count"),
                    CSRField("rdcount", size=9, description="Tx read count"),
                    CSRField(
                        "concatenate_channels",
                        size=1,
                        reset=concatenate_channels,
                        description="Receive and send both channels atomically"
                    )
                ])
            self.tx_conf = CSRStatus(
                description="TX configuration",
                fields=[
                    CSRField(
                        "format",
                        size=2,
                        reset=frame_format.value,
                        description=
                        "I2S sample format. {} is left-justified, {} is I2S standard"
                        .format(I2S_FORMAT.I2S_LEFT_JUSTIFIED,
                                I2S_FORMAT.I2S_STANDARD)),
                    CSRField("sample_width",
                             size=6,
                             reset=sample_width,
                             description="Single sample width"),
                    CSRField("lrck_freq",
                             size=24,
                             reset=lrck_freq,
                             description="Audio sampling rate frequency"),
                ])

            tx_rst_cnt = Signal(3)
            tx_reset = Signal()
            self.sync += [
                If(
                    self.tx_ctl.fields.reset,
                    tx_rst_cnt.eq(5),  # 5 cycles reset required by design
                    tx_reset.eq(1)).Else(
                        If(tx_rst_cnt == 0,
                           tx_reset.eq(0)).Else(tx_rst_cnt.eq(tx_rst_cnt - 1),
                                                tx_reset.eq(1)))
            ]

            # At a width of 32 bits, an 18kiB fifo is 512 entries deep
            self.specials += Instance(
                "FIFO_SYNC_MACRO",
                p_DEVICE="7SERIES",
                p_FIFO_SIZE="18Kb",
                p_DATA_WIDTH=fifo_data_width,
                p_ALMOST_EMPTY_OFFSET=fifo_depth,
                p_ALMOST_FULL_OFFSET=8,
                p_DO_REG=0,
                i_CLK=ClockSignal(),
                i_RST=tx_reset,
                o_ALMOSTFULL=tx_almostfull,
                o_ALMOSTEMPTY=tx_almostempty,
                o_FULL=tx_full,
                o_EMPTY=tx_empty,
                i_WREN=tx_wren & ~tx_reset,
                i_DI=tx_wr_d,
                i_RDEN=tx_rden & ~tx_reset,
                o_DO=tx_rd_d,
                o_RDCOUNT=tx_rdcount,
                o_RDERR=tx_rderr,
                o_WRCOUNT=tx_wrcount,
                o_WRERR=tx_wrerr,
            )

            self.comb += [  # Wire up the status signals and interrupts
                self.tx_stat.fields.underflow.eq(tx_rderr),
                self.tx_stat.fields.free.eq(tx_almostempty),
                self.tx_stat.fields.almostfull.eq(tx_almostfull),
                self.tx_stat.fields.full.eq(tx_full),
                self.tx_stat.fields.empty.eq(tx_empty),
                self.tx_stat.fields.rdcount.eq(tx_rdcount),
                self.tx_stat.fields.wrcount.eq(tx_wrcount),
                self.ev.tx_ready.trigger.eq(tx_almostempty),
                self.ev.tx_error.trigger.eq(tx_wrerr | tx_rderr),
            ]
            self.sync += [
                # This is the bus responder -- need to check how this interacts with uncached memory
                # region
                If(
                    bus.cyc & bus.stb & bus.we & ~bus.ack,
                    If(
                        ~tx_full,
                        tx_wr_d.eq(bus.dat_w),
                        tx_wren.eq(1),
                        wr_ack.eq(1),
                    ).Else(
                        tx_wren.eq(0),
                        wr_ack.eq(0),
                    )).Else(
                        tx_wren.eq(0),
                        wr_ack.eq(0),
                    )
            ]

            tx_buf_width = fifo_data_width + 1 if frame_format == I2S_FORMAT.I2S_STANDARD else fifo_data_width
            sample_width = sample_width + 1 if frame_format == I2S_FORMAT.I2S_STANDARD else sample_width
            offset = [0] if frame_format == I2S_FORMAT.I2S_STANDARD else []

            tx_cnt_width = math.ceil(math.log(fifo_data_width, 2))
            tx_cnt = Signal(tx_cnt_width)
            tx_buf = Signal(tx_buf_width)
            sample_msb = fifo_data_width - 1
            self.submodules.txi2s = txi2s = FSM(reset_state="IDLE")
            txi2s.act(
                "IDLE",
                If(
                    self.tx_ctl.fields.enable,
                    If(
                        falling_edge &
                        (~sync_pin if frame_format == I2S_FORMAT.I2S_STANDARD
                         else sync_pin),
                        NextState("WAIT_SYNC"),
                    ))),
            txi2s.act(
                "WAIT_SYNC",
                If(
                    falling_edge & (~sync_pin if frame_format
                                    == I2S_FORMAT.I2S_STANDARD else sync_pin),
                    NextState("LEFT"),
                    NextValue(tx_cnt, sample_width),
                    NextValue(tx_buf, Cat(tx_rd_d, offset)),
                    tx_rden.eq(1),
                ))
            txi2s.act(
                "LEFT",
                If(~self.tx_ctl.fields.enable, NextState("IDLE")).Else(
                    NextValue(tx_pin, tx_buf[sample_msb]),
                    NextValue(tx_buf, Cat(0, tx_buf[:-1])),
                    NextValue(tx_cnt, tx_cnt - 1), NextState("LEFT_WAIT")))
            if concatenate_channels:
                txi2s.act(
                    "LEFT_WAIT",
                    If(~self.tx_ctl.fields.enable, NextState("IDLE")).Else(
                        If(
                            falling_edge,
                            If((tx_cnt == 0),
                               If(
                                   (sync_pin if frame_format
                                    == I2S_FORMAT.I2S_STANDARD else ~sync_pin),
                                   NextValue(tx_cnt, sample_width),
                                   NextState("RIGHT"),
                               ).Else(NextState("LEFT_WAIT"), )).Elif(
                                   tx_cnt > 0,
                                   NextState("LEFT"),
                               ))))
            else:
                txi2s.act(
                    "LEFT_WAIT",
                    If(~self.tx_ctl.fields.enable, NextState("IDLE")).Else(
                        If(
                            falling_edge,
                            If((tx_cnt == 0),
                               If(
                                   (sync_pin if frame_format
                                    == I2S_FORMAT.I2S_STANDARD else ~sync_pin),
                                   NextValue(tx_cnt, sample_width),
                                   NextState("RIGHT"),
                                   NextValue(tx_buf, Cat(tx_rd_d, offset)),
                                   tx_rden.eq(1),
                               ).Else(NextState("LEFT_WAIT"), )).Elif(
                                   tx_cnt > 0,
                                   NextState("LEFT"),
                               ))))

            txi2s.act(
                "RIGHT",
                If(~self.tx_ctl.fields.enable, NextState("IDLE")).Else(
                    NextValue(tx_pin, tx_buf[sample_msb]),
                    NextValue(tx_buf, Cat(0, tx_buf[:-1])),
                    NextValue(tx_cnt, tx_cnt - 1), NextState("RIGHT_WAIT")))
            txi2s.act(
                "RIGHT_WAIT",
                If(~self.tx_ctl.fields.enable, NextState("IDLE")).Else(
                    If(
                        falling_edge,
                        If((tx_cnt == 0) &
                           (~sync_pin if frame_format
                            == I2S_FORMAT.I2S_STANDARD else sync_pin),
                           NextValue(tx_cnt, sample_width), NextState("LEFT"),
                           NextValue(tx_buf, Cat(tx_rd_d, offset)),
                           tx_rden.eq(1)).Elif(tx_cnt > 0,
                                               NextState("RIGHT")))))
 def __init__(self, signal):
     self._in = CSRStatus(len(signal))
     self.specials += MultiReg(signal, self._in.status)
示例#18
0
    def __init__(self, sys_clk_freq):
        self.done = Signal()
        self.restart = Signal()

        # GTP signals
        self.plllock = Signal()
        self.pllreset = Signal()
        self.gttxreset = Signal()
        self.txresetdone = Signal()
        self.txdlysreset = Signal()
        self.txdlysresetdone = Signal()
        self.txphinit = Signal()
        self.txphinitdone = Signal()
        self.txphalign = Signal()
        self.txphaligndone = Signal()
        self.txdlyen = Signal()
        self.txuserrdy = Signal()

        # # #

        # Double-latch transceiver asynch outputs
        plllock = Signal()
        txresetdone = Signal()
        txdlysresetdone = Signal()
        txphinitdone = Signal()
        txphaligndone = Signal()
        self.specials += [
            MultiReg(self.plllock, plllock),
            MultiReg(self.txresetdone, txresetdone),
            MultiReg(self.txdlysresetdone, txdlysresetdone),
            MultiReg(self.txphinitdone, txphinitdone),
            MultiReg(self.txphaligndone, txphaligndone)
        ]

        # Deglitch FSM outputs driving transceiver asynch inputs
        gttxreset = Signal()
        txdlysreset = Signal()
        txphinit = Signal()
        txphalign = Signal()
        txdlyen = Signal()
        txuserrdy = Signal()
        self.sync += [
            self.gttxreset.eq(gttxreset),
            self.txdlysreset.eq(txdlysreset),
            self.txphinit.eq(txphinit),
            self.txphalign.eq(txphalign),
            self.txdlyen.eq(txdlyen),
            self.txuserrdy.eq(txuserrdy)
        ]

        # PLL reset must be at least 500us
        pll_reset_cycles = ceil(500e-9 * sys_clk_freq)
        pll_reset_timer = WaitTimer(pll_reset_cycles)
        self.submodules += pll_reset_timer

        startup_fsm = ResetInserter()(FSM(reset_state="PLL_RESET"))
        self.submodules += startup_fsm

        ready_timer = WaitTimer(int(1e-3 * sys_clk_freq))
        self.submodules += ready_timer
        self.comb += [
            ready_timer.wait.eq(~self.done & ~startup_fsm.reset),
            startup_fsm.reset.eq(self.restart | ready_timer.done)
        ]

        txphaligndone_r = Signal(reset=1)
        txphaligndone_rising = Signal()
        self.sync += txphaligndone_r.eq(txphaligndone)
        self.comb += txphaligndone_rising.eq(txphaligndone & ~txphaligndone_r)

        startup_fsm.act("PLL_RESET", self.pllreset.eq(1),
                        pll_reset_timer.wait.eq(1),
                        If(pll_reset_timer.done, NextState("GTP_RESET")))
        startup_fsm.act("GTP_RESET", gttxreset.eq(1),
                        If(plllock, NextState("WAIT_GTP_RESET_DONE")))
        # Release GTP reset and wait for GTP resetdone
        # (from UG482, GTP is reset on falling edge
        # of gttxreset)
        startup_fsm.act("WAIT_GTP_RESET_DONE", txuserrdy.eq(1),
                        If(txresetdone, NextState("ALIGN")))
        # Start delay alignment
        startup_fsm.act("ALIGN", txuserrdy.eq(1), txdlysreset.eq(1),
                        If(txdlysresetdone, NextState("PHALIGN")))
        # Start phase alignment
        startup_fsm.act("PHALIGN", txuserrdy.eq(1), txphinit.eq(1),
                        If(txphinitdone, NextState("WAIT_FIRST_ALIGN_DONE")))
        # Wait 2 rising edges of Xxphaligndone
        # (from UG482 in TX Buffer Bypass in Single-Lane Auto Mode)
        startup_fsm.act(
            "WAIT_FIRST_ALIGN_DONE", txuserrdy.eq(1), txphalign.eq(1),
            If(txphaligndone_rising, NextState("WAIT_SECOND_ALIGN_DONE")))
        startup_fsm.act("WAIT_SECOND_ALIGN_DONE", txuserrdy.eq(1),
                        txdlyen.eq(1),
                        If(txphaligndone_rising, NextState("READY")))
        startup_fsm.act("READY", txuserrdy.eq(1), self.done.eq(1),
                        If(self.restart, NextState("PLL_RESET")))
示例#19
0
    def __init__(self,
                 platform,
                 pads,
                 data_width=64,
                 bar0_size=1 * MB,
                 cd="sys",
                 pcie_data_width=64):
        # Streams ----------------------------------------------------------------------------------
        self.sink = stream.Endpoint(phy_layout(data_width))
        self.source = stream.Endpoint(phy_layout(data_width))
        self.msi = stream.Endpoint(msi_layout())

        # Registers --------------------------------------------------------------------------------
        self._link_up = CSRStatus(
            description="Link Up Status. ``1``: Link is Up.")
        self._msi_enable = CSRStatus(
            description="MSI Enable Status. ``1``: MSI is enabled.")
        self._bus_master_enable = CSRStatus(
            description="Bus Mastering Status. ``1``: Bus Mastering enabled.")
        self._max_request_size = CSRStatus(
            16, description="Negiotiated Max Request Size (in bytes).")
        self._max_payload_size = CSRStatus(
            16, description="Negiotiated Max Payload Size (in bytes).")

        # Parameters/Locals ------------------------------------------------------------------------
        self.platform = platform
        self.data_width = data_width
        self.pcie_data_width = pcie_data_width

        self.id = Signal(16)
        self.bar0_size = bar0_size
        self.bar0_mask = get_bar_mask(bar0_size)
        self.max_request_size = Signal(16)
        self.max_payload_size = Signal(16)

        self.external_hard_ip = False

        # # #

        self.nlanes = nlanes = len(pads.tx_p)

        assert nlanes in [1, 2, 4]
        assert data_width in [64, 128]
        assert pcie_data_width in [64, 128]

        # Clocking ---------------------------------------------------------------------------------
        pcie_refclk = Signal()
        self.specials += Instance("IBUFDS_GTE2",
                                  i_CEB=0,
                                  i_I=pads.clk_p,
                                  i_IB=pads.clk_n,
                                  o_O=pcie_refclk)
        platform.add_period_constraint(pads.clk_p, 1e9 / 100e6)
        self.clock_domains.cd_pcie = ClockDomain()
        pcie_clk_freq = max(125e6, nlanes * 62.5e6 * 64 / pcie_data_width)
        platform.add_period_constraint(self.cd_pcie.clk, 1e9 / pcie_clk_freq)

        # TX (FPGA --> HOST) CDC / Data Width Convertion -------------------------------------------
        if (cd == "pcie") and (data_width == pcie_data_width):
            s_axis_tx = self.sink
        else:
            tx_pipe_valid = stream.PipeValid(phy_layout(data_width))
            tx_pipe_valid = ClockDomainsRenamer(cd)(tx_pipe_valid)
            tx_cdc = stream.AsyncFIFO(phy_layout(data_width), 4)
            tx_cdc = ClockDomainsRenamer({"write": cd, "read": "pcie"})(tx_cdc)
            tx_converter = stream.StrideConverter(phy_layout(data_width),
                                                  phy_layout(pcie_data_width))
            tx_converter = ClockDomainsRenamer("pcie")(tx_converter)
            tx_pipe_ready = stream.PipeValid(phy_layout(pcie_data_width))
            tx_pipe_ready = ClockDomainsRenamer("pcie")(tx_pipe_ready)
            self.submodules += tx_pipe_valid, tx_cdc, tx_converter, tx_pipe_ready
            self.comb += [
                self.sink.connect(tx_pipe_valid.sink),
                tx_pipe_valid.source.connect(tx_cdc.sink),
                tx_cdc.source.connect(tx_converter.sink),
                tx_converter.source.connect(tx_pipe_ready.sink)
            ]
            s_axis_tx = tx_pipe_ready.source

        # RX (HOST --> FPGA) CDC / Data Width Convertion -------------------------------------------
        if (cd == "pcie") and (data_width == pcie_data_width):
            m_axis_rx = self.source
        else:
            rx_pipe_ready = stream.PipeReady(phy_layout(pcie_data_width))
            rx_pipe_ready = ClockDomainsRenamer("pcie")(rx_pipe_ready)
            rx_converter = stream.StrideConverter(phy_layout(pcie_data_width),
                                                  phy_layout(data_width))
            rx_converter = ClockDomainsRenamer("pcie")(rx_converter)
            rx_cdc = stream.AsyncFIFO(phy_layout(data_width), 4)
            rx_cdc = ClockDomainsRenamer({"write": "pcie", "read": cd})(rx_cdc)
            rx_pipe_valid = stream.PipeValid(phy_layout(data_width))
            rx_pipe_valid = ClockDomainsRenamer(cd)(rx_pipe_valid)
            self.submodules += rx_pipe_ready, rx_converter, rx_pipe_valid, rx_cdc
            self.comb += [
                rx_pipe_ready.source.connect(rx_converter.sink),
                rx_converter.source.connect(rx_cdc.sink),
                rx_cdc.source.connect(rx_pipe_valid.sink),
                rx_pipe_valid.source.connect(self.source),
            ]
            m_axis_rx = rx_pipe_ready.sink
        if pcie_data_width == 128:
            rx_aligner = AXISRX128BAligner()
            rx_aligner = ClockDomainsRenamer("pcie")(rx_aligner)
            self.submodules += rx_aligner
            self.comb += rx_aligner.source.connect(m_axis_rx)
            m_axis_rx = rx_aligner.sink

        # MSI CDC (FPGA --> HOST) ------------------------------------------------------------------
        if cd == "pcie":
            cfg_msi = self.msi
        else:
            msi_cdc = stream.AsyncFIFO(msi_layout(), 4)
            msi_cdc = ClockDomainsRenamer({
                "write": cd,
                "read": "pcie"
            })(msi_cdc)
            self.submodules += msi_cdc
            self.comb += self.msi.connect(msi_cdc.sink)
            cfg_msi = msi_cdc.source

        # Hard IP Configuration --------------------------------------------------------------------
        def convert_size(command, size, max_size):
            cases = {}
            value = 128
            for i in range(6):
                cases[i] = size.eq(value)
                value = min(value * 2, max_size)
            return Case(command, cases)

        link_up = Signal()
        msi_enable = Signal()
        bus_number = Signal(8)
        device_number = Signal(5)
        function_number = Signal(3)
        command = Signal(16)
        dcommand = Signal(16)
        self.sync.pcie += [
            convert_size(dcommand[12:15], self.max_request_size, max_size=512),
            convert_size(dcommand[5:8], self.max_payload_size, max_size=512),
            self.id.eq(Cat(function_number, device_number, bus_number))
        ]
        self.specials += [
            MultiReg(link_up, self._link_up.status),
            MultiReg(command[2], self._bus_master_enable.status),
            MultiReg(msi_enable, self._msi_enable.status),
            MultiReg(self.max_request_size, self._max_request_size.status),
            MultiReg(self.max_payload_size, self._max_payload_size.status)
        ]

        # Hard IP ----------------------------------------------------------------------------------
        class Open(Signal):
            pass

        m_axis_rx_tlast = Signal()
        m_axis_rx_tuser = Signal(32)
        self.pcie_phy_params = dict(
            # Parameters ---------------------------------------------------------------------------
            p_LINK_CAP_MAX_LINK_WIDTH=nlanes,
            p_C_DATA_WIDTH=pcie_data_width,
            p_KEEP_WIDTH=pcie_data_width // 8,
            p_PCIE_REFCLK_FREQ=0,  # 100MHz refclk
            p_PCIE_USERCLK1_FREQ=3 if nlanes <= 2 else 4,
            p_PCIE_USERCLK2_FREQ=3 if (pcie_clk_freq == 125e6) else 4,
            p_PCIE_GT_DEVICE={
                "xc7a": "GTP",
                "xc7k": "GTX",
                "xc7v": "GTX"
            }[platform.device[:4]],
            p_PCIE_USE_MODE="1.0",

            # PCI Express Interface ----------------------------------------------------------------
            i_sys_clk=pcie_refclk,
            i_sys_rst_n=1 if not hasattr(pads, "rst_n") else pads.rst_n,
            # TX
            o_pci_exp_txp=pads.tx_p,
            o_pci_exp_txn=pads.tx_n,
            # RX
            i_pci_exp_rxp=pads.rx_p,
            i_pci_exp_rxn=pads.rx_n,

            # Clocking Sharing Interface -----------------------------------------------------------
            o_pipe_pclk_out_slave=Open(),
            o_pipe_rxusrclk_out=Open(),
            o_pipe_rxoutclk_out=Open(),
            o_pipe_dclk_out=Open(),
            o_pipe_userclk1_out=Open(),
            o_pipe_userclk2_out=Open(),
            o_pipe_oobclk_out=Open(),
            o_pipe_mmcm_lock_out=Open(),
            i_pipe_pclk_sel_slave=0b00,
            i_pipe_mmcm_rst_n=1,

            # AXI-S Interface ----------------------------------------------------------------------
            # Common
            o_user_clk_out=ClockSignal("pcie"),
            o_user_reset_out=ResetSignal("pcie"),
            o_user_lnk_up=link_up,
            o_user_app_rdy=Open(),

            # TX
            o_tx_buf_av=Open(),
            o_tx_err_drop=Open(),
            o_tx_cfg_req=Open(),
            i_tx_cfg_gnt=1,
            i_s_axis_tx_tvalid=s_axis_tx.valid,
            i_s_axis_tx_tlast=s_axis_tx.last,
            o_s_axis_tx_tready=s_axis_tx.ready,
            i_s_axis_tx_tdata=s_axis_tx.dat,
            i_s_axis_tx_tkeep=s_axis_tx.be,
            i_s_axis_tx_tuser=0,

            # RX
            i_rx_np_ok=1,
            i_rx_np_req=1,
            o_m_axis_rx_tvalid=m_axis_rx.valid,
            o_m_axis_rx_tlast=m_axis_rx_tlast,
            i_m_axis_rx_tready=m_axis_rx.ready,
            o_m_axis_rx_tdata=m_axis_rx.dat,
            o_m_axis_rx_tkeep=m_axis_rx.be,
            o_m_axis_rx_tuser=m_axis_rx_tuser,

            # Flow Control
            o_fc_cpld=Open(),
            o_fc_cplh=Open(),
            o_fc_npd=Open(),
            o_fc_nph=Open(),
            o_fc_pd=Open(),
            o_fc_ph=Open(),
            i_fc_sel=0,

            # Management Interface -----------------------------------------------------------------
            o_cfg_mgmt_do=Open(),
            o_cfg_mgmt_rd_wr_done=Open(),
            i_cfg_mgmt_di=0,
            i_cfg_mgmt_byte_en=0,
            i_cfg_mgmt_dwaddr=0,
            i_cfg_mgmt_wr_en=0,
            i_cfg_mgmt_rd_en=0,
            i_cfg_mgmt_wr_readonly=0,
            i_cfg_mgmt_wr_rw1c_as_rw=0,

            # Error Reporting Interface ------------------------------------------------------------
            i_cfg_err_ecrc=0,
            i_cfg_err_ur=0,
            i_cfg_err_cpl_timeout=0,
            i_cfg_err_cpl_unexpect=0,
            i_cfg_err_cpl_abort=0,
            i_cfg_err_posted=0,
            i_cfg_err_cor=0,
            i_cfg_err_atomic_egress_blocked=0,
            i_cfg_err_internal_cor=0,
            i_cfg_err_malformed=0,
            i_cfg_err_mc_blocked=0,
            i_cfg_err_poisoned=0,
            i_cfg_err_norecovery=0,
            i_cfg_err_tlp_cpl_header=0,
            o_cfg_err_cpl_rdy=Open(),
            i_cfg_err_locked=0,
            i_cfg_err_acs=0,
            i_cfg_err_internal_uncor=0,

            # AER interface ------------------------------------------------------------------------
            i_cfg_err_aer_headerlog=0,
            i_cfg_aer_interrupt_msgnum=0,
            o_cfg_err_aer_headerlog_set=Open(),
            o_cfg_aer_ecrc_check_en=Open(),
            o_cfg_aer_ecrc_gen_en=Open(),
            i_cfg_turnoff_ok=0,
            i_cfg_trn_pending=0,
            i_cfg_pm_halt_aspm_l0s=0,
            i_cfg_pm_halt_aspm_l1=0,
            i_cfg_pm_force_state_en=0,
            i_cfg_pm_force_state=0,
            i_cfg_dsn=0,
            i_cfg_pm_send_pme_to=0,
            i_cfg_ds_bus_number=0,
            i_cfg_ds_device_number=0,
            i_cfg_ds_function_number=0,
            i_cfg_pm_wake=0,

            # Interrupt Interface ------------------------------------------------------------------
            i_cfg_interrupt=cfg_msi.valid,
            o_cfg_interrupt_rdy=cfg_msi.ready,
            i_cfg_interrupt_assert=0,
            i_cfg_interrupt_di=cfg_msi.dat,
            o_cfg_interrupt_do=Open(),
            o_cfg_interrupt_mmenable=Open(),
            o_cfg_interrupt_msienable=msi_enable,
            o_cfg_interrupt_msixenable=Open(),
            o_cfg_interrupt_msixfm=Open(),
            i_cfg_interrupt_stat=0,
            i_cfg_pciecap_interrupt_msgnum=0,

            # Configuration Interface --------------------------------------------------------------
            o_cfg_status=Open(),
            o_cfg_command=command,
            o_cfg_dstatus=Open(),
            o_cfg_dcommand=dcommand,
            o_cfg_lstatus=Open(),
            o_cfg_lcommand=Open(),
            o_cfg_dcommand2=Open(),
            o_cfg_pcie_link_state=Open(),
            o_cfg_to_turnoff=Open(),
            o_cfg_bus_number=bus_number,
            o_cfg_device_number=device_number,
            o_cfg_function_number=function_number,
            o_cfg_pmcsr_pme_en=Open(),
            o_cfg_pmcsr_powerstate=Open(),
            o_cfg_pmcsr_pme_status=Open(),
            o_cfg_received_func_lvl_rst=Open(),
            o_cfg_bridge_serr_en=Open(),
            o_cfg_slot_control_electromech_il_ctl_pulse=Open(),
            o_cfg_root_control_syserr_corr_err_en=Open(),
            o_cfg_root_control_syserr_non_fatal_err_en=Open(),
            o_cfg_root_control_syserr_fatal_err_en=Open(),
            o_cfg_root_control_pme_int_en=Open(),
            o_cfg_aer_rooterr_corr_err_reporting_en=Open(),
            o_cfg_aer_rooterr_non_fatal_err_reporting_en=Open(),
            o_cfg_aer_rooterr_fatal_err_reporting_en=Open(),
            o_cfg_aer_rooterr_corr_err_received=Open(),
            o_cfg_aer_rooterr_non_fatal_err_received=Open(),
            o_cfg_aer_rooterr_fatal_err_received=Open(),

            # VC Interface -------------------------------------------------------------------------
            o_cfg_vc_tcvc_map=Open(),
            o_cfg_msg_received=Open(),
            o_cfg_msg_data=Open(),
            o_cfg_msg_received_pm_as_nak=Open(),
            o_cfg_msg_received_setslotpowerlimit=Open(),
            o_cfg_msg_received_err_cor=Open(),
            o_cfg_msg_received_err_non_fatal=Open(),
            o_cfg_msg_received_err_fatal=Open(),
            o_cfg_msg_received_pm_pme=Open(),
            o_cfg_msg_received_pme_to_ack=Open(),
            o_cfg_msg_received_assert_int_a=Open(),
            o_cfg_msg_received_assert_int_b=Open(),
            o_cfg_msg_received_assert_int_c=Open(),
            o_cfg_msg_received_assert_int_d=Open(),
            o_cfg_msg_received_deassert_int_a=Open(),
            o_cfg_msg_received_deassert_int_b=Open(),
            o_cfg_msg_received_deassert_int_c=Open(),
            o_cfg_msg_received_deassert_int_d=Open(),

            # Physical Layer Interface -------------------------------------------------------------
            i_pl_directed_link_change=0,
            i_pl_directed_link_width=0,
            i_pl_directed_link_speed=0,
            i_pl_directed_link_auton=0,
            i_pl_upstream_prefer_deemph=1,
            o_pl_sel_lnk_rate=Open(),
            o_pl_sel_lnk_width=Open(),
            o_pl_ltssm_state=Open(),
            o_pl_lane_reversal_mode=Open(),
            o_pl_phy_lnk_up=Open(),
            o_pl_tx_pm_state=Open(),
            o_pl_rx_pm_state=Open(),
            o_pl_link_upcfg_cap=Open(),
            o_pl_link_gen2_cap=Open(),
            o_pl_link_partner_gen2_supported=Open(),
            o_pl_initial_link_width=Open(),
            o_pl_directed_change_done=Open(),
            o_pl_received_hot_rst=Open(),
            i_pl_transmit_hot_rst=0,
            i_pl_downstream_deemph_source=0,

            # PCIe DRP Interface -------------------------------------------------------------------
            i_pcie_drp_clk=1,
            i_pcie_drp_en=0,
            i_pcie_drp_we=0,
            i_pcie_drp_addr=0,
            i_pcie_drp_di=0,
            o_pcie_drp_rdy=Open(),
            o_pcie_drp_do=Open(),
        )
        if pcie_data_width == 128:
            rx_is_sof = m_axis_rx_tuser[
                10:15]  # Start of a new packet header in m_axis_rx_tdata.
            rx_is_eof = m_axis_rx_tuser[
                17:22]  # End of a packet in m_axis_rx_tdata.
            self.comb += [
                m_axis_rx.first.eq(rx_is_sof[-1]),
                m_axis_rx.last.eq(rx_is_eof[-1]),
                If(rx_is_sof == 0b11000, rx_aligner.first_dword.eq(2)),
            ]
        else:
            self.comb += [
                m_axis_rx.first.eq(0),
                m_axis_rx.last.eq(m_axis_rx_tlast),
            ]
示例#20
0
    def __init__(self, sys_clk_freq):
        self.done = Signal()
        self.restart = Signal()

        # GTP signals
        self.plllock = Signal()
        self.gtrxreset = Signal()
        self.rxresetdone = Signal()
        self.rxdlysreset = Signal()
        self.rxdlysresetdone = Signal()
        self.rxphalign = Signal()
        self.rxdlyen = Signal()
        self.rxuserrdy = Signal()
        self.rxsyncdone = Signal()
        self.rxpmaresetdone = Signal()

        self.drpaddr = Signal(9)
        self.drpen = Signal()
        self.drpdi = Signal(16)
        self.drprdy = Signal()
        self.drpdo = Signal(16)
        self.drpwe = Signal()

        # # #

        drpvalue = Signal(16)
        drpmask = Signal()
        self.comb += [
            self.drpaddr.eq(0x011),
            If(drpmask,
               self.drpdi.eq(drpvalue & 0xf7ff)).Else(self.drpdi.eq(drpvalue))
        ]

        rxpmaresetdone = Signal()
        self.specials += MultiReg(self.rxpmaresetdone, rxpmaresetdone)
        rxpmaresetdone_r = Signal()
        self.sync += rxpmaresetdone_r.eq(rxpmaresetdone)

        # Double-latch transceiver asynch outputs
        plllock = Signal()
        rxresetdone = Signal()
        rxdlysresetdone = Signal()
        rxsyncdone = Signal()
        self.specials += [
            MultiReg(self.plllock, plllock),
            MultiReg(self.rxresetdone, rxresetdone),
            MultiReg(self.rxdlysresetdone, rxdlysresetdone),
            MultiReg(self.rxsyncdone, rxsyncdone)
        ]

        # Deglitch FSM outputs driving transceiver asynch inputs
        gtrxreset = Signal()
        rxdlysreset = Signal()
        rxphalign = Signal()
        rxdlyen = Signal()
        rxuserrdy = Signal()
        self.sync += [
            self.gtrxreset.eq(gtrxreset),
            self.rxdlysreset.eq(rxdlysreset),
            self.rxphalign.eq(rxphalign),
            self.rxdlyen.eq(rxdlyen),
            self.rxuserrdy.eq(rxuserrdy)
        ]

        # After configuration, transceiver resets have to stay low for
        # at least 500ns (see AR43482)
        pll_reset_cycles = ceil(500e-9 * sys_clk_freq)
        pll_reset_timer = WaitTimer(pll_reset_cycles)
        self.submodules += pll_reset_timer

        startup_fsm = ResetInserter()(FSM(reset_state="GTP_RESET"))
        self.submodules += startup_fsm

        ready_timer = WaitTimer(int(4e-3 * sys_clk_freq))
        self.submodules += ready_timer
        self.comb += [
            ready_timer.wait.eq(~self.done & ~startup_fsm.reset),
            startup_fsm.reset.eq(self.restart | ready_timer.done)
        ]

        cdr_stable_timer = WaitTimer(1024)
        self.submodules += cdr_stable_timer

        startup_fsm.act("GTP_RESET", gtrxreset.eq(1),
                        NextState("DRP_READ_ISSUE"))
        startup_fsm.act("DRP_READ_ISSUE", gtrxreset.eq(1), self.drpen.eq(1),
                        NextState("DRP_READ_WAIT"))
        startup_fsm.act(
            "DRP_READ_WAIT", gtrxreset.eq(1),
            If(self.drprdy, NextValue(drpvalue, self.drpdo),
               NextState("DRP_MOD_ISSUE")))
        startup_fsm.act("DRP_MOD_ISSUE", gtrxreset.eq(1), drpmask.eq(1),
                        self.drpen.eq(1), self.drpwe.eq(1),
                        NextState("DRP_MOD_WAIT"))
        startup_fsm.act("DRP_MOD_WAIT", gtrxreset.eq(1),
                        If(self.drprdy, NextState("WAIT_PMARST_FALL")))
        startup_fsm.act(
            "WAIT_PMARST_FALL", rxuserrdy.eq(1),
            If(rxpmaresetdone_r & ~rxpmaresetdone,
               NextState("DRP_RESTORE_ISSUE")))
        startup_fsm.act("DRP_RESTORE_ISSUE", rxuserrdy.eq(1), self.drpen.eq(1),
                        self.drpwe.eq(1), NextState("DRP_RESTORE_WAIT"))
        startup_fsm.act("DRP_RESTORE_WAIT", rxuserrdy.eq(1),
                        If(self.drprdy, NextState("WAIT_GTP_RESET_DONE")))
        # Release GTP reset and wait for GTP resetdone
        # (from UG482, GTP is reset on falling edge
        # of gtrxreset)
        startup_fsm.act(
            "WAIT_GTP_RESET_DONE", rxuserrdy.eq(1),
            cdr_stable_timer.wait.eq(1),
            If(rxresetdone & cdr_stable_timer.done, NextState("ALIGN")))
        # Start delay alignment
        startup_fsm.act("ALIGN", rxuserrdy.eq(1), rxdlysreset.eq(1),
                        If(rxdlysresetdone, NextState("WAIT_ALIGN_DONE")))
        # Wait for delay alignment
        startup_fsm.act("WAIT_ALIGN_DONE", rxuserrdy.eq(1),
                        If(rxsyncdone, NextState("READY")))
        startup_fsm.act("READY", rxuserrdy.eq(1), self.done.eq(1),
                        If(self.restart, NextState("GTP_RESET")))
示例#21
0
    def __init__(self, default_video_timings="800x600@60Hz"):
        # Check / Get Video Timings (can be str or dict)
        if isinstance(default_video_timings, str):
            try:
                self.video_timings = vt = video_timings[default_video_timings]
            except KeyError:
                msg = [f"Video Timings {default_video_timings} not supported, availables:"]
                for video_timing in video_timings.keys():
                    msg.append(f" - {video_timing} / {video_timings[video_timing]['pix_clk']/1e6:3.2f}MHz.")
                raise ValueError("\n".join(msg))
        else:
            self.video_timings = vt = default_video_timings

        # MMAP Control/Status Registers.
        self._enable      = CSRStorage(reset=1)

        self._hres        = CSRStorage(hbits, vt["h_active"])
        self._hsync_start = CSRStorage(hbits, vt["h_active"] + vt["h_sync_offset"])
        self._hsync_end   = CSRStorage(hbits, vt["h_active"] + vt["h_sync_offset"] + vt["h_sync_width"])
        self._hscan       = CSRStorage(hbits, vt["h_active"] + vt["h_blanking"])

        self._vres        = CSRStorage(vbits, vt["v_active"])
        self._vsync_start = CSRStorage(vbits, vt["v_active"] + vt["v_sync_offset"])
        self._vsync_end   = CSRStorage(vbits, vt["v_active"] + vt["v_sync_offset"] + vt["v_sync_width"])
        self._vscan       = CSRStorage(vbits, vt["v_active"] + vt["v_blanking"])

        # Video Timing Source
        self.source = source = stream.Endpoint(video_timing_layout)

        # # #

        # Resynchronize Enable to Video clock domain.
        self.enable = enable = Signal()
        self.specials += MultiReg(self._enable.storage, enable)

        # Resynchronize Horizontal Timings to Video clock domain.
        self.hres        = hres        = Signal(hbits)
        self.hsync_start = hsync_start = Signal(hbits)
        self.hsync_end   = hsync_end   = Signal(hbits)
        self.hscan       = hscan       = Signal(hbits)
        self.specials += MultiReg(self._hres.storage,        hres)
        self.specials += MultiReg(self._hsync_start.storage, hsync_start)
        self.specials += MultiReg(self._hsync_end.storage,   hsync_end)
        self.specials += MultiReg(self._hscan.storage,       hscan)

        # Resynchronize Vertical Timings to Video clock domain.
        self.vres        = vres        = Signal(vbits)
        self.vsync_start = vsync_start = Signal(vbits)
        self.vsync_end   = vsync_end   = Signal(vbits)
        self.vscan       = vscan       = Signal(vbits)
        self.specials += MultiReg(self._vres.storage,        vres)
        self.specials += MultiReg(self._vsync_start.storage, vsync_start)
        self.specials += MultiReg(self._vsync_end.storage,   vsync_end)
        self.specials += MultiReg(self._vscan.storage,       vscan)

        # Generate timings.
        hactive = Signal()
        vactive = Signal()
        fsm = FSM(reset_state="IDLE")
        fsm = ResetInserter()(fsm)
        self.submodules.fsm = fsm
        self.comb += fsm.reset.eq(~enable)
        fsm.act("IDLE",
            NextValue(hactive, 0),
            NextValue(vactive, 0),
            NextValue(source.hres, hres),
            NextValue(source.vres, vres),
            NextValue(source.hcount,  0),
            NextValue(source.vcount,  0),
            NextState("RUN")
        )
        self.comb += source.de.eq(hactive & vactive) # DE when both HActive and VActive.
        self.sync += source.first.eq((source.hcount ==     0) & (source.vcount ==     0)),
        self.sync += source.last.eq( (source.hcount == hscan) & (source.vcount == vscan)),
        fsm.act("RUN",
            source.valid.eq(1),
            If(source.ready,
                # Increment HCount.
                NextValue(source.hcount, source.hcount + 1),
                # Generate HActive / HSync.
                If(source.hcount == 0,           NextValue(hactive,      1)), # Start of HActive.
                If(source.hcount == hres,        NextValue(hactive,      0)), # End of HActive.
                If(source.hcount == hsync_start, NextValue(source.hsync, 1)), # Start of HSync.
                If(source.hcount == hsync_end,   NextValue(source.hsync, 0)), # End of HSync.
                # End of HScan.
                If(source.hcount == hscan,
                    # Reset HCount.
                    NextValue(source.hcount, 0),
                    # Increment VCount.
                    NextValue(source.vcount, source.vcount + 1),
                    # Generate VActive / VSync.
                    If(source.vcount == 0,           NextValue(vactive,      1)), # Start of VActive.
                    If(source.vcount == vres,        NextValue(vactive,      0)), # End of HActive.
                    If(source.vcount == vsync_start, NextValue(source.vsync, 1)), # Start of VSync.
                    If(source.vcount == vsync_end,   NextValue(source.vsync, 0)), # End of VSync.
                    # End of VScan.
                    If(source.vcount == vscan,
                        # Reset VCount.
                        NextValue(source.vcount, 0),
                    )
                )
            )
        )
示例#22
0
文件: usb_fifo.py 项目: ozbenh/litex
    def __init__(self,
                 pads,
                 clk_freq,
                 fifo_depth=8,
                 read_time=128,
                 write_time=128):
        dw = len(pads.data)
        self.clk_freq = clk_freq

        # timings
        tRD = self.ns(30)  # RD# active pulse width (t4)
        tRDDataSetup = self.ns(14)  # RD# to DATA (t3)
        tWRDataSetup = self.ns(5)  # DATA to WR# active setup time (t8)
        tWR = self.ns(30)  # WR# active pulse width (t10)
        tMultiReg = 2

        # read fifo (FTDI --> SoC)
        read_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth)

        # write fifo (SoC --> FTDI)
        write_fifo = stream.SyncFIFO(phy_description(dw), fifo_depth)

        self.submodules += read_fifo, write_fifo

        # sink / source interfaces
        self.sink = write_fifo.sink
        self.source = read_fifo.source

        # read / write arbitration
        wants_write = Signal()
        wants_read = Signal()

        txe_n = Signal()
        rxf_n = Signal()

        self.specials += [
            MultiReg(pads.txe_n, txe_n),
            MultiReg(pads.rxf_n, rxf_n)
        ]

        self.comb += [
            wants_write.eq(~txe_n & write_fifo.source.valid),
            wants_read.eq(~rxf_n & read_fifo.sink.ready),
        ]

        read_time_en, max_read_time = anti_starvation(self, read_time)
        write_time_en, max_write_time = anti_starvation(self, write_time)

        fsm = FSM(reset_state="READ")
        self.submodules += fsm

        read_done = Signal()
        write_done = Signal()
        commuting = Signal()

        fsm.act(
            "READ", read_time_en.eq(1),
            If(
                wants_write & read_done,
                If(~wants_read | max_read_time, commuting.eq(1),
                   NextState("RTW"))))
        fsm.act("RTW", NextState("WRITE"))
        fsm.act(
            "WRITE", write_time_en.eq(1),
            If(
                wants_read & write_done,
                If(~wants_write | max_write_time, commuting.eq(1),
                   NextState("WTR"))))
        fsm.act("WTR", NextState("READ"))

        # databus tristate
        data_w = Signal(dw)
        data_r_async = Signal(dw)
        data_r = Signal(dw)
        data_oe = Signal()
        self.specials += [
            Tristate(pads.data, data_w, data_oe, data_r_async),
            MultiReg(data_r_async, data_r)
        ]

        # read actions
        pads.rd_n.reset = 1

        read_fsm = FSM(reset_state="IDLE")
        self.submodules += read_fsm
        read_counter = Signal(8)
        read_fsm.act(
            "IDLE", read_done.eq(1), NextValue(read_counter, 0),
            If(
                fsm.ongoing("READ") & wants_read,
                If(~commuting, NextState("PULSE_RD_N"))))
        read_fsm.act(
            "PULSE_RD_N", pads.rd_n.eq(0),
            NextValue(read_counter, read_counter + 1),
            If(read_counter == max(tRD - 1, tRDDataSetup + tMultiReg - 1),
               NextState("ACQUIRE_DATA")))
        read_fsm.act("ACQUIRE_DATA", read_fifo.sink.valid.eq(1),
                     read_fifo.sink.data.eq(data_r), NextState("WAIT_RXF_N"))
        read_fsm.act("WAIT_RXF_N", If(rxf_n, NextState("IDLE")))

        # write actions
        pads.wr_n.reset = 1

        write_fsm = FSM(reset_state="IDLE")
        self.submodules += write_fsm
        write_counter = Signal(8)
        write_fsm.act(
            "IDLE", write_done.eq(1), NextValue(write_counter, 0),
            If(
                fsm.ongoing("WRITE") & wants_write,
                If(~commuting, NextState("SET_DATA"))))
        write_fsm.act(
            "SET_DATA", data_oe.eq(1), data_w.eq(write_fifo.source.data),
            NextValue(write_counter, write_counter + 1),
            If(write_counter == (tWRDataSetup - 1),
               NextValue(write_counter, 0), NextState("PULSE_WR_N")))
        write_fsm.act("PULSE_WR_N", data_oe.eq(1),
                      data_w.eq(write_fifo.source.data), pads.wr_n.eq(0),
                      NextValue(write_counter, write_counter + 1),
                      If(write_counter == (tWR - 1), NextState("WAIT_TXE_N")))
        write_fsm.act(
            "WAIT_TXE_N",
            If(txe_n, write_fifo.source.ready.eq(1), NextState("IDLE")))
示例#23
0
    def __init__(self, data_width, depth):
        self.sink = sink = stream.Endpoint(core_layout(data_width))

        self.enable = CSRStorage()
        self.done = CSRStatus()

        self.length = CSRStorage(bits_for(depth))
        self.offset = CSRStorage(bits_for(depth))

        self.mem_valid = CSRStatus()
        self.mem_ready = CSR()
        self.mem_data = CSRStatus(data_width)

        # # #


        # control re-synchronization
        enable = Signal()
        enable_d = Signal()

        enable = Signal()
        enable_d = Signal()
        self.specials += MultiReg(self.enable.storage, enable, "scope")
        self.sync.scope += enable_d.eq(enable)

        length = Signal(max=depth)
        offset = Signal(max=depth)
        self.specials += [
            MultiReg(self.length.storage, length, "scope"),
            MultiReg(self.offset.storage, offset, "scope")
        ]

        # status re-synchronization
        done = Signal()
        self.specials += MultiReg(done, self.done.status)

        # memory
        mem = stream.SyncFIFO([("data", data_width)], depth, buffered=True)
        mem = ClockDomainsRenamer("scope")(mem)
        cdc = stream.AsyncFIFO([("data", data_width)], 4)
        cdc = ClockDomainsRenamer(
            {"write": "scope", "read": "sys"})(cdc)
        self.submodules += mem, cdc

        # flush
        mem_flush = WaitTimer(depth)
        mem_flush = ClockDomainsRenamer("scope")(mem_flush)
        self.submodules += mem_flush

        # fsm
        fsm = FSM(reset_state="IDLE")
        fsm = ClockDomainsRenamer("scope")(fsm)
        self.submodules += fsm
        fsm.act("IDLE",
            done.eq(1),
            If(enable & ~enable_d,
                NextState("FLUSH")
            ),
            sink.ready.eq(1),
            mem.source.connect(cdc.sink)
        )
        fsm.act("FLUSH",
            sink.ready.eq(1),
            mem_flush.wait.eq(1),
            mem.source.ready.eq(1),
            If(mem_flush.done,
                NextState("WAIT")
            )
        )
        fsm.act("WAIT",
            sink.connect(mem.sink, omit={"hit"}),
            If(sink.valid & sink.hit,
                NextState("RUN")
            ),
            mem.source.ready.eq(mem.level >= self.offset.storage)
        )
        fsm.act("RUN",
            sink.connect(mem.sink, omit={"hit"}),
            If(mem.level >= self.length.storage,
                NextState("IDLE"),
            )
        )

        # memory read
        self.comb += [
            self.mem_valid.status.eq(cdc.source.valid),
            cdc.source.ready.eq(self.mem_ready.re | ~self.enable.storage),
            self.mem_data.status.eq(cdc.source.data)
        ]
示例#24
0
    def __init__(self, comma, tx_clk_freq, check_period=6e-3):
        self.rxdata = Signal(20)
        self.restart = Signal()

        self.ready = Signal()

        check_max_val = ceil(check_period*tx_clk_freq)
        check_counter = Signal(max=check_max_val+1)
        check = Signal()
        reset_check_counter = Signal()
        self.sync.rtio_tx += [
            check.eq(0),
            If(reset_check_counter,
                check_counter.eq(check_max_val)
            ).Else(
                If(check_counter == 0,
                    check.eq(1),
                    check_counter.eq(check_max_val)
                ).Else(
                    check_counter.eq(check_counter-1)
                )
            )
        ]

        checks_reset = PulseSynchronizer("rtio_tx", "rtio_rx")
        self.submodules += checks_reset

        comma_n = ~comma & 0b1111111111
        comma_seen_rxclk = Signal()
        comma_seen = Signal()
        comma_seen_rxclk.attr.add("no_retiming")
        self.specials += MultiReg(comma_seen_rxclk, comma_seen)
        self.sync.rtio_rx += \
            If(checks_reset.o,
                comma_seen_rxclk.eq(0)
            ).Elif((self.rxdata[:10] == comma) | (self.rxdata[:10] == comma_n),
                comma_seen_rxclk.eq(1)
            )

        error_seen_rxclk = Signal()
        error_seen = Signal()
        error_seen_rxclk.attr.add("no_retiming")
        self.specials += MultiReg(error_seen_rxclk, error_seen)
        rx1cnt = Signal(max=11)
        self.sync.rtio_rx += [
            rx1cnt.eq(reduce(add, [self.rxdata[i] for i in range(10)])),
            If(checks_reset.o,
                error_seen_rxclk.eq(0)
            ).Elif((rx1cnt != 4) & (rx1cnt != 5) & (rx1cnt != 6),
                error_seen_rxclk.eq(1)
            )
        ]

        fsm = ClockDomainsRenamer("rtio_tx")(FSM(reset_state="WAIT_COMMA"))
        self.submodules += fsm

        fsm.act("WAIT_COMMA",
            If(check,
                # Errors are still OK at this stage, as the transceiver
                # has just been reset and may output garbage data.
                If(comma_seen,
                    NextState("WAIT_NOERROR")
                ).Else(
                    self.restart.eq(1)
                ),
                checks_reset.i.eq(1)
            )
        )
        fsm.act("WAIT_NOERROR",
            If(check,
                If(comma_seen & ~error_seen,
                    NextState("READY")
                ).Else(
                    self.restart.eq(1),
                    NextState("WAIT_COMMA")
                ),
                checks_reset.i.eq(1)
            )
        )
        fsm.act("READY",
            reset_check_counter.eq(1),
            self.ready.eq(1),
            If(error_seen,
                checks_reset.i.eq(1),
                self.restart.eq(1),
                NextState("WAIT_COMMA")
            )
        )
示例#25
0
    def __init__(self, phys, jesd_settings, converter_data_width):
        self.enable = Signal()
        self.jsync = Signal()
        self.jref = Signal()
        self.ready = Signal()
        self.restart = Signal()

        self.prbs_config = Signal(4)
        self.stpl_enable = Signal()

        self.sink = Record([("converter" + str(i), converter_data_width)
                            for i in range(jesd_settings.nconverters)])

        # # #

        # restart when disabled or on re-synchronization request
        self.comb += self.restart.eq(~self.enable | self.ready & ~self.jsync)

        # transport layer
        transport = JESD204BTransportTX(jesd_settings, converter_data_width)
        self.submodules.transport = transport

        # stpl
        stpl = JESD204BSTPLGenerator(jesd_settings, converter_data_width)
        self.submodules += stpl
        stpl_enable = Signal()
        self.specials += \
            MultiReg(self.stpl_enable, stpl_enable)
        self.comb += \
            If(stpl_enable,
                transport.sink.eq(stpl.source)
            ).Else(
                transport.sink.eq(self.sink)
            )

        links = []
        for n, (phy, lane) in enumerate(zip(phys, transport.source.flatten())):
            phy_name = "phy{}".format(n)
            phy_cd = phy_name + "_tx"

            # claim the phy
            setattr(self.submodules, phy_name, phy)

            ebuf = ElasticBuffer(len(phy.data), 4, "sys", phy_cd)
            setattr(self.submodules, "ebuf{}".format(n), ebuf)

            link = JESD204BLinkTX(len(phy.data), jesd_settings, n)
            link = ClockDomainsRenamer(phy_cd)(link)
            links.append(link)
            self.comb += [link.jsync.eq(self.jsync), link.jref.eq(self.jref)]
            self.submodules += link

            # connect data
            self.comb += [
                ebuf.din.eq(lane),
                link.sink.data.eq(ebuf.dout),
                phy.data.eq(link.source.data),
                phy.ctrl.eq(link.source.ctrl)
            ]

            # connect control
            self.comb += phy.transmitter.init.restart.eq(
                self.restart & (self.prbs_config == 0))

            self.specials += MultiReg(self.prbs_config,
                                      phy.transmitter.prbs_config, phy_cd)
        ready = Signal()
        self.comb += ready.eq(reduce(and_, [link.ready for link in links]))
        self.specials += MultiReg(ready, self.ready)
示例#26
0
文件: ulpicfg.py 项目: ymz000/ov_ftdi
    def __init__(self, clk, cd_rst, ulpi_rst, ulpi_stp_ovr, ulpi_reg):

        # TESTING - UCFG_RST register
        #  - BRST: reseting of code in the ULPI cd
        #  - URST: reset of external phy
        #  - FSTP: Force assert of STP during reset
        #   (should be part of ULPI cd bringup code)
        #
        # Format:
        #
        #    7    6    5    4    3    2    1    0
        #    ---------------------------------------
        #    0    0    0    0    0    FSTP BRST URST
        #

        self._rst = CSRStorage(3)
        self.comb += ulpi_rst.eq(self._rst.storage[0])
        self.comb += cd_rst.eq(self._rst.storage[1])
        self.comb += ulpi_stp_ovr.eq(self._rst.storage[2])

        # TESTING - UCFG_STAT register
        #
        # CKACT: single status bit that indicates whether
        # the ULPI phy is providing a 60mhz clock signal on clk
        #
        # Format:
        #
        #    7    6    5    4    3    2    1    0
        #    ----------------------------------------
        #    0    0    0    0    0    0    0    CKACT
        #

        self._stat = CSRStatus(1)

        ulpi_clk_act_cd = Signal(8)

        # Resample ulpi_clk in sys
        sys_ulpi_clk = Signal(1)
        self.specials += MultiReg(clk, sys_ulpi_clk)

        # Edge detect the ULPI clk
        last_ulpi_clk = Signal(1)
        self.sync += [
            last_ulpi_clk.eq(sys_ulpi_clk),

            # On detected transistions, reset the countdown
            If(last_ulpi_clk != sys_ulpi_clk, ulpi_clk_act_cd.eq(0)).Elif(
                ulpi_clk_act_cd < 0xFF,
                ulpi_clk_act_cd.eq(ulpi_clk_act_cd + 1))
        ]

        self.comb += self._stat.status.eq(ulpi_clk_act_cd != 0xFF)

        # ULPI_xDATA and xCMD registers
        #
        # Used for reading/writing ULPI regs
        #
        # ULPI_xDATA Format: just 8 bit data reg
        #
        # ULPI_xCMD Format:
        #
        #    7    6    5    4    3    2    1    0
        #    ----------------------------------------
        #    GO   0    UA5  UA4  UA3  UA2  UA1  UA0
        #
        # GO:
        #    - write 1 to start ULPI reg transaction
        #    - stays 1 while transaction in progress
        #    - clears to 0 when transaction complete
        #
        # UA5..0 - ULPI register address

        # To do a write: write UCFG_WDATA with the value
        # and then write ULPI_WCMD with GO | addr
        #
        # To read: write ULPI_RCMD with GO | addr, poll
        # until GO clear, then read ULPI_RDATA

        self._wdata = CSRStorage(8)
        self._wcmd = _ULPI_cmd_reg(ulpi_reg.wreq, ulpi_reg.wack,
                                   ulpi_reg.waddr)
        self.submodules += self._wcmd
        self.comb += ulpi_reg.wdata.eq(self._wdata.storage)

        self._rdata = CSRStatus(8)
        self._rcmd = _ULPI_cmd_reg(ulpi_reg.rreq, ulpi_reg.rack,
                                   ulpi_reg.raddr)
        self.submodules += self._rcmd
        self.sync += If(ulpi_reg.rack, self._rdata.status.eq(ulpi_reg.rdata))
示例#27
0
    def __init__(self, platform):
        default_period = 325000000
        self.intro = ModuleDoc("""Watch Dog Timer
A watchdog timer for Betrusted. Once enabled, it cannot be disabled, and
it must have the reset_wdt bit written periodically to avoid a watchdog reset event.

If this does not happen, the WDT will attempt to toggle reset of the full chip via GSR.

The timeout period is specified in 'approximately 65MHz' (15.38ns) periods by the period register.
According to Xilinx, 'approximately' is +/-50%.

The register cannot be updated once the WDT is running.
        """)
        self.gsr = Signal()  # wire to the GSR line for the FPGA
        self.cfgmclk = Signal(
        )  # wire to FPGA's CFGMCLK ring oscillator, a "typical" 65MHz clock
        self.clock_domains.cd_wdt = ClockDomain()
        self.specials += Instance("BUFG",
                                  i_I=self.cfgmclk,
                                  o_O=self.cd_wdt.clk)
        platform.add_platform_command(
            "create_clock -name wdt -period 10.256 [get_nets {net}]",
            net=self.cd_wdt.clk)  # 65MHz + 50% tolerance

        ### WATCHDOG RESET, uses the extcomm_div divider to save on gates
        self.watchdog = CSRStorage(fields=[
            CSRField("reset_wdt",
                     size=1,
                     description=
                     "Write to this register to reset the watchdog timer",
                     pulse=True),
            CSRField(
                "enable",
                description=
                "Enable the watchdog timer. Cannot be disabled once enabled, except with a reset. Notably, a watchdog reset will disable the watchdog.",
                reset=0),
        ])
        reset_wdt = Signal()
        w_stretch = Signal(3)
        reset_wdt_sys = Signal()
        self.sync += [
            If(self.watchdog.fields.reset_wdt,
               w_stretch.eq(7)).Elif(w_stretch > 0,
                                     w_stretch.eq(w_stretch - 1)),
            reset_wdt_sys.eq(w_stretch != 0),
        ]
        self.submodules.reset_sync = BlindTransfer("sys", "wdt")
        self.comb += [
            self.reset_sync.i.eq(reset_wdt_sys),
            reset_wdt.eq(self.reset_sync.o),
        ]
        self.period = CSRStorage(
            32,
            fields=[
                CSRField(
                    "period",
                    size=32,
                    description=
                    "Number of 'approximately 65MHz' CFGMCLK cycles before each reset_code must be entered. Defaults to a range of {:0.2f}-{:0.2f} seconds"
                    .format((default_period * 10.256e-9) * 0.5,
                            (default_period * 10.256e-9) * 1.5),
                    reset=default_period)
            ])

        self.state = CSRStatus(
            4,
            fields=[
                CSRField("enabled", size=1,
                         description="WDT has been enabled"),
                CSRField("armed1",
                         size=1,
                         description="WDT in the armed1 state"),
                CSRField("armed2",
                         size=1,
                         description="WDT in the armed2 state"),
                CSRField("disarmed",
                         size=1,
                         description="WDT in the disarmed state"),
            ])
        armed1 = Signal()
        armed2 = Signal()
        disarmed = Signal()
        self.specials += MultiReg(armed1, self.state.fields.armed1)
        self.specials += MultiReg(armed2, self.state.fields.armed2)
        self.specials += MultiReg(disarmed, self.state.fields.disarmed)

        wdog_enable_wdt = Signal()
        self.specials += MultiReg(self.watchdog.fields.enable,
                                  wdog_enable_wdt,
                                  odomain="wdt")
        wdog_enabled = Signal(reset=0)
        wdog_enabled_r = Signal(reset=0)
        self.sync.wdt += [
            If(wdog_enable_wdt,
               wdog_enabled.eq(1)).Else(wdog_enabled.eq(wdog_enabled)),
            wdog_enabled_r.eq(wdog_enabled)
        ]
        self.specials += MultiReg(wdog_enabled, self.state.fields.enabled)

        self.submodules.period_sync = BusSynchronizer(32, "sys", "wdt")
        wdt_count = Signal(32)
        self.comb += [
            self.period_sync.i.eq(self.period.fields.period),
            wdt_count.eq(self.period_sync.o)
        ]
        wdt_count_lock = Signal(32)
        wdt_start = Signal()
        self.sync.wdt += [
            wdt_start.eq(~wdog_enabled_r & wdog_enabled),
            If(~wdog_enabled_r & wdog_enabled,
               wdt_count_lock.eq(wdt_count)).Else(
                   wdt_count_lock.eq(wdt_count_lock), )
        ]
        wdog_counter = Signal(32, reset=default_period)
        wdog_cycle = Signal()
        self.sync.wdt += [
            If(
                wdt_start,
                wdog_counter.eq(wdt_count_lock),
            ).Else(
                If(
                    wdog_enabled,
                    If(wdog_counter == 0, wdog_cycle.eq(1),
                       wdog_counter.eq(wdt_count_lock)).Else(
                           wdog_counter.eq(wdog_counter - 1),
                           wdog_cycle.eq(0),
                       )))
        ]
        do_reset = Signal()
        wdog = ClockDomainsRenamer("wdt")(FSM(reset_state="IDLE"))
        self.submodules += wdog
        wdog.act("IDLE", If(wdog_enabled, NextState("DISARMED")))
        wdog.act(
            "ARMED_HOT",
            armed2.eq(1),
            If(reset_wdt, NextState("DISARMED")).Elif(
                wdog_cycle,
                do_reset.eq(1),
            ),
        )
        # double-interlock: not having responded to the watchdog code immediately
        # is not cause for a reset: this could just be the wdog_cycle hitting at an
        # inopportune time relative to the watchdog reset routine.
        # instead, escalate to the ARMED_HOT state so that
        # the watchdog next period, if no action was taken, we do a reset
        wdog.act(
            "ARMED", armed1.eq(1),
            If(reset_wdt, NextState("DISARMED")).Elif(wdog_cycle,
                                                      NextState("ARMED_HOT")))
        wdog.act("DISARMED", disarmed.eq(1), If(wdog_cycle,
                                                NextState("ARMED")))
        do_reset_sys = Signal()
        reset_stretch = Signal(5, reset=0)
        self.submodules.do_res_sync = BlindTransfer("wdt", "sys")
        self.comb += [
            self.do_res_sync.i.eq(do_reset),
            do_reset_sys.eq(self.do_res_sync.o),
        ]
        self.sync += [
            If(
                do_reset_sys,
                reset_stretch.eq(31),
                self.gsr.eq(0),
            ).Elif(
                reset_stretch != 0,
                self.gsr.eq(1),
                reset_stretch.eq(reset_stretch - 1),
            ).Else(
                reset_stretch.eq(0),
                self.gsr.eq(0),
            )
        ]
示例#28
0
文件: serdes_ecp5.py 项目: blazra/tdr
    def __init__(self,
                 pll,
                 tx_pads,
                 rx_pads,
                 dual=0,
                 channel=0,
                 data_width=20,
                 tx_polarity=0,
                 rx_polarity=0):
        assert (data_width == 20)
        assert dual in [0, 1]
        assert channel in [0, 1]
        self.dual = dual
        self.channel = channel

        # TX controls
        self.tx_enable = Signal(reset=1)
        self.tx_ready = Signal()
        self.tx_inhibit = Signal()  # FIXME
        self.tx_produce_square_wave = Signal()
        self.tx_produce_pattern = Signal()
        self.tx_pattern = Signal(data_width)
        self.tx_prbs_config = Signal(2)
        self.tx_idle = Signal()
        self.tx_data = Signal(20)
        self.ldr_tx_data = Signal()

        # RX controls
        self.rx_enable = Signal(reset=1)
        self.rx_ready = Signal()
        self.rx_prbs_config = Signal(2)
        self.rx_prbs_errors = Signal(32)
        self.rx_idle = Signal()
        self.rx_data = Signal(20)

        # Loopback
        self.loopback = Signal(
        )  # FIXME: reconfigure lb_ctl to 0b0001 but does not seem enough

        # # #

        self.nwords = nwords = data_width // 10

        # Transceiver direct clock outputs (useful to specify clock constraints)
        self.txoutclk = Signal()
        self.rxoutclk = Signal()

        self.tx_clk_freq = pll.config["linerate"] / data_width
        self.rx_clk_freq = pll.config["linerate"] / data_width

        # Internal signals -------------------------------------------------------------------------
        rx_los = Signal()
        self.rx_lol = Signal()
        rx_lsm = Signal()
        rx_bus = Signal(24)

        tx_lol = Signal()
        tx_bus = Signal(24)

        # Control/Status CDC -----------------------------------------------------------------------
        self.specials += [
            MultiReg(rx_los, self.rx_idle, "sys"),
        ]

        # Clocking ---------------------------------------------------------------------------------
        self.clock_domains.cd_tx = ClockDomain()
        self.comb += self.cd_tx.clk.eq(self.txoutclk)
        self.specials += AsyncResetSynchronizer(self.cd_tx, ResetSignal("sys"))
        self.specials += MultiReg(~self.cd_tx.rst, self.tx_ready)

        self.clock_domains.cd_rx = ClockDomain()
        self.comb += self.cd_rx.clk.eq(self.rxoutclk)
        self.specials += AsyncResetSynchronizer(self.cd_rx, ResetSignal("sys"))
        self.specials += MultiReg(~self.cd_rx.rst, self.rx_ready)

        # DCU instance -----------------------------------------------------------------------------
        self.serdes_params = dict(
            # ECP5's DCU parameters/signals/instance have been documented by whitequark as part of
            #             Yumewatari project: https://github.com/whitequark/Yumewatari
            #                  Copyright (C) 2018 [email protected]
            # DCU ----------------------------------------------------------------------------------
            # DCU — power management
            p_D_MACROPDB="0b1",
            p_D_IB_PWDNB="0b1",  # undocumented (required for RX)
            p_D_TXPLL_PWDNB="0b1",
            p_D_XGE_MODE="0b0",
            i_D_FFC_MACROPDB=1,

            # DCU — reset
            i_D_FFC_MACRO_RST=ResetSignal("sys"),
            i_D_FFC_DUAL_RST=ResetSignal("sys"),

            # DCU — clocking
            i_D_REFCLKI=pll.refclk,
            o_D_FFS_PLOL=tx_lol,
            p_D_REFCK_MODE={
                25: "0b100",
                20: "0b000",
                16: "0b010",
                10: "0b001",
                8: "0b011"
            }[pll.config["mult"]],
            p_D_TX_MAX_RATE="2",  # Gbps
            p_D_TX_VCO_CK_DIV={
                32: "0b111",
                16: "0b110",
                8: "0b101",
                4: "0b100",
                2: "0b010",
                1: "0b000"
            }[1],  # DIV/1
            p_D_BITCLK_LOCAL_EN="0b1",  # Use clock from local PLL
            p_D_CDR_LOL_SET="0b00",  # After LOL do nothing

            # DCU ­— unknown
            p_D_CMUSETBIASI=
            "0b00",  # begin undocumented (10BSER sample code used)
            p_D_CMUSETI4CPP="0d3",
            p_D_CMUSETI4CPZ="0d3",
            p_D_CMUSETI4VCO="0b00",
            p_D_CMUSETICP4P="0b01",
            p_D_CMUSETICP4Z="0b101",
            p_D_CMUSETINITVCT="0b00",
            p_D_CMUSETISCL4VCO="0b000",
            p_D_CMUSETP1GM="0b000",
            p_D_CMUSETP2AGM="0b000",
            p_D_CMUSETZGM="0b000",
            p_D_SETIRPOLY_AUX="0b10",
            p_D_SETICONST_AUX="0b01",
            p_D_SETIRPOLY_CH="0b10",
            p_D_SETICONST_CH="0b10",
            p_D_SETPLLRC="0d1",
            p_D_SYNC_LOCAL_EN="0b1",
            p_D_RG_EN="0b0",
            p_D_RG_SET="0b00",
            p_D_REQ_ISET="0b001",
            p_D_PD_ISET="0b00",  # end undocumented

            # DCU — FIFOs
            p_D_LOW_MARK=
            "0d4",  # Clock compensation FIFO low  water mark (mean=8)
            p_D_HIGH_MARK=
            "0d12",  # Clock compensation FIFO high water mark (mean=8)

            # CHX common ---------------------------------------------------------------------------
            # CHX — protocol
            p_CHX_PROTOCOL="10BSER",
            p_CHX_UC_MODE="0b1",  # Selects User Configured mode
            p_CHX_ENC_BYPASS="******",  # Bypass 8b10b encoder
            p_CHX_DEC_BYPASS="******",  # Bypass 8b10b encoder

            # CHX receive --------------------------------------------------------------------------
            # CHX RX ­— power management
            p_CHX_RPWDNB="0b1",
            i_CHX_FFC_RXPWDNB=1,

            # CHX RX ­— reset
            i_CHX_FFC_RRST=~self.rx_enable,
            i_CHX_FFC_LANE_RX_RST=~self.rx_enable,

            # CHX RX ­— input
            i_CHX_HDINP=rx_pads.p,
            i_CHX_HDINN=rx_pads.n,
            p_CHX_REQ_EN="0b0",  # Enable equalizer
            p_CHX_RX_RATE_SEL="0d10",  # Equalizer  pole position
            p_CHX_RTERM_RX={
                "5k-ohms": "0b00000",
                "80-ohms": "0b00001",
                "75-ohms": "0b00100",
                "70-ohms": "0b00110",
                "60-ohms": "0b01011",
                "50-ohms": "0b10011",
                "46-ohms": "0b11001"
            }["50-ohms"],
            p_CHX_RXIN_CM="0b11",  # CMFB (wizard value used)
            p_CHX_RXTERM_CM="0b11",  # RX Input (wizard value used)
            p_CHX_RCV_DCC_EN="0b1",  # Receiver DC coupling enable

            # CHX RX ­— clocking
            i_CHX_RX_REFCLK=pll.refclk,
            o_CHX_FF_RX_PCLK=self.rxoutclk,
            i_CHX_FF_RXI_CLK=ClockSignal("rx"),
            p_CHX_CDR_MAX_RATE="2",  # Gbps
            p_CHX_RX_DCO_CK_DIV={
                32: "0b111",
                16: "0b110",
                8: "0b101",
                4: "0b100",
                2: "0b010",
                1: "0b000"
            }[1],  # DIV/1
            p_CHX_RX_GEAR_MODE="0b1",  # 1:2 gearbox
            p_CHX_FF_RX_H_CLK_EN="0b1",  # enable  DIV/2 output clock
            p_CHX_FF_RX_F_CLK_DIS="0b1",  # disable DIV/1 output clock
            p_CHX_SEL_SD_RX_CLK="0b1",  # FIFO driven by recovered clock
            p_CHX_AUTO_FACQ_EN="0b1",  # undocumented (wizard value used)
            p_CHX_AUTO_CALIB_EN="0b1",  # undocumented (wizard value used)
            p_CHX_PDEN_SEL="0b0",  # phase detector disabled on LOS

            #p_CHX_DCO_FACQ_RST
            p_CHX_DCOATDCFG="0b00",  # begin undocumented (sample code used)
            p_CHX_DCOATDDLY="0b00",
            p_CHX_DCOBYPSATD="0b1",
            p_CHX_DCOCALDIV="0b000",
            p_CHX_DCOCTLGI="0b011",
            p_CHX_DCODISBDAVOID="0b0",
            p_CHX_DCOFLTDAC="0b00",
            p_CHX_DCOFTNRG="0b001",
            p_CHX_DCOIOSTUNE="0b010",
            p_CHX_DCOITUNE="0b00",
            p_CHX_DCOITUNE4LSB="0b010",
            p_CHX_DCOIUPDNX2="0b1",
            p_CHX_DCONUOFLSB="0b100",
            p_CHX_DCOSCALEI="0b01",
            p_CHX_DCOSTARTVAL="0b010",
            p_CHX_DCOSTEP="0b11",  # end undocumented

            # CHX RX — loss of signal
            o_CHX_FFS_RLOS=rx_los,
            p_CHX_RLOS_SEL="0b0",
            p_CHX_RX_LOS_EN="0b0",
            p_CHX_RX_LOS_LVL="0b100",  # Lattice "TBD" (wizard value used)
            p_CHX_RX_LOS_CEQ="0b11",  # Lattice "TBD" (wizard value used)

            # CHX RX — loss of lock
            o_CHX_FFS_RLOL=self.rx_lol,

            # CHx_RXLSM? CHx_RXWA?
            p_CHX_LSM_DISABLE="0b1",

            # CHX RX — link state machine
            i_CHX_FFC_SIGNAL_DETECT=0,
            o_CHX_FFS_LS_SYNC_STATUS=rx_lsm,
            p_CHX_ENABLE_CG_ALIGN="0b0",
            p_CHX_UDF_COMMA_MASK="0x0ff",  # compare the 8 lsbs
            p_CHX_UDF_COMMA_A="0b0000000011",  # K28.1, K28.5 and K28.7
            p_CHX_UDF_COMMA_B="0b0001111100",  # K28.1, K28.5 and K28.7
            p_CHX_CTC_BYPASS="******",  # bypass CTC FIFO
            p_CHX_MIN_IPG_CNT="0b11",  # minimum interpacket gap of 4
            p_CHX_MATCH_2_ENABLE="0b0",  # 2 character skip matching
            p_CHX_MATCH_4_ENABLE="0b0",  # 4 character skip matching
            p_CHX_CC_MATCH_1="0x000",
            p_CHX_CC_MATCH_2="0x000",
            p_CHX_CC_MATCH_3="0x000",
            p_CHX_CC_MATCH_4="0x000",

            # CHX RX — data
            **{"o_CHX_FF_RX_D_%d" % n: rx_bus[n]
               for n in range(rx_bus.nbits)},

            # CHX transmit -------------------------------------------------------------------------
            # CHX TX — power management
            p_CHX_TPWDNB="0b1",
            i_CHX_FFC_TXPWDNB=1,

            # CHX TX ­— reset
            i_D_FFC_TRST=~self.tx_enable,
            i_CHX_FFC_LANE_TX_RST=~self.tx_enable,

            # CHX TX ­— output
            o_CHX_HDOUTP=tx_pads.p,
            o_CHX_HDOUTN=tx_pads.n,
            p_CHX_TXAMPLITUDE="0d1000",  # 1000 mV
            p_CHX_RTERM_TX={
                "5k-ohms": "0b00000",
                "80-ohms": "0b00001",
                "75-ohms": "0b00100",
                "70-ohms": "0b00110",
                "60-ohms": "0b01011",
                "50-ohms": "0b10011",
                "46-ohms": "0b11001"
            }["50-ohms"],
            p_CHX_TDRV_SLICE0_CUR="0b011",  # 400 uA
            p_CHX_TDRV_SLICE0_SEL="0b01",  # main data
            p_CHX_TDRV_SLICE1_CUR="0b000",  # 100 uA
            p_CHX_TDRV_SLICE1_SEL="0b00",  # power down
            p_CHX_TDRV_SLICE2_CUR="0b11",  # 3200 uA
            p_CHX_TDRV_SLICE2_SEL="0b01",  # main data
            p_CHX_TDRV_SLICE3_CUR="0b10",  # 2400 uA
            p_CHX_TDRV_SLICE3_SEL="0b01",  # main data
            p_CHX_TDRV_SLICE4_CUR="0b00",  # 800 uA
            p_CHX_TDRV_SLICE4_SEL="0b00",  # power down
            p_CHX_TDRV_SLICE5_CUR="0b00",  # 800 uA
            p_CHX_TDRV_SLICE5_SEL="0b00",  # power down

            # CHX TX ­— clocking
            o_CHX_FF_TX_PCLK=self.txoutclk,
            i_CHX_FF_TXI_CLK=ClockSignal("tx"),
            p_CHX_TX_GEAR_MODE="0b1",  # 1:2 gearbox
            p_CHX_FF_TX_H_CLK_EN="0b1",  # enable  DIV/2 output clock
            p_CHX_FF_TX_F_CLK_DIS="0b1",  # disable DIV/1 output clock

            # CHX TX — data
            **{"i_CHX_FF_TX_D_%d" % n: tx_bus[n]
               for n in range(tx_bus.nbits)},

            # CHX TX LowDataRate data input
            i_CHX_FFC_LDR_CORE2TX_EN=1,
            p_CH1_LDR_CORE2TX_SEL="0b1",
            i_CHX_LDR_CORE2TX=self.ldr_tx_data,
        )

        # SCI Reconfiguration ----------------------------------------------------------------------
        sci_reconfig = SerDesECP5SCIReconfig(self)
        self.submodules.sci_reconfig = sci_reconfig

        # TX Datapath ------------------------------------------------------------------------------

        self.comb += [
            tx_bus[0:10].eq(self.tx_data[0:10]),
            tx_bus[12:22].eq(self.tx_data[10:20]),
        ]

        # RX Datapath ------------------------------------------------------------------------------
        self.comb += [
            self.rx_data[0:10].eq(rx_bus[0:10]),
            self.rx_data[10:20].eq(rx_bus[12:22]),
        ]

        self.analyzer_signals = [
            tx_lol,
            self.tx_enable,
            self.tx_inhibit,
            self.tx_ready,
            self.rx_enable,
            self.rx_ready,
            self.rx_data,
            self.rx_lol,
            rx_los,
            sci_reconfig.fc2dco_floop,
        ]
示例#29
0
    def __init__(self, pll, pads, mode="master"):
        self.tx_data = Signal(32)
        self.rx_data = 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.d[0].eq(self.tx_data[0:8]),
                self.encoder.d[1].eq(self.tx_data[8:16]),
                self.encoder.d[2].eq(self.tx_data[16:24]),
                self.encoder.d[3].eq(self.tx_data[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_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"),
                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_data.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)))

        ]
示例#30
0
    def __init__(self, dram_port):
        ashift, awidth = get_ashift_awidth(dram_port)
        self.reset = CSR()
        self.start = CSR()
        self.done = CSRStatus()
        self.base = CSRStorage(awidth)
        self.length = CSRStorage(awidth)
        self.random = CSRStorage()
        self.ticks = CSRStatus(32)
        self.errors = CSRStatus(32)

        # # #

        clock_domain = dram_port.clock_domain

        core = _LiteDRAMBISTChecker(dram_port)
        core = ClockDomainsRenamer(clock_domain)(core)
        self.submodules += core

        if clock_domain != "sys":
            reset_sync = PulseSynchronizer("sys", clock_domain)
            start_sync = PulseSynchronizer("sys", clock_domain)
            self.submodules += reset_sync, start_sync
            self.comb += [
                reset_sync.i.eq(self.reset.re),
                core.reset.eq(reset_sync.o),
                start_sync.i.eq(self.start.re),
                core.start.eq(start_sync.o)
            ]

            done_sync = BusSynchronizer(1, clock_domain, "sys")
            self.submodules += done_sync
            self.comb += [
                done_sync.i.eq(core.done),
                self.done.status.eq(done_sync.o)
            ]

            base_sync = BusSynchronizer(awidth, "sys", clock_domain)
            length_sync = BusSynchronizer(awidth, "sys", clock_domain)
            self.submodules += base_sync, length_sync
            self.comb += [
                base_sync.i.eq(self.base.storage),
                core.base.eq(base_sync.o),
                length_sync.i.eq(self.length.storage),
                core.length.eq(length_sync.o)
            ]

            self.specials += MultiReg(self.random.storage, core.random,
                                      clock_domain)

            ticks_sync = BusSynchronizer(32, clock_domain, "sys")
            self.submodules += ticks_sync
            self.comb += [
                ticks_sync.i.eq(core.ticks),
                self.ticks.status.eq(ticks_sync.o)
            ]

            errors_sync = BusSynchronizer(32, clock_domain, "sys")
            self.submodules += errors_sync
            self.comb += [
                errors_sync.i.eq(core.errors),
                self.errors.status.eq(errors_sync.o)
            ]
        else:
            self.comb += [
                core.reset.eq(self.reset.re),
                core.start.eq(self.start.re),
                self.done.status.eq(core.done),
                core.base.eq(self.base.storage),
                core.length.eq(self.length.storage),
                core.random.eq(self.random.storage),
                self.ticks.status.eq(core.ticks),
                self.errors.status.eq(core.errors)
            ]