From bd876d4cd6315ff7121bde7098532eb26697df4b Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 28 Jun 2017 22:47:13 +0200 Subject: [PATCH] merge migen 9a6fdea3 changes --- litex/build/xilinx/common.py | 17 ++++++++++------- litex/build/xilinx/ise.py | 2 ++ litex/build/xilinx/vivado.py | 37 ++++++++++++++++++++++++++++++------ litex/gen/fhdl/decorators.py | 4 +++- litex/gen/fhdl/specials.py | 6 +++++- litex/gen/fhdl/structure.py | 26 +++++++++++++++++++++++-- litex/gen/fhdl/tools.py | 5 +++-- litex/gen/fhdl/verilog.py | 17 +++++++++++------ litex/gen/genlib/fifo.py | 1 + litex/gen/sim/core.py | 2 +- 10 files changed, 91 insertions(+), 26 deletions(-) diff --git a/litex/build/xilinx/common.py b/litex/build/xilinx/common.py index 75412a13..c747945b 100644 --- a/litex/build/xilinx/common.py +++ b/litex/build/xilinx/common.py @@ -32,7 +32,6 @@ if _have_colorama: def settings(path, ver=None, sub=None): - assert path is not None if ver is None: vers = list(tools.versions(path)) if not vers: @@ -77,15 +76,19 @@ class XilinxMultiReg: class XilinxAsyncResetSynchronizerImpl(Module): def __init__(self, cd, async_reset): - rst1 = Signal() + if not hasattr(async_reset, "attr"): + i, async_reset = async_reset, Signal() + self.comb += async_reset.eq(i) + rst_meta = Signal() self.specials += [ Instance("FDPE", p_INIT=1, i_D=0, i_PRE=async_reset, - i_CE=1, i_C=cd.clk, o_Q=rst1), - Instance("FDPE", p_INIT=1, i_D=rst1, i_PRE=async_reset, - i_CE=1, i_C=cd.clk, o_Q=cd.rst) + i_CE=1, i_C=cd.clk, o_Q=rst_meta, + attr={"async_reg", "ars_ff"}), + Instance("FDPE", p_INIT=1, i_D=rst_meta, i_PRE=async_reset, + i_CE=1, i_C=cd.clk, o_Q=cd.rst, + attr={"async_reg", "ars_ff"}) ] - rst1.attr.add("async_reg") - cd.rst.attr.add("async_reg") + async_reset.attr.add("ars_false_path") class XilinxAsyncResetSynchronizer: diff --git a/litex/build/xilinx/ise.py b/litex/build/xilinx/ise.py index 19bbe9ef..0356f964 100644 --- a/litex/build/xilinx/ise.py +++ b/litex/build/xilinx/ise.py @@ -127,6 +127,8 @@ class XilinxISEToolchain: "keep": ("keep", "true"), "no_retiming": ("register_balancing", "no"), "async_reg": None, + "ars_ff": None, + "ars_false_path": None, "no_shreg_extract": ("shreg_extract", "no") } diff --git a/litex/build/xilinx/vivado.py b/litex/build/xilinx/vivado.py index 524d7984..8051e167 100644 --- a/litex/build/xilinx/vivado.py +++ b/litex/build/xilinx/vivado.py @@ -75,6 +75,8 @@ 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 "no_shreg_extract": None } @@ -88,31 +90,37 @@ class XilinxVivadoToolchain: def _build_batch(self, platform, sources, build_name): tcl = [] + tcl.append("create_property ars_ff cell") + tcl.append("create_property ars_false_path net") for filename, language, library in sources: filename_tcl = "{" + filename + "}" tcl.append("add_files " + filename_tcl) - if language == "vhdl": - tcl.append("set_property library {} [get_files {}]" - .format(library, filename_tcl)) + tcl.append("set_property library {} [get_files {}]" + .format(library, 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 if platform.verilog_include_paths: - synth_design_extra = "-include_dirs {{{}}}".format(" ".join(platform.verilog_include_paths)) + tcl.append("synth_design -top {} -part {} -include_dirs {{{}}}".format(build_name, platform.device, " ".join(platform.verilog_include_paths))) else: - synth_design_extra = "" - tcl.append("synth_design -top {} -part {} {}".format(build_name, platform.device, synth_design_extra)) + 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)) + tcl.append("opt_design") 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("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("write_checkpoint -force {}_route.dcp".format(build_name)) tcl.append("report_route_status -file {}_route_status.rpt".format(build_name)) tcl.append("report_drc -file {}_drc.rpt".format(build_name)) tcl.append("report_timing_summary -datasheet -max_paths 10 -file {}_timing.rpt".format(build_name)) @@ -144,6 +152,22 @@ class XilinxVivadoToolchain: del self.clocks del self.false_paths + def _constrain(self, platform): + # 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}}]" + ) + # 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}}]" + ) + def build(self, platform, fragment, build_dir="build", build_name="top", toolchain_path=None, source=True, run=True, **kwargs): if toolchain_path is None: @@ -161,6 +185,7 @@ class XilinxVivadoToolchain: fragment = fragment.get_fragment() platform.finalize(fragment) self._convert_clocks(platform) + self._constrain(platform) v_output = platform.get_verilog(fragment, name=build_name, **kwargs) named_sc, named_pc = platform.resolve_signals(v_output.ns) v_file = build_name + ".v" diff --git a/litex/gen/fhdl/decorators.py b/litex/gen/fhdl/decorators.py index 347eaaa1..d33ee712 100644 --- a/litex/gen/fhdl/decorators.py +++ b/litex/gen/fhdl/decorators.py @@ -71,7 +71,9 @@ class ControlInserter(ModuleTransformer): def transform_fragment(self, i, f): if self.clock_domains is None: - if len(f.sync) != 1: + if not f.sync: + return + if len(f.sync) > 1: raise ValueError("Control signal clock domains must be specified when module has more than one domain") cdn = list(f.sync.keys())[0] to_insert = [(getattr(i, self.control_name), cdn)] diff --git a/litex/gen/fhdl/specials.py b/litex/gen/fhdl/specials.py index 8fcade3f..4b7ab386 100644 --- a/litex/gen/fhdl/specials.py +++ b/litex/gen/fhdl/specials.py @@ -101,7 +101,8 @@ class Instance(Special): class PreformattedParam(str): pass - def __init__(self, of, *items, name="", synthesis_directive=None, **kwargs): + def __init__(self, of, *items, name="", synthesis_directive=None, + attr=None, **kwargs): Special.__init__(self) self.of = of if name: @@ -110,6 +111,9 @@ class Instance(Special): self.name_override = of self.items = list(items) self.synthesis_directive = synthesis_directive + if attr is None: + attr = set() + self.attr = attr for k, v in sorted(kwargs.items(), key=itemgetter(0)): try: item_type, item_name = k.split("_", maxsplit=1) diff --git a/litex/gen/fhdl/structure.py b/litex/gen/fhdl/structure.py index 9dc922dc..652f2668 100644 --- a/litex/gen/fhdl/structure.py +++ b/litex/gen/fhdl/structure.py @@ -304,6 +304,10 @@ class Signal(_Value): given value. When this `Signal` is unassigned in combinatorial context (due to conditional assignments not being taken), the `Signal` assumes its `reset` value. Defaults to 0. + reset_less : bool + If `True`, do not generate reset logic for this `Signal` in + synchronous statements. The `reset` value is only used as a + combinatorial default or as the initial value. Defaults to `False`. name_override : str or None Do not use the inferred name but the given one. min : int or None @@ -316,7 +320,9 @@ class Signal(_Value): """ _name_re = _re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$") - def __init__(self, bits_sign=None, name=None, variable=False, reset=0, name_override=None, min=None, max=None, related=None, attr=None): + def __init__(self, bits_sign=None, name=None, variable=False, reset=0, + reset_less=False, name_override=None, min=None, max=None, + related=None, attr=None): from litex.gen.fhdl.bitcontainer import bits_for _Value.__init__(self) @@ -351,6 +357,7 @@ class Signal(_Value): self.variable = variable # deprecated self.reset = reset + self.reset_less = reset_less self.name_override = name_override self.backtrace = _tracer.trace_back(name) self.related = related @@ -376,7 +383,13 @@ class Signal(_Value): See `migen.fhdl.bitcontainer.value_bits_sign` for details. """ from litex.gen.fhdl.bitcontainer import value_bits_sign - return cls(bits_sign=value_bits_sign(other), **kwargs) + kw = dict(bits_sign=value_bits_sign(other)) + if isinstance(other, cls): + kw.update(variable=other.variable, + reset=other.reset.value, reset_less=other.reset_less, + related=other.related, attr=set(other.attr)) + kw.update(kwargs) + return cls(**kw) def __hash__(self): return self.duid @@ -695,6 +708,15 @@ class _ClockDomainList(list): else: return list.__getitem__(self, key) + def __contains__(self, cd_or_name): + if isinstance(cd_or_name, str): + for cd in self: + if cd.name == cd_or_name: + return True + return False + else: + return list.__contains__(self, cd_or_name) + (SPECIAL_INPUT, SPECIAL_OUTPUT, SPECIAL_INOUT) = range(3) diff --git a/litex/gen/fhdl/tools.py b/litex/gen/fhdl/tools.py index 8da2f496..eefb5e01 100644 --- a/litex/gen/fhdl/tools.py +++ b/litex/gen/fhdl/tools.py @@ -143,11 +143,12 @@ def is_variable(node): def generate_reset(rst, sl): targets = list_targets(sl) - return [t.eq(t.reset) for t in sorted(targets, key=lambda x: x.duid)] + return [t.eq(t.reset) for t in sorted(targets, key=lambda x: x.duid) + if not t.reset_less] def insert_reset(rst, sl): - return [If(rst, *generate_reset(rst, sl)).Else(*sl)] + return sl + [If(rst, *generate_reset(rst, sl))] def insert_resets(f): diff --git a/litex/gen/fhdl/verilog.py b/litex/gen/fhdl/verilog.py index d5aef8d6..33873154 100644 --- a/litex/gen/fhdl/verilog.py +++ b/litex/gen/fhdl/verilog.py @@ -174,10 +174,10 @@ def _list_comb_wires(f): r |= g[0] return r -def _printattr(sig, attr_translate): +def _printattr(attr, attr_translate): r = "" firsta = True - for attr in sorted(sig.attr, + for attr in sorted(attr, key=lambda x: ("", x) if isinstance(x, str) else x): if isinstance(attr, tuple): # platform-dependent attribute @@ -210,7 +210,7 @@ def _printheader(f, ios, name, ns, attr_translate, if not firstp: r += ",\n" firstp = False - attr = _printattr(sig, attr_translate) + attr = _printattr(sig.attr, attr_translate) if attr: r += "\t" + attr if sig in inouts: @@ -224,7 +224,7 @@ def _printheader(f, ios, name, ns, attr_translate, r += "\tinput " + _printsig(ns, sig) r += "\n);\n\n" for sig in sorted(sigs - ios, key=lambda x: x.duid): - attr = _printattr(sig, attr_translate) + attr = _printattr(sig.attr, attr_translate) if attr: r += attr + " " if sig in wires: @@ -300,9 +300,13 @@ def _printsync(f, ns): return r -def _printspecials(overrides, specials, ns, add_data_file): +def _printspecials(overrides, specials, ns, add_data_file, attr_translate): r = "" for special in sorted(specials, key=lambda x: x.duid): + if hasattr(special, "attr"): + attr = _printattr(special.attr, attr_translate) + if attr: + r += attr + " " pr = call_special_classmethod(overrides, special, "emit_verilog", ns, add_data_file) if pr is None: raise NotImplementedError("Special " + str(special) + " failed to implement emit_verilog") @@ -369,7 +373,8 @@ def convert(f, ios=None, name="top", dummy_signal=dummy_signal, blocking_assign=blocking_assign) src += _printsync(f, ns) - src += _printspecials(special_overrides, f.specials - lowered_specials, ns, r.add_data_file) + src += _printspecials(special_overrides, f.specials - lowered_specials, + ns, r.add_data_file, attr_translate) src += "endmodule\n" r.set_main_source(src) diff --git a/litex/gen/genlib/fifo.py b/litex/gen/genlib/fifo.py index f24449ff..630a42e2 100644 --- a/litex/gen/genlib/fifo.py +++ b/litex/gen/genlib/fifo.py @@ -57,6 +57,7 @@ class _FIFOInterface: self.din = Signal(width) self.dout = Signal(width) self.width = width + self.depth = depth class SyncFIFO(Module, _FIFOInterface): diff --git a/litex/gen/sim/core.py b/litex/gen/sim/core.py index 8b03a0df..2ab9b4bd 100644 --- a/litex/gen/sim/core.py +++ b/litex/gen/sim/core.py @@ -271,7 +271,7 @@ class Simulator: self.time = TimeManager(clocks) for clock in clocks.keys(): if clock not in self.fragment.clock_domains: - cd = ClockDomain(name=clock) + cd = ClockDomain(name=clock, reset_less=True) cd.clk.reset = C(self.time.clocks[clock].high) self.fragment.clock_domains.append(cd) -- 2.30.2