1 |
5 |
sergeykhbr |
-----------------------------------------------------------------------------
|
2 |
|
|
--! @file
|
3 |
|
|
--! @copyright Copyright 2016 GNSS Sensor Ltd. All right reserved.
|
4 |
|
|
--! @author Sergey Khabarov - sergeykhbr@gmail.com
|
5 |
|
|
--! @details Implementation of the axictrl device.
|
6 |
|
|
------------------------------------------------------------------------------
|
7 |
|
|
|
8 |
|
|
library ieee;
|
9 |
|
|
use ieee.std_logic_1164.all;
|
10 |
|
|
library commonlib;
|
11 |
|
|
use commonlib.types_common.all;
|
12 |
|
|
library ambalib;
|
13 |
|
|
use ambalib.types_amba4.all;
|
14 |
|
|
|
15 |
|
|
--! @brief AXI (NASTI) bus controller.
|
16 |
|
|
--! @details Simplified version with the hardcoded priorities to bus access.
|
17 |
|
|
--! Lower master index has a higher priority.
|
18 |
|
|
--! @todo Round-robin algorithm for the master selection.
|
19 |
|
|
entity axictrl is
|
20 |
|
|
generic (
|
21 |
|
|
watchdog_memop : integer := 0
|
22 |
|
|
);
|
23 |
|
|
port (
|
24 |
|
|
i_clk : in std_logic;
|
25 |
|
|
i_nrst : in std_logic;
|
26 |
|
|
i_slvcfg : in nasti_slave_cfg_vector;
|
27 |
|
|
i_slvo : in nasti_slaves_out_vector;
|
28 |
|
|
i_msto : in nasti_master_out_vector;
|
29 |
|
|
o_slvi : out nasti_slave_in_vector;
|
30 |
|
|
o_msti : out nasti_master_in_vector;
|
31 |
|
|
o_miss_irq : out std_logic;
|
32 |
|
|
o_miss_addr : out std_logic_vector(CFG_NASTI_ADDR_BITS-1 downto 0);
|
33 |
|
|
o_bus_util_w : out std_logic_vector(CFG_NASTI_MASTER_TOTAL-1 downto 0);
|
34 |
|
|
o_bus_util_r : out std_logic_vector(CFG_NASTI_MASTER_TOTAL-1 downto 0)
|
35 |
|
|
);
|
36 |
|
|
end;
|
37 |
|
|
|
38 |
|
|
architecture arch_axictrl of axictrl is
|
39 |
|
|
|
40 |
|
|
constant MISS_ACCESS_SLAVE : nasti_slave_out_type := (
|
41 |
|
|
'1', '1', '0', NASTI_RESP_EXOKAY,
|
42 |
|
|
(others=>'0'), '0', '1', '0', NASTI_RESP_EXOKAY, (others=>'1'),
|
43 |
|
|
'1', (others=>'0'), '0');
|
44 |
|
|
|
45 |
|
|
type nasti_master_out_vector_miss is array (0 to CFG_NASTI_MASTER_TOTAL)
|
46 |
|
|
of nasti_master_out_type;
|
47 |
|
|
|
48 |
|
|
type nasti_master_in_vector_miss is array (0 to CFG_NASTI_MASTER_TOTAL)
|
49 |
|
|
of nasti_master_in_type;
|
50 |
|
|
|
51 |
|
|
type nasti_slave_out_vector_miss is array (0 to CFG_NASTI_SLAVES_TOTAL)
|
52 |
|
|
of nasti_slave_out_type;
|
53 |
|
|
|
54 |
|
|
type nasti_slave_in_vector_miss is array (0 to CFG_NASTI_SLAVES_TOTAL)
|
55 |
|
|
of nasti_slave_in_type;
|
56 |
|
|
|
57 |
|
|
type slave_selector_type is array (0 to CFG_NASTI_MASTER_TOTAL-1)
|
58 |
|
|
of integer range 0 to CFG_NASTI_SLAVES_TOTAL;
|
59 |
|
|
|
60 |
|
|
type reg_type is record
|
61 |
|
|
w_busy : std_logic;
|
62 |
|
|
w_mst_idx : integer range 0 to CFG_NASTI_MASTER_TOTAL;
|
63 |
|
|
w_slv_idx : integer range 0 to CFG_NASTI_SLAVES_TOTAL; -- +1 miss access
|
64 |
|
|
r_busy : std_logic;
|
65 |
|
|
r_mst_idx : integer range 0 to CFG_NASTI_MASTER_TOTAL;
|
66 |
|
|
r_slv_idx : integer range 0 to CFG_NASTI_SLAVES_TOTAL; -- +1 miss access
|
67 |
|
|
b_busy : std_logic;
|
68 |
|
|
b_mst_idx : integer range 0 to CFG_NASTI_MASTER_TOTAL;
|
69 |
|
|
b_slv_idx : integer range 0 to CFG_NASTI_SLAVES_TOTAL; -- +1 miss access
|
70 |
|
|
|
71 |
|
|
miss_addr : std_logic_vector(CFG_NASTI_ADDR_BITS-1 downto 0);
|
72 |
|
|
end record;
|
73 |
|
|
|
74 |
|
|
signal rin, r : reg_type;
|
75 |
|
|
begin
|
76 |
|
|
|
77 |
|
|
comblogic : process(i_nrst, i_slvcfg, i_msto, i_slvo, r)
|
78 |
|
|
variable v : reg_type;
|
79 |
|
|
variable missaccess : std_logic;
|
80 |
|
|
variable ar_mst_idx : integer range 0 to CFG_NASTI_MASTER_TOTAL;
|
81 |
|
|
variable aw_mst_idx : integer range 0 to CFG_NASTI_MASTER_TOTAL;
|
82 |
|
|
variable ar_slv_idx : integer range 0 to CFG_NASTI_SLAVES_TOTAL; -- +1 miss access
|
83 |
|
|
variable aw_slv_idx : integer range 0 to CFG_NASTI_SLAVES_TOTAL; -- +1 miss access
|
84 |
|
|
variable vmsto : nasti_master_out_vector_miss;
|
85 |
|
|
variable vmsti : nasti_master_in_vector_miss;
|
86 |
|
|
variable vslvi : nasti_slave_in_vector_miss;
|
87 |
|
|
variable vslvo : nasti_slave_out_vector_miss;
|
88 |
|
|
variable aw_fire : std_logic;
|
89 |
|
|
variable ar_fire : std_logic;
|
90 |
|
|
variable w_fire : std_logic;
|
91 |
|
|
variable w_available : std_logic;
|
92 |
|
|
variable r_fire : std_logic;
|
93 |
|
|
variable r_available : std_logic;
|
94 |
|
|
variable b_fire : std_logic;
|
95 |
|
|
variable b_available : std_logic;
|
96 |
|
|
-- Bus statistic signals
|
97 |
|
|
variable wb_bus_util_w : std_logic_vector(CFG_NASTI_MASTER_TOTAL downto 0);
|
98 |
|
|
variable wb_bus_util_r : std_logic_vector(CFG_NASTI_MASTER_TOTAL downto 0);
|
99 |
|
|
|
100 |
|
|
begin
|
101 |
|
|
|
102 |
|
|
v := r;
|
103 |
|
|
|
104 |
|
|
missaccess := '0';
|
105 |
|
|
wb_bus_util_w := (others => '0');
|
106 |
|
|
wb_bus_util_r := (others => '0');
|
107 |
|
|
ar_mst_idx := CFG_NASTI_MASTER_TOTAL; -- Default master is empty master
|
108 |
|
|
aw_mst_idx := CFG_NASTI_MASTER_TOTAL; -- Default master is empty master
|
109 |
|
|
ar_slv_idx := CFG_NASTI_SLAVES_TOTAL; -- miss access index
|
110 |
|
|
aw_slv_idx := CFG_NASTI_SLAVES_TOTAL; -- miss access index
|
111 |
|
|
|
112 |
|
|
for n in 0 to CFG_NASTI_MASTER_TOTAL-1 loop
|
113 |
|
|
vmsto(n) := i_msto(n);
|
114 |
|
|
vmsti(n) := nasti_master_in_none;
|
115 |
|
|
end loop;
|
116 |
|
|
vmsto(CFG_NASTI_MASTER_TOTAL) := nasti_master_out_none;
|
117 |
|
|
vmsti(CFG_NASTI_MASTER_TOTAL) := nasti_master_in_none;
|
118 |
|
|
for k in 0 to CFG_NASTI_SLAVES_TOTAL-1 loop
|
119 |
|
|
vslvo(k) := i_slvo(k);
|
120 |
|
|
vslvi(k) := nasti_slave_in_none;
|
121 |
|
|
end loop;
|
122 |
|
|
vslvo(CFG_NASTI_SLAVES_TOTAL) := MISS_ACCESS_SLAVE;
|
123 |
|
|
vslvi(CFG_NASTI_SLAVES_TOTAL) := nasti_slave_in_none;
|
124 |
|
|
|
125 |
|
|
-- Select master bus:
|
126 |
|
|
for n in 0 to CFG_NASTI_MASTER_TOTAL-1 loop
|
127 |
|
|
if i_msto(n).ar_valid = '1' then
|
128 |
|
|
ar_mst_idx := n;
|
129 |
|
|
end if;
|
130 |
|
|
if i_msto(n).aw_valid = '1' then
|
131 |
|
|
aw_mst_idx := n;
|
132 |
|
|
end if;
|
133 |
|
|
end loop;
|
134 |
|
|
|
135 |
|
|
-- Adress Read/Address Write channels
|
136 |
|
|
for k in 0 to CFG_NASTI_SLAVES_TOTAL-1 loop
|
137 |
|
|
if i_slvcfg(k).xmask /= X"00000" and
|
138 |
|
|
(vmsto(ar_mst_idx).ar_bits.addr(CFG_NASTI_ADDR_BITS-1 downto 12)
|
139 |
|
|
and i_slvcfg(k).xmask) = i_slvcfg(k).xaddr then
|
140 |
|
|
ar_slv_idx := k;
|
141 |
|
|
end if;
|
142 |
|
|
if i_slvcfg(k).xmask /= X"00000" and
|
143 |
|
|
(vmsto(aw_mst_idx).aw_bits.addr(CFG_NASTI_ADDR_BITS-1 downto 12)
|
144 |
|
|
and i_slvcfg(k).xmask) = i_slvcfg(k).xaddr then
|
145 |
|
|
aw_slv_idx := k;
|
146 |
|
|
end if;
|
147 |
|
|
end loop;
|
148 |
|
|
|
149 |
|
|
-- Statistic
|
150 |
|
|
wb_bus_util_w(r.w_mst_idx) := r.w_busy;
|
151 |
|
|
wb_bus_util_r(r.r_mst_idx) := r.r_busy;
|
152 |
|
|
|
153 |
|
|
-- Pipeline
|
154 |
|
|
--! @todo It is possible to implement inpendent channels of same type for each
|
155 |
|
|
--! master slot and process transactions to separate slaves simultaneously.
|
156 |
|
|
--! I think it will be usefull feature but doesn't increase CPI of
|
157 |
|
|
--! single core.
|
158 |
|
|
|
159 |
|
|
-- Read Channel:
|
160 |
|
|
r_fire := vmsto(r.r_mst_idx).r_ready and vslvo(r.r_slv_idx).r_valid and vslvo(r.r_slv_idx).r_last;
|
161 |
|
|
r_available := not r.r_busy or (r.r_busy and r_fire);
|
162 |
|
|
ar_fire := vmsto(ar_mst_idx).ar_valid and vslvo(ar_slv_idx).ar_ready and r_available;
|
163 |
|
|
-- Write channel:
|
164 |
|
|
w_fire := vmsto(r.w_mst_idx).w_valid and vslvo(r.w_slv_idx).w_ready and vmsto(r.w_mst_idx).w_last;
|
165 |
|
|
w_available := not r.w_busy or (r.w_busy and w_fire);
|
166 |
|
|
aw_fire := vmsto(aw_mst_idx).aw_valid and vslvo(aw_slv_idx).aw_ready and w_available;
|
167 |
|
|
|
168 |
|
|
vmsti(ar_mst_idx).ar_ready := vslvo(ar_slv_idx).ar_ready and r_available;
|
169 |
|
|
vslvi(ar_slv_idx).ar_valid := vmsto(ar_mst_idx).ar_valid and r_available;
|
170 |
|
|
vslvi(ar_slv_idx).ar_bits := vmsto(ar_mst_idx).ar_bits;
|
171 |
|
|
vslvi(ar_slv_idx).ar_id := vmsto(ar_mst_idx).ar_id;
|
172 |
|
|
vslvi(ar_slv_idx).ar_user := vmsto(ar_mst_idx).ar_user;
|
173 |
|
|
|
174 |
|
|
vmsti(aw_mst_idx).aw_ready := vslvo(aw_slv_idx).aw_ready and w_available;
|
175 |
|
|
vslvi(aw_slv_idx).aw_valid := vmsto(aw_mst_idx).aw_valid and w_available;
|
176 |
|
|
vslvi(aw_slv_idx).aw_bits := vmsto(aw_mst_idx).aw_bits;
|
177 |
|
|
vslvi(aw_slv_idx).aw_id := vmsto(aw_mst_idx).aw_id;
|
178 |
|
|
vslvi(aw_slv_idx).aw_user := vmsto(aw_mst_idx).aw_user;
|
179 |
|
|
|
180 |
|
|
if (w_available and aw_fire) = '1' then
|
181 |
|
|
v.w_busy := '1';
|
182 |
|
|
v.w_slv_idx := aw_slv_idx;
|
183 |
|
|
v.w_mst_idx := aw_mst_idx;
|
184 |
|
|
end if;
|
185 |
|
|
|
186 |
|
|
vmsti(r.w_mst_idx).w_ready := vslvo(r.w_slv_idx).w_ready;
|
187 |
|
|
vslvi(r.w_slv_idx).w_valid := vmsto(r.w_mst_idx).w_valid;
|
188 |
|
|
vslvi(r.w_slv_idx).w_data := vmsto(r.w_mst_idx).w_data;
|
189 |
|
|
vslvi(r.w_slv_idx).w_last := vmsto(r.w_mst_idx).w_last;
|
190 |
|
|
vslvi(r.w_slv_idx).w_strb := vmsto(r.w_mst_idx).w_strb;
|
191 |
|
|
vslvi(r.w_slv_idx).w_user := vmsto(r.w_mst_idx).w_user;
|
192 |
|
|
|
193 |
|
|
-- Write Handshake channel:
|
194 |
|
|
b_fire := vmsto(r.b_mst_idx).b_ready and vslvo(r.b_slv_idx).b_valid;
|
195 |
|
|
b_available := not r.b_busy or (r.b_busy and b_fire);
|
196 |
|
|
if (b_available and w_fire) = '1' then
|
197 |
|
|
v.w_busy := '0';
|
198 |
|
|
v.b_busy := '1';
|
199 |
|
|
v.b_slv_idx := r.w_slv_idx;
|
200 |
|
|
v.b_mst_idx := r.w_mst_idx;
|
201 |
|
|
end if;
|
202 |
|
|
if b_fire = '1' then
|
203 |
|
|
v.b_busy := w_fire;
|
204 |
|
|
end if;
|
205 |
|
|
|
206 |
|
|
vmsti(r.b_mst_idx).b_valid := vslvo(r.b_slv_idx).b_valid;
|
207 |
|
|
vmsti(r.b_mst_idx).b_resp := vslvo(r.b_slv_idx).b_resp;
|
208 |
|
|
vmsti(r.b_mst_idx).b_id := vslvo(r.b_slv_idx).b_id;
|
209 |
|
|
vmsti(r.b_mst_idx).b_user := vslvo(r.b_slv_idx).b_user;
|
210 |
|
|
vslvi(r.b_slv_idx).b_ready := vmsto(r.b_mst_idx).b_ready;
|
211 |
|
|
|
212 |
|
|
if (r_available and ar_fire) = '1' then
|
213 |
|
|
v.r_busy := '1';
|
214 |
|
|
v.r_slv_idx := ar_slv_idx;
|
215 |
|
|
v.r_mst_idx := ar_mst_idx;
|
216 |
|
|
end if;
|
217 |
|
|
if r_fire = '1' then
|
218 |
|
|
v.r_busy := ar_fire;
|
219 |
|
|
end if;
|
220 |
|
|
|
221 |
|
|
vmsti(r.r_mst_idx).r_valid := vslvo(r.r_slv_idx).r_valid;
|
222 |
|
|
vmsti(r.r_mst_idx).r_resp := vslvo(r.r_slv_idx).r_resp;
|
223 |
|
|
vmsti(r.r_mst_idx).r_data := vslvo(r.r_slv_idx).r_data;
|
224 |
|
|
vmsti(r.r_mst_idx).r_last := vslvo(r.r_slv_idx).r_last;
|
225 |
|
|
vmsti(r.r_mst_idx).r_id := vslvo(r.r_slv_idx).r_id;
|
226 |
|
|
vmsti(r.r_mst_idx).r_user := vslvo(r.r_slv_idx).r_user;
|
227 |
|
|
vslvi(r.r_slv_idx).r_ready := vmsto(r.r_mst_idx).r_ready;
|
228 |
|
|
|
229 |
|
|
if aw_fire = '1' and aw_slv_idx = CFG_NASTI_SLAVES_TOTAL then
|
230 |
|
|
missaccess := '1';
|
231 |
|
|
v.miss_addr := vmsto(aw_mst_idx).aw_bits.addr;
|
232 |
|
|
end if;
|
233 |
|
|
if ar_fire = '1' and ar_slv_idx = CFG_NASTI_SLAVES_TOTAL then
|
234 |
|
|
missaccess := '1';
|
235 |
|
|
v.miss_addr := vmsto(ar_mst_idx).ar_bits.addr;
|
236 |
|
|
end if;
|
237 |
|
|
|
238 |
|
|
if i_nrst = '0' then
|
239 |
|
|
v.w_busy := '0';
|
240 |
|
|
v.w_mst_idx := CFG_NASTI_MASTER_TOTAL;
|
241 |
|
|
v.w_slv_idx := CFG_NASTI_SLAVES_TOTAL;
|
242 |
|
|
v.r_busy := '0';
|
243 |
|
|
v.r_mst_idx := CFG_NASTI_MASTER_TOTAL;
|
244 |
|
|
v.r_slv_idx := CFG_NASTI_SLAVES_TOTAL;
|
245 |
|
|
v.b_busy := '0';
|
246 |
|
|
v.b_mst_idx := CFG_NASTI_MASTER_TOTAL;
|
247 |
|
|
v.b_slv_idx := CFG_NASTI_SLAVES_TOTAL;
|
248 |
|
|
v.miss_addr := (others => '0');
|
249 |
|
|
end if;
|
250 |
|
|
|
251 |
|
|
rin <= v;
|
252 |
|
|
|
253 |
|
|
for k in 0 to CFG_NASTI_MASTER_TOTAL-1 loop
|
254 |
|
|
o_msti(k) <= vmsti(k);
|
255 |
|
|
end loop;
|
256 |
|
|
for k in 0 to CFG_NASTI_SLAVES_TOTAL-1 loop
|
257 |
|
|
o_slvi(k) <= vslvi(k);
|
258 |
|
|
end loop;
|
259 |
|
|
o_miss_irq <= missaccess;
|
260 |
|
|
o_miss_addr <= r.miss_addr;
|
261 |
|
|
o_bus_util_w <= wb_bus_util_w(CFG_NASTI_MASTER_TOTAL-1 downto 0);
|
262 |
|
|
o_bus_util_r <= wb_bus_util_r(CFG_NASTI_MASTER_TOTAL-1 downto 0);
|
263 |
|
|
end process;
|
264 |
|
|
|
265 |
|
|
reg0 : process(i_clk) begin
|
266 |
|
|
if rising_edge(i_clk) then
|
267 |
|
|
r <= rin;
|
268 |
|
|
end if;
|
269 |
|
|
end process;
|
270 |
|
|
end;
|