def settings(path, ver=None, sub=None):
- assert path is not None
if ver is None:
vers = list(tools.versions(path))
if not vers:
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:
"keep": ("keep", "true"),
"no_retiming": ("register_balancing", "no"),
"async_reg": None,
+ "ars_ff": None,
+ "ars_false_path": None,
"no_shreg_extract": ("shreg_extract", "no")
}
"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
}
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))
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:
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"
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)]
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:
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)
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
"""
_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)
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
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
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)
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):
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
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:
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:
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")
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)
self.din = Signal(width)
self.dout = Signal(width)
self.width = width
+ self.depth = depth
class SyncFIFO(Module, _FIFOInterface):
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)