build.res,vendor: place clock constraint on port, not net, if possible.
authorwhitequark <whitequark@whitequark.org>
Thu, 6 Feb 2020 23:37:15 +0000 (23:37 +0000)
committerwhitequark <whitequark@whitequark.org>
Thu, 6 Feb 2020 23:37:15 +0000 (23:37 +0000)
For most toolchains, these are functionally identical, although ports
tend to work a bit better, being the common case. For Vivado, though,
it is necessary to place them on the port because its timing analyzer
considers input buffer delay.

Fixes #301.

nmigen/build/res.py
nmigen/vendor/intel.py
nmigen/vendor/lattice_ecp5.py
nmigen/vendor/lattice_ice40.py
nmigen/vendor/lattice_machxo2.py
nmigen/vendor/xilinx_7series.py
nmigen/vendor/xilinx_spartan_3_6.py
nmigen/vendor/xilinx_ultrascale.py

index afcf41cc562c85f92a0a5612b10697fdc67eb8fd..5153a5c881cc14502ce569e526f53114015e7b98 100644 (file)
@@ -226,4 +226,25 @@ class ResourceManager:
             self._clocks[clock] = float(frequency)
 
     def iter_clock_constraints(self):
-        return iter(self._clocks.items())
+        # Back-propagate constraints through the input buffer. For clock constraints on pins
+        # (the majority of cases), toolchains work better if the constraint is defined on the pin
+        # and not on the buffered internal net; and if the toolchain is advanced enough that
+        # it considers clock phase and delay of the input buffer, it is *necessary* to define
+        # the constraint on the pin to match the designer's expectation of phase being referenced
+        # to the pin.
+        #
+        # Constraints on nets with no corresponding input pin (e.g. PLL or SERDES outputs) are not
+        # affected.
+        pin_i_to_port = SignalDict()
+        for res, pin, port, attrs in self._ports:
+            if hasattr(pin, "i"):
+                if isinstance(res.ios[0], Pins):
+                    pin_i_to_port[pin.i] = port.io
+                elif isinstance(res.ios[0], DiffPairs):
+                    pin_i_to_port[pin.i] = port.p
+                else:
+                    assert False
+
+        for net_signal, frequency in self._clocks.items():
+            port_signal = pin_i_to_port.get(net_signal)
+            yield net_signal, port_signal, frequency
index 7ff366dc57ec673419dea93af2e710c282cda781..4b8e4f906cfcc510a012076d3b7249895eb5f9e9 100644 (file)
@@ -107,15 +107,19 @@ class IntelPlatform(TemplatedPlatform):
             set_global_assignment -name GENERATE_RBF_FILE ON
         """,
         "{{name}}.sdc": r"""
-            {% for signal, frequency in platform.iter_clock_constraints() -%}
-                create_clock -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}} -period {{1000000000/frequency}} [get_ports {{port_signal.name}}]
+                {% else -%}
+                    create_clock -name {{net_signal.name}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("|")}}]
+                {% endif %}
             {% endfor %}
         """,
         "{{name}}.srf": r"""
             {% for warning in platform.quartus_suppressed_warnings %}
             { "" "" "" "{{name}}.v" {  } {  } 0 {{warning}} "" 0 0 "Design Software" 0 -1 0 ""}
             {% endfor %}
