Skip to content

Commit

Permalink
Merge pull request #364 from slaweksiluk/master
Browse files Browse the repository at this point in the history
Support for Avalon-MM burst transfers
  • Loading branch information
kraigher authored Nov 30, 2018
2 parents 2eea711 + 166bf13 commit 7e90f4f
Show file tree
Hide file tree
Showing 10 changed files with 457 additions and 70 deletions.
2 changes: 1 addition & 1 deletion vunit/vhdl/verification_components/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def gen_avalon_master_tests(obj, *args):
if test.name == "wr single rd single":
gen_avalon_master_tests(test, [1], [1.0], [0.0], [1.0], [1.0])
else:
gen_avalon_master_tests(test, [16], [1.0, 0.3], [0.0, 0.7], [1.0, 0.3], [1.0, 0.3])
gen_avalon_master_tests(test, [64], [1.0, 0.3], [0.0, 0.7], [1.0, 0.3], [1.0, 0.3])

tb_wishbone_slave = lib.test_bench("tb_wishbone_slave")

Expand Down
74 changes: 70 additions & 4 deletions vunit/vhdl/verification_components/src/avalon_master.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@
-- Copyright (c) 2014-2018, Lars Asplund lars.anders.asplund@gmail.com
-- Author Slawomir Siluk slaweksiluk@gazeta.pl
-- Avalon Memory Mapped Master BFM
-- - support burstcount > 1

-- TODO:
-- - handle byteenable in bursts
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

use work.queue_pkg.all;
use work.bus_master_pkg.all;
context work.com_context;
use work.com_types_pkg.all;
use work.logger_pkg.all;
use work.check_pkg.all;
use work.sync_pkg.all;

library osvvm;
use osvvm.RandomPkg.all;
Expand Down Expand Up @@ -44,18 +46,24 @@ end entity;

architecture a of avalon_master is
constant av_master_read_actor : actor_t := new_actor;
constant avmm_burst_rd_actor : actor_t := new_actor;
constant acknowledge_queue : queue_t := new_queue;
constant burst_acknowledge_queue : queue_t := new_queue;
constant burstlen_queue : queue_t := new_queue;
signal burst_read_flag : boolean := false;
begin

