build/microsemi/libero_soc: add timing constraints support
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 19 Nov 2018 08:40:16 +0000 (09:40 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 19 Nov 2018 08:40:16 +0000 (09:40 +0100)
litex/build/microsemi/libero_soc.py
litex/build/microsemi/platform.py

index 32fa40939eb6028e9cc33b16cffa0d500354d0fa..6e561c4d67efe68f476b4c893a2e3adfb644073b 100644 (file)
@@ -87,7 +87,7 @@ def _build_tcl(platform, sources, build_dir, build_name):
         "-adv_options {VCCI_2.5_VOLTR:EXT}",
         "-adv_options {VCCI_3.3_VOLTR:EXT}",
         "-adv_options {VOLTR:EXT} "
-    ]))   
+    ]))
 
     # add files
     for filename, language, library in sources:
@@ -102,7 +102,7 @@ def _build_tcl(platform, sources, build_dir, build_name):
         if file.endswith(".init"):
             tcl.append("file copy -- {} impl/synthesis".format(file))
 
-    # import constraints
+    # import io constraints
     tcl.append("import_files -io_pdc {{{}}}".format(build_name + ".pdc"))
     tcl.append(" ".join(["organize_tool_files",
         "-tool {PLACEROUTE}",
@@ -111,6 +111,15 @@ def _build_tcl(platform, sources, build_dir, build_name):
         "-input_type {constraint}"
     ]))
 
+    # import timing constraints
+    tcl.append("import_files -convert_EDN_to_HDL 0 -sdc {{{}}}".format(build_name + ".sdc"))
+    tcl.append(" ".join(["organize_tool_files",
+        "-tool {VERIFYTIMING}",
+        "-file impl/constraint/{}.sdc".format(build_name),
+        "-module {}".format(build_name),
+        "-input_type {constraint}"
+    ]))
+
     # build flow
     tcl.append("run_tool -name {CONSTRAINT_MANAGEMENT}")
     tcl.append("run_tool -name {SYNTHESIZE}")
@@ -129,6 +138,24 @@ def _build_tcl(platform, sources, build_dir, build_name):
     tools.write_to_file(build_name + ".tcl", "\n".join(tcl))
 
 
+def _build_sdc(vns, clocks, false_paths, build_name):
+    sdc = []
+
+    for clk, period in sorted(clocks.items(), key=lambda x: x[0].duid):
+        sdc.append(
+            "create_clock -name {clk} -period " + str(period) +
+            " [get_nets {clk}]".format(clk=vns.get_name(clk)))
+    for from_, to in sorted(false_paths,
+                            key=lambda x: (x[0].duid, x[1].duid)):
+        sdc.append(
+            "set_clock_groups "
+            "-group [get_clocks -include_generated_clocks -of [get_nets {from_}]] "
+            "-group [get_clocks -include_generated_clocks -of [get_nets {to}]] "
+            "-asynchronous".format(from_=from_, to=to))
+
+    # generate sdc
+    tools.write_to_file(build_name + ".sdc", "\n".join(sdc))
+
 def _build_script(build_name, device, toolchain_path, ver=None):
     if sys.platform in ("win32", "cygwin"):
         script_ext = ".bat"
@@ -170,6 +197,10 @@ class MicrosemiLiberoSoCPolarfireToolchain:
 
     special_overrides = common.microsemi_polarfire_special_overrides
 
+    def __init__(self):
+        self.clocks = dict()
+        self.false_paths = set()
+
     def build(self, platform, fragment, build_dir="build", build_name="top",
               toolchain_path=None, run=False, **kwargs):
         os.makedirs(build_dir, exist_ok=True)
@@ -190,9 +221,12 @@ class MicrosemiLiberoSoCPolarfireToolchain:
         # generate design script (tcl)
         _build_tcl(platform, platform.sources, build_dir, build_name)
 
-        # generate design constraints (pdc)
+        # generate design io constraints (pdc)
         _build_pdc(named_sc, named_pc, build_name)
 
+        # generate design timing constraints (sdc)
+        _build_sdc(top_output.ns, self.clocks, self.false_paths, build_name)
+
         # generate build script
         script = _build_script(build_name, platform.device, toolchain_path)
         
@@ -205,4 +239,10 @@ class MicrosemiLiberoSoCPolarfireToolchain:
         return top_output.ns
 
     def add_period_constraint(self, platform, clk, period):
-        print("TODO: add_period_constraint")
\ No newline at end of file
+        if clk in self.clocks:
+            raise ValueError("A period constraint already exists")
+        self.clocks[clk] = period
+
+    def add_false_path_constraint(self, platform, from_, to):
+        if (to, from_) not in self.false_paths:
+            self.false_paths.add((from_, to))
index 6ecb8e9237fa9909973eb684e8121f156bbc4357..db6392884de4ae816c507bbaecefa7c2698cdd86 100644 (file)
@@ -13,7 +13,7 @@ class MicrosemiPlatform(GenericPlatform):
             raise ValueError("Unknown toolchain")
 
     def get_verilog(self, *args, special_overrides=dict(), **kwargs):
-        so = dict()  # No common overrides between ECP and ice40.
+        so = dict()
         so.update(self.toolchain.special_overrides)
         so.update(special_overrides)
         return GenericPlatform.get_verilog(self, *args, special_overrides=so,
@@ -27,3 +27,10 @@ class MicrosemiPlatform(GenericPlatform):
         if hasattr(clk, "p"):
             clk = clk.p
         self.toolchain.add_period_constraint(self, clk, period)
+
+    def add_false_path_constraint(self, from_, to):
+        if hasattr(from_, "p"):
+            from_ = from_.p
+        if hasattr(to, "p"):
+            to = to.p
+        self.toolchain.add_false_path_constraint(self, from_, to)