Skip to content

Commit 9686da2

Browse files
wanda-phiwhitequark
authored andcommitted
build: add clock constraints on IOPort instead of buffered Signal.
1 parent ef5c506 commit 9686da2

File tree

9 files changed

+107
-108
lines changed

9 files changed

+107
-108
lines changed

amaranth/build/plat.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,14 @@ class TemplatedPlatform(Platform):
198198
""",
199199
}
200200

201-
def iter_clock_constraints(self):
202-
for net_signal, port_signal, frequency in super().iter_clock_constraints():
201+
def iter_signal_clock_constraints(self):
202+
for signal, frequency in super().iter_signal_clock_constraints():
203203
# Skip any clock constraints placed on signals that are never used in the design.
204204
# Otherwise, it will cause a crash in the vendor platform if it supports clock
205205
# constraints on non-port nets.
206-
if net_signal not in self._name_map:
206+
if signal not in self._name_map:
207207
continue
208-
yield net_signal, port_signal, frequency
208+
yield signal, frequency
209209

210210
def toolchain_prepare(self, fragment, name, *, emit_src=True, **kwargs):
211211
# Restrict the name of the design to a strict alphanumeric character set. Platforms will
@@ -327,8 +327,11 @@ def options(opts):
327327
else:
328328
return " ".join(opts)
329329

330-
def hierarchy(signal, separator):
331-
return separator.join(self._name_map[signal][1:])
330+
def hierarchy(net, separator):
331+
if isinstance(net, IOPort):
332+
return net.name
333+
else:
334+
return separator.join(self._name_map[net][1:])
332335

333336
def ascii_escape(string):
334337
def escape_one(match):

amaranth/build/res.py

+24-32
Original file line numberDiff line numberDiff line change
@@ -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

amaranth/vendor/_altera.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -310,12 +310,11 @@ class AlteraPlatform(TemplatedPlatform):
310310
{{get_override("add_settings")|default("# (add_settings placeholder)")}}
311311
""",
312312
"{{name}}.sdc": r"""
313-
{% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
314-
{% if port_signal is not none -%}
315-
create_clock -name {{port_signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_quote}}]
316-
{% else -%}
317-
create_clock -name {{net_signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("|")|tcl_quote}}]
318-
{% endif %}
313+
{% for signal, frequency in platform.iter_signal_clock_constraints() -%}
314+
create_clock -name {{signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_nets {{signal|hierarchy("|")|tcl_quote}}]
315+
{% endfor %}
316+
{% for port, frequency in platform.iter_port_clock_constraints() -%}
317+
create_clock -name {{port.name|tcl_quote}} -period {{1000000000/frequency}} [get_ports {{port.name|tcl_quote}}]
319318
{% endfor %}
320319
{{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
321320
""",

