import warnings
from ...tools import deprecated
-from ...lib.cdc import MultiReg as NativeMultiReg
+from ...lib.cdc import FFSynchronizer as NativeFFSynchronizer
from ...hdl.ast import *
from ..fhdl.module import CompatModule
from ..fhdl.structure import If
__all__ = ["MultiReg", "GrayCounter", "GrayDecoder"]
-class MultiReg(NativeMultiReg):
+class MultiReg(NativeFFSynchronizer):
def __init__(self, i, o, odomain="sync", n=2, reset=0):
+ old_opts = []
+ new_opts = []
if odomain != "sync":
- warnings.warn("instead of `MultiReg(..., odomain={!r})`, "
- "use `MultiReg(..., o_domain={!r})`"
- .format(odomain, odomain),
- DeprecationWarning, stacklevel=2)
- super().__init__(i, o, o_domain=odomain, n=n, reset=reset)
+ old_opts.append(", odomain={!r}".format(odomain))
+ new_opts.append(", o_domain={!r}".format(odomain))
+ if n != 2:
+ old_opts.append(", n={!r}".format(n))
+ new_opts.append(", stages={!r}".format(n))
+ warnings.warn("instead of `MultiReg(...{})`, use `FFSynchronizer(...{})`"
+ .format("".join(old_opts), "".join(new_opts)),
+ DeprecationWarning, stacklevel=2)
+ super().__init__(i, o, o_domain=odomain, stages=n, reset=reset)
self.odomain = odomain
+from ..tools import deprecated
from .. import *
-__all__ = ["MultiReg", "ResetSynchronizer"]
+__all__ = ["FFSynchronizer", "ResetSynchronizer"]
+# TODO(nmigen-0.2): remove this
+__all__ += ["MultiReg"]
-class MultiReg(Elaboratable):
+class FFSynchronizer(Elaboratable):
"""Resynchronise a signal to a different clock domain.
Consists of a chain of flip-flops. Eliminates metastabilities at the output, but provides
Parameters
----------
- i : Signal(), in
- Signal to be resynchronised
- o : Signal(), out
- Signal connected to synchroniser output
+ i : Signal, in
+ Signal to be resynchronised.
+ o : Signal, out
+ Signal connected to synchroniser output.
o_domain : str
- Name of output clock domain
- n : int
- Number of flops between input and output.
+ Name of output clock domain.
+ stages : int
+ Number of synchronization stages between input and output. The lowest safe number is 2,
+ with higher numbers reducing MTBF further, at the cost of increased latency.
reset : int
- Reset value of the flip-flops. On FPGAs, even if ``reset_less`` is True, the MultiReg is
- still set to this value during initialization.
+ Reset value of the flip-flops. On FPGAs, even if ``reset_less`` is True,
+ the :class:`FFSynchronizer` is still set to this value during initialization.
reset_less : bool
- If True (the default), this MultiReg is unaffected by ``o_domain`` reset.
+ If True (the default), this :class:`FFSynchronizer` is unaffected by ``o_domain`` reset.
See "Note on Reset" below.
Platform override
-----------------
- Define the ``get_multi_reg`` platform method to override the implementation of MultiReg,
+ Define the ``get_ff_sync`` platform method to override the implementation of :class:`FFSynchronizer`,
e.g. to instantiate library cells directly.
Note on Reset
-------------
- MultiReg is non-resettable by default. Usually this is the safest option; on FPGAs
- the MultiReg will still be initialized to its ``reset`` value when the FPGA loads its
- configuration.
+ :class:`FFSynchronizer` is non-resettable by default. Usually this is the safest option;
+ on FPGAs the :class:`FFSynchronizer` will still be initialized to its ``reset`` value when
+ the FPGA loads its configuration.
- However, in designs where the value of the MultiReg must be valid immediately after reset,
- consider setting ``reset_less`` to False if any of the following is true:
+ However, in designs where the value of the :class:`FFSynchronizer` must be valid immediately
+ after reset, consider setting ``reset_less`` to False if any of the following is true:
- You are targeting an ASIC, or an FPGA that does not allow arbitrary initial flip-flop states;
- Your design features warm (non-power-on) resets of ``o_domain``, so the one-time
initialization at power on is insufficient;
- - Your design features a sequenced reset, and the MultiReg must maintain its reset value until
- ``o_domain`` reset specifically is deasserted.
+ - Your design features a sequenced reset, and the :class:`FFSynchronizer` must maintain
+ its reset value until ``o_domain`` reset specifically is deasserted.
- MultiReg is reset by the ``o_domain`` reset only.
+ :class:`FFSynchronizer` is reset by the ``o_domain`` reset only.
"""
- def __init__(self, i, o, *, o_domain="sync", n=2, reset=0, reset_less=True):
+ def __init__(self, i, o, *, o_domain="sync", stages=2, reset=0, reset_less=True):
self.i = i
self.o = o
self._o_domain = o_domain
- self._regs = [Signal(self.i.shape(), name="cdc{}".format(i), reset=reset,
- reset_less=reset_less)
- for i in range(n)]
+ self._stages = [Signal(self.i.shape(), name="stage{}".format(index),
+ reset=reset, reset_less=reset_less)
+ for index in range(stages)]
def elaborate(self, platform):
- if hasattr(platform, "get_multi_reg"):
- return platform.get_multi_reg(self)
+ if hasattr(platform, "get_ff_sync"):
+ return platform.get_ff_sync(self)
m = Module()
- for i, o in zip((self.i, *self._regs), self._regs):
+ for i, o in zip((self.i, *self._stages), self._stages):
m.d[self._o_domain] += o.eq(i)
- m.d.comb += self.o.eq(self._regs[-1])
+ m.d.comb += self.o.eq(self._stages[-1])
return m
+# TODO(nmigen-0.2): remove this
+MultiReg = deprecated("instead of `MultiReg`, use `FFSynchronizer`")(FFSynchronizer)
+
+
class ResetSynchronizer(Elaboratable):
- def __init__(self, arst, *, domain="sync", n=2):
+ def __init__(self, arst, *, domain="sync", stages=2):
self.arst = arst
self._domain = domain
- self._regs = [Signal(1, name="arst{}".format(i), reset=1)
- for i in range(n)]
+ self._stages = [Signal(1, name="stage{}".format(i), reset=1)
+ for i in range(stages)]
def elaborate(self, platform):
if hasattr(platform, "get_reset_sync"):
m = Module()
m.domains += ClockDomain("reset_sync", async_reset=True, local=True)
- for i, o in zip((0, *self._regs), self._regs):
+ for i, o in zip((0, *self._stages), self._stages):
m.d.reset_sync += o.eq(i)
m.d.comb += [
ClockSignal("reset_sync").eq(ClockSignal(self._domain)),
ResetSignal("reset_sync").eq(self.arst),
- ResetSignal(self._domain).eq(self._regs[-1])
+ ResetSignal(self._domain).eq(self._stages[-1])
]
return m
from ..asserts import *
from ..tools import log2_int, deprecated
from .coding import GrayEncoder
-from .cdc import MultiReg
+from .cdc import FFSynchronizer
__all__ = ["FIFOInterface", "SyncFIFO", "SyncFIFOBuffered", "AsyncFIFO", "AsyncFIFOBuffered"]
produce_enc = m.submodules.produce_enc = \
GrayEncoder(self._ctr_bits)
produce_cdc = m.submodules.produce_cdc = \
- MultiReg(produce_w_gry, produce_r_gry, o_domain=self._r_domain)
+ FFSynchronizer(produce_w_gry, produce_r_gry, o_domain=self._r_domain)
m.d.comb += produce_enc.i.eq(produce_w_nxt),
m.d[self._w_domain] += produce_w_gry.eq(produce_enc.o)
consume_enc = m.submodules.consume_enc = \
GrayEncoder(self._ctr_bits)
consume_cdc = m.submodules.consume_cdc = \
- MultiReg(consume_r_gry, consume_w_gry, o_domain=self._w_domain)
+ FFSynchronizer(consume_r_gry, consume_w_gry, o_domain=self._w_domain)
m.d.comb += consume_enc.i.eq(consume_r_nxt)
m.d[self._r_domain] += consume_r_gry.eq(consume_enc.o)