Permalink
Please sign in to comment.
| @@ -0,0 +1,114 @@ | ||
| """ | ||
| Clock Abstraction Modules | ||
| Made in Paris-CDG while waiting a delayed Air-France KLM flight... | ||
| """ | ||
| from migen import * | ||
| from migen.genlib.io import DifferentialInput | ||
| from migen.genlib.resetsync import AsyncResetSynchronizer | ||
| # TODO: | ||
| # - add S7PLL support for all family/speedgrades (currently Artix7 -3 speedgrade) | ||
| # - add S7MMCM support (should be very similar to S7PLL) | ||
| def period_ns(freq): | ||
| return 1e9/freq | ||
| class S7PLL(Module): | ||
| nclkouts_max = 6 | ||
| clkin_freq_range = (10e6, 800e6) | ||
| vco_freq_range = (600e6, 1600e6) | ||
| clkfbout_mult_frange = (2, 64+1) | ||
| clkout_divide_range = (1, 128+1) | ||
| def __init__(self): | ||
| self.reset = Signal() | ||
| self.locked = Signal() | ||
| self.clkin_freq = None | ||
| self.vcxo_freq = None | ||
| self.nclkouts = 0 | ||
| self.clkouts = {} | ||
| self.config = {} | ||
| def register_clkin(self, clkin, freq): | ||
| self.clkin = Signal() | ||
| if isinstance(clkin, Signal): | ||
| self.comb += self.clkin.eq(clkin) | ||
| elif isinstance(clkin, Record): | ||
| self.specials += DifferentialInput(clkin.p, clkin.n, self.clkin) | ||
| else: | ||
| raise ValueError | ||
| self.clkin_freq = freq | ||
| def create_clkout(self, cd, freq, phase=0): | ||
| assert self.nclkouts < self.nclkouts_max | ||
| clkout = Signal() | ||
| clkout_bufg = Signal() | ||
| self.specials += AsyncResetSynchronizer(cd, ~self.locked | self.reset), | ||
| self.specials += Instance("BUFG", i_I=clkout, o_O=clkout_bufg) | ||
| self.comb += cd.clk.eq(clkout_bufg) | ||
| self.clkouts[self.nclkouts] = (clkout, freq, phase) | ||
| self.nclkouts += 1 | ||
| return clkout_bufg | ||
| def compute_config(self): | ||
| config = {} | ||
| config["divclk_divide"] = 1 | ||
| for clkfbout_mult in range(*self.clkfbout_mult_frange): | ||
| all_valid = True | ||
| vco_freq = self.clkin_freq*clkfbout_mult | ||
| (vco_freq_min, vco_freq_max) = self.vco_freq_range | ||
| if vco_freq >= vco_freq_min and vco_freq <= vco_freq_max: | ||
| for n, (clk, f, p) in sorted(self.clkouts.items()): | ||
| valid = False | ||
| for d in range(*self.clkout_divide_range): | ||
| clk_freq = vco_freq/d | ||
| if clk_freq == f: | ||
| config["clkout{}_divide".format(n)] = d | ||
| config["clkout{}_phase".format(n)] = p | ||
| valid = True | ||
| break | ||
| if not valid: | ||
| all_valid = False | ||
| else: | ||
| all_valid = False | ||
| if all_valid: | ||
| config["vco"] = vco_freq | ||
| config["clkfbout_mult"] = clkfbout_mult | ||
| return config | ||
| raise ValueError("No PLL config found") | ||
| def add_idelayctrl(self, cd): | ||
| reset_counter = Signal(4, reset=15) | ||
| ic_reset = Signal(reset=1) | ||
| sync = getattr(self.sync, cd.name) | ||
| sync += \ | ||
| If(reset_counter != 0, | ||
| reset_counter.eq(reset_counter - 1) | ||
| ).Else( | ||
| ic_reset.eq(0) | ||
| ) | ||
| self.specials += Instance("IDELAYCTRL", i_REFCLK=cd.clk, i_RST=ic_reset) | ||
| def do_finalize(self): | ||
| assert hasattr(self, "clkin") | ||
| config = self.compute_config() | ||
| pll_fb = Signal() | ||
| pll_params = dict( | ||
| p_STARTUP_WAIT="FALSE", o_LOCKED=self.locked, | ||
| # VCO | ||
| p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=period_ns(self.clkin_freq), | ||
| p_CLKFBOUT_MULT=config["clkfbout_mult"], p_DIVCLK_DIVIDE=config["divclk_divide"], | ||
| i_CLKIN1=self.clkin, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, | ||
| ) | ||
| for n, (clk, f, p) in sorted(self.clkouts.items()): | ||
| pll_params["p_CLKOUT{}_DIVIDE".format(n)] = config["clkout{}_divide".format(n)] | ||
| pll_params["p_CLKOUT{}_PHASE".format(n)] = config["clkout{}_phase".format(n)] | ||
| pll_params["o_CLKOUT{}".format(n)] = clk | ||
| self.specials += Instance("PLLE2_BASE", **pll_params) |
0 comments on commit
63fc395