vendor.xilinx_{7series,ultrascale}: use BUFGCTRL rather than BUFGCE.
[nmigen.git] / nmigen / vendor / xilinx_ultrascale.py
index 113753c313713ccb0a6c1b9edfc4b70960bf7055..4d8a0766462468d5b5dae291edeb68c88cd3f82c 100644 (file)
@@ -51,12 +51,8 @@ class XilinxUltraScalePlatform(TemplatedPlatform):
     device  = abstractproperty()
     package = abstractproperty()
     speed   = abstractproperty()
-    grade   = None
 
-    required_tools = [
-        "yosys",
-        "vivado"
-    ]
+    required_tools = ["vivado"]
     file_templates = {
         **TemplatedPlatform.build_script_templates,
         "build_{{name}}.sh": r"""
@@ -76,14 +72,14 @@ class XilinxUltraScalePlatform(TemplatedPlatform):
         """,
         "{{name}}.tcl": r"""
             # {{autogenerated}}
-            create_project -force -name {{name}} -part {{platform.device}}-{{platform.package}}-{{platform.speed}}{{"-" + platform.grade if platform.grade else ""}}
+            create_project -force -name {{name}} -part {{platform.device}}-{{platform.package}}-{{platform.speed}}
             {% for file in platform.iter_extra_files(".v", ".sv", ".vhd", ".vhdl") -%}
-                add_files {{file}}
+                add_files {{file|tcl_escape}}
             {% endfor %}
             add_files {{name}}.v
             read_xdc {{name}}.xdc
             {% for file in platform.iter_extra_files(".xdc") -%}
-                read_xdc {{file}}
+                read_xdc {{file|tcl_escape}}
             {% endfor %}
             {{get_override("script_after_read")|default("# (script_after_read placeholder)")}}
             synth_design -top {{name}}
@@ -128,16 +124,16 @@ class XilinxUltraScalePlatform(TemplatedPlatform):
         "{{name}}.xdc": r"""
             # {{autogenerated}}
             {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
-                set_property LOC {{pin_name}} [get_ports {{port_name}}]
+                set_property LOC {{pin_name}} [get_ports {{port_name|tcl_escape}}]
                 {% for attr_name, attr_value in attrs.items() -%}
-                    set_property {{attr_name}} {{attr_value}} [get_ports {{port_name}}]
+                    set_property {{attr_name}} {{attr_value|tcl_escape}} [get_ports {{port_name|tcl_escape}}]
                 {% endfor %}
             {% endfor %}
             {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
                 {% if port_signal is not none -%}
-                    create_clock -name {{port_signal.name}} -period {{1000000000/frequency}} [get_ports {{port_signal.name}}]
+                    create_clock -name {{port_signal.name|ascii_escape}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_escape}}]
                 {% else -%}
-                    create_clock -name {{net_signal.name}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")}}]
+                    create_clock -name {{net_signal.name|ascii_escape}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_escape}}]
                 {% endif %}
             {% endfor %}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
@@ -172,11 +168,22 @@ class XilinxUltraScalePlatform(TemplatedPlatform):
             ready = Signal()
             m.submodules += Instance("STARTUPE3", o_EOS=ready)
             m.domains += ClockDomain("sync", reset_less=self.default_rst is None)
-            m.submodules += Instance("BUFGCE", i_CE=ready, i_I=clk_i, o_O=ClockSignal("sync"))
+            # Actually use BUFGCTRL configured as BUFGCE, since using BUFGCE causes sim/synth
+            # mismatches with Vivado 2019.2, and the suggested workaround (SIM_DEVICE parameter)
+            # breaks Vivado 2017.4.
+            m.submodules += Instance("BUFGCTRL",
+                i_I0=clk_i,   i_S0=C(1, 1), i_CE0=ready,   i_IGNORE0=C(0, 1),
+                i_I1=C(1, 1), i_S1=C(0, 1), i_CE1=C(0, 1), i_IGNORE1=C(1, 1),
+                o_O=ClockSignal("sync")
+            )
             if self.default_rst is not None:
                 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"] = "TRUE"
+
     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.