source: Hardware/WARP_v3/Rev1.1/Config_CPLD/src/spi_boot_OpenCores_src/bench/vhdl/card.vhd

Last change on this file was 1799, checked in by murphpo, 12 years ago

Adding WARP v3 hardware files (schematics, FPGA pinout, configuration CPLD source)

File size: 11.9 KB
RevLine 
[1799]1-------------------------------------------------------------------------------
2--
3-- SD/MMC Bootloader
4-- Simple SD and MMC model
5--
6-- $Id: card.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
47library ieee;
48use ieee.std_logic_1164.all;
49
50
51entity card is
52
53  generic (
54    card_type_g  : string := "none";
55    is_sd_card_g : integer := 1
56  );
57
58  port (
59    spi_clk_i  : in  std_logic;
60    spi_cs_n_i : in  std_logic;
61    spi_data_i : in  std_logic;
62    spi_data_o : out std_logic
63  );
64
65end card;
66
67
68library ieee;
69use ieee.numeric_std.all;
70library std;
71use std.textio.all;
72
73use work.tb_pack.all;
74
75architecture behav of card is
76
77  signal power_on_n_s : std_logic;
78  signal soft_res_n_s : std_logic;
79  signal res_n_s      : std_logic;
80
81  signal rx_s : std_logic_vector(47 downto 0);
82
83  signal set_spi_mode_s,
84         spi_mode_q       : boolean;
85  signal set_idle_mode_s,
86         poll_idle_mode_s : boolean;
87  signal idle_mode_q      : natural;
88
89  signal block_len_q,
90         block_len_s     : unsigned(31 downto 0);
91  signal set_block_len_s : boolean;
92
93  signal new_read_addr_s,
94         read_addr_q     : unsigned(31 downto 0);
95  signal set_read_addr_s,
96         inc_read_addr_s : boolean;
97
98  signal cmd_spi_data_s,
99         read_spi_data_s : std_logic;
100  signal start_read_s    : boolean;
101  signal reading_s       : boolean;
102
103  procedure rise_clk is
104  begin
105    wait until spi_clk_i'event and to_X01(spi_clk_i) = '1';
106  end rise_clk;
107
108--  procedure rise_clk(num : natural) is
109--  begin
110--    for i in 1 to num loop
111--      rise_clk;
112--    end loop;
113--  end rise_clk;
114
115  procedure fall_clk is
116  begin
117    wait until spi_clk_i'event and to_X01(spi_clk_i) = '0';
118  end fall_clk;
119
120  procedure fall_clk(num : natural) is
121  begin
122    for i in 1 to num loop
123      fall_clk;
124    end loop;
125  end fall_clk;
126
127begin
128
129  res_n_s <= power_on_n_s and soft_res_n_s;
130
131  -----------------------------------------------------------------------------
132  -- Power on reset
133  -----------------------------------------------------------------------------
134  por: process
135  begin
136    power_on_n_s <= '0';
137    wait for 200 ns;
138    power_on_n_s <= '1';
139    wait;
140  end process por;
141
142
143  -----------------------------------------------------------------------------
144  --
145  ctrl: process
146
147    function check_crc(payload : in std_logic_vector(47 downto 0))
148      return boolean is
149
150    begin
151
152      return calc_crc(payload(47 downto 8)) = payload(7 downto 1);
153    end check_crc;
154
155    variable rx_v        : std_logic_vector(47 downto 0);
156    variable cmd_v       : std_logic_vector( 5 downto 0);
157    variable arg_v       : std_logic_vector(31 downto 0);
158    variable crc_v       : std_logic_vector( 6 downto 0);
159    variable wrong_v     : std_logic;
160    variable read_data_v : boolean;
161
162  begin
163    rx_s <= (others => '0');
164    set_spi_mode_s   <= false;
165    set_idle_mode_s  <= false;
166    poll_idle_mode_s <= false;
167    cmd_spi_data_s   <= '1';
168    soft_res_n_s     <= '1';
169    set_block_len_s  <= false;
170    block_len_s      <= (others => '0');
171    new_read_addr_s  <= (others => '0');
172    set_read_addr_s  <= false;
173    start_read_s     <= false;
174    read_data_v      := false;
175
176    loop
177
178      rise_clk;
179      -- wait for startbit of command
180      while to_X01(spi_data_i) = '1' loop
181        rise_clk;
182      end loop;
183      rx_v(47) := '0';
184
185      -- read remaining 47 bits of command
186      for i in 46 downto 0 loop
187        rise_clk;
188        rx_v(i) := to_X01(spi_data_i);
189      end loop;
190      rx_s <= rx_v;
191
192      -- dissect received data
193      cmd_v := rx_v(45 downto 40);
194      arg_v := rx_v(39 downto  8);
195      crc_v := rx_v( 7 downto  1);
196
197      assert spi_mode_q or check_crc(payload => rx_v)
198        report "CRC mismatch"
199        severity error;
200
201      wrong_v     := '0';
202      case cmd_v is
203        -- CMD0: GO_IDLE_STATE ------------------------------------------------
204        when "000000" =>
205          set_spi_mode_s  <= true;
206          set_idle_mode_s <= true;
207        -- CMD1: SEND_OP_COND -------------------------------------------------
208        when "000001" =>
209          poll_idle_mode_s <= true;
210        -- CMD12: STOP_TRANSMISSION -------------------------------------------
211        when "001100" =>
212          start_read_s <= false;
213          read_data_v  := false;
214        -- CMD16: SET_BLOCKLEN ------------------------------------------------
215        when "010000" =>
216          block_len_s     <= unsigned(arg_v);
217          set_block_len_s <= true;
218        -- CMD18: READ_MULTIPLE_BLOCK -----------------------------------------
219        when "010010" =>
220          new_read_addr_s <= unsigned(arg_v);
221          set_read_addr_s <= true;
222          read_data_v     := true;
223        -- CMD55: APPL_CMD ----------------------------------------------------
224        when "110111" =>
225          -- command only available for SD card
226          if is_sd_card_g /= 1 then
227            wrong_v := '1';
228          end if;
229        -- ACMD41: SEND_OP_COND -----------------------------------------------
230        when "101001" =>
231          -- command only available for SD card
232          if is_sd_card_g /= 1 then
233            wrong_v := '1';
234          else
235            poll_idle_mode_s <= true;
236          end if;
237
238        when others =>
239          wrong_v := '1';
240          null;
241      end case;
242
243
244      -- spend some time before removing control signals
245      fall_clk(2);
246      poll_idle_mode_s <= false;
247      set_idle_mode_s <= false;
248      fall_clk(6);
249      set_spi_mode_s  <= false;
250      set_block_len_s <= false;
251      set_read_addr_s <= false;
252
253      if reading_s then
254        wait until not reading_s;
255      end if;
256
257
258      -- wait for a total two "bytes" before sending out response
259      for i in 1 to 8 loop
260        fall_clk;
261      end loop;
262
263      for i in 7 downto 0 loop
264        fall_clk;
265        case i is
266          when 2 =>
267            cmd_spi_data_s <= wrong_v;
268          when 0 =>
269            if idle_mode_q = 0 then
270              cmd_spi_data_s <= '0';
271            else
272              cmd_spi_data_s <= '1';
273            end if;
274          when others =>
275            cmd_spi_data_s <= '0';
276        end case;
277      end loop;
278      fall_clk;
279      cmd_spi_data_s <= '1';
280
281      -- transmit data if requested
282      start_read_s <= read_data_v;
283
284    end loop;
285  end process ctrl;
286  --
287  -----------------------------------------------------------------------------
288
289
290  -----------------------------------------------------------------------------
291  --
292  seq: process (res_n_s,
293                spi_clk_i,
294                set_spi_mode_s,
295                set_idle_mode_s,
296                poll_idle_mode_s,
297                set_block_len_s,
298                block_len_s)
299
300  begin
301    if res_n_s = '0' then
302      spi_mode_q  <= false;
303      idle_mode_q <= 5;
304      block_len_q <= (others => '0');
305      read_addr_q <= (others => '0');
306
307    elsif spi_clk_i'event and spi_clk_i = '1' then
308      if set_spi_mode_s then
309        spi_mode_q  <= true;
310      end if;
311
312      if set_idle_mode_s then
313        idle_mode_q  <= 5;
314      elsif poll_idle_mode_s then
315        if idle_mode_q > 0 then
316          idle_mode_q <= idle_mode_q - 1;
317        end if;
318      end if;
319
320      if set_block_len_s then
321        block_len_q <= block_len_s;
322      end if;
323
324      if set_read_addr_s then
325        read_addr_q <= new_read_addr_s;
326      elsif inc_read_addr_s then
327        read_addr_q <= read_addr_q + 1;
328      end if;
329
330    end if;
331  end process seq;
332  --
333  -----------------------------------------------------------------------------
334
335
336  -----------------------------------------------------------------------------
337  --
338  read_block: process
339
340    variable t_v : unsigned(7 downto 0);
341
342  begin
343    -- default assignments
344    inc_read_addr_s <= false;
345    reading_s       <= false;
346    read_spi_data_s <= '1';
347
348    loop
349      if not start_read_s then
350        wait until start_read_s;
351      end if;
352
353      reading_s <= true;
354
355      fall_clk(8);                    -- delay for one "byte"
356
357      -- send data token
358      fall_clk(7);                    -- 7 ones in a data token
359      read_spi_data_s <= '0';
360
361      -- send payload
362      payload: for i in 0 to to_integer(block_len_q)-1 loop
363        t_v := read_addr_q(0) & calc_crc(read_addr_q);
364        for bit in 7 downto 0 loop
365          fall_clk;
366          read_spi_data_s <= t_v(bit);
367
368          exit payload when not start_read_s;
369        end loop;
370        inc_read_addr_s <= true;
371        rise_clk;
372        inc_read_addr_s <= false;
373        wait for 10 ns;
374      end loop;
375
376      if start_read_s then
377        -- send crc
378        for i in 0 to 15 loop
379          fall_clk;
380          t_v := to_unsigned(i, 8);
381          read_spi_data_s <= t_v(0);
382        end loop;
383        fall_clk;
384      end if;
385
386      read_spi_data_s <= '1';
387      reading_s <= false;
388      -- loop for one "byte"
389      fall_clk(8);
390
391    end loop;
392  end process read_block;
393  --
394  -----------------------------------------------------------------------------
395
396
397  -----------------------------------------------------------------------------
398  --
399  clk_check: process (spi_clk_i)
400
401    variable last_rising_v : time := 0 ns;
402    variable dump_line     : line;
403
404  begin
405    if spi_clk_i'event and spi_clk_i = '1' then
406      if is_sd_card_g = 0 and card_type_g /= "Minimal Chip" and
407         idle_mode_q > 0 then
408        if now - last_rising_v < 2.5 us and last_rising_v > 0 ns then
409          write(dump_line, card_type_g);
410          write(dump_line, string'(" @ "));
411          write(dump_line, now);
412          write(dump_line, string'(": Last rising edge of SPI clock "));
413          write(dump_line, now - last_rising_v);
414          write(dump_line, string'(" ago."));
415          writeline(output, dump_line);
416        end if;
417
418        last_rising_v := now;
419      end if;
420    end if;
421  end process clk_check;
422  --
423  -----------------------------------------------------------------------------
424
425
426  -----------------------------------------------------------------------------
427  -- Output Mapping
428  -----------------------------------------------------------------------------
429  spi_data_o <=   cmd_spi_data_s and read_spi_data_s
430                when spi_cs_n_i = '0' else
431                  'Z';
432
433end behav;
Note: See TracBrowser for help on using the repository browser.