begin
spiin <= cSPID;
dataout <= cOut;
-- !! We work with 10MHz clock
inst_clkdivider : clkdivider
PORT MAP
(
clkin => clk,
reset => reset,
clkout => clk10M
);
-- !! The update process, reset, new state, and so on.
update : process (clk10M, reset)
begin
if reset = '0' then
cState <= ST_IDLE;
cSPID <= "11011";
ciCount <= (others => '0');
cInstr <= (others => '0');
cOut <= (others => '0');
inCmd <= (others => '0');
elsif clk10M'event and clk10M = '1' then
cState <= nState;
cSPID <= nSPID;
ciCount <= niCount;
cInstr <= nInstr;
cOut <= nOut;
inCmd <= command;
end if;
end process update;
-- !! Main process for SPI-EEPROM communication
main_spi : process(cState, ciCount, inCmd, cOut, cSPID, cInstr, spiout)
begin
case cState is
-- wait for a valid command to proceed
when ST_IDLE =>
nSPID <= cSPID;
niCount <= "000000";
nInstr <= cInstr;
nOut <= cOut;
isIdle <= '1';
case inCmd is
when x"0" =>
nState <= ST_IDLE;
--isIdle <= '1';
when others =>
nState <= ST_DECODE;
--isIdle <= '0';
end case;
-- decode command in flash instruction
when ST_DECODE =>
nSPID <= cSPID;
niCount <= "000000";
case inCmd is
when x"1" =>
nInstr <= x"06"; -- WREN Write Enable
when x"2" =>
nInstr <= x"04"; -- WRDI Write Disable
when x"3" =>
nInstr <= x"9F"; -- RDID Read Identification
when x"4" =>
nInstr <= x"05"; -- RDSR Read Status Register
when x"5" =>
nInstr <= x"01"; -- WRSR Write Status Register
when x"6" =>
nInstr <= x"03"; -- READ Read Data Bytes
when x"7" =>
nInstr <= x"0B"; -- FAST_READ Read Data Bytes at High Speed
when x"8" =>
nInstr <= x"02"; -- PP Page Program
when x"9" =>
nInstr <= x"D8"; -- SE Sector Erase
when x"A" =>
nInstr <= x"C7"; -- BE Bulk Erase
when x"B" =>
nInstr <= x"B9"; -- DP Deep Power-Down
when x"C" =>
nInstr <= x"AB"; -- RES Release from Deep Power-Down
when others =>
nInstr <= x"00";
end case;
nOut <= cOut;
nState <= ST_CSEL;
isIdle <= '1';
-- Chip Select Active
when ST_CSEL =>
nSPID <= "11010"; -- put /S - Chip Select on 0 - active
niCount <= "000000";
nInstr <= cInstr;
nOut <= cOut;
isIdle <= '0';
nState <= ST_INSTR;
-- Put 8bits Instruction on SPI Data Input Line
-- !! On the rising edge of CLK
when ST_INSTR =>
if ciCount(0) = '0' then -- in one clock put data and put clock on low
nSPID <= "11" & cInstr(7-conv_integer(ciCount(5 downto 1))) & "00";
else -- in the other clock put clock on high to latch data
nSPID <= cSPID(4 downto 2) & "10";
end if;
nOut <= cOut;
isIdle <= '0';
nInstr <= cInstr;
if ciCount = 15 then
niCount <= (others => '0'); -- put it on zero
case cInstr is
-- Instructions (WREN, WRDI, BE, DP) with no address nor data
when x"06" | x"04" | x"C7" | x"B9" =>
nState <= ST_CDES;
-- Instruction RDSR - has to read 8bits from Q line
when x"05" =>
nState <= ST_READ;
-- !! TODO: !!
when x"9F" | x"01" =>
nState <= ST_CDES;
-- Instructions (READ, PP, SE, READ_FAST) that require ADDRESS
when x"03" | x"02" | x"D8" | x"0B"=>
nState <= ST_ADDR;
-- When Others -> error
when others =>
nState <= ST_CDES;
end case;
else
niCount <= ciCount + 1; -- increment
nState <= ST_INSTR;
end if;
-- Put 24bits Address on SPI Data Input Line
-- ! On the rising edge of CLK
when ST_ADDR =>
if ciCount(0) = '0' then -- in one clock put data and put clock on low
nSPID <= "11" & address(23-conv_integer(ciCount(5 downto 1))) & "00";
else -- in the other clock put clock on high to latch data
nSPID <= cSPID(4 downto 2) & "10";
end if;
nOut <= cOut;
isIdle <= '0';
nInstr <= cInstr;
if ciCount = 47 then
niCount <= (others => '0'); -- put it on zero
case cInstr is
-- Instructions (READ) that have to read data from Q line
when x"03" =>
nState <= ST_READ;
-- !! TODO: Instruction with (FAST_READ) Dummy bits
when x"0B" =>
nState <= ST_CDES;
-- Instructions (SE) that don't required anything else
when x"D8" =>
nState <= ST_CDES;
-- Instructions (PP) that have to write additional data on D line
when x"02" =>
nState <= ST_WRITE;
-- When others -> error
when others =>
nState <= ST_CDES;
end case;
else
nState <= ST_ADDR;
niCount <= ciCount + 1; -- increment
end if;
-- Read Data from Q line
-- ?? Old and false: !! Reading is done on the falling edge of CLK
-- 19.10.2010: Reading on rising edge. New data available after falling edge
when ST_READ =>
if ciCount(0) = '0' then -- put clock on low latch data from Q
nSPID <= cSPID(4 downto 3) & "000";
nOut <= cOut;
else -- in the other clock put clock on high
nSPID <= cSPID(4 downto 3) & "010";
nOut(7-conv_integer(ciCount(5 downto 1))) <= spiout;
end if;
isIdle <= '0';
nInstr <= cInstr;
-- read and store actual data
-- 19.10.2010: 15 instead of 14
if ciCount = 15 then
niCount <= (others => '0'); -- put it on zero
-- there is nothing else to do, go to Chip DeSelect
nState <= ST_CDES;
else
nState <= ST_READ;
niCount <= ciCount + 1; -- increment
end if;
-- Program/Write data on D line
-- !! Programming is done on the rising edge of CLK
when ST_WRITE =>
if ciCount(0) = '0' then -- put clock on low and update D line
nSPID <= cSPID(4 downto 3) & datain(7-conv_integer(ciCount(5 downto 1))) & "00";
else -- in the other clock put clock on high - latch on clock high
nSPID <= cSPID(4 downto 2) & "10";
end if;
nOut <= cOut;
isIdle <= '0';
nInstr <= cInstr;
-- ?? ha?? 19.10.2010 ?? it is 13 because the first falling edge comes from the previous
-- state (ST_ADDR, .. etc)
-- modified on 19.10.2010 - 15 instead of 13 ??
if ciCount = 15 then
niCount <= (others => '0'); -- put it on zero
-- there is nothing else to do, go to Chips DeSelect
nState <= ST_CDES;
else
nState <= ST_WRITE;
niCount <= ciCount + 1; -- increment
end if;
-- Chip Select Inactive
when ST_CDES =>
nSPID <= "11011"; -- put /S - Chip Select on 0 - active
niCount <= "000000";
nInstr <= cInstr;
nOut <= cOut;
isIdle <= '0';
nState <= ST_IDLE;
when others =>
nSPID <= cSPID;
niCount <= "000000";
nInstr <= cInstr;
nOut <= cOut;
isIdle <= '0';
nState <= ST_IDLE;
end case;
end process main_spi;