From a243bcb7a0e87013a4e3125198e747158f9ccfeb Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Tue, 19 Mar 2019 03:36:55 +0000 Subject: [PATCH] lib.cdc: add optional reset to MultiReg, and document its use cases. --- nmigen/lib/cdc.py | 48 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/nmigen/lib/cdc.py b/nmigen/lib/cdc.py index c7624bc..3018b37 100644 --- a/nmigen/lib/cdc.py +++ b/nmigen/lib/cdc.py @@ -5,13 +5,57 @@ __all__ = ["MultiReg", "ResetSynchronizer"] class MultiReg: - def __init__(self, i, o, odomain="sync", n=2, reset=0): + """Resynchronise a signal to a different clock domain. + + Consists of a chain of flip-flops. Eliminates metastabilities at the output, but provides + no other guarantee as to the safe domain-crossing of a signal. + + Parameters + ---------- + i : Signal(), in + Signal to be resynchronised + o : Signal(), out + Signal connected to synchroniser output + odomain : str + Name of output clock domain + n : int + Number of flops between input and output. + 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_less : bool + If True (the default), this MultiReg is unaffected by ``odomain`` reset. + See "Note on Reset" below. + + Platform override + ----------------- + Define the ``get_multi_reg`` platform metehod to override the implementation of MultiReg, + 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. + + 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: + + - 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 ``odomain``, 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 + ``odomain`` reset specifically is deasserted. + + MultiReg is reset by the ``odomain`` reset only. + """ + def __init__(self, i, o, odomain="sync", n=2, reset=0, reset_less=True): self.i = i self.o = o self.odomain = odomain self._regs = [Signal(self.i.shape(), name="cdc{}".format(i), - reset=reset, reset_less=True, attrs={"no_retiming": True}) + reset=reset, reset_less=reset_less, attrs={"no_retiming": True}) for i in range(n)] def elaborate(self, platform): -- 2.30.2