URL
https://opencores.org/ocsvn/sdhc-sc-core/sdhc-sc-core/trunk
Subversion Repositories sdhc-sc-core
[/] [sdhc-sc-core/] [trunk/] [grpSd/] [unitSdController/] [src/] [SdController-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 : SdController-Rtl-a.vhdl -- Owner : Rainer Kastl -- Description : Main FSM controlling Cmd and Data FSMs, communicates with Wb -- Links : -- architecture Rtl of SdController is type aSdControllerState is (startup, init, config, requestnewoperation, idle, invalidCard, read, write); type aCmdRegion is (CMD0, CMD8, ACMD41, CMD2, CMD3, SelectCard, CheckBusWidth, SetBusWidth, CheckSpeed, ChangeSpeed, GetStatus); type aRegion is (idle, send, response, waitstate, senddata, receivedata, checkbusy, waitstatedata); subtype aCounter is natural range 0 to (512/32)-1; constant cDefaultToSdCmd : aSdCmdFromController := ( (id => (others => '0'), arg => (others => '0')), Valid => cInactivated, ExpectCID => cInactivated, CheckCrc => cActivated); type aSdControllerReg is record State : aSdControllerState; CmdRegion : aCmdRegion; Region : aRegion; Counter : aCounter; SendCMD55 : std_ulogic; SentCMD55 : std_ulogic; HCS : std_ulogic; CCS : std_ulogic; RCA : aSdRCA; CardStatus : aSdCardStatus; ToSdCmd : aSdCmdFromController; ToSdData : aSdDataFromController; ToDataRam : aSdControllerToRam; ToSdWbSlave : aSdControllerToSdWbSlave; HighSpeed : std_ulogic; OperationBlock : aOperationBlock; LedBank : std_ulogic_vector(7 downto 0); end record aSdControllerReg; constant cDefaultSdControllerReg : aSdControllerReg := ( State => startup, CmdRegion => CMD0, Region => idle, Counter => 0, SendCMD55 => cInactivated, SentCMD55 => cInactivated, HCS => cActivated, CCS => cInactivated, RCA => cDefaultRCA, CardStatus => cDefaultSdCardStatus, ToSdCmd => cDefaultToSdCmd, ToSdData => cDefaultSdDataFromController, ToDataRam => cDefaultSdControllerToRam, ToSdWbSlave => cDefaultSdControllerToSdWbSlave, HighSpeed => cInactivated, OperationBlock => cDefaultOperationBlock, LedBank => (others => '0')); signal R, NextR : aSdControllerReg; constant cReadTimeoutNat : natural := gClkFrequency / (1 sec / gReadTimeout) - 1; constant cWriteTimeoutNat : natural := gClkFrequency / (1 sec / gWriteTimeout) - 1; constant cNcrTimeoutNatLow : natural := gClkFrequency / (1 sec / (1 sec / 25E6 * 8)) - 1; constant cNcrTimeoutNatHigh : natural := gClkFrequency / (1 sec / (1 sec / 50E6 * 8)) - 1; constant cStartupTimeoutNat : natural := gClkFrequency / (1 sec / gStartupTimeout) - 1; constant cMaxTimeoutBitWidth : natural := LogDualis(cWriteTimeoutNat); subtype aTimeoutValue is unsigned(cMaxTimeoutBitWidth - 1 downto 0); constant cNcrTimeoutLow : aTimeoutValue := to_unsigned(cNcrTimeoutNatLow, aTimeoutValue'length); constant cNcrTimeoutHigh : aTimeoutValue := to_unsigned(cNcrTimeoutNatHigh, aTimeoutValue'length); constant cStartupTimeout : aTimeoutValue := to_unsigned(cStartupTimeoutNat, aTimeoutValue'length); constant cReadTimeout : aTimeoutValue := to_unsigned(cReadTimeoutNat, aTimeoutValue'length); constant cWriteTimeout : aTimeoutValue := to_unsigned(cWriteTimeoutNat, aTimeoutValue'length); signal TimeoutEnable : std_ulogic; signal TimeoutDisable : std_ulogic; signal Timeout : std_ulogic; signal TimeoutMax : unsigned(cMaxTimeoutBitWidth - 1 downto 0); begin oSdCmd <= R.ToSdCmd; oSdData <= R.ToSdData; oSdWbSlave <= R.ToSdWbSlave; oHighSpeed <= R.HighSpeed; oLedBank <= R.LedBank; Regs : process (iClk, iRstSync) begin if (iClk'event and iClk = cActivated) then if (iRstSync = cActivated) then R <= cDefaultSdControllerReg; else R <= NextR; end if; end if; end process Regs; Comb : process (iSdCmd, iSdData, iSdWbSlave, Timeout, R) variable ocr : aSdRegOCR; variable arg : aSdCmdArg; variable NextRegion : aRegion; variable NextCmdRegion : aCmdRegion; variable NextState : aSdControllerState; procedure EnableNcrTimeout is begin TimeoutEnable <= cActivated; if (R.HighSpeed = cInactivated) then TimeoutMax <= cNcrTimeoutLow; else TimeoutMax <= cNcrTimeoutHigh; end if; end procedure EnableNcrTimeout; begin -- default assignments NextR <= R; NextR.ToSdCmd <= cDefaultToSdCmd; TimeoutEnable <= cInactivated; TimeoutDisable <= cInactivated; TimeoutMax <= to_unsigned(0, TimeoutMax'length); NextRegion := R.Region; NextCmdRegion := R.CmdRegion; NextState := R.State; case R.State is when startup => TimeoutEnable <= cActivated; TimeoutMax <= cStartupTimeout; if (Timeout = cActivated) then TimeoutDisable <= cActivated; NextR.State <= init; NextR.CmdRegion <= CMD0; NextR.Region <= send; end if; when init => case R.CmdRegion is when CMD0 => case R.Region is when send => NextR.ToSdCmd.Content.id <= cSdCmdGoIdleState; NextR.CardStatus <= cDefaultSdCardStatus; NextRegion := waitstate; when waitstate => NextRegion := send; NextCmdRegion := CMD8; when others => report "SdController: Unhandled state" severity error; end case; when CMD8 => case R.Region is when send => NextR.ToSdCmd.Content.id <= cSdCmdSendIfCond; NextR.ToSdCmd.Content.arg <= cSdArgVoltage; NextRegion := response; when response => if (iSdCmd.Valid = cActivated) then if (iSdCmd.Content.id = cSdCmdSendIfCond and iSdCmd.Content.arg = cSdArgVoltage) then NextR.Region <= waitstate; NextR.HCS <= cActivated; else NextR.State <= invalidCard; end if; elsif (Timeout = cActivated) then NextR.HCS <= cInactivated; NextR.CmdRegion <= ACMD41; NextR.Region <= send; NextR.SendCMD55 <= cActivated; end if; when waitstate => NextCmdRegion := ACMD41; NextRegion := send; NextR.SendCMD55 <= cActivated; when others => report "SdController: Unhandled state" severity error; end case; when ACMD41 => if (R.SendCMD55 = cInactivated) then case R.Region is when send => ocr.nBusy := '0'; ocr.ccs := R.HCS; ocr.voltagewindow := cVoltageWindow; NextR.ToSdCmd.Content.id <= cSdCmdACMD41; NextR.ToSdCmd.Content.arg <= OCRToArg(ocr); NextRegion := response; when response => NextR.ToSdCmd.CheckCrc <= cInactivated; if (iSdCmd.Valid = cActivated) then NextR.CmdRegion <= CMD8; NextR.Region <= waitstate; if (iSdCmd.Content.id = cSdR3Id) then ocr := ArgToOcr(iSdCmd.Content.arg); if (ocr.nBusy = cnInactivated) then if (ocr.voltagewindow /= cVoltageWindow) then NextR.State <= invalidCard; else NextR.CCS <= ocr.ccs; NextR.CmdRegion <= ACMD41; NextR.Region <= waitstate; end if; end if; end if; elsif (Timeout = cActivated) then NextR.State <= invalidCard; end if; when waitstate => NextCmdRegion := CMD2; NextRegion := send; when others => report "SdController: Unhandled state" severity error; end case; end if; when CMD2 => case R.Region is when send => NextR.ToSdCmd.Content.id <= cSdCmdAllSendCID; NextR.ToSdCmd.Valid <= cActivated; NextRegion := response; when response => NextR.ToSdCmd.ExpectCID <= cActivated; if (iSdCmd.Valid = cActivated) then NextR.State <= invalidCard; if (iSdCmd.Content.id = cSdR2Id) then NextR.State <= init; NextR.Region <= waitstate; end if; elsif (Timeout = cActivated) then NextR.State <= invalidCard; end if; when waitstate => NextCmdRegion := CMD3; NextRegion := send; when others => report "SdController: Unhandled state" severity error; end case; when CMD3 => case R.Region is when send => NextR.ToSdCmd.Content.id <= cSdCmdSendRelAdr; NextR.ToSdCmd.Valid <= cActivated; NextRegion := response; when response => if (iSdCmd.Valid = cActivated) then if (iSdCmd.Content.id = cSdCmdSendRelAdr) then NextR.RCA <= iSdCmd.Content.arg(31 downto 16); NextR.Region <= waitstate; end if; elsif (Timeout = cActivated) then NextR.State <= invalidCard; end if; when waitstate => NextState := config; NextCmdRegion := SelectCard; NextRegion := send; when others => report "SdController: Unhandled region" severity error; end case; when others => report "SdController: Unhandled CmdRegion" severity error; end case; when config => case R.CmdRegion is when SelectCard => case R.Region is when send => NextR.ToSdCmd.Content.id <= cSdCmdSelCard; NextR.ToSdCmd.Content.arg <= R.RCA & X"0000"; NextRegion := response; when response => -- Response R1b: with busy! if (iSdCmd.Valid = cActivated) then if (iSdCmd.Content.id = cSdCmdSelCard) then NextR.CardStatus <= iSdCmd.Content.arg; if (iSdCmd.Content.arg(cSdStatusReadyForDataBit) = cActivated) then NextR.Region <= waitstatedata; else NextR.Region <= waitstate; end if; else NextR.State <= invalidCard; end if; elsif (Timeout = cActivated) then NextR.State <= invalidCard; end if; when waitstate => NextRegion := checkbusy; when waitstatedata => NextR.SendCMD55 <= cActivated; NextCmdRegion := CheckBusWidth; NextRegion := send; when others => report "Unhandled Region" severity error; end case; when CheckBusWidth => if (R.SendCMD55 = cInactivated) then NextR.ToSdData.DataMode <= widewidth; NextR.ToSdData.ExpectBits <= ScrBits; case R.Region is when send => NextR.ToSdCmd.Content.id <= cSdCmdSendSCR; NextR.ToSdCmd.Content.arg <= (others => '0'); -- stuff bits NextRegion := response; when response => if (iSdCmd.Valid = cActivated) then if (iSdCmd.Content.id = cSdCmdSendSCR) then NextR.CardStatus <= iSdCmd.Content.arg; NextR.Region <= receivedata; TimeoutDisable <= cActivated; else NextR.State <= invalidCard; end if; elsif (Timeout = cActivated) then NextR.State <= invalidCard; end if; when receivedata => null; when waitstatedata => NextRegion := send; if (Timeout = cActivated) then if (iSdData.WideMode = cActivated) then NextCmdRegion := SetBusWidth; NextR.SendCMD55 <= cActivated; else NextCmdRegion := CheckSpeed; end if; end if; when others => report "Unhandled region" severity error; end case; end if; when SetBusWidth => if (R.SendCMD55 = cInactivated) then case R.Region is when send => NextR.ToSdCmd.Content.id <= cSdCmdSetBusWidth; NextR.ToSdCmd.Content.arg(1 downto 0) <= cSdWideBusWidth; NextRegion := response; when response => if (iSdCmd.Valid = cActivated) then if (iSdCmd.Content.id = cSdCmdSetBusWidth) then NextR.CardStatus <= iSdCmd.Content.arg; NextR.Region <= waitstate; else NextR.State <= invalidCard; end if; elsif (Timeout = cActivated) then NextR.State <= invalidCard; end if; when waitstate => NextR.ToSdData.Mode <= wide; -- NextR.LedBank(4) <= cActivated; if gHighSpeedMode = true then NextRegion := send; NextCmdRegion := CheckSpeed; else NextState := idle; end if; when others => report "Unhandled region" severity error; end case; end if; when CheckSpeed => NextR.ToSdData.DataMode <= widewidth; NextR.ToSdData.ExpectBits <= SwitchFunctionBits; case R.Region is when send => NextR.ToSdCmd.Content.id <= cSdCmdSwitchFunction; NextR.ToSdCmd.Content.arg <= cSdCmdCheckSpeedSupport; NextRegion := response; when response => if (iSdCmd.Valid = cActivated) then if (iSdCmd.Content.id = cSdCmdSwitchFunction) then NextR.CardStatus <= iSdCmd.Content.arg; NextR.Region <= receivedata; else NextR.State <= invalidCard; end if; elsif (Timeout = cActivated) then NextR.State <= invalidCard; end if; when receivedata => null; when waitstatedata => if (Timeout = cActivated) then -- check if high speed mode is supported if (iSdData.SpeedBits.HighSpeedSupported = cActivated and iSdData.SpeedBits.SwitchFunctionOK = X"1") then NextRegion := send; NextCmdRegion := ChangeSpeed; else NextRegion := idle; NextState := requestnewoperation; end if; end if; when others => report "Unhandled region" severity error; end case; when ChangeSpeed => case R.Region is when send => NextR.ToSdCmd.Content.id <= cSdCmdSwitchFunction; NextR.ToSdCmd.Content.arg <= cSdCmdSwitchSpeed; NextRegion := response; when response => if (iSdCmd.Valid = cActivated) then if (iSdCmd.Content.id = cSdCmdSwitchFunction) then NextR.CardStatus <= iSdCmd.Content.arg; NextR.Region <= receivedata; else NextR.State <= invalidCard; end if; elsif (Timeout = cActivated) then NextR.State <= invalidCard; end if; when receivedata => when waitstatedata => if (Timeout = cActivated) then -- check if switching was successful if (iSdData.SpeedBits.HighSpeedSupported = cActivated and iSdData.SpeedBits.SwitchFunctionOK = X"1") then NextR.HighSpeed <= cActivated; NextRegion := send; NextCmdRegion := GetStatus; --NextR.LedBank(5)<= cActivated; else NextRegion := idle; NextState := requestnewoperation; end if; end if; when others => report "Unhandled region" severity error; end case; when GetStatus => case R.Region is when idle => EnableNcrTimeout; if (Timeout = cActivated) then NextR.Region <= send; end if; when send => NextR.ToSdCmd.Content.id <= cSdCmdSendStatus; NextR.ToSdCmd.Content.arg(31 downto 16) <= R.RCA; NextRegion := response; when response => if (iSdCmd.Valid = cActivated) then if (iSdCmd.Content.id = cSdCmdSendStatus) then NextR.CardStatus <= iSdCmd.Content.arg; NextR.Region <= waitstate; else NextR.State <= invalidCard; end if; elsif (Timeout = cActivated) then NextR.State <= invalidCard; end if; when waitstate => NextRegion := idle; NextState := requestnewoperation; when others => report "Unhandled region" severity error; end case; when others => report "Unhandled CmdRegion" severity error; end case; when read => NextR.ToSdData.DataMode <= usual; case R.Region is when send => NextR.LedBank(0) <= cActivated; -- send a read command NextR.ToSdCmd.Content.id <= cSdCmdReadSingleBlock; -- we get a block address, but a standard capacity card needs a byte address case R.CCS is when cActivated => NextR.ToSdCmd.Content.arg <= R.OperationBlock.StartAddr; when cInactivated => NextR.ToSdCmd.Content.arg <= R.OperationBlock.StartAddr(31-9 downto 0) & X"00" & '0'; -- calculate byte address when others => report "Invalid CCS" severity error; end case; NextRegion := response; when response => NextR.LedBank(1) <= cActivated; -- wait for the response and handle it if (iSdCmd.Valid = cActivated) then if (iSdCmd.Content.id = cSdCmdReadSingleBlock) then NextR.CardStatus <= iSdCmd.Content.arg; NextR.Region <= receivedata; else NextR.State <= invalidCard; end if; elsif (Timeout = cActivated) then NextR.State <= invalidCard; end if; when receivedata => NextR.LedBank(2) <= cActivated; when waitstatedata => NextR.LedBank(3) <= cActivated; NextRegion := idle; NextState := requestnewoperation; when others => report "Unhandled region"; end case; when write => NextR.ToSdData.DataMode <= usual; case R.Region is when send => -- send a write command NextR.ToSdCmd.Content.id <= cSdCmdWriteSingleBlock; -- we get a block address, but a standard capacity card needs a byte address case R.CCS is when cActivated => NextR.ToSdCmd.Content.arg <= R.OperationBlock.StartAddr; when cInactivated => NextR.ToSdCmd.Content.arg <= R.OperationBlock.StartAddr(31-9 downto 0) & X"00" & '0'; -- calculate byte address when others => report "Invalid CCS" severity error; end case; NextRegion := response; when response => -- wait for the response and handle it if (iSdCmd.Valid = cActivated) then if (iSdCmd.Content.id = cSdCmdWriteSingleBlock) then NextR.CardStatus <= iSdCmd.Content.arg; NextR.Region <= senddata; else NextR.State <= invalidCard; end if; elsif (Timeout = cActivated) then NextR.State <= invalidCard; end if; when senddata => NextRegion := checkbusy; when checkbusy => null; when waitstatedata => NextRegion := idle; NextState := requestnewoperation; when others => report "Unhandled region"; end case; when requestnewoperation => NextR.LedBank <= (others => '0'); NextR.ToSdData.DisableRb <= cInactivated; NextR.ToSdWbSlave.ReqOperation <= not R.ToSdWbSlave.ReqOperation; NextR.State <= idle; when idle => NextR.LedBank(6) <= cActivated; -- wait for next operation if (iSdWbSlave.AckOperation = cActivated) then -- save operation NextR.OperationBlock <= iSdWbSlave.OperationBlock; -- handle operations case iSdWbSlave.OperationBlock.Operation is when cOperationRead => NextR.State <= read; NextR.Region <= send; when cOperationWrite => NextR.State <= write; NextR.Region <= send; when others => NextR.State <= requestnewoperation; report "Unknown operation" severity error; end case; NextR.LedBank(6) <= cInactivated; end if; when invalidCard => NextR.LedBank(7) <= cActivated; when others => report "SdController: Unhandled state" severity error; end case; case R.Region is when idle => -- do nothing null; when send => NextR.ToSdCmd.Valid <= cActivated; if (R.SendCMD55 = cActivated) then NextR.ToSdCmd.Content.id <= cSdNextIsACMD; NextR.ToSdCmd.Content.arg <= R.RCA & X"0000"; NextRegion := response; end if; if (iSdCmd.Ack = cActivated) then NextR.ToSdCmd.Valid <= cInactivated; NextR.Region <= NextRegion; end if; when response => -- oLedBank(0) <= cActivated; TimeoutEnable <= cActivated; TimeoutMax <= cReadTimeout; if (iSdCmd.Valid = cActivated) then TimeoutDisable <= cActivated; end if; if (R.SendCMD55 = cActivated) then if (iSdCmd.Valid = cActivated) then if (iSdCmd.Content.id = cSdNextIsACMD) then NextR.CardStatus <= iSdCmd.Content.arg; NextR.Region <= waitstate; if (iSdCmd.Content.arg(cSdArgAppCmdPos) = cActivated) then NextR.SentCMD55 <= cActivated; end if; else NextR.State <= invalidCard; end if; elsif (Timeout = cActivated) then NextR.State <= startup; NextR.CmdRegion <= CMD0; NextR.Region <= idle; end if; end if; when waitstate => EnableNcrTimeout; if (Timeout = cActivated) then if (R.SentCMD55 = cActivated) then NextR.SentCMD55 <= cInactivated; NextR.SendCMD55 <= cInactivated; NextRegion := send; end if; TimeoutDisable <= cActivated; NextR.Region <= NextRegion; NextR.CmdRegion <= NextCmdRegion; NextR.State <= NextState; end if; when senddata => NextR.ToSdData.Valid <= cActivated; if (iSdData.Ack = cActivated) then NextR.ToSdData.Valid <= cInactivated; NextR.Region <= NextRegion; end if; when checkbusy => NextR.ToSdData.CheckBusy <= cActivated; TimeoutEnable <= cActivated; TimeoutMax <= cWriteTimeout; if (iSdData.Valid = cActivated) then NextR.Region <= waitstatedata; NextR.ToSdData.CheckBusy <= cInactivated; TimeoutDisable <= cActivated; end if; when receivedata => TimeoutEnable <= cActivated; TimeoutMax <= cReadTimeout; if (iSdData.Err = cActivated) then NextR.State <= init; TimeoutDisable <= cActivated; elsif (iSdData.Valid = cActivated) then NextR.Region <= waitstatedata; TimeoutDisable <= cActivated; elsif (Timeout = cActivated) then NextR.State <= invalidCard; NextR.LedBank(5) <= cActivated; end if; when waitstatedata => EnableNcrTimeout; if (Timeout = cActivated) then TimeoutDisable <= cActivated; NextR.Region <= NextRegion; NextR.CmdRegion <= NextCmdRegion; NextR.State <= NextState; end if; when others => report "Unhandled region" severity error; end case; end process Comb; TimeoutCounter_inst : entity work.Counter generic map ( gBitWidth => cMaxTimeoutBitWidth ) port map ( iClk => iClk, iRstSync => iRstSync, iEnable => TimeoutEnable, iDisable => TimeoutDisable, iMax => TimeoutMax, oStrobe => Timeout); end architecture Rtl;