-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathavm_arbit.vhd
More file actions
333 lines (290 loc) · 13.6 KB
/
Copy pathavm_arbit.vhd
File metadata and controls
333 lines (290 loc) · 13.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std_unsigned.all;
-- This arbitrates fairly between two Masters connected to a single Slave
-- This file is copied from https://github.com/MJoergen/Avalon
-- It is a highly optimized arbiter, designed to minimize waiting
-- time when switching between the two Masters.
-- It works in round-robin fashion, so whenever one Master has finished a
-- transaction, the other Master is granted access.
entity avm_arbit is
generic (
G_PREFER_SWAP : boolean;
G_FREQ_HZ : integer := 100_000_000; -- 100 MHz
G_ADDRESS_SIZE : integer;
G_DATA_SIZE : integer
);
port (
clk_i : in std_logic;
rst_i : in std_logic;
-- Slave interface 0 (input)
s0_avm_write_i : in std_logic;
s0_avm_read_i : in std_logic;
s0_avm_address_i : in std_logic_vector(G_ADDRESS_SIZE - 1 downto 0);
s0_avm_writedata_i : in std_logic_vector(G_DATA_SIZE - 1 downto 0);
s0_avm_byteenable_i : in std_logic_vector(G_DATA_SIZE / 8 - 1 downto 0);
s0_avm_burstcount_i : in std_logic_vector(7 downto 0);
s0_avm_readdata_o : out std_logic_vector(G_DATA_SIZE - 1 downto 0);
s0_avm_readdatavalid_o : out std_logic;
s0_avm_waitrequest_o : out std_logic;
-- Slave interface 1 (input)
s1_avm_write_i : in std_logic;
s1_avm_read_i : in std_logic;
s1_avm_address_i : in std_logic_vector(G_ADDRESS_SIZE - 1 downto 0);
s1_avm_writedata_i : in std_logic_vector(G_DATA_SIZE - 1 downto 0);
s1_avm_byteenable_i : in std_logic_vector(G_DATA_SIZE / 8 - 1 downto 0);
s1_avm_burstcount_i : in std_logic_vector(7 downto 0);
s1_avm_readdata_o : out std_logic_vector(G_DATA_SIZE - 1 downto 0);
s1_avm_readdatavalid_o : out std_logic;
s1_avm_waitrequest_o : out std_logic;
-- Master interface (output)
m_avm_write_o : out std_logic;
m_avm_read_o : out std_logic;
m_avm_address_o : out std_logic_vector(G_ADDRESS_SIZE - 1 downto 0);
m_avm_writedata_o : out std_logic_vector(G_DATA_SIZE - 1 downto 0);
m_avm_byteenable_o : out std_logic_vector(G_DATA_SIZE / 8 - 1 downto 0);
m_avm_burstcount_o : out std_logic_vector(7 downto 0);
m_avm_readdata_i : in std_logic_vector(G_DATA_SIZE - 1 downto 0);
m_avm_readdatavalid_i : in std_logic;
m_avm_waitrequest_i : in std_logic
);
end entity avm_arbit;
architecture synthesis of avm_arbit is
signal s0_active_req : std_logic;
signal s1_active_req : std_logic;
signal s0_active_grant : std_logic := '0';
signal s1_active_grant : std_logic := '0';
signal active_grants : std_logic_vector(1 downto 0);
signal s0_last : std_logic;
signal s1_last : std_logic;
signal last_grant : std_logic := '0';
signal swapped : std_logic := '0';
signal burstcount : std_logic_vector(7 downto 0);
-- Debug counters. Not connected anywhere.
signal cnt : integer range 0 to G_FREQ_HZ - 1;
signal cnt_s0_active_grant : integer range 0 to G_FREQ_HZ - 1;
signal cnt_s1_active_grant : integer range 0 to G_FREQ_HZ - 1;
signal cnt_s0_waiting : integer range 0 to G_FREQ_HZ - 1;
signal cnt_s1_waiting : integer range 0 to G_FREQ_HZ - 1;
signal cnt_s0_waiting_tot : integer range 0 to G_FREQ_HZ - 1;
signal cnt_s1_waiting_tot : integer range 0 to G_FREQ_HZ - 1;
signal cnt_s0_waiting_max : integer range 0 to G_FREQ_HZ - 1;
signal cnt_s1_waiting_max : integer range 0 to G_FREQ_HZ - 1;
begin
-- Debug statistics to measure performance. Only used in simulation.
-- Will automatically be optimized away during synthesis
-- because the registers are not used anywhere.
cnt_proc : process (clk_i)
begin
if rising_edge(clk_i) then
if s0_active_req = '1' and s0_active_grant = '0' then
cnt_s0_waiting <= cnt_s0_waiting + 1;
cnt_s0_waiting_tot <= cnt_s0_waiting_tot + 1;
end if;
if s1_active_req = '1' and s1_active_grant = '0' then
cnt_s1_waiting <= cnt_s1_waiting + 1;
cnt_s1_waiting_tot <= cnt_s1_waiting_tot + 1;
end if;
if s0_active_grant = '1' then
if cnt_s0_waiting > cnt_s0_waiting_max then
cnt_s0_waiting_max <= cnt_s0_waiting;
end if;
cnt_s0_waiting <= 0;
cnt_s0_active_grant <= cnt_s0_active_grant + 1;
end if;
if s1_active_grant = '1' then
if cnt_s1_waiting > cnt_s1_waiting_max then
cnt_s1_waiting_max <= cnt_s1_waiting;
end if;
cnt_s1_waiting <= 0;
cnt_s1_active_grant <= cnt_s1_active_grant + 1;
end if;
if rst_i = '1' or cnt = G_FREQ_HZ - 1 then
cnt_s0_waiting <= 0;
cnt_s1_waiting <= 0;
cnt_s0_waiting_tot <= 0;
cnt_s1_waiting_tot <= 0;
cnt_s0_waiting_max <= 0;
cnt_s1_waiting_max <= 0;
cnt_s0_active_grant <= 0;
cnt_s1_active_grant <= 0;
cnt <= 0;
else
cnt <= cnt + 1;
end if;
end if;
end process cnt_proc;
-- Validation check that the two Masters are not granted access at the same time.
assert not (s0_active_grant and s1_active_grant);
s0_avm_waitrequest_o <= m_avm_waitrequest_i or not s0_active_grant;
s1_avm_waitrequest_o <= m_avm_waitrequest_i or not s1_active_grant;
s0_active_req <= s0_avm_write_i or s0_avm_read_i;
s1_active_req <= s1_avm_write_i or s1_avm_read_i;
-- Determine remaining length of current transaction.
burstcount_proc : process (clk_i)
begin
if rising_edge(clk_i) then
if s0_avm_write_i = '1' and s0_avm_waitrequest_o = '0' and burstcount = 0 then
burstcount <= std_logic_vector(unsigned(s0_avm_burstcount_i) - 1);
elsif s0_avm_read_i and not s0_avm_waitrequest_o then
burstcount <= s0_avm_burstcount_i;
elsif s1_avm_write_i = '1' and s1_avm_waitrequest_o = '0' and burstcount = 0 then
burstcount <= std_logic_vector(unsigned(s1_avm_burstcount_i) - 1);
elsif s1_avm_read_i and not s1_avm_waitrequest_o then
burstcount <= s1_avm_burstcount_i;
else
if (s0_avm_write_i and not s0_avm_waitrequest_o) or
s0_avm_readdatavalid_o or
(s1_avm_write_i and not s1_avm_waitrequest_o) or
s1_avm_readdatavalid_o then
burstcount <= std_logic_vector(unsigned(burstcount) - 1);
end if;
end if;
if rst_i = '1' then
burstcount <= X"00";
end if;
end if;
end process burstcount_proc;
-- Determine whether the current access is finished and no new transaction has begun.
last_proc : process (all)
begin
s0_last <= '0';
s1_last <= '0';
if s0_active_grant = '1' then
if burstcount = X"00" or (burstcount = X"01" and s0_avm_readdatavalid_o = '1')
or (burstcount = X"01" and s0_avm_write_i = '1') then
if s0_active_req = '0'
or (burstcount = X"01" and s0_avm_readdatavalid_o = '1' and s0_avm_waitrequest_o = '1')
or (burstcount = X"01" and s0_avm_write_i = '1' and s0_avm_waitrequest_o = '0')
or (s0_avm_burstcount_i = X"01" and s0_avm_write_i = '1' and s0_avm_waitrequest_o = '0') then
s0_last <= '1';
end if;
end if;
end if;
if s1_active_grant = '1' then
if burstcount = X"00" or (burstcount = X"01" and s1_avm_readdatavalid_o = '1')
or (burstcount = X"01" and s1_avm_write_i = '1') then
if s1_active_req = '0'
or (burstcount = X"01" and s1_avm_readdatavalid_o = '1' and s1_avm_waitrequest_o = '1')
or (burstcount = X"01" and s1_avm_write_i = '1' and s1_avm_waitrequest_o = '0')
or (s1_avm_burstcount_i = X"01" and s1_avm_write_i = '1' and s1_avm_waitrequest_o = '0') then
s1_last <= '1';
end if;
end if;
end if;
end process last_proc;
-- Determine who to grant access next.
active_grants <= s1_active_grant & s0_active_grant;
grant_proc : process (clk_i)
begin
if rising_edge(clk_i) then
-- Last clock cycle in a burst transfer
if s0_last = '1' then
s0_active_grant <= '0';
end if;
if s1_last = '1' then
s1_active_grant <= '0';
end if;
case active_grants is
when "00" =>
if s0_active_req = '1' and (last_grant = '1' or s1_active_req = '0') then
s0_active_grant <= '1';
last_grant <= '0';
end if;
if s1_active_req = '1' and (last_grant = '0' or s0_active_req = '0') then
s1_active_grant <= '1';
last_grant <= '1';
end if;
when "01" =>
if s0_last = '1' then
if s0_active_req = '1' and not (last_grant = '0' and s1_active_req = '1') then
s0_active_grant <= '1';
last_grant <= '0';
elsif s1_active_req = '1' and not (last_grant = '1' and s0_active_req = '1') then
s1_active_grant <= '1';
s0_active_grant <= '0';
last_grant <= '1';
end if;
if G_PREFER_SWAP then
-- If no pending requests, pre-emptively give grant to other
if s1_active_req = '0' and s0_active_req = '0' and swapped = '0' then
s1_active_grant <= '1';
last_grant <= '1';
swapped <= '1';
end if;
if s1_active_req = '0' and s0_active_req = '0' and swapped = '1' then
s0_active_grant <= '1';
last_grant <= '0';
end if;
else
-- If no pending requests, keep the existing grant
if s1_active_req = '0' and s0_active_req = '0' then
s0_active_grant <= '1';
last_grant <= '0';
end if;
end if;
end if;
when "10" =>
if s1_last = '1' then
if s1_active_req = '1' and not (last_grant = '1' and s0_active_req = '1') then
s1_active_grant <= '1';
last_grant <= '1';
elsif s0_active_req = '1' and not (last_grant = '0' and s1_active_req = '1') then
s0_active_grant <= '1';
s1_active_grant <= '0';
last_grant <= '0';
end if;
if G_PREFER_SWAP then
-- If no pending requests, pre-emptively give grant to other
if s1_active_req = '0' and s0_active_req = '0' and swapped = '0' then
s0_active_grant <= '1';
last_grant <= '0';
swapped <= '1';
end if;
if s1_active_req = '0' and s0_active_req = '0' and swapped = '1' then
s1_active_grant <= '1';
last_grant <= '1';
end if;
else
-- If no pending requests, keep the existing grant
if s1_active_req = '0' and s0_active_req = '0' then
s1_active_grant <= '1';
last_grant <= '1';
end if;
end if;
end if;
when others =>
report "S0 and S1 both active"
severity failure;
end case;
if s1_active_req = '1' or s0_active_req = '1' then
swapped <= '0';
end if;
if rst_i = '1' then
s0_active_grant <= '0';
s1_active_grant <= '0';
last_grant <= '1';
end if;
end if;
end process grant_proc;
-- Generate output signals combinatorially
m_avm_write_o <= s0_avm_write_i and s0_active_grant when last_grant = '0' else
s1_avm_write_i and s1_active_grant;
m_avm_read_o <= s0_avm_read_i and s0_active_grant when last_grant = '0' else
s1_avm_read_i and s1_active_grant;
m_avm_address_o <= s0_avm_address_i when last_grant = '0' else
s1_avm_address_i;
m_avm_writedata_o <= s0_avm_writedata_i when last_grant = '0' else
s1_avm_writedata_i;
m_avm_byteenable_o <= s0_avm_byteenable_i when last_grant = '0' else
s1_avm_byteenable_i;
m_avm_burstcount_o <= s0_avm_burstcount_i when last_grant = '0' else
s1_avm_burstcount_i;
s0_avm_readdata_o <= m_avm_readdata_i;
s0_avm_readdatavalid_o <= m_avm_readdatavalid_i when last_grant = '0' else
'0';
s1_avm_readdata_o <= m_avm_readdata_i;
s1_avm_readdatavalid_o <= m_avm_readdatavalid_i when last_grant = '1' else
'0';
end architecture synthesis;