GCC Code Coverage Report
Directory: generated/vunit_out/preprocessed/ Exec Total Coverage
File: generated/vunit_out/preprocessed/fifo/tb_asynchronous_fifo.vhd Lines: 232 232 100.0 %
Date: 2021-06-12 04:12:08 Branches: 743 965 77.0 %

Line Branch Exec Source
1
240
-- -------------------------------------------------------------------------------------------------
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
9
library ieee;
10
use ieee.std_logic_1164.all;
11
use ieee.numeric_std.all;
12
13
library osvvm;
14
use osvvm.RandomPkg.all;
15
16
library vunit_lib;
17
use vunit_lib.axi_stream_pkg.all;
18
use vunit_lib.sync_pkg.all;
19
context vunit_lib.com_context;
20
context vunit_lib.vunit_context;
21
22
library common;
23
use common.types_pkg.all;
24
25
26




















440
entity tb_asynchronous_fifo is
27
  generic (
28
40
    depth : integer;
29

360
    read_clock_is_faster : boolean;
30
40
    almost_empty_level : natural := 0;
31

160
    almost_full_level : natural := 0;
32

120
    read_stall_probability_percent : integer := 0;
33




1040
    write_stall_probability_percent : integer := 0;
34

80
    enable_packet_mode : boolean := false;
35



160
    enable_last : boolean := false;
36

120
    enable_drop_packet : boolean := false;
37

40
    runner_cfg : string
38

40
  );
39

40
end entity;
40
41
architecture tb of tb_asynchronous_fifo is
42
43
40
  constant width : integer := 8;
44
40
45
80
  signal clk_read, clk_write : std_logic := '0';
46
47
80
  signal read_ready, read_valid, read_last : std_logic := '0';
48


1040
  signal write_ready, write_valid, write_last : std_logic := '0';
49
1320
  signal read_data, write_data : std_logic_vector(width - 1 downto 0) := (others => '0');
50
40
51
40
  signal read_level, write_level : integer;
52
40
  signal read_almost_empty, write_almost_full : std_logic := '0';
53
54
40
  signal drop_packet : std_logic := '0';
55
56
40
  signal has_gone_full_times, has_gone_empty_times : integer := 0;
57
58
40
  constant read_stall_config : stall_config_t := new_stall_config(
59
    stall_probability => real(read_stall_probability_percent) / 100.0,
60
    min_stall_cycles => 1,
61

40
    max_stall_cycles => 4);
62
40
  constant read_slave : axi_stream_slave_t := new_axi_stream_slave(
63
    data_length => width,
64
    stall_config => read_stall_config,
65
    protocol_checker => new_axi_stream_protocol_checker(data_length => width,
66
                                                        logger => get_logger("read_slave")));
67
40
68
40
  constant write_stall_config : stall_config_t := new_stall_config(
69
    stall_probability => real(write_stall_probability_percent) / 100.0,
70
40
    min_stall_cycles => 1,
71
    max_stall_cycles => 4);
72
80
  constant write_master : axi_stream_master_t := new_axi_stream_master(
73
40
    data_length => width,
74

360
    stall_config => write_stall_config,
75
    protocol_checker => new_axi_stream_protocol_checker(data_length => width,
76
40
                                                        logger => get_logger("write_master")));
77
78
begin
79
80

320
  test_runner_watchdog(runner, 2 ms);
81
82
40
  clocks : if read_clock_is_faster generate
83
100153
    clk_read  <= not clk_read after 2 ns;
84
66758
    clk_write <= not clk_write after 3 ns;
85
  else  generate
86
65273
    clk_read  <= not clk_read after 3 ns;
87
97656
    clk_write <= not clk_write after 2 ns;
88
  end generate;
89
90
91
  ------------------------------------------------------------------------------
92
40
  main : process
93
94
40
    variable data_queue, last_queue, axi_stream_pop_reference_queue : queue_t := new_queue;
