cores/clock: add logging to visualize clkin/clkouts and computed config.
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Tue, 10 Mar 2020 10:11:33 +0000 (11:11 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Tue, 10 Mar 2020 10:13:16 +0000 (11:13 +0100)
litex/soc/cores/clock.py

index 32b550d82956bc5f9b46df98ba6b30cd2085b36f..37dfdae80f51cc799f71822077a7823ff93a2e0a 100644 (file)
@@ -4,16 +4,50 @@
 
 """Clock Abstraction Modules"""
 
+import logging
+
 from migen import *
 from migen.genlib.io import DifferentialInput
 from migen.genlib.resetsync import AsyncResetSynchronizer
 
+from litex.soc.integration.soc import colorer
 from litex.soc.interconnect.csr import *
 
+logging.basicConfig(level=logging.INFO)
 
 def period_ns(freq):
     return 1e9/freq
 
+# Logging ------------------------------------------------------------------------------------------
+
+def register_clkin_log(logger, clkin, freq):
+    logger.info("Registering {} {} of {}.".format(
+        colorer("Differential") if isinstance(clkin, Record) else colorer("Single Ended"),
+        colorer("ClkIn"),
+        colorer("{:3.2f}MHz".format(freq/1e6))
+    ))
+
+def create_clkout_log(logger, name, freq, margin, nclkouts):
+    logger.info("Creating {} of {} {}.".format(
+        colorer("ClkOut{} {}".format(nclkouts, name)),
+        colorer("{:3.2f}MHz".format(freq/1e6)),
+        "(+-{:3.2f}ppm)".format(margin*1e6),
+    ))
+
+def compute_config_log(logger, config):
+    log    = "Config:\n"
+    length = 0
+    for name in config.keys():
+        if len(name) > length: length = len(name)
+    for name, value in config.items():
+        if "freq" in name or "vco" in name:
+            value = "{:3.2f}MHz".format(value/1e6)
+        if "phase" in name:
+            value = "{:3.2f}°".format(value)
+        log += "{}{}: {}\n".format(name, " "*(length-len(name)), value)
+    log = log[:-1]
+    logger.info(log)
+
 # Xilinx / Generic ---------------------------------------------------------------------------------
 
 class XilinxClocking(Module, AutoCSR):
@@ -40,12 +74,12 @@ class XilinxClocking(Module, AutoCSR):
         else:
             raise ValueError
         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)
-        self.nclkouts += 1
         if with_reset:
             self.specials += AsyncResetSynchronizer(cd, ~self.locked | self.reset)
         if buf is None:
@@ -65,6 +99,8 @@ class XilinxClocking(Module, AutoCSR):
                 self.specials += Instance("BUFIO", i_I=clkout, o_O=clkout_buf)
             else:
                 raise ValueError("Unsupported clock buffer: {}".format(buf))
+        create_clkout_log(self.logger, cd.name, freq, margin, self.nclkouts)
+        self.nclkouts += 1
 
     def compute_config(self):
         config = {}
@@ -91,8 +127,9 @@ class XilinxClocking(Module, AutoCSR):
                 else:
                     all_valid = False
                 if all_valid:
-                    config["vco"] = vco_freq
+                    config["vco"]           = vco_freq
                     config["clkfbout_mult"] = clkfbout_mult
+                    compute_config_log(self.logger, config)
                     return config
         raise ValueError("No PLL config found")
 
@@ -131,6 +168,7 @@ class XilinxClocking(Module, AutoCSR):
             )
         ]
         self.comb += self.drp_locked.status.eq(self.locked)
+        self.logger.info("Exposing DRP interface.")
 
     def do_finalize(self):
         assert hasattr(self, "clkin")
@@ -142,6 +180,8 @@ class S6PLL(XilinxClocking):
     clkin_freq_range = (19e6, 540e6)
 
     def __init__(self, speedgrade=-1):
