From d89d6dfd0a569eb7868e5735f9f6e7fb1be3c3e6 Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Sat, 1 Oct 2022 12:28:32 -0500 Subject: [PATCH 1/3] soc/cores/clock/intel_common: cleanup --- litex/soc/cores/clock/intel_common.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/litex/soc/cores/clock/intel_common.py b/litex/soc/cores/clock/intel_common.py index 513c22cb2..4e5eabd3a 100644 --- a/litex/soc/cores/clock/intel_common.py +++ b/litex/soc/cores/clock/intel_common.py @@ -115,10 +115,10 @@ class IntelClocking(Module, AutoCSR): o_LOCKED = self.locked, ) for n, (clk, f, p, m) in sorted(self.clkouts.items()): - clk_phase_ps = int((1e12/config["clk{}_freq".format(n)])*config["clk{}_phase".format(n)]/360) - self.params["p_CLK{}_DIVIDE_BY".format(n)] = config["clk{}_divide".format(n)] - self.params["p_CLK{}_DUTY_CYCLE".format(n)] = 50 - self.params["p_CLK{}_MULTIPLY_BY".format(n)] = config["m"] - self.params["p_CLK{}_PHASE_SHIFT".format(n)] = clk_phase_ps + clk_phase_ps = int((1e12/config[f"clk{n}_freq"])*config[f"clk{n}_phase"]/360) + self.params[f"p_CLK{n}_DIVIDE_BY"] = config[f"clk{n}_divide"] + self.params[f"p_CLK{n}_DUTY_CYCLE"] = 50 + self.params[f"p_CLK{n}_MULTIPLY_BY"] = config["m"] + self.params[f"p_CLK{n}_PHASE_SHIFT"] = clk_phase_ps self.comb += clk.eq(clks[n]) self.specials += Instance("ALTPLL", **self.params) From b7ef9899633b6c3bb95a5a847da41d85c71fee78 Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Sat, 1 Oct 2022 12:37:23 -0500 Subject: [PATCH 2/3] soc/cores/clock/intel_*: respect PFD input frequency Only use input clock divisors which respect the device limitation for the phase-frequency detector's input frequency. This avoids errors where Quartus complains the PLL parameters are invalid and refuses to implement it. The supported PFD frequencies in integer mode have been verified against each family's datasheet. The unsupported-by-LiteX fractional frequency information is removed for clarity. As a bonus, this speeds up PLL config computation by several times. --- litex/soc/cores/clock/intel_common.py | 9 ++++++++- litex/soc/cores/clock/intel_cyclone10.py | 2 +- litex/soc/cores/clock/intel_cyclone4.py | 1 + litex/soc/cores/clock/intel_cyclone5.py | 3 +-- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/litex/soc/cores/clock/intel_common.py b/litex/soc/cores/clock/intel_common.py index 4e5eabd3a..9dee644ca 100644 --- a/litex/soc/cores/clock/intel_common.py +++ b/litex/soc/cores/clock/intel_common.py @@ -5,6 +5,7 @@ # Copyright (c) 2022 Jevin Sweval # SPDX-License-Identifier: BSD-2-Clause +import math from operator import mul from functools import reduce @@ -58,7 +59,13 @@ class IntelClocking(Module, AutoCSR): def compute_config(self): valid_configs = {} - for n in range(*self.n_div_range): + # Only test values of N (input clock divisor) which result in a PFD + # input frequency within the allowable range. + min_n = math.ceil(self.clkin_freq/self.clkin_pfd_freq_range[1]) + max_n = math.floor(self.clkin_freq/self.clkin_pfd_freq_range[0]) + min_n = max(min_n, self.n_div_range[0]) # keep within counter size + max_n = min(max_n+1, self.n_div_range[1]) + for n in range(min_n, max_n): for m in range(*self.m_div_range): # For this given N, M, check to see if we can meet requirements # for each clkout. If so, record the difference ratio from the diff --git a/litex/soc/cores/clock/intel_cyclone10.py b/litex/soc/cores/clock/intel_cyclone10.py index 71e461762..5c699330a 100644 --- a/litex/soc/cores/clock/intel_cyclone10.py +++ b/litex/soc/cores/clock/intel_cyclone10.py @@ -16,7 +16,7 @@ class Cyclone10LPPLL(IntelClocking): n_div_range = (1, 512+1) m_div_range = (1, 512+1) c_div_range = (1, 512+1) - clkin_pfd_freq_range = (5e6, 325e6) # FIXME: use + clkin_pfd_freq_range = (5e6, 325e6) vco_freq_range = (600e6, 1300e6) def __init__(self, speedgrade="-C6"): self.logger = logging.getLogger("Cyclone10LPPLL") diff --git a/litex/soc/cores/clock/intel_cyclone4.py b/litex/soc/cores/clock/intel_cyclone4.py index d208a7376..fa2c484e1 100644 --- a/litex/soc/cores/clock/intel_cyclone4.py +++ b/litex/soc/cores/clock/intel_cyclone4.py @@ -16,6 +16,7 @@ class CycloneIVPLL(IntelClocking): n_div_range = (1, 512+1) m_div_range = (1, 512+1) c_div_range = (1, 512+1) + clkin_pfd_freq_range = (5e6, 325e6) vco_freq_range = (600e6, 1300e6) def __init__(self, speedgrade="-6"): self.logger = logging.getLogger("CycloneIVPLL") diff --git a/litex/soc/cores/clock/intel_cyclone5.py b/litex/soc/cores/clock/intel_cyclone5.py index c8e9572f2..d8f0aadd1 100644 --- a/litex/soc/cores/clock/intel_cyclone5.py +++ b/litex/soc/cores/clock/intel_cyclone5.py @@ -16,8 +16,7 @@ class CycloneVPLL(IntelClocking): n_div_range = (1, 512+1) m_div_range = (1, 512+1) c_div_range = (1, 512+1) - clkin_pfd_freq_range = (5e6, 325e6) # FIXME: use - clkfin_pfd_freq_range = (50e6, 160e6) # FIXME: use + clkin_pfd_freq_range = (5e6, 325e6) def __init__(self, speedgrade="-C6"): self.logger = logging.getLogger("CycloneVPLL") self.logger.info("Creating CycloneVPLL, {}.".format(colorer("speedgrade {}".format(speedgrade)))) From fea73d932ee0faf849a1d8007b9f7e127f482db8 Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Sat, 1 Oct 2022 13:04:16 -0500 Subject: [PATCH 3/3] soc/cores/clock/intel: speed up PLL config computation Caching the list of clock divisors to test speeds up computation by about a factor of three. --- litex/soc/cores/clock/intel_common.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/litex/soc/cores/clock/intel_common.py b/litex/soc/cores/clock/intel_common.py index 9dee644ca..cba985567 100644 --- a/litex/soc/cores/clock/intel_common.py +++ b/litex/soc/cores/clock/intel_common.py @@ -59,6 +59,7 @@ class IntelClocking(Module, AutoCSR): def compute_config(self): valid_configs = {} + clkdiv_range_list = list(clkdiv_range(*self.c_div_range)) # for speed # Only test values of N (input clock divisor) which result in a PFD # input frequency within the allowable range. min_n = math.ceil(self.clkin_freq/self.clkin_pfd_freq_range[1]) @@ -81,7 +82,7 @@ class IntelClocking(Module, AutoCSR): # For each C, see if the output frequency is within margin # and the difference is better than the previous valid, best C. best_diff = float("inf") - for c in clkdiv_range(*self.c_div_range): + for c in clkdiv_range_list: clk_freq = vco_freq/c diff = abs(clk_freq - f) if diff <= f*_m and diff < best_diff: