vendor.xilinx_{7series,ultrascale}: add (*keep*) on constrained clocks.
authorwhitequark <whitequark@whitequark.org>
Wed, 20 May 2020 04:58:03 +0000 (04:58 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 31 Dec 2021 13:31:52 +0000 (13:31 +0000)
If the clock signal is not a top-level port and has aliases, it can
be optimized out, and then the constraint will no longer apply.
To prevent this, make sure the constrained signal is preferred over
any aliases by using the `keep` attribute.

Vivado does not parse attributes like (* keep = 32'd1 *) as valid
even though, AFAICT, they are equivalent to (* keep = 1 *) or simply
(* keep *) per IEEE 1364. To work around this, use the solution we
currently use for Quartus, which is `write_verilog -decimal`.

Fixes #373.

nmigen/vendor/intel.py
nmigen/vendor/xilinx_7series.py
nmigen/vendor/xilinx_ultrascale.py

index 07ee95bc9d1b12e998034aca5495828fdac20716..942a162eae4b11166f96a0c481c8539c918bb898 100644 (file)
@@ -146,8 +146,6 @@ class IntelPlatform(TemplatedPlatform):
 
     def add_clock_constraint(self, clock, frequency):
         super().add_clock_constraint(clock, frequency)
-        # Make sure the net constrained in the SDC file is kept through synthesis; it is redundant
-        # after Quartus flattens the hierarchy and will be eliminated if not explicitly kept.
         clock.attrs["keep"] = 1
 
     # The altiobuf_* and altddio_* primitives are explained in the following Intel documents:
index 5da57a69fa2375027868f772814a4207f1791e39..dec32a26596dda608175e1cb6e22565ab07647a3 100644 (file)
@@ -66,13 +66,15 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
             [ -n "${{platform._toolchain_env_var}}" ] && . "${{platform._toolchain_env_var}}"
             {{emit_commands("sh")}}
         """,
+        # Vivado doesn't like constructs like (* keep = 32'd1 *), even though they mean the same
+        # thing as (* keep = 1 *); use -decimal to work around that.
         "{{name}}.v": r"""
             /* {{autogenerated}} */
-            {{emit_verilog()}}
+            {{emit_verilog(["-decimal"])}}
         """,
         "{{name}}.debug.v": r"""
             /* {{autogenerated}} */
-            {{emit_debug_verilog()}}
+            {{emit_debug_verilog(["-decimal"])}}
         """,
         "{{name}}.tcl": r"""
             # {{autogenerated}}
@@ -177,6 +179,10 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
                 m.submodules.reset_sync = ResetSynchronizer(rst_i, domain="sync")
             return m
 
+    def add_clock_constraint(self, clock, frequency):
+        super().add_clock_constraint(clock, frequency)
+        clock.attrs["keep"] = 1
+
     def _get_xdr_buffer(self, m, pin, *, i_invert=False, o_invert=False):
         def get_dff(clk, d, q):
             # SDR I/O is performed by packing a flip-flop into the pad IOB.
index d4136fb9a950ee89acb86dbadef2123ebe671ad6..7445f4bfb6b5eee1c9eb93be69268cdbf8860263 100644 (file)
@@ -66,13 +66,15 @@ class XilinxUltraScalePlatform(TemplatedPlatform):
             [ -n "${{platform._toolchain_env_var}}" ] && . "${{platform._toolchain_env_var}}"
             {{emit_commands("sh")}}
         """,
+        # Vivado doesn't like constructs like (* keep = 32'd1 *), even though they mean the same
+        # thing as (* keep = 1 *); use -decimal to work around that.
         "{{name}}.v": r"""
             /* {{autogenerated}} */
-            {{emit_verilog()}}
+            {{emit_verilog(["-decimal"])}}
         """,
         "{{name}}.debug.v": r"""
             /* {{autogenerated}} */
-            {{emit_debug_verilog()}}
+            {{emit_debug_verilog(["-decimal"])}}
         """,
         "{{name}}.tcl": r"""
             # {{autogenerated}}
@@ -177,6 +179,10 @@ class XilinxUltraScalePlatform(TemplatedPlatform):
                 m.submodules.reset_sync = ResetSynchronizer(rst_i, domain="sync")
             return m
 
+    def add_clock_constraint(self, clock, frequency):
+        super().add_clock_constraint(clock, frequency)
+        clock.attrs["keep"] = 1
+
     def _get_xdr_buffer(self, m, pin, *, i_invert=False, o_invert=False):
         def get_dff(clk, d, q):
             # SDR I/O is performed by packing a flip-flop into the pad IOB.