From eb27295b083513b868e9c5ea7b2a842c7663823b Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 20 May 2020 04:58:03 +0000 Subject: [PATCH] vendor.xilinx_{7series,ultrascale}: add (*keep*) on constrained clocks. 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 | 2 -- nmigen/vendor/xilinx_7series.py | 10 ++++++++-- nmigen/vendor/xilinx_ultrascale.py | 10 ++++++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/nmigen/vendor/intel.py b/nmigen/vendor/intel.py index 07ee95b..942a162 100644 --- a/nmigen/vendor/intel.py +++ b/nmigen/vendor/intel.py @@ -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: diff --git a/nmigen/vendor/xilinx_7series.py b/nmigen/vendor/xilinx_7series.py index 5da57a6..dec32a2 100644 --- a/nmigen/vendor/xilinx_7series.py +++ b/nmigen/vendor/xilinx_7series.py @@ -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. diff --git a/nmigen/vendor/xilinx_ultrascale.py b/nmigen/vendor/xilinx_ultrascale.py index d4136fb..7445f4b 100644 --- a/nmigen/vendor/xilinx_ultrascale.py +++ b/nmigen/vendor/xilinx_ultrascale.py @@ -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. -- 2.30.2