OpenCores
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; +

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.