GCC Code Coverage Report
Directory: generated/vunit_out/preprocessed/ Exec Total Coverage
File: generated/vunit_out/preprocessed/fifo/asynchronous_fifo.vhd Lines: 65 65 100.0 %
Date: 2021-06-12 04:12:08 Branches: 247 345 71.6 %

Line Branch Exec Source
1
1110
-- -------------------------------------------------------------------------------------------------
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
-- Asynchronous FIFO.
9
-- -------------------------------------------------------------------------------------------------
10
11
library ieee;
12
use ieee.std_logic_1164.all;
13
use ieee.numeric_std.all;
14
15
library common;
16
use common.attribute_pkg.all;
17
use common.types_pkg.all;
18
19
library math;
20
use math.math_pkg.all;
21
22
library resync;
23
24
25


17157
entity asynchronous_fifo is
26
  generic (
27
    width : positive;
28
    depth : positive;
29
    -- Changing these levels from default value will increase logic footprint
30
    almost_full_level : integer range 0 to depth := depth;
31
    almost_empty_level : integer range 0 to depth := 0;
32
    -- Set to true in order to use read_last and write_last
33
    enable_last : boolean := false;
34
    -- If enabled, read_valid will not be asserted until a full packet is available in
35
    -- FIFO. I.e. when write_last has been received.
36
    enable_packet_mode : boolean := false;
37
    -- Set to true in order to use the drop_packet port. Must set enable_packet_mode as
38
384
    -- well to use this.
39



2768
    enable_drop_packet : boolean := false;
40
    ram_type : ram_style_t := ram_style_auto
41
384
  );
42





26214590
  port (
43
    -- Read data interface
44
    clk_read : in std_logic;
45
    read_ready : in  std_logic;
46
    -- '1' if FIFO is not empty
47
    read_valid : out std_logic := '0';
48
    read_data : out std_logic_vector(width - 1 downto 0) := (others => '0');
49
    -- Must set enable_last generic in order to use this
50
    read_last : out std_logic := '0';
51
52
    -- Status signals on the read side. Updated one clock cycle after read transactions.
53
    -- Updated "a while" after write transactions (not deterministic).
54
    --
55
    -- Note that this port will be CONSTANTLY ZERO if the enable_packet_mode generic is set
56
    -- to true. This is since a glitch-free value can not be guaranteed in this mode.
57
    --
58
    -- When packet_mode is enabled, this value will still reflect the number of words that are in
59
    -- the FIFO RAM. This is not necessarily the same as the number of words that can be read, in
60
    -- this mode.
61
    read_level : out integer range 0 to depth := 0;
62
    -- '1' if there are almost_empty_level or fewer words available to read
63
    --
64
    -- Note that this port will be CONSTANTLY ONE if the enable_packet_mode generic is set
65
    -- to true, and almost_empty_level has a non-default value.
66
    -- This is since a glitch-free value of read_level can not be guaranteed in this mode.
67
    read_almost_empty : out std_logic := '1';
68
69
    -- Write data interface
70
    clk_write : in std_logic;
71
    -- '1' if FIFO is not full
72
    write_ready : out std_logic := '1';
73
    write_valid : in  std_logic;
74
    write_data  : in  std_logic_vector(width - 1 downto 0);
75
    -- Must set enable_last generic in order to use this
76
    write_last : in std_logic := '0';
77
78
    -- Status signals on the write side. Updated one clock cycle after write transactions.
79
    -- Updated "a while" after read transactions (not deterministic).
80
    write_level : out integer range 0 to depth := 0;
81
    -- '1' if there are almost_full_level or more words available in the FIFO
82
    write_almost_full : out std_logic := '0';
83
84
    -- Drop the current packet (all words that have been writen since the previous write_last).
85
    -- Must set enable_drop_packet generic in order to use this.
86
    drop_packet : in std_logic := '0'
87
  );
88
end entity;
89
90
185
architecture a of asynchronous_fifo is
91
92
  -- Need one extra bit in the addresses to be able to make the distinction if the FIFO
93
  -- is full or empty (where the addresses would otherwise be equal).
94
  subtype fifo_addr_t is unsigned(num_bits_needed(2 * depth - 1) - 1 downto 0);
95
4701
  signal read_addr_next, write_addr : fifo_addr_t := (others => '0');
96
97
  -- The counter for number of lasts in the FIFO (used by packet mode) also needs one extra bit,