main : process
variable request_msg : msg_t;
variable msg_type : msg_type_t;
variable rnd : RandomPType;
variable msgs : natural;
variable burst : positive;
begin
rnd.InitSeed(rnd'instance_name);
write <= '0';
read <= '0';
burstcount <= std_logic_vector(to_unsigned(1, burstcount'length));
wait until rising_edge(clk);
loop
request_msg := null_msg;
Expand All @@ -74,17 +82,55 @@ begin
read <= '0';
push(acknowledge_queue, request_msg);

elsif msg_type = bus_burst_read_msg then
while rnd.Uniform(0.0, 1.0) > read_high_probability loop
wait until rising_edge(clk);
end loop;
address <= pop_std_ulogic_vector(request_msg);
burstcount <= std_logic_vector(to_unsigned(1, burstcount'length));
burst := pop_integer(request_msg);
burstcount <= std_logic_vector(to_unsigned(burst, burstcount'length));
byteenable(byteenable'range) <= (others => '1');
read <= '1';
wait until rising_edge(clk) and waitrequest = '0';
read <= '0';
push(burst_acknowledge_queue, request_msg);
push(burstlen_queue, burst);

elsif msg_type = bus_write_msg then
while rnd.Uniform(0.0, 1.0) > write_high_probability loop
wait until rising_edge(clk);
end loop;
address <= pop_std_ulogic_vector(request_msg);
burstcount <= std_logic_vector(to_unsigned(1, burstcount'length));
writedata <= pop_std_ulogic_vector(request_msg);
byteenable <= pop_std_ulogic_vector(request_msg);
write <= '1';
wait until rising_edge(clk) and waitrequest = '0';
write <= '0';

elsif msg_type = bus_burst_write_msg then
address <= pop_std_ulogic_vector(request_msg);
burst := pop_integer(request_msg);
burstcount <= std_logic_vector(to_unsigned(burst, burstcount'length));
for i in 0 to burst-1 loop
while rnd.Uniform(0.0, 1.0) > write_high_probability loop
wait until rising_edge(clk);
end loop;
writedata <= pop_std_ulogic_vector(request_msg);
-- TODO handle byteenable
byteenable(byteenable'range) <= (others => '1');
write <= '1';
wait until rising_edge(clk) and waitrequest = '0';
write <= '0';
address(address'range) <= (others => 'U');
burstcount(burstcount'range) <= (others => 'U');
end loop;

elsif msg_type = wait_until_idle_msg then
wait until not burst_read_flag and is_empty(burst_acknowledge_queue) and rising_edge(clk);
handle_wait_until_idle(net, msg_type, request_msg);

else
unexpected_msg_type(msg_type);
end if;
Expand All @@ -98,7 +144,7 @@ begin
variable request_msg, reply_msg : msg_t;
begin
if use_readdatavalid then
wait until readdatavalid = '1' and rising_edge(clk);
wait until readdatavalid = '1' and not is_empty(acknowledge_queue) and rising_edge(clk);
else
-- Non-pipelined case: waits for slave to de-assert waitrequest and sample data after fixed_read_latency cycles.
wait until rising_edge(clk) and waitrequest = '0' and read = '1';
Expand All @@ -115,5 +161,25 @@ begin
delete(request_msg);
end process;

burstcount <= "1";
burst_read_capture : process
variable request_msg, reply_msg : msg_t;
variable burst : positive;
begin
wait until readdatavalid = '1' and not is_empty(burst_acknowledge_queue) and rising_edge(clk);
burst_read_flag <= true;
request_msg := pop(burst_acknowledge_queue);
burst := pop(burstlen_queue);
reply_msg := new_msg(sender => avmm_burst_rd_actor);
push_integer(reply_msg, burst);
push_std_ulogic_vector(reply_msg, readdata);
for i in 1 to burst-1 loop
wait until readdatavalid = '1' and rising_edge(clk) for 1 us;
check_true(readdatavalid = '1', "avalon master burst readdatavalid timeout");
push_std_ulogic_vector(reply_msg, readdata);
end loop;
reply(net, request_msg, reply_msg);
delete(request_msg);
burst_read_flag <= false;
end process;

end architecture;
2 changes: 1 addition & 1 deletion vunit/vhdl/verification_components/src/avalon_pkg.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ package body avalon_pkg is
return avalon_slave_t is
begin
return (p_actor => new_actor(name),
p_ack_actor => new_actor(name&"_ack"),
p_ack_actor => new_actor(name&" read-ack"),
p_memory => to_vc_interface(memory, logger),
p_logger => logger,
readdatavalid_high_probability => readdatavalid_high_probability,
Expand Down
77 changes: 41 additions & 36 deletions vunit/vhdl/verification_components/src/avalon_slave.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
-- Author Slawomir Siluk slaweksiluk@gazeta.pl
--
-- Avalon memory mapped slave wrapper for Vunit memory VC
-- TODO:
-- - support burstcount > 1

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
Expand Down Expand Up @@ -40,58 +39,64 @@ end entity;

architecture a of avalon_slave is

constant slave_write_msg : msg_type_t := new_msg_type("avmm slave write");
constant slave_read_msg : msg_type_t := new_msg_type("avmm slave read");

begin

request : process
variable wr_request_msg : msg_t;
write_handler : process
variable pending_writes : positive := 1;
variable addr : natural;
begin
loop
wait until write = '1' and waitrequest = '0' and rising_edge(clk);
-- Burst write in progress
if pending_writes > 1 then
addr := addr + byteenable'length;
pending_writes := pending_writes -1;
write_word(avalon_slave.p_memory, addr, writedata);
-- Burst start or single burst
else
addr := to_integer(unsigned(address));
pending_writes := to_integer(unsigned(burstcount));
write_word(avalon_slave.p_memory, addr, writedata);
end if;
end loop;
end process;

read_request : process
variable rd_request_msg : msg_t;
begin
wait until (write or read) = '1' and waitrequest = '0' and rising_edge(clk);
check_false(write = '1' and read = '1');
if write = '1' then
wr_request_msg := new_msg(slave_write_msg, avalon_slave.p_actor);
-- For write, address and data are passed to ack proc
push_integer(wr_request_msg, to_integer(unsigned(address)));
push_std_ulogic_vector(wr_request_msg, writedata);
send(net, avalon_slave.p_ack_actor, wr_request_msg);
elsif read = '1' then
rd_request_msg := new_msg(slave_read_msg, avalon_slave.p_actor);
-- For read, only address is passed to ack proc
push_integer(rd_request_msg, to_integer(unsigned(address)));
send(net, avalon_slave.p_ack_actor, rd_request_msg);
end if;
wait until read = '1' and waitrequest = '0' and rising_edge(clk);
rd_request_msg := new_msg(slave_read_msg, avalon_slave.p_actor);
-- For read, only address is passed to ack proc
push_integer(rd_request_msg, to_integer(unsigned(burstcount)));
push_integer(rd_request_msg, to_integer(unsigned(address)));
send(net, avalon_slave.p_ack_actor, rd_request_msg);
end process;

acknowledge : process
read_handler : process
variable request_msg : msg_t;
variable msg_type : msg_type_t;
variable data : std_logic_vector(writedata'range);
variable addr : natural;
variable baseaddr : natural;
variable burst : positive;
variable rnd : RandomPType;
begin
readdatavalid <= '0';
receive(net, avalon_slave.p_ack_actor, request_msg);
msg_type := message_type(request_msg);

if msg_type = slave_write_msg then
addr := pop_integer(request_msg);
data := pop_std_ulogic_vector(request_msg);
write_word(avalon_slave.p_memory, addr, data);

elsif msg_type = slave_read_msg then
data := (others => '0');
addr := pop_integer(request_msg);
data := read_word(avalon_slave.p_memory, addr, byteenable'length);
while rnd.Uniform(0.0, 1.0) > avalon_slave.readdatavalid_high_probability loop
if msg_type = slave_read_msg then
burst := pop_integer(request_msg);
baseaddr := pop_integer(request_msg);
for i in 0 to burst-1 loop
while rnd.Uniform(0.0, 1.0) > avalon_slave.readdatavalid_high_probability loop
wait until rising_edge(clk);
end loop;
readdata <= read_word(avalon_slave.p_memory, baseaddr + byteenable'length*i, byteenable'length);
readdatavalid <= '1';
wait until rising_edge(clk);
readdatavalid <= '0';
end loop;
readdata <= data;
readdatavalid <= '1';
wait until rising_edge(clk);
readdatavalid <= '0';

else
unexpected_msg_type(msg_type);
Expand Down
93 changes: 93 additions & 0 deletions vunit/vhdl/verification_components/src/bus_master_pkg-body.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use ieee.numeric_std.all;

use work.queue_pkg.all;
use work.sync_pkg.all;
use work.queue_pkg.all;
use work.check_pkg.all;

package body bus_master_pkg is

Expand Down Expand Up @@ -96,6 +98,34 @@ package body bus_master_pkg is
write_bus(net, bus_handle, to_address(bus_handle, address), data, byte_enable);
end;

procedure burst_write_bus(signal net : inout network_t;
constant bus_handle : bus_master_t;
constant address : std_logic_vector;
constant burst_length : positive;
constant data : queue_t) is
variable request_msg : msg_t := new_msg(bus_burst_write_msg);
variable full_address : std_logic_vector(bus_handle.p_address_length-1 downto 0) := (others => '0');
variable full_data : std_logic_vector(bus_handle.p_data_length-1 downto 0) := (others => '0');
begin
full_address(address'length-1 downto 0) := address;
push_std_ulogic_vector(request_msg, full_address);
push_integer(request_msg, burst_length);
for i in 0 to burst_length-1 loop
full_data(bus_handle.p_data_length-1 downto 0) := pop(data);
push_std_ulogic_vector(request_msg, full_data);
end loop;
send(net, bus_handle.p_actor, request_msg);
end procedure;

procedure burst_write_bus(signal net : inout network_t;
constant bus_handle : bus_master_t;
constant address : natural;
constant burst_length : positive;
constant data : queue_t) is
begin
burst_write_bus(net, bus_handle, to_address(bus_handle, address), burst_length, data);
end procedure;

procedure check_bus(signal net : inout network_t;
constant bus_handle : bus_master_t;
constant address : std_logic_vector;
Expand Down Expand Up @@ -158,6 +188,30 @@ package body bus_master_pkg is
read_bus(net, bus_handle, to_address(bus_handle, address), reference);
end;

procedure burst_read_bus(signal net : inout network_t;
constant bus_handle : bus_master_t;
constant address : std_logic_vector;
constant burst_length : positive;
variable reference : inout bus_reference_t) is
variable full_address : std_logic_vector(bus_handle.p_address_length-1 downto 0) := (others => '0');
alias request_msg : msg_t is reference;
begin
request_msg := new_msg(bus_burst_read_msg);
full_address(address'length-1 downto 0) := address;
push_std_ulogic_vector(request_msg, full_address);
push_integer(request_msg, burst_length);
send(net, bus_handle.p_actor, request_msg);
end procedure;

procedure burst_read_bus(signal net : inout network_t;
constant bus_handle : bus_master_t;
constant address : natural;
constant burst_length : positive;
variable reference : inout bus_reference_t) is
begin
burst_read_bus(net, bus_handle, to_address(bus_handle, address), burst_length, reference);
end procedure;

-- Await read bus reply
procedure await_read_bus_reply(signal net : inout network_t;
variable reference : inout bus_reference_t;
Expand All @@ -171,6 +225,25 @@ package body bus_master_pkg is
delete(reply_msg);
end procedure;

procedure await_burst_read_bus_reply(signal net : inout network_t;
constant bus_handle : bus_master_t;
constant data : queue_t;
variable reference : inout bus_reference_t) is
variable reply_msg : msg_t;
alias request_msg : msg_t is reference;
variable d : std_logic_vector(bus_handle.p_data_length-1 downto 0);
variable burst_length : positive;
begin
receive_reply(net, request_msg, reply_msg);
burst_length := pop_integer(reply_msg);
for i in 0 to burst_length-1 loop
d := pop_std_ulogic_vector(reply_msg)(d'range);
push(data, d);
end loop;
delete(request_msg);
delete(reply_msg);
end procedure;

-- Blocking read with immediate reply
procedure read_bus(signal net : inout network_t;
constant bus_handle : bus_master_t;
Expand All @@ -191,6 +264,26 @@ package body bus_master_pkg is
read_bus(net, bus_handle, to_address(bus_handle, address), data);
end;

procedure burst_read_bus(signal net : inout network_t;
constant bus_handle : bus_master_t;
constant address : std_logic_vector;
constant burst_length : positive;
constant data : queue_t) is
variable reference : bus_reference_t;
begin
burst_read_bus(net, bus_handle, address, burst_length, reference);
await_burst_read_bus_reply(net, bus_handle, data, reference);
end procedure;

procedure burst_read_bus(signal net : inout network_t;
constant bus_handle : bus_master_t;
constant address : natural;
constant burst_length : positive;
constant data : queue_t) is
begin
burst_read_bus(net, bus_handle, to_address(bus_handle, address), burst_length, data);
end procedure;

procedure wait_until_read_equals(
signal net : inout network_t;
bus_handle : bus_master_t;
Expand Down
Loading

0 comments on commit 7e90f4f

Please sign in to comment.