merge migen 9a6fdea3 changes
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 28 Jun 2017 20:47:13 +0000 (22:47 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 28 Jun 2017 20:47:13 +0000 (22:47 +0200)
litex/build/xilinx/common.py
litex/build/xilinx/ise.py
litex/build/xilinx/vivado.py
litex/gen/fhdl/decorators.py
litex/gen/fhdl/specials.py
litex/gen/fhdl/structure.py
litex/gen/fhdl/tools.py
litex/gen/fhdl/verilog.py
litex/gen/genlib/fifo.py
litex/gen/sim/core.py

index 75412a137d67009c011a56bdc9b0e896bb99191e..c747945b16d265a177491272dc17d00e3a9afed4 100644 (file)
@@ -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:
index 19bbe9ef4b8b577602d01ae1c058c5936219df8f..0356f964462f335100524944fe6b023a63c606b9 100644 (file)
@@ -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")
     }
 
index 524d7984df270771f4c57efd29345a022e823ba8..8051e1676839b9dc0bcf3e768fbc820084e2bd81 100644 (file)
@@ -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"
index 347eaaa1aac5887c35d1e214c44ad3b3b41cfa58..d33ee71260477f62594aa4376c36ceca2ad67f47 100644 (file)
@@ -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)]
index 8fcade3ffbd4fd1af9d9cb6f71364d00f1aec5d1..4b7ab38698673c699813ee9ba63a688008012819 100644 (file)
@@ -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)
index 9dc922dc7339bfdbdb66f303227eb41c1d63c8de..652f26685bc426883250de8a08df5323336d9b2c 100644 (file)
@@ -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)
 
index 8da2f4968b8f368202dd948d3d258bcaab58ed50..eefb5e0155060657df748f1c6426fa030084ac5e 100644 (file)
@@ -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):
index d5aef8d6d4f6ad0fbddf7cd20d9b95484ad272bc..33873154f2eb66ed2f77a316ba879c7434ca2849 100644 (file)
@@ -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)
 
index f24449ffaa05296a2eaf432281e56a15a4e78792..630a42e274b730eced59c5dd8dd8002b0830f48a 100644 (file)
@@ -57,6 +57,7 @@ class _FIFOInterface:
         self.din = Signal(width)
         self.dout = Signal(width)
         self.width = width
+        self.depth = depth
 
 
 class SyncFIFO(Module, _FIFOInterface):
index 8b03a0dfde845b33996d87f42e6d0aab79028ecd..2ab9b4bd3d24423a0c426bb9fd66ef196bf84db1 100644 (file)
@@ -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)