tsfpga VHDL coverage


Directory: generated/vunit_out/preprocessed/
File: generated/vunit_out/preprocessed/axi/axi_pkg.vhd
Date: 2021-07-26 04:08:16
Exec Total Coverage
Lines: 0 219 0.0%
Branches: 0 613 0.0%

Line Branch Exec Source
1 -- -------------------------------------------------------------------------------------------------
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 -- Data types for working with AXI4 interfaces
9 --
10 -- Based on the document "ARM IHI 0022E (ID022613): AMBA AXI and ACE Protocol Specification",
11 -- available here: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ihi0022e/index.html
12 -- -------------------------------------------------------------------------------------------------
13
14 library ieee;
15 use ieee.std_logic_1164.all;
16 use ieee.numeric_std.all;
17
18 library math;
19 use math.math_pkg.all;
20
21
22 package axi_pkg is
23
24 -- Max value
25 constant axi_id_sz : positive := 24;
26
27 constant axi_max_burst_length_beats : positive := 256;
28 constant axi3_max_burst_length_beats : positive := 16;
29
30
31 ------------------------------------------------------------------------------
32 -- A (Address Read and Address Write) channels
33 ------------------------------------------------------------------------------
34
35 -- Max value
36 constant axi_a_addr_sz : positive := 64;
37 -- Number of transfers = len + 1
38 constant axi_a_len_sz : positive := 8;
39 -- Bytes per transfer = 2^size
40 constant axi_a_size_sz : positive := 3;
41
42 function to_len(burst_length_beats : positive) return unsigned;
43 function to_size(data_width_bits : positive) return unsigned;
44
45 constant axi_a_burst_sz : positive := 2;
46 constant axi_a_burst_fixed : std_logic_vector(axi_a_burst_sz - 1 downto 0) := "00";
47 constant axi_a_burst_incr : std_logic_vector(axi_a_burst_sz - 1 downto 0) := "01";
48 constant axi_a_burst_wrap : std_logic_vector(axi_a_burst_sz - 1 downto 0) := "10";
49
50 constant axi_a_lock_sz : positive := 1; -- Two bits in AXI3
51 constant axi_a_lock_normal : std_logic_vector(axi_a_lock_sz - 1 downto 0) := "0";
52 constant axi_a_lock_exclusive : std_logic_vector(axi_a_lock_sz - 1 downto 0) := "1";
53 constant axi3_a_lock_normal : std_logic_vector(2 - 1 downto 0) := "00";
54 constant axi3_a_lock_exclusive : std_logic_vector(2 - 1 downto 0) := "01";
55 constant axi3_a_lock_locked : std_logic_vector(2 - 1 downto 0) := "10";
56
57 constant axi_a_cache_sz : positive := 4;
58 constant axi_a_cache_device_non_bufferable : std_logic_vector(axi_a_cache_sz - 1 downto 0) := "0000";
59 constant axi_a_cache_device_bufferable : std_logic_vector(axi_a_cache_sz - 1 downto 0) := "0001";
60 constant axi_a_cache_normal_non_cacheable_non_bufferable : std_logic_vector(axi_a_cache_sz - 1 downto 0) := "0010";
61 constant axi_a_cache_normal_non_cacheable_bufferable : std_logic_vector(axi_a_cache_sz - 1 downto 0) := "0011";
62 constant axi_ar_cache_write_through_no_allocate : std_logic_vector(axi_a_cache_sz - 1 downto 0) := "1010";
63 constant axi_aw_cache_write_through_no_allocate : std_logic_vector(axi_a_cache_sz - 1 downto 0) := "0110";
64 constant axi_a_cache_write_through_read_allocate : std_logic_vector(axi_a_cache_sz - 1 downto 0) := "0110";
65 constant axi_a_cache_write_through_write_allocate : std_logic_vector(axi_a_cache_sz - 1 downto 0) := "1010";
66 constant axi_a_cache_write_through_read_and_write_allocate : std_logic_vector(axi_a_cache_sz - 1 downto 0) := "1110";
67 constant axi_ar_cache_write_back_no_allocate : std_logic_vector(axi_a_cache_sz - 1 downto 0) := "1011";
68 constant axi_aw_cache_write_back_no_allocate : std_logic_vector(axi_a_cache_sz - 1 downto 0) := "0111";
69 constant axi_a_cache_write_back_read_allocate : std_logic_vector(axi_a_cache_sz - 1 downto 0) := "0111";
70 constant axi_a_cache_write_back_write_allocate : std_logic_vector(axi_a_cache_sz - 1 downto 0) := "1011";
71 constant axi_a_cache_write_back_read_and_write_allocate : std_logic_vector(axi_a_cache_sz - 1 downto 0) := "1111";
72
73 constant axi_a_prot_sz : positive := 3;
74 constant axi_a_prot_privileged : std_logic_vector(axi_a_prot_sz - 1 downto 0) := "001";
75 constant axi_a_prot_unprivileged : std_logic_vector(axi_a_prot_sz - 1 downto 0) := "000";
76 constant axi_a_prot_secure : std_logic_vector(axi_a_prot_sz - 1 downto 0) := "000";
77 constant axi_a_prot_nonsecure : std_logic_vector(axi_a_prot_sz - 1 downto 0) := "010";
78 constant axi_a_prot_data : std_logic_vector(axi_a_prot_sz - 1 downto 0) := "000";
79 constant axi_a_prot_instruction : std_logic_vector(axi_a_prot_sz - 1 downto 0) := "100";
80
81 constant axi_a_region_sz : positive := 4;
82
83 type axi_m2s_a_t is record
84 valid : std_logic;
85 id : unsigned(axi_id_sz - 1 downto 0);
86 addr : unsigned(axi_a_addr_sz - 1 downto 0);
87 len : unsigned(axi_a_len_sz - 1 downto 0);
88 size : unsigned(axi_a_size_sz - 1 downto 0);
89 burst : std_logic_vector(axi_a_burst_sz - 1 downto 0);
90 -- Excluded members: lock, cache, prot, region.
91 -- These are typically not changed on a transfer-to-transfer basis.
92 end record;
93
94 constant axi_m2s_a_init : axi_m2s_a_t := (
95 valid => '0',
96 burst => (others => '0'),
97 others => (others => '0')
98 );
99 function axi_m2s_a_sz(id_width : natural; addr_width : positive) return positive;
100 type axi_m2s_a_vec_t is array (integer range <>) of axi_m2s_a_t;
101
102 function to_slv(
103 data : axi_m2s_a_t; id_width : natural; addr_width : positive
104 ) return std_logic_vector;
105 function to_axi_m2s_a(
106 data : std_logic_vector; id_width : natural; addr_width : positive
107 ) return axi_m2s_a_t;
108
109 type axi_s2m_a_t is record
110 ready : std_logic;
111 end record;
112
113 constant axi_s2m_a_init : axi_s2m_a_t := (ready => '0');
114 type axi_s2m_a_vec_t is array (integer range <>) of axi_s2m_a_t;
115
116
117 ------------------------------------------------------------------------------
118 -- W (Write Data) channels
119 ------------------------------------------------------------------------------
120
121 -- Max values
122 constant axi_data_sz : positive := 128;
123 constant axi_w_strb_sz : positive := axi_data_sz / 8;
124
125 function to_strb(data_width : positive) return std_logic_vector;
126
127 type axi_m2s_w_t is record
128 valid : std_logic;
129 data : std_logic_vector(axi_data_sz - 1 downto 0);
130 strb : std_logic_vector(axi_w_strb_sz - 1 downto 0);
131 last : std_logic;
132 -- Only available in AXI3. We assume that AXI4 is used most of the time, hence id_width is
133 -- defaulted to zero in the functions below.
134 id : unsigned(axi_id_sz - 1 downto 0);
135 end record;
136
137 constant axi_m2s_w_init : axi_m2s_w_t := (
138 valid => '0',
139 data => (others => '-'),
140 last => '0',
141 id => (others => '-'),
142 others => (others => '0')
143 );
144 function axi_m2s_w_sz(data_width : positive; id_width : natural := 0) return positive;
145 type axi_m2s_w_vec_t is array (integer range <>) of axi_m2s_w_t;
146
147 function axi_w_strb_width(data_width : positive) return positive;
148
149 function to_slv(
150 data : axi_m2s_w_t; data_width : positive; id_width : natural := 0
151 ) return std_logic_vector;
152 function to_axi_m2s_w(
153 data : std_logic_vector; data_width : positive; id_width : natural := 0
154 ) return axi_m2s_w_t;
155
156 type axi_s2m_w_t is record
157 ready : std_logic;
158 end record;
159 type axi_s2m_w_vec_t is array (integer range <>) of axi_s2m_w_t;
160
161 constant axi_s2m_w_init : axi_s2m_w_t := (ready => '0');
162
163
164 ------------------------------------------------------------------------------
165 -- B (Write Response) channels
166 ------------------------------------------------------------------------------
167
168 type axi_m2s_b_t is record
169 ready : std_logic;
170 end record;
171
172 constant axi_m2s_b_init : axi_m2s_b_t := (ready => '0');
173
174 constant axi_resp_sz : positive := 2;
175 constant axi_resp_okay : std_logic_vector(axi_resp_sz - 1 downto 0) := "00";
176 -- Exclusive access okay.
177 constant axi_resp_exokay : std_logic_vector(axi_resp_sz - 1 downto 0) := "01";
178 -- Slave error. Slave wishes to return error.
179 constant axi_resp_slverr : std_logic_vector(axi_resp_sz - 1 downto 0) := "10";
180 -- Decode error. There is no slave at transaction address.
181 constant axi_resp_decerr : std_logic_vector(axi_resp_sz - 1 downto 0) := "11";
182
183 type axi_s2m_b_t is record
184 valid : std_logic;
185 id : unsigned(axi_id_sz - 1 downto 0);
186 resp : std_logic_vector(axi_resp_sz - 1 downto 0);
187 end record;
188
189 constant axi_s2m_b_init : axi_s2m_b_t := (
190 valid => '0',
191 id => (others => '0'),
192 resp => (others => '0')
193 );
194 function axi_s2m_b_sz(id_width : natural) return positive;
195 type axi_s2m_b_vec_t is array (integer range <>) of axi_s2m_b_t;
196
197 function to_slv(data : axi_s2m_b_t; id_width : natural) return std_logic_vector;
198 function to_axi_s2m_b(data : std_logic_vector; id_width : natural) return axi_s2m_b_t;
199
200
201 ------------------------------------------------------------------------------
202 -- R (Read Data) channels
203 ------------------------------------------------------------------------------
204
205 type axi_m2s_r_t is record
206 ready : std_logic;
207 end record;
208 type axi_m2s_r_vec_t is array (integer range <>) of axi_m2s_r_t;
209
210 constant axi_m2s_r_init : axi_m2s_r_t := (ready => '0');
211
212 type axi_s2m_r_t is record
213 valid : std_logic;
214 id : unsigned(axi_id_sz - 1 downto 0);
215 data : std_logic_vector(axi_data_sz - 1 downto 0);
216 resp : std_logic_vector(axi_resp_sz - 1 downto 0);
217 last : std_logic;
218 end record;
219
220 constant axi_s2m_r_init : axi_s2m_r_t := (
221 valid => '0',
222 last => '0',
223 id => (others => '0'),
224 others => (others => '0')
225 );
226 function axi_s2m_r_sz(data_width : positive; id_width : natural) return positive;
227 type axi_s2m_r_vec_t is array (integer range <>) of axi_s2m_r_t;
228
229 function to_slv(data : axi_s2m_r_t; data_width : positive; id_width : natural) return std_logic_vector;
230 function to_axi_s2m_r(data : std_logic_vector; data_width : positive; id_width : natural) return axi_s2m_r_t;
231
232
233 ------------------------------------------------------------------------------
234 -- The complete buses
235 ------------------------------------------------------------------------------
236
237 type axi_read_m2s_t is record
238 ar : axi_m2s_a_t;
239 r : axi_m2s_r_t;
240 end record;
241 type axi_read_m2s_vec_t is array (integer range <>) of axi_read_m2s_t;
242
243 constant axi_read_m2s_init : axi_read_m2s_t := (ar => axi_m2s_a_init, r => axi_m2s_r_init);
244
245 type axi_read_s2m_t is record
246 ar : axi_s2m_a_t;
247 r : axi_s2m_r_t;
248 end record;
249 type axi_read_s2m_vec_t is array (integer range <>) of axi_read_s2m_t;
250
251 constant axi_read_s2m_init : axi_read_s2m_t := (ar => axi_s2m_a_init, r => axi_s2m_r_init);
252
253 type axi_write_m2s_t is record
254 aw : axi_m2s_a_t;
255 w : axi_m2s_w_t;
256 b : axi_m2s_b_t;
257 end record;
258 type axi_write_m2s_vec_t is array (integer range <>) of axi_write_m2s_t;
259
260 constant axi_write_m2s_init : axi_write_m2s_t := (aw => axi_m2s_a_init, w => axi_m2s_w_init, b => axi_m2s_b_init);
261
262 type axi_write_s2m_t is record
263 aw : axi_s2m_a_t;
264 w : axi_s2m_w_t;
265 b : axi_s2m_b_t;
266 end record;
267 type axi_write_s2m_vec_t is array (integer range <>) of axi_write_s2m_t;
268
269 constant axi_write_s2m_init : axi_write_s2m_t := (aw => axi_s2m_a_init, w => axi_s2m_w_init, b => axi_s2m_b_init);
270
271 type axi_m2s_t is record
272 read : axi_read_m2s_t;
273 write : axi_write_m2s_t;
274 end record;
275 type axi_m2s_vec_t is array (integer range <>) of axi_m2s_t;
276
277 constant axi_m2s_init : axi_m2s_t := (read => axi_read_m2s_init, write => axi_write_m2s_init);
278
279 type axi_s2m_t is record
280 read : axi_read_s2m_t;
281 write : axi_write_s2m_t;
282 end record;
283 type axi_s2m_vec_t is array (integer range <>) of axi_s2m_t;
284
285 constant axi_s2m_init : axi_s2m_t := (read => axi_read_s2m_init, write => axi_write_s2m_init);
286
287 function combine_response(resp1, resp2 : std_logic_vector(axi_resp_sz - 1 downto 0))
288 return std_logic_vector;
289
290 end;
291
292 package body axi_pkg is
293
294 function to_len(burst_length_beats : positive) return unsigned is
295 variable result : unsigned(axi_a_len_sz - 1 downto 0);
296 begin
297 -- burst_length_beats is number of transfers
298 result := to_unsigned(burst_length_beats - 1, result'length);
299 return result;
300 end function;
301
302 function to_size(data_width_bits : positive) return unsigned is
303 variable result : unsigned(axi_a_size_sz - 1 downto 0);
304 begin
305 result := to_unsigned(log2(data_width_bits / 8), result'length);
306 return result;
307 end function;
308
309 function axi_m2s_a_sz(id_width : natural; addr_width : positive) return positive is
310 begin
311 -- Exluded member: valid
312 return id_width + addr_width + axi_a_len_sz + axi_a_size_sz + axi_a_burst_sz;
313 end function;
314
315 function to_slv(
316 data : axi_m2s_a_t; id_width : natural; addr_width : positive
317 ) return std_logic_vector is
318 variable result : std_logic_vector(axi_m2s_a_sz(id_width, addr_width) - 1 downto 0);
319 variable lo, hi : natural := 0;
320 begin
321 lo := 0;
322 if id_width > 0 then
323 hi := id_width - 1;
324 result(hi downto lo) := std_logic_vector(data.id(hi downto lo));
325 lo := hi + 1;
326 end if;
327 hi := lo + addr_width - 1;
328 result(hi downto lo) := std_logic_vector(data.addr(addr_width - 1 downto 0));
329 lo := hi + 1;
330 hi := lo + data.len'length - 1;
331 result(hi downto lo) := std_logic_vector(data.len);
332 lo := hi + 1;
333 hi := lo + data.size'length - 1;
334 result(hi downto lo) := std_logic_vector(data.size);
335 lo := hi + 1;
336 hi := lo + data.burst'length - 1;
337 result(hi downto lo) := data.burst;
338 assert hi = result'high severity failure;
339 return result;
340 end function;
341
342 function to_axi_m2s_a(
343 data : std_logic_vector; id_width : natural; addr_width : positive
344 ) return axi_m2s_a_t is
345 constant offset : natural := data'low;
346 variable result : axi_m2s_a_t := axi_m2s_a_init;
347 variable lo, hi : natural := 0;
348 begin
349 lo := 0;
350 if id_width > 0 then
351 hi := id_width - 1;
352 result.id(hi downto lo) := unsigned(data(hi + offset downto lo + offset));
353 lo := hi + 1;
354 end if;
355 hi := lo + addr_width - 1;
356 result.addr(addr_width - 1 downto 0) := unsigned(data(hi + offset downto lo + offset));
357 lo := hi + 1;
358 hi := lo + result.len'length - 1;
359 result.len := unsigned(data(hi + offset downto lo + offset));
360 lo := hi + 1;
361 hi := lo + result.size'length - 1;
362 result.size := unsigned(data(hi + offset downto lo + offset));
363 lo := hi + 1;
364 hi := lo + result.burst'length - 1;
365 result.burst := data(hi + offset downto lo + offset);
366 assert hi + offset = data'high severity failure;
367 return result;
368 end function;
369
370 function to_strb(data_width : positive) return std_logic_vector is
371 variable result : std_logic_vector(axi_w_strb_sz - 1 downto 0) := (others => '0');
372 begin
373 result(data_width / 8 - 1 downto 0) := (others => '1');
374 return result;
375 end function;
376
377 function axi_w_strb_width(data_width : positive) return positive is
378 begin
379 return data_width / 8;
380 end function;
381
382 function axi_m2s_w_sz(data_width : positive; id_width : natural := 0) return positive is
383 begin
384 -- Exluded member: valid.
385 -- The 1 is "last".
386 return data_width + axi_w_strb_width(data_width) + 1 + id_width;
387 end function;
388
389 function to_slv(
390 data : axi_m2s_w_t; data_width : positive; id_width : natural := 0
391 ) return std_logic_vector is
392 variable result :
393 std_logic_vector(axi_m2s_w_sz(data_width=>data_width, id_width=>id_width) - 1 downto 0) :=
394 (others => '0');
395 variable lo, hi : natural := 0;
396 begin
397 lo := 0;
398
399 hi := lo + data_width - 1;
400 result(hi downto lo) := data.data(data_width - 1 downto 0);
401 lo := hi + 1;
402
403 hi := lo + axi_w_strb_width(data_width) - 1;
404 result(hi downto lo) := data.strb(axi_w_strb_width(data_width) - 1 downto 0);
405 lo := hi + 1;
406
407 hi := lo + id_width - 1;
408 result(hi downto lo) := std_logic_vector(data.id(id_width - 1 downto 0));
409 lo := hi + 1;
410
411 hi := lo;
412 result(hi) := data.last;
413 assert hi = result'high severity failure;
414 return result;
415 end function;
416
417 function to_axi_m2s_w(
418 data : std_logic_vector; data_width : positive; id_width : natural := 0
419 ) return axi_m2s_w_t is
420 constant offset : natural := data'low;
421 variable result : axi_m2s_w_t := axi_m2s_w_init;
422 variable lo, hi : natural := 0;
423 begin
424 lo := 0;
425
426 hi := lo + data_width - 1;
427 result.data(data_width - 1 downto 0) := data(hi + offset downto lo + offset);
428 lo := hi + 1;
429
430 hi := lo + axi_w_strb_width(data_width) - 1;
431 result.strb(axi_w_strb_width(data_width) - 1 downto 0) := data(hi + offset downto lo + offset);
432 lo := hi + 1;
433
434 hi := lo + id_width - 1;
435 result.id(id_width - 1 downto 0) := unsigned(data(hi + offset downto lo + offset));
436 lo := hi + 1;
437
438 hi := lo;
439 result.last := data(hi + offset);
440 assert hi + offset = data'high severity failure;
441 return result;
442 end function;
443
444 function axi_s2m_b_sz(id_width : natural) return positive is
445 begin
446 -- Exluded member: valid
447 return id_width + axi_resp_sz;
448 end function;
449
450 function to_slv(data : axi_s2m_b_t; id_width : natural) return std_logic_vector is
451 variable result : std_logic_vector(axi_s2m_b_sz(id_width) - 1 downto 0);
452 variable lo, hi : natural := 0;
453 begin
454 lo := 0;
455 if id_width > 0 then
456 hi := id_width - 1;
457 result(hi downto lo) := std_logic_vector(data.id(hi downto lo));
458 lo := hi + 1;
459 end if;
460 hi := lo + axi_resp_sz - 1;
461 result(hi downto lo) := data.resp;
462 assert hi = result'high severity failure;
463 return result;
464 end function;
465
466 function to_axi_s2m_b(data : std_logic_vector; id_width : natural) return axi_s2m_b_t is
467 constant offset : natural := data'low;
468 variable result : axi_s2m_b_t := axi_s2m_b_init;
469 variable lo, hi : natural := 0;
470 begin
471 lo := 0;
472 if id_width > 0 then
473 hi := id_width - 1;
474 result.id(hi downto lo) := unsigned(data(hi + offset downto lo + offset));
475 lo := hi + 1;
476 end if;
477 hi := lo + axi_resp_sz - 1;
478 result.resp := data(hi + offset downto lo + offset);
479 assert hi + offset = data'high severity failure;
480 return result;
481 end function;
482
483 function axi_s2m_r_sz(data_width : positive; id_width : natural) return positive is
484 begin
485 -- Exluded member: valid.
486 -- The 1 is "last".
487 return data_width + id_width + axi_resp_sz + 1;
488 end function;
489
490 function to_slv(data : axi_s2m_r_t; data_width : positive; id_width : natural) return std_logic_vector is
491 variable result : std_logic_vector(axi_s2m_r_sz(data_width, id_width) - 1 downto 0);
492 variable lo, hi : natural := 0;
493 begin
494 lo := 0;
495 if id_width > 0 then
496 hi := id_width - 1;
497 result(hi downto lo) := std_logic_vector(data.id(hi downto lo));
498 lo := hi + 1;
499 end if;
500 hi := lo + data_width - 1;
501 result(hi downto lo) := data.data(data_width - 1 downto 0);
502 lo := hi + 1;
503 hi := lo + axi_resp_sz - 1;
504 result(hi downto lo) := data.resp;
505 lo := hi + 1;
506 hi := lo;
507 result(hi) := data.last;
508 assert hi = result'high severity failure;
509 return result;
510 end function;
511
512 function to_axi_s2m_r(data : std_logic_vector; data_width : positive; id_width : natural) return axi_s2m_r_t is
513 constant offset : natural := data'low;
514 variable result : axi_s2m_r_t := axi_s2m_r_init;
515 variable lo, hi : natural := 0;
516 begin
517 lo := 0;
518 if id_width > 0 then
519 hi := id_width - 1;
520 result.id(hi downto lo) := unsigned(data(hi + offset downto lo + offset));
521 lo := hi + 1;
522 end if;
523 hi := lo + data_width - 1;
524 result.data(data_width - 1 downto 0) := data(hi + offset downto lo + offset);
525 lo := hi + 1;
526 hi := lo + axi_resp_sz - 1;
527 result.resp := data(hi + offset downto lo + offset);
528 lo := hi + 1;
529 hi := lo;
530 result.last := data(hi + offset);
531 assert hi + offset = data'high severity failure;
532 return result;
533 end function;
534
535 -- Combine responses, with the "worst" response taking priority. OKAY may be considered
536 -- an error if an exclusive access was desired, so OKAY takes priority over EXOKAY.
537 function combine_response(
538 resp1, resp2 : std_logic_vector(axi_resp_sz - 1 downto 0)
539 ) return std_logic_vector is
540 variable resp : std_logic_vector(axi_resp_sz - 1 downto 0);
541 begin
542 resp := resp1;
543
544 case resp is
545 when axi_resp_exokay =>
546 -- All values take priority over EXOKAY
547 resp := resp2;
548
549 when axi_resp_okay =>
550 -- Errors take priority over OKAY
551 if resp2 = axi_resp_slverr then
552 resp := axi_resp_slverr;
553 end if;
554 if resp2 = axi_resp_decerr then
555 resp := axi_resp_decerr;
556 end if;
557
558 when axi_resp_slverr =>
559 -- Only DECERR takes priority over SLVERR
560 if resp2 = axi_resp_decerr then
561 resp := axi_resp_decerr;
562 end if;
563
564 when others =>
565 -- DECERR
566 resp := axi_resp_decerr;
567
568 end case;
569
570 return resp;
571 end function;
572 end;
573