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] - Diff between revs 170 and 185

Show entire file | Details | Blame | View Log

Rev 170 Rev 185
Line 1... Line 1...
 
-- 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;
 
 
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

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