build.res,vendor: place clock constraint on port, not net, if possible.

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.
This commit is contained in:
whitequark 2020-02-06 23:37:15 +00:00
parent 5888f29c1f
commit 3e2ecdf2fb
8 changed files with 70 additions and 27 deletions

View 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

View 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"""

View 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)")}}
""",

View 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)")}}
""",

View 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)")}}
""",

View 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)")}}
"""

View 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)")}}
"""

View 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)")}}
"""