-------------------------------------------------------------------------------
--  File Name: s25fl064k.vhd
-------------------------------------------------------------------------------
--  Copyright (C) 2012 Spansion, LLC.
--
--  MODIFICATION HISTORY:
--
--  version:  |    author:    | mod date: |  changes made:
--    V1.0     R. Prokopovic    10 Sep 08   Inital Release
--    V1.0     S. Petrovic      12 Sep 12   Corrected functionality for sector
--                                          and block erase and page program
--                                          operation
-------------------------------------------------------------------------------
--  PART DESCRIPTION:
--
--  Library:    FLASH
--  Technology: FLASH MEMORY
--  Part:       S25FL064K
--
--   Description: 64 Megabit Serial Flash Memory
--
-------------------------------------------------------------------------------
--  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 s25fl064k IS
    GENERIC (
    ---------------------------------------------------------------------------
    -- TIMING GENERICS:
    ---------------------------------------------------------------------------
        -- tipd delays: interconnect path delays (delay between components)
        --    There should be one for each IN or INOUT pin in the port list
        --    They are given default values of zero delay.
        tipd_SCK                : VitalDelayType01  := VitalZeroDelay01;
        tipd_SI                 : VitalDelayType01  := VitalZeroDelay01;
        tipd_SO                 : VitalDelayType01  := VitalZeroDelay01;

        tipd_CSNeg              : VitalDelayType01  := VitalZeroDelay01;
        tipd_HOLDNeg            : VitalDelayType01  := VitalZeroDelay01;
        tipd_WPNeg              : VitalDelayType01  := VitalZeroDelay01;

        -- tpd delays: propagation delays (pin-to-pin delay within a component)
        tpd_SCK_SO_RDID_EQ_0    : VitalDelayType01Z := UnitDelay01Z;--tCLQV1
        tpd_SCK_SO_RDID_EQ_1    : VitalDelayType01Z := UnitDelay01Z;--tCLQV2
        tpd_CSNeg_SO            : VitalDelayType01Z := UnitDelay01Z;--tSHQZ
        tpd_HOLDNeg_SO          : VitalDelayType01Z := UnitDelay01Z;--tHLQZ

        -- tsetup values: setup times
        tsetup_CSNeg_SCK        :  VitalDelayType    := UnitDelay;--tSLCH,tSHCH
        tsetup_SI_SCK_normal_noedge_posedge      :  VitalDelayType
                                                     := UnitDelay;--tDVCH
        tsetup_HOLDNeg_SCK      :  VitalDelayType    := UnitDelay;--tHLCH,tHHCH
        tsetup_WPNeg_CSNeg      :  VitalDelayType    := UnitDelay;--tWHSL

        -- thold values: hold times
        thold_CSNeg_SCK         :  VitalDelayType    := UnitDelay;--tSLCH,tSHCH
        thold_SI_SCK_normal_noedge_posedge  :  VitalDelayType
                                                     := UnitDelay;--tCHDX
        thold_HOLDNeg_SCK       :  VitalDelayType    := UnitDelay;--tCHHL,tCHHH
        thold_WPNeg_CSNeg       :  VitalDelayType    := UnitDelay;--tSHWL

        --tpw values: pulse width
        tpw_SCK_slow_posedge     : VitalDelayType     := UnitDelay; -- tCH
        tpw_SCK_slow_negedge     : VitalDelayType     := UnitDelay; -- tCL
        tpw_SCK_fast_posedge     : VitalDelayType     := UnitDelay; -- tCH
        tpw_SCK_fast_negedge     : VitalDelayType     := UnitDelay; -- tCL
        tpw_CSNeg_read_posedge   : VitalDelayType     := UnitDelay; -- tSHSL1
        tpw_CSNeg_pger_posedge   : VitalDelayType     := UnitDelay; -- tSHSL2

        -- tperiod min (calculated as 1/max freq)
        tperiod_SCK_slow         : VitalDelayType     := UnitDelay;--
        tperiod_SCK_fast         : VitalDelayType     := UnitDelay;--

        -- tdevice values: values for internal delays
        -- VCC (min) to CS# Low
        tdevice_PU              : VitalDelayType := 10 us;
        -- CS# High to Power Down Mode -- tDP
        tdevice_DP              : VitalDelayType := 3 us;
        -- CS# High to StandBy mode without Electronic Signature read
        tdevice_RES1            : VitalDelayType := 3 us;
        -- CS# High to StandBy mode with Electronic Signature read
        tdevice_RES2            : VitalDelayType := 1.8 us;
        -- CS# High to next Instruction after Suspend
        tdevice_PRGSUSP         : VitalDelayType := 20 us;
        -- CS# High to next Instruction after Suspend
        tdevice_ERSSUSP         : VitalDelayType := 20 us;
        -- CS# High to next Instruction after Suspend
        tdevice_SUSP_DLY        : VitalDelayType := 20 us;
        -- Resume Suspend to Program/Erase time
        tdevice_PRGRES          : VitalDelayType := 200 ns;
        -- Resume Suspend to Program/Erase time
        tdevice_ERSRES          : VitalDelayType := 200 ns;
        -- Page Program Time
        tdevice_PP              : VitalDelayType := 3 ms;
        -- Byte Program Time (First Byte)
        tdevice_BP1             : VitalDelayType := 50 us;
        -- Additional Byte Program Time (After First Byte)
        tdevice_BP2             : VitalDelayType := 12 us;
        -- Sector Erase Time (4KB)
        tdevice_SE              : VitalDelayType := 400 ms;
        -- Block Erase Time (32KB)
        tdevice_BE1             : VitalDelayType := 800 ms;
        -- Block Erase Time (64KB)
        tdevice_BE2             : VitalDelayType := 1000 ms;
        -- Chip Erase Time
        tdevice_CE              : VitalDelayType := 30 sec;
        -- Write Status Register Time
        tdevice_WRR             : VitalDelayType := 15 ms;
        -- Write Volatile Status Register Time
        tdevice_VRR             : VitalDelayType := 50 ns;

    ---------------------------------------------------------------------------
    -- CONTROL GENERICS:
    ---------------------------------------------------------------------------

        -- generic control parameters
        InstancePath      : STRING    := DefaultInstancePath;
        TimingChecksOn    : BOOLEAN   := DefaultTimingChecks;
        MsgOn             : BOOLEAN   := DefaultMsgOn;
        XOn               : BOOLEAN   := DefaultXon;

        -- memory file to be loaded
        mem_file_name     : STRING    := "s25fl064k.mem";
        screg_file_name   : STRING    := "s25fl064kscreg.mem";

        UserPreload       : BOOLEAN   := FALSE; --TRUE;
        LongTimming       : BOOLEAN   := FALSE;

        -- For FMF SDF technology file usage
        TimingModel       : STRING    := DefaultTimingModel
    );
    PORT (
        -- Data Inputs/Outputs
        SI                : INOUT std_ulogic := 'U'; -- serial data input/IO0
        SO                : INOUT std_ulogic := 'U'; -- serial data output/IO1
        -- Controls
        SCK               : IN    std_ulogic := 'U'; -- serial clock input
        CSNeg             : IN    std_ulogic := 'U'; -- chip select input
        WPNeg             : INOUT std_ulogic := 'U'; -- write protect input/IO2
        HOLDNeg           : INOUT std_ulogic := 'U'  -- hold input/IO3
    );

    ATTRIBUTE VITAL_LEVEL0 of s25fl064k : ENTITY IS TRUE;
END s25fl064k;

-------------------------------------------------------------------------------
-- ARCHITECTURE DECLARATION
-------------------------------------------------------------------------------
ARCHITECTURE vhdl_behavioral of s25fl064k IS
    ATTRIBUTE VITAL_LEVEL0 OF vhdl_behavioral : ARCHITECTURE IS TRUE;

    ---------------------------------------------------------------------------
    -- CONSTANT AND SIGNAL DECLARATION
    ---------------------------------------------------------------------------
    --Declaration of constants - memory characteristics
        -- The constant declared here are used to enable the creation of models
        -- of memories within a family with a minimum amount of editing

    CONSTANT  PartID        : STRING  := "s25fl064k";
    CONSTANT  MaxData       : NATURAL := 16#FF#;
    CONSTANT  AddrRANGE     : NATURAL := 16#7FFFFF#;
    CONSTANT  PageNum       : NATURAL := 16#7FFF#;
    CONSTANT  SecSize_4     : NATURAL := 16#FFF#;
    CONSTANT  SecSize_32    : NATURAL := 16#7FFF#;
    CONSTANT  SecSize_64    : NATURAL := 16#FFFF#;
    CONSTANT  Blk_4_Num     : NATURAL := 2047;
    CONSTANT  Blk_64_Num    : NATURAL := 127;
    CONSTANT  Blk_32_Num    : NATURAL := 255;
    CONSTANT  SFDP_HiAddr   : NATURAL := 16#FF#;
    CONSTANT  SFDP_LoAddr   : NATURAL := 16#00#;
    CONSTANT  SecReg_HiAddr : NATURAL := 16#FF#;
    CONSTANT  SecReg_LoAddr : NATURAL := 16#00#;
    CONSTANT  SCREG_LoAddr  : NATURAL := 16#000#;
    CONSTANT  SCREG_HiAddr  : NATURAL := 16#2FF#;
    CONSTANT  BYTE          : NATURAL := 8;

    -- Manufacturer Identification and Device Identification
    CONSTANT  Manuf_ID      : NATURAL := 16#EF#;
    CONSTANT  Device_ID1    : NATURAL := 16#16#;
    CONSTANT  Device_ID2    : NATURAL := 16#40#;
    CONSTANT  Device_ID3    : NATURAL := 16#17#;
    CONSTANT  Unique_id_1   : NATURAL := 16#ABAB#;--this is 64bit ID number
    CONSTANT  Unique_id_2   : NATURAL := 16#00#;--this is 64bit ID number

    -- Declaration of signals that will hold the delayed values of ports
    SIGNAL SI_ipd          : std_ulogic := 'U';
    SIGNAL SO_ipd          : std_ulogic := 'U';
    SIGNAL SCK_ipd         : std_ulogic := 'U';
    SIGNAL CSNeg_ipd       : std_ulogic := 'U';
    SIGNAL WPNeg_ipd       : std_ulogic := 'U';
    SIGNAL HOLDNeg_ipd     : std_ulogic := 'U';
    SIGNAL HOLDNeg_pullup  : std_ulogic := 'U';
    SIGNAL WPNeg_pullup    : std_ulogic := 'U';

    -- internal delays
    SIGNAL PP_in           : std_ulogic := '0';
    SIGNAL PP_out          : std_ulogic := '0';
    SIGNAL BP1_in          : std_ulogic := '0';
    SIGNAL BP1_out         : std_ulogic := '0';
    SIGNAL BP2_in          : std_ulogic := '0';
    SIGNAL BP2_out         : std_ulogic := '0';
    SIGNAL SE_in           : std_ulogic := '0';
    SIGNAL SE_out          : std_ulogic := '0';
    SIGNAL BE1_in          : std_ulogic := '0';
    SIGNAL BE1_out         : std_ulogic := '0';
    SIGNAL BE2_in          : std_ulogic := '0';
    SIGNAL BE2_out         : std_ulogic := '0';
    SIGNAL CE_in           : std_ulogic := '0';
    SIGNAL CE_out          : std_ulogic := '0';
    SIGNAL WRR_in          : std_ulogic := '0';
    SIGNAL WRR_out         : std_ulogic := '0';
    SIGNAL ERSSUSP_in      : std_ulogic := '0';
    SIGNAL ERSSUSP_out     : std_ulogic := '0';
    SIGNAL ERSRES_in       : std_ulogic := '0';
    SIGNAL ERSRES_out      : std_ulogic := '0';
    SIGNAL PRGSUSP_in      : std_ulogic := '0';
    SIGNAL PRGSUSP_out     : std_ulogic := '0';
    SIGNAL PRGRES_in       : std_ulogic := '0';
    SIGNAL PRGRES_out      : std_ulogic := '0';
    SIGNAL PU_in           : std_ulogic := '0';
    SIGNAL PU_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 DP_in           : std_ulogic := '0';
    SIGNAL DP_out          : std_ulogic := '0';
    SIGNAL SUSP_FL_IN      : std_ulogic := '0';
    SIGNAL SUSP_FL_OUT     : std_ulogic := '0';

