1 from .._utils
import deprecated
5 __all__
= ["FFSynchronizer", "AsyncFFSynchronizer", "ResetSynchronizer", "PulseSynchronizer"]
8 def _check_stages(stages
):
9 if not isinstance(stages
, int) or stages
< 1:
10 raise TypeError("Synchronization stage count must be a positive integer, not {!r}"
13 raise ValueError("Synchronization stage count may not safely be less than 2")
16 class FFSynchronizer(Elaboratable
):
17 """Resynchronise a signal to a different clock domain.
19 Consists of a chain of flip-flops. Eliminates metastabilities at the output, but provides
20 no other guarantee as to the safe domain-crossing of a signal.
25 Signal to be resynchronised.
27 Signal connected to synchroniser output.
29 Name of output clock domain.
31 Reset value of the flip-flops. On FPGAs, even if ``reset_less`` is True,
32 the :class:`FFSynchronizer` is still set to this value during initialization.
34 If ``True`` (the default), this :class:`FFSynchronizer` is unaffected by ``o_domain``
35 reset. See "Note on Reset" below.
37 Number of synchronization stages between input and output. The lowest safe number is 2,
38 with higher numbers reducing MTBF further, at the cost of increased latency.
39 max_input_delay : None or float
40 Maximum delay from the input signal's clock to the first synchronization stage, in seconds.
41 If specified and the platform does not support it, elaboration will fail.
45 Define the ``get_ff_sync`` platform method to override the implementation of
46 :class:`FFSynchronizer`, e.g. to instantiate library cells directly.
50 :class:`FFSynchronizer` is non-resettable by default. Usually this is the safest option;
51 on FPGAs the :class:`FFSynchronizer` will still be initialized to its ``reset`` value when
52 the FPGA loads its configuration.
54 However, in designs where the value of the :class:`FFSynchronizer` must be valid immediately
55 after reset, consider setting ``reset_less`` to False if any of the following is true:
57 - You are targeting an ASIC, or an FPGA that does not allow arbitrary initial flip-flop states;
58 - Your design features warm (non-power-on) resets of ``o_domain``, so the one-time
59 initialization at power on is insufficient;
60 - Your design features a sequenced reset, and the :class:`FFSynchronizer` must maintain
61 its reset value until ``o_domain`` reset specifically is deasserted.
63 :class:`FFSynchronizer` is reset by the ``o_domain`` reset only.
65 def __init__(self
, i
, o
, *, o_domain
="sync", reset
=0, reset_less
=True, stages
=2,
66 max_input_delay
=None):
73 self
._reset
_less
= reset_less
74 self
._o
_domain
= o_domain
77 self
._max
_input
_delay
= max_input_delay
79 def elaborate(self
, platform
):
80 if hasattr(platform
, "get_ff_sync"):
81 return platform
.get_ff_sync(self
)
83 if self
._max
_input
_delay
is not None:
84 raise NotImplementedError("Platform '{}' does not support constraining input delay "
86 .format(type(platform
).__name
__))
89 flops
= [Signal(self
.i
.shape(), name
="stage{}".format(index
),
90 reset
=self
._reset
, reset_less
=self
._reset
_less
)
91 for index
in range(self
._stages
)]
92 for i
, o
in zip((self
.i
, *flops
), flops
):
93 m
.d
[self
._o
_domain
] += o
.eq(i
)
94 m
.d
.comb
+= self
.o
.eq(flops
[-1])
98 class AsyncFFSynchronizer(Elaboratable
):
99 """Synchronize deassertion of an asynchronous signal.
101 The signal driven by the :class:`AsyncFFSynchronizer` is asserted asynchronously and deasserted
102 synchronously, eliminating metastability during deassertion.
104 This synchronizer is primarily useful for resets and reset-like signals.
109 Asynchronous input signal, to be synchronized.
111 Synchronously released output signal.
113 Name of clock domain to synchronize to.
115 Number of synchronization stages between input and output. The lowest safe number is 2,
116 with higher numbers reducing MTBF further, at the cost of increased deassertion latency.
118 The edge of the input signal which causes the output to be set. Must be one of "pos" or "neg".
119 max_input_delay : None or float
120 Maximum delay from the input signal's clock to the first synchronization stage, in seconds.
121 If specified and the platform does not support it, elaboration will fail.
125 Define the ``get_async_ff_sync`` platform method to override the implementation of
126 :class:`AsyncFFSynchronizer`, e.g. to instantiate library cells directly.
128 def __init__(self
, i
, o
, *, o_domain
="sync", stages
=2, async_edge
="pos", max_input_delay
=None):
129 _check_stages(stages
)
132 raise ValueError("AsyncFFSynchronizer input width must be 1, not {}"
135 raise ValueError("AsyncFFSynchronizer output width must be 1, not {}"
138 if async_edge
not in ("pos", "neg"):
139 raise ValueError("AsyncFFSynchronizer async edge must be one of 'pos' or 'neg', "
146 self
._o
_domain
= o_domain
147 self
._stages
= stages
149 self
._edge
= async_edge
151 self
._max
_input
_delay
= max_input_delay
153 def elaborate(self
, platform
):
154 if hasattr(platform
, "get_async_ff_sync"):
155 return platform
.get_async_ff_sync(self
)
157 if self
._max
_input
_delay
is not None:
158 raise NotImplementedError("Platform '{}' does not support constraining input delay "
159 "for AsyncFFSynchronizer"
160 .format(type(platform
).__name
__))
163 m
.domains
+= ClockDomain("async_ff", async_reset
=True, local
=True)
164 flops
= [Signal(1, name
="stage{}".format(index
), reset
=1)
165 for index
in range(self
._stages
)]
166 for i
, o
in zip((0, *flops
), flops
):
167 m
.d
.async_ff
+= o
.eq(i
)
169 if self
._edge
== "pos":
170 m
.d
.comb
+= ResetSignal("async_ff").eq(self
.i
)
172 m
.d
.comb
+= ResetSignal("async_ff").eq(~self
.i
)
175 ClockSignal("async_ff").eq(ClockSignal(self
._o
_domain
)),
182 class ResetSynchronizer(Elaboratable
):
183 """Synchronize deassertion of a clock domain reset.
185 The reset of the clock domain driven by the :class:`ResetSynchronizer` is asserted
186 asynchronously and deasserted synchronously, eliminating metastability during deassertion.
188 The driven clock domain could use a reset that is asserted either synchronously or
189 asynchronously; a reset is always deasserted synchronously. A domain with an asynchronously
190 asserted reset is useful if the clock of the domain may be gated, yet the domain still
191 needs to be reset promptly; otherwise, synchronously asserted reset (the default) should
197 Asynchronous reset signal, to be synchronized.
199 Name of clock domain to reset.
201 Number of synchronization stages between input and output. The lowest safe number is 2,
202 with higher numbers reducing MTBF further, at the cost of increased deassertion latency.
203 max_input_delay : None or float
204 Maximum delay from the input signal's clock to the first synchronization stage, in seconds.
205 If specified and the platform does not support it, elaboration will fail.
209 Define the ``get_reset_sync`` platform method to override the implementation of
210 :class:`ResetSynchronizer`, e.g. to instantiate library cells directly.
212 def __init__(self
, arst
, *, domain
="sync", stages
=2, max_input_delay
=None):
213 _check_stages(stages
)
217 self
._domain
= domain
218 self
._stages
= stages
220 self
._max
_input
_delay
= max_input_delay
222 def elaborate(self
, platform
):
223 return AsyncFFSynchronizer(self
.arst
, ResetSignal(self
._domain
), o_domain
=self
._domain
,
224 stages
=self
._stages
, max_input_delay
=self
._max
_input
_delay
)
227 class PulseSynchronizer(Elaboratable
):
228 """A one-clock pulse on the input produces a one-clock pulse on the output.
230 If the output clock is faster than the input clock, then the input may be safely asserted at
231 100% duty cycle. Otherwise, if the clock ratio is `n`:1, the input may be asserted at most once
232 in every `n` input clocks, else pulses may be dropped. Other than this there is no constraint
233 on the ratio of input and output clock frequency.
238 Name of input clock domain.
240 Name of output clock domain.
242 Number of synchronization stages between input and output. The lowest safe number is 2,
243 with higher numbers reducing MTBF further, at the cost of increased deassertion latency.
245 def __init__(self
, i_domain
, o_domain
, *, stages
=2):
246 _check_stages(stages
)
251 self
._i
_domain
= i_domain
252 self
._o
_domain
= o_domain
253 self
._stages
= stages
255 def elaborate(self
, platform
):
261 ff_sync
= m
.submodules
.ff_sync
= \
262 FFSynchronizer(i_toggle
, o_toggle
, o_domain
=self
._o
_domain
, stages
=self
._stages
)
264 m
.d
[self
._i
_domain
] += i_toggle
.eq(i_toggle ^ self
.i
)
265 m
.d
[self
._o
_domain
] += r_toggle
.eq(o_toggle
)
266 m
.d
.comb
+= self
.o
.eq(o_toggle ^ r_toggle
)