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
/sd_card_controller
- from Rev 14 to Rev 15
- ↔ Reverse comparison
Rev 14 → Rev 15
/trunk/doc/sd_card_pack_OC120116.odt
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
trunk/doc/sd_card_pack_OC120116.odt
Property changes :
Deleted: svn:mime-type
## -1 +0,0 ##
-application/octet-stream
\ No newline at end of property
Index: trunk/doc/sd_card_pack_OC120116.pdf
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: trunk/doc/sd_card_pack_OC120116.pdf
===================================================================
--- trunk/doc/sd_card_pack_OC120116.pdf (revision 14)
+++ trunk/doc/sd_card_pack_OC120116.pdf (nonexistent)
trunk/doc/sd_card_pack_OC120116.pdf
Property changes :
Deleted: svn:mime-type
## -1 +0,0 ##
-application/octet-stream
\ No newline at end of property
Index: trunk/doc/sd_host_pack_OC070417.odt
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: trunk/doc/sd_host_pack_OC070417.odt
===================================================================
--- trunk/doc/sd_host_pack_OC070417.odt (nonexistent)
+++ trunk/doc/sd_host_pack_OC070417.odt (revision 15)
trunk/doc/sd_host_pack_OC070417.odt
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: trunk/doc/sd_host_pack_OC070417.pdf
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: trunk/doc/sd_host_pack_OC070417.pdf
===================================================================
--- trunk/doc/sd_host_pack_OC070417.pdf (nonexistent)
+++ trunk/doc/sd_host_pack_OC070417.pdf (revision 15)
trunk/doc/sd_host_pack_OC070417.pdf
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: trunk/doc/sd_host_pack_registers.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: trunk/doc/sd_host_pack_registers.ods
===================================================================
--- trunk/doc/sd_host_pack_registers.ods (nonexistent)
+++ trunk/doc/sd_host_pack_registers.ods (revision 15)
trunk/doc/sd_host_pack_registers.ods
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: trunk/rtl/VHDL/sd_card_pack.vhd
===================================================================
--- trunk/rtl/VHDL/sd_card_pack.vhd (revision 14)
+++ trunk/rtl/VHDL/sd_card_pack.vhd (nonexistent)
@@ -1,2952 +0,0 @@
---------------------------------------------------------------------------
--- 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: trunk/rtl/VHDL/dds_pack.vhd
===================================================================
--- trunk/rtl/VHDL/dds_pack.vhd (nonexistent)
+++ trunk/rtl/VHDL/dds_pack.vhd (revision 15)
@@ -0,0 +1,970 @@
+--------------------------------------------------------------------------
+-- Package of Direct Digital Synthesizer (DDS) components
+--
+-- NOTE: These components are for producing digital pulse outputs at
+-- desired frequencies and/or duty cycles. In other words, there
+-- are no modules here which include sinewave lookup tables. For
+-- that type of module, please refer to "dds_sine_pack.vhd"
+--
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+package dds_pack is
+
+ component dds_constant_squarewave
+ generic (
+ OUTPUT_FREQ : real; -- Desired output frequency
+ SYS_CLK_RATE : real; -- underlying clock rate
+ ACC_BITS : integer -- Bit width of DDS phase accumulator
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Output
+ pulse_o : out std_logic;
+ squarewave_o : out std_logic
+ );
+ end component;
+
+ component dds_squarewave
+ generic (
+ ACC_BITS : integer -- Bit width of DDS phase accumulator
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Frequency setting
+ freq_i : in unsigned(ACC_BITS-1 downto 0);
+
+ -- Output
+ pulse_o : out std_logic;
+ squarewave_o : out std_logic
+ );
+ end component;
+
+ component dds_squarewave_phase_load
+ generic (
+ ACC_BITS : integer -- Bit width of DDS phase accumulator
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Frequency setting
+ freq_i : in unsigned(ACC_BITS-1 downto 0);
+
+ -- Synchronous load
+ phase_i : in unsigned(ACC_BITS-1 downto 0);
+ phase_ld_i : in std_logic;
+
+ -- Output
+ pulse_o : out std_logic;
+ squarewave_o : out std_logic
+ );
+ end component;
+
+ component dds_constant_clk_en_gen
+ generic (
+ OUTPUT_FREQ : real; -- Desired output frequency
+ SYS_CLK_RATE : real; -- underlying clock rate
+ ACC_BITS : integer -- Bit width of DDS phase accumulator
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Output
+ clk_en_o : out std_logic
+ );
+ end component;
+
+ component dds_clk_en_gen
+ generic (
+ ACC_BITS : integer -- Bit width of DDS phase accumulator
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Frequency setting
+ freq_i : in unsigned(ACC_BITS-1 downto 0);
+
+ -- Output
+ clk_en_o : out std_logic
+ );
+ end component;
+
+ component calibrated_clk_en_gen
+ generic (
+ SYS_CLK_RATE : real -- underlying clock rate
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Frequency setting
+ freq_i : in unsigned(31 downto 0); -- some MSBs may be ignored
+
+ -- Output
+ clk_en_o : out std_logic
+ );
+ end component;
+
+ component dds_pwm_dac
+ generic (
+ ACC_BITS : integer -- Bit width of DDS phase accumulator
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Frequency setting
+ freq_i : in unsigned(ACC_BITS-1 downto 0);
+
+ -- Output
+ clk_en_o : out std_logic
+ );
+ end component;
+
+ component dds_pwm_dac_srv
+ generic (
+ ACC_BITS : integer -- Bit width of DDS phase accumulator
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Frequency/Phase settings
+ phase_load_i : in std_logic;
+ phase_val_i : in unsigned(ACC_BITS-1 downto 0);
+ freq_i : in unsigned(ACC_BITS-1 downto 0);
+
+ -- Output
+ clk_en_o : out std_logic
+ );
+ end component;
+
+end dds_pack;
+
+package body dds_pack is
+end dds_pack;
+
+-------------------------------------------------------------------------------
+-- Direct Digital Synthesizer Constant Squarewave module
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Update: Sep. 5, 2002 copied this file from "auto_baud_pack.vhd"
+-- Added tracking functions, and debugged them.
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This is a simple direct digital synthesizer module. It includes a phase
+-- accumulator which increments in order to produce the desired output
+-- frequency in its most significant bit, which is the squarewave output.
+--
+-- In addition to the squarewave output there is a pulse output which is
+-- high for one sys_clk period, during the sys_clk period immediately
+-- preceding the rising edge of the squarewave output.
+--
+-- NOTES:
+-- The accumulator increment word is:
+-- increment = Fout*2^N/Fsys_clk
+--
+-- Where N is the number of bits in the phase accumulator.
+--
+-- There will always be jitter with this type of clock source, but the
+-- long time average frequency can be made arbitrarily close to whatever
+-- value is desired, simply by increasing N.
+--
+-- To reduce jitter, use a higher underlying system clock frequency, and
+-- for goodness sakes, try to keep the desired output frequency much lower
+-- than the system clock frequency. The closer it gets to Fsys_clk/2, the
+-- closer it is to the Nyquist limit, and the output jitter is much more
+-- significant at that point.
+--
+--
+
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+ entity dds_constant_squarewave is
+ generic (
+ OUTPUT_FREQ : real := 8000.0; -- Desired output frequency
+ SYS_CLK_RATE : real := 48000000.0; -- underlying clock rate
+ ACC_BITS : integer := 16 -- Bit width of DDS phase accumulator
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Output
+ pulse_o : out std_logic;
+ squarewave_o : out std_logic
+ );
+ end dds_constant_squarewave;
+
+architecture beh of dds_constant_squarewave is
+
+-- Constants
+constant DDS_INCREMENT : integer := integer(OUTPUT_FREQ*(2**real(ACC_BITS))/SYS_CLK_RATE);
+
+-- Signals
+signal dds_phase : unsigned(ACC_BITS-1 downto 0); -- phase accumulator register
+signal dds_phase_next : unsigned(ACC_BITS-1 downto 0);
+
+-----------------------------------------------------------------------------
+begin
+
+ dds_proc: Process(sys_rst_n,sys_clk)
+ begin
+ if (sys_rst_n = '0') then
+ dds_phase <= (others=>'0');
+ elsif (sys_clk'event and sys_clk='1') then
+ if (sys_clk_en='1') then
+ dds_phase <= dds_phase_next;
+ end if;
+ end if; -- sys_clk
+ end process dds_proc;
+ dds_phase_next <= dds_phase + DDS_INCREMENT;
+ pulse_o <= '1' when sys_clk_en='1' and dds_phase(dds_phase'length-1)='0' and dds_phase_next(dds_phase_next'length-1)='1' else '0';
+ squarewave_o <= dds_phase(dds_phase'length-1);
+
+end beh;
+
+
+-------------------------------------------------------------------------------
+-- Direct Digital Synthesizer Variable Frequency Squarewave module
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Update: Jan. 31, 2013 copied code from dds_constant_squarewave, and
+-- modified it to accept a frequency setting input.
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This is a simple direct digital synthesizer module. It includes a phase
+-- accumulator which increments in order to produce the desired output
+-- frequency in its most significant bit, which is the squarewave output.
+--
+-- In addition to the squarewave output there is a pulse output which is
+-- high for one sys_clk period, during the sys_clk period immediately
+-- preceding the rising edge of the squarewave output.
+--
+-- NOTES:
+-- The accumulator increment word is:
+-- increment = Fout*2^N/Fsys_clk
+--
+-- Where N is the number of bits in the phase accumulator.
+--
+-- There will always be jitter with this type of clock source, but the
+-- long time average frequency can be made arbitrarily close to whatever
+-- value is desired, simply by increasing N.
+--
+-- To reduce jitter, use a higher underlying system clock frequency, and
+-- for goodness sakes, try to keep the desired output frequency much lower
+-- than the system clock frequency. The closer it gets to Fsys_clk/2, the
+-- closer it is to the Nyquist limit, and the output jitter is much more
+-- significant as compared to the output period at that point.
+--
+--
+
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+ entity dds_squarewave is
+ generic (
+ ACC_BITS : integer := 16 -- Bit width of DDS phase accumulator
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Frequency setting
+ freq_i : in unsigned(ACC_BITS-1 downto 0);
+
+ -- Output
+ pulse_o : out std_logic;
+ squarewave_o : out std_logic
+ );
+ end dds_squarewave;
+
+architecture beh of dds_squarewave is
+
+-- Signals
+signal dds_phase : unsigned(ACC_BITS-1 downto 0); -- phase accumulator register
+signal dds_phase_next : unsigned(ACC_BITS-1 downto 0);
+
+-----------------------------------------------------------------------------
+begin
+
+ dds_proc: Process(sys_rst_n,sys_clk)
+ begin
+ if (sys_rst_n = '0') then
+ dds_phase <= (others=>'0');
+ elsif (sys_clk'event and sys_clk='1') then
+ if (sys_clk_en='1') then
+ dds_phase <= dds_phase_next;
+ end if;
+ end if; -- sys_clk
+ end process dds_proc;
+ dds_phase_next <= dds_phase + freq_i;
+ pulse_o <= '1' when sys_clk_en='1' and dds_phase(dds_phase'length-1)='0' and dds_phase_next(dds_phase_next'length-1)='1' else '0';
+ squarewave_o <= dds_phase(dds_phase'length-1);
+
+end beh;
+
+
+-------------------------------------------------------------------------------
+-- Direct Digital Synthesizer Variable Frequency Squarewave module,
+-- with synchronous phase load
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Update: Aug. 1, 2013 copied code from dds_squarewave, and
+-- modified it to accept a synchronous load input.
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This is a simple direct digital synthesizer module. It includes a phase
+-- accumulator which increments in order to produce the desired output
+-- frequency in its most significant bit, which is the squarewave output.
+--
+-- In addition to the squarewave output there is a pulse output which is
+-- high for one sys_clk period, during the sys_clk period immediately
+-- preceding the rising edge of the squarewave output.
+--
+-- A synchronous load input allows the synthesizer to be adjusted to any
+-- desired initial phase condition. This is useful when using it for
+-- timing and synchronization.
+--
+-- NOTES:
+-- The accumulator increment word is:
+-- increment = Fout*2^N/Fsys_clk
+--
+-- Where N is the number of bits in the phase accumulator.
+--
+-- There will always be jitter with this type of clock source, but the
+-- long time average frequency can be made arbitrarily close to whatever
+-- value is desired, simply by increasing N.
+--
+-- To reduce jitter, use a higher underlying system clock frequency, and
+-- for goodness sakes, try to keep the desired output frequency much lower
+-- than the system clock frequency. The closer it gets to Fsys_clk/2, the
+-- closer it is to the Nyquist limit, and the output jitter is much more
+-- significant as compared to the output period at that point.
+--
+--
+
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+ entity dds_squarewave_phase_load is
+ generic (
+ ACC_BITS : integer := 16 -- Bit width of DDS phase accumulator
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Frequency setting
+ freq_i : in unsigned(ACC_BITS-1 downto 0);
+
+ -- Synchronous load
+ phase_i : in unsigned(ACC_BITS-1 downto 0);
+ phase_ld_i : in std_logic;
+
+ -- Output
+ pulse_o : out std_logic;
+ squarewave_o : out std_logic
+ );
+ end dds_squarewave_phase_load;
+
+architecture beh of dds_squarewave_phase_load is
+
+-- Signals
+signal dds_phase : unsigned(ACC_BITS-1 downto 0); -- phase accumulator register
+signal dds_phase_next : unsigned(ACC_BITS-1 downto 0);
+
+-----------------------------------------------------------------------------
+begin
+
+ dds_proc: Process(sys_rst_n,sys_clk)
+ begin
+ if (sys_rst_n = '0') then
+ dds_phase <= (others=>'0');
+ elsif (sys_clk'event and sys_clk='1') then
+ if (sys_clk_en='1') then
+ dds_phase <= dds_phase_next;
+ end if;
+ if (phase_ld_i='1') then
+ dds_phase <= phase_i;
+ end if;
+ end if; -- sys_clk
+ end process dds_proc;
+ dds_phase_next <= dds_phase + freq_i;
+ pulse_o <= '1' when sys_clk_en='1' and dds_phase(dds_phase'length-1)='0' and dds_phase_next(dds_phase_next'length-1)='1' else '0';
+ squarewave_o <= dds_phase(dds_phase'length-1);
+
+end beh;
+
+
+-------------------------------------------------------------------------------
+-- Direct Digital Synthesizer Clock Enable Generator, Constant output frequency
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Update: Oct. 4, 2013 Copied code from dds_clk_en_gen, and modified it to
+-- create a clock enable output using generics to set
+-- the frequency.
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This is a simple direct digital synthesizer module. It includes a phase
+-- accumulator which increments in order to produce the desired output
+-- frequency in its most significant bit, which is a squarewave with
+-- some unavoidable jitter.
+--
+-- In this module, the squarewave is not provided as an output, because
+-- this module's purpose is to generate a clock enable signal.
+--
+-- The clock enable output is a pulsed output which, for frequencies below
+-- the Nyquist frequency is high for one sys_clk period, during the sys_clk
+-- period immediately preceding the rising edge of the squarewave output.
+--
+-- A special "trick" is performed inside this module, which is to invert the
+-- pulse output for frequencies above the Nyquist frequency. Since the pulse
+-- train is a perfect 50% duty cycle squarewave at the Nyquist frequency, the
+-- pulse train and its inverse are equivalent at that point... But for
+-- higher frequencies, the squarewave reduces in frequency back down towards
+-- zero Hz. However, since the pulse train is inverted for frequencies above
+-- the Nyquist frequency (Fsys_clk/2), then the output pulse train is high for
+-- a larger and larger fraction of time... essentially forming a nice clock
+-- enable which can be varied from 0% duty cycle, all the way up to N% duty
+-- cycle, where K is given by:
+--
+-- K = max_duty_cycle = 100 * (1-2**(-N)) percent
+--
+-- Where N is the number of bits in the phase accumulator (ACC_BITS)
+--
+--
+-- NOTES:
+-- The accumulator increment word is set by generics:
+-- increment = OUTPUT_FREQ*2^ACC_BITS/SYS_CLK_RATE
+--
+-- Where N is the number of bits in the phase accumulator (ACC_BITS)
+--
+-- There will always be jitter with this type of clock source, but the
+-- clock enable output duty cycle can be adjusted in increments as fine
+-- as may be desired, simply by increasing N.
+--
+--
+
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+ entity dds_constant_clk_en_gen is
+ generic (
+ OUTPUT_FREQ : real := 32000000.0; -- Desired output frequency
+ SYS_CLK_RATE : real := 50000000.0; -- underlying clock rate
+ ACC_BITS : integer := 30 -- Bit width of DDS phase accumulator
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Output
+ clk_en_o : out std_logic
+ );
+ end dds_constant_clk_en_gen;
+
+architecture beh of dds_constant_clk_en_gen is
+
+-- Constants
+constant DDS_INCREMENT : integer := integer(OUTPUT_FREQ*(2**real(ACC_BITS))/SYS_CLK_RATE);
+constant HALFWAY : integer := integer(2**real(ACC_BITS-1));
+
+-- Signals
+signal dds_phase : unsigned(ACC_BITS-1 downto 0); -- phase accumulator register
+signal dds_phase_next : unsigned(ACC_BITS-1 downto 0);
+signal pulse_l : std_logic;
+
+-----------------------------------------------------------------------------
+begin
+
+ dds_proc: Process(sys_rst_n,sys_clk)
+ begin
+ if (sys_rst_n = '0') then
+ dds_phase <= (others=>'0');
+ elsif (sys_clk'event and sys_clk='1') then
+ if (sys_clk_en='1') then
+ dds_phase <= dds_phase_next;
+ end if;
+ end if; -- sys_clk
+ end process dds_proc;
+ dds_phase_next <= dds_phase + DDS_INCREMENT;
+ pulse_l <= '1' when sys_clk_en='1' and dds_phase(dds_phase'length-1)='0' and dds_phase_next(dds_phase_next'length-1)='1' else '0';
+ clk_en_o <= pulse_l when (DDS_INCREMENT'0');
+ elsif (sys_clk'event and sys_clk='1') then
+ if (sys_clk_en='1') then
+ dds_phase <= dds_phase_next;
+ end if;
+ end if; -- sys_clk
+ end process dds_proc;
+ dds_phase_next <= dds_phase + freq_i;
+ pulse_l <= '1' when sys_clk_en='1' and dds_phase(dds_phase'length-1)='0' and dds_phase_next(dds_phase_next'length-1)='1' else '0';
+ clk_en_o <= pulse_l when freq_i(freq_i'length-1)='0' else not pulse_l;
+
+end beh;
+
+
+-------------------------------------------------------------------------------
+-- Calibrated Direct Digital Synthesizer Clock Enable Generator
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Update: Nov. 11, 2013 Copied code from dds_clk_en_gen, and modified it.
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This is two DDS units tied together. The first unit produces a calibration
+-- clock enable, at a frequency which is very close to a power of two Hz.
+-- It uses the highest power of two which can be achieved using the given
+-- system clock frequency.
+--
+-- The second DDS unit then uses the calibration clock enable for its
+-- clock enable input. This effectively "calibrates" the second unit
+-- so that its input frequency is in Hz.
+--
+-- The input frequency to this module was fixed at 32 bits, but the
+-- most significant bits may be ignored.
+--
+
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+library work;
+use work.dds_pack.all;
+use work.convert_pack.all;
+
+ entity calibrated_clk_en_gen is
+ generic (
+ SYS_CLK_RATE : real := 50000000.0 -- underlying clock rate
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Frequency setting
+ freq_i : in unsigned(31 downto 0);
+
+ -- Output
+ clk_en_o : out std_logic
+ );
+ end calibrated_clk_en_gen;
+
+architecture beh of calibrated_clk_en_gen is
+
+-- Constants
+constant LOG2_CAL_BITS : natural := bit_width(SYS_CLK_RATE)-1;
+
+-- Signals
+signal cal_clk_en : std_logic;
+
+
+
+-----------------------------------------------------------------------------
+begin
+
+ -- Calibration clock enable
+ cal_clk_gen : dds_constant_clk_en_gen
+ generic map(
+ OUTPUT_FREQ => real(2**LOG2_CAL_BITS),
+ SYS_CLK_RATE => SYS_CLK_RATE,
+ ACC_BITS => 30
+ )
+ port map(
+
+ sys_rst_n => sys_rst_n,
+ sys_clk => sys_clk,
+ sys_clk_en => sys_clk_en,
+
+ -- Output
+ clk_en_o => cal_clk_en
+ );
+
+ clk_en_gen : dds_clk_en_gen
+ generic map(
+ ACC_BITS => LOG2_CAL_BITS
+ )
+ port map(
+
+ sys_rst_n => sys_rst_n,
+ sys_clk => sys_clk,
+ sys_clk_en => cal_clk_en,
+
+ -- Frequency setting
+ freq_i => freq_i(LOG2_CAL_BITS-1 downto 0),
+
+ -- Output
+ clk_en_o => clk_en_o
+ );
+
+end beh;
+
+
+-------------------------------------------------------------------------------
+-- Direct Digital Synthesizer PWM DAC
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Update:
+-- Jan. 23, 2015 Copied code from clk_en_gen, and brought pulse_l
+-- logic inside the sys_clk_en enabled process, so
+-- that the pulses are widened according to sys_clk_en.
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This is exactly the same as dds_clk_en_gen, except that it brings the pulse_l
+-- logic inside the clocked process, so that output pulses are no longer 1
+-- sys_clk wide, but are instead lengthened according to sys_clk_en. This makes
+-- the unit useful for generating a PWM output signal, with the smallest pulse
+-- being the period between sys_clk_en pulses.
+--
+-- This is a simple direct digital synthesizer module. It includes a phase
+-- accumulator which increments in order to produce the desired output
+-- frequency in its most significant bit, which is a squarewave with
+-- some unavoidable jitter.
+--
+-- In this module, the squarewave is not provided as an output, because
+-- this module's purpose is to generate a clock enable signal.
+--
+-- The clock enable output is a pulsed output which, for frequencies below
+-- the Nyquist frequency is high for one sys_clk period, during the sys_clk
+-- period immediately preceding the rising edge of the squarewave output.
+--
+-- A special "trick" is performed inside this module, which is to invert the
+-- pulse output for frequencies above the Nyquist frequency. Since the pulse
+-- train is a perfect 50% duty cycle squarewave at the Nyquist frequency, the
+-- pulse train and its inverse are equivalent at that point... But for
+-- higher frequencies, the squarewave reduces in frequency back down towards
+-- zero Hz. However, since the pulse train is inverted for frequencies above
+-- the Nyquist frequency (Fsys_clk/2), then the output pulse train is high for
+-- a larger and larger fraction of time... essentially forming a nice clock
+-- enable which can be varied from 0% duty cycle, all the way up to N% duty
+-- cycle, where K is given by:
+--
+-- K = max_duty_cycle = 100 * (1-2**(-N)) percent
+--
+-- Where N is the number of bits in the phase accumulator (ACC_BITS)
+--
+-- This can perhaps operate as a form of PWM also... although the fundamental
+-- frequency is not constant, as it is in true PWM.
+--
+--
+-- NOTES:
+-- The accumulator increment word is:
+-- increment = Fout*2^N/Fsys_clk
+--
+-- Where N is the number of bits in the phase accumulator (ACC_BITS)
+--
+-- There will always be jitter with this type of clock source, but the
+-- clock enable output duty cycle can be adjusted in increments as fine
+-- as may be desired, simply by increasing N.
+--
+--
+
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+ entity dds_pwm_dac is
+ generic (
+ ACC_BITS : integer := 16 -- Bit width of DDS phase accumulator
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Frequency setting
+ freq_i : in unsigned(ACC_BITS-1 downto 0);
+
+ -- Output
+ clk_en_o : out std_logic
+ );
+ end dds_pwm_dac;
+
+architecture beh of dds_pwm_dac is
+
+-- Signals
+signal dds_phase : unsigned(ACC_BITS-1 downto 0); -- phase accumulator register
+signal dds_phase_next : unsigned(ACC_BITS-1 downto 0);
+signal pulse_l : std_logic;
+
+-----------------------------------------------------------------------------
+begin
+
+ dds_proc: Process(sys_rst_n,sys_clk)
+ begin
+ if (sys_rst_n = '0') then
+ dds_phase <= (others=>'0');
+ pulse_l <= '0';
+ elsif (sys_clk'event and sys_clk='1') then
+ if (sys_clk_en='1') then
+ dds_phase <= dds_phase_next;
+ if (dds_phase(dds_phase'length-1)='0' and dds_phase_next(dds_phase_next'length-1)='1') then
+ pulse_l <= '1';
+ else
+ pulse_l <= '0';
+ end if;
+ end if;
+ end if; -- sys_clk
+ end process dds_proc;
+ dds_phase_next <= dds_phase + freq_i;
+ clk_en_o <= pulse_l when freq_i(freq_i'length-1)='0' else not pulse_l;
+
+end beh;
+
+-------------------------------------------------------------------------------
+-- Direct Digital Synthesizer PWM DAC - Synchronously Resettable Version
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Update:
+-- Jan. 23, 2015 Copied code from dds_pwm_dac, and added synchronous
+-- phase load input and phase value inputs
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This is exactly the same as dds_pwm_dac, except that a synchronous phase
+-- load is provided. This was needed when using the DAC to "throttle" pixel
+-- counters driving a display. By resetting the DAC's phase accumulator
+-- during each retrace interval, visible "jitter" was reduced, and made
+-- identical for each line of display pixels.
+--
+-- NOTES:
+-- The accumulator increment word is:
+-- increment = Fout*2^N/Fsys_clk
+--
+-- Where N is the number of bits in the phase accumulator (ACC_BITS)
+--
+-- There will always be jitter with this type of clock source, but the
+-- clock enable output duty cycle can be adjusted in increments as fine
+-- as may be desired, simply by increasing N.
+--
+--
+
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+ entity dds_pwm_dac_srv is
+ generic (
+ ACC_BITS : integer := 16 -- Bit width of DDS phase accumulator
+ );
+ port (
+
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Frequency/Phase settings
+ phase_load_i : in std_logic;
+ phase_val_i : in unsigned(ACC_BITS-1 downto 0);
+ freq_i : in unsigned(ACC_BITS-1 downto 0);
+
+ -- Output
+ clk_en_o : out std_logic
+ );
+ end dds_pwm_dac_srv;
+
+architecture beh of dds_pwm_dac_srv is
+
+-- Signals
+signal dds_phase : unsigned(ACC_BITS-1 downto 0); -- phase accumulator register
+signal dds_phase_next : unsigned(ACC_BITS-1 downto 0);
+signal pulse_l : std_logic;
+
+-----------------------------------------------------------------------------
+begin
+
+ dds_proc: Process(sys_rst_n,sys_clk)
+ begin
+ if (sys_rst_n = '0') then
+ dds_phase <= (others=>'0');
+ pulse_l <= '0';
+ elsif (sys_clk'event and sys_clk='1') then
+ if (sys_clk_en='1') then
+ if (phase_load_i='1') then
+ dds_phase <= phase_val_i;
+ pulse_l <= '0';
+ else
+ dds_phase <= dds_phase_next;
+ if (dds_phase(dds_phase'length-1)='0' and dds_phase_next(dds_phase_next'length-1)='1') then
+ pulse_l <= '1';
+ else
+ pulse_l <= '0';
+ end if;
+ end if; -- phase_zero_i
+ end if; -- sys_clk_en
+ end if; -- sys_clk
+ end process dds_proc;
+ dds_phase_next <= dds_phase + freq_i;
+ clk_en_o <= pulse_l when freq_i(freq_i'length-1)='0' else not pulse_l;
+
+end beh;
+
+
Index: trunk/rtl/VHDL/sd_host_pack.vhd
===================================================================
--- trunk/rtl/VHDL/sd_host_pack.vhd (nonexistent)
+++ trunk/rtl/VHDL/sd_host_pack.vhd (revision 15)
@@ -0,0 +1,1564 @@
+--------------------------------------------------------------------------
+-- 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_host_pack is
+
+-- Constants relating to the SD Card interface
+
+ -- Register size constants
+constant BLKSIZE_W : integer := 12;
+constant BLKCNT_W : integer := 16;
+
+ -- cmd module interrupts
+constant INT_CMD_CC : integer := 0;
+constant INT_CMD_EI : integer := 1;
+constant INT_CMD_CTE : integer := 2;
+constant INT_CMD_CCRCE : integer := 3;
+constant INT_CMD_CIE : integer := 4;
+constant INT_CMD_SIZE : integer := 5; -- Size of register field, in bits
+
+ -- data module interrupts
+constant INT_DATA_CC : integer := 0;
+constant INT_DATA_CCRCE : integer := 1;
+constant INT_DATA_CFE : integer := 2;
+constant INT_DATA_SIZE : integer := 3; -- Size of register field, in bits
+
+ component sd_cmd_host
+ port(
+ sys_rst : in std_logic;
+ sd_clk : in std_logic;
+ -- Control and settings
+ start_i : in std_logic;
+ int_rst_i : in std_logic;
+ busy_i : in std_logic; --direct signal from data sd data input (data[0])
+ cmd_index_i : in unsigned(5 downto 0);
+ argument_i : in unsigned(31 downto 0);
+ timeout_i : in unsigned(15 downto 0);
+ int_status_o : out unsigned(4 downto 0);
+ response_0_o : out unsigned(31 downto 0);
+ response_1_o : out unsigned(31 downto 0);
+ response_2_o : out unsigned(31 downto 0);
+ response_3_o : out unsigned(31 downto 0);
+ -- SD/MMC card command signals
+ sd_cmd_i : in std_logic;
+ sd_cmd_o : out std_logic;
+ sd_cmd_oe_o : out std_logic
+ );
+ end component;
+
+ component sd_data_8bit_host
+ port(
+ sd_clk : in std_logic;
+ sys_rst : 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_siz_o : out unsigned(1 downto 0);
+ sd_dat_oe_o : out std_logic;
+ sd_dat_o : out unsigned(7 downto 0);
+ sd_dat_i : in unsigned(7 downto 0);
+ --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);
+ 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;
+ bustest_res_o : out unsigned(2 downto 0);
+ sd_dat_busy_o : out std_logic;
+ fsm_busy_o : out std_logic;
+ crc_ok_o : out std_logic
+ );
+ end component;
+
+ component sd_controller_8bit_bram
+ port (
+ -- WISHBONE common
+ wb_clk_i : in std_logic;
+ wb_rst_i : in std_logic;
+ -- WISHBONE slave (register interface)
+ wb_dat_i : in unsigned(31 downto 0);
+ wb_dat_o : out unsigned(31 downto 0);
+ wb_adr_i : in unsigned(3 downto 0);
+ wb_we_i : in std_logic;
+ wb_cyc_i : in std_logic;
+ wb_ack_o : out std_logic;
+ -- Dedicated BRAM port without acknowledge.
+ -- Access cycles must complete immediately.
+ -- (data to cross clock domains by this dual-ported BRAM)
+ bram_clk_o : out std_logic; -- Same as sd_clk_o_pad
+ bram_dat_o : out unsigned(7 downto 0);
+ bram_dat_i : in unsigned(7 downto 0);
+ bram_adr_o : out unsigned(31 downto 0);
+ bram_we_o : out std_logic;
+ bram_cyc_o : out std_logic;
+ --SD Card Interface
+ sd_cmd_i : in std_logic;
+ sd_cmd_o : out std_logic;
+ sd_cmd_oe_o : out std_logic;
+ 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);
+ sd_clk_o_pad : out std_logic;
+ -- Interrupt outputs
+ int_cmd_o : out std_logic;
+ int_data_o : out std_logic
+ );
+ end component;
+
+end sd_host_pack;
+
+package body sd_host_pack is
+end sd_host_pack;
+
+-------------------------------------------------------------------------------
+-- SD/MMC Command Host
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Update: June 11, 2016 Combined sd_cmd_master with sd_cmd_serial_host from
+-- the opencores.org VHDL code, in order to make this
+-- unit. The reason for combining them is that eight
+-- interface signals were shared only between those two
+-- modules when they were instantiated, and they are not
+-- needed individually.
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This module handles generating the serial SD/MMC command output, and
+-- receiving the SD/MMC responses from the card.
+--
+-- This unit runs entirely within the sd_clk_i clock domain.
+--
+
+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;
+
+entity sd_cmd_host is
+ port(
+ sys_rst : in std_logic;
+ sd_clk : in std_logic;
+ -- Control and settings
+ start_i : in std_logic;
+ int_rst_i : in std_logic;
+ busy_i : in std_logic; --direct signal from data sd data input (data[0])
+ cmd_index_i : in unsigned(5 downto 0);
+ argument_i : in unsigned(31 downto 0);
+ timeout_i : in unsigned(15 downto 0);
+ int_status_o : out unsigned(4 downto 0);
+ response_0_o : out unsigned(31 downto 0);
+ response_1_o : out unsigned(31 downto 0);
+ response_2_o : out unsigned(31 downto 0);
+ response_3_o : out unsigned(31 downto 0);
+ -- SD/MMC card command signals
+ sd_cmd_i : in std_logic;
+ sd_cmd_o : out std_logic;
+ sd_cmd_oe_o : out std_logic
+ );
+end sd_cmd_host;
+
+architecture beh of sd_cmd_host is
+
+---------------Internal Constants-------------
+constant INIT_DELAY : integer := 4;
+constant BITS_TO_SEND : integer := 48;
+constant CMD_SIZE : integer := 40;
+constant RESP_SIZE : integer := 128;
+
+-----------------Internal Signals-----------
+signal cmd_dat_reg : std_logic;
+signal resp_len : integer;
+signal cmd_buff : unsigned(CMD_SIZE-1 downto 0);
+signal resp_buff : unsigned(RESP_SIZE-1 downto 0);
+signal resp_idx : integer;
+ --CRC related
+signal crc_rst_n : std_logic;
+signal crc_in : unsigned(6 downto 0);
+signal crc_val : unsigned(6 downto 0);
+signal crc_enable : std_logic;
+signal crc_bit : std_logic;
+signal crc_ok : std_logic;
+ --Internal Counters
+signal counter : integer;
+ --State Machines
+type SERIAL_STATE_TYPE is (INIT, IDLE, SETUP_CRC, WRITE, READ_WAIT, READ, FINISH_WR);
+signal serial_state : SERIAL_STATE_TYPE;
+type CMD_STATE_TYPE is (IDLE, EXECUTE, BUSY_WAIT);
+signal cmd_state : CMD_STATE_TYPE;
+
+signal expect_response : std_logic;
+signal watchdog : unsigned(15 downto 0);
+
+-- Signals originally from sd_cmd_master (DELETE THIS COMMENT SOON)
+signal timeout_reg : unsigned(15 downto 0);
+signal int_status_reg : unsigned(4 downto 0);
+
+begin
+
+-- Form a signal indicating when a response is expected
+expect_response <= '0' when (cmd_index_i=0 or cmd_index_i=4 or cmd_index_i=15) else '1';
+
+-- Command Finite State Machine
+cmd_fsm_proc : process(sys_rst,sd_clk)
+begin
+ if (sys_rst='1') then
+ response_0_o <= (others=>'0');
+ response_1_o <= (others=>'0');
+ response_2_o <= (others=>'0');
+ response_3_o <= (others=>'0');
+ int_status_reg <= (others=>'0');
+ resp_len <= 0;
+ watchdog <= (others=>'0');
+ timeout_reg <= (others=>'0');
+ cmd_state <= IDLE;
+ cmd_buff <= (others=>'0');
+ elsif (sd_clk'event and sd_clk='1') then
+ watchdog <= watchdog+1;
+ case (cmd_state) is
+ when IDLE =>
+ -- Only CMD2, CMD9 and CMD10 have long responses...
+ if (cmd_index_i=2 or cmd_index_i=9 or cmd_index_i=10) then
+ resp_len <= 127;
+ else
+ resp_len <= 39;
+ end if;
+ cmd_buff(39 downto 38) <= "01";
+ cmd_buff(37 downto 32) <= cmd_index_i;
+ cmd_buff(31 downto 0) <= argument_i; --CMD_Argument
+ timeout_reg <= timeout_i;
+ watchdog <= (others=>'0');
+ if (start_i='1') then
+ int_status_reg <= (others=>'0');
+ end if;
+ -- State transition
+ if (start_i='1') then
+ response_0_o <= (others=>'0');
+ response_1_o <= (others=>'0');
+ response_2_o <= (others=>'0');
+ response_3_o <= (others=>'0');
+ cmd_state <= EXECUTE;
+ end if;
+
+ when EXECUTE =>
+ if (watchdog > timeout_reg) then
+ int_status_reg(INT_CMD_CTE) <= '1';
+ int_status_reg(INT_CMD_EI) <= '1';
+ response_0_o <= to_unsigned(16#55555555#,32);
+ response_1_o <= to_unsigned(16#55555555#,32);
+ response_2_o <= to_unsigned(16#55555555#,32);
+ response_3_o <= to_unsigned(16#55555555#,32);
+ cmd_state <= IDLE;
+ else --Incoming New Status
+ if (serial_state=FINISH_WR) then --Data available
+ -- CMD1 has "1111111" for the CRC field...
+ if (cmd_index_i/=1 and crc_ok='0') then
+ int_status_reg(INT_CMD_CCRCE) <= '1';
+ int_status_reg(INT_CMD_EI) <= '1';
+ end if;
+ if (resp_len=39 and cmd_index_i/=1 and cmd_buff(37 downto 32)/=resp_buff(125 downto 120)) then
+ int_status_reg(INT_CMD_CIE) <= '1';
+ int_status_reg(INT_CMD_EI) <= '1';
+ end if;
+ int_status_reg(INT_CMD_CC) <= '1';
+ if (expect_response/='0') then
+ response_0_o <= resp_buff(119 downto 88);
+ response_1_o <= resp_buff(87 downto 56);
+ response_2_o <= resp_buff(55 downto 24);
+ response_3_o <= resp_buff(23 downto 0) & "00000000";
+ end if;
+ -- end
+ end if; --Data avaible
+ end if; --Status change
+ -- State transition
+ if (watchdog > timeout_reg) then
+ cmd_state <= IDLE;
+ elsif (serial_state=FINISH_WR) then
+ cmd_state <= BUSY_WAIT;
+ end if;
+
+ when BUSY_WAIT =>
+ if (watchdog > timeout_reg) then
+ int_status_reg(INT_CMD_CTE) <= '1';
+ int_status_reg(INT_CMD_EI) <= '1';
+ cmd_state <= IDLE;
+ end if;
+ -- State transition
+ if (busy_i='0') then
+ cmd_state <= IDLE;
+ end if;
+
+ when others =>
+ cmd_state <= IDLE;
+
+ end case;
+
+ if (int_rst_i='1') then
+ int_status_reg <= (others=>'0');
+ end if;
+
+ end if;
+end process;
+int_status_o <= int_status_reg;
+
+
+
+--sd cmd input pad register
+process(sd_clk, sys_rst) -- JLC added sys_rst to sensitivity list.
+begin
+ if (sys_rst='1') then
+ cmd_dat_reg <= '0';
+-- elsif (sd_clk'event and sd_clk='0') then -- use falling edge, when data is stable
+ elsif (sd_clk'event and sd_clk='0') then -- use rising edge, per the specification
+ cmd_dat_reg <= sd_cmd_i;
+ end if;
+end process;
+
+--------------------------------------------
+-- CRC generator
+
+ crc0 : ucrc_ser
+ generic map (
+ POLYNOMIAL => "0001001",
+ INIT_VALUE => "0000000"
+ )
+ port map (
+ -- System clock and asynchronous reset
+ sys_clk => sd_clk,
+ sys_rst_n => crc_rst_n,
+ sys_clk_en => crc_enable,
+
+ -- Input and Control
+ clear_i => '0',
+ data_i => crc_bit,
+ flush_i => '0',
+
+ -- Output
+ match_o => open,
+ crc_o => crc_val
+ );
+
+--------------------------------------------
+-- This is the serial_state machine
+--------------------------------------------
+serial_fsm_proc : process(sd_clk, sys_rst)
+begin
+ if (sys_rst='1') then
+ serial_state <= INIT;
+ crc_enable <= '0';
+ resp_idx <= 0;
+ sd_cmd_oe_o <= '1';
+ sd_cmd_o <= '1';
+ resp_buff <= (others=>'0');
+ crc_rst_n <= '0';
+ crc_bit <= '0';
+ crc_in <= (others=>'0');
+ crc_ok <= '0';
+ counter <= 0;
+ elsif (sd_clk'event and sd_clk='1') then
+
+ case (serial_state) is
+
+ when INIT =>
+ counter <= counter+1;
+ sd_cmd_oe_o <= '1';
+ sd_cmd_o <= '1';
+ if (counter >= INIT_DELAY) then
+ serial_state <= IDLE;
+ end if;
+
+ when IDLE =>
+ sd_cmd_oe_o <= '0'; --Put CMD to Z
+ counter <= 0;
+ crc_rst_n <= '0';
+ crc_enable <= '0';
+ resp_idx <= 0;
+ if (start_i='1') then
+ serial_state <= SETUP_CRC;
+ resp_buff <= (others=>'0');
+ end if;
+
+ when SETUP_CRC =>
+ crc_rst_n <= '1';
+ crc_enable <= '1';
+ crc_bit <= cmd_buff(CMD_SIZE-1-counter);
+ serial_state <= WRITE;
+
+ when WRITE =>
+ if (counter < BITS_TO_SEND-8) then -- 1->40 CMD, (41 <= CNT <=47) CRC, 48 stop_bit
+ sd_cmd_oe_o <= '1';
+ sd_cmd_o <= cmd_buff(CMD_SIZE-1-counter);
+ if (counter < BITS_TO_SEND-9) then --1 step ahead
+ crc_bit <= cmd_buff((CMD_SIZE-1-counter)-1);
+ else
+ crc_enable <= '0';
+ end if;
+ elsif (counter < BITS_TO_SEND-1) then
+ crc_enable <= '0';
+ sd_cmd_o <= crc_val(BITS_TO_SEND-counter-2);
+ sd_cmd_oe_o <= '1';
+ elsif (counter = BITS_TO_SEND-1) then
+ sd_cmd_oe_o <= '1';
+ sd_cmd_o <= '1';
+ else
+ sd_cmd_oe_o <= '0';
+ sd_cmd_o <= '1';
+ end if;
+ counter <= counter+1;
+
+ if (counter >= BITS_TO_SEND and expect_response='1') then
+ serial_state <= READ_WAIT;
+ elsif (counter >= BITS_TO_SEND) then
+ serial_state <= FINISH_WR;
+ end if;
+
+ when READ_WAIT =>
+ crc_enable <= '0';
+ crc_rst_n <= '0';
+ counter <= 1;
+ sd_cmd_oe_o <= '0';
+ resp_buff(RESP_SIZE-1) <= cmd_dat_reg;
+ if (cmd_dat_reg='0') then
+ serial_state <= READ;
+ end if;
+
+ when READ =>
+ crc_rst_n <= '1';
+ if ((resp_len/=RESP_SIZE-1) or (counter>7)) then
+ crc_enable <= '1';
+ end if;
+ sd_cmd_oe_o <= '0';
+ if (counter <= resp_len) then
+ if (counter < 8) then --1+1+6 (S,T,Index)
+ resp_buff(RESP_SIZE-1-counter) <= cmd_dat_reg;
+ else
+ resp_idx <= resp_idx + 1;
+ resp_buff(RESP_SIZE-9-resp_idx) <= cmd_dat_reg;
+ end if;
+ crc_bit <= cmd_dat_reg;
+ elsif (counter-resp_len <= 7) then
+ crc_in((resp_len+7)-counter) <= cmd_dat_reg;
+ crc_enable <= '0';
+ else
+ crc_enable <= '0';
+ if (crc_in = crc_val) then
+ crc_ok <= '1';
+ else
+ crc_ok <= '0';
+ end if;
+ end if;
+ counter <= counter + 1;
+ if (counter >= resp_len+8) then
+ serial_state <= FINISH_WR;
+ end if;
+
+ when FINISH_WR =>
+ crc_enable <= '0';
+ crc_rst_n <= '0';
+ counter <= 0;
+ sd_cmd_oe_o <= '0';
+ serial_state <= IDLE;
+
+ when others =>
+ serial_state <= INIT;
+
+ end case;
+
+ end if;
+end process;
+
+end beh;
+
+----------------------------------------------------------------------
+---- ----
+---- WISHBONE SD Card Controller IP Core ----
+---- ----
+---- sd_data_8bit_host.vhd ----
+---- ----
+---- This file is part of the WISHBONE SD Card ----
+---- Controller IP Core project ----
+---- http:--opencores.org/project,sd_card_controller ----
+---- ----
+---- Description ----
+---- Module resposible for sending and receiving data through ----
+---- sd/mmc card data interface ----
+---- ----
+---- Author(s): ----
+---- - John Clayton, morianton@gmail.com ----
+---- ----
+----------------------------------------------------------------------
+---- ----
+---- Copyright (C) 2016 Authors ----
+---- ----
+---- Based on original work by ----
+---- Adam Edvardsson (adam.edvardsson@orsoc.se) ----
+---- ----
+---- Copyright (C) 2009 Authors ----
+---- ----
+---- 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 Lesser General ----
+---- Public License as published by the Free Software Foundation; ----
+---- either version 2.1 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 Lesser General Public License for more ----
+---- details. ----
+---- ----
+---- You should have received a copy of the GNU Lesser General ----
+---- Public License along with this source; if not, download it ----
+---- from http:--www.opencores.org/lgpl.shtml ----
+---- ----
+-- Author: John Clayton --
+-- Update: June 11, 2016 Added bustest_w_i and bustest_r_i, plus --
+-- bustest_res_o result output. --
+---- ----
+----------------------------------------------------------------------
+--
+-- Explanation:
+-- bustest_res_o values are:
+-- 000 = BUSTEST_R (CMD14) not yet performed
+-- 001 = 1 bit data width
+-- 010 = 4 bit data width
+-- 011 = 8 bit data width
+-- 100 = Unspecified Error
+--
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.sd_host_pack.all;
+use work.ucrc_pack.all;
+
+entity sd_data_8bit_host is
+ port(
+ sd_clk : in std_logic;
+ sys_rst : 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_siz_o : out unsigned(1 downto 0);
+ sd_dat_oe_o : out std_logic;
+ sd_dat_o : out unsigned(7 downto 0);
+ sd_dat_i : in unsigned(7 downto 0);
+ --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);
+ 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;
+ bustest_res_o : out unsigned(2 downto 0);
+ sd_dat_busy_o : out std_logic;
+ fsm_busy_o : out std_logic;
+ crc_ok_o : out std_logic
+ );
+end sd_data_8bit_host;
+
+architecture beh of sd_data_8bit_host is
+
+-- Internal constants
+
+-- 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(BLKSIZE_W+3 downto 0);
+ --State Machine
+type FSM_STATE_TYPE is (IDLE, WRITE_DAT, CHECK_CRC_STATUS, WRITE_BUSY,
+ READ_WAIT, READ_DAT, SEND_BUSTEST,
+ READ_BUSTEST_WAIT, READ_BUSTEST, ANALYZE_BUSTEST);
+signal state : FSM_STATE_TYPE;
+
+signal crc_s_cnt : unsigned(2 downto 0);
+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_s : 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 bustest_x : unsigned(7 downto 0);
+
+begin
+
+--sd data input pad register
+process(sd_clk)
+begin
+ if (sd_clk'event and sd_clk='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,
+ 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 (dat_reg(0)='0') else '0';
+-- Provide external bus size signals, for controlling data bus tri-states
+sd_dat_siz_o <= "10" when state=SEND_BUSTEST else bus_size_i;
+
+-- Create bus test analysis, by XORing the two returned patterns
+-- together.
+bustest_x <= bustest_0 xor bustest_1;
+
+fsm_proc : process(sys_rst,sd_clk)
+begin
+ if (sys_rst='1') 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_in <= (others=>'0');
+ sd_dat_o <= (others=>'0');
+ crc_s_cnt <= (others=>'0');
+ crc_s <= (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');
+ bustest_res_o <= (others=>'0');
+ elsif (sd_clk'event and sd_clk='1') then
+ case(state) is
+ when IDLE =>
+ 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);
+ crc_s_cnt <= (others=>'0');
+ crc_s <= (others=>'0');
+ rx_dat_we_o <= '0';
+ tx_dat_rd_o <= '0';
+ data_index <= (others=>'1');
+ 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
+ if (d_read_i='0' and d_write_i='1' and bustest_w_i='0' and bustest_r_i='0') then
+ state <= WRITE_DAT;
+ elsif (d_read_i='1' and d_write_i='0' and bustest_w_i='0' and bustest_r_i='0') then
+ state <= READ_WAIT;
+ elsif (d_read_i='0' and d_write_i='0' and bustest_w_i='1' and bustest_r_i='0') then
+ data_cycles <= to_unsigned(24,data_cycles'length);
+ state <= SEND_BUSTEST;
+ elsif (d_read_i='0' and d_write_i='0' and bustest_w_i='0' and bustest_r_i='1') 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;
+ -- Send out first pattern
+ if (transf_cnt = 2) then
+ sd_dat_o <= "10101010";
+ end if;
+ -- Send out second pattern
+ if (transf_cnt = 3) then
+ sd_dat_o <= "01010101";
+ end if;
+ -- Send out zeros
+ 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 (transf_cnt >= data_cycles+1) then
+ transf_cnt <= (others=>'0');
+ state <= IDLE;
+ end if;
+
+ when READ_BUSTEST_WAIT =>
+ sd_dat_oe_o <= '0';
+ transf_cnt <= (others=>'0');
+ bustest_0 <= (others=>'0');
+ bustest_1 <= (others=>'0');
+ bustest_res_o <= (others=>'0');
+ -- state transition
+ if (start_bit='1') then
+ state <= READ_BUSTEST;
+ end if;
+
+ when READ_BUSTEST =>
+ transf_cnt <= transf_cnt+1;
+ if (transf_cnt = 0) then
+ bustest_0 <= dat_reg;
+ end if;
+ if (transf_cnt = 1) then
+ bustest_1 <= dat_reg;
+ end if;
+ -- state transition
+ -- No CRC status response is needed
+ -- Look for stop bits
+ if (dat_reg = "11111111") then
+ state <= ANALYZE_BUSTEST;
+ end if;
+
+ when ANALYZE_BUSTEST =>
+ if (bustest_x="00000001") then
+ bustest_res_o <= "001";
+ elsif (bustest_x="00001111") then
+ bustest_res_o <= "010";
+ elsif (bustest_x="11111111") then
+ bustest_res_o <= "011";
+ else
+ bustest_res_o <= "100";
+ end if;
+ state <= IDLE;
+
+ when WRITE_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';
+ 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);
+ elsif ((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;
+ elsif (transf_cnt = data_cycles+18) then -- stop bits
+ sd_dat_o <= "11111111";
+ elsif (transf_cnt >= data_cycles+19) then
+ sd_dat_oe_o <= '0';
+ end if;
+ -- state transition
+ -- There are two clocks of bus turnaround time, plus one extra
+ -- because of the data input register, then the start bit of
+ -- the CRC status occurs.
+ if (d_stop_i='1') then
+ state <= IDLE;
+ elsif (transf_cnt = data_cycles+23) then
+ if (start_bit='1') then
+ state <= CHECK_CRC_STATUS;
+ else
+ transf_cnt <= (others=>'0');
+ blkcnt_reg <= blkcnt_reg-1;
+ crc_rst_n <= '0';
+ crc_c <= to_unsigned(16,crc_c'length);
+ crc_s_cnt <= (others=>'0');
+ if (blkcnt_reg>1) then
+ state <= WRITE_DAT;
+ else
+ state <= IDLE;
+ end if;
+ end if;
+ end if;
+
+ when CHECK_CRC_STATUS =>
+ if (crc_s_cnt < 4) then
+ crc_s(to_integer(crc_s_cnt)) <= dat_reg(0);
+ end if;
+ crc_s_cnt <= crc_s_cnt+1;
+ busy_int <= '1';
+ -- state transition
+ if (crc_s_cnt = 4) then
+ if (crc_s="1010") then
+ crc_ok_l <= '1';
+ else
+ crc_ok_l <= '0';
+ end if;
+ state <= WRITE_BUSY;
+ end if;
+
+ when WRITE_BUSY =>
+ busy_int <= not dat_reg(0);
+ transf_cnt <= (others=>'0');
+ -- state transition
+ if (busy_int='0') then
+ blkcnt_reg <= blkcnt_reg-1;
+ crc_rst_n <= '0';
+ crc_c <= to_unsigned(16,crc_c'length);
+ crc_s_cnt <= (others=>'0');
+ if (blkcnt_reg>1 and crc_ok_l='1') then
+ state <= WRITE_DAT;
+ elsif (busy_int='0') then
+ state <= IDLE;
+ end if;
+ end if;
+
+ when READ_WAIT =>
+ 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 (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
+ if (d_stop_i='1') then
+ state <= IDLE;
+ elsif (transf_cnt=(data_cycles+17) and blkcnt_reg>1 and crc_ok_l='1') then
+ blkcnt_reg <= blkcnt_reg-1;
+ state <= READ_WAIT;
+ elsif (transf_cnt=data_cycles+17) then
+ state <= IDLE;
+ end if;
+
+ when others =>
+ null;
+
+ end case;
+ end if;
+end process;
+
+end beh;
+
+----------------------------------------------------------------------
+---- ----
+---- WISHBONE SD Card Controller IP Core ----
+---- ----
+---- sd_controller_8bit.vhd ----
+---- ----
+---- This file is part of the WISHBONE SD Card ----
+---- Controller IP Core project ----
+---- http:--opencores.org/project,sd_card_controller ----
+---- ----
+---- Description ----
+---- Top level entity. ----
+---- This core is based on the "sd card controller" project from ----
+---- http:--opencores.org/project,sdcard_mass_storage_controller ----
+---- but has been largely rewritten. A lot of effort has been ----
+---- made to make the core more generic and easily usable ----
+---- with OSs like Linux. ----
+---- - data transfer commands are not fixed ----
+---- - data transfer block size is configurable ----
+---- - multiple block transfer support ----
+---- - R2 responses (136 bit) support ----
+---- ----
+---- Author(s): ----
+---- - John Clayton, morianton@gmail.com ----
+---- ----
+----------------------------------------------------------------------
+---- ----
+---- Copyright (C) 2016 Authors ----
+---- ----
+---- Based on original work by ----
+---- Adam Edvardsson (adam.edvardsson@orsoc.se) ----
+---- ----
+---- Copyright (C) 2009 Authors ----
+---- ----
+---- 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 Lesser General ----
+---- Public License as published by the Free Software Foundation; ----
+---- either version 2.1 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 Lesser General Public License for more ----
+---- details. ----
+---- ----
+---- You should have received a copy of the GNU Lesser General ----
+---- Public License along with this source; if not, download it ----
+---- from http:--www.opencores.org/lgpl.shtml ----
+---- ----
+----------------------------------------------------------------------
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+
+library work;
+use work.sd_host_pack.all;
+use work.dds_pack.all;
+use work.fifo_pack.all;
+use work.convert_pack.all;
+use work.signal_conditioning_pack.all;
+
+entity sd_controller_8bit_bram is
+ port (
+ -- WISHBONE common
+ wb_clk_i : in std_logic; -- system clock
+ wb_rst_i : in std_logic; -- asynchronous
+ -- WISHBONE slave (register interface)
+ wb_dat_i : in unsigned(31 downto 0);
+ wb_dat_o : out unsigned(31 downto 0);
+ wb_adr_i : in unsigned(3 downto 0);
+ wb_we_i : in std_logic;
+ wb_cyc_i : in std_logic;
+ wb_ack_o : out std_logic;
+ -- Dedicated BRAM port without acknowledge.
+ -- Access cycles must complete immediately.
+ -- (data to cross clock domains by this dual-ported BRAM)
+ bram_clk_o : out std_logic; -- Same as sd_clk_o_pad
+ bram_dat_o : out unsigned(7 downto 0);
+ bram_dat_i : in unsigned(7 downto 0);
+ bram_adr_o : out unsigned(31 downto 0);
+ bram_we_o : out std_logic;
+ bram_cyc_o : out std_logic;
+ --SD Card Interface
+ sd_cmd_i : in std_logic;
+ sd_cmd_o : out std_logic;
+ sd_cmd_oe_o : out std_logic;
+ 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);
+ sd_clk_o_pad : out std_logic;
+ -- Interrupt outputs
+ int_cmd_o : out std_logic;
+ int_data_o : out std_logic
+ );
+end sd_controller_8bit_bram;
+
+architecture beh of sd_controller_8bit_bram is
+
+--SD clock
+signal sd_clk_l : std_logic; --sd_clk used in the system
+signal sd_clk_en_l : std_logic; --clock enable pulse of sd_clk
+signal combo_rst : std_logic; -- combines two reset signals
+signal combo_rst_n : std_logic;
+signal wb_ack_r1 : std_logic;
+signal wb_ack_r2 : std_logic;
+
+signal cmd_start_pend : std_logic;
+signal cmd_start : std_logic;
+signal cmd_start_r1 : std_logic;
+signal cmd_with_data : std_logic;
+signal sd_data_rd : std_logic;
+
+ -- Related to BRAM interface port
+signal bram_cyc_l : std_logic;
+signal offset : unsigned(31 downto 0);
+
+ -- Related to data master
+signal d_write : std_logic;
+signal d_read : std_logic;
+signal bustest_r : std_logic;
+signal bustest_w : std_logic;
+signal bustest_res : unsigned(2 downto 0);
+signal sd_dat_busy : std_logic;
+signal data_busy : std_logic;
+signal data_crc_ok : std_logic;
+signal bram_rd : std_logic;
+signal bram_we : std_logic;
+
+signal cmd_int_rst_pend : std_logic;
+signal cmd_int_rst : std_logic;
+signal cmd_int_rst_edge : std_logic;
+signal data_int_rst_pend : std_logic;
+signal data_int_rst : std_logic;
+signal data_int_rst_edge : std_logic;
+
+ --SD Data Master State Machine
+type DM_STATE_TYPE is (IDLE, WAIT_FOR_CMD_INT, DATA_TX_START, DATA_TX,
+ DATA_RX, BUSTEST_ACTIVE, BUSTEST_W_START);
+signal dm_state : DM_STATE_TYPE;
+
+-- registers
+signal argument_reg : unsigned(31 downto 0);
+signal cmd_index_reg : unsigned(5 downto 0);
+signal blk_size_reg : unsigned(BLKSIZE_W-1 downto 0);
+signal blk_count_reg : unsigned(BLKCNT_W-1 downto 0);
+signal resp_0_reg : unsigned(31 downto 0);
+signal resp_1_reg : unsigned(31 downto 0);
+signal resp_2_reg : unsigned(31 downto 0);
+signal resp_3_reg : unsigned(31 downto 0);
+ -- Fields of the settings register
+signal bus_siz_reg : unsigned(1 downto 0);
+signal sw_rst_reg : std_logic;
+signal d_stop : std_logic;
+signal sd_freq_reg : unsigned(31 downto 0);
+signal timeout_reg : unsigned(15 downto 0);
+ -- Registers 0x9..0xC are interrupt related
+signal cmd_int_status_reg : unsigned(4 downto 0);
+signal cmd_int_enable_reg : unsigned(4 downto 0);
+signal data_int_status_reg : unsigned(2 downto 0);
+signal data_int_enable_reg : unsigned(2 downto 0);
+ -- Register holding current bus address
+signal dma_adr_reg : unsigned(31 downto 0);
+
+begin
+
+ -- Register read mux
+ with (to_integer(wb_adr_i)) select
+ wb_dat_o <=
+ u_resize(blk_size_reg,32) when 0,
+ u_resize(blk_count_reg,32) when 1,
+ u_resize(cmd_index_reg,32) when 2,
+ argument_reg when 3,
+ resp_0_reg when 4,
+ resp_1_reg when 5,
+ resp_2_reg when 6,
+ resp_3_reg when 7,
+ timeout_reg & "00000" & bustest_res & "000" & sw_rst_reg & "00" & bus_siz_reg when 8,
+ sd_freq_reg when 9,
+ u_resize(cmd_int_status_reg,32) when 10,
+ u_resize(cmd_int_enable_reg,32) when 11,
+ u_resize(data_int_status_reg,32) when 12,
+ u_resize(data_int_enable_reg,32) when 13,
+ dma_adr_reg when 14,
+ str2u("55555555",32) when others;
+
+ -- Register Writing Process
+reg_wr_proc : process(wb_rst_i, wb_clk_i)
+begin
+ if (wb_rst_i='1') then
+ argument_reg <= (others=>'0');
+ cmd_index_reg <= (others=>'0');
+ blk_size_reg <= to_unsigned(512,blk_size_reg'length);
+ blk_count_reg <= to_unsigned(1,blk_count_reg'length);
+ bus_siz_reg <= "00";
+ sw_rst_reg <= '0';
+ sd_freq_reg <= str2u("010624DD",sd_freq_reg'length); -- Set for 400 kHz default (100 MHz sys_clk)
+ timeout_reg <= to_unsigned(1000,timeout_reg'length);
+ cmd_int_rst_pend <= '0';
+ cmd_int_rst <= '0';
+ d_stop <= '0';
+ cmd_int_enable_reg <= (others=>'0');
+ data_int_rst_pend <= '0';
+ data_int_rst <= '0';
+ data_int_enable_reg <= (others=>'0');
+ wb_ack_r1 <= '0';
+ wb_ack_r2 <= '0';
+ cmd_start_pend <= '0';
+ cmd_start <= '0';
+ cmd_start_r1 <= '0';
+ dma_adr_reg <= (others=>'0');
+ elsif (wb_clk_i'event and wb_clk_i='1') then
+ -- default values, clocked on sd_clk_en_l
+ if (sd_clk_en_l='1') then
+ cmd_start <= '0';
+ data_int_rst <= '0';
+ cmd_int_rst <= '0';
+ d_stop <= '0';
+ end if;
+ -- signals raised on sd_clk_en_l
+ -- higher priority than the default
+ if (sd_clk_en_l='1') then
+ if (cmd_start_pend='1') then
+ cmd_start <= '1';
+ cmd_start_pend <= '0';
+ end if;
+ if (data_int_rst_pend='1') then
+ data_int_rst <= '1';
+ data_int_rst_pend <= '0';
+ end if;
+ if (cmd_int_rst_pend='1') then
+ cmd_int_rst <= '1';
+ cmd_int_rst_pend <= '0';
+ end if;
+ end if;
+ -- delayed version
+ cmd_start_r1 <= cmd_start;
+
+
+ if (wb_ack_r1='1' and wb_ack_r2='0') then
+ if (wb_we_i='1') then
+ case (to_integer(wb_adr_i)) is
+ when 0 =>
+ blk_size_reg <= wb_dat_i(BLKSIZE_W-1 downto 0);
+
+ when 1 =>
+ blk_count_reg <= wb_dat_i(BLKCNT_W-1 downto 0);
+
+ when 2 =>
+ cmd_index_reg <= wb_dat_i(5 downto 0);
+
+ when 3 =>
+ argument_reg <= wb_dat_i;
+ cmd_start_pend <= '1';
+
+ when 8 =>
+ bus_siz_reg <= wb_dat_i(1 downto 0);
+ sw_rst_reg <= wb_dat_i(4);
+ d_stop <= wb_dat_i(5); -- write only bit
+ timeout_reg <= wb_dat_i(31 downto 16);
+
+ when 9 =>
+ sd_freq_reg <= wb_dat_i;
+
+ when 10 =>
+ cmd_int_rst_pend <= '1';
+
+ when 11 =>
+ cmd_int_enable_reg <= wb_dat_i(cmd_int_enable_reg'length-1 downto 0);
+
+ when 12 =>
+ data_int_rst_pend <= '1';
+
+ when 13 =>
+ data_int_enable_reg <= wb_dat_i(data_int_enable_reg'length-1 downto 0);
+
+ when 14 =>
+ dma_adr_reg <= wb_dat_i;
+
+ when others =>
+ null;
+ end case;
+ end if;
+ end if;
+ -- Detect rising edge of wb_cyc_i
+ wb_ack_r1 <= wb_cyc_i;
+ wb_ack_r2 <= wb_ack_r1;
+ end if;
+end process;
+
+ -- Provide Wishbone bus cycle acknowledge
+ wb_ack_o <= wb_ack_r1;
+
+ -- Form a combined reset signal
+ combo_rst <= wb_rst_i or sw_rst_reg;
+ combo_rst_n <= not combo_rst;
+
+-- SD Card clock generation
+-- A DDS is used.
+sd_clk_dds : dds_squarewave
+ generic map(
+ ACC_BITS => sd_freq_reg'length -- Bit width of DDS phase accumulator
+ )
+ port map(
+
+ sys_rst_n => combo_rst_n,
+ sys_clk => wb_clk_i,
+ sys_clk_en => '1',
+
+ -- Frequency setting
+ freq_i => sd_freq_reg,
+
+ -- Output
+ pulse_o => sd_clk_en_l,
+ squarewave_o => sd_clk_l
+ );
+sd_clk_o_pad <= sd_clk_l;
+
+
+cmd_host_0 : sd_cmd_host
+ port map(
+ sd_clk => sd_clk_l,
+ sys_rst => combo_rst,
+ -- Control and settings
+ start_i => cmd_start_r1,
+ int_rst_i => cmd_int_rst_edge,
+ busy_i => sd_dat_busy,
+ cmd_index_i => cmd_index_reg,
+ argument_i => argument_reg,
+ timeout_i => timeout_reg,
+ int_status_o => cmd_int_status_reg,
+ response_0_o => resp_0_reg,
+ response_1_o => resp_1_reg,
+ response_2_o => resp_2_reg,
+ response_3_o => resp_3_reg,
+ -- SD/MMC card command signals
+ sd_cmd_i => sd_cmd_i,
+ sd_cmd_o => sd_cmd_o,
+ sd_cmd_oe_o => sd_cmd_oe_o
+ );
+
+cmd_with_data <= '1' when cmd_index_reg=20 or cmd_index_reg=24 or cmd_index_reg=25 or
+ cmd_index_reg=8 or cmd_index_reg=11 or cmd_index_reg=17 or
+ cmd_index_reg=18 or cmd_index_reg=14 or cmd_index_reg=19 else '0';
+sd_data_rd <= '1' when cmd_index_reg=8 or cmd_index_reg=11 or
+ cmd_index_reg=17 or cmd_index_reg=18 else '0';
+
+ -- SD Data Master Finite State Machine
+d_read <= '1' when dm_state=IDLE and cmd_start_r1='1' and cmd_with_data='1' and sd_data_rd='1' else '0';
+d_write <= '1' when dm_state=DATA_TX_START else '0';
+bustest_r <= '1' when dm_state=IDLE and cmd_start_r1='1' and cmd_index_reg=14 else '0';
+bustest_w <= '1' when dm_state=BUSTEST_W_START else '0';
+
+dm_fsm_proc : process(combo_rst, sd_clk_l)
+begin
+ if (combo_rst='1') then
+ offset <= (others=>'0');
+ data_int_status_reg <= (others=>'0');
+ dm_state <= IDLE;
+ elsif (sd_clk_l'event and sd_clk_l='1') then
+ case (dm_state) is
+ when IDLE =>
+ offset <= (others=>'0');
+ -- state transition
+ if (cmd_start_r1='1') then
+ if (cmd_with_data='1') then
+ if (cmd_index_reg=14) then -- BUSTEST_R
+ dm_state <= BUSTEST_ACTIVE;
+ elsif (sd_data_rd='1') then -- Reading
+ dm_state <= DATA_RX;
+ else
+ dm_state <= WAIT_FOR_CMD_INT;
+ end if;
+ end if;
+ end if;
+
+ when BUSTEST_ACTIVE =>
+ if (data_busy='0') then --Transfer complete
+ dm_state <= IDLE;
+ end if;
+
+ when BUSTEST_W_START =>
+ dm_state <= BUSTEST_ACTIVE;
+
+ when WAIT_FOR_CMD_INT =>
+ if (cmd_int_status_reg(INT_CMD_CC)='1') then
+ if (cmd_index_reg=19) then
+ dm_state <= BUSTEST_W_START;
+ else
+ dm_state <= DATA_TX_START;
+ end if;
+ elsif (cmd_int_status_reg(INT_CMD_EI)='1') then
+ dm_state <= IDLE;
+ end if;
+
+ when DATA_TX_START =>
+ dm_state <= DATA_TX;
+
+ when DATA_TX =>
+ if (bram_cyc_l='1') then
+ offset <= offset+1;
+ end if;
+ if (data_busy='0') then --Transfer complete
+ if (data_crc_ok='0') then --Wrong CRC
+ data_int_status_reg(INT_DATA_CCRCE) <= '1';
+ else
+ data_int_status_reg(INT_DATA_CC) <= '1';
+ end if;
+ dm_state <= IDLE;
+ end if;
+
+ when DATA_RX =>
+ if (bram_cyc_l='1') then
+ offset <= offset+1;
+ end if;
+ if (data_busy='0') then --Transfer complete
+ if (data_crc_ok='0') then --Wrong CRC
+ data_int_status_reg(INT_DATA_CCRCE) <= '1';
+ else
+ data_int_status_reg(INT_DATA_CC) <= '1';
+ end if;
+ dm_state <= IDLE;
+ end if;
+
+ when others =>
+ null;
+
+ end case;
+
+ if (data_int_rst_edge='1') then
+ data_int_status_reg <= (others=>'0');
+ end if;
+ end if;
+end process;
+
+
+sd_data_host0 : sd_data_8bit_host
+ port map(
+ sd_clk => sd_clk_l,
+ sys_rst => combo_rst,
+ --Tx Fifo
+ tx_dat_i => bram_dat_i,
+ tx_dat_rd_o => bram_rd,
+ --Rx Fifo
+ rx_dat_o => bram_dat_o,
+ rx_dat_we_o => bram_we,
+ --tristate data
+ sd_dat_siz_o => sd_dat_siz_o,
+ sd_dat_oe_o => sd_dat_oe_o,
+ sd_dat_o => sd_dat_o,
+ sd_dat_i => sd_dat_i,
+ --Control signals
+ blksize_i => blk_size_reg,
+ bus_size_i => bus_siz_reg,
+ blkcnt_i => blk_count_reg,
+ d_stop_i => d_stop,
+ d_read_i => d_read,
+ d_write_i => d_write,
+ bustest_w_i => bustest_w,
+ bustest_r_i => bustest_r,
+ bustest_res_o => bustest_res,
+ sd_dat_busy_o => sd_dat_busy,
+ fsm_busy_o => data_busy,
+ crc_ok_o => data_crc_ok
+ );
+
+bram_clk_o <= not sd_clk_l;
+bram_we_o <= bram_we;
+bram_cyc_l <= bram_rd or bram_we;
+bram_cyc_o <= bram_cyc_l;
+bram_adr_o <= dma_adr_reg+offset;
+
+cmd_int_rst_edge_detect : edge_detector
+ generic map(
+ DETECT_RISING => 1,
+ DETECT_FALLING => 0
+ )
+ port map(
+ -- System Clock and Clock Enable
+ sys_rst_n => combo_rst_n,
+ sys_clk => sd_clk_l,
+ sys_clk_en => '1',
+
+ -- Input Signal
+ sig_i => cmd_int_rst,
+
+ -- Output pulse
+ pulse_o => cmd_int_rst_edge
+ );
+
+data_int_rst_edge_detect : edge_detector
+ generic map(
+ DETECT_RISING => 1,
+ DETECT_FALLING => 0
+ )
+ port map(
+ -- System Clock and Clock Enable
+ sys_rst_n => combo_rst_n,
+ sys_clk => sd_clk_l,
+ sys_clk_en => '1',
+
+ -- Input Signal
+ sig_i => data_int_rst,
+
+ -- Output pulse
+ pulse_o => data_int_rst_edge
+ );
+
+-- provide outputs
+int_cmd_o <= '1' when (cmd_int_status_reg or cmd_int_enable_reg)/=0 else '0';
+int_data_o <= '1' when (data_int_status_reg or data_int_enable_reg)/=0 else '0';
+
+end beh;
+
Index: trunk/rtl/VHDL/signal_conditioning_pack.vhd
===================================================================
--- trunk/rtl/VHDL/signal_conditioning_pack.vhd (nonexistent)
+++ trunk/rtl/VHDL/signal_conditioning_pack.vhd (revision 15)
@@ -0,0 +1,743 @@
+--------------------------------------------------------------------------
+-- Package
+--
+--
+
+library IEEE;
+use IEEE.STD_LOGIC_1164.ALL;
+use IEEE.NUMERIC_STD.ALL;
+use IEEE.MATH_REAL.ALL;
+
+package signal_conditioning_pack is
+
+ component edge_detector
+ generic(
+ DETECT_RISING : natural;
+ DETECT_FALLING : natural
+ );
+ port (
+ -- System Clock and Clock Enable
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Input Signal
+ sig_i : in std_logic;
+
+ -- Output pulse
+ pulse_o : out std_logic
+
+ );
+ end component;
+
+ component leaky_integrator
+ generic(
+ LEAK_FACTOR_BITS : natural;
+ LEAK_FACTOR : natural;
+ INTEGRATOR_BITS : natural -- Bits in the integrating accumulator
+ );
+ port (
+ -- System Clock and Clock Enable
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Settings
+ input : in signed(INTEGRATOR_BITS-1 downto 0);
+
+ -- Integration Result
+ integrator : out signed(INTEGRATOR_BITS-1 downto 0)
+
+ );
+ end component;
+
+ component leaky_integrator_with_digital_output
+ generic(
+ FACTOR_BITS : natural; -- Make this less than INTEGRATOR_BITS
+ HYSTERESIS_BITS : natural; -- Make this less than INTEGRATOR_BITS
+ INTEGRATOR_BITS : natural -- Bits in the integrating accumulator
+ );
+ port (
+ -- System Clock and Clock Enable
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Settings
+ input : in signed(INTEGRATOR_BITS-1 downto 0);
+ leak_factor : in signed(FACTOR_BITS-1 downto 0);
+ hysteresis : in unsigned(HYSTERESIS_BITS-1 downto 0);
+
+ -- Integration Result
+ integrator : out signed(INTEGRATOR_BITS-1 downto 0);
+
+ -- Conditioned Digital Output Signal
+ output : out std_logic
+ );
+ end component;
+
+ component multi_stage_leaky_integrator
+ generic(
+ STAGES : natural;
+ LEAK_FACTOR_BITS : natural; -- Inversely related to LP corner frequency. (Min=1)
+ HYSTERESIS_BITS : natural; -- Make this less than INTEGRATOR_BITS
+ INTEGRATOR_BITS : natural -- Bits in each integrating accumulator
+ );
+ port (
+ -- System Clock and Clock Enable
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Settings
+ input : in signed(INTEGRATOR_BITS-1 downto 0);
+ hysteresis : in unsigned(HYSTERESIS_BITS-1 downto 0);
+
+ -- Final Stage Integration Result
+ integrator : out signed(INTEGRATOR_BITS-1 downto 0);
+
+ -- Conditioned Digital Output Signal
+ output : out std_logic
+ );
+ end component;
+
+ component integrating_pulse_stretcher
+ generic(
+ MIN_CLKS : natural; -- pulses below this many clocks are ignored
+ RETRIGGERABLE : natural; -- 1=restart on new pulses. 0=decay to zero before restarting
+ STRETCH_FACTOR : natural; -- 0=don't stretch, 1=double, 2=triple
+ INITIAL_OFFSET : natural; -- Value initially loaded into integrator
+ INTEGRATOR_BITS : natural -- Bits in the integrating accumulator
+ );
+ port (
+ -- System Clock and Clock Enable
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Input
+ pulse_i : in std_logic;
+
+ -- Output
+ pulse_o : out std_logic
+
+ );
+ end component;
+
+end signal_conditioning_pack;
+
+-------------------------------------------------------------------------------
+-- Edge Detector
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Date : Nov. 1, 2013 Started Coding, drawing from various other sources.
+-- Created description. Simulated it and saw that it
+-- works.
+--
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This module is a super simple edge detector, which produces is high-going
+-- pulse whenever there is an edge on the input. The type of edge is
+-- selectable via generic.
+--
+-- The sys_clk_en affects the operation by extending the length of the pulse
+-- output beyond one single sys_clk cycle, as expected.
+--
+-- Detecting both rising and falling edges is allowed. Detecting neither is
+-- also allowed, but not recommended.
+--
+-- The sys_rst_n input is an asynchronous reset.
+
+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 edge_detector is
+ generic(
+ DETECT_RISING : natural := 1;
+ DETECT_FALLING : natural := 0
+ );
+ port (
+ -- System Clock and Clock Enable
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Input Signal
+ sig_i : in std_logic;
+
+ -- Output pulse
+ pulse_o : out std_logic
+
+ );
+ end edge_detector;
+
+architecture beh of edge_detector is
+
+ -- Constants
+
+ -- Functions & associated types
+
+ -- Signal Declarations
+ signal sig_r1 : std_logic;
+ signal pulse_r : std_logic;
+ signal pulse_f : std_logic;
+ signal pulse_b : std_logic;
+
+begin
+
+process (sys_clk, sys_rst_n)
+begin
+ if (sys_rst_n='0') then
+ sig_r1 <= '0';
+ elsif (sys_clk'event and sys_clk='1') then -- rising edge
+ if (sys_clk_en='1') then
+ sig_r1 <= sig_i;
+ end if;
+ end if;
+end process;
+
+-- The detection
+pulse_r <= '1' when sig_i='1' and sig_r1='0' else '0';
+pulse_f <= '1' when sig_i='0' and sig_r1='1' else '0';
+pulse_b <= sig_i xor sig_r1;
+
+-- The output
+pulse_o <= pulse_b when DETECT_RISING/=0 and DETECT_FALLING/=0 else
+ pulse_r when DETECT_RISING/=0 else
+ pulse_f when DETECT_FALLING/=0 else
+ '0'; -- Haha! Don't go there!
+
+end beh;
+
+-------------------------------------------------------------------------------
+-- Leaky Integrator
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Date : Oct. 11, 2013 Started Coding, drawing from various other sources.
+-- Created description. Simulated it and saw that it
+-- works.
+--
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This module is a pretty simple digital "leaky integrator" designed to low
+-- pass noisy signals by integrating them.
+--
+-- The first order differential equation is of the form:
+--
+-- dx/dt = -leak_factor*x + input
+--
+-- The input is discretized in both time and amplitude. A one bit digital
+-- input can be mapped to the "input" signal by using a positive value for
+-- '1' and a negative value for '0' Alternately, a signed DSP type signal
+-- can be used directly.
+--
+-- The "leak_factor" is a feedback term, so that "DC gain" is inversely
+-- proportional to the leak_factor.
+--
+-- Due to the presence of the feedback term, the integration's DC value, or
+-- constant term, gets "leaked" to zero over time. This is nice because
+-- the threshold centers around zero.
+--
+-- Hysteresis can be added so that the digital output transitions an amount
+-- above or below zero, depending on the current value of the output.
+--
+-- Clear as mud? Well, it's similar to a low-pass filter, and the hysteresis
+-- also helps remove noise on the input signal.
+--
+-- The sys_rst_n input is an asynchronous reset.
+
+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 leaky_integrator is
+ generic(
+ LEAK_FACTOR_BITS : natural := 10;
+ LEAK_FACTOR : natural := 10;
+ INTEGRATOR_BITS : natural := 16 -- Bits in the integrating accumulator
+ );
+ port (
+ -- System Clock and Clock Enable
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Settings
+ input : in signed(INTEGRATOR_BITS-1 downto 0);
+
+ -- Integration Result
+ integrator : out signed(INTEGRATOR_BITS-1 downto 0)
+
+ );
+ end leaky_integrator;
+
+architecture beh of leaky_integrator is
+
+ -- Constants
+
+ -- Functions & associated types
+
+ -- Signal Declarations
+ signal sum : signed(INTEGRATOR_BITS-1 downto 0);
+ signal delta : signed(INTEGRATOR_BITS-1 downto 0);
+ signal m_term : signed(INTEGRATOR_BITS+LEAK_FACTOR_BITS downto 0);
+
+begin
+
+-- The feedback term
+m_term <= sum*to_signed(LEAK_FACTOR,LEAK_FACTOR_BITS+1);
+
+-- The difference term
+delta <= input - s_resize_l(m_term,delta'length);
+
+-- The leaky integrator
+process (sys_clk, sys_rst_n)
+begin
+ if (sys_rst_n='0') then
+ sum <= to_signed(0,integrator'length);
+ elsif (sys_clk'event and sys_clk='1') then -- rising edge
+ if (sys_clk_en='1') then
+ sum <= sum + delta;
+ end if;
+ end if;
+end process;
+
+-- The outputs
+integrator <= sum;
+
+end beh;
+
+-------------------------------------------------------------------------------
+-- Leaky Integrator with conditioned Digital Output
+-------------------------------------------------------------------------------
+--
+-- Author: John Clayton
+-- Date : Oct. 11, 2013 Started Coding, drawing from various other sources.
+-- Created description. Simulated it and saw that it
+-- works.
+--
+--
+-- Description
+-------------------------------------------------------------------------------
+-- This module is a pretty simple digital "leaky integrator" designed to clean
+-- up noisy repetitive signals by integrating them, and applying thresholds
+-- to the integrated result.
+--
+-- The first order differential equation is of the form:
+--
+-- dx/dt = -leak_factor*x + input
+--
+-- The input is discretized in both time and amplitude. A one bit digital
+-- input can be mapped to the "input" signal by using a positive value for
+-- '1' and a negative value for '0'
+--
+-- The "leak_factor" is a feedback term, so that "DC gain" is inversely
+-- proportional to the leak_factor.
+--
+-- Due to the presence of the feedback term, the integration's DC value, or
+-- constant term, gets "leaked" to zero over time. This is nice because
+-- the threshold centers around zero.
+--
+-- Hysteresis can be added so that the digital output transitions an amount
+-- above or below zero, depending on the current value of the output.
+--
+-- Clear as mud? Well, it's similar to a low-pass filter, and the hysteresis
+-- also helps remove noise on the input signal.
+--
+-- The sys_rst_n input is an asynchronous reset.
+
+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 leaky_integrator_with_digital_output is
+ generic(
+ FACTOR_BITS : natural := 10; -- Make this less than INTEGRATOR_BITS
+ HYSTERESIS_BITS : natural := 10; -- Make this less than INTEGRATOR_BITS
+ INTEGRATOR_BITS : natural := 16 -- Bits in the integrating accumulator
+ );
+ port (
+ -- System Clock and Clock Enable
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Settings
+ input : in signed(INTEGRATOR_BITS-1 downto 0);
+ leak_factor : in signed(FACTOR_BITS-1 downto 0);
+ hysteresis : in unsigned(HYSTERESIS_BITS-1 downto 0);
+
+ -- Integration Result
+ integrator : out signed(INTEGRATOR_BITS-1 downto 0);
+
+ -- Conditioned Digital Output Signal
+ output : out std_logic
+ );
+ end leaky_integrator_with_digital_output;
+
+architecture beh of leaky_integrator_with_digital_output is
+
+ -- Constants
+
+ -- Functions & associated types
+
+ -- Signal Declarations
+ signal sum : signed(INTEGRATOR_BITS-1 downto 0);
+ signal delta : signed(INTEGRATOR_BITS-1 downto 0);
+ signal m_term : signed(INTEGRATOR_BITS+FACTOR_BITS-1 downto 0);
+ signal out_l : std_logic;
+ signal hp_term : signed(INTEGRATOR_BITS-1 downto 0);
+ signal hn_term : signed(INTEGRATOR_BITS-1 downto 0);
+
+begin
+
+-- The feedback term
+m_term <= sum*leak_factor;
+
+-- The difference term
+delta <= input - s_resize_l(m_term,delta'length);
+
+-- The leaky integrator
+process (sys_clk, sys_rst_n)
+begin
+ if (sys_rst_n='0') then
+ sum <= to_signed(0,integrator'length);
+ out_l <= '0';
+ elsif (sys_clk'event and sys_clk='1') then -- rising edge
+ if (sys_clk_en='1') then
+ sum <= sum + delta;
+ if (out_l='0') then
+ if (sum>hp_term) then
+ out_l <= '1';
+ end if;
+ else
+ if (sum=2.
+-- Between stages, an arithmetic shift right operation is inserted, which is
+-- intended to automatically scale the signal to fit the next integrator.
+--
+-- The hysteresis value is only applied at the final stage output, to derive
+-- the conditioned digital output signal.
+--
+-- The "leak_factor" is a feedback term, so that "DC gain" is inversely
+-- proportional to the leak_factor.
+--
+-- Due to the presence of the feedback term, the integration's DC value, or
+-- constant term, gets "leaked" to zero over time. This is nice because
+-- the threshold centers around zero.
+--
+-- Hysteresis can be added so that the digital output transitions an amount
+-- above or below zero, depending on the current value of the output.
+--
+-- Clear as mud? Well, it's similar to a low-pass filter, and the hysteresis
+-- also helps remove noise on the input signal.
+--
+-- The more stages are used, the more low-pass filtering occurs.
+--
+-- The sys_rst_n input is an asynchronous reset.
+
+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.signal_conditioning_pack.all;
+
+ entity multi_stage_leaky_integrator is
+ generic(
+ STAGES : natural := 2;
+ LEAK_FACTOR_BITS : natural := 5; -- Inversely related to LP corner frequency. (Min=1)
+ HYSTERESIS_BITS : natural := 8; -- Make this less than INTEGRATOR_BITS
+ INTEGRATOR_BITS : natural := 16 -- Bits in each integrating accumulator
+ );
+ port (
+ -- System Clock and Clock Enable
+ sys_rst_n : in std_logic;
+ sys_clk : in std_logic;
+ sys_clk_en : in std_logic;
+
+ -- Settings
+ input : in signed(INTEGRATOR_BITS-1 downto 0);
+ hysteresis : in unsigned(HYSTERESIS_BITS-1 downto 0);
+
+ -- Final Stage Integration Result
+ integrator : out signed(INTEGRATOR_BITS-1 downto 0);
+
+ -- Conditioned Digital Output Signal
+ output : out std_logic
+ );
+ end multi_stage_leaky_integrator;
+
+architecture beh of multi_stage_leaky_integrator is
+
+ -- Constants
+ -- This value has been found to preserve amplitude between stages,
+ -- without appreciable growth or shrinkage of sum levels.
+ constant STAGE_ASR : natural := LEAK_FACTOR_BITS+1;
+ constant LEAK_FACTOR : natural := 1;
+
+ -- Functions & associated types
+
+ -- Signal Declarations
+ type sum_type is array (natural range STAGES-1 downto 0) of signed(INTEGRATOR_BITS-1 downto 0);
+ signal sum_in : sum_type;
+ signal sum_out : sum_type;
+ signal out_l : std_logic;
+ signal hp_term : signed(INTEGRATOR_BITS-1 downto 0);
+ signal hn_term : signed(INTEGRATOR_BITS-1 downto 0);
+
+begin
+
+
+----------------------------------------------
+leaky_gen : for nvar in 0 to STAGES-1 generate
+begin
+ lint : leaky_integrator
+ generic map(
+ LEAK_FACTOR_BITS => LEAK_FACTOR_BITS,
+ LEAK_FACTOR => LEAK_FACTOR,
+ INTEGRATOR_BITS => INTEGRATOR_BITS
+ )
+ port map(
+ -- System Clock and Clock Enable
+ sys_rst_n => sys_rst_n,
+ sys_clk => sys_clk,
+ sys_clk_en => sys_clk_en,
+
+ -- Settings
+ input => sum_in(nvar),
+
+ -- Integration Result
+ integrator => sum_out(nvar)
+
+ );
+end generate;
+
+sum_in(0) <= input;
+sum_gen : for nvar in 1 to STAGES-1 generate
+begin
+ sum_in(nvar) <= asr_function(sum_out(nvar-1),STAGE_ASR);
+end generate;
+
+-- The hysteresis and digital output
+process (sys_clk, sys_rst_n)
+begin
+ if (sys_rst_n='0') then
+ out_l <= '0';
+ elsif (sys_clk'event and sys_clk='1') then -- rising edge
+ if (sys_clk_en='1') then
+ if (out_l='0') then
+ if (sum_out(STAGES-1)>hp_term) then
+ out_l <= '1';
+ end if;
+ else
+ if (sum_out(STAGES-1)0) then
+ if (pulse_i='1') then
+ runt_count <= runt_count-1;
+ else
+ runt_count <= to_unsigned(MIN_CLKS,runt_count'length);
+ end if;
+ end if;
+ -- Trigger on rising edge of pulse_i
+ if (pulse_i='1' and pulse_i_r1='0') then
+ if (pulse_l='0' or (RETRIGGERABLE=1 and pulse_l='1')) then
+ runt_count <= to_unsigned(MIN_CLKS,runt_count'length);
+ end if;
+ end if;
+ -- Load initial offset into accumulator on final runt countdown
+ if (runt_count=1) then
+ sum <= to_signed(INITIAL_OFFSET,sum'length);
+ end if;
+ -- Either accumulate or decay, depending on input state
+ if (pulse_i='1' and runt_count=0) then
+ sum <= sum+STRETCH_FACTOR;
+ elsif (pulse_i='0' and pulse_l='1') then
+ sum <= sum-1;
+ end if;
+ end if;
+ end if;
+end process;
+
+-- The output
+pulse_l <= '1' when (sum>0) else '0';
+pulse_o <= pulse_l;
+
+end beh;
+