-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathavm_pause.vhd
171 lines (140 loc) · 5.55 KB
/
avm_pause.vhd
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
-- This module inserts empty wait cycles into an Avalon Memory Map stream.
-- The throughput is 1 - 1/G_PAUSE.
-- So a value of 4 results in a 75% throughput.
--
-- Created by Michael Jørgensen in 2022 (mjoergen.github.io/HyperRAM).
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.numeric_std_unsigned.all;
entity avm_pause is
generic (
G_REQ_PAUSE : integer;
G_RESP_PAUSE : integer;
G_ADDRESS_SIZE : integer; -- Number of bits
G_DATA_SIZE : integer -- Number of bits
);
port (
clk_i : in std_logic;
rst_i : in std_logic;
s_avm_write_i : in std_logic;
s_avm_read_i : in std_logic;
s_avm_address_i : in std_logic_vector(G_ADDRESS_SIZE-1 downto 0);
s_avm_writedata_i : in std_logic_vector(G_DATA_SIZE-1 downto 0);
s_avm_byteenable_i : in std_logic_vector(G_DATA_SIZE/8-1 downto 0);
s_avm_burstcount_i : in std_logic_vector(7 downto 0);
s_avm_readdata_o : out std_logic_vector(G_DATA_SIZE-1 downto 0);
s_avm_readdatavalid_o : out std_logic;
s_avm_waitrequest_o : out std_logic;
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_pause;
architecture synthesis of avm_pause is
signal rd_burstcount : integer range 0 to 255;
signal cnt : std_logic_vector(16 downto 0);
signal inc_s : std_logic_vector(16 downto 0);
signal allow : std_logic;
type read_resp_t is array (0 to G_RESP_PAUSE) of std_logic_vector(G_DATA_SIZE downto 0);
signal read_resp : read_resp_t;
signal lfsr_output : std_logic_vector(21 downto 0);
signal lfsr_reverse : std_logic_vector(21 downto 0);
signal lfsr_random : std_logic_vector(21 downto 0);
signal lfsr_update_s : std_logic;
begin
----------------------
-- Handle read burst
---------------------
p_rd_burstcount : process (clk_i)
begin
if rising_edge(clk_i) then
if s_avm_readdatavalid_o then
assert rst_i = '1' or rd_burstcount /= 0
report "s_avm_readdatavalid_o asserted when rd_burstcount = 0";
rd_burstcount <= rd_burstcount - 1;
end if;
if s_avm_read_i and not s_avm_waitrequest_o then
rd_burstcount <= to_integer(s_avm_burstcount_i);
end if;
if rst_i = '1' then
rd_burstcount <= 0;
end if;
end if;
end process p_rd_burstcount;
------------------------------------
-- Insert random pauses in requests
------------------------------------
inc_s(16 downto 16-G_REQ_PAUSE+1) <= (others => '0');
inc_s(16-G_REQ_PAUSE downto 0) <= lfsr_random(16-G_REQ_PAUSE downto 0);
p_cnt : process (clk_i)
begin
if rising_edge(clk_i) then
if G_REQ_PAUSE > 0 then
cnt <= ("0" & cnt(15 downto 0)) + inc_s;
end if;
if rst_i = '1' then
cnt <= (others => '0');
end if;
end if;
end process p_cnt;
allow <= not cnt(16);
m_avm_write_o <= s_avm_write_i and allow when rd_burstcount = 0 else '0';
m_avm_read_o <= s_avm_read_i and allow when rd_burstcount = 0 else '0';
m_avm_address_o <= s_avm_address_i;
m_avm_writedata_o <= s_avm_writedata_i;
m_avm_byteenable_o <= s_avm_byteenable_i;
m_avm_burstcount_o <= s_avm_burstcount_i;
s_avm_waitrequest_o <= '1' when rd_burstcount /= 0 else
m_avm_waitrequest_i or not allow;
-------------------
-- Handle response
-------------------
read_resp(0)(G_DATA_SIZE-1 downto 0) <= m_avm_readdata_i;
read_resp(0)(G_DATA_SIZE) <= m_avm_readdatavalid_i;
gen: for i in 1 to G_RESP_PAUSE generate
p_resp : process (clk_i)
begin
if rising_edge(clk_i) then
read_resp(i) <= read_resp(i-1);
if read_resp(i-1)(G_DATA_SIZE) = '0' then
read_resp(i) <= (others => '0');
end if;
if rst_i = '1' then
read_resp(i) <= (others => '0');
end if;
end if;
end process p_resp;
end generate gen;
s_avm_readdata_o <= read_resp(G_RESP_PAUSE)(G_DATA_SIZE-1 downto 0);
s_avm_readdatavalid_o <= read_resp(G_RESP_PAUSE)(G_DATA_SIZE);
--------------------------------------
-- Instantiate randon number generator
--------------------------------------
i_lfsr : entity work.lfsr
generic map (
G_WIDTH => 22,
G_TAPS => X"000000000020069E" -- See https://users.ece.cmu.edu/~koopman/lfsr/22.txt
)
port map (
clk_i => clk_i,
rst_i => rst_i,
update_i => '1',
load_i => '0',
load_val_i => (others => '1'),
output_o => lfsr_output
); -- i_lfsr
p_reverse : process(all)
begin
for i in lfsr_output'low to lfsr_output'high loop
lfsr_reverse(lfsr_output'high - i) <= lfsr_output(i);
end loop;
end process p_reverse;
lfsr_random <= std_logic_vector(unsigned(lfsr_output) + unsigned(lfsr_reverse));
end architecture synthesis;