-# This file is Copyright (c) 2014 Florent Kermarrec <florent@enjoy-digital.fr>
+# This file is Copyright (c) 2014-2019 Florent Kermarrec <florent@enjoy-digital.fr>
# License: BSD
import os
import subprocess
import sys
+import math
+from distutils.spawn import find_executable
from migen.fhdl.structure import _Fragment
def _run_vivado(build_name, vivado_path, source, ver=None):
if sys.platform == "win32" or sys.platform == "cygwin":
- build_script_contents = "REM Autogenerated by Migen\n"
+ build_script_contents = "REM Autogenerated by LiteX / git: " + tools.get_litex_git_revision() + "\n"
build_script_contents += "vivado -mode batch -source " + build_name + ".tcl\n"
build_script_file = "build_" + build_name + ".bat"
tools.write_to_file(build_script_file, build_script_contents)
command = build_script_file
else:
- build_script_contents = "# Autogenerated by Migen\nset -e\n"
-
- # For backwards compatibility with ISE paths, also
- # look for a version in a subdirectory named "Vivado"
- # under the current directory.
- paths_to_try = [vivado_path, os.path.join(vivado_path, "Vivado")]
- for p in paths_to_try:
- try:
- settings = common.settings(p, ver)
- except OSError:
- continue
- break
- else:
- raise OSError("Unable to locate Vivado directory or settings.")
+ build_script_contents = "# Autogenerated by LiteX / git: " + tools.get_litex_git_revision() + "\nset -e\n"
+ # Only source Vivado settings if not already in our $PATH
+ if not find_executable("vivado"):
+ # For backwards compatibility with ISE paths, also
+ # look for a version in a subdirectory named "Vivado"
+ # under the current directory.
+ paths_to_try = [vivado_path, os.path.join(vivado_path, "Vivado")]
+ for p in paths_to_try:
+ try:
+ settings = common.settings(p, ver)
+ except OSError:
+ continue
+ break
+ else:
+ raise OSError("Unable to locate Vivado directory or settings.")
+ build_script_contents += "source " + settings + "\n"
- build_script_contents += "source " + settings + "\n"
build_script_contents += "vivado -mode batch -source " + build_name + ".tcl\n"
build_script_file = "build_" + build_name + ".sh"
tools.write_to_file(build_script_file, build_script_contents)
self.bitstream_commands = []
self.additional_commands = []
self.pre_synthesis_commands = []
- self.with_phys_opt = False
+ self.with_phys_opt = False # deprecated -> vivado_post_place_phys_opt_directive
+ self.incremental_implementation = False
+ self.vivado_synth_directive = 'default'
+ self.opt_directive = 'default'
+ self.vivado_place_directive = 'default'
+ self.vivado_post_place_phys_opt_directive = None
+ self.vivado_route_directive = 'default'
+ self.vivado_post_route_phys_opt_directive = 'default'
self.clocks = dict()
self.false_paths = set()
- def _build_batch(self, platform, sources, edifs, ips, build_name, synth_mode="vivado"):
+ def _build_batch(self, platform, sources, edifs, ips, build_name, synth_mode, enable_xpm):
+ assert synth_mode in ["vivado", "yosys"]
tcl = []
tcl.append("create_project -force -name {} -part {}".format(build_name, platform.device))
- tcl.append("set_property XPM_LIBRARIES {XPM_CDC XPM_MEMORY} [current_project]")
+ tcl.append("set_msg_config -id {Common 17-55} -new_severity {Warning}")
+ if enable_xpm:
+ tcl.append("set_property XPM_LIBRARIES {XPM_CDC XPM_MEMORY} [current_project]")
if synth_mode == "vivado":
# "-include_dirs {}" crashes Vivado 2016.4
for filename, language, library in sources:
filename_tcl = "{" + filename + "}"
tcl.append("add_files " + filename_tcl)
- tcl.append("set_property library {} [get_files {}]"
- .format(library, filename_tcl))
+ if language == "vhdl":
+ tcl.append("set_property library {} [get_files {}]"
+ .format(library, filename_tcl))
for filename in edifs:
filename_tcl = "{" + filename + "}"
tcl.append("read_edif " + filename_tcl)
tcl.extend(c.format(build_name=build_name) for c in self.pre_synthesis_commands)
if synth_mode == "vivado":
+ synth_cmd = "synth_design -directive {} -top {} -part {}".format(self.vivado_synth_directive,
+ build_name, platform.device)
if platform.verilog_include_paths:
- tcl.append("synth_design -top {} -part {} -include_dirs {{{}}}".format(build_name, platform.device, " ".join(platform.verilog_include_paths)))
- else:
- tcl.append("synth_design -top {} -part {}".format(build_name, platform.device))
+ synth_cmd += " -include_dirs {{{}}}".format(" ".join(platform.verilog_include_paths))
+ tcl.append(synth_cmd)
elif synth_mode == "yosys":
tcl.append("read_edif {}.edif".format(build_name))
tcl.append("link_design -top {} -part {}".format(build_name, platform.device))
tcl.append("report_timing_summary -file {}_timing_synth.rpt".format(build_name))
tcl.append("report_utilization -hierarchical -file {}_utilization_hierarchical_synth.rpt".format(build_name))
tcl.append("report_utilization -file {}_utilization_synth.rpt".format(build_name))
- tcl.append("opt_design")
- tcl.append("place_design")
+ tcl.append("opt_design -directive {}".format(self.opt_directive))
+ if self.incremental_implementation:
+ tcl.append("read_checkpoint -incremental {}_route.dcp".format(build_name))
+ tcl.append("place_design -directive {}".format(self.vivado_place_directive))
if self.with_phys_opt:
- tcl.append("phys_opt_design -directive AddRetime")
+ tools.deprecated_warning('with_phys_opt -> vivado_post_place_phys_opt_directive')
+ self.vivado_post_place_phys_opt_directive = 'AddRetime'
+ if self.vivado_post_place_phys_opt_directive:
+ tcl.append("phys_opt_design -directive {}".format(self.vivado_post_place_phys_opt_directive))
tcl.append("report_utilization -hierarchical -file {}_utilization_hierarchical_place.rpt".format(build_name))
tcl.append("report_utilization -file {}_utilization_place.rpt".format(build_name))
tcl.append("report_io -file {}_io.rpt".format(build_name))
tcl.append("report_control_sets -verbose -file {}_control_sets.rpt".format(build_name))
tcl.append("report_clock_utilization -file {}_clock_utilization.rpt".format(build_name))
- tcl.append("route_design")
- tcl.append("phys_opt_design")
+ tcl.append("route_design -directive {}".format(self.vivado_route_directive))
+ tcl.append("phys_opt_design -directive {}".format(self.vivado_post_route_phys_opt_directive))
tcl.append("report_timing_summary -no_header -no_detailed_paths")
tcl.append("write_checkpoint -force {}_route.dcp".format(build_name))
tcl.append("report_route_status -file {}_route_status.rpt".format(build_name))
# The asynchronous input to a MultiReg is a false path
platform.add_platform_command(
"set_false_path -quiet "
- "-to [get_nets -filter {{mr_ff == TRUE}}]"
+ "-to [get_nets -quiet -filter {{mr_ff == TRUE}}]"
)
# The asychronous reset input to the AsyncResetSynchronizer is a false
# path
platform.add_platform_command(
"set_false_path -quiet "
- "-to [get_pins -filter {{REF_PIN_NAME == PRE}} "
- "-of [get_cells -filter {{ars_ff1 == TRUE || ars_ff2 == TRUE}}]]"
+ "-to [get_pins -quiet -filter {{REF_PIN_NAME == PRE}} "
+ "-of [get_cells -quiet -filter {{ars_ff1 == TRUE || ars_ff2 == TRUE}}]]"
)
# clock_period-2ns to resolve metastability on the wire between the
# AsyncResetSynchronizer FFs
platform.add_platform_command(
"set_max_delay 2 -quiet "
- "-from [get_pins -filter {{REF_PIN_NAME == Q}} "
- "-of [get_cells -filter {{ars_ff1 == TRUE}}]] "
- "-to [get_pins -filter {{REF_PIN_NAME == D}} "
- "-of [get_cells -filter {{ars_ff2 == TRUE}}]]"
+ "-from [get_pins -quiet -filter {{REF_PIN_NAME == Q}} "
+ "-of [get_cells -quiet -filter {{ars_ff1 == TRUE}}]] "
+ "-to [get_pins -quiet -filter {{REF_PIN_NAME == D}} "
+ "-of [get_cells -quiet -filter {{ars_ff2 == TRUE}}]]"
)
def build(self, platform, fragment, build_dir="build", build_name="top",
- toolchain_path="/opt/Xilinx/Vivado", source=True, run=True, synth_mode="vivado", **kwargs):
+ toolchain_path="/opt/Xilinx/Vivado", source=True, run=True,
+ synth_mode="vivado", enable_xpm=False, **kwargs):
if toolchain_path is None:
toolchain_path = "/opt/Xilinx/Vivado"
os.makedirs(build_dir, exist_ok=True)
sources = platform.sources | {(v_file, "verilog", "work")}
edifs = platform.edifs
ips = platform.ips
- self._build_batch(platform, sources, edifs, ips, build_name, synth_mode=synth_mode)
+ self._build_batch(platform, sources, edifs, ips, build_name, synth_mode, enable_xpm)
tools.write_to_file(build_name + ".xdc", _build_xdc(named_sc, named_pc))
if run:
if synth_mode == "yosys":
def add_period_constraint(self, platform, clk, period):
if clk in self.clocks:
raise ValueError("A period constraint already exists")
+ period = math.floor(period*1e3)/1e3 # round to lowest picosecond
self.clocks[clk] = period
def add_false_path_constraint(self, platform, from_, to):