95
200
    variable rnd : RandomPType;
96
97








724842
    procedure run_test(read_count, write_count : natural; set_last_flag : boolean := true) is
98
20106
      variable data : std_logic_vector(write_data'range);
99
2234
      variable last, last_expected : std_logic := '0';
100
2234
      variable axi_stream_pop_reference : axi_stream_reference_t;
101
    begin
102
2234
      for write_idx in 0 to write_count - 1 loop
103
28748
        data := rnd.RandSLV(data'length);
104
28748
        last := to_sl(write_idx = write_count - 1 and set_last_flag);
105
106
59688
        push_axi_stream(net, write_master, data, last);
107
108
57496
        push(data_queue, data);
109

114992
        push(last_queue, last);
110
      end loop;
111
112
      -- Queue up reads in order to get full throughput
113
2234
      for read_idx in 0 to read_count - 1 loop
114
56152
        pop_axi_stream(net, read_slave, axi_stream_pop_reference);
115
        -- We need to keep track of the pop_reference when we read the reply later.
116
        -- Hence it is pushed to a queue.
117

112224
        push(axi_stream_pop_reference_queue, axi_stream_pop_reference);
118
      end loop;
119
120
2234
      for read_idx in 0 to read_count - 1 loop
121
28056
        axi_stream_pop_reference := pop(axi_stream_pop_reference_queue);
122
112224
        await_pop_axi_stream_reply(net, axi_stream_pop_reference, data, last);
123
124

56112
        check_equal(data, pop_std_ulogic_vector(data_queue), "read_idx " & to_string(read_idx), line_num => 124, file_name => "tb_asynchronous_fifo.vhd");
125
28056
        last_expected := pop(last_queue);
126
28056
        if enable_last then
127


101088
          check_equal(last, last_expected, "read_idx " & to_string(read_idx), line_num => 127, file_name => "tb_asynchronous_fifo.vhd");
128
        end if;
129
      end loop;
130
131
8938
      wait_until_idle(net, as_sync(write_master));
132

662028
      wait until rising_edge(clk_write);
133
    end procedure;
134
135

7408
    procedure run_read(count : natural) is
136
    begin
137
7408
      run_test(count, 0);
138
    end procedure;
139
140

306
    procedure run_write(count : natural) is
141
    begin
142
306
      run_test(0, count);
143
    end procedure;
144
145

160
    procedure wait_for_read_to_propagate is
146
    begin
147

80
      wait until rising_edge(clk_write);
148

120
      wait until rising_edge(clk_write);
149
    end procedure;
150
151


429
    procedure wait_for_write_to_propagate is
152
    begin
153

109
      wait until rising_edge(clk_read);
154

128
      wait until rising_edge(clk_read);
155

128
      wait until rising_edge(clk_read);
156

256
      wait until rising_edge(clk_read);
157
    end procedure;
158
159
16
    procedure clear_queue(queue : queue_t) is
160
8
      variable dummy : character;
161
    begin
162
10568
      while not is_empty(queue) loop
163
10576
        dummy := unsafe_pop(queue);
164
      end loop;
165
    end procedure;
166
167

20
    procedure pulse_drop_packet is
168
    begin
169

4
      drop_packet <= '1';
170

16
      wait until rising_edge(clk_write);
171
































































77659
      drop_packet <= '0';
172
    end procedure;
173
174
  begin
175
120
    test_runner_setup(runner, runner_cfg);
176
80
    rnd.InitSeed(rnd'instance_name);
177
178
    -- Decrease noise
179
80
    disable(get_logger("read_slave:rule 4"), warning);
180
80
    disable(get_logger("write_master:rule 4"), warning);
181
    -- Some tests leave data unread in the FIFO
182
80
    disable(get_logger("read_slave:rule 9"), error);
183
184
40
    if run("test_init_state") then
185
8
      check_equal(read_valid, '0', line_num => 185, file_name => "tb_asynchronous_fifo.vhd");
186
8
      check_equal(write_ready, '1', line_num => 186, file_name => "tb_asynchronous_fifo.vhd");
187
8
      check_equal(write_almost_full, '0', line_num => 187, file_name => "tb_asynchronous_fifo.vhd");
188
8
      check_equal(read_almost_empty, '1', line_num => 188, file_name => "tb_asynchronous_fifo.vhd");
189


12
      wait until read_valid'event or write_ready'event or write_almost_full'event or read_almost_empty'event for 1 us;
190
8
      check_equal(read_valid, '0', line_num => 190, file_name => "tb_asynchronous_fifo.vhd");
191
8
      check_equal(write_ready, '1', line_num => 191, file_name => "tb_asynchronous_fifo.vhd");
192
8
      check_equal(write_almost_full, '0', line_num => 192, file_name => "tb_asynchronous_fifo.vhd");
193
12
      check_equal(read_almost_empty, '1', line_num => 193, file_name => "tb_asynchronous_fifo.vhd");
194
195
36
    elsif run("test_write_faster_than_read") then
196
24028
      run_test(3000, 3000);
197

8
      check_relation(has_gone_full_times > 200, line_num => 197, file_name => "tb_asynchronous_fifo.vhd", context_msg => "Expected has_gone_full_times > 200. Left is " & to_string(has_gone_full_times) & ". Right is " & to_string(200) & ".");
198

12
      check_true(is_empty(data_queue), line_num => 198, file_name => "tb_asynchronous_fifo.vhd");
199
200
32
    elsif run("test_read_faster_than_write") then
201
24028
      run_test(3000, 3000);
202

8
      check_relation(has_gone_empty_times > 200, line_num => 202, file_name => "tb_asynchronous_fifo.vhd", context_msg => "Expected has_gone_empty_times > 200. Left is " & to_string(has_gone_empty_times) & ". Right is " & to_string(200) & ".");
203

12
      check_true(is_empty(data_queue), line_num => 203, file_name => "tb_asynchronous_fifo.vhd");
204
205
28
    elsif run("test_packet_mode") then
206
      -- Write and immediately read a small packet
207
36
      run_test(read_count=>1, write_count=>1);
208
209
      -- Write a few words, without setting last
210
28
      run_test(read_count=>0, write_count=>3, set_last_flag=>false);
211
38
      wait_for_write_to_propagate;
212

8
      check_relation(read_level > 0, line_num => 212, file_name => "tb_asynchronous_fifo.vhd", context_msg => "Expected read_level > 0. Left is " & to_string(read_level) & ". Right is " & to_string(0) & ".");
213
8
      check_equal(read_valid, False, line_num => 213, file_name => "tb_asynchronous_fifo.vhd");
214
215
      -- Writing another word, with last set, shall enable read valid
216
28
      run_test(read_count=>0, write_count=>1);
217
38
      wait_for_write_to_propagate;
218
8
      check_equal(read_valid, True, line_num => 218, file_name => "tb_asynchronous_fifo.vhd");
219
220
      -- Write further packets
221
4
      for i in 1 to 3 loop
222
84
        run_test(read_count=>0, write_count=>4);
223

48
        check_equal(read_valid, True, line_num => 223, file_name => "tb_asynchronous_fifo.vhd");
224
      end loop;
225
226
      -- Read and check all the packets (will only work if read_valid is set properly)
227
156
      run_read(4 * 4);
228
8
      check_equal(read_valid, False, line_num => 228, file_name => "tb_asynchronous_fifo.vhd");
229
8
      check_equal(read_level, 0, line_num => 229, file_name => "tb_asynchronous_fifo.vhd");
230
231
      -- Write a few words, without setting last
232
28
      run_test(read_count=>0, write_count=>3, set_last_flag=>false);
233
38
      wait_for_write_to_propagate;
234

8
      check_relation(read_level > 0, line_num => 234, file_name => "tb_asynchronous_fifo.vhd", context_msg => "Expected read_level > 0. Left is " & to_string(read_level) & ". Right is " & to_string(0) & ".");
235
8
      check_equal(read_valid, False, line_num => 235, file_name => "tb_asynchronous_fifo.vhd");
236
237
      -- Writing another word, with last set, shall enable read valid
238
28
      run_test(read_count=>0, write_count=>1);
239
36
      wait_for_write_to_propagate;
240
12
      check_equal(read_valid, True, line_num => 240, file_name => "tb_asynchronous_fifo.vhd");
241
242
24
    elsif run("test_packet_mode_deep") then
243
      -- Show that the FIFO can be filled with lasts and that the last counters can wrap around.
244
245
      -- Fill the FIFO with lasts
246
4
      for i in 1 to depth loop
247

9504
        run_test(read_count=>0, write_count=>1, set_last_flag=>true);
248
      end loop;
249
8
      check_equal(read_valid, True, line_num => 249, file_name => "tb_asynchronous_fifo.vhd");
250
251
36
      run_read(1);
252
8
      check_equal(read_valid, True, line_num => 252, file_name => "tb_asynchronous_fifo.vhd");
253
254
28
      run_write(1);
255
38
      wait_for_write_to_propagate;
256
8
      check_equal(read_valid, True, line_num => 256, file_name => "tb_asynchronous_fifo.vhd");
257
258

2140
      run_read(depth);
259
8
      check_equal(read_valid, False, line_num => 259, file_name => "tb_asynchronous_fifo.vhd");
260
261
      -- Fill the FIFO with lasts again, making the write counter wrap around
262
4
      for i in 1 to depth loop
263

9504
        run_test(read_count=>0, write_count=>1, set_last_flag=>true);
264
      end loop;
265
8
      check_equal(read_valid, True, line_num => 265, file_name => "tb_asynchronous_fifo.vhd");
266
267

2132
      run_read(depth - 1);
268
8
      check_equal(read_valid, True, line_num => 268, file_name => "tb_asynchronous_fifo.vhd");
269
270
36
      run_read(1);
271
12
      check_equal(read_valid, False, line_num => 271, file_name => "tb_asynchronous_fifo.vhd");
272
273
20
    elsif run("test_drop_packet_mode_read_level_should_be_zero") then
274
      -- Write a couple of packets
275
14
      run_write(4);
276
14
      run_write(4);
277
14
      run_write(4);
278
19
      wait_for_write_to_propagate;
279
280
6
      check_equal(read_level, 0, line_num => 280, file_name => "tb_asynchronous_fifo.vhd");
281
282
18
    elsif run("test_drop_packet_random_data") then
283
      -- Write and read some data, to make the pointers advance a little.
284
      -- Note that this will set write_last on the last write, and some data will be left unread.
285

1084
      run_test(read_count=>depth / 2, write_count=>depth * 3 / 4);
286
24
      wait_for_read_to_propagate;
287
8
      check_equal(write_level, depth / 4, line_num => 287, file_name => "tb_asynchronous_fifo.vhd");
288
289
      -- Write some data without setting last, simulating a packet in progress.
290
      -- Drop the packet, and then read out the remainder of the previous packet.
291
      -- Note that the counts chosen will make the pointers wraparound.
292

28
      run_test(read_count=>0, write_count=>depth / 2, set_last_flag=>false);
293
16
      pulse_drop_packet;
294

556
      run_read(depth / 4);
295
296
24
      wait_for_read_to_propagate;
297
8
      check_equal(read_valid, '0', line_num => 297, file_name => "tb_asynchronous_fifo.vhd");
298
8
      check_equal(write_level, 0, line_num => 298, file_name => "tb_asynchronous_fifo.vhd");
299
300
      -- Clear the data in the reference queues. This will be the data that was written, and then
301
      -- cleared. Hence it was never read and therefore the data is left in the queues.
302
8
      clear_queue(data_queue);
303
8
      clear_queue(last_queue);
304
305
      -- Write and verify a packet. Should be the only thing remaining in the FIFO.
306
28
      run_write(4);
307
8
      check_equal(write_level, 4, line_num => 307, file_name => "tb_asynchronous_fifo.vhd");
308
309
60
      run_read(4);
310
8
      check_equal(read_valid, '0', line_num => 310, file_name => "tb_asynchronous_fifo.vhd");
311
24
      wait_for_read_to_propagate;
312
12
      check_equal(write_level, 0, line_num => 312, file_name => "tb_asynchronous_fifo.vhd");
313
314
14
    elsif run("test_drop_packet_in_same_cycle_as_write_last_should_drop_the_packet") then
315
4
      check_equal(write_level, 0, line_num => 315, file_name => "tb_asynchronous_fifo.vhd");
316
317
6
      push_axi_stream(net, write_master, tdata=>x"00", tlast=>'0');
318
4
      push_axi_stream(net, write_master, tdata=>x"00", tlast=>'1');
319
320
      -- Time the behavior of the AXI-Stream master. Appears to be a one cycle delay.
321

6
      wait until rising_edge(clk_write);
322
323
      -- The first write happens at this rising edge.
324

8
      wait until rising_edge(clk_write);
325
326
      -- Set drop signal on same cycle as the "last" write
327

2
      drop_packet <= '1';
328

8
      wait until rising_edge(clk_write);
329
330
4
      check_equal(write_level, 1, line_num => 330, file_name => "tb_asynchronous_fifo.vhd");
331
4
      check_equal(write_ready and write_valid and write_last and drop_packet, '1', line_num => 331, file_name => "tb_asynchronous_fifo.vhd");
332

8
      wait until rising_edge(clk_write);
333
334
      -- Make sure the packet was dropped
335
4
      check_equal(write_level, 0, line_num => 335, file_name => "tb_asynchronous_fifo.vhd");
336
18
      wait_for_write_to_propagate;
337
6
      check_equal(read_valid, '0', line_num => 337, file_name => "tb_asynchronous_fifo.vhd");
338
339
12
    elsif run("test_levels_full_range") then
340
      -- Check empty status
341
8
      check_equal(write_level, 0, line_num => 341, file_name => "tb_asynchronous_fifo.vhd");
342
8
      check_equal(read_level, 0, line_num => 342, file_name => "tb_asynchronous_fifo.vhd");
343
344
      -- Fill the FIFO
345

28
      run_write(depth);
346
347
      -- Check full status. Must wait a while before all writes have propagated to read side.
348
8
      check_equal(write_level, depth, line_num => 348, file_name => "tb_asynchronous_fifo.vhd");
349
37
      wait_for_write_to_propagate;
350
8
      check_equal(read_level, depth, line_num => 350, file_name => "tb_asynchronous_fifo.vhd");
351
352
      -- Empty the FIFO
353

2140
      run_read(depth);
354
355
      -- Check empty status. Must wait a while before all reads have propagated to write side.
356
8
      check_equal(read_level, 0, line_num => 356, file_name => "tb_asynchronous_fifo.vhd");
357
24
      wait_for_read_to_propagate;
358
12
      check_equal(write_level, 0, line_num => 358, file_name => "tb_asynchronous_fifo.vhd");
359
360
8
    elsif run("test_write_almost_full") then
361
8
      check_equal(write_almost_full, '0', line_num => 361, file_name => "tb_asynchronous_fifo.vhd");
362
363

28
      run_write(almost_full_level - 1);
364
8
      check_equal(write_almost_full, '0', line_num => 364, file_name => "tb_asynchronous_fifo.vhd");
365
366
28
      run_write(1);
367
8
      check_equal(write_almost_full, '1', line_num => 367, file_name => "tb_asynchronous_fifo.vhd");
368
369
36
      run_read(1);
370
24
      wait_for_read_to_propagate;
371
12
      check_equal(write_almost_full, '0', line_num => 371, file_name => "tb_asynchronous_fifo.vhd");
372
373
44
    elsif run("test_read_almost_empty") then
374
8
      check_equal(read_almost_empty, '1', line_num => 374, file_name => "tb_asynchronous_fifo.vhd");
375
376
28
      run_write(almost_empty_level);
377
8
      check_equal(read_almost_empty, '1', line_num => 377, file_name => "tb_asynchronous_fifo.vhd");
378
379
28
      run_write(1);
380
39
      wait_for_write_to_propagate;
381
8
      check_equal(read_almost_empty, '0', line_num => 381, file_name => "tb_asynchronous_fifo.vhd");
382
383
36
      run_read(1);
384
12
      check_equal(read_almost_empty, '1', line_num => 384, file_name => "tb_asynchronous_fifo.vhd");
385
    end if;
386
387

340330
    test_runner_cleanup(runner, allow_disabled_errors=>true);
388
  end process;
389
390
391
  ------------------------------------------------------------------------------
392
40
  read_status_tracking : process
393
40
    variable read_transaction : std_logic := '0';
394
  begin
395

330350
    wait until rising_edge(clk_read);
396
397
    -- If there was a read transaction last clock cycle, and we now want to read but there is no data available.
398
82582
    if read_transaction and read_ready and not read_valid then
399

9480
      has_gone_empty_times <= has_gone_empty_times + 1;
400
    end if;
401
402

493906
    read_transaction := read_ready and read_valid;
403
  end process;
404
405
406
  ------------------------------------------------------------------------------
407
40
  write_status_tracking : process
408
40
    variable write_transaction : std_logic := '0';
409
  begin
410

328742
    wait until rising_edge(clk_write);
411
412
    -- If there was a write transaction last clock cycle, and we now want to write but the fifo is full.
413
82184
    if write_transaction and write_valid and not write_ready then
414

8019
      has_gone_full_times <= has_gone_full_times + 1;
415
    end if;
416
417
164368
    write_transaction := write_ready and write_valid;
418
  end process;
419
420
421
  ------------------------------------------------------------------------------
422
40
  axi_stream_slave_inst : entity vunit_lib.axi_stream_slave
423
    generic map(
424
      slave => read_slave
425
    )
426
    port map(
427
      aclk => clk_read,
428
      tvalid => read_valid,
429
      tready => read_ready,
430
      tdata => read_data,
431
      tlast => read_last
432
    );
433
434
435
  ------------------------------------------------------------------------------
436
40
  axi_stream_master_inst : entity vunit_lib.axi_stream_master
437
    generic map(
438
      master => write_master)
439
    port map(
440
      aclk => clk_write,
441
      tvalid => write_valid,
442
      tready => write_ready,
443
      tdata => write_data,
444
      tlast => write_last
445
    );
446
447
448
  ------------------------------------------------------------------------------
449


40
  dut : entity work.asynchronous_fifo
450
    generic map (
451
      width => width,
452
      depth => depth,
453
      almost_full_level => almost_full_level,
454
      almost_empty_level => almost_empty_level,
455
      enable_packet_mode => enable_packet_mode,
456
      enable_last => enable_last,
457
      enable_drop_packet => enable_drop_packet
458
    )
459
    port map (
460
      clk_read => clk_read,
461
      read_ready   => read_ready,
462
      read_valid   => read_valid,
463
      read_data    => read_data,
464
      read_last    => read_last,
465
      --
466
      read_level => read_level,
467
      read_almost_empty => read_almost_empty,
468
      --
469
      clk_write => clk_write,
470
      write_ready => write_ready,
471
      write_valid => write_valid,
472
      write_data  => write_data,
473
      write_last  => write_last,
474
      --
475
      write_level => write_level,
476
      write_almost_full => write_almost_full,
477
      --
478
      drop_packet => drop_packet
479
    );
480
481
end architecture;