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/] [SdCardInit.vhd] - Rev 2
Compare with Previous | Blame | View Log
---------------------------------------------------------------------------------- -- Company: -- Engineer: CW -- -- Create Date: 12:30:20 11/16/2014 -- Design Name: -- Module Name: SdCardInit - 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 SdCardInit is Port ( CLK_IN : in STD_LOGIC; RESET_IN : in STD_LOGIC; SD_PRESENT_BAR_IN : in STD_LOGIC; SD_INIT_OUT : out 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; SD_ERROR_IN : in STD_LOGIC_VECTOR (15 downto 0); SD_INIT_CMPLT_OUT : out STD_LOGIC; FAT_BEGIN_ADDR_OUT : out STD_LOGIC_VECTOR (31 downto 0); SECTORS_PER_FAT_OUT : out STD_LOGIC_VECTOR (31 downto 0); CLUSTER_BEGIN_ADDR_OUT : out STD_LOGIC_VECTOR (31 downto 0); SECTORS_PER_CLUSTER_OUT : out STD_LOGIC_VECTOR (7 downto 0); ROOT_DIR_FIRST_CLUSTER_OUT : out STD_LOGIC_VECTOR (31 downto 0)); end SdCardInit; architecture Behavioral of SdCardInit 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; subtype slv is std_logic_vector; ------------------------ INIT FSM ----------------------------------- constant C_500_ms_startup_delay : unsigned(25 downto 0) := "10"&X"FAF080"; -- zero indexed constant C_sd_init_attempts : unsigned(3 downto 0) := X"2"; -- zero indexed constant C_mbr_veracity : std_logic_vector(15 downto 0) := X"AA55"; constant C_bytes_per_sector : std_logic_vector(15 downto 0) := X"0200"; constant C_volume_signature : std_logic_vector(15 downto 0) := X"AA55"; signal startup_delay_counter : unsigned(25 downto 0) := C_500_ms_startup_delay; signal startup_delay_cmplt : std_logic := '0'; signal sd_busy, sd_present, sd_init, sd_rd_block, rd_byte, rd_byte_ack : std_logic := '0'; signal sd_init_attempts_counter : unsigned(3 downto 0) := X"0"; signal sd_error : std_logic_vector(15 downto 0) := (others => '0'); signal sd_data, block_rd_data : std_logic_vector(7 downto 0) := (others => '0'); signal sd_block_addr : std_logic_vector(31 downto 0) := (others => '0'); signal init_cmplt : std_logic; signal mbr_veracity : std_logic_vector(15 downto 0) := (others => '0'); signal lba_block_addr : std_logic_vector(31 downto 0) := (others => '0'); signal num_reserved_sectors, vol_signature : std_logic_vector(15 downto 0); signal bytes_per_sector : std_logic_vector(15 downto 0); signal sectors_per_fat : std_logic_vector(30 downto 0); signal sectors_per_cluster : unsigned(7 downto 0); signal fat_begin_lba, cluster_begin_lba : unsigned(31 downto 0); signal root_dir_cluster : unsigned(31 downto 0); type MAIN_ROUTINE is ( REPORT_ERROR, WAIT_FOR_SD_UNPLUGGED, IDLE, SD_INIT0, SD_INIT1, SD_INIT2, SD_INIT3, CHECK_FILE_SYS_VERACITY0, CHECK_FILE_SYS_VERACITY1, CHECK_FILE_SYS_VERACITY2, CHECK_FILE_SYS_VERACITY3, CHECK_FILE_SYS_VERACITY4, CHECK_FILE_SYS_VERACITY5, CHECK_FILE_SYS_VERACITY6, GET_LBA_START_ADDR0, GET_LBA_START_ADDR1, GET_LBA_START_ADDR2, GET_LBA_START_ADDR3, GET_LBA_START_ADDR4, GET_LBA_START_ADDR5, GET_LBA_START_ADDR6, GET_VOLUME_ID_DATA0, GET_VOLUME_ID_DATA1, GET_VOLUME_ID_DATA2, GET_VOLUME_ID_DATA3, GET_VOLUME_ID_DATA4, GET_VOLUME_ID_DATA5, GET_VOLUME_ID_DATA6, GET_VOLUME_ID_DATA7, GET_VOLUME_ID_DATA8, GET_VOLUME_ID_DATA9, GET_VOLUME_ID_DATA10, GET_VOLUME_ID_DATA11, GET_VOLUME_ID_DATA12, GET_VOLUME_ID_DATA13, GET_VOLUME_ID_DATA14, GET_VOLUME_ID_DATA15, GET_VOLUME_ID_DATA16, GET_VOLUME_ID_DATA17, GET_VOLUME_ID_DATA18, GET_VOLUME_ID_DATA19, GET_VOLUME_ID_DATA20, GET_VOLUME_ID_DATA21, GET_VOLUME_ID_DATA22, GET_VOLUME_ID_DATA23, SD_INIT_CMPLT); signal ir_state, ir_next_state : MAIN_ROUTINE := IDLE; ------------------------ BLOCK RD ----------------------------------- signal perform_block_rd, block_rd_we : std_logic := '0'; signal block_wr_addr, block_rd_addr : unsigned(8 downto 0); type BLOCK_RD_ROUTINE is ( IDLE, READ_BYTE0, READ_BYTE1, READ_BYTE2, READ_BYTE3 ); signal br_state, br_next_state : BLOCK_RD_ROUTINE; begin SD_INIT_OUT <= sd_init; SD_BLOCK_RD_OUT <= sd_rd_block; SD_BLOCK_ADDR_OUT <= 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; sd_error <= SD_ERROR_IN; SD_INIT_CMPLT_OUT <= init_cmplt; SECTORS_PER_FAT_OUT <= '0'§ors_per_fat; FAT_BEGIN_ADDR_OUT <= slv(fat_begin_lba); CLUSTER_BEGIN_ADDR_OUT <= slv(cluster_begin_lba); SECTORS_PER_CLUSTER_OUT <= slv(sectors_per_cluster); ROOT_DIR_FIRST_CLUSTER_OUT <= slv(root_dir_cluster); STARTUP_DELAY: process(CLK_IN) begin if rising_edge(CLK_IN) then if ir_state = IDLE then if sd_present = '1' and startup_delay_counter /= "00"&X"000000" then startup_delay_counter <= startup_delay_counter - 1; else startup_delay_counter <= C_500_ms_startup_delay; end if; else startup_delay_counter <= C_500_ms_startup_delay; end if; if startup_delay_counter = X"000000" then startup_delay_cmplt <= '1'; else startup_delay_cmplt <= '0'; end if; end if; end process; SD_CARD_PRESENT: process(CLK_IN) begin if rising_edge(CLK_IN) then sd_present <= not SD_PRESENT_BAR_IN; end if; end process; SD_INIT_FLAGS: process(CLK_IN) begin if rising_edge(CLK_IN) then if ir_state = SD_INIT0 then sd_init <= '1'; else sd_init <= '0'; end if; if ir_state = SD_INIT2 then sd_init_attempts_counter <= sd_init_attempts_counter + 1; end if; end if; end process; SD_RD_BLOCK_FLAGS: process(CLK_IN) begin if rising_edge(CLK_IN) then if ir_state = CHECK_FILE_SYS_VERACITY0 then sd_rd_block <= '1'; elsif ir_state = GET_LBA_START_ADDR6 then sd_rd_block <= '1'; else sd_rd_block <= '0'; end if; if ir_state = CHECK_FILE_SYS_VERACITY0 then sd_block_addr <= X"00000000"; elsif ir_state = GET_LBA_START_ADDR6 then sd_block_addr <= lba_block_addr; else sd_block_addr <= X"00000000"; end if; if ir_state = CHECK_FILE_SYS_VERACITY2 then block_rd_addr <= "1"&X"FE"; elsif ir_state = CHECK_FILE_SYS_VERACITY3 then block_rd_addr <= "1"&X"FF"; elsif ir_state = GET_LBA_START_ADDR0 then block_rd_addr <= "1"&X"C6"; elsif ir_state = GET_LBA_START_ADDR1 then block_rd_addr <= "1"&X"C7"; elsif ir_state = GET_LBA_START_ADDR2 then block_rd_addr <= "1"&X"C8"; elsif ir_state = GET_LBA_START_ADDR3 then block_rd_addr <= "1"&X"C9"; elsif ir_state = GET_VOLUME_ID_DATA2 then block_rd_addr <= "0"&X"0D"; elsif ir_state = GET_VOLUME_ID_DATA3 then block_rd_addr <= "0"&X"0E"; elsif ir_state = GET_VOLUME_ID_DATA4 then block_rd_addr <= "0"&X"0F"; elsif ir_state = GET_VOLUME_ID_DATA5 then block_rd_addr <= "0"&X"24"; elsif ir_state = GET_VOLUME_ID_DATA6 then block_rd_addr <= "0"&X"25"; elsif ir_state = GET_VOLUME_ID_DATA7 then block_rd_addr <= "0"&X"26"; elsif ir_state = GET_VOLUME_ID_DATA8 then block_rd_addr <= "0"&X"27"; elsif ir_state = GET_VOLUME_ID_DATA9 then block_rd_addr <= "0"&X"2C"; elsif ir_state = GET_VOLUME_ID_DATA10 then block_rd_addr <= "0"&X"2D"; elsif ir_state = GET_VOLUME_ID_DATA11 then block_rd_addr <= "0"&X"2E"; elsif ir_state = GET_VOLUME_ID_DATA12 then block_rd_addr <= "0"&X"2F"; elsif ir_state = GET_VOLUME_ID_DATA13 then block_rd_addr <= "1"&X"FE"; elsif ir_state = GET_VOLUME_ID_DATA14 then block_rd_addr <= "1"&X"FF"; elsif ir_state = GET_VOLUME_ID_DATA15 then block_rd_addr <= "0"&X"0B"; elsif ir_state = GET_VOLUME_ID_DATA16 then block_rd_addr <= "0"&X"0C"; else block_rd_addr <= (others => '0'); end if; if ir_state = CHECK_FILE_SYS_VERACITY4 then mbr_veracity(7 downto 0) <= block_rd_data; elsif ir_state = CHECK_FILE_SYS_VERACITY5 then mbr_veracity(15 downto 8) <= block_rd_data; end if; end if; end process; LBA_SETUP: process(CLK_IN) begin if rising_edge(CLK_IN) then if ir_state = GET_LBA_START_ADDR2 then lba_block_addr(7 downto 0) <= block_rd_data; elsif ir_state = GET_LBA_START_ADDR3 then lba_block_addr(15 downto 8) <= block_rd_data; elsif ir_state = GET_LBA_START_ADDR4 then lba_block_addr(23 downto 16) <= block_rd_data; elsif ir_state = GET_LBA_START_ADDR5 then lba_block_addr(31 downto 24) <= block_rd_data; end if; end if; end process; VOLUME_DATA: process(CLK_IN) begin if rising_edge(CLK_IN) then if ir_state = GET_VOLUME_ID_DATA4 then sectors_per_cluster <= unsigned(block_rd_data); elsif ir_state = GET_VOLUME_ID_DATA5 then num_reserved_sectors(7 downto 0) <= block_rd_data; elsif ir_state = GET_VOLUME_ID_DATA6 then num_reserved_sectors(15 downto 8) <= block_rd_data; elsif ir_state = GET_VOLUME_ID_DATA7 then sectors_per_fat(7 downto 0) <= block_rd_data; elsif ir_state = GET_VOLUME_ID_DATA8 then sectors_per_fat(15 downto 8) <= block_rd_data; elsif ir_state = GET_VOLUME_ID_DATA9 then sectors_per_fat(23 downto 16) <= block_rd_data; elsif ir_state = GET_VOLUME_ID_DATA10 then sectors_per_fat(30 downto 24) <= block_rd_data(6 downto 0); elsif ir_state = GET_VOLUME_ID_DATA11 then root_dir_cluster(7 downto 0) <= unsigned(block_rd_data); elsif ir_state = GET_VOLUME_ID_DATA12 then root_dir_cluster(15 downto 8) <= unsigned(block_rd_data); elsif ir_state = GET_VOLUME_ID_DATA13 then root_dir_cluster(23 downto 16) <= unsigned(block_rd_data); elsif ir_state = GET_VOLUME_ID_DATA14 then root_dir_cluster(31 downto 24) <= unsigned(block_rd_data); elsif ir_state = GET_VOLUME_ID_DATA15 then vol_signature(7 downto 0) <= block_rd_data; elsif ir_state = GET_VOLUME_ID_DATA16 then vol_signature(15 downto 8) <= block_rd_data; elsif ir_state = GET_VOLUME_ID_DATA17 then bytes_per_sector(7 downto 0) <= block_rd_data; elsif ir_state = GET_VOLUME_ID_DATA18 then bytes_per_sector(15 downto 8) <= block_rd_data; end if; if ir_state = GET_VOLUME_ID_DATA20 then fat_begin_lba <= unsigned(lba_block_addr) + RESIZE(unsigned(num_reserved_sectors), 32); end if; if ir_state = GET_VOLUME_ID_DATA21 then cluster_begin_lba <= fat_begin_lba; elsif ir_state = GET_VOLUME_ID_DATA22 then cluster_begin_lba <= cluster_begin_lba + unsigned(sectors_per_fat&"0"); end if; end if; end process; CMPLT_FLAG: process(CLK_IN) begin if rising_edge(CLK_IN) then if ir_state = SD_INIT_CMPLT then init_cmplt <= '1'; else init_cmplt <= '0'; end if; end if; end process; INIT_ROUTINE_SYNC: process(CLK_IN) begin if rising_edge(CLK_IN) then if RESET_IN = '0' then ir_state <= ir_next_state; else ir_state <= IDLE; end if; end if; end process; INIT_ROUTINE_DECODE: process ( ir_state, sd_error, sd_present, startup_delay_cmplt, sd_busy, sd_init_attempts_counter, mbr_veracity, bytes_per_sector, vol_signature ) begin ir_next_state <= ir_state; -- default is to stay in current state case (ir_state) is when REPORT_ERROR => ir_next_state <= WAIT_FOR_SD_UNPLUGGED; when WAIT_FOR_SD_UNPLUGGED => if sd_present = '0' then ir_next_state <= IDLE; end if; when IDLE => if startup_delay_cmplt = '1' then ir_next_state <= SD_INIT0; end if; when SD_INIT0 => if sd_busy = '1' then ir_next_state <= SD_INIT1; end if; when SD_INIT1 => if sd_busy = '0' then if sd_error = X"0000" then ir_next_state <= CHECK_FILE_SYS_VERACITY0; else ir_next_state <= SD_INIT2; end if; end if; when SD_INIT2 => if sd_init_attempts_counter = C_sd_init_attempts then ir_next_state <= SD_INIT3; else ir_next_state <= SD_INIT0; end if; when SD_INIT3 => ir_next_state <= REPORT_ERROR; when CHECK_FILE_SYS_VERACITY0 => if sd_busy = '1' then ir_next_state <= CHECK_FILE_SYS_VERACITY1; end if; when CHECK_FILE_SYS_VERACITY1 => ir_next_state <= CHECK_FILE_SYS_VERACITY2; when CHECK_FILE_SYS_VERACITY2 => if sd_busy = '0' then ir_next_state <= CHECK_FILE_SYS_VERACITY3; end if; when CHECK_FILE_SYS_VERACITY3 => ir_next_state <= CHECK_FILE_SYS_VERACITY4; when CHECK_FILE_SYS_VERACITY4 => ir_next_state <= CHECK_FILE_SYS_VERACITY5; when CHECK_FILE_SYS_VERACITY5 => ir_next_state <= CHECK_FILE_SYS_VERACITY6; when CHECK_FILE_SYS_VERACITY6 => if mbr_veracity = C_mbr_veracity then ir_next_state <= GET_LBA_START_ADDR0; else ir_next_state <= REPORT_ERROR; end if; when GET_LBA_START_ADDR0 => ir_next_state <= GET_LBA_START_ADDR1; when GET_LBA_START_ADDR1 => ir_next_state <= GET_LBA_START_ADDR2; when GET_LBA_START_ADDR2 => ir_next_state <= GET_LBA_START_ADDR3; when GET_LBA_START_ADDR3 => ir_next_state <= GET_LBA_START_ADDR4; when GET_LBA_START_ADDR4 => ir_next_state <= GET_LBA_START_ADDR5; when GET_LBA_START_ADDR5 => ir_next_state <= GET_LBA_START_ADDR6; when GET_LBA_START_ADDR6 => if sd_busy = '1' then ir_next_state <= GET_VOLUME_ID_DATA0; end if; when GET_VOLUME_ID_DATA0 => ir_next_state <= GET_VOLUME_ID_DATA1; when GET_VOLUME_ID_DATA1 => if sd_busy = '0' then ir_next_state <= GET_VOLUME_ID_DATA2; end if; when GET_VOLUME_ID_DATA2 => ir_next_state <= GET_VOLUME_ID_DATA3; when GET_VOLUME_ID_DATA3 => ir_next_state <= GET_VOLUME_ID_DATA4; when GET_VOLUME_ID_DATA4 => ir_next_state <= GET_VOLUME_ID_DATA5; when GET_VOLUME_ID_DATA5 => ir_next_state <= GET_VOLUME_ID_DATA6; when GET_VOLUME_ID_DATA6 => ir_next_state <= GET_VOLUME_ID_DATA7; when GET_VOLUME_ID_DATA7 => ir_next_state <= GET_VOLUME_ID_DATA8; when GET_VOLUME_ID_DATA8 => ir_next_state <= GET_VOLUME_ID_DATA9; when GET_VOLUME_ID_DATA9 => ir_next_state <= GET_VOLUME_ID_DATA10; when GET_VOLUME_ID_DATA10 => ir_next_state <= GET_VOLUME_ID_DATA11; when GET_VOLUME_ID_DATA11 => ir_next_state <= GET_VOLUME_ID_DATA12; when GET_VOLUME_ID_DATA12 => ir_next_state <= GET_VOLUME_ID_DATA13; when GET_VOLUME_ID_DATA13 => ir_next_state <= GET_VOLUME_ID_DATA14; when GET_VOLUME_ID_DATA14 => ir_next_state <= GET_VOLUME_ID_DATA15; when GET_VOLUME_ID_DATA15 => ir_next_state <= GET_VOLUME_ID_DATA16; when GET_VOLUME_ID_DATA16 => ir_next_state <= GET_VOLUME_ID_DATA17; when GET_VOLUME_ID_DATA17 => ir_next_state <= GET_VOLUME_ID_DATA18; when GET_VOLUME_ID_DATA18 => ir_next_state <= GET_VOLUME_ID_DATA19; when GET_VOLUME_ID_DATA19 => if bytes_per_sector /= C_bytes_per_sector or vol_signature /= C_volume_signature then ir_next_state <= REPORT_ERROR; else ir_next_state <= GET_VOLUME_ID_DATA20; end if; when GET_VOLUME_ID_DATA20 => ir_next_state <= GET_VOLUME_ID_DATA21; when GET_VOLUME_ID_DATA21 => ir_next_state <= GET_VOLUME_ID_DATA22; when GET_VOLUME_ID_DATA22 => ir_next_state <= GET_VOLUME_ID_DATA23; when GET_VOLUME_ID_DATA23 => ir_next_state <= SD_INIT_CMPLT; when SD_INIT_CMPLT => ir_next_state <= SD_INIT_CMPLT; end case; end process; BLOCK_READ_SYNC: process(CLK_IN) begin if rising_edge(CLK_IN) then br_state <= br_next_state; end if; end process; BLOCK_READ_TRIG: process(CLK_IN) begin if rising_edge(CLK_IN) then if ir_state = CHECK_FILE_SYS_VERACITY0 and sd_busy = '1' then perform_block_rd <= '1'; elsif ir_state = GET_LBA_START_ADDR6 and sd_busy = '1' then perform_block_rd <= '1'; else perform_block_rd <= '0'; end if; 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; 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 <= 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 <= IDLE; else br_next_state <= READ_BYTE0; end if; end case; end process; TDP_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); end Behavioral;