use std.textio.all; ARCHITECTURE behav OF flash_28F128J3A IS -- controls signal chipSelect : std_ulogic; signal writePulse : std_ulogic; signal writePulseDelayed : std_ulogic; signal memoryCommand : unsigned(7 downto 0); signal wordProgramBusy : std_ulogic := '0'; signal blockEraseBusy : std_ulogic := '0'; signal busy : std_ulogic; signal readPulseCs : std_ulogic := '0'; signal readPulseOe : std_ulogic := '0'; signal readPulse : std_ulogic; signal memoryAddressDebug : unsigned(A'range); type state_type is ( READ_ARRAY, READ_ID_CODES, READ_QUERY, READ_STATUS, WRITE_BUFFER, WORD_PROGRAM_1, WORD_PROGRAM_2, BLOCK_ERASE_1, BLOCK_ERASE_2, CONFIG, PROG_LOCK_BITS, PROG_PROT, BOTCH_LOCK,-- BOTCH_LOCK_ERS_SUSP,-- LOCK_DONE, PROG_LOCK_BITS_ERS_SUSP,-- LOCK_DONE_ERS_SUSP, PROT_PROG_BUSY,-- PROT_PROG_DONE,-- WORD_PROGRAM_1_ERS_SUSP,-- PROG_BUSY,-- PROG_BUSY_ERS_SUSP,-- READ_STATUS_PROG_SUSP,-- READ_ARRAY_PROG_SUSP,-- READ_CONFIG_PROG_SUSP,-- READ_QUERY_PROG_SUSP,-- PROGRAM_DONE,-- PROGRAM_DONE_ERS_SUSP,-- BOTCH_ERS,-- ERASE_BUSY,-- READ_STATUS_ERS_SUSP,-- READ_ARRAY_ERS_SUSP,-- READ_CONFIG_ERS_SUSP,-- READ_QUERY_ERS_SUSP,-- ERASE_DONE-- ); signal currentState : state_type; signal nextState : state_type; -- storage constant blockLength : positive:= 16#10000#; -- 64 Kword blocks constant memoryLength: positive := 2**(A'length-1); -- constant memoryLength : positive := 2*blockLength; subtype memoryWord is std_ulogic_vector(DQ'range); type memoryArray is array(0 to memoryLength-1) of memoryWord; signal memoryDataWord : memoryWord; BEGIN --############################################################################ -- Controls ------------------------------------------------------------------------------ chipSelect <= ( (not CE(2)) and (not CE(1)) and (not CE(0)) ) or ( CE(2) and ( (not CE(1)) or (not CE(0)) ) ); writePulse <= chipSelect and not(WE_n); writePulseDelayed <= writePulse after 1 ns; memoryCommand <= unsigned(DQ(memoryCommand'range)); process(chipSelect) begin if rising_edge(chipSelect) then readPulseCs <= '1' after T_R3; elsif falling_edge(chipSelect) then readPulseCs <= '0' after T_R8; end if; end process; process(OE_n) begin if falling_edge(OE_n) then readPulseOe <= '1' after T_R7; elsif rising_edge(OE_n) then readPulseOe <= '0' after T_R9; end if; end process; readPulse <= readPulseCs and readPulseOe; ------------------------------------------------------------------------------ -- Programming delays ------------------------------------------------------------------------------ wordProgramBusy <= '1', '0' after T_W16_program when currentState = WORD_PROGRAM_2; blockEraseBusy <= '1', '0' after T_W16_erase when currentState = BLOCK_ERASE_2; busy <= wordProgramBusy or blockEraseBusy; ------------------------------------------------------------------------------ -- FSM: find next state ------------------------------------------------------------------------------ -- Table 4 p. 12 process(writePulse, busy) begin case currentState is when READ_ARRAY | READ_ID_CODES | READ_QUERY | READ_STATUS => case to_integer(memoryCommand) is when 16#FF# => nextState <= READ_ARRAY; when 16#90# => nextState <= READ_ID_CODES; when 16#98# => nextState <= READ_QUERY; when 16#70# => nextState <= READ_STATUS; when 16#E8# => nextState <= WRITE_BUFFER; when 16#10# | 16#40# => nextState <= WORD_PROGRAM_1; when 16#20# => nextState <= BLOCK_ERASE_1; when 16#B8# => nextState <= CONFIG; when 16#60# => nextState <= PROG_LOCK_BITS; when 16#C0# => nextState <= PROG_PROT; when others => nextState <= READ_ARRAY; end case; when WORD_PROGRAM_1 => nextState <= WORD_PROGRAM_2; when WORD_PROGRAM_2 => nextState <= READ_ARRAY; when BLOCK_ERASE_1 => if to_integer(memoryCommand) = 16#D0# then nextState <= BLOCK_ERASE_2; else nextState <= READ_ARRAY; end if; when BLOCK_ERASE_2 => nextState <= READ_ARRAY; -- WHEN PROG_LOCK_BITS => -- IF rising_edge(WENeg) THEN -- -- SECOND CYCLE CHECK -- IF data=16#D0# OR data=16#01# OR data=16#2F# THEN -- nextState<=READ_ARRAY; -- ELSE -- nextState <= BOTCH_LOCK; -- END IF; -- END IF; -- -- WHEN PROG_LOCK_BITS_ERS_SUSP => -- IF rising_edge(WENeg) THEN -- IF data=16#D0# OR data=16#01# OR data=16#2F# THEN -- nextState<=READ_ARRAY_ERS_SUSP; -- ELSE -- nextState <= BOTCH_LOCK_ERS_SUSP; -- END IF; -- END IF; -- -- -- WHEN LOCK_DONE => -- IF rising_edge(WENeg) THEN -- CASE data IS -- WHEN 16#10# | 16#40# => nextState <= WORD_PROGRAM_1; -- WHEN 16#20# => nextState <= BLOCK_ERASE_1; -- WHEN 16#70# => nextState <= READ_STATUS; -- WHEN 16#90# => nextState <= READ_CONFIG; -- WHEN 16#98# => nextState <= READ_QUERY; -- WHEN 16#60# => nextState <= PROG_LOCK_BITS; -- WHEN 16#C0# => nextState <= PROG_PROT; -- WHEN OTHERS => nextState <= READ_ARRAY; -- END CASE; -- END IF; -- -- WHEN LOCK_DONE_ERS_SUSP => -- IF rising_edge(WENeg) THEN -- CASE data IS -- WHEN 16#10# | 16#40# => nextState <= WORD_PROGRAM_1_ERS_SUSP; -- WHEN 16#70# => nextState <= READ_STATUS_ERS_SUSP; -- WHEN 16#90# => nextState <= READ_CONFIG_ERS_SUSP; -- WHEN 16#98# => nextState <= READ_QUERY_ERS_SUSP; -- WHEN 16#60# => nextState <= PROG_LOCK_BITS_ERS_SUSP; -- WHEN 16#D0# => nextState <= ERASE_BUSY; -- WHEN OTHERS => nextState <= READ_ARRAY_ERS_SUSP; -- END CASE; -- END IF; -- -- WHEN BOTCH_LOCK => -- IF rising_edge(WENeg) THEN -- CASE data IS -- WHEN 16#10# | 16#40# => nextState <= WORD_PROGRAM_1; -- WHEN 16#20# => nextState <= BLOCK_ERASE_1; -- WHEN 16#70# => nextState <= READ_STATUS; -- WHEN 16#90# => nextState <= READ_CONFIG; -- WHEN 16#98# => nextState <= READ_QUERY; -- WHEN 16#60# => nextState <= PROG_LOCK_BITS; -- WHEN 16#C0# => nextState <= PROG_PROT; -- WHEN OTHERS => nextState <= READ_ARRAY; -- END CASE; -- END IF; -- -- WHEN BOTCH_LOCK_ERS_SUSP => -- IF rising_edge(WENeg) THEN -- CASE data IS -- WHEN 16#10# | 16#40# => -- nextState <= WORD_PROGRAM_1_ERS_SUSP; -- WHEN 16#70# => nextState <= READ_STATUS_ERS_SUSP; -- WHEN 16#90# => nextState <= READ_CONFIG_ERS_SUSP; -- WHEN 16#98# => nextState <= READ_QUERY_ERS_SUSP; -- WHEN 16#60# => nextState <= PROG_LOCK_BITS_ERS_SUSP; -- WHEN OTHERS => nextState <= READ_ARRAY_ERS_SUSP; -- END CASE; -- END IF; -- -- -- WHEN BOTCH_ERS => -- IF rising_edge(WENeg) THEN -- CASE data IS -- WHEN 16#10# | 16#40# => -- nextState <= WORD_PROGRAM_1; -- WHEN 16#20# => nextState <=BLOCK_ERASE_1; -- WHEN 16#70# => nextState <= READ_STATUS; -- WHEN 16#90# => nextState <= READ_CONFIG; -- WHEN 16#98# => nextState <= READ_QUERY; -- WHEN 16#60# => nextState <= PROG_LOCK_BITS; -- WHEN 16#C0# => nextState <= PROG_PROT; -- WHEN OTHERS => nextState <= READ_ARRAY; -- END CASE; -- END IF; -- -- -- WHEN PROG_PROT => -- IF rising_edge(WENeg) THEN -- nextState <= PROT_PROG_BUSY; -- END IF; -- -- WHEN PROT_PROG_BUSY => -- IF S_Reg(7)='1' THEN -- nextState <= PROT_PROG_DONE; -- ELSE -- nextState <= PROT_PROG_BUSY; -- END IF; -- -- WHEN PROT_PROG_DONE => -- IF rising_edge(WENeg) THEN -- CASE data IS -- WHEN 16#10# | 16#40# => nextState <= WORD_PROGRAM_1; -- WHEN 16#20# => nextState <= BLOCK_ERASE_1; -- WHEN 16#70# => nextState <= READ_STATUS; -- WHEN 16#90# => nextState <= READ_CONFIG; -- WHEN 16#98# => nextState <= READ_QUERY; -- WHEN 16#60# => nextState <= PROG_LOCK_BITS; -- WHEN 16#C0# => nextState <= PROG_PROT; -- WHEN OTHERS => nextState <= READ_ARRAY; -- END CASE; -- END IF; -- -- WHEN WORD_PROGRAM_1 => -- IF rising_edge(WENeg) THEN -- nextState <= PROG_BUSY; -- END IF; -- -- WHEN WORD_PROGRAM_1_ERS_SUSP => -- IF rising_edge(WENeg) THEN -- nextState <= PROG_BUSY_ERS_SUSP; -- END IF; -- -- WHEN PROG_BUSY => -- IF WDone THEN -- nextState<=PROGRAM_DONE; -- ELSIF rising_edge(WENeg) THEN -- IF data= 16#B0# THEN -- nextState <= READ_STATUS_PROG_SUSP; -- ELSE -- nextState <= PROG_BUSY; -- END IF; -- END IF; -- -- WHEN PROG_BUSY_ERS_SUSP => -- IF WDone THEN -- nextState<=PROGRAM_DONE_ERS_SUSP; -- ELSIF rising_edge(WENeg) THEN -- nextState <= PROG_BUSY_ERS_SUSP; -- END IF; -- -- WHEN READ_STATUS_PROG_SUSP | READ_ARRAY_PROG_SUSP | -- READ_CONFIG_PROG_SUSP | READ_QUERY_PROG_SUSP => -- IF rising_edge(WENeg) THEN -- CASE data IS -- --WHEN 16#D0# => nextState <= READ_ARRAY_PROG_SUSP; -- WHEN 16#D0# => nextState <= PROG_BUSY; -- WHEN 16#B0# | 16#70# => nextState <= READ_STATUS_PROG_SUSP; -- WHEN 16#90# => nextState <= READ_CONFIG_PROG_SUSP; -- WHEN 16#98# => nextState <= READ_QUERY_PROG_SUSP; -- WHEN OTHERS => nextState <= READ_ARRAY_PROG_SUSP; -- END CASE; -- END IF; -- -- WHEN PROGRAM_DONE => -- IF rising_edge(WENeg) THEN -- CASE data IS -- WHEN 16#10# | 16#40# => nextState <= WORD_PROGRAM_1; -- WHEN 16#20# => nextState <= BLOCK_ERASE_1; -- WHEN 16#70# => nextState <= READ_STATUS; -- WHEN 16#90# => nextState <= READ_CONFIG; -- WHEN 16#98# => nextState <= READ_QUERY; -- WHEN 16#60# => nextState <= PROG_LOCK_BITS; -- WHEN 16#C0# => nextState <= PROG_PROT; -- WHEN OTHERS => nextState <= READ_ARRAY; -- END CASE; -- END IF; -- -- WHEN PROGRAM_DONE_ERS_SUSP => -- IF rising_edge(WENeg) THEN -- CASE data IS -- WHEN 16#10# | 16#40# => nextState <= WORD_PROGRAM_1_ERS_SUSP; -- WHEN 16#B0# | 16#70# => nextState <= READ_STATUS_ERS_SUSP; -- WHEN 16#D0# => nextState <= ERASE_BUSY; -- WHEN 16#90# => nextState <= READ_CONFIG_ERS_SUSP; -- WHEN 16#98# => nextState <= READ_QUERY_ERS_SUSP; -- WHEN 16#60# => nextState <= PROG_LOCK_BITS_ERS_SUSP; -- WHEN OTHERS => nextState <= READ_ARRAY_ERS_SUSP; -- END CASE; -- END IF; -- -- -- WHEN ERASE_BUSY => -- IF rising_edge(WENeg) AND data= 16#B0# THEN -- nextState <= READ_STATUS_ERS_SUSP; -- ELSIF EDone AND ECount=31 THEN -- nextState<=ERASE_DONE; -- ELSE -- nextState <= ERASE_BUSY; -- END IF; -- -- WHEN READ_STATUS_ERS_SUSP | READ_ARRAY_ERS_SUSP | -- READ_CONFIG_ERS_SUSP | READ_QUERY_ERS_SUSP => -- IF rising_edge(WENeg) THEN -- CASE data IS -- WHEN 16#10# | 16#40# => nextState <=WORD_PROGRAM_1_ERS_SUSP; -- WHEN 16#B0# | 16#70# | 16#80# => -- nextState<= READ_STATUS_ERS_SUSP; -- WHEN 16#D0# => nextState <= ERASE_BUSY; -- WHEN 16#90# => nextState <= READ_CONFIG_ERS_SUSP; -- WHEN 16#98# => nextState <= READ_QUERY_ERS_SUSP; -- WHEN 16#60# => nextState <= PROG_LOCK_BITS_ERS_SUSP; -- WHEN OTHERS => nextState <= READ_ARRAY_ERS_SUSP; -- END CASE; -- END IF; -- -- WHEN ERASE_DONE => -- IF rising_edge(WENeg) THEN -- CASE data IS -- WHEN 16#10# | 16#40# => nextState <= WORD_PROGRAM_1; -- WHEN 16#20# => nextState <= BLOCK_ERASE_1; -- WHEN 16#70# => nextState <= READ_STATUS; -- WHEN 16#90# => nextState <= READ_CONFIG; -- WHEN 16#98# => nextState <= READ_QUERY; -- WHEN 16#60# => nextState <= PROG_LOCK_BITS; -- WHEN 16#C0# => nextState <= PROG_PROT; -- WHEN OTHERS => nextState <= READ_ARRAY; -- END CASE; -- END IF; when others => nextState <= READ_ARRAY; end case; end process; ------------------------------------------------------------------------------ -- FSM: update state ------------------------------------------------------------------------------ process(RP_N, writePulseDelayed, busy) begin if RP_n = '0' then currentState <= READ_ARRAY; elsif falling_edge(writePulseDelayed) then currentState <= nextState; elsif falling_edge(busy) then currentState <= nextState; end if; end process; ------------------------------------------------------------------------------ -- STS ------------------------------------------------------------------------------ process begin STS <= '1'; wait on busy; if rising_edge(busy) then STS <= '0' after T_W13; wait until falling_edge(busy); end if; end process; --############################################################################ -- Storage ------------------------------------------------------------------------------ process(writePulse, A) variable memContent : memoryArray; -- much faster than using a signal variable loadMemFromFile : boolean := true; file memoryFile : text open read_mode is fileSpec; variable srecLine : line; variable srecChar : character; variable srecType : natural; variable srecAddrLength : natural; variable srecWordAscii : string(8 downto 1); variable srecLength : natural; variable srecAddress : natural; variable memoryAddress : natural; variable srecData : natural; function readNumber(hexString: string) return natural is variable currentCharPos: natural; variable intValue: natural; variable accValue: natural; begin accValue := 0; for index in hexString'range loop currentCharPos := character'pos(hexString(index)); if currentCharPos <= character'pos('9') then intValue := currentCharPos - character'pos('0'); else intValue := currentCharPos - character'pos('A') + 10; end if; accValue := accValue * 16 + intValue; end loop; return accValue; end readNumber; begin if loadMemFromFile then -- only happens at simulation start while not endfile(memoryFile) loop readline(memoryFile, srecLine); --report "-> " & srecLine.all; -- trim leading whitespaces while (not (srecLine'length=0)) and (srecLine(srecLine'left) = ' ') loop read(srecLine, srecChar); end loop; -- get record type if srecLine'length > 0 then read(srecLine, srecChar); if (srecChar = 'S') or (srecChar = 's') then read(srecLine, srecChar); srecType := character'pos(srecChar) - character'pos('0'); --report "-> srec type: " & integer'image(srecType); srecAddrLength := srecType + 1; if (srecType >= 1) and (srecType <= 3) then -- get record length srecWordAscii := (others => '0'); read(srecLine, srecWordAscii(2)); read(srecLine, srecWordAscii(1)); srecLength := readNumber(srecWordAscii); -- get record base address srecWordAscii := (others => '0'); for index in 2*(srecAddrLength) downto 1 loop read(srecLine, srecWordAscii(index)); end loop; srecAddress := readNumber(srecWordAscii); memoryAddress := srecAddress/2; -- get record data for index1 in 1 to (srecLength - srecAddrLength - 1) / 2 loop srecWordAscii := (others => '0'); for index2 in 4 downto 1 loop read(srecLine, srecWordAscii(index2)); end loop; srecData := readNumber(srecWordAscii); if memoryAddress < memoryLength then memContent(memoryAddress) := std_ulogic_vector(to_unsigned(srecData, memoryWord'length)); end if; memoryAddress := memoryAddress + 1; end loop; end if; end if; end if; end loop; loadMemFromFile := false; else -- normal functionality if falling_edge(writePulse) then -- program a word if currentState = WORD_PROGRAM_1 then memoryAddress := to_integer(A(A'high downto 1)); memoryAddressDebug <= to_unsigned(memoryAddress, memoryAddressDebug'length); memContent(memoryAddress) := std_ulogic_vector(DQ); -- erase a block elsif currentState = BLOCK_ERASE_1 then memoryAddress := to_integer(A and not(to_unsigned(blockLength-1, A'length))); for index in 0 to blockLength-1 loop if memoryAddress < memoryLength then memContent(memoryAddress) := (others => '1'); memoryAddress := memoryAddress + 1; end if; end loop; end if; end if; -- update readout data if A'event then memoryAddress := to_integer(A(A'high downto 1)); memoryAddressDebug <= to_unsigned(memoryAddress, memoryAddressDebug'length); memoryDataWord <= memContent(memoryAddress) after T_R2; end if; end if; end process; process(memoryDataWord, readPulse) begin if readPulse = '1' then DQ <= std_logic_vector(memoryDataWord); else DQ <= (others => 'Z'); end if; end process; END ARCHITECTURE behav;