cores/clock: simplify Fractional Divide support on S7MMCM.
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 13 Mar 2020 14:51:18 +0000 (15:51 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Fri, 13 Mar 2020 14:56:39 +0000 (15:56 +0100)
Specific clkoutn_divide_range can now be provided by specialized XilinxClocking classes.
When provided, the specific range will be used. Floats are also now supported in the
range definition/iteration.

litex/soc/cores/clock.py

index 827215a02c0fcbc49f67c4c13e12ac59748887b2..5b68ec59593fb5e8326e8528511251bd068f7b50 100644 (file)
@@ -4,6 +4,7 @@
 
 """Clock Abstraction Modules"""
 
+import math
 import logging
 
 from migen import *
@@ -48,12 +49,22 @@ def compute_config_log(logger, config):
     log = log[:-1]
     logger.info(log)
 
+# Helpers ------------------------------------------------------------------------------------------
+
+def clkdiv_range(start, stop, step=1):
+    start   = float(start)
+    stop    = float(stop)
+    step    = float(step)
+    current = start
+    while current < stop:
+        yield int(current) if math.floor(current) == current else current
+        current += step
+
 # Xilinx / Generic ---------------------------------------------------------------------------------
 
 class XilinxClocking(Module, AutoCSR):
     clkfbout_mult_frange = (2,  64+1)
     clkout_divide_range  = (1, 128+1)
-    clkout0_divide_range = (2, (128+0.125), 0.125)
 
     def __init__(self, vco_margin=0):
         self.vco_margin = vco_margin
@@ -115,7 +126,9 @@ class XilinxClocking(Module, AutoCSR):
                     vco_freq <= vco_freq_max*(1 - self.vco_margin)):
                     for n, (clk, f, p, m) in sorted(self.clkouts.items()):
                         valid = False
-                        for d in range(*self.clkout_divide_range):
+                        d_range = self.clkout_divide_range
+                        d_range = getattr(self, "clkout{}_divide_range".format(n), d_range)
+                        for d in clkdiv_range(*d_range):
                             clk_freq = vco_freq/d
                             if abs(clk_freq - f) <= f*m:
                                 config["clkout{}_freq".format(n)]   = clk_freq
@@ -123,19 +136,6 @@ class XilinxClocking(Module, AutoCSR):
                                 config["clkout{}_phase".format(n)]  = p
                                 valid = True
                                 break
-                        if not valid and n == 0:
-                            # clkout0 supports fractional division, try the fractional range as a fallback
-                            (start, stop, step) = self.clkout0_divide_range
-                            d = start
-                            while d < stop:
-                                clk_freq = vco_freq / d
-                                if abs(clk_freq - f) <= f * m:
-                                    config["clkout{}_freq".format(n)] = clk_freq
-                                    config["clkout{}_divide".format(n)] = d
-                                    config["clkout{}_phase".format(n)] = p
-                                    valid = True
-                                    break
-                                d += step
                         if not valid:
                             all_valid = False
                 else:
@@ -310,7 +310,8 @@ class S7PLL(XilinxClocking):
 
 
 class S7MMCM(XilinxClocking):
-    nclkouts_max = 7
+    nclkouts_max         = 7
+    clkout0_divide_range = (1, (128 + 1/8), 1/8) # Fractional Divide available on CLKOUT0
 
     def __init__(self, speedgrade=-1):
         self.logger = logging.getLogger("S7MMCM")