build.plat: skip clock constraints on unused signals.
authorwhitequark <whitequark@whitequark.org>
Wed, 20 May 2020 05:35:47 +0000 (05:35 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 31 Dec 2021 13:32:02 +0000 (13:32 +0000)
It's not very nice to add more internal mutable state to Platform
related classes, but our whole approach for Platform is inherently
stateful, and other solutions (like changing every individual vendor
platform to check for unused signals) are even worse.

Fixes #374.

nmigen/build/plat.py

index 17f147baff21513412e33a01814a81e04eb473c7..523e1ae9e50d9c970bcec33276c1a2f1a688d55a 100644 (file)
@@ -276,6 +276,15 @@ class TemplatedPlatform(Platform):
         """,
     }
 
+    def iter_clock_constraints(self):
+        for net_signal, port_signal, frequency in super().iter_clock_constraints():
+            # Skip any clock constraints placed on signals that are never used in the design.
+            # Otherwise, it will cause a crash in the vendor platform if it supports clock
+            # constraints on non-port nets.
+            if net_signal not in self._name_map:
+                continue
+            yield net_signal, port_signal, frequency
+
     def toolchain_prepare(self, fragment, name, **kwargs):
         # Restrict the name of the design to a strict alphanumeric character set. Platforms will
         # interpolate the name of the design in many different contexts: filesystem paths, Python
@@ -292,7 +301,7 @@ class TemplatedPlatform(Platform):
         # and to incorporate the nMigen version into generated code.
         autogenerated = "Automatically generated by nMigen {}. Do not edit.".format(__version__)
 
-        rtlil_text, name_map = rtlil.convert_fragment(fragment, name=name)
+        rtlil_text, self._name_map = rtlil.convert_fragment(fragment, name=name)
 
         def emit_rtlil():
             return rtlil_text
@@ -366,7 +375,7 @@ class TemplatedPlatform(Platform):
                 return " ".join(opts)
 
         def hierarchy(signal, separator):
-            return separator.join(name_map[signal][1:])
+            return separator.join(self._name_map[signal][1:])
 
         def ascii_escape(string):
             def escape_one(match):