Ejemplo n.º 1
0
    def elaborate(self, platform):
        pll = Instance(
            "SB_PLL40_2_PAD",
            p_FEEDBACK_PATH="SIMPLE",
            p_DIVR=self.coeff.divr,
            p_DIVF=self.coeff.divf,
            p_DIVQ=self.coeff.divq,
            p_FILTER_RANGE=0b001,
            i_PACKAGEPIN=self.clk_pin,
            i_RESETB=self.reset,
            i_BYPASS=Const(0),
            o_PLLOUTGLOBALA=ClockSignal(self.orig_domain_name),
            o_PLLOUTGLOBALB=ClockSignal(self.pll_domain_name),
            o_LOCK=self.pll_lock,
        )

        m = Module()
        m.submodules += pll
        m.submodules += ResetSynchronizer(~self.pll_lock, domain=self.pll_domain_name)
        m.submodules += ResetSynchronizer(~self.pll_lock, domain=self.orig_domain_name)

        m.domains += self.orig_domain
        m.domains += self.pll_domain

        return m
Ejemplo n.º 2
0
    def elaborate(self, platform):
        m = Module()

        # copy all the signals to validate them and make sure we (as a system)
        # have a version we can do whatever with and is just connected to the
        # outside world
        def copy_signals(signals):
            copied = []
            for fi, field in enumerate(signals._fields):
                outside_signal = signals[fi]
                if not isinstance(outside_signal, (Value, ValueCastable)):
                    raise TypeError("{} must be a Value, not {!r}".format(
                        field, type(outside_signal)))
                our_signal = Signal(len(outside_signal), name=field)
                if field.startswith("i_"):
                    m.d.comb += our_signal.eq(outside_signal)
                else:
                    m.d.comb += outside_signal.eq(our_signal)
                copied.append(our_signal)
            return signals._make(copied)

        clock_signals = copy_signals(self._in_clock_signals)
        snes_signals = copy_signals(self._in_snes_signals)
        uart_signals = copy_signals(self._in_uart_signals)
        memory_signals = copy_signals(self._in_memory_signals)

        # now we can give all the signals to the core
        core = TASHACore(
            snes_signals=snes_signals,
            uart_signals=uart_signals,
            memory_signals=memory_signals,
        )
        m.submodules += core

        # wire up the clocks to the actual clock domains. we do it here because
        # the different platforms have different ways of giving us clocks
        sync_domain = ClockDomain("sync")
        apu_domain = ClockDomain("apu")
        m.domains += [sync_domain, apu_domain]
        m.d.comb += [
            ClockSignal("sync").eq(clock_signals.i_sys_clk_12),
            ClockSignal("apu").eq(clock_signals.i_apu_clk_24p75),
        ]
        # hook up reset signals too. the system can request its own reset, so we
        # have to incorporate that here.
        do_reset = Signal()
        m.d.comb += do_reset.eq(clock_signals.i_reset | core.o_reset_req)
        # synchronize the various resets to the clock domains. we use a lot of
        # stages to ensure that nothing weird happens when the system tries to
        # reset itself
        m.submodules += ResetSynchronizer(do_reset, domain="sync", stages=4)
        m.submodules += ResetSynchronizer(do_reset, domain="apu", stages=4)

        return m
Ejemplo n.º 3
0
    def elaborate(self, platform):
        pll_lock = Signal()
        pll = Instance("SB_PLL40_PAD",
                       p_FEEDBACK_PATH='SIMPLE',
                       p_DIVR=self.coeff.divr,
                       p_DIVF=self.coeff.divf,
                       p_DIVQ=self.coeff.divq,
                       p_FILTER_RANGE=0b001,
                       i_PACKAGEPIN=self.clk_pin,
                       i_RESETB=Const(1),
                       i_BYPASS=Const(0),
                       o_PLLOUTGLOBAL=ClockSignal(self.domain_name),
                       o_LOCK=pll_lock)

        m = Module()
        rst_signal = Signal()

        if (self.external_rst is not None):
            m.d.comb += rst_signal.eq(~pll_lock & self.external_rst)
        else:
            m.d.comb += rst_signal.eq(~pll_lock)

        #rs = ResetSynchronizer(~pll_lock, domain=self.domain_name)
        rs = ResetSynchronizer(rst_signal, domain=self.domain_name)

        m.submodules += [pll, rs]
        return m
Ejemplo n.º 4
0
    def elaborate(self, platform):
        m = Module()
        m.domains += ClockDomain('sync')
        m.submodules.ps = ps = PsZynqMP()

        clk = ps.get_clock_signal(0, 200e6)
        m.d.comb += ClockSignal().eq(clk)
        reset = ps.get_reset_signal(0)
        reset_sync = ResetSynchronizer(reset, domain="sync")
        m.submodules.reset_sync = reset_sync

        axi_ps = ps.get_axi('maxigp2')
        m.d.comb += axi_ps['ACLK'].eq(clk)
        axi_master = AxiMaster.from_record(axi_ps)

        axi2axil = Axi2AxiLite(data_w=32, addr_w=16, id_w=5, domain='sync')
        m.submodules.axi2axil = axi2axil
        m.d.comb += axi_master.connect(axi2axil.axi)

        xbar = AxiLiteXBar(data_w=32, addr_w=16, domain='sync')
        m.submodules.xbar = xbar
        xbar.add_master(axi2axil.axilite)

        for i in range(5):
            demo = DemoAxi(32, 16, 'sync')
            m.submodules['demo' + str(i)] = demo
            xbar.add_slave(demo.axilite, 0x1000 * i, 0x1000)

        return m
Ejemplo n.º 5
0
    def elaborate(self, platform):
        m = Module()
        m.domains += ClockDomain('sync')
        m.submodules.ps = ps = PsZynqMP()

        cnt = Signal(29)
        m.d.sync += cnt.eq(cnt + 1)
        m.d.comb += ps.get_irq_signal(0).eq(cnt[-1])

        clk = ps.get_clock_signal(0, 200e6)
        m.d.comb += ClockSignal('sync').eq(clk)

        reset = ps.get_reset_signal(0)
        reset_sync = ResetSynchronizer(reset, domain='sync')
        m.submodules.reset_sync = reset_sync
        return m
Ejemplo n.º 6
0
    def elaborate(self, platform):

        # coeff = self._calc_freq_coefficients()

        pll_lock = Signal()
        pll = Instance("SB_PLL40_PAD",
                       p_FEEDBACK_PATH='SIMPLE',
                       p_DIVR=self.coeff.divr,
                       p_DIVF=self.coeff.divf,
                       p_DIVQ=self.coeff.divq,
                       p_FILTER_RANGE=0b001,
                       i_PACKAGEPIN=self.clk_pin,
                       i_RESETB=Const(1),
                       i_BYPASS=Const(0),
                       o_PLLOUTGLOBAL=ClockSignal(self.domain_name),
                       o_LOCK=pll_lock)
        rs = ResetSynchronizer(~pll_lock, domain=self.domain_name)

        m = Module()
        m.submodules += [pll, rs]
        return m
Ejemplo n.º 7
0
    def elaborate(self, platform):
        pll_lock = Signal()
        pll = Instance(
            "SB_PLL40_CORE",
            p_FEEDBACK_PATH='SIMPLE',
            p_PLLOUT_SELECT='GENCLK',
            p_DIVR=self.coeff.divr,
            p_DIVF=self.coeff.divf,
            p_DIVQ=self.coeff.divq,
            p_FILTER_RANGE=0b001,
            i_REFERENCECLK=self.clk_pin,
            i_RESETB=Const(1),
            i_BYPASS=Const(0),
            o_PLLOUTCORE=ClockSignal(self.domain_name),
            o_LOCK=pll_lock,
        )

        rs = ResetSynchronizer(~pll_lock, domain=self.domain_name)

        m = Module()
        m.submodules += [pll, rs]
        return m