-        """,      
+        """,
     }
     command_templates = [
         r"""
index 13f04fd85fa733c5b6c795a79c72e2c4068c87cd..691ac0bd61e447c5813dbdf20e8441f20cfb9c85 100644 (file)
@@ -135,8 +135,12 @@ class LatticeECP5Platform(TemplatedPlatform):
                     {%- for key, value in extras.items() %} {{key}}={{value}}{% endfor %};
                 {% endif %}
             {% endfor %}
-            {% for signal, frequency in platform.iter_clock_constraints() -%}
-                FREQUENCY NET "{{signal|hierarchy(".")}}" {{frequency}} HZ;
+            {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
+                {% if port_signal is not none -%}
+                    FREQUENCY PORT "{{port_signal.name}}" {{frequency}} HZ;
+                {% else -%}
+                    FREQUENCY NET "{{net_signal|hierarchy(".")}}" {{frequency}} HZ;
+                {% endif %}
             {% endfor %}
             {{get_override("add_preferences")|default("# (add_preferences placeholder)")}}
         """
@@ -227,14 +231,15 @@ class LatticeECP5Platform(TemplatedPlatform):
                 IOBUF PORT "{{port_name}}"
                     {%- for key, value in extras.items() %} {{key}}={{value}}{% endfor %};
             {% endfor %}
-            {% for signal, frequency in platform.iter_clock_constraints() -%}
-                FREQUENCY NET "{{signal|hierarchy("/")}}" {{frequency/1000000}} MHZ;
-            {% endfor %}
             {{get_override("add_preferences")|default("# (add_preferences placeholder)")}}
         """,
         "{{name}}.sdc": r"""
-            {% for signal, frequency in platform.iter_clock_constraints() -%}
-                create_clock -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}} -period {{1000000000/frequency}} [get_ports {{port_signal.name}}]
+                {% else -%}
+                    create_clock -name {{net_signal.name}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")}}]
+                {% endif %}
             {% endfor %}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
         """,
index 370f750f81ceaa027cdbee234a46967313eca1b9..e5570ecfbd1162738efd7858ea350c832cc67a92 100644 (file)
@@ -134,8 +134,8 @@ class LatticeICE40Platform(TemplatedPlatform):
             {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
                 set_io {{port_name}} {{pin_name}}
             {% endfor %}
-            {% for signal, frequency in platform.iter_clock_constraints() -%}
-                set_frequency {{signal|hierarchy(".")}} {{frequency/1000000}}
+            {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
+                set_frequency {{net_signal|hierarchy(".")}} {{frequency/1000000}}
             {% endfor%}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
         """,
@@ -243,8 +243,12 @@ class LatticeICE40Platform(TemplatedPlatform):
         """,
         "{{name}}.sdc": r"""
             # {{autogenerated}}
-            {% 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}} -period {{1000000000/frequency}} [get_ports {{port_signal.name}}]
+                {% else -%}
+                    create_clock -name {{net_signal.name}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")}}]
+                {% endif %}
             {% endfor %}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
         """,
index 99c093cf6514a6423b1a33ac2db7c0da36b1fac0..962994b5fbded365a011572ab7d526481a4f7d4d 100644 (file)
@@ -91,14 +91,15 @@ class LatticeMachXO2Platform(TemplatedPlatform):
                     {%- for key, value in extras.items() %} {{key}}={{value}}{% endfor %};
                 {% endif %}
             {% endfor %}
-            {% for signal, frequency in platform.iter_clock_constraints() -%}
-                FREQUENCY NET "{{signal|hierarchy("/")}}" {{frequency/1000000}} MHZ;
-            {% endfor %}
             {{get_override("add_preferences")|default("# (add_preferences placeholder)")}}
         """,
         "{{name}}.sdc": r"""
-            {% for signal, frequency in platform.iter_clock_constraints() -%}
-                create_clock -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}} -period {{1000000000/frequency}} [get_ports {{port_signal.name}}]
+                {% else -%}
+                    create_clock -name {{net_signal.name}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")}}]
+                {% endif %}
             {% endfor %}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
         """,
index 50f66367de5a677096d9b93b57b479eb6eb0db74..99778a34157833b0ce5b8ed07ff3f522c9ece287 100644 (file)
@@ -133,8 +133,12 @@ class Xilinx7SeriesPlatform(TemplatedPlatform):
                     set_property {{attr_name}} {{attr_value}} [get_ports {{port_name}}]
                 {% 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}} -period {{1000000000/frequency}} [get_ports {{port_signal.name}}]
+                {% else -%}
+                    create_clock -name {{net_signal.name}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")}}]
+                {% endif %}
             {% endfor %}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
         """
index a8e265a69a2d7a07a3d37aad8a31eea6f622136e..6081e410975f14fc882d011bea8ed1b5031379bf 100644 (file)
@@ -132,9 +132,9 @@ class XilinxSpartan3Or6Platform(TemplatedPlatform):
                     NET "{{port_name}}" {{attr_name}}={{attr_value}};
                 {% endfor %}
             {% endfor %}
-            {% for signal, frequency in platform.iter_clock_constraints() -%}
-                NET "{{signal|hierarchy("/")}}" TNM_NET="PRD{{signal|hierarchy("/")}}";
-                TIMESPEC "TS{{signal|hierarchy("/")}}"=PERIOD "PRD{{signal|hierarchy("/")}}" {{1000000000/frequency}} ns HIGH 50%;
+            {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
+                NET "{{net_signal|hierarchy("/")}}" TNM_NET="PRD{{net_signal|hierarchy("/")}}";
+                TIMESPEC "TS{{net_signal|hierarchy("/")}}"=PERIOD "PRD{{net_signal|hierarchy("/")}}" {{1000000000/frequency}} ns HIGH 50%;
             {% endfor %}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
         """
index 74d5986d75c92679475e1a9533c090735f54dd6f..31f5f22ac68155f4f8241f021f1d650d89f5330f 100644 (file)
@@ -133,8 +133,12 @@ class XilinxUltraScalePlatform(TemplatedPlatform):
                     set_property {{attr_name}} {{attr_value}} [get_ports {{port_name}}]
                 {% 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}} -period {{1000000000/frequency}} [get_ports {{port_signal.name}}]
+                {% else -%}
+                    create_clock -name {{net_signal.name}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")}}]
+                {% endif %}
             {% endfor %}
             {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
         """