URL
https://opencores.org/ocsvn/sd_card_controller/sd_card_controller/trunk
Subversion Repositories sd_card_controller
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 13 to Rev 14
- ↔ Reverse comparison
Rev 13 → Rev 14
/sd_card_controller/trunk/doc/sd_card_pack_OC120116.odt
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
sd_card_controller/trunk/doc/sd_card_pack_OC120116.odt
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: sd_card_controller/trunk/doc/sd_card_pack_OC120116.pdf
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: sd_card_controller/trunk/doc/sd_card_pack_OC120116.pdf
===================================================================
--- sd_card_controller/trunk/doc/sd_card_pack_OC120116.pdf (nonexistent)
+++ sd_card_controller/trunk/doc/sd_card_pack_OC120116.pdf (revision 14)
sd_card_controller/trunk/doc/sd_card_pack_OC120116.pdf
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: sd_card_controller/trunk/rtl/VHDL/block_ram_pack.vhd
===================================================================
--- sd_card_controller/trunk/rtl/VHDL/block_ram_pack.vhd (nonexistent)
+++ sd_card_controller/trunk/rtl/VHDL/block_ram_pack.vhd (revision 14)
@@ -0,0 +1,468 @@
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+package block_ram_pack is
+
+ component block_ram
+ generic(
+ WRITETHRU : integer; -- Set to nonzero value for writethrough mode
+ USE_FILE : integer; -- Set to nonzero value to use INIT_FILE
+ INIT_VAL : integer; -- Value used when INIT_FILE is not used
+ INIT_FILE : string; -- ASCII hexadecimal initialization file name
+ FIL_WIDTH : integer; -- Bit width of init file lines
+ ADR_WIDTH : integer;
+ DAT_WIDTH : integer
+ );
+ port (
+ clk_a : in std_logic;
+ adr_a_i : in unsigned(adr_width-1 downto 0);
+ we_a_i : in std_logic;
+ en_a_i : in std_logic;
+ dat_a_i : in unsigned(dat_width-1 downto 0);
+ dat_a_o : out unsigned(dat_width-1 downto 0);
+
+ clk_b : in std_logic;
+ adr_b_i : in unsigned(adr_width-1 downto 0);
+ we_b_i : in std_logic;
+ en_b_i : in std_logic;
+ dat_b_i : in unsigned(dat_width-1 downto 0);
+ dat_b_o : out unsigned(dat_width-1 downto 0)
+ );
+ end component;
+
+ component block_ram_async_reset
+ generic(
+ WRITETHRU : integer; -- Set to nonzero value for writethrough mode
+ USE_FILE : integer; -- Set to nonzero value to use INIT_FILE
+ INIT_VAL : integer; -- Value used when INIT_FILE is not used
+ INIT_FILE : string; -- ASCII hexadecimal initialization file name
+ FIL_WIDTH : integer; -- Bit width of init file lines
+ ADR_WIDTH : integer;
+ DAT_WIDTH : integer
+ );
+ port (
+ reset_a : in std_logic;
+ clk_a : in std_logic;
+ adr_a_i : in unsigned(adr_width-1 downto 0);
+ we_a_i : in std_logic;
+ en_a_i : in std_logic;
+ dat_a_i : in unsigned(dat_width-1 downto 0);
+ dat_a_o : out unsigned(dat_width-1 downto 0);
+
+ reset_b : in std_logic;
+ clk_b : in std_logic;
+ adr_b_i : in unsigned(adr_width-1 downto 0);
+ we_b_i : in std_logic;
+ en_b_i : in std_logic;
+ dat_b_i : in unsigned(dat_width-1 downto 0);
+ dat_b_o : out unsigned(dat_width-1 downto 0)
+ );
+ end component;
+
+ component swiss_army_ram
+ generic(
+ USE_BRAM : integer; -- Set to nonzero value for BRAM, zero for distributed RAM
+ WRITETHRU : integer; -- Set to nonzero value for writethrough mode
+ USE_FILE : integer; -- Set to nonzero value to use INIT_FILE
+ INIT_VAL : integer; -- Value used when INIT_FILE is not used
+ INIT_SEL : integer; -- Selects which segment of (larger) INIT_FILE to use
+ INIT_FILE : string; -- ASCII hexadecimal initialization file name
+ FIL_WIDTH : integer; -- Bit width of init file lines
+ ADR_WIDTH : integer;
+ DAT_WIDTH : integer
+ );
+ port (
+ clk_a : in std_logic;
+ adr_a_i : in unsigned(adr_width-1 downto 0);
+ we_a_i : in std_logic;
+ en_a_i : in std_logic;
+ dat_a_i : in unsigned(dat_width-1 downto 0);
+ dat_a_o : out unsigned(dat_width-1 downto 0);
+
+ clk_b : in std_logic;
+ adr_b_i : in unsigned(adr_width-1 downto 0);
+ we_b_i : in std_logic;
+ en_b_i : in std_logic;
+ dat_b_i : in unsigned(dat_width-1 downto 0);
+ dat_b_o : out unsigned(dat_width-1 downto 0)
+ );
+ end component;
+
+end block_ram_pack;
+
+------------------------------------------------------------------
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+use IEEE.STD_LOGIC_TEXTIO.ALL;
+
+library std ;
+use std.textio.all;
+
+entity block_ram is
+ generic(
+ WRITETHRU : integer := 1; -- Set to nonzero value for writethrough mode
+ USE_FILE : integer := 0; -- Set to nonzero value to use INIT_FILE
+ INIT_VAL : integer := 0; -- Value used when INIT_FILE is not used
+ INIT_FILE : string := ".\foo.txt"; -- ASCII hexadecimal initialization file name
+ FIL_WIDTH : integer := 32; -- Bit width of init file lines
+ ADR_WIDTH : integer := 3;
+ DAT_WIDTH : integer := 32
+ );
+ port (
+ clk_a : in std_logic;
+ adr_a_i : in unsigned(adr_width-1 downto 0);
+ we_a_i : in std_logic;
+ en_a_i : in std_logic;
+ dat_a_i : in unsigned(dat_width-1 downto 0);
+ dat_a_o : out unsigned(dat_width-1 downto 0);
+
+ clk_b : in std_logic;
+ adr_b_i : in unsigned(adr_width-1 downto 0);
+ we_b_i : in std_logic;
+ en_b_i : in std_logic;
+ dat_b_i : in unsigned(dat_width-1 downto 0);
+ dat_b_o : out unsigned(dat_width-1 downto 0)
+ );
+end block_ram;
+
+architecture beh of block_ram is
+
+ -- Constants
+
+ -- Functions & associated types
+ type ram_array is array(0 to 2**ADR_WIDTH-1) of unsigned(DAT_WIDTH-1 downto 0);
+ impure function ram_file_init (INIT_FILE : in string) return ram_array is
+ FILE F1 : text is in INIT_FILE;
+ variable ligne : line;
+ variable rambo : ram_array;
+ variable vect : std_logic_vector(FIL_WIDTH-1 downto 0);
+ variable uvect : unsigned(DAT_WIDTH-1 downto 0);
+ begin
+ for I in ram_array'range loop
+ if (USE_FILE/=0) then
+ readline(F1,ligne);
+ hread(ligne,vect);
+ for j in uvect'range loop
+ if (vect(j)='1') then
+ uvect(j):='1';
+ else
+ uvect(j):='0';
+ end if;
+ end loop;
+ else
+ uvect := to_unsigned(INIT_VAL,DAT_WIDTH);
+ end if;
+ rambo(I):=uvect;
+ end loop;
+ return rambo;
+ end function;
+
+ -- Variable Declarations
+ shared variable ram1 : ram_array := ram_file_init(init_file);
+
+ -- Signal Declarations
+ signal dat_a_wt : unsigned(DAT_WIDTH-1 downto 0);
+ signal dat_b_wt : unsigned(DAT_WIDTH-1 downto 0);
+ signal dat_a_l : unsigned(DAT_WIDTH-1 downto 0);
+ signal dat_b_l : unsigned(DAT_WIDTH-1 downto 0);
+
+begin
+
+process (clk_a)
+variable i : integer;
+begin
+ if (clk_a'event and clk_a='1') then
+ if (en_a_i='1') then
+ dat_a_l <= ram1(to_integer(adr_a_i));
+ if (we_a_i='1') then
+ ram1(to_integer(adr_a_i)) := dat_a_i;
+ dat_a_wt <= dat_a_i;
+ else
+ dat_a_wt <= ram1(to_integer(adr_a_i));
+ end if;
+ end if;
+ end if;
+end process;
+dat_a_o <= dat_a_l when WRITETHRU=0 else dat_a_wt;
+
+process (clk_b)
+variable i : integer;
+begin
+ if (clk_b'event and clk_b='1') then
+ if (en_b_i='1') then
+ dat_b_l <= ram1(to_integer(adr_b_i));
+ if (we_b_i='1') then
+ ram1(to_integer(adr_b_i)) := dat_b_i;
+ dat_b_wt <= dat_b_i;
+ end if;
+ dat_b_wt <= ram1(to_integer(adr_b_i));
+ end if;
+ end if;
+end process;
+dat_b_o <= dat_b_l when WRITETHRU=0 else dat_b_wt;
+
+end beh;
+
+------------------------------------------------------------------
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+use IEEE.STD_LOGIC_TEXTIO.ALL;
+
+library std ;
+use std.textio.all;
+
+entity block_ram_async_reset is
+ generic(
+ WRITETHRU : integer := 1; -- Set to nonzero value for writethrough mode
+ USE_FILE : integer := 0; -- Set to nonzero value to use INIT_FILE
+ INIT_VAL : integer := 0; -- Value used when INIT_FILE is not used
+ INIT_FILE : string := ".\foo.txt"; -- ASCII hexadecimal initialization file name
+ FIL_WIDTH : integer := 32; -- Bit width of init file lines
+ ADR_WIDTH : integer := 3;
+ DAT_WIDTH : integer := 32
+ );
+ port (
+ reset_a : in std_logic;
+ clk_a : in std_logic;
+ adr_a_i : in unsigned(adr_width-1 downto 0);
+ we_a_i : in std_logic;
+ en_a_i : in std_logic;
+ dat_a_i : in unsigned(dat_width-1 downto 0);
+ dat_a_o : out unsigned(dat_width-1 downto 0);
+
+ reset_b : in std_logic;
+ clk_b : in std_logic;
+ adr_b_i : in unsigned(adr_width-1 downto 0);
+ we_b_i : in std_logic;
+ en_b_i : in std_logic;
+ dat_b_i : in unsigned(dat_width-1 downto 0);
+ dat_b_o : out unsigned(dat_width-1 downto 0)
+ );
+end block_ram_async_reset;
+
+architecture beh of block_ram_async_reset is
+
+ -- Constants
+
+ -- Functions & associated types
+ type ram_array is array(0 to 2**ADR_WIDTH-1) of unsigned(DAT_WIDTH-1 downto 0);
+ impure function ram_file_init (INIT_FILE : in string) return ram_array is
+ FILE F1 : text is in INIT_FILE;
+ variable ligne : line;
+ variable rambo : ram_array;
+ variable vect : std_logic_vector(FIL_WIDTH-1 downto 0);
+ variable uvect : unsigned(DAT_WIDTH-1 downto 0);
+ begin
+ for I in ram_array'range loop
+ if (USE_FILE/=0) then
+ readline(F1,ligne);
+ hread(ligne,vect);
+ for j in uvect'range loop
+ if (vect(j)='1') then
+ uvect(j):='1';
+ else
+ uvect(j):='0';
+ end if;
+ end loop;
+ else
+ uvect := to_unsigned(INIT_VAL,DAT_WIDTH);
+ end if;
+ rambo(I):=uvect;
+ end loop;
+ return rambo;
+ end function;
+
+ -- Variable Declarations
+ shared variable ram1 : ram_array := ram_file_init(init_file);
+
+ -- Signal Declarations
+ signal dat_a_wt : unsigned(DAT_WIDTH-1 downto 0);
+ signal dat_b_wt : unsigned(DAT_WIDTH-1 downto 0);
+ signal dat_a_l : unsigned(DAT_WIDTH-1 downto 0);
+ signal dat_b_l : unsigned(DAT_WIDTH-1 downto 0);
+
+begin
+
+process (clk_a)
+variable i : integer;
+begin
+ if (reset_a = '1') then
+ dat_a_l <= (others=>'0');
+ dat_a_wt <= (others=>'0');
+ elsif (clk_a'event and clk_a='1') then
+ if (en_a_i='1') then
+ dat_a_l <= ram1(to_integer(adr_a_i));
+ if (we_a_i='1') then
+ ram1(to_integer(adr_a_i)) := dat_a_i;
+ dat_a_wt <= dat_a_i;
+ else
+ dat_a_wt <= ram1(to_integer(adr_a_i));
+ end if;
+ end if;
+ end if;
+end process;
+dat_a_o <= dat_a_l when WRITETHRU=0 else dat_a_wt;
+
+process (clk_b)
+variable i : integer;
+begin
+ if (reset_b = '1') then
+ dat_b_l <= (others=>'0');
+ dat_b_wt <= (others=>'0');
+ elsif (clk_b'event and clk_b='1') then
+ if (en_b_i='1') then
+ dat_b_l <= ram1(to_integer(adr_b_i));
+ if (we_b_i='1') then
+ ram1(to_integer(adr_b_i)) := dat_b_i;
+ dat_b_wt <= dat_b_i;
+ end if;
+ dat_b_wt <= ram1(to_integer(adr_b_i));
+ end if;
+ end if;
+end process;
+dat_b_o <= dat_b_l when WRITETHRU=0 else dat_b_wt;
+
+end beh;
+
+------------------------------------------------------------------
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+use IEEE.STD_LOGIC_TEXTIO.ALL;
+
+library std ;
+use std.textio.all;
+
+entity swiss_army_ram is
+ generic(
+ USE_BRAM : integer := 0; -- Set to nonzero value for BRAM, zero for distributed RAM
+ WRITETHRU : integer := 1; -- Set to nonzero value for writethrough mode
+ USE_FILE : integer := 0; -- Set to nonzero value to use INIT_FILE
+ INIT_VAL : integer := 0; -- Value used when INIT_FILE is not used
+ INIT_SEL : natural := 0; -- Can be used with generate loop variable to select a segment of the (larger) init file
+ INIT_FILE : string := ".\foo.txt"; -- ASCII hexadecimal initialization file name
+ FIL_WIDTH : integer := 32; -- Bit width of init file lines
+ ADR_WIDTH : integer := 3;
+ DAT_WIDTH : integer := 32
+ );
+ port (
+ clk_a : in std_logic;
+ adr_a_i : in unsigned(adr_width-1 downto 0);
+ we_a_i : in std_logic;
+ en_a_i : in std_logic;
+ dat_a_i : in unsigned(dat_width-1 downto 0);
+ dat_a_o : out unsigned(dat_width-1 downto 0);
+
+ clk_b : in std_logic;
+ adr_b_i : in unsigned(adr_width-1 downto 0);
+ we_b_i : in std_logic;
+ en_b_i : in std_logic;
+ dat_b_i : in unsigned(dat_width-1 downto 0);
+ dat_b_o : out unsigned(dat_width-1 downto 0)
+ );
+end swiss_army_ram;
+
+architecture beh of swiss_army_ram is
+
+ -- Constants
+
+ -- Functions & associated types
+ type ram_array is array(0 to 2**ADR_WIDTH-1) of unsigned(DAT_WIDTH-1 downto 0);
+ impure function ram_file_init (INIT_FILE : in string) return ram_array is
+ FILE F1 : text is in INIT_FILE;
+ variable ligne : line;
+ variable rambo : ram_array;
+ variable vect : std_logic_vector(FIL_WIDTH-1 downto 0);
+ variable uvect : unsigned(DAT_WIDTH-1 downto 0);
+ variable I,J : integer;
+ begin
+ -- If using the file, then index through the file to the desired selection
+ if (USE_FILE/=0) then
+ if (INIT_SEL>0) then
+ for I in 0 to INIT_SEL-1 loop
+ for J in ram_array'range loop
+ readline(F1,ligne);
+ end loop;
+ end loop;
+ end if;
+ end if;
+ -- Obtain the desired initialization values
+ for I in ram_array'range loop
+ if (USE_FILE/=0) then
+ readline(F1,ligne);
+ hread(ligne,vect);
+ for J in uvect'range loop
+ if (vect(J)='1') then
+ uvect(J):='1';
+ else
+ uvect(J):='0';
+ end if;
+ end loop;
+ else
+ uvect := to_unsigned(INIT_VAL,DAT_WIDTH);
+ end if;
+ rambo(I):=uvect;
+ end loop;
+ return rambo;
+ end function;
+
+ -- Variable Declarations
+ -- To run with RAM > 64k comment this initialization
+ -- and un-comment the next line
+ shared variable ram1 : ram_array := ram_file_init(init_file);
+-- shared variable ram1 : ram_array; -- Initialization removed for this project due to Vivado 64K loop limit...
+
+ -- Signal Declarations
+ signal dat_a_wt : unsigned(DAT_WIDTH-1 downto 0);
+ signal dat_b_wt : unsigned(DAT_WIDTH-1 downto 0);
+ signal dat_a_l : unsigned(DAT_WIDTH-1 downto 0);
+ signal dat_b_l : unsigned(DAT_WIDTH-1 downto 0);
+
+begin
+
+process (clk_a)
+variable i : integer;
+begin
+ if (clk_a'event and clk_a='1') then
+ if (en_a_i='1') then
+ dat_a_l <= ram1(to_integer(adr_a_i));
+ if (we_a_i='1') then
+ ram1(to_integer(adr_a_i)) := dat_a_i;
+ dat_a_wt <= dat_a_i;
+ else
+ dat_a_wt <= ram1(to_integer(adr_a_i));
+ end if;
+ end if;
+ end if;
+end process;
+dat_a_o <= ram1(to_integer(adr_a_i)) when USE_BRAM=0 else
+ dat_a_l when WRITETHRU=0 else
+ dat_a_wt;
+
+process (clk_b)
+variable i : integer;
+begin
+ if (clk_b'event and clk_b='1') then
+ if (en_b_i='1') then
+ dat_b_l <= ram1(to_integer(adr_b_i));
+ if (we_b_i='1') then
+ ram1(to_integer(adr_b_i)) := dat_b_i;
+ dat_b_wt <= dat_b_i;
+ end if;
+ dat_b_wt <= ram1(to_integer(adr_b_i));
+ end if;
+ end if;
+end process;
+dat_b_o <= ram1(to_integer(adr_b_i)) when USE_BRAM=0 else
+ dat_b_l when WRITETHRU=0 else
+ dat_b_wt;
+
+end beh;
+
Index: sd_card_controller/trunk/rtl/VHDL/convert_pack.vhd
===================================================================
--- sd_card_controller/trunk/rtl/VHDL/convert_pack.vhd (nonexistent)
+++ sd_card_controller/trunk/rtl/VHDL/convert_pack.vhd (revision 14)
@@ -0,0 +1,1468 @@
+-- A package containing various conversion functions useful in testbenches,
+-- especially when used with text file IO in reading and displaying
+-- hexadecimal values.
+--
+-- Modifications by : John Clayton
+--
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+use ieee.math_real.all;
+use std.textio.all;
+
+package convert_pack is
+
+------------------------------------------------------------------------------------
+-- function calls
+------------------------------------------------------------------------------------
+ function string_to_integer (in_string : string) return integer ;
+ function vector_to_string (in_vector : std_logic_vector) return string ;
+ function char_to_bit (in_char : character) return std_logic ;
+ function char_to_hex (in_char : character) return std_logic_vector ;
+
+ function slv2string(in_vector : std_logic_vector; nibbles : natural) return string ; -- Name changed by John Clayton
+ function u2string(in_vector : unsigned; nibbles : natural) return string ; -- Added by John Clayton
+ function u2asciichar(in_vector : unsigned(7 downto 0)) return character ; -- Added by John Clayton
+ function asciichar2u(in_char : character) return unsigned; -- Added by John Clayton
+
+ function hex_to_ascii(in_vector : std_logic_vector; nibbles : natural) return string ;
+ function u2ascii(in_vector : unsigned; nibbles : natural) return string ; -- Added by John Clayton
+ function hex_data_wrd(in_vector : std_logic_vector) return string ;
+ function hex_data_dblwrd(in_vector : std_logic_vector) return string ;
+ function hex_data_dblwrdz(in_vector : std_logic_vector) return string ;
+
+ function is_hex(c : character) return boolean; -- Added by John Clayton
+ function is_std_logic(c : character) return boolean; -- Added by John Clayton
+ function is_space(c : character) return boolean; -- Added by John Clayton
+ function char2sl(in_char : character) return std_logic; -- Added by John Clayton
+ function char2slv(in_char : character) return std_logic_vector;
+ function char2u(in_char : character) return unsigned;
+ function slv2u(in_a : std_logic_vector) return unsigned; -- Added by John Clayton
+ function u2slv(in_a : unsigned) return std_logic_vector; -- Added by John Clayton
+ function slv2s(in_a : std_logic_vector) return signed; -- Added by John Clayton
+ function s2slv(in_a : signed) return std_logic_vector; -- Added by John Clayton
+ function str2u(in_string : string; out_size:integer) return unsigned; -- Added by John Clayton
+ function str2s(in_string : string; out_size:integer) return signed; -- Added by John Clayton
+-- function "**"(in_a : natural; in_b : natural) return natural; -- Added by John Clayton
+ function pow_2_u(in_a : natural; out_size:integer) return unsigned; -- Added by John Clayton
+ function asr_function(in_vect : signed; in_a : natural) return signed; -- Added by John Clayton
+
+ function slv_resize(in_vect : std_logic_vector; out_size : integer) return std_logic_vector; -- Added by John Clayton
+ function slv_resize_l(in_vect : std_logic_vector; out_size : integer) return std_logic_vector; -- Added by John Clayton
+ function slv_resize_se(in_vect : std_logic_vector; out_size : integer) return std_logic_vector; -- Added by John Clayton
+ function s_resize(in_vect : signed; out_size : integer) return signed; -- Added by John Clayton
+ function s_resize_l(in_vect : signed; out_size : integer) return signed; -- Added by John Clayton
+ function s_resize_se(in_vect : signed; out_size : integer) return signed; -- Added by John Clayton
+ function u_resize(in_vect : unsigned; out_size : integer) return unsigned; -- Added by John Clayton
+ function u_resize_l(in_vect : unsigned; out_size : integer) return unsigned; -- Added by John Clayton
+ function u_select(in_vect : unsigned; slice_num : integer; slice_size : integer) return unsigned; -- Added by John Clayton
+ function u_reverse(in_vect : unsigned) return unsigned; -- Added by John Clayton
+
+ function u_recursive_parity ( x : unsigned ) return std_logic; -- Added by John Clayton
+
+ function bit_width (maxval : integer) return integer ; -- Added by John Clayton
+ function bit_width (maxval : real) return integer ; -- Added by John Clayton
+ function timer_width (maxval : integer) return integer ; -- Added by John Clayton
+ function timer_width (maxval : real) return integer ; -- Added by John Clayton
+
+ function num_words (num_bits : integer; bits_per_word : integer) return integer ;
+ function asciichar2u2(d:character) return unsigned; -- Added by John Clayton. Loosely based on code in Thesis by Rudi Rughoonundon, 11-1-1996
+ function str2u(s: string) return unsigned; -- Added by John Clayton, Converts a string of ASCII characters into unsigned
+ function u_ones(in_a : unsigned) return natural; -- Added by John Clayton, counts the number of '1' bits in an unsigned
+
+
+------------------------------------------------------------------------------------
+-- procedures
+------------------------------------------------------------------------------------
+
+
+end convert_pack;
+
+
+package body convert_pack is
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+--* Title : TEST_PARITY
+--* Filename & Ext : test_parity.vhdl
+--* Author : David Bishop X-66788
+--* Created : 3/18/97
+--* Version : 1.2
+--* Revision Date : 97/04/15
+--* SCCSid : 1.2 04/15/97 test_parity.vhdl
+--* WORK Library : testchip
+--* Mod History :
+--* Description : This is a parity generator which is written recursively
+--* : It is designed to test the ability of Simulation and
+--* : Synthesis tools to check this capability.
+--* Known Bugs :
+--* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+
+
+ function u_recursive_parity ( x : unsigned ) return std_logic is
+ variable Upper, Lower : std_logic;
+ variable Half : integer;
+ variable BUS_int : unsigned( x'length-1 downto 0 );
+ variable Result : std_logic;
+ begin
+ BUS_int := x;
+ if ( BUS_int'length = 1 ) then
+ Result := BUS_int ( BUS_int'left );
+ elsif ( BUS_int'length = 2 ) then
+ Result := BUS_int ( BUS_int'right ) xor BUS_int ( BUS_int'left );
+ else
+ Half := ( BUS_int'length + 1 ) / 2 + BUS_int'right;
+ Upper := u_recursive_parity ( BUS_int ( BUS_int'left downto Half ));
+ Lower := u_recursive_parity ( BUS_int ( Half - 1 downto BUS_int'right ));
+ Result := Upper xor Lower;
+ end if;
+ return Result;
+ end;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function vector_to_string (in_vector : std_logic_vector) return string is
+
+ variable out_string : string(32 downto 1);
+
+ begin
+
+ for i in in_vector'range loop
+ if in_vector(i) = '1' then
+ out_string(i+1) := '1';
+ elsif in_vector(i) = '0' then
+ out_string(i+1) := '0';
+ else
+ assert false
+ report " illegal bit vector to bit string"
+ severity note;
+ end if;
+ end loop;
+ return out_string;
+
+ end vector_to_string;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function string_to_integer (in_string : string) return integer is
+
+ variable int : integer := 0;
+ begin
+
+ for j in in_string'range loop
+ case in_string(j) is
+ when '0' => int := int;
+ when '1' => int := int + (1 * 10**(j-1));
+ when '2' => int := int + (2 * 10**(j-1));
+ when '3' => int := int + (3 * 10**(j-1));
+ when '4' => int := int + (4 * 10**(j-1));
+ when '5' => int := int + (5 * 10**(j-1));
+ when '6' => int := int + (6 * 10**(j-1));
+ when '7' => int := int + (7 * 10**(j-1));
+ when '8' => int := int + (8 * 10**(j-1));
+ when '9' => int := int + (9 * 10**(j-1));
+ when others =>
+ assert false
+ report " illegal character to integer"
+ severity note;
+ end case;
+ end loop;
+ return int;
+ end string_to_integer;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function char_to_bit (in_char : character) return std_logic is
+
+ variable out_bit : std_logic;
+
+ begin
+
+ if (in_char = '1') then
+ out_bit := '1';
+ elsif (in_char = '0') then
+ out_bit := '0';
+ else
+ assert false
+ report "illegal character to bit"
+ severity note;
+ end if;
+
+ return out_bit;
+ end char_to_bit;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+ function char_to_hex (in_char : character) return std_logic_vector is
+
+ variable out_vec : std_logic_vector(3 downto 0);
+
+
+ begin
+ case in_char is
+ when '0' => out_vec := "0000";
+ when '1' => out_vec := "0001";
+ when '2' => out_vec := "0010";
+ when '3' => out_vec := "0011";
+ when '4' => out_vec := "0100";
+ when '5' => out_vec := "0101";
+ when '6' => out_vec := "0110";
+ when '7' => out_vec := "0111";
+ when '8' => out_vec := "1000";
+ when '9' => out_vec := "1001";
+ when 'A' | 'a' => out_vec := "1010";
+ when 'B' | 'b' => out_vec := "1011";
+ when 'C' | 'c' => out_vec := "1100";
+ when 'D' | 'd' => out_vec := "1101";
+ when 'E' | 'e' => out_vec := "1110";
+ when 'F' | 'f' => out_vec := "1111";
+ when others =>
+ assert false
+ report " illegal character to hex"
+ severity note;
+ end case;
+ return out_vec;
+ end char_to_hex;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function slv2string(in_vector : std_logic_vector; nibbles : natural) return string is
+ variable out_string : string(1 to nibbles);
+ variable temp_in_vector : std_logic_vector(4*nibbles-1 downto 0);
+ variable vector : std_logic_vector(3 downto 0);
+
+ begin
+ temp_in_vector := in_vector(in_vector'length-1 downto in_vector'length-temp_in_vector'length);
+ for i in 1 to nibbles loop
+ vector := temp_in_vector((4*(nibbles-i)+3) downto 4*(nibbles-i));
+ case vector is
+ when "0000" => out_string(i) := '0';
+ when "0001" => out_string(i) := '1';
+ when "0010" => out_string(i) := '2';
+ when "0011" => out_string(i) := '3';
+ when "0100" => out_string(i) := '4';
+ when "0101" => out_string(i) := '5';
+ when "0110" => out_string(i) := '6';
+ when "0111" => out_string(i) := '7';
+ when "1000" => out_string(i) := '8';
+ when "1001" => out_string(i) := '9';
+ when "1010" => out_string(i) := 'A';
+ when "1011" => out_string(i) := 'B';
+ when "1100" => out_string(i) := 'C';
+ when "1101" => out_string(i) := 'D';
+ when "1110" => out_string(i) := 'E';
+ when "1111" => out_string(i) := 'F';
+ when others =>
+ out_string(i) := 'J';
+ assert false
+ report " illegal std_logic_vector to string"
+ severity note;
+ end case;
+ end loop;
+ return out_string;
+ end;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function u2string(in_vector : unsigned; nibbles : natural) return string is
+ variable out_string : string(1 to nibbles);
+ variable temp_in_vector : unsigned(4*nibbles-1 downto 0);
+ variable vector : unsigned(3 downto 0);
+
+ begin
+ temp_in_vector := in_vector(in_vector'length-1 downto in_vector'length-temp_in_vector'length);
+ for i in 1 to nibbles loop
+ vector := temp_in_vector((4*(nibbles-i)+3) downto 4*(nibbles-i));
+ case vector is
+ when "0000" => out_string(i) := '0';
+ when "0001" => out_string(i) := '1';
+ when "0010" => out_string(i) := '2';
+ when "0011" => out_string(i) := '3';
+ when "0100" => out_string(i) := '4';
+ when "0101" => out_string(i) := '5';
+ when "0110" => out_string(i) := '6';
+ when "0111" => out_string(i) := '7';
+ when "1000" => out_string(i) := '8';
+ when "1001" => out_string(i) := '9';
+ when "1010" => out_string(i) := 'A';
+ when "1011" => out_string(i) := 'B';
+ when "1100" => out_string(i) := 'C';
+ when "1101" => out_string(i) := 'D';
+ when "1110" => out_string(i) := 'E';
+ when "1111" => out_string(i) := 'F';
+ when others =>
+ out_string(i) := 'U';
+ assert false report " illegal unsigned to string" severity note;
+ end case;
+ end loop;
+ return out_string;
+ end;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function u2asciichar(in_vector : unsigned(7 downto 0)) return character is
+ variable out_char : character;
+
+ begin
+ case in_vector is
+ when "00001001" => out_char := HT; -- Horizontal Tab
+ when "00100000" => out_char := ' ';
+ when "00100001" => out_char := '!';
+ when "00100010" => out_char := '"';
+ when "00100011" => out_char := '#';
+ when "00100100" => out_char := '$';
+ when "00100101" => out_char := '%';
+ when "00100110" => out_char := '&';
+ when "00100111" => out_char := ''';
+ when "00101000" => out_char := '(';
+ when "00101001" => out_char := ')';
+ when "00101010" => out_char := '*';
+ when "00101011" => out_char := '+';
+ when "00101100" => out_char := ',';
+ when "00101101" => out_char := '-';
+ when "00101110" => out_char := '.';
+ when "00101111" => out_char := '/';
+ when "00110000" => out_char := '0';
+ when "00110001" => out_char := '1';
+ when "00110010" => out_char := '2';
+ when "00110011" => out_char := '3';
+ when "00110100" => out_char := '4';
+ when "00110101" => out_char := '5';
+ when "00110110" => out_char := '6';
+ when "00110111" => out_char := '7';
+ when "00111000" => out_char := '8';
+ when "00111001" => out_char := '9';
+ when "00111010" => out_char := ':';
+ when "00111011" => out_char := ';';
+ when "00111100" => out_char := '<';
+ when "00111101" => out_char := '=';
+ when "00111110" => out_char := '>';
+ when "00111111" => out_char := '?';
+ when "01000000" => out_char := '@';
+ when "01000001" => out_char := 'A';
+ when "01000010" => out_char := 'B';
+ when "01000011" => out_char := 'C';
+ when "01000100" => out_char := 'D';
+ when "01000101" => out_char := 'E';
+ when "01000110" => out_char := 'F';
+ when "01000111" => out_char := 'G';
+ when "01001000" => out_char := 'H';
+ when "01001001" => out_char := 'I';
+ when "01001010" => out_char := 'J';
+ when "01001011" => out_char := 'K';
+ when "01001100" => out_char := 'L';
+ when "01001101" => out_char := 'M';
+ when "01001110" => out_char := 'N';
+ when "01001111" => out_char := 'O';
+ when "01010000" => out_char := 'P';
+ when "01010001" => out_char := 'Q';
+ when "01010010" => out_char := 'R';
+ when "01010011" => out_char := 'S';
+ when "01010100" => out_char := 'T';
+ when "01010101" => out_char := 'U';
+ when "01010110" => out_char := 'V';
+ when "01010111" => out_char := 'W';
+ when "01011000" => out_char := 'X';
+ when "01011001" => out_char := 'Y';
+ when "01011010" => out_char := 'Z';
+ when "01011011" => out_char := '[';
+ when "01011100" => out_char := '\';
+ when "01011101" => out_char := ']';
+ when "01011110" => out_char := '^';
+ when "01011111" => out_char := '_';
+ when "01100000" => out_char := '`';
+ when "01100001" => out_char := 'a';
+ when "01100010" => out_char := 'b';
+ when "01100011" => out_char := 'c';
+ when "01100100" => out_char := 'd';
+ when "01100101" => out_char := 'e';
+ when "01100110" => out_char := 'f';
+ when "01100111" => out_char := 'g';
+ when "01101000" => out_char := 'h';
+ when "01101001" => out_char := 'i';
+ when "01101010" => out_char := 'j';
+ when "01101011" => out_char := 'k';
+ when "01101100" => out_char := 'l';
+ when "01101101" => out_char := 'm';
+ when "01101110" => out_char := 'n';
+ when "01101111" => out_char := 'o';
+ when "01110000" => out_char := 'p';
+ when "01110001" => out_char := 'q';
+ when "01110010" => out_char := 'r';
+ when "01110011" => out_char := 's';
+ when "01110100" => out_char := 't';
+ when "01110101" => out_char := 'u';
+ when "01110110" => out_char := 'v';
+ when "01110111" => out_char := 'w';
+ when "01111000" => out_char := 'x';
+ when "01111001" => out_char := 'y';
+ when "01111010" => out_char := 'z';
+ when "01111011" => out_char := '{';
+ when "01111100" => out_char := '|';
+ when "01111101" => out_char := '}';
+ when "01111110" => out_char := '~';
+ when others =>
+ out_char := '*';
+ --assert false report " illegal unsigned to ascii character" severity note;
+ end case;
+ return out_char;
+ end;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function asciichar2u(in_char : character) return unsigned is
+ variable out_vect : unsigned(7 downto 0);
+
+ begin
+ case in_char is
+ when HT => out_vect := "00001001";
+ when ' ' => out_vect := "00100000";
+ when '!' => out_vect := "00100001";
+ when '"' => out_vect := "00100010";
+ when '#' => out_vect := "00100011";
+ when '$' => out_vect := "00100100";
+ when '%' => out_vect := "00100101";
+ when '&' => out_vect := "00100110";
+ when ''' => out_vect := "00100111";
+ when '(' => out_vect := "00101000";
+ when ')' => out_vect := "00101001";
+ when '*' => out_vect := "00101010";
+ when '+' => out_vect := "00101011";
+ when ',' => out_vect := "00101100";
+ when '-' => out_vect := "00101101";
+ when '.' => out_vect := "00101110";
+ when '/' => out_vect := "00101111";
+ when '0' => out_vect := "00110000";
+ when '1' => out_vect := "00110001";
+ when '2' => out_vect := "00110010";
+ when '3' => out_vect := "00110011";
+ when '4' => out_vect := "00110100";
+ when '5' => out_vect := "00110101";
+ when '6' => out_vect := "00110110";
+ when '7' => out_vect := "00110111";
+ when '8' => out_vect := "00111000";
+ when '9' => out_vect := "00111001";
+ when ':' => out_vect := "00111010";
+ when ';' => out_vect := "00111011";
+ when '<' => out_vect := "00111100";
+ when '=' => out_vect := "00111101";
+ when '>' => out_vect := "00111110";
+ when '?' => out_vect := "00111111";
+ when '@' => out_vect := "01000000";
+ when 'A' => out_vect := "01000001";
+ when 'B' => out_vect := "01000010";
+ when 'C' => out_vect := "01000011";
+ when 'D' => out_vect := "01000100";
+ when 'E' => out_vect := "01000101";
+ when 'F' => out_vect := "01000110";
+ when 'G' => out_vect := "01000111";
+ when 'H' => out_vect := "01001000";
+ when 'I' => out_vect := "01001001";
+ when 'J' => out_vect := "01001010";
+ when 'K' => out_vect := "01001011";
+ when 'L' => out_vect := "01001100";
+ when 'M' => out_vect := "01001101";
+ when 'N' => out_vect := "01001110";
+ when 'O' => out_vect := "01001111";
+ when 'P' => out_vect := "01010000";
+ when 'Q' => out_vect := "01010001";
+ when 'R' => out_vect := "01010010";
+ when 'S' => out_vect := "01010011";
+ when 'T' => out_vect := "01010100";
+ when 'U' => out_vect := "01010101";
+ when 'V' => out_vect := "01010110";
+ when 'W' => out_vect := "01010111";
+ when 'X' => out_vect := "01011000";
+ when 'Y' => out_vect := "01011001";
+ when 'Z' => out_vect := "01011010";
+ when '[' => out_vect := "01011011";
+ when '\' => out_vect := "01011100";
+ when ']' => out_vect := "01011101";
+ when '^' => out_vect := "01011110";
+ when '_' => out_vect := "01011111";
+ when '`' => out_vect := "01100000";
+ when 'a' => out_vect := "01100001";
+ when 'b' => out_vect := "01100010";
+ when 'c' => out_vect := "01100011";
+ when 'd' => out_vect := "01100100";
+ when 'e' => out_vect := "01100101";
+ when 'f' => out_vect := "01100110";
+ when 'g' => out_vect := "01100111";
+ when 'h' => out_vect := "01101000";
+ when 'i' => out_vect := "01101001";
+ when 'j' => out_vect := "01101010";
+ when 'k' => out_vect := "01101011";
+ when 'l' => out_vect := "01101100";
+ when 'm' => out_vect := "01101101";
+ when 'n' => out_vect := "01101110";
+ when 'o' => out_vect := "01101111";
+ when 'p' => out_vect := "01110000";
+ when 'q' => out_vect := "01110001";
+ when 'r' => out_vect := "01110010";
+ when 's' => out_vect := "01110011";
+ when 't' => out_vect := "01110100";
+ when 'u' => out_vect := "01110101";
+ when 'v' => out_vect := "01110110";
+ when 'w' => out_vect := "01110111";
+ when 'x' => out_vect := "01111000";
+ when 'y' => out_vect := "01111001";
+ when 'z' => out_vect := "01111010";
+ when '{' => out_vect := "01111011";
+ when '|' => out_vect := "01111100";
+ when '}' => out_vect := "01111101";
+ when '~' => out_vect := "01111110";
+ when others =>
+ out_vect := "00101010";
+ --assert false report " illegal char to unsigned" severity note;
+ end case;
+ return out_vect;
+ end;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+ function char2slv (in_char : character) return std_logic_vector is
+
+ variable out_vec : std_logic_vector(3 downto 0);
+
+ begin
+ case in_char is
+ when '0' => out_vec := "0000";
+ when '1' => out_vec := "0001";
+ when '2' => out_vec := "0010";
+ when '3' => out_vec := "0011";
+ when '4' => out_vec := "0100";
+ when '5' => out_vec := "0101";
+ when '6' => out_vec := "0110";
+ when '7' => out_vec := "0111";
+ when '8' => out_vec := "1000";
+ when '9' => out_vec := "1001";
+ when 'A' | 'a' => out_vec := "1010";
+ when 'B' | 'b' => out_vec := "1011";
+ when 'C' | 'c' => out_vec := "1100";
+ when 'D' | 'd' => out_vec := "1101";
+ when 'E' | 'e' => out_vec := "1110";
+ when 'F' | 'f' => out_vec := "1111";
+ when others =>
+ out_vec := "0000";
+ end case;
+ return out_vec;
+ end char2slv;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+ function char2u(in_char : character) return unsigned is
+
+ variable out_vec : unsigned(3 downto 0);
+
+ begin
+ case in_char is
+ when '0' => out_vec := "0000";
+ when '1' => out_vec := "0001";
+ when '2' => out_vec := "0010";
+ when '3' => out_vec := "0011";
+ when '4' => out_vec := "0100";
+ when '5' => out_vec := "0101";
+ when '6' => out_vec := "0110";
+ when '7' => out_vec := "0111";
+ when '8' => out_vec := "1000";
+ when '9' => out_vec := "1001";
+ when 'A' | 'a' => out_vec := "1010";
+ when 'B' | 'b' => out_vec := "1011";
+ when 'C' | 'c' => out_vec := "1100";
+ when 'D' | 'd' => out_vec := "1101";
+ when 'E' | 'e' => out_vec := "1110";
+ when 'F' | 'f' => out_vec := "1111";
+ when others =>
+ out_vec := "0000";
+ end case;
+ return out_vec;
+ end char2u;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function hex_to_ascii(in_vector : std_logic_vector; nibbles : natural) return string is
+ variable out_string : string(1 to nibbles);
+ variable temp_in_vector : std_logic_vector(4*nibbles-1 downto 0);
+ variable vector : std_logic_vector(3 downto 0);
+
+ begin
+ temp_in_vector := in_vector(in_vector'length-1 downto in_vector'length-temp_in_vector'length);
+ for i in 1 to nibbles loop
+ vector := temp_in_vector((4*(nibbles-i)+3) downto 4*(nibbles-i));
+ case vector is
+ when "0000" => out_string(i) := '0';
+ when "0001" => out_string(i) := '1';
+ when "0010" => out_string(i) := '2';
+ when "0011" => out_string(i) := '3';
+ when "0100" => out_string(i) := '4';
+ when "0101" => out_string(i) := '5';
+ when "0110" => out_string(i) := '6';
+ when "0111" => out_string(i) := '7';
+ when "1000" => out_string(i) := '8';
+ when "1001" => out_string(i) := '9';
+ when "1010" => out_string(i) := 'A';
+ when "1011" => out_string(i) := 'B';
+ when "1100" => out_string(i) := 'C';
+ when "1101" => out_string(i) := 'D';
+ when "1110" => out_string(i) := 'E';
+ when "1111" => out_string(i) := 'F';
+ when others =>
+ out_string(i) := 'J';
+ assert false
+ report " illegal std_logic_vector to string"
+ severity note;
+ end case;
+ end loop;
+ return out_string;
+ end;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function u2ascii(in_vector : unsigned; nibbles : natural) return string is
+ variable out_string : string(1 to nibbles);
+ variable temp_in_vector : unsigned(4*nibbles-1 downto 0);
+ variable vector : unsigned(3 downto 0);
+
+ begin
+ temp_in_vector := in_vector(in_vector'length-1 downto in_vector'length-temp_in_vector'length);
+ for i in 1 to nibbles loop
+ vector := temp_in_vector((4*(nibbles-i)+3) downto 4*(nibbles-i));
+ case vector is
+ when "0000" => out_string(i) := '0';
+ when "0001" => out_string(i) := '1';
+ when "0010" => out_string(i) := '2';
+ when "0011" => out_string(i) := '3';
+ when "0100" => out_string(i) := '4';
+ when "0101" => out_string(i) := '5';
+ when "0110" => out_string(i) := '6';
+ when "0111" => out_string(i) := '7';
+ when "1000" => out_string(i) := '8';
+ when "1001" => out_string(i) := '9';
+ when "1010" => out_string(i) := 'A';
+ when "1011" => out_string(i) := 'B';
+ when "1100" => out_string(i) := 'C';
+ when "1101" => out_string(i) := 'D';
+ when "1110" => out_string(i) := 'E';
+ when "1111" => out_string(i) := 'F';
+ when others =>
+ out_string(i) := 'U';
+ assert false report " illegal unsigned to string" severity note;
+ end case;
+ end loop;
+ return out_string;
+ end;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function hex_data_wrd(in_vector : std_logic_vector) return string is
+ variable out_string : string(1 to 8);
+ variable temp_in_vector : std_logic_vector(31 downto 0);
+ variable vector : std_logic_vector(3 downto 0);
+
+ begin
+ temp_in_vector := in_vector;
+ for i in 1 to 8 loop
+ vector := temp_in_vector((35-(4*i)) downto (32-(4*i)));
+ case vector is
+ when "0000" => out_string(i) := '0';
+ when "0001" => out_string(i) := '1';
+ when "0010" => out_string(i) := '2';
+ when "0011" => out_string(i) := '3';
+ when "0100" => out_string(i) := '4';
+ when "0101" => out_string(i) := '5';
+ when "0110" => out_string(i) := '6';
+ when "0111" => out_string(i) := '7';
+ when "1000" => out_string(i) := '8';
+ when "1001" => out_string(i) := '9';
+ when "1010" => out_string(i) := 'A';
+ when "1011" => out_string(i) := 'B';
+ when "1100" => out_string(i) := 'C';
+ when "1101" => out_string(i) := 'D';
+ when "1110" => out_string(i) := 'E';
+ when "1111" => out_string(i) := 'F';
+ when others =>
+ out_string(i) := 'J';
+ assert false
+ report " illegal std_logic_vector to string"
+ severity note;
+ end case;
+ end loop;
+ return out_string;
+ end;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function hex_data_dblwrd(in_vector : std_logic_vector) return string is
+ variable out_string : string(1 to 16);
+ variable temp_in_vector : std_logic_vector(63 downto 0);
+ variable vector : std_logic_vector(3 downto 0);
+
+ begin
+ temp_in_vector := in_vector;
+ for i in 1 to 16 loop
+ vector := temp_in_vector((67-(4*i)) downto (64-(4*i)));
+ case vector is
+ when "0000" => out_string(i) := '0';
+ when "0001" => out_string(i) := '1';
+ when "0010" => out_string(i) := '2';
+ when "0011" => out_string(i) := '3';
+ when "0100" => out_string(i) := '4';
+ when "0101" => out_string(i) := '5';
+ when "0110" => out_string(i) := '6';
+ when "0111" => out_string(i) := '7';
+ when "1000" => out_string(i) := '8';
+ when "1001" => out_string(i) := '9';
+ when "1010" => out_string(i) := 'A';
+ when "1011" => out_string(i) := 'B';
+ when "1100" => out_string(i) := 'C';
+ when "1101" => out_string(i) := 'D';
+ when "1110" => out_string(i) := 'E';
+ when "1111" => out_string(i) := 'F';
+ when others =>
+ out_string(i) := 'J';
+ assert false
+ report " illegal std_logic_vector to string"
+ severity note;
+ end case;
+ end loop;
+ return out_string;
+ end;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function hex_data_dblwrdz(in_vector : std_logic_vector) return string is
+ variable out_string : string(1 to 16);
+ variable temp_in_vector : std_logic_vector(63 downto 0);
+ variable vector : std_logic_vector(3 downto 0);
+
+ begin
+ temp_in_vector := in_vector;
+ for i in 1 to 16 loop
+ vector := temp_in_vector((67-(4*i)) downto (64-(4*i)));
+ case vector is
+ when "0000" => out_string(i) := '0';
+ when "0001" => out_string(i) := '1';
+ when "0010" => out_string(i) := '2';
+ when "0011" => out_string(i) := '3';
+ when "0100" => out_string(i) := '4';
+ when "0101" => out_string(i) := '5';
+ when "0110" => out_string(i) := '6';
+ when "0111" => out_string(i) := '7';
+ when "1000" => out_string(i) := '8';
+ when "1001" => out_string(i) := '9';
+ when "1010" => out_string(i) := 'A';
+ when "1011" => out_string(i) := 'B';
+ when "1100" => out_string(i) := 'C';
+ when "1101" => out_string(i) := 'D';
+ when "1110" => out_string(i) := 'E';
+ when "1111" => out_string(i) := 'F';
+ when "ZZZZ" => out_string(i) := 'Z';
+ when others =>
+ out_string(i) := 'J';
+ assert false
+ report " illegal std_logic_vector to string"
+ severity note;
+ end case;
+ end loop;
+ return out_string;
+ end;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+ -- returns true if the character is a valid hexadecimal character.
+ function is_hex(c : character) return boolean is
+ begin
+ case c is
+ when '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
+ 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'a' | 'b' | 'c' | 'd' |
+ 'e' | 'f' =>
+ return(true);
+ when others =>
+ return(false);
+ end case;
+ end is_hex;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+ -- returns true if the character is a valid hexadecimal character.
+ function is_std_logic(c : character) return boolean is
+ begin
+ case c is
+ when '0' | '1' | 'u' | 'U' | 'x' | 'X' | 'z' | 'Z' =>
+ return(true);
+ when others =>
+ return(false);
+ end case;
+ end is_std_logic;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+ -- returns true if the character is whitespace.
+ function is_space(c : character) return boolean is
+ begin
+ case c is
+ when ' ' | HT =>
+ return(true);
+ when others =>
+ return(false);
+ end case;
+ end is_space;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function char2sl(in_char : character) return std_logic is
+
+ variable out_bit : std_logic;
+
+ begin
+
+ if (in_char = '1') then
+ out_bit := '1';
+ elsif (in_char = '0') then
+ out_bit := '0';
+ elsif (in_char = 'x') then
+ out_bit := 'X';
+ elsif (in_char = 'X') then
+ out_bit := 'X';
+ elsif (in_char = 'u') then
+ out_bit := 'U';
+ elsif (in_char = 'U') then
+ out_bit := 'U';
+ elsif (in_char = 'z') then
+ out_bit := 'Z';
+ elsif (in_char = 'Z') then
+ out_bit := 'Z';
+ else
+ assert false
+ report "illegal character to std_logic"
+ severity note;
+ end if;
+
+-- Mysteriously, the following code did not work in place of the
+-- above chain of if-elsif-else logic... it seemed to always return '1'.
+-- I cannot tell why. -- John Clayton
+-- case in_char is
+-- when '1' =>
+-- out_bit:= '1';
+-- when '0' =>
+-- out_bit:= '1';
+-- when 'u' | 'U' =>
+-- out_bit:= 'U';
+-- when 'x' | 'X' =>
+-- out_bit:= 'X';
+-- when 'z' | 'Z' =>
+-- out_bit:= 'Z';
+-- when others =>
+-- assert false
+-- report "illegal character to std_logic"
+-- severity note;
+-- end case;
+
+ return out_bit;
+ end char2sl;
+
+
+
+------------------------------------------------------------------------------------
+-- Converts Standard Logic Vectors to Unsigned
+------------------------------------------------------------------------------------
+
+ function slv2u(in_a : std_logic_vector) return unsigned is
+ variable i : natural;
+ variable o : unsigned(in_a'length-1 downto 0);
+
+ begin
+
+ o := (others=>'0');
+ for i in 0 to in_a'length-1 loop
+ o(i) := in_a(i);
+ end loop;
+
+ return(o);
+
+ end;
+
+------------------------------------------------------------------------------------
+-- Converts Unsigned to Standard Logic Vector
+------------------------------------------------------------------------------------
+
+ function u2slv(in_a : unsigned) return std_logic_vector is
+ variable i : natural;
+ variable o : std_logic_vector(in_a'length-1 downto 0);
+
+ begin
+
+ o := (others=>'0');
+ for i in 0 to in_a'length-1 loop
+ o(i) := in_a(i);
+ end loop;
+
+ return(o);
+
+ end;
+
+------------------------------------------------------------------------------------
+-- Converts Standard Logic Vectors to Signed
+------------------------------------------------------------------------------------
+
+ function slv2s(in_a : std_logic_vector) return signed is
+ variable i : natural;
+ variable o : signed(in_a'length-1 downto 0);
+
+ begin
+
+ o := (others=>'0');
+ for i in 0 to in_a'length-1 loop
+ o(i) := in_a(i);
+ end loop;
+
+ return(o);
+
+ end;
+
+------------------------------------------------------------------------------------
+-- Converts Signed to Standard Logic Vector
+------------------------------------------------------------------------------------
+
+ function s2slv(in_a : signed) return std_logic_vector is
+ variable i : natural;
+ variable o : std_logic_vector(in_a'length-1 downto 0);
+
+ begin
+
+ o := (others=>'0');
+ for i in 0 to in_a'length-1 loop
+ o(i) := in_a(i);
+ end loop;
+
+ return(o);
+
+ end;
+
+------------------------------------------------------------------------------------
+-- Resizes Standard Logic Vectors, "right justified" i.e. starts at LSB...
+------------------------------------------------------------------------------------
+
+ function slv_resize(in_vect : std_logic_vector; out_size : integer) return std_logic_vector is
+ variable i : integer;
+ variable o_vect : std_logic_vector(out_size-1 downto 0);
+
+ begin
+
+ o_vect := (others=>'0');
+ for i in 0 to in_vect'length-1 loop
+ if (i'0');
+ j := out_size-1;
+ for i in in_vect'length-1 downto 0 loop
+ if (j>=0) then
+ o_vect(j) := in_vect(i);
+ j := j-1;
+ end if;
+ end loop;
+
+ return(o_vect);
+
+ end slv_resize_l;
+
+------------------------------------------------------------------------------------
+-- Resizes Standard Logic Vectors, "right justified with sign extension"
+------------------------------------------------------------------------------------
+
+ function slv_resize_se(in_vect : std_logic_vector; out_size : integer) return std_logic_vector is
+ variable i : integer;
+ variable o_vect : std_logic_vector(out_size-1 downto 0);
+
+ begin
+
+ o_vect := (others=>in_vect(in_vect'length-1));
+ for i in 0 to in_vect'length-1 loop
+ if (i'0');
+ for i in 0 to in_vect'length-1 loop
+ if (i'0');
+ j := out_size-1;
+ for i in in_vect'length-1 downto 0 loop
+ if (j>=0) then
+ o_vect(j) := in_vect(i);
+ j := j-1;
+ end if;
+ end loop;
+
+ return(o_vect);
+
+ end s_resize_l;
+
+------------------------------------------------------------------------------------
+-- Resizes Signed, "right justified with sign extension"
+------------------------------------------------------------------------------------
+
+ function s_resize_se(in_vect : signed; out_size : integer) return signed is
+ variable i : integer;
+ variable o_vect : signed(out_size-1 downto 0);
+
+ begin
+
+ o_vect := (others=>in_vect(in_vect'length-1));
+ for i in 0 to in_vect'length-1 loop
+ if (i'0');
+ for i in 0 to in_vect'length-1 loop
+ if (i'0');
+ j := out_size-1;
+ for i in in_vect'length-1 downto 0 loop
+ if (j>=0) then
+ o_vect(j) := in_vect(i);
+ j := j-1;
+ end if;
+ end loop;
+
+ return(o_vect);
+
+ end u_resize_l;
+
+------------------------------------------------------------------------------------
+-- Selects a slice of the input vector, "right justified" i.e. slice 0 starts at LSB...
+------------------------------------------------------------------------------------
+
+ function u_select(in_vect : unsigned; slice_num : integer; slice_size : integer) return unsigned is
+ variable i : integer;
+ variable o_vect : unsigned(slice_size-1 downto 0);
+
+ begin
+ o_vect := (others=>'0');
+ for i in 0 to o_vect'length-1 loop
+ o_vect(i) := in_vect(i+slice_num*slice_size);
+ end loop;
+
+ return(o_vect);
+
+ end u_select;
+
+------------------------------------------------------------------------------------
+-- Bit Reverses the input vector
+------------------------------------------------------------------------------------
+
+ function u_reverse(in_vect : unsigned) return unsigned is
+ variable i : integer;
+ variable o_vect : unsigned(in_vect'length-1 downto 0);
+
+ begin
+
+ for i in in_vect'length-1 downto 0 loop
+ o_vect(in_vect'length-1-i) := in_vect(i);
+ end loop;
+
+ return(o_vect);
+
+ end u_reverse;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function str2u(in_string : string; out_size:integer) return unsigned is
+
+ variable uval : unsigned(out_size-1 downto 0);
+ variable nibble : unsigned(3 downto 0);
+ begin
+ uval := (others=>'0');
+ for j in in_string'range loop
+ uval(uval'length-1 downto 4) := uval(uval'length-5 downto 0);
+ uval(3 downto 0) := char2u(in_string(j));
+ end loop;
+ return uval;
+ end str2u;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function str2s(in_string : string; out_size:integer) return signed is
+
+ variable uval : signed(out_size-1 downto 0);
+ variable nibble : signed(3 downto 0);
+ begin
+ uval := (others=>'0');
+ for j in in_string'range loop
+ uval(uval'length-1 downto 4) := uval(uval'length-5 downto 0);
+ uval(3 downto 0) := signed(char2u(in_string(j)));
+ end loop;
+ return uval;
+ end str2s;
+
+------------------------------------------------------------------------------------
+-- Power Function for naturals
+------------------------------------------------------------------------------------
+
+-- function "**"(in_a : natural; in_b : natural) return natural is
+-- variable i : natural;
+-- variable o : natural;
+--
+-- begin
+--
+-- -- Coded with a for loop: works in simulation, but Synplify will not synthesize.
+---- if (in_b=0) then
+---- o := 1;
+---- else
+---- o := in_a;
+---- if (in_b>1) then
+---- for i in 2 to in_b loop
+---- o := o * in_a;
+---- end loop;
+---- end if;
+---- end if;
+---- return(o);
+--
+-- if (in_b=0) then
+-- o := 1;
+-- else
+-- o := in_a;
+-- i := 1;
+-- while (i0) then
+ o := o(out_size-2 downto 0) & '0';
+ j := j-1;
+ end if;
+ end loop;
+ return(o);
+
+ end;
+
+------------------------------------------------------------------------------------
+-- A sort of "barrel shifter." Produces the ASR by in_a of the input...
+------------------------------------------------------------------------------------
+
+ function asr_function(in_vect : signed; in_a : natural) return signed is
+ variable i : natural;
+ variable j : natural;
+ variable o_vect : signed(in_vect'length-1 downto 0);
+
+ begin
+
+ o_vect := in_vect;
+ j := in_a;
+ for i in 0 to in_vect'length-1 loop -- Now loop to fill in the actual results
+ if (j>0) then
+ o_vect := o_vect(o_vect'length-1) & o_vect(o_vect'length-1 downto 1);
+ j := j-1;
+ end if;
+ end loop;
+
+ return(o_vect);
+
+ end asr_function;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function bit_width (maxval : integer) return integer is
+
+ variable w : integer;
+ begin
+ if (maxval<2) then
+ w := 1;
+ else
+ w := integer(ceil(log2(real(maxval))));
+ end if;
+
+ return w;
+ end bit_width;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function bit_width (maxval : real) return integer is
+
+ variable w : integer;
+ begin
+ if (maxval<2.0) then
+ w := 1;
+ else
+ w := integer(ceil(log2(maxval)));
+ end if;
+
+ return w;
+ end bit_width;
+
+------------------------------------------------------------------------------------
+-- Timer width differs from bit width in the following way:
+-- Bit width gives a vector large enough to have maxval different states, but
+-- timer width gives a vector large enough to hold the quantity maxval.
+--
+-- The difference is critical when using timers, since they often count down from
+-- the initial value, and trigger timeout at a value of 1... So for maxval equal
+-- to a power of two, an extra bit must be reserved. This is done by adding one
+-- to the maxval input...
+------------------------------------------------------------------------------------
+
+ function timer_width (maxval : integer) return integer is
+
+ variable w : integer;
+ begin
+ if (maxval<2) then
+ w := 1;
+ else
+ w := integer(ceil(log2(real(maxval+1))));
+ end if;
+
+ return w;
+ end timer_width;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function timer_width (maxval : real) return integer is
+
+ variable w : integer;
+ begin
+ if (maxval<2.0) then
+ w := 1;
+ else
+ w := integer(ceil(log2(maxval+1.0)));
+ end if;
+
+ return w;
+ end timer_width;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+ function num_words (num_bits : integer; bits_per_word : integer) return integer is
+
+ variable w : integer;
+ begin
+ if (num_bits mod bits_per_word /= 0) then
+ w := integer(ceil(real(num_bits) / real(bits_per_word)));
+ else
+ w := integer(floor(real(num_bits) / real(bits_per_word)));
+ end if;
+ return w;
+ end num_words;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+function asciichar2u2(d:character) return unsigned is
+ variable dout : unsigned(0 to 7);
+ variable ascii_int : integer := 0;
+ variable val : integer := 0;
+begin
+ -- Get integer value of the character
+ ascii_int := character'pos(d);
+ for index in dout'range loop
+ val := ascii_int rem 2;
+ ascii_int := ascii_int/2;
+ if val=0 then
+ dout(dout'high-index):='0';
+ else
+ dout(dout'high-index):='1';
+ end if;
+ end loop;
+
+ return dout;
+end asciichar2u2;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+-- converts a string into std_logic_vector
+
+function str2u(s: string) return unsigned is
+ variable uv: unsigned(8*s'high-1 downto 0);
+ variable k: integer;
+begin
+ k := s'high-s'low;
+ for i in s'range loop
+-- uv(8*k+7 downto 8*k) := unsigned(chartobyte(s(i)));
+ uv(8*k+7 downto 8*k) := asciichar2u2(s(i));
+ k := k - 1;
+ end loop;
+ return uv;
+end str2u;
+
+------------------------------------------------------------------------------------
+-- Counts the number of ones in an unsigned input
+------------------------------------------------------------------------------------
+
+ function u_ones(in_a : unsigned) return natural is
+ variable i,c : natural;
+
+ begin
+ c := 0;
+ for i in 0 to in_a'length-1 loop
+ if (in_a(i)='1') then
+ c := c+1;
+ end if;
+ end loop;
+
+ return(c);
+
+ end;
+
+------------------------------------------------------------------------------------
+--
+------------------------------------------------------------------------------------
+
+end convert_pack;
+
+
+
Index: sd_card_controller/trunk/rtl/VHDL/fifo_pack.vhd
===================================================================
--- sd_card_controller/trunk/rtl/VHDL/fifo_pack.vhd (nonexistent)
+++ sd_card_controller/trunk/rtl/VHDL/fifo_pack.vhd (revision 14)
@@ -0,0 +1,1346 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+package fifo_pack is
+
+ component generic_fifo
+ generic(
+ WIDTH : integer;
+ DEPTH : integer;
+ PF_FULL_POINT : integer;
+ PF_FLAG_POINT : integer;
+ PF_EMPTY_POINT : integer
+ );
+ port (
+ sys_rst_n : in std_logic; -- Asynchronous
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ reset_i : in std_logic; -- Synchronous
+
+ fifo_rd_i : in std_logic;
+ fifo_dout : out unsigned(WIDTH-1 downto 0);
+
+ fifo_wr_i : in std_logic;
+ fifo_din : in unsigned(WIDTH-1 downto 0);
+
+ fifo_full : out std_logic;
+ fifo_empty : out std_logic;
+ fifo_pf_full : out std_logic;
+ fifo_pf_flag : out std_logic;
+ fifo_pf_empty : out std_logic
+ );
+ end component;
+
+ component fifo_with_fill_level
+ generic(
+ WIDTH : integer;
+ DEPTH : integer;
+ FILL_LEVEL_BITS : integer; -- Should be at least int(floor(log2(DEPTH))+1.0)
+ PF_FULL_POINT : integer;
+ PF_FLAG_POINT : integer;
+ PF_EMPTY_POINT : integer
+ );
+ port (
+ sys_rst_n : in std_logic; -- Asynchronous
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ reset_i : in std_logic; -- Synchronous
+
+ fifo_rd_i : in std_logic;
+ fifo_dout : out unsigned(WIDTH-1 downto 0);
+
+ fifo_wr_i : in std_logic;
+ fifo_din : in unsigned(WIDTH-1 downto 0);
+
+ fifo_fill_level : out unsigned(FILL_LEVEL_BITS-1 downto 0);
+ fifo_full : out std_logic;
+ fifo_empty : out std_logic;
+ fifo_pf_full : out std_logic;
+ fifo_pf_flag : out std_logic;
+ fifo_pf_empty : out std_logic
+ );
+ end component;
+
+ component swiss_army_fifo
+ generic(
+ USE_BRAM : integer; -- Set to nonzero value for BRAM, zero for distributed RAM
+ WIDTH : integer;
+ DEPTH : integer;
+ FILL_LEVEL_BITS : integer; -- Should be at least int(floor(log2(DEPTH))+1.0)
+ PF_FULL_POINT : integer;
+ PF_FLAG_POINT : integer;
+ PF_EMPTY_POINT : integer
+ );
+ port (
+ sys_rst_n : in std_logic; -- Asynchronous
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ reset_i : in std_logic; -- Synchronous
+
+ fifo_wr_i : in std_logic;
+ fifo_din : in unsigned(WIDTH-1 downto 0);
+
+ fifo_rd_i : in std_logic;
+ fifo_dout : out unsigned(WIDTH-1 downto 0);
+
+ fifo_fill_level : out unsigned(FILL_LEVEL_BITS-1 downto 0);
+ fifo_full : out std_logic;
+ fifo_empty : out std_logic;
+ fifo_pf_full : out std_logic;
+ fifo_pf_flag : out std_logic;
+ fifo_pf_empty : out std_logic
+ );
+ end component;
+
+ component swiss_army_fifo_cdc
+ generic (
+ USE_BRAM : integer; -- Set to nonzero value for BRAM, zero for distributed RAM
+ WIDTH : integer;
+ DEPTH : integer;
+ FILL_LEVEL_BITS : integer; -- Should be at least int(floor(log2(DEPTH))+1.0)
+ PF_FULL_POINT : integer;
+ PF_FLAG_POINT : integer;
+ PF_EMPTY_POINT : integer
+ );
+ port (
+ sys_rst_n : in std_logic; -- Asynchronous
+
+ wr_clk_i : in std_logic;
+ wr_clk_en_i : in std_logic;
+ wr_reset_i : in std_logic; -- Synchronous
+ wr_en_i : in std_logic;
+ wr_dat_i : in unsigned(WIDTH-1 downto 0);
+ wr_fifo_level : out unsigned(FILL_LEVEL_BITS-1 downto 0);
+ wr_fifo_full : out std_logic;
+ wr_fifo_empty : out std_logic;
+ wr_fifo_pf_full : out std_logic;
+ wr_fifo_pf_flag : out std_logic;
+ wr_fifo_pf_empty : out std_logic;
+
+ rd_clk_i : in std_logic;
+ rd_clk_en_i : in std_logic;
+ rd_reset_i : in std_logic; -- Synchronous
+ rd_en_i : in std_logic;
+ rd_dat_o : out unsigned(WIDTH-1 downto 0);
+ rd_fifo_level : out unsigned(FILL_LEVEL_BITS-1 downto 0);
+ rd_fifo_full : out std_logic;
+ rd_fifo_empty : out std_logic;
+ rd_fifo_pf_full : out std_logic;
+ rd_fifo_pf_flag : out std_logic;
+ rd_fifo_pf_empty : out std_logic
+ );
+ end component;
+
+ component data_packer
+ generic (
+ ADR_W : integer; -- Bit width of snoop address
+ DATA_IN_W : integer; -- Maximum in_dat_i word size
+ LOG2_DATA_IN_W : integer; -- Bit width of in_word_size_i
+ DATA_OUT_W : integer; -- Bit width of archive data
+ FIFO_DEPTH : integer -- Size of BRAM FIFO buffer
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Input Port
+ in_dat_i : in unsigned(DATA_IN_W-1 downto 0);
+ in_word_size_i : in unsigned(LOG2_DATA_IN_W downto 0);
+ in_last_word_i : in std_logic;
+ in_adr_i : in unsigned(ADR_W-1 downto 0);
+ in_match_adr_i : in unsigned(ADR_W-1 downto 0);
+ in_cyc_i : in std_logic;
+ in_ack_i : in std_logic;
+
+ -- Status
+ fifo_full_o : out std_logic;
+ fifo_reset_i : in std_logic;
+
+ -- Output Port
+ tx_done_i : in std_logic;
+ tx_buff_i : in unsigned(ADR_W-1 downto 0);
+ out_dat_o : out unsigned(DATA_OUT_W-1 downto 0);
+ out_last_word_o : out std_logic;
+ out_cyc_o : out std_logic;
+ out_ack_i : in std_logic
+
+ );
+ end component;
+
+end fifo_pack;
+
+
+--------------------------------------------------------------
+-- Generic FIFO
+--------------------------------------------------------------
+-- Description:
+--
+-- This is a generic, parameterized FIFO module meant to be used
+-- by logic which is already synchronous to the system clock.
+-- The input and output use a single system clock.
+-- Also, there is no handshaking for read/write requests.
+-- This means that Read/Write request assertions must conform to
+-- setup & hold times within the system clock domain in order for
+-- this FIFO to operate correctly. In other words, don't use
+-- this FIFO with any inputs originating from a different clock
+-- domain.
+--
+-- This FIFO has a memory array which is not address pipelined,
+-- and which operates in a "single clock cycle response" mode
+-- so that writes and reads are completed at the first clock
+-- edge following the assertion of a read or write request.
+-- Therefore, the system clock speed must be limited to speeds
+-- at which the memory can respond in that fashion. Also, it is
+-- assumed that the memory array used for the FIFO storage will
+-- be synthesized with separate input and output data paths, such
+-- that reads and writes can occur at the same clock edge. Thus
+-- there does not need to be a prioritization of read vs. write
+-- operations, since they can both occur at any given clock edge.
+--
+-- NOTES:
+-- The DEPTH does not need to be a power of two.
+-- This FIFO has been simulated using DEPTH values down to as
+-- low as 2. Depths less than this are considered degenerate
+-- cases, and will produce errors.
+--
+-- Since the read_row points to the data about to be read,
+-- the fifo_dout bus contains the read data before a read
+-- request is actually asserted. In the case of an empty
+-- FIFO, the output data bus is driven by the input data bus.
+--
+-- If read and write are requested simultaneously to a full
+-- FIFO, it will remain full and it operates as an N stage
+-- delay line.
+--
+-- If read and write are requested simultaneously to an empty
+-- FIFO, it will remain empty. No actual access to storage
+-- is performed, and the input is simply passed to the output,
+-- which could be considered to be a zero stage delay line...
+--
+-- If the PF empty and full points are set to be overlapping,
+-- they can conceivably both be active at the same time.
+-- PF empty values less than zero cause the fifo_pf_empty
+-- output to stay inactive. PF full values greater than the
+-- FIFO depth cause the fifo_pf_full output to behave exactly
+-- the same as fifo_full.
+-- There is a third fifo fill level output, fifo_pf_flag.
+-- It is high only when the FIFO fill level is greater than
+-- or equal to the desired set value.
+--
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+library work;
+use work.convert_pack.all;
+
+entity generic_fifo is
+ generic (
+ WIDTH : integer := 8;
+ DEPTH : integer := 5;
+ PF_FULL_POINT : integer := 3;
+ PF_FLAG_POINT : integer := 2;
+ PF_EMPTY_POINT : integer := 0
+ );
+ port (
+ sys_rst_n : in std_logic; -- Asynchronous
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ reset_i : in std_logic; -- Synchronous
+
+ fifo_rd_i : in std_logic;
+ fifo_dout : out unsigned(WIDTH-1 downto 0);
+
+ fifo_wr_i : in std_logic;
+ fifo_din : in unsigned(WIDTH-1 downto 0);
+
+ fifo_full : out std_logic;
+ fifo_empty : out std_logic;
+ fifo_pf_full : out std_logic;
+ fifo_pf_flag : out std_logic;
+ fifo_pf_empty : out std_logic
+ );
+end generic_fifo;
+
+architecture beh of generic_fifo is
+
+ -- Constants
+ constant FLG_WIDTH : integer := bit_width(DEPTH); -- Bit Width of memory address. Pointers are one bit wider,
+ -- so that fill_level can represent the full quantity of
+ -- items stored in the FIFO. This is important when DEPTH
+ -- is an even power of 2.
+
+ -- Signal Declarations
+ signal rd_row : unsigned(FLG_WIDTH downto 0);
+ signal wr_row : unsigned(FLG_WIDTH downto 0);
+ signal fill_level : unsigned(FLG_WIDTH downto 0);
+
+ TYPE memory_array IS
+ ARRAY (integer RANGE 0 TO DEPTH-1) OF unsigned(WIDTH-1 DOWNTO 0);
+
+ SIGNAL fifo_array: memory_array;
+
+ TYPE STATE_TYPE IS (st_empty, st_data, st_full);
+
+ signal current_state : STATE_TYPE ;
+
+
+BEGIN
+
+ fifo_empty <= '1' when (current_state=st_empty) else '0';
+ fifo_full <= '1' when (current_state=st_full) else '0';
+ fifo_pf_full <= '1' when (fill_level>=PF_FULL_POINT or current_state=st_full) else '0';
+ fifo_pf_flag <= '1' when (fill_level>=PF_FLAG_POINT) else '0';
+ fifo_pf_empty <= '1' when (fill_level<=PF_EMPTY_POINT and current_state/=st_full) else '0';
+
+-------------------------
+-- The FIFO Fill Level
+fill_level_proc: process(wr_row, rd_row, current_state)
+ begin
+ if (current_state=st_empty) then
+ fill_level <= (others=>'0');
+ elsif (wr_row>rd_row) then
+ fill_level <= wr_row-rd_row;
+ else
+ fill_level <= DEPTH+(wr_row-rd_row);
+ end if;
+ end process;
+
+-------------------------
+-- The FIFO memory
+memory: process (sys_clk, sys_rst_n)
+ variable i : integer;
+ begin
+ -- The memory initialization at reset was included for simulation only.
+ -- It can be removed for synthesis if desired.
+ if (sys_rst_n='0') then
+ for i in 0 to DEPTH-1 loop
+ fifo_array(i) <= (others=>'0');
+ end loop;
+ elsif (sys_clk'event and sys_clk = '1') then
+ if (sys_clk_en='1') then
+ if ((fifo_wr_i='1' and current_state/=st_full) or
+ (fifo_wr_i='1' and current_state=st_full and fifo_rd_i='1')) then
+ fifo_array(to_integer(wr_row(FLG_WIDTH-1 downto 0))) <= fifo_din;
+ end if;
+ end if;
+ end if;
+ end process;
+fifo_dout <= fifo_array(to_integer(rd_row(FLG_WIDTH-1 downto 0))) when (current_state/=st_empty)
+ else fifo_din;
+
+
+-------------------------
+-- The FIFO state machine
+ clocked : PROCESS(sys_clk, sys_rst_n)
+
+ procedure do_write is
+ begin
+ if (wr_row=DEPTH-1) then -- Roll buffer index for non-power-of-two
+ wr_row <= (others=>'0');
+ else
+ wr_row<=wr_row+1;
+ end if;
+ end do_write;
+
+ procedure do_read is
+ begin
+ if (rd_row=DEPTH-1) then -- Roll buffer index for non-power-of-two
+ rd_row <= (others=>'0');
+ else
+ rd_row<=rd_row+1;
+ end if;
+ end do_read;
+
+ begin
+ if (sys_rst_n = '0') then
+ current_state <= st_empty;
+ rd_row <= (others=>'0');
+ wr_row <= (others=>'0');
+
+ elsif (sys_clk'EVENT and sys_clk = '1') then
+ if (sys_clk_en='1') then
+ if (reset_i='1') then
+ current_state <= st_empty;
+ wr_row <= (others=>'0');
+ rd_row <= (others=>'0');
+ else
+ case current_state is
+
+ when st_empty =>
+ if (fifo_wr_i='1') then
+ do_write;
+ if (fifo_rd_i='0') then
+ current_state<=st_data;
+ else
+ do_read;
+ end if;
+ end if;
+
+ when st_data =>
+ if (fifo_wr_i='1') then
+ do_write;
+ if (fifo_rd_i='0' and fill_level=DEPTH-1) then
+ current_state<=st_full;
+ end if;
+ end if;
+ if (fifo_rd_i='1') then
+ do_read;
+ if (fifo_wr_i='0' and fill_level=1) then
+ current_state<=st_empty;
+ end if;
+ end if;
+
+ when st_full =>
+ if (fifo_rd_i='1') then
+ do_read;
+ if (fifo_wr_i='0') then
+ current_state<=st_data;
+ else
+ do_write;
+ end if;
+ end if;
+
+ when others => null;
+ end case;
+
+ end if;
+ end if; -- sys_clk_en
+ end if; -- sys_clk
+ end process clocked;
+
+
+end beh;
+
+
+--------------------------------------------------------------
+-- FIFO with fill level output
+--------------------------------------------------------------
+-- Description:
+--
+-- This is the same as "generic_fifo" but with an additional
+-- output providing the fifo_fill_level.
+--
+-- The bit width of this additional output is set by a generic
+-- parameter
+--
+--
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+library work;
+use work.convert_pack.all;
+
+entity fifo_with_fill_level is
+ generic (
+ WIDTH : integer := 8;
+ DEPTH : integer := 5;
+ FILL_LEVEL_BITS : integer := 3; -- Should be at least int(floor(log2(DEPTH))+1.0)
+ PF_FULL_POINT : integer := 3;
+ PF_FLAG_POINT : integer := 2;
+ PF_EMPTY_POINT : integer := 0
+ );
+ port (
+ sys_rst_n : in std_logic; -- Asynchronous
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ reset_i : in std_logic; -- Synchronous
+
+ fifo_rd_i : in std_logic;
+ fifo_dout : out unsigned(WIDTH-1 downto 0);
+
+ fifo_wr_i : in std_logic;
+ fifo_din : in unsigned(WIDTH-1 downto 0);
+
+ fifo_fill_level : out unsigned(FILL_LEVEL_BITS-1 downto 0);
+ fifo_full : out std_logic;
+ fifo_empty : out std_logic;
+ fifo_pf_full : out std_logic;
+ fifo_pf_flag : out std_logic;
+ fifo_pf_empty : out std_logic
+ );
+end fifo_with_fill_level;
+
+architecture beh of fifo_with_fill_level is
+
+ -- Constants
+ constant FLG_WIDTH : integer := bit_width(DEPTH); -- Bit Width of memory address. Pointers are one bit wider,
+ -- so that fill_level can represent the full quantity of
+ -- items stored in the FIFO. This is important when DEPTH
+ -- is an even power of 2.
+
+ -- Signal Declarations
+ signal rd_row : unsigned(FLG_WIDTH downto 0);
+ signal wr_row : unsigned(FLG_WIDTH downto 0);
+ signal fill_level : unsigned(FLG_WIDTH downto 0);
+
+ TYPE memory_array IS
+ ARRAY (integer RANGE 0 TO DEPTH-1) OF unsigned(WIDTH-1 DOWNTO 0);
+
+ SIGNAL fifo_array: memory_array;
+
+ TYPE STATE_TYPE IS (st_empty, st_data, st_full);
+
+ signal current_state : STATE_TYPE ;
+
+
+BEGIN
+
+ fifo_empty <= '1' when (current_state=st_empty) else '0';
+ fifo_full <= '1' when (current_state=st_full) else '0';
+ fifo_pf_full <= '1' when (fill_level>=PF_FULL_POINT or current_state=st_full) else '0';
+ fifo_pf_flag <= '1' when (fill_level>=PF_FLAG_POINT) else '0';
+ fifo_pf_empty <= '1' when (fill_level<=PF_EMPTY_POINT and current_state/=st_full) else '0';
+ fifo_fill_level <= u_resize(fill_level,FILL_LEVEL_BITS);
+
+-------------------------
+-- The FIFO Fill Level
+fill_level_proc: process(wr_row, rd_row, current_state)
+ begin
+ if (current_state=st_empty) then
+ fill_level <= (others=>'0');
+ elsif (wr_row>rd_row) then
+ fill_level <= wr_row-rd_row;
+ else
+ fill_level <= DEPTH+(wr_row-rd_row);
+ end if;
+ end process;
+
+-------------------------
+-- The FIFO memory
+memory: process (sys_clk, sys_rst_n)
+ variable i : integer;
+ begin
+ -- The memory initialization at reset was included for simulation only.
+ -- It can be removed for synthesis if desired.
+ if (sys_rst_n='0') then
+ for i in 0 to DEPTH-1 loop
+ fifo_array(i) <= (others=>'0');
+ end loop;
+ elsif (sys_clk'event and sys_clk = '1') then
+ if (sys_clk_en='1') then
+ if ((fifo_wr_i='1' and current_state/=st_full) or
+ (fifo_wr_i='1' and current_state=st_full and fifo_rd_i='1')) then
+ fifo_array(to_integer(wr_row(FLG_WIDTH-1 downto 0))) <= fifo_din;
+ end if;
+ end if;
+ end if;
+end process;
+fifo_dout <= fifo_array(to_integer(rd_row(FLG_WIDTH-1 downto 0))) when (current_state/=st_empty)
+ else fifo_din;
+
+
+-------------------------
+-- The FIFO state machine
+ clocked : PROCESS(sys_clk, sys_rst_n)
+
+ procedure do_write is
+ begin
+ if (wr_row=DEPTH-1) then -- Roll buffer index for non-power-of-two
+ wr_row <= (others=>'0');
+ else
+ wr_row<=wr_row+1;
+ end if;
+ end do_write;
+
+ procedure do_read is
+ begin
+ if (rd_row=DEPTH-1) then -- Roll buffer index for non-power-of-two
+ rd_row <= (others=>'0');
+ else
+ rd_row<=rd_row+1;
+ end if;
+ end do_read;
+
+ begin
+ if (sys_rst_n = '0') then
+ current_state <= st_empty;
+ rd_row <= (others=>'0');
+ wr_row <= (others=>'0');
+
+ elsif (sys_clk'EVENT and sys_clk = '1') then
+ if (sys_clk_en='1') then
+ if (reset_i='1') then
+ current_state <= st_empty;
+ wr_row <= (others=>'0');
+ rd_row <= (others=>'0');
+ else
+ case current_state is
+
+ when st_empty =>
+ if (fifo_wr_i='1') then
+ do_write;
+ if (fifo_rd_i='0') then
+ current_state<=st_data;
+ else
+ do_read;
+ end if;
+ end if;
+
+ when st_data =>
+ if (fifo_wr_i='1') then
+ do_write;
+ if (fifo_rd_i='0' and fill_level=DEPTH-1) then
+ current_state<=st_full;
+ end if;
+ end if;
+ if (fifo_rd_i='1') then
+ do_read;
+ if (fifo_wr_i='0' and fill_level=1) then
+ current_state<=st_empty;
+ end if;
+ end if;
+
+ when st_full =>
+ if (fifo_rd_i='1') then
+ do_read;
+ if (fifo_wr_i='0') then
+ current_state<=st_data;
+ else
+ do_write;
+ end if;
+ end if;
+
+ when others => null;
+ end case;
+
+ end if;
+ end if; -- sys_clk_en
+ end if; -- sys_clk
+ end process clocked;
+
+
+end beh;
+
+
+--------------------------------------------------------------
+-- SWISS ARMY FIFO with fill level output
+--------------------------------------------------------------
+-- Description:
+--
+-- This is the same as "fifo_with_fill_level" but it has been
+-- coded to select whether Block RAMs or distributed RAMs are inferred.
+--
+-- The bit width of this additional output is set by a generic
+-- parameter
+--
+-- Note : When USE_BRAM=0, the behavior when reading the FIFO is to
+-- make read data available immediately during the clock cycle
+-- in which fifo_rd_i='1'. When USE_BRAM/=0, then an additional
+-- clock cycle occurs following the fifo_rd_i pulse, before the
+-- output data is available.
+-- Please be aware of this.
+--
+--
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+library work;
+use work.convert_pack.all;
+use work.block_ram_pack.all;
+
+entity swiss_army_fifo is
+ generic (
+ USE_BRAM : integer := 1; -- Set to nonzero value for BRAM, zero for distributed RAM
+ WIDTH : integer := 8;
+ DEPTH : integer := 5;
+ FILL_LEVEL_BITS : integer := 3; -- Should be at least int(floor(log2(DEPTH))+1.0)
+ PF_FULL_POINT : integer := 3;
+ PF_FLAG_POINT : integer := 2;
+ PF_EMPTY_POINT : integer := 0
+ );
+ port (
+ sys_rst_n : in std_logic; -- Asynchronous
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ reset_i : in std_logic; -- Synchronous
+
+ fifo_wr_i : in std_logic;
+ fifo_din : in unsigned(WIDTH-1 downto 0);
+
+ fifo_rd_i : in std_logic;
+ fifo_dout : out unsigned(WIDTH-1 downto 0);
+
+ fifo_fill_level : out unsigned(FILL_LEVEL_BITS-1 downto 0);
+ fifo_full : out std_logic;
+ fifo_empty : out std_logic;
+ fifo_pf_full : out std_logic;
+ fifo_pf_flag : out std_logic;
+ fifo_pf_empty : out std_logic
+ );
+end swiss_army_fifo;
+
+architecture beh of swiss_army_fifo is
+
+ -- Constants
+ constant FLG_WIDTH : integer := bit_width(DEPTH); -- Bit Width of memory address. Pointers are one bit wider,
+ -- so that fill_level can represent the full quantity of
+ -- items stored in the FIFO. This is important when DEPTH
+ -- is an even power of 2.
+
+ -- Signal Declarations
+ signal rd_row : unsigned(FLG_WIDTH downto 0);
+ signal wr_row : unsigned(FLG_WIDTH downto 0);
+ signal fill_level : unsigned(FLG_WIDTH downto 0);
+ signal ram_we_a : std_logic;
+ signal ram_dout : unsigned(WIDTH-1 downto 0);
+
+ TYPE STATE_TYPE IS (st_empty, st_data, st_full);
+ signal current_state : STATE_TYPE ;
+
+ signal bram_dat_b : unsigned(WIDTH-1 downto 0);
+
+BEGIN
+
+ fifo_empty <= '1' when (current_state=st_empty) else '0';
+ fifo_full <= '1' when (current_state=st_full) else '0';
+ fifo_pf_full <= '1' when (fill_level>=PF_FULL_POINT or current_state=st_full) else '0';
+ fifo_pf_flag <= '1' when (fill_level>=PF_FLAG_POINT) else '0';
+ fifo_pf_empty <= '1' when (fill_level<=PF_EMPTY_POINT and current_state/=st_full) else '0';
+ fifo_fill_level <= u_resize(fill_level,FILL_LEVEL_BITS);
+
+-------------------------
+-- The FIFO Fill Level
+fill_level_proc: process(wr_row, rd_row, current_state)
+ begin
+ if (current_state=st_empty) then
+ fill_level <= (others=>'0');
+ elsif (wr_row>rd_row) then
+ fill_level <= wr_row-rd_row;
+ else
+ fill_level <= DEPTH+(wr_row-rd_row);
+ end if;
+ end process;
+
+-------------------------
+-- The FIFO memory
+
+-- Port A is the write side.
+-- Port B is dedicated to reading only.
+-- The hexfile is used to permit initialization of the RAM
+
+ fifo_ram : swiss_army_ram
+ generic map(
+ USE_BRAM => USE_BRAM,
+ WRITETHRU => 0, -- Set to nonzero value for writethrough mode
+ USE_FILE => 0, -- Set to nonzero value to use INIT_FILE
+ INIT_VAL => 0,
+ INIT_SEL => 0, -- No generate loop here
+ INIT_FILE => ".\foo.txt", -- ASCII hexadecimal initialization file name
+ FIL_WIDTH => 32, -- Bit width of init file lines
+ ADR_WIDTH => FLG_WIDTH,
+ DAT_WIDTH => WIDTH
+ )
+ port map (
+ clk_a => sys_clk,
+ clk_b => sys_clk,
+
+ adr_a_i => wr_row(FLG_WIDTH-1 downto 0),
+ adr_b_i => rd_row(FLG_WIDTH-1 downto 0),
+
+ we_a_i => ram_we_a,
+ en_a_i => sys_clk_en,
+ dat_a_i => fifo_din,
+ dat_a_o => open,
+
+ we_b_i => '0',
+ en_b_i => sys_clk_en,
+ dat_b_i => bram_dat_b,
+ dat_b_o => ram_dout
+ );
+
+ bram_dat_b <= (others=>'0');
+ ram_we_a <= '1' when fifo_wr_i='1' and (current_state/=st_full or (current_state=st_full and fifo_rd_i='1')) else '0';
+ fifo_dout <= ram_dout;
+
+
+-------------------------
+-- The FIFO state machine
+ clocked : PROCESS(sys_clk, sys_rst_n)
+
+ procedure do_write is
+ begin
+ if (wr_row=DEPTH-1) then -- Roll buffer index for non-power-of-two
+ wr_row <= (others=>'0');
+ else
+ wr_row<=wr_row+1;
+ end if;
+ end do_write;
+
+ procedure do_read is
+ begin
+ if (rd_row=DEPTH-1) then -- Roll buffer index for non-power-of-two
+ rd_row <= (others=>'0');
+ else
+ rd_row<=rd_row+1;
+ end if;
+ end do_read;
+
+ begin
+ if (sys_rst_n = '0') then
+ current_state <= st_empty;
+ rd_row <= (others=>'0');
+ wr_row <= (others=>'0');
+
+ elsif (sys_clk'EVENT and sys_clk = '1') then
+ if (sys_clk_en='1') then
+ if (reset_i='1') then
+ current_state <= st_empty;
+ wr_row <= (others=>'0');
+ rd_row <= (others=>'0');
+ else
+ case current_state is
+
+ -- When empty, one can only read if also writing
+ when st_empty =>
+ if (fifo_wr_i='1') then
+ do_write;
+ if (fifo_rd_i='1') then
+ do_read;
+ else
+ current_state<=st_data;
+ end if;
+ end if;
+
+ when st_data =>
+ if (fifo_wr_i='1') then
+ do_write;
+ if (fifo_rd_i='0' and fill_level=DEPTH-1) then
+ current_state<=st_full;
+ end if;
+ end if;
+ if (fifo_rd_i='1') then
+ do_read;
+ if (fifo_wr_i='0' and fill_level=1) then
+ current_state<=st_empty;
+ end if;
+ end if;
+
+ -- When full, one can only write if also reading
+ when st_full =>
+ if (fifo_rd_i='1') then
+ do_read;
+ if (fifo_wr_i='1') then
+ do_write;
+ else
+ current_state<=st_data;
+ end if;
+ end if;
+
+ when others => null;
+ end case;
+
+ end if;
+ end if; -- sys_clk_en
+ end if; -- sys_clk
+ end process clocked;
+
+
+end beh;
+
+--------------------------------------------------------------
+-- SWISS ARMY FIFO "Clock Domain Crossing" version
+--------------------------------------------------------------
+-- Description:
+--
+-- This is the same as "swiss_army_fifo" but it has been
+-- coded to include two separate clock domains. Originally,
+-- the status signals were all synchronized to their respective
+-- clock domains. However, it was taken out so that the user of
+-- this module must take care as the status signals are not delayed,
+-- but they are possibly subject to metastability.
+--
+-- Note : When USE_BRAM=0, the behavior when reading the FIFO is to
+-- make read data available immediately during the clock cycle
+-- in which fifo_rd_i='1'. When USE_BRAM/=0, then an additional
+-- clock cycle occurs following the fifo_rd_i pulse, before the
+-- output data is available.
+-- Please be aware of this.
+--
+--
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+library work;
+use work.convert_pack.all;
+use work.block_ram_pack.all;
+
+entity swiss_army_fifo_cdc is
+ generic (
+ USE_BRAM : integer := 1; -- Set to nonzero value for BRAM, zero for distributed RAM
+ WIDTH : integer := 8;
+ DEPTH : integer := 5;
+ FILL_LEVEL_BITS : integer := 3; -- Should be at least int(floor(log2(DEPTH))+1.0)
+ PF_FULL_POINT : integer := 3;
+ PF_FLAG_POINT : integer := 2;
+ PF_EMPTY_POINT : integer := 0
+ );
+ port (
+ sys_rst_n : in std_logic; -- Asynchronous
+
+ wr_clk_i : in std_logic;
+ wr_clk_en_i : in std_logic;
+ wr_reset_i : in std_logic; -- Synchronous
+ wr_en_i : in std_logic;
+ wr_dat_i : in unsigned(WIDTH-1 downto 0);
+ wr_fifo_level : out unsigned(FILL_LEVEL_BITS-1 downto 0);
+ wr_fifo_full : out std_logic;
+ wr_fifo_empty : out std_logic;
+ wr_fifo_pf_full : out std_logic;
+ wr_fifo_pf_flag : out std_logic;
+ wr_fifo_pf_empty : out std_logic;
+
+ rd_clk_i : in std_logic;
+ rd_clk_en_i : in std_logic;
+ rd_reset_i : in std_logic; -- Synchronous
+ rd_en_i : in std_logic;
+ rd_dat_o : out unsigned(WIDTH-1 downto 0);
+ rd_fifo_level : out unsigned(FILL_LEVEL_BITS-1 downto 0);
+ rd_fifo_full : out std_logic;
+ rd_fifo_empty : out std_logic;
+ rd_fifo_pf_full : out std_logic;
+ rd_fifo_pf_flag : out std_logic;
+ rd_fifo_pf_empty : out std_logic
+
+ );
+end swiss_army_fifo_cdc;
+
+architecture beh of swiss_army_fifo_cdc is
+
+ -- Constants
+ constant FLG_WIDTH : integer := bit_width(DEPTH); -- Bit Width of memory address. Pointers are one bit wider,
+ -- so that fill_level can represent the full quantity of
+ -- items stored in the FIFO. This is important when DEPTH
+ -- is an even power of 2.
+
+ -- Signal Declarations
+ signal rd_row : unsigned(FLG_WIDTH downto 0);
+ signal wr_row : unsigned(FLG_WIDTH downto 0);
+ signal fill_level : unsigned(FLG_WIDTH+1 downto 0);
+ signal ram_we_a : std_logic;
+ signal bram_dat_b : unsigned(WIDTH-1 downto 0);
+
+ signal fifo_level : unsigned(FILL_LEVEL_BITS-1 downto 0);
+ signal fifo_full : std_logic;
+ signal fifo_empty : std_logic;
+ signal fifo_pf_full : std_logic;
+ signal fifo_pf_flag : std_logic;
+ signal fifo_pf_empty : std_logic;
+
+begin
+
+ fifo_level <= u_resize(fill_level,FILL_LEVEL_BITS);
+ fifo_full <= '1' when (fill_level=DEPTH) else '0';
+ fifo_empty <= '1' when (fill_level=0) else '0';
+ fifo_pf_full <= '1' when (fill_level>=PF_FULL_POINT) else '0';
+ fifo_pf_flag <= '1' when (fill_level>=PF_FLAG_POINT) else '0';
+ fifo_pf_empty <= '1' when (fill_level<=PF_EMPTY_POINT) else '0';
+
+-------------------------
+-- The FIFO Fill Level
+
+fill_level <= (others=>'0') when wr_row=rd_row else
+ ('0' & wr_row)-('0' & rd_row) when wr_row>rd_row else
+ (2**(FLG_WIDTH+1))+(('0' & wr_row)-('0' & rd_row));
+
+-------------------------
+-- The FIFO memory
+
+-- Port A is the write side.
+-- Port B is dedicated to reading only.
+-- The hexfile is used to permit initialization of the RAM
+
+ fifo_ram : swiss_army_ram
+ generic map(
+ USE_BRAM => USE_BRAM,
+ WRITETHRU => 0, -- Set to nonzero value for writethrough mode
+ USE_FILE => 0, -- Set to nonzero value to use INIT_FILE
+ INIT_VAL => 0,
+ INIT_SEL => 0, -- No generate loop here
+ INIT_FILE => ".\foo.txt", -- ASCII hexadecimal initialization file name
+ FIL_WIDTH => 32, -- Bit width of init file lines
+ ADR_WIDTH => FLG_WIDTH,
+ DAT_WIDTH => WIDTH
+ )
+ port map (
+ clk_a => wr_clk_i,
+ clk_b => rd_clk_i,
+
+ adr_a_i => wr_row(FLG_WIDTH-1 downto 0),
+ adr_b_i => rd_row(FLG_WIDTH-1 downto 0),
+
+ we_a_i => ram_we_a,
+ en_a_i => wr_clk_en_i,
+ dat_a_i => wr_dat_i,
+ dat_a_o => open,
+
+ we_b_i => '0',
+ en_b_i => rd_clk_en_i,
+ dat_b_i => bram_dat_b,
+ dat_b_o => rd_dat_o
+ );
+
+ bram_dat_b <= (others=>'0');
+ ram_we_a <= '1' when wr_en_i='1' and fifo_full='0' else '0';
+
+-------------------------
+-- The FIFO writing process
+ wr_proc : PROCESS(wr_clk_i, sys_rst_n)
+ begin
+ if (sys_rst_n = '0') then
+ wr_row <= (others=>'0');
+ elsif (wr_clk_i'event and wr_clk_i = '1') then
+ if (wr_clk_en_i='1') then
+ if (wr_reset_i='1') then
+ wr_row <= (others=>'0');
+ else
+ if (ram_we_a='1') then
+ if (fifo_level=DEPTH) then
+ null; -- FIFO is full! Don't do any writes.
+ else
+ wr_row <= wr_row+1;
+ end if;
+ end if;
+ end if;
+ -- Synchronize all dataflow outputs to the
+ -- wr_clk_i clock domain
+-- wr_fifo_level <= fifo_level;
+-- wr_fifo_full <= fifo_full;
+-- wr_fifo_empty <= fifo_empty;
+-- wr_fifo_pf_full <= fifo_pf_full;
+-- wr_fifo_pf_flag <= fifo_pf_flag;
+-- wr_fifo_pf_empty <= fifo_pf_empty;
+ end if; -- wr_clk_en
+ end if; -- wr_clk_i
+ end process wr_proc;
+ -- Synchronized version removed, because it added an extra clock
+ -- cycle of delay.
+ -- This may be dangerous in terms of flip-flop metastability
+ wr_fifo_level <= fifo_level;
+ wr_fifo_full <= fifo_full;
+ wr_fifo_empty <= fifo_empty;
+ wr_fifo_pf_full <= fifo_pf_full;
+ wr_fifo_pf_flag <= fifo_pf_flag;
+ wr_fifo_pf_empty <= fifo_pf_empty;
+
+-------------------------
+-- The FIFO reading process
+ rd_proc : PROCESS(rd_clk_i, sys_rst_n)
+ begin
+ if (sys_rst_n = '0') then
+ rd_row <= (others=>'0');
+ elsif (rd_clk_i'event and rd_clk_i = '1') then
+ if (rd_clk_en_i='1') then
+ if (rd_reset_i='1') then
+ rd_row <= (others=>'0');
+ else
+ if (rd_en_i='1' and fifo_empty='0') then
+ if (fifo_level=0) then
+ null; -- FIFO is empty! Don't read anything.
+ else
+ rd_row <= rd_row+1;
+ end if;
+ end if;
+ end if;
+ -- Synchronize all dataflow outputs to the
+ -- rd_clk_i clock domain
+-- rd_fifo_level <= fifo_level;
+-- rd_fifo_full <= fifo_full;
+-- rd_fifo_empty <= fifo_empty;
+-- rd_fifo_pf_full <= fifo_pf_full;
+-- rd_fifo_pf_flag <= fifo_pf_flag;
+-- rd_fifo_pf_empty <= fifo_pf_empty;
+ end if; -- rd_clk_en
+ end if; -- rd_clk_i
+ end process rd_proc;
+ -- Synchronized version removed, because it added an extra clock
+ -- cycle of delay.
+ -- This may be dangerous in terms of flip-flop metastability
+ rd_fifo_level <= fifo_level;
+ rd_fifo_full <= fifo_full;
+ rd_fifo_empty <= fifo_empty;
+ rd_fifo_pf_full <= fifo_pf_full;
+ rd_fifo_pf_flag <= fifo_pf_flag;
+ rd_fifo_pf_empty <= fifo_pf_empty;
+
+end beh;
+
+-------------------------------------------------------------------------------
+-- Adjustable Data Packer
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Date : Sep. 04, 2012 Copied code from pcm_tx, and began
+-- updating the description.
+-- July 18, 2013 Moved this module from decom_pack into
+-- fifo_pack, and revised the description
+-- to make it sound more generic.
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This module is a very simple "bit packer" that takes in data on a parallel
+-- bus, along with a word size value that indicates which of the input least
+-- significant bits are to be "packed."
+--
+-- The input port is an address snooper, meaning that it is intended to be used
+-- on a bus with other units also receiving the data. The other units will
+-- acknowledge the transfers, and this unit uses that acknowledge to latch the
+-- bus data.
+--
+-- The latched input word is shifted one bit at a time into the output
+-- word shift register. When the output word shift register is full, the
+-- output word is latched, and an output cycle is produced.
+--
+-- This mechanism allows data words of dynamically programmable size to be
+-- "snooped up" for any selected data source on the input bus, and then sent
+-- over the ethernet interface as 8-bit values.
+--
+-- When asserted, the "last word" input causes zero bits to be packed into the
+-- output word as needed to finish up a final output cycle.
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+library work;
+use work.fifo_pack.all;
+use work.convert_pack.all;
+
+ entity data_packer is
+ generic (
+ ADR_W : integer := 4; -- Bit width of snoop address
+ DATA_IN_W : integer := 16; -- Maximum in_dat_i word size
+ LOG2_DATA_IN_W : integer := 4; -- Bit width of in_word_size_i
+ DATA_OUT_W : integer := 8; -- Bit width of archive data
+ FIFO_DEPTH : integer := 512 -- Size of BRAM FIFO buffer
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Input Port
+ in_dat_i : in unsigned(DATA_IN_W-1 downto 0);
+ in_word_size_i : in unsigned(LOG2_DATA_IN_W downto 0);
+ in_last_word_i : in std_logic;
+ in_adr_i : in unsigned(ADR_W-1 downto 0);
+ in_match_adr_i : in unsigned(ADR_W-1 downto 0);
+ in_cyc_i : in std_logic;
+ in_ack_i : in std_logic;
+
+ -- Status
+ fifo_full_o : out std_logic;
+ fifo_reset_i : in std_logic;
+
+ -- Output Port
+ tx_done_i : in std_logic;
+ tx_buff_i : in unsigned(ADR_W-1 downto 0);
+ out_dat_o : out unsigned(DATA_OUT_W-1 downto 0);
+ out_last_word_o : out std_logic;
+ out_cyc_o : out std_logic;
+ out_ack_i : in std_logic
+
+ );
+ end data_packer;
+
+architecture beh of data_packer is
+
+-- Constants
+constant FIFO_WIDTH : natural := (LOG2_DATA_IN_W+1)+DATA_IN_W+1; -- word_size, data, 1 bit last word flag
+constant FIFO_FILL_BITS : natural := timer_width(FIFO_DEPTH);
+constant LOG2_DATA_OUT_W : natural := bit_width(DATA_OUT_W);
+
+-- Internal signal declarations
+signal fifo_din : unsigned(FIFO_WIDTH-1 downto 0);
+signal fifo_dout : unsigned(FIFO_WIDTH-1 downto 0);
+signal fifo_we : std_logic;
+signal fifo_rd : std_logic;
+signal fifo_empty : std_logic;
+signal stored_data : unsigned(DATA_IN_W-1 downto 0);
+signal stored_word_size : unsigned(LOG2_DATA_IN_W downto 0);
+signal stored_last_word : std_logic;
+
+ -- Modified Miller Code State Machine
+type FSM_STATE_TYPE is (TRANSFER, READ_DATA, MAKE_TAIL, WRITE_DATA, WRITE_LAST_DATA);
+signal fsm_state : FSM_STATE_TYPE;
+
+
+
+signal bits_in : unsigned(DATA_IN_W downto 0); -- includes "last word" bit
+signal bits_in_count : unsigned(LOG2_DATA_IN_W downto 0);
+signal bit_sel : unsigned(LOG2_DATA_IN_W downto 0);
+signal bits_out : unsigned(DATA_OUT_W-1 downto 0);
+signal bits_out_count : unsigned(LOG2_DATA_OUT_W downto 0);
+signal transfer_bit : std_logic;
+signal buffering : std_logic;
+
+begin
+
+fifo_din <= in_word_size_i & in_dat_i & in_last_word_i;
+fifo_we <= '1' when (in_adr_i=in_match_adr_i) and in_cyc_i='1' and in_ack_i='1' else '0';
+stored_word_size <= fifo_dout(DATA_IN_W+1+LOG2_DATA_IN_W downto DATA_IN_W+1);
+stored_data <= fifo_dout(DATA_IN_W downto 1);
+stored_last_word <= fifo_dout(0);
+
+packer_fifo : swiss_army_fifo
+ generic map(
+ USE_BRAM => 1,
+ WIDTH => FIFO_WIDTH,
+ DEPTH => FIFO_DEPTH,
+ FILL_LEVEL_BITS => FIFO_FILL_BITS,
+ PF_FULL_POINT => FIFO_DEPTH-4,
+ PF_FLAG_POINT => FIFO_DEPTH/2,
+ PF_EMPTY_POINT => 4
+ )
+ port map(
+ sys_rst_n => sys_rst_n,
+ sys_clk => sys_clk,
+ sys_clk_en => sys_clk_en,
+
+ reset_i => fifo_reset_i,
+
+ fifo_wr_i => fifo_we,
+ fifo_din => fifo_din,
+
+ fifo_rd_i => fifo_rd,
+ fifo_dout => fifo_dout,
+
+ fifo_fill_level => open,
+ fifo_full => fifo_full_o,
+ fifo_empty => fifo_empty,
+ fifo_pf_full => open,
+ fifo_pf_flag => open,
+ fifo_pf_empty => open
+ );
+
+pack_proc: process(sys_clk, sys_rst_n)
+begin
+ if (sys_rst_n='0') then
+ buffering <= '1';
+ bits_in <= (others=>'0');
+ bits_in_count <= (others=>'0');
+ bits_out <= (others=>'0');
+ bits_out_count <= (others=>'0');
+ bit_sel <= (others=>'0');
+ fsm_state <= READ_DATA;
+ elsif (sys_clk'event and sys_clk='1') then
+ if (sys_clk_en='1') then
+
+ -- Handle transitions from packing state to buffering state
+ if (tx_done_i='1' and tx_buff_i=in_match_adr_i) then
+ buffering <= '0';
+ end if;
+
+ if (buffering='0') then
+
+ -- Default values
+
+ -- Handle state transitions
+ case (fsm_state) is
+
+ when TRANSFER =>
+ if (bits_in_count=0) then
+ if (transfer_bit='1') then -- Check last word bit.
+ fsm_state <= MAKE_TAIL;
+ else
+ fsm_state <= READ_DATA;
+ end if;
+ -- Writing completed data is highest priority
+ if (bits_out_count=DATA_OUT_W) then
+ if (transfer_bit='1') then
+ fsm_state <= WRITE_LAST_DATA;
+ bits_out_count <= (others=>'0');
+ else
+ fsm_state <= WRITE_DATA;
+ bits_out_count <= (others=>'0');
+ end if;
+ end if;
+ elsif (bits_out_count=DATA_OUT_W) then
+ fsm_state <= WRITE_DATA;
+ bits_out_count <= (others=>'0');
+ elsif (bits_in_count>0) then
+ bits_out <= bits_out(bits_out'length-2 downto 0) & transfer_bit;
+ bits_in <= bits_in(bits_in'length-2 downto 0) & '0';
+ bits_in_count <= bits_in_count-1;
+ bits_out_count <= bits_out_count+1;
+ end if;
+
+ when READ_DATA =>
+ bits_in <= stored_data & stored_last_word;
+ bits_in_count <= stored_word_size;
+ bit_sel <= stored_word_size;
+ if (fifo_rd='1' and stored_word_size>0) then
+ fsm_state <= TRANSFER;
+ end if;
+
+ when MAKE_TAIL =>
+ if (bits_out_count>=DATA_OUT_W) then
+ fsm_state <= WRITE_LAST_DATA;
+ bits_out_count <= (others=>'0');
+ else
+ bits_out <= bits_out(DATA_OUT_W-2 downto 0) & '0';
+ bits_out_count <= bits_out_count+1;
+ end if;
+
+ when WRITE_DATA =>
+ if (out_ack_i='1') then
+ fsm_state <= TRANSFER;
+ if (bits_in_count=0) then
+ fsm_state <= READ_DATA;
+ end if;
+ end if;
+
+ when WRITE_LAST_DATA =>
+ if (out_ack_i='1') then
+ fsm_state <= TRANSFER;
+ if (bits_in_count=0) then
+ fsm_state <= READ_DATA;
+ end if;
+ buffering <= '1';
+ end if;
+
+ --when others =>
+ -- fsm_state <= IDLE;
+ end case;
+
+ end if; -- buffering='0' and fifo_empty='0'
+
+ end if; -- sys_clk_en
+ end if; -- sys_clk
+end process;
+
+-- Select the correct bit to transfer
+transfer_bit <= bits_in(to_integer(bit_sel));
+
+-- Create FIFO read signal
+fifo_rd <= '1' when fsm_state=READ_DATA and fifo_empty='0' and buffering='0' else '0';
+
+-- Assign the outputs
+out_last_word_o <= '1' when fsm_state=WRITE_LAST_DATA else '0';
+out_cyc_o <= '1' when fsm_state=WRITE_DATA or fsm_state=WRITE_LAST_DATA else '0';
+out_dat_o <= bits_out;
+
+end beh;
+
Index: sd_card_controller/trunk/rtl/VHDL/sd_card_pack.vhd
===================================================================
--- sd_card_controller/trunk/rtl/VHDL/sd_card_pack.vhd (nonexistent)
+++ sd_card_controller/trunk/rtl/VHDL/sd_card_pack.vhd (revision 14)
@@ -0,0 +1,2952 @@
+--------------------------------------------------------------------------
+-- Package containing SD Card interface modules,
+-- and related support modules.
+--
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+
+package sd_card_pack is
+
+ component sd_card_cmd_rx
+ port(
+ -- Asynchronous reset
+ sys_rst_n : in std_logic;
+ -- SD/MMC card command signals
+ sd_clk_i : in std_logic;
+ sd_cmd_i : in std_logic;
+ -- Command outputs
+ cmd_raw_o : out unsigned(47 downto 0);
+ cmd_index_o : out unsigned(5 downto 0);
+ cmd_arg_o : out unsigned(31 downto 0);
+ -- Status and done indicator
+ cmd_done_o : out std_logic;
+ crc_err_o : out std_logic;
+ dir_err_o : out std_logic;
+ stop_err_o : out std_logic
+ );
+ end component;
+
+ component sd_card_responder
+ generic (
+ N_CR : integer; -- Number of clocks between respond_i and response start
+ RESP_PYLD_LEN : integer;
+ CRC_OFFSET : integer; -- Start CRC calculation after this many bits
+ CRC_SEND_ONES : integer
+ );
+ port (
+ -- Asynchronous reset
+ sys_rst_n : in std_logic;
+ -- SD/MMC card command signals
+ sd_clk_i : in std_logic;
+ sd_cmd_o : out std_logic;
+ sd_cmd_oe_o : out std_logic;
+ -- Response inputs
+ resp_index_i : in unsigned(5 downto 0);
+ resp_pyld_i : in unsigned(RESP_PYLD_LEN-1 downto 0);
+ respond_i : in std_logic;
+ -- Status and done indicator
+ done_o : out std_logic; -- A one clock long pulse
+ busy_o : out std_logic
+ );
+ end component;
+
+ component sd_card_data_unit
+ generic (
+ BLK_PRG_TIME : integer; -- Number of clocks to program a sector in FLASH (emulated)
+ BLKSIZE_W : integer;
+ BLKCNT_W : integer
+ );
+ port(
+ sd_clk_i : in std_logic;
+ sys_rst_n : in std_logic;
+ --Tx Fifo
+ tx_dat_i : in unsigned(7 downto 0);
+ tx_dat_rd_o : out std_logic;
+ --Rx Fifo
+ rx_dat_o : out unsigned(7 downto 0);
+ rx_dat_we_o : out std_logic;
+ --SD data
+ sd_dat_i : in unsigned(7 downto 0);
+ sd_dat_o : out unsigned(7 downto 0);
+ sd_dat_oe_o : out std_logic;
+ --Control signals
+ blksize_i : in unsigned(BLKSIZE_W-1 downto 0);
+ bus_size_i : in unsigned(1 downto 0);
+ blkcnt_i : in unsigned(BLKCNT_W-1 downto 0);
+ continuous_i : in std_logic;
+ d_stop_i : in std_logic;
+ d_read_i : in std_logic;
+ d_write_i : in std_logic;
+ bustest_w_i : in std_logic;
+ bustest_r_i : in std_logic;
+ sd_dat_busy_o : out std_logic;
+ fsm_busy_o : out std_logic;
+ crc_ok_o : out std_logic
+ );
+ end component;
+
+ component sd_card_emulator
+ generic (
+ USE_R4_RESPONSE : integer; -- Fast I/O read/write (app specific)
+ USE_R5_RESPONSE : integer; -- Interrupt Request Mode
+ EXT_CSD_INIT_FILE : string; -- Initial contents of EXT_CSD
+ OCR_USE_DUAL_VOLTAGE : integer;
+ OCR_USE_SECTOR_MODE : integer;
+ CID_MID : unsigned( 7 downto 0); -- Manufacturer ID
+ CID_OID : unsigned( 7 downto 0); -- OEM ID
+ CID_CBX : unsigned( 1 downto 0); -- 0=Card, 1=BGA, 2=Package On Package
+ CID_PNM : unsigned(47 downto 0); -- Product Name, 6 ASCII chars
+ CID_PRV : unsigned( 7 downto 0); -- Product Rev (2 BCD digits, e.g. 6.2=0x62)
+ CID_PSN : unsigned(31 downto 0); -- Product serial number
+ CID_MDT : unsigned( 7 downto 0); -- Manufacture Date (Jan=1, 1997=0, e.g. Apr. 2000=0x43)
+ DEF_STAT : unsigned(31 downto 0); -- Read Write, R_0
+ CSD_WORD_3 : unsigned(31 downto 0); -- Read only
+ CSD_WORD_2 : unsigned(31 downto 0); -- Read only
+ CSD_WORD_1 : unsigned(31 downto 0); -- Read only
+ CSD_WORD_0 : unsigned(31 downto 0); -- (31:16) is read only, (15:0) is R_1 default (R/W)
+ DEF_R_Z : unsigned(31 downto 0) -- Value returned for nonexistent registers
+ );
+ port (
+
+ -- Asynchronous reset
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+
+ -- Bus interface
+ adr_i : in unsigned(3 downto 0);
+ sel_i : in std_logic;
+ we_i : in std_logic;
+ dat_i : in unsigned(31 downto 0);
+ dat_o : out unsigned(31 downto 0);
+ ack_o : out std_logic;
+
+ -- SD/MMC card signals
+ sd_clk_i : in std_logic;
+ sd_cmd_i : in std_logic;
+ sd_cmd_o : out std_logic;
+ sd_cmd_oe_o : out std_logic;
+ sd_od_mode_o : out std_logic; -- Open drain mode
+ sd_dat_i : in unsigned(7 downto 0);
+ sd_dat_o : out unsigned(7 downto 0);
+ sd_dat_oe_o : out std_logic;
+ sd_dat_siz_o : out unsigned(1 downto 0);
+
+ -- Data FIFO interface
+ buf_adr_o : out unsigned(31 downto 0);
+ buf_dat_o : out unsigned(7 downto 0);
+ buf_dat_we_o : out std_logic;
+ buf_dat_i : in unsigned(7 downto 0);
+ buf_dat_rd_o : out std_logic
+ );
+ end component;
+
+ component mmc_data_pipe
+ generic (
+ EXT_CSD_INIT_FILE : string; -- Initial contents of EXT_CSD
+ FIFO_DEPTH : integer;
+ FILL_LEVEL_BITS : integer; -- Should be at least int(floor(log2(FIFO_DEPTH))+1.0)
+ RAM_ADR_WIDTH : integer
+ );
+ port (
+
+ -- Asynchronous reset
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+
+ -- Bus interface
+ adr_i : in unsigned(3 downto 0);
+ sel_i : in std_logic;
+ we_i : in std_logic;
+ dat_i : in unsigned(31 downto 0);
+ dat_o : out unsigned(31 downto 0);
+ ack_o : out std_logic;
+
+ -- SD/MMC card signals
+ mmc_clk_i : in std_logic;
+ mmc_cmd_i : in std_logic;
+ mmc_cmd_o : out std_logic;
+ mmc_cmd_oe_o : out std_logic;
+ mmc_od_mode_o : out std_logic; -- Open drain mode
+ mmc_dat_i : in unsigned(7 downto 0);
+ mmc_dat_o : out unsigned(7 downto 0);
+ mmc_dat_oe_o : out std_logic;
+ mmc_dat_siz_o : out unsigned(1 downto 0);
+
+ -- Data Pipe FIFOs
+ wr_clk_i : in std_logic;
+ wr_clk_en_i : in std_logic;
+ wr_reset_i : in std_logic; -- Synchronous
+ wr_en_i : in std_logic;
+ wr_dat_i : in unsigned(7 downto 0);
+ wr_fifo_level : out unsigned(FILL_LEVEL_BITS-1 downto 0);
+ wr_fifo_full : out std_logic;
+ wr_fifo_empty : out std_logic;
+
+ rd_clk_i : in std_logic;
+ rd_clk_en_i : in std_logic;
+ rd_reset_i : in std_logic; -- Synchronous
+ rd_en_i : in std_logic;
+ rd_dat_o : out unsigned(7 downto 0);
+ rd_fifo_level : out unsigned(FILL_LEVEL_BITS-1 downto 0);
+ rd_fifo_full : out std_logic;
+ rd_fifo_empty : out std_logic;
+
+ -- Data Pipe RAM
+ ram_clk_i : in std_logic;
+ ram_clk_en_i : in std_logic;
+ ram_adr_i : in unsigned(RAM_ADR_WIDTH-1 downto 0);
+ ram_we_i : in std_logic;
+ ram_dat_i : in unsigned(7 downto 0);
+ ram_dat_o : out unsigned(7 downto 0)
+
+ );
+ end component;
+
+end sd_card_pack;
+
+package body sd_card_pack is
+end sd_card_pack;
+
+
+-------------------------------------------------------------------------------
+-- SD/MMC Card Command Receiver
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Update: Mar. 24, 2016 Wrote description and initial code
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This module is meant to be part of a system that emulates an SD/MMC card.
+--
+-- This module clocks incoming serial command bits into a 48 bit shift
+-- register. It starts when a '0' (start) bit is found, and then shifts in
+-- 47 additional bits. The expected format of the command is:
+--
+-- 0 1 [index] [arg] [crc] 1
+--
+-- Where:
+-- index = 6 bits
+-- arg = 32 bits
+-- crc = 7 bits
+--
+-- It checks that the second bit is a '1' indicating that
+-- the command is from the host to the card. It also checks that the last bit
+-- is a '1' (stop) bit. The seven bits immediately prior to the stop bit are
+-- checked using a CRC-7 code.
+--
+-- If any of the checks does not pass, the associated error bits are set, and
+-- the cmd_ outputs remain unchanged. If all checks pass, then the newly
+-- received command contents are stored into the cmd_ outputs, and the
+-- cmd_rx_done_o output is pulsed high for one sd_clk_i cycle.
+--
+-- Note that this receiver runs entirely within the sd_clk_i clock domain.
+-- Therefore, care must be taken when using the outputs. A FIFO can form
+-- a natural "clock domain boundary crossing" or the user may need to
+-- implement other special handshaking to safely transfer signals into a
+-- different clock domain.
+--
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.ucrc_pack.all;
+
+entity sd_card_cmd_rx is
+ port (
+ -- Asynchronous reset
+ sys_rst_n : in std_logic;
+ -- SD/MMC card command signals
+ sd_clk_i : in std_logic;
+ sd_cmd_i : in std_logic;
+ -- Command outputs
+ cmd_raw_o : out unsigned(47 downto 0);
+ cmd_index_o : out unsigned(5 downto 0);
+ cmd_arg_o : out unsigned(31 downto 0);
+ -- Status and done indicator
+ cmd_done_o : out std_logic;
+ crc_err_o : out std_logic;
+ dir_err_o : out std_logic;
+ stop_err_o : out std_logic
+ );
+end sd_card_cmd_rx;
+
+architecture beh of sd_card_cmd_rx is
+
+ -- CRC related
+signal crc_clk : std_logic;
+signal crc_clr : std_logic;
+signal crc_match : std_logic;
+signal crc_val : unsigned(6 downto 0);
+ -- Related to the incoming command
+signal counter : unsigned(5 downto 0);
+signal rx_sr : unsigned(45 downto 0);
+signal cmd_raw_l : unsigned(47 downto 0);
+
+begin
+
+--------------------------------------------
+-- CRC generator
+
+ crc0 : ucrc_ser
+ generic map (
+ POLYNOMIAL => "0001001",
+ INIT_VALUE => "0000000"
+ )
+ port map (
+ -- System clock and asynchronous reset
+ sys_clk => crc_clk,
+ sys_rst_n => sys_rst_n,
+ sys_clk_en => '1',
+
+ -- Input and Control
+ clear_i => crc_clr,
+ data_i => sd_cmd_i,
+ flush_i => '0',
+
+ -- Output
+ match_o => crc_match,
+ crc_o => crc_val
+ );
+ -- Falling edge was used for a while...
+ -- Rising edge is now being used, per the specification.
+ --crc_clk <= not sd_clk_i;
+ crc_clk <= sd_clk_i;
+ crc_clr <= '1' when counter=0 else '0';
+
+
+--------------------------------------------
+-- Command receiver
+
+command_rx_proc : process(sys_rst_n, sd_clk_i)
+begin
+ if (sys_rst_n='0') then
+ counter <= (others=>'0');
+ rx_sr <= (others=>'0');
+ cmd_raw_l <= (others=>'1');
+-- elsif (sd_clk_i'event and sd_clk_i='0') then -- falling edge is used, when data is stable.
+ elsif (sd_clk_i'event and sd_clk_i='1') then -- rising edge is used, per the specification.
+ -- The shift register bit is the only synchronization flip flop
+ rx_sr(0) <= sd_cmd_i;
+ rx_sr(45 downto 1) <= rx_sr(44 downto 0);
+ -- Decrement the counter when it is non-zero
+ if (counter>0) then
+ counter <= counter-1;
+ end if;
+ -- Load the counter when a start bit is seen
+ if (counter=0 and sd_cmd_i='0') then
+ counter <= to_unsigned(47,counter'length);
+ end if;
+ -- Store the output when the counter is expiring
+ if (counter=2) then
+ cmd_raw_l <= rx_sr & sd_cmd_i & '1';
+ end if;
+ end if;
+end process;
+
+-- Provide output signals
+cmd_done_o <= '1' when (counter=1 and crc_match='1' and cmd_raw_l(46)='1' and sd_cmd_i='1') else '0';
+stop_err_o <= '1' when (counter=1 and sd_cmd_i='0') else '0';
+dir_err_o <= '1' when (counter=1 and cmd_raw_l(46)='0') else '0';
+crc_err_o <= '1' when (counter=1 and crc_match='0') else '0';
+
+-- Split out fields of the command
+cmd_raw_o <= cmd_raw_l;
+cmd_index_o <= cmd_raw_l(45 downto 40);
+cmd_arg_o <= cmd_raw_l(39 downto 8);
+
+end beh;
+
+
+-------------------------------------------------------------------------------
+-- SD/MMC Card Command Responder
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Update: Mar. 30, 2016 Wrote description and initial code
+-- Apr. 28, 2016 Added N_CR generic
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This module is meant to be part of a system that emulates an SD/MMC card.
+--
+-- This module latches parallel data into a shift register, and then shifts
+-- the data out as a command response, using the sd_clk_i input as the clock.
+--
+-- The process of sending a response begins when the respond_i input is driven
+-- high. The generic N_CR determines how many clocks occur between the
+-- respond_i pulse, and the actual start bit of the response. However,
+-- per the SD/MMC card specifications, there are supposed to be two clock
+-- periods of tri-state bus "turnaround time" following the stop bit of the
+-- command. After the bus turnaround time, then the card pulls up the
+-- command line, until the full N_CR time has expired. The value of N_CR
+-- must not be set below 5 to comply with the minimum values in the SD/MMC
+-- specification. If the respond_i input occurs in the clock following the
+-- command stop bit, then a value of 4 is the lowest permitted N_CR...
+--
+-- According to the SD/MMC card specification, there are several different
+-- types of card responses:
+--
+-- type length structure
+-- ---- ------ ----------------------------------------------------------
+-- R1 = 48 bit, ("00" & 6 bit index & 32 bit card status & 7 bit CRC & '1')
+-- R2 = 136 bit, ("00111111" & 120 bit CID or CSD & 7 bit CRC & '1')
+-- R3 = 48 bit, ("00111111" & 32 bit OCR & "11111111")
+-- R4 = 48 bit, ("00100111" & 16 bit RCA & 1 bit status & 7 bit reg addr & 8 bit reg read data & 7 bit CRC & '1')
+-- R5 = 48 bit, ("00101000" & 16 bit RCA & 16 bit undefined & 7 bit CRC & '1')
+--
+-- The length of the shift register is determined by a generic parameter,
+-- RESP_PYLD_LEN, according to the following formula:
+--
+-- shift_reg_length = 8 + RESP_PYLD_LEN + 8 = 16 + RESP_PYLD_LEN
+--
+-- Thus, for the 48 bit response, RESP_PYLD_LEN is set to 32, and for the
+-- 136 bit response, RESP_PYLD_LEN is set to 120.
+--
+-- This module automatically populates the first two bits of the reply with
+-- "00", Because all of the replies begin with "00." The next 6 bits are
+-- supplied by the "resp_index_i" signal. After that, the next set of bits
+-- is supplied by the signal "resp_pyld_i" which stands for
+-- "response payload." Since the payload could be either 32 bits or 120 bits
+-- long, the payload length is set by the RESP_PYLD_LEN generic.
+--
+-- This module contains a CRC unit which calculates the 7 CRC bits to place at
+-- the end, and the final stop bit is also sent out automatically.
+--
+-- Whenever the responder is idle, asserting the respond_i input causes the
+-- response to be latched immediately, and the first bit of the newly
+-- requested reponse is sent out on the following clock cycle. If a response
+-- is already being actively sent out, the respond_i input is simply ignored.
+--
+-- It is envisioned that several instances of the responder may be used in
+-- parallel, each being connected to a different SD/MMC card register.
+-- Therefore, coordination of the response signals needs to be done in a
+-- higher level module, possibly through some sort of data selector or "mux"
+-- to determine which sd_cmd_o and sd_cmd_oe_o outputs get used, and also
+-- perhaps through logic to ensure that only the desired respond_i input is
+-- asserted. This may seem somewhat "messy," but it was done with the idea
+-- in mind that certain types of responses could be easily left out of the
+-- design completely, by eliminating the associated responder instance.
+-- The higher level module is also responsible for determining the timing
+-- between receipt of a command, and the start of the response.
+-- For instance, the SD/MMC card standard specifies that for identification
+-- responses, exactly 5 clock cycles should exist between the stop bit of
+-- the command, and the start bit of the response.
+--
+-- Note that this responder runs entirely within the sd_clk_i clock domain.
+-- Therefore, care must be taken when supplying the inputs. A FIFO can form
+-- a natural "clock domain boundary crossing" or the user may need to
+-- implement other special handshaking to safely receive signals from a
+-- different clock domain.
+--
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.ucrc_pack.all;
+use work.convert_pack.all;
+
+entity sd_card_responder is
+ generic (
+ N_CR : integer := 5; -- Number of clocks between respond_i and response start
+ RESP_PYLD_LEN : integer := 32;
+ CRC_OFFSET : integer := 0; -- Start CRC calculation after this many bits
+ CRC_SEND_ONES : integer := 0
+ );
+ port (
+ -- Asynchronous reset
+ sys_rst_n : in std_logic;
+ -- SD/MMC card command signals
+ sd_clk_i : in std_logic;
+ sd_cmd_o : out std_logic;
+ sd_cmd_oe_o : out std_logic;
+ -- Response inputs
+ resp_index_i : in unsigned(5 downto 0);
+ resp_pyld_i : in unsigned(RESP_PYLD_LEN-1 downto 0);
+ respond_i : in std_logic;
+ -- Status and done indicator
+ done_o : out std_logic; -- A one clock long pulse
+ busy_o : out std_logic
+ );
+end sd_card_responder;
+
+architecture beh of sd_card_responder is
+
+ -- CRC related
+signal crc_clk_en : std_logic;
+signal crc_clr : std_logic;
+signal crc_val : unsigned(6 downto 0);
+signal crc_enable : std_logic;
+ -- Related to the response
+signal n_cr_count : unsigned(timer_width(N_CR)-1 downto 0);
+signal counter : unsigned(7 downto 0);
+signal tx_sr : unsigned(RESP_PYLD_LEN+7 downto 0);
+signal tail_end : unsigned(8 downto 0);
+
+begin
+
+--------------------------------------------
+-- CRC generator
+
+ crc0 : ucrc_ser
+ generic map (
+ POLYNOMIAL => "0001001",
+ INIT_VALUE => "0000000"
+ )
+ port map (
+ -- System clock and asynchronous reset
+ sys_clk => sd_clk_i,
+ sys_rst_n => sys_rst_n,
+ sys_clk_en => crc_clk_en,
+
+ -- Input and Control
+ clear_i => crc_clr,
+ data_i => tx_sr(tx_sr'length-1),
+ flush_i => '0',
+
+ -- Output
+ match_o => open,
+ crc_o => crc_val
+ );
+ crc_clk_en <= '1' when counter=0 or counter>8 else '0';
+ crc_clr <= '1' when counter=0 or counter>(RESP_PYLD_LEN+16-CRC_OFFSET) else '0';
+ -- Attach a stop bit to the CRC code, and another for easy indexing by the main counter
+ tail_end <= crc_val & "11" when CRC_SEND_ONES=0 else "111111111";
+
+--------------------------------------------
+-- Response Transmitter
+
+response_tx_proc : process(sys_rst_n, sd_clk_i)
+begin
+ if (sys_rst_n='0') then
+ n_cr_count <= (others=>'0');
+ counter <= (others=>'0');
+ tx_sr <= (others=>'1');
+ elsif (sd_clk_i'event and sd_clk_i='1') then
+ -- Default values
+
+ -- Left shifting shift register
+ tx_sr <= tx_sr(tx_sr'length-2 downto 0) & '0';
+ -- Handle the N_CR counter, an incrementing counter
+ if (n_cr_count>0) then
+ n_cr_count <= n_cr_count+1;
+ end if;
+ -- Decrement the main counter when it is non-zero
+ if (counter>0) then
+ counter <= counter-1;
+ end if;
+ -- Load the N_CR counter when a start signal is seen
+ if (counter=0 and n_cr_count=0 and respond_i='1') then
+ n_cr_count <= to_unsigned(1,n_cr_count'length);
+ end if;
+ -- Load the main counter when the N_CR counter matures
+ if (counter=0 and n_cr_count=N_CR) then
+ n_cr_count <= (others=>'0');
+ counter <= to_unsigned(RESP_PYLD_LEN+16,counter'length);
+ tx_sr <= "00" & resp_index_i & resp_pyld_i;
+ end if;
+ end if;
+end process;
+
+done_o <= '1' when counter=1 else '0';
+busy_o <= '1' when counter>0 else '0';
+-- In our current implementation, there are already two cycles of
+-- tri-state bus turnaround time, therefore and additional two cycles
+-- is not required. Uncomment this line for implementations where
+-- the bus turnaround needs to be explicitly created.
+--sd_cmd_oe_o <= '1' when n_cr_count>2 or counter>0 else '0';
+sd_cmd_oe_o <= '1' when n_cr_count>0 or counter>0 else '0';
+sd_cmd_o <= tx_sr(tx_sr'length-1) when counter>8 else
+ tail_end(to_integer(counter));
+
+end beh;
+
+
+-------------------------------------------------------------------------------
+-- SD/MMC Card Data Unit
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Update: Apr. 14, 2016 Wrote description and initial code
+-- June 9, 2016 Added bustest_w_i and bustest_r_i signals
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This module is meant to emulate the data handler of an SD/MMC card.
+--
+-- This module accepts SD/MMC card data transfers, and generates return
+-- transfers for sending data to the cardbus host.
+--
+-- Most of this unit runs entirely within the sd_clk_i clock domain. The FIFO
+-- data storage buffers form a natural place at which to interface between
+-- clock domains, and the registers are also read and written from a separate
+-- clock domain (sys_clk).
+--
+--
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.ucrc_pack.all;
+use work.sd_host_pack.all;
+use work.convert_pack.all;
+
+entity sd_card_data_unit is
+ generic (
+ BLK_PRG_TIME : integer := 400; -- Number of clocks to program a sector in FLASH (emulated)
+ BLKSIZE_W : integer := 12;
+ BLKCNT_W : integer := 16
+ );
+ port(
+ sd_clk_i : in std_logic;
+ sys_rst_n : in std_logic;
+ --Tx Fifo
+ tx_dat_i : in unsigned(7 downto 0);
+ tx_dat_rd_o : out std_logic;
+ --Rx Fifo
+ rx_dat_o : out unsigned(7 downto 0);
+ rx_dat_we_o : out std_logic;
+ --SD data
+ sd_dat_i : in unsigned(7 downto 0);
+ sd_dat_o : out unsigned(7 downto 0);
+ sd_dat_oe_o : out std_logic;
+ --Control signals
+ blksize_i : in unsigned(BLKSIZE_W-1 downto 0);
+ bus_size_i : in unsigned(1 downto 0);
+ blkcnt_i : in unsigned(BLKCNT_W-1 downto 0);
+ continuous_i : in std_logic;
+ d_stop_i : in std_logic;
+ d_read_i : in std_logic;
+ d_write_i : in std_logic;
+ bustest_w_i : in std_logic;
+ bustest_r_i : in std_logic;
+ sd_dat_busy_o : out std_logic;
+ fsm_busy_o : out std_logic;
+ crc_ok_o : out std_logic
+ );
+end sd_card_data_unit;
+
+architecture beh of sd_card_data_unit is
+
+-- Internal constants
+constant BLK_PRG_CBITS : natural := timer_width(BLK_PRG_TIME);
+
+-- Internal signals
+signal dat_reg : unsigned(7 downto 0);
+signal data_cycles : unsigned(BLKSIZE_W+2 downto 0);
+signal bus_size_reg : unsigned(1 downto 0);
+--CRC16
+signal crc_in : unsigned(7 downto 0);
+signal crc_enable : std_logic;
+signal crc_rst_n : std_logic;
+type crc_out_type is
+ array (integer range 0 to 7) of unsigned(15 downto 0);
+signal crc_out : crc_out_type;
+signal crc_ok_l : std_logic;
+signal transf_cnt : unsigned(15 downto 0);
+ --State Machine
+type FSM_STATE_TYPE is (IDLE, SEND_DAT, READ_WAIT, READ_DAT, SEND_BUSTEST,
+ READ_BUSTEST_WAIT, READ_BUSTEST, CRC_ACK, CRC_NACK,
+ RECV_BUSY);
+signal state : FSM_STATE_TYPE;
+
+signal busy_int : std_logic;
+signal blkcnt_reg : unsigned(BLKCNT_W-1 downto 0);
+signal start_bit : std_logic;
+signal crc_c : unsigned(4 downto 0);
+signal crc_status : unsigned(3 downto 0);
+signal data_index : unsigned(2 downto 0);
+signal last_din : unsigned(7 downto 0);
+
+signal bustest_0 : unsigned(7 downto 0);
+signal bustest_1 : unsigned(7 downto 0);
+signal blk_prg_tmr : unsigned(BLK_PRG_CBITS-1 downto 0);
+signal d_stop_pending : std_logic;
+
+begin
+
+--sd data input pad register
+process(sys_rst_n,sd_clk_i)
+begin
+ if (sys_rst_n='0') then
+ dat_reg <= (others=>'0');
+ elsif (sd_clk_i'event and sd_clk_i='1') then
+ dat_reg <= sd_dat_i;
+ end if;
+end process;
+
+-- There are eight different CRC generators
+sd_crc_gen : for nvar in 0 to 7 generate
+begin
+ crc_unit : ucrc_ser
+ generic map (
+ POLYNOMIAL => "0001000000100001",
+ INIT_VALUE => "0000000000000000"
+ )
+ port map (
+ -- System clock and asynchronous reset
+ sys_clk => sd_clk_i,
+ sys_rst_n => crc_rst_n,
+ sys_clk_en => crc_enable,
+
+ -- Input and Control
+ clear_i => '0',
+ data_i => crc_in(nvar),
+ flush_i => '0',
+
+ -- Output
+ match_o => open,
+ crc_o => crc_out(nvar)
+ );
+end generate;
+
+crc_ok_o <= crc_ok_l;
+fsm_busy_o <= '1' when (state/=IDLE) else '0';
+start_bit <= '1' when (dat_reg(0)='0') else '0';
+sd_dat_busy_o <= '1' when (state=RECV_BUSY) else '0';
+
+fsm_proc : process(sys_rst_n,sd_clk_i)
+begin
+ if (sys_rst_n='0') then
+ state <= IDLE;
+ sd_dat_oe_o <= '0';
+ crc_enable <= '0';
+ crc_rst_n <= '0';
+ transf_cnt <= (others=>'0');
+ tx_dat_rd_o <= '0';
+ last_din <= (others=>'0');
+ crc_c <= (others=>'0');
+ crc_status <= (others=>'0');
+ crc_in <= (others=>'0');
+ sd_dat_o <= (others=>'0');
+ rx_dat_we_o <= '0';
+ rx_dat_o <= (others=>'0');
+ crc_ok_l <= '0';
+ busy_int <= '0';
+ data_index <= (others=>'0');
+ blkcnt_reg <= (others=>'0');
+ data_cycles <= (others=>'0');
+ bus_size_reg <= (others=>'0');
+ bustest_0 <= (others=>'0');
+ bustest_1 <= (others=>'0');
+ blk_prg_tmr <= (others=>'0');
+ d_stop_pending <= '0';
+ elsif (sd_clk_i'event and sd_clk_i='1') then
+ -- Handle block programming timer
+ if (blk_prg_tmr>0) then
+ blk_prg_tmr <= blk_prg_tmr-1;
+ end if;
+ -- Implement finite state machine
+ case(state) is
+ when IDLE =>
+ d_stop_pending <= '0';
+ sd_dat_oe_o <= '0';
+ sd_dat_o <= "11111111";
+ crc_enable <= '0';
+ crc_rst_n <= '0';
+ transf_cnt <= (others=>'0');
+ crc_c <= to_unsigned(16,crc_c'length);
+ rx_dat_we_o <= '0';
+ tx_dat_rd_o <= '0';
+ data_index <= (others=>'0');
+ blkcnt_reg <= blkcnt_i;
+ if (bus_size_i=2) then
+ data_cycles <= "000" & blksize_i; -- (<<0) operation
+ elsif (bus_size_i=1) then
+ data_cycles <= "00" & blksize_i & '0'; -- (<<1) operation
+ else
+ data_cycles <= blksize_i & "000"; -- (<<3) operation
+ end if;
+ bus_size_reg <= bus_size_i;
+ -- state transition
+ -- Currently stream based reads and writes are not supported, so if "continuous_i" is
+ -- asserted, remain in IDLE state
+ if (continuous_i='0' and d_stop_i='0' and d_read_i='0' and d_write_i='1' and bustest_w_i='0' and bustest_r_i='0') then
+ state <= SEND_DAT;
+ -- For the case of 8-bit bus width, provide early read signal, so that
+ -- synchronous RAMs, such as BRAMs and BRAM based FIFOs have a chance to
+ -- respond in time.
+ if (bus_size_reg=2) then
+ tx_dat_rd_o <= '1';
+ end if;
+ elsif (continuous_i='0' and d_stop_i='0' and d_read_i='1' and d_write_i='0' and bustest_w_i='0' and bustest_r_i='0') then
+ state <= READ_WAIT;
+ elsif (continuous_i='0' and d_stop_i='0' and d_read_i='0' and d_write_i='0' and bustest_w_i='0' and bustest_r_i='1') then
+ data_cycles <= to_unsigned(24,data_cycles'length);
+ state <= SEND_BUSTEST;
+ elsif (continuous_i='0' and d_stop_i='0' and d_read_i='0' and d_write_i='0' and bustest_w_i='1' and bustest_r_i='0') then
+ state <= READ_BUSTEST_WAIT;
+ end if;
+
+ when SEND_BUSTEST =>
+ transf_cnt <= transf_cnt+1;
+ tx_dat_rd_o <= '0';
+ -- Send out start bits
+ if (transf_cnt = 1) then
+ sd_dat_oe_o <= '1';
+ sd_dat_o <= "00000000";
+ end if;
+ if (transf_cnt = 2) then
+ sd_dat_o <= bustest_0;
+ end if;
+ if (transf_cnt = 3) then
+ sd_dat_o <= bustest_1;
+ end if;
+ if ((transf_cnt >= 4) and (transf_cnt < data_cycles)) then
+ sd_dat_o <= "00000000";
+ end if;
+ if (transf_cnt = data_cycles) then -- stop bits
+ sd_dat_o <= "11111111";
+ end if;
+ if (transf_cnt = data_cycles+1) then
+ sd_dat_oe_o <= '0';
+ end if;
+ -- state transition
+ if ((d_stop_i='1') or (transf_cnt >= data_cycles+1)) then
+ state <= IDLE;
+ end if;
+
+ when READ_BUSTEST_WAIT =>
+ sd_dat_oe_o <= '0';
+ transf_cnt <= (others=>'0');
+ -- state transition
+ if (d_stop_i='1') then -- signal for stopping
+ state <= IDLE;
+ elsif (start_bit='1') then
+ state <= READ_BUSTEST;
+ end if;
+
+ when READ_BUSTEST =>
+ transf_cnt <= transf_cnt+1;
+ if (transf_cnt = 0) then
+ bustest_0 <= not dat_reg;
+ end if;
+ if (transf_cnt = 1) then
+ bustest_1 <= not dat_reg;
+ end if;
+ -- state transition
+ -- No CRC status response is needed
+ -- Look for stop bits
+ if ((d_stop_i='1') or (dat_reg = "11111111")) then
+ state <= IDLE;
+ end if;
+
+ when SEND_DAT =>
+ crc_ok_l <= '0';
+ transf_cnt <= transf_cnt+1;
+ tx_dat_rd_o <= '0';
+ -- Load values for last_din and crc_in
+ if (bus_size_reg=2) then
+ last_din <= tx_dat_i;
+ crc_in <= tx_dat_i;
+ if (transf_cnt'0');
+ else
+ data_index <= data_index+1;
+ end if;
+ else
+ last_din <= "1111111" & tx_dat_i(7-to_integer(data_index));
+ crc_in <= "1111111" & tx_dat_i(7-to_integer(data_index));
+ if (transf_cnt'0');
+ else
+ data_index <= data_index+1;
+ end if;
+ end if;
+ -- Treat first transfer differently
+ if (transf_cnt = 1) then
+ crc_rst_n <= '1';
+ crc_enable <= '1';
+ if (bus_size_reg=2) then
+ last_din <= tx_dat_i;
+ crc_in <= tx_dat_i;
+ elsif (bus_size_reg=1) then
+ last_din <= "1111" & tx_dat_i(7 downto 4);
+ crc_in <= "1111" & tx_dat_i(7 downto 4);
+ else
+ last_din <= "1111111" & tx_dat_i(7);
+ crc_in <= "1111111" & tx_dat_i(7);
+ end if;
+ sd_dat_oe_o <= '1';
+ sd_dat_o <= "00000000";
+ -- Previous code took care to provide start bit on only
+ -- the active lines. However, the bus_size_reg logic
+ -- takes care of masking the unused lines anyway, at
+ -- the top level.
+ --if (bus_size_reg=2) then -- start bits
+ -- sd_dat_o <= "00000000";
+ --elsif (bus_size_reg=1) then
+ -- sd_dat_o <= "11110000";
+ --else
+ -- sd_dat_o <= "11111110";
+ --end if;
+ data_index <= to_unsigned(1,data_index'length);
+ end if;
+ if ((transf_cnt >= 2) and (transf_cnt <= data_cycles+1)) then
+ sd_dat_o <= last_din;
+ if (transf_cnt = data_cycles+1) then
+ crc_enable <= '0';
+ end if;
+ elsif (transf_cnt > data_cycles+1) and (crc_c/=0) then
+ crc_enable <= '0';
+ crc_c <= crc_c-1;
+ sd_dat_o(0) <= crc_out(0)(to_integer(crc_c)-1);
+ if (bus_size_reg=2) then
+ sd_dat_o(7 downto 1) <= crc_out(7)(to_integer(crc_c)-1) & crc_out(6)(to_integer(crc_c)-1) &
+ crc_out(5)(to_integer(crc_c)-1) & crc_out(4)(to_integer(crc_c)-1) &
+ crc_out(3)(to_integer(crc_c)-1) & crc_out(2)(to_integer(crc_c)-1) &
+ crc_out(1)(to_integer(crc_c)-1);
+ elsif (bus_size_reg=1) then
+ sd_dat_o(3 downto 1) <= crc_out(3)(to_integer(crc_c)-1) & crc_out(2)(to_integer(crc_c)-1) &
+ crc_out(1)(to_integer(crc_c)-1);
+ sd_dat_o(7 downto 4) <= (others=>'1');
+ else
+ sd_dat_o(7 downto 1) <= (others=>'1');
+ end if;
+ end if;
+ if (transf_cnt = data_cycles+18) then -- stop bits
+ sd_dat_o <= "11111111";
+ end if;
+ if (transf_cnt = data_cycles+19) then
+ sd_dat_oe_o <= '0';
+ end if;
+ -- state transition
+ if (d_stop_i='1') then -- signal for stopping
+ state <= IDLE;
+ elsif (transf_cnt >= data_cycles+19) then
+ transf_cnt <= (others=>'0');
+ if (blkcnt_reg>0) then
+ blkcnt_reg <= blkcnt_reg-1;
+ end if;
+ crc_rst_n <= '0';
+ crc_c <= to_unsigned(16,crc_c'length);
+ -- State transition
+ if (blkcnt_reg=1) then
+ state <= IDLE;
+ else
+ state <= SEND_DAT;
+ end if;
+ end if;
+
+ when READ_WAIT =>
+ sd_dat_oe_o <= '0';
+ crc_rst_n <= '1';
+ crc_enable <= '1';
+ crc_in <= (others=>'0');
+ crc_c <= to_unsigned(15,crc_c'length);-- end
+ transf_cnt <= (others=>'0');
+ -- state transition
+ if (d_stop_i='1') then -- signal for stopping
+ state <= IDLE;
+ elsif (start_bit='1') then
+ state <= READ_DAT;
+ end if;
+
+ when READ_DAT =>
+ transf_cnt <= transf_cnt+1;
+ if (transf_cnt < data_cycles) then
+ if (bus_size_reg=2) then
+ rx_dat_we_o <= '1';
+ rx_dat_o <= dat_reg;
+ elsif (bus_size_reg=1) then
+ if (transf_cnt(0 downto 0)=1) then
+ rx_dat_we_o <= '1';
+ else
+ rx_dat_we_o <= '0';
+ end if;
+ rx_dat_o(7-(4*to_integer(transf_cnt(0 downto 0)))) <= dat_reg(3);
+ rx_dat_o(6-(4*to_integer(transf_cnt(0 downto 0)))) <= dat_reg(2);
+ rx_dat_o(5-(4*to_integer(transf_cnt(0 downto 0)))) <= dat_reg(1);
+ rx_dat_o(4-(4*to_integer(transf_cnt(0 downto 0)))) <= dat_reg(0);
+ else
+ if (transf_cnt(2 downto 0)=7) then
+ rx_dat_we_o <= '1';
+ else
+ rx_dat_we_o <= '0';
+ end if;
+ rx_dat_o(7-to_integer(transf_cnt(2 downto 0))) <= dat_reg(0);
+ end if;
+ crc_in <= dat_reg;
+ crc_ok_l <= '1';
+ elsif (transf_cnt <= data_cycles+16) then
+ crc_enable <= '0';
+ last_din <= dat_reg;
+ rx_dat_we_o <= '0';
+ if (transf_cnt > data_cycles) then
+ crc_c <= crc_c-1;
+ if (crc_out(0)(to_integer(crc_c)) /= last_din(0)) then
+ crc_ok_l <= '0';
+ end if;
+ if (crc_out(1)(to_integer(crc_c)) /= last_din(1) and bus_size_reg>0) then
+ crc_ok_l <= '0';
+ end if;
+ if (crc_out(2)(to_integer(crc_c)) /= last_din(2) and bus_size_reg>0) then
+ crc_ok_l <= '0';
+ end if;
+ if (crc_out(3)(to_integer(crc_c)) /= last_din(3) and bus_size_reg>0) then
+ crc_ok_l <= '0';
+ end if;
+ if (crc_out(4)(to_integer(crc_c)) /= last_din(4) and bus_size_reg>1) then
+ crc_ok_l <= '0';
+ end if;
+ if (crc_out(5)(to_integer(crc_c)) /= last_din(5) and bus_size_reg>1) then
+ crc_ok_l <= '0';
+ end if;
+ if (crc_out(6)(to_integer(crc_c)) /= last_din(6) and bus_size_reg>1) then
+ crc_ok_l <= '0';
+ end if;
+ if (crc_out(7)(to_integer(crc_c)) /= last_din(7) and bus_size_reg>1) then
+ crc_ok_l <= '0';
+ end if;
+ if (crc_c=0) then
+ crc_rst_n <= '0';
+ end if;
+ end if;
+ end if;
+ -- state transition, provide CRC status reponse
+ -- The bus turnaround time (tri-state condition) occurs
+ -- on transf_cnt=(data_cycles+16) and (data_cycles+17)
+ -- Then, CRC status response begins
+ if (d_stop_i='1') then -- signal for stopping
+ if (transf_cnt <= data_cycles+16) then
+ state <= IDLE;
+ else
+ d_stop_pending <= '1'; -- Continue with CRC status token response, then stop.
+ end if;
+ end if;
+ if (transf_cnt=(data_cycles+17)) then
+ sd_dat_oe_o <= '1';
+ sd_dat_o <= "00000000"; -- start bit for CRC status response
+ if (crc_ok_l='1') then
+ crc_status <= "0101"; -- status for good CRC, with stop bit
+ state <= CRC_ACK;
+ else
+ crc_status <= "1011"; -- status for bad CRC, with stop bit
+ state <= CRC_NACK;
+ end if;
+ end if;
+
+ when CRC_ACK =>
+ transf_cnt <= transf_cnt+1;
+ sd_dat_o(0) <= crc_status(3);
+ sd_dat_o(7 downto 1) <= (others=>'1');
+ crc_status <= crc_status(2 downto 0) & '1';
+ if (d_stop_i='1') then
+ d_stop_pending <= '1';
+ end if;
+ if (transf_cnt=(data_cycles+22)) then
+ blk_prg_tmr <= to_unsigned(BLK_PRG_TIME,blk_prg_tmr'length);
+ state <= RECV_BUSY;
+ end if;
+
+ when CRC_NACK =>
+ transf_cnt <= transf_cnt+1;
+ sd_dat_o(0) <= crc_status(3);
+ sd_dat_o(7 downto 1) <= (others=>'1');
+ crc_status <= crc_status(2 downto 0) & '1';
+ if (d_stop_i='1') then
+ d_stop_pending <= '1';
+ end if;
+ if (transf_cnt=(data_cycles+22)) then
+ blkcnt_reg <= to_unsigned(1,blkcnt_reg'length); -- Cancel remainder, due to error
+ blk_prg_tmr <= to_unsigned(BLK_PRG_TIME,blk_prg_tmr'length);
+ state <= RECV_BUSY;
+ end if;
+
+ when RECV_BUSY =>
+ if (d_stop_i='1') then
+ d_stop_pending <= '1';
+ end if;
+ -- Wait for busy period, even if stop is pending
+ if (blk_prg_tmr>0) then
+ null; -- Wait here
+ else
+ if (blkcnt_reg>0) then
+ blkcnt_reg <= blkcnt_reg-1;
+ end if;
+ -- State transition
+ if ((d_stop_pending='1') or (blkcnt_reg=1)) then
+ state <= IDLE;
+ else
+ state <= READ_WAIT;
+ end if;
+ end if;
+
+
+ when others =>
+ null;
+
+ end case;
+ end if;
+end process;
+
+
+end beh;
+
+
+
+-------------------------------------------------------------------------------
+-- SD/MMC Card Emulator
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Update: Apr. 6, 2016 Wrote description and initial code
+-- Apr. 28, 2016 Added sd_card_data_unit, and various signals to
+-- support it.
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This module is meant to emulate an SD/MMC card.
+--
+-- This module does what an SD/MMC card would do, within reason.
+-- That is to say, it responds to commands, and accepts and provides data,
+-- but it does not contain the actual data storage cells. Instead of storing
+-- data directly into a non-volatile memory array, this module provides an
+-- addressed parallel bus interface, so that FIFOs or other RAM buffers can
+-- be attached and used as storage. The idea is that entire ranges of
+-- addresses can be mapped into the same storage buffer, or a set of buffers
+-- which are set up on certain address boundaries. With these buffers in
+-- place, the sd_card_controller can act as a "bridge" between a host system
+-- and the FIFOs. Data can be transferred to and from the FIFO buffers, all
+-- the while the host system believes it is communicating with an SD or MMC
+-- card.
+--
+-- Obviously, this scheme does not include the concept of a file system, which
+-- may necessitate one of the following:
+--
+-- 1. A host command which can read and write to specific SD/MMC sectors,
+-- which are most likely 512 bytes each in length.
+-- 2. The creation of a file system within the storage area of the FIFO
+-- buffers.
+--
+-- Option 2 requires significant amounts of cleverness, and has not yet been
+-- worked out in the mind of this code author. However, for option 1, there
+-- exists a command in Linux, namely the "dd" command, which can serve to
+-- access individual sectors, in the fashion shown below. A software log
+-- file output is shown after each command, helping to illustrate the sequence
+-- of SD/MMC commands and responses which occur as part of the transfer, from
+-- the perspective of the host:
+--
+-- WRITE BLOCK 0 : dd if=/dev/zero of=/dev/mmcblk1 bs=4k count=1
+--
+-- Jan 15 11:45:31 bbb user.debug kernel: [ 253.042114] omap_hsmmc 481d8000.mmc: enabled
+-- Jan 15 11:45:31 bbb user.debug kernel: [ 253.042235] omap_hsmmc 481d8000.mmc: mmc1: CMD25, argument 0x00000000
+-- Jan 15 11:45:31 bbb user.debug kernel: [ 253.042274] omap_hsmmc 481d8000.mmc: IRQ Status is 1
+-- Jan 15 11:45:31 bbb user.debug kernel: [ 253.096448] omap_hsmmc 481d8000.mmc: IRQ Status is 2
+-- Jan 15 11:45:31 bbb user.debug kernel: [ 253.096478] omap_hsmmc 481d8000.mmc: mmc1: CMD12, argument 0x00000000
+-- Jan 15 11:45:31 bbb user.debug kernel: [ 253.096511] omap_hsmmc 481d8000.mmc: IRQ Status is 3
+-- Jan 15 11:45:31 bbb user.debug kernel: [ 253.096617] omap_hsmmc 481d8000.mmc: mmc1: CMD13, argument 0x00010000
+-- Jan 15 11:45:31 bbb user.debug kernel: [ 253.096640] omap_hsmmc 481d8000.mmc: IRQ Status is 1
+-- Jan 15 11:45:31 bbb user.debug kernel: [ 253.195201] omap_hsmmc 481d8000.mmc: disabled
+--
+--
+-- WRITE BLOCK 1 : dd if=/dev/zero of=/dev/mmcblk1 bs=4k count=1 seek=1
+--
+-- Jan 15 11:50:19 bbb user.debug kernel: [ 541.840549] omap_hsmmc 481d8000.mmc: enabled
+-- Jan 15 11:50:19 bbb user.debug kernel: [ 541.840671] omap_hsmmc 481d8000.mmc: mmc1: CMD25, argument 0x00000008
+-- Jan 15 11:50:19 bbb user.debug kernel: [ 541.840706] omap_hsmmc 481d8000.mmc: IRQ Status is 1
+-- Jan 15 11:50:19 bbb user.debug kernel: [ 541.840858] omap_hsmmc 481d8000.mmc: IRQ Status is 2
+-- Jan 15 11:50:19 bbb user.debug kernel: [ 541.840871] omap_hsmmc 481d8000.mmc: mmc1: CMD12, argument 0x00000000
+-- Jan 15 11:50:19 bbb user.debug kernel: [ 541.840888] omap_hsmmc 481d8000.mmc: IRQ Status is 1
+-- Jan 15 11:50:19 bbb user.debug kernel: [ 541.841414] omap_hsmmc 481d8000.mmc: IRQ Status is 2
+-- Jan 15 11:50:19 bbb user.debug kernel: [ 541.841484] omap_hsmmc 481d8000.mmc: mmc1: CMD13, argument 0x00010000
+-- Jan 15 11:50:19 bbb user.debug kernel: [ 541.841506] omap_hsmmc 481d8000.mmc: IRQ Status is 1
+-- Jan 15 11:50:20 bbb user.debug kernel: [ 541.934036] omap_hsmmc 481d8000.mmc: disabled
+--
+--
+-- WRITE BLOCK 2 : dd if=/dev/zero of=/dev/mmcblk1 bs=4k count=1 seek=2
+--
+-- Jan 15 11:49:31 bbb user.debug kernel: [ 493.057453] omap_hsmmc 481d8000.mmc: enabled
+-- Jan 15 11:49:31 bbb user.debug kernel: [ 493.057573] omap_hsmmc 481d8000.mmc: mmc1: CMD25, argument 0x00000010
+-- Jan 15 11:49:31 bbb user.debug kernel: [ 493.057610] omap_hsmmc 481d8000.mmc: IRQ Status is 1
+-- Jan 15 11:49:31 bbb user.debug kernel: [ 493.057761] omap_hsmmc 481d8000.mmc: IRQ Status is 2
+-- Jan 15 11:49:31 bbb user.debug kernel: [ 493.057775] omap_hsmmc 481d8000.mmc: mmc1: CMD12, argument 0x00000000
+-- Jan 15 11:49:31 bbb user.debug kernel: [ 493.057792] omap_hsmmc 481d8000.mmc: IRQ Status is 1
+-- Jan 15 11:49:31 bbb user.debug kernel: [ 493.058283] omap_hsmmc 481d8000.mmc: IRQ Status is 2
+-- Jan 15 11:49:31 bbb user.debug kernel: [ 493.058357] omap_hsmmc 481d8000.mmc: mmc1: CMD13, argument 0x00010000
+-- Jan 15 11:49:31 bbb user.debug kernel: [ 493.058379] omap_hsmmc 481d8000.mmc: IRQ Status is 1
+-- Jan 15 11:49:31 bbb user.debug kernel: [ 493.150608] omap_hsmmc 481d8000.mmc: disabled
+--
+--
+-- This SD/MMC card emulator can implement the following response types:
+--
+-- type length structure
+-- ---- ------ ----------------------------------------------------------
+-- R1 = 48 bit, ("00" & 6 bit index & 32 bit card status & 7 bit CRC & '1')
+-- R2 = 136 bit, ("00111111" & 120 bit CID or CSD & 7 bit CRC & '1')
+-- R3 = 48 bit, ("00111111" & 32 bit OCR & "11111111")
+-- R4 = 48 bit, ("00100111" & 16 bit RCA & 1 bit status & 7 bit reg addr & 8 bit reg read data & 7 bit CRC & '1')
+-- R5 = 48 bit, ("00101000" & 16 bit RCA & 16 bit undefined & 7 bit CRC & '1')
+--
+-- There is a "modified" R1 response, called R1b, in which the D0 line can
+-- be held low to signify that the card needs more time. Currently, the
+-- R1b option to delay is not used by this card.
+--
+-- The R4 and R5 response types are optional, and can be de-selected by
+-- setting generics to zero.
+--
+-- Boot modes are not supported, although they probably could be with a
+-- modicum of additional work. The states are already provided in the card
+-- state machine, along with some comments detailing what needs to be done.
+--
+-- This module assumes it is the only card on the host SD/MMC card bus.
+-- Therefore, it does not "bitwise monitor its outgoing bitstream" when
+-- responding to ALL_SEND_CID (CMD2). See eMMC Specification JESD84-A44,
+-- section 7.4.5 "Card Identification Process" for further details.
+-- Of course, feel free to upgrade this module to operate on multi-card
+-- buses, if that is what interests you.
+--
+-- Most of this unit runs entirely within the sd_clk_i clock domain. The FIFO
+-- data storage buffers form a natural place at which to interface between
+-- clock domains, and the registers are also read and written from a separate
+-- clock domain (sys_clk).
+--
+-- Register default values are set by generics.
+--
+-- The module registers are summarized as follows:
+--
+-- Address Structure Function
+-- ------- --------- -----------------------------------------------------
+-- 0x0 (31:0) Card status, some bits read only
+-- 0x1 (31:0) (31:16)=Relative Card Address (RCA) (READ ONLY)
+-- (15: 0)=Driver Stage Register (DSR) (READ ONLY)
+-- 0x2 (8:0) EXT_CSD address
+-- 0x3 (7:0) EXT_CSD data
+-- 0x4 (31:0) Card Specific Data (CSD) bytes [ 3: 0]
+-- Byte [0] is a "scratchpad" only, since the card R2
+-- responder populates those bits with CRC-7 and stop bit.
+-- 0x5 (31:0) Card Specific Data (CSD) bytes [ 7: 4]
+-- 0x6 (31:0) Card Specific Data (CSD) bytes [11: 8]
+-- 0x7 (31:0) Card Specific Data (CSD) bytes [15:12]
+-- 0xF (15:0) Command receive CRC error count
+--
+-- Notes on SD/MMC card registers:
+--
+-- The module registers are not equivalent to the card registers.
+-- The card has the following registers:
+-- Module
+-- Name Size Access Notes
+-- ------ --------- ------ ---------------------------
+-- status 4 bytes RW module R_0
+-- CID 16 bytes RO Wholly set by generics
+-- CSD 16 bytes RW Defaults set by generics
+-- EXT_CSD 512 bytes RW contained in initialized Block RAM
+-- RCA 2 bytes RO module R_1, bits (31:16)
+-- DSR 2 bytes RO module R_1, bits (15: 0), use is optional
+-- OCR 4 bytes RW Set by constant plus generics
+--
+-- CSD is readable in the 2 lower bytes by the card, the upper 14 bytes are
+-- read only on the card side.
+--
+-- Notes on module registers:
+--
+-- Refer to MMC specifications for descriptions of the card registers.
+--
+-- 0xF : SD/MMC command receive CRC error count
+--
+-- bits (15:0) contain a count of the number of SD/MMC commands
+-- which have been received with CRC errors. This
+-- count is reset to zero whenever it is written to,
+-- regardless of what value is written.
+--
+
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.convert_pack.all;
+use work.sd_card_pack.all;
+use work.block_ram_pack.all;
+
+entity sd_card_emulator is
+ generic (
+ USE_R4_RESPONSE : integer := 1; -- Fast I/O read/write (app specific)
+ USE_R5_RESPONSE : integer := 0; -- Interrupt Request Mode
+ EXT_CSD_INIT_FILE : string := "ext_csd_init.txt"; -- Initial contents of EXT_CSD
+ OCR_USE_DUAL_VOLTAGE : integer := 1;
+ OCR_USE_SECTOR_MODE : integer := 0;
+ CID_MID : unsigned( 7 downto 0) := str2u("45",8); -- Manufacturer ID
+ CID_OID : unsigned( 7 downto 0) := str2u("77",8); -- OEM ID
+ CID_CBX : unsigned( 1 downto 0) := "00"; -- 0=Card, 1=BGA, 2=Package On Package
+ CID_PNM : unsigned(47 downto 0) := str2u("434152444C59",48); -- Product Name, 6 ASCII chars
+ CID_PRV : unsigned( 7 downto 0) := str2u("01",8); -- Product Rev (2 BCD digits, e.g. 6.2=0x62)
+ CID_PSN : unsigned(31 downto 0) := str2u("00000012",32); -- Product serial number
+ CID_MDT : unsigned( 7 downto 0) := str2u("43",8); -- Manufacture Date (Jan=1, 1997=0, e.g. Apr. 2000=0x43)
+ DEF_STAT : unsigned(31 downto 0) := str2u("00000000",32); -- Read Write, R_0
+ CSD_WORD_3 : unsigned(31 downto 0) := str2u("905E002A",32); -- See MMC spec
+ CSD_WORD_2 : unsigned(31 downto 0) := str2u("1F5983D3",32); -- See MMC spec
+ CSD_WORD_1 : unsigned(31 downto 0) := str2u("EDB707FF",32); -- See MMC spec
+ CSD_WORD_0 : unsigned(31 downto 0) := str2u("96400000",32); -- See MMC spec, bits (7:0) not used.
+ DEF_R_Z : unsigned(31 downto 0) := str2u("33333333",32) -- Value returned for nonexistent registers
+ );
+ port (
+
+ -- Asynchronous reset
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+
+ -- Bus interface
+ adr_i : in unsigned(3 downto 0);
+ sel_i : in std_logic;
+ we_i : in std_logic;
+ dat_i : in unsigned(31 downto 0);
+ dat_o : out unsigned(31 downto 0);
+ ack_o : out std_logic;
+
+ -- SD/MMC card command signals
+ sd_clk_i : in std_logic;
+ sd_cmd_i : in std_logic;
+ sd_cmd_o : out std_logic;
+ sd_cmd_oe_o : out std_logic;
+ sd_od_mode_o : out std_logic; -- Open drain mode
+ sd_dat_i : in unsigned(7 downto 0);
+ sd_dat_o : out unsigned(7 downto 0);
+ sd_dat_oe_o : out std_logic;
+ sd_dat_siz_o : out unsigned(1 downto 0);
+
+ -- Data FIFO interface
+ buf_adr_o : out unsigned(31 downto 0);
+ buf_dat_o : out unsigned(7 downto 0);
+ buf_dat_we_o : out std_logic;
+ buf_dat_i : in unsigned(7 downto 0);
+ buf_dat_rd_o : out std_logic
+ );
+end sd_card_emulator;
+
+architecture beh of sd_card_emulator is
+
+-- constants
+constant N_ID : integer := 5; -- Number of clocks before response in card ID mode
+constant N_CR : integer := 5; -- Number of clocks before response in data transfer mode
+
+constant N_CD : integer := 45; -- Number of clocks before return data in data transfer mode
+constant D_BITS : integer := 6; -- Number of bits used in N_CD countdown timers (Command to Data)
+
+constant IMPLEMENT_WRITE_PROT : integer := 0; -- Can be added as a generic if desired...
+
+-- signals
+ -- related to card registers
+signal status : unsigned(31 downto 0);
+signal reported_status : unsigned(31 downto 0); -- contains some read only fields
+signal cid : unsigned(127 downto 0);
+signal cid_resp : unsigned(119 downto 0);
+signal csd : unsigned(127 downto 0);
+signal csd_resp : unsigned(119 downto 0);
+signal rca : unsigned(15 downto 0);
+signal dsr : unsigned(15 downto 0);
+signal ocr : unsigned(31 downto 0);
+signal ocr_mode : unsigned(1 downto 0);
+signal ocr_vbit : std_logic;
+signal ocr_pwrup_done : std_logic;
+ -- Pertaining to the EXT_CSD register, which is 512 bytes long
+ -- System side
+signal ext_csd_reg_adr : unsigned(8 downto 0);
+signal ext_csd_reg_dat_rd : unsigned(7 downto 0);
+signal ext_csd_reg_we : std_logic;
+ -- SD/MMC card side
+signal ext_csd_sd_adr : unsigned(8 downto 0);
+signal ext_csd_sd_we : std_logic;
+signal ext_csd_sd_dat_wr : unsigned(7 downto 0);
+signal ext_csd_sd_dat_rd : unsigned(7 downto 0);
+signal cmd6_op : unsigned(1 downto 0); -- Orchestrates operations on ext_csd mode space
+signal ext_csd_rd_adr : unsigned(8 downto 0);
+signal dreply_start_count : unsigned(D_BITS-1 downto 0); -- Determines when data reply begins
+signal prg_dly_count : unsigned(23 downto 0); -- Determines emulated programming delay
+
+ -- Related to receiving commands
+signal sd_cmd_index : unsigned(5 downto 0);
+signal sd_cmd_arg : unsigned(31 downto 0);
+signal sd_cmd_done : std_logic;
+signal sd_cmd_crc_err : std_logic;
+signal sd_cmd_rx : std_logic;
+signal sd_cmd_oe_l : std_logic;
+
+ -- Related to Card Finite State Machine
+type CARD_STATE_TYPE is (CARD_IDLE, CARD_READY, CARD_IDENT, CARD_STBY,
+ CARD_TRAN, CARD_DATA, CARD_RCV,
+ CARD_PRG, CARD_DIS, CARD_BTST, CARD_SLP, CARD_INA,
+ CARD_IRQ, CARD_PRE_IDLE, CARD_PRE_BOOT, CARD_BOOT);
+signal card_state : CARD_STATE_TYPE;
+signal card_state_reply : CARD_STATE_TYPE; -- For reporting in status
+
+signal r_delay : unsigned(5 downto 0); -- Used to count reply delay clock cycles
+signal sd_adr_match : std_logic;
+signal card_cmd_set : unsigned(2 downto 0);
+signal card_adr : unsigned(31 downto 0);
+signal card_blocklen : unsigned(11 downto 0);
+signal card_block_count : unsigned(15 downto 0);
+signal card_dbus_size : unsigned(1 downto 0);
+signal card_rel_wr_req : std_logic;
+signal card_erase_group_start : unsigned(31 downto 0);
+signal card_erase_group_end : unsigned(31 downto 0);
+signal card_d_crc_ok : std_logic;
+signal card_d_continuous : std_logic;
+signal card_d_stop : std_logic;
+signal card_d_recv : std_logic;
+signal card_d_send : std_logic;
+signal card_bustest_r : std_logic;
+signal card_bustest_w : std_logic;
+signal card_sd_dat_busy : std_logic;
+signal sd_dat_unbusy : unsigned(7 downto 0); -- Data lines before adding CARD_PRG busy indication
+signal sd_dat_oe_unbusy : std_logic; -- Output enable before adding CARD_PRG busy indication
+signal card_d_busy : std_logic;
+signal card_d_busy_r1 : std_logic;
+signal card_tx_dat : unsigned(7 downto 0);
+signal card_tx_dat_rd : std_logic;
+signal adr_offset : unsigned(31 downto 0);
+signal buf_dat_we_l : std_logic;
+
+ -- Related to command responses
+ -- R1 response type
+signal r1_cmd : std_logic;
+signal r1_cmd_oe : std_logic;
+signal r1_start : std_logic;
+signal r1_done : std_logic;
+signal crc_err_reply : std_logic; -- Cleared at end of R1 reponse
+signal cmd_err_reply : std_logic; -- Cleared at end of R1 reponse
+signal sd_cmd_neverbad : std_logic;
+
+ -- R2 CID response type
+signal r2_cid_cmd : std_logic;
+signal r2_cid_cmd_oe : std_logic;
+signal r2_cid_start : std_logic;
+signal r2_cid_done : std_logic;
+
+ -- R2 CSD response type
+signal r2_csd_cmd : std_logic;
+signal r2_csd_cmd_oe : std_logic;
+signal r2_csd_start : std_logic;
+signal r2_csd_done : std_logic;
+
+ -- R3 response type
+signal r3_cmd : std_logic;
+signal r3_cmd_oe : std_logic;
+signal r3_start : std_logic;
+signal r3_done : std_logic;
+
+ -- R4 response type
+signal r4_cmd : std_logic;
+signal r4_cmd_oe : std_logic;
+signal r4_start : std_logic;
+signal r4_done : std_logic;
+signal fast_io_reg_rd : unsigned(31 downto 0);
+signal r4_status : std_logic;
+signal r4_reg_adr : unsigned(6 downto 0);
+signal r4_reg_dat_rd : unsigned(7 downto 0);
+signal r4_reg_dat_wr : unsigned(7 downto 0);
+signal r4_reg_we : std_logic;
+ -- Special purpose registers used with CMD39
+ -- (Currently only a pair of registers is provided,
+ -- because we do not have a purpose for them.)
+signal r4_reg_0 : unsigned(7 downto 0);
+signal r4_reg_1 : unsigned(7 downto 0);
+
+ -- R5 response type
+signal r5_cmd : std_logic;
+signal r5_cmd_oe : std_logic;
+signal r5_start : std_logic;
+signal r5_done : std_logic;
+signal irq_response : unsigned(31 downto 0);
+
+begin
+
+ -- module register read mux
+ with to_integer(adr_i) select
+ dat_o <=
+ reported_status when 0,
+ rca & dsr when 1,
+ u_resize(ext_csd_reg_adr,32) when 2,
+ u_resize(ext_csd_reg_dat_rd,32) when 3,
+ csd(31 downto 0) when 4,
+ csd(63 downto 32) when 5,
+ csd(95 downto 64) when 6,
+ csd(127 downto 96) when 7,
+ DEF_R_Z when others;
+
+ -- Create acknowledge signal
+ ack_o <= sel_i;
+
+ -- module register writes are handled here.
+ module_reg_proc: process(sys_clk, sys_rst_n)
+ begin
+ if (sys_rst_n='0') then
+ status <= DEF_STAT;
+ csd <= CSD_WORD_3 & CSD_WORD_2 & CSD_WORD_1 & CSD_WORD_0;
+ ext_csd_reg_adr <= (others=>'0');
+ elsif (sys_clk'event and sys_clk='1') then
+ -- Handle bus writes to registers
+ -- These are allowed even when sys_clk_en is low
+ if (sel_i='1' and we_i='1') then
+ case to_integer(adr_i) is
+ when 0 =>
+ -- Except for the reported card_state, and the self-clearing
+ -- error bits, the other status can be set here.
+ status <= dat_i;
+ when 2 =>
+ ext_csd_reg_adr <= dat_i(8 downto 0);
+ when 3 =>
+ null; -- EXT_CSD write handled at the BRAM
+ when 4 =>
+ csd( 31 downto 0) <= dat_i;
+ when 5 =>
+ csd( 63 downto 32) <= dat_i;
+ when 6 =>
+ csd( 95 downto 64) <= dat_i;
+ when 7 =>
+ csd(127 downto 96) <= dat_i;
+ when others => null;
+ end case;
+ end if; -- sel_i
+ end if; -- sys_clk
+ end process;
+
+ -- formulate any card registers which may depend on generics
+ -- Per the eMMC Specification, JESD84-A44, the following fields are defined:
+ -- (From table 41, page 112, Section 8.1)
+ --
+ -- Bits (127:120) = MID (Manufacturer ID)
+ -- Bits (119:114) = 000000b (Reserved)
+ -- Bits (113:112) = CBX (00=Card, 01=BGA, 10=POP, 11=reserved) (POP=Package On Package)
+ -- Bits (111:104) = OID (OEM ID)
+ -- Bits (103: 56) = PNM (Product Name, 6 ASCII characters)
+ -- Bits ( 55: 48) = PRV (Product Revision)
+ -- Bits ( 47: 16) = PSN (Product Serial Number)
+ -- Bits ( 15: 8) = MDT (Manufacturing Date)
+ -- Bits ( 7: 1) = CRC-7 checksum (Added by responder in this case)
+ -- Bit ( 0) = '1' (Stop Bit, added by responder in this case)
+cid <= CID_MID & "000000" & CID_CBX & CID_OID & CID_PNM &
+ CID_PRV & CID_PSN & CID_MDT & "00000001";
+cid_resp <= cid(127 downto 8); -- Responder adds the CRC-7 and stop bit fields
+csd_resp <= csd(127 downto 8); -- Responder adds the CRC-7 and stop bit fields
+
+ -- OCR:
+ -- Per the eMMC Specification, JESD84-A44, the following fields are defined:
+ -- (From table 40, page 111, Section 8.1)
+ --
+ -- Bits (6:0) = "0000000" (Reserved)
+ -- Bit (7) = '0' (1.7 to 1.95 Volts; set for "dual voltage" cards)
+ -- Bits (14:8) = "0000000" (2.0 to 2.6 Volts)
+ -- Bits (23:15) = "111111111" (2.7 to 3.6 Volts)
+ -- Bits (28:24) = "00000" (Reserved)
+ -- Bits (30:29) = "00" (Byte mode) or "01" (Sector mode)
+ -- Bit (31) = '1' (Card power up status, set to '0' for "busy")
+ocr_vbit <= '1' when OCR_USE_DUAL_VOLTAGE>0 else '0';
+ocr_mode <= "01" when OCR_USE_SECTOR_MODE>0 else "00";
+ocr <= ocr_pwrup_done & ocr_mode & "00000" & "111111111" & "0000000" & ocr_vbit & "0000000";
+ -- Note: OCR response to CMD1 for eMMC can be a fixed pattern, because the
+ -- host's indication of requested voltage ranges is no longer meaningful for
+ -- eMMC devices.
+ -- Fixed pattern can be:
+ -- 0x00FF8080 for <=2GB eMMC
+ -- 0x40FF8080 for >2GB eMMC
+ -- These fixed patterns are exactly what is produced by the ocr setting above, assuming
+ -- that OCR_USE_DUAL_VOLTAGE is non-zero.
+
+--------------------------------------------
+-- BRAM for 512 byte long EXT_CSD register
+ ext_csd_ram: swiss_army_ram
+ generic map(
+ USE_BRAM => 1, -- Set to nonzero value for BRAM, zero for distributed RAM
+ WRITETHRU => 1, -- Set to nonzero value for writethrough mode
+ USE_FILE => 1, -- Set to nonzero value to use INIT_FILE
+ INIT_VAL => 0, -- Value used when INIT_FILE is not used
+ INIT_SEL => 0, -- Selects which segment of (larger) INIT_FILE to use
+ INIT_FILE => EXT_CSD_INIT_FILE, -- ASCII hexadecimal initialization file name
+ FIL_WIDTH => 8, -- Bit width of init file lines
+ ADR_WIDTH => 9,
+ DAT_WIDTH => 8
+ )
+ port map(
+ clk_a => sys_clk,
+ adr_a_i => ext_csd_reg_adr,
+ we_a_i => ext_csd_reg_we,
+ en_a_i => '1',
+ dat_a_i => dat_i(7 downto 0),
+ dat_a_o => ext_csd_reg_dat_rd,
+
+ clk_b => sd_clk_i,
+ adr_b_i => ext_csd_sd_adr,
+ we_b_i => ext_csd_sd_we,
+ en_b_i => '1',
+ dat_b_i => ext_csd_sd_dat_wr,
+ dat_b_o => ext_csd_sd_dat_rd
+ );
+
+ -- create system side write enable
+ ext_csd_reg_we <= '1' when sel_i='1' and we_i='1' and adr_i=3 else '0';
+
+ -- process for the SD/MMC card side
+ -- CMD39 "FAST_IO" register writes are handled here
+ sd_reg_proc: process(sd_clk_i, sys_rst_n)
+ begin
+ if (sys_rst_n='0') then
+ ext_csd_rd_adr <= (others=>'0');
+ elsif (sd_clk_i'event and sd_clk_i='1') then
+ if (dreply_start_count=0 and card_tx_dat_rd='1') then
+ ext_csd_rd_adr <= ext_csd_rd_adr+1;
+ end if;
+ -- Perform one full readout
+ if (ext_csd_rd_adr/=0 and card_tx_dat_rd='1') then
+ ext_csd_rd_adr <= ext_csd_rd_adr+1;
+ end if;
+ end if; -- sd_clk_i
+ end process;
+
+ ext_csd_sd_adr <= '0' & sd_cmd_arg(23 downto 16) when card_state=CARD_TRAN and sd_cmd_index=6 and sd_cmd_arg(25 downto 24)/=0 and sd_cmd_arg(23 downto 16)<192 else ext_csd_rd_adr;
+ ext_csd_sd_we <= '1' when cmd6_op>0 else '0';
+ ext_csd_sd_dat_wr <= sd_cmd_arg(15 downto 8) OR ext_csd_sd_dat_rd when cmd6_op=1 else -- set bits
+ (NOT sd_cmd_arg(15 downto 8)) AND ext_csd_sd_dat_rd when cmd6_op=2 else -- clear bits
+ sd_cmd_arg(15 downto 8); -- write byte
+
+--------------------------------------------
+-- SD/MMC Command Receiver
+
+ -- Make sure the receiver only listens when there are no
+ -- outgoing transmissions...
+ sd_cmd_rx <= sd_cmd_i when sd_cmd_oe_l='0' else '1';
+
+ cmd_receiver: sd_card_cmd_rx
+ port map(
+ -- Asynchronous reset
+ sys_rst_n => sys_rst_n,
+ -- SD/MMC card command signals
+ sd_clk_i => sd_clk_i,
+ sd_cmd_i => sd_cmd_rx,
+ -- Command outputs
+ cmd_raw_o => open,
+ cmd_index_o => sd_cmd_index,
+ cmd_arg_o => sd_cmd_arg,
+ -- Status and done indicator
+ cmd_done_o => sd_cmd_done,
+ crc_err_o => sd_cmd_crc_err,
+ dir_err_o => open,
+ stop_err_o => open
+ );
+ -- Create an indication that this card is being addressed
+ sd_adr_match <= '1' when sd_cmd_arg(31 downto 16)=rca else '0';
+ -- Create a signal that indicates when a "neverbad" command is received
+ sd_cmd_neverbad <= '1' when sd_cmd_index=0 or sd_cmd_index=15 or sd_cmd_index=55 else '0';
+
+--------------------------------------------
+-- Card State Machine
+
+card_fsm_proc: process(sd_clk_i, sys_rst_n)
+begin
+ if (sys_rst_n='0') then
+ card_state <= CARD_PRE_IDLE;
+ card_state_reply <= CARD_PRE_IDLE;
+ r_delay <= (others=>'0');
+ rca <= str2u("0001",16);
+ dsr <= str2u("0404",16);
+ card_cmd_set <= (others=>'0');
+ card_adr <= (others=>'0');
+ card_blocklen <= to_unsigned(512,card_blocklen'length);
+ card_block_count <= to_unsigned(0,card_block_count'length);
+ card_dbus_size <= "00";
+ card_rel_wr_req <= '0';
+ card_erase_group_start <= (others=>'0');
+ card_erase_group_end <= (others=>'0');
+ cmd6_op <= (others=>'0');
+ prg_dly_count <= (others=>'0');
+ dreply_start_count <= (others=>'0');
+ crc_err_reply <= '0';
+ cmd_err_reply <= '0';
+ r1_start <= '0';
+ r2_cid_start <= '0';
+ r2_csd_start <= '0';
+ r3_start <= '0';
+ r4_start <= '0';
+ r5_start <= '0';
+ r4_reg_dat_wr <= (others=>'0');
+ r4_reg_adr <= (others=>'0');
+ r4_status <= '0';
+ r4_reg_we <= '0';
+ card_d_stop <= '0';
+ card_d_recv <= '0';
+ card_bustest_w <= '0';
+ card_d_busy_r1 <= '0';
+ ocr_pwrup_done <= '0'; -- low means busy
+
+ elsif (sd_clk_i'event and sd_clk_i='1') then
+ -- For edge detection
+ card_d_busy_r1 <= card_d_busy;
+
+ -- Default values
+ r1_start <= '0';
+ r2_cid_start <= '0';
+ r2_csd_start <= '0';
+ r3_start <= '0';
+ r4_start <= '0';
+ r5_start <= '0';
+
+ r4_reg_we <= '0';
+ cmd6_op <= (others=>'0');
+ card_bustest_w <= '0';
+ card_d_stop <= '0';
+ card_d_recv <= '0';
+
+ -- Decrement the EXT_CSD readout delay timer
+ if (dreply_start_count>0) then
+ dreply_start_count <= dreply_start_count-1;
+ end if;
+
+ -- Decrement the programming delay timer
+ if (prg_dly_count>0) then
+ prg_dly_count <= prg_dly_count-1;
+ end if;
+
+ -- Clear certain status bits when reply is done
+ if (r1_done='1') then
+ crc_err_reply <= '0';
+ cmd_err_reply <= '0';
+ end if;
+ -- Set CRC error status bit when errors are found
+ if (sd_cmd_done='1' and sd_cmd_crc_err='1') then
+ crc_err_reply <= '1';
+ end if;
+
+ -- Handle state transitions
+ case (card_state) is
+ when CARD_PRE_IDLE =>
+ -- BOOT_PARTITION_ENABLE bit in EXT_CSD would be checked here
+ -- but it is not currently supported, so just move on...
+ card_state <= CARD_IDLE;
+ -- IF BOOT_PARTITION_ENABLE were set, state would move to
+ -- CARD_PRE_BOOT.
+
+ when CARD_PRE_BOOT =>
+ -- If sd_cmd_i is held low for >74 clocks, or if CMD0 is
+ -- received with arg = 0xFFFFFFFA, then move to CARD_BOOT.
+ -- NOTE: CMD0 is implemented outside of the FSM case statement,
+ -- so be aware of that when implementing this special
+ -- CMD0 with arg = 0xFFFFFFFA.
+ -- but it is not currently supported, so just move on...
+ card_state <= CARD_IDLE;
+ -- If sd_cmd_i goes high in less than 74 clocks, or if
+ -- "normal" CMD0 or CMD1 is received, move to CARD_IDLE
+
+ when CARD_BOOT =>
+ -- sd_cmd_i going high, or CMD0 with arg = 0x00000000
+ -- moves to CARD_IDLE. Meanwhile, all the while this
+ -- state persists, continue sending boot data
+ card_state <= CARD_IDLE;
+
+ when CARD_IDLE =>
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0') then
+ -- Look for SEND_OP_COND (CMD1)
+ if (sd_cmd_index=1) then
+ -- Here, check the sd_cmd_arg to see if the voltage range is
+ -- compatible. If it is not, then go to CARD_INA (inactive)
+ -- state. For this module, it is "inconceivable" that the
+ -- requested voltage range would not be acceptable, so the
+ -- check is not being performed. But the reply is being given.
+ r3_start <= '1';
+ if (ocr_pwrup_done='1') then
+ card_state <= CARD_READY;
+ end if;
+ elsif (sd_cmd_neverbad='0') then
+ cmd_err_reply <= '1';
+ end if;
+ end if;
+ -- When the R3 reply is finished, set the ocr_pwrup_done bit, to show
+ -- that the card powerup status is no longer busy... this is
+ -- sketchy in the eMMC spec. The card can stay in CARD_IDLE when
+ -- it is busy. We do this once, to match behavior of real cards.
+ if (r3_done='1') then
+ ocr_pwrup_done <= '1';
+ end if;
+
+ when CARD_READY =>
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0') then
+ -- Look for ALL_SEND_CID (CMD2)
+ if (sd_cmd_index=2) then
+ -- Here, the idea in multi-card systems, is that each card sends
+ -- out its 136 bit reply containing the CID. All cards reply
+ -- simultaneously, using open-drain drivers. They are supposed
+ -- to monitor the state of the sd_cmd_i line while sending their
+ -- replies, to see if what they are seeing does not match what
+ -- they are sending out. If there is a mismatch, then the card
+ -- "loses" the bus, and goes to the CARD_INA (inactive) state.
+ --
+ -- This implementation does not do the check, since in this case
+ -- the assumption is made that there are no other cards present.
+ --
+ -- It's a pretty safe assumption, n'est-ce pas?
+ -- So, this module expects to always "win" the bus!
+ --
+ r2_cid_start <= '1';
+ card_state <= CARD_IDENT;
+ elsif (sd_cmd_neverbad='0') then
+ cmd_err_reply <= '1';
+ end if;
+ end if;
+
+ when CARD_IDENT =>
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0') then
+ -- Look for SET_RELATIVE_ADDR (CMD3)
+ if (sd_cmd_index=3) then
+ rca <= sd_cmd_arg(31 downto 16);
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_state <= CARD_STBY;
+ elsif (sd_cmd_neverbad='0') then
+ cmd_err_reply <= '1';
+ end if;
+ end if;
+
+ when CARD_STBY =>
+ -- Look for SET_DSR (CMD4), which has no reply
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=4) then
+ dsr <= sd_cmd_arg(31 downto 16);
+ end if;
+ -- Look for SLEEP_AWAKE (CMD5), which toggles between CARD_STBY and CARD_SLP
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=5) then
+ if sd_cmd_arg(15)='1' then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_state <= CARD_SLP;
+ end if;
+ end if;
+ -- Look for SELECT_CARD (CMD7)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=7) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_state <= CARD_TRAN;
+ end if;
+ -- Look for SEND_CSD (CMD9)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=9) then
+ r2_csd_start <= '1';
+ end if;
+ -- Look for SEND_CID (CMD10)
+ -- This is similar to CMD2, except only the addressed card responds...
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=10) then
+ r2_cid_start <= '1';
+ end if;
+ -- Look for SEND_STATUS (CMD13)
+ -- Per the spec, if a CRC error occurs, the card does not
+ -- respond. Therefore, the CRC error status bit is not
+ -- reported until an R1 response is given to a later command
+ -- that is received correctly.
+ -- Hence, CMD13 is only executed if there is no CRC error.
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=13) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ end if;
+ -- Look for GO_INACTIVE_STATE (CMD15), which has no reply
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=15) then
+ card_state <= CARD_INA;
+ end if;
+ -- Look for FAST_IO (CMD39)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=39) then
+ if (USE_R4_RESPONSE>0) then
+ r4_start <= '1';
+ r4_status <= sd_cmd_arg(15);
+ r4_reg_adr <= sd_cmd_arg(14 downto 8);
+ r4_reg_dat_wr <= sd_cmd_arg(7 downto 0);
+ if (sd_cmd_arg(15)='1') then
+ r4_reg_we <= '1';
+ end if;
+ end if;
+ end if;
+ -- Look for GO_IRQ_STATE (CMD40)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=40) then
+ if (USE_R5_RESPONSE>0) then
+ r5_start <= '1';
+ card_state <= CARD_IRQ;
+ end if;
+ end if;
+ -- Flag illegal commands
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_neverbad='0') then
+ if (sd_cmd_index/= 4 and sd_cmd_index/= 5 and sd_cmd_index/= 7 and
+ sd_cmd_index/= 9 and sd_cmd_index/=10 and sd_cmd_index/=13 and
+ sd_cmd_index/=39 and sd_cmd_index/=40) then
+ cmd_err_reply <= '1';
+ end if;
+ end if;
+
+ when CARD_TRAN =>
+ -- Look for SWITCH (CMD6)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=6) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ if (sd_cmd_arg(25 downto 24)=0) then
+ card_cmd_set <= sd_cmd_arg(2 downto 0);
+ else
+ -- Setting the cmd6_op non-zero performs a write to ext_csd
+ -- Different masking is done, based on the value
+ cmd6_op <= sd_cmd_arg(25 downto 24);
+ end if;
+ end if;
+ -- For CMD6, change states only when ext_csd processing is complete
+ -- In reality, only a few clock cycles are needed for the processing,
+ -- but it is convenient to simply wait for the response to finish.
+ if (sd_cmd_index=6) then
+ if (r1_done='1') then
+ --prg_dly_count <= to_unsigned(4000,prg_dly_count'length); -- Programming delay (card is busy!)
+ prg_dly_count <= to_unsigned(40,prg_dly_count'length); -- Programming delay (card is busy!)
+ card_state <= CARD_PRG;
+ -- "Operation Complete" returns from CARD_PRG back to CARD_TRAN.
+ -- prg_dly_count determines the length of the programming time.
+ -- The parts of the EXT_CSD that we really care about,
+ -- are being "shadowed" as registers here, so capture them
+ card_dbus_size <= ext_csd_sd_dat_rd(1 downto 0);
+ end if;
+ end if;
+ -- Look for DESELECT_CARD (CMD7 without address match), which has no reply
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='0' and sd_cmd_index=7) then
+ card_state <= CARD_STBY;
+ end if;
+ -- Look for SEND_EXT_CSD (CMD8)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=8) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ dreply_start_count <= to_unsigned(N_CD,D_BITS); -- Set the data readout delay counter
+ card_block_count <= to_unsigned(1,card_block_count'length);
+ card_state <= CARD_DATA;
+ end if;
+ -- Look for READ_DAT_UNTIL_STOP (CMD11)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=11) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_adr <= sd_cmd_arg;
+ dreply_start_count <= to_unsigned(N_CD,D_BITS); -- Set the data readout delay counter
+ card_state <= CARD_DATA;
+ end if;
+ -- Look for SEND_STATUS (CMD13)
+ -- Per the spec, if a CRC error occurs, the card does not
+ -- respond. Therefore, the CRC error status bit is not
+ -- reported until an R1 response is given to a later command
+ -- that is received correctly.
+ -- Hence, CMD13 is only executed if there is no CRC error.
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=13) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ end if;
+ -- Look for GO_INACTIVE_STATE (CMD15), which has no reply
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=15) then
+ card_state <= CARD_INA;
+ end if;
+ -- Look for SET_BLOCKLEN (CMD16)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=16) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_blocklen <= sd_cmd_arg(card_blocklen'length-1 downto 0);
+ end if;
+ -- Look for READ_SINGLE_BLOCK (CMD17)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=17) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_adr <= sd_cmd_arg;
+ card_block_count <= to_unsigned(1,card_block_count'length);
+ dreply_start_count <= to_unsigned(N_CD,D_BITS); -- Set the data readout delay counter
+ card_state <= CARD_DATA;
+ end if;
+ -- Look for READ_MULTIPLE_BLOCK (CMD18)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=18) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_adr <= sd_cmd_arg;
+ dreply_start_count <= to_unsigned(N_CD,D_BITS); -- Set the data readout delay counter
+ card_state <= CARD_DATA;
+ end if;
+ -- Look for BUSTEST_W (CMD19)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=19) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_bustest_w <= '1';
+ card_state <= CARD_BTST;
+ end if;
+ -- Look for WRITE_DAT_UNTIL_STOP (CMD20)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=20) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_adr <= sd_cmd_arg;
+ card_d_recv <= '1';
+ card_state <= CARD_RCV;
+ end if;
+ -- Look for SET_BLOCK_COUNT (CMD23)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=23) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_block_count <= sd_cmd_arg(15 downto 0);
+ card_rel_wr_req <= sd_cmd_arg(31);
+ end if;
+ -- Look for WRITE_BLOCK (CMD24)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=24) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_adr <= sd_cmd_arg;
+ card_block_count <= to_unsigned(1,card_block_count'length);
+ card_d_recv <= '1';
+ card_state <= CARD_RCV;
+ end if;
+ -- Look for WRITE_MULTIPLE_BLOCK (CMD25)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=25) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_adr <= sd_cmd_arg;
+ card_d_recv <= '1';
+ card_state <= CARD_RCV;
+ end if;
+ -- Look for PROGRAM_CSD (CMD27)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=27) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_state <= CARD_RCV;
+ end if;
+ -- Look for SET_WRITE_PROT (CMD28)
+ -- Currently there is no write protection in this emulated card.
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=28 and IMPLEMENT_WRITE_PROT>0) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ prg_dly_count <= to_unsigned(4000,prg_dly_count'length); -- Programming delay (card is busy!)
+ card_state <= CARD_PRG;
+ end if;
+ -- Look for CLR_WRITE_PROT (CMD29)
+ -- Currently there is no write protection in this emulated card.
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=29 and IMPLEMENT_WRITE_PROT>0) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ prg_dly_count <= to_unsigned(4000,prg_dly_count'length); -- Programming delay (card is busy!)
+ card_state <= CARD_PRG;
+ end if;
+ -- Look for SEND_WRITE_PROT (CMD30)
+ -- Currently there is no write protection in this emulated card.
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=30 and IMPLEMENT_WRITE_PROT>0) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_state <= CARD_DATA;
+ end if;
+ -- Look for SEND_WRITE_PROT_TYPE (CMD31)
+ -- Currently there is no write protection in this emulated card.
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=31 and IMPLEMENT_WRITE_PROT>0) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_state <= CARD_DATA;
+ end if;
+ -- Look for ERASE_GROUP_START (CMD35)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=35) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_erase_group_start <= sd_cmd_arg;
+ end if;
+ -- Look for ERASE_GROUP_END (CMD36)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=36) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_erase_group_end <= sd_cmd_arg;
+ end if;
+ -- Look for ERASE (CMD38)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=38) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ prg_dly_count <= to_unsigned(4000,prg_dly_count'length); -- Programming delay for erase (card is busy!)
+ card_state <= CARD_PRG;
+ end if;
+ -- Look for LOCK_UNLOCK (CMD42)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=42) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_state <= CARD_RCV;
+ end if;
+ -- Flag illegal commands
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_neverbad='0') then
+ if (sd_cmd_index< 6 or sd_cmd_index= 9 or sd_cmd_index=10 or
+ sd_cmd_index=12 or sd_cmd_index=14 or sd_cmd_index=21 or
+ sd_cmd_index=22 or sd_cmd_index=26 or sd_cmd_index=32 or
+ sd_cmd_index=33 or sd_cmd_index=34 or sd_cmd_index=37 or
+ sd_cmd_index=39 or sd_cmd_index=40 or sd_cmd_index=41 or
+ sd_cmd_index>42) then
+ cmd_err_reply <= '1';
+ end if;
+ end if;
+
+ when CARD_DATA =>
+ -- Look for DESELECT_CARD (CMD7 without address match), which has no reply
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='0' and sd_cmd_index=7) then
+ card_state <= CARD_STBY;
+ end if;
+ -- Look for STOP_TRANSMISSION (CMD12)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=12) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_d_stop <= '1';
+ card_block_count <= to_unsigned(0,card_block_count'length);
+ card_state <= CARD_TRAN;
+ end if;
+ -- Look for SEND_STATUS (CMD13)
+ -- Per the spec, if a CRC error occurs, the card does not
+ -- respond. Therefore, the CRC error status bit is not
+ -- reported until an R1 response is given to a later command
+ -- that is received correctly.
+ -- Hence, CMD13 is only executed if there is no CRC error.
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=13) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ end if;
+ -- Look for GO_INACTIVE_STATE (CMD15), which has no reply
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=15) then
+ card_state <= CARD_INA;
+ end if;
+ -- Flag illegal commands
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_neverbad='0') then
+ if (sd_cmd_index/= 7 and sd_cmd_index/=12 and sd_cmd_index/=13) then
+ cmd_err_reply <= '1';
+ end if;
+ end if;
+ -- check for various "operation complete" conditions
+ if (card_d_busy='0' and card_d_busy_r1='1') then -- falling edge
+ -- For completion of CMD8 (SEND_EXT_CSD), change states
+ -- Change states for CMD8, CMD11, CMD17, CMD18, CMD30 or CMD56(read).
+ -- To make this easy, do not filter on the command index, just
+ -- make the transition, assuming that the data transaction which
+ -- just ended resulted from one of the listed commands.
+ --if (sd_cmd_index=8) then
+ card_block_count <= to_unsigned(0,card_block_count'length);
+ card_state <= CARD_TRAN;
+ --end if;
+ end if;
+
+ when CARD_BTST =>
+ -- Look for SEND_STATUS (CMD13)
+ -- Per the spec, if a CRC error occurs, the card does not
+ -- respond. Therefore, the CRC error status bit is not
+ -- reported until an R1 response is given to a later command
+ -- that is received correctly.
+ -- Hence, CMD13 is only executed if there is no CRC error.
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=13) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ end if;
+ -- Look for BUSTEST_R (CMD14)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=14) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ dreply_start_count <= to_unsigned(N_CD,D_BITS); -- Set the data readout delay counter
+ card_state <= CARD_TRAN;
+ end if;
+ -- Look for GO_INACTIVE_STATE (CMD15), which has no reply
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=15) then
+ card_state <= CARD_INA;
+ end if;
+ -- Flag illegal commands
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_neverbad='0') then
+ if (sd_cmd_index/=13 and sd_cmd_index/=14) then
+ cmd_err_reply <= '1';
+ end if;
+ end if;
+
+ when CARD_RCV =>
+ -- Look for STOP_TRANSMISSION (CMD12)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=12) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_d_stop <= '1';
+ card_block_count <= to_unsigned(0,card_block_count'length);
+ card_state <= CARD_PRG; -- sd_card_data_unit handles busy indication for this case.
+ end if;
+ -- Check for various "operation complete" conditions
+ if (card_d_busy='0' and card_d_busy_r1='1') then -- falling edge
+ -- Change states for CMD24, CMD25, CMD26, CMD27, CMD42 or CMD56(write).
+ -- To make this easy, do not filter on the command index, just
+ -- make the transition, assuming that the data transaction which
+ -- just ended resulted from one of the listed commands.
+ card_block_count <= to_unsigned(0,card_block_count'length);
+ card_state <= CARD_PRG; -- sd_card_data_unit handles busy indication for this case.
+ end if;
+ -- Look for SEND_STATUS (CMD13)
+ -- Per the spec, if a CRC error occurs, the card does not
+ -- respond. Therefore, the CRC error status bit is not
+ -- reported until an R1 response is given to a later command
+ -- that is received correctly.
+ -- Hence, CMD13 is only executed if there is no CRC error.
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=13) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ end if;
+ -- Look for GO_INACTIVE_STATE (CMD15), which has no reply
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=15) then
+ card_state <= CARD_INA;
+ end if;
+ -- Flag illegal commands
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_neverbad='0') then
+ if (sd_cmd_index/=12 and sd_cmd_index/=13) then
+ cmd_err_reply <= '1';
+ end if;
+ end if;
+
+ -- Within this state, use card_cmd_arg directly for command input, including the address.
+ when CARD_PRG =>
+ -- Look for DESELECT_CARD (CMD7 without address match), which has no reply
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='0' and sd_cmd_index=7) then
+ card_state <= CARD_DIS;
+ end if;
+ -- Look for SEND_STATUS (CMD13)
+ -- Per the spec, if a CRC error occurs, the card does not
+ -- respond. Therefore, the CRC error status bit is not
+ -- reported until an R1 response is given to a later command
+ -- that is received correctly.
+ -- Hence, CMD13 is only executed if there is no CRC error.
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=13) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ end if;
+ -- If the programming timer expires, then consider that the programming
+ -- operation is complete. Return to CARD_TRAN state. In a real card, this
+ -- CARD_PRG state would be actual flash programming time, but in our emulated
+ -- card, the programming time is merely emulated.
+ -- Delay, with accompanying card busy indication, is implemented explicitly
+ -- here, by prg_dly_count, for:
+ -- CMD6, CMD28, CMD29 and CMD38.
+ -- A signal from sd_card_data_unit, controls the assertion of the card
+ -- busy indicator during CARD_RCV state.
+ if (prg_dly_count=0) then
+ card_state <= CARD_TRAN;
+ end if;
+ -- Look for GO_INACTIVE_STATE (CMD15), which has no reply
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=15) then
+ prg_dly_count <= (others=>'0');
+ card_state <= CARD_INA;
+ end if;
+ -- A host should not issue this while busy is active and card is in this state
+ -- Look for WRITE_BLOCK (CMD24)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=24) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ prg_dly_count <= (others=>'0');
+ card_state <= CARD_RCV;
+ card_adr <= sd_cmd_arg;
+ end if;
+ -- A host should not issue this while busy is active and card is in this state
+ -- Look for WRITE_MULTIPLE_BLOCK (CMD25)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=25) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ prg_dly_count <= (others=>'0');
+ card_state <= CARD_RCV;
+ card_adr <= sd_cmd_arg;
+ end if;
+ -- Flag illegal commands
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_neverbad='0') then
+ if (sd_cmd_index/= 7 and sd_cmd_index/=13 and
+ sd_cmd_index/=24 and sd_cmd_index/=25) then
+ cmd_err_reply <= '1';
+ end if;
+ end if;
+
+ when CARD_DIS =>
+ -- Look for SELECT_CARD (CMD7)
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=7) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ prg_dly_count <= to_unsigned(4000,prg_dly_count'length);
+ card_state <= CARD_PRG;
+ end if;
+ -- Look for SEND_STATUS (CMD13)
+ -- Per the spec, if a CRC error occurs, the card does not
+ -- respond. Therefore, the CRC error status bit is not
+ -- reported until an R1 response is given to a later command
+ -- that is received correctly.
+ -- Hence, CMD13 is only executed if there is no CRC error.
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=13) then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ end if;
+ -- Look for GO_INACTIVE_STATE (CMD15), which has no reply
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=15) then
+ card_state <= CARD_INA;
+ end if;
+ -- Flag illegal commands
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_neverbad='0') then
+ if (sd_cmd_index/= 7 and sd_cmd_index/=13) then
+ cmd_err_reply <= '1';
+ end if;
+ end if;
+
+ when CARD_INA =>
+ -- This state is pretty much a "dead end"
+ -- Only reset can get out of it.
+ null;
+
+ when CARD_SLP =>
+ -- Look for SLEEP_AWAKE (CMD5), which toggles between CARD_STBY and CARD_SLP
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_adr_match='1' and sd_cmd_index=5) then
+ if sd_cmd_arg(15)='0' then
+ r1_start <= '1';
+ card_state_reply <= card_state;
+ card_state <= CARD_STBY;
+ end if;
+ end if;
+ -- Flag illegal commands
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0') then
+ if (sd_cmd_index/= 0 and sd_cmd_index/= 5) then
+ cmd_err_reply <= '1';
+ end if;
+ end if;
+
+ when CARD_IRQ =>
+ -- In reality, there is supposed to be some IRQ event which occurs
+ -- before the R5 response is given. No such events are implemented
+ -- in this card, but if they were, it would be cool to just reset a
+ -- timer or counter, in the manner of kicking a watchdog timer, until
+ -- the event trigger occurs, then issue the r5_start pulse.
+ -- The host has a mechanism for generating a "pseudo reply" at RCA
+ -- of 0x0000, which is supposed to cause this state to exit.
+ --
+ -- "Any start bit on the bus" exits this state
+ -- The method used here is to wait for the command to finish
+ -- being received, instead of actually looking for the start
+ -- bit...
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0') then
+ if (sd_cmd_index/=55) then
+ card_state <= CARD_STBY;
+ end if;
+ end if;
+
+ when others =>
+ card_state <= CARD_IDLE;
+ end case;
+ -- CMD0 affects nearly all states the same way, so it is coded here.
+ if (sd_cmd_done='1' and sd_cmd_crc_err='0' and sd_cmd_index=0) then
+ if (card_state/=CARD_INA and card_state/=CARD_IRQ) then
+ ocr_pwrup_done <= '0';
+ card_dbus_size <= "00"; -- Revert back to single data bit
+ rca <= str2u("0001",16);
+ dsr <= str2u("0404",16);
+ card_cmd_set <= (others=>'0');
+ if (sd_cmd_arg=0) then
+ card_state <= CARD_IDLE;
+ else
+ card_state <= CARD_PRE_IDLE;
+ end if;
+ end if;
+ end if;
+ end if; -- sd_clk_i
+end process;
+
+--------------------------------------------
+-- Response Transmitters
+
+ R1_responder: sd_card_responder
+ generic map(
+ N_CR => N_CR,
+ RESP_PYLD_LEN => 32,
+ CRC_OFFSET => 0, -- Start CRC calculation after this many bits
+ CRC_SEND_ONES => 0
+ )
+ port map(
+ -- Asynchronous reset
+ sys_rst_n => sys_rst_n,
+ -- SD/MMC card command signals
+ sd_clk_i => sd_clk_i,
+ sd_cmd_o => r1_cmd,
+ sd_cmd_oe_o => r1_cmd_oe,
+ -- Response inputs
+ resp_index_i => sd_cmd_index,
+ resp_pyld_i => reported_status,
+ respond_i => r1_start,
+ -- Status and done indicator
+ done_o => r1_done, -- A one clock long pulse
+ busy_o => open
+ );
+ -- Create a status report. Some fields are read only.
+ reported_status(31 downto 24) <= status(31 downto 24);
+ reported_status(23) <= crc_err_reply;
+ reported_status(22) <= cmd_err_reply;
+ reported_status(21 downto 13) <= status(21 downto 13);
+ with card_state_reply select
+ reported_status(12 downto 9) <=
+ "0000" when CARD_IDLE,
+ "0001" when CARD_READY,
+ "0010" when CARD_IDENT,
+ "0011" when CARD_STBY,
+ "0100" when CARD_TRAN,
+ "0101" when CARD_DATA,
+ "0110" when CARD_RCV,
+ "0111" when CARD_PRG,
+ "1000" when CARD_DIS,
+ "1001" when CARD_BTST,
+ "1010" when CARD_SLP,
+ "1011" when others;
+ reported_status(8) <= '1'; -- Buffers are empty!
+ reported_status(7 downto 0) <= status(7 downto 0);
+
+ R2_CID_responder: sd_card_responder
+ generic map(
+ N_CR => N_CR,
+ RESP_PYLD_LEN => 120,
+ CRC_OFFSET => 8, -- Start CRC calculation after this many bits
+ CRC_SEND_ONES => 0
+ )
+ port map(
+ -- Asynchronous reset
+ sys_rst_n => sys_rst_n,
+ -- SD/MMC card command signals
+ sd_clk_i => sd_clk_i,
+ sd_cmd_o => r2_cid_cmd,
+ sd_cmd_oe_o => r2_cid_cmd_oe,
+ -- Response inputs
+ resp_index_i => "111111",
+ resp_pyld_i => cid_resp,
+ respond_i => r2_cid_start,
+ -- Status and done indicator
+ done_o => r2_cid_done, -- A one clock long pulse
+ busy_o => open
+ );
+
+ R2_CSD_responder: sd_card_responder
+ generic map(
+ N_CR => N_CR,
+ RESP_PYLD_LEN => 120,
+ CRC_OFFSET => 8, -- Start CRC calculation after this many bits
+ CRC_SEND_ONES => 0
+ )
+ port map(
+ -- Asynchronous reset
+ sys_rst_n => sys_rst_n,
+ -- SD/MMC card command signals
+ sd_clk_i => sd_clk_i,
+ sd_cmd_o => r2_csd_cmd,
+ sd_cmd_oe_o => r2_csd_cmd_oe,
+ -- Response inputs
+ resp_index_i => "111111",
+ resp_pyld_i => csd_resp,
+ respond_i => r2_csd_start,
+ -- Status and done indicator
+ done_o => r2_csd_done, -- A one clock long pulse
+ busy_o => open
+ );
+
+ R3_responder: sd_card_responder
+ generic map(
+ N_CR => N_ID,
+ RESP_PYLD_LEN => 32,
+ CRC_OFFSET => 0, -- Start CRC calculation after this many bits
+ CRC_SEND_ONES => 1
+ )
+ port map(
+ -- Asynchronous reset
+ sys_rst_n => sys_rst_n,
+ -- SD/MMC card command signals
+ sd_clk_i => sd_clk_i,
+ sd_cmd_o => r3_cmd,
+ sd_cmd_oe_o => r3_cmd_oe,
+ -- Response inputs
+ resp_index_i => "111111",
+ resp_pyld_i => ocr,
+ respond_i => r3_start,
+ -- Status and done indicator
+ done_o => r3_done, -- A one clock long pulse
+ busy_o => open
+ );
+
+ R4_responder: sd_card_responder
+ generic map(
+ N_CR => N_CR,
+ RESP_PYLD_LEN => 32,
+ CRC_OFFSET => 0, -- Start CRC calculation after this many bits
+ CRC_SEND_ONES => 0
+ )
+ port map(
+ -- Asynchronous reset
+ sys_rst_n => sys_rst_n,
+ -- SD/MMC card command signals
+ sd_clk_i => sd_clk_i,
+ sd_cmd_o => r4_cmd,
+ sd_cmd_oe_o => r4_cmd_oe,
+ -- Response inputs
+ resp_index_i => "100111",
+ resp_pyld_i => fast_io_reg_rd,
+ respond_i => r4_start,
+ -- Status and done indicator
+ done_o => r4_done, -- A one clock long pulse
+ busy_o => open
+ );
+ -- Assign response for R4
+ fast_io_reg_rd <= rca & r4_status & r4_reg_adr & r4_reg_dat_rd;
+
+ -- An interesting idea : Add a CMD39 "R4" register read/write bus port
+ -- to the top level of this module, if this function of reading and
+ -- writing special registers becomes important and/or useful enough
+ -- to justify the effort.
+
+ -- CMD39 "FAST_IO" register read mux
+ with to_integer(r4_reg_adr) select
+ r4_reg_dat_rd <=
+ r4_reg_0 when 0,
+ r4_reg_1 when 1,
+ "10100101" when others;
+
+ -- CMD39 "FAST_IO" register writes are handled here
+ reg_proc: process(sd_clk_i, sys_rst_n)
+ begin
+ if (sys_rst_n='0') then
+ r4_reg_0 <= (others=>'0');
+ r4_reg_1 <= (others=>'0');
+ elsif (sd_clk_i'event and sd_clk_i='1') then
+ if (r4_reg_we='1') then
+ case to_integer(adr_i) is
+ when 0 =>
+ r4_reg_0 <= r4_reg_dat_wr;
+ when 1 =>
+ r4_reg_1 <= r4_reg_dat_wr;
+ when others => null;
+ end case;
+ end if;
+ end if; -- sd_clk_i
+ end process;
+
+
+ R5_responder: sd_card_responder
+ generic map(
+ N_CR => N_CR,
+ RESP_PYLD_LEN => 32,
+ CRC_OFFSET => 0, -- Start CRC calculation after this many bits
+ CRC_SEND_ONES => 0
+ )
+ port map(
+ -- Asynchronous reset
+ sys_rst_n => sys_rst_n,
+ -- SD/MMC card command signals
+ sd_clk_i => sd_clk_i,
+ sd_cmd_o => r5_cmd,
+ sd_cmd_oe_o => r5_cmd_oe,
+ -- Response inputs
+ resp_index_i => "101000",
+ resp_pyld_i => irq_response,
+ respond_i => r5_start,
+ -- Status and done indicator
+ done_o => r5_done, -- A one clock long pulse
+ busy_o => open
+ );
+ -- Assign response for R5
+ irq_response <= rca & to_unsigned(0,16);
+
+-- Select which response gets driven out
+sd_cmd_o <= r1_cmd when r1_cmd_oe='1' else
+ r2_cid_cmd when r2_cid_cmd_oe='1' else
+ r2_csd_cmd when r2_csd_cmd_oe='1' else
+ r3_cmd when r3_cmd_oe='1' else
+ r4_cmd when r4_cmd_oe='1' and USE_R4_RESPONSE>0 else
+ r5_cmd when r5_cmd_oe='1' and USE_R5_RESPONSE>0 else
+ '1';
+
+ -- NOTE: If multiple responders are active at the same time, then
+ -- the drive signal may not be correct, so don't do that!
+sd_cmd_oe_l <= '1' when r1_cmd_oe='1' or r2_cid_cmd_oe='1' or
+ r2_csd_cmd_oe='1' or r3_cmd_oe='1' or
+ (r4_cmd_oe='1' and USE_R4_RESPONSE>0) or
+ (r5_cmd_oe='1' and USE_R5_RESPONSE>0) else
+ '0';
+sd_cmd_oe_o <= sd_cmd_oe_l;
+
+sd_od_mode_o <= '1' when card_state=CARD_INA or card_state=CARD_PRE_IDLE or
+ card_state=CARD_PRE_BOOT or card_state=CARD_IDLE or
+ card_state=CARD_READY or card_state=CARD_IDENT or
+ card_state=CARD_IRQ else '0';
+
+-- SD/MMC data handling unit
+ sd_card_d_handler : sd_card_data_unit
+ generic map(
+ BLK_PRG_TIME => 200, -- Number of clocks to program a sector in FLASH (emulated)
+ BLKSIZE_W => card_blocklen'length,
+ BLKCNT_W => card_block_count'length
+ )
+ port map(
+ sd_clk_i => sd_clk_i,
+ sys_rst_n => sys_rst_n,
+ --Tx Fifo
+ tx_dat_i => card_tx_dat,
+ tx_dat_rd_o => card_tx_dat_rd,
+ --Rx Fifo
+ rx_dat_o => buf_dat_o,
+ rx_dat_we_o => buf_dat_we_l,
+ --SD data
+ sd_dat_i => sd_dat_i,
+ sd_dat_o => sd_dat_unbusy,
+ sd_dat_oe_o => sd_dat_oe_unbusy,
+ --Control signals
+ blksize_i => card_blocklen,
+ bus_size_i => card_dbus_size,
+ blkcnt_i => card_block_count,
+ continuous_i => card_d_continuous,
+ d_stop_i => card_d_stop,
+ d_read_i => card_d_recv,
+ d_write_i => card_d_send,
+ bustest_w_i => card_bustest_w, -- Receives bustest pattern
+ bustest_r_i => card_bustest_r, -- Sends bustest pattern out
+ sd_dat_busy_o => card_sd_dat_busy,
+ fsm_busy_o => card_d_busy,
+ crc_ok_o => card_d_crc_ok
+ );
+
+-- Indicate when the card is busy, based on state of this state machine,
+-- and the state in sd_card_data_unit. The output enable signal is also
+-- controlled, to ensure that the busy indicator is asserted.
+sd_dat_o <= (sd_dat_unbusy and "11111110") when card_sd_dat_busy='1' or (card_state=CARD_PRG and prg_dly_count>0) else sd_dat_unbusy;
+sd_dat_oe_o <= '1' when card_state=CARD_PRG and prg_dly_count>0 else sd_dat_oe_unbusy;
+
+-- Provide special override for bus size, when BUSTEST is being used.
+sd_dat_siz_o <= "10" when sd_cmd_index=14 else card_dbus_size; -- Drive entire bus for BUSTEST_R response
+
+-- Provide write enable output for data buffers
+buf_dat_we_o <= buf_dat_we_l;
+
+-- Provide address to be used for steering data to and from
+-- the correct FIFO buffers.
+ adr_offset_proc: process(sd_clk_i, sys_rst_n)
+ begin
+ if (sys_rst_n='0') then
+ adr_offset <= (others=>'0');
+ elsif (sd_clk_i'event and sd_clk_i='1') then
+ if (buf_dat_we_l='1' or (card_tx_dat_rd='1' and sd_cmd_index/=8)) then -- Do not increment for CMD8 (EXT_CSD_READ)
+ adr_offset <= adr_offset+1;
+ end if;
+ if (card_d_recv='1' or card_d_send='1') then
+ adr_offset <= (others=>'0');
+ end if;
+ end if; -- sd_clk_i
+ end process;
+
+buf_adr_o <= card_adr(buf_adr_o'length-1 downto 0) + adr_offset;
+
+-- Select which data source is transmitted.
+card_tx_dat <= ext_csd_sd_dat_rd when sd_cmd_index=8 else buf_dat_i; -- CMD8 returns EXT_CSD as data...
+buf_dat_rd_o <= '0' when sd_cmd_index=8 else card_tx_dat_rd;
+
+-- Indicate to sd_card_data_unit when continous data transfer is needed
+card_d_continuous <= '1' when (sd_cmd_index=11 or sd_cmd_index=20) else '0';
+-- Start a transmit operation, when needed
+card_d_send <= '1' when (sd_cmd_index=8 or sd_cmd_index=11 or sd_cmd_index=17 or sd_cmd_index=18) and dreply_start_count=1 else '0';
+-- Start sending bustest response data, when needed
+card_bustest_r <= '1' when sd_cmd_index=14 and dreply_start_count=1 else '0';
+
+end beh;
+
+-------------------------------------------------------------------------------
+-- MMC Data Pipe
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Update: May 12, 2016 Wrote description and assembled the needed modules
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This module is meant to emulate an SD/MMC card, but instead of having a
+-- vast FLASH based storage array, it provides a simple set of data FIFOs
+-- and a small RAM.
+--
+-- MMC sectors of 512 bytes are mapped into the RAM. These are the lowest
+-- addresses of the card address space. All addresses higher than the end
+-- of the RAM block are mapped to the FIFOs. Data written to the card ends
+-- up in one FIFO, while data read from the card is taken from the other FIFO.
+--
+-- The unit is currently set up to use MMC byte addressing mode. Sector
+-- addressing could also be enabled if desired. Just set the EXT_CSD correctly,
+-- and then change the generic OCR_USE_SECTOR_MODE to a nonzero value on the
+-- sd_card_emulator unit.
+--
+-- Note that the FIFOs are "clock domain crossing" type. The thing to remember
+-- with them is that the fifo empty, full and fill_level status is not
+-- synchronized to the local clock domain. The user is free to perform that
+-- synchronization or not, as desired, and incur the additional delay that it
+-- brings, or not.
+--
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.fifo_pack.all;
+use work.convert_pack.all;
+use work.sd_card_pack.all;
+use work.block_ram_pack.all;
+
+ entity mmc_data_pipe is
+ generic (
+ EXT_CSD_INIT_FILE : string := "ext_csd_init.txt"; -- Initial contents of EXT_CSD
+ FIFO_DEPTH : integer := 2048;
+ FILL_LEVEL_BITS : integer := 12; -- Should be at least int(floor(log2(FIFO_DEPTH))+1.0)
+ RAM_ADR_WIDTH : integer := 14 -- 16 Kilobytes
+ );
+ port (
+
+ -- Asynchronous reset
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+
+ -- Bus interface
+ adr_i : in unsigned(3 downto 0);
+ sel_i : in std_logic;
+ we_i : in std_logic;
+ dat_i : in unsigned(31 downto 0);
+ dat_o : out unsigned(31 downto 0);
+ ack_o : out std_logic;
+
+ -- SD/MMC card signals
+ mmc_clk_i : in std_logic;
+ mmc_cmd_i : in std_logic;
+ mmc_cmd_o : out std_logic;
+ mmc_cmd_oe_o : out std_logic;
+ mmc_od_mode_o : out std_logic; -- Open drain mode
+ mmc_dat_i : in unsigned(7 downto 0);
+ mmc_dat_o : out unsigned(7 downto 0);
+ mmc_dat_oe_o : out std_logic;
+ mmc_dat_siz_o : out unsigned(1 downto 0);
+
+ -- Data Pipe FIFOs
+ wr_clk_i : in std_logic;
+ wr_clk_en_i : in std_logic;
+ wr_reset_i : in std_logic; -- Synchronous
+ wr_en_i : in std_logic;
+ wr_dat_i : in unsigned(7 downto 0);
+ wr_fifo_level : out unsigned(FILL_LEVEL_BITS-1 downto 0);
+ wr_fifo_full : out std_logic;
+ wr_fifo_empty : out std_logic;
+
+ rd_clk_i : in std_logic;
+ rd_clk_en_i : in std_logic;
+ rd_reset_i : in std_logic; -- Synchronous
+ rd_en_i : in std_logic;
+ rd_dat_o : out unsigned(7 downto 0);
+ rd_fifo_level : out unsigned(FILL_LEVEL_BITS-1 downto 0);
+ rd_fifo_full : out std_logic;
+ rd_fifo_empty : out std_logic;
+
+ -- Data Pipe RAM
+ ram_clk_i : in std_logic;
+ ram_clk_en_i : in std_logic;
+ ram_adr_i : in unsigned(RAM_ADR_WIDTH-1 downto 0);
+ ram_we_i : in std_logic;
+ ram_dat_i : in unsigned(7 downto 0);
+ ram_dat_o : out unsigned(7 downto 0)
+ );
+ end mmc_data_pipe;
+
+architecture beh of mmc_data_pipe is
+
+-- constants
+constant N_ID : integer := 5; -- Number of clocks before response in card ID mode
+
+-- signals
+signal buf_adr : unsigned(31 downto 0);
+signal buf_dat_from_host : unsigned(7 downto 0);
+signal buf_dat_we : std_logic;
+signal buf_dat_to_host : unsigned(7 downto 0);
+signal buf_dat_rd : std_logic;
+signal fifo_dat_rd : std_logic;
+signal fifo_dat_to_host : unsigned(7 downto 0);
+signal ram_dat_to_host : unsigned(7 downto 0);
+signal fifo_we : std_logic;
+signal ram_we : std_logic;
+
+begin
+
+-- Instantiate the MMC
+mmc_1 : sd_card_emulator
+ generic map(
+ USE_R4_RESPONSE => 0, -- Fast I/O read/write (app specific)
+ USE_R5_RESPONSE => 0, -- Interrupt Request Mode
+ EXT_CSD_INIT_FILE => EXT_CSD_INIT_FILE, -- Initial contents of EXT_CSD
+ OCR_USE_DUAL_VOLTAGE => 0,
+ OCR_USE_SECTOR_MODE => 0,
+ CID_MID => str2u("45",8), -- Manufacturer ID
+ CID_OID => str2u("77",8), -- OEM ID
+ CID_CBX => "00", -- 0=Card, 1=BGA, 2=Package On Package
+ CID_PNM => str2u("434152444953",48), -- Product Name, 6 ASCII chars
+ CID_PRV => str2u("01",8), -- Product Rev (2 BCD digits, e.g. 6.2=0x62)
+ CID_PSN => str2u("00000012",32), -- Product serial number
+ CID_MDT => str2u("43",8), -- Manufacture Date (Jan=1, 1997=0, e.g. Apr. 2000=0x43)
+ DEF_STAT => str2u("00000000",32), -- Read Write, R_0
+ CSD_WORD_3 => str2u("905E002A",32), -- See MMC spec
+ CSD_WORD_2 => str2u("1F5903D3",32), -- See MMC spec
+ CSD_WORD_1 => str2u("EDB707FF",32), -- See MMC spec
+ CSD_WORD_0 => str2u("96400000",32), -- See MMC spec, bits (7:0) not used
+ DEF_R_Z => str2u("33333333",32) -- Value returned for nonexistent registers
+ )
+ port map(
+
+ -- Asynchronous reset
+ sys_rst_n => sys_rst_n,
+ sys_clk => sys_clk,
+
+ -- Bus interface
+ adr_i => adr_i,
+ sel_i => sel_i,
+ we_i => we_i,
+ dat_i => dat_i,
+ dat_o => dat_o,
+ ack_o => ack_o,
+
+ -- SD/MMC card command signals
+ sd_clk_i => mmc_clk_i,
+ sd_cmd_i => mmc_cmd_i,
+ sd_cmd_o => mmc_cmd_o,
+ sd_cmd_oe_o => mmc_cmd_oe_o,
+ sd_od_mode_o => mmc_od_mode_o, -- Open drain mode
+ sd_dat_i => mmc_dat_i,
+ sd_dat_o => mmc_dat_o,
+ sd_dat_oe_o => mmc_dat_oe_o,
+ sd_dat_siz_o => mmc_dat_siz_o,
+
+ -- Data FIFO interface
+ buf_adr_o => buf_adr,
+ buf_dat_o => buf_dat_from_host,
+ buf_dat_we_o => buf_dat_we,
+ buf_dat_i => buf_dat_to_host,
+ buf_dat_rd_o => buf_dat_rd -- Used by FIFOs only.
+ );
+ -- Select the appropriate data to return to the host
+ buf_dat_to_host <= ram_dat_to_host when buf_adr(buf_adr'length-1 downto RAM_ADR_WIDTH)=0 else fifo_dat_to_host;
+
+-- Instantiate the FIFOs
+ fifo_from_mmc : swiss_army_fifo_cdc
+ generic map(
+ USE_BRAM => 1, -- Set to nonzero value for BRAM, zero for distributed RAM
+ WIDTH => 8,
+ DEPTH => FIFO_DEPTH,
+ FILL_LEVEL_BITS => FILL_LEVEL_BITS, -- Should be at least int(floor(log2(DEPTH))+1.0)
+ PF_FULL_POINT => FIFO_DEPTH-1,
+ PF_FLAG_POINT => 512,
+ PF_EMPTY_POINT => 1
+ )
+ port map(
+ sys_rst_n => sys_rst_n, -- Asynchronous
+
+ wr_clk_i => mmc_clk_i,
+ wr_clk_en_i => '1',
+ wr_reset_i => '0', -- Synchronous
+ wr_en_i => fifo_we,
+ wr_dat_i => buf_dat_from_host,
+ wr_fifo_level => open,
+ wr_fifo_full => open,
+ wr_fifo_empty => open,
+ wr_fifo_pf_full => open,
+ wr_fifo_pf_flag => open,
+ wr_fifo_pf_empty => open,
+
+ rd_clk_i => rd_clk_i,
+ rd_clk_en_i => rd_clk_en_i,
+ rd_reset_i => rd_reset_i, -- Synchronous
+ rd_en_i => rd_en_i,
+ rd_dat_o => rd_dat_o,
+ rd_fifo_level => rd_fifo_level,
+ rd_fifo_full => rd_fifo_full,
+ rd_fifo_empty => rd_fifo_empty,
+ rd_fifo_pf_full => open,
+ rd_fifo_pf_flag => open,
+ rd_fifo_pf_empty => open
+
+ );
+ fifo_we <= '1' when buf_dat_we='1' and buf_adr(buf_adr'length-1 downto RAM_ADR_WIDTH)>0 else '0';
+
+ fifo_to_mmc : swiss_army_fifo_cdc
+ generic map(
+ USE_BRAM => 1, -- Set to nonzero value for BRAM, zero for distributed RAM
+ WIDTH => 8,
+ DEPTH => FIFO_DEPTH,
+ FILL_LEVEL_BITS => FILL_LEVEL_BITS, -- Should be at least int(floor(log2(DEPTH))+1.0)
+ PF_FULL_POINT => FIFO_DEPTH-1,
+ PF_FLAG_POINT => 512,
+ PF_EMPTY_POINT => 1
+ )
+ port map(
+ sys_rst_n => sys_rst_n, -- Asynchronous
+
+ wr_clk_i => wr_clk_i,
+ wr_clk_en_i => wr_clk_en_i,
+ wr_reset_i => wr_reset_i, -- Synchronous
+ wr_en_i => wr_en_i,
+ wr_dat_i => wr_dat_i,
+ wr_fifo_level => wr_fifo_level,
+ wr_fifo_full => wr_fifo_full,
+ wr_fifo_empty => wr_fifo_empty,
+ wr_fifo_pf_full => open,
+ wr_fifo_pf_flag => open,
+ wr_fifo_pf_empty => open,
+
+ rd_clk_i => mmc_clk_i,
+ rd_clk_en_i => '1',
+ rd_reset_i => '0', -- Synchronous
+ rd_en_i => fifo_dat_rd,
+ rd_dat_o => fifo_dat_to_host,
+ rd_fifo_level => open,
+ rd_fifo_full => open,
+ rd_fifo_empty => open,
+ rd_fifo_pf_full => open,
+ rd_fifo_pf_flag => open,
+ rd_fifo_pf_empty => open
+ );
+ fifo_dat_rd <= '1' when buf_dat_rd='1' and buf_adr(buf_adr'length-1 downto RAM_ADR_WIDTH)>0 else '0';
+
+-- Instantiate the RAM block
+-- Port A is the MMC side.
+-- Port B is the user side.
+ pipe_ram : swiss_army_ram
+ generic map(
+ USE_BRAM => 1,
+ WRITETHRU => 0, -- Set to nonzero value for writethrough mode
+ USE_FILE => 0, -- Set to nonzero value to use INIT_FILE
+ INIT_VAL => 18,
+ INIT_SEL => 0, -- No generate loop here
+ INIT_FILE => ".\foo.txt", -- ASCII hexadecimal initialization file name
+ FIL_WIDTH => 32, -- Bit width of init file lines
+ ADR_WIDTH => RAM_ADR_WIDTH,
+ DAT_WIDTH => 8
+ )
+ port map (
+ clk_a => mmc_clk_i,
+ clk_b => ram_clk_i,
+
+ adr_a_i => buf_adr(RAM_ADR_WIDTH-1 downto 0),
+ adr_b_i => ram_adr_i,
+
+ we_a_i => ram_we,
+ en_a_i => '1',
+ dat_a_i => buf_dat_from_host,
+ dat_a_o => ram_dat_to_host,
+
+ we_b_i => ram_we_i,
+ en_b_i => ram_clk_en_i,
+ dat_b_i => ram_dat_i,
+ dat_b_o => ram_dat_o
+ );
+ ram_we <= '1' when buf_dat_we='1' and buf_adr(buf_adr'length-1 downto RAM_ADR_WIDTH)=0 else '0';
+
+end beh;
+
Index: sd_card_controller/trunk/rtl/VHDL/ucrc_pack.vhd
===================================================================
--- sd_card_controller/trunk/rtl/VHDL/ucrc_pack.vhd (nonexistent)
+++ sd_card_controller/trunk/rtl/VHDL/ucrc_pack.vhd (revision 14)
@@ -0,0 +1,426 @@
+--------------------------------------------------------------------------
+-- Package
+--
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+package ucrc_pack is
+
+ component ucrc_ser
+ generic (
+ POLYNOMIAL : unsigned; -- 4 to 32 bits
+ INIT_VALUE : unsigned
+ );
+ port (
+ -- System clock and asynchronous reset
+ sys_clk : in std_logic; -- clock
+ sys_rst_n : in std_logic; -- asynchronous reset
+ sys_clk_en : in std_logic; -- clock enable
+
+ -- Input and Control
+ clear_i : in std_logic; -- synchronous reset
+ data_i : in std_logic; -- data input
+ flush_i : in std_logic; -- flush crc
+
+ -- Output
+ match_o : out std_logic; -- CRC match flag
+ crc_o : out unsigned(POLYNOMIAL'length - 1 downto 0) -- CRC output
+ );
+ end component;
+
+ component ucrc_par
+ generic (
+ POLYNOMIAL : unsigned;
+ INIT_VALUE : unsigned;
+ DATA_WIDTH : integer range 2 to 256
+ );
+ port (
+ -- System clock and asynchronous reset
+ sys_clk : in std_logic; -- clock
+ sys_rst_n : in std_logic; -- asynchronous reset
+ sys_clk_en : in std_logic; -- clock enable
+
+ -- Input and Control
+ clear_i : in std_logic; -- synchronous reset
+ data_i : in unsigned(DATA_WIDTH - 1 downto 0); -- data input
+
+ -- Output
+ match_o : out std_logic; -- CRC match flag
+ crc_o : out unsigned(POLYNOMIAL'length - 1 downto 0) -- CRC output
+ );
+ end component;
+
+end ucrc_pack;
+
+-------------------------------------------------------------------------------
+-- Serial CRC module
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Date : Jan. 8, 2014 Wrote description and began coding.
+-- Added separate asynchronous and synchronous
+-- reset inputs. Changed signal names to resemble
+-- other packages within the project, and modified
+-- format to match my own personal coding style.
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This is a CRC calculator.
+-- It was obtained from http://www.opencores.org.
+----------------------------------------------------------------------
+---- ----
+---- Ultimate CRC. ----
+---- ----
+---- This file is part of the ultimate CRC project ----
+---- http://www.opencores.org/cores/ultimate_crc/ ----
+---- ----
+---- Description ----
+---- CRC generator/checker, serial implementation. ----
+---- ----
+---- ----
+---- To Do: ----
+---- - ----
+---- ----
+---- Author(s): ----
+---- - Geir Drange, gedra@opencores.org ----
+---- ----
+----------------------------------------------------------------------
+---- ----
+---- Copyright (C) 2005 Authors and OPENCORES.ORG ----
+---- ----
+---- This source file may be used and distributed without ----
+---- restriction provided that this copyright statement is not ----
+---- removed from the file and that any derivative work contains ----
+---- the original copyright notice and the associated disclaimer. ----
+---- ----
+---- This source file is free software; you can redistribute it ----
+---- and/or modify it under the terms of the GNU General ----
+---- Public License as published by the Free Software Foundation; ----
+---- either version 2.0 of the License, or (at your option) any ----
+---- later version. ----
+---- ----
+---- This source is distributed in the hope that it will be ----
+---- useful, but WITHOUT ANY WARRANTY; without even the implied ----
+---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ----
+---- PURPOSE. See the GNU General Public License for more details.----
+---- ----
+---- You should have received a copy of the GNU General ----
+---- Public License along with this source; if not, download it ----
+---- from http://www.gnu.org/licenses/gpl.txt ----
+---- ----
+----------------------------------------------------------------------
+--
+-- CVS Revision History
+--
+-- $Log: not supported by cvs2svn $
+-- Revision 1.2 2005/05/09 19:26:58 gedra
+-- Moved match signal into clock enable
+--
+-- Revision 1.1 2005/05/07 12:47:47 gedra
+-- Serial implementation.
+--
+--
+--
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity ucrc_ser is
+ generic (
+ POLYNOMIAL : unsigned := "0001000000100001"; -- 4 to 32 bits
+ INIT_VALUE : unsigned := "1111111111111111"
+ );
+ port (
+ -- System clock and asynchronous reset
+ sys_clk : in std_logic; -- clock
+ sys_rst_n : in std_logic; -- asynchronous reset
+ sys_clk_en : in std_logic; -- clock enable
+
+ -- Input and Control
+ clear_i : in std_logic; -- synchronous reset
+ data_i : in std_logic; -- data input
+ flush_i : in std_logic; -- flush crc
+
+ -- Output
+ match_o : out std_logic; -- CRC match flag
+ crc_o : out unsigned(POLYNOMIAL'length - 1 downto 0) -- CRC output
+ );
+end ucrc_ser;
+
+architecture rtl of ucrc_ser is
+
+ constant msb : integer := POLYNOMIAL'length - 1;
+ constant init_msb : integer := INIT_VALUE'length - 1;
+ constant p : unsigned(msb downto 0) := POLYNOMIAL;
+
+ signal din, crc_msb : unsigned(msb downto 1);
+ signal crc, zero, fb : unsigned(msb downto 0);
+
+begin
+
+-- Parameter checking: Invalid generics will abort simulation/synthesis
+ PCHK : if msb /= init_msb generate
+ process
+ begin
+ report "POLYNOMIAL and INIT_VALUE vectors must be equal length!"
+ severity failure;
+ wait;
+ end process;
+ end generate PCHK;
+
+ PCHK2 : if (msb < 3) or (msb > 31) generate
+ process
+ begin
+ report "POLYNOMIAL must be of order 4 to 32!"
+ severity failure;
+ wait;
+ end process;
+ end generate PCHK2;
+
+ PCHK3 : if p(0) /= '1' generate -- LSB must be 1
+ process
+ begin
+ report "POLYNOMIAL must have lsb set to 1!"
+ severity failure;
+ wait;
+ end process;
+ end generate PCHK3;
+
+ zero <= (others => '0');
+ crc_o <= crc;
+
+-- Create vectors of data input and MSB of CRC
+ DI : for i in 1 to msb generate
+ din(i) <= data_i;
+ crc_msb(i) <= crc(msb);
+ end generate DI;
+
+-- Feedback signals
+ fb(0) <= data_i xor crc(msb);
+ fb(msb downto 1) <= crc(msb-1 downto 0) xor ((din xor crc_msb) and p(msb downto 1));
+
+-- CRC process
+ CRCP : process (sys_clk, sys_rst_n)
+ begin
+ if sys_rst_n='0' then -- async. reset
+ crc <= INIT_VALUE;
+ match_o <= '0';
+ elsif rising_edge(sys_clk) then
+ if clear_i='1' then -- sync. reset
+ crc <= INIT_VALUE;
+ match_o <= '0';
+ else
+ if sys_clk_en = '1' then
+ -- CRC generation
+ if flush_i = '1' then
+ crc(0) <= '0';
+ crc(msb downto 1) <= crc(msb - 1 downto 0);
+ else
+ crc <= fb;
+ end if;
+ -- CRC match checker (if data plus CRC is clocked in without errors,
+ -- the CRC register ends up with all zeroes)
+ if fb = zero then
+ match_o <= '1';
+ else
+ match_o <= '0';
+ end if;
+ end if;
+ end if;
+ end if;
+ end process;
+
+end rtl;
+
+-------------------------------------------------------------------------------
+-- Parallel CRC module
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Date : Jan. 8, 2014 Wrote description and began coding.
+-- Added separate asynchronous and synchronous
+-- reset inputs. Changed signal names to resemble
+-- other packages within the project, and modified
+-- format to match my own personal coding style.
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This is a CRC calculator.
+-- It was obtained from http://www.opencores.org.
+----------------------------------------------------------------------
+---- ----
+---- Ultimate CRC. ----
+---- ----
+---- This file is part of the ultimate CRC projectt ----
+---- http://www.opencores.org/cores/ultimate_crc/ ----
+---- ----
+---- Description ----
+---- CRC generator/checker, parallel implementation. ----
+---- ----
+---- ----
+---- To Do: ----
+---- - ----
+---- ----
+---- Author(s): ----
+---- - Geir Drange, gedra@opencores.org ----
+---- ----
+----------------------------------------------------------------------
+---- ----
+---- Copyright (C) 2005 Authors and OPENCORES.ORG ----
+---- ----
+---- This source file may be used and distributed without ----
+---- restriction provided that this copyright statement is not ----
+---- removed from the file and that any derivative work contains ----
+---- the original copyright notice and the associated disclaimer. ----
+---- ----
+---- This source file is free software; you can redistribute it ----
+---- and/or modify it under the terms of the GNU General ----
+---- Public License as published by the Free Software Foundation; ----
+---- either version 2.0 of the License, or (at your option) any ----
+---- later version. ----
+---- ----
+---- This source is distributed in the hope that it will be ----
+---- useful, but WITHOUT ANY WARRANTY; without even the implied ----
+---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ----
+---- PURPOSE. See the GNU General Public License for more details.----
+---- ----
+---- You should have received a copy of the GNU General ----
+---- Public License along with this source; if not, download it ----
+---- from http://www.gnu.org/licenses/gpl.txt ----
+---- ----
+----------------------------------------------------------------------
+--
+-- CVS Revision History
+--
+-- $Log: not supported by cvs2svn $
+-- Revision 1.1 2005/05/09 15:58:38 gedra
+-- Parallel implementation
+--
+--
+--
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+entity ucrc_par is
+ generic (
+ POLYNOMIAL : unsigned := "0001000000100001";
+ INIT_VALUE : unsigned := "1111111111111111";
+ DATA_WIDTH : integer range 2 to 256 := 8
+ );
+ port (
+ -- System clock and asynchronous reset
+ sys_clk : in std_logic; -- clock
+ sys_rst_n : in std_logic; -- asynchronous reset
+ sys_clk_en : in std_logic; -- clock enable
+
+ -- Input and Control
+ clear_i : in std_logic; -- synchronous reset
+ data_i : in unsigned(DATA_WIDTH - 1 downto 0); -- data input
+
+ -- Output
+ match_o : out std_logic; -- CRC match flag
+ crc_o : out unsigned(POLYNOMIAL'length - 1 downto 0) -- CRC output
+ );
+end ucrc_par;
+
+architecture rtl of ucrc_par is
+
+ constant msb : integer := POLYNOMIAL'length - 1;
+ constant init_msb : integer := INIT_VALUE'length - 1;
+ constant p : unsigned(msb downto 0) := POLYNOMIAL;
+ constant dw : integer := DATA_WIDTH;
+ constant pw : integer := POLYNOMIAL'length;
+ type fb_array is array (dw downto 1) of unsigned(msb downto 0);
+ type dmsb_array is array (dw downto 1) of unsigned(msb downto 1);
+ signal crca : fb_array;
+ signal da, ma : dmsb_array;
+ signal crc, zero : unsigned(msb downto 0);
+
+begin
+
+-- Parameter checking: Invalid generics will abort simulation/synthesis
+ PCHK1 : if msb /= init_msb generate
+ process
+ begin
+ report "POLYNOMIAL and INIT_VALUE vectors must be equal length!"
+ severity failure;
+ wait;
+ end process;
+ end generate PCHK1;
+
+ PCHK2 : if (msb < 3) or (msb > 31) generate
+ process
+ begin
+ report "POLYNOMIAL must be of order 4 to 32!"
+ severity failure;
+ wait;
+ end process;
+ end generate PCHK2;
+
+ PCHK3 : if p(0) /= '1' generate -- LSB must be 1
+ process
+ begin
+ report "POLYNOMIAL must have lsb set to 1!"
+ severity failure;
+ wait;
+ end process;
+ end generate PCHK3;
+
+-- Generate vector of each data bit
+ CA : for i in 1 to dw generate -- data bits
+ DAT : for j in 1 to msb generate
+ da(i)(j) <= data_i(i - 1);
+ end generate DAT;
+ end generate CA;
+
+-- Generate vector of each CRC MSB
+ MS0 : for i in 1 to msb generate
+ ma(1)(i) <= crc(msb);
+ end generate MS0;
+ MSP : for i in 2 to dw generate
+ MSU : for j in 1 to msb generate
+ ma(i)(j) <= crca(i - 1)(msb);
+ end generate MSU;
+ end generate MSP;
+
+-- Generate feedback matrix
+ crca(1)(0) <= da(1)(1) xor crc(msb);
+ crca(1)(msb downto 1) <= crc(msb - 1 downto 0) xor ((da(1) xor ma(1)) and p(msb downto 1));
+ FB : for i in 2 to dw generate
+ crca(i)(0) <= da(i)(1) xor crca(i - 1)(msb);
+ crca(i)(msb downto 1) <= crca(i - 1)(msb - 1 downto 0) xor
+ ((da(i) xor ma(i)) and p(msb downto 1));
+ end generate FB;
+
+-- CRC process
+ crc_o <= crc;
+ zero <= (others => '0');
+
+ CRCP : process (sys_clk, sys_rst_n)
+ begin
+ if sys_rst_n='0' then -- async. reset
+ crc <= INIT_VALUE;
+ match_o <= '0';
+ elsif rising_edge(sys_clk) then
+ if clear_i='1' then -- sync. reset
+ crc <= INIT_VALUE;
+ match_o <= '0';
+ elsif sys_clk_en = '1' then
+ crc <= crca(dw);
+ if crca(dw) = zero then
+ match_o <= '1';
+ else
+ match_o <= '0';
+ end if;
+ end if;
+ end if;
+ end process;
+
+end rtl;
+
+