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/] [s25fl064a.vhd] - Rev 2
Compare with Previous | Blame | View Log
------------------------------------------------------------------------------- -- File Name: s25fl064a.vhd ------------------------------------------------------------------------------- -- Copyright (C) 2005-2007 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 May 11 Inital Release -- V1.1 D.Randjelovic 06 Apr 11 MSB of latched address is ignored -- V1.2 D.Randjelovic 06 May 04 Page Program Command used with the -- single byte data corrected. -- Release from Deep Power Down when -- Electronic Signature is not read -- fixed -- V1.3 D.Stanojkovic 07 Jul 02 Correction to enable testing in NCSim -- ------------------------------------------------------------------------------- -- PART DESCRIPTION: -- -- Library: FLASH -- Technology: Flash Memory -- Part: S25FL064A -- -- Description: 64 Megabit Serial Flash Memory with 50MHz SPI Bus Interface -- ------------------------------------------------------------------------------- -- Comments : -- When testing with NCSim default value for TimingModel in -- generic list should be removed, otherwise backannotation of this value -- will not be done properly ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- -- Known Bugs: -- ------------------------------------------------------------------------------- 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 s25fl064a IS GENERIC ( -- tipd delays: interconnect path delays tipd_SCK : VitalDelayType01 := VitalZeroDelay01; tipd_SI : VitalDelayType01 := VitalZeroDelay01; tipd_CSNeg : VitalDelayType01 := VitalZeroDelay01; tipd_HOLDNeg : VitalDelayType01 := VitalZeroDelay01; tipd_WNeg : VitalDelayType01 := VitalZeroDelay01; -- tpd delays tpd_SCK_SO : VitalDelayType01Z := UnitDelay01Z;--tV tpd_CSNeg_SO : VitalDelayType01Z := UnitDelay01Z;--tDIS tpd_HOLDNeg_SO : VitalDelayType01Z := UnitDelay01Z;--tLZ,tHZ --tsetup values tsetup_SI_SCK : VitalDelayType := UnitDelay; --tsuDAT / tsetup_CSNeg_SCK : VitalDelayType := UnitDelay; --tCSS / tsetup_HOLDNeg_SCK : VitalDelayType := UnitDelay; --tHD / tsetup_WNeg_CSNeg : VitalDelayType := UnitDelay; --tWPS \ --thold values thold_SI_SCK : VitalDelayType := UnitDelay; --thdDAT / thold_CSNeg_SCK : VitalDelayType := UnitDelay; --tCSH / thold_HOLDNeg_SCK : VitalDelayType := UnitDelay; --tCD / thold_WNeg_CSNeg : VitalDelayType := UnitDelay; --tWPH \ --tpw values: pulse width tpw_SCK_posedge : VitalDelayType := UnitDelay; --tWH tpw_SCK_negedge : VitalDelayType := UnitDelay; --tWL tpw_CSNeg_posedge : VitalDelayType := UnitDelay; --tCS -- tperiod min (calculated as 1/max freq) tperiod_SCK_rd : VitalDelayType := UnitDelay; -- fSCK=33MHz tperiod_SCK_fast_rd : VitalDelayType := UnitDelay; -- fSCK=50MHz -- tdevice values: values for internal delays -- Page Program Operation tdevice_PP : VitalDelayType := 3 ms; --tPP --Sector Erase Operation tdevice_SE : VitalDelayType := 3 sec; --tSE --Bulk Erase Operation tdevice_BE : VitalDelayType := 384 sec; --tBE --Write Status Register Operation tdevice_WR : VitalDelayType := 60 ms; --tW --Deep Power Down tdevice_DP : VitalDelayType := 3 us; --tDP --Release from Software Protect Mode tdevice_RES : VitalDelayType := 30 us; --tRES --VCC (min) to CS# Low tdevice_PU : VitalDelayType := 10 ms; -- generic control parameters InstancePath : STRING := DefaultInstancePath; TimingChecksOn : BOOLEAN := DefaultTimingChecks; MsgOn : BOOLEAN := DefaultMsgOn; XOn : BOOLEAN := DefaultXon; -- memory file to be loaded mem_file_name : STRING := "s25fl064a.mem"; UserPreload : BOOLEAN := FALSE; --TRUE; LongTimming : BOOLEAN := TRUE; -- For FMF SDF technology file usage TimingModel : STRING := DefaultTimingModel ); PORT ( SCK : IN std_ulogic := 'U'; --serial clock input SI : IN std_ulogic := 'U'; --serial data input CSNeg : IN std_ulogic := 'U'; -- chip select input HOLDNeg : IN std_ulogic := 'U'; -- hold input WNeg : IN std_ulogic := 'U'; -- write protect input SO : OUT std_ulogic := 'U' --serial data output ); ATTRIBUTE VITAL_LEVEL0 of s25fl064a : ENTITY IS TRUE; END s25fl064a; ------------------------------------------------------------------------------- -- ARCHITECTURE DECLARATION ------------------------------------------------------------------------------- ARCHITECTURE vhdl_behavioral of s25fl064a IS ATTRIBUTE VITAL_LEVEL0 OF vhdl_behavioral : ARCHITECTURE IS TRUE; CONSTANT PartID : STRING := "s25fl064a"; CONSTANT MaxData : NATURAL := 16#FF#; --255; CONSTANT SecSize : NATURAL := 16#FFFF#; --65535 CONSTANT SecNum : NATURAL := 127; CONSTANT HiAddrBit : NATURAL := 22; CONSTANT AddrRANGE : NATURAL := 16#7FFFFF#; CONSTANT BYTE : NATURAL := 8; --Electronic Signature CONSTANT ES : NATURAL := 16#16#; --Device ID --Manufacturer Identification && Memory Type && Memory Capacity CONSTANT DeviceID : NATURAL := 16#010216#; -- interconnect path delay signals SIGNAL SCK_ipd : std_ulogic := 'U'; SIGNAL SI_ipd : std_ulogic := 'U'; SIGNAL CSNeg_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 PU_in : std_ulogic := '0'; SIGNAL PU_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 RES_in : std_ulogic := '0'; SIGNAL RES_out : std_ulogic := '0'; BEGIN --------------------------------------------------------------------------- -- Internal Delays --------------------------------------------------------------------------- -- Artificial VITAL primitives to incorporate internal delays PP :VitalBuf(PP_out, PP_in, (tdevice_PP ,UnitDelay)); PU :VitalBuf(PU_out, PU_in, (tdevice_PU ,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)); RES :VitalBuf(RES_out, RES_in, (tdevice_RES ,UnitDelay)); --------------------------------------------------------------------------- -- Wire Delays --------------------------------------------------------------------------- WireDelay : BLOCK BEGIN w_1 : VitalWireDelay (SCK_ipd, SCK, tipd_SCK); w_2 : VitalWireDelay (SI_ipd, SI, tipd_SI); w_3 : VitalWireDelay (CSNeg_ipd, CSNeg, tipd_CSNeg); 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, RDID, 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 SO_zd : std_logic :='Z'; --HOLD delay on output data SIGNAL SO_z : std_logic :='Z'; -- powerup SIGNAL PoweredUp : 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 WEL :std_logic IS Status_reg(1); ALIAS WIP :std_logic IS Status_reg(0); 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 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 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 time; --------------------------------------------------------------------------- PoweredUp <= '1' AFTER tdevice_PU; --------------------------------------------------------------------------- -- VITAL Timing Checks Procedures --------------------------------------------------------------------------- VITALTimingCheck: PROCESS(SI_ipd, SCK_ipd, CSNeg_ipd, HOLDNeg_ipd, WNeg_ipd) -- Timing Check Variables VARIABLE Tviol_SI_SCK : X01 := '0'; VARIABLE TD_SI_SCK : VitalTimingDataType; VARIABLE Tviol_HOLD_SCK : X01 := '0'; VARIABLE TD_HOLD_SCK : VitalTimingDataType; VARIABLE Tviol_CS_SCK : X01 := '0'; VARIABLE TD_CS_SCK : VitalTimingDataType; VARIABLE Tviol_WS_CS : X01 := '0'; VARIABLE TD_WS_CS : VitalTimingDataType; VARIABLE Tviol_WH_CS : X01 := '0'; VARIABLE TD_WH_CS : VitalTimingDataType; VARIABLE Pviol_CS : X01 := '0'; VARIABLE PD_CS : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Pviol_SCK : X01 := '0'; VARIABLE PD_SCK : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Pviol_SCK_rd : X01 := '0'; VARIABLE PD_SCK_rd : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Pviol_SCK_fast_rd: X01 := '0'; VARIABLE PD_SCK_fast_rd : VitalPeriodDataType := VitalPeriodDataInit; VARIABLE Violation : X01 := '0'; BEGIN --------------------------------------------------------------------------- -- Timing Check Section --------------------------------------------------------------------------- IF (TimingChecksOn) THEN -- Setup/Hold Check between SI and SCK VitalSetupHoldCheck ( TestSignal => SI_ipd, TestSignalName => "SI", RefSignal => SCK_ipd, RefSignalName => "SCK", SetupHigh => tsetup_SI_SCK, SetupLow => tsetup_SI_SCK, HoldHigh => thold_SI_SCK, HoldLow => thold_SI_SCK, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_SI_SCK, Violation => Tviol_SI_SCK ); -- Setup/Hold Check between HOLD# and SCK / VitalSetupHoldCheck ( TestSignal => HOLDNeg_ipd, TestSignalName => "HOLD#", RefSignal => SCK_ipd, RefSignalName => "SCK", SetupLow => tsetup_HOLDNeg_SCK, HoldLow => thold_HOLDNeg_SCK, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_HOLD_SCK, Violation => Tviol_HOLD_SCK ); -- Setup/Hold Check between CS# and SCK VitalSetupHoldCheck ( TestSignal => CSNeg_ipd, TestSignalName => "CS#", RefSignal => SCK_ipd, RefSignalName => "SCK", SetupHigh => tsetup_CSNeg_SCK, SetupLow => tsetup_CSNeg_SCK, HoldHigh => thold_CSNeg_SCK, HoldLow => thold_CSNeg_SCK, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_CS_SCK, Violation => Tviol_CS_SCK ); -- Setup Check between W# and CS# \ VitalSetupHoldCheck ( TestSignal => WNeg_ipd, TestSignalName => "W#", RefSignal => CSNeg_ipd, RefSignalName => "CS#", SetupHigh => tsetup_WNeg_CSNeg, CheckEnabled => true, RefTransition => '\', HeaderMsg => InstancePath & PartID, TimingData => TD_WS_CS, Violation => Tviol_WS_CS ); -- Hold Check between W# and CS# / VitalSetupHoldCheck ( TestSignal => WNeg_ipd, TestSignalName => "W#", RefSignal => CSNeg_ipd, RefSignalName => "CS#", HoldHigh => thold_WNeg_CSNeg, CheckEnabled => true, RefTransition => '/', HeaderMsg => InstancePath & PartID, TimingData => TD_WH_CS, Violation => Tviol_WH_CS ); -- Period Check CS# m VitalPeriodPulseCheck ( TestSignal => CSNeg_ipd, TestSignalName => "CS#", PulseWidthHigh => tpw_CSNeg_posedge, PeriodData => PD_CS, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_CS, HeaderMsg => InstancePath & PartID, CheckEnabled => true ); -- Period Check SCK for everything but READ VitalPeriodPulseCheck ( TestSignal => SCK_ipd, TestSignalName => "SCK", PulseWidthLow => tpw_SCK_negedge, PulseWidthHigh => tpw_SCK_posedge, PeriodData => PD_SCK, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_SCK, HeaderMsg => InstancePath & PartID, CheckEnabled => true ); -- Period Check SCK for READ VitalPeriodPulseCheck ( TestSignal => SCK_ipd, TestSignalName => "SCK", Period => tperiod_SCK_rd, PeriodData => PD_SCK_rd, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_SCK_rd, HeaderMsg => InstancePath & PartID, CheckEnabled => rd ); -- Period Check SCK for other than READ VitalPeriodPulseCheck ( TestSignal => SCK_ipd, TestSignalName => "SCK", Period => tperiod_SCK_fast_rd, PeriodData => PD_SCK_fast_rd, XOn => XOn, MsgOn => MsgOn, Violation => Pviol_SCK_fast_rd, HeaderMsg => InstancePath & PartID, CheckEnabled => fast_rd ); Violation := Tviol_SI_SCK OR Tviol_HOLD_SCK OR Tviol_CS_SCK OR Tviol_WS_CS OR Tviol_WH_CS OR Pviol_SCK OR Pviol_SCK_rd OR Pviol_SCK_fast_rd OR Pviol_CS; 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, PoweredUp) BEGIN IF PoweredUp = '1' THEN current_state <= next_state; END IF; END PROCESS StateTransition; --------------------------------------------------------------------------- -- Write cycle decode --------------------------------------------------------------------------- BusCycleDecode : PROCESS(SCK_ipd, CSNeg_ipd, HOLDNeg_ipd, SI_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(CSNeg_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(SCK_ipd) AND HOLDNeg_ipd = '1' THEN Code_in(code_cnt) := SI_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 "10011111" => Instruct <= RDID; bus_cycle_state := DATA_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(SCK_ipd) AND HOLDNeg_ipd = '1' THEN Address_in(addr_cnt) := SI_ipd; addr_cnt := addr_cnt + 1; IF addr_cnt = 3*BYTE THEN FOR I IN 23 DOWNTO 23-HiAddrBit 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(SCK_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; END IF; END IF; IF rising_edge(CSNeg_ipd) THEN bus_cycle_state := STAND_BY; IF HOLDNeg_ipd = '1' AND Instruct = RES_READ_ES THEN write <= '0'; END IF; END IF; WHEN DATA_BYTES => IF falling_edge(SCK_ipd) AND CSNeg_ipd = '0' AND HOLDNeg_ipd = '1' THEN IF Instruct = READ OR Instruct = RES_READ_ES OR Instruct = FAST_READ OR Instruct = RDSR OR Instruct = RDID THEN read_out <= '1', '0' AFTER 1 ns; END IF; END IF; IF rising_edge(SCK_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) := SI_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) := SI_ipd; data_cnt := data_cnt + 1; bit_cnt := 0; END IF; END IF; IF rising_edge(CSNeg_ipd) THEN bus_cycle_state := STAND_BY; IF HOLDNeg_ipd = '1' THEN CASE Instruct IS WHEN WREN | WRDI | DP | BE | SE => IF data_cnt = 0 THEN write <= '0'; END IF; WHEN RDID | 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 > 0) 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; CheckCEOnPowerUP :PROCESS BEGIN IF CSNeg /= '1' THEN REPORT InstancePath & partID & ": Device is selected during Power Up" SEVERITY WARNING; END IF; WAIT; END PROCESS; --------------------------------------------------------------------------- -- Main Behavior Process -- combinational process for next state generation --------------------------------------------------------------------------- StateGen :PROCESS(write, CSNeg, 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, CSNeg_ipd, HOLDNeg_ipd, Instruct, Address, WByte, RES_out, change_addr, PoweredUp, WNeg_ipd) 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 PoweredUp = '1'; 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 RES_out'EVENT AND RES_out = '1' THEN RES_in <= '0'; END IF; CASE current_state IS WHEN IDLE => IF falling_edge(write) THEN read_cnt := 0; IF RES_in = '1' 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 SO_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); SO_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; ELSIF Instruct = RDID THEN --Read Device ID --can be terminated by driving CSNeg high --at any time ident_out := to_slv(DeviceID,24); SO_zd <= ident_out(23-read_cnt); read_cnt := read_cnt + 1; IF read_cnt = 24 THEN read_cnt := 0; END IF; ELSIF Instruct = RES_READ_ES THEN --Read Electronic Signature data_out := to_slv(ES,8); SO_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 SO_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 SO_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(127) := '1'; Sec_Prot(126) := '1'; Sec_Prot(125 downto 0) := (others => '0'); WHEN "010" => Sec_Prot(127 downto 124):= (others => '1'); Sec_Prot(123 downto 0) := (others => '0'); WHEN "011" => Sec_Prot(127 downto 120):= to_slv(16#FF#,8); Sec_Prot(119 downto 0) := (others => '0'); WHEN "100" => Sec_Prot(127 downto 112):= to_slv(16#FFFF#,16); Sec_Prot(111 downto 0) := (others => '0'); WHEN "101" => Sec_Prot(127 downto 112):= to_slv(16#FFFF#,16); Sec_Prot(111 downto 96):= to_slv(16#FFFF#,16); Sec_Prot(95 downto 0) := (others => '0'); WHEN "110" => Sec_Prot(127 downto 112):= to_slv(16#FFFF#,16); Sec_Prot(111 downto 96):= to_slv(16#FFFF#,16); Sec_Prot(95 downto 80):= to_slv(16#FFFF#,16); Sec_Prot(79 downto 64):= to_slv(16#FFFF#,16); Sec_Prot(63 downto 0) := (others => '0'); WHEN others => Sec_Prot := (others => '1'); END CASE; END IF; WHEN PAGE_PG => IF oe AND Instruct = RDSR THEN SO_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); IF (Addr + wr_cnt) > AddrHi THEN wr_cnt := AddrHi - Addr; END IF; FOR I IN Addr TO Addr + wr_cnt LOOP new_int := WData(i-Addr); 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 LOOP; FOR I IN Addr TO Addr + wr_cnt LOOP Mem (i) := -1; END LOOP; IF PDONE = '1' THEN WIP := '0'; WEL := '0'; FOR i IN Addr TO Addr + wr_cnt LOOP Mem(i) := WData(i-Addr); END LOOP; END IF; WHEN SECTOR_ER => IF oe AND Instruct = RDSR THEN SO_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 SO_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 RES_in <= '1'; END IF; ELSIF oe AND Instruct = RES_READ_ES THEN --Read Electronic Signature data_out := to_slv(ES,8); SO_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 (CSNeg_ipd = '1') THEN SO_zd <= 'Z'; END IF; END PROCESS Functional; HOLD_FRAME_ON_SO_ZD : PROCESS( SO_zd, HOLDNeg_ipd) BEGIN IF (HOLDNeg_ipd = '0') THEN SO_z <= 'Z'; ELSE SO_z <= SO_zd; END IF; END PROCESS HOLD_FRAME_ON_SO_ZD; --------------------------------------------------------------------------- ---- File Read Section - Preload Control --------------------------------------------------------------------------- MemPreload : PROCESS -- text file input variables FILE mem_file : text is mem_file_name; VARIABLE ind : NATURAL := 0; VARIABLE buf : line; BEGIN --------------------------------------------------------------------------- --s25fl016a memory preload file format ----------------------------------- --------------------------------------------------------------------------- -- / - comment -- @aaaaaa - <aaaaaa> stands for address -- dd - <dd> is byte to be written at Mem(aaaaaa++) -- (aaaaaa is incremented at every load) -- only first 1-7 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 7)); --address IF ind > AddrRANGE THEN ASSERT false REPORT "Given preload address is out of" & "memory address range" SEVERITY warning; END IF; ELSE IF ind <= AddrRANGE THEN Mem(ind) := h(buf(1 to 2)); END IF; IF ind < AddrRANGE THEN ind := ind + 1; END IF; END IF; END LOOP; END IF; WAIT; END PROCESS MemPreload; SO_OUT: PROCESS(SO_z) VARIABLE SO_GlitchData : VitalGlitchDataType; BEGIN VitalPathDelay01Z ( OutSignal => SO, OutSignalName => "SO", OutTemp => SO_z, GlitchData => SO_GlitchData, XOn => XOn, MsgOn => MsgOn, Paths => ( 0 => (InputChangeTime => SCK_ipd'LAST_EVENT, PathDelay => VitalExtendtofillDelay(tpd_SCK_SO), PathCondition => SO_z /= 'Z'), 1 => (InputChangeTime => CSNeg_ipd'LAST_EVENT, PathDelay => tpd_CSNeg_SO, PathCondition => CSNeg_ipd = '1'), 2 => (InputChangeTime => HOLDNeg_ipd'LAST_EVENT, PathDelay => tpd_HOLDNeg_SO, PathCondition => TRUE) ) ); END PROCESS SO_OUT; END BLOCK behavior; END vhdl_behavioral;