URL
https://opencores.org/ocsvn/pdp8/pdp8/trunk
Subversion Repositories pdp8
[/] [pdp8/] [trunk/] [pdp8/] [rk8e/] [sd.vhd] - Rev 2
Compare with Previous | Blame | View Log
-------------------------------------------------------------------- --! --! PDP-8 Processor --! --! \brief --! RK8E Secure Digital Interface --! --! \details --! The SD Interface reads or writes a 256 word (512 byte) --! sector to the SD device. This interfaces uses a --! SPI interface (implemented independantly) to communicate --! with the SD device. --! --! The RK8E controller has a LEN bit in the Command Register --! which causes the controller to perform a 128 word (256 byte) --! disk operation. This eventually drives the sdLEN pin --! of this entity. --! --! Section 11.14.7.11 of the External Bus Options Maintenance --! Manual Volume 3 says the following: --! --! \code --! If the RK8-E has been instructed to write 128 words, --! 128th word is asserted after 128 words (half block) --! have been transferred. The 128th word ends data --! transfer operations and the disk reads or writes zeros --! until the full block of data (256 words) has been read --! or written. --! \endcode --! --! It is fortunate that the controller works as described --! above because interactions between the controller and --! the SD disk are always 256 words (512 bytes). The SD --! device cannot support 128 word (256 byte) transfers. --! --! \file --! sd.vhd --! --! \author --! Rob Doyle - doyle (at) cox (dot) net --! -------------------------------------------------------------------- -- -- Copyright (C) 2012 Rob Doyle -- -- This source file may be used and distributed without -- restriction provided that this copyright statement is not -- removed from the file and that any derivative work contains -- the original copyright notice and the associated disclaimer. -- -- This source file is free software; you can redistribute it -- and/or modify it under the terms of the GNU Lesser General -- Public License as published by the Free Software Foundation; -- version 2.1 of the License. -- -- This source is distributed in the hope that it will be -- useful, but WITHOUT ANY WARRANTY; without even the implied -- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -- PURPOSE. See the GNU Lesser General Public License for more -- details. -- -- You should have received a copy of the GNU Lesser General -- Public License along with this source; if not, download it -- from http://www.gnu.org/licenses/lgpl.txt -- -------------------------------------------------------------------- -- -- Comments are formatted for doxygen -- library ieee; --! IEEE Library use ieee.std_logic_1164.all; --! IEEE 1164 use ieee.numeric_std.all; --! IEEE Numeric Std use work.cpu_types.all; --! CPU Types use work.sdspi_types.all; --! SPI Types use work.sd_types.all; --! SD Types -- --! RK8E Secure Digital Interface Entity -- entity eSD is port ( sys : in sys_t; --! Clock/Reset ioclr : in std_logic; --! IOCLR -- PDP8 Interface dmaDIN : in data_t; --! DMA Data Into Disk dmaDOUT : out data_t; --! DMA Data Out of Disk dmaADDR : out addr_t; --! DMA Address dmaRD : out std_logic; --! DMA Read dmaWR : out std_logic; --! DMA Write dmaREQ : out std_logic; --! DMA Request dmaGNT : in std_logic; --! DMA Grant -- Interface to SD Hardware sdMISO : in std_logic; --! SD Data In sdMOSI : out std_logic; --! SD Data Out sdSCLK : out std_logic; --! SD Clock sdCS : out std_logic; --! SD Chip Select -- RK8E Interface sdOP : in sdOP_t; --! SD OP sdMEMaddr : in addr_t; --! Memory Address sdDISKaddr : in sdDISKaddr_t; --! Disk Address sdLEN : in sdLEN_t; --! Sector Length sdSTAT : out sdSTAT_t --! Status ); end eSD; -- --! RK8E Secure Digital Interface RTL -- architecture rtl of eSD is -- -- Sending leading 0xff just sends clocks with data parked. -- constant sdCMD0 : sdCMD_t := (x"40", x"00", x"00", x"00", x"00", x"95"); constant sdCMD8 : sdCMD_t := (x"48", x"00", x"00", x"01", x"aa", x"87"); constant sdCMD13 : sdCMD_t := (x"4d", x"00", x"00", x"00", x"00", x"ff"); constant sdACMD41 : sdCMD_t := (x"69", x"40", x"00", x"00", x"00", x"ff"); constant sdCMD55 : sdCMD_t := (x"77", x"00", x"00", x"00", x"00", x"ff"); constant sdCMD58 : sdCMD_t := (x"7a", x"00", x"00", x"00", x"00", x"ff"); type state_t is (stateRESET, -- Init States stateINIT00, stateINIT01, stateINIT02, stateINIT03, stateINIT04, stateINIT05, stateINIT06, stateINIT07, stateINIT08, stateINIT09, stateINIT10, stateINIT11, stateINIT12, stateINIT13, stateINIT14, stateINIT15, stateINIT16, stateINIT17, -- Read States stateREAD00, stateREAD01, stateREAD02, stateREAD03, stateREAD04, stateREAD05, stateREAD06, stateREAD07, stateREAD08, stateREAD09, -- Write States stateWRITE00, stateWRITE01, stateWRITE02, stateWRITE03, stateWRITE04, stateWRITE05, stateWRITE06, stateWRITE07, stateWRITE08, stateWRITE09, stateWRITE10, stateWRITE11, stateWRITE12, stateWRITE13, stateWRITE14, stateWRITE15, stateWRITE16, -- Other States stateFINI, stateIDLE, stateDONE, stateINFAIL, stateRWFAIL); signal state : state_t; --! Current State signal spiOP : spiOP_t; --! SPI Op signal spiRXD : sdBYTE_t; --! SPI Received Data signal spiTXD : sdBYTE_t; --! SPI Transmit Data signal spiDONE : std_logic; --! Asserted when SPI is done signal bytecnt : integer range 0 to 65535;--! Byte Counter signal sdCMD17 : sdCMD_t; --! CMD17 signal sdCMD24 : sdCMD_t; --! CMD24 signal memADDR : addr_t; --! Memory Address signal memBUF : std_logic_vector(0 to 3);--! Memory Buffer signal memREQ : std_logic; --! DMA Request signal abort : std_logic; --! Abort this command signal timeout : integer range 0 to 499999;--! Timeout signal rdCNT : sdBYTE_t; --! Read Counter signal wrCNT : sdBYTE_t; --! Write Counter signal err : sdBYTE_t; --! Error State signal val : sdBYTE_t; --! Error Value signal sdSTATE : sdSTATE_t; --! State constant nCR : integer := 8; --! NCR from SD Spec constant nAC : integer := 1023; --! NAC from SD Spec constant nWR : integer := 20; --! NWR from SD Spec begin --! --! SD_STATE: --! This process assumes a 50 MHz clock -- SD_STATE : process(sys) begin if sys.rst = '1' then err <= (others => '0'); val <= (others => '0'); rdCNT <= (others => '0'); wrCNT <= (others => '0'); spiOP <= spiNOP; bytecnt <= 0; dmaRD <= '0'; dmaWR <= '0'; memREQ <= '0'; memBUF <= (others => '0'); memADDR <= (others => '0'); dmaDOUT <= (others => '0'); spiTXD <= (others => '0'); sdCMD17 <= (x"51", x"00", x"00", x"00", x"00", x"ff"); sdCMD24 <= (x"58", x"00", x"00", x"00", x"00", x"ff"); abort <= '0'; bytecnt <= 0; dmaRD <= '0'; dmaWR <= '0'; memREQ <= '0'; spiOP <= spiNOP; timeout <= 499999; sdSTATE <= sdstateINIT; state <= stateRESET; elsif rising_edge(sys.clk) then dmaRD <= '0'; dmaWR <= '0'; spiOP <= spiNOP; if sdOP = sdopABORT and state /= stateIDLE then abort <= '1'; end if; case state is -- -- stateRESET: -- when stateRESET => timeout <= timeout - 1; bytecnt <= 0; state <= stateINIT00; -- -- stateINIT00 -- Send 8x8 clocks cycles -- when stateINIT00 => timeout <= timeout - 1; if spiDONE = '1' or bytecnt = 0 then if bytecnt = nCR then bytecnt <= 0; spiOP <= spiCSL; state <= stateINIT01; else spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= bytecnt + 1; end if; end if; -- -- stateINIT01: -- Send GO_IDLE_STATE command (CMD0) -- when stateINIT01 => timeout <= timeout - 1; if spiDONE = '1' or bytecnt = 0 then if bytecnt = 6 then bytecnt <= 0; state <= stateINIT02; else spiOP <= spiTR; spiTXD <= sdCMD0(bytecnt); bytecnt <= bytecnt + 1; end if; end if; -- -- stateINIT02: -- Read R1 Response from CMD0 -- Response should be x"01" -- when stateINIT02 => timeout <= timeout - 1; if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; else if spiDONE = '1' then if spiRXD = x"ff" then if bytecnt = nCR then spiOP <= spiCSH; bytecnt <= 0; state <= stateRESET; else spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= bytecnt + 1; end if; else spiOP <= spiCSH; bytecnt <= 0; if spiRXD = x"01" then state <= stateINIT03; else state <= stateRESET; end if; end if; end if; end if; -- -- stateINIT03: -- Send 8 clock cycles -- when stateINIT03 => timeout <= timeout - 1; if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; elsif spiDONE = '1' then spiOP <= spiCSL; bytecnt <= 0; state <= stateINIT04; end if; -- -- stateINIT04: -- Send SEND_IF_COND (CMD8) -- when stateINIT04 => timeout <= timeout - 1; if spiDONE = '1' or bytecnt = 0 then if bytecnt = 6 then bytecnt <= 0; state <= stateINIT05; else spiOP <= spiTR; spiTXD <= sdCMD8(bytecnt); bytecnt <= bytecnt + 1; end if; end if; -- -- stateINIT05 -- Read first byte R1 of R7 Response -- Response should be x"01" for V2.00 initialization or -- x"05" for V1.00 initialization. -- when stateINIT05 => timeout <= timeout - 1; if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; else if spiDONE = '1' then if spiRXD = x"ff" then if bytecnt = nCR then spiOP <= spiCSH; bytecnt <= 0; err <= x"01"; state <= stateINFAIL; else spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= bytecnt + 1; end if; else bytecnt <= 0; if spiRXD = x"01" then state <= stateINIT06; elsif spiRXD <= x"05" then err <= x"02"; state <= stateINFAIL; else spiOP <= spiCSH; err <= x"03"; state <= stateINFAIL; end if; end if; end if; end if; -- -- stateINIT06 -- Read 32-bit Response to CMD8 -- Response should be x"00_00_01_aa" -- x"01" - Voltage -- x"55" - Pattern -- when stateINIT06 => timeout <= timeout - 1; case bytecnt is when 0 => spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; when 1 => if spiDONE = '1' then if spiRXD = x"00" then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 2; else err <= x"04"; state <= stateINFAIL; end if; end if; when 2 => if spiDONE = '1' then if spiRXD = x"00" then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 3; else err <= x"05"; state <= stateINFAIL; end if; end if; when 3 => if spiDONE = '1' then if spiRXD = x"01" then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 4; else err <= x"06"; state <= stateINFAIL; end if; end if; when 4 => if spiDONE = '1' then if spiRXD = x"aa" then spiOP <= spiCSH; bytecnt <= 0; state <= stateINIT07; else err <= x"07"; state <= stateINFAIL; end if; end if; when others => null; end case; -- -- stateINIT07: -- Send 8 clock cycles -- when stateINIT07 => timeout <= timeout - 1; if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; elsif spiDONE = '1' then spiOP <= spiCSL; bytecnt <= 0; state <= stateINIT08; end if; -- -- stateINIT08: -- Send APP_CMD (CMD55) -- when stateINIT08 => timeout <= timeout - 1; if spiDONE = '1' or bytecnt = 0 then if bytecnt = 6 then bytecnt <= 0; state <= stateINIT09; else spiOP <= spiTR; spiTXD <= sdCMD55(bytecnt); bytecnt <= bytecnt + 1; end if; end if; -- -- stateINIT09: -- Read R1 response from CMD55. -- Response should be x"01" -- when stateINIT09 => timeout <= timeout - 1; if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; else if spiDONE = '1' then if spiRXD = x"ff" then if bytecnt = nCR then spiOP <= spiCSH; bytecnt <= 0; err <= x"08"; state <= stateINFAIL; else spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= bytecnt + 1; end if; else spiOP <= spiCSH; bytecnt <= 0; if spiRXD = x"01" then state <= stateINIT10; else state <= stateINIT07; end if; end if; end if; end if; -- -- stateINIT10: -- Send 8 clock cycles -- when stateINIT10 => timeout <= timeout - 1; if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; elsif spiDONE = '1' then spiOP <= spiCSL; bytecnt <= 0; state <= stateINIT11; end if; -- -- stateINIT11: -- Send SD_SEND_OP_COND (ACMD41) -- when stateINIT11 => timeout <= timeout - 1; if spiDONE = '1' or bytecnt = 0 then if bytecnt = 6 then bytecnt <= 0; state <= stateINIT12; else spiOP <= spiTR; spiTXD <= sdACMD41(bytecnt); bytecnt <= bytecnt + 1; end if; end if; -- -- stateINIT12: -- Read R1 response from ACMD41. -- Response should be x"00" -- when stateINIT12 => timeout <= timeout - 1; if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; else if spiDONE = '1' then if spiRXD = x"ff" then if bytecnt = nCR then spiOP <= spiCSH; bytecnt <= 0; err <= x"09"; state <= stateINFAIL; else spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= bytecnt + 1; end if; else spiOP <= spiCSH; bytecnt <= 0; if spiRXD = x"00" then state <= stateINIT13; else state <= stateINIT07; end if; end if; end if; end if; -- -- stateINIT13 -- Send 8 clock cycles -- when stateINIT13 => timeout <= timeout - 1; if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; elsif spiDONE = '1' then spiOP <= spiCSL; bytecnt <= 0; state <= stateINIT14; end if; -- -- stateINIT14: -- Send READ_OCR (CMD58) -- when stateINIT14 => timeout <= timeout - 1; if spiDONE = '1' or bytecnt = 0 then if bytecnt = 6 then bytecnt <= 0; state <= stateINIT15; else spiOP <= spiTR; spiTXD <= sdCMD58(bytecnt); bytecnt <= bytecnt + 1; end if; end if; -- -- stateINIT15 -- Read first byte of R3 response to CMD58 -- Response should be x"00" -- when stateINIT15 => timeout <= timeout - 1; if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; else if spiDONE = '1' then if spiRXD = x"ff" then if bytecnt = nCR then spiOP <= spiCSH; bytecnt <= 0; err <= x"0a"; state <= stateINFAIL; else spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= bytecnt + 1; end if; else bytecnt <= 0; if spiRXD = x"00" then state <= stateINIT16; else spiOP <= spiCSH; err <= x"0b"; state <= stateINFAIL; end if; end if; end if; end if; -- -- stateINIT16 -- Response should be "e0_ff_80_00" -- Read 32-bit OCR response to CMD58 -- when stateINIT16 => timeout <= timeout - 1; case bytecnt is when 0 => spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; when 1 => if spiDONE = '1' then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 2; end if; when 2 => if spiDONE = '1' then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 3; end if; when 3 => if spiDONE = '1' then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 4; end if; when 4 => if spiDONE = '1' then spiOP <= spiCSH; bytecnt <= 0; state <= stateINIT17; end if; when others => null; end case; -- -- stateINIT17: -- Send 8 clock cycles -- when stateINIT17 => timeout <= timeout - 1; if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; elsif spiDONE = '1' then bytecnt <= 0; -- spiOP <= spiFAST; state <= stateIDLE; end if; -- -- stateIDLE: -- Wait for a command to process. -- Once the SD card is initialized, it waits in this state -- for either a read (sdopRD) or a write (sdopWR) command. -- when stateIDLE => abort <= '0'; sdSTATE <= sdstateREADY; case sdOP is when sdopNOP => state <= stateIDLE; when sdopRD => rdCNT <= std_logic_vector(unsigned(rdCNT) + 1); state <= stateREAD00; when sdopWR => wrCNT <= std_logic_vector(unsigned(wrCNT) + 1); state <= stateWRITE00; when others => state <= stateIDLE; end case; -- -- stateREAD00: -- Setup Read Single Block (CMD17) -- when stateREAD00 => sdSTATE <= sdstateREAD; memADDR <= sdMEMaddr; sdCMD17(0) <= x"51"; sdCMD17(1) <= sdDISKaddr( 0 to 7); sdCMD17(2) <= sdDISKaddr( 8 to 15); sdCMD17(3) <= sdDISKaddr(16 to 23); sdCMD17(4) <= sdDISKaddr(24 to 31); sdCMD17(5) <= x"ff"; bytecnt <= 0; spiOP <= spiCSL; state <= stateREAD01; -- -- stateREAD01: -- Send Read Single Block (CMD17) -- when stateREAD01 => if spiDONE = '1' or bytecnt = 0 then if bytecnt = 6 then bytecnt <= 0; state <= stateREAD02; else spiOP <= spiTR; spiTXD <= sdCMD17(bytecnt); bytecnt <= bytecnt + 1; end if; end if; -- -- stateREAD02: -- Read R1 response from CMD17 -- Response should be x"00" -- when stateREAD02 => if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; else if spiDONE = '1' then if spiRXD = x"ff" then if bytecnt = nCR then spiOP <= spiCSH; bytecnt <= 0; err <= x"0c"; state <= stateRWFAIL; else spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= bytecnt + 1; end if; else bytecnt <= 0; if spiRXD = x"00" then state <= stateREAD03; else spiOP <= spiCSH; err <= x"0d"; state <= stateRWFAIL; end if; end if; end if; end if; -- -- stateREAD03: -- Find 'Read Start token' which should be x"fe" -- when stateREAD03 => if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; else if spiDONE = '1' then if spiRXD = x"ff" then if bytecnt = nAC then spiOP <= spiCSH; bytecnt <= 0; err <= x"0e"; state <= stateRWFAIL; else spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= bytecnt + 1; end if; else bytecnt <= 0; if spiRXD = x"fe" then state <= stateREAD04; else spiOP <= spiCSH; err <= x"0f"; val <= spiRXD; state <= stateRWFAIL; end if; end if; end if; end if; -- -- stateREAD04: -- Acquire DMA. Setup for loop. -- when stateREAD04 => memREQ <= '1'; if dmaGNT = '1' then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 0; state <= stateREAD05; end if; -- -- stateREAD05: -- Read LSBYTE of data from disk (even addresses) -- Loop destination -- when stateREAD05 => if spiDONE = '1' then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= bytecnt + 1; dmaDOUT(4 to 11) <= spiRXD(0 to 7); state <= stateREAD06; end if; -- -- stateREAD06: -- Read MSBYTE of data from disk (odd addresses). -- Discard the top four bits forming a 12-bit word -- from the two bytes. -- when stateREAD06 => if spiDONE = '1' then spiOP <= spiTR; spiTXD <= x"ff"; dmaDOUT(0 to 3) <= spiRXD(4 to 7); state <= stateREAD07; end if; -- -- stateREAD07: -- Write disk data to memory. -- If memREQ is not asserted, we are reading the second -- 128 words of a 128 word read. Notice no DMA occurs -- to memory and the bits are dropped. -- when stateREAD07 => if memREQ = '1' then dmaWR <= '1'; end if; state <= stateREAD08; -- -- stateREAD08: -- This state checks the loop conditions: -- 1. An abort command causes the loop to terminate immediately. -- 2. If sdLEN is asserted (128 word read) at byte 255, then -- the memory write DMA request is dropped. The DMA address -- stops incrementing. The state machine continues to read -- all 256 words (512 bytes). -- 3. At word 256 (byte 512), the loop terminates. -- when stateREAD08 => if abort = '1' then memREQ <= '0'; spiOP <= spiCSH; bytecnt <= 0; state <= stateFINI; elsif bytecnt = 511 then memREQ <= '0'; memADDR <= std_logic_vector(unsigned(memADDR) + 1); bytecnt <= 0; state <= stateREAD09; elsif bytecnt >= 255 and sdLEN = '1' then memREQ <= '0'; bytecnt <= bytecnt + 1; state <= stateREAD05; else memADDR <= std_logic_vector(unsigned(memADDR) + 1); bytecnt <= bytecnt + 1; state <= stateREAD05; end if; -- -- stateREAD09: -- Read 2 bytes of CRC which is required for the SD Card. -- when stateREAD09 => if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; else if spiDONE = '1' then if bytecnt = 1 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 2; elsif bytecnt = 2 then spiOP <= spiCSH; bytecnt <= 0; state <= stateFINI; end if; end if; end if; -- -- stateWRITE00: -- Setup Write Single Block (CMD24) -- when stateWRITE00 => sdSTATE <= sdstateWRITE; memADDR <= sdMEMaddr; sdCMD24(0) <= x"58"; sdCMD24(1) <= sdDISKaddr( 0 to 7); sdCMD24(2) <= sdDISKaddr( 8 to 15); sdCMD24(3) <= sdDISKaddr(16 to 23); sdCMD24(4) <= sdDISKaddr(24 to 31); sdCMD24(5) <= x"ff"; bytecnt <= 0; spiOP <= spiCSL; state <= stateWRITE01; -- -- stateWRITE01: -- Send Write Single Block (CMD24) -- when stateWRITE01 => if spiDONE = '1' or bytecnt = 0 then if bytecnt = 6 then bytecnt <= 0; state <= stateWRITE02; else spiOP <= spiTR; spiTXD <= sdCMD24(bytecnt); bytecnt <= bytecnt + 1; end if; end if; -- -- stateWRITE02: -- Read R1 response from CMD24 -- Response should be x"00" -- when stateWRITE02 => if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; else if spiDONE = '1' then if spiRXD = x"ff" then if bytecnt = nCR then spiOP <= spiCSH; bytecnt <= 0; err <= x"10"; state <= stateRWFAIL; else spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= bytecnt + 1; end if; else bytecnt <= 0; if spiRXD = x"00" then state <= stateWRITE03; else spiOP <= spiCSH; val <= spiRXD; err <= x"11"; state <= stateRWFAIL; end if; end if; end if; end if; -- -- stateWRITE03: -- Send 8 clock cycles -- when stateWRITE03 => if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; elsif spiDONE = '1' then bytecnt <= 0; state <= stateWRITE04; end if; -- -- stateWRITE04: -- Send "Write Start Token". The write start token is x"fe" -- when stateWRITE04 => if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"fe"; bytecnt <= 1; elsif spiDONE = '1' then bytecnt <= 0; state <= stateWRITE05; end if; -- -- stateWRITE05: -- Start a DMA Read Address Cycle -- when stateWRITE05 => memREQ <= '1'; if dmaGNT = '1' then state <= stateWRITE06; end if; -- -- stateWRITE06: -- Loop destination -- This is the data phase of the read cycle. -- If memREQ is not asserted, we are writing the second -- 128 words of a 128 word write. Notice no DMA occurs. -- when stateWRITE06 => if memREQ = '1' then dmaRD <= '1'; end if; state <= stateWRITE07; -- -- stateWRITE07: -- Write LSBYTE of data to disk (even addresses) -- This state has two modes: -- If memREQ is asserted we are operating normally. -- If memREQ is negated we are writing the last 128 -- words of a 128 word operation. Therefore we -- write zeros. See file header. -- when stateWRITE07 => spiOP <= spiTR; if memREQ = '1' then memBUF <= dmaDIN(0 to 3); spiTXD <= dmaDIN(4 to 11); else memBUF <= b"0000"; spiTXD <= b"0000_0000"; end if; state <= stateWRITE08; -- -- stateWRITE08: -- Write MSBYTE of data to disk (odd addresses) -- Note: The top 4 bits of the MSBYTE are zero. -- when stateWRITE08 => if spiDONE = '1' then spiOP <= spiTR; spiTXD <= b"0000" & memBUF; bytecnt <= bytecnt + 1; state <= stateWRITE09; end if; -- -- stateWRITE09: -- This is the addr phase of the read cycle. -- when stateWRITE09 => if spiDONE = '1' then if abort = '1' then memREQ <= '0'; spiOP <= spiCSH; bytecnt <= 0; state <= stateFINI; elsif bytecnt = 511 then memREQ <= '0'; spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 0; memADDR <= std_logic_vector(unsigned(memADDR) + 1); state <= stateWRITE10; elsif (bytecnt = 255 and sdLEN = '1') then memREQ <= '0'; spiOP <= spiCSH; bytecnt <= bytecnt + 1; state <= stateWRITE06; else bytecnt <= bytecnt + 1; memADDR <= std_logic_vector(unsigned(memADDR) + 1); state <= stateWRITE06; end if; end if; -- -- stateWRITE10: -- Write CRC bytes -- when stateWRITE10 => if spiDONE = '1' then if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; else spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 0; state <= stateWRITE11; end if; end if; -- -- stateWRITE11: -- Read Data Response. The response is is one byte long -- and has the following format: -- -- xxx0sss1 -- -- Where x is don't-care and sss is a 3-bit status field. -- 010 is accepted, -- 101 is rejected due to CRC error and -- 110 is rejected due to write error. -- when stateWRITE11 => if spiDONE = '1' then if spiRXD(3 to 7) = b"0_010_1" then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 0; state <= stateWRITE12; else spiOP <= spiCSH; val <= spiRXD; err <= x"12"; bytecnt <= 0; state <= stateRWFAIL; end if; end if; -- -- stateWRITE12: -- Wait for busy token to clear. The disk reports -- all zeros while the write is occurring. -- when stateWRITE12 => if spiDONE = '1' then if spiRXD = x"00" then if bytecnt = 65535 then spiOP <= spiCSH; bytecnt <= 0; err <= x"13"; state <= stateRWFAIL; else spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= bytecnt + 1; end if; else bytecnt <= 0; state <= stateWRITE13; end if; end if; -- -- stateWRITE13: -- Send "Send Status" Command (CMD13) -- when stateWRITE13 => if spiDONE = '1' or bytecnt = 0 then if bytecnt = 6 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 0; state <= stateWRITE14; else spiOP <= spiTR; spiTXD <= sdCMD13(bytecnt); bytecnt <= bytecnt + 1; end if; end if; -- -- stateWRITE14: -- Check first byte of CMD13 response -- Status: -- Bit 0: Zero -- Bit 1: Parameter Error -- Bit 2: Address Error -- Bit 3: Erase Sequence Error -- Bit 4: COM CRC Error -- Bit 5: Illegal Command -- Bit 6: Erase Reset -- Bit 7: Idle State -- when stateWRITE14 => if spiDONE = '1' then if spiRXD = x"ff" then if bytecnt = nCR then spiOP <= spiCSH; bytecnt <= 0; err <= x"14"; state <= stateRWFAIL; else spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= bytecnt + 1; end if; else if spiRXD = x"00" or spiRXD = x"01" then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 0; state <= stateWRITE15; else spiOP <= spiCSH; bytecnt <= 0; val <= spiRXD; err <= x"15"; state <= stateRWFAIL; end if; end if; end if; -- -- stateWRITE15: -- Check second byte of CMD13 response -- Status: -- Bit 0: Out of range -- Bit 1: Erase Param -- Bit 2: WP Violation -- Bit 3: ECC Error -- Bit 4: CC Error -- Bit 5: Error -- Bit 6: WP Erase Skip -- Bit 7: Card is locked -- when stateWRITE15 => if spiDONE = '1' then if spiRXD = x"00" then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; state <= stateWRITE16; else spiOP <= spiCSH; bytecnt <= 0; val <= spiRXD; err <= x"16"; state <= stateRWFAIL; end if; end if; -- -- stateWRITE16: -- Send 8 clock cycles. Pull CS High. -- when stateWRITE16 => if spiDONE = '1' then spiOP <= spiCSH; bytecnt <= 0; state <= stateFINI; end if; -- -- stateFINI: -- Send 8 clock cycles -- when stateFINI => if bytecnt = 0 then spiOP <= spiTR; spiTXD <= x"ff"; bytecnt <= 1; elsif spiDONE = '1' then bytecnt <= 0; state <= stateDONE; end if; -- -- stateDONE: -- when stateDONE => sdSTATE <= sdstateDONE; state <= stateIDLE; -- -- stateINFAIL: -- Initialization failed somehow. -- when stateINFAIL => sdSTATE <= sdstateINFAIL; state <= stateINFAIL; -- -- stateRWFAIL: -- Read or Write failed somehow. -- when stateRWFAIL => sdSTATE <= sdstateRWFAIL; state <= stateRWFAIL; end case; if timeout = 0 then state <= stateINFAIL; end if; end if; end process SD_STATE; -- --! SDSPI Instance -- iSDSPI : entity work.eSDSPI (rtl) port map ( sys => sys, spiOP => spiOP, spiTXD => spiTXD, spiRXD => spiRXD, spiMISO => sdMISO, spiMOSI => sdMOSI, spiSCLK => sdSCLK, spiCS => sdCS, spiDONE => spiDONE ); with state select sdSTAT.debug <= -- Initialization b"0000_0000" when stateINIT00, b"0000_0001" when stateINIT01, b"0000_0010" when stateINIT02, b"0000_0011" when stateINIT03, b"0000_0100" when stateINIT04, b"0000_0101" when stateINIT05, b"0000_0110" when stateINIT06, b"0000_0111" when stateINIT07, b"0000_1000" when stateINIT08, b"0000_1001" when stateINIT09, b"0000_1010" when stateINIT10, b"0000_1011" when stateINIT11, b"0000_1100" when stateINIT12, b"0000_1101" when stateINIT13, b"0000_1110" when stateINIT14, b"0000_1111" when stateINIT15, b"0001_0000" when stateINIT16, b"0001_0001" when stateINIT17, -- Read states b"0010_0000" when stateREAD00, b"0010_0001" when stateREAD01, b"0010_0010" when stateREAD02, b"0010_0011" when stateREAD03, b"0010_0100" when stateREAD04, b"0010_0101" when stateREAD05, b"0010_0110" when stateREAD06, b"0010_0110" when stateREAD07, b"0010_0110" when stateREAD08, b"0010_0110" when stateREAD09, -- Write states b"0011_0000" when stateWRITE00, b"0011_0001" when stateWRITE01, b"0011_0010" when stateWRITE02, b"0011_0011" when stateWRITE03, b"0011_0100" when stateWRITE04, b"0011_0101" when stateWRITE05, b"0011_0110" when stateWRITE06, b"0011_0111" when stateWRITE07, b"0011_1000" when stateWRITE08, b"0011_1001" when stateWRITE09, b"0011_1010" when stateWRITE10, b"0011_1010" when stateWRITE11, b"0011_1010" when stateWRITE12, b"0011_1010" when stateWRITE13, b"0011_1010" when stateWRITE14, b"0011_1010" when stateWRITE15, b"0011_1010" when stateWRITE16, -- Other states b"1111_0000" when stateRESET, b"1111_0001" when stateIDLE, b"1111_0010" when stateINFAIL, b"1111_0011" when stateRWFAIL, b"1111_0100" when others; dmaADDR <= memADDR; dmaREQ <= memREQ; sdSTAT.err <= err; sdSTAT.val <= val; sdSTAT.rdCNT <= rdCNT; sdSTAT.wrCNT <= wrCNT; sdSTAT.state <= sdSTATE; end rtl;