OpenCores
URL https://opencores.org/ocsvn/sdhc-sc-core/sdhc-sc-core/trunk

Subversion Repositories sdhc-sc-core

[/] [sdhc-sc-core/] [trunk/] [grpSd/] [unitSdData/] [src/] [SdData-Rtl-a.vhdl] - Rev 185

Compare with Previous | Blame | View Log

-- SDHC-SC-Core
-- Secure Digital High Capacity Self Configuring Core
-- 
-- (C) Copyright 2010, Rainer Kastl
-- All rights reserved.
-- 
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions are met:
--     * Redistributions of source code must retain the above copyright
--       notice, this list of conditions and the following disclaimer.
--     * Redistributions in binary form must reproduce the above copyright
--       notice, this list of conditions and the following disclaimer in the
--       documentation and/or other materials provided with the distribution.
--     * Neither the name of the <organization> nor the
--       names of its contributors may be used to endorse or promote products
--       derived from this software without specific prior written permission.
-- 
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  "AS IS" AND
-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-- DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
-- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-- 
-- File        : SdData-Rtl-a.vhdl
-- Owner       : Rainer Kastl
-- Description : FSM for sending and receiving data via the SD Bus
-- Links       : SD Spec 2.00
-- 
 
architecture Rtl of SdData is
 
	type aState is (idle, send, receive, crcstatus, checkbusy); -- overall states
	type aRegion is (startbit, data, crc, endbit); -- regions in send and receive state
	subtype aCounter is unsigned(LogDualis(512*8)-1 downto 0); -- bit counter
 
	subtype aCrcStatus is std_ulogic_vector(2 downto 0);
 
	-- all registers
	type aReg is record
		State   : aState;
		Region  : aRegion;
		Counter : aCounter;
 
		Mode : aSdDataBusMode; -- standard or wide SD mode
 
		Word        : aWord; -- temporary save for data to write to the read fifo
		WordInvalid : std_ulogic; -- after starting receiving we have to wait for the word to be valid before it can be written to the read fifo
 
		-- outputs
		Data          : aoSdData;
		Controller    : aSdDataToController;
		ReadWriteFifo : aoReadFifo;
		WriteReadFifo : aoWriteFifo;
		DisableSdClk  : std_ulogic;
		CrcStatus     : aCrcStatus;
	end record aReg;
 
	-- default value for registers
	constant cDefaultReg : aReg := (
	State         => idle,
	Region        => startbit,
	Counter       => (others => '0'),
	Mode          => standard,
	WordInvalid   => cInactivated,
	Word          => (others => '0'),
	Data          => cDefaultSdData,
	Controller    => cDefaultSdDataToController,
	ReadWriteFifo => cDefaultoReadFifo,
	WriteReadFifo => cDefaultoWriteFifo,
	DisableSdClk  => cInactivated,
	CrcStatus     => (others => '0'));
 
	type aCrcOut is record
		DataIn  : std_ulogic;
		Data    : std_ulogic_vector(3 downto 0);
	end record aCrcOut;
 
	constant cDefaultCrcOut : aCrcOut := (
	DataIn => cInactivated,
	Data   => (others       => '0'));
 
	type aCrcIn is record
		Correct : std_ulogic_vector(3 downto 0);
		Serial  : std_ulogic_vector(3 downto 0);
	end record aCrcIn;
 
	signal CrcIn     : aCrcIn;
	signal CrcOut    : aCrcOut;
	signal CrcDataIn : std_ulogic_vector(3 downto 0);
	signal R, NextR  : aReg;
 
	-- aliases for bits, bytes and words from the bit counter
	alias RBitC is R.Counter(LogDualis(8)-1 downto 0);
	alias RByteC is R.Counter(LogDualis(4)+LogDualis(8)-1 downto LogDualis(8));
	alias RWordC is R.Counter(R.Counter'high downto LogDualis(4)+LogDualis(8));
	alias RBitInWordC is R.Counter(LogDualis(32)-1 downto 0);
 
begin
 
	-- registered outputs
	oData               <= R.Data;
	oSdDataToController <= R.Controller;
	oReadWriteFifo      <= R.ReadWriteFifo;
	oWriteReadFifo      <= R.WriteReadFifo;
	oDisableSdClk       <= R.DisableSdClk;
 
 
	Regs : process (iClk)
	begin
		-- clock event
		if (iClk'event and iClk = cActivated) then
			if (iRstSync = cActivated) then
				R <= cDefaultReg;
			else
				-- synchronous enable
				if (iStrobe = cActivated) then
					R <= NextR;
				end if;
 
				-- rdreq and wrreq have to be exactly one clock cycle wide
				R.ReadWriteFifo.rdreq <= NextR.ReadWriteFifo.rdreq and iStrobe;
				R.WriteReadFifo.wrreq <= NextR.WriteReadFifo.wrreq and iStrobe;
 
				-- Clock has to be disabled before the next strobe is generated
				R.DisableSdClk        <= NextR.DisableSdClk;
			end if;
		end if;
	end process Regs;
 
	-- Calculate the next state and output
	Comb : process (iData, iSdDataFromController, CrcIn, iReadWriteFifo, iWriteReadFifo, R)
 
		--------------------------------------------------------------------------------
		-- Handle accessing the fifo
		--------------------------------------------------------------------------------
		procedure HandleFifoAccess (signal status : in std_ulogic; signal req : out std_ulogic) is
		begin
			if (status = cActivated) then
				-- stop data transfer to card and wait for a change of the fifo status
				report "Fifo not ready, waiting" severity note;
 
				NextR.DisableSdClk <= cActivated;
				NextR.Counter      <= R.Counter;
				req                <= cInactivated;
			else
				-- enable request and continue transfer with the sd card
				NextR.DisableSdClk <= cInactivated;
				req                <= cActivated;
			end if;
		end procedure HandleFifoAccess;
 
		--------------------------------------------------------------------------------
		-- Set crc outputs so data is shifted in
		--------------------------------------------------------------------------------
		procedure ShiftIntoCrc (constant data : in aSdData) is
		begin
			CrcOut.Data   <= data;
			CrcOut.DataIn <= cActivated;
		end procedure ShiftIntoCrc;
 
		--------------------------------------------------------------------------------
		-- Send data to card and calculate crc
		--------------------------------------------------------------------------------
		procedure SendBitsAndShiftIntoCrc (constant data : in aSdData) is
		begin
			ShiftIntoCrc(data);
			NextR.Data.Data <= data;
		end procedure SendBitsAndShiftIntoCrc;
 
		--------------------------------------------------------------------------------
		-- Calculate the next counter and region
		-- Handles loading next data from fifo or writing data to fifo as well
		--------------------------------------------------------------------------------
		procedure CalcNextAndHandleData (constant send : boolean) is
			-- End and decrement values for standard mode
			variable BitEnd : integer := 0;
			variable BitDec : integer := 1;
		begin
 
			-- reset variables if wide mode is used
			if R.Mode = wide then
				BitEnd := 3;
				BitDec := 4;
			end if;
 
			if (RBitC = BitEnd) then
				-- Byte finished, switch to next byte starting with MSBit
				NextR.Counter <= R.Counter + (16 - BitDec);
 
				if (RByteC = 3) then
					-- Word finished
					NextR.WordInvalid  <= cInactivated; -- received words are no longer invalid
 
					if (RWordC = 127) then
						-- whole block finished, send crc next
						NextR.Region  <= crc;
						NextR.Counter <= to_unsigned(0, aCounter'length);
 
					else
						if (send = true) then
							-- save next word to send from fifo
							NextR.Word <= iReadWriteFifo.q;
						end if;
					end if;
				end if;
			else
				NextR.Counter <= R.Counter - BitDec; -- switch to next bits (MSBit to LSBit)
			end if;
 
			if (send = true) then
				if ((RBitC = BitEnd + BitDec and RByteC = 3 and RWordC < 127)) then
					-- current word almost sent, request next word to send from fifo
					HandleFifoAccess(iReadWriteFifo.rdempty, NextR.ReadWriteFifo.rdreq);
 
				end if;
			else
				if (RByteC = 0 and RBitC = 7 and R.WordInvalid = cInactivated and iSdDataFromController.DisableRb = cInactivated) then
					-- received word is valid, save it to ram
					NextR.WriteReadFifo.data <= R.Word;
					HandleFifoAccess(iWriteReadFifo.wrfull, NextR.WriteReadFifo.wrreq);
				end if;
			end if;
		end procedure CalcNextAndHandleData;
 
		--------------------------------------------------------------------------------
		-- Calculate the bit address in widewidth mode
		--------------------------------------------------------------------------------
		impure
		function IsBitAddrInRangeWideWidth (constant addr : in natural) return boolean is
			variable curHighAddr : integer;
		begin
			-- calculate current address (of the high bit in case of wide mode)
			-- widewidth receiving counts from an offset to 4096
			-- and the bit counter is reversed
			curHighAddr := (127 - to_integer(RWordC)) * 32 + (3 - to_integer(RByteC)) * 8 + to_integer(RBitC);
 
			if (R.Mode = standard) then
				return curHighAddr = addr;
			else
				return curHighAddr >= addr and curHighAddr - 3 <= addr;
			end if;
		end function IsBitAddrInRangeWideWidth;
 
		--------------------------------------------------------------------------------
		-- Get specific bit from data vector
		--------------------------------------------------------------------------------
		impure
		function GetBitFromData (constant addr : in natural) return std_ulogic is
		begin
			if (R.Mode = standard) then
				return iData.Data(0);
			else
				return iData.Data(addr mod 4);
			end if;
		end function GetBitFromData;
 
		variable temp : std_ulogic_vector(3 downto 0) := "0000";
 
	begin
 
		-- default assignments
		NextR                                         <= R;
		NextR.Data.En                                 <= (others => cInactivated);
		NextR.Controller                              <= cDefaultSdDataToController;
		NextR.Controller.WideMode                     <= R.Controller.WideMode;
		NextR.Controller.SpeedBits.HighSpeedSupported <= R.Controller.SpeedBits.HighSpeedSupported;
		NextR.Controller.SpeedBits.SwitchFunctionOK   <= R.Controller.SpeedBits.SwitchFunctionOK;
		NextR.ReadWriteFifo                           <= cDefaultoReadFifo;
		NextR.WriteReadFifo                           <= cDefaultoWriteFifo;
		CrcOut                                        <= cDefaultCrcOut;
 
		case R.State is
			when idle => 
				-- check if card signals that it is busy (the controller has to enable this check)
				if (iSdDataFromController.CheckBusy = cActivated) then
					NextR.State <= crcstatus;
					NextR.Region <= startbit;
					NextR.Counter <= (others => '0');
 
				elsif (R.Mode = wide and iData.Data = cSdStartBits) or (R.Mode = standard and iData.Data(0) = cSdStartBit) then
					-- start receiving
					NextR.Region      <= data;
					NextR.State       <= receive;
					NextR.Counter     <= to_unsigned(7,aCounter'length);
					NextR.WordInvalid <= cActivated;
 
					-- which kind of response is expected?
					if (iSdDataFromController.DataMode = widewidth) then
						if (iSdDataFromController.ExpectBits = ScrBits) then
							NextR.Counter <= to_unsigned(cScrBitsCount, aCounter'length);
						elsif (iSdDataFromController.ExpectBits = SwitchFunctionBits) then 
							NextR.Counter <= to_unsigned(cSwitchFunctionBitsCount, aCounter'length);
						end if;
					end if;
 
				elsif (iSdDataFromController.Valid = cActivated) then
					-- sending requested by controller
 
					case iReadWriteFifo.rdempty is
						when cActivated => 
							-- no data is available to send -> stall
							report "Fifo empty, waiting for data" severity note;
							NextR.DisableSdClk <= cActivated;
 
						when cInactivated => 
							-- data is available, start sending
							NextR.State               <= send;
							NextR.Region              <= startbit;
							NextR.ReadWriteFifo.rdreq <= cActivated;
							NextR.DisableSdClk        <= cInactivated;
							NextR.Counter             <= to_unsigned(7, aCounter'length);
 
						when others => 
							report "rdempty invalid" severity error;
					end case;
				else
					-- switch between standard and wide mode only if nothing else is going on
					NextR.Mode <= iSdDataFromController.Mode; 
				end if;
 
			when crcstatus =>		
				case R.Region is
					when startbit => 
						if (iData.Data(0) = cSdStartBit) then
							NextR.Region <= data;
						end if;
 
					when data => 
						NextR.CrcStatus(to_integer(R.Counter)) <= iData.Data(0);
						NextR.Counter <= R.Counter + 1;
 
						if (R.Counter = 2) then
							NextR.Region <= endbit;
						end if;
 
					when endbit => 
						if (R.CrcStatus /= "010") then
							NextR.Controller.Err <= cActivated;
							NextR.State <= idle;
						else
							NextR.State <= checkbusy;
						end if;
					when others => 
						report "Invalid state reached" severity error;
				end case;
 
			when checkbusy => 
				NextR.Controller.Busy <= cActivated;
 
				if (iData.Data(0) = cActivated) then
					NextR.Controller.Valid <= cActivated;
					NextR.State <= idle;
				end if;
 
			when send =>
 
				-- Handle the data enable signal
				case R.Mode is
					when wide => 
						NextR.Data.En <= (others => cActivated);
 
					when standard => 
						NextR.Data.En <= "0001";
 
					when others => 
						report "Invalid SDData mode" severity error;
						NextR.Data.En <= (others => 'X');
				end case;
 
				case R.Region is
					when startbit => 
						SendBitsAndShiftIntoCrc(cSdStartBits);
						NextR.Region <= data;
 
						-- save data to send from fifo
						NextR.Word <= iReadWriteFifo.q;
 
					when data => 
						case R.Mode is
							when wide => 
								for i in 0 to 3 loop
									temp(3 - i) := R.Word(to_integer(RBitInWordC) - i);
								end loop;
 
							when standard => 
								temp := "---" & R.Word(to_integer(RBitInWordC));
 
							when others => 
								temp := "XXXX";
						end case;
 
						SendBitsAndShiftIntoCrc(temp);
						CalcNextAndHandleData(true);							
 
					when crc => 
						NextR.Data.Data <= CrcIn.Serial;
 
						if (R.Counter = 15) then
						-- all crc bits sent
							NextR.Counter        <= to_unsigned(0, aCounter'length);
							NextR.Region         <= endbit;
							NextR.Controller.Ack <= cActivated;
 
						else
							NextR.Counter <= R.Counter + 1;
						end if;
 
					when endbit => 
						NextR.Data.Data <= cSdEndBits;
						NextR.State     <= idle;
 
					when others => 
						report "Region not handled" severity error;
				end case;	
 
			when receive => 
				case R.Region is
					when data => 
						-- save received data to temporary word register
						case R.Mode is
							when standard => 
								NextR.Word(to_integer(RBitInWordC)) <= iData.Data(0);
 
							when wide => 
								for i in 0 to 3 loop
									NextR.Word(to_integer(RBitInWordC) - i) <= iData.Data(3 - i);
								end loop;
 
							when others => 
								report "Unhandled mode" severity error;
						end case;	
 
						ShiftIntoCrc(std_ulogic_vector(iData.Data));
						CalcNextAndHandleData(false);
 
						-- check responses 
						if (iSdDataFromController.DataMode = widewidth) then
							if (iSdDataFromController.ExpectBits = ScrBits) then
								if (IsBitAddrInRangeWideWidth(cWideModeBitAddr)) then
									NextR.Controller.WideMode <= GetBitFromData(cWideModeBitAddr);
								end if;
							end if;
 
							if (iSdDataFromController.ExpectBits = SwitchFunctionBits) then
								if (IsBitAddrInRangeWideWidth(cHighSpeedBitAddr)) then
									NextR.Controller.SpeedBits.HighSpeedSupported <= GetBitFromData(cHighSpeedBitAddr);
								elsif (IsBitAddrInRangeWideWidth(cSwitchFunctionBitLowAddr)) then
									NextR.Controller.SpeedBits.SwitchFunctionOK <= iData.Data;
								end if;
							end if;
						end if;
 
					when crc =>
						-- save last word to ram
						ShiftIntoCrc(std_ulogic_vector(iData.Data));
 
						if (R.Counter = 15) then
							-- all 16 crc bits received
							NextR.Region <= endbit;
						else
							NextR.Counter <= R.Counter + 1;
 
							if (R.Counter = 0 and iSdDataFromController.DisableRb = cInactivated) then
								HandleFifoAccess(iWriteReadFifo.wrfull, NextR.WriteReadFifo.wrreq);
								NextR.WriteReadFifo.data <= R.Word;
							end if;
						end if;
 
					when endbit => 
						-- in standard mode all unused crcs are correct, because no data was shifted in
						if (CrcIn.Correct = "1111") then 
							NextR.Controller.Valid <= cActivated;
						else
							NextR.Controller.Err <= cActivated;
						end if;
 
						NextR.Region <= startbit;
						NextR.State  <= idle;
 
					when others => 
						report "Region not handled" severity error;
				end case;
 
			when others => 
				report "State not handled" severity error;
		end case;
 
	end process Comb;
 
	CrcDataIn <= (others => CrcOut.DataIn) when R.Mode = wide else "000" & CrcOut.DataIn;
 
	crcs: for idx in 3 downto 0 generate
 
		CRC_inst : entity work.Crc
		generic map (
			gPolynom => crc16
		)
		port map (
			iClk         => iClk,
			iRstSync     => iRstSync,
			iStrobe      => iStrobe,
			iClear		 => cInactivated,
			iDataIn      => CrcDataIn(idx),
			iData        => CrcOut.Data(idx),
			oIsCorrect   => CrcIn.Correct(idx),
			oSerial      => CrcIn.Serial(idx)
		);
 
	end generate crcs;
 
end architecture Rtl;
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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