+        self.logger = logging.getLogger("S6PLL")
+        self.logger.info("Creating S6PLL, {}.".format(colorer("speedgrade {}".format(speedgrade))))
         XilinxClocking.__init__(self)
         self.divclk_divide_range = (1, 52 + 1)
         self.vco_freq_range      = {
@@ -186,6 +226,8 @@ class S6DCM(XilinxClocking):
     clkout_divide_range  = (1, 256 + 1)
 
     def __init__(self, speedgrade=-1):
+        self.logger = logging.getLogger("S6DCM")
+        self.logger.info("Creating S6DCM, {}.".format(colorer("speedgrade {}".format(speedgrade))))
         XilinxClocking.__init__(self)
         self.divclk_divide_range = (1, 1) # FIXME
         self.clkin_freq_range = {
@@ -224,6 +266,8 @@ class S7PLL(XilinxClocking):
     clkin_freq_range = (19e6, 800e6)
 
     def __init__(self, speedgrade=-1):
+        self.logger = logging.getLogger("S7PLL")
+        self.logger.info("Creating S7PLL, {}.".format(colorer("speedgrade {}".format(speedgrade))))
         XilinxClocking.__init__(self)
         self.divclk_divide_range = (1, 56+1)
         self.vco_freq_range = {
@@ -255,6 +299,8 @@ class S7MMCM(XilinxClocking):
     nclkouts_max = 7
 
     def __init__(self, speedgrade=-1):
+        self.logger = logging.getLogger("S7MMCM")
+        self.logger.info("Creating S7MMCM, {}.".format(colorer("speedgrade {}".format(speedgrade))))
         XilinxClocking.__init__(self)
         self.divclk_divide_range = (1, 106+1)
         self.clkin_freq_range = {
@@ -313,6 +359,8 @@ class USPLL(XilinxClocking):
     nclkouts_max = 6
 
     def __init__(self, speedgrade=-1):
+        self.logger = logging.getLogger("USPLL")
+        self.logger.info("Creating USPLL, {}.".format(colorer("speedgrade {}".format(speedgrade))))
         XilinxClocking.__init__(self)
         self.divclk_divide_range = (1, 56+1)
         self.clkin_freq_range = {
@@ -349,6 +397,8 @@ class USMMCM(XilinxClocking):
     nclkouts_max = 7
 
     def __init__(self, speedgrade=-1):
+        self.logger = logging.getLogger("USMMCM")
+        self.logger.info("Creating UMMCM, {}.".format(colorer("speedgrade {}".format(speedgrade))))
         XilinxClocking.__init__(self)
         self.divclk_divide_range = (1, 106+1)
         self.clkin_freq_range = {
@@ -418,6 +468,8 @@ class iCE40PLL(Module):
 
     def __init__(self, primitive="SB_PLL40_CORE"):
         assert primitive in ["SB_PLL40_CORE", "SB_PLL40_PAD"]
+        self.logger = logging.getLogger("iCE40PLL")
+        self.logger.info("Creating iCE40PLL, {} primitive.".format(colorer(primitive)))
         self.primitive  = primitive
         self.reset      = Signal()
         self.locked     = Signal()
@@ -438,6 +490,7 @@ class iCE40PLL(Module):
         else:
             raise ValueError
         self.clkin_freq = freq
+        register_clkin_log(self.logger, clkin, freq)
 
     def create_clkout(self, cd, freq, margin=1e-2):
         (clko_freq_min, clko_freq_max) = self.clko_freq_range
@@ -446,8 +499,9 @@ class iCE40PLL(Module):
         assert self.nclkouts < self.nclkouts_max
         clkout = Signal()
         self.clkouts[self.nclkouts] = (clkout, freq, 0, margin)
-        self.nclkouts += 1
         self.comb += cd.clk.eq(clkout)
+        create_clkout_log(self.logger, cd.name, freq, margin, self.nclkouts)
+        self.nclkouts += 1
 
     def compute_config(self):
         config = {}
@@ -462,7 +516,8 @@ class iCE40PLL(Module):
                         for divq in range(*self.divq_range):
                             clk_freq = vco_freq/(2**divq)
                             if abs(clk_freq - f) <= f*m:
-                                config["divq"] = divq
+                                config["clkout_freq"] = clk_freq
+                                config["divq"]        = divq
                                 valid = True
                                 break
                         if not valid:
@@ -473,6 +528,7 @@ class iCE40PLL(Module):
                     config["vco"] = vco_freq
                     config["divr"] = divr
                     config["divf"] = divf
+                    compute_config_log(self.logger, config)
                     return config
         raise ValueError("No PLL config found")
 
@@ -515,6 +571,8 @@ class ECP5PLL(Module):
     vco_freq_range  = (  400e6,  800e6)
 
     def __init__(self):
+        self.logger = logging.getLogger("ECP5PLL")
+        self.logger.info("Creating ECP5PLL.")
         self.reset      = Signal()
         self.locked     = Signal()
         self.clkin_freq = None
@@ -534,6 +592,7 @@ class ECP5PLL(Module):
         else:
             raise ValueError
         self.clkin_freq = freq
+        register_clkin_log(self.logger, clkin, freq)
 
     def create_clkout(self, cd, freq, phase=0, margin=1e-2):
         (clko_freq_min, clko_freq_max) = self.clko_freq_range
@@ -542,8 +601,9 @@ class ECP5PLL(Module):
         assert self.nclkouts < self.nclkouts_max
         clkout = Signal()
         self.clkouts[self.nclkouts] = (clkout, freq, phase, margin)
-        self.nclkouts += 1
         self.comb += cd.clk.eq(clkout)
+        create_clkout_log(self.logger, cd.name, freq, margin, self.nclkouts)
+        self.nclkouts += 1
 
     def compute_config(self):
         config = {}
@@ -570,6 +630,7 @@ class ECP5PLL(Module):
             if all_valid:
                 config["vco"] = vco_freq
                 config["clkfb_div"] = clkfb_div
+                compute_config_log(self.logger, config)
                 return config
         raise ValueError("No PLL config found")