X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=litex%2Fbuild%2Fxilinx%2Fvivado.py;h=244288e050dd524f4951c9a629f5efc85cb92abc;hb=861eea8a07c40fb88ccd6d786b03a5eb54d7fd7a;hp=974958c9c56ac24fba70f971f075db78bd2ba614;hpb=b200ce9983c6efafcb992b9f93961bce5f5a6c39;p=litex.git diff --git a/litex/build/xilinx/vivado.py b/litex/build/xilinx/vivado.py index 974958c9..244288e0 100644 --- a/litex/build/xilinx/vivado.py +++ b/litex/build/xilinx/vivado.py @@ -1,9 +1,11 @@ -# This file is Copyright (c) 2014 Florent Kermarrec +# This file is Copyright (c) 2014-2019 Florent Kermarrec # License: BSD import os import subprocess import sys +import math +from distutils.spawn import find_executable from migen.fhdl.structure import _Fragment @@ -56,28 +58,29 @@ def _build_xdc(named_sc, named_pc): def _run_vivado(build_name, vivado_path, source, ver=None): if sys.platform == "win32" or sys.platform == "cygwin": - build_script_contents = "REM Autogenerated by LiteX\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 LiteX\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) @@ -102,21 +105,32 @@ class XilinxVivadoToolchain: 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) @@ -134,10 +148,11 @@ class XilinxVivadoToolchain: 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)) @@ -147,17 +162,22 @@ class XilinxVivadoToolchain: 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)) @@ -194,35 +214,30 @@ class XilinxVivadoToolchain: # 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=None, source=True, run=True, **kwargs): - synth_mode = kwargs.get('synth_mode', 'yosys') + toolchain_path="/opt/Xilinx/Vivado", source=True, run=True, + synth_mode="vivado", enable_xpm=False, **kwargs): if toolchain_path is None: - if sys.platform == "win32": - toolchain_path = "C:\\Xilinx\\Vivado" - elif sys.platform == "cygwin": - toolchain_path = "/cygdrive/c/Xilinx/Vivado" - else: - toolchain_path = "/opt/Xilinx/Vivado" + toolchain_path = "/opt/Xilinx/Vivado" os.makedirs(build_dir, exist_ok=True) cwd = os.getcwd() os.chdir(build_dir) @@ -236,16 +251,14 @@ class XilinxVivadoToolchain: named_sc, named_pc = platform.resolve_signals(v_output.ns) v_file = build_name + ".v" v_output.write(v_file) - sources = platform.sources + [(v_file, "verilog", "work")] + 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": common._run_yosys(platform.device, sources, platform.verilog_include_paths, build_name) - else: - raise OSError("Error!") _run_vivado(build_name, toolchain_path, source) os.chdir(cwd) @@ -255,6 +268,7 @@ class XilinxVivadoToolchain: 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):