BEGIN

    ---------------------------------------------------------------------------
    -- Internal Delays
    ---------------------------------------------------------------------------
    -- Artificial VITAL primitives to incorporate internal delays
    -- Because a tdevice generics is used, there must be a VITAL_primitives
    -- assotiated with them
    PP        :VitalBuf(PP_out,      PP_in,      (tdevice_PP      ,UnitDelay));
    BP1       :VitalBuf(BP1_out,     BP1_in,     (tdevice_BP1     ,UnitDelay));
    BP2       :VitalBuf(BP2_out,     BP2_in,     (tdevice_BP2     ,UnitDelay));
    SE        :VitalBuf(SE_out,      SE_in,      (tdevice_SE      ,UnitDelay));
    BE1       :VitalBuf(BE1_out,     BE1_in,     (tdevice_BE1     ,UnitDelay));
    BE2       :VitalBuf(BE2_out,     BE2_in,     (tdevice_BE2     ,UnitDelay));
    WRR       :VitalBuf(WRR_out,     WRR_in,     (tdevice_WRR     ,UnitDelay));
    ERSSUSP   :VitalBuf(ERSSUSP_out, ERSSUSP_in, (tdevice_ERSSUSP ,UnitDelay));
    ERSRES    :VitalBuf(ERSRES_out,  ERSRES_in,  (tdevice_ERSRES  ,UnitDelay));
    PRGSUSP   :VitalBuf(PRGSUSP_out, PRGSUSP_in, (tdevice_PRGSUSP ,UnitDelay));
    PRGRES    :VitalBuf(PRGRES_out,  PRGRES_in,  (tdevice_PRGRES  ,UnitDelay));
    PU        :VitalBuf(PU_out,      PU_in,      (tdevice_PU      ,UnitDelay));
    RES1      :VitalBuf(RES1_out,    RES1_in,    (tdevice_RES1    ,UnitDelay));
    CE        :VitalBuf(CE_out,      CE_in,      (tdevice_CE      ,UnitDelay));
    DP        :VitalBuf(DP_out,      DP_in,      (tdevice_DP      ,UnitDelay));
    RES2      :VitalBuf(RES2_out,    RES2_in,    (tdevice_RES2    ,UnitDelay));
    SUSP_DLY  :VitalBuf(SUSP_FL_OUT, SUSP_FL_IN, (tdevice_SUSP_DLY,UnitDelay));

    ---------------------------------------------------------------------------
    -- Wire Delays
    ---------------------------------------------------------------------------
    WireDelay : BLOCK
    BEGIN

        w_1 : VitalWireDelay (SI_ipd,      SI,      tipd_SI);
        w_2 : VitalWireDelay (SO_ipd,      SO,      tipd_SO);
        w_3 : VitalWireDelay (SCK_ipd,     SCK,     tipd_SCK);
        w_4 : VitalWireDelay (CSNeg_ipd,   CSNeg,   tipd_CSNeg);
        w_6 : VitalWireDelay (WPNeg_ipd,   WPNeg,   tipd_WPNeg);
        w_7 : VitalWireDelay (HOLDNeg_ipd, HOLDNeg, tipd_HOLDNeg);

    END BLOCK;

    ---------------------------------------------------------------------------
    -- Main Behavior Block
    ---------------------------------------------------------------------------
    Behavior: BLOCK

        PORT (
            SIIn           : IN    std_ulogic := 'U';
            SIOut          : OUT   std_ulogic := 'U';
            SOIn           : IN    std_logic  := 'U';
            SOut           : OUT   std_logic  := 'U';
            SCK            : IN    std_ulogic := 'U';
            CSNeg          : IN    std_ulogic := 'U';
            HOLDNegIn      : IN    std_ulogic := 'U';
            HOLDNegOut     : OUT   std_ulogic := 'U';
            WPNegIn        : IN    std_ulogic := 'U';
            WPNegOut       : OUT   std_ulogic := 'U'
        );

        PORT MAP (
             SIIn       => SI_ipd,
             SIOut      => SI,
             SOIn       => SO_ipd,
             SOut       => SO,
             SCK        => SCK_ipd,
             CSNeg      => CSNeg_ipd,
             HOLDNegIn  => HOLDNeg_ipd,
             HOLDNegOut => HOLDNeg,
             WPNegIn    => WPNeg_ipd,
             WPNegOut   => WPNeg
        );

        -- State Machine : State_Type
        TYPE state_type IS (IDLE,
                            WRITE_SR,
                            PAGE_PG,
                            PG_SUSP,
                            SECTOR_ERS,
                            BULK_ERS,
                            ERS_SUSP,
                            ERS_SUSP_PG,
                            PG_SUSP_ERS,
                            DP_DOWN,
                            WRITE_SR_V
                            );

        -- Instruction Type
        TYPE instruction_type IS (  NONE,
                                    WREN           , -- 06h
                                    WRENV          , -- 50h
                                    WRDI           , -- 04h
                                    RDSR           , -- 05h
                                    RDSR2          , -- 35h
                                    WRR            , -- 01h
                                    READ           , -- 03h
                                    FAST_READ      , -- 0Bh
                                    FAST_DREAD     , -- 3Bh
                                    FAST_QREAD     , -- 6Bh
                                    FAST_DREAD_2   , -- BBh
                                    FAST_QREAD_4   , -- EBh
                                    W_QREAD        , -- E7h
                                    WOCT_QREAD     , -- E3h
                                    SET_BURST_WRAP , -- 77h
                                    CONT_RD_RST    , -- FFh or FFFFH
                                    PP             , -- 02h
                                    QPP            , -- 32h
                                    SE             , -- 20h
                                    BE_32          , -- 52h
                                    BE_64          , -- D8h
                                    CE             , -- C7h or 60h
                                    ERS_PG_SUSP    , -- 75h
                                    ERS_PG_RES     , -- 7Ah
                                    DP             , -- B9h
                                    RES_RD_ID      , -- ABh
                                    RDID           , -- 90h
                                    RDID_DUAL      , -- 92h
                                    RDID_QUAD      , -- 94h
                                    RD_UNIQ_ID     , -- 4Bh
                                    RDIDJ          , -- 9Fh
                                    RD_SFDP        , -- 5Ah
                                    ERS_SCREG      , -- 44h
                                    PG_SCREG       , -- 42h
                                    RD_SCREG         -- 48h
                                );

        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;
        -- SFDP Memory Array
        TYPE SFDPArray IS ARRAY (SFDP_LoAddr TO SFDP_HiAddr) OF INTEGER
                                                    RANGE -1 TO MaxData;
        -- Security Register Array
        TYPE SCREGArray IS ARRAY (SecReg_LoAddr TO SecReg_HiAddr) OF INTEGER
                                                    RANGE -1 TO MaxData;
        -----------------------------------------------------------------------
        --  memory declaration
        -----------------------------------------------------------------------
        -- Memory
        SHARED VARIABLE Mem           : MemArray   := (OTHERS => MaxData);
        -- Security Register 1
        SHARED VARIABLE Security_Reg1 : SCREGArray := (OTHERS => MaxData);
        -- Security Register 2
        SHARED VARIABLE Security_Reg2 : SCREGArray := (OTHERS => MaxData);
        -- Security Register 3
        SHARED VARIABLE Security_Reg3 : SCREGArray := (OTHERS => MaxData);
        --SFDP Array
        SHARED VARIABLE SFDP_array    : SFDPArray  := (OTHERS => 0);
        -- Programming Buffer
        SIGNAL WByte                  : WByteType  := (OTHERS => MaxData);

        -- states
        SIGNAL current_state         : state_type;
        SIGNAL next_state            : state_type;

        SIGNAL Instruct              : instruction_type;

        --zero delay signal
        SIGNAL SOut_zd               : std_logic := 'Z';
        SIGNAL SIOut_zd              : std_logic := 'Z';
        SIGNAL HOLDNegOut_zd         : std_logic := 'Z';
        SIGNAL WPNegOut_zd           : std_logic := 'Z';
        --HOLD delay on output data
        SIGNAL SOut_z                : std_logic := 'Z';
        SIGNAL SIOut_z               : std_logic := 'Z';
        -- powerup
        SIGNAL PoweredUp             : std_logic := '0';

        -----------------------------------------------------------------------
        -- Registers
        -----------------------------------------------------------------------
        -- Status register 1
        SHARED VARIABLE Status_reg1   : std_logic_vector(7 downto 0)
                                                := (others => '0');
        SIGNAL Status_reg1_in         : std_logic_vector(7 downto 0)
                                                := (others => '0');

        -- Status Register Protect Bit 0
        ALIAS SRP0      :std_logic IS Status_reg1(7);
        -- Sector/Block protect bit
        ALIAS SEC       :std_logic IS Status_reg1(6);
        -- Top Bottom Bit
        ALIAS TB        :std_logic IS Status_reg1(5);
        -- Status Register Block Protection Bits
        ALIAS BP2       :std_logic IS Status_reg1(4);
        ALIAS BP1       :std_logic IS Status_reg1(3);
        ALIAS BP0       :std_logic IS Status_reg1(2);
        -- Status Register Write Enable Latch Bit
        ALIAS WEL       :std_logic IS Status_reg1(1);
        -- Status Register Busy Bit
        ALIAS BUSY      :std_logic IS Status_reg1(0);

        -- Status register 2
        SHARED VARIABLE Status_reg2   : std_logic_vector(7 downto 0)
                                                := (others => '0');
        SIGNAL Status_reg2_in         : std_logic_vector(7 downto 0)
                                                := (others => '0');

        -- Suspend status bit
        ALIAS SUS       :std_logic IS Status_reg2(7);
        -- Complement protect bit
        ALIAS CMP       :std_logic IS Status_reg2(6);
        -- Security Register Lock bits
        ALIAS LB3       :std_logic IS Status_reg2(5);
        ALIAS LB2       :std_logic IS Status_reg2(4);
        ALIAS LB1       :std_logic IS Status_reg2(3);
        -- Quad enable bit
        ALIAS QE        :std_logic IS Status_reg2(1);
        -- Status register protect bit
        ALIAS SRP1      :std_logic IS Status_reg2(0);

        -- Sector is protect if Sec_Prot(Blk_4_Num) = '1'
        SHARED VARIABLE Sec_Prot  : std_logic_vector(Blk_4_Num downto 0) :=
                                                   (OTHERS => '0');

        --Command Register
        SIGNAL write              : std_logic := '0';
        SIGNAL read_out           : std_logic := '0';

        SIGNAL pg_screg_flag      : boolean := false;
        SIGNAL ers_screg_flag     : boolean := false;
        SIGNAL slow_read          : boolean := false;
        SIGNAL dual_read          : boolean := false;
        SIGNAL fast_rd            : boolean := true;
        SIGNAL quad_read          : boolean := false;
        SIGNAL read_id            : boolean := false;
        SIGNAL sr_read            : boolean := false;

        SHARED VARIABLE pp_quad   : boolean := false;
        SHARED VARIABLE hold_mode : boolean := false;
        SHARED VARIABLE res_flag  : boolean := false;
        SHARED VARIABLE wren_vlt_flag : boolean := false;

        --FSM control signals
        SIGNAL PDONE     : std_logic := '1';
        SIGNAL PSTART    : std_logic := '0';
        SIGNAL PGSUSP    : std_logic := '0';
        SIGNAL PGRES     : std_logic := '0';

        SIGNAL WDONE     : std_logic := '1';
        SIGNAL WSTART    : std_logic := '0';
        SIGNAL VLTSTART  : std_logic := '0';
        SIGNAL VLTDONE   : std_logic := '1';

        SIGNAL EDONE     : std_logic := '1';
        SIGNAL ESTART    : std_logic := '0';
        SIGNAL ESUSP     : std_logic := '0';
        SIGNAL ERES      : std_logic := '0';

        SHARED VARIABLE read_cnt  : NATURAL := 0;
        SHARED VARIABLE read_addr : NATURAL RANGE 0 TO AddrRANGE ;
        SHARED VARIABLE wrap_byte : std_logic_vector(7 downto 0);
        SIGNAL change_addr        : std_logic := '0';
        SIGNAL Address            : NATURAL RANGE 0 TO AddrRANGE := 0;

        SIGNAL change_prot_bits   : std_logic := '0';
        SHARED VARIABLE BP_bits   : std_logic_vector(2 downto 0) := "000";
        SHARED VARIABLE LB_bits   : std_logic_vector(2 downto 0) := "000";

        SIGNAL Byte_number        : NATURAL RANGE 0 TO 255    := 0;

        -- Sector and subsector addresses
        SIGNAL SA                   : NATURAL RANGE 0 TO Blk_4_Num := 0;
        SHARED VARIABLE sect        : NATURAL RANGE 0 TO Blk_4_Num;
        SHARED VARIABLE sect_tmp_pg : NATURAL RANGE 0 TO Blk_4_Num;
        SHARED VARIABLE sect_tmp_ers: NATURAL RANGE 0 TO Blk_4_Num;

        SHARED VARIABLE w_size      : NATURAL RANGE 0 TO 64;

        -- timing check violation
        SIGNAL Viol               : X01 := '0';

        PROCEDURE ADDRHILO_SEC64 (
            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 Blk_64_Num;
        BEGIN
            sector   := Addr/16#10000#;
            AddrLOW  := sector*16#10000#;
            AddrHIGH := sector*16#10000# + 16#0FFFF#;
        END ADDRHILO_SEC64;

        PROCEDURE ADDRHILO_SEC32 (
            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 Blk_32_Num;
        BEGIN
            sector   := Addr/16#8000#;
            AddrLOW  := sector*16#8000#;
            AddrHIGH := sector*16#8000# + 16#7FFF#;
        END ADDRHILO_SEC32;

        PROCEDURE ADDRHILO_SEC4 (
            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 Blk_4_Num;
        BEGIN
            sector   := Addr/16#1000#;
            AddrLOW  := sector*16#1000#;
            AddrHIGH := sector*16#1000# + 16#0FFF#;
        END ADDRHILO_SEC4;

        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 PageNum;
        BEGIN
            page     := Addr/16#100#;
            AddrLOW  := Page*16#100#;
            AddrHIGH := Page*16#100# + 16#FF#;
        END AddrHILO_PG;

--         PROCEDURE ADDRHILO_WRAP(
--             VARIABLE   AddrLOW_w  : INOUT NATURAL RANGE 0 to AddrRANGE;
--             VARIABLE   AddrHIGH_w : INOUT NATURAL RANGE 0 to AddrRANGE;
--             VARIABLE   Addr       : NATURAL;
--             VARIABLE   w_size     : NATURAL) IS
--             VARIABLE   sect_wrap  : NATURAL ;
--         BEGIN
--             sect_wrap  := Addr/w_size;
--             AddrLOW_w  := sect_wrap*w_size;
--             AddrHIGH_w := sect_wrap*w_size + (w_size - 1);
--         END ADDRHILO_WRAP;

    PROCEDURE ADDRHILO_WRAP(
        VARIABLE   AddrLOW  : INOUT NATURAL RANGE 0 to ADDRRange;
        VARIABLE   AddrHIGH : INOUT NATURAL RANGE 0 to ADDRRange;
        VARIABLE   Address  : NATURAL;
        VARIABLE   Wrap_size: NATURAL) IS
        VARIABLE   Addr_tmp : NATURAL;
        VARIABLE   Sect_wrap: NATURAL;
    BEGIN
        Addr_tmp  := Address;
        Sect_wrap := Addr_tmp/Wrap_size;

        AddrLOW := Sect_wrap*Wrap_size;
        AddrHIGH := Sect_wrap*Wrap_size + (Wrap_size - 1);
    END ADDRHILO_WRAP;

    BEGIN
    ---------------------------------------------------------------------------
    --Power Up time
    ---------------------------------------------------------------------------
    PoweredUp <= '1' AFTER tdevice_PU;

    ---------------------------------------------------------------------------
    -- VITAL Timing Checks Procedures
    ---------------------------------------------------------------------------
    VITALTimingCheck: PROCESS(SIIn,SOIn,SCK_ipd,CSNeg_ipd,HOLDNegIn,WPNegIn)

        -- Timing Check Variables
        -- Setup/Hold Checks variables
        VARIABLE Tviol_CSNeg_SCK         : X01 := '0';
        VARIABLE TD_CSNeg_SCK            : VitalTimingDataType;

        VARIABLE Tviol_SI_SCK            : X01 := '0';
        VARIABLE TD_SI_SCK               : VitalTimingDataType;

        VARIABLE Tviol_SOIn_SCK          : X01 := '0';
        VARIABLE TD_SOIn_SCK             : VitalTimingDataType;

        VARIABLE Tviol_HOLDNeg_SCK       : X01 := '0';
        VARIABLE TD_HOLDNeg_SCK          : VitalTimingDataType;

        VARIABLE Tviol_HOLDNegIn_SCK     : X01 := '0';
        VARIABLE TD_HOLDNegIn_SCK        : VitalTimingDataType;

        VARIABLE Tviol_WPNegIn_SCK       : X01 := '0';
        VARIABLE TD_WPNegIn_SCK          : VitalTimingDataType;

        VARIABLE Tviol_WPNeg_CSNeg_setup : X01 := '0';
        VARIABLE TD_WPNeg_CSNeg_setup    : VitalTimingDataType;

        VARIABLE Tviol_WPNeg_CSNeg_hold  : X01 := '0';
        VARIABLE TD_WPNeg_CSNeg_hold     : VitalTimingDataType;

        --Pulse Width and Period Check Variables
        VARIABLE Pviol_SCK_slow    : X01 := '0';
        VARIABLE PD_SCK_slow       : VitalPeriodDataType:= VitalPeriodDataInit;

        VARIABLE Pviol_SCK_fast    : X01 := '0';
        VARIABLE PD_SCK_fast       : VitalPeriodDataType:= VitalPeriodDataInit;

        VARIABLE Pviol_CSNeg_read  : X01 := '0';
        VARIABLE PD_CSNeg_read     : VitalPeriodDataType:= VitalPeriodDataInit;

        VARIABLE Pviol_CSNeg_pgers : X01 := '0';
        VARIABLE PD_CSNeg_pgers    : VitalPeriodDataType:= VitalPeriodDataInit;

        VARIABLE Pviol_SCK_slow_p  : X01 := '0';
        VARIABLE PD_SCK_slow_p     : VitalPeriodDataType:= VitalPeriodDataInit;

        VARIABLE Pviol_SCK_fast_p  : X01 := '0';
        VARIABLE PD_SCK_fast_p     : VitalPeriodDataType:= VitalPeriodDataInit;

        VARIABLE Violation         : X01 := '0';

        BEGIN
    ---------------------------------------------------------------------------
    -- Timing Check Section
    ---------------------------------------------------------------------------
        IF (TimingChecksOn) THEN

        -- 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_CSNeg_SCK,
            Violation       => Tviol_CSNeg_SCK
        );
        -- Setup/Hold Check between SI and SCK /
        VitalSetupHoldCheck (
            TestSignal      => SIIn,
            TestSignalName  => "SI",
            RefSignal       => SCK_ipd,
            RefSignalName   => "SCK",
            SetupHigh       => tsetup_SI_SCK_normal_noedge_posedge,
            SetupLow        => tsetup_SI_SCK_normal_noedge_posedge,
            HoldHigh        => thold_SI_SCK_normal_noedge_posedge,
            HoldLow         => thold_SI_SCK_normal_noedge_posedge,
            CheckEnabled    => SIOut_z /= SIIn,
            RefTransition   => '/',
            HeaderMsg       => InstancePath & PartID,
            TimingData      => TD_SI_SCK,
            Violation       => Tviol_SI_SCK
        );

        VitalSetupHoldCheck (
            TestSignal      => SOIn,
            TestSignalName  => "SO",
            RefSignal       => SCK_ipd,
            RefSignalName   => "SCK",
            SetupHigh       => tsetup_SI_SCK_normal_noedge_posedge,
            SetupLow        => tsetup_SI_SCK_normal_noedge_posedge,
            HoldHigh        => thold_SI_SCK_normal_noedge_posedge,
            HoldLow         => thold_SI_SCK_normal_noedge_posedge,
            CheckEnabled    => SOut_z /= SOIn,
            RefTransition   => '/',
            HeaderMsg       => InstancePath & PartID,
            TimingData      => TD_SOIn_SCK,
            Violation       => Tviol_SOIn_SCK
        );

        VitalSetupHoldCheck (
            TestSignal      => HOLDNegIn,
            TestSignalName  => "HOLD#",
            RefSignal       => SCK_ipd,
            RefSignalName   => "SCK",
            SetupHigh       => tsetup_SI_SCK_normal_noedge_posedge,
            SetupLow        => tsetup_SI_SCK_normal_noedge_posedge,
            HoldHigh        => thold_SI_SCK_normal_noedge_posedge,
            HoldLow         => thold_SI_SCK_normal_noedge_posedge,
            CheckEnabled    => HOLDNegOut_zd /= HOLDNegIn,
            RefTransition   => '/',
            HeaderMsg       => InstancePath & PartID,
            TimingData      => TD_HOLDNegIn_SCK,
            Violation       => Tviol_HOLDNegIn_SCK
        );

        VitalSetupHoldCheck (
            TestSignal      => WPNegIn,
            TestSignalName  => "WP#",
            RefSignal       => SCK_ipd,
            RefSignalName   => "SCK",
            SetupHigh       => tsetup_SI_SCK_normal_noedge_posedge,
            SetupLow        => tsetup_SI_SCK_normal_noedge_posedge,
            HoldHigh        => thold_SI_SCK_normal_noedge_posedge,
            HoldLow         => thold_SI_SCK_normal_noedge_posedge,
            CheckEnabled    => WPNegOut_zd /= WPNegIn,
            RefTransition   => '/',
            HeaderMsg       => InstancePath & PartID,
            TimingData      => TD_WPNegIn_SCK,
            Violation       => Tviol_WPNegIn_SCK
        );

        -- Setup/Hold Check between HOLD# and SCK /
        VitalSetupHoldCheck (
            TestSignal      => HOLDNegIn,
            TestSignalName  => "HOLD#",
            RefSignal       => SCK_ipd,
            RefSignalName   => "SCK",
            SetupHigh       => tsetup_HOLDNeg_SCK,
            SetupLow        => tsetup_HOLDNeg_SCK,
            HoldHigh        => thold_HOLDNeg_SCK,
            HoldLow         => thold_HOLDNeg_SCK,
            CheckEnabled    => QE = '0',
            RefTransition   => '/',
            HeaderMsg       => InstancePath & PartID,
            TimingData      => TD_HOLDNeg_SCK,
            Violation       => Tviol_HOLDNeg_SCK
        );

        -- Setup Check between WP# and CS# \
        VitalSetupHoldCheck (
            TestSignal      => WPNegIn,
            TestSignalName  => "WP#",
            RefSignal       => CSNeg_ipd,
            RefSignalName   => "CS#",
            SetupHigh       => tsetup_WPNeg_CSNeg,
            CheckEnabled    => QE = '0',
            RefTransition   => '\',
            HeaderMsg       => InstancePath & PartID,
            TimingData      => TD_WPNeg_CSNeg_setup,
            Violation       => Tviol_WPNeg_CSNeg_setup
        );

        -- Hold Check between WP# and CS# /
        VitalSetupHoldCheck (
            TestSignal      => WPNegIn,
            TestSignalName  => "WP#",
            RefSignal       => CSNeg_ipd,
            RefSignalName   => "CS#",
            HoldHigh        => thold_WPNeg_CSNeg,
            CheckEnabled    => QE = '0',
            RefTransition   => '/',
            HeaderMsg       => InstancePath & PartID,
            TimingData      => TD_WPNeg_CSNeg_hold,
            Violation       => Tviol_WPNeg_CSNeg_hold
        );

        --Pulse Width and Period Check Variables
        VitalPeriodPulseCheck (
            TestSignal      =>  SCK_ipd,
            TestSignalName  =>  "SCK",
            PulseWidthLow   =>  tpw_SCK_slow_negedge,
            PulseWidthHigh  =>  tpw_SCK_slow_posedge,
            PeriodData      =>  PD_SCK_slow,
            XOn             =>  XOn,
            MsgOn           =>  MsgOn,
            Violation       =>  Pviol_SCK_slow,
            HeaderMsg       =>  InstancePath & PartID,
            CheckEnabled    =>  slow_read
        );

        VitalPeriodPulseCheck (
            TestSignal      =>  SCK_ipd,
            TestSignalName  =>  "SCK",
            PulseWidthLow   =>  tpw_SCK_fast_negedge,
            PulseWidthHigh  =>  tpw_SCK_fast_posedge,
            PeriodData      =>  PD_SCK_fast,
            XOn             =>  XOn,
            MsgOn           =>  MsgOn,
            Violation       =>  Pviol_SCK_fast,
            HeaderMsg       =>  InstancePath & PartID,
            CheckEnabled    =>  fast_rd
        );

        -- Pulse Width Check CS# for READ, serial mode
        VitalPeriodPulseCheck (
            TestSignal      =>  CSNeg_ipd,
            TestSignalName  =>  "CS#",
            PulseWidthHigh  =>  tpw_CSNeg_read_posedge,
            PeriodData      =>  PD_CSNeg_read,
            XOn             =>  XOn,
            MsgOn           =>  MsgOn,
            Violation       =>  Pviol_CSNeg_read,
            HeaderMsg       =>  InstancePath & PartID,
            CheckEnabled    =>  slow_read OR fast_rd OR dual_read OR
                                quad_read
        );

        -- Pulse Width Check CS# for Program/Erase, serial mode
        VitalPeriodPulseCheck (
            TestSignal      =>  CSNeg_ipd,
            TestSignalName  =>  "CS#",
            PulseWidthHigh  =>  tpw_CSNeg_pger_posedge,
            PeriodData      =>  PD_CSNeg_pgers,
            XOn             =>  XOn,
            MsgOn           =>  MsgOn,
            Violation       =>  Pviol_CSNeg_pgers,
            HeaderMsg       =>  InstancePath & PartID,
            CheckEnabled    =>  true);

        -- Period Check SCK for READ, serial mode
        VitalPeriodPulseCheck (
            TestSignal      =>  SCK_ipd,
            TestSignalName  =>  "SCK",
            Period          =>  tperiod_SCK_slow,
            PeriodData      =>  PD_SCK_slow_p,
            XOn             =>  XOn,
            MsgOn           =>  MsgOn,
            Violation       =>  Pviol_SCK_slow_p,
            HeaderMsg       =>  InstancePath & PartID,
            CheckEnabled    =>  slow_read
        );

        VitalPeriodPulseCheck (
            TestSignal      =>  SCK_ipd,
            TestSignalName  =>  "SCK",
            Period          =>  tperiod_SCK_fast,
            PeriodData      =>  PD_SCK_fast_p,
            XOn             =>  XOn,
            MsgOn           =>  MsgOn,
            Violation       =>  Pviol_SCK_fast_p,
            HeaderMsg       =>  InstancePath & PartID,
            CheckEnabled    =>  fast_rd OR dual_read OR quad_read
        );

        Violation :=    Tviol_CSNeg_SCK OR
                        Tviol_SI_SCK    OR
                        Tviol_HOLDNeg_SCK OR
                        Tviol_WPNeg_CSNeg_setup OR
                        Tviol_WPNeg_CSNeg_hold OR
                        Tviol_HOLDNegIn_SCK OR
                        Tviol_WPNegIn_SCK OR
                        Tviol_SOIn_SCK OR
                        Pviol_SCK_slow OR
                        Pviol_SCK_fast OR
                        Pviol_CSNeg_read OR
                        Pviol_CSNeg_pgers OR
                        Pviol_SCK_slow_p OR
                        Pviol_SCK_fast_p;

            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
            IF next_state'EVENT THEN
                current_state <= next_state;
            END IF;
        END IF;
    END PROCESS StateTransition;

    ---------------------------------------------------------------------------
    --  Write cycle decode
    ---------------------------------------------------------------------------
    BusCycleDecode : PROCESS(SCK_ipd, CSNeg_ipd)

        TYPE bus_cycle_type IS (STAND_BY,
                                OPCODE_BYTE,
                                ADDRESS_BYTES,
                                DUMMY_BYTES,
                                MODE_BYTE,
                                DATA_BYTES
                                );

        TYPE quad_data_type IS ARRAY (0 TO 511) OF INTEGER RANGE 0 TO 15;

        VARIABLE bus_cycle_state    : bus_cycle_type;

        VARIABLE opcode_cnt : NATURAL  := 0;
        VARIABLE addr_cnt   : NATURAL  := 0;
        VARIABLE mode_cnt   : NATURAL  := 0;
        VARIABLE wrap_cnt   : NATURAL  := 0;
        VARIABLE dummy_cnt  : NATURAL  := 0;
        VARIABLE data_cnt   : NATURAL  := 0;
        VARIABLE bit_cnt    : NATURAL  := 0;

        VARIABLE Data_in            : std_logic_vector(2047 downto 0)
                                                    := (others => '0');
        VARIABLE opcode             : std_logic_vector(7 downto 0);
        VARIABLE opcode_in          : std_logic_vector(7 downto 0);
        VARIABLE opcode_double      : std_logic_vector(15 downto 0);
        VARIABLE opcode_double_in   : std_logic_vector(15 downto 0);
        VARIABLE addr_bytes         : std_logic_vector(23 downto 0);
        VARIABLE Address_in         : std_logic_vector(23 downto 0);
        VARIABLE mode_bits          : std_logic_vector(7 downto 0);
        VARIABLE mode_in            : std_logic_vector(7 downto 0);
--         VARIABLE wrap_byte          : std_logic_vector(7 downto 0);
        VARIABLE wrap_in            : std_logic_vector(7 downto 0);
        VARIABLE quad_data_in       : quad_data_type;
        VARIABLE quad_nybble        : std_logic_vector(3 downto 0);
        VARIABLE Quad_slv           : std_logic_vector(3 downto 0);
        VARIABLE Byte_slv           : std_logic_vector(7 downto 0);

    BEGIN

        IF falling_edge(CSNeg_ipd) THEN
            IF (bus_cycle_state = STAND_BY) THEN
                bus_cycle_state := OPCODE_BYTE;
                Instruct <= NONE;
                write    <= '1';
                opcode_cnt := 0;
                addr_cnt   := 0;
                data_cnt   := 0;
                mode_cnt   := 0;
                wrap_cnt   := 0;
                dummy_cnt  := 0;
            ELSIF (bus_cycle_state = DATA_BYTES AND
                            mode_bits(5 DOWNTO 4) = "10") THEN
                bus_cycle_state := ADDRESS_BYTES;
                dummy_cnt  := 0;
                opcode_cnt := 0;
            END IF;
        END IF;

        IF rising_edge(SCK_ipd) AND (PoweredUp = '1') THEN
            IF (CSNeg_ipd = '0') THEN
                CASE (bus_cycle_state) IS
                    WHEN OPCODE_BYTE =>
                        IF (HOLDNeg_pullup = '1' AND QE='0') OR QE='1' THEN
                            opcode_in(opcode_cnt) := SIIn;
                            opcode_cnt := opcode_cnt + 1;
                            IF opcode_cnt = BYTE THEN
                                FOR I IN 7 DOWNTO 0 LOOP
                                    opcode(i) := opcode_in(7-i);
                                END LOOP;

                                CASE opcode IS
                                WHEN "00000110" => -- 06H
                                    Instruct <= WREN;
                                    bus_cycle_state := DATA_BYTES;
                                WHEN "01010000" =>
                                    Instruct <= WRENV;
                                    bus_cycle_state := DATA_BYTES;
                                WHEN "00000100"  => --04h
                                    Instruct <= WRDI;
                                    bus_cycle_state := DATA_BYTES;
                                WHEN "00000101" => -- 05h
                                    Instruct <= RDSR;
                                    bus_cycle_state := DATA_BYTES;
                                WHEN "00110101" => -- 35h
                                    Instruct <= RDSR2;
                                    bus_cycle_state := DATA_BYTES;
                                WHEN "00000001" => -- 01h
                                    Instruct <= WRR;
                                    bus_cycle_state := DATA_BYTES;
                                WHEN "00000011" => -- 03h
                                    Instruct <= READ;
                                    bus_cycle_state := ADDRESS_BYTES;
                                WHEN "00001011" => -- 0Bh
                                    Instruct <= FAST_READ;
                                    bus_cycle_state := ADDRESS_BYTES;
                                WHEN "00111011" => -- 3Bh
                                    Instruct <= FAST_DREAD;
                                    bus_cycle_state := ADDRESS_BYTES;
                                WHEN "01101011" => -- 6Bh
                                    Instruct <= FAST_QREAD;
                                    IF (QE = '1') THEN
                                        bus_cycle_state := ADDRESS_BYTES;
                                    ELSE
                                        bus_cycle_state := STAND_BY;
                                    END IF;
                                WHEN "10111011" => -- BBh
                                    Instruct <= FAST_DREAD_2;
                                    bus_cycle_state := ADDRESS_BYTES;
                                WHEN "11101011" => -- EBh
                                    Instruct <= FAST_QREAD_4;
                                    IF (QE = '1') THEN
                                        bus_cycle_state := ADDRESS_BYTES;
                                    ELSE
                                        bus_cycle_state := STAND_BY;
                                    END IF;
                                WHEN "11100111" => --E7h
                                    Instruct <= W_QREAD;
                                    IF (QE = '1') THEN
                                        bus_cycle_state := ADDRESS_BYTES;
                                    ELSE
                                        bus_cycle_state := STAND_BY;
                                    END IF;
                                WHEN "11100011" => -- E3h
                                    Instruct <= WOCT_QREAD;
                                    IF (QE = '1') THEN
                                        bus_cycle_state := ADDRESS_BYTES;
                                    ELSE
                                        bus_cycle_state := STAND_BY;
                                    END IF;
                                WHEN "01110111" => -- 77h
                                    Instruct <= SET_BURST_WRAP;
                                    IF (QE = '1') THEN
                                        bus_cycle_state := DUMMY_BYTES;
                                    ELSE
                                        bus_cycle_state := STAND_BY;
                                    END IF;
                                WHEN "11111111" => -- FFh
                                    Instruct <= CONT_RD_RST;
                                    bus_cycle_state := MODE_BYTE;
                                WHEN "00000010" => -- 02H
                                    Instruct <= PP;
                                    bus_cycle_state := ADDRESS_BYTES;
                                WHEN "00110010" => -- 32h
                                    Instruct <= QPP;
                                    IF (QE = '1') THEN
                                        bus_cycle_state := ADDRESS_BYTES;
                                    ELSE
                                        bus_cycle_state := STAND_BY;
                                    END IF;
                                WHEN "00100000" => -- 20h
                                    Instruct <= SE;
                                    bus_cycle_state := ADDRESS_BYTES;
                                WHEN "01010010" => -- 52h
                                    Instruct <= BE_32;
                                    bus_cycle_state := ADDRESS_BYTES;
                                WHEN "11011000" => -- D8h
                                    Instruct <= BE_64;
                                    bus_cycle_state := ADDRESS_BYTES;
                                WHEN "11000111" | "01100000" => -- C7 or 60h
                                    Instruct <= CE;
                                    bus_cycle_state := DATA_BYTES;
                                WHEN "01110101" =>  -- 75h
                                    Instruct <= ERS_PG_SUSP;
                                    bus_cycle_state := DATA_BYTES;
                                WHEN "01111010" => -- 7Ah
                                    Instruct <= ERS_PG_RES;
                                    bus_cycle_state := DATA_BYTES;
                                WHEN "10111001" => -- B9h
                                    Instruct <= DP;
                                    bus_cycle_state := DATA_BYTES;
                                WHEN "10101011" => -- ABh
                                    Instruct <= RES_RD_ID;
                                    bus_cycle_state := DUMMY_BYTES;
                                WHEN "10010000" => -- 90h
                                    Instruct <= RDID;
                                    bus_cycle_state := ADDRESS_BYTES;
                                WHEN "10010010" => -- 92h
                                    Instruct <= RDID_DUAL;
                                    bus_cycle_state := ADDRESS_BYTES;
                                WHEN "10010100" => -- 94h
                                    Instruct <= RDID_QUAD;
                                    IF (QE = '1') THEN
                                        bus_cycle_state := ADDRESS_BYTES;
                                    ELSE
                                        bus_cycle_state := STAND_BY;
                                    END IF;
                                WHEN "01001011" => -- 4Bh
                                    Instruct <= RD_UNIQ_ID;
                                    bus_cycle_state := DUMMY_BYTES;
                                WHEN "10011111" => -- 9Fh
                                    Instruct <= RDIDJ;
                                    bus_cycle_state := DATA_BYTES;
                                WHEN "01011010" => -- 5Ah
                                    Instruct <= RD_SFDP;
                                    bus_cycle_state := ADDRESS_BYTES;
                                WHEN "01000100" => -- 44h
                                    Instruct <= ERS_SCREG;
                                    bus_cycle_state := ADDRESS_BYTES;
                                WHEN "01000010" => -- 42h
                                    Instruct <= PG_SCREG;
                                    bus_cycle_state := ADDRESS_BYTES;
                                WHEN "01001000" => -- 48h
                                    Instruct <= RD_SCREG;
                                    bus_cycle_state := ADDRESS_BYTES;

                                WHEN OTHERS =>
                                    NULL;

                                END CASE;
                            END IF;
                        ELSE
                            REPORT "Device is in HOLD mode, opcode"
                            SEVERITY NOTE;
                        END IF;

                    WHEN ADDRESS_BYTES =>
                        IF (HOLDNeg_pullup = '1' AND QE='0') OR QE='1' THEN
                            IF (Instruct = READ OR Instruct = FAST_READ OR
                                Instruct = FAST_DREAD OR Instruct = RDID OR
                                Instruct = SE OR Instruct = PP OR
                                Instruct = RD_SCREG OR Instruct = PG_SCREG OR
                                Instruct = RD_SFDP OR Instruct = BE_32 OR
                                Instruct = BE_64 OR Instruct = ERS_SCREG OR
                                ((Instruct = QPP OR Instruct = FAST_QREAD)
                                AND QE = '1')) THEN
                                Address_in(addr_cnt) := SIIn;
                                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 = PP OR Instruct = QPP
                                    OR Instruct = READ OR Instruct = SE
                                    OR Instruct = BE_32 OR Instruct = BE_64
                                    OR Instruct = RDID OR Instruct = PG_SCREG
                                    OR Instruct = ERS_SCREG) THEN
                                        bus_cycle_state := DATA_BYTES;
                                    ELSE
                                        bus_cycle_state := DUMMY_BYTES;
                                    END IF;
                                END IF;
                            ELSIF (Instruct = RDID_DUAL OR
                                   Instruct = FAST_DREAD_2) THEN
                                IF (SOIn /= 'Z') THEN
                                    Address_in(2*addr_cnt)    := SOIn;
                                    Address_in(2*addr_cnt + 1):= SIIn;
                                    read_cnt := 0;
                                    addr_cnt := addr_cnt + 1;
                                    IF (addr_cnt = (3*BYTE)/2) THEN
                                        addr_cnt := 0;
                                        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;
                                        bus_cycle_state := MODE_BYTE;
                                    END IF;
                                ELSIF (mode_bits(5 downto 4) = "10") THEN
                                    opcode_double_in(opcode_cnt) := SIIn;
                                    opcode_cnt := opcode_cnt + 1;
                                    IF (opcode_cnt = 2*BYTE) THEN
                                        FOR I IN 15 DOWNTO 0 LOOP
                                            opcode_double(i) :=
                                                opcode_double_in(15-i);
                                        END LOOP;
                                        IF (opcode_double="1111111111111111") THEN
                                            Instruct <= CONT_RD_RST;
                                            bus_cycle_state := MODE_BYTE;
                                        END IF;
                                    END IF;
                                END IF;
                            ELSIF (QE = '1' AND (Instruct = FAST_QREAD_4 OR
                            Instruct = W_QREAD OR Instruct = WOCT_QREAD OR
                            Instruct = RDID_QUAD)) THEN
                                IF (SOIn /= 'Z') THEN
                                    Address_in(4*addr_cnt)   := HOLDNegIn;
                                    Address_in(4*addr_cnt+1) := WPNegIn;
                                    Address_in(4*addr_cnt+2) := SOIn;
                                    Address_in(4*addr_cnt+3) := SIIn;
                                    read_cnt := 0;
                                    addr_cnt := addr_cnt + 1;
                                    IF (addr_cnt = (3*BYTE)/4) THEN
                                        addr_cnt := 0;
                                        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;
                                        bus_cycle_state := MODE_BYTE;
                                    END IF;
                                ELSIF (mode_bits(5 downto 4) = "10") THEN
                                    opcode_in(opcode_cnt) := SIIn;
                                    opcode_cnt := opcode_cnt + 1;
                                    IF (opcode_cnt = BYTE) THEN
                                        FOR I IN 7 DOWNTO 0 LOOP
                                            opcode(i) :=
                                                opcode_in(7-i);
                                        END LOOP;
                                        IF (opcode = "11111111") THEN
                                            Instruct <= CONT_RD_RST;
                                            bus_cycle_state := MODE_BYTE;
                                        END IF;
                                    END IF;
                                END IF;
                            END IF;
                        ELSE
                            REPORT "Device is in HOLD mode, addr"
                            SEVERITY NOTE;
                        END IF;

                    WHEN MODE_BYTE =>
                        IF (QE = '1' OR (HOLDNeg_pullup = '1' AND QE = '0')) THEN
                            IF (Instruct = SET_BURST_WRAP AND QE = '1') THEN
                                wrap_in(4*wrap_cnt)   := HOLDNegIn;
                                wrap_in(4*wrap_cnt+1) := WPNegIn;
                                wrap_in(4*wrap_cnt+2) := SOIn;
                                wrap_in(4*wrap_cnt+3) := SIIn;
                                wrap_cnt := wrap_cnt + 1;
                                IF (wrap_cnt = BYTE/4) THEN
                                    wrap_cnt := 0;
                                    FOR I IN 7 DOWNTO 0 LOOP
                                        wrap_byte(i) := wrap_in(7-i);
                                    END LOOP;
                                    bus_cycle_state := DATA_BYTES;
                                END IF;
                                CASE (wrap_byte(6 DOWNTO 5)) IS
                                    WHEN "00" =>
                                        w_size := 8;
                                    WHEN "01" =>
                                        w_size := 16;
                                    WHEN "10" =>
                                        w_size := 32;
                                    WHEN "11" =>
                                        w_size := 64;
                                    WHEN OTHERS =>
                                        NULL;
                                END CASE;
                            ELSIF ((Instruct = FAST_QREAD_4 OR
                            Instruct = WOCT_QREAD OR Instruct = W_QREAD OR
                            Instruct = RDID_QUAD ) AND QE = '1') THEN
                                mode_in(4*mode_cnt)   := HOLDNegIn;
                                mode_in(4*mode_cnt+1) := WPNegIn;
                                mode_in(4*mode_cnt+2) := SOIn;
                                mode_in(4*mode_cnt+3) := SIIn;
                                mode_cnt := mode_cnt + 1;
                                IF (mode_cnt = BYTE/4) THEN
                                    mode_cnt := 0;
                                    FOR I IN 7 DOWNTO 0 LOOP
                                        mode_bits(i) := mode_in(7-i);
                                    END LOOP;
                                    IF (Instruct = WOCT_QREAD) THEN
                                        bus_cycle_state := DATA_BYTES;
                                    ELSE
                                        bus_cycle_state := DUMMY_BYTES;
                                    END IF;
                                END IF;
                            ELSIF (Instruct = RDID_DUAL OR
                                     Instruct = FAST_DREAD_2) THEN
                                mode_in(2*mode_cnt)   := SOIn;
                                mode_in(2*mode_cnt+1) := SIIn;
                                mode_cnt := mode_cnt + 1;
                                IF (mode_cnt = BYTE/2) THEN
                                    mode_cnt := 0;
                                    FOR I IN 7 DOWNTO 0 LOOP
                                        mode_bits(i) := mode_in(7-i);
                                    END LOOP;
                                    bus_cycle_state := DATA_BYTES;
                                END IF;
                            END IF;
                        ELSE
                            REPORT "Device is in HOLD mode, mode"
                            SEVERITY NOTE;
                        END IF;

                    WHEN DUMMY_BYTES =>
                        IF (QE = '1' OR (HOLDNeg_pullup = '1' AND QE = '0')) THEN
                            IF ((Instruct = FAST_QREAD_4 OR
                                Instruct = RDID_QUAD) AND QE = '1') THEN
                                dummy_cnt := dummy_cnt + 1;
                                IF (dummy_cnt = BYTE/2) THEN
                                    bus_cycle_state := DATA_BYTES;
                                END IF;
                            ELSIF (Instruct = W_QREAD AND QE = '1') THEN
                                dummy_cnt := dummy_cnt + 1;
                                IF (dummy_cnt = BYTE/4) THEN
                                    bus_cycle_state := DATA_BYTES;
                                END IF;
                            ELSIF (Instruct = SET_BURST_WRAP AND QE = '1') THEN
                                dummy_cnt := dummy_cnt + 1;
                                IF (dummy_cnt = 3*BYTE/4) THEN
                                    bus_cycle_state := MODE_BYTE;
                                END IF;
                            ELSIF (Instruct = FAST_QREAD AND QE = '1') THEN
                                dummy_cnt := dummy_cnt + 1;
                                IF (dummy_cnt = BYTE) THEN
                                    bus_cycle_state := DATA_BYTES;
                                END IF;
                            ELSIF (Instruct=FAST_READ  OR Instruct=RD_SFDP
                            OR Instruct = FAST_DREAD OR Instruct=RD_SCREG) THEN
                                dummy_cnt := dummy_cnt + 1;
                                IF (dummy_cnt = BYTE) THEN
                                    bus_cycle_state := DATA_BYTES;
                                END IF;
                            ELSIF (Instruct = RD_UNIQ_ID) THEN
                                dummy_cnt := dummy_cnt + 1;
                                IF (dummy_cnt = 4*BYTE) THEN
                                    bus_cycle_state := DATA_BYTES;
                                END IF;
                            ELSE -- for RES_RD_ID
                                dummy_cnt := dummy_cnt + 1;
                                IF (dummy_cnt = 3*BYTE) THEN
                                    bus_cycle_state := DATA_BYTES;
                                END IF;
                            END IF;
                        ELSE
                            REPORT "Device is in HOLD mode, dummy"
                            SEVERITY NOTE;
                        END IF; -- end of DUMMY_BYTES

                    WHEN DATA_BYTES =>
                        IF (Instruct = PP OR Instruct = WRR OR
                            Instruct = PG_SCREG) THEN
                            IF ((HOLDNeg_pullup = '1' AND QE='0') OR QE='1') THEN
                                IF (data_cnt > 2047) THEN
                                --In case of serial mode and 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) := SIIn;
                                    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) := SIIn;
                                    data_cnt := data_cnt + 1;
                                    bit_cnt := 0;
                                END IF;
                            ELSE
                                REPORT "Device is in HOLD mode, data"
                                SEVERITY NOTE;
                            END IF;
                        ELSIF (Instruct = QPP AND QE ='1') THEN
                            pp_quad := TRUE;
                            quad_nybble := HOLDNegIn & WPNegIn & SOIn & SIIn;
                            IF (data_cnt > 511) THEN
                            --In case of quad mode and QPP,IF more than
                            -- 256 bytes are sent to the device
                                FOR I IN 0 TO 510 LOOP
                                    quad_data_in(i) := quad_data_in(i+1);
                                END LOOP;
                                quad_data_in(511) := to_nat(quad_nybble);
                                data_cnt := data_cnt +1;
                            ELSE
                                IF (quad_nybble /= "ZZZZ") THEN
                                    quad_data_in(data_cnt) :=
                                                to_nat(quad_nybble);
                                END IF;
                                data_cnt := data_cnt +1;
                            END IF;
                        END IF;

                    WHEN OTHERS => NULL;
                END CASE;
            END IF;
        END IF;

        IF falling_edge(SCK_ipd) AND (bus_cycle_state = DATA_BYTES AND
                                                        CSNeg_ipd ='0') THEN
            IF (((Instruct = RDSR       OR Instruct = RDSR2        OR
                Instruct = FAST_READ    OR Instruct = FAST_DREAD   OR
                Instruct = FAST_DREAD_2 OR Instruct = RES_RD_ID    OR
                Instruct = RDID         OR Instruct = RDID_DUAL    OR
                Instruct = RD_UNIQ_ID   OR Instruct = RDIDJ        OR
                Instruct = RD_SFDP      OR Instruct = RD_SCREG     OR
                Instruct = READ) AND ((HOLDNeg_pullup ='1' AND QE='0') OR QE='1'))
                OR ((Instruct = FAST_QREAD OR Instruct = FAST_QREAD_4 OR
                Instruct = W_QREAD OR Instruct = RDID_QUAD OR
                Instruct = WOCT_QREAD) AND QE='1')) THEN
                read_out <= '1', '0' AFTER 1 ns;
            END IF;
        END IF;

        IF rising_edge(CSNeg_ipd) THEN
            IF (bus_cycle_state=MODE_BYTE AND Instruct = CONT_RD_RST) THEN
                mode_bits(5 downto 4) := "11";
                mode_bits(7 downto 6) := "00";
                mode_bits(3 downto 0) := "0000";
                bus_cycle_state := STAND_BY;
            ELSIF (bus_cycle_state=DATA_BYTES AND
                    NOT (mode_bits(5 downto 4)="10")) THEN
                bus_cycle_state := STAND_BY;
                CASE (Instruct) IS
                    WHEN WREN | WRDI | SET_BURST_WRAP | SE | BE_32 | BE_64 |
                           CE | ERS_PG_RES | DP | ERS_SCREG =>

                        IF (data_cnt = 0) THEN
                            write <= '0';
                        END IF;
                    WHEN WRENV =>
                        write <= '0';
                        wren_vlt_flag := TRUE;

                    WHEN RES_RD_ID =>
                        write <= '0';
                        res_flag := TRUE;

                    WHEN WRR =>
                        IF (data_cnt = 8) THEN
                        --If CS# is driven high after eight
                        --cycle,only the Status Register is
                        --written to.
                            write <= '0';
                            FOR i IN 0 TO 7 LOOP
                                Status_reg1_in(i) <= Data_in(7-i);
                            END LOOP;
                        ELSIF (data_cnt = 16) THEN
                        --After the 16th cycle both the
                        --Status and Configuration Registers
                        --are written to.
                            write <= '0';
                            FOR i IN 0 TO 7 LOOP
                                Status_reg1_in(i) <= Data_in(7-i);
                            END LOOP;

                            FOR j IN 0 TO 7 LOOP
                                Status_reg2_in(j) <= Data_in(15-j);
                            END LOOP;
--                             FOR I IN 0 TO 15 LOOP
--                                 Status_reg1_in(i) <= Data_in(7-i);
--                                 Status_reg2_in(i) <= Data_in(15-i);
--                             END LOOP;
                        END IF;

                    WHEN PP | PG_SCREG =>
                        IF (data_cnt > 0) THEN
                            IF ((data_cnt mod 8) = 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;
                        END IF;

                    WHEN QPP =>
                        IF (data_cnt >0) THEN
                            IF ((data_cnt mod 2) = 0) THEN
                                write <= '0';
                                FOR I IN 0 TO 255 LOOP
                                    FOR J IN 1 DOWNTO 0 LOOP
                                        Quad_slv :=
                                        to_slv(quad_data_in((i*2) +
                                            (1-j)),4);

                                        Byte_slv(4*j+3 DOWNTO 4*j) :=
                                            Quad_slv;
                                    END LOOP;
                                    WByte(i) <= to_nat(Byte_slv);
                                END LOOP;

                                IF (data_cnt > 256*BYTE/4) THEN
                                    Byte_number <= 255;
                                ELSE
                                    Byte_number <= ((data_cnt/2) - 1);
                                END IF;
                            END IF;
                        END IF;

                    WHEN others =>
                        null;

                END CASE;

            ELSIF (bus_cycle_state=DATA_BYTES AND
                            (mode_bits(5 DOWNTO 4)="10")) THEN
                bus_cycle_state := DATA_BYTES;
            ELSE
                bus_cycle_state := STAND_BY;
                IF (HOLDNeg_pullup ='1' AND (Instruct = RES_RD_ID) AND
                (dummy_cnt = 0)) THEN
                    write <= '0';
                    res_flag := FALSE;
                END IF;
            END IF;
        END IF;  -- end of rising_edge_CSNeg_ipd

    END PROCESS BusCycleDecode;

    ---------------------------------------------------------------------------
    -- Timing control for the Page Program
    ---------------------------------------------------------------------------
    ProgTime : PROCESS(PSTART, PGSUSP, PGRES)
        VARIABLE pob      : time;
        VARIABLE elapsed  : time;
        VARIABLE start    : time;
        VARIABLE duration : time;
    BEGIN
        IF Instruct = PP OR Instruct = QPP OR Instruct = PG_SCREG THEN
            IF LongTimming THEN
                pob  := tdevice_PP;
            ELSE
                pob  := tdevice_PP / 10;
            END IF;
        END IF;
        IF rising_edge(PSTART) AND PDONE = '1' THEN
            elapsed := 0 ns;
            PDONE <= '0', '1' AFTER pob;
            start := NOW;
        ELSIF PGSUSP'EVENT AND PGSUSP = '1' AND PDONE /= '1' THEN
            elapsed  := NOW - start;
            duration := pob - elapsed;
            PDONE <= '0';
        ELSIF PGRES'EVENT AND PGRES = '1' AND PDONE /= '1'THEN
            start := NOW;
            PDONE <= '0', '1' AFTER duration;
        END IF;

    END PROCESS ProgTime;

    ---------------------------------------------------------------------------
    -- Timing control for the Write Status Register
    ---------------------------------------------------------------------------
    WriteTime : PROCESS(WSTART)
        VARIABLE wob      : time;
    BEGIN
        IF LongTimming THEN
            wob  := tdevice_WRR;
        ELSE
            wob  := tdevice_WRR / 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 Write Status Register when Write Enable for
    -- Volatile Status Register was issued
    ---------------------------------------------------------------------------

    WriteTimeVlt : PROCESS(VLTSTART)
        VARIABLE wvob   : time;
    BEGIN
        wvob := tdevice_VRR;
        IF rising_edge(VLTSTART) AND VLTDONE = '1' THEN
            VLTDONE <= '0' , '1' AFTER wvob;
        END IF;
    END PROCESS WriteTimeVlt;

    ---------------------------------------------------------------------------
    -- Timing control for the Erase Operation
    ---------------------------------------------------------------------------
    ErsTime : PROCESS(ESTART, ESUSP, ERES)
        VARIABLE seo      : time;
        VARIABLE beo32    : time;
        VARIABLE beo64    : time;
        VARIABLE ceo      : time;
        VARIABLE elapsed  : time;
        VARIABLE start    : time;
        VARIABLE duration : time;
    BEGIN
        IF LongTimming THEN
            seo   := tdevice_SE;
            beo32 := tdevice_BE1;
            beo64 := tdevice_BE2;
            ceo   := tdevice_CE;
        ELSE
            seo   := tdevice_SE / 100;
            beo32 := tdevice_BE1 / 100;
            beo64 := tdevice_BE2 / 100;
            ceo   := tdevice_CE / 100;
        END IF;
        IF rising_edge(ESTART) AND EDONE = '1' THEN
            IF Instruct = CE THEN
                duration := ceo;
            ELSIF Instruct = BE_64 THEN
                duration := beo64;
            ELSIF Instruct = BE_32 THEN
                duration := beo32;
            ELSE -- sector erase 4KB, instruct SE
                duration := seo;
            END IF;
            elapsed := 0 ns;
            EDONE <= '0', '1' AFTER duration;
            start := NOW;
        ELSIF ESUSP'EVENT AND ESUSP = '1' AND EDONE /= '1' THEN
            elapsed  := NOW - start;
            duration := duration - elapsed;
            EDONE <= '0';
        ELSIF ERES'EVENT AND ERES = '1' AND EDONE /= '1' THEN
            start := NOW;
            EDONE <= '0', '1' AFTER duration;
        END IF;

    END PROCESS ErsTime;

    CheckCEOnPowerUP :PROCESS(CSNeg_ipd)
    BEGIN
        IF (PoweredUp = '0' AND falling_edge(CSNeg_ipd)) THEN
            REPORT InstancePath & partID &
            ": Device is selected during Power Up"
            SEVERITY WARNING;
        END IF;
    END PROCESS;

    ---------------------------------------------------------------------------
    -- Main Behavior Process
    -- combinational process for next state generation
    ---------------------------------------------------------------------------
    StateGen :PROCESS(PoweredUp, write, CSNeg_ipd, WDONE, ERSSUSP_out, RES1_out,
                      ERSRES_out, PRGSUSP_out, EDONE,PRGRES_out, DP_out, PDONE,
                      VLTDONE,RES2_out)

    BEGIN

        IF rising_edge(PoweredUp) THEN
            next_state <= IDLE;
        ELSE
            CASE current_state IS
                WHEN IDLE =>
                    IF falling_edge(write) THEN
                        IF (Instruct = WRR AND (SRP1='0' AND
                            (SRP0='0' OR (SRP0='1' AND WPNeg ='1')))) THEN
                            IF (WEL='1' AND NOT (wren_vlt_flag)) THEN
                                next_state <= WRITE_SR;
                            ELSIF (WEL='0' AND wren_vlt_flag) THEN
                                next_state <= WRITE_SR_V;
                            END IF;
                        ELSIF (Instruct = PP AND WEL='1') THEN
                            sect := Address / 16#1000#;
                            sect_tmp_pg := sect;
                            IF (Sec_Prot(sect) = '0') THEN
                                next_state <= PAGE_PG;
                            END IF;
                        ELSIF (Instruct = QPP AND WEL='1' AND QE='1') THEN
                            sect := Address / 16#1000#;
                            sect_tmp_pg := sect;
                            IF (Sec_Prot(sect) = '0') THEN
                                next_state <= PAGE_PG;
                            END IF;
                        ELSIF (Instruct = PG_SCREG AND WEL='1') THEN
                            sect := Address / 16#1000#;
                            IF ((sect < 4 AND sect > 0) AND
                                            LB_bits(sect-1)='0') THEN
                                next_state <= PAGE_PG;
                            END IF;
                        ELSIF (Instruct = ERS_SCREG AND WEL='1') THEN
                            sect := Address / 16#1000#;
                            IF ((sect <= 3) AND LB_bits(sect-1)='0') THEN
                                next_state <= SECTOR_ERS;
                            END IF;
                        ELSIF ((Instruct = SE OR Instruct = BE_32 OR
                                Instruct = BE_64) AND WEL='1') THEN
                            sect := Address / 16#1000#;
                            sect_tmp_ers := sect;
                            IF (Sec_Prot(sect) = '0') THEN
                                next_state <= SECTOR_ERS;
                            END IF;
                        ELSIF (Instruct = CE AND WEL='1' AND
                        ((CMP='0' AND BP2='0' AND BP1='0' AND BP0='0') OR
                        (CMP='1' AND BP2='1' AND BP1='1' AND BP0='1'))) THEN
                            next_state <= BULK_ERS;
                        ELSE
                            next_state <= IDLE;
                        END IF;
                    ELSIF rising_edge(DP_out) THEN
                        next_state <= DP_DOWN;
                    END IF;

                WHEN WRITE_SR =>
                    IF rising_edge(WDONE) THEN
                        next_state <= IDLE;
                    END IF;  -- end of WRITE_SR

                WHEN WRITE_SR_V =>
                    IF rising_edge(VLTDONE) THEN
                        next_state <= IDLE;
                    END IF;

                WHEN PAGE_PG =>
                    IF (PRGSUSP_out'event AND PRGSUSP_out = '1') THEN
                        next_state <= PG_SUSP;
                    ELSIF rising_edge(PDONE) THEN
                        next_state <= IDLE;
                    END IF; -- end of PAGE_PG

                WHEN PG_SUSP =>
                    IF (PRGRES_out'event AND PRGRES_out = '1') THEN
                        next_state <= PAGE_PG;
                    ELSIF falling_edge(write) THEN
                        IF (Instruct = SE OR Instruct = BE_32 OR
                            Instruct = BE_64) THEN
                            sect := Address / 16#1000#;
                            IF ((Sec_Prot(sect) = '0') AND
                            (sect /= sect_tmp_pg)) THEN
                                next_state <= PG_SUSP_ERS;
                            END IF;
                        END IF;
                    END IF; -- end of PG_SUSP

                WHEN PG_SUSP_ERS =>
                    IF rising_edge(EDONE) THEN
                        next_state <= PG_SUSP;
                    ELSE
                        next_state <= PG_SUSP_ERS;
                    END IF;

                WHEN BULK_ERS =>
                    IF rising_edge(EDONE) THEN
                        next_state <= IDLE;
                    END IF;

                WHEN SECTOR_ERS =>
                    IF (ERSSUSP_out'event AND ERSSUSP_out = '1') THEN
                        next_state <= ERS_SUSP;
                    ELSIF rising_edge(EDONE) THEN
                        next_state <= IDLE;
                    END IF;

                WHEN ERS_SUSP =>
                    IF (ERSRES_out'event AND ERSRES_out = '1') THEN
                        next_state <= SECTOR_ERS;
                    ELSIF falling_edge(write) THEN
                        IF (Instruct = PP OR (Instruct = QPP AND QE='1')) THEN
                            sect := Address / 16#1000#;
                            IF ((Sec_Prot(sect) = '0') AND
                                                (sect /= sect_tmp_ers)) THEN
                                next_state <= ERS_SUSP_PG;
                            END IF;
                        ELSIF (Instruct = PG_SCREG) THEN
                            sect := Address / 16#1000#;
                            IF ((sect < 4 AND sect > 0) AND
                                    LB_bits(sect-1)='0') THEN
                                next_state <= ERS_SUSP_PG;
                            END IF;
                        END IF;
                    END IF;

                WHEN ERS_SUSP_PG =>
                    IF rising_edge(PDONE) THEN
                        next_state <= ERS_SUSP;
                    ELSE
                        next_state <= ERS_SUSP_PG;
                    END IF;

                WHEN DP_DOWN =>
                    IF rising_edge(RES1_out) OR rising_edge(RES2_out) THEN
                        next_state <= IDLE;
                    END IF;

            END CASE;
        END IF;
    END PROCESS StateGen;
    ---------------------------------------------------------------------------
    --FSM Output generation and general funcionality
    ---------------------------------------------------------------------------
    Functional : PROCESS(read_out, Instruct, SCK_ipd, change_addr, write,
                        Address, PDONE, WDONE, EDONE, ERSSUSP_out, PoweredUp,
                        CSNeg_ipd, RES1_out, ERSRES_out, PRGSUSP_out,PRGRES_out,
                        VLTDONE, current_state, DP_out, RES2_out,SUSP_FL_OUT)

        VARIABLE WData          : WByteType:= (OTHERS => MaxData);

        VARIABLE oe             : boolean := FALSE;

        VARIABLE AddrLo         : NATURAL;
        VARIABLE AddrHi         : NATURAL;

        VARIABLE AddrLo_ers     : NATURAL;
        VARIABLE AddrHi_ers     : NATURAL;
        VARIABLE AddrLo_wrap    : NATURAL;
        VARIABLE AddrHi_wrap    : NATURAL;

        VARIABLE Addr           : NATURAL;
        VARIABLE Addr_w         : NATURAL;
        VARIABLE Addr_ers       : NATURAL;
        VARIABLE Addr_tmp       : NATURAL;
        VARIABLE Addr_tmp_2     : NATURAL;
        VARIABLE Addr_tmp_3     : NATURAL;
        VARIABLE Addr_screg     : NATURAL;
        VARIABLE Addr_screg_tmp : NATURAL;

        VARIABLE data_out       : std_logic_vector(7 downto 0);
        VARIABLE ident_out      : std_logic_vector(23 downto 0);
        VARIABLE ident_out2     : std_logic_vector(15 downto 0);
        VARIABLE uniq_id        : std_logic_vector(63 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 Blk_4_Num;
        VARIABLE cnt            : NATURAL RANGE 0 TO 256 := 0;

    BEGIN

        oe := rising_edge(read_out) AND PoweredUp = '1';

        IF Instruct'EVENT THEN
            read_cnt := 0;

            fast_rd   <= true;
            dual_read <= false;
            slow_read <= false;
            quad_read <= false;
            sr_read   <= false;
            read_id   <= false;
            pp_quad   := FALSE;

            IF (current_state = IDLE AND DP_in = '1') THEN
                    REPORT "Command results can be corrupted "
                    SEVERITY WARNING;
            END IF;
        END IF;

        IF rising_edge(PoweredUp) THEN
            WEL  := '0';
            BUSY := '0';
            SUS  := '0';
            change_prot_bits <= '1', '0' AFTER 1 ns;
        END IF;

        IF change_addr'EVENT 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;

        IF SUSP_FL_OUT'EVENT AND SUSP_FL_OUT = '1' THEN
            SUSP_FL_IN <= '0';
        END IF;

        CASE current_state IS

            WHEN IDLE  =>

                fast_rd   <= true;
                dual_read <= false;
                slow_read <= false;
                quad_read <= false;
                read_id   <= false;
                sr_read <= false;
                res_flag := FALSE;
                pg_screg_flag <= false;
                ers_screg_flag <= false;

                IF falling_edge(write) AND DP_in ='0' THEN
                    read_cnt := 0;
                    IF (Instruct = WREN) THEN
                        WEL := '1';
                    ELSIF (Instruct = WRDI) THEN
                        WEL := '0';
                    ELSIF (Instruct = WRR) THEN
                        IF(SRP1='0' AND (SRP0='0' OR
                                        (SRP0='1' AND WPNeg='1'))) THEN
                            IF WEL='1' AND NOT (wren_vlt_flag) THEN
                                WSTART <= '1', '0' AFTER 5 ns;
                                BUSY := '1';
                            ELSIF (WEL='0' AND wren_vlt_flag) THEN
                                VLTSTART <= '1', '0' AFTER 5 ns;
                            END IF;
                        ELSE
                            WEL := '0';
                        END IF;
                    ELSIF ((Instruct = PP OR (Instruct = QPP AND QE='1'))
                            AND WEL='1' AND PDONE='1') THEN
                        sect := Address / 16#1000#;
                        IF (Sec_Prot(sect) = '0') THEN
                            PSTART <= '1', '0' AFTER 5 ns;
                            PGSUSP  <= '0';
                            PGRES   <= '0';
                            BUSY    := '1';
                            SA      <= sect;
                            Addr    := Address;
                            Addr_tmp:= Address;
                            wr_cnt  := Byte_number;

                            FOR I IN wr_cnt DOWNTO 0 LOOP
                                IF Viol /= '0' THEN
                                    WData(i) := -1;
                                ELSE
                                    WData(i) := WByte(i);
                                END IF;
                            END LOOP;
                        ELSE
                            WEL := '0';
                        END IF;
                    ELSIF (Instruct = PG_SCREG AND WEL='1') THEN
                        sect := Address / 16#1000#;
                        IF ((sect <= 3) AND LB_bits(sect-1)='0') THEN
                            PSTART <= '1', '0' AFTER 5 ns;
                            PGSUSP  <= '0';
                            PGRES   <= '0';
                            BUSY    := '1';
                            SA      <= sect;
                            wr_cnt  := Byte_number;
                            Addr_screg := Address mod 16#1000#;
                            Addr_screg_tmp := Address mod 16#1000#;
                            pg_screg_flag <= true;

                            FOR I IN wr_cnt DOWNTO 0 LOOP
                                IF Viol /= '0' THEN
                                    WData(i) := -1;
                                ELSE
                                    WData(i) := WByte(i);
                                END IF;
                            END LOOP;

                        ELSE
                            WEL := '0';
                        END IF;
                    ELSIF ((Instruct = SE OR Instruct = BE_32 OR
                                Instruct = BE_64) AND WEL='1') THEN
                        sect := Address / 16#1000#;
                        IF (Sec_Prot(sect) = '0') THEN
                            ESTART <= '1', '0' AFTER 5 ns;
                            ESUSP  <= '0';
                            ERES   <= '0';
                            BUSY  := '1';
                            Addr_ers := Address;
                        ELSE
                            WEL := '0';
                        END IF;
                    ELSIF (Instruct = CE AND WEL='1') THEN
                        IF ((CMP='0' AND BP2='0' AND BP1='0' AND BP0='0') OR
                           (CMP='1' AND BP2='1' AND BP1='1' AND BP0='1')) THEN
--                         IF (Sec_Prot = 0)
                            ESTART <= '1', '0' AFTER 5 ns;
                            ESUSP  <= '0';
                            ERES   <= '0';
                            BUSY  := '1';
                        ELSE
                            WEL := '0';
                        END IF;
                    ELSIF (Instruct = ERS_SCREG AND WEL='1') THEN
                        sect := Address / 16#1000#;
                        IF ((sect <= 3) AND LB_bits(sect-1)='0') THEN
                            ESTART <= '1', '0' AFTER 5 ns;
                            ESUSP  <= '0';
                            ERES   <= '0';
                            BUSY  := '1';
                            SA    <= sect;
                            ers_screg_flag <= true;
                        ELSE
                            WEL := '0';
                        END IF;
                    ELSIF (Instruct = DP) THEN
                        RES2_in <= '0';
                        RES1_in <= '0';
                        DP_in  <= '1';
                    END IF;
                -- end of falling_edge_write
                ELSIF (oe AND DP_in='0') THEN
                    IF (Instruct = RDSR) THEN
                    --Read Status Register
                        sr_read <= true;
                        SOut_zd <= Status_reg1(7-read_cnt);
                        read_cnt := read_cnt + 1;
                        IF (read_cnt = 8) THEN
                            read_cnt := 0;
                        END IF;
                    ELSIF (Instruct = RDSR2) THEN
                        sr_read <= true;
                        SOut_zd <= Status_reg2(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
                        IF (Instruct = READ) THEN
                            fast_rd   <= false;
                            dual_read <= false;
                            slow_read <= true;
                            quad_read <= false;
                            sr_read   <= false;
                        ELSE
                            fast_rd   <= true;
                            dual_read <= false;
                            slow_read <= false;
                            quad_read <= false;
                            sr_read   <= false;
                        END IF;
                        IF (Mem(read_addr) /= -1) THEN
                            data_out := to_slv(Mem(read_addr),8);
                            SOut_zd  <= data_out(7-read_cnt);
                        ELSE
                            SOut_zd  <= 'U';
                        END IF;
                        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=FAST_DREAD OR Instruct=FAST_DREAD_2) THEN
                        fast_rd   <= false;
                        dual_read <= true;
                        slow_read <= false;
                        quad_read <= false;
                        sr_read   <= false;
                        data_out := to_slv(Mem(read_addr),8);
                        SOut_zd      <= data_out(7-2*read_cnt);
                        SIOut_zd     <= data_out(6-2*read_cnt);
                        read_cnt := read_cnt + 1;
                        IF (read_cnt = 4) THEN
                            read_cnt := 0;
                            IF (read_addr = AddrRANGE) THEN
                                read_addr := 0;
                            ELSE
                                read_addr := read_addr + 1;
                            END IF;
                        END IF;
                    ELSIF ((Instruct=FAST_QREAD OR Instruct=FAST_QREAD_4 OR
                              Instruct=W_QREAD  OR Instruct=WOCT_QREAD)
                            AND QE='1') THEN
                        IF ((Instruct=W_QREAD AND (Address mod 2 /= 0) ) OR
                           (Instruct=WOCT_QREAD AND
                                (Address mod 16 /= 0))) THEN
                            read_cnt := read_cnt + 1;
                            IF (read_cnt = 2) THEN
                                read_cnt := 0;
                                REPORT "Word Read can't execute Wrong Address"
                                SEVERITY NOTE;
                            END IF;
                        ELSE
                            fast_rd   <= false;
                            dual_read <= false;
                            slow_read <= false;
                            quad_read <= true;
                            sr_read   <= false;
                            Addr_w   := Address;
                            data_out := to_slv(Mem(read_addr),8);
                            HOLDNegOut_zd <= data_out(7-4*read_cnt);
                            WPNegOut_zd   <= data_out(6-4*read_cnt);
                            SOut_zd       <= data_out(5-4*read_cnt);
                            SIOut_zd      <= data_out(4-4*read_cnt);
                            read_cnt := read_cnt + 1;
                            IF (read_cnt = 2) THEN
                                read_cnt := 0;
                                IF (wrap_byte(4)='0' AND (Instruct=FAST_QREAD_4
                                 OR Instruct=W_QREAD)) THEN
                                    ADDRHILO_WRAP(AddrLo_wrap,AddrHi_wrap,
                                                  Addr_w,w_size);
                                    IF (read_addr = AddrHi_wrap) THEN
                                        read_addr := AddrLo_wrap;
                                    ELSE
                                        read_addr := read_addr + 1;
                                    END IF;
                                ELSE
                                    IF (read_addr = AddrRANGE) THEN
                                        read_addr := 0;
                                    ELSE
                                        read_addr := read_addr + 1;
                                    END IF;
                                END IF;
                            END IF;
                        END IF;
                    ELSIF (Instruct=RDID OR Instruct=RDID_DUAL OR
                             Instruct=RDID_QUAD) THEN
                        IF (read_addr mod 2 = 0) THEN
                            ident_out2 := to_slv(Manuf_ID,8) &
                                          to_slv(Device_ID1,8);
                        ELSE
                            ident_out2 := to_slv(Device_ID1,8) &
                                          to_slv(Manuf_ID,8);
                        END IF;
                        read_id <= true;
                        IF (Instruct = RDID) THEN
                            fast_rd   <= true;
                            dual_read <= false;
                            slow_read <= false;
                            quad_read <= false;
                            sr_read   <= false;
                            SOut_zd <= ident_out2(15-read_cnt);
                            read_cnt  := read_cnt + 1;
                            IF (read_cnt = 16) THEN
                                read_cnt := 0;
                            END IF;
                        ELSIF (Instruct = RDID_DUAL) THEN
                            fast_rd   <= false;
                            dual_read <= true;
                            slow_read <= false;
                            quad_read <= false;
                            sr_read   <= false;
                            SOut_zd  <= ident_out2(15-2*read_cnt);
                            SIOut_zd <= ident_out2(14-2*read_cnt);
                            read_cnt := read_cnt + 1;
                            IF (read_cnt = 8) THEN
                                read_cnt := 0;
                            END IF;
                        ELSE --  (Instruct = RDID_QUAD)
                            fast_rd   <= false;
                            dual_read <= false;
                            slow_read <= false;
                            quad_read <= true;
                            sr_read   <= false;
                            HOLDNegOut_zd <= ident_out2(15-4*read_cnt);
                            WPNegOut_zd   <= ident_out2(14-4*read_cnt);
                            SOut_zd       <= ident_out2(13-4*read_cnt);
                            SIOut_zd      <= ident_out2(12-4*read_cnt);
                            read_cnt := read_cnt + 1;
                            IF (read_cnt = 4) THEN
                                read_cnt := 0;
                            END IF;
                        END IF;
                    ELSIF (Instruct = RD_UNIQ_ID) THEN
                    -- unique ID number is not in data sheet
                        read_id <= true;
                        uniq_id := to_slv(Unique_id_2,32)&
                                   to_slv(Unique_id_1,32);
                        SOut_zd <= uniq_id(63-read_cnt);
                        read_cnt := read_cnt + 1;
                        IF (read_cnt = 64) THEN
                            read_cnt := 0;
                        END IF;
                    ELSIF (Instruct = RDIDJ) THEN
                        read_id <= true;
                        ident_out := to_slv(Manuf_ID,8) &
                        to_slv(Device_ID2,8) & to_slv(Device_ID3,8);
                        SOut_zd <= ident_out(23-read_cnt);
                        read_cnt := read_cnt + 1;
                        IF (read_cnt = 24) THEN
                            read_cnt := 0;
                        END IF;
                    ELSIF (Instruct = RD_SFDP) THEN
--                         sfdp_addr := read_addr / 16#100#;
                        IF (read_addr / 16#100# = 0) THEN
                            Addr_tmp_2 := (read_addr mod 16#100#);
                            data_out := to_slv(SFDP_array(Addr_tmp_2),8);
                            SOut_zd  <= data_out(7-read_cnt);
                            read_cnt := read_cnt + 1;
                            IF (read_cnt = 8) THEN
                                read_cnt := 0;
                                IF (read_addr = SFDP_HiAddr) THEN
                                    read_addr := 0;
                                ELSE
                                    read_addr := read_addr + 1;
                                END IF;
                            END IF;
                        ELSE
                            read_cnt := read_cnt + 1;
                            IF (read_cnt = 8) THEN
                                read_cnt := 0;
                                REPORT "Given SFDP address is out of range"
                                SEVERITY NOTE;
                            END IF;
                        END IF;
                    ELSIF (Instruct = RD_SCREG) THEN
                        Addr_tmp_2 := read_addr / 16#100#;
                        Addr_tmp_3 := read_addr mod 16#100#;
                        IF (Addr_tmp_2 = 16) THEN
                            -- Security Register No.1
                            data_out := to_slv(Security_Reg1(Addr_tmp_3),8);
                            SOut_zd  <= data_out(7-read_cnt);
                            read_cnt := read_cnt + 1;
                        ELSIF (Addr_tmp_2 = 32) THEN
                            -- Security Register No.2
                            data_out := to_slv(Security_Reg2(Addr_tmp_3),8);
                            SOut_zd  <= data_out(7-read_cnt);
                            read_cnt := read_cnt + 1;
                        ELSIF (Addr_tmp_2 = 48) THEN
                            -- Security Register No.2
                            data_out := to_slv(Security_Reg3(Addr_tmp_3),8);
                            SOut_zd  <= data_out(7-read_cnt);
                            read_cnt := read_cnt + 1;
                        ELSE
                            read_cnt := read_cnt + 1;
                            IF (read_cnt = 8) THEN
                                read_cnt := 0;
                                REPORT "Security Reg address is out of range "
                                SEVERITY NOTE;
                            END IF;
                        END IF;
                        IF (read_cnt = 8) THEN
                            read_cnt := 0;
                            IF (read_addr mod 256 = SecReg_HiAddr) THEN
                                read_addr := (read_addr/256)*(SecReg_HiAddr+1);
                            ELSE
                                read_addr := read_addr + 1;
                            END IF;
                        END IF;
                    ELSIF Instruct = RES_RD_ID THEN
                        read_id <= true;
                        data_out := to_slv(Device_ID1,8);
                        SOut_zd  <= data_out(7-read_cnt);
                        read_cnt := read_cnt + 1;
                        IF (read_cnt = 8) THEN
                            read_cnt := 0;
                        END IF;
                    END IF;  -- end of oe
                ELSIF rising_edge(DP_out) THEN
                    DP_in <= '0';
                END IF;  -- end of IDLE state

            WHEN WRITE_SR =>

                IF (WDONE ='1') THEN
                    BUSY := '0';
                    WEL  := '0';

                    SRP0 := Status_reg1_in(7);
                    SEC  := Status_reg1_in(6);
                    TB   := Status_reg1_in(5);
                    BP2  := Status_reg1_in(4);
                    BP1  := Status_reg1_in(3);
                    BP0  := Status_reg1_in(2);
                    BP_bits := BP2 & BP1 & BP0;
                    CMP  := Status_reg2_in(6);
                    QE   := Status_reg2_in(1);
                    -- SRP1 bit will only change value from '0' to '1'
                    -- if SRP1 is '1' than Status Register is protected
                    --and is not possible to write it
                    SRP1 := Status_reg2_in(0);

                    IF LB3 = '0' THEN
                        LB3 := Status_reg2_in(5);
                    ELSE
                        REPORT "LB bit is set to '1', no change allowed"
                        SEVERITY NOTE;
                    END IF;

                    IF LB2 = '0' THEN
                        LB2 := Status_reg2_in(4);
                    ELSE
                        REPORT "LB bit is set to '1', no change allowed"
                        SEVERITY NOTE;
                    END IF;
                    IF LB1 = '0' THEN
                        LB1 := Status_reg2_in(3);
                    ELSE
                        REPORT "LB bit is set to '1', no change allowed"
                        SEVERITY NOTE;
                    END IF;
                    LB_bits := LB3 & LB2 & LB1;
                    change_prot_bits <= '1' , '0' AFTER 2 ns;
                END IF; -- end of WDONE

                IF (oe AND Instruct = RDSR) THEN
                --Read Status Register 1
                        sr_read  <= true;
                        SOut_zd  <= Status_reg1(7-read_cnt);
                        read_cnt := read_cnt + 1;
                        IF (read_cnt = 8) THEN
                            read_cnt := 0;
                        END IF;
                END IF; -- end of WRITE_SR

            WHEN WRITE_SR_V =>

                IF (VLTDONE = '1') THEN
                    SRP0 := Status_reg1_in(7);
                    SEC  := Status_reg1_in(6);
                    TB   := Status_reg1_in(5);
                    BP2  := Status_reg1_in(4);
                    BP1  := Status_reg1_in(3);
                    BP0  := Status_reg1_in(2);
                    BP_bits := BP2 & BP1 & BP0;
                    CMP  := Status_reg2_in(6);
                    QE   := Status_reg2_in(1);
                    -- SRP1 bit will only change value from '0' to '1'
                    -- if SRP1 is '1' than Status Register is protected
                    --and is not possible to write it
                    SRP1 := Status_reg2_in(0);
                    IF LB3 = '0' THEN
                        LB3 := Status_reg2_in(5);
                    ELSIF LB2 = '0' THEN
                        LB2 := Status_reg2_in(4);
                    ELSIF LB1 = '0' THEN
                        LB1 := Status_reg2_in(3);
                    ELSE
                        REPORT "LB bit is set to '1', no change allowed"
                        SEVERITY NOTE;
                    END IF;

                    change_prot_bits <= '1' , '0' AFTER 2 ns;

                    wren_vlt_flag := FALSE;
                END IF;

            WHEN PAGE_PG | ERS_SUSP_PG =>

                IF falling_edge(PDONE) THEN

                    IF (Instruct /= PG_SCREG) THEN
                        ADDRHILO_PG(AddrLo, AddrHi, Addr);
                    END IF;
                    cnt := 0;

                    FOR i IN 0 TO wr_cnt LOOP
                        new_int := WData(i);
                        IF (Instruct = PG_SCREG) THEN
                            IF (sect = 1) THEN
                                old_int := Security_Reg1(Addr_screg + i - cnt);
                            ELSIF (sect = 2) THEN
                                old_int := Security_Reg2(Addr_screg + i - cnt);
                            ELSE
                                old_int := Security_Reg3(Addr_screg + i - cnt);
                            END IF;
                        ELSE
                            old_int := Mem(Addr + i - cnt);
                        END IF;
                        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) := new_int;
                        ELSE
                            WData(i) := -1;
                        END IF;
                        IF (Instruct = PG_SCREG) THEN
                            IF (sect = 1) THEN
                                Security_Reg1(Addr_screg + i - cnt) := - 1;
                            ELSIF (sect = 2) THEN
                                Security_Reg2(Addr_screg + i - cnt) := - 1;
                            ELSE
                                Security_Reg3(Addr_screg + i - cnt) := - 1;
                            END IF;
                        ELSE
                            Mem(Addr + i - cnt) := - 1;
                        END IF;
                        IF (Instruct /= PG_SCREG) THEN
                            IF ((Addr + i) = AddrHi) THEN
                                Addr := AddrLo;
                                cnt  := i + 1;
                            END IF;
                        ELSE
                            IF Addr_screg + i = SecReg_HiAddr THEN
                                Addr_screg := SecReg_LoAddr;
                                cnt  := i + 1;
                            END IF;
                        END IF;
                    END LOOP;
                    cnt := 0;

                END IF;

                IF (PDONE = '1') THEN
                    IF (current_state /= ERS_SUSP_PG) THEN
                        BUSY := '0';
                    END IF;
                    WEL := '0';

                    FOR I IN 0 TO wr_cnt LOOP
                        IF pg_screg_flag  THEN
                            IF (sect = 1) THEN
                                Security_Reg1(Addr_screg_tmp + i - cnt) :=WData(i);
                            ELSIF (sect = 2) THEN
                                Security_Reg2(Addr_screg_tmp + i - cnt) :=WData(i);
                            ELSE
                                Security_Reg3(Addr_screg_tmp + i - cnt) :=WData(i);
                            END IF;
                            IF ((Addr_screg_tmp + i) = SecReg_HiAddr) THEN
                                Addr_screg_tmp := SecReg_LoAddr;
                                cnt := i + 1;
                            END IF;
                        ELSE
                            Mem(Addr_tmp + i - cnt) := WData(i);
                            IF ((Addr_tmp + i) = AddrHi) THEN
                                Addr_tmp := AddrLo;
                                cnt := i + 1;
                            END IF;
                        END IF;
                    END LOOP;
                END IF;  -- end of PDONE

                IF (Instruct = ERS_PG_SUSP AND current_state = PAGE_PG AND
                SUSP_FL_IN = '0') THEN
                    PGSUSP <= '1', '0' AFTER 1 ns;
                    PRGSUSP_in <= '1';
                END IF;

                IF (oe AND Instruct = RDSR) THEN
                --Read Status Register 1
                    sr_read   <= true;
                    SOut_zd <= Status_reg1(7-read_cnt);
                    read_cnt := read_cnt + 1;
                    IF (read_cnt = 8) THEN
                        read_cnt := 0;
                    END IF;
                END IF;

            WHEN PG_SUSP =>
                fast_rd   <= true;
                dual_read <= false;
                slow_read <= false;
                quad_read <= false;
                sr_read   <= false;
                BUSY := '0';
                IF (PRGSUSP_out = '1' AND (Instruct /= ERS_PG_RES)) THEN
                    PRGSUSP_in <= '0';
                    --The BUSY bit in the Status Register will indicate that
                    --the device is ready for another operation.
--                     BUSY := '0';
                    --The SuspEND (SUS) bit in the Status Register2 will
                    --be set to the logical “1” state to indicate that the
                    --program operation has been suspENDed.
                    SUS := '1';
                END IF;
                IF (PRGRES_out'event AND PRGRES_out = '1') THEN
                   PRGRES_in <= '0';
                   BUSY := '1';
                END IF;
                IF (SUS = '1') THEN
                    IF falling_edge(write) THEN
                        IF (Instruct = ERS_PG_RES) THEN
                            SUS := '0';
                            PRGRES_in <= '1';
                            SUSP_FL_IN <= '1';
                            PGRES <= '1', '0' AFTER 5 ns;
                        ELSIF ((Instruct = SE OR Instruct = BE_32 OR
                                Instruct = BE_64) AND WEL='1') THEN
                            sect := Address / 16#1000#;
                            IF (sect /= sect_tmp_pg AND
                                            Sec_Prot(sect) = '0') THEN
                                ESTART <= '1', '0' AFTER 5 ns;
                                ESUSP  <= '0';
                                ERES   <= '0';
                                BUSY     := '1';
                                Addr_ers := Address;
                            ELSE
                                BUSY := '0';
                                REPORT "Can't erase sector,protected or susp."
                                SEVERITY NOTE;
                            END IF;
                        END IF;
                    ELSIF (oe) THEN
                        IF (Instruct = RDSR) THEN
                            --Read Status Register 1
                            sr_read  <= true;
                            SOut_zd <= Status_reg1(7-read_cnt);
                            read_cnt := read_cnt + 1;
                            IF (read_cnt = 8) THEN
                                read_cnt := 0;
                            END IF;
                        ELSIF (Instruct = RDSR2) THEN
                            --Read Status Register 2
                            sr_read   <= true;
                            SOut_zd <= Status_reg2(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
                            IF (sect_tmp_pg /= read_addr / 16#1000#) THEN
                                IF (Instruct = READ) THEN
                                    fast_rd   <= false;
                                    dual_read <= false;
                                    slow_read <= true;
                                    quad_read <= false;
                                    sr_read   <= false;
                                ELSE
                                    fast_rd   <= true;
                                    dual_read <= false;
                                    slow_read <= false;
                                    quad_read <= false;
                                    sr_read   <= false;
                                END IF;
                                IF (Mem(read_addr) /= -1) THEN
                                    data_out := to_slv(Mem(read_addr),8);
                                    SOut_zd  <= data_out(7-read_cnt);
                                ELSE
                                    SOut_zd  <= 'U';
                                END IF;
                                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
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 8) THEN
                                    REPORT "Can't read suspended sector"
                                    SEVERITY NOTE;
                                    read_cnt := 0;
                                END IF;
                            END IF;
                        ELSIF (Instruct=FAST_DREAD OR
                                 Instruct=FAST_DREAD_2) THEN
                            IF sect_tmp_pg /= (read_addr / 16#1000#) THEN
                                fast_rd   <= false;
                                dual_read <= true;
                                slow_read <= false;
                                quad_read <= false;
                                sr_read   <= false;
                                IF (Mem(read_addr) /= -1) THEN
                                    data_out := to_slv(Mem(read_addr),8);
                                    SOut_zd  <= data_out(7-2*read_cnt);
                                    SIOut_zd <= data_out(6-2*read_cnt);
                                ELSE
                                    SOut_zd  <= 'U';
                                    SIOut_zd <= 'U';
                                END if;
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 4) THEN
                                    read_cnt := 0;
                                    IF (read_addr = AddrRANGE) THEN
                                        read_addr := 0;
                                    ELSE
                                        read_addr := read_addr + 1;
                                    END IF;
                                END IF;
                            ELSE
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 4) THEN
                                    REPORT "Can't read suspended sector"
                                    SEVERITY NOTE;
                                    read_cnt := 0;
                                END IF;
                            END IF;
                        ELSIF ((Instruct=FAST_QREAD OR Instruct=W_QREAD
                             OR Instruct=FAST_QREAD_4 OR Instruct=WOCT_QREAD)
                                AND QE = '1') THEN
                            IF sect_tmp_pg /= (read_addr / 16#1000#) THEN
                                IF ((Instruct=W_QREAD AND
                                Address mod 2 /= 0) OR
                                (Instruct=WOCT_QREAD AND
                                Address mod 16 /= 0)) THEN
                                    read_cnt := read_cnt + 1;
                                    IF (read_cnt = 2) THEN
                                        read_cnt := 0;
                                        REPORT "Word Read - Wrong Read Address"
                                        SEVERITY NOTE;
                                    END IF;
                                ELSE
                                    fast_rd   <= false;
                                    dual_read <= false;
                                    slow_read <= false;
                                    quad_read <= true;
                                    sr_read   <= false;
                                    Addr_w   := Address;
                                    data_out      := to_slv(Mem(read_addr),8);
                                    HOLDNegOut_zd <= data_out(7-4*read_cnt);
                                    WPNegOut_zd   <= data_out(6-4*read_cnt);
                                    SOut_zd       <= data_out(5-4*read_cnt);
                                    SIOut_zd      <= data_out(4-4*read_cnt);
                                    read_cnt := read_cnt + 1;
                                    IF (read_cnt = 2) THEN
                                        read_cnt := 0;
                                        IF (wrap_byte(4)= '0' AND
                                        (Instruct=FAST_QREAD_4 OR
                                         Instruct=W_QREAD)) THEN
                                            ADDRHILO_WRAP(AddrLo_wrap,
                                                AddrHi_wrap, Addr_w,w_size);
                                            IF (read_addr = AddrHi_wrap) THEN
                                                read_addr := AddrLo_wrap;
                                            ELSE
                                                read_addr := read_addr + 1;
                                            END IF;
                                        ELSE
                                            IF (read_addr = AddrRANGE) THEN
                                                read_addr := 0;
                                            ELSE
                                                read_addr := read_addr + 1;
                                            END IF;
                                        END IF;
                                    END IF;
                                END IF;
                            ELSE
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 2) THEN
                                    REPORT "Can't read suspended sector"
                                    SEVERITY NOTE;
                                    read_cnt := 0;
                                END IF;
                            END IF;
                        ELSIF (Instruct=RDID OR Instruct=RDID_DUAL OR
                                Instruct=RDID_QUAD) THEN
                            IF (read_addr mod 2 = 0) THEN
                                ident_out2 := to_slv(Manuf_ID,8) &
                                              to_slv(Device_ID1,8);
                            ELSE
                                ident_out2 := to_slv(Device_ID1,8)&
                                              to_slv(Manuf_ID,8);
                            END IF;
                            read_id <= true;
                            IF (Instruct = RDID) THEN
                                fast_rd   <= true;
                                dual_read <= false;
                                slow_read <= false;
                                quad_read <= false;
                                sr_read   <= false;
                                SOut_zd <= ident_out2(15-read_cnt);
                                read_cnt  := read_cnt + 1;
                                IF (read_cnt = 16) THEN
                                    read_cnt := 0;
                                END IF;
                            ELSIF (Instruct = RDID_DUAL) THEN
                                fast_rd   <= false;
                                dual_read <= true;
                                slow_read <= false;
                                quad_read <= false;
                                sr_read   <= false;
                                SOut_zd  <= ident_out2(15-2*read_cnt);
                                SIOut_zd <= ident_out2(14-2*read_cnt);
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 8) THEN
                                    read_cnt := 0;
                                END IF;
                            ELSE --  (Instruct = RDID_QUAD)
                                fast_rd   <= false;
                                dual_read <= false;
                                slow_read <= false;
                                quad_read <= true;
                                sr_read   <= false;
                                HOLDNegOut_zd <= ident_out2(15-4*read_cnt);
                                WPNegOut_zd   <= ident_out2(14-4*read_cnt);
                                SOut_zd       <= ident_out2(13-4*read_cnt);
                                SIOut_zd      <= ident_out2(12-4*read_cnt);
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 4) THEN
                                    read_cnt := 0;
                                END IF;
                            END IF;
                        ELSIF (Instruct = RD_UNIQ_ID) THEN
                        -- unique ID number is not in data sheet
                            read_id <= true;
                            uniq_id := to_slv(Unique_id_2,32)&
                                       to_slv(Unique_id_1,32);
                            SOut_zd <= uniq_id(63-read_cnt);
                            read_cnt := read_cnt + 1;
                            IF (read_cnt = 64) THEN
                                read_cnt := 0;
                            END IF;
                        ELSIF (Instruct = RDIDJ) THEN
                            read_id <= true;
                            ident_out := to_slv(Manuf_ID,8) &
                            to_slv(Device_ID2,8) & to_slv(Device_ID3,8);
                            SOut_zd <= ident_out(23-read_cnt);
                            read_cnt := read_cnt + 1;
                            IF (read_cnt = 24) THEN
                                read_cnt := 0;
                            END IF;
                        ELSIF (Instruct = RD_SFDP) THEN
                            IF (read_addr / 16#100# = 0) THEN
                                Addr_tmp_2 := (read_addr mod 16#100#);
                                data_out := to_slv(SFDP_array(Addr_tmp_2),8);
                                SOut_zd  <= data_out(7-read_cnt);
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 8) THEN
                                    read_cnt := 0;
                                    IF (read_addr = SFDP_HiAddr) THEN
                                        read_addr := 0;
                                    ELSE
                                        read_addr := read_addr + 1;
                                    END IF;
                                END IF;
                            ELSE
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 8) THEN
                                    read_cnt := 0;
                                    REPORT "SFDP address is out of range"
                                    SEVERITY NOTE;
                                END IF;
                            END IF;
                        ELSIF (Instruct = RD_SCREG) THEN
                            Addr_tmp_2 := read_addr / 16#100#;
                            Addr_tmp_3 := read_addr mod 16#100#;
                            IF (Addr_tmp_2 = 16) THEN
                                -- Security Register No.1
                                data_out := to_slv(Security_Reg1(Addr_tmp_3),8);
                                SOut_zd  <= data_out(7-read_cnt);
                                read_cnt := read_cnt + 1;
                            ELSIF (Addr_tmp_2 = 32) THEN
                                -- Security Register No.2
                                data_out := to_slv(Security_Reg2(Addr_tmp_3),8);
                                SOut_zd  <= data_out(7-read_cnt);
                                read_cnt := read_cnt + 1;
                            ELSIF (Addr_tmp_2 = 48) THEN
                                -- Security Register No.2
                                data_out := to_slv(Security_Reg3(Addr_tmp_3),8);
                                SOut_zd  <= data_out(7-read_cnt);
                                read_cnt := read_cnt + 1;
                            ELSE
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 8) THEN
                                    read_cnt := 0;
                                    REPORT "Security Reg addr is out of range "
                                    SEVERITY NOTE;
                                END if;
                            END IF;

                            IF (read_cnt = 8) THEN
                                read_cnt := 0;
                                IF (read_addr mod 256) = SecReg_HiAddr THEN
                                    read_addr:=(read_addr/256)*
                                                (SecReg_HiAddr+1);
                                ELSE
                                    read_addr := read_addr + 1;
                                END IF;
                            END IF;
                        END IF;
                    END IF;
                END IF;

            WHEN SECTOR_ERS | PG_SUSP_ERS =>
                IF falling_edge(EDONE) THEN
                    IF (Instruct = SE) THEN
                        ADDRHILO_SEC4(AddrLo_ers, AddrHi_ers, Addr_ers);
                    ELSIF (Instruct = BE_32) THEN
                        ADDRHILO_SEC32(AddrLo_ers, AddrHi_ers, Addr_ers);
                    ELSIF (Instruct = BE_64) THEN
                        ADDRHILO_SEC64(AddrLo_ers, AddrHi_ers, Addr_ers);
                    END IF;
                    IF (Instruct /= ERS_SCREG) THEN

                        FOR I IN AddrLo_ers TO AddrHi_ers LOOP
                            Mem(i) := -1;
                        END LOOP;
                    ELSE
                        IF (sect = 1) THEN
                            FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP
                                Security_Reg1(i) := -1;
                            END LOOP;
                        ELSIF (sect = 2) THEN
                            FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP
                                Security_Reg2(i) := -1;
                            END LOOP;
                        ELSE
                            FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP
                                Security_Reg3(i) := -1;
                            END LOOP;
                        END IF;
                    END IF;
                END IF;
                IF (EDONE = '1') THEN
                    IF (current_state /= PG_SUSP_ERS) THEN
                        BUSY := '0';
                    END IF;
                    WEL := '0';
                    IF (ers_screg_flag) THEN
                        IF (sect = 1) THEN
                            FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP
                                Security_Reg1(i) := MaxData;
                            END LOOP;
                        ELSIF (sect = 2) THEN
                            FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP
                                Security_Reg2(i) := MaxData;
                            END LOOP;
                        ELSE
                            FOR I IN SecReg_LoAddr TO SecReg_HiAddr LOOP
                                Security_Reg3(i) := MaxData;
                            END LOOP;
                        END IF;
                    ELSE
                        FOR I IN AddrLo_ers TO AddrHi_ers LOOP
                            Mem(i) := MaxData;
                        END LOOP;
                    END IF;
                END IF;

                IF (Instruct = ERS_PG_SUSP AND current_state = SECTOR_ERS AND
                SUSP_FL_IN = '0') THEN
                    ESUSP <= '1', '0' AFTER 1 ns;
                    ERSSUSP_in <= '1';
                END IF;
                IF (oe AND Instruct = RDSR) THEN
                    --Read Status Register 1
                    sr_read  <= true;
                    SOut_zd  <= Status_reg1(7-read_cnt);
                    read_cnt := read_cnt + 1;
                    IF (read_cnt = 8) THEN
                        read_cnt := 0;
                    END IF;
                END IF;

            WHEN BULK_ERS =>
                IF (current_state'event AND EDONE = '0') THEN
                    FOR I IN 0 TO AddrRANGE LOOP
                        Mem(i) := -1;
                    END LOOP;
                END IF;
                IF (EDONE = '1') THEN
                    BUSY := '0';
                    WEL  := '0';
                    FOR I IN 0 TO AddrRANGE LOOP
                        Mem(i) := MaxData;
                    END LOOP;

                END IF;
                IF (oe AND Instruct = RDSR) THEN
                    --Read Status Register 1
                    sr_read   <= true;
                    SOut_zd <= Status_reg1(7-read_cnt);
                    read_cnt := read_cnt + 1;
                    IF (read_cnt = 8) THEN
                        read_cnt := 0;
                    END IF;
                END IF;

            WHEN ERS_SUSP =>
                fast_rd   <= true;
                dual_read <= false;
                slow_read <= false;
                quad_read <= false;
                sr_read   <= false;
                pg_screg_flag <= false;
                BUSY := '0';
                IF (ERSSUSP_out = '1' AND (Instruct /= ERS_PG_RES)) THEN
                    ERSSUSP_in <= '0';
                    --The BUSY bit in the Status Register will indicate that
                    --the device is ready for another operation.
--                     BUSY := '0';
                    --The SuspEND (SUS) bit in the Status Register2 will
                    --be set to the logical “1” state to indicate that the
                    --program operation has been suspENDed.
                    SUS := '1';
                END IF;
                IF (ERSRES_out'event AND ERSRES_out = '1') THEN
                   ERSRES_in <= '0';
                   BUSY := '1';
                END IF;
                IF (SUS = '1') THEN
                    IF falling_edge(write) THEN
                        IF (Instruct = ERS_PG_RES) THEN
                            SUS := '0';
                            ERSRES_in <= '1';
                            SUSP_FL_IN <= '1';
                            ERES <= '1', '0' AFTER 5 ns;
                        ELSIF ((Instruct = PP OR (Instruct=QPP AND QE='1'))
                                 AND WEL ='1') THEN
                            sect := Address / 16#1000#;
                            IF (sect /= sect_tmp_ers AND
                                            Sec_Prot(sect)='0') THEN
                                PSTART <= '1', '0' AFTER 5 ns;
                                PGSUSP  <= '0';
                                PGRES   <= '0';
                                BUSY    := '1';
                                SA      <= sect;
                                Addr    := Address;
                                Addr_tmp:= Address;
                                wr_cnt  := Byte_number;
                                FOR I IN wr_cnt DOWNTO 0 LOOP
                                    IF Viol /= '0' THEN
                                        WData(i) := -1;
                                    ELSE
                                        WData(i) := WByte(i);
                                    END IF;
                                END LOOP;
                            ELSE
                                BUSY := '0';
                                REPORT "Can't program sector,protected or susp"
                                SEVERITY NOTE;
                            END IF;
                        ELSIF (Instruct = PG_SCREG) THEN
                            sect := Address / 16#1000#;
                            IF ((sect <= 3 AND sect >=1) AND
                                                LB_bits(sect-1)='0') THEN
                                PSTART <= '1', '0' AFTER 5 ns;
                                PGSUSP  <= '0';
                                PGRES   <= '0';
                                BUSY    := '1';
                                SA      <= sect;
                                wr_cnt  := Byte_number;
                                Addr_screg := Address mod 16#1000#;
                                Addr_screg_tmp := Address mod 16#1000#;
                                pg_screg_flag <= true;
                                FOR I IN wr_cnt DOWNTO 0 LOOP
                                    IF Viol /= '0' THEN
                                        WData(i) := -1;
                                    ELSE
                                        WData(i) := WByte(i);
                                    END IF;
                                END LOOP;
                            ELSE
                                WEL := '0';
                            END IF;
                        END IF;
                    ELSIF (oe) THEN
                        IF (Instruct = RDSR) THEN
                            --Read Status Register 1
                            sr_read <= true;
                            SOut_zd <= Status_reg1(7-read_cnt);
                            read_cnt := read_cnt + 1;
                            IF (read_cnt = 8) THEN
                                read_cnt := 0;
                            END IF;
                        ELSIF (Instruct = RDSR2) THEN
                            --Read Status Register 2
                            sr_read <= true;
                            SOut_zd <= Status_reg2(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
                            IF sect /= (read_addr / 16#1000#) THEN
                                IF (Instruct = READ) THEN
                                    fast_rd   <= false;
                                    dual_read <= false;
                                    slow_read <= true;
                                    quad_read <= false;
                                    sr_read   <= true;
                                ELSE
                                    fast_rd   <= true;
                                    dual_read <= false;
                                    slow_read <= false;
                                    quad_read <= false;
                                    sr_read   <= false;
                                END IF;
                                IF (Mem(read_addr) /= -1) THEN
                                    data_out := to_slv(Mem(read_addr),8);
                                    SOut_zd  <= data_out(7-read_cnt);
                                ELSE
                                    SOut_zd  <= 'U';
                                END IF;
                                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
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 8) THEN
                                    REPORT "Can't read suspended sector"
                                    SEVERITY NOTE;
                                    read_cnt := 0;
                                END IF;
                            END IF;
                        ELSIF (Instruct = FAST_DREAD OR
                               Instruct = FAST_DREAD_2) THEN
                            IF sect_tmp_ers /= (read_addr / 16#1000#) THEN
                                fast_rd   <= false;
                                dual_read <= true;
                                slow_read <= false;
                                quad_read <= false;
                                sr_read   <= false;
                                IF (Mem(read_addr) /= -1) THEN
                                    data_out := to_slv(Mem(read_addr),8);
                                    SOut_zd      <= data_out(7-2*read_cnt);
                                    SIOut_zd     <= data_out(6-2*read_cnt);
                                ELSE
                                    SOut_zd      <= 'U';
                                    SIOut_zd     <= 'U';
                                END IF;
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 4) THEN
                                    read_cnt := 0;
                                    IF (read_addr = AddrRANGE) THEN
                                        read_addr := 0;
                                    ELSE
                                        read_addr := read_addr + 1;
                                    END IF;
                                END IF;
                            ELSE
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 4) THEN
                                    REPORT "Can't read suspended sector"
                                    SEVERITY NOTE;
                                    read_cnt := 0;
                                END IF;
                            END IF;
                        ELSIF ((Instruct=FAST_QREAD OR Instruct=W_QREAD
                             OR Instruct=FAST_QREAD_4 OR Instruct=WOCT_QREAD)
                                AND QE = '1') THEN
                            IF sect_tmp_ers /= (read_addr / 16#1000#) THEN
                                IF ((Instruct=W_QREAD AND
                                Address mod 2 /= 0) OR
                                (Instruct=WOCT_QREAD AND
                                 Address mod 16 /=0)) THEN
                                    read_cnt := read_cnt + 1;
                                    IF (read_cnt = 2) THEN
                                        read_cnt := 0;
                                        REPORT "Bad Word Read- Wrong Address"
                                        SEVERITY NOTE;
                                    END IF;
                                ELSE
                                    fast_rd   <= false;
                                    dual_read <= false;
                                    slow_read <= false;
                                    quad_read <= true;
                                    sr_read   <= false;
                                    data_out := to_slv(Mem(read_addr),8);
                                    Addr_w    := Address;
                                    HOLDNegOut_zd <= data_out(7-4*read_cnt);
                                    WPNegOut_zd   <= data_out(6-4*read_cnt);
                                    SOut_zd       <= data_out(5-4*read_cnt);
                                    SIOut_zd      <= data_out(4-4*read_cnt);
                                    read_cnt := read_cnt + 1;
                                    IF (read_cnt = 2) THEN
                                        read_cnt := 0;
                                        IF (wrap_byte(4)='0' AND
                                           (Instruct=FAST_QREAD_4
                                           OR Instruct=W_QREAD)) THEN
                                            ADDRHILO_WRAP(AddrLo_wrap,
                                            AddrHi_wrap,Addr_w,w_size);
                                            IF (read_addr = AddrHi_wrap) THEN
                                                read_addr := AddrLo_wrap;
                                            ELSE
                                                read_addr := read_addr + 1;
                                            END IF;
                                        ELSE
                                            IF (read_addr = AddrRANGE) THEN
                                                read_addr := 0;
                                            ELSE
                                                read_addr := read_addr + 1;
                                            END IF;
                                        END IF;
                                    END IF;
                                END IF;
                            ELSE
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 2) THEN
                                    REPORT "Can't read suspended sector"
                                    SEVERITY NOTE;
                                    read_cnt := 0;
                                END IF;
                            END IF;
                        ELSIF (Instruct=RDID OR Instruct=RDID_DUAL OR
                                Instruct=RDID_QUAD) THEN
                            IF (read_addr mod 2 = 0) THEN
                                ident_out2 := to_slv(Manuf_ID,8) &
                                              to_slv(Device_ID1,8);
                            ELSE
                                ident_out2 := to_slv(Device_ID1,8) &
                                            to_slv(Manuf_ID,8);
                            END IF;
                            read_id <= true;
                            IF (Instruct = RDID) THEN
                                fast_rd   <= true;
                                dual_read <= false;
                                slow_read <= false;
                                quad_read <= false;
                                sr_read   <= false;
                                SOut_zd <= ident_out2(15-read_cnt);
                                read_cnt  := read_cnt + 1;
                                IF (read_cnt = 16) THEN
                                    read_cnt := 0;
                                END IF;
                            ELSIF (Instruct = RDID_DUAL) THEN
                                fast_rd   <= false;
                                dual_read <= true;
                                slow_read <= false;
                                quad_read <= false;
                                sr_read   <= false;
                                SOut_zd  <= ident_out2(15-2*read_cnt);
                                SIOut_zd <= ident_out2(14-2*read_cnt);
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 8) THEN
                                    read_cnt := 0;
                                END IF;
                            ELSE --  (Instruct = RDID_QUAD)
                                fast_rd   <= false;
                                dual_read <= false;
                                slow_read <= false;
                                quad_read <= true;
                                sr_read   <= false;
                                HOLDNegOut_zd <= ident_out2(15-4*read_cnt);
                                WPNegOut_zd   <= ident_out2(14-4*read_cnt);
                                SOut_zd       <= ident_out2(13-4*read_cnt);
                                SIOut_zd      <= ident_out2(12-4*read_cnt);
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 4) THEN
                                    read_cnt := 0;
                                END IF;
                            END IF;
                        ELSIF (Instruct = RD_UNIQ_ID) THEN
                        -- unique ID number is not in data sheet
                            read_id <= true;
                            uniq_id := to_slv(Unique_id_2,32)&
                                       to_slv(Unique_id_1,32);
                            SOut_zd <= uniq_id(63-read_cnt);
                            read_cnt := read_cnt + 1;
                            IF (read_cnt = 64) THEN
                                read_cnt := 0;
                            END IF;
                        ELSIF (Instruct = RDIDJ) THEN
                            read_id <= true;
                            ident_out := to_slv(Manuf_ID,8) &
                            to_slv(Device_ID2,8) & to_slv(Device_ID3,8);
                            SOut_zd <= ident_out(23-read_cnt);
                            read_cnt := read_cnt + 1;
                            IF (read_cnt = 24) THEN
                                read_cnt := 0;
                            END IF;
                        ELSIF (Instruct = RD_SFDP) THEN
--                             sfdp_addr := read_addr / 16#100#;
                            IF (read_addr / 16#100# = 0) THEN
                                Addr_tmp_2 := (read_addr mod 16#100#);
                                data_out := to_slv(SFDP_array(Addr_tmp_2),8);
                                SOut_zd  <= data_out(7-read_cnt);
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 8) THEN
                                    read_cnt := 0;
                                    IF (read_addr = SFDP_HiAddr) THEN
                                        read_addr := 0;
                                    ELSE
                                        read_addr := read_addr + 1;
                                    END IF;
                                END IF;
                            ELSE
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 8) THEN
                                    read_cnt := 0;
                                    REPORT "Given SFDP address is out of range"
                                    SEVERITY NOTE;
                                END IF;
                            END IF;
                        ELSIF (Instruct = RD_SCREG) THEN
                            Addr_tmp_2 := read_addr / 16#100#;
                            Addr_tmp_3 := read_addr mod 16#100#;
                            IF (Addr_tmp_2 = 16) THEN
                                -- Security Register No.1
                                data_out :=to_slv(Security_Reg1(Addr_tmp_3),8);
                                SOut_zd  <= data_out(7-read_cnt);
                                read_cnt := read_cnt + 1;
                            ELSIF (Addr_tmp_2 = 32) THEN
                                -- Security Register No.2
                                data_out :=to_slv(Security_Reg2(Addr_tmp_3),8);
                                SOut_zd  <= data_out(7-read_cnt);
                                read_cnt := read_cnt + 1;
                            ELSIF (Addr_tmp_2 = 48) THEN
                                -- Security Register No.2
                                data_out :=to_slv(Security_Reg3(Addr_tmp_3),8);
                                SOut_zd  <= data_out(7-read_cnt);
                                read_cnt := read_cnt + 1;
--                             END IF;
                            ELSE
                                read_cnt := read_cnt + 1;
                                IF (read_cnt = 8) THEN
                                    read_cnt := 0;
                                    REPORT "Security Reg addr is out of range"
                                    SEVERITY NOTE;
                                END IF;
                            END IF;
                            IF (read_cnt = 8) THEN
                                read_cnt := 0;
                                IF (read_addr mod 256 = SecReg_HiAddr) THEN
                                    read_addr := (read_addr/256)*
                                                (SecReg_HiAddr+1);
                                ELSE
                                    read_addr := read_addr + 1;
                                END IF;
                            END IF;
                        END IF;
                    END IF;
                END IF;

            WHEN DP_DOWN =>
                IF (oe AND Instruct = RES_RD_ID) THEN
                    read_id <= true;
                    data_out := to_slv(Device_ID1,8);
                    SOut_zd  <= data_out(7-read_cnt);
                    read_cnt := read_cnt + 1;
                    IF (read_cnt = 8) THEN
                        read_cnt := 0;
                    END IF;
                END IF;
                IF falling_edge(write) THEN
                    IF (Instruct = RES_RD_ID) THEN
                        IF res_flag = true THEN
                            RES2_in <= '1';
                        ELSE
                            RES1_in <= '1';
                        END IF;
                    ELSE
                        REPORT "Device is in DPD Mode No instructions allowed"
                        SEVERITY NOTE;
                    END IF;
                END IF;

        END CASE;

        --Output Disable Control
        IF (CSNeg_ipd = '1') THEN
            SIOut_zd        <= 'Z';
            HOLDNegOut_zd   <= 'Z';
            WPNegOut_zd     <= 'Z';
            SOut_zd         <= 'Z';
        END IF;

    END PROCESS Functional;

    ---------------------------------------------------------------------------
    -- SFDP Process
    ---------------------------------------------------------------------------
    SFDPPreload:    PROCESS

    BEGIN
        -----------------------------------------------------------------------
        --SFDP array data
        -----------------------------------------------------------------------

        SFDP_array(16#00#) := 16#53#;
        SFDP_array(16#01#) := 16#46#;
        SFDP_array(16#02#) := 16#44#;
        SFDP_array(16#03#) := 16#50#;
        SFDP_array(16#04#) := 16#01#;
        SFDP_array(16#05#) := 16#01#;
        SFDP_array(16#06#) := 16#00#;
        SFDP_array(16#07#) := 16#FF#;
        SFDP_array(16#08#) := 16#EF#;
        SFDP_array(16#09#) := 16#00#;
        SFDP_array(16#0A#) := 16#01#;
        SFDP_array(16#0B#) := 16#04#;
        SFDP_array(16#0C#) := 16#80#;
        SFDP_array(16#0D#) := 16#00#;
        SFDP_array(16#0E#) := 16#00#;
        SFDP_array(16#0F#) := 16#FF#;
        SFDP_array(16#10#) := 16#EF#;
        SFDP_array(16#11#) := 16#00#;
        SFDP_array(16#12#) := 16#01#;
        SFDP_array(16#13#) := 16#00#;
        SFDP_array(16#14#) := 16#90#;
        SFDP_array(16#15#) := 16#00#;
        SFDP_array(16#16#) := 16#00#;
        SFDP_array(16#17#) := 16#FF#;

        FOR I IN 24 TO 127 LOOP
            SFDP_array(i) := MaxData;
        END LOOP;

        SFDP_array(16#80#) := 16#E5#;
        SFDP_array(16#81#) := 16#20#;
        SFDP_array(16#82#) := 16#F1#;
        SFDP_array(16#83#) := 16#FF#;
        SFDP_array(16#84#) := 16#FF#;
        SFDP_array(16#85#) := 16#FF#;
        SFDP_array(16#86#) := 16#FF#;
        SFDP_array(16#87#) := 16#03#;
        SFDP_array(16#88#) := 16#44#;
        SFDP_array(16#89#) := 16#EB#;
        SFDP_array(16#8A#) := 16#08#;
        SFDP_array(16#8B#) := 16#6B#;
        SFDP_array(16#8C#) := 16#08#;
        SFDP_array(16#8D#) := 16#3B#;
        SFDP_array(16#8E#) := 16#80#;
        SFDP_array(16#8F#) := 16#BB#;

        FOR I IN 144 TO 255 LOOP
            SFDP_array(i) := MaxData;
        END LOOP;

        WAIT;

    END PROCESS SFDPPreload;

    ---------------------------------------------------------------------------
    -- Sector Protection Bits
    ---------------------------------------------------------------------------
    Protect : PROCESS(change_prot_bits)
    BEGIN
        IF rising_edge(change_prot_bits) THEN

            CASE BP_bits IS
                WHEN "000" =>
                    IF (CMP = '0') THEN
                        Sec_Prot := (others => '0');
                    ELSE
                        Sec_Prot := (others => '1');
                    END IF;
                WHEN "001" =>
                    IF (CMP = '0') THEN
                        IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
                                Sec_Prot(2047 downto 2016) :=
                                                        (others => '1');
                                Sec_Prot(2015 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
                                Sec_Prot(31 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 32) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
                                Sec_Prot(2047) := '1';
                                Sec_Prot(2046 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
                                Sec_Prot(0) := '1';
                                Sec_Prot(2047 downto 1) :=
                                                        (others => '0');
                        END IF;
                    ELSE
                        IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
                                Sec_Prot(2015 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 2016) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
                                Sec_Prot(2047 downto 32) :=
                                                        (others => '1');
                                Sec_Prot(31 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
                                Sec_Prot(2046 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047) := '0';

                        ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
                                Sec_Prot(2047 downto 1) :=
                                                        (others => '1');
                                Sec_Prot(0) := '0';
                        END IF;
                    END IF;
                WHEN "010"  =>
                    IF (CMP = '0') THEN
                        IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
                                Sec_Prot(2047 downto 1984) :=
                                                        (others => '1');
                                Sec_Prot(1983 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
                                Sec_Prot(63 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 64) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
                                Sec_Prot(2047 downto 2046) :=
                                                        (others => '1');
                                Sec_Prot(2045 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
                                Sec_Prot(1 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 2) :=
                                                        (others => '0');
                        END IF;
                    ELSE
                        IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
                                Sec_Prot(1983 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 1984) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
                                Sec_Prot(2047 downto 64) :=
                                                        (others => '1');
                                Sec_Prot(63 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
                                Sec_Prot(2045 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 2046) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
                                Sec_Prot(2047 downto 2) :=
                                                        (others => '1');
                                Sec_Prot(1 downto 0) :=
                                                        (others => '0');
                        END IF;
                    END IF;

                WHEN "011"  =>
                    IF (CMP = '0') THEN
                        IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
                                Sec_Prot(2047 downto 1920) :=
                                                        (others => '1');
                                Sec_Prot(1919 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
                                Sec_Prot(127 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 128) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
                                Sec_Prot(2047 downto 2044) :=
                                                        (others => '1');
                                Sec_Prot(2043 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
                                Sec_Prot(3 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 4) :=
                                                        (others => '0');
                        END IF;
                    ELSE
                        IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
                                Sec_Prot(1919 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 1920) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
                                Sec_Prot(2047 downto 128) :=
                                                        (others => '1');
                                Sec_Prot(127 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
                                Sec_Prot(2043 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 2044) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
                                Sec_Prot(2047 downto 4) :=
                                                        (others => '1');
                                Sec_Prot(3 downto 0) :=
                                                        (others => '0');
                        END IF;
                    END IF;

                    WHEN "100"  =>
                    IF (CMP = '0') THEN
                        IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
                                Sec_Prot(2047 downto 1792) :=
                                                        (others => '1');
                                Sec_Prot(1791 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
                                Sec_Prot(255 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 256) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
                                Sec_Prot(2047 downto 2040) :=
                                                        (others => '1');
                                Sec_Prot(2041 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
                                Sec_Prot(7 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 8) :=
                                                        (others => '0');
                        END IF;
                    ELSE
                        IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
                                Sec_Prot(1791 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 1792) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
                                Sec_Prot(2047 downto 256) :=
                                                        (others => '1');
                                Sec_Prot(255 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
                                Sec_Prot(2039 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 2040) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
                                Sec_Prot(2047 downto 8) :=
                                                        (others => '1');
                                Sec_Prot(7 downto 0) :=
                                                        (others => '0');
                        END IF;
                    END IF;

                WHEN "101"  =>
                    IF (CMP = '0') THEN
                            IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
                                Sec_Prot(2047 downto 1536) :=
                                                        (others => '1');
                                Sec_Prot(1535 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
                                Sec_Prot(511 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 512) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
                                Sec_Prot(2047 downto 2040) :=
                                                        (others => '1');
                                Sec_Prot(2039 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
                                Sec_Prot(7 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 8) :=
                                                        (others => '0');
                        END IF;
                    ELSE
                            IF Status_reg1(6 downto 5) = to_slv(16#00#,2) THEN
                                Sec_Prot(1535 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 1536) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#01#,2) THEN
                                Sec_Prot(2047 downto 512) :=
                                                        (others => '1');
                                Sec_Prot(511 downto 0) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#02#,2) THEN
                                Sec_Prot(2039 downto 0) :=
                                                        (others => '1');
                                Sec_Prot(2047 downto 2040) :=
                                                        (others => '0');
                        ELSIF Status_reg1(6 downto 5) = to_slv(16#03#,2) THEN
                                Sec_Prot(2047 downto 8) :=
                                                        (others => '1');
                                Sec_Prot(7 downto 0) :=
                                                        (others => '0');
                        END IF;
                    END IF;

                WHEN "110"  =>
                    IF (CMP = '0') THEN
                        IF (SEC = '0' AND TB = '0') THEN
                            Sec_Prot(2047 downto 1024) := (others => '1');
                            Sec_Prot(1023 downto 0) := (others => '0');
                        ELSIF (SEC = '0' AND TB = '1') THEN
                            Sec_Prot(1023 downto 0) := (others => '1');
                            Sec_Prot(2047 downto 1024) := (others => '0');
                        END IF;
                    ELSE
                        IF (SEC = '0' AND TB = '0') THEN
                            Sec_Prot(2047 downto 1024) := (others => '0');
                            Sec_Prot(1023 downto 0) := (others => '1');
                        ELSIF (SEC = '0' AND TB = '1') THEN
                            Sec_Prot(2047 downto 1024) := (others => '1');
                            Sec_Prot(1023 downto 0) := (others => '0');
                        END IF;
                    END IF;

                WHEN "111"  =>
                    IF (CMP = '0') THEN
                        Sec_Prot(2047 downto 0) := (others => '1');
                    ELSE
                            Sec_Prot(2047 downto 0) := (others => '0');
                    END IF;
                WHEN OTHERS =>
                        Sec_Prot := (OTHERS => '1');
            END CASE;  -- end of CASE BP_bits
        END IF;
    END PROCESS Protect;

    HOLD_FRAME_ON_PO_ZD : PROCESS(SOut_zd, SIOut_zd, HOLDNegIn)
    BEGIN
        IF (HOLDNegIn = '0' AND QE /= '1') THEN
            hold_mode := TRUE;
            SIOut_z <= 'Z';
            SOut_z  <= 'Z';
        ELSE
            IF hold_mode THEN
                SIOut_z <= SIOut_zd AFTER tpd_HOLDNeg_SO(trz0);
                SOut_z  <= SOut_zd AFTER tpd_HOLDNeg_SO(trz0);
                hold_mode := FALSE;
            ELSE
                SIOut_z <= SIOut_zd;
                SOut_z  <= SOut_zd;
                hold_mode := FALSE;
            END IF;
        END IF;
    END PROCESS HOLD_FRAME_ON_PO_ZD;

    HOLD_PULL_UP : PROCESS(HOLDNegIn)
    BEGIN
        IF (QE = '0') THEN
            IF (HOLDNegIn = 'Z') THEN
                HOLDNeg_pullup <= '1';
            ELSE
                HOLDNeg_pullup <= HOLDNegIn;
            END IF;
        END IF;
    END PROCESS HOLD_PULL_UP;

    WP_PULL_UP : PROCESS(WPNegIn)
    BEGIN
        IF (QE = '0') THEN
            IF (WPNegIn = 'Z') THEN
                WPNeg_pullup <= '1';
            ELSE
                WPNeg_pullup <= WPNegIn;
            END IF;
        END IF;
    END PROCESS WP_PULL_UP;

    ---------------------------------------------------------------------------
    ---- File Read Section - Preload Control
    ---------------------------------------------------------------------------

    MemPreload:    PROCESS
        -- text file input variables
        FILE mem_file     : text  is  mem_file_name;
        FILE screg_file   : text  is  screg_file_name;
        VARIABLE ind      : NATURAL RANGE 0 TO AddrRANGE:= 0;
        VARIABLE screg_ind: NATURAL RANGE 16#00# TO 16#2FF#:= 16#00#;
        VARIABLE buf      : line;

    BEGIN
         -- memory preload
        IF (mem_file_name (1 to 4)/= "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
                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;

        -----------------------------------------------------------------------
        -- Security Register Preload
        -----------------------------------------------------------------------

        IF (screg_file_name(1 to 4) /= "none" AND UserPreload) THEN
            ind := 0;
            Security_Reg1 := (OTHERS => MaxData);
            Security_Reg2 := (OTHERS => MaxData);
            Security_Reg3 := (OTHERS => MaxData);
            WHILE (not ENDFILE (screg_file)) LOOP
                READLINE (screg_file, buf);
                IF buf(1) = '/' THEN
                    NEXT;
                ELSIF buf(1) = '@' THEN
                    screg_ind := h(buf(2 to 4)); --address
                ELSE
                    IF screg_ind <= 16#0FF# THEN
                        Security_Reg1(screg_ind) := h(buf(1 to 2));
                    ELSIF screg_ind>=16#100# AND screg_ind<=16#1FF# THEN
                        Security_Reg2(screg_ind-16#100#) := h(buf(1 to 2));
                    ELSIF screg_ind>=16#200# AND screg_ind<=16#2FF# THEN
                        Security_Reg3(screg_ind-16#200#) := h(buf(1 to 2));
                    END IF;
                    IF (screg_ind mod 16#100#) < 16#FF# THEN
                        screg_ind := screg_ind + 1;
                    END IF;
                END IF;
            END LOOP;
        END IF;

        WAIT;
    END PROCESS MemPreload;

    ---------------------------------------------------------------------------
    -- Path Delay Section
    ---------------------------------------------------------------------------

    S_Out_PathDelay_Gen : PROCESS(SOut_z)

            VARIABLE SO_GlitchData : VitalGlitchDataType;
        BEGIN
            VitalPathDelay01Z (
                OutSignal       => SOut,
                OutSignalName   => "SO",
                OutTemp         => SOut_z,
                GlitchData      => SO_GlitchData,
                Paths           => (
                    0 => (InputChangeTime => SCK_ipd'LAST_EVENT,
                        PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0),
                        PathCondition   => SOut_z /= 'Z' AND NOT(read_id)),
                    1 => (InputChangeTime => SCK_ipd'LAST_EVENT,
                        PathDelay   => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1),
                        PathCondition   => SOut_z /= 'Z' AND read_id),
                    2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT,
                        PathDelay       => tpd_CSNeg_SO,
                        PathCondition   => CSNeg_ipd = '1'),
                    3 => (InputChangeTime => HOLDNegIn'LAST_EVENT,
                        PathDelay       => tpd_HOLDNeg_SO,
                        PathCondition   => QE = '0')
                )
            );
        END PROCESS;

    SI_Out_PathDelay : PROCESS(SIOut_z)

            VARIABLE SI_GlitchData : VitalGlitchDataType;
        BEGIN
            VitalPathDelay01Z (
                OutSignal       => SIOut,
                OutSignalName   => "SI",
                OutTemp         => SIOut_z,
                GlitchData      => SI_GlitchData,
                Paths           => (
                    0 => (InputChangeTime => SCK_ipd'LAST_EVENT,
                        PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0),
                        PathCondition => SIOut_z /= 'Z' AND NOT(read_id)),
                    1 => (InputChangeTime => SCK_ipd'LAST_EVENT,
                        PathDelay   => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1),
                        PathCondition   => SIOut_z /= 'Z' AND read_id),
                    2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT,
                        PathDelay       => tpd_CSNeg_SO,
                        PathCondition   => CSNeg_ipd = '1' AND SIOut_zd = 'Z'),
                    3 => (InputChangeTime => HOLDNegIn'LAST_EVENT,
                        PathDelay       => tpd_HOLDNeg_SO,
                        PathCondition   => SIOut_z /= 'Z' AND QE = '0')
                )
            );
        END PROCESS;

    HOLD_Out_PathDelay : PROCESS(HOLDNegOut_zd)

            VARIABLE HOLD_GlitchData : VitalGlitchDataType;
        BEGIN
            VitalPathDelay01Z (
                OutSignal       => HOLDNegOut,
                OutSignalName   => "HOLDNeg",
                OutTemp         => HOLDNegOut_zd,
                GlitchData      => HOLD_GlitchData,
                Paths           => (
                    0 => (InputChangeTime => SCK_ipd'LAST_EVENT,
                        PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0),
                        PathCondition   => HOLDNegOut_zd /= 'Z' --AND quad_read
                                           AND QE = '1' AND NOT(read_id)),
                    1 => (InputChangeTime => SCK_ipd'LAST_EVENT,
                        PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1),
                        PathCondition   => HOLDNegOut_zd /= 'Z' --AND quad_read
                                           AND QE = '1' AND read_id),
                    2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT,
                        PathDelay       => tpd_CSNeg_SO,
                        PathCondition   => CSNeg_ipd = '1' AND --quad_read AND
                                           HOLDNegOut_zd = 'Z' AND QE = '1')
                )
            );
        END PROCESS;

    WP_Out_PathDelay : PROCESS(WPNegOut_zd)

            VARIABLE WP_GlitchData : VitalGlitchDataType;
        BEGIN
            VitalPathDelay01Z (
                OutSignal       => WPNegOut,
                OutSignalName   => "WPNeg",
                OutTemp         => WPNegOut_zd,
                GlitchData      => WP_GlitchData,
                Paths           => (
                    0 => (InputChangeTime => SCK_ipd'LAST_EVENT,
                        PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_0),
                        PathCondition   => WPNegOut_zd /= 'Z' --AND quad_read
                                           AND QE = '1' AND NOT(read_id)),
                    1 => (InputChangeTime => SCK_ipd'LAST_EVENT,
                        PathDelay => VitalExtendtofillDelay(tpd_SCK_SO_RDID_EQ_1),
                        PathCondition   => WPNegOut_zd /= 'Z' -- AND quad_read
                                           AND QE = '1' AND read_id),
                    2 => (InputChangeTime => CSNeg_ipd'LAST_EVENT,
                        PathDelay       => tpd_CSNeg_SO,
                        PathCondition   => CSNeg_ipd = '1' AND --quad_read AND
                                           WPNegOut_zd = 'Z' AND QE = '1')
                )
            );
        END PROCESS;

    END BLOCK behavior;
END vhdl_behavioral;