@@ -109,8 +109,9 @@ def __init__(self, resources, connectors):
109109
110110 # List of (pin, port, buffer) pairs for non-dir="-" requests.
111111 self ._pins = []
112- # Constraint list
112+ # Constraint lists
113113 self ._clocks = SignalDict ()
114+ self ._io_clocks = {}
114115
115116 self .add_resources (resources )
116117 self .add_connectors (connectors )
@@ -219,6 +220,8 @@ def resolve(resource, dir, xdr, path, attrs):
219220 for name in phys_names
220221 ])
221222 port = io .SingleEndedPort (iop , invert = phys .invert , direction = direction )
223+ if resource .clock is not None :
224+ self .add_clock_constraint (iop , resource .clock .frequency )
222225 if isinstance (phys , DiffPairs ):
223226 phys_names_p = phys .p .map_names (self ._conn_pins , resource )
224227 phys_names_n = phys .n .map_names (self ._conn_pins , resource )
@@ -232,7 +235,8 @@ def resolve(resource, dir, xdr, path, attrs):
232235 for name in phys_names_n
233236 ])
234237 port = io .DifferentialPort (p , n , invert = phys .invert , direction = direction )
235-
238+ if resource .clock is not None :
239+ self .add_clock_constraint (p , resource .clock .frequency )
236240 for phys_name in phys_names :
237241 if phys_name in self ._phys_reqd :
238242 raise ResourceError ("Resource component {} uses physical pin {}, but it "
@@ -253,8 +257,6 @@ def resolve(resource, dir, xdr, path, attrs):
253257 buffer = PinBuffer (pin , port )
254258 self ._pins .append ((pin , port , buffer ))
255259
256- if resource .clock is not None :
257- self .add_clock_constraint (pin .i , resource .clock .frequency )
258260 return pin
259261
260262 else :
@@ -275,38 +277,28 @@ def add_clock_constraint(self, clock, frequency):
275277 raise TypeError (f"A clock constraint can only be applied to a Signal, but a "
276278 f"ClockSignal is provided; assign the ClockSignal to an "
277279 f"intermediate signal and constrain the latter instead." )
278- elif not isinstance (clock , Signal ):
279- raise TypeError (f"Object { clock !r} is not a Signal" )
280+ elif not isinstance (clock , ( Signal , IOPort ) ):
281+ raise TypeError (f"Object { clock !r} is not a Signal or IOPort " )
280282 if not isinstance (frequency , (int , float )):
281283 raise TypeError (f"Frequency must be a number, not { frequency !r} " )
282284
283- if clock in self ._clocks :
285+ if isinstance (clock , IOPort ):
286+ clocks = self ._io_clocks
287+ else :
288+ clocks = self ._clocks
289+
290+ frequency = float (frequency )
291+ if clock in clocks and clocks [clock ] != frequency :
284292 raise ValueError ("Cannot add clock constraint on {!r}, which is already constrained "
285293 "to {} Hz"
286- .format (clock , self . _clocks [clock ]))
294+ .format (clock , clocks [clock ]))
287295 else :
288- self ._clocks [clock ] = float (frequency )
289-
290- def iter_clock_constraints (self ):
291- # Back-propagate constraints through the input buffer. For clock constraints on pins
292- # (the majority of cases), toolchains work better if the constraint is defined on the pin
293- # and not on the buffered internal net; and if the toolchain is advanced enough that
294- # it considers clock phase and delay of the input buffer, it is *necessary* to define
295- # the constraint on the pin to match the designer's expectation of phase being referenced
296- # to the pin.
297- #
298- # Constraints on nets with no corresponding input pin (e.g. PLL or SERDES outputs) are not
299- # affected.
300- pin_i_to_port = SignalDict ()
301- for pin , port , _fragment in self ._pins :
302- if hasattr (pin , "i" ):
303- if isinstance (port , io .SingleEndedPort ):
304- pin_i_to_port [pin .i ] = port .io
305- elif isinstance (port , io .DifferentialPort ):
306- pin_i_to_port [pin .i ] = port .p
307- else :
308- assert False
296+ clocks [clock ] = frequency
297+
298+ def iter_signal_clock_constraints (self ):
299+ for signal , frequency in self ._clocks .items ():
300+ yield signal , frequency
309301
310- for net_signal , frequency in self . _clocks . items ( ):
311- port_signal = pin_i_to_port . get ( net_signal )
312- yield net_signal , port_signal , frequency
302+ def iter_port_clock_constraints ( self ):
303+ for port , frequency in self . _io_clocks . items ():
304+ yield port , frequency
0 commit comments