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:
parent
5888f29c1f
commit
3e2ecdf2fb
8 changed files with 70 additions and 27 deletions
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue