2018-12-15 07:23:42 -07:00
|
|
|
from .. import *
|
2018-12-12 03:12:35 -07:00
|
|
|
|
|
|
|
|
2019-01-26 11:07:59 -07:00
|
|
|
__all__ = ["MultiReg", "ResetSynchronizer"]
|
2018-12-12 03:12:35 -07:00
|
|
|
|
|
|
|
|
2019-04-21 02:52:57 -06:00
|
|
|
class MultiReg(Elaboratable):
|
2019-03-18 21:36:55 -06:00
|
|
|
"""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
|
|
|
|
-----------------
|
2019-06-09 04:24:01 -06:00
|
|
|
Define the ``get_multi_reg`` platform method to override the implementation of MultiReg,
|
2019-03-18 21:36:55 -06:00
|
|
|
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):
|
2018-12-12 03:12:35 -07:00
|
|
|
self.i = i
|
|
|
|
self.o = o
|
|
|
|
self.odomain = odomain
|
|
|
|
|
2019-06-28 01:22:54 -06:00
|
|
|
self._regs = [Signal(self.i.shape(), name="cdc{}".format(i), reset=reset,
|
|
|
|
reset_less=reset_less)
|
2018-12-12 03:52:32 -07:00
|
|
|
for i in range(n)]
|
2018-12-12 03:12:35 -07:00
|
|
|
|
2019-01-25 19:31:12 -07:00
|
|
|
def elaborate(self, platform):
|
2018-12-12 05:38:24 -07:00
|
|
|
if hasattr(platform, "get_multi_reg"):
|
|
|
|
return platform.get_multi_reg(self)
|
|
|
|
|
|
|
|
m = Module()
|
2018-12-12 03:52:32 -07:00
|
|
|
for i, o in zip((self.i, *self._regs), self._regs):
|
2018-12-12 05:38:24 -07:00
|
|
|
m.d[self.odomain] += o.eq(i)
|
|
|
|
m.d.comb += self.o.eq(self._regs[-1])
|
2019-01-25 19:31:12 -07:00
|
|
|
return m
|
2019-01-26 11:07:59 -07:00
|
|
|
|
|
|
|
|
2019-04-21 02:52:57 -06:00
|
|
|
class ResetSynchronizer(Elaboratable):
|
2019-01-26 11:07:59 -07:00
|
|
|
def __init__(self, arst, domain="sync", n=2):
|
|
|
|
self.arst = arst
|
|
|
|
self.domain = domain
|
|
|
|
|
2019-06-28 01:22:54 -06:00
|
|
|
self._regs = [Signal(1, name="arst{}".format(i), reset=1)
|
2019-01-26 11:07:59 -07:00
|
|
|
for i in range(n)]
|
|
|
|
|
|
|
|
def elaborate(self, platform):
|
|
|
|
if hasattr(platform, "get_reset_sync"):
|
|
|
|
return platform.get_reset_sync(self)
|
|
|
|
|
|
|
|
m = Module()
|
|
|
|
m.domains += ClockDomain("_reset_sync", async_reset=True)
|
|
|
|
for i, o in zip((0, *self._regs), self._regs):
|
|
|
|
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])
|
|
|
|
]
|
|
|
|
return m
|