hdl.ast: simplify Mux implementation.
[nmigen.git] / nmigen / vendor / xilinx.py
1 from abc import abstractproperty
2
3 from ..hdl import *
4 from ..lib.cdc import ResetSynchronizer
5 from ..build import *
6
7
8 __all__ = ["XilinxPlatform"]
9
10
11 class XilinxPlatform(TemplatedPlatform):
12 """
13 Vivado toolchain
14 ----------------
15
16 Required tools:
17 * ``vivado``
18
19 The environment is populated by running the script specified in the environment variable
20 ``NMIGEN_ENV_Vivado``, if present.
21
22 Available overrides:
23 * ``script_after_read``: inserts commands after ``read_xdc`` in Tcl script.
24 * ``script_after_synth``: inserts commands after ``synth_design`` in Tcl script.
25 * ``script_after_place``: inserts commands after ``place_design`` in Tcl script.
26 * ``script_after_route``: inserts commands after ``route_design`` in Tcl script.
27 * ``script_before_bitstream``: inserts commands before ``write_bitstream`` in Tcl script.
28 * ``script_after_bitstream``: inserts commands after ``write_bitstream`` in Tcl script.
29 * ``add_constraints``: inserts commands in XDC file.
30 * ``vivado_opts``: adds extra options for ``vivado``.
31
32 Build products:
33 * ``{{name}}.log``: Vivado log.
34 * ``{{name}}_timing_synth.rpt``: Vivado report.
35 * ``{{name}}_utilization_hierarchical_synth.rpt``: Vivado report.
36 * ``{{name}}_utilization_synth.rpt``: Vivado report.
37 * ``{{name}}_utilization_hierarchical_place.rpt``: Vivado report.
38 * ``{{name}}_utilization_place.rpt``: Vivado report.
39 * ``{{name}}_io.rpt``: Vivado report.
40 * ``{{name}}_control_sets.rpt``: Vivado report.
41 * ``{{name}}_clock_utilization.rpt``: Vivado report.
42 * ``{{name}}_route_status.rpt``: Vivado report.
43 * ``{{name}}_drc.rpt``: Vivado report.
44 * ``{{name}}_methodology.rpt``: Vivado report.
45 * ``{{name}}_timing.rpt``: Vivado report.
46 * ``{{name}}_power.rpt``: Vivado report.
47 * ``{{name}}_route.dcp``: Vivado design checkpoint.
48 * ``{{name}}.bit``: binary bitstream with metadata.
49 * ``{{name}}.bin``: binary bitstream.
50
51 ISE toolchain
52 -------------
53
54 Required tools:
55 * ``xst``
56 * ``ngdbuild``
57 * ``map``
58 * ``par``
59 * ``bitgen``
60
61 The environment is populated by running the script specified in the environment variable
62 ``NMIGEN_ENV_ISE``, if present.
63
64 Available overrides:
65 * ``script_after_run``: inserts commands after ``run`` in XST script.
66 * ``add_constraints``: inserts commands in UCF file.
67 * ``xst_opts``: adds extra options for ``xst``.
68 * ``ngdbuild_opts``: adds extra options for ``ngdbuild``.
69 * ``map_opts``: adds extra options for ``map``.
70 * ``par_opts``: adds extra options for ``par``.
71 * ``bitgen_opts``: adds extra and overrides default options for ``bitgen``;
72 default options: ``-g Compress``.
73
74 Build products:
75 * ``{{name}}.srp``: synthesis report.
76 * ``{{name}}.ngc``: synthesized RTL.
77 * ``{{name}}.bld``: NGDBuild log.
78 * ``{{name}}.ngd``: design database.
79 * ``{{name}}_map.map``: MAP log.
80 * ``{{name}}_map.mrp``: mapping report.
81 * ``{{name}}_map.ncd``: mapped netlist.
82 * ``{{name}}.pcf``: physical constraints.
83 * ``{{name}}_par.par``: PAR log.
84 * ``{{name}}_par_pad.txt``: I/O usage report.
85 * ``{{name}}_par.ncd``: place and routed netlist.
86 * ``{{name}}.drc``: DRC report.
87 * ``{{name}}.bgn``: BitGen log.
88 * ``{{name}}.bit``: binary bitstream with metadata.
89 * ``{{name}}.bin``: raw binary bitstream.
90
91 Symbiflow toolchain
92 -------------------
93
94 Required tools:
95 * ``symbiflow_synth``
96 * ``symbiflow_pack``
97 * ``symbiflow_place``
98 * ``symbiflow_route``
99 * ``symbiflow_write_fasm``
100 * ``symbiflow_write_bitstream``
101
102 The environment is populated by running the script specified in the environment variable
103 ``NMIGEN_ENV_Symbiflow``, if present.
104
105 Available overrides:
106 * ``add_constraints``: inserts commands in XDC file.
107 """
108
109 toolchain = None # selected when creating platform
110
111 device = abstractproperty()
112 package = abstractproperty()
113 speed = abstractproperty()
114
115 @property
116 def _part(self):
117 if self.family in {"ultrascale", "ultrascaleplus"}:
118 return "{}-{}-{}".format(self.device, self.package, self.speed)
119 else:
120 return "{}{}-{}".format(self.device, self.package, self.speed)
121
122 # Vivado templates
123
124 _vivado_required_tools = ["vivado"]
125 _vivado_file_templates = {
126 **TemplatedPlatform.build_script_templates,
127 "build_{{name}}.sh": r"""
128 # {{autogenerated}}
129 set -e{{verbose("x")}}
130 if [ -z "$BASH" ] ; then exec /bin/bash "$0" "$@"; fi
131 [ -n "${{platform._toolchain_env_var}}" ] && . "${{platform._toolchain_env_var}}"
132 {{emit_commands("sh")}}
133 """,
134 "{{name}}.v": r"""
135 /* {{autogenerated}} */
136 {{emit_verilog()}}
137 """,
138 "{{name}}.debug.v": r"""
139 /* {{autogenerated}} */
140 {{emit_debug_verilog()}}
141 """,
142 "{{name}}.tcl": r"""
143 # {{autogenerated}}
144 create_project -force -name {{name}} -part {{platform._part}}
145 {% for file in platform.iter_files(".v", ".sv", ".vhd", ".vhdl") -%}
146 add_files {{file|tcl_escape}}
147 {% endfor %}
148 add_files {{name}}.v
149 read_xdc {{name}}.xdc
150 {% for file in platform.iter_files(".xdc") -%}
151 read_xdc {{file|tcl_escape}}
152 {% endfor %}
153 {{get_override("script_after_read")|default("# (script_after_read placeholder)")}}
154 synth_design -top {{name}}
155 foreach cell [get_cells -quiet -hier -filter {nmigen.vivado.false_path == "TRUE"}] {
156 set_false_path -to $cell
157 }
158 foreach cell [get_cells -quiet -hier -filter {nmigen.vivado.max_delay != ""}] {
159 set clock [get_clocks -of_objects \
160 [all_fanin -flat -startpoints_only [get_pin $cell/D]]]
161 if {[llength $clock] != 0} {
162 set_max_delay -datapath_only -from $clock \
163 -to [get_cells $cell] [get_property nmigen.vivado.max_delay $cell]
164 }
165 }
166 {{get_override("script_after_synth")|default("# (script_after_synth placeholder)")}}
167 report_timing_summary -file {{name}}_timing_synth.rpt
168 report_utilization -hierarchical -file {{name}}_utilization_hierarchical_synth.rpt
169 report_utilization -file {{name}}_utilization_synth.rpt
170 opt_design
171 place_design
172 {{get_override("script_after_place")|default("# (script_after_place placeholder)")}}
173 report_utilization -hierarchical -file {{name}}_utilization_hierarchical_place.rpt
174 report_utilization -file {{name}}_utilization_place.rpt
175 report_io -file {{name}}_io.rpt
176 report_control_sets -verbose -file {{name}}_control_sets.rpt
177 report_clock_utilization -file {{name}}_clock_utilization.rpt
178 route_design
179 {{get_override("script_after_route")|default("# (script_after_route placeholder)")}}
180 phys_opt_design
181 report_timing_summary -no_header -no_detailed_paths
182 write_checkpoint -force {{name}}_route.dcp
183 report_route_status -file {{name}}_route_status.rpt
184 report_drc -file {{name}}_drc.rpt
185 report_methodology -file {{name}}_methodology.rpt
186 report_timing_summary -datasheet -max_paths 10 -file {{name}}_timing.rpt
187 report_power -file {{name}}_power.rpt
188 {{get_override("script_before_bitstream")|default("# (script_before_bitstream placeholder)")}}
189 write_bitstream -force -bin_file {{name}}.bit
190 {{get_override("script_after_bitstream")|default("# (script_after_bitstream placeholder)")}}
191 quit
192 """,
193 "{{name}}.xdc": r"""
194 # {{autogenerated}}
195 {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
196 set_property LOC {{pin_name}} [get_ports {{port_name|tcl_escape}}]
197 {% for attr_name, attr_value in attrs.items() -%}
198 set_property {{attr_name}} {{attr_value|tcl_escape}} [get_ports {{port_name|tcl_escape}}]
199 {% endfor %}
200 {% endfor %}
201 {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
202 {% if port_signal is not none -%}
203 create_clock -name {{port_signal.name|ascii_escape}} -period {{1000000000/frequency}} [get_ports {{port_signal.name|tcl_escape}}]
204 {% else -%}
205 create_clock -name {{net_signal.name|ascii_escape}} -period {{1000000000/frequency}} [get_nets {{net_signal|hierarchy("/")|tcl_escape}}]
206 {% endif %}
207 {% endfor %}
208 {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
209 """
210 }
211 _vivado_command_templates = [
212 r"""
213 {{invoke_tool("vivado")}}
214 {{verbose("-verbose")}}
215 {{get_override("vivado_opts")|options}}
216 -mode batch
217 -log {{name}}.log
218 -source {{name}}.tcl
219 """
220 ]
221
222 # ISE toolchain
223
224 _ise_required_tools = [
225 "xst",
226 "ngdbuild",
227 "map",
228 "par",
229 "bitgen",
230 ]
231 _ise_file_templates = {
232 **TemplatedPlatform.build_script_templates,
233 "build_{{name}}.sh": r"""
234 # {{autogenerated}}
235 set -e{{verbose("x")}}
236 if [ -z "$BASH" ] ; then exec /bin/bash "$0" "$@"; fi
237 [ -n "${{platform._toolchain_env_var}}" ] && . "${{platform._toolchain_env_var}}"
238 {{emit_commands("sh")}}
239 """,
240 "{{name}}.v": r"""
241 /* {{autogenerated}} */
242 {{emit_verilog()}}
243 """,
244 "{{name}}.debug.v": r"""
245 /* {{autogenerated}} */
246 {{emit_debug_verilog()}}
247 """,
248 "{{name}}.prj": r"""
249 # {{autogenerated}}
250 {% for file in platform.iter_files(".vhd", ".vhdl") -%}
251 vhdl work {{file}}
252 {% endfor %}
253 {% for file in platform.iter_files(".v") -%}
254 verilog work {{file}}
255 {% endfor %}
256 verilog work {{name}}.v
257 """,
258 "{{name}}.xst": r"""
259 # {{autogenerated}}
260 run
261 -ifn {{name}}.prj
262 -ofn {{name}}.ngc
263 -top {{name}}
264 -use_new_parser yes
265 -p {{platform.device}}{{platform.package}}-{{platform.speed}}
266 {{get_override("script_after_run")|default("# (script_after_run placeholder)")}}
267 """,
268 "{{name}}.ucf": r"""
269 # {{autogenerated}}
270 {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
271 {% set port_name = port_name|replace("[", "<")|replace("]", ">") -%}
272 NET "{{port_name}}" LOC={{pin_name}};
273 {% for attr_name, attr_value in attrs.items() -%}
274 NET "{{port_name}}" {{attr_name}}={{attr_value}};
275 {% endfor %}
276 {% endfor %}
277 {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
278 NET "{{net_signal|hierarchy("/")}}" TNM_NET="PRD{{net_signal|hierarchy("/")}}";
279 TIMESPEC "TS{{net_signal|hierarchy("__")}}"=PERIOD "PRD{{net_signal|hierarchy("/")}}" {{1000000000/frequency}} ns HIGH 50%;
280 {% endfor %}
281 {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
282 """
283 }
284 _ise_command_templates = [
285 r"""
286 {{invoke_tool("xst")}}
287 {{get_override("xst_opts")|options}}
288 -ifn {{name}}.xst
289 """,
290 r"""
291 {{invoke_tool("ngdbuild")}}
292 {{quiet("-quiet")}}
293 {{verbose("-verbose")}}
294 {{get_override("ngdbuild_opts")|options}}
295 -uc {{name}}.ucf
296 {{name}}.ngc
297 """,
298 r"""
299 {{invoke_tool("map")}}
300 {{verbose("-detail")}}
301 {{get_override("map_opts")|default([])|options}}
302 -w
303 -o {{name}}_map.ncd
304 {{name}}.ngd
305 {{name}}.pcf
306 """,
307 r"""
308 {{invoke_tool("par")}}
309 {{get_override("par_opts")|default([])|options}}
310 -w
311 {{name}}_map.ncd
312 {{name}}_par.ncd
313 {{name}}.pcf
314 """,
315 r"""
316 {{invoke_tool("bitgen")}}
317 {{get_override("bitgen_opts")|default(["-g Compress"])|options}}
318 -w
319 -g Binary:Yes
320 {{name}}_par.ncd
321 {{name}}.bit
322 """
323 ]
324
325 # Symbiflow templates
326
327 _symbiflow_part_map = {
328 "xc7a35ticsg324-1L": "xc7a35tcsg324-1", # Arty-A7
329 }
330
331 _symbiflow_required_tools = [
332 "symbiflow_synth",
333 "symbiflow_pack",
334 "symbiflow_place",
335 "symbiflow_route",
336 "symbiflow_write_fasm",
337 "symbiflow_write_bitstream"
338 ]
339 _symbiflow_file_templates = {
340 **TemplatedPlatform.build_script_templates,
341 "{{name}}.v": r"""
342 /* {{autogenerated}} */
343 {{emit_verilog()}}
344 """,
345 "{{name}}.debug.v": r"""
346 /* {{autogenerated}} */
347 {{emit_debug_verilog()}}
348 """,
349 "{{name}}.pcf": r"""
350 # {{autogenerated}}
351 {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
352 set_io {{port_name}} {{pin_name}}
353 {% endfor %}
354 """,
355 "{{name}}.xdc": r"""
356 # {{autogenerated}}
357 {% for port_name, pin_name, attrs in platform.iter_port_constraints_bits() -%}
358 {% for attr_name, attr_value in attrs.items() -%}
359 set_property {{attr_name}} {{attr_value}} [get_ports {{port_name|tcl_escape}} }]
360 {% endfor %}
361 {% endfor %}
362 {{get_override("add_constraints")|default("# (add_constraints placeholder)")}}
363 """,
364 "{{name}}.sdc": r"""
365 # {{autogenerated}}
366 {% for net_signal, port_signal, frequency in platform.iter_clock_constraints() -%}
367 {% if port_signal is none -%}
368 create_clock -period {{1000000000/frequency}} {{net_signal.name|ascii_escape}}
369 {% endif %}
370 {% endfor %}
371 """
372 }
373 _symbiflow_command_templates = [
374 r"""
375 {{invoke_tool("symbiflow_synth")}}
376 -t {{name}}
377 -v {% for file in platform.iter_files(".v", ".sv", ".vhd", ".vhdl") -%} {{file}} {% endfor %} {{name}}.v
378 -p {{platform._symbiflow_part_map.get(platform._part, platform._part)}}
379 -x {{name}}.xdc
380 """,
381 r"""
382 {{invoke_tool("symbiflow_pack")}}
383 -e {{name}}.eblif
384 -P {{platform._symbiflow_part_map.get(platform._part, platform._part)}}
385 -s {{name}}.sdc
386 """,
387 r"""
388 {{invoke_tool("symbiflow_place")}}
389 -e {{name}}.eblif
390 -p {{name}}.pcf
391 -n {{name}}.net
392 -P {{platform._symbiflow_part_map.get(platform._part, platform._part)}}
393 -s {{name}}.sdc
394 """,
395 r"""
396 {{invoke_tool("symbiflow_route")}}
397 -e {{name}}.eblif
398 -P {{platform._symbiflow_part_map.get(platform._part, platform._part)}}
399 -s {{name}}.sdc
400 """,
401 r"""
402 {{invoke_tool("symbiflow_write_fasm")}}
403 -e {{name}}.eblif
404 -P {{platform._symbiflow_part_map.get(platform._part, platform._part)}}
405 """,
406 r"""
407 {{invoke_tool("symbiflow_write_bitstream")}}
408 -f {{name}}.fasm
409 -p {{platform._symbiflow_part_map.get(platform._part, platform._part)}}
410 -b {{name}}.bit
411 """
412 ]
413
414 # Common logic
415
416 def __init__(self, *, toolchain=None):
417 super().__init__()
418
419 # Determine device family.
420 device = self.device.lower()
421 # Remove the prefix.
422 if device.startswith("xc"):
423 device = device[2:]
424 elif device.startswith("xa"):
425 device = device[2:]
426 elif device.startswith("xqr"):
427 device = device[3:]
428 elif device.startswith("xq"):
429 device = device[2:]
430 else:
431 raise ValueError("Device '{}' is not recognized".format(self.device))
432 # Do actual name matching.
433 if device.startswith("2vp"):
434 self.family = "virtex2p"
435 elif device.startswith("2v"):
436 self.family = "virtex2"
437 elif device.startswith("3sd"):
438 self.family = "spartan3adsp"
439 elif device.startswith("3s"):
440 if device.endswith("a"):
441 self.family = "spartan3a"
442 elif device.endswith("e"):
443 self.family = "spartan3e"
444 else:
445 self.family = "spartan3"
446 elif device.startswith("4v"):
447 self.family = "virtex4"
448 elif device.startswith("5v"):
449 self.family = "virtex5"
450 elif device.startswith("6v"):
451 self.family = "virtex6"
452 elif device.startswith("6s"):
453 self.family = "spartan6"
454 elif device.startswith("7"):
455 self.family = "series7"
456 elif device.startswith(("vu", "ku")):
457 if device.endswith("p"):
458 self.family = "ultrascaleplus"
459 else:
460 self.family = "ultrascale"
461 elif device.startswith(("zu", "u", "k26")):
462 self.family = "ultrascaleplus"
463 elif device.startswith(("v", "2s")):
464 # Match last to avoid conflict with ultrascale.
465 # Yes, Spartan 2 is the same thing as Virtex.
466 if device.endswith("e"):
467 self.family = "virtexe"
468 else:
469 self.family = "virtex"
470
471
472 ISE_FAMILIES = {
473 "virtex", "virtexe",
474 "virtex2", "virtex2p",
475 "spartan3", "spartan3e", "spartan3a", "spartan3adsp",
476 "virtex4",
477 "virtex5",
478 "virtex6",
479 "spartan6",
480 }
481 if toolchain is None:
482 if self.family in ISE_FAMILIES:
483 toolchain = "ISE"
484 else:
485 toolchain = "Vivado"
486
487 assert toolchain in ("Vivado", "ISE", "Symbiflow")
488 if toolchain == "Vivado":
489 if self.family in ISE_FAMILIES:
490 raise ValueError("Family '{}' is not supported by the Vivado toolchain, please use ISE instead".format(self.family))
491 elif toolchain == "ISE":
492 if self.family not in ISE_FAMILIES and self.family != "series7":
493 raise ValueError("Family '{}' is not supported by the ISE toolchain, please use Vivado instead".format(self.family))
494 elif toolchain == "Symbiflow":
495 if self.family != "series7":
496 raise ValueError("Family '{}' is not supported by the Symbiflow toolchain".format(self.family))
497 self.toolchain = toolchain
498
499 @property
500 def required_tools(self):
501 if self.toolchain == "Vivado":
502 return self._vivado_required_tools
503 if self.toolchain == "ISE":
504 return self._ise_required_tools
505 if self.toolchain == "Symbiflow":
506 return self._symbiflow_required_tools
507 assert False
508
509 @property
510 def file_templates(self):
511 if self.toolchain == "Vivado":
512 return self._vivado_file_templates
513 if self.toolchain == "ISE":
514 return self._ise_file_templates
515 if self.toolchain == "Symbiflow":
516 return self._symbiflow_file_templates
517 assert False
518
519 @property
520 def command_templates(self):
521 if self.toolchain == "Vivado":
522 return self._vivado_command_templates
523 if self.toolchain == "ISE":
524 return self._ise_command_templates
525 if self.toolchain == "Symbiflow":
526 return self._symbiflow_command_templates
527 assert False
528
529 def create_missing_domain(self, name):
530 # Xilinx devices have a global write enable (GWE) signal that asserted during configuraiton
531 # and deasserted once it ends. Because it is an asynchronous signal (GWE is driven by logic
532 # syncronous to configuration clock, which is not used by most designs), even though it is
533 # a low-skew global network, its deassertion may violate a setup/hold constraint with
534 # relation to a user clock. The recommended solution is to use a BUFGCE driven by the EOS
535 # signal (if available). For details, see:
536 # * https://www.xilinx.com/support/answers/44174.html
537 # * https://www.xilinx.com/support/documentation/white_papers/wp272.pdf
538
539 STARTUP_PRIMITIVE = {
540 "spartan6": "STARTUP_SPARTAN6",
541 "virtex4": "STARTUP_VIRTEX4",
542 "virtex5": "STARTUP_VIRTEX5",
543 "virtex6": "STARTUP_VIRTEX6",
544 "series7": "STARTUPE2",
545 "ultrascale": "STARTUPE3",
546 "ultrascaleplus": "STARTUPE3",
547 }
548
549 if self.family not in STARTUP_PRIMITIVE or self.toolchain == "Symbiflow":
550 # Spartan 3 and before lacks a STARTUP primitive with EOS output; use a simple ResetSynchronizer
551 # in that case, as is the default.
552 # Symbiflow does not support the STARTUPE2 primitive.
553 return super().create_missing_domain(name)
554
555 if name == "sync" and self.default_clk is not None:
556 clk_i = self.request(self.default_clk).i
557 if self.default_rst is not None:
558 rst_i = self.request(self.default_rst).i
559
560 m = Module()
561 ready = Signal()
562 m.submodules += Instance(STARTUP_PRIMITIVE[self.family], o_EOS=ready)
563 m.domains += ClockDomain("sync", reset_less=self.default_rst is None)
564 if self.toolchain != "Vivado":
565 m.submodules += Instance("BUFGCE", i_CE=ready, i_I=clk_i, o_O=ClockSignal("sync"))
566 elif self.family == "series7":
567 # Actually use BUFGCTRL configured as BUFGCE, since using BUFGCE causes
568 # sim/synth mismatches with Vivado 2019.2, and the suggested workaround
569 # (SIM_DEVICE parameter) breaks Vivado 2017.4.
570 m.submodules += Instance("BUFGCTRL",
571 p_SIM_DEVICE="7SERIES",
572 i_I0=clk_i, i_S0=C(1, 1), i_CE0=ready, i_IGNORE0=C(0, 1),
573 i_I1=C(1, 1), i_S1=C(0, 1), i_CE1=C(0, 1), i_IGNORE1=C(1, 1),
574 o_O=ClockSignal("sync")
575 )
576 else:
577 m.submodules += Instance("BUFGCE",
578 p_SIM_DEVICE="ULTRASCALE",
579 i_CE=ready,
580 i_I=clk_i,
581 o_O=ClockSignal("sync")
582 )
583 if self.default_rst is not None:
584 m.submodules.reset_sync = ResetSynchronizer(rst_i, domain="sync")
585 return m
586
587 def add_clock_constraint(self, clock, frequency):
588 super().add_clock_constraint(clock, frequency)
589 clock.attrs["keep"] = "TRUE"
590
591 def _get_xdr_buffer(self, m, pin, iostd, *, i_invert=False, o_invert=False):
592 XFDDR_FAMILIES = {
593 "virtex2",
594 "virtex2p",
595 "spartan3",
596 }
597 XDDR2_FAMILIES = {
598 "spartan3e",
599 "spartan3a",
600 "spartan3adsp",
601 "spartan6",
602 }
603 XDDR_FAMILIES = {
604 "virtex4",
605 "virtex5",
606 "virtex6",
607 "series7",
608 }
609 XDDRE1_FAMILIES = {
610 "ultrascale",
611 "ultrascaleplus",
612 }
613
614 def get_iob_dff(clk, d, q):
615 # SDR I/O is performed by packing a flip-flop into the pad IOB.
616 for bit in range(len(q)):
617 m.submodules += Instance("FDCE",
618 a_IOB="TRUE",
619 i_C=clk,
620 i_CE=Const(1),
621 i_CLR=Const(0),
622 i_D=d[bit],
623 o_Q=q[bit]
624 )
625
626 def get_dff(clk, d, q):
627 for bit in range(len(q)):
628 m.submodules += Instance("FDCE",
629 i_C=clk,
630 i_CE=Const(1),
631 i_CLR=Const(0),
632 i_D=d[bit],
633 o_Q=q[bit]
634 )
635
636 def get_ifddr(clk, io, q0, q1):
637 assert self.family in XFDDR_FAMILIES
638 for bit in range(len(q0)):
639 m.submodules += Instance("IFDDRCPE",
640 i_C0=clk, i_C1=~clk,
641 i_CE=Const(1),
642 i_CLR=Const(0), i_PRE=Const(0),
643 i_D=io[bit],
644 o_Q0=q0[bit], o_Q1=q1[bit]
645 )
646
647 def get_iddr2(clk, d, q0, q1, alignment):
648 assert self.family in XDDR2_FAMILIES
649 for bit in range(len(q0)):
650 m.submodules += Instance("IDDR2",
651 p_DDR_ALIGNMENT=alignment,
652 p_SRTYPE="ASYNC",
653 p_INIT_Q0=C(0, 1), p_INIT_Q1=C(0, 1),
654 i_C0=clk, i_C1=~clk,
655 i_CE=Const(1),
656 i_S=Const(0), i_R=Const(0),
657 i_D=d[bit],
658 o_Q0=q0[bit], o_Q1=q1[bit]
659 )
660
661 def get_iddr(clk, d, q1, q2):
662 assert self.family in XDDR_FAMILIES or self.family in XDDRE1_FAMILIES
663 for bit in range(len(q1)):
664 if self.family in XDDR_FAMILIES:
665 m.submodules += Instance("IDDR",
666 p_DDR_CLK_EDGE="SAME_EDGE_PIPELINED",
667 p_SRTYPE="ASYNC",
668 p_INIT_Q1=C(0, 1), p_INIT_Q2=C(0, 1),
669 i_C=clk,
670 i_CE=Const(1),
671 i_S=Const(0), i_R=Const(0),
672 i_D=d[bit],
673 o_Q1=q1[bit], o_Q2=q2[bit]
674 )
675 else:
676 m.submodules += Instance("IDDRE1",
677 p_DDR_CLK_EDGE="SAME_EDGE_PIPELINED",
678 p_IS_C_INVERTED=C(0, 1), p_IS_CB_INVERTED=C(1, 1),
679 i_C=clk, i_CB=clk,
680 i_R=Const(0),
681 i_D=d[bit],
682 o_Q1=q1[bit], o_Q2=q2[bit]
683 )
684
685 def get_fddr(clk, d0, d1, q):
686 for bit in range(len(q)):
687 if self.family in XFDDR_FAMILIES:
688 m.submodules += Instance("FDDRCPE",
689 i_C0=clk, i_C1=~clk,
690 i_CE=Const(1),
691 i_PRE=Const(0), i_CLR=Const(0),
692 i_D0=d0[bit], i_D1=d1[bit],
693 o_Q=q[bit]
694 )
695 else:
696 m.submodules += Instance("ODDR2",
697 p_DDR_ALIGNMENT="NONE",
698 p_SRTYPE="ASYNC",
699 p_INIT=C(0, 1),
700 i_C0=clk, i_C1=~clk,
701 i_CE=Const(1),
702 i_S=Const(0), i_R=Const(0),
703 i_D0=d0[bit], i_D1=d1[bit],
704 o_Q=q[bit]
705 )
706
707 def get_oddr(clk, d1, d2, q):
708 for bit in range(len(q)):
709 if self.family in XDDR2_FAMILIES:
710 m.submodules += Instance("ODDR2",
711 p_DDR_ALIGNMENT="C0",
712 p_SRTYPE="ASYNC",
713 p_INIT=C(0, 1),
714 i_C0=clk, i_C1=~clk,
715 i_CE=Const(1),
716 i_S=Const(0), i_R=Const(0),
717 i_D0=d1[bit], i_D1=d2[bit],
718 o_Q=q[bit]
719 )
720 elif self.family in XDDR_FAMILIES:
721 m.submodules += Instance("ODDR",
722 p_DDR_CLK_EDGE="SAME_EDGE",
723 p_SRTYPE="ASYNC",
724 p_INIT=C(0, 1),
725 i_C=clk,
726 i_CE=Const(1),
727 i_S=Const(0), i_R=Const(0),
728 i_D1=d1[bit], i_D2=d2[bit],
729 o_Q=q[bit]
730 )
731 elif self.family in XDDRE1_FAMILIES:
732 m.submodules += Instance("ODDRE1",
733 p_SRVAL=C(0, 1),
734 i_C=clk,
735 i_SR=Const(0),
736 i_D1=d1[bit], i_D2=d2[bit],
737 o_Q=q[bit]
738 )
739
740 def get_ineg(y, invert):
741 if invert:
742 a = Signal.like(y, name_suffix="_n")
743 m.d.comb += y.eq(~a)
744 return a
745 else:
746 return y
747
748 def get_oneg(a, invert):
749 if invert:
750 y = Signal.like(a, name_suffix="_n")
751 m.d.comb += y.eq(~a)
752 return y
753 else:
754 return a
755
756 if "i" in pin.dir:
757 if pin.xdr < 2:
758 pin_i = get_ineg(pin.i, i_invert)
759 elif pin.xdr == 2:
760 pin_i0 = get_ineg(pin.i0, i_invert)
761 pin_i1 = get_ineg(pin.i1, i_invert)
762 if "o" in pin.dir:
763 if pin.xdr < 2:
764 pin_o = get_oneg(pin.o, o_invert)
765 elif pin.xdr == 2:
766 pin_o0 = get_oneg(pin.o0, o_invert)
767 pin_o1 = get_oneg(pin.o1, o_invert)
768
769 i = o = t = None
770 if "i" in pin.dir:
771 i = Signal(pin.width, name="{}_xdr_i".format(pin.name))
772 if "o" in pin.dir:
773 o = Signal(pin.width, name="{}_xdr_o".format(pin.name))
774 if pin.dir in ("oe", "io"):
775 t = Signal(1, name="{}_xdr_t".format(pin.name))
776
777 if pin.xdr == 0:
778 if "i" in pin.dir:
779 i = pin_i
780 if "o" in pin.dir:
781 o = pin_o
782 if pin.dir in ("oe", "io"):
783 t = ~pin.oe
784 elif pin.xdr == 1:
785 if "i" in pin.dir:
786 get_iob_dff(pin.i_clk, i, pin_i)
787 if "o" in pin.dir:
788 get_iob_dff(pin.o_clk, pin_o, o)
789 if pin.dir in ("oe", "io"):
790 get_iob_dff(pin.o_clk, ~pin.oe, t)
791 elif pin.xdr == 2:
792 # On Spartan 3E/3A, the situation with DDR registers is messy: while the hardware
793 # supports same-edge alignment, it does so by borrowing the resources of the other
794 # pin in the differential pair (if any). Since we cannot be sure if the other pin
795 # is actually unused (or if the pin is even part of a differential pair in the first
796 # place), we only use the hardware alignment feature in two cases:
797 #
798 # - differential inputs (since the other pin's input registers will be unused)
799 # - true differential outputs (since they use only one pin's output registers,
800 # as opposed to pseudo-differential outputs that use both)
801 TRUE_DIFF_S3EA = {
802 "LVDS_33", "LVDS_25",
803 "MINI_LVDS_33", "MINI_LVDS_25",
804 "RSDS_33", "RSDS_25",
805 "PPDS_33", "PPDS_25",
806 "TMDS_33",
807 }
808 DIFF_S3EA = TRUE_DIFF_S3EA | {
809 "DIFF_HSTL_I",
810 "DIFF_HSTL_III",
811 "DIFF_HSTL_I_18",
812 "DIFF_HSTL_II_18",
813 "DIFF_HSTL_III_18",
814 "DIFF_SSTL3_I",
815 "DIFF_SSTL3_II",
816 "DIFF_SSTL2_I",
817 "DIFF_SSTL2_II",
818 "DIFF_SSTL18_I",
819 "DIFF_SSTL18_II",
820 "BLVDS_25",
821 }
822 if "i" in pin.dir:
823 if self.family in XFDDR_FAMILIES:
824 # First-generation input DDR register: basically just two FFs with opposite
825 # clocks. Add a register on both outputs, so that they enter fabric on
826 # the same clock edge, adding one cycle of latency.
827 i0_ff = Signal.like(pin_i0, name_suffix="_ff")
828 i1_ff = Signal.like(pin_i1, name_suffix="_ff")
829 get_dff(pin.i_clk, i0_ff, pin_i0)
830 get_dff(pin.i_clk, i1_ff, pin_i1)
831 get_iob_dff(pin.i_clk, i, i0_ff)
832 get_iob_dff(~pin.i_clk, i, i1_ff)
833 elif self.family in XDDR2_FAMILIES:
834 if self.family == 'spartan6' or iostd in DIFF_S3EA:
835 # Second-generation input DDR register: hw realigns i1 to positive clock edge,
836 # but also misaligns it with i0 input. Re-register first input before it
837 # enters fabric. This allows both inputs to enter fabric on the same clock
838 # edge, and adds one cycle of latency.
839 i0_ff = Signal.like(pin_i0, name_suffix="_ff")
840 get_dff(pin.i_clk, i0_ff, pin_i0)
841 get_iddr2(pin.i_clk, i, i0_ff, pin_i1, "C0")
842 else:
843 # No extra register available for hw alignment, use extra registers.
844 i0_ff = Signal.like(pin_i0, name_suffix="_ff")
845 i1_ff = Signal.like(pin_i1, name_suffix="_ff")
846 get_dff(pin.i_clk, i0_ff, pin_i0)
847 get_dff(pin.i_clk, i1_ff, pin_i1)
848 get_iddr2(pin.i_clk, i, i0_ff, i1_ff, "NONE")
849 else:
850 # Third-generation input DDR register: does all of the above on its own.
851 get_iddr(pin.i_clk, i, pin_i0, pin_i1)
852 if "o" in pin.dir:
853 if self.family in XFDDR_FAMILIES or self.family == "spartan3e" or (self.family.startswith("spartan3a") and iostd not in TRUE_DIFF_S3EA):
854 # For this generation, we need to realign o1 input ourselves.
855 o1_ff = Signal.like(pin_o1, name_suffix="_ff")
856 get_dff(pin.o_clk, pin_o1, o1_ff)
857 get_fddr(pin.o_clk, pin_o0, o1_ff, o)
858 else:
859 get_oddr(pin.o_clk, pin_o0, pin_o1, o)
860 if pin.dir in ("oe", "io"):
861 if self.family == "spartan6":
862 get_oddr(pin.o_clk, ~pin.oe, ~pin.oe, t)
863 else:
864 get_iob_dff(pin.o_clk, ~pin.oe, t)
865 else:
866 assert False
867
868 return (i, o, t)
869
870 def _get_valid_xdrs(self):
871 if self.family in {"virtex", "virtexe"}:
872 return (0, 1)
873 else:
874 return (0, 1, 2)
875
876 def get_input(self, pin, port, attrs, invert):
877 self._check_feature("single-ended input", pin, attrs,
878 valid_xdrs=self._get_valid_xdrs(), valid_attrs=True)
879 m = Module()
880 i, o, t = self._get_xdr_buffer(m, pin, attrs.get("IOSTANDARD"), i_invert=invert)
881 for bit in range(pin.width):
882 m.submodules["{}_{}".format(pin.name, bit)] = Instance("IBUF",
883 i_I=port.io[bit],
884 o_O=i[bit]
885 )
886 return m
887
888 def get_output(self, pin, port, attrs, invert):
889 self._check_feature("single-ended output", pin, attrs,
890 valid_xdrs=self._get_valid_xdrs(), valid_attrs=True)
891 m = Module()
892 i, o, t = self._get_xdr_buffer(m, pin, attrs.get("IOSTANDARD"), o_invert=invert)
893 if self.toolchain != "Symbiflow":
894 for bit in range(pin.width):
895 m.submodules["{}_{}".format(pin.name, bit)] = Instance("OBUF",
896 i_I=o[bit],
897 o_O=port.io[bit]
898 )
899 else:
900 m.d.comb += port.eq(self._invert_if(invert, o))
901 return m
902
903 def get_tristate(self, pin, port, attrs, invert):
904 if self.toolchain == "Symbiflow":
905 return super().get_tristate(pin, port, attrs, invert)
906
907 self._check_feature("single-ended tristate", pin, attrs,
908 valid_xdrs=self._get_valid_xdrs(), valid_attrs=True)
909 m = Module()
910 i, o, t = self._get_xdr_buffer(m, pin, attrs.get("IOSTANDARD"), o_invert=invert)
911 for bit in range(pin.width):
912 m.submodules["{}_{}".format(pin.name, bit)] = Instance("OBUFT",
913 i_T=t,
914 i_I=o[bit],
915 o_O=port.io[bit]
916 )
917 return m
918
919 def get_input_output(self, pin, port, attrs, invert):
920 if self.toolchain == "Symbiflow":
921 return super().get_input_output(pin, port, attrs, invert)
922
923 self._check_feature("single-ended input/output", pin, attrs,
924 valid_xdrs=self._get_valid_xdrs(), valid_attrs=True)
925 m = Module()
926 i, o, t = self._get_xdr_buffer(m, pin, attrs.get("IOSTANDARD"), i_invert=invert, o_invert=invert)
927 for bit in range(pin.width):
928 m.submodules["{}_{}".format(pin.name, bit)] = Instance("IOBUF",
929 i_T=t,
930 i_I=o[bit],
931 o_O=i[bit],
932 io_IO=port.io[bit]
933 )
934 return m
935
936 def get_diff_input(self, pin, port, attrs, invert):
937 if self.toolchain == "Symbiflow":
938 return super().get_diff_input(pin, port, attrs, invert)
939
940 self._check_feature("differential input", pin, attrs,
941 valid_xdrs=self._get_valid_xdrs(), valid_attrs=True)
942 m = Module()
943 i, o, t = self._get_xdr_buffer(m, pin, attrs.get("IOSTANDARD", "LVDS_25"), i_invert=invert)
944 for bit in range(pin.width):
945 m.submodules["{}_{}".format(pin.name, bit)] = Instance("IBUFDS",
946 i_I=port.p[bit], i_IB=port.n[bit],
947 o_O=i[bit]
948 )
949 return m
950
951 def get_diff_output(self, pin, port, attrs, invert):
952 if self.toolchain == "Symbiflow":
953 return super().get_diff_output(pin, port, attrs, invert)
954
955 self._check_feature("differential output", pin, attrs,
956 valid_xdrs=self._get_valid_xdrs(), valid_attrs=True)
957 m = Module()
958 i, o, t = self._get_xdr_buffer(m, pin, attrs.get("IOSTANDARD", "LVDS_25"), o_invert=invert)
959 for bit in range(pin.width):
960 m.submodules["{}_{}".format(pin.name, bit)] = Instance("OBUFDS",
961 i_I=o[bit],
962 o_O=port.p[bit], o_OB=port.n[bit]
963 )
964 return m
965
966 def get_diff_tristate(self, pin, port, attrs, invert):
967 if self.toolchain == "Symbiflow":
968 return super().get_diff_tristate(pin, port, attrs, invert)
969
970 self._check_feature("differential tristate", pin, attrs,
971 valid_xdrs=self._get_valid_xdrs(), valid_attrs=True)
972 m = Module()
973 i, o, t = self._get_xdr_buffer(m, pin, attrs.get("IOSTANDARD", "LVDS_25"), o_invert=invert)
974 for bit in range(pin.width):
975 m.submodules["{}_{}".format(pin.name, bit)] = Instance("OBUFTDS",
976 i_T=t,
977 i_I=o[bit],
978 o_O=port.p[bit], o_OB=port.n[bit]
979 )
980 return m
981
982 def get_diff_input_output(self, pin, port, attrs, invert):
983 if self.toolchain == "Symbiflow":
984 return super().get_diff_input_output(pin, port, attrs, invert)
985
986 self._check_feature("differential input/output", pin, attrs,
987 valid_xdrs=self._get_valid_xdrs(), valid_attrs=True)
988 m = Module()
989 i, o, t = self._get_xdr_buffer(m, pin, attrs.get("IOSTANDARD", "LVDS_25"), i_invert=invert, o_invert=invert)
990 for bit in range(pin.width):
991 m.submodules["{}_{}".format(pin.name, bit)] = Instance("IOBUFDS",
992 i_T=t,
993 i_I=o[bit],
994 o_O=i[bit],
995 io_IO=port.p[bit], io_IOB=port.n[bit]
996 )
997 return m
998
999 # The synchronizer implementations below apply two separate but related timing constraints.
1000 #
1001 # First, the ASYNC_REG attribute prevents inference of shift registers from synchronizer FFs,
1002 # and constraints the FFs to be placed as close as possible, ideally in one CLB. This attribute
1003 # only affects the synchronizer FFs themselves.
1004 #
1005 # Second, for Vivado only, the nmigen.vivado.false_path or nmigen.vivado.max_delay attribute
1006 # affects the path into the synchronizer. If maximum input delay is specified, a datapath-only
1007 # maximum delay constraint is applied, limiting routing delay (and therefore skew) at
1008 # the synchronizer input. Otherwise, a false path constraint is used to omit the input path
1009 # from the timing analysis.
1010
1011 def get_ff_sync(self, ff_sync):
1012 m = Module()
1013 flops = [Signal(ff_sync.i.shape(), name="stage{}".format(index),
1014 reset=ff_sync._reset, reset_less=ff_sync._reset_less,
1015 attrs={"ASYNC_REG": "TRUE"})
1016 for index in range(ff_sync._stages)]
1017 if self.toolchain == "Vivado":
1018 if ff_sync._max_input_delay is None:
1019 flops[0].attrs["nmigen.vivado.false_path"] = "TRUE"
1020 else:
1021 flops[0].attrs["nmigen.vivado.max_delay"] = str(ff_sync._max_input_delay * 1e9)
1022 elif ff_sync._max_input_delay is not None:
1023 raise NotImplementedError("Platform '{}' does not support constraining input delay "
1024 "for FFSynchronizer"
1025 .format(type(self).__name__))
1026 for i, o in zip((ff_sync.i, *flops), flops):
1027 m.d[ff_sync._o_domain] += o.eq(i)
1028 m.d.comb += ff_sync.o.eq(flops[-1])
1029 return m
1030
1031
1032 def get_async_ff_sync(self, async_ff_sync):
1033 m = Module()
1034 m.domains += ClockDomain("async_ff", async_reset=True, local=True)
1035 flops = [Signal(1, name="stage{}".format(index), reset=1,
1036 attrs={"ASYNC_REG": "TRUE"})
1037 for index in range(async_ff_sync._stages)]
1038 if self.toolchain == "Vivado":
1039 if async_ff_sync._max_input_delay is None:
1040 flops[0].attrs["nmigen.vivado.false_path"] = "TRUE"
1041 else:
1042 flops[0].attrs["nmigen.vivado.max_delay"] = str(async_ff_sync._max_input_delay * 1e9)
1043 elif async_ff_sync._max_input_delay is not None:
1044 raise NotImplementedError("Platform '{}' does not support constraining input delay "
1045 "for AsyncFFSynchronizer"
1046 .format(type(self).__name__))
1047 for i, o in zip((0, *flops), flops):
1048 m.d.async_ff += o.eq(i)
1049
1050 if async_ff_sync._edge == "pos":
1051 m.d.comb += ResetSignal("async_ff").eq(async_ff_sync.i)
1052 else:
1053 m.d.comb += ResetSignal("async_ff").eq(~async_ff_sync.i)
1054
1055 m.d.comb += [
1056 ClockSignal("async_ff").eq(ClockSignal(async_ff_sync._o_domain)),
1057 async_ff_sync.o.eq(flops[-1])
1058 ]
1059
1060 return m