Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unaligned addresses with axi_read_slave #936

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
14 changes: 12 additions & 2 deletions vunit/vhdl/verification_components/src/axi_read_slave.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use ieee.numeric_std.all;
use work.axi_pkg.all;
use work.axi_slave_private_pkg.all;
use work.queue_pkg.all;
use work.logger_pkg.all;
context work.com_context;
context work.vc_context;

Expand Down Expand Up @@ -58,6 +59,7 @@ begin

variable response_time : time;
variable has_response_time : boolean := false;
variable logger : logger_t := get_logger("axi_process");
begin
assert arid'length = rid'length report "arid vs rid data width mismatch";
-- Initialization
Expand Down Expand Up @@ -92,15 +94,23 @@ begin
beats := burst.length;
rid <= std_logic_vector(to_unsigned(burst.id, rid'length));
rresp <= axi_resp_okay;
address := burst.address;
address := burst.address - (burst.address mod burst.size); --aligned address
end if;
end if;

if beats > 0 and (rvalid = '0' or rready = '1') and not self.should_stall_data then
rvalid <= '1';
rdata <= (rdata'range => '-');
for j in 0 to burst.size-1 loop
idx := (address + j) mod self.data_size;
rdata(8*idx+7 downto 8*idx) <= std_logic_vector(to_unsigned(read_byte(axi_slave.p_memory, address+j), 8));

--Don't try to read lower than the burst's base addr; only kicks in when unaligned
if address+j >= burst.address then
debug(logger, "RD addr " & integer'image(address+j) & ", put in byte lane " & integer'image(idx));
rdata(8*idx+7 downto 8*idx) <= std_logic_vector(to_unsigned(read_byte(axi_slave.p_memory, address+j), 8));
else
debug(logger, "SKIP RD addr " & integer'image(address+j));
end if;
end loop;

if burst.burst_type = axi_burst_type_incr then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ package body axi_slave_private_pkg is
variable first_page, last_page : integer;
begin
first_address := burst.address - (burst.address mod data_size); -- Aligned
last_address := burst.address + burst.size*burst.length - 1;
last_address := first_address + burst.size*burst.length - 1;

first_page := first_address / 4096;
last_page := last_address / 4096;
Expand Down
51 changes: 44 additions & 7 deletions vunit/vhdl/verification_components/test/tb_axi_read_slave.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,19 @@ begin

procedure read_data(id : std_logic_vector; address : natural; size : natural; resp : axi_resp_t; last : boolean) is
variable idx : integer;
variable addr : integer;
variable logger : logger_t := get_logger("read_data");
begin
rready <= '1';
wait until (rvalid and rready) = '1' and rising_edge(clk);
rready <= '0';
addr := address - (address mod size); --align address to transfer size
for i in 0 to size-1 loop
idx := (address + i) mod data_size; -- Align data bus
check_equal(rdata(8*idx+7 downto 8*idx), read_byte(memory, address+i));
idx := ((addr mod data_size) + i); --idx is the byte lane for this value
if addr >= address then
debug(logger, "RD addr " & integer'image(addr+i) & ", got " & integer'image(read_byte(memory, addr+i)) & ", compare to rdata byte lane " & integer'image(idx));
check_equal(rdata(8*idx+7 downto 8*idx), read_byte(memory, addr+i), result("for rdata in byte lane " & integer'image(idx)));
end if;
end loop;
check_equal(rid, id, "rid");
check_equal(rresp, resp, "rresp");
Expand All @@ -86,15 +92,16 @@ begin

procedure transfer(log_size, len : natural;
id : std_logic_vector;
burst : std_logic_vector) is
burst : std_logic_vector;
alignment : positive := 4096) is
variable buf : buffer_t;
variable size : natural;
variable data : integer_vector_ptr_t;
begin
size := 2**log_size;
random_integer_vector_ptr(rnd, data, size * len, 0, 255);

buf := allocate(memory, 8 * len, alignment => 4096);
buf := allocate(memory, length(data), alignment => alignment);
for i in 0 to length(data)-1 loop
write_byte(memory, base_address(buf)+i, get(data, i));
end loop;
Expand All @@ -109,7 +116,7 @@ begin
variable log_size : natural;
variable buf : buffer_t;
variable id : std_logic_vector(arid'range);
variable len : natural;
variable len : positive;
variable burst : axi_burst_type_t;
variable start_time, diff_time : time;
begin
Expand All @@ -131,8 +138,38 @@ begin
assert false;
end case;

log_size := rnd.RandInt(0, 3);
transfer(log_size, len, id, burst);
log_size := rnd.RandInt(0, log_data_size);
transfer(log_size, len, id, burst, alignment => 4096);
end loop;

elsif run("Test unaligned read") then
for test_idx in 0 to 32-1 loop

id := rnd.RandSlv(arid'length);
case rnd.RandInt(1) is
when 0 =>
burst := axi_burst_type_fixed;
len := 1;
when 1 =>
burst := axi_burst_type_incr;
len := rnd.RandInt(1, 2**arlen'length);
when others =>
assert false;
end case;

log_size := rnd.RandInt(0, log_data_size);

--If the burst will cross a 4KB boundary, lower the length
--If the min length is reached and still crossing, lower the size
while (2**log_size * len) > (4096 - (num_bytes(memory) mod 4096)) loop
debug("total size = " & integer'image(2**log_size * len) & ", num_bytes = " & integer'image(num_bytes(memory)));
if len = 1 then
log_size := log_size - 1;
else
len := len - 1;
end if;
end loop;
transfer(log_size, len, id, burst, alignment => rnd.RandInt(1, log_data_size));
end loop;

elsif run("Test random data stall") then
Expand Down