amaranth/vendor/_gowin.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -439,8 +439,11 @@ def _osc_div(self):
439439
""",
440440
"{{name}}.sdc": r"""
441441
// {{autogenerated}}
442-
{% for net_signal,port_signal,frequency in platform.iter_clock_constraints() -%}
443-
create_clock -name {{port_signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_quote}}]
442+
{% for signal, frequency in platform.iter_signal_clock_constraints() -%}
443+
create_clock -name {{signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_nets {{signal|hierarchy("/")|tcl_quote}}]
444+
{% endfor %}
445+
{% for port, frequency in platform.iter_port_clock_constraints() -%}
446+
create_clock -name {{port.name|tcl_quote}} -period {{1000000000/frequency}} [get_ports {{port.name|tcl_quote}}]
444447
{% endfor %}
445448
{{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
446449
""",

amaranth/vendor/_lattice.py

+20-24
Original file line numberDiff line numberDiff line change
@@ -497,12 +497,11 @@ class LatticePlatform(TemplatedPlatform):
497497
{%- for key, value in attrs.items() %} {{key}}={{value}}{% endfor %};
498498
{% endif %}
499499
{% endfor %}
500-
{% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
501-
{% if port_signal is not none -%}
502-
FREQUENCY PORT "{{port_signal.name}}" {{frequency}} HZ;
503-
{% else -%}
504-
FREQUENCY NET "{{net_signal|hierarchy(".")}}" {{frequency}} HZ;
505-
{% endif %}
500+
{% for signal, frequency in platform.iter_signal_clock_constraints() -%}
501+
FREQUENCY NET "{{signals|hierarchy(".")}}" {{frequency}} HZ;
502+
{% endfor %}
503+
{% for port, frequency in platform.iter_port_clock_constraints() -%}
504+
FREQUENCY PORT "{{port.name}}" {{frequency}} HZ;
506505
{% endfor %}
507506
{{get_override("add_preferences")|default("# (add_preferences placeholder)")}}
508507
"""
@@ -584,12 +583,11 @@ class LatticePlatform(TemplatedPlatform):
584583
ldc_set_port -iobuf {{ '{' }}{%- for key, value in attrs.items() %}{{key}}={{value}} {% endfor %}{{ '}' }} {{'['}}get_ports {{port_name}}{{']'}}
585584
{% endif %}
586585
{% endfor %}
587-
{% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
588-
{% if port_signal is not none -%}
589-
create_clock -name {{port_signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_quote}}]
590-
{% else -%}
591-
create_clock -name {{net_signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_quote}}]
592-
{% endif %}
586+
{% for signal, frequency in platform.iter_signal_clock_constraints() -%}
587+
create_clock -name {{signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_nets {{signal|hierarchy("/")|tcl_quote}}]
588+
{% endfor %}
589+
{% for port, frequency in platform.iter_port_clock_constraints() -%}
590+
create_clock -name {{port.name|tcl_quote}} -period {{1000000000/frequency}} [get_ports {{port.name|tcl_quote}}]
593591
{% endfor %}
594592
{{get_override("add_preferences")|default("# (add_preferences placeholder)")}}
595593
"""
@@ -684,12 +682,11 @@ class LatticePlatform(TemplatedPlatform):
684682
""",
685683
"{{name}}.sdc": r"""
686684
set_hierarchy_separator {/}
687-
{% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
688-
{% if port_signal is not none -%}
689-
create_clock -name {{port_signal.name|tcl_quote("Diamond")}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_quote("Diamond")}}]
690-
{% else -%}
691-
create_clock -name {{net_signal.name|tcl_quote("Diamond")}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_quote("Diamond")}}]
692-
{% endif %}
685+
{% for signal, frequency in platform.iter_signal_clock_constraints() -%}
686+
create_clock -name {{signal.name|tcl_quote("Diamond")}} -period {{1000000000/frequency}} [get_nets {{signal|hierarchy("/")|tcl_quote("Diamond")}}]
687+
{% endfor %}
688+
{% for port, frequency in platform.iter_port_clock_constraints() -%}
689+
create_clock -name {{port.name|tcl_quote("Diamond")}} -period {{1000000000/frequency}} [get_ports {{port.name|tcl_quote("Diamond")}}]
693690
{% endfor %}
694691
{{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
695692
""",
@@ -782,12 +779,11 @@ class LatticePlatform(TemplatedPlatform):
782779
""",
783780
# Pre-synthesis SDC constraints
784781
"{{name}}.sdc": r"""
785-
{% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
786-
{% if port_signal is not none -%}
787-
create_clock -name {{port_signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_ports {{port_signal.name}}]
788-
{% else -%}
789-
create_clock -name {{net_signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")}}]
790-
{% endif %}
782+
{% for signal, frequency in platform.iter_signal_clock_constraints() -%}
783+
create_clock -name {{signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_nets {{signal|hierarchy("/")|tcl_quote}}]
784+
{% endfor %}
785+
{% for port, frequency in platform.iter_port_clock_constraints() -%}
786+
create_clock -name {{port.name|tcl_quote}} -period {{1000000000/frequency}} [get_ports {{port.name|tcl_quote}}]
791787
{% endfor %}
792788
{{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
793789
""",

amaranth/vendor/_quicklogic.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,11 @@ class QuicklogicPlatform(TemplatedPlatform):
7171
""",
7272
"{{name}}.sdc": r"""
7373
# {{autogenerated}}
74-
{% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
75-
{% if port_signal is not none -%}
76-
create_clock -period {{100000000/frequency}} {{port_signal.name|ascii_escape}}
77-
{% endif %}
74+
{% for signal, frequency in platform.iter_signal_clock_constraints() -%}
75+
create_clock -period {{100000000/frequency}} {{signal.name|ascii_escape}}
76+
{% endfor %}
77+
{% for port, frequency in platform.iter_port_clock_constraints() -%}
78+
create_clock -period {{100000000/frequency}} {{port.name|ascii_escape}}
7879
{% endfor %}
7980
"""
8081
}

amaranth/vendor/_siliconblue.py

+11-9
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,12 @@ class SiliconBluePlatform(TemplatedPlatform):
134134
{% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
135135
set_io {{port_name}} {{pin_name}}
136136
{% endfor %}
137-
{% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
138-
set_frequency {{net_signal|hierarchy(".")}} {{frequency/1000000}}
139-
{% endfor%}
137+
{% for signal, frequency in platform.iter_signal_clock_constraints() -%}
138+
set_frequency {{signal|hierarchy(".")}} {{frequency/1000000}}
139+
{% endfor %}
140+
{% for port, frequency in platform.iter_port_clock_constraints() -%}
141+
set_frequency {{port.name}} {{frequency/1000000}}
142+
{% endfor %}
140143
{{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
141144
""",
142145
}
@@ -242,12 +245,11 @@ class SiliconBluePlatform(TemplatedPlatform):
242245
"{{name}}.sdc": r"""
243246
# {{autogenerated}}
244247
set_hierarchy_separator {/}
245-
{% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
246-
{% if port_signal is not none -%}
247-
create_clock -name {{port_signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_quote}}]
248-
{% else -%}
249-
create_clock -name {{net_signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_quote}}]
250-
{% endif %}
248+
{% for signal, frequency in platform.iter_signal_clock_constraints() -%}
249+
create_clock -name {{signal.name|tcl_quote}} -period {{1000000000/frequency}} [get_nets {{signal|hierarchy("/")|tcl_quote}}]
250+
{% endfor %}
251+
{% for port, frequency in platform.iter_port_clock_constraints() -%}
252+
create_clock -name {{port.name|tcl_quote}} -period {{1000000000/frequency}} [get_ports {{port.name|tcl_quote}}]
251253
{% endfor %}
252254
{{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
253255
""",

amaranth/vendor/_xilinx.py

+19-14
Original file line numberDiff line numberDiff line change
@@ -647,12 +647,11 @@ def vendor_toolchain(self):
647647
set_property {{attr_name}} {{attr_value|tcl_quote}} [get_ports {{port_name|tcl_quote}}]
648648
{% endfor %}
649649
{% endfor %}
650-
{% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
651-
{% if port_signal is not none -%}
652-
create_clock -name {{port_signal.name|ascii_escape}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_quote}}]
653-
{% else -%}
654-
create_clock -name {{net_signal.name|ascii_escape}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_quote}}]
655-
{% endif %}
650+
{% for signal, frequency in platform.iter_signal_clock_constraints() -%}
651+
create_clock -name {{signal.name|ascii_escape}} -period {{1000000000/frequency}} [get_nets {{signal|hierarchy("/")|tcl_quote}}]
652+
{% endfor %}
653+
{% for port, frequency in platform.iter_port_clock_constraints() -%}
654+
create_clock -name {{port.name|ascii_escape}} -period {{1000000000/frequency}} [get_nets {{port|hierarchy("/")|tcl_quote}}]
656655
{% endfor %}
657656
{{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
658657
"""
@@ -723,9 +722,13 @@ def vendor_toolchain(self):
723722
NET "{{port_name}}" {{attr_name}}={{attr_value}};
724723
{% endfor %}
725724
{% endfor %}
726-
{% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
727-
NET "{{net_signal|hierarchy("/")}}" TNM_NET="PRD{{net_signal|hierarchy("/")}}";
728-
TIMESPEC "TS{{net_signal|hierarchy("__")}}"=PERIOD "PRD{{net_signal|hierarchy("/")}}" {{1000000000/frequency}} ns HIGH 50%;
725+
{% for signal, frequency in platform.iter_signal_clock_constraints() -%}
726+
NET "{{signal|hierarchy("/")}}" TNM_NET="PRD{{signal|hierarchy("/")}}";
727+
TIMESPEC "TS{{signal|hierarchy("__")}}"=PERIOD "PRD{{signal|hierarchy("/")}}" {{1000000000/frequency}} ns HIGH 50%;
728+
{% endfor %}
729+
{% for port, frequency in platform.iter_port_clock_constraints() -%}
730+
NET "{{port|hierarchy("/")}}" TNM_NET="PRD{{port|hierarchy("/")}}";
731+
TIMESPEC "TS{{port|hierarchy("__")}}"=PERIOD "PRD{{port|hierarchy("/")}}" {{1000000000/frequency}} ns HIGH 50%;
729732
{% endfor %}
730733
{{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
731734
"""
@@ -848,10 +851,11 @@ def _symbiflow_device(self):
848851
""",
849852
"{{name}}.sdc": r"""
850853
# {{autogenerated}}
851-
{% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
852-
{% if port_signal is none -%}
853-
create_clock -period {{1000000000/frequency}} {{net_signal.name|ascii_escape}}
854-
{% endif %}
854+
{% for signal, frequency in platform.iter_signal_clock_constraints() -%}
855+
create_clock -period {{1000000000/frequency}} {{signal.name|ascii_escape}}
856+
{% endfor %}
857+
{% for port, frequency in platform.iter_port_clock_constraints() -%}
858+
create_clock -period {{1000000000/frequency}} {{port.name|ascii_escape}}
855859
{% endfor %}
856860
"""
857861
}
@@ -1173,7 +1177,8 @@ def create_missing_domain(self, name):
11731177

11741178
def add_clock_constraint(self, clock, frequency):
11751179
super().add_clock_constraint(clock, frequency)
1176-
clock.attrs["keep"] = "TRUE"
1180+
if not isinstance(clock, IOPort):
1181+
clock.attrs["keep"] = "TRUE"
11771182

11781183
def get_io_buffer(self, buffer):
11791184
if isinstance(buffer, io.Buffer):

0 commit comments

Comments
 (0)