vendor.xilinx_{7series,ultrascale}: use BUFGCTRL rather than BUFGCE.
[nmigen.git] / nmigen / vendor / xilinx_ultrascale.py
index 74d5986d75c92679475e1a9533c090735f54dd6f..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,13 +124,17 @@ 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 signal, frequency in platform.iter_clock_constraints() -%}
-                create_clock -name {{signal.name}} -period {{1000000000/frequency}} [get_nets {{signal|hierarchy("/")}}]
+            {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
+                {% if port_signal is not none -%}
+                    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|ascii_escape}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_escape}}]
+                {% endif %}
             {% endfor %}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
         """
@@ -168,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.
@@ -399,21 +410,27 @@ class XilinxUltraScalePlatform(TemplatedPlatform):
         m.d.comb += ff_sync.o.eq(flops[-1])
         return m
 
-    def get_reset_sync(self, reset_sync):
+    def get_async_ff_sync(self, async_ff_sync):
         m = Module()
-        m.domains += ClockDomain("reset_sync", async_reset=True, local=True)
+        m.domains += ClockDomain("async_ff", async_reset=True, local=True)
         flops = [Signal(1, name="stage{}".format(index), reset=1,
                         attrs={"ASYNC_REG": "TRUE"})
-                 for index in range(reset_sync._stages)]
-        if reset_sync._max_input_delay is None:
+                 for index in range(async_ff_sync._stages)]
+        if async_ff_sync._max_input_delay is None:
             flops[0].attrs["nmigen.vivado.false_path"] = "TRUE"
         else:
-            flops[0].attrs["nmigen.vivado.max_delay"] = str(reset_sync._max_input_delay * 1e9)
+            flops[0].attrs["nmigen.vivado.max_delay"] = str(async_ff_sync._max_input_delay * 1e9)
         for i, o in zip((0, *flops), flops):
-            m.d.reset_sync += o.eq(i)
+            m.d.async_ff += o.eq(i)
+
+        if async_ff_sync._edge == "pos":
+            m.d.comb += ResetSignal("async_ff").eq(async_ff_sync.i)
+        else:
+            m.d.comb += ResetSignal("async_ff").eq(~async_ff_sync.i)
+
         m.d.comb += [
-            ClockSignal("reset_sync").eq(ClockSignal(reset_sync._domain)),
-            ResetSignal("reset_sync").eq(reset_sync.arst),
-            ResetSignal(reset_sync._domain).eq(flops[-1])
+            ClockSignal("async_ff").eq(ClockSignal(async_ff_sync._domain)),
+            async_ff_sync.o.eq(flops[-1])
         ]
+
         return m