GCC Code Coverage Report
Directory: generated/vunit_out/preprocessed/ Exec Total Coverage
File: generated/vunit_out/preprocessed/resync/resync_slv_level_coherent.vhd Lines: 23 23 100.0 %
Date: 2021-06-12 04:12:08 Branches: 46 60 76.7 %

Line Branch Exec Source
1
54
-- -------------------------------------------------------------------------------------------------
2
-- Copyright (c) Lukas Vik. All rights reserved.
3
--
4
-- This file is part of the tsfpga project.
5
-- https://tsfpga.com
6
-- https://gitlab.com/tsfpga/tsfpga
7
-- -------------------------------------------------------------------------------------------------
8
-- Resynchronize a data vector from one clock domain to another. Unlike e.g. resync_slv_level, this
9
-- entity contains a mechanism that guarantees bit coherency. An asynchronous FIFO can also be used
10
-- to achieve this task, but this entity results in a smaller logic footprint.
11
--
12
-- Note that unlike e.g. resync_level, it is safe to drive the input of this entity with LUTs
13
-- as well as FFs.
14
--
15
-- A level signal is rotated around between input and output side, with three registers in each
16
-- direction. The level toggles for each roundtrip, and data is sampled on each side upon a level
17
-- transition.
18
-- This ensures that data is sample on the output side only when we know that the sampled
19
-- input data is stable. Conversely input data is only sampled when we know that data has been
20
-- sampled on the output in a stable fashion.
21
--
22
-- The latency is less than or equal to
23
--   3 * period(clk_in) + 3 * period(clk_out)
24
--
25
-- This is also the sampling period of the signal. As such this resync is not suitable for signals
26
-- that change quickly. It is instead typically used for e.g. monotonic counters, slow moving status
27
-- words, and other data where the different bits are correlated.
28
--
29
-- The LUT utilization is always 3. The FF utilization increases linearly at a rate of 2 * width.
30
--
31
-- Compared to resync_counter this entity has lower LUT and FF usage in all scenarios. It does
32
-- however have higher latency.
33
--
34
-- Compared to asynchronous_fifo this entity has lower LUT usage. FF usage is lower up to around
35
-- width 32 where this entity will consume more FF. Latency is about the same for both.
36
-- -------------------------------------------------------------------------------------------------
37
38
library ieee;
39
use ieee.std_logic_1164.all;
40
41
42

265
entity resync_slv_level_coherent is
43
  generic (
44
    width : positive;
45
    -- Initial value for the ouput that will be set for a few cycles before the first input
46
    -- value has propagated.
47
    default_value : std_logic_vector(width - 1 downto 0) := (others => '0')
48
  );
49
  port (
50
    clk_in : in std_logic := '0';
51
    data_in : in std_logic_vector(default_value'range);
52
53
    clk_out : in std_logic;
54
    data_out : out std_logic_vector(default_value'range) := default_value
55
  );
56
end entity;
57
58
architecture a of resync_slv_level_coherent is
59
60
101
  signal data_in_sampled, data_out_int : std_logic_vector(data_in'range) := default_value;
61
62
9
  constant level_default_value : std_logic := '0';
63
18
  signal input_level, input_level_m1, input_level_m1_not_inverted, output_level, output_level_m1
64
18
    : std_logic := level_default_value;
65
18
66
begin
67
18
68
147
  ------------------------------------------------------------------------------
69
9
  resync_level_to_output_inst : entity work.resync_level
70
    generic map (
71
      -- Value is driven by a FF so this is not needed
72
      enable_input_register => false,
73
      default_value => level_default_value
74
    )
75
    port map (
76
      clk_in => clk_in,
77
      data_in => input_level,
78
      --
79
      clk_out => clk_out,
80
      data_out => output_level_m1
81
    );
82
83
84
  ------------------------------------------------------------------------------
85
9
  resync_level_to_input_inst : entity work.resync_level
86
    generic map (
87
      -- Value is driven by a FF so this is not needed
88
      enable_input_register => false,
89
      default_value => level_default_value
90
    )
91
    port map (
92
      clk_in => clk_out,
93
      data_in => output_level,
94
      --
95
      clk_out => clk_in,
96
      data_out => input_level_m1_not_inverted
97
    );
98
99
  -- Invert here, before the last input level register, so that the output level async_reg is
100
  -- driven by an FF and not a LUT.
101

1624
  input_level_m1 <= not input_level_m1_not_inverted;
102
103
104
  ------------------------------------------------------------------------------
105
55
  handle_input : process
106
  begin
107

1495
    wait until rising_edge(clk_in);
108
109
372
    if input_level /= input_level_m1 then
110


780
      data_in_sampled <= data_in;
111
    end if;
112
113


1829
    input_level <= input_level_m1;
114
  end process;
115
116
117
  ------------------------------------------------------------------------------
118
55
  handle_output : process
119
  begin
120

1085
    wait until rising_edge(clk_out);
121
122
270
    if output_level /= output_level_m1 then
123

660
      data_out_int <= data_in_sampled;
124
    end if;
125
126

540
    output_level <= output_level_m1;
127
  end process;
128
129


223
  data_out <= data_out_int;
130
131
end architecture;