Skip to content

Commit 7e90f4f

Browse files
authored
Merge pull request #364 from slaweksiluk/master
Support for Avalon-MM burst transfers
2 parents 2eea711 + 166bf13 commit 7e90f4f

10 files changed

Lines changed: 457 additions & 70 deletions

File tree

vunit/vhdl/verification_components/run.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def gen_avalon_master_tests(obj, *args):
7272
if test.name == "wr single rd single":
7373
gen_avalon_master_tests(test, [1], [1.0], [0.0], [1.0], [1.0])
7474
else:
75-
gen_avalon_master_tests(test, [16], [1.0, 0.3], [0.0, 0.7], [1.0, 0.3], [1.0, 0.3])
75+
gen_avalon_master_tests(test, [64], [1.0, 0.3], [0.0, 0.7], [1.0, 0.3], [1.0, 0.3])
7676

7777
tb_wishbone_slave = lib.test_bench("tb_wishbone_slave")
7878

vunit/vhdl/verification_components/src/avalon_master.vhd

Lines changed: 70 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@
55
-- Copyright (c) 2014-2018, Lars Asplund lars.anders.asplund@gmail.com
66
-- Author Slawomir Siluk slaweksiluk@gazeta.pl
77
-- Avalon Memory Mapped Master BFM
8-
-- - support burstcount > 1
9-
8+
-- TODO:
9+
-- - handle byteenable in bursts
1010
library ieee;
1111
use ieee.std_logic_1164.all;
12+
use ieee.numeric_std.all;
1213

1314
use work.queue_pkg.all;
1415
use work.bus_master_pkg.all;
1516
context work.com_context;
1617
use work.com_types_pkg.all;
1718
use work.logger_pkg.all;
1819
use work.check_pkg.all;
20+
use work.sync_pkg.all;
1921

2022
library osvvm;
2123
use osvvm.RandomPkg.all;
@@ -44,18 +46,24 @@ end entity;
4446

4547
architecture a of avalon_master is
4648
constant av_master_read_actor : actor_t := new_actor;
49+
constant avmm_burst_rd_actor : actor_t := new_actor;
4750
constant acknowledge_queue : queue_t := new_queue;
51+
constant burst_acknowledge_queue : queue_t := new_queue;
52+
constant burstlen_queue : queue_t := new_queue;
53+
signal burst_read_flag : boolean := false;
4854
begin
4955

