URL
https://opencores.org/ocsvn/fat_32_file_parser/fat_32_file_parser/trunk
Subversion Repositories fat_32_file_parser
[/] [fat_32_file_parser/] [trunk/] [SdCardReadWrite.vhd] - Rev 2
Compare with Previous | Blame | View Log
---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 15:20:06 11/16/2014 -- Design Name: -- Module Name: SdCardReadWrite - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; library UNISIM; use UNISIM.VComponents.all; entity SdCardReadWrite is Port ( CLK_IN : in STD_LOGIC; RESET_IN : in STD_LOGIC; FAT_BEGIN_ADDR_IN : in STD_LOGIC_VECTOR (31 downto 0); SECTORS_PER_FAT_IN : in STD_LOGIC_VECTOR (31 downto 0); CLUSTER_BEGIN_ADDR_IN : in STD_LOGIC_VECTOR (31 downto 0); SECTORS_PER_CLUSTER_IN : in STD_LOGIC_VECTOR (7 downto 0); ROOT_DIR_FIRST_CLUSTER_IN : in STD_LOGIC_VECTOR (31 downto 0); SD_INIT_CMPLT_IN : in STD_LOGIC; SD_BLOCK_RD_OUT : out STD_LOGIC; SD_BLOCK_ADDR_OUT : out STD_LOGIC_VECTOR (31 downto 0); SD_DATA_IN : in STD_LOGIC_VECTOR (7 downto 0); SD_BUSY_IN : in STD_LOGIC; SD_BYTE_RD_OUT : out STD_LOGIC; SD_BYTE_RD_ACK_IN : in STD_LOGIC; GET_NEXT_DIRENT_IN : in STD_LOGIC; NEXT_DIRENT_DONE_OUT : out STD_LOGIC; DIRENT_IS_FOLDER_OUT : out STD_LOGIC; RD_DIRENT_NAME_CHAR_IN : in STD_LOGIC; DIRENT_CHAR_OUT : out STD_LOGIC_VECTOR(7 downto 0); END_OF_DIRENT_NAME_OUT : out STD_LOGIC; NO_MORE_DIRENTS_OUT : out STD_LOGIC; DEBUG_IN : in STD_LOGIC_VECTOR(7 downto 0); DEBUG_OUT : out STD_LOGIC_VECTOR(15 downto 0); DEBUG_OUT2 : out STD_LOGIC_VECTOR(7 downto 0)); end SdCardReadWrite; architecture Behavioral of SdCardReadWrite is COMPONENT TDP_RAM Generic (G_DATA_A_SIZE :natural :=32; G_ADDR_A_SIZE :natural :=9; G_RELATION :natural :=3; G_INIT_FILE :string :="");--log2(SIZE_A/SIZE_B) Port ( CLK_A_IN : in STD_LOGIC; WE_A_IN : in STD_LOGIC; ADDR_A_IN : in STD_LOGIC_VECTOR (G_ADDR_A_SIZE-1 downto 0); DATA_A_IN : in STD_LOGIC_VECTOR (G_DATA_A_SIZE-1 downto 0); DATA_A_OUT : out STD_LOGIC_VECTOR (G_DATA_A_SIZE-1 downto 0); CLK_B_IN : in STD_LOGIC; WE_B_IN : in STD_LOGIC; ADDR_B_IN : in STD_LOGIC_VECTOR (G_ADDR_A_SIZE+G_RELATION-1 downto 0); DATA_B_IN : in STD_LOGIC_VECTOR (G_DATA_A_SIZE/(2**G_RELATION)-1 downto 0); DATA_B_OUT : out STD_LOGIC_VECTOR (G_DATA_A_SIZE/(2**G_RELATION)-1 downto 0)); END COMPONENT; COMPONENT lifo is Generic ( G_LOG2_DEPTH : natural := 6; G_DATA_SIZE : natural := 8 ); -- LOG2(lifo depth) Port ( CLK_IN : in STD_LOGIC; RESET_IN : in STD_LOGIC; CACHE_ADDR_IN : in STD_LOGIC; GOTO_CACHE_IN : in STD_LOGIC; WR_DATA_IN : in STD_LOGIC_VECTOR ((G_DATA_SIZE - 1) downto 0); WR_EN_IN : in STD_LOGIC; RD_DATA_OUT : out STD_LOGIC_VECTOR ((G_DATA_SIZE - 1) downto 0); RD_EN_IN : in STD_LOGIC; EMPTY_OUT : out STD_LOGIC; FULL_OUT : out STD_LOGIC); END COMPONENT; subtype slv is std_logic_vector; constant C_unused_entry : std_logic_vector(7 downto 0) := X"E5"; constant C_end_of_directory : std_logic_vector(7 downto 0) := X"00"; constant C_file_name_type : std_logic_vector(7 downto 0) := X"0F"; constant C_folder_type : std_logic_vector(7 downto 0) := X"10"; constant C_file_type : std_logic_vector(7 downto 0) := X"20"; constant C_attrib_offset : unsigned(4 downto 0) := "01011"; constant C_lsb_word_lsb_offset : unsigned(4 downto 0) := "11010"; constant C_lsb_word_msb_offset : unsigned(4 downto 0) := "11011"; constant C_msb_word_lsb_offset : unsigned(4 downto 0) := "10100"; constant C_msb_word_msb_offset : unsigned(4 downto 0) := "10101"; signal sd_init_cmplt, sd_block_rd, perform_block_rd, block_rd_cmplt : std_logic := '0'; signal sd_busy, rd_byte, rd_byte_ack, get_next_dirent : std_logic := '0'; signal sd_data, block_rd_data : std_logic_vector(7 downto 0) := (others => '0'); signal fat_begin_addr, sectors_per_fat : unsigned(31 downto 0); signal sd_block_addr : unsigned(31 downto 0); signal cluster_begin_addr : unsigned(31 downto 0); signal find_dirent_addr, find_dirent_addr_rd, find_dirent_addr_cache : unsigned(8 downto 0) := (others => '0'); signal find_dirent_addr_rd_slv : std_logic_vector(8 downto 0); signal dirent_found, dirent_is_folder : std_logic := '0'; signal dirent_lifo_we, dirent_lifo_rst, dirent_lifo_cache_addr : std_logic := '0'; signal dirent_lifo_goto_cache, dirent_lifo_full, dirent_lifo_empty : std_logic := '0'; signal folder_addr, folder_addr_tmp, folder_addr_final : unsigned(31 downto 0) := X"00000000"; signal sectors_per_cluster, spc_counter : std_logic_vector(7 downto 0) := X"00"; signal bp_lifo_rst, bp_lifo_we, bp_lifo_rd, bp_lifo_empty : std_logic := '0'; signal bp_lifo_block_data : std_logic_vector(31 downto 0) := (others => '0'); signal find_addr_lifo_rst, find_addr_lifo_we, find_addr_lifo_rd, find_addr_lifo_empty : std_logic := '0'; signal end_of_dirents : std_logic := '0'; signal sectors_per_cluster_zero_indexed, find_dirent_block_num, find_dirent_block_num_rd : unsigned(7 downto 0) := X"00"; signal current_cluster, current_cluster_buf, current_cluster_rd : unsigned(31 downto 0) := X"00000000"; signal current_cluster_fat_block_addr, current_cluster_tmp, next_cluster_lba : unsigned(31 downto 0) := X"00000000"; signal current_cluster_lifo_rst, current_cluster_lifo_we, current_cluster_lifo_rd : std_logic := '0'; signal current_cluster_lifo_empty : std_logic := '0'; signal current_cluster_rd_slv : std_logic_vector(31 downto 0); signal find_dirent_block_lifo_rst, find_dirent_block_lifo_we, find_dirent_block_lifo_rd : std_logic := '0'; signal find_dirent_block_lifo_empty : std_logic := '0'; signal find_dirent_block_num_rd_slv : std_logic_vector(7 downto 0); signal file_counter :unsigned(15 downto 0) := (others => '0'); signal debug : std_logic := '0'; type MAIN_ROUTINE is ( REPORT_ERROR, WAIT_FOR_INIT_CMPLT, IDLE_W_BLOCK_RD, IDLE_NO_BLOCK_RD, FIND_NEXT_DIRENT0, FIND_NEXT_DIRENT1, FIND_NEXT_DIRENT2, FIND_NEXT_DIRENT3, FIND_NEXT_DIRENT4, FIND_NEXT_DIRENT5, FIND_NEXT_DIRENT6, PARSE_NAME_DIRENT0, PARSE_NAME_DIRENT1, PARSE_NAME_DIRENT2, PARSE_NAME_DIRENT3, PARSE_NAME_DIRENT4, PARSE_NAME_DIRENT5, PARSE_NAME_DIRENT6, PARSE_NAME_DIRENT7, PARSE_NAME_DIRENT8, PARSE_NAME_DIRENT9, PARSE_NAME_DIRENT10, PARSE_NAME_DIRENT11, PARSE_NAME_DIRENT12, PARSE_NAME_DIRENT13, PARSE_NAME_DIRENT14, PARSE_NAME_DIRENT15, PARSE_NAME_DIRENT16, PARSE_NAME_DIRENT17, HANDLE_FILE_DIRENT0, HANDLE_END_OF_DIR0, HANDLE_END_OF_DIR1, HANDLE_END_OF_DIR2, HANDLE_END_OF_DIR3, HANDLE_FOLDER_DIRENT0, HANDLE_FOLDER_DIRENT1, HANDLE_FOLDER_DIRENT2, HANDLE_FOLDER_DIRENT3, HANDLE_FOLDER_DIRENT4, HANDLE_FOLDER_DIRENT5, HANDLE_FOLDER_DIRENT6, HANDLE_FOLDER_DIRENT7, HANDLE_FOLDER_DIRENT8, HANDLE_FOLDER_DIRENT9, HANDLE_INTERNAL_ADDR_INC0, HANDLE_INTERNAL_ADDR_INC1, HANDLE_INTERNAL_ADDR_INC2, HANDLE_INTERNAL_ADDR_INC3, HANDLE_INTERNAL_ADDR_INC4, HANDLE_INTERNAL_ADDR_INC5, HANDLE_INTERNAL_ADDR_INC6, HANDLE_INTERNAL_ADDR_INC7, FIND_NEXT_CLUSTER0, FIND_NEXT_CLUSTER1, FIND_NEXT_CLUSTER2, FIND_NEXT_CLUSTER3, FIND_NEXT_CLUSTER4, FIND_NEXT_CLUSTER5, FIND_NEXT_CLUSTER6, FIND_NEXT_CLUSTER7, FIND_NEXT_CLUSTER8, FIND_NEXT_CLUSTER9, HANDLE_END_OF_DIRENTS0, HANDLE_END_OF_DIRENTS1); signal rw_state, rw_next_state, rw_state_cached : MAIN_ROUTINE := WAIT_FOR_INIT_CMPLT; signal block_rd_we : std_logic := '0'; signal block_wr_addr, block_rd_addr : unsigned(8 downto 0) := (others => '0'); type BLOCK_RD_ROUTINE is ( IDLE, WAIT_UNTIL_NOT_BUSY, WAIT_UNTIL_BLOCK_READ_ACKD, READ_BYTE0, READ_BYTE1, READ_BYTE2, READ_BYTE3, READ_BYTE4 ); signal br_state, br_next_state : BLOCK_RD_ROUTINE; signal state_debug_sig : unsigned(5 downto 0); signal state_debug_sig2 : unsigned(1 downto 0); begin sd_init_cmplt <= SD_INIT_CMPLT_IN; SD_BLOCK_RD_OUT <= sd_block_rd; SD_BLOCK_ADDR_OUT <= slv(sd_block_addr); sd_data <= SD_DATA_IN; sd_busy <= SD_BUSY_IN; SD_BYTE_RD_OUT <= rd_byte; rd_byte_ack <= SD_BYTE_RD_ACK_IN; fat_begin_addr <= unsigned(FAT_BEGIN_ADDR_IN); sectors_per_fat <= unsigned(SECTORS_PER_FAT_IN); cluster_begin_addr <= unsigned(CLUSTER_BEGIN_ADDR_IN); get_next_dirent <= GET_NEXT_DIRENT_IN; sectors_per_cluster <= SECTORS_PER_CLUSTER_IN; sectors_per_cluster_zero_indexed <= unsigned(SECTORS_PER_CLUSTER_IN) - 1; NEXT_DIRENT_DONE_OUT <= dirent_found; DIRENT_IS_FOLDER_OUT <= dirent_is_folder; END_OF_DIRENT_NAME_OUT <= dirent_lifo_empty; NO_MORE_DIRENTS_OUT <= end_of_dirents; -- debug_state: process(CLK_IN) -- begin -- if rising_edge(CLK_IN) then -- case (br_state) is -- when IDLE => -- state_debug_sig <= to_unsigned(0, 6); -- when WAIT_UNTIL_NOT_BUSY => -- state_debug_sig <= to_unsigned(1, 6); -- when WAIT_UNTIL_BLOCK_READ_ACKD => -- state_debug_sig <= to_unsigned(2, 6); -- when READ_BYTE0 => -- state_debug_sig <= to_unsigned(3, 6); -- when READ_BYTE1 => -- state_debug_sig <= to_unsigned(4, 6); -- when READ_BYTE2 => -- state_debug_sig <= to_unsigned(5, 6); -- when READ_BYTE3 => -- state_debug_sig <= to_unsigned(6, 6); -- when READ_BYTE4 => -- state_debug_sig <= to_unsigned(7, 6); -- end case; -- end if; -- end process; debug_state: process(CLK_IN) begin if rising_edge(CLK_IN) then case( rw_state ) is when REPORT_ERROR => state_debug_sig <= to_unsigned(0, 6); when WAIT_FOR_INIT_CMPLT => state_debug_sig <= to_unsigned(1, 6); when IDLE_W_BLOCK_RD => state_debug_sig <= to_unsigned(2, 6); when IDLE_NO_BLOCK_RD => state_debug_sig <= to_unsigned(3, 6); when FIND_NEXT_DIRENT0 => state_debug_sig <= to_unsigned(4, 6); when FIND_NEXT_DIRENT1 => state_debug_sig <= to_unsigned(5, 6); when FIND_NEXT_DIRENT2 => state_debug_sig <= to_unsigned(6, 6); when FIND_NEXT_DIRENT3 => state_debug_sig <= to_unsigned(7, 6); when FIND_NEXT_DIRENT4 => state_debug_sig <= to_unsigned(8, 6); when FIND_NEXT_DIRENT5 => state_debug_sig <= to_unsigned(9, 6); when FIND_NEXT_DIRENT6 => state_debug_sig <= to_unsigned(10, 6); when PARSE_NAME_DIRENT0 => state_debug_sig <= to_unsigned(11, 6); when PARSE_NAME_DIRENT1 => state_debug_sig <= to_unsigned(12, 6); when PARSE_NAME_DIRENT2 => state_debug_sig <= to_unsigned(13, 6); when PARSE_NAME_DIRENT3 => state_debug_sig <= to_unsigned(14, 6); when PARSE_NAME_DIRENT4 => state_debug_sig <= to_unsigned(15, 6); when PARSE_NAME_DIRENT5 => state_debug_sig <= to_unsigned(16, 6); when PARSE_NAME_DIRENT6 => state_debug_sig <= to_unsigned(17, 6); when PARSE_NAME_DIRENT7 => state_debug_sig <= to_unsigned(18, 6); when PARSE_NAME_DIRENT8 => state_debug_sig <= to_unsigned(19, 6); when PARSE_NAME_DIRENT9 => state_debug_sig <= to_unsigned(20, 6); when PARSE_NAME_DIRENT10 => state_debug_sig <= to_unsigned(21, 6); when PARSE_NAME_DIRENT11 => state_debug_sig <= to_unsigned(22, 6); when PARSE_NAME_DIRENT12 => state_debug_sig <= to_unsigned(23, 6); when PARSE_NAME_DIRENT13 => state_debug_sig <= to_unsigned(24, 6); when PARSE_NAME_DIRENT14 => state_debug_sig <= to_unsigned(25, 6); when PARSE_NAME_DIRENT15 => state_debug_sig <= to_unsigned(26, 6); when PARSE_NAME_DIRENT16 => state_debug_sig <= to_unsigned(27, 6); when PARSE_NAME_DIRENT17 => state_debug_sig <= to_unsigned(28, 6); when HANDLE_FILE_DIRENT0 => state_debug_sig <= to_unsigned(29, 6); when HANDLE_END_OF_DIR0 => state_debug_sig <= to_unsigned(30, 6); when HANDLE_END_OF_DIR1 => state_debug_sig <= to_unsigned(31, 6); when HANDLE_END_OF_DIR2 => state_debug_sig <= to_unsigned(32, 6); when HANDLE_END_OF_DIR3 => state_debug_sig <= to_unsigned(33, 6); when HANDLE_FOLDER_DIRENT0 => state_debug_sig <= to_unsigned(34, 6); when HANDLE_FOLDER_DIRENT1 => state_debug_sig <= to_unsigned(35, 6); when HANDLE_FOLDER_DIRENT2 => state_debug_sig <= to_unsigned(36, 6); when HANDLE_FOLDER_DIRENT3 => state_debug_sig <= to_unsigned(37, 6); when HANDLE_FOLDER_DIRENT4 => state_debug_sig <= to_unsigned(38, 6); when HANDLE_FOLDER_DIRENT5 => state_debug_sig <= to_unsigned(39, 6); when HANDLE_FOLDER_DIRENT6 => state_debug_sig <= to_unsigned(40, 6); when HANDLE_FOLDER_DIRENT7 => state_debug_sig <= to_unsigned(41, 6); when HANDLE_FOLDER_DIRENT8 => state_debug_sig <= to_unsigned(42, 6); when HANDLE_FOLDER_DIRENT9 => state_debug_sig <= to_unsigned(43, 6); when HANDLE_INTERNAL_ADDR_INC0 => state_debug_sig <= to_unsigned(44, 6); when HANDLE_INTERNAL_ADDR_INC1 => state_debug_sig <= to_unsigned(45, 6); when HANDLE_INTERNAL_ADDR_INC2 => state_debug_sig <= to_unsigned(46, 6); when HANDLE_INTERNAL_ADDR_INC3 => state_debug_sig <= to_unsigned(47, 6); when HANDLE_INTERNAL_ADDR_INC4 => state_debug_sig <= to_unsigned(48, 6); when HANDLE_INTERNAL_ADDR_INC5 => state_debug_sig <= to_unsigned(49, 6); when HANDLE_INTERNAL_ADDR_INC6 => state_debug_sig <= to_unsigned(50, 6); when HANDLE_INTERNAL_ADDR_INC7 => state_debug_sig <= to_unsigned(51, 6); when FIND_NEXT_CLUSTER0 => state_debug_sig <= to_unsigned(52, 6); when FIND_NEXT_CLUSTER1 => state_debug_sig <= to_unsigned(53, 6); when FIND_NEXT_CLUSTER2 => state_debug_sig <= to_unsigned(54, 6); when FIND_NEXT_CLUSTER3 => state_debug_sig <= to_unsigned(55, 6); when FIND_NEXT_CLUSTER4 => state_debug_sig <= to_unsigned(56, 6); when FIND_NEXT_CLUSTER5 => state_debug_sig <= to_unsigned(57, 6); when FIND_NEXT_CLUSTER6 => state_debug_sig <= to_unsigned(58, 6); when FIND_NEXT_CLUSTER7 => state_debug_sig <= to_unsigned(59, 6); when FIND_NEXT_CLUSTER8 => state_debug_sig <= to_unsigned(60, 6); when FIND_NEXT_CLUSTER9 => state_debug_sig <= to_unsigned(61, 6); when HANDLE_END_OF_DIRENTS0 => state_debug_sig <= to_unsigned(62, 6); when HANDLE_END_OF_DIRENTS1 => state_debug_sig <= to_unsigned(63, 6); end case; end if; end process; debug_state2: process(CLK_IN) begin if rising_edge(CLK_IN) then case( rw_state_cached ) is when FIND_NEXT_DIRENT2 => state_debug_sig2 <= to_unsigned(0, 2); when PARSE_NAME_DIRENT15 => state_debug_sig2 <= to_unsigned(1, 2); when IDLE_NO_BLOCK_RD => state_debug_sig2 <= to_unsigned(2, 2); when others => state_debug_sig2 <= to_unsigned(3, 2); end case; end if; end process; -------- FSM OUTPUT -------- BLOCK_RD: process(CLK_IN) begin if rising_edge(CLK_IN) then if rw_state = WAIT_FOR_INIT_CMPLT then sd_block_addr <= cluster_begin_addr; elsif rw_state = HANDLE_FOLDER_DIRENT9 then sd_block_addr <= folder_addr_final; elsif rw_state = HANDLE_END_OF_DIR0 then sd_block_addr <= unsigned(bp_lifo_block_data); elsif rw_state = HANDLE_END_OF_DIRENTS0 then sd_block_addr <= cluster_begin_addr; elsif rw_state = HANDLE_INTERNAL_ADDR_INC1 then sd_block_addr <= sd_block_addr + 1; elsif rw_state = FIND_NEXT_CLUSTER1 then sd_block_addr <= current_cluster_fat_block_addr; elsif rw_state = HANDLE_INTERNAL_ADDR_INC6 then sd_block_addr <= next_cluster_lba; end if; if rw_state = FIND_NEXT_DIRENT0 then perform_block_rd <= '1'; elsif rw_state = HANDLE_INTERNAL_ADDR_INC1 then perform_block_rd <= '1'; elsif rw_state = FIND_NEXT_CLUSTER1 then perform_block_rd <= '1'; elsif rw_state = HANDLE_INTERNAL_ADDR_INC6 then perform_block_rd <= '1'; else perform_block_rd <= '0'; end if; if rw_state = FIND_NEXT_DIRENT2 then block_rd_addr <= find_dirent_addr; elsif rw_state = FIND_NEXT_DIRENT3 then block_rd_addr <= find_dirent_addr(8 downto 5) & C_attrib_offset; elsif rw_state = PARSE_NAME_DIRENT1 then block_rd_addr <= find_dirent_addr(8 downto 5) & to_unsigned(30, 5); elsif rw_state = PARSE_NAME_DIRENT2 then block_rd_addr <= find_dirent_addr(8 downto 5) & to_unsigned(28,5); elsif rw_state = PARSE_NAME_DIRENT3 then block_rd_addr <= find_dirent_addr(8 downto 5) & to_unsigned(24,5); elsif rw_state = PARSE_NAME_DIRENT4 then block_rd_addr <= find_dirent_addr(8 downto 5) & to_unsigned(22,5); elsif rw_state = PARSE_NAME_DIRENT5 then block_rd_addr <= find_dirent_addr(8 downto 5) & to_unsigned(20,5); elsif rw_state = PARSE_NAME_DIRENT6 then block_rd_addr <= find_dirent_addr(8 downto 5) & to_unsigned(18,5); elsif rw_state = PARSE_NAME_DIRENT7 then block_rd_addr <= find_dirent_addr(8 downto 5) & to_unsigned(16,5); elsif rw_state = PARSE_NAME_DIRENT8 then block_rd_addr <= find_dirent_addr(8 downto 5) & to_unsigned(14,5); elsif rw_state = PARSE_NAME_DIRENT9 then block_rd_addr <= find_dirent_addr(8 downto 5) & to_unsigned(9, 5); elsif rw_state = PARSE_NAME_DIRENT10 then block_rd_addr <= find_dirent_addr(8 downto 5) & to_unsigned(7, 5); elsif rw_state = PARSE_NAME_DIRENT11 then block_rd_addr <= find_dirent_addr(8 downto 5) & to_unsigned(5, 5); elsif rw_state = PARSE_NAME_DIRENT12 then block_rd_addr <= find_dirent_addr(8 downto 5) & to_unsigned(3, 5); elsif rw_state = PARSE_NAME_DIRENT13 then block_rd_addr <= find_dirent_addr(8 downto 5) & to_unsigned(1, 5); elsif rw_state = PARSE_NAME_DIRENT15 then block_rd_addr <= find_dirent_addr(8 downto 5) & C_attrib_offset; elsif rw_state = HANDLE_FOLDER_DIRENT0 then block_rd_addr <= find_dirent_addr(8 downto 5) & C_lsb_word_lsb_offset; elsif rw_state = HANDLE_FOLDER_DIRENT1 then block_rd_addr <= find_dirent_addr(8 downto 5) & C_lsb_word_msb_offset; elsif rw_state = HANDLE_FOLDER_DIRENT2 then block_rd_addr <= find_dirent_addr(8 downto 5) & C_msb_word_lsb_offset; elsif rw_state = HANDLE_FOLDER_DIRENT3 then block_rd_addr <= find_dirent_addr(8 downto 5) & C_msb_word_msb_offset; elsif rw_state = FIND_NEXT_CLUSTER3 then block_rd_addr <= current_cluster_buf(6 downto 0) & "00"; elsif rw_state = FIND_NEXT_CLUSTER4 then block_rd_addr <= current_cluster_buf(6 downto 0) & "01"; elsif rw_state = FIND_NEXT_CLUSTER5 then block_rd_addr <= current_cluster_buf(6 downto 0) & "10"; elsif rw_state = FIND_NEXT_CLUSTER6 then block_rd_addr <= current_cluster_buf(6 downto 0) & "11"; end if; if rw_state = FIND_NEXT_CLUSTER2 then current_cluster_buf <= current_cluster; end if; if rw_state = FIND_NEXT_DIRENT6 then rw_state_cached <= FIND_NEXT_DIRENT2; elsif rw_state = PARSE_NAME_DIRENT14 then rw_state_cached <= PARSE_NAME_DIRENT15; elsif rw_state = HANDLE_FILE_DIRENT0 then rw_state_cached <= IDLE_NO_BLOCK_RD; end if; if rw_state = HANDLE_FILE_DIRENT0 then file_counter <= file_counter + 1; elsif rw_state = HANDLE_END_OF_DIRENTS1 and DEBUG_IN(0) = '1' then file_counter <= (others => '0'); end if; if rw_state = HANDLE_FOLDER_DIRENT9 then find_dirent_addr <= (others => '0'); elsif rw_state = HANDLE_END_OF_DIR0 then find_dirent_addr <= find_dirent_addr_rd; elsif rw_state = HANDLE_END_OF_DIRENTS0 then find_dirent_addr <= (others => '0'); elsif rw_state = HANDLE_INTERNAL_ADDR_INC0 then find_dirent_addr <= find_dirent_addr + "000100000"; end if; if rw_state = HANDLE_FOLDER_DIRENT0 then find_dirent_addr_cache <= find_dirent_addr + "000100000"; end if; if rw_state = HANDLE_INTERNAL_ADDR_INC1 then if find_dirent_block_num = sectors_per_cluster_zero_indexed then find_dirent_block_num <= (others => '0'); else find_dirent_block_num <= find_dirent_block_num + 1; end if; elsif rw_state = HANDLE_FOLDER_DIRENT9 then find_dirent_block_num <= (others => '0'); elsif rw_state = HANDLE_END_OF_DIR0 then find_dirent_block_num <= find_dirent_block_num_rd; end if; end if; end process; DIRENT_LIFO: process(CLK_IN) begin if rising_edge(CLK_IN) then if rw_next_state = PARSE_NAME_DIRENT0 then dirent_lifo_rst <= '1'; else dirent_lifo_rst <= '0'; end if; if rw_state = PARSE_NAME_DIRENT2 then dirent_lifo_we <= '1'; elsif rw_state = HANDLE_INTERNAL_ADDR_INC0 then dirent_lifo_we <= '0'; end if; end if; end process; dirent_name_lifo : lifo Generic Map ( G_LOG2_DEPTH => 7, G_DATA_SIZE => block_rd_data'length ) Port Map ( CLK_IN => CLK_IN, RESET_IN => dirent_lifo_rst, CACHE_ADDR_IN => dirent_lifo_cache_addr, GOTO_CACHE_IN => dirent_lifo_goto_cache, WR_DATA_IN => block_rd_data, WR_EN_IN => dirent_lifo_we, RD_DATA_OUT => DIRENT_CHAR_OUT, RD_EN_IN => RD_DIRENT_NAME_CHAR_IN, EMPTY_OUT => dirent_lifo_empty, FULL_OUT => dirent_lifo_full); HANDLE_FOLDER_DIRENT: process(CLK_IN) begin if rising_edge(CLK_IN) then if rw_next_state = HANDLE_FOLDER_DIRENT0 or rw_next_state = HANDLE_FILE_DIRENT0 then dirent_found <= '1'; else dirent_found <= '0'; end if; if rw_next_state = HANDLE_FOLDER_DIRENT0 then dirent_is_folder <= '1'; else dirent_is_folder <= '0'; end if; if rw_state = HANDLE_FOLDER_DIRENT2 then folder_addr(7 downto 0) <= unsigned(block_rd_data); elsif rw_state = HANDLE_FOLDER_DIRENT3 then folder_addr(15 downto 8) <= unsigned(block_rd_data); elsif rw_state = HANDLE_FOLDER_DIRENT4 then folder_addr(23 downto 16) <= unsigned(block_rd_data); elsif rw_state = HANDLE_FOLDER_DIRENT5 then folder_addr(31 downto 24) <= unsigned(block_rd_data); end if; if rw_state = HANDLE_FOLDER_DIRENT6 then folder_addr_tmp <= (folder_addr - 2); elsif rw_state = HANDLE_FOLDER_DIRENT7 then folder_addr_tmp(31 downto 1) <= folder_addr_tmp(30 downto 0); folder_addr_tmp(0) <= '0'; end if; if rw_state = HANDLE_FOLDER_DIRENT8 then folder_addr_final <= folder_addr_tmp + cluster_begin_addr; end if; if rw_state = HANDLE_FOLDER_DIRENT7 or rw_state = HANDLE_INTERNAL_ADDR_INC4 then spc_counter(7 downto 1) <= spc_counter(6 downto 0); spc_counter(0) <= '0'; else spc_counter <= X"02"; end if; end if; end process; HANDLE_BP_CACHING: process(CLK_IN) begin if rising_edge(CLK_IN) then if rw_state = HANDLE_FOLDER_DIRENT0 then bp_lifo_we <= '1'; else bp_lifo_we <= '0'; end if; if rw_next_state = HANDLE_END_OF_DIR0 then bp_lifo_rd <= '1'; else bp_lifo_rd <= '0'; end if; end if; end process; sd_block_pointer_lifo : lifo Generic Map ( G_LOG2_DEPTH => 5, G_DATA_SIZE => sd_block_addr'length ) Port Map ( CLK_IN => CLK_IN, RESET_IN => bp_lifo_rst, CACHE_ADDR_IN => '0', GOTO_CACHE_IN => '0', WR_DATA_IN => slv(sd_block_addr), WR_EN_IN => bp_lifo_we, RD_DATA_OUT => bp_lifo_block_data, RD_EN_IN => bp_lifo_rd, EMPTY_OUT => bp_lifo_empty, FULL_OUT => open); find_addr_lifo_we <= bp_lifo_we; find_addr_lifo_rd <= bp_lifo_rd; find_dirent_addr_rd <= unsigned(find_dirent_addr_rd_slv); find_dirent_addr_lifo : lifo Generic Map ( G_LOG2_DEPTH => 5, G_DATA_SIZE => find_dirent_addr'length ) Port Map ( CLK_IN => CLK_IN, RESET_IN => find_addr_lifo_rst, CACHE_ADDR_IN => '0', GOTO_CACHE_IN => '0', WR_DATA_IN => slv(find_dirent_addr_cache), WR_EN_IN => find_addr_lifo_we, RD_DATA_OUT => find_dirent_addr_rd_slv, RD_EN_IN => find_addr_lifo_rd, EMPTY_OUT => find_addr_lifo_empty, FULL_OUT => open); HANDLE_END_FLAG: process(CLK_IN) begin if rising_edge(CLK_IN) then if rw_state = HANDLE_END_OF_DIRENTS0 then end_of_dirents <= '1'; elsif rw_state = FIND_NEXT_DIRENT0 then end_of_dirents <= '0'; end if; end if; end process; GOTO_NEXT_CLUSTER: process(CLK_IN) begin if rising_edge(CLK_IN) then if rw_state = FIND_NEXT_CLUSTER0 then current_cluster_fat_block_addr <= fat_begin_addr + RESIZE(current_cluster(31 downto 7), 32); end if; if rw_state = FIND_NEXT_CLUSTER5 then current_cluster(7 downto 0) <= unsigned(block_rd_data); elsif rw_state = FIND_NEXT_CLUSTER6 then current_cluster(15 downto 8) <= unsigned(block_rd_data); elsif rw_state = FIND_NEXT_CLUSTER7 then current_cluster(23 downto 16) <= unsigned(block_rd_data); elsif rw_state = FIND_NEXT_CLUSTER8 then current_cluster(31 downto 24) <= unsigned(block_rd_data); -- TODO Check if equal to 0FFFFFFF (end of cluster) ? elsif rw_state = HANDLE_FOLDER_DIRENT6 then current_cluster <= folder_addr; elsif rw_state = WAIT_FOR_INIT_CMPLT or rw_state = HANDLE_END_OF_DIRENTS0 then current_cluster <= X"00000002"; -- TODO Set to ROOT_DIR_FIRST_CLUSTER_IN ? elsif rw_state = HANDLE_END_OF_DIR0 then current_cluster <= current_cluster_rd; end if; if rw_state = HANDLE_INTERNAL_ADDR_INC3 then current_cluster_tmp <= (current_cluster - 2); elsif rw_state = HANDLE_INTERNAL_ADDR_INC4 then current_cluster_tmp(31 downto 1) <= current_cluster_tmp(30 downto 0); current_cluster_tmp(0) <= '0'; end if; if rw_state = HANDLE_INTERNAL_ADDR_INC5 then next_cluster_lba <= current_cluster_tmp + cluster_begin_addr; end if; end if; end process; current_cluster_lifo_we <= bp_lifo_we; current_cluster_lifo_rd <= bp_lifo_rd; current_cluster_rd <= unsigned(current_cluster_rd_slv); current_cluster_lifo : lifo Generic Map ( G_LOG2_DEPTH => 5, G_DATA_SIZE => current_cluster'length ) Port Map ( CLK_IN => CLK_IN, RESET_IN => current_cluster_lifo_rst, CACHE_ADDR_IN => '0', GOTO_CACHE_IN => '0', WR_DATA_IN => slv(current_cluster), WR_EN_IN => current_cluster_lifo_we, RD_DATA_OUT => current_cluster_rd_slv, RD_EN_IN => current_cluster_lifo_rd, EMPTY_OUT => current_cluster_lifo_empty, FULL_OUT => open); find_dirent_block_lifo_we <= bp_lifo_we; find_dirent_block_lifo_rd <= bp_lifo_rd; find_dirent_block_num_rd <= unsigned(find_dirent_block_num_rd_slv); find_dirent_block_num_lifo : lifo Generic Map ( G_LOG2_DEPTH => 5, G_DATA_SIZE => find_dirent_block_num'length ) Port Map ( CLK_IN => CLK_IN, RESET_IN => find_dirent_block_lifo_rst, CACHE_ADDR_IN => '0', GOTO_CACHE_IN => '0', WR_DATA_IN => slv(find_dirent_block_num), WR_EN_IN => find_dirent_block_lifo_we, RD_DATA_OUT => find_dirent_block_num_rd_slv, RD_EN_IN => find_dirent_block_lifo_rd, EMPTY_OUT => find_dirent_block_lifo_empty, FULL_OUT => open); LIFO_RST_PROC : process(CLK_IN) begin if rising_edge(CLK_IN) then if rw_state = HANDLE_END_OF_DIRENTS0 then find_dirent_block_lifo_rst <= '1'; current_cluster_lifo_rst <= '1'; find_addr_lifo_rst <= '1'; bp_lifo_rst <= '1'; else find_dirent_block_lifo_rst <= '0'; current_cluster_lifo_rst <= '0'; find_addr_lifo_rst <= '0'; bp_lifo_rst <= '0'; end if; end if; end process; ----------- MAIN FSM ------------ MAIN_ROUTINE_SYNC: process(CLK_IN) begin if rising_edge(CLK_IN) then if RESET_IN = '0' then rw_state <= rw_next_state; else rw_state <= IDLE_W_BLOCK_RD; end if; end if; end process; MAIN_ROUTINE_DECODE: process ( sd_init_cmplt, block_rd_cmplt, block_rd_cmplt ) begin rw_next_state <= rw_state; -- default is to stay in current state case (rw_state) is when REPORT_ERROR => rw_next_state <= WAIT_FOR_INIT_CMPLT; when WAIT_FOR_INIT_CMPLT => if sd_init_cmplt = '1' then rw_next_state <= IDLE_W_BLOCK_RD; end if; when IDLE_W_BLOCK_RD => if get_next_dirent = '1' then rw_next_state <= FIND_NEXT_DIRENT0; end if; when IDLE_NO_BLOCK_RD => if get_next_dirent = '1' then rw_next_state <= FIND_NEXT_DIRENT2; end if; when FIND_NEXT_DIRENT0 => rw_next_state <= FIND_NEXT_DIRENT1; when FIND_NEXT_DIRENT1 => if block_rd_cmplt = '1' then rw_next_state <= FIND_NEXT_DIRENT2; end if; when FIND_NEXT_DIRENT2 => rw_next_state <= FIND_NEXT_DIRENT3; when FIND_NEXT_DIRENT3 => rw_next_state <= FIND_NEXT_DIRENT4; when FIND_NEXT_DIRENT4 => if block_rd_data = C_unused_entry then rw_next_state <= FIND_NEXT_DIRENT6; elsif block_rd_data = C_end_of_directory then rw_next_state <= HANDLE_END_OF_DIR0; else rw_next_state <= FIND_NEXT_DIRENT5; end if; when FIND_NEXT_DIRENT5 => if block_rd_data /= C_file_name_type then rw_next_state <= FIND_NEXT_DIRENT6; else rw_next_state <= PARSE_NAME_DIRENT0; end if; when FIND_NEXT_DIRENT6 => rw_next_state <= HANDLE_INTERNAL_ADDR_INC0; when PARSE_NAME_DIRENT0 => rw_next_state <= PARSE_NAME_DIRENT1; when PARSE_NAME_DIRENT1 => rw_next_state <= PARSE_NAME_DIRENT2; when PARSE_NAME_DIRENT2 => rw_next_state <= PARSE_NAME_DIRENT3; when PARSE_NAME_DIRENT3 => rw_next_state <= PARSE_NAME_DIRENT4; when PARSE_NAME_DIRENT4 => rw_next_state <= PARSE_NAME_DIRENT5; when PARSE_NAME_DIRENT5 => rw_next_state <= PARSE_NAME_DIRENT6; when PARSE_NAME_DIRENT6 => rw_next_state <= PARSE_NAME_DIRENT7; when PARSE_NAME_DIRENT7 => rw_next_state <= PARSE_NAME_DIRENT8; when PARSE_NAME_DIRENT8 => rw_next_state <= PARSE_NAME_DIRENT9; when PARSE_NAME_DIRENT9 => rw_next_state <= PARSE_NAME_DIRENT10; when PARSE_NAME_DIRENT10 => rw_next_state <= PARSE_NAME_DIRENT11; when PARSE_NAME_DIRENT11 => rw_next_state <= PARSE_NAME_DIRENT12; when PARSE_NAME_DIRENT12 => rw_next_state <= PARSE_NAME_DIRENT13; when PARSE_NAME_DIRENT13 => rw_next_state <= PARSE_NAME_DIRENT14; when PARSE_NAME_DIRENT14 => rw_next_state <= HANDLE_INTERNAL_ADDR_INC0; when PARSE_NAME_DIRENT15 => rw_next_state <= PARSE_NAME_DIRENT16; when PARSE_NAME_DIRENT16 => rw_next_state <= PARSE_NAME_DIRENT17; when PARSE_NAME_DIRENT17 => if block_rd_data = C_file_name_type then rw_next_state <= PARSE_NAME_DIRENT1; elsif block_rd_data(7 downto 4) = C_folder_type(7 downto 4) then rw_next_state <= HANDLE_FOLDER_DIRENT0; elsif block_rd_data(7 downto 4) = C_file_type(7 downto 4) then rw_next_state <= HANDLE_FILE_DIRENT0; -- TODO create 'else' case to prevent lockups end if; when HANDLE_FILE_DIRENT0 => rw_next_state <= HANDLE_INTERNAL_ADDR_INC0; when HANDLE_END_OF_DIR0 => if bp_lifo_empty = '0' then rw_next_state <= HANDLE_END_OF_DIR1; else rw_next_state <= HANDLE_END_OF_DIRENTS0; end if; when HANDLE_END_OF_DIR1 => rw_next_state <= HANDLE_END_OF_DIR2; when HANDLE_END_OF_DIR2 => rw_next_state <= HANDLE_END_OF_DIR3; when HANDLE_END_OF_DIR3 => rw_next_state <= IDLE_W_BLOCK_RD; when HANDLE_FOLDER_DIRENT0 => rw_next_state <= HANDLE_FOLDER_DIRENT1; when HANDLE_FOLDER_DIRENT1 => rw_next_state <= HANDLE_FOLDER_DIRENT2; when HANDLE_FOLDER_DIRENT2 => rw_next_state <= HANDLE_FOLDER_DIRENT3; when HANDLE_FOLDER_DIRENT3 => rw_next_state <= HANDLE_FOLDER_DIRENT4; when HANDLE_FOLDER_DIRENT4 => rw_next_state <= HANDLE_FOLDER_DIRENT5; when HANDLE_FOLDER_DIRENT5 => rw_next_state <= HANDLE_FOLDER_DIRENT6; when HANDLE_FOLDER_DIRENT6 => rw_next_state <= HANDLE_FOLDER_DIRENT7; when HANDLE_FOLDER_DIRENT7 => if spc_counter = sectors_per_cluster then rw_next_state <= HANDLE_FOLDER_DIRENT8; end if; when HANDLE_FOLDER_DIRENT8 => rw_next_state <= HANDLE_FOLDER_DIRENT9; when HANDLE_FOLDER_DIRENT9 => rw_next_state <= IDLE_W_BLOCK_RD; when HANDLE_END_OF_DIRENTS0 => rw_next_state <= HANDLE_END_OF_DIRENTS1; when HANDLE_END_OF_DIRENTS1 => if DEBUG_IN(0) = '1' then rw_next_state <= IDLE_W_BLOCK_RD; end if; when HANDLE_INTERNAL_ADDR_INC0 => if find_dirent_addr(8 downto 5) = "1111" then rw_next_state <= HANDLE_INTERNAL_ADDR_INC1; else rw_next_state <= rw_state_cached; end if; when HANDLE_INTERNAL_ADDR_INC1 => if find_dirent_block_num = sectors_per_cluster_zero_indexed then rw_next_state <= FIND_NEXT_CLUSTER0; else rw_next_state <= HANDLE_INTERNAL_ADDR_INC2; end if; when HANDLE_INTERNAL_ADDR_INC2 => if block_rd_cmplt = '1' then rw_next_state <= rw_state_cached; end if; when HANDLE_INTERNAL_ADDR_INC3 => rw_next_state <= HANDLE_INTERNAL_ADDR_INC4; when HANDLE_INTERNAL_ADDR_INC4 => if spc_counter = sectors_per_cluster then rw_next_state <= HANDLE_INTERNAL_ADDR_INC5; end if; when HANDLE_INTERNAL_ADDR_INC5 => rw_next_state <= HANDLE_INTERNAL_ADDR_INC6; when HANDLE_INTERNAL_ADDR_INC6 => rw_next_state <= HANDLE_INTERNAL_ADDR_INC7; when HANDLE_INTERNAL_ADDR_INC7 => if block_rd_cmplt = '1' then rw_next_state <= rw_state_cached; end if; when FIND_NEXT_CLUSTER0 => rw_next_state <= FIND_NEXT_CLUSTER1; when FIND_NEXT_CLUSTER1 => rw_next_state <= FIND_NEXT_CLUSTER2; when FIND_NEXT_CLUSTER2 => if block_rd_cmplt = '1' then rw_next_state <= FIND_NEXT_CLUSTER3; end if; when FIND_NEXT_CLUSTER3 => rw_next_state <= FIND_NEXT_CLUSTER4; when FIND_NEXT_CLUSTER4 => rw_next_state <= FIND_NEXT_CLUSTER5; when FIND_NEXT_CLUSTER5 => rw_next_state <= FIND_NEXT_CLUSTER6; when FIND_NEXT_CLUSTER6 => rw_next_state <= FIND_NEXT_CLUSTER7; when FIND_NEXT_CLUSTER7 => rw_next_state <= FIND_NEXT_CLUSTER8; when FIND_NEXT_CLUSTER8 => rw_next_state <= FIND_NEXT_CLUSTER9; when FIND_NEXT_CLUSTER9 => rw_next_state <= HANDLE_INTERNAL_ADDR_INC3; end case; end process; ----------- BLOCK READ FSM ------------ BLOCK_READ_SYNC: process(CLK_IN) begin if rising_edge(CLK_IN) then br_state <= br_next_state; end if; end process; BLOCK_READ_FLAGS: process(CLK_IN) begin if rising_edge(CLK_IN) then if br_state = READ_BYTE0 and rd_byte_ack = '1' then block_rd_we <= '1'; else block_rd_we <= '0'; end if; if br_state = READ_BYTE1 then rd_byte <= '1'; elsif br_state = READ_BYTE2 and rd_byte_ack = '0' then rd_byte <= '0'; end if; if br_state = IDLE then block_wr_addr <= (others => '0'); elsif br_state = READ_BYTE1 then block_wr_addr <= block_wr_addr + 1; end if; if br_state = READ_BYTE4 then block_rd_cmplt <= '1'; else block_rd_cmplt <= '0'; end if; if br_state = WAIT_UNTIL_BLOCK_READ_ACKD then sd_block_rd <= '1'; else sd_block_rd <= '0'; end if; end if; end process; BLOCK_READ_DECODE: process (br_state, perform_block_rd, rd_byte_ack, block_wr_addr) begin br_next_state <= br_state; -- default is to stay in current state case (br_state) is when IDLE => if perform_block_rd = '1' then br_next_state <= WAIT_UNTIL_NOT_BUSY; end if; when WAIT_UNTIL_NOT_BUSY => if sd_busy = '0' then br_next_state <= WAIT_UNTIL_BLOCK_READ_ACKD; end if; when WAIT_UNTIL_BLOCK_READ_ACKD => if sd_busy = '1' then br_next_state <= READ_BYTE0; end if; when READ_BYTE0 => if rd_byte_ack = '1' then br_next_state <= READ_BYTE1; end if; when READ_BYTE1 => br_next_state <= READ_BYTE2; when READ_BYTE2 => if rd_byte_ack = '0' then br_next_state <= READ_BYTE3; end if; when READ_BYTE3 => if block_wr_addr = "000000000" then br_next_state <= READ_BYTE4; else br_next_state <= READ_BYTE0; end if; when READ_BYTE4 => br_next_state <= IDLE; end case; end process; Block_Ram_Inst : TDP_RAM Generic Map ( G_DATA_A_SIZE => sd_data'length, G_ADDR_A_SIZE => block_wr_addr'length, G_RELATION => 0, G_INIT_FILE => "") --log2(SIZE_A/SIZE_B) Port Map ( CLK_A_IN => CLK_IN, WE_A_IN => block_rd_we, ADDR_A_IN => slv(block_wr_addr), DATA_A_IN => sd_data, DATA_A_OUT => open, CLK_B_IN => CLK_IN, WE_B_IN => '0', ADDR_B_IN => slv(block_rd_addr), DATA_B_IN => X"00", DATA_B_OUT => block_rd_data); --DEBUG_OUT2(0) <= '1' when rw_state = PARSE_NAME_DIRENT17 else '0'; DEBUG_OUT2(5 downto 0) <= slv(state_debug_sig); DEBUG_OUT2(7) <= sd_busy; DEBUG_OUT <= slv(file_counter(15 downto 0)); end Behavioral;