Clock Domain Crossing

The torii.lib.cdc module provides building blocks for transferring data between clock domains.

class torii.lib.cdc.AsyncFFSynchronizer(i: Signal, o: Signal, *, o_domain: str = 'sync', stages: int = 2, async_edge: Literal['pos', 'neg'] = 'pos', max_input_delay: float | None = None) None

Synchronize de-assertion of an asynchronous signal.

The signal driven by the AsyncFFSynchronizer is asserted asynchronously and de-asserted synchronously, eliminating metastability during de-assertion.

This synchronizer is primarily useful for resets and reset-like signals.

Parameters:
  • i (Signal(1), in) – Asynchronous input signal, to be synchronized.

  • o (Signal(1), out) – Synchronously released output signal.

  • o_domain (str) – Name of clock domain to synchronize to.

  • stages (int, >=2) – 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 de-assertion latency.

  • async_edge (str) – The edge of the input signal which causes the output to be set. Must be one of “pos” or “neg”.

  • max_input_delay (None | float) – Maximum delay from the input signal’s clock to the first synchronization stage, in seconds. If specified and the platform does not support it, elaboration will fail.

Platform overrides

Define the get_async_ff_sync platform method to override the implementation of AsyncFFSynchronizer, e.g. to instantiate library cells directly.

elaborate(platform) Module
Return type:

Module

Todo

Document Me

class torii.lib.cdc.FFSynchronizer(i: Signal, o: Signal, *, o_domain: str = 'sync', reset: int = 0, reset_less: bool = True, stages: int = 2, max_input_delay: float | None = None) None

Resynchronize 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(n), in) – Signal to be resynchronized.

  • o (Signal(n), out) – Signal connected to synchronizer output.

  • o_domain (str) – Name of output clock domain.

  • reset (int) – Reset value of the flip-flops. On FPGAs, even if reset_less is True, the FFSynchronizer is still set to this value during initialization.

  • reset_less (bool) – If True (the default), this FFSynchronizer is unaffected by o_domain reset. See the note below for details.

  • stages (int, >=2) – 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.

  • max_input_delay (None | float) – Maximum delay from the input signal’s clock to the first synchronization stage, in seconds. If specified and the platform does not support it, elaboration will fail.

Note

FFSynchronizer is non-resettable by default. Usually this is the safest option; on FPGAs the FFSynchronizer will still be initialized to its reset value when the FPGA loads its configuration.

However, in designs where the value of the 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 FFSynchronizer must maintain

    its reset value until o_domain reset specifically is de-asserted.

FFSynchronizer is reset by the o_domain reset only.

Platform overrides

Define the get_ff_sync platform method to override the implementation of FFSynchronizer, e.g. to instantiate library cells directly.

elaborate(platform) Module
Return type:

Module

Todo

Document Me

class torii.lib.cdc.PulseStretcher(i: Signal, o: Signal, *, cycles: int = 1, domain: str = 'sync') None

Stretch a single-cycle input pulse out to a given number of clock cycles.

Note

If you wish to stretch a pulse between two clock domains there are two possible solutions. The first is to put a PulseSynchronizer before the PulseStretcher so cross the clock domain boundary prior to stretching:

The other method is to put an FFSynchronizer after this PulseStretcher to have the stretched output signal cross over the clock domain boundary:

Parameters:
  • i (Signal) – The input pulse to stretch

  • o (Signal) – The resulting stretched pulse

  • cycles (int) – The number of cycles to stretch the pulse.

  • domain (str) – The domain that this pulse stretcher runs on.

elaborate(platform: Platform | None) Module
Return type:

Module

Todo

Document Me

class torii.lib.cdc.PulseSynchronizer(i: Signal, i_domain: str, o: Signal, o_domain: str = 'sync', *, stages: int = 2) None

Resynchronize a one-clock pulse between clock domains.

This ensures that a one-clock pulse on the input signal produces a one-clock pulse on the output signal across clock domains.

Important

If the output clock domain is faster than the input clock domain, then the input signal may be asserted safely at 100% duty cycle.

However, if the ratio between input and output clock domains is n:1, then the input signal may only be asserted at most once every n clock cycles on the input domain, otherwise pulses have the possibility of being lost.

Other than this restriction, there is no constraint on the ratio between the input and output clock domain frequencies.

Parameters:
  • i (Signal) – The input signal to synchronize

  • i_domain (str) – Name of input clock domain

  • o (Signal) – The synchronized output signal

  • o_domain (str) – Name of output clock domain

  • stages (int, >=2) – 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 de-assertion latency.

elaborate(platform) Module
Return type:

Module

Todo

Document Me

class torii.lib.cdc.ResetSynchronizer(arst: Signal, *, domain: str = 'sync', stages: int = 2, max_input_delay: float | None = None) None

Synchronize de-assertion of a clock domain reset.

The reset of the clock domain driven by the ResetSynchronizer is asserted asynchronously and de-asserted synchronously, eliminating metastability during de-assertion.

The driven clock domain could use a reset that is asserted either synchronously or asynchronously; a reset is always de-asserted synchronously. A domain with an asynchronously asserted reset is useful if the clock of the domain may be gated, yet the domain still needs to be reset promptly; otherwise, synchronously asserted reset (the default) should be used.

Parameters:
  • arst (Signal(1), in) – Asynchronous reset signal, to be synchronized.

  • domain (str) – Name of clock domain to reset.

  • stages (int, >=2) – 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 de-assertion latency.

  • max_input_delay (None | float) – Maximum delay from the input signal’s clock to the first synchronization stage, in seconds. If specified and the platform does not support it, elaboration will fail.

Platform overrides

Define the get_reset_sync platform method to override the implementation of ResetSynchronizer, e.g. to instantiate library cells directly.

elaborate(platform) AsyncFFSynchronizer
Return type:

AsyncFFSynchronizer

Todo

Document Me