-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathhyperram_ctrl.vhd
294 lines (258 loc) · 10.3 KB
/
hyperram_ctrl.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
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
-- This is the main state machine of the HyperRAM controller.
-- The purpose is to implement the HyperBus protocol, i.e.
-- to decode the Avalon Memory Map requests and generate the control
-- signals for the HyperRAM device.
--
-- Bit 31 of avm_address_i is used to indicate register space.
--
-- Created by Michael Jørgensen in 2022 (mjoergen.github.io/HyperRAM).
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity hyperram_ctrl is
generic (
G_LATENCY : integer
);
port (
clk_i : in std_logic;
rst_i : in std_logic;
-- Avalon Memory Map
avm_write_i : in std_logic;
avm_read_i : in std_logic;
avm_address_i : in std_logic_vector(31 downto 0);
avm_writedata_i : in std_logic_vector(15 downto 0);
avm_byteenable_i : in std_logic_vector(1 downto 0);
avm_burstcount_i : in std_logic_vector(7 downto 0);
avm_readdata_o : out std_logic_vector(15 downto 0);
avm_readdatavalid_o : out std_logic;
avm_waitrequest_o : out std_logic;
-- Statistics
count_long_o : out unsigned(31 downto 0);
count_short_o : out unsigned(31 downto 0);
underrun_o : out std_logic;
timeout_o : out std_logic;
-- HyperBus control signals
hb_rstn_o : out std_logic;
hb_csn_o : out std_logic;
hb_ck_ddr_o : out std_logic_vector(1 downto 0);
hb_dq_ddr_in_i : in std_logic_vector(15 downto 0);
hb_dq_ddr_out_o : out std_logic_vector(15 downto 0);
hb_dq_oe_o : out std_logic;
hb_dq_ie_i : in std_logic;
hb_rwds_ddr_out_o : out std_logic_vector(1 downto 0);
hb_rwds_oe_o : out std_logic;
hb_rwds_in_i : in std_logic;
hb_read_o : out std_logic
);
end entity hyperram_ctrl;
architecture synthesis of hyperram_ctrl is
type state_t is (
INIT_ST,
COMMAND_ADDRESS_ST,
WAIT_ST,
WAIT2_ST,
SAMPLE_RWDS_ST,
LATENCY_ST,
READ_ST,
WRITE_ST,
WRITE_BURST_ST,
RECOVERY_ST
);
signal state : state_t;
signal writedata : std_logic_vector(15 downto 0);
signal byteenable : std_logic_vector(1 downto 0);
signal read : std_logic;
signal config : std_logic;
signal burst_count : integer range 0 to 255;
signal command_address : std_logic_vector(47 downto 0);
signal ca_count : integer range 0 to 3;
signal latency_count : integer range 0 to 15;
signal read_clk_count : integer range 0 to 256;
signal read_return_count : integer range 0 to 255;
signal write_clk_count : integer range 0 to 255;
signal recovery_count : integer range 0 to 255;
-- Decode Command/Address value
constant R_CA_RW : integer := 47;
constant R_CA_AS : integer := 46;
constant R_CA_BURST : integer := 45;
subtype R_CA_ADDR_MSB is natural range 44 downto 16;
subtype R_CA_RESERVED is natural range 15 downto 3;
subtype R_CA_ADDR_LSB is natural range 2 downto 0;
-- Statistics
signal count_long : unsigned(31 downto 0);
signal count_short : unsigned(31 downto 0);
signal hb_dq_ie_d : std_logic;
signal timeout_count : natural range 0 to 15;
begin
p_fsm : process (clk_i)
begin
if rising_edge(clk_i) then
hb_rstn_o <= '1';
hb_dq_oe_o <= '0';
hb_rwds_oe_o <= '0';
hb_read_o <= '0';
underrun_o <= '0';
timeout_o <= '0';
hb_dq_ie_d <= hb_dq_ie_i;
case state is
when INIT_ST =>
if avm_read_i = '1' or avm_write_i = '1' then
read <= avm_read_i;
config <= avm_address_i(31);
writedata <= avm_writedata_i;
byteenable <= avm_byteenable_i;
burst_count <= to_integer(unsigned(avm_burstcount_i));
command_address(R_CA_RW) <= avm_read_i;
command_address(R_CA_AS) <= avm_address_i(31);
command_address(R_CA_BURST) <= '1';
command_address(R_CA_ADDR_MSB) <= '0' & avm_address_i(30 downto 3);
command_address(R_CA_RESERVED) <= "0000000000000";
command_address(R_CA_ADDR_LSB) <= avm_address_i(2 downto 0);
avm_waitrequest_o <= '1';
hb_csn_o <= '0';
hb_dq_oe_o <= '1';
ca_count <= 2;
if avm_address_i(31) = '1' then
ca_count <= 3;
end if;
state <= COMMAND_ADDRESS_ST;
end if;
when COMMAND_ADDRESS_ST =>
command_address <= command_address(31 downto 0) & writedata(15 downto 0);
if ca_count > 0 then
hb_dq_oe_o <= '1';
hb_ck_ddr_o <= "10";
ca_count <= ca_count - 1;
else
if config = '1' and read = '0' then
recovery_count <= 3;
state <= RECOVERY_ST;
else
state <= WAIT_ST;
end if;
end if;
when WAIT_ST =>
state <= WAIT2_ST;
when WAIT2_ST =>
state <= SAMPLE_RWDS_ST;
when SAMPLE_RWDS_ST =>
if hb_rwds_in_i = '1' then
latency_count <= 2*G_LATENCY - 5;
count_long <= count_long + 1;
state <= LATENCY_ST;
else
count_short <= count_short + 1;
if G_LATENCY >= 5 then
latency_count <= G_LATENCY - 5;
state <= LATENCY_ST;
else
if read = '1' then
read_clk_count <= burst_count+1;
read_return_count <= burst_count;
hb_read_o <= '1';
timeout_count <= 15;
state <= READ_ST;
else
write_clk_count <= burst_count;
hb_dq_oe_o <= '1';
hb_rwds_oe_o <= '1';
state <= WRITE_ST;
end if;
end if;
end if;
when LATENCY_ST =>
if latency_count > 0 then
latency_count <= latency_count - 1;
else
if read = '1' then
read_clk_count <= burst_count+1;
read_return_count <= burst_count;
hb_read_o <= '1';
timeout_count <= 15;
state <= READ_ST;
else
write_clk_count <= burst_count;
hb_dq_oe_o <= '1';
hb_rwds_oe_o <= '1';
state <= WRITE_ST;
end if;
end if;
when READ_ST =>
hb_read_o <= '1';
if read_clk_count > 0 then
read_clk_count <= read_clk_count - 1;
else
hb_ck_ddr_o <= "00";
end if;
if hb_dq_ie_d = '1' and hb_dq_ie_i = '0' then
underrun_o <= '1';
end if;
if timeout_count > 0 then
timeout_count <= timeout_count - 1;
else
timeout_o <= '1';
end if;
if hb_dq_ie_i = '1' then
timeout_count <= 1;
read_return_count <= read_return_count - 1;
if read_return_count = 1 then
hb_csn_o <= '1';
hb_ck_ddr_o <= "00";
recovery_count <= 1;
state <= RECOVERY_ST;
end if;
end if;
when WRITE_ST | WRITE_BURST_ST =>
state <= WRITE_BURST_ST;
writedata <= avm_writedata_i;
byteenable <= avm_byteenable_i;
hb_dq_oe_o <= '1';
hb_rwds_oe_o <= '1';
avm_waitrequest_o <= '0';
if avm_write_i = '1' or state = WRITE_ST then
hb_ck_ddr_o <= "10";
if write_clk_count > 0 then
write_clk_count <= write_clk_count - 1;
if write_clk_count = 1 then
recovery_count <= 2;
hb_dq_oe_o <= '0';
hb_rwds_oe_o <= '0';
avm_waitrequest_o <= '1';
state <= RECOVERY_ST;
end if;
end if;
else
hb_ck_ddr_o <= "00";
end if;
when RECOVERY_ST =>
hb_csn_o <= '1';
hb_ck_ddr_o <= "00";
if recovery_count > 0 then
recovery_count <= recovery_count - 1;
else
avm_waitrequest_o <= '0';
state <= INIT_ST;
end if;
end case;
if rst_i = '1' then
avm_waitrequest_o <= '1';
state <= INIT_ST;
hb_rstn_o <= '0';
hb_ck_ddr_o <= (others => '0');
hb_csn_o <= '1';
hb_dq_oe_o <= '0';
hb_rwds_oe_o <= '0';
count_long <= (others => '0');
count_short <= (others => '0');
end if;
end if;
end process p_fsm;
avm_readdata_o <= hb_dq_ddr_in_i;
avm_readdatavalid_o <= hb_dq_ie_i when state = READ_ST else '0';
hb_dq_ddr_out_o <= avm_writedata_i when state = WRITE_BURST_ST else
command_address(47 downto 32);
hb_rwds_ddr_out_o <= not byteenable when state = WRITE_ST or state = WRITE_BURST_ST else "00";
-- Statistics
count_long_o <= count_long;
count_short_o <= count_short;
end architecture synthesis;