From: Luke Kenneth Casson Leighton Date: Sun, 20 Mar 2022 11:34:42 +0000 (+0000) Subject: first cut at Arty A7 Clock-Reset-Generator with S7 PLL X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7601689cf6f027a5a2866011b2df61bb0bcdac59;p=ls2.git first cut at Arty A7 Clock-Reset-Generator with S7 PLL --- diff --git a/src/arty_crg.py b/src/arty_crg.py index 58a5024..e1a7c65 100644 --- a/src/arty_crg.py +++ b/src/arty_crg.py @@ -11,6 +11,8 @@ from nmigen import (Elaboratable, Module, Signal, ClockDomain, Instance, ClockSignal, ResetSignal) +from nmigen.lib.cdc import ResetSynchronizer +import math __ALL__ = ["ArtyCRG"] @@ -26,13 +28,15 @@ def clkdiv_range(start, stop, step=1): yield int(current) if math.floor(current) == current else current current += step + # Xilinx / Generic ----------------------------------------------------- -class XilinxClocking(Module): +class XilinxClocking(Elaboratable): clkfbout_mult_frange = (2, 64+1) clkout_divide_range = (1, 128+1) - def __init__(self, vco_margin=0): + def __init__(self, clkin, vco_margin=0): + self.clkin = clkin self.vco_margin = vco_margin self.reset = Signal() self.locked = Signal() @@ -43,48 +47,56 @@ class XilinxClocking(Module): self.config = {} self.params = {} - def register_clkin(self, clkin, freq): - self.clkin = Signal() - if isinstance(clkin, (Signal, ClockSignal)): - self.comb += self.clkin.eq(clkin) - elif isinstance(clkin, Record): - self.specials += DifferentialInput(clkin.p, clkin.n, self.clkin) - else: - raise ValueError + def set_clkin_freq(self, freq): self.clkin_freq = freq - register_clkin_log(self.logger, clkin, freq) def create_clkout(self, cd, freq, phase=0, buf="bufg", margin=1e-2, with_reset=True, ce=None): assert self.nclkouts < self.nclkouts_max clkout = Signal() - self.clkouts[self.nclkouts] = (clkout, freq, phase, margin) - if with_reset: - self.specials += AsyncResetSynchronizer(cd, ~self.locked | - self.reset) - if buf is None: - self.comb += cd.clk.eq(clkout) - else: - clkout_buf = Signal() - self.comb += cd.clk.eq(clkout_buf) - if buf == "bufg": - self.specials += Instance("BUFG", i_I=clkout, o_O=clkout_buf) - elif buf == "bufr": - self.specials += Instance("BUFR", i_I=clkout, o_O=clkout_buf) - elif buf == "bufgce": - if ce is None: - raise ValueError("BUFGCE requires user to provide " - "a clock enable ce Signal") - self.specials += Instance("BUFGCE", i_I=clkout, - o_O=clkout_buf, i_CE=ce) - elif buf == "bufio": - self.specials += Instance("BUFIO", i_I=clkout, - o_O=clkout_buf) + self.clkouts[self.nclkouts] = (clkout, freq, phase, margin, cd, + buf, with_reset, ce) + + def elaborate(self, platform): + assert self.clkin_freq is not None + m = Module() + comb = m.d.comb + for n, clkcfg in self.clkouts.items(): + (clkout, freq, phase, margin, cd, buf, with_reset, ce) = clkcfg + if with_reset: + arst = Signal() + m.submodules += ResetSynchronizer(arst, domain=cd.name) + comb += arst.eq(~self.locked | self.reset) + if buf is None: + comb += cd.clk.eq(clkout) else: - raise ValueError("Unsupported clock buffer: {}".format(buf)) - create_clkout_log(self.logger, cd.name, freq, margin, self.nclkouts) - self.nclkouts += 1 - assert hasattr(self, "clkin") + clkout_buf = Signal() + comb += cd.clk.eq(clkout_buf) + if buf == "bufg": + m.submodules += Instance("BUFG", + i_I=clkout, + o_O=clkout_buf) + elif buf == "bufr": + m.submodules += Instance("BUFR", + i_I=clkout, + o_O=clkout_buf) + elif buf == "bufgce": + if ce is None: + raise ValueError("BUFGCE requires user to provide " + "a clock enable ce Signal") + m.submodules += Instance("BUFGCE", + i_I=clkout, + o_O=clkout_buf, + i_CE=ce) + elif buf == "bufio": + m.submodules += Instance("BUFIO", + i_I=clkout, + o_O=clkout_buf) + else: + raise ValueError("Unsupported clock buffer: %s" % buf) + print(cd.name, freq, margin, self.nclkouts) + + return m def compute_config(self): config = {} @@ -99,7 +111,8 @@ class XilinxClocking(Module): (vco_freq_min, vco_freq_max) = self.vco_freq_range if (vco_freq >= vco_freq_min*(1 + self.vco_margin) and vco_freq <= vco_freq_max*(1 - self.vco_margin)): - for n, (clk, f, p, m) in sorted(self.clkouts.items()): + for n, clkcfg in sorted(self.clkouts.items()): + (clkout, f, p, m, _, _, _, _) = clkcfg valid = False d_ranges = [self.clkout_divide_range] r = getattr(self, "clkout%d_divide_range" % n, None) @@ -123,7 +136,7 @@ class XilinxClocking(Module): if all_valid: config["vco"] = vco_freq config["clkfbout_mult"] = clkfbout_mult - compute_config_log(self.logger, config) + print(config) return config raise ValueError("No PLL config found") @@ -134,10 +147,10 @@ class S7PLL(XilinxClocking): nclkouts_max = 6 clkin_freq_range = (19e6, 800e6) - def __init__(self, speedgrade=-1): + def __init__(self, clkin, speedgrade=-1): + super().__init__(clkin) #self.logger = logging.getLogger("S7PLL") print ("Creating S7PLL, speedgrade %d" % speedgrade) - XilinxClocking.__init__(self) self.divclk_divide_range = (1, 56+1) self.vco_freq_range = { -1: (800e6, 1600e6), @@ -145,8 +158,8 @@ class S7PLL(XilinxClocking): -3: (800e6, 2133e6), }[speedgrade] - def do_finalize(self): - XilinxClocking.do_finalize(self) + def elaborate(self, platform): + m = super().elaborate(platform) config = self.compute_config() pll_fb = Signal() self.params.update( @@ -158,14 +171,14 @@ class S7PLL(XilinxClocking): p_DIVCLK_DIVIDE=config["divclk_divide"], i_CLKIN1=self.clkin, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, ) - for n, (clk, f, p, m) in sorted(self.clkouts.items()): - self.params["p_CLKOUT{}_DIVIDE".format(n)] = \ - config["clkout{}_divide".format(n)] - self.params["p_CLKOUT{}_PHASE".format(n)] = \ - config["clkout{}_phase".format(n)] + for n, (clk, f, p, _, _, _, _, _) in sorted(self.clkouts.items()): + div = config["clkout{}_divide".format(n)] + phs = config["clkout{}_phase".format(n)] + self.params["p_CLKOUT{}_DIVIDE".format(n)] = div + self.params["p_CLKOUT{}_PHASE".format(n)] = phs self.params["o_CLKOUT{}".format(n)] = clk - self.specials += Instance("PLLE2_ADV", **self.params) - + m.submodules += Instance("PLLE2_ADV", **self.params) + return m class ECP5PLL(Elaboratable): @@ -341,7 +354,7 @@ class ArtyA7CRG(Elaboratable): #cd_clk200 = ClockDomain("cd_clk200") #cd_eth = ClockDomain("cd_eth") dramsync = ClockDomain("dramsync") - + m.domains += sync #m.domains += sync2x #m.domains += sync4x @@ -349,26 +362,28 @@ class ArtyA7CRG(Elaboratable): #m.domains += cd_clk200 #m.domains += cd_eth m.domains += dramsync - + clk100_ibuf = Signal() clk100_buf = Signal() m.submodules += [ - Instance("IBUF", i_I=ckl100, o_O=clk100_ibuf), + Instance("IBUF", i_I=clk100, o_O=clk100_ibuf), Instance("BUFG", i_I=clk100_ibuf, o_O=clk100_buf) ] - self.submodules.pll = pll = S7PLL(speedgrade=-1) + m.submodules.pll = pll = S7PLL(clk100_buf, speedgrade=-1) reset = platform.request(platform.default_rst).i - self.comb += pll.reset.eq(~reset) - pll.register_clkin(clk100_buf, 100e6) - pll.create_clkout(self.sync, sys_clk_freq) + m.d.comb += pll.reset.eq(~reset) + pll.set_clkin_freq(100e6) - platform.add_period_constraint(clk100_buf, 1e9/100e6) - platform.add_period_constraint(sync.clk, 1e9/sys_clk_freq) - platform.add_false_path_constraints(clk100_buf, sync.clk) + pll.create_clkout(sync, self.sys_clk_freq) + + #platform.add_period_constraint(clk100_buf, 1e9/100e6) + #platform.add_period_constraint(sync.clk, 1e9/sys_clk_freq) + #platform.add_false_path_constraints(clk100_buf, sync.clk) # temporarily set dram sync clock exactly equal to main sync m.d.comb += ClockSignal("dramsync").eq(ClockSignal("sync")) + return m class ECPIX5CRG(Elaboratable): diff --git a/src/ls2.py b/src/ls2.py index 1968aa7..5e0997d 100644 --- a/src/ls2.py +++ b/src/ls2.py @@ -52,6 +52,7 @@ from nmigen_boards.test.blinky import Blinky from icarusversa import IcarusVersaPlatform # Clock-Reset Generator (works for all ECP5 platforms) from crg import ECPIX5CRG +from arty_crg import ArtyA7CRG import sys import os @@ -273,7 +274,7 @@ class DDR3SoC(SoC, Elaboratable): if fpga in ['versa_ecp5', 'versa_ecp5_85', 'isim']: self.crg = ECPIX5CRG(clk_freq) if fpga in ['arty_a7']: - self.crg = ArtyCRG(clk_freq) + self.crg = ArtyA7CRG(clk_freq) # set up CPU, with 64-to-32-bit downconverters if add_cpu: