GCC Code Coverage Report
Directory: generated/vunit_out/preprocessed/ Exec Total Coverage
File: generated/vunit_out/preprocessed/fifo/tb_fifo.vhd Lines: 192 192 100.0 %
Date: 2021-06-12 04:12:08 Branches: 625 833 75.0 %

Line Branch Exec Source
1
102
-- -------------------------------------------------------------------------------------------------
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




















187
entity tb_fifo is
27
  generic (
28
17
    depth : integer;
29

153
    almost_full_level : integer := 0;
30
17
    almost_empty_level : integer := 0;
31

68
    read_stall_probability_percent : integer := 0;
32

51
    write_stall_probability_percent : integer := 0;
33




442
    enable_last : boolean := false;
34

34
    enable_packet_mode : boolean := false;
35



68
    enable_drop_packet : boolean := false;
36

51
    runner_cfg : string
37

17
  );
38

17
end entity;
39
17
40
architecture tb of tb_fifo is
41
17
42
17
  constant width : integer := 8;
43
44
17
  signal clk : std_logic := '0';
45
34
  signal level : integer;
46
47
34
  signal read_ready, read_valid, read_last, almost_empty : std_logic := '0';
48
17
  signal write_ready, write_valid, write_last, almost_full : std_logic := '0';
49
578
  signal read_data, write_data : std_logic_vector(width - 1 downto 0) := (others => '0');
50


442
  signal drop_packet : std_logic := '0';
51
52
34
  signal has_gone_full_times, has_gone_empty_times : integer := 0;
53
54
34
  constant read_stall_config : stall_config_t := new_stall_config(
55
    stall_probability => real(read_stall_probability_percent) / 100.0,
56
    min_stall_cycles => 1,
57
17
    max_stall_cycles => 4);
58
34
  constant read_slave : axi_stream_slave_t := new_axi_stream_slave(
59

153
    data_length => width,
60
    stall_config => read_stall_config,
61
17
    protocol_checker => new_axi_stream_protocol_checker(data_length => width,
62
                                                        logger => get_logger("read_slave")));
63
17
64
17
  constant write_stall_config : stall_config_t := new_stall_config(
65
    stall_probability => real(write_stall_probability_percent) / 100.0,
66
34
    min_stall_cycles => 1,
67
    max_stall_cycles => 4);
68
34
  constant write_master : axi_stream_master_t := new_axi_stream_master(
69
    data_length => width,
70
    stall_config => write_stall_config,
71
    protocol_checker => new_axi_stream_protocol_checker(data_length => width,
72
                                                        logger => get_logger("write_master")));
73
74
begin
75
76
119489
  test_runner_watchdog(runner, 1 ms);
77
119387
  clk <= not clk after 2 ns;
78
79
80
  ------------------------------------------------------------------------------
81
17
  main : process
82
83
17
    variable data_queue, last_queue, axi_stream_pop_reference_queue : queue_t := new_queue;
84
85
    variable rnd : RandomPType;
85
86








546090
    procedure run_test(read_count, write_count : natural; set_last_flag : boolean := true) is
