add fractional division options to clk0 config on PLL
authorbunnie <bunnie@kosagi.com>
Tue, 10 Mar 2020 10:48:30 +0000 (18:48 +0800)
committerbunnie <bunnie@kosagi.com>
Tue, 10 Mar 2020 10:48:30 +0000 (18:48 +0800)
S7 MMCMs allow fractional divider on clock 0. Add a fallback
to try fractional values on clock 0 if a solution can't be found.

This is necessary for e.g. generating both a 100MHz and 48MHz
clock from a 12MHz source with margin=0

litex/soc/cores/clock.py

index 63a9edaa63344fb39483d4c9f1f07a4125133d1c..d8d9f1f3c0def601e752ac90f14e1c6ffda2e0b4 100644 (file)
@@ -19,6 +19,7 @@ def period_ns(freq):
 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
@@ -86,6 +87,19 @@ 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: