GCC Code Coverage Report
Directory: generated/vunit_out/preprocessed/ Exec Total Coverage
File: generated/vunit_out/preprocessed/axi/axi_simple_write_crossbar.vhd Lines: 37 37 100.0 %
Date: 2021-06-12 04:12:08 Branches: 195 235 83.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 write 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 AW/W/B 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 write (W) transactions and write
14
-- response (B) transaction. After that the crossbar moves on to do a new address transaction
15
-- on, possibly, 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 reach higher throughput there needs to be
19
-- separation of the channels so that further AW transactions are queued up while other W and B
20
-- transactions are running, and further W transactions are performed while waiting for other
21
-- B transactions.
22
-- -------------------------------------------------------------------------------------------------
23
24
library ieee;
25
use ieee.std_logic_1164.all;
26
27
library axi;
28
use axi.axi_pkg.all;
29
30
library common;
31
use common.types_pkg.all;
32
33
34











655218
entity axi_simple_write_crossbar is
35
  generic(
36
    num_inputs : integer
37
  );
38
  port(
39
    clk : in std_logic;
40
    --
41
    input_ports_m2s : in axi_write_m2s_vec_t(0 to num_inputs - 1) := (others => axi_write_m2s_init);
42
    input_ports_s2m : out axi_write_s2m_vec_t(0 to num_inputs - 1) := (others => axi_write_s2m_init);
43
    --
44
    output_m2s : out axi_write_m2s_t := axi_write_m2s_init;
45
    output_s2m : in axi_write_s2m_t := axi_write_s2m_init
46
  );
47
end entity;
48
49
architecture a of axi_simple_write_crossbar is
50
51
4
  constant no_input_selected : integer := input_ports_m2s'high + 1;
52
53
  -- Max num outstanding address transactions
54
4
  constant max_addr_fifo_depth : integer := 128;
55
56
4
  signal input_select : integer range 0 to no_input_selected := no_input_selected;
57
4
  signal input_select_turn_counter : integer range input_ports_s2m'range := 0;
58
59
  type state_t is (wait_for_aw_valid, wait_for_aw_done, wait_for_b_done);
60
8
  signal state : state_t := wait_for_aw_valid;
61
62
begin
63
64
  ----------------------------------------------------------------------------
65
4
  select_input : process
66
4
    variable aw_done, b_done : std_logic;
67
4
    variable num_outstanding_addr_transactions : integer range 0 to max_addr_fifo_depth := 0;
68
  begin
69
643322
    wait until rising_edge(clk);
70
71
160830
    aw_done := output_s2m.aw.ready and output_m2s.aw.valid;
72
160830
    b_done := output_m2s.b.ready and output_s2m.b.valid;
73
74
160830
    num_outstanding_addr_transactions := num_outstanding_addr_transactions
75
      + to_int(aw_done) - to_int(b_done);
76
77
160830
    case state is
78
      when wait_for_aw_valid =>
79
        -- Rotate around to find an input that requests a transaction
80
119476
        if input_ports_m2s(input_select_turn_counter).aw.valid then
81
2000
          input_select <= input_select_turn_counter;
82
2000
          state <= wait_for_aw_done;
83
        end if;
84
85
119476
        if input_select_turn_counter = input_ports_m2s'high then
86
29866
          input_select_turn_counter <= 0;
87
        else
88
119476
          input_select_turn_counter <= input_select_turn_counter + 1;
89
        end if;
90
91
      when wait_for_aw_done =>
92
        -- Wait for address transaction so that num_outstanding_addr_transactions
93
        -- is updated and this input actually gets to do a transaction
94
2832
        if aw_done then
95
2832
          state <= wait_for_b_done;
96
        end if;
97
98
      when wait_for_b_done =>
99
        -- Wait until all of this input's negotiated bursts are done, and then
100
        -- go back to choose a new input
101
38522
        if num_outstanding_addr_transactions = 0 then
102
2000
          input_select <= no_input_selected;
103
400523
          state <= wait_for_aw_valid;
104
        end if;
105
106
    end case;
107
  end process;
108
109
110
  ----------------------------------------------------------------------------
111
7012
  assign_bus : process(all)
112
  begin
113











16009189
    output_m2s.aw <= (
114
      valid => '0',
115
      burst => (others => '-'),
116
      others => (others => '-')
117
    );
118








26576831
    output_m2s.w <= (
119
      valid => '0',
120
      last => '-',
121
      id=> (others => '-'),
122
      others => (others => '-')
123
    );
124

78863
    output_m2s.b <= (ready => '0');
125
126
78863
    for idx in input_ports_s2m'range loop
127
      -- Default assignment of all members. Non-selected inputs will be zero'd out below.
128






8517204
      input_ports_s2m(idx) <= output_s2m;
129
130
315452
      if idx = input_select then
131
        -- Assign whole M2S bus from the selected input
132
















7328610
        output_m2s <= input_ports_m2s(idx);
133
      else
134
        -- Non-selected inputs shall have their control signal zero'd out.
135
        -- Other members of the bus (b.resp, etc.) can still be assigned.
136

288309
        input_ports_s2m(idx).aw.ready <= '0';
137

288309
        input_ports_s2m(idx).w.ready <= '0';
138

315456
        input_ports_s2m(idx).b.valid <= '0';
139
      end if;
140
    end loop;
141
  end process;
142
143
end architecture;