//////////////////////////////////////////////////////////////////////////////
//  File name : s25fl032p.v
//////////////////////////////////////////////////////////////////////////////
//  Copyright (C) 2011 Spansion, LLC.
//
//  MODIFICATION HISTORY :
//
//  version: |   author:      |  mod date: | changes made:
//    V1.0     D.Stanojkovic     08 Jan 22   Inital Release
//    V1.1     D.Stanojkovic     08 Feb 20   BP bits setting corrected
//    V1.2     D.Stanojkovic     08 Mar 05   MPM mode corrected
//    V1.3     D.Stanojkovic     08 Mar 20   MPM mode removed
//    V1.4     J.Stoickov        08 Aug 07   WEL bit corrected
//    V1.5     J.Stoickov        08 Sep 16   Latest datasheet aligned
//    V1.6     J.Stoickov        08 Dec 10   Latest datasheet aligned
//                                            (S25FL129 064 032P)
//                                          Program Error bit will not be
//                                          set after programming in
//                                          protect memory region
//    V1.7     V.Mancev          10 Sep 29   Implementation of internal pull-up
//                                           for HOLDNeg and WPNeg pins
//    V1.8     V.Mancev          11 Dec 15   Latest datasheet aligned
//                                                (S25FL032P_00_05)
//////////////////////////////////////////////////////////////////////////////
//  PART DESCRIPTION:
//
//  Library:    FLASH
//  Technology: FLASH MEMORY
//  Part:       S25FL032P
//
//  Description: 32 Megabit Serial Flash Memory with 104 MHz SPI Bus Interface
//  Comments :
//      For correct simulation, simulator resolution should be set to 1 ps
//
//////////////////////////////////////////////////////////////////////////////
//  Known Bugs:
//
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
// MODULE DECLARATION                                                       //
//////////////////////////////////////////////////////////////////////////////
`timescale 1 ps/1 ps

module s25fl032p
(
    SCK      ,
    SI       ,
    CSNeg    ,
    HOLDNeg  ,
    WPNeg    ,
    SO
);
////////////////////////////////////////////////////////////////////////
// Port / Part SOIn Declarations
////////////////////////////////////////////////////////////////////////
    input  SCK     ;
    inout  SI      ;

    input  CSNeg   ;
    inout  HOLDNeg ;
    inout  WPNeg   ;
    inout  SO      ;

// interconnect path delay signals
    wire  SCK_ipd           ;
    wire  SI_ipd            ;

    wire  SI_in             ;
    assign SI_in = SI_ipd   ;

    wire  SI_out            ;
    assign SI_out = SI      ;

    wire  CSNeg_ipd    ;
    wire  HOLDNeg_ipd  ;
    wire  WPNeg_ipd    ;
    wire  SO_ipd       ;

    wire HOLDNeg_in                  ;
    //Internal pull-up
    assign HOLDNeg_in = (HOLDNeg_ipd === 1'bx) ? 1'b1 : HOLDNeg_ipd;

    wire   HOLDNeg_out               ;
    assign HOLDNeg_out = HOLDNeg     ;

    wire   WPNeg_in                  ;
    //Internal pull-up
    assign WPNeg_in = (WPNeg_ipd === 1'bx) ? 1'b1 : WPNeg_ipd;

    wire   WPNeg_out                 ;
    assign WPNeg_out = WPNeg         ;

    wire  SOIn               ;
    assign SOIn = SO_ipd     ;

    wire  SOut              ;
    assign SOut = SO        ;

//  internal delays
    reg PP_in       ;
    reg PP_out      ;
    reg PU_in       ;
    reg PU_out      ;
    reg SE_in       ;
    reg SE_out      ;
    reg BE_in       ;
    reg BE_out      ;
    reg PE_in       ;
    reg PE_out      ;
    reg WR_in       ;
    reg WR_out      ;
    reg DP_in       ;
    reg DP_out      ;
    reg EP_in       ;
    reg EP_out      ;
    reg RES_in      ;
    reg RES_out     ;

    reg SOut_zd = 1'bZ;
    reg SOut_z  = 1'bZ;

    wire  SI_z              ;
    wire  SO_z              ;

    reg SIOut_zd = 1'bZ     ;
    reg SIOut_z  = 1'bZ     ;

    reg WPNegOut_zd   = 1'bZ  ;
    reg HOLDNegOut_zd = 1'bZ  ;

    assign SI_z = SIOut_z;
    assign SO_z = SOut_z;

    parameter UserPreload       = 1;
    parameter mem_file_name     = "none";//"s25fl032p.mem";
    parameter otp_file_name     = "none";//"s25fl032p_secsi.mem";

    parameter TimingModel   = "DefaultTimingModel";

    parameter PartID        = "s25fl032p";
    parameter MaxData       = 255;
    parameter SecSize       = 16'hFFFF;
    parameter SecSize_4     = 4095;
    parameter SecSize_8     = 8191;
    parameter SecNum        = 63;
    parameter PageNum       = 16'h3FFF;
    parameter OTPSize       = 511;
    parameter OTPLoAddr     = 9'h100;
    parameter OTPHiAddr     = 10'h2FF;
    parameter HiAddrBit     = 23;
    parameter AddrRANGE     = 24'h3FFFFF;
    parameter BYTE          = 8;
    parameter Manuf_ID      = 8'h01;
    parameter ES            = 8'h15;
    parameter Jedec_ID      = 8'h20; // first byte of Device ID
    parameter DeviceID      = 16'h0215;
    parameter ExtendedBytes = 8'h4D;
    parameter ReservedBytes = 8'h00;

    // If speed simulation is needed uncomment following line

//     `define SPEEDSIM;

    // powerup
    reg PoweredUp;

    //FSM control signals
    reg PDONE    ; ////Prog. Done
    reg PSTART   ; ////Start Programming

    reg EDONE    ; ////Era. Done
    reg ESTART   ; ////Start Erasing

    reg WDONE    ; //// Writing Done
    reg WSTART   ; ////Start writing

    //Command Register
    reg write;
    reg cfg_write;
    reg read_out;

    //Status reg.
    reg[7:0] Status_reg      = 8'b0;
    reg[7:0] Status_reg_in   = 8'b0;
    reg[7:0] Sec_conf_reg    = 8'b0;
    reg[7:0] Sec_conf_reg_in = 8'b0;

    wire FREEZE;
    wire QUAD;
    wire TBPARM;
    wire BPNV;
    wire TBPROT;
    assign FREEZE   = Sec_conf_reg[0];
    assign QUAD     = Sec_conf_reg[1];
    assign TBPARM  = Sec_conf_reg[2];
    assign BPNV     = Sec_conf_reg[3];
    assign TBPROT   = Sec_conf_reg[5];

    wire WIP;
    wire WEL;
    wire [2:0]BP;
    wire E_ERR;
    wire P_ERR;
    wire SRWD;
    assign WIP      = Status_reg[0];
    assign WEL      = Status_reg[1];
    assign BP       = Status_reg[4:2];
    assign E_ERR    = Status_reg[5];
    assign P_ERR    = Status_reg[6];
    assign SRWD     = Status_reg[7];

    integer SA          = 0;         // 0 TO SecNum+1
    integer Byte_number = 0;
    integer sect;

    //Address
    integer Address = 0;         // 0 - AddrRANGE
    reg  change_addr;
    reg  rd_fast;       // = 1'b1;
    reg  rd_slow;
    reg  rd_jedec;
    reg  change_BP = 0;
    reg  rd_dual;
    reg  dual;
    wire fast_rd;
    wire rd;
    wire rd_jid;

    wire RD_EQU_1;
    assign RD_EQU_1 = rd_slow;

    wire RD_EQU_0;
    assign RD_EQU_0 = ~rd_slow;

    reg  hold_mode;
    reg  mpm_mode = 0;
    wire hold;

    //Sector Protection Status
    reg [SecNum:0] Sec_Prot = 64'b0; //= SecNum'b0;

    // timing check violation
    reg Viol = 1'b0;

    integer Mem[0:AddrRANGE];
    integer OTPMem[OTPLoAddr: OTPHiAddr];

    integer WByte[0:255];
    integer WOTPByte;
    integer AddrLo;
    integer AddrHi;

    reg[7:0]  old_bit, new_bit;
    integer old_int, new_int;
    integer wr_cnt;
    integer cnt;

    integer read_cnt = 0;
    integer read_addr = 0;
    reg[7:0] data_out;
    reg[647:0] ident_out;

    reg oe = 1'b0;
    event oe_event;

    integer CFI_array[8'h07:8'h50];
    reg [591:0] CFI_array_tmp;
    reg [7:0] CFI_tmp;

    reg[15:0] PR_LOCK1;
    reg[15:0] PR_LOCK2;
    reg[15:0] PR_LOCK3;

///////////////////////////////////////////////////////////////////////////////
//Interconnect Path Delay Section
///////////////////////////////////////////////////////////////////////////////

 buf   (SCK_ipd, SCK);
 buf   (SI_ipd, SI);

 buf   (CSNeg_ipd, CSNeg);
 buf   (HOLDNeg_ipd, HOLDNeg);
 buf   (WPNeg_ipd, WPNeg);
 buf   (SO_ipd, SO);

///////////////////////////////////////////////////////////////////////////////
// Propagation  delay Section
///////////////////////////////////////////////////////////////////////////////
    nmos   (SO,   SO_z , 1);

    nmos   (SI,   SI_z , 1);
    nmos   (HOLDNeg,   HOLDNegOut_zd , 1);
    nmos   (WPNeg,   WPNegOut_zd , 1);

    wire deg_pin;
    wire deg_sin;
    wire deg_holdin;
    //VHDL VITAL CheckEnable equivalents
    wire dual_wr;
    assign dual_wr = deg_holdin && QUAD;
    wire dual_rd;
    assign dual_rd = dual;
    wire quad_wr;
    assign quad_wr = SRWD && WEL ;
    wire power;
    assign power = PoweredUp;

 specify
        // tipd delays: interconnect path delays , mapped to input port delays.
        // In Verilog is not necessary to declare any tipd_ delay variables,
        // they can be taken from SDF file
        // With all the other delays real delays would be taken from SDF file

                        // tpd delays
     specparam           tpd_SCK_SO             =1;
     specparam           tpd_SCK_SI             =1;
     specparam           tpd_CSNeg_SO           =1;
     specparam           tpd_HOLDNeg_SO         =1;

     specparam           tsetup_SI_SCK          =1;   //tsuDAT /
     specparam           tsetup_CSNeg_SCK       =1;   // tCSS /
     specparam           tsetup_HOLDNeg_SCK     =1;   //tHD /
     specparam           tsetup_SCK_HOLDNeg     =1;   //tCH \
     specparam           tsetup_WPNeg_CSNeg      =1;   //tWPS \

                          // thold values: hold times
     specparam           thold_SI_SCK           =1; //thdDAT /
     specparam           thold_CSNeg_SCK        =1; //tCSH /
     specparam           thold_HOLDNeg_SCK      =1; //tCHHH /
     specparam           thold_SCK_HOLDNeg      =1; //tHC \
     specparam           thold_WPNeg_CSNeg       =1; //tWPH \

        // tpw values: pulse width
     specparam           tpw_SCK_fast_posedge    =1; //tWH
     specparam           tpw_SCK_posedge         =1; //tWH
     specparam           tpw_SCK_dual_posedge    =1; //tWH
     specparam           tpw_SCK_rdid_posedge    =1; //tWH
     specparam           tpw_SCK_fast_negedge    =1; //tWL
     specparam           tpw_SCK_negedge         =1; //tWL
     specparam           tpw_SCK_dual_negedge    =1; //tWL
     specparam           tpw_SCK_rdid_negedge    =1; //tWL
     specparam           tpw_CSNeg_read_posedge  =1; //tCS
     specparam           tpw_CSNeg_pgm_posedge   =1; //tCS

        // tperiod min (calculated as 1/max freq)
     specparam           tperiod_SCK_rd              =1; // fSCK = 40MHz
     specparam           tperiod_SCK_fast_rd         =1; // fSCK = 104MHz
     specparam           tperiod_SCK_dual_fast_rd    =1; // fSCK = 80MHz
     specparam           tperiod_SCK_rdid            =1; // fSCK = 50MHz

        // tdevice values: values for internal delays
        `ifdef SPEEDSIM
            // Page Program Operation
            specparam   tdevice_PP                     = 3e7; //30 us;
                    //Page Program Operation (ACC=9V))
            specparam   tdevice_EP                     = 2.4e9; //2.4 ms;
                    //Sector Erase Operation
            specparam   tdevice_SE                     = 2e9; //2 ms;
                    //Bulk Erase Operation
            specparam   tdevice_BE                     = 64e9; //64 ms;
                    //Write Status Register Operation
            specparam   tdevice_WR                     = 5e8; // 0.5 ms;
                    //Software Protect Mode
            specparam   tdevice_DP                     = 10000000; // 10 us;
                    //Release from Software Protect Mode
            specparam   tdevice_RES                    = 30000000; // 30 us;
                    //Parameter block erase
            specparam   tdevice_PE                     = 800e6; //800 us;
                    //VCC (min) to CS# Low
            specparam   tdevice_PU                     = 300000000; //300 us;
        `else
            // Page Program Operation
            specparam   tdevice_PP                     = 3e9; //3 ms;
                    //Page Program Operation (ACC=9V))
            specparam   tdevice_EP                     = 2.4e9; //2.4 ms;
                    //Sector Erase Operation
            specparam   tdevice_SE                     = 2e12; //2 s;
                    //Bulk Erase Operation
            specparam   tdevice_BE                     = 64e12; //64 sec;
                    //Write Status Register Operation
            specparam   tdevice_WR                     = 50e9; // 50 ms;
                    //Software Protect Mode
            specparam   tdevice_DP                     = 10000000; // 10 us;
                    //Release from Software Protect Mode
            specparam   tdevice_RES                    = 30000000; // 30 us;
                    //Parameter block erase
            specparam   tdevice_PE                     = 800e9; //800 ms;
                    //VCC (min) to CS# Low
            specparam   tdevice_PU                     = 300000000; //300 us;
        `endif//SPEEDSIM

///////////////////////////////////////////////////////////////////////////////
// Input Port  Delays  don't require Verilog description
///////////////////////////////////////////////////////////////////////////////
// Path delays                                                               //
///////////////////////////////////////////////////////////////////////////////
  if (~dual) (SCK => SO) = tpd_SCK_SO;
  if (dual)  (SCK => SO) = tpd_SCK_SI;
  if (CSNeg)(CSNeg => SO) = tpd_CSNeg_SO;
  if (~dual) (HOLDNeg => SO) = tpd_HOLDNeg_SO;
  if (dual)  (HOLDNeg => SO) = tpd_HOLDNeg_SO;

  if (dual)(SCK => SI) = tpd_SCK_SI;
  if (dual && CSNeg)(CSNeg => SI) = tpd_CSNeg_SO;
  if (dual)(HOLDNeg => SI) = tpd_HOLDNeg_SO;

  if (dual && QUAD)(SCK => HOLDNeg) = tpd_SCK_SI;
  if (dual && CSNeg && QUAD)(CSNeg => HOLDNeg) = tpd_CSNeg_SO;

  if (dual && QUAD)(SCK => WPNeg) = tpd_SCK_SI;
  if (dual && CSNeg && QUAD)(CSNeg => WPNeg) = tpd_CSNeg_SO;
////////////////////////////////////////////////////////////////////////////////
// Timing Violation                                                           //
////////////////////////////////////////////////////////////////////////////////
        $setup ( SI             , posedge SCK &&& deg_sin,
                                                tsetup_SI_SCK, Viol);
        $setup ( negedge HOLDNeg, posedge SCK &&& dual_wr,
                                                tsetup_HOLDNeg_SCK, Viol);
        $setup ( posedge SCK    , posedge HOLDNeg &&& dual_wr,
                                                tsetup_SCK_HOLDNeg, Viol);
        $setup ( CSNeg          , posedge SCK &&& power,
                                                tsetup_CSNeg_SCK, Viol);
        $setup ( WPNeg          , negedge CSNeg &&& WPNeg,
                                                tsetup_WPNeg_CSNeg, Viol);

        $hold ( posedge SCK     , SI &&& deg_sin,
                                                thold_SI_SCK, Viol);
        $hold ( posedge HOLDNeg , posedge SCK &&& dual_wr,
                                                thold_SCK_HOLDNeg, Viol);
        $hold ( posedge SCK     , CSNeg &&& power,
                                                thold_CSNeg_SCK, Viol);
        $hold ( posedge CSNeg   , WPNeg &&& quad_wr,
                                                thold_WPNeg_CSNeg, Viol);
        $hold ( posedge SCK     , negedge HOLDNeg &&& dual_wr,
                                                thold_HOLDNeg_SCK, Viol);

        $width (posedge SCK &&& rd      , tpw_SCK_posedge);
        $width (posedge SCK &&& fast_rd , tpw_SCK_fast_posedge);
        $width (posedge SCK &&& dual_rd , tpw_SCK_dual_posedge);
        $width (posedge SCK &&& rd_jid  , tpw_SCK_rdid_posedge);
        $width (negedge SCK &&& rd      , tpw_SCK_negedge);
        $width (negedge SCK &&& fast_rd , tpw_SCK_fast_negedge);
        $width (negedge SCK &&& dual_rd , tpw_SCK_dual_negedge);
        $width (negedge SCK &&& rd_jid  , tpw_SCK_rdid_negedge);

        $width (posedge CSNeg &&& RD_EQU_0, tpw_CSNeg_pgm_posedge);
        $width (posedge CSNeg &&& RD_EQU_1, tpw_CSNeg_read_posedge);

        $period (posedge SCK &&& rd, tperiod_SCK_rd);
        $period (posedge SCK &&& fast_rd, tperiod_SCK_fast_rd);
        $period (posedge SCK &&& dual_rd, tperiod_SCK_dual_fast_rd);
        $period (posedge SCK &&& rd_jid,  tperiod_SCK_rdid);

    endspecify

////////////////////////////////////////////////////////////////////////////////
// Main Behavior Block                                                        //
////////////////////////////////////////////////////////////////////////////////
// FSM states
 parameter IDLE            =4'd0;
 parameter WRITE_SR        =4'd1;
 parameter DP_DOWN_WAIT    =4'd2;
 parameter DP_DOWN         =4'd3;
 parameter SECTOR_ER       =4'd4;
 parameter BULK_ER         =4'd5;
 parameter PAGE_PG         =4'd6;
 parameter OTP_PG          =4'd7;
 parameter P4_ER           =4'd8;
 parameter P8_ER           =4'd9;

 reg [3:0] current_state;
 reg [3:0] next_state;

// Instructions
 parameter NONE            =5'd0;
 parameter WREN            =5'd1;
 parameter WRDI            =5'd2;
 parameter WRR             =5'd3;
 parameter RDSR            =5'd4;
 parameter READ            =5'd5;
 parameter READ_ID         =5'd6;
 parameter RDID            =5'd7;
 parameter FAST_READ       =5'd8;
 parameter DUAL_READ       =5'd9;
 parameter QUAD_READ       =5'd10;
 parameter DH_READ         =5'd11;
 parameter QH_READ         =5'd12;
 parameter SE              =5'd13;
 parameter BE              =5'd14;
 parameter PP              =5'd15;
 parameter QPP             =5'd16;
 parameter DP              =5'd17;
 parameter RES_READ_ES     =5'd18;
 parameter CLSR            =5'd19;
 parameter RCR             =5'd20;
 parameter P4E             =5'd21;
 parameter P8E             =5'd22;
 parameter OTPP            =5'd23;
 parameter OTPR            =5'd24;
 reg [4:0] Instruct;

//Bus cycle states
 parameter STAND_BY        =3'd0;
 parameter CODE_BYTE       =3'd1;
 parameter ADDRESS_BYTES   =3'd2;
 parameter DUMMY_BYTES     =3'd3;
 parameter MODE_BYTE       =3'd4;
 parameter DATA_BYTES      =3'd5;

 reg [2:0] bus_cycle_state;

 reg deq_pin;
    always @(SOIn, SO_z)
    begin
      if (SOIn==SO_z)
        deq_pin=1'b0;
      else
        deq_pin=1'b1;
    end
    // chech when data is generated from model to avoid setuphold check in
    // those occasion
    assign deg_pin=deq_pin;

 reg deq_sin;
    always @(SI_in, SIOut_z)
    begin
      if (SI_in==SIOut_z)
        deq_sin=1'b0;
      else
        deq_sin=1'b1;
    end
    // chech when data is generated from model to avoid setuphold check in
    // those occasion
    assign deg_sin=deq_sin;

 reg deq_holdin;
    always @(HOLDNeg_ipd, HOLDNegOut_zd)
    begin
      if (HOLDNeg_ipd==HOLDNegOut_zd)
        deq_holdin=1'b0;
      else
        deq_holdin=1'b1;
    end
    // check when data is generated from model to avoid setuphold check in
    // those occasion
    assign deg_holdin=deq_holdin;

    initial
    begin : Init

        write       = 1'b0;
        cfg_write   = 1'b0;
        read_out    = 1'b0;
        Address     = 0;
        change_addr = 1'b0;

        PDONE       = 1'b1;
        PSTART      = 1'b0;

        EDONE       = 1'b1;
        ESTART      = 1'b0;

        WDONE       = 1'b1;
        WSTART      = 1'b0;

        DP_in       = 1'b0;
        DP_out      = 1'b0;
        RES_in      = 1'b0;
        RES_out     = 1'b0;
        Instruct    = NONE;

        bus_cycle_state = STAND_BY;
        current_state   = IDLE;
        next_state      = IDLE;
    end

    //CFI
    initial
    begin: InitCFI
    integer i;
    integer j;

            CFI_array[8'h07] = 8'hFF;
            CFI_array[8'h08] = 8'hFF;
            CFI_array[8'h09] = 8'hFF;
            CFI_array[8'h0A] = 8'hFF;
            CFI_array[8'h0B] = 8'hFF;
            CFI_array[8'h0C] = 8'hFF;
            CFI_array[8'h0D] = 8'hFF;
            CFI_array[8'h0E] = 8'hFF;
            CFI_array[8'h0F] = 8'hFF;
            CFI_array[8'h10] = 8'h51;
            CFI_array[8'h11] = 8'h52;
            CFI_array[8'h12] = 8'h59;
            CFI_array[8'h13] = 8'h02;
            CFI_array[8'h14] = 8'h00;
            CFI_array[8'h15] = 8'h40;
            CFI_array[8'h16] = 8'h00;
            CFI_array[8'h17] = 8'h00;
            CFI_array[8'h18] = 8'h00;
            CFI_array[8'h19] = 8'h00;
            CFI_array[8'h1A] = 8'h00;
            //System interface string
            CFI_array[8'h1B] = 8'h27;
            CFI_array[8'h1C] = 8'h36;
            CFI_array[8'h1D] = 8'h00;
            CFI_array[8'h1E] = 8'h00;
            CFI_array[8'h1F] = 8'h0B;
            CFI_array[8'h20] = 8'h0B;
            CFI_array[8'h21] = 8'h09;
            CFI_array[8'h22] = 8'h0F;
            CFI_array[8'h23] = 8'h01;
            CFI_array[8'h24] = 8'h01;
            CFI_array[8'h25] = 8'h02;
            CFI_array[8'h26] = 8'h01;
            //device geometry definition
            CFI_array[8'h27] = 8'h16;
            CFI_array[8'h28] = 8'h05;
            CFI_array[8'h29] = 8'h05;
            CFI_array[8'h2A] = 8'h08;
            CFI_array[8'h2B] = 8'h00;
            CFI_array[8'h2C] = 8'h02;
            CFI_array[8'h2D] = 8'h1F;
            CFI_array[8'h2E] = 8'h00;
            CFI_array[8'h2F] = 8'h10;
            CFI_array[8'h30] = 8'h00;
            CFI_array[8'h31] = 8'h3D;
            CFI_array[8'h32] = 8'h00;
            CFI_array[8'h33] = 8'h00;
            CFI_array[8'h34] = 8'h01;
            CFI_array[8'h35] = 8'h00;
            CFI_array[8'h36] = 8'h00;
            CFI_array[8'h37] = 8'h00;
            CFI_array[8'h38] = 8'h00;
            CFI_array[8'h39] = 8'h00;
            CFI_array[8'h3A] = 8'h00;
            CFI_array[8'h3B] = 8'h00;
            CFI_array[8'h3C] = 8'h00;
            CFI_array[8'h3D] = 8'hFF;
            CFI_array[8'h3E] = 8'hFF;
            CFI_array[8'h3F] = 8'hFF;
            //primary vendor-specific extended query
            CFI_array[8'h40] = 8'h50;
            CFI_array[8'h41] = 8'h52;
            CFI_array[8'h42] = 8'h49;
            CFI_array[8'h43] = 8'h31;
            CFI_array[8'h44] = 8'h33;
            CFI_array[8'h45] = 8'h15;
            CFI_array[8'h46] = 8'h00;
            CFI_array[8'h47] = 8'h01;
            CFI_array[8'h48] = 8'h00;
            CFI_array[8'h49] = 8'h05;
            CFI_array[8'h4A] = 8'h00;
            CFI_array[8'h4B] = 8'h01;
            CFI_array[8'h4C] = 8'h03;
            CFI_array[8'h4D] = 8'h85;
            CFI_array[8'h4E] = 8'h95;
            CFI_array[8'h4F] = 8'h07;
            CFI_array[8'h50] = 8'h00;

            for(i=73;i>=0;i=i-1)
            begin
                CFI_tmp = CFI_array[8'h07-i+73];
                for(j=7;j>=0;j=j-1)
                begin
                    CFI_array_tmp[8*i+j] = CFI_tmp[j];
                end
            end
    end

    // initialize memory
    initial
    begin: InitMemory
    integer i;

        for (i=0;i<=AddrRANGE;i=i+1)
        begin
            Mem[i] = MaxData;
        end

        if ((UserPreload) && !(mem_file_name == "none"))
        begin
           // Memory Preload
           // s25fl032p.mem, memory preload file
           //  @aaaaaa - <aaaaaa> stands for address
           //  dd      - <dd> is byte to be written at Mem(aaaaaa++)
           // (aaaaaa is incremented at every load)
           $readmemh(mem_file_name,Mem);
        end

        for (i=OTPLoAddr;i<=OTPHiAddr;i=i+1)
        begin
            OTPMem[i] = MaxData;
        end
        if (UserPreload && !(otp_file_name == "none"))
        begin
        //s25fl032p_secsi memory file
        //   /       - comment
        //   @aaaaaa     - <aaaaaa> stands for address within last defined
        //   sector
        //   dd      - <dd> is byte to be written at SecSi(aaaaaa++)
        //   (aa is incremented at every load)
        //   only first 1-5 columns are loaded. NO empty lines !!!!!!!!!!!!!!!!
           $readmemh(otp_file_name,OTPMem);
        end
        PR_LOCK1[15:8] = 16'h0;
        PR_LOCK1[7:0]  = OTPMem[256];

        PR_LOCK2[15:8] = OTPMem[275];
        PR_LOCK2[7:0]  = OTPMem[274];

        PR_LOCK3[15:8] = OTPMem[533];
        PR_LOCK3[7:0]  = OTPMem[532];
    end

    //Power Up time;
    initial
    begin
        PoweredUp = 1'b0;
        #tdevice_PU PoweredUp = 1'b1;
    end

   always @(posedge DP_in)
   begin:TDPr
     #tdevice_DP DP_out = DP_in;
   end
   always @(negedge DP_in)
   begin:TDPf
     #1 DP_out = DP_in;
   end

   always @(posedge RES_in)
   begin:TRESr
     #tdevice_RES RES_out = RES_in;
   end
   always @(negedge RES_in)
   begin:TRESf
     #1 RES_out = RES_in;
   end

   always @(next_state or PoweredUp)
   begin: StateTransition
       if (PoweredUp)
       begin
           current_state = next_state;
       end
   end

   always @(negedge CSNeg_ipd)
   begin:CheckCSOnPowerUP
       if (~PoweredUp)
           $display ("Device is selected during Power Up");
   end

//   ///////////////////////////////////////////////////////////////////////////
//   // Instruction cycle decode
//   ///////////////////////////////////////////////////////////////////////////
 integer data_cnt   = 0;
 integer addr_cnt   = 0;
 integer code_cnt   = 0;
 integer mode_cnt   = 0;
 integer dummy_cnt  = 0;
 integer bit_cnt    = 0;

 reg[2047:0] Data_in = 2048'b0;
 integer quad_data_in [0:511];
 reg[3:0] quad_nybble = 4'b0;
 reg[3:0] Quad_slv = 4'b0;
 reg[7:0] code = 8'b0;
 reg[7:0] code_in = 8'b0;
 reg[7:0] Byte_slv = 8'b0;
 reg[HiAddrBit:0] addr_bytes;
 reg[23:0] Address_in = 8'b0;
 reg[7:0] mode_bytes;
 reg[7:0] mode_in;

 reg rising_edge_CSNeg_ipd  = 1'b0;
 reg falling_edge_CSNeg_ipd = 1'b0;
 reg rising_edge_SCK_ipd    = 1'b0;
 reg falling_edge_SCK_ipd   = 1'b0;

    always @(falling_edge_CSNeg_ipd or rising_edge_CSNeg_ipd
    or rising_edge_SCK_ipd or falling_edge_SCK_ipd)
    begin: Buscycle1
        integer i;
        integer j;
        integer k;
        if (falling_edge_CSNeg_ipd)
        begin
            if (bus_cycle_state==STAND_BY)
            begin
                bus_cycle_state = CODE_BYTE;
                Instruct = NONE;
                write = 1'b1;
                code_cnt = 0;
                addr_cnt = 0;
                data_cnt = 0;
                mode_cnt = 0;
                dummy_cnt = 0;
            end
        end

        if (rising_edge_SCK_ipd)
        begin
            if (~CSNeg_ipd)
            begin
                case (bus_cycle_state)
                    CODE_BYTE :
                    begin
                        if ((HOLDNeg_in && ~QUAD) || QUAD)
                        begin
                            code_in[code_cnt] = SI_in;
                            code_cnt = code_cnt + 1;
                            if (code_cnt == BYTE)
                            begin
                                for (i=0;i<=7;i=i+1)
                                begin
                                    code[i] = code_in[7-i];
                                end
                                case(code)
                                    8'b00000110 :
                                    begin
                                        Instruct = WREN;
                                        bus_cycle_state = DATA_BYTES;
                                    end
                                    8'b00000100 :
                                    begin
                                        Instruct = WRDI;
                                        bus_cycle_state = DATA_BYTES;
                                    end
                                    8'b00000001 :
                                    begin
                                        Instruct = WRR;
                                        bus_cycle_state = DATA_BYTES;
                                    end
                                    8'b00000101 :
                                    begin
                                        Instruct = RDSR;
                                        bus_cycle_state = DATA_BYTES;
                                    end
                                    8'b00000011 :
                                    begin
                                        Instruct = READ;
                                        bus_cycle_state = ADDRESS_BYTES;
                                    end
                                    8'b00001011 :
                                    begin
                                        Instruct = FAST_READ;
                                        bus_cycle_state = ADDRESS_BYTES;
                                    end
                                    8'b10011111 :
                                    begin
                                        Instruct = RDID;
                                        bus_cycle_state = DATA_BYTES;
                                    end
                                    8'b10010000 :
                                    begin
                                        Instruct = READ_ID;
                                        bus_cycle_state = ADDRESS_BYTES;
                                    end
                                    8'b10101011 :
                                    begin
                                        Instruct = RES_READ_ES;
                                        bus_cycle_state = DUMMY_BYTES;
                                    end
                                    8'b11011000 :
                                    begin
                                        Instruct = SE;
                                        bus_cycle_state = ADDRESS_BYTES;
                                    end
                                    8'b11000111 , 8'b01100000:
                                    begin
                                        Instruct = BE;
                                        bus_cycle_state = DATA_BYTES;
                                    end
                                    8'b00000010 :
                                    begin
                                        Instruct = PP;
                                        bus_cycle_state = ADDRESS_BYTES;
                                    end
                                    8'b00110010 :
                                    begin
                                        Instruct = QPP;
                                        bus_cycle_state = ADDRESS_BYTES;
                                    end
                                    8'b10111001 :
                                    begin
                                        Instruct = DP;
                                        bus_cycle_state = DATA_BYTES;
                                    end
                                    8'b00110000 :
                                    begin
                                        Instruct = CLSR;
                                        bus_cycle_state = DATA_BYTES;
                                    end
                                    8'b00110101 :
                                    begin
                                        Instruct = RCR;
                                        bus_cycle_state = DATA_BYTES;
                                    end
                                    8'b00100000 :
                                    begin
                                        Instruct = P4E;
                                        bus_cycle_state = ADDRESS_BYTES;
                                    end
                                    8'b01000000 :
                                    begin
                                        Instruct = P8E;
                                        bus_cycle_state = ADDRESS_BYTES;
                                    end
                                    8'b01000010 :
                                    begin
                                        Instruct = OTPP;
                                        bus_cycle_state = ADDRESS_BYTES;
                                    end
                                    8'b01001011 :
                                    begin
                                        Instruct = OTPR;
                                        bus_cycle_state = ADDRESS_BYTES;
                                    end
                                    8'b00111011 :
                                    begin
                                        Instruct = DUAL_READ;
                                        bus_cycle_state = ADDRESS_BYTES;
                                    end
                                    8'b01101011 :
                                    begin
                                        Instruct = QUAD_READ;
                                        bus_cycle_state = ADDRESS_BYTES;
                                    end
                                    8'b10111011 :
                                    begin
                                        Instruct = DH_READ;
                                        bus_cycle_state = ADDRESS_BYTES;
                                    end
                                    8'b11101011 :
                                    begin
                                        Instruct = QH_READ;
                                        bus_cycle_state = ADDRESS_BYTES;
                                    end
                                endcase
                            end
                        end
                    end

                    ADDRESS_BYTES :
                    begin
                        if (((Instruct == FAST_READ || Instruct == OTPR ||
                            Instruct == DUAL_READ) &&
                            ((HOLDNeg_in && ~QUAD) || QUAD)) ||
                            ((Instruct == QUAD_READ) && QUAD))
                        begin
                            Address_in[addr_cnt] = SI_in;
                            addr_cnt = addr_cnt + 1;
                            if (addr_cnt == 3*BYTE)
                            begin
                                for (i=23;i>=23-HiAddrBit;i=i-1)
                                begin
                                    addr_bytes[23-i] = Address_in[i];
                                end
                                Address = addr_bytes;
                                change_addr = 1'b1;
                                #1 change_addr = 1'b0;
                                bus_cycle_state = DUMMY_BYTES;
                            end
                        end
                        else if (Instruct == DH_READ &&
                                ((HOLDNeg_in && ~QUAD) || QUAD))
                        begin
                            if (SOIn !== 1'b0 && SOIn !== 1'b1)
                            begin
                                mpm_mode = 0;
                                bus_cycle_state = STAND_BY;
                            end
                            else
                            begin
                                Address_in[2*addr_cnt]   = SOIn;
                                Address_in[2*addr_cnt+1] = SI_in;
                                read_cnt = 0;
                                addr_cnt = addr_cnt + 1;
                                if (addr_cnt == 12)
                                begin
                                    addr_cnt = 0;
                                    for (i=23;i>=23-HiAddrBit;i=i-1)
                                    begin
                                        addr_bytes[23-i] = Address_in[i];
                                    end
                                    Address = addr_bytes;
                                    change_addr = 1'b1;
                                    #1 change_addr = 1'b0;
                                    bus_cycle_state = MODE_BYTE;
                                end
                            end
                        end
                        else if (Instruct == QH_READ)
                        begin
                            if(QUAD)
                            begin
                                if (SOIn !== 1'b0 && SOIn !== 1'b1)
                                begin
                                    mpm_mode = 0;
                                    bus_cycle_state = STAND_BY;
                                end
                                else
                                begin
                                    Address_in[4*addr_cnt]   = HOLDNeg_in;
                                    Address_in[4*addr_cnt+1] = WPNeg_in;
                                    Address_in[4*addr_cnt+2] = SOIn;
                                    Address_in[4*addr_cnt+3] = SI_in;
                                    read_cnt = 0;
                                    addr_cnt = addr_cnt + 1;
                                    if (addr_cnt == 6)
                                    begin
                                        addr_cnt = 0;
                                        for (i=23;i>=23-HiAddrBit;i=i-1)
                                        begin
                                            addr_bytes[23-i] = Address_in[i];
                                        end
                                        Address = addr_bytes;
                                        change_addr = 1'b1;
                                        #1 change_addr = 1'b0;
                                        bus_cycle_state = MODE_BYTE;
                                    end
                                end
                            end
                            else
                            begin
                                bus_cycle_state = STAND_BY;
                            end
                        end
                        else if ((HOLDNeg_in && ~QUAD) || QUAD)
                        begin
                            Address_in[addr_cnt] = SI_in;
                            addr_cnt = addr_cnt + 1;
                            if (addr_cnt == 3*BYTE)
                            begin
                                for (i=23;i>=23-HiAddrBit;i=i-1)
                                begin
                                    addr_bytes[23-i] = Address_in[i];
                                end
                                Address = addr_bytes;
                                change_addr = 1'b1;
                                #1 change_addr = 1'b0;
                                bus_cycle_state = DATA_BYTES;
                            end
                        end
                    end

                    MODE_BYTE :
                    begin
                        if((Instruct == DH_READ) &&
                          ((HOLDNeg_in && ~QUAD) || QUAD))
                        begin
                            mode_in[2*mode_cnt]   = SOIn;
                            mode_in[2*mode_cnt+1] = SI_in;
                            mode_cnt = mode_cnt + 1;
                            if (mode_cnt == BYTE/2)
                            begin
                                mode_cnt = 0;
                                for (i=7;i>=7-BYTE;i=i-1)
                                begin
                                    mode_bytes[i] = mode_in[7-i];
                                end
                                bus_cycle_state = DATA_BYTES;
                            end
                        end
                        else if((Instruct == QH_READ) && QUAD)
                        begin
                            mode_in[4*mode_cnt]   = HOLDNeg_in;
                            mode_in[4*mode_cnt+1] = WPNeg_in;
                            mode_in[4*mode_cnt+2] = SOIn;
                            mode_in[4*mode_cnt+3] = SI_in;
                            mode_cnt = mode_cnt + 1;
                            if (mode_cnt == BYTE/4)
                            begin
                                mode_cnt = 0;
                                for (i=7;i>=7-BYTE;i=i-1)
                                begin
                                    mode_bytes[i] = mode_in[7-i];
                                end
                                bus_cycle_state = DUMMY_BYTES;
                            end
                        end
                        dummy_cnt = 0;
                    end

                    DUMMY_BYTES :
                    begin
                        if(QUAD && (Instruct == QUAD_READ ||
                           Instruct == QH_READ))
                        begin
                            dummy_cnt = dummy_cnt + 1;
                            if ((dummy_cnt == BYTE) && Instruct == QUAD_READ)
                                bus_cycle_state = DATA_BYTES;
                            else if ((dummy_cnt == BYTE/2) &&
                                      Instruct == QH_READ)
                                bus_cycle_state = DATA_BYTES;
                        end
                        else if((HOLDNeg_in && ~QUAD) || QUAD)
                        begin
                            dummy_cnt = dummy_cnt + 1;
                            if (dummy_cnt == BYTE && (Instruct == FAST_READ ||
                                Instruct == OTPR || Instruct == DUAL_READ))
                                bus_cycle_state = DATA_BYTES;
                            else if (dummy_cnt == 3*BYTE)
                                bus_cycle_state = DATA_BYTES;
                        end
                    end

                    DATA_BYTES :
                    begin
                        if(QUAD && Instruct == QPP)
                        begin
                            quad_nybble = {HOLDNeg_in, WPNeg_in, SOIn, SI_in};
                            if (data_cnt > 511)
                            begin
                                //In case of quad mode and QPP,
                                //if more than 512 bytes are sent to the device
                                for (i=0;i<=510;i=i+1)
                                begin
                                    quad_data_in[i] = quad_data_in[i+1];
                                end
                                quad_data_in[511] = quad_nybble;
                                data_cnt = data_cnt + 1;
                            end
                            else
                            begin
                                if( quad_nybble !== 4'bZZZZ)
                                begin
                                    quad_data_in[data_cnt] = quad_nybble;
                                end
                                data_cnt = data_cnt + 1;
                            end
                        end
                        else if ((HOLDNeg_in && ~QUAD) || QUAD)
                        begin
                            if (data_cnt > 2047)
                            //In case of serial mode and PP, if more than 256
                            //bytes are sent to the device
                            begin
                                if (bit_cnt == 0)
                                begin
                                    for (i=0;i<=(255*BYTE-1);i=i+1)
                                    begin
                                        Data_in[i] = Data_in[i+8];
                                    end
                                end
                                Data_in[2040 + bit_cnt] = SI_in;
                                bit_cnt = bit_cnt + 1;
                                if (bit_cnt == 8)
                                begin
                                    bit_cnt = 0;
                                end
                                data_cnt = data_cnt + 1;
                            end
                            else
                            begin
                                Data_in[data_cnt] = SI_in;
                                data_cnt = data_cnt + 1;
                                bit_cnt = 0;
                            end
                        end
                    end
                endcase
            end
        end
        if (falling_edge_SCK_ipd)
        begin
            if ((bus_cycle_state == DATA_BYTES) && (~CSNeg_ipd))
            begin
                if (((Instruct == READ || Instruct == FAST_READ ||
                    Instruct == DUAL_READ || Instruct == DH_READ ||
                    Instruct == RES_READ_ES || Instruct == RDID ||
                    Instruct == RDSR || Instruct == READ_ID ||
                    Instruct == RCR || Instruct == OTPR) &&
                    ((HOLDNeg_in && ~QUAD) || QUAD)) ||
                    ((Instruct == QUAD_READ || Instruct == QH_READ) && QUAD))
                begin
                    read_out = 1'b1;
                    #1 read_out = 1'b0;
                end
            end
        end
        if (rising_edge_CSNeg_ipd)
        begin
            if ((bus_cycle_state != DATA_BYTES) &&
                (bus_cycle_state != DUMMY_BYTES))
            begin
                bus_cycle_state = STAND_BY;
            end
            else
            begin
            if (bus_cycle_state == DATA_BYTES)
            begin
                if (mpm_mode && (mode_bytes[7:4] == 4'b1010) &&
                    (Instruct == DH_READ || Instruct == QH_READ))
                begin
                    bus_cycle_state = ADDRESS_BYTES;
                end
                else
                begin
                    mpm_mode = 0;
                    bus_cycle_state = STAND_BY;
                end
                if (Instruct == QPP)
                begin
                    if (data_cnt > 0)
                    begin
                        if ((data_cnt % 2) == 0)
                        begin
                            write = 0;
                            for(i=0;i<=255;i=i+1)
                            begin
                                for(j=1;j>=0;j=j-1)
                                begin
                                    Quad_slv = quad_data_in[(i*2)+(1-j)];
                                    for(k=3;k>=0;k=k-1)
                                    begin
                                        Byte_slv[4*j+k] = Quad_slv[k];
                                    end
                                end
                                WByte[i] = Byte_slv;
                            end
                            if (data_cnt > 512)
                                Byte_number = 255;
                            else
                                Byte_number = data_cnt/2 -1;
                        end
                    end
                end
                if ((HOLDNeg_in && ~QUAD) || QUAD)
                begin
                    case (Instruct)
                        WRDI,
                        WREN,
                        DP,
                        BE,
                        SE,
                        P4E,
                        P8E,
                        CLSR:
                        begin
                            if (data_cnt == 0)
                                write = 1'b0;
                        end

                        RES_READ_ES:
                        begin
                            write = 1'b0;
                        end

                        WRR :
                        begin
                            if((HOLDNeg_in && ~QUAD) || QUAD)
                            begin
                                if (data_cnt == 8)
                                begin
                                    write = 0;
                                    cfg_write = 1'b0;
                                    for(i=0;i<=7;i=i+1)
                                    begin
                                        Status_reg_in[i]=
                                        Data_in[7-i];
                                    end
                                end
                                else if (data_cnt == 16)
                                begin
                                    write = 0;
                                    cfg_write = 1'b1;
                                    for(i=0;i<=7;i=i+1)
                                    begin
                                        Status_reg_in[i]=
                                        Data_in[7-i];
                                        Sec_conf_reg_in[i]=
                                        Data_in[15-i];
                                    end
                                end
                            end
                        end

                        PP :
                        begin
                            if (data_cnt > 0)
                            begin
                                if ((data_cnt % 8) == 0)
                                begin
                                    write = 1'b0;
                                    for (i=0;i<=255;i=i+1)
                                    begin
                                        for (j=7;j>=0;j=j-1)
                                        begin
                                            Byte_slv[j] =
                                            Data_in[(i*8) + (7-j)];
                                        end
                                        WByte[i] = Byte_slv;
                                    end
                                    if (data_cnt > 256*BYTE)
                                        Byte_number = 255;
                                    else
                                        Byte_number = ((data_cnt/8) - 1);
                                end
                            end
                        end

                        OTPP :
                        begin
                            if (data_cnt == 8)
                            begin
                                write = 1'b0;
                                for (j=7;j>=0;j=j-1)
                                begin
                                    Byte_slv[j] = Data_in[7-j];
                                end
                                WOTPByte = Byte_slv;
                            end
                        end
                    endcase
                end
            end
            else
                if (bus_cycle_state == DUMMY_BYTES)
                begin
                    bus_cycle_state = STAND_BY;
                    if (((HOLDNeg_in && ~QUAD) || QUAD) &&
                       (Instruct == RES_READ_ES) && (dummy_cnt == 0))
                        write = 1'b0;
                end
            end
        end
    end

//    /////////////////////////////////////////////////////////////////////////
//    // Timing control for the Program Operations
//    // start
//    /////////////////////////////////////////////////////////////////////////

 event pdone_event;

    always @(PSTART)
    begin
        if (PSTART && PDONE)
            if (Sec_Prot[SA] == 1'b0)
            begin
                PDONE = 1'b0;
                ->pdone_event;
            end
    end

    always @(pdone_event)
    begin:pdone_process
        PDONE = 1'b0;
        #tdevice_PP PDONE = 1'b1;
    end

//    /////////////////////////////////////////////////////////////////////////
//    // Timing control for the Write Status Register Operation
//    // start
//    /////////////////////////////////////////////////////////////////////////

 event wdone_event;

    always @(WSTART)
    begin
        if (WSTART && WDONE)
        begin
            WDONE = 1'b0;
            ->wdone_event;
        end
    end

    always @(wdone_event)
    begin:wdone_process
        WDONE = 1'b0;
        #tdevice_WR WDONE = 1'b1;
    end

//    /////////////////////////////////////////////////////////////////////////
//    // Timing control for the Erase Operations
//    /////////////////////////////////////////////////////////////////////////
 time duration_erase;

    event edone_event;

    always @(ESTART)
    begin: erase
        if (ESTART && EDONE)
        begin
            if (Instruct == BE)
            begin
                duration_erase = tdevice_BE;
            end
            else if (Instruct == P4E || Instruct == P8E)
            begin
                duration_erase = tdevice_PE;
            end
            else
            begin
                duration_erase = tdevice_SE;
            end

            EDONE = 1'b0;
            ->edone_event;
        end
    end

    always @(edone_event)
    begin : edone_process
        EDONE = 1'b0;
        #duration_erase EDONE = 1'b1;
    end
//    /////////////////////////////////////////////////////////////////////////
//    // Main Behavior Process
//    // combinational process for next state generation
//    /////////////////////////////////////////////////////////////////////////

    reg rising_edge_PDONE = 1'b0;
    reg rising_edge_EDONE = 1'b0;
    reg rising_edge_WDONE = 1'b0;
    reg rising_edge_DP_out = 1'b0;
    reg falling_edge_write = 1'b0;
    integer i;
    integer j;

    always @(falling_edge_write or rising_edge_PDONE or rising_edge_WDONE
    or rising_edge_EDONE or rising_edge_DP_out)
    begin: StateGen1
        if (falling_edge_write)
        begin
            case (current_state)
                IDLE :
                begin
                    if (~write)
                    begin
                        if ((Instruct == WRR) && WEL)
                        begin
                            if (~(Status_reg[7] && ~WPNeg_in && ~QUAD))
                            //HPM is disabled when the Quad I/O Mode is enabled
                            //(Quad bit = 1 in the Configuration Register)
                                next_state = WRITE_SR;
                        end

                        else if ((Instruct == PP || Instruct == QPP) &&
                                  WEL)
                        begin
                            sect = Address / 24'h10000;
                            if (Sec_Prot[sect] == 1'b0)
                                next_state = PAGE_PG;
                        end

                        else if (Instruct == OTPP && WEL)
                        begin
                            if(Address == 256 || Address == 257 ||
                            ((Address >= 258 && Address <= 273) &&
                            PR_LOCK1[(Address-258)/8] == 1'b1)
                            || Address == 274
                            || Address == 275 || ((Address >= 276 &&
                            Address <= 531) && PR_LOCK2[(Address-276)/16]
                            ==1'b1) || Address == 532 || Address == 533 ||
                            ((Address >= 534 && Address <= 767)
                            && PR_LOCK3[(Address-534)/16] == 1'b1))
                                next_state =  OTP_PG;
                        end

                        else if (Instruct == SE && WEL)
                        begin
                            sect = Address / 24'h10000;
                            if (Sec_Prot[sect] == 1'b0)
                                next_state = SECTOR_ER;
                        end

                        else if (Instruct == P4E && WEL)
                        begin
                            sect = Address / 24'h10000;
                            if (Sec_Prot[sect] == 1'b0 && (((sect == 0 ||
                                sect == 1) && ~TBPARM) || ((sect == SecNum ||
                                sect == SecNum-1) && TBPARM)))
                                next_state = P4_ER;
                        end

                        else if (Instruct == P8E && WEL)
                        begin
                            sect = Address / 24'h10000;
                            if (Sec_Prot[sect] == 1'b0 && (((sect == 0 ||
                                sect == 1) && ~TBPARM) || ((sect == SecNum ||
                                sect == SecNum-1) && TBPARM)))
                                next_state = P8_ER;
                        end

                        else if (Instruct == BE && WEL)
                        begin
                            if (Status_reg[2]==1'b0 && Status_reg[3]==1'b0 &&
                                Status_reg[4]==1'b0)
                                next_state = BULK_ER;
                        end
                        else if (Instruct == DP)
                            next_state = DP_DOWN_WAIT;
                        else
                            next_state = IDLE;
                    end
                end

                DP_DOWN :
                begin
                    if (~write)
                    begin
                        if (Instruct == RES_READ_ES)
                            next_state = IDLE;
                    end
                end

            endcase
        end

        if (rising_edge_PDONE)
        begin
            if (current_state==PAGE_PG || current_state==OTP_PG)
            begin
                next_state = IDLE;
            end
        end

        if (rising_edge_WDONE)
        begin
            if (current_state==WRITE_SR)
            begin
                next_state = IDLE;
            end
        end

        if (rising_edge_EDONE)
        begin
            if (current_state==SECTOR_ER || current_state==BULK_ER
            || current_state==P4_ER || current_state==P8_ER)
            begin
                next_state = IDLE;
            end
        end

        if (rising_edge_DP_out)
        begin
            if (current_state==DP_DOWN_WAIT)
                next_state = DP_DOWN;
        end

    end

    ///////////////////////////////////////////////////////////////////////////
    //FSM Output generation and general functionality
    ///////////////////////////////////////////////////////////////////////////
    reg rising_edge_read_out = 1'b0;
    reg rising_edge_RES_out  = 1'b0;
    reg Instruct_event       = 1'b0;
    reg change_addr_event    = 1'b0;
    reg rising_edge_powered  = 1'b0;
    reg current_state_event  = 1'b0;

    integer sector;
    integer WData [0:255];
    integer WOTPData;
    integer Addr;
    integer Addr_tmp;

    always @(oe_event)
    begin
        oe = 1'b1;
        #1 oe = 1'b0;
    end

    always @(rising_edge_read_out or Instruct_event or
             change_addr_event or oe or current_state_event or
             falling_edge_write or EDONE or WDONE or PDONE or
             CSNeg_ipd or rising_edge_RES_out or rising_edge_powered or
             rising_edge_DP_out)
    begin: Functionality
    integer i,j;

        if (rising_edge_read_out)
        begin
            if (PoweredUp == 1'b1)
                ->oe_event;
        end

        if (Instruct_event)
        begin
            read_cnt = 0;
            rd_fast  = 1'b1;
            rd_slow  = 1'b0;
            rd_jedec = 1'b0;
            dual     = 1'b0;
            if (current_state == DP_DOWN_WAIT)
            begin
                if (DP_in == 1'b1)
                begin
                    $display ("Command results can be corrupted");
                end
            end
            if (Instruct == DH_READ || Instruct == QH_READ)
            begin
                mpm_mode = 1;
            end
        end

        if (rising_edge_powered)
        begin
            //The Configuration Register FREEZE bit is cleared.
            Sec_conf_reg[0] = 1'b0;

            if (BPNV == 1 && FREEZE == 0)
            begin
            //When BPNV is set to ‘1’,the BP2-0 bits in the Status Register
            //are volatile and will be reset to binary 111 after power on reset.
                Status_reg[4] = 1'b1;// BP2
                Status_reg[3] = 1'b1;// BP1
                Status_reg[2] = 1'b1;// BP0
                change_BP = 1'b1;
                #1 change_BP = 1'b0;
            end
        end

        if (change_addr_event)
        begin
            read_addr = Address;
        end

        if (oe || current_state_event)
        begin
            case (current_state)
                IDLE :
                begin
                    if (oe && ~RES_in)
                    begin
                        if (Instruct == RDSR)
                        begin
                        //Read Status Register
                            SOut_zd = Status_reg[7-read_cnt];
                            read_cnt = read_cnt + 1;
                            if (read_cnt == 8)
                                read_cnt = 0;
                        end
                        if (Instruct == RCR)
                        begin
                        //Read Security Conf. Register
                            SOut_zd = Sec_conf_reg[7-read_cnt];
                            read_cnt = read_cnt + 1;
                            if (read_cnt == 8)
                                read_cnt = 0;
                        end
                        else if (Instruct == READ || Instruct == FAST_READ)
                        begin
                        //Read Memory array
                            if (Instruct == READ)
                            begin
                                rd_fast  = 1'b0;
                                rd_jedec = 1'b0;
                                rd_slow  = 1'b1;
                            end
                            data_out[7:0] = Mem[read_addr];
                            SOut_zd  = data_out[7-read_cnt];
                            read_cnt = read_cnt + 1;
                            if (read_cnt == 8)
                            begin
                                read_cnt = 0;
                                if (read_addr == AddrRANGE)
                                    read_addr = 0;
                                else
                                    read_addr = read_addr + 1;
                            end
                        end
                        else if (Instruct == DUAL_READ || Instruct == DH_READ)
                        begin
                        //Read Memory array
                            rd_fast  = 1'b0;
                            rd_slow  = 1'b0;
                            rd_jedec = 1'b0;
                            dual     = 1'b1;
                            data_out[7:0] = Mem[read_addr];
                            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)
                            begin
                                read_cnt = 0;
                                if (read_addr == AddrRANGE)
                                    read_addr = 0;
                                else
                                    read_addr = read_addr + 1;
                            end
                        end
                        else if (Instruct == QUAD_READ || Instruct == QH_READ)
                        begin
                        //Read Memory array
                            rd_fast  = 1'b0;
                            rd_slow  = 1'b0;
                            rd_jedec = 1'b0;
                            dual     = 1'b1;
                            data_out[7:0] = Mem[read_addr];
                            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)
                            begin
                                read_cnt = 0;
                                if (read_addr == AddrRANGE)
                                    read_addr = 0;
                                else
                                    read_addr = read_addr + 1;
                            end
                        end
                        else if (Instruct == OTPR)
                        begin
                            if(read_addr>=OTPLoAddr && read_addr<=OTPHiAddr)
                            begin
                                //Read OTP Memory array
                                rd_fast  = 1'b1;
                                rd_slow  = 1'b0;
                                rd_jedec = 1'b0;
                                dual     = 1'b0;
                                data_out = OTPMem[read_addr];
                                SOut_zd  = data_out[7-read_cnt];
                                read_cnt = read_cnt + 1;
                                if (read_cnt == 8)
                                begin
                                    read_cnt = 0;
                                    read_addr = read_addr + 1;
                                end
                            end
                            else
                            begin
                            //OTP Read operation will not wrap to the
                            //starting address after the OTP address is at
                            //its maximum;
                            //instead, the data will be indeterminate.
                                SOut_zd = 1'bX;
                                read_cnt = read_cnt + 1;
                                if (read_cnt == 8)
                                    read_cnt = 0;
                            end
                        end
                        else if (Instruct == RDID)
                        begin
                        // Read ID
                            rd_fast  = 1'b0;
                            rd_slow  = 1'b0;
                            rd_jedec = 1'b1;
                            dual     = 1'b0;
                            ident_out = {Manuf_ID,DeviceID,ExtendedBytes,
                            ReservedBytes,ReservedBytes,
                            ReservedBytes,CFI_array_tmp};
                            SOut_zd = ident_out[647-read_cnt];
                            read_cnt  = read_cnt + 1;
                            if (read_cnt == 648)
                                read_cnt = 0;
                        end
                        else if (Instruct == READ_ID)
                        begin
                        // --Read Manufacturer and Device ID
                            if (read_addr % 2 == 0)
                            begin
                                data_out[7:0] = Manuf_ID;
                                SOut_zd = data_out[7-read_cnt];
                                read_cnt = read_cnt + 1;
                                if (read_cnt == 8)
                                begin
                                    read_cnt = 0;
                                    read_addr = read_addr + 1;
                                end
                            end
                            else if (read_addr % 2 == 1)
                            begin
                                data_out[7:0] = ES;
                                SOut_zd = data_out[7-read_cnt];
                                read_cnt = read_cnt + 1;
                                if (read_cnt == 8)
                                begin
                                    read_cnt = 0;
                                    read_addr = 0;
                                end
                            end
                        end
                    end
                    else if (oe && RES_in)
                    begin
                        $display ("Command results can be corrupted");
                        SOut_zd = 1'bX;
                        read_cnt = read_cnt + 1;
                        if (read_cnt == 8)
                            read_cnt = 0;
                    end
                end

                WRITE_SR,
                SECTOR_ER,
                BULK_ER,
                P4_ER,
                P8_ER,
                OTP_PG,
                PAGE_PG :
                begin
                    if (oe && Instruct == RDSR)
                    begin
                    //Read Status Register
                        SOut_zd = Status_reg[7-read_cnt];
                        read_cnt = read_cnt + 1;
                        if (read_cnt == 8)
                            read_cnt = 0;
                    end
                    if (oe && Instruct == RCR)
                    begin
                    //Read Security Conf. Register
                        SOut_zd = Sec_conf_reg[7-read_cnt];
                        read_cnt = read_cnt + 1;
                        if (read_cnt == 8)
                            read_cnt = 0;
                    end
                end
                DP_DOWN :
                begin
                    if (oe && Instruct == RES_READ_ES)
                    begin
                    // Read ID
                        data_out[7:0] = ES;
                        SOut_zd = data_out[7-read_cnt];
                        read_cnt = read_cnt + 1;
                        if (read_cnt == 8)
                            read_cnt = 0;
                    end
                end

            endcase
        end

        if (falling_edge_write)
        begin
            case (current_state)
                IDLE :
                begin
                    if (~write)
                    begin
                        if (RES_in == 1'b1 && Instruct != DP)
                        begin
                            $display ("Command results can be corrupted");
                        end
                        if (Instruct == WREN)
                            Status_reg[1] = 1'b1;
                        else if (Instruct == WRDI)
                            Status_reg[1] = 1'b0;
                        else if (Instruct == WRR && WEL)
                        begin
                            if (~(Status_reg[7] && ~WPNeg_in && ~QUAD))
                            begin
                                WSTART = 1'b1;
                                WSTART <= #1 1'b0;
                                Status_reg[0] = 1'b1;
                            end
                            else
                            begin
                                Status_reg[1] = 0;
                            end
                        end
                        else if ((Instruct == PP || Instruct == QPP) &&
                                  WEL)
                        begin
                            sect = Address / 24'h10000;
                            if (Sec_Prot[sect] == 1'b0)
                            begin
                                PSTART = 1'b1;
                                PSTART <= #1 1'b0;
                                Status_reg[0] = 1'b1; //WIP
                                Addr = Address;
                                Addr_tmp = Address;
                                SA = sect;
                                wr_cnt = Byte_number;
                                for (i=0;i<=wr_cnt;i=i+1)
                                begin
                                    if (Viol != 1'b0)
                                        WData[i] = -1;
                                    else
                                        WData[i] = WByte[i];
                                end
                            end
                            else
                            begin
                                Status_reg[1] = 1'b0;
                            end
                        end
                        else if (Instruct == OTPP && WEL)
                        begin
                            if(Address == 256 || Address == 257 ||
                            ((Address >= 258 && Address <= 273) &&
                            PR_LOCK1[(Address-258)/8] == 1'b1)
                            || Address == 274
                            || Address == 275 || ((Address >= 276 &&
                            Address <= 531) && PR_LOCK2[(Address-276)/16]
                            ==1'b1) || Address == 532 || Address == 533 ||
                            ((Address >= 534 && Address <= 767)
                            && PR_LOCK3[(Address-534)/16] == 1'b1))
                            begin
                                PSTART = 1'b1;
                                PSTART <= #1 1'b0;
                                Status_reg[0] = 1'b1; //WIP
                                Addr = Address;
                                if (Viol != 1'b0 )
                                    WOTPData = -1;
                                else
                                    WOTPData = WOTPByte;
                            end
                            else if (Address < 100 || Address > 767 )
                            begin
                                Status_reg[6] = 1'b1;
                                Status_reg[1] = 1'b0;
                            end
                            else
                            begin
                                Status_reg[1] = 1'b0;
                            end
                        end
                        else if (Instruct == SE && WEL)
                        begin
                            sect = Address / 24'h10000;
                            if (Sec_Prot[sect] == 1'b0)
                            begin
                                ESTART = 1'b1;
                                ESTART <= #1 1'b0;
                                Status_reg[0] = 1'b1;
                                Addr = Address;
                            end
                            else
                            begin
                                Status_reg[1] = 1'b0;
                            end
                        end
                        else if (Instruct == BE && WEL)
                        begin
                            if(Status_reg[2]==1'b0 && Status_reg[3]==1'b0 &&
                               Status_reg[4]==1'b0)
                            begin
                                ESTART = 1'b1;
                                ESTART <= #1 1'b0;
                                Status_reg[0] = 1'b1;
                            end
                            else
                            begin
                                Status_reg[1] = 1'b0;
                            end
                        end
                        else if (Instruct == P4E && WEL)
                        begin
                            sect = Address / 24'h10000;
                            if (((sect == 0 ||
                                sect == 1) && ~TBPARM) || ((sect == SecNum ||
                                sect == SecNum-1) && TBPARM))
                            begin
                                if (Sec_Prot[sect] == 1'b0)
                                begin
                                    ESTART = 1'b1;
                                    ESTART <= #1 1'b0;
                                    Status_reg[0] = 1'b1;
                                    Addr = Address;
                                end
                                else
                                begin
                                    Status_reg[1] = 1'b0;
                                end
                            end
                            else
                            begin
                                Status_reg[5] = 1'b1;
                                Status_reg[1] = 1'b0;
                            end
                        end
                        else if (Instruct == P8E && WEL)
                        begin
                            sect = Address / 24'h10000;
                            if (((sect == 0 ||
                                sect == 1) && ~TBPARM) || ((sect == SecNum ||
                                sect == SecNum-1) && TBPARM))
                            begin
                                if (Sec_Prot[sect] == 1'b0)
                                begin
                                    ESTART = 1'b1;
                                    ESTART <= #1 1'b0;
                                    Status_reg[0] = 1'b1;
                                    Addr = Address;
                                end
                                else
                                begin
                                    Status_reg[1] = 1'b0;
                                end
                            end
                            else
                            begin
                                Status_reg[5] = 1'b1;
                                Status_reg[1] = 1'b0;
                            end
                        end
                        else if (Instruct == CLSR)
                        begin
                            Status_reg[5] = 1'b0;
                            Status_reg[6] = 1'b0;
                        end
                        else if (Instruct == DP)
                        begin
                            RES_in <= 1'b0;
                            DP_in = 1'b1;
                        end
                        else if (Instruct == RES_READ_ES)
                        begin
                            RES_in <= 1'b1;
                        end
                    end

                end

                DP_DOWN :
                begin
                    if (~write)
                    begin
                        if (Instruct == RES_READ_ES)
                            RES_in = 1'b1;
                    end
                end

            endcase
        end

        if(current_state_event || EDONE)
        begin
            case (current_state)

                SECTOR_ER :
                begin
                    ADDRHILO_SEC(AddrLo, AddrHi, Addr);
                    for (i=AddrLo;i<=AddrHi;i=i+1)
                    begin
                        Mem[i] = -1;
                    end
                    if (EDONE)
                    begin
                        Status_reg[0] = 1'b0;
                        Status_reg[1] = 1'b0;
                        for (i=AddrLo;i<=AddrHi;i=i+1)
                        begin
                            Mem[i] = MaxData;
                        end
                    end
                end
                BULK_ER :
                begin
                    for (i=0;i<=AddrRANGE;i=i+1)
                    begin
                        Mem[i] = -1;
                    end

                    if (EDONE)
                    begin
                        Status_reg[0] = 1'b0;
                        Status_reg[1] = 1'b0;
                        for (i=0;i<=AddrRANGE;i=i+1)
                        begin
                            Mem[i] = MaxData;
                        end
                    end
                end
                P4_ER :
                begin
                    ADDRHILO_PB4(AddrLo, AddrHi, Addr);
                    for (i=AddrLo;i<=AddrHi;i=i+1)
                    begin
                        Mem[i] = -1;
                    end
                    if (EDONE)
                    begin
                        Status_reg[0] = 1'b0;
                        Status_reg[1] = 1'b0;
                        for (i=AddrLo;i<=AddrHi;i=i+1)
                        begin
                            Mem[i] =  MaxData;
                        end
                    end
                end
                P8_ER :
                begin
                    ADDRHILO_PB8(AddrLo, AddrHi, Addr);
                    for (i=AddrLo;i<=AddrHi;i=i+1)
                    begin
                        Mem[i] = -1;
                    end
                    if (EDONE)
                    begin
                        Status_reg[0] = 1'b0;
                        Status_reg[1] = 1'b0;
                        for (i=AddrLo;i<=AddrHi;i=i+1)
                        begin
                            Mem[i] =  MaxData;
                        end
                    end
                end
            endcase
        end

        if(current_state_event || WDONE)
        begin
            if (current_state == WRITE_SR)
            begin
                if (WDONE)
                begin
                    Status_reg[0] = 1'b0;//WIP
                    Status_reg[1] = 1'b0;//WEL
                    //SRWD bit
                    Status_reg[7] = Status_reg_in[7];//MSB first

                    if (FREEZE == 0)
                    //The Freeze Bit, when set to 1, locks the current
                    //state of the BP2-0 bits in Status Register,
                    //the TBPROT and TBPARM bits in the Config Register
                    //As long as the FREEZE bit remains cleared to logic
                    //'0', the other bits of the Configuration register
                    //including FREEZE are writeable.
                    begin
                        Status_reg[4] = Status_reg_in[4];// BP2
                        Status_reg[3] = Status_reg_in[3];// BP1
                        Status_reg[2] = Status_reg_in[2];// BP0

                        if (cfg_write)
                        begin
                            Sec_conf_reg[0] = Sec_conf_reg_in[0];// FREEZE

                            if (TBPARM == 1'b0)
                            begin
                                Sec_conf_reg[2] = Sec_conf_reg_in[2];//TBPARM
                            end

                            if (TBPROT == 1'b0)
                            begin
                                Sec_conf_reg[5] = Sec_conf_reg_in[5];//TBPROT
                            end

                            Sec_conf_reg[1] = Sec_conf_reg_in[1];// QUAD

                            if (BPNV == 1'b0)
                            begin
                                Sec_conf_reg[3] = Sec_conf_reg_in[3];//BPNV
                            end
                        end

                        change_BP = 1'b1;
                        #1 change_BP = 1'b0;
                    end

                end
            end
        end

        if(current_state_event || PDONE)
        begin
            if (current_state == PAGE_PG)
            begin
                ADDRHILO_PG(AddrLo, AddrHi, Addr);
                cnt = 0;

                for (i=0;i<=wr_cnt;i=i+1)
                begin
                    new_int = WData[i];
                    old_int = Mem[Addr + i - cnt];
                    if (new_int > -1)
                    begin
                        new_bit = new_int;
                        if (old_int > -1)
                        begin
                            old_bit = old_int;
                            for(j=0;j<=7;j=j+1)
                                if (~old_bit[j])
                                    new_bit[j]=1'b0;
                            new_int=new_bit;
                        end

                        WData[i]= new_int;
                    end
                    else
                    begin
                        WData[i] = -1;
                    end

                    Mem[Addr + i -cnt] = - 1;

                    if ((Addr + i) == AddrHi)
                    begin
                        Addr = AddrLo;
                        cnt = i + 1;
                    end
                end

                cnt = 0;

                if (PDONE)
                begin
                    Status_reg[0] = 1'b0;//wip
                    Status_reg[1] = 1'b0;
                    for (i=0;i<=wr_cnt;i=i+1)
                    begin
                        Mem[Addr_tmp + i - cnt] = WData[i];
                        if ((Addr_tmp + i) == AddrHi)
                        begin
                            Addr_tmp = AddrLo;
                            cnt = i + 1;
                        end
                    end
                end
            end
        end

        if(current_state_event || PDONE)
        begin
            if (current_state == OTP_PG)
            begin
                new_int = WOTPData;
                old_int = OTPMem[Addr];
                if (new_int > -1)
                begin
                    new_bit = new_int;
                    if (old_int > -1)
                    begin
                        old_bit = old_int;
                        for(j=0;j<=7;j=j+1)
                        begin
                            if (~old_bit[j])
                                new_bit[j] = 1'b0;
                        end
                        new_int = new_bit;
                    end
                    WOTPData = new_int;
                end
                else
                begin
                    WOTPData = -1;
                end
                OTPMem[Addr] =  -1;
                if (PDONE)
                begin
                    Status_reg[0] = 1'b0;
                    Status_reg[1] = 1'b0;
                    OTPMem[Addr] = WOTPData;
                    PR_LOCK1 = {OTPMem[257],OTPMem[256]};

                    PR_LOCK1[15:8] = OTPMem[257];
                    PR_LOCK1[7:0]  = OTPMem[256];
                    PR_LOCK2[15:8] = OTPMem[275];
                    PR_LOCK2[7:0]  = OTPMem[274];
                    PR_LOCK3[15:8] = OTPMem[533];
                    PR_LOCK3[7:0]  = OTPMem[532];
                end
            end
        end

        //Output Disable Control
        if (CSNeg_ipd )
        begin
            SIOut_zd      = 1'bZ;
            HOLDNegOut_zd = 1'bZ;
            WPNegOut_zd   = 1'bZ;
            SOut_zd = 1'bZ;
        end

        if (rising_edge_RES_out)
        begin
            if(RES_out)
            begin
                RES_in = 1'b0;
            end
        end

        if (rising_edge_DP_out)
        begin
            if (current_state == DP_DOWN_WAIT)
            begin
                DP_in = 1'b0;
            end
        end

    end

    always @(change_BP)
    begin
        if (change_BP)
        begin
            case (Status_reg[4:2])
                3'b000 :
                begin
                    Sec_Prot = 256'h0;
                end

                3'b001 :
                begin
                    if (~Sec_conf_reg[5])
                    begin
                        Sec_Prot[SecNum : (SecNum+1)*63/64] = 1'b1;
                        Sec_Prot[(SecNum+1)*63/64 - 1 : 0] = 126'h0;
                    end
                    else
                    begin
                        Sec_Prot[(SecNum+1)/64 - 1 : 0] = 2'b11;
                        Sec_Prot[SecNum : (SecNum+1)/64] = 126'h0;
                    end
                end

                3'b010 :
                begin
                    if (~Sec_conf_reg[5])
                    begin
                        Sec_Prot[SecNum : (SecNum+1)*31/32] = 4'hF;
                        Sec_Prot[(SecNum+1)*31/32 - 1 : 0] = 124'h0;
                    end
                    else
                    begin
                        Sec_Prot[(SecNum+1)/32 - 1 : 0] = 4'hF;
                        Sec_Prot[SecNum : (SecNum+1)/32] = 124'h0;
                    end
                end

                3'b011 :
                begin
                    if (~Sec_conf_reg[5])
                    begin
                        Sec_Prot[SecNum : (SecNum+1)*15/16] = 8'hFF;
                        Sec_Prot[(SecNum+1)*15/16 - 1 : 0]  = 120'h0;
                    end
                    else
                    begin
                        Sec_Prot[(SecNum+1)/16 - 1 : 0]  = 8'hFF;
                        Sec_Prot[SecNum : (SecNum+1)/16] = 120'h0;
                    end
                end

                3'b100 :
                begin
                    if (~Sec_conf_reg[5])
                    begin
                        Sec_Prot[SecNum : (SecNum+1)*7/8] = 16'hFFFF;
                        Sec_Prot[(SecNum+1)*7/8 - 1 : 0]  = 112'h0;
                    end
                    else
                    begin
                        Sec_Prot[(SecNum+1)/8 - 1 : 0]  = 16'hFFFF;
                        Sec_Prot[SecNum : (SecNum+1)/8] = 112'h0;
                    end
                end

                3'b101 :
                begin
                    if (~Sec_conf_reg[5])
                    begin
                        Sec_Prot[SecNum : (SecNum+1)*3/4]
                                                    = 32'hFFFFFFFF;
                        Sec_Prot[(SecNum+1)*3/4 - 1 : 0] = 96'h0;
                    end
                    else
                    begin
                        Sec_Prot[(SecNum+1)/4 - 1 : 0]
                                                    = 32'hFFFFFFFF;
                        Sec_Prot[SecNum : (SecNum+1)/4] = 96'h0;
                    end
                end

                3'b110 :
                begin
                    if (~Sec_conf_reg[5])
                    begin
                        Sec_Prot[SecNum : (SecNum+1)/2]
                                                 = 64'hFFFFFFFFFFFFFFFF;
                        Sec_Prot[(SecNum+1)/2 - 1 : 0] = 64'h0;
                    end
                    else
                    begin
                        Sec_Prot[(SecNum+1)/2 - 1 : 0]
                                                 = 64'hFFFFFFFFFFFFFFFF;
                        Sec_Prot[SecNum : (SecNum+1)/2] = 64'h0;
                    end
                end

                3'b111 :
                begin
                    Sec_Prot = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
                end

            endcase
        end
    end

    assign fast_rd = rd_fast;
    assign rd = rd_slow;
    assign rd_jid = rd_jedec;

    always @(SOut_zd or HOLDNeg_in or SIOut_zd)
    begin
        if (~HOLDNeg_in && ~QUAD)
        begin
            hold_mode = 1'b1;
            SIOut_z   = 1'bZ;
            SOut_z    = 1'bZ;
        end
        else
        begin
            if (hold_mode)
            begin
                SIOut_z <= #(tpd_HOLDNeg_SO) SIOut_zd;
                SOut_z  <= #(tpd_HOLDNeg_SO) SOut_zd;
                hold_mode = 1'b0;
            end
            else
            begin
                SIOut_z = SIOut_zd;
                SOut_z  = SOut_zd;
                hold_mode = 1'b0;
            end
        end
    end

// Procedure ADDRHILO_SEC
 task ADDRHILO_SEC;
 inout  AddrLOW;
 inout  AddrHIGH;
 input   Addr;
 integer AddrLOW;
 integer AddrHIGH;
 integer Addr;
 integer sector;
 begin
    sector = Addr / 20'h10000;
    AddrLOW = sector * 20'h10000;
    AddrHIGH = sector * 20'h10000 + 16'hFFFF;
 end
 endtask

// Procedure ADDRHILO_PG
 task ADDRHILO_PG;
 inout  AddrLOW;
 inout  AddrHIGH;
 input   Addr;
 integer AddrLOW;
 integer AddrHIGH;
 integer Addr;
 integer page;
 begin

    page = Addr / 16'h100;
    AddrLOW = page * 16'h100;
    AddrHIGH = page * 16'h100 + 8'hFF;

 end
 endtask

// Procedure ADDRHILO_PB4
 task ADDRHILO_PB4;
 inout   AddrLOW;
 inout   AddrHIGH;
 input   Addr;
 integer AddrLOW;
 integer AddrHIGH;
 integer Addr;
 integer sector;
 begin
    sector = Addr / 20'h10000;
    if (sector == 0 || sector == 1 ||
        sector == SecNum || sector == SecNum-1)
    begin
        AddrLOW  = (Address/(SecSize_4+1))*(SecSize_4+1);
        AddrHIGH = (Address/(SecSize_4+1))*(SecSize_4+1) + SecSize_4;
    end
 end
 endtask

// Procedure ADDRHILO_PB8
 task ADDRHILO_PB8;
 inout   AddrLOW;
 inout   AddrHIGH;
 input   Addr;
 integer AddrLOW;
 integer AddrHIGH;
 integer Addr;
 integer sector;
 begin
    sector = Addr / 20'h10000;
    if (sector == 0 || sector == SecNum-1)
    begin
        AddrLOW  = (Address/(SecSize_8+1))*(SecSize_8+1);
        AddrHIGH = (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8;
    end
    if (sector == 1)
    begin
        AddrLOW  = (Address/(SecSize_8+1))*(SecSize_8+1);
        AddrHIGH = (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8;
        if (AddrHIGH > 20'h1FFFF)
            AddrHIGH = 20'h1FFFF;
    end
    if (sector == SecNum)
    begin
        AddrLOW  = (Address/(SecSize_8+1))*(SecSize_8+1);
        AddrHIGH = (Address/(SecSize_8+1))*(SecSize_8+1) + SecSize_8;
        if (AddrHIGH > 24'h3FFFFF)
            AddrHIGH = 24'h3FFFFF;
    end
 end
 endtask

    always @(negedge CSNeg_ipd)
    begin
        falling_edge_CSNeg_ipd = 1'b1;
        #1 falling_edge_CSNeg_ipd = 1'b0;
    end

    always @(posedge SCK_ipd)
    begin
        rising_edge_SCK_ipd = 1'b1;
        #1 rising_edge_SCK_ipd = 1'b0;
    end

    always @(negedge SCK_ipd)
    begin
        falling_edge_SCK_ipd = 1'b1;
        #1 falling_edge_SCK_ipd = 1'b0;
    end

    always @(posedge CSNeg_ipd)
    begin
        rising_edge_CSNeg_ipd = 1'b1;
        #1 rising_edge_CSNeg_ipd = 1'b0;
    end

    always @(negedge write)
    begin
        falling_edge_write = 1'b1;
        #1 falling_edge_write = 1'b0;
    end

    always @(posedge PDONE)
    begin
        rising_edge_PDONE = 1'b1;
        #1 rising_edge_PDONE = 1'b0;
    end

    always @(posedge WDONE)
    begin
        rising_edge_WDONE = 1'b1;
        #1 rising_edge_WDONE = 1'b0;
    end

    always @(posedge EDONE)
    begin
        rising_edge_EDONE = 1'b1;
        #1 rising_edge_EDONE = 1'b0;
    end

    always @(posedge DP_out)
    begin
        rising_edge_DP_out = 1'b1;
        #1 rising_edge_DP_out = 1'b0;
    end

    always @(posedge RES_out)
    begin
        rising_edge_RES_out = 1'b1;
        #1 rising_edge_RES_out = 1'b0;
    end

    always @(posedge read_out)
    begin
        rising_edge_read_out = 1'b1;
        #1 rising_edge_read_out = 1'b0;
    end

    always @(posedge PoweredUp)
    begin
        rising_edge_powered = 1'b1;
        #1 rising_edge_powered = 1'b0;
    end

    always @(Instruct)
    begin
        Instruct_event = 1'b1;
        #1 Instruct_event = 1'b0;
    end

    always @(change_addr)
    begin
        change_addr_event = 1'b1;
        #1 change_addr_event = 1'b0;
    end

    always @(current_state)
    begin
        current_state_event = 1'b1;
        #1 current_state_event = 1'b0;
    end

endmodule