GCC Code Coverage Report
Directory: generated/vunit_out/preprocessed/ Exec Total Coverage
File: generated/vunit_out/preprocessed/axi/axi_simple_read_crossbar.vhd Lines: 35 35 100.0 %
Date: 2021-06-12 04:12:08 Branches: 147 175 84.0 %

Line Branch Exec Source
1
24
-- -------------------------------------------------------------------------------------------------
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
-- Simple N-to-1 crossbar for connecting multiple AXI read masters to one port.
9
--
10
-- Uses round-robin scheduling for the inputs. It is simple in the sense that
11
-- there is no separation of AXI AR and R channels with separate queues.
12
-- After a channel has been selected for address transaction, the crossbar is
13
-- locked on that channel until it has finished it's read response transactions.
14
-- After that the crossbar moves on to do a new address transaction on, possibly,
15
-- another channel.
16
--
17
-- Due to this it has a very small logic footprint but will never reach full
18
-- utilization of the data channels. In order to get higher throughput, further address transactions
19
-- should be queued up to the slave while a read response burst is running.
20
-- -------------------------------------------------------------------------------------------------
21
22
library ieee;
23
use ieee.std_logic_1164.all;
24
25
library axi;
26
use axi.axi_pkg.all;
27
28
library common;
29
use common.types_pkg.all;
30
31
32









653618
entity axi_simple_read_crossbar is
33
  generic(
34
    num_inputs : integer
35
  );
36
  port(
37
    clk : in std_logic;
38
    --
39
    input_ports_m2s : in axi_read_m2s_vec_t(0 to num_inputs - 1) := (others => axi_read_m2s_init);
40
    input_ports_s2m : out axi_read_s2m_vec_t(0 to num_inputs - 1) := (others => axi_read_s2m_init);
41
    --
42
    output_m2s : out axi_read_m2s_t := axi_read_m2s_init;
43
    output_s2m : in axi_read_s2m_t := axi_read_s2m_init
44
  );
45
end entity;
46
47
architecture a of axi_simple_read_crossbar is
48
49
4
  constant no_input_selected : integer := input_ports_m2s'high + 1;
50
51
  -- Max num outstanding address transactions
52
4
  constant max_addr_fifo_depth : integer := 128;
53
54
4
  signal input_select : integer range 0 to no_input_selected := no_input_selected;
55
4
  signal input_select_turn_counter : integer range input_ports_m2s'range := 0;
56
57
  type state_t is (wait_for_ar_valid, wait_for_ar_done, wait_for_r_done);
58
8
  signal state : state_t := wait_for_ar_valid;
59
60
begin
61
62
  ----------------------------------------------------------------------------
63
4
  select_input : process
64
4
    variable ar_done, r_done : std_logic;
65
4
    variable num_outstanding_addr_transactions : integer range 0 to max_addr_fifo_depth := 0;
66
  begin
67
643322
    wait until rising_edge(clk);
68
69
160830
    ar_done := output_s2m.ar.ready and output_m2s.ar.valid;
70
160830
    r_done := output_m2s.r.ready and output_s2m.r.valid and output_s2m.r.last;
71
72
160830
    num_outstanding_addr_transactions := num_outstanding_addr_transactions
73
      + to_int(ar_done) - to_int(r_done);
74
75
160830
    case state is
76
      when wait_for_ar_valid =>
77
        -- Rotate around to find an input that requests a transaction
78
122168
        if input_ports_m2s(input_select_turn_counter).ar.valid then
79
2000
          input_select <= input_select_turn_counter;
80
2000
          state <= wait_for_ar_done;
81
        end if;
82
83
122168
        if input_select_turn_counter = input_ports_m2s'high then
84
30542
          input_select_turn_counter <= 0;
85
        else
86
122168
          input_select_turn_counter <= input_select_turn_counter + 1;
87
        end if;
88
89
      when wait_for_ar_done =>
90
        -- Wait for address transaction so that num_outstanding_addr_transactions
91
        -- is updated and this input actually gets to do a transaction
92
2860
        if ar_done then
93
2860
          state <= wait_for_r_done;
94
        end if;
95
96
      when wait_for_r_done =>
97
        -- Wait until all of this input's negotiated bursts are done, and then
98
        -- go back to choose a new input
99
35802
        if num_outstanding_addr_transactions = 0 then
100
2000
          input_select <= no_input_selected;
101
394857
          state <= wait_for_ar_valid;
102
        end if;
103
104
    end case;
105
  end process;
106
107
108
  ----------------------------------------------------------------------------
109
5540
  assign_bus : process(all)
110
  begin
111











14858991
    output_m2s.ar <= (
112
      valid => '0',
113
      burst => (others => '-'),
114
      others => (others => '-')
115
    );
116

73197
    output_m2s.r <= (ready => '0');
117
118
73197
    for idx in input_ports_m2s'range loop
119
      -- Default assignment of all members. Non-selected inputs will be zero'd out below.
120








45382140
      input_ports_s2m(idx) <= output_s2m;
121
122
292788
      if idx = input_select then
123
        -- Assign whole M2S bus from the selected input
124









2094366
        output_m2s <= input_ports_m2s(idx);
125
      else
126
        -- Non-selected inputs shall have their control signal zero'd out.
127
        -- Other members of the bus (r.data, etc.) can still be assigned.
128

272255
        input_ports_s2m(idx).ar.ready <= '0';
129


292792
        input_ports_s2m(idx).r.valid <= '0';
130
      end if;
131
    end loop;
132
  end process;
133
134
end architecture;