-
Notifications
You must be signed in to change notification settings - Fork 269
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #364 from slaweksiluk/master
Support for Avalon-MM burst transfers
- Loading branch information
Showing
10 changed files
with
457 additions
and
70 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,17 +5,19 @@ | |
-- Copyright (c) 2014-2018, Lars Asplund [email protected] | ||
-- Author Slawomir Siluk [email protected] | ||
-- 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; | ||
|
@@ -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; | ||
|
@@ -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; | ||
|
@@ -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'; | ||
|
@@ -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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,8 +6,7 @@ | |
-- Author Slawomir Siluk [email protected] | ||
-- | ||
-- 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; | ||
|
@@ -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); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.