98
  -- to cover the case when the whole FIFO depth has been written with lasts.
99
2443
  signal num_lasts_written : fifo_addr_t := (others => '0');
100
101
  -- The part of the address that actually goes to the BRAM address port
102
  subtype bram_addr_range is integer range num_bits_needed(depth - 1) - 1 downto 0;
103
104
begin
105
106
555
  assert is_power_of_two(depth) report "Depth must be a power of two" severity failure;
107
108

370
  assert enable_last or (not enable_packet_mode)
109
    report "Must set enable_last for packet mode" severity failure;
110

370
  assert enable_packet_mode or (not enable_drop_packet)
111
    report "Must set enable_packet_mode for drop packet support" severity failure;
112
113
114
  assign_almost_full : if almost_full_level = depth generate
115

497
    write_almost_full <= not write_ready;
116
  else generate
117

41688
    write_almost_full <= to_sl(write_level > almost_full_level - 1);
118
  end generate;
119
120
  assign_almost_empty : if almost_empty_level = 0 generate
121

121804
    read_almost_empty <= not read_valid;
122
  else generate
123
    -- Note that read_level will always be zero if drop_packet support is enabled, making this
124
    -- signal always '1' in that mode.
125


13205766
    read_almost_empty <= to_sl(read_level < almost_empty_level + 1);
126
  end generate;
127
128
129
  ------------------------------------------------------------------------------
130
  write_block : block
131
6959
    signal write_addr_next, write_addr_next_if_not_drop, write_addr_start_of_packet :
132
      fifo_addr_t := (others => '0');
133
2443
    signal read_addr_resync : fifo_addr_t := (others => '0');
134
  begin
135
136
    ------------------------------------------------------------------------------
137
3572
    write_status : process
138
    begin
139

13205661
      wait until rising_edge(clk_write);
140
141
3301402
      if enable_drop_packet then
142



25047
        num_lasts_written <= num_lasts_written
143
          + to_int(write_ready and write_valid and write_last and not drop_packet);
144
      else
145



22840826
        num_lasts_written <= num_lasts_written + to_int(write_ready and write_valid and write_last);
146
      end if;
147
148
      -- Note that write_ready looks at the next write address that will be used if there is
149
      -- no packet drop. This is done to ease the timing of write_ready which is
150
      -- often critical. There is a functional difference only in the special case when the FIFO
151
      -- goes full in the same cycle as drop_packet is sent. In that case, write_ready will be low
152
      -- for one cycle and then go high the next.
153






3301402
      write_ready <= to_sl(
154
        read_addr_resync(bram_addr_range) /= write_addr_next_if_not_drop(bram_addr_range)
155
        or read_addr_resync(read_addr_resync'high) =  write_addr_next_if_not_drop(write_addr_next'high));
156
157
      -- Note that this potential update of write_addr_next does not affect write_ready,
158
      -- assigned above. This is done to save logic and ease the timing of write_ready which is
159
      -- often critical. There is a functional difference only in the special case when the FIFO
160
      -- goes full in the same cycle as drop_packet is sent. In that case, write_ready will be low
161
      -- for one cycle and then go high the next.
162
3301402
      if enable_drop_packet then
163
2362
        if (not drop_packet) and write_ready and write_valid and write_last then
164

3301492
          write_addr_start_of_packet <= write_addr_next;
165
        end if;
166
      end if;
167
168
      -- These signals however must have the updated value.
169

3301402
      write_level <= to_integer(write_addr_next - read_addr_resync) mod (2 * depth);
170

26167275
      write_addr <= write_addr_next;
171
    end process;
172
173



1201121
    write_addr_next_if_not_drop <= write_addr + to_int(write_ready and write_valid);
174



728140
    write_addr_next <=
175

92524
      write_addr_start_of_packet when enable_drop_packet and drop_packet = '1'
176
      else write_addr_next_if_not_drop;
177
178
179
    ------------------------------------------------------------------------------
180

1314
    resync_read_addr : entity resync.resync_counter
181
      generic map (
182
        width => read_addr_next'length
183
      )
184
      port map (
185
        clk_in      => clk_read,
186
        counter_in  => read_addr_next,
187
        clk_out     => clk_write,
188
        counter_out => read_addr_resync
189
      );
190
191
  end block;
192
193
194
  ------------------------------------------------------------------------------
195
  read_block : block