5056
main : process
5157
variable request_msg : msg_t;
5258
variable msg_type : msg_type_t;
5359
variable rnd : RandomPType;
5460
variable msgs : natural;
61+
variable burst : positive;
5562
begin
5663
rnd.InitSeed(rnd'instance_name);
5764
write <= '0';
5865
read <= '0';
66+
burstcount <= std_logic_vector(to_unsigned(1, burstcount'length));
5967
wait until rising_edge(clk);
6068
loop
6169
request_msg := null_msg;
@@ -74,17 +82,55 @@ begin
7482
read <= '0';
7583
push(acknowledge_queue, request_msg);
7684

85+
elsif msg_type = bus_burst_read_msg then
86+
while rnd.Uniform(0.0, 1.0) > read_high_probability loop
87+
wait until rising_edge(clk);
88+
end loop;
89+
address <= pop_std_ulogic_vector(request_msg);
90+
burstcount <= std_logic_vector(to_unsigned(1, burstcount'length));
91+
burst := pop_integer(request_msg);
92+
burstcount <= std_logic_vector(to_unsigned(burst, burstcount'length));
93+
byteenable(byteenable'range) <= (others => '1');
94+
read <= '1';
95+
wait until rising_edge(clk) and waitrequest = '0';
96+
read <= '0';
97+
push(burst_acknowledge_queue, request_msg);
98+
push(burstlen_queue, burst);
99+
77100
elsif msg_type = bus_write_msg then
78101
while rnd.Uniform(0.0, 1.0) > write_high_probability loop
79102
wait until rising_edge(clk);
80103
end loop;
81104
address <= pop_std_ulogic_vector(request_msg);
105+
burstcount <= std_logic_vector(to_unsigned(1, burstcount'length));
82106
writedata <= pop_std_ulogic_vector(request_msg);
83107
byteenable <= pop_std_ulogic_vector(request_msg);
84108
write <= '1';
85109
wait until rising_edge(clk) and waitrequest = '0';
86110
write <= '0';
87111

112+
elsif msg_type = bus_burst_write_msg then
113+
address <= pop_std_ulogic_vector(request_msg);
114+
burst := pop_integer(request_msg);
115+
burstcount <= std_logic_vector(to_unsigned(burst, burstcount'length));
116+
for i in 0 to burst-1 loop
117+
while rnd.Uniform(0.0, 1.0) > write_high_probability loop
118+
wait until rising_edge(clk);
119+
end loop;
120+
writedata <= pop_std_ulogic_vector(request_msg);
121+
-- TODO handle byteenable
122+
byteenable(byteenable'range) <= (others => '1');
123+
write <= '1';
124+
wait until rising_edge(clk) and waitrequest = '0';
125+
write <= '0';
126+
address(address'range) <= (others => 'U');
127+
burstcount(burstcount'range) <= (others => 'U');
128+
end loop;
129+
130+
elsif msg_type = wait_until_idle_msg then
131+
wait until not burst_read_flag and is_empty(burst_acknowledge_queue) and rising_edge(clk);
132+
handle_wait_until_idle(net, msg_type, request_msg);
133+
88134
else
89135
unexpected_msg_type(msg_type);
90136
end if;
@@ -98,7 +144,7 @@ begin
98144
variable request_msg, reply_msg : msg_t;
99145
begin
100146
if use_readdatavalid then
101-
wait until readdatavalid = '1' and rising_edge(clk);
147+
wait until readdatavalid = '1' and not is_empty(acknowledge_queue) and rising_edge(clk);
102148
else
103149
-- Non-pipelined case: waits for slave to de-assert waitrequest and sample data after fixed_read_latency cycles.
104150
wait until rising_edge(clk) and waitrequest = '0' and read = '1';
@@ -115,5 +161,25 @@ begin
115161
delete(request_msg);
116162
end process;
117163

118-
burstcount <= "1";
164+
burst_read_capture : process
165+
variable request_msg, reply_msg : msg_t;
166+
variable burst : positive;
167+
begin
168+
wait until readdatavalid = '1' and not is_empty(burst_acknowledge_queue) and rising_edge(clk);
169+
burst_read_flag <= true;
170+
request_msg := pop(burst_acknowledge_queue);
171+
burst := pop(burstlen_queue);
172+
reply_msg := new_msg(sender => avmm_burst_rd_actor);
173+
push_integer(reply_msg, burst);
174+
push_std_ulogic_vector(reply_msg, readdata);
175+
for i in 1 to burst-1 loop
176+
wait until readdatavalid = '1' and rising_edge(clk) for 1 us;
177+
check_true(readdatavalid = '1', "avalon master burst readdatavalid timeout");
178+
push_std_ulogic_vector(reply_msg, readdata);
179+
end loop;
180+
reply(net, request_msg, reply_msg);
181+
delete(request_msg);
182+
burst_read_flag <= false;
183+
end process;
184+
119185
end architecture;

vunit/vhdl/verification_components/src/avalon_pkg.vhd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ package body avalon_pkg is
4545
return avalon_slave_t is
4646
begin
4747
return (p_actor => new_actor(name),
48-
p_ack_actor => new_actor(name&"_ack"),
48+
p_ack_actor => new_actor(name&" read-ack"),
4949
p_memory => to_vc_interface(memory, logger),
5050
p_logger => logger,
5151
readdatavalid_high_probability => readdatavalid_high_probability,

vunit/vhdl/verification_components/src/avalon_slave.vhd

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
-- Author Slawomir Siluk slaweksiluk@gazeta.pl
77
--
88
-- Avalon memory mapped slave wrapper for Vunit memory VC
9-
-- TODO:
10-
-- - support burstcount > 1
9+
1110
library ieee;
1211
use ieee.std_logic_1164.all;
1312
use ieee.numeric_std.all;
@@ -40,58 +39,64 @@ end entity;
4039

4140
architecture a of avalon_slave is
4241

43-
constant slave_write_msg : msg_type_t := new_msg_type("avmm slave write");
4442
constant slave_read_msg : msg_type_t := new_msg_type("avmm slave read");
4543

4644
begin
4745

48-
request : process
49-
variable wr_request_msg : msg_t;
46+
write_handler : process
47+
variable pending_writes : positive := 1;
48+
variable addr : natural;
49+
begin
50+
loop
51+
wait until write = '1' and waitrequest = '0' and rising_edge(clk);
52+
-- Burst write in progress
53+
if pending_writes > 1 then
54+
addr := addr + byteenable'length;
55+
pending_writes := pending_writes -1;
56+
write_word(avalon_slave.p_memory, addr, writedata);
57+
-- Burst start or single burst
58+
else
59+
addr := to_integer(unsigned(address));
60+
pending_writes := to_integer(unsigned(burstcount));
61+
write_word(avalon_slave.p_memory, addr, writedata);
62+
end if;
63+
end loop;
64+
end process;
65+
66+
read_request : process
5067
variable rd_request_msg : msg_t;
5168
begin
52-
wait until (write or read) = '1' and waitrequest = '0' and rising_edge(clk);
53-
check_false(write = '1' and read = '1');
54-
if write = '1' then
55-
wr_request_msg := new_msg(slave_write_msg, avalon_slave.p_actor);
56-
-- For write, address and data are passed to ack proc
57-
push_integer(wr_request_msg, to_integer(unsigned(address)));
58-
push_std_ulogic_vector(wr_request_msg, writedata);
59-
send(net, avalon_slave.p_ack_actor, wr_request_msg);
60-
elsif read = '1' then
61-
rd_request_msg := new_msg(slave_read_msg, avalon_slave.p_actor);
62-
-- For read, only address is passed to ack proc
63-
push_integer(rd_request_msg, to_integer(unsigned(address)));
64-
send(net, avalon_slave.p_ack_actor, rd_request_msg);
65-
end if;
69+
wait until read = '1' and waitrequest = '0' and rising_edge(clk);
70+
rd_request_msg := new_msg(slave_read_msg, avalon_slave.p_actor);
71+
-- For read, only address is passed to ack proc
72+
push_integer(rd_request_msg, to_integer(unsigned(burstcount)));
73+
push_integer(rd_request_msg, to_integer(unsigned(address)));
74+
send(net, avalon_slave.p_ack_actor, rd_request_msg);
6675
end process;
6776

68-
acknowledge : process
77+
read_handler : process
6978
variable request_msg : msg_t;
7079
variable msg_type : msg_type_t;
71-
variable data : std_logic_vector(writedata'range);
72-
variable addr : natural;
80+
variable baseaddr : natural;
81+
variable burst : positive;
7382
variable rnd : RandomPType;
7483
begin
7584
readdatavalid <= '0';
7685
receive(net, avalon_slave.p_ack_actor, request_msg);
7786
msg_type := message_type(request_msg);
7887

79-
if msg_type = slave_write_msg then
80-
addr := pop_integer(request_msg);
81-
data := pop_std_ulogic_vector(request_msg);
82-
write_word(avalon_slave.p_memory, addr, data);
83-
84-
elsif msg_type = slave_read_msg then
85-
data := (others => '0');
86-
addr := pop_integer(request_msg);
87-
data := read_word(avalon_slave.p_memory, addr, byteenable'length);
88-
while rnd.Uniform(0.0, 1.0) > avalon_slave.readdatavalid_high_probability loop
88+
if msg_type = slave_read_msg then
89+
burst := pop_integer(request_msg);
90+
baseaddr := pop_integer(request_msg);
91+
for i in 0 to burst-1 loop
92+
while rnd.Uniform(0.0, 1.0) > avalon_slave.readdatavalid_high_probability loop
93+
wait until rising_edge(clk);
94+
end loop;
95+
readdata <= read_word(avalon_slave.p_memory, baseaddr + byteenable'length*i, byteenable'length);
96+
readdatavalid <= '1';
8997
wait until rising_edge(clk);
98+
readdatavalid <= '0';
9099
end loop;
91-
readdata <= data;
92-
readdatavalid <= '1';
93-
wait until rising_edge(clk);
94-
readdatavalid <= '0';
95100

96101
else
97102
unexpected_msg_type(msg_type);

vunit/vhdl/verification_components/src/bus_master_pkg-body.vhd

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use ieee.numeric_std.all;
1010

1111
use work.queue_pkg.all;
1212
use work.sync_pkg.all;
13+
use work.queue_pkg.all;
14+
use work.check_pkg.all;
1315

1416
package body bus_master_pkg is
1517

@@ -96,6 +98,34 @@ package body bus_master_pkg is
9698
write_bus(net, bus_handle, to_address(bus_handle, address), data, byte_enable);
9799
end;
98100

101+
procedure burst_write_bus(signal net : inout network_t;
102+
constant bus_handle : bus_master_t;
103+
constant address : std_logic_vector;
104+
constant burst_length : positive;
105+
constant data : queue_t) is
106+
variable request_msg : msg_t := new_msg(bus_burst_write_msg);
107+
variable full_address : std_logic_vector(bus_handle.p_address_length-1 downto 0) := (others => '0');
108+
variable full_data : std_logic_vector(bus_handle.p_data_length-1 downto 0) := (others => '0');
109+
begin
110+
full_address(address'length-1 downto 0) := address;
111+
push_std_ulogic_vector(request_msg, full_address);
112+
push_integer(request_msg, burst_length);
113+
for i in 0 to burst_length-1 loop
114+
full_data(bus_handle.p_data_length-1 downto 0) := pop(data);
115+
push_std_ulogic_vector(request_msg, full_data);
116+
end loop;
117+
send(net, bus_handle.p_actor, request_msg);
118+
end procedure;
119+
120+
procedure burst_write_bus(signal net : inout network_t;
121+
constant bus_handle : bus_master_t;
122+
constant address : natural;
123+
constant burst_length : positive;
124+
constant data : queue_t) is
125+
begin
126+
burst_write_bus(net, bus_handle, to_address(bus_handle, address), burst_length, data);
127+
end procedure;
128+
99129
procedure check_bus(signal net : inout network_t;
100130
constant bus_handle : bus_master_t;
101131
constant address : std_logic_vector;
@@ -158,6 +188,30 @@ package body bus_master_pkg is
158188
read_bus(net, bus_handle, to_address(bus_handle, address), reference);
159189
end;
160190

191+
procedure burst_read_bus(signal net : inout network_t;
192+
constant bus_handle : bus_master_t;
193+
constant address : std_logic_vector;
194+
constant burst_length : positive;
195+
variable reference : inout bus_reference_t) is
196+
variable full_address : std_logic_vector(bus_handle.p_address_length-1 downto 0) := (others => '0');
197+
alias request_msg : msg_t is reference;
198+
begin
199+
request_msg := new_msg(bus_burst_read_msg);
200+
full_address(address'length-1 downto 0) := address;
201+
push_std_ulogic_vector(request_msg, full_address);
202+
push_integer(request_msg, burst_length);
203+
send(net, bus_handle.p_actor, request_msg);
204+
end procedure;
205+
206+
procedure burst_read_bus(signal net : inout network_t;
207+
constant bus_handle : bus_master_t;
208+
constant address : natural;
209+
constant burst_length : positive;
210+
variable reference : inout bus_reference_t) is
211+
begin
212+
burst_read_bus(net, bus_handle, to_address(bus_handle, address), burst_length, reference);
213+
end procedure;
214+
161215
-- Await read bus reply
162216
procedure await_read_bus_reply(signal net : inout network_t;
163217
variable reference : inout bus_reference_t;
@@ -171,6 +225,25 @@ package body bus_master_pkg is
171225
delete(reply_msg);
172226
end procedure;
173227

228+
procedure await_burst_read_bus_reply(signal net : inout network_t;
229+
constant bus_handle : bus_master_t;
230+
constant data : queue_t;
231+
variable reference : inout bus_reference_t) is
232+
variable reply_msg : msg_t;
233+
alias request_msg : msg_t is reference;
234+
variable d : std_logic_vector(bus_handle.p_data_length-1 downto 0);
235+
variable burst_length : positive;
236+
begin
237+
receive_reply(net, request_msg, reply_msg);
238+
burst_length := pop_integer(reply_msg);
239+
for i in 0 to burst_length-1 loop
240+
d := pop_std_ulogic_vector(reply_msg)(d'range);
241+
push(data, d);
242+
end loop;
243+
delete(request_msg);
244+
delete(reply_msg);
245+
end procedure;
246+
174247
-- Blocking read with immediate reply
175248
procedure read_bus(signal net : inout network_t;
176249
constant bus_handle : bus_master_t;
@@ -191,6 +264,26 @@ package body bus_master_pkg is
191264
read_bus(net, bus_handle, to_address(bus_handle, address), data);
192265
end;
193266

267+
procedure burst_read_bus(signal net : inout network_t;
268+
constant bus_handle : bus_master_t;
269+
constant address : std_logic_vector;
270+
constant burst_length : positive;
271+
constant data : queue_t) is
272+
variable reference : bus_reference_t;
273+
begin
274+
burst_read_bus(net, bus_handle, address, burst_length, reference);
275+
await_burst_read_bus_reply(net, bus_handle, data, reference);
276+
end procedure;
277+
278+
procedure burst_read_bus(signal net : inout network_t;
279+
constant bus_handle : bus_master_t;
280+
constant address : natural;
281+
constant burst_length : positive;
282+
constant data : queue_t) is
283+
begin
284+
burst_read_bus(net, bus_handle, to_address(bus_handle, address), burst_length, data);
285+
end procedure;
286+
194287
procedure wait_until_read_equals(
195288
signal net : inout network_t;
196289
bus_handle : bus_master_t;

0 commit comments

Comments
 (0)