X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=litex%2Fbuild%2Fxilinx%2Fvivado.py;h=10a795bd7665533e1f88f5a63179b51621ddf803;hb=b8be9545cc9df790c1038b0b030f0058e0466095;hp=4b9fedfa1a7a5f9b0f2f5adc8a395da7d6ca58b1;hpb=ee6b33e9d3bcfbbdea9709de4bb6670ae6721211;p=litex.git diff --git a/litex/build/xilinx/vivado.py b/litex/build/xilinx/vivado.py index 4b9fedfa..10a795bd 100644 --- a/litex/build/xilinx/vivado.py +++ b/litex/build/xilinx/vivado.py @@ -5,7 +5,8 @@ import os import subprocess import sys -from litex.gen.fhdl.structure import _Fragment +from migen.fhdl.structure import _Fragment + from litex.build.generic_platform import * from litex.build import tools from litex.build.xilinx import common @@ -21,7 +22,7 @@ def _format_constraint(c): elif isinstance(c, Misc): return "set_property " + c.misc.replace("=", " ") elif isinstance(c, Inverted): - return "" + return None else: raise ValueError("unknown constraint {}".format(c)) @@ -33,7 +34,8 @@ def _format_xdc(signame, resname, *constraints): fmt_r += "." + resname[2] r = " ## {}\n".format(fmt_r) for c in fmt_c: - r += c + " [get_ports " + signame + "]\n" + if c is not None: + r += c + " [get_ports " + signame + "]\n" return r @@ -61,7 +63,20 @@ def _run_vivado(build_name, vivado_path, source, ver=None): command = build_script_file else: build_script_contents = "# Autogenerated by LiteX\nset -e\n" - settings = common.settings(vivado_path, "Vivado", ver, first="name") + + # 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 += "vivado -mode batch -source " + build_name + ".tcl\n" build_script_file = "build_" + build_name + ".sh" @@ -77,8 +92,9 @@ class XilinxVivadoToolchain: "keep": ("dont_touch", "true"), "no_retiming": ("dont_touch", "true"), "async_reg": ("async_reg", "true"), - "ars_ff": ("ars_ff", "true"), # user-defined attribute - "ars_false_path": ("ars_false_path", "true"), # user-defined attribute + "mr_ff": ("mr_ff", "true"), # user-defined attribute + "ars_ff1": ("ars_ff1", "true"), # user-defined attribute + "ars_ff2": ("ars_ff2", "true"), # user-defined attribute "no_shreg_extract": None } @@ -90,10 +106,10 @@ class XilinxVivadoToolchain: self.clocks = dict() self.false_paths = set() - def _build_batch(self, platform, sources, edifs, build_name): + def _build_batch(self, platform, sources, edifs, ips, build_name): tcl = [] - tcl.append("create_property ars_ff cell") - tcl.append("create_property ars_false_path net") + tcl.append("create_project -force -name {} -part {}".format(build_name, platform.device)) + tcl.append("set_property XPM_LIBRARIES {XPM_CDC XPM_MEMORY} [current_project]") for filename, language, library in sources: filename_tcl = "{" + filename + "}" tcl.append("add_files " + filename_tcl) @@ -102,6 +118,16 @@ class XilinxVivadoToolchain: for filename in edifs: filename_tcl = "{" + filename + "}" tcl.append("read_edif " + filename_tcl) + + for filename in ips: + filename_tcl = "{" + filename + "}" + ip = os.path.splitext(os.path.basename(filename))[0] + tcl.append("read_ip " + filename_tcl) + tcl.append("upgrade_ip [get_ips {}]".format(ip)) + tcl.append("generate_target all [get_ips {}]".format(ip)) + tcl.append("synth_ip [get_ips {}] -force".format(ip)) + tcl.append("get_files -all -of_objects [get_files {}]".format(filename_tcl)) + tcl.append("read_xdc {}.xdc".format(build_name)) tcl.extend(c.format(build_name=build_name) for c in self.pre_synthesis_commands) # "-include_dirs {}" crashes Vivado 2016.4 @@ -109,7 +135,6 @@ class XilinxVivadoToolchain: 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)) - tcl.append("write_checkpoint -force {}_synth.dcp".format(build_name)) 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)) @@ -117,11 +142,9 @@ class XilinxVivadoToolchain: tcl.append("place_design") if self.with_phys_opt: tcl.append("phys_opt_design -directive AddRetime") - tcl.append("write_checkpoint -force {}_place.dcp".format(build_name)) 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("write_csv -force {}_tracelength.csv".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") @@ -145,12 +168,11 @@ class XilinxVivadoToolchain: " [get_nets {clk}]", clk=clk) for from_, to in sorted(self.false_paths, key=lambda x: (x[0].duid, x[1].duid)): - if (from_ not in self.clocks - or to not in self.clocks): - raise ValueError("Vivado requires period " - "constraints on all clocks used in false paths") platform.add_platform_command( - "set_false_path -from [get_clocks {from_}] -to [get_clocks {to}]", + "set_clock_groups " + "-group [get_clocks -include_generated_clocks -of [get_nets {from_}]] " + "-group [get_clocks -include_generated_clocks -of [get_nets {to}]] " + "-asynchronous", from_=from_, to=to) # make sure add_*_constraint cannot be used again @@ -158,30 +180,37 @@ class XilinxVivadoToolchain: del self.false_paths def _constrain(self, platform): + # 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}}]" + ) # The asychronous reset input to the AsyncResetSynchronizer is a false # path platform.add_platform_command( "set_false_path -quiet " - "-through [get_nets -hier -filter {{ars_false_path==true}}] " - "-to [get_cells -hier -filter {{ars_ff==true}}]" + "-to [get_pins -filter {{REF_PIN_NAME == PRE}} " + "-of [get_cells -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_cells -hier -filter {{ars_ff==true}}] " - "-to [get_cells -hier -filter {{ars_ff==true}}]" + "-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}}]]" ) def build(self, platform, fragment, build_dir="build", build_name="top", toolchain_path=None, source=True, run=True, **kwargs): if toolchain_path is None: if sys.platform == "win32": - toolchain_path = "C:\\Xilinx" + toolchain_path = "C:\\Xilinx\\Vivado" elif sys.platform == "cygwin": - toolchain_path = "/cygdrive/c/Xilinx" + toolchain_path = "/cygdrive/c/Xilinx/Vivado" else: - toolchain_path = "/opt/Xilinx" + toolchain_path = "/opt/Xilinx/Vivado" os.makedirs(build_dir, exist_ok=True) cwd = os.getcwd() os.chdir(build_dir) @@ -195,9 +224,10 @@ 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 - self._build_batch(platform, sources, edifs, build_name) + ips = platform.ips + self._build_batch(platform, sources, edifs, ips, build_name) tools.write_to_file(build_name + ".xdc", _build_xdc(named_sc, named_pc)) if run: _run_vivado(build_name, toolchain_path, source) @@ -212,4 +242,5 @@ class XilinxVivadoToolchain: self.clocks[clk] = period def add_false_path_constraint(self, platform, from_, to): - self.false_paths.add((from_, to)) + if (to, from_) not in self.false_paths: + self.false_paths.add((from_, to))