196
4701
    signal write_addr_resync, read_addr : fifo_addr_t := (others => '0');
197
4701
    signal num_lasts_read, num_lasts_written_resync : fifo_addr_t := (others => '0');
198
  begin
199
200
    ------------------------------------------------------------------------------
201
185
    read_status : process
202
185
      variable read_level_next : integer range 0 to depth;
203
3572
      variable num_lasts_read_next : fifo_addr_t := (others => '0');
204
    begin
205

25985310
      wait until rising_edge(clk_read);
206
207

45089576
      read_addr <= read_addr_next;
208
209
      -- If drop_packet support is enabled, the write_addr can make jumps that are greater
210
      -- than +/- 1. This means that the resynced counter can have glitches, since it is possible
211
      -- that the counter value is sampled just as more than one bit are changing.
212
      -- This is an issue despite the value being gray-coded and the bus_skew constraint
213
      -- being present.
214
      --
215
      -- Since we can not guarantee a glitch-free read_level value in this mode, we simply do not
216
      -- assign the counter.
217
6496288
      if not enable_drop_packet then
218
6491464
        read_level_next := to_integer(write_addr_resync - read_addr_next) mod (2 * depth);
219

6491464
        read_level <= read_level_next;
220
      end if;
221
222
6496288
      if enable_packet_mode then
223

396480
        num_lasts_read_next := num_lasts_read + to_int(read_ready and read_valid and read_last);
224
225

4727770
        num_lasts_read <= num_lasts_read_next;
226

396480
        read_valid <= to_sl(num_lasts_read_next /= num_lasts_written_resync);
227
      else
228

13532617
        read_valid <= to_sl(read_level_next /= 0);
229
      end if;
230
    end process;
231
232



3578587
    read_addr_next <= read_addr + to_int(read_ready and read_valid);
233
234
235
    ------------------------------------------------------------------------------
236
    -- This value is not used in the write clock domain if we are in drop_packet mode
237
    resync_write_addr : if not enable_drop_packet generate
238

1441
      resync_counter_inst : entity resync.resync_counter
239
        generic map (
240
          width => write_addr'length
241
        )
242
        port map (
243
          clk_in      => clk_write,
244
          counter_in  => write_addr,
245
          clk_out     => clk_read,
246
          counter_out => write_addr_resync
247
        );
248
    end generate;
249
250
251
    ------------------------------------------------------------------------------
252
    -- This value is used in the write clock domain only if we are in packet mode
253
    resync_num_lasts_written : if enable_packet_mode generate
254

383
      resync_counter_inst : entity resync.resync_counter
255
        generic map (
256
          width => num_lasts_written'length
257
        )
258
        port map (
259
          clk_in      => clk_write,
260
          counter_in  => num_lasts_written,
261
          clk_out     => clk_read,
262
          counter_out => num_lasts_written_resync
263
        );
264
    end generate;
265
  end block;
266
267
268
  ------------------------------------------------------------------------------
269
  memory : block
270
185
    constant memory_word_width : integer := width + to_int(enable_last);
271
    subtype word_t is std_logic_vector(memory_word_width - 1 downto 0);
272
    type mem_t is array (integer range <>) of word_t;
273
274
1475033
    signal mem : mem_t(0 to depth - 1) := (others => (others => '0'));
275
    attribute ram_style of mem : signal is to_attribute(ram_type);
276
277
7983
    signal memory_read_data, memory_write_data : word_t;
278
  begin
279
280




6370874
    read_data <= memory_read_data(read_data'range);
281




1839193
    memory_write_data(write_data'range) <= write_data;
282
283
    assign_data : if enable_last generate
284

6516
      read_last <= memory_read_data(memory_read_data'high);
285


13210039
      memory_write_data(memory_write_data'high) <= write_last;
286
    end generate;
287
288
737609
    write_memory : process
289
    begin
290

13205661
      wait until rising_edge(clk_write);
291
292
3301402
      if write_ready and write_valid then
293





21277546
        mem(to_integer(write_addr(bram_addr_range))) <= memory_write_data;
294
      end if;
295
    end process;
296
297
4084
    read_memory : process
298
    begin
299

12992655
      wait until rising_edge(clk_read);
300
301




94557723
      memory_read_data <= mem(to_integer(read_addr_next(bram_addr_range)));
302
    end process;
303
  end block;
304
305
end architecture;