@@ -109,8 +109,9 @@ def __init__(self, resources, connectors):
109
109
110
110
# List of (pin, port, buffer) pairs for non-dir="-" requests.
111
111
self ._pins = []
112
- # Constraint list
112
+ # Constraint lists
113
113
self ._clocks = SignalDict ()
114
+ self ._io_clocks = {}
114
115
115
116
self .add_resources (resources )
116
117
self .add_connectors (connectors )
@@ -219,6 +220,8 @@ def resolve(resource, dir, xdr, path, attrs):
219
220
for name in phys_names
220
221
])
221
222
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 )
222
225
if isinstance (phys , DiffPairs ):
223
226
phys_names_p = phys .p .map_names (self ._conn_pins , resource )
224
227
phys_names_n = phys .n .map_names (self ._conn_pins , resource )
@@ -232,7 +235,8 @@ def resolve(resource, dir, xdr, path, attrs):
232
235
for name in phys_names_n
233
236
])
234
237
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 )
236
240
for phys_name in phys_names :
237
241
if phys_name in self ._phys_reqd :
238
242
raise ResourceError ("Resource component {} uses physical pin {}, but it "
@@ -253,8 +257,6 @@ def resolve(resource, dir, xdr, path, attrs):
253
257
buffer = PinBuffer (pin , port )
254
258
self ._pins .append ((pin , port , buffer ))
255
259
256
- if resource .clock is not None :
257
- self .add_clock_constraint (pin .i , resource .clock .frequency )
258
260
return pin
259
261
260
262
else :
@@ -275,38 +277,28 @@ def add_clock_constraint(self, clock, frequency):
275
277
raise TypeError (f"A clock constraint can only be applied to a Signal, but a "
276
278
f"ClockSignal is provided; assign the ClockSignal to an "
277
279
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 " )
280
282
if not isinstance (frequency , (int , float )):
281
283
raise TypeError (f"Frequency must be a number, not { frequency !r} " )
282
284
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 :
284
292
raise ValueError ("Cannot add clock constraint on {!r}, which is already constrained "
285
293
"to {} Hz"
286
- .format (clock , self . _clocks [clock ]))
294
+ .format (clock , clocks [clock ]))
287
295
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
309
301
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