URL
https://opencores.org/ocsvn/mips_enhanced/mips_enhanced/trunk
Subversion Repositories mips_enhanced
[/] [mips_enhanced/] [trunk/] [grlib-gpl-1.0.19-b3188/] [lib/] [fmf/] [flash/] [m25p80.vhd] - Rev 2
Compare with Previous | Blame | View Log
-------------------------------------------------------------------------------- -- File Name: m25p80.vhd -------------------------------------------------------------------------------- -- Copyright (C) 2005 Free Model Foundry; http://www.FreeModelFoundry.com -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License version 2 as -- published by the Free Software Foundation. -- -- MODIFICATION HISTORY: -- -- version: | author: | mod date: | changes made: -- V1.0 G.Gojanovic 05 Jun 27 initial version -- -------------------------------------------------------------------------------- -- PART DESCRIPTION: -- -- Library: FLASH MEMORY -- Technology: CMOS -- Part: M25P80 -- -- Description: 8Mbit Serial Flash memory w/ 40MHz SPI Bus Interface -- -------------------------------------------------------------------------------- LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; USE STD.textio.ALL; USE IEEE.VITAL_timing.ALL; USE IEEE.VITAL_primitives.ALL; LIBRARY FMF; USE FMF.gen_utils.ALL; USE FMF.conversions.ALL; ------------------------------------------------------------------------------- -- ENTITY DECLARATION ------------------------------------------------------------------------------- ENTITY m25p80 IS GENERIC ( -- tipd delays: interconnect path delays tipd_C : VitalDelayType01 := VitalZeroDelay01; tipd_D : VitalDelayType01 := VitalZeroDelay01; tipd_SNeg : VitalDelayType01 := VitalZeroDelay01; tipd_HOLDNeg : VitalDelayType01 := VitalZeroDelay01; tipd_WNeg : VitalDelayType01 := VitalZeroDelay01; -- tpd delays tpd_C_Q : VitalDelayType01 := UnitDelay01;--tV tpd_SNeg_Q : VitalDelayType01Z := UnitDelay01Z;--tDIS tpd_HOLDNeg_Q : VitalDelayType01Z := UnitDelay01Z;--tLZ,tHZ --tsetup values tsetup_D_C : VitalDelayType := UnitDelay; --tDVCH / tsetup_SNeg_C : VitalDelayType := UnitDelay; --tSLCH / tsetup_HOLDNeg_C : VitalDelayType := UnitDelay; --tHHCH / tsetup_C_HOLDNeg : VitalDelayType := UnitDelay; --tHLCH \ tsetup_WNeg_SNeg : VitalDelayType := UnitDelay; --tWHSL \ --thold values thold_D_C : VitalDelayType := UnitDelay; --tCHDX / thold_SNeg_C : VitalDelayType := UnitDelay; --tCHSL / thold_HOLDNeg_C : VitalDelayType := UnitDelay; --tCHHL / thold_C_HOLDNeg : VitalDelayType := UnitDelay; --tCHHH \ thold_WNeg_SNeg : VitalDelayType := UnitDelay; --tWPH \ --tpw values: pulse width tpw_C_posedge : VitalDelayType := UnitDelay; --tCH tpw_C_negedge : VitalDelayType := UnitDelay; --tCL tpw_SNeg_posedge : VitalDelayType := UnitDelay; --tSHSL -- tperiod min (calculated as 1/max freq) tperiod_C_rd : VitalDelayType := UnitDelay; -- fC=20MHz tperiod_C_fast_rd : VitalDelayType := UnitDelay; -- fC=25/40MHz -- tdevice values: values for internal delays -- Page Program Operation tdevice_PP : VitalDelayType := 5 ms; --tPP --Sector Erase Operation tdevice_SE : VitalDelayType := 3 sec; --tSE --Bulk Erase Operation tdevice_BE : VitalDelayType := 20 sec; --tBE --Write Status Register Operation tdevice_WR : VitalDelayType := 15 ms; --tW --Deep Power Down tdevice_DP : VitalDelayType := 3 us; --tDP --Release from Deep Power Down ES not read tdevice_RES1 : VitalDelayType := 3 us; --tRES1 --Release from Deep Power Down ES read tdevice_RES2 : VitalDelayType := 1.8 us; --tRES2 --VCC (min) to S# Low tdevice_VSL : VitalDelayType := 10 us; --tVSL --Time delay to Write instruction tdevice_PUW : VitalDelayType := 10 ms; --tPUW -- generic control parameters InstancePath : STRING := DefaultInstancePath; TimingChecksOn : BOOLEAN := DefaultTimingChecks; MsgOn : BOOLEAN := DefaultMsgOn; XOn : BOOLEAN := DefaultXon; -- memory file to be loaded mem_file_name : STRING := "m25p80.mem"; UserPreload : BOOLEAN := FALSE; --TRUE; DebugInfo : BOOLEAN := FALSE; LongTimming : BOOLEAN := TRUE; -- For FMF SDF technology file usage TimingModel : STRING := DefaultTimingModel ); PORT ( C : IN std_ulogic := 'U'; --serial clock input D : IN std_ulogic := 'U'; --serial data input SNeg : IN std_ulogic := 'U'; -- chip select input HOLDNeg : IN std_ulogic := 'U'; -- hold input WNeg : IN std_ulogic := 'U'; -- write protect input Q : OUT std_ulogic := 'U' --serial data output ); ATTRIBUTE VITAL_LEVEL0 of m25p80 : ENTITY IS TRUE; END m25p80; ------------------------------------------------------------------------------- -- ARCHITECTURE DECLARATION ------------------------------------------------------------------------------- ARCHITECTURE vhdl_behavioral of m25p80 IS ATTRIBUTE VITAL_LEVEL0 OF vhdl_behavioral : ARCHITECTURE IS TRUE; CONSTANT PartID : STRING := "m25p80"; CONSTANT MaxData : NATURAL := 16#FF#; --255; CONSTANT SecSize : NATURAL := 16#FFFF#; --65535 CONSTANT SecNum : NATURAL := 15; CONSTANT HiAddrBit : NATURAL := 23; CONSTANT AddrRANGE : NATURAL := 16#FFFFF#; CONSTANT BYTE : NATURAL := 8; --Electronic Signature CONSTANT ES : NATURAL := 16#13#; -- interconnect path delay signals SIGNAL C_ipd : std_ulogic := 'U'; SIGNAL D_ipd : std_ulogic := 'U'; SIGNAL SNeg_ipd : std_ulogic := 'U'; SIGNAL HOLDNeg_ipd : std_ulogic := 'U'; SIGNAL WNeg_ipd : std_ulogic := 'U'; --- internal delays SIGNAL PP_in : std_ulogic := '0'; SIGNAL PP_out : std_ulogic := '0'; SIGNAL PUW_in : std_ulogic := '0'; SIGNAL PUW_out : std_ulogic := '0'; SIGNAL SE_in : std_ulogic := '0'; SIGNAL SE_out : std_ulogic := '0'; SIGNAL BE_in : std_ulogic := '0'; SIGNAL BE_out : std_ulogic := '0'; SIGNAL WR_in : std_ulogic := '0'; SIGNAL WR_out : std_ulogic := '0'; SIGNAL DP_in : std_ulogic := '0'; SIGNAL DP_out : std_ulogic := '0'; SIGNAL RES1_in : std_ulogic := '0'; SIGNAL RES1_out : std_ulogic := '0'; SIGNAL RES2_in : std_ulogic := '0'; SIGNAL RES2_out : std_ulogic := '0'; SIGNAL VSL_in : std_ulogic := '0'; SIGNAL VSL_out : std_ulogic := '0'; BEGIN --------------------------------------------------------------------------- -- Internal Delays --------------------------------------------------------------------------- -- Artificial VITAL primitives to incorporate internal delays PP :VitalBuf(PP_out, PP_in, (tdevice_PP ,UnitDelay)); PUW :VitalBuf(PUW_out, PUW_in, (tdevice_PUW ,UnitDelay)); SE :VitalBuf(SE_out, SE_in, (tdevice_SE ,UnitDelay)); BE :VitalBuf(BE_out, BE_in, (tdevice_BE ,UnitDelay)); WR :VitalBuf(WR_out, WR_in, (tdevice_WR ,UnitDelay)); DP :VitalBuf(DP_out, DP_in, (tdevice_DP ,UnitDelay)); RES1 :VitalBuf(RES1_out, RES1_in, (tdevice_RES1 ,UnitDelay)); RES2 :VitalBuf(RES2_out, RES2_in, (tdevice_RES2 ,UnitDelay)); VSL :VitalBuf(VSL_out, VSL_in, (tdevice_VSL ,UnitDelay)); --------------------------------------------------------------------------- -- Wire Delays --------------------------------------------------------------------------- WireDelay : BLOCK BEGIN w_1 : VitalWireDelay (C_ipd, C, tipd_C); w_2 : VitalWireDelay (D_ipd, D, tipd_D); w_3 : VitalWireDelay (SNeg_ipd, SNeg, tipd_SNeg); w_4 : VitalWireDelay (HOLDNeg_ipd, HOLDNeg, tipd_HOLDNeg); w_5 : VitalWireDelay (WNeg_ipd, WNeg, tipd_WNeg); END BLOCK; --------------------------------------------------------------------------- -- Main Behavior Block --------------------------------------------------------------------------- Behavior: BLOCK -- State Machine : State_Type TYPE state_type IS (IDLE, DP_DOWN, WRITE_SR, SECTOR_ER, BULK_ER, PAGE_PG ); -- Instruction Type TYPE instruction_type IS (NONE, WREN, WRDI, WRSR, RDSR, READ, FAST_READ, SE, BE, PP, DP, RES_READ_ES ); TYPE WByteType IS ARRAY (0 TO 255) OF INTEGER RANGE -1 TO MaxData; --Flash Memory Array TYPE MemArray IS ARRAY (0 TO AddrRANGE) OF INTEGER RANGE -1 TO MaxData; --------------------------------------------------------------------------- -- memory declaration --------------------------------------------------------------------------- SHARED VARIABLE Mem : MemArray := (OTHERS => MaxData); -- states SIGNAL current_state : state_type; -- SIGNAL next_state : state_type; -- SIGNAL WByte : WByteType := (others => 0); SIGNAL Instruct : instruction_type; --zero delay signal SIGNAL Q_zd : std_logic :='Z'; SIGNAL Q_temp : std_logic :='Z'; -- powerup parameters SIGNAL ChipSelectOk : std_logic := '0'; SIGNAL WriteOk : std_logic := '0'; SHARED VARIABLE Status_reg : std_logic_vector(7 downto 0) := (others => '0'); SIGNAL Status_reg_in : std_logic_vector(7 downto 0) := (others => '0'); ALIAS WIP :std_logic IS Status_reg(0); ALIAS WEL :std_logic IS Status_reg(1); ALIAS BP0 :std_logic IS Status_reg(2); ALIAS BP1 :std_logic IS Status_reg(3); ALIAS BP2 :std_logic IS Status_reg(4); ALIAS SRWD :std_logic IS Status_reg(7); --Command Register SIGNAL write : std_logic := '0'; SIGNAL read_out : std_logic := '0'; SIGNAL fast_rd : boolean := true; SIGNAL rd : boolean := false; SIGNAL es_read : boolean := false; SIGNAL change_addr : std_logic := '0'; --FSM control signals SIGNAL PDONE : std_logic := '1'; --Page Prog. Done SIGNAL PSTART : std_logic := '0'; --Start Page Programming SIGNAL WDONE : std_logic := '1'; --Write. Done SIGNAL WSTART : std_logic := '0'; --Start Write SIGNAL ESTART : std_logic := '0'; --Start Erase SIGNAL EDONE : std_logic := '1'; --Erase Done SIGNAL RES_in : std_logic := '0'; --RES1_in OR RES2_in SIGNAL SA : NATURAL RANGE 0 TO SecNum := 0; SIGNAL Byte_number : NATURAL RANGE 0 TO 255 := 0; SHARED VARIABLE Sec_Prot : std_logic_vector(SecNum downto 0) := (OTHERS => '0'); SIGNAL Address : NATURAL RANGE 0 TO AddrRANGE := 0; -- timing check violation SIGNAL Viol : X01 := '0'; PROCEDURE ADDRHILO_SEC( VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; VARIABLE Addr : NATURAL) IS VARIABLE sector : NATURAL RANGE 0 TO SecNum; BEGIN sector := Addr/16#10000#; AddrLOW := sector*16#10000#; AddrHIGH := sector*16#10000# + 16#0FFFF#; END AddrHILO_SEC; PROCEDURE ADDRHILO_PG( VARIABLE AddrLOW : INOUT NATURAL RANGE 0 to ADDRRange; VARIABLE AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange; VARIABLE Addr : NATURAL) IS VARIABLE page : NATURAL RANGE 0 TO 65535; BEGIN page := Addr/16#100#; AddrLOW := Page*16#100#; AddrHIGH := Page*16#100# + 16#FF#; END AddrHILO_PG; BEGIN ---------------------------------------------------------------------------- --Power Up parameters timing --------------------------------------------------------------------------- ChipSelectOk <= '1' AFTER tdevice_VSL; WriteOk <= '1' AFTER tdevice_PUW; --------------------------------------------------------------------------- -- VITAL Timing Checks Procedures --------------------------------------------------------------------------- VITALTimingCheck: PROCESS(D_ipd, C_ipd, SNeg_ipd, HOLDNeg_ipd, WNeg_ipd) -- Timing Check Variables VARIABLE Tviol_D_C : X01 := '0'; VARIABLE TD_D_C : VitalTimingDataType; VARIABLE Tviol_HOLD_C : X01 := '0'; VARIABLE TD_HOLD_C : VitalTimingDataType; VARIABLE Tviol_S_C : X01 := '0'; VARIABLE TD_S_C : VitalTimingDataType; VARIABLE Tviol_WS_S : X01 := '0'; VARIABLE TD_WS_S : VitalTimingDataType; VARIABLE Tviol_WH_S : X01 := '0'; VARIABLE TD_WH_S : VitalTimingDataType; VARIABLE Pviol_S : X01 := '0'; VARIABLE PD_S : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Pviol_C : X01 := '0'; VARIABLE PD_C : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Pviol_C_rd : X01 := '0'; VARIABLE PD_C_rd : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Pviol_C_fast_rd : X01 := '0'; VARIABLE PD_C_fast_rd : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Violation : X01 := '0'; BEGIN --------------------------------------------------------------------------- -- Timing Check Section --------------------------------------------------------------------------- IF (TimingChecksOn) THEN -- Setup/Hold Check between D and C VitalSetupHoldCheck ( TestSignal => D_ipd, TestSignalName => "D", RefSignal => C_ipd, RefSignalName => "C", SetupHigh => tsetup_D_C, SetupLow => tsetup_D_C, HoldHigh => thold_D_C, HoldLow => thold_D_C, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_D_C, Violation => Tviol_D_C ); -- Setup/Hold Check between HOLD# and C / VitalSetupHoldCheck ( TestSignal => HOLDNeg_ipd, TestSignalName => "HOLD#", RefSignal => C_ipd, RefSignalName => "C", SetupHigh => tsetup_C_HOLDNeg, SetupLow => tsetup_HOLDNeg_C, HoldHigh => thold_C_HOLDNeg, HoldLow => thold_HOLDNeg_C, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_HOLD_C, Violation => Tviol_HOLD_C ); -- Setup/Hold Check between CS# and C VitalSetupHoldCheck ( TestSignal => SNeg_ipd, TestSignalName => "S#", RefSignal => C_ipd, RefSignalName => "C", SetupHigh => tsetup_SNeg_C, SetupLow => tsetup_SNeg_C, HoldHigh => thold_SNeg_C, HoldLow => thold_SNeg_C, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_S_C, Violation => Tviol_S_C ); -- Setup Check between W# and CS# \ VitalSetupHoldCheck ( TestSignal => WNeg_ipd, TestSignalName => "W#", RefSignal => SNeg_ipd, RefSignalName => "S#", SetupHigh => tsetup_WNeg_SNeg, CheckEnabled => true, RefTransition => '\', HeaderMsg => InstancePath & PartID, TimingData => TD_WS_S, Violation => Tviol_WS_S ); -- Hold Check between W# and CS# / VitalSetupHoldCheck ( TestSignal => WNeg_ipd, TestSignalName => "W#", RefSignal => SNeg_ipd, RefSignalName => "S#", HoldHigh => thold_WNeg_SNeg, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_WH_S, Violation => Tviol_WH_S ); -- Period Check S# VitalPeriodPulseCheck ( TestSignal => SNeg_ipd, TestSignalName => "S#", PulseWidthHigh => tpw_SNeg_posedge, PeriodData => PD_S, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_S, HeaderMsg => InstancePath & PartID, CheckEnabled => true ); -- Period Check C for everything but READ VitalPeriodPulseCheck ( TestSignal => C_ipd, TestSignalName => "C", PulseWidthLow => tpw_C_negedge, PulseWidthHigh => tpw_C_posedge, PeriodData => PD_C, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_C, HeaderMsg => InstancePath & PartID, CheckEnabled => true ); -- Period Check C for READ VitalPeriodPulseCheck ( TestSignal => C_ipd, TestSignalName => "C", Period => tperiod_C_rd, PeriodData => PD_C_rd, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_C_rd, HeaderMsg => InstancePath & PartID, CheckEnabled => rd ); -- Period Check C for other than READ VitalPeriodPulseCheck ( TestSignal => C_ipd, TestSignalName => "C", Period => tperiod_C_fast_rd, PeriodData => PD_C_fast_rd, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_C_fast_rd, HeaderMsg => InstancePath & PartID, CheckEnabled => fast_rd ); Violation := Tviol_D_C OR Tviol_HOLD_C OR Tviol_S_C OR Tviol_WS_S OR Tviol_WH_S OR Pviol_C OR Pviol_C_rd OR Pviol_C_fast_rd OR Pviol_S; Viol <= Violation; ASSERT Violation = '0' REPORT InstancePath & partID & ": simulation may be" & " inaccurate due to timing violations" SEVERITY WARNING; END IF; END PROCESS VITALTimingCheck; ---------------------------------------------------------------------------- -- sequential process for FSM state transition ---------------------------------------------------------------------------- StateTransition : PROCESS(next_state, WriteOk) BEGIN IF WriteOk = '1' THEN current_state <= next_state; END IF; END PROCESS StateTransition; --------------------------------------------------------------------------- -- Write cycle decode --------------------------------------------------------------------------- BusCycleDecode : PROCESS(C_ipd, SNeg_ipd, HOLDNeg_ipd, D_ipd, RES_in) TYPE bus_cycle_type IS (STAND_BY, CODE_BYTE, ADDRESS_BYTES, DUMMY_BYTES, DATA_BYTES ); VARIABLE bus_cycle_state : bus_cycle_type; VARIABLE data_cnt : NATURAL := 0; VARIABLE addr_cnt : NATURAL := 0; VARIABLE code_cnt : NATURAL := 0; VARIABLE dummy_cnt : NATURAL := 0; VARIABLE bit_cnt : NATURAL := 0; VARIABLE Data_in : std_logic_vector(2047 downto 0) := (others => '0'); VARIABLE code : std_logic_vector(7 downto 0); VARIABLE code_in : std_logic_vector(7 downto 0); VARIABLE Byte_slv : std_logic_vector(7 downto 0); VARIABLE addr_bytes : std_logic_vector(HiAddrBit downto 0); VARIABLE Address_in : std_logic_vector(23 downto 0); BEGIN CASE bus_cycle_state IS WHEN STAND_BY => IF falling_edge(SNeg_ipd) THEN Instruct <= NONE; write <= '1'; code_cnt := 0; addr_cnt := 0; data_cnt := 0; dummy_cnt := 0; bus_cycle_state := CODE_BYTE; END IF; WHEN CODE_BYTE => IF rising_edge(C_ipd) AND HOLDNeg_ipd = '1' THEN Code_in(code_cnt) := D_ipd; code_cnt := code_cnt + 1; IF code_cnt = BYTE THEN --MSB first FOR I IN 7 DOWNTO 0 LOOP code(i) := code_in(7-i); END LOOP; CASE code IS WHEN "00000110" => Instruct <= WREN; bus_cycle_state := DATA_BYTES; WHEN "00000100" => Instruct <= WRDI; bus_cycle_state := DATA_BYTES; WHEN "00000001" => Instruct <= WRSR; bus_cycle_state := DATA_BYTES; WHEN "00000101" => Instruct <= RDSR; bus_cycle_state := DATA_BYTES; WHEN "00000011" => Instruct <= READ; bus_cycle_state := ADDRESS_BYTES; WHEN "00001011" => Instruct <= FAST_READ; bus_cycle_state := ADDRESS_BYTES; WHEN "10101011" => Instruct <= RES_READ_ES; bus_cycle_state := DUMMY_BYTES; WHEN "11011000" => Instruct <= SE; bus_cycle_state := ADDRESS_BYTES; WHEN "11000111" => Instruct <= BE; bus_cycle_state := DATA_BYTES; WHEN "00000010" => Instruct <= PP; bus_cycle_state := ADDRESS_BYTES; WHEN "10111001" => Instruct <= DP; bus_cycle_state := DATA_BYTES; WHEN others => null; END CASE; END IF; END IF; WHEN ADDRESS_BYTES => IF rising_edge(C_ipd) AND HOLDNeg_ipd = '1' THEN Address_in(addr_cnt) := D_ipd; addr_cnt := addr_cnt + 1; IF addr_cnt = 3*BYTE THEN FOR I IN 23 DOWNTO 0 LOOP addr_bytes(23-i) := Address_in(i); END LOOP; Address <= to_nat(addr_bytes); change_addr <= '1','0' AFTER 1 ns; IF Instruct = FAST_READ THEN bus_cycle_state := DUMMY_BYTES; ELSE bus_cycle_state := DATA_BYTES; END IF; END IF; END IF; WHEN DUMMY_BYTES => IF rising_edge(C_ipd) AND HOLDNeg_ipd = '1' THEN dummy_cnt := dummy_cnt + 1; IF dummy_cnt = BYTE THEN IF Instruct = FAST_READ THEN bus_cycle_state := DATA_BYTES; END IF; ELSIF dummy_cnt = 3*BYTE THEN bus_cycle_state := DATA_BYTES; es_read <= true; END IF; END IF; IF rising_edge(SNeg_ipd) THEN IF (HOLDNeg_ipd = '1' AND dummy_cnt = 0 AND Instruct = RES_READ_ES) THEN write <= '0'; es_read <= false; END IF; bus_cycle_state := STAND_BY; END IF; WHEN DATA_BYTES => IF falling_edge(C_ipd) AND SNeg_ipd = '0' AND HOLDNeg_ipd = '1' THEN IF Instruct = READ OR Instruct = RES_READ_ES OR Instruct = FAST_READ OR Instruct = RDSR THEN read_out <= '1', '0' AFTER 1 ns; END IF; END IF; IF rising_edge(C_ipd) AND HOLDNeg_ipd = '1' THEN IF data_cnt > 2047 THEN --In case of PP, if more than 256 bytes are --sent to the device IF bit_cnt = 0 THEN FOR I IN 0 TO (255*BYTE - 1) LOOP Data_in(i) := Data_in(i+8); END LOOP; END IF; Data_in(2040 + bit_cnt) := D_ipd; bit_cnt := bit_cnt + 1; IF bit_cnt = 8 THEN bit_cnt := 0; END IF; data_cnt := data_cnt + 1; ELSE Data_in(data_cnt) := D_ipd; data_cnt := data_cnt + 1; bit_cnt := 0; END IF; END IF; IF rising_edge(SNeg_ipd) THEN bus_cycle_state := STAND_BY; es_read <= true; IF HOLDNeg_ipd = '1' AND WriteOk = '1' THEN CASE Instruct IS WHEN WREN | WRDI | DP | BE | SE => IF data_cnt = 0 THEN write <= '0'; END IF; WHEN RES_READ_ES => write <= '0'; WHEN WRSR => IF data_cnt = 8 THEN write <= '0'; Status_reg_in <= Data_in(7 downto 0); --MSB first END IF; WHEN PP => IF ((data_cnt mod 8) = 0 AND data_cnt > BYTE) THEN write <= '0'; FOR I IN 0 TO 255 LOOP FOR J IN 7 DOWNTO 0 LOOP Byte_slv(j) := Data_in((i*8) + (7-j)); END LOOP; WByte(i) <= to_nat(Byte_slv); END LOOP; IF data_cnt > 256*BYTE THEN Byte_number <= 255; ELSE Byte_number <= data_cnt/8-1; END IF; END IF; WHEN others => null; END CASE; END IF; END IF; END CASE; END PROCESS BusCycleDecode; --------------------------------------------------------------------------- -- Timing control for the Page Program --------------------------------------------------------------------------- ProgTime : PROCESS(PSTART) VARIABLE pob : time; BEGIN IF LongTimming THEN pob := tdevice_PP; ELSE pob := tdevice_PP / 100; END IF; IF rising_edge(PSTART) AND PDONE = '1' THEN IF NOT Sec_Prot(SA) = '1' THEN PDONE <= '0', '1' AFTER pob; END IF; END IF; END PROCESS ProgTime; --------------------------------------------------------------------------- -- Timing control for the Write Status Register --------------------------------------------------------------------------- WriteTime : PROCESS(WSTART) VARIABLE wob : time; BEGIN IF LongTimming THEN wob := tdevice_WR; ELSE wob := tdevice_WR / 100; END IF; IF rising_edge(WSTART) AND WDONE = '1' THEN WDONE <= '0', '1' AFTER wob; END IF; END PROCESS WriteTime; --------------------------------------------------------------------------- -- Timing control for the Bulk Erase --------------------------------------------------------------------------- ErsTime : PROCESS(ESTART) VARIABLE seo : time; VARIABLE beo : time; VARIABLE duration : time; BEGIN IF LongTimming THEN seo := tdevice_SE; beo := tdevice_BE; ELSE seo := tdevice_SE / 100; beo := tdevice_BE / 100; END IF; IF rising_edge(ESTART) AND EDONE = '1' THEN IF Instruct = BE THEN duration := beo; ELSE --Instruct = SE duration := seo; END IF; EDONE <= '0', '1' AFTER duration; END IF; END PROCESS ErsTime; --------------------------------------------------------------------------- -- Main Behavior Process -- combinational process for next state generation --------------------------------------------------------------------------- StateGen :PROCESS(write, SNeg, WDONE, PDONE, EDONE) VARIABLE sect : NATURAL RANGE 0 TO SecNum; BEGIN ----------------------------------------------------------------------- -- Functionality Section ----------------------------------------------------------------------- CASE current_state IS WHEN IDLE => IF falling_edge(write) THEN IF Instruct = WRSR AND WEL = '1' AND not(SRWD = '1' AND WNeg = '0') THEN -- can not execute if HPM is entered -- or if WEL bit is zero next_state <= WRITE_SR; ELSIF Instruct = PP AND WEL = '1' THEN sect := Address / 16#10000#; IF Sec_Prot(sect) = '0' THEN next_state <= PAGE_PG; END IF; ELSIF Instruct = SE AND WEL = '1' THEN sect := Address / 16#10000#; IF Sec_Prot(sect) = '0' THEN next_state <= SECTOR_ER; END IF; ELSIF Instruct = BE AND WEL = '1' AND (BP0 = '0' AND BP1 = '0' AND BP2 = '0') THEN next_state <= BULK_ER; ELSIF Instruct = DP THEN next_state <= DP_DOWN; ELSE next_state <= IDLE; END IF; END IF; WHEN WRITE_SR => IF rising_edge(WDONE) THEN next_state <= IDLE; END IF; WHEN PAGE_PG => IF rising_edge(PDONE) THEN next_state <= IDLE; END IF; WHEN BULK_ER | SECTOR_ER => IF rising_edge(EDONE) THEN next_state <= IDLE; END IF; WHEN DP_DOWN => IF falling_edge(write) AND Instruct = RES_READ_ES THEN next_state <= IDLE; END IF; END CASE; END PROCESS StateGen; --------------------------------------------------------------------------- --FSM Output generation and general funcionality --------------------------------------------------------------------------- Functional : PROCESS(write,read_out, WDONE, PDONE, EDONE, current_state, SNeg_ipd, HOLDNeg_ipd, Instruct, Address, WByte, WriteOk, RES1_out, RES2_out, change_addr, ChipSelectOk, WNeg_ipd, RES1_in, RES2_in) TYPE WDataType IS ARRAY (0 TO 255) OF INTEGER RANGE -1 TO MaxData; VARIABLE WData : WDataType:= (OTHERS => 0); VARIABLE oe : boolean := FALSE; VARIABLE AddrLo : NATURAL; VARIABLE AddrHi : NATURAL; VARIABLE Addr : NATURAL; VARIABLE read_cnt : NATURAL; VARIABLE read_addr : NATURAL RANGE 0 TO AddrRANGE; VARIABLE data_out : std_logic_vector(7 downto 0); VARIABLE ident_out : std_logic_vector(23 downto 0); VARIABLE old_bit : std_logic_vector(7 downto 0); VARIABLE new_bit : std_logic_vector(7 downto 0); VARIABLE old_int : INTEGER RANGE -1 to MaxData; VARIABLE new_int : INTEGER RANGE -1 to MaxData; VARIABLE wr_cnt : NATURAL RANGE 0 TO 255; VARIABLE sect : NATURAL RANGE 0 TO SecNum; VARIABLE BP : std_logic_vector(2 downto 0) := "000"; BEGIN ----------------------------------------------------------------------- -- Functionality Section ----------------------------------------------------------------------- oe := rising_edge(read_out) AND ChipSelectOk = '1'; RES_in <= RES1_in OR RES2_in; --this way, both timing conditions on --Release from Deep Power Down are merged IF Instruct'EVENT THEN read_cnt := 0; fast_rd <= true; rd <= false; END IF; IF rising_edge(change_addr) THEN read_addr := Address; END IF; IF RES1_out'EVENT AND RES1_out = '1' THEN RES1_in <= '0'; END IF; IF RES2_out'EVENT AND RES2_out = '1' THEN RES2_in <= '0'; END IF; CASE current_state IS WHEN IDLE => IF falling_edge(write) AND WriteOK = '1' THEN IF RES_in = '1' AND Instruct /= DP THEN ASSERT false REPORT InstancePath & partID & "Command results" & " can be corrupted, a delay of tRES" & " currently in progress." SEVERITY WARNING; END IF; IF Instruct = WREN THEN WEL := '1'; ELSIF Instruct = WRDI THEN WEL := '0'; ELSIF Instruct = WRSR AND WEL = '1' AND not(SRWD = '1' AND WNeg_ipd = '0') THEN -- can not execute if HPM is entered -- or if WEL bit is zero WSTART <= '1', '0' AFTER 1 ns; WIP := '1'; ELSIF Instruct = PP AND WEL = '1' THEN sect := Address / 16#10000#; IF Sec_Prot(sect) = '0' THEN PSTART <= '1', '0' AFTER 1 ns; WIP := '1'; SA <= sect; Addr := Address; wr_cnt := Byte_number; FOR I IN wr_cnt DOWNTO 0 LOOP IF Viol /= '0' AND Sec_Prot(SA) /= '0' THEN WData(i) := -1; ELSE WData(i) := WByte(i); END IF; END LOOP; END IF; ELSIF Instruct = SE AND WEL = '1' THEN sect := Address / 16#10000#; IF Sec_Prot(sect) = '0' THEN ESTART <= '1', '0' AFTER 1 ns; WIP := '1'; Addr := Address; END IF; ELSIF Instruct = BE AND WEL = '1' AND (BP0 = '0' AND BP1 = '0' AND BP2 = '0') THEN ESTART <= '1', '0' AFTER 1 ns; WIP := '1'; END IF; ELSIF oe AND RES_in = '0' THEN IF Instruct = RDSR THEN --Read Status Register Q_zd <= Status_reg(7-read_cnt); read_cnt := read_cnt + 1; IF read_cnt = 8 THEN read_cnt := 0; END IF; ELSIF Instruct = READ OR Instruct = FAST_READ THEN --Read Memory array IF Instruct = READ THEN fast_rd <= false; rd <= true; END IF; data_out := to_slv(Mem(read_addr),8); Q_zd <= data_out(7-read_cnt); read_cnt := read_cnt + 1; IF read_cnt = 8 THEN read_cnt := 0; IF read_addr = AddrRANGE THEN read_addr := 0; ELSE read_addr := read_addr + 1; END IF; END IF; ELSE --IF Instruct = RES_READ_ES - look at assertion of oe data_out := to_slv(ES, 8); Q_zd <= data_out(7-read_cnt); read_cnt := read_cnt + 1; IF read_cnt = 8 THEN read_cnt := 0; END IF; END IF; ELSIF oe AND RES_in = '1' THEN Q_zd <= 'X'; read_cnt := read_cnt + 1; IF read_cnt = 8 THEN read_cnt := 0; END IF; ASSERT false REPORT InstancePath & partID & "Command results" & " can be corrupted, a delay of tRES" & " currently in progress." SEVERITY WARNING; END IF; WHEN WRITE_SR => IF oe AND Instruct = RDSR THEN Q_zd <= Status_reg(7-read_cnt); read_cnt := read_cnt + 1; IF read_cnt = 8 THEN read_cnt := 0; END IF; END IF; IF WDONE = '1' THEN WIP := '0'; WEL := '0'; SRWD := Status_reg_in(0);--MSB first BP2 := Status_reg_in(3); BP1 := Status_reg_in(4); BP0 := Status_reg_in(5); BP := BP2 & BP1 & BP0; CASE BP IS WHEN "000" => Sec_Prot := (others => '0'); WHEN "001" => Sec_Prot(15) := '1'; WHEN "010" => Sec_Prot(15 downto 14):= "11"; WHEN "011" => Sec_Prot(15 downto 12):= to_slv(16#F#,4); WHEN "100" => Sec_Prot(15 downto 8):= to_slv(16#FF#,8); WHEN others => Sec_Prot := (others => '1'); END CASE; END IF; WHEN PAGE_PG => IF oe AND Instruct = RDSR THEN Q_zd <= Status_reg(7-read_cnt); read_cnt := read_cnt + 1; IF read_cnt = 8 THEN read_cnt := 0; END IF; END IF; ADDRHILO_PG(AddrLo, AddrHi, Addr); FOR I IN Addr TO Addr + wr_cnt LOOP new_int := WData(i-Addr); IF (i - AddrLo) >= 256 THEN old_int := Mem(i - 256); IF new_int > -1 THEN new_bit := to_slv(new_int,8); IF old_int > -1 THEN old_bit := to_slv(old_int,8); FOR j IN 0 TO 7 LOOP IF old_bit(j) = '0' THEN new_bit(j) := '0'; END IF; END LOOP; new_int := to_nat(new_bit); END IF; WData(i-Addr) := new_int; ELSE WData(i-Addr) := -1; END IF; ELSE old_int := Mem(i); IF new_int > -1 THEN new_bit := to_slv(new_int,8); IF old_int > -1 THEN old_bit := to_slv(old_int,8); FOR j IN 0 TO 7 LOOP IF old_bit(j) = '0' THEN new_bit(j) := '0'; END IF; END LOOP; new_int := to_nat(new_bit); END IF; WData(i-Addr) := new_int; ELSE WData(i-Addr) := -1; END IF; END IF; END LOOP; FOR I IN Addr TO Addr + wr_cnt LOOP IF (i - AddrLo) >= 256 THEN Mem (i - 256) := -1; ELSE Mem (i) := -1; END IF; END LOOP; IF PDONE = '1' THEN WIP := '0'; WEL := '0'; FOR i IN Addr TO Addr + wr_cnt LOOP IF (i - AddrLo) >= 256 THEN Mem(i - 256) := WData(i-Addr); ELSE Mem (i) := WData(i-Addr); END IF; END LOOP; END IF; WHEN SECTOR_ER => IF oe AND Instruct = RDSR THEN Q_zd <= Status_reg(7-read_cnt); read_cnt := read_cnt + 1; IF read_cnt = 8 THEN read_cnt := 0; END IF; END IF; ADDRHILO_SEC(AddrLo, AddrHi, Addr); FOR i IN AddrLo TO AddrHi LOOP Mem(i) := -1; END LOOP; IF EDONE = '1' THEN WIP := '0'; WEL := '0'; FOR i IN AddrLo TO AddrHi LOOP Mem(i) := MaxData; END LOOP; END IF; WHEN BULK_ER => IF oe AND Instruct = RDSR THEN Q_zd <= Status_reg(7-read_cnt); read_cnt := read_cnt + 1; IF read_cnt = 8 THEN read_cnt := 0; END IF; END IF; FOR i IN 0 TO AddrRANGE LOOP Mem(i) := -1; END LOOP; IF EDONE = '1' THEN WIP := '0'; WEL := '0'; FOR i IN 0 TO AddrRANGE LOOP Mem(i) := MaxData; END LOOP; END IF; WHEN DP_DOWN => IF falling_edge(write) THEN IF Instruct = RES_READ_ES THEN IF es_read THEN RES1_in <= '1'; ELSE RES2_in <= '1'; END IF; END IF; ELSIF oe AND Instruct = RES_READ_ES THEN --Read Electronic Signature data_out := to_slv(ES,8); Q_zd <= data_out(7 - read_cnt); read_cnt := read_cnt + 1; IF read_cnt = 8 THEN read_cnt := 0; END IF; END IF; END CASE; --Output Disable Control IF ((SNeg_ipd = '1') OR (HOLDNeg_ipd = '0')) THEN Q_temp <= Q_zd; Q_zd <= 'Z'; END IF; IF ((SNeg_ipd = '0') AND rising_edge(HOLDNeg_ipd) AND C_ipd = '0') THEN Q_zd <= Q_temp; END IF; END PROCESS Functional; --------------------------------------------------------------------------- ---- File Read Section - Preload Control --------------------------------------------------------------------------- MemPreload : PROCESS -- text file input variables FILE mem_file : text is mem_file_name; VARIABLE ind : NATURAL RANGE 0 TO AddrRANGE := 0; VARIABLE buf : line; BEGIN --------------------------------------------------------------------------- --m25p80 memory preload file format ----------------------------------- --------------------------------------------------------------------------- -- / - comment -- @aaaaa - <aaaaa> stands for address -- dd - <dd> is byte to be written at Mem(aaaaa++) -- (aaaaa is incremented at every load) -- only first 1-6 columns are loaded. NO empty lines !!!!!!!!!!!!!!!! --------------------------------------------------------------------------- -- memory preload IF (mem_file_name /= "none" AND UserPreload) THEN ind := 0; Mem := (OTHERS => MaxData); WHILE (not ENDFILE (mem_file)) LOOP READLINE (mem_file, buf); IF buf(1) = '/' THEN NEXT; ELSIF buf(1) = '@' THEN ind := h(buf(2 to 6)); --address ELSE IF ind <= AddrRANGE THEN Mem(ind) := h(buf(1 to 2)); END IF; IF ind < AddrRANGE THEN ind := ind + 1; ELSIF ind >= AddrRANGE THEN ASSERT false REPORT "Given preload address is out of" & "memory address range" SEVERITY warning; END IF; END IF; END LOOP; END IF; WAIT; END PROCESS MemPreload; Q_OUT: PROCESS(Q_zd) VARIABLE Q_GlitchData : VitalGlitchDataType; BEGIN VitalPathDelay01Z ( OutSignal => Q, OutSignalName => "Q", OutTemp => Q_zd, GlitchData => Q_GlitchData, XOn => XOn, MsgOn => MsgOn, Paths => ( 0 => (InputChangeTime => C_ipd'LAST_EVENT, PathDelay => VitalExtendtofillDelay(tpd_C_Q), PathCondition => true), 1 => (InputChangeTime => SNeg_ipd'LAST_EVENT, PathDelay => tpd_SNeg_Q, PathCondition => SNeg_ipd = '1'), 2 => (InputChangeTime => HOLDNeg_ipd'LAST_EVENT, PathDelay => tpd_HOLDNeg_Q, PathCondition => TRUE) ) ); END PROCESS Q_OUT; END BLOCK behavior; END vhdl_behavioral;