87
9990
      variable data : std_logic_vector(write_data'range);
88
1110
      variable last, last_expected : std_logic := '0';
89
1110
      variable axi_stream_pop_reference : axi_stream_reference_t;
90
    begin
91
1110
      for write_idx in 0 to write_count - 1 loop
92
21834
        data := rnd.RandSLV(data'length);
93
21834
        last := to_sl(write_idx = write_count - 1 and set_last_flag);
94
95
44759
        push_axi_stream(net, write_master, data, last);
96
97
43668
        push(data_queue, data);
98

87336
        push(last_queue, last);
99
      end loop;
100
101
      -- Queue up reads in order to get full throughput
102
1110
      for read_idx in 0 to read_count - 1 loop
103
43018
        pop_axi_stream(net, read_slave, axi_stream_pop_reference);
104
        -- We need to keep track of the pop_reference when we read the reply later.
105
        -- Hence it is pushed to a queue.
106

86000
        push(axi_stream_pop_reference_queue, axi_stream_pop_reference);
107
      end loop;
108
109
1110
      for read_idx in 0 to read_count - 1 loop
110
21500
        axi_stream_pop_reference := pop(axi_stream_pop_reference_queue);
111
86000
        await_pop_axi_stream_reply(net, axi_stream_pop_reference, data, last);
112
113

43000
        check_equal(data, pop_std_ulogic_vector(data_queue), "read_idx " & to_string(read_idx), line_num => 113, file_name => "tb_fifo.vhd");
114
21500
        last_expected := pop(last_queue);
115
21500
        if enable_last then
116


77488
          check_equal(last, last_expected, "read_idx " & to_string(read_idx), line_num => 116, file_name => "tb_fifo.vhd");
117
        end if;
118
      end loop;
119
120
4441
      wait_until_idle(net, as_sync(write_master));
121

499760
      wait until rising_edge(clk);
122
    end procedure;
123
124

2630
    procedure run_read(count : natural) is
125
    begin
126
2630
      run_test(count, 0);
127
    end procedure;
128
129

108
    procedure run_write(count : natural) is
130
    begin
131
108
      run_test(0, count);
132
    end procedure;
133
134
8
    procedure clear_queue(queue : queue_t) is
135
4
      variable dummy : character;
136
    begin
137
5284
      while not is_empty(queue) loop
138
5288
        dummy := unsafe_pop(queue);
139
      end loop;
140
    end procedure;
141
142

10
    procedure pulse_drop_packet is
143
    begin
144

2
      drop_packet <= '1';
145

8
      wait until rising_edge(clk);
146






















































53457
      drop_packet <= '0';
147
    end procedure;
148
149
  begin
150
51
    test_runner_setup(runner, runner_cfg);
151
34
    rnd.InitSeed(rnd'instance_name);
152
153
    -- Decrease noise
154
34
    disable(get_logger("read_slave:rule 4"), warning);
155
34
    disable(get_logger("write_master:rule 4"), warning);
156
    -- Some tests leave data unread in the FIFO
157
34
    disable(get_logger("read_slave:rule 9"), error);
158
159
160
17
    if run("test_init_state") then
161
4
      check_equal(read_valid, '0', line_num => 161, file_name => "tb_fifo.vhd");
162
4
      check_equal(write_ready, '1', line_num => 162, file_name => "tb_fifo.vhd");
163
4
      check_equal(almost_full, '0', line_num => 163, file_name => "tb_fifo.vhd");
164
4
      check_equal(almost_empty, '1', line_num => 164, file_name => "tb_fifo.vhd");
165
166


6
      wait until
167
        read_valid'event or write_ready'event or almost_full'event or almost_empty'event
168
        for 1 us;
169
170
4
      check_equal(read_valid, '0', line_num => 170, file_name => "tb_fifo.vhd");
171
4
      check_equal(write_ready, '1', line_num => 171, file_name => "tb_fifo.vhd");
172
4
      check_equal(almost_full, '0', line_num => 172, file_name => "tb_fifo.vhd");
173
6
      check_equal(almost_empty, '1', line_num => 173, file_name => "tb_fifo.vhd");
174
175
15
    elsif run("test_write_faster_than_read") then
176
20014
      run_test(5000, 5000);
177

4
      check_true(is_empty(data_queue), line_num => 177, file_name => "tb_fifo.vhd");
178


6
      check_relation(has_gone_full_times > 500, "Got " & to_string(has_gone_full_times), line_num => 178, file_name => "tb_fifo.vhd", context_msg => "Expected has_gone_full_times > 500. Left is " & to_string(has_gone_full_times) & ". Right is " & to_string(500) & ".");
179
180
13
    elsif run("test_read_faster_than_write") then
181
20014
      run_test(5000, 5000);
182

4
      check_true(is_empty(data_queue), line_num => 182, file_name => "tb_fifo.vhd");
183


6
      check_relation(has_gone_empty_times > 500, "Got " & to_string(has_gone_empty_times), line_num => 183, file_name => "tb_fifo.vhd", context_msg => "Expected has_gone_empty_times > 500. Left is " & to_string(has_gone_empty_times) & ". Right is " & to_string(500) & ".");
184
185
11
    elsif run("test_packet_mode") then
186
      -- Write and immediately read a short packet
187
18
      run_test(read_count=>1, write_count=>1);
188
189
      -- Write a few words, without setting last
190
14
      run_test(read_count=>0, write_count=>3, set_last_flag=>false);
191

4
      check_relation(level > 0, line_num => 191, file_name => "tb_fifo.vhd", context_msg => "Expected level > 0. Left is " & to_string(level) & ". Right is " & to_string(0) & ".");
192
4
      check_equal(read_valid, False, line_num => 192, file_name => "tb_fifo.vhd");
193
194
      -- Writing another word, with last set, shall enable read valid.
195
      -- Note that the read_valid latency is one cycle higher in packet_mode.
196
14
      run_test(read_count=>0, write_count=>1);
197

8
      wait until rising_edge(clk);
198
4
      check_equal(read_valid, True, line_num => 198, file_name => "tb_fifo.vhd");
199
200
      -- Write further packets
201
2
      for i in 1 to 3 loop
202
42
        run_test(read_count=>0, write_count=>4);
203

24
        check_equal(read_valid, True, line_num => 203, file_name => "tb_fifo.vhd");
204
      end loop;
205
206
      -- Read and check all the packets (will only work if read_valid is set properly)
207
78
      run_read(4 * 4);
208
4
      check_equal(read_valid, False, line_num => 208, file_name => "tb_fifo.vhd");
209
4
      check_equal(level, 0, line_num => 209, file_name => "tb_fifo.vhd");
210
211
      -- Write a few words, without setting last
212
14
      run_test(read_count=>0, write_count=>3, set_last_flag=>false);
213

4
      check_relation(level > 0, line_num => 213, file_name => "tb_fifo.vhd", context_msg => "Expected level > 0. Left is " & to_string(level) & ". Right is " & to_string(0) & ".");
214
4
      check_equal(read_valid, False, line_num => 214, file_name => "tb_fifo.vhd");
215
216
      -- Writing another word, with last set, shall enable read valid.
217
      -- Note that the read_valid latency is one cycle higher in packet_mode.
218
14
      run_test(read_count=>0, write_count=>1);
219

8
      wait until rising_edge(clk);
220
6
      check_equal(read_valid, True, line_num => 220, file_name => "tb_fifo.vhd");
221
222
9
    elsif run("test_packet_mode_deep") then
223
      -- Show that the FIFO can be filled with lasts
224
225
      -- Fill the FIFO with lasts
226
2
      for i in 1 to depth loop
227

4752
        run_test(read_count=>0, write_count=>1, set_last_flag=>true);
228
      end loop;
229
4
      check_equal(read_valid, True, line_num => 229, file_name => "tb_fifo.vhd");
230
231
18
      run_read(1);
232
4
      check_equal(read_valid, True, line_num => 232, file_name => "tb_fifo.vhd");
233
234
14
      run_write(1);
235
4
      check_equal(read_valid, True, line_num => 235, file_name => "tb_fifo.vhd");
236
237

1070
      run_read(depth);
238
4
      check_equal(read_valid, False, line_num => 238, file_name => "tb_fifo.vhd");
239
240
      -- Fill the FIFO with lasts again
241
2
      for i in 1 to depth loop
242

4752
        run_test(read_count=>0, write_count=>1, set_last_flag=>true);
243
      end loop;
244
4
      check_equal(read_valid, True, line_num => 244, file_name => "tb_fifo.vhd");
245
246

1066
      run_read(depth - 1);
247
4
      check_equal(read_valid, True, line_num => 247, file_name => "tb_fifo.vhd");
248
249
18
      run_read(1);
250
6
      check_equal(read_valid, False, line_num => 250, file_name => "tb_fifo.vhd");
251
252
7
    elsif run("test_drop_packet_random_data") then
253
      -- Write and read some data, to make the pointers advance a little.
254
      -- Note that this will set write_last on the last write, and some data will be left unread.
255

542
      run_test(read_count=>depth / 2, write_count=>depth * 3 / 4);
256
4
      check_equal(level, depth / 4, line_num => 256, file_name => "tb_fifo.vhd");
257
258
      -- Write some data without setting last, simulating a packet in progress.
259
      -- Drop the packet, and then read out the remainder of the previous packet.
260
      -- Note that the counts chosen will make the pointers wraparound.
261

14
      run_test(read_count=>0, write_count=>depth / 2, set_last_flag=>false);
262
8
      pulse_drop_packet;
263

278
      run_read(depth / 4);
264
265
4
      check_equal(read_valid, '0', line_num => 265, file_name => "tb_fifo.vhd");
266
4
      check_equal(level, 0, line_num => 266, file_name => "tb_fifo.vhd");
267
268
      -- Clear the data in the reference queues. This will be the data that was written, and then
269
      -- cleared. Hence it was never read and therefore the data is left in the queues.
270
4
      clear_queue(data_queue);
271
4
      clear_queue(last_queue);
272
273
      -- Write and verify a packet. Should be the only thing remaining in the FIFO.
274
14
      run_write(4);
275
4
      check_equal(level, 4, line_num => 275, file_name => "tb_fifo.vhd");
276
277
30
      run_read(4);
278
4
      check_equal(read_valid, '0', line_num => 278, file_name => "tb_fifo.vhd");
279
6
      check_equal(level, 0, line_num => 279, file_name => "tb_fifo.vhd");
280
281
5
    elsif run("test_drop_packet_in_same_cycle_as_write_last_should_drop_the_packet") then
282
2
      check_equal(level, 0, line_num => 282, file_name => "tb_fifo.vhd");
283
284
3
      push_axi_stream(net, write_master, tdata=>x"00", tlast=>'0');
285
2
      push_axi_stream(net, write_master, tdata=>x"00", tlast=>'1');
286
287
      -- Time the behavior of the AXI-Stream master. Appears to be a one cycle delay.
288

3
      wait until rising_edge(clk);
289
290
      -- The first write happens at this rising edge.
291

4
      wait until rising_edge(clk);
292
293
      -- Set drop signal on same cycle as the "last" write
294

1
      drop_packet <= '1';
295

4
      wait until rising_edge(clk);
296
297
2
      check_equal(level, 1, line_num => 297, file_name => "tb_fifo.vhd");
298
2
      check_equal(write_ready and write_valid and write_last and drop_packet, '1', line_num => 298, file_name => "tb_fifo.vhd");
299

4
      wait until rising_edge(clk);
300
301
      -- Make sure the packet was dropped
302
2
      check_equal(level, 0, line_num => 302, file_name => "tb_fifo.vhd");
303
2
      check_equal(read_valid, '0', line_num => 303, file_name => "tb_fifo.vhd");
304

4
      wait until rising_edge(clk);
305
3
      check_equal(read_valid, '0', line_num => 305, file_name => "tb_fifo.vhd");
306
307
4
    elsif run("test_almost_full") then
308
4
      check_equal(almost_full, '0', line_num => 308, file_name => "tb_fifo.vhd");
309
310

14
      run_write(almost_full_level - 1);
311
4
      check_equal(almost_full, '0', line_num => 311, file_name => "tb_fifo.vhd");
312
313
14
      run_write(1);
314
4
      check_equal(almost_full, '1', line_num => 314, file_name => "tb_fifo.vhd");
315
316
18
      run_read(1);
317
6
      check_equal(almost_full, '0', line_num => 317, file_name => "tb_fifo.vhd");
318
319
19
    elsif run("test_almost_empty") then
320
4
      check_equal(almost_empty, '1', line_num => 320, file_name => "tb_fifo.vhd");
321
322

14
      run_write(almost_empty_level);
323
4
      check_equal(almost_empty, '1', line_num => 323, file_name => "tb_fifo.vhd");
324
325
14
      run_write(1);
326
2
      if almost_empty_level = 0 then
327
        -- almost_empty is updated one cycle later, since write must propagate into RAM before
328
        -- read data is valid
329

4
        wait until rising_edge(clk);
330
      end if;
331
4
      check_equal(almost_empty, '0', line_num => 331, file_name => "tb_fifo.vhd");
332
333
18
      run_read(1);
334
6
      check_equal(almost_empty, '1', line_num => 334, file_name => "tb_fifo.vhd");
335
    end if;
336
337

243596
    test_runner_cleanup(runner, allow_disabled_errors=>true);
338
  end process;
339
340
341
  ------------------------------------------------------------------------------
342
17
  status_tracking : process
343
17
    variable read_transaction, write_transaction : std_logic := '0';
344
  begin
345

238738
    wait until rising_edge(clk);
346
347
    -- If there was a read transaction last clock cycle, and we now want to read but there is no
348
    -- data available.
349
59684
    if read_transaction and read_ready and not read_valid then
350

8958
      has_gone_empty_times <= has_gone_empty_times + 1;
351
    end if;
352
353
    -- If there was a write transaction last clock cycle, and we now want to write but the fifo
354
    -- is full.
355
59684
    if write_transaction and write_valid and not write_ready then
356

8225
      has_gone_full_times <= has_gone_full_times + 1;
357
    end if;
358
359
59684
    read_transaction := read_ready and read_valid;
360
119368
    write_transaction := write_ready and write_valid;
361
  end process;
362
363
364
  ------------------------------------------------------------------------------
365
17
  axi_stream_slave_inst : entity vunit_lib.axi_stream_slave
366
    generic map(
367
      slave => read_slave
368
    )
369
    port map(
370
      aclk => clk,
371
      tvalid => read_valid,
372
      tready => read_ready,
373
      tdata => read_data,
374
      tlast => read_last
375
    );
376
377
378
  ------------------------------------------------------------------------------
379
17
  axi_stream_master_inst : entity vunit_lib.axi_stream_master
380
    generic map(
381
      master => write_master)
382
    port map(
383
      aclk => clk,
384
      tvalid => write_valid,
385
      tready => write_ready,
386
      tdata => write_data,
387
      tlast => write_last
388
    );
389
390
391
  ------------------------------------------------------------------------------
392



17
  dut : entity work.fifo
393
    generic map (
394
      width => width,
395
      depth => depth,
396
      almost_full_level => almost_full_level,
397
      almost_empty_level => almost_empty_level,
398
      enable_last => enable_last,
399
      enable_packet_mode => enable_packet_mode,
400
      enable_drop_packet => enable_drop_packet
401
    )
402
    port map (
403
      clk => clk,
404
      level => level,
405
406
      read_ready => read_ready,
407
      read_valid => read_valid,
408
      read_data => read_data,
409
      read_last => read_last,
410
      almost_empty => almost_empty,
411
412
      write_ready => write_ready,
413
      write_valid => write_valid,
414
      write_data => write_data,
415
      write_last => write_last,
416
      almost_full => almost_full,
417
      drop_packet => drop_packet
418
    );
419
420
end architecture;