1 | ------------------------------------------------------------------------------- |
---|
2 | -- |
---|
3 | -- SD/MMC Bootloader |
---|
4 | -- Sample client for loading an image to asynchronous SRAM |
---|
5 | -- |
---|
6 | -- $Id: ram_loader.vhd 77 2009-04-01 19:53:14Z arniml $ |
---|
7 | -- |
---|
8 | -- Copyright (c) 2005, Arnim Laeuger (arniml@opencores.org) |
---|
9 | -- |
---|
10 | -- All rights reserved, see COPYING. |
---|
11 | -- |
---|
12 | -- Redistribution and use in source and synthezised forms, with or without |
---|
13 | -- modification, are permitted provided that the following conditions are met: |
---|
14 | -- |
---|
15 | -- Redistributions of source code must retain the above copyright notice, |
---|
16 | -- this list of conditions and the following disclaimer. |
---|
17 | -- |
---|
18 | -- Redistributions in synthesized form must reproduce the above copyright |
---|
19 | -- notice, this list of conditions and the following disclaimer in the |
---|
20 | -- documentation and/or other materials provided with the distribution. |
---|
21 | -- |
---|
22 | -- Neither the name of the author nor the names of other contributors may |
---|
23 | -- be used to endorse or promote products derived from this software without |
---|
24 | -- specific prior written permission. |
---|
25 | -- |
---|
26 | -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
27 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
---|
28 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
---|
29 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE |
---|
30 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
---|
31 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
---|
32 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
---|
33 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
---|
34 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
---|
35 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
---|
36 | -- POSSIBILITY OF SUCH DAMAGE. |
---|
37 | -- |
---|
38 | -- Please report bugs to the author, but before you do so, please |
---|
39 | -- make sure that this is not a derivative work and that |
---|
40 | -- you have the latest version of this file. |
---|
41 | -- |
---|
42 | -- The latest version of this file can be found at: |
---|
43 | -- http://www.opencores.org/projects.cgi/web/spi_boot/overview |
---|
44 | -- |
---|
45 | ------------------------------------------------------------------------------- |
---|
46 | |
---|
47 | library ieee; |
---|
48 | use ieee.std_logic_1164.all; |
---|
49 | |
---|
50 | |
---|
51 | entity ram_loader is |
---|
52 | |
---|
53 | port ( |
---|
54 | -- Global Interface ------------------------------------------------------- |
---|
55 | clk_i : in std_logic; |
---|
56 | reset_i : in std_logic; |
---|
57 | lamp_o : out std_logic; |
---|
58 | -- Config Interface ------------------------------------------------------- |
---|
59 | cfg_clk_i : in std_logic; |
---|
60 | cfg_data_i : in std_logic; |
---|
61 | start_o : out std_logic; |
---|
62 | mode_o : out std_logic; |
---|
63 | done_o : out std_logic; |
---|
64 | detached_i : in std_logic; |
---|
65 | -- Asynchronous RAM Interface --------------------------------------------- |
---|
66 | ram_addr_o : out std_logic_vector(15 downto 0); |
---|
67 | ram_data_b : out std_logic_vector( 7 downto 0); |
---|
68 | ram_ce_no : out std_logic_vector( 3 downto 0); |
---|
69 | ram_oe_no : out std_logic; |
---|
70 | ram_we_no : out std_logic |
---|
71 | ); |
---|
72 | |
---|
73 | end ram_loader; |
---|
74 | |
---|
75 | |
---|
76 | library ieee; |
---|
77 | use ieee.numeric_std.all; |
---|
78 | |
---|
79 | architecture rtl of ram_loader is |
---|
80 | |
---|
81 | signal addr_q : unsigned(17 downto 0); |
---|
82 | signal inc_addr_s : boolean; |
---|
83 | |
---|
84 | signal shift_dat_q : std_logic_vector(7 downto 0); |
---|
85 | signal ser_dat_q : std_logic_vector(7 downto 0); |
---|
86 | signal bit_q : unsigned(2 downto 0); |
---|
87 | signal bit_ovfl_q : boolean; |
---|
88 | |
---|
89 | type fsm_t is (IDLE, |
---|
90 | WE_ON, |
---|
91 | WE_OFF, |
---|
92 | INC_ADDR1, INC_ADDR2, |
---|
93 | FINISHED); |
---|
94 | signal fsm_s, |
---|
95 | fsm_q : fsm_t; |
---|
96 | signal done_q : std_logic; |
---|
97 | signal done_s : boolean; |
---|
98 | signal mode_q, |
---|
99 | mode_s : std_logic; |
---|
100 | |
---|
101 | signal ram_we_n_q, |
---|
102 | ram_we_n_s : std_logic; |
---|
103 | signal ram_ce_n_q, |
---|
104 | ram_ce_n_s : std_logic_vector(3 downto 0); |
---|
105 | |
---|
106 | type start_fsm_t is (WAIT_DETACH, |
---|
107 | CHECK_NO_DONE, |
---|
108 | WAIT_DONE); |
---|
109 | signal start_fsm_s, |
---|
110 | start_fsm_q : start_fsm_t; |
---|
111 | |
---|
112 | signal start_s, |
---|
113 | start_q : std_logic; |
---|
114 | signal enable_s, |
---|
115 | enable_q : boolean; |
---|
116 | |
---|
117 | begin |
---|
118 | |
---|
119 | ----------------------------------------------------------------------------- |
---|
120 | -- Process seq |
---|
121 | -- |
---|
122 | -- Purpose: |
---|
123 | -- Implements the sequential elements clocked with cfg_clk_i. |
---|
124 | -- |
---|
125 | seq: process (cfg_clk_i, reset_i) |
---|
126 | begin |
---|
127 | if reset_i = '0' then |
---|
128 | addr_q <= (others => '0'); |
---|
129 | shift_dat_q <= (others => '0'); |
---|
130 | ser_dat_q <= (others => '0'); |
---|
131 | bit_q <= (others => '0'); |
---|
132 | bit_ovfl_q <= false; |
---|
133 | fsm_q <= IDLE; |
---|
134 | ram_we_n_q <= '1'; |
---|
135 | ram_ce_n_q <= (others => '1'); |
---|
136 | done_q <= '0'; |
---|
137 | mode_q <= '0'; |
---|
138 | |
---|
139 | elsif cfg_clk_i'event and cfg_clk_i = '1' then |
---|
140 | if inc_addr_s then |
---|
141 | addr_q <= addr_q + 1; |
---|
142 | end if; |
---|
143 | |
---|
144 | if enable_q then |
---|
145 | bit_q <= bit_q + 1; |
---|
146 | bit_ovfl_q <= bit_q = 7; |
---|
147 | |
---|
148 | shift_dat_q(0) <= cfg_data_i; |
---|
149 | shift_dat_q(7 downto 1) <= shift_dat_q(6 downto 0); |
---|
150 | end if; |
---|
151 | |
---|
152 | -- update register when 8 serial bits have been shifted in |
---|
153 | if bit_ovfl_q then |
---|
154 | ser_dat_q <= shift_dat_q; |
---|
155 | end if; |
---|
156 | |
---|
157 | fsm_q <= fsm_s; |
---|
158 | |
---|
159 | ram_we_n_q <= ram_we_n_s; |
---|
160 | ram_ce_n_q <= ram_ce_n_s; |
---|
161 | |
---|
162 | -- done only settable once |
---|
163 | if done_s then |
---|
164 | done_q <= '1'; |
---|
165 | end if; |
---|
166 | |
---|
167 | mode_q <= mode_s; |
---|
168 | |
---|
169 | end if; |
---|
170 | end process seq; |
---|
171 | -- |
---|
172 | ----------------------------------------------------------------------------- |
---|
173 | |
---|
174 | |
---|
175 | ----------------------------------------------------------------------------- |
---|
176 | -- Process fsm |
---|
177 | -- |
---|
178 | -- Purpose: |
---|
179 | -- Implements the combinational logic of the RAM loader FSM. |
---|
180 | -- |
---|
181 | fsm: process (fsm_q, |
---|
182 | bit_ovfl_q, |
---|
183 | start_q, |
---|
184 | addr_q) |
---|
185 | begin |
---|
186 | -- default assignments |
---|
187 | inc_addr_s <= false; |
---|
188 | ram_we_n_s <= '1'; |
---|
189 | done_s <= false; |
---|
190 | fsm_s <= IDLE; |
---|
191 | lamp_o <= '1'; |
---|
192 | mode_s <= '0'; |
---|
193 | |
---|
194 | case fsm_q is |
---|
195 | when IDLE => |
---|
196 | lamp_o <= '0'; |
---|
197 | if start_q = '1' then |
---|
198 | if bit_ovfl_q then |
---|
199 | fsm_s <= WE_ON; |
---|
200 | end if; |
---|
201 | end if; |
---|
202 | |
---|
203 | when WE_ON => |
---|
204 | ram_we_n_s <= '0'; |
---|
205 | fsm_s <= WE_OFF; |
---|
206 | |
---|
207 | when WE_OFF => |
---|
208 | fsm_s <= INC_ADDR1; |
---|
209 | |
---|
210 | when INC_ADDR1 => |
---|
211 | fsm_s <= INC_ADDR2; |
---|
212 | |
---|
213 | when INC_ADDR2 => |
---|
214 | if addr_q = "001111111111111111" then -- load only 64k |
---|
215 | fsm_s <= FINISHED; |
---|
216 | done_s <= true; |
---|
217 | mode_s <= '1'; |
---|
218 | else |
---|
219 | inc_addr_s <= true; |
---|
220 | fsm_s <= IDLE; |
---|
221 | end if; |
---|
222 | |
---|
223 | when FINISHED => |
---|
224 | fsm_s <= FINISHED; |
---|
225 | lamp_o <= '1'; |
---|
226 | mode_s <= '1'; |
---|
227 | |
---|
228 | when others => |
---|
229 | end case; |
---|
230 | |
---|
231 | end process fsm; |
---|
232 | -- |
---|
233 | ----------------------------------------------------------------------------- |
---|
234 | |
---|
235 | |
---|
236 | ----------------------------------------------------------------------------- |
---|
237 | -- Process ce_gen |
---|
238 | -- |
---|
239 | -- Purpose: |
---|
240 | -- Generates the four CE signals for the external RAM chips. |
---|
241 | -- |
---|
242 | ce_gen: process (addr_q) |
---|
243 | begin |
---|
244 | ram_ce_n_s <= (others => '1'); |
---|
245 | ram_ce_n_s(to_integer(addr_q(17 downto 16))) <= '0'; |
---|
246 | end process ce_gen; |
---|
247 | -- |
---|
248 | ----------------------------------------------------------------------------- |
---|
249 | |
---|
250 | |
---|
251 | ----------------------------------------------------------------------------- |
---|
252 | -- Process start_seq |
---|
253 | -- |
---|
254 | -- Purpose: |
---|
255 | -- Implements the sequential elements clocked with clk_i. |
---|
256 | -- |
---|
257 | start_seq: process (clk_i, reset_i) |
---|
258 | begin |
---|
259 | if reset_i = '0' then |
---|
260 | start_fsm_q <= WAIT_DETACH; |
---|
261 | start_q <= '0'; |
---|
262 | enable_q <= false; |
---|
263 | |
---|
264 | elsif clk_i'event and clk_i = '1' then |
---|
265 | start_fsm_q <= start_fsm_s; |
---|
266 | |
---|
267 | enable_q <= enable_s; |
---|
268 | |
---|
269 | start_q <= start_s; |
---|
270 | |
---|
271 | end if; |
---|
272 | end process start_seq; |
---|
273 | -- |
---|
274 | ----------------------------------------------------------------------------- |
---|
275 | |
---|
276 | |
---|
277 | ----------------------------------------------------------------------------- |
---|
278 | -- Process start_comb |
---|
279 | -- |
---|
280 | -- Purpose: |
---|
281 | -- Implements the combinational logic of the start FSM. |
---|
282 | -- |
---|
283 | start_comb: process (start_fsm_q, |
---|
284 | detached_i, |
---|
285 | done_q, |
---|
286 | enable_q, |
---|
287 | start_q) |
---|
288 | begin |
---|
289 | -- default assignments |
---|
290 | start_fsm_s <= WAIT_DETACH; |
---|
291 | enable_s <= enable_q; |
---|
292 | start_s <= start_q; |
---|
293 | |
---|
294 | case start_fsm_q is |
---|
295 | -- Wait for detached_i to become '1' |
---|
296 | -- This state is entered/left twice: |
---|
297 | -- 1. after reset to start the data download |
---|
298 | -- 2. after data download to start the next configuration cycle |
---|
299 | when WAIT_DETACH => |
---|
300 | if detached_i = '1' then |
---|
301 | start_fsm_s <= CHECK_NO_DONE; |
---|
302 | enable_s <= true; |
---|
303 | start_s <= '1'; |
---|
304 | |
---|
305 | else |
---|
306 | start_fsm_s <= WAIT_DETACH; |
---|
307 | end if; |
---|
308 | |
---|
309 | -- Wait until done_q is '0' |
---|
310 | -- This ensures that the FSM stalls when it has started the configuration |
---|
311 | -- download. There must be no further action in this case. |
---|
312 | when CHECK_NO_DONE => |
---|
313 | if done_q = '0' then |
---|
314 | start_fsm_s <= WAIT_DONE; |
---|
315 | else |
---|
316 | start_fsm_s <= CHECK_NO_DONE; |
---|
317 | end if; |
---|
318 | |
---|
319 | -- Wait until done_q is '1' |
---|
320 | -- done_q is the signal that the main FSM has finished its work. We |
---|
321 | -- need to start the configuration download. |
---|
322 | when WAIT_DONE => |
---|
323 | if done_q = '1' then |
---|
324 | start_fsm_s <= WAIT_DETACH; |
---|
325 | enable_s <= false; |
---|
326 | start_s <= '0'; |
---|
327 | else |
---|
328 | start_fsm_s <= WAIT_DONE; |
---|
329 | end if; |
---|
330 | |
---|
331 | when others => |
---|
332 | null; |
---|
333 | |
---|
334 | end case; |
---|
335 | |
---|
336 | end process start_comb; |
---|
337 | -- |
---|
338 | ----------------------------------------------------------------------------- |
---|
339 | |
---|
340 | |
---|
341 | ----------------------------------------------------------------------------- |
---|
342 | -- Output Mapping |
---|
343 | ----------------------------------------------------------------------------- |
---|
344 | start_o <= start_q; |
---|
345 | mode_o <= mode_q; |
---|
346 | done_o <= done_q |
---|
347 | when start_q = '1' else |
---|
348 | '1'; |
---|
349 | ram_addr_o <= std_logic_vector(addr_q(15 downto 0)); |
---|
350 | ram_data_b <= ser_dat_q; |
---|
351 | ram_oe_no <= '1'; |
---|
352 | ram_ce_no <= ram_ce_n_q; |
---|
353 | ram_we_no <= ram_we_n_q; |
---|
354 | |
---|
355 | end rtl; |
---|