[1799] | 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; |
---|