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 reset.
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
, *, domain
="sync", stages
=2, async_edge
="pos", max_input_delay
=None):
129 _check_stages(stages
)
134 self
._domain
= domain
135 self
._stages
= stages
137 if async_edge
not in ("pos", "neg"):
138 raise ValueError("AsyncFFSynchronizer async edge must be one of 'pos' or 'neg', "
141 self
._edge
= async_edge
143 self
._max
_input
_delay
= max_input_delay
145 def elaborate(self
, platform
):
146 if hasattr(platform
, "get_async_ff_sync"):
147 return platform
.get_async_ff_sync(self
)
149 if self
._max
_input
_delay
is not None:
150 raise NotImplementedError("Platform '{}' does not support constraining input delay "
151 "for AsyncFFSynchronizer"
152 .format(type(platform
).__name
__))
155 m
.domains
+= ClockDomain("async_ff", async_reset
=True, local
=True)
156 flops
= [Signal(1, name
="stage{}".format(index
), reset
=1)
157 for index
in range(self
._stages
)]
158 for i
, o
in zip((0, *flops
), flops
):
159 m
.d
.async_ff
+= o
.eq(i
)
161 if self
._edge
== "pos":
162 m
.d
.comb
+= ResetSignal("async_ff").eq(self
.i
)
164 m
.d
.comb
+= ResetSignal("async_ff").eq(~self
.i
)
167 ClockSignal("async_ff").eq(ClockSignal(self
._domain
)),
174 class ResetSynchronizer(Elaboratable
):
175 """Synchronize deassertion of a clock domain reset.
177 The reset of the clock domain driven by the :class:`ResetSynchronizer` is asserted
178 asynchronously and deasserted synchronously, eliminating metastability during deassertion.
180 The driven clock domain could use a reset that is asserted either synchronously or
181 asynchronously; a reset is always deasserted synchronously. A domain with an asynchronously
182 asserted reset is useful if the clock of the domain may be gated, yet the domain still
183 needs to be reset promptly; otherwise, synchronously asserted reset (the default) should
189 Asynchronous reset signal, to be synchronized.
191 Name of clock domain to reset.
193 Number of synchronization stages between input and output. The lowest safe number is 2,
194 with higher numbers reducing MTBF further, at the cost of increased deassertion latency.
195 max_input_delay : None or float
196 Maximum delay from the input signal's clock to the first synchronization stage, in seconds.
197 If specified and the platform does not support it, elaboration will fail.
201 Define the ``get_reset_sync`` platform method to override the implementation of
202 :class:`ResetSynchronizer`, e.g. to instantiate library cells directly.
204 def __init__(self
, arst
, *, domain
="sync", stages
=2, max_input_delay
=None):
205 _check_stages(stages
)
209 self
._domain
= domain
210 self
._stages
= stages
212 self
._max
_input
_delay
= max_input_delay
214 def elaborate(self
, platform
):
215 return AsyncFFSynchronizer(self
.arst
, ResetSignal(self
._domain
), domain
=self
._domain
,
216 stages
=self
._stages
, max_input_delay
=self
._max
_input
_delay
)
219 class PulseSynchronizer(Elaboratable
):
220 """A one-clock pulse on the input produces a one-clock pulse on the output.
222 If the output clock is faster than the input clock, then the input may be safely asserted at
223 100% duty cycle. Otherwise, if the clock ratio is `n`:1, the input may be asserted at most once
224 in every `n` input clocks, else pulses may be dropped. Other than this there is no constraint
225 on the ratio of input and output clock frequency.
230 Name of input clock domain.
232 Name of output clock domain.
234 Number of synchronization stages between input and output. The lowest safe number is 2,
235 with higher numbers reducing MTBF further, at the cost of increased deassertion latency.
237 def __init__(self
, i_domain
, o_domain
, *, stages
=2):
238 _check_stages(stages
)
243 self
._i
_domain
= i_domain
244 self
._o
_domain
= o_domain
245 self
._stages
= stages
247 def elaborate(self
, platform
):
253 ff_sync
= m
.submodules
.ff_sync
= \
254 FFSynchronizer(i_toggle
, o_toggle
, o_domain
=self
._o
_domain
, stages
=self
._stages
)
256 m
.d
[self
._i
_domain
] += i_toggle
.eq(i_toggle ^ self
.i
)
257 m
.d
[self
._o
_domain
] += r_toggle
.eq(o_toggle
)
258 m
.d
.comb
+= self
.o
.eq(o_toggle ^ r_toggle
)