Ejemplo n.º 8
0
    def elaborate(self, platform):
        m = Module()

        if platform is not None:
            # platform.default_clk_frequency is in Hz
            coeff = self._calc_freq_coefficients(
                platform.default_clk_frequency / 1_000_000, self.freq_out)
            # clk_pin = platform.request(platform.default_clk)

            lock = Signal()

            pll = Instance(
                "SB_PLL40_CORE",
                p_FEEDBACK_PATH='SIMPLE',
                p_DIVR=coeff.divr,
                p_DIVF=coeff.divf,
                p_DIVQ=coeff.divq,
                p_FILTER_RANGE=0b001,
                p_DELAY_ADJUSTMENT_MODE_FEEDBACK='FIXED',
                p_FDA_FEEDBACK=0b0000,
                p_DELAY_ADJUSTMENT_MODE_RELATIVE='FIXED',
                p_FDA_RELATIVE=0b0000,
                p_SHIFTREG_DIV_MODE=0b00,
                p_PLLOUT_SELECT='GENCLK',
                p_ENABLE_ICEGATE=0b0,
                i_REFERENCECLK=ClockSignal(),
                o_PLLOUTCORE=ClockSignal(self.domain_name),
                i_RESETB=ResetSignal(),
                i_BYPASS=Const(0),
                o_LOCK=lock,
            )
            rs = ResetSynchronizer(~lock, domain=self.domain_name)

            m.submodules += [pll, rs]

        m.domains += ClockDomain(self.domain_name)

        return m
Ejemplo n.º 9
0
    def elaborate(self, platform):

        # coeff = self._calc_freq_coefficients()

        pll_lock = Signal()
        pll = Instance(
            "SB_PLL40_CORE",
            p_FEEDBACK_PATH='SIMPLE',
            p_DIVR=self.coeff.divr,
            p_DIVF=self.coeff.divf,
            p_DIVQ=self.coeff.divq,
            #p_FILTER_RANGE=0b001,
            i_REFERENCECLK=self.clk_pin,
            i_RESETB=Const(1),
            i_BYPASS=Const(0),
            o_PLLOUTCORE=ClockSignal(self.domain_name),
            o_LOCK=pll_lock)

        m = Module()
        m.submodules += pll
        m.domains.pll = self.domain
        m.submodules += ResetSynchronizer(~pll_lock, domain=self.domain_name)
        return m
Ejemplo n.º 10
0
    def elaborate(self, platform):

        # coeff = self._calc_freq_coefficients()

        pll_lock = Signal()
        clk_out = Signal()
        pll = Instance("SB_PLL40_CORE",
                       p_FEEDBACK_PATH='SIMPLE',
                       p_DIVR=self.coeff.divr,
                       p_DIVF=self.coeff.divf,
                       p_DIVQ=self.coeff.divq,
                       p_FILTER_RANGE=0b001,
                       i_REFERENCECLK=self.clk_pin,
                       i_RESETB=Const(1),
                       i_BYPASS=Const(0),
                       o_PLLOUTGLOBAL=clk_out,
                       o_LOCK=pll_lock)

        m = Module()
        platform.add_clock_constraint(clk_out, self.freq_out * 1e6)
        m.d.comb += ClockSignal(self.domain_name).eq(clk_out)
        m.submodules += pll
        m.submodules += ResetSynchronizer(~pll_lock, domain=self.domain_name)
        return m
Ejemplo n.º 11
0
    def elaborate(self, platform):
        clk_fb = Signal()
        locked = Signal()
        mmcm = Instance(
            "MMCME2_BASE",
            p_BANDWIDTH="OPTIMIZED",  # Jitter programming (OPTIMIZED, HIGH, LOW)
            p_CLKFBOUT_MULT_F=37.125,  # Multiply value for all CLKOUT (2.000-64.000).
            p_CLKFBOUT_PHASE=0.0,  # Phase offset in degrees of CLKFB (-360.000-360.000).
            p_CLKIN1_PERIOD=10.0,  # Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz).
            # CLKOUT0_DIVIDE - CLKOUT6_DIVIDE: Divide amount for each CLKOUT (1-128)
            p_CLKOUT1_DIVIDE=4,
            p_CLKOUT0_DIVIDE_F=6.250,  # Divide amount for CLKOUT0 (1.000-128.000).
            # CLKOUT0_DUTY_CYCLE - CLKOUT6_DUTY_CYCLE: Duty cycle for each CLKOUT (0.01-0.99).
            p_CLKOUT0_DUTY_CYCLE=0.5,
            # CLKOUT0_PHASE - CLKOUT6_PHASE: Phase offset for each CLKOUT (-360.000-360.000).
            p_CLKOUT0_PHASE=0.0,
            p_CLKOUT4_CASCADE="FALSE",  # Cascade CLKOUT4 counter with CLKOUT6 (FALSE, TRUE)
            p_DIVCLK_DIVIDE=4,  # Master division value (1-106)
            p_REF_JITTER1=0.0,  # Reference input jitter in UI (0.000-0.999).
            p_STARTUP_WAIT="TRUE",  # Delays DONE until MMCM is locked (FALSE, TRUE)
            # Clock Outputs: 1-bit (each) output: User configurable clock outputs
            o_CLKOUT0=ClockSignal("pxl"),  # 1-bit output: CLKOUT0
            # Feedback Clocks: 1-bit (each) output: Clock feedback ports
            o_CLKFBOUT=clk_fb,  # 1-bit output: Feedback clock0
            # Status Ports: 1-bit (each) output: MMCM status ports
            o_LOCKED=locked,  # 1-bit output: LOCK
            # Clock Inputs: 1-bit (each) input: Clock input
            i_CLKIN1=ClockSignal(),  # 1-bit input: Clock
            # Control Ports: 1-bit (each) input: MMCM control ports
            i_PWRDWN=Const(0),  # 1-bit input: Power-down
            i_RST=ResetSignal(),  # 1-bit input: Reset
            # Feedback Clocks: 1-bit (each) input: Clock feedback ports
            i_CLKFBIN=clk_fb,  # 1-bit input: Feedback clock
        )

        m = Module()

        m.submodules.mmcm = mmcm
        m.submodules.rs = ResetSynchronizer(~locked, domain="pxl")

        # Create pxl clock domain
        m.domains.pxl = ClockDomain("pxl", local=True)

        x_max = 2200 - 1
        y_max = 1125 - 1
        x = Signal(range(x_max))
        y = Signal(range(y_max))

        with m.If(x == x_max):
            m.d.pxl += x.eq(0)
            m.d.pxl += y.eq(Mux(y == y_max, 0, y + 1))
        with m.Else():
            m.d.pxl += x.eq(x + 1)

        vgapmod = platform.request("vgapmod")

        with m.If((y < 1080) & (x < 1920)):
            lfsr = Signal(21, reset=688348)  # xnor taps at 21,19
            m.d.pxl += [
                lfsr.eq(Cat((lfsr >> 1)[:20], (lfsr[0] == lfsr[2]))),
            ]
            rnd = lfsr[:4]
            with m.If(x < 640 - 8 + rnd):
                m.d.comb += [vgapmod.r.eq(0), vgapmod.g.eq(0), vgapmod.b.eq(rnd)]
            with m.Elif(x < 640 + 640 - 8 + rnd):
                m.d.comb += [
                    vgapmod.r.eq(rnd),
                    vgapmod.g.eq(rnd),
                    vgapmod.b.eq(rnd),
                ]
            with m.Elif(x < 640 + 640 + 640):
                m.d.comb += [vgapmod.r.eq(rnd), vgapmod.g.eq(0), vgapmod.b.eq(0)]

        m.d.pxl += [
            vgapmod.hsync.eq((x >= 1920 + 88) & (x < 1920 + 88 + 44)),
            vgapmod.vsync.eq((y >= 1080 + 4) & (y < 1080 + 4 + 5)),
        ]

        return m
Ejemplo n.º 12
0
    def elaborate(self, platform):
        m = Module()

        # The ECP5 SerDes uses a simple feedback mechanism to keep its FIFO clocks in sync
        # with the FPGA's fabric. Accordingly, we'll need to capture the output clocks and then
        # pass them back to the SerDes; this allows the placer to handle clocking correctly, allows us
        # to attach clock constraints for analysis, and allows us to use these clocks for -very- simple tasks.
        txoutclk = Signal()
        rxoutclk = Signal()

        # Internal state.
        rx_los = Signal()
        rx_lol = Signal()
        rx_lsm = Signal()
        rx_align = Signal()
        rx_bus = Signal(24)

        tx_lol = Signal()
        tx_bus = Signal(24)

        #
        # Clock domain crossing.
        #
        tx_produce_square_wave = Signal()
        tx_produce_pattern = Signal()
        tx_pattern = Signal(20)

        m.submodules += [
            # Transmit control  synchronization.
            FFSynchronizer(self.tx_produce_square_wave,
                           tx_produce_square_wave,
                           o_domain="tx"),
            FFSynchronizer(self.tx_produce_pattern,
                           tx_produce_pattern,
                           o_domain="tx"),
            FFSynchronizer(self.tx_pattern, tx_pattern, o_domain="tx"),

            # Receive control synchronization.
            FFSynchronizer(self.rx_align, rx_align, o_domain="rx"),
            FFSynchronizer(rx_los, self.rx_idle, o_domain="sync"),
        ]

        #
        # Clocking / reset control.
        #

        # The SerDes needs to be brought up gradually; we'll do that here.
        m.submodules.reset_sequencer = reset = ECP5ResetSequencer()
        m.d.comb += [
            reset.tx_pll_locked.eq(~tx_lol),
            reset.rx_pll_locked.eq(~rx_lol)
        ]

        # Create a local transmit domain, for our transmit-side hardware.
        m.domains.tx = ClockDomain()
        m.d.comb += ClockSignal("tx").eq(txoutclk)
        m.submodules += [
            ResetSynchronizer(ResetSignal("sync"), domain="tx"),
            FFSynchronizer(~ResetSignal("tx"), self.tx_ready)
        ]

        # Create the same setup, buf for the receive side.
        m.domains.rx = ClockDomain()
        m.d.comb += ClockSignal("rx").eq(rxoutclk)
        m.submodules += [
            ResetSynchronizer(ResetSignal("sync"), domain="rx"),
            FFSynchronizer(~ResetSignal("rx"), self.rx_ready)
        ]

        #
        # Core SerDes instantiation.
        #
        serdes_params = dict(
            # DCU — power management
            p_D_MACROPDB="0b1",
            p_D_IB_PWDNB="0b1",  # undocumented (required for RX)
            p_D_TXPLL_PWDNB="0b1",
            i_D_FFC_MACROPDB=1,

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

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

            # Clock multiplier unit configuration
            p_D_CMUSETBIASI=
            "0b00",  # begin undocumented (10BSER sample code used)
            p_D_CMUSETI4CPP="0d3",
            p_D_CMUSETI4CPZ="0d3",
            p_D_CMUSETI4VCO="0b00",
            p_D_CMUSETICP4P="0b01",
            p_D_CMUSETICP4Z="0b101",
            p_D_CMUSETINITVCT="0b00",
            p_D_CMUSETISCL4VCO="0b000",
            p_D_CMUSETP1GM="0b000",
            p_D_CMUSETP2AGM="0b000",
            p_D_CMUSETZGM="0b000",
            p_D_SETIRPOLY_AUX="0b01",
            p_D_SETICONST_AUX="0b01",
            p_D_SETIRPOLY_CH="0b01",
            p_D_SETICONST_CH="0b10",
            p_D_SETPLLRC="0d1",
            p_D_RG_EN="0b0",
            p_D_RG_SET="0b00",
            p_D_REQ_ISET="0b011",
            p_D_PD_ISET="0b11",  # end undocumented

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

            # CHX common ---------------------------------------------------------------------------
            # CHX — protocol
            p_CHX_PROTOCOL="10BSER",
            p_CHX_UC_MODE="0b1",
            p_CHX_ENC_BYPASS="******",  # Use the 8b10b encoder
            p_CHX_DEC_BYPASS="******",  # Use the 8b10b decoder

            # 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 | reset.serdes_rx_reset,
            i_CHX_FFC_LANE_RX_RST=~self.rx_enable | reset.pcs_reset,

            # CHX RX ­— input
            i_CHX_HDINP=self._rx_pads.p,
            i_CHX_HDINN=self._rx_pads.n,
            p_CHX_REQ_EN="0b1",  # Enable equalizer
            p_CHX_REQ_LVL_SET="0b01",
            p_CHX_RX_RATE_SEL="0d09",  # 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",
                "wizard-50-ohms": "0d22"
            }["wizard-50-ohms"],
            p_CHX_RXIN_CM="0b11",  # CMFB (wizard value used)
            p_CHX_RXTERM_CM="0b10",  # RX Input (wizard value used)

            # CHX RX ­— clocking
            i_CHX_RX_REFCLK=self._pll.refclk,
            o_CHX_FF_RX_PCLK=rxoutclk,
            i_CHX_FF_RXI_CLK=ClockSignal("rx"),
            p_CHX_CDR_MAX_RATE="5.0",  # 5.0 Gbps
            p_CHX_RX_DCO_CK_DIV={
                32: "0b111",
                16: "0b110",
                8: "0b101",
                4: "0b100",
                2: "0b010",
                1: "0b000"
            }[1],  # DIV/1
            p_CHX_RX_GEAR_MODE="0b1",  # 1:2 gearbox
            p_CHX_FF_RX_H_CLK_EN="0b1",  # enable  DIV/2 output clock
            p_CHX_FF_RX_F_CLK_DIS="0b1",  # disable DIV/1 output clock
            p_CHX_SEL_SD_RX_CLK="0b1",  # FIFO driven by recovered clock
            p_CHX_AUTO_FACQ_EN="0b1",  # undocumented (wizard value used)
            p_CHX_AUTO_CALIB_EN="0b1",  # undocumented (wizard value used)
            p_CHX_PDEN_SEL="0b0",  # phase detector disabled on LOS
            p_CHX_DCOATDCFG="0b00",  # begin undocumented (sample code used)
            p_CHX_DCOATDDLY="0b00",
            p_CHX_DCOBYPSATD="0b1",
            p_CHX_DCOCALDIV="0b000",
            p_CHX_DCOCTLGI="0b011",
            p_CHX_DCODISBDAVOID="0b0",
            p_CHX_DCOFLTDAC="0b00",
            p_CHX_DCOFTNRG="0b001",
            p_CHX_DCOIOSTUNE="0b010",
            p_CHX_DCOITUNE="0b00",
            p_CHX_DCOITUNE4LSB="0b010",
            p_CHX_DCOIUPDNX2="0b1",
            p_CHX_DCONUOFLSB="0b100",
            p_CHX_DCOSCALEI="0b01",
            p_CHX_DCOSTARTVAL="0b010",
            p_CHX_DCOSTEP="0b11",  # end undocumented

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

            # CHX RX — loss of lock
            o_CHX_FFS_RLOL=rx_lol,

            # CHX RX — link state machine
            # Note that Lattice Diamond needs these in their provided bases (and string lengths!).
            # Changing their bases will work with the open toolchain, but will make Diamond mad.
            i_CHX_FFC_SIGNAL_DETECT=rx_align,
            o_CHX_FFS_LS_SYNC_STATUS=rx_lsm,
            p_CHX_ENABLE_CG_ALIGN="0b1",
            p_CHX_UDF_COMMA_MASK="0x0ff",  # compare the 8 lsbs
            p_CHX_UDF_COMMA_A=
            "0x003",  # "0b0000000011", # K28.1, K28.5 and K28.7
            p_CHX_UDF_COMMA_B=
            "0x07c",  # "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(len(rx_bus))},

            # 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 | reset.serdes_tx_reset,
            i_CHX_FFC_LANE_TX_RST=~self.tx_enable | reset.pcs_reset,

            # CHX TX ­— output
            o_CHX_HDOUTP=self._tx_pads.p,
            o_CHX_HDOUTN=self._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",
                "wizard-50-ohms": "0d19"
            }["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=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(len(tx_bus))},

            # SCI interface.
            #**{"i_D_SCIWDATA%d" % n: sci.sci_wdata[n] for n in range(8)},
            #**{"i_D_SCIADDR%d"   % n: sci.sci_addr[n] for n in range(6)},
            #**{"o_D_SCIRDATA%d" % n: sci.sci_rdata[n] for n in range(8)},
            #i_D_SCIENAUX  = sci.dual_sel,
            #i_D_SCISELAUX = sci.dual_sel,
            #i_CHX_SCIEN   = sci.chan_sel,
            #i_CHX_SCISEL  = sci.chan_sel,
            #i_D_SCIRD     = sci.sci_rd,
            #i_D_SCIWSTN   = sci.sci_wrn,

            # Out-of-band signaling Rx support.
            p_CHX_LDR_RX2CORE_SEL="0b1",  # Enables low-speed out-of-band input.
            o_CHX_LDR_RX2CORE=self.rx_gpio,

            # Out-of-band signaling Tx support.
            p_CHX_LDR_CORE2TX_SEL=
            "0b0",  # Uses CORE2TX_EN to enable out-of-band output.
            i_CHX_LDR_CORE2TX=self.tx_gpio,
            i_CHX_FFC_LDR_CORE2TX_EN=self.tx_gpio_en)

        # Translate the 'CHX' string to the correct channel name in each of our SerDes parameters,
        # and create our SerDes instance.
        serdes_params = {
            k.replace("CHX", f"CH{self._channel}"): v
            for (k, v) in serdes_params.items()
        }
        m.submodules.serdes = serdes = Instance("DCUA", **serdes_params)

        # Bind our SerDes to the correct location inside the FPGA.
        serdes.attrs["LOC"] = "DCU{}".format(self._dual)
        serdes.attrs["CHAN"] = "CH{}".format(self._channel)
        serdes.attrs["BEL"] = "X42/Y71/DCU"

        #
        # TX and RX datapaths (SerDes <-> stream conversion)
        #
        sink = self.sink
        source = self.source

        m.d.comb += [
            # Grab our received data directly from our SerDes; modifying things to match the
            # SerDes Rx bus layout, which squishes status signals between our two geared words.
            source.data[0:8].eq(rx_bus[0:8]),
            source.data[8:16].eq(rx_bus[12:20]),
            source.ctrl[0].eq(rx_bus[8]),
            source.ctrl[1].eq(rx_bus[20]),
            source.valid.eq(1),

            # Stick the data we'd like to transmit into the SerDes; again modifying things to match
            # the transmit bus layout.
            tx_bus[0:8].eq(sink.data[0:8]),
            tx_bus[12:20].eq(sink.data[8:16]),
            tx_bus[8].eq(sink.ctrl[0]),
            tx_bus[20].eq(sink.ctrl[1]),
            sink.ready.eq(1)
        ]

        return m
Ejemplo n.º 13
0
    def elaborate(self, platform):
        m = Module()

        # Create clock out signals
        self.clk = {cfg.cd_name: Signal() for cfg in self.clock_config}
        self._pll_lock = Signal()

        # Create our clock domains.
        for cfg in self.clock_config:
            m.domains += ClockDomain(cfg.cd_name)
            m.d.comb += ClockSignal(domain=cfg.cd_name).eq(self.clk[cfg.cd_name])
            m.submodules += ResetSynchronizer(~self._pll_lock, domain=cfg.cd_name)

        # Grab our input clock
        clock_name = self.clock_name if self.clock_name else platform.default_clk
        
        try:
            self.clkin_frequency = platform.lookup(clock_name).clock.frequency / 1e6
            input_clock_pin = platform.request(clock_name)
        except:
            input_clock_pin = ClockSignal(clock_name)
            # TODO: Make this nicer, remove clock_signal_freq
            self.clkin_frequency = self.clock_signal_freq / 1e6

        # Calculate configuration parameters
        params = self.calc_pll_params(self.clkin_frequency, self.clock_config[0].freq)
        if len(self.clock_config) > 1:
            self.generate_secondary_output(params, 0, self.clock_config[1].freq, self.clock_config[1].phase)
        if len(self.clock_config) > 2:
            self.generate_secondary_output(params, 1, self.clock_config[2].freq, self.clock_config[2].phase)
        if len(self.clock_config) > 3:
            self.generate_secondary_output(params, 2, self.clock_config[3].freq, self.clock_config[3].phase)

        for i, p in enumerate([
                params,
                params["secondary"][0],
                params["secondary"][1],
                params["secondary"][2]
            ]):
            if p["error"] > 0:
                logger.warning("ClockDomain {} has an error of {:.3f} MHz ({} instead of {})"
                    .format(self.clock_config[i].cd_name, p["error"], p["freq"], p["freq_requested"]))
                if not self.skip_checks:
                    assert(p["error"] <= self.clock_config[i].error)

        m.submodules.pll = Instance("EHXPLLL",
            # Clock in.
            i_CLKI=input_clock_pin,

            # Generated clock outputs.
            o_CLKOP=self.clk[self.clock_config[0].cd_name],
            o_CLKOS=self.clk[self.clock_config[1].cd_name] if len(self.clock_config) > 1 else Signal(),
            o_CLKOS2=self.clk[self.clock_config[2].cd_name] if len(self.clock_config) > 2 else Signal(),
            o_CLKOS3=self.clk[self.clock_config[3].cd_name] if len(self.clock_config) > 3 else Signal(),

            # Status.
            o_LOCK=self._pll_lock,

            # PLL parameters...
            p_PLLRST_ENA="DISABLED",
            p_INTFB_WAKE="DISABLED",
            p_STDBY_ENABLE="DISABLED",
            p_DPHASE_SOURCE="DISABLED",

            p_OUTDIVIDER_MUXA="DIVA",
            p_OUTDIVIDER_MUXB="DIVB",
            p_OUTDIVIDER_MUXC="DIVC",
            p_OUTDIVIDER_MUXD="DIVD",

            p_CLKI_DIV=params["refclk_div"],
            p_CLKOP_ENABLE="ENABLED",
            p_CLKOP_DIV=params["output_div"],
            p_CLKOP_CPHASE=params["primary_cphase"],
            p_CLKOP_FPHASE=0,

            p_CLKOS_ENABLE="ENABLED" if params["secondary"][0]["enabled"] else "DISABLED",
            p_CLKOS_FPHASE=params["secondary"][0]["fphase"],
            p_CLKOS_CPHASE=params["secondary"][0]["cphase"],
            p_CLKOS_DIV=params["secondary"][0]["div"],

            p_CLKOS2_ENABLE="ENABLED" if params["secondary"][1]["enabled"] else "DISABLED",
            p_CLKOS2_FPHASE=params["secondary"][1]["fphase"],
            p_CLKOS2_CPHASE=params["secondary"][1]["cphase"],
            p_CLKOS2_DIV=params["secondary"][1]["div"],

            p_CLKOS3_ENABLE="ENABLED" if params["secondary"][2]["enabled"] else "DISABLED",
            p_CLKOS3_FPHASE=params["secondary"][2]["fphase"],
            p_CLKOS3_CPHASE=params["secondary"][2]["cphase"],
            p_CLKOS3_DIV=params["secondary"][2]["div"],

            p_FEEDBK_PATH="CLKOP", # TODO: external feedback
            p_CLKFB_DIV=params["feedback_div"],

            # Internal feedback.
            i_CLKFB=self.clk[self.clock_config[0].cd_name],

            # TODO: Reset
            i_RST=0,

            # TODO: Standby
            i_STDBY=0,

            # TODO: Dynamic mode
            i_PHASESEL0=0,
            i_PHASESEL1=0,
            i_PHASEDIR=0,
            i_PHASESTEP=0,
            i_PHASELOADREG=0,

            i_PLLWAKESYNC=0,

            # Output Enables.
            i_ENCLKOP=0,
            i_ENCLKOS=0,
            i_ENCLKOS2=0,
            i_ENCLKOS3=0,

            # Synthesis attributes.
            a_FREQUENCY_PIN_CLKI=str(self.clkin_frequency),
            a_FREQUENCY_PIN_CLKOP=str(self.clock_config[0].freq),
            a_FREQUENCY_PIN_CLKOS=str(self.clock_config[1].freq) if len(self.clock_config) > 1 else "0",
            a_FREQUENCY_PIN_CLKOS2=str(self.clock_config[2].freq) if len(self.clock_config) > 2 else "0",
            a_FREQUENCY_PIN_CLKOS3=str(self.clock_config[3].freq) if len(self.clock_config) > 3 else "0",
            a_ICP_CURRENT="12",
            a_LPF_RESISTOR="8",
            a_MFG_ENABLE_FILTEROPAMP="1",
            a_MFG_GMCREF_SEL="2",
        )
        return m