blob: 9e230cf819726fab8d66dff5c96e430d1e0100bb [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
// SPDX-FileCopyrightText: 2012 Spansion, LLC.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileContributor: Created by Dinesh Annayya <dinesha@opencores.org>
//
///////////////////////////////////////////////////////////////////////////////
// File name : s25fl256s.v
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2012 Spansion, LLC.
//
// MODIFICATION HISTORY :
//
// version: | author: | mod date: | changes made:
// V1.0 V.Mancev 19 Nov 09 Initial
// R.Prokopovic
// V1.1 V.Mancev 04 Mar 10 addr_cnt for second read in
// high performance read continuous
// mode can change its value only
// when CSNeg = '0'
// V1.2 V.Mancev 23 Mar 10 During read operations read_out
// signal changes its value in
// shorter interval
// V1.3 V.Mancev 12 Apr 10 HOLD mode corrected
// Condition for PP operation
// corrected
// V1.4 V.Mancev 20 May 10 SRWD bit assignment is corrected
// Condition for WRR command in
// write_cycle _decode section is
// corrected
// Blocking assignments for signals
// WSTART and PSTART are replaced
// with nonblocking assignments
// Conditions in Page Program
// section are fixed
// V1.5 V.Mancev 25 May 10 Conditions in programming
// sections are fixed
// Timing control sections for
// Program and Erase operation are
// changed
// V1.6 V.Mancev 03 June 10 bus_cycle_state section for
// PGSP command is fixed
// V1.7 V.Mancev 28 July 10 During the QUAD mode HOLD# input
// is not monitored for its normal
// function
// write cycle decode section is
// changed
// V1.8 B.Colakovic 24 Aug 10 All redundant signals are removed
// from BusCycle process
// V1.9 V.Mancev 30 Sep 10 Latest datasheet aligned
// B.Colakovic
//
// V2.0 V.Mancev 05 Nov 10 Hybrid configuration added
//
// V2.1 V.Mancev 12 Nov 10 QUAD Program operation during Erase
// Suspend is added
// Warning for Resume to Suspend time
// is added
// During Erase Suspend, after Program
// operation is completed, WEL bit is
// cleared
// Implemetation of Software Reset is
// Changed
// V2.2 S.Petrovic 18 Apr 11 Corrected timing in always block
// that generates rising_edge_CSNeg_ipd
// V2.3 B.Colakovic 05 July 11 Latest datasheet aligned
// V2.4 B.Colakovic 14 July 11 Optimization issue is fixed
// V2.5 V.Mancev 19 July 11 Timing check issue is fixed
// V2.6 V. Mancev 18 Nov 11 Time tHO is changed to 1 ns
// (customer's request)
// BRWR instruction is corrected
// V2.7 S.Petrovic 28 Aug 12 QPP Instruction is allowed on
// previously programmed page
// V2.8 V. Mancev 13 Feb 13 Reverted restriction for QPP
// on programmed page and
// added clearing with sector erase
// V2.9 S.Petrovic 13 Nov 28 Corrected FSM state transition
// started on Power-Up and HW
// Reset in StateGen process
// V2.10 V. Mancev 13 Dec 20 Corrected DLP read
// V2.11 M.Stojanovic 15 May 15 Ignored upper address bits for RD4
// V2.12 M.Stojanovic 15 May 29 Ignored upper address bits for all
// commands in QUAD mode
// V2.13 M.Stojanovic 16 May 11 During QPP and QPP4 commands
// the same page must not be
// programmed more than once. However
// do not generate P_ERR if this
// occurs.
// V2.14 M.Krneta 19 May 07 Updated according to the rev *P
// (QPP and QPP4 commands changed,
// ECCRD command added,
// LOCK bit removed)
// V2.15 B.Barac 20 Jan 24 Bug 49 fixed, issue with not assigning
// sector in commands P4E4 and P4E
//
///////////////////////////////////////////////////////////////////////////////
// PART DESCRIPTION:
//
// Library: FLASH
// Technology: FLASH MEMORY
// Part: S25FL256S
//
// Description: 256 Megabit Serial Flash Memory
//
//////////////////////////////////////////////////////////////////////////////
// Comments :
// For correct simulation, simulator resolution should be set to 1 ps
// A device ordering (trim) option determines whether a feature is enabled
// or not, or provide relevant parameters:
// -15th character in TimingModel determines if enhanced high
// performance option is available
// (0,2,3,R,A,B,C,D) EHPLC
// (Y,Z,S,T,K,L) Security EHPLC
// (4,6,7,8,9,Q) HPLC
// -15th character in TimingModel determines if RESET# input
// is available
// (R,A,B,C,D,Q.6,7,K,L,S,T,M,N,U,V) RESET# is available
// (0,2,3,4,8,9,Y.Z.W,X) RESET# is tied to the inactive
// state,inside the package.
// -16th character in TimingModel determines Sector and Page Size:
// (0) Sector Size = 64 kB; Page Size = 256 bytes
// Hybrid Top/Bottom sector size architecture
// (1) Sector Size = 256 kB; Page Size = 512 bytes
// Uniform sector size architecture
//////////////////////////////////////////////////////////////////////////////
// Known Bugs:
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// MODULE DECLARATION //
//////////////////////////////////////////////////////////////////////////////
`timescale 1 ps/1 ps
module s25fl256s
(
// Data Inputs/Outputs
SI ,
SO ,
// Controls
SCK ,
CSNeg ,
RSTNeg ,
WPNeg ,
HOLDNeg
);
///////////////////////////////////////////////////////////////////////////////
// Port / Part Pin Declarations
///////////////////////////////////////////////////////////////////////////////
inout SI ;
inout SO ;
input SCK ;
input CSNeg ;
input RSTNeg ;
inout HOLDNeg ;
inout WPNeg ;
// interconnect path delay signals
wire SCK_ipd ;
wire SI_ipd ;
wire SO_ipd ;
wire SI_in ;
assign SI_in = SI_ipd ;
wire SI_out ;
assign SI_out = SI ;
wire SO_in ;
assign SO_in = SO_ipd ;
wire SO_out ;
assign SO_out = SO ;
wire CSNeg_ipd ;
wire HOLDNeg_ipd ;
wire WPNeg_ipd ;
wire RSTNeg_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 RSTNeg_in ;
//Internal pull-up
assign RSTNeg_in = (RSTNeg_ipd === 1'bx) ? 1'b1 : RSTNeg_ipd;
// internal delays
reg PP_in ;
reg PP_out ;
reg BP_in ;
reg BP_out ;
reg SE_in ;
reg SE_out ;
reg BE_in ;
reg BE_out ;
reg WRR_in ;
reg WRR_out ;
reg ERSSUSP_in ;
reg ERSSUSP_out ;
reg PRGSUSP_in ;
reg PRGSUSP_out ;
reg PU_in ;
reg PU_out ;
reg RST_in ;
reg RST_out ;
reg PPBERASE_in ;
reg PPBERASE_out;
reg PASSULCK_in ;
reg PASSULCK_out;
reg PASSACC_in ;
reg PASSACC_out;
// event control registers
reg PRGSUSP_out_event;
reg ERSSUSP_out_event;
reg Reseted_event;
reg SCK_ipd_event;
reg next_state_event;
reg rising_edge_PoweredUp;
reg rising_edge_Reseted;
reg rising_edge_PASSULCK_in;
reg rising_edge_RES_out;
reg rising_edge_PSTART;
reg rising_edge_WSTART;
reg rising_edge_ESTART;
reg rising_edge_RSTNeg;
reg rising_edge_RST;
reg falling_edge_RSTNeg;
reg falling_edge_RST;
reg rising_edge_RST_out;
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;
reg RST ;
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";//"s25fl256s.mem";
parameter otp_file_name = "s25fl256sOTP.mem";//"none";
parameter TimingModel = "DefaultTimingModel";
parameter PartID = "s25fl256s";
parameter MaxData = 255;
parameter MemSize = 28'h1FFFFFF;
parameter SecSize256 = 20'h3FFFF;
parameter SecSize64 = 16'hFFFF;
parameter SecSize4 = 12'hFFF;
parameter SecNum64 = 541;
parameter SecNum256 = 127;
parameter PageNum64 = 20'h3FFFF;
parameter PageNum256 = 16'hFFFF;
parameter AddrRANGE = 28'h1FFFFFF;
parameter HiAddrBit = 31;
parameter OTPSize = 1023;
parameter OTPLoAddr = 12'h000;
parameter OTPHiAddr = 12'h3FF;
parameter BYTE = 8;
// Manufacturer Identification
parameter Manuf_ID = 8'h01;
parameter DeviceID = 8'h18;
// Electronic Signature
parameter ESignature = 8'h18;
// Device ID
//Manufacturer Identification && Memory Type && Memory Capacity
parameter Jedec_ID = 8'h01;
parameter DeviceID1 = 8'h02;
parameter DeviceID2 = 8'h19;
parameter ExtendedBytes = 8'h4D;
parameter ExtendedID64 = 8'h01;
parameter ExtendedID256 = 8'h00;
parameter DieRev = 8'h00;
parameter MaskRev = 8'h00;
integer PageSize;
integer PageNum;
integer SecSize;
integer b_act = 0;
integer ASP_ProtSE = 0;
integer Sec_ProtSE = 0;
integer EHP; //Enhanced High Performance Mode active
integer BAR_ACC = 0; //Bank Register Access active
//varaibles to resolve architecture used
reg [24*8-1:0] tmp_timing;//stores copy of TimingModel
reg [7:0] tmp_char1;//Define EHPLC or HPLC Mode
reg [7:0] tmp_char2;//stores "0" or "1" character defining sector/page size
integer found = 1'b0;
// If speedsimulation is needed uncomment following line
`define SPEEDSIM;
// powerup
reg PoweredUp;
// Memory Array Configuration
reg BottomBoot = 1'b0;
reg TopBoot = 1'b0;
reg UniformSec = 1'b0;
// FSM control signals
reg PDONE ;
reg PSTART ;
reg PGSUSP ;
reg PGRES ;
reg TSU ;
reg RES_TO_SUSP_MIN_TIME;
reg RES_TO_SUSP_TYP_TIME;
reg WDONE ;
reg WSTART ;
reg EDONE ;
reg ESTART ;
reg ESUSP ;
reg ERES ;
reg Reseted ;
reg PARAM_REGION = 1'b0;
// Lock Bit is enabled for customer programming
reg WRLOCKENABLE = 1'b1;
// Flag that mark if ASP Register is allready programmed
reg ASPOTPFLAG = 1'b0;
//Flag for Password unlock command
reg PASS_UNLOCKED = 1'b0;
reg [63:0] PASS_TEMP = 64'hFFFFFFFFFFFFFFFF;
reg QUADRD = 1'b0;
reg INITIAL_CONFIG = 1'b0;
reg CHECK_FREQ = 1'b0;
// Programming buffer
integer WByte[0:511];
// CFI array
integer CFI_array[8'h00:8'h50];
// OTP Memory Array
integer OTPMem[OTPLoAddr:OTPHiAddr];
// Flash Memory Array
integer Mem[0:AddrRANGE];
// Registers
// VDLR Register
reg[7:0] VDLR_reg = 8'h00;
reg[7:0] VDLR_reg_in = 8'h00;
// NVDLR Register
reg[7:0] NVDLR_reg = 8'h00;
reg[7:0] NVDLR_reg_in = 8'h00;
reg start_dlp = 1'b0;
// Status Register 1
reg[7:0] Status_reg1 = 8'h00;
reg[7:0] Status_reg1_in = 8'h00;
wire SRWD ;
wire P_ERR;
wire E_ERR;
wire [2:0]BP;
wire WEL;
wire WIP;
assign SRWD = Status_reg1[7];
assign P_ERR = Status_reg1[6];
assign E_ERR = Status_reg1[5];
assign BP = Status_reg1[4:2];
assign WEL = Status_reg1[1];
assign WIP = Status_reg1[0];
// Status Register 2
reg[7:0] Status_reg2 = 8'h00;
reg[7:0] Status_reg2_in = 8'h00;
wire ES ;
wire PS ;
assign ES = Status_reg2[1];
assign PS = Status_reg2[0];
// Configuration Register 1
reg[7:0] Config_reg1 = 8'h00;
reg[7:0] Config_reg1_in = 8'h00;
wire LC1 ;
wire LC0 ;
wire TBPROT ;
// wire LOCK ;
wire BPNV ;
wire TBPARM ;
wire QUAD ;
wire FREEZE ;
assign LC1 = Config_reg1[7];
assign LC0 = Config_reg1[6];
assign TBPROT = Config_reg1[5];
// assign LOCK = Config_reg1[4];
assign BPNV = Config_reg1[3];
assign TBPARM = Config_reg1[2];
assign QUAD = Config_reg1[1];
assign FREEZE = Config_reg1[0];
// Autoboot Register
reg[31:0] AutoBoot_reg = 32'h00000000;
reg[31:0] AutoBoot_reg_in = 32'h00000000;
wire ABE;
assign ABE = AutoBoot_reg[0];
// Bank Address Register
reg [7:0] Bank_Addr_reg = 8'h00;
reg [7:0] Bank_Addr_reg_in = 8'h00;
wire EXTADD;
wire BA24;
assign EXTADD = Bank_Addr_reg[7];
assign BA24 = Bank_Addr_reg[0];
// ECC Status Register
reg[7:0] ECCSR = 8'h00;
wire EECC;
wire EECCD;
wire ECCDI;
assign EECC = ECCSR[2];
assign EECCD = ECCSR[1];
assign ECCDI = ECCSR[0];
// ASP Register
reg[15:0] ASP_reg ;
reg[15:0] ASP_reg_in;
wire RPME ;
wire PPBOTP ;
wire PWDMLB ;
wire PSTMLB ;
assign RPME = ASP_reg[5];
assign PPBOTP = ASP_reg[3];
assign PWDMLB = ASP_reg[2];
assign PSTMLB = ASP_reg[1];
// Password register
reg[63:0] Password_reg = 64'hFFFFFFFFFFFFFFFF;
reg[63:0] Password_reg_in = 64'hFFFFFFFFFFFFFFFF;
// PPB Lock Register
reg[7:0] PPBL = 8'h00;
reg[7:0] PPBL_in = 8'h00;
wire PPB_LOCK ;
assign PPB_LOCK = PPBL[0];
// PPB Access Register
reg[7:0] PPBAR = 8'hFF;
reg[7:0] PPBAR_in = 8'hFF;
reg[SecNum64:0] PPB_bits = {542{1'b1}};
// DYB Access Register
reg[7:0] DYBAR = 8'hFF;
reg[7:0] DYBAR_in = 8'hFF;
reg[SecNum64:0] DYB_bits = {542{1'b1}};
//The Lock Protection Registers for OTP Memory space
reg[7:0] LOCK_BYTE1;
reg[7:0] LOCK_BYTE2;
reg[7:0] LOCK_BYTE3;
reg[7:0] LOCK_BYTE4;
// Command Register
reg write;
reg cfg_write;
reg read_out;
reg dual = 1'b0;
reg rd_fast = 1'b1;
reg rd_slow = 1'b0;
reg ddr = 1'b0;
reg ddr80 = 1'b0;
reg ddr_fast = 1'b0;
reg hold_mode = 1'b0;
reg any_read = 1'b0;
reg quad_pg = 1'b0;
wire rd ;
wire fast_rd ;
wire ddrd ;
wire fast_ddr ;
wire ddrd80 ;
wire quadpg ;
assign quadpg = quad_pg;
wire RD_EQU_1;
assign RD_EQU_1 = any_read;
wire RD_EQU_0;
assign RD_EQU_0 = ~any_read;
reg change_TBPARM = 0;
reg change_BP = 0;
reg [2:0] BP_bits = 3'b0;
reg DOUBLE = 1'b0; //Double Data Rate (DDR) flag
reg RdPswdProtMode = 1'b0;//Read Password Protection Mode Active flag
reg RdPswdProtEnable = 1'b0;//Read Password Protection Mode Support flag
integer Byte_number = 0;
reg oe = 1'b0;
reg oe_z = 1'b0;
reg [647:0] CFI_array_tmp ;
reg [7:0] CFI_tmp;
integer start_delay;
reg start_autoboot;
integer ABSD;
reg change_addr ;
integer Address = 0;
integer SectorSuspend = 0;
//Sector and subsector addresses
integer SA = 0;
// Sector is protect if Sec_Prot(SecNum) = '1'
reg [SecNum64:0] Sec_Prot = {542{1'b0}};
// timing check violation
reg Viol = 1'b0;
integer WOTPByte;
integer AddrLo;
integer AddrHi;
reg[7:0] old_bit, new_bit;
integer old_int, new_int;
reg[63:0] old_pass;
reg[63:0] new_pass;
integer wr_cnt;
integer cnt;
integer read_cnt = 0;
integer byte_cnt = 1;
integer read_addr = 0;
integer read_addr_tmp = 0;
integer Sec_addr = 0;
integer SecAddr = 0;
integer Page_addr = 0;
integer pgm_page = 0;
reg[7:0] data_out;
reg[647:0] ident_out;
time SCK_cycle = 0;
time prev_SCK;
time start_ddr;
time out_time;
time SCK_SO_DDR;
///////////////////////////////////////////////////////////////////////////////
//Interconnect Path Delay Section
///////////////////////////////////////////////////////////////////////////////
buf (SCK_ipd, SCK);
buf (SI_ipd, SI);
buf (SO_ipd, SO);
buf (CSNeg_ipd, CSNeg);
buf (HOLDNeg_ipd, HOLDNeg);
buf (WPNeg_ipd, WPNeg);
buf (RSTNeg_ipd, RSTNeg);
///////////////////////////////////////////////////////////////////////////////
// Propagation delay Section
///////////////////////////////////////////////////////////////////////////////
nmos (SI, SI_z , 1);
nmos (SO, SO_z , 1);
nmos (HOLDNeg, HOLDNegOut_zd , 1);
nmos (WPNeg, WPNegOut_zd , 1);
wire deg_pin;
wire deg_sin;
wire deg_holdin;
wire deh_pin;
wire deh_sout;
wire deh_ddr_sout;
wire deh_holdin;
//VHDL VITAL CheckEnable equivalents
wire quad_rd;
assign quad_rd = deg_holdin && ~QUAD && (SIOut_z != 1'bz);
wire wr_prot;
assign wr_prot = SRWD && WEL && ~QUAD;
wire dual_rd;
assign dual_rd = dual ;
wire ddro;
assign ddro = ddr && ~ddr80 && ~dual ;
wire ddro80;
assign ddro80 = ddr && ddr80 && ~dual ;
wire ddr_rd;
assign ddr_rd = PoweredUp && ddr;
wire sdr_rd;
assign sdr_rd = PoweredUp && ~ddr;
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_normal =1;
specparam tpd_CSNeg_SO =1;
specparam tpd_HOLDNeg_SO =1;
specparam tpd_RSTNeg_SO =1;
//DDR operation values
specparam tpd_SCK_SO_DDR =1;
//tsetup values: setup times
specparam tsetup_CSNeg_SCK =1;
specparam tsetup_SI_SCK_normal =1;
specparam tsetup_WPNeg_CSNeg =1;
specparam tsetup_HOLDNeg_SCK =1;
specparam tsetup_RSTNeg_CSNeg =1;
// DDR operation values
specparam tsetup_SI_SCK_DDR =1;
specparam tsetup_SI_SCK_DDR_fast =1;
specparam tsetup_CSNeg_SCK_DDR =1;
//thold values: hold times
specparam thold_CSNeg_SCK =1;
specparam thold_SI_SCK_normal =1;
specparam thold_SO_SCK_normal =1;
specparam thold_WPNeg_CSNeg =1;
specparam thold_HOLDNeg_SCK =1;
specparam thold_CSNeg_RSTNeg =1;
// DDR operation values
specparam thold_SI_SCK_DDR =1;
specparam thold_SI_SCK_DDR_fast =1;
specparam thold_CSNeg_SCK_DDR =1;
// tpw values: pulse width
specparam tpw_SCK_serial_posedge =1;
specparam tpw_SCK_dual_posedge =1;
specparam tpw_SCK_fast_posedge =1;
specparam tpw_SCK_quadpg_posedge =1;
specparam tpw_SCK_serial_negedge =1;
specparam tpw_SCK_dual_negedge =1;
specparam tpw_SCK_fast_negedge =1;
specparam tpw_SCK_quadpg_negedge =1;
specparam tpw_CSNeg_read_posedge =1;
specparam tpw_CSNeg_pgers_posedge =1;
specparam tpw_RSTNeg_negedge =1;
specparam tpw_RSTNeg_posedge =1;
// DDR operation values
specparam tpw_SCK_DDR_posedge =1;
specparam tpw_SCK_DDR_negedge =1;
specparam tpw_SCK_DDR80_posedge =1;
specparam tpw_SCK_DDR80_negedge =1;
// tperiod min (calculated as 1/max freq)
specparam tperiod_SCK_serial_rd =1;// 50 MHz
specparam tperiod_SCK_fast_rd =1;//133 MHz
specparam tperiod_SCK_dual_rd =1;//104 MHz
specparam tperiod_SCK_quadpg =1;// 80 MHz
// DDR operation values
specparam tperiod_SCK_DDR_rd =1;// 66 MHz
specparam tperiod_SCK_DDR80_rd =1;// 80 MHz
`ifdef SPEEDSIM
// Page Program Operation
specparam tdevice_PP_256 = 75e7;//tPP
// Page Program Operation
specparam tdevice_PP_512 = 75e7;//tPP
// Typical Byte Programming Time
specparam tdevice_BP = 4e8;//tBP
// Sector Erase Operation
specparam tdevice_SE64 = 10e7; // 650e7;//tSE Dinesh A
// Sector Erase Operation
specparam tdevice_SE256 = 10e7; // 1875e7;//tSE Dinesh A
// Bulk Erase Operation
specparam tdevice_BE = 330e9;//tBE
// WRR Cycle Time
specparam tdevice_WRR = 1; // 2e9;//tW Dinesh A
// Erase Suspend/Erase Resume Time
specparam tdevice_ERSSUSP = 45e6;//tESL
// Program Suspend/Program Resume Time
specparam tdevice_PRGSUSP = 1; // 40e6;// Dinesh A
// VCC (min) to CS# Low
specparam tdevice_PU = 1; // 3e8;//tPU Dinesh A
// PPB Erase Time
specparam tdevice_PPBERASE = 1; // 15e9;// Dinesh A
// Password Unlock Time
specparam tdevice_PASSULCK = 1e6;//
// Password Unlock to Password Unlock Time
specparam tdevice_PASSACC = 100e6;
// Data In Setup Max time
specparam tdevice_TSU = 300e3;
`else
// Page Program Operation
specparam tdevice_PP_256 = 75e7;//tPP
// Page Program Operation
specparam tdevice_PP_512 = 75e7;//tPP
// Typical Byte Programming Time
specparam tdevice_BP = 4e8;//tBP
// Sector Erase Operation
specparam tdevice_SE64 = 650e9;//tSE
// Sector Erase Operation
specparam tdevice_SE256 = 1875e9;//tSE
// Bulk Erase Operation
specparam tdevice_BE = 330e12;//tBE
// WRR Cycle Time
specparam tdevice_WRR = 2e11;//tW
// Erase Suspend/Erase Resume Time
specparam tdevice_ERSSUSP = 45e6;//tESL
// Program Suspend/Program Resume Time
specparam tdevice_PRGSUSP = 40e6;//
// VCC (min) to CS# Low
specparam tdevice_PU = 3e8;//tPU
// PPB Erase Time
specparam tdevice_PPBERASE = 15e9;//
// Password Unlock Time
specparam tdevice_PASSULCK = 1e6;//
// Password Unlock to Password Unlock Time
specparam tdevice_PASSACC = 100e6;
// Data In Setup Max time
specparam tdevice_TSU = 300e3;
`endif // SPEEDSIM
///////////////////////////////////////////////////////////////////////////////
// Input Port Delays don't require Verilog description
///////////////////////////////////////////////////////////////////////////////
// Path delays //
///////////////////////////////////////////////////////////////////////////////
if (~ddr) (SCK => SO) = tpd_SCK_SO_normal;
if (ddr || rd_fast) (SCK => SO) = tpd_SCK_SO_DDR;
if (~ddr && dual) (SCK => SI) = tpd_SCK_SO_normal;
if ( ddr && dual) (SCK => SI) = tpd_SCK_SO_DDR;
if (~ddr && QUAD)(SCK => HOLDNeg) = tpd_SCK_SO_normal;
if ( ddr && QUAD)(SCK => HOLDNeg) = tpd_SCK_SO_DDR;
if (~ddr && QUAD)(SCK => WPNeg) = tpd_SCK_SO_normal;
if ( ddr && QUAD)(SCK => WPNeg) = tpd_SCK_SO_DDR;
if (CSNeg) (CSNeg => SO) = tpd_CSNeg_SO;
if (CSNeg && dual) (CSNeg => SI) = tpd_CSNeg_SO;
if (CSNeg && QUAD) (CSNeg => HOLDNeg) = tpd_CSNeg_SO;
if (CSNeg && QUAD) (CSNeg => WPNeg) = tpd_CSNeg_SO;
if (~QUAD) (HOLDNeg => SO) = tpd_HOLDNeg_SO;
if (~QUAD && dual) (HOLDNeg => SI) = tpd_HOLDNeg_SO;
(RSTNeg => SO) = tpd_RSTNeg_SO;
///////////////////////////////////////////////////////////////////////////////
// Timing Violation //
///////////////////////////////////////////////////////////////////////////////
$setup ( CSNeg , posedge SCK &&& sdr_rd,
tsetup_CSNeg_SCK, Viol);
$setup ( CSNeg , posedge SCK &&& ddr_rd,
tsetup_CSNeg_SCK_DDR, Viol);
$setup ( SI , posedge SCK &&& deg_sin,
tsetup_SI_SCK_normal, Viol);
$setup ( WPNeg , negedge CSNeg &&& wr_prot,
tsetup_WPNeg_CSNeg, Viol);
$setup ( HOLDNeg , posedge SCK &&& quad_rd,
tsetup_HOLDNeg_SCK, Viol);
$setup ( SI , posedge SCK &&& ddro,
tsetup_SI_SCK_DDR, Viol);
$setup ( SI , negedge SCK &&& ddro,
tsetup_SI_SCK_DDR, Viol);
$setup ( SI , posedge SCK &&& ddro80,
tsetup_SI_SCK_DDR, Viol);
$setup ( SI , negedge SCK &&& ddro80,
tsetup_SI_SCK_DDR, Viol);
$setup ( RSTNeg , negedge CSNeg,
tsetup_RSTNeg_CSNeg, Viol);
$hold ( posedge SCK &&& sdr_rd , CSNeg,
thold_CSNeg_SCK, Viol);
$hold ( posedge SCK &&& ddr_rd , CSNeg,
thold_CSNeg_SCK_DDR, Viol);
$hold ( posedge SCK &&& deg_sin , SI ,
thold_SI_SCK_normal, Viol);
$hold ( negedge SCK &&& deh_sout , SO ,
thold_SO_SCK_normal, Viol);
$hold ( negedge SCK &&& deh_ddr_sout , SO ,
thold_SO_SCK_normal, Viol);
$hold ( posedge SCK &&& deh_ddr_sout , SO ,
thold_SO_SCK_normal, Viol);
$hold ( posedge CSNeg &&& wr_prot , WPNeg ,
thold_WPNeg_CSNeg, Viol);
$hold ( posedge SCK &&& quad_rd , HOLDNeg ,
thold_HOLDNeg_SCK, Viol);
$hold ( posedge SCK &&& ddro , SI,
thold_SI_SCK_DDR, Viol);
$hold ( negedge SCK &&& ddro , SI,
thold_SI_SCK_DDR, Viol);
$hold ( posedge SCK &&& ddro80 , SI,
thold_SI_SCK_DDR, Viol);
$hold ( negedge SCK &&& ddro80 , SI,
thold_SI_SCK_DDR, Viol);
$hold ( negedge RSTNeg , CSNeg,
thold_CSNeg_RSTNeg, Viol);
$width ( posedge SCK &&& rd , tpw_SCK_serial_posedge);
$width ( negedge SCK &&& rd , tpw_SCK_serial_negedge);
$width ( posedge SCK &&& dual_rd , tpw_SCK_dual_posedge);
$width ( negedge SCK &&& dual_rd , tpw_SCK_dual_negedge);
$width ( posedge SCK &&& fast_rd , tpw_SCK_fast_posedge);
$width ( negedge SCK &&& fast_rd , tpw_SCK_fast_negedge);
$width ( posedge SCK &&& ddrd , tpw_SCK_DDR_posedge);
$width ( negedge SCK &&& ddrd , tpw_SCK_DDR_negedge);
$width ( posedge SCK &&& ddrd80 , tpw_SCK_DDR80_posedge);
$width ( negedge SCK &&& ddrd80 , tpw_SCK_DDR80_negedge);
$width ( posedge SCK &&& quadpg , tpw_SCK_quadpg_posedge);
$width ( negedge SCK &&& quadpg , tpw_SCK_quadpg_negedge);
$width ( posedge CSNeg &&& RD_EQU_1, tpw_CSNeg_read_posedge);
$width ( posedge CSNeg &&& RD_EQU_0, tpw_CSNeg_pgers_posedge);
$width ( negedge RSTNeg , tpw_RSTNeg_negedge);
$width ( posedge RSTNeg , tpw_RSTNeg_posedge);
$period ( posedge SCK &&& rd , tperiod_SCK_serial_rd);
$period ( posedge SCK &&& fast_rd , tperiod_SCK_fast_rd);
$period ( posedge SCK &&& dual_rd , tperiod_SCK_dual_rd);
$period ( posedge SCK &&& quadpg , tperiod_SCK_quadpg);
$period ( posedge SCK &&& ddrd , tperiod_SCK_DDR_rd);
$period ( posedge SCK &&& ddrd80 , tperiod_SCK_DDR80_rd);
endspecify
///////////////////////////////////////////////////////////////////////////////
// Main Behavior Block //
///////////////////////////////////////////////////////////////////////////////
// FSM states
parameter IDLE = 5'd0;
parameter RESET_STATE = 5'd1;
parameter AUTOBOOT = 5'd2;
parameter WRITE_SR = 5'd3;
parameter PAGE_PG = 5'd4;
parameter OTP_PG = 5'd5;
parameter PG_SUSP = 5'd6;
parameter SECTOR_ERS = 5'd7;
parameter BULK_ERS = 5'd8;
parameter ERS_SUSP = 5'd9;
parameter ERS_SUSP_PG = 5'd10;
parameter ERS_SUSP_PG_SUSP= 5'd11;
parameter PASS_PG = 5'd12;
parameter PASS_UNLOCK = 5'd13;
parameter PPB_PG = 5'd14;
parameter PPB_ERS = 5'd15;
parameter AUTOBOOT_PG = 5'd16;
parameter ASP_PG = 5'd17;
parameter PLB_PG = 5'd18;
parameter DYB_PG = 5'd19;
parameter NVDLR_PG = 5'd20;
reg [4:0] current_state;
reg [4:0] next_state;
// Instruction type
parameter NONE = 7'd0;
parameter WRR = 7'd1;
parameter PP = 7'd2;
parameter READ = 7'd3;
parameter WRDI = 7'd4;
parameter RDSR = 7'd5;
parameter WREN = 7'd6;
parameter RDSR2 = 7'd7;
parameter FSTRD = 7'd8;
parameter FSTRD4 = 7'd9;
parameter DDRFR = 7'd10;
parameter DDRFR4 = 7'd11;
parameter PP4 = 7'd12;
parameter RD4 = 7'd13;
parameter ABRD = 7'd14;
parameter ABWR = 7'd15;
parameter BRRD = 7'd16;
parameter BRWR = 7'd17;
parameter P4E = 7'd19;
parameter P4E4 = 7'd20;
parameter ASPRD = 7'd21;
parameter ASPP = 7'd22;
parameter CLSR = 7'd23;
parameter QPP = 7'd24;
parameter QPP4 = 7'd25;
parameter RDCR = 7'd26;
parameter DOR = 7'd27;
parameter DOR4 = 7'd28;
parameter DLPRD = 7'd29;
parameter OTPP = 7'd30;
parameter PNVDLR = 7'd31;
parameter OTPR = 7'd32;
parameter WVDLR = 7'd33;
parameter BE = 7'd34;
parameter QOR = 7'd35;
parameter QOR4 = 7'd36;
parameter ERSP = 7'd37;
parameter ERRS = 7'd38;
parameter PGSP = 7'd39;
parameter PGRS = 7'd40;
parameter REMS = 7'd41;
parameter RDID = 7'd42;
parameter MPM = 7'd43;
parameter PLBWR = 7'd44;
parameter PLBRD = 7'd45;
parameter RES = 7'd46;
parameter DIOR = 7'd47;
parameter DIOR4 = 7'd48;
parameter DDRDIOR = 7'd49;
parameter DDRDIOR4 = 7'd50;
parameter SE = 7'd51;
parameter SE4 = 7'd52;
parameter DYBRD = 7'd53;
parameter DYBWR = 7'd54;
parameter PPBRD = 7'd55;
parameter PPBP = 7'd56;
parameter PPBERS = 7'd57;
parameter PASSRD = 7'd58;
parameter PASSP = 7'd59;
parameter PASSU = 7'd60;
parameter QIOR = 7'd61;
parameter QIOR4 = 7'd62;
parameter DDRQIOR = 7'd63;
parameter DDRQIOR4 = 7'd64;
parameter RESET = 7'd65;
parameter MBR = 7'd66;
parameter BRAC = 7'd67;
parameter ECCRD = 7'd68;
reg [6:0] Instruct;
//Bus cycle state
parameter STAND_BY = 3'd0;
parameter OPCODE_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 @(SO_in, SO_z)
begin
if (SO_in==SO_z)
deq_pin=1'b0;
else
deq_pin=1'b1;
end
// check when data is generated from model to avoid setuphold check in
// this occasion
assign deg_pin = deq_pin;
assign deh_pin = (deq_pin == 1'b0) && (SO_z != 1'bz);
reg deq_sin;
always @(SI_in, SIOut_z)
begin
if (SI_in==SIOut_z)
deq_sin=1'b0;
else
deq_sin=1'b1;
end
// check when data is generated from model to avoid setuphold check in
// this occasion
assign deg_sin=deq_sin
&& (ddr == 1'b0) && (Instruct !== DDRFR)
&& (Instruct !== DDRFR4) && (Instruct !== DDRDIOR)
&& (Instruct !== DDRDIOR4) && (Instruct !== DDRQIOR)
&& (Instruct !== DDRQIOR4) && (SIOut_z != 1'bz);
reg deq_sout;
always @(SO_out, SIOut_z)
begin
if (SO_out==SIOut_z)
deq_sout=1'b0;
else
deq_sout=1'b1;
end
// check when data is generated from model
assign deh_sout= (deq_sout == 1'b0)
&& (ddr == 1'b0) && (SOut_z != 1'bz);
assign deh_ddr_sout= (deq_sout == 1'b0)
&& (ddr == 1'b1) && (SOut_z != 1'bz);
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
// this occasion
assign deg_holdin=deq_holdin;
assign deh_holdin=(deq_holdin == 1'b0) && (HOLDNegOut_zd != 1'bz);
//Power Up time;
initial
begin
PoweredUp = 1'b0;
$display("%0t=>STATUS: SPI FLASH POWER UP Wait Time: %0d:%0d",$time,tdevice_PU,tdevice_PRGSUSP);
#tdevice_PU PoweredUp = 1'b1;
$display("%0t=>STATUS: SPI FLASH POWER UP",$time,);
end
initial
begin : Init
write = 1'b0;
cfg_write = 1'b0;
read_out = 1'b0;
Address = 0;
change_addr = 1'b0;
cnt = 0;
RST = 1'b0;
RST_in = 1'b0;
RST_out = 1'b1;
PDONE = 1'b1;
PSTART = 1'b0;
PGSUSP = 1'b0;
PGRES = 1'b0;
PRGSUSP_in = 1'b0;
ERSSUSP_in = 1'b0;
RES_TO_SUSP_MIN_TIME = 1'b0;
RES_TO_SUSP_TYP_TIME = 1'b0;
EDONE = 1'b1;
ESTART = 1'b0;
ESUSP = 1'b0;
ERES = 1'b0;
WDONE = 1'b1;
WSTART = 1'b0;
Reseted = 1'b0;
Instruct = NONE;
bus_cycle_state = STAND_BY;
current_state = RESET_STATE;
next_state = RESET_STATE;
end
// initialize memory and load preload files if any
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
//s25fl256s.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)
$display("%m: Loading Memfile : %s",mem_file_name);
$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
//s25fl256s_otp memory file
// / - comment
// @aaaaaa - <aaaaaa> stands for address within last defined
// sector
// dd - <dd> is byte to be written at OTPMem(aaa++)
// (aa is incremented at every load)
// only first 1-4 columns are loaded. NO empty lines !!!!!!!!!!!!!!!!
$readmemh(otp_file_name,OTPMem);
end
LOCK_BYTE1[7:0] = OTPMem[16];
LOCK_BYTE2[7:0] = OTPMem[17];
LOCK_BYTE3[7:0] = OTPMem[18];
LOCK_BYTE4[7:0] = OTPMem[19];
end
// initialize memory and load preload files if any
initial
begin: InitTimingModel
integer i;
integer j;
//UNIFORM OR HYBRID arch model is used
//assumptions:
//1. TimingModel has format as S25FL128SXXXXXXXX_X_XXpF
//it is important that 16-th character from first one is "0" or "1"
//2. TimingModel does not have more then 24 characters
tmp_timing = TimingModel;//copy of TimingModel
i = 23;
while ((i >= 0) && (found != 1'b1))//search for first non null character
begin //i keeps position of first non null character
j = 7;
while ((j >= 0) && (found != 1'b1))
begin
if (tmp_timing[i*8+j] != 1'd0)
found = 1'b1;
else
j = j-1;
end
i = i - 1;
end
i = i +1;
if (found)//if non null character is found
begin
for (j=0;j<=7;j=j+1)
begin
//EHPLC/HPLC character is 15
tmp_char1[j] = TimingModel[(i-14)*8+j];
//256B/512B Page character is 16
tmp_char2[j] = TimingModel[(i-15)*8+j];
end
end
if (tmp_char1 == "0" || tmp_char1 == "2" || tmp_char1 == "3" ||
tmp_char1 == "R" || tmp_char1 == "A" || tmp_char1 == "B" ||
tmp_char1 == "C" || tmp_char1 == "D" || tmp_char1 == "Y" ||
tmp_char1 == "Z" || tmp_char1 == "S" || tmp_char1 == "T" ||
tmp_char1 == "K" || tmp_char1 == "L")
begin
EHP = 1;
if(tmp_char1 == "Z" || tmp_char1 == "S" || tmp_char1 == "T" ||
tmp_char1 == "K" || tmp_char1 == "L" || tmp_char1 == "Y")
begin
RdPswdProtEnable = 1;
end
end
else if (tmp_char1 == "4" || tmp_char1 == "6" || tmp_char1 == "7" ||
tmp_char1 == "8" || tmp_char1 == "9" || tmp_char1 == "Q")
begin
EHP = 0;
end
if (tmp_char1 == "0" || tmp_char1 == "2" || tmp_char1 == "3" ||
tmp_char1 == "R" || tmp_char1 == "A" || tmp_char1 == "B" ||
tmp_char1 == "C" || tmp_char1 == "D" || tmp_char1 == "4" ||
tmp_char1 == "6" || tmp_char1 == "7" || tmp_char1 == "8" ||
tmp_char1 == "9" || tmp_char1 == "Q")
begin
ASP_reg = 16'hFE7F;
ASP_reg_in = 16'hFE7F;
end
else if (tmp_char1 == "Y" || tmp_char1 == "Z" || tmp_char1 == "S" ||
tmp_char1 == "T" || tmp_char1 == "K" || tmp_char1 == "L")
begin
ASP_reg = 16'hFE4F;
ASP_reg_in = 16'hFE4F;
end
if (tmp_char2 == "0")
begin
PageSize = 255;
PageNum = PageNum64;
SecSize = SecSize64;
end
else if (tmp_char2 == "1")
begin
PageSize = 511;
PageNum = PageNum256;
SecSize = SecSize256;
end
end
//CFI
initial
begin: InitCFI
integer i;
integer j;
///////////////////////////////////////////////////////////////////////
// ID-CFI array data
///////////////////////////////////////////////////////////////////////
// Manufacturer and Device ID
CFI_array[8'h00] = Jedec_ID;
CFI_array[8'h01] = DeviceID1;
CFI_array[8'h02] = DeviceID2;
CFI_array[8'h03] = 8'h00;
if (tmp_char2 == "0")
// Uniform 64kB sectors
CFI_array[8'h04] = ExtendedID64;
else if (tmp_char2 == "1")
// Uniform 256kB sectors
CFI_array[8'h04] = ExtendedID256;
CFI_array[8'h05] = 8'h80;
CFI_array[8'h06] = 8'h00;
CFI_array[8'h07] = 8'h00;
CFI_array[8'h08] = 8'h00;
CFI_array[8'h09] = 8'h00;
CFI_array[8'h0A] = 8'h00;
CFI_array[8'h0B] = 8'h00;
CFI_array[8'h0C] = 8'h00;
CFI_array[8'h0D] = 8'h00;
CFI_array[8'h0E] = 8'h00;
CFI_array[8'h0F] = 8'h00;
// CFI Query Identification String
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'h53;
CFI_array[8'h18] = 8'h46;
CFI_array[8'h19] = 8'h51;
CFI_array[8'h1A] = 8'h00;
//CFI 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'h06;
if (tmp_char2 == "0")
begin
// 64kB sector and 256B page
CFI_array[8'h20] = 8'h08;
CFI_array[8'h21] = 8'h08;
end
else if (tmp_char2 == "1")
begin
// 256kB sector and 512B page
CFI_array[8'h20] = 8'h09;
CFI_array[8'h21] = 8'h09;
end
CFI_array[8'h22] = 8'h10;
CFI_array[8'h23] = 8'h02;
CFI_array[8'h24] = 8'h02;
CFI_array[8'h25] = 8'h03;
CFI_array[8'h26] = 8'h03;
// Device Geometry Definition(Uniform Sector Devices)
CFI_array[8'h27] = 8'h19;
CFI_array[8'h28] = 8'h02;
CFI_array[8'h29] = 8'h01;
if (tmp_char2 == "0")
// 64kB sectors
CFI_array[8'h2A] = 8'h08;
else if (tmp_char2 == "1")
CFI_array[8'h2A] = 8'h09;
CFI_array[8'h2B] = 8'h00;
if (tmp_char2 == "1")
begin
CFI_array[8'h2C] = 8'h01;
CFI_array[8'h2D] = 8'h7F;
CFI_array[8'h2E] = 8'h00;
CFI_array[8'h2F] = 8'h00;
CFI_array[8'h30] = 8'h04;
CFI_array[8'h31] = 8'hFF;
CFI_array[8'h32] = 8'hFF;
CFI_array[8'h33] = 8'hFF;
CFI_array[8'h34] = 8'hFF;
end
else
begin
CFI_array[8'h2C] = 8'h02;
if (TBPARM)
begin
// 4KB physical sectors at top
CFI_array[8'h2D] = 8'hFD;
CFI_array[8'h2E] = 8'h00;
CFI_array[8'h2F] = 8'h00;
CFI_array[8'h30] = 8'h01;
CFI_array[8'h31] = 8'h1F;
CFI_array[8'h32] = 8'h01;
CFI_array[8'h33] = 8'h10;
CFI_array[8'h34] = 8'h00;
end
else
begin
// 4KB physical sectors at bottom
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'hFD;
CFI_array[8'h32] = 8'h01;
CFI_array[8'h33] = 8'h00;
CFI_array[8'h34] = 8'h01;
end
end
CFI_array[8'h35] = 8'hFF;
CFI_array[8'h36] = 8'hFF;
CFI_array[8'h37] = 8'hFF;
CFI_array[8'h38] = 8'hFF;
CFI_array[8'h39] = 8'hFF;
CFI_array[8'h3A] = 8'hFF;
CFI_array[8'h3B] = 8'hFF;
CFI_array[8'h3C] = 8'hFF;
CFI_array[8'h3D] = 8'hFF;
CFI_array[8'h3E] = 8'hFF;
CFI_array[8'h3F] = 8'hFF;
// CFI 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'h21;
CFI_array[8'h46] = 8'h02;
CFI_array[8'h47] = 8'h01;
CFI_array[8'h48] = 8'h00;
CFI_array[8'h49] = 8'h08;
CFI_array[8'h4A] = 8'h00;
CFI_array[8'h4B] = 8'h01;
CFI_array[8'h4C] = 8'h00;
CFI_array[8'h4D] = 8'h00;
CFI_array[8'h4E] = 8'h00;
CFI_array[8'h4F] = 8'h07;
CFI_array[8'h50] = 8'h01;
begin
for(i=80;i>=0;i=i-1)
begin
CFI_tmp = CFI_array[8'h00-i+80];
for(j=7;j>=0;j=j-1)
begin
CFI_array_tmp[8*i+j] = CFI_tmp[j];
end
end
end
end
always @(next_state_event or PoweredUp or RST or RST_out or
RSTNeg_in or rising_edge_RSTNeg or falling_edge_RST)
begin: StateTransition
if (PoweredUp)
begin
if ((RSTNeg_in == 1'b1) && (RST_out == 1'b1))
current_state = #(1000) next_state;
else if ((~RSTNeg_in || rising_edge_RSTNeg) && falling_edge_RST)
begin
// no state transition while RESET# low
current_state = RESET_STATE;
RST_in = 1'b1;
#1000 RST_in = 1'b0;
end
end
end
always @(posedge RST_in)
begin:Threset
RST_out = 1'b0;
#(35000000-200000) RST_out = 1'b1;
end
always @(negedge CSNeg_ipd)
begin:CheckCEOnPowerUP
if (~PoweredUp)
$display ("%0t=> Device is selected during Power Up",$time);
end
///////////////////////////////////////////////////////////////////////////
//// Internal Delays
///////////////////////////////////////////////////////////////////////////
always @(posedge PRGSUSP_in)
begin:PRGSuspend
PRGSUSP_out = 1'b0;
#tdevice_PRGSUSP PRGSUSP_out = 1'b1;
end
always @(posedge PPBERASE_in)
begin:PPBErs
PPBERASE_out = 1'b0;
#tdevice_PPBERASE PPBERASE_out = 1'b1;
end
always @(posedge ERSSUSP_in)
begin:ERSSuspend
ERSSUSP_out = 1'b0;
#tdevice_ERSSUSP ERSSUSP_out = 1'b1;
end
always @(posedge PASSULCK_in)
begin:PASSULock
PASSULCK_out = 1'b0;
#tdevice_PASSULCK PASSULCK_out = 1'b1;
end
always @(posedge PASSACC_in)
begin:PASSAcc
PASSACC_out = 1'b0;
#tdevice_PASSACC PASSACC_out = 1'b1;
end
///////////////////////////////////////////////////////////////////////////////
// write cycle decode
///////////////////////////////////////////////////////////////////////////////
integer opcode_cnt = 0;
integer addr_cnt = 0;
integer mode_cnt = 0;
integer dummy_cnt = 0;
integer data_cnt = 0;
integer bit_cnt = 0;
reg [4095:0] Data_in = 4096'b0;
reg [7:0] opcode;
reg [7:0] opcode_in;
reg [7:0] opcode_tmp;
reg [31:0] addr_bytes;
reg [31:0] hiaddr_bytes;
reg [31:0] Address_in;
reg [7:0] mode_bytes;
reg [7:0] mode_in;
integer Latency_code;
integer quad_data_in [0:1023];
reg [3:0] quad_nybble = 4'b0;
reg [3:0] Quad_slv;
reg [7:0] Byte_slv;
always @(rising_edge_CSNeg_ipd or falling_edge_CSNeg_ipd or
rising_edge_SCK_ipd or falling_edge_SCK_ipd or
current_state)
begin: Buscycle
integer i;
integer j;
integer k;
time CLK_PER;
time LAST_CLK;
if (current_state == RESET_STATE)
bus_cycle_state = STAND_BY;
else
begin
if (falling_edge_CSNeg_ipd)
begin
if (bus_cycle_state==STAND_BY)
begin
Instruct = NONE;
write = 1'b1;
cfg_write = 0;
opcode_cnt = 0;
addr_cnt = 0;
mode_cnt = 0;
dummy_cnt = 0;
data_cnt = 0;
opcode_tmp = 0;
start_dlp = 0;
DOUBLE = 1'b0;
QUADRD = 1'b0;
CLK_PER = 1'b0;
LAST_CLK = 1'b0;
if (current_state == AUTOBOOT)
begin
bus_cycle_state = DATA_BYTES;
end
else
begin
bus_cycle_state = OPCODE_BYTE;
end
end
end
if (rising_edge_SCK_ipd) // Instructions, addresses or data present
begin // at SI are latched on the rising edge of SCK
CLK_PER = $time - LAST_CLK;
LAST_CLK = $time;
if (CHECK_FREQ)
begin
if ((CLK_PER < 20000 && Latency_code == 3) ||
(CLK_PER < 12500 && Latency_code == 0) ||
(CLK_PER < 11100 && Latency_code == 1) ||
(CLK_PER < 9600 && Latency_code == 2))
begin
$display ("More wait states are required for");
$display ("this clock frequency value");
end
if (Instruct == DDRFR || Instruct == DDRFR4 || Instruct == DDRDIOR ||
Instruct == DDRDIOR4 || Instruct == DDRQIOR || Instruct == DDRQIOR4)
begin
if (CLK_PER < 12500)
begin
ddr80 = 1'b1;
end
else
begin
ddr80 = 1'b0;
end
end
CHECK_FREQ = 0;
end
if (~CSNeg_ipd)
begin
case (bus_cycle_state)
OPCODE_BYTE:
begin
if ((HOLDNeg_in && ~QUAD) || QUAD)
begin
opcode_in[opcode_cnt] = SI_in;
opcode_cnt = opcode_cnt + 1;
Latency_code = Config_reg1[7:6];
if (opcode_cnt == BYTE)
begin
for(i=7;i>=0;i=i-1)
begin
opcode[i] = opcode_in[7-i];
end
case (opcode)
8'b00000110 : // 06h
begin
Instruct = WREN;
bus_cycle_state = DATA_BYTES;
end
8'b00000100 : // 04h
begin
Instruct = WRDI;
bus_cycle_state = DATA_BYTES;
end
8'b00000001 : // 01h
begin
Instruct = WRR;
bus_cycle_state = DATA_BYTES;
end
8'b00000011 : // 03h
begin
Instruct = READ;
bus_cycle_state = ADDRESS_BYTES;
end
8'b00010011 : // 13h
begin
Instruct = RD4;
bus_cycle_state = ADDRESS_BYTES;
end
8'b01001011 : // 4Bh
begin
Instruct = OTPR;
bus_cycle_state = ADDRESS_BYTES;
end
8'b00000101 : // 05h
begin
Instruct = RDSR;
bus_cycle_state = DATA_BYTES;
end
8'b00000111 : // 07h
begin
Instruct = RDSR2;
bus_cycle_state = DATA_BYTES;
end
8'b00110101 : // 35h
begin
Instruct = RDCR;
bus_cycle_state = DATA_BYTES;
end
8'b10010000 : // 90h
begin
Instruct = REMS;
bus_cycle_state = ADDRESS_BYTES;
end
8'b10011111 : // 9Fh
begin
Instruct = RDID;
bus_cycle_state = DATA_BYTES;
end
8'b10101011 : // ABh
begin
Instruct = RES;
bus_cycle_state = DUMMY_BYTES;
end
8'b00001011 : // 0Bh
begin
Instruct = FSTRD;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b00001100 : // 0Ch
begin
Instruct = FSTRD4;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b00001101 : // 0Dh
begin
Instruct = DDRFR;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b00001110 : // 0Eh
begin
Instruct = DDRFR4;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b00111011 : // 3Bh
begin
Instruct = DOR;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b00111100 : // 3Ch
begin
Instruct = DOR4;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b10111011 : // BBh
begin
Instruct = DIOR;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b10111100 : // BCh
begin
Instruct = DIOR4;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b10111101 : // BDh
begin
Instruct = DDRDIOR;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b10111110 : // BEh
begin
Instruct = DDRDIOR4;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b01101011 : // 6Bh
begin
Instruct = QOR;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b01101100 : // 6Ch
begin
Instruct = QOR4;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b11101011 : // EBh
begin
Instruct = QIOR;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b11101100 : // ECh
begin
Instruct = QIOR4;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b11101101 : // EDh
begin
Instruct = DDRQIOR;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b11101110 : // EEh
begin
Instruct = DDRQIOR4;
bus_cycle_state = ADDRESS_BYTES;
CHECK_FREQ = 1'b1;
end
8'b00000010 : // 02h
begin
Instruct = PP;
bus_cycle_state = ADDRESS_BYTES;
end
8'b00010010 : // 12h
begin
Instruct = PP4;
bus_cycle_state = ADDRESS_BYTES;
end
8'b00110010: // 32h
begin
Instruct = QPP;
bus_cycle_state = ADDRESS_BYTES;
quad_pg = 1'b1;
end
8'b00111000: // 38h
begin
Instruct = QPP;
bus_cycle_state = ADDRESS_BYTES;
quad_pg = 1'b1;
end
8'b00110100 : // 34h
begin
Instruct = QPP4;
bus_cycle_state = ADDRESS_BYTES;
quad_pg = 1'b1;
end
8'b01000010 : // 42h
begin
Instruct = OTPP;
bus_cycle_state = ADDRESS_BYTES;
end
8'b10000101 : // 85h
begin
Instruct = PGSP;
bus_cycle_state = DATA_BYTES;
end
8'b10001010 : // 8Ah
begin
Instruct = PGRS;
bus_cycle_state = DATA_BYTES;
end
8'b11000111 : // C7h
begin
Instruct = BE;
bus_cycle_state = DATA_BYTES;
end
8'b01100000 : // 60h
begin
Instruct = BE;
bus_cycle_state = DATA_BYTES;
end
8'b11011000 : // D8h
begin
Instruct = SE;
bus_cycle_state = ADDRESS_BYTES;
end
8'b11011100 : // DCh
begin
Instruct = SE4;
bus_cycle_state = ADDRESS_BYTES;
end
8'b01110101 : // 75h
begin
Instruct = ERSP;
bus_cycle_state = DATA_BYTES;
end
8'b01111010 : // 7Ah
begin
Instruct = ERRS;
bus_cycle_state = DATA_BYTES;
end
8'b00010100 : // 14h
begin
Instruct = ABRD;
bus_cycle_state = DATA_BYTES;
end
8'b00010101 : // 15h
begin
Instruct = ABWR;
bus_cycle_state = DATA_BYTES;
end
8'b00010110 : // 16h
begin
Instruct = BRRD;
bus_cycle_state = DATA_BYTES;
end
8'b00010111 : // 17h
begin
Instruct = BRWR;
bus_cycle_state = DATA_BYTES;
end
8'b00101011 : // 2Bh
begin
Instruct = ASPRD;
bus_cycle_state = DATA_BYTES;
end
8'b00101111 : // 2Fh
begin
Instruct = ASPP;
bus_cycle_state = DATA_BYTES;
end
8'b11100000 : // E0h
begin
Instruct = DYBRD;
bus_cycle_state = ADDRESS_BYTES;
end
8'b11100001 : // E1h
begin
Instruct = DYBWR;
bus_cycle_state = ADDRESS_BYTES;
end
8'b11100010 : // E2h
begin
Instruct = PPBRD;
bus_cycle_state = ADDRESS_BYTES;
end
8'b11100011 : // E3h
begin
Instruct = PPBP;
bus_cycle_state = ADDRESS_BYTES;
end
8'b11100100 : // E4h
begin
Instruct = PPBERS;
bus_cycle_state = DATA_BYTES;
end
8'b10100110 : // A6h
begin
Instruct = PLBWR;
bus_cycle_state = DATA_BYTES;
end
8'b10100111 : // A7h
begin
Instruct = PLBRD;
bus_cycle_state = DATA_BYTES;
end
8'b11100111 : // E7h
begin
Instruct = PASSRD;
bus_cycle_state = DATA_BYTES;
end
8'b11101000 : // E8h
begin
Instruct = PASSP;
bus_cycle_state = DATA_BYTES;
end
8'b11101001 : // E9h
begin
Instruct = PASSU;
bus_cycle_state = DATA_BYTES;
end
8'b11110000 : // F0h
begin
Instruct = RESET;
bus_cycle_state = DATA_BYTES;
end
8'b00110000 : // 30h
begin
Instruct = CLSR;
bus_cycle_state = DATA_BYTES;
end
8'b00100000 : // 20h
begin
Instruct = P4E;
bus_cycle_state = ADDRESS_BYTES;
end
8'b00100001 : // 21h
begin
Instruct = P4E4;
bus_cycle_state = ADDRESS_BYTES;
end
8'b01000001 : // 41h
begin
Instruct = DLPRD;
bus_cycle_state = DATA_BYTES;
end
8'b01000011 : // 43h
begin
Instruct = PNVDLR;
bus_cycle_state = DATA_BYTES;
end
8'b01001010 : // 4Ah
begin
Instruct = WVDLR;
bus_cycle_state = DATA_BYTES;
end
8'b10111001 : // B9h
begin
Instruct = BRAC;
bus_cycle_state = DATA_BYTES;
end
8'b11111111 : // FFh
begin
Instruct = MBR;
bus_cycle_state = MODE_BYTE;
end
8'b00011000 : // 18h
begin
Instruct = ECCRD;
bus_cycle_state = ADDRESS_BYTES;
end
endcase
end
end
end //end of OPCODE BYTE
ADDRESS_BYTES :
begin
if ((Instruct == DDRFR) || (Instruct == DDRFR4) ||
(Instruct == DDRDIOR) || (Instruct == DDRDIOR4) ||
(Instruct == DDRQIOR) || (Instruct == DDRQIOR4))
DOUBLE = 1'b1;
else
DOUBLE = 1'b0;
if ((Instruct == QOR) || (Instruct == QOR4) ||
(Instruct == QIOR) || (Instruct == QIOR4) ||
(Instruct == DDRQIOR) || (Instruct == DDRQIOR4))
QUADRD = 1'b1;
else
QUADRD = 1'b0;
if (DOUBLE == 1'b0)
begin
if (((((Instruct == FSTRD) && (~EXTADD)) ||
((Instruct == DOR) && (~EXTADD)) ||
(Instruct == OTPR)) &&
((HOLDNeg_in && ~QUAD) || QUAD)) ||
((Instruct == QOR) && QUAD && (~EXTADD)))
begin
//Instruction + 3 Bytes Address + Dummy Byte
Address_in[addr_cnt] = SI_in;
addr_cnt = addr_cnt + 1;
if (addr_cnt == 3*BYTE)
begin
for(i=23;i>=0;i=i-1)
begin
addr_bytes[23-i] = Address_in[i];
end
addr_bytes[31:25] = 7'b0000000;
addr_bytes[24] = Bank_Addr_reg[0];
Address = addr_bytes ;
change_addr = 1'b1;
#1 change_addr = 1'b0;
if (Instruct==FSTRD || Instruct==DOR ||
Instruct == QOR)
begin
if (Latency_code == 3)
bus_cycle_state = DATA_BYTES;
else
bus_cycle_state = DUMMY_BYTES;
end
else
bus_cycle_state = DUMMY_BYTES;
end
end
else if (Instruct==ECCRD)
begin
//Instruction + 4 Bytes Address + Dummy Byte
Address_in[addr_cnt] = SI_in;
addr_cnt = addr_cnt + 1;
if (addr_cnt == 4*BYTE)
begin
for(i=31;i>=0;i=i-1)
begin
hiaddr_bytes[31-i] = Address_in[i];
end
//High order address bits are ignored
Address = {hiaddr_bytes[31:4],4'b0000};
change_addr = 1'b1;
#1 change_addr = 1'b0;
bus_cycle_state = DUMMY_BYTES;
end
end
else if ((((Instruct==FSTRD4) ||
(Instruct==DOR4) ||
((Instruct==FSTRD) && EXTADD) ||
((Instruct==DOR) && EXTADD)) &&
((HOLDNeg_in && ~QUAD) || QUAD)) ||
((Instruct==QOR4) && QUAD) ||
((Instruct==QOR) && QUAD && EXTADD))
begin
//Instruction + 4 Bytes Address + Dummy Byte
Address_in[addr_cnt] = SI_in;
addr_cnt = addr_cnt + 1;
if (addr_cnt == 4*BYTE)
begin
for(i=31;i>=0;i=i-1)
begin
hiaddr_bytes[31-i] = Address_in[i];
end
//High order address bits are ignored
Address = {7'b0000000,hiaddr_bytes[24:0]};
change_addr = 1'b1;
#1 change_addr = 1'b0;
if (Latency_code == 3)
bus_cycle_state = DATA_BYTES;
else
begin
bus_cycle_state = DUMMY_BYTES;
end
end
end
else if ((Instruct==DIOR) && (~EXTADD) &&
((HOLDNeg_in && ~QUAD) || QUAD))
begin
//DUAL I/O High Performance Read(3 Bytes Addr)
Address_in[2*addr_cnt] = SO_in;
Address_in[2*addr_cnt + 1] = SI_in;
read_cnt = 0;
addr_cnt = addr_cnt + 1;
if (addr_cnt == 3*BYTE/2)
begin
addr_cnt = 0;
for(i=23;i>=0;i=i-1)
begin
addr_bytes[23-i]=Address_in[i];
end
addr_bytes[31:25] = 7'b0000000;
addr_bytes[24] = Bank_Addr_reg[0];
Address = addr_bytes;
change_addr = 1'b1;
#1 change_addr = 1'b0;
if (EHP)
bus_cycle_state = MODE_BYTE;
else
bus_cycle_state = DUMMY_BYTES;
end
end
else if (((Instruct==DIOR4) ||
((Instruct==DIOR) && EXTADD)) &&
((HOLDNeg_in && ~QUAD) || QUAD))
begin //DUAL I/O High Performance Read(4Bytes Addr)
Address_in[2*addr_cnt] = SO_in;
Address_in[2*addr_cnt + 1] = SI_in;
read_cnt = 0;
addr_cnt = addr_cnt + 1;
if (addr_cnt == 4*BYTE/2)
begin
addr_cnt = 0;
for(i=31;i>=0;i=i-1)
begin
addr_bytes[31-i] = Address_in[i];
end
Address = {7'b0000000,addr_bytes[24:0]};
change_addr = 1'b1;
#1 change_addr = 1'b0;
if (EHP)
bus_cycle_state = MODE_BYTE;
else
bus_cycle_state = DUMMY_BYTES;
end
end
else if ((Instruct == QIOR) && (~EXTADD))
begin
//QUAD I/O High Performance Read (3Bytes Address)
if (QUAD)
begin
Address_in[4*addr_cnt] = HOLDNeg_in;
Address_in[4*addr_cnt+1] = WPNeg_in;
Address_in[4*addr_cnt+2] = SO_in;
Address_in[4*addr_cnt+3] = SI_in;
read_cnt = 0;
addr_cnt = addr_cnt + 1;
if (addr_cnt == 3*BYTE/4)
begin
addr_cnt = 0;
for(i=23;i>=0;i=i-1)
begin
addr_bytes[23-i] = Address_in[i];
end
addr_bytes[31:25] = 7'b0000000;
addr_bytes[24] = Bank_Addr_reg[0];
Address = addr_bytes;
change_addr = 1'b1;
#1 change_addr = 1'b0;
bus_cycle_state = MODE_BYTE;
end
end
else
bus_cycle_state = STAND_BY;
end
else if ((Instruct==QIOR4) || ((Instruct==QIOR)
&& EXTADD))
begin
//QUAD I/O High Performance Read (4Bytes Addr)
if (QUAD)
begin
Address_in[4*addr_cnt] = HOLDNeg_in;
Address_in[4*addr_cnt+1] = WPNeg_in;
Address_in[4*addr_cnt+2] = SO_in;
Address_in[4*addr_cnt+3] = SI_in;
read_cnt = 0;
addr_cnt = addr_cnt +1;
if (addr_cnt == 4*BYTE/4)
begin
addr_cnt =0;
for(i=31;i>=0;i=i-1)
begin
hiaddr_bytes[31-i] = Address_in[i];
end
//High order address bits are ignored
Address = {7'b0000000,hiaddr_bytes[24:0]};
change_addr = 1'b1;
#1 change_addr = 1'b0;
bus_cycle_state = MODE_BYTE;
end
end
else
bus_cycle_state = STAND_BY;
end
else if ((((Instruct==RD4) || (Instruct==PP4) ||
(Instruct==SE4) ||(Instruct==PPBRD) ||
(Instruct==DYBRD) ||(Instruct==DYBWR) ||
(Instruct==PPBP) || (Instruct==P4E4) ||
((Instruct==READ) && EXTADD) ||
((Instruct==PP) && EXTADD) ||
((Instruct==P4E) && EXTADD) ||
((Instruct==SE) && EXTADD)) &&
((HOLDNeg_in && ~QUAD) || QUAD)) ||
(QUAD && (Instruct==QPP4 ||
((Instruct==QPP) && EXTADD))))
begin
Address_in[addr_cnt] = SI_in;
addr_cnt = addr_cnt + 1;
if (addr_cnt == 4*BYTE)
begin
for(i=31;i>=0;i=i-1)
begin
hiaddr_bytes[31-i] = Address_in[i];
end
//High order address bits are ignored
Address = {7'b0000000,hiaddr_bytes[24:0]};
change_addr = 1'b1;
#1 change_addr = 1'b0;
bus_cycle_state = DATA_BYTES;
end
end
else if (((HOLDNeg_in && ~QUAD) || QUAD) &&
(~EXTADD))
begin
Address_in[addr_cnt] = SI_in;
addr_cnt = addr_cnt + 1;
if (addr_cnt == 3*BYTE)
begin
for(i=23;i>=0;i=i-1)
begin
addr_bytes[23-i] = Address_in[i];
end
addr_bytes[31:25] = 7'b0000000;
addr_bytes[24] = Bank_Addr_reg[0];
Address = addr_bytes;
change_addr = 1'b1;
#1 change_addr = 1'b0;
bus_cycle_state = DATA_BYTES;
end
end
end
else
begin
if ((Instruct==DDRFR) && (~EXTADD))
//Fast DDR Read Mode
begin
Address_in[addr_cnt] = SI_in;
if ((addr_cnt/2) <= 16)
begin
opcode_tmp[addr_cnt/2] = SI_in;
end
addr_cnt = addr_cnt + 1;
read_cnt = 0;
end
else if ((Instruct==DDRFR4) ||
((Instruct==DDRFR) && EXTADD))
begin
Address_in[addr_cnt] = SI_in;
if ((addr_cnt/2) <= 16)
begin
opcode_tmp[addr_cnt/2] = SI_in;
end
addr_cnt = addr_cnt + 1;
read_cnt = 0;
end
else if ((Instruct == DDRDIOR) && (~EXTADD))
begin //Dual I/O DDR Read Mode
Address_in[2*addr_cnt] = SO_in;
Address_in[2*addr_cnt+1]= SI_in;
if ((addr_cnt/2) <= 16)
begin
opcode_tmp[addr_cnt/2] = SI_in;
end
addr_cnt = addr_cnt + 1;
read_cnt = 0;
end
else if ((Instruct==DDRDIOR4) ||
((Instruct==DDRDIOR) && EXTADD))
begin //Dual I/O DDR Read Mode
Address_in[2*addr_cnt] = SO_in;
Address_in[2*addr_cnt+1] = SI_in;
if ((addr_cnt/2) <= 16)
begin
opcode_tmp[addr_cnt/2] = SI_in;
end
addr_cnt = addr_cnt + 1;
read_cnt = 0;
end
else if ((Instruct==DDRQIOR) && (~EXTADD) && QUAD)
begin //Quad I/O DDR Read Mode
Address_in[4*addr_cnt] = HOLDNeg_in;
Address_in[4*addr_cnt+1] = WPNeg_in;
Address_in[4*addr_cnt+2] = SO_in;
Address_in[4*addr_cnt+3] = SI_in;
opcode_tmp[addr_cnt/2] = SI_in;
addr_cnt = addr_cnt +1;
read_cnt = 0;
end
else if (QUAD && ((Instruct==DDRQIOR4) ||
((Instruct==DDRQIOR) && EXTADD)))
begin
Address_in[4*addr_cnt] = HOLDNeg_in;
Address_in[4*addr_cnt+1] = WPNeg_in;
Address_in[4*addr_cnt+2] = SO_in;
Address_in[4*addr_cnt+3] = SI_in;
opcode_tmp[addr_cnt/2] = SI_in;
addr_cnt = addr_cnt +1;
read_cnt = 0;
end
end
end
MODE_BYTE :
begin
if (((Instruct==DIOR) || (Instruct == DIOR4))
&& ((HOLDNeg_in && ~QUAD) || QUAD))
begin
mode_in[2*mode_cnt] = SO_in;
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>=0;i=i-1)
begin
mode_bytes[i] = mode_in[7-i];
end
if (Latency_code == 0 || Latency_code == 3)
bus_cycle_state = DATA_BYTES;
else
bus_cycle_state = DUMMY_BYTES;
end
end
else if (((Instruct==QIOR) || (Instruct == QIOR4))
&& QUAD)
begin
mode_in[4*mode_cnt] = HOLDNeg_in;
mode_in[4*mode_cnt+1] = WPNeg_in;
mode_in[4*mode_cnt+2] = SO_in;
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>=0;i=i-1)
begin
mode_bytes[i] = mode_in[7-i];
end
bus_cycle_state = DUMMY_BYTES;
end
end
else if ((Instruct == DDRFR) || (Instruct == DDRFR4))
mode_in[2*mode_cnt] = SI_in;
else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4))
begin
mode_in[4*mode_cnt] = SO_in;
mode_in[4*mode_cnt+1] = SI_in;
end
else if (((Instruct==DDRQIOR) || (Instruct == DDRQIOR4))
&& QUAD)
begin
mode_in[0] = HOLDNeg_in;
mode_in[1] = WPNeg_in;
mode_in[2] = SO_in;
mode_in[3] = SI_in;
end
dummy_cnt = 0;
end
DUMMY_BYTES :
begin
Return_DLP(Instruct, EHP, Latency_code,
dummy_cnt, start_dlp);
if (DOUBLE == 1'b1 && (hold_mode==0) &&
(VDLR_reg != 8'b00000000) && start_dlp)
begin
read_out = 1'b1;
#10 read_out = 1'b0;
end
if ((((Instruct==FSTRD) || (Instruct==FSTRD4) ||
(Instruct==DOR) || (Instruct==DOR4) ||
(Instruct==OTPR)) &&
((HOLDNeg_in && ~QUAD) || QUAD)) ||
(((Instruct==QOR)||(Instruct==QOR4)) && QUAD))
begin
dummy_cnt = dummy_cnt + 1;
if (dummy_cnt == BYTE)
begin
bus_cycle_state = DATA_BYTES;
end
end
else if ((Instruct==DDRFR) || (Instruct==DDRFR4))
begin
dummy_cnt = dummy_cnt + 1;
if (EHP)
begin
if (((Latency_code == 3) && (dummy_cnt==1)) ||
((Latency_code == 0) && (dummy_cnt==2)) ||
((Latency_code == 1) && (dummy_cnt==4)) ||
((Latency_code == 2) && (dummy_cnt==5)))
begin
bus_cycle_state = DATA_BYTES;
end
end
else
begin
if (((Latency_code == 3) && (dummy_cnt==4)) ||
((Latency_code == 0) && (dummy_cnt==5)) ||
((Latency_code == 1) && (dummy_cnt==6)) ||
((Latency_code == 2) && (dummy_cnt==7)))
begin
bus_cycle_state = DATA_BYTES;
end
end
end
else if (Instruct==RES)
begin
dummy_cnt = dummy_cnt + 1;
if (dummy_cnt == 3*BYTE)
bus_cycle_state = DATA_BYTES;
end
else if (Instruct==ECCRD)
begin
dummy_cnt = dummy_cnt + 1;
if (dummy_cnt == BYTE)
bus_cycle_state = DATA_BYTES;
end
else if ((Instruct == DIOR) || (Instruct == DIOR4)
&& ((HOLDNeg_in && ~QUAD) || QUAD))
begin
dummy_cnt = dummy_cnt + 1;
if (EHP)
begin
if (((Latency_code == 1) && (dummy_cnt==1)) ||
((Latency_code == 2) && (dummy_cnt==2)))
bus_cycle_state = DATA_BYTES;
end
else
begin
if (((Latency_code == 3) && (dummy_cnt==4)) ||
((Latency_code == 0) && (dummy_cnt==4)) ||
((Latency_code == 1) && (dummy_cnt==5)) ||
((Latency_code == 2) && (dummy_cnt==6)))
bus_cycle_state = DATA_BYTES;
end
end
else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4))
begin
dummy_cnt = dummy_cnt + 1;
if (EHP)
begin
if (((Latency_code == 3) && (dummy_cnt==2)) ||
((Latency_code == 0) && (dummy_cnt==4)) ||
((Latency_code == 1) && (dummy_cnt==5)) ||
((Latency_code == 2) && (dummy_cnt==6)))
begin
bus_cycle_state = DATA_BYTES;
end
end
else
begin
if (((Latency_code == 3) && (dummy_cnt==4)) ||
((Latency_code == 0) && (dummy_cnt==6)) ||
((Latency_code == 1) && (dummy_cnt==7)) ||
((Latency_code == 2) && (dummy_cnt==8)))
begin
bus_cycle_state = DATA_BYTES;
end
end
end
else if (((Instruct == QIOR) || (Instruct == QIOR4))
&& QUAD)
begin
dummy_cnt = dummy_cnt + 1;
if (((Latency_code == 3) && (dummy_cnt==1)) ||
((Latency_code == 0) && (dummy_cnt==4)) ||
((Latency_code == 1) && (dummy_cnt==4)) ||
((Latency_code == 2) && (dummy_cnt==5)))
begin
bus_cycle_state = DATA_BYTES;
end
end
else if (((Instruct==DDRQIOR) || (Instruct==DDRQIOR4))
&& QUAD)
begin
dummy_cnt = dummy_cnt + 1;
if (((Latency_code == 3) && (dummy_cnt==3)) ||
((Latency_code == 0) && (dummy_cnt==6)) ||
((Latency_code == 1) && (dummy_cnt==7)) ||
((Latency_code == 2) && (dummy_cnt==8)))
begin
bus_cycle_state = DATA_BYTES;
end
end
end
DATA_BYTES :
begin
if (DOUBLE == 1'b1 && (hold_mode==0))
begin
read_out = 1'b1;
#10 read_out = 1'b0;
end
if ((QUAD) && ((Instruct==QPP) || (Instruct == QPP4)))
begin
quad_nybble = {HOLDNeg_in, WPNeg_in, SO_in, SI_in};
if (data_cnt > ((PageSize+1)*2-1))
begin
//In case of quad mode and QPP,
//if more than 512 bytes are sent to the device
for(i=0;i<=(PageSize*2-1);i=i+1)
begin
quad_data_in[i] = quad_data_in[i+1];
end
quad_data_in[(PageSize+1)*2-1] = 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 ((~QUADRD) && ((HOLDNeg_in && ~QUAD) || QUAD))
begin
if (data_cnt > ((PageSize+1)*8-1))
begin
//In case of serial mode and PP,
//if more than PageSize are sent to the device
//previously latched data are discarded and last
//256/512 data bytes are guaranteed to be programmed
//correctly within the same page.
if (bit_cnt == 0)
begin
for(i=0;i<=(PageSize*BYTE-1);i=i+1)
begin
Data_in[i] = Data_in[i+8];
end
end
Data_in[PageSize*BYTE + 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 (~CSNeg_ipd)
begin
case (bus_cycle_state)
ADDRESS_BYTES :
begin
if (DOUBLE == 1'b1)
begin
if ((Instruct==DDRFR) && (~EXTADD))
//Fast DDR Read Mode
begin
Address_in[addr_cnt] = SI_in;
if (addr_cnt != 0)
begin
addr_cnt = addr_cnt + 1;
end
read_cnt = 0;
if (addr_cnt == 3*BYTE)
begin
addr_cnt = 0;
for(i=23;i>=0;i=i-1)
begin
addr_bytes[23-i] = Address_in[i];
end
addr_bytes[31:25] = 7'b0000000;
addr_bytes[24] = Bank_Addr_reg[0];
Address = addr_bytes;
change_addr = 1'b1;
#1 change_addr = 1'b0;
if (EHP)
bus_cycle_state = MODE_BYTE;
else
bus_cycle_state = DUMMY_BYTES;
end
end
else if ((Instruct==DDRFR4) ||
((Instruct==DDRFR) && EXTADD))
begin
Address_in[addr_cnt] = SI_in;
if (addr_cnt != 0)
begin
addr_cnt = addr_cnt + 1;
end
read_cnt = 0;
if (addr_cnt == 4*BYTE)
begin
addr_cnt = 0;
for(i=31;i>=0;i=i-1)
begin
addr_bytes[31-i] = Address_in[i];
end
Address = {7'b0000000,addr_bytes[24:0]};
change_addr = 1'b1;
#1 change_addr = 1'b0;
if (EHP)
bus_cycle_state = MODE_BYTE;
else
begin
bus_cycle_state = DUMMY_BYTES;
if (DOUBLE == 1'b1 && (hold_mode==0)
&& VDLR_reg != 8'b00000000)
begin
read_out = 1'b1;
#10 read_out = 1'b0;
end
end
end
end
else if ((Instruct == DDRDIOR) && (~EXTADD))
begin //Dual I/O DDR Read Mode
Address_in[2*addr_cnt] = SO_in;
Address_in[2*addr_cnt+1]= SI_in;
if (addr_cnt != 0)
begin
addr_cnt = addr_cnt + 1;
end
read_cnt = 0;
if (addr_cnt == 3*BYTE/2)
begin
addr_cnt = 0;
for(i=23;i>=0;i=i-1)
begin
addr_bytes[23-i] = Address_in[i];
end
addr_bytes[31:25] = 7'b0000000;
addr_bytes[24] = Bank_Addr_reg[0];
Address = addr_bytes;
change_addr = 1'b1;
#1 change_addr = 1'b0;
if (EHP)
bus_cycle_state = MODE_BYTE;
else
bus_cycle_state = DUMMY_BYTES;
end
end
else if ((Instruct==DDRDIOR4) ||
((Instruct==DDRDIOR) && EXTADD))
begin //Dual I/O DDR Read Mode
Address_in[2*addr_cnt] = SO_in;
Address_in[2*addr_cnt+1] = SI_in;
if (addr_cnt != 0)
begin
addr_cnt = addr_cnt + 1;
end
read_cnt = 0;
if (addr_cnt == 4*BYTE/2)
begin
addr_cnt = 0;
for(i=31;i>=0;i=i-1)
begin
addr_bytes[31-i] = Address_in[i];
end
Address = {7'b0000000,addr_bytes[24:0]};
change_addr = 1'b1;
#1 change_addr = 1'b0;
if (EHP)
bus_cycle_state = MODE_BYTE;
else
begin
bus_cycle_state = DUMMY_BYTES;
if (DOUBLE == 1'b1 && (hold_mode==0)
&& VDLR_reg != 8'b00000000)
begin
read_out = 1'b1;
#10 read_out = 1'b0;
end
end
end
end
else if ((Instruct==DDRQIOR) && (~EXTADD) && QUAD)
begin //Quad I/O DDR Read Mode
Address_in[4*addr_cnt] = HOLDNeg_in;
Address_in[4*addr_cnt+1] = WPNeg_in;
Address_in[4*addr_cnt+2] = SO_in;
Address_in[4*addr_cnt+3] = SI_in;
if (addr_cnt != 0)
begin
addr_cnt = addr_cnt + 1;
end
read_cnt = 0;
if (addr_cnt == 3*BYTE/4)
begin
addr_cnt = 0;
for(i=23;i>=0;i=i-1)
begin
addr_bytes[23-i] = Address_in[i];
end
addr_bytes[31:25] = 7'b0000000;
addr_bytes[24] = Bank_Addr_reg[0];
Address = addr_bytes;
change_addr = 1'b1;
#1 change_addr = 1'b0;
bus_cycle_state = MODE_BYTE;
end
end
else if (QUAD && ((Instruct==DDRQIOR4) ||
((Instruct==DDRQIOR) && EXTADD)))
begin
Address_in[4*addr_cnt] = HOLDNeg_in;
Address_in[4*addr_cnt+1] = WPNeg_in;
Address_in[4*addr_cnt+2] = SO_in;
Address_in[4*addr_cnt+3] = SI_in;
if (addr_cnt != 0)
begin
addr_cnt = addr_cnt + 1;
end
read_cnt = 0;
if (addr_cnt == 4*BYTE/4)
begin
addr_cnt = 0;
for(i=31;i>=0;i=i-1)
begin
addr_bytes[31-i] = Address_in[i];
end
Address = {7'b0000000,addr_bytes[24:0]};
change_addr = 1'b1;
#1 change_addr = 1'b0;
bus_cycle_state = MODE_BYTE;
end
end
end
end
MODE_BYTE :
begin
if ((Instruct == DDRFR) || (Instruct == DDRFR4))
begin
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>=0;i=i-1)
begin
mode_bytes[i] = mode_in[7-i];
end
bus_cycle_state = DUMMY_BYTES;
Return_DLP(Instruct, EHP, Latency_code,
dummy_cnt, start_dlp);
if (DOUBLE == 1'b1 && (hold_mode==0) &&
(VDLR_reg != 8'b00000000) && start_dlp)
begin
read_out = 1'b1;
#10 read_out = 1'b0;
end
end
end
else if ((Instruct==DDRDIOR) || (Instruct==DDRDIOR4))
begin
mode_in[4*mode_cnt+2] = SO_in;
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>=0;i=i-1)
begin
mode_bytes[i] = mode_in[7-i];
end
bus_cycle_state = DUMMY_BYTES;
Return_DLP(Instruct, EHP, Latency_code,
dummy_cnt, start_dlp);
if (DOUBLE == 1'b1 && (hold_mode==0) &&
(VDLR_reg != 8'b00000000) && start_dlp)
begin
read_out = 1'b1;
#10 read_out = 1'b0;
end
end
end
else if ((Instruct==DDRQIOR) || (Instruct==DDRQIOR4))
begin
mode_in[4] = HOLDNeg_in;
mode_in[5] = WPNeg_in;
mode_in[6] = SO_in;
mode_in[7] = SI_in;
for(i=7;i>=0;i=i-1)
begin
mode_bytes[i] = mode_in[7-i];
end
bus_cycle_state = DUMMY_BYTES;
Return_DLP(Instruct, EHP, Latency_code,
dummy_cnt, start_dlp);
if (DOUBLE == 1'b1 && (hold_mode==0) &&
(VDLR_reg != 8'b00000000) && start_dlp)
begin
read_out = 1'b1;
#10 read_out = 1'b0;
end
end
end
DATA_BYTES:
begin
if (hold_mode==0)
begin
if (DOUBLE == 1'b1 )
begin
read_out = 1'b1;
#10 read_out = 1'b0;
end
else
begin
if ((Instruct==READ) || (Instruct==RD4) ||
(Instruct==FSTRD)|| (Instruct==FSTRD4)||
(Instruct==RDSR) || (Instruct==RDSR2) ||
(Instruct==RDCR) || (Instruct==OTPR) ||
(Instruct==DOR) || (Instruct==DOR4) ||
(Instruct==DIOR)|| (Instruct==DIOR4)||
(Instruct==ABRD) || (Instruct==BRRD) ||
(Instruct==ASPRD)|| (Instruct==DYBRD) ||
(Instruct==PPBRD)|| (Instruct == ECCRD) ||
(Instruct==PASSRD)|| (Instruct==RDID)||
(Instruct==RES) || (Instruct==REMS) ||
(Instruct==PLBRD)|| (Instruct==DLPRD) ||
(current_state == AUTOBOOT &&
start_delay == 0) ||
(((Instruct==QOR) || (Instruct==QIOR) ||
(Instruct==QOR4) ||
(Instruct==QIOR4)) && QUAD))
begin
read_out = 1'b1;
#10 read_out = 1'b0;
end
end
end
end
DUMMY_BYTES:
begin
if (hold_mode==0)
begin
Return_DLP(Instruct, EHP, Latency_code,
dummy_cnt, start_dlp);
if (DOUBLE == 1'b1 && VDLR_reg != 8'b00000000 &&
start_dlp)
begin
read_out = 1'b1;
#10 read_out = 1'b0;
end
end
end
endcase
end
end
if (rising_edge_CSNeg_ipd)
begin
if (bus_cycle_state != DATA_BYTES)
begin
if (bus_cycle_state == ADDRESS_BYTES && opcode_tmp == 8'hFF)
begin
Instruct = MBR;
end
bus_cycle_state = STAND_BY;
end
else
begin
if (bus_cycle_state == DATA_BYTES)
begin
if (((mode_bytes[7:4] == 4'b1010) &&
(Instruct==DIOR || Instruct==DIOR4 ||
Instruct==QIOR || Instruct==QIOR4)) ||
((mode_bytes[7:4] == ~mode_bytes[3:0]) &&
(Instruct == DDRFR || Instruct == DDRFR4 ||
Instruct == DDRDIOR || Instruct == DDRDIOR4 ||
Instruct == DDRQIOR || Instruct == DDRQIOR4)))
bus_cycle_state = ADDRESS_BYTES;
else
bus_cycle_state = STAND_BY;
case (Instruct)
WREN,
WRDI,
BE,
SE,
SE4,
P4E,
P4E4,
CLSR,
BRAC,
RESET,
PPBERS,
PPBP,
PLBWR,
PGSP,
PGRS,
ERSP,
ERRS:
begin
if ((HOLDNeg_in && ~QUAD) || QUAD)
begin
if (data_cnt == 0)
write = 1'b0;
end
end
WRR:
begin
if ((HOLDNeg_in && ~QUAD) || QUAD)
begin
if (data_cnt == 8)
//If CS# is driven high after eight
//cycle,only the Status Register is
//written to.
begin
write = 1'b0;
if (BAR_ACC == 0)
begin
for(i=0;i<=7;i=i+1)
begin
Status_reg1_in[i]=
Data_in[7-i];
end
end
else
begin
if (P_ERR == 0 && E_ERR == 0)
begin
for(i=0;i<=7;i=i+1)
begin
Bank_Addr_reg_in[i]=
Data_in[7-i];
end
end
end
end
else if (data_cnt == 16)
//After the 16th cycle both the
//Status and Configuration Registers
//are written to.
begin
write = 1'b0;
if (BAR_ACC == 0)
begin
cfg_write = 1'b1;
for(i=0;i<=7;i=i+1)
begin
Status_reg1_in[i]=
Data_in[7-i];
Config_reg1_in[i]=
Data_in[15-i];
end
end
else
begin
if (P_ERR == 0 && E_ERR == 0)
begin
for(i=0;i<=7;i=i+1)
begin
Bank_Addr_reg_in[i]=
Data_in[7-i];
end
end
end
end
end
end
PP,
PP4,
OTPP:
begin
if ((HOLDNeg_in && ~QUAD) || QUAD)
begin
if (data_cnt > 0)
begin
if ((data_cnt % 8) == 0)
begin
write = 1'b0;
for(i=0;i<=PageSize;i=i+1)
begin
for(j=7;j>=0;j=j-1)
begin
if ((Data_in[(i*8)+(7-j)])
!== 1'bX)
begin
Byte_slv[j] =
Data_in[(i*8)+(7-j)];
end
end
WByte[i] = Byte_slv;
//$display("%m: Loc: %x Byte: %x",i,Byte_slv);
end
if (data_cnt > (PageSize+1)*BYTE)
Byte_number = PageSize;
else
Byte_number =
((data_cnt/8) - 1);
end
end
end
end
QPP,
QPP4:
begin
if (data_cnt >0)
begin
if ((data_cnt % 2) == 0)
begin
write = 1'b0;
quad_pg = 1'b0;
for(i=0;i<=PageSize;i=i+1)
begin
for(j=1;j>=0;j=j-1)
begin
Quad_slv =
quad_data_in[(i*2)+(1-j)];
if (j==1)
Byte_slv[7:4] = Quad_slv;
else if (j==0)
Byte_slv[3:0] = Quad_slv;
end
WByte[i] = Byte_slv;
end
if (data_cnt > (PageSize+1)*2)
Byte_number = PageSize;
else
Byte_number = ((data_cnt/2)-1);
end
end
end
ABWR:
begin
if ((HOLDNeg_in && ~QUAD) || QUAD)
begin
if (data_cnt == 32)
begin
write = 1'b0;
for(j=0;j<=31;j=j+1)
begin
AutoBoot_reg_in[j] = Data_in[31-j];
end
end
end
end
BRWR:
begin
if ((HOLDNeg_in && ~QUAD) || QUAD)
begin
if (data_cnt == 8)
begin
write = 1'b0;
for(j=0;j<=7;j=j+1)
begin
Bank_Addr_reg_in[j] = Data_in[7-j];
end
end
end
end
ASPP:
begin
if ((HOLDNeg_in && ~QUAD) || QUAD)
begin
if (data_cnt == 16)
begin
write = 1'b0;
for(j=0;j<=15;j=j+1)
begin
ASP_reg_in[j] = Data_in[15-j];
end
end
end
end
DYBWR:
begin
if ((HOLDNeg_in && ~QUAD) || QUAD)
begin
if (data_cnt == 8)
begin
write = 1'b0;
for(j=0;j<=7;j=j+1)
begin
DYBAR_in[j] = Data_in[7-j];
end
end
end
end
PNVDLR:
begin
if ((HOLDNeg_in && ~QUAD) || QUAD)
begin
if (data_cnt == 8)
begin
write = 1'b0;
for(j=0;j<=7;j=j+1)
begin
NVDLR_reg_in[j] = Data_in[7-j];
end
end
end
end
WVDLR:
begin
if ((HOLDNeg_in && ~QUAD) || QUAD)
begin
if (data_cnt == 8)
begin
write = 1'b0;
for(j=0;j<=7;j=j+1)
begin
VDLR_reg_in[j] = Data_in[7-j];
end
end
end
end
PASSP:
begin
if ((HOLDNeg_in && ~QUAD) || QUAD)
begin
if (data_cnt == 64)
begin
write = 1'b0;
for(j=1;j<=8;j=j+1)
begin
for(k=1;k<=8;k=k+1)
begin
Password_reg_in[j*8-k] =
Data_in[8*(j-1)+k-1];
end
end
end
end
end
PASSU:
begin
if ((HOLDNeg_in && ~QUAD) || QUAD)
begin
if (data_cnt == 64)
begin
write = 1'b0;
for(j=1;j<=8;j=j+1)
begin
for(k=1;k<=8;k=k+1)
begin
PASS_TEMP[j*8-k] =
Data_in[8*(j-1)+k-1];
end
end
end
end
end
endcase
end
end
end
end
end
///////////////////////////////////////////////////////////////////////////////
// Timing control for the Page Program
///////////////////////////////////////////////////////////////////////////////
time pob;
time elapsed_pgm;
time elapsed_tsu;
time start_pgm;
time start_tsu;
time duration_pgm;
time duration_tsu;
event pdone_event;
always @(rising_edge_PSTART)
begin
if ((Instruct == PP) || (Instruct == PP4) || (Instruct == OTPP) ||
(Instruct == QPP) || (Instruct == QPP4))
if (PageSize == 255)
begin
pob = tdevice_PP_256;
end
else
begin
pob = tdevice_PP_512;
end
else
pob = tdevice_BP;
if ((rising_edge_PSTART) && PDONE)
begin
elapsed_pgm = 0;
duration_pgm = pob;
PDONE = 1'b0;
->pdone_event;
start_pgm = $time;
end
end
always @(posedge PGSUSP)
begin
if (PGSUSP && (~PDONE))
begin
disable pdone_process;
elapsed_pgm = $time - start_pgm;
duration_pgm = pob - elapsed_pgm;
PDONE = 1'b0;
end
end
always @(posedge PGRES)
begin
start_pgm = $time;
->pdone_event;
end
always @(pdone_event)
begin:pdone_process
PDONE = 1'b0;
#duration_pgm PDONE = 1'b1;
end
always @(SI)
begin
if ((Instruct == PGSP) || (Instruct == PGRS) ||
(Instruct == ERSP) || (Instruct == ERRS))
begin
start_tsu = $time;
end
end
always @(posedge SCK)
begin
if ((Instruct == PGSP) || (Instruct == PGRS) ||
(Instruct == ERSP) || (Instruct == ERRS))
begin
elapsed_tsu = $time - start_tsu;
duration_tsu = tdevice_TSU - elapsed_tsu;
if (duration_tsu > 0)
begin
TSU = 1'b0;
end
else
begin
TSU = 1'b1;
$display("Warning at", $time);
$display("tSU max time violation");
end
end
end
///////////////////////////////////////////////////////////////////////////////
// Timing control for the Write Status Register
///////////////////////////////////////////////////////////////////////////////
time wob;
always @(posedge WSTART)
begin:wdone_process
wob = tdevice_WRR;
if (WSTART && WDONE)
begin
WDONE = 1'b0;
#wob WDONE = 1'b1;
end
end
///////////////////////////////////////////////////////////////////////////////
// Reset Timing
///////////////////////////////////////////////////////////////////////////////
time startlo;
time starthi;
time durationlo;
time durationhi;
always @(negedge RSTNeg_in or Instruct)
begin
if (~RSTNeg_in)
begin
RST = 1'b1;
#200000 RST = 1'b0; // 200 ns
end
else if (Instruct == RESET)
begin
Reseted = 1'b0;
#10000 Reseted = 1'b1; // 10 ns
end
end
always @(RST_in or rising_edge_Reseted) // Reset done,program terminated
begin
if ((RST_in && ~RST) || (rising_edge_Reseted))
disable pdone_process;
disable edone_process;
disable wdone_process;
PDONE = 1'b1;
EDONE = 1'b1;
WDONE = 1'b1;
end
///////////////////////////////////////////////////////////////////////////////
// Timing control for the Bulk Erase
///////////////////////////////////////////////////////////////////////////////
time seo;
time beo;
event edone_event;
time elapsed_ers;
time start_ers;
time duration_ers;
always @(rising_edge_ESTART)
begin
if (UniformSec)
begin
seo = tdevice_SE256;
end
else
begin
seo = tdevice_SE64;
end
beo = tdevice_BE;
if ((rising_edge_ESTART) && EDONE)
begin
if (Instruct == BE)
begin
duration_ers = beo;
end
else
begin
duration_ers = seo;
end
elapsed_ers = 0;
EDONE = 1'b0;
->edone_event;
start_ers = $time;
end
end
always @(posedge ESUSP)
begin
if (ESUSP && (~EDONE))
begin
disable edone_process;
elapsed_ers = $time - start_ers;
duration_ers = seo - elapsed_ers;
EDONE = 1'b0;
end
end
always @(posedge ERES)
begin
if (ERES && (~EDONE))
begin
start_ers = $time;
->edone_event;
end
end
always @(edone_event)
begin : edone_process
EDONE = 1'b0;
#duration_ers EDONE = 1'b1;
end
///////////////////////////////////////////////////////////////////
// Process for clock frequency determination
///////////////////////////////////////////////////////////////////
always @(posedge SCK_ipd)
begin : clock_period
if (SCK_ipd)
begin
SCK_cycle = $time - prev_SCK;
prev_SCK = $time;
end
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 falling_edge_write = 1'b0;
reg falling_edge_PPBERASE_in = 1'b0;
reg falling_edge_PASSULCK_in = 1'b0;
integer i;
integer j;
always @(rising_edge_PoweredUp or falling_edge_write or
falling_edge_RSTNeg or rising_edge_PDONE or rising_edge_WDONE or
rising_edge_EDONE or ERSSUSP_out_event or rising_edge_RSTNeg or
PRGSUSP_out_event or rising_edge_CSNeg_ipd or rising_edge_RST_out
or falling_edge_PPBERASE_in or falling_edge_PASSULCK_in or RST_out)
begin: StateGen1
integer sect;
if (rising_edge_PoweredUp && RSTNeg_in && RST_out)
begin
if (ABE == 1 && RPME !== 0 )
begin
next_state = AUTOBOOT;
read_cnt = 0;
byte_cnt = 1;
read_addr = {AutoBoot_reg[31:9], 9'b0};
start_delay = AutoBoot_reg[8:1];
start_autoboot = 0;
ABSD = AutoBoot_reg[8:1];
end
else
next_state = IDLE;
end
else if (PoweredUp)
begin
if (RST_out == 1'b0)
next_state = current_state;
else if (falling_edge_write && Instruct == RESET)
begin
if (ABE == 1 && RPME !== 0)
begin
read_cnt = 0;
byte_cnt = 1;
read_addr = {AutoBoot_reg[31:9], 9'b0};
start_delay = AutoBoot_reg[8:1];
ABSD = AutoBoot_reg[8:1];
start_autoboot = 0;
next_state = AUTOBOOT;
end
else
next_state = IDLE;
end
else
begin
case (current_state)
RESET_STATE :
begin
if ((rising_edge_RST_out && RSTNeg_in) ||
(rising_edge_RSTNeg && RST_out))
begin
if (ABE == 1 && RPME!== 0)
begin
next_state = AUTOBOOT;
read_cnt = 0;
byte_cnt = 1;
read_addr = {AutoBoot_reg[31:9],9'b0};
start_delay = AutoBoot_reg[8:1];
start_autoboot = 0;
ABSD = AutoBoot_reg[8:1];
end
else
next_state = IDLE;
end
end
IDLE :
begin
if (falling_edge_write && RdPswdProtMode == 0)
begin
if (Instruct == WRR && WEL == 1 && BAR_ACC == 0
&& (((~(SRWD == 1 && ~WPNeg_in))&& ~QUAD) || QUAD))
// can not execute if HPM is entered or
// if WEL bit is zero
if (((TBPROT==1 && Config_reg1_in[5]==1'b0) ||
(TBPARM==1 && Config_reg1_in[2]==1'b0) ||
(BPNV ==1 && Config_reg1_in[3]==1'b0)) &&
cfg_write)
begin
$display ("WARNING: Changing value of ");
$display ("Configuration Register OTP ");
$display ("bit from 1 to 0 is not");
$display ("allowed!!!");
end
else
begin
next_state = WRITE_SR;
end
else if (Instruct == WRR && BAR_ACC == 1)
begin
// Write to the lower address bits of the BAR
if (P_ERR == 0 && E_ERR == 0)
begin
next_state = IDLE;
end
end
else if ((Instruct == PP || Instruct == QPP ||
Instruct == PP4 || Instruct == QPP4) &&
WEL == 1)
begin
ReturnSectorID(sect,Address);
pgm_page = Address / (PageSize+1);
if (Sec_Prot[sect]== 0 && PPB_bits[sect]== 1 &&
DYB_bits[sect]== 1)
begin
next_state = PAGE_PG;
end
end
else if (Instruct==OTPP && WEL==1 && FREEZE==0)
begin
if (((((Address>=16'h0010 && Address<=16'h0013)
||(Address>=16'h0020 && Address<=16'h00FF))
&& LOCK_BYTE1[Address/32] == 1) ||
((Address>=16'h0100 && Address<=16'h01FF)
&& LOCK_BYTE2[(Address-16'h0100)/32]==1) ||
((Address>=16'h0200 && Address<=16'h02FF)
&& LOCK_BYTE3[(Address-16'h0200)/32]==1) ||
((Address>=16'h0300 && Address<=16'h03FF)
&& LOCK_BYTE4[(Address-16'h0300)/32] == 1))
&& (Address + Byte_number <= OTPHiAddr))
next_state = OTP_PG;
end
else if ((Instruct == SE || Instruct == SE4)
&& WEL == 1)
begin
ReturnSectorID(sect,Address);
if (UniformSec || (TopBoot && sect < 510) ||
(BottomBoot && sect > 31))
begin
if (Sec_Prot[sect]== 0 && PPB_bits[sect]== 1
&& DYB_bits[sect]== 1)
next_state = SECTOR_ERS;
end
else if ((TopBoot && sect >= 510) ||
(BottomBoot && sect <= 31))
begin
if (Sec_ProtSE == 32 && ASP_ProtSE == 32)
//Sector erase command is applied to a
//64 KB range that includes 4 KB sectors.
next_state = SECTOR_ERS;
end
end
else if ((Instruct == P4E || Instruct == P4E4)
&& WEL == 1)
begin
ReturnSectorID(sect,Address);
if (UniformSec || (TopBoot && sect < 510) ||
(BottomBoot && sect > 31))
begin
$display("The instruction is applied to");
$display("a sector that is larger than");
$display("4 KB.");
$display("Instruction is ignored!!!");
end
else
begin
if (Sec_Prot[sect]== 0 &&
PPB_bits[sect]== 1 && DYB_bits[sect]== 1)
next_state = SECTOR_ERS;
end
end
else if (Instruct == BE && WEL == 1 &&
(Status_reg1[4]== 0 && Status_reg1[3]== 0 &&
Status_reg1[2]== 0))
next_state = BULK_ERS;
else if (Instruct == ABWR && WEL == 1)
//Autoboot Register Write Command
next_state = AUTOBOOT_PG;
else if (Instruct == BRWR)
//Bank Register Write Command
next_state = IDLE;
else if (Instruct == ASPP && WEL == 1)
begin
//ASP Register Program Command
if (~(ASPOTPFLAG))
next_state = ASP_PG;
end
else if (Instruct == PLBWR && WEL == 1 &&
RdPswdProtEnable == 0)
next_state = PLB_PG;
else if (Instruct == PASSP && WEL == 1)
begin
if (~(PWDMLB== 0 && PSTMLB== 1))
next_state = PASS_PG;
end
else if (Instruct == PASSU && WEL && ~WIP)
next_state = PASS_UNLOCK;
else if (Instruct == PPBP && WEL == 1)
next_state <= PPB_PG;
else if (Instruct == PPBERS && WEL && PPBOTP)
next_state <= PPB_ERS;
else if (Instruct == DYBWR && WEL == 1)
next_state = DYB_PG;
else if (Instruct == PNVDLR && WEL == 1)
next_state = NVDLR_PG;
else
next_state = IDLE;
end
if (falling_edge_write && RdPswdProtMode == 1 && ~WIP)
begin
if (Instruct == PASSU)
next_state = PASS_UNLOCK;
end
end
AUTOBOOT :
begin
if (rising_edge_CSNeg_ipd)
next_state = IDLE;
end
WRITE_SR :
begin
if (rising_edge_WDONE)
next_state = IDLE;
end
PAGE_PG :
begin
if (PRGSUSP_out_event && PRGSUSP_out == 1)
next_state = PG_SUSP;
else if (rising_edge_PDONE)
next_state = IDLE;
end
PG_SUSP :
begin
if (falling_edge_write)
begin
if (Instruct == BRWR)
//Bank Register Write Command
next_state = PG_SUSP;
else if (Instruct == PGRS)
next_state = PAGE_PG;
end
end
OTP_PG :
begin
if (rising_edge_PDONE)
next_state = IDLE;
end
BULK_ERS :
begin
if (rising_edge_EDONE)
next_state = IDLE;
end
SECTOR_ERS :
begin
if (ERSSUSP_out_event && ERSSUSP_out == 1)
next_state = ERS_SUSP;
else if (rising_edge_EDONE)
next_state = IDLE;
end
ERS_SUSP :
begin
if (falling_edge_write)
begin
if ((Instruct == PP || Instruct == QPP ||
Instruct == PP4 || Instruct == QPP4) &&
WEL == 1)
begin
if ((PARAM_REGION &&
SectorSuspend != Address/(SecSize+1)) ||
(~PARAM_REGION && SectorSuspend !=
Address/(SecSize+1)+30*b_act))
begin
ReturnSectorID(sect,Address);
pgm_page = Address / (PageSize+1);
if (PPB_bits[sect]== 1 &&
DYB_bits[sect]== 1)
begin
next_state = ERS_SUSP_PG;
end
end
end
else if (Instruct == BRWR)
begin
//Bank Register Write Command
next_state = ERS_SUSP;
end
else if (Instruct == DYBWR && WEL == 1)
next_state = DYB_PG;
else if (Instruct == ERRS)
next_state = SECTOR_ERS;
end
end
ERS_SUSP_PG :
begin
if (rising_edge_PDONE)
next_state = ERS_SUSP;
else if (PRGSUSP_out_event && PRGSUSP_out == 1)
next_state = ERS_SUSP_PG_SUSP;
end
ERS_SUSP_PG_SUSP :
begin
if (rising_edge_PDONE)
next_state = ERS_SUSP;
if (falling_edge_write)
begin
if (Instruct == BRWR)
begin
next_state = ERS_SUSP_PG_SUSP;
end
else if (Instruct == PGRS)
begin
next_state = ERS_SUSP_PG;
end
end
end
PASS_PG :
begin
if (rising_edge_PDONE)
next_state = IDLE;
end
PASS_UNLOCK :
begin
if (falling_edge_PASSULCK_in)
next_state = IDLE;
end
PPB_PG :
begin
if (rising_edge_PDONE)
next_state = IDLE;
end
PPB_ERS :
begin
if (falling_edge_PPBERASE_in)
next_state = IDLE;
end
AUTOBOOT_PG :
begin
if (rising_edge_PDONE)
next_state = IDLE;
end
PLB_PG :
begin
if (rising_edge_PDONE)
next_state = IDLE;
end
DYB_PG :
begin
if (rising_edge_PDONE)
if (ES)
next_state = ERS_SUSP;
else
next_state = IDLE;
end
ASP_PG :
begin
if (rising_edge_PDONE)
next_state = IDLE;
end
NVDLR_PG :
begin
if (rising_edge_PDONE)
next_state = IDLE;
end
endcase
end
end
end
///////////////////////////////////////////////////////////////////////////
//FSM Output generation and general functionality
///////////////////////////////////////////////////////////////////////////
reg rising_edge_read_out = 1'b0;
reg Instruct_event = 1'b0;
reg change_addr_event = 1'b0;
reg current_state_event = 1'b0;
reg rising_edge_DP_out = 1'b0;
integer WData [0:511];
integer WOTPData;
integer Addr;
integer Addr_tmp;
always @(Instruct_event)
begin
read_cnt = 0;
byte_cnt = 1;
rd_fast = 1'b1;
dual = 1'b0;
rd_slow = 1'b0;
any_read = 1'b0;
end
always @(rising_edge_read_out)
begin
if (rising_edge_read_out == 1'b1)
begin
if (PoweredUp == 1'b1)
begin
oe_z = 1'b1;
#1000 oe_z = 1'b0;
oe = 1'b1;
#1000 oe = 1'b0;
end
end
end
always @(change_addr_event)
begin
if (change_addr_event)
begin
read_addr = Address;
end
end
always @(posedge PASSACC_out)
begin
Status_reg1[0] = 1'b0; //WIP
PASSACC_in = 1'b0;
end
always @(Instruct or posedge start_autoboot or oe or current_state_event or
falling_edge_write or posedge PDONE or posedge WDONE or oe_z or
posedge EDONE or ERSSUSP_out or rising_edge_Reseted or
rising_edge_PoweredUp or rising_edge_CSNeg_ipd or PRGSUSP_out or
Address)
begin: Functionality
integer i,j;
integer sect;
if (rising_edge_PoweredUp)
begin
//the default condition after power-up
//The Bank Address Register is loaded to all zeroes
Bank_Addr_reg = 8'h0;
//The Configuration Register FREEZE bit is cleared.
Config_reg1[0] = 0;
//The WEL bit is cleared.
Status_reg1[1] = 0;
//When BPNV is set to '1'. the BP2-0 bits in Status Register are
//volatile and will be reset binary 111 after power-on reset
if (BPNV == 1 && FREEZE == 0 ) //&& LOCK == 0
begin
Status_reg1[4] = 1'b0;// BP2
Status_reg1[3] = 1'b0;// BP1
Status_reg1[2] = 1'b0;// BP0
BP_bits = {Status_reg1[4],Status_reg1[3],Status_reg1[2]};
change_BP = 1'b1;
#1000 change_BP = 1'b0;
end
//As shipped from the factory, all devices default ASP to the
//Persistent Protection mode, with all sectors unprotected,
//when power is applied. The device programmer or host system must
//then choose which sector protection method to use.
//For Persistent Protection mode, PPBLOCK defaults to "1"
PPBL[0] = 1'b1;
//All the DYB power-up in the unprotected state
DYB_bits = {542{1'b1}};
end
if (Instruct == RESET)
begin
//EXTADD is cleared to “0”
Bank_Addr_reg[7] = 1'b0;
//P_ERR bit is cleared
Status_reg1[6] = 1'b0;
//E_ERR bit is cleared
Status_reg1[5] = 1'b0;
//The WEL bit is cleared.
Status_reg1[1] = 1'b0;
//The WIP bit is cleared.
Status_reg1[0] = 1'b0;
//The ES bit is cleared.
Status_reg2[1] = 1'b0;
//The PS bit is cleared.
Status_reg2[0] = 1'b0;
//When BPNV is set to '1'. the BP2-0 bits in Status
//Register are volatile and will be reseted after
//reset command
if (BPNV == 1 && FREEZE == 0) //&& LOCK== 0
begin
Status_reg1[4] = 1'b1;
Status_reg1[3] = 1'b1;
Status_reg1[2] = 1'b1;
BP_bits = {Status_reg1[4],Status_reg1[3],
Status_reg1[2]};
change_BP = 1'b1;
#1000 change_BP = 1'b0;
end
end
case (current_state)
IDLE :
begin
rd_fast = 1'b1;
rd_slow = 1'b0;
dual = 1'b0;
ddr = 1'b0;
ASP_ProtSE = 0;
Sec_ProtSE = 0;
if (BottomBoot)
begin
for (j=31;j>=0;j=j-1)
begin
if (PPB_bits[j] == 1 && DYB_bits[j] == 1)
begin
ASP_ProtSE = ASP_ProtSE + 1;
end
if (Sec_Prot[j] == 0)
begin
Sec_ProtSE = Sec_ProtSE + 1;
end
end
end
else if (TopBoot)
begin
for (j=541;j>=510;j=j-1)
begin
if (PPB_bits[j] == 1 && DYB_bits[j] == 1)
begin
ASP_ProtSE = ASP_ProtSE + 1;
end
if (Sec_Prot[j] == 0)
begin
Sec_ProtSE = Sec_ProtSE + 1;
end
end
end
if (falling_edge_write && RdPswdProtMode == 1)
begin
if(Instruct == PASSU)
begin
if (~WIP)
begin
PASSULCK_in = 1;
Status_reg1[0] = 1'b1; //WIP
end
else
begin
$display ("The PASSU command cannot be accepted");
$display (" any faster than once every 100us");
end
end
else if (Instruct == CLSR)
begin
//The Clear Status Register Command resets bit SR1[5]
//(Erase Fail Flag) and bit SR1[6] (Program Fail Flag)
Status_reg1[5] = 0;
Status_reg1[6] = 0;
end
end
if (falling_edge_write && RdPswdProtMode == 0)
begin
read_cnt = 0;
byte_cnt = 1;
if (Instruct == WREN)
Status_reg1[1] = 1'b1;
else if (Instruct == WRDI)
Status_reg1[1] = 0;
else if ((Instruct == WRR) && WEL == 1 && WDONE == 1 &&
BAR_ACC == 0)
begin
if (((~(SRWD == 1 && ~WPNeg_in))&& ~QUAD) || QUAD)
begin
if (((TBPROT==1 && Config_reg1_in[5]==1'b0) ||
(TBPARM==1 && Config_reg1_in[2]==1'b0) ||
(BPNV ==1 && Config_reg1_in[3]==1'b0)) &&
cfg_write)
begin
// P_ERR bit is set to 1
Status_reg1[6] = 1'b1;
end
else
begin
// can not execute if Hardware Protection Mode
// is entered or if WEL bit is zero
WSTART = 1'b1;
WSTART <= #5 1'b0;
Status_reg1[0] = 1'b1;
end
end
else
Status_reg1[1] = 0;
end
else if ((Instruct == PP || Instruct == PP4) && WEL ==1 &&
PDONE == 1 )
begin
ReturnSectorID(sect,Address);
if (Sec_Prot[sect] == 0 &&
PPB_bits[sect]== 1 && DYB_bits[sect]== 1)
begin
PSTART = 1'b1;
PSTART <= #5 1'b0;
PGSUSP = 0;
PGRES = 0;
INITIAL_CONFIG = 1;
Status_reg1[0] = 1'b1;
SA = sect;
Addr = Address;
Addr_tmp= Address;
wr_cnt = Byte_number;
for (i=wr_cnt;i>=0;i=i-1)
begin
if (Viol != 0)
WData[i] = -1;
else begin
WData[i] = WByte[i];
//$display("%m: Loc: %x WData: %x",i,WData[i]);
end
end
end
else
begin
//P_ERR bit will be set when the user attempts to
//to program within a protected main memory sector
Status_reg1[6] = 1'b1; //P_ERR
Status_reg1[1] = 1'b0; //WEL
end
end
else if ((Instruct == QPP || Instruct == QPP4) && WEL ==1 &&
PDONE == 1 )
begin
ReturnSectorID(sect,Address);
pgm_page = Address / (PageSize+1);
if (Sec_Prot[sect] == 0 &&
PPB_bits[sect]== 1 && DYB_bits[sect]== 1)
begin
PSTART = 1'b1;
PSTART <= #5 1'b0;
PGSUSP = 0;
PGRES = 0;
INITIAL_CONFIG = 1;
// QPP_page[pgm_page] = 1'b1;
Status_reg1[0] = 1'b1;
SA = sect;
Addr = Address;
Addr_tmp= Address;
wr_cnt = Byte_number;
for (i=wr_cnt;i>=0;i=i-1)
begin
if (Viol != 0)
WData[i] = -1;
else
WData[i] = WByte[i];
end
end
else
begin
//P_ERR bit will be set when the user attempts to
//to program within a protected main memory sector
Status_reg1[6] = 1'b1; //P_ERR
Status_reg1[1] = 1'b0; //WEL
end
end
else if (Instruct == OTPP && WEL == 1)
begin
// As long as the FREEZE bit remains cleared to a logic
// '0' the OTP address space is programmable.
if (FREEZE == 0)
begin
if (((((Address>= 16'h0010 && Address<= 16'h0013) ||
(Address >= 16'h0020 && Address <= 16'h00FF))
&& LOCK_BYTE1[Address/32] == 1) ||
((Address >= 16'h0100 && Address <= 16'h01FF)
&& LOCK_BYTE2[(Address-16'h0100)/32] == 1) ||
((Address >= 16'h0200 && Address <= 16'h02FF)
&& LOCK_BYTE3[(Address-16'h0200)/32] == 1) ||
((Address >= 16'h0300 && Address <= 16'h03FF)
&& LOCK_BYTE4[(Address-16'h0300)/32] == 1)) &&
(Address + Byte_number <= OTPHiAddr))
begin
PSTART = 1'b1;
PSTART <= #5 1'b0;
Status_reg1[0] = 1'b1;
Addr = Address;
Addr_tmp= Address;
wr_cnt = Byte_number;
for (i=wr_cnt;i>=0;i=i-1)
begin
if (Viol != 0)
WData[i] = -1;
else
WData[i] = WByte[i];
end
end
else if ((Address < 8'h10 || (Address > 8'h13 &&
Address < 8'h20) || Address > 12'h3FF ))
begin
Status_reg1[6] = 1'b1;//P_ERR
Status_reg1[1] = 1'b0;//WEL
if (Address < 8'h20)
begin
$display ("Given address is ");
$display ("in reserved address range");
end
else if (Address > 12'h3FF)
begin
$display ("Given address is ");
$display ("out of OTP address range");
end
end
else
begin
//P_ERR bit will be set when the user attempts to
// to program within locked OTP region
Status_reg1[6] = 1'b1;//P_ERR
Status_reg1[1] = 1'b0;//WEL
end
end
else
begin
//P_ERR bit will be set when the user attempts to