.. _module_resync: Module resync ============= This document contains technical documentation for the ``resync`` module. To browse the source code, visit the `repository on GitHub `__. This module contains a large set of VHDL entities for clock domain crossing (CDC) of data in an FPGA. Everything in this module is properly and carefully constrained, and has a thought-out structure to ensure stable operation. Note that most of the entities in this module have :ref:`scoped constraint ` files that must be used for proper operation. This also means that certain build tool settings need to be considered for the constraints to work. Please see this article `this article `__ for details. See :ref:`fifo.asynchronous_fifo` if you want to use asynchronous FIFO as a CDC solution. For AXI buses, there is also :ref:`axi.axi_address_fifo`, :ref:`axi.axi_r_fifo`, :ref:`axi.axi_w_fifo`, :ref:`axi.axi_b_fifo`, :ref:`axi.axi_read_cdc`, :ref:`axi.axi_write_cdc`. .. _resync.resync_counter: resync_counter.vhd ------------------ `View source code on GitHub `__. .. symbolator:: component resync_counter is generic ( width : positive; default_value : u_unsigned; pipeline_output : boolean; assert_false_on_counter_jumps : boolean ); port ( clk_in : in std_ulogic; counter_in : in u_unsigned; --# {{}} clk_out : in std_ulogic; counter_out : out u_unsigned ); end component; Synchronize a counter value between two domains using Gray-coded values. Converts the binary input counter word to Gray code, resynchronizes it to the output clock domain with an ``async_reg`` chain, and converts it back to a binary number. .. figure:: resync_counter_transparent.png Note that unlike e.g. :ref:`resync.resync_level`, it is safe to drive the input of this entity with LUTs as well as FFs. .. note:: This entity has a scoped constraint file `resync_counter.tcl `__ that must be used for proper operation. See :ref:`here ` for instructions. .. warning:: This entity assumes that the input counter value only increments and decrements in steps of one. Erroneous values can appear on the output if this is not followed. See the `constraint file `__ and `this article `__ for information about timing constraints and how this CDC topology is made reliable. .. _resync.resync_counter.resource_utilization: Resource utilization ____________________ This entity has `netlist builds `__ set up with `automatic size checkers `__ in `module_resync.py `__. The following table lists the resource utilization for the entity, depending on generic configuration. .. list-table:: Resource utilization for **resync_counter** netlist builds. :header-rows: 1 * - Generics - Total LUTs - LUTRAMs - FFs - Maximum logic level * - width = 8 - 11 - 0 - 24 - 3 * - width = 16 - 23 - 0 - 48 - 4 * - width = 24 - 35 - 0 - 72 - 6 * - width = 32 - 59 - 0 - 96 - 3 * - width = 64 - 123 - 0 - 192 - 4 .. _resync.resync_cycles: resync_cycles.vhd ----------------- `View source code on GitHub `__. .. symbolator:: component resync_cycles is generic ( counter_width : positive; active_level : std_ulogic ); port ( clk_in : in std_ulogic; data_in : in std_ulogic; --# {{}} clk_out : in std_ulogic; data_out : out std_ulogic ); end component; Resynchronizes a bit, so that the output bit is asserted as many clock cycles as the input bit. .. note:: This entity instantiates :ref:`resync.resync_counter` which has a :ref:`scoped constraint ` file that must be used. This module counts each ``clk_in`` cycle the input bit is asserted. The counter is resynchronized to ``clk_out``, and used as a reference to know how many ``clk_out`` cycles the output bit should be asserted. Note that unlike e.g. :ref:`resync.resync_level`, it is safe to drive the input of this entity with LUTs as well as FFs. Counter width _____________ The module may fail when ``clk_out`` is slower than ``clk_in`` and the input is asserted many cycles in a row. An RTL assertion is made to check for this error in simulation. Increasing ``counter_width`` increases the tolerance for this error. .. _resync.resync_cycles.resource_utilization: Resource utilization ____________________ This entity has `netlist builds `__ set up with `automatic size checkers `__ in `module_resync.py `__. The following table lists the resource utilization for the entity, depending on generic configuration. .. list-table:: Resource utilization for **resync_cycles** netlist builds. :header-rows: 1 * - Generics - Total LUTs - LUTRAMs - FFs - Maximum logic level * - counter_width = 8 - 26 - 0 - 41 - 5 * - counter_width = 16 - 31 - 0 - 81 - 7 * - counter_width = 24 - 45 - 0 - 121 - 9 * - counter_width = 32 - 69 - 0 - 161 - 9 * - counter_width = 64 - 140 - 0 - 321 - 17 .. _resync.resync_level: resync_level.vhd ---------------- `View source code on GitHub `__. .. symbolator:: component resync_level is generic ( enable_input_register : boolean; default_value : std_ulogic ); port ( clk_in : in std_ulogic; data_in : in std_ulogic; --# {{}} clk_out : in std_ulogic; data_out : out std_ulogic ); end component; Resync a single bit from one clock domain to another, using two ``async_reg`` registers. .. figure:: resync_level_transparent.png The two registers will be placed in the same slice, in order to maximize metastability recovery, which minimizes mean time between failure (MTBF). This enables proper resynchronization of semi-static "level"-type signals without meta stability on rising/falling edges. .. note:: This entity has a scoped constraint file `resync_level.tcl `__ that must be used for proper operation. See :ref:`here ` for instructions. .. warning:: This entity works only for semi-static "level"-type input signals. This entity can not handle "pulse"-type signals. Pulses can be missed and single-cycle pulse behavior will not work. See the `constraint file `__ and `this article `__ for information about timing constraints and how this CDC topology is made reliable. Deterministic latency ________________________________________ If you want a deterministic latency through this resync block, via a ``set_max_delay`` constraint, the ``enable_input_register`` generic must be enabled and the ``clk_in`` port assigned. If it is not, a simple ``set_false_path`` constraint will be used and the latency can be arbitrary, depending on the placer/router. Glitches ________ The ``enable_input_register`` generic helps to prevent sampling of data when the input is in a transient "glitch" state, which can occur if it is driven by a LUT as opposed to a flip-flop. When this option is enabled, the ``clk_in`` port must be driven with the correct clock. Note that this is a separate issue from meta-stability; they can happen independently of each other. If the input is already driven by a flip-flop, you can set the generic to ``false`` in order to save resources. But notice though, as stated above, that this will result in a ``set_false_path`` constraint being used, which can result in quite arbitrary latency. .. _resync.resync_level_on_signal: resync_level_on_signal.vhd -------------------------- `View source code on GitHub `__. .. symbolator:: component resync_level_on_signal is generic ( default_value : std_ulogic ); port ( data_in : in std_ulogic; --# {{}} clk_out : in std_ulogic; sample_value : in std_ulogic; data_out : out std_ulogic ); end component; Sample a bit from one clock domain to another. .. note:: This entity has a scoped constraint file `resync_level_on_signal.tcl `__ that must be used for proper operation. See :ref:`here ` for instructions. This entity does not utilize any meta stability protection. It is up to the user to ensure that ``data_in`` is stable when ``sample_value`` is asserted. Note that unlike e.g. :ref:`resync.resync_level`, it is safe to drive the input of this entity with a LUT as well as an FF. .. _resync.resync_pulse: resync_pulse.vhd ---------------- `View source code on GitHub `__. .. symbolator:: component resync_pulse is generic ( active_level : std_ulogic; enable_feedback : boolean; assert_false_on_pulse_overload : boolean ); port ( clk_in : in std_ulogic; pulse_in : in std_ulogic; overload_has_occurred : out std_ulogic; --# {{}} clk_out : in std_ulogic; pulse_out : out std_ulogic ); end component; A robust way of resyncing a pulse signal from one clock domain to another. .. figure:: resync_pulse_transparent.png .. note:: This entity has a scoped constraint file `resync_pulse.tcl `__ that must be used for proper operation. See :ref:`here ` for instructions. Note that unlike e.g. :ref:`resync.resync_level`, it is safe to drive the input of this entity with a LUT as well as an FF. See the `constraint file `__ and `this article `__ for detailed information about timing constraints and how this CDC topology can be used reliably. Pulse overload ______________ The barebone pulse CDC is vulnerable to pulse overload, meaning that if multiple pulses arrive close together, some or all of them can be missed. This can happen if the distance between input pulses is not significantly greater than two output clock domain cycles. To re-formulate this problem, the design is safe and can not miss pulses if 1. The output clock is significantly more than two times faster than the input clock, or 2. The user knows from the application that input pulses can not happen often. Otherwise it is unsafe, and pulses can be missed. Using the feedback level mechanism, as described below, can mitigate this problem. Feedback level ______________ This entity features an optional feedback level and input gating which mitigates the pulse overload problem. When this is enabled and the pulse overload scenario happens, the feedback will guarantee that at least one pulse arrives on the output. Note that pulses can still be missed, meaning fewer pulses might arrive on the output than were received on the input. But, once again, the mechanism guarantees that at least one pulse arrives. Hence, this CDC in this configuration is not suitable for applications where the exact pulse count is important. It is more suitable for situations where the user wants to know wether or not something has occurred, and not the exact number of times it occurred. The feedback level and input gating mechanisms are enabled by the ``enable_feedback`` generic. Note that it has default value ``true``, since that is considered the most robust behavior. .. _resync.resync_pulse.resource_utilization: Resource utilization ____________________ This entity has `netlist builds `__ set up with `automatic size checkers `__ in `module_resync.py `__. The following table lists the resource utilization for the entity, depending on generic configuration. .. list-table:: Resource utilization for **resync_pulse** netlist builds. :header-rows: 1 * - Generics - Total LUTs - FFs * - enable_feedback = False - 2 - 4 * - enable_feedback = True - 3 - 7 .. _resync.resync_rarely_valid: resync_rarely_valid.vhd ----------------------- `View source code on GitHub `__. .. symbolator:: component resync_rarely_valid is generic ( data_width : positive ); port ( input_clk : in std_ulogic; input_valid : in std_ulogic; input_data : in std_ulogic_vector; --# {{}} result_clk : in std_ulogic; result_valid : out std_ulogic; result_data : out std_ulogic_vector ); end component; Simple CDC where a ``data`` word, qualified with a ``valid`` signal, is resynchronized from one clock domain to another. The ``input_valid`` must be pulsed for one clock cycle when the ``input_data`` is valid, which will result in one ``result_valid`` pulse once data has propagated. This CDC features no feedback and no backpressure, and will fail if ``input`` words arrive too close together. It is up to the user to make sure that this does not happen. There needs to be at least 1 ``input`` clock cycle and 3 ``result`` clock cycles between between each word. .. warning:: This CDC topology is inherently unsafe and should be used with a lot of caution. If ``input`` words arrive too close together, there will be corrupted and/or metastable ``result`` words. There is no monitoring/detection/reporting mechanism for such events. Use this entity only if 1. you are absolutely sure, due to the design of upstream logic, that ``input`` words will never arrive "too close", or 2. you have some status feedback mechanism outside of this entity. The name of this CDC topology comes from the fact that ``valid`` may only arrive quite rarely. And also, due to its inherent unsafe nature, it is rarely a valid choice to use this CDC. This CDC features no ``ready`` signals for backpressure. See e.g. :ref:`resync.resync_twophase_handshake` or :ref:`fifo.asynchronous_fifo` instead if backpressure is needed, or if the flow of data is unknown. .. warning:: This entity is in active development. Using it is NOT recommended at this point. .. note:: This entity has a scoped constraint file `resync_rarely_valid.tcl `__ that must be used for proper operation. See :ref:`here ` for instructions. .. note:: TODO: * Add constraints. * Run post synthesis simulation. * Test on hardware. .. _resync.resync_rarely_valid.resource_utilization: Resource utilization ____________________ This entity has `netlist builds `__ set up with `automatic size checkers `__ in `module_resync.py `__. The following table lists the resource utilization for the entity, depending on generic configuration. .. list-table:: Resource utilization for **resync_rarely_valid** netlist builds. :header-rows: 1 * - Generics - Total LUTs - LUTRAMs - FFs - Maximum logic level * - data_width = 8 - 2 - 0 - 21 - 2 * - data_width = 16 - 2 - 0 - 37 - 2 * - data_width = 24 - 2 - 0 - 53 - 2 * - data_width = 32 - 2 - 0 - 69 - 2 * - data_width = 64 - 2 - 0 - 133 - 2 .. _resync.resync_rarely_valid_lutram: resync_rarely_valid_lutram.vhd ------------------------------ `View source code on GitHub `__. .. symbolator:: component resync_rarely_valid_lutram is generic ( data_width : positive; enable_output_register : boolean ); port ( input_clk : in std_ulogic; input_valid : in std_ulogic; input_data : in std_ulogic_vector; --# {{}} result_clk : in std_ulogic; result_valid : out std_ulogic; result_data : out std_ulogic_vector ); end component; Simple CDC where a ``data`` word, qualified with a ``valid`` signal, is resynchronized from one clock domain to another. The ``input_valid`` must be pulsed for one clock cycle when the ``input_data`` is valid, which will result in one ``result_valid`` pulse once data has propagated. .. figure:: resync_rarely_valid_lutram.png Very similar to :ref:`resync.resync_rarely_valid` but uses LUTRAM instead of registers, making it extremely :ref:`resource efficient `. See :ref:`resync.resync_rarely_valid` for further information and some usage instructions. .. warning:: This entity is in active development. Using it is NOT recommended at this point. .. note:: This entity has a scoped constraint file `resync_rarely_valid_lutram.tcl `__ that must be used for proper operation. See :ref:`here ` for instructions. .. note:: TODO: * Add constraints. * Investigate synthesis bug. Outputs are driven to ground through LUTs. * Run post synthesis simulation. * Test on hardware. .. _resync.resync_rarely_valid_lutram.resource_utilization: Resource utilization ____________________ This entity has `netlist builds `__ set up with `automatic size checkers `__ in `module_resync.py `__. The following table lists the resource utilization for the entity, depending on generic configuration. .. list-table:: Resource utilization for **resync_rarely_valid_lutram** netlist builds. :header-rows: 1 * - Generics - Total LUTs - LUTRAMs - FFs - Maximum logic level * - data_width = 8 - 10 - 8 - 4 - 2 * - data_width = 16 - 14 - 12 - 4 - 2 * - data_width = 24 - 18 - 16 - 4 - 2 * - data_width = 32 - 26 - 24 - 4 - 2 * - data_width = 64 - 46 - 44 - 4 - 2 .. _resync.resync_slv_level: resync_slv_level.vhd -------------------- `View source code on GitHub `__. .. symbolator:: component resync_slv_level is generic ( width : positive; enable_input_register : boolean; default_value : std_ulogic_vector ); port ( clk_in : in std_ulogic; data_in : in std_ulogic_vector; --# {{}} clk_out : in std_ulogic; data_out : out std_ulogic_vector ); end component; Resync a vector from one clock domain to another. .. note:: This entity instantiates :ref:`resync.resync_level` which has a :ref:`scoped constraint ` file that must be used. This simple vector resync mechanism does not guarantee any coherency between the bits. There might be a large skew between different bits. It will also not be able to handle pulses in the input data, but can instead only handle semi-static "level"-type signals. It does however have meta-stability protection. See :ref:`resync.resync_level` for details about constraining and usage of the ``enable_input_register`` generic. .. _resync.resync_slv_level_on_signal: resync_slv_level_on_signal.vhd ------------------------------ `View source code on GitHub `__. .. symbolator:: component resync_slv_level_on_signal is generic ( width : positive; default_value : std_ulogic_vector ); port ( data_in : in std_ulogic_vector; --# {{}} clk_out : in std_ulogic; sample_value : in std_ulogic; data_out : out std_ulogic_vector ); end component; Sample a vector from one clock domain to another. .. note:: This entity instantiates :ref:`resync.resync_level_on_signal` which has a :ref:`scoped constraint ` file that must be used. This modules does not utilize any meta stability protection. It is up to the user to ensure that ``data_in`` is stable when ``sample_value`` is asserted. It will not be able to handle pulses in the data and does not feature any bit coherency. Hence it can only be used with semi-static "level"-type signals. Note that unlike e.g. :ref:`resync.resync_level`, it is safe to drive the input of this entity with LUTs as well as FFs. .. _resync.resync_sticky_level: resync_sticky_level.vhd ----------------------- `View source code on GitHub `__. .. symbolator:: component resync_sticky_level is generic ( enable_input_register : boolean ); port ( input_clk : in std_ulogic; input_event : in std_ulogic; --# {{}} result_clk : in std_ulogic ; result_sticky : out std_ulogic ); end component; Resync a sticky status bit from one clock domain to another. If ``input_event`` is high at any point, the ``result_sticky`` will be raised and will remain high. There is no way to reset this value. Typical use case is to CDC a critical error bit, which might exhibit a pulse-like behavior, from one clock domain to another. This entity is a very small wrapper around :ref:`resync.resync_level`. Latency _______ By default, the ``enable_input_register`` generic which is propagated to :ref:`resync.resync_level` is ``false``. This will result in a ``set_false_path`` constraint for the level signal that crosses clock domains. This will yield an arbitrary build-dependent latency. If a deterministic and bounded latency is required, set the ``enable_input_register`` to ``true`` to get a ``set_max_delay`` constraint. .. _resync.resync_twophase: resync_twophase.vhd ------------------- `View source code on GitHub `__. .. symbolator:: component resync_twophase is generic ( width : positive; default_value : std_ulogic_vector ); port ( clk_in : in std_ulogic; data_in : in std_ulogic_vector; --# {{}} clk_out : in std_ulogic; data_out : out std_ulogic_vector ); end component; Free-running two-phase CDC for resynchronizing a vector of correlated data from one clock domain to another. Unlike e.g. :ref:`resync.resync_slv_level`, this entity contains a mechanism that guarantees bit coherency. .. figure:: resync_twophase_transparent.png A level signal is rotated around between input and output side, with three registers in each direction. The level toggles for each roundtrip, and data is sampled on each side upon a level transition. This ensures that data is sampled on the output side only when we know that the sampled input data is stable. Conversely, input data is only sampled when we know that data has been sampled on the output in a stable fashion. .. note:: This entity is free-running, meaning that it will sample and resync input data back-to-back. See :ref:`resync.resync_twophase_handshake` for a version that features AXI-Stream-like handshaking on the input and result sides. This entity is suitable for resynchronizing e.g. a control/status register or a counter value, which are scenarios where bit coherency is crucial. It will not be able to handle pulses in the input data, it is very likely that pulses will be missed. .. note:: This entity has a scoped constraint file `resync_twophase.tcl `__ that must be used for proper operation. See :ref:`here ` for instructions. Note that unlike e.g. :ref:`resync.resync_level`, it is safe to drive the input of this entity with LUTs as well as FFs. Latency and resource utilization ________________________________ The latency from input to output, given the constraints that we apply, is in the absolute worst case almost equal to 4 * period(clk_in) + 4 * period(clk_out) Depending on * which state the level signal is in, * the place/route result, * and how the clock edges align, the latency from input to output can be significantly lower. This is also how the sampling period of the signal behaves. As such this resync is not suitable for signals that change quickly. It is instead typically used for e.g. slow moving counters and status words, or other data where the different bits are correlated. The LUT utilization is always 3. The FF utilization increases linearly at a rate of ``2 * width``. Compared to :ref:`resync.resync_counter` this entity has lower LUT and FF usage in all scenarios. It does however have higher latency. Another way of achieving the same functionality is to use a shallow :ref:`fifo.asynchronous_fifo` with ``write_valid`` and ``read_ready`` statically set to ``1``. The FIFO will however have higher LUT usage. FF usage is higher for the FIFO, up to around width 32 where this entity will consume more FF. Latency is about the same for both. Why is this a separate implementation? ______________________________________ In terms of functionality, this entity is identical to :ref:`resync.resync_twophase_handshake`, but with handshaking ``input_valid`` and ``result_ready`` tied to ``'1'``. However, doing it like that results in a slightly higher result utilization than a purpose-specific implementation as in this file. .. _resync.resync_twophase.resource_utilization: Resource utilization ____________________ This entity has `netlist builds `__ set up with `automatic size checkers `__ in `module_resync.py `__. The following table lists the resource utilization for the entity, depending on generic configuration. .. list-table:: Resource utilization for **resync_twophase** netlist builds. :header-rows: 1 * - Generics - Total LUTs - LUTRAMs - FFs - Maximum logic level * - width = 8 - 3 - 0 - 22 - 2 * - width = 16 - 3 - 0 - 38 - 2 * - width = 24 - 3 - 0 - 54 - 2 * - width = 32 - 3 - 0 - 70 - 2 * - width = 64 - 3 - 0 - 134 - 2 .. _resync.resync_twophase_handshake: resync_twophase_handshake.vhd ----------------------------- `View source code on GitHub `__. .. symbolator:: component resync_twophase_handshake is generic ( data_width : positive ); port ( input_clk : in std_ulogic; input_ready : out std_ulogic; input_valid : in std_ulogic; input_data : in std_ulogic_vector; --# {{}} result_clk : in std_ulogic; result_ready : in std_ulogic; result_valid : out std_ulogic; result_data : out std_ulogic_vector ); end component; Two-phase handshaking CDC for resynchronizing a vector of correlated data from one clock domain to another. Features an AXI-Stream-like handshaking interface on both the ``input`` and ``result`` side. .. figure:: resync_twophase_handshake_transparent.png In many ways this entity is a superset of :ref:`resync.resync_twophase`, so see that for some more insight. But this one features ``ready``/``valid`` handshaking, which enables backpressure but increases :ref:`resync.resync_twophase_handshake.resource_utilization` slightly. .. note:: This entity has a scoped constraint file `resync_twophase_handshake.tcl `__ that must be used for proper operation. See :ref:`here ` for instructions. Note that unlike e.g. :ref:`resync.resync_level`, it is safe to drive the input of this entity with LUTs as well as FFs. Latency _______ The latency from ``input`` to ``result`` is less than or equal to period(input_clk) + 3 * period(result_clk), Throughput __________ The sampling period (inverse of throughput) of is roughly equal to 3 * period(input_clk) + 3 * period(result_clk). If ``result_ready`` is stalling, new ``input`` can be sampled before the previous ``result`` is sent out, which aids throughput in this scenario. .. _resync.resync_twophase_handshake.resource_utilization: Resource utilization ____________________ This entity has `netlist builds `__ set up with `automatic size checkers `__ in `module_resync.py `__. The following table lists the resource utilization for the entity, depending on generic configuration. .. list-table:: Resource utilization for **resync_twophase_handshake** netlist builds. :header-rows: 1 * - Generics - Total LUTs - LUTRAMs - FFs - Maximum logic level * - data_width = 8 - 5 - 0 - 24 - 2 * - data_width = 16 - 5 - 0 - 40 - 2 * - data_width = 24 - 5 - 0 - 56 - 2 * - data_width = 32 - 5 - 0 - 72 - 2 * - data_width = 64 - 5 - 0 - 136 - 2 .. _resync.resync_twophase_lutram: resync_twophase_lutram.vhd -------------------------- `View source code on GitHub `__. .. symbolator:: component resync_twophase_lutram is generic ( width : positive; default_value : std_ulogic_vector; enable_output_register : boolean ); port ( clk_in : in std_ulogic; data_in : in std_ulogic_vector; --# {{}} clk_out : in std_ulogic; data_out : out std_ulogic_vector ); end component; Free-running two-phase handshaking CDC for resynchronizing a vector of correlated data from one clock domain to another. Very similar to :ref:`resync.resync_twophase` but uses LUTRAM instead of registers, making it extremely :ref:`resource efficient `. .. warning:: This entity is in active development. Using it is NOT recommended at this point. .. note:: This entity has a scoped constraint file `resync_twophase_lutram.tcl `__ that must be used for proper operation. See :ref:`here ` for instructions. .. figure:: resync_twophase_lutram.png .. _resync.resync_twophase_lutram.resource_utilization: Resource utilization ____________________ This entity has `netlist builds `__ set up with `automatic size checkers `__ in `module_resync.py `__. The following table lists the resource utilization for the entity, depending on generic configuration. .. list-table:: Resource utilization for **resync_twophase_lutram** netlist builds. :header-rows: 1 * - Generics - Total LUTs - LUTRAMs - FFs - Maximum logic level * - width = 8 - 10 - 8 - 6 - 2 * - width = 16 - 14 - 12 - 6 - 2 * - width = 24 - 18 - 16 - 6 - 2 * - width = 32 - 26 - 24 - 6 - 2 * - width = 64 - 46 - 44